]> git.saurik.com Git - apple/security.git/blob - SecurityTool/macOS/trusted_cert_utils.c
Security-59306.11.20.tar.gz
[apple/security.git] / SecurityTool / macOS / trusted_cert_utils.c
1 /*
2 * Copyright (c) 2003-2004,2006,2009-2019 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 * trusted_cert_utils.c
24 */
25
26 #include "trusted_cert_utils.h"
27 #include "trusted_cert_ssl.h"
28 #include "SecBase64.h"
29 #include <Security/SecCertificatePriv.h>
30 #include <Security/SecPolicyPriv.h>
31 #include <Security/SecBasePriv.h>
32 #include <Security/SecTrustSettings.h>
33 #include <Security/cssmapple.h>
34 #include <Security/oidsalg.h>
35 #include <utilities/fileIo.h>
36 #include <utilities/SecCFRelease.h>
37 #include <security_cdsa_utils/cuPem.h>
38
39 static int indentSize = 0;
40 void indentIncr(void) { indentSize += 3; }
41 void indentDecr(void) { indentSize -= 3; }
42
43 void indent(void)
44 {
45 int dex;
46 if(indentSize < 0) {
47 /* bug */
48 indentSize = 0;
49 }
50 for (dex=0; dex<indentSize; dex++) {
51 putchar(' ');
52 }
53 }
54
55 void printAscii(
56 const char *buf,
57 unsigned len,
58 unsigned maxLen)
59 {
60 bool doEllipsis = false;
61 unsigned dex;
62 if(len > maxLen) {
63 len = maxLen;
64 doEllipsis = true;
65 }
66 for(dex=0; dex<len; dex++) {
67 char c = *buf++;
68 if(isalnum(c)) {
69 putchar(c);
70 }
71 else {
72 putchar('.');
73 }
74 fflush(stdout);
75 }
76 if(doEllipsis) {
77 printf("...etc.");
78 }
79 }
80
81 void printHex(
82 const unsigned char *buf,
83 unsigned len,
84 unsigned maxLen)
85 {
86 bool doEllipsis = false;
87 unsigned dex;
88 if(len > maxLen) {
89 len = maxLen;
90 doEllipsis = true;
91 }
92 for(dex=0; dex<len; dex++) {
93 printf("%02X ", *buf++);
94 }
95 if(doEllipsis) {
96 printf("...etc.");
97 }
98 }
99
100 /* print the contents of a CFString */
101 void printCfStr(
102 CFStringRef cfstr)
103 {
104 if(cfstr == NULL) {
105 printf("<NULL>");
106 return;
107 }
108 CFDataRef strData = CFStringCreateExternalRepresentation(NULL, cfstr,
109 kCFStringEncodingUTF8, true);
110 CFIndex dex;
111
112 if(strData == NULL) {
113 printf("<<string decode error>>");
114 return;
115 }
116 const char *cp = (const char *)CFDataGetBytePtr(strData);
117 CFIndex len = CFDataGetLength(strData);
118 for(dex=0; dex<len; dex++) {
119 if (*cp == '\n' || *cp == '\r') {
120 printf("\n"); /* handle line breaks */
121 cp++;
122 } else {
123 putchar(*cp++);
124 }
125 }
126 CFRelease(strData);
127 }
128
129 /* print a CFDateRef */
130 static const char *months[12] = {
131 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
132 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
133 };
134
135 void printCFDate(
136 CFDateRef dateRef)
137 {
138 CFAbsoluteTime absTime = CFDateGetAbsoluteTime(dateRef);
139 if(absTime == 0.0) {
140 printf("<<Malformed CFDateRef>>\n");
141 return;
142 }
143 CFGregorianDate gregDate = CFAbsoluteTimeGetGregorianDate(absTime, NULL);
144 const char *month = "Unknown";
145 if((gregDate.month > 12) || (gregDate.month <= 0)) {
146 printf("Huh? GregDate.month > 11. These amps only GO to 11.\n");
147 }
148 else {
149 month = months[gregDate.month - 1];
150 }
151 printf("%s %d, %d %02d:%02d",
152 month, gregDate.day, (int)gregDate.year, gregDate.hour, gregDate.minute);
153 }
154
155 /* print a CFNumber */
156 void printCfNumber(
157 CFNumberRef cfNum)
158 {
159 SInt32 s;
160 if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &s)) {
161 printf("***CFNumber overflow***");
162 return;
163 }
164 printf("%d", (int)s);
165 }
166
167 /* print a CFNumber as a SecTrustSettingsResult */
168 void printResultType(
169 CFNumberRef cfNum)
170 {
171 SInt32 n;
172 if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &n)) {
173 printf("***CFNumber overflow***");
174 return;
175 }
176 const char *s;
177 char bogus[100];
178 switch(n) {
179 case kSecTrustSettingsResultInvalid: s = "kSecTrustSettingsResultInvalid"; break;
180 case kSecTrustSettingsResultTrustRoot: s = "kSecTrustSettingsResultTrustRoot"; break;
181 case kSecTrustSettingsResultTrustAsRoot: s = "kSecTrustSettingsResultTrustAsRoot"; break;
182 case kSecTrustSettingsResultDeny: s = "kSecTrustSettingsResultDeny"; break;
183 case kSecTrustSettingsResultUnspecified: s = "kSecTrustSettingsResultUnspecified"; break;
184 default:
185 sprintf(bogus, "Unknown SecTrustSettingsResult (%d)", (int)n);
186 s = bogus;
187 break;
188 }
189 printf("%s", s);
190 }
191
192 /* print a CFNumber as SecTrustSettingsKeyUsage */
193 void printKeyUsage(
194 CFNumberRef cfNum)
195 {
196 SInt32 s;
197 if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &s)) {
198 printf("***CFNumber overflow***");
199 return;
200 }
201 uint32 n = (uint32)s;
202 if(n == kSecTrustSettingsKeyUseAny) {
203 printf("<any>");
204 return;
205 }
206 else if(n == 0) {
207 printf("<none>");
208 return;
209 }
210 printf("< ");
211 if(n & kSecTrustSettingsKeyUseSignature) {
212 printf("Signature ");
213 }
214 if(n & kSecTrustSettingsKeyUseEnDecryptData) {
215 printf("EnDecryptData ");
216 }
217 if(n & kSecTrustSettingsKeyUseEnDecryptKey) {
218 printf("EnDecryptKey ");
219 }
220 if(n & kSecTrustSettingsKeyUseSignCert) {
221 printf("SignCert ");
222 }
223 if(n & kSecTrustSettingsKeyUseSignRevocation) {
224 printf("SignRevocation ");
225 }
226 if(n & kSecTrustSettingsKeyUseKeyExchange) {
227 printf("KeyExchange ");
228 }
229 printf(" >");
230 }
231
232 /* print a CFNumber as CSSM_RETURN string */
233 void printCssmErr(
234 CFNumberRef cfNum)
235 {
236 SInt32 s;
237 if(!CFNumberGetValue(cfNum, kCFNumberSInt32Type, &s)) {
238 printf("***CFNumber overflow***");
239 return;
240 }
241 printf("%s", cssmErrorString((CSSM_RETURN)s));
242 }
243
244 /* convert an OID to a SecPolicyRef */
245 SecPolicyRef oidToPolicy(
246 const CSSM_OID *oid)
247 {
248 OSStatus ortn;
249 SecPolicyRef policyRef = NULL;
250
251 ortn = SecPolicyCopy(CSSM_CERT_X_509v3, oid, &policyRef);
252 if(ortn) {
253 cssmPerror("SecPolicyCopy", ortn);
254 return NULL;
255 }
256 return policyRef;
257 }
258
259 typedef struct {
260 const CSSM_OID *oid;
261 const char *oidStr;
262 } OidString;
263
264 static OidString oidStrings[] =
265 {
266 { &CSSMOID_APPLE_ISIGN, "iSign" },
267 { &CSSMOID_APPLE_X509_BASIC, "Apple X509 Basic" },
268 { &CSSMOID_APPLE_TP_SSL, "SSL" },
269 { &CSSMOID_APPLE_TP_SMIME, "SMIME" },
270 { &CSSMOID_APPLE_TP_EAP, "EAP" },
271 { &CSSMOID_APPLE_TP_SW_UPDATE_SIGNING, "SW Update Signing" },
272 { &CSSMOID_APPLE_TP_IP_SEC, "IPSec" },
273 { &CSSMOID_APPLE_TP_ICHAT, "iChat" },
274 { &CSSMOID_APPLE_TP_RESOURCE_SIGN, "Resource Signing" },
275 { &CSSMOID_APPLE_TP_PKINIT_CLIENT, "PKINIT Client" },
276 { &CSSMOID_APPLE_TP_PKINIT_SERVER, "PKINIT Server" },
277 { &CSSMOID_APPLE_TP_CODE_SIGNING, "Code Signing" },
278 { &CSSMOID_APPLE_TP_PACKAGE_SIGNING, "Package Signing" },
279 { &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT, "Mac App Store" },
280 { &CSSMOID_APPLE_TP_APPLEID_SHARING, "AppleID Sharing" }
281 };
282 #define NUM_OID_STRINGS (sizeof(oidStrings) / sizeof(oidStrings[0]))
283
284 /* convert a policy string to a SecPolicyRef */
285 SecPolicyRef oidStringToPolicy(
286 const char *oidStr)
287 {
288 /* OID string to an OID pointer */
289 const CSSM_OID *oid = NULL;
290 unsigned dex;
291
292 for(dex=0; dex<NUM_OID_STRINGS; dex++) {
293 OidString *os = &oidStrings[dex];
294 if(!strcmp(oidStr, os->oidStr)) {
295 oid = os->oid;
296 break;
297 }
298 }
299 if(oid == NULL) {
300 return NULL;
301 }
302
303 /* OID to SecPolicyRef */
304 return oidToPolicy(oid);
305 }
306
307 /* CSSM_OID --> OID string */
308 const char *oidToOidString(
309 const CSSM_OID *oid)
310 {
311 unsigned dex;
312 static char unknownOidString[200];
313
314 for(dex=0; dex<NUM_OID_STRINGS; dex++) {
315 OidString *os = &oidStrings[dex];
316 if(compareOids(oid, os->oid)) {
317 return os->oidStr;
318 }
319 }
320 sprintf(unknownOidString, "Unknown OID length %ld, value { ", oid->Length);
321 for(dex=0; dex<oid->Length; dex++) {
322 char tmp[6];
323 sprintf(tmp, "%02X ", oid->Data[dex]);
324 strcat(unknownOidString, tmp);
325 }
326 strcat(unknownOidString, " }");
327 return unknownOidString;
328 }
329
330 /* compare OIDs; returns 1 if identical, else returns 0 */
331 int compareOids(
332 const CSSM_OID *oid1,
333 const CSSM_OID *oid2)
334 {
335 if((oid1 == NULL) || (oid2 == NULL)) {
336 return 0;
337 }
338 if(oid1->Length != oid2->Length) {
339 return 0;
340 }
341 if(memcmp(oid1->Data, oid2->Data, oid1->Length)) {
342 return 0;
343 }
344 return 1;
345 }
346
347 /* app path string to SecTrustedApplicationRef */
348 SecTrustedApplicationRef appPathToAppRef(
349 const char *appPath)
350 {
351 SecTrustedApplicationRef appRef = NULL;
352 OSStatus ortn;
353
354 if(appPath == NULL) {
355 return NULL;
356 }
357 ortn = SecTrustedApplicationCreateFromPath(appPath, &appRef);
358 if(ortn) {
359 cssmPerror("SecTrustedApplicationCreateFromPath", ortn);
360 return NULL;
361 }
362 return appRef;
363 }
364
365 int readCertFile(
366 const char *fileName,
367 SecCertificateRef *certRef)
368 {
369 unsigned char *cp = NULL;
370 size_t len = 0;
371 CSSM_DATA certData;
372 OSStatus ortn;
373 unsigned char *decoded = NULL;
374 unsigned decodedLen = 0;
375
376 if(readFileSizet(fileName, &cp, &len)) {
377 printf("***Error reading file %s\n", fileName);
378 return -1;
379 }
380 if(isPem(cp, (unsigned) len)) {
381 if(pemDecode(cp, (unsigned) len, &decoded, &decodedLen)) {
382 fprintf(stderr, "Error decoding cert file %s\n", fileName);
383 return -1;
384 }
385 certData.Length = decodedLen;
386 certData.Data = decoded;
387 }
388 else {
389 certData.Length = len;
390 certData.Data = cp;
391 }
392 ortn = SecCertificateCreateFromData(&certData,
393 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, certRef);
394 free(cp);
395 if(decoded) {
396 free(decoded);
397 }
398 if(ortn) {
399 cssmPerror("SecCertificateCreateFromData", ortn);
400 return -1;
401 }
402 return 0;
403 }
404
405 /* policy string --> CSSM_OID */
406 const CSSM_OID *policyStringToOid(
407 const char *policy,
408 bool *useTLS)
409 {
410 if(!policy || !useTLS) {
411 return NULL;
412 }
413 if(!strcmp(policy, "ssl")) {
414 *useTLS = true;
415 return &CSSMOID_APPLE_TP_SSL;
416 }
417 else if(!strcmp(policy, "smime")) {
418 return &CSSMOID_APPLE_TP_SMIME;
419 }
420 else if(!strcmp(policy, "codeSign")) {
421 return &CSSMOID_APPLE_TP_CODE_SIGNING;
422 }
423 else if(!strcmp(policy, "IPSec")) {
424 *useTLS = true;
425 return &CSSMOID_APPLE_TP_IP_SEC;
426 }
427 else if(!strcmp(policy, "basic")) {
428 return &CSSMOID_APPLE_X509_BASIC;
429 }
430 else if(!strcmp(policy, "swUpdate")) {
431 return &CSSMOID_APPLE_TP_SW_UPDATE_SIGNING;
432 }
433 else if(!strcmp(policy, "pkgSign")) {
434 return &CSSMOID_APPLE_TP_PACKAGE_SIGNING;
435 }
436 else if(!strcmp(policy, "eap")) {
437 *useTLS = true;
438 return &CSSMOID_APPLE_TP_EAP;
439 }
440 else if(!strcmp(policy, "macappstore")) {
441 return &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT;
442 }
443 else if(!strcmp(policy, "appleID")) {
444 return &CSSMOID_APPLE_TP_APPLEID_SHARING;
445 }
446 else if(!strcmp(policy, "timestamping")) {
447 return &CSSMOID_APPLE_TP_TIMESTAMPING;
448 }
449 else {
450 fprintf(stderr, "***unknown policy spec (%s)\n", policy);
451 return NULL;
452 }
453 }
454
455 CFOptionFlags revCheckOptionStringToFlags(
456 const char *revCheckOption)
457 {
458 CFOptionFlags result = 0;
459 if(revCheckOption == NULL) {
460 return result;
461 }
462 else if(!strcmp(revCheckOption, "ocsp")) {
463 result |= kSecRevocationOCSPMethod;
464 }
465 else if(!strcmp(revCheckOption, "crl")) {
466 result |= kSecRevocationCRLMethod;
467 }
468 else if(!strcmp(revCheckOption, "require")) {
469 result |= kSecRevocationRequirePositiveResponse;
470 }
471 else if(!strcmp(revCheckOption, "offline")) {
472 result |= kSecRevocationNetworkAccessDisabled;
473 }
474 else if(!strcmp(revCheckOption, "online")) {
475 result |= kSecRevocationOnlineCheck;
476 }
477 return result;
478 }
479
480 static size_t print_buffer_pem(FILE *stream,
481 const char *pem_name, size_t length, const uint8_t *bytes)
482 {
483 size_t pem_name_len = strlen(pem_name);
484 size_t b64_len = SecBase64Encode2(NULL, length, NULL, 0,
485 kSecB64_F_LINE_LEN_USE_PARAM, 64, NULL);
486 char *buffer = malloc(33 + 2 * pem_name_len + b64_len);
487 char *p = buffer;
488 p += sprintf(buffer, "-----BEGIN %s-----\n", pem_name);
489 SecBase64Result result;
490 p += SecBase64Encode2(bytes, length, p, b64_len,\
491 kSecB64_F_LINE_LEN_USE_PARAM, 64, &result);
492 if (result) {
493 free(buffer);
494 return result;
495 }
496 p += sprintf(p, "\n-----END %s-----\n", pem_name);
497 size_t res = fwrite(buffer, 1, p - buffer, stream);
498 fflush(stream);
499 bzero(buffer, p - buffer);
500 free(buffer);
501 return res;
502 }
503
504 void printCertLabel(SecCertificateRef certRef)
505 {
506 CFStringRef label = SecCertificateCopySubjectSummary(certRef);
507 printCfStr(label);
508 CFReleaseSafe(label);
509 }
510
511 void printCertDescription(SecCertificateRef certRef)
512 {
513 CFStringRef description = CFCopyDescription((CFTypeRef)certRef);
514 printCfStr(description);
515 CFReleaseSafe(description);
516 }
517
518 void printCertText(SecCertificateRef certRef)
519 {
520 CFStringRef certStr = CopyCertificateTextRepresentation(certRef);
521 printf("\n");
522 printCfStr(certStr);
523 printf("\n\n");
524 CFReleaseSafe(certStr);
525 }
526
527 void printCertChain(SecTrustRef trustRef, bool printPem, bool printText)
528 {
529 CFIndex idx, count = SecTrustGetCertificateCount(trustRef);
530 for (idx = 0; idx < count; idx++) {
531 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trustRef, idx);
532 fprintf(stdout, " %ld: ", idx);
533 printCertLabel(cert);
534 fprintf(stdout, "\n ");
535 if (!cert) { continue; }
536 printCertDescription(cert);
537 fprintf(stdout, "\n");
538 if (printText) {
539 printCertText(cert);
540 }
541 if (printPem) {
542 print_buffer_pem(stdout, "CERTIFICATE",
543 SecCertificateGetLength(cert),
544 SecCertificateGetBytePtr(cert));
545 }
546 }
547 }
548