]>
git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/signerutils.cpp
a7e925ae216ae66b5a7c9842b61bc6f19404fba0
2 * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 // signerutils - utilities for signature generation
27 #include "signerutils.h"
29 #include "SecCodeSigner.h"
30 #include <Security/SecIdentity.h>
31 #include <Security/CMSEncoder.h>
33 #include "csutilities.h"
34 #include <security_utilities/unix++.h>
35 #include <security_utilities/unixchild.h>
38 // for helper validation
40 #include <security_utilities/cfmunge.h>
41 #include <sys/codesign.h>
45 namespace CodeSigning
{
49 // About the Mach-O allocation helper
51 static const char helperName
[] = "codesign_allocate";
52 static const char helperPath
[] = "/usr/bin/codesign_allocate";
53 static const char helperOverride
[] = "CODESIGN_ALLOCATE";
54 static const size_t csAlign
= 16;
60 void BlobWriter::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
62 return EmbeddedSignatureBlob::Maker::component(slot
, data
);
66 void DetachedBlobWriter::flush()
68 EmbeddedSignatureBlob
*blob
= this->make();
69 signer
.code
->detachedSignature(makeCFData(*blob
));
70 signer
.state
.returnDetachedSignature(blob
, signer
);
78 ArchEditor::ArchEditor(Universal
&code
, uint32_t attrs
/* = 0 */)
79 : DiskRep::Writer(attrs
)
81 Universal::Architectures archList
;
82 code
.architectures(archList
);
83 for (Universal::Architectures::const_iterator it
= archList
.begin();
84 it
!= archList
.end(); ++it
)
85 architecture
[*it
] = new Arch(*it
);
89 ArchEditor::~ArchEditor()
91 for (ArchMap::iterator it
= begin(); it
!= end(); ++it
)
99 void BlobEditor::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
101 mGlobal
.component(slot
, data
);
104 void BlobEditor::write(Arch
&arch
, EmbeddedSignatureBlob
*blob
)
106 mMaker
.add(arch
.architecture
.cpuType(), blob
);
110 void BlobEditor::commit()
112 // create the architecture-global blob and store it into the superblob
113 mMaker
.add(0, mGlobal
.make()); // takes ownership of blob
115 // finish up the superblob and deliver it
116 DetachedSignatureBlob
*blob
= mMaker
.make();
117 signer
.state
.returnDetachedSignature(blob
, signer
);
123 // MachOEditor's allocate() method spawns the codesign_allocate helper tool to
124 // "drill up" the Mach-O binary for insertion of Code Signing signature data.
125 // After the tool succeeds, we open the new file and are ready to write it.
127 MachOEditor::MachOEditor(DiskRep::Writer
*w
, Universal
&code
, std::string srcPath
)
128 : ArchEditor(code
, w
->attributes()), writer(w
), sourcePath(srcPath
), tempPath(srcPath
+ ".cstemp"),
129 mNewCode(NULL
), mTempMayExist(false)
131 if (const char *path
= getenv(helperOverride
)) {
133 mHelperOverridden
= true;
135 mHelperPath
= helperPath
;
136 mHelperOverridden
= false;
140 MachOEditor::~MachOEditor()
144 ::remove(tempPath
.c_str()); // ignore error (can't do anything about it)
149 void MachOEditor::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
151 writer
->component(slot
, data
);
155 void MachOEditor::allocate()
157 // note that we may have a temporary file from now on (for cleanup in the error case)
158 mTempMayExist
= true;
160 // run codesign_allocate to make room in the executable file
163 if (!Child::succeeded())
164 UnixError::throwMe(ENOEXEC
); //@@@ how to signal "it din' work"?
166 // open the new (temporary) Universal file
169 mFd
.open(tempPath
, O_RDWR
);
171 mNewCode
= new Universal(mFd
);
174 static const unsigned char appleReq
[] = {
175 // anchor apple and info["Application-Group"] = "com.apple.tool.codesign_allocate"
176 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
177 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x11, 0x41, 0x70, 0x70, 0x6c,
178 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x00, 0x00, 0x00,
179 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
180 0x65, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x5f,
181 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65,
184 void MachOEditor::parentAction()
186 if (mHelperOverridden
) {
187 CODESIGN_ALLOCATE_VALIDATE((char*)mHelperPath
, this->pid());
188 // check code identity of an overridden allocation helper
189 SecPointer
<SecStaticCode
> code
= new SecStaticCode(DiskRep::bestGuess(mHelperPath
));
190 code
->validateDirectory();
191 code
->validateExecutable();
192 code
->validateResources();
193 code
->validateRequirements((const Requirement
*)appleReq
, errSecCSReqFailed
);
197 void MachOEditor::childAction()
199 vector
<const char *> arguments
;
200 arguments
.push_back(helperName
);
201 arguments
.push_back("-i");
202 arguments
.push_back(sourcePath
.c_str());
203 arguments
.push_back("-o");
204 arguments
.push_back(tempPath
.c_str());
206 for (Iterator it
= architecture
.begin(); it
!= architecture
.end(); ++it
) {
207 size_t size
= LowLevelMemoryUtilities::alignUp(it
->second
->blobSize
, csAlign
);
208 char *ssize
; // we'll leak this (execv is coming soon)
209 asprintf(&ssize
, "%d", size
);
211 if (const char *arch
= it
->first
.name()) {
212 CODESIGN_ALLOCATE_ARCH((char*)arch
, size
);
213 arguments
.push_back("-a");
214 arguments
.push_back(arch
);
216 CODESIGN_ALLOCATE_ARCHN(it
->first
.cpuType(), it
->first
.cpuSubtype(), size
);
217 arguments
.push_back("-A");
219 asprintf(&anum
, "%d", it
->first
.cpuType());
220 arguments
.push_back(anum
);
221 asprintf(&anum
, "%d", it
->first
.cpuSubtype());
222 arguments
.push_back(anum
);
224 arguments
.push_back(ssize
);
226 arguments
.push_back(NULL
);
228 if (mHelperOverridden
)
229 ::csops(0, CS_EXEC_SET_KILL
, NULL
, 0); // force code integrity
230 ::seteuid(0); // activate privilege if caller has it; ignore error if not
231 execv(mHelperPath
, (char * const *)&arguments
[0]);
234 void MachOEditor::reset(Arch
&arch
)
236 arch
.source
.reset(mNewCode
->architecture(arch
.architecture
));
237 arch
.cdbuilder
.reopen(tempPath
,
238 arch
.source
->offset(), arch
.source
->signingOffset());
243 // MachOEditor's write() method actually writes the blob into the CODESIGNING section
244 // of the executable image file.
246 void MachOEditor::write(Arch
&arch
, EmbeddedSignatureBlob
*blob
)
248 if (size_t offset
= arch
.source
->signingOffset()) {
249 size_t signingLength
= arch
.source
->signingLength();
250 CODESIGN_ALLOCATE_WRITE((char*)arch
.architecture
.name(), offset
, blob
->length(), signingLength
);
251 if (signingLength
< blob
->length())
252 MacOSError::throwMe(errSecCSCMSTooLarge
);
253 arch
.source
->seek(offset
);
254 arch
.source
->writeAll(*blob
);
255 ::free(blob
); // done with it
257 secdebug("signer", "%p cannot find CODESIGNING section", this);
258 MacOSError::throwMe(errSecCSInternalError
);
265 // This moves the temporary editor copy over the source image file.
266 // Note that the Universal object returned by allocate() is still open
267 // and valid; the caller owns it.
269 void MachOEditor::commit()
271 // if the file's owned by someone else *and* we can become root...
273 UnixError::check(::stat(sourcePath
.c_str(), &st
));
275 // copy over all the *other* stuff
278 copy
.set(COPYFILE_STATE_DST_FD
, &fd
);
280 // perform copy under root or file-owner privileges if available
282 if (!guard
.seteuid(0))
283 guard
.seteuid(st
.st_uid
);
284 copy(sourcePath
.c_str(), NULL
, COPYFILE_SECURITY
| COPYFILE_METADATA
);
286 // move the new file into place
287 UnixError::check(::rename(tempPath
.c_str(), sourcePath
.c_str()));
288 mTempMayExist
= false; // we renamed it away
293 } // end namespace CodeSigning
294 } // end namespace Security