1/*
2 * Copyright (c) 2003-2004 Apple Computer, 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 * trusted_cert_utils.c
24 */
25
26#include "trusted_cert_utils.h"
27#include <Security/SecPolicyPriv.h>
28#include <Security/SecBasePriv.h>
29#include <Security/SecTrust.h>
30#include <Security/SecTrustSettings.h>
31#include <Security/cssmapple.h>
32#include <Security/oidsalg.h>
33#include <security_cdsa_utils/cuFileIo.h>
34#include <security_cdsa_utils/cuPem.h>
35
36static int indentSize = 0;
37void indentIncr(void)	{ indentSize += 3; }
38void indentDecr(void)	{ indentSize -= 3; }
39
40void indent(void)
41{
42	int dex;
43	if(indentSize < 0) {
44		/* bug */
45		indentSize = 0;
46	}
47	for (dex=0; dex<indentSize; dex++) {
48		putchar(' ');
49	}
50}
51
52void printAscii(
53	const char *buf,
54	unsigned len,
55	unsigned maxLen)
56{
57	bool doEllipsis = false;
58	unsigned dex;
59	if(len > maxLen) {
60		len = maxLen;
61		doEllipsis = true;
62	}
63	for(dex=0; dex<len; dex++) {
64		char c = *buf++;
65		if(isalnum(c)) {
66			putchar(c);
67		}
68		else {
69			putchar('.');
70		}
71		fflush(stdout);
72	}
73	if(doEllipsis) {
74		printf("...etc.");
75	}
76}
77
78void printHex(
79	const unsigned char *buf,
80	unsigned len,
81	unsigned maxLen)
82{
83	bool doEllipsis = false;
84	unsigned dex;
85	if(len > maxLen) {
86		len = maxLen;
87		doEllipsis = true;
88	}
89	for(dex=0; dex<len; dex++) {
90		printf("%02X ", *buf++);
91	}
92	if(doEllipsis) {
93		printf("...etc.");
94	}
95}
96
97/* print the contents of a CFString */
98void printCfStr(
99	CFStringRef cfstr)
100{
101	CFDataRef strData = CFStringCreateExternalRepresentation(NULL, cfstr,
102		kCFStringEncodingUTF8, true);
103	CFIndex dex;
104
105	if(strData == NULL) {
106		printf("<<string decode error>>");
107		return;
108	}
109	const char *cp = (const char *)CFDataGetBytePtr(strData);
110	CFIndex len = CFDataGetLength(strData);
111	for(dex=0; dex<len; dex++) {
112		putchar(*cp++);
113	}
114	CFRelease(strData);
115}
116
117/* print a CFDateRef */
118static const char *months[12] = {
119	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
120	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
121};
122
123void printCFDate(
124	CFDateRef dateRef)
125{
126	CFAbsoluteTime absTime = CFDateGetAbsoluteTime(dateRef);
127	if(absTime == 0.0) {
128		printf("<<Malformed CFDateeRef>>\n");
129		return;
130	}
131	CFGregorianDate gregDate = CFAbsoluteTimeGetGregorianDate(absTime, NULL);
132	const char *month = "Unknown";
133	if((gregDate.month > 12) || (gregDate.month <= 0)) {
134		printf("Huh? GregDate.month > 11. These amps only GO to 11.\n");
135	}
136	else {
137		month = months[gregDate.month - 1];
138	}
139	printf("%s %d, %d %02d:%02d",
140		month, gregDate.day, (int)gregDate.year, gregDate.hour, gregDate.minute);
141}
142
143/* print a CFNumber */
144void printCfNumber(
145	CFNumberRef cfNum)
146{
147	SInt32 s;
148	if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &s)) {
149		printf("***CFNumber overflow***");
150		return;
151	}
152	printf("%d", (int)s);
153}
154
155/* print a CFNumber as a SecTrustSettingsResult */
156void printResultType(
157	CFNumberRef cfNum)
158{
159	SInt32 n;
160	if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &n)) {
161		printf("***CFNumber overflow***");
162		return;
163	}
164	const char *s;
165	char bogus[100];
166	switch(n) {
167		case kSecTrustSettingsResultInvalid: s = "kSecTrustSettingsResultInvalid"; break;
168		case kSecTrustSettingsResultTrustRoot: s = "kSecTrustSettingsResultTrustRoot"; break;
169		case kSecTrustSettingsResultTrustAsRoot: s = "kSecTrustSettingsResultTrustAsRoot"; break;
170		case kSecTrustSettingsResultDeny:    s = "kSecTrustSettingsResultDeny"; break;
171		case kSecTrustSettingsResultUnspecified: s = "kSecTrustSettingsResultUnspecified"; break;
172		default:
173			sprintf(bogus, "Unknown SecTrustSettingsResult (%d)", (int)n);
174			s = bogus;
175			break;
176	}
177	printf("%s", s);
178}
179
180/* print a CFNumber as SecTrustSettingsKeyUsage */
181void printKeyUsage(
182	CFNumberRef cfNum)
183{
184	SInt32 s;
185	if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &s)) {
186		printf("***CFNumber overflow***");
187		return;
188	}
189	uint32 n = (uint32)s;
190	if(n == kSecTrustSettingsKeyUseAny) {
191		printf("<any>");
192		return;
193	}
194	else if(n == 0) {
195		printf("<none>");
196		return;
197	}
198	printf("< ");
199	if(n & kSecTrustSettingsKeyUseSignature) {
200		printf("Signature ");
201	}
202	if(n & kSecTrustSettingsKeyUseEnDecryptData) {
203		printf("EnDecryptData ");
204	}
205	if(n & kSecTrustSettingsKeyUseEnDecryptKey) {
206		printf("EnDecryptKey ");
207	}
208	if(n & kSecTrustSettingsKeyUseSignCert) {
209		printf("SignCert ");
210	}
211	if(n & kSecTrustSettingsKeyUseSignRevocation) {
212		printf("SignRevocation ");
213	}
214	if(n & kSecTrustSettingsKeyUseKeyExchange) {
215		printf("KeyExchange ");
216	}
217	printf(" >");
218}
219
220/* print a CFNumber as CSSM_RETURN string */
221void printCssmErr(
222	CFNumberRef cfNum)
223{
224	SInt32 s;
225	if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &s)) {
226		printf("***CFNumber overflow***");
227		return;
228	}
229	printf("%s", cssmErrorString((CSSM_RETURN)s));
230}
231
232/* convert an OID to a SecPolicyRef */
233SecPolicyRef oidToPolicy(
234	const CSSM_OID *oid)
235{
236	OSStatus ortn;
237	SecPolicyRef policyRef = NULL;
238
239	ortn = SecPolicyCopy(CSSM_CERT_X_509v3, oid, &policyRef);
240	if(ortn) {
241		cssmPerror("SecPolicyCopy", ortn);
242		return NULL;
243	}
244	return policyRef;
245}
246
247typedef struct {
248	const CSSM_OID *oid;
249	const char *oidStr;
250} OidString;
251
252static OidString oidStrings[] =
253{
254	{ &CSSMOID_APPLE_ISIGN, "iSign" },
255	{ &CSSMOID_APPLE_X509_BASIC, "Apple X509 Basic" },
256	{ &CSSMOID_APPLE_TP_SSL, "SSL" },
257	{ &CSSMOID_APPLE_TP_SMIME, "SMIME" },
258	{ &CSSMOID_APPLE_TP_EAP, "EAP" },
259	{ &CSSMOID_APPLE_TP_SW_UPDATE_SIGNING, "SW Update Signing" },
260	{ &CSSMOID_APPLE_TP_IP_SEC, "IPSec" },
261	{ &CSSMOID_APPLE_TP_ICHAT, "iChat" },
262	{ &CSSMOID_APPLE_TP_RESOURCE_SIGN, "Resource Signing" },
263	{ &CSSMOID_APPLE_TP_PKINIT_CLIENT, "PKINIT Client" },
264	{ &CSSMOID_APPLE_TP_PKINIT_SERVER, "PKINIT Server" },
265	{ &CSSMOID_APPLE_TP_CODE_SIGNING, "Code Signing" },
266	{ &CSSMOID_APPLE_TP_PACKAGE_SIGNING, "Package Signing" },
267	{ &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT, "Mac App Store" },
268	{ &CSSMOID_APPLE_TP_APPLEID_SHARING, "AppleID Sharing" }
269};
270#define NUM_OID_STRINGS		(sizeof(oidStrings) / sizeof(oidStrings[0]))
271
272/* convert a policy string to a SecPolicyRef */
273SecPolicyRef oidStringToPolicy(
274	const char *oidStr)
275{
276	/* OID string to an OID pointer */
277	const CSSM_OID *oid = NULL;
278	unsigned dex;
279
280	for(dex=0; dex<NUM_OID_STRINGS; dex++) {
281		OidString *os = &oidStrings[dex];
282		if(!strcmp(oidStr, os->oidStr)) {
283			oid = os->oid;
284			break;
285		}
286	}
287	if(oid == NULL) {
288		return NULL;
289	}
290
291	/* OID to SecPolicyRef */
292	return oidToPolicy(oid);
293}
294
295/* CSSM_OID --> OID string */
296const char *oidToOidString(
297	const CSSM_OID *oid)
298{
299	unsigned dex;
300	static char unknownOidString[200];
301
302	for(dex=0; dex<NUM_OID_STRINGS; dex++) {
303		OidString *os = &oidStrings[dex];
304		if(compareOids(oid, os->oid)) {
305			return os->oidStr;
306		}
307	}
308	sprintf(unknownOidString, "Unknown OID length %ld, value { ", oid->Length);
309	for(dex=0; dex<oid->Length; dex++) {
310		char tmp[6];
311		sprintf(tmp, "%02X ", oid->Data[dex]);
312		strcat(unknownOidString, tmp);
313	}
314	strcat(unknownOidString, " }");
315	return unknownOidString;
316}
317
318/* compare OIDs; returns 1 if identical, else returns 0 */
319int compareOids(
320	const CSSM_OID *oid1,
321	const CSSM_OID *oid2)
322{
323	if((oid1 == NULL) || (oid2 == NULL)) {
324		return 0;
325	}
326	if(oid1->Length != oid2->Length) {
327		return 0;
328	}
329	if(memcmp(oid1->Data, oid2->Data, oid1->Length)) {
330		return 0;
331	}
332	return 1;
333}
334
335/* app path string to SecTrustedApplicationRef */
336SecTrustedApplicationRef appPathToAppRef(
337	const char *appPath)
338{
339	SecTrustedApplicationRef appRef = NULL;
340	OSStatus ortn;
341
342	if(appPath == NULL) {
343		return NULL;
344	}
345	ortn = SecTrustedApplicationCreateFromPath(appPath, &appRef);
346	if(ortn) {
347		cssmPerror("SecTrustedApplicationCreateFromPath", ortn);
348		return NULL;
349	}
350	return appRef;
351}
352
353int readCertFile(
354	const char *fileName,
355	SecCertificateRef *certRef)
356{
357	unsigned char *cp = NULL;
358	unsigned len = 0;
359	CSSM_DATA certData;
360	OSStatus ortn;
361	unsigned char *decoded = NULL;
362	unsigned decodedLen = 0;
363
364	if(readFile(fileName, &cp, &len)) {
365		printf("***Error reading file %s\n", fileName);
366		return -1;
367	}
368	if(isPem(cp, len)) {
369		if(pemDecode(cp, len, &decoded, &decodedLen)) {
370			fprintf(stderr, "Error decoding cert file %s\n", fileName);
371			return -1;
372		}
373		certData.Length = decodedLen;
374		certData.Data = decoded;
375	}
376	else {
377		certData.Length = len;
378		certData.Data = cp;
379	}
380	ortn = SecCertificateCreateFromData(&certData,
381			CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, certRef);
382	free(cp);
383	if(decoded) {
384		free(decoded);
385	}
386	if(ortn) {
387		cssmPerror("SecCertificateCreateFromData", ortn);
388		return -1;
389	}
390	return 0;
391}
392
393/* policy string --> CSSM_OID */
394const CSSM_OID *policyStringToOid(
395	const char *policy)
396{
397	if(policy == NULL) {
398		return NULL;
399	}
400	if(!strcmp(policy, "ssl")) {
401		return &CSSMOID_APPLE_TP_SSL;
402	}
403	else if(!strcmp(policy, "smime")) {
404		return &CSSMOID_APPLE_TP_SMIME;
405	}
406	else if(!strcmp(policy, "codeSign")) {
407		return &CSSMOID_APPLE_TP_CODE_SIGNING;
408	}
409	else if(!strcmp(policy, "IPSec")) {
410		return &CSSMOID_APPLE_TP_IP_SEC;
411	}
412	else if(!strcmp(policy, "iChat")) {
413		return &CSSMOID_APPLE_TP_ICHAT;
414	}
415	else if(!strcmp(policy, "basic")) {
416		return &CSSMOID_APPLE_X509_BASIC;
417	}
418	else if(!strcmp(policy, "swUpdate")) {
419		return &CSSMOID_APPLE_TP_SW_UPDATE_SIGNING;
420	}
421	else if(!strcmp(policy, "pkgSign")) {
422		return &CSSMOID_APPLE_TP_PACKAGE_SIGNING;
423	}
424	else if(!strcmp(policy, "pkinitClient")) {
425		return &CSSMOID_APPLE_TP_PKINIT_CLIENT;
426	}
427	else if(!strcmp(policy, "pkinitServer")) {
428		return &CSSMOID_APPLE_TP_PKINIT_SERVER;
429	}
430	else if(!strcmp(policy, "eap")) {
431		return &CSSMOID_APPLE_TP_EAP;
432	}
433	else if(!strcmp(policy, "macappstore")) {
434		return &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT;
435	}
436	else if(!strcmp(policy, "appleID")) {
437		return &CSSMOID_APPLE_TP_APPLEID_SHARING;
438	}
439	else if(!strcmp(policy, "timestamping")) {
440		return &CSSMOID_APPLE_TP_TIMESTAMPING;
441	}
442	else {
443		fprintf(stderr, "***unknown policy spec (%s)\n", policy);
444		return NULL;
445	}
446}
447