2 * Copyright (c) 2006 Apple Computer, 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 // machorep - DiskRep mix-in for handling Mach-O main executables
28 #include "StaticCode.h"
33 namespace CodeSigning
{
35 using namespace UnixPlusPlus
;
40 // We open the main executable lazily, so nothing much happens on construction.
41 // If the context specifies a file offset, we directly pick that Mach-O binary (only).
42 // if it specifies an architecture, we try to pick that. Otherwise, we deliver the whole
43 // Universal object (which will usually deliver the "native" architecture later).
45 MachORep::MachORep(const char *path
, const Context
*ctx
)
46 : SingleDiskRep(path
), mSigningData(NULL
)
50 mExecutable
= new Universal(fd(), (size_t)ctx
->offset
);
52 auto_ptr
<Universal
> full(new Universal(fd()));
53 mExecutable
= new Universal(fd(), full
->archOffset(ctx
->arch
));
55 mExecutable
= new Universal(fd());
57 mExecutable
= new Universal(fd());
59 CODESIGN_DISKREP_CREATE_MACHO(this, (char*)path
, (void*)ctx
);
70 // Sniffer function for "plausible Mach-O binary"
72 bool MachORep::candidate(FileDesc
&fd
)
74 switch (Universal::typeOf(fd
)) {
81 return true; // dynamic image; supported
83 return false; // maybe later...
85 return false; // not Mach-O (or too exotic)
92 // Nowadays, the main executable object is created upon construction.
94 Universal
*MachORep::mainExecutableImage()
101 // Signing base is the start of the Mach-O architecture we're using
103 size_t MachORep::signingBase()
105 return mainExecutableImage()->archOffset();
110 // We choose the binary identifier for a Mach-O binary as follows:
111 // - If the Mach-O headers have a UUID command, use the UUID.
112 // - Otherwise, use the SHA-1 hash of the (entire) load commands.
114 CFDataRef
MachORep::identification()
116 std::auto_ptr
<MachO
> macho(mainExecutableImage()->architecture());
117 return identificationFor(macho
.get());
120 CFDataRef
MachORep::identificationFor(MachO
*macho
)
122 // if there is a LC_UUID load command, use the UUID contained therein
123 if (const load_command
*cmd
= macho
->findCommand(LC_UUID
)) {
124 const uuid_command
*uuidc
= reinterpret_cast<const uuid_command
*>(cmd
);
125 char result
[4 + sizeof(uuidc
->uuid
)];
126 memcpy(result
, "UUID", 4);
127 memcpy(result
+4, uuidc
->uuid
, sizeof(uuidc
->uuid
));
128 return makeCFData(result
, sizeof(result
));
131 // otherwise, use the SHA-1 hash of the entire load command area
133 hash(&macho
->header(), sizeof(mach_header
));
134 hash(macho
->loadCommands(), macho
->commandLength());
137 return makeCFData(digest
, sizeof(digest
));
142 // Retrieve a component from the executable.
143 // This reads the entire signing SuperBlob when first called for an executable,
144 // and then caches it for further use.
145 // Note that we could read individual components directly off disk and only cache
146 // the SuperBlob Index directory. Our caller (usually SecStaticCode) is expected
147 // to cache the pieces anyway.
149 CFDataRef
MachORep::component(CodeDirectory::SpecialSlot slot
)
155 return embeddedComponent(slot
);
160 // Retrieve a component from the embedded signature SuperBlob (if present).
161 // This reads the entire signing SuperBlob when first called for an executable,
162 // and then caches it for further use.
163 // Note that we could read individual components directly off disk and only cache
164 // the SuperBlob Index directory. Our caller (usually SecStaticCode) is expected
165 // to cache the pieces anyway. But it's not clear that the resulting multiple I/O
166 // calls wouldn't be slower in the end.
168 CFDataRef
MachORep::embeddedComponent(CodeDirectory::SpecialSlot slot
)
170 if (!mSigningData
) { // fetch and cache
171 auto_ptr
<MachO
> macho(mainExecutableImage()->architecture());
173 if (const linkedit_data_command
*cs
= macho
->findCodeSignature()) {
174 size_t offset
= macho
->flip(cs
->dataoff
);
175 size_t length
= macho
->flip(cs
->datasize
);
176 if ((mSigningData
= EmbeddedSignatureBlob::readBlob(macho
->fd(), macho
->offset() + offset
, length
))) {
177 secdebug("machorep", "%zd signing bytes in %d blob(s) from %s(%s)",
178 mSigningData
->length(), mSigningData
->count(),
179 mainExecutablePath().c_str(), macho
->architecture().name());
181 secdebug("machorep", "failed to read signing bytes from %s(%s)",
182 mainExecutablePath().c_str(), macho
->architecture().name());
183 MacOSError::throwMe(errSecCSSignatureInvalid
);
188 return mSigningData
->component(slot
);
196 // Extract an embedded Info.plist from the file.
197 // Returns NULL if none is found.
199 CFDataRef
MachORep::infoPlist()
201 CFRef
<CFDataRef
> info
;
203 auto_ptr
<MachO
> macho(mainExecutableImage()->architecture());
204 if (const section
*sect
= macho
->findSection("__TEXT", "__info_plist")) {
206 const section_64
*sect64
= reinterpret_cast<const section_64
*>(sect
);
207 info
.take(macho
->dataAt(macho
->flip(sect64
->offset
), (size_t)macho
->flip(sect64
->size
)));
209 info
.take(macho
->dataAt(macho
->flip(sect
->offset
), macho
->flip(sect
->size
)));
213 secdebug("machorep", "exception reading embedded Info.plist");
220 // Provide a (vaguely) human readable characterization of this code
222 string
MachORep::format()
224 if (Universal
*fat
= mainExecutableImage()) {
225 Universal::Architectures archs
;
226 fat
->architectures(archs
);
227 if (fat
->isUniversal()) {
228 string s
= "Mach-O universal (";
229 for (Universal::Architectures::const_iterator it
= archs
.begin();
230 it
!= archs
.end(); ++it
) {
231 if (it
!= archs
.begin())
233 s
+= it
->displayName();
237 assert(archs
.size() == 1);
238 return string("Mach-O thin (") + archs
.begin()->displayName() + ")";
241 return "Mach-O (unrecognized format)";
248 void MachORep::flush()
252 ::free(mSigningData
);
254 SingleDiskRep::flush();
255 mExecutable
= new Universal(fd());
260 // Return a recommended unique identifier.
261 // If our file has an embedded Info.plist, use the CFBundleIdentifier from that.
262 // Otherwise, use the default.
264 string
MachORep::recommendedIdentifier(const SigningContext
&ctx
)
266 if (CFDataRef info
= infoPlist()) {
267 if (CFRef
<CFDictionaryRef
> dict
= makeCFDictionaryFrom(info
)) {
268 CFStringRef code
= CFStringRef(CFDictionaryGetValue(dict
, kCFBundleIdentifierKey
));
269 if (code
&& CFGetTypeID(code
) != CFStringGetTypeID())
270 MacOSError::throwMe(errSecCSBadDictionaryFormat
);
272 return cfString(code
);
274 MacOSError::throwMe(errSecCSBadDictionaryFormat
);
277 // ah well. Use the default
278 return SingleDiskRep::recommendedIdentifier(ctx
);
283 // The default suggested requirements for Mach-O binaries are as follows:
284 // Library requirement: Composed from dynamic load commands.
286 const Requirements
*MachORep::defaultRequirements(const Architecture
*arch
, const SigningContext
&ctx
)
288 assert(arch
); // enforced by signing infrastructure
289 Requirements::Maker maker
;
291 // add library requirements from DYLIB commands (if any)
292 if (Requirement
*libreq
= libraryRequirements(arch
, ctx
))
293 maker
.add(kSecLibraryRequirementType
, libreq
); // takes ownership
299 Requirement
*MachORep::libraryRequirements(const Architecture
*arch
, const SigningContext
&ctx
)
301 auto_ptr
<MachO
> macho(mainExecutableImage()->architecture(*arch
));
302 Requirement::Maker maker
;
303 Requirement::Maker::Chain
chain(maker
, opOr
);
306 if (const linkedit_data_command
*ldep
= macho
->findLibraryDependencies()) {
307 size_t offset
= macho
->flip(ldep
->dataoff
);
308 size_t length
= macho
->flip(ldep
->datasize
);
309 if (LibraryDependencyBlob
*deplist
= LibraryDependencyBlob::readBlob(macho
->fd(), macho
->offset() + offset
, length
)) {
311 secdebug("machorep", "%zd library dependency bytes in %d blob(s) from %s(%s)",
312 deplist
->length(), deplist
->count(),
313 mainExecutablePath().c_str(), macho
->architecture().name());
314 unsigned count
= deplist
->count();
315 // we could walk through DYLIB load commands in parallel. We just don't need anything from them so far
316 for (unsigned n
= 0; n
< count
; n
++) {
317 const Requirement
*req
= NULL
;
318 if (const BlobCore
*dep
= deplist
->blob(n
)) {
319 if ((req
= Requirement::specific(dep
))) {
320 // binary code requirement; good to go
321 } else if (const BlobWrapper
*wrap
= BlobWrapper::specific(dep
)) {
322 // blob-wrapped text form - convert to binary requirement
323 std::string reqString
= std::string((const char *)wrap
->data(), wrap
->length());
324 CFRef
<SecRequirementRef
> areq
;
325 MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString
), kSecCSDefaultFlags
, &areq
.aref()));
326 CFRef
<CFDataRef
> reqData
;
327 MacOSError::check(SecRequirementCopyData(areq
, kSecCSDefaultFlags
, &reqData
.aref()));
328 req
= Requirement::specific((const BlobCore
*)CFDataGetBytePtr(reqData
));
330 secdebug("machorep", "unexpected blob type 0x%x in slot %d of binary dependencies", dep
->magic(), n
);
336 secdebug("machorep", "missing DR info for library index %d", n
);
353 // Default to system page size for segmented (paged) signatures
355 size_t MachORep::pageSize(const SigningContext
&)
357 return segmentedPageSize
;
362 // FileDiskRep::Writers
364 DiskRep::Writer
*MachORep::writer()
366 return new Writer(this);
371 // Write a component.
372 // MachORep::Writers don't write to components directly; the signing code uses special
373 // knowledge of the Mach-O format to build embedded signatures and blasts them directly
374 // to disk. Thus this implementation will never be called (and, if called, will simply fail).
376 void MachORep::Writer::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
379 MacOSError::throwMe(errSecCSInternalError
);
383 } // end namespace CodeSigning
384 } // end namespace Security