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(), 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
)) {
80 return true; // dynamic image; supported
82 return false; // maybe later...
84 return false; // not Mach-O (or too exotic)
91 // Nowadays, the main executable object is created upon construction.
93 Universal
*MachORep::mainExecutableImage()
100 // Signing base is the start of the Mach-O architecture we're using
102 size_t MachORep::signingBase()
104 return mainExecutableImage()->archOffset();
109 // We choose the binary identifier for a Mach-O binary as follows:
110 // - If the Mach-O headers have a UUID command, use the UUID.
111 // - Otherwise, use the SHA-1 hash of the (entire) load commands.
113 CFDataRef
MachORep::identification()
115 std::auto_ptr
<MachO
> macho(mainExecutableImage()->architecture());
116 return identificationFor(macho
.get());
119 CFDataRef
MachORep::identificationFor(MachO
*macho
)
121 // if there is a LC_UUID load command, use the UUID contained therein
122 if (const load_command
*cmd
= macho
->findCommand(LC_UUID
)) {
123 const uuid_command
*uuidc
= reinterpret_cast<const uuid_command
*>(cmd
);
124 char result
[4 + sizeof(uuidc
->uuid
)];
125 memcpy(result
, "UUID", 4);
126 memcpy(result
+4, uuidc
->uuid
, sizeof(uuidc
->uuid
));
127 return makeCFData(result
, sizeof(result
));
130 // otherwise, use the SHA-1 hash of the entire load command area
132 hash(&macho
->header(), sizeof(mach_header
));
133 hash(macho
->loadCommands(), macho
->commandLength());
136 return makeCFData(digest
, sizeof(digest
));
141 // Retrieve a component from the executable.
142 // This reads the entire signing SuperBlob when first called for an executable,
143 // and then caches it for further use.
144 // Note that we could read individual components directly off disk and only cache
145 // the SuperBlob Index directory. Our caller (usually SecStaticCode) is expected
146 // to cache the pieces anyway.
148 CFDataRef
MachORep::component(CodeDirectory::SpecialSlot slot
)
154 return embeddedComponent(slot
);
159 // Retrieve a component from the embedded signature SuperBlob (if present).
160 // This reads the entire signing SuperBlob when first called for an executable,
161 // and then caches it for further use.
162 // Note that we could read individual components directly off disk and only cache
163 // the SuperBlob Index directory. Our caller (usually SecStaticCode) is expected
164 // to cache the pieces anyway. But it's not clear that the resulting multiple I/O
165 // calls wouldn't be slower in the end.
167 CFDataRef
MachORep::embeddedComponent(CodeDirectory::SpecialSlot slot
)
169 if (!mSigningData
) { // fetch and cache
170 auto_ptr
<MachO
> macho(mainExecutableImage()->architecture());
172 if (const linkedit_data_command
*cs
= macho
->findCodeSignature()) {
173 size_t offset
= macho
->flip(cs
->dataoff
);
174 size_t length
= macho
->flip(cs
->datasize
);
175 if (mSigningData
= EmbeddedSignatureBlob::readBlob(macho
->fd(), macho
->offset() + offset
, length
)) {
176 secdebug("machorep", "%zd signing bytes in %d blob(s) from %s(%s)",
177 mSigningData
->length(), mSigningData
->count(),
178 mainExecutablePath().c_str(), macho
->architecture().name());
180 secdebug("machorep", "failed to read signing bytes from %s(%s)",
181 mainExecutablePath().c_str(), macho
->architecture().name());
182 MacOSError::throwMe(errSecCSSignatureInvalid
);
187 return mSigningData
->component(slot
);
195 // Extract an embedded Info.plist from the file.
196 // Returns NULL if none is found.
198 CFDataRef
MachORep::infoPlist()
200 CFRef
<CFDataRef
> info
;
202 auto_ptr
<MachO
> macho(mainExecutableImage()->architecture());
203 if (const section
*sect
= macho
->findSection("__TEXT", "__info_plist")) {
205 const section_64
*sect64
= reinterpret_cast<const section_64
*>(sect
);
206 info
.take(macho
->dataAt(macho
->flip(sect64
->offset
), macho
->flip(sect64
->size
)));
208 info
.take(macho
->dataAt(macho
->flip(sect
->offset
), macho
->flip(sect
->size
)));
212 secdebug("machorep", "exception reading embedded Info.plist");
219 // Provide a (vaguely) human readable characterization of this code
221 string
MachORep::format()
223 if (Universal
*fat
= mainExecutableImage()) {
224 Universal::Architectures archs
;
225 fat
->architectures(archs
);
226 if (fat
->isUniversal()) {
227 string s
= "Mach-O universal (";
228 for (Universal::Architectures::const_iterator it
= archs
.begin();
229 it
!= archs
.end(); ++it
) {
230 if (it
!= archs
.begin())
232 s
+= it
->displayName();
236 assert(archs
.size() == 1);
237 return string("Mach-O thin (") + archs
.begin()->displayName() + ")";
240 return "Mach-O (unrecognized format)";
247 void MachORep::flush()
251 ::free(mSigningData
);
253 SingleDiskRep::flush();
254 mExecutable
= new Universal(fd());
259 // Return a recommended unique identifier.
260 // If our file has an embedded Info.plist, use the CFBundleIdentifier from that.
261 // Otherwise, use the default.
263 string
MachORep::recommendedIdentifier(const SigningContext
&ctx
)
265 if (CFDataRef info
= infoPlist()) {
266 if (CFDictionaryRef dict
= makeCFDictionaryFrom(info
)) {
267 CFStringRef code
= CFStringRef(CFDictionaryGetValue(dict
, kCFBundleIdentifierKey
));
268 if (code
&& CFGetTypeID(code
) != CFStringGetTypeID())
269 MacOSError::throwMe(errSecCSBadDictionaryFormat
);
271 return cfString(code
);
273 MacOSError::throwMe(errSecCSBadDictionaryFormat
);
276 // ah well. Use the default
277 return SingleDiskRep::recommendedIdentifier(ctx
);
282 // The default suggested requirements for Mach-O binaries are as follows:
283 // Hosting requirement: Rosetta if it's PPC, none otherwise.
284 // Library requirement: Composed from dynamic load commands.
286 static const uint8_t ppc_host_ireq
[] = { // anchor apple and identifier com.apple.translate
287 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
288 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x63, 0x6f, 0x6d, 0x2e,
289 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x65, 0x00,
292 const Requirements
*MachORep::defaultRequirements(const Architecture
*arch
, const SigningContext
&ctx
)
294 assert(arch
); // enforced by signing infrastructure
295 Requirements::Maker maker
;
297 // if ppc architecture, add hosting requirement for Rosetta's translate tool
298 if (arch
->cpuType() == CPU_TYPE_POWERPC
)
299 maker
.add(kSecHostRequirementType
, ((const Requirement
*)ppc_host_ireq
)->clone());
301 // add library requirements from DYLIB commands (if any)
302 if (Requirement
*libreq
= libraryRequirements(arch
, ctx
))
303 maker
.add(kSecLibraryRequirementType
, libreq
); // takes ownership
309 Requirement
*MachORep::libraryRequirements(const Architecture
*arch
, const SigningContext
&ctx
)
311 auto_ptr
<MachO
> macho(mainExecutableImage()->architecture(*arch
));
312 Requirement::Maker maker
;
313 Requirement::Maker::Chain
chain(maker
, opOr
);
315 for (const load_command
*command
= macho
->loadCommands(); command
; command
= macho
->nextCommand(command
)) {
316 if (macho
->flip(command
->cmd
) == LC_LOAD_DYLIB
) {
317 const dylib_command
*dycmd
= (const dylib_command
*)command
;
318 if (const char *name
= macho
->string(command
, dycmd
->dylib
.name
))
320 string path
= ctx
.sdkPath(name
);
321 secdebug("machorep", "examining DYLIB %s", path
.c_str());
322 // find path on disk, get designated requirement (if signed)
323 if (RefPointer
<DiskRep
> rep
= DiskRep::bestGuess(path
))
324 if (SecPointer
<SecStaticCode
> code
= new SecStaticCode(rep
))
325 if (const Requirement
*req
= code
->designatedRequirement()) {
326 CODESIGN_SIGN_DEP_MACHO(this, (char*)path
.c_str(), (void*)req
);
328 chain
.maker
.copy(req
);
331 CODESIGN_SIGN_DEP_MACHO(this, (char*)name
, NULL
);
332 secdebug("machorep", "exception getting library requirement (ignored)");
335 CODESIGN_SIGN_DEP_MACHO(this, NULL
, NULL
);
347 // Default to system page size for segmented (paged) signatures
349 size_t MachORep::pageSize(const SigningContext
&)
351 return segmentedPageSize
;
356 // FileDiskRep::Writers
358 DiskRep::Writer
*MachORep::writer()
360 return new Writer(this);
365 // Write a component.
366 // MachORep::Writers don't write to components directly; the signing code uses special
367 // knowledge of the Mach-O format to build embedded signatures and blasts them directly
368 // to disk. Thus this implementation will never be called (and, if called, will simply fail).
370 void MachORep::Writer::component(CodeDirectory::SpecialSlot slot
, CFDataRef data
)
373 MacOSError::throwMe(errSecCSInternalError
);
377 } // end namespace CodeSigning
378 } // end namespace Security