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