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