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/oidsPriv.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 */
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
);
547 static OSStatus
parseRDNContent(const DERItem
*rdnSetContent
, void *context
,
548 parseX501NameCallback callback
) {
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
++);
567 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
569 return errSecSuccess
;
571 return errSecInvalidCertificate
;
574 static OSStatus
parseX501NameContent(const DERItem
*x501NameContent
, void *context
,
575 parseX501NameCallback callback
) {
577 DERReturn drtn
= DERDecodeSeqContentInit(x501NameContent
, &derSeq
);
578 require_noerr_quiet(drtn
, badDER
);
579 DERDecodedInfo currDecoded
;
580 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
581 require_quiet(currDecoded
.tag
== ASN1_CONSTR_SET
, badDER
);
582 OSStatus status
= parseRDNContent(&currDecoded
.content
, context
,
587 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
589 return errSecSuccess
;
592 return errSecInvalidCertificate
;
595 static OSStatus
parseX501Name(const DERItem
*x501Name
, void *context
,
596 parseX501NameCallback callback
) {
597 DERDecodedInfo x501NameContent
;
598 if (DERDecodeItem(x501Name
, &x501NameContent
) ||
599 x501NameContent
.tag
!= ASN1_CONSTR_SEQUENCE
) {
600 return errSecInvalidCertificate
;
602 return parseX501NameContent(&x501NameContent
.content
, context
,
607 /************************************************************************/
608 /********************** Extension Parsing Routines **********************/
609 /************************************************************************/
611 static bool SecCEPSubjectKeyIdentifier(SecCertificateRef certificate
,
612 const SecCertificateExtension
*extn
) {
613 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
614 DERDecodedInfo keyIdentifier
;
615 DERReturn drtn
= DERDecodeItem(&extn
->extnValue
, &keyIdentifier
);
616 require_noerr_quiet(drtn
, badDER
);
617 require_quiet(keyIdentifier
.tag
== ASN1_OCTET_STRING
, badDER
);
618 certificate
->_subjectKeyIdentifier
= keyIdentifier
.content
;
622 secwarning("Invalid SubjectKeyIdentifier Extension");
626 static bool SecCEPKeyUsage(SecCertificateRef certificate
,
627 const SecCertificateExtension
*extn
) {
628 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
629 SecKeyUsage keyUsage
= extn
->critical
? kSecKeyUsageCritical
: 0;
630 DERDecodedInfo bitStringContent
;
631 DERReturn drtn
= DERDecodeItem(&extn
->extnValue
, &bitStringContent
);
632 require_noerr_quiet(drtn
, badDER
);
633 require_quiet(bitStringContent
.tag
== ASN1_BIT_STRING
, badDER
);
634 DERSize len
= bitStringContent
.content
.length
- 1;
635 require_quiet(len
== 1 || len
== 2, badDER
);
636 DERByte numUnusedBits
= bitStringContent
.content
.data
[0];
637 require_quiet(numUnusedBits
< 8, badDER
);
638 /* Flip the bits in the bit string so the first bit in the lsb. */
639 uint_fast16_t bits
= 8 * len
- numUnusedBits
;
640 uint_fast16_t value
= bitStringContent
.content
.data
[1];
643 value
= (value
<< 8) + bitStringContent
.content
.data
[2];
649 for (ix
= 0; ix
< bits
; ++ix
) {
655 certificate
->_keyUsage
= keyUsage
;
658 certificate
->_keyUsage
= kSecKeyUsageUnspecified
;
659 secwarning("Invalid KeyUsage Extension");
663 static bool SecCEPPrivateKeyUsagePeriod(SecCertificateRef certificate
,
664 const SecCertificateExtension
*extn
) {
665 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
669 static bool SecCEPSubjectAltName(SecCertificateRef certificate
,
670 const SecCertificateExtension
*extn
) {
671 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
672 certificate
->_subjectAltName
= extn
;
676 static bool SecCEPIssuerAltName(SecCertificateRef certificate
,
677 const SecCertificateExtension
*extn
) {
678 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
682 static bool SecCEPBasicConstraints(SecCertificateRef certificate
,
683 const SecCertificateExtension
*extn
) {
684 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
685 DERBasicConstraints basicConstraints
;
686 require_noerr_quiet(DERParseSequence(&extn
->extnValue
,
687 DERNumBasicConstraintsItemSpecs
, DERBasicConstraintsItemSpecs
,
688 &basicConstraints
, sizeof(basicConstraints
)), badDER
);
689 require_noerr_quiet(DERParseBooleanWithDefault(&basicConstraints
.cA
, false,
690 &certificate
->_basicConstraints
.isCA
), badDER
);
691 if (basicConstraints
.pathLenConstraint
.length
!= 0) {
692 require_noerr_quiet(DERParseInteger(
693 &basicConstraints
.pathLenConstraint
,
694 &certificate
->_basicConstraints
.pathLenConstraint
), badDER
);
695 certificate
->_basicConstraints
.pathLenConstraintPresent
= true;
697 certificate
->_basicConstraints
.present
= true;
698 certificate
->_basicConstraints
.critical
= extn
->critical
;
701 certificate
->_basicConstraints
.present
= false;
702 secwarning("Invalid BasicConstraints Extension");
708 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
710 * NameConstraints ::= SEQUENCE {
711 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
712 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
714 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
716 * GeneralSubtree ::= SEQUENCE {
718 * minimum [0] BaseDistance DEFAULT 0,
719 * maximum [1] BaseDistance OPTIONAL }
721 * BaseDistance ::= INTEGER (0..MAX)
723 static DERReturn
parseGeneralSubtrees(DERItem
*derSubtrees
, CFArrayRef
*generalSubtrees
) {
724 CFMutableArrayRef gs
= NULL
;
726 DERReturn drtn
= DERDecodeSeqContentInit(derSubtrees
, &gsSeq
);
727 require_noerr_quiet(drtn
, badDER
);
728 DERDecodedInfo gsContent
;
729 require_quiet(gs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
730 &kCFTypeArrayCallBacks
),
732 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
733 DERGeneralSubtree derGS
;
734 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
735 drtn
= DERParseSequenceContent(&gsContent
.content
,
736 DERNumGeneralSubtreeItemSpecs
,
737 DERGeneralSubtreeItemSpecs
,
738 &derGS
, sizeof(derGS
));
739 require_noerr_quiet(drtn
, badDER
);
742 * Within this profile, the minimum and maximum fields are not used with
743 * any name forms, thus, the minimum MUST be zero, and maximum MUST be
746 * Because minimum DEFAULT 0, absence equivalent to present and 0.
748 if (derGS
.minimum
.length
) {
750 require_noerr_quiet(DERParseInteger(&derGS
.minimum
, &minimum
),
752 require_quiet(minimum
== 0, badDER
);
754 require_quiet(derGS
.maximum
.length
== 0, badDER
);
755 require_quiet(derGS
.generalName
.length
!= 0, badDER
);
757 CFDataRef generalName
= NULL
;
758 require_quiet(generalName
= CFDataCreate(kCFAllocatorDefault
,
759 derGS
.generalName
.data
,
760 derGS
.generalName
.length
),
762 CFArrayAppendValue(gs
, generalName
);
763 CFReleaseNull(generalName
);
765 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
767 // since generalSubtrees is a pointer to an instance variable,
768 // make sure we release the existing array before assignment.
769 CFReleaseSafe(*generalSubtrees
);
770 *generalSubtrees
= gs
;
776 secdebug("cert","failed to parse GeneralSubtrees");
780 static bool SecCEPNameConstraints(SecCertificateRef certificate
,
781 const SecCertificateExtension
*extn
) {
782 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
783 DERNameConstraints nc
;
785 drtn
= DERParseSequence(&extn
->extnValue
,
786 DERNumNameConstraintsItemSpecs
,
787 DERNameConstraintsItemSpecs
,
789 require_noerr_quiet(drtn
, badDER
);
790 if (nc
.permittedSubtrees
.length
) {
791 require_noerr_quiet(parseGeneralSubtrees(&nc
.permittedSubtrees
, &certificate
->_permittedSubtrees
), badDER
);
793 if (nc
.excludedSubtrees
.length
) {
794 require_noerr_quiet(parseGeneralSubtrees(&nc
.excludedSubtrees
, &certificate
->_excludedSubtrees
), badDER
);
799 secwarning("Invalid Name Constraints extension");
803 static OSStatus
appendCRLDPFromGeneralNames(void *context
, SecCEGeneralNameType type
,
804 const DERItem
*value
) {
805 CFMutableArrayRef
*crlDPs
= (CFMutableArrayRef
*)context
;
806 if (type
== GNT_URI
) {
808 url
= CFURLCreateWithBytes(NULL
, value
->data
, value
->length
, kCFStringEncodingASCII
, NULL
);
811 *crlDPs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
813 CFArrayAppendValue(*crlDPs
, url
);
817 return errSecSuccess
;
821 id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 }
823 CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
825 DistributionPoint ::= SEQUENCE {
826 distributionPoint [0] DistributionPointName OPTIONAL,
827 reasons [1] ReasonFlags OPTIONAL,
828 cRLIssuer [2] GeneralNames OPTIONAL }
830 DistributionPointName ::= CHOICE {
831 fullName [0] GeneralNames,
832 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
834 static bool SecCEPCrlDistributionPoints(SecCertificateRef certificate
,
835 const SecCertificateExtension
*extn
) {
836 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
837 DERSequence crlDPSeq
;
839 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &crlDPSeq
);
840 require_noerr_quiet(drtn
, badDER
);
841 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
842 DERDecodedInfo dpContent
;
843 while ((drtn
= DERDecodeSeqNext(&crlDPSeq
, &dpContent
)) == DR_Success
) {
844 require_quiet(dpContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
845 DERDistributionPoint dp
;
846 drtn
= DERParseSequenceContent(&dpContent
.content
, DERNumDistributionPointItemSpecs
,
847 DERDistributionPointItemSpecs
, &dp
, sizeof(dp
));
848 require_noerr_quiet(drtn
, badDER
);
849 require_quiet(dp
.distributionPoint
.data
|| dp
.cRLIssuer
.data
, badDER
);
850 if (dp
.distributionPoint
.data
) {
851 DERDecodedInfo dpName
;
852 drtn
= DERDecodeItem(&dp
.distributionPoint
, &dpName
);
853 require_noerr_quiet(drtn
, badDER
);
854 switch (dpName
.tag
) {
855 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
856 drtn
= parseGeneralNamesContent(&dpName
.content
, &certificate
->_crlDistributionPoints
,
857 appendCRLDPFromGeneralNames
);
858 require_noerr_quiet(drtn
, badDER
);
860 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1:
861 /* RelativeDistinguishName. Nothing we can do with that. */
867 if (dp
.cRLIssuer
.data
) {
868 drtn
= SecCertificateParseGeneralNames(&dp
.cRLIssuer
, &certificate
->_crlDistributionPoints
,
869 appendCRLDPFromGeneralNames
);
870 require_noerr_quiet(drtn
, badDER
);
873 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
876 secwarning("Invalid CRL Distribution Points extension");
881 certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
883 PolicyInformation ::= SEQUENCE {
884 policyIdentifier CertPolicyId,
885 policyQualifiers SEQUENCE SIZE (1..MAX) OF
886 PolicyQualifierInfo OPTIONAL }
888 CertPolicyId ::= OBJECT IDENTIFIER
890 PolicyQualifierInfo ::= SEQUENCE {
891 policyQualifierId PolicyQualifierId,
892 qualifier ANY DEFINED BY policyQualifierId }
894 /* maximum number of policies of 8192 seems more than adequate */
895 #define MAX_CERTIFICATE_POLICIES 8192
896 static bool SecCEPCertificatePolicies(SecCertificateRef certificate
,
897 const SecCertificateExtension
*extn
) {
898 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
901 SecCEPolicyInformation
*policies
= NULL
;
902 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &piSeq
);
903 require_noerr_quiet(drtn
, badDER
);
904 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
905 DERDecodedInfo piContent
;
906 DERSize policy_count
= 0;
907 while ((policy_count
< MAX_CERTIFICATE_POLICIES
) &&
908 (drtn
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) {
909 require_quiet(piContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
912 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
913 require_quiet(policies
= (SecCEPolicyInformation
*)malloc(sizeof(SecCEPolicyInformation
)
914 * (policy_count
> 0 ? policy_count
: 1)),
916 drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &piSeq
);
917 require_noerr_quiet(drtn
, badDER
);
918 DERSize policy_ix
= 0;
919 while ((policy_ix
< (policy_count
> 0 ? policy_count
: 1)) &&
920 (drtn
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) {
921 DERPolicyInformation pi
;
922 drtn
= DERParseSequenceContent(&piContent
.content
,
923 DERNumPolicyInformationItemSpecs
,
924 DERPolicyInformationItemSpecs
,
926 require_noerr_quiet(drtn
, badDER
);
927 policies
[policy_ix
].policyIdentifier
= pi
.policyIdentifier
;
928 policies
[policy_ix
++].policyQualifiers
= pi
.policyQualifiers
;
930 certificate
->_certificatePolicies
.present
= true;
931 certificate
->_certificatePolicies
.critical
= extn
->critical
;
932 certificate
->_certificatePolicies
.numPolicies
= policy_count
;
933 certificate
->_certificatePolicies
.policies
= policies
;
938 certificate
->_certificatePolicies
.present
= false;
939 secwarning("Invalid CertificatePolicies Extension");
944 id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 }
946 PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
947 issuerDomainPolicy CertPolicyId,
948 subjectDomainPolicy CertPolicyId }
950 #define MAX_POLICY_MAPPINGS 8192
951 static bool SecCEPPolicyMappings(SecCertificateRef certificate
,
952 const SecCertificateExtension
*extn
) {
953 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
956 SecCEPolicyMapping
*mappings
= NULL
;
957 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &pmSeq
);
958 require_noerr_quiet(drtn
, badDER
);
959 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
960 DERDecodedInfo pmContent
;
961 DERSize mapping_count
= 0;
962 while ((mapping_count
< MAX_POLICY_MAPPINGS
) &&
963 (drtn
= DERDecodeSeqNext(&pmSeq
, &pmContent
)) == DR_Success
) {
964 require_quiet(pmContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
967 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
968 require_quiet(mappings
= (SecCEPolicyMapping
*)malloc(sizeof(SecCEPolicyMapping
)
969 * (mapping_count
> 0 ? mapping_count
: 1)),
971 drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &pmSeq
);
972 require_noerr_quiet(drtn
, badDER
);
973 DERSize mapping_ix
= 0;
974 while ((mapping_ix
< (mapping_count
> 0 ? mapping_count
: 1)) &&
975 (drtn
= DERDecodeSeqNext(&pmSeq
, &pmContent
)) == DR_Success
) {
976 require_quiet(pmContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
978 drtn
= DERParseSequenceContent(&pmContent
.content
,
979 DERNumPolicyMappingItemSpecs
,
980 DERPolicyMappingItemSpecs
,
982 require_noerr_quiet(drtn
, badDER
);
983 mappings
[mapping_ix
].issuerDomainPolicy
= pm
.issuerDomainPolicy
;
984 mappings
[mapping_ix
++].subjectDomainPolicy
= pm
.subjectDomainPolicy
;
986 certificate
->_policyMappings
.present
= true;
987 certificate
->_policyMappings
.critical
= extn
->critical
;
988 certificate
->_policyMappings
.numMappings
= mapping_count
;
989 certificate
->_policyMappings
.mappings
= mappings
;
995 certificate
->_policyMappings
.present
= false;
996 secwarning("Invalid CertificatePolicies Extension");
1001 AuthorityKeyIdentifier ::= SEQUENCE {
1002 keyIdentifier [0] KeyIdentifier OPTIONAL,
1003 authorityCertIssuer [1] GeneralNames OPTIONAL,
1004 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
1005 -- authorityCertIssuer and authorityCertSerialNumber MUST both
1006 -- be present or both be absent
1008 KeyIdentifier ::= OCTET STRING
1010 static bool SecCEPAuthorityKeyIdentifier(SecCertificateRef certificate
,
1011 const SecCertificateExtension
*extn
) {
1012 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1013 DERAuthorityKeyIdentifier akid
;
1015 drtn
= DERParseSequence(&extn
->extnValue
,
1016 DERNumAuthorityKeyIdentifierItemSpecs
,
1017 DERAuthorityKeyIdentifierItemSpecs
,
1018 &akid
, sizeof(akid
));
1019 require_noerr_quiet(drtn
, badDER
);
1020 if (akid
.keyIdentifier
.length
) {
1021 certificate
->_authorityKeyIdentifier
= akid
.keyIdentifier
;
1023 if (akid
.authorityCertIssuer
.length
||
1024 akid
.authorityCertSerialNumber
.length
) {
1025 require_quiet(akid
.authorityCertIssuer
.length
&&
1026 akid
.authorityCertSerialNumber
.length
, badDER
);
1027 /* Perhaps put in a subsection called Authority Certificate Issuer. */
1028 certificate
->_authorityKeyIdentifierIssuer
= akid
.authorityCertIssuer
;
1029 certificate
->_authorityKeyIdentifierSerialNumber
= akid
.authorityCertSerialNumber
;
1034 secwarning("Invalid AuthorityKeyIdentifier Extension");
1038 static bool SecCEPPolicyConstraints(SecCertificateRef certificate
,
1039 const SecCertificateExtension
*extn
) {
1040 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1041 DERPolicyConstraints pc
;
1043 drtn
= DERParseSequence(&extn
->extnValue
,
1044 DERNumPolicyConstraintsItemSpecs
,
1045 DERPolicyConstraintsItemSpecs
,
1047 require_noerr_quiet(drtn
, badDER
);
1048 if (pc
.requireExplicitPolicy
.length
) {
1049 require_noerr_quiet(DERParseInteger(
1050 &pc
.requireExplicitPolicy
,
1051 &certificate
->_policyConstraints
.requireExplicitPolicy
), badDER
);
1052 certificate
->_policyConstraints
.requireExplicitPolicyPresent
= true;
1054 if (pc
.inhibitPolicyMapping
.length
) {
1055 require_noerr_quiet(DERParseInteger(
1056 &pc
.inhibitPolicyMapping
,
1057 &certificate
->_policyConstraints
.inhibitPolicyMapping
), badDER
);
1058 certificate
->_policyConstraints
.inhibitPolicyMappingPresent
= true;
1061 certificate
->_policyConstraints
.present
= true;
1062 certificate
->_policyConstraints
.critical
= extn
->critical
;
1066 certificate
->_policyConstraints
.present
= false;
1067 secwarning("Invalid PolicyConstraints Extension");
1071 static bool SecCEPExtendedKeyUsage(SecCertificateRef certificate
,
1072 const SecCertificateExtension
*extn
) {
1073 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1078 InhibitAnyPolicy ::= SkipCerts
1080 SkipCerts ::= INTEGER (0..MAX)
1082 static bool SecCEPInhibitAnyPolicy(SecCertificateRef certificate
,
1083 const SecCertificateExtension
*extn
) {
1084 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1085 DERDecodedInfo iapContent
;
1086 require_noerr_quiet(DERDecodeItem(&extn
->extnValue
, &iapContent
), badDER
);
1087 require_quiet(iapContent
.tag
== ASN1_INTEGER
, badDER
);
1088 require_noerr_quiet(DERParseInteger(
1089 &iapContent
.content
,
1090 &certificate
->_inhibitAnyPolicySkipCerts
.skipCerts
), badDER
);
1092 certificate
->_inhibitAnyPolicySkipCerts
.present
= true;
1093 certificate
->_inhibitAnyPolicySkipCerts
.critical
= extn
->critical
;
1096 certificate
->_inhibitAnyPolicySkipCerts
.present
= false;
1097 secwarning("Invalid InhibitAnyPolicy Extension");
1102 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
1104 AuthorityInfoAccessSyntax ::=
1105 SEQUENCE SIZE (1..MAX) OF AccessDescription
1107 AccessDescription ::= SEQUENCE {
1108 accessMethod OBJECT IDENTIFIER,
1109 accessLocation GeneralName }
1111 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
1113 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
1115 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
1117 static bool SecCEPAuthorityInfoAccess(SecCertificateRef certificate
,
1118 const SecCertificateExtension
*extn
) {
1119 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1122 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &adSeq
);
1123 require_noerr_quiet(drtn
, badDER
);
1124 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1125 DERDecodedInfo adContent
;
1126 while ((drtn
= DERDecodeSeqNext(&adSeq
, &adContent
)) == DR_Success
) {
1127 require_quiet(adContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1128 DERAccessDescription ad
;
1129 drtn
= DERParseSequenceContent(&adContent
.content
,
1130 DERNumAccessDescriptionItemSpecs
,
1131 DERAccessDescriptionItemSpecs
,
1133 require_noerr_quiet(drtn
, badDER
);
1134 CFMutableArrayRef
*urls
;
1135 if (DEROidCompare(&ad
.accessMethod
, &oidAdOCSP
))
1136 urls
= &certificate
->_ocspResponders
;
1137 else if (DEROidCompare(&ad
.accessMethod
, &oidAdCAIssuer
))
1138 urls
= &certificate
->_caIssuers
;
1142 DERDecodedInfo generalNameContent
;
1143 drtn
= DERDecodeItem(&ad
.accessLocation
, &generalNameContent
);
1144 require_noerr_quiet(drtn
, badDER
);
1145 switch (generalNameContent
.tag
) {
1147 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
1148 /* Technically I don't think this is valid, but there are certs out
1149 in the wild that use a constructed IA5String. In particular the
1150 VeriSign Time Stamping Authority CA.cer does this. */
1152 case ASN1_CONTEXT_SPECIFIC
| 6:
1154 CFURLRef url
= CFURLCreateWithBytes(kCFAllocatorDefault
,
1155 generalNameContent
.content
.data
, generalNameContent
.content
.length
,
1156 kCFStringEncodingASCII
, NULL
);
1159 *urls
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1160 CFArrayAppendValue(*urls
, url
);
1166 secdebug("cert", "bad general name for id-ad-ocsp AccessDescription t: 0x%02llx v: %.*s",
1167 generalNameContent
.tag
, (int) generalNameContent
.content
.length
, generalNameContent
.content
.data
);
1172 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
1175 secwarning("Invalid Authority Information Access extension");
1179 /* Apple Worldwide Developer Relations Certificate Authority subject name.
1180 * This is a DER sequence with the leading tag and length bytes removed,
1181 * to match what tbsCert.issuer contains.
1183 static const unsigned char Apple_WWDR_CA_Subject_Name
[]={
1184 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
1185 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
1186 0x20,0x49,0x6E,0x63,0x2E,0x31,0x2C,0x30,0x2A,0x06,0x03,0x55,0x04,0x0B,0x0C,0x23,
1187 0x41,0x70,0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20,
1188 0x44,0x65,0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,
1189 0x6F,0x6E,0x73,0x31,0x44,0x30,0x42,0x06,0x03,0x55,0x04,0x03,0x0C,0x3B,0x41,0x70,
1190 0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20,0x44,0x65,
1191 0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,0x6F,0x6E,
1192 0x73,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,
1193 0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79
1196 static void checkForMissingRevocationInfo(SecCertificateRef certificate
) {
1198 certificate
->_crlDistributionPoints
||
1199 certificate
->_ocspResponders
) {
1200 /* We already have an OCSP or CRL URI (or no cert) */
1203 /* Specify an appropriate OCSP responder if we recognize the issuer. */
1204 CFURLRef url
= NULL
;
1205 if (sizeof(Apple_WWDR_CA_Subject_Name
) == certificate
->_issuer
.length
&&
1206 !memcmp(certificate
->_issuer
.data
, Apple_WWDR_CA_Subject_Name
,
1207 sizeof(Apple_WWDR_CA_Subject_Name
))) {
1208 const char *WWDR_OCSP_URI
= "http://ocsp.apple.com/ocsp-wwdr01";
1209 url
= CFURLCreateWithBytes(kCFAllocatorDefault
,
1210 (const UInt8
*)WWDR_OCSP_URI
, strlen(WWDR_OCSP_URI
),
1211 kCFStringEncodingASCII
, NULL
);
1214 CFMutableArrayRef
*urls
= &certificate
->_ocspResponders
;
1215 *urls
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1216 CFArrayAppendValue(*urls
, url
);
1221 static bool SecCEPSubjectInfoAccess(SecCertificateRef certificate
,
1222 const SecCertificateExtension
*extn
) {
1223 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1227 static bool SecCEPNetscapeCertType(SecCertificateRef certificate
,
1228 const SecCertificateExtension
*extn
) {
1229 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1233 static bool SecCEPEntrustVersInfo(SecCertificateRef certificate
,
1234 const SecCertificateExtension
*extn
) {
1235 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1239 static bool SecCEPEscrowMarker(SecCertificateRef certificate
,
1240 const SecCertificateExtension
*extn
) {
1241 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1246 /* Dictionary key callback for comparing to DERItems. */
1247 static Boolean
SecDERItemEqual(const void *value1
, const void *value2
) {
1248 return DEROidCompare((const DERItem
*)value1
, (const DERItem
*)value2
);
1251 /* Dictionary key callback calculating the hash of a DERItem. */
1252 static CFHashCode
SecDERItemHash(const void *value
) {
1253 const DERItem
*derItem
= (const DERItem
*)value
;
1254 CFHashCode hash
= derItem
->length
;
1255 DERSize ix
= derItem
->length
> 8 ? derItem
->length
- 8 : 0;
1256 for (; ix
< derItem
->length
; ++ix
) {
1257 hash
= (hash
<< 9) + (hash
>> 23) + derItem
->data
[ix
];
1263 /* Dictionary key callbacks using the above 2 functions. */
1264 static const CFDictionaryKeyCallBacks SecDERItemKeyCallBacks
= {
1268 NULL
, /* copyDescription */
1269 SecDERItemEqual
, /* equal */
1270 SecDERItemHash
/* hash */
1273 static void SecCertificateInitializeExtensionParsers(void) {
1274 /* Build a dictionary that maps from extension OIDs to callback functions
1275 which can parse the extension of the type given. */
1276 static const void *extnOIDs
[] = {
1277 &oidSubjectKeyIdentifier
,
1279 &oidPrivateKeyUsagePeriod
,
1282 &oidBasicConstraints
,
1283 &oidNameConstraints
,
1284 &oidCrlDistributionPoints
,
1285 &oidCertificatePolicies
,
1287 &oidAuthorityKeyIdentifier
,
1288 &oidPolicyConstraints
,
1289 &oidExtendedKeyUsage
,
1290 &oidInhibitAnyPolicy
,
1291 &oidAuthorityInfoAccess
,
1292 &oidSubjectInfoAccess
,
1293 &oidNetscapeCertType
,
1294 &oidEntrustVersInfo
,
1295 &oidApplePolicyEscrowService
1297 static const void *extnParsers
[] = {
1298 SecCEPSubjectKeyIdentifier
,
1300 SecCEPPrivateKeyUsagePeriod
,
1301 SecCEPSubjectAltName
,
1302 SecCEPIssuerAltName
,
1303 SecCEPBasicConstraints
,
1304 SecCEPNameConstraints
,
1305 SecCEPCrlDistributionPoints
,
1306 SecCEPCertificatePolicies
,
1307 SecCEPPolicyMappings
,
1308 SecCEPAuthorityKeyIdentifier
,
1309 SecCEPPolicyConstraints
,
1310 SecCEPExtendedKeyUsage
,
1311 SecCEPInhibitAnyPolicy
,
1312 SecCEPAuthorityInfoAccess
,
1313 SecCEPSubjectInfoAccess
,
1314 SecCEPNetscapeCertType
,
1315 SecCEPEntrustVersInfo
,
1318 sExtensionParsers
= CFDictionaryCreate(kCFAllocatorDefault
, extnOIDs
,
1319 extnParsers
, array_size(extnOIDs
),
1320 &SecDERItemKeyCallBacks
, NULL
);
1323 CFGiblisWithFunctions(SecCertificate
, NULL
, NULL
, SecCertificateDestroy
, SecCertificateEqual
, SecCertificateHash
, NULL
, SecCertificateCopyDescription
, NULL
, NULL
, ^{
1324 SecCertificateInitializeExtensionParsers();
1327 static bool isAppleExtensionOID(const DERItem
*extnID
)
1329 static const uint8_t appleExtension
[8] = { 0x2a,0x86,0x48,0x86,0xf7,0x63,0x64,0x06 };
1330 return (extnID
&& extnID
->data
&&
1331 extnID
->length
> sizeof(appleExtension
) &&
1332 !memcmp(extnID
->data
, appleExtension
, sizeof(appleExtension
)));
1335 /* Given the contents of an X.501 Name return the contents of a normalized
1337 CFDataRef
createNormalizedX501Name(CFAllocatorRef allocator
,
1338 const DERItem
*x501name
) {
1339 CFMutableDataRef result
= CFDataCreateMutable(allocator
, x501name
->length
);
1340 CFIndex length
= x501name
->length
;
1341 CFDataSetLength(result
, length
);
1342 UInt8
*base
= CFDataGetMutableBytePtr(result
);
1345 DERReturn drtn
= DERDecodeSeqContentInit(x501name
, &rdnSeq
);
1347 require_noerr_quiet(drtn
, badDER
);
1350 /* Always points to last rdn tag. */
1351 const DERByte
*rdnTag
= rdnSeq
.nextItem
;
1352 /* Offset relative to base of current rdn set tag. */
1353 CFIndex rdnTagLocation
= 0;
1354 while ((drtn
= DERDecodeSeqNext(&rdnSeq
, &rdn
)) == DR_Success
) {
1355 require_quiet(rdn
.tag
== ASN1_CONSTR_SET
, badDER
);
1356 /* We don't allow empty RDNs. */
1357 require_quiet(rdn
.content
.length
!= 0, badDER
);
1358 /* Length of the tag and length of the current rdn. */
1359 CFIndex rdnTLLength
= rdn
.content
.data
- rdnTag
;
1360 CFIndex rdnContentLength
= rdn
.content
.length
;
1361 /* Copy the tag and length of the RDN. */
1362 memcpy(base
+ rdnTagLocation
, rdnTag
, rdnTLLength
);
1365 drtn
= DERDecodeSeqContentInit(&rdn
.content
, &atvSeq
);
1366 require_quiet(drtn
== DR_Success
, badDER
);
1369 /* Always points to tag of current atv sequence. */
1370 const DERByte
*atvTag
= atvSeq
.nextItem
;
1371 /* Offset relative to base of current atv sequence tag. */
1372 CFIndex atvTagLocation
= rdnTagLocation
+ rdnTLLength
;
1373 while ((drtn
= DERDecodeSeqNext(&atvSeq
, &atv
)) == DR_Success
) {
1374 require_quiet(atv
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1375 /* Length of the tag and length of the current atv. */
1376 CFIndex atvTLLength
= atv
.content
.data
- atvTag
;
1377 CFIndex atvContentLength
= atv
.content
.length
;
1378 /* Copy the tag and length of the atv and the atv itself. */
1379 memcpy(base
+ atvTagLocation
, atvTag
,
1380 atvTLLength
+ atv
.content
.length
);
1382 /* Now decode the atv sequence. */
1383 DERAttributeTypeAndValue atvPair
;
1384 drtn
= DERParseSequenceContent(&atv
.content
,
1385 DERNumAttributeTypeAndValueItemSpecs
,
1386 DERAttributeTypeAndValueItemSpecs
,
1387 &atvPair
, sizeof(atvPair
));
1388 require_noerr_quiet(drtn
, badDER
);
1389 require_quiet(atvPair
.type
.length
!= 0, badDER
);
1390 DERDecodedInfo value
;
1391 drtn
= DERDecodeItem(&atvPair
.value
, &value
);
1392 require_noerr_quiet(drtn
, badDER
);
1394 /* (c) attribute values in PrintableString are not case sensitive
1395 (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and
1397 (d) attribute values in PrintableString are compared after
1398 removing leading and trailing white space and converting internal
1399 substrings of one or more consecutive white space characters to a
1401 if (value
.tag
== ASN1_PRINTABLE_STRING
) {
1402 /* Offset relative to base of current value tag. */
1403 CFIndex valueTagLocation
= atvTagLocation
+ atvPair
.value
.data
- atvTag
;
1404 CFIndex valueTLLength
= value
.content
.data
- atvPair
.value
.data
;
1405 CFIndex valueContentLength
= value
.content
.length
;
1407 /* Now copy all the bytes, but convert to upper case while
1408 doing so and convert multiple whitespace chars into a
1410 bool lastWasBlank
= false;
1411 CFIndex valueLocation
= valueTagLocation
+ valueTLLength
;
1412 CFIndex valueCurrentLocation
= valueLocation
;
1414 for (ix
= 0; ix
< valueContentLength
; ++ix
) {
1415 UInt8 ch
= value
.content
.data
[ix
];
1420 /* Don't insert a space for first character
1422 if (valueCurrentLocation
> valueLocation
) {
1423 base
[valueCurrentLocation
++] = ' ';
1425 lastWasBlank
= true;
1428 lastWasBlank
= false;
1429 if ('a' <= ch
&& ch
<= 'z') {
1430 base
[valueCurrentLocation
++] = ch
+ 'A' - 'a';
1432 base
[valueCurrentLocation
++] = ch
;
1436 /* Finally if lastWasBlank remove the trailing space. */
1437 if (lastWasBlank
&& valueCurrentLocation
> valueLocation
) {
1438 valueCurrentLocation
--;
1440 /* Adjust content length to normalized length. */
1441 valueContentLength
= valueCurrentLocation
- valueLocation
;
1443 /* Number of bytes by which the length should be shorted. */
1444 CFIndex lengthDiff
= value
.content
.length
- valueContentLength
;
1445 if (lengthDiff
== 0) {
1446 /* Easy case no need to adjust lengths. */
1448 /* Hard work we need to go back and fix up length fields
1450 1) The value itself.
1451 2) The ATV Sequence containing type/value
1452 3) The RDN Set containing one or more atv pairs.
1456 /* Step 1 fix up length of value. */
1457 /* Length of value tag and length minus the tag. */
1458 DERSize newValueTLLength
= valueTLLength
- 1;
1459 drtn
= DEREncodeLength(valueContentLength
,
1460 base
+ valueTagLocation
+ 1, &newValueTLLength
);
1461 require(drtn
== DR_Success
, badDER
);
1462 /* Add the length of the tag back in. */
1464 CFIndex valueLLDiff
= valueTLLength
- newValueTLLength
;
1466 /* The size of the length field changed, let's slide
1467 the value back by valueLLDiff bytes. */
1468 memmove(base
+ valueTagLocation
+ newValueTLLength
,
1469 base
+ valueTagLocation
+ valueTLLength
,
1470 valueContentLength
);
1471 /* The length diff for the enclosing object. */
1472 lengthDiff
+= valueLLDiff
;
1475 /* Step 2 fix up length of the enclosing ATV Sequence. */
1476 atvContentLength
-= lengthDiff
;
1477 DERSize newATVTLLength
= atvTLLength
- 1;
1478 drtn
= DEREncodeLength(atvContentLength
,
1479 base
+ atvTagLocation
+ 1, &newATVTLLength
);
1480 require(drtn
== DR_Success
, badDER
);
1481 /* Add the length of the tag back in. */
1483 CFIndex atvLLDiff
= atvTLLength
- newATVTLLength
;
1485 /* The size of the length field changed, let's slide
1486 the value back by valueLLDiff bytes. */
1487 memmove(base
+ atvTagLocation
+ newATVTLLength
,
1488 base
+ atvTagLocation
+ atvTLLength
,
1490 /* The length diff for the enclosing object. */
1491 lengthDiff
+= atvLLDiff
;
1492 atvTLLength
= newATVTLLength
;
1495 /* Step 3 fix up length of enclosing RDN Set. */
1496 rdnContentLength
-= lengthDiff
;
1497 DERSize newRDNTLLength
= rdnTLLength
- 1;
1498 drtn
= DEREncodeLength(rdnContentLength
,
1499 base
+ rdnTagLocation
+ 1, &newRDNTLLength
);
1500 require_quiet(drtn
== DR_Success
, badDER
);
1501 /* Add the length of the tag back in. */
1503 CFIndex rdnLLDiff
= rdnTLLength
- newRDNTLLength
;
1505 /* The size of the length field changed, let's slide
1506 the value back by valueLLDiff bytes. */
1507 memmove(base
+ rdnTagLocation
+ newRDNTLLength
,
1508 base
+ rdnTagLocation
+ rdnTLLength
,
1510 /* The length diff for the enclosing object. */
1511 lengthDiff
+= rdnLLDiff
;
1512 rdnTLLength
= newRDNTLLength
;
1514 /* Adjust the locations that might have changed due to
1516 atvTagLocation
-= rdnLLDiff
;
1518 (void) lengthDiff
; // No next object, silence analyzer
1521 atvTagLocation
+= atvTLLength
+ atvContentLength
;
1522 atvTag
= atvSeq
.nextItem
;
1524 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
1525 rdnTagLocation
+= rdnTLLength
+ rdnContentLength
;
1526 rdnTag
= rdnSeq
.nextItem
;
1528 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
1529 /* Truncate the result to the proper length. */
1530 CFDataSetLength(result
, rdnTagLocation
);
1539 static CFDataRef
SecDERItemCopySequence(DERItem
*content
) {
1540 DERSize seq_len_length
= DERLengthOfLength(content
->length
);
1541 size_t sequence_length
= 1 + seq_len_length
+ content
->length
;
1542 CFMutableDataRef sequence
= CFDataCreateMutable(kCFAllocatorDefault
,
1544 CFDataSetLength(sequence
, sequence_length
);
1545 uint8_t *sequence_ptr
= CFDataGetMutableBytePtr(sequence
);
1546 *sequence_ptr
++ = ONE_BYTE_ASN1_CONSTR_SEQUENCE
;
1547 require_noerr_quiet(DEREncodeLength(content
->length
,
1548 sequence_ptr
, &seq_len_length
), out
);
1549 sequence_ptr
+= seq_len_length
;
1550 memcpy(sequence_ptr
, content
->data
, content
->length
);
1553 CFReleaseSafe(sequence
);
1557 static CFDataRef
SecCopySequenceFromContent(CFDataRef content
) {
1559 tmpItem
.data
= (void *)CFDataGetBytePtr(content
);
1560 tmpItem
.length
= CFDataGetLength(content
);
1562 return SecDERItemCopySequence(&tmpItem
);
1565 CFDataRef
SecDistinguishedNameCopyNormalizedContent(CFDataRef distinguished_name
)
1567 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(distinguished_name
), CFDataGetLength(distinguished_name
) };
1568 DERDecodedInfo content
;
1569 /* Decode top level sequence into DERItem */
1570 if (!DERDecodeItem(&name
, &content
) && (content
.tag
== ASN1_CONSTR_SEQUENCE
))
1571 return createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1575 CFDataRef
SecDistinguishedNameCopyNormalizedSequence(CFDataRef distinguished_name
)
1577 if (!distinguished_name
) { return NULL
; }
1578 CFDataRef normalizedContent
= SecDistinguishedNameCopyNormalizedContent(distinguished_name
);
1579 if (!normalizedContent
) { return NULL
; }
1580 CFDataRef result
= SecCopySequenceFromContent(normalizedContent
);
1581 CFReleaseNull(normalizedContent
);
1585 /* AUDIT[securityd]:
1586 certificate->_der is a caller provided data of any length (might be 0).
1588 Top level certificate decode.
1590 static bool SecCertificateParse(SecCertificateRef certificate
)
1595 require_quiet(certificate
, badCert
);
1596 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
1598 /* top level decode */
1599 DERSignedCertCrl signedCert
;
1600 drtn
= DERParseSequence(&certificate
->_der
, DERNumSignedCertCrlItemSpecs
,
1601 DERSignedCertCrlItemSpecs
, &signedCert
,
1602 sizeof(signedCert
));
1603 require_noerr_quiet(drtn
, badCert
);
1604 /* Store tbs since we need to digest it for verification later on. */
1605 certificate
->_tbs
= signedCert
.tbs
;
1607 /* decode the TBSCert - it was saved in full DER form */
1609 drtn
= DERParseSequence(&signedCert
.tbs
,
1610 DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
,
1611 &tbsCert
, sizeof(tbsCert
));
1612 require_noerr_quiet(drtn
, badCert
);
1614 /* sequence we're given: decode the signedCerts Signature Algorithm. */
1615 /* This MUST be the same as the certificate->_tbsSigAlg with the exception
1616 of the params field. */
1617 drtn
= DERParseSequenceContent(&signedCert
.sigAlg
,
1618 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
1619 &certificate
->_sigAlg
, sizeof(certificate
->_sigAlg
));
1620 require_noerr_quiet(drtn
, badCert
);
1622 /* The contents of signedCert.sig is a bit string whose contents
1623 are the signature itself. */
1624 DERByte numUnusedBits
;
1625 drtn
= DERParseBitString(&signedCert
.sig
,
1626 &certificate
->_signature
, &numUnusedBits
);
1627 require_noerr_quiet(drtn
, badCert
);
1629 /* Now decode the tbsCert. */
1631 /* First we turn the optional version into an int. */
1632 if (tbsCert
.version
.length
) {
1633 DERDecodedInfo decoded
;
1634 drtn
= DERDecodeItem(&tbsCert
.version
, &decoded
);
1635 require_noerr_quiet(drtn
, badCert
);
1636 require_quiet(decoded
.tag
== ASN1_INTEGER
, badCert
);
1637 require_quiet(decoded
.content
.length
== 1, badCert
);
1638 certificate
->_version
= decoded
.content
.data
[0];
1639 if (certificate
->_version
> 2) {
1640 secwarning("Invalid certificate version (%d), must be 0..2",
1641 certificate
->_version
);
1643 require_quiet(certificate
->_version
> 0, badCert
);
1644 require_quiet(certificate
->_version
< 3, badCert
);
1646 certificate
->_version
= 0;
1649 /* The serial number is in the tbsCert.serialNum - it was saved in
1650 INTEGER form without the tag and length. */
1651 certificate
->_serialNum
= tbsCert
.serialNum
;
1653 /* Note: RFC5280 4.1.2.2 limits serial number values to 20 octets.
1654 For now, we warn about larger values, but will still create the
1655 certificate with values up to 36 octets to avoid breaking some
1656 nonconforming certs with slightly longer serial numbers.
1657 We also explicitly allow serial numbers of 21 octets where the
1658 leading byte is 0x00 which is used to make a negative 20 octet
1661 if (tbsCert
.serialNum
.length
< 1 || tbsCert
.serialNum
.length
> 21 ||
1662 (tbsCert
.serialNum
.length
== 21 && tbsCert
.serialNum
.data
[0] != 0x00)) {
1663 secwarning("Invalid serial number length (%ld), must be 1..20",
1664 tbsCert
.serialNum
.length
);
1666 require_quiet(tbsCert
.serialNum
.data
!= NULL
&&
1667 tbsCert
.serialNum
.length
>= 1 &&
1668 tbsCert
.serialNum
.length
<= 36, badCert
);
1669 certificate
->_serialNumber
= CFDataCreate(allocator
,
1670 tbsCert
.serialNum
.data
, tbsCert
.serialNum
.length
);
1672 /* sequence we're given: decode the tbsCerts TBS Signature Algorithm. */
1673 drtn
= DERParseSequenceContent(&tbsCert
.tbsSigAlg
,
1674 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
1675 &certificate
->_tbsSigAlg
, sizeof(certificate
->_tbsSigAlg
));
1676 require_noerr_quiet(drtn
, badCert
);
1678 /* The issuer is in the tbsCert.issuer - it's a sequence without the tag
1679 and length fields. */
1680 certificate
->_issuer
= tbsCert
.issuer
;
1681 certificate
->_normalizedIssuer
= createNormalizedX501Name(allocator
,
1684 /* sequence we're given: decode the tbsCerts Validity sequence. */
1685 DERValidity validity
;
1686 drtn
= DERParseSequenceContent(&tbsCert
.validity
,
1687 DERNumValidityItemSpecs
, DERValidityItemSpecs
,
1688 &validity
, sizeof(validity
));
1689 require_noerr_quiet(drtn
, badCert
);
1690 require_quiet(derDateGetAbsoluteTime(&validity
.notBefore
,
1691 &certificate
->_notBefore
), badCert
);
1692 require_quiet(derDateGetAbsoluteTime(&validity
.notAfter
,
1693 &certificate
->_notAfter
), badCert
);
1695 /* The subject is in the tbsCert.subject - it's a sequence without the tag
1696 and length fields. */
1697 certificate
->_subject
= tbsCert
.subject
;
1698 certificate
->_normalizedSubject
= createNormalizedX501Name(allocator
,
1701 /* Keep the SPKI around for CT */
1702 certificate
->_subjectPublicKeyInfo
= tbsCert
.subjectPubKey
;
1704 /* sequence we're given: encoded DERSubjPubKeyInfo - it was saved in full DER form */
1705 DERSubjPubKeyInfo pubKeyInfo
;
1706 drtn
= DERParseSequence(&tbsCert
.subjectPubKey
,
1707 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
1708 &pubKeyInfo
, sizeof(pubKeyInfo
));
1709 require_noerr_quiet(drtn
, badCert
);
1711 /* sequence we're given: decode the pubKeyInfos DERAlgorithmId */
1712 drtn
= DERParseSequenceContent(&pubKeyInfo
.algId
,
1713 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
1714 &certificate
->_algId
, sizeof(certificate
->_algId
));
1715 require_noerr_quiet(drtn
, badCert
);
1717 /* Now we can figure out the key's algorithm id and params based on
1718 certificate->_algId.oid. */
1720 /* The contents of pubKeyInfo.pubKey is a bit string whose contents
1721 are a PKCS1 format RSA key. */
1722 drtn
= DERParseBitString(&pubKeyInfo
.pubKey
,
1723 &certificate
->_pubKeyDER
, &numUnusedBits
);
1724 require_noerr_quiet(drtn
, badCert
);
1726 /* The contents of tbsCert.issuerID is a bit string. */
1727 certificate
->_issuerUniqueID
= tbsCert
.issuerID
;
1729 /* The contents of tbsCert.subjectID is a bit string. */
1730 certificate
->_subjectUniqueID
= tbsCert
.subjectID
;
1733 if (tbsCert
.extensions
.length
) {
1734 CFIndex extensionCount
= 0;
1737 drtn
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
,
1739 require_noerr_quiet(drtn
, badCert
);
1740 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badCert
);
1741 DERDecodedInfo currDecoded
;
1742 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
1744 /* ! = MUST recognize ? = SHOULD recognize
1747 KnownExtension _subjectKeyID
; /* ?SubjectKeyIdentifier id-ce 14 */
1748 KnownExtension _keyUsage
; /* !KeyUsage id-ce 15 */
1749 KnownExtension _subjectAltName
; /* !SubjectAltName id-ce 17 */
1750 KnownExtension _basicConstraints
; /* !BasicConstraints id-ce 19 */
1751 KnownExtension _authorityKeyID
; /* ?AuthorityKeyIdentifier id-ce 35 */
1752 KnownExtension _extKeyUsage
; /* !ExtKeyUsage id-ce 37 */
1753 KnownExtension _netscapeCertType
; /* 2.16.840.1.113730.1.1 netscape 1 1 */
1754 KnownExtension _qualCertStatements
; /* QCStatements id-pe 3 */
1756 KnownExtension _issuerAltName
; /* IssuerAltName id-ce 18 */
1757 KnownExtension _nameConstraints
; /* !NameConstraints id-ce 30 */
1758 KnownExtension _cRLDistributionPoints
; /* CRLDistributionPoints id-ce 31 */
1759 KnownExtension _certificatePolicies
; /* !CertificatePolicies id-ce 32 */
1760 KnownExtension _policyMappings
; /* ?PolicyMappings id-ce 33 */
1761 KnownExtension _policyConstraints
; /* !PolicyConstraints id-ce 36 */
1762 KnownExtension _freshestCRL
; /* FreshestCRL id-ce 46 */
1763 KnownExtension _inhibitAnyPolicy
; /* !InhibitAnyPolicy id-ce 54 */
1765 KnownExtension _authorityInfoAccess
; /* AuthorityInfoAccess id-pe 1 */
1766 KnownExtension _subjectInfoAccess
; /* SubjectInfoAccess id-pe 11 */
1771 require_quiet(drtn
== DR_EndOfSequence
, badCert
);
1773 /* Put some upper limit on the number of extensions allowed. */
1774 require_quiet(extensionCount
< 10000, badCert
);
1775 certificate
->_extensionCount
= extensionCount
;
1776 certificate
->_extensions
=
1777 malloc(sizeof(SecCertificateExtension
) * (extensionCount
> 0 ? extensionCount
: 1));
1778 require_quiet(certificate
->_extensions
, badCert
);
1781 drtn
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
, &derSeq
);
1782 require_noerr_quiet(drtn
, badCert
);
1783 for (ix
= 0; ix
< extensionCount
; ++ix
) {
1784 drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
);
1785 require_quiet(drtn
== DR_Success
||
1786 (ix
== extensionCount
- 1 && drtn
== DR_EndOfSequence
), badCert
);
1787 require_quiet(currDecoded
.tag
== ASN1_CONSTR_SEQUENCE
, badCert
);
1789 drtn
= DERParseSequenceContent(&currDecoded
.content
,
1790 DERNumExtensionItemSpecs
, DERExtensionItemSpecs
,
1791 &extn
, sizeof(extn
));
1792 require_noerr_quiet(drtn
, badCert
);
1793 /* Copy stuff into certificate->extensions[ix]. */
1794 certificate
->_extensions
[ix
].extnID
= extn
.extnID
;
1795 require_noerr_quiet(drtn
= DERParseBooleanWithDefault(&extn
.critical
, false,
1796 &certificate
->_extensions
[ix
].critical
), badCert
);
1797 certificate
->_extensions
[ix
].extnValue
= extn
.extnValue
;
1799 SecCertificateExtensionParser parser
=
1800 (SecCertificateExtensionParser
)CFDictionaryGetValue(
1801 sExtensionParsers
, &certificate
->_extensions
[ix
].extnID
);
1803 /* Invoke the parser. If the extension is critical and the
1804 * parser fails, fail the cert. */
1805 require_quiet(parser(certificate
, &certificate
->_extensions
[ix
]) ||
1806 !certificate
->_extensions
[ix
].critical
, badCert
);
1807 } else if (certificate
->_extensions
[ix
].critical
) {
1808 if (isAppleExtensionOID(&extn
.extnID
)) {
1811 secdebug("cert", "Found unknown critical extension");
1812 certificate
->_foundUnknownCriticalExtension
= true;
1814 secdebug("cert", "Found unknown non critical extension");
1818 checkForMissingRevocationInfo(certificate
);
1827 /* Public API functions. */
1828 SecCertificateRef
SecCertificateCreateWithBytes(CFAllocatorRef allocator
,
1829 const UInt8
*der_bytes
, CFIndex der_length
) {
1830 if (der_bytes
== NULL
) return NULL
;
1831 if (der_length
== 0) return NULL
;
1833 CFIndex size
= sizeof(struct __SecCertificate
) + der_length
;
1834 SecCertificateRef result
= (SecCertificateRef
)_CFRuntimeCreateInstance(
1835 allocator
, SecCertificateGetTypeID(), size
- sizeof(CFRuntimeBase
), 0);
1837 memset((char*)result
+ sizeof(result
->_base
), 0,
1838 sizeof(*result
) - sizeof(result
->_base
));
1839 result
->_der
.data
= ((DERByte
*)result
+ sizeof(*result
));
1840 result
->_der
.length
= der_length
;
1841 memcpy(result
->_der
.data
, der_bytes
, der_length
);
1842 if (!SecCertificateParse(result
)) {
1850 /* @@@ Placeholder until <rdar://problem/5701851> iap submits a binary is fixed. */
1851 SecCertificateRef
SecCertificateCreate(CFAllocatorRef allocator
,
1852 const UInt8
*der_bytes
, CFIndex der_length
);
1854 SecCertificateRef
SecCertificateCreate(CFAllocatorRef allocator
,
1855 const UInt8
*der_bytes
, CFIndex der_length
) {
1856 return SecCertificateCreateWithBytes(allocator
, der_bytes
, der_length
);
1858 /* @@@ End of placeholder. */
1860 /* AUDIT[securityd](done):
1861 der_certificate is a caller provided data of any length (might be 0), only
1862 its cf type has been checked.
1864 SecCertificateRef
SecCertificateCreateWithData(CFAllocatorRef allocator
,
1865 CFDataRef der_certificate
) {
1866 if (!der_certificate
) {
1869 CFIndex size
= sizeof(struct __SecCertificate
);
1870 SecCertificateRef result
= (SecCertificateRef
)_CFRuntimeCreateInstance(
1871 allocator
, SecCertificateGetTypeID(), size
- sizeof(CFRuntimeBase
), 0);
1873 memset((char*)result
+ sizeof(result
->_base
), 0, size
- sizeof(result
->_base
));
1874 result
->_der_data
= CFDataCreateCopy(allocator
, der_certificate
);
1875 result
->_der
.data
= (DERByte
*)CFDataGetBytePtr(result
->_der_data
);
1876 result
->_der
.length
= CFDataGetLength(result
->_der_data
);
1877 if (!SecCertificateParse(result
)) {
1885 SecCertificateRef
SecCertificateCreateWithKeychainItem(CFAllocatorRef allocator
,
1886 CFDataRef der_certificate
,
1887 CFTypeRef keychain_item
)
1889 SecCertificateRef result
= SecCertificateCreateWithData(allocator
, der_certificate
);
1891 CFRetainSafe(keychain_item
);
1892 result
->_keychain_item
= keychain_item
;
1897 OSStatus
SecCertificateSetKeychainItem(SecCertificateRef certificate
,
1898 CFTypeRef keychain_item
)
1903 CFRetainSafe(keychain_item
);
1904 CFReleaseSafe(certificate
->_keychain_item
);
1905 certificate
->_keychain_item
= keychain_item
;
1906 return errSecSuccess
;
1909 CFDataRef
SecCertificateCopyData(SecCertificateRef certificate
) {
1911 CFDataRef result
= NULL
;
1915 if (certificate
->_der_data
) {
1916 CFRetain(certificate
->_der_data
);
1917 result
= certificate
->_der_data
;
1919 result
= CFDataCreate(CFGetAllocator(certificate
),
1920 certificate
->_der
.data
, certificate
->_der
.length
);
1922 /* FIXME: If we wish to cache result we need to lock the certificate.
1923 Also this create 2 copies of the certificate data which is somewhat
1926 certificate
->_der_data
= result
;
1933 CFIndex
SecCertificateGetLength(SecCertificateRef certificate
) {
1934 return certificate
->_der
.length
;
1937 const UInt8
*SecCertificateGetBytePtr(SecCertificateRef certificate
) {
1938 return certificate
->_der
.data
;
1941 /* Used to recreate preCert from cert for Certificate Transparency */
1942 CFDataRef
SecCertificateCopyPrecertTBS(SecCertificateRef certificate
)
1944 CFDataRef outData
= NULL
;
1945 DERItem tbsIn
= certificate
->_tbs
;
1946 DERItem tbsOut
= {0,};
1947 DERItem extensionsOut
= {0,};
1948 DERItem
*extensionsList
= malloc(sizeof(DERItem
)*certificate
->_extensionCount
); /* This maybe one too many */
1949 DERItemSpec
*extensionsListSpecs
= malloc(sizeof(DERItemSpec
)*certificate
->_extensionCount
);
1953 require_quiet(extensionsList
&& extensionsListSpecs
, out
);
1955 /* decode the TBSCert - it was saved in full DER form */
1956 drtn
= DERParseSequence(&tbsIn
,
1957 DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
,
1958 &tbsCert
, sizeof(tbsCert
));
1959 require_noerr_quiet(drtn
, out
);
1961 /* Go over extensions and filter any SCT extension */
1962 CFIndex extensionsCount
= 0;
1964 if (tbsCert
.extensions
.length
) {
1967 drtn
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
,
1969 require_noerr_quiet(drtn
, out
);
1970 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, out
);
1971 DERDecodedInfo currDecoded
;
1972 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
1974 require_quiet(currDecoded
.tag
== ASN1_CONSTR_SEQUENCE
, out
);
1976 drtn
= DERParseSequenceContent(&currDecoded
.content
,
1977 DERNumExtensionItemSpecs
, DERExtensionItemSpecs
,
1978 &extn
, sizeof(extn
));
1979 require_noerr_quiet(drtn
, out
);
1981 if (extn
.extnID
.length
== oidGoogleEmbeddedSignedCertificateTimestamp
.length
&&
1982 !memcmp(extn
.extnID
.data
, oidGoogleEmbeddedSignedCertificateTimestamp
.data
, extn
.extnID
.length
))
1985 extensionsList
[extensionsCount
] = currDecoded
.content
;
1986 extensionsListSpecs
[extensionsCount
].offset
= sizeof(DERItem
)*extensionsCount
;
1987 extensionsListSpecs
[extensionsCount
].options
= 0;
1988 extensionsListSpecs
[extensionsCount
].tag
= ASN1_CONSTR_SEQUENCE
;
1993 require_quiet(drtn
== DR_EndOfSequence
, out
);
1997 /* Encode extensions */
1998 extensionsOut
.length
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, extensionsList
, extensionsCount
, extensionsListSpecs
);
1999 extensionsOut
.data
= malloc(extensionsOut
.length
);
2000 require_quiet(extensionsOut
.data
, out
);
2001 drtn
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, extensionsList
, extensionsCount
, extensionsListSpecs
, extensionsOut
.data
, &extensionsOut
.length
);
2002 require_noerr_quiet(drtn
, out
);
2004 tbsCert
.extensions
= extensionsOut
;
2006 tbsOut
.length
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &tbsCert
, DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
);
2007 tbsOut
.data
= malloc(tbsOut
.length
);
2008 require_quiet(tbsOut
.data
, out
);
2009 drtn
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &tbsCert
, DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
, tbsOut
.data
, &tbsOut
.length
);
2010 require_noerr_quiet(drtn
, out
);
2012 outData
= CFDataCreate(kCFAllocatorDefault
, tbsOut
.data
, tbsOut
.length
);
2015 if (extensionsOut
.data
) free(extensionsOut
.data
);
2016 if (tbsOut
.data
) free(tbsOut
.data
);
2017 if (extensionsList
) free(extensionsList
);
2018 if (extensionsListSpecs
) free(extensionsListSpecs
);
2023 /* From rfc3280 - Appendix B. ASN.1 Notes
2025 Object Identifiers (OIDs) are used throughout this specification to
2026 identify certificate policies, public key and signature algorithms,
2027 certificate extensions, etc. There is no maximum size for OIDs.
2028 This specification mandates support for OIDs which have arc elements
2029 with values that are less than 2^28, that is, they MUST be between 0
2030 and 268,435,455, inclusive. This allows each arc element to be
2031 represented within a single 32 bit word. Implementations MUST also
2032 support OIDs where the length of the dotted decimal (see [RFC 2252],
2033 section 4.1) string representation can be up to 100 bytes
2034 (inclusive). Implementations MUST be able to handle OIDs with up to
2035 20 elements (inclusive). CAs SHOULD NOT issue certificates which
2036 contain OIDs that exceed these requirements. Likewise, CRL issuers
2037 SHOULD NOT issue CRLs which contain OIDs that exceed these
2041 /* Oids longer than this are considered invalid. */
2042 #define MAX_OID_SIZE 32
2044 CFStringRef
SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator
,
2045 const DERItem
*oid
) {
2047 if (oid
->length
== 0) {
2048 return SecCopyCertString(SEC_NULL_KEY
);
2050 if (oid
->length
> MAX_OID_SIZE
) {
2051 return SecCopyCertString(SEC_OID_TOO_LONG_KEY
);
2054 CFMutableStringRef result
= CFStringCreateMutable(allocator
, 0);
2056 // The first two levels are encoded into one byte, since the root level
2057 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then
2058 // y may be > 39, so we have to add special-case handling for this.
2059 uint32_t x
= oid
->data
[0] / 40;
2060 uint32_t y
= oid
->data
[0] % 40;
2063 // Handle special case for large y if x = 2
2067 CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
);
2070 for (x
= 1; x
< oid
->length
; ++x
)
2072 value
= (value
<< 7) | (oid
->data
[x
] & 0x7F);
2073 /* @@@ value may not span more than 4 bytes. */
2074 /* A max number of 20 values is allowed. */
2075 if (!(oid
->data
[x
] & 0x80))
2077 CFStringAppendFormat(result
, NULL
, CFSTR(".%" PRIu32
), value
);
2084 static CFStringRef
copyLocalizedOidDescription(CFAllocatorRef allocator
,
2085 const DERItem
*oid
) {
2086 if (oid
->length
== 0) {
2087 return SecCopyCertString(SEC_NULL_KEY
);
2090 /* Build the key we use to lookup the localized OID description. */
2091 CFMutableStringRef oidKey
= CFStringCreateMutable(allocator
,
2092 oid
->length
* 3 + 5);
2093 CFStringAppendFormat(oidKey
, NULL
, CFSTR("06 %02lX"), oid
->length
);
2095 for (ix
= 0; ix
< oid
->length
; ++ix
)
2096 CFStringAppendFormat(oidKey
, NULL
, CFSTR(" %02X"), oid
->data
[ix
]);
2098 CFStringRef name
= SecFrameworkCopyLocalizedString(oidKey
, CFSTR("OID"));
2099 if (CFEqual(oidKey
, name
)) {
2101 name
= SecDERItemCopyOIDDecimalRepresentation(allocator
, oid
);
2108 /* Return the ipAddress as a dotted quad for ipv4 or as 8 colon separated
2109 4 digit hex strings for ipv6. Return NULL if the passed in IP doesn't
2110 have a length of exactly 4 or 16 octects. */
2111 static CFStringRef
copyIPAddressContentDescription(CFAllocatorRef allocator
,
2112 const DERItem
*ip
) {
2113 /* @@@ This is the IP Address as an OCTECT STRING. For IPv4 it's
2114 4 octects addr, or 8 octects, addr/mask for ipv6 it's
2115 16 octects addr, or 32 octects addr/mask. */
2116 CFStringRef value
= NULL
;
2117 if (ip
->length
== 4) {
2118 value
= CFStringCreateWithFormat(allocator
, NULL
,
2119 CFSTR("%u.%u.%u.%u"),
2120 ip
->data
[0], ip
->data
[1], ip
->data
[2], ip
->data
[3]);
2121 } else if (ip
->length
== 16) {
2122 value
= CFStringCreateWithFormat(allocator
, NULL
,
2123 CFSTR("%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
2124 "%02x%02x:%02x%02x:%02x%02x:%02x%02x"),
2125 ip
->data
[0], ip
->data
[1], ip
->data
[2], ip
->data
[3],
2126 ip
->data
[4], ip
->data
[5], ip
->data
[6], ip
->data
[7],
2127 ip
->data
[8], ip
->data
[9], ip
->data
[10], ip
->data
[11],
2128 ip
->data
[12], ip
->data
[13], ip
->data
[14], ip
->data
[15]);
2134 void appendProperty(CFMutableArrayRef properties
, CFStringRef propertyType
,
2135 CFStringRef label
, CFStringRef localizedLabel
, CFTypeRef value
) {
2136 CFDictionaryRef property
;
2139 if (localizedLabel
) {
2142 ll
= localizedLabel
= SecCopyCertString(label
);
2144 const void *all_keys
[4];
2145 all_keys
[0] = kSecPropertyKeyType
;
2146 all_keys
[1] = kSecPropertyKeyLabel
;
2147 all_keys
[2] = kSecPropertyKeyLocalizedLabel
;
2148 all_keys
[3] = kSecPropertyKeyValue
;
2149 const void *property_values
[] = {
2155 property
= CFDictionaryCreate(CFGetAllocator(properties
),
2156 all_keys
, property_values
, value
? 4 : 3,
2157 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2160 const void *nolabel_keys
[2];
2161 nolabel_keys
[0] = kSecPropertyKeyType
;
2162 nolabel_keys
[1] = kSecPropertyKeyValue
;
2163 const void *property_values
[] = {
2167 property
= CFDictionaryCreate(CFGetAllocator(properties
),
2168 nolabel_keys
, property_values
, 2,
2169 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2172 CFArrayAppendValue(properties
, property
);
2173 CFRelease(property
);
2177 #define UTC_TIME_NOSEC_ZULU_LEN 11
2179 #define UTC_TIME_ZULU_LEN 13
2180 /* YYMMDDhhmmssThhmm */
2181 #define UTC_TIME_LOCALIZED_LEN 17
2182 /* YYYYMMDDhhmmssZ */
2183 #define GENERALIZED_TIME_ZULU_LEN 15
2184 /* YYYYMMDDhhmmssThhmm */
2185 #define GENERALIZED_TIME_LOCALIZED_LEN 19
2187 /* Parse 2 digits at (*p)[0] and (*p)[1] and return the result. Also
2189 static inline int parseDecimalPair(const DERByte
**p
) {
2190 const DERByte
*cp
= *p
;
2192 return 10 * (cp
[0] - '0') + cp
[1] - '0';
2195 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime.
2196 Return a CFErrorRef in the error parameter if decoding fails.
2197 Note that this is needed to distinguish an error condition from a
2198 valid time which specifies 2001-01-01 00:00:00 (i.e. a value of 0).
2200 static CFAbsoluteTime
SecAbsoluteTimeFromDateContentWithError(DERTag tag
,
2201 const uint8_t *bytes
,
2203 CFErrorRef
*error
) {
2207 if (NULL
== bytes
|| 0 == length
) {
2211 bool isUtcLength
= false;
2212 bool isLocalized
= false;
2213 bool noSeconds
= false;
2215 case UTC_TIME_NOSEC_ZULU_LEN
: /* YYMMDDhhmmZ */
2219 case UTC_TIME_ZULU_LEN
: /* YYMMDDhhmmssZ */
2222 case GENERALIZED_TIME_ZULU_LEN
: /* YYYYMMDDhhmmssZ */
2224 case UTC_TIME_LOCALIZED_LEN
: /* YYMMDDhhmmssThhmm (where T=[+,-]) */
2227 case GENERALIZED_TIME_LOCALIZED_LEN
:/* YYYYMMDDhhmmssThhmm (where T=[+,-]) */
2230 default: /* unknown format */
2234 /* Make sure the der tag fits the thing inside it. */
2235 if (tag
== ASN1_UTC_TIME
) {
2239 } else if (tag
== ASN1_GENERALIZED_TIME
) {
2247 const DERByte
*cp
= bytes
;
2248 /* Check that all characters are digits, except if localized the timezone
2249 indicator or if not localized the 'Z' at the end. */
2251 for (ix
= 0; ix
< length
; ++ix
) {
2252 if (!(isdigit(cp
[ix
]))) {
2253 if ((isLocalized
&& ix
== length
- 5 &&
2254 (cp
[ix
] == '+' || cp
[ix
] == '-')) ||
2255 (!isLocalized
&& ix
== length
- 1 && cp
[ix
] == 'Z')) {
2262 /* Parse the date and time fields. */
2263 int year
, month
, day
, hour
, minute
, second
;
2265 year
= parseDecimalPair(&cp
);
2267 /* 0 <= year < 50 : assume century 21 */
2269 } else if (year
< 70) {
2270 /* 50 <= year < 70 : illegal per PKIX */
2273 /* 70 < year <= 99 : assume century 20 */
2277 year
= 100 * parseDecimalPair(&cp
) + parseDecimalPair(&cp
);
2279 month
= parseDecimalPair(&cp
);
2280 day
= parseDecimalPair(&cp
);
2281 hour
= parseDecimalPair(&cp
);
2282 minute
= parseDecimalPair(&cp
);
2286 second
= parseDecimalPair(&cp
);
2289 CFTimeInterval timeZoneOffset
;
2291 /* ZONE INDICATOR */
2292 int multiplier
= *cp
++ == '+' ? 60 : -60;
2293 timeZoneOffset
= multiplier
*
2294 (parseDecimalPair(&cp
) * 60 + parseDecimalPair(&cp
));
2299 secdebug("dateparse",
2300 "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g",
2301 (int) length
, bytes
, year
, month
,
2302 day
, hour
, minute
, second
,
2303 timeZoneOffset
/ 60);
2305 static int mdays
[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
2306 int is_leap_year
= year
% 4 == 0 && (year
% 100 != 0 || year
% 400 == 0) ? 1 : 0;
2307 if (month
< 1 || month
> 12 || day
< 1 || day
> 31 || hour
> 23 || minute
> 59 || second
> 59
2308 || (month
== 2 && day
> mdays
[month
] - mdays
[month
- 1] + is_leap_year
)
2309 || (month
!= 2 && day
> mdays
[month
] - mdays
[month
- 1])) {
2314 int dy
= year
- 2001;
2319 int leap_days
= dy
/ 4 - dy
/ 100 + dy
/ 400;
2320 day
+= ((year
- 2001) * 365 + leap_days
) + mdays
[month
- 1] - 1;
2322 day
+= is_leap_year
;
2324 CFAbsoluteTime absTime
= (CFAbsoluteTime
)((day
* 24.0 + hour
) * 60.0 + minute
) * 60.0 + second
;
2325 return absTime
- timeZoneOffset
;
2329 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidCertificate
, NULL
);
2334 CFAbsoluteTime
SecAbsoluteTimeFromDateContent(DERTag tag
, const uint8_t *bytes
,
2336 return SecAbsoluteTimeFromDateContentWithError(tag
, bytes
, length
, NULL
);
2339 __attribute__((__nonnull__
)) static bool derDateContentGetAbsoluteTime(DERTag tag
, const DERItem
*date
,
2340 CFAbsoluteTime
*pabsTime
) {
2341 CFErrorRef error
= NULL
;
2342 CFAbsoluteTime absTime
= SecAbsoluteTimeFromDateContentWithError(tag
, date
->data
,
2343 date
->length
, &error
);
2345 secwarning("Invalid date specification in certificate (see RFC5280 4.1.2.5)");
2350 *pabsTime
= absTime
;
2354 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return
2355 true if the date was valid and properly decoded, also return the result in
2356 absTime. Return false otherwise. */
2357 __attribute__((__nonnull__
)) static bool derDateGetAbsoluteTime(const DERItem
*dateChoice
,
2358 CFAbsoluteTime
*absTime
) {
2359 if (dateChoice
->length
== 0) return false;
2361 DERDecodedInfo decoded
;
2362 if (DERDecodeItem(dateChoice
, &decoded
))
2365 return derDateContentGetAbsoluteTime(decoded
.tag
, &decoded
.content
,
2369 static void appendDataProperty(CFMutableArrayRef properties
,
2370 CFStringRef label
, CFStringRef localizedLabel
, const DERItem
*der_data
) {
2371 CFDataRef data
= CFDataCreate(CFGetAllocator(properties
),
2372 der_data
->data
, der_data
->length
);
2373 appendProperty(properties
, kSecPropertyTypeData
, label
, localizedLabel
,
2378 static void appendRelabeledProperty(CFMutableArrayRef properties
,
2380 CFStringRef localizedLabel
,
2381 const DERItem
*der_data
,
2382 CFStringRef labelFormat
) {
2383 CFStringRef newLabel
=
2384 CFStringCreateWithFormat(CFGetAllocator(properties
), NULL
,
2385 labelFormat
, label
);
2387 if (localizedLabel
) {
2390 ll
= localizedLabel
= SecCopyCertString(label
);
2392 CFStringRef localizedLabelFormat
= SecCopyCertString(labelFormat
);
2393 CFStringRef newLocalizedLabel
=
2394 CFStringCreateWithFormat(CFGetAllocator(properties
), NULL
,
2395 localizedLabelFormat
, localizedLabel
);
2397 CFReleaseSafe(localizedLabelFormat
);
2398 appendDataProperty(properties
, newLabel
, newLocalizedLabel
, der_data
);
2399 CFReleaseSafe(newLabel
);
2400 CFReleaseSafe(newLocalizedLabel
);
2404 static void appendUnparsedProperty(CFMutableArrayRef properties
,
2405 CFStringRef label
, CFStringRef localizedLabel
, const DERItem
*der_data
) {
2406 appendRelabeledProperty(properties
, label
, localizedLabel
, der_data
,
2410 static void appendInvalidProperty(CFMutableArrayRef properties
,
2411 CFStringRef label
, const DERItem
*der_data
) {
2412 appendRelabeledProperty(properties
, label
, NULL
, der_data
, SEC_INVALID_KEY
);
2415 static void appendDateContentProperty(CFMutableArrayRef properties
,
2416 CFStringRef label
, DERTag tag
,
2417 const DERItem
*dateContent
) {
2418 CFAbsoluteTime absTime
;
2419 if (!derDateContentGetAbsoluteTime(tag
, dateContent
, &absTime
)) {
2420 /* Date decode failure insert hex bytes instead. */
2421 return appendInvalidProperty(properties
, label
, dateContent
);
2423 CFDateRef date
= CFDateCreate(CFGetAllocator(properties
), absTime
);
2424 appendProperty(properties
, kSecPropertyTypeDate
, label
, NULL
, date
);
2428 static void appendDateProperty(CFMutableArrayRef properties
,
2429 CFStringRef label
, CFAbsoluteTime absTime
) {
2430 CFDateRef date
= CFDateCreate(CFGetAllocator(properties
), absTime
);
2431 appendProperty(properties
, kSecPropertyTypeDate
, label
, NULL
, date
);
2435 static void appendValidityPeriodProperty(CFMutableArrayRef parent
, CFStringRef label
,
2436 SecCertificateRef certificate
) {
2437 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2438 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2440 appendDateProperty(properties
, SEC_NOT_VALID_BEFORE_KEY
,
2441 certificate
->_notBefore
);
2442 appendDateProperty(properties
, SEC_NOT_VALID_AFTER_KEY
,
2443 certificate
->_notAfter
);
2445 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, properties
);
2446 CFReleaseNull(properties
);
2449 static void appendIPAddressContentProperty(CFMutableArrayRef properties
,
2450 CFStringRef label
, const DERItem
*ip
) {
2452 copyIPAddressContentDescription(CFGetAllocator(properties
), ip
);
2454 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, value
);
2457 appendUnparsedProperty(properties
, label
, NULL
, ip
);
2461 static void appendURLContentProperty(CFMutableArrayRef properties
,
2462 CFStringRef label
, const DERItem
*urlContent
) {
2463 CFURLRef url
= CFURLCreateWithBytes(CFGetAllocator(properties
),
2464 urlContent
->data
, urlContent
->length
, kCFStringEncodingASCII
, NULL
);
2466 appendProperty(properties
, kSecPropertyTypeURL
, label
, NULL
, url
);
2469 appendInvalidProperty(properties
, label
, urlContent
);
2473 static void appendURLProperty(CFMutableArrayRef properties
,
2474 CFStringRef label
, const DERItem
*url
) {
2475 DERDecodedInfo decoded
;
2478 drtn
= DERDecodeItem(url
, &decoded
);
2479 if (drtn
|| decoded
.tag
!= ASN1_IA5_STRING
) {
2480 appendInvalidProperty(properties
, label
, url
);
2482 appendURLContentProperty(properties
, label
, &decoded
.content
);
2486 static void appendOIDProperty(CFMutableArrayRef properties
,
2487 CFStringRef label
, CFStringRef llabel
, const DERItem
*oid
) {
2488 CFStringRef oid_string
=
2489 copyLocalizedOidDescription(CFGetAllocator(properties
), oid
);
2490 appendProperty(properties
, kSecPropertyTypeString
, label
, llabel
,
2492 CFRelease(oid_string
);
2495 static void appendAlgorithmProperty(CFMutableArrayRef properties
,
2496 CFStringRef label
, const DERAlgorithmId
*algorithm
) {
2497 CFMutableArrayRef alg_props
=
2498 CFArrayCreateMutable(CFGetAllocator(properties
), 0,
2499 &kCFTypeArrayCallBacks
);
2500 appendOIDProperty(alg_props
, SEC_ALGORITHM_KEY
, NULL
, &algorithm
->oid
);
2501 if (algorithm
->params
.length
) {
2502 if (algorithm
->params
.length
== 2 &&
2503 algorithm
->params
.data
[0] == ASN1_NULL
&&
2504 algorithm
->params
.data
[1] == 0) {
2505 CFStringRef value
= SecCopyCertString(SEC_NONE_KEY
);
2506 appendProperty(alg_props
, kSecPropertyTypeString
,
2507 SEC_PARAMETERS_KEY
, NULL
, value
);
2510 appendUnparsedProperty(alg_props
, SEC_PARAMETERS_KEY
, NULL
,
2511 &algorithm
->params
);
2514 appendProperty(properties
, kSecPropertyTypeSection
, label
, NULL
, alg_props
);
2515 CFRelease(alg_props
);
2518 static void appendPublicKeyProperty(CFMutableArrayRef parent
, CFStringRef label
,
2519 SecCertificateRef certificate
) {
2520 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2521 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2523 /* Public key algorithm. */
2524 appendAlgorithmProperty(properties
, SEC_PUBLIC_KEY_ALG_KEY
,
2525 &certificate
->_algId
);
2527 /* Public Key Size */
2528 #if TARGET_OS_IPHONE
2529 SecKeyRef publicKey
= SecCertificateCopyPublicKey(certificate
);
2531 SecKeyRef publicKey
= SecCertificateCopyPublicKey_ios(certificate
);
2534 size_t sizeInBytes
= SecKeyGetBlockSize(publicKey
);
2535 CFStringRef sizeInBitsString
= CFStringCreateWithFormat(allocator
, NULL
,
2536 CFSTR("%ld"), (sizeInBytes
*8));
2537 if (sizeInBitsString
) {
2538 appendProperty(properties
, kSecPropertyTypeString
, SEC_PUBLIC_KEY_SIZE_KEY
,
2539 NULL
, sizeInBitsString
);
2541 CFReleaseNull(sizeInBitsString
);
2543 CFReleaseNull(publicKey
);
2545 /* Consider breaking down an RSA public key into modulus and
2547 appendDataProperty(properties
, SEC_PUBLIC_KEY_DATA_KEY
, NULL
,
2548 &certificate
->_pubKeyDER
);
2550 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, properties
);
2551 CFReleaseNull(properties
);
2554 static void appendSignatureProperty(CFMutableArrayRef parent
, CFStringRef label
,
2555 SecCertificateRef certificate
) {
2556 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2557 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2559 appendAlgorithmProperty(properties
, SEC_SIGNATURE_ALGORITHM_KEY
,
2560 &certificate
->_tbsSigAlg
);
2562 appendDataProperty(properties
, SEC_SIGNATURE_DATA_KEY
, NULL
,
2563 &certificate
->_signature
);
2565 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, properties
);
2566 CFReleaseNull(properties
);
2569 static void appendFingerprintsProperty(CFMutableArrayRef parent
, CFStringRef label
, SecCertificateRef certificate
) {
2570 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2571 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2573 CFDataRef sha256Fingerprint
= SecCertificateCopySHA256Digest(certificate
);
2574 if (sha256Fingerprint
) {
2575 appendProperty(properties
, kSecPropertyTypeData
, SEC_SHA2_FINGERPRINT_KEY
,
2576 NULL
, sha256Fingerprint
);
2578 CFReleaseNull(sha256Fingerprint
);
2580 appendProperty(properties
, kSecPropertyTypeData
, SEC_SHA1_FINGERPRINT_KEY
,
2581 NULL
, SecCertificateGetSHA1Digest(certificate
));
2583 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, properties
);
2584 CFReleaseNull(properties
);
2587 static CFStringRef
copyHexDescription(CFAllocatorRef allocator
,
2588 const DERItem
*blob
) {
2589 CFIndex ix
, length
= blob
->length
/* < 24 ? blob->length : 24 */;
2590 CFMutableStringRef string
= CFStringCreateMutable(allocator
,
2591 blob
->length
* 3 - 1);
2592 for (ix
= 0; ix
< length
; ++ix
)
2594 CFStringAppendFormat(string
, NULL
, CFSTR("%02X"), blob
->data
[ix
]);
2596 CFStringAppendFormat(string
, NULL
, CFSTR(" %02X"), blob
->data
[ix
]);
2601 /* Returns a (localized) blob string. */
2602 static CFStringRef
copyBlobString(CFAllocatorRef allocator
,
2603 CFStringRef blobType
, CFStringRef quanta
, const DERItem
*blob
) {
2604 CFStringRef localizedBlobType
= SecCopyCertString(blobType
);
2605 CFStringRef localizedQuanta
= SecCopyCertString(quanta
);
2606 /* "format string for encoded field data (e.g. Sequence; 128 bytes; "
2607 "data = 00 00 ...)" */
2608 CFStringRef blobFormat
= SecCopyCertString(SEC_BLOB_KEY
);
2609 CFStringRef hex
= copyHexDescription(allocator
, blob
);
2610 CFStringRef result
= CFStringCreateWithFormat(allocator
, NULL
,
2611 blobFormat
, localizedBlobType
, blob
->length
, localizedQuanta
, hex
);
2613 CFRelease(blobFormat
);
2614 CFReleaseSafe(localizedQuanta
);
2615 CFReleaseSafe(localizedBlobType
);
2620 /* Return a string verbatim (unlocalized) from a DER field. */
2621 static CFStringRef
copyContentString(CFAllocatorRef allocator
,
2622 const DERItem
*string
, CFStringEncoding encoding
,
2623 bool printableOnly
) {
2624 /* Strip potential bogus trailing zero from printable strings. */
2625 DERSize length
= string
->length
;
2626 if (length
&& string
->data
[length
- 1] == 0) {
2627 /* Don't mess with the length of UTF16 strings though. */
2628 if (encoding
!= kCFStringEncodingUTF16
)
2631 /* A zero length string isn't considered printable. */
2632 if (!length
&& printableOnly
)
2635 /* Passing true for the 5th paramater to CFStringCreateWithBytes() makes
2636 it treat kCFStringEncodingUTF16 as big endian by default, whereas
2637 passing false makes it treat it as native endian by default. */
2638 CFStringRef result
= CFStringCreateWithBytes(allocator
, string
->data
,
2639 length
, encoding
, encoding
== kCFStringEncodingUTF16
);
2643 return printableOnly
? NULL
: copyHexDescription(allocator
, string
);
2646 /* From rfc3280 - Appendix B. ASN.1 Notes
2648 CAs MUST force the serialNumber to be a non-negative integer, that
2649 is, the sign bit in the DER encoding of the INTEGER value MUST be
2650 zero - this can be done by adding a leading (leftmost) `00'H octet if
2651 necessary. This removes a potential ambiguity in mapping between a
2652 string of octets and an integer value.
2654 As noted in section 4.1.2.2, serial numbers can be expected to
2655 contain long integers. Certificate users MUST be able to handle
2656 serialNumber values up to 20 octets in length. Conformant CAs MUST
2657 NOT use serialNumber values longer than 20 octets.
2660 /* Return the given numeric data as a string: decimal up to 64 bits,
2662 static CFStringRef
copyIntegerContentDescription(CFAllocatorRef allocator
,
2663 const DERItem
*integer
) {
2665 CFIndex ix
, length
= integer
->length
;
2667 if (length
== 0 || length
> 8)
2668 return copyHexDescription(allocator
, integer
);
2670 for(ix
= 0; ix
< length
; ++ix
) {
2672 value
+= integer
->data
[ix
];
2675 return CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%llu"), value
);
2678 static CFStringRef
copyDERThingContentDescription(CFAllocatorRef allocator
,
2679 DERTag tag
, const DERItem
*derThing
, bool printableOnly
) {
2680 if (!derThing
) { return NULL
; }
2684 return printableOnly
? NULL
: copyIntegerContentDescription(allocator
, derThing
);
2685 case ASN1_PRINTABLE_STRING
:
2686 case ASN1_IA5_STRING
:
2687 return copyContentString(allocator
, derThing
, kCFStringEncodingASCII
, printableOnly
);
2688 case ASN1_UTF8_STRING
:
2689 case ASN1_GENERAL_STRING
:
2690 case ASN1_UNIVERSAL_STRING
:
2691 return copyContentString(allocator
, derThing
, kCFStringEncodingUTF8
, printableOnly
);
2692 case ASN1_T61_STRING
: // 20, also BER_TAG_TELETEX_STRING
2693 case ASN1_VIDEOTEX_STRING
: // 21
2694 case ASN1_VISIBLE_STRING
: // 26
2695 return copyContentString(allocator
, derThing
, kCFStringEncodingISOLatin1
, printableOnly
);
2696 case ASN1_BMP_STRING
: // 30
2697 return copyContentString(allocator
, derThing
, kCFStringEncodingUTF16
, printableOnly
);
2698 case ASN1_OCTET_STRING
:
2699 return printableOnly
? NULL
:
2700 copyBlobString(allocator
, SEC_BYTE_STRING_KEY
, SEC_BYTES_KEY
,
2702 //return copyBlobString(BYTE_STRING_STR, BYTES_STR, derThing);
2703 case ASN1_BIT_STRING
:
2704 return printableOnly
? NULL
:
2705 copyBlobString(allocator
, SEC_BIT_STRING_KEY
, SEC_BITS_KEY
,
2707 case ASN1_CONSTR_SEQUENCE
:
2708 return printableOnly
? NULL
:
2709 copyBlobString(allocator
, SEC_SEQUENCE_KEY
, SEC_BYTES_KEY
,
2711 case ASN1_CONSTR_SET
:
2712 return printableOnly
? NULL
:
2713 copyBlobString(allocator
, SEC_SET_KEY
, SEC_BYTES_KEY
, derThing
);
2714 case ASN1_OBJECT_ID
:
2715 return printableOnly
? NULL
: copyLocalizedOidDescription(allocator
, derThing
);
2717 if (printableOnly
) {
2720 CFStringRef fmt
= SecCopyCertString(SEC_NOT_DISPLAYED_KEY
);
2721 if (!fmt
) { return NULL
; }
2722 CFStringRef result
= CFStringCreateWithFormat(allocator
, NULL
, fmt
,
2723 (unsigned long)tag
, (unsigned long)derThing
->length
);
2730 static CFStringRef
copyDERThingDescription(CFAllocatorRef allocator
,
2731 const DERItem
*derThing
, bool printableOnly
) {
2732 DERDecodedInfo decoded
;
2735 drtn
= DERDecodeItem(derThing
, &decoded
);
2737 /* TODO: Perhaps put something in the label saying we couldn't parse
2739 return printableOnly
? NULL
: copyHexDescription(allocator
, derThing
);
2741 return copyDERThingContentDescription(allocator
, decoded
.tag
,
2742 &decoded
.content
, false);
2746 static void appendDERThingProperty(CFMutableArrayRef properties
,
2747 CFStringRef label
, CFStringRef localizedLabel
, const DERItem
*derThing
) {
2748 CFStringRef value
= copyDERThingDescription(CFGetAllocator(properties
),
2751 appendProperty(properties
, kSecPropertyTypeString
, label
, localizedLabel
,
2754 CFReleaseSafe(value
);
2757 static OSStatus
appendRDNProperty(void *context
, const DERItem
*rdnType
,
2758 const DERItem
*rdnValue
, CFIndex rdnIX
) {
2759 CFMutableArrayRef properties
= (CFMutableArrayRef
)context
;
2761 /* If there is more than one value pair we create a subsection for the
2762 second pair, and append things to the subsection for subsequent
2764 CFIndex lastIX
= CFArrayGetCount(properties
) - 1;
2765 CFTypeRef lastValue
= CFArrayGetValueAtIndex(properties
, lastIX
);
2767 /* Since this is the second rdn pair for a given rdn, we setup a
2768 new subsection for this rdn. We remove the first property
2769 from the properties array and make it the first element in the
2770 subsection instead. */
2771 CFMutableArrayRef rdn_props
= CFArrayCreateMutable(
2772 CFGetAllocator(properties
), 0, &kCFTypeArrayCallBacks
);
2773 CFArrayAppendValue(rdn_props
, lastValue
);
2774 CFArrayRemoveValueAtIndex(properties
, lastIX
);
2775 appendProperty(properties
, kSecPropertyTypeSection
, NULL
, NULL
,
2777 properties
= rdn_props
;
2779 /* Since this is the third or later rdn pair we have already
2780 created a subsection in the top level properties array. Instead
2781 of appending to that directly we append to the array inside the
2783 properties
= (CFMutableArrayRef
)CFDictionaryGetValue(
2784 (CFDictionaryRef
)lastValue
, kSecPropertyKeyValue
);
2788 /* Finally we append the new rdn value to the property array. */
2789 CFStringRef label
= SecDERItemCopyOIDDecimalRepresentation(
2790 CFGetAllocator(properties
), rdnType
);
2791 CFStringRef localizedLabel
=
2792 copyLocalizedOidDescription(CFGetAllocator(properties
), rdnType
);
2793 appendDERThingProperty(properties
, label
, localizedLabel
, rdnValue
);
2794 CFReleaseSafe(label
);
2795 CFReleaseSafe(localizedLabel
);
2796 return errSecSuccess
;
2799 static CFArrayRef
createPropertiesForRDNContent(CFAllocatorRef allocator
,
2800 const DERItem
*rdnSetContent
) {
2801 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2802 &kCFTypeArrayCallBacks
);
2803 OSStatus status
= parseRDNContent(rdnSetContent
, properties
,
2806 CFArrayRemoveAllValues(properties
);
2807 appendInvalidProperty(properties
, SEC_RDN_KEY
, rdnSetContent
);
2814 From rfc3739 - 3.1.2. Subject
2816 When parsing the subject here are some tips for a short name of the cert.
2817 Choice I: commonName
2818 Choice II: givenName
2819 Choice III: pseudonym
2821 The commonName attribute value SHALL, when present, contain a name
2822 of the subject. This MAY be in the subject's preferred
2823 presentation format, or a format preferred by the CA, or some
2824 other format. Pseudonyms, nicknames, and names with spelling
2825 other than defined by the registered name MAY be used. To
2826 understand the nature of the name presented in commonName,
2827 complying applications MAY have to examine present values of the
2828 givenName and surname attributes, or the pseudonym attribute.
2831 static CFArrayRef
createPropertiesForX501NameContent(CFAllocatorRef allocator
,
2832 const DERItem
*x501NameContent
) {
2833 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2834 &kCFTypeArrayCallBacks
);
2835 OSStatus status
= parseX501NameContent(x501NameContent
, properties
,
2838 CFArrayRemoveAllValues(properties
);
2839 appendInvalidProperty(properties
, SEC_X501_NAME_KEY
, x501NameContent
);
2845 static CFArrayRef
createPropertiesForX501Name(CFAllocatorRef allocator
,
2846 const DERItem
*x501Name
) {
2847 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2848 &kCFTypeArrayCallBacks
);
2849 OSStatus status
= parseX501Name(x501Name
, properties
, appendRDNProperty
);
2851 CFArrayRemoveAllValues(properties
);
2852 appendInvalidProperty(properties
, SEC_X501_NAME_KEY
, x501Name
);
2858 static void appendIntegerProperty(CFMutableArrayRef properties
,
2859 CFStringRef label
, const DERItem
*integer
) {
2860 CFStringRef string
= copyIntegerContentDescription(
2861 CFGetAllocator(properties
), integer
);
2862 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, string
);
2866 static void appendBoolProperty(CFMutableArrayRef properties
,
2867 CFStringRef label
, bool boolean
) {
2868 CFStringRef value
= SecCopyCertString(boolean
? SEC_YES_KEY
: SEC_NO_KEY
);
2869 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, value
);
2873 static void appendBooleanProperty(CFMutableArrayRef properties
,
2874 CFStringRef label
, const DERItem
*boolean
, bool defaultValue
) {
2876 DERReturn drtn
= DERParseBooleanWithDefault(boolean
, defaultValue
, &result
);
2878 /* Couldn't parse boolean; dump the raw unparsed data as hex. */
2879 appendInvalidProperty(properties
, label
, boolean
);
2881 appendBoolProperty(properties
, label
, result
);
2885 static void appendSerialNumberProperty(CFMutableArrayRef parent
, CFStringRef label
,
2886 DERItem
*serialNum
) {
2887 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2888 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2890 if (serialNum
->length
) {
2891 appendIntegerProperty(properties
, SEC_SERIAL_NUMBER_KEY
,
2893 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, properties
);
2896 CFReleaseNull(properties
);
2899 static void appendBitStringContentNames(CFMutableArrayRef properties
,
2900 CFStringRef label
, const DERItem
*bitStringContent
,
2901 const CFStringRef
*names
, CFIndex namesCount
) {
2902 DERSize len
= bitStringContent
->length
- 1;
2903 require_quiet(len
== 1 || len
== 2, badDER
);
2904 DERByte numUnusedBits
= bitStringContent
->data
[0];
2905 require_quiet(numUnusedBits
< 8, badDER
);
2906 uint_fast16_t bits
= 8 * len
- numUnusedBits
;
2907 require_quiet(bits
<= (uint_fast16_t)namesCount
, badDER
);
2908 uint_fast16_t value
= bitStringContent
->data
[1];
2911 value
= (value
<< 8) + bitStringContent
->data
[2];
2917 CFStringRef fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
2918 CFStringRef string
= NULL
;
2919 for (ix
= 0; ix
< bits
; ++ix
) {
2923 CFStringCreateWithFormat(CFGetAllocator(properties
),
2924 NULL
, fmt
, string
, names
[ix
]);
2935 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
2936 string
? string
: CFSTR(""));
2937 CFReleaseSafe(string
);
2940 appendInvalidProperty(properties
, label
, bitStringContent
);
2943 static void appendBitStringNames(CFMutableArrayRef properties
,
2944 CFStringRef label
, const DERItem
*bitString
,
2945 const CFStringRef
*names
, CFIndex namesCount
) {
2946 DERDecodedInfo bitStringContent
;
2947 DERReturn drtn
= DERDecodeItem(bitString
, &bitStringContent
);
2948 require_noerr_quiet(drtn
, badDER
);
2949 require_quiet(bitStringContent
.tag
== ASN1_BIT_STRING
, badDER
);
2950 appendBitStringContentNames(properties
, label
, &bitStringContent
.content
,
2954 appendInvalidProperty(properties
, label
, bitString
);
2957 static void appendKeyUsage(CFMutableArrayRef properties
,
2958 const DERItem
*extnValue
) {
2959 static const CFStringRef usageNames
[] = {
2960 SEC_DIGITAL_SIGNATURE_KEY
,
2961 SEC_NON_REPUDIATION_KEY
,
2962 SEC_KEY_ENCIPHERMENT_KEY
,
2963 SEC_DATA_ENCIPHERMENT_KEY
,
2964 SEC_KEY_AGREEMENT_KEY
,
2967 SEC_ENCIPHER_ONLY_KEY
,
2968 SEC_DECIPHER_ONLY_KEY
2970 appendBitStringNames(properties
, SEC_USAGE_KEY
, extnValue
,
2971 usageNames
, array_size(usageNames
));
2974 static void appendPrivateKeyUsagePeriod(CFMutableArrayRef properties
,
2975 const DERItem
*extnValue
) {
2976 DERPrivateKeyUsagePeriod pkup
;
2977 DERReturn drtn
= DERParseSequence(extnValue
,
2978 DERNumPrivateKeyUsagePeriodItemSpecs
, DERPrivateKeyUsagePeriodItemSpecs
,
2979 &pkup
, sizeof(pkup
));
2980 require_noerr_quiet(drtn
, badDER
);
2981 if (pkup
.notBefore
.length
) {
2982 appendDateContentProperty(properties
, SEC_NOT_VALID_BEFORE_KEY
,
2983 ASN1_GENERALIZED_TIME
, &pkup
.notBefore
);
2985 if (pkup
.notAfter
.length
) {
2986 appendDateContentProperty(properties
, SEC_NOT_VALID_AFTER_KEY
,
2987 ASN1_GENERALIZED_TIME
, &pkup
.notAfter
);
2991 appendInvalidProperty(properties
, SEC_PRIVATE_KU_PERIOD_KEY
, extnValue
);
2994 static void appendStringContentProperty(CFMutableArrayRef properties
,
2995 CFStringRef label
, const DERItem
*stringContent
,
2996 CFStringEncoding encoding
) {
2997 CFStringRef string
= CFStringCreateWithBytes(CFGetAllocator(properties
),
2998 stringContent
->data
, stringContent
->length
, encoding
, FALSE
);
3000 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, string
);
3003 appendInvalidProperty(properties
, label
, stringContent
);
3008 OtherName ::= SEQUENCE {
3009 type-id OBJECT IDENTIFIER,
3010 value [0] EXPLICIT ANY DEFINED BY type-id }
3012 static void appendOtherNameContentProperty(CFMutableArrayRef properties
,
3013 const DERItem
*otherNameContent
) {
3015 DERReturn drtn
= DERParseSequenceContent(otherNameContent
,
3016 DERNumOtherNameItemSpecs
, DEROtherNameItemSpecs
,
3018 require_noerr_quiet(drtn
, badDER
);
3019 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3021 SecDERItemCopyOIDDecimalRepresentation(allocator
, &on
.typeIdentifier
);
3022 CFStringRef localizedLabel
=
3023 copyLocalizedOidDescription(allocator
, &on
.typeIdentifier
);
3024 CFStringRef value_string
= copyDERThingDescription(allocator
, &on
.value
, false);
3026 appendProperty(properties
, kSecPropertyTypeString
, label
,
3027 localizedLabel
, value_string
);
3029 appendUnparsedProperty(properties
, label
, localizedLabel
, &on
.value
);
3031 CFReleaseSafe(value_string
);
3032 CFReleaseSafe(label
);
3033 CFReleaseSafe(localizedLabel
);
3036 appendInvalidProperty(properties
, SEC_OTHER_NAME_KEY
, otherNameContent
);
3040 GeneralName ::= CHOICE {
3041 otherName [0] OtherName,
3042 rfc822Name [1] IA5String,
3043 dNSName [2] IA5String,
3044 x400Address [3] ORAddress,
3045 directoryName [4] Name,
3046 ediPartyName [5] EDIPartyName,
3047 uniformResourceIdentifier [6] IA5String,
3048 iPAddress [7] OCTET STRING,
3049 registeredID [8] OBJECT IDENTIFIER}
3051 EDIPartyName ::= SEQUENCE {
3052 nameAssigner [0] DirectoryString OPTIONAL,
3053 partyName [1] DirectoryString }
3055 static bool appendGeneralNameContentProperty(CFMutableArrayRef properties
,
3056 DERTag tag
, const DERItem
*generalName
) {
3058 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
3059 appendOtherNameContentProperty(properties
, generalName
);
3061 case ASN1_CONTEXT_SPECIFIC
| 1:
3063 appendStringContentProperty(properties
, SEC_EMAIL_ADDRESS_KEY
,
3064 generalName
, kCFStringEncodingASCII
);
3066 case ASN1_CONTEXT_SPECIFIC
| 2:
3068 appendStringContentProperty(properties
, SEC_DNS_NAME_KEY
, generalName
,
3069 kCFStringEncodingASCII
);
3071 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 3:
3072 appendUnparsedProperty(properties
, SEC_X400_ADDRESS_KEY
, NULL
,
3075 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 4:
3077 CFArrayRef directory_plist
=
3078 createPropertiesForX501Name(CFGetAllocator(properties
),
3080 appendProperty(properties
, kSecPropertyTypeSection
,
3081 SEC_DIRECTORY_NAME_KEY
, NULL
, directory_plist
);
3082 CFRelease(directory_plist
);
3085 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 5:
3086 appendUnparsedProperty(properties
, SEC_EDI_PARTY_NAME_KEY
, NULL
,
3089 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
3090 /* Technically I don't think this is valid, but there are certs out
3091 in the wild that use a constructed IA5String. In particular the
3092 VeriSign Time Stamping Authority CA.cer does this. */
3093 appendURLProperty(properties
, SEC_URI_KEY
, generalName
);
3095 case ASN1_CONTEXT_SPECIFIC
| 6:
3096 appendURLContentProperty(properties
, SEC_URI_KEY
, generalName
);
3098 case ASN1_CONTEXT_SPECIFIC
| 7:
3099 appendIPAddressContentProperty(properties
, SEC_IP_ADDRESS_KEY
,
3102 case ASN1_CONTEXT_SPECIFIC
| 8:
3103 appendOIDProperty(properties
, SEC_REGISTERED_ID_KEY
, NULL
, generalName
);
3114 static void appendGeneralNameProperty(CFMutableArrayRef properties
,
3115 const DERItem
*generalName
) {
3116 DERDecodedInfo generalNameContent
;
3117 DERReturn drtn
= DERDecodeItem(generalName
, &generalNameContent
);
3118 require_noerr_quiet(drtn
, badDER
);
3119 if (appendGeneralNameContentProperty(properties
, generalNameContent
.tag
,
3120 &generalNameContent
.content
))
3123 appendInvalidProperty(properties
, SEC_GENERAL_NAME_KEY
, generalName
);
3128 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
3130 static void appendGeneralNamesContent(CFMutableArrayRef properties
,
3131 const DERItem
*generalNamesContent
) {
3133 DERReturn drtn
= DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
);
3134 require_noerr_quiet(drtn
, badDER
);
3135 DERDecodedInfo generalNameContent
;
3136 while ((drtn
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) ==
3138 if (!appendGeneralNameContentProperty(properties
,
3139 generalNameContent
.tag
, &generalNameContent
.content
)) {
3143 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3146 appendInvalidProperty(properties
, SEC_GENERAL_NAMES_KEY
,
3147 generalNamesContent
);
3150 static void appendGeneralNames(CFMutableArrayRef properties
,
3151 const DERItem
*generalNames
) {
3152 DERDecodedInfo generalNamesContent
;
3153 DERReturn drtn
= DERDecodeItem(generalNames
, &generalNamesContent
);
3154 require_noerr_quiet(drtn
, badDER
);
3155 require_quiet(generalNamesContent
.tag
== ASN1_CONSTR_SEQUENCE
,
3157 appendGeneralNamesContent(properties
, &generalNamesContent
.content
);
3160 appendInvalidProperty(properties
, SEC_GENERAL_NAMES_KEY
, generalNames
);
3164 BasicConstraints ::= SEQUENCE {
3165 cA BOOLEAN DEFAULT FALSE,
3166 pathLenConstraint INTEGER (0..MAX) OPTIONAL }
3168 static void appendBasicConstraints(CFMutableArrayRef properties
,
3169 const DERItem
*extnValue
) {
3170 DERBasicConstraints basicConstraints
;
3171 DERReturn drtn
= DERParseSequence(extnValue
,
3172 DERNumBasicConstraintsItemSpecs
, DERBasicConstraintsItemSpecs
,
3173 &basicConstraints
, sizeof(basicConstraints
));
3174 require_noerr_quiet(drtn
, badDER
);
3176 appendBooleanProperty(properties
, SEC_CERT_AUTHORITY_KEY
,
3177 &basicConstraints
.cA
, false);
3179 if (basicConstraints
.pathLenConstraint
.length
!= 0) {
3180 appendIntegerProperty(properties
, SEC_PATH_LEN_CONSTRAINT_KEY
,
3181 &basicConstraints
.pathLenConstraint
);
3185 appendInvalidProperty(properties
, SEC_BASIC_CONSTRAINTS_KEY
, extnValue
);
3189 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
3191 * NameConstraints ::= SEQUENCE {
3192 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
3193 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
3195 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
3197 * GeneralSubtree ::= SEQUENCE {
3199 * minimum [0] BaseDistance DEFAULT 0,
3200 * maximum [1] BaseDistance OPTIONAL }
3202 * BaseDistance ::= INTEGER (0..MAX)
3204 static void appendNameConstraints(CFMutableArrayRef properties
,
3205 const DERItem
*extnValue
) {
3206 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3207 DERNameConstraints nc
;
3209 drtn
= DERParseSequence(extnValue
,
3210 DERNumNameConstraintsItemSpecs
,
3211 DERNameConstraintsItemSpecs
,
3213 require_noerr_quiet(drtn
, badDER
);
3214 if (nc
.permittedSubtrees
.length
) {
3216 require_noerr_quiet(DERDecodeSeqContentInit(&nc
.permittedSubtrees
, &gsSeq
), badDER
);
3217 DERDecodedInfo gsContent
;
3218 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
3219 DERGeneralSubtree derGS
;
3220 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
3221 drtn
= DERParseSequenceContent(&gsContent
.content
,
3222 DERNumGeneralSubtreeItemSpecs
,
3223 DERGeneralSubtreeItemSpecs
,
3224 &derGS
, sizeof(derGS
));
3225 require_noerr_quiet(drtn
, badDER
);
3226 if (derGS
.minimum
.length
) {
3227 appendIntegerProperty(properties
, SEC_PERMITTED_MINIMUM_KEY
, &derGS
.minimum
);
3229 if (derGS
.maximum
.length
) {
3230 appendIntegerProperty(properties
, SEC_PERMITTED_MAXIMUM_KEY
, &derGS
.maximum
);
3232 if (derGS
.generalName
.length
) {
3233 CFMutableArrayRef base
= CFArrayCreateMutable(allocator
, 0,
3234 &kCFTypeArrayCallBacks
);
3235 appendProperty(properties
, kSecPropertyTypeSection
,
3236 SEC_PERMITTED_NAME_KEY
, NULL
, base
);
3237 appendGeneralNameProperty(base
, &derGS
.generalName
);
3241 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3243 if (nc
.excludedSubtrees
.length
) {
3245 require_noerr_quiet(DERDecodeSeqContentInit(&nc
.excludedSubtrees
, &gsSeq
), badDER
);
3246 DERDecodedInfo gsContent
;
3247 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
3248 DERGeneralSubtree derGS
;
3249 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
3250 drtn
= DERParseSequenceContent(&gsContent
.content
,
3251 DERNumGeneralSubtreeItemSpecs
,
3252 DERGeneralSubtreeItemSpecs
,
3253 &derGS
, sizeof(derGS
));
3254 require_noerr_quiet(drtn
, badDER
);
3255 if (derGS
.minimum
.length
) {
3256 appendIntegerProperty(properties
, SEC_EXCLUDED_MINIMUM_KEY
, &derGS
.minimum
);
3258 if (derGS
.maximum
.length
) {
3259 appendIntegerProperty(properties
, SEC_EXCLUDED_MAXIMUM_KEY
, &derGS
.maximum
);
3261 if (derGS
.generalName
.length
) {
3262 CFMutableArrayRef base
= CFArrayCreateMutable(allocator
, 0,
3263 &kCFTypeArrayCallBacks
);
3264 appendProperty(properties
, kSecPropertyTypeSection
,
3265 SEC_EXCLUDED_NAME_KEY
, NULL
, base
);
3266 appendGeneralNameProperty(base
, &derGS
.generalName
);
3270 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3275 appendInvalidProperty(properties
, SEC_NAME_CONSTRAINTS_KEY
, extnValue
);
3279 CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
3281 DistributionPoint ::= SEQUENCE {
3282 distributionPoint [0] DistributionPointName OPTIONAL,
3283 reasons [1] ReasonFlags OPTIONAL,
3284 cRLIssuer [2] GeneralNames OPTIONAL }
3286 DistributionPointName ::= CHOICE {
3287 fullName [0] GeneralNames,
3288 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
3290 ReasonFlags ::= BIT STRING {
3294 affiliationChanged (3),
3296 cessationOfOperation (5),
3297 certificateHold (6),
3298 privilegeWithdrawn (7),
3301 static void appendCrlDistributionPoints(CFMutableArrayRef properties
,
3302 const DERItem
*extnValue
) {
3303 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3306 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &dpSeq
);
3307 require_noerr_quiet(drtn
, badDER
);
3308 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3309 DERDecodedInfo dpSeqContent
;
3310 while ((drtn
= DERDecodeSeqNext(&dpSeq
, &dpSeqContent
)) == DR_Success
) {
3311 require_quiet(dpSeqContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3312 DERDistributionPoint dp
;
3313 drtn
= DERParseSequenceContent(&dpSeqContent
.content
,
3314 DERNumDistributionPointItemSpecs
,
3315 DERDistributionPointItemSpecs
,
3317 require_noerr_quiet(drtn
, badDER
);
3318 if (dp
.distributionPoint
.length
) {
3319 DERDecodedInfo distributionPointName
;
3320 drtn
= DERDecodeItem(&dp
.distributionPoint
, &distributionPointName
);
3321 require_noerr_quiet(drtn
, badDER
);
3322 if (distributionPointName
.tag
==
3323 (ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0)) {
3325 appendGeneralNamesContent(properties
,
3326 &distributionPointName
.content
);
3327 } else if (distributionPointName
.tag
==
3328 (ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1)) {
3329 CFArrayRef rdn_props
= createPropertiesForRDNContent(allocator
,
3331 appendProperty(properties
, kSecPropertyTypeSection
,
3332 SEC_NAME_REL_CRL_ISSUER_KEY
, NULL
, rdn_props
);
3333 CFRelease(rdn_props
);
3338 if (dp
.reasons
.length
) {
3339 static const CFStringRef reasonNames
[] = {
3341 SEC_KEY_COMPROMISE_KEY
,
3342 SEC_CA_COMPROMISE_KEY
,
3343 SEC_AFFILIATION_CHANGED_KEY
,
3345 SEC_CESSATION_OF_OPER_KEY
,
3346 SEC_CERTIFICATE_HOLD_KEY
,
3347 SEC_PRIV_WITHDRAWN_KEY
,
3348 SEC_AA_COMPROMISE_KEY
3350 appendBitStringContentNames(properties
, SEC_REASONS_KEY
,
3352 reasonNames
, array_size(reasonNames
));
3354 if (dp
.cRLIssuer
.length
) {
3355 CFMutableArrayRef crlIssuer
= CFArrayCreateMutable(allocator
, 0,
3356 &kCFTypeArrayCallBacks
);
3357 appendProperty(properties
, kSecPropertyTypeSection
,
3358 SEC_CRL_ISSUER_KEY
, NULL
, crlIssuer
);
3359 CFRelease(crlIssuer
);
3360 appendGeneralNames(crlIssuer
, &dp
.cRLIssuer
);
3363 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3366 appendInvalidProperty(properties
, SEC_CRL_DISTR_POINTS_KEY
, extnValue
);
3369 /* Decode a sequence of integers into a comma separated list of ints. */
3370 static void appendIntegerSequenceContent(CFMutableArrayRef properties
,
3371 CFStringRef label
, const DERItem
*intSequenceContent
) {
3372 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3374 CFStringRef fmt
= NULL
, value
= NULL
, intDesc
= NULL
, v
= NULL
;
3375 DERReturn drtn
= DERDecodeSeqContentInit(intSequenceContent
, &intSeq
);
3376 require_noerr_quiet(drtn
, badDER
);
3377 DERDecodedInfo intContent
;
3378 fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
3379 require_quiet(fmt
, badDER
);
3380 while ((drtn
= DERDecodeSeqNext(&intSeq
, &intContent
)) == DR_Success
) {
3381 require_quiet(intContent
.tag
== ASN1_INTEGER
, badDER
);
3382 intDesc
= copyIntegerContentDescription(
3383 allocator
, &intContent
.content
);
3384 require_quiet(intDesc
, badDER
);
3386 v
= CFStringCreateWithFormat(allocator
, NULL
, fmt
, value
, intDesc
);
3387 CFReleaseNull(value
);
3388 require_quiet(v
, badDER
);
3391 value
= CFStringCreateMutableCopy(allocator
, 0, intDesc
);
3392 require_quiet(value
, badDER
);
3394 CFReleaseNull(intDesc
);
3397 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3399 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, value
);
3403 /* DROPTHOUGH if !value. */
3406 CFReleaseNull(intDesc
);
3407 CFReleaseNull(value
);
3408 appendInvalidProperty(properties
, label
, intSequenceContent
);
3411 static void appendCertificatePolicies(CFMutableArrayRef properties
,
3412 const DERItem
*extnValue
) {
3413 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3414 CFStringRef piLabel
= NULL
, piFmt
= NULL
, lpiLabel
= NULL
;
3415 CFStringRef pqLabel
= NULL
, pqFmt
= NULL
, lpqLabel
= NULL
;
3418 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &piSeq
);
3419 require_noerr_quiet(drtn
, badDER
);
3420 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3421 DERDecodedInfo piContent
;
3423 while ((drtn
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) {
3424 require_quiet(piContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3425 DERPolicyInformation pi
;
3426 drtn
= DERParseSequenceContent(&piContent
.content
,
3427 DERNumPolicyInformationItemSpecs
,
3428 DERPolicyInformationItemSpecs
,
3430 require_noerr_quiet(drtn
, badDER
);
3431 require_quiet(piLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3432 SEC_POLICY_IDENTIFIER_KEY
, pin
), badDER
);
3433 require_quiet(piFmt
= SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY
), badDER
);
3434 require_quiet(lpiLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3435 piFmt
, pin
++), badDER
);
3436 CFReleaseNull(piFmt
);
3437 appendOIDProperty(properties
, piLabel
, lpiLabel
, &pi
.policyIdentifier
);
3438 CFReleaseNull(piLabel
);
3439 CFReleaseNull(lpiLabel
);
3440 if (pi
.policyQualifiers
.length
== 0)
3444 drtn
= DERDecodeSeqContentInit(&pi
.policyQualifiers
, &pqSeq
);
3445 require_noerr_quiet(drtn
, badDER
);
3446 DERDecodedInfo pqContent
;
3448 while ((drtn
= DERDecodeSeqNext(&pqSeq
, &pqContent
)) == DR_Success
) {
3449 DERPolicyQualifierInfo pqi
;
3450 drtn
= DERParseSequenceContent(&pqContent
.content
,
3451 DERNumPolicyQualifierInfoItemSpecs
,
3452 DERPolicyQualifierInfoItemSpecs
,
3454 require_noerr_quiet(drtn
, badDER
);
3455 DERDecodedInfo qualifierContent
;
3456 drtn
= DERDecodeItem(&pqi
.qualifier
, &qualifierContent
);
3457 require_noerr_quiet(drtn
, badDER
);
3458 require_quiet(pqLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3459 SEC_POLICY_QUALIFIER_KEY
, pqn
), badDER
);
3460 require_quiet(pqFmt
= SecCopyCertString(SEC_POLICY_QUALIFIER_KEY
), badDER
);
3461 require_quiet(lpqLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3462 pqFmt
, pqn
++), badDER
);
3463 CFReleaseNull(pqFmt
);
3464 appendOIDProperty(properties
, pqLabel
, lpqLabel
,
3465 &pqi
.policyQualifierID
);
3466 CFReleaseNull(pqLabel
);
3467 CFReleaseNull(lpqLabel
);
3468 if (DEROidCompare(&oidQtCps
, &pqi
.policyQualifierID
)) {
3469 require_quiet(qualifierContent
.tag
== ASN1_IA5_STRING
, badDER
);
3470 appendURLContentProperty(properties
, SEC_CPS_URI_KEY
,
3471 &qualifierContent
.content
);
3472 } else if (DEROidCompare(&oidQtUNotice
, &pqi
.policyQualifierID
)) {
3473 require_quiet(qualifierContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3475 drtn
= DERParseSequenceContent(&qualifierContent
.content
,
3476 DERNumUserNoticeItemSpecs
,
3477 DERUserNoticeItemSpecs
,
3479 require_noerr_quiet(drtn
, badDER
);
3480 if (un
.noticeRef
.length
) {
3481 DERNoticeReference nr
;
3482 drtn
= DERParseSequenceContent(&un
.noticeRef
,
3483 DERNumNoticeReferenceItemSpecs
,
3484 DERNoticeReferenceItemSpecs
,
3486 require_noerr_quiet(drtn
, badDER
);
3487 appendDERThingProperty(properties
,
3488 SEC_ORGANIZATION_KEY
, NULL
,
3490 appendIntegerSequenceContent(properties
,
3491 SEC_NOTICE_NUMBERS_KEY
, &nr
.noticeNumbers
);
3493 if (un
.explicitText
.length
) {
3494 appendDERThingProperty(properties
, SEC_EXPLICIT_TEXT_KEY
,
3495 NULL
, &un
.explicitText
);
3498 appendUnparsedProperty(properties
, SEC_QUALIFIER_KEY
, NULL
,
3502 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3504 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3507 CFReleaseNull(piFmt
);
3508 CFReleaseNull(piLabel
);
3509 CFReleaseNull(lpiLabel
);
3510 CFReleaseNull(pqFmt
);
3511 CFReleaseNull(pqLabel
);
3512 CFReleaseNull(lpqLabel
);
3513 appendInvalidProperty(properties
, SEC_CERT_POLICIES_KEY
, extnValue
);
3516 static void appendSubjectKeyIdentifier(CFMutableArrayRef properties
,
3517 const DERItem
*extnValue
) {
3519 DERDecodedInfo keyIdentifier
;
3520 drtn
= DERDecodeItem(extnValue
, &keyIdentifier
);
3521 require_noerr_quiet(drtn
, badDER
);
3522 require_quiet(keyIdentifier
.tag
== ASN1_OCTET_STRING
, badDER
);
3523 appendDataProperty(properties
, SEC_KEY_IDENTIFIER_KEY
, NULL
,
3524 &keyIdentifier
.content
);
3528 appendInvalidProperty(properties
, SEC_SUBJ_KEY_ID_KEY
,
3533 AuthorityKeyIdentifier ::= SEQUENCE {
3534 keyIdentifier [0] KeyIdentifier OPTIONAL,
3535 authorityCertIssuer [1] GeneralNames OPTIONAL,
3536 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
3537 -- authorityCertIssuer and authorityCertSerialNumber MUST both
3538 -- be present or both be absent
3540 KeyIdentifier ::= OCTET STRING
3542 static void appendAuthorityKeyIdentifier(CFMutableArrayRef properties
,
3543 const DERItem
*extnValue
) {
3544 DERAuthorityKeyIdentifier akid
;
3546 drtn
= DERParseSequence(extnValue
,
3547 DERNumAuthorityKeyIdentifierItemSpecs
,
3548 DERAuthorityKeyIdentifierItemSpecs
,
3549 &akid
, sizeof(akid
));
3550 require_noerr_quiet(drtn
, badDER
);
3551 if (akid
.keyIdentifier
.length
) {
3552 appendDataProperty(properties
, SEC_KEY_IDENTIFIER_KEY
, NULL
,
3553 &akid
.keyIdentifier
);
3555 if (akid
.authorityCertIssuer
.length
||
3556 akid
.authorityCertSerialNumber
.length
) {
3557 require_quiet(akid
.authorityCertIssuer
.length
&&
3558 akid
.authorityCertSerialNumber
.length
, badDER
);
3559 /* Perhaps put in a subsection called Authority Certificate Issuer. */
3560 appendGeneralNamesContent(properties
,
3561 &akid
.authorityCertIssuer
);
3562 appendIntegerProperty(properties
, SEC_AUTH_CERT_SERIAL_KEY
,
3563 &akid
.authorityCertSerialNumber
);
3568 appendInvalidProperty(properties
, SEC_AUTHORITY_KEY_ID_KEY
, extnValue
);
3572 PolicyConstraints ::= SEQUENCE {
3573 requireExplicitPolicy [0] SkipCerts OPTIONAL,
3574 inhibitPolicyMapping [1] SkipCerts OPTIONAL }
3576 SkipCerts ::= INTEGER (0..MAX)
3578 static void appendPolicyConstraints(CFMutableArrayRef properties
,
3579 const DERItem
*extnValue
) {
3580 DERPolicyConstraints pc
;
3582 drtn
= DERParseSequence(extnValue
,
3583 DERNumPolicyConstraintsItemSpecs
,
3584 DERPolicyConstraintsItemSpecs
,
3586 require_noerr_quiet(drtn
, badDER
);
3587 if (pc
.requireExplicitPolicy
.length
) {
3588 appendIntegerProperty(properties
, SEC_REQUIRE_EXPL_POLICY_KEY
,
3589 &pc
.requireExplicitPolicy
);
3591 if (pc
.inhibitPolicyMapping
.length
) {
3592 appendIntegerProperty(properties
, SEC_INHIBIT_POLICY_MAP_KEY
,
3593 &pc
.inhibitPolicyMapping
);
3599 appendInvalidProperty(properties
, SEC_POLICY_CONSTRAINTS_KEY
, extnValue
);
3603 extendedKeyUsage EXTENSION ::= {
3604 SYNTAX SEQUENCE SIZE (1..MAX) OF KeyPurposeId
3605 IDENTIFIED BY id-ce-extKeyUsage }
3607 KeyPurposeId ::= OBJECT IDENTIFIER
3609 static void appendExtendedKeyUsage(CFMutableArrayRef properties
,
3610 const DERItem
*extnValue
) {
3613 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &derSeq
);
3614 require_noerr_quiet(drtn
, badDER
);
3615 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3616 DERDecodedInfo currDecoded
;
3617 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
3618 require_quiet(currDecoded
.tag
== ASN1_OBJECT_ID
, badDER
);
3619 appendOIDProperty(properties
, SEC_PURPOSE_KEY
, NULL
,
3620 &currDecoded
.content
);
3622 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3625 appendInvalidProperty(properties
, SEC_EXTENDED_KEY_USAGE_KEY
, extnValue
);
3629 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
3631 AuthorityInfoAccessSyntax ::=
3632 SEQUENCE SIZE (1..MAX) OF AccessDescription
3634 AccessDescription ::= SEQUENCE {
3635 accessMethod OBJECT IDENTIFIER,
3636 accessLocation GeneralName }
3638 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
3640 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
3642 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
3644 static void appendInfoAccess(CFMutableArrayRef properties
,
3645 const DERItem
*extnValue
) {
3648 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &adSeq
);
3649 require_noerr_quiet(drtn
, badDER
);
3650 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3651 DERDecodedInfo adContent
;
3652 while ((drtn
= DERDecodeSeqNext(&adSeq
, &adContent
)) == DR_Success
) {
3653 require_quiet(adContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3654 DERAccessDescription ad
;
3655 drtn
= DERParseSequenceContent(&adContent
.content
,
3656 DERNumAccessDescriptionItemSpecs
,
3657 DERAccessDescriptionItemSpecs
,
3659 require_noerr_quiet(drtn
, badDER
);
3660 appendOIDProperty(properties
, SEC_ACCESS_METHOD_KEY
, NULL
,
3662 //TODO: Do something with SEC_ACCESS_LOCATION_KEY
3663 appendGeneralNameProperty(properties
, &ad
.accessLocation
);
3665 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3668 appendInvalidProperty(properties
, SEC_AUTH_INFO_ACCESS_KEY
, extnValue
);
3671 static void appendNetscapeCertType(CFMutableArrayRef properties
,
3672 const DERItem
*extnValue
) {
3673 static const CFStringRef certTypes
[] = {
3677 SEC_OBJECT_SIGNING_KEY
,
3681 SEC_OBJECT_SIGNING_CA_KEY
3683 appendBitStringNames(properties
, SEC_USAGE_KEY
, extnValue
,
3684 certTypes
, array_size(certTypes
));
3687 static bool appendPrintableDERSequence(CFMutableArrayRef properties
,
3688 CFStringRef label
, const DERItem
*sequence
) {
3691 DERReturn drtn
= DERDecodeSeqInit(sequence
, &tag
, &derSeq
);
3692 require_noerr_quiet(drtn
, badSequence
);
3693 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badSequence
);
3694 DERDecodedInfo currDecoded
;
3695 bool appendedSomething
= false;
3696 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
3697 switch (currDecoded
.tag
)
3700 case ASN1_SEQUENCE
: // 16
3701 case ASN1_SET
: // 17
3702 // skip constructed object lengths
3705 case ASN1_UTF8_STRING
: // 12
3706 case ASN1_NUMERIC_STRING
: // 18
3707 case ASN1_PRINTABLE_STRING
: // 19
3708 case ASN1_T61_STRING
: // 20, also ASN1_TELETEX_STRING
3709 case ASN1_VIDEOTEX_STRING
: // 21
3710 case ASN1_IA5_STRING
: // 22
3711 case ASN1_GRAPHIC_STRING
: // 25
3712 case ASN1_VISIBLE_STRING
: // 26, also ASN1_ISO646_STRING
3713 case ASN1_GENERAL_STRING
: // 27
3714 case ASN1_UNIVERSAL_STRING
: // 28
3716 CFStringRef string
=
3717 copyDERThingContentDescription(CFGetAllocator(properties
),
3718 currDecoded
.tag
, &currDecoded
.content
, false);
3719 require_quiet(string
, badSequence
);
3721 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
3723 CFReleaseNull(string
);
3724 appendedSomething
= true;
3731 require_quiet(drtn
== DR_EndOfSequence
, badSequence
);
3732 return appendedSomething
;
3737 static void appendExtension(CFMutableArrayRef parent
,
3738 const SecCertificateExtension
*extn
) {
3739 CFAllocatorRef allocator
= CFGetAllocator(parent
);
3740 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
3741 &kCFTypeArrayCallBacks
);
3743 *extnID
= &extn
->extnID
,
3744 *extnValue
= &extn
->extnValue
;
3745 CFStringRef label
= NULL
;
3746 CFStringRef localizedLabel
= NULL
;
3748 appendBoolProperty(properties
, SEC_CRITICAL_KEY
, extn
->critical
);
3749 require_quiet(extnID
, xit
);
3751 bool handled
= true;
3752 /* Extensions that we know how to handle ourselves... */
3753 if (extnID
->length
== oidSubjectKeyIdentifier
.length
&&
3754 !memcmp(extnID
->data
, oidSubjectKeyIdentifier
.data
, extnID
->length
- 1))
3756 switch (extnID
->data
[extnID
->length
- 1]) {
3757 case 14: /* SubjectKeyIdentifier id-ce 14 */
3758 appendSubjectKeyIdentifier(properties
, extnValue
);
3760 case 15: /* KeyUsage id-ce 15 */
3761 appendKeyUsage(properties
, extnValue
);
3763 case 16: /* PrivateKeyUsagePeriod id-ce 16 */
3764 appendPrivateKeyUsagePeriod(properties
, extnValue
);
3766 case 17: /* SubjectAltName id-ce 17 */
3767 case 18: /* IssuerAltName id-ce 18 */
3768 appendGeneralNames(properties
, extnValue
);
3770 case 19: /* BasicConstraints id-ce 19 */
3771 appendBasicConstraints(properties
, extnValue
);
3773 case 30: /* NameConstraints id-ce 30 */
3774 appendNameConstraints(properties
, extnValue
);
3776 case 31: /* CRLDistributionPoints id-ce 31 */
3777 appendCrlDistributionPoints(properties
, extnValue
);
3779 case 32: /* CertificatePolicies id-ce 32 */
3780 appendCertificatePolicies(properties
, extnValue
);
3782 case 33: /* PolicyMappings id-ce 33 */
3785 case 35: /* AuthorityKeyIdentifier id-ce 35 */
3786 appendAuthorityKeyIdentifier(properties
, extnValue
);
3788 case 36: /* PolicyConstraints id-ce 36 */
3789 appendPolicyConstraints(properties
, extnValue
);
3791 case 37: /* ExtKeyUsage id-ce 37 */
3792 appendExtendedKeyUsage(properties
, extnValue
);
3794 case 46: /* FreshestCRL id-ce 46 */
3797 case 54: /* InhibitAnyPolicy id-ce 54 */
3804 } else if (extnID
->length
== oidAuthorityInfoAccess
.length
&&
3805 !memcmp(extnID
->data
, oidAuthorityInfoAccess
.data
, extnID
->length
- 1))
3807 switch (extnID
->data
[extnID
->length
- 1]) {
3808 case 1: /* AuthorityInfoAccess id-pe 1 */
3809 appendInfoAccess(properties
, extnValue
);
3811 case 3: /* QCStatements id-pe 3 */
3814 case 11: /* SubjectInfoAccess id-pe 11 */
3815 appendInfoAccess(properties
, extnValue
);
3821 } else if (DEROidCompare(extnID
, &oidNetscapeCertType
)) {
3822 /* 2.16.840.1.113730.1.1 netscape 1 1 */
3823 appendNetscapeCertType(properties
, extnValue
);
3829 /* Try to parse and display printable string(s). */
3830 if (appendPrintableDERSequence(properties
, SEC_DATA_KEY
, extnValue
)) {
3831 /* Nothing to do here appendPrintableDERSequence did the work. */
3833 /* Couldn't parse extension; dump the raw unparsed data as hex. */
3834 appendUnparsedProperty(properties
, SEC_DATA_KEY
, NULL
, extnValue
);
3837 label
= SecDERItemCopyOIDDecimalRepresentation(allocator
, extnID
);
3838 localizedLabel
= copyLocalizedOidDescription(allocator
, extnID
);
3839 appendProperty(parent
, kSecPropertyTypeSection
, label
, localizedLabel
, properties
);
3842 CFReleaseSafe(localizedLabel
);
3843 CFReleaseSafe(label
);
3844 CFReleaseSafe(properties
);
3847 /* Different types of summary types from least desired to most desired. */
3850 kSummaryTypePrintable
,
3851 kSummaryTypeOrganizationName
,
3852 kSummaryTypeOrganizationalUnitName
,
3853 kSummaryTypeCommonName
,
3857 enum SummaryType type
;
3858 CFStringRef summary
;
3859 CFStringRef description
;
3862 static OSStatus
obtainSummaryFromX501Name(void *context
,
3863 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
3864 struct Summary
*summary
= (struct Summary
*)context
;
3865 enum SummaryType stype
= kSummaryTypeNone
;
3866 CFStringRef string
= NULL
;
3867 if (DEROidCompare(type
, &oidCommonName
)) {
3868 stype
= kSummaryTypeCommonName
;
3869 } else if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
3870 stype
= kSummaryTypeOrganizationalUnitName
;
3871 } else if (DEROidCompare(type
, &oidOrganizationName
)) {
3872 stype
= kSummaryTypeOrganizationName
;
3873 } else if (DEROidCompare(type
, &oidDescription
)) {
3874 string
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
3876 if (summary
->description
) {
3877 CFStringRef fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
3878 CFStringRef newDescription
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, string
, summary
->description
);
3880 CFRelease(summary
->description
);
3881 summary
->description
= newDescription
;
3883 summary
->description
= string
;
3886 stype
= kSummaryTypePrintable
;
3889 stype
= kSummaryTypePrintable
;
3892 /* Build a string with all instances of the most desired
3893 component type in reverse order encountered comma separated list,
3894 The order of desirability is defined by enum SummaryType. */
3895 if (summary
->type
<= stype
) {
3897 string
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
3900 if (summary
->type
== stype
) {
3901 CFStringRef fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
3902 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, string
, summary
->summary
);
3905 string
= newSummary
;
3907 summary
->type
= stype
;
3909 CFReleaseSafe(summary
->summary
);
3910 summary
->summary
= string
;
3913 CFReleaseSafe(string
);
3916 return errSecSuccess
;
3919 CFStringRef
SecCertificateCopySubjectSummary(SecCertificateRef certificate
) {
3920 struct Summary summary
= {};
3921 parseX501NameContent(&certificate
->_subject
, &summary
, obtainSummaryFromX501Name
);
3922 /* If we found a description and a common name we change the summary to
3923 CommonName (Description). */
3924 if (summary
.description
) {
3925 if (summary
.type
== kSummaryTypeCommonName
) {
3926 CFStringRef fmt
= SecCopyCertString(SEC_COMMON_NAME_DESC_KEY
);
3927 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, summary
.summary
, summary
.description
);
3929 CFRelease(summary
.summary
);
3930 summary
.summary
= newSummary
;
3932 CFRelease(summary
.description
);
3935 if (!summary
.summary
) {
3936 /* If we didn't find a suitable printable string in the subject at all, we try
3937 the first email address in the certificate instead. */
3938 CFArrayRef names
= SecCertificateCopyRFC822Names(certificate
);
3940 /* If we didn't find any email addresses in the certificate, we try finding
3941 a DNS name instead. */
3942 names
= SecCertificateCopyDNSNames(certificate
);
3945 summary
.summary
= CFArrayGetValueAtIndex(names
, 0);
3946 CFRetain(summary
.summary
);
3951 return summary
.summary
;
3954 CFStringRef
SecCertificateCopyIssuerSummary(SecCertificateRef certificate
) {
3955 struct Summary summary
= {};
3956 parseX501NameContent(&certificate
->_issuer
, &summary
, obtainSummaryFromX501Name
);
3957 /* If we found a description and a common name we change the summary to
3958 CommonName (Description). */
3959 if (summary
.description
) {
3960 if (summary
.type
== kSummaryTypeCommonName
) {
3961 CFStringRef fmt
= SecCopyCertString(SEC_COMMON_NAME_DESC_KEY
);
3962 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, summary
.summary
, summary
.description
);
3964 CFRelease(summary
.summary
);
3965 summary
.summary
= newSummary
;
3967 CFRelease(summary
.description
);
3970 return summary
.summary
;
3973 /* Return the earliest date on which all certificates in this chain are still
3975 static CFAbsoluteTime
SecCertificateGetChainsLastValidity(
3976 SecCertificateRef certificate
) {
3977 CFAbsoluteTime earliest
= certificate
->_notAfter
;
3979 while (certificate
->_parent
) {
3980 certificate
= certificate
->_parent
;
3981 if (earliest
> certificate
->_notAfter
)
3982 earliest
= certificate
->_notAfter
;
3989 /* Return the latest date on which all certificates in this chain will be
3991 static CFAbsoluteTime
SecCertificateGetChainsFirstValidity(
3992 SecCertificateRef certificate
) {
3993 CFAbsoluteTime latest
= certificate
->_notBefore
;
3995 while (certificate
->_parent
) {
3996 certificate
= certificate
->_parent
;
3997 if (latest
< certificate
->_notBefore
)
3998 latest
= certificate
->_notBefore
;
4005 bool SecCertificateIsValid(SecCertificateRef certificate
,
4006 CFAbsoluteTime verifyTime
) {
4007 return certificate
&& certificate
->_notBefore
<= verifyTime
&&
4008 verifyTime
<= certificate
->_notAfter
;
4011 CFIndex
SecCertificateVersion(SecCertificateRef certificate
) {
4012 return certificate
->_version
+ 1;
4015 CFAbsoluteTime
SecCertificateNotValidBefore(SecCertificateRef certificate
) {
4016 return certificate
->_notBefore
;
4019 CFAbsoluteTime
SecCertificateNotValidAfter(SecCertificateRef certificate
) {
4020 return certificate
->_notAfter
;
4023 CFMutableArrayRef
SecCertificateCopySummaryProperties(
4024 SecCertificateRef certificate
, CFAbsoluteTime verifyTime
) {
4025 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
4026 CFMutableArrayRef summary
= CFArrayCreateMutable(allocator
, 0,
4027 &kCFTypeArrayCallBacks
);
4029 /* First we put the subject summary name. */
4030 CFStringRef ssummary
= SecCertificateCopySubjectSummary(certificate
);
4032 appendProperty(summary
, kSecPropertyTypeTitle
,
4033 NULL
, NULL
, ssummary
);
4034 CFRelease(ssummary
);
4037 /* Let see if this certificate is currently valid. */
4039 CFAbsoluteTime when
;
4040 CFStringRef message
;
4042 if (verifyTime
> certificate
->_notAfter
) {
4043 label
= SEC_EXPIRED_KEY
;
4044 when
= certificate
->_notAfter
;
4045 ptype
= kSecPropertyTypeError
;
4046 message
= SEC_CERT_EXPIRED_KEY
;
4047 } else if (certificate
->_notBefore
> verifyTime
) {
4048 label
= SEC_VALID_FROM_KEY
;
4049 when
= certificate
->_notBefore
;
4050 ptype
= kSecPropertyTypeError
;
4051 message
= SEC_CERT_NOT_YET_VALID_KEY
;
4053 CFAbsoluteTime last
= SecCertificateGetChainsLastValidity(certificate
);
4054 CFAbsoluteTime first
= SecCertificateGetChainsFirstValidity(certificate
);
4055 if (verifyTime
> last
) {
4056 label
= SEC_EXPIRED_KEY
;
4058 ptype
= kSecPropertyTypeError
;
4059 message
= SEC_ISSUER_EXPIRED_KEY
;
4060 } else if (verifyTime
< first
) {
4061 label
= SEC_VALID_FROM_KEY
;
4063 ptype
= kSecPropertyTypeError
;
4064 message
= SEC_ISSR_NOT_YET_VALID_KEY
;
4066 label
= SEC_EXPIRES_KEY
;
4067 when
= certificate
->_notAfter
;
4068 ptype
= kSecPropertyTypeSuccess
;
4069 message
= SEC_CERT_VALID_KEY
;
4073 appendDateProperty(summary
, label
, when
);
4074 CFStringRef lmessage
= SecCopyCertString(message
);
4075 appendProperty(summary
, ptype
, NULL
, NULL
, lmessage
);
4076 CFRelease(lmessage
);
4081 CFArrayRef
SecCertificateCopyProperties(SecCertificateRef certificate
) {
4082 if (!certificate
->_properties
) {
4083 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
4084 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
4085 &kCFTypeArrayCallBacks
);
4086 require_quiet(properties
, out
);
4089 /* First we put the Subject Name in the property list. */
4090 CFArrayRef subject_plist
= createPropertiesForX501NameContent(allocator
,
4091 &certificate
->_subject
);
4092 if (subject_plist
) {
4093 appendProperty(properties
, kSecPropertyTypeSection
,
4094 SEC_SUBJECT_NAME_KEY
, NULL
, subject_plist
);
4096 CFReleaseNull(subject_plist
);
4098 /* Next we put the Issuer Name in the property list. */
4099 CFArrayRef issuer_plist
= createPropertiesForX501NameContent(allocator
,
4100 &certificate
->_issuer
);
4102 appendProperty(properties
, kSecPropertyTypeSection
,
4103 SEC_ISSUER_NAME_KEY
, NULL
, issuer_plist
);
4105 CFReleaseNull(issuer_plist
);
4108 CFStringRef fmt
= SecCopyCertString(SEC_CERT_VERSION_VALUE_KEY
);
4109 CFStringRef versionString
= NULL
;
4111 versionString
= CFStringCreateWithFormat(allocator
, NULL
, fmt
,
4112 certificate
->_version
+ 1);
4115 if (versionString
) {
4116 appendProperty(properties
, kSecPropertyTypeString
,
4117 SEC_VERSION_KEY
, NULL
, versionString
);
4119 CFReleaseNull(versionString
);
4122 appendSerialNumberProperty(properties
, SEC_SERIAL_NUMBER_KEY
, &certificate
->_serialNum
);
4124 /* Validity dates. */
4125 appendValidityPeriodProperty(properties
, SEC_VALIDITY_PERIOD_KEY
, certificate
);
4127 if (certificate
->_subjectUniqueID
.length
) {
4128 appendDataProperty(properties
, SEC_SUBJECT_UNIQUE_ID_KEY
, NULL
,
4129 &certificate
->_subjectUniqueID
);
4131 if (certificate
->_issuerUniqueID
.length
) {
4132 appendDataProperty(properties
, SEC_ISSUER_UNIQUE_ID_KEY
, NULL
,
4133 &certificate
->_issuerUniqueID
);
4136 appendPublicKeyProperty(properties
, SEC_PUBLIC_KEY_KEY
, certificate
);
4139 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
4140 appendExtension(properties
, &certificate
->_extensions
[ix
]);
4144 appendSignatureProperty(properties
, SEC_SIGNATURE_KEY
, certificate
);
4146 appendFingerprintsProperty(properties
, SEC_FINGERPRINTS_KEY
, certificate
);
4148 certificate
->_properties
= properties
;
4152 CFRetainSafe(certificate
->_properties
);
4153 return certificate
->_properties
;
4156 /* Unified serial number API */
4157 CFDataRef
SecCertificateCopySerialNumberData(
4158 SecCertificateRef certificate
,
4163 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidCertificate
, NULL
);
4167 if (certificate
->_serialNumber
) {
4168 CFRetain(certificate
->_serialNumber
);
4170 return certificate
->_serialNumber
;
4174 /* On OS X, the SecCertificateCopySerialNumber API takes two arguments. */
4175 CFDataRef
SecCertificateCopySerialNumber(
4176 SecCertificateRef certificate
,
4177 CFErrorRef
*error
) {
4178 return SecCertificateCopySerialNumberData(certificate
, error
);
4181 /* On iOS, the SecCertificateCopySerialNumber API takes one argument. */
4182 CFDataRef
SecCertificateCopySerialNumber(
4183 SecCertificateRef certificate
) {
4184 return SecCertificateCopySerialNumberData(certificate
, NULL
);
4188 CFDataRef
SecCertificateGetNormalizedIssuerContent(
4189 SecCertificateRef certificate
) {
4190 return certificate
->_normalizedIssuer
;
4193 CFDataRef
SecCertificateGetNormalizedSubjectContent(
4194 SecCertificateRef certificate
) {
4195 return certificate
->_normalizedSubject
;
4198 /* Verify that certificate was signed by issuerKey. */
4199 OSStatus
SecCertificateIsSignedBy(SecCertificateRef certificate
,
4200 SecKeyRef issuerKey
) {
4201 /* Setup algId in SecAsn1AlgId format. */
4203 algId
.algorithm
.Length
= certificate
->_tbsSigAlg
.oid
.length
;
4204 algId
.algorithm
.Data
= certificate
->_tbsSigAlg
.oid
.data
;
4205 algId
.parameters
.Length
= certificate
->_tbsSigAlg
.params
.length
;
4206 algId
.parameters
.Data
= certificate
->_tbsSigAlg
.params
.data
;
4208 /* RFC5280 4.1.1.2, 4.1.2.3 requires the actual signature algorithm
4209 must match the specified algorithm in the TBSCertificate. */
4210 bool sigAlgMatch
= DEROidCompare(&certificate
->_sigAlg
.oid
,
4211 &certificate
->_tbsSigAlg
.oid
);
4213 secwarning("Signature algorithm mismatch in certificate (see RFC5280 4.1.1.2)");
4216 CFErrorRef error
= NULL
;
4218 !SecVerifySignatureWithPublicKey(issuerKey
, &algId
,
4219 certificate
->_tbs
.data
, certificate
->_tbs
.length
,
4220 certificate
->_signature
.data
, certificate
->_signature
.length
, &error
))
4222 #if !defined(NDEBUG)
4223 secdebug("verify", "signature verify failed: %" PRIdOSStatus
, (error
) ? (OSStatus
)CFErrorGetCode(error
) : errSecNotSigner
);
4225 CFReleaseSafe(error
);
4226 return errSecNotSigner
;
4229 return errSecSuccess
;
4232 const DERItem
* SecCertificateGetSubjectAltName(SecCertificateRef certificate
) {
4233 if (!certificate
->_subjectAltName
) {
4236 return &certificate
->_subjectAltName
->extnValue
;
4239 static OSStatus
appendIPAddressesFromGeneralNames(void *context
,
4240 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4241 CFMutableArrayRef ipAddresses
= (CFMutableArrayRef
)context
;
4242 if (gnType
== GNT_IPAddress
) {
4243 CFStringRef string
= copyIPAddressContentDescription(
4244 kCFAllocatorDefault
, generalName
);
4246 CFArrayAppendValue(ipAddresses
, string
);
4249 return errSecInvalidCertificate
;
4252 return errSecSuccess
;
4255 CFArrayRef
SecCertificateCopyIPAddresses(SecCertificateRef certificate
) {
4256 /* These can only exist in the subject alt name. */
4257 if (!certificate
->_subjectAltName
)
4260 CFMutableArrayRef ipAddresses
= CFArrayCreateMutable(kCFAllocatorDefault
,
4261 0, &kCFTypeArrayCallBacks
);
4262 OSStatus status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4263 ipAddresses
, appendIPAddressesFromGeneralNames
);
4264 if (status
|| CFArrayGetCount(ipAddresses
) == 0) {
4265 CFRelease(ipAddresses
);
4271 static OSStatus
appendDNSNamesFromGeneralNames(void *context
, SecCEGeneralNameType gnType
,
4272 const DERItem
*generalName
) {
4273 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4274 if (gnType
== GNT_DNSName
) {
4275 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorDefault
,
4276 generalName
->data
, generalName
->length
,
4277 kCFStringEncodingUTF8
, FALSE
);
4279 CFArrayAppendValue(dnsNames
, string
);
4282 return errSecInvalidCertificate
;
4285 return errSecSuccess
;
4288 /* Return true if the passed in string matches the
4289 Preferred name syntax from sections 2.3.1. in RFC 1035.
4290 With the added check that we disallow empty dns names.
4291 Also in order to support wildcard DNSNames we allow for the '*'
4292 character anywhere in a dns component where we currently allow
4295 <domain> ::= <subdomain> | " "
4297 <subdomain> ::= <label> | <subdomain> "." <label>
4299 <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
4301 <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
4303 <let-dig-hyp> ::= <let-dig> | "-"
4305 <let-dig> ::= <letter> | <digit>
4307 <letter> ::= any one of the 52 alphabetic characters A through Z in
4308 upper case and a through z in lower case
4310 <digit> ::= any one of the ten digits 0 through 9
4312 static bool isDNSName(CFStringRef string
) {
4313 CFStringInlineBuffer buf
= {};
4314 CFIndex ix
, labelLength
= 0, length
= CFStringGetLength(string
);
4315 /* From RFC 1035 2.3.4. Size limits:
4316 labels 63 octets or less
4317 names 255 octets or less */
4318 require_quiet(length
<= 255, notDNS
);
4319 CFRange range
= { 0, length
};
4320 CFStringInitInlineBuffer(string
, &buf
, range
);
4324 kDNSStateAfterAlpha
,
4325 kDNSStateAfterDigit
,
4327 } state
= kDNSStateInital
;
4329 for (ix
= 0; ix
< length
; ++ix
) {
4330 UniChar ch
= CFStringGetCharacterFromInlineBuffer(&buf
, ix
);
4333 require_quiet(labelLength
<= 64 &&
4334 (state
== kDNSStateAfterAlpha
|| state
== kDNSStateAfterDigit
),
4336 state
= kDNSStateAfterDot
;
4338 } else if (('A' <= ch
&& ch
<= 'Z') || ('a' <= ch
&& ch
<= 'z') ||
4340 state
= kDNSStateAfterAlpha
;
4341 } else if ('0' <= ch
&& ch
<= '9') {
4343 /* The requirement for labels to start with a letter was
4344 dropped so we don't check this anymore. */
4345 require_quiet(state
== kDNSStateAfterAlpha
||
4346 state
== kDNSStateAfterDigit
||
4347 state
== kDNSStateAfterDash
, notDNS
);
4349 state
= kDNSStateAfterDigit
;
4350 } else if (ch
== '-') {
4351 require_quiet(state
== kDNSStateAfterAlpha
||
4352 state
== kDNSStateAfterDigit
||
4353 state
== kDNSStateAfterDash
, notDNS
);
4354 state
= kDNSStateAfterDash
;
4360 /* We don't allow a dns name to end in a dot or dash. */
4361 require_quiet(labelLength
<= 63 &&
4362 (state
== kDNSStateAfterAlpha
|| state
== kDNSStateAfterDigit
),
4370 static OSStatus
appendDNSNamesFromX501Name(void *context
, const DERItem
*type
,
4371 const DERItem
*value
, CFIndex rdnIX
) {
4372 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4373 if (DEROidCompare(type
, &oidCommonName
)) {
4374 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4377 if (isDNSName(string
)) {
4378 /* We found a common name that is formatted like a valid
4380 CFArrayAppendValue(dnsNames
, string
);
4384 return errSecInvalidCertificate
;
4387 return errSecSuccess
;
4390 /* Not everything returned by this function is going to be a proper DNS name,
4391 we also return the certificates common name entries from the subject,
4392 assuming they look like dns names as specified in RFC 1035. */
4393 CFArrayRef
SecCertificateCopyDNSNames(SecCertificateRef certificate
) {
4394 /* These can exist in the subject alt name or in the subject. */
4395 CFMutableArrayRef dnsNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4396 0, &kCFTypeArrayCallBacks
);
4397 OSStatus status
= errSecSuccess
;
4398 if (certificate
->_subjectAltName
) {
4399 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4400 dnsNames
, appendDNSNamesFromGeneralNames
);
4402 /* RFC 2818 section 3.1. Server Identity
4404 If a subjectAltName extension of type dNSName is present, that MUST
4405 be used as the identity. Otherwise, the (most specific) Common Name
4406 field in the Subject field of the certificate MUST be used. Although
4407 the use of the Common Name is existing practice, it is deprecated and
4408 Certification Authorities are encouraged to use the dNSName instead.
4411 This implies that if we found 1 or more DNSNames in the
4412 subjectAltName, we should not use the Common Name of the subject as
4415 if (!status
&& CFArrayGetCount(dnsNames
) == 0) {
4416 status
= parseX501NameContent(&certificate
->_subject
, dnsNames
,
4417 appendDNSNamesFromX501Name
);
4419 if (status
|| CFArrayGetCount(dnsNames
) == 0) {
4420 CFRelease(dnsNames
);
4426 static OSStatus
appendRFC822NamesFromGeneralNames(void *context
,
4427 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4428 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4429 if (gnType
== GNT_RFC822Name
) {
4430 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorDefault
,
4431 generalName
->data
, generalName
->length
,
4432 kCFStringEncodingASCII
, FALSE
);
4434 CFArrayAppendValue(dnsNames
, string
);
4437 return errSecInvalidCertificate
;
4440 return errSecSuccess
;
4443 static OSStatus
appendRFC822NamesFromX501Name(void *context
, const DERItem
*type
,
4444 const DERItem
*value
, CFIndex rdnIX
) {
4445 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4446 if (DEROidCompare(type
, &oidEmailAddress
)) {
4447 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4450 CFArrayAppendValue(dnsNames
, string
);
4453 return errSecInvalidCertificate
;
4456 return errSecSuccess
;
4459 CFArrayRef
SecCertificateCopyRFC822Names(SecCertificateRef certificate
) {
4460 /* These can exist in the subject alt name or in the subject. */
4461 CFMutableArrayRef rfc822Names
= CFArrayCreateMutable(kCFAllocatorDefault
,
4462 0, &kCFTypeArrayCallBacks
);
4463 OSStatus status
= errSecSuccess
;
4464 if (certificate
->_subjectAltName
) {
4465 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4466 rfc822Names
, appendRFC822NamesFromGeneralNames
);
4469 status
= parseX501NameContent(&certificate
->_subject
, rfc822Names
,
4470 appendRFC822NamesFromX501Name
);
4472 if (status
|| CFArrayGetCount(rfc822Names
) == 0) {
4473 CFRelease(rfc822Names
);
4479 OSStatus
SecCertificateCopyEmailAddresses(SecCertificateRef certificate
, CFArrayRef
* __nonnull CF_RETURNS_RETAINED emailAddresses
) {
4480 if (!certificate
|| !emailAddresses
) {
4483 *emailAddresses
= SecCertificateCopyRFC822Names(certificate
);
4484 if (*emailAddresses
== NULL
) {
4485 *emailAddresses
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
4487 return errSecSuccess
;
4490 static OSStatus
appendCommonNamesFromX501Name(void *context
,
4491 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4492 CFMutableArrayRef commonNames
= (CFMutableArrayRef
)context
;
4493 if (DEROidCompare(type
, &oidCommonName
)) {
4494 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4497 CFArrayAppendValue(commonNames
, string
);
4500 return errSecInvalidCertificate
;
4503 return errSecSuccess
;
4506 CFArrayRef
SecCertificateCopyCommonNames(SecCertificateRef certificate
) {
4507 CFMutableArrayRef commonNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4508 0, &kCFTypeArrayCallBacks
);
4510 status
= parseX501NameContent(&certificate
->_subject
, commonNames
,
4511 appendCommonNamesFromX501Name
);
4512 if (status
|| CFArrayGetCount(commonNames
) == 0) {
4513 CFRelease(commonNames
);
4519 OSStatus
SecCertificateCopyCommonName(SecCertificateRef certificate
, CFStringRef
*commonName
)
4524 CFArrayRef commonNames
= SecCertificateCopyCommonNames(certificate
);
4526 return errSecInternal
;
4530 CFIndex count
= CFArrayGetCount(commonNames
);
4531 *commonName
= CFRetainSafe(CFArrayGetValueAtIndex(commonNames
, count
-1));
4533 CFReleaseSafe(commonNames
);
4534 return errSecSuccess
;
4537 static OSStatus
appendOrganizationFromX501Name(void *context
,
4538 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4539 CFMutableArrayRef organization
= (CFMutableArrayRef
)context
;
4540 if (DEROidCompare(type
, &oidOrganizationName
)) {
4541 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4544 CFArrayAppendValue(organization
, string
);
4547 return errSecInvalidCertificate
;
4550 return errSecSuccess
;
4553 CFArrayRef
SecCertificateCopyOrganization(SecCertificateRef certificate
) {
4554 CFMutableArrayRef organization
= CFArrayCreateMutable(kCFAllocatorDefault
,
4555 0, &kCFTypeArrayCallBacks
);
4557 status
= parseX501NameContent(&certificate
->_subject
, organization
,
4558 appendOrganizationFromX501Name
);
4559 if (status
|| CFArrayGetCount(organization
) == 0) {
4560 CFRelease(organization
);
4561 organization
= NULL
;
4563 return organization
;
4566 static OSStatus
appendOrganizationalUnitFromX501Name(void *context
,
4567 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4568 CFMutableArrayRef organizationalUnit
= (CFMutableArrayRef
)context
;
4569 if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
4570 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4573 CFArrayAppendValue(organizationalUnit
, string
);
4576 return errSecInvalidCertificate
;
4579 return errSecSuccess
;
4582 CFArrayRef
SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate
) {
4583 CFMutableArrayRef organizationalUnit
= CFArrayCreateMutable(kCFAllocatorDefault
,
4584 0, &kCFTypeArrayCallBacks
);
4586 status
= parseX501NameContent(&certificate
->_subject
, organizationalUnit
,
4587 appendOrganizationalUnitFromX501Name
);
4588 if (status
|| CFArrayGetCount(organizationalUnit
) == 0) {
4589 CFRelease(organizationalUnit
);
4590 organizationalUnit
= NULL
;
4592 return organizationalUnit
;
4595 static OSStatus
appendCountryFromX501Name(void *context
,
4596 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4597 CFMutableArrayRef countries
= (CFMutableArrayRef
)context
;
4598 if (DEROidCompare(type
, &oidCountryName
)) {
4599 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4602 CFArrayAppendValue(countries
, string
);
4605 return errSecInvalidCertificate
;
4608 return errSecSuccess
;
4611 CFArrayRef
SecCertificateCopyCountry(SecCertificateRef certificate
) {
4612 CFMutableArrayRef countries
= CFArrayCreateMutable(kCFAllocatorDefault
,
4613 0, &kCFTypeArrayCallBacks
);
4615 status
= parseX501NameContent(&certificate
->_subject
, countries
,
4616 appendCountryFromX501Name
);
4617 if (status
|| CFArrayGetCount(countries
) == 0) {
4618 CFRelease(countries
);
4624 const SecCEBasicConstraints
*
4625 SecCertificateGetBasicConstraints(SecCertificateRef certificate
) {
4626 if (certificate
->_basicConstraints
.present
)
4627 return &certificate
->_basicConstraints
;
4632 CFArrayRef
SecCertificateGetPermittedSubtrees(SecCertificateRef certificate
) {
4633 return (certificate
->_permittedSubtrees
);
4636 CFArrayRef
SecCertificateGetExcludedSubtrees(SecCertificateRef certificate
) {
4637 return (certificate
->_excludedSubtrees
);
4640 const SecCEPolicyConstraints
*
4641 SecCertificateGetPolicyConstraints(SecCertificateRef certificate
) {
4642 if (certificate
->_policyConstraints
.present
)
4643 return &certificate
->_policyConstraints
;
4648 const SecCEPolicyMappings
*
4649 SecCertificateGetPolicyMappings(SecCertificateRef certificate
) {
4650 if (certificate
->_policyMappings
.present
) {
4651 return &certificate
->_policyMappings
;
4657 const SecCECertificatePolicies
*
4658 SecCertificateGetCertificatePolicies(SecCertificateRef certificate
) {
4659 if (certificate
->_certificatePolicies
.present
)
4660 return &certificate
->_certificatePolicies
;
4665 const SecCEInhibitAnyPolicy
*
4666 SecCertificateGetInhibitAnyPolicySkipCerts(SecCertificateRef certificate
) {
4667 if (certificate
->_inhibitAnyPolicySkipCerts
.present
) {
4668 return &certificate
->_inhibitAnyPolicySkipCerts
;
4674 static OSStatus
appendNTPrincipalNamesFromGeneralNames(void *context
,
4675 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4676 CFMutableArrayRef ntPrincipalNames
= (CFMutableArrayRef
)context
;
4677 if (gnType
== GNT_OtherName
) {
4679 DERReturn drtn
= DERParseSequenceContent(generalName
,
4680 DERNumOtherNameItemSpecs
, DEROtherNameItemSpecs
,
4682 require_noerr_quiet(drtn
, badDER
);
4683 if (DEROidCompare(&on
.typeIdentifier
, &oidMSNTPrincipalName
)) {
4685 require_quiet(string
= copyDERThingDescription(kCFAllocatorDefault
,
4686 &on
.value
, true), badDER
);
4687 CFArrayAppendValue(ntPrincipalNames
, string
);
4691 return errSecSuccess
;
4694 return errSecInvalidCertificate
;
4698 CFArrayRef
SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate
) {
4699 CFMutableArrayRef ntPrincipalNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4700 0, &kCFTypeArrayCallBacks
);
4701 OSStatus status
= errSecSuccess
;
4702 if (certificate
->_subjectAltName
) {
4703 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4704 ntPrincipalNames
, appendNTPrincipalNamesFromGeneralNames
);
4706 if (status
|| CFArrayGetCount(ntPrincipalNames
) == 0) {
4707 CFRelease(ntPrincipalNames
);
4708 ntPrincipalNames
= NULL
;
4710 return ntPrincipalNames
;
4713 static OSStatus
appendToRFC2253String(void *context
,
4714 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4715 CFMutableStringRef string
= (CFMutableStringRef
)context
;
4719 ST stateOrProvinceName
4721 OU organizationalUnitName
4723 STREET streetAddress
4727 /* Prepend a + if this is not the first RDN in an RDN set.
4728 Otherwise prepend a , if this is not the first RDN. */
4730 CFStringAppend(string
, CFSTR("+"));
4731 else if (CFStringGetLength(string
)) {
4732 CFStringAppend(string
, CFSTR(","));
4735 CFStringRef label
, oid
= NULL
;
4736 /* @@@ Consider changing this to a dictionary lookup keyed by the
4737 decimal representation. */
4738 if (DEROidCompare(type
, &oidCommonName
)) {
4739 label
= CFSTR("CN");
4740 } else if (DEROidCompare(type
, &oidLocalityName
)) {
4742 } else if (DEROidCompare(type
, &oidStateOrProvinceName
)) {
4743 label
= CFSTR("ST");
4744 } else if (DEROidCompare(type
, &oidOrganizationName
)) {
4746 } else if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
4747 label
= CFSTR("OU");
4748 } else if (DEROidCompare(type
, &oidCountryName
)) {
4751 } else if (DEROidCompare(type
, &oidStreetAddress
)) {
4752 label
= CFSTR("STREET");
4753 } else if (DEROidCompare(type
, &oidDomainComponent
)) {
4754 label
= CFSTR("DC");
4755 } else if (DEROidCompare(type
, &oidUserID
)) {
4756 label
= CFSTR("UID");
4759 label
= oid
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, type
);
4762 CFStringAppend(string
, label
);
4763 CFStringAppend(string
, CFSTR("="));
4764 CFStringRef raw
= NULL
;
4766 raw
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
4769 /* Append raw to string while escaping:
4770 a space or "#" character occurring at the beginning of the string
4771 a space character occurring at the end of the string
4772 one of the characters ",", "+", """, "\", "<", ">" or ";"
4774 CFStringInlineBuffer buffer
= {};
4775 CFIndex ix
, length
= CFStringGetLength(raw
);
4776 CFRange range
= { 0, length
};
4777 CFStringInitInlineBuffer(raw
, &buffer
, range
);
4778 for (ix
= 0; ix
< length
; ++ix
) {
4779 UniChar ch
= CFStringGetCharacterFromInlineBuffer(&buffer
, ix
);
4781 CFStringAppendFormat(string
, NULL
, CFSTR("\\%02X"), ch
);
4782 } else if (ch
== ',' || ch
== '+' || ch
== '"' || ch
== '\\' ||
4783 ch
== '<' || ch
== '>' || ch
== ';' ||
4784 (ch
== ' ' && (ix
== 0 || ix
== length
- 1)) ||
4785 (ch
== '#' && ix
== 0)) {
4786 UniChar chars
[] = { '\\', ch
};
4787 CFStringAppendCharacters(string
, chars
, 2);
4789 CFStringAppendCharacters(string
, &ch
, 1);
4794 /* Append the value in hex. */
4795 CFStringAppend(string
, CFSTR("#"));
4797 for (ix
= 0; ix
< value
->length
; ++ix
)
4798 CFStringAppendFormat(string
, NULL
, CFSTR("%02X"), value
->data
[ix
]);
4803 return errSecSuccess
;
4806 CFStringRef
SecCertificateCopySubjectString(SecCertificateRef certificate
) {
4807 CFMutableStringRef string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
4808 OSStatus status
= parseX501NameContent(&certificate
->_subject
, string
, appendToRFC2253String
);
4809 if (status
|| CFStringGetLength(string
) == 0) {
4816 static OSStatus
appendToCompanyNameString(void *context
,
4817 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4818 CFMutableStringRef string
= (CFMutableStringRef
)context
;
4819 if (CFStringGetLength(string
) != 0)
4820 return errSecSuccess
;
4822 if (!DEROidCompare(type
, &oidOrganizationName
))
4823 return errSecSuccess
;
4826 raw
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
4828 return errSecSuccess
;
4829 CFStringAppend(string
, raw
);
4832 return errSecSuccess
;
4835 CFStringRef
SecCertificateCopyCompanyName(SecCertificateRef certificate
) {
4836 CFMutableStringRef string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
4837 OSStatus status
= parseX501NameContent(&certificate
->_subject
, string
,
4838 appendToCompanyNameString
);
4839 if (status
|| CFStringGetLength(string
) == 0) {
4846 CFDataRef
SecCertificateCopyIssuerSequence(
4847 SecCertificateRef certificate
) {
4848 return SecDERItemCopySequence(&certificate
->_issuer
);
4851 CFDataRef
SecCertificateCopySubjectSequence(
4852 SecCertificateRef certificate
) {
4853 return SecDERItemCopySequence(&certificate
->_subject
);
4856 CFDataRef
SecCertificateCopyNormalizedIssuerSequence(SecCertificateRef certificate
) {
4857 if (!certificate
|| !certificate
->_normalizedIssuer
) {
4860 return SecCopySequenceFromContent(certificate
->_normalizedIssuer
);
4863 CFDataRef
SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certificate
) {
4864 if (!certificate
|| !certificate
->_normalizedSubject
) {
4867 return SecCopySequenceFromContent(certificate
->_normalizedSubject
);
4870 const DERAlgorithmId
*SecCertificateGetPublicKeyAlgorithm(
4871 SecCertificateRef certificate
) {
4872 return &certificate
->_algId
;
4875 const DERItem
*SecCertificateGetPublicKeyData(SecCertificateRef certificate
) {
4876 return &certificate
->_pubKeyDER
;
4880 /* There is already a SecCertificateCopyPublicKey with different args on OS X,
4881 so we will refer to this one internally as SecCertificateCopyPublicKey_ios.
4883 __nullable SecKeyRef
SecCertificateCopyPublicKey_ios(SecCertificateRef certificate
)
4885 __nullable SecKeyRef
SecCertificateCopyPublicKey(SecCertificateRef certificate
)
4888 if (certificate
->_pubKey
== NULL
) {
4889 const DERAlgorithmId
*algId
=
4890 SecCertificateGetPublicKeyAlgorithm(certificate
);
4891 const DERItem
*keyData
= SecCertificateGetPublicKeyData(certificate
);
4892 const DERItem
*params
= NULL
;
4893 if (algId
->params
.length
!= 0) {
4894 params
= &algId
->params
;
4896 SecAsn1Oid oid1
= { .Data
= algId
->oid
.data
, .Length
= algId
->oid
.length
};
4897 SecAsn1Item params1
= {
4898 .Data
= params
? params
->data
: NULL
,
4899 .Length
= params
? params
->length
: 0
4901 SecAsn1Item keyData1
= {
4902 .Data
= keyData
? keyData
->data
: NULL
,
4903 .Length
= keyData
? keyData
->length
: 0
4905 certificate
->_pubKey
= SecKeyCreatePublicFromDER(kCFAllocatorDefault
, &oid1
, ¶ms1
,
4909 return CFRetainSafe(certificate
->_pubKey
);
4912 static CFIndex
SecCertificateGetPublicKeyAlgorithmIdAndSize(SecCertificateRef certificate
, size_t *keySizeInBytes
) {
4913 CFIndex keyAlgID
= kSecNullAlgorithmID
;
4916 SecKeyRef pubKey
= NULL
;
4917 require_quiet(certificate
, out
);
4919 require_quiet(pubKey
= SecCertificateCopyPublicKey_ios(certificate
), out
);
4921 require_quiet(pubKey
= SecCertificateCopyPublicKey(certificate
) ,out
);
4923 size
= SecKeyGetBlockSize(pubKey
);
4924 keyAlgID
= SecKeyGetAlgorithmId(pubKey
);
4927 CFReleaseNull(pubKey
);
4928 if (keySizeInBytes
) { *keySizeInBytes
= size
; }
4933 * Public keys in certificates may be considered "weak" or "strong" or neither
4934 * (that is, in between). Certificates using weak keys are not trusted at all.
4935 * Certificates using neither strong nor weak keys are only trusted in certain
4936 * contexts. SecPolicy and SecPolicyServer define the contexts by which we enforce
4937 * these (or stronger) key size trust policies.
4939 bool SecCertificateIsWeakKey(SecCertificateRef certificate
) {
4940 if (!certificate
) { return true; }
4944 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) {
4945 case kSecRSAAlgorithmID
:
4946 if (MIN_RSA_KEY_SIZE
<= size
) weak
= false;
4948 case kSecECDSAAlgorithmID
:
4949 if (MIN_EC_KEY_SIZE
<= size
) weak
= false;
4957 bool SecCertificateIsStrongKey(SecCertificateRef certificate
) {
4958 if (!certificate
) { return false; }
4960 bool strong
= false;
4962 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) {
4963 case kSecRSAAlgorithmID
:
4964 if (MIN_STRONG_RSA_KEY_SIZE
<= size
) strong
= true;
4966 case kSecECDSAAlgorithmID
:
4967 if (MIN_STRONG_EC_KEY_SIZE
<= size
) strong
= true;
4975 bool SecCertificateIsWeakHash(SecCertificateRef certificate
) {
4976 if (!certificate
) { return true; }
4977 SecSignatureHashAlgorithm certAlg
= 0;
4978 certAlg
= SecCertificateGetSignatureHashAlgorithm(certificate
);
4979 if (certAlg
== kSecSignatureHashAlgorithmUnknown
||
4980 certAlg
== kSecSignatureHashAlgorithmMD2
||
4981 certAlg
== kSecSignatureHashAlgorithmMD4
||
4982 certAlg
== kSecSignatureHashAlgorithmMD5
||
4983 certAlg
== kSecSignatureHashAlgorithmSHA1
) {
4989 bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate
,
4990 CFDictionaryRef keySizes
) {
4991 if (!certificate
) { return false; }
4993 bool goodSize
= false;
4995 CFNumberRef minSize
;
4996 size_t minSizeInBits
;
4997 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) {
4998 case kSecRSAAlgorithmID
:
4999 if(CFDictionaryGetValueIfPresent(keySizes
, kSecAttrKeyTypeRSA
, (const void**)&minSize
)
5000 && minSize
&& CFNumberGetValue(minSize
, kCFNumberLongType
, &minSizeInBits
)) {
5001 if (size
>= (size_t)(minSizeInBits
+7)/8) goodSize
= true;
5004 case kSecECDSAAlgorithmID
:
5005 if(CFDictionaryGetValueIfPresent(keySizes
, kSecAttrKeyTypeEC
, (const void**)&minSize
)
5006 && minSize
&& CFNumberGetValue(minSize
, kCFNumberLongType
, &minSizeInBits
)) {
5007 if (size
>= (size_t)(minSizeInBits
+7)/8) goodSize
= true;
5016 CFDataRef
SecCertificateGetSHA1Digest(SecCertificateRef certificate
) {
5017 if (!certificate
|| !certificate
->_der
.data
) {
5020 if (!certificate
->_sha1Digest
) {
5021 certificate
->_sha1Digest
=
5022 SecSHA1DigestCreate(CFGetAllocator(certificate
),
5023 certificate
->_der
.data
, certificate
->_der
.length
);
5025 return certificate
->_sha1Digest
;
5028 CFDataRef
SecCertificateCopySHA256Digest(SecCertificateRef certificate
) {
5029 if (!certificate
|| !certificate
->_der
.data
) {
5032 return SecSHA256DigestCreate(CFGetAllocator(certificate
),
5033 certificate
->_der
.data
, certificate
->_der
.length
);
5036 CFDataRef
SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate
) {
5037 CFDataRef digest
= NULL
;
5038 CFDataRef issuer
= SecCertificateCopyIssuerSequence(certificate
);
5040 digest
= SecSHA1DigestCreate(kCFAllocatorDefault
,
5041 CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
));
5047 CFDataRef
SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate
) {
5048 if (!certificate
|| !certificate
->_pubKeyDER
.data
) {
5051 return SecSHA1DigestCreate(CFGetAllocator(certificate
),
5052 certificate
->_pubKeyDER
.data
, certificate
->_pubKeyDER
.length
);
5055 CFDataRef
SecCertificateCopySubjectPublicKeyInfoSHA1Digest(SecCertificateRef certificate
) {
5056 if (!certificate
|| !certificate
->_subjectPublicKeyInfo
.data
) {
5059 return SecSHA1DigestCreate(CFGetAllocator(certificate
),
5060 certificate
->_subjectPublicKeyInfo
.data
, certificate
->_subjectPublicKeyInfo
.length
);
5063 CFDataRef
SecCertificateCopySubjectPublicKeyInfoSHA256Digest(SecCertificateRef certificate
) {
5064 if (!certificate
|| !certificate
->_subjectPublicKeyInfo
.data
) {
5067 return SecSHA256DigestCreate(CFGetAllocator(certificate
),
5068 certificate
->_subjectPublicKeyInfo
.data
, certificate
->_subjectPublicKeyInfo
.length
);
5071 CFTypeRef
SecCertificateCopyKeychainItem(SecCertificateRef certificate
)
5076 CFRetainSafe(certificate
->_keychain_item
);
5077 return certificate
->_keychain_item
;
5080 CFDataRef
SecCertificateGetAuthorityKeyID(SecCertificateRef certificate
) {
5084 if (!certificate
->_authorityKeyID
&&
5085 certificate
->_authorityKeyIdentifier
.length
) {
5086 certificate
->_authorityKeyID
= CFDataCreate(kCFAllocatorDefault
,
5087 certificate
->_authorityKeyIdentifier
.data
,
5088 certificate
->_authorityKeyIdentifier
.length
);
5091 return certificate
->_authorityKeyID
;
5094 CFDataRef
SecCertificateGetSubjectKeyID(SecCertificateRef certificate
) {
5098 if (!certificate
->_subjectKeyID
&&
5099 certificate
->_subjectKeyIdentifier
.length
) {
5100 certificate
->_subjectKeyID
= CFDataCreate(kCFAllocatorDefault
,
5101 certificate
->_subjectKeyIdentifier
.data
,
5102 certificate
->_subjectKeyIdentifier
.length
);
5105 return certificate
->_subjectKeyID
;
5108 CFArrayRef
SecCertificateGetCRLDistributionPoints(SecCertificateRef certificate
) {
5112 return certificate
->_crlDistributionPoints
;
5115 CFArrayRef
SecCertificateGetOCSPResponders(SecCertificateRef certificate
) {
5119 return certificate
->_ocspResponders
;
5122 CFArrayRef
SecCertificateGetCAIssuers(SecCertificateRef certificate
) {
5126 return certificate
->_caIssuers
;
5129 bool SecCertificateHasCriticalSubjectAltName(SecCertificateRef certificate
) {
5133 return certificate
->_subjectAltName
&&
5134 certificate
->_subjectAltName
->critical
;
5137 bool SecCertificateHasSubject(SecCertificateRef certificate
) {
5141 /* Since the _subject field is the content of the subject and not the
5142 whole thing, we can simply check for a 0 length subject here. */
5143 return certificate
->_subject
.length
!= 0;
5146 bool SecCertificateHasUnknownCriticalExtension(SecCertificateRef certificate
) {
5150 return certificate
->_foundUnknownCriticalExtension
;
5153 /* Private API functions. */
5154 void SecCertificateShow(SecCertificateRef certificate
) {
5156 fprintf(stderr
, "SecCertificate instance %p:\n", certificate
);
5157 fprintf(stderr
, "\n");
5161 CFDictionaryRef
SecCertificateCopyAttributeDictionary(
5162 SecCertificateRef certificate
) {
5163 if (!certificate
|| !(CFGetTypeID(certificate
) == SecCertificateGetTypeID())) {
5166 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
5167 CFNumberRef certificateType
= NULL
;
5168 CFNumberRef certificateEncoding
= NULL
;
5169 CFStringRef label
= NULL
;
5170 CFStringRef alias
= NULL
;
5171 CFDataRef skid
= NULL
;
5172 CFDataRef pubKeyDigest
= NULL
;
5173 CFDataRef certData
= NULL
;
5174 CFDictionaryRef dict
= NULL
;
5178 /* CSSM_CERT_X_509v1, CSSM_CERT_X_509v2 or CSSM_CERT_X_509v3 */
5179 SInt32 ctv
= certificate
->_version
+ 1;
5180 SInt32 cev
= 3; /* CSSM_CERT_ENCODING_DER */
5181 certificateType
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &ctv
);
5182 require_quiet(certificateType
!= NULL
, out
);
5183 certificateEncoding
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &cev
);
5184 require_quiet(certificateEncoding
!= NULL
, out
);
5185 certData
= SecCertificateCopyData(certificate
);
5186 require_quiet(certData
!= NULL
, out
);
5187 skid
= SecCertificateGetSubjectKeyID(certificate
);
5188 require_quiet(certificate
->_pubKeyDER
.data
!= NULL
&& certificate
->_pubKeyDER
.length
> 0, out
);
5189 pubKeyDigest
= SecSHA1DigestCreate(allocator
, certificate
->_pubKeyDER
.data
,
5190 certificate
->_pubKeyDER
.length
);
5191 require_quiet(pubKeyDigest
!= NULL
, out
);
5193 /* We still need to figure out how to deal with multi valued attributes. */
5194 alias
= SecCertificateCopyRFC822Names(certificate
);
5195 label
= SecCertificateCopySubjectSummary(certificate
);
5201 DICT_ADDPAIR(kSecClass
, kSecClassCertificate
);
5202 DICT_ADDPAIR(kSecAttrCertificateType
, certificateType
);
5203 DICT_ADDPAIR(kSecAttrCertificateEncoding
, certificateEncoding
);
5205 DICT_ADDPAIR(kSecAttrLabel
, label
);
5208 DICT_ADDPAIR(kSecAttrAlias
, alias
);
5210 if (isData(certificate
->_normalizedSubject
)) {
5211 DICT_ADDPAIR(kSecAttrSubject
, certificate
->_normalizedSubject
);
5213 require_quiet(isData(certificate
->_normalizedIssuer
), out
);
5214 DICT_ADDPAIR(kSecAttrIssuer
, certificate
->_normalizedIssuer
);
5215 require_quiet(isData(certificate
->_serialNumber
), out
);
5216 DICT_ADDPAIR(kSecAttrSerialNumber
, certificate
->_serialNumber
);
5218 DICT_ADDPAIR(kSecAttrSubjectKeyID
, skid
);
5220 DICT_ADDPAIR(kSecAttrPublicKeyHash
, pubKeyDigest
);
5221 DICT_ADDPAIR(kSecValueData
, certData
);
5222 dict
= DICT_CREATE(allocator
);
5225 CFReleaseSafe(label
);
5226 CFReleaseSafe(alias
);
5227 CFReleaseSafe(pubKeyDigest
);
5228 CFReleaseSafe(certData
);
5229 CFReleaseSafe(certificateEncoding
);
5230 CFReleaseSafe(certificateType
);
5235 SecCertificateRef
SecCertificateCreateFromAttributeDictionary(
5236 CFDictionaryRef refAttributes
) {
5237 /* @@@ Support having an allocator in refAttributes. */
5238 CFAllocatorRef allocator
= NULL
;
5239 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecValueData
);
5240 return data
? SecCertificateCreateWithData(allocator
, data
) : NULL
;
5244 static bool _SecCertificateIsSelfSigned(SecCertificateRef certificate
) {
5245 if (certificate
->_isSelfSigned
== kSecSelfSignedUnknown
) {
5246 certificate
->_isSelfSigned
= kSecSelfSignedFalse
;
5247 SecKeyRef publicKey
= NULL
;
5248 require(certificate
&& (CFGetTypeID(certificate
) == SecCertificateGetTypeID()), out
);
5250 require(publicKey
= SecCertificateCopyPublicKey_ios(certificate
), out
);
5252 require(publicKey
= SecCertificateCopyPublicKey(certificate
), out
);
5254 CFDataRef normalizedIssuer
=
5255 SecCertificateGetNormalizedIssuerContent(certificate
);
5256 CFDataRef normalizedSubject
=
5257 SecCertificateGetNormalizedSubjectContent(certificate
);
5258 require_quiet(normalizedIssuer
&& normalizedSubject
&&
5259 CFEqual(normalizedIssuer
, normalizedSubject
), out
);
5261 CFDataRef authorityKeyID
= SecCertificateGetAuthorityKeyID(certificate
);
5262 CFDataRef subjectKeyID
= SecCertificateGetSubjectKeyID(certificate
);
5263 if (authorityKeyID
) {
5264 require_quiet(subjectKeyID
&& CFEqual(subjectKeyID
, authorityKeyID
), out
);
5267 require_noerr_quiet(SecCertificateIsSignedBy(certificate
, publicKey
), out
);
5269 certificate
->_isSelfSigned
= kSecSelfSignedTrue
;
5271 CFReleaseSafe(publicKey
);
5274 return (certificate
->_isSelfSigned
== kSecSelfSignedTrue
);
5277 bool SecCertificateIsCA(SecCertificateRef certificate
) {
5278 bool result
= false;
5279 require(certificate
&& (CFGetTypeID(certificate
) == SecCertificateGetTypeID()), out
);
5280 if (SecCertificateVersion(certificate
) >= 3) {
5281 const SecCEBasicConstraints
*basicConstraints
= SecCertificateGetBasicConstraints(certificate
);
5282 result
= (basicConstraints
&& basicConstraints
->isCA
);
5285 result
= _SecCertificateIsSelfSigned(certificate
);
5291 bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate
) {
5292 return (_SecCertificateIsSelfSigned(certificate
) && SecCertificateIsCA(certificate
));
5295 OSStatus
SecCertificateIsSelfSigned(SecCertificateRef certificate
, Boolean
*isSelfSigned
) {
5296 if (!certificate
|| (CFGetTypeID(certificate
) != SecCertificateGetTypeID())) {
5297 return errSecInvalidCertificate
;
5299 if (!isSelfSigned
) {
5302 *isSelfSigned
= _SecCertificateIsSelfSigned(certificate
);
5303 return errSecSuccess
;
5306 SecKeyUsage
SecCertificateGetKeyUsage(SecCertificateRef certificate
) {
5308 return kSecKeyUsageUnspecified
;
5310 return certificate
->_keyUsage
;
5313 CFArrayRef
SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate
)
5315 CFMutableArrayRef extended_key_usage_oids
=
5316 CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
5317 require_quiet(certificate
&& extended_key_usage_oids
, out
);
5319 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5320 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5321 if (extn
->extnID
.length
== oidExtendedKeyUsage
.length
&&
5322 !memcmp(extn
->extnID
.data
, oidExtendedKeyUsage
.data
, extn
->extnID
.length
)) {
5325 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &derSeq
);
5326 require_noerr_quiet(drtn
, out
);
5327 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, out
);
5328 DERDecodedInfo currDecoded
;
5330 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
5331 require_quiet(currDecoded
.tag
== ASN1_OBJECT_ID
, out
);
5332 CFDataRef oid
= CFDataCreate(kCFAllocatorDefault
,
5333 currDecoded
.content
.data
, currDecoded
.content
.length
);
5334 require_quiet(oid
, out
);
5335 CFArrayAppendValue(extended_key_usage_oids
, oid
);
5338 require_quiet(drtn
== DR_EndOfSequence
, out
);
5339 return extended_key_usage_oids
;
5343 CFReleaseSafe(extended_key_usage_oids
);
5347 CFArrayRef
SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate
)
5349 require_quiet(certificate
, out
);
5352 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5353 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5354 if (extn
->extnID
.length
== oidGoogleEmbeddedSignedCertificateTimestamp
.length
&&
5355 !memcmp(extn
->extnID
.data
, oidGoogleEmbeddedSignedCertificateTimestamp
.data
, extn
->extnID
.length
)) {
5356 /* Got the SCT oid */
5357 DERDecodedInfo sctList
;
5358 DERReturn drtn
= DERDecodeItem(&extn
->extnValue
, &sctList
);
5359 require_noerr_quiet(drtn
, out
);
5360 require_quiet(sctList
.tag
== ASN1_OCTET_STRING
, out
);
5361 return SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sctList
.content
.data
, sctList
.content
.length
);
5369 static bool matches_expected(DERItem der
, CFTypeRef expected
) {
5370 if (der
.length
> 1) {
5371 DERDecodedInfo decoded
;
5372 DERDecodeItem(&der
, &decoded
);
5373 switch (decoded
.tag
) {
5376 return decoded
.content
.length
== 0 && expected
== NULL
;
5380 case ASN1_IA5_STRING
:
5381 case ASN1_UTF8_STRING
: {
5382 if (isString(expected
)) {
5383 CFStringRef expectedString
= (CFStringRef
) expected
;
5384 CFStringRef itemString
= CFStringCreateWithBytesNoCopy(kCFAllocatorDefault
, decoded
.content
.data
, decoded
.content
.length
, kCFStringEncodingUTF8
, false, kCFAllocatorNull
);
5386 bool result
= (kCFCompareEqualTo
== CFStringCompare(expectedString
, itemString
, 0));
5387 CFReleaseNull(itemString
);
5393 case ASN1_OCTET_STRING
: {
5394 if (isData(expected
)) {
5395 CFDataRef expectedData
= (CFDataRef
) expected
;
5396 CFDataRef itemData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, decoded
.content
.data
, decoded
.content
.length
, kCFAllocatorNull
);
5398 bool result
= CFEqual(expectedData
, itemData
);
5399 CFReleaseNull(itemData
);
5405 case ASN1_INTEGER
: {
5406 SInt32 expected_value
= 0;
5407 if (isString(expected
))
5409 CFStringRef aStr
= (CFStringRef
)expected
;
5410 expected_value
= CFStringGetIntValue(aStr
);
5412 else if (isNumber(expected
))
5414 CFNumberGetValue(expected
, kCFNumberSInt32Type
, &expected_value
);
5417 uint32_t num_value
= 0;
5418 if (!DERParseInteger(&decoded
.content
, &num_value
))
5420 return ((uint32_t)expected_value
== num_value
);
5433 static bool cert_contains_marker_extension_value(SecCertificateRef certificate
, CFDataRef oid
, CFTypeRef expectedValue
)
5436 const uint8_t *oid_data
= CFDataGetBytePtr(oid
);
5437 size_t oid_len
= CFDataGetLength(oid
);
5439 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5440 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5441 if (extn
->extnID
.length
== oid_len
5442 && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
))
5444 return matches_expected(extn
->extnValue
, expectedValue
);
5450 static bool cert_contains_marker_extension(SecCertificateRef certificate
, CFTypeRef oid
)
5452 return cert_contains_marker_extension_value(certificate
, oid
, NULL
);
5455 struct search_context
{
5457 SecCertificateRef certificate
;
5460 static bool GetDecimalValueOfString(CFStringRef string
, uint32_t* value
)
5462 CFCharacterSetRef nonDecimalDigit
= CFCharacterSetCreateInvertedSet(NULL
, CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
));
5463 bool result
= false;
5465 if ( CFStringGetLength(string
) > 0
5466 && !CFStringFindCharacterFromSet(string
, nonDecimalDigit
, CFRangeMake(0, CFStringGetLength(string
)), kCFCompareForcedOrdering
, NULL
))
5469 *value
= CFStringGetIntValue(string
);
5473 CFReleaseNull(nonDecimalDigit
);
5478 bool SecCertificateIsOidString(CFStringRef oid
)
5480 if (!oid
) return false;
5481 if (2 >= CFStringGetLength(oid
)) return false;
5484 /* oid string only has the allowed characters */
5485 CFCharacterSetRef decimalOid
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("0123456789."));
5486 CFCharacterSetRef nonDecimalOid
= CFCharacterSetCreateInvertedSet(NULL
, decimalOid
);
5487 if (CFStringFindCharacterFromSet(oid
, nonDecimalOid
, CFRangeMake(0, CFStringGetLength(oid
)), kCFCompareForcedOrdering
, NULL
)) {
5491 /* first arc is allowed */
5492 UniChar firstArc
[2];
5493 CFRange firstTwo
= {0, 2};
5494 CFStringGetCharacters(oid
, firstTwo
, firstArc
);
5495 if (firstArc
[1] != '.' ||
5496 (firstArc
[0] != '0' && firstArc
[0] != '1' && firstArc
[0] != '2')) {
5500 CFReleaseNull(decimalOid
);
5501 CFReleaseNull(nonDecimalOid
);
5506 CFDataRef
SecCertificateCreateOidDataFromString(CFAllocatorRef allocator
, CFStringRef string
)
5508 CFMutableDataRef currentResult
= NULL
;
5509 CFDataRef encodedResult
= NULL
;
5511 CFArrayRef parts
= NULL
;
5514 if (!string
|| !SecCertificateIsOidString(string
))
5517 parts
= CFStringCreateArrayBySeparatingStrings(NULL
, string
, CFSTR("."));
5522 count
= CFArrayGetCount(parts
);
5526 // assume no more than 5 bytes needed to represent any part of the oid,
5527 // since we limit parts to 32-bit values,
5528 // but the first two parts only need 1 byte
5529 currentResult
= CFDataCreateMutable(allocator
, 1+(count
-2)*5);
5535 part
= CFArrayGetValueAtIndex(parts
, 0);
5537 if (!GetDecimalValueOfString(part
, &x
) || x
> 6)
5544 part
= CFArrayGetValueAtIndex(parts
, 1);
5546 if (!GetDecimalValueOfString(part
, &x
) || x
> 39)
5552 CFDataAppendBytes(currentResult
, &firstByte
, 1);
5554 for (CFIndex i
= 2; i
< count
&& GetDecimalValueOfString(CFArrayGetValueAtIndex(parts
, i
), &x
); ++i
) {
5555 uint8_t b
[5] = {0, 0, 0, 0, 0};
5557 b
[3] = 0x80 | ((x
>> 7) & 0x7F);
5558 b
[2] = 0x80 | ((x
>> 14) & 0x7F);
5559 b
[1] = 0x80 | ((x
>> 21) & 0x7F);
5560 b
[0] = 0x80 | ((x
>> 28) & 0x7F);
5562 // Skip the unused extension bytes.
5563 size_t skipBytes
= 0;
5564 while (b
[skipBytes
] == 0x80)
5567 CFDataAppendBytes(currentResult
, b
+ skipBytes
, sizeof(b
) - skipBytes
);
5570 encodedResult
= currentResult
;
5571 currentResult
= NULL
;
5574 CFReleaseNull(parts
);
5575 CFReleaseNull(currentResult
);
5577 return encodedResult
;
5580 static void check_for_marker(const void *key
, const void *value
, void *context
)
5582 struct search_context
* search_ctx
= (struct search_context
*) context
;
5583 CFStringRef key_string
= (CFStringRef
) key
;
5584 CFTypeRef value_ref
= (CFTypeRef
) value
;
5586 // If we could have short circuted the iteration
5587 // we would have, but the best we can do
5588 // is not waste time comparing once a match
5590 if (search_ctx
->found
)
5593 if (CFGetTypeID(key_string
) != CFStringGetTypeID())
5596 CFDataRef key_data
= SecCertificateCreateOidDataFromString(NULL
, key_string
);
5598 if (NULL
== key_data
)
5601 if (cert_contains_marker_extension_value(search_ctx
->certificate
, key_data
, value_ref
))
5602 search_ctx
->found
= true;
5604 CFReleaseNull(key_data
);
5608 // CFType Ref is either:
5610 // CFData - OID to match with no data permitted
5611 // CFString - decimal OID to match
5612 // CFDictionary - OID -> Value table for expected values Single Object or Array
5613 // CFArray - Array of the above.
5615 // This returns true if any of the requirements are met.
5616 bool SecCertificateHasMarkerExtension(SecCertificateRef certificate
, CFTypeRef oids
)
5618 if (CFGetTypeID(oids
) == CFArrayGetTypeID()) {
5619 CFIndex ix
, length
= CFArrayGetCount(oids
);
5620 for (ix
= 0; ix
< length
; ix
++)
5621 if (SecCertificateHasMarkerExtension(certificate
, CFArrayGetValueAtIndex((CFArrayRef
)oids
, ix
)))
5623 } else if (CFGetTypeID(oids
) == CFDictionaryGetTypeID()) {
5624 struct search_context context
= { .found
= false, .certificate
= certificate
};
5625 CFDictionaryApplyFunction((CFDictionaryRef
) oids
, &check_for_marker
, &context
);
5626 return context
.found
;
5627 } else if (CFGetTypeID(oids
) == CFDataGetTypeID()) {
5628 return cert_contains_marker_extension(certificate
, oids
);
5629 } else if (CFGetTypeID(oids
) == CFStringGetTypeID()) {
5630 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, oids
);
5631 if (dataOid
== NULL
) return false;
5632 bool result
= cert_contains_marker_extension(certificate
, dataOid
);
5633 CFReleaseNull(dataOid
);
5639 static DERItem
*cert_extension_value_for_marker(SecCertificateRef certificate
, CFDataRef oid
) {
5641 const uint8_t *oid_data
= CFDataGetBytePtr(oid
);
5642 size_t oid_len
= CFDataGetLength(oid
);
5644 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5645 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5646 if (extn
->extnID
.length
== oid_len
5647 && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
))
5649 return (DERItem
*)&extn
->extnValue
;
5656 // CFType Ref is either:
5658 // CFData - OID to match with no data permitted
5659 // CFString - decimal OID to match
5661 DERItem
*SecCertificateGetExtensionValue(SecCertificateRef certificate
, CFTypeRef oid
) {
5662 if (!certificate
|| !oid
) {
5666 if(CFGetTypeID(oid
) == CFDataGetTypeID()) {
5667 return cert_extension_value_for_marker(certificate
, oid
);
5668 } else if (CFGetTypeID(oid
) == CFStringGetTypeID()) {
5669 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, oid
);
5670 if (dataOid
== NULL
) return NULL
;
5671 DERItem
*result
= cert_extension_value_for_marker(certificate
, dataOid
);
5672 CFReleaseNull(dataOid
);
5679 CFDataRef
SecCertificateCopyiAPAuthCapabilities(SecCertificateRef certificate
) {
5683 CFDataRef extensionData
= NULL
;
5684 DERItem
*extensionValue
= NULL
;
5685 extensionValue
= SecCertificateGetExtensionValue(certificate
,
5686 CFSTR("1.2.840.113635.100.6.36"));
5687 require_quiet(extensionValue
, out
);
5688 /* The extension is a octet string containing the DER-encoded 32-byte octet string */
5689 require_quiet(extensionValue
->length
== 34, out
);
5690 DERDecodedInfo decodedValue
;
5691 require_noerr_quiet(DERDecodeItem(extensionValue
, &decodedValue
), out
);
5692 if (decodedValue
.tag
== ASN1_OCTET_STRING
) {
5693 require_quiet(decodedValue
.content
.length
== 32, out
);
5694 extensionData
= CFDataCreate(NULL
, decodedValue
.content
.data
,
5695 decodedValue
.content
.length
);
5697 require_quiet(extensionValue
->data
[33] == 0x00 &&
5698 extensionValue
->data
[32] == 0x00, out
);
5699 extensionData
= CFDataCreate(NULL
, extensionValue
->data
, 32);
5702 return extensionData
;
5706 /* From iapd IAPAuthenticationTypes.h */
5707 typedef struct IapCertSerialNumber
5709 uint8_t xservID
; // Xserver ID
5710 uint8_t hsmID
; // Hardware security module ID (generated cert)
5711 uint8_t delimiter01
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5712 uint8_t dateYear
; // Date year cert was issued
5713 uint8_t dateMonth
; // Date month cert was issued
5714 uint8_t dateDay
; // Date day cert was issued
5715 uint8_t delimiter02
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5716 uint8_t devClass
; // iAP device class (maps to lingo permissions)
5717 uint8_t delimiter03
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5718 uint8_t batchNumHi
; // Batch number high byte (15:08)
5719 uint8_t batchNumLo
; // Batch number low byte (07:00)
5720 uint8_t delimiter04
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5721 uint8_t serialNumHi
; // Serial number high byte (23:16)
5722 uint8_t serialNumMid
; // Serial number middle byte (15:08)
5723 uint8_t serialNumLo
; // Serial number low byte (07:00)
5725 } IapCertSerialNumber_t
, *pIapCertSerialNumber_t
;
5728 #define IAP_CERT_FIELD_DELIMITER 0xAA // "Apple_Accessory" delimiter
5729 SeciAuthVersion
SecCertificateGetiAuthVersion(SecCertificateRef certificate
) {
5731 return kSeciAuthInvalid
;
5733 if (NULL
!= SecCertificateGetExtensionValue(certificate
,
5734 CFSTR("1.2.840.113635.100.6.36"))) {
5735 return kSeciAuthVersion3
;
5737 DERItem serialNumber
= certificate
->_serialNum
;
5738 require_quiet(serialNumber
.data
, out
);
5739 require_quiet(serialNumber
.length
== 15, out
);
5740 require_quiet(serialNumber
.data
[2] == IAP_CERT_FIELD_DELIMITER
&&
5741 serialNumber
.data
[6] == IAP_CERT_FIELD_DELIMITER
&&
5742 serialNumber
.data
[8] == IAP_CERT_FIELD_DELIMITER
&&
5743 serialNumber
.data
[11] == IAP_CERT_FIELD_DELIMITER
, out
);
5744 return kSeciAuthVersion2
;
5746 return kSeciAuthInvalid
;
5749 SecCertificateRef
SecCertificateCreateWithPEM(CFAllocatorRef allocator
,
5750 CFDataRef pem_certificate
)
5752 static const char begin_cert
[] = "-----BEGIN CERTIFICATE-----\n";
5753 static const char end_cert
[] = "-----END CERTIFICATE-----\n";
5754 uint8_t *base64_data
= NULL
;
5755 SecCertificateRef cert
= NULL
;
5756 const unsigned char *data
= CFDataGetBytePtr(pem_certificate
);
5757 //const size_t length = CFDataGetLength(pem_certificate);
5758 char *begin
= strstr((const char *)data
, begin_cert
);
5759 char *end
= strstr((const char *)data
, end_cert
);
5762 begin
+= sizeof(begin_cert
) - 1;
5763 size_t base64_length
= SecBase64Decode(begin
, end
- begin
, NULL
, 0);
5764 if (base64_length
&& (base64_length
< (size_t)CFDataGetLength(pem_certificate
))) {
5765 require_quiet(base64_data
= calloc(1, base64_length
), out
);
5766 require_action_quiet(base64_length
= SecBase64Decode(begin
, end
- begin
, base64_data
, base64_length
), out
, free(base64_data
));
5767 cert
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, base64_data
, base64_length
);
5776 // -- MARK -- XPC encoding/decoding
5779 bool SecCertificateAppendToXPCArray(SecCertificateRef certificate
, xpc_object_t xpc_certificates
, CFErrorRef
*error
) {
5781 return true; // NOOP
5783 size_t length
= SecCertificateGetLength(certificate
);
5784 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
5785 #if SECTRUST_VERBOSE_DEBUG
5786 secerror("cert=0x%lX length=%d bytes=0x%lX", (uintptr_t)certificate
, (int)length
, (uintptr_t)bytes
);
5788 if (!length
|| !bytes
) {
5789 return SecError(errSecParam
, error
, CFSTR("failed to der encode certificate"));
5791 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
5795 SecCertificateRef
SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates
, size_t index
, CFErrorRef
*error
) {
5796 SecCertificateRef certificate
= NULL
;
5798 const uint8_t *bytes
= xpc_array_get_data(xpc_certificates
, index
, &length
);
5800 certificate
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, bytes
, length
);
5803 SecError(errSecParam
, error
, CFSTR("certificates[%zu] failed to decode"), index
);
5808 xpc_object_t
SecCertificateArrayCopyXPCArray(CFArrayRef certificates
, CFErrorRef
*error
) {
5809 xpc_object_t xpc_certificates
;
5810 require_action_quiet(xpc_certificates
= xpc_array_create(NULL
, 0), exit
,
5811 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
5812 CFIndex ix
, count
= CFArrayGetCount(certificates
);
5813 for (ix
= 0; ix
< count
; ++ix
) {
5814 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
5815 #if SECTRUST_VERBOSE_DEBUG
5816 CFIndex length
= SecCertificateGetLength(certificate
);
5817 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
5818 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
);
5820 if (!SecCertificateAppendToXPCArray(certificate
, xpc_certificates
, error
)) {
5821 xpc_release(xpc_certificates
);
5822 xpc_certificates
= NULL
;
5828 return xpc_certificates
;
5831 CFArrayRef
SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates
, CFErrorRef
*error
) {
5832 CFMutableArrayRef certificates
= NULL
;
5833 require_action_quiet(xpc_get_type(xpc_certificates
) == XPC_TYPE_ARRAY
, exit
,
5834 SecError(errSecParam
, error
, CFSTR("certificates xpc value is not an array")));
5835 size_t count
= xpc_array_get_count(xpc_certificates
);
5836 require_action_quiet(certificates
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
), exit
,
5837 SecError(errSecAllocate
, error
, CFSTR("failed to create CFArray of capacity %zu"), count
));
5840 for (ix
= 0; ix
< count
; ++ix
) {
5841 SecCertificateRef cert
= SecCertificateCreateWithXPCArrayAtIndex(xpc_certificates
, ix
, error
);
5843 CFRelease(certificates
);
5846 CFArraySetValueAtIndex(certificates
, ix
, cert
);
5851 return certificates
;
5854 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
5857 static CFArrayRef
CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType
, CFErrorRef
* error
)
5859 __block CFArrayRef result
= NULL
;
5861 do_if_registered(ota_CopyEscrowCertificates
, escrowRootType
, error
);
5863 securityd_send_sync_and_do(kSecXPCOpOTAGetEscrowCertificates
, error
,
5864 ^bool(xpc_object_t message
, CFErrorRef
*error
)
5866 xpc_dictionary_set_uint64(message
, "escrowType", (uint64_t)escrowRootType
);
5869 ^bool(xpc_object_t response
, CFErrorRef
*error
)
5871 xpc_object_t xpc_array
= xpc_dictionary_get_value(response
, kSecXPCKeyResult
);
5873 if (response
&& (NULL
!= xpc_array
)) {
5874 result
= (CFArrayRef
)_CFXPCCreateCFObjectFromXPCObject(xpc_array
);
5877 return SecError(errSecInternal
, error
, CFSTR("Did not get the Escrow certificates"));
5879 return result
!= NULL
;
5884 CFArrayRef
SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType
)
5886 CFArrayRef result
= NULL
;
5888 CFDataRef certData
= NULL
;
5891 if (kSecCertificateBaselineEscrowRoot
== escrowRootType
||
5892 kSecCertificateBaselinePCSEscrowRoot
== escrowRootType
||
5893 kSecCertificateBaselineEscrowBackupRoot
== escrowRootType
||
5894 kSecCertificateBaselineEscrowEnrollmentRoot
== escrowRootType
)
5896 // The request is for the base line certificates.
5897 // Use the hard coded data to generate the return array.
5898 struct RootRecord
** pEscrowRoots
;
5899 switch (escrowRootType
) {
5900 case kSecCertificateBaselineEscrowRoot
:
5901 numRoots
= kNumberOfBaseLineEscrowRoots
;
5902 pEscrowRoots
= kBaseLineEscrowRoots
;
5904 case kSecCertificateBaselinePCSEscrowRoot
:
5905 numRoots
= kNumberOfBaseLinePCSEscrowRoots
;
5906 pEscrowRoots
= kBaseLinePCSEscrowRoots
;
5908 case kSecCertificateBaselineEscrowBackupRoot
:
5909 numRoots
= kNumberOfBaseLineEscrowBackupRoots
;
5910 pEscrowRoots
= kBaseLineEscrowBackupRoots
;
5912 case kSecCertificateBaselineEscrowEnrollmentRoot
:
5914 numRoots
= kNumberOfBaseLineEscrowEnrollmentRoots
;
5915 pEscrowRoots
= kBaseLineEscrowEnrollmentRoots
;
5919 // Get the hard coded set of roots
5920 SecCertificateRef baseLineCerts
[numRoots
];
5921 struct RootRecord
* pRootRecord
= NULL
;
5923 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
5924 pRootRecord
= pEscrowRoots
[iCnt
];
5925 if (NULL
!= pRootRecord
&& pRootRecord
->_length
> 0 && NULL
!= pRootRecord
->_bytes
) {
5926 certData
= CFDataCreate(kCFAllocatorDefault
, pRootRecord
->_bytes
, pRootRecord
->_length
);
5927 if (NULL
!= certData
) {
5928 baseLineCerts
[iCnt
] = SecCertificateCreateWithData(kCFAllocatorDefault
, certData
);
5929 CFRelease(certData
);
5933 result
= CFArrayCreate(kCFAllocatorDefault
, (const void **)baseLineCerts
, numRoots
, &kCFTypeArrayCallBacks
);
5934 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
5935 if (NULL
!= baseLineCerts
[iCnt
]) {
5936 CFRelease(baseLineCerts
[iCnt
]);
5941 // The request is for the current certificates.
5942 CFErrorRef error
= NULL
;
5943 CFArrayRef cert_datas
= CopyEscrowCertificates(escrowRootType
, &error
);
5944 if (NULL
!= error
|| NULL
== cert_datas
) {
5945 if (NULL
!= error
) {
5948 if (NULL
!= cert_datas
) {
5949 CFRelease(cert_datas
);
5954 numRoots
= (int)(CFArrayGetCount(cert_datas
));
5956 SecCertificateRef assetCerts
[numRoots
];
5957 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
5958 certData
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, iCnt
);
5959 if (NULL
!= certData
) {
5960 SecCertificateRef aCertRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, certData
);
5961 assetCerts
[iCnt
] = aCertRef
;
5964 assetCerts
[iCnt
] = NULL
;
5969 result
= CFArrayCreate(kCFAllocatorDefault
, (const void **)assetCerts
, numRoots
, &kCFTypeArrayCallBacks
);
5970 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
5971 if (NULL
!= assetCerts
[iCnt
]) {
5972 CFRelease(assetCerts
[iCnt
]);
5976 CFReleaseSafe(cert_datas
);
5981 SEC_CONST_DECL (kSecSignatureDigestAlgorithmUnknown
, "SignatureDigestUnknown");
5982 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD2
, "SignatureDigestMD2");
5983 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD4
, "SignatureDigestMD4");
5984 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD5
, "SignatureDigestMD5");
5985 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA1
, "SignatureDigestSHA1");
5986 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA224
, "SignatureDigestSHA224");
5987 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA256
, "SignatureDigestSHA256");
5988 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA384
, "SignatureDigestSHA284");
5989 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA512
, "SignatureDigestSHA512");
5991 SecSignatureHashAlgorithm
SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate
)
5993 SecSignatureHashAlgorithm result
= kSecSignatureHashAlgorithmUnknown
;
5994 DERAlgorithmId
*algId
= (certificate
) ? &certificate
->_tbsSigAlg
: NULL
;
5995 const DERItem
*algOid
= (algId
) ? &algId
->oid
: NULL
;
5997 if (!algOid
->data
|| !algOid
->length
) {
6000 /* classify the signature algorithm OID into one of our known types */
6001 if (DEROidCompare(algOid
, &oidSha512Ecdsa
) ||
6002 DEROidCompare(algOid
, &oidSha512Rsa
) ||
6003 DEROidCompare(algOid
, &oidSha512
)) {
6004 result
= kSecSignatureHashAlgorithmSHA512
;
6007 if (DEROidCompare(algOid
, &oidSha384Ecdsa
) ||
6008 DEROidCompare(algOid
, &oidSha384Rsa
) ||
6009 DEROidCompare(algOid
, &oidSha384
)) {
6010 result
= kSecSignatureHashAlgorithmSHA384
;
6013 if (DEROidCompare(algOid
, &oidSha256Ecdsa
) ||
6014 DEROidCompare(algOid
, &oidSha256Rsa
) ||
6015 DEROidCompare(algOid
, &oidSha256
)) {
6016 result
= kSecSignatureHashAlgorithmSHA256
;
6019 if (DEROidCompare(algOid
, &oidSha224Ecdsa
) ||
6020 DEROidCompare(algOid
, &oidSha224Rsa
) ||
6021 DEROidCompare(algOid
, &oidSha224
)) {
6022 result
= kSecSignatureHashAlgorithmSHA224
;
6025 if (DEROidCompare(algOid
, &oidSha1Ecdsa
) ||
6026 DEROidCompare(algOid
, &oidSha1Rsa
) ||
6027 DEROidCompare(algOid
, &oidSha1Dsa
) ||
6028 DEROidCompare(algOid
, &oidSha1DsaOIW
) ||
6029 DEROidCompare(algOid
, &oidSha1DsaCommonOIW
) ||
6030 DEROidCompare(algOid
, &oidSha1RsaOIW
) ||
6031 DEROidCompare(algOid
, &oidSha1Fee
) ||
6032 DEROidCompare(algOid
, &oidSha1
)) {
6033 result
= kSecSignatureHashAlgorithmSHA1
;
6036 if (DEROidCompare(algOid
, &oidMd5Rsa
) ||
6037 DEROidCompare(algOid
, &oidMd5Fee
) ||
6038 DEROidCompare(algOid
, &oidMd5
)) {
6039 result
= kSecSignatureHashAlgorithmMD5
;
6042 if (DEROidCompare(algOid
, &oidMd4Rsa
) ||
6043 DEROidCompare(algOid
, &oidMd4
)) {
6044 result
= kSecSignatureHashAlgorithmMD4
;
6047 if (DEROidCompare(algOid
, &oidMd2Rsa
) ||
6048 DEROidCompare(algOid
, &oidMd2
)) {
6049 result
= kSecSignatureHashAlgorithmMD2
;
6058 CFArrayRef
SecCertificateCopyiPhoneDeviceCAChain(void) {
6059 CFMutableArrayRef result
= NULL
;
6060 SecCertificateRef iPhoneDeviceCA
= NULL
, iPhoneCA
= NULL
, appleRoot
= NULL
;
6062 require_quiet(iPhoneDeviceCA
= SecCertificateCreateWithBytes(NULL
, _AppleiPhoneDeviceCA
, sizeof(_AppleiPhoneDeviceCA
)),
6064 require_quiet(iPhoneCA
= SecCertificateCreateWithBytes(NULL
, _AppleiPhoneCA
, sizeof(_AppleiPhoneCA
)),
6066 require_quiet(appleRoot
= SecCertificateCreateWithBytes(NULL
, _AppleRootCA
, sizeof(_AppleRootCA
)),
6069 require_quiet(result
= CFArrayCreateMutable(NULL
, 3, &kCFTypeArrayCallBacks
), errOut
);
6070 CFArrayAppendValue(result
, iPhoneDeviceCA
);
6071 CFArrayAppendValue(result
, iPhoneCA
);
6072 CFArrayAppendValue(result
, appleRoot
);
6075 CFReleaseNull(iPhoneDeviceCA
);
6076 CFReleaseNull(iPhoneCA
);
6077 CFReleaseNull(appleRoot
);