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
31namespace Security {
32namespace CodeSigning {
33
34using namespace UnixPlusPlus;
35
36
37//
38// Table of reserved words (keywords), generated by ANTLR
39//
40static const char * const keywords[] = {
41#include "RequirementKeywords.h"
42	"",
43	NULL
44};
45
46
47//
48// Printf to established output channel
49//
50void 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//
64void 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//
80string 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
103string 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
119string 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//
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:
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 opCertPolicy:
212		print("certificate"); certSlot(); print("[");
213		{
214			const unsigned char *data; size_t length;
215			getData(data, length);
216			print("policy.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
217		}
218		print("]"); match();
219		break;
220	case opTrustedCert:
221		print("certificate"); certSlot(); print("trusted");
222		break;
223	case opTrustedCerts:
224		print("anchor trusted");
225		break;
226	case opNamedAnchor:
227		print("anchor apple "); data();
228		break;
229	case opNamedCode:
230		print("("); data(); print(")");
231		break;
232	default:
233		if (op & opGenericFalse) {
234			print(" false /* opcode %d */", op & ~opFlagMask);
235			break;
236		} else if (op & opGenericSkip) {
237			print(" /* opcode %d */", op & ~opFlagMask);
238			break;
239		} else {
240			print("OPCODE %d NOT UNDERSTOOD (ending print)", op);
241			return;
242		}
243	}
244}
245
246void Dumper::certSlot()
247{
248	switch (int32_t slot = get<int32_t>()) {
249	case Requirement::anchorCert:
250		print(" root");
251		break;
252	case Requirement::leafCert:
253		print(" leaf");
254		break;
255	default:
256		print(" %d", slot);
257		break;
258	}
259}
260
261void Dumper::match()
262{
263	switch (MatchOperation op = MatchOperation(get<uint32_t>())) {
264	case matchExists:
265		print(" /* exists */");
266		break;
267	case matchEqual:
268		print(" = "); data();
269		break;
270	case matchContains:
271		print(" ~ "); data();
272		break;
273	case matchBeginsWith:
274		print(" = "); data(); print("*");
275		break;
276	case matchEndsWith:
277		print(" = *"); data();
278		break;
279	case matchLessThan:
280		print(" < "); data();
281		break;
282	case matchGreaterEqual:
283		print(" >= "); data();
284		break;
285	case matchLessEqual:
286		print(" <= "); data();
287		break;
288	case matchGreaterThan:
289		print(" > "); data();
290		break;
291	default:
292		print("MATCH OPCODE %d NOT UNDERSTOOD", op);
293		break;
294	}
295}
296
297void Dumper::hashData()
298{
299	print("H\"");
300	const unsigned char *data; size_t length;
301	getData(data, length);
302	printBytes(data, length);
303	print("\"");
304}
305
306void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false */)
307{
308	const unsigned char *data; size_t length;
309	getData(data, length);
310	for (unsigned n = 0; n < length; n++)
311		if ((isalnum(data[n]) || (data[n] == '.' && dotOkay))) {	// simple
312			if (n == 0 && isdigit(data[n]))	// unquoted idents can't start with a digit
313				bestMode = isPrintable;
314		} else if (isgraph(data[n]) || isspace(data[n])) {
315			if (bestMode == isSimple)
316				bestMode = isPrintable;
317		} else {
318			bestMode = isBinary;
319			break;		// pessimal
320		}
321
322	if (bestMode == isSimple) {
323		string s((const char *)data, length);
324		for (const char * const * k = keywords; *k; k++)
325			if (s == *k) {
326				bestMode = isPrintable;		// reserved word; need quotes
327				break;
328			}
329	}
330
331	switch (bestMode) {
332	case isSimple:
333		print("%.*s", length, data);
334		break;
335	case isPrintable:
336		print("\"%.*s\"", length, data);
337		break;
338	default:
339		print("0x");
340		printBytes(data, length);
341		break;
342	}
343}
344
345void Dumper::printBytes(const Byte *data, size_t length)
346{
347	for (unsigned n = 0; n < length; n++)
348		print("%02.2x", data[n]);
349}
350
351
352}	// CodeSigning
353}	// Security
354