]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/reqdumper.cpp
Security-59754.60.13.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / reqdumper.cpp
1 /*
2 * Copyright (c) 2006-2007,2011-2013 Apple 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 // reqdumper - Requirement un-parsing (disassembly)
26 //
27 #include "reqdumper.h"
28 #if TARGET_OS_OSX
29 #include <security_cdsa_utilities/cssmdata.h> // OID encoder
30 #endif
31 #include <cstdarg>
32
33 namespace Security {
34 namespace CodeSigning {
35
36 using namespace UnixPlusPlus;
37
38
39 //
40 // Table of reserved words (keywords), generated by ANTLR
41 //
42 static const char * const keywords[] = {
43 #include "RequirementKeywords.h"
44 "",
45 NULL
46 };
47
48
49 //
50 // Printf to established output channel
51 //
52 void Dumper::print(const char *format, ...)
53 {
54 char buffer[256];
55 va_list args;
56 va_start(args, format);
57 vsnprintf(buffer, sizeof(buffer), format, args);
58 va_end(args);
59 mOutput += buffer;
60 }
61
62
63 //
64 // Dump the underlying Requirement program
65 //
66 void Dumper::dump()
67 {
68 this->expr();
69
70 // remove any initial space
71 if (mOutput[0] == ' ')
72 mOutput = mOutput.substr(1);
73 }
74
75
76 //
77 // Dump an entire Requirements set, using temporary Dumper objects.
78 //
79 // This detects single Requirement inputs and dumps them successfully (using
80 // single-requirement syntax). No indication of error is returned in this case.
81 //
82 string Dumper::dump(const Requirements *reqs, bool debug /* = false */)
83 {
84 if (!reqs) {
85 return "# no requirement(s)";
86 } else if (reqs->magic() == Requirement::typeMagic) { // single requirement
87 return dump((const Requirement *)reqs) + "\n";
88 } else {
89 string result;
90 for (unsigned n = 0; n < reqs->count(); n++) {
91 char prefix[200];
92 if (reqs->type(n) < kSecRequirementTypeCount)
93 snprintf(prefix, sizeof(prefix),
94 "%s => ", Requirement::typeNames[reqs->type(n)]);
95 else
96 snprintf(prefix, sizeof(prefix), "/*unknown type*/ %d => ", reqs->type(n));
97 Dumper dumper(reqs->blob<Requirement>(n), debug);
98 dumper.expr();
99 result += prefix + dumper.value() + "\n";
100 }
101 return result;
102 }
103 }
104
105 string Dumper::dump(const Requirement *req, bool debug /* = false */)
106 {
107 Dumper dumper(req, debug);
108 try {
109 dumper.dump();
110 return dumper;
111 } catch (const CommonError &err) {
112 if (debug) {
113 char errstr[80];
114 snprintf(errstr, sizeof(errstr), " !! error %ld !!", (unsigned long)err.osStatus());
115 return dumper.value() + errstr;
116 }
117 throw;
118 }
119 }
120
121 string Dumper::dump(const BlobCore *req, bool debug /* = false */)
122 {
123 switch (req->magic()) {
124 case Requirement::typeMagic:
125 return dump(static_cast<const Requirement *>(req), debug);
126 case Requirements::typeMagic:
127 return dump(static_cast<const Requirements *>(req), debug);
128 default:
129 return "invalid data type";
130 }
131 }
132
133
134 //
135 // Element dumpers. Output accumulates in internal buffer.
136 //
137 void Dumper::expr(SyntaxLevel level)
138 {
139 if (mDebug)
140 print("/*@0x%x*/", pc());
141 ExprOp op = ExprOp(get<uint32_t>());
142 switch (op & ~opFlagMask) {
143 case opFalse:
144 print("never");
145 break;
146 case opTrue:
147 print("always");
148 break;
149 case opIdent:
150 print("identifier ");
151 data();
152 break;
153 case opAppleAnchor:
154 print("anchor apple");
155 break;
156 case opAppleGenericAnchor:
157 print("anchor apple generic");
158 break;
159 case opAnchorHash:
160 print("certificate"); certSlot(); print(" = "); hashData();
161 break;
162 case opInfoKeyValue:
163 if (mDebug)
164 print("/*legacy*/");
165 print("info["); dotString(); print("] = "); data();
166 break;
167 case opAnd:
168 if (level < slAnd)
169 print("(");
170 expr(slAnd);
171 print(" and ");
172 expr(slAnd);
173 if (level < slAnd)
174 print(")");
175 break;
176 case opOr:
177 if (level < slOr)
178 print("(");
179 expr(slOr);
180 print(" or ");
181 expr(slOr);
182 if (level < slOr)
183 print(")");
184 break;
185 case opNot:
186 print("! ");
187 expr(slPrimary);
188 break;
189 case opCDHash:
190 print("cdhash ");
191 hashData();
192 break;
193 case opInfoKeyField:
194 print("info["); dotString(); print("]"); match();
195 break;
196 case opEntitlementField:
197 print("entitlement["); dotString(); print("]"); match();
198 break;
199 case opCertField:
200 print("certificate"); certSlot(); print("["); dotString(); print("]"); match();
201 break;
202 case opCertFieldDate:
203 print("certificate"); certSlot(); print("[");
204 #if TARGET_OS_OSX
205 {
206 const unsigned char *data; size_t length;
207 getData(data, length);
208 print("timestamp.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
209 }
210 #endif
211 case opCertGeneric:
212 print("certificate"); certSlot(); print("[");
213 #if TARGET_OS_OSX
214 {
215 const unsigned char *data; size_t length;
216 getData(data, length);
217 print("field.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
218 }
219 #endif
220 print("]"); match();
221 break;
222 case opCertPolicy:
223 print("certificate"); certSlot(); print("[");
224 #if TARGET_OS_OSX
225 {
226 const unsigned char *data; size_t length;
227 getData(data, length);
228 print("policy.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
229 }
230 #endif
231 print("]"); match();
232 break;
233 case opTrustedCert:
234 print("certificate"); certSlot(); print("trusted");
235 break;
236 case opTrustedCerts:
237 print("anchor trusted");
238 break;
239 case opNamedAnchor:
240 print("anchor apple "); data();
241 break;
242 case opNamedCode:
243 print("("); data(); print(")");
244 break;
245 case opPlatform:
246 print("platform = %d", get<int32_t>());
247 break;
248 case opNotarized:
249 print("notarized");
250 break;
251 case opLegacyDevID:
252 print("legacy");
253 break;
254 default:
255 if (op & opGenericFalse) {
256 print(" false /* opcode %d */", op & ~opFlagMask);
257 break;
258 } else if (op & opGenericSkip) {
259 print(" /* opcode %d */", op & ~opFlagMask);
260 break;
261 } else {
262 print("OPCODE %d NOT UNDERSTOOD (ending print)", op);
263 return;
264 }
265 }
266 }
267
268 void Dumper::certSlot()
269 {
270 switch (int32_t slot = get<int32_t>()) {
271 case Requirement::anchorCert:
272 print(" root");
273 break;
274 case Requirement::leafCert:
275 print(" leaf");
276 break;
277 default:
278 print(" %d", slot);
279 break;
280 }
281 }
282
283 void Dumper::match()
284 {
285 switch (MatchOperation op = MatchOperation(get<uint32_t>())) {
286 case matchExists:
287 print(" /* exists */");
288 break;
289 case matchAbsent:
290 print(" absent ");
291 break;
292 case matchEqual:
293 print(" = "); data();
294 break;
295 case matchContains:
296 print(" ~ "); data();
297 break;
298 case matchBeginsWith:
299 print(" = "); data(); print("*");
300 break;
301 case matchEndsWith:
302 print(" = *"); data();
303 break;
304 case matchLessThan:
305 print(" < "); data();
306 break;
307 case matchGreaterEqual:
308 print(" >= "); data();
309 break;
310 case matchLessEqual:
311 print(" <= "); data();
312 break;
313 case matchGreaterThan:
314 print(" > "); data();
315 break;
316 case matchOn:
317 print(" = "); timestamp();
318 break;
319 case matchBefore:
320 print(" < "); timestamp();
321 break;
322 case matchAfter:
323 print(" > "); timestamp();
324 break;
325 case matchOnOrBefore:
326 print(" <= "); timestamp();
327 break;
328 case matchOnOrAfter:
329 print(" >= "); timestamp();
330 break;
331 default:
332 print("MATCH OPCODE %d NOT UNDERSTOOD", op);
333 break;
334 }
335 }
336
337 void Dumper::hashData()
338 {
339 print("H\"");
340 const unsigned char *data; size_t length;
341 getData(data, length);
342 printBytes(data, length);
343 print("\"");
344 }
345
346 void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false */)
347 {
348 const unsigned char *data; size_t length;
349 getData(data, length);
350 for (unsigned n = 0; n < length; n++)
351 if ((isalnum(data[n]) || (data[n] == '.' && dotOkay))) { // simple
352 if (n == 0 && isdigit(data[n])) // unquoted idents can't start with a digit
353 bestMode = isPrintable;
354 } else if (isgraph(data[n]) || isspace(data[n])) {
355 if (bestMode == isSimple)
356 bestMode = isPrintable;
357 } else {
358 bestMode = isBinary;
359 break; // pessimal
360 }
361
362 if (bestMode == isSimple) {
363 string s((const char *)data, length);
364 for (const char * const * k = keywords; *k; k++)
365 if (s == *k) {
366 bestMode = isPrintable; // reserved word; need quotes
367 break;
368 }
369 }
370
371 switch (bestMode) {
372 case isSimple:
373 print("%.*s", (int)length, data);
374 break;
375 case isPrintable:
376 print("\"");
377 for (unsigned n = 0; n < length; n++)
378 switch (data[n]) {
379 case '\\':
380 case '"':
381 print("\\%c", data[n]);
382 break;
383 default:
384 print("%c", data[n]);
385 break;
386 }
387 print("\"");
388 break;
389 default:
390 print("0x");
391 printBytes(data, length);
392 break;
393 }
394 }
395
396 void Dumper::timestamp()
397 {
398 CFAbsoluteTime at = static_cast<CFAbsoluteTime>(get<int64_t>());
399 CFRef<CFDateRef> date = CFDateCreate(NULL, at);
400
401 CFRef<CFStringRef> str = CFCopyDescription(date);
402
403 print("<%s>", cfString(str).c_str());
404 }
405
406 void Dumper::printBytes(const Byte *data, size_t length)
407 {
408 for (unsigned n = 0; n < length; n++)
409 print("%02.2x", data[n]);
410 }
411
412
413 } // CodeSigning
414 } // Security