1/*
2 * Copyright (c) 2005-2007,2011-2012,2014 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/*
26 * printFeilds.h - print various DER objects
27 *
28 */
29
30#include <libDERUtils/printFields.h>
31#include <libDER/DER_Decode.h>
32#include <libDER/asn1Types.h>
33#include <libDER/DER_Keys.h>
34#include <libDERUtils/libDERUtils.h>
35#include <stdlib.h>
36#include <strings.h>
37#include <stdio.h>
38
39static int indentLevel = 0;
40
41void doIndent(void)
42{
43	int i;
44	for (i = 0; i<indentLevel; i++) {
45		putchar(' ');
46	}
47} /* indent */
48
49void incrIndent(void)
50{
51	indentLevel += 3;
52}
53
54void decrIndent(void)
55{
56	indentLevel -= 3;
57}
58
59#define TO_PRINT_MAX	12
60
61void printHex(
62	DERItem *item)
63{
64	unsigned long dex;
65	unsigned long toPrint = item->length;
66
67	printf("<%lu> ", item->length);
68	if(toPrint > TO_PRINT_MAX) {
69		toPrint = TO_PRINT_MAX;
70	}
71	for(dex=0; dex<toPrint; dex++) {
72		printf("%02x ", item->data[dex]);
73	}
74	if(item->length > TO_PRINT_MAX) {
75		printf("...");
76	}
77	printf("\n");
78}
79
80void printBitString(
81	DERItem *item)
82{
83	DERSize dex;
84	DERSize toPrint = item->length;
85	DERItem bitStringBytes;
86	DERByte numUnused;
87	DERReturn drtn;
88
89	drtn = DERParseBitString(item, &bitStringBytes, &numUnused);
90	if(drtn) {
91		DERPerror("DERParseBitString", drtn);
92		return;
93	}
94
95	printf("<%lu, %lu> ", (unsigned long)bitStringBytes.length, (unsigned long)numUnused);
96	toPrint = bitStringBytes.length;
97	if(toPrint > TO_PRINT_MAX) {
98		toPrint = TO_PRINT_MAX;
99	}
100	for(dex=0; dex<toPrint; dex++) {
101		printf("%02x ", bitStringBytes.data[dex]);
102	}
103	if(item->length > TO_PRINT_MAX) {
104		printf("...");
105	}
106	printf("\n");
107}
108
109void printString(
110	DERItem *item)
111{
112	unsigned dex;
113	char *cp = (char *)item->data;
114	printf("'");
115	for(dex=0; dex<item->length; dex++) {
116		putchar(*cp++);
117	}
118	printf("'\n");
119
120}
121
122#define COLON_COLUMN	20
123
124/*
125 * Print line header, with current indent, followed by specified label, followed
126 * by a ':' in column COLON_COLUMN, followed by one space.
127 */
128void printHeader(
129	const char *label)
130{
131	size_t numPrinted;
132
133	doIndent();
134	printf("%s", label);
135	numPrinted = indentLevel + strlen(label);
136	if(numPrinted < COLON_COLUMN) {
137		size_t numSpaces = COLON_COLUMN - numPrinted;
138		size_t dex;
139		for(dex=0; dex<numSpaces; dex++) {
140			putchar(' ');
141		}
142	}
143	printf(": ");
144}
145
146void printItem(
147	const char *label,
148	ItemType itemType,
149	int verbose,
150	DERTag tag,         // maybe from decoding, maybe the real tag underlying
151						// an implicitly tagged item
152	DERItem *item)		// content
153{
154	DERTag tagClass = tag & ASN1_CLASS_MASK;
155	DERTag tagNum = tag & ASN1_TAGNUM_MASK;
156	char printable = 0;
157	char *asnType = NULL;
158
159	printHeader(label);
160
161	if((itemType == IT_Branch) && !verbose) {
162		printf("\n");
163		return;
164	}
165	switch(tagClass) {
166		case ASN1_UNIVERSAL:
167			break;		// proceed with normal tags */
168		case ASN1_APPLICATION:
169			printf("APPLICATION (tag %u) ", tagNum);
170			printHex(item);
171			return;
172		case ASN1_CONTEXT_SPECIFIC:
173			printf("CONTEXT SPECIFIC (tag %u) ", tagNum);
174			printHex(item);
175			return;
176		case ASN1_PRIVATE:
177			printf("PRIVATE (tag %u) ", tagNum);
178			printHex(item);
179			return;
180	}
181	switch(tagNum) {
182		case ASN1_BOOLEAN:
183			asnType = "BOOLEAN";
184			break;
185		case ASN1_INTEGER:
186			asnType = "INTEGER";
187			break;
188		case ASN1_BIT_STRING:
189			/* special case here... */
190			printf("BIT STRING ");
191			printBitString(item);
192			return;
193		case ASN1_OCTET_STRING:
194			asnType = "OCTET STRING";
195			break;
196		case ASN1_NULL:
197			asnType = "NULL";
198			break;
199		case ASN1_OBJECT_ID:
200			asnType = "OID";
201			break;
202		case ASN1_OBJECT_DESCRIPTOR:
203			asnType = "OBJECT_DESCRIPTOR";
204			break;
205		case ASN1_REAL:
206			asnType = "REAL";
207			break;
208		case ASN1_ENUMERATED:
209			asnType = "ENUM";
210			break;
211		case ASN1_EMBEDDED_PDV:
212			asnType = "EMBEDDED_PDV";
213			break;
214		case ASN1_UTF8_STRING:
215			asnType = "UTF8 STRING";
216			/* FIXME print these too */
217			break;
218		case ASN1_SEQUENCE:
219			asnType = "SEQ";
220			break;
221		case ASN1_SET:
222			asnType = "SET";
223			break;
224		case ASN1_NUMERIC_STRING:
225			asnType = "NUMERIC_STRING";
226			break;
227		case ASN1_PRINTABLE_STRING:
228			asnType = "PRINTABLE_STRING";
229			printable = 1;
230			break;
231		case ASN1_T61_STRING:
232			asnType = "T61_STRING";
233			printable = 1;
234			break;
235		case ASN1_VIDEOTEX_STRING:
236			asnType = "VIDEOTEX_STRING";
237			printable = 1;
238			break;
239		case ASN1_IA5_STRING:
240			asnType = "IA5_STRING";
241			printable = 1;
242			break;
243		case ASN1_UTC_TIME:
244			asnType = "UTC_TIME";
245			printable = 1;
246			break;
247		case ASN1_GENERALIZED_TIME:
248			asnType = "GENERALIZED_TIME";
249			printable = 1;
250			break;
251		case ASN1_GRAPHIC_STRING:
252			asnType = "GRAPHIC_STRING";
253			break;
254		case ASN1_VISIBLE_STRING:
255			asnType = "VISIBLE_STRING";
256			break;
257		case ASN1_GENERAL_STRING:
258			asnType = "GENERAL_STRING";
259			break;
260		case ASN1_UNIVERSAL_STRING:
261			asnType = "UNIVERSAL_STRING";
262			break;
263		case ASN1_BMP_STRING:
264			asnType = "BMP_STRING";
265			break;
266		default:
267			asnType = "[unknown]";
268			break;
269	}
270	printf("%s ", asnType);
271	if(printable) {
272		printString(item);
273	}
274	else {
275		printHex(item);
276	}
277}
278
279void printAlgId(
280	const DERItem *content,
281	int verbose)
282{
283	DERReturn drtn;
284	DERAlgorithmId algId;
285
286	drtn = DERParseSequenceContent(content,
287		DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs,
288		&algId, sizeof(algId));
289	if(drtn) {
290		DERPerror("DERParseSequenceContent(algId)", drtn);
291		return;
292	}
293	printItem("alg", IT_Leaf, verbose, ASN1_OBJECT_ID, &algId.oid);
294	if(algId.params.data) {
295		printItem("params", IT_Leaf, verbose, algId.params.data[0], &algId.params);
296	}
297}
298
299void printSubjPubKeyInfo(
300	const DERItem *content,
301	int verbose)
302{
303	DERReturn drtn;
304	DERSubjPubKeyInfo pubKeyInfo;
305	DERRSAPubKeyPKCS1 pkcs1Key;
306	DERItem bitStringContents;
307	DERByte numUnused;
308
309	drtn = DERParseSequenceContent(content,
310		DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs,
311		&pubKeyInfo, sizeof(pubKeyInfo));
312	if(drtn) {
313		DERPerror("DERParseSequenceContent(pubKeyInfo)", drtn);
314		return;
315	}
316	printItem("algId", IT_Branch, verbose, ASN1_CONSTR_SEQUENCE, &pubKeyInfo.algId);
317	incrIndent();
318	printAlgId(&pubKeyInfo.algId, verbose);
319	decrIndent();
320
321	printItem("pubKey", IT_Branch, verbose, ASN1_BIT_STRING, &pubKeyInfo.pubKey);
322
323	/*
324	 * The contents of that bit string are a PKCS1 format RSA key.
325	 */
326	drtn = DERParseBitString(&pubKeyInfo.pubKey, &bitStringContents, &numUnused);
327	if(drtn) {
328		DERPerror("DERParseBitString(pubKeyInfo.pubKey)", drtn);
329		decrIndent();
330		return;
331	}
332	drtn = DERParseSequence(&bitStringContents,
333		DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs,
334		&pkcs1Key, sizeof(pkcs1Key));
335	if(drtn) {
336		DERPerror("DERParseSequenceContent(pubKeyBits)", drtn);
337		decrIndent();
338		return;
339	}
340	incrIndent();
341	printItem("modulus", IT_Leaf, verbose, ASN1_INTEGER, &pkcs1Key.modulus);
342	printItem("pubExponent", IT_Leaf, verbose, ASN1_INTEGER, &pkcs1Key.pubExponent);
343
344	decrIndent();
345}
346
347/* decode one item and print it */
348void decodePrintItem(
349	const char *label,
350	ItemType itemType,
351	int verbose,
352	DERItem *derItem)
353{
354	DERDecodedInfo decoded;
355	DERReturn drtn;
356
357	drtn = DERDecodeItem(derItem, &decoded);
358	if(drtn) {
359		DERPerror("DERDecodeItem()", drtn);
360		return;
361	}
362	printItem(label, IT_Leaf, 0, decoded.tag, &decoded.content);
363}
364
365