]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_codesigning/lib/reqdumper.cpp
Security-58286.240.4.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / reqdumper.cpp
CommitLineData
b1ab9ed8 1/*
d8f41ccd 2 * Copyright (c) 2006-2007,2011-2013 Apple Inc. All Rights Reserved.
b1ab9ed8
A
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"
866f8763 28#if TARGET_OS_OSX
b1ab9ed8 29#include <security_cdsa_utilities/cssmdata.h> // OID encoder
866f8763 30#endif
b1ab9ed8
A
31#include <cstdarg>
32
33namespace Security {
34namespace CodeSigning {
35
36using namespace UnixPlusPlus;
37
38
39//
40// Table of reserved words (keywords), generated by ANTLR
41//
42static const char * const keywords[] = {
43#include "RequirementKeywords.h"
44 "",
45 NULL
46};
47
48
49//
50// Printf to established output channel
51//
52void 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//
66void 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//
82string 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
105string 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
121string 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);
b1ab9ed8
A
126 case Requirements::typeMagic:
127 return dump(static_cast<const Requirements *>(req), debug);
b1ab9ed8
A
128 default:
129 return "invalid data type";
130 }
131}
132
133
134//
135// Element dumpers. Output accumulates in internal buffer.
136//
137void 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:
427c49bc 190 print("cdhash ");
b1ab9ed8
A
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("[");
866f8763 204#if TARGET_OS_OSX
b1ab9ed8
A
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 }
866f8763 210#endif
b1ab9ed8
A
211 print("]"); match();
212 break;
213 case opCertPolicy:
214 print("certificate"); certSlot(); print("[");
866f8763 215#if TARGET_OS_OSX
b1ab9ed8
A
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 }
866f8763 221#endif
b1ab9ed8
A
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;
5c19dc3a
A
236 case opPlatform:
237 print("platform = %d", get<int32_t>());
238 break;
79b9da22
A
239 case opNotarized:
240 print("notarized");
241 break;
b1ab9ed8
A
242 default:
243 if (op & opGenericFalse) {
244 print(" false /* opcode %d */", op & ~opFlagMask);
245 break;
246 } else if (op & opGenericSkip) {
247 print(" /* opcode %d */", op & ~opFlagMask);
248 break;
249 } else {
250 print("OPCODE %d NOT UNDERSTOOD (ending print)", op);
251 return;
252 }
253 }
254}
255
256void Dumper::certSlot()
257{
258 switch (int32_t slot = get<int32_t>()) {
259 case Requirement::anchorCert:
260 print(" root");
261 break;
262 case Requirement::leafCert:
263 print(" leaf");
264 break;
265 default:
266 print(" %d", slot);
267 break;
268 }
269}
270
271void Dumper::match()
272{
273 switch (MatchOperation op = MatchOperation(get<uint32_t>())) {
274 case matchExists:
275 print(" /* exists */");
276 break;
277 case matchEqual:
278 print(" = "); data();
279 break;
280 case matchContains:
281 print(" ~ "); data();
282 break;
283 case matchBeginsWith:
284 print(" = "); data(); print("*");
285 break;
286 case matchEndsWith:
287 print(" = *"); data();
288 break;
289 case matchLessThan:
290 print(" < "); data();
291 break;
292 case matchGreaterEqual:
293 print(" >= "); data();
294 break;
295 case matchLessEqual:
296 print(" <= "); data();
297 break;
298 case matchGreaterThan:
299 print(" > "); data();
300 break;
301 default:
302 print("MATCH OPCODE %d NOT UNDERSTOOD", op);
303 break;
304 }
305}
306
307void Dumper::hashData()
308{
309 print("H\"");
310 const unsigned char *data; size_t length;
311 getData(data, length);
312 printBytes(data, length);
313 print("\"");
314}
315
316void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false */)
317{
318 const unsigned char *data; size_t length;
319 getData(data, length);
320 for (unsigned n = 0; n < length; n++)
321 if ((isalnum(data[n]) || (data[n] == '.' && dotOkay))) { // simple
322 if (n == 0 && isdigit(data[n])) // unquoted idents can't start with a digit
323 bestMode = isPrintable;
324 } else if (isgraph(data[n]) || isspace(data[n])) {
325 if (bestMode == isSimple)
326 bestMode = isPrintable;
327 } else {
328 bestMode = isBinary;
329 break; // pessimal
330 }
331
332 if (bestMode == isSimple) {
333 string s((const char *)data, length);
334 for (const char * const * k = keywords; *k; k++)
335 if (s == *k) {
336 bestMode = isPrintable; // reserved word; need quotes
337 break;
338 }
339 }
340
341 switch (bestMode) {
342 case isSimple:
866f8763 343 print("%.*s", (int)length, data);
b1ab9ed8
A
344 break;
345 case isPrintable:
5c19dc3a
A
346 print("\"");
347 for (unsigned n = 0; n < length; n++)
348 switch (data[n]) {
349 case '\\':
350 case '"':
351 print("\\%c", data[n]);
352 break;
353 default:
354 print("%c", data[n]);
355 break;
356 }
357 print("\"");
b1ab9ed8
A
358 break;
359 default:
360 print("0x");
361 printBytes(data, length);
362 break;
363 }
364}
365
366void Dumper::printBytes(const Byte *data, size_t length)
367{
368 for (unsigned n = 0; n < length; n++)
369 print("%02.2x", data[n]);
370}
371
372
373} // CodeSigning
374} // Security