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