]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/signerutils.cpp
Security-57337.50.23.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / signerutils.cpp
1 /*
2 * Copyright (c) 2006-2013 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 //
25 // signerutils - utilities for signature generation
26 //
27 #include "signerutils.h"
28 #include "signer.h"
29 #include "SecCodeSigner.h"
30 #include <Security/SecIdentity.h>
31 #include <Security/CMSEncoder.h>
32 #include "resources.h"
33 #include "csutilities.h"
34 #include "drmaker.h"
35 #include <security_utilities/unix++.h>
36 #include <security_utilities/unixchild.h>
37 #include <vector>
38
39 // for helper validation
40 #include "Code.h"
41 #include <security_utilities/cfmunge.h>
42 #include <sys/codesign.h>
43
44
45 namespace Security {
46 namespace CodeSigning {
47
48
49 //
50 // About the Mach-O allocation helper
51 //
52 static const char helperName[] = "codesign_allocate";
53 static const char helperPath[] = "/usr/bin/codesign_allocate";
54 static const char helperOverride[] = "CODESIGN_ALLOCATE";
55 static const size_t csAlign = 16;
56
57
58 //
59 // BlobWriters
60 //
61 void BlobWriter::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
62 {
63 return EmbeddedSignatureBlob::Maker::component(slot, data);
64 }
65
66
67 void DetachedBlobWriter::flush()
68 {
69 EmbeddedSignatureBlob *blob = this->make();
70 signer.code->detachedSignature(CFTempData(*blob));
71 signer.state.returnDetachedSignature(blob, signer);
72 ::free(blob);
73 }
74
75
76 //
77 // ArchEditor
78 //
79 ArchEditor::ArchEditor(Universal &code, CodeDirectory::HashAlgorithms hashTypes, uint32_t attrs)
80 : DiskRep::Writer(attrs)
81 {
82 Universal::Architectures archList;
83 code.architectures(archList);
84 for (Universal::Architectures::const_iterator it = archList.begin();
85 it != archList.end(); ++it)
86 architecture[*it] = new Arch(*it, hashTypes);
87 }
88
89
90 ArchEditor::~ArchEditor()
91 {
92 for (ArchMap::iterator it = begin(); it != end(); ++it)
93 delete it->second;
94 }
95
96
97 ArchEditor::Arch::Arch(const Architecture &arch, CodeDirectory::HashAlgorithms hashTypes)
98 : architecture(arch)
99 {
100 for (auto type = hashTypes.begin(); type != hashTypes.end(); ++type)
101 cdBuilders.insert(make_pair(*type, new CodeDirectory::Builder(*type)));
102 }
103
104
105 //
106 // BlobEditor
107 //
108 BlobEditor::BlobEditor(Universal &fat, SecCodeSigner::Signer &s)
109 : ArchEditor(fat, s.digestAlgorithms(), 0), signer(s)
110 { }
111
112
113 void BlobEditor::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
114 {
115 mGlobal.component(slot, data);
116 }
117
118 void BlobEditor::write(Arch &arch, EmbeddedSignatureBlob *blob)
119 {
120 mMaker.add(arch.architecture.cpuType(), blob);
121 }
122
123
124 void BlobEditor::commit()
125 {
126 // create the architecture-global blob and store it into the superblob
127 mMaker.add(0, mGlobal.make()); // takes ownership of blob
128
129 // finish up the superblob and deliver it
130 DetachedSignatureBlob *blob = mMaker.make();
131 signer.state.returnDetachedSignature(blob, signer);
132 ::free(blob);
133 }
134
135
136 //
137 // MachOEditor's allocate() method spawns the codesign_allocate helper tool to
138 // "drill up" the Mach-O binary for insertion of Code Signing signature data.
139 // After the tool succeeds, we open the new file and are ready to write it.
140 //
141 MachOEditor::MachOEditor(DiskRep::Writer *w, Universal &code, CodeDirectory::HashAlgorithms hashTypes, std::string srcPath)
142 : ArchEditor(code, hashTypes, w->attributes()),
143 writer(w),
144 sourcePath(srcPath),
145 tempPath(srcPath + ".cstemp"),
146 mHashTypes(hashTypes),
147 mNewCode(NULL),
148 mTempMayExist(false)
149 {
150 if (const char *path = getenv(helperOverride)) {
151 mHelperPath = path;
152 mHelperOverridden = true;
153 } else {
154 mHelperPath = helperPath;
155 mHelperOverridden = false;
156 }
157 }
158
159 MachOEditor::~MachOEditor()
160 {
161 delete mNewCode;
162 if (mTempMayExist)
163 ::remove(tempPath.c_str()); // ignore error (can't do anything about it)
164 this->kill();
165 }
166
167
168 void MachOEditor::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
169 {
170 writer->component(slot, data);
171 }
172
173
174 void MachOEditor::allocate()
175 {
176 // note that we may have a temporary file from now on (for cleanup in the error case)
177 mTempMayExist = true;
178
179 // run codesign_allocate to make room in the executable file
180 fork();
181 wait();
182 if (!Child::succeeded())
183 MacOSError::throwMe(errSecCSHelperFailed);
184
185 // open the new (temporary) Universal file
186 {
187 UidGuard guard(0);
188 mFd.open(tempPath, O_RDWR);
189 }
190 mNewCode = new Universal(mFd);
191 }
192
193 static const unsigned char appleReq[] = {
194 // anchor apple and info["Application-Group"] = "com.apple.tool.codesign_allocate"
195 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
196 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x11, 0x41, 0x70, 0x70, 0x6c,
197 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
199 0x65, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x5f,
200 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65,
201 };
202
203 void MachOEditor::parentAction()
204 {
205 if (mHelperOverridden) {
206 CODESIGN_ALLOCATE_VALIDATE((char*)mHelperPath, this->pid());
207 // check code identity of an overridden allocation helper
208 SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(mHelperPath));
209 code->staticValidate(kSecCSDefaultFlags, NULL);
210 code->validateRequirement((const Requirement *)appleReq, errSecCSReqFailed);
211 }
212 }
213
214 void MachOEditor::childAction()
215 {
216 vector<const char *> arguments;
217 arguments.push_back(helperName);
218 arguments.push_back("-i");
219 arguments.push_back(sourcePath.c_str());
220 arguments.push_back("-o");
221 arguments.push_back(tempPath.c_str());
222
223 for (Iterator it = architecture.begin(); it != architecture.end(); ++it) {
224 size_t size = LowLevelMemoryUtilities::alignUp(it->second->blobSize, csAlign);
225 char *ssize; // we'll leak this (execv is coming soon)
226 asprintf(&ssize, "%zd", size);
227
228 if (const char *arch = it->first.name()) {
229 CODESIGN_ALLOCATE_ARCH((char*)arch, (unsigned int)size);
230 arguments.push_back("-a");
231 arguments.push_back(arch);
232 } else {
233 CODESIGN_ALLOCATE_ARCHN(it->first.cpuType(), it->first.cpuSubtype(), (unsigned int)size);
234 arguments.push_back("-A");
235 char *anum;
236 asprintf(&anum, "%d", it->first.cpuType());
237 arguments.push_back(anum);
238 asprintf(&anum, "%d", it->first.cpuSubtype());
239 arguments.push_back(anum);
240 }
241 arguments.push_back(ssize);
242 }
243 arguments.push_back(NULL);
244
245 if (mHelperOverridden)
246 ::csops(0, CS_OPS_MARKKILL, NULL, 0); // force code integrity
247 ::seteuid(0); // activate privilege if caller has it; ignore error if not
248 execv(mHelperPath, (char * const *)&arguments[0]);
249 }
250
251 void MachOEditor::reset(Arch &arch)
252 {
253 arch.source.reset(mNewCode->architecture(arch.architecture));
254
255 for (auto type = mHashTypes.begin(); type != mHashTypes.end(); ++type) {
256 arch.eachDigest(^(CodeDirectory::Builder& builder) {
257 builder.reopen(tempPath, arch.source->offset(), arch.source->signingOffset());
258 });
259 }
260 }
261
262
263 //
264 // MachOEditor's write() method actually writes the blob into the CODESIGNING section
265 // of the executable image file.
266 //
267 void MachOEditor::write(Arch &arch, EmbeddedSignatureBlob *blob)
268 {
269 if (size_t offset = arch.source->signingOffset()) {
270 size_t signingLength = arch.source->signingLength();
271 CODESIGN_ALLOCATE_WRITE((char*)arch.architecture.name(), offset, (unsigned)blob->length(), (unsigned)signingLength);
272 if (signingLength < blob->length())
273 MacOSError::throwMe(errSecCSCMSTooLarge);
274 arch.source->seek(offset);
275 arch.source->writeAll(*blob);
276 ::free(blob); // done with it
277 } else {
278 secdebug("signer", "%p cannot find CODESIGNING section", this);
279 MacOSError::throwMe(errSecCSInternalError);
280 }
281 }
282
283
284 //
285 // Commit the edit.
286 // This moves the temporary editor copy over the source image file.
287 // Note that the Universal object returned by allocate() is still open
288 // and valid; the caller owns it.
289 //
290 void MachOEditor::commit()
291 {
292 // if the file's owned by someone else *and* we can become root...
293 struct stat st;
294 UnixError::check(::stat(sourcePath.c_str(), &st));
295
296 // copy over all the *other* stuff
297 Copyfile copy;
298 int fd = mFd;
299 copy.set(COPYFILE_STATE_DST_FD, &fd);
300 {
301 // perform copy under root or file-owner privileges if available
302 UidGuard guard;
303 if (!guard.seteuid(0))
304 guard.seteuid(st.st_uid);
305
306 // copy metadata from original file...
307 copy(sourcePath.c_str(), NULL, COPYFILE_SECURITY | COPYFILE_METADATA);
308
309 // ... but explicitly update the timestamps since we did change the file
310 char buf;
311 mFd.read(&buf, sizeof(buf), 0);
312 mFd.write(&buf, sizeof(buf), 0);
313
314 // move the new file into place
315 UnixError::check(::rename(tempPath.c_str(), sourcePath.c_str()));
316 mTempMayExist = false; // we renamed it away
317 }
318 }
319
320
321 //
322 // InternalRequirements
323 //
324 void InternalRequirements::operator () (const Requirements *given, const Requirements *defaulted, const Requirement::Context &context)
325 {
326 // first add the default internal requirements
327 if (defaulted) {
328 this->add(defaulted);
329 ::free((void *)defaulted); // was malloc(3)ed by DiskRep
330 }
331
332 // now override them with any requirements explicitly given by the signer
333 if (given)
334 this->add(given);
335
336 // now add the Designated Requirement, if we can make it and it's not been provided
337 if (!this->contains(kSecDesignatedRequirementType)) {
338 DRMaker maker(context);
339 if (Requirement *dr = maker.make()) {
340 this->add(kSecDesignatedRequirementType, dr); // takes ownership of dr
341 }
342 }
343
344 // return the result
345 mReqs = this->make();
346 }
347
348
349 //
350 // Pre-Signing contexts
351 //
352 PreSigningContext::PreSigningContext(const SecCodeSigner::Signer &signer)
353 {
354 // construct a cert chain
355 if (signer.signingIdentity() != SecIdentityRef(kCFNull)) {
356 CFRef<SecCertificateRef> signingCert;
357 MacOSError::check(SecIdentityCopyCertificate(signer.signingIdentity(), &signingCert.aref()));
358 CFRef<SecPolicyRef> policy = SecPolicyCreateWithOID(kSecPolicyAppleCodeSigning);
359 CFRef<SecTrustRef> trust;
360 MacOSError::check(SecTrustCreateWithCertificates(CFArrayRef(signingCert.get()), policy, &trust.aref()));
361 SecTrustResultType result;
362 MacOSError::check(SecTrustEvaluate(trust, &result));
363 CSSM_TP_APPLE_EVIDENCE_INFO *info;
364 MacOSError::check(SecTrustGetResult(trust, &result, &mCerts.aref(), &info));
365 this->certs = mCerts;
366 }
367
368 // other stuff
369 this->identifier = signer.signingIdentifier();
370 }
371
372
373 //
374 // A collector of CodeDirectories for hash-agile construction of signatures.
375 //
376 CodeDirectorySet::~CodeDirectorySet()
377 {
378 for (auto it = begin(); it != end(); ++it)
379 ::free(const_cast<CodeDirectory*>(it->second));
380 }
381
382
383 void CodeDirectorySet::add(const Security::CodeSigning::CodeDirectory *cd)
384 {
385 insert(make_pair(cd->hashType, cd));
386 if (cd->hashType == kSecCodeSignatureHashSHA1)
387 mPrimary = cd;
388 }
389
390
391 void CodeDirectorySet::populate(DiskRep::Writer *writer) const
392 {
393 assert(!empty());
394
395 if (mPrimary == NULL) // didn't add SHA-1; pick another occupant for this slot
396 mPrimary = begin()->second;
397
398 // reserve slot zero for a SHA-1 digest if present; else pick something else
399 CodeDirectory::SpecialSlot nextAlternate = cdAlternateCodeDirectorySlots;
400 for (auto it = begin(); it != end(); ++it) {
401 if (it->second == mPrimary) {
402 writer->codeDirectory(it->second, cdCodeDirectorySlot);
403 } else {
404 writer->codeDirectory(it->second, nextAlternate++);
405 }
406 }
407 }
408
409
410 const CodeDirectory* CodeDirectorySet::primary() const
411 {
412 if (mPrimary == NULL)
413 mPrimary = begin()->second;
414 return mPrimary;
415 }
416
417
418 CFArrayRef CodeDirectorySet::hashBag() const
419 {
420 CFRef<CFMutableArrayRef> hashList = makeCFMutableArray(0);
421 for (auto it = begin(); it != end(); ++it) {
422 CFRef<CFDataRef> cdhash = it->second->cdhash();
423 CFArrayAppendValue(hashList, cdhash);
424 }
425 return hashList.yield();
426 }
427
428
429 } // end namespace CodeSigning
430 } // end namespace Security