]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/reqdumper.cpp
Security-57337.20.44.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 #include <security_cdsa_utilities/cssmdata.h> // OID encoder
29 #include <cstdarg>
30
31 namespace Security {
32 namespace CodeSigning {
33
34 using namespace UnixPlusPlus;
35
36
37 //
38 // Table of reserved words (keywords), generated by ANTLR
39 //
40 static const char * const keywords[] = {
41 #include "RequirementKeywords.h"
42 "",
43 NULL
44 };
45
46
47 //
48 // Printf to established output channel
49 //
50 void Dumper::print(const char *format, ...)
51 {
52 char buffer[256];
53 va_list args;
54 va_start(args, format);
55 vsnprintf(buffer, sizeof(buffer), format, args);
56 va_end(args);
57 mOutput += buffer;
58 }
59
60
61 //
62 // Dump the underlying Requirement program
63 //
64 void Dumper::dump()
65 {
66 this->expr();
67
68 // remove any initial space
69 if (mOutput[0] == ' ')
70 mOutput = mOutput.substr(1);
71 }
72
73
74 //
75 // Dump an entire Requirements set, using temporary Dumper objects.
76 //
77 // This detects single Requirement inputs and dumps them successfully (using
78 // single-requirement syntax). No indication of error is returned in this case.
79 //
80 string Dumper::dump(const Requirements *reqs, bool debug /* = false */)
81 {
82 if (!reqs) {
83 return "# no requirement(s)";
84 } else if (reqs->magic() == Requirement::typeMagic) { // single requirement
85 return dump((const Requirement *)reqs) + "\n";
86 } else {
87 string result;
88 for (unsigned n = 0; n < reqs->count(); n++) {
89 char prefix[200];
90 if (reqs->type(n) < kSecRequirementTypeCount)
91 snprintf(prefix, sizeof(prefix),
92 "%s => ", Requirement::typeNames[reqs->type(n)]);
93 else
94 snprintf(prefix, sizeof(prefix), "/*unknown type*/ %d => ", reqs->type(n));
95 Dumper dumper(reqs->blob<Requirement>(n), debug);
96 dumper.expr();
97 result += prefix + dumper.value() + "\n";
98 }
99 return result;
100 }
101 }
102
103 string Dumper::dump(const Requirement *req, bool debug /* = false */)
104 {
105 Dumper dumper(req, debug);
106 try {
107 dumper.dump();
108 return dumper;
109 } catch (const CommonError &err) {
110 if (debug) {
111 char errstr[80];
112 snprintf(errstr, sizeof(errstr), " !! error %ld !!", (unsigned long)err.osStatus());
113 return dumper.value() + errstr;
114 }
115 throw;
116 }
117 }
118
119 string Dumper::dump(const BlobCore *req, bool debug /* = false */)
120 {
121 switch (req->magic()) {
122 case Requirement::typeMagic:
123 return dump(static_cast<const Requirement *>(req), debug);
124 break;
125 case Requirements::typeMagic:
126 return dump(static_cast<const Requirements *>(req), debug);
127 break;
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 {
205 const unsigned char *data; size_t length;
206 getData(data, length);
207 print("field.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
208 }
209 print("]"); match();
210 break;
211 case opCertPolicy:
212 print("certificate"); certSlot(); print("[");
213 {
214 const unsigned char *data; size_t length;
215 getData(data, length);
216 print("policy.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
217 }
218 print("]"); match();
219 break;
220 case opTrustedCert:
221 print("certificate"); certSlot(); print("trusted");
222 break;
223 case opTrustedCerts:
224 print("anchor trusted");
225 break;
226 case opNamedAnchor:
227 print("anchor apple "); data();
228 break;
229 case opNamedCode:
230 print("("); data(); print(")");
231 break;
232 case opPlatform:
233 print("platform = %d", get<int32_t>());
234 break;
235 default:
236 if (op & opGenericFalse) {
237 print(" false /* opcode %d */", op & ~opFlagMask);
238 break;
239 } else if (op & opGenericSkip) {
240 print(" /* opcode %d */", op & ~opFlagMask);
241 break;
242 } else {
243 print("OPCODE %d NOT UNDERSTOOD (ending print)", op);
244 return;
245 }
246 }
247 }
248
249 void Dumper::certSlot()
250 {
251 switch (int32_t slot = get<int32_t>()) {
252 case Requirement::anchorCert:
253 print(" root");
254 break;
255 case Requirement::leafCert:
256 print(" leaf");
257 break;
258 default:
259 print(" %d", slot);
260 break;
261 }
262 }
263
264 void Dumper::match()
265 {
266 switch (MatchOperation op = MatchOperation(get<uint32_t>())) {
267 case matchExists:
268 print(" /* exists */");
269 break;
270 case matchEqual:
271 print(" = "); data();
272 break;
273 case matchContains:
274 print(" ~ "); data();
275 break;
276 case matchBeginsWith:
277 print(" = "); data(); print("*");
278 break;
279 case matchEndsWith:
280 print(" = *"); data();
281 break;
282 case matchLessThan:
283 print(" < "); data();
284 break;
285 case matchGreaterEqual:
286 print(" >= "); data();
287 break;
288 case matchLessEqual:
289 print(" <= "); data();
290 break;
291 case matchGreaterThan:
292 print(" > "); data();
293 break;
294 default:
295 print("MATCH OPCODE %d NOT UNDERSTOOD", op);
296 break;
297 }
298 }
299
300 void Dumper::hashData()
301 {
302 print("H\"");
303 const unsigned char *data; size_t length;
304 getData(data, length);
305 printBytes(data, length);
306 print("\"");
307 }
308
309 void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false */)
310 {
311 const unsigned char *data; size_t length;
312 getData(data, length);
313 for (unsigned n = 0; n < length; n++)
314 if ((isalnum(data[n]) || (data[n] == '.' && dotOkay))) { // simple
315 if (n == 0 && isdigit(data[n])) // unquoted idents can't start with a digit
316 bestMode = isPrintable;
317 } else if (isgraph(data[n]) || isspace(data[n])) {
318 if (bestMode == isSimple)
319 bestMode = isPrintable;
320 } else {
321 bestMode = isBinary;
322 break; // pessimal
323 }
324
325 if (bestMode == isSimple) {
326 string s((const char *)data, length);
327 for (const char * const * k = keywords; *k; k++)
328 if (s == *k) {
329 bestMode = isPrintable; // reserved word; need quotes
330 break;
331 }
332 }
333
334 switch (bestMode) {
335 case isSimple:
336 print("%.*s", length, data);
337 break;
338 case isPrintable:
339 print("\"");
340 for (unsigned n = 0; n < length; n++)
341 switch (data[n]) {
342 case '\\':
343 case '"':
344 print("\\%c", data[n]);
345 break;
346 default:
347 print("%c", data[n]);
348 break;
349 }
350 print("\"");
351 break;
352 default:
353 print("0x");
354 printBytes(data, length);
355 break;
356 }
357 }
358
359 void Dumper::printBytes(const Byte *data, size_t length)
360 {
361 for (unsigned n = 0; n < length; n++)
362 print("%02.2x", data[n]);
363 }
364
365
366 } // CodeSigning
367 } // Security