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
<= 37, 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
;
2778 // rdn_props is now retained by the original properties array
2779 CFReleaseSafe(rdn_props
);
2781 /* Since this is the third or later rdn pair we have already
2782 created a subsection in the top level properties array. Instead
2783 of appending to that directly we append to the array inside the
2785 properties
= (CFMutableArrayRef
)CFDictionaryGetValue(
2786 (CFDictionaryRef
)lastValue
, kSecPropertyKeyValue
);
2790 /* Finally we append the new rdn value to the property array. */
2791 CFStringRef label
= SecDERItemCopyOIDDecimalRepresentation(CFGetAllocator(properties
),
2793 CFStringRef localizedLabel
=
2794 copyLocalizedOidDescription(CFGetAllocator(properties
), rdnType
);
2795 appendDERThingProperty(properties
, label
, localizedLabel
, rdnValue
);
2796 CFReleaseSafe(label
);
2797 CFReleaseSafe(localizedLabel
);
2798 return errSecSuccess
;
2801 static CFArrayRef
createPropertiesForRDNContent(CFAllocatorRef allocator
,
2802 const DERItem
*rdnSetContent
) {
2803 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2804 &kCFTypeArrayCallBacks
);
2805 OSStatus status
= parseRDNContent(rdnSetContent
, properties
,
2808 CFArrayRemoveAllValues(properties
);
2809 appendInvalidProperty(properties
, SEC_RDN_KEY
, rdnSetContent
);
2816 From rfc3739 - 3.1.2. Subject
2818 When parsing the subject here are some tips for a short name of the cert.
2819 Choice I: commonName
2820 Choice II: givenName
2821 Choice III: pseudonym
2823 The commonName attribute value SHALL, when present, contain a name
2824 of the subject. This MAY be in the subject's preferred
2825 presentation format, or a format preferred by the CA, or some
2826 other format. Pseudonyms, nicknames, and names with spelling
2827 other than defined by the registered name MAY be used. To
2828 understand the nature of the name presented in commonName,
2829 complying applications MAY have to examine present values of the
2830 givenName and surname attributes, or the pseudonym attribute.
2833 static CFArrayRef
createPropertiesForX501NameContent(CFAllocatorRef allocator
,
2834 const DERItem
*x501NameContent
) {
2835 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2836 &kCFTypeArrayCallBacks
);
2837 OSStatus status
= parseX501NameContent(x501NameContent
, properties
,
2840 CFArrayRemoveAllValues(properties
);
2841 appendInvalidProperty(properties
, SEC_X501_NAME_KEY
, x501NameContent
);
2847 static CFArrayRef
createPropertiesForX501Name(CFAllocatorRef allocator
,
2848 const DERItem
*x501Name
) {
2849 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2850 &kCFTypeArrayCallBacks
);
2851 OSStatus status
= parseX501Name(x501Name
, properties
, appendRDNProperty
);
2853 CFArrayRemoveAllValues(properties
);
2854 appendInvalidProperty(properties
, SEC_X501_NAME_KEY
, x501Name
);
2860 static void appendIntegerProperty(CFMutableArrayRef properties
,
2861 CFStringRef label
, const DERItem
*integer
) {
2862 CFStringRef string
= copyIntegerContentDescription(
2863 CFGetAllocator(properties
), integer
);
2864 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, string
);
2868 static void appendBoolProperty(CFMutableArrayRef properties
,
2869 CFStringRef label
, bool boolean
) {
2870 CFStringRef value
= SecCopyCertString(boolean
? SEC_YES_KEY
: SEC_NO_KEY
);
2871 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, value
);
2875 static void appendBooleanProperty(CFMutableArrayRef properties
,
2876 CFStringRef label
, const DERItem
*boolean
, bool defaultValue
) {
2878 DERReturn drtn
= DERParseBooleanWithDefault(boolean
, defaultValue
, &result
);
2880 /* Couldn't parse boolean; dump the raw unparsed data as hex. */
2881 appendInvalidProperty(properties
, label
, boolean
);
2883 appendBoolProperty(properties
, label
, result
);
2887 static void appendSerialNumberProperty(CFMutableArrayRef parent
, CFStringRef label
,
2888 DERItem
*serialNum
) {
2889 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2890 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2892 if (serialNum
->length
) {
2893 appendIntegerProperty(properties
, SEC_SERIAL_NUMBER_KEY
,
2895 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, properties
);
2898 CFReleaseNull(properties
);
2901 static void appendBitStringContentNames(CFMutableArrayRef properties
,
2902 CFStringRef label
, const DERItem
*bitStringContent
,
2903 const CFStringRef
*names
, CFIndex namesCount
) {
2904 DERSize len
= bitStringContent
->length
- 1;
2905 require_quiet(len
== 1 || len
== 2, badDER
);
2906 DERByte numUnusedBits
= bitStringContent
->data
[0];
2907 require_quiet(numUnusedBits
< 8, badDER
);
2908 uint_fast16_t bits
= 8 * len
- numUnusedBits
;
2909 require_quiet(bits
<= (uint_fast16_t)namesCount
, badDER
);
2910 uint_fast16_t value
= bitStringContent
->data
[1];
2913 value
= (value
<< 8) + bitStringContent
->data
[2];
2919 CFStringRef fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
2920 CFStringRef string
= NULL
;
2921 for (ix
= 0; ix
< bits
; ++ix
) {
2925 CFStringCreateWithFormat(CFGetAllocator(properties
),
2926 NULL
, fmt
, string
, names
[ix
]);
2937 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
2938 string
? string
: CFSTR(""));
2939 CFReleaseSafe(string
);
2942 appendInvalidProperty(properties
, label
, bitStringContent
);
2945 static void appendBitStringNames(CFMutableArrayRef properties
,
2946 CFStringRef label
, const DERItem
*bitString
,
2947 const CFStringRef
*names
, CFIndex namesCount
) {
2948 DERDecodedInfo bitStringContent
;
2949 DERReturn drtn
= DERDecodeItem(bitString
, &bitStringContent
);
2950 require_noerr_quiet(drtn
, badDER
);
2951 require_quiet(bitStringContent
.tag
== ASN1_BIT_STRING
, badDER
);
2952 appendBitStringContentNames(properties
, label
, &bitStringContent
.content
,
2956 appendInvalidProperty(properties
, label
, bitString
);
2959 static void appendKeyUsage(CFMutableArrayRef properties
,
2960 const DERItem
*extnValue
) {
2961 static const CFStringRef usageNames
[] = {
2962 SEC_DIGITAL_SIGNATURE_KEY
,
2963 SEC_NON_REPUDIATION_KEY
,
2964 SEC_KEY_ENCIPHERMENT_KEY
,
2965 SEC_DATA_ENCIPHERMENT_KEY
,
2966 SEC_KEY_AGREEMENT_KEY
,
2969 SEC_ENCIPHER_ONLY_KEY
,
2970 SEC_DECIPHER_ONLY_KEY
2972 appendBitStringNames(properties
, SEC_USAGE_KEY
, extnValue
,
2973 usageNames
, array_size(usageNames
));
2976 static void appendPrivateKeyUsagePeriod(CFMutableArrayRef properties
,
2977 const DERItem
*extnValue
) {
2978 DERPrivateKeyUsagePeriod pkup
;
2979 DERReturn drtn
= DERParseSequence(extnValue
,
2980 DERNumPrivateKeyUsagePeriodItemSpecs
, DERPrivateKeyUsagePeriodItemSpecs
,
2981 &pkup
, sizeof(pkup
));
2982 require_noerr_quiet(drtn
, badDER
);
2983 if (pkup
.notBefore
.length
) {
2984 appendDateContentProperty(properties
, SEC_NOT_VALID_BEFORE_KEY
,
2985 ASN1_GENERALIZED_TIME
, &pkup
.notBefore
);
2987 if (pkup
.notAfter
.length
) {
2988 appendDateContentProperty(properties
, SEC_NOT_VALID_AFTER_KEY
,
2989 ASN1_GENERALIZED_TIME
, &pkup
.notAfter
);
2993 appendInvalidProperty(properties
, SEC_PRIVATE_KU_PERIOD_KEY
, extnValue
);
2996 static void appendStringContentProperty(CFMutableArrayRef properties
,
2997 CFStringRef label
, const DERItem
*stringContent
,
2998 CFStringEncoding encoding
) {
2999 CFStringRef string
= CFStringCreateWithBytes(CFGetAllocator(properties
),
3000 stringContent
->data
, stringContent
->length
, encoding
, FALSE
);
3002 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, string
);
3005 appendInvalidProperty(properties
, label
, stringContent
);
3010 OtherName ::= SEQUENCE {
3011 type-id OBJECT IDENTIFIER,
3012 value [0] EXPLICIT ANY DEFINED BY type-id }
3014 static void appendOtherNameContentProperty(CFMutableArrayRef properties
,
3015 const DERItem
*otherNameContent
) {
3017 DERReturn drtn
= DERParseSequenceContent(otherNameContent
,
3018 DERNumOtherNameItemSpecs
, DEROtherNameItemSpecs
,
3020 require_noerr_quiet(drtn
, badDER
);
3021 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3023 SecDERItemCopyOIDDecimalRepresentation(allocator
, &on
.typeIdentifier
);
3024 CFStringRef localizedLabel
=
3025 copyLocalizedOidDescription(allocator
, &on
.typeIdentifier
);
3026 CFStringRef value_string
= copyDERThingDescription(allocator
, &on
.value
, false);
3028 appendProperty(properties
, kSecPropertyTypeString
, label
,
3029 localizedLabel
, value_string
);
3031 appendUnparsedProperty(properties
, label
, localizedLabel
, &on
.value
);
3033 CFReleaseSafe(value_string
);
3034 CFReleaseSafe(label
);
3035 CFReleaseSafe(localizedLabel
);
3038 appendInvalidProperty(properties
, SEC_OTHER_NAME_KEY
, otherNameContent
);
3042 GeneralName ::= CHOICE {
3043 otherName [0] OtherName,
3044 rfc822Name [1] IA5String,
3045 dNSName [2] IA5String,
3046 x400Address [3] ORAddress,
3047 directoryName [4] Name,
3048 ediPartyName [5] EDIPartyName,
3049 uniformResourceIdentifier [6] IA5String,
3050 iPAddress [7] OCTET STRING,
3051 registeredID [8] OBJECT IDENTIFIER}
3053 EDIPartyName ::= SEQUENCE {
3054 nameAssigner [0] DirectoryString OPTIONAL,
3055 partyName [1] DirectoryString }
3057 static bool appendGeneralNameContentProperty(CFMutableArrayRef properties
,
3058 DERTag tag
, const DERItem
*generalName
) {
3060 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
3061 appendOtherNameContentProperty(properties
, generalName
);
3063 case ASN1_CONTEXT_SPECIFIC
| 1:
3065 appendStringContentProperty(properties
, SEC_EMAIL_ADDRESS_KEY
,
3066 generalName
, kCFStringEncodingASCII
);
3068 case ASN1_CONTEXT_SPECIFIC
| 2:
3070 appendStringContentProperty(properties
, SEC_DNS_NAME_KEY
, generalName
,
3071 kCFStringEncodingASCII
);
3073 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 3:
3074 appendUnparsedProperty(properties
, SEC_X400_ADDRESS_KEY
, NULL
,
3077 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 4:
3079 CFArrayRef directory_plist
=
3080 createPropertiesForX501Name(CFGetAllocator(properties
),
3082 appendProperty(properties
, kSecPropertyTypeSection
,
3083 SEC_DIRECTORY_NAME_KEY
, NULL
, directory_plist
);
3084 CFRelease(directory_plist
);
3087 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 5:
3088 appendUnparsedProperty(properties
, SEC_EDI_PARTY_NAME_KEY
, NULL
,
3091 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
3092 /* Technically I don't think this is valid, but there are certs out
3093 in the wild that use a constructed IA5String. In particular the
3094 VeriSign Time Stamping Authority CA.cer does this. */
3095 appendURLProperty(properties
, SEC_URI_KEY
, generalName
);
3097 case ASN1_CONTEXT_SPECIFIC
| 6:
3098 appendURLContentProperty(properties
, SEC_URI_KEY
, generalName
);
3100 case ASN1_CONTEXT_SPECIFIC
| 7:
3101 appendIPAddressContentProperty(properties
, SEC_IP_ADDRESS_KEY
,
3104 case ASN1_CONTEXT_SPECIFIC
| 8:
3105 appendOIDProperty(properties
, SEC_REGISTERED_ID_KEY
, NULL
, generalName
);
3116 static void appendGeneralNameProperty(CFMutableArrayRef properties
,
3117 const DERItem
*generalName
) {
3118 DERDecodedInfo generalNameContent
;
3119 DERReturn drtn
= DERDecodeItem(generalName
, &generalNameContent
);
3120 require_noerr_quiet(drtn
, badDER
);
3121 if (appendGeneralNameContentProperty(properties
, generalNameContent
.tag
,
3122 &generalNameContent
.content
))
3125 appendInvalidProperty(properties
, SEC_GENERAL_NAME_KEY
, generalName
);
3130 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
3132 static void appendGeneralNamesContent(CFMutableArrayRef properties
,
3133 const DERItem
*generalNamesContent
) {
3135 DERReturn drtn
= DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
);
3136 require_noerr_quiet(drtn
, badDER
);
3137 DERDecodedInfo generalNameContent
;
3138 while ((drtn
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) ==
3140 if (!appendGeneralNameContentProperty(properties
,
3141 generalNameContent
.tag
, &generalNameContent
.content
)) {
3145 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3148 appendInvalidProperty(properties
, SEC_GENERAL_NAMES_KEY
,
3149 generalNamesContent
);
3152 static void appendGeneralNames(CFMutableArrayRef properties
,
3153 const DERItem
*generalNames
) {
3154 DERDecodedInfo generalNamesContent
;
3155 DERReturn drtn
= DERDecodeItem(generalNames
, &generalNamesContent
);
3156 require_noerr_quiet(drtn
, badDER
);
3157 require_quiet(generalNamesContent
.tag
== ASN1_CONSTR_SEQUENCE
,
3159 appendGeneralNamesContent(properties
, &generalNamesContent
.content
);
3162 appendInvalidProperty(properties
, SEC_GENERAL_NAMES_KEY
, generalNames
);
3166 BasicConstraints ::= SEQUENCE {
3167 cA BOOLEAN DEFAULT FALSE,
3168 pathLenConstraint INTEGER (0..MAX) OPTIONAL }
3170 static void appendBasicConstraints(CFMutableArrayRef properties
,
3171 const DERItem
*extnValue
) {
3172 DERBasicConstraints basicConstraints
;
3173 DERReturn drtn
= DERParseSequence(extnValue
,
3174 DERNumBasicConstraintsItemSpecs
, DERBasicConstraintsItemSpecs
,
3175 &basicConstraints
, sizeof(basicConstraints
));
3176 require_noerr_quiet(drtn
, badDER
);
3178 appendBooleanProperty(properties
, SEC_CERT_AUTHORITY_KEY
,
3179 &basicConstraints
.cA
, false);
3181 if (basicConstraints
.pathLenConstraint
.length
!= 0) {
3182 appendIntegerProperty(properties
, SEC_PATH_LEN_CONSTRAINT_KEY
,
3183 &basicConstraints
.pathLenConstraint
);
3187 appendInvalidProperty(properties
, SEC_BASIC_CONSTRAINTS_KEY
, extnValue
);
3191 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
3193 * NameConstraints ::= SEQUENCE {
3194 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
3195 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
3197 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
3199 * GeneralSubtree ::= SEQUENCE {
3201 * minimum [0] BaseDistance DEFAULT 0,
3202 * maximum [1] BaseDistance OPTIONAL }
3204 * BaseDistance ::= INTEGER (0..MAX)
3206 static void appendNameConstraints(CFMutableArrayRef properties
,
3207 const DERItem
*extnValue
) {
3208 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3209 DERNameConstraints nc
;
3211 drtn
= DERParseSequence(extnValue
,
3212 DERNumNameConstraintsItemSpecs
,
3213 DERNameConstraintsItemSpecs
,
3215 require_noerr_quiet(drtn
, badDER
);
3216 if (nc
.permittedSubtrees
.length
) {
3218 require_noerr_quiet(DERDecodeSeqContentInit(&nc
.permittedSubtrees
, &gsSeq
), badDER
);
3219 DERDecodedInfo gsContent
;
3220 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
3221 DERGeneralSubtree derGS
;
3222 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
3223 drtn
= DERParseSequenceContent(&gsContent
.content
,
3224 DERNumGeneralSubtreeItemSpecs
,
3225 DERGeneralSubtreeItemSpecs
,
3226 &derGS
, sizeof(derGS
));
3227 require_noerr_quiet(drtn
, badDER
);
3228 if (derGS
.minimum
.length
) {
3229 appendIntegerProperty(properties
, SEC_PERMITTED_MINIMUM_KEY
, &derGS
.minimum
);
3231 if (derGS
.maximum
.length
) {
3232 appendIntegerProperty(properties
, SEC_PERMITTED_MAXIMUM_KEY
, &derGS
.maximum
);
3234 if (derGS
.generalName
.length
) {
3235 CFMutableArrayRef base
= CFArrayCreateMutable(allocator
, 0,
3236 &kCFTypeArrayCallBacks
);
3237 appendProperty(properties
, kSecPropertyTypeSection
,
3238 SEC_PERMITTED_NAME_KEY
, NULL
, base
);
3239 appendGeneralNameProperty(base
, &derGS
.generalName
);
3243 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3245 if (nc
.excludedSubtrees
.length
) {
3247 require_noerr_quiet(DERDecodeSeqContentInit(&nc
.excludedSubtrees
, &gsSeq
), badDER
);
3248 DERDecodedInfo gsContent
;
3249 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
3250 DERGeneralSubtree derGS
;
3251 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
3252 drtn
= DERParseSequenceContent(&gsContent
.content
,
3253 DERNumGeneralSubtreeItemSpecs
,
3254 DERGeneralSubtreeItemSpecs
,
3255 &derGS
, sizeof(derGS
));
3256 require_noerr_quiet(drtn
, badDER
);
3257 if (derGS
.minimum
.length
) {
3258 appendIntegerProperty(properties
, SEC_EXCLUDED_MINIMUM_KEY
, &derGS
.minimum
);
3260 if (derGS
.maximum
.length
) {
3261 appendIntegerProperty(properties
, SEC_EXCLUDED_MAXIMUM_KEY
, &derGS
.maximum
);
3263 if (derGS
.generalName
.length
) {
3264 CFMutableArrayRef base
= CFArrayCreateMutable(allocator
, 0,
3265 &kCFTypeArrayCallBacks
);
3266 appendProperty(properties
, kSecPropertyTypeSection
,
3267 SEC_EXCLUDED_NAME_KEY
, NULL
, base
);
3268 appendGeneralNameProperty(base
, &derGS
.generalName
);
3272 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3277 appendInvalidProperty(properties
, SEC_NAME_CONSTRAINTS_KEY
, extnValue
);
3281 CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
3283 DistributionPoint ::= SEQUENCE {
3284 distributionPoint [0] DistributionPointName OPTIONAL,
3285 reasons [1] ReasonFlags OPTIONAL,
3286 cRLIssuer [2] GeneralNames OPTIONAL }
3288 DistributionPointName ::= CHOICE {
3289 fullName [0] GeneralNames,
3290 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
3292 ReasonFlags ::= BIT STRING {
3296 affiliationChanged (3),
3298 cessationOfOperation (5),
3299 certificateHold (6),
3300 privilegeWithdrawn (7),
3303 static void appendCrlDistributionPoints(CFMutableArrayRef properties
,
3304 const DERItem
*extnValue
) {
3305 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3308 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &dpSeq
);
3309 require_noerr_quiet(drtn
, badDER
);
3310 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3311 DERDecodedInfo dpSeqContent
;
3312 while ((drtn
= DERDecodeSeqNext(&dpSeq
, &dpSeqContent
)) == DR_Success
) {
3313 require_quiet(dpSeqContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3314 DERDistributionPoint dp
;
3315 drtn
= DERParseSequenceContent(&dpSeqContent
.content
,
3316 DERNumDistributionPointItemSpecs
,
3317 DERDistributionPointItemSpecs
,
3319 require_noerr_quiet(drtn
, badDER
);
3320 if (dp
.distributionPoint
.length
) {
3321 DERDecodedInfo distributionPointName
;
3322 drtn
= DERDecodeItem(&dp
.distributionPoint
, &distributionPointName
);
3323 require_noerr_quiet(drtn
, badDER
);
3324 if (distributionPointName
.tag
==
3325 (ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0)) {
3327 appendGeneralNamesContent(properties
,
3328 &distributionPointName
.content
);
3329 } else if (distributionPointName
.tag
==
3330 (ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1)) {
3331 CFArrayRef rdn_props
= createPropertiesForRDNContent(allocator
,
3333 appendProperty(properties
, kSecPropertyTypeSection
,
3334 SEC_NAME_REL_CRL_ISSUER_KEY
, NULL
, rdn_props
);
3335 CFRelease(rdn_props
);
3340 if (dp
.reasons
.length
) {
3341 static const CFStringRef reasonNames
[] = {
3343 SEC_KEY_COMPROMISE_KEY
,
3344 SEC_CA_COMPROMISE_KEY
,
3345 SEC_AFFILIATION_CHANGED_KEY
,
3347 SEC_CESSATION_OF_OPER_KEY
,
3348 SEC_CERTIFICATE_HOLD_KEY
,
3349 SEC_PRIV_WITHDRAWN_KEY
,
3350 SEC_AA_COMPROMISE_KEY
3352 appendBitStringContentNames(properties
, SEC_REASONS_KEY
,
3354 reasonNames
, array_size(reasonNames
));
3356 if (dp
.cRLIssuer
.length
) {
3357 CFMutableArrayRef crlIssuer
= CFArrayCreateMutable(allocator
, 0,
3358 &kCFTypeArrayCallBacks
);
3359 appendProperty(properties
, kSecPropertyTypeSection
,
3360 SEC_CRL_ISSUER_KEY
, NULL
, crlIssuer
);
3361 CFRelease(crlIssuer
);
3362 appendGeneralNames(crlIssuer
, &dp
.cRLIssuer
);
3365 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3368 appendInvalidProperty(properties
, SEC_CRL_DISTR_POINTS_KEY
, extnValue
);
3371 /* Decode a sequence of integers into a comma separated list of ints. */
3372 static void appendIntegerSequenceContent(CFMutableArrayRef properties
,
3373 CFStringRef label
, const DERItem
*intSequenceContent
) {
3374 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3376 CFStringRef fmt
= NULL
, value
= NULL
, intDesc
= NULL
, v
= NULL
;
3377 DERReturn drtn
= DERDecodeSeqContentInit(intSequenceContent
, &intSeq
);
3378 require_noerr_quiet(drtn
, badDER
);
3379 DERDecodedInfo intContent
;
3380 fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
3381 require_quiet(fmt
, badDER
);
3382 while ((drtn
= DERDecodeSeqNext(&intSeq
, &intContent
)) == DR_Success
) {
3383 require_quiet(intContent
.tag
== ASN1_INTEGER
, badDER
);
3384 intDesc
= copyIntegerContentDescription(
3385 allocator
, &intContent
.content
);
3386 require_quiet(intDesc
, badDER
);
3388 v
= CFStringCreateWithFormat(allocator
, NULL
, fmt
, value
, intDesc
);
3389 CFReleaseNull(value
);
3390 require_quiet(v
, badDER
);
3393 value
= CFStringCreateMutableCopy(allocator
, 0, intDesc
);
3394 require_quiet(value
, badDER
);
3396 CFReleaseNull(intDesc
);
3399 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3401 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, value
);
3405 /* DROPTHOUGH if !value. */
3408 CFReleaseNull(intDesc
);
3409 CFReleaseNull(value
);
3410 appendInvalidProperty(properties
, label
, intSequenceContent
);
3413 static void appendCertificatePolicies(CFMutableArrayRef properties
,
3414 const DERItem
*extnValue
) {
3415 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3416 CFStringRef piLabel
= NULL
, piFmt
= NULL
, lpiLabel
= NULL
;
3417 CFStringRef pqLabel
= NULL
, pqFmt
= NULL
, lpqLabel
= NULL
;
3420 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &piSeq
);
3421 require_noerr_quiet(drtn
, badDER
);
3422 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3423 DERDecodedInfo piContent
;
3425 while ((drtn
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) {
3426 require_quiet(piContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3427 DERPolicyInformation pi
;
3428 drtn
= DERParseSequenceContent(&piContent
.content
,
3429 DERNumPolicyInformationItemSpecs
,
3430 DERPolicyInformationItemSpecs
,
3432 require_noerr_quiet(drtn
, badDER
);
3433 require_quiet(piLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3434 SEC_POLICY_IDENTIFIER_KEY
, pin
), badDER
);
3435 require_quiet(piFmt
= SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY
), badDER
);
3436 require_quiet(lpiLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3437 piFmt
, pin
++), badDER
);
3438 CFReleaseNull(piFmt
);
3439 appendOIDProperty(properties
, piLabel
, lpiLabel
, &pi
.policyIdentifier
);
3440 CFReleaseNull(piLabel
);
3441 CFReleaseNull(lpiLabel
);
3442 if (pi
.policyQualifiers
.length
== 0)
3446 drtn
= DERDecodeSeqContentInit(&pi
.policyQualifiers
, &pqSeq
);
3447 require_noerr_quiet(drtn
, badDER
);
3448 DERDecodedInfo pqContent
;
3450 while ((drtn
= DERDecodeSeqNext(&pqSeq
, &pqContent
)) == DR_Success
) {
3451 DERPolicyQualifierInfo pqi
;
3452 drtn
= DERParseSequenceContent(&pqContent
.content
,
3453 DERNumPolicyQualifierInfoItemSpecs
,
3454 DERPolicyQualifierInfoItemSpecs
,
3456 require_noerr_quiet(drtn
, badDER
);
3457 DERDecodedInfo qualifierContent
;
3458 drtn
= DERDecodeItem(&pqi
.qualifier
, &qualifierContent
);
3459 require_noerr_quiet(drtn
, badDER
);
3460 require_quiet(pqLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3461 SEC_POLICY_QUALIFIER_KEY
, pqn
), badDER
);
3462 require_quiet(pqFmt
= SecCopyCertString(SEC_POLICY_QUALIFIER_KEY
), badDER
);
3463 require_quiet(lpqLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3464 pqFmt
, pqn
++), badDER
);
3465 CFReleaseNull(pqFmt
);
3466 appendOIDProperty(properties
, pqLabel
, lpqLabel
,
3467 &pqi
.policyQualifierID
);
3468 CFReleaseNull(pqLabel
);
3469 CFReleaseNull(lpqLabel
);
3470 if (DEROidCompare(&oidQtCps
, &pqi
.policyQualifierID
)) {
3471 require_quiet(qualifierContent
.tag
== ASN1_IA5_STRING
, badDER
);
3472 appendURLContentProperty(properties
, SEC_CPS_URI_KEY
,
3473 &qualifierContent
.content
);
3474 } else if (DEROidCompare(&oidQtUNotice
, &pqi
.policyQualifierID
)) {
3475 require_quiet(qualifierContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3477 drtn
= DERParseSequenceContent(&qualifierContent
.content
,
3478 DERNumUserNoticeItemSpecs
,
3479 DERUserNoticeItemSpecs
,
3481 require_noerr_quiet(drtn
, badDER
);
3482 if (un
.noticeRef
.length
) {
3483 DERNoticeReference nr
;
3484 drtn
= DERParseSequenceContent(&un
.noticeRef
,
3485 DERNumNoticeReferenceItemSpecs
,
3486 DERNoticeReferenceItemSpecs
,
3488 require_noerr_quiet(drtn
, badDER
);
3489 appendDERThingProperty(properties
,
3490 SEC_ORGANIZATION_KEY
, NULL
,
3492 appendIntegerSequenceContent(properties
,
3493 SEC_NOTICE_NUMBERS_KEY
, &nr
.noticeNumbers
);
3495 if (un
.explicitText
.length
) {
3496 appendDERThingProperty(properties
, SEC_EXPLICIT_TEXT_KEY
,
3497 NULL
, &un
.explicitText
);
3500 appendUnparsedProperty(properties
, SEC_QUALIFIER_KEY
, NULL
,
3504 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3506 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3509 CFReleaseNull(piFmt
);
3510 CFReleaseNull(piLabel
);
3511 CFReleaseNull(lpiLabel
);
3512 CFReleaseNull(pqFmt
);
3513 CFReleaseNull(pqLabel
);
3514 CFReleaseNull(lpqLabel
);
3515 appendInvalidProperty(properties
, SEC_CERT_POLICIES_KEY
, extnValue
);
3518 static void appendSubjectKeyIdentifier(CFMutableArrayRef properties
,
3519 const DERItem
*extnValue
) {
3521 DERDecodedInfo keyIdentifier
;
3522 drtn
= DERDecodeItem(extnValue
, &keyIdentifier
);
3523 require_noerr_quiet(drtn
, badDER
);
3524 require_quiet(keyIdentifier
.tag
== ASN1_OCTET_STRING
, badDER
);
3525 appendDataProperty(properties
, SEC_KEY_IDENTIFIER_KEY
, NULL
,
3526 &keyIdentifier
.content
);
3530 appendInvalidProperty(properties
, SEC_SUBJ_KEY_ID_KEY
,
3535 AuthorityKeyIdentifier ::= SEQUENCE {
3536 keyIdentifier [0] KeyIdentifier OPTIONAL,
3537 authorityCertIssuer [1] GeneralNames OPTIONAL,
3538 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
3539 -- authorityCertIssuer and authorityCertSerialNumber MUST both
3540 -- be present or both be absent
3542 KeyIdentifier ::= OCTET STRING
3544 static void appendAuthorityKeyIdentifier(CFMutableArrayRef properties
,
3545 const DERItem
*extnValue
) {
3546 DERAuthorityKeyIdentifier akid
;
3548 drtn
= DERParseSequence(extnValue
,
3549 DERNumAuthorityKeyIdentifierItemSpecs
,
3550 DERAuthorityKeyIdentifierItemSpecs
,
3551 &akid
, sizeof(akid
));
3552 require_noerr_quiet(drtn
, badDER
);
3553 if (akid
.keyIdentifier
.length
) {
3554 appendDataProperty(properties
, SEC_KEY_IDENTIFIER_KEY
, NULL
,
3555 &akid
.keyIdentifier
);
3557 if (akid
.authorityCertIssuer
.length
||
3558 akid
.authorityCertSerialNumber
.length
) {
3559 require_quiet(akid
.authorityCertIssuer
.length
&&
3560 akid
.authorityCertSerialNumber
.length
, badDER
);
3561 /* Perhaps put in a subsection called Authority Certificate Issuer. */
3562 appendGeneralNamesContent(properties
,
3563 &akid
.authorityCertIssuer
);
3564 appendIntegerProperty(properties
, SEC_AUTH_CERT_SERIAL_KEY
,
3565 &akid
.authorityCertSerialNumber
);
3570 appendInvalidProperty(properties
, SEC_AUTHORITY_KEY_ID_KEY
, extnValue
);
3574 PolicyConstraints ::= SEQUENCE {
3575 requireExplicitPolicy [0] SkipCerts OPTIONAL,
3576 inhibitPolicyMapping [1] SkipCerts OPTIONAL }
3578 SkipCerts ::= INTEGER (0..MAX)
3580 static void appendPolicyConstraints(CFMutableArrayRef properties
,
3581 const DERItem
*extnValue
) {
3582 DERPolicyConstraints pc
;
3584 drtn
= DERParseSequence(extnValue
,
3585 DERNumPolicyConstraintsItemSpecs
,
3586 DERPolicyConstraintsItemSpecs
,
3588 require_noerr_quiet(drtn
, badDER
);
3589 if (pc
.requireExplicitPolicy
.length
) {
3590 appendIntegerProperty(properties
, SEC_REQUIRE_EXPL_POLICY_KEY
,
3591 &pc
.requireExplicitPolicy
);
3593 if (pc
.inhibitPolicyMapping
.length
) {
3594 appendIntegerProperty(properties
, SEC_INHIBIT_POLICY_MAP_KEY
,
3595 &pc
.inhibitPolicyMapping
);
3601 appendInvalidProperty(properties
, SEC_POLICY_CONSTRAINTS_KEY
, extnValue
);
3605 extendedKeyUsage EXTENSION ::= {
3606 SYNTAX SEQUENCE SIZE (1..MAX) OF KeyPurposeId
3607 IDENTIFIED BY id-ce-extKeyUsage }
3609 KeyPurposeId ::= OBJECT IDENTIFIER
3611 static void appendExtendedKeyUsage(CFMutableArrayRef properties
,
3612 const DERItem
*extnValue
) {
3615 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &derSeq
);
3616 require_noerr_quiet(drtn
, badDER
);
3617 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3618 DERDecodedInfo currDecoded
;
3619 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
3620 require_quiet(currDecoded
.tag
== ASN1_OBJECT_ID
, badDER
);
3621 appendOIDProperty(properties
, SEC_PURPOSE_KEY
, NULL
,
3622 &currDecoded
.content
);
3624 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3627 appendInvalidProperty(properties
, SEC_EXTENDED_KEY_USAGE_KEY
, extnValue
);
3631 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
3633 AuthorityInfoAccessSyntax ::=
3634 SEQUENCE SIZE (1..MAX) OF AccessDescription
3636 AccessDescription ::= SEQUENCE {
3637 accessMethod OBJECT IDENTIFIER,
3638 accessLocation GeneralName }
3640 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
3642 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
3644 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
3646 static void appendInfoAccess(CFMutableArrayRef properties
,
3647 const DERItem
*extnValue
) {
3650 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &adSeq
);
3651 require_noerr_quiet(drtn
, badDER
);
3652 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3653 DERDecodedInfo adContent
;
3654 while ((drtn
= DERDecodeSeqNext(&adSeq
, &adContent
)) == DR_Success
) {
3655 require_quiet(adContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3656 DERAccessDescription ad
;
3657 drtn
= DERParseSequenceContent(&adContent
.content
,
3658 DERNumAccessDescriptionItemSpecs
,
3659 DERAccessDescriptionItemSpecs
,
3661 require_noerr_quiet(drtn
, badDER
);
3662 appendOIDProperty(properties
, SEC_ACCESS_METHOD_KEY
, NULL
,
3664 //TODO: Do something with SEC_ACCESS_LOCATION_KEY
3665 appendGeneralNameProperty(properties
, &ad
.accessLocation
);
3667 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3670 appendInvalidProperty(properties
, SEC_AUTH_INFO_ACCESS_KEY
, extnValue
);
3673 static void appendNetscapeCertType(CFMutableArrayRef properties
,
3674 const DERItem
*extnValue
) {
3675 static const CFStringRef certTypes
[] = {
3679 SEC_OBJECT_SIGNING_KEY
,
3683 SEC_OBJECT_SIGNING_CA_KEY
3685 appendBitStringNames(properties
, SEC_USAGE_KEY
, extnValue
,
3686 certTypes
, array_size(certTypes
));
3689 static bool appendPrintableDERSequence(CFMutableArrayRef properties
,
3690 CFStringRef label
, const DERItem
*sequence
) {
3693 DERReturn drtn
= DERDecodeSeqInit(sequence
, &tag
, &derSeq
);
3694 require_noerr_quiet(drtn
, badSequence
);
3695 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badSequence
);
3696 DERDecodedInfo currDecoded
;
3697 bool appendedSomething
= false;
3698 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
3699 switch (currDecoded
.tag
)
3702 case ASN1_SEQUENCE
: // 16
3703 case ASN1_SET
: // 17
3704 // skip constructed object lengths
3707 case ASN1_UTF8_STRING
: // 12
3708 case ASN1_NUMERIC_STRING
: // 18
3709 case ASN1_PRINTABLE_STRING
: // 19
3710 case ASN1_T61_STRING
: // 20, also ASN1_TELETEX_STRING
3711 case ASN1_VIDEOTEX_STRING
: // 21
3712 case ASN1_IA5_STRING
: // 22
3713 case ASN1_GRAPHIC_STRING
: // 25
3714 case ASN1_VISIBLE_STRING
: // 26, also ASN1_ISO646_STRING
3715 case ASN1_GENERAL_STRING
: // 27
3716 case ASN1_UNIVERSAL_STRING
: // 28
3718 CFStringRef string
=
3719 copyDERThingContentDescription(CFGetAllocator(properties
),
3720 currDecoded
.tag
, &currDecoded
.content
, false);
3721 require_quiet(string
, badSequence
);
3723 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
3725 CFReleaseNull(string
);
3726 appendedSomething
= true;
3733 require_quiet(drtn
== DR_EndOfSequence
, badSequence
);
3734 return appendedSomething
;
3739 static void appendExtension(CFMutableArrayRef parent
,
3740 const SecCertificateExtension
*extn
) {
3741 CFAllocatorRef allocator
= CFGetAllocator(parent
);
3742 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
3743 &kCFTypeArrayCallBacks
);
3745 *extnID
= &extn
->extnID
,
3746 *extnValue
= &extn
->extnValue
;
3747 CFStringRef label
= NULL
;
3748 CFStringRef localizedLabel
= NULL
;
3750 appendBoolProperty(properties
, SEC_CRITICAL_KEY
, extn
->critical
);
3751 require_quiet(extnID
, xit
);
3753 bool handled
= true;
3754 /* Extensions that we know how to handle ourselves... */
3755 if (extnID
->length
== oidSubjectKeyIdentifier
.length
&&
3756 !memcmp(extnID
->data
, oidSubjectKeyIdentifier
.data
, extnID
->length
- 1))
3758 switch (extnID
->data
[extnID
->length
- 1]) {
3759 case 14: /* SubjectKeyIdentifier id-ce 14 */
3760 appendSubjectKeyIdentifier(properties
, extnValue
);
3762 case 15: /* KeyUsage id-ce 15 */
3763 appendKeyUsage(properties
, extnValue
);
3765 case 16: /* PrivateKeyUsagePeriod id-ce 16 */
3766 appendPrivateKeyUsagePeriod(properties
, extnValue
);
3768 case 17: /* SubjectAltName id-ce 17 */
3769 case 18: /* IssuerAltName id-ce 18 */
3770 appendGeneralNames(properties
, extnValue
);
3772 case 19: /* BasicConstraints id-ce 19 */
3773 appendBasicConstraints(properties
, extnValue
);
3775 case 30: /* NameConstraints id-ce 30 */
3776 appendNameConstraints(properties
, extnValue
);
3778 case 31: /* CRLDistributionPoints id-ce 31 */
3779 appendCrlDistributionPoints(properties
, extnValue
);
3781 case 32: /* CertificatePolicies id-ce 32 */
3782 appendCertificatePolicies(properties
, extnValue
);
3784 case 33: /* PolicyMappings id-ce 33 */
3787 case 35: /* AuthorityKeyIdentifier id-ce 35 */
3788 appendAuthorityKeyIdentifier(properties
, extnValue
);
3790 case 36: /* PolicyConstraints id-ce 36 */
3791 appendPolicyConstraints(properties
, extnValue
);
3793 case 37: /* ExtKeyUsage id-ce 37 */
3794 appendExtendedKeyUsage(properties
, extnValue
);
3796 case 46: /* FreshestCRL id-ce 46 */
3799 case 54: /* InhibitAnyPolicy id-ce 54 */
3806 } else if (extnID
->length
== oidAuthorityInfoAccess
.length
&&
3807 !memcmp(extnID
->data
, oidAuthorityInfoAccess
.data
, extnID
->length
- 1))
3809 switch (extnID
->data
[extnID
->length
- 1]) {
3810 case 1: /* AuthorityInfoAccess id-pe 1 */
3811 appendInfoAccess(properties
, extnValue
);
3813 case 3: /* QCStatements id-pe 3 */
3816 case 11: /* SubjectInfoAccess id-pe 11 */
3817 appendInfoAccess(properties
, extnValue
);
3823 } else if (DEROidCompare(extnID
, &oidNetscapeCertType
)) {
3824 /* 2.16.840.1.113730.1.1 netscape 1 1 */
3825 appendNetscapeCertType(properties
, extnValue
);
3831 /* Try to parse and display printable string(s). */
3832 if (appendPrintableDERSequence(properties
, SEC_DATA_KEY
, extnValue
)) {
3833 /* Nothing to do here appendPrintableDERSequence did the work. */
3835 /* Couldn't parse extension; dump the raw unparsed data as hex. */
3836 appendUnparsedProperty(properties
, SEC_DATA_KEY
, NULL
, extnValue
);
3839 label
= SecDERItemCopyOIDDecimalRepresentation(allocator
, extnID
);
3840 localizedLabel
= copyLocalizedOidDescription(allocator
, extnID
);
3841 appendProperty(parent
, kSecPropertyTypeSection
, label
, localizedLabel
, properties
);
3844 CFReleaseSafe(localizedLabel
);
3845 CFReleaseSafe(label
);
3846 CFReleaseSafe(properties
);
3849 /* Different types of summary types from least desired to most desired. */
3852 kSummaryTypePrintable
,
3853 kSummaryTypeOrganizationName
,
3854 kSummaryTypeOrganizationalUnitName
,
3855 kSummaryTypeCommonName
,
3859 enum SummaryType type
;
3860 CFStringRef summary
;
3861 CFStringRef description
;
3864 static OSStatus
obtainSummaryFromX501Name(void *context
,
3865 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
3866 struct Summary
*summary
= (struct Summary
*)context
;
3867 enum SummaryType stype
= kSummaryTypeNone
;
3868 CFStringRef string
= NULL
;
3869 if (DEROidCompare(type
, &oidCommonName
)) {
3870 stype
= kSummaryTypeCommonName
;
3871 } else if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
3872 stype
= kSummaryTypeOrganizationalUnitName
;
3873 } else if (DEROidCompare(type
, &oidOrganizationName
)) {
3874 stype
= kSummaryTypeOrganizationName
;
3875 } else if (DEROidCompare(type
, &oidDescription
)) {
3876 string
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
3878 if (summary
->description
) {
3879 CFStringRef fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
3880 CFStringRef newDescription
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, string
, summary
->description
);
3882 CFRelease(summary
->description
);
3883 summary
->description
= newDescription
;
3885 summary
->description
= string
;
3888 stype
= kSummaryTypePrintable
;
3891 stype
= kSummaryTypePrintable
;
3894 /* Build a string with all instances of the most desired
3895 component type in reverse order encountered comma separated list,
3896 The order of desirability is defined by enum SummaryType. */
3897 if (summary
->type
<= stype
) {
3899 string
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
3902 if (summary
->type
== stype
) {
3903 CFStringRef fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
3904 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, string
, summary
->summary
);
3907 string
= newSummary
;
3909 summary
->type
= stype
;
3911 CFReleaseSafe(summary
->summary
);
3912 summary
->summary
= string
;
3915 CFReleaseSafe(string
);
3918 return errSecSuccess
;
3921 CFStringRef
SecCertificateCopySubjectSummary(SecCertificateRef certificate
) {
3922 struct Summary summary
= {};
3923 parseX501NameContent(&certificate
->_subject
, &summary
, obtainSummaryFromX501Name
);
3924 /* If we found a description and a common name we change the summary to
3925 CommonName (Description). */
3926 if (summary
.description
) {
3927 if (summary
.type
== kSummaryTypeCommonName
) {
3928 CFStringRef fmt
= SecCopyCertString(SEC_COMMON_NAME_DESC_KEY
);
3929 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, summary
.summary
, summary
.description
);
3931 CFRelease(summary
.summary
);
3932 summary
.summary
= newSummary
;
3934 CFRelease(summary
.description
);
3937 if (!summary
.summary
) {
3938 /* If we didn't find a suitable printable string in the subject at all, we try
3939 the first email address in the certificate instead. */
3940 CFArrayRef names
= SecCertificateCopyRFC822Names(certificate
);
3942 /* If we didn't find any email addresses in the certificate, we try finding
3943 a DNS name instead. */
3944 names
= SecCertificateCopyDNSNames(certificate
);
3947 summary
.summary
= CFArrayGetValueAtIndex(names
, 0);
3948 CFRetain(summary
.summary
);
3953 return summary
.summary
;
3956 CFStringRef
SecCertificateCopyIssuerSummary(SecCertificateRef certificate
) {
3957 struct Summary summary
= {};
3958 parseX501NameContent(&certificate
->_issuer
, &summary
, obtainSummaryFromX501Name
);
3959 /* If we found a description and a common name we change the summary to
3960 CommonName (Description). */
3961 if (summary
.description
) {
3962 if (summary
.type
== kSummaryTypeCommonName
) {
3963 CFStringRef fmt
= SecCopyCertString(SEC_COMMON_NAME_DESC_KEY
);
3964 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, summary
.summary
, summary
.description
);
3966 CFRelease(summary
.summary
);
3967 summary
.summary
= newSummary
;
3969 CFRelease(summary
.description
);
3972 return summary
.summary
;
3975 /* Return the earliest date on which all certificates in this chain are still
3977 static CFAbsoluteTime
SecCertificateGetChainsLastValidity(
3978 SecCertificateRef certificate
) {
3979 CFAbsoluteTime earliest
= certificate
->_notAfter
;
3981 while (certificate
->_parent
) {
3982 certificate
= certificate
->_parent
;
3983 if (earliest
> certificate
->_notAfter
)
3984 earliest
= certificate
->_notAfter
;
3991 /* Return the latest date on which all certificates in this chain will be
3993 static CFAbsoluteTime
SecCertificateGetChainsFirstValidity(
3994 SecCertificateRef certificate
) {
3995 CFAbsoluteTime latest
= certificate
->_notBefore
;
3997 while (certificate
->_parent
) {
3998 certificate
= certificate
->_parent
;
3999 if (latest
< certificate
->_notBefore
)
4000 latest
= certificate
->_notBefore
;
4007 bool SecCertificateIsValid(SecCertificateRef certificate
,
4008 CFAbsoluteTime verifyTime
) {
4009 return certificate
&& certificate
->_notBefore
<= verifyTime
&&
4010 verifyTime
<= certificate
->_notAfter
;
4013 CFIndex
SecCertificateVersion(SecCertificateRef certificate
) {
4014 return certificate
->_version
+ 1;
4017 CFAbsoluteTime
SecCertificateNotValidBefore(SecCertificateRef certificate
) {
4018 return certificate
->_notBefore
;
4021 CFAbsoluteTime
SecCertificateNotValidAfter(SecCertificateRef certificate
) {
4022 return certificate
->_notAfter
;
4025 CFMutableArrayRef
SecCertificateCopySummaryProperties(
4026 SecCertificateRef certificate
, CFAbsoluteTime verifyTime
) {
4027 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
4028 CFMutableArrayRef summary
= CFArrayCreateMutable(allocator
, 0,
4029 &kCFTypeArrayCallBacks
);
4031 /* First we put the subject summary name. */
4032 CFStringRef ssummary
= SecCertificateCopySubjectSummary(certificate
);
4034 appendProperty(summary
, kSecPropertyTypeTitle
,
4035 NULL
, NULL
, ssummary
);
4036 CFRelease(ssummary
);
4039 /* Let see if this certificate is currently valid. */
4041 CFAbsoluteTime when
;
4042 CFStringRef message
;
4044 if (verifyTime
> certificate
->_notAfter
) {
4045 label
= SEC_EXPIRED_KEY
;
4046 when
= certificate
->_notAfter
;
4047 ptype
= kSecPropertyTypeError
;
4048 message
= SEC_CERT_EXPIRED_KEY
;
4049 } else if (certificate
->_notBefore
> verifyTime
) {
4050 label
= SEC_VALID_FROM_KEY
;
4051 when
= certificate
->_notBefore
;
4052 ptype
= kSecPropertyTypeError
;
4053 message
= SEC_CERT_NOT_YET_VALID_KEY
;
4055 CFAbsoluteTime last
= SecCertificateGetChainsLastValidity(certificate
);
4056 CFAbsoluteTime first
= SecCertificateGetChainsFirstValidity(certificate
);
4057 if (verifyTime
> last
) {
4058 label
= SEC_EXPIRED_KEY
;
4060 ptype
= kSecPropertyTypeError
;
4061 message
= SEC_ISSUER_EXPIRED_KEY
;
4062 } else if (verifyTime
< first
) {
4063 label
= SEC_VALID_FROM_KEY
;
4065 ptype
= kSecPropertyTypeError
;
4066 message
= SEC_ISSR_NOT_YET_VALID_KEY
;
4068 label
= SEC_EXPIRES_KEY
;
4069 when
= certificate
->_notAfter
;
4070 ptype
= kSecPropertyTypeSuccess
;
4071 message
= SEC_CERT_VALID_KEY
;
4075 appendDateProperty(summary
, label
, when
);
4076 CFStringRef lmessage
= SecCopyCertString(message
);
4077 appendProperty(summary
, ptype
, NULL
, NULL
, lmessage
);
4078 CFRelease(lmessage
);
4083 CFArrayRef
SecCertificateCopyLegacyProperties(SecCertificateRef certificate
) {
4085 This function replicates the content returned by SecCertificateCopyProperties
4086 prior to 10.12.4, providing stable return values for SecCertificateCopyValues.
4087 Unlike SecCertificateCopyProperties, it does not cache the result and
4088 assumes the caller will do so.
4090 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
4091 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
,
4092 0, &kCFTypeArrayCallBacks
);
4095 CFArrayRef subject_plist
= createPropertiesForX501NameContent(allocator
,
4096 &certificate
->_subject
);
4097 appendProperty(properties
, kSecPropertyTypeSection
, CFSTR("Subject Name"),
4098 NULL
, subject_plist
);
4099 CFRelease(subject_plist
);
4102 CFArrayRef issuer_plist
= createPropertiesForX501NameContent(allocator
,
4103 &certificate
->_issuer
);
4104 appendProperty(properties
, kSecPropertyTypeSection
, CFSTR("Issuer Name"),
4105 NULL
, issuer_plist
);
4106 CFRelease(issuer_plist
);
4109 CFStringRef versionString
= CFStringCreateWithFormat(allocator
,
4110 NULL
, CFSTR("%d"), certificate
->_version
+ 1);
4111 appendProperty(properties
, kSecPropertyTypeString
, CFSTR("Version"),
4112 NULL
, versionString
);
4113 CFRelease(versionString
);
4116 if (certificate
->_serialNum
.length
) {
4117 appendIntegerProperty(properties
, CFSTR("Serial Number"),
4118 &certificate
->_serialNum
);
4121 /* Signature Algorithm */
4122 appendAlgorithmProperty(properties
, CFSTR("Signature Algorithm"),
4123 &certificate
->_tbsSigAlg
);
4125 /* Validity dates */
4126 appendDateProperty(properties
, CFSTR("Not Valid Before"), certificate
->_notBefore
);
4127 appendDateProperty(properties
, CFSTR("Not Valid After"), certificate
->_notAfter
);
4129 if (certificate
->_subjectUniqueID
.length
) {
4130 appendDataProperty(properties
, CFSTR("Subject Unique ID"),
4131 NULL
, &certificate
->_subjectUniqueID
);
4133 if (certificate
->_issuerUniqueID
.length
) {
4134 appendDataProperty(properties
, CFSTR("Issuer Unique ID"),
4135 NULL
, &certificate
->_issuerUniqueID
);
4138 /* Public Key Algorithm */
4139 appendAlgorithmProperty(properties
, CFSTR("Public Key Algorithm"),
4140 &certificate
->_algId
);
4142 /* Public Key Data */
4143 appendDataProperty(properties
, CFSTR("Public Key Data"),
4144 NULL
, &certificate
->_pubKeyDER
);
4147 appendDataProperty(properties
, CFSTR("Signature"),
4148 NULL
, &certificate
->_signature
);
4152 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
4153 appendExtension(properties
, &certificate
->_extensions
[ix
]);
4157 appendFingerprintsProperty(properties
, CFSTR("Fingerprints"), certificate
);
4162 CFArrayRef
SecCertificateCopyProperties(SecCertificateRef certificate
) {
4163 if (!certificate
->_properties
) {
4164 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
4165 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
4166 &kCFTypeArrayCallBacks
);
4167 require_quiet(properties
, out
);
4170 /* First we put the Subject Name in the property list. */
4171 CFArrayRef subject_plist
= createPropertiesForX501NameContent(allocator
,
4172 &certificate
->_subject
);
4173 if (subject_plist
) {
4174 appendProperty(properties
, kSecPropertyTypeSection
,
4175 SEC_SUBJECT_NAME_KEY
, NULL
, subject_plist
);
4177 CFReleaseNull(subject_plist
);
4179 /* Next we put the Issuer Name in the property list. */
4180 CFArrayRef issuer_plist
= createPropertiesForX501NameContent(allocator
,
4181 &certificate
->_issuer
);
4183 appendProperty(properties
, kSecPropertyTypeSection
,
4184 SEC_ISSUER_NAME_KEY
, NULL
, issuer_plist
);
4186 CFReleaseNull(issuer_plist
);
4189 CFStringRef fmt
= SecCopyCertString(SEC_CERT_VERSION_VALUE_KEY
);
4190 CFStringRef versionString
= NULL
;
4192 versionString
= CFStringCreateWithFormat(allocator
, NULL
, fmt
,
4193 certificate
->_version
+ 1);
4196 if (versionString
) {
4197 appendProperty(properties
, kSecPropertyTypeString
,
4198 SEC_VERSION_KEY
, NULL
, versionString
);
4200 CFReleaseNull(versionString
);
4203 appendSerialNumberProperty(properties
, SEC_SERIAL_NUMBER_KEY
, &certificate
->_serialNum
);
4205 /* Validity dates. */
4206 appendValidityPeriodProperty(properties
, SEC_VALIDITY_PERIOD_KEY
, certificate
);
4208 if (certificate
->_subjectUniqueID
.length
) {
4209 appendDataProperty(properties
, SEC_SUBJECT_UNIQUE_ID_KEY
, NULL
,
4210 &certificate
->_subjectUniqueID
);
4212 if (certificate
->_issuerUniqueID
.length
) {
4213 appendDataProperty(properties
, SEC_ISSUER_UNIQUE_ID_KEY
, NULL
,
4214 &certificate
->_issuerUniqueID
);
4217 appendPublicKeyProperty(properties
, SEC_PUBLIC_KEY_KEY
, certificate
);
4220 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
4221 appendExtension(properties
, &certificate
->_extensions
[ix
]);
4225 appendSignatureProperty(properties
, SEC_SIGNATURE_KEY
, certificate
);
4227 appendFingerprintsProperty(properties
, SEC_FINGERPRINTS_KEY
, certificate
);
4229 certificate
->_properties
= properties
;
4233 CFRetainSafe(certificate
->_properties
);
4234 return certificate
->_properties
;
4237 /* Unified serial number API */
4238 CFDataRef
SecCertificateCopySerialNumberData(
4239 SecCertificateRef certificate
,
4244 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidCertificate
, NULL
);
4248 if (certificate
->_serialNumber
) {
4249 CFRetain(certificate
->_serialNumber
);
4251 return certificate
->_serialNumber
;
4255 /* On OS X, the SecCertificateCopySerialNumber API takes two arguments. */
4256 CFDataRef
SecCertificateCopySerialNumber(
4257 SecCertificateRef certificate
,
4258 CFErrorRef
*error
) {
4259 return SecCertificateCopySerialNumberData(certificate
, error
);
4262 /* On iOS, the SecCertificateCopySerialNumber API takes one argument. */
4263 CFDataRef
SecCertificateCopySerialNumber(
4264 SecCertificateRef certificate
) {
4265 return SecCertificateCopySerialNumberData(certificate
, NULL
);
4269 CFDataRef
SecCertificateGetNormalizedIssuerContent(
4270 SecCertificateRef certificate
) {
4271 return certificate
->_normalizedIssuer
;
4274 CFDataRef
SecCertificateGetNormalizedSubjectContent(
4275 SecCertificateRef certificate
) {
4276 return certificate
->_normalizedSubject
;
4279 /* Verify that certificate was signed by issuerKey. */
4280 OSStatus
SecCertificateIsSignedBy(SecCertificateRef certificate
,
4281 SecKeyRef issuerKey
) {
4282 /* Setup algId in SecAsn1AlgId format. */
4284 algId
.algorithm
.Length
= certificate
->_tbsSigAlg
.oid
.length
;
4285 algId
.algorithm
.Data
= certificate
->_tbsSigAlg
.oid
.data
;
4286 algId
.parameters
.Length
= certificate
->_tbsSigAlg
.params
.length
;
4287 algId
.parameters
.Data
= certificate
->_tbsSigAlg
.params
.data
;
4289 /* RFC5280 4.1.1.2, 4.1.2.3 requires the actual signature algorithm
4290 must match the specified algorithm in the TBSCertificate. */
4291 bool sigAlgMatch
= DEROidCompare(&certificate
->_sigAlg
.oid
,
4292 &certificate
->_tbsSigAlg
.oid
);
4294 secwarning("Signature algorithm mismatch in certificate (see RFC5280 4.1.1.2)");
4297 CFErrorRef error
= NULL
;
4299 !SecVerifySignatureWithPublicKey(issuerKey
, &algId
,
4300 certificate
->_tbs
.data
, certificate
->_tbs
.length
,
4301 certificate
->_signature
.data
, certificate
->_signature
.length
, &error
))
4303 #if !defined(NDEBUG)
4304 secdebug("verify", "signature verify failed: %" PRIdOSStatus
, (error
) ? (OSStatus
)CFErrorGetCode(error
) : errSecNotSigner
);
4306 CFReleaseSafe(error
);
4307 return errSecNotSigner
;
4310 return errSecSuccess
;
4313 const DERItem
* SecCertificateGetSubjectAltName(SecCertificateRef certificate
) {
4314 if (!certificate
->_subjectAltName
) {
4317 return &certificate
->_subjectAltName
->extnValue
;
4320 static OSStatus
appendIPAddressesFromGeneralNames(void *context
,
4321 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4322 CFMutableArrayRef ipAddresses
= (CFMutableArrayRef
)context
;
4323 if (gnType
== GNT_IPAddress
) {
4324 CFStringRef string
= copyIPAddressContentDescription(
4325 kCFAllocatorDefault
, generalName
);
4327 CFArrayAppendValue(ipAddresses
, string
);
4330 return errSecInvalidCertificate
;
4333 return errSecSuccess
;
4336 CFArrayRef
SecCertificateCopyIPAddresses(SecCertificateRef certificate
) {
4337 /* These can only exist in the subject alt name. */
4338 if (!certificate
->_subjectAltName
)
4341 CFMutableArrayRef ipAddresses
= CFArrayCreateMutable(kCFAllocatorDefault
,
4342 0, &kCFTypeArrayCallBacks
);
4343 OSStatus status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4344 ipAddresses
, appendIPAddressesFromGeneralNames
);
4345 if (status
|| CFArrayGetCount(ipAddresses
) == 0) {
4346 CFRelease(ipAddresses
);
4352 static OSStatus
appendDNSNamesFromGeneralNames(void *context
, SecCEGeneralNameType gnType
,
4353 const DERItem
*generalName
) {
4354 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4355 if (gnType
== GNT_DNSName
) {
4356 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorDefault
,
4357 generalName
->data
, generalName
->length
,
4358 kCFStringEncodingUTF8
, FALSE
);
4360 CFArrayAppendValue(dnsNames
, string
);
4363 return errSecInvalidCertificate
;
4366 return errSecSuccess
;
4369 /* Return true if the passed in string matches the
4370 Preferred name syntax from sections 2.3.1. in RFC 1035.
4371 With the added check that we disallow empty dns names.
4372 Also in order to support wildcard DNSNames we allow for the '*'
4373 character anywhere in a dns component where we currently allow
4376 <domain> ::= <subdomain> | " "
4378 <subdomain> ::= <label> | <subdomain> "." <label>
4380 <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
4382 <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
4384 <let-dig-hyp> ::= <let-dig> | "-"
4386 <let-dig> ::= <letter> | <digit>
4388 <letter> ::= any one of the 52 alphabetic characters A through Z in
4389 upper case and a through z in lower case
4391 <digit> ::= any one of the ten digits 0 through 9
4393 static bool isDNSName(CFStringRef string
) {
4394 CFStringInlineBuffer buf
= {};
4395 CFIndex ix
, labelLength
= 0, length
= CFStringGetLength(string
);
4396 /* From RFC 1035 2.3.4. Size limits:
4397 labels 63 octets or less
4398 names 255 octets or less */
4399 require_quiet(length
<= 255, notDNS
);
4400 CFRange range
= { 0, length
};
4401 CFStringInitInlineBuffer(string
, &buf
, range
);
4405 kDNSStateAfterAlpha
,
4406 kDNSStateAfterDigit
,
4408 } state
= kDNSStateInital
;
4410 for (ix
= 0; ix
< length
; ++ix
) {
4411 UniChar ch
= CFStringGetCharacterFromInlineBuffer(&buf
, ix
);
4414 require_quiet(labelLength
<= 64 &&
4415 (state
== kDNSStateAfterAlpha
|| state
== kDNSStateAfterDigit
),
4417 state
= kDNSStateAfterDot
;
4419 } else if (('A' <= ch
&& ch
<= 'Z') || ('a' <= ch
&& ch
<= 'z') ||
4421 state
= kDNSStateAfterAlpha
;
4422 } else if ('0' <= ch
&& ch
<= '9') {
4424 /* The requirement for labels to start with a letter was
4425 dropped so we don't check this anymore. */
4426 require_quiet(state
== kDNSStateAfterAlpha
||
4427 state
== kDNSStateAfterDigit
||
4428 state
== kDNSStateAfterDash
, notDNS
);
4430 state
= kDNSStateAfterDigit
;
4431 } else if (ch
== '-') {
4432 require_quiet(state
== kDNSStateAfterAlpha
||
4433 state
== kDNSStateAfterDigit
||
4434 state
== kDNSStateAfterDash
, notDNS
);
4435 state
= kDNSStateAfterDash
;
4441 /* We don't allow a dns name to end in a dot or dash. */
4442 require_quiet(labelLength
<= 63 &&
4443 (state
== kDNSStateAfterAlpha
|| state
== kDNSStateAfterDigit
),
4451 static OSStatus
appendDNSNamesFromX501Name(void *context
, const DERItem
*type
,
4452 const DERItem
*value
, CFIndex rdnIX
) {
4453 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4454 if (DEROidCompare(type
, &oidCommonName
)) {
4455 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4458 if (isDNSName(string
)) {
4459 /* We found a common name that is formatted like a valid
4461 CFArrayAppendValue(dnsNames
, string
);
4465 return errSecInvalidCertificate
;
4468 return errSecSuccess
;
4471 /* Not everything returned by this function is going to be a proper DNS name,
4472 we also return the certificates common name entries from the subject,
4473 assuming they look like dns names as specified in RFC 1035. */
4474 CFArrayRef
SecCertificateCopyDNSNames(SecCertificateRef certificate
) {
4475 /* These can exist in the subject alt name or in the subject. */
4476 CFMutableArrayRef dnsNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4477 0, &kCFTypeArrayCallBacks
);
4478 OSStatus status
= errSecSuccess
;
4479 if (certificate
->_subjectAltName
) {
4480 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4481 dnsNames
, appendDNSNamesFromGeneralNames
);
4483 /* RFC 2818 section 3.1. Server Identity
4485 If a subjectAltName extension of type dNSName is present, that MUST
4486 be used as the identity. Otherwise, the (most specific) Common Name
4487 field in the Subject field of the certificate MUST be used. Although
4488 the use of the Common Name is existing practice, it is deprecated and
4489 Certification Authorities are encouraged to use the dNSName instead.
4492 This implies that if we found 1 or more DNSNames in the
4493 subjectAltName, we should not use the Common Name of the subject as
4496 if (!status
&& CFArrayGetCount(dnsNames
) == 0) {
4497 status
= parseX501NameContent(&certificate
->_subject
, dnsNames
,
4498 appendDNSNamesFromX501Name
);
4500 if (status
|| CFArrayGetCount(dnsNames
) == 0) {
4501 CFRelease(dnsNames
);
4507 static OSStatus
appendRFC822NamesFromGeneralNames(void *context
,
4508 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4509 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4510 if (gnType
== GNT_RFC822Name
) {
4511 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorDefault
,
4512 generalName
->data
, generalName
->length
,
4513 kCFStringEncodingASCII
, FALSE
);
4515 CFArrayAppendValue(dnsNames
, string
);
4518 return errSecInvalidCertificate
;
4521 return errSecSuccess
;
4524 static OSStatus
appendRFC822NamesFromX501Name(void *context
, const DERItem
*type
,
4525 const DERItem
*value
, CFIndex rdnIX
) {
4526 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4527 if (DEROidCompare(type
, &oidEmailAddress
)) {
4528 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4531 CFArrayAppendValue(dnsNames
, string
);
4534 return errSecInvalidCertificate
;
4537 return errSecSuccess
;
4540 CFArrayRef
SecCertificateCopyRFC822Names(SecCertificateRef certificate
) {
4541 /* These can exist in the subject alt name or in the subject. */
4542 CFMutableArrayRef rfc822Names
= CFArrayCreateMutable(kCFAllocatorDefault
,
4543 0, &kCFTypeArrayCallBacks
);
4544 OSStatus status
= errSecSuccess
;
4545 if (certificate
->_subjectAltName
) {
4546 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4547 rfc822Names
, appendRFC822NamesFromGeneralNames
);
4550 status
= parseX501NameContent(&certificate
->_subject
, rfc822Names
,
4551 appendRFC822NamesFromX501Name
);
4553 if (status
|| CFArrayGetCount(rfc822Names
) == 0) {
4554 CFRelease(rfc822Names
);
4560 OSStatus
SecCertificateCopyEmailAddresses(SecCertificateRef certificate
, CFArrayRef
* __nonnull CF_RETURNS_RETAINED emailAddresses
) {
4561 if (!certificate
|| !emailAddresses
) {
4564 *emailAddresses
= SecCertificateCopyRFC822Names(certificate
);
4565 if (*emailAddresses
== NULL
) {
4566 *emailAddresses
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
4568 return errSecSuccess
;
4571 static OSStatus
appendCommonNamesFromX501Name(void *context
,
4572 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4573 CFMutableArrayRef commonNames
= (CFMutableArrayRef
)context
;
4574 if (DEROidCompare(type
, &oidCommonName
)) {
4575 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4578 CFArrayAppendValue(commonNames
, string
);
4581 return errSecInvalidCertificate
;
4584 return errSecSuccess
;
4587 CFArrayRef
SecCertificateCopyCommonNames(SecCertificateRef certificate
) {
4588 CFMutableArrayRef commonNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4589 0, &kCFTypeArrayCallBacks
);
4591 status
= parseX501NameContent(&certificate
->_subject
, commonNames
,
4592 appendCommonNamesFromX501Name
);
4593 if (status
|| CFArrayGetCount(commonNames
) == 0) {
4594 CFRelease(commonNames
);
4600 OSStatus
SecCertificateCopyCommonName(SecCertificateRef certificate
, CFStringRef
*commonName
)
4605 CFArrayRef commonNames
= SecCertificateCopyCommonNames(certificate
);
4607 return errSecInternal
;
4611 CFIndex count
= CFArrayGetCount(commonNames
);
4612 *commonName
= CFRetainSafe(CFArrayGetValueAtIndex(commonNames
, count
-1));
4614 CFReleaseSafe(commonNames
);
4615 return errSecSuccess
;
4618 static OSStatus
appendOrganizationFromX501Name(void *context
,
4619 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4620 CFMutableArrayRef organization
= (CFMutableArrayRef
)context
;
4621 if (DEROidCompare(type
, &oidOrganizationName
)) {
4622 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4625 CFArrayAppendValue(organization
, string
);
4628 return errSecInvalidCertificate
;
4631 return errSecSuccess
;
4634 CFArrayRef
SecCertificateCopyOrganization(SecCertificateRef certificate
) {
4635 CFMutableArrayRef organization
= CFArrayCreateMutable(kCFAllocatorDefault
,
4636 0, &kCFTypeArrayCallBacks
);
4638 status
= parseX501NameContent(&certificate
->_subject
, organization
,
4639 appendOrganizationFromX501Name
);
4640 if (status
|| CFArrayGetCount(organization
) == 0) {
4641 CFRelease(organization
);
4642 organization
= NULL
;
4644 return organization
;
4647 static OSStatus
appendOrganizationalUnitFromX501Name(void *context
,
4648 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4649 CFMutableArrayRef organizationalUnit
= (CFMutableArrayRef
)context
;
4650 if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
4651 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4654 CFArrayAppendValue(organizationalUnit
, string
);
4657 return errSecInvalidCertificate
;
4660 return errSecSuccess
;
4663 CFArrayRef
SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate
) {
4664 CFMutableArrayRef organizationalUnit
= CFArrayCreateMutable(kCFAllocatorDefault
,
4665 0, &kCFTypeArrayCallBacks
);
4667 status
= parseX501NameContent(&certificate
->_subject
, organizationalUnit
,
4668 appendOrganizationalUnitFromX501Name
);
4669 if (status
|| CFArrayGetCount(organizationalUnit
) == 0) {
4670 CFRelease(organizationalUnit
);
4671 organizationalUnit
= NULL
;
4673 return organizationalUnit
;
4676 static OSStatus
appendCountryFromX501Name(void *context
,
4677 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4678 CFMutableArrayRef countries
= (CFMutableArrayRef
)context
;
4679 if (DEROidCompare(type
, &oidCountryName
)) {
4680 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4683 CFArrayAppendValue(countries
, string
);
4686 return errSecInvalidCertificate
;
4689 return errSecSuccess
;
4692 CFArrayRef
SecCertificateCopyCountry(SecCertificateRef certificate
) {
4693 CFMutableArrayRef countries
= CFArrayCreateMutable(kCFAllocatorDefault
,
4694 0, &kCFTypeArrayCallBacks
);
4696 status
= parseX501NameContent(&certificate
->_subject
, countries
,
4697 appendCountryFromX501Name
);
4698 if (status
|| CFArrayGetCount(countries
) == 0) {
4699 CFRelease(countries
);
4705 const SecCEBasicConstraints
*
4706 SecCertificateGetBasicConstraints(SecCertificateRef certificate
) {
4707 if (certificate
->_basicConstraints
.present
)
4708 return &certificate
->_basicConstraints
;
4713 CFArrayRef
SecCertificateGetPermittedSubtrees(SecCertificateRef certificate
) {
4714 return (certificate
->_permittedSubtrees
);
4717 CFArrayRef
SecCertificateGetExcludedSubtrees(SecCertificateRef certificate
) {
4718 return (certificate
->_excludedSubtrees
);
4721 const SecCEPolicyConstraints
*
4722 SecCertificateGetPolicyConstraints(SecCertificateRef certificate
) {
4723 if (certificate
->_policyConstraints
.present
)
4724 return &certificate
->_policyConstraints
;
4729 const SecCEPolicyMappings
*
4730 SecCertificateGetPolicyMappings(SecCertificateRef certificate
) {
4731 if (certificate
->_policyMappings
.present
) {
4732 return &certificate
->_policyMappings
;
4738 const SecCECertificatePolicies
*
4739 SecCertificateGetCertificatePolicies(SecCertificateRef certificate
) {
4740 if (certificate
->_certificatePolicies
.present
)
4741 return &certificate
->_certificatePolicies
;
4746 const SecCEInhibitAnyPolicy
*
4747 SecCertificateGetInhibitAnyPolicySkipCerts(SecCertificateRef certificate
) {
4748 if (certificate
->_inhibitAnyPolicySkipCerts
.present
) {
4749 return &certificate
->_inhibitAnyPolicySkipCerts
;
4755 static OSStatus
appendNTPrincipalNamesFromGeneralNames(void *context
,
4756 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4757 CFMutableArrayRef ntPrincipalNames
= (CFMutableArrayRef
)context
;
4758 if (gnType
== GNT_OtherName
) {
4760 DERReturn drtn
= DERParseSequenceContent(generalName
,
4761 DERNumOtherNameItemSpecs
, DEROtherNameItemSpecs
,
4763 require_noerr_quiet(drtn
, badDER
);
4764 if (DEROidCompare(&on
.typeIdentifier
, &oidMSNTPrincipalName
)) {
4766 require_quiet(string
= copyDERThingDescription(kCFAllocatorDefault
,
4767 &on
.value
, true), badDER
);
4768 CFArrayAppendValue(ntPrincipalNames
, string
);
4772 return errSecSuccess
;
4775 return errSecInvalidCertificate
;
4779 CFArrayRef
SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate
) {
4780 CFMutableArrayRef ntPrincipalNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4781 0, &kCFTypeArrayCallBacks
);
4782 OSStatus status
= errSecSuccess
;
4783 if (certificate
->_subjectAltName
) {
4784 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4785 ntPrincipalNames
, appendNTPrincipalNamesFromGeneralNames
);
4787 if (status
|| CFArrayGetCount(ntPrincipalNames
) == 0) {
4788 CFRelease(ntPrincipalNames
);
4789 ntPrincipalNames
= NULL
;
4791 return ntPrincipalNames
;
4794 static OSStatus
appendToRFC2253String(void *context
,
4795 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4796 CFMutableStringRef string
= (CFMutableStringRef
)context
;
4800 ST stateOrProvinceName
4802 OU organizationalUnitName
4804 STREET streetAddress
4808 /* Prepend a + if this is not the first RDN in an RDN set.
4809 Otherwise prepend a , if this is not the first RDN. */
4811 CFStringAppend(string
, CFSTR("+"));
4812 else if (CFStringGetLength(string
)) {
4813 CFStringAppend(string
, CFSTR(","));
4816 CFStringRef label
, oid
= NULL
;
4817 /* @@@ Consider changing this to a dictionary lookup keyed by the
4818 decimal representation. */
4819 if (DEROidCompare(type
, &oidCommonName
)) {
4820 label
= CFSTR("CN");
4821 } else if (DEROidCompare(type
, &oidLocalityName
)) {
4823 } else if (DEROidCompare(type
, &oidStateOrProvinceName
)) {
4824 label
= CFSTR("ST");
4825 } else if (DEROidCompare(type
, &oidOrganizationName
)) {
4827 } else if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
4828 label
= CFSTR("OU");
4829 } else if (DEROidCompare(type
, &oidCountryName
)) {
4832 } else if (DEROidCompare(type
, &oidStreetAddress
)) {
4833 label
= CFSTR("STREET");
4834 } else if (DEROidCompare(type
, &oidDomainComponent
)) {
4835 label
= CFSTR("DC");
4836 } else if (DEROidCompare(type
, &oidUserID
)) {
4837 label
= CFSTR("UID");
4840 label
= oid
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, type
);
4843 CFStringAppend(string
, label
);
4844 CFStringAppend(string
, CFSTR("="));
4845 CFStringRef raw
= NULL
;
4847 raw
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
4850 /* Append raw to string while escaping:
4851 a space or "#" character occurring at the beginning of the string
4852 a space character occurring at the end of the string
4853 one of the characters ",", "+", """, "\", "<", ">" or ";"
4855 CFStringInlineBuffer buffer
= {};
4856 CFIndex ix
, length
= CFStringGetLength(raw
);
4857 CFRange range
= { 0, length
};
4858 CFStringInitInlineBuffer(raw
, &buffer
, range
);
4859 for (ix
= 0; ix
< length
; ++ix
) {
4860 UniChar ch
= CFStringGetCharacterFromInlineBuffer(&buffer
, ix
);
4862 CFStringAppendFormat(string
, NULL
, CFSTR("\\%02X"), ch
);
4863 } else if (ch
== ',' || ch
== '+' || ch
== '"' || ch
== '\\' ||
4864 ch
== '<' || ch
== '>' || ch
== ';' ||
4865 (ch
== ' ' && (ix
== 0 || ix
== length
- 1)) ||
4866 (ch
== '#' && ix
== 0)) {
4867 UniChar chars
[] = { '\\', ch
};
4868 CFStringAppendCharacters(string
, chars
, 2);
4870 CFStringAppendCharacters(string
, &ch
, 1);
4875 /* Append the value in hex. */
4876 CFStringAppend(string
, CFSTR("#"));
4878 for (ix
= 0; ix
< value
->length
; ++ix
)
4879 CFStringAppendFormat(string
, NULL
, CFSTR("%02X"), value
->data
[ix
]);
4884 return errSecSuccess
;
4887 CFStringRef
SecCertificateCopySubjectString(SecCertificateRef certificate
) {
4888 CFMutableStringRef string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
4889 OSStatus status
= parseX501NameContent(&certificate
->_subject
, string
, appendToRFC2253String
);
4890 if (status
|| CFStringGetLength(string
) == 0) {
4897 static OSStatus
appendToCompanyNameString(void *context
,
4898 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4899 CFMutableStringRef string
= (CFMutableStringRef
)context
;
4900 if (CFStringGetLength(string
) != 0)
4901 return errSecSuccess
;
4903 if (!DEROidCompare(type
, &oidOrganizationName
))
4904 return errSecSuccess
;
4907 raw
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
4909 return errSecSuccess
;
4910 CFStringAppend(string
, raw
);
4913 return errSecSuccess
;
4916 CFStringRef
SecCertificateCopyCompanyName(SecCertificateRef certificate
) {
4917 CFMutableStringRef string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
4918 OSStatus status
= parseX501NameContent(&certificate
->_subject
, string
,
4919 appendToCompanyNameString
);
4920 if (status
|| CFStringGetLength(string
) == 0) {
4927 CFDataRef
SecCertificateCopyIssuerSequence(
4928 SecCertificateRef certificate
) {
4929 return SecDERItemCopySequence(&certificate
->_issuer
);
4932 CFDataRef
SecCertificateCopySubjectSequence(
4933 SecCertificateRef certificate
) {
4934 return SecDERItemCopySequence(&certificate
->_subject
);
4937 CFDataRef
SecCertificateCopyNormalizedIssuerSequence(SecCertificateRef certificate
) {
4938 if (!certificate
|| !certificate
->_normalizedIssuer
) {
4941 return SecCopySequenceFromContent(certificate
->_normalizedIssuer
);
4944 CFDataRef
SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certificate
) {
4945 if (!certificate
|| !certificate
->_normalizedSubject
) {
4948 return SecCopySequenceFromContent(certificate
->_normalizedSubject
);
4951 const DERAlgorithmId
*SecCertificateGetPublicKeyAlgorithm(
4952 SecCertificateRef certificate
) {
4953 return &certificate
->_algId
;
4956 const DERItem
*SecCertificateGetPublicKeyData(SecCertificateRef certificate
) {
4957 return &certificate
->_pubKeyDER
;
4961 /* There is already a SecCertificateCopyPublicKey with different args on OS X,
4962 so we will refer to this one internally as SecCertificateCopyPublicKey_ios.
4964 __nullable SecKeyRef
SecCertificateCopyPublicKey_ios(SecCertificateRef certificate
)
4966 __nullable SecKeyRef
SecCertificateCopyPublicKey(SecCertificateRef certificate
)
4969 if (certificate
->_pubKey
== NULL
) {
4970 const DERAlgorithmId
*algId
=
4971 SecCertificateGetPublicKeyAlgorithm(certificate
);
4972 const DERItem
*keyData
= SecCertificateGetPublicKeyData(certificate
);
4973 const DERItem
*params
= NULL
;
4974 if (algId
->params
.length
!= 0) {
4975 params
= &algId
->params
;
4977 SecAsn1Oid oid1
= { .Data
= algId
->oid
.data
, .Length
= algId
->oid
.length
};
4978 SecAsn1Item params1
= {
4979 .Data
= params
? params
->data
: NULL
,
4980 .Length
= params
? params
->length
: 0
4982 SecAsn1Item keyData1
= {
4983 .Data
= keyData
? keyData
->data
: NULL
,
4984 .Length
= keyData
? keyData
->length
: 0
4986 certificate
->_pubKey
= SecKeyCreatePublicFromDER(kCFAllocatorDefault
, &oid1
, ¶ms1
,
4990 return CFRetainSafe(certificate
->_pubKey
);
4993 static CFIndex
SecCertificateGetPublicKeyAlgorithmIdAndSize(SecCertificateRef certificate
, size_t *keySizeInBytes
) {
4994 CFIndex keyAlgID
= kSecNullAlgorithmID
;
4997 SecKeyRef pubKey
= NULL
;
4998 require_quiet(certificate
, out
);
5000 require_quiet(pubKey
= SecCertificateCopyPublicKey_ios(certificate
), out
);
5002 require_quiet(pubKey
= SecCertificateCopyPublicKey(certificate
) ,out
);
5004 size
= SecKeyGetBlockSize(pubKey
);
5005 keyAlgID
= SecKeyGetAlgorithmId(pubKey
);
5008 CFReleaseNull(pubKey
);
5009 if (keySizeInBytes
) { *keySizeInBytes
= size
; }
5014 * Public keys in certificates may be considered "weak" or "strong" or neither
5015 * (that is, in between). Certificates using weak keys are not trusted at all.
5016 * Certificates using neither strong nor weak keys are only trusted in certain
5017 * contexts. SecPolicy and SecPolicyServer define the contexts by which we enforce
5018 * these (or stronger) key size trust policies.
5020 bool SecCertificateIsWeakKey(SecCertificateRef certificate
) {
5021 if (!certificate
) { return true; }
5025 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) {
5026 case kSecRSAAlgorithmID
:
5027 if (MIN_RSA_KEY_SIZE
<= size
) weak
= false;
5029 case kSecECDSAAlgorithmID
:
5030 if (MIN_EC_KEY_SIZE
<= size
) weak
= false;
5038 bool SecCertificateIsStrongKey(SecCertificateRef certificate
) {
5039 if (!certificate
) { return false; }
5041 bool strong
= false;
5043 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) {
5044 case kSecRSAAlgorithmID
:
5045 if (MIN_STRONG_RSA_KEY_SIZE
<= size
) strong
= true;
5047 case kSecECDSAAlgorithmID
:
5048 if (MIN_STRONG_EC_KEY_SIZE
<= size
) strong
= true;
5056 bool SecCertificateIsWeakHash(SecCertificateRef certificate
) {
5057 if (!certificate
) { return true; }
5058 SecSignatureHashAlgorithm certAlg
= 0;
5059 certAlg
= SecCertificateGetSignatureHashAlgorithm(certificate
);
5060 if (certAlg
== kSecSignatureHashAlgorithmUnknown
||
5061 certAlg
== kSecSignatureHashAlgorithmMD2
||
5062 certAlg
== kSecSignatureHashAlgorithmMD4
||
5063 certAlg
== kSecSignatureHashAlgorithmMD5
||
5064 certAlg
== kSecSignatureHashAlgorithmSHA1
) {
5070 bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate
,
5071 CFDictionaryRef keySizes
) {
5072 if (!certificate
) { return false; }
5074 bool goodSize
= false;
5076 CFNumberRef minSize
;
5077 size_t minSizeInBits
;
5078 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) {
5079 case kSecRSAAlgorithmID
:
5080 if(CFDictionaryGetValueIfPresent(keySizes
, kSecAttrKeyTypeRSA
, (const void**)&minSize
)
5081 && minSize
&& CFNumberGetValue(minSize
, kCFNumberLongType
, &minSizeInBits
)) {
5082 if (size
>= (size_t)(minSizeInBits
+7)/8) goodSize
= true;
5085 case kSecECDSAAlgorithmID
:
5086 if(CFDictionaryGetValueIfPresent(keySizes
, kSecAttrKeyTypeEC
, (const void**)&minSize
)
5087 && minSize
&& CFNumberGetValue(minSize
, kCFNumberLongType
, &minSizeInBits
)) {
5088 if (size
>= (size_t)(minSizeInBits
+7)/8) goodSize
= true;
5097 CFDataRef
SecCertificateGetSHA1Digest(SecCertificateRef certificate
) {
5098 if (!certificate
|| !certificate
->_der
.data
) {
5101 if (!certificate
->_sha1Digest
) {
5102 certificate
->_sha1Digest
=
5103 SecSHA1DigestCreate(CFGetAllocator(certificate
),
5104 certificate
->_der
.data
, certificate
->_der
.length
);
5106 return certificate
->_sha1Digest
;
5109 CFDataRef
SecCertificateCopySHA256Digest(SecCertificateRef certificate
) {
5110 if (!certificate
|| !certificate
->_der
.data
) {
5113 return SecSHA256DigestCreate(CFGetAllocator(certificate
),
5114 certificate
->_der
.data
, certificate
->_der
.length
);
5117 CFDataRef
SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate
) {
5118 CFDataRef digest
= NULL
;
5119 CFDataRef issuer
= SecCertificateCopyIssuerSequence(certificate
);
5121 digest
= SecSHA1DigestCreate(kCFAllocatorDefault
,
5122 CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
));
5128 CFDataRef
SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate
) {
5129 if (!certificate
|| !certificate
->_pubKeyDER
.data
) {
5132 return SecSHA1DigestCreate(CFGetAllocator(certificate
),
5133 certificate
->_pubKeyDER
.data
, certificate
->_pubKeyDER
.length
);
5136 CFDataRef
SecCertificateCopySubjectPublicKeyInfoSHA1Digest(SecCertificateRef certificate
) {
5137 if (!certificate
|| !certificate
->_subjectPublicKeyInfo
.data
) {
5140 return SecSHA1DigestCreate(CFGetAllocator(certificate
),
5141 certificate
->_subjectPublicKeyInfo
.data
, certificate
->_subjectPublicKeyInfo
.length
);
5144 CFDataRef
SecCertificateCopySubjectPublicKeyInfoSHA256Digest(SecCertificateRef certificate
) {
5145 if (!certificate
|| !certificate
->_subjectPublicKeyInfo
.data
) {
5148 return SecSHA256DigestCreate(CFGetAllocator(certificate
),
5149 certificate
->_subjectPublicKeyInfo
.data
, certificate
->_subjectPublicKeyInfo
.length
);
5152 CFTypeRef
SecCertificateCopyKeychainItem(SecCertificateRef certificate
)
5157 CFRetainSafe(certificate
->_keychain_item
);
5158 return certificate
->_keychain_item
;
5161 CFDataRef
SecCertificateGetAuthorityKeyID(SecCertificateRef certificate
) {
5165 if (!certificate
->_authorityKeyID
&&
5166 certificate
->_authorityKeyIdentifier
.length
) {
5167 certificate
->_authorityKeyID
= CFDataCreate(kCFAllocatorDefault
,
5168 certificate
->_authorityKeyIdentifier
.data
,
5169 certificate
->_authorityKeyIdentifier
.length
);
5172 return certificate
->_authorityKeyID
;
5175 CFDataRef
SecCertificateGetSubjectKeyID(SecCertificateRef certificate
) {
5179 if (!certificate
->_subjectKeyID
&&
5180 certificate
->_subjectKeyIdentifier
.length
) {
5181 certificate
->_subjectKeyID
= CFDataCreate(kCFAllocatorDefault
,
5182 certificate
->_subjectKeyIdentifier
.data
,
5183 certificate
->_subjectKeyIdentifier
.length
);
5186 return certificate
->_subjectKeyID
;
5189 CFArrayRef
SecCertificateGetCRLDistributionPoints(SecCertificateRef certificate
) {
5193 return certificate
->_crlDistributionPoints
;
5196 CFArrayRef
SecCertificateGetOCSPResponders(SecCertificateRef certificate
) {
5200 return certificate
->_ocspResponders
;
5203 CFArrayRef
SecCertificateGetCAIssuers(SecCertificateRef certificate
) {
5207 return certificate
->_caIssuers
;
5210 bool SecCertificateHasCriticalSubjectAltName(SecCertificateRef certificate
) {
5214 return certificate
->_subjectAltName
&&
5215 certificate
->_subjectAltName
->critical
;
5218 bool SecCertificateHasSubject(SecCertificateRef certificate
) {
5222 /* Since the _subject field is the content of the subject and not the
5223 whole thing, we can simply check for a 0 length subject here. */
5224 return certificate
->_subject
.length
!= 0;
5227 bool SecCertificateHasUnknownCriticalExtension(SecCertificateRef certificate
) {
5231 return certificate
->_foundUnknownCriticalExtension
;
5234 /* Private API functions. */
5235 void SecCertificateShow(SecCertificateRef certificate
) {
5237 fprintf(stderr
, "SecCertificate instance %p:\n", certificate
);
5238 fprintf(stderr
, "\n");
5242 CFDictionaryRef
SecCertificateCopyAttributeDictionary(
5243 SecCertificateRef certificate
) {
5244 if (!certificate
|| !(CFGetTypeID(certificate
) == SecCertificateGetTypeID())) {
5247 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
5248 CFNumberRef certificateType
= NULL
;
5249 CFNumberRef certificateEncoding
= NULL
;
5250 CFStringRef label
= NULL
;
5251 CFStringRef alias
= NULL
;
5252 CFDataRef skid
= NULL
;
5253 CFDataRef pubKeyDigest
= NULL
;
5254 CFDataRef certData
= NULL
;
5255 CFDictionaryRef dict
= NULL
;
5259 /* CSSM_CERT_X_509v1, CSSM_CERT_X_509v2 or CSSM_CERT_X_509v3 */
5260 SInt32 ctv
= certificate
->_version
+ 1;
5261 SInt32 cev
= 3; /* CSSM_CERT_ENCODING_DER */
5262 certificateType
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &ctv
);
5263 require_quiet(certificateType
!= NULL
, out
);
5264 certificateEncoding
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &cev
);
5265 require_quiet(certificateEncoding
!= NULL
, out
);
5266 certData
= SecCertificateCopyData(certificate
);
5267 require_quiet(certData
!= NULL
, out
);
5268 skid
= SecCertificateGetSubjectKeyID(certificate
);
5269 require_quiet(certificate
->_pubKeyDER
.data
!= NULL
&& certificate
->_pubKeyDER
.length
> 0, out
);
5270 pubKeyDigest
= SecSHA1DigestCreate(allocator
, certificate
->_pubKeyDER
.data
,
5271 certificate
->_pubKeyDER
.length
);
5272 require_quiet(pubKeyDigest
!= NULL
, out
);
5274 /* We still need to figure out how to deal with multi valued attributes. */
5275 alias
= SecCertificateCopyRFC822Names(certificate
);
5276 label
= SecCertificateCopySubjectSummary(certificate
);
5282 DICT_ADDPAIR(kSecClass
, kSecClassCertificate
);
5283 DICT_ADDPAIR(kSecAttrCertificateType
, certificateType
);
5284 DICT_ADDPAIR(kSecAttrCertificateEncoding
, certificateEncoding
);
5286 DICT_ADDPAIR(kSecAttrLabel
, label
);
5289 DICT_ADDPAIR(kSecAttrAlias
, alias
);
5291 if (isData(certificate
->_normalizedSubject
)) {
5292 DICT_ADDPAIR(kSecAttrSubject
, certificate
->_normalizedSubject
);
5294 require_quiet(isData(certificate
->_normalizedIssuer
), out
);
5295 DICT_ADDPAIR(kSecAttrIssuer
, certificate
->_normalizedIssuer
);
5296 require_quiet(isData(certificate
->_serialNumber
), out
);
5297 DICT_ADDPAIR(kSecAttrSerialNumber
, certificate
->_serialNumber
);
5299 DICT_ADDPAIR(kSecAttrSubjectKeyID
, skid
);
5301 DICT_ADDPAIR(kSecAttrPublicKeyHash
, pubKeyDigest
);
5302 DICT_ADDPAIR(kSecValueData
, certData
);
5303 dict
= DICT_CREATE(allocator
);
5306 CFReleaseSafe(label
);
5307 CFReleaseSafe(alias
);
5308 CFReleaseSafe(pubKeyDigest
);
5309 CFReleaseSafe(certData
);
5310 CFReleaseSafe(certificateEncoding
);
5311 CFReleaseSafe(certificateType
);
5316 SecCertificateRef
SecCertificateCreateFromAttributeDictionary(
5317 CFDictionaryRef refAttributes
) {
5318 /* @@@ Support having an allocator in refAttributes. */
5319 CFAllocatorRef allocator
= NULL
;
5320 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecValueData
);
5321 return data
? SecCertificateCreateWithData(allocator
, data
) : NULL
;
5325 static bool _SecCertificateIsSelfSigned(SecCertificateRef certificate
) {
5326 if (certificate
->_isSelfSigned
== kSecSelfSignedUnknown
) {
5327 certificate
->_isSelfSigned
= kSecSelfSignedFalse
;
5328 SecKeyRef publicKey
= NULL
;
5329 require(certificate
&& (CFGetTypeID(certificate
) == SecCertificateGetTypeID()), out
);
5331 require(publicKey
= SecCertificateCopyPublicKey_ios(certificate
), out
);
5333 require(publicKey
= SecCertificateCopyPublicKey(certificate
), out
);
5335 CFDataRef normalizedIssuer
=
5336 SecCertificateGetNormalizedIssuerContent(certificate
);
5337 CFDataRef normalizedSubject
=
5338 SecCertificateGetNormalizedSubjectContent(certificate
);
5339 require_quiet(normalizedIssuer
&& normalizedSubject
&&
5340 CFEqual(normalizedIssuer
, normalizedSubject
), out
);
5342 CFDataRef authorityKeyID
= SecCertificateGetAuthorityKeyID(certificate
);
5343 CFDataRef subjectKeyID
= SecCertificateGetSubjectKeyID(certificate
);
5344 if (authorityKeyID
) {
5345 require_quiet(subjectKeyID
&& CFEqual(subjectKeyID
, authorityKeyID
), out
);
5348 require_noerr_quiet(SecCertificateIsSignedBy(certificate
, publicKey
), out
);
5350 certificate
->_isSelfSigned
= kSecSelfSignedTrue
;
5352 CFReleaseSafe(publicKey
);
5355 return (certificate
->_isSelfSigned
== kSecSelfSignedTrue
);
5358 bool SecCertificateIsCA(SecCertificateRef certificate
) {
5359 bool result
= false;
5360 require(certificate
&& (CFGetTypeID(certificate
) == SecCertificateGetTypeID()), out
);
5361 if (SecCertificateVersion(certificate
) >= 3) {
5362 const SecCEBasicConstraints
*basicConstraints
= SecCertificateGetBasicConstraints(certificate
);
5363 result
= (basicConstraints
&& basicConstraints
->isCA
);
5366 result
= _SecCertificateIsSelfSigned(certificate
);
5372 bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate
) {
5373 return (_SecCertificateIsSelfSigned(certificate
) && SecCertificateIsCA(certificate
));
5376 OSStatus
SecCertificateIsSelfSigned(SecCertificateRef certificate
, Boolean
*isSelfSigned
) {
5377 if (!certificate
|| (CFGetTypeID(certificate
) != SecCertificateGetTypeID())) {
5378 return errSecInvalidCertificate
;
5380 if (!isSelfSigned
) {
5383 *isSelfSigned
= _SecCertificateIsSelfSigned(certificate
);
5384 return errSecSuccess
;
5387 SecKeyUsage
SecCertificateGetKeyUsage(SecCertificateRef certificate
) {
5389 return kSecKeyUsageUnspecified
;
5391 return certificate
->_keyUsage
;
5394 CFArrayRef
SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate
)
5396 CFMutableArrayRef extended_key_usage_oids
=
5397 CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
5398 require_quiet(certificate
&& extended_key_usage_oids
, out
);
5400 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5401 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5402 if (extn
->extnID
.length
== oidExtendedKeyUsage
.length
&&
5403 !memcmp(extn
->extnID
.data
, oidExtendedKeyUsage
.data
, extn
->extnID
.length
)) {
5406 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &derSeq
);
5407 require_noerr_quiet(drtn
, out
);
5408 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, out
);
5409 DERDecodedInfo currDecoded
;
5411 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
5412 require_quiet(currDecoded
.tag
== ASN1_OBJECT_ID
, out
);
5413 CFDataRef oid
= CFDataCreate(kCFAllocatorDefault
,
5414 currDecoded
.content
.data
, currDecoded
.content
.length
);
5415 require_quiet(oid
, out
);
5416 CFArrayAppendValue(extended_key_usage_oids
, oid
);
5419 require_quiet(drtn
== DR_EndOfSequence
, out
);
5420 return extended_key_usage_oids
;
5424 CFReleaseSafe(extended_key_usage_oids
);
5428 CFArrayRef
SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate
)
5430 require_quiet(certificate
, out
);
5433 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5434 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5435 if (extn
->extnID
.length
== oidGoogleEmbeddedSignedCertificateTimestamp
.length
&&
5436 !memcmp(extn
->extnID
.data
, oidGoogleEmbeddedSignedCertificateTimestamp
.data
, extn
->extnID
.length
)) {
5437 /* Got the SCT oid */
5438 DERDecodedInfo sctList
;
5439 DERReturn drtn
= DERDecodeItem(&extn
->extnValue
, &sctList
);
5440 require_noerr_quiet(drtn
, out
);
5441 require_quiet(sctList
.tag
== ASN1_OCTET_STRING
, out
);
5442 return SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sctList
.content
.data
, sctList
.content
.length
);
5450 static bool matches_expected(DERItem der
, CFTypeRef expected
) {
5451 if (der
.length
> 1) {
5452 DERDecodedInfo decoded
;
5453 DERDecodeItem(&der
, &decoded
);
5454 switch (decoded
.tag
) {
5457 return decoded
.content
.length
== 0 && expected
== NULL
;
5461 case ASN1_IA5_STRING
:
5462 case ASN1_UTF8_STRING
: {
5463 if (isString(expected
)) {
5464 CFStringRef expectedString
= (CFStringRef
) expected
;
5465 CFStringRef itemString
= CFStringCreateWithBytesNoCopy(kCFAllocatorDefault
, decoded
.content
.data
, decoded
.content
.length
, kCFStringEncodingUTF8
, false, kCFAllocatorNull
);
5467 bool result
= (kCFCompareEqualTo
== CFStringCompare(expectedString
, itemString
, 0));
5468 CFReleaseNull(itemString
);
5474 case ASN1_OCTET_STRING
: {
5475 if (isData(expected
)) {
5476 CFDataRef expectedData
= (CFDataRef
) expected
;
5477 CFDataRef itemData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, decoded
.content
.data
, decoded
.content
.length
, kCFAllocatorNull
);
5479 bool result
= CFEqual(expectedData
, itemData
);
5480 CFReleaseNull(itemData
);
5486 case ASN1_INTEGER
: {
5487 SInt32 expected_value
= 0;
5488 if (isString(expected
))
5490 CFStringRef aStr
= (CFStringRef
)expected
;
5491 expected_value
= CFStringGetIntValue(aStr
);
5493 else if (isNumber(expected
))
5495 CFNumberGetValue(expected
, kCFNumberSInt32Type
, &expected_value
);
5498 uint32_t num_value
= 0;
5499 if (!DERParseInteger(&decoded
.content
, &num_value
))
5501 return ((uint32_t)expected_value
== num_value
);
5514 static bool cert_contains_marker_extension_value(SecCertificateRef certificate
, CFDataRef oid
, CFTypeRef expectedValue
)
5517 const uint8_t *oid_data
= CFDataGetBytePtr(oid
);
5518 size_t oid_len
= CFDataGetLength(oid
);
5520 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5521 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5522 if (extn
->extnID
.length
== oid_len
5523 && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
))
5525 return matches_expected(extn
->extnValue
, expectedValue
);
5531 static bool cert_contains_marker_extension(SecCertificateRef certificate
, CFTypeRef oid
)
5533 return cert_contains_marker_extension_value(certificate
, oid
, NULL
);
5536 struct search_context
{
5538 SecCertificateRef certificate
;
5541 static bool GetDecimalValueOfString(CFStringRef string
, uint32_t* value
)
5543 CFCharacterSetRef nonDecimalDigit
= CFCharacterSetCreateInvertedSet(NULL
, CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
));
5544 bool result
= false;
5546 if ( CFStringGetLength(string
) > 0
5547 && !CFStringFindCharacterFromSet(string
, nonDecimalDigit
, CFRangeMake(0, CFStringGetLength(string
)), kCFCompareForcedOrdering
, NULL
))
5550 *value
= CFStringGetIntValue(string
);
5554 CFReleaseNull(nonDecimalDigit
);
5559 bool SecCertificateIsOidString(CFStringRef oid
)
5561 if (!oid
) return false;
5562 if (2 >= CFStringGetLength(oid
)) return false;
5565 /* oid string only has the allowed characters */
5566 CFCharacterSetRef decimalOid
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("0123456789."));
5567 CFCharacterSetRef nonDecimalOid
= CFCharacterSetCreateInvertedSet(NULL
, decimalOid
);
5568 if (CFStringFindCharacterFromSet(oid
, nonDecimalOid
, CFRangeMake(0, CFStringGetLength(oid
)), kCFCompareForcedOrdering
, NULL
)) {
5572 /* first arc is allowed */
5573 UniChar firstArc
[2];
5574 CFRange firstTwo
= {0, 2};
5575 CFStringGetCharacters(oid
, firstTwo
, firstArc
);
5576 if (firstArc
[1] != '.' ||
5577 (firstArc
[0] != '0' && firstArc
[0] != '1' && firstArc
[0] != '2')) {
5581 CFReleaseNull(decimalOid
);
5582 CFReleaseNull(nonDecimalOid
);
5587 CFDataRef
SecCertificateCreateOidDataFromString(CFAllocatorRef allocator
, CFStringRef string
)
5589 CFMutableDataRef currentResult
= NULL
;
5590 CFDataRef encodedResult
= NULL
;
5592 CFArrayRef parts
= NULL
;
5595 if (!string
|| !SecCertificateIsOidString(string
))
5598 parts
= CFStringCreateArrayBySeparatingStrings(NULL
, string
, CFSTR("."));
5603 count
= CFArrayGetCount(parts
);
5607 // assume no more than 5 bytes needed to represent any part of the oid,
5608 // since we limit parts to 32-bit values,
5609 // but the first two parts only need 1 byte
5610 currentResult
= CFDataCreateMutable(allocator
, 1+(count
-2)*5);
5616 part
= CFArrayGetValueAtIndex(parts
, 0);
5618 if (!GetDecimalValueOfString(part
, &x
) || x
> 6)
5625 part
= CFArrayGetValueAtIndex(parts
, 1);
5627 if (!GetDecimalValueOfString(part
, &x
) || x
> 39)
5633 CFDataAppendBytes(currentResult
, &firstByte
, 1);
5635 for (CFIndex i
= 2; i
< count
&& GetDecimalValueOfString(CFArrayGetValueAtIndex(parts
, i
), &x
); ++i
) {
5636 uint8_t b
[5] = {0, 0, 0, 0, 0};
5638 b
[3] = 0x80 | ((x
>> 7) & 0x7F);
5639 b
[2] = 0x80 | ((x
>> 14) & 0x7F);
5640 b
[1] = 0x80 | ((x
>> 21) & 0x7F);
5641 b
[0] = 0x80 | ((x
>> 28) & 0x7F);
5643 // Skip the unused extension bytes.
5644 size_t skipBytes
= 0;
5645 while (b
[skipBytes
] == 0x80)
5648 CFDataAppendBytes(currentResult
, b
+ skipBytes
, sizeof(b
) - skipBytes
);
5651 encodedResult
= currentResult
;
5652 currentResult
= NULL
;
5655 CFReleaseNull(parts
);
5656 CFReleaseNull(currentResult
);
5658 return encodedResult
;
5661 static void check_for_marker(const void *key
, const void *value
, void *context
)
5663 struct search_context
* search_ctx
= (struct search_context
*) context
;
5664 CFStringRef key_string
= (CFStringRef
) key
;
5665 CFTypeRef value_ref
= (CFTypeRef
) value
;
5667 // If we could have short circuted the iteration
5668 // we would have, but the best we can do
5669 // is not waste time comparing once a match
5671 if (search_ctx
->found
)
5674 if (CFGetTypeID(key_string
) != CFStringGetTypeID())
5677 CFDataRef key_data
= SecCertificateCreateOidDataFromString(NULL
, key_string
);
5679 if (NULL
== key_data
)
5682 if (cert_contains_marker_extension_value(search_ctx
->certificate
, key_data
, value_ref
))
5683 search_ctx
->found
= true;
5685 CFReleaseNull(key_data
);
5689 // CFType Ref is either:
5691 // CFData - OID to match with no data permitted
5692 // CFString - decimal OID to match
5693 // CFDictionary - OID -> Value table for expected values Single Object or Array
5694 // CFArray - Array of the above.
5696 // This returns true if any of the requirements are met.
5697 bool SecCertificateHasMarkerExtension(SecCertificateRef certificate
, CFTypeRef oids
)
5699 if (CFGetTypeID(oids
) == CFArrayGetTypeID()) {
5700 CFIndex ix
, length
= CFArrayGetCount(oids
);
5701 for (ix
= 0; ix
< length
; ix
++)
5702 if (SecCertificateHasMarkerExtension(certificate
, CFArrayGetValueAtIndex((CFArrayRef
)oids
, ix
)))
5704 } else if (CFGetTypeID(oids
) == CFDictionaryGetTypeID()) {
5705 struct search_context context
= { .found
= false, .certificate
= certificate
};
5706 CFDictionaryApplyFunction((CFDictionaryRef
) oids
, &check_for_marker
, &context
);
5707 return context
.found
;
5708 } else if (CFGetTypeID(oids
) == CFDataGetTypeID()) {
5709 return cert_contains_marker_extension(certificate
, oids
);
5710 } else if (CFGetTypeID(oids
) == CFStringGetTypeID()) {
5711 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, oids
);
5712 if (dataOid
== NULL
) return false;
5713 bool result
= cert_contains_marker_extension(certificate
, dataOid
);
5714 CFReleaseNull(dataOid
);
5720 static DERItem
*cert_extension_value_for_marker(SecCertificateRef certificate
, CFDataRef oid
) {
5722 const uint8_t *oid_data
= CFDataGetBytePtr(oid
);
5723 size_t oid_len
= CFDataGetLength(oid
);
5725 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5726 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5727 if (extn
->extnID
.length
== oid_len
5728 && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
))
5730 return (DERItem
*)&extn
->extnValue
;
5737 // CFType Ref is either:
5739 // CFData - OID to match with no data permitted
5740 // CFString - decimal OID to match
5742 DERItem
*SecCertificateGetExtensionValue(SecCertificateRef certificate
, CFTypeRef oid
) {
5743 if (!certificate
|| !oid
) {
5747 if(CFGetTypeID(oid
) == CFDataGetTypeID()) {
5748 return cert_extension_value_for_marker(certificate
, oid
);
5749 } else if (CFGetTypeID(oid
) == CFStringGetTypeID()) {
5750 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, oid
);
5751 if (dataOid
== NULL
) return NULL
;
5752 DERItem
*result
= cert_extension_value_for_marker(certificate
, dataOid
);
5753 CFReleaseNull(dataOid
);
5760 CFDataRef
SecCertificateCopyiAPAuthCapabilities(SecCertificateRef certificate
) {
5764 CFDataRef extensionData
= NULL
;
5765 DERItem
*extensionValue
= NULL
;
5766 extensionValue
= SecCertificateGetExtensionValue(certificate
,
5767 CFSTR("1.2.840.113635.100.6.36"));
5768 require_quiet(extensionValue
, out
);
5769 /* The extension is a octet string containing the DER-encoded 32-byte octet string */
5770 require_quiet(extensionValue
->length
== 34, out
);
5771 DERDecodedInfo decodedValue
;
5772 require_noerr_quiet(DERDecodeItem(extensionValue
, &decodedValue
), out
);
5773 if (decodedValue
.tag
== ASN1_OCTET_STRING
) {
5774 require_quiet(decodedValue
.content
.length
== 32, out
);
5775 extensionData
= CFDataCreate(NULL
, decodedValue
.content
.data
,
5776 decodedValue
.content
.length
);
5778 require_quiet(extensionValue
->data
[33] == 0x00 &&
5779 extensionValue
->data
[32] == 0x00, out
);
5780 extensionData
= CFDataCreate(NULL
, extensionValue
->data
, 32);
5783 return extensionData
;
5787 /* From iapd IAPAuthenticationTypes.h */
5788 typedef struct IapCertSerialNumber
5790 uint8_t xservID
; // Xserver ID
5791 uint8_t hsmID
; // Hardware security module ID (generated cert)
5792 uint8_t delimiter01
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5793 uint8_t dateYear
; // Date year cert was issued
5794 uint8_t dateMonth
; // Date month cert was issued
5795 uint8_t dateDay
; // Date day cert was issued
5796 uint8_t delimiter02
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5797 uint8_t devClass
; // iAP device class (maps to lingo permissions)
5798 uint8_t delimiter03
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5799 uint8_t batchNumHi
; // Batch number high byte (15:08)
5800 uint8_t batchNumLo
; // Batch number low byte (07:00)
5801 uint8_t delimiter04
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5802 uint8_t serialNumHi
; // Serial number high byte (23:16)
5803 uint8_t serialNumMid
; // Serial number middle byte (15:08)
5804 uint8_t serialNumLo
; // Serial number low byte (07:00)
5806 } IapCertSerialNumber_t
, *pIapCertSerialNumber_t
;
5809 #define IAP_CERT_FIELD_DELIMITER 0xAA // "Apple_Accessory" delimiter
5810 SeciAuthVersion
SecCertificateGetiAuthVersion(SecCertificateRef certificate
) {
5812 return kSeciAuthInvalid
;
5814 if (NULL
!= SecCertificateGetExtensionValue(certificate
,
5815 CFSTR("1.2.840.113635.100.6.36"))) {
5816 return kSeciAuthVersion3
;
5818 DERItem serialNumber
= certificate
->_serialNum
;
5819 require_quiet(serialNumber
.data
, out
);
5820 require_quiet(serialNumber
.length
== 15, out
);
5821 require_quiet(serialNumber
.data
[2] == IAP_CERT_FIELD_DELIMITER
&&
5822 serialNumber
.data
[6] == IAP_CERT_FIELD_DELIMITER
&&
5823 serialNumber
.data
[8] == IAP_CERT_FIELD_DELIMITER
&&
5824 serialNumber
.data
[11] == IAP_CERT_FIELD_DELIMITER
, out
);
5825 return kSeciAuthVersion2
;
5827 return kSeciAuthInvalid
;
5830 SecCertificateRef
SecCertificateCreateWithPEM(CFAllocatorRef allocator
,
5831 CFDataRef pem_certificate
)
5833 static const char begin_cert
[] = "-----BEGIN CERTIFICATE-----\n";
5834 static const char end_cert
[] = "-----END CERTIFICATE-----\n";
5835 uint8_t *base64_data
= NULL
;
5836 SecCertificateRef cert
= NULL
;
5837 const unsigned char *data
= CFDataGetBytePtr(pem_certificate
);
5838 //const size_t length = CFDataGetLength(pem_certificate);
5839 char *begin
= strstr((const char *)data
, begin_cert
);
5840 char *end
= strstr((const char *)data
, end_cert
);
5843 begin
+= sizeof(begin_cert
) - 1;
5844 size_t base64_length
= SecBase64Decode(begin
, end
- begin
, NULL
, 0);
5845 if (base64_length
&& (base64_length
< (size_t)CFDataGetLength(pem_certificate
))) {
5846 require_quiet(base64_data
= calloc(1, base64_length
), out
);
5847 require_action_quiet(base64_length
= SecBase64Decode(begin
, end
- begin
, base64_data
, base64_length
), out
, free(base64_data
));
5848 cert
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, base64_data
, base64_length
);
5857 // -- MARK -- XPC encoding/decoding
5860 bool SecCertificateAppendToXPCArray(SecCertificateRef certificate
, xpc_object_t xpc_certificates
, CFErrorRef
*error
) {
5862 return true; // NOOP
5864 size_t length
= SecCertificateGetLength(certificate
);
5865 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
5866 #if SECTRUST_VERBOSE_DEBUG
5867 secerror("cert=0x%lX length=%d bytes=0x%lX", (uintptr_t)certificate
, (int)length
, (uintptr_t)bytes
);
5869 if (!length
|| !bytes
) {
5870 return SecError(errSecParam
, error
, CFSTR("failed to der encode certificate"));
5872 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
5876 SecCertificateRef
SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates
, size_t index
, CFErrorRef
*error
) {
5877 SecCertificateRef certificate
= NULL
;
5879 const uint8_t *bytes
= xpc_array_get_data(xpc_certificates
, index
, &length
);
5881 certificate
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, bytes
, length
);
5884 SecError(errSecParam
, error
, CFSTR("certificates[%zu] failed to decode"), index
);
5889 xpc_object_t
SecCertificateArrayCopyXPCArray(CFArrayRef certificates
, CFErrorRef
*error
) {
5890 xpc_object_t xpc_certificates
;
5891 require_action_quiet(xpc_certificates
= xpc_array_create(NULL
, 0), exit
,
5892 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
5893 CFIndex ix
, count
= CFArrayGetCount(certificates
);
5894 for (ix
= 0; ix
< count
; ++ix
) {
5895 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
5896 #if SECTRUST_VERBOSE_DEBUG
5897 CFIndex length
= SecCertificateGetLength(certificate
);
5898 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
5899 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
);
5901 if (!SecCertificateAppendToXPCArray(certificate
, xpc_certificates
, error
)) {
5902 xpc_release(xpc_certificates
);
5903 xpc_certificates
= NULL
;
5909 return xpc_certificates
;
5912 CFArrayRef
SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates
, CFErrorRef
*error
) {
5913 CFMutableArrayRef certificates
= NULL
;
5914 require_action_quiet(xpc_get_type(xpc_certificates
) == XPC_TYPE_ARRAY
, exit
,
5915 SecError(errSecParam
, error
, CFSTR("certificates xpc value is not an array")));
5916 size_t count
= xpc_array_get_count(xpc_certificates
);
5917 require_action_quiet(certificates
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
), exit
,
5918 SecError(errSecAllocate
, error
, CFSTR("failed to create CFArray of capacity %zu"), count
));
5921 for (ix
= 0; ix
< count
; ++ix
) {
5922 SecCertificateRef cert
= SecCertificateCreateWithXPCArrayAtIndex(xpc_certificates
, ix
, error
);
5924 CFRelease(certificates
);
5927 CFArraySetValueAtIndex(certificates
, ix
, cert
);
5932 return certificates
;
5935 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
5938 static CFArrayRef
CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType
, CFErrorRef
* error
)
5940 __block CFArrayRef result
= NULL
;
5942 do_if_registered(ota_CopyEscrowCertificates
, escrowRootType
, error
);
5944 securityd_send_sync_and_do(kSecXPCOpOTAGetEscrowCertificates
, error
,
5945 ^bool(xpc_object_t message
, CFErrorRef
*error
)
5947 xpc_dictionary_set_uint64(message
, "escrowType", (uint64_t)escrowRootType
);
5950 ^bool(xpc_object_t response
, CFErrorRef
*error
)
5952 xpc_object_t xpc_array
= xpc_dictionary_get_value(response
, kSecXPCKeyResult
);
5954 if (response
&& (NULL
!= xpc_array
)) {
5955 result
= (CFArrayRef
)_CFXPCCreateCFObjectFromXPCObject(xpc_array
);
5958 return SecError(errSecInternal
, error
, CFSTR("Did not get the Escrow certificates"));
5960 return result
!= NULL
;
5965 CFArrayRef
SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType
)
5967 CFArrayRef result
= NULL
;
5969 CFDataRef certData
= NULL
;
5972 if (kSecCertificateBaselineEscrowRoot
== escrowRootType
||
5973 kSecCertificateBaselinePCSEscrowRoot
== escrowRootType
||
5974 kSecCertificateBaselineEscrowBackupRoot
== escrowRootType
||
5975 kSecCertificateBaselineEscrowEnrollmentRoot
== escrowRootType
)
5977 // The request is for the base line certificates.
5978 // Use the hard coded data to generate the return array.
5979 struct RootRecord
** pEscrowRoots
;
5980 switch (escrowRootType
) {
5981 case kSecCertificateBaselineEscrowRoot
:
5982 numRoots
= kNumberOfBaseLineEscrowRoots
;
5983 pEscrowRoots
= kBaseLineEscrowRoots
;
5985 case kSecCertificateBaselinePCSEscrowRoot
:
5986 numRoots
= kNumberOfBaseLinePCSEscrowRoots
;
5987 pEscrowRoots
= kBaseLinePCSEscrowRoots
;
5989 case kSecCertificateBaselineEscrowBackupRoot
:
5990 numRoots
= kNumberOfBaseLineEscrowBackupRoots
;
5991 pEscrowRoots
= kBaseLineEscrowBackupRoots
;
5993 case kSecCertificateBaselineEscrowEnrollmentRoot
:
5995 numRoots
= kNumberOfBaseLineEscrowEnrollmentRoots
;
5996 pEscrowRoots
= kBaseLineEscrowEnrollmentRoots
;
6000 // Get the hard coded set of roots
6001 SecCertificateRef baseLineCerts
[numRoots
];
6002 struct RootRecord
* pRootRecord
= NULL
;
6004 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6005 pRootRecord
= pEscrowRoots
[iCnt
];
6006 if (NULL
!= pRootRecord
&& pRootRecord
->_length
> 0 && NULL
!= pRootRecord
->_bytes
) {
6007 certData
= CFDataCreate(kCFAllocatorDefault
, pRootRecord
->_bytes
, pRootRecord
->_length
);
6008 if (NULL
!= certData
) {
6009 baseLineCerts
[iCnt
] = SecCertificateCreateWithData(kCFAllocatorDefault
, certData
);
6010 CFRelease(certData
);
6014 result
= CFArrayCreate(kCFAllocatorDefault
, (const void **)baseLineCerts
, numRoots
, &kCFTypeArrayCallBacks
);
6015 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6016 if (NULL
!= baseLineCerts
[iCnt
]) {
6017 CFRelease(baseLineCerts
[iCnt
]);
6022 // The request is for the current certificates.
6023 CFErrorRef error
= NULL
;
6024 CFArrayRef cert_datas
= CopyEscrowCertificates(escrowRootType
, &error
);
6025 if (NULL
!= error
|| NULL
== cert_datas
) {
6026 if (NULL
!= error
) {
6029 if (NULL
!= cert_datas
) {
6030 CFRelease(cert_datas
);
6035 numRoots
= (int)(CFArrayGetCount(cert_datas
));
6037 SecCertificateRef assetCerts
[numRoots
];
6038 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6039 certData
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, iCnt
);
6040 if (NULL
!= certData
) {
6041 SecCertificateRef aCertRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, certData
);
6042 assetCerts
[iCnt
] = aCertRef
;
6045 assetCerts
[iCnt
] = NULL
;
6050 result
= CFArrayCreate(kCFAllocatorDefault
, (const void **)assetCerts
, numRoots
, &kCFTypeArrayCallBacks
);
6051 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6052 if (NULL
!= assetCerts
[iCnt
]) {
6053 CFRelease(assetCerts
[iCnt
]);
6057 CFReleaseSafe(cert_datas
);
6062 SEC_CONST_DECL (kSecSignatureDigestAlgorithmUnknown
, "SignatureDigestUnknown");
6063 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD2
, "SignatureDigestMD2");
6064 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD4
, "SignatureDigestMD4");
6065 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD5
, "SignatureDigestMD5");
6066 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA1
, "SignatureDigestSHA1");
6067 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA224
, "SignatureDigestSHA224");
6068 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA256
, "SignatureDigestSHA256");
6069 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA384
, "SignatureDigestSHA284");
6070 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA512
, "SignatureDigestSHA512");
6072 SecSignatureHashAlgorithm
SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate
)
6074 SecSignatureHashAlgorithm result
= kSecSignatureHashAlgorithmUnknown
;
6075 DERAlgorithmId
*algId
= (certificate
) ? &certificate
->_tbsSigAlg
: NULL
;
6076 const DERItem
*algOid
= (algId
) ? &algId
->oid
: NULL
;
6078 if (!algOid
->data
|| !algOid
->length
) {
6081 /* classify the signature algorithm OID into one of our known types */
6082 if (DEROidCompare(algOid
, &oidSha512Ecdsa
) ||
6083 DEROidCompare(algOid
, &oidSha512Rsa
) ||
6084 DEROidCompare(algOid
, &oidSha512
)) {
6085 result
= kSecSignatureHashAlgorithmSHA512
;
6088 if (DEROidCompare(algOid
, &oidSha384Ecdsa
) ||
6089 DEROidCompare(algOid
, &oidSha384Rsa
) ||
6090 DEROidCompare(algOid
, &oidSha384
)) {
6091 result
= kSecSignatureHashAlgorithmSHA384
;
6094 if (DEROidCompare(algOid
, &oidSha256Ecdsa
) ||
6095 DEROidCompare(algOid
, &oidSha256Rsa
) ||
6096 DEROidCompare(algOid
, &oidSha256
)) {
6097 result
= kSecSignatureHashAlgorithmSHA256
;
6100 if (DEROidCompare(algOid
, &oidSha224Ecdsa
) ||
6101 DEROidCompare(algOid
, &oidSha224Rsa
) ||
6102 DEROidCompare(algOid
, &oidSha224
)) {
6103 result
= kSecSignatureHashAlgorithmSHA224
;
6106 if (DEROidCompare(algOid
, &oidSha1Ecdsa
) ||
6107 DEROidCompare(algOid
, &oidSha1Rsa
) ||
6108 DEROidCompare(algOid
, &oidSha1Dsa
) ||
6109 DEROidCompare(algOid
, &oidSha1DsaOIW
) ||
6110 DEROidCompare(algOid
, &oidSha1DsaCommonOIW
) ||
6111 DEROidCompare(algOid
, &oidSha1RsaOIW
) ||
6112 DEROidCompare(algOid
, &oidSha1Fee
) ||
6113 DEROidCompare(algOid
, &oidSha1
)) {
6114 result
= kSecSignatureHashAlgorithmSHA1
;
6117 if (DEROidCompare(algOid
, &oidMd5Rsa
) ||
6118 DEROidCompare(algOid
, &oidMd5Fee
) ||
6119 DEROidCompare(algOid
, &oidMd5
)) {
6120 result
= kSecSignatureHashAlgorithmMD5
;
6123 if (DEROidCompare(algOid
, &oidMd4Rsa
) ||
6124 DEROidCompare(algOid
, &oidMd4
)) {
6125 result
= kSecSignatureHashAlgorithmMD4
;
6128 if (DEROidCompare(algOid
, &oidMd2Rsa
) ||
6129 DEROidCompare(algOid
, &oidMd2
)) {
6130 result
= kSecSignatureHashAlgorithmMD2
;
6139 CFArrayRef
SecCertificateCopyiPhoneDeviceCAChain(void) {
6140 CFMutableArrayRef result
= NULL
;
6141 SecCertificateRef iPhoneDeviceCA
= NULL
, iPhoneCA
= NULL
, appleRoot
= NULL
;
6143 require_quiet(iPhoneDeviceCA
= SecCertificateCreateWithBytes(NULL
, _AppleiPhoneDeviceCA
, sizeof(_AppleiPhoneDeviceCA
)),
6145 require_quiet(iPhoneCA
= SecCertificateCreateWithBytes(NULL
, _AppleiPhoneCA
, sizeof(_AppleiPhoneCA
)),
6147 require_quiet(appleRoot
= SecCertificateCreateWithBytes(NULL
, _AppleRootCA
, sizeof(_AppleRootCA
)),
6150 require_quiet(result
= CFArrayCreateMutable(NULL
, 3, &kCFTypeArrayCallBacks
), errOut
);
6151 CFArrayAppendValue(result
, iPhoneDeviceCA
);
6152 CFArrayAppendValue(result
, iPhoneCA
);
6153 CFArrayAppendValue(result
, appleRoot
);
6156 CFReleaseNull(iPhoneDeviceCA
);
6157 CFReleaseNull(iPhoneCA
);
6158 CFReleaseNull(appleRoot
);