]>
git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/signerutils.cpp
e005e82700b6e4d2f6713cfa2e34eea25ede015a
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 <security_utilities/unix++.h>
34 #include <security_utilities/unixchild.h>
38 namespace CodeSigning
{
42 // About the Mach-O allocation helper
44 static const char helperName
[] = "codesign_allocate";
45 static const char helperPath
[] = "/usr/bin/codesign_allocate";
46 static const size_t csAlign
= 16;
50 // InternalRequirements
52 void InternalRequirements::operator () (const Requirements
*given
, const Requirements
*defaulted
)
56 ::free((void *)defaulted
); // was malloc(3)ed by DiskRep
67 void BlobWriter::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
69 return EmbeddedSignatureBlob::Maker::component(slot
, data
);
73 void DetachedBlobWriter::flush()
75 EmbeddedSignatureBlob
*blob
= this->make();
76 signer
.code
->detachedSignature(CFTempData(*blob
));
77 signer
.state
.returnDetachedSignature(blob
);
85 ArchEditor::ArchEditor(Universal
&code
, uint32_t attrs
/* = 0 */)
86 : DiskRep::Writer(attrs
)
88 Universal::Architectures archList
;
89 code
.architectures(archList
);
90 for (Universal::Architectures::const_iterator it
= archList
.begin();
91 it
!= archList
.end(); ++it
)
92 architecture
[*it
] = new Arch(*it
);
96 ArchEditor::~ArchEditor()
98 for (ArchMap::iterator it
= begin(); it
!= end(); ++it
)
106 void BlobEditor::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
108 mGlobal
.component(slot
, data
);
111 void BlobEditor::write(Arch
&arch
, EmbeddedSignatureBlob
*blob
)
113 mMaker
.add(arch
.architecture
.cpuType(), blob
);
117 void BlobEditor::commit()
119 // create the architecture-global blob and store it into the superblob
120 mMaker
.add(0, mGlobal
.make()); // takes ownership of blob
122 // finish up the superblob and deliver it
123 DetachedSignatureBlob
*blob
= mMaker
.make();
124 signer
.state
.returnDetachedSignature(blob
);
130 // MachOEditor's allocate() method spawns the codesign_allocate helper tool to
131 // "drill up" the Mach-O binary for insertion of Code Signing signature data.
132 // After the tool succeeds, we open the new file and are ready to write it.
134 MachOEditor::MachOEditor(DiskRep::Writer
*w
, Universal
&code
, std::string srcPath
)
135 : ArchEditor(code
, w
->attributes()), writer(w
), sourcePath(srcPath
), tempPath(srcPath
+ ".cstemp"),
136 mNewCode(NULL
), mTempMayExist(false)
140 MachOEditor::~MachOEditor()
144 ::remove(tempPath
.c_str()); // ignore error (can't do anything about it)
148 void MachOEditor::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
150 writer
->component(slot
, data
);
154 void MachOEditor::allocate()
156 // note that we may have a temporary file from now on (for cleanup in the error case)
157 mTempMayExist
= true;
159 // run codesign_allocate to make room in the executable file
162 if (!Child::succeeded())
163 UnixError::throwMe(ENOEXEC
); //@@@ how to signal "it din' work"?
165 // open the new (temporary) Universal file
168 mFd
.open(tempPath
, O_RDWR
);
170 mNewCode
= new Universal(mFd
);
173 void MachOEditor::childAction()
175 vector
<const char *> arguments
;
176 arguments
.push_back(helperName
);
177 arguments
.push_back("-i");
178 arguments
.push_back(sourcePath
.c_str());
179 arguments
.push_back("-o");
180 arguments
.push_back(tempPath
.c_str());
182 for (Iterator it
= architecture
.begin(); it
!= architecture
.end(); ++it
) {
183 char *size
; // we'll leak this (execv is coming soon)
184 asprintf(&size
, "%d", LowLevelMemoryUtilities::alignUp(it
->second
->blobSize
, csAlign
));
185 secdebug("machoedit", "preparing %s size=%s", it
->first
.name(), size
);
186 arguments
.push_back("-a");
187 arguments
.push_back(it
->first
.name());
188 arguments
.push_back(size
);
190 arguments
.push_back(NULL
);
191 ::seteuid(0); // activate privilege if caller has it; ignore error if not
192 execv(helperPath
, (char * const *)&arguments
[0]);
195 void MachOEditor::reset(Arch
&arch
)
197 arch
.source
.reset(mNewCode
->architecture(arch
.architecture
));
198 arch
.cdbuilder
.reopen(tempPath
,
199 arch
.source
->offset(), arch
.source
->signingOffset());
204 // MachOEditor's write() method actually writes the blob into the CODESIGNING section
205 // of the executable image file.
207 void MachOEditor::write(Arch
&arch
, EmbeddedSignatureBlob
*blob
)
209 if (size_t offset
= arch
.source
->signingOffset()) {
210 size_t signingLength
= arch
.source
->signingLength();
211 secdebug("codesign", "writing architecture %s at 0x%zx (%zd of %zd)",
212 arch
.architecture
.name(), offset
, blob
->length(), signingLength
);
213 if (signingLength
< blob
->length()) {
214 secdebug("codesign", "trying to write %zd bytes into %zd area",
215 blob
->length(), signingLength
);
216 MacOSError::throwMe(errSecCSInternalError
);
218 arch
.source
->seek(offset
);
219 arch
.source
->writeAll(*blob
);
220 ::free(blob
); // done with it
222 secdebug("signer", "%p cannot find CODESIGNING section", this);
223 MacOSError::throwMe(errSecCSInternalError
);
230 // This moves the temporary editor copy over the source image file.
231 // Note that the Universal object returned by allocate() is still open
232 // and valid; the caller owns it.
234 void MachOEditor::commit()
236 // if the file's owned by someone else *and* we can become root...
238 UnixError::check(::stat(sourcePath
.c_str(), &st
));
240 // copy over all the *other* stuff
243 copy
.set(COPYFILE_STATE_DST_FD
, &fd
);
245 // perform copy under root or file-owner privileges if available
247 if (!guard
.seteuid(0))
248 guard
.seteuid(st
.st_uid
);
249 copy(sourcePath
.c_str(), NULL
, COPYFILE_SECURITY
| COPYFILE_METADATA
);
251 // move the new file into place
252 UnixError::check(::rename(tempPath
.c_str(), sourcePath
.c_str()));
253 mTempMayExist
= false; // we renamed it away
263 if (!(mState
= copyfile_state_alloc()))
264 UnixError::throwMe();
267 void Copyfile::set(uint32_t flag
, const void *value
)
269 check(::copyfile_state_set(mState
, flag
, value
));
272 void Copyfile::get(uint32_t flag
, void *value
)
274 check(::copyfile_state_set(mState
, flag
, value
));
277 void Copyfile::operator () (const char *src
, const char *dst
, copyfile_flags_t flags
)
279 check(::copyfile(src
, dst
, mState
, flags
));
282 void Copyfile::check(int rc
)
285 UnixError::throwMe();
289 } // end namespace CodeSigning
290 } // end namespace Security