]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/reqdumper.cpp
Security-58286.51.6.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 opCertGeneric:
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("field.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
209 }
210 #endif
211 print("]"); match();
212 break;
213 case opCertPolicy:
214 print("certificate"); certSlot(); print("[");
215 #if TARGET_OS_OSX
216 {
217 const unsigned char *data; size_t length;
218 getData(data, length);
219 print("policy.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
220 }
221 #endif
222 print("]"); match();
223 break;
224 case opTrustedCert:
225 print("certificate"); certSlot(); print("trusted");
226 break;
227 case opTrustedCerts:
228 print("anchor trusted");
229 break;
230 case opNamedAnchor:
231 print("anchor apple "); data();
232 break;
233 case opNamedCode:
234 print("("); data(); print(")");
235 break;
236 case opPlatform:
237 print("platform = %d", get<int32_t>());
238 break;
239 default:
240 if (op & opGenericFalse) {
241 print(" false /* opcode %d */", op & ~opFlagMask);
242 break;
243 } else if (op & opGenericSkip) {
244 print(" /* opcode %d */", op & ~opFlagMask);
245 break;
246 } else {
247 print("OPCODE %d NOT UNDERSTOOD (ending print)", op);
248 return;
249 }
250 }
251 }
252
253 void Dumper::certSlot()
254 {
255 switch (int32_t slot = get<int32_t>()) {
256 case Requirement::anchorCert:
257 print(" root");
258 break;
259 case Requirement::leafCert:
260 print(" leaf");
261 break;
262 default:
263 print(" %d", slot);
264 break;
265 }
266 }
267
268 void Dumper::match()
269 {
270 switch (MatchOperation op = MatchOperation(get<uint32_t>())) {
271 case matchExists:
272 print(" /* exists */");
273 break;
274 case matchEqual:
275 print(" = "); data();
276 break;
277 case matchContains:
278 print(" ~ "); data();
279 break;
280 case matchBeginsWith:
281 print(" = "); data(); print("*");
282 break;
283 case matchEndsWith:
284 print(" = *"); data();
285 break;
286 case matchLessThan:
287 print(" < "); data();
288 break;
289 case matchGreaterEqual:
290 print(" >= "); data();
291 break;
292 case matchLessEqual:
293 print(" <= "); data();
294 break;
295 case matchGreaterThan:
296 print(" > "); data();
297 break;
298 default:
299 print("MATCH OPCODE %d NOT UNDERSTOOD", op);
300 break;
301 }
302 }
303
304 void Dumper::hashData()
305 {
306 print("H\"");
307 const unsigned char *data; size_t length;
308 getData(data, length);
309 printBytes(data, length);
310 print("\"");
311 }
312
313 void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false */)
314 {
315 const unsigned char *data; size_t length;
316 getData(data, length);
317 for (unsigned n = 0; n < length; n++)
318 if ((isalnum(data[n]) || (data[n] == '.' && dotOkay))) { // simple
319 if (n == 0 && isdigit(data[n])) // unquoted idents can't start with a digit
320 bestMode = isPrintable;
321 } else if (isgraph(data[n]) || isspace(data[n])) {
322 if (bestMode == isSimple)
323 bestMode = isPrintable;
324 } else {
325 bestMode = isBinary;
326 break; // pessimal
327 }
328
329 if (bestMode == isSimple) {
330 string s((const char *)data, length);
331 for (const char * const * k = keywords; *k; k++)
332 if (s == *k) {
333 bestMode = isPrintable; // reserved word; need quotes
334 break;
335 }
336 }
337
338 switch (bestMode) {
339 case isSimple:
340 print("%.*s", (int)length, data);
341 break;
342 case isPrintable:
343 print("\"");
344 for (unsigned n = 0; n < length; n++)
345 switch (data[n]) {
346 case '\\':
347 case '"':
348 print("\\%c", data[n]);
349 break;
350 default:
351 print("%c", data[n]);
352 break;
353 }
354 print("\"");
355 break;
356 default:
357 print("0x");
358 printBytes(data, length);
359 break;
360 }
361 }
362
363 void Dumper::printBytes(const Byte *data, size_t length)
364 {
365 for (unsigned n = 0; n < length; n++)
366 print("%02.2x", data[n]);
367 }
368
369
370 } // CodeSigning
371 } // Security