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