]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/reqdumper.cpp
Security-58286.260.20.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 default:
252 if (op & opGenericFalse) {
253 print(" false /* opcode %d */", op & ~opFlagMask);
254 break;
255 } else if (op & opGenericSkip) {
256 print(" /* opcode %d */", op & ~opFlagMask);
257 break;
258 } else {
259 print("OPCODE %d NOT UNDERSTOOD (ending print)", op);
260 return;
261 }
262 }
263 }
264
265 void Dumper::certSlot()
266 {
267 switch (int32_t slot = get<int32_t>()) {
268 case Requirement::anchorCert:
269 print(" root");
270 break;
271 case Requirement::leafCert:
272 print(" leaf");
273 break;
274 default:
275 print(" %d", slot);
276 break;
277 }
278 }
279
280 void Dumper::match()
281 {
282 switch (MatchOperation op = MatchOperation(get<uint32_t>())) {
283 case matchExists:
284 print(" /* exists */");
285 break;
286 case matchAbsent:
287 print(" absent ");
288 break;
289 case matchEqual:
290 print(" = "); data();
291 break;
292 case matchContains:
293 print(" ~ "); data();
294 break;
295 case matchBeginsWith:
296 print(" = "); data(); print("*");
297 break;
298 case matchEndsWith:
299 print(" = *"); data();
300 break;
301 case matchLessThan:
302 print(" < "); data();
303 break;
304 case matchGreaterEqual:
305 print(" >= "); data();
306 break;
307 case matchLessEqual:
308 print(" <= "); data();
309 break;
310 case matchGreaterThan:
311 print(" > "); data();
312 break;
313 case matchOn:
314 print(" = "); timestamp();
315 break;
316 case matchBefore:
317 print(" < "); timestamp();
318 break;
319 case matchAfter:
320 print(" > "); timestamp();
321 break;
322 case matchOnOrBefore:
323 print(" <= "); timestamp();
324 break;
325 case matchOnOrAfter:
326 print(" >= "); timestamp();
327 break;
328 default:
329 print("MATCH OPCODE %d NOT UNDERSTOOD", op);
330 break;
331 }
332 }
333
334 void Dumper::hashData()
335 {
336 print("H\"");
337 const unsigned char *data; size_t length;
338 getData(data, length);
339 printBytes(data, length);
340 print("\"");
341 }
342
343 void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false */)
344 {
345 const unsigned char *data; size_t length;
346 getData(data, length);
347 for (unsigned n = 0; n < length; n++)
348 if ((isalnum(data[n]) || (data[n] == '.' && dotOkay))) { // simple
349 if (n == 0 && isdigit(data[n])) // unquoted idents can't start with a digit
350 bestMode = isPrintable;
351 } else if (isgraph(data[n]) || isspace(data[n])) {
352 if (bestMode == isSimple)
353 bestMode = isPrintable;
354 } else {
355 bestMode = isBinary;
356 break; // pessimal
357 }
358
359 if (bestMode == isSimple) {
360 string s((const char *)data, length);
361 for (const char * const * k = keywords; *k; k++)
362 if (s == *k) {
363 bestMode = isPrintable; // reserved word; need quotes
364 break;
365 }
366 }
367
368 switch (bestMode) {
369 case isSimple:
370 print("%.*s", (int)length, data);
371 break;
372 case isPrintable:
373 print("\"");
374 for (unsigned n = 0; n < length; n++)
375 switch (data[n]) {
376 case '\\':
377 case '"':
378 print("\\%c", data[n]);
379 break;
380 default:
381 print("%c", data[n]);
382 break;
383 }
384 print("\"");
385 break;
386 default:
387 print("0x");
388 printBytes(data, length);
389 break;
390 }
391 }
392
393 void Dumper::timestamp()
394 {
395 CFAbsoluteTime at = static_cast<CFAbsoluteTime>(get<int64_t>());
396 CFRef<CFDateRef> date = CFDateCreate(NULL, at);
397
398 CFRef<CFStringRef> str = CFCopyDescription(date);
399
400 print("<%s>", cfString(str).c_str());
401 }
402
403 void Dumper::printBytes(const Byte *data, size_t length)
404 {
405 for (unsigned n = 0; n < length; n++)
406 print("%02.2x", data[n]);
407 }
408
409
410 } // CodeSigning
411 } // Security