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 // codedirectory - format and operations for code signing "code directory" structures
27 #include "codedirectory.h"
30 using namespace UnixPlusPlus
;
34 namespace CodeSigning
{
38 // Canonical filesystem names for select slot numbers.
39 // These are variously used for filenames, extended attribute names, etc.
40 // to get some consistency in naming. These are for storing signing-related
41 // data; they have no bearing on the actual hash slots in the CodeDirectory.
43 const char *CodeDirectory::canonicalSlotName(SpecialSlot slot
)
46 case cdRequirementsSlot
:
47 return kSecCS_REQUIREMENTSFILE
;
48 case cdResourceDirSlot
:
49 return kSecCS_RESOURCEDIRFILE
;
50 case cdCodeDirectorySlot
:
51 return kSecCS_CODEDIRECTORYFILE
;
53 return kSecCS_SIGNATUREFILE
;
54 case cdApplicationSlot
:
55 return kSecCS_APPLICATIONFILE
;
63 // Canonical attributes of SpecialSlots.
65 unsigned CodeDirectory::slotAttributes(SpecialSlot slot
)
68 case cdRequirementsSlot
:
69 return cdComponentIsBlob
; // global
70 case cdCodeDirectorySlot
:
71 return cdComponentPerArchitecture
| cdComponentIsBlob
;
73 return cdComponentPerArchitecture
; // raw
75 return 0; // global, raw
81 // Symbolic names for code directory special slots.
82 // These are only used for debug output. They are not API-official.
83 // Needs to be coordinated with the cd*Slot enumeration in codedirectory.h.
86 const char * const CodeDirectory::debugSlotName
[] = {
97 // Check the version of this CodeDirectory for basic sanity.
98 // Throws if the directory is corrupted or out of versioning bounds.
99 // Returns if the version is usable (perhaps with degraded features due to
100 // compatibility hacks).
102 void CodeDirectory::checkVersion() const
104 if (!this->validateBlob())
105 MacOSError::throwMe(errSecCSSignatureInvalid
); // busted
106 if (version
> compatibilityLimit
)
107 MacOSError::throwMe(errSecCSSignatureUnsupported
); // too new - no clue
108 if (version
> currentVersion
)
109 secdebug("codedir", "%p version 0x%x newer than current 0x%x",
110 this, uint32_t(version
), currentVersion
);
115 // Validate a slot against data in memory.
117 bool CodeDirectory::validateSlot(const void *data
, size_t length
, Slot slot
) const
119 secdebug("codedir", "%p validating slot %d", this, int(slot
));
120 Hash::Byte digest
[Hash::digestLength
];
121 hash(data
, length
, digest
);
122 return memcmp(digest
, (*this)[slot
], Hash::digestLength
) == 0;
127 // Validate a slot against the contents of an open file. At most 'length' bytes
128 // will be read from the file.
130 bool CodeDirectory::validateSlot(FileDesc fd
, size_t length
, Slot slot
) const
133 hash(fd
, digest
, length
);
134 return memcmp(digest
, (*this)[slot
], Hash::digestLength
) == 0;
139 // Check whether a particular slot is present.
140 // Absense is indicated by either a zero hash, or by lying outside
143 bool CodeDirectory::slotIsPresent(Slot slot
) const
145 if (slot
>= -Slot(nSpecialSlots
) && slot
< Slot(nCodeSlots
)) {
146 const Hash::Byte
*digest
= (*this)[slot
];
147 for (unsigned n
= 0; n
< Hash::digestLength
; n
++)
149 return true; // non-zero digest => present
151 return false; // absent
156 // Hash the next limit bytes of a file and return the digest.
157 // If the file is shorter, hash as much as you can.
158 // Limit==0 means unlimited (to end of file).
159 // Return how many bytes were actually hashed.
160 // Throw on any errors.
162 size_t CodeDirectory::hash(FileDesc fd
, Hash::Byte
*digest
, size_t limit
)
164 IFDEBUG(size_t hpos
= fd
.position());
165 IFDEBUG(size_t hlimit
= limit
);
166 unsigned char buffer
[4096];
170 size_t size
= sizeof(buffer
);
171 if (limit
&& limit
< size
)
173 size_t got
= fd
.read(buffer
, size
);
178 if (limit
&& (limit
-= got
) == 0)
182 secdebug("cdhash", "fd %d %zd@0x%zx => %2x.%2x.%2x...",
183 fd
.fd(), hpos
, hlimit
, digest
[0], digest
[1], digest
[2]);
189 // Ditto, but hash a memory buffer instead.
191 size_t CodeDirectory::hash(const void *data
, size_t length
, Hash::Byte
*digest
)
201 // Canonical text form for user-settable code directory flags
203 const CodeDirectory::FlagItem
CodeDirectory::flagItems
[] = {
204 { "host", kSecCodeSignatureHost
, true },
205 { "adhoc", kSecCodeSignatureAdhoc
, false },
206 { "hard", kSecCodeSignatureForceHard
, true },
207 { "kill", kSecCodeSignatureForceKill
, true },
208 { "expires", kSecCodeSignatureForceExpiration
, true },
214 // Parse a canonical text description of code flags, in the form
216 // where each flag can be a prefix of a known flag name.
217 // Internally set flags are not accepted.
219 uint32_t CodeDirectory::textFlags(std::string text
)
222 for (string::size_type comma
= text
.find(','); ; text
= text
.substr(comma
+1), comma
= text
.find(',')) {
223 string word
= (comma
== string::npos
) ? text
: text
.substr(0, comma
);
224 const CodeDirectory::FlagItem
*item
;
225 for (item
= CodeDirectory::flagItems
; item
->name
; item
++)
226 if (item
->external
&& !strncmp(word
.c_str(), item
->name
, word
.size())) {
227 flags
|= item
->value
;
230 if (!item
) // not found
231 MacOSError::throwMe(errSecCSInvalidFlags
);
232 if (comma
== string::npos
) // last word