]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/reqdumper.cpp
8fbd4446c424ad7d8b1bbe7a9345cc34848a3477
[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 // Printf to established output channel
39 //
40 void Dumper::print(const char *format, ...)
41 {
42 char buffer[256];
43 va_list args;
44 va_start(args, format);
45 vsnprintf(buffer, sizeof(buffer), format, args);
46 va_end(args);
47 mOutput += buffer;
48 }
49
50
51 //
52 // Dump the underlying Requirement program
53 //
54 void Dumper::dump()
55 {
56 this->expr();
57
58 // remove any initial space
59 if (mOutput[0] == ' ')
60 mOutput = mOutput.substr(1);
61 }
62
63
64 //
65 // Dump an entire Requirements set, using temporary Dumper objects.
66 //
67 // This detects single Requirement inputs and dumps them successfully (using
68 // single-requirement syntax). No indication of error is returned in this case.
69 //
70 string Dumper::dump(const Requirements *reqs, bool debug /* = false */)
71 {
72 if (!reqs) {
73 return "# no requirement(s)";
74 } else if (reqs->magic() == Requirement::typeMagic) { // single requirement
75 return dump((const Requirement *)reqs) + "\n";
76 } else {
77 string result;
78 for (unsigned n = 0; n < reqs->count(); n++) {
79 char prefix[200];
80 if (reqs->type(n) < kSecRequirementTypeCount)
81 snprintf(prefix, sizeof(prefix),
82 "%s => ", Requirement::typeNames[reqs->type(n)]);
83 else
84 snprintf(prefix, sizeof(prefix), "/*unknown type*/ %d => ", reqs->type(n));
85 Dumper dumper(reqs->blob<Requirement>(n), debug);
86 dumper.expr();
87 result += prefix + dumper.value() + "\n";
88 }
89 return result;
90 }
91 }
92
93 string Dumper::dump(const Requirement *req, bool debug /* = false */)
94 {
95 Dumper dumper(req, debug);
96 try {
97 dumper.dump();
98 return dumper;
99 } catch (const CommonError &err) {
100 if (debug) {
101 char errstr[80];
102 snprintf(errstr, sizeof(errstr), " !! error %ld !!", err.osStatus());
103 return dumper.value() + errstr;
104 }
105 throw;
106 }
107 }
108
109 string Dumper::dump(const BlobCore *req, bool debug /* = false */)
110 {
111 switch (req->magic()) {
112 case Requirement::typeMagic:
113 return dump(static_cast<const Requirement *>(req), debug);
114 break;
115 case Requirements::typeMagic:
116 return dump(static_cast<const Requirements *>(req), debug);
117 break;
118 default:
119 return "invalid data type";
120 }
121 }
122
123
124 //
125 // Element dumpers. Output accumulates in internal buffer.
126 //
127 void Dumper::expr(SyntaxLevel level)
128 {
129 if (mDebug)
130 print("/*@0x%x*/", pc());
131 ExprOp op = ExprOp(get<uint32_t>());
132 switch (op & ~opFlagMask) {
133 case opFalse:
134 print("never");
135 break;
136 case opTrue:
137 print("always");
138 break;
139 case opIdent:
140 print("identifier ");
141 data();
142 break;
143 case opAppleAnchor:
144 print("anchor apple");
145 break;
146 case opAppleGenericAnchor:
147 print("anchor apple generic");
148 break;
149 case opAnchorHash:
150 print("anchor"); certSlot(); print(" = "); hashData();
151 break;
152 case opInfoKeyValue:
153 if (mDebug)
154 print("/*legacy*/");
155 print("info["); dotString(); print("] = "); data();
156 break;
157 case opAnd:
158 if (level < slAnd)
159 print("(");
160 expr(slAnd);
161 print(" and ");
162 expr(slAnd);
163 if (level < slAnd)
164 print(")");
165 break;
166 case opOr:
167 if (level < slOr)
168 print("(");
169 expr(slOr);
170 print(" or ");
171 expr(slOr);
172 if (level < slOr)
173 print(")");
174 break;
175 case opNot:
176 print("! ");
177 expr(slPrimary);
178 break;
179 case opCDHash:
180 print(" cdhash ");
181 hashData();
182 break;
183 case opInfoKeyField:
184 print("info["); dotString(); print("]"); match();
185 break;
186 case opEntitlementField:
187 print("entitlement["); dotString(); print("]"); match();
188 break;
189 case opCertField:
190 print("certificate"); certSlot(); print("["); dotString(); print("]"); match();
191 break;
192 case opCertGeneric:
193 print("certificate"); certSlot(); print("[");
194 {
195 const unsigned char *data; size_t length;
196 getData(data, length);
197 print("field.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
198 }
199 print("]"); match();
200 break;
201 case opTrustedCert:
202 print("certificate"); certSlot(); print("trusted");
203 break;
204 case opTrustedCerts:
205 print("anchor trusted");
206 break;
207 default:
208 if (op & opGenericFalse) {
209 print(" false /* opcode %d */", op & ~opFlagMask);
210 break;
211 } else if (op & opGenericSkip) {
212 print(" /* opcode %d */", op & ~opFlagMask);
213 break;
214 } else {
215 print("OPCODE %d NOT UNDERSTOOD (ending print)", op);
216 return;
217 }
218 }
219 }
220
221 void Dumper::certSlot()
222 {
223 switch (uint32_t slot = get<uint32_t>()) {
224 case Requirement::anchorCert:
225 print(" root");
226 break;
227 case Requirement::leafCert:
228 print(" leaf");
229 break;
230 default:
231 print(" %d", slot);
232 break;
233 }
234 }
235
236 void Dumper::match()
237 {
238 switch (MatchOperation op = MatchOperation(get<uint32_t>())) {
239 case matchExists:
240 print(" exists");
241 break;
242 case matchEqual:
243 print(" = "); data();
244 break;
245 case matchContains:
246 print(" ~ "); data();
247 break;
248 case matchBeginsWith:
249 print(" = "); data(); print("*");
250 break;
251 case matchEndsWith:
252 print(" = *"); data();
253 break;
254 case matchLessThan:
255 print(" < "); data();
256 break;
257 case matchGreaterEqual:
258 print(" >= "); data();
259 break;
260 case matchLessEqual:
261 print(" <= "); data();
262 break;
263 case matchGreaterThan:
264 print(" > "); data();
265 break;
266 default:
267 print("MATCH OPCODE %d NOT UNDERSTOOD", op);
268 break;
269 }
270 }
271
272 void Dumper::hashData()
273 {
274 print("H\"");
275 const unsigned char *data; size_t length;
276 getData(data, length);
277 printBytes(data, length);
278 print("\"");
279 }
280
281 void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false */)
282 {
283 const unsigned char *data; size_t length;
284 getData(data, length);
285 for (unsigned n = 0; n < length; n++)
286 if ((isalnum(data[n]) || (data[n] == '.' && dotOkay))) { // simple
287 if (n == 0 && isdigit(data[n])) // unquoted idents can't start with a digit
288 bestMode = isPrintable;
289 } else if (isgraph(data[n]) || isspace(data[n])) {
290 if (bestMode == isSimple)
291 bestMode = isPrintable;
292 } else {
293 bestMode = isBinary;
294 break; // pessimal
295 }
296
297 if (length == 0 && bestMode == isSimple)
298 bestMode = isPrintable; // force quotes for empty string
299
300 switch (bestMode) {
301 case isSimple:
302 print("%.*s", length, data);
303 break;
304 case isPrintable:
305 print("\"%.*s\"", length, data);
306 break;
307 default:
308 print("0x");
309 printBytes(data, length);
310 break;
311 }
312 }
313
314 void Dumper::printBytes(const Byte *data, size_t length)
315 {
316 for (unsigned n = 0; n < length; n++)
317 print("%02.2x", data[n]);
318 }
319
320
321 } // CodeSigning
322 } // Security