1/* 2 * Copyright (c) 2006-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 * SecCertificate.c - CoreFoundation based certificate object 26 */ 27 28#ifdef STANDALONE 29/* Allows us to build genanchors against the BaseSDK. */ 30#undef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ 31#undef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 32#endif 33 34#include <Security/SecCertificateInternal.h> 35#include <utilities/SecIOFormat.h> 36#include <CommonCrypto/CommonDigest.h> 37#include <CoreFoundation/CFRuntime.h> 38#include <CoreFoundation/CFString.h> 39#include <CoreFoundation/CFBundle.h> 40#include <CoreFoundation/CFDictionary.h> 41#include <CoreFoundation/CFNumber.h> 42#include <CoreFoundation/CFCalendar.h> 43#include <CoreFoundation/CFTimeZone.h> 44#include <CoreFoundation/CFXPCBridge.h> 45#include <string.h> 46#include <AssertMacros.h> 47#include <libDER/DER_CertCrl.h> 48#include <libDER/DER_Encode.h> 49#include <libDER/DER_Keys.h> 50#include <libDER/asn1Types.h> 51#include <libDER/oids.h> 52#include "SecBasePriv.h" 53#include "SecRSAKey.h" 54#include "SecFramework.h" 55#include "SecItem.h" 56#include "SecItemPriv.h" 57#include <stdbool.h> 58#include <utilities/debugging.h> 59#include <utilities/SecCFWrappers.h> 60#include <utilities/SecCFError.h> 61#include <utilities/array_size.h> 62#include <stdlib.h> 63#include <libkern/OSByteOrder.h> 64#include <ctype.h> 65#include <Security/SecInternal.h> 66#include <Security/SecFrameworkStrings.h> 67#include "SecBase64.h" 68#include "AppleBaselineEscrowCertificates.h" 69#include <ipc/securityd_client.h> 70 71typedef struct SecCertificateExtension { 72 DERItem extnID; 73 bool critical; 74 DERItem extnValue; 75} SecCertificateExtension; 76 77#if 0 78typedef struct KnownExtension { 79 bool critical; 80 DERItem extnValue; 81} KnownExtension; 82 83enum { 84 kSecSelfSignedUnknown = 0, 85 kSecSelfSignedFalse, 86 kSecSelfSignedTrue, 87}; 88#endif 89 90struct __SecCertificate { 91 CFRuntimeBase _base; 92 93 DERItem _der; /* Entire certificate in DER form. */ 94 DERItem _tbs; /* To Be Signed cert DER bytes. */ 95 DERAlgorithmId _sigAlg; /* Top level signature algorithm. */ 96 DERItem _signature; /* The content of the sig bit string. */ 97 98 UInt8 _version; 99 DERItem _serialNum; /* Integer. */ 100 DERAlgorithmId _tbsSigAlg; /* sig alg MUST be same as _sigAlg. */ 101 DERItem _issuer; /* Sequence of RDN. */ 102 CFAbsoluteTime _notBefore; 103 CFAbsoluteTime _notAfter; 104 DERItem _subject; /* Sequence of RDN. */ 105 DERAlgorithmId _algId; /* oid and params of _pubKeyDER. */ 106 DERItem _pubKeyDER; /* contents of bit string */ 107 DERItem _issuerUniqueID; /* bit string, optional */ 108 DERItem _subjectUniqueID; /* bit string, optional */ 109 110#if 0 111 /* Known extensions if the certificate contains them, 112 extnValue.length will be > 0. */ 113 KnownExtension _authorityKeyID; 114 115 /* This extension is used to uniquely identify a certificate from among 116 several that have the same subject name. If the extension is not 117 present, its value is calculated by performing a SHA-1 hash of the 118 certificate's DER encoded subjectPublicKeyInfo, as recommended by 119 PKIX. */ 120 KnownExtension _subjectKeyID; 121 KnownExtension _keyUsage; 122 KnownExtension _extendedKeyUsage; 123 KnownExtension _basicConstraints; 124 KnownExtension _netscapeCertType; 125 KnownExtension _subjectAltName; 126 KnownExtension _qualCertStatements; 127 128#endif 129 bool _foundUnknownCriticalExtension; 130 131 /* Well known certificate extensions. */ 132 SecCEBasicConstraints _basicConstraints; 133 SecCEPolicyConstraints _policyConstraints; 134 CFDictionaryRef _policyMappings; 135 SecCECertificatePolicies _certificatePolicies; 136 137 /* If InhibitAnyPolicy extension is not present or invalid UINT32_MAX, 138 value of the SkipCerts field of the InhibitAnyPolicy extension 139 otherwise. */ 140 uint32_t _inhibitAnyPolicySkipCerts; 141 142 /* If KeyUsage extension is not present this is 0, otherwise it's 143 the value of the extension. */ 144 SecKeyUsage _keyUsage; 145 146 /* OCTECTS of SubjectKeyIdentifier extensions KeyIdentifier. 147 Length = 0 if not present. */ 148 DERItem _subjectKeyIdentifier; 149 150 /* OCTECTS of AuthorityKeyIdentifier extensions KeyIdentifier. 151 Length = 0 if not present. */ 152 DERItem _authorityKeyIdentifier; 153 /* AuthorityKeyIdentifier extension _authorityKeyIdentifierIssuer and 154 _authorityKeyIdentifierSerialNumber have non zero length if present. 155 Both are either present or absent together. */ 156 DERItem _authorityKeyIdentifierIssuer; 157 DERItem _authorityKeyIdentifierSerialNumber; 158 159 /* Subject alt name extension, if present. Not malloced, it's just a 160 pointer to an element in the _extensions array. */ 161 const SecCertificateExtension *_subjectAltName; 162 163 /* Parsed extension values. */ 164 165 /* Array of CFURLRefs containing the URI values of crlDistributionPoints. */ 166 CFMutableArrayRef _crlDistributionPoints; 167 168 /* Array of CFURLRefs containing the URI values of accessLocations of each 169 id-ad-ocsp AccessDescription in the Authority Information Access 170 extension. */ 171 CFMutableArrayRef _ocspResponders; 172 173 /* Array of CFURLRefs containing the URI values of accessLocations of each 174 id-ad-caIssuers AccessDescription in the Authority Information Access 175 extension. */ 176 CFMutableArrayRef _caIssuers; 177 178 /* All other (non known) extensions. The _extensions array is malloced. */ 179 CFIndex _extensionCount; 180 SecCertificateExtension *_extensions; 181 182 /* Optional cached fields. */ 183 SecKeyRef _pubKey; 184 CFDataRef _der_data; 185 CFArrayRef _properties; 186 CFDataRef _serialNumber; 187 CFDataRef _normalizedIssuer; 188 CFDataRef _normalizedSubject; 189 CFDataRef _authorityKeyID; 190 CFDataRef _subjectKeyID; 191 192 CFDataRef _sha1Digest; 193 uint8_t _isSelfSigned; 194 195}; 196 197#define SEC_CONST_DECL(k,v) CFTypeRef k = (CFTypeRef)(CFSTR(v)); 198 199SEC_CONST_DECL (kSecCertificateProductionEscrowKey, "ProductionEscrowKey"); 200SEC_CONST_DECL (kSecCertificateProductionPCSEscrowKey, "ProductionPCSEscrowKey"); 201SEC_CONST_DECL (kSecCertificateEscrowFileName, "AppleESCertificates"); 202 203/* Public Constants for property list keys. */ 204SEC_CONST_DECL (kSecPropertyKeyType, "type"); 205SEC_CONST_DECL (kSecPropertyKeyLabel, "label"); 206SEC_CONST_DECL (kSecPropertyKeyLocalizedLabel, "localized label"); 207SEC_CONST_DECL (kSecPropertyKeyValue, "value"); 208 209/* Public Constants for property list values. */ 210SEC_CONST_DECL (kSecPropertyTypeWarning, "warning"); 211SEC_CONST_DECL (kSecPropertyTypeError, "error"); 212SEC_CONST_DECL (kSecPropertyTypeSuccess, "success"); 213SEC_CONST_DECL (kSecPropertyTypeTitle, "title"); 214SEC_CONST_DECL (kSecPropertyTypeSection, "section"); 215SEC_CONST_DECL (kSecPropertyTypeData, "data"); 216SEC_CONST_DECL (kSecPropertyTypeString, "string"); 217SEC_CONST_DECL (kSecPropertyTypeURL, "url"); 218SEC_CONST_DECL (kSecPropertyTypeDate, "date"); 219 220/* Extension parsing routine. */ 221typedef void (*SecCertificateExtensionParser)(SecCertificateRef certificate, 222 const SecCertificateExtension *extn); 223 224/* Mapping from extension OIDs (as a DERItem *) to 225 SecCertificateExtensionParser extension parsing routines. */ 226static CFDictionaryRef sExtensionParsers; 227 228/* Forward declarations of static functions. */ 229static CFStringRef SecCertificateDescribe(CFTypeRef cf); 230static void SecCertificateDestroy(CFTypeRef cf); 231static bool derDateGetAbsoluteTime(const DERItem *dateChoice, 232 CFAbsoluteTime *absTime) __attribute__((__nonnull__)); 233 234/* Static functions. */ 235static CF_RETURNS_RETAINED CFStringRef SecCertificateDescribe(CFTypeRef cf) { 236 SecCertificateRef certificate = (SecCertificateRef)cf; 237 CFStringRef subject = SecCertificateCopySubjectSummary(certificate); 238 CFStringRef issuer = SecCertificateCopyIssuerSummary(certificate); 239 CFStringRef desc = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, 240 CFSTR("<cert(%p) s: %@ i: %@>"), certificate, subject, issuer); 241 CFReleaseSafe(issuer); 242 CFReleaseSafe(subject); 243 return desc; 244} 245 246static void SecCertificateDestroy(CFTypeRef cf) { 247 SecCertificateRef certificate = (SecCertificateRef)cf; 248 if (certificate->_certificatePolicies.policies) 249 free(certificate->_certificatePolicies.policies); 250 CFReleaseSafe(certificate->_policyMappings); 251 CFReleaseSafe(certificate->_crlDistributionPoints); 252 CFReleaseSafe(certificate->_ocspResponders); 253 CFReleaseSafe(certificate->_caIssuers); 254 if (certificate->_extensions) { 255 free(certificate->_extensions); 256 } 257 CFReleaseSafe(certificate->_pubKey); 258 CFReleaseSafe(certificate->_der_data); 259 CFReleaseSafe(certificate->_properties); 260 CFReleaseSafe(certificate->_serialNumber); 261 CFReleaseSafe(certificate->_normalizedIssuer); 262 CFReleaseSafe(certificate->_normalizedSubject); 263 CFReleaseSafe(certificate->_authorityKeyID); 264 CFReleaseSafe(certificate->_subjectKeyID); 265 CFReleaseSafe(certificate->_sha1Digest); 266} 267 268static Boolean SecCertificateEqual(CFTypeRef cf1, CFTypeRef cf2) { 269 SecCertificateRef cert1 = (SecCertificateRef)cf1; 270 SecCertificateRef cert2 = (SecCertificateRef)cf2; 271 if (cert1 == cert2) 272 return true; 273 if (!cert2 || cert1->_der.length != cert2->_der.length) 274 return false; 275 return !memcmp(cert1->_der.data, cert2->_der.data, cert1->_der.length); 276} 277 278/* Hash of the certificate is der length + signature length + last 4 bytes 279 of signature. */ 280static CFHashCode SecCertificateHash(CFTypeRef cf) { 281 SecCertificateRef certificate = (SecCertificateRef)cf; 282 size_t der_length = certificate->_der.length; 283 size_t sig_length = certificate->_signature.length; 284 size_t ix = (sig_length > 4) ? sig_length - 4 : 0; 285 CFHashCode hashCode = 0; 286 for (; ix < sig_length; ++ix) 287 hashCode = (hashCode << 8) + certificate->_signature.data[ix]; 288 289 return (hashCode + der_length + sig_length); 290} 291 292#if 1 293 294/************************************************************************/ 295/************************* General Name Parsing *************************/ 296/************************************************************************/ 297 298typedef OSStatus (*parseGeneralNameCallback)(void *context, 299 SecCEGeneralNameType type, const DERItem *value); 300 301 302/* 303 GeneralName ::= CHOICE { 304 otherName [0] OtherName, 305 rfc822Name [1] IA5String, 306 dNSName [2] IA5String, 307 x400Address [3] ORAddress, 308 directoryName [4] Name, 309 ediPartyName [5] EDIPartyName, 310 uniformResourceIdentifier [6] IA5String, 311 iPAddress [7] OCTET STRING, 312 registeredID [8] OBJECT IDENTIFIER} 313 314 OtherName ::= SEQUENCE { 315 type-id OBJECT IDENTIFIER, 316 value [0] EXPLICIT ANY DEFINED BY type-id } 317 318 EDIPartyName ::= SEQUENCE { 319 nameAssigner [0] DirectoryString OPTIONAL, 320 partyName [1] DirectoryString } 321 */ 322static OSStatus parseGeneralNameContentProperty(DERTag tag, 323 const DERItem *generalNameContent, 324 void *context, parseGeneralNameCallback callback) { 325 switch (tag) { 326 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0: 327 return callback(context, GNT_OtherName, generalNameContent); 328 case ASN1_CONTEXT_SPECIFIC | 1: 329 return callback(context, GNT_RFC822Name, generalNameContent); 330 case ASN1_CONTEXT_SPECIFIC | 2: 331 return callback(context, GNT_DNSName, generalNameContent); 332 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3: 333 return callback(context, GNT_X400Address, generalNameContent); 334 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4: 335 return callback(context, GNT_DirectoryName, generalNameContent); 336 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5: 337 return callback(context, GNT_EdiPartyName, generalNameContent); 338 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6: 339 { 340 /* Technically I don't think this is valid, but there are certs out 341 in the wild that use a constructed IA5String. In particular the 342 VeriSign Time Stamping Authority CA.cer does this. */ 343 DERDecodedInfo uriContent; 344 require_noerr(DERDecodeItem(generalNameContent, &uriContent), badDER); 345 require(uriContent.tag == ASN1_IA5_STRING, badDER); 346 return callback(context, GNT_URI, &uriContent.content); 347 } 348 case ASN1_CONTEXT_SPECIFIC | 6: 349 return callback(context, GNT_URI, generalNameContent); 350 case ASN1_CONTEXT_SPECIFIC | 7: 351 return callback(context, GNT_IPAddress, generalNameContent); 352 case ASN1_CONTEXT_SPECIFIC | 8: 353 return callback(context, GNT_RegisteredID, generalNameContent); 354 default: 355 goto badDER; 356 } 357badDER: 358 return errSecInvalidCertificate; 359} 360 361static OSStatus parseGeneralNamesContent(const DERItem *generalNamesContent, 362 void *context, parseGeneralNameCallback callback) { 363 DERSequence gnSeq; 364 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq); 365 require_noerr_quiet(drtn, badDER); 366 DERDecodedInfo generalNameContent; 367 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) == 368 DR_Success) { 369 OSStatus status = parseGeneralNameContentProperty( 370 generalNameContent.tag, &generalNameContent.content, context, 371 callback); 372 if (status) 373 return status; 374 } 375 require_quiet(drtn == DR_EndOfSequence, badDER); 376 return errSecSuccess; 377 378badDER: 379 return errSecInvalidCertificate; 380} 381 382static OSStatus parseGeneralNames(const DERItem *generalNames, void *context, 383 parseGeneralNameCallback callback) { 384 DERDecodedInfo generalNamesContent; 385 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent); 386 require_noerr_quiet(drtn, badDER); 387 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 388 return parseGeneralNamesContent(&generalNamesContent.content, context, 389 callback); 390badDER: 391 return errSecInvalidCertificate; 392} 393 394#else 395 396/* 397 GeneralName ::= CHOICE { 398 otherName [0] OtherName, 399 rfc822Name [1] IA5String, 400 dNSName [2] IA5String, 401 x400Address [3] ORAddress, 402 directoryName [4] Name, 403 ediPartyName [5] EDIPartyName, 404 uniformResourceIdentifier [6] IA5String, 405 iPAddress [7] OCTET STRING, 406 registeredID [8] OBJECT IDENTIFIER} 407 408 EDIPartyName ::= SEQUENCE { 409 nameAssigner [0] DirectoryString OPTIONAL, 410 partyName [1] DirectoryString } 411 */ 412static OSStatus parseGeneralNameContentProperty(DERTag tag, 413 const DERItem *generalNameContent, SecCEGeneralName *generalName) { 414 switch (tag) { 415 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0: 416 generalName->nameType = GNT_OtherName; 417 generalName->berEncoded = true; 418 generalName->name = *generalNameContent; 419 break; 420 case ASN1_CONTEXT_SPECIFIC | 1: 421 /* IA5String. */ 422 generalName->nameType = GNT_RFC822Name; 423 generalName->berEncoded = false; 424 generalName->name = *generalNameContent; 425 break; 426 case ASN1_CONTEXT_SPECIFIC | 2: 427 /* IA5String. */ 428 generalName->nameType = GNT_DNSName; 429 generalName->berEncoded = false; 430 generalName->name = *generalNameContent; 431 break; 432 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3: 433 generalName->nameType = GNT_X400Address; 434 generalName->berEncoded = true; 435 generalName->name = *generalNameContent; 436 break; 437 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4: 438 generalName->nameType = GNT_DirectoryName; 439 generalName->berEncoded = true; 440 generalName->name = *generalNameContent; 441 break; 442 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5: 443 generalName->nameType = GNT_EdiPartyName; 444 generalName->berEncoded = true; 445 generalName->name = *generalNameContent; 446 break; 447 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6: 448 { 449 /* Technically I don't think this is valid, but there are certs out 450 in the wild that use a constructed IA5String. In particular the 451 VeriSign Time Stamping Authority CA.cer does this. */ 452 DERDecodedInfo decoded; 453 require_noerr(DERDecodeItem(generalNameContent, &decoded), badDER); 454 require(decoded.tag == ASN1_IA5_STRING, badDER); 455 generalName->nameType = GNT_URI; 456 generalName->berEncoded = false; 457 generalName->name = decoded.content; 458 break; 459 } 460 case ASN1_CONTEXT_SPECIFIC | 6: 461 generalName->nameType = GNT_URI; 462 generalName->berEncoded = false; 463 generalName->name = *generalNameContent; 464 break; 465 case ASN1_CONTEXT_SPECIFIC | 7: 466 /* @@@ This is the IP Address as an OCTECT STRING. For IPv4 it's 467 8 octects, addr/mask for ipv6 it's 32. */ 468 generalName->nameType = GNT_IPAddress; 469 generalName->berEncoded = false; 470 generalName->name = *generalNameContent; 471 break; 472 case ASN1_CONTEXT_SPECIFIC | 8: 473 /* name is the content of an OID. */ 474 generalName->nameType = GNT_RegisteredID; 475 generalName->berEncoded = false; 476 generalName->name = *generalNameContent; 477 break; 478 default: 479 goto badDER; 480 break; 481 } 482 return errSecSuccess; 483badDER: 484 return errSecInvalidCertificate; 485} 486 487/* 488 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 489 */ 490static OSStatus parseGeneralNamesContent(const DERItem *generalNamesContent, 491 CFIndex *count, SecCEGeneralName **name) { 492 SecCEGeneralName *generalNames = NULL; 493 DERSequence gnSeq; 494 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq); 495 require_noerr_quiet(drtn, badDER); 496 DERDecodedInfo generalNameContent; 497 CFIndex generalNamesCount = 0; 498 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) == 499 DR_Success) { 500 ++generalNamesCount; 501 } 502 require_quiet(drtn == DR_EndOfSequence, badDER); 503 504 require(generalNames = calloc(generalNamesCount, sizeof(SecCEGeneralName)), 505 badDER); 506 DERDecodeSeqContentInit(generalNamesContent, &gnSeq); 507 CFIndex ix = 0; 508 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) == 509 DR_Success) { 510 if (!parseGeneralNameContentProperty(generalNameContent.tag, 511 &generalNameContent.content, &generalNames[ix])) { 512 goto badDER; 513 } 514 ++ix; 515 } 516 *count = generalNamesCount; 517 *name = generalNames; 518 return errSecSuccess; 519 520badDER: 521 if (generalNames) 522 free(generalNames); 523 return errSecInvalidCertificate; 524} 525 526static OSStatus parseGeneralNames(const DERItem *generalNames, 527 CFIndex *count, SecCEGeneralName **name) { 528 DERDecodedInfo generalNamesContent; 529 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent); 530 require_noerr_quiet(drtn, badDER); 531 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE, 532 badDER); 533 parseGeneralNamesContent(&generalNamesContent.content, count, name); 534 return errSecSuccess; 535badDER: 536 return errSecInvalidCertificate; 537} 538#endif 539 540/************************************************************************/ 541/************************** X.509 Name Parsing **************************/ 542/************************************************************************/ 543 544typedef OSStatus (*parseX501NameCallback)(void *context, const DERItem *type, 545 const DERItem *value, CFIndex rdnIX); 546 547static OSStatus parseRDNContent(const DERItem *rdnSetContent, void *context, 548 parseX501NameCallback callback) { 549 DERSequence rdn; 550 DERReturn drtn = DERDecodeSeqContentInit(rdnSetContent, &rdn); 551 require_noerr_quiet(drtn, badDER); 552 DERDecodedInfo atvContent; 553 CFIndex rdnIX = 0; 554 while ((drtn = DERDecodeSeqNext(&rdn, &atvContent)) == DR_Success) { 555 require_quiet(atvContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 556 DERAttributeTypeAndValue atv; 557 drtn = DERParseSequenceContent(&atvContent.content, 558 DERNumAttributeTypeAndValueItemSpecs, 559 DERAttributeTypeAndValueItemSpecs, 560 &atv, sizeof(atv)); 561 require_noerr_quiet(drtn, badDER); 562 require_quiet(atv.type.length != 0, badDER); 563 OSStatus status = callback(context, &atv.type, &atv.value, rdnIX++); 564 if (status) 565 return status; 566 } 567 require_quiet(drtn == DR_EndOfSequence, badDER); 568 569 return errSecSuccess; 570badDER: 571 return errSecInvalidCertificate; 572} 573 574static OSStatus parseX501NameContent(const DERItem *x501NameContent, void *context, 575 parseX501NameCallback callback) { 576 DERSequence derSeq; 577 DERReturn drtn = DERDecodeSeqContentInit(x501NameContent, &derSeq); 578 require_noerr_quiet(drtn, badDER); 579 DERDecodedInfo currDecoded; 580 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) { 581 require_quiet(currDecoded.tag == ASN1_CONSTR_SET, badDER); 582 OSStatus status = parseRDNContent(&currDecoded.content, context, 583 callback); 584 if (status) 585 return status; 586 } 587 require_quiet(drtn == DR_EndOfSequence, badDER); 588 589 return errSecSuccess; 590 591badDER: 592 return errSecInvalidCertificate; 593} 594 595static OSStatus parseX501Name(const DERItem *x501Name, void *context, 596 parseX501NameCallback callback) { 597 DERDecodedInfo x501NameContent; 598 if (DERDecodeItem(x501Name, &x501NameContent) || 599 x501NameContent.tag != ASN1_CONSTR_SEQUENCE) { 600 return errSecInvalidCertificate; 601 } else { 602 return parseX501NameContent(&x501NameContent.content, context, 603 callback); 604 } 605} 606 607/************************************************************************/ 608/********************** Extension Parsing Routines **********************/ 609/************************************************************************/ 610 611static void SecCEPSubjectKeyIdentifier(SecCertificateRef certificate, 612 const SecCertificateExtension *extn) { 613 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 614 DERDecodedInfo keyIdentifier; 615 DERReturn drtn = DERDecodeItem(&extn->extnValue, &keyIdentifier); 616 require_noerr_quiet(drtn, badDER); 617 require_quiet(keyIdentifier.tag == ASN1_OCTET_STRING, badDER); 618 certificate->_subjectKeyIdentifier = keyIdentifier.content; 619 620 return; 621badDER: 622 secwarning("Invalid SubjectKeyIdentifier Extension"); 623} 624 625static void SecCEPKeyUsage(SecCertificateRef certificate, 626 const SecCertificateExtension *extn) { 627 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 628 SecKeyUsage keyUsage = extn->critical ? kSecKeyUsageCritical : 0; 629 DERDecodedInfo bitStringContent; 630 DERReturn drtn = DERDecodeItem(&extn->extnValue, &bitStringContent); 631 require_noerr_quiet(drtn, badDER); 632 require_quiet(bitStringContent.tag == ASN1_BIT_STRING, badDER); 633 DERSize len = bitStringContent.content.length - 1; 634 require_quiet(len == 1 || len == 2, badDER); 635 DERByte numUnusedBits = bitStringContent.content.data[0]; 636 require_quiet(numUnusedBits < 8, badDER); 637 /* Flip the bits in the bit string so the first bit in the lsb. */ 638 uint_fast16_t bits = 8 * len - numUnusedBits; 639 uint_fast16_t value = bitStringContent.content.data[1]; 640 uint_fast16_t mask; 641 if (len > 1) { 642 value = (value << 8) + bitStringContent.content.data[2]; 643 mask = 0x8000; 644 } else { 645 mask = 0x80; 646 } 647 uint_fast16_t ix; 648 for (ix = 0; ix < bits; ++ix) { 649 if (value & mask) { 650 keyUsage |= 1 << ix; 651 } 652 mask >>= 1; 653 } 654 certificate->_keyUsage = keyUsage; 655 return; 656badDER: 657 certificate->_keyUsage = kSecKeyUsageUnspecified; 658} 659 660static void SecCEPPrivateKeyUsagePeriod(SecCertificateRef certificate, 661 const SecCertificateExtension *extn) { 662 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 663} 664 665static void SecCEPSubjectAltName(SecCertificateRef certificate, 666 const SecCertificateExtension *extn) { 667 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 668 certificate->_subjectAltName = extn; 669} 670 671static void SecCEPIssuerAltName(SecCertificateRef certificate, 672 const SecCertificateExtension *extn) { 673 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 674} 675 676static void SecCEPBasicConstraints(SecCertificateRef certificate, 677 const SecCertificateExtension *extn) { 678 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 679 DERBasicConstraints basicConstraints; 680 require_noerr_quiet(DERParseSequence(&extn->extnValue, 681 DERNumBasicConstraintsItemSpecs, DERBasicConstraintsItemSpecs, 682 &basicConstraints, sizeof(basicConstraints)), badDER); 683 require_noerr_quiet(DERParseBoolean(&basicConstraints.cA, false, 684 &certificate->_basicConstraints.isCA), badDER); 685 if (basicConstraints.pathLenConstraint.length != 0) { 686 require_noerr_quiet(DERParseInteger( 687 &basicConstraints.pathLenConstraint, 688 &certificate->_basicConstraints.pathLenConstraint), badDER); 689 certificate->_basicConstraints.pathLenConstraintPresent = true; 690 } 691 certificate->_basicConstraints.present = true; 692 certificate->_basicConstraints.critical = extn->critical; 693 return; 694badDER: 695 certificate->_basicConstraints.present = false; 696 secwarning("Invalid BasicConstraints Extension"); 697} 698 699static void SecCEPCrlDistributionPoints(SecCertificateRef certificate, 700 const SecCertificateExtension *extn) { 701 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 702} 703 704/* 705 certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation 706 707 PolicyInformation ::= SEQUENCE { 708 policyIdentifier CertPolicyId, 709 policyQualifiers SEQUENCE SIZE (1..MAX) OF 710 PolicyQualifierInfo OPTIONAL } 711 712 CertPolicyId ::= OBJECT IDENTIFIER 713 714 PolicyQualifierInfo ::= SEQUENCE { 715 policyQualifierId PolicyQualifierId, 716 qualifier ANY DEFINED BY policyQualifierId } 717*/ 718static void SecCEPCertificatePolicies(SecCertificateRef certificate, 719 const SecCertificateExtension *extn) { 720 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 721 DERTag tag; 722 DERSequence piSeq; 723 SecCEPolicyInformation *policies = NULL; 724 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &piSeq); 725 require_noerr_quiet(drtn, badDER); 726 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 727 DERDecodedInfo piContent; 728 DERSize policy_count = 0; 729 while ((drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) { 730 require_quiet(piContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 731 policy_count++; 732 } 733 require_quiet(drtn == DR_EndOfSequence, badDER); 734 policies = (SecCEPolicyInformation *)malloc(sizeof(SecCEPolicyInformation) 735 * (policy_count > 0 ? policy_count : 1)); 736 DERDecodeSeqInit(&extn->extnValue, &tag, &piSeq); 737 DERSize policy_ix = 0; 738 while ((drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) { 739 DERPolicyInformation pi; 740 drtn = DERParseSequenceContent(&piContent.content, 741 DERNumPolicyInformationItemSpecs, 742 DERPolicyInformationItemSpecs, 743 &pi, sizeof(pi)); 744 require_noerr_quiet(drtn, badDER); 745 policies[policy_ix].policyIdentifier = pi.policyIdentifier; 746 policies[policy_ix++].policyQualifiers = pi.policyQualifiers; 747 } 748 certificate->_certificatePolicies.present = true; 749 certificate->_certificatePolicies.critical = extn->critical; 750 certificate->_certificatePolicies.numPolicies = policy_count; 751 certificate->_certificatePolicies.policies = policies; 752 return; 753badDER: 754 if (policies) 755 free(policies); 756 certificate->_certificatePolicies.present = false; 757 secwarning("Invalid CertificatePolicies Extension"); 758} 759 760/* 761 id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } 762 763 PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { 764 issuerDomainPolicy CertPolicyId, 765 subjectDomainPolicy CertPolicyId } 766*/ 767#if 0 768static void SecCEPPolicyMappings(SecCertificateRef certificate, 769 const SecCertificateExtension *extn) { 770 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 771 DERTag tag; 772 DERSequence pmSeq; 773 SecCEPolicyMapping *mappings = NULL; 774 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &pmSeq); 775 require_noerr_quiet(drtn, badDER); 776 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 777 DERDecodedInfo pmContent; 778 DERSize mapping_count = 0; 779 while ((drtn = DERDecodeSeqNext(&pmSeq, &pmContent)) == DR_Success) { 780 require_quiet(pmContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 781 mapping_count++; 782 } 783 mappings = (SecCEPolicyMapping *)malloc(sizeof(SecCEPolicyMapping) 784 * mapping_count); 785 DERDecodeSeqInit(&extn->extnValue, &tag, &pmSeq); 786 DERSize mapping_ix = 0; 787 while ((drtn = DERDecodeSeqNext(&pmSeq, &pmContent)) == DR_Success) { 788 DERPolicyMapping pm; 789 drtn = DERParseSequenceContent(&pmContent.content, 790 DERNumPolicyMappingItemSpecs, 791 DERPolicyMappingItemSpecs, 792 &pm, sizeof(pm)); 793 require_noerr_quiet(drtn, badDER); 794 mappings[mapping_ix].issuerDomainPolicy = pm.issuerDomainPolicy; 795 mappings[mapping_ix++].subjectDomainPolicy = pm.subjectDomainPolicy; 796 } 797 require_quiet(drtn == DR_EndOfSequence, badDER); 798 certificate->_policyMappings.present = true; 799 certificate->_policyMappings.critical = extn->critical; 800 certificate->_policyMappings.numMappings = mapping_count; 801 certificate->_policyMappings.mappings = mappings; 802 return; 803badDER: 804 if (mappings) 805 free(mappings); 806 CFReleaseSafe(mappings); 807 certificate->_policyMappings.present = false; 808 secwarning("Invalid CertificatePolicies Extension"); 809} 810#else 811static void SecCEPPolicyMappings(SecCertificateRef certificate, 812 const SecCertificateExtension *extn) { 813 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 814 DERTag tag; 815 DERSequence pmSeq; 816 CFMutableDictionaryRef mappings = NULL; 817 CFDataRef idp = NULL, sdp = NULL; 818 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &pmSeq); 819 require_noerr_quiet(drtn, badDER); 820 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 821 DERDecodedInfo pmContent; 822 require_quiet(mappings = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 823 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), 824 badDER); 825 while ((drtn = DERDecodeSeqNext(&pmSeq, &pmContent)) == DR_Success) { 826 require_quiet(pmContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 827 DERPolicyMapping pm; 828 drtn = DERParseSequenceContent(&pmContent.content, 829 DERNumPolicyMappingItemSpecs, 830 DERPolicyMappingItemSpecs, 831 &pm, sizeof(pm)); 832 require_noerr_quiet(drtn, badDER); 833 require_quiet(idp = CFDataCreate(kCFAllocatorDefault, 834 pm.issuerDomainPolicy.data, pm.issuerDomainPolicy.length), badDER); 835 require_quiet(sdp = CFDataCreate(kCFAllocatorDefault, 836 pm.subjectDomainPolicy.data, pm.subjectDomainPolicy.length), badDER); 837 CFMutableArrayRef sdps = 838 (CFMutableArrayRef)CFDictionaryGetValue(mappings, idp); 839 if (sdps) { 840 CFArrayAppendValue(sdps, sdp); 841 } else { 842 require_quiet(sdps = CFArrayCreateMutable(kCFAllocatorDefault, 0, 843 &kCFTypeArrayCallBacks), badDER); 844 CFDictionarySetValue(mappings, idp, sdps); 845 CFRelease(sdps); 846 } 847 CFReleaseNull(idp); 848 CFReleaseNull(sdp); 849 } 850 require_quiet(drtn == DR_EndOfSequence, badDER); 851 certificate->_policyMappings = mappings; 852 return; 853badDER: 854 CFReleaseSafe(idp); 855 CFReleaseSafe(sdp); 856 CFReleaseSafe(mappings); 857 certificate->_policyMappings = NULL; 858 secwarning("Invalid CertificatePolicies Extension"); 859} 860#endif 861 862/* 863AuthorityKeyIdentifier ::= SEQUENCE { 864 keyIdentifier [0] KeyIdentifier OPTIONAL, 865 authorityCertIssuer [1] GeneralNames OPTIONAL, 866 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } 867 -- authorityCertIssuer and authorityCertSerialNumber MUST both 868 -- be present or both be absent 869 870KeyIdentifier ::= OCTET STRING 871*/ 872static void SecCEPAuthorityKeyIdentifier(SecCertificateRef certificate, 873 const SecCertificateExtension *extn) { 874 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 875 DERAuthorityKeyIdentifier akid; 876 DERReturn drtn; 877 drtn = DERParseSequence(&extn->extnValue, 878 DERNumAuthorityKeyIdentifierItemSpecs, 879 DERAuthorityKeyIdentifierItemSpecs, 880 &akid, sizeof(akid)); 881 require_noerr_quiet(drtn, badDER); 882 if (akid.keyIdentifier.length) { 883 certificate->_authorityKeyIdentifier = akid.keyIdentifier; 884 } 885 if (akid.authorityCertIssuer.length || 886 akid.authorityCertSerialNumber.length) { 887 require_quiet(akid.authorityCertIssuer.length && 888 akid.authorityCertSerialNumber.length, badDER); 889 /* Perhaps put in a subsection called Authority Certificate Issuer. */ 890 certificate->_authorityKeyIdentifierIssuer = akid.authorityCertIssuer; 891 certificate->_authorityKeyIdentifierSerialNumber = akid.authorityCertSerialNumber; 892 } 893 894 return; 895badDER: 896 secwarning("Invalid AuthorityKeyIdentifier Extension"); 897} 898 899static void SecCEPPolicyConstraints(SecCertificateRef certificate, 900 const SecCertificateExtension *extn) { 901 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 902 DERPolicyConstraints pc; 903 DERReturn drtn; 904 drtn = DERParseSequence(&extn->extnValue, 905 DERNumPolicyConstraintsItemSpecs, 906 DERPolicyConstraintsItemSpecs, 907 &pc, sizeof(pc)); 908 require_noerr_quiet(drtn, badDER); 909 if (pc.requireExplicitPolicy.length) { 910 require_noerr_quiet(DERParseInteger( 911 &pc.requireExplicitPolicy, 912 &certificate->_policyConstraints.requireExplicitPolicy), badDER); 913 certificate->_policyConstraints.requireExplicitPolicyPresent = true; 914 } 915 if (pc.inhibitPolicyMapping.length) { 916 require_noerr_quiet(DERParseInteger( 917 &pc.inhibitPolicyMapping, 918 &certificate->_policyConstraints.inhibitPolicyMapping), badDER); 919 certificate->_policyConstraints.inhibitPolicyMappingPresent = true; 920 } 921 922 certificate->_policyConstraints.present = true; 923 certificate->_policyConstraints.critical = extn->critical; 924 925 return; 926badDER: 927 certificate->_policyConstraints.present = false; 928 secwarning("Invalid PolicyConstraints Extension"); 929} 930 931static void SecCEPExtendedKeyUsage(SecCertificateRef certificate, 932 const SecCertificateExtension *extn) { 933 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 934} 935 936/* 937 InhibitAnyPolicy ::= SkipCerts 938 939 SkipCerts ::= INTEGER (0..MAX) 940*/ 941static void SecCEPInhibitAnyPolicy(SecCertificateRef certificate, 942 const SecCertificateExtension *extn) { 943 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 944 require_noerr_quiet(DERParseInteger( 945 &extn->extnValue, 946 &certificate->_inhibitAnyPolicySkipCerts), badDER); 947 return; 948badDER: 949 certificate->_inhibitAnyPolicySkipCerts = UINT32_MAX; 950 secwarning("Invalid InhibitAnyPolicy Extension"); 951} 952 953/* 954 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } 955 956 AuthorityInfoAccessSyntax ::= 957 SEQUENCE SIZE (1..MAX) OF AccessDescription 958 959 AccessDescription ::= SEQUENCE { 960 accessMethod OBJECT IDENTIFIER, 961 accessLocation GeneralName } 962 963 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } 964 965 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 } 966 967 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } 968 */ 969static void SecCEPAuthorityInfoAccess(SecCertificateRef certificate, 970 const SecCertificateExtension *extn) { 971 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 972 DERTag tag; 973 DERSequence adSeq; 974 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &adSeq); 975 require_noerr_quiet(drtn, badDER); 976 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 977 DERDecodedInfo adContent; 978 while ((drtn = DERDecodeSeqNext(&adSeq, &adContent)) == DR_Success) { 979 require_quiet(adContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 980 DERAccessDescription ad; 981 drtn = DERParseSequenceContent(&adContent.content, 982 DERNumAccessDescriptionItemSpecs, 983 DERAccessDescriptionItemSpecs, 984 &ad, sizeof(ad)); 985 require_noerr_quiet(drtn, badDER); 986 CFMutableArrayRef *urls; 987 if (DEROidCompare(&ad.accessMethod, &oidAdOCSP)) 988 urls = &certificate->_ocspResponders; 989 else if (DEROidCompare(&ad.accessMethod, &oidAdCAIssuer)) 990 urls = &certificate->_caIssuers; 991 else 992 continue; 993 994 DERDecodedInfo generalNameContent; 995 drtn = DERDecodeItem(&ad.accessLocation, &generalNameContent); 996 require_noerr_quiet(drtn, badDER); 997 switch (generalNameContent.tag) { 998#if 0 999 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6: 1000 /* Technically I don't think this is valid, but there are certs out 1001 in the wild that use a constructed IA5String. In particular the 1002 VeriSign Time Stamping Authority CA.cer does this. */ 1003#endif 1004 case ASN1_CONTEXT_SPECIFIC | 6: 1005 { 1006 CFURLRef url = CFURLCreateWithBytes(kCFAllocatorDefault, 1007 generalNameContent.content.data, generalNameContent.content.length, 1008 kCFStringEncodingASCII, NULL); 1009 if (url) { 1010 if (!*urls) 1011 *urls = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 1012 CFArrayAppendValue(*urls, url); 1013 CFRelease(url); 1014 } 1015 break; 1016 } 1017 default: 1018 secdebug("cert", "bad general name for id-ad-ocsp AccessDescription t: 0x%02x v: %.*s", 1019 generalNameContent.tag, (int) generalNameContent.content.length, generalNameContent.content.data); 1020 goto badDER; 1021 break; 1022 } 1023 } 1024 require_quiet(drtn == DR_EndOfSequence, badDER); 1025 return; 1026badDER: 1027 secdebug("cert", "failed to parse Authority Information Access extension"); 1028} 1029 1030/* Apple Worldwide Developer Relations Certificate Authority subject name. 1031 * This is a DER sequence with the leading tag and length bytes removed, 1032 * to match what tbsCert.issuer contains. 1033 */ 1034static const unsigned char Apple_WWDR_CA_Subject_Name[]={ 1035 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, 1036 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65, 1037 0x20,0x49,0x6E,0x63,0x2E,0x31,0x2C,0x30,0x2A,0x06,0x03,0x55,0x04,0x0B,0x0C,0x23, 1038 0x41,0x70,0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20, 1039 0x44,0x65,0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69, 1040 0x6F,0x6E,0x73,0x31,0x44,0x30,0x42,0x06,0x03,0x55,0x04,0x03,0x0C,0x3B,0x41,0x70, 1041 0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20,0x44,0x65, 1042 0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,0x6F,0x6E, 1043 0x73,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, 1044 0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79 1045}; 1046 1047static void checkForMissingRevocationInfo(SecCertificateRef certificate) { 1048 if (!certificate || 1049 certificate->_crlDistributionPoints || 1050 certificate->_ocspResponders) { 1051 /* We already have an OCSP or CRL URI (or no cert) */ 1052 return; 1053 } 1054 /* Specify an appropriate OCSP responder if we recognize the issuer. */ 1055 CFURLRef url = NULL; 1056 if (sizeof(Apple_WWDR_CA_Subject_Name) == certificate->_issuer.length && 1057 !memcmp(certificate->_issuer.data, Apple_WWDR_CA_Subject_Name, 1058 sizeof(Apple_WWDR_CA_Subject_Name))) { 1059 const char *WWDR_OCSP_URI = "http://ocsp.apple.com/ocsp-wwdr01"; 1060 url = CFURLCreateWithBytes(kCFAllocatorDefault, 1061 (const UInt8*)WWDR_OCSP_URI, strlen(WWDR_OCSP_URI), 1062 kCFStringEncodingASCII, NULL); 1063 } 1064 if (url) { 1065 CFMutableArrayRef *urls = &certificate->_ocspResponders; 1066 *urls = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 1067 CFArrayAppendValue(*urls, url); 1068 CFRelease(url); 1069 } 1070} 1071 1072static void SecCEPSubjectInfoAccess(SecCertificateRef certificate, 1073 const SecCertificateExtension *extn) { 1074 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 1075} 1076 1077static void SecCEPNetscapeCertType(SecCertificateRef certificate, 1078 const SecCertificateExtension *extn) { 1079 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 1080} 1081 1082static void SecCEPEntrustVersInfo(SecCertificateRef certificate, 1083 const SecCertificateExtension *extn) { 1084 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 1085} 1086 1087static void SecCEPEscrowMarker(SecCertificateRef certificate, 1088 const SecCertificateExtension *extn) { 1089 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 1090} 1091 1092 1093/* Dictionary key callback for comparing to DERItems. */ 1094static Boolean SecDERItemEqual(const void *value1, const void *value2) { 1095 return DEROidCompare((const DERItem *)value1, (const DERItem *)value2); 1096} 1097 1098/* Dictionary key callback calculating the hash of a DERItem. */ 1099static CFHashCode SecDERItemHash(const void *value) { 1100 const DERItem *derItem = (const DERItem *)value; 1101 CFHashCode hash = derItem->length; 1102 DERSize ix = derItem->length > 8 ? derItem->length - 8 : 0; 1103 for (; ix < derItem->length; ++ix) { 1104 hash = (hash << 9) + (hash >> 23) + derItem->data[ix]; 1105 } 1106 1107 return hash; 1108} 1109 1110/* Dictionary key callbacks using the above 2 functions. */ 1111static const CFDictionaryKeyCallBacks SecDERItemKeyCallBacks = { 1112 0, /* version */ 1113 NULL, /* retain */ 1114 NULL, /* release */ 1115 NULL, /* copyDescription */ 1116 SecDERItemEqual, /* equal */ 1117 SecDERItemHash /* hash */ 1118}; 1119 1120static void SecCertificateInitializeExtensionParsers(void) { 1121 /* Build a dictionary that maps from extension OIDs to callback functions 1122 which can parse the extension of the type given. */ 1123 static const void *extnOIDs[] = { 1124 &oidSubjectKeyIdentifier, 1125 &oidKeyUsage, 1126 &oidPrivateKeyUsagePeriod, 1127 &oidSubjectAltName, 1128 &oidIssuerAltName, 1129 &oidBasicConstraints, 1130 &oidCrlDistributionPoints, 1131 &oidCertificatePolicies, 1132 &oidPolicyMappings, 1133 &oidAuthorityKeyIdentifier, 1134 &oidPolicyConstraints, 1135 &oidExtendedKeyUsage, 1136 &oidInhibitAnyPolicy, 1137 &oidAuthorityInfoAccess, 1138 &oidSubjectInfoAccess, 1139 &oidNetscapeCertType, 1140 &oidEntrustVersInfo, 1141 &oidApplePolicyEscrowService 1142 }; 1143 static const void *extnParsers[] = { 1144 SecCEPSubjectKeyIdentifier, 1145 SecCEPKeyUsage, 1146 SecCEPPrivateKeyUsagePeriod, 1147 SecCEPSubjectAltName, 1148 SecCEPIssuerAltName, 1149 SecCEPBasicConstraints, 1150 SecCEPCrlDistributionPoints, 1151 SecCEPCertificatePolicies, 1152 SecCEPPolicyMappings, 1153 SecCEPAuthorityKeyIdentifier, 1154 SecCEPPolicyConstraints, 1155 SecCEPExtendedKeyUsage, 1156 SecCEPInhibitAnyPolicy, 1157 SecCEPAuthorityInfoAccess, 1158 SecCEPSubjectInfoAccess, 1159 SecCEPNetscapeCertType, 1160 SecCEPEntrustVersInfo, 1161 SecCEPEscrowMarker, 1162 }; 1163 sExtensionParsers = CFDictionaryCreate(kCFAllocatorDefault, extnOIDs, 1164 extnParsers, array_size(extnOIDs), 1165 &SecDERItemKeyCallBacks, NULL); 1166} 1167 1168CFGiblisWithFunctions(SecCertificate, NULL, NULL, SecCertificateDestroy, SecCertificateEqual, SecCertificateHash, NULL, SecCertificateDescribe, NULL, NULL, ^{ 1169 SecCertificateInitializeExtensionParsers(); 1170}) 1171 1172/* Given the contents of an X.501 Name return the contents of a normalized 1173 X.501 name. */ 1174CFDataRef createNormalizedX501Name(CFAllocatorRef allocator, 1175 const DERItem *x501name) { 1176 CFMutableDataRef result = CFDataCreateMutable(allocator, x501name->length); 1177 CFIndex length = x501name->length; 1178 CFDataSetLength(result, length); 1179 UInt8 *base = CFDataGetMutableBytePtr(result); 1180 1181 DERSequence rdnSeq; 1182 DERReturn drtn = DERDecodeSeqContentInit(x501name, &rdnSeq); 1183 1184 require_noerr_quiet(drtn, badDER); 1185 DERDecodedInfo rdn; 1186 1187 /* Always points to last rdn tag. */ 1188 const DERByte *rdnTag = rdnSeq.nextItem; 1189 /* Offset relative to base of current rdn set tag. */ 1190 CFIndex rdnTagLocation = 0; 1191 while ((drtn = DERDecodeSeqNext(&rdnSeq, &rdn)) == DR_Success) { 1192 require_quiet(rdn.tag == ASN1_CONSTR_SET, badDER); 1193 /* We don't allow empty RDNs. */ 1194 require_quiet(rdn.content.length != 0, badDER); 1195 /* Length of the tag and length of the current rdn. */ 1196 CFIndex rdnTLLength = rdn.content.data - rdnTag; 1197 CFIndex rdnContentLength = rdn.content.length; 1198 /* Copy the tag and length of the RDN. */ 1199 memcpy(base + rdnTagLocation, rdnTag, rdnTLLength); 1200 1201 DERSequence atvSeq; 1202 drtn = DERDecodeSeqContentInit(&rdn.content, &atvSeq); 1203 require_quiet(drtn == DR_Success, badDER); 1204 1205 DERDecodedInfo atv; 1206 /* Always points to tag of current atv sequence. */ 1207 const DERByte *atvTag = atvSeq.nextItem; 1208 /* Offset relative to base of current atv sequence tag. */ 1209 CFIndex atvTagLocation = rdnTagLocation + rdnTLLength; 1210 while ((drtn = DERDecodeSeqNext(&atvSeq, &atv)) == DR_Success) { 1211 require_quiet(atv.tag == ASN1_CONSTR_SEQUENCE, badDER); 1212 /* Length of the tag and length of the current atv. */ 1213 CFIndex atvTLLength = atv.content.data - atvTag; 1214 CFIndex atvContentLength = atv.content.length; 1215 /* Copy the tag and length of the atv and the atv itself. */ 1216 memcpy(base + atvTagLocation, atvTag, 1217 atvTLLength + atv.content.length); 1218 1219 /* Now decode the atv sequence. */ 1220 DERAttributeTypeAndValue atvPair; 1221 drtn = DERParseSequenceContent(&atv.content, 1222 DERNumAttributeTypeAndValueItemSpecs, 1223 DERAttributeTypeAndValueItemSpecs, 1224 &atvPair, sizeof(atvPair)); 1225 require_noerr_quiet(drtn, badDER); 1226 require_quiet(atvPair.type.length != 0, badDER); 1227 DERDecodedInfo value; 1228 drtn = DERDecodeItem(&atvPair.value, &value); 1229 require_noerr_quiet(drtn, badDER); 1230 1231 /* (c) attribute values in PrintableString are not case sensitive 1232 (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and 1233 1234 (d) attribute values in PrintableString are compared after 1235 removing leading and trailing white space and converting internal 1236 substrings of one or more consecutive white space characters to a 1237 single space. */ 1238 if (value.tag == ASN1_PRINTABLE_STRING) { 1239 /* Offset relative to base of current value tag. */ 1240 CFIndex valueTagLocation = atvTagLocation + atvPair.value.data - atvTag; 1241 CFIndex valueTLLength = value.content.data - atvPair.value.data; 1242 CFIndex valueContentLength = value.content.length; 1243 1244 /* Now copy all the bytes, but convert to upper case while 1245 doing so and convert multiple whitespace chars into a 1246 single space. */ 1247 bool lastWasBlank = false; 1248 CFIndex valueLocation = valueTagLocation + valueTLLength; 1249 CFIndex valueCurrentLocation = valueLocation; 1250 CFIndex ix; 1251 for (ix = 0; ix < valueContentLength; ++ix) { 1252 UInt8 ch = value.content.data[ix]; 1253 if (isblank(ch)) { 1254 if (lastWasBlank) { 1255 continue; 1256 } else { 1257 /* Don't insert a space for first character 1258 we encounter. */ 1259 if (valueCurrentLocation > valueLocation) { 1260 base[valueCurrentLocation++] = ' '; 1261 } 1262 lastWasBlank = true; 1263 } 1264 } else { 1265 lastWasBlank = false; 1266 if ('a' <= ch && ch <= 'z') { 1267 base[valueCurrentLocation++] = ch + 'A' - 'a'; 1268 } else { 1269 base[valueCurrentLocation++] = ch; 1270 } 1271 } 1272 } 1273 /* Finally if lastWasBlank remove the trailing space. */ 1274 if (lastWasBlank && valueCurrentLocation > valueLocation) { 1275 valueCurrentLocation--; 1276 } 1277 /* Adjust content length to normalized length. */ 1278 valueContentLength = valueCurrentLocation - valueLocation; 1279 1280 /* Number of bytes by which the length should be shorted. */ 1281 CFIndex lengthDiff = value.content.length - valueContentLength; 1282 if (lengthDiff == 0) { 1283 /* Easy case no need to adjust lengths. */ 1284 } else { 1285 /* Hard work we need to go back and fix up length fields 1286 for: 1287 1) The value itself. 1288 2) The ATV Sequence containing type/value 1289 3) The RDN Set containing one or more atv pairs. 1290 4) The result. 1291 */ 1292 1293 /* Step 1 fix up length of value. */ 1294 /* Length of value tag and length minus the tag. */ 1295 DERSize newValueTLLength = valueTLLength - 1; 1296 drtn = DEREncodeLength(valueContentLength, 1297 base + valueTagLocation + 1, &newValueTLLength); 1298 require(drtn == DR_Success, badDER); 1299 /* Add the length of the tag back in. */ 1300 newValueTLLength++; 1301 CFIndex valueLLDiff = valueTLLength - newValueTLLength; 1302 if (valueLLDiff) { 1303 /* The size of the length field changed, let's slide 1304 the value back by valueLLDiff bytes. */ 1305 memmove(base + valueTagLocation + newValueTLLength, 1306 base + valueTagLocation + valueTLLength, 1307 valueContentLength); 1308 /* The length diff for the enclosing object. */ 1309 lengthDiff += valueLLDiff; 1310 } 1311 1312 /* Step 2 fix up length of the enclosing ATV Sequence. */ 1313 atvContentLength -= lengthDiff; 1314 DERSize newATVTLLength = atvTLLength - 1; 1315 drtn = DEREncodeLength(atvContentLength, 1316 base + atvTagLocation + 1, &newATVTLLength); 1317 require(drtn == DR_Success, badDER); 1318 /* Add the length of the tag back in. */ 1319 newATVTLLength++; 1320 CFIndex atvLLDiff = atvTLLength - newATVTLLength; 1321 if (atvLLDiff) { 1322 /* The size of the length field changed, let's slide 1323 the value back by valueLLDiff bytes. */ 1324 memmove(base + atvTagLocation + newATVTLLength, 1325 base + atvTagLocation + atvTLLength, 1326 atvContentLength); 1327 /* The length diff for the enclosing object. */ 1328 lengthDiff += atvLLDiff; 1329 atvTLLength = newATVTLLength; 1330 } 1331 1332 /* Step 3 fix up length of enclosing RDN Set. */ 1333 rdnContentLength -= lengthDiff; 1334 DERSize newRDNTLLength = rdnTLLength - 1; 1335 drtn = DEREncodeLength(rdnContentLength, 1336 base + rdnTagLocation + 1, &newRDNTLLength); 1337 require_quiet(drtn == DR_Success, badDER); 1338 /* Add the length of the tag back in. */ 1339 newRDNTLLength++; 1340 CFIndex rdnLLDiff = rdnTLLength - newRDNTLLength; 1341 if (rdnLLDiff) { 1342 /* The size of the length field changed, let's slide 1343 the value back by valueLLDiff bytes. */ 1344 memmove(base + rdnTagLocation + newRDNTLLength, 1345 base + rdnTagLocation + rdnTLLength, 1346 rdnContentLength); 1347 /* The length diff for the enclosing object. */ 1348 lengthDiff += rdnLLDiff; 1349 rdnTLLength = newRDNTLLength; 1350 1351 /* Adjust the locations that might have changed due to 1352 this slide. */ 1353 atvTagLocation -= rdnLLDiff; 1354 } 1355 (void) lengthDiff; // No next object, silence analyzer 1356 } 1357 } 1358 atvTagLocation += atvTLLength + atvContentLength; 1359 atvTag = atvSeq.nextItem; 1360 } 1361 rdnTagLocation += rdnTLLength + rdnContentLength; 1362 rdnTag = rdnSeq.nextItem; 1363 } 1364 require_quiet(drtn == DR_EndOfSequence, badDER); 1365 /* Truncate the result to the proper length. */ 1366 CFDataSetLength(result, rdnTagLocation); 1367 1368 return result; 1369 1370badDER: 1371 CFRelease(result); 1372 return NULL; 1373} 1374 1375CFDataRef SecDistinguishedNameCopyNormalizedContent(CFDataRef distinguished_name) 1376{ 1377 const DERItem name = { (unsigned char *)CFDataGetBytePtr(distinguished_name), CFDataGetLength(distinguished_name) }; 1378 DERDecodedInfo content; 1379 /* Decode top level sequence into DERItem */ 1380 if (!DERDecodeItem(&name, &content) && (content.tag == ASN1_CONSTR_SEQUENCE)) 1381 return createNormalizedX501Name(kCFAllocatorDefault, &content.content); 1382 return NULL; 1383} 1384 1385/* AUDIT[securityd]: 1386 certificate->_der is a caller provided data of any length (might be 0). 1387 1388 Top level certificate decode. 1389 */ 1390static bool SecCertificateParse(SecCertificateRef certificate) 1391{ 1392 DERReturn drtn; 1393 1394 check(certificate); 1395 require_quiet(certificate, badCert); 1396 CFAllocatorRef allocator = CFGetAllocator(certificate); 1397 1398 /* top level decode */ 1399 DERSignedCertCrl signedCert; 1400 drtn = DERParseSequence(&certificate->_der, DERNumSignedCertCrlItemSpecs, 1401 DERSignedCertCrlItemSpecs, &signedCert, 1402 sizeof(signedCert)); 1403 require_noerr_quiet(drtn, badCert); 1404 /* Store tbs since we need to digest it for verification later on. */ 1405 certificate->_tbs = signedCert.tbs; 1406 1407 /* decode the TBSCert - it was saved in full DER form */ 1408 DERTBSCert tbsCert; 1409 drtn = DERParseSequence(&signedCert.tbs, 1410 DERNumTBSCertItemSpecs, DERTBSCertItemSpecs, 1411 &tbsCert, sizeof(tbsCert)); 1412 require_noerr_quiet(drtn, badCert); 1413 1414 /* sequence we're given: decode the signedCerts Signature Algorithm. */ 1415 /* This MUST be the same as the certificate->_tbsSigAlg with the exception 1416 of the params field. */ 1417 drtn = DERParseSequenceContent(&signedCert.sigAlg, 1418 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, 1419 &certificate->_sigAlg, sizeof(certificate->_sigAlg)); 1420 require_noerr_quiet(drtn, badCert); 1421 1422 /* The contents of signedCert.sig is a bit string whose contents 1423 are the signature itself. */ 1424 DERByte numUnusedBits; 1425 drtn = DERParseBitString(&signedCert.sig, 1426 &certificate->_signature, &numUnusedBits); 1427 require_noerr_quiet(drtn, badCert); 1428 1429 /* Now decode the tbsCert. */ 1430 1431 /* First we turn the optional version into an int. */ 1432 if (tbsCert.version.length) { 1433 DERDecodedInfo decoded; 1434 drtn = DERDecodeItem(&tbsCert.version, &decoded); 1435 require_noerr_quiet(drtn, badCert); 1436 require_quiet(decoded.tag == ASN1_INTEGER, badCert); 1437 require_quiet(decoded.content.length == 1, badCert); 1438 certificate->_version = decoded.content.data[0]; 1439 require_quiet(certificate->_version > 0, badCert); 1440 require_quiet(certificate->_version < 3, badCert); 1441 } else { 1442 certificate->_version = 0; 1443 } 1444 1445 /* The serial number is in the tbsCert.serialNum - it was saved in 1446 INTEGER form without the tag and length. */ 1447 certificate->_serialNum = tbsCert.serialNum; 1448 certificate->_serialNumber = CFDataCreate(allocator, 1449 tbsCert.serialNum.data, tbsCert.serialNum.length); 1450 1451 /* sequence we're given: decode the tbsCerts TBS Signature Algorithm. */ 1452 drtn = DERParseSequenceContent(&tbsCert.tbsSigAlg, 1453 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, 1454 &certificate->_tbsSigAlg, sizeof(certificate->_tbsSigAlg)); 1455 require_noerr_quiet(drtn, badCert); 1456 1457 /* The issuer is in the tbsCert.issuer - it's a sequence without the tag 1458 and length fields. */ 1459 certificate->_issuer = tbsCert.issuer; 1460 certificate->_normalizedIssuer = createNormalizedX501Name(allocator, 1461 &tbsCert.issuer); 1462 1463 /* sequence we're given: decode the tbsCerts Validity sequence. */ 1464 DERValidity validity; 1465 drtn = DERParseSequenceContent(&tbsCert.validity, 1466 DERNumValidityItemSpecs, DERValidityItemSpecs, 1467 &validity, sizeof(validity)); 1468 require_noerr_quiet(drtn, badCert); 1469 require_quiet(derDateGetAbsoluteTime(&validity.notBefore, 1470 &certificate->_notBefore), badCert); 1471 require_quiet(derDateGetAbsoluteTime(&validity.notAfter, 1472 &certificate->_notAfter), badCert); 1473 1474 /* The subject is in the tbsCert.subject - it's a sequence without the tag 1475 and length fields. */ 1476 certificate->_subject = tbsCert.subject; 1477 certificate->_normalizedSubject = createNormalizedX501Name(allocator, 1478 &tbsCert.subject); 1479 1480 /* sequence we're given: encoded DERSubjPubKeyInfo */ 1481 DERSubjPubKeyInfo pubKeyInfo; 1482 drtn = DERParseSequenceContent(&tbsCert.subjectPubKey, 1483 DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs, 1484 &pubKeyInfo, sizeof(pubKeyInfo)); 1485 require_noerr_quiet(drtn, badCert); 1486 1487 /* sequence we're given: decode the pubKeyInfos DERAlgorithmId */ 1488 drtn = DERParseSequenceContent(&pubKeyInfo.algId, 1489 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, 1490 &certificate->_algId, sizeof(certificate->_algId)); 1491 require_noerr_quiet(drtn, badCert); 1492 1493 /* Now we can figure out the key's algorithm id and params based on 1494 certificate->_algId.oid. */ 1495 1496 /* The contents of pubKeyInfo.pubKey is a bit string whose contents 1497 are a PKCS1 format RSA key. */ 1498 drtn = DERParseBitString(&pubKeyInfo.pubKey, 1499 &certificate->_pubKeyDER, &numUnusedBits); 1500 require_noerr_quiet(drtn, badCert); 1501 1502 /* The contents of tbsCert.issuerID is a bit string. */ 1503 certificate->_issuerUniqueID = tbsCert.issuerID; 1504 1505 /* The contents of tbsCert.subjectID is a bit string. */ 1506 certificate->_subjectUniqueID = tbsCert.subjectID; 1507 1508 /* Extensions. */ 1509 if (tbsCert.extensions.length) { 1510 CFIndex extensionCount = 0; 1511 DERSequence derSeq; 1512 DERTag tag; 1513 drtn = DERDecodeSeqInit(&tbsCert.extensions, &tag, 1514 &derSeq); 1515 require_noerr_quiet(drtn, badCert); 1516 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badCert); 1517 DERDecodedInfo currDecoded; 1518 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) { 1519#if 0 1520/* ! = MUST recognize ? = SHOULD recognize 1521*/ 1522 1523 KnownExtension _subjectKeyID; /* ?SubjectKeyIdentifier id-ce 14 */ 1524 KnownExtension _keyUsage; /* !KeyUsage id-ce 15 */ 1525 KnownExtension _subjectAltName; /* !SubjectAltName id-ce 17 */ 1526 KnownExtension _basicConstraints; /* !BasicConstraints id-ce 19 */ 1527 KnownExtension _authorityKeyID; /* ?AuthorityKeyIdentifier id-ce 35 */ 1528 KnownExtension _extKeyUsage; /* !ExtKeyUsage id-ce 37 */ 1529 KnownExtension _netscapeCertType; /* 2.16.840.1.113730.1.1 netscape 1 1 */ 1530 KnownExtension _qualCertStatements; /* QCStatements id-pe 3 */ 1531 1532 KnownExtension _issuerAltName; /* IssuerAltName id-ce 18 */ 1533 KnownExtension _nameConstraints; /* !NameConstraints id-ce 30 */ 1534 KnownExtension _cRLDistributionPoints; /* CRLDistributionPoints id-ce 31 */ 1535 KnownExtension _certificatePolicies; /* !CertificatePolicies id-ce 32 */ 1536 KnownExtension _policyMappings; /* ?PolicyMappings id-ce 33 */ 1537 KnownExtension _policyConstraints; /* !PolicyConstraints id-ce 36 */ 1538 KnownExtension _freshestCRL; /* FreshestCRL id-ce 46 */ 1539 KnownExtension _inhibitAnyPolicy; /* !InhibitAnyPolicy id-ce 54 */ 1540 1541 KnownExtension _authorityInfoAccess; /* AuthorityInfoAccess id-pe 1 */ 1542 KnownExtension _subjectInfoAccess; /* SubjectInfoAccess id-pe 11 */ 1543#endif 1544 1545 extensionCount++; 1546 } 1547 require_quiet(drtn == DR_EndOfSequence, badCert); 1548 1549 /* Put some upper limit on the number of extensions allowed. */ 1550 require_quiet(extensionCount < 10000, badCert); 1551 certificate->_extensionCount = extensionCount; 1552 certificate->_extensions = 1553 malloc(sizeof(SecCertificateExtension) * (extensionCount > 0 ? extensionCount : 1)); 1554 1555 CFIndex ix = 0; 1556 drtn = DERDecodeSeqInit(&tbsCert.extensions, &tag, &derSeq); 1557 require_noerr_quiet(drtn, badCert); 1558 for (ix = 0; ix < extensionCount; ++ix) { 1559 drtn = DERDecodeSeqNext(&derSeq, &currDecoded); 1560 require_quiet(drtn == DR_Success || 1561 (ix == extensionCount - 1 && drtn == DR_EndOfSequence), badCert); 1562 require_quiet(currDecoded.tag == ASN1_CONSTR_SEQUENCE, badCert); 1563 DERExtension extn; 1564 drtn = DERParseSequenceContent(&currDecoded.content, 1565 DERNumExtensionItemSpecs, DERExtensionItemSpecs, 1566 &extn, sizeof(extn)); 1567 require_noerr_quiet(drtn, badCert); 1568 /* Copy stuff into certificate->extensions[ix]. */ 1569 certificate->_extensions[ix].extnID = extn.extnID; 1570 require_noerr_quiet(drtn = DERParseBoolean(&extn.critical, false, 1571 &certificate->_extensions[ix].critical), badCert); 1572 certificate->_extensions[ix].extnValue = extn.extnValue; 1573 1574 SecCertificateExtensionParser parser = 1575 (SecCertificateExtensionParser)CFDictionaryGetValue( 1576 sExtensionParsers, &certificate->_extensions[ix].extnID); 1577 if (parser) { 1578 /* Invoke the parser. */ 1579 parser(certificate, &certificate->_extensions[ix]); 1580 } else if (certificate->_extensions[ix].critical) { 1581 secdebug("cert", "Found unknown critical extension"); 1582 certificate->_foundUnknownCriticalExtension = true; 1583 } else { 1584 secdebug("cert", "Found unknown non critical extension"); 1585 } 1586 } 1587 } 1588 checkForMissingRevocationInfo(certificate); 1589 1590 return true; 1591 1592badCert: 1593 return false; 1594} 1595 1596 1597/* Public API functions. */ 1598SecCertificateRef SecCertificateCreateWithBytes(CFAllocatorRef allocator, 1599 const UInt8 *der_bytes, CFIndex der_length) { 1600 if (der_bytes == NULL) return NULL; 1601 if (der_length == 0) return NULL; 1602 1603 CFIndex size = sizeof(struct __SecCertificate) + der_length; 1604 SecCertificateRef result = (SecCertificateRef)_CFRuntimeCreateInstance( 1605 allocator, SecCertificateGetTypeID(), size - sizeof(CFRuntimeBase), 0); 1606 if (result) { 1607 memset((char*)result + sizeof(result->_base), 0, 1608 sizeof(*result) - sizeof(result->_base)); 1609 result->_der.data = ((DERByte *)result + sizeof(*result)); 1610 result->_der.length = der_length; 1611 memcpy(result->_der.data, der_bytes, der_length); 1612 if (!SecCertificateParse(result)) { 1613 CFRelease(result); 1614 return NULL; 1615 } 1616 } 1617 return result; 1618} 1619 1620/* @@@ Placeholder until <rdar://problem/5701851> iap submits a binary is fixed. */ 1621SecCertificateRef SecCertificateCreate(CFAllocatorRef allocator, 1622 const UInt8 *der_bytes, CFIndex der_length); 1623 1624SecCertificateRef SecCertificateCreate(CFAllocatorRef allocator, 1625 const UInt8 *der_bytes, CFIndex der_length) { 1626 return SecCertificateCreateWithBytes(allocator, der_bytes, der_length); 1627} 1628/* @@@ End of placeholder. */ 1629 1630/* AUDIT[securityd](done): 1631 der_certificate is a caller provided data of any length (might be 0), only 1632 its cf type has been checked. 1633 */ 1634SecCertificateRef SecCertificateCreateWithData(CFAllocatorRef allocator, 1635 CFDataRef der_certificate) { 1636 check(der_certificate); 1637 CFIndex size = sizeof(struct __SecCertificate); 1638 SecCertificateRef result = (SecCertificateRef)_CFRuntimeCreateInstance( 1639 allocator, SecCertificateGetTypeID(), size - sizeof(CFRuntimeBase), 0); 1640 if (result) { 1641 memset((char*)result + sizeof(result->_base), 0, size - sizeof(result->_base)); 1642 result->_der_data = CFDataCreateCopy(allocator, der_certificate); 1643 result->_der.data = (DERByte *)CFDataGetBytePtr(result->_der_data); 1644 result->_der.length = CFDataGetLength(result->_der_data); 1645 if (!SecCertificateParse(result)) { 1646 CFRelease(result); 1647 return NULL; 1648 } 1649 } 1650 return result; 1651} 1652 1653CFDataRef SecCertificateCopyData(SecCertificateRef certificate) { 1654 check(certificate); 1655 CFDataRef result; 1656 if (certificate->_der_data) { 1657 CFRetain(certificate->_der_data); 1658 result = certificate->_der_data; 1659 } else { 1660 result = CFDataCreate(CFGetAllocator(certificate), 1661 certificate->_der.data, certificate->_der.length); 1662#if 0 1663 /* FIXME: If we wish to cache result we need to lock the certificate. 1664 Also this create 2 copies of the certificate data which is somewhat 1665 suboptimal. */ 1666 CFRetain(result); 1667 certificate->_der_data = result; 1668#endif 1669 } 1670 1671 return result; 1672} 1673 1674CFIndex SecCertificateGetLength(SecCertificateRef certificate) { 1675 return certificate->_der.length; 1676} 1677 1678const UInt8 *SecCertificateGetBytePtr(SecCertificateRef certificate) { 1679 return certificate->_der.data; 1680} 1681 1682/* From rfc3280 - Appendix B. ASN.1 Notes 1683 1684 Object Identifiers (OIDs) are used throughout this specification to 1685 identify certificate policies, public key and signature algorithms, 1686 certificate extensions, etc. There is no maximum size for OIDs. 1687 This specification mandates support for OIDs which have arc elements 1688 with values that are less than 2^28, that is, they MUST be between 0 1689 and 268,435,455, inclusive. This allows each arc element to be 1690 represented within a single 32 bit word. Implementations MUST also 1691 support OIDs where the length of the dotted decimal (see [RFC 2252], 1692 section 4.1) string representation can be up to 100 bytes 1693 (inclusive). Implementations MUST be able to handle OIDs with up to 1694 20 elements (inclusive). CAs SHOULD NOT issue certificates which 1695 contain OIDs that exceed these requirements. Likewise, CRL issuers 1696 SHOULD NOT issue CRLs which contain OIDs that exceed these 1697 requirements. 1698*/ 1699 1700/* Oids longer than this are considered invalid. */ 1701#define MAX_OID_SIZE 32 1702 1703CFStringRef SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator, 1704 const DERItem *oid) { 1705 1706 if (oid->length == 0) { 1707 return SecCopyCertString(SEC_NULL_KEY); 1708 } 1709 if (oid->length > MAX_OID_SIZE) { 1710 return SecCopyCertString(SEC_OID_TOO_LONG_KEY); 1711 } 1712 1713 CFMutableStringRef result = CFStringCreateMutable(allocator, 0); 1714 1715 // The first two levels are encoded into one byte, since the root level 1716 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then 1717 // y may be > 39, so we have to add special-case handling for this. 1718 uint32_t x = oid->data[0] / 40; 1719 uint32_t y = oid->data[0] % 40; 1720 if (x > 2) 1721 { 1722 // Handle special case for large y if x = 2 1723 y += (x - 2) * 40; 1724 x = 2; 1725 } 1726 CFStringAppendFormat(result, NULL, CFSTR("%u.%u"), x, y); 1727 1728 uint32_t value = 0; 1729 for (x = 1; x < oid->length; ++x) 1730 { 1731 value = (value << 7) | (oid->data[x] & 0x7F); 1732 /* @@@ value may not span more than 4 bytes. */ 1733 /* A max number of 20 values is allowed. */ 1734 if (!(oid->data[x] & 0x80)) 1735 { 1736 CFStringAppendFormat(result, NULL, CFSTR(".%" PRIu32), value); 1737 value = 0; 1738 } 1739 } 1740 return result; 1741} 1742 1743static CFStringRef copyLocalizedOidDescription(CFAllocatorRef allocator, 1744 const DERItem *oid) { 1745 if (oid->length == 0) { 1746 return SecCopyCertString(SEC_NULL_KEY); 1747 } 1748 1749 /* Build the key we use to lookup the localized OID description. */ 1750 CFMutableStringRef oidKey = CFStringCreateMutable(allocator, 1751 oid->length * 3 + 5); 1752 CFStringAppendFormat(oidKey, NULL, CFSTR("06 %02lX"), oid->length); 1753 DERSize ix; 1754 for (ix = 0; ix < oid->length; ++ix) 1755 CFStringAppendFormat(oidKey, NULL, CFSTR(" %02X"), oid->data[ix]); 1756 1757 CFStringRef name = SecFrameworkCopyLocalizedString(oidKey, CFSTR("OID")); 1758 if (CFEqual(oidKey, name)) { 1759 CFRelease(name); 1760 name = SecDERItemCopyOIDDecimalRepresentation(allocator, oid); 1761 } 1762 CFRelease(oidKey); 1763 1764 return name; 1765} 1766 1767/* Return the ipAddress as a dotted quad for ipv4 or as 8 colon separated 1768 4 digit hex strings for ipv6. Return NULL if the passed in IP doesn't 1769 have a length of exactly 4 or 16 octects. */ 1770static CFStringRef copyIPAddressContentDescription(CFAllocatorRef allocator, 1771 const DERItem *ip) { 1772 /* @@@ This is the IP Address as an OCTECT STRING. For IPv4 it's 1773 4 octects addr, or 8 octects, addr/mask for ipv6 it's 1774 16 octects addr, or 32 octects addr/mask. */ 1775 CFStringRef value = NULL; 1776 if (ip->length == 4) { 1777 value = CFStringCreateWithFormat(allocator, NULL, 1778 CFSTR("%u.%u.%u.%u"), 1779 ip->data[0], ip->data[1], ip->data[2], ip->data[3]); 1780 } else if (ip->length == 16) { 1781 value = CFStringCreateWithFormat(allocator, NULL, 1782 CFSTR("%02x%02x:%02x%02x:%02x%02x:%02x%02x:" 1783 "%02x%02x:%02x%02x:%02x%02x:%02x%02x"), 1784 ip->data[0], ip->data[1], ip->data[2], ip->data[3], 1785 ip->data[4], ip->data[5], ip->data[6], ip->data[7], 1786 ip->data[8], ip->data[9], ip->data[10], ip->data[11], 1787 ip->data[12], ip->data[13], ip->data[14], ip->data[15]); 1788 } 1789 1790 return value; 1791} 1792 1793#if 0 1794static CFStringRef copyFullOidDescription(CFAllocatorRef allocator, 1795 const DERItem *oid) { 1796 CFStringRef decimal = SecDERItemCopyOIDDecimalRepresentation(allocator, oid); 1797 CFStringRef name = copyLocalizedOidDescription(allocator, oid); 1798 CFStringRef oid_string = CFStringCreateWithFormat(allocator, NULL, 1799 CFSTR("%@ (%@)"), name, decimal); 1800 CFRelease(name); 1801 CFRelease(decimal); 1802 return oid_string; 1803} 1804#endif 1805 1806void appendProperty(CFMutableArrayRef properties, CFStringRef propertyType, 1807 CFStringRef label, CFStringRef localizedLabel, CFTypeRef value) { 1808 CFDictionaryRef property; 1809 if (label) { 1810 CFStringRef ll; 1811 if (localizedLabel) { 1812 ll = NULL; 1813 } else { 1814 ll = localizedLabel = SecCopyCertString(label); 1815 } 1816 const void *all_keys[4]; 1817 all_keys[0] = kSecPropertyKeyType; 1818 all_keys[1] = kSecPropertyKeyLabel; 1819 all_keys[2] = kSecPropertyKeyLocalizedLabel; 1820 all_keys[3] = kSecPropertyKeyValue; 1821 const void *property_values[] = { 1822 propertyType, 1823 label, 1824 localizedLabel, 1825 value, 1826 }; 1827 property = CFDictionaryCreate(CFGetAllocator(properties), 1828 all_keys, property_values, value ? 4 : 3, 1829 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1830 CFReleaseSafe(ll); 1831 } else { 1832 const void *nolabel_keys[2]; 1833 nolabel_keys[0] = kSecPropertyKeyType; 1834 nolabel_keys[1] = kSecPropertyKeyValue; 1835 const void *property_values[] = { 1836 propertyType, 1837 value, 1838 }; 1839 property = CFDictionaryCreate(CFGetAllocator(properties), 1840 nolabel_keys, property_values, 2, 1841 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1842 } 1843 1844 CFArrayAppendValue(properties, property); 1845 CFRelease(property); 1846} 1847 1848/* YYMMDDhhmmZ */ 1849#define UTC_TIME_NOSEC_ZULU_LEN 11 1850/* YYMMDDhhmmssZ */ 1851#define UTC_TIME_ZULU_LEN 13 1852/* YYMMDDhhmmssThhmm */ 1853#define UTC_TIME_LOCALIZED_LEN 17 1854/* YYYYMMDDhhmmssZ */ 1855#define GENERALIZED_TIME_ZULU_LEN 15 1856/* YYYYMMDDhhmmssThhmm */ 1857#define GENERALIZED_TIME_LOCALIZED_LEN 19 1858 1859/* Parse 2 digits at (*p)[0] and (*p)[1] and return the result. Also 1860 advance *p by 2. */ 1861static inline int parseDecimalPair(const DERByte **p) { 1862 const DERByte *cp = *p; 1863 *p += 2; 1864 return 10 * (cp[0] - '0') + cp[1] - '0'; 1865} 1866 1867/* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return 1868 true if the date was valid and properly decoded, also return the result in 1869 absTime. Return false otherwise. */ 1870CFAbsoluteTime SecAbsoluteTimeFromDateContent(DERTag tag, const uint8_t *bytes, 1871 size_t length) { 1872 if (bytes == NULL) 1873 return NULL_TIME; 1874 if (length == 0) 1875 return NULL_TIME; 1876 1877 bool isUtcLength = false; 1878 bool isLocalized = false; 1879 bool noSeconds = false; 1880 switch (length) { 1881 case UTC_TIME_NOSEC_ZULU_LEN: /* YYMMDDhhmmZ */ 1882 isUtcLength = true; 1883 noSeconds = true; 1884 break; 1885 case UTC_TIME_ZULU_LEN: /* YYMMDDhhmmssZ */ 1886 isUtcLength = true; 1887 break; 1888 case GENERALIZED_TIME_ZULU_LEN: /* YYYYMMDDhhmmssZ */ 1889 break; 1890 case UTC_TIME_LOCALIZED_LEN: /* YYMMDDhhmmssThhmm (where T=[+,-]) */ 1891 isUtcLength = true; 1892 /*DROPTHROUGH*/ 1893 case GENERALIZED_TIME_LOCALIZED_LEN:/* YYYYMMDDhhmmssThhmm (where T=[+,-]) */ 1894 isLocalized = true; 1895 break; 1896 default: /* unknown format */ 1897 return NULL_TIME; 1898 } 1899 1900 /* Make sure the der tag fits the thing inside it. */ 1901 if (tag == ASN1_UTC_TIME) { 1902 if (!isUtcLength) 1903 return NULL_TIME; 1904 } else if (tag == ASN1_GENERALIZED_TIME) { 1905 if (isUtcLength) 1906 return NULL_TIME; 1907 } else { 1908 return NULL_TIME; 1909 } 1910 1911 const DERByte *cp = bytes; 1912 /* Check that all characters are digits, except if localized the timezone 1913 indicator or if not localized the 'Z' at the end. */ 1914 DERSize ix; 1915 for (ix = 0; ix < length; ++ix) { 1916 if (!(isdigit(cp[ix]))) { 1917 if ((isLocalized && ix == length - 5 && 1918 (cp[ix] == '+' || cp[ix] == '-')) || 1919 (!isLocalized && ix == length - 1 && cp[ix] == 'Z')) { 1920 continue; 1921 } 1922 return NULL_TIME; 1923 } 1924 } 1925 1926 /* Parse the date and time fields. */ 1927 int year, month, day, hour, minute, second; 1928 if (isUtcLength) { 1929 year = parseDecimalPair(&cp); 1930 if (year < 50) { 1931 /* 0 <= year < 50 : assume century 21 */ 1932 year += 2000; 1933 } else if (year < 70) { 1934 /* 50 <= year < 70 : illegal per PKIX */ 1935 return false; 1936 } else { 1937 /* 70 < year <= 99 : assume century 20 */ 1938 year += 1900; 1939 } 1940 } else { 1941 year = 100 * parseDecimalPair(&cp) + parseDecimalPair(&cp); 1942 } 1943 month = parseDecimalPair(&cp); 1944 day = parseDecimalPair(&cp); 1945 hour = parseDecimalPair(&cp); 1946 minute = parseDecimalPair(&cp); 1947 if (noSeconds) { 1948 second = 0; 1949 } else { 1950 second = parseDecimalPair(&cp); 1951 } 1952 1953 CFTimeInterval timeZoneOffset; 1954 if (isLocalized) { 1955 /* ZONE INDICATOR */ 1956 int multiplier = *cp++ == '+' ? 60 : -60; 1957 timeZoneOffset = multiplier * 1958 (parseDecimalPair(&cp) * 60 + parseDecimalPair(&cp)); 1959 } else { 1960 timeZoneOffset = 0; 1961 } 1962 1963 secdebug("dateparse", 1964 "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g", 1965 (int) length, bytes, year, month, 1966 day, hour, minute, second, 1967 timeZoneOffset / 60); 1968 1969 static int mdays[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; 1970 int is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) ? 1 : 0; 1971 if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59 1972 || (month == 2 && day > mdays[month] - mdays[month - 1] + is_leap_year) 1973 || (month != 2 && day > mdays[month] - mdays[month - 1])) { 1974 /* Invalid date. */ 1975 return NULL_TIME; 1976 } 1977 1978 int dy = year - 2001; 1979 if (dy < 0) { 1980 dy += 1; 1981 day -= 1; 1982 } 1983 int leap_days = dy / 4 - dy / 100 + dy / 400; 1984 day += ((year - 2001) * 365 + leap_days) + mdays[month - 1] - 1; 1985 if (month > 2) 1986 day += is_leap_year; 1987 1988 CFAbsoluteTime absTime = (CFAbsoluteTime)((day * 24 + hour) * 60 + minute) * 60 + second; 1989 return absTime - timeZoneOffset; 1990} 1991 1992__attribute__((__nonnull__)) static bool derDateContentGetAbsoluteTime(DERTag tag, const DERItem *date, 1993 CFAbsoluteTime *pabsTime) { 1994 CFAbsoluteTime absTime = SecAbsoluteTimeFromDateContent(tag, date->data, 1995 date->length); 1996 if (absTime == NULL_TIME) 1997 return false; 1998 1999 *pabsTime = absTime; 2000 return true; 2001} 2002 2003/* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return 2004 true if the date was valid and properly decoded, also return the result in 2005 absTime. Return false otherwise. */ 2006__attribute__((__nonnull__)) static bool derDateGetAbsoluteTime(const DERItem *dateChoice, 2007 CFAbsoluteTime *absTime) { 2008 if (dateChoice == NULL || dateChoice->length == 0) return false; 2009 if (absTime == NULL) return false; 2010 2011 DERDecodedInfo decoded; 2012 if (DERDecodeItem(dateChoice, &decoded)) 2013 return false; 2014 2015 return derDateContentGetAbsoluteTime(decoded.tag, &decoded.content, 2016 absTime); 2017} 2018 2019static void appendDataProperty(CFMutableArrayRef properties, 2020 CFStringRef label, CFStringRef localizedLabel, const DERItem *der_data) { 2021 CFDataRef data = CFDataCreate(CFGetAllocator(properties), 2022 der_data->data, der_data->length); 2023 appendProperty(properties, kSecPropertyTypeData, label, localizedLabel, 2024 data); 2025 CFRelease(data); 2026} 2027 2028static void appendRelabeledProperty(CFMutableArrayRef properties, 2029 CFStringRef label, 2030 CFStringRef localizedLabel, 2031 const DERItem *der_data, 2032 CFStringRef labelFormat) { 2033 CFStringRef newLabel = 2034 CFStringCreateWithFormat(CFGetAllocator(properties), NULL, 2035 labelFormat, label); 2036 CFStringRef ll; 2037 if (localizedLabel) { 2038 ll = NULL; 2039 } else { 2040 ll = localizedLabel = SecCopyCertString(label); 2041 } 2042 CFStringRef localizedLabelFormat = SecCopyCertString(labelFormat); 2043 CFStringRef newLocalizedLabel = 2044 CFStringCreateWithFormat(CFGetAllocator(properties), NULL, 2045 localizedLabelFormat, localizedLabel); 2046 CFReleaseSafe(ll); 2047 CFReleaseSafe(localizedLabelFormat); 2048 appendDataProperty(properties, newLabel, newLocalizedLabel, der_data); 2049 CFReleaseSafe(newLabel); 2050 CFReleaseSafe(newLocalizedLabel); 2051} 2052 2053 2054static void appendUnparsedProperty(CFMutableArrayRef properties, 2055 CFStringRef label, CFStringRef localizedLabel, const DERItem *der_data) { 2056 appendRelabeledProperty(properties, label, localizedLabel, der_data, 2057 SEC_UNPARSED_KEY); 2058} 2059 2060static void appendInvalidProperty(CFMutableArrayRef properties, 2061 CFStringRef label, const DERItem *der_data) { 2062 appendRelabeledProperty(properties, label, NULL, der_data, SEC_INVALID_KEY); 2063} 2064 2065static void appendDateContentProperty(CFMutableArrayRef properties, 2066 CFStringRef label, DERTag tag, 2067 const DERItem *dateContent) { 2068 CFAbsoluteTime absTime; 2069 if (!derDateContentGetAbsoluteTime(tag, dateContent, &absTime)) { 2070 /* Date decode failure insert hex bytes instead. */ 2071 return appendInvalidProperty(properties, label, dateContent); 2072 } 2073 CFDateRef date = CFDateCreate(CFGetAllocator(properties), absTime); 2074 appendProperty(properties, kSecPropertyTypeDate, label, NULL, date); 2075 CFRelease(date); 2076} 2077 2078static void appendDateProperty(CFMutableArrayRef properties, 2079 CFStringRef label, CFAbsoluteTime absTime) { 2080 CFDateRef date = CFDateCreate(CFGetAllocator(properties), absTime); 2081 appendProperty(properties, kSecPropertyTypeDate, label, NULL, date); 2082 CFRelease(date); 2083} 2084 2085static void appendIPAddressContentProperty(CFMutableArrayRef properties, 2086 CFStringRef label, const DERItem *ip) { 2087 CFStringRef value = 2088 copyIPAddressContentDescription(CFGetAllocator(properties), ip); 2089 if (value) { 2090 appendProperty(properties, kSecPropertyTypeString, label, NULL, value); 2091 CFRelease(value); 2092 } else { 2093 appendUnparsedProperty(properties, label, NULL, ip); 2094 } 2095} 2096 2097static void appendURLContentProperty(CFMutableArrayRef properties, 2098 CFStringRef label, const DERItem *urlContent) { 2099 CFURLRef url = CFURLCreateWithBytes(CFGetAllocator(properties), 2100 urlContent->data, urlContent->length, kCFStringEncodingASCII, NULL); 2101 if (url) { 2102 appendProperty(properties, kSecPropertyTypeURL, label, NULL, url); 2103 CFRelease(url); 2104 } else { 2105 appendInvalidProperty(properties, label, urlContent); 2106 } 2107} 2108 2109static void appendURLProperty(CFMutableArrayRef properties, 2110 CFStringRef label, const DERItem *url) { 2111 DERDecodedInfo decoded; 2112 DERReturn drtn; 2113 2114 drtn = DERDecodeItem(url, &decoded); 2115 if (drtn || decoded.tag != ASN1_IA5_STRING) { 2116 appendInvalidProperty(properties, label, url); 2117 } else { 2118 appendURLContentProperty(properties, label, &decoded.content); 2119 } 2120} 2121 2122static void appendOIDProperty(CFMutableArrayRef properties, 2123 CFStringRef label, CFStringRef llabel, const DERItem *oid) { 2124 CFStringRef oid_string = 2125 copyLocalizedOidDescription(CFGetAllocator(properties), oid); 2126 appendProperty(properties, kSecPropertyTypeString, label, llabel, 2127 oid_string); 2128 CFRelease(oid_string); 2129} 2130 2131static void appendAlgorithmProperty(CFMutableArrayRef properties, 2132 CFStringRef label, const DERAlgorithmId *algorithm) { 2133 CFMutableArrayRef alg_props = 2134 CFArrayCreateMutable(CFGetAllocator(properties), 0, 2135 &kCFTypeArrayCallBacks); 2136 appendOIDProperty(alg_props, SEC_ALGORITHM_KEY, NULL, &algorithm->oid); 2137 if (algorithm->params.length) { 2138 if (algorithm->params.length == 2 && 2139 algorithm->params.data[0] == ASN1_NULL && 2140 algorithm->params.data[1] == 0) { 2141 CFStringRef value = SecCopyCertString(SEC_NONE_KEY); 2142 appendProperty(alg_props, kSecPropertyTypeString, 2143 SEC_PARAMETERS_KEY, NULL, value); 2144 CFRelease(value); 2145 } else { 2146 appendUnparsedProperty(alg_props, SEC_PARAMETERS_KEY, NULL, 2147 &algorithm->params); 2148 } 2149 } 2150 appendProperty(properties, kSecPropertyTypeSection, label, NULL, alg_props); 2151 CFRelease(alg_props); 2152} 2153 2154static CFStringRef copyHexDescription(CFAllocatorRef allocator, 2155 const DERItem *blob) { 2156 CFIndex ix, length = blob->length /* < 24 ? blob->length : 24 */; 2157 CFMutableStringRef string = CFStringCreateMutable(allocator, 2158 blob->length * 3 - 1); 2159 for (ix = 0; ix < length; ++ix) 2160 if (ix == 0) 2161 CFStringAppendFormat(string, NULL, CFSTR("%02X"), blob->data[ix]); 2162 else 2163 CFStringAppendFormat(string, NULL, CFSTR(" %02X"), blob->data[ix]); 2164 2165 return string; 2166} 2167 2168/* Returns a (localized) blob string. */ 2169static CFStringRef copyBlobString(CFAllocatorRef allocator, 2170 CFStringRef blobType, CFStringRef quanta, const DERItem *blob) { 2171 CFStringRef localizedBlobType = SecCopyCertString(blobType); 2172 CFStringRef localizedQuanta = SecCopyCertString(quanta); 2173 /* "format string for encoded field data (e.g. Sequence; 128 bytes; " 2174 "data = 00 00 ...)" */ 2175 CFStringRef blobFormat = SecCopyCertString(SEC_BLOB_KEY); 2176 CFStringRef hex = copyHexDescription(allocator, blob); 2177 CFStringRef result = CFStringCreateWithFormat(allocator, NULL, 2178 blobFormat, localizedBlobType, blob->length, localizedQuanta, hex); 2179 CFRelease(hex); 2180 CFRelease(blobFormat); 2181 CFReleaseSafe(localizedQuanta); 2182 CFReleaseSafe(localizedBlobType); 2183 2184 return result; 2185} 2186 2187/* Return a string verbatim (unlocalized) from a DER field. */ 2188static CFStringRef copyContentString(CFAllocatorRef allocator, 2189 const DERItem *string, CFStringEncoding encoding, 2190 bool printableOnly) { 2191 /* Strip potential bogus trailing zero from printable strings. */ 2192 DERSize length = string->length; 2193 if (length && string->data[length - 1] == 0) { 2194 /* Don't mess with the length of UTF16 strings though. */ 2195 if (encoding != kCFStringEncodingUTF16) 2196 length--; 2197 } 2198 /* A zero length string isn't considered printable. */ 2199 if (!length && printableOnly) 2200 return NULL; 2201 2202 /* Passing true for the 5th paramater to CFStringCreateWithBytes() makes 2203 it treat kCFStringEncodingUTF16 as big endian by default, whereas 2204 passing false makes it treat it as native endian by default. */ 2205 CFStringRef result = CFStringCreateWithBytes(allocator, string->data, 2206 length, encoding, encoding == kCFStringEncodingUTF16); 2207 if (result) 2208 return result; 2209 2210 return printableOnly ? NULL : copyHexDescription(allocator, string); 2211} 2212 2213/* From rfc3280 - Appendix B. ASN.1 Notes 2214 2215 CAs MUST force the serialNumber to be a non-negative integer, that 2216 is, the sign bit in the DER encoding of the INTEGER value MUST be 2217 zero - this can be done by adding a leading (leftmost) `00'H octet if 2218 necessary. This removes a potential ambiguity in mapping between a 2219 string of octets and an integer value. 2220 2221 As noted in section 4.1.2.2, serial numbers can be expected to 2222 contain long integers. Certificate users MUST be able to handle 2223 serialNumber values up to 20 octets in length. Conformant CAs MUST 2224 NOT use serialNumber values longer than 20 octets. 2225*/ 2226 2227/* Return the given numeric data as a string: decimal up to 64 bits, 2228 hex otherwise. */ 2229static CFStringRef copyIntegerContentDescription(CFAllocatorRef allocator, 2230 const DERItem *integer) { 2231 uint64_t value = 0; 2232 CFIndex ix, length = integer->length; 2233 2234 if (length == 0 || length > 8) 2235 return copyHexDescription(allocator, integer); 2236 2237 for(ix = 0; ix < length; ++ix) { 2238 value <<= 8; 2239 value += integer->data[ix]; 2240 } 2241 2242 return CFStringCreateWithFormat(allocator, NULL, CFSTR("%llu"), value); 2243} 2244 2245static CFStringRef copyDERThingContentDescription(CFAllocatorRef allocator, 2246 DERTag tag, const DERItem *derThing, bool printableOnly) { 2247 switch(tag) { 2248 case ASN1_INTEGER: 2249 case ASN1_BOOLEAN: 2250 return printableOnly ? NULL : copyIntegerContentDescription(allocator, derThing); 2251 case ASN1_PRINTABLE_STRING: 2252 case ASN1_IA5_STRING: 2253 return copyContentString(allocator, derThing, kCFStringEncodingASCII, printableOnly); 2254 case ASN1_UTF8_STRING: 2255 case ASN1_GENERAL_STRING: 2256 case ASN1_UNIVERSAL_STRING: 2257 return copyContentString(allocator, derThing, kCFStringEncodingUTF8, printableOnly); 2258 case ASN1_T61_STRING: // 20, also BER_TAG_TELETEX_STRING 2259 case ASN1_VIDEOTEX_STRING: // 21 2260 case ASN1_VISIBLE_STRING: // 26 2261 return copyContentString(allocator, derThing, kCFStringEncodingISOLatin1, printableOnly); 2262 case ASN1_BMP_STRING: // 30 2263 return copyContentString(allocator, derThing, kCFStringEncodingUTF16, printableOnly); 2264 case ASN1_OCTET_STRING: 2265 return printableOnly ? NULL : 2266 copyBlobString(allocator, SEC_BYTE_STRING_KEY, SEC_BYTES_KEY, 2267 derThing); 2268 //return copyBlobString(BYTE_STRING_STR, BYTES_STR, derThing); 2269 case ASN1_BIT_STRING: 2270 return printableOnly ? NULL : 2271 copyBlobString(allocator, SEC_BIT_STRING_KEY, SEC_BITS_KEY, 2272 derThing); 2273 case ASN1_CONSTR_SEQUENCE: 2274 return printableOnly ? NULL : 2275 copyBlobString(allocator, SEC_SEQUENCE_KEY, SEC_BYTES_KEY, 2276 derThing); 2277 case ASN1_CONSTR_SET: 2278 return printableOnly ? NULL : 2279 copyBlobString(allocator, SEC_SET_KEY, SEC_BYTES_KEY, derThing); 2280 case ASN1_OBJECT_ID: 2281 return printableOnly ? NULL : copyLocalizedOidDescription(allocator, derThing); 2282 default: 2283 if (printableOnly) { 2284 return NULL; 2285 } else { 2286 CFStringRef fmt = SecCopyCertString(SEC_NOT_DISPLAYED_KEY); 2287 CFStringRef result = CFStringCreateWithFormat(allocator, NULL, fmt, 2288 tag, derThing->length); 2289 CFRelease(fmt); 2290 return result; 2291 } 2292 } 2293} 2294 2295static CFStringRef copyDERThingDescription(CFAllocatorRef allocator, 2296 const DERItem *derThing, bool printableOnly) { 2297 DERDecodedInfo decoded; 2298 DERReturn drtn; 2299 2300 drtn = DERDecodeItem(derThing, &decoded); 2301 if (drtn) { 2302 /* TODO: Perhaps put something in the label saying we couldn't parse 2303 the DER? */ 2304 return printableOnly ? NULL : copyHexDescription(allocator, derThing); 2305 } else { 2306 return copyDERThingContentDescription(allocator, decoded.tag, 2307 &decoded.content, false); 2308 } 2309} 2310 2311static void appendDERThingProperty(CFMutableArrayRef properties, 2312 CFStringRef label, CFStringRef localizedLabel, const DERItem *derThing) { 2313 CFStringRef value = copyDERThingDescription(CFGetAllocator(properties), 2314 derThing, false); 2315 appendProperty(properties, kSecPropertyTypeString, label, localizedLabel, 2316 value); 2317 CFRelease(value); 2318} 2319 2320static OSStatus appendRDNProperty(void *context, const DERItem *rdnType, 2321 const DERItem *rdnValue, CFIndex rdnIX) { 2322 CFMutableArrayRef properties = (CFMutableArrayRef)context; 2323 if (rdnIX > 0) { 2324 /* If there is more than one value pair we create a subsection for the 2325 second pair, and append things to the subsection for subsequent 2326 pairs. */ 2327 CFIndex lastIX = CFArrayGetCount(properties) - 1; 2328 CFTypeRef lastValue = CFArrayGetValueAtIndex(properties, lastIX); 2329 if (rdnIX == 1) { 2330 /* Since this is the second rdn pair for a given rdn, we setup a 2331 new subsection for this rdn. We remove the first property 2332 from the properties array and make it the first element in the 2333 subsection instead. */ 2334 CFMutableArrayRef rdn_props = CFArrayCreateMutable( 2335 CFGetAllocator(properties), 0, &kCFTypeArrayCallBacks); 2336 CFArrayAppendValue(rdn_props, lastValue); 2337 CFArrayRemoveValueAtIndex(properties, lastIX); 2338 appendProperty(properties, kSecPropertyTypeSection, NULL, NULL, 2339 rdn_props); 2340 properties = rdn_props; 2341 } else { 2342 /* Since this is the third or later rdn pair we have already 2343 created a subsection in the top level properties array. Instead 2344 of appending to that directly we append to the array inside the 2345 subsection. */ 2346 properties = (CFMutableArrayRef)CFDictionaryGetValue( 2347 (CFDictionaryRef)lastValue, kSecPropertyKeyValue); 2348 } 2349 } 2350 2351 /* Finally we append the new rdn value to the property array. */ 2352 CFStringRef label = SecDERItemCopyOIDDecimalRepresentation( 2353 CFGetAllocator(properties), rdnType); 2354 CFStringRef localizedLabel = 2355 copyLocalizedOidDescription(CFGetAllocator(properties), rdnType); 2356 appendDERThingProperty(properties, label, localizedLabel, rdnValue); 2357 CFRelease(label); 2358 CFRelease(localizedLabel); 2359 return errSecSuccess; 2360} 2361 2362static CFArrayRef createPropertiesForRDNContent(CFAllocatorRef allocator, 2363 const DERItem *rdnSetContent) { 2364 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, 2365 &kCFTypeArrayCallBacks); 2366 OSStatus status = parseRDNContent(rdnSetContent, properties, 2367 appendRDNProperty); 2368 if (status) { 2369 CFArrayRemoveAllValues(properties); 2370 appendInvalidProperty(properties, SEC_RDN_KEY, rdnSetContent); 2371 } 2372 2373 return properties; 2374} 2375 2376/* 2377 From rfc3739 - 3.1.2. Subject 2378 2379 When parsing the subject here are some tips for a short name of the cert. 2380 Choice I: commonName 2381 Choice II: givenName 2382 Choice III: pseudonym 2383 2384 The commonName attribute value SHALL, when present, contain a name 2385 of the subject. This MAY be in the subject's preferred 2386 presentation format, or a format preferred by the CA, or some 2387 other format. Pseudonyms, nicknames, and names with spelling 2388 other than defined by the registered name MAY be used. To 2389 understand the nature of the name presented in commonName, 2390 complying applications MAY have to examine present values of the 2391 givenName and surname attributes, or the pseudonym attribute. 2392 2393*/ 2394static CFArrayRef createPropertiesForX501NameContent(CFAllocatorRef allocator, 2395 const DERItem *x501NameContent) { 2396 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, 2397 &kCFTypeArrayCallBacks); 2398 OSStatus status = parseX501NameContent(x501NameContent, properties, 2399 appendRDNProperty); 2400 if (status) { 2401 CFArrayRemoveAllValues(properties); 2402 appendInvalidProperty(properties, SEC_X501_NAME_KEY, x501NameContent); 2403 } 2404 2405 return properties; 2406} 2407 2408static CFArrayRef createPropertiesForX501Name(CFAllocatorRef allocator, 2409 const DERItem *x501Name) { 2410 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, 2411 &kCFTypeArrayCallBacks); 2412 OSStatus status = parseX501Name(x501Name, properties, appendRDNProperty); 2413 if (status) { 2414 CFArrayRemoveAllValues(properties); 2415 appendInvalidProperty(properties, SEC_X501_NAME_KEY, x501Name); 2416 } 2417 2418 return properties; 2419} 2420 2421static void appendIntegerProperty(CFMutableArrayRef properties, 2422 CFStringRef label, const DERItem *integer) { 2423 CFStringRef string = copyIntegerContentDescription( 2424 CFGetAllocator(properties), integer); 2425 appendProperty(properties, kSecPropertyTypeString, label, NULL, string); 2426 CFRelease(string); 2427} 2428 2429static void appendBoolProperty(CFMutableArrayRef properties, 2430 CFStringRef label, bool boolean) { 2431 CFStringRef value = SecCopyCertString(boolean ? SEC_YES_KEY : SEC_NO_KEY); 2432 appendProperty(properties, kSecPropertyTypeString, label, NULL, value); 2433 CFRelease(value); 2434} 2435 2436static void appendBooleanProperty(CFMutableArrayRef properties, 2437 CFStringRef label, const DERItem *boolean, bool defaultValue) { 2438 bool result; 2439 DERReturn drtn = DERParseBoolean(boolean, defaultValue, &result); 2440 if (drtn) { 2441 /* Couldn't parse boolean; dump the raw unparsed data as hex. */ 2442 appendInvalidProperty(properties, label, boolean); 2443 } else { 2444 appendBoolProperty(properties, label, result); 2445 } 2446} 2447 2448static void appendBitStringContentNames(CFMutableArrayRef properties, 2449 CFStringRef label, const DERItem *bitStringContent, 2450 const CFStringRef *names, CFIndex namesCount) { 2451 DERSize len = bitStringContent->length - 1; 2452 require_quiet(len == 1 || len == 2, badDER); 2453 DERByte numUnusedBits = bitStringContent->data[0]; 2454 require_quiet(numUnusedBits < 8, badDER); 2455 uint_fast16_t bits = 8 * len - numUnusedBits; 2456 require_quiet(bits <= (uint_fast16_t)namesCount, badDER); 2457 uint_fast16_t value = bitStringContent->data[1]; 2458 uint_fast16_t mask; 2459 if (len > 1) { 2460 value = (value << 8) + bitStringContent->data[2]; 2461 mask = 0x8000; 2462 } else { 2463 mask = 0x80; 2464 } 2465 uint_fast16_t ix; 2466 CFStringRef fmt = SecCopyCertString(SEC_STRING_LIST_KEY); 2467 CFStringRef string = NULL; 2468 for (ix = 0; ix < bits; ++ix) { 2469 if (value & mask) { 2470 if (string) { 2471 CFStringRef s = 2472 CFStringCreateWithFormat(CFGetAllocator(properties), 2473 NULL, fmt, string, names[ix]); 2474 CFRelease(string); 2475 string = s; 2476 } else { 2477 string = names[ix]; 2478 CFRetain(string); 2479 } 2480 } 2481 mask >>= 1; 2482 } 2483 CFRelease(fmt); 2484 appendProperty(properties, kSecPropertyTypeString, label, NULL, 2485 string ? string : CFSTR("")); 2486 CFReleaseSafe(string); 2487 return; 2488badDER: 2489 appendInvalidProperty(properties, label, bitStringContent); 2490} 2491 2492static void appendBitStringNames(CFMutableArrayRef properties, 2493 CFStringRef label, const DERItem *bitString, 2494 const CFStringRef *names, CFIndex namesCount) { 2495 DERDecodedInfo bitStringContent; 2496 DERReturn drtn = DERDecodeItem(bitString, &bitStringContent); 2497 require_noerr_quiet(drtn, badDER); 2498 require_quiet(bitStringContent.tag == ASN1_BIT_STRING, badDER); 2499 appendBitStringContentNames(properties, label, &bitStringContent.content, 2500 names, namesCount); 2501 return; 2502badDER: 2503 appendInvalidProperty(properties, label, bitString); 2504} 2505 2506#if 0 2507typedef uint16_t SecKeyUsage; 2508 2509#define kSecKeyUsageDigitalSignature 0x8000 2510#define kSecKeyUsageNonRepudiation 0x4000 2511#define kSecKeyUsageKeyEncipherment 0x2000 2512#define kSecKeyUsageDataEncipherment 0x1000 2513#define kSecKeyUsageKeyAgreement 0x0800 2514#define kSecKeyUsageKeyCertSign 0x0400 2515#define kSecKeyUsageCRLSign 0x0200 2516#define kSecKeyUsageEncipherOnly 0x0100 2517#define kSecKeyUsageDecipherOnly 0x0080 2518 2519/* 2520 KeyUsage ::= BIT STRING { 2521 digitalSignature (0), 2522 nonRepudiation (1), 2523 keyEncipherment (2), 2524 dataEncipherment (3), 2525 keyAgreement (4), 2526 keyCertSign (5), 2527 cRLSign (6), 2528 encipherOnly (7), 2529 decipherOnly (8) } 2530 */ 2531static void appendKeyUsage(CFMutableArrayRef properties, 2532 const DERItem *extnValue) { 2533 if ((extnValue->length != 4 && extnValue->length != 5) || 2534 extnValue->data[0] != ASN1_BIT_STRING || 2535 extnValue->data[1] < 2 || extnValue->data[1] > 3 || 2536 extnValue->data[2] > 7) { 2537 appendInvalidProperty(properties, CFSTR("KeyUsage Extension"), 2538 extnValue); 2539 } else { 2540 CFMutableStringRef string = 2541 CFStringCreateMutable(CFGetAllocator(properties), 0); 2542 SecKeyUsage usage = (extnValue->data[3] << 8); 2543 if (extnValue->length == 5) 2544 usage += extnValue->data[4]; 2545 secdebug("keyusage", "keyusage: %04X", usage); 2546 static const CFStringRef usageNames[] = { 2547 CFSTR("Digital Signature"), 2548 CFSTR("Non-Repudiation"), 2549 CFSTR("Key Encipherment"), 2550 CFSTR("Data Encipherment"), 2551 CFSTR("Key Agreement"), 2552 CFSTR("Cert Sign"), 2553 CFSTR("CRL Sign"), 2554 CFSTR("Encipher"), 2555 CFSTR("Decipher"), 2556 }; 2557 bool didOne = false; 2558 SecKeyUsage mask = kSecKeyUsageDigitalSignature; 2559 CFIndex ix, bits = (extnValue->data[1] - 1) * 8 - extnValue->data[2]; 2560 for (ix = 0; ix < bits; ++ix) { 2561 if (usage & mask) { 2562 if (didOne) { 2563 CFStringAppend(string, CFSTR(", ")); 2564 } else { 2565 didOne = true; 2566 } 2567 /* @@@ Localize usageNames[ix]. */ 2568 CFStringAppend(string, usageNames[ix]); 2569 } 2570 mask >>= 1; 2571 } 2572 appendProperty(properties, kSecPropertyTypeString, CFSTR("Usage"), 2573 string); 2574 CFRelease(string); 2575 } 2576} 2577#else 2578static void appendKeyUsage(CFMutableArrayRef properties, 2579 const DERItem *extnValue) { 2580 static const CFStringRef usageNames[] = { 2581 SEC_DIGITAL_SIGNATURE_KEY, 2582 SEC_NON_REPUDIATION_KEY, 2583 SEC_KEY_ENCIPHERMENT_KEY, 2584 SEC_DATA_ENCIPHERMENT_KEY, 2585 SEC_KEY_AGREEMENT_KEY, 2586 SEC_CERT_SIGN_KEY, 2587 SEC_CRL_SIGN_KEY, 2588 SEC_ENCIPHER_ONLY_KEY, 2589 SEC_DECIPHER_ONLY_KEY 2590 }; 2591 appendBitStringNames(properties, SEC_USAGE_KEY, extnValue, 2592 usageNames, array_size(usageNames)); 2593} 2594#endif 2595 2596static void appendPrivateKeyUsagePeriod(CFMutableArrayRef properties, 2597 const DERItem *extnValue) { 2598 DERPrivateKeyUsagePeriod pkup; 2599 DERReturn drtn = DERParseSequence(extnValue, 2600 DERNumPrivateKeyUsagePeriodItemSpecs, DERPrivateKeyUsagePeriodItemSpecs, 2601 &pkup, sizeof(pkup)); 2602 require_noerr_quiet(drtn, badDER); 2603 if (pkup.notBefore.length) { 2604 appendDateContentProperty(properties, SEC_NOT_VALID_BEFORE_KEY, 2605 ASN1_GENERALIZED_TIME, &pkup.notBefore); 2606 } 2607 if (pkup.notAfter.length) { 2608 appendDateContentProperty(properties, SEC_NOT_VALID_AFTER_KEY, 2609 ASN1_GENERALIZED_TIME, &pkup.notAfter); 2610 } 2611 return; 2612badDER: 2613 appendInvalidProperty(properties, SEC_PRIVATE_KU_PERIOD_KEY, extnValue); 2614} 2615 2616static void appendStringContentProperty(CFMutableArrayRef properties, 2617 CFStringRef label, const DERItem *stringContent, 2618 CFStringEncoding encoding) { 2619 CFStringRef string = CFStringCreateWithBytes(CFGetAllocator(properties), 2620 stringContent->data, stringContent->length, encoding, FALSE); 2621 if (string) { 2622 appendProperty(properties, kSecPropertyTypeString, label, NULL, string); 2623 CFRelease(string); 2624 } else { 2625 appendInvalidProperty(properties, label, stringContent); 2626 } 2627} 2628 2629/* 2630 OtherName ::= SEQUENCE { 2631 type-id OBJECT IDENTIFIER, 2632 value [0] EXPLICIT ANY DEFINED BY type-id } 2633*/ 2634static void appendOtherNameContentProperty(CFMutableArrayRef properties, 2635 const DERItem *otherNameContent) { 2636 DEROtherName on; 2637 DERReturn drtn = DERParseSequenceContent(otherNameContent, 2638 DERNumOtherNameItemSpecs, DEROtherNameItemSpecs, 2639 &on, sizeof(on)); 2640 require_noerr_quiet(drtn, badDER); 2641 CFAllocatorRef allocator = CFGetAllocator(properties); 2642 CFStringRef label = 2643 SecDERItemCopyOIDDecimalRepresentation(allocator, &on.typeIdentifier); 2644 CFStringRef localizedLabel = 2645 copyLocalizedOidDescription(allocator, &on.typeIdentifier); 2646 CFStringRef value_string = copyDERThingDescription(allocator, &on.value, false); 2647 if (value_string) 2648 appendProperty(properties, kSecPropertyTypeString, label, 2649 localizedLabel, value_string); 2650 else 2651 appendUnparsedProperty(properties, label, localizedLabel, &on.value); 2652 2653 CFReleaseSafe(value_string); 2654 CFReleaseSafe(label); 2655 CFReleaseSafe(localizedLabel); 2656 return; 2657badDER: 2658 appendInvalidProperty(properties, SEC_OTHER_NAME_KEY, otherNameContent); 2659} 2660 2661/* 2662 GeneralName ::= CHOICE { 2663 otherName [0] OtherName, 2664 rfc822Name [1] IA5String, 2665 dNSName [2] IA5String, 2666 x400Address [3] ORAddress, 2667 directoryName [4] Name, 2668 ediPartyName [5] EDIPartyName, 2669 uniformResourceIdentifier [6] IA5String, 2670 iPAddress [7] OCTET STRING, 2671 registeredID [8] OBJECT IDENTIFIER} 2672 2673 EDIPartyName ::= SEQUENCE { 2674 nameAssigner [0] DirectoryString OPTIONAL, 2675 partyName [1] DirectoryString } 2676 */ 2677static bool appendGeneralNameContentProperty(CFMutableArrayRef properties, 2678 DERTag tag, const DERItem *generalName) { 2679 switch (tag) { 2680 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0: 2681 appendOtherNameContentProperty(properties, generalName); 2682 break; 2683 case ASN1_CONTEXT_SPECIFIC | 1: 2684 /* IA5String. */ 2685 appendStringContentProperty(properties, SEC_EMAIL_ADDRESS_KEY, 2686 generalName, kCFStringEncodingASCII); 2687 break; 2688 case ASN1_CONTEXT_SPECIFIC | 2: 2689 /* IA5String. */ 2690 appendStringContentProperty(properties, SEC_DNS_NAME_KEY, generalName, 2691 kCFStringEncodingASCII); 2692 break; 2693 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3: 2694 appendUnparsedProperty(properties, SEC_X400_ADDRESS_KEY, NULL, 2695 generalName); 2696 break; 2697 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4: 2698 { 2699 CFArrayRef directory_plist = 2700 createPropertiesForX501Name(CFGetAllocator(properties), 2701 generalName); 2702 appendProperty(properties, kSecPropertyTypeSection, 2703 SEC_DIRECTORY_NAME_KEY, NULL, directory_plist); 2704 CFRelease(directory_plist); 2705 break; 2706 } 2707 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5: 2708 appendUnparsedProperty(properties, SEC_EDI_PARTY_NAME_KEY, NULL, 2709 generalName); 2710 break; 2711 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6: 2712 /* Technically I don't think this is valid, but there are certs out 2713 in the wild that use a constructed IA5String. In particular the 2714 VeriSign Time Stamping Authority CA.cer does this. */ 2715 appendURLProperty(properties, SEC_URI_KEY, generalName); 2716 break; 2717 case ASN1_CONTEXT_SPECIFIC | 6: 2718 appendURLContentProperty(properties, SEC_URI_KEY, generalName); 2719 break; 2720 case ASN1_CONTEXT_SPECIFIC | 7: 2721 appendIPAddressContentProperty(properties, SEC_IP_ADDRESS_KEY, 2722 generalName); 2723 break; 2724 case ASN1_CONTEXT_SPECIFIC | 8: 2725 appendOIDProperty(properties, SEC_REGISTERED_ID_KEY, NULL, generalName); 2726 break; 2727 default: 2728 goto badDER; 2729 break; 2730 } 2731 return true; 2732badDER: 2733 return false; 2734} 2735 2736static void appendGeneralNameProperty(CFMutableArrayRef properties, 2737 const DERItem *generalName) { 2738 DERDecodedInfo generalNameContent; 2739 DERReturn drtn = DERDecodeItem(generalName, &generalNameContent); 2740 require_noerr_quiet(drtn, badDER); 2741 if (appendGeneralNameContentProperty(properties, generalNameContent.tag, 2742 &generalNameContent.content)) 2743 return; 2744badDER: 2745 appendInvalidProperty(properties, SEC_GENERAL_NAME_KEY, generalName); 2746} 2747 2748 2749/* 2750 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 2751 */ 2752static void appendGeneralNamesContent(CFMutableArrayRef properties, 2753 const DERItem *generalNamesContent) { 2754 DERSequence gnSeq; 2755 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq); 2756 require_noerr_quiet(drtn, badDER); 2757 DERDecodedInfo generalNameContent; 2758 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) == 2759 DR_Success) { 2760 if (!appendGeneralNameContentProperty(properties, 2761 generalNameContent.tag, &generalNameContent.content)) { 2762 goto badDER; 2763 } 2764 } 2765 require_quiet(drtn == DR_EndOfSequence, badDER); 2766 return; 2767badDER: 2768 appendInvalidProperty(properties, SEC_GENERAL_NAMES_KEY, 2769 generalNamesContent); 2770} 2771 2772static void appendGeneralNames(CFMutableArrayRef properties, 2773 const DERItem *generalNames) { 2774 DERDecodedInfo generalNamesContent; 2775 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent); 2776 require_noerr_quiet(drtn, badDER); 2777 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE, 2778 badDER); 2779 appendGeneralNamesContent(properties, &generalNamesContent.content); 2780 return; 2781badDER: 2782 appendInvalidProperty(properties, SEC_GENERAL_NAMES_KEY, generalNames); 2783} 2784 2785/* 2786BasicConstraints ::= SEQUENCE { 2787 cA BOOLEAN DEFAULT FALSE, 2788 pathLenConstraint INTEGER (0..MAX) OPTIONAL } 2789*/ 2790static void appendBasicConstraints(CFMutableArrayRef properties, 2791 const DERItem *extnValue) { 2792 DERBasicConstraints basicConstraints; 2793 DERReturn drtn = DERParseSequence(extnValue, 2794 DERNumBasicConstraintsItemSpecs, DERBasicConstraintsItemSpecs, 2795 &basicConstraints, sizeof(basicConstraints)); 2796 require_noerr_quiet(drtn, badDER); 2797 2798 appendBooleanProperty(properties, SEC_CERT_AUTHORITY_KEY, 2799 &basicConstraints.cA, false); 2800 2801 if (basicConstraints.pathLenConstraint.length != 0) { 2802 appendIntegerProperty(properties, SEC_PATH_LEN_CONSTRAINT_KEY, 2803 &basicConstraints.pathLenConstraint); 2804 } 2805 return; 2806badDER: 2807 appendInvalidProperty(properties, SEC_BASIC_CONSTRAINTS_KEY, extnValue); 2808} 2809 2810/* 2811 CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint 2812 2813 DistributionPoint ::= SEQUENCE { 2814 distributionPoint [0] DistributionPointName OPTIONAL, 2815 reasons [1] ReasonFlags OPTIONAL, 2816 cRLIssuer [2] GeneralNames OPTIONAL } 2817 2818 DistributionPointName ::= CHOICE { 2819 fullName [0] GeneralNames, 2820 nameRelativeToCRLIssuer [1] RelativeDistinguishedName } 2821 2822 ReasonFlags ::= BIT STRING { 2823 unused (0), 2824 keyCompromise (1), 2825 cACompromise (2), 2826 affiliationChanged (3), 2827 superseded (4), 2828 cessationOfOperation (5), 2829 certificateHold (6), 2830 privilegeWithdrawn (7), 2831 aACompromise (8) } 2832*/ 2833static void appendCrlDistributionPoints(CFMutableArrayRef properties, 2834 const DERItem *extnValue) { 2835 CFAllocatorRef allocator = CFGetAllocator(properties); 2836 DERTag tag; 2837 DERSequence dpSeq; 2838 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &dpSeq); 2839 require_noerr_quiet(drtn, badDER); 2840 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 2841 DERDecodedInfo dpSeqContent; 2842 while ((drtn = DERDecodeSeqNext(&dpSeq, &dpSeqContent)) == DR_Success) { 2843 require_quiet(dpSeqContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 2844 DERDistributionPoint dp; 2845 drtn = DERParseSequenceContent(&dpSeqContent.content, 2846 DERNumDistributionPointItemSpecs, 2847 DERDistributionPointItemSpecs, 2848 &dp, sizeof(dp)); 2849 require_noerr_quiet(drtn, badDER); 2850 if (dp.distributionPoint.length) { 2851 DERDecodedInfo distributionPointName; 2852 drtn = DERDecodeItem(&dp.distributionPoint, &distributionPointName); 2853 require_noerr_quiet(drtn, badDER); 2854 if (distributionPointName.tag == 2855 (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0)) { 2856 /* Full Name */ 2857 appendGeneralNamesContent(properties, 2858 &distributionPointName.content); 2859 } else if (distributionPointName.tag == 2860 (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1)) { 2861 CFArrayRef rdn_props = createPropertiesForRDNContent(allocator, 2862 &dp.reasons); 2863 appendProperty(properties, kSecPropertyTypeSection, 2864 SEC_NAME_REL_CRL_ISSUER_KEY, NULL, rdn_props); 2865 CFRelease(rdn_props); 2866 } else { 2867 goto badDER; 2868 } 2869 } 2870 if (dp.reasons.length) { 2871 static const CFStringRef reasonNames[] = { 2872 SEC_UNUSED_KEY, 2873 SEC_KEY_COMPROMISE_KEY, 2874 SEC_CA_COMPROMISE_KEY, 2875 SEC_AFFILIATION_CHANGED_KEY, 2876 SEC_SUPERSEDED_KEY, 2877 SEC_CESSATION_OF_OPER_KEY, 2878 SEC_CERTIFICATE_HOLD_KEY, 2879 SEC_PRIV_WITHDRAWN_KEY, 2880 SEC_AA_COMPROMISE_KEY 2881 }; 2882 appendBitStringContentNames(properties, SEC_REASONS_KEY, 2883 &dp.reasons, 2884 reasonNames, array_size(reasonNames)); 2885 } 2886 if (dp.cRLIssuer.length) { 2887 CFMutableArrayRef crlIssuer = CFArrayCreateMutable(allocator, 0, 2888 &kCFTypeArrayCallBacks); 2889 appendProperty(properties, kSecPropertyTypeSection, 2890 SEC_CRL_ISSUER_KEY, NULL, crlIssuer); 2891 CFRelease(crlIssuer); 2892 appendGeneralNames(crlIssuer, &dp.cRLIssuer); 2893 } 2894 } 2895 require_quiet(drtn == DR_EndOfSequence, badDER); 2896 return; 2897badDER: 2898 appendInvalidProperty(properties, SEC_CRL_DISTR_POINTS_KEY, extnValue); 2899} 2900 2901/* Decode a sequence of integers into a comma separated list of ints. */ 2902static void appendIntegerSequenceContent(CFMutableArrayRef properties, 2903 CFStringRef label, const DERItem *intSequenceContent) { 2904 CFAllocatorRef allocator = CFGetAllocator(properties); 2905 DERSequence intSeq; 2906 DERReturn drtn = DERDecodeSeqContentInit(intSequenceContent, &intSeq); 2907 require_noerr_quiet(drtn, badDER); 2908 DERDecodedInfo intContent; 2909 CFStringRef value = NULL; 2910 CFStringRef fmt = SecCopyCertString(SEC_STRING_LIST_KEY); 2911 while ((drtn = DERDecodeSeqNext(&intSeq, &intContent)) == DR_Success) { 2912 require_quiet(intContent.tag == ASN1_INTEGER, badDER); 2913 CFStringRef intDesc = copyIntegerContentDescription( 2914 allocator, &intContent.content); 2915 if (value) { 2916 CFStringRef v; 2917 v = CFStringCreateWithFormat(allocator, NULL, fmt, value, intDesc); 2918 CFRelease(value); 2919 value = v; 2920 CFRelease(intDesc); 2921 } else { 2922 value = intDesc; 2923 } 2924 } 2925 CFRelease(fmt); 2926 require_quiet(drtn == DR_EndOfSequence, badDER); 2927 if (value) { 2928 appendProperty(properties, kSecPropertyTypeString, label, NULL, value); 2929 CFRelease(value); 2930 return; 2931 } 2932 /* DROPTHOUGH if !value. */ 2933badDER: 2934 appendInvalidProperty(properties, label, intSequenceContent); 2935} 2936 2937static void appendCertificatePolicies(CFMutableArrayRef properties, 2938 const DERItem *extnValue) { 2939 CFAllocatorRef allocator = CFGetAllocator(properties); 2940 DERTag tag; 2941 DERSequence piSeq; 2942 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &piSeq); 2943 require_noerr_quiet(drtn, badDER); 2944 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 2945 DERDecodedInfo piContent; 2946 int pin = 1; 2947 while ((drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) { 2948 require_quiet(piContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 2949 DERPolicyInformation pi; 2950 drtn = DERParseSequenceContent(&piContent.content, 2951 DERNumPolicyInformationItemSpecs, 2952 DERPolicyInformationItemSpecs, 2953 &pi, sizeof(pi)); 2954 require_noerr_quiet(drtn, badDER); 2955 CFStringRef piLabel = CFStringCreateWithFormat(allocator, NULL, 2956 SEC_POLICY_IDENTIFIER_KEY, pin); 2957 CFStringRef piFmt = SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY); 2958 CFStringRef lpiLabel = CFStringCreateWithFormat(allocator, NULL, 2959 piFmt, pin++); 2960 CFRelease(piFmt); 2961 appendOIDProperty(properties, piLabel, lpiLabel, &pi.policyIdentifier); 2962 CFRelease(piLabel); 2963 CFRelease(lpiLabel); 2964 if (pi.policyQualifiers.length == 0) 2965 continue; 2966 2967 DERSequence pqSeq; 2968 drtn = DERDecodeSeqContentInit(&pi.policyQualifiers, &pqSeq); 2969 require_noerr_quiet(drtn, badDER); 2970 DERDecodedInfo pqContent; 2971 int pqn = 1; 2972 while ((drtn = DERDecodeSeqNext(&pqSeq, &pqContent)) == DR_Success) { 2973 DERPolicyQualifierInfo pqi; 2974 drtn = DERParseSequenceContent(&pqContent.content, 2975 DERNumPolicyQualifierInfoItemSpecs, 2976 DERPolicyQualifierInfoItemSpecs, 2977 &pqi, sizeof(pqi)); 2978 require_noerr_quiet(drtn, badDER); 2979 DERDecodedInfo qualifierContent; 2980 drtn = DERDecodeItem(&pqi.qualifier, &qualifierContent); 2981 require_noerr_quiet(drtn, badDER); 2982 CFStringRef pqLabel = CFStringCreateWithFormat(allocator, NULL, 2983 SEC_POLICY_QUALIFIER_KEY, pqn); 2984 CFStringRef pqFmt = SecCopyCertString(SEC_POLICY_QUALIFIER_KEY); 2985 CFStringRef lpqLabel = CFStringCreateWithFormat(allocator, NULL, 2986 pqFmt, pqn++); 2987 CFRelease(pqFmt); 2988 appendOIDProperty(properties, pqLabel, lpqLabel, 2989 &pqi.policyQualifierID); 2990 CFRelease(pqLabel); 2991 CFRelease(lpqLabel); 2992 if (DEROidCompare(&oidQtCps, &pqi.policyQualifierID)) { 2993 require_quiet(qualifierContent.tag == ASN1_IA5_STRING, badDER); 2994 appendURLContentProperty(properties, SEC_CPS_URI_KEY, 2995 &qualifierContent.content); 2996 } else if (DEROidCompare(&oidQtUNotice, &pqi.policyQualifierID)) { 2997 require_quiet(qualifierContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 2998 DERUserNotice un; 2999 drtn = DERParseSequenceContent(&qualifierContent.content, 3000 DERNumUserNoticeItemSpecs, 3001 DERUserNoticeItemSpecs, 3002 &un, sizeof(un)); 3003 require_noerr_quiet(drtn, badDER); 3004 if (un.noticeRef.length) { 3005 DERNoticeReference nr; 3006 drtn = DERParseSequenceContent(&un.noticeRef, 3007 DERNumNoticeReferenceItemSpecs, 3008 DERNoticeReferenceItemSpecs, 3009 &nr, sizeof(nr)); 3010 require_noerr_quiet(drtn, badDER); 3011 appendDERThingProperty(properties, 3012 SEC_ORGANIZATION_KEY, NULL, 3013 &nr.organization); 3014 appendIntegerSequenceContent(properties, 3015 SEC_NOTICE_NUMBERS_KEY, &nr.noticeNumbers); 3016 } 3017 if (un.explicitText.length) { 3018 appendDERThingProperty(properties, SEC_EXPLICIT_TEXT_KEY, 3019 NULL, &un.explicitText); 3020 } 3021 } else { 3022 appendUnparsedProperty(properties, SEC_QUALIFIER_KEY, NULL, 3023 &pqi.qualifier); 3024 } 3025 } 3026 } 3027 require_quiet(drtn == DR_EndOfSequence, badDER); 3028 return; 3029badDER: 3030 appendInvalidProperty(properties, SEC_CERT_POLICIES_KEY, extnValue); 3031} 3032 3033static void appendSubjectKeyIdentifier(CFMutableArrayRef properties, 3034 const DERItem *extnValue) { 3035 DERReturn drtn; 3036 DERDecodedInfo keyIdentifier; 3037 drtn = DERDecodeItem(extnValue, &keyIdentifier); 3038 require_noerr_quiet(drtn, badDER); 3039 require_quiet(keyIdentifier.tag == ASN1_OCTET_STRING, badDER); 3040 appendDataProperty(properties, SEC_KEY_IDENTIFIER_KEY, NULL, 3041 &keyIdentifier.content); 3042 3043 return; 3044badDER: 3045 appendInvalidProperty(properties, SEC_SUBJ_KEY_ID_KEY, 3046 extnValue); 3047} 3048 3049/* 3050AuthorityKeyIdentifier ::= SEQUENCE { 3051 keyIdentifier [0] KeyIdentifier OPTIONAL, 3052 authorityCertIssuer [1] GeneralNames OPTIONAL, 3053 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } 3054 -- authorityCertIssuer and authorityCertSerialNumber MUST both 3055 -- be present or both be absent 3056 3057KeyIdentifier ::= OCTET STRING 3058*/ 3059static void appendAuthorityKeyIdentifier(CFMutableArrayRef properties, 3060 const DERItem *extnValue) { 3061 DERAuthorityKeyIdentifier akid; 3062 DERReturn drtn; 3063 drtn = DERParseSequence(extnValue, 3064 DERNumAuthorityKeyIdentifierItemSpecs, 3065 DERAuthorityKeyIdentifierItemSpecs, 3066 &akid, sizeof(akid)); 3067 require_noerr_quiet(drtn, badDER); 3068 if (akid.keyIdentifier.length) { 3069 appendDataProperty(properties, SEC_KEY_IDENTIFIER_KEY, NULL, 3070 &akid.keyIdentifier); 3071 } 3072 if (akid.authorityCertIssuer.length || 3073 akid.authorityCertSerialNumber.length) { 3074 require_quiet(akid.authorityCertIssuer.length && 3075 akid.authorityCertSerialNumber.length, badDER); 3076 /* Perhaps put in a subsection called Authority Certificate Issuer. */ 3077 appendGeneralNamesContent(properties, 3078 &akid.authorityCertIssuer); 3079 appendIntegerProperty(properties, SEC_AUTH_CERT_SERIAL_KEY, 3080 &akid.authorityCertSerialNumber); 3081 } 3082 3083 return; 3084badDER: 3085 appendInvalidProperty(properties, SEC_AUTHORITY_KEY_ID_KEY, extnValue); 3086} 3087 3088/* 3089 PolicyConstraints ::= SEQUENCE { 3090 requireExplicitPolicy [0] SkipCerts OPTIONAL, 3091 inhibitPolicyMapping [1] SkipCerts OPTIONAL } 3092 3093 SkipCerts ::= INTEGER (0..MAX) 3094*/ 3095static void appendPolicyConstraints(CFMutableArrayRef properties, 3096 const DERItem *extnValue) { 3097 DERPolicyConstraints pc; 3098 DERReturn drtn; 3099 drtn = DERParseSequence(extnValue, 3100 DERNumPolicyConstraintsItemSpecs, 3101 DERPolicyConstraintsItemSpecs, 3102 &pc, sizeof(pc)); 3103 require_noerr_quiet(drtn, badDER); 3104 if (pc.requireExplicitPolicy.length) { 3105 appendIntegerProperty(properties, SEC_REQUIRE_EXPL_POLICY_KEY, 3106 &pc.requireExplicitPolicy); 3107 } 3108 if (pc.inhibitPolicyMapping.length) { 3109 appendIntegerProperty(properties, SEC_INHIBIT_POLICY_MAP_KEY, 3110 &pc.inhibitPolicyMapping); 3111 } 3112 3113 return; 3114 3115badDER: 3116 appendInvalidProperty(properties, SEC_POLICY_CONSTRAINTS_KEY, extnValue); 3117} 3118 3119/* 3120extendedKeyUsage EXTENSION ::= { 3121 SYNTAX SEQUENCE SIZE (1..MAX) OF KeyPurposeId 3122 IDENTIFIED BY id-ce-extKeyUsage } 3123 3124KeyPurposeId ::= OBJECT IDENTIFIER 3125*/ 3126static void appendExtendedKeyUsage(CFMutableArrayRef properties, 3127 const DERItem *extnValue) { 3128 DERTag tag; 3129 DERSequence derSeq; 3130 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &derSeq); 3131 require_noerr_quiet(drtn, badDER); 3132 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 3133 DERDecodedInfo currDecoded; 3134 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) { 3135 require_quiet(currDecoded.tag == ASN1_OBJECT_ID, badDER); 3136 appendOIDProperty(properties, SEC_PURPOSE_KEY, NULL, 3137 &currDecoded.content); 3138 } 3139 require_quiet(drtn == DR_EndOfSequence, badDER); 3140 return; 3141badDER: 3142 appendInvalidProperty(properties, SEC_EXTENDED_KEY_USAGE_KEY, extnValue); 3143} 3144 3145/* 3146 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } 3147 3148 AuthorityInfoAccessSyntax ::= 3149 SEQUENCE SIZE (1..MAX) OF AccessDescription 3150 3151 AccessDescription ::= SEQUENCE { 3152 accessMethod OBJECT IDENTIFIER, 3153 accessLocation GeneralName } 3154 3155 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } 3156 3157 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 } 3158 3159 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } 3160*/ 3161static void appendInfoAccess(CFMutableArrayRef properties, 3162 const DERItem *extnValue) { 3163 DERTag tag; 3164 DERSequence adSeq; 3165 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &adSeq); 3166 require_noerr_quiet(drtn, badDER); 3167 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 3168 DERDecodedInfo adContent; 3169 while ((drtn = DERDecodeSeqNext(&adSeq, &adContent)) == DR_Success) { 3170 require_quiet(adContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 3171 DERAccessDescription ad; 3172 drtn = DERParseSequenceContent(&adContent.content, 3173 DERNumAccessDescriptionItemSpecs, 3174 DERAccessDescriptionItemSpecs, 3175 &ad, sizeof(ad)); 3176 require_noerr_quiet(drtn, badDER); 3177 appendOIDProperty(properties, SEC_ACCESS_METHOD_KEY, NULL, 3178 &ad.accessMethod); 3179 //TODO: Do something with SEC_ACCESS_LOCATION_KEY 3180 appendGeneralNameProperty(properties, &ad.accessLocation); 3181 } 3182 require_quiet(drtn == DR_EndOfSequence, badDER); 3183 return; 3184badDER: 3185 appendInvalidProperty(properties, SEC_AUTH_INFO_ACCESS_KEY, extnValue); 3186} 3187 3188static void appendNetscapeCertType(CFMutableArrayRef properties, 3189 const DERItem *extnValue) { 3190 static const CFStringRef certTypes[] = { 3191 SEC_SSL_CLIENT_KEY, 3192 SEC_SSL_SERVER_KEY, 3193 SEC_SMIME_KEY, 3194 SEC_OBJECT_SIGNING_KEY, 3195 SEC_RESERVED_KEY, 3196 SEC_SSL_CA_KEY, 3197 SEC_SMIME_CA_KEY, 3198 SEC_OBJECT_SIGNING_CA_KEY 3199 }; 3200 appendBitStringNames(properties, SEC_USAGE_KEY, extnValue, 3201 certTypes, array_size(certTypes)); 3202} 3203 3204#if 0 3205static void appendEntrustVersInfo(CFMutableArrayRef properties, 3206 const DERItem *extnValue) { 3207} 3208 3209/* 3210 * The list of Qualified Cert Statement statementIds we understand, even though 3211 * we don't actually do anything with them; if these are found in a Qualified 3212 * Cert Statement that's critical, we can truthfully say "yes we understand this". 3213 */ 3214static const CSSM_OID_PTR knownQualifiedCertStatements[] = 3215{ 3216 /* id-qcs := { id-pkix 11 } */ 3217 (const CSSM_OID_PTR)&CSSMOID_OID_QCS_SYNTAX_V1, /* id-qcs 1 */ 3218 (const CSSM_OID_PTR)&CSSMOID_OID_QCS_SYNTAX_V2, /* id-qcs 2 */ 3219 (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_COMPLIANCE, 3220 (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_LIMIT_VALUE, 3221 (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_RETENTION, 3222 (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_SSCD 3223}; 3224#define NUM_KNOWN_QUAL_CERT_STATEMENTS (sizeof(knownQualifiedCertStatements) / sizeof(CSSM_OID_PTR)) 3225*/ 3226static void appendQCCertStatements(CFMutableArrayRef properties, 3227 const DERItem *extnValue) { 3228} 3229 3230#endif 3231 3232static bool appendPrintableDERSequence(CFMutableArrayRef properties, 3233 CFStringRef label, const DERItem *sequence) { 3234 DERTag tag; 3235 DERSequence derSeq; 3236 DERReturn drtn = DERDecodeSeqInit(sequence, &tag, &derSeq); 3237 require_noerr_quiet(drtn, badSequence); 3238 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badSequence); 3239 DERDecodedInfo currDecoded; 3240 bool appendedSomething = false; 3241 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) { 3242 switch (currDecoded.tag) 3243 { 3244 case 0: // 0 3245 case ASN1_SEQUENCE: // 16 3246 case ASN1_SET: // 17 3247 // skip constructed object lengths 3248 break; 3249 3250 case ASN1_UTF8_STRING: // 12 3251 case ASN1_NUMERIC_STRING: // 18 3252 case ASN1_PRINTABLE_STRING: // 19 3253 case ASN1_T61_STRING: // 20, also ASN1_TELETEX_STRING 3254 case ASN1_VIDEOTEX_STRING: // 21 3255 case ASN1_IA5_STRING: // 22 3256 case ASN1_GRAPHIC_STRING: // 25 3257 case ASN1_VISIBLE_STRING: // 26, also ASN1_ISO646_STRING 3258 case ASN1_GENERAL_STRING: // 27 3259 case ASN1_UNIVERSAL_STRING: // 28 3260 { 3261 CFStringRef string = 3262 copyDERThingContentDescription(CFGetAllocator(properties), 3263 currDecoded.tag, &currDecoded.content, false); 3264 //CFStringRef cleanString = copyStringRemovingPercentEscapes(string); 3265 3266 appendProperty(properties, kSecPropertyTypeString, label, NULL, 3267 string); 3268 CFRelease(string); 3269 appendedSomething = true; 3270 break; 3271 } 3272 default: 3273 break; 3274 } 3275 } 3276 require_quiet(drtn == DR_EndOfSequence, badSequence); 3277 return appendedSomething; 3278badSequence: 3279 return false; 3280} 3281 3282static void appendExtension(CFMutableArrayRef parent, 3283 const SecCertificateExtension *extn) { 3284 CFAllocatorRef allocator = CFGetAllocator(parent); 3285 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, 3286 &kCFTypeArrayCallBacks); 3287 const DERItem 3288 *extnID = &extn->extnID, 3289 *extnValue = &extn->extnValue; 3290 CFStringRef label = NULL; 3291 CFStringRef localizedLabel = NULL; 3292 3293 appendBoolProperty(properties, SEC_CRITICAL_KEY, extn->critical); 3294 require_quiet(extnID, xit); 3295 3296#if 1 3297 bool handeled = true; 3298 /* Extensions that we know how to handle ourselves... */ 3299 if (extnID->length == oidSubjectKeyIdentifier.length && 3300 !memcmp(extnID->data, oidSubjectKeyIdentifier.data, extnID->length - 1)) 3301 { 3302 switch (extnID->data[extnID->length - 1]) { 3303 case 14: /* SubjectKeyIdentifier id-ce 14 */ 3304 appendSubjectKeyIdentifier(properties, extnValue); 3305 break; 3306 case 15: /* KeyUsage id-ce 15 */ 3307 appendKeyUsage(properties, extnValue); 3308 break; 3309 case 16: /* PrivateKeyUsagePeriod id-ce 16 */ 3310 appendPrivateKeyUsagePeriod(properties, extnValue); 3311 break; 3312 case 17: /* SubjectAltName id-ce 17 */ 3313 case 18: /* IssuerAltName id-ce 18 */ 3314 appendGeneralNames(properties, extnValue); 3315 break; 3316 case 19: /* BasicConstraints id-ce 19 */ 3317 appendBasicConstraints(properties, extnValue); 3318 break; 3319 case 30: /* NameConstraints id-ce 30 */ 3320 handeled = false; 3321 break; 3322 case 31: /* CRLDistributionPoints id-ce 31 */ 3323 appendCrlDistributionPoints(properties, extnValue); 3324 break; 3325 case 32: /* CertificatePolicies id-ce 32 */ 3326 appendCertificatePolicies(properties, extnValue); 3327 break; 3328 case 33: /* PolicyMappings id-ce 33 */ 3329 handeled = false; 3330 break; 3331 case 35: /* AuthorityKeyIdentifier id-ce 35 */ 3332 appendAuthorityKeyIdentifier(properties, extnValue); 3333 break; 3334 case 36: /* PolicyConstraints id-ce 36 */ 3335 appendPolicyConstraints(properties, extnValue); 3336 break; 3337 case 37: /* ExtKeyUsage id-ce 37 */ 3338 appendExtendedKeyUsage(properties, extnValue); 3339 break; 3340 case 46: /* FreshestCRL id-ce 46 */ 3341 handeled = false; 3342 break; 3343 case 54: /* InhibitAnyPolicy id-ce 54 */ 3344 handeled = false; 3345 break; 3346 default: 3347 handeled = false; 3348 break; 3349 } 3350 } else if (extnID->length == oidAuthorityInfoAccess.length && 3351 !memcmp(extnID->data, oidAuthorityInfoAccess.data, extnID->length - 1)) 3352 { 3353 switch (extnID->data[extnID->length - 1]) { 3354 case 1: /* AuthorityInfoAccess id-pe 1 */ 3355 appendInfoAccess(properties, extnValue); 3356 break; 3357 case 3: /* QCStatements id-pe 3 */ 3358 handeled = false; 3359 break; 3360 case 11: /* SubjectInfoAccess id-pe 11 */ 3361 appendInfoAccess(properties, extnValue); 3362 break; 3363 default: 3364 handeled = false; 3365 break; 3366 } 3367 } else if (DEROidCompare(extnID, &oidNetscapeCertType)) { 3368 /* 2.16.840.1.113730.1.1 netscape 1 1 */ 3369 appendNetscapeCertType(properties, extnValue); 3370 } else { 3371 handeled = false; 3372 } 3373 3374 if (!handeled) { 3375 /* Try to parse and display printable string(s). */ 3376 if (appendPrintableDERSequence(properties, SEC_DATA_KEY, extnValue)) { 3377 /* Nothing to do here appendPrintableDERSequence did the work. */ 3378 } else { 3379 /* Couldn't parse extension; dump the raw unparsed data as hex. */ 3380 appendUnparsedProperty(properties, SEC_DATA_KEY, NULL, extnValue); 3381 } 3382 } 3383#else 3384 /* Extensions that we know how to handle ourselves... */ 3385 if (DEROidCompare(extnID, &oidSubjectKeyIdentifier)) { 3386 appendSubjectKeyIdentifier(properties, extnValue); 3387 } else if (DEROidCompare(extnID, &oidKeyUsage)) { 3388 appendKeyUsage(properties, extnValue); 3389 } else if (DEROidCompare(extnID, &oidPrivateKeyUsagePeriod)) { 3390 appendPrivateKeyUsagePeriod(properties, extnValue); 3391 } else if (DEROidCompare(extnID, &oidSubjectAltName)) { 3392 appendGeneralNames(properties, extnValue); 3393 } else if (DEROidCompare(extnID, &oidIssuerAltName)) { 3394 appendGeneralNames(properties, extnValue); 3395 } else if (DEROidCompare(extnID, &oidBasicConstraints)) { 3396 appendBasicConstraints(properties, extnValue); 3397 } else if (DEROidCompare(extnID, &oidCrlDistributionPoints)) { 3398 appendCrlDistributionPoints(properties, extnValue); 3399 } else if (DEROidCompare(extnID, &oidCertificatePolicies)) { 3400 appendCertificatePolicies(properties, extnValue); 3401 } else if (DEROidCompare(extnID, &oidAuthorityKeyIdentifier)) { 3402 appendAuthorityKeyIdentifier(properties, extnValue); 3403 } else if (DEROidCompare(extnID, &oidPolicyConstraints)) { 3404 appendPolicyConstraints(properties, extnValue); 3405 } else if (DEROidCompare(extnID, &oidExtendedKeyUsage)) { 3406 appendExtendedKeyUsage(properties, extnValue); 3407 } else if (DEROidCompare(extnID, &oidAuthorityInfoAccess)) { 3408 appendInfoAccess(properties, extnValue); 3409 } else if (DEROidCompare(extnID, &oidSubjectInfoAccess)) { 3410 appendInfoAccess(properties, extnValue); 3411 } else if (DEROidCompare(extnID, &oidNetscapeCertType)) { 3412 appendNetscapeCertType(properties, extnValue); 3413#if 0 3414 } else if (DEROidCompare(extnID, &oidEntrustVersInfo)) { 3415 appendEntrustVersInfo(properties, extnValue); 3416#endif 3417 } else 3418 /* Try to parse and display printable string(s). */ 3419 if (appendPrintableDERSequence(properties, SEC_DATA_KEY, extnValue)) { 3420 /* Nothing to do here appendPrintableDERSequence did the work. */ 3421 } else { 3422 /* Couldn't parse extension; dump the raw unparsed data as hex. */ 3423 appendUnparsedProperty(properties, SEC_DATA_KEY, NULL, extnValue); 3424 } 3425#endif 3426 label = SecDERItemCopyOIDDecimalRepresentation(allocator, extnID); 3427 localizedLabel = copyLocalizedOidDescription(allocator, extnID); 3428 appendProperty(parent, kSecPropertyTypeSection, label, localizedLabel, properties); 3429 3430xit: 3431 CFReleaseSafe(localizedLabel); 3432 CFReleaseSafe(label); 3433 CFReleaseSafe(properties); 3434} 3435 3436/* Different types of summary types from least desired to most desired. */ 3437enum SummaryType { 3438 kSummaryTypeNone, 3439 kSummaryTypePrintable, 3440 kSummaryTypeOrganizationName, 3441 kSummaryTypeOrganizationalUnitName, 3442 kSummaryTypeCommonName, 3443}; 3444 3445struct Summary { 3446 enum SummaryType type; 3447 CFStringRef summary; 3448 CFStringRef description; 3449}; 3450 3451static OSStatus obtainSummaryFromX501Name(void *context, 3452 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 3453 struct Summary *summary = (struct Summary *)context; 3454 enum SummaryType stype = kSummaryTypeNone; 3455 CFStringRef string = NULL; 3456 if (DEROidCompare(type, &oidCommonName)) { 3457 stype = kSummaryTypeCommonName; 3458 } else if (DEROidCompare(type, &oidOrganizationalUnitName)) { 3459 stype = kSummaryTypeOrganizationalUnitName; 3460 } else if (DEROidCompare(type, &oidOrganizationName)) { 3461 stype = kSummaryTypeOrganizationName; 3462 } else if (DEROidCompare(type, &oidDescription)) { 3463 string = copyDERThingDescription(kCFAllocatorDefault, value, true); 3464 if (string) { 3465 if (summary->description) { 3466 CFStringRef fmt = SecCopyCertString(SEC_STRING_LIST_KEY); 3467 CFStringRef newDescription = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, string, summary->description); 3468 CFRelease(fmt); 3469 CFRelease(summary->description); 3470 summary->description = newDescription; 3471 } else { 3472 summary->description = string; 3473 CFRetain(string); 3474 } 3475 stype = kSummaryTypePrintable; 3476 } 3477 } else { 3478 stype = kSummaryTypePrintable; 3479 } 3480 3481 /* Build a string with all instances of the most desired 3482 component type in reverse order encountered comma separated list, 3483 The order of desirability is defined by enum SummaryType. */ 3484 if (summary->type <= stype) { 3485 if (!string) 3486 string = copyDERThingDescription(kCFAllocatorDefault, value, true); 3487 3488 if (string) { 3489 if (summary->type == stype) { 3490 CFStringRef fmt = SecCopyCertString(SEC_STRING_LIST_KEY); 3491 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, string, summary->summary); 3492 CFRelease(fmt); 3493 CFRelease(string); 3494 string = newSummary; 3495 } else { 3496 summary->type = stype; 3497 } 3498 CFReleaseSafe(summary->summary); 3499 summary->summary = string; 3500 } 3501 } else { 3502 CFReleaseSafe(string); 3503 } 3504 3505 return errSecSuccess; 3506} 3507 3508CFStringRef SecCertificateCopySubjectSummary(SecCertificateRef certificate) { 3509 struct Summary summary = {}; 3510 parseX501NameContent(&certificate->_subject, &summary, obtainSummaryFromX501Name); 3511 /* If we found a description and a common name we change the summary to 3512 CommonName (Description). */ 3513 if (summary.description) { 3514 if (summary.type == kSummaryTypeCommonName) { 3515 CFStringRef fmt = SecCopyCertString(SEC_COMMON_NAME_DESC_KEY); 3516 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, summary.summary, summary.description); 3517 CFRelease(fmt); 3518 CFRelease(summary.summary); 3519 summary.summary = newSummary; 3520 } 3521 CFRelease(summary.description); 3522 } 3523 3524 if (!summary.summary) { 3525 /* If we didn't find a suitable printable string in the subject at all, we try 3526 the first email address in the certificate instead. */ 3527 CFArrayRef names = SecCertificateCopyRFC822Names(certificate); 3528 if (!names) { 3529 /* If we didn't find any email addresses in the certificate, we try finding 3530 a DNS name instead. */ 3531 names = SecCertificateCopyDNSNames(certificate); 3532 } 3533 if (names) { 3534 summary.summary = CFArrayGetValueAtIndex(names, 0); 3535 CFRetain(summary.summary); 3536 CFRelease(names); 3537 } 3538 } 3539 3540 return summary.summary; 3541} 3542 3543CFStringRef SecCertificateCopyIssuerSummary(SecCertificateRef certificate) { 3544 struct Summary summary = {}; 3545 parseX501NameContent(&certificate->_issuer, &summary, obtainSummaryFromX501Name); 3546 /* If we found a description and a common name we change the summary to 3547 CommonName (Description). */ 3548 if (summary.description) { 3549 if (summary.type == kSummaryTypeCommonName) { 3550 CFStringRef fmt = SecCopyCertString(SEC_COMMON_NAME_DESC_KEY); 3551 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, summary.summary, summary.description); 3552 CFRelease(fmt); 3553 CFRelease(summary.summary); 3554 summary.summary = newSummary; 3555 } 3556 CFRelease(summary.description); 3557 } 3558 3559 return summary.summary; 3560} 3561 3562/* Return the earliest date on which all certificates in this chain are still 3563 valid. */ 3564static CFAbsoluteTime SecCertificateGetChainsLastValidity( 3565 SecCertificateRef certificate) { 3566 CFAbsoluteTime earliest = certificate->_notAfter; 3567#if 0 3568 while (certificate->_parent) { 3569 certificate = certificate->_parent; 3570 if (earliest > certificate->_notAfter) 3571 earliest = certificate->_notAfter; 3572 } 3573#endif 3574 3575 return earliest; 3576} 3577 3578/* Return the latest date on which all certificates in this chain will be 3579 valid. */ 3580static CFAbsoluteTime SecCertificateGetChainsFirstValidity( 3581 SecCertificateRef certificate) { 3582 CFAbsoluteTime latest = certificate->_notBefore; 3583#if 0 3584 while (certificate->_parent) { 3585 certificate = certificate->_parent; 3586 if (latest < certificate->_notBefore) 3587 latest = certificate->_notBefore; 3588 } 3589#endif 3590 3591 return latest; 3592} 3593 3594bool SecCertificateIsValid(SecCertificateRef certificate, 3595 CFAbsoluteTime verifyTime) { 3596 return certificate && certificate->_notBefore <= verifyTime && 3597 verifyTime <= certificate->_notAfter; 3598} 3599 3600CFIndex SecCertificateVersion(SecCertificateRef certificate) { 3601 return certificate->_version + 1; 3602} 3603 3604CFAbsoluteTime SecCertificateNotValidBefore(SecCertificateRef certificate) { 3605 return certificate->_notBefore; 3606} 3607 3608CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate) { 3609 return certificate->_notAfter; 3610} 3611 3612CFMutableArrayRef SecCertificateCopySummaryProperties( 3613 SecCertificateRef certificate, CFAbsoluteTime verifyTime) { 3614 CFAllocatorRef allocator = CFGetAllocator(certificate); 3615 CFMutableArrayRef summary = CFArrayCreateMutable(allocator, 0, 3616 &kCFTypeArrayCallBacks); 3617 3618 /* First we put the subject summary name. */ 3619 CFStringRef ssummary = SecCertificateCopySubjectSummary(certificate); 3620 if (ssummary) { 3621 appendProperty(summary, kSecPropertyTypeTitle, 3622 NULL, NULL, ssummary); 3623 CFRelease(ssummary); 3624 } 3625#if 0 3626 CFStringRef isummary = SEC_ISSUER_SUMMARY_KEY; 3627 appendProperty(summary, kSecPropertyTypeString, 3628 SEC_ISSUED_BY_KEY, isummary); 3629 CFRelease(isummary); 3630#endif 3631 3632 /* Let see if this certificate is currently valid. */ 3633 CFStringRef label; 3634 CFAbsoluteTime when; 3635 CFStringRef message; 3636 CFStringRef ptype; 3637 if (verifyTime > certificate->_notAfter) { 3638 label = SEC_EXPIRED_KEY; 3639 when = certificate->_notAfter; 3640 ptype = kSecPropertyTypeError; 3641 message = SEC_CERT_EXPIRED_KEY; 3642 } else if (certificate->_notBefore > verifyTime) { 3643 label = SEC_VALID_FROM_KEY; 3644 when = certificate->_notBefore; 3645 ptype = kSecPropertyTypeError; 3646 message = SEC_CERT_NOT_YET_VALID_KEY; 3647 } else { 3648 CFAbsoluteTime last = SecCertificateGetChainsLastValidity(certificate); 3649 CFAbsoluteTime first = SecCertificateGetChainsFirstValidity(certificate); 3650 if (verifyTime > last) { 3651 label = SEC_EXPIRED_KEY; 3652 when = last; 3653 ptype = kSecPropertyTypeError; 3654 message = SEC_ISSUER_EXPIRED_KEY; 3655 } else if (verifyTime < first) { 3656 label = SEC_VALID_FROM_KEY; 3657 when = first; 3658 ptype = kSecPropertyTypeError; 3659 message = SEC_ISSR_NOT_YET_VALID_KEY; 3660 } else { 3661 label = SEC_EXPIRES_KEY; 3662 when = certificate->_notAfter; 3663 ptype = kSecPropertyTypeSuccess; 3664 message = SEC_CERT_VALID_KEY; 3665 } 3666 } 3667 3668 appendDateProperty(summary, label, when); 3669 CFStringRef lmessage = SecCopyCertString(message); 3670 appendProperty(summary, ptype, NULL, NULL, lmessage); 3671 CFRelease(lmessage); 3672 3673 return summary; 3674} 3675 3676CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate) { 3677 if (!certificate->_properties) { 3678 CFAllocatorRef allocator = CFGetAllocator(certificate); 3679 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, 3680 &kCFTypeArrayCallBacks); 3681 3682 /* First we put the Subject Name in the property list. */ 3683 CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator, 3684 &certificate->_subject); 3685 appendProperty(properties, kSecPropertyTypeSection, 3686 SEC_SUBJECT_NAME_KEY, NULL, subject_plist); 3687 CFRelease(subject_plist); 3688 3689#if 0 3690 /* Put Normalized subject in for testing. */ 3691 if (certificate->_normalizedSubject) { 3692 DERItem nsubject = { 3693 (DERByte *)CFDataGetBytePtr(certificate->_normalizedSubject), 3694 CFDataGetLength(certificate->_normalizedSubject) 3695 }; 3696 CFArrayRef nsubject_plist = createPropertiesForX501NameContent(allocator, 3697 &nsubject); 3698 appendProperty(properties, kSecPropertyTypeSection, 3699 CFSTR("Normalized Subject Name"), nsubject_plist); 3700 CFRelease(nsubject_plist); 3701 } 3702#endif 3703 3704 /* Next we put the Issuer Name in the property list. */ 3705 CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator, 3706 &certificate->_issuer); 3707 appendProperty(properties, kSecPropertyTypeSection, 3708 SEC_ISSUER_NAME_KEY, NULL, issuer_plist); 3709 CFRelease(issuer_plist); 3710 3711#if 0 3712 /* Certificate version/type. */ 3713 bool isRoot = false; 3714 CFStringRef fmt = SecCopyCertString(SEC_X509_VERSION_KEY); 3715 CFStringRef typeString = CFStringCreateWithFormat(allocator, NULL, 3716 fmt, certificate->_version + 1, isRoot ? "root " : ""); 3717 CFRelease(fmt); 3718 appendProperty(properties, kSecPropertyTypeString, 3719 SEC_CERTIFICATE_TYPE_KEY, typeString); 3720 CFRelease(typeString); 3721#endif 3722 3723 /* Version */ 3724 CFStringRef fmt = SecCopyCertString(SEC_CERT_VERSION_VALUE_KEY); 3725 CFStringRef versionString = CFStringCreateWithFormat(allocator, 3726 NULL, fmt, certificate->_version + 1); 3727 CFRelease(fmt); 3728 appendProperty(properties, kSecPropertyTypeString, 3729 SEC_VERSION_KEY, NULL, versionString); 3730 CFRelease(versionString); 3731 3732 /* Serial Number */ 3733 if (certificate->_serialNum.length) { 3734 appendIntegerProperty(properties, SEC_SERIAL_NUMBER_KEY, 3735 &certificate->_serialNum); 3736 } 3737 3738 /* Signature algorithm. */ 3739#if 0 3740 appendAlgorithmProperty(properties, SEC_SIGNATURE_ALGORITHM_KEY, 3741 &certificate->_sigAlg); 3742#endif 3743 appendAlgorithmProperty(properties, SEC_SIGNATURE_ALGORITHM_KEY, 3744 &certificate->_tbsSigAlg); 3745 3746 3747 /* Validity dates. */ 3748 appendDateProperty(properties, SEC_NOT_VALID_BEFORE_KEY, 3749 certificate->_notBefore); 3750 appendDateProperty(properties, SEC_NOT_VALID_AFTER_KEY, 3751 certificate->_notAfter); 3752 3753 if (certificate->_subjectUniqueID.length) { 3754 appendDataProperty(properties, SEC_SUBJECT_UNIQUE_ID_KEY, NULL, 3755 &certificate->_subjectUniqueID); 3756 } 3757 if (certificate->_issuerUniqueID.length) { 3758 appendDataProperty(properties, SEC_ISSUER_UNIQUE_ID_KEY, NULL, 3759 &certificate->_issuerUniqueID); 3760 } 3761 3762 /* Public key algorithm. */ 3763 appendAlgorithmProperty(properties, SEC_PUBLIC_KEY_ALG_KEY, 3764 &certificate->_algId); 3765 3766 /* Consider breaking down an RSA public key into modulus and 3767 exponent? */ 3768 appendDataProperty(properties, SEC_PULIC_KEY_DATA_KEY, NULL, 3769 &certificate->_pubKeyDER); 3770 /* TODO: Add Key Size. */ 3771 /* TODO: Add Key Usage. */ 3772 3773 appendDataProperty(properties, SEC_SIGNATURE_KEY, NULL, 3774 &certificate->_signature); 3775 3776 CFIndex ix; 3777 for (ix = 0; ix < certificate->_extensionCount; ++ix) { 3778 appendExtension(properties, &certificate->_extensions[ix]); 3779 } 3780 3781 /* TODO: Certificate/Key Fingerprints. */ 3782 3783 certificate->_properties = properties; 3784 } 3785 3786 CFRetain(certificate->_properties); 3787 return certificate->_properties; 3788} 3789 3790CFDataRef SecCertificateCopySerialNumber( 3791 SecCertificateRef certificate) { 3792 if (certificate->_serialNumber) { 3793 CFRetain(certificate->_serialNumber); 3794 } 3795 return certificate->_serialNumber; 3796} 3797 3798CFDataRef SecCertificateGetNormalizedIssuerContent( 3799 SecCertificateRef certificate) { 3800 return certificate->_normalizedIssuer; 3801} 3802 3803CFDataRef SecCertificateGetNormalizedSubjectContent( 3804 SecCertificateRef certificate) { 3805 return certificate->_normalizedSubject; 3806} 3807 3808/* Verify that certificate was signed by issuerKey. */ 3809OSStatus SecCertificateIsSignedBy(SecCertificateRef certificate, 3810 SecKeyRef issuerKey) { 3811 /* Setup algId in SecAsn1AlgId format. */ 3812 SecAsn1AlgId algId; 3813 algId.algorithm.Length = certificate->_tbsSigAlg.oid.length; 3814 algId.algorithm.Data = certificate->_tbsSigAlg.oid.data; 3815 algId.parameters.Length = certificate->_tbsSigAlg.params.length; 3816 algId.parameters.Data = certificate->_tbsSigAlg.params.data; 3817 3818 OSStatus status = SecKeyDigestAndVerify(issuerKey, &algId, 3819 certificate->_tbs.data, certificate->_tbs.length, 3820 certificate->_signature.data, certificate->_signature.length); 3821 if (status) { 3822 secdebug("verify", "signature verify failed: %" PRIdOSStatus, status); 3823 return errSecNotSigner; 3824 } 3825 3826 return errSecSuccess; 3827} 3828 3829#if 0 3830static OSStatus SecCertificateIsIssuedBy(SecCertificateRef certificate, 3831 SecCertificateRef issuer, bool signatureCheckOnly) { 3832 if (!signatureCheckOnly) { 3833 /* It turns out we don't actually need to use normalized subject and 3834 issuer according to rfc2459. */ 3835 3836 /* If present we should check issuerID against the issuer subjectID. */ 3837 3838 /* If we have an AuthorityKeyIdentifier extension that has a keyIdentifier 3839 then we should look for a SubjectKeyIdentifier in the issuer 3840 certificate. 3841 If we have a authorityCertSerialNumber we can use that for chaining. 3842 If we have a authorityCertIssuer we can use that? (or not) */ 3843 3844 /* Verify that this cert was issued by issuer. Do so by chaining 3845 either issuerID to subjectID or normalized issuer to normalized 3846 subject. */ 3847 CFDataRef normalizedIssuer = 3848 SecCertificateGetNormalizedIssuerContent(certificate); 3849 CFDataRef normalizedIssuerSubject = 3850 SecCertificateGetNormalizedSubjectContent(issuer); 3851 if (normalizedIssuer && normalizedIssuerSubject && 3852 !CFEqual(normalizedIssuer, normalizedIssuerSubject)) 3853 return errSecIssuerMismatch; 3854 } 3855 3856 /* Next verify that this cert was signed by issuer. */ 3857 SecKeyRef issuerKey = SecCertificateGetPublicKey(issuer); 3858 3859 /* Get the encodedDigestInfo from the digest of the subject's TBSCert */ 3860 /* FIXME: We sould cache this (or at least the digest) until we find 3861 a suitable issuer. */ 3862 uint8_t signedData[DER_SHA1_DIGEST_INFO_LEN]; 3863 CFIndex signedDataLength; 3864 CertVerifyReturn crtn; 3865 if (DEROidCompare(&certificate->_tbsSigAlg.oid, &oidSha1Rsa)) { 3866 signedDataLength = DER_SHA1_DIGEST_INFO_LEN; 3867 crtn = sha1DigestInfo(&certificate->_tbs, signedData); 3868 } else if(DEROidCompare(&certificate->_tbsSigAlg.oid, &oidMd5Rsa)) { 3869 signedDataLength = DER_MD_DIGEST_INFO_LEN; 3870 crtn = mdDigestInfo(WD_MD5, &certificate->_tbs, signedData); 3871 } else if(DEROidCompare(&certificate->_tbsSigAlg.oid, &oidMd2Rsa)) { 3872 signedDataLength = DER_MD_DIGEST_INFO_LEN; 3873 crtn = mdDigestInfo(WD_MD2, &certificate->_tbs, signedData); 3874 } else { 3875 secdebug("verify", "unsupported algorithm"); 3876 return errSecUnsupportedAlgorithm; 3877 } 3878 if (crtn) { 3879 secdebug("verify", "*DigestInfo returned: %d", crtn); 3880 /* FIXME: Do proper error code translation. */ 3881 return errSecUnsupportedAlgorithm; 3882 } 3883 3884 OSStatus status = SecKeyRawVerify(issuerKey, kSecPaddingPKCS1, 3885 signedData, signedDataLength, 3886 certificate->_signature.data, certificate->_signature.length); 3887 if (status) { 3888 secdebug("verify", "signature verify failed: %d", status); 3889 return errSecNotSigner; 3890 } 3891 3892 return errSecSuccess; 3893} 3894 3895static OSStatus _SecCertificateSetParent(SecCertificateRef certificate, 3896 SecCertificateRef issuer, bool signatureCheckOnly) { 3897 check(issuer); 3898 if (certificate->_parent) { 3899 /* Setting a certificates issuer twice is only allowed if the new 3900 issuer is equal to the current one. */ 3901 return issuer && CFEqual(certificate->_parent, issuer); 3902 } 3903 3904#if 0 3905 OSStatus status = SecCertificateIsIssuedBy(certificate, issuer, 3906 signatureCheckOnly); 3907#else 3908 OSStatus status = errSecSuccess; 3909#endif 3910 if (!status) { 3911 if (CFEqual(certificate, issuer)) { 3912 /* We don't retain ourselves cause that would be bad mojo, 3913 however we do record that we are properly self signed. */ 3914 certificate->_isSelfSigned = kSecSelfSignedTrue; 3915 secdebug("cert", "set self as parent"); 3916 return errSecSuccess; 3917 } 3918 3919 CFRetain(issuer); 3920 certificate->_parent = issuer; 3921 certificate->_isSelfSigned = kSecSelfSignedFalse; 3922 } 3923 3924 return status; 3925} 3926 3927static bool SecCertificateIsSelfSigned(SecCertificateRef certificate) { 3928 if (certificate->_isSelfSigned == kSecSelfSignedUnknown) { 3929 certificate->_isSelfSigned = 3930 (SecCertificateIsIssuedBy(certificate, certificate, false) ? 3931 kSecSelfSignedTrue : kSecSelfSignedFalse); 3932 } 3933 3934 return certificate->_isSelfSigned == kSecSelfSignedTrue; 3935} 3936 3937/* Return true iff we were able to set our own parent from one of the 3938 certificates in other_certificates, return false otherwise. If 3939 signatureCheckOnly is true, we can skip the subject == issuer or 3940 authorityKeyIdentifier tests. */ 3941static bool SecCertificateSetParentFrom(SecCertificateRef certificate, 3942 CFArrayRef other_certificates, bool signatureCheckOnly) { 3943 CFIndex count = CFArrayGetCount(other_certificates); 3944 CFIndex ix; 3945 for (ix = 0; ix < count; ++ix) { 3946 SecCertificateRef candidate = (SecCertificateRef) 3947 CFArrayGetValueAtIndex(other_certificates, ix); 3948 if (_SecCertificateSetParent(certificate, candidate, 3949 signatureCheckOnly)) 3950 return true; 3951 } 3952 return false; 3953} 3954 3955/* Lookup the parent of certificate in the keychain and set it. */ 3956static bool SecCertificateFindParent(SecCertificateRef certificate) { 3957 /* FIXME: Search for things other than just subject of our issuer if we 3958 have a subjectID or authorityKeyIdentifier. */ 3959 CFDataRef normalizedIssuer = 3960 SecCertificateGetNormalizedIssuerContent(certificate); 3961 const void *keys[] = { 3962 kSecClass, 3963 kSecReturnRef, 3964 kSecMatchLimit, 3965 kSecAttrSubject 3966 }, 3967 *values[] = { 3968 kSecClassCertificate, 3969 kCFBooleanTrue, 3970 kSecMatchLimitAll, 3971 normalizedIssuer 3972 }; 3973 CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, 3974 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 3975 CFTypeRef results; 3976 OSStatus status = SecItemCopyMatching(query, &results); 3977 CFRelease(query); 3978 if (status) { 3979 secdebug("cert", "SecCertificateFindParent: SecItemCopyMatching: %d", 3980 status); 3981 return false; 3982 } 3983 CFArrayRef certs = (CFArrayRef)results; 3984 /* Since we already know the certificates we are providing as candidates 3985 have been checked for subject matching, we can ask 3986 SecCertificateSetParentFrom to skip everything except the signature 3987 checks. */ 3988 bool result = SecCertificateSetParentFrom(certificate, certs, true); 3989 CFRelease(certs); 3990 return result; 3991} 3992 3993OSStatus SecCertificateCompleteChain(SecCertificateRef certificate, 3994 CFArrayRef other_certificates) { 3995 for (;;) { 3996 if (certificate->_parent == NULL) { 3997 if (SecCertificateIsSelfSigned(certificate)) 3998 return errSecSuccess; 3999 if (!other_certificates || 4000 !SecCertificateSetParentFrom(certificate, other_certificates,\ 4001 false)) { 4002 if (!SecCertificateFindParent(certificate)) 4003 return errSecIssuerNotFound; 4004 } 4005 } 4006 certificate = certificate->_parent; 4007 } 4008} 4009#endif 4010 4011static OSStatus appendIPAddressesFromGeneralNames(void *context, 4012 SecCEGeneralNameType gnType, const DERItem *generalName) { 4013 CFMutableArrayRef ipAddresses = (CFMutableArrayRef)context; 4014 if (gnType == GNT_IPAddress) { 4015 CFStringRef string = copyIPAddressContentDescription( 4016 kCFAllocatorDefault, generalName); 4017 if (string) { 4018 CFArrayAppendValue(ipAddresses, string); 4019 CFRelease(string); 4020 } else { 4021 return errSecInvalidCertificate; 4022 } 4023 } 4024 return errSecSuccess; 4025} 4026 4027CFArrayRef SecCertificateCopyIPAddresses(SecCertificateRef certificate) { 4028 /* These can only exist in the subject alt name. */ 4029 if (!certificate->_subjectAltName) 4030 return NULL; 4031 4032 CFMutableArrayRef ipAddresses = CFArrayCreateMutable(kCFAllocatorDefault, 4033 0, &kCFTypeArrayCallBacks); 4034 OSStatus status = parseGeneralNames(&certificate->_subjectAltName->extnValue, 4035 ipAddresses, appendIPAddressesFromGeneralNames); 4036 if (status || CFArrayGetCount(ipAddresses) == 0) { 4037 CFRelease(ipAddresses); 4038 ipAddresses = NULL; 4039 } 4040 return ipAddresses; 4041} 4042 4043static OSStatus appendDNSNamesFromGeneralNames(void *context, SecCEGeneralNameType gnType, 4044 const DERItem *generalName) { 4045 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context; 4046 if (gnType == GNT_DNSName) { 4047 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, 4048 generalName->data, generalName->length, 4049 kCFStringEncodingUTF8, FALSE); 4050 if (string) { 4051 CFArrayAppendValue(dnsNames, string); 4052 CFRelease(string); 4053 } else { 4054 return errSecInvalidCertificate; 4055 } 4056 } 4057 return errSecSuccess; 4058} 4059 4060/* Return true if the passed in string matches the 4061 Preferred name syntax from sections 2.3.1. in RFC 1035. 4062 With the added check that we disallow empty dns names. 4063 Also in order to support wildcard DNSNames we allow for the '*' 4064 character anywhere in a dns component where we currently allow 4065 a letter. 4066 4067 <domain> ::= <subdomain> | " " 4068 4069 <subdomain> ::= <label> | <subdomain> "." <label> 4070 4071 <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ] 4072 4073 <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str> 4074 4075 <let-dig-hyp> ::= <let-dig> | "-" 4076 4077 <let-dig> ::= <letter> | <digit> 4078 4079 <letter> ::= any one of the 52 alphabetic characters A through Z in 4080 upper case and a through z in lower case 4081 4082 <digit> ::= any one of the ten digits 0 through 9 4083 */ 4084static bool isDNSName(CFStringRef string) { 4085 CFStringInlineBuffer buf; 4086 CFIndex ix, labelLength = 0, length = CFStringGetLength(string); 4087 /* From RFC 1035 2.3.4. Size limits: 4088 labels 63 octets or less 4089 names 255 octets or less */ 4090 require_quiet(length <= 255, notDNS); 4091 CFRange range = { 0, length }; 4092 CFStringInitInlineBuffer(string, &buf, range); 4093 enum { 4094 kDNSStateInital, 4095 kDNSStateAfterDot, 4096 kDNSStateAfterAlpha, 4097 kDNSStateAfterDigit, 4098 kDNSStateAfterDash, 4099 } state = kDNSStateInital; 4100 4101 for (ix = 0; ix < length; ++ix) { 4102 UniChar ch = CFStringGetCharacterFromInlineBuffer(&buf, ix); 4103 labelLength++; 4104 if (ch == '.') { 4105 require_quiet(labelLength <= 64 && 4106 (state == kDNSStateAfterAlpha || state == kDNSStateAfterDigit), 4107 notDNS); 4108 state = kDNSStateAfterDot; 4109 labelLength = 0; 4110 } else if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || 4111 ch == '*') { 4112 state = kDNSStateAfterAlpha; 4113 } else if ('0' <= ch && ch <= '9') { 4114#if 0 4115 /* The requirement for labels to start with a letter was 4116 dropped so we don't check this anymore. */ 4117 require_quiet(state == kDNSStateAfterAlpha || 4118 state == kDNSStateAfterDigit || 4119 state == kDNSStateAfterDash, notDNS); 4120#endif 4121 state = kDNSStateAfterDigit; 4122 } else if (ch == '-') { 4123 require_quiet(state == kDNSStateAfterAlpha || 4124 state == kDNSStateAfterDigit || 4125 state == kDNSStateAfterDash, notDNS); 4126 state = kDNSStateAfterDash; 4127 } else { 4128 goto notDNS; 4129 } 4130 } 4131 4132 /* We don't allow a dns name to end in a dot or dash. */ 4133 require_quiet(labelLength <= 63 && 4134 (state == kDNSStateAfterAlpha || state == kDNSStateAfterDigit), 4135 notDNS); 4136 4137 return true; 4138notDNS: 4139 return false; 4140} 4141 4142static OSStatus appendDNSNamesFromX501Name(void *context, const DERItem *type, 4143 const DERItem *value, CFIndex rdnIX) { 4144 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context; 4145 if (DEROidCompare(type, &oidCommonName)) { 4146 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault, 4147 value, true); 4148 if (string) { 4149 if (isDNSName(string)) { 4150 /* We found a common name that is formatted like a valid 4151 dns name. */ 4152 CFArrayAppendValue(dnsNames, string); 4153 } 4154 CFRelease(string); 4155 } else { 4156 return errSecInvalidCertificate; 4157 } 4158 } 4159 return errSecSuccess; 4160} 4161 4162/* Not everything returned by this function is going to be a proper DNS name, 4163 we also return the certificates common name entries from the subject, 4164 assuming they look like dns names as specified in RFC 1035. */ 4165CFArrayRef SecCertificateCopyDNSNames(SecCertificateRef certificate) { 4166 /* These can exist in the subject alt name or in the subject. */ 4167 CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault, 4168 0, &kCFTypeArrayCallBacks); 4169 OSStatus status = errSecSuccess; 4170 if (certificate->_subjectAltName) { 4171 status = parseGeneralNames(&certificate->_subjectAltName->extnValue, 4172 dnsNames, appendDNSNamesFromGeneralNames); 4173 } 4174 /* RFC 2818 section 3.1. Server Identity 4175 [...] 4176 If a subjectAltName extension of type dNSName is present, that MUST 4177 be used as the identity. Otherwise, the (most specific) Common Name 4178 field in the Subject field of the certificate MUST be used. Although 4179 the use of the Common Name is existing practice, it is deprecated and 4180 Certification Authorities are encouraged to use the dNSName instead. 4181 [...] 4182 4183 This implies that if we found 1 or more DNSNames in the 4184 subjectAltName, we should not use the Common Name of the subject as 4185 a DNSName. 4186 */ 4187 if (!status && CFArrayGetCount(dnsNames) == 0) { 4188 status = parseX501NameContent(&certificate->_subject, dnsNames, 4189 appendDNSNamesFromX501Name); 4190 } 4191 if (status || CFArrayGetCount(dnsNames) == 0) { 4192 CFRelease(dnsNames); 4193 dnsNames = NULL; 4194 } 4195 return dnsNames; 4196} 4197 4198static OSStatus appendRFC822NamesFromGeneralNames(void *context, 4199 SecCEGeneralNameType gnType, const DERItem *generalName) { 4200 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context; 4201 if (gnType == GNT_RFC822Name) { 4202 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, 4203 generalName->data, generalName->length, 4204 kCFStringEncodingASCII, FALSE); 4205 if (string) { 4206 CFArrayAppendValue(dnsNames, string); 4207 CFRelease(string); 4208 } else { 4209 return errSecInvalidCertificate; 4210 } 4211 } 4212 return errSecSuccess; 4213} 4214 4215static OSStatus appendRFC822NamesFromX501Name(void *context, const DERItem *type, 4216 const DERItem *value, CFIndex rdnIX) { 4217 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context; 4218 if (DEROidCompare(type, &oidEmailAddress)) { 4219 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault, 4220 value, true); 4221 if (string) { 4222 CFArrayAppendValue(dnsNames, string); 4223 CFRelease(string); 4224 } else { 4225 return errSecInvalidCertificate; 4226 } 4227 } 4228 return errSecSuccess; 4229} 4230 4231CFArrayRef SecCertificateCopyRFC822Names(SecCertificateRef certificate) { 4232 /* These can exist in the subject alt name or in the subject. */ 4233 CFMutableArrayRef rfc822Names = CFArrayCreateMutable(kCFAllocatorDefault, 4234 0, &kCFTypeArrayCallBacks); 4235 OSStatus status = errSecSuccess; 4236 if (certificate->_subjectAltName) { 4237 status = parseGeneralNames(&certificate->_subjectAltName->extnValue, 4238 rfc822Names, appendRFC822NamesFromGeneralNames); 4239 } 4240 if (!status) { 4241 status = parseX501NameContent(&certificate->_subject, rfc822Names, 4242 appendRFC822NamesFromX501Name); 4243 } 4244 if (status || CFArrayGetCount(rfc822Names) == 0) { 4245 CFRelease(rfc822Names); 4246 rfc822Names = NULL; 4247 } 4248 return rfc822Names; 4249} 4250 4251static OSStatus appendCommonNamesFromX501Name(void *context, 4252 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 4253 CFMutableArrayRef commonNames = (CFMutableArrayRef)context; 4254 if (DEROidCompare(type, &oidCommonName)) { 4255 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault, 4256 value, true); 4257 if (string) { 4258 CFArrayAppendValue(commonNames, string); 4259 CFRelease(string); 4260 } else { 4261 return errSecInvalidCertificate; 4262 } 4263 } 4264 return errSecSuccess; 4265} 4266 4267CFArrayRef SecCertificateCopyCommonNames(SecCertificateRef certificate) { 4268 CFMutableArrayRef commonNames = CFArrayCreateMutable(kCFAllocatorDefault, 4269 0, &kCFTypeArrayCallBacks); 4270 OSStatus status; 4271 status = parseX501NameContent(&certificate->_subject, commonNames, 4272 appendCommonNamesFromX501Name); 4273 if (status || CFArrayGetCount(commonNames) == 0) { 4274 CFRelease(commonNames); 4275 commonNames = NULL; 4276 } 4277 return commonNames; 4278} 4279 4280static OSStatus appendOrganizationFromX501Name(void *context, 4281 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 4282 CFMutableArrayRef organization = (CFMutableArrayRef)context; 4283 if (DEROidCompare(type, &oidOrganizationName)) { 4284 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault, 4285 value, true); 4286 if (string) { 4287 CFArrayAppendValue(organization, string); 4288 CFRelease(string); 4289 } else { 4290 return errSecInvalidCertificate; 4291 } 4292 } 4293 return errSecSuccess; 4294} 4295 4296CFArrayRef SecCertificateCopyOrganization(SecCertificateRef certificate) { 4297 CFMutableArrayRef organization = CFArrayCreateMutable(kCFAllocatorDefault, 4298 0, &kCFTypeArrayCallBacks); 4299 OSStatus status; 4300 status = parseX501NameContent(&certificate->_subject, organization, 4301 appendOrganizationFromX501Name); 4302 if (status || CFArrayGetCount(organization) == 0) { 4303 CFRelease(organization); 4304 organization = NULL; 4305 } 4306 return organization; 4307} 4308 4309static OSStatus appendOrganizationalUnitFromX501Name(void *context, 4310 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 4311 CFMutableArrayRef organizationalUnit = (CFMutableArrayRef)context; 4312 if (DEROidCompare(type, &oidOrganizationalUnitName)) { 4313 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault, 4314 value, true); 4315 if (string) { 4316 CFArrayAppendValue(organizationalUnit, string); 4317 CFRelease(string); 4318 } else { 4319 return errSecInvalidCertificate; 4320 } 4321 } 4322 return errSecSuccess; 4323} 4324 4325CFArrayRef SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate) { 4326 CFMutableArrayRef organizationalUnit = CFArrayCreateMutable(kCFAllocatorDefault, 4327 0, &kCFTypeArrayCallBacks); 4328 OSStatus status; 4329 status = parseX501NameContent(&certificate->_subject, organizationalUnit, 4330 appendOrganizationalUnitFromX501Name); 4331 if (status || CFArrayGetCount(organizationalUnit) == 0) { 4332 CFRelease(organizationalUnit); 4333 organizationalUnit = NULL; 4334 } 4335 return organizationalUnit; 4336} 4337 4338const SecCEBasicConstraints * 4339SecCertificateGetBasicConstraints(SecCertificateRef certificate) { 4340 if (certificate->_basicConstraints.present) 4341 return &certificate->_basicConstraints; 4342 else 4343 return NULL; 4344} 4345 4346const SecCEPolicyConstraints * 4347SecCertificateGetPolicyConstraints(SecCertificateRef certificate) { 4348 if (certificate->_policyConstraints.present) 4349 return &certificate->_policyConstraints; 4350 else 4351 return NULL; 4352} 4353 4354CFDictionaryRef 4355SecCertificateGetPolicyMappings(SecCertificateRef certificate) { 4356 return certificate->_policyMappings; 4357} 4358 4359const SecCECertificatePolicies * 4360SecCertificateGetCertificatePolicies(SecCertificateRef certificate) { 4361 if (certificate->_certificatePolicies.present) 4362 return &certificate->_certificatePolicies; 4363 else 4364 return NULL; 4365} 4366 4367uint32_t 4368SecCertificateGetInhibitAnyPolicySkipCerts(SecCertificateRef certificate) { 4369 return certificate->_inhibitAnyPolicySkipCerts; 4370} 4371 4372static OSStatus appendNTPrincipalNamesFromGeneralNames(void *context, 4373 SecCEGeneralNameType gnType, const DERItem *generalName) { 4374 CFMutableArrayRef ntPrincipalNames = (CFMutableArrayRef)context; 4375 if (gnType == GNT_OtherName) { 4376 DEROtherName on; 4377 DERReturn drtn = DERParseSequenceContent(generalName, 4378 DERNumOtherNameItemSpecs, DEROtherNameItemSpecs, 4379 &on, sizeof(on)); 4380 require_noerr_quiet(drtn, badDER); 4381 if (DEROidCompare(&on.typeIdentifier, &oidMSNTPrincipalName)) { 4382 CFStringRef string; 4383 require_quiet(string = copyDERThingDescription(kCFAllocatorDefault, 4384 &on.value, true), badDER); 4385 CFArrayAppendValue(ntPrincipalNames, string); 4386 CFRelease(string); 4387 } 4388 } 4389 return errSecSuccess; 4390 4391badDER: 4392 return errSecInvalidCertificate; 4393 4394} 4395 4396CFArrayRef SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate) { 4397 CFMutableArrayRef ntPrincipalNames = CFArrayCreateMutable(kCFAllocatorDefault, 4398 0, &kCFTypeArrayCallBacks); 4399 OSStatus status = errSecSuccess; 4400 if (certificate->_subjectAltName) { 4401 status = parseGeneralNames(&certificate->_subjectAltName->extnValue, 4402 ntPrincipalNames, appendNTPrincipalNamesFromGeneralNames); 4403 } 4404 if (status || CFArrayGetCount(ntPrincipalNames) == 0) { 4405 CFRelease(ntPrincipalNames); 4406 ntPrincipalNames = NULL; 4407 } 4408 return ntPrincipalNames; 4409} 4410 4411static OSStatus appendToRFC2253String(void *context, 4412 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 4413 CFMutableStringRef string = (CFMutableStringRef)context; 4414 /* 4415 CN commonName 4416 L localityName 4417 ST stateOrProvinceName 4418 O organizationName 4419 OU organizationalUnitName 4420 C countryName 4421 STREET streetAddress 4422 DC domainComponent 4423 UID userid 4424 */ 4425 /* Prepend a + if this is not the first RDN in an RDN set. 4426 Otherwise prepend a , if this is not the first RDN. */ 4427 if (rdnIX > 0) 4428 CFStringAppend(string, CFSTR("+")); 4429 else if (CFStringGetLength(string)) { 4430 CFStringAppend(string, CFSTR(",")); 4431 } 4432 4433 CFStringRef label, oid = NULL; 4434 /* @@@ Consider changing this to a dictionary lookup keyed by the 4435 decimal representation. */ 4436 if (DEROidCompare(type, &oidCommonName)) { 4437 label = CFSTR("CN"); 4438 } else if (DEROidCompare(type, &oidLocalityName)) { 4439 label = CFSTR("L"); 4440 } else if (DEROidCompare(type, &oidStateOrProvinceName)) { 4441 label = CFSTR("ST"); 4442 } else if (DEROidCompare(type, &oidOrganizationName)) { 4443 label = CFSTR("O"); 4444 } else if (DEROidCompare(type, &oidOrganizationalUnitName)) { 4445 label = CFSTR("OU"); 4446 } else if (DEROidCompare(type, &oidCountryName)) { 4447 label = CFSTR("C"); 4448#if 0 4449 } else if (DEROidCompare(type, &oidStreetAddress)) { 4450 label = CFSTR("STREET"); 4451 } else if (DEROidCompare(type, &oidDomainComponent)) { 4452 label = CFSTR("DC"); 4453 } else if (DEROidCompare(type, &oidUserID)) { 4454 label = CFSTR("UID"); 4455#endif 4456 } else { 4457 label = oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, type); 4458 } 4459 4460 CFStringAppend(string, label); 4461 CFStringAppend(string, CFSTR("=")); 4462 CFStringRef raw = NULL; 4463 if (!oid) 4464 raw = copyDERThingDescription(kCFAllocatorDefault, value, true); 4465 4466 if (raw) { 4467 /* Append raw to string while escaping: 4468 a space or "#" character occurring at the beginning of the string 4469 a space character occurring at the end of the string 4470 one of the characters ",", "+", """, "\", "<", ">" or ";" 4471 */ 4472 CFStringInlineBuffer buffer; 4473 CFIndex ix, length = CFStringGetLength(raw); 4474 CFRange range = { 0, length }; 4475 CFStringInitInlineBuffer(raw, &buffer, range); 4476 for (ix = 0; ix < length; ++ix) { 4477 UniChar ch = CFStringGetCharacterFromInlineBuffer(&buffer, ix); 4478 if (ch < 0x20) { 4479 CFStringAppendFormat(string, NULL, CFSTR("\\%02X"), ch); 4480 } else if (ch == ',' || ch == '+' || ch == '"' || ch == '\\' || 4481 ch == '<' || ch == '>' || ch == ';' || 4482 (ch == ' ' && (ix == 0 || ix == length - 1)) || 4483 (ch == '#' && ix == 0)) { 4484 UniChar chars[] = { '\\', ch }; 4485 CFStringAppendCharacters(string, chars, 2); 4486 } else { 4487 CFStringAppendCharacters(string, &ch, 1); 4488 } 4489 } 4490 CFRelease(raw); 4491 } else { 4492 /* Append the value in hex. */ 4493 CFStringAppend(string, CFSTR("#")); 4494 DERSize ix; 4495 for (ix = 0; ix < value->length; ++ix) 4496 CFStringAppendFormat(string, NULL, CFSTR("%02X"), value->data[ix]); 4497 } 4498 4499 CFReleaseSafe(oid); 4500 4501 return errSecSuccess; 4502} 4503 4504CFStringRef SecCertificateCopySubjectString(SecCertificateRef certificate) { 4505 CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0); 4506 OSStatus status = parseX501NameContent(&certificate->_subject, string, appendToRFC2253String); 4507 if (status || CFStringGetLength(string) == 0) { 4508 CFRelease(string); 4509 string = NULL; 4510 } 4511 return string; 4512} 4513 4514static OSStatus appendToCompanyNameString(void *context, 4515 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 4516 CFMutableStringRef string = (CFMutableStringRef)context; 4517 if (CFStringGetLength(string) != 0) 4518 return errSecSuccess; 4519 4520 if (!DEROidCompare(type, &oidOrganizationName)) 4521 return errSecSuccess; 4522 4523 CFStringRef raw; 4524 raw = copyDERThingDescription(kCFAllocatorDefault, value, true); 4525 if (!raw) 4526 return errSecSuccess; 4527 CFStringAppend(string, raw); 4528 CFRelease(raw); 4529 4530 return errSecSuccess; 4531} 4532 4533CFStringRef SecCertificateCopyCompanyName(SecCertificateRef certificate) { 4534 CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0); 4535 OSStatus status = parseX501NameContent(&certificate->_subject, string, 4536 appendToCompanyNameString); 4537 if (status || CFStringGetLength(string) == 0) { 4538 CFRelease(string); 4539 string = NULL; 4540 } 4541 return string; 4542} 4543 4544static CFDataRef SecDERItemCopySequence(DERItem *content) { 4545 DERSize seq_len_length = DERLengthOfLength(content->length); 4546 size_t sequence_length = 1 + seq_len_length + content->length; 4547 CFMutableDataRef sequence = CFDataCreateMutable(kCFAllocatorDefault, 4548 sequence_length); 4549 CFDataSetLength(sequence, sequence_length); 4550 uint8_t *sequence_ptr = CFDataGetMutableBytePtr(sequence); 4551 *sequence_ptr++ = 0x30; /* ASN1_CONSTR_SEQUENCE */ 4552 require_noerr_quiet(DEREncodeLength(content->length, 4553 sequence_ptr, &seq_len_length), out); 4554 sequence_ptr += seq_len_length; 4555 memcpy(sequence_ptr, content->data, content->length); 4556 return sequence; 4557out: 4558 CFReleaseSafe(sequence); 4559 return NULL; 4560} 4561 4562CFDataRef SecCertificateCopyIssuerSequence( 4563 SecCertificateRef certificate) { 4564 return SecDERItemCopySequence(&certificate->_issuer); 4565} 4566 4567CFDataRef SecCertificateCopySubjectSequence( 4568 SecCertificateRef certificate) { 4569 return SecDERItemCopySequence(&certificate->_subject); 4570} 4571 4572const DERAlgorithmId *SecCertificateGetPublicKeyAlgorithm( 4573 SecCertificateRef certificate) { 4574 return &certificate->_algId; 4575} 4576 4577const DERItem *SecCertificateGetPublicKeyData(SecCertificateRef certificate) { 4578 return &certificate->_pubKeyDER; 4579} 4580 4581SecKeyRef SecCertificateCopyPublicKey(SecCertificateRef certificate) { 4582 const DERAlgorithmId *algId = 4583 SecCertificateGetPublicKeyAlgorithm(certificate); 4584 const DERItem *keyData = SecCertificateGetPublicKeyData(certificate); 4585 const DERItem *params = NULL; 4586 if (algId->params.length != 0) { 4587 params = &algId->params; 4588 } 4589 SecAsn1Oid oid1 = { .Data = algId->oid.data, .Length = algId->oid.length }; 4590 SecAsn1Item params1 = { 4591 .Data = params ? params->data : NULL, 4592 .Length = params ? params->length : 0 4593 }; 4594 SecAsn1Item keyData1 = { 4595 .Data = keyData ? keyData->data : NULL, 4596 .Length = keyData ? keyData->length : 0 4597 }; 4598 return SecKeyCreatePublicFromDER(kCFAllocatorDefault, &oid1, ¶ms1, 4599 &keyData1); 4600} 4601 4602CFDataRef SecCertificateGetSHA1Digest(SecCertificateRef certificate) { 4603 if (!certificate->_sha1Digest) { 4604 certificate->_sha1Digest = 4605 SecSHA1DigestCreate(CFGetAllocator(certificate), 4606 certificate->_der.data, certificate->_der.length); 4607 } 4608 4609 return certificate->_sha1Digest; 4610} 4611 4612CFDataRef SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate) { 4613 CFDataRef digest = NULL; 4614 CFDataRef issuer = SecCertificateCopyIssuerSequence(certificate); 4615 if (issuer) { 4616 digest = SecSHA1DigestCreate(kCFAllocatorDefault, 4617 CFDataGetBytePtr(issuer), CFDataGetLength(issuer)); 4618 CFRelease(issuer); 4619 } 4620 return digest; 4621} 4622 4623CFDataRef SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate) { 4624 return SecSHA1DigestCreate(CFGetAllocator(certificate), 4625 certificate->_pubKeyDER.data, certificate->_pubKeyDER.length); 4626} 4627 4628CFDataRef SecCertificateGetAuthorityKeyID(SecCertificateRef certificate) { 4629 if (!certificate->_authorityKeyID && 4630 certificate->_authorityKeyIdentifier.length) { 4631 certificate->_authorityKeyID = CFDataCreate(kCFAllocatorDefault, 4632 certificate->_authorityKeyIdentifier.data, 4633 certificate->_authorityKeyIdentifier.length); 4634 } 4635 4636 return certificate->_authorityKeyID; 4637} 4638 4639CFDataRef SecCertificateGetSubjectKeyID(SecCertificateRef certificate) { 4640 if (!certificate->_subjectKeyID && 4641 certificate->_subjectKeyIdentifier.length) { 4642 certificate->_subjectKeyID = CFDataCreate(kCFAllocatorDefault, 4643 certificate->_subjectKeyIdentifier.data, 4644 certificate->_subjectKeyIdentifier.length); 4645 } 4646 4647 return certificate->_subjectKeyID; 4648} 4649 4650CFArrayRef SecCertificateGetCRLDistributionPoints(SecCertificateRef certificate) { 4651 return certificate->_crlDistributionPoints; 4652} 4653 4654CFArrayRef SecCertificateGetOCSPResponders(SecCertificateRef certificate) { 4655 return certificate->_ocspResponders; 4656} 4657 4658CFArrayRef SecCertificateGetCAIssuers(SecCertificateRef certificate) { 4659 return certificate->_caIssuers; 4660} 4661 4662bool SecCertificateHasCriticalSubjectAltName(SecCertificateRef certificate) { 4663 return certificate->_subjectAltName && 4664 certificate->_subjectAltName->critical; 4665} 4666 4667bool SecCertificateHasSubject(SecCertificateRef certificate) { 4668 /* Since the _subject field is the content of the subject and not the 4669 whole thing, we can simply check for a 0 length subject here. */ 4670 return certificate->_subject.length != 0; 4671} 4672 4673bool SecCertificateHasUnknownCriticalExtension(SecCertificateRef certificate) { 4674 return certificate->_foundUnknownCriticalExtension; 4675} 4676 4677/* Private API functions. */ 4678void SecCertificateShow(SecCertificateRef certificate) { 4679 check(certificate); 4680 fprintf(stderr, "SecCertificate instance %p:\n", certificate); 4681 fprintf(stderr, "\n"); 4682} 4683 4684#ifndef STANDALONE 4685CFDictionaryRef SecCertificateCopyAttributeDictionary( 4686 SecCertificateRef certificate) { 4687 CFAllocatorRef allocator = CFGetAllocator(certificate); 4688 CFNumberRef certificateType, certificateEncoding; 4689 CFStringRef label, alias; 4690 CFDataRef skid, pubKeyDigest, certData; 4691 CFDictionaryRef dict = NULL; 4692 4693 DICT_DECLARE(11); 4694 4695 /* CSSM_CERT_X_509v1, CSSM_CERT_X_509v2 or CSSM_CERT_X_509v3 */ 4696 SInt32 ctv = certificate->_version + 1; 4697 SInt32 cev = 3; /* CSSM_CERT_ENCODING_DER */ 4698 certificateType = CFNumberCreate(allocator, kCFNumberSInt32Type, &ctv); 4699 certificateEncoding = CFNumberCreate(allocator, kCFNumberSInt32Type, &cev); 4700 certData = SecCertificateCopyData(certificate); 4701 skid = SecCertificateGetSubjectKeyID(certificate); 4702 pubKeyDigest = SecSHA1DigestCreate(allocator, certificate->_pubKeyDER.data, 4703 certificate->_pubKeyDER.length); 4704#if 0 4705 /* We still need to figure out how to deal with multi valued attributes. */ 4706 alias = SecCertificateCopyRFC822Names(certificate); 4707 label = SecCertificateCopySubjectSummary(certificate); 4708#else 4709 alias = NULL; 4710 label = NULL; 4711#endif 4712 4713 DICT_ADDPAIR(kSecClass, kSecClassCertificate); 4714 DICT_ADDPAIR(kSecAttrCertificateType, certificateType); 4715 DICT_ADDPAIR(kSecAttrCertificateEncoding, certificateEncoding); 4716 if (label) 4717 DICT_ADDPAIR(kSecAttrLabel, label); 4718 if (alias) 4719 DICT_ADDPAIR(kSecAttrAlias, alias); 4720 DICT_ADDPAIR(kSecAttrSubject, certificate->_normalizedSubject); 4721 DICT_ADDPAIR(kSecAttrIssuer, certificate->_normalizedIssuer); 4722 DICT_ADDPAIR(kSecAttrSerialNumber, certificate->_serialNumber); 4723 if (skid) 4724 DICT_ADDPAIR(kSecAttrSubjectKeyID, skid); 4725 DICT_ADDPAIR(kSecAttrPublicKeyHash, pubKeyDigest); 4726 DICT_ADDPAIR(kSecValueData, certData); 4727 dict = DICT_CREATE(allocator); 4728 4729 CFReleaseSafe(label); 4730 CFReleaseSafe(pubKeyDigest); 4731 CFReleaseSafe(certData); 4732 CFReleaseSafe(certificateEncoding); 4733 CFReleaseSafe(certificateType); 4734 4735 return dict; 4736} 4737 4738SecCertificateRef SecCertificateCreateFromAttributeDictionary( 4739 CFDictionaryRef refAttributes) { 4740 /* @@@ Support having an allocator in refAttributes. */ 4741 CFAllocatorRef allocator = NULL; 4742 CFDataRef data = CFDictionaryGetValue(refAttributes, kSecValueData); 4743 return data ? SecCertificateCreateWithData(allocator, data) : NULL; 4744} 4745#endif 4746 4747bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate) { 4748 bool result = false; 4749 SecKeyRef publicKey; 4750 require(publicKey = SecCertificateCopyPublicKey(certificate), out); 4751 CFDataRef normalizedIssuer = 4752 SecCertificateGetNormalizedIssuerContent(certificate); 4753 CFDataRef normalizedSubject = 4754 SecCertificateGetNormalizedSubjectContent(certificate); 4755 require_quiet(normalizedIssuer && normalizedSubject && 4756 CFEqual(normalizedIssuer, normalizedSubject), out); 4757 4758 CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(certificate); 4759 CFDataRef subjectKeyID = SecCertificateGetSubjectKeyID(certificate); 4760 if (authorityKeyID) { 4761 require_quiet(subjectKeyID && CFEqual(subjectKeyID, authorityKeyID), out); 4762 } 4763 4764 if (SecCertificateVersion(certificate) >= 3) { 4765 const SecCEBasicConstraints *basicConstraints = SecCertificateGetBasicConstraints(certificate); 4766 require_quiet(basicConstraints && basicConstraints->isCA, out); 4767 require_noerr_quiet(SecCertificateIsSignedBy(certificate, publicKey), out); 4768 } 4769 4770 result = true; 4771out: 4772 CFReleaseSafe(publicKey); 4773 return result; 4774} 4775 4776SecKeyUsage SecCertificateGetKeyUsage(SecCertificateRef certificate) { 4777 return certificate->_keyUsage; 4778} 4779 4780CFArrayRef SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate) 4781{ 4782 CFMutableArrayRef extended_key_usage_oids = 4783 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 4784 require_quiet(extended_key_usage_oids, out); 4785 int ix; 4786 for (ix = 0; ix < certificate->_extensionCount; ++ix) { 4787 const SecCertificateExtension *extn = &certificate->_extensions[ix]; 4788 if (extn->extnID.length == oidExtendedKeyUsage.length && 4789 !memcmp(extn->extnID.data, oidExtendedKeyUsage.data, extn->extnID.length)) { 4790 DERTag tag; 4791 DERSequence derSeq; 4792 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &derSeq); 4793 require_noerr_quiet(drtn, out); 4794 require_quiet(tag == ASN1_CONSTR_SEQUENCE, out); 4795 DERDecodedInfo currDecoded; 4796 4797 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) { 4798 require_quiet(currDecoded.tag == ASN1_OBJECT_ID, out); 4799 CFDataRef oid = CFDataCreate(kCFAllocatorDefault, 4800 currDecoded.content.data, currDecoded.content.length); 4801 if (oid) { 4802 CFArrayAppendValue(extended_key_usage_oids, oid); 4803 CFRelease(oid); 4804 } 4805 } 4806 require_quiet(drtn == DR_EndOfSequence, out); 4807 return extended_key_usage_oids; 4808 } 4809 } 4810out: 4811 CFReleaseSafe(extended_key_usage_oids); 4812 return NULL; 4813} 4814 4815static bool matches_expected(DERItem der, CFTypeRef expected) { 4816 if (der.length > 1) { 4817 DERDecodedInfo decoded; 4818 DERDecodeItem(&der, &decoded); 4819 switch (decoded.tag) { 4820 case ASN1_NULL: 4821 { 4822 return decoded.content.length == 0 && expected == NULL; 4823 } 4824 break; 4825 4826 case ASN1_UTF8_STRING: { 4827 if (isString(expected)) { 4828 CFStringRef expectedString = (CFStringRef) expected; 4829 CFStringRef itemString = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, decoded.content.data, decoded.content.length, kCFStringEncodingUTF8, false, kCFAllocatorNull); 4830 4831 bool result = (kCFCompareEqualTo == CFStringCompare(expectedString, itemString, 0)); 4832 CFReleaseNull(itemString); 4833 return result; 4834 } 4835 } 4836 break; 4837 4838 case ASN1_OCTET_STRING: { 4839 if (isData(expected)) { 4840 CFDataRef expectedData = (CFDataRef) expected; 4841 CFDataRef itemData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, decoded.content.data, decoded.content.length, kCFAllocatorNull); 4842 4843 bool result = CFEqual(expectedData, itemData); 4844 CFReleaseNull(itemData); 4845 return result; 4846 } 4847 } 4848 break; 4849 4850 case ASN1_INTEGER: { 4851 SInt32 expected_value = 0; 4852 if (isString(expected)) 4853 { 4854 CFStringRef aStr = (CFStringRef)expected; 4855 expected_value = CFStringGetIntValue(aStr); 4856 } 4857 else if (isNumber(expected)) 4858 { 4859 CFNumberGetValue(expected, kCFNumberSInt32Type, &expected_value); 4860 } 4861 4862 uint32_t num_value = 0; 4863 if (!DERParseInteger(&decoded.content, &num_value)) 4864 { 4865 return ((uint32_t)expected_value == num_value); 4866 } 4867 } 4868 break; 4869 4870 default: 4871 break; 4872 } 4873 } 4874 4875 return false; 4876} 4877 4878static bool cert_contains_marker_extension_value(SecCertificateRef certificate, CFDataRef oid, CFTypeRef expectedValue) 4879{ 4880 CFIndex ix; 4881 const uint8_t *oid_data = CFDataGetBytePtr(oid); 4882 size_t oid_len = CFDataGetLength(oid); 4883 4884 for (ix = 0; ix < certificate->_extensionCount; ++ix) { 4885 const SecCertificateExtension *extn = &certificate->_extensions[ix]; 4886 if (extn->extnID.length == oid_len 4887 && !memcmp(extn->extnID.data, oid_data, extn->extnID.length)) 4888 { 4889 return matches_expected(extn->extnValue, expectedValue); 4890 } 4891 } 4892 return false; 4893} 4894 4895static bool cert_contains_marker_extension(SecCertificateRef certificate, CFTypeRef oid) 4896{ 4897 return cert_contains_marker_extension_value(certificate, oid, NULL); 4898} 4899 4900struct search_context { 4901 bool found; 4902 SecCertificateRef certificate; 4903}; 4904 4905static bool GetDecimalValueOfString(CFStringRef string, uint32_t* value) 4906{ 4907 CFCharacterSetRef nonDecimalDigit = CFCharacterSetCreateInvertedSet(NULL, CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit)); 4908 bool result = false; 4909 4910 if ( CFStringGetLength(string) > 0 4911 && !CFStringFindCharacterFromSet(string, nonDecimalDigit, CFRangeMake(0, CFStringGetLength(string)), kCFCompareForcedOrdering, NULL)) 4912 { 4913 if (value) 4914 *value = CFStringGetIntValue(string); 4915 result = true; 4916 } 4917 4918 CFReleaseNull(nonDecimalDigit); 4919 4920 return result; 4921} 4922 4923static CFDataRef CreateOidDataFromString(CFAllocatorRef allocator, CFStringRef string) 4924{ 4925 CFMutableDataRef currentResult = NULL; 4926 CFDataRef encodedResult = NULL; 4927 4928 CFArrayRef parts = NULL; 4929 CFIndex count = 0; 4930 4931 if (!string) 4932 goto exit; 4933 4934 parts = CFStringCreateArrayBySeparatingStrings(NULL, string, CFSTR(".")); 4935 4936 if (!parts) 4937 goto exit; 4938 4939 count = CFArrayGetCount(parts); 4940 if (count == 0) 4941 goto exit; 4942 4943 // assume no more than 5 bytes needed to represent any part of the oid, 4944 // since we limit parts to 32-bit values, 4945 // but the first two parts only need 1 byte 4946 currentResult = CFDataCreateMutable(allocator, 1+(count-2)*5); 4947 4948 CFStringRef part; 4949 uint32_t x; 4950 uint8_t firstByte; 4951 4952 part = CFArrayGetValueAtIndex(parts, 0); 4953 4954 if (!GetDecimalValueOfString(part, &x) || x > 6) 4955 goto exit; 4956 4957 firstByte = x * 40; 4958 4959 4960 if (count > 1) { 4961 part = CFArrayGetValueAtIndex(parts, 1); 4962 4963 if (!GetDecimalValueOfString(part, &x) || x > 39) 4964 goto exit; 4965 4966 firstByte += x; 4967 } 4968 4969 CFDataAppendBytes(currentResult, &firstByte, 1); 4970 4971 for (CFIndex i = 2; i < count && GetDecimalValueOfString(CFArrayGetValueAtIndex(parts, i), &x); ++i) { 4972 uint8_t b[5] = {0, 0, 0, 0, 0}; 4973 b[4] = (x & 0x7F); 4974 b[3] = 0x80 | ((x >> 7) & 0x7F); 4975 b[2] = 0x80 | ((x >> 14) & 0x7F); 4976 b[1] = 0x80 | ((x >> 21) & 0x7F); 4977 b[0] = 0x80 | ((x >> 28) & 0x7F); 4978 4979 // Skip the unused extension bytes. 4980 size_t skipBytes = 0; 4981 while (b[skipBytes] == 0x80) 4982 ++skipBytes; 4983 4984 CFDataAppendBytes(currentResult, b + skipBytes, sizeof(b) - skipBytes); 4985 } 4986 4987 encodedResult = currentResult; 4988 currentResult = NULL; 4989 4990exit: 4991 CFReleaseNull(parts); 4992 CFReleaseNull(currentResult); 4993 4994 return encodedResult; 4995} 4996 4997static void check_for_marker(const void *key, const void *value, void *context) 4998{ 4999 struct search_context * search_ctx = (struct search_context *) context; 5000 CFStringRef key_string = (CFStringRef) key; 5001 CFTypeRef value_ref = (CFTypeRef) value; 5002 5003 // If we could have short circuted the iteration 5004 // we would have, but the best we can do 5005 // is not waste time comparing once a match 5006 // was found. 5007 if (search_ctx->found) 5008 return; 5009 5010 if (CFGetTypeID(key_string) != CFStringGetTypeID()) 5011 return; 5012 5013 CFDataRef key_data = CreateOidDataFromString(NULL, key_string); 5014 5015 if (NULL == key_data) 5016 return; 5017 5018 if (cert_contains_marker_extension_value(search_ctx->certificate, key_data, value_ref)) 5019 search_ctx->found = true; 5020 5021 CFReleaseNull(key_data); 5022} 5023 5024// 5025// CFType Ref is either: 5026// 5027// CFData - OID to match with no data permitted 5028// CFDictionary - OID -> Value table for expected values Single Object or Array 5029// CFArray - Array of the above. 5030// 5031// This returns true if any of the requirements are met. 5032bool SecCertificateHasMarkerExtension(SecCertificateRef certificate, CFTypeRef oids) 5033{ 5034 if (CFGetTypeID(oids) == CFArrayGetTypeID()) { 5035 CFIndex ix, length = CFArrayGetCount(oids); 5036 for (ix = 0; ix < length; ix++) 5037 if (SecCertificateHasMarkerExtension(certificate, CFArrayGetValueAtIndex((CFArrayRef)oids, ix))) 5038 return true; 5039 } else if (CFGetTypeID(oids) == CFDictionaryGetTypeID()) { 5040 struct search_context context = { .found = false, .certificate = certificate }; 5041 CFDictionaryApplyFunction((CFDictionaryRef) oids, &check_for_marker, &context); 5042 return context.found; 5043 } else if (CFGetTypeID(oids) == CFDataGetTypeID()) { 5044 return cert_contains_marker_extension(certificate, oids); 5045 } 5046 return false; 5047} 5048 5049SecCertificateRef SecCertificateCreateWithPEM(CFAllocatorRef allocator, 5050 CFDataRef pem_certificate) 5051{ 5052 static const char begin_cert[] = "-----BEGIN CERTIFICATE-----\n"; 5053 static const char end_cert[] = "-----END CERTIFICATE-----\n"; 5054 uint8_t *base64_data = NULL; 5055 SecCertificateRef cert = NULL; 5056 const unsigned char *data = CFDataGetBytePtr(pem_certificate); 5057 //const size_t length = CFDataGetLength(pem_certificate); 5058 char *begin = strstr((const char *)data, begin_cert); 5059 char *end = strstr((const char *)data, end_cert); 5060 if (!begin || !end) 5061 return NULL; 5062 begin += sizeof(begin_cert) - 1; 5063 size_t base64_length = SecBase64Decode(begin, end - begin, NULL, 0); 5064 if (base64_length) { 5065 require_quiet(base64_data = calloc(1, base64_length), out); 5066 require_quiet(base64_length = SecBase64Decode(begin, end - begin, base64_data, base64_length), out); 5067 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, base64_data, base64_length); 5068 free(base64_data); 5069 } 5070out: 5071 return cert; 5072} 5073 5074 5075// 5076// -- MARK -- XPC encoding/decoding 5077// 5078 5079bool SecCertificateAppendToXPCArray(SecCertificateRef certificate, xpc_object_t xpc_certificates, CFErrorRef *error) { 5080 if (!certificate) 5081 return true; // NOOP 5082 5083 size_t length = SecCertificateGetLength(certificate); 5084 const uint8_t *bytes = SecCertificateGetBytePtr(certificate); 5085 if (!length || !bytes) 5086 return SecError(errSecParam, error, CFSTR("failed to der encode certificate")); 5087 5088 xpc_array_set_data(xpc_certificates, XPC_ARRAY_APPEND, bytes, length); 5089 return true; 5090} 5091 5092SecCertificateRef SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates, size_t index, CFErrorRef *error) { 5093 SecCertificateRef certificate = NULL; 5094 size_t length = 0; 5095 const uint8_t *bytes = xpc_array_get_data(xpc_certificates, index, &length); 5096 if (bytes) { 5097 certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length); 5098 } 5099 if (!certificate) 5100 SecError(errSecParam, error, CFSTR("certificates[%zu] failed to decode"), index); 5101 5102 return certificate; 5103} 5104 5105xpc_object_t SecCertificateArrayCopyXPCArray(CFArrayRef certificates, CFErrorRef *error) { 5106 xpc_object_t xpc_certificates; 5107 require_action_quiet(xpc_certificates = xpc_array_create(NULL, 0), exit, 5108 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array"))); 5109 CFIndex ix, count = CFArrayGetCount(certificates); 5110 for (ix = 0; ix < count; ++ix) { 5111 if (!SecCertificateAppendToXPCArray((SecCertificateRef)CFArrayGetValueAtIndex(certificates, ix), xpc_certificates, error)) { 5112 xpc_release(xpc_certificates); 5113 return NULL; 5114 } 5115 } 5116 5117exit: 5118 return xpc_certificates; 5119} 5120 5121CFArrayRef SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates, CFErrorRef *error) { 5122 CFMutableArrayRef certificates = NULL; 5123 require_action_quiet(xpc_get_type(xpc_certificates) == XPC_TYPE_ARRAY, exit, 5124 SecError(errSecParam, error, CFSTR("certificates xpc value is not an array"))); 5125 size_t count = xpc_array_get_count(xpc_certificates); 5126 require_action_quiet(certificates = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit, 5127 SecError(errSecAllocate, error, CFSTR("failed to create CFArray of capacity %zu"), count)); 5128 5129 size_t ix; 5130 for (ix = 0; ix < count; ++ix) { 5131 SecCertificateRef cert = SecCertificateCreateWithXPCArrayAtIndex(xpc_certificates, ix, error); 5132 if (!cert) { 5133 CFRelease(certificates); 5134 return NULL; 5135 } 5136 CFArraySetValueAtIndex(certificates, ix, cert); 5137 CFRelease(cert); 5138 } 5139 5140exit: 5141 return certificates; 5142} 5143 5144#define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); } 5145 5146 5147static CFArrayRef CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType, CFErrorRef* error) 5148{ 5149 __block CFArrayRef result = NULL; 5150 5151 do_if_registered(ota_CopyEscrowCertificates, escrowRootType, error); 5152 5153 securityd_send_sync_and_do(kSecXPCOpOTAGetEscrowCertificates, error, 5154 ^bool(xpc_object_t message, CFErrorRef *error) 5155 { 5156 xpc_dictionary_set_uint64(message, "escrowType", (uint64_t)escrowRootType); 5157 return true; 5158 }, 5159 ^bool(xpc_object_t response, CFErrorRef *error) 5160 { 5161 xpc_object_t xpc_array = xpc_dictionary_get_value(response, kSecXPCKeyResult); 5162 5163 if (response && (NULL != xpc_array)) 5164 { 5165 result = (CFArrayRef)_CFXPCCreateCFObjectFromXPCObject(xpc_array); 5166 } 5167 else 5168 { 5169 return SecError(errSecInternal, error, CFSTR("Did not get the Escrow certificates")); 5170 } 5171 return result != NULL; 5172 }); 5173 return result; 5174} 5175 5176CFArrayRef SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType) 5177{ 5178 CFArrayRef result = NULL; 5179 int iCnt; 5180 CFDataRef certData = NULL; 5181 int numRoots = 0; 5182 5183 // The request is for the base line certificates. 5184 // Use the hard coded data to generate the return array 5185 if (kSecCertificateBaselineEscrowRoot == escrowRootType || 5186 kSecCertificateBaselinePCSEscrowRoot == escrowRootType) 5187 { 5188 // Get the hard coded set of roots 5189 numRoots = (kSecCertificateBaselineEscrowRoot == escrowRootType) ? 5190 kNumberOfBaseLineEscrowRoots : 5191 kNumberOfBaseLinePCSEscrowRoots; 5192 SecCertificateRef baseLineCerts[numRoots]; 5193 struct RootRecord** pEscrowRoots = kBaseLineEscrowRoots; 5194 struct RootRecord* pRootRecord = NULL; 5195 5196 if (kSecCertificateBaselinePCSEscrowRoot == escrowRootType) { 5197 pEscrowRoots = kBaseLinePCSEscrowRoots; 5198 } 5199 5200 for (iCnt = 0; iCnt < numRoots; iCnt++) 5201 { 5202 pRootRecord = pEscrowRoots[iCnt]; 5203 if (NULL != pRootRecord && pRootRecord->_length > 0 && NULL != pRootRecord->_bytes) 5204 { 5205 certData = CFDataCreate(kCFAllocatorDefault, pRootRecord->_bytes, pRootRecord->_length); 5206 if (NULL != certData) 5207 { 5208 baseLineCerts[iCnt] = SecCertificateCreateWithData(kCFAllocatorDefault, certData); 5209 CFRelease(certData); 5210 } 5211 } 5212 } 5213 result = CFArrayCreate(kCFAllocatorDefault, (const void **)baseLineCerts, numRoots, &kCFTypeArrayCallBacks); 5214 for (iCnt = 0; iCnt < numRoots; iCnt++) 5215 { 5216 if (NULL != baseLineCerts[iCnt]) 5217 { 5218 CFRelease(baseLineCerts[iCnt]); 5219 } 5220 } 5221 } 5222 // The request is for the current certificates. 5223 else 5224 { 5225 CFErrorRef error = NULL; 5226 CFArrayRef cert_datas = CopyEscrowCertificates(escrowRootType, &error); 5227 if (NULL != error || NULL == cert_datas) 5228 { 5229 if (NULL != error) 5230 { 5231 CFRelease(error); 5232 } 5233 5234 if (NULL != cert_datas) 5235 { 5236 CFRelease(cert_datas); 5237 } 5238 return result; 5239 } 5240 5241 numRoots = (int)(CFArrayGetCount(cert_datas)); 5242 5243 SecCertificateRef assetCerts[numRoots]; 5244 for (iCnt = 0; iCnt < numRoots; iCnt++) 5245 { 5246 certData = (CFDataRef)CFArrayGetValueAtIndex(cert_datas, iCnt); 5247 if (NULL != certData) 5248 { 5249 SecCertificateRef aCertRef = SecCertificateCreateWithData(kCFAllocatorDefault, certData); 5250 assetCerts[iCnt] = aCertRef; 5251 } 5252 else 5253 { 5254 assetCerts[iCnt] = NULL; 5255 } 5256 } 5257 5258 if (numRoots > 0) 5259 { 5260 result = CFArrayCreate(kCFAllocatorDefault, (const void **)assetCerts, numRoots, &kCFTypeArrayCallBacks); 5261 for (iCnt = 0; iCnt < numRoots; iCnt++) 5262 { 5263 if (NULL != assetCerts[iCnt]) 5264 { 5265 CFRelease(assetCerts[iCnt]); 5266 } 5267 } 5268 } 5269 CFReleaseSafe(cert_datas); 5270 } 5271 return result; 5272} 5273