]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/codedirectory.cpp
f9ad55d9e0747ceaeed719f0cbf996b212cae5b1
[apple/libsecurity_codesigning.git] / lib / codedirectory.cpp
1 /*
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 //
25 // codedirectory - format and operations for code signing "code directory" structures
26 //
27 #include "codedirectory.h"
28 #include "CSCommon.h"
29
30 using namespace UnixPlusPlus;
31
32
33 namespace Security {
34 namespace CodeSigning {
35
36
37 //
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.
42 //
43 const char *CodeDirectory::canonicalSlotName(SpecialSlot slot)
44 {
45 switch (slot) {
46 case cdRequirementsSlot:
47 return kSecCS_REQUIREMENTSFILE;
48 case cdResourceDirSlot:
49 return kSecCS_RESOURCEDIRFILE;
50 case cdCodeDirectorySlot:
51 return kSecCS_CODEDIRECTORYFILE;
52 case cdSignatureSlot:
53 return kSecCS_SIGNATUREFILE;
54 case cdApplicationSlot:
55 return kSecCS_APPLICATIONFILE;
56 default:
57 return NULL;
58 }
59 }
60
61
62 //
63 // Canonical attributes of SpecialSlots.
64 //
65 unsigned CodeDirectory::slotAttributes(SpecialSlot slot)
66 {
67 switch (slot) {
68 case cdRequirementsSlot:
69 return cdComponentIsBlob; // global
70 case cdCodeDirectorySlot:
71 return cdComponentPerArchitecture | cdComponentIsBlob;
72 case cdSignatureSlot:
73 return cdComponentPerArchitecture; // raw
74 default:
75 return 0; // global, raw
76 }
77 }
78
79
80 //
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.
84 //
85 #if !defined(NDEBUG)
86 const char * const CodeDirectory::debugSlotName[] = {
87 "codedirectory",
88 "info",
89 "requirements",
90 "resources",
91 "application"
92 };
93 #endif //NDEBUG
94
95
96 //
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).
101 //
102 void CodeDirectory::checkVersion() const
103 {
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);
111 }
112
113
114 //
115 // Validate a slot against data in memory.
116 //
117 bool CodeDirectory::validateSlot(const void *data, size_t length, Slot slot) const
118 {
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;
123 }
124
125
126 //
127 // Validate a slot against the contents of an open file. At most 'length' bytes
128 // will be read from the file.
129 //
130 bool CodeDirectory::validateSlot(FileDesc fd, size_t length, Slot slot) const
131 {
132 Hash::Digest digest;
133 hash(fd, digest, length);
134 return memcmp(digest, (*this)[slot], Hash::digestLength) == 0;
135 }
136
137
138 //
139 // Check whether a particular slot is present.
140 // Absense is indicated by either a zero hash, or by lying outside
141 // the slot range.
142 //
143 bool CodeDirectory::slotIsPresent(Slot slot) const
144 {
145 if (slot >= -Slot(nSpecialSlots) && slot < Slot(nCodeSlots)) {
146 const Hash::Byte *digest = (*this)[slot];
147 for (unsigned n = 0; n < Hash::digestLength; n++)
148 if (digest[n])
149 return true; // non-zero digest => present
150 }
151 return false; // absent
152 }
153
154
155 //
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.
161 //
162 size_t CodeDirectory::hash(FileDesc fd, Hash::Byte *digest, size_t limit)
163 {
164 IFDEBUG(size_t hpos = fd.position());
165 IFDEBUG(size_t hlimit = limit);
166 unsigned char buffer[4096];
167 Hash hash;
168 size_t total = 0;
169 for (;;) {
170 size_t size = sizeof(buffer);
171 if (limit && limit < size)
172 size = limit;
173 size_t got = fd.read(buffer, size);
174 total += got;
175 if (fd.atEnd())
176 break;
177 hash(buffer, got);
178 if (limit && (limit -= got) == 0)
179 break;
180 }
181 hash.finish(digest);
182 secdebug("cdhash", "fd %d %zd@0x%zx => %2x.%2x.%2x...",
183 fd.fd(), hpos, hlimit, digest[0], digest[1], digest[2]);
184 return total;
185 }
186
187
188 //
189 // Ditto, but hash a memory buffer instead.
190 //
191 size_t CodeDirectory::hash(const void *data, size_t length, Hash::Byte *digest)
192 {
193 Hash hash;
194 hash(data, length);
195 hash.finish(digest);
196 return length;
197 }
198
199
200 //
201 // Canonical text form for user-settable code directory flags
202 //
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 },
209 { NULL }
210 };
211
212
213 //
214 // Parse a canonical text description of code flags, in the form
215 // flag,...,flag
216 // where each flag can be a prefix of a known flag name.
217 // Internally set flags are not accepted.
218 //
219 uint32_t CodeDirectory::textFlags(std::string text)
220 {
221 uint32_t flags = 0;
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;
228 break;
229 }
230 if (!item) // not found
231 MacOSError::throwMe(errSecCSInvalidFlags);
232 if (comma == string::npos) // last word
233 break;
234 }
235 return flags;
236 }
237
238
239 } // CodeSigning
240 } // Security