2  * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25  * SecCertificate.c - CoreFoundation based certificate object 
  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__ 
  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> 
  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" 
  56 #include "SecItemPriv.h" 
  57 #include "SecSignatureVerificationSupport.h" 
  59 #include <utilities/debugging.h> 
  60 #include <utilities/SecCFWrappers.h> 
  61 #include <utilities/SecCFError.h> 
  62 #include <utilities/SecSCTUtils.h> 
  63 #include <utilities/array_size.h> 
  65 #include <libkern/OSByteOrder.h> 
  67 #include <Security/SecInternal.h> 
  68 #include <Security/SecFrameworkStrings.h> 
  69 #include "SecBase64.h" 
  70 #include "AppleBaselineEscrowCertificates.h" 
  71 #include "AppleiPhoneDeviceCACertificates.h" 
  72 #include <ipc/securityd_client.h> 
  73 #include <Security/SecKeyInternal.h> 
  75 #pragma clang diagnostic ignored "-Wformat=2" 
  77 /* The minimum key sizes necessary to not be considered "weak" */ 
  78 #define MIN_RSA_KEY_SIZE    128     // 1024-bit 
  79 #define MIN_EC_KEY_SIZE     20      // 160-bit 
  81 /* The minimum key sizes necessary to be considered "strong" */ 
  82 #define MIN_STRONG_RSA_KEY_SIZE     256     // 2048-bit 
  83 #define MIN_STRONG_EC_KEY_SIZE      28      // 224-bit 
  85 typedef struct SecCertificateExtension 
{ 
  89 } SecCertificateExtension
; 
  92     kSecSelfSignedUnknown 
= 0, 
  97 struct __SecCertificate 
{ 
 100     DERItem             _der
;           /* Entire certificate in DER form. */ 
 101     DERItem             _tbs
;           /* To Be Signed cert DER bytes. */ 
 102     DERAlgorithmId      _sigAlg
;        /* Top level signature algorithm. */ 
 103     DERItem             _signature
;     /* The content of the sig bit string. */ 
 106     DERItem             _serialNum
;     /* Integer. */ 
 107     DERAlgorithmId      _tbsSigAlg
;     /* sig alg MUST be same as _sigAlg. */ 
 108     DERItem             _issuer
;        /* Sequence of RDN. */ 
 109     CFAbsoluteTime      _notBefore
; 
 110     CFAbsoluteTime      _notAfter
; 
 111     DERItem             _subject
;       /* Sequence of RDN. */ 
 112     DERItem             _subjectPublicKeyInfo
; /* SPKI (without tag/length) */ 
 113     DERAlgorithmId      _algId
;         /* oid and params of _pubKeyDER. */ 
 114     DERItem             _pubKeyDER
;     /* contents of bit string */ 
 115     DERItem             _issuerUniqueID
;    /* bit string, optional */ 
 116     DERItem             _subjectUniqueID
;   /* bit string, optional */ 
 118     bool                _foundUnknownCriticalExtension
; 
 120     /* Well known certificate extensions. */ 
 121     SecCEBasicConstraints       _basicConstraints
; 
 122     SecCEPolicyConstraints      _policyConstraints
; 
 123     SecCEPolicyMappings         _policyMappings
; 
 124     SecCECertificatePolicies    _certificatePolicies
; 
 125     SecCEInhibitAnyPolicy       _inhibitAnyPolicySkipCerts
; 
 127     /* If KeyUsage extension is not present this is 0, otherwise it's 
 128        the value of the extension. */ 
 129     SecKeyUsage _keyUsage
; 
 131     /* OCTETS of SubjectKeyIdentifier extensions KeyIdentifier. 
 132        Length = 0 if not present. */ 
 133     DERItem             _subjectKeyIdentifier
; 
 135     /* OCTETS of AuthorityKeyIdentifier extensions KeyIdentifier. 
 136        Length = 0 if not present. */ 
 137     DERItem             _authorityKeyIdentifier
; 
 138     /* AuthorityKeyIdentifier extension _authorityKeyIdentifierIssuer and 
 139        _authorityKeyIdentifierSerialNumber have non zero length if present. 
 140        Both are either present or absent together.  */ 
 141     DERItem             _authorityKeyIdentifierIssuer
; 
 142     DERItem             _authorityKeyIdentifierSerialNumber
; 
 144     /* Subject alt name extension, if present.  Not malloced, it's just a 
 145        pointer to an element in the _extensions array. */ 
 146     const SecCertificateExtension  
*_subjectAltName
; 
 148     /* Parsed extension values. */ 
 150     /* Array of CFURLRefs containing the URI values of crlDistributionPoints. */ 
 151     CFMutableArrayRef   _crlDistributionPoints
; 
 153     /* Array of CFURLRefs containing the URI values of accessLocations of each 
 154        id-ad-ocsp AccessDescription in the Authority Information Access 
 156     CFMutableArrayRef   _ocspResponders
; 
 158     /* Array of CFURLRefs containing the URI values of accessLocations of each 
 159        id-ad-caIssuers AccessDescription in the Authority Information Access 
 161     CFMutableArrayRef   _caIssuers
; 
 163     /* Array of CFDataRefs containing the generalNames for permittedSubtrees 
 165     CFArrayRef          _permittedSubtrees
; 
 167     /* Array of CFDataRefs containing the generalNames for excludedSubtrees 
 169     CFArrayRef          _excludedSubtrees
; 
 171     CFMutableArrayRef   _embeddedSCTs
; 
 173     /* All other (non known) extensions.   The _extensions array is malloced. */ 
 174     CFIndex             _extensionCount
; 
 175     SecCertificateExtension 
*_extensions
; 
 177     /* Optional cached fields. */ 
 180     CFArrayRef          _properties
; 
 181     CFDataRef           _serialNumber
; 
 182     CFDataRef           _normalizedIssuer
; 
 183     CFDataRef           _normalizedSubject
; 
 184     CFDataRef           _authorityKeyID
; 
 185     CFDataRef           _subjectKeyID
; 
 187     CFDataRef           _sha1Digest
; 
 188     CFTypeRef           _keychain_item
; 
 189     uint8_t             _isSelfSigned
; 
 193 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); 
 195 SEC_CONST_DECL (kSecCertificateProductionEscrowKey
, "ProductionEscrowKey"); 
 196 SEC_CONST_DECL (kSecCertificateProductionPCSEscrowKey
, "ProductionPCSEscrowKey"); 
 197 SEC_CONST_DECL (kSecCertificateEscrowFileName
, "AppleESCertificates"); 
 199 /* Public Constants for property list keys. */ 
 200 SEC_CONST_DECL (kSecPropertyKeyType
, "type"); 
 201 SEC_CONST_DECL (kSecPropertyKeyLabel
, "label"); 
 202 SEC_CONST_DECL (kSecPropertyKeyLocalizedLabel
, "localized label"); 
 203 SEC_CONST_DECL (kSecPropertyKeyValue
, "value"); 
 205 /* Public Constants for property list values. */ 
 206 SEC_CONST_DECL (kSecPropertyTypeWarning
, "warning"); 
 207 SEC_CONST_DECL (kSecPropertyTypeError
, "error"); 
 208 SEC_CONST_DECL (kSecPropertyTypeSuccess
, "success"); 
 209 SEC_CONST_DECL (kSecPropertyTypeTitle
, "title"); 
 210 SEC_CONST_DECL (kSecPropertyTypeSection
, "section"); 
 211 SEC_CONST_DECL (kSecPropertyTypeData
, "data"); 
 212 SEC_CONST_DECL (kSecPropertyTypeString
, "string"); 
 213 SEC_CONST_DECL (kSecPropertyTypeURL
, "url"); 
 214 SEC_CONST_DECL (kSecPropertyTypeDate
, "date"); 
 216 /* Extension parsing routine. */ 
 217 typedef bool (*SecCertificateExtensionParser
)(SecCertificateRef certificate
, 
 218         const SecCertificateExtension 
*extn
); 
 220 /* Mapping from extension OIDs (as a DERItem *) to 
 221    SecCertificateExtensionParser extension parsing routines. */ 
 222 static CFDictionaryRef sExtensionParsers
; 
 224 /* Forward declarations of static functions. */ 
 225 static CFStringRef 
SecCertificateCopyDescription(CFTypeRef cf
); 
 226 static void SecCertificateDestroy(CFTypeRef cf
); 
 227 static bool derDateGetAbsoluteTime(const DERItem 
*dateChoice
, 
 228     CFAbsoluteTime 
*absTime
) __attribute__((__nonnull__
)); 
 230 /* Static functions. */ 
 231 static CFStringRef 
SecCertificateCopyDescription(CFTypeRef cf
) { 
 232     SecCertificateRef certificate 
= (SecCertificateRef
)cf
; 
 233     CFStringRef subject 
= SecCertificateCopySubjectSummary(certificate
); 
 234     CFStringRef issuer 
= SecCertificateCopyIssuerSummary(certificate
); 
 235     CFStringRef desc 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, 
 236         CFSTR("<cert(%p) s: %@ i: %@>"), certificate
, subject
, issuer
); 
 237     CFReleaseSafe(issuer
); 
 238     CFReleaseSafe(subject
); 
 242 static void SecCertificateDestroy(CFTypeRef cf
) { 
 243     SecCertificateRef certificate 
= (SecCertificateRef
)cf
; 
 244     if (certificate
->_certificatePolicies
.policies
) { 
 245         free(certificate
->_certificatePolicies
.policies
); 
 246         certificate
->_certificatePolicies
.policies 
= NULL
; 
 248     if (certificate
->_policyMappings
.mappings
) { 
 249         free(certificate
->_policyMappings
.mappings
); 
 250         certificate
->_policyMappings
.mappings 
= NULL
; 
 252     CFReleaseNull(certificate
->_crlDistributionPoints
); 
 253     CFReleaseNull(certificate
->_ocspResponders
); 
 254     CFReleaseNull(certificate
->_caIssuers
); 
 255     if (certificate
->_extensions
) { 
 256         free(certificate
->_extensions
); 
 257         certificate
->_extensions 
= NULL
; 
 259     CFReleaseNull(certificate
->_pubKey
); 
 260     CFReleaseNull(certificate
->_der_data
); 
 261     CFReleaseNull(certificate
->_properties
); 
 262     CFReleaseNull(certificate
->_serialNumber
); 
 263     CFReleaseNull(certificate
->_normalizedIssuer
); 
 264     CFReleaseNull(certificate
->_normalizedSubject
); 
 265     CFReleaseNull(certificate
->_authorityKeyID
); 
 266     CFReleaseNull(certificate
->_subjectKeyID
); 
 267     CFReleaseNull(certificate
->_sha1Digest
); 
 268     CFReleaseNull(certificate
->_keychain_item
); 
 269     CFReleaseNull(certificate
->_permittedSubtrees
); 
 270     CFReleaseNull(certificate
->_excludedSubtrees
); 
 273 static Boolean 
SecCertificateEqual(CFTypeRef cf1
, CFTypeRef cf2
) { 
 274     SecCertificateRef cert1 
= (SecCertificateRef
)cf1
; 
 275     SecCertificateRef cert2 
= (SecCertificateRef
)cf2
; 
 278     if (!cert2 
|| cert1
->_der
.length 
!= cert2
->_der
.length
) 
 280     return !memcmp(cert1
->_der
.data
, cert2
->_der
.data
, cert1
->_der
.length
); 
 283 /* Hash of the certificate is der length + signature length + last 4 bytes 
 285 static CFHashCode 
SecCertificateHash(CFTypeRef cf
) { 
 286     SecCertificateRef certificate 
= (SecCertificateRef
)cf
; 
 287         size_t der_length 
= certificate
->_der
.length
; 
 288         size_t sig_length 
= certificate
->_signature
.length
; 
 289         size_t ix 
= (sig_length 
> 4) ? sig_length 
- 4 : 0; 
 290         CFHashCode hashCode 
= 0; 
 291         for (; ix 
< sig_length
; ++ix
) 
 292                 hashCode 
= (hashCode 
<< 8) + certificate
->_signature
.data
[ix
]; 
 294         return (hashCode 
+ der_length 
+ sig_length
); 
 299 /************************************************************************/ 
 300 /************************* General Name Parsing *************************/ 
 301 /************************************************************************/ 
 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} 
 314       OtherName ::= SEQUENCE { 
 315            type-id    OBJECT IDENTIFIER, 
 316            value      [0] EXPLICIT ANY DEFINED BY type-id } 
 318       EDIPartyName ::= SEQUENCE { 
 319            nameAssigner            [0]     DirectoryString OPTIONAL, 
 320            partyName               [1]     DirectoryString } 
 322 OSStatus 
SecCertificateParseGeneralNameContentProperty(DERTag tag
, 
 323         const DERItem 
*generalNameContent
, 
 324         void *context
, parseGeneralNameCallback callback
) { 
 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: 
 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
); 
 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
); 
 358         return errSecInvalidCertificate
; 
 361 static OSStatus 
parseGeneralNamesContent(const DERItem 
*generalNamesContent
, 
 362         void *context
, parseGeneralNameCallback callback
) { 
 364     DERReturn drtn 
= DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
); 
 365     require_noerr_quiet(drtn
, badDER
); 
 366     DERDecodedInfo generalNameContent
; 
 367     while ((drtn 
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) == 
 369                 OSStatus status 
= SecCertificateParseGeneralNameContentProperty( 
 370                         generalNameContent
.tag
, &generalNameContent
.content
, context
, 
 375     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
 376         return errSecSuccess
; 
 379         return errSecInvalidCertificate
; 
 382 OSStatus 
SecCertificateParseGeneralNames(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
, 
 391         return errSecInvalidCertificate
; 
 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} 
 408       EDIPartyName ::= SEQUENCE { 
 409            nameAssigner            [0]     DirectoryString OPTIONAL, 
 410            partyName               [1]     DirectoryString } 
 412 static OSStatus 
parseGeneralNameContentProperty(DERTag tag
, 
 413         const DERItem 
*generalNameContent
, SecCEGeneralName 
*generalName
) { 
 415         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 0: 
 416                 generalName
->nameType 
= GNT_OtherName
; 
 417                 generalName
->berEncoded 
= true; 
 418                 generalName
->name 
= *generalNameContent
; 
 420         case ASN1_CONTEXT_SPECIFIC 
| 1: 
 422                 generalName
->nameType 
= GNT_RFC822Name
; 
 423                 generalName
->berEncoded 
= false; 
 424                 generalName
->name 
= *generalNameContent
; 
 426         case ASN1_CONTEXT_SPECIFIC 
| 2: 
 428                 generalName
->nameType 
= GNT_DNSName
; 
 429                 generalName
->berEncoded 
= false; 
 430                 generalName
->name 
= *generalNameContent
; 
 432         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 3: 
 433                 generalName
->nameType 
= GNT_X400Address
; 
 434                 generalName
->berEncoded 
= true; 
 435                 generalName
->name 
= *generalNameContent
; 
 437         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 4: 
 438                 generalName
->nameType 
= GNT_DirectoryName
; 
 439                 generalName
->berEncoded 
= true; 
 440                 generalName
->name 
= *generalNameContent
; 
 442         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 5: 
 443                 generalName
->nameType 
= GNT_EdiPartyName
; 
 444                 generalName
->berEncoded 
= true; 
 445                 generalName
->name 
= *generalNameContent
; 
 447         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 6: 
 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
; 
 460         case ASN1_CONTEXT_SPECIFIC 
| 6: 
 461                 generalName
->nameType 
= GNT_URI
; 
 462                 generalName
->berEncoded 
= false; 
 463                 generalName
->name 
= *generalNameContent
; 
 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
; 
 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
; 
 482         return errSecSuccess
; 
 484         return errSecInvalidCertificate
; 
 488       GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 
 490 static OSStatus 
parseGeneralNamesContent(const DERItem 
*generalNamesContent
, 
 491         CFIndex 
*count
, SecCEGeneralName 
**name
) { 
 492         SecCEGeneralName 
*generalNames 
= NULL
; 
 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
)) == 
 502     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
 504         require(generalNames 
= calloc(generalNamesCount
, sizeof(SecCEGeneralName
)), 
 506     DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
); 
 508     while ((drtn 
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) == 
 510                 if (!parseGeneralNameContentProperty(generalNameContent
.tag
, 
 511                         &generalNameContent
.content
, &generalNames
[ix
])) { 
 516         *count 
= generalNamesCount
; 
 517         *name 
= generalNames
; 
 518         return errSecSuccess
; 
 523         return errSecInvalidCertificate
; 
 526 static 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
, 
 533     parseGeneralNamesContent(&generalNamesContent
.content
, count
, name
); 
 534     return errSecSuccess
; 
 536         return errSecInvalidCertificate
; 
 540 /************************************************************************/ 
 541 /************************** X.509 Name Parsing **************************/ 
 542 /************************************************************************/ 
 544 typedef OSStatus (*parseX501NameCallback
)(void *context
, const DERItem 
*type
, 
 545         const DERItem 
*value
, CFIndex rdnIX
, bool localized
); 
 547 static OSStatus 
parseRDNContent(const DERItem 
*rdnSetContent
, void *context
, 
 548         parseX501NameCallback callback
, bool localized
) { 
 550         DERReturn drtn 
= DERDecodeSeqContentInit(rdnSetContent
, &rdn
); 
 551         require_noerr_quiet(drtn
, badDER
); 
 552         DERDecodedInfo atvContent
; 
 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
, 
 561                 require_noerr_quiet(drtn
, badDER
); 
 562                 require_quiet(atv
.type
.length 
!= 0, badDER
); 
 563                 OSStatus status 
= callback(context
, &atv
.type
, &atv
.value
, rdnIX
++, localized
); 
 568         require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
 570         return errSecSuccess
; 
 572         return errSecInvalidCertificate
; 
 575 static OSStatus 
parseX501NameContent(const DERItem 
*x501NameContent
, void *context
, 
 576         parseX501NameCallback callback
, bool localized
) { 
 578         DERReturn drtn 
= DERDecodeSeqContentInit(x501NameContent
, &derSeq
); 
 579         require_noerr_quiet(drtn
, badDER
); 
 580         DERDecodedInfo currDecoded
; 
 581         while ((drtn 
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) { 
 582                 require_quiet(currDecoded
.tag 
== ASN1_CONSTR_SET
, badDER
); 
 583                 OSStatus status 
= parseRDNContent(&currDecoded
.content
, context
, 
 584                         callback
, localized
); 
 589         require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
 591         return errSecSuccess
; 
 594         return errSecInvalidCertificate
; 
 597 static OSStatus 
parseX501Name(const DERItem 
*x501Name
, void *context
, 
 598         parseX501NameCallback callback
, bool localized
) { 
 599         DERDecodedInfo x501NameContent
; 
 600         if (DERDecodeItem(x501Name
, &x501NameContent
) || 
 601         x501NameContent
.tag 
!= ASN1_CONSTR_SEQUENCE
) { 
 602                 return errSecInvalidCertificate
; 
 604         return parseX501NameContent(&x501NameContent
.content
, context
, 
 605                         callback
, localized
); 
 609 /************************************************************************/ 
 610 /********************** Extension Parsing Routines **********************/ 
 611 /************************************************************************/ 
 613 static bool SecCEPSubjectKeyIdentifier(SecCertificateRef certificate
, 
 614         const SecCertificateExtension 
*extn
) { 
 615         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
 616     DERDecodedInfo keyIdentifier
; 
 617         DERReturn drtn 
= DERDecodeItem(&extn
->extnValue
, &keyIdentifier
); 
 618         require_noerr_quiet(drtn
, badDER
); 
 619         require_quiet(keyIdentifier
.tag 
== ASN1_OCTET_STRING
, badDER
); 
 620         certificate
->_subjectKeyIdentifier 
= keyIdentifier
.content
; 
 624         secwarning("Invalid SubjectKeyIdentifier Extension"); 
 628 static bool SecCEPKeyUsage(SecCertificateRef certificate
, 
 629         const SecCertificateExtension 
*extn
) { 
 630         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
 631     SecKeyUsage keyUsage 
= extn
->critical 
? kSecKeyUsageCritical 
: 0; 
 632     DERDecodedInfo bitStringContent
; 
 633     DERReturn drtn 
= DERDecodeItem(&extn
->extnValue
, &bitStringContent
); 
 634     require_noerr_quiet(drtn
, badDER
); 
 635     require_quiet(bitStringContent
.tag 
== ASN1_BIT_STRING
, badDER
); 
 636     DERSize len 
= bitStringContent
.content
.length 
- 1; 
 637     require_quiet(len 
== 1 || len 
== 2, badDER
); 
 638     DERByte numUnusedBits 
= bitStringContent
.content
.data
[0]; 
 639     require_quiet(numUnusedBits 
< 8, badDER
); 
 640     /* Flip the bits in the bit string so the first bit in the lsb. */ 
 641     uint_fast16_t bits 
= 8 * len 
- numUnusedBits
; 
 642     uint_fast16_t value 
= bitStringContent
.content
.data
[1]; 
 645         value 
= (value 
<< 8) + bitStringContent
.content
.data
[2]; 
 651     for (ix 
= 0; ix 
< bits
; ++ix
) { 
 657     certificate
->_keyUsage 
= keyUsage
; 
 660     certificate
->_keyUsage 
= kSecKeyUsageUnspecified
; 
 661     secwarning("Invalid KeyUsage Extension"); 
 665 static bool SecCEPPrivateKeyUsagePeriod(SecCertificateRef certificate
, 
 666         const SecCertificateExtension 
*extn
) { 
 667         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
 671 static bool SecCEPSubjectAltName(SecCertificateRef certificate
, 
 672         const SecCertificateExtension 
*extn
) { 
 673         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
 674         certificate
->_subjectAltName 
= extn
; 
 678 static bool SecCEPIssuerAltName(SecCertificateRef certificate
, 
 679         const SecCertificateExtension 
*extn
) { 
 680         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
 684 static bool SecCEPBasicConstraints(SecCertificateRef certificate
, 
 685         const SecCertificateExtension 
*extn
) { 
 686         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
 687         DERBasicConstraints basicConstraints
; 
 688         require_noerr_quiet(DERParseSequence(&extn
->extnValue
, 
 689         DERNumBasicConstraintsItemSpecs
, DERBasicConstraintsItemSpecs
, 
 690         &basicConstraints
, sizeof(basicConstraints
)), badDER
); 
 691     require_noerr_quiet(DERParseBooleanWithDefault(&basicConstraints
.cA
, false, 
 692                 &certificate
->_basicConstraints
.isCA
), badDER
); 
 693     if (basicConstraints
.pathLenConstraint
.length 
!= 0) { 
 694         require_noerr_quiet(DERParseInteger( 
 695             &basicConstraints
.pathLenConstraint
, 
 696             &certificate
->_basicConstraints
.pathLenConstraint
), badDER
); 
 697                 certificate
->_basicConstraints
.pathLenConstraintPresent 
= true; 
 699     certificate
->_basicConstraints
.present 
= true; 
 700         certificate
->_basicConstraints
.critical 
= extn
->critical
; 
 703     certificate
->_basicConstraints
.present 
= false; 
 704         secwarning("Invalid BasicConstraints Extension"); 
 710  * id-ce-nameConstraints OBJECT IDENTIFIER ::=  { id-ce 30 } 
 712  * NameConstraints ::= SEQUENCE { 
 713  * permittedSubtrees       [0]     GeneralSubtrees OPTIONAL, 
 714  * excludedSubtrees        [1]     GeneralSubtrees OPTIONAL } 
 716  * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree 
 718  * GeneralSubtree ::= SEQUENCE { 
 720  * minimum         [0]     BaseDistance DEFAULT 0, 
 721  * maximum         [1]     BaseDistance OPTIONAL } 
 723  * BaseDistance ::= INTEGER (0..MAX) 
 725 static DERReturn 
parseGeneralSubtrees(DERItem 
*derSubtrees
, CFArrayRef 
*generalSubtrees
) { 
 726     CFMutableArrayRef gs 
= NULL
; 
 728     DERReturn drtn 
= DERDecodeSeqContentInit(derSubtrees
, &gsSeq
); 
 729     require_noerr_quiet(drtn
, badDER
); 
 730     DERDecodedInfo gsContent
; 
 731     require_quiet(gs 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, 
 732                   &kCFTypeArrayCallBacks
), 
 734     while ((drtn 
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) { 
 735         DERGeneralSubtree derGS
; 
 736         require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
); 
 737         drtn 
= DERParseSequenceContent(&gsContent
.content
, 
 738                                        DERNumGeneralSubtreeItemSpecs
, 
 739                                        DERGeneralSubtreeItemSpecs
, 
 740                                        &derGS
, sizeof(derGS
)); 
 741         require_noerr_quiet(drtn
, badDER
); 
 744          * Within this profile, the minimum and maximum fields are not used with 
 745          * any name forms, thus, the minimum MUST be zero, and maximum MUST be 
 748          * Because minimum DEFAULT 0, absence equivalent to present and 0. 
 750         if (derGS
.minimum
.length
) { 
 752             require_noerr_quiet(DERParseInteger(&derGS
.minimum
, &minimum
), 
 754             require_quiet(minimum 
== 0, badDER
); 
 756         require_quiet(derGS
.maximum
.length 
== 0, badDER
); 
 757         require_quiet(derGS
.generalName
.length 
!= 0, badDER
); 
 759         CFDataRef generalName 
= NULL
; 
 760         require_quiet(generalName 
= CFDataCreate(kCFAllocatorDefault
, 
 761                                              derGS
.generalName
.data
, 
 762                                              derGS
.generalName
.length
), 
 764         CFArrayAppendValue(gs
, generalName
); 
 765         CFReleaseNull(generalName
); 
 767     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
 769     // since generalSubtrees is a pointer to an instance variable, 
 770     // make sure we release the existing array before assignment. 
 771     CFReleaseSafe(*generalSubtrees
); 
 772     *generalSubtrees 
= gs
; 
 778     secdebug("cert","failed to parse GeneralSubtrees"); 
 782 static bool SecCEPNameConstraints(SecCertificateRef certificate
, 
 783     const SecCertificateExtension 
*extn
) { 
 784     secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
 785     DERNameConstraints nc
; 
 787     drtn 
= DERParseSequence(&extn
->extnValue
, 
 788                             DERNumNameConstraintsItemSpecs
, 
 789                             DERNameConstraintsItemSpecs
, 
 791     require_noerr_quiet(drtn
, badDER
); 
 792     if (nc
.permittedSubtrees
.length
) { 
 793         require_noerr_quiet(parseGeneralSubtrees(&nc
.permittedSubtrees
, &certificate
->_permittedSubtrees
), badDER
); 
 795     if (nc
.excludedSubtrees
.length
) { 
 796         require_noerr_quiet(parseGeneralSubtrees(&nc
.excludedSubtrees
, &certificate
->_excludedSubtrees
), badDER
); 
 801     secwarning("Invalid Name Constraints extension"); 
 805 static OSStatus 
appendCRLDPFromGeneralNames(void *context
, SecCEGeneralNameType type
, 
 806                                                    const DERItem 
*value
) { 
 807     CFMutableArrayRef 
*crlDPs 
= (CFMutableArrayRef 
*)context
; 
 808     if (type 
== GNT_URI
) { 
 810         url 
= CFURLCreateWithBytes(NULL
, value
->data
, value
->length
, kCFStringEncodingASCII
, NULL
); 
 813                 *crlDPs 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 815             CFArrayAppendValue(*crlDPs
, url
); 
 819     return errSecSuccess
; 
 823  id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::=  { id-ce 31 } 
 825  CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint 
 827  DistributionPoint ::= SEQUENCE { 
 828     distributionPoint       [0]     DistributionPointName OPTIONAL, 
 829     reasons                 [1]     ReasonFlags OPTIONAL, 
 830     cRLIssuer               [2]     GeneralNames OPTIONAL } 
 832  DistributionPointName ::= CHOICE { 
 833     fullName                [0]     GeneralNames, 
 834     nameRelativeToCRLIssuer [1]     RelativeDistinguishedName } 
 836 static bool SecCEPCrlDistributionPoints(SecCertificateRef certificate
, 
 837         const SecCertificateExtension 
*extn
) { 
 838         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
 839     DERSequence crlDPSeq
; 
 841     DERReturn drtn 
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &crlDPSeq
); 
 842     require_noerr_quiet(drtn
, badDER
); 
 843     require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
 844     DERDecodedInfo dpContent
; 
 845     while ((drtn 
= DERDecodeSeqNext(&crlDPSeq
, &dpContent
)) == DR_Success
) { 
 846         require_quiet(dpContent
.tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
 847         DERDistributionPoint dp
; 
 848         drtn 
= DERParseSequenceContent(&dpContent
.content
, DERNumDistributionPointItemSpecs
, 
 849                                        DERDistributionPointItemSpecs
, &dp
, sizeof(dp
)); 
 850         require_noerr_quiet(drtn
, badDER
); 
 851         require_quiet(dp
.distributionPoint
.data 
|| dp
.cRLIssuer
.data
, badDER
); 
 852         if (dp
.distributionPoint
.data
) { 
 853             DERDecodedInfo dpName
; 
 854             drtn 
= DERDecodeItem(&dp
.distributionPoint
, &dpName
); 
 855             require_noerr_quiet(drtn
, badDER
); 
 856             switch (dpName
.tag
) { 
 857                 case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 0: 
 858                     drtn 
= parseGeneralNamesContent(&dpName
.content
, &certificate
->_crlDistributionPoints
, 
 859                                                     appendCRLDPFromGeneralNames
); 
 860                     require_noerr_quiet(drtn
, badDER
); 
 862                 case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 1: 
 863                     /* RelativeDistinguishName. Nothing we can do with that. */ 
 869         if (dp
.cRLIssuer
.data
) { 
 870             drtn 
= SecCertificateParseGeneralNames(&dp
.cRLIssuer
, &certificate
->_crlDistributionPoints
, 
 871                                                    appendCRLDPFromGeneralNames
); 
 872             require_noerr_quiet(drtn
, badDER
); 
 875     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
 878     secwarning("Invalid CRL Distribution Points extension"); 
 883    certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation 
 885    PolicyInformation ::= SEQUENCE { 
 886         policyIdentifier   CertPolicyId, 
 887         policyQualifiers   SEQUENCE SIZE (1..MAX) OF 
 888                                 PolicyQualifierInfo OPTIONAL } 
 890    CertPolicyId ::= OBJECT IDENTIFIER 
 892    PolicyQualifierInfo ::= SEQUENCE { 
 893         policyQualifierId  PolicyQualifierId, 
 894         qualifier          ANY DEFINED BY policyQualifierId } 
 896 /* maximum number of policies of 8192 seems more than adequate */ 
 897 #define MAX_CERTIFICATE_POLICIES 8192 
 898 static bool SecCEPCertificatePolicies(SecCertificateRef certificate
, 
 899         const SecCertificateExtension 
*extn
) { 
 900         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
 903     SecCEPolicyInformation 
*policies 
= NULL
; 
 904     DERReturn drtn 
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &piSeq
); 
 905     require_noerr_quiet(drtn
, badDER
); 
 906     require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
 907     DERDecodedInfo piContent
; 
 908     DERSize policy_count 
= 0; 
 909     while ((policy_count 
< MAX_CERTIFICATE_POLICIES
) && 
 910            (drtn 
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) { 
 911         require_quiet(piContent
.tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
 914     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
 915     require_quiet(policies 
= (SecCEPolicyInformation 
*)malloc(sizeof(SecCEPolicyInformation
) 
 916                                                 * (policy_count 
> 0 ? policy_count 
: 1)), 
 918     drtn 
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &piSeq
); 
 919     require_noerr_quiet(drtn
, badDER
); 
 920     DERSize policy_ix 
= 0; 
 921     while ((policy_ix 
< (policy_count 
> 0 ? policy_count 
: 1)) && 
 922            (drtn 
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) { 
 923         DERPolicyInformation pi
; 
 924         drtn 
= DERParseSequenceContent(&piContent
.content
, 
 925             DERNumPolicyInformationItemSpecs
, 
 926             DERPolicyInformationItemSpecs
, 
 928         require_noerr_quiet(drtn
, badDER
); 
 929         policies
[policy_ix
].policyIdentifier 
= pi
.policyIdentifier
; 
 930         policies
[policy_ix
++].policyQualifiers 
= pi
.policyQualifiers
; 
 932     certificate
->_certificatePolicies
.present 
= true; 
 933     certificate
->_certificatePolicies
.critical 
= extn
->critical
; 
 934     certificate
->_certificatePolicies
.numPolicies 
= policy_count
; 
 935     certificate
->_certificatePolicies
.policies 
= policies
; 
 940     certificate
->_certificatePolicies
.present 
= false; 
 941         secwarning("Invalid CertificatePolicies Extension"); 
 946    id-ce-policyMappings OBJECT IDENTIFIER ::=  { id-ce 33 } 
 948    PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { 
 949         issuerDomainPolicy      CertPolicyId, 
 950         subjectDomainPolicy     CertPolicyId } 
 952 #define MAX_POLICY_MAPPINGS 8192 
 953 static bool SecCEPPolicyMappings(SecCertificateRef certificate
, 
 954         const SecCertificateExtension 
*extn
) { 
 955         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
 958     SecCEPolicyMapping 
*mappings 
= NULL
; 
 959     DERReturn drtn 
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &pmSeq
); 
 960     require_noerr_quiet(drtn
, badDER
); 
 961     require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
 962     DERDecodedInfo pmContent
; 
 963     DERSize mapping_count 
= 0; 
 964     while ((mapping_count 
< MAX_POLICY_MAPPINGS
) && 
 965            (drtn 
= DERDecodeSeqNext(&pmSeq
, &pmContent
)) == DR_Success
) { 
 966         require_quiet(pmContent
.tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
 969     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
 970     require_quiet(mappings 
= (SecCEPolicyMapping 
*)malloc(sizeof(SecCEPolicyMapping
) 
 971                                             * (mapping_count 
> 0 ? mapping_count 
: 1)), 
 973     drtn 
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &pmSeq
); 
 974     require_noerr_quiet(drtn
, badDER
); 
 975     DERSize mapping_ix 
= 0; 
 976     while ((mapping_ix 
< (mapping_count 
> 0 ? mapping_count 
: 1)) && 
 977            (drtn 
= DERDecodeSeqNext(&pmSeq
, &pmContent
)) == DR_Success
) { 
 978         require_quiet(pmContent
.tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
 980         drtn 
= DERParseSequenceContent(&pmContent
.content
, 
 981             DERNumPolicyMappingItemSpecs
, 
 982             DERPolicyMappingItemSpecs
, 
 984         require_noerr_quiet(drtn
, badDER
); 
 985         mappings
[mapping_ix
].issuerDomainPolicy 
= pm
.issuerDomainPolicy
; 
 986         mappings
[mapping_ix
++].subjectDomainPolicy 
= pm
.subjectDomainPolicy
; 
 988     certificate
->_policyMappings
.present 
= true; 
 989     certificate
->_policyMappings
.critical 
= extn
->critical
; 
 990     certificate
->_policyMappings
.numMappings 
= mapping_count
; 
 991     certificate
->_policyMappings
.mappings 
= mappings
; 
 997     certificate
->_policyMappings
.present 
= false; 
 998         secwarning("Invalid CertificatePolicies Extension"); 
1003 AuthorityKeyIdentifier ::= SEQUENCE { 
1004     keyIdentifier             [0] KeyIdentifier            OPTIONAL, 
1005     authorityCertIssuer       [1] GeneralNames             OPTIONAL, 
1006     authorityCertSerialNumber [2] CertificateSerialNumber  OPTIONAL } 
1007     -- authorityCertIssuer and authorityCertSerialNumber MUST both 
1008     -- be present or both be absent 
1010 KeyIdentifier ::= OCTET STRING 
1012 static bool SecCEPAuthorityKeyIdentifier(SecCertificateRef certificate
, 
1013         const SecCertificateExtension 
*extn
) { 
1014         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
1015         DERAuthorityKeyIdentifier akid
; 
1017         drtn 
= DERParseSequence(&extn
->extnValue
, 
1018                 DERNumAuthorityKeyIdentifierItemSpecs
, 
1019                 DERAuthorityKeyIdentifierItemSpecs
, 
1020                 &akid
, sizeof(akid
)); 
1021         require_noerr_quiet(drtn
, badDER
); 
1022         if (akid
.keyIdentifier
.length
) { 
1023                 certificate
->_authorityKeyIdentifier 
= akid
.keyIdentifier
; 
1025         if (akid
.authorityCertIssuer
.length 
|| 
1026                 akid
.authorityCertSerialNumber
.length
) { 
1027                 require_quiet(akid
.authorityCertIssuer
.length 
&& 
1028                         akid
.authorityCertSerialNumber
.length
, badDER
); 
1029                 /* Perhaps put in a subsection called Authority Certificate Issuer. */ 
1030                 certificate
->_authorityKeyIdentifierIssuer 
= akid
.authorityCertIssuer
; 
1031                 certificate
->_authorityKeyIdentifierSerialNumber 
= akid
.authorityCertSerialNumber
; 
1036         secwarning("Invalid AuthorityKeyIdentifier Extension"); 
1040 static bool SecCEPPolicyConstraints(SecCertificateRef certificate
, 
1041         const SecCertificateExtension 
*extn
) { 
1042         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
1043         DERPolicyConstraints pc
; 
1045         drtn 
= DERParseSequence(&extn
->extnValue
, 
1046                 DERNumPolicyConstraintsItemSpecs
, 
1047                 DERPolicyConstraintsItemSpecs
, 
1049         require_noerr_quiet(drtn
, badDER
); 
1050         if (pc
.requireExplicitPolicy
.length
) { 
1051         require_noerr_quiet(DERParseInteger( 
1052             &pc
.requireExplicitPolicy
, 
1053             &certificate
->_policyConstraints
.requireExplicitPolicy
), badDER
); 
1054         certificate
->_policyConstraints
.requireExplicitPolicyPresent 
= true; 
1056         if (pc
.inhibitPolicyMapping
.length
) { 
1057         require_noerr_quiet(DERParseInteger( 
1058             &pc
.inhibitPolicyMapping
, 
1059             &certificate
->_policyConstraints
.inhibitPolicyMapping
), badDER
); 
1060         certificate
->_policyConstraints
.inhibitPolicyMappingPresent 
= true; 
1063     certificate
->_policyConstraints
.present 
= true; 
1064     certificate
->_policyConstraints
.critical 
= extn
->critical
; 
1068     certificate
->_policyConstraints
.present 
= false; 
1069         secwarning("Invalid PolicyConstraints Extension"); 
1073 static bool SecCEPExtendedKeyUsage(SecCertificateRef certificate
, 
1074         const SecCertificateExtension 
*extn
) { 
1075         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
1080    InhibitAnyPolicy ::= SkipCerts 
1082    SkipCerts ::= INTEGER (0..MAX) 
1084 static bool SecCEPInhibitAnyPolicy(SecCertificateRef certificate
, 
1085         const SecCertificateExtension 
*extn
) { 
1086         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
1087     DERDecodedInfo iapContent
; 
1088     require_noerr_quiet(DERDecodeItem(&extn
->extnValue
, &iapContent
), badDER
); 
1089     require_quiet(iapContent
.tag 
== ASN1_INTEGER
, badDER
); 
1090     require_noerr_quiet(DERParseInteger( 
1091         &iapContent
.content
, 
1092         &certificate
->_inhibitAnyPolicySkipCerts
.skipCerts
), badDER
); 
1094     certificate
->_inhibitAnyPolicySkipCerts
.present 
= true; 
1095     certificate
->_inhibitAnyPolicySkipCerts
.critical 
= extn
->critical
; 
1098     certificate
->_inhibitAnyPolicySkipCerts
.present 
= false; 
1099         secwarning("Invalid InhibitAnyPolicy Extension"); 
1104    id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } 
1106    AuthorityInfoAccessSyntax  ::= 
1107            SEQUENCE SIZE (1..MAX) OF AccessDescription 
1109    AccessDescription  ::=  SEQUENCE { 
1110            accessMethod          OBJECT IDENTIFIER, 
1111            accessLocation        GeneralName  } 
1113    id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } 
1115    id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 } 
1117    id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } 
1119 static bool SecCEPAuthorityInfoAccess(SecCertificateRef certificate
, 
1120         const SecCertificateExtension 
*extn
) { 
1121         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
1124     DERReturn drtn 
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &adSeq
); 
1125     require_noerr_quiet(drtn
, badDER
); 
1126     require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
1127     DERDecodedInfo adContent
; 
1128     while ((drtn 
= DERDecodeSeqNext(&adSeq
, &adContent
)) == DR_Success
) { 
1129         require_quiet(adContent
.tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
1130                 DERAccessDescription ad
; 
1131                 drtn 
= DERParseSequenceContent(&adContent
.content
, 
1132                         DERNumAccessDescriptionItemSpecs
, 
1133                         DERAccessDescriptionItemSpecs
, 
1135                 require_noerr_quiet(drtn
, badDER
); 
1136         CFMutableArrayRef 
*urls
; 
1137         if (DEROidCompare(&ad
.accessMethod
, &oidAdOCSP
)) 
1138             urls 
= &certificate
->_ocspResponders
; 
1139         else if (DEROidCompare(&ad
.accessMethod
, &oidAdCAIssuer
)) 
1140             urls 
= &certificate
->_caIssuers
; 
1144         DERDecodedInfo generalNameContent
; 
1145         drtn 
= DERDecodeItem(&ad
.accessLocation
, &generalNameContent
); 
1146         require_noerr_quiet(drtn
, badDER
); 
1147         switch (generalNameContent
.tag
) { 
1149         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 6: 
1150             /* Technically I don't think this is valid, but there are certs out 
1151                in the wild that use a constructed IA5String.   In particular the 
1152                VeriSign Time Stamping Authority CA.cer does this.  */ 
1154         case ASN1_CONTEXT_SPECIFIC 
| 6: 
1156             CFURLRef url 
= CFURLCreateWithBytes(kCFAllocatorDefault
, 
1157                 generalNameContent
.content
.data
, generalNameContent
.content
.length
, 
1158                 kCFStringEncodingASCII
, NULL
); 
1161                     *urls 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
1162                 CFArrayAppendValue(*urls
, url
); 
1168             secdebug("cert", "bad general name for id-ad-ocsp AccessDescription t: 0x%02llx v: %.*s", 
1169                 generalNameContent
.tag
, (int) generalNameContent
.content
.length
, generalNameContent
.content
.data
); 
1174     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
1177     secwarning("Invalid Authority Information Access extension"); 
1181 /* Apple Worldwide Developer Relations Certificate Authority subject name. 
1182  * This is a DER sequence with the leading tag and length bytes removed, 
1183  * to match what tbsCert.issuer contains. 
1185 static const unsigned char Apple_WWDR_CA_Subject_Name
[]={ 
1186                  0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53, 
1187   0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65, 
1188   0x20,0x49,0x6E,0x63,0x2E,0x31,0x2C,0x30,0x2A,0x06,0x03,0x55,0x04,0x0B,0x0C,0x23, 
1189   0x41,0x70,0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20, 
1190   0x44,0x65,0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69, 
1191   0x6F,0x6E,0x73,0x31,0x44,0x30,0x42,0x06,0x03,0x55,0x04,0x03,0x0C,0x3B,0x41,0x70, 
1192   0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20,0x44,0x65, 
1193   0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,0x6F,0x6E, 
1194   0x73,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, 
1195   0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79 
1198 static void checkForMissingRevocationInfo(SecCertificateRef certificate
) { 
1200                 certificate
->_crlDistributionPoints 
|| 
1201                 certificate
->_ocspResponders
) { 
1202                 /* We already have an OCSP or CRL URI (or no cert) */ 
1205         /* Specify an appropriate OCSP responder if we recognize the issuer. */ 
1206         CFURLRef url 
= NULL
; 
1207         if (sizeof(Apple_WWDR_CA_Subject_Name
) == certificate
->_issuer
.length 
&& 
1208                 !memcmp(certificate
->_issuer
.data
, Apple_WWDR_CA_Subject_Name
, 
1209                                 sizeof(Apple_WWDR_CA_Subject_Name
))) { 
1210                 const char *WWDR_OCSP_URI 
= "http://ocsp.apple.com/ocsp-wwdr01"; 
1211                 url 
= CFURLCreateWithBytes(kCFAllocatorDefault
, 
1212                                 (const UInt8
*)WWDR_OCSP_URI
, strlen(WWDR_OCSP_URI
), 
1213                                 kCFStringEncodingASCII
, NULL
); 
1216                 CFMutableArrayRef 
*urls 
= &certificate
->_ocspResponders
; 
1217                 *urls 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
1218                 CFArrayAppendValue(*urls
, url
); 
1223 static bool SecCEPSubjectInfoAccess(SecCertificateRef certificate
, 
1224         const SecCertificateExtension 
*extn
) { 
1225         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
1229 static bool SecCEPNetscapeCertType(SecCertificateRef certificate
, 
1230         const SecCertificateExtension 
*extn
) { 
1231         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
1235 static bool SecCEPEntrustVersInfo(SecCertificateRef certificate
, 
1236         const SecCertificateExtension 
*extn
) { 
1237         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
1241 static bool SecCEPEscrowMarker(SecCertificateRef certificate
, 
1242                                const SecCertificateExtension 
*extn
) { 
1243         secdebug("cert", "critical: %s", extn
->critical 
? "yes" : "no"); 
1247 static bool SecCEPOCSPNoCheck(SecCertificateRef certificate
, 
1248                               const SecCertificateExtension 
*extn
) { 
1249     secdebug("cert", "ocsp-nocheck critical: %s", extn
->critical 
? "yes" : "no"); 
1253 /* Dictionary key callback for comparing to DERItems. */ 
1254 static Boolean 
SecDERItemEqual(const void *value1
, const void *value2
) { 
1255         return DEROidCompare((const DERItem 
*)value1
, (const DERItem 
*)value2
); 
1258 /* Dictionary key callback calculating the hash of a DERItem. */ 
1259 static CFHashCode 
SecDERItemHash(const void *value
) { 
1260         const DERItem 
*derItem 
= (const DERItem 
*)value
; 
1261         CFHashCode hash 
= derItem
->length
; 
1262         DERSize ix 
= derItem
->length 
> 8 ? derItem
->length 
- 8 : 0; 
1263         for (; ix 
< derItem
->length
; ++ix
) { 
1264                 hash 
= (hash 
<< 9) + (hash 
>> 23) + derItem
->data
[ix
]; 
1270 /* Dictionary key callbacks using the above 2 functions. */ 
1271 static const CFDictionaryKeyCallBacks SecDERItemKeyCallBacks 
= { 
1275         NULL
,                           /* copyDescription */ 
1276         SecDERItemEqual
,        /* equal */ 
1277         SecDERItemHash          
/* hash */ 
1280 static void SecCertificateInitializeExtensionParsers(void) { 
1281         /* Build a dictionary that maps from extension OIDs to callback functions 
1282      which can parse the extension of the type given. */ 
1283         static const void *extnOIDs
[] = { 
1284                 &oidSubjectKeyIdentifier
, 
1286                 &oidPrivateKeyUsagePeriod
, 
1289                 &oidBasicConstraints
, 
1290                 &oidNameConstraints
, 
1291                 &oidCrlDistributionPoints
, 
1292                 &oidCertificatePolicies
, 
1294                 &oidAuthorityKeyIdentifier
, 
1295                 &oidPolicyConstraints
, 
1296                 &oidExtendedKeyUsage
, 
1297                 &oidInhibitAnyPolicy
, 
1298                 &oidAuthorityInfoAccess
, 
1299                 &oidSubjectInfoAccess
, 
1300                 &oidNetscapeCertType
, 
1301                 &oidEntrustVersInfo
, 
1302         &oidApplePolicyEscrowService
, 
1305         static const void *extnParsers
[] = { 
1306                 SecCEPSubjectKeyIdentifier
, 
1308                 SecCEPPrivateKeyUsagePeriod
, 
1309                 SecCEPSubjectAltName
, 
1310                 SecCEPIssuerAltName
, 
1311                 SecCEPBasicConstraints
, 
1312                 SecCEPNameConstraints
, 
1313                 SecCEPCrlDistributionPoints
, 
1314                 SecCEPCertificatePolicies
, 
1315                 SecCEPPolicyMappings
, 
1316                 SecCEPAuthorityKeyIdentifier
, 
1317                 SecCEPPolicyConstraints
, 
1318                 SecCEPExtendedKeyUsage
, 
1319         SecCEPInhibitAnyPolicy
, 
1320                 SecCEPAuthorityInfoAccess
, 
1321                 SecCEPSubjectInfoAccess
, 
1322                 SecCEPNetscapeCertType
, 
1323                 SecCEPEntrustVersInfo
, 
1327         sExtensionParsers 
= CFDictionaryCreate(kCFAllocatorDefault
, extnOIDs
, 
1328                                            extnParsers
, array_size(extnOIDs
), 
1329                                            &SecDERItemKeyCallBacks
, NULL
); 
1332 CFGiblisWithFunctions(SecCertificate
, NULL
, NULL
, SecCertificateDestroy
, SecCertificateEqual
, SecCertificateHash
, NULL
, SecCertificateCopyDescription
, NULL
, NULL
, ^{ 
1333     SecCertificateInitializeExtensionParsers(); 
1336 static bool isAppleExtensionOID(const DERItem 
*extnID
) 
1338         static const uint8_t appleExtension
[8] = { 0x2a,0x86,0x48,0x86,0xf7,0x63,0x64,0x06 }; 
1339         return (extnID 
&& extnID
->data 
&& 
1340                         extnID
->length 
> sizeof(appleExtension
) && 
1341                         !memcmp(extnID
->data
, appleExtension
, sizeof(appleExtension
))); 
1344 /* Given the contents of an X.501 Name return the contents of a normalized 
1346 CFDataRef 
createNormalizedX501Name(CFAllocatorRef allocator
, 
1347         const DERItem 
*x501name
) { 
1348     CFMutableDataRef result 
= CFDataCreateMutable(allocator
, x501name
->length
); 
1349     CFIndex length 
= x501name
->length
; 
1350     CFDataSetLength(result
, length
); 
1351     UInt8 
*base 
= CFDataGetMutableBytePtr(result
); 
1354         DERReturn drtn 
= DERDecodeSeqContentInit(x501name
, &rdnSeq
); 
1356         require_noerr_quiet(drtn
, badDER
); 
1359     /* Always points to last rdn tag. */ 
1360     const DERByte 
*rdnTag 
= rdnSeq
.nextItem
; 
1361     /* Offset relative to base of current rdn set tag. */ 
1362     CFIndex rdnTagLocation 
= 0; 
1363         while ((drtn 
= DERDecodeSeqNext(&rdnSeq
, &rdn
)) == DR_Success
) { 
1364                 require_quiet(rdn
.tag 
== ASN1_CONSTR_SET
, badDER
); 
1365                 /* We don't allow empty RDNs. */ 
1366                 require_quiet(rdn
.content
.length 
!= 0, badDER
); 
1367         /* Length of the tag and length of the current rdn. */ 
1368         CFIndex rdnTLLength 
= rdn
.content
.data 
- rdnTag
; 
1369         CFIndex rdnContentLength 
= rdn
.content
.length
; 
1370         /* Copy the tag and length of the RDN. */ 
1371         memcpy(base 
+ rdnTagLocation
, rdnTag
, rdnTLLength
); 
1374                 drtn 
= DERDecodeSeqContentInit(&rdn
.content
, &atvSeq
); 
1375         require_quiet(drtn 
== DR_Success
, badDER
); 
1378         /* Always points to tag of current atv sequence. */ 
1379         const DERByte 
*atvTag 
= atvSeq
.nextItem
; 
1380         /* Offset relative to base of current atv sequence tag. */ 
1381         CFIndex atvTagLocation 
= rdnTagLocation 
+ rdnTLLength
; 
1382                 while ((drtn 
= DERDecodeSeqNext(&atvSeq
, &atv
)) == DR_Success
) { 
1383                         require_quiet(atv
.tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
1384             /* Length of the tag and length of the current atv. */ 
1385             CFIndex atvTLLength 
= atv
.content
.data 
- atvTag
; 
1386             CFIndex atvContentLength 
= atv
.content
.length
; 
1387             /* Copy the tag and length of the atv and the atv itself. */ 
1388             memcpy(base 
+ atvTagLocation
, atvTag
, 
1389                 atvTLLength 
+ atv
.content
.length
); 
1391             /* Now decode the atv sequence. */ 
1392                         DERAttributeTypeAndValue atvPair
; 
1393                         drtn 
= DERParseSequenceContent(&atv
.content
, 
1394                                 DERNumAttributeTypeAndValueItemSpecs
, 
1395                                 DERAttributeTypeAndValueItemSpecs
, 
1396                                 &atvPair
, sizeof(atvPair
)); 
1397                         require_noerr_quiet(drtn
, badDER
); 
1398                         require_quiet(atvPair
.type
.length 
!= 0, badDER
); 
1399             DERDecodedInfo value
; 
1400             drtn 
= DERDecodeItem(&atvPair
.value
, &value
); 
1401                         require_noerr_quiet(drtn
, badDER
); 
1403             /* (c) attribute values in PrintableString are not case sensitive 
1404                (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and 
1406                (d) attribute values in PrintableString are compared after 
1407                removing leading and trailing white space and converting internal 
1408                substrings of one or more consecutive white space characters to a 
1410             if (value
.tag 
== ASN1_PRINTABLE_STRING
) { 
1411                 /* Offset relative to base of current value tag. */ 
1412                 CFIndex valueTagLocation 
= atvTagLocation 
+ atvPair
.value
.data 
- atvTag
; 
1413                 CFIndex valueTLLength 
= value
.content
.data 
- atvPair
.value
.data
; 
1414                 CFIndex valueContentLength 
= value
.content
.length
; 
1416                 /* Now copy all the bytes, but convert to upper case while 
1417                    doing so and convert multiple whitespace chars into a 
1419                 bool lastWasBlank 
= false; 
1420                 CFIndex valueLocation 
= valueTagLocation 
+ valueTLLength
; 
1421                 CFIndex valueCurrentLocation 
= valueLocation
; 
1423                 for (ix 
= 0; ix 
< valueContentLength
; ++ix
) { 
1424                     UInt8 ch 
= value
.content
.data
[ix
]; 
1429                             /* Don't insert a space for first character 
1431                             if (valueCurrentLocation 
> valueLocation
) { 
1432                                 base
[valueCurrentLocation
++] = ' '; 
1434                             lastWasBlank 
= true; 
1437                         lastWasBlank 
= false; 
1438                         if ('a' <= ch 
&& ch 
<= 'z') { 
1439                             base
[valueCurrentLocation
++] = ch 
+ 'A' - 'a'; 
1441                             base
[valueCurrentLocation
++] = ch
; 
1445                 /* Finally if lastWasBlank remove the trailing space. */ 
1446                 if (lastWasBlank 
&& valueCurrentLocation 
> valueLocation
) { 
1447                     valueCurrentLocation
--; 
1449                 /* Adjust content length to normalized length. */ 
1450                 valueContentLength 
= valueCurrentLocation 
- valueLocation
; 
1452                 /* Number of bytes by which the length should be shorted. */ 
1453                 CFIndex lengthDiff 
= value
.content
.length 
- valueContentLength
; 
1454                 if (lengthDiff 
== 0) { 
1455                     /* Easy case no need to adjust lengths. */ 
1457                     /* Hard work we need to go back and fix up length fields 
1459                            1) The value itself. 
1460                            2) The ATV Sequence containing type/value 
1461                            3) The RDN Set containing one or more atv pairs. 
1465                     /* Step 1 fix up length of value. */ 
1466                     /* Length of value tag and length minus the tag. */ 
1467                     DERSize newValueTLLength 
= valueTLLength 
- 1; 
1468                     drtn 
= DEREncodeLength(valueContentLength
, 
1469                         base 
+ valueTagLocation 
+ 1, &newValueTLLength
); 
1470                     require(drtn 
== DR_Success
, badDER
); 
1471                     /* Add the length of the tag back in. */ 
1473                     CFIndex valueLLDiff 
= valueTLLength 
- newValueTLLength
; 
1475                         /* The size of the length field changed, let's slide 
1476                            the value back by valueLLDiff bytes. */ 
1477                         memmove(base 
+ valueTagLocation 
+ newValueTLLength
, 
1478                             base 
+ valueTagLocation 
+ valueTLLength
, 
1479                             valueContentLength
); 
1480                         /* The length diff for the enclosing object. */ 
1481                         lengthDiff 
+= valueLLDiff
; 
1484                     /* Step 2 fix up length of the enclosing ATV Sequence. */ 
1485                     atvContentLength 
-= lengthDiff
; 
1486                     DERSize newATVTLLength 
= atvTLLength 
- 1; 
1487                     drtn 
= DEREncodeLength(atvContentLength
, 
1488                         base 
+ atvTagLocation 
+ 1, &newATVTLLength
); 
1489                     require(drtn 
== DR_Success
, badDER
); 
1490                     /* Add the length of the tag back in. */ 
1492                     CFIndex atvLLDiff 
= atvTLLength 
- newATVTLLength
; 
1494                         /* The size of the length field changed, let's slide 
1495                            the value back by valueLLDiff bytes. */ 
1496                         memmove(base 
+ atvTagLocation 
+ newATVTLLength
, 
1497                             base 
+ atvTagLocation 
+ atvTLLength
, 
1499                         /* The length diff for the enclosing object. */ 
1500                         lengthDiff 
+= atvLLDiff
; 
1501                         atvTLLength 
= newATVTLLength
; 
1504                     /* Step 3 fix up length of enclosing RDN Set. */ 
1505                     rdnContentLength 
-= lengthDiff
; 
1506                     DERSize newRDNTLLength 
= rdnTLLength 
- 1; 
1507                     drtn 
= DEREncodeLength(rdnContentLength
, 
1508                         base 
+ rdnTagLocation 
+ 1, &newRDNTLLength
); 
1509                     require_quiet(drtn 
== DR_Success
, badDER
); 
1510                     /* Add the length of the tag back in. */ 
1512                     CFIndex rdnLLDiff 
= rdnTLLength 
- newRDNTLLength
; 
1514                         /* The size of the length field changed, let's slide 
1515                            the value back by valueLLDiff bytes. */ 
1516                         memmove(base 
+ rdnTagLocation 
+ newRDNTLLength
, 
1517                             base 
+ rdnTagLocation 
+ rdnTLLength
, 
1519                         /* The length diff for the enclosing object. */ 
1520                         lengthDiff 
+= rdnLLDiff
; 
1521                         rdnTLLength 
= newRDNTLLength
; 
1523                         /* Adjust the locations that might have changed due to 
1525                         atvTagLocation 
-= rdnLLDiff
; 
1527                     (void) lengthDiff
; // No next object, silence analyzer 
1530             atvTagLocation 
+= atvTLLength 
+ atvContentLength
; 
1531             atvTag 
= atvSeq
.nextItem
; 
1533         require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
1534         rdnTagLocation 
+= rdnTLLength 
+ rdnContentLength
; 
1535         rdnTag 
= rdnSeq
.nextItem
; 
1537         require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
1538     /* Truncate the result to the proper length. */ 
1539     CFDataSetLength(result
, rdnTagLocation
); 
1548 static CFDataRef 
SecDERItemCopySequence(DERItem 
*content
) { 
1549     DERSize seq_len_length 
= DERLengthOfLength(content
->length
); 
1550     size_t sequence_length 
= 1 + seq_len_length 
+ content
->length
; 
1551     CFMutableDataRef sequence 
= CFDataCreateMutable(kCFAllocatorDefault
, 
1553     CFDataSetLength(sequence
, sequence_length
); 
1554     uint8_t *sequence_ptr 
= CFDataGetMutableBytePtr(sequence
); 
1555     *sequence_ptr
++ = ONE_BYTE_ASN1_CONSTR_SEQUENCE
; 
1556     require_noerr_quiet(DEREncodeLength(content
->length
, 
1557                                         sequence_ptr
, &seq_len_length
), out
); 
1558     sequence_ptr 
+= seq_len_length
; 
1559     memcpy(sequence_ptr
, content
->data
, content
->length
); 
1562     CFReleaseSafe(sequence
); 
1566 static CFDataRef 
SecCopySequenceFromContent(CFDataRef content
) { 
1568     tmpItem
.data 
= (void *)CFDataGetBytePtr(content
); 
1569     tmpItem
.length 
= CFDataGetLength(content
); 
1571     return SecDERItemCopySequence(&tmpItem
); 
1574 CFDataRef 
SecDistinguishedNameCopyNormalizedContent(CFDataRef distinguished_name
) 
1576     const DERItem name 
= { (unsigned char *)CFDataGetBytePtr(distinguished_name
), CFDataGetLength(distinguished_name
) }; 
1577     DERDecodedInfo content
; 
1578     /* Decode top level sequence into DERItem */ 
1579     if (!DERDecodeItem(&name
, &content
) && (content
.tag 
== ASN1_CONSTR_SEQUENCE
)) 
1580         return createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
); 
1584 CFDataRef 
SecDistinguishedNameCopyNormalizedSequence(CFDataRef distinguished_name
) 
1586     if (!distinguished_name
) { return NULL
; } 
1587     CFDataRef normalizedContent 
= SecDistinguishedNameCopyNormalizedContent(distinguished_name
); 
1588     if (!normalizedContent
) { return NULL
; } 
1589     CFDataRef result 
= SecCopySequenceFromContent(normalizedContent
); 
1590     CFReleaseNull(normalizedContent
); 
1594 /* AUDIT[securityd]: 
1595    certificate->_der is a caller provided data of any length (might be 0). 
1597    Top level certificate decode. 
1599 static bool SecCertificateParse(SecCertificateRef certificate
) 
1604     require_quiet(certificate
, badCert
); 
1605     CFAllocatorRef allocator 
= CFGetAllocator(certificate
); 
1607         /* top level decode */ 
1608         DERSignedCertCrl signedCert
; 
1609         drtn 
= DERParseSequence(&certificate
->_der
, DERNumSignedCertCrlItemSpecs
, 
1610                 DERSignedCertCrlItemSpecs
, &signedCert
, 
1611                 sizeof(signedCert
)); 
1612         require_noerr_quiet(drtn
, badCert
); 
1613         /* Store tbs since we need to digest it for verification later on. */ 
1614         certificate
->_tbs 
= signedCert
.tbs
; 
1616         /* decode the TBSCert - it was saved in full DER form */ 
1618         drtn 
= DERParseSequence(&signedCert
.tbs
, 
1619                 DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
, 
1620                 &tbsCert
, sizeof(tbsCert
)); 
1621         require_noerr_quiet(drtn
, badCert
); 
1623         /* sequence we're given: decode the signedCerts Signature Algorithm. */ 
1624         /* This MUST be the same as the certificate->_tbsSigAlg with the exception 
1625            of the params field. */ 
1626         drtn 
= DERParseSequenceContent(&signedCert
.sigAlg
, 
1627                 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
, 
1628                 &certificate
->_sigAlg
, sizeof(certificate
->_sigAlg
)); 
1629         require_noerr_quiet(drtn
, badCert
); 
1631         /* The contents of signedCert.sig is a bit string whose contents 
1632            are the signature itself. */ 
1633     DERByte numUnusedBits
; 
1634         drtn 
= DERParseBitString(&signedCert
.sig
, 
1635         &certificate
->_signature
, &numUnusedBits
); 
1636         require_noerr_quiet(drtn
, badCert
); 
1638     /* Now decode the tbsCert. */ 
1640     /* First we turn the optional version into an int. */ 
1641     if (tbsCert
.version
.length
) { 
1642         DERDecodedInfo decoded
; 
1643         drtn 
= DERDecodeItem(&tbsCert
.version
, &decoded
); 
1644         require_noerr_quiet(drtn
, badCert
); 
1645         require_quiet(decoded
.tag 
== ASN1_INTEGER
, badCert
); 
1646         require_quiet(decoded
.content
.length 
== 1, badCert
); 
1647         certificate
->_version 
= decoded
.content
.data
[0]; 
1648         if (certificate
->_version 
> 2) { 
1649             secwarning("Invalid certificate version (%d), must be 0..2", 
1650                 certificate
->_version
); 
1652         require_quiet(certificate
->_version 
> 0, badCert
); 
1653         require_quiet(certificate
->_version 
< 3, badCert
); 
1655         certificate
->_version 
= 0; 
1658     /* The serial number is in the tbsCert.serialNum - it was saved in 
1659        INTEGER form without the tag and length. */ 
1660     certificate
->_serialNum 
= tbsCert
.serialNum
; 
1662     /* Note: RFC5280 4.1.2.2 limits serial number values to 20 octets. 
1663        For now, we warn about larger values, but will still create the 
1664        certificate with values up to 36 octets to avoid breaking some 
1665        nonconforming certs with slightly longer serial numbers. 
1666        We also explicitly allow serial numbers of 21 octets where the 
1667        leading byte is 0x00 which is used to make a negative 20 octet 
1670     if (tbsCert
.serialNum
.length 
< 1 || tbsCert
.serialNum
.length 
> 21 || 
1671         (tbsCert
.serialNum
.length 
== 21 && tbsCert
.serialNum
.data
[0] != 0x00)) { 
1672         secwarning("Invalid serial number length (%ld), must be 1..20", 
1673             tbsCert
.serialNum
.length
); 
1675     require_quiet(tbsCert
.serialNum
.data 
!= NULL 
&& 
1676                   tbsCert
.serialNum
.length 
>= 1 && 
1677                   tbsCert
.serialNum
.length 
<= 37, badCert
); 
1678     certificate
->_serialNumber 
= CFDataCreate(allocator
, 
1679         tbsCert
.serialNum
.data
, tbsCert
.serialNum
.length
); 
1681         /* sequence we're given: decode the tbsCerts TBS Signature Algorithm. */ 
1682         drtn 
= DERParseSequenceContent(&tbsCert
.tbsSigAlg
, 
1683                 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
, 
1684                 &certificate
->_tbsSigAlg
, sizeof(certificate
->_tbsSigAlg
)); 
1685         require_noerr_quiet(drtn
, badCert
); 
1687         /* The issuer is in the tbsCert.issuer - it's a sequence without the tag 
1688        and length fields. */ 
1689         certificate
->_issuer 
= tbsCert
.issuer
; 
1690     certificate
->_normalizedIssuer 
= createNormalizedX501Name(allocator
, 
1693         /* sequence we're given: decode the tbsCerts Validity sequence. */ 
1694     DERValidity validity
; 
1695         drtn 
= DERParseSequenceContent(&tbsCert
.validity
, 
1696                 DERNumValidityItemSpecs
, DERValidityItemSpecs
, 
1697                 &validity
, sizeof(validity
)); 
1698         require_noerr_quiet(drtn
, badCert
); 
1699     require_quiet(derDateGetAbsoluteTime(&validity
.notBefore
, 
1700         &certificate
->_notBefore
), badCert
); 
1701     require_quiet(derDateGetAbsoluteTime(&validity
.notAfter
, 
1702         &certificate
->_notAfter
), badCert
); 
1704         /* The subject is in the tbsCert.subject - it's a sequence without the tag 
1705        and length fields. */ 
1706         certificate
->_subject 
= tbsCert
.subject
; 
1707     certificate
->_normalizedSubject 
= createNormalizedX501Name(allocator
, 
1710     /* Keep the SPKI around for CT */ 
1711     certificate
->_subjectPublicKeyInfo 
= tbsCert
.subjectPubKey
; 
1713         /* sequence we're given: encoded DERSubjPubKeyInfo */ 
1714         DERSubjPubKeyInfo pubKeyInfo
; 
1715         drtn 
= DERParseSequenceContent(&tbsCert
.subjectPubKey
, 
1716                 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
, 
1717                 &pubKeyInfo
, sizeof(pubKeyInfo
)); 
1718         require_noerr_quiet(drtn
, badCert
); 
1720         /* sequence we're given: decode the pubKeyInfos DERAlgorithmId */ 
1721         drtn 
= DERParseSequenceContent(&pubKeyInfo
.algId
, 
1722                 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
, 
1723                 &certificate
->_algId
, sizeof(certificate
->_algId
)); 
1724         require_noerr_quiet(drtn
, badCert
); 
1726         /* Now we can figure out the key's algorithm id and params based on 
1727            certificate->_algId.oid. */ 
1729         /* The contents of pubKeyInfo.pubKey is a bit string whose contents 
1730            are a PKCS1 format RSA key. */ 
1731         drtn 
= DERParseBitString(&pubKeyInfo
.pubKey
, 
1732         &certificate
->_pubKeyDER
, &numUnusedBits
); 
1733         require_noerr_quiet(drtn
, badCert
); 
1735         /* The contents of tbsCert.issuerID is a bit string. */ 
1736         certificate
->_issuerUniqueID 
= tbsCert
.issuerID
; 
1738         /* The contents of tbsCert.subjectID is a bit string. */ 
1739         certificate
->_subjectUniqueID 
= tbsCert
.subjectID
; 
1742     if (tbsCert
.extensions
.length
) { 
1743         CFIndex extensionCount 
= 0; 
1746         drtn 
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
, 
1748         require_noerr_quiet(drtn
, badCert
); 
1749         require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, badCert
); 
1750         DERDecodedInfo currDecoded
; 
1751         while ((drtn 
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) { 
1753 /* ! = MUST recognize ? = SHOULD recognize 
1756     KnownExtension      _subjectKeyID
;          /* ?SubjectKeyIdentifier     id-ce 14 */ 
1757     KnownExtension      _keyUsage
;              /* !KeyUsage                 id-ce 15 */ 
1758     KnownExtension      _subjectAltName
;        /* !SubjectAltName           id-ce 17 */ 
1759     KnownExtension      _basicConstraints
;      /* !BasicConstraints         id-ce 19 */ 
1760     KnownExtension      _authorityKeyID
;        /* ?AuthorityKeyIdentifier   id-ce 35 */ 
1761     KnownExtension      _extKeyUsage
;           /* !ExtKeyUsage              id-ce 37 */ 
1762     KnownExtension      _netscapeCertType
;      /* 2.16.840.1.113730.1.1 netscape 1 1 */ 
1763     KnownExtension      _qualCertStatements
;    /* QCStatements             id-pe 3 */ 
1765     KnownExtension      _issuerAltName
;         /* IssuerAltName            id-ce 18 */ 
1766     KnownExtension      _nameConstraints
;       /* !NameConstraints          id-ce 30 */ 
1767     KnownExtension      _cRLDistributionPoints
; /* CRLDistributionPoints    id-ce 31 */ 
1768     KnownExtension      _certificatePolicies
;   /* !CertificatePolicies      id-ce 32 */ 
1769     KnownExtension      _policyMappings
;        /* ?PolicyMappings           id-ce 33 */ 
1770     KnownExtension      _policyConstraints
;     /* !PolicyConstraints        id-ce 36 */ 
1771     KnownExtension      _freshestCRL
;           /* FreshestCRL              id-ce 46 */ 
1772     KnownExtension      _inhibitAnyPolicy
;      /* !InhibitAnyPolicy         id-ce 54 */ 
1774     KnownExtension      _authorityInfoAccess
;   /* AuthorityInfoAccess      id-pe 1 */ 
1775     KnownExtension      _subjectInfoAccess
;     /* SubjectInfoAccess        id-pe 11 */ 
1780         require_quiet(drtn 
== DR_EndOfSequence
, badCert
); 
1782         /* Put some upper limit on the number of extensions allowed. */ 
1783         require_quiet(extensionCount 
< 10000, badCert
); 
1784         certificate
->_extensionCount 
= extensionCount
; 
1785         certificate
->_extensions 
= 
1786         malloc(sizeof(SecCertificateExtension
) * (extensionCount 
> 0 ? extensionCount 
: 1)); 
1787         require_quiet(certificate
->_extensions
, badCert
); 
1790         drtn 
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
, &derSeq
); 
1791         require_noerr_quiet(drtn
, badCert
); 
1792         for (ix 
= 0; ix 
< extensionCount
; ++ix
) { 
1793             drtn 
= DERDecodeSeqNext(&derSeq
, &currDecoded
); 
1794             require_quiet(drtn 
== DR_Success 
|| 
1795                 (ix 
== extensionCount 
- 1 && drtn 
== DR_EndOfSequence
), badCert
); 
1796             require_quiet(currDecoded
.tag 
== ASN1_CONSTR_SEQUENCE
, badCert
); 
1798             drtn 
= DERParseSequenceContent(&currDecoded
.content
, 
1799                 DERNumExtensionItemSpecs
, DERExtensionItemSpecs
, 
1800                 &extn
, sizeof(extn
)); 
1801             require_noerr_quiet(drtn
, badCert
); 
1802             /* Copy stuff into certificate->extensions[ix]. */ 
1803             certificate
->_extensions
[ix
].extnID 
= extn
.extnID
; 
1804             require_noerr_quiet(drtn 
= DERParseBooleanWithDefault(&extn
.critical
, false, 
1805                 &certificate
->_extensions
[ix
].critical
), badCert
); 
1806             certificate
->_extensions
[ix
].extnValue 
= extn
.extnValue
; 
1808                         SecCertificateExtensionParser parser 
= 
1809                                 (SecCertificateExtensionParser
)CFDictionaryGetValue( 
1810                                 sExtensionParsers
, &certificate
->_extensions
[ix
].extnID
); 
1812                                 /* Invoke the parser. If the extension is critical and the 
1813                  * parser fails, fail the cert. */ 
1814                 require_quiet(parser(certificate
, &certificate
->_extensions
[ix
]) || 
1815                               !certificate
->_extensions
[ix
].critical
, badCert
); 
1816                         } else if (certificate
->_extensions
[ix
].critical
) { 
1817                                 if (isAppleExtensionOID(&extn
.extnID
)) { 
1820                                 secdebug("cert", "Found unknown critical extension"); 
1821                                 certificate
->_foundUnknownCriticalExtension 
= true; 
1823                                 secdebug("cert", "Found unknown non critical extension"); 
1827         checkForMissingRevocationInfo(certificate
); 
1836 /* Public API functions. */ 
1837 SecCertificateRef 
SecCertificateCreateWithBytes(CFAllocatorRef allocator
, 
1838         const UInt8 
*der_bytes
, CFIndex der_length
) { 
1839         if (der_bytes 
== NULL
) return NULL
; 
1840     if (der_length 
== 0) return NULL
; 
1842     CFIndex size 
= sizeof(struct __SecCertificate
) + der_length
; 
1843     SecCertificateRef result 
= (SecCertificateRef
)_CFRuntimeCreateInstance( 
1844                 allocator
, SecCertificateGetTypeID(), size 
- sizeof(CFRuntimeBase
), 0); 
1846                 memset((char*)result 
+ sizeof(result
->_base
), 0, 
1847                         sizeof(*result
) - sizeof(result
->_base
)); 
1848                 result
->_der
.data 
= ((DERByte 
*)result 
+ sizeof(*result
)); 
1849                 result
->_der
.length 
= der_length
; 
1850                 memcpy(result
->_der
.data
, der_bytes
, der_length
); 
1851                 if (!SecCertificateParse(result
)) { 
1859 /* @@@ Placeholder until <rdar://problem/5701851> iap submits a binary is fixed. */ 
1860 SecCertificateRef 
SecCertificateCreate(CFAllocatorRef allocator
, 
1861         const UInt8 
*der_bytes
, CFIndex der_length
); 
1863 SecCertificateRef 
SecCertificateCreate(CFAllocatorRef allocator
, 
1864         const UInt8 
*der_bytes
, CFIndex der_length
) { 
1865     return SecCertificateCreateWithBytes(allocator
, der_bytes
, der_length
); 
1867 /* @@@ End of placeholder. */ 
1869 /* AUDIT[securityd](done): 
1870    der_certificate is a caller provided data of any length (might be 0), only 
1871    its cf type has been checked. 
1873 SecCertificateRef 
SecCertificateCreateWithData(CFAllocatorRef allocator
, 
1874         CFDataRef der_certificate
) { 
1875         if (!der_certificate
) { 
1878         CFIndex size 
= sizeof(struct __SecCertificate
); 
1879         SecCertificateRef result 
= (SecCertificateRef
)_CFRuntimeCreateInstance( 
1880                 allocator
, SecCertificateGetTypeID(), size 
- sizeof(CFRuntimeBase
), 0); 
1882                 memset((char*)result 
+ sizeof(result
->_base
), 0, size 
- sizeof(result
->_base
)); 
1883                 result
->_der_data 
= CFDataCreateCopy(allocator
, der_certificate
); 
1884                 result
->_der
.data 
= (DERByte 
*)CFDataGetBytePtr(result
->_der_data
); 
1885                 result
->_der
.length 
= CFDataGetLength(result
->_der_data
); 
1886                 if (!SecCertificateParse(result
)) { 
1894 SecCertificateRef 
SecCertificateCreateWithKeychainItem(CFAllocatorRef allocator
, 
1895         CFDataRef der_certificate
, 
1896         CFTypeRef keychain_item
) 
1898         SecCertificateRef result 
= SecCertificateCreateWithData(allocator
, der_certificate
); 
1900                 CFRetainSafe(keychain_item
); 
1901                 result
->_keychain_item 
= keychain_item
; 
1906 OSStatus 
SecCertificateSetKeychainItem(SecCertificateRef certificate
, 
1907         CFTypeRef keychain_item
) 
1912         CFRetainSafe(keychain_item
); 
1913         CFReleaseSafe(certificate
->_keychain_item
); 
1914         certificate
->_keychain_item 
= keychain_item
; 
1915         return errSecSuccess
; 
1918 CFDataRef 
SecCertificateCopyData(SecCertificateRef certificate
) { 
1920         CFDataRef result 
= NULL
; 
1924         if (certificate
->_der_data
) { 
1925         CFRetain(certificate
->_der_data
); 
1926         result 
= certificate
->_der_data
; 
1928                 result 
= CFDataCreate(CFGetAllocator(certificate
), 
1929             certificate
->_der
.data
, certificate
->_der
.length
); 
1931                 /* FIXME: If we wish to cache result we need to lock the certificate. 
1932            Also this create 2 copies of the certificate data which is somewhat 
1935         certificate
->_der_data 
= result
; 
1942 CFIndex 
SecCertificateGetLength(SecCertificateRef certificate
) { 
1943         return certificate
->_der
.length
; 
1946 const UInt8 
*SecCertificateGetBytePtr(SecCertificateRef certificate
) { 
1947         return certificate
->_der
.data
; 
1950 /* Used to recreate preCert from cert for Certificate Transparency */ 
1951 CFDataRef 
SecCertificateCopyPrecertTBS(SecCertificateRef certificate
) 
1953     CFDataRef outData 
= NULL
; 
1954     DERItem tbsIn 
= certificate
->_tbs
; 
1955     DERItem tbsOut 
= {0,}; 
1956     DERItem extensionsOut 
= {0,}; 
1957     DERItem 
*extensionsList 
= malloc(sizeof(DERItem
)*certificate
->_extensionCount
); /* This maybe one too many */ 
1958     DERItemSpec 
*extensionsListSpecs 
= malloc(sizeof(DERItemSpec
)*certificate
->_extensionCount
); 
1962     require_quiet(extensionsList 
&& extensionsListSpecs
, out
); 
1964     /* decode the TBSCert - it was saved in full DER form */ 
1965     drtn 
= DERParseSequence(&tbsIn
, 
1966                             DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
, 
1967                             &tbsCert
, sizeof(tbsCert
)); 
1968     require_noerr_quiet(drtn
, out
); 
1970     /* Go over extensions and filter any SCT extension */ 
1971     CFIndex extensionsCount 
= 0; 
1973     if (tbsCert
.extensions
.length
) { 
1976         drtn 
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
, 
1978         require_noerr_quiet(drtn
, out
); 
1979         require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, out
); 
1980         DERDecodedInfo currDecoded
; 
1981         while ((drtn 
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) { 
1983             require_quiet(currDecoded
.tag 
== ASN1_CONSTR_SEQUENCE
, out
); 
1985             drtn 
= DERParseSequenceContent(&currDecoded
.content
, 
1986                                            DERNumExtensionItemSpecs
, DERExtensionItemSpecs
, 
1987                                            &extn
, sizeof(extn
)); 
1988             require_noerr_quiet(drtn
, out
); 
1990             if (extn
.extnID
.length 
== oidGoogleEmbeddedSignedCertificateTimestamp
.length 
&& 
1991                 !memcmp(extn
.extnID
.data
, oidGoogleEmbeddedSignedCertificateTimestamp
.data
, extn
.extnID
.length
)) 
1994             extensionsList
[extensionsCount
] = currDecoded
.content
; 
1995             extensionsListSpecs
[extensionsCount
].offset 
= sizeof(DERItem
)*extensionsCount
; 
1996             extensionsListSpecs
[extensionsCount
].options 
= 0; 
1997             extensionsListSpecs
[extensionsCount
].tag 
= ASN1_CONSTR_SEQUENCE
; 
2002         require_quiet(drtn 
== DR_EndOfSequence
, out
); 
2006     /* Encode extensions */ 
2007     extensionsOut
.length 
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, extensionsList
, extensionsCount
, extensionsListSpecs
); 
2008     extensionsOut
.data 
= malloc(extensionsOut
.length
); 
2009     require_quiet(extensionsOut
.data
, out
); 
2010     drtn 
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, extensionsList
, extensionsCount
, extensionsListSpecs
, extensionsOut
.data
, &extensionsOut
.length
); 
2011     require_noerr_quiet(drtn
, out
); 
2013     tbsCert
.extensions 
= extensionsOut
; 
2015     tbsOut
.length 
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &tbsCert
, DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
); 
2016     tbsOut
.data 
= malloc(tbsOut
.length
); 
2017     require_quiet(tbsOut
.data
, out
); 
2018     drtn 
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &tbsCert
, DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
, tbsOut
.data
, &tbsOut
.length
); 
2019     require_noerr_quiet(drtn
, out
); 
2021     outData 
= CFDataCreate(kCFAllocatorDefault
, tbsOut
.data
, tbsOut
.length
); 
2024     if (extensionsOut
.data
) free(extensionsOut
.data
); 
2025     if (tbsOut
.data
) free(tbsOut
.data
); 
2026     if (extensionsList
) free(extensionsList
); 
2027     if (extensionsListSpecs
) free(extensionsListSpecs
); 
2032 /* From rfc3280 - Appendix B.  ASN.1 Notes 
2034    Object Identifiers (OIDs) are used throughout this specification to 
2035    identify certificate policies, public key and signature algorithms, 
2036    certificate extensions, etc.  There is no maximum size for OIDs. 
2037    This specification mandates support for OIDs which have arc elements 
2038    with values that are less than 2^28, that is, they MUST be between 0 
2039    and 268,435,455, inclusive.  This allows each arc element to be 
2040    represented within a single 32 bit word.  Implementations MUST also 
2041    support OIDs where the length of the dotted decimal (see [RFC 2252], 
2042    section 4.1) string representation can be up to 100 bytes 
2043    (inclusive).  Implementations MUST be able to handle OIDs with up to 
2044    20 elements (inclusive).  CAs SHOULD NOT issue certificates which 
2045    contain OIDs that exceed these requirements.  Likewise, CRL issuers 
2046    SHOULD NOT issue CRLs which contain OIDs that exceed these 
2050 /* Oids longer than this are considered invalid. */ 
2051 #define MAX_OID_SIZE                            32 
2053 CFStringRef 
SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator
, 
2054     const DERItem 
*oid
) { 
2056         if (oid
->length 
== 0) { 
2057         return SecCopyCertString(SEC_NULL_KEY
); 
2059         if (oid
->length 
> MAX_OID_SIZE
) { 
2060         return SecCopyCertString(SEC_OID_TOO_LONG_KEY
); 
2063     CFMutableStringRef result 
= CFStringCreateMutable(allocator
, 0); 
2065         // The first two levels are encoded into one byte, since the root level 
2066         // has only 3 nodes (40*x + y).  However if x = joint-iso-itu-t(2) then 
2067         // y may be > 39, so we have to add special-case handling for this. 
2068         uint32_t x 
= oid
->data
[0] / 40; 
2069         uint32_t y 
= oid
->data
[0] % 40; 
2072                 // Handle special case for large y if x = 2 
2076     CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
); 
2079         for (x 
= 1; x 
< oid
->length
; ++x
) 
2081                 value 
= (value 
<< 7) | (oid
->data
[x
] & 0x7F); 
2082         /* @@@ value may not span more than 4 bytes. */ 
2083         /* A max number of 20 values is allowed. */ 
2084                 if (!(oid
->data
[x
] & 0x80)) 
2086             CFStringAppendFormat(result
, NULL
, CFSTR(".%" PRIu32
), value
); 
2093 static CFStringRef 
copyOidDescription(CFAllocatorRef allocator
, 
2094     const DERItem 
*oid
, bool localized
) { 
2095         if (!oid 
|| oid
->length 
== 0) { 
2096         return (localized
) ? SecCopyCertString(SEC_NULL_KEY
) : SEC_NULL_KEY
; 
2099     CFStringRef name 
= SecDERItemCopyOIDDecimalRepresentation(allocator
, oid
); 
2104     /* Build the key we use to lookup the localized OID description. */ 
2105     CFMutableStringRef oidKey 
= CFStringCreateMutable(allocator
, 
2106         oid
->length 
* 3 + 5); 
2107     CFStringAppendFormat(oidKey
, NULL
, CFSTR("06 %02lX"), oid
->length
); 
2108     for (DERSize ix 
= 0; ix 
< oid
->length
; ++ix
) { 
2109         CFStringAppendFormat(oidKey
, NULL
, CFSTR(" %02X"), oid
->data
[ix
]); 
2111     CFStringRef locname 
= SecFrameworkCopyLocalizedString(oidKey
, CFSTR("OID")); 
2112     if (locname 
&& !CFEqual(oidKey
, locname
)) { 
2113         /* Found localized description string, so use it instead of OID. */ 
2114         CFReleaseSafe(name
); 
2117         CFReleaseSafe(locname
); 
2124 /* Return the ipAddress as a dotted quad for ipv4, or as 8 colon separated 
2125    4 digit hex strings for ipv6.  Return NULL if the provided IP doesn't 
2126    have a length of exactly 4 or 16 octets. 
2128 static CFStringRef 
copyIPAddressContentDescription(CFAllocatorRef allocator
, 
2129         const DERItem 
*ip
) { 
2130     /* This is the IP Address as an OCTET STRING. 
2131        For IPv4 it's 4 octets addr, or 8 octets, addr/mask. 
2132        For IPv6 it's 16 octets addr, or 32 octets addr/mask. 
2134         CFStringRef value 
= NULL
; 
2135         if (ip
->length 
== 4) { 
2136                 value 
= CFStringCreateWithFormat(allocator
, NULL
, 
2137                         CFSTR("%u.%u.%u.%u"), 
2138                         ip
->data
[0], ip
->data
[1], ip
->data
[2], ip
->data
[3]); 
2139         } else if (ip
->length 
== 16) { 
2140                 value 
= CFStringCreateWithFormat(allocator
, NULL
, 
2141                         CFSTR("%02x%02x:%02x%02x:%02x%02x:%02x%02x:" 
2142                         "%02x%02x:%02x%02x:%02x%02x:%02x%02x"), 
2143                         ip
->data
[0], ip
->data
[1], ip
->data
[2], ip
->data
[3], 
2144                         ip
->data
[4], ip
->data
[5], ip
->data
[6], ip
->data
[7], 
2145                         ip
->data
[8], ip
->data
[9], ip
->data
[10], ip
->data
[11], 
2146                         ip
->data
[12], ip
->data
[13], ip
->data
[14], ip
->data
[15]); 
2152 void appendProperty(CFMutableArrayRef properties
, CFStringRef propertyType
, 
2153     CFStringRef label
, CFStringRef localizedLabel
, CFTypeRef value
, 
2155     CFDictionaryRef property
; 
2157         CFStringRef ll 
= NULL
; 
2159             /* use unlocalized label, overriding localizedLabel */ 
2160             ll 
= localizedLabel 
= (CFStringRef
) CFRetainSafe(label
); 
2161         } else if (!localizedLabel
) { 
2162             /* copy localized label for unlocalized label */ 
2163             ll 
= localizedLabel 
= SecCopyCertString(label
); 
2165         const void *all_keys
[4]; 
2166         all_keys
[0] = kSecPropertyKeyType
; 
2167         all_keys
[1] = kSecPropertyKeyLabel
; 
2168         all_keys
[2] = kSecPropertyKeyLocalizedLabel
; 
2169         all_keys
[3] = kSecPropertyKeyValue
; 
2170         const void *property_values
[] = { 
2176         property 
= CFDictionaryCreate(CFGetAllocator(properties
), 
2177             all_keys
, property_values
, value 
? 4 : 3, 
2178             &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
2181         const void *nolabel_keys
[2]; 
2182         nolabel_keys
[0] = kSecPropertyKeyType
; 
2183         nolabel_keys
[1] = kSecPropertyKeyValue
; 
2184         const void *property_values
[] = { 
2188         property 
= CFDictionaryCreate(CFGetAllocator(properties
), 
2189             nolabel_keys
, property_values
, 2, 
2190             &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
2193     CFArrayAppendValue(properties
, property
); 
2194     CFRelease(property
); 
2198 #define UTC_TIME_NOSEC_ZULU_LEN                 11 
2200 #define UTC_TIME_ZULU_LEN                               13 
2201 /* YYMMDDhhmmssThhmm */ 
2202 #define UTC_TIME_LOCALIZED_LEN                  17 
2203 /* YYYYMMDDhhmmssZ */ 
2204 #define GENERALIZED_TIME_ZULU_LEN               15 
2205 /* YYYYMMDDhhmmssThhmm */ 
2206 #define GENERALIZED_TIME_LOCALIZED_LEN  19 
2208 /* Parse 2 digits at (*p)[0] and (*p)[1] and return the result.  Also 
2210 static inline int parseDecimalPair(const DERByte 
**p
) { 
2211     const DERByte 
*cp 
= *p
; 
2213     return 10 * (cp
[0] - '0') + cp
[1] - '0'; 
2216 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. 
2217    Return a CFErrorRef in the error parameter if decoding fails. 
2218    Note that this is needed to distinguish an error condition from a 
2219    valid time which specifies 2001-01-01 00:00:00 (i.e. a value of 0). 
2221 static CFAbsoluteTime 
SecAbsoluteTimeFromDateContentWithError(DERTag tag
, 
2222         const uint8_t *bytes
, 
2224         CFErrorRef 
*error
) { 
2228         if (NULL 
== bytes 
|| 0 == length
) { 
2232         bool isUtcLength 
= false; 
2233         bool isLocalized 
= false; 
2234         bool noSeconds 
= false; 
2236                 case UTC_TIME_NOSEC_ZULU_LEN
:       /* YYMMDDhhmmZ */ 
2240                 case UTC_TIME_ZULU_LEN
:             /* YYMMDDhhmmssZ */ 
2243                 case GENERALIZED_TIME_ZULU_LEN
:     /* YYYYMMDDhhmmssZ */ 
2245                 case UTC_TIME_LOCALIZED_LEN
:        /* YYMMDDhhmmssThhmm (where T=[+,-]) */ 
2248                 case GENERALIZED_TIME_LOCALIZED_LEN
:/* YYYYMMDDhhmmssThhmm (where T=[+,-]) */ 
2251                 default:                            /* unknown format */ 
2255         /* Make sure the der tag fits the thing inside it. */ 
2256         if (tag 
== ASN1_UTC_TIME
) { 
2260         } else if (tag 
== ASN1_GENERALIZED_TIME
) { 
2268         const DERByte 
*cp 
= bytes
; 
2269         /* Check that all characters are digits, except if localized the timezone 
2270            indicator or if not localized the 'Z' at the end.  */ 
2272         for (ix 
= 0; ix 
< length
; ++ix
) { 
2273                 if (!(isdigit(cp
[ix
]))) { 
2274                         if ((isLocalized 
&& ix 
== length 
- 5 && 
2275                                  (cp
[ix
] == '+' || cp
[ix
] == '-')) || 
2276                                 (!isLocalized 
&& ix 
== length 
- 1 && cp
[ix
] == 'Z')) { 
2283         /* Parse the date and time fields. */ 
2284         int year
, month
, day
, hour
, minute
, second
; 
2286                 year 
= parseDecimalPair(&cp
); 
2288                         /* 0  <= year <  50 : assume century 21 */ 
2290                 } else if (year 
< 70) { 
2291                         /* 50 <= year <  70 : illegal per PKIX */ 
2294                         /* 70 <  year <= 99 : assume century 20 */ 
2298                 year 
= 100 * parseDecimalPair(&cp
) + parseDecimalPair(&cp
); 
2300         month 
= parseDecimalPair(&cp
); 
2301         day 
= parseDecimalPair(&cp
); 
2302         hour 
= parseDecimalPair(&cp
); 
2303         minute 
= parseDecimalPair(&cp
); 
2307                 second 
= parseDecimalPair(&cp
); 
2310         CFTimeInterval timeZoneOffset
; 
2312                 /* ZONE INDICATOR */ 
2313         int multiplier 
= *cp
++ == '+' ? 60 : -60; 
2314         timeZoneOffset 
= multiplier 
* 
2315             (parseDecimalPair(&cp
) * 60 + parseDecimalPair(&cp
)); 
2320     secdebug("dateparse", 
2321         "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g", 
2322         (int) length
, bytes
, year
, month
, 
2323         day
, hour
, minute
, second
, 
2324         timeZoneOffset 
/ 60); 
2326     static int mdays
[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; 
2327     int is_leap_year 
= year 
% 4 == 0 && (year 
% 100 != 0 || year 
% 400 == 0) ? 1 : 0; 
2328     if (month 
< 1 || month 
> 12 || day 
< 1 || day 
> 31 || hour 
> 23 || minute 
> 59 || second 
> 59 
2329         || (month 
== 2 && day 
> mdays
[month
] - mdays
[month 
- 1] + is_leap_year
) 
2330         || (month 
!= 2 && day 
> mdays
[month
] - mdays
[month 
- 1])) { 
2335     int dy 
= year 
- 2001; 
2340     int leap_days 
= dy 
/ 4 - dy 
/ 100 + dy 
/ 400; 
2341     day 
+= ((year 
- 2001) * 365 + leap_days
) + mdays
[month 
- 1] - 1; 
2343         day 
+= is_leap_year
; 
2345     CFAbsoluteTime absTime 
= (CFAbsoluteTime
)((day 
* 24.0 + hour
) * 60.0 + minute
) * 60.0 + second
; 
2346     return absTime 
- timeZoneOffset
; 
2350         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidCertificate
, NULL
); 
2355 CFAbsoluteTime 
SecAbsoluteTimeFromDateContent(DERTag tag
, const uint8_t *bytes
, 
2357     return SecAbsoluteTimeFromDateContentWithError(tag
, bytes
, length
, NULL
); 
2360 __attribute__((__nonnull__
)) static bool derDateContentGetAbsoluteTime(DERTag tag
, const DERItem 
*date
, 
2361     CFAbsoluteTime 
*pabsTime
)  { 
2362     CFErrorRef error 
= NULL
; 
2363     CFAbsoluteTime absTime 
= SecAbsoluteTimeFromDateContentWithError(tag
, date
->data
, 
2364         date
->length
, &error
); 
2366         secwarning("Invalid date specification in certificate (see RFC5280 4.1.2.5)"); 
2371     *pabsTime 
= absTime
; 
2375 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return 
2376    true if the date was valid and properly decoded, also return the result in 
2377    absTime.  Return false otherwise. */ 
2378 __attribute__((__nonnull__
)) static bool derDateGetAbsoluteTime(const DERItem 
*dateChoice
, 
2379         CFAbsoluteTime 
*absTime
) { 
2380         if (dateChoice
->length 
== 0) return false; 
2382         DERDecodedInfo decoded
; 
2383         if (DERDecodeItem(dateChoice
, &decoded
)) 
2386     return derDateContentGetAbsoluteTime(decoded
.tag
, &decoded
.content
, 
2390 static void appendDataProperty(CFMutableArrayRef properties
, 
2391     CFStringRef label
, CFStringRef localizedLabel
, const DERItem 
*der_data
, 
2393     CFDataRef data 
= CFDataCreate(CFGetAllocator(properties
), 
2394         der_data
->data
, der_data
->length
); 
2395     appendProperty(properties
, kSecPropertyTypeData
, label
, localizedLabel
, 
2400 static void appendRelabeledProperty(CFMutableArrayRef properties
, 
2402                                     CFStringRef localizedLabel
, 
2403                                     const DERItem 
*der_data
, 
2404                                     CFStringRef labelFormat
, 
2406     CFStringRef newLabel 
= 
2407         CFStringCreateWithFormat(CFGetAllocator(properties
), NULL
, 
2408                                  labelFormat
, label
); 
2409     CFStringRef ll 
= NULL
; 
2410     CFStringRef localizedLabelFormat 
= NULL
; 
2412         /* use provided label and format strings; do not localize */ 
2413         ll 
= localizedLabel 
= (CFStringRef
) CFRetainSafe(label
); 
2414         localizedLabelFormat 
= (CFStringRef
) CFRetainSafe(labelFormat
); 
2416         if (!localizedLabel
) { 
2417             /* copy localized label for provided label */ 
2418             ll 
= localizedLabel 
= SecCopyCertString(label
); 
2420         /* copy localized format for provided format */ 
2421         localizedLabelFormat 
= SecCopyCertString(labelFormat
); 
2424     CFStringRef newLocalizedLabel 
= 
2425         CFStringCreateWithFormat(CFGetAllocator(properties
), NULL
, 
2426                                  localizedLabelFormat
, localizedLabel
); 
2428     CFReleaseSafe(localizedLabelFormat
); 
2429     appendDataProperty(properties
, newLabel
, newLocalizedLabel
, der_data
, localized
); 
2430     CFReleaseSafe(newLabel
); 
2431     CFReleaseSafe(newLocalizedLabel
); 
2435 static void appendUnparsedProperty(CFMutableArrayRef properties
, 
2436     CFStringRef label
, CFStringRef localizedLabel
, 
2437     const DERItem 
*der_data
, bool localized
) { 
2438     appendRelabeledProperty(properties
, label
, localizedLabel
, der_data
, 
2439                             SEC_UNPARSED_KEY
, localized
); 
2442 static void appendInvalidProperty(CFMutableArrayRef properties
, 
2443     CFStringRef label
, const DERItem 
*der_data
, bool localized
) { 
2444     appendRelabeledProperty(properties
, label
, NULL
, der_data
, 
2445                             SEC_INVALID_KEY
, localized
); 
2448 static void appendDateContentProperty(CFMutableArrayRef properties
, 
2449     CFStringRef label
, DERTag tag
, 
2450     const DERItem 
*dateContent
, bool localized
) { 
2451         CFAbsoluteTime absTime
; 
2452         if (!derDateContentGetAbsoluteTime(tag
, dateContent
, &absTime
)) { 
2453                 /* Date decode failure; insert hex bytes instead. */ 
2454                 return appendInvalidProperty(properties
, label
, dateContent
, localized
); 
2456     CFDateRef date 
= CFDateCreate(CFGetAllocator(properties
), absTime
); 
2457     appendProperty(properties
, kSecPropertyTypeDate
, label
, NULL
, date
, localized
); 
2461 static void appendDateProperty(CFMutableArrayRef properties
, 
2462     CFStringRef label
, CFAbsoluteTime absTime
, bool localized
) { 
2463     CFDateRef date 
= CFDateCreate(CFGetAllocator(properties
), absTime
); 
2464     appendProperty(properties
, kSecPropertyTypeDate
, label
, NULL
, date
, localized
); 
2468 static void appendValidityPeriodProperty(CFMutableArrayRef parent
, CFStringRef label
, 
2469                                          SecCertificateRef certificate
, bool localized
) { 
2470     CFAllocatorRef allocator 
= CFGetAllocator(parent
); 
2471     CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
2473     appendDateProperty(properties
, SEC_NOT_VALID_BEFORE_KEY
, 
2474                        certificate
->_notBefore
, localized
); 
2475     appendDateProperty(properties
, SEC_NOT_VALID_AFTER_KEY
, 
2476                        certificate
->_notAfter
, localized
); 
2478     appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, properties
, localized
); 
2479     CFReleaseNull(properties
); 
2482 static void appendIPAddressContentProperty(CFMutableArrayRef properties
, 
2483     CFStringRef label
, const DERItem 
*ip
, bool localized
) { 
2485                 copyIPAddressContentDescription(CFGetAllocator(properties
), ip
); 
2487         appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, value
, localized
); 
2490                 appendUnparsedProperty(properties
, label
, NULL
, ip
, localized
); 
2494 static void appendURLContentProperty(CFMutableArrayRef properties
, 
2495     CFStringRef label
, const DERItem 
*urlContent
, bool localized
) { 
2496     CFURLRef url 
= CFURLCreateWithBytes(CFGetAllocator(properties
), 
2497         urlContent
->data
, urlContent
->length
, kCFStringEncodingASCII
, NULL
); 
2499         appendProperty(properties
, kSecPropertyTypeURL
, label
, NULL
, url
, localized
); 
2502                 appendInvalidProperty(properties
, label
, urlContent
, localized
); 
2506 static void appendURLProperty(CFMutableArrayRef properties
, 
2507     CFStringRef label
, const DERItem 
*url
, bool localized
) { 
2508         DERDecodedInfo decoded
; 
2511         drtn 
= DERDecodeItem(url
, &decoded
); 
2512     if (drtn 
|| decoded
.tag 
!= ASN1_IA5_STRING
) { 
2513                 appendInvalidProperty(properties
, label
, url
, localized
); 
2515         appendURLContentProperty(properties
, label
, &decoded
.content
, localized
); 
2519 static void appendOIDProperty(CFMutableArrayRef properties
, 
2520     CFStringRef label
, CFStringRef llabel
, const DERItem 
*oid
, bool localized
) { 
2521     CFStringRef oid_string 
= 
2522         copyOidDescription(CFGetAllocator(properties
), oid
, localized
); 
2523     appendProperty(properties
, kSecPropertyTypeString
, label
, llabel
, 
2524                    oid_string
, localized
); 
2525     CFRelease(oid_string
); 
2528 static void appendAlgorithmProperty(CFMutableArrayRef properties
, 
2529     CFStringRef label
, const DERAlgorithmId 
*algorithm
, bool localized
) { 
2530     CFMutableArrayRef alg_props 
= 
2531         CFArrayCreateMutable(CFGetAllocator(properties
), 0, 
2532             &kCFTypeArrayCallBacks
); 
2533     appendOIDProperty(alg_props
, SEC_ALGORITHM_KEY
, NULL
, 
2534                       &algorithm
->oid
, localized
); 
2535     if (algorithm
->params
.length
) { 
2536         if (algorithm
->params
.length 
== 2 && 
2537             algorithm
->params
.data
[0] == ASN1_NULL 
&& 
2538             algorithm
->params
.data
[1] == 0) { 
2539             CFStringRef value 
= SecCopyCertString(SEC_NONE_KEY
); 
2540             appendProperty(alg_props
, kSecPropertyTypeString
, 
2541                            SEC_PARAMETERS_KEY
, NULL
, value
, localized
); 
2544             appendUnparsedProperty(alg_props
, SEC_PARAMETERS_KEY
, NULL
, 
2545                                    &algorithm
->params
, localized
); 
2548     appendProperty(properties
, kSecPropertyTypeSection
, label
, NULL
, 
2549                    alg_props
, localized
); 
2550     CFRelease(alg_props
); 
2553 static void appendPublicKeyProperty(CFMutableArrayRef parent
, CFStringRef label
, 
2554                                     SecCertificateRef certificate
, bool localized
) { 
2555     CFAllocatorRef allocator 
= CFGetAllocator(parent
); 
2556     CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
2558     /* Public key algorithm. */ 
2559     appendAlgorithmProperty(properties
, SEC_PUBLIC_KEY_ALG_KEY
, 
2560                             &certificate
->_algId
, localized
); 
2562     /* Public Key Size */ 
2563     SecKeyRef publicKey 
= SecCertificateCopyKey(certificate
); 
2565         size_t sizeInBytes 
= SecKeyGetBlockSize(publicKey
); 
2566         CFStringRef sizeInBitsString 
= CFStringCreateWithFormat(allocator
, NULL
, 
2567                                                                 CFSTR("%ld"), (sizeInBytes
*8)); 
2568         if (sizeInBitsString
) { 
2569             appendProperty(properties
, kSecPropertyTypeString
, SEC_PUBLIC_KEY_SIZE_KEY
, 
2570                            NULL
, sizeInBitsString
, localized
); 
2572         CFReleaseNull(sizeInBitsString
); 
2574     CFReleaseNull(publicKey
); 
2576     /* Consider breaking down an RSA public key into modulus and 
2578     appendDataProperty(properties
, SEC_PUBLIC_KEY_DATA_KEY
, NULL
, 
2579                        &certificate
->_pubKeyDER
, localized
); 
2581     appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, 
2582                    properties
, localized
); 
2583     CFReleaseNull(properties
); 
2586 static void appendSignatureProperty(CFMutableArrayRef parent
, CFStringRef label
, 
2587                                     SecCertificateRef certificate
, bool localized
) { 
2588     CFAllocatorRef allocator 
= CFGetAllocator(parent
); 
2589     CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
2591     appendAlgorithmProperty(properties
, SEC_SIGNATURE_ALGORITHM_KEY
, 
2592                             &certificate
->_tbsSigAlg
, localized
); 
2594     appendDataProperty(properties
, SEC_SIGNATURE_DATA_KEY
, NULL
, 
2595                        &certificate
->_signature
, localized
); 
2597     appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, 
2598                    properties
, localized
); 
2599     CFReleaseNull(properties
); 
2602 static void appendFingerprintsProperty(CFMutableArrayRef parent
, CFStringRef label
, 
2603                                        SecCertificateRef certificate
, bool localized
) { 
2604     CFAllocatorRef allocator 
= CFGetAllocator(parent
); 
2605     CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
2607     CFDataRef sha256Fingerprint 
= SecCertificateCopySHA256Digest(certificate
); 
2608     if (sha256Fingerprint
) { 
2609         appendProperty(properties
, kSecPropertyTypeData
, SEC_SHA2_FINGERPRINT_KEY
, 
2610                        NULL
, sha256Fingerprint
, localized
); 
2612     CFReleaseNull(sha256Fingerprint
); 
2614     appendProperty(properties
, kSecPropertyTypeData
, SEC_SHA1_FINGERPRINT_KEY
, 
2615                    NULL
, SecCertificateGetSHA1Digest(certificate
), localized
); 
2617     appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, 
2618                    properties
, localized
); 
2619     CFReleaseNull(properties
); 
2622 static CFStringRef 
copyHexDescription(CFAllocatorRef allocator
, 
2623     const DERItem 
*blob
) { 
2624     CFIndex ix
, length 
= blob
->length 
/* < 24 ? blob->length : 24 */; 
2625     CFMutableStringRef string 
= CFStringCreateMutable(allocator
, 
2626         blob
->length 
* 3 - 1); 
2627     for (ix 
= 0; ix 
< length
; ++ix
) 
2629             CFStringAppendFormat(string
, NULL
, CFSTR("%02X"), blob
->data
[ix
]); 
2631             CFStringAppendFormat(string
, NULL
, CFSTR(" %02X"), blob
->data
[ix
]); 
2636 static CFStringRef 
copyBlobString(CFAllocatorRef allocator
, 
2637     CFStringRef blobType
, CFStringRef quanta
, 
2638     const DERItem 
*blob
, bool localized
) { 
2639     CFStringRef localizedBlobType 
= (localized
) ? 
2640         SecCopyCertString(blobType
) : (CFStringRef
) CFRetainSafe(blobType
); 
2641     CFStringRef localizedQuanta 
= (localized
) ? 
2642         SecCopyCertString(quanta
) : (CFStringRef
) CFRetainSafe(quanta
); 
2643     /*  "format string for encoded field data (e.g. Sequence; 128 bytes; " 
2644         "data = 00 00 ...)" */ 
2645     CFStringRef blobFormat 
= (localized
) ? 
2646         SecCopyCertString(SEC_BLOB_KEY
) : SEC_BLOB_KEY
; 
2647     CFStringRef hex 
= copyHexDescription(allocator
, blob
); 
2648     CFStringRef result 
= CFStringCreateWithFormat(allocator
, NULL
, 
2649         blobFormat
, localizedBlobType
, blob
->length
, localizedQuanta
, hex
); 
2651     CFRelease(blobFormat
); 
2652     CFReleaseSafe(localizedQuanta
); 
2653     CFReleaseSafe(localizedBlobType
); 
2658 /* Return a string verbatim (unlocalized) from a DER field. */ 
2659 static CFStringRef 
copyContentString(CFAllocatorRef allocator
, 
2660         const DERItem 
*string
, CFStringEncoding encoding
, 
2661     bool printableOnly
) { 
2662     /* Strip potential bogus trailing zero from printable strings. */ 
2663     DERSize length 
= string
->length
; 
2664     if (length 
&& string
->data
[length 
- 1] == 0) { 
2665         /* Don't mess with the length of UTF16 strings though. */ 
2666         if (encoding 
!= kCFStringEncodingUTF16
) 
2669     /* A zero length string isn't considered printable. */ 
2670     if (!length 
&& printableOnly
) 
2673     /* Passing true for the 5th paramater to CFStringCreateWithBytes() makes 
2674        it treat kCFStringEncodingUTF16 as big endian by default, whereas 
2675        passing false makes it treat it as native endian by default.  */ 
2676     CFStringRef result 
= CFStringCreateWithBytes(allocator
, string
->data
, 
2677         length
, encoding
, encoding 
== kCFStringEncodingUTF16
); 
2681     return printableOnly 
? NULL 
: copyHexDescription(allocator
, string
); 
2684 /* From rfc3280 - Appendix B.  ASN.1 Notes 
2686    CAs MUST force the serialNumber to be a non-negative integer, that 
2687    is, the sign bit in the DER encoding of the INTEGER value MUST be 
2688    zero - this can be done by adding a leading (leftmost) `00'H octet if 
2689    necessary.  This removes a potential ambiguity in mapping between a 
2690    string of octets and an integer value. 
2692    As noted in section 4.1.2.2, serial numbers can be expected to 
2693    contain long integers.  Certificate users MUST be able to handle 
2694    serialNumber values up to 20 octets in length.  Conformant CAs MUST 
2695    NOT use serialNumber values longer than 20 octets. 
2698 /* Return the given numeric data as a string: decimal up to 64 bits, 
2701 static CFStringRef 
copyIntegerContentDescription(CFAllocatorRef allocator
, 
2702         const DERItem 
*integer
) { 
2704         CFIndex ix
, length 
= integer
->length
; 
2706         if (length 
== 0 || length 
> 8) 
2707                 return copyHexDescription(allocator
, integer
); 
2709         for(ix 
= 0; ix 
< length
; ++ix
) { 
2711                 value 
+= integer
->data
[ix
]; 
2714     return CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%llu"), value
); 
2717 static CFStringRef 
copyDERThingContentDescription(CFAllocatorRef allocator
, 
2718         DERTag tag
, const DERItem 
*derThing
, bool printableOnly
, bool localized
) { 
2719     if (!derThing
) { return NULL
; } 
2723         return printableOnly 
? NULL 
: copyIntegerContentDescription(allocator
, derThing
); 
2724     case ASN1_PRINTABLE_STRING
: 
2725     case ASN1_IA5_STRING
: 
2726         return copyContentString(allocator
, derThing
, kCFStringEncodingASCII
, printableOnly
); 
2727     case ASN1_UTF8_STRING
: 
2728     case ASN1_GENERAL_STRING
: 
2729     case ASN1_UNIVERSAL_STRING
: 
2730         return copyContentString(allocator
, derThing
, kCFStringEncodingUTF8
, printableOnly
); 
2731     case ASN1_T61_STRING
:               // 20, also BER_TAG_TELETEX_STRING 
2732     case ASN1_VIDEOTEX_STRING
:   // 21 
2733     case ASN1_VISIBLE_STRING
:           // 26 
2734         return copyContentString(allocator
, derThing
, kCFStringEncodingISOLatin1
, printableOnly
); 
2735     case ASN1_BMP_STRING
:   // 30 
2736         return copyContentString(allocator
, derThing
, kCFStringEncodingUTF16
, printableOnly
); 
2737     case ASN1_OCTET_STRING
: 
2738         return printableOnly 
? NULL 
: 
2739             copyBlobString(allocator
, SEC_BYTE_STRING_KEY
, SEC_BYTES_KEY
, 
2740                            derThing
, localized
); 
2741     case ASN1_BIT_STRING
: 
2742         return printableOnly 
? NULL 
: 
2743             copyBlobString(allocator
, SEC_BIT_STRING_KEY
, SEC_BITS_KEY
, 
2744                            derThing
, localized
); 
2745     case ASN1_CONSTR_SEQUENCE
: 
2746         return printableOnly 
? NULL 
: 
2747             copyBlobString(allocator
, SEC_SEQUENCE_KEY
, SEC_BYTES_KEY
, 
2748                            derThing
, localized
); 
2749     case ASN1_CONSTR_SET
: 
2750         return printableOnly 
? NULL 
: 
2751             copyBlobString(allocator
, SEC_SET_KEY
, SEC_BYTES_KEY
, 
2752                            derThing
, localized
); 
2753     case ASN1_OBJECT_ID
: 
2754         return printableOnly 
? NULL 
: copyOidDescription(allocator
, derThing
, localized
); 
2756         if (printableOnly
) { 
2759             CFStringRef fmt 
= (localized
) ? 
2760                 SecCopyCertString(SEC_NOT_DISPLAYED_KEY
) : SEC_NOT_DISPLAYED_KEY
; 
2761             if (!fmt
) { return NULL
; } 
2762             CFStringRef result 
= CFStringCreateWithFormat(allocator
, NULL
, fmt
, 
2763                 (unsigned long)tag
, (unsigned long)derThing
->length
); 
2770 static CFStringRef 
copyDERThingDescription(CFAllocatorRef allocator
, 
2771         const DERItem 
*derThing
, bool printableOnly
, bool localized
) { 
2772         DERDecodedInfo decoded
; 
2775         drtn 
= DERDecodeItem(derThing
, &decoded
); 
2777         /* TODO: Perhaps put something in the label saying we couldn't parse 
2779         return printableOnly 
? NULL 
: copyHexDescription(allocator
, derThing
); 
2781         return copyDERThingContentDescription(allocator
, decoded
.tag
, 
2782             &decoded
.content
, false, localized
); 
2786 static void appendDERThingProperty(CFMutableArrayRef properties
, 
2787     CFStringRef label
, CFStringRef localizedLabel
, 
2788     const DERItem 
*derThing
, bool localized
) { 
2789     CFStringRef value 
= copyDERThingDescription(CFGetAllocator(properties
), 
2790         derThing
, false, localized
); 
2792         appendProperty(properties
, kSecPropertyTypeString
, label
, localizedLabel
, 
2795     CFReleaseSafe(value
); 
2798 static OSStatus 
appendRDNProperty(void *context
, const DERItem 
*rdnType
, 
2799                                   const DERItem 
*rdnValue
, CFIndex rdnIX
, 
2801     CFMutableArrayRef properties 
= (CFMutableArrayRef
)context
; 
2803         /* If there is more than one value pair we create a subsection for the 
2804          second pair, and append things to the subsection for subsequent 
2806         CFIndex lastIX 
= CFArrayGetCount(properties
) - 1; 
2807         CFTypeRef lastValue 
= CFArrayGetValueAtIndex(properties
, lastIX
); 
2809             /* Since this is the second rdn pair for a given rdn, we setup a 
2810              new subsection for this rdn.  We remove the first property 
2811              from the properties array and make it the first element in the 
2812              subsection instead. */ 
2813             CFMutableArrayRef rdn_props 
= CFArrayCreateMutable( 
2814                 CFGetAllocator(properties
), 0, &kCFTypeArrayCallBacks
); 
2815             CFArrayAppendValue(rdn_props
, lastValue
); 
2816             CFArrayRemoveValueAtIndex(properties
, lastIX
); 
2817             appendProperty(properties
, kSecPropertyTypeSection
, NULL
, NULL
, 
2818                            rdn_props
, localized
); 
2819             properties 
= rdn_props
; 
2820             // rdn_props is now retained by the original properties array 
2821             CFReleaseSafe(rdn_props
); 
2823             /* Since this is the third or later rdn pair we have already 
2824              created a subsection in the top level properties array.  Instead 
2825              of appending to that directly we append to the array inside the 
2827             properties 
= (CFMutableArrayRef
)CFDictionaryGetValue( 
2828                 (CFDictionaryRef
)lastValue
, kSecPropertyKeyValue
); 
2832     /* Finally we append the new rdn value to the property array. */ 
2834         SecDERItemCopyOIDDecimalRepresentation(CFGetAllocator(properties
), 
2836     CFStringRef localizedLabel 
= copyOidDescription(CFGetAllocator(properties
), 
2837                                                     rdnType
, localized
); 
2838     appendDERThingProperty(properties
, label
, localizedLabel
, 
2839                            rdnValue
, localized
); 
2840     CFReleaseSafe(label
); 
2841     CFReleaseSafe(localizedLabel
); 
2842     return errSecSuccess
; 
2845 static CFArrayRef 
createPropertiesForRDNContent(CFAllocatorRef allocator
, 
2846         const DERItem 
*rdnSetContent
, bool localized
) { 
2847         CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 0, 
2848                 &kCFTypeArrayCallBacks
); 
2849         OSStatus status 
= parseRDNContent(rdnSetContent
, properties
, 
2850                 appendRDNProperty
, localized
); 
2852         CFArrayRemoveAllValues(properties
); 
2853                 appendInvalidProperty(properties
, SEC_RDN_KEY
, rdnSetContent
, 
2861     From rfc3739 - 3.1.2.  Subject 
2863     When parsing the subject here are some tips for a short name of the cert. 
2864       Choice   I:  commonName 
2865       Choice  II:  givenName 
2866       Choice III:  pseudonym 
2868       The commonName attribute value SHALL, when present, contain a name 
2869       of the subject.  This MAY be in the subject's preferred 
2870       presentation format, or a format preferred by the CA, or some 
2871       other format.  Pseudonyms, nicknames, and names with spelling 
2872       other than defined by the registered name MAY be used.  To 
2873       understand the nature of the name presented in commonName, 
2874       complying applications MAY have to examine present values of the 
2875       givenName and surname attributes, or the pseudonym attribute. 
2878 static CFArrayRef 
createPropertiesForX501NameContent(CFAllocatorRef allocator
, 
2879         const DERItem 
*x501NameContent
, bool localized
) { 
2880         CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 0, 
2881                 &kCFTypeArrayCallBacks
); 
2882         OSStatus status 
= parseX501NameContent(x501NameContent
, properties
, 
2883                 appendRDNProperty
, localized
); 
2885         CFArrayRemoveAllValues(properties
); 
2886         appendInvalidProperty(properties
, SEC_X501_NAME_KEY
, 
2887                               x501NameContent
, localized
); 
2893 static CFArrayRef 
createPropertiesForX501Name(CFAllocatorRef allocator
, 
2894         const DERItem 
*x501Name
, bool localized
) { 
2895         CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 0, 
2896                 &kCFTypeArrayCallBacks
); 
2897         OSStatus status 
= parseX501Name(x501Name
, properties
, appendRDNProperty
, localized
); 
2899         CFArrayRemoveAllValues(properties
); 
2900         appendInvalidProperty(properties
, SEC_X501_NAME_KEY
, 
2901                               x501Name
, localized
); 
2907 static void appendIntegerProperty(CFMutableArrayRef properties
, 
2908     CFStringRef label
, const DERItem 
*integer
, bool localized
) { 
2909     CFStringRef string 
= copyIntegerContentDescription( 
2910         CFGetAllocator(properties
), integer
); 
2911     appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, 
2916 static void appendBoolProperty(CFMutableArrayRef properties
, 
2917     CFStringRef label
, bool boolean
, bool localized
) { 
2918     CFStringRef key 
= (boolean
) ? SEC_YES_KEY 
: SEC_NO_KEY
; 
2919     CFStringRef value 
= (localized
) ? SecCopyCertString(key
) : key
; 
2920     appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, 
2925 static void appendBooleanProperty(CFMutableArrayRef properties
, 
2926     CFStringRef label
, const DERItem 
*boolean
, 
2927     bool defaultValue
, bool localized
) { 
2929     DERReturn drtn 
= DERParseBooleanWithDefault(boolean
, defaultValue
, &result
); 
2931         /* Couldn't parse boolean; dump the raw unparsed data as hex. */ 
2932         appendInvalidProperty(properties
, label
, boolean
, localized
); 
2934         appendBoolProperty(properties
, label
, result
, localized
); 
2938 static void appendSerialNumberProperty(CFMutableArrayRef parent
, CFStringRef label
, 
2939                                        DERItem 
*serialNum
, bool localized
) { 
2940     CFAllocatorRef allocator 
= CFGetAllocator(parent
); 
2941     CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
2943     if (serialNum
->length
) { 
2944         appendIntegerProperty(properties
, SEC_SERIAL_NUMBER_KEY
, 
2945                               serialNum
, localized
); 
2946         appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, 
2947                        properties
, localized
); 
2950     CFReleaseNull(properties
); 
2953 static void appendBitStringContentNames(CFMutableArrayRef properties
, 
2954     CFStringRef label
, const DERItem 
*bitStringContent
, 
2955     const CFStringRef 
*names
, CFIndex namesCount
, 
2957     DERSize len 
= bitStringContent
->length 
- 1; 
2958     require_quiet(len 
== 1 || len 
== 2, badDER
); 
2959     DERByte numUnusedBits 
= bitStringContent
->data
[0]; 
2960     require_quiet(numUnusedBits 
< 8, badDER
); 
2961     uint_fast16_t bits 
= 8 * len 
- numUnusedBits
; 
2962     require_quiet(bits 
<= (uint_fast16_t)namesCount
, badDER
); 
2963     uint_fast16_t value 
= bitStringContent
->data
[1]; 
2966         value 
= (value 
<< 8) + bitStringContent
->data
[2]; 
2972     CFStringRef fmt 
= (localized
) ? 
2973         SecCopyCertString(SEC_STRING_LIST_KEY
) : SEC_STRING_LIST_KEY
; 
2974     CFStringRef string 
= NULL
; 
2975     for (ix 
= 0; ix 
< bits
; ++ix
) { 
2979                     CFStringCreateWithFormat(CFGetAllocator(properties
), 
2980                                              NULL
, fmt
, string
, names
[ix
]); 
2991     appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, 
2992                    string 
? string 
: CFSTR(""), localized
); 
2993     CFReleaseSafe(string
); 
2996     appendInvalidProperty(properties
, label
, bitStringContent
, localized
); 
2999 static void appendBitStringNames(CFMutableArrayRef properties
, 
3000     CFStringRef label
, const DERItem 
*bitString
, 
3001     const CFStringRef 
*names
, CFIndex namesCount
, 
3003     DERDecodedInfo bitStringContent
; 
3004     DERReturn drtn 
= DERDecodeItem(bitString
, &bitStringContent
); 
3005     require_noerr_quiet(drtn
, badDER
); 
3006     require_quiet(bitStringContent
.tag 
== ASN1_BIT_STRING
, badDER
); 
3007     appendBitStringContentNames(properties
, label
, &bitStringContent
.content
, 
3008         names
, namesCount
, localized
); 
3011     appendInvalidProperty(properties
, label
, bitString
, localized
); 
3014 static void appendKeyUsage(CFMutableArrayRef properties
, 
3015     const DERItem 
*extnValue
, bool localized
) { 
3016     static const CFStringRef usageNames
[] = { 
3017         SEC_DIGITAL_SIGNATURE_KEY
, 
3018         SEC_NON_REPUDIATION_KEY
, 
3019         SEC_KEY_ENCIPHERMENT_KEY
, 
3020         SEC_DATA_ENCIPHERMENT_KEY
, 
3021         SEC_KEY_AGREEMENT_KEY
, 
3024         SEC_ENCIPHER_ONLY_KEY
, 
3025         SEC_DECIPHER_ONLY_KEY
 
3027     appendBitStringNames(properties
, SEC_USAGE_KEY
, extnValue
, 
3028         usageNames
, array_size(usageNames
), localized
); 
3031 static void appendPrivateKeyUsagePeriod(CFMutableArrayRef properties
, 
3032     const DERItem 
*extnValue
, bool localized
) { 
3033     DERPrivateKeyUsagePeriod pkup
; 
3034     DERReturn drtn 
= DERParseSequence(extnValue
, 
3035         DERNumPrivateKeyUsagePeriodItemSpecs
, DERPrivateKeyUsagePeriodItemSpecs
, 
3036         &pkup
, sizeof(pkup
)); 
3037     require_noerr_quiet(drtn
, badDER
); 
3038     if (pkup
.notBefore
.length
) { 
3039         appendDateContentProperty(properties
, SEC_NOT_VALID_BEFORE_KEY
, 
3040             ASN1_GENERALIZED_TIME
, &pkup
.notBefore
, localized
); 
3042     if (pkup
.notAfter
.length
) { 
3043         appendDateContentProperty(properties
, SEC_NOT_VALID_AFTER_KEY
, 
3044             ASN1_GENERALIZED_TIME
, &pkup
.notAfter
, localized
); 
3048     appendInvalidProperty(properties
, SEC_PRIVATE_KU_PERIOD_KEY
, 
3049                           extnValue
, localized
); 
3052 static void appendStringContentProperty(CFMutableArrayRef properties
, 
3053     CFStringRef label
, const DERItem 
*stringContent
, 
3054     CFStringEncoding encoding
, bool localized
) { 
3055     CFStringRef string 
= CFStringCreateWithBytes(CFGetAllocator(properties
), 
3056             stringContent
->data
, stringContent
->length
, encoding
, FALSE
); 
3058         appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, 
3062         appendInvalidProperty(properties
, label
, stringContent
, localized
); 
3067       OtherName ::= SEQUENCE { 
3068            type-id    OBJECT IDENTIFIER, 
3069            value      [0] EXPLICIT ANY DEFINED BY type-id } 
3071 static void appendOtherNameContentProperty(CFMutableArrayRef properties
, 
3072         const DERItem 
*otherNameContent
, bool localized
) { 
3074         DERReturn drtn 
= DERParseSequenceContent(otherNameContent
, 
3075         DERNumOtherNameItemSpecs
, DEROtherNameItemSpecs
, 
3077         require_noerr_quiet(drtn
, badDER
); 
3078         CFAllocatorRef allocator 
= CFGetAllocator(properties
); 
3080         SecDERItemCopyOIDDecimalRepresentation(allocator
, &on
.typeIdentifier
); 
3081         CFStringRef localizedLabel 
= 
3082         copyOidDescription(allocator
, &on
.typeIdentifier
, localized
); 
3083         CFStringRef value_string 
= copyDERThingDescription(allocator
, &on
.value
, 
3086                 appendProperty(properties
, kSecPropertyTypeString
, label
, 
3087                        localizedLabel
, value_string
, localized
); 
3089         appendUnparsedProperty(properties
, label
, localizedLabel
, 
3090                                &on
.value
, localized
); 
3092     CFReleaseSafe(value_string
); 
3093     CFReleaseSafe(label
); 
3094     CFReleaseSafe(localizedLabel
); 
3097     appendInvalidProperty(properties
, SEC_OTHER_NAME_KEY
, 
3098                           otherNameContent
, localized
); 
3102       GeneralName ::= CHOICE { 
3103            otherName                       [0]     OtherName, 
3104            rfc822Name                      [1]     IA5String, 
3105            dNSName                         [2]     IA5String, 
3106            x400Address                     [3]     ORAddress, 
3107            directoryName                   [4]     Name, 
3108            ediPartyName                    [5]     EDIPartyName, 
3109            uniformResourceIdentifier       [6]     IA5String, 
3110            iPAddress                       [7]     OCTET STRING, 
3111            registeredID                    [8]     OBJECT IDENTIFIER} 
3113       EDIPartyName ::= SEQUENCE { 
3114            nameAssigner            [0]     DirectoryString OPTIONAL, 
3115            partyName               [1]     DirectoryString } 
3117 static bool appendGeneralNameContentProperty(CFMutableArrayRef properties
, 
3118     DERTag tag
, const DERItem 
*generalName
, bool localized
) { 
3120         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 0: 
3121                 appendOtherNameContentProperty(properties
, generalName
, localized
); 
3123         case ASN1_CONTEXT_SPECIFIC 
| 1: 
3125                 appendStringContentProperty(properties
, SEC_EMAIL_ADDRESS_KEY
, 
3126                         generalName
, kCFStringEncodingASCII
, localized
); 
3128         case ASN1_CONTEXT_SPECIFIC 
| 2: 
3130                 appendStringContentProperty(properties
, SEC_DNS_NAME_KEY
, generalName
, 
3131                         kCFStringEncodingASCII
, localized
); 
3133         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 3: 
3134                 appendUnparsedProperty(properties
, SEC_X400_ADDRESS_KEY
, NULL
, 
3135                         generalName
, localized
); 
3137         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 4: 
3139                 CFArrayRef directory_plist 
= 
3140                         createPropertiesForX501Name(CFGetAllocator(properties
), 
3141                                 generalName
, localized
); 
3142                 appendProperty(properties
, kSecPropertyTypeSection
, 
3143                         SEC_DIRECTORY_NAME_KEY
, NULL
, directory_plist
, localized
); 
3144                 CFRelease(directory_plist
); 
3147         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 5: 
3148                 appendUnparsedProperty(properties
, SEC_EDI_PARTY_NAME_KEY
, NULL
, 
3149                         generalName
, localized
); 
3151         case ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 6: 
3152                 /* Technically I don't think this is valid, but there are certs out 
3153                    in the wild that use a constructed IA5String.   In particular the 
3154                    VeriSign Time Stamping Authority CA.cer does this.  */ 
3155                 appendURLProperty(properties
, SEC_URI_KEY
, generalName
, localized
); 
3157         case ASN1_CONTEXT_SPECIFIC 
| 6: 
3158                 appendURLContentProperty(properties
, SEC_URI_KEY
, generalName
, localized
); 
3160         case ASN1_CONTEXT_SPECIFIC 
| 7: 
3161                 appendIPAddressContentProperty(properties
, SEC_IP_ADDRESS_KEY
, 
3162                         generalName
, localized
); 
3164         case ASN1_CONTEXT_SPECIFIC 
| 8: 
3165                 appendOIDProperty(properties
, SEC_REGISTERED_ID_KEY
, NULL
, 
3166                           generalName
, localized
); 
3177 static void appendGeneralNameProperty(CFMutableArrayRef properties
, 
3178     const DERItem 
*generalName
, bool localized
) { 
3179     DERDecodedInfo generalNameContent
; 
3180         DERReturn drtn 
= DERDecodeItem(generalName
, &generalNameContent
); 
3181         require_noerr_quiet(drtn
, badDER
); 
3182         if (appendGeneralNameContentProperty(properties
, generalNameContent
.tag
, 
3183                 &generalNameContent
.content
, localized
)) 
3186     appendInvalidProperty(properties
, SEC_GENERAL_NAME_KEY
, 
3187                           generalName
, localized
); 
3192       GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 
3194 static void appendGeneralNamesContent(CFMutableArrayRef properties
, 
3195     const DERItem 
*generalNamesContent
, bool localized
) { 
3197     DERReturn drtn 
= DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
); 
3198     require_noerr_quiet(drtn
, badDER
); 
3199     DERDecodedInfo generalNameContent
; 
3200     while ((drtn 
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) == 
3202                 if (!appendGeneralNameContentProperty(properties
, 
3203                         generalNameContent
.tag
, &generalNameContent
.content
, localized
)) { 
3207     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
3210     appendInvalidProperty(properties
, SEC_GENERAL_NAMES_KEY
, 
3211         generalNamesContent
, localized
); 
3214 static void appendGeneralNames(CFMutableArrayRef properties
, 
3215     const DERItem 
*generalNames
, bool localized
) { 
3216     DERDecodedInfo generalNamesContent
; 
3217     DERReturn drtn 
= DERDecodeItem(generalNames
, &generalNamesContent
); 
3218     require_noerr_quiet(drtn
, badDER
); 
3219     require_quiet(generalNamesContent
.tag 
== ASN1_CONSTR_SEQUENCE
, 
3221     appendGeneralNamesContent(properties
, &generalNamesContent
.content
, 
3225     appendInvalidProperty(properties
, SEC_GENERAL_NAMES_KEY
, 
3226                           generalNames
, localized
); 
3230     BasicConstraints ::= SEQUENCE { 
3231         cA                      BOOLEAN DEFAULT FALSE, 
3232         pathLenConstraint       INTEGER (0..MAX) OPTIONAL } 
3234 static void appendBasicConstraints(CFMutableArrayRef properties
, 
3235     const DERItem 
*extnValue
, bool localized
) { 
3236         DERBasicConstraints basicConstraints
; 
3237         DERReturn drtn 
= DERParseSequence(extnValue
, 
3238         DERNumBasicConstraintsItemSpecs
, DERBasicConstraintsItemSpecs
, 
3239         &basicConstraints
, sizeof(basicConstraints
)); 
3240         require_noerr_quiet(drtn
, badDER
); 
3242     appendBooleanProperty(properties
, SEC_CERT_AUTHORITY_KEY
, 
3243         &basicConstraints
.cA
, false, localized
); 
3245     if (basicConstraints
.pathLenConstraint
.length 
!= 0) { 
3246         appendIntegerProperty(properties
, SEC_PATH_LEN_CONSTRAINT_KEY
, 
3247             &basicConstraints
.pathLenConstraint
, localized
); 
3251     appendInvalidProperty(properties
, SEC_BASIC_CONSTRAINTS_KEY
, 
3252                           extnValue
, localized
); 
3256  * id-ce-nameConstraints OBJECT IDENTIFIER ::=  { id-ce 30 } 
3258  * NameConstraints ::= SEQUENCE { 
3259  * permittedSubtrees       [0]     GeneralSubtrees OPTIONAL, 
3260  * excludedSubtrees        [1]     GeneralSubtrees OPTIONAL } 
3262  * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree 
3264  * GeneralSubtree ::= SEQUENCE { 
3266  * minimum         [0]     BaseDistance DEFAULT 0, 
3267  * maximum         [1]     BaseDistance OPTIONAL } 
3269  * BaseDistance ::= INTEGER (0..MAX) 
3271 static void appendNameConstraints(CFMutableArrayRef properties
, 
3272     const DERItem 
*extnValue
, bool localized
) { 
3273     CFAllocatorRef allocator 
= CFGetAllocator(properties
); 
3274     DERNameConstraints nc
; 
3276     drtn 
= DERParseSequence(extnValue
, 
3277                             DERNumNameConstraintsItemSpecs
, 
3278                             DERNameConstraintsItemSpecs
, 
3280     require_noerr_quiet(drtn
, badDER
); 
3281     if (nc
.permittedSubtrees
.length
) { 
3283         require_noerr_quiet(DERDecodeSeqContentInit(&nc
.permittedSubtrees
, &gsSeq
), badDER
); 
3284         DERDecodedInfo gsContent
; 
3285         while ((drtn 
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) { 
3286             DERGeneralSubtree derGS
; 
3287             require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
); 
3288             drtn 
= DERParseSequenceContent(&gsContent
.content
, 
3289                                            DERNumGeneralSubtreeItemSpecs
, 
3290                                            DERGeneralSubtreeItemSpecs
, 
3291                                            &derGS
, sizeof(derGS
)); 
3292             require_noerr_quiet(drtn
, badDER
); 
3293             if (derGS
.minimum
.length
) { 
3294                 appendIntegerProperty(properties
, SEC_PERMITTED_MINIMUM_KEY
, 
3295                                       &derGS
.minimum
, localized
); 
3297             if (derGS
.maximum
.length
) { 
3298                 appendIntegerProperty(properties
, SEC_PERMITTED_MAXIMUM_KEY
, 
3299                                       &derGS
.maximum
, localized
); 
3301             if (derGS
.generalName
.length
) { 
3302                 CFMutableArrayRef base 
= CFArrayCreateMutable(allocator
, 0, 
3303                                                                    &kCFTypeArrayCallBacks
); 
3304                 appendProperty(properties
, kSecPropertyTypeSection
, 
3305                                SEC_PERMITTED_NAME_KEY
, NULL
, base
, localized
); 
3306                 appendGeneralNameProperty(base
, &derGS
.generalName
, localized
); 
3310         require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
3312     if (nc
.excludedSubtrees
.length
) { 
3314         require_noerr_quiet(DERDecodeSeqContentInit(&nc
.excludedSubtrees
, &gsSeq
), badDER
); 
3315         DERDecodedInfo gsContent
; 
3316         while ((drtn 
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) { 
3317             DERGeneralSubtree derGS
; 
3318             require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
); 
3319             drtn 
= DERParseSequenceContent(&gsContent
.content
, 
3320                                            DERNumGeneralSubtreeItemSpecs
, 
3321                                            DERGeneralSubtreeItemSpecs
, 
3322                                            &derGS
, sizeof(derGS
)); 
3323             require_noerr_quiet(drtn
, badDER
); 
3324             if (derGS
.minimum
.length
) { 
3325                 appendIntegerProperty(properties
, SEC_EXCLUDED_MINIMUM_KEY
, 
3326                                       &derGS
.minimum
, localized
); 
3328             if (derGS
.maximum
.length
) { 
3329                 appendIntegerProperty(properties
, SEC_EXCLUDED_MAXIMUM_KEY
, 
3330                                       &derGS
.maximum
, localized
); 
3332             if (derGS
.generalName
.length
) { 
3333                 CFMutableArrayRef base 
= CFArrayCreateMutable(allocator
, 0, 
3334                                                               &kCFTypeArrayCallBacks
); 
3335                 appendProperty(properties
, kSecPropertyTypeSection
, 
3336                                SEC_EXCLUDED_NAME_KEY
, NULL
, base
, localized
); 
3337                 appendGeneralNameProperty(base
, &derGS
.generalName
, localized
); 
3341         require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
3346     appendInvalidProperty(properties
, SEC_NAME_CONSTRAINTS_KEY
, 
3347                           extnValue
, localized
); 
3351    CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint 
3353    DistributionPoint ::= SEQUENCE { 
3354         distributionPoint       [0]     DistributionPointName OPTIONAL, 
3355         reasons                 [1]     ReasonFlags OPTIONAL, 
3356         cRLIssuer               [2]     GeneralNames OPTIONAL } 
3358    DistributionPointName ::= CHOICE { 
3359         fullName                [0]     GeneralNames, 
3360         nameRelativeToCRLIssuer [1]     RelativeDistinguishedName } 
3362    ReasonFlags ::= BIT STRING { 
3366         affiliationChanged      (3), 
3368         cessationOfOperation    (5), 
3369         certificateHold         (6), 
3370         privilegeWithdrawn      (7), 
3373 static void appendCrlDistributionPoints(CFMutableArrayRef properties
, 
3374     const DERItem 
*extnValue
, bool localized
) { 
3375     CFAllocatorRef allocator 
= CFGetAllocator(properties
); 
3378     DERReturn drtn 
= DERDecodeSeqInit(extnValue
, &tag
, &dpSeq
); 
3379     require_noerr_quiet(drtn
, badDER
); 
3380     require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
3381     DERDecodedInfo dpSeqContent
; 
3382     while ((drtn 
= DERDecodeSeqNext(&dpSeq
, &dpSeqContent
)) == DR_Success
) { 
3383         require_quiet(dpSeqContent
.tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
3384         DERDistributionPoint dp
; 
3385         drtn 
= DERParseSequenceContent(&dpSeqContent
.content
, 
3386             DERNumDistributionPointItemSpecs
, 
3387             DERDistributionPointItemSpecs
, 
3389         require_noerr_quiet(drtn
, badDER
); 
3390         if (dp
.distributionPoint
.length
) { 
3391             DERDecodedInfo distributionPointName
; 
3392             drtn 
= DERDecodeItem(&dp
.distributionPoint
, &distributionPointName
); 
3393             require_noerr_quiet(drtn
, badDER
); 
3394             if (distributionPointName
.tag 
== 
3395                 (ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 0)) { 
3397                 appendGeneralNamesContent(properties
, 
3398                     &distributionPointName
.content
, localized
); 
3399             } else if (distributionPointName
.tag 
== 
3400                 (ASN1_CONTEXT_SPECIFIC 
| ASN1_CONSTRUCTED 
| 1)) { 
3401                                 CFArrayRef rdn_props 
= createPropertiesForRDNContent(allocator
, 
3402                                         &dp
.reasons
, localized
); 
3403                                 appendProperty(properties
, kSecPropertyTypeSection
, 
3404                                         SEC_NAME_REL_CRL_ISSUER_KEY
, NULL
, rdn_props
, localized
); 
3405                                 CFRelease(rdn_props
); 
3410         if (dp
.reasons
.length
) { 
3411             static const CFStringRef reasonNames
[] = { 
3413                 SEC_KEY_COMPROMISE_KEY
, 
3414                 SEC_CA_COMPROMISE_KEY
, 
3415                 SEC_AFFILIATION_CHANGED_KEY
, 
3417                 SEC_CESSATION_OF_OPER_KEY
, 
3418                 SEC_CERTIFICATE_HOLD_KEY
, 
3419                 SEC_PRIV_WITHDRAWN_KEY
, 
3420                 SEC_AA_COMPROMISE_KEY
 
3422             appendBitStringContentNames(properties
, SEC_REASONS_KEY
, 
3424                 reasonNames
, array_size(reasonNames
), localized
); 
3426         if (dp
.cRLIssuer
.length
) { 
3427             CFMutableArrayRef crlIssuer 
= CFArrayCreateMutable(allocator
, 0, 
3428                 &kCFTypeArrayCallBacks
); 
3429             appendProperty(properties
, kSecPropertyTypeSection
, 
3430                 SEC_CRL_ISSUER_KEY
, NULL
, crlIssuer
, localized
); 
3431             CFRelease(crlIssuer
); 
3432             appendGeneralNames(crlIssuer
, &dp
.cRLIssuer
, localized
); 
3435     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
3438     appendInvalidProperty(properties
, SEC_CRL_DISTR_POINTS_KEY
, 
3439                           extnValue
, localized
); 
3443     Decode a sequence of integers into a comma separated list of ints. 
3445 static void appendIntegerSequenceContent(CFMutableArrayRef properties
, 
3446     CFStringRef label
, const DERItem 
*intSequenceContent
, 
3448     CFAllocatorRef allocator 
= CFGetAllocator(properties
); 
3450     CFStringRef fmt 
= NULL
, value 
= NULL
, intDesc 
= NULL
, v 
= NULL
; 
3451         DERReturn drtn 
= DERDecodeSeqContentInit(intSequenceContent
, &intSeq
); 
3452         require_noerr_quiet(drtn
, badDER
); 
3453         DERDecodedInfo intContent
; 
3455         SecCopyCertString(SEC_STRING_LIST_KEY
) : SEC_STRING_LIST_KEY
; 
3456     require_quiet(fmt
, badDER
); 
3457         while ((drtn 
= DERDecodeSeqNext(&intSeq
, &intContent
)) == DR_Success
) { 
3458                 require_quiet(intContent
.tag 
== ASN1_INTEGER
, badDER
); 
3459                 intDesc 
= copyIntegerContentDescription( 
3460                         allocator
, &intContent
.content
); 
3461         require_quiet(intDesc
, badDER
); 
3463             v 
= CFStringCreateWithFormat(allocator
, NULL
, fmt
, value
, intDesc
); 
3464             CFReleaseNull(value
); 
3465             require_quiet(v
, badDER
); 
3468                         value 
= CFStringCreateMutableCopy(allocator
, 0, intDesc
); 
3469             require_quiet(value
, badDER
); 
3471         CFReleaseNull(intDesc
); 
3474         require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
3476                 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, 
3481         /* DROPTHOUGH if !value. */ 
3484     CFReleaseNull(intDesc
); 
3485     CFReleaseNull(value
); 
3486         appendInvalidProperty(properties
, label
, intSequenceContent
, localized
); 
3489 static void appendCertificatePolicies(CFMutableArrayRef properties
, 
3490     const DERItem 
*extnValue
, bool localized
) { 
3491     CFAllocatorRef allocator 
= CFGetAllocator(properties
); 
3492     CFStringRef piLabel 
= NULL
, piFmt 
= NULL
, lpiLabel 
= NULL
; 
3493     CFStringRef pqLabel 
= NULL
, pqFmt 
= NULL
, lpqLabel 
= NULL
; 
3496     DERReturn drtn 
= DERDecodeSeqInit(extnValue
, &tag
, &piSeq
); 
3497     require_noerr_quiet(drtn
, badDER
); 
3498     require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
3499     DERDecodedInfo piContent
; 
3501     while ((drtn 
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) { 
3502         require_quiet(piContent
.tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
3503         DERPolicyInformation pi
; 
3504         drtn 
= DERParseSequenceContent(&piContent
.content
, 
3505             DERNumPolicyInformationItemSpecs
, 
3506             DERPolicyInformationItemSpecs
, 
3508         require_noerr_quiet(drtn
, badDER
); 
3509         piLabel 
= CFStringCreateWithFormat(allocator
, NULL
, 
3510             SEC_POLICY_IDENTIFIER_KEY
, pin
); 
3511         require_quiet(piLabel
, badDER
); 
3512         piFmt 
= (localized
) ? 
3513             SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY
) : SEC_POLICY_IDENTIFIER_KEY
; 
3514         require_quiet(piFmt
, badDER
); 
3515         lpiLabel 
= CFStringCreateWithFormat(allocator
, NULL
, piFmt
, pin
++); 
3516         require_quiet(lpiLabel
, badDER
); 
3517         CFReleaseNull(piFmt
); 
3518         appendOIDProperty(properties
, piLabel
, lpiLabel
, 
3519                           &pi
.policyIdentifier
, localized
); 
3520         CFReleaseNull(piLabel
); 
3521         CFReleaseNull(lpiLabel
); 
3522         if (pi
.policyQualifiers
.length 
== 0) 
3526         drtn 
= DERDecodeSeqContentInit(&pi
.policyQualifiers
, &pqSeq
); 
3527         require_noerr_quiet(drtn
, badDER
); 
3528         DERDecodedInfo pqContent
; 
3530         while ((drtn 
= DERDecodeSeqNext(&pqSeq
, &pqContent
)) == DR_Success
) { 
3531             DERPolicyQualifierInfo pqi
; 
3532             drtn 
= DERParseSequenceContent(&pqContent
.content
, 
3533                 DERNumPolicyQualifierInfoItemSpecs
, 
3534                 DERPolicyQualifierInfoItemSpecs
, 
3536             require_noerr_quiet(drtn
, badDER
); 
3537             DERDecodedInfo qualifierContent
; 
3538             drtn 
= DERDecodeItem(&pqi
.qualifier
, &qualifierContent
); 
3539             require_noerr_quiet(drtn
, badDER
); 
3540             pqLabel 
= CFStringCreateWithFormat(allocator
, NULL
, 
3541                 SEC_POLICY_QUALIFIER_KEY
, pqn
); 
3542             require_quiet(pqLabel
, badDER
); 
3543             pqFmt 
= (localized
) ? 
3544                 SecCopyCertString(SEC_POLICY_QUALIFIER_KEY
) : SEC_POLICY_QUALIFIER_KEY
; 
3545             require_quiet(pqFmt
, badDER
); 
3546             lpqLabel 
= CFStringCreateWithFormat(allocator
, NULL
, pqFmt
, pqn
++); 
3547             require_quiet(lpqLabel
, badDER
); 
3548             CFReleaseNull(pqFmt
); 
3549             appendOIDProperty(properties
, pqLabel
, lpqLabel
, 
3550                               &pqi
.policyQualifierID
, localized
); 
3551             CFReleaseNull(pqLabel
); 
3552             CFReleaseNull(lpqLabel
); 
3553             if (DEROidCompare(&oidQtCps
, &pqi
.policyQualifierID
)) { 
3554                 require_quiet(qualifierContent
.tag 
== ASN1_IA5_STRING
, badDER
); 
3555                 appendURLContentProperty(properties
, SEC_CPS_URI_KEY
, 
3556                                          &qualifierContent
.content
, localized
); 
3557             } else if (DEROidCompare(&oidQtUNotice
, &pqi
.policyQualifierID
)) { 
3558                 require_quiet(qualifierContent
.tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
3560                 drtn 
= DERParseSequenceContent(&qualifierContent
.content
, 
3561                     DERNumUserNoticeItemSpecs
, 
3562                     DERUserNoticeItemSpecs
, 
3564                 require_noerr_quiet(drtn
, badDER
); 
3565                 if (un
.noticeRef
.length
) { 
3566                     DERNoticeReference nr
; 
3567                     drtn 
= DERParseSequenceContent(&un
.noticeRef
, 
3568                         DERNumNoticeReferenceItemSpecs
, 
3569                         DERNoticeReferenceItemSpecs
, 
3571                     require_noerr_quiet(drtn
, badDER
); 
3572                     appendDERThingProperty(properties
, 
3573                         SEC_ORGANIZATION_KEY
, NULL
, 
3574                         &nr
.organization
, localized
); 
3575                                         appendIntegerSequenceContent(properties
, 
3576                                                 SEC_NOTICE_NUMBERS_KEY
, &nr
.noticeNumbers
, localized
); 
3578                 if (un
.explicitText
.length
) { 
3579                     appendDERThingProperty(properties
, SEC_EXPLICIT_TEXT_KEY
, 
3580                         NULL
, &un
.explicitText
, localized
); 
3583                 appendUnparsedProperty(properties
, SEC_QUALIFIER_KEY
, NULL
, 
3584                     &pqi
.qualifier
, localized
); 
3587         require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
3589     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
3592     CFReleaseNull(piFmt
); 
3593     CFReleaseNull(piLabel
); 
3594     CFReleaseNull(lpiLabel
); 
3595     CFReleaseNull(pqFmt
); 
3596     CFReleaseNull(pqLabel
); 
3597     CFReleaseNull(lpqLabel
); 
3598     appendInvalidProperty(properties
, SEC_CERT_POLICIES_KEY
, 
3599                           extnValue
, localized
); 
3602 static void appendSubjectKeyIdentifier(CFMutableArrayRef properties
, 
3603     const DERItem 
*extnValue
, bool localized
) { 
3605     DERDecodedInfo keyIdentifier
; 
3606         drtn 
= DERDecodeItem(extnValue
, &keyIdentifier
); 
3607         require_noerr_quiet(drtn
, badDER
); 
3608         require_quiet(keyIdentifier
.tag 
== ASN1_OCTET_STRING
, badDER
); 
3609         appendDataProperty(properties
, SEC_KEY_IDENTIFIER_KEY
, NULL
, 
3610                 &keyIdentifier
.content
, localized
); 
3614     appendInvalidProperty(properties
, SEC_SUBJ_KEY_ID_KEY
, 
3615         extnValue
, localized
); 
3619 AuthorityKeyIdentifier ::= SEQUENCE { 
3620     keyIdentifier             [0] KeyIdentifier            OPTIONAL, 
3621     authorityCertIssuer       [1] GeneralNames             OPTIONAL, 
3622     authorityCertSerialNumber [2] CertificateSerialNumber  OPTIONAL } 
3623     -- authorityCertIssuer and authorityCertSerialNumber MUST both 
3624     -- be present or both be absent 
3626 KeyIdentifier ::= OCTET STRING 
3628 static void appendAuthorityKeyIdentifier(CFMutableArrayRef properties
, 
3629     const DERItem 
*extnValue
, bool localized
) { 
3630         DERAuthorityKeyIdentifier akid
; 
3632         drtn 
= DERParseSequence(extnValue
, 
3633                 DERNumAuthorityKeyIdentifierItemSpecs
, 
3634                 DERAuthorityKeyIdentifierItemSpecs
, 
3635                 &akid
, sizeof(akid
)); 
3636         require_noerr_quiet(drtn
, badDER
); 
3637         if (akid
.keyIdentifier
.length
) { 
3638                 appendDataProperty(properties
, SEC_KEY_IDENTIFIER_KEY
, NULL
, 
3639                         &akid
.keyIdentifier
, localized
); 
3641         if (akid
.authorityCertIssuer
.length 
|| 
3642                 akid
.authorityCertSerialNumber
.length
) { 
3643                 require_quiet(akid
.authorityCertIssuer
.length 
&& 
3644                         akid
.authorityCertSerialNumber
.length
, badDER
); 
3645                 /* Perhaps put in a subsection called Authority Certificate Issuer. */ 
3646                 appendGeneralNamesContent(properties
, 
3647                         &akid
.authorityCertIssuer
, localized
); 
3648                 appendIntegerProperty(properties
, SEC_AUTH_CERT_SERIAL_KEY
, 
3649                         &akid
.authorityCertSerialNumber
, localized
); 
3654     appendInvalidProperty(properties
, SEC_AUTHORITY_KEY_ID_KEY
, 
3655                           extnValue
, localized
); 
3659    PolicyConstraints ::= SEQUENCE { 
3660         requireExplicitPolicy           [0] SkipCerts OPTIONAL, 
3661         inhibitPolicyMapping            [1] SkipCerts OPTIONAL } 
3663    SkipCerts ::= INTEGER (0..MAX) 
3665 static void appendPolicyConstraints(CFMutableArrayRef properties
, 
3666     const DERItem 
*extnValue
, bool localized
) { 
3667         DERPolicyConstraints pc
; 
3669         drtn 
= DERParseSequence(extnValue
, 
3670                 DERNumPolicyConstraintsItemSpecs
, 
3671                 DERPolicyConstraintsItemSpecs
, 
3673         require_noerr_quiet(drtn
, badDER
); 
3674         if (pc
.requireExplicitPolicy
.length
) { 
3675                 appendIntegerProperty(properties
, SEC_REQUIRE_EXPL_POLICY_KEY
, 
3676                               &pc
.requireExplicitPolicy
, localized
); 
3678         if (pc
.inhibitPolicyMapping
.length
) { 
3679                 appendIntegerProperty(properties
, SEC_INHIBIT_POLICY_MAP_KEY
, 
3680                               &pc
.inhibitPolicyMapping
, localized
); 
3686     appendInvalidProperty(properties
, SEC_POLICY_CONSTRAINTS_KEY
, 
3687                           extnValue
, localized
); 
3691 extendedKeyUsage EXTENSION ::= { 
3692         SYNTAX SEQUENCE SIZE (1..MAX) OF KeyPurposeId 
3693         IDENTIFIED BY id-ce-extKeyUsage } 
3695 KeyPurposeId ::= OBJECT IDENTIFIER 
3697 static void appendExtendedKeyUsage(CFMutableArrayRef properties
, 
3698     const DERItem 
*extnValue
, bool localized
) { 
3701     DERReturn drtn 
= DERDecodeSeqInit(extnValue
, &tag
, &derSeq
); 
3702     require_noerr_quiet(drtn
, badDER
); 
3703     require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
3704     DERDecodedInfo currDecoded
; 
3705     while ((drtn 
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) { 
3706         require_quiet(currDecoded
.tag 
== ASN1_OBJECT_ID
, badDER
); 
3707         appendOIDProperty(properties
, SEC_PURPOSE_KEY
, NULL
, 
3708             &currDecoded
.content
, localized
); 
3710     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
3713     appendInvalidProperty(properties
, SEC_EXTENDED_KEY_USAGE_KEY
, 
3714                           extnValue
, localized
); 
3718    id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } 
3720    AuthorityInfoAccessSyntax  ::= 
3721            SEQUENCE SIZE (1..MAX) OF AccessDescription 
3723    AccessDescription  ::=  SEQUENCE { 
3724            accessMethod          OBJECT IDENTIFIER, 
3725            accessLocation        GeneralName  } 
3727    id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } 
3729    id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 } 
3731    id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } 
3733 static void appendInfoAccess(CFMutableArrayRef properties
, 
3734     const DERItem 
*extnValue
, bool localized
) { 
3737     DERReturn drtn 
= DERDecodeSeqInit(extnValue
, &tag
, &adSeq
); 
3738     require_noerr_quiet(drtn
, badDER
); 
3739     require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
3740     DERDecodedInfo adContent
; 
3741     while ((drtn 
= DERDecodeSeqNext(&adSeq
, &adContent
)) == DR_Success
) { 
3742         require_quiet(adContent
.tag 
== ASN1_CONSTR_SEQUENCE
, badDER
); 
3743                 DERAccessDescription ad
; 
3744                 drtn 
= DERParseSequenceContent(&adContent
.content
, 
3745                         DERNumAccessDescriptionItemSpecs
, 
3746                         DERAccessDescriptionItemSpecs
, 
3748                 require_noerr_quiet(drtn
, badDER
); 
3749         appendOIDProperty(properties
, SEC_ACCESS_METHOD_KEY
, NULL
, 
3750                           &ad
.accessMethod
, localized
); 
3751                 //TODO: Do something with SEC_ACCESS_LOCATION_KEY 
3752         appendGeneralNameProperty(properties
, &ad
.accessLocation
, localized
); 
3754     require_quiet(drtn 
== DR_EndOfSequence
, badDER
); 
3757     appendInvalidProperty(properties
, SEC_AUTH_INFO_ACCESS_KEY
, 
3758                           extnValue
, localized
); 
3761 static void appendNetscapeCertType(CFMutableArrayRef properties
, 
3762     const DERItem 
*extnValue
, bool localized
) { 
3763     static const CFStringRef certTypes
[] = { 
3767         SEC_OBJECT_SIGNING_KEY
, 
3771         SEC_OBJECT_SIGNING_CA_KEY
 
3773     appendBitStringNames(properties
, SEC_USAGE_KEY
, extnValue
, 
3774         certTypes
, array_size(certTypes
), localized
); 
3777 static bool appendPrintableDERSequence(CFMutableArrayRef properties
, 
3778     CFStringRef label
, const DERItem 
*sequence
, bool localized
) { 
3781     DERReturn drtn 
= DERDecodeSeqInit(sequence
, &tag
, &derSeq
); 
3782     require_noerr_quiet(drtn
, badSequence
); 
3783     require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, badSequence
); 
3784     DERDecodedInfo currDecoded
; 
3785     bool appendedSomething 
= false; 
3786     while ((drtn 
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) { 
3787                 switch (currDecoded
.tag
) 
3790                         case ASN1_SEQUENCE
:                 // 16 
3791                         case ASN1_SET
:                      // 17 
3792                                 // skip constructed object lengths 
3795                         case ASN1_UTF8_STRING
:              // 12 
3796                         case ASN1_NUMERIC_STRING
:           // 18 
3797                         case ASN1_PRINTABLE_STRING
:         // 19 
3798                         case ASN1_T61_STRING
:               // 20, also ASN1_TELETEX_STRING 
3799                         case ASN1_VIDEOTEX_STRING
:          // 21 
3800                         case ASN1_IA5_STRING
:               // 22 
3801                         case ASN1_GRAPHIC_STRING
:           // 25 
3802                         case ASN1_VISIBLE_STRING
:           // 26, also ASN1_ISO646_STRING 
3803                         case ASN1_GENERAL_STRING
:           // 27 
3804                         case ASN1_UNIVERSAL_STRING
:         // 28 
3806                 CFStringRef string 
= 
3807                     copyDERThingContentDescription(CFGetAllocator(properties
), 
3808                         currDecoded
.tag
, &currDecoded
.content
, false, localized
); 
3809                 require_quiet(string
, badSequence
); 
3811                 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, 
3813                 CFReleaseNull(string
); 
3814                                 appendedSomething 
= true; 
3821     require_quiet(drtn 
== DR_EndOfSequence
, badSequence
); 
3822         return appendedSomething
; 
3827 static void appendExtension(CFMutableArrayRef parent
, 
3828     const SecCertificateExtension 
*extn
, 
3830     CFAllocatorRef allocator 
= CFGetAllocator(parent
); 
3831     CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 0, 
3832         &kCFTypeArrayCallBacks
); 
3834         *extnID 
= &extn
->extnID
, 
3835         *extnValue 
= &extn
->extnValue
; 
3836     CFStringRef label 
= NULL
; 
3837     CFStringRef localizedLabel 
= NULL
; 
3839     appendBoolProperty(properties
, SEC_CRITICAL_KEY
, extn
->critical
, localized
); 
3840     require_quiet(extnID
, xit
); 
3842         bool handled 
= true; 
3843         /* Extensions that we know how to handle ourselves... */ 
3844         if (extnID
->length 
== oidSubjectKeyIdentifier
.length 
&& 
3845                 !memcmp(extnID
->data
, oidSubjectKeyIdentifier
.data
, extnID
->length 
- 1)) 
3847                 switch (extnID
->data
[extnID
->length 
- 1]) { 
3848                 case 14: /* SubjectKeyIdentifier     id-ce 14 */ 
3849                         appendSubjectKeyIdentifier(properties
, extnValue
, localized
); 
3851                 case 15: /* KeyUsage                 id-ce 15 */ 
3852                         appendKeyUsage(properties
, extnValue
, localized
); 
3854                 case 16: /* PrivateKeyUsagePeriod    id-ce 16 */ 
3855                         appendPrivateKeyUsagePeriod(properties
, extnValue
, localized
); 
3857                 case 17: /* SubjectAltName           id-ce 17 */ 
3858                 case 18: /* IssuerAltName            id-ce 18 */ 
3859                         appendGeneralNames(properties
, extnValue
, localized
); 
3861                 case 19: /* BasicConstraints         id-ce 19 */ 
3862                         appendBasicConstraints(properties
, extnValue
, localized
); 
3864                 case 30: /* NameConstraints          id-ce 30 */ 
3865                         appendNameConstraints(properties
, extnValue
, localized
); 
3867                 case 31: /* CRLDistributionPoints    id-ce 31 */ 
3868                         appendCrlDistributionPoints(properties
, extnValue
, localized
); 
3870                 case 32: /* CertificatePolicies      id-ce 32 */ 
3871                         appendCertificatePolicies(properties
, extnValue
, localized
); 
3873                 case 33: /* PolicyMappings           id-ce 33 */ 
3876                 case 35: /* AuthorityKeyIdentifier   id-ce 35 */ 
3877                         appendAuthorityKeyIdentifier(properties
, extnValue
, localized
); 
3879                 case 36: /* PolicyConstraints        id-ce 36 */ 
3880                         appendPolicyConstraints(properties
, extnValue
, localized
); 
3882                 case 37: /* ExtKeyUsage              id-ce 37 */ 
3883                         appendExtendedKeyUsage(properties
, extnValue
, localized
); 
3885                 case 46: /* FreshestCRL              id-ce 46 */ 
3888                 case 54: /* InhibitAnyPolicy         id-ce 54 */ 
3895         } else if (extnID
->length 
== oidAuthorityInfoAccess
.length 
&& 
3896                 !memcmp(extnID
->data
, oidAuthorityInfoAccess
.data
, extnID
->length 
- 1)) 
3898                 switch (extnID
->data
[extnID
->length 
- 1]) { 
3899                 case  1: /* AuthorityInfoAccess      id-pe 1 */ 
3900                         appendInfoAccess(properties
, extnValue
, localized
); 
3902                 case  3: /* QCStatements             id-pe 3 */ 
3905                 case 11: /* SubjectInfoAccess        id-pe 11 */ 
3906                         appendInfoAccess(properties
, extnValue
, localized
); 
3912         } else if (DEROidCompare(extnID
, &oidNetscapeCertType
)) { 
3913                 /* 2.16.840.1.113730.1.1 netscape 1 1 */ 
3914                 appendNetscapeCertType(properties
, extnValue
, localized
); 
3920                 /* Try to parse and display printable string(s). */ 
3921                 if (appendPrintableDERSequence(properties
, SEC_DATA_KEY
, extnValue
, localized
)) { 
3922                         /* Nothing to do here appendPrintableDERSequence did the work. */ 
3924                         /* Couldn't parse extension; dump the raw unparsed data as hex. */ 
3925                         appendUnparsedProperty(properties
, SEC_DATA_KEY
, NULL
, extnValue
, localized
); 
3928     label 
= SecDERItemCopyOIDDecimalRepresentation(allocator
, extnID
); 
3929     localizedLabel 
= copyOidDescription(allocator
, extnID
, localized
); 
3930     appendProperty(parent
, kSecPropertyTypeSection
, label
, localizedLabel
, 
3931                    properties
, localized
); 
3933     CFReleaseSafe(localizedLabel
); 
3934     CFReleaseSafe(label
); 
3935     CFReleaseSafe(properties
); 
3938 /* Different types of summary types from least desired to most desired. */ 
3941     kSummaryTypePrintable
, 
3942     kSummaryTypeOrganizationName
, 
3943     kSummaryTypeOrganizationalUnitName
, 
3944     kSummaryTypeCommonName
, 
3948     enum SummaryType type
; 
3949     CFStringRef summary
; 
3950     CFStringRef description
; 
3953 static OSStatus 
obtainSummaryFromX501Name(void *context
, 
3954     const DERItem 
*type
, const DERItem 
*value
, CFIndex rdnIX
, 
3956     struct Summary 
*summary 
= (struct Summary 
*)context
; 
3957     enum SummaryType stype 
= kSummaryTypeNone
; 
3958     CFStringRef string 
= NULL
; 
3959     if (DEROidCompare(type
, &oidCommonName
)) { 
3960         stype 
= kSummaryTypeCommonName
; 
3961     } else if (DEROidCompare(type
, &oidOrganizationalUnitName
)) { 
3962         stype 
= kSummaryTypeOrganizationalUnitName
; 
3963     } else if (DEROidCompare(type
, &oidOrganizationName
)) { 
3964         stype 
= kSummaryTypeOrganizationName
; 
3965     } else if (DEROidCompare(type
, &oidDescription
)) { 
3966         string 
= copyDERThingDescription(kCFAllocatorDefault
, value
, 
3969             if (summary
->description
) { 
3970                 CFStringRef fmt 
= (localized
) ? 
3971                     SecCopyCertString(SEC_STRING_LIST_KEY
) : SEC_STRING_LIST_KEY
; 
3972                 CFStringRef newDescription 
= CFStringCreateWithFormat(kCFAllocatorDefault
, 
3973                     NULL
, fmt
, string
, summary
->description
); 
3975                 CFRelease(summary
->description
); 
3976                 summary
->description 
= newDescription
; 
3978                 summary
->description 
= string
; 
3981             stype 
= kSummaryTypePrintable
; 
3984         stype 
= kSummaryTypePrintable
; 
3987     /* Build a string with all instances of the most desired 
3988        component type in reverse order encountered comma separated list, 
3989        The order of desirability is defined by enum SummaryType. */ 
3990     if (summary
->type 
<= stype
) { 
3992             string 
= copyDERThingDescription(kCFAllocatorDefault
, value
, 
3996             if (summary
->type 
== stype
) { 
3997                 CFStringRef fmt 
= (localized
) ? 
3998                     SecCopyCertString(SEC_STRING_LIST_KEY
) : SEC_STRING_LIST_KEY
; 
3999                 CFStringRef newSummary 
= CFStringCreateWithFormat(kCFAllocatorDefault
, 
4000                     NULL
, fmt
, string
, summary
->summary
); 
4003                 string 
= newSummary
; 
4005                 summary
->type 
= stype
; 
4007             CFReleaseSafe(summary
->summary
); 
4008             summary
->summary 
= string
; 
4011         CFReleaseSafe(string
); 
4014         return errSecSuccess
; 
4017 CFStringRef 
SecCertificateCopySubjectSummary(SecCertificateRef certificate
) { 
4018     struct Summary summary 
= {}; 
4019         OSStatus status 
= parseX501NameContent(&certificate
->_subject
, &summary
, obtainSummaryFromX501Name
, true); 
4020     if (status 
!= errSecSuccess
) { 
4023     /* If we found a description and a common name we change the summary to 
4024        CommonName (Description). */ 
4025     if (summary
.description
) { 
4026         if (summary
.type 
== kSummaryTypeCommonName
) { 
4027             CFStringRef fmt 
= SecCopyCertString(SEC_COMMON_NAME_DESC_KEY
); 
4028             CFStringRef newSummary 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, summary
.summary
, summary
.description
); 
4030             CFRelease(summary
.summary
); 
4031             summary
.summary 
= newSummary
; 
4033         CFRelease(summary
.description
); 
4036     if (!summary
.summary
) { 
4037         /* If we didn't find a suitable printable string in the subject at all, we try 
4038            the first email address in the certificate instead. */ 
4039         CFArrayRef names 
= SecCertificateCopyRFC822Names(certificate
); 
4041             /* If we didn't find any email addresses in the certificate, we try finding 
4042                a DNS name instead. */ 
4043             names 
= SecCertificateCopyDNSNames(certificate
); 
4046             summary
.summary 
= CFArrayGetValueAtIndex(names
, 0); 
4047             CFRetain(summary
.summary
); 
4052         return summary
.summary
; 
4055 CFStringRef 
SecCertificateCopyIssuerSummary(SecCertificateRef certificate
) { 
4056     struct Summary summary 
= {}; 
4057         OSStatus status 
= parseX501NameContent(&certificate
->_issuer
, &summary
, obtainSummaryFromX501Name
, true); 
4058     if (status 
!= errSecSuccess
) { 
4061     /* If we found a description and a common name we change the summary to 
4062        CommonName (Description). */ 
4063     if (summary
.description
) { 
4064         if (summary
.type 
== kSummaryTypeCommonName
) { 
4065             CFStringRef fmt 
= SecCopyCertString(SEC_COMMON_NAME_DESC_KEY
); 
4066             CFStringRef newSummary 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, summary
.summary
, summary
.description
); 
4068             CFRelease(summary
.summary
); 
4069             summary
.summary 
= newSummary
; 
4071         CFRelease(summary
.description
); 
4074         return summary
.summary
; 
4077 /* Return the earliest date on which all certificates in this chain are still 
4079 static CFAbsoluteTime 
SecCertificateGetChainsLastValidity( 
4080     SecCertificateRef certificate
) { 
4081     CFAbsoluteTime earliest 
= certificate
->_notAfter
; 
4083     while (certificate
->_parent
) { 
4084         certificate 
= certificate
->_parent
; 
4085         if (earliest 
> certificate
->_notAfter
) 
4086             earliest 
= certificate
->_notAfter
; 
4093 /* Return the latest date on which all certificates in this chain will be 
4095 static CFAbsoluteTime 
SecCertificateGetChainsFirstValidity( 
4096     SecCertificateRef certificate
) { 
4097     CFAbsoluteTime latest 
= certificate
->_notBefore
; 
4099     while (certificate
->_parent
) { 
4100         certificate 
= certificate
->_parent
; 
4101         if (latest 
< certificate
->_notBefore
) 
4102             latest 
= certificate
->_notBefore
; 
4109 bool SecCertificateIsValid(SecCertificateRef certificate
, 
4110         CFAbsoluteTime verifyTime
) { 
4111     return certificate 
&& certificate
->_notBefore 
<= verifyTime 
&& 
4112                 verifyTime 
<= certificate
->_notAfter
; 
4115 CFIndex 
SecCertificateVersion(SecCertificateRef certificate
) { 
4116         return certificate
->_version 
+ 1; 
4119 CFAbsoluteTime 
SecCertificateNotValidBefore(SecCertificateRef certificate
) { 
4120         return certificate
->_notBefore
; 
4123 CFAbsoluteTime 
SecCertificateNotValidAfter(SecCertificateRef certificate
) { 
4124         return certificate
->_notAfter
; 
4127 CFMutableArrayRef 
SecCertificateCopySummaryProperties( 
4128     SecCertificateRef certificate
, CFAbsoluteTime verifyTime
) { 
4129     CFAllocatorRef allocator 
= CFGetAllocator(certificate
); 
4130     CFMutableArrayRef summary 
= CFArrayCreateMutable(allocator
, 0, 
4131         &kCFTypeArrayCallBacks
); 
4132     bool localized 
= true; 
4134     /* First we put the subject summary name. */ 
4135     CFStringRef ssummary 
= SecCertificateCopySubjectSummary(certificate
); 
4137         appendProperty(summary
, kSecPropertyTypeTitle
, 
4138             NULL
, NULL
, ssummary
, localized
); 
4139         CFRelease(ssummary
); 
4142     /* Let see if this certificate is currently valid. */ 
4144     CFAbsoluteTime when
; 
4145     CFStringRef message
; 
4147     if (verifyTime 
> certificate
->_notAfter
) { 
4148         label 
= SEC_EXPIRED_KEY
; 
4149         when 
= certificate
->_notAfter
; 
4150         ptype 
= kSecPropertyTypeError
; 
4151         message 
= SEC_CERT_EXPIRED_KEY
; 
4152     } else if (certificate
->_notBefore 
> verifyTime
) { 
4153         label 
= SEC_VALID_FROM_KEY
; 
4154         when 
= certificate
->_notBefore
; 
4155         ptype 
= kSecPropertyTypeError
; 
4156         message 
= SEC_CERT_NOT_YET_VALID_KEY
; 
4158         CFAbsoluteTime last 
= SecCertificateGetChainsLastValidity(certificate
); 
4159         CFAbsoluteTime first 
= SecCertificateGetChainsFirstValidity(certificate
); 
4160         if (verifyTime 
> last
) { 
4161             label 
= SEC_EXPIRED_KEY
; 
4163             ptype 
= kSecPropertyTypeError
; 
4164             message 
= SEC_ISSUER_EXPIRED_KEY
; 
4165         } else if (verifyTime 
< first
) { 
4166             label 
= SEC_VALID_FROM_KEY
; 
4168             ptype 
= kSecPropertyTypeError
; 
4169             message 
= SEC_ISSR_NOT_YET_VALID_KEY
; 
4171             label 
= SEC_EXPIRES_KEY
; 
4172             when 
= certificate
->_notAfter
; 
4173             ptype 
= kSecPropertyTypeSuccess
; 
4174             message 
= SEC_CERT_VALID_KEY
; 
4178     appendDateProperty(summary
, label
, when
, localized
); 
4179     CFStringRef lmessage 
= SecCopyCertString(message
); 
4180     appendProperty(summary
, ptype
, NULL
, NULL
, lmessage
, localized
); 
4181     CFRelease(lmessage
); 
4186 CFArrayRef 
SecCertificateCopyLegacyProperties(SecCertificateRef certificate
) { 
4188        This function replicates the content returned by SecCertificateCopyProperties 
4189        prior to 10.12.4, providing stable return values for SecCertificateCopyValues. 
4190        Unlike SecCertificateCopyProperties, it does not cache the result and 
4191        assumes the caller will do so. 
4193     CFAllocatorRef allocator 
= CFGetAllocator(certificate
); 
4194     CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 
4195         0, &kCFTypeArrayCallBacks
); 
4198     CFArrayRef subject_plist 
= createPropertiesForX501NameContent(allocator
, 
4199         &certificate
->_subject
, false); 
4200     appendProperty(properties
, kSecPropertyTypeSection
, CFSTR("Subject Name"), 
4201         NULL
, subject_plist
, false); 
4202     CFRelease(subject_plist
); 
4205     CFArrayRef issuer_plist 
= createPropertiesForX501NameContent(allocator
, 
4206         &certificate
->_issuer
, false); 
4207     appendProperty(properties
, kSecPropertyTypeSection
, CFSTR("Issuer Name"), 
4208         NULL
, issuer_plist
, false); 
4209     CFRelease(issuer_plist
); 
4212     CFStringRef versionString 
= CFStringCreateWithFormat(allocator
, 
4213         NULL
, CFSTR("%d"), certificate
->_version 
+ 1); 
4214     appendProperty(properties
, kSecPropertyTypeString
, CFSTR("Version"), 
4215         NULL
, versionString
, false); 
4216     CFRelease(versionString
); 
4219     if (certificate
->_serialNum
.length
) { 
4220         appendIntegerProperty(properties
, CFSTR("Serial Number"), 
4221             &certificate
->_serialNum
, false); 
4224     /* Signature Algorithm */ 
4225     appendAlgorithmProperty(properties
, CFSTR("Signature Algorithm"), 
4226         &certificate
->_tbsSigAlg
, false); 
4228     /* Validity dates */ 
4229     appendDateProperty(properties
, CFSTR("Not Valid Before"), certificate
->_notBefore
, false); 
4230     appendDateProperty(properties
, CFSTR("Not Valid After"), certificate
->_notAfter
, false); 
4232     if (certificate
->_subjectUniqueID
.length
) { 
4233         appendDataProperty(properties
, CFSTR("Subject Unique ID"), 
4234             NULL
, &certificate
->_subjectUniqueID
, false); 
4236     if (certificate
->_issuerUniqueID
.length
) { 
4237         appendDataProperty(properties
, CFSTR("Issuer Unique ID"), 
4238             NULL
, &certificate
->_issuerUniqueID
, false); 
4241     /* Public Key Algorithm */ 
4242     appendAlgorithmProperty(properties
, CFSTR("Public Key Algorithm"), 
4243         &certificate
->_algId
, false); 
4245     /* Public Key Data */ 
4246     appendDataProperty(properties
, CFSTR("Public Key Data"), 
4247         NULL
, &certificate
->_pubKeyDER
, false); 
4250     appendDataProperty(properties
, CFSTR("Signature"), 
4251         NULL
, &certificate
->_signature
, false); 
4255     for (ix 
= 0; ix 
< certificate
->_extensionCount
; ++ix
) { 
4256         appendExtension(properties
, &certificate
->_extensions
[ix
], false); 
4260     appendFingerprintsProperty(properties
, CFSTR("Fingerprints"), certificate
, false); 
4265 CFArrayRef 
SecCertificateCopyProperties(SecCertificateRef certificate
) { 
4266         if (!certificate
->_properties
) { 
4267                 CFAllocatorRef allocator 
= CFGetAllocator(certificate
); 
4268                 CFMutableArrayRef properties 
= CFArrayCreateMutable(allocator
, 0, 
4269                         &kCFTypeArrayCallBacks
); 
4270         require_quiet(properties
, out
); 
4271         bool localized 
= true; 
4273         /* First we put the Subject Name in the property list. */ 
4274         CFArrayRef subject_plist 
= createPropertiesForX501NameContent(allocator
, 
4275                                                                       &certificate
->_subject
, 
4277         if (subject_plist
) { 
4278             appendProperty(properties
, kSecPropertyTypeSection
, 
4279                            SEC_SUBJECT_NAME_KEY
, NULL
, subject_plist
, localized
); 
4281         CFReleaseNull(subject_plist
); 
4283         /* Next we put the Issuer Name in the property list. */ 
4284         CFArrayRef issuer_plist 
= createPropertiesForX501NameContent(allocator
, 
4285                                                                      &certificate
->_issuer
, 
4288             appendProperty(properties
, kSecPropertyTypeSection
, 
4289                            SEC_ISSUER_NAME_KEY
, NULL
, issuer_plist
, localized
); 
4291         CFReleaseNull(issuer_plist
); 
4294         CFStringRef fmt 
= SecCopyCertString(SEC_CERT_VERSION_VALUE_KEY
); 
4295         CFStringRef versionString 
= NULL
; 
4297             versionString 
= CFStringCreateWithFormat(allocator
, NULL
, fmt
, 
4298                                                      certificate
->_version 
+ 1); 
4301         if (versionString
) { 
4302             appendProperty(properties
, kSecPropertyTypeString
, 
4303                            SEC_VERSION_KEY
, NULL
, versionString
, localized
); 
4305         CFReleaseNull(versionString
); 
4308         appendSerialNumberProperty(properties
, SEC_SERIAL_NUMBER_KEY
, &certificate
->_serialNum
, localized
); 
4310         /* Validity dates. */ 
4311         appendValidityPeriodProperty(properties
, SEC_VALIDITY_PERIOD_KEY
, certificate
, localized
); 
4313         if (certificate
->_subjectUniqueID
.length
) { 
4314             appendDataProperty(properties
, SEC_SUBJECT_UNIQUE_ID_KEY
, NULL
, 
4315                 &certificate
->_subjectUniqueID
, localized
); 
4317         if (certificate
->_issuerUniqueID
.length
) { 
4318             appendDataProperty(properties
, SEC_ISSUER_UNIQUE_ID_KEY
, NULL
, 
4319                 &certificate
->_issuerUniqueID
, localized
); 
4322         appendPublicKeyProperty(properties
, SEC_PUBLIC_KEY_KEY
, certificate
, localized
); 
4325         for (ix 
= 0; ix 
< certificate
->_extensionCount
; ++ix
) { 
4326             appendExtension(properties
, &certificate
->_extensions
[ix
], localized
); 
4330         appendSignatureProperty(properties
, SEC_SIGNATURE_KEY
, certificate
, localized
); 
4332         appendFingerprintsProperty(properties
, SEC_FINGERPRINTS_KEY
, certificate
, localized
); 
4334                 certificate
->_properties 
= properties
; 
4338     CFRetainSafe(certificate
->_properties
); 
4339         return certificate
->_properties
; 
4342 /* Unified serial number API */ 
4343 CFDataRef 
SecCertificateCopySerialNumberData( 
4344         SecCertificateRef certificate
, 
4349                         *error 
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidCertificate
, NULL
); 
4353         if (certificate
->_serialNumber
) { 
4354                 CFRetain(certificate
->_serialNumber
); 
4356         return certificate
->_serialNumber
; 
4360 /* On iOS, the SecCertificateCopySerialNumber API takes one argument. */ 
4361 CFDataRef 
SecCertificateCopySerialNumber( 
4362                 SecCertificateRef certificate
) { 
4363         return SecCertificateCopySerialNumberData(certificate
, NULL
); 
4367 CFDataRef 
SecCertificateGetNormalizedIssuerContent( 
4368     SecCertificateRef certificate
) { 
4369     return certificate
->_normalizedIssuer
; 
4372 CFDataRef 
SecCertificateGetNormalizedSubjectContent( 
4373     SecCertificateRef certificate
) { 
4374     return certificate
->_normalizedSubject
; 
4377 /* Verify that certificate was signed by issuerKey. */ 
4378 OSStatus 
SecCertificateIsSignedBy(SecCertificateRef certificate
, 
4379     SecKeyRef issuerKey
) { 
4380     /* Setup algId in SecAsn1AlgId format. */ 
4382     algId
.algorithm
.Length 
= certificate
->_tbsSigAlg
.oid
.length
; 
4383     algId
.algorithm
.Data 
= certificate
->_tbsSigAlg
.oid
.data
; 
4384     algId
.parameters
.Length 
= certificate
->_tbsSigAlg
.params
.length
; 
4385     algId
.parameters
.Data 
= certificate
->_tbsSigAlg
.params
.data
; 
4387     /* RFC5280 4.1.1.2, 4.1.2.3 requires the actual signature algorithm 
4388        must match the specified algorithm in the TBSCertificate. */ 
4389         bool sigAlgMatch 
= DEROidCompare(&certificate
->_sigAlg
.oid
, 
4390                          &certificate
->_tbsSigAlg
.oid
); 
4392         secwarning("Signature algorithm mismatch in certificate (see RFC5280 4.1.1.2)"); 
4395     CFErrorRef error 
= NULL
; 
4397         !SecVerifySignatureWithPublicKey(issuerKey
, &algId
, 
4398         certificate
->_tbs
.data
, certificate
->_tbs
.length
, 
4399         certificate
->_signature
.data
, certificate
->_signature
.length
, &error
)) 
4401 #if !defined(NDEBUG) 
4402         secdebug("verify", "signature verify failed: %" PRIdOSStatus
, (error
) ? (OSStatus
)CFErrorGetCode(error
) : errSecNotSigner
); 
4404         CFReleaseSafe(error
); 
4405         return errSecNotSigner
; 
4408     return errSecSuccess
; 
4411 const DERItem 
* SecCertificateGetSubjectAltName(SecCertificateRef certificate
) { 
4412     if (!certificate
->_subjectAltName
) { 
4415     return &certificate
->_subjectAltName
->extnValue
; 
4418 static bool convertIPAddress(CFStringRef name
, CFDataRef 
*dataIP
) { 
4419     /* IPv4: 4 octets in decimal separated by dots. We don't support matching IPv6 already. */ 
4420     bool result 
= false; 
4422     if (CFStringGetLength(name
) < 7 || /* min size is #.#.#.# */ 
4423         CFStringGetLength(name
) > 15) { /* max size is ###.###.###.### */ 
4427     CFCharacterSetRef decimals 
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("0123456789.")); 
4428     CFCharacterSetRef nonDecimals 
= CFCharacterSetCreateInvertedSet(NULL
, decimals
); 
4429     CFMutableDataRef data 
= CFDataCreateMutable(NULL
, 0); 
4430     CFArrayRef parts 
= CFStringCreateArrayBySeparatingStrings(NULL
, name
, CFSTR(".")); 
4432     /* Check character set */ 
4433     if (CFStringFindCharacterFromSet(name
, nonDecimals
, 
4434                                       CFRangeMake(0, CFStringGetLength(name
)), 
4435                                       kCFCompareForcedOrdering
, NULL
)) { 
4439     /* Check number of labels */ 
4440     if (CFArrayGetCount(parts
) != 4) { 
4444     /* Check each label and convert */ 
4445     CFIndex i
, count 
= CFArrayGetCount(parts
); 
4446     for (i 
= 0; i 
< count
; i
++) { 
4447         CFStringRef octet 
= CFArrayGetValueAtIndex(parts
, i
); 
4448         char *cString 
= CFStringToCString(octet
); 
4449         uint32_t value 
= atoi(cString
); 
4454             uint8_t byte 
= value
; 
4455             CFDataAppendBytes(data
, &byte
, 1); 
4460         *dataIP 
= CFRetain(data
); 
4464     CFReleaseNull(data
); 
4465     CFReleaseNull(parts
); 
4466     CFReleaseNull(decimals
); 
4467     CFReleaseNull(nonDecimals
); 
4471 static OSStatus 
appendIPAddressesFromGeneralNames(void *context
, 
4472         SecCEGeneralNameType gnType
, const DERItem 
*generalName
) { 
4473         CFMutableArrayRef ipAddresses 
= (CFMutableArrayRef
)context
; 
4474         if (gnType 
== GNT_IPAddress
) { 
4475                 CFStringRef string 
= copyIPAddressContentDescription( 
4476                         kCFAllocatorDefault
, generalName
); 
4478                         CFArrayAppendValue(ipAddresses
, string
); 
4481                         return errSecInvalidCertificate
; 
4484         return errSecSuccess
; 
4487 CFArrayRef 
SecCertificateCopyIPAddresses(SecCertificateRef certificate
) { 
4488         /* These can only exist in the subject alt name. */ 
4489         if (!certificate
->_subjectAltName
) 
4492         CFMutableArrayRef ipAddresses 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4493                 0, &kCFTypeArrayCallBacks
); 
4494         OSStatus status 
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
, 
4495                 ipAddresses
, appendIPAddressesFromGeneralNames
); 
4496         if (status 
|| CFArrayGetCount(ipAddresses
) == 0) { 
4497                 CFRelease(ipAddresses
); 
4503 static OSStatus 
appendIPAddressesFromX501Name(void *context
, const DERItem 
*type
, 
4504                                               const DERItem 
*value
, CFIndex rdnIX
, 
4506     CFMutableArrayRef addrs 
= (CFMutableArrayRef
)context
; 
4507     if (DEROidCompare(type
, &oidCommonName
)) { 
4508         CFStringRef string 
= copyDERThingDescription(kCFAllocatorDefault
, 
4509                                                      value
, true, localized
); 
4511             CFDataRef data 
= NULL
; 
4512             if (convertIPAddress(string
, &data
)) { 
4513                 CFArrayAppendValue(addrs
, data
); 
4514                 CFReleaseNull(data
); 
4518             return errSecInvalidCertificate
; 
4521     return errSecSuccess
; 
4524 CFArrayRef 
SecCertificateCopyIPAddressesFromSubject(SecCertificateRef certificate
) { 
4525     CFMutableArrayRef addrs 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4526                                                       0, &kCFTypeArrayCallBacks
); 
4527     OSStatus status 
= parseX501NameContent(&certificate
->_subject
, addrs
, 
4528                                            appendIPAddressesFromX501Name
, true); 
4529     if (status 
|| CFArrayGetCount(addrs
) == 0) { 
4530         CFReleaseNull(addrs
); 
4536 static OSStatus 
appendDNSNamesFromGeneralNames(void *context
, SecCEGeneralNameType gnType
, 
4537         const DERItem 
*generalName
) { 
4538         CFMutableArrayRef dnsNames 
= (CFMutableArrayRef
)context
; 
4539         if (gnType 
== GNT_DNSName
) { 
4540                 CFStringRef string 
= CFStringCreateWithBytes(kCFAllocatorDefault
, 
4541                         generalName
->data
, generalName
->length
, 
4542                         kCFStringEncodingUTF8
, FALSE
); 
4544                         CFArrayAppendValue(dnsNames
, string
); 
4547                         return errSecInvalidCertificate
; 
4550         return errSecSuccess
; 
4553 /* Return true if the passed in string matches the 
4554    Preferred name syntax from sections 2.3.1. in RFC 1035. 
4555    With the added check that we disallow empty dns names. 
4556    Also in order to support wildcard DNSNames we allow for the '*' 
4557    character anywhere in a dns component where we currently allow 
4560         <domain> ::= <subdomain> | " " 
4562         <subdomain> ::= <label> | <subdomain> "." <label> 
4564         <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ] 
4566         <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str> 
4568         <let-dig-hyp> ::= <let-dig> | "-" 
4570         <let-dig> ::= <letter> | <digit> 
4572         <letter> ::= any one of the 52 alphabetic characters A through Z in 
4573         upper case and a through z in lower case 
4575         <digit> ::= any one of the ten digits 0 through 9 
4577 static bool isDNSName(CFStringRef string
) { 
4578     CFStringInlineBuffer buf 
= {}; 
4579         CFIndex ix
, labelLength 
= 0, length 
= CFStringGetLength(string
); 
4580         /* From RFC 1035 2.3.4. Size limits: 
4581            labels          63 octets or less 
4582            names           255 octets or less */ 
4583         require_quiet(length 
<= 255, notDNS
); 
4584         CFRange range 
= { 0, length 
}; 
4585         CFStringInitInlineBuffer(string
, &buf
, range
); 
4589                 kDNSStateAfterAlpha
, 
4590                 kDNSStateAfterDigit
, 
4592         } state 
= kDNSStateInital
; 
4594         for (ix 
= 0; ix 
< length
; ++ix
) { 
4595                 UniChar ch 
= CFStringGetCharacterFromInlineBuffer(&buf
, ix
); 
4598                         require_quiet(labelLength 
<= 64 && 
4599                                 (state 
== kDNSStateAfterAlpha 
|| state 
== kDNSStateAfterDigit
), 
4601                         state 
= kDNSStateAfterDot
; 
4603                 } else if (('A' <= ch 
&& ch 
<= 'Z') || ('a' <= ch 
&& ch 
<= 'z')  || 
4605                         state 
= kDNSStateAfterAlpha
; 
4606                 } else if ('0' <= ch 
&& ch 
<= '9') { 
4608                         /* The requirement for labels to start with a letter was 
4609                            dropped so we don't check this anymore.  */ 
4610                         require_quiet(state 
== kDNSStateAfterAlpha 
|| 
4611                                 state 
== kDNSStateAfterDigit 
|| 
4612                                 state 
== kDNSStateAfterDash
, notDNS
); 
4614                         state 
= kDNSStateAfterDigit
; 
4615                 } else if (ch 
== '-') { 
4616                         require_quiet(state 
== kDNSStateAfterAlpha 
|| 
4617                                 state 
== kDNSStateAfterDigit 
|| 
4618                                 state 
== kDNSStateAfterDash
, notDNS
); 
4619                         state 
= kDNSStateAfterDash
; 
4625         /* We don't allow a dns name to end in a dot or dash.  */ 
4626         require_quiet(labelLength 
<= 63 && 
4627                 (state 
== kDNSStateAfterAlpha 
|| state 
== kDNSStateAfterDigit
), 
4635 static OSStatus 
appendDNSNamesFromX501Name(void *context
, const DERItem 
*type
, 
4636         const DERItem 
*value
, CFIndex rdnIX
, bool localized
) { 
4637         CFMutableArrayRef dnsNames 
= (CFMutableArrayRef
)context
; 
4638         if (DEROidCompare(type
, &oidCommonName
)) { 
4639                 CFStringRef string 
= copyDERThingDescription(kCFAllocatorDefault
, 
4640                         value
, true, localized
); 
4642                         if (isDNSName(string
)) { 
4643                                 /* We found a common name that is formatted like a valid 
4645                                 CFArrayAppendValue(dnsNames
, string
); 
4649                         return errSecInvalidCertificate
; 
4652         return errSecSuccess
; 
4655 CFArrayRef 
SecCertificateCopyDNSNamesFromSubject(SecCertificateRef certificate
) { 
4656     CFMutableArrayRef dnsNames 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4657                                                       0, &kCFTypeArrayCallBacks
); 
4658     OSStatus status 
= parseX501NameContent(&certificate
->_subject
, dnsNames
, 
4659                                           appendDNSNamesFromX501Name
, true); 
4660     if (status 
|| CFArrayGetCount(dnsNames
) == 0) { 
4661         CFReleaseNull(dnsNames
); 
4665     /* appendDNSNamesFromX501Name allows IP addresses, we don't want those for this function */ 
4666     __block CFMutableArrayRef result 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
4667     CFArrayForEach(dnsNames
, ^(const void *value
) { 
4668         CFStringRef name 
= (CFStringRef
)value
; 
4669         if (!convertIPAddress(name
, NULL
)) { 
4670             CFArrayAppendValue(result
, name
); 
4673     CFReleaseNull(dnsNames
); 
4674     if (CFArrayGetCount(result
) == 0) { 
4675         CFReleaseNull(result
); 
4681 CFArrayRef 
SecCertificateCopyDNSNamesFromSAN(SecCertificateRef certificate
) { 
4682     CFMutableArrayRef dnsNames 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4683                                                       0, &kCFTypeArrayCallBacks
); 
4684     OSStatus status 
= errSecSuccess
; 
4685     if (certificate
->_subjectAltName
) { 
4686         status 
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
, 
4687                                                  dnsNames
, appendDNSNamesFromGeneralNames
); 
4690     if (status 
|| CFArrayGetCount(dnsNames
) == 0) { 
4691         CFReleaseNull(dnsNames
); 
4696 /* Not everything returned by this function is going to be a proper DNS name, 
4697    we also return the certificates common name entries from the subject, 
4698    assuming they look like dns names as specified in RFC 1035. */ 
4699 CFArrayRef 
SecCertificateCopyDNSNames(SecCertificateRef certificate
) { 
4700         /* These can exist in the subject alt name or in the subject. */ 
4701     CFArrayRef sanNames 
= SecCertificateCopyDNSNamesFromSAN(certificate
); 
4702     if (sanNames 
&& CFArrayGetCount(sanNames
) > 0) { 
4705     CFReleaseNull(sanNames
); 
4707         /* RFC 2818 section 3.1.  Server Identity 
4709           If a subjectAltName extension of type dNSName is present, that MUST 
4710           be used as the identity. Otherwise, the (most specific) Common Name 
4711           field in the Subject field of the certificate MUST be used. Although 
4712           the use of the Common Name is existing practice, it is deprecated and 
4713           Certification Authorities are encouraged to use the dNSName instead. 
4716           This implies that if we found 1 or more DNSNames in the 
4717           subjectAltName, we should not use the Common Name of the subject as 
4721     /* To preserve bug for bug compatibility, we can't use SecCertificateCopyDNSNamesFromSubject 
4722      * because that function filters out IP Addresses. This function is Private, but 
4723      * SecCertificateCopyValues uses it and that's Public. */ 
4724     CFMutableArrayRef dnsNames 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4725                                                       0, &kCFTypeArrayCallBacks
); 
4726     OSStatus status 
= parseX501NameContent(&certificate
->_subject
, dnsNames
, 
4727             appendDNSNamesFromX501Name
, true); 
4728     if (status 
|| CFArrayGetCount(dnsNames
) == 0) { 
4729         CFReleaseNull(dnsNames
); 
4734 static OSStatus 
appendRFC822NamesFromGeneralNames(void *context
, 
4735         SecCEGeneralNameType gnType
, const DERItem 
*generalName
) { 
4736         CFMutableArrayRef dnsNames 
= (CFMutableArrayRef
)context
; 
4737         if (gnType 
== GNT_RFC822Name
) { 
4738                 CFStringRef string 
= CFStringCreateWithBytes(kCFAllocatorDefault
, 
4739                         generalName
->data
, generalName
->length
, 
4740                         kCFStringEncodingASCII
, FALSE
); 
4742                         CFArrayAppendValue(dnsNames
, string
); 
4745                         return errSecInvalidCertificate
; 
4748         return errSecSuccess
; 
4751 static OSStatus 
appendRFC822NamesFromX501Name(void *context
, const DERItem 
*type
, 
4752         const DERItem 
*value
, CFIndex rdnIX
, bool localized
) { 
4753         CFMutableArrayRef dnsNames 
= (CFMutableArrayRef
)context
; 
4754         if (DEROidCompare(type
, &oidEmailAddress
)) { 
4755                 CFStringRef string 
= copyDERThingDescription(kCFAllocatorDefault
, 
4756                         value
, true, localized
); 
4758                         CFArrayAppendValue(dnsNames
, string
); 
4761                         return errSecInvalidCertificate
; 
4764         return errSecSuccess
; 
4767 CFArrayRef 
SecCertificateCopyRFC822Names(SecCertificateRef certificate
) { 
4768         /* These can exist in the subject alt name or in the subject. */ 
4769         CFMutableArrayRef rfc822Names 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4770                 0, &kCFTypeArrayCallBacks
); 
4771         OSStatus status 
= errSecSuccess
; 
4772         if (certificate
->_subjectAltName
) { 
4773                 status 
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
, 
4774                         rfc822Names
, appendRFC822NamesFromGeneralNames
); 
4777                 status 
= parseX501NameContent(&certificate
->_subject
, rfc822Names
, 
4778                         appendRFC822NamesFromX501Name
, true); 
4780         if (status 
|| CFArrayGetCount(rfc822Names
) == 0) { 
4781                 CFRelease(rfc822Names
); 
4787 OSStatus 
SecCertificateCopyEmailAddresses(SecCertificateRef certificate
, CFArrayRef 
* __nonnull CF_RETURNS_RETAINED emailAddresses
) { 
4788     if (!certificate 
|| !emailAddresses
) { 
4791     *emailAddresses 
= SecCertificateCopyRFC822Names(certificate
); 
4792     if (*emailAddresses 
== NULL
) { 
4793         *emailAddresses 
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
); 
4795     return errSecSuccess
; 
4798 CFArrayRef 
SecCertificateCopyRFC822NamesFromSubject(SecCertificateRef certificate
) { 
4799     CFMutableArrayRef rfc822Names 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4800                                                          0, &kCFTypeArrayCallBacks
); 
4801     OSStatus status 
= parseX501NameContent(&certificate
->_subject
, rfc822Names
, 
4802                                       appendRFC822NamesFromX501Name
, true); 
4803     if (status 
|| CFArrayGetCount(rfc822Names
) == 0) { 
4804         CFRelease(rfc822Names
); 
4810 static OSStatus 
appendCommonNamesFromX501Name(void *context
, 
4811     const DERItem 
*type
, const DERItem 
*value
, CFIndex rdnIX
, bool localized
) { 
4812         CFMutableArrayRef commonNames 
= (CFMutableArrayRef
)context
; 
4813         if (DEROidCompare(type
, &oidCommonName
)) { 
4814                 CFStringRef string 
= copyDERThingDescription(kCFAllocatorDefault
, 
4815                         value
, true, localized
); 
4817             CFArrayAppendValue(commonNames
, string
); 
4820                         return errSecInvalidCertificate
; 
4823         return errSecSuccess
; 
4826 CFArrayRef 
SecCertificateCopyCommonNames(SecCertificateRef certificate
) { 
4827         CFMutableArrayRef commonNames 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4828                 0, &kCFTypeArrayCallBacks
); 
4830     status 
= parseX501NameContent(&certificate
->_subject
, commonNames
, 
4831         appendCommonNamesFromX501Name
, true); 
4832         if (status 
|| CFArrayGetCount(commonNames
) == 0) { 
4833                 CFRelease(commonNames
); 
4839 OSStatus 
SecCertificateCopyCommonName(SecCertificateRef certificate
, CFStringRef 
*commonName
) 
4844     CFArrayRef commonNames 
= SecCertificateCopyCommonNames(certificate
); 
4846         return errSecInternal
; 
4850         CFIndex count 
= CFArrayGetCount(commonNames
); 
4851         *commonName 
= CFRetainSafe(CFArrayGetValueAtIndex(commonNames
, count
-1)); 
4853     CFReleaseSafe(commonNames
); 
4854     return errSecSuccess
; 
4857 static OSStatus 
appendOrganizationFromX501Name(void *context
, 
4858         const DERItem 
*type
, const DERItem 
*value
, CFIndex rdnIX
, bool localized
) { 
4859         CFMutableArrayRef organization 
= (CFMutableArrayRef
)context
; 
4860         if (DEROidCompare(type
, &oidOrganizationName
)) { 
4861                 CFStringRef string 
= copyDERThingDescription(kCFAllocatorDefault
, 
4862                         value
, true, localized
); 
4864                         CFArrayAppendValue(organization
, string
); 
4867                         return errSecInvalidCertificate
; 
4870         return errSecSuccess
; 
4873 CFArrayRef 
SecCertificateCopyOrganizationFromX501NameContent(const DERItem 
*nameContent
) { 
4874     CFMutableArrayRef organization 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4875                                                           0, &kCFTypeArrayCallBacks
); 
4877     status 
= parseX501NameContent(nameContent
, organization
, 
4878                                   appendOrganizationFromX501Name
, true); 
4879     if (status 
|| CFArrayGetCount(organization
) == 0) { 
4880         CFRelease(organization
); 
4881         organization 
= NULL
; 
4883     return organization
; 
4886 CFArrayRef 
SecCertificateCopyOrganization(SecCertificateRef certificate
) { 
4887     return SecCertificateCopyOrganizationFromX501NameContent(&certificate
->_subject
); 
4890 static OSStatus 
appendOrganizationalUnitFromX501Name(void *context
, 
4891         const DERItem 
*type
, const DERItem 
*value
, CFIndex rdnIX
, bool localized
) { 
4892         CFMutableArrayRef organizationalUnit 
= (CFMutableArrayRef
)context
; 
4893         if (DEROidCompare(type
, &oidOrganizationalUnitName
)) { 
4894                 CFStringRef string 
= copyDERThingDescription(kCFAllocatorDefault
, 
4895                         value
, true, localized
); 
4897                         CFArrayAppendValue(organizationalUnit
, string
); 
4900                         return errSecInvalidCertificate
; 
4903         return errSecSuccess
; 
4906 CFArrayRef 
SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate
) { 
4907         CFMutableArrayRef organizationalUnit 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4908                 0, &kCFTypeArrayCallBacks
); 
4910         status 
= parseX501NameContent(&certificate
->_subject
, organizationalUnit
, 
4911         appendOrganizationalUnitFromX501Name
, true); 
4912         if (status 
|| CFArrayGetCount(organizationalUnit
) == 0) { 
4913                 CFRelease(organizationalUnit
); 
4914                 organizationalUnit 
= NULL
; 
4916         return organizationalUnit
; 
4919 static OSStatus 
appendCountryFromX501Name(void *context
, 
4920     const DERItem 
*type
, const DERItem 
*value
, CFIndex rdnIX
, bool localized
) { 
4921     CFMutableArrayRef countries 
= (CFMutableArrayRef
)context
; 
4922     if (DEROidCompare(type
, &oidCountryName
)) { 
4923         CFStringRef string 
= copyDERThingDescription(kCFAllocatorDefault
, 
4924                                                      value
, true, localized
); 
4926             CFArrayAppendValue(countries
, string
); 
4929             return errSecInvalidCertificate
; 
4932     return errSecSuccess
; 
4935 CFArrayRef 
SecCertificateCopyCountry(SecCertificateRef certificate
) { 
4936     CFMutableArrayRef countries 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
4937                                                                 0, &kCFTypeArrayCallBacks
); 
4939     status 
= parseX501NameContent(&certificate
->_subject
, countries
, 
4940                                   appendCountryFromX501Name
, true); 
4941     if (status 
|| CFArrayGetCount(countries
) == 0) { 
4942         CFRelease(countries
); 
4948 const SecCEBasicConstraints 
* 
4949 SecCertificateGetBasicConstraints(SecCertificateRef certificate
) { 
4950         if (certificate
->_basicConstraints
.present
) 
4951                 return &certificate
->_basicConstraints
; 
4956 CFArrayRef 
SecCertificateGetPermittedSubtrees(SecCertificateRef certificate
) { 
4957     return (certificate
->_permittedSubtrees
); 
4960 CFArrayRef 
SecCertificateGetExcludedSubtrees(SecCertificateRef certificate
) { 
4961     return (certificate
->_excludedSubtrees
); 
4964 const SecCEPolicyConstraints 
* 
4965 SecCertificateGetPolicyConstraints(SecCertificateRef certificate
) { 
4966         if (certificate
->_policyConstraints
.present
) 
4967                 return &certificate
->_policyConstraints
; 
4972 const SecCEPolicyMappings 
* 
4973 SecCertificateGetPolicyMappings(SecCertificateRef certificate
) { 
4974     if (certificate
->_policyMappings
.present
) { 
4975         return &certificate
->_policyMappings
; 
4981 const SecCECertificatePolicies 
* 
4982 SecCertificateGetCertificatePolicies(SecCertificateRef certificate
) { 
4983         if (certificate
->_certificatePolicies
.present
) 
4984                 return &certificate
->_certificatePolicies
; 
4989 const SecCEInhibitAnyPolicy 
* 
4990 SecCertificateGetInhibitAnyPolicySkipCerts(SecCertificateRef certificate
) { 
4991     if (certificate
->_inhibitAnyPolicySkipCerts
.present
) { 
4992         return &certificate
->_inhibitAnyPolicySkipCerts
; 
4998 static OSStatus 
appendNTPrincipalNamesFromGeneralNames(void *context
, 
4999         SecCEGeneralNameType gnType
, const DERItem 
*generalName
) { 
5000         CFMutableArrayRef ntPrincipalNames 
= (CFMutableArrayRef
)context
; 
5001         if (gnType 
== GNT_OtherName
) { 
5003         DERReturn drtn 
= DERParseSequenceContent(generalName
, 
5004             DERNumOtherNameItemSpecs
, DEROtherNameItemSpecs
, 
5006         require_noerr_quiet(drtn
, badDER
); 
5007         if (DEROidCompare(&on
.typeIdentifier
, &oidMSNTPrincipalName
)) { 
5009             require_quiet(string 
= copyDERThingDescription(kCFAllocatorDefault
, 
5010                 &on
.value
, true, true), badDER
); 
5011             CFArrayAppendValue(ntPrincipalNames
, string
); 
5015         return errSecSuccess
; 
5018     return errSecInvalidCertificate
; 
5022 CFArrayRef 
SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate
) { 
5023         CFMutableArrayRef ntPrincipalNames 
= CFArrayCreateMutable(kCFAllocatorDefault
, 
5024                 0, &kCFTypeArrayCallBacks
); 
5025         OSStatus status 
= errSecSuccess
; 
5026         if (certificate
->_subjectAltName
) { 
5027                 status 
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
, 
5028                         ntPrincipalNames
, appendNTPrincipalNamesFromGeneralNames
); 
5030         if (status 
|| CFArrayGetCount(ntPrincipalNames
) == 0) { 
5031                 CFRelease(ntPrincipalNames
); 
5032                 ntPrincipalNames 
= NULL
; 
5034         return ntPrincipalNames
; 
5037 static OSStatus 
appendToRFC2253String(void *context
, 
5038         const DERItem 
*type
, const DERItem 
*value
, CFIndex rdnIX
, bool localized
) { 
5039         CFMutableStringRef string 
= (CFMutableStringRef
)context
; 
5043                     ST      stateOrProvinceName 
5045                     OU      organizationalUnitName 
5047                     STREET  streetAddress 
5051     /* Prepend a + if this is not the first RDN in an RDN set. 
5052        Otherwise prepend a , if this is not the first RDN. */ 
5054         CFStringAppend(string
, CFSTR("+")); 
5055     else if (CFStringGetLength(string
)) { 
5056         CFStringAppend(string
, CFSTR(",")); 
5059     CFStringRef label
, oid 
= NULL
; 
5060     /* @@@ Consider changing this to a dictionary lookup keyed by the 
5061        decimal representation. */ 
5062         if (DEROidCompare(type
, &oidCommonName
)) { 
5063         label 
= CFSTR("CN"); 
5064     } else if (DEROidCompare(type
, &oidLocalityName
)) { 
5066     } else if (DEROidCompare(type
, &oidStateOrProvinceName
)) { 
5067         label 
= CFSTR("ST"); 
5068     } else if (DEROidCompare(type
, &oidOrganizationName
)) { 
5070     } else if (DEROidCompare(type
, &oidOrganizationalUnitName
)) { 
5071         label 
= CFSTR("OU"); 
5072     } else if (DEROidCompare(type
, &oidCountryName
)) { 
5075     } else if (DEROidCompare(type
, &oidStreetAddress
)) { 
5076         label 
= CFSTR("STREET"); 
5077     } else if (DEROidCompare(type
, &oidDomainComponent
)) { 
5078         label 
= CFSTR("DC"); 
5079     } else if (DEROidCompare(type
, &oidUserID
)) { 
5080         label 
= CFSTR("UID"); 
5083         label 
= oid 
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, type
); 
5086     CFStringAppend(string
, label
); 
5087     CFStringAppend(string
, CFSTR("=")); 
5088     CFStringRef raw 
= NULL
; 
5090         raw 
= copyDERThingDescription(kCFAllocatorDefault
, value
, true, localized
); 
5093         /* Append raw to string while escaping: 
5094            a space or "#" character occurring at the beginning of the string 
5095            a space character occurring at the end of the string 
5096            one of the characters ",", "+", """, "\", "<", ">" or ";" 
5098         CFStringInlineBuffer buffer 
= {}; 
5099         CFIndex ix
, length 
= CFStringGetLength(raw
); 
5100         CFRange range 
= { 0, length 
}; 
5101         CFStringInitInlineBuffer(raw
, &buffer
, range
); 
5102         for (ix 
= 0; ix 
< length
; ++ix
) { 
5103             UniChar ch 
= CFStringGetCharacterFromInlineBuffer(&buffer
, ix
); 
5105                 CFStringAppendFormat(string
, NULL
, CFSTR("\\%02X"), ch
); 
5106             } else if (ch 
== ',' || ch 
== '+' || ch 
== '"' || ch 
== '\\' || 
5107                 ch 
== '<' || ch 
== '>' || ch 
== ';' || 
5108                 (ch 
== ' ' && (ix 
== 0 || ix 
== length 
- 1)) || 
5109                 (ch 
== '#' && ix 
== 0)) { 
5110                 UniChar chars
[] = { '\\', ch 
}; 
5111                 CFStringAppendCharacters(string
, chars
, 2); 
5113                 CFStringAppendCharacters(string
, &ch
, 1); 
5118         /* Append the value in hex. */ 
5119         CFStringAppend(string
, CFSTR("#")); 
5121         for (ix 
= 0; ix 
< value
->length
; ++ix
) 
5122             CFStringAppendFormat(string
, NULL
, CFSTR("%02X"), value
->data
[ix
]); 
5127         return errSecSuccess
; 
5130 CFStringRef 
SecCertificateCopySubjectString(SecCertificateRef certificate
) { 
5131         CFMutableStringRef string 
= CFStringCreateMutable(kCFAllocatorDefault
, 0); 
5132         OSStatus status 
= parseX501NameContent(&certificate
->_subject
, string
, appendToRFC2253String
, true); 
5133         if (status 
|| CFStringGetLength(string
) == 0) { 
5140 static OSStatus 
appendToCompanyNameString(void *context
, 
5141         const DERItem 
*type
, const DERItem 
*value
, CFIndex rdnIX
, bool localized
) { 
5142         CFMutableStringRef string 
= (CFMutableStringRef
)context
; 
5143     if (CFStringGetLength(string
) != 0) 
5144         return errSecSuccess
; 
5146     if (!DEROidCompare(type
, &oidOrganizationName
)) 
5147         return errSecSuccess
; 
5150     raw 
= copyDERThingDescription(kCFAllocatorDefault
, value
, true, localized
); 
5152         return errSecSuccess
; 
5153     CFStringAppend(string
, raw
); 
5156         return errSecSuccess
; 
5159 CFStringRef 
SecCertificateCopyCompanyName(SecCertificateRef certificate
) { 
5160         CFMutableStringRef string 
= CFStringCreateMutable(kCFAllocatorDefault
, 0); 
5161         OSStatus status 
= parseX501NameContent(&certificate
->_subject
, string
, 
5162         appendToCompanyNameString
, true); 
5163         if (status 
|| CFStringGetLength(string
) == 0) { 
5170 CFDataRef 
SecCertificateCopyIssuerSequence( 
5171     SecCertificateRef certificate
) { 
5172     return SecDERItemCopySequence(&certificate
->_issuer
); 
5175 CFDataRef 
SecCertificateCopySubjectSequence( 
5176     SecCertificateRef certificate
) { 
5177     return SecDERItemCopySequence(&certificate
->_subject
); 
5180 CFDataRef 
SecCertificateCopyNormalizedIssuerSequence(SecCertificateRef certificate
) { 
5181     if (!certificate 
|| !certificate
->_normalizedIssuer
) { 
5184     return SecCopySequenceFromContent(certificate
->_normalizedIssuer
); 
5187 CFDataRef 
SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certificate
) { 
5188     if (!certificate 
|| !certificate
->_normalizedSubject
) { 
5191     return SecCopySequenceFromContent(certificate
->_normalizedSubject
); 
5194 const DERAlgorithmId 
*SecCertificateGetPublicKeyAlgorithm( 
5195         SecCertificateRef certificate
) { 
5196         return &certificate
->_algId
; 
5199 const DERItem 
*SecCertificateGetPublicKeyData(SecCertificateRef certificate
) { 
5200         return &certificate
->_pubKeyDER
; 
5204 /* There is already a SecCertificateCopyPublicKey with different args on OS X, 
5205    so we will refer to this one internally as SecCertificateCopyPublicKey_ios. 
5207 __nullable SecKeyRef 
SecCertificateCopyPublicKey_ios(SecCertificateRef certificate
) 
5209 __nullable SecKeyRef 
SecCertificateCopyPublicKey(SecCertificateRef certificate
) 
5212     return SecCertificateCopyKey(certificate
); 
5215 SecKeyRef 
SecCertificateCopyKey(SecCertificateRef certificate
) { 
5216     if (certificate
->_pubKey 
== NULL
) { 
5217         const DERAlgorithmId 
*algId 
= 
5218         SecCertificateGetPublicKeyAlgorithm(certificate
); 
5219         const DERItem 
*keyData 
= SecCertificateGetPublicKeyData(certificate
); 
5220         const DERItem 
*params 
= NULL
; 
5221         if (algId
->params
.length 
!= 0) { 
5222             params 
= &algId
->params
; 
5224         SecAsn1Oid oid1 
= { .Data 
= algId
->oid
.data
, .Length 
= algId
->oid
.length 
}; 
5225         SecAsn1Item params1 
= { 
5226             .Data 
= params 
? params
->data 
: NULL
, 
5227             .Length 
= params 
? params
->length 
: 0 
5229         SecAsn1Item keyData1 
= { 
5230             .Data 
= keyData 
? keyData
->data 
: NULL
, 
5231             .Length 
= keyData 
? keyData
->length 
: 0 
5233         certificate
->_pubKey 
= SecKeyCreatePublicFromDER(kCFAllocatorDefault
, &oid1
, ¶ms1
, 
5237     return CFRetainSafe(certificate
->_pubKey
); 
5240 static CFIndex 
SecCertificateGetPublicKeyAlgorithmIdAndSize(SecCertificateRef certificate
, size_t *keySizeInBytes
) { 
5241     CFIndex keyAlgID 
= kSecNullAlgorithmID
; 
5244     SecKeyRef pubKey 
= NULL
; 
5245     require_quiet(certificate
, out
); 
5246     require_quiet(pubKey 
= SecCertificateCopyKey(certificate
) ,out
); 
5247     size 
= SecKeyGetBlockSize(pubKey
); 
5248     keyAlgID 
= SecKeyGetAlgorithmId(pubKey
); 
5251     CFReleaseNull(pubKey
); 
5252     if (keySizeInBytes
) { *keySizeInBytes 
= size
; } 
5257  * Public keys in certificates may be considered "weak" or "strong" or neither 
5258  * (that is, in between). Certificates using weak keys are not trusted at all. 
5259  * Certificates using neither strong nor weak keys are only trusted in certain 
5260  * contexts. SecPolicy and SecPolicyServer define the contexts by which we enforce 
5261  * these (or stronger) key size trust policies. 
5263 bool SecCertificateIsWeakKey(SecCertificateRef certificate
) { 
5264     if (!certificate
) { return true; } 
5268     switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) { 
5269         case kSecRSAAlgorithmID
: 
5270             if (MIN_RSA_KEY_SIZE 
<= size
) weak 
= false; 
5272         case kSecECDSAAlgorithmID
: 
5273             if (MIN_EC_KEY_SIZE 
<= size
) weak 
= false; 
5281 bool SecCertificateIsStrongKey(SecCertificateRef certificate
) { 
5282     if (!certificate
) { return false; } 
5284     bool strong 
= false; 
5286     switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) { 
5287         case kSecRSAAlgorithmID
: 
5288             if (MIN_STRONG_RSA_KEY_SIZE 
<= size
) strong 
= true; 
5290         case kSecECDSAAlgorithmID
: 
5291             if (MIN_STRONG_EC_KEY_SIZE 
<= size
) strong 
= true; 
5299 bool SecCertificateIsWeakHash(SecCertificateRef certificate
) { 
5300     if (!certificate
) { return true; } 
5301     SecSignatureHashAlgorithm certAlg 
= 0; 
5302     certAlg 
= SecCertificateGetSignatureHashAlgorithm(certificate
); 
5303     if (certAlg 
== kSecSignatureHashAlgorithmUnknown 
|| 
5304         certAlg 
== kSecSignatureHashAlgorithmMD2 
|| 
5305         certAlg 
== kSecSignatureHashAlgorithmMD4 
|| 
5306         certAlg 
== kSecSignatureHashAlgorithmMD5 
|| 
5307         certAlg 
== kSecSignatureHashAlgorithmSHA1
) { 
5313 bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate
, 
5314                                        CFDictionaryRef keySizes
) { 
5315     if (!certificate
) { return false; } 
5317     bool goodSize 
= false; 
5319     CFNumberRef minSize
; 
5320     size_t minSizeInBits
; 
5321     switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) { 
5322         case kSecRSAAlgorithmID
: 
5323             if(CFDictionaryGetValueIfPresent(keySizes
, kSecAttrKeyTypeRSA
, (const void**)&minSize
) 
5324                && minSize 
&& CFNumberGetValue(minSize
, kCFNumberLongType
, &minSizeInBits
)) { 
5325                 if (size 
>= (size_t)(minSizeInBits
+7)/8) goodSize 
= true; 
5328         case kSecECDSAAlgorithmID
: 
5329             if(CFDictionaryGetValueIfPresent(keySizes
, kSecAttrKeyTypeEC
, (const void**)&minSize
) 
5330                && minSize 
&& CFNumberGetValue(minSize
, kCFNumberLongType
, &minSizeInBits
)) { 
5331                 if (size 
>= (size_t)(minSizeInBits
+7)/8) goodSize 
= true; 
5340 CFDataRef 
SecCertificateGetSHA1Digest(SecCertificateRef certificate
) { 
5341     if (!certificate 
|| !certificate
->_der
.data
) { 
5344     if (!certificate
->_sha1Digest
) { 
5345         certificate
->_sha1Digest 
= 
5346             SecSHA1DigestCreate(CFGetAllocator(certificate
), 
5347                 certificate
->_der
.data
, certificate
->_der
.length
); 
5349     return certificate
->_sha1Digest
; 
5352 CFDataRef 
SecCertificateCopySHA256Digest(SecCertificateRef certificate
) { 
5353     if (!certificate 
|| !certificate
->_der
.data
) { 
5356     return SecSHA256DigestCreate(CFGetAllocator(certificate
), 
5357                                  certificate
->_der
.data
, certificate
->_der
.length
); 
5360 CFDataRef 
SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate
) { 
5361     CFDataRef digest 
= NULL
; 
5362     CFDataRef issuer 
= SecCertificateCopyIssuerSequence(certificate
); 
5364         digest 
= SecSHA1DigestCreate(kCFAllocatorDefault
, 
5365             CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
)); 
5371 CFDataRef 
SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate
) { 
5372     if (!certificate 
|| !certificate
->_pubKeyDER
.data
) { 
5375     return SecSHA1DigestCreate(CFGetAllocator(certificate
), 
5376         certificate
->_pubKeyDER
.data
, certificate
->_pubKeyDER
.length
); 
5379 static CFDataRef 
SecCertificateCopySPKIEncoded(SecCertificateRef certificate
) { 
5380     /* SPKI is saved without the tag/length by libDER, so we need to re-encode */ 
5381     if (!certificate 
|| !certificate
->_subjectPublicKeyInfo
.data
) { 
5384     DERSize size 
= DERLengthOfItem(ASN1_CONSTR_SEQUENCE
, certificate
->_subjectPublicKeyInfo
.length
); 
5385     if (size 
< certificate
->_subjectPublicKeyInfo
.length
) { 
5388     uint8_t *temp 
= malloc(size
); 
5392     DERReturn drtn 
= DEREncodeItem(ASN1_CONSTR_SEQUENCE
, 
5393                                    certificate
->_subjectPublicKeyInfo
.length
, 
5394                                    certificate
->_subjectPublicKeyInfo
.data
, 
5396     CFDataRef encodedSPKI 
= NULL
; 
5397     if (drtn 
== DR_Success
) { 
5398         encodedSPKI 
= CFDataCreate(NULL
, temp
, size
); 
5404 CFDataRef 
SecCertificateCopySubjectPublicKeyInfoSHA1Digest(SecCertificateRef certificate
) { 
5405     CFDataRef encodedSPKI 
= SecCertificateCopySPKIEncoded(certificate
); 
5406     if (!encodedSPKI
) { return NULL
; } 
5407     CFDataRef hash 
= SecSHA1DigestCreate(CFGetAllocator(certificate
), 
5408                                          CFDataGetBytePtr(encodedSPKI
), 
5409                                          CFDataGetLength(encodedSPKI
)); 
5410     CFReleaseNull(encodedSPKI
); 
5414 CFDataRef 
SecCertificateCopySubjectPublicKeyInfoSHA256Digest(SecCertificateRef certificate
) { 
5415     CFDataRef encodedSPKI 
= SecCertificateCopySPKIEncoded(certificate
); 
5416     if (!encodedSPKI
) { return NULL
; } 
5417     CFDataRef hash 
= SecSHA256DigestCreate(CFGetAllocator(certificate
), 
5418                                            CFDataGetBytePtr(encodedSPKI
), 
5419                                            CFDataGetLength(encodedSPKI
)); 
5420     CFReleaseNull(encodedSPKI
); 
5424 CFTypeRef 
SecCertificateCopyKeychainItem(SecCertificateRef certificate
) 
5429         CFRetainSafe(certificate
->_keychain_item
); 
5430         return certificate
->_keychain_item
; 
5433 CFDataRef 
SecCertificateGetAuthorityKeyID(SecCertificateRef certificate
) { 
5437         if (!certificate
->_authorityKeyID 
&& 
5438                 certificate
->_authorityKeyIdentifier
.length
) { 
5439                 certificate
->_authorityKeyID 
= CFDataCreate(kCFAllocatorDefault
, 
5440                         certificate
->_authorityKeyIdentifier
.data
, 
5441                         certificate
->_authorityKeyIdentifier
.length
); 
5444     return certificate
->_authorityKeyID
; 
5447 CFDataRef 
SecCertificateGetSubjectKeyID(SecCertificateRef certificate
) { 
5451         if (!certificate
->_subjectKeyID 
&& 
5452                 certificate
->_subjectKeyIdentifier
.length
) { 
5453                 certificate
->_subjectKeyID 
= CFDataCreate(kCFAllocatorDefault
, 
5454                         certificate
->_subjectKeyIdentifier
.data
, 
5455                         certificate
->_subjectKeyIdentifier
.length
); 
5458     return certificate
->_subjectKeyID
; 
5461 CFArrayRef 
SecCertificateGetCRLDistributionPoints(SecCertificateRef certificate
) { 
5465     return certificate
->_crlDistributionPoints
; 
5468 CFArrayRef 
SecCertificateGetOCSPResponders(SecCertificateRef certificate
) { 
5472     return certificate
->_ocspResponders
; 
5475 CFArrayRef 
SecCertificateGetCAIssuers(SecCertificateRef certificate
) { 
5479     return certificate
->_caIssuers
; 
5482 bool SecCertificateHasCriticalSubjectAltName(SecCertificateRef certificate
) { 
5486     return certificate
->_subjectAltName 
&& 
5487         certificate
->_subjectAltName
->critical
; 
5490 bool SecCertificateHasSubject(SecCertificateRef certificate
) { 
5494         /* Since the _subject field is the content of the subject and not the 
5495            whole thing, we can simply check for a 0 length subject here. */ 
5496         return certificate
->_subject
.length 
!= 0; 
5499 bool SecCertificateHasUnknownCriticalExtension(SecCertificateRef certificate
) { 
5503     return certificate
->_foundUnknownCriticalExtension
; 
5506 /* Private API functions. */ 
5507 void SecCertificateShow(SecCertificateRef certificate
) { 
5509         fprintf(stderr
, "SecCertificate instance %p:\n", certificate
); 
5510                 fprintf(stderr
, "\n"); 
5514 CFDictionaryRef 
SecCertificateCopyAttributeDictionary( 
5515         SecCertificateRef certificate
) { 
5516         if (!certificate 
|| !(CFGetTypeID(certificate
) == SecCertificateGetTypeID())) { 
5519         CFAllocatorRef allocator 
= CFGetAllocator(certificate
); 
5520         CFNumberRef certificateType 
= NULL
; 
5521         CFNumberRef certificateEncoding 
= NULL
; 
5522         CFStringRef label 
= NULL
; 
5523         CFStringRef alias 
= NULL
; 
5524         CFDataRef skid 
= NULL
; 
5525         CFDataRef pubKeyDigest 
= NULL
; 
5526         CFDataRef certData 
= NULL
; 
5527         CFDictionaryRef dict 
= NULL
; 
5531         /* CSSM_CERT_X_509v1, CSSM_CERT_X_509v2 or CSSM_CERT_X_509v3 */ 
5532         SInt32 ctv 
= certificate
->_version 
+ 1; 
5533         SInt32 cev 
= 3; /* CSSM_CERT_ENCODING_DER */ 
5534         certificateType 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &ctv
); 
5535         require_quiet(certificateType 
!= NULL
, out
); 
5536         certificateEncoding 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &cev
); 
5537         require_quiet(certificateEncoding 
!= NULL
, out
); 
5538         certData 
= SecCertificateCopyData(certificate
); 
5539         require_quiet(certData 
!= NULL
, out
); 
5540         skid 
= SecCertificateGetSubjectKeyID(certificate
); 
5541         require_quiet(certificate
->_pubKeyDER
.data 
!= NULL 
&& certificate
->_pubKeyDER
.length 
> 0, out
); 
5542         pubKeyDigest 
= SecSHA1DigestCreate(allocator
, certificate
->_pubKeyDER
.data
, 
5543                 certificate
->_pubKeyDER
.length
); 
5544         require_quiet(pubKeyDigest 
!= NULL
, out
); 
5546         /* We still need to figure out how to deal with multi valued attributes. */ 
5547         alias 
= SecCertificateCopyRFC822Names(certificate
); 
5548         label 
= SecCertificateCopySubjectSummary(certificate
); 
5554         DICT_ADDPAIR(kSecClass
, kSecClassCertificate
); 
5555         DICT_ADDPAIR(kSecAttrCertificateType
, certificateType
); 
5556         DICT_ADDPAIR(kSecAttrCertificateEncoding
, certificateEncoding
); 
5558                 DICT_ADDPAIR(kSecAttrLabel
, label
); 
5561                 DICT_ADDPAIR(kSecAttrAlias
, alias
); 
5563         if (isData(certificate
->_normalizedSubject
)) { 
5564                 DICT_ADDPAIR(kSecAttrSubject
, certificate
->_normalizedSubject
); 
5566         require_quiet(isData(certificate
->_normalizedIssuer
), out
); 
5567         DICT_ADDPAIR(kSecAttrIssuer
, certificate
->_normalizedIssuer
); 
5568         require_quiet(isData(certificate
->_serialNumber
), out
); 
5569         DICT_ADDPAIR(kSecAttrSerialNumber
, certificate
->_serialNumber
); 
5571                 DICT_ADDPAIR(kSecAttrSubjectKeyID
, skid
); 
5573         DICT_ADDPAIR(kSecAttrPublicKeyHash
, pubKeyDigest
); 
5574         DICT_ADDPAIR(kSecValueData
, certData
); 
5575         dict 
= DICT_CREATE(allocator
); 
5578         CFReleaseSafe(label
); 
5579         CFReleaseSafe(alias
); 
5580         CFReleaseSafe(pubKeyDigest
); 
5581         CFReleaseSafe(certData
); 
5582         CFReleaseSafe(certificateEncoding
); 
5583         CFReleaseSafe(certificateType
); 
5588 SecCertificateRef 
SecCertificateCreateFromAttributeDictionary( 
5589         CFDictionaryRef refAttributes
) { 
5590         /* @@@ Support having an allocator in refAttributes. */ 
5591         CFAllocatorRef allocator 
= NULL
; 
5592         CFDataRef data 
= CFDictionaryGetValue(refAttributes
, kSecValueData
); 
5593         return data 
? SecCertificateCreateWithData(allocator
, data
) : NULL
; 
5597 static bool _SecCertificateIsSelfSigned(SecCertificateRef certificate
) { 
5598     if (certificate
->_isSelfSigned 
== kSecSelfSignedUnknown
) { 
5599         certificate
->_isSelfSigned 
= kSecSelfSignedFalse
; 
5600         SecKeyRef publicKey 
= NULL
; 
5601         require(certificate 
&& (CFGetTypeID(certificate
) == SecCertificateGetTypeID()), out
); 
5602         require(publicKey 
= SecCertificateCopyKey(certificate
), out
); 
5603         CFDataRef normalizedIssuer 
= 
5604         SecCertificateGetNormalizedIssuerContent(certificate
); 
5605         CFDataRef normalizedSubject 
= 
5606         SecCertificateGetNormalizedSubjectContent(certificate
); 
5607         require_quiet(normalizedIssuer 
&& normalizedSubject 
&& 
5608                       CFEqual(normalizedIssuer
, normalizedSubject
), out
); 
5610         CFDataRef authorityKeyID 
= SecCertificateGetAuthorityKeyID(certificate
); 
5611         CFDataRef subjectKeyID 
= SecCertificateGetSubjectKeyID(certificate
); 
5612         if (authorityKeyID
) { 
5613             require_quiet(subjectKeyID 
&& CFEqual(subjectKeyID
, authorityKeyID
), out
); 
5616         require_noerr_quiet(SecCertificateIsSignedBy(certificate
, publicKey
), out
); 
5618         certificate
->_isSelfSigned 
= kSecSelfSignedTrue
; 
5620         CFReleaseSafe(publicKey
); 
5623     return (certificate
->_isSelfSigned 
== kSecSelfSignedTrue
); 
5626 bool SecCertificateIsCA(SecCertificateRef certificate
) { 
5627     bool result 
= false; 
5628     require(certificate 
&& (CFGetTypeID(certificate
) == SecCertificateGetTypeID()), out
); 
5629     if (SecCertificateVersion(certificate
) >= 3) { 
5630         const SecCEBasicConstraints 
*basicConstraints 
= SecCertificateGetBasicConstraints(certificate
); 
5631         result 
= (basicConstraints 
&& basicConstraints
->isCA
); 
5634         result 
= _SecCertificateIsSelfSigned(certificate
); 
5640 bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate
) { 
5641     return (_SecCertificateIsSelfSigned(certificate
) && SecCertificateIsCA(certificate
)); 
5644 OSStatus 
SecCertificateIsSelfSigned(SecCertificateRef certificate
, Boolean 
*isSelfSigned
) { 
5645     if (!certificate 
|| (CFGetTypeID(certificate
) != SecCertificateGetTypeID())) { 
5646         return errSecInvalidCertificate
; 
5648     if (!isSelfSigned
) { 
5651     *isSelfSigned 
= _SecCertificateIsSelfSigned(certificate
); 
5652     return errSecSuccess
; 
5655 SecKeyUsage 
SecCertificateGetKeyUsage(SecCertificateRef certificate
) { 
5657         return kSecKeyUsageUnspecified
; 
5659     return certificate
->_keyUsage
; 
5662 CFArrayRef 
SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate
) 
5664     CFMutableArrayRef extended_key_usage_oids 
= 
5665         CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
5666     require_quiet(certificate 
&& extended_key_usage_oids
, out
); 
5668     for (ix 
= 0; ix 
< certificate
->_extensionCount
; ++ix
) { 
5669         const SecCertificateExtension 
*extn 
= &certificate
->_extensions
[ix
]; 
5670         if (extn
->extnID
.length 
== oidExtendedKeyUsage
.length 
&& 
5671             !memcmp(extn
->extnID
.data
, oidExtendedKeyUsage
.data
, extn
->extnID
.length
)) { 
5674             DERReturn drtn 
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &derSeq
); 
5675             require_noerr_quiet(drtn
, out
); 
5676             require_quiet(tag 
== ASN1_CONSTR_SEQUENCE
, out
); 
5677             DERDecodedInfo currDecoded
; 
5679             while ((drtn 
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) { 
5680                 require_quiet(currDecoded
.tag 
== ASN1_OBJECT_ID
, out
); 
5681                 CFDataRef oid 
= CFDataCreate(kCFAllocatorDefault
, 
5682                     currDecoded
.content
.data
, currDecoded
.content
.length
); 
5683                 require_quiet(oid
, out
); 
5684                 CFArrayAppendValue(extended_key_usage_oids
, oid
); 
5687             require_quiet(drtn 
== DR_EndOfSequence
, out
); 
5688             return extended_key_usage_oids
; 
5692     CFReleaseSafe(extended_key_usage_oids
); 
5696 CFArrayRef 
SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate
) 
5698     require_quiet(certificate
, out
); 
5701     for (ix 
= 0; ix 
< certificate
->_extensionCount
; ++ix
) { 
5702         const SecCertificateExtension 
*extn 
= &certificate
->_extensions
[ix
]; 
5703         if (extn
->extnID
.length 
== oidGoogleEmbeddedSignedCertificateTimestamp
.length 
&& 
5704             !memcmp(extn
->extnID
.data
, oidGoogleEmbeddedSignedCertificateTimestamp
.data
, extn
->extnID
.length
)) { 
5705             /* Got the SCT oid */ 
5706             DERDecodedInfo sctList
; 
5707             DERReturn drtn 
= DERDecodeItem(&extn
->extnValue
, &sctList
); 
5708             require_noerr_quiet(drtn
, out
); 
5709             require_quiet(sctList
.tag 
== ASN1_OCTET_STRING
, out
); 
5710             return SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sctList
.content
.data
, sctList
.content
.length
); 
5718 static bool matches_expected(DERItem der
, CFTypeRef expected
) { 
5719     if (der
.length 
> 1) { 
5720         DERDecodedInfo decoded
; 
5721         DERDecodeItem(&der
, &decoded
); 
5722         switch (decoded
.tag
) { 
5725                 return decoded
.content
.length 
== 0 && expected 
== NULL
; 
5729             case ASN1_IA5_STRING
: 
5730             case ASN1_UTF8_STRING
: { 
5731                 if (isString(expected
)) { 
5732                     CFStringRef expectedString 
= (CFStringRef
) expected
; 
5733                     CFStringRef itemString 
= CFStringCreateWithBytesNoCopy(kCFAllocatorDefault
, decoded
.content
.data
, decoded
.content
.length
, kCFStringEncodingUTF8
, false, kCFAllocatorNull
); 
5735                     bool result 
= (kCFCompareEqualTo 
== CFStringCompare(expectedString
, itemString
, 0)); 
5736                     CFReleaseNull(itemString
); 
5742             case ASN1_OCTET_STRING
: { 
5743                 if (isData(expected
)) { 
5744                     CFDataRef expectedData 
= (CFDataRef
) expected
; 
5745                     CFDataRef itemData 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, decoded
.content
.data
, decoded
.content
.length
, kCFAllocatorNull
); 
5747                     bool result 
= CFEqual(expectedData
, itemData
); 
5748                     CFReleaseNull(itemData
); 
5754             case ASN1_INTEGER
: { 
5755                 SInt32 expected_value 
= 0; 
5756                 if (isString(expected
)) 
5758                     CFStringRef aStr 
= (CFStringRef
)expected
; 
5759                     expected_value 
= CFStringGetIntValue(aStr
); 
5761                 else if (isNumber(expected
)) 
5763                     CFNumberGetValue(expected
, kCFNumberSInt32Type
, &expected_value
); 
5766                 uint32_t num_value 
= 0; 
5767                 if (!DERParseInteger(&decoded
.content
, &num_value
)) 
5769                     return ((uint32_t)expected_value 
== num_value
); 
5782 static bool cert_contains_marker_extension_value(SecCertificateRef certificate
, CFDataRef oid
, CFTypeRef expectedValue
) 
5785     const uint8_t *oid_data 
= CFDataGetBytePtr(oid
); 
5786     size_t oid_len 
= CFDataGetLength(oid
); 
5788     for (ix 
= 0; ix 
< certificate
->_extensionCount
; ++ix
) { 
5789         const SecCertificateExtension 
*extn 
= &certificate
->_extensions
[ix
]; 
5790         if (extn
->extnID
.length 
== oid_len
 
5791             && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
)) 
5793                         return matches_expected(extn
->extnValue
, expectedValue
); 
5799 static bool cert_contains_marker_extension(SecCertificateRef certificate
, CFTypeRef oid
) 
5801     return cert_contains_marker_extension_value(certificate
, oid
, NULL
); 
5804 struct search_context 
{ 
5806     SecCertificateRef certificate
; 
5809 static bool GetDecimalValueOfString(CFStringRef string
, uint32_t* value
) 
5811     CFCharacterSetRef nonDecimalDigit 
= CFCharacterSetCreateInvertedSet(NULL
, CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
)); 
5812     bool result 
= false; 
5814     if ( CFStringGetLength(string
) > 0 
5815       && !CFStringFindCharacterFromSet(string
, nonDecimalDigit
, CFRangeMake(0, CFStringGetLength(string
)), kCFCompareForcedOrdering
, NULL
)) 
5818             *value 
= CFStringGetIntValue(string
); 
5822     CFReleaseNull(nonDecimalDigit
); 
5827 bool SecCertificateIsOidString(CFStringRef oid
) 
5829     if (!oid
) return false; 
5830     if (2 >= CFStringGetLength(oid
)) return false; 
5833     /* oid string only has the allowed characters */ 
5834     CFCharacterSetRef decimalOid 
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("0123456789.")); 
5835     CFCharacterSetRef nonDecimalOid 
= CFCharacterSetCreateInvertedSet(NULL
, decimalOid
); 
5836     if (CFStringFindCharacterFromSet(oid
, nonDecimalOid
, CFRangeMake(0, CFStringGetLength(oid
)), kCFCompareForcedOrdering
, NULL
)) { 
5840     /* first arc is allowed */ 
5841     UniChar firstArc
[2]; 
5842     CFRange firstTwo 
= {0, 2}; 
5843     CFStringGetCharacters(oid
, firstTwo
, firstArc
); 
5844     if (firstArc
[1] != '.' || 
5845         (firstArc
[0] != '0' && firstArc
[0] != '1' && firstArc
[0] != '2')) { 
5849     CFReleaseNull(decimalOid
); 
5850     CFReleaseNull(nonDecimalOid
); 
5855 CFDataRef 
SecCertificateCreateOidDataFromString(CFAllocatorRef allocator
, CFStringRef string
) 
5857     CFMutableDataRef currentResult 
= NULL
; 
5858     CFDataRef encodedResult 
= NULL
; 
5860     CFArrayRef parts 
= NULL
; 
5863     if (!string 
|| !SecCertificateIsOidString(string
)) 
5866     parts 
= CFStringCreateArrayBySeparatingStrings(NULL
, string
, CFSTR(".")); 
5871     count 
= CFArrayGetCount(parts
); 
5875     // assume no more than 5 bytes needed to represent any part of the oid, 
5876     // since we limit parts to 32-bit values, 
5877     // but the first two parts only need 1 byte 
5878     currentResult 
= CFDataCreateMutable(allocator
, 1+(count
-2)*5); 
5884     part 
= CFArrayGetValueAtIndex(parts
, 0); 
5886     if (!GetDecimalValueOfString(part
, &x
) || x 
> 6) 
5893         part 
= CFArrayGetValueAtIndex(parts
, 1); 
5895         if (!GetDecimalValueOfString(part
, &x
) || x 
> 39) 
5901     CFDataAppendBytes(currentResult
, &firstByte
, 1); 
5903     for (CFIndex i 
= 2; i 
< count 
&& GetDecimalValueOfString(CFArrayGetValueAtIndex(parts
, i
), &x
); ++i
) { 
5904         uint8_t b
[5] = {0, 0, 0, 0, 0}; 
5906         b
[3] = 0x80 | ((x 
>> 7) & 0x7F); 
5907         b
[2] = 0x80 | ((x 
>> 14) & 0x7F); 
5908         b
[1] = 0x80 | ((x 
>> 21) & 0x7F); 
5909         b
[0] = 0x80 | ((x 
>> 28) & 0x7F); 
5911         // Skip the unused extension bytes. 
5912         size_t skipBytes 
= 0; 
5913         while (b
[skipBytes
] == 0x80) 
5916         CFDataAppendBytes(currentResult
, b 
+ skipBytes
, sizeof(b
) - skipBytes
); 
5919     encodedResult 
= currentResult
; 
5920     currentResult 
= NULL
; 
5923     CFReleaseNull(parts
); 
5924     CFReleaseNull(currentResult
); 
5926     return encodedResult
; 
5929 static void check_for_marker(const void *key
, const void *value
, void *context
) 
5931     struct search_context 
* search_ctx 
= (struct search_context 
*) context
; 
5932     CFStringRef key_string 
= (CFStringRef
) key
; 
5933     CFTypeRef value_ref 
= (CFTypeRef
) value
; 
5935     // If we could have short circuted the iteration 
5936     // we would have, but the best we can do 
5937     // is not waste time comparing once a match 
5939     if (search_ctx
->found
) 
5942     if (CFGetTypeID(key_string
) != CFStringGetTypeID()) 
5945     CFDataRef key_data 
= SecCertificateCreateOidDataFromString(NULL
, key_string
); 
5947     if (NULL 
== key_data
) 
5950     if (cert_contains_marker_extension_value(search_ctx
->certificate
, key_data
, value_ref
)) 
5951         search_ctx
->found 
= true; 
5953     CFReleaseNull(key_data
); 
5957 // CFType Ref is either: 
5959 // CFData - OID to match with no data permitted 
5960 // CFString - decimal OID to match 
5961 // CFDictionary - OID -> Value table for expected values Single Object or Array 
5962 // CFArray - Array of the above. 
5964 // This returns true if any of the requirements are met. 
5965 bool SecCertificateHasMarkerExtension(SecCertificateRef certificate
, CFTypeRef oids
) 
5967     if (CFGetTypeID(oids
) == CFArrayGetTypeID()) { 
5968         CFIndex ix
, length 
= CFArrayGetCount(oids
); 
5969         for (ix 
= 0; ix 
< length
; ix
++) 
5970             if (SecCertificateHasMarkerExtension(certificate
, CFArrayGetValueAtIndex((CFArrayRef
)oids
, ix
))) 
5972     } else if (CFGetTypeID(oids
) == CFDictionaryGetTypeID()) { 
5973         struct search_context context 
= { .found 
= false, .certificate 
= certificate 
}; 
5974         CFDictionaryApplyFunction((CFDictionaryRef
) oids
, &check_for_marker
, &context
); 
5975         return context
.found
; 
5976     } else if (CFGetTypeID(oids
) == CFDataGetTypeID()) { 
5977         return cert_contains_marker_extension(certificate
, oids
); 
5978     } else if (CFGetTypeID(oids
) == CFStringGetTypeID()) { 
5979         CFDataRef dataOid 
= SecCertificateCreateOidDataFromString(NULL
, oids
); 
5980         if (dataOid 
== NULL
) return false; 
5981         bool result 
= cert_contains_marker_extension(certificate
, dataOid
); 
5982         CFReleaseNull(dataOid
); 
5988 static DERItem 
*cert_extension_value_for_marker(SecCertificateRef certificate
, CFDataRef oid
) { 
5990     const uint8_t *oid_data 
= CFDataGetBytePtr(oid
); 
5991     size_t oid_len 
= CFDataGetLength(oid
); 
5993     for (ix 
= 0; ix 
< certificate
->_extensionCount
; ++ix
) { 
5994         const SecCertificateExtension 
*extn 
= &certificate
->_extensions
[ix
]; 
5995         if (extn
->extnID
.length 
== oid_len
 
5996             && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
)) 
5998             return (DERItem 
*)&extn
->extnValue
; 
6005 // CFType Ref is either: 
6007 // CFData - OID to match with no data permitted 
6008 // CFString - decimal OID to match 
6010 DERItem 
*SecCertificateGetExtensionValue(SecCertificateRef certificate
, CFTypeRef oid
) { 
6011     if (!certificate 
|| !oid
) { 
6015     if(CFGetTypeID(oid
) == CFDataGetTypeID()) { 
6016         return cert_extension_value_for_marker(certificate
, oid
); 
6017     } else if (CFGetTypeID(oid
) == CFStringGetTypeID()) { 
6018         CFDataRef dataOid 
= SecCertificateCreateOidDataFromString(NULL
, oid
); 
6019         if (dataOid 
== NULL
) return NULL
; 
6020         DERItem 
*result 
= cert_extension_value_for_marker(certificate
, dataOid
); 
6021         CFReleaseNull(dataOid
); 
6028 CFDataRef 
SecCertificateCopyExtensionValue(SecCertificateRef certificate
, CFTypeRef extensionOID
, bool *isCritical
) { 
6029     if (!certificate 
|| !extensionOID
) { 
6033     CFDataRef oid 
= NULL
, extensionValue 
= NULL
; 
6034     if (CFGetTypeID(extensionOID
) == CFDataGetTypeID()) { 
6035         oid 
= CFRetainSafe(extensionOID
); 
6036     } else if (CFGetTypeID(extensionOID
) == CFStringGetTypeID()) { 
6037         oid 
= SecCertificateCreateOidDataFromString(NULL
, extensionOID
); 
6044     const uint8_t *oid_data 
= CFDataGetBytePtr(oid
); 
6045     size_t oid_len 
= CFDataGetLength(oid
); 
6047     for (ix 
= 0; ix 
< certificate
->_extensionCount
; ++ix
) { 
6048         const SecCertificateExtension 
*extn 
= &certificate
->_extensions
[ix
]; 
6049         if (extn
->extnID
.length 
== oid_len
 
6050             && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
)) 
6053                 *isCritical 
= extn
->critical
; 
6055             extensionValue 
= CFDataCreate(NULL
, extn
->extnValue
.data
, extn
->extnValue
.length
); 
6061     return extensionValue
; 
6064 CFDataRef 
SecCertificateCopyiAPAuthCapabilities(SecCertificateRef certificate
) { 
6068     CFDataRef extensionData 
= NULL
; 
6069     DERItem 
*extensionValue 
= NULL
; 
6070     extensionValue 
= SecCertificateGetExtensionValue(certificate
, 
6071                                                      CFSTR("1.2.840.113635.100.6.36")); 
6072     require_quiet(extensionValue
, out
); 
6073     /* The extension is a octet string containing the DER-encoded 32-byte octet string */ 
6074     require_quiet(extensionValue
->length 
== 34, out
); 
6075     DERDecodedInfo decodedValue
; 
6076     require_noerr_quiet(DERDecodeItem(extensionValue
, &decodedValue
), out
); 
6077     if (decodedValue
.tag 
== ASN1_OCTET_STRING
) { 
6078         require_quiet(decodedValue
.content
.length 
== 32, out
); 
6079         extensionData 
= CFDataCreate(NULL
, decodedValue
.content
.data
, 
6080                                      decodedValue
.content
.length
); 
6082         require_quiet(extensionValue
->data
[33] == 0x00 && 
6083                       extensionValue
->data
[32] == 0x00, out
); 
6084         extensionData 
= CFDataCreate(NULL
, extensionValue
->data
, 32); 
6087     return extensionData
; 
6091 /* From iapd IAPAuthenticationTypes.h */ 
6092 typedef struct  IapCertSerialNumber
 
6094     uint8_t   xservID
;            // Xserver ID 
6095     uint8_t   hsmID
;              // Hardware security module ID (generated cert) 
6096     uint8_t   delimiter01
;        // Field delimiter (IAP_CERT_FIELD_DELIMITER) 
6097     uint8_t   dateYear
;           // Date year  cert was issued 
6098     uint8_t   dateMonth
;          // Date month cert was issued 
6099     uint8_t   dateDay
;            // Date day   cert was issued 
6100     uint8_t   delimiter02
;        // Field delimiter (IAP_CERT_FIELD_DELIMITER) 
6101     uint8_t   devClass
;           // iAP device class (maps to lingo permissions) 
6102     uint8_t   delimiter03
;        // Field delimiter (IAP_CERT_FIELD_DELIMITER) 
6103     uint8_t   batchNumHi
;         // Batch number high byte (15:08) 
6104     uint8_t   batchNumLo
;         // Batch number low  byte (07:00) 
6105     uint8_t   delimiter04
;        // Field delimiter (IAP_CERT_FIELD_DELIMITER) 
6106     uint8_t   serialNumHi
;        // Serial number high   byte (23:16) 
6107     uint8_t   serialNumMid
;       // Serial number middle byte (15:08) 
6108     uint8_t   serialNumLo
;        // Serial number low    byte (07:00) 
6110 }   IapCertSerialNumber_t
, *pIapCertSerialNumber_t
; 
6113 #define IAP_CERT_FIELD_DELIMITER        0xAA    // "Apple_Accessory" delimiter 
6114 SeciAuthVersion 
SecCertificateGetiAuthVersion(SecCertificateRef certificate
) { 
6116         return kSeciAuthInvalid
; 
6118     if (NULL 
!= SecCertificateGetExtensionValue(certificate
, 
6119                                                 CFSTR("1.2.840.113635.100.6.36"))) { 
6120         /* v3 Capabilities Extension */ 
6121         return kSeciAuthVersion3
; 
6123     if (NULL 
!= SecCertificateGetExtensionValue(certificate
, 
6124                                                 CFSTR("1.2.840.113635.100.6.59.1"))) { 
6125         /* SW Auth General Capabilities Extension */ 
6126         return kSeciAuthVersionSW
; 
6128     DERItem serialNumber 
= certificate
->_serialNum
; 
6129     require_quiet(serialNumber
.data
, out
); 
6130     require_quiet(serialNumber
.length 
== 15, out
); 
6131     require_quiet(serialNumber
.data
[2] == IAP_CERT_FIELD_DELIMITER 
&& 
6132                   serialNumber
.data
[6] == IAP_CERT_FIELD_DELIMITER 
&& 
6133                   serialNumber
.data
[8] == IAP_CERT_FIELD_DELIMITER 
&& 
6134                   serialNumber
.data
[11] == IAP_CERT_FIELD_DELIMITER
, out
); 
6135     return kSeciAuthVersion2
; 
6137     return kSeciAuthInvalid
; 
6140 static CFStringRef 
SecCertificateiAPSWAuthCapabilitiesTypeToOID(SeciAPSWAuthCapabilitiesType type
) { 
6141     CFStringRef extensionOID 
= NULL
; 
6142     /* Get the oid for the type */ 
6143     if (type 
== kSeciAPSWAuthGeneralCapabilities
) { 
6144         extensionOID 
= CFSTR("1.2.840.113635.100.6.59.1"); 
6145     } else if (type 
== kSeciAPSWAuthAirPlayCapabilities
) { 
6146         extensionOID 
= CFSTR("1.2.840.113635.100.6.59.2"); 
6147     } else if (type 
== kSeciAPSWAuthHomeKitCapabilities
) { 
6148         extensionOID 
= CFSTR("1.2.840.113635.100.6.59.3"); 
6150     return extensionOID
; 
6153 CFDataRef 
SecCertificateCopyiAPSWAuthCapabilities(SecCertificateRef certificate
, SeciAPSWAuthCapabilitiesType type
) { 
6157     CFDataRef extensionData 
= NULL
; 
6158     DERItem 
*extensionValue 
= NULL
; 
6159     CFStringRef extensionOID 
= SecCertificateiAPSWAuthCapabilitiesTypeToOID(type
); 
6160     require_quiet(extensionOID
, out
); 
6161     extensionValue 
= SecCertificateGetExtensionValue(certificate
, extensionOID
); 
6162     require_quiet(extensionValue
, out
); 
6163     /* The extension is a octet string containing the DER-encoded variable-length octet string */ 
6164     DERDecodedInfo decodedValue
; 
6165     require_noerr_quiet(DERDecodeItem(extensionValue
, &decodedValue
), out
); 
6166     if (decodedValue
.tag 
== ASN1_OCTET_STRING
) { 
6167         extensionData 
= CFDataCreate(NULL
, decodedValue
.content
.data
, 
6168                                      decodedValue
.content
.length
); 
6171     return extensionData
; 
6174 SecCertificateRef 
SecCertificateCreateWithPEM(CFAllocatorRef allocator
, 
6175         CFDataRef pem_certificate
) 
6177     static const char begin_cert
[] = "-----BEGIN CERTIFICATE-----\n"; 
6178     static const char end_cert
[] = "-----END CERTIFICATE-----\n"; 
6179     uint8_t *base64_data 
= NULL
; 
6180     SecCertificateRef cert 
= NULL
; 
6181     const unsigned char *data 
= CFDataGetBytePtr(pem_certificate
); 
6182     //const size_t length = CFDataGetLength(pem_certificate); 
6183     char *begin 
= strstr((const char *)data
, begin_cert
); 
6184     char *end 
= strstr((const char *)data
, end_cert
); 
6187     begin 
+= sizeof(begin_cert
) - 1; 
6188     size_t base64_length 
= SecBase64Decode(begin
, end 
- begin
, NULL
, 0); 
6189     if (base64_length 
&& (base64_length 
< (size_t)CFDataGetLength(pem_certificate
))) { 
6190         require_quiet(base64_data 
= calloc(1, base64_length
), out
); 
6191         require_action_quiet(base64_length 
= SecBase64Decode(begin
, end 
- begin
, base64_data
, base64_length
), out
, free(base64_data
)); 
6192         cert 
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, base64_data
, base64_length
); 
6201 // -- MARK -- XPC encoding/decoding 
6204 bool SecCertificateAppendToXPCArray(SecCertificateRef certificate
, xpc_object_t xpc_certificates
, CFErrorRef 
*error
) { 
6206         return true; // NOOP 
6208     size_t length 
= SecCertificateGetLength(certificate
); 
6209     const uint8_t *bytes 
= SecCertificateGetBytePtr(certificate
); 
6210 #if SECTRUST_VERBOSE_DEBUG 
6211         secerror("cert=0x%lX length=%d bytes=0x%lX", (uintptr_t)certificate
, (int)length
, (uintptr_t)bytes
); 
6213     if (!length 
|| !bytes
) { 
6214         return SecError(errSecParam
, error
, CFSTR("failed to der encode certificate")); 
6216     xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
); 
6220 SecCertificateRef 
SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates
, size_t index
, CFErrorRef 
*error
) { 
6221     SecCertificateRef certificate 
= NULL
; 
6223     const uint8_t *bytes 
= xpc_array_get_data(xpc_certificates
, index
, &length
); 
6225         certificate 
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, bytes
, length
); 
6228         SecError(errSecParam
, error
, CFSTR("certificates[%zu] failed to decode"), index
); 
6233 xpc_object_t 
SecCertificateArrayCopyXPCArray(CFArrayRef certificates
, CFErrorRef 
*error
) { 
6234     xpc_object_t xpc_certificates
; 
6235     require_action_quiet(xpc_certificates 
= xpc_array_create(NULL
, 0), exit
, 
6236                          SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array"))); 
6237     CFIndex ix
, count 
= CFArrayGetCount(certificates
); 
6238     for (ix 
= 0; ix 
< count
; ++ix
) { 
6239                 SecCertificateRef certificate 
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
); 
6240     #if SECTRUST_VERBOSE_DEBUG 
6241                 CFIndex length 
= SecCertificateGetLength(certificate
); 
6242                 const UInt8 
*bytes 
= SecCertificateGetBytePtr(certificate
); 
6243                 secerror("idx=%d of %d; cert=0x%lX length=%ld bytes=0x%lX", (int)ix
, (int)count
, (uintptr_t)certificate
, (size_t)length
, (uintptr_t)bytes
); 
6245         if (!SecCertificateAppendToXPCArray(certificate
, xpc_certificates
, error
)) { 
6246             xpc_release(xpc_certificates
); 
6247             xpc_certificates 
= NULL
; 
6253     return xpc_certificates
; 
6256 CFArrayRef 
SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates
, CFErrorRef 
*error
) { 
6257     CFMutableArrayRef certificates 
= NULL
; 
6258     require_action_quiet(xpc_get_type(xpc_certificates
) == XPC_TYPE_ARRAY
, exit
, 
6259                          SecError(errSecParam
, error
, CFSTR("certificates xpc value is not an array"))); 
6260     size_t count 
= xpc_array_get_count(xpc_certificates
); 
6261     require_action_quiet(certificates 
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
), exit
, 
6262                          SecError(errSecAllocate
, error
, CFSTR("failed to create CFArray of capacity %zu"), count
)); 
6265     for (ix 
= 0; ix 
< count
; ++ix
) { 
6266         SecCertificateRef cert 
= SecCertificateCreateWithXPCArrayAtIndex(xpc_certificates
, ix
, error
); 
6268             CFRelease(certificates
); 
6271         CFArraySetValueAtIndex(certificates
, ix
, cert
); 
6276     return certificates
; 
6279 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); } 
6282 static CFArrayRef 
CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType
, CFErrorRef
* error
) 
6284         __block CFArrayRef result 
= NULL
; 
6286         do_if_registered(ota_CopyEscrowCertificates
, escrowRootType
, error
); 
6288         securityd_send_sync_and_do(kSecXPCOpOTAGetEscrowCertificates
, error
, 
6289                 ^bool(xpc_object_t message
, CFErrorRef 
*error
) 
6291                         xpc_dictionary_set_uint64(message
, "escrowType", (uint64_t)escrowRootType
); 
6294                 ^bool(xpc_object_t response
, CFErrorRef 
*error
) 
6296                         xpc_object_t xpc_array 
= xpc_dictionary_get_value(response
, kSecXPCKeyResult
); 
6298                         if (response 
&& (NULL 
!= xpc_array
)) { 
6299                                 result 
= (CFArrayRef
)_CFXPCCreateCFObjectFromXPCObject(xpc_array
); 
6302                                 return SecError(errSecInternal
, error
, CFSTR("Did not get the Escrow certificates")); 
6304                         return result 
!= NULL
; 
6309 CFArrayRef 
SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType
) 
6311         CFArrayRef result 
= NULL
; 
6313         CFDataRef certData 
= NULL
; 
6316         if (kSecCertificateBaselineEscrowRoot 
== escrowRootType 
|| 
6317                 kSecCertificateBaselinePCSEscrowRoot 
== escrowRootType 
|| 
6318                 kSecCertificateBaselineEscrowBackupRoot 
== escrowRootType 
|| 
6319                 kSecCertificateBaselineEscrowEnrollmentRoot 
== escrowRootType
) 
6321                 // The request is for the base line certificates. 
6322                 // Use the hard coded data to generate the return array. 
6323                 struct RootRecord
** pEscrowRoots
; 
6324                 switch (escrowRootType
) { 
6325                         case kSecCertificateBaselineEscrowRoot
: 
6326                                 numRoots 
= kNumberOfBaseLineEscrowRoots
; 
6327                                 pEscrowRoots 
= kBaseLineEscrowRoots
; 
6329                         case kSecCertificateBaselinePCSEscrowRoot
: 
6330                                 numRoots 
= kNumberOfBaseLinePCSEscrowRoots
; 
6331                                 pEscrowRoots 
= kBaseLinePCSEscrowRoots
; 
6333                         case kSecCertificateBaselineEscrowBackupRoot
: 
6334                                 numRoots 
= kNumberOfBaseLineEscrowBackupRoots
; 
6335                                 pEscrowRoots 
= kBaseLineEscrowBackupRoots
; 
6337                         case kSecCertificateBaselineEscrowEnrollmentRoot
: 
6339                                 numRoots 
= kNumberOfBaseLineEscrowEnrollmentRoots
; 
6340                                 pEscrowRoots 
= kBaseLineEscrowEnrollmentRoots
; 
6344                 // Get the hard coded set of roots 
6345                 SecCertificateRef baseLineCerts
[numRoots
]; 
6346                 struct RootRecord
* pRootRecord 
= NULL
; 
6348                 for (iCnt 
= 0; iCnt 
< numRoots
; iCnt
++) { 
6349                         pRootRecord 
= pEscrowRoots
[iCnt
]; 
6350                         if (NULL 
!= pRootRecord 
&& pRootRecord
->_length 
> 0 && NULL 
!= pRootRecord
->_bytes
) { 
6351                                 certData 
= CFDataCreate(kCFAllocatorDefault
, pRootRecord
->_bytes
, pRootRecord
->_length
); 
6352                                 if (NULL 
!= certData
) { 
6353                                         baseLineCerts
[iCnt
] = SecCertificateCreateWithData(kCFAllocatorDefault
, certData
); 
6354                                         CFRelease(certData
); 
6358                 result 
= CFArrayCreate(kCFAllocatorDefault
, (const void **)baseLineCerts
, numRoots
, &kCFTypeArrayCallBacks
); 
6359                 for (iCnt 
= 0; iCnt 
< numRoots
; iCnt
++) { 
6360                         if (NULL 
!= baseLineCerts
[iCnt
]) { 
6361                                 CFRelease(baseLineCerts
[iCnt
]); 
6366                 // The request is for the current certificates. 
6367                 CFErrorRef error 
= NULL
; 
6368                 CFArrayRef cert_datas 
= CopyEscrowCertificates(escrowRootType
, &error
); 
6369                 if (NULL 
!= error 
|| NULL 
== cert_datas
) { 
6370                         if (NULL 
!= error
) { 
6373                         if (NULL 
!= cert_datas
) { 
6374                                 CFRelease(cert_datas
); 
6379                 numRoots 
= (int)(CFArrayGetCount(cert_datas
)); 
6381                 SecCertificateRef assetCerts
[numRoots
]; 
6382                 for (iCnt 
= 0; iCnt 
< numRoots
; iCnt
++) { 
6383                         certData 
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, iCnt
); 
6384                         if (NULL 
!= certData
) { 
6385                                 SecCertificateRef aCertRef 
= SecCertificateCreateWithData(kCFAllocatorDefault
, certData
); 
6386                                 assetCerts
[iCnt
] = aCertRef
; 
6389                                 assetCerts
[iCnt
] = NULL
; 
6394                         result 
= CFArrayCreate(kCFAllocatorDefault
, (const void **)assetCerts
, numRoots
, &kCFTypeArrayCallBacks
); 
6395                         for (iCnt 
= 0; iCnt 
< numRoots
; iCnt
++) { 
6396                                 if (NULL 
!= assetCerts
[iCnt
]) { 
6397                                         CFRelease(assetCerts
[iCnt
]); 
6401                 CFReleaseSafe(cert_datas
); 
6406 SEC_CONST_DECL (kSecSignatureDigestAlgorithmUnknown
, "SignatureDigestUnknown"); 
6407 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD2
, "SignatureDigestMD2"); 
6408 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD4
, "SignatureDigestMD4"); 
6409 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD5
, "SignatureDigestMD5"); 
6410 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA1
, "SignatureDigestSHA1"); 
6411 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA224
, "SignatureDigestSHA224"); 
6412 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA256
, "SignatureDigestSHA256"); 
6413 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA384
, "SignatureDigestSHA284"); 
6414 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA512
, "SignatureDigestSHA512"); 
6416 SecSignatureHashAlgorithm 
SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate
) 
6418         SecSignatureHashAlgorithm result 
= kSecSignatureHashAlgorithmUnknown
; 
6419         DERAlgorithmId 
*algId 
= (certificate
) ? &certificate
->_tbsSigAlg 
: NULL
; 
6420         const DERItem 
*algOid 
= (algId
) ? &algId
->oid 
: NULL
; 
6422                 if (!algOid
->data 
|| !algOid
->length
) { 
6425                 /* classify the signature algorithm OID into one of our known types */ 
6426                 if (DEROidCompare(algOid
, &oidSha512Ecdsa
) || 
6427                         DEROidCompare(algOid
, &oidSha512Rsa
) || 
6428                         DEROidCompare(algOid
, &oidSha512
)) { 
6429                         result 
= kSecSignatureHashAlgorithmSHA512
; 
6432                 if (DEROidCompare(algOid
, &oidSha384Ecdsa
) || 
6433                         DEROidCompare(algOid
, &oidSha384Rsa
) || 
6434                         DEROidCompare(algOid
, &oidSha384
)) { 
6435                         result 
= kSecSignatureHashAlgorithmSHA384
; 
6438                 if (DEROidCompare(algOid
, &oidSha256Ecdsa
) || 
6439                         DEROidCompare(algOid
, &oidSha256Rsa
) || 
6440                         DEROidCompare(algOid
, &oidSha256
)) { 
6441                         result 
= kSecSignatureHashAlgorithmSHA256
; 
6444                 if (DEROidCompare(algOid
, &oidSha224Ecdsa
) || 
6445                         DEROidCompare(algOid
, &oidSha224Rsa
) || 
6446                         DEROidCompare(algOid
, &oidSha224
)) { 
6447                         result 
= kSecSignatureHashAlgorithmSHA224
; 
6450                 if (DEROidCompare(algOid
, &oidSha1Ecdsa
) || 
6451                         DEROidCompare(algOid
, &oidSha1Rsa
) || 
6452                         DEROidCompare(algOid
, &oidSha1Dsa
) || 
6453                         DEROidCompare(algOid
, &oidSha1DsaOIW
) || 
6454                         DEROidCompare(algOid
, &oidSha1DsaCommonOIW
) || 
6455                         DEROidCompare(algOid
, &oidSha1RsaOIW
) || 
6456                         DEROidCompare(algOid
, &oidSha1Fee
) || 
6457                         DEROidCompare(algOid
, &oidSha1
)) { 
6458                         result 
= kSecSignatureHashAlgorithmSHA1
; 
6461                 if (DEROidCompare(algOid
, &oidMd5Rsa
) || 
6462                         DEROidCompare(algOid
, &oidMd5Fee
) || 
6463                         DEROidCompare(algOid
, &oidMd5
)) { 
6464                         result 
= kSecSignatureHashAlgorithmMD5
; 
6467                 if (DEROidCompare(algOid
, &oidMd4Rsa
) || 
6468                         DEROidCompare(algOid
, &oidMd4
)) { 
6469                         result 
= kSecSignatureHashAlgorithmMD4
; 
6472                 if (DEROidCompare(algOid
, &oidMd2Rsa
) || 
6473                         DEROidCompare(algOid
, &oidMd2
)) { 
6474                         result 
= kSecSignatureHashAlgorithmMD2
; 
6483 CFArrayRef 
SecCertificateCopyiPhoneDeviceCAChain(void) { 
6484     CFMutableArrayRef result 
= NULL
; 
6485     SecCertificateRef iPhoneDeviceCA 
= NULL
, iPhoneCA 
= NULL
, appleRoot 
= NULL
; 
6487     require_quiet(iPhoneDeviceCA 
= SecCertificateCreateWithBytes(NULL
, _AppleiPhoneDeviceCA
, sizeof(_AppleiPhoneDeviceCA
)), 
6489     require_quiet(iPhoneCA 
= SecCertificateCreateWithBytes(NULL
, _AppleiPhoneCA
, sizeof(_AppleiPhoneCA
)), 
6491     require_quiet(appleRoot 
= SecCertificateCreateWithBytes(NULL
, _AppleRootCA
, sizeof(_AppleRootCA
)), 
6494     require_quiet(result 
= CFArrayCreateMutable(NULL
, 3, &kCFTypeArrayCallBacks
), errOut
); 
6495     CFArrayAppendValue(result
, iPhoneDeviceCA
); 
6496     CFArrayAppendValue(result
, iPhoneCA
); 
6497     CFArrayAppendValue(result
, appleRoot
); 
6500     CFReleaseNull(iPhoneDeviceCA
); 
6501     CFReleaseNull(iPhoneCA
); 
6502     CFReleaseNull(appleRoot
); 
6506 bool SecCertificateGetDeveloperIDDate(SecCertificateRef certificate
, CFAbsoluteTime 
*time
, CFErrorRef 
*error
) { 
6507     if (!certificate 
|| !time
) { 
6508         return SecError(errSecParam
, error
, CFSTR("DeveloperID Date parsing: missing required input")); 
6510     DERItem 
*extensionValue 
= SecCertificateGetExtensionValue(certificate
, CFSTR("1.2.840.113635.100.6.1.33")); 
6511     if (!extensionValue
) { 
6512         return SecError(errSecMissingRequiredExtension
, error
, CFSTR("DeveloperID Date parsing: extension not found")); 
6514     DERDecodedInfo decodedValue
; 
6515     if (DERDecodeItem(extensionValue
, &decodedValue
) != DR_Success
) { 
6516         return SecError(errSecDecode
, error
, CFSTR("DeveloperID Date parsing: extension value failed to decode")); 
6518     /* The extension value is a DERGeneralizedTime encoded in a UTF8String */ 
6519     CFErrorRef localError 
= NULL
; 
6520     if (decodedValue
.tag 
== ASN1_UTF8_STRING
) { 
6521          *time 
= SecAbsoluteTimeFromDateContentWithError(ASN1_GENERALIZED_TIME
, decodedValue
.content
.data
, decodedValue
.content
.length
, &localError
); 
6523         return SecError(errSecDecode
, error
, CFSTR("DeveloperID Date parsing: extension value wrong tag")); 
6525     return CFErrorPropagate(localError
, error
);