]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_codesigning/lib/reqdumper.cpp
Security-57740.51.3.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 case Requirements::typeMagic:
125 return dump(static_cast<const Requirements *>(req), debug);
126 default:
127 return "invalid data type";
128 }
129 }
130
131
132 //
133 // Element dumpers. Output accumulates in internal buffer.
134 //
135 void Dumper::expr(SyntaxLevel level)
136 {
137 if (mDebug)
138 print("/*@0x%x*/", pc());
139 ExprOp op = ExprOp(get<uint32_t>());
140 switch (op & ~opFlagMask) {
141 case opFalse:
142 print("never");
143 break;
144 case opTrue:
145 print("always");
146 break;
147 case opIdent:
148 print("identifier ");
149 data();
150 break;
151 case opAppleAnchor:
152 print("anchor apple");
153 break;
154 case opAppleGenericAnchor:
155 print("anchor apple generic");
156 break;
157 case opAnchorHash:
158 print("certificate"); certSlot(); print(" = "); hashData();
159 break;
160 case opInfoKeyValue:
161 if (mDebug)
162 print("/*legacy*/");
163 print("info["); dotString(); print("] = "); data();
164 break;
165 case opAnd:
166 if (level < slAnd)
167 print("(");
168 expr(slAnd);
169 print(" and ");
170 expr(slAnd);
171 if (level < slAnd)
172 print(")");
173 break;
174 case opOr:
175 if (level < slOr)
176 print("(");
177 expr(slOr);
178 print(" or ");
179 expr(slOr);
180 if (level < slOr)
181 print(")");
182 break;
183 case opNot:
184 print("! ");
185 expr(slPrimary);
186 break;
187 case opCDHash:
188 print("cdhash ");
189 hashData();
190 break;
191 case opInfoKeyField:
192 print("info["); dotString(); print("]"); match();
193 break;
194 case opEntitlementField:
195 print("entitlement["); dotString(); print("]"); match();
196 break;
197 case opCertField:
198 print("certificate"); certSlot(); print("["); dotString(); print("]"); match();
199 break;
200 case opCertGeneric:
201 print("certificate"); certSlot(); print("[");
202 {
203 const unsigned char *data; size_t length;
204 getData(data, length);
205 print("field.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
206 }
207 print("]"); match();
208 break;
209 case opCertPolicy:
210 print("certificate"); certSlot(); print("[");
211 {
212 const unsigned char *data; size_t length;
213 getData(data, length);
214 print("policy.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
215 }
216 print("]"); match();
217 break;
218 case opTrustedCert:
219 print("certificate"); certSlot(); print("trusted");
220 break;
221 case opTrustedCerts:
222 print("anchor trusted");
223 break;
224 case opNamedAnchor:
225 print("anchor apple "); data();
226 break;
227 case opNamedCode:
228 print("("); data(); print(")");
229 break;
230 case opPlatform:
231 print("platform = %d", get<int32_t>());
232 break;
233 default:
234 if (op & opGenericFalse) {
235 print(" false /* opcode %d */", op & ~opFlagMask);
236 break;
237 } else if (op & opGenericSkip) {
238 print(" /* opcode %d */", op & ~opFlagMask);
239 break;
240 } else {
241 print("OPCODE %d NOT UNDERSTOOD (ending print)", op);
242 return;
243 }
244 }
245 }
246
247 void Dumper::certSlot()
248 {
249 switch (int32_t slot = get<int32_t>()) {
250 case Requirement::anchorCert:
251 print(" root");
252 break;
253 case Requirement::leafCert:
254 print(" leaf");
255 break;
256 default:
257 print(" %d", slot);
258 break;
259 }
260 }
261
262 void Dumper::match()
263 {
264 switch (MatchOperation op = MatchOperation(get<uint32_t>())) {
265 case matchExists:
266 print(" /* exists */");
267 break;
268 case matchEqual:
269 print(" = "); data();
270 break;
271 case matchContains:
272 print(" ~ "); data();
273 break;
274 case matchBeginsWith:
275 print(" = "); data(); print("*");
276 break;
277 case matchEndsWith:
278 print(" = *"); data();
279 break;
280 case matchLessThan:
281 print(" < "); data();
282 break;
283 case matchGreaterEqual:
284 print(" >= "); data();
285 break;
286 case matchLessEqual:
287 print(" <= "); data();
288 break;
289 case matchGreaterThan:
290 print(" > "); data();
291 break;
292 default:
293 print("MATCH OPCODE %d NOT UNDERSTOOD", op);
294 break;
295 }
296 }
297
298 void Dumper::hashData()
299 {
300 print("H\"");
301 const unsigned char *data; size_t length;
302 getData(data, length);
303 printBytes(data, length);
304 print("\"");
305 }
306
307 void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false */)
308 {
309 const unsigned char *data; size_t length;
310 getData(data, length);
311 for (unsigned n = 0; n < length; n++)
312 if ((isalnum(data[n]) || (data[n] == '.' && dotOkay))) { // simple
313 if (n == 0 && isdigit(data[n])) // unquoted idents can't start with a digit
314 bestMode = isPrintable;
315 } else if (isgraph(data[n]) || isspace(data[n])) {
316 if (bestMode == isSimple)
317 bestMode = isPrintable;
318 } else {
319 bestMode = isBinary;
320 break; // pessimal
321 }
322
323 if (bestMode == isSimple) {
324 string s((const char *)data, length);
325 for (const char * const * k = keywords; *k; k++)
326 if (s == *k) {
327 bestMode = isPrintable; // reserved word; need quotes
328 break;
329 }
330 }
331
332 switch (bestMode) {
333 case isSimple:
334 print("%.*s", length, data);
335 break;
336 case isPrintable:
337 print("\"");
338 for (unsigned n = 0; n < length; n++)
339 switch (data[n]) {
340 case '\\':
341 case '"':
342 print("\\%c", data[n]);
343 break;
344 default:
345 print("%c", data[n]);
346 break;
347 }
348 print("\"");
349 break;
350 default:
351 print("0x");
352 printBytes(data, length);
353 break;
354 }
355 }
356
357 void Dumper::printBytes(const Byte *data, size_t length)
358 {
359 for (unsigned n = 0; n < length; n++)
360 print("%02.2x", data[n]);
361 }
362
363
364 } // CodeSigning
365 } // Security