2 * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecCertificate.c - CoreFoundation based certificate object
29 /* Allows us to build genanchors against the BaseSDK. */
30 #undef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
31 #undef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
34 #include <Security/SecCertificateInternal.h>
35 #include <utilities/SecIOFormat.h>
36 #include <CommonCrypto/CommonDigest.h>
37 #include <CoreFoundation/CFRuntime.h>
38 #include <CoreFoundation/CFString.h>
39 #include <CoreFoundation/CFBundle.h>
40 #include <CoreFoundation/CFDictionary.h>
41 #include <CoreFoundation/CFNumber.h>
42 #include <CoreFoundation/CFCalendar.h>
43 #include <CoreFoundation/CFTimeZone.h>
44 #include <CoreFoundation/CFXPCBridge.h>
46 #include <AssertMacros.h>
47 #include <libDER/DER_CertCrl.h>
48 #include <libDER/DER_Encode.h>
49 #include <libDER/DER_Keys.h>
50 #include <libDER/asn1Types.h>
51 #include <libDER/oids.h>
52 #include "SecBasePriv.h"
53 #include "SecRSAKey.h"
54 #include "SecFramework.h"
56 #include "SecItemPriv.h"
57 #include "SecSignatureVerificationSupport.h"
59 #include <utilities/debugging.h>
60 #include <utilities/SecCFWrappers.h>
61 #include <utilities/SecCFError.h>
62 #include <utilities/SecSCTUtils.h>
63 #include <utilities/array_size.h>
65 #include <libkern/OSByteOrder.h>
67 #include <Security/SecInternal.h>
68 #include <Security/SecFrameworkStrings.h>
69 #include "SecBase64.h"
70 #include "AppleBaselineEscrowCertificates.h"
71 #include "AppleiPhoneDeviceCACertificates.h"
72 #include <ipc/securityd_client.h>
73 #include <Security/SecKeyInternal.h>
75 #pragma clang diagnostic ignored "-Wformat=2"
77 /* The minimum key sizes necessary to not be considered "weak" */
78 #define MIN_RSA_KEY_SIZE 128 // 1024-bit
79 #define MIN_EC_KEY_SIZE 20 // 160-bit
81 /* The minimum key sizes necessary to be considered "strong" */
82 #define MIN_STRONG_RSA_KEY_SIZE 256 // 2048-bit
83 #define MIN_STRONG_EC_KEY_SIZE 28 // 224-bit
85 typedef struct SecCertificateExtension
{
89 } SecCertificateExtension
;
92 kSecSelfSignedUnknown
= 0,
97 struct __SecCertificate
{
100 DERItem _der
; /* Entire certificate in DER form. */
101 DERItem _tbs
; /* To Be Signed cert DER bytes. */
102 DERAlgorithmId _sigAlg
; /* Top level signature algorithm. */
103 DERItem _signature
; /* The content of the sig bit string. */
106 DERItem _serialNum
; /* Integer. */
107 DERAlgorithmId _tbsSigAlg
; /* sig alg MUST be same as _sigAlg. */
108 DERItem _issuer
; /* Sequence of RDN. */
109 CFAbsoluteTime _notBefore
;
110 CFAbsoluteTime _notAfter
;
111 DERItem _subject
; /* Sequence of RDN. */
112 DERItem _subjectPublicKeyInfo
; /* SPKI (without tag/length) */
113 DERAlgorithmId _algId
; /* oid and params of _pubKeyDER. */
114 DERItem _pubKeyDER
; /* contents of bit string */
115 DERItem _issuerUniqueID
; /* bit string, optional */
116 DERItem _subjectUniqueID
; /* bit string, optional */
118 bool _foundUnknownCriticalExtension
;
120 /* Well known certificate extensions. */
121 SecCEBasicConstraints _basicConstraints
;
122 SecCEPolicyConstraints _policyConstraints
;
123 SecCEPolicyMappings _policyMappings
;
124 SecCECertificatePolicies _certificatePolicies
;
125 SecCEInhibitAnyPolicy _inhibitAnyPolicySkipCerts
;
127 /* If KeyUsage extension is not present this is 0, otherwise it's
128 the value of the extension. */
129 SecKeyUsage _keyUsage
;
131 /* OCTETS of SubjectKeyIdentifier extensions KeyIdentifier.
132 Length = 0 if not present. */
133 DERItem _subjectKeyIdentifier
;
135 /* OCTETS of AuthorityKeyIdentifier extensions KeyIdentifier.
136 Length = 0 if not present. */
137 DERItem _authorityKeyIdentifier
;
138 /* AuthorityKeyIdentifier extension _authorityKeyIdentifierIssuer and
139 _authorityKeyIdentifierSerialNumber have non zero length if present.
140 Both are either present or absent together. */
141 DERItem _authorityKeyIdentifierIssuer
;
142 DERItem _authorityKeyIdentifierSerialNumber
;
144 /* Subject alt name extension, if present. Not malloced, it's just a
145 pointer to an element in the _extensions array. */
146 const SecCertificateExtension
*_subjectAltName
;
148 /* Parsed extension values. */
150 /* Array of CFURLRefs containing the URI values of crlDistributionPoints. */
151 CFMutableArrayRef _crlDistributionPoints
;
153 /* Array of CFURLRefs containing the URI values of accessLocations of each
154 id-ad-ocsp AccessDescription in the Authority Information Access
156 CFMutableArrayRef _ocspResponders
;
158 /* Array of CFURLRefs containing the URI values of accessLocations of each
159 id-ad-caIssuers AccessDescription in the Authority Information Access
161 CFMutableArrayRef _caIssuers
;
163 /* Array of CFDataRefs containing the generalNames for permittedSubtrees
165 CFArrayRef _permittedSubtrees
;
167 /* Array of CFDataRefs containing the generalNames for excludedSubtrees
169 CFArrayRef _excludedSubtrees
;
171 CFMutableArrayRef _embeddedSCTs
;
173 /* All other (non known) extensions. The _extensions array is malloced. */
174 CFIndex _extensionCount
;
175 SecCertificateExtension
*_extensions
;
177 /* Optional cached fields. */
180 CFArrayRef _properties
;
181 CFDataRef _serialNumber
;
182 CFDataRef _normalizedIssuer
;
183 CFDataRef _normalizedSubject
;
184 CFDataRef _authorityKeyID
;
185 CFDataRef _subjectKeyID
;
187 CFDataRef _sha1Digest
;
188 CFTypeRef _keychain_item
;
189 uint8_t _isSelfSigned
;
193 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
195 SEC_CONST_DECL (kSecCertificateProductionEscrowKey
, "ProductionEscrowKey");
196 SEC_CONST_DECL (kSecCertificateProductionPCSEscrowKey
, "ProductionPCSEscrowKey");
197 SEC_CONST_DECL (kSecCertificateEscrowFileName
, "AppleESCertificates");
199 /* Public Constants for property list keys. */
200 SEC_CONST_DECL (kSecPropertyKeyType
, "type");
201 SEC_CONST_DECL (kSecPropertyKeyLabel
, "label");
202 SEC_CONST_DECL (kSecPropertyKeyLocalizedLabel
, "localized label");
203 SEC_CONST_DECL (kSecPropertyKeyValue
, "value");
205 /* Public Constants for property list values. */
206 SEC_CONST_DECL (kSecPropertyTypeWarning
, "warning");
207 SEC_CONST_DECL (kSecPropertyTypeError
, "error");
208 SEC_CONST_DECL (kSecPropertyTypeSuccess
, "success");
209 SEC_CONST_DECL (kSecPropertyTypeTitle
, "title");
210 SEC_CONST_DECL (kSecPropertyTypeSection
, "section");
211 SEC_CONST_DECL (kSecPropertyTypeData
, "data");
212 SEC_CONST_DECL (kSecPropertyTypeString
, "string");
213 SEC_CONST_DECL (kSecPropertyTypeURL
, "url");
214 SEC_CONST_DECL (kSecPropertyTypeDate
, "date");
216 /* Extension parsing routine. */
217 typedef bool (*SecCertificateExtensionParser
)(SecCertificateRef certificate
,
218 const SecCertificateExtension
*extn
);
220 /* Mapping from extension OIDs (as a DERItem *) to
221 SecCertificateExtensionParser extension parsing routines. */
222 static CFDictionaryRef sExtensionParsers
;
224 /* Forward declarations of static functions. */
225 static CFStringRef
SecCertificateCopyDescription(CFTypeRef cf
);
226 static void SecCertificateDestroy(CFTypeRef cf
);
227 static bool derDateGetAbsoluteTime(const DERItem
*dateChoice
,
228 CFAbsoluteTime
*absTime
) __attribute__((__nonnull__
));
230 /* Static functions. */
231 static CFStringRef
SecCertificateCopyDescription(CFTypeRef cf
) {
232 SecCertificateRef certificate
= (SecCertificateRef
)cf
;
233 CFStringRef subject
= SecCertificateCopySubjectSummary(certificate
);
234 CFStringRef issuer
= SecCertificateCopyIssuerSummary(certificate
);
235 CFStringRef desc
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
236 CFSTR("<cert(%p) s: %@ i: %@>"), certificate
, subject
, issuer
);
237 CFReleaseSafe(issuer
);
238 CFReleaseSafe(subject
);
242 static void SecCertificateDestroy(CFTypeRef cf
) {
243 SecCertificateRef certificate
= (SecCertificateRef
)cf
;
244 if (certificate
->_certificatePolicies
.policies
) {
245 free(certificate
->_certificatePolicies
.policies
);
246 certificate
->_certificatePolicies
.policies
= NULL
;
248 if (certificate
->_policyMappings
.mappings
) {
249 free(certificate
->_policyMappings
.mappings
);
250 certificate
->_policyMappings
.mappings
= NULL
;
252 CFReleaseNull(certificate
->_crlDistributionPoints
);
253 CFReleaseNull(certificate
->_ocspResponders
);
254 CFReleaseNull(certificate
->_caIssuers
);
255 if (certificate
->_extensions
) {
256 free(certificate
->_extensions
);
257 certificate
->_extensions
= NULL
;
259 CFReleaseNull(certificate
->_pubKey
);
260 CFReleaseNull(certificate
->_der_data
);
261 CFReleaseNull(certificate
->_properties
);
262 CFReleaseNull(certificate
->_serialNumber
);
263 CFReleaseNull(certificate
->_normalizedIssuer
);
264 CFReleaseNull(certificate
->_normalizedSubject
);
265 CFReleaseNull(certificate
->_authorityKeyID
);
266 CFReleaseNull(certificate
->_subjectKeyID
);
267 CFReleaseNull(certificate
->_sha1Digest
);
268 CFReleaseNull(certificate
->_keychain_item
);
269 CFReleaseNull(certificate
->_permittedSubtrees
);
270 CFReleaseNull(certificate
->_excludedSubtrees
);
273 static Boolean
SecCertificateEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
274 SecCertificateRef cert1
= (SecCertificateRef
)cf1
;
275 SecCertificateRef cert2
= (SecCertificateRef
)cf2
;
278 if (!cert2
|| cert1
->_der
.length
!= cert2
->_der
.length
)
280 return !memcmp(cert1
->_der
.data
, cert2
->_der
.data
, cert1
->_der
.length
);
283 /* Hash of the certificate is der length + signature length + last 4 bytes
285 static CFHashCode
SecCertificateHash(CFTypeRef cf
) {
286 SecCertificateRef certificate
= (SecCertificateRef
)cf
;
287 size_t der_length
= certificate
->_der
.length
;
288 size_t sig_length
= certificate
->_signature
.length
;
289 size_t ix
= (sig_length
> 4) ? sig_length
- 4 : 0;
290 CFHashCode hashCode
= 0;
291 for (; ix
< sig_length
; ++ix
)
292 hashCode
= (hashCode
<< 8) + certificate
->_signature
.data
[ix
];
294 return (hashCode
+ der_length
+ sig_length
);
299 /************************************************************************/
300 /************************* General Name Parsing *************************/
301 /************************************************************************/
303 GeneralName ::= CHOICE {
304 otherName [0] OtherName,
305 rfc822Name [1] IA5String,
306 dNSName [2] IA5String,
307 x400Address [3] ORAddress,
308 directoryName [4] Name,
309 ediPartyName [5] EDIPartyName,
310 uniformResourceIdentifier [6] IA5String,
311 iPAddress [7] OCTET STRING,
312 registeredID [8] OBJECT IDENTIFIER}
314 OtherName ::= SEQUENCE {
315 type-id OBJECT IDENTIFIER,
316 value [0] EXPLICIT ANY DEFINED BY type-id }
318 EDIPartyName ::= SEQUENCE {
319 nameAssigner [0] DirectoryString OPTIONAL,
320 partyName [1] DirectoryString }
322 OSStatus
SecCertificateParseGeneralNameContentProperty(DERTag tag
,
323 const DERItem
*generalNameContent
,
324 void *context
, parseGeneralNameCallback callback
) {
326 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
327 return callback(context
, GNT_OtherName
, generalNameContent
);
328 case ASN1_CONTEXT_SPECIFIC
| 1:
329 return callback(context
, GNT_RFC822Name
, generalNameContent
);
330 case ASN1_CONTEXT_SPECIFIC
| 2:
331 return callback(context
, GNT_DNSName
, generalNameContent
);
332 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 3:
333 return callback(context
, GNT_X400Address
, generalNameContent
);
334 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 4:
335 return callback(context
, GNT_DirectoryName
, generalNameContent
);
336 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 5:
337 return callback(context
, GNT_EdiPartyName
, generalNameContent
);
338 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
340 /* Technically I don't think this is valid, but there are certs out
341 in the wild that use a constructed IA5String. In particular the
342 VeriSign Time Stamping Authority CA.cer does this. */
343 DERDecodedInfo uriContent
;
344 require_noerr(DERDecodeItem(generalNameContent
, &uriContent
), badDER
);
345 require(uriContent
.tag
== ASN1_IA5_STRING
, badDER
);
346 return callback(context
, GNT_URI
, &uriContent
.content
);
348 case ASN1_CONTEXT_SPECIFIC
| 6:
349 return callback(context
, GNT_URI
, generalNameContent
);
350 case ASN1_CONTEXT_SPECIFIC
| 7:
351 return callback(context
, GNT_IPAddress
, generalNameContent
);
352 case ASN1_CONTEXT_SPECIFIC
| 8:
353 return callback(context
, GNT_RegisteredID
, generalNameContent
);
358 return errSecInvalidCertificate
;
361 static OSStatus
parseGeneralNamesContent(const DERItem
*generalNamesContent
,
362 void *context
, parseGeneralNameCallback callback
) {
364 DERReturn drtn
= DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
);
365 require_noerr_quiet(drtn
, badDER
);
366 DERDecodedInfo generalNameContent
;
367 while ((drtn
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) ==
369 OSStatus status
= SecCertificateParseGeneralNameContentProperty(
370 generalNameContent
.tag
, &generalNameContent
.content
, context
,
375 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
376 return errSecSuccess
;
379 return errSecInvalidCertificate
;
382 OSStatus
SecCertificateParseGeneralNames(const DERItem
*generalNames
, void *context
,
383 parseGeneralNameCallback callback
) {
384 DERDecodedInfo generalNamesContent
;
385 DERReturn drtn
= DERDecodeItem(generalNames
, &generalNamesContent
);
386 require_noerr_quiet(drtn
, badDER
);
387 require_quiet(generalNamesContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
388 return parseGeneralNamesContent(&generalNamesContent
.content
, context
,
391 return errSecInvalidCertificate
;
397 GeneralName ::= CHOICE {
398 otherName [0] OtherName,
399 rfc822Name [1] IA5String,
400 dNSName [2] IA5String,
401 x400Address [3] ORAddress,
402 directoryName [4] Name,
403 ediPartyName [5] EDIPartyName,
404 uniformResourceIdentifier [6] IA5String,
405 iPAddress [7] OCTET STRING,
406 registeredID [8] OBJECT IDENTIFIER}
408 EDIPartyName ::= SEQUENCE {
409 nameAssigner [0] DirectoryString OPTIONAL,
410 partyName [1] DirectoryString }
412 static OSStatus
parseGeneralNameContentProperty(DERTag tag
,
413 const DERItem
*generalNameContent
, SecCEGeneralName
*generalName
) {
415 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
416 generalName
->nameType
= GNT_OtherName
;
417 generalName
->berEncoded
= true;
418 generalName
->name
= *generalNameContent
;
420 case ASN1_CONTEXT_SPECIFIC
| 1:
422 generalName
->nameType
= GNT_RFC822Name
;
423 generalName
->berEncoded
= false;
424 generalName
->name
= *generalNameContent
;
426 case ASN1_CONTEXT_SPECIFIC
| 2:
428 generalName
->nameType
= GNT_DNSName
;
429 generalName
->berEncoded
= false;
430 generalName
->name
= *generalNameContent
;
432 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 3:
433 generalName
->nameType
= GNT_X400Address
;
434 generalName
->berEncoded
= true;
435 generalName
->name
= *generalNameContent
;
437 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 4:
438 generalName
->nameType
= GNT_DirectoryName
;
439 generalName
->berEncoded
= true;
440 generalName
->name
= *generalNameContent
;
442 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 5:
443 generalName
->nameType
= GNT_EdiPartyName
;
444 generalName
->berEncoded
= true;
445 generalName
->name
= *generalNameContent
;
447 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
449 /* Technically I don't think this is valid, but there are certs out
450 in the wild that use a constructed IA5String. In particular the
451 VeriSign Time Stamping Authority CA.cer does this. */
452 DERDecodedInfo decoded
;
453 require_noerr(DERDecodeItem(generalNameContent
, &decoded
), badDER
);
454 require(decoded
.tag
== ASN1_IA5_STRING
, badDER
);
455 generalName
->nameType
= GNT_URI
;
456 generalName
->berEncoded
= false;
457 generalName
->name
= decoded
.content
;
460 case ASN1_CONTEXT_SPECIFIC
| 6:
461 generalName
->nameType
= GNT_URI
;
462 generalName
->berEncoded
= false;
463 generalName
->name
= *generalNameContent
;
465 case ASN1_CONTEXT_SPECIFIC
| 7:
466 /* @@@ This is the IP Address as an OCTECT STRING. For IPv4 it's
467 8 octects, addr/mask for ipv6 it's 32. */
468 generalName
->nameType
= GNT_IPAddress
;
469 generalName
->berEncoded
= false;
470 generalName
->name
= *generalNameContent
;
472 case ASN1_CONTEXT_SPECIFIC
| 8:
473 /* name is the content of an OID. */
474 generalName
->nameType
= GNT_RegisteredID
;
475 generalName
->berEncoded
= false;
476 generalName
->name
= *generalNameContent
;
482 return errSecSuccess
;
484 return errSecInvalidCertificate
;
488 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
490 static OSStatus
parseGeneralNamesContent(const DERItem
*generalNamesContent
,
491 CFIndex
*count
, SecCEGeneralName
**name
) {
492 SecCEGeneralName
*generalNames
= NULL
;
494 DERReturn drtn
= DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
);
495 require_noerr_quiet(drtn
, badDER
);
496 DERDecodedInfo generalNameContent
;
497 CFIndex generalNamesCount
= 0;
498 while ((drtn
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) ==
502 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
504 require(generalNames
= calloc(generalNamesCount
, sizeof(SecCEGeneralName
)),
506 DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
);
508 while ((drtn
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) ==
510 if (!parseGeneralNameContentProperty(generalNameContent
.tag
,
511 &generalNameContent
.content
, &generalNames
[ix
])) {
516 *count
= generalNamesCount
;
517 *name
= generalNames
;
518 return errSecSuccess
;
523 return errSecInvalidCertificate
;
526 static OSStatus
parseGeneralNames(const DERItem
*generalNames
,
527 CFIndex
*count
, SecCEGeneralName
**name
) {
528 DERDecodedInfo generalNamesContent
;
529 DERReturn drtn
= DERDecodeItem(generalNames
, &generalNamesContent
);
530 require_noerr_quiet(drtn
, badDER
);
531 require_quiet(generalNamesContent
.tag
== ASN1_CONSTR_SEQUENCE
,
533 parseGeneralNamesContent(&generalNamesContent
.content
, count
, name
);
534 return errSecSuccess
;
536 return errSecInvalidCertificate
;
540 /************************************************************************/
541 /************************** X.509 Name Parsing **************************/
542 /************************************************************************/
544 typedef OSStatus (*parseX501NameCallback
)(void *context
, const DERItem
*type
,
545 const DERItem
*value
, CFIndex rdnIX
, bool localized
);
547 static OSStatus
parseRDNContent(const DERItem
*rdnSetContent
, void *context
,
548 parseX501NameCallback callback
, bool localized
) {
550 DERReturn drtn
= DERDecodeSeqContentInit(rdnSetContent
, &rdn
);
551 require_noerr_quiet(drtn
, badDER
);
552 DERDecodedInfo atvContent
;
554 while ((drtn
= DERDecodeSeqNext(&rdn
, &atvContent
)) == DR_Success
) {
555 require_quiet(atvContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
556 DERAttributeTypeAndValue atv
;
557 drtn
= DERParseSequenceContent(&atvContent
.content
,
558 DERNumAttributeTypeAndValueItemSpecs
,
559 DERAttributeTypeAndValueItemSpecs
,
561 require_noerr_quiet(drtn
, badDER
);
562 require_quiet(atv
.type
.length
!= 0, badDER
);
563 OSStatus status
= callback(context
, &atv
.type
, &atv
.value
, rdnIX
++, localized
);
568 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
570 return errSecSuccess
;
572 return errSecInvalidCertificate
;
575 static OSStatus
parseX501NameContent(const DERItem
*x501NameContent
, void *context
,
576 parseX501NameCallback callback
, bool localized
) {
578 DERReturn drtn
= DERDecodeSeqContentInit(x501NameContent
, &derSeq
);
579 require_noerr_quiet(drtn
, badDER
);
580 DERDecodedInfo currDecoded
;
581 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
582 require_quiet(currDecoded
.tag
== ASN1_CONSTR_SET
, badDER
);
583 OSStatus status
= parseRDNContent(&currDecoded
.content
, context
,
584 callback
, localized
);
589 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
591 return errSecSuccess
;
594 return errSecInvalidCertificate
;
597 static OSStatus
parseX501Name(const DERItem
*x501Name
, void *context
,
598 parseX501NameCallback callback
, bool localized
) {
599 DERDecodedInfo x501NameContent
;
600 if (DERDecodeItem(x501Name
, &x501NameContent
) ||
601 x501NameContent
.tag
!= ASN1_CONSTR_SEQUENCE
) {
602 return errSecInvalidCertificate
;
604 return parseX501NameContent(&x501NameContent
.content
, context
,
605 callback
, localized
);
609 /************************************************************************/
610 /********************** Extension Parsing Routines **********************/
611 /************************************************************************/
613 static bool SecCEPSubjectKeyIdentifier(SecCertificateRef certificate
,
614 const SecCertificateExtension
*extn
) {
615 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
616 DERDecodedInfo keyIdentifier
;
617 DERReturn drtn
= DERDecodeItem(&extn
->extnValue
, &keyIdentifier
);
618 require_noerr_quiet(drtn
, badDER
);
619 require_quiet(keyIdentifier
.tag
== ASN1_OCTET_STRING
, badDER
);
620 certificate
->_subjectKeyIdentifier
= keyIdentifier
.content
;
624 secwarning("Invalid SubjectKeyIdentifier Extension");
628 static bool SecCEPKeyUsage(SecCertificateRef certificate
,
629 const SecCertificateExtension
*extn
) {
630 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
631 SecKeyUsage keyUsage
= extn
->critical
? kSecKeyUsageCritical
: 0;
632 DERDecodedInfo bitStringContent
;
633 DERReturn drtn
= DERDecodeItem(&extn
->extnValue
, &bitStringContent
);
634 require_noerr_quiet(drtn
, badDER
);
635 require_quiet(bitStringContent
.tag
== ASN1_BIT_STRING
, badDER
);
636 DERSize len
= bitStringContent
.content
.length
- 1;
637 require_quiet(len
== 1 || len
== 2, badDER
);
638 DERByte numUnusedBits
= bitStringContent
.content
.data
[0];
639 require_quiet(numUnusedBits
< 8, badDER
);
640 /* Flip the bits in the bit string so the first bit in the lsb. */
641 uint_fast16_t bits
= 8 * len
- numUnusedBits
;
642 uint_fast16_t value
= bitStringContent
.content
.data
[1];
645 value
= (value
<< 8) + bitStringContent
.content
.data
[2];
651 for (ix
= 0; ix
< bits
; ++ix
) {
657 certificate
->_keyUsage
= keyUsage
;
660 certificate
->_keyUsage
= kSecKeyUsageUnspecified
;
661 secwarning("Invalid KeyUsage Extension");
665 static bool SecCEPPrivateKeyUsagePeriod(SecCertificateRef certificate
,
666 const SecCertificateExtension
*extn
) {
667 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
671 static bool SecCEPSubjectAltName(SecCertificateRef certificate
,
672 const SecCertificateExtension
*extn
) {
673 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
674 certificate
->_subjectAltName
= extn
;
678 static bool SecCEPIssuerAltName(SecCertificateRef certificate
,
679 const SecCertificateExtension
*extn
) {
680 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
684 static bool SecCEPBasicConstraints(SecCertificateRef certificate
,
685 const SecCertificateExtension
*extn
) {
686 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
687 DERBasicConstraints basicConstraints
;
688 require_noerr_quiet(DERParseSequence(&extn
->extnValue
,
689 DERNumBasicConstraintsItemSpecs
, DERBasicConstraintsItemSpecs
,
690 &basicConstraints
, sizeof(basicConstraints
)), badDER
);
691 require_noerr_quiet(DERParseBooleanWithDefault(&basicConstraints
.cA
, false,
692 &certificate
->_basicConstraints
.isCA
), badDER
);
693 if (basicConstraints
.pathLenConstraint
.length
!= 0) {
694 require_noerr_quiet(DERParseInteger(
695 &basicConstraints
.pathLenConstraint
,
696 &certificate
->_basicConstraints
.pathLenConstraint
), badDER
);
697 certificate
->_basicConstraints
.pathLenConstraintPresent
= true;
699 certificate
->_basicConstraints
.present
= true;
700 certificate
->_basicConstraints
.critical
= extn
->critical
;
703 certificate
->_basicConstraints
.present
= false;
704 secwarning("Invalid BasicConstraints Extension");
710 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
712 * NameConstraints ::= SEQUENCE {
713 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
714 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
716 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
718 * GeneralSubtree ::= SEQUENCE {
720 * minimum [0] BaseDistance DEFAULT 0,
721 * maximum [1] BaseDistance OPTIONAL }
723 * BaseDistance ::= INTEGER (0..MAX)
725 static DERReturn
parseGeneralSubtrees(DERItem
*derSubtrees
, CFArrayRef
*generalSubtrees
) {
726 CFMutableArrayRef gs
= NULL
;
728 DERReturn drtn
= DERDecodeSeqContentInit(derSubtrees
, &gsSeq
);
729 require_noerr_quiet(drtn
, badDER
);
730 DERDecodedInfo gsContent
;
731 require_quiet(gs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
732 &kCFTypeArrayCallBacks
),
734 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
735 DERGeneralSubtree derGS
;
736 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
737 drtn
= DERParseSequenceContent(&gsContent
.content
,
738 DERNumGeneralSubtreeItemSpecs
,
739 DERGeneralSubtreeItemSpecs
,
740 &derGS
, sizeof(derGS
));
741 require_noerr_quiet(drtn
, badDER
);
744 * Within this profile, the minimum and maximum fields are not used with
745 * any name forms, thus, the minimum MUST be zero, and maximum MUST be
748 * Because minimum DEFAULT 0, absence equivalent to present and 0.
750 if (derGS
.minimum
.length
) {
752 require_noerr_quiet(DERParseInteger(&derGS
.minimum
, &minimum
),
754 require_quiet(minimum
== 0, badDER
);
756 require_quiet(derGS
.maximum
.length
== 0, badDER
);
757 require_quiet(derGS
.generalName
.length
!= 0, badDER
);
759 CFDataRef generalName
= NULL
;
760 require_quiet(generalName
= CFDataCreate(kCFAllocatorDefault
,
761 derGS
.generalName
.data
,
762 derGS
.generalName
.length
),
764 CFArrayAppendValue(gs
, generalName
);
765 CFReleaseNull(generalName
);
767 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
769 // since generalSubtrees is a pointer to an instance variable,
770 // make sure we release the existing array before assignment.
771 CFReleaseSafe(*generalSubtrees
);
772 *generalSubtrees
= gs
;
778 secdebug("cert","failed to parse GeneralSubtrees");
782 static bool SecCEPNameConstraints(SecCertificateRef certificate
,
783 const SecCertificateExtension
*extn
) {
784 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
785 DERNameConstraints nc
;
787 drtn
= DERParseSequence(&extn
->extnValue
,
788 DERNumNameConstraintsItemSpecs
,
789 DERNameConstraintsItemSpecs
,
791 require_noerr_quiet(drtn
, badDER
);
792 if (nc
.permittedSubtrees
.length
) {
793 require_noerr_quiet(parseGeneralSubtrees(&nc
.permittedSubtrees
, &certificate
->_permittedSubtrees
), badDER
);
795 if (nc
.excludedSubtrees
.length
) {
796 require_noerr_quiet(parseGeneralSubtrees(&nc
.excludedSubtrees
, &certificate
->_excludedSubtrees
), badDER
);
801 secwarning("Invalid Name Constraints extension");
805 static OSStatus
appendCRLDPFromGeneralNames(void *context
, SecCEGeneralNameType type
,
806 const DERItem
*value
) {
807 CFMutableArrayRef
*crlDPs
= (CFMutableArrayRef
*)context
;
808 if (type
== GNT_URI
) {
810 url
= CFURLCreateWithBytes(NULL
, value
->data
, value
->length
, kCFStringEncodingASCII
, NULL
);
813 *crlDPs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
815 CFArrayAppendValue(*crlDPs
, url
);
819 return errSecSuccess
;
823 id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 }
825 CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
827 DistributionPoint ::= SEQUENCE {
828 distributionPoint [0] DistributionPointName OPTIONAL,
829 reasons [1] ReasonFlags OPTIONAL,
830 cRLIssuer [2] GeneralNames OPTIONAL }
832 DistributionPointName ::= CHOICE {
833 fullName [0] GeneralNames,
834 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
836 static bool SecCEPCrlDistributionPoints(SecCertificateRef certificate
,
837 const SecCertificateExtension
*extn
) {
838 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
839 DERSequence crlDPSeq
;
841 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &crlDPSeq
);
842 require_noerr_quiet(drtn
, badDER
);
843 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
844 DERDecodedInfo dpContent
;
845 while ((drtn
= DERDecodeSeqNext(&crlDPSeq
, &dpContent
)) == DR_Success
) {
846 require_quiet(dpContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
847 DERDistributionPoint dp
;
848 drtn
= DERParseSequenceContent(&dpContent
.content
, DERNumDistributionPointItemSpecs
,
849 DERDistributionPointItemSpecs
, &dp
, sizeof(dp
));
850 require_noerr_quiet(drtn
, badDER
);
851 require_quiet(dp
.distributionPoint
.data
|| dp
.cRLIssuer
.data
, badDER
);
852 if (dp
.distributionPoint
.data
) {
853 DERDecodedInfo dpName
;
854 drtn
= DERDecodeItem(&dp
.distributionPoint
, &dpName
);
855 require_noerr_quiet(drtn
, badDER
);
856 switch (dpName
.tag
) {
857 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
858 drtn
= parseGeneralNamesContent(&dpName
.content
, &certificate
->_crlDistributionPoints
,
859 appendCRLDPFromGeneralNames
);
860 require_noerr_quiet(drtn
, badDER
);
862 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1:
863 /* RelativeDistinguishName. Nothing we can do with that. */
869 if (dp
.cRLIssuer
.data
) {
870 drtn
= SecCertificateParseGeneralNames(&dp
.cRLIssuer
, &certificate
->_crlDistributionPoints
,
871 appendCRLDPFromGeneralNames
);
872 require_noerr_quiet(drtn
, badDER
);
875 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
878 secwarning("Invalid CRL Distribution Points extension");
883 certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
885 PolicyInformation ::= SEQUENCE {
886 policyIdentifier CertPolicyId,
887 policyQualifiers SEQUENCE SIZE (1..MAX) OF
888 PolicyQualifierInfo OPTIONAL }
890 CertPolicyId ::= OBJECT IDENTIFIER
892 PolicyQualifierInfo ::= SEQUENCE {
893 policyQualifierId PolicyQualifierId,
894 qualifier ANY DEFINED BY policyQualifierId }
896 /* maximum number of policies of 8192 seems more than adequate */
897 #define MAX_CERTIFICATE_POLICIES 8192
898 static bool SecCEPCertificatePolicies(SecCertificateRef certificate
,
899 const SecCertificateExtension
*extn
) {
900 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
903 SecCEPolicyInformation
*policies
= NULL
;
904 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &piSeq
);
905 require_noerr_quiet(drtn
, badDER
);
906 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
907 DERDecodedInfo piContent
;
908 DERSize policy_count
= 0;
909 while ((policy_count
< MAX_CERTIFICATE_POLICIES
) &&
910 (drtn
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) {
911 require_quiet(piContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
914 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
915 require_quiet(policies
= (SecCEPolicyInformation
*)malloc(sizeof(SecCEPolicyInformation
)
916 * (policy_count
> 0 ? policy_count
: 1)),
918 drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &piSeq
);
919 require_noerr_quiet(drtn
, badDER
);
920 DERSize policy_ix
= 0;
921 while ((policy_ix
< (policy_count
> 0 ? policy_count
: 1)) &&
922 (drtn
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) {
923 DERPolicyInformation pi
;
924 drtn
= DERParseSequenceContent(&piContent
.content
,
925 DERNumPolicyInformationItemSpecs
,
926 DERPolicyInformationItemSpecs
,
928 require_noerr_quiet(drtn
, badDER
);
929 policies
[policy_ix
].policyIdentifier
= pi
.policyIdentifier
;
930 policies
[policy_ix
++].policyQualifiers
= pi
.policyQualifiers
;
932 certificate
->_certificatePolicies
.present
= true;
933 certificate
->_certificatePolicies
.critical
= extn
->critical
;
934 certificate
->_certificatePolicies
.numPolicies
= policy_count
;
935 certificate
->_certificatePolicies
.policies
= policies
;
940 certificate
->_certificatePolicies
.present
= false;
941 secwarning("Invalid CertificatePolicies Extension");
946 id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 }
948 PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
949 issuerDomainPolicy CertPolicyId,
950 subjectDomainPolicy CertPolicyId }
952 #define MAX_POLICY_MAPPINGS 8192
953 static bool SecCEPPolicyMappings(SecCertificateRef certificate
,
954 const SecCertificateExtension
*extn
) {
955 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
958 SecCEPolicyMapping
*mappings
= NULL
;
959 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &pmSeq
);
960 require_noerr_quiet(drtn
, badDER
);
961 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
962 DERDecodedInfo pmContent
;
963 DERSize mapping_count
= 0;
964 while ((mapping_count
< MAX_POLICY_MAPPINGS
) &&
965 (drtn
= DERDecodeSeqNext(&pmSeq
, &pmContent
)) == DR_Success
) {
966 require_quiet(pmContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
969 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
970 require_quiet(mappings
= (SecCEPolicyMapping
*)malloc(sizeof(SecCEPolicyMapping
)
971 * (mapping_count
> 0 ? mapping_count
: 1)),
973 drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &pmSeq
);
974 require_noerr_quiet(drtn
, badDER
);
975 DERSize mapping_ix
= 0;
976 while ((mapping_ix
< (mapping_count
> 0 ? mapping_count
: 1)) &&
977 (drtn
= DERDecodeSeqNext(&pmSeq
, &pmContent
)) == DR_Success
) {
978 require_quiet(pmContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
980 drtn
= DERParseSequenceContent(&pmContent
.content
,
981 DERNumPolicyMappingItemSpecs
,
982 DERPolicyMappingItemSpecs
,
984 require_noerr_quiet(drtn
, badDER
);
985 mappings
[mapping_ix
].issuerDomainPolicy
= pm
.issuerDomainPolicy
;
986 mappings
[mapping_ix
++].subjectDomainPolicy
= pm
.subjectDomainPolicy
;
988 certificate
->_policyMappings
.present
= true;
989 certificate
->_policyMappings
.critical
= extn
->critical
;
990 certificate
->_policyMappings
.numMappings
= mapping_count
;
991 certificate
->_policyMappings
.mappings
= mappings
;
997 certificate
->_policyMappings
.present
= false;
998 secwarning("Invalid CertificatePolicies Extension");
1003 AuthorityKeyIdentifier ::= SEQUENCE {
1004 keyIdentifier [0] KeyIdentifier OPTIONAL,
1005 authorityCertIssuer [1] GeneralNames OPTIONAL,
1006 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
1007 -- authorityCertIssuer and authorityCertSerialNumber MUST both
1008 -- be present or both be absent
1010 KeyIdentifier ::= OCTET STRING
1012 static bool SecCEPAuthorityKeyIdentifier(SecCertificateRef certificate
,
1013 const SecCertificateExtension
*extn
) {
1014 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1015 DERAuthorityKeyIdentifier akid
;
1017 drtn
= DERParseSequence(&extn
->extnValue
,
1018 DERNumAuthorityKeyIdentifierItemSpecs
,
1019 DERAuthorityKeyIdentifierItemSpecs
,
1020 &akid
, sizeof(akid
));
1021 require_noerr_quiet(drtn
, badDER
);
1022 if (akid
.keyIdentifier
.length
) {
1023 certificate
->_authorityKeyIdentifier
= akid
.keyIdentifier
;
1025 if (akid
.authorityCertIssuer
.length
||
1026 akid
.authorityCertSerialNumber
.length
) {
1027 require_quiet(akid
.authorityCertIssuer
.length
&&
1028 akid
.authorityCertSerialNumber
.length
, badDER
);
1029 /* Perhaps put in a subsection called Authority Certificate Issuer. */
1030 certificate
->_authorityKeyIdentifierIssuer
= akid
.authorityCertIssuer
;
1031 certificate
->_authorityKeyIdentifierSerialNumber
= akid
.authorityCertSerialNumber
;
1036 secwarning("Invalid AuthorityKeyIdentifier Extension");
1040 static bool SecCEPPolicyConstraints(SecCertificateRef certificate
,
1041 const SecCertificateExtension
*extn
) {
1042 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1043 DERPolicyConstraints pc
;
1045 drtn
= DERParseSequence(&extn
->extnValue
,
1046 DERNumPolicyConstraintsItemSpecs
,
1047 DERPolicyConstraintsItemSpecs
,
1049 require_noerr_quiet(drtn
, badDER
);
1050 if (pc
.requireExplicitPolicy
.length
) {
1051 require_noerr_quiet(DERParseInteger(
1052 &pc
.requireExplicitPolicy
,
1053 &certificate
->_policyConstraints
.requireExplicitPolicy
), badDER
);
1054 certificate
->_policyConstraints
.requireExplicitPolicyPresent
= true;
1056 if (pc
.inhibitPolicyMapping
.length
) {
1057 require_noerr_quiet(DERParseInteger(
1058 &pc
.inhibitPolicyMapping
,
1059 &certificate
->_policyConstraints
.inhibitPolicyMapping
), badDER
);
1060 certificate
->_policyConstraints
.inhibitPolicyMappingPresent
= true;
1063 certificate
->_policyConstraints
.present
= true;
1064 certificate
->_policyConstraints
.critical
= extn
->critical
;
1068 certificate
->_policyConstraints
.present
= false;
1069 secwarning("Invalid PolicyConstraints Extension");
1073 static bool SecCEPExtendedKeyUsage(SecCertificateRef certificate
,
1074 const SecCertificateExtension
*extn
) {
1075 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1080 InhibitAnyPolicy ::= SkipCerts
1082 SkipCerts ::= INTEGER (0..MAX)
1084 static bool SecCEPInhibitAnyPolicy(SecCertificateRef certificate
,
1085 const SecCertificateExtension
*extn
) {
1086 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1087 DERDecodedInfo iapContent
;
1088 require_noerr_quiet(DERDecodeItem(&extn
->extnValue
, &iapContent
), badDER
);
1089 require_quiet(iapContent
.tag
== ASN1_INTEGER
, badDER
);
1090 require_noerr_quiet(DERParseInteger(
1091 &iapContent
.content
,
1092 &certificate
->_inhibitAnyPolicySkipCerts
.skipCerts
), badDER
);
1094 certificate
->_inhibitAnyPolicySkipCerts
.present
= true;
1095 certificate
->_inhibitAnyPolicySkipCerts
.critical
= extn
->critical
;
1098 certificate
->_inhibitAnyPolicySkipCerts
.present
= false;
1099 secwarning("Invalid InhibitAnyPolicy Extension");
1104 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
1106 AuthorityInfoAccessSyntax ::=
1107 SEQUENCE SIZE (1..MAX) OF AccessDescription
1109 AccessDescription ::= SEQUENCE {
1110 accessMethod OBJECT IDENTIFIER,
1111 accessLocation GeneralName }
1113 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
1115 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
1117 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
1119 static bool SecCEPAuthorityInfoAccess(SecCertificateRef certificate
,
1120 const SecCertificateExtension
*extn
) {
1121 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1124 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &adSeq
);
1125 require_noerr_quiet(drtn
, badDER
);
1126 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1127 DERDecodedInfo adContent
;
1128 while ((drtn
= DERDecodeSeqNext(&adSeq
, &adContent
)) == DR_Success
) {
1129 require_quiet(adContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1130 DERAccessDescription ad
;
1131 drtn
= DERParseSequenceContent(&adContent
.content
,
1132 DERNumAccessDescriptionItemSpecs
,
1133 DERAccessDescriptionItemSpecs
,
1135 require_noerr_quiet(drtn
, badDER
);
1136 CFMutableArrayRef
*urls
;
1137 if (DEROidCompare(&ad
.accessMethod
, &oidAdOCSP
))
1138 urls
= &certificate
->_ocspResponders
;
1139 else if (DEROidCompare(&ad
.accessMethod
, &oidAdCAIssuer
))
1140 urls
= &certificate
->_caIssuers
;
1144 DERDecodedInfo generalNameContent
;
1145 drtn
= DERDecodeItem(&ad
.accessLocation
, &generalNameContent
);
1146 require_noerr_quiet(drtn
, badDER
);
1147 switch (generalNameContent
.tag
) {
1149 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
1150 /* Technically I don't think this is valid, but there are certs out
1151 in the wild that use a constructed IA5String. In particular the
1152 VeriSign Time Stamping Authority CA.cer does this. */
1154 case ASN1_CONTEXT_SPECIFIC
| 6:
1156 CFURLRef url
= CFURLCreateWithBytes(kCFAllocatorDefault
,
1157 generalNameContent
.content
.data
, generalNameContent
.content
.length
,
1158 kCFStringEncodingASCII
, NULL
);
1161 *urls
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1162 CFArrayAppendValue(*urls
, url
);
1168 secdebug("cert", "bad general name for id-ad-ocsp AccessDescription t: 0x%02llx v: %.*s",
1169 generalNameContent
.tag
, (int) generalNameContent
.content
.length
, generalNameContent
.content
.data
);
1174 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
1177 secwarning("Invalid Authority Information Access extension");
1181 /* Apple Worldwide Developer Relations Certificate Authority subject name.
1182 * This is a DER sequence with the leading tag and length bytes removed,
1183 * to match what tbsCert.issuer contains.
1185 static const unsigned char Apple_WWDR_CA_Subject_Name
[]={
1186 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
1187 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
1188 0x20,0x49,0x6E,0x63,0x2E,0x31,0x2C,0x30,0x2A,0x06,0x03,0x55,0x04,0x0B,0x0C,0x23,
1189 0x41,0x70,0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20,
1190 0x44,0x65,0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,
1191 0x6F,0x6E,0x73,0x31,0x44,0x30,0x42,0x06,0x03,0x55,0x04,0x03,0x0C,0x3B,0x41,0x70,
1192 0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20,0x44,0x65,
1193 0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,0x6F,0x6E,
1194 0x73,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,
1195 0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79
1198 static void checkForMissingRevocationInfo(SecCertificateRef certificate
) {
1200 certificate
->_crlDistributionPoints
||
1201 certificate
->_ocspResponders
) {
1202 /* We already have an OCSP or CRL URI (or no cert) */
1205 /* Specify an appropriate OCSP responder if we recognize the issuer. */
1206 CFURLRef url
= NULL
;
1207 if (sizeof(Apple_WWDR_CA_Subject_Name
) == certificate
->_issuer
.length
&&
1208 !memcmp(certificate
->_issuer
.data
, Apple_WWDR_CA_Subject_Name
,
1209 sizeof(Apple_WWDR_CA_Subject_Name
))) {
1210 const char *WWDR_OCSP_URI
= "http://ocsp.apple.com/ocsp-wwdr01";
1211 url
= CFURLCreateWithBytes(kCFAllocatorDefault
,
1212 (const UInt8
*)WWDR_OCSP_URI
, strlen(WWDR_OCSP_URI
),
1213 kCFStringEncodingASCII
, NULL
);
1216 CFMutableArrayRef
*urls
= &certificate
->_ocspResponders
;
1217 *urls
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1218 CFArrayAppendValue(*urls
, url
);
1223 static bool SecCEPSubjectInfoAccess(SecCertificateRef certificate
,
1224 const SecCertificateExtension
*extn
) {
1225 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1229 static bool SecCEPNetscapeCertType(SecCertificateRef certificate
,
1230 const SecCertificateExtension
*extn
) {
1231 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1235 static bool SecCEPEntrustVersInfo(SecCertificateRef certificate
,
1236 const SecCertificateExtension
*extn
) {
1237 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1241 static bool SecCEPEscrowMarker(SecCertificateRef certificate
,
1242 const SecCertificateExtension
*extn
) {
1243 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1247 static bool SecCEPOCSPNoCheck(SecCertificateRef certificate
,
1248 const SecCertificateExtension
*extn
) {
1249 secdebug("cert", "ocsp-nocheck critical: %s", extn
->critical
? "yes" : "no");
1253 /* Dictionary key callback for comparing to DERItems. */
1254 static Boolean
SecDERItemEqual(const void *value1
, const void *value2
) {
1255 return DEROidCompare((const DERItem
*)value1
, (const DERItem
*)value2
);
1258 /* Dictionary key callback calculating the hash of a DERItem. */
1259 static CFHashCode
SecDERItemHash(const void *value
) {
1260 const DERItem
*derItem
= (const DERItem
*)value
;
1261 CFHashCode hash
= derItem
->length
;
1262 DERSize ix
= derItem
->length
> 8 ? derItem
->length
- 8 : 0;
1263 for (; ix
< derItem
->length
; ++ix
) {
1264 hash
= (hash
<< 9) + (hash
>> 23) + derItem
->data
[ix
];
1270 /* Dictionary key callbacks using the above 2 functions. */
1271 static const CFDictionaryKeyCallBacks SecDERItemKeyCallBacks
= {
1275 NULL
, /* copyDescription */
1276 SecDERItemEqual
, /* equal */
1277 SecDERItemHash
/* hash */
1280 static void SecCertificateInitializeExtensionParsers(void) {
1281 /* Build a dictionary that maps from extension OIDs to callback functions
1282 which can parse the extension of the type given. */
1283 static const void *extnOIDs
[] = {
1284 &oidSubjectKeyIdentifier
,
1286 &oidPrivateKeyUsagePeriod
,
1289 &oidBasicConstraints
,
1290 &oidNameConstraints
,
1291 &oidCrlDistributionPoints
,
1292 &oidCertificatePolicies
,
1294 &oidAuthorityKeyIdentifier
,
1295 &oidPolicyConstraints
,
1296 &oidExtendedKeyUsage
,
1297 &oidInhibitAnyPolicy
,
1298 &oidAuthorityInfoAccess
,
1299 &oidSubjectInfoAccess
,
1300 &oidNetscapeCertType
,
1301 &oidEntrustVersInfo
,
1302 &oidApplePolicyEscrowService
,
1305 static const void *extnParsers
[] = {
1306 SecCEPSubjectKeyIdentifier
,
1308 SecCEPPrivateKeyUsagePeriod
,
1309 SecCEPSubjectAltName
,
1310 SecCEPIssuerAltName
,
1311 SecCEPBasicConstraints
,
1312 SecCEPNameConstraints
,
1313 SecCEPCrlDistributionPoints
,
1314 SecCEPCertificatePolicies
,
1315 SecCEPPolicyMappings
,
1316 SecCEPAuthorityKeyIdentifier
,
1317 SecCEPPolicyConstraints
,
1318 SecCEPExtendedKeyUsage
,
1319 SecCEPInhibitAnyPolicy
,
1320 SecCEPAuthorityInfoAccess
,
1321 SecCEPSubjectInfoAccess
,
1322 SecCEPNetscapeCertType
,
1323 SecCEPEntrustVersInfo
,
1327 sExtensionParsers
= CFDictionaryCreate(kCFAllocatorDefault
, extnOIDs
,
1328 extnParsers
, array_size(extnOIDs
),
1329 &SecDERItemKeyCallBacks
, NULL
);
1332 CFGiblisWithFunctions(SecCertificate
, NULL
, NULL
, SecCertificateDestroy
, SecCertificateEqual
, SecCertificateHash
, NULL
, SecCertificateCopyDescription
, NULL
, NULL
, ^{
1333 SecCertificateInitializeExtensionParsers();
1336 static bool isAppleExtensionOID(const DERItem
*extnID
)
1338 static const uint8_t appleExtension
[8] = { 0x2a,0x86,0x48,0x86,0xf7,0x63,0x64,0x06 };
1339 return (extnID
&& extnID
->data
&&
1340 extnID
->length
> sizeof(appleExtension
) &&
1341 !memcmp(extnID
->data
, appleExtension
, sizeof(appleExtension
)));
1344 /* Given the contents of an X.501 Name return the contents of a normalized
1346 CFDataRef
createNormalizedX501Name(CFAllocatorRef allocator
,
1347 const DERItem
*x501name
) {
1348 CFMutableDataRef result
= CFDataCreateMutable(allocator
, x501name
->length
);
1349 CFIndex length
= x501name
->length
;
1350 CFDataSetLength(result
, length
);
1351 UInt8
*base
= CFDataGetMutableBytePtr(result
);
1354 DERReturn drtn
= DERDecodeSeqContentInit(x501name
, &rdnSeq
);
1356 require_noerr_quiet(drtn
, badDER
);
1359 /* Always points to last rdn tag. */
1360 const DERByte
*rdnTag
= rdnSeq
.nextItem
;
1361 /* Offset relative to base of current rdn set tag. */
1362 CFIndex rdnTagLocation
= 0;
1363 while ((drtn
= DERDecodeSeqNext(&rdnSeq
, &rdn
)) == DR_Success
) {
1364 require_quiet(rdn
.tag
== ASN1_CONSTR_SET
, badDER
);
1365 /* We don't allow empty RDNs. */
1366 require_quiet(rdn
.content
.length
!= 0, badDER
);
1367 /* Length of the tag and length of the current rdn. */
1368 CFIndex rdnTLLength
= rdn
.content
.data
- rdnTag
;
1369 CFIndex rdnContentLength
= rdn
.content
.length
;
1370 /* Copy the tag and length of the RDN. */
1371 memcpy(base
+ rdnTagLocation
, rdnTag
, rdnTLLength
);
1374 drtn
= DERDecodeSeqContentInit(&rdn
.content
, &atvSeq
);
1375 require_quiet(drtn
== DR_Success
, badDER
);
1378 /* Always points to tag of current atv sequence. */
1379 const DERByte
*atvTag
= atvSeq
.nextItem
;
1380 /* Offset relative to base of current atv sequence tag. */
1381 CFIndex atvTagLocation
= rdnTagLocation
+ rdnTLLength
;
1382 while ((drtn
= DERDecodeSeqNext(&atvSeq
, &atv
)) == DR_Success
) {
1383 require_quiet(atv
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1384 /* Length of the tag and length of the current atv. */
1385 CFIndex atvTLLength
= atv
.content
.data
- atvTag
;
1386 CFIndex atvContentLength
= atv
.content
.length
;
1387 /* Copy the tag and length of the atv and the atv itself. */
1388 memcpy(base
+ atvTagLocation
, atvTag
,
1389 atvTLLength
+ atv
.content
.length
);
1391 /* Now decode the atv sequence. */
1392 DERAttributeTypeAndValue atvPair
;
1393 drtn
= DERParseSequenceContent(&atv
.content
,
1394 DERNumAttributeTypeAndValueItemSpecs
,
1395 DERAttributeTypeAndValueItemSpecs
,
1396 &atvPair
, sizeof(atvPair
));
1397 require_noerr_quiet(drtn
, badDER
);
1398 require_quiet(atvPair
.type
.length
!= 0, badDER
);
1399 DERDecodedInfo value
;
1400 drtn
= DERDecodeItem(&atvPair
.value
, &value
);
1401 require_noerr_quiet(drtn
, badDER
);
1403 /* (c) attribute values in PrintableString are not case sensitive
1404 (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and
1406 (d) attribute values in PrintableString are compared after
1407 removing leading and trailing white space and converting internal
1408 substrings of one or more consecutive white space characters to a
1410 if (value
.tag
== ASN1_PRINTABLE_STRING
) {
1411 /* Offset relative to base of current value tag. */
1412 CFIndex valueTagLocation
= atvTagLocation
+ atvPair
.value
.data
- atvTag
;
1413 CFIndex valueTLLength
= value
.content
.data
- atvPair
.value
.data
;
1414 CFIndex valueContentLength
= value
.content
.length
;
1416 /* Now copy all the bytes, but convert to upper case while
1417 doing so and convert multiple whitespace chars into a
1419 bool lastWasBlank
= false;
1420 CFIndex valueLocation
= valueTagLocation
+ valueTLLength
;
1421 CFIndex valueCurrentLocation
= valueLocation
;
1423 for (ix
= 0; ix
< valueContentLength
; ++ix
) {
1424 UInt8 ch
= value
.content
.data
[ix
];
1429 /* Don't insert a space for first character
1431 if (valueCurrentLocation
> valueLocation
) {
1432 base
[valueCurrentLocation
++] = ' ';
1434 lastWasBlank
= true;
1437 lastWasBlank
= false;
1438 if ('a' <= ch
&& ch
<= 'z') {
1439 base
[valueCurrentLocation
++] = ch
+ 'A' - 'a';
1441 base
[valueCurrentLocation
++] = ch
;
1445 /* Finally if lastWasBlank remove the trailing space. */
1446 if (lastWasBlank
&& valueCurrentLocation
> valueLocation
) {
1447 valueCurrentLocation
--;
1449 /* Adjust content length to normalized length. */
1450 valueContentLength
= valueCurrentLocation
- valueLocation
;
1452 /* Number of bytes by which the length should be shorted. */
1453 CFIndex lengthDiff
= value
.content
.length
- valueContentLength
;
1454 if (lengthDiff
== 0) {
1455 /* Easy case no need to adjust lengths. */
1457 /* Hard work we need to go back and fix up length fields
1459 1) The value itself.
1460 2) The ATV Sequence containing type/value
1461 3) The RDN Set containing one or more atv pairs.
1465 /* Step 1 fix up length of value. */
1466 /* Length of value tag and length minus the tag. */
1467 DERSize newValueTLLength
= valueTLLength
- 1;
1468 drtn
= DEREncodeLength(valueContentLength
,
1469 base
+ valueTagLocation
+ 1, &newValueTLLength
);
1470 require(drtn
== DR_Success
, badDER
);
1471 /* Add the length of the tag back in. */
1473 CFIndex valueLLDiff
= valueTLLength
- newValueTLLength
;
1475 /* The size of the length field changed, let's slide
1476 the value back by valueLLDiff bytes. */
1477 memmove(base
+ valueTagLocation
+ newValueTLLength
,
1478 base
+ valueTagLocation
+ valueTLLength
,
1479 valueContentLength
);
1480 /* The length diff for the enclosing object. */
1481 lengthDiff
+= valueLLDiff
;
1484 /* Step 2 fix up length of the enclosing ATV Sequence. */
1485 atvContentLength
-= lengthDiff
;
1486 DERSize newATVTLLength
= atvTLLength
- 1;
1487 drtn
= DEREncodeLength(atvContentLength
,
1488 base
+ atvTagLocation
+ 1, &newATVTLLength
);
1489 require(drtn
== DR_Success
, badDER
);
1490 /* Add the length of the tag back in. */
1492 CFIndex atvLLDiff
= atvTLLength
- newATVTLLength
;
1494 /* The size of the length field changed, let's slide
1495 the value back by valueLLDiff bytes. */
1496 memmove(base
+ atvTagLocation
+ newATVTLLength
,
1497 base
+ atvTagLocation
+ atvTLLength
,
1499 /* The length diff for the enclosing object. */
1500 lengthDiff
+= atvLLDiff
;
1501 atvTLLength
= newATVTLLength
;
1504 /* Step 3 fix up length of enclosing RDN Set. */
1505 rdnContentLength
-= lengthDiff
;
1506 DERSize newRDNTLLength
= rdnTLLength
- 1;
1507 drtn
= DEREncodeLength(rdnContentLength
,
1508 base
+ rdnTagLocation
+ 1, &newRDNTLLength
);
1509 require_quiet(drtn
== DR_Success
, badDER
);
1510 /* Add the length of the tag back in. */
1512 CFIndex rdnLLDiff
= rdnTLLength
- newRDNTLLength
;
1514 /* The size of the length field changed, let's slide
1515 the value back by valueLLDiff bytes. */
1516 memmove(base
+ rdnTagLocation
+ newRDNTLLength
,
1517 base
+ rdnTagLocation
+ rdnTLLength
,
1519 /* The length diff for the enclosing object. */
1520 lengthDiff
+= rdnLLDiff
;
1521 rdnTLLength
= newRDNTLLength
;
1523 /* Adjust the locations that might have changed due to
1525 atvTagLocation
-= rdnLLDiff
;
1527 (void) lengthDiff
; // No next object, silence analyzer
1530 atvTagLocation
+= atvTLLength
+ atvContentLength
;
1531 atvTag
= atvSeq
.nextItem
;
1533 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
1534 rdnTagLocation
+= rdnTLLength
+ rdnContentLength
;
1535 rdnTag
= rdnSeq
.nextItem
;
1537 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
1538 /* Truncate the result to the proper length. */
1539 CFDataSetLength(result
, rdnTagLocation
);
1548 static CFDataRef
SecDERItemCopySequence(DERItem
*content
) {
1549 DERSize seq_len_length
= DERLengthOfLength(content
->length
);
1550 size_t sequence_length
= 1 + seq_len_length
+ content
->length
;
1551 CFMutableDataRef sequence
= CFDataCreateMutable(kCFAllocatorDefault
,
1553 CFDataSetLength(sequence
, sequence_length
);
1554 uint8_t *sequence_ptr
= CFDataGetMutableBytePtr(sequence
);
1555 *sequence_ptr
++ = ONE_BYTE_ASN1_CONSTR_SEQUENCE
;
1556 require_noerr_quiet(DEREncodeLength(content
->length
,
1557 sequence_ptr
, &seq_len_length
), out
);
1558 sequence_ptr
+= seq_len_length
;
1559 memcpy(sequence_ptr
, content
->data
, content
->length
);
1562 CFReleaseSafe(sequence
);
1566 static CFDataRef
SecCopySequenceFromContent(CFDataRef content
) {
1568 tmpItem
.data
= (void *)CFDataGetBytePtr(content
);
1569 tmpItem
.length
= CFDataGetLength(content
);
1571 return SecDERItemCopySequence(&tmpItem
);
1574 CFDataRef
SecDistinguishedNameCopyNormalizedContent(CFDataRef distinguished_name
)
1576 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(distinguished_name
), CFDataGetLength(distinguished_name
) };
1577 DERDecodedInfo content
;
1578 /* Decode top level sequence into DERItem */
1579 if (!DERDecodeItem(&name
, &content
) && (content
.tag
== ASN1_CONSTR_SEQUENCE
))
1580 return createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1584 CFDataRef
SecDistinguishedNameCopyNormalizedSequence(CFDataRef distinguished_name
)
1586 if (!distinguished_name
) { return NULL
; }
1587 CFDataRef normalizedContent
= SecDistinguishedNameCopyNormalizedContent(distinguished_name
);
1588 if (!normalizedContent
) { return NULL
; }
1589 CFDataRef result
= SecCopySequenceFromContent(normalizedContent
);
1590 CFReleaseNull(normalizedContent
);
1594 /* AUDIT[securityd]:
1595 certificate->_der is a caller provided data of any length (might be 0).
1597 Top level certificate decode.
1599 static bool SecCertificateParse(SecCertificateRef certificate
)
1604 require_quiet(certificate
, badCert
);
1605 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
1607 /* top level decode */
1608 DERSignedCertCrl signedCert
;
1609 drtn
= DERParseSequence(&certificate
->_der
, DERNumSignedCertCrlItemSpecs
,
1610 DERSignedCertCrlItemSpecs
, &signedCert
,
1611 sizeof(signedCert
));
1612 require_noerr_quiet(drtn
, badCert
);
1613 /* Store tbs since we need to digest it for verification later on. */
1614 certificate
->_tbs
= signedCert
.tbs
;
1616 /* decode the TBSCert - it was saved in full DER form */
1618 drtn
= DERParseSequence(&signedCert
.tbs
,
1619 DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
,
1620 &tbsCert
, sizeof(tbsCert
));
1621 require_noerr_quiet(drtn
, badCert
);
1623 /* sequence we're given: decode the signedCerts Signature Algorithm. */
1624 /* This MUST be the same as the certificate->_tbsSigAlg with the exception
1625 of the params field. */
1626 drtn
= DERParseSequenceContent(&signedCert
.sigAlg
,
1627 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
1628 &certificate
->_sigAlg
, sizeof(certificate
->_sigAlg
));
1629 require_noerr_quiet(drtn
, badCert
);
1631 /* The contents of signedCert.sig is a bit string whose contents
1632 are the signature itself. */
1633 DERByte numUnusedBits
;
1634 drtn
= DERParseBitString(&signedCert
.sig
,
1635 &certificate
->_signature
, &numUnusedBits
);
1636 require_noerr_quiet(drtn
, badCert
);
1638 /* Now decode the tbsCert. */
1640 /* First we turn the optional version into an int. */
1641 if (tbsCert
.version
.length
) {
1642 DERDecodedInfo decoded
;
1643 drtn
= DERDecodeItem(&tbsCert
.version
, &decoded
);
1644 require_noerr_quiet(drtn
, badCert
);
1645 require_quiet(decoded
.tag
== ASN1_INTEGER
, badCert
);
1646 require_quiet(decoded
.content
.length
== 1, badCert
);
1647 certificate
->_version
= decoded
.content
.data
[0];
1648 if (certificate
->_version
> 2) {
1649 secwarning("Invalid certificate version (%d), must be 0..2",
1650 certificate
->_version
);
1652 require_quiet(certificate
->_version
> 0, badCert
);
1653 require_quiet(certificate
->_version
< 3, badCert
);
1655 certificate
->_version
= 0;
1658 /* The serial number is in the tbsCert.serialNum - it was saved in
1659 INTEGER form without the tag and length. */
1660 certificate
->_serialNum
= tbsCert
.serialNum
;
1662 /* Note: RFC5280 4.1.2.2 limits serial number values to 20 octets.
1663 For now, we warn about larger values, but will still create the
1664 certificate with values up to 36 octets to avoid breaking some
1665 nonconforming certs with slightly longer serial numbers.
1666 We also explicitly allow serial numbers of 21 octets where the
1667 leading byte is 0x00 which is used to make a negative 20 octet
1670 if (tbsCert
.serialNum
.length
< 1 || tbsCert
.serialNum
.length
> 21 ||
1671 (tbsCert
.serialNum
.length
== 21 && tbsCert
.serialNum
.data
[0] != 0x00)) {
1672 secwarning("Invalid serial number length (%ld), must be 1..20",
1673 tbsCert
.serialNum
.length
);
1675 require_quiet(tbsCert
.serialNum
.data
!= NULL
&&
1676 tbsCert
.serialNum
.length
>= 1 &&
1677 tbsCert
.serialNum
.length
<= 37, badCert
);
1678 certificate
->_serialNumber
= CFDataCreate(allocator
,
1679 tbsCert
.serialNum
.data
, tbsCert
.serialNum
.length
);
1681 /* sequence we're given: decode the tbsCerts TBS Signature Algorithm. */
1682 drtn
= DERParseSequenceContent(&tbsCert
.tbsSigAlg
,
1683 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
1684 &certificate
->_tbsSigAlg
, sizeof(certificate
->_tbsSigAlg
));
1685 require_noerr_quiet(drtn
, badCert
);
1687 /* The issuer is in the tbsCert.issuer - it's a sequence without the tag
1688 and length fields. */
1689 certificate
->_issuer
= tbsCert
.issuer
;
1690 certificate
->_normalizedIssuer
= createNormalizedX501Name(allocator
,
1693 /* sequence we're given: decode the tbsCerts Validity sequence. */
1694 DERValidity validity
;
1695 drtn
= DERParseSequenceContent(&tbsCert
.validity
,
1696 DERNumValidityItemSpecs
, DERValidityItemSpecs
,
1697 &validity
, sizeof(validity
));
1698 require_noerr_quiet(drtn
, badCert
);
1699 require_quiet(derDateGetAbsoluteTime(&validity
.notBefore
,
1700 &certificate
->_notBefore
), badCert
);
1701 require_quiet(derDateGetAbsoluteTime(&validity
.notAfter
,
1702 &certificate
->_notAfter
), badCert
);
1704 /* The subject is in the tbsCert.subject - it's a sequence without the tag
1705 and length fields. */
1706 certificate
->_subject
= tbsCert
.subject
;
1707 certificate
->_normalizedSubject
= createNormalizedX501Name(allocator
,
1710 /* Keep the SPKI around for CT */
1711 certificate
->_subjectPublicKeyInfo
= tbsCert
.subjectPubKey
;
1713 /* sequence we're given: encoded DERSubjPubKeyInfo */
1714 DERSubjPubKeyInfo pubKeyInfo
;
1715 drtn
= DERParseSequenceContent(&tbsCert
.subjectPubKey
,
1716 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
1717 &pubKeyInfo
, sizeof(pubKeyInfo
));
1718 require_noerr_quiet(drtn
, badCert
);
1720 /* sequence we're given: decode the pubKeyInfos DERAlgorithmId */
1721 drtn
= DERParseSequenceContent(&pubKeyInfo
.algId
,
1722 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
1723 &certificate
->_algId
, sizeof(certificate
->_algId
));
1724 require_noerr_quiet(drtn
, badCert
);
1726 /* Now we can figure out the key's algorithm id and params based on
1727 certificate->_algId.oid. */
1729 /* The contents of pubKeyInfo.pubKey is a bit string whose contents
1730 are a PKCS1 format RSA key. */
1731 drtn
= DERParseBitString(&pubKeyInfo
.pubKey
,
1732 &certificate
->_pubKeyDER
, &numUnusedBits
);
1733 require_noerr_quiet(drtn
, badCert
);
1735 /* The contents of tbsCert.issuerID is a bit string. */
1736 certificate
->_issuerUniqueID
= tbsCert
.issuerID
;
1738 /* The contents of tbsCert.subjectID is a bit string. */
1739 certificate
->_subjectUniqueID
= tbsCert
.subjectID
;
1742 if (tbsCert
.extensions
.length
) {
1743 CFIndex extensionCount
= 0;
1746 drtn
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
,
1748 require_noerr_quiet(drtn
, badCert
);
1749 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badCert
);
1750 DERDecodedInfo currDecoded
;
1751 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
1753 /* ! = MUST recognize ? = SHOULD recognize
1756 KnownExtension _subjectKeyID
; /* ?SubjectKeyIdentifier id-ce 14 */
1757 KnownExtension _keyUsage
; /* !KeyUsage id-ce 15 */
1758 KnownExtension _subjectAltName
; /* !SubjectAltName id-ce 17 */
1759 KnownExtension _basicConstraints
; /* !BasicConstraints id-ce 19 */
1760 KnownExtension _authorityKeyID
; /* ?AuthorityKeyIdentifier id-ce 35 */
1761 KnownExtension _extKeyUsage
; /* !ExtKeyUsage id-ce 37 */
1762 KnownExtension _netscapeCertType
; /* 2.16.840.1.113730.1.1 netscape 1 1 */
1763 KnownExtension _qualCertStatements
; /* QCStatements id-pe 3 */
1765 KnownExtension _issuerAltName
; /* IssuerAltName id-ce 18 */
1766 KnownExtension _nameConstraints
; /* !NameConstraints id-ce 30 */
1767 KnownExtension _cRLDistributionPoints
; /* CRLDistributionPoints id-ce 31 */
1768 KnownExtension _certificatePolicies
; /* !CertificatePolicies id-ce 32 */
1769 KnownExtension _policyMappings
; /* ?PolicyMappings id-ce 33 */
1770 KnownExtension _policyConstraints
; /* !PolicyConstraints id-ce 36 */
1771 KnownExtension _freshestCRL
; /* FreshestCRL id-ce 46 */
1772 KnownExtension _inhibitAnyPolicy
; /* !InhibitAnyPolicy id-ce 54 */
1774 KnownExtension _authorityInfoAccess
; /* AuthorityInfoAccess id-pe 1 */
1775 KnownExtension _subjectInfoAccess
; /* SubjectInfoAccess id-pe 11 */
1780 require_quiet(drtn
== DR_EndOfSequence
, badCert
);
1782 /* Put some upper limit on the number of extensions allowed. */
1783 require_quiet(extensionCount
< 10000, badCert
);
1784 certificate
->_extensionCount
= extensionCount
;
1785 certificate
->_extensions
=
1786 malloc(sizeof(SecCertificateExtension
) * (extensionCount
> 0 ? extensionCount
: 1));
1787 require_quiet(certificate
->_extensions
, badCert
);
1790 drtn
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
, &derSeq
);
1791 require_noerr_quiet(drtn
, badCert
);
1792 for (ix
= 0; ix
< extensionCount
; ++ix
) {
1793 drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
);
1794 require_quiet(drtn
== DR_Success
||
1795 (ix
== extensionCount
- 1 && drtn
== DR_EndOfSequence
), badCert
);
1796 require_quiet(currDecoded
.tag
== ASN1_CONSTR_SEQUENCE
, badCert
);
1798 drtn
= DERParseSequenceContent(&currDecoded
.content
,
1799 DERNumExtensionItemSpecs
, DERExtensionItemSpecs
,
1800 &extn
, sizeof(extn
));
1801 require_noerr_quiet(drtn
, badCert
);
1802 /* Copy stuff into certificate->extensions[ix]. */
1803 certificate
->_extensions
[ix
].extnID
= extn
.extnID
;
1804 require_noerr_quiet(drtn
= DERParseBooleanWithDefault(&extn
.critical
, false,
1805 &certificate
->_extensions
[ix
].critical
), badCert
);
1806 certificate
->_extensions
[ix
].extnValue
= extn
.extnValue
;
1808 SecCertificateExtensionParser parser
=
1809 (SecCertificateExtensionParser
)CFDictionaryGetValue(
1810 sExtensionParsers
, &certificate
->_extensions
[ix
].extnID
);
1812 /* Invoke the parser. If the extension is critical and the
1813 * parser fails, fail the cert. */
1814 require_quiet(parser(certificate
, &certificate
->_extensions
[ix
]) ||
1815 !certificate
->_extensions
[ix
].critical
, badCert
);
1816 } else if (certificate
->_extensions
[ix
].critical
) {
1817 if (isAppleExtensionOID(&extn
.extnID
)) {
1820 secdebug("cert", "Found unknown critical extension");
1821 certificate
->_foundUnknownCriticalExtension
= true;
1823 secdebug("cert", "Found unknown non critical extension");
1827 checkForMissingRevocationInfo(certificate
);
1836 /* Public API functions. */
1837 SecCertificateRef
SecCertificateCreateWithBytes(CFAllocatorRef allocator
,
1838 const UInt8
*der_bytes
, CFIndex der_length
) {
1839 if (der_bytes
== NULL
) return NULL
;
1840 if (der_length
== 0) return NULL
;
1842 CFIndex size
= sizeof(struct __SecCertificate
) + der_length
;
1843 SecCertificateRef result
= (SecCertificateRef
)_CFRuntimeCreateInstance(
1844 allocator
, SecCertificateGetTypeID(), size
- sizeof(CFRuntimeBase
), 0);
1846 memset((char*)result
+ sizeof(result
->_base
), 0,
1847 sizeof(*result
) - sizeof(result
->_base
));
1848 result
->_der
.data
= ((DERByte
*)result
+ sizeof(*result
));
1849 result
->_der
.length
= der_length
;
1850 memcpy(result
->_der
.data
, der_bytes
, der_length
);
1851 if (!SecCertificateParse(result
)) {
1859 /* @@@ Placeholder until <rdar://problem/5701851> iap submits a binary is fixed. */
1860 SecCertificateRef
SecCertificateCreate(CFAllocatorRef allocator
,
1861 const UInt8
*der_bytes
, CFIndex der_length
);
1863 SecCertificateRef
SecCertificateCreate(CFAllocatorRef allocator
,
1864 const UInt8
*der_bytes
, CFIndex der_length
) {
1865 return SecCertificateCreateWithBytes(allocator
, der_bytes
, der_length
);
1867 /* @@@ End of placeholder. */
1869 /* AUDIT[securityd](done):
1870 der_certificate is a caller provided data of any length (might be 0), only
1871 its cf type has been checked.
1873 SecCertificateRef
SecCertificateCreateWithData(CFAllocatorRef allocator
,
1874 CFDataRef der_certificate
) {
1875 if (!der_certificate
) {
1878 CFIndex size
= sizeof(struct __SecCertificate
);
1879 SecCertificateRef result
= (SecCertificateRef
)_CFRuntimeCreateInstance(
1880 allocator
, SecCertificateGetTypeID(), size
- sizeof(CFRuntimeBase
), 0);
1882 memset((char*)result
+ sizeof(result
->_base
), 0, size
- sizeof(result
->_base
));
1883 result
->_der_data
= CFDataCreateCopy(allocator
, der_certificate
);
1884 result
->_der
.data
= (DERByte
*)CFDataGetBytePtr(result
->_der_data
);
1885 result
->_der
.length
= CFDataGetLength(result
->_der_data
);
1886 if (!SecCertificateParse(result
)) {
1894 SecCertificateRef
SecCertificateCreateWithKeychainItem(CFAllocatorRef allocator
,
1895 CFDataRef der_certificate
,
1896 CFTypeRef keychain_item
)
1898 SecCertificateRef result
= SecCertificateCreateWithData(allocator
, der_certificate
);
1900 CFRetainSafe(keychain_item
);
1901 result
->_keychain_item
= keychain_item
;
1906 OSStatus
SecCertificateSetKeychainItem(SecCertificateRef certificate
,
1907 CFTypeRef keychain_item
)
1912 CFRetainSafe(keychain_item
);
1913 CFReleaseSafe(certificate
->_keychain_item
);
1914 certificate
->_keychain_item
= keychain_item
;
1915 return errSecSuccess
;
1918 CFDataRef
SecCertificateCopyData(SecCertificateRef certificate
) {
1920 CFDataRef result
= NULL
;
1924 if (certificate
->_der_data
) {
1925 CFRetain(certificate
->_der_data
);
1926 result
= certificate
->_der_data
;
1928 result
= CFDataCreate(CFGetAllocator(certificate
),
1929 certificate
->_der
.data
, certificate
->_der
.length
);
1931 /* FIXME: If we wish to cache result we need to lock the certificate.
1932 Also this create 2 copies of the certificate data which is somewhat
1935 certificate
->_der_data
= result
;
1942 CFIndex
SecCertificateGetLength(SecCertificateRef certificate
) {
1943 return certificate
->_der
.length
;
1946 const UInt8
*SecCertificateGetBytePtr(SecCertificateRef certificate
) {
1947 return certificate
->_der
.data
;
1950 /* Used to recreate preCert from cert for Certificate Transparency */
1951 CFDataRef
SecCertificateCopyPrecertTBS(SecCertificateRef certificate
)
1953 CFDataRef outData
= NULL
;
1954 DERItem tbsIn
= certificate
->_tbs
;
1955 DERItem tbsOut
= {0,};
1956 DERItem extensionsOut
= {0,};
1957 DERItem
*extensionsList
= malloc(sizeof(DERItem
)*certificate
->_extensionCount
); /* This maybe one too many */
1958 DERItemSpec
*extensionsListSpecs
= malloc(sizeof(DERItemSpec
)*certificate
->_extensionCount
);
1962 require_quiet(extensionsList
&& extensionsListSpecs
, out
);
1964 /* decode the TBSCert - it was saved in full DER form */
1965 drtn
= DERParseSequence(&tbsIn
,
1966 DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
,
1967 &tbsCert
, sizeof(tbsCert
));
1968 require_noerr_quiet(drtn
, out
);
1970 /* Go over extensions and filter any SCT extension */
1971 CFIndex extensionsCount
= 0;
1973 if (tbsCert
.extensions
.length
) {
1976 drtn
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
,
1978 require_noerr_quiet(drtn
, out
);
1979 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, out
);
1980 DERDecodedInfo currDecoded
;
1981 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
1983 require_quiet(currDecoded
.tag
== ASN1_CONSTR_SEQUENCE
, out
);
1985 drtn
= DERParseSequenceContent(&currDecoded
.content
,
1986 DERNumExtensionItemSpecs
, DERExtensionItemSpecs
,
1987 &extn
, sizeof(extn
));
1988 require_noerr_quiet(drtn
, out
);
1990 if (extn
.extnID
.length
== oidGoogleEmbeddedSignedCertificateTimestamp
.length
&&
1991 !memcmp(extn
.extnID
.data
, oidGoogleEmbeddedSignedCertificateTimestamp
.data
, extn
.extnID
.length
))
1994 extensionsList
[extensionsCount
] = currDecoded
.content
;
1995 extensionsListSpecs
[extensionsCount
].offset
= sizeof(DERItem
)*extensionsCount
;
1996 extensionsListSpecs
[extensionsCount
].options
= 0;
1997 extensionsListSpecs
[extensionsCount
].tag
= ASN1_CONSTR_SEQUENCE
;
2002 require_quiet(drtn
== DR_EndOfSequence
, out
);
2006 /* Encode extensions */
2007 extensionsOut
.length
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, extensionsList
, extensionsCount
, extensionsListSpecs
);
2008 extensionsOut
.data
= malloc(extensionsOut
.length
);
2009 require_quiet(extensionsOut
.data
, out
);
2010 drtn
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, extensionsList
, extensionsCount
, extensionsListSpecs
, extensionsOut
.data
, &extensionsOut
.length
);
2011 require_noerr_quiet(drtn
, out
);
2013 tbsCert
.extensions
= extensionsOut
;
2015 tbsOut
.length
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &tbsCert
, DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
);
2016 tbsOut
.data
= malloc(tbsOut
.length
);
2017 require_quiet(tbsOut
.data
, out
);
2018 drtn
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &tbsCert
, DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
, tbsOut
.data
, &tbsOut
.length
);
2019 require_noerr_quiet(drtn
, out
);
2021 outData
= CFDataCreate(kCFAllocatorDefault
, tbsOut
.data
, tbsOut
.length
);
2024 if (extensionsOut
.data
) free(extensionsOut
.data
);
2025 if (tbsOut
.data
) free(tbsOut
.data
);
2026 if (extensionsList
) free(extensionsList
);
2027 if (extensionsListSpecs
) free(extensionsListSpecs
);
2032 /* From rfc3280 - Appendix B. ASN.1 Notes
2034 Object Identifiers (OIDs) are used throughout this specification to
2035 identify certificate policies, public key and signature algorithms,
2036 certificate extensions, etc. There is no maximum size for OIDs.
2037 This specification mandates support for OIDs which have arc elements
2038 with values that are less than 2^28, that is, they MUST be between 0
2039 and 268,435,455, inclusive. This allows each arc element to be
2040 represented within a single 32 bit word. Implementations MUST also
2041 support OIDs where the length of the dotted decimal (see [RFC 2252],
2042 section 4.1) string representation can be up to 100 bytes
2043 (inclusive). Implementations MUST be able to handle OIDs with up to
2044 20 elements (inclusive). CAs SHOULD NOT issue certificates which
2045 contain OIDs that exceed these requirements. Likewise, CRL issuers
2046 SHOULD NOT issue CRLs which contain OIDs that exceed these
2050 /* Oids longer than this are considered invalid. */
2051 #define MAX_OID_SIZE 32
2053 CFStringRef
SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator
,
2054 const DERItem
*oid
) {
2056 if (oid
->length
== 0) {
2057 return SecCopyCertString(SEC_NULL_KEY
);
2059 if (oid
->length
> MAX_OID_SIZE
) {
2060 return SecCopyCertString(SEC_OID_TOO_LONG_KEY
);
2063 CFMutableStringRef result
= CFStringCreateMutable(allocator
, 0);
2065 // The first two levels are encoded into one byte, since the root level
2066 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then
2067 // y may be > 39, so we have to add special-case handling for this.
2068 uint32_t x
= oid
->data
[0] / 40;
2069 uint32_t y
= oid
->data
[0] % 40;
2072 // Handle special case for large y if x = 2
2076 CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
);
2079 for (x
= 1; x
< oid
->length
; ++x
)
2081 value
= (value
<< 7) | (oid
->data
[x
] & 0x7F);
2082 /* @@@ value may not span more than 4 bytes. */
2083 /* A max number of 20 values is allowed. */
2084 if (!(oid
->data
[x
] & 0x80))
2086 CFStringAppendFormat(result
, NULL
, CFSTR(".%" PRIu32
), value
);
2093 static CFStringRef
copyOidDescription(CFAllocatorRef allocator
,
2094 const DERItem
*oid
, bool localized
) {
2095 if (!oid
|| oid
->length
== 0) {
2096 return (localized
) ? SecCopyCertString(SEC_NULL_KEY
) : SEC_NULL_KEY
;
2099 CFStringRef name
= SecDERItemCopyOIDDecimalRepresentation(allocator
, oid
);
2104 /* Build the key we use to lookup the localized OID description. */
2105 CFMutableStringRef oidKey
= CFStringCreateMutable(allocator
,
2106 oid
->length
* 3 + 5);
2107 CFStringAppendFormat(oidKey
, NULL
, CFSTR("06 %02lX"), oid
->length
);
2108 for (DERSize ix
= 0; ix
< oid
->length
; ++ix
) {
2109 CFStringAppendFormat(oidKey
, NULL
, CFSTR(" %02X"), oid
->data
[ix
]);
2111 CFStringRef locname
= SecFrameworkCopyLocalizedString(oidKey
, CFSTR("OID"));
2112 if (locname
&& !CFEqual(oidKey
, locname
)) {
2113 /* Found localized description string, so use it instead of OID. */
2114 CFReleaseSafe(name
);
2117 CFReleaseSafe(locname
);
2124 /* Return the ipAddress as a dotted quad for ipv4, or as 8 colon separated
2125 4 digit hex strings for ipv6. Return NULL if the provided IP doesn't
2126 have a length of exactly 4 or 16 octets.
2128 static CFStringRef
copyIPAddressContentDescription(CFAllocatorRef allocator
,
2129 const DERItem
*ip
) {
2130 /* This is the IP Address as an OCTET STRING.
2131 For IPv4 it's 4 octets addr, or 8 octets, addr/mask.
2132 For IPv6 it's 16 octets addr, or 32 octets addr/mask.
2134 CFStringRef value
= NULL
;
2135 if (ip
->length
== 4) {
2136 value
= CFStringCreateWithFormat(allocator
, NULL
,
2137 CFSTR("%u.%u.%u.%u"),
2138 ip
->data
[0], ip
->data
[1], ip
->data
[2], ip
->data
[3]);
2139 } else if (ip
->length
== 16) {
2140 value
= CFStringCreateWithFormat(allocator
, NULL
,
2141 CFSTR("%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
2142 "%02x%02x:%02x%02x:%02x%02x:%02x%02x"),
2143 ip
->data
[0], ip
->data
[1], ip
->data
[2], ip
->data
[3],
2144 ip
->data
[4], ip
->data
[5], ip
->data
[6], ip
->data
[7],
2145 ip
->data
[8], ip
->data
[9], ip
->data
[10], ip
->data
[11],
2146 ip
->data
[12], ip
->data
[13], ip
->data
[14], ip
->data
[15]);
2152 void appendProperty(CFMutableArrayRef properties
, CFStringRef propertyType
,
2153 CFStringRef label
, CFStringRef localizedLabel
, CFTypeRef value
,
2155 CFDictionaryRef property
;
2157 CFStringRef ll
= NULL
;
2159 /* use unlocalized label, overriding localizedLabel */
2160 ll
= localizedLabel
= (CFStringRef
) CFRetainSafe(label
);
2161 } else if (!localizedLabel
) {
2162 /* copy localized label for unlocalized label */
2163 ll
= localizedLabel
= SecCopyCertString(label
);
2165 const void *all_keys
[4];
2166 all_keys
[0] = kSecPropertyKeyType
;
2167 all_keys
[1] = kSecPropertyKeyLabel
;
2168 all_keys
[2] = kSecPropertyKeyLocalizedLabel
;
2169 all_keys
[3] = kSecPropertyKeyValue
;
2170 const void *property_values
[] = {
2176 property
= CFDictionaryCreate(CFGetAllocator(properties
),
2177 all_keys
, property_values
, value
? 4 : 3,
2178 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2181 const void *nolabel_keys
[2];
2182 nolabel_keys
[0] = kSecPropertyKeyType
;
2183 nolabel_keys
[1] = kSecPropertyKeyValue
;
2184 const void *property_values
[] = {
2188 property
= CFDictionaryCreate(CFGetAllocator(properties
),
2189 nolabel_keys
, property_values
, 2,
2190 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2193 CFArrayAppendValue(properties
, property
);
2194 CFRelease(property
);
2198 #define UTC_TIME_NOSEC_ZULU_LEN 11
2200 #define UTC_TIME_ZULU_LEN 13
2201 /* YYMMDDhhmmssThhmm */
2202 #define UTC_TIME_LOCALIZED_LEN 17
2203 /* YYYYMMDDhhmmssZ */
2204 #define GENERALIZED_TIME_ZULU_LEN 15
2205 /* YYYYMMDDhhmmssThhmm */
2206 #define GENERALIZED_TIME_LOCALIZED_LEN 19
2208 /* Parse 2 digits at (*p)[0] and (*p)[1] and return the result. Also
2210 static inline int parseDecimalPair(const DERByte
**p
) {
2211 const DERByte
*cp
= *p
;
2213 return 10 * (cp
[0] - '0') + cp
[1] - '0';
2216 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime.
2217 Return a CFErrorRef in the error parameter if decoding fails.
2218 Note that this is needed to distinguish an error condition from a
2219 valid time which specifies 2001-01-01 00:00:00 (i.e. a value of 0).
2221 static CFAbsoluteTime
SecAbsoluteTimeFromDateContentWithError(DERTag tag
,
2222 const uint8_t *bytes
,
2224 CFErrorRef
*error
) {
2228 if (NULL
== bytes
|| 0 == length
) {
2232 bool isUtcLength
= false;
2233 bool isLocalized
= false;
2234 bool noSeconds
= false;
2236 case UTC_TIME_NOSEC_ZULU_LEN
: /* YYMMDDhhmmZ */
2240 case UTC_TIME_ZULU_LEN
: /* YYMMDDhhmmssZ */
2243 case GENERALIZED_TIME_ZULU_LEN
: /* YYYYMMDDhhmmssZ */
2245 case UTC_TIME_LOCALIZED_LEN
: /* YYMMDDhhmmssThhmm (where T=[+,-]) */
2248 case GENERALIZED_TIME_LOCALIZED_LEN
:/* YYYYMMDDhhmmssThhmm (where T=[+,-]) */
2251 default: /* unknown format */
2255 /* Make sure the der tag fits the thing inside it. */
2256 if (tag
== ASN1_UTC_TIME
) {
2260 } else if (tag
== ASN1_GENERALIZED_TIME
) {
2268 const DERByte
*cp
= bytes
;
2269 /* Check that all characters are digits, except if localized the timezone
2270 indicator or if not localized the 'Z' at the end. */
2272 for (ix
= 0; ix
< length
; ++ix
) {
2273 if (!(isdigit(cp
[ix
]))) {
2274 if ((isLocalized
&& ix
== length
- 5 &&
2275 (cp
[ix
] == '+' || cp
[ix
] == '-')) ||
2276 (!isLocalized
&& ix
== length
- 1 && cp
[ix
] == 'Z')) {
2283 /* Parse the date and time fields. */
2284 int year
, month
, day
, hour
, minute
, second
;
2286 year
= parseDecimalPair(&cp
);
2288 /* 0 <= year < 50 : assume century 21 */
2290 } else if (year
< 70) {
2291 /* 50 <= year < 70 : illegal per PKIX */
2294 /* 70 < year <= 99 : assume century 20 */
2298 year
= 100 * parseDecimalPair(&cp
) + parseDecimalPair(&cp
);
2300 month
= parseDecimalPair(&cp
);
2301 day
= parseDecimalPair(&cp
);
2302 hour
= parseDecimalPair(&cp
);
2303 minute
= parseDecimalPair(&cp
);
2307 second
= parseDecimalPair(&cp
);
2310 CFTimeInterval timeZoneOffset
;
2312 /* ZONE INDICATOR */
2313 int multiplier
= *cp
++ == '+' ? 60 : -60;
2314 timeZoneOffset
= multiplier
*
2315 (parseDecimalPair(&cp
) * 60 + parseDecimalPair(&cp
));
2320 secdebug("dateparse",
2321 "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g",
2322 (int) length
, bytes
, year
, month
,
2323 day
, hour
, minute
, second
,
2324 timeZoneOffset
/ 60);
2326 static int mdays
[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
2327 int is_leap_year
= year
% 4 == 0 && (year
% 100 != 0 || year
% 400 == 0) ? 1 : 0;
2328 if (month
< 1 || month
> 12 || day
< 1 || day
> 31 || hour
> 23 || minute
> 59 || second
> 59
2329 || (month
== 2 && day
> mdays
[month
] - mdays
[month
- 1] + is_leap_year
)
2330 || (month
!= 2 && day
> mdays
[month
] - mdays
[month
- 1])) {
2335 int dy
= year
- 2001;
2340 int leap_days
= dy
/ 4 - dy
/ 100 + dy
/ 400;
2341 day
+= ((year
- 2001) * 365 + leap_days
) + mdays
[month
- 1] - 1;
2343 day
+= is_leap_year
;
2345 CFAbsoluteTime absTime
= (CFAbsoluteTime
)((day
* 24.0 + hour
) * 60.0 + minute
) * 60.0 + second
;
2346 return absTime
- timeZoneOffset
;
2350 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidCertificate
, NULL
);
2355 CFAbsoluteTime
SecAbsoluteTimeFromDateContent(DERTag tag
, const uint8_t *bytes
,
2357 return SecAbsoluteTimeFromDateContentWithError(tag
, bytes
, length
, NULL
);
2360 __attribute__((__nonnull__
)) static bool derDateContentGetAbsoluteTime(DERTag tag
, const DERItem
*date
,
2361 CFAbsoluteTime
*pabsTime
) {
2362 CFErrorRef error
= NULL
;
2363 CFAbsoluteTime absTime
= SecAbsoluteTimeFromDateContentWithError(tag
, date
->data
,
2364 date
->length
, &error
);
2366 secwarning("Invalid date specification in certificate (see RFC5280 4.1.2.5)");
2371 *pabsTime
= absTime
;
2375 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return
2376 true if the date was valid and properly decoded, also return the result in
2377 absTime. Return false otherwise. */
2378 __attribute__((__nonnull__
)) static bool derDateGetAbsoluteTime(const DERItem
*dateChoice
,
2379 CFAbsoluteTime
*absTime
) {
2380 if (dateChoice
->length
== 0) return false;
2382 DERDecodedInfo decoded
;
2383 if (DERDecodeItem(dateChoice
, &decoded
))
2386 return derDateContentGetAbsoluteTime(decoded
.tag
, &decoded
.content
,
2390 static void appendDataProperty(CFMutableArrayRef properties
,
2391 CFStringRef label
, CFStringRef localizedLabel
, const DERItem
*der_data
,
2393 CFDataRef data
= CFDataCreate(CFGetAllocator(properties
),
2394 der_data
->data
, der_data
->length
);
2395 appendProperty(properties
, kSecPropertyTypeData
, label
, localizedLabel
,
2400 static void appendRelabeledProperty(CFMutableArrayRef properties
,
2402 CFStringRef localizedLabel
,
2403 const DERItem
*der_data
,
2404 CFStringRef labelFormat
,
2406 CFStringRef newLabel
=
2407 CFStringCreateWithFormat(CFGetAllocator(properties
), NULL
,
2408 labelFormat
, label
);
2409 CFStringRef ll
= NULL
;
2410 CFStringRef localizedLabelFormat
= NULL
;
2412 /* use provided label and format strings; do not localize */
2413 ll
= localizedLabel
= (CFStringRef
) CFRetainSafe(label
);
2414 localizedLabelFormat
= (CFStringRef
) CFRetainSafe(labelFormat
);
2416 if (!localizedLabel
) {
2417 /* copy localized label for provided label */
2418 ll
= localizedLabel
= SecCopyCertString(label
);
2420 /* copy localized format for provided format */
2421 localizedLabelFormat
= SecCopyCertString(labelFormat
);
2424 CFStringRef newLocalizedLabel
=
2425 CFStringCreateWithFormat(CFGetAllocator(properties
), NULL
,
2426 localizedLabelFormat
, localizedLabel
);
2428 CFReleaseSafe(localizedLabelFormat
);
2429 appendDataProperty(properties
, newLabel
, newLocalizedLabel
, der_data
, localized
);
2430 CFReleaseSafe(newLabel
);
2431 CFReleaseSafe(newLocalizedLabel
);
2435 static void appendUnparsedProperty(CFMutableArrayRef properties
,
2436 CFStringRef label
, CFStringRef localizedLabel
,
2437 const DERItem
*der_data
, bool localized
) {
2438 appendRelabeledProperty(properties
, label
, localizedLabel
, der_data
,
2439 SEC_UNPARSED_KEY
, localized
);
2442 static void appendInvalidProperty(CFMutableArrayRef properties
,
2443 CFStringRef label
, const DERItem
*der_data
, bool localized
) {
2444 appendRelabeledProperty(properties
, label
, NULL
, der_data
,
2445 SEC_INVALID_KEY
, localized
);
2448 static void appendDateContentProperty(CFMutableArrayRef properties
,
2449 CFStringRef label
, DERTag tag
,
2450 const DERItem
*dateContent
, bool localized
) {
2451 CFAbsoluteTime absTime
;
2452 if (!derDateContentGetAbsoluteTime(tag
, dateContent
, &absTime
)) {
2453 /* Date decode failure; insert hex bytes instead. */
2454 return appendInvalidProperty(properties
, label
, dateContent
, localized
);
2456 CFDateRef date
= CFDateCreate(CFGetAllocator(properties
), absTime
);
2457 appendProperty(properties
, kSecPropertyTypeDate
, label
, NULL
, date
, localized
);
2461 static void appendDateProperty(CFMutableArrayRef properties
,
2462 CFStringRef label
, CFAbsoluteTime absTime
, bool localized
) {
2463 CFDateRef date
= CFDateCreate(CFGetAllocator(properties
), absTime
);
2464 appendProperty(properties
, kSecPropertyTypeDate
, label
, NULL
, date
, localized
);
2468 static void appendValidityPeriodProperty(CFMutableArrayRef parent
, CFStringRef label
,
2469 SecCertificateRef certificate
, bool localized
) {
2470 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2471 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2473 appendDateProperty(properties
, SEC_NOT_VALID_BEFORE_KEY
,
2474 certificate
->_notBefore
, localized
);
2475 appendDateProperty(properties
, SEC_NOT_VALID_AFTER_KEY
,
2476 certificate
->_notAfter
, localized
);
2478 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
, properties
, localized
);
2479 CFReleaseNull(properties
);
2482 static void appendIPAddressContentProperty(CFMutableArrayRef properties
,
2483 CFStringRef label
, const DERItem
*ip
, bool localized
) {
2485 copyIPAddressContentDescription(CFGetAllocator(properties
), ip
);
2487 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, value
, localized
);
2490 appendUnparsedProperty(properties
, label
, NULL
, ip
, localized
);
2494 static void appendURLContentProperty(CFMutableArrayRef properties
,
2495 CFStringRef label
, const DERItem
*urlContent
, bool localized
) {
2496 CFURLRef url
= CFURLCreateWithBytes(CFGetAllocator(properties
),
2497 urlContent
->data
, urlContent
->length
, kCFStringEncodingASCII
, NULL
);
2499 appendProperty(properties
, kSecPropertyTypeURL
, label
, NULL
, url
, localized
);
2502 appendInvalidProperty(properties
, label
, urlContent
, localized
);
2506 static void appendURLProperty(CFMutableArrayRef properties
,
2507 CFStringRef label
, const DERItem
*url
, bool localized
) {
2508 DERDecodedInfo decoded
;
2511 drtn
= DERDecodeItem(url
, &decoded
);
2512 if (drtn
|| decoded
.tag
!= ASN1_IA5_STRING
) {
2513 appendInvalidProperty(properties
, label
, url
, localized
);
2515 appendURLContentProperty(properties
, label
, &decoded
.content
, localized
);
2519 static void appendOIDProperty(CFMutableArrayRef properties
,
2520 CFStringRef label
, CFStringRef llabel
, const DERItem
*oid
, bool localized
) {
2521 CFStringRef oid_string
=
2522 copyOidDescription(CFGetAllocator(properties
), oid
, localized
);
2523 appendProperty(properties
, kSecPropertyTypeString
, label
, llabel
,
2524 oid_string
, localized
);
2525 CFRelease(oid_string
);
2528 static void appendAlgorithmProperty(CFMutableArrayRef properties
,
2529 CFStringRef label
, const DERAlgorithmId
*algorithm
, bool localized
) {
2530 CFMutableArrayRef alg_props
=
2531 CFArrayCreateMutable(CFGetAllocator(properties
), 0,
2532 &kCFTypeArrayCallBacks
);
2533 appendOIDProperty(alg_props
, SEC_ALGORITHM_KEY
, NULL
,
2534 &algorithm
->oid
, localized
);
2535 if (algorithm
->params
.length
) {
2536 if (algorithm
->params
.length
== 2 &&
2537 algorithm
->params
.data
[0] == ASN1_NULL
&&
2538 algorithm
->params
.data
[1] == 0) {
2539 CFStringRef value
= SecCopyCertString(SEC_NONE_KEY
);
2540 appendProperty(alg_props
, kSecPropertyTypeString
,
2541 SEC_PARAMETERS_KEY
, NULL
, value
, localized
);
2544 appendUnparsedProperty(alg_props
, SEC_PARAMETERS_KEY
, NULL
,
2545 &algorithm
->params
, localized
);
2548 appendProperty(properties
, kSecPropertyTypeSection
, label
, NULL
,
2549 alg_props
, localized
);
2550 CFRelease(alg_props
);
2553 static void appendPublicKeyProperty(CFMutableArrayRef parent
, CFStringRef label
,
2554 SecCertificateRef certificate
, bool localized
) {
2555 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2556 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2558 /* Public key algorithm. */
2559 appendAlgorithmProperty(properties
, SEC_PUBLIC_KEY_ALG_KEY
,
2560 &certificate
->_algId
, localized
);
2562 /* Public Key Size */
2563 #if TARGET_OS_IPHONE
2564 SecKeyRef publicKey
= SecCertificateCopyPublicKey(certificate
);
2566 SecKeyRef publicKey
= SecCertificateCopyPublicKey_ios(certificate
);
2569 size_t sizeInBytes
= SecKeyGetBlockSize(publicKey
);
2570 CFStringRef sizeInBitsString
= CFStringCreateWithFormat(allocator
, NULL
,
2571 CFSTR("%ld"), (sizeInBytes
*8));
2572 if (sizeInBitsString
) {
2573 appendProperty(properties
, kSecPropertyTypeString
, SEC_PUBLIC_KEY_SIZE_KEY
,
2574 NULL
, sizeInBitsString
, localized
);
2576 CFReleaseNull(sizeInBitsString
);
2578 CFReleaseNull(publicKey
);
2580 /* Consider breaking down an RSA public key into modulus and
2582 appendDataProperty(properties
, SEC_PUBLIC_KEY_DATA_KEY
, NULL
,
2583 &certificate
->_pubKeyDER
, localized
);
2585 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
,
2586 properties
, localized
);
2587 CFReleaseNull(properties
);
2590 static void appendSignatureProperty(CFMutableArrayRef parent
, CFStringRef label
,
2591 SecCertificateRef certificate
, bool localized
) {
2592 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2593 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2595 appendAlgorithmProperty(properties
, SEC_SIGNATURE_ALGORITHM_KEY
,
2596 &certificate
->_tbsSigAlg
, localized
);
2598 appendDataProperty(properties
, SEC_SIGNATURE_DATA_KEY
, NULL
,
2599 &certificate
->_signature
, localized
);
2601 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
,
2602 properties
, localized
);
2603 CFReleaseNull(properties
);
2606 static void appendFingerprintsProperty(CFMutableArrayRef parent
, CFStringRef label
,
2607 SecCertificateRef certificate
, bool localized
) {
2608 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2609 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2611 CFDataRef sha256Fingerprint
= SecCertificateCopySHA256Digest(certificate
);
2612 if (sha256Fingerprint
) {
2613 appendProperty(properties
, kSecPropertyTypeData
, SEC_SHA2_FINGERPRINT_KEY
,
2614 NULL
, sha256Fingerprint
, localized
);
2616 CFReleaseNull(sha256Fingerprint
);
2618 appendProperty(properties
, kSecPropertyTypeData
, SEC_SHA1_FINGERPRINT_KEY
,
2619 NULL
, SecCertificateGetSHA1Digest(certificate
), localized
);
2621 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
,
2622 properties
, localized
);
2623 CFReleaseNull(properties
);
2626 static CFStringRef
copyHexDescription(CFAllocatorRef allocator
,
2627 const DERItem
*blob
) {
2628 CFIndex ix
, length
= blob
->length
/* < 24 ? blob->length : 24 */;
2629 CFMutableStringRef string
= CFStringCreateMutable(allocator
,
2630 blob
->length
* 3 - 1);
2631 for (ix
= 0; ix
< length
; ++ix
)
2633 CFStringAppendFormat(string
, NULL
, CFSTR("%02X"), blob
->data
[ix
]);
2635 CFStringAppendFormat(string
, NULL
, CFSTR(" %02X"), blob
->data
[ix
]);
2640 static CFStringRef
copyBlobString(CFAllocatorRef allocator
,
2641 CFStringRef blobType
, CFStringRef quanta
,
2642 const DERItem
*blob
, bool localized
) {
2643 CFStringRef localizedBlobType
= (localized
) ?
2644 SecCopyCertString(blobType
) : (CFStringRef
) CFRetainSafe(blobType
);
2645 CFStringRef localizedQuanta
= (localized
) ?
2646 SecCopyCertString(quanta
) : (CFStringRef
) CFRetainSafe(quanta
);
2647 /* "format string for encoded field data (e.g. Sequence; 128 bytes; "
2648 "data = 00 00 ...)" */
2649 CFStringRef blobFormat
= (localized
) ?
2650 SecCopyCertString(SEC_BLOB_KEY
) : SEC_BLOB_KEY
;
2651 CFStringRef hex
= copyHexDescription(allocator
, blob
);
2652 CFStringRef result
= CFStringCreateWithFormat(allocator
, NULL
,
2653 blobFormat
, localizedBlobType
, blob
->length
, localizedQuanta
, hex
);
2655 CFRelease(blobFormat
);
2656 CFReleaseSafe(localizedQuanta
);
2657 CFReleaseSafe(localizedBlobType
);
2662 /* Return a string verbatim (unlocalized) from a DER field. */
2663 static CFStringRef
copyContentString(CFAllocatorRef allocator
,
2664 const DERItem
*string
, CFStringEncoding encoding
,
2665 bool printableOnly
) {
2666 /* Strip potential bogus trailing zero from printable strings. */
2667 DERSize length
= string
->length
;
2668 if (length
&& string
->data
[length
- 1] == 0) {
2669 /* Don't mess with the length of UTF16 strings though. */
2670 if (encoding
!= kCFStringEncodingUTF16
)
2673 /* A zero length string isn't considered printable. */
2674 if (!length
&& printableOnly
)
2677 /* Passing true for the 5th paramater to CFStringCreateWithBytes() makes
2678 it treat kCFStringEncodingUTF16 as big endian by default, whereas
2679 passing false makes it treat it as native endian by default. */
2680 CFStringRef result
= CFStringCreateWithBytes(allocator
, string
->data
,
2681 length
, encoding
, encoding
== kCFStringEncodingUTF16
);
2685 return printableOnly
? NULL
: copyHexDescription(allocator
, string
);
2688 /* From rfc3280 - Appendix B. ASN.1 Notes
2690 CAs MUST force the serialNumber to be a non-negative integer, that
2691 is, the sign bit in the DER encoding of the INTEGER value MUST be
2692 zero - this can be done by adding a leading (leftmost) `00'H octet if
2693 necessary. This removes a potential ambiguity in mapping between a
2694 string of octets and an integer value.
2696 As noted in section 4.1.2.2, serial numbers can be expected to
2697 contain long integers. Certificate users MUST be able to handle
2698 serialNumber values up to 20 octets in length. Conformant CAs MUST
2699 NOT use serialNumber values longer than 20 octets.
2702 /* Return the given numeric data as a string: decimal up to 64 bits,
2705 static CFStringRef
copyIntegerContentDescription(CFAllocatorRef allocator
,
2706 const DERItem
*integer
) {
2708 CFIndex ix
, length
= integer
->length
;
2710 if (length
== 0 || length
> 8)
2711 return copyHexDescription(allocator
, integer
);
2713 for(ix
= 0; ix
< length
; ++ix
) {
2715 value
+= integer
->data
[ix
];
2718 return CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%llu"), value
);
2721 static CFStringRef
copyDERThingContentDescription(CFAllocatorRef allocator
,
2722 DERTag tag
, const DERItem
*derThing
, bool printableOnly
, bool localized
) {
2723 if (!derThing
) { return NULL
; }
2727 return printableOnly
? NULL
: copyIntegerContentDescription(allocator
, derThing
);
2728 case ASN1_PRINTABLE_STRING
:
2729 case ASN1_IA5_STRING
:
2730 return copyContentString(allocator
, derThing
, kCFStringEncodingASCII
, printableOnly
);
2731 case ASN1_UTF8_STRING
:
2732 case ASN1_GENERAL_STRING
:
2733 case ASN1_UNIVERSAL_STRING
:
2734 return copyContentString(allocator
, derThing
, kCFStringEncodingUTF8
, printableOnly
);
2735 case ASN1_T61_STRING
: // 20, also BER_TAG_TELETEX_STRING
2736 case ASN1_VIDEOTEX_STRING
: // 21
2737 case ASN1_VISIBLE_STRING
: // 26
2738 return copyContentString(allocator
, derThing
, kCFStringEncodingISOLatin1
, printableOnly
);
2739 case ASN1_BMP_STRING
: // 30
2740 return copyContentString(allocator
, derThing
, kCFStringEncodingUTF16
, printableOnly
);
2741 case ASN1_OCTET_STRING
:
2742 return printableOnly
? NULL
:
2743 copyBlobString(allocator
, SEC_BYTE_STRING_KEY
, SEC_BYTES_KEY
,
2744 derThing
, localized
);
2745 case ASN1_BIT_STRING
:
2746 return printableOnly
? NULL
:
2747 copyBlobString(allocator
, SEC_BIT_STRING_KEY
, SEC_BITS_KEY
,
2748 derThing
, localized
);
2749 case ASN1_CONSTR_SEQUENCE
:
2750 return printableOnly
? NULL
:
2751 copyBlobString(allocator
, SEC_SEQUENCE_KEY
, SEC_BYTES_KEY
,
2752 derThing
, localized
);
2753 case ASN1_CONSTR_SET
:
2754 return printableOnly
? NULL
:
2755 copyBlobString(allocator
, SEC_SET_KEY
, SEC_BYTES_KEY
,
2756 derThing
, localized
);
2757 case ASN1_OBJECT_ID
:
2758 return printableOnly
? NULL
: copyOidDescription(allocator
, derThing
, localized
);
2760 if (printableOnly
) {
2763 CFStringRef fmt
= (localized
) ?
2764 SecCopyCertString(SEC_NOT_DISPLAYED_KEY
) : SEC_NOT_DISPLAYED_KEY
;
2765 if (!fmt
) { return NULL
; }
2766 CFStringRef result
= CFStringCreateWithFormat(allocator
, NULL
, fmt
,
2767 (unsigned long)tag
, (unsigned long)derThing
->length
);
2774 static CFStringRef
copyDERThingDescription(CFAllocatorRef allocator
,
2775 const DERItem
*derThing
, bool printableOnly
, bool localized
) {
2776 DERDecodedInfo decoded
;
2779 drtn
= DERDecodeItem(derThing
, &decoded
);
2781 /* TODO: Perhaps put something in the label saying we couldn't parse
2783 return printableOnly
? NULL
: copyHexDescription(allocator
, derThing
);
2785 return copyDERThingContentDescription(allocator
, decoded
.tag
,
2786 &decoded
.content
, false, localized
);
2790 static void appendDERThingProperty(CFMutableArrayRef properties
,
2791 CFStringRef label
, CFStringRef localizedLabel
,
2792 const DERItem
*derThing
, bool localized
) {
2793 CFStringRef value
= copyDERThingDescription(CFGetAllocator(properties
),
2794 derThing
, false, localized
);
2796 appendProperty(properties
, kSecPropertyTypeString
, label
, localizedLabel
,
2799 CFReleaseSafe(value
);
2802 static OSStatus
appendRDNProperty(void *context
, const DERItem
*rdnType
,
2803 const DERItem
*rdnValue
, CFIndex rdnIX
,
2805 CFMutableArrayRef properties
= (CFMutableArrayRef
)context
;
2807 /* If there is more than one value pair we create a subsection for the
2808 second pair, and append things to the subsection for subsequent
2810 CFIndex lastIX
= CFArrayGetCount(properties
) - 1;
2811 CFTypeRef lastValue
= CFArrayGetValueAtIndex(properties
, lastIX
);
2813 /* Since this is the second rdn pair for a given rdn, we setup a
2814 new subsection for this rdn. We remove the first property
2815 from the properties array and make it the first element in the
2816 subsection instead. */
2817 CFMutableArrayRef rdn_props
= CFArrayCreateMutable(
2818 CFGetAllocator(properties
), 0, &kCFTypeArrayCallBacks
);
2819 CFArrayAppendValue(rdn_props
, lastValue
);
2820 CFArrayRemoveValueAtIndex(properties
, lastIX
);
2821 appendProperty(properties
, kSecPropertyTypeSection
, NULL
, NULL
,
2822 rdn_props
, localized
);
2823 properties
= rdn_props
;
2824 // rdn_props is now retained by the original properties array
2825 CFReleaseSafe(rdn_props
);
2827 /* Since this is the third or later rdn pair we have already
2828 created a subsection in the top level properties array. Instead
2829 of appending to that directly we append to the array inside the
2831 properties
= (CFMutableArrayRef
)CFDictionaryGetValue(
2832 (CFDictionaryRef
)lastValue
, kSecPropertyKeyValue
);
2836 /* Finally we append the new rdn value to the property array. */
2838 SecDERItemCopyOIDDecimalRepresentation(CFGetAllocator(properties
),
2840 CFStringRef localizedLabel
= copyOidDescription(CFGetAllocator(properties
),
2841 rdnType
, localized
);
2842 appendDERThingProperty(properties
, label
, localizedLabel
,
2843 rdnValue
, localized
);
2844 CFReleaseSafe(label
);
2845 CFReleaseSafe(localizedLabel
);
2846 return errSecSuccess
;
2849 static CFArrayRef
createPropertiesForRDNContent(CFAllocatorRef allocator
,
2850 const DERItem
*rdnSetContent
, bool localized
) {
2851 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2852 &kCFTypeArrayCallBacks
);
2853 OSStatus status
= parseRDNContent(rdnSetContent
, properties
,
2854 appendRDNProperty
, localized
);
2856 CFArrayRemoveAllValues(properties
);
2857 appendInvalidProperty(properties
, SEC_RDN_KEY
, rdnSetContent
,
2865 From rfc3739 - 3.1.2. Subject
2867 When parsing the subject here are some tips for a short name of the cert.
2868 Choice I: commonName
2869 Choice II: givenName
2870 Choice III: pseudonym
2872 The commonName attribute value SHALL, when present, contain a name
2873 of the subject. This MAY be in the subject's preferred
2874 presentation format, or a format preferred by the CA, or some
2875 other format. Pseudonyms, nicknames, and names with spelling
2876 other than defined by the registered name MAY be used. To
2877 understand the nature of the name presented in commonName,
2878 complying applications MAY have to examine present values of the
2879 givenName and surname attributes, or the pseudonym attribute.
2882 static CFArrayRef
createPropertiesForX501NameContent(CFAllocatorRef allocator
,
2883 const DERItem
*x501NameContent
, bool localized
) {
2884 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2885 &kCFTypeArrayCallBacks
);
2886 OSStatus status
= parseX501NameContent(x501NameContent
, properties
,
2887 appendRDNProperty
, localized
);
2889 CFArrayRemoveAllValues(properties
);
2890 appendInvalidProperty(properties
, SEC_X501_NAME_KEY
,
2891 x501NameContent
, localized
);
2897 static CFArrayRef
createPropertiesForX501Name(CFAllocatorRef allocator
,
2898 const DERItem
*x501Name
, bool localized
) {
2899 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2900 &kCFTypeArrayCallBacks
);
2901 OSStatus status
= parseX501Name(x501Name
, properties
, appendRDNProperty
, localized
);
2903 CFArrayRemoveAllValues(properties
);
2904 appendInvalidProperty(properties
, SEC_X501_NAME_KEY
,
2905 x501Name
, localized
);
2911 static void appendIntegerProperty(CFMutableArrayRef properties
,
2912 CFStringRef label
, const DERItem
*integer
, bool localized
) {
2913 CFStringRef string
= copyIntegerContentDescription(
2914 CFGetAllocator(properties
), integer
);
2915 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
2920 static void appendBoolProperty(CFMutableArrayRef properties
,
2921 CFStringRef label
, bool boolean
, bool localized
) {
2922 CFStringRef key
= (boolean
) ? SEC_YES_KEY
: SEC_NO_KEY
;
2923 CFStringRef value
= (localized
) ? SecCopyCertString(key
) : key
;
2924 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
2929 static void appendBooleanProperty(CFMutableArrayRef properties
,
2930 CFStringRef label
, const DERItem
*boolean
,
2931 bool defaultValue
, bool localized
) {
2933 DERReturn drtn
= DERParseBooleanWithDefault(boolean
, defaultValue
, &result
);
2935 /* Couldn't parse boolean; dump the raw unparsed data as hex. */
2936 appendInvalidProperty(properties
, label
, boolean
, localized
);
2938 appendBoolProperty(properties
, label
, result
, localized
);
2942 static void appendSerialNumberProperty(CFMutableArrayRef parent
, CFStringRef label
,
2943 DERItem
*serialNum
, bool localized
) {
2944 CFAllocatorRef allocator
= CFGetAllocator(parent
);
2945 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
2947 if (serialNum
->length
) {
2948 appendIntegerProperty(properties
, SEC_SERIAL_NUMBER_KEY
,
2949 serialNum
, localized
);
2950 appendProperty(parent
, kSecPropertyTypeSection
, label
, NULL
,
2951 properties
, localized
);
2954 CFReleaseNull(properties
);
2957 static void appendBitStringContentNames(CFMutableArrayRef properties
,
2958 CFStringRef label
, const DERItem
*bitStringContent
,
2959 const CFStringRef
*names
, CFIndex namesCount
,
2961 DERSize len
= bitStringContent
->length
- 1;
2962 require_quiet(len
== 1 || len
== 2, badDER
);
2963 DERByte numUnusedBits
= bitStringContent
->data
[0];
2964 require_quiet(numUnusedBits
< 8, badDER
);
2965 uint_fast16_t bits
= 8 * len
- numUnusedBits
;
2966 require_quiet(bits
<= (uint_fast16_t)namesCount
, badDER
);
2967 uint_fast16_t value
= bitStringContent
->data
[1];
2970 value
= (value
<< 8) + bitStringContent
->data
[2];
2976 CFStringRef fmt
= (localized
) ?
2977 SecCopyCertString(SEC_STRING_LIST_KEY
) : SEC_STRING_LIST_KEY
;
2978 CFStringRef string
= NULL
;
2979 for (ix
= 0; ix
< bits
; ++ix
) {
2983 CFStringCreateWithFormat(CFGetAllocator(properties
),
2984 NULL
, fmt
, string
, names
[ix
]);
2995 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
2996 string
? string
: CFSTR(""), localized
);
2997 CFReleaseSafe(string
);
3000 appendInvalidProperty(properties
, label
, bitStringContent
, localized
);
3003 static void appendBitStringNames(CFMutableArrayRef properties
,
3004 CFStringRef label
, const DERItem
*bitString
,
3005 const CFStringRef
*names
, CFIndex namesCount
,
3007 DERDecodedInfo bitStringContent
;
3008 DERReturn drtn
= DERDecodeItem(bitString
, &bitStringContent
);
3009 require_noerr_quiet(drtn
, badDER
);
3010 require_quiet(bitStringContent
.tag
== ASN1_BIT_STRING
, badDER
);
3011 appendBitStringContentNames(properties
, label
, &bitStringContent
.content
,
3012 names
, namesCount
, localized
);
3015 appendInvalidProperty(properties
, label
, bitString
, localized
);
3018 static void appendKeyUsage(CFMutableArrayRef properties
,
3019 const DERItem
*extnValue
, bool localized
) {
3020 static const CFStringRef usageNames
[] = {
3021 SEC_DIGITAL_SIGNATURE_KEY
,
3022 SEC_NON_REPUDIATION_KEY
,
3023 SEC_KEY_ENCIPHERMENT_KEY
,
3024 SEC_DATA_ENCIPHERMENT_KEY
,
3025 SEC_KEY_AGREEMENT_KEY
,
3028 SEC_ENCIPHER_ONLY_KEY
,
3029 SEC_DECIPHER_ONLY_KEY
3031 appendBitStringNames(properties
, SEC_USAGE_KEY
, extnValue
,
3032 usageNames
, array_size(usageNames
), localized
);
3035 static void appendPrivateKeyUsagePeriod(CFMutableArrayRef properties
,
3036 const DERItem
*extnValue
, bool localized
) {
3037 DERPrivateKeyUsagePeriod pkup
;
3038 DERReturn drtn
= DERParseSequence(extnValue
,
3039 DERNumPrivateKeyUsagePeriodItemSpecs
, DERPrivateKeyUsagePeriodItemSpecs
,
3040 &pkup
, sizeof(pkup
));
3041 require_noerr_quiet(drtn
, badDER
);
3042 if (pkup
.notBefore
.length
) {
3043 appendDateContentProperty(properties
, SEC_NOT_VALID_BEFORE_KEY
,
3044 ASN1_GENERALIZED_TIME
, &pkup
.notBefore
, localized
);
3046 if (pkup
.notAfter
.length
) {
3047 appendDateContentProperty(properties
, SEC_NOT_VALID_AFTER_KEY
,
3048 ASN1_GENERALIZED_TIME
, &pkup
.notAfter
, localized
);
3052 appendInvalidProperty(properties
, SEC_PRIVATE_KU_PERIOD_KEY
,
3053 extnValue
, localized
);
3056 static void appendStringContentProperty(CFMutableArrayRef properties
,
3057 CFStringRef label
, const DERItem
*stringContent
,
3058 CFStringEncoding encoding
, bool localized
) {
3059 CFStringRef string
= CFStringCreateWithBytes(CFGetAllocator(properties
),
3060 stringContent
->data
, stringContent
->length
, encoding
, FALSE
);
3062 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
3066 appendInvalidProperty(properties
, label
, stringContent
, localized
);
3071 OtherName ::= SEQUENCE {
3072 type-id OBJECT IDENTIFIER,
3073 value [0] EXPLICIT ANY DEFINED BY type-id }
3075 static void appendOtherNameContentProperty(CFMutableArrayRef properties
,
3076 const DERItem
*otherNameContent
, bool localized
) {
3078 DERReturn drtn
= DERParseSequenceContent(otherNameContent
,
3079 DERNumOtherNameItemSpecs
, DEROtherNameItemSpecs
,
3081 require_noerr_quiet(drtn
, badDER
);
3082 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3084 SecDERItemCopyOIDDecimalRepresentation(allocator
, &on
.typeIdentifier
);
3085 CFStringRef localizedLabel
=
3086 copyOidDescription(allocator
, &on
.typeIdentifier
, localized
);
3087 CFStringRef value_string
= copyDERThingDescription(allocator
, &on
.value
,
3090 appendProperty(properties
, kSecPropertyTypeString
, label
,
3091 localizedLabel
, value_string
, localized
);
3093 appendUnparsedProperty(properties
, label
, localizedLabel
,
3094 &on
.value
, localized
);
3096 CFReleaseSafe(value_string
);
3097 CFReleaseSafe(label
);
3098 CFReleaseSafe(localizedLabel
);
3101 appendInvalidProperty(properties
, SEC_OTHER_NAME_KEY
,
3102 otherNameContent
, localized
);
3106 GeneralName ::= CHOICE {
3107 otherName [0] OtherName,
3108 rfc822Name [1] IA5String,
3109 dNSName [2] IA5String,
3110 x400Address [3] ORAddress,
3111 directoryName [4] Name,
3112 ediPartyName [5] EDIPartyName,
3113 uniformResourceIdentifier [6] IA5String,
3114 iPAddress [7] OCTET STRING,
3115 registeredID [8] OBJECT IDENTIFIER}
3117 EDIPartyName ::= SEQUENCE {
3118 nameAssigner [0] DirectoryString OPTIONAL,
3119 partyName [1] DirectoryString }
3121 static bool appendGeneralNameContentProperty(CFMutableArrayRef properties
,
3122 DERTag tag
, const DERItem
*generalName
, bool localized
) {
3124 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
3125 appendOtherNameContentProperty(properties
, generalName
, localized
);
3127 case ASN1_CONTEXT_SPECIFIC
| 1:
3129 appendStringContentProperty(properties
, SEC_EMAIL_ADDRESS_KEY
,
3130 generalName
, kCFStringEncodingASCII
, localized
);
3132 case ASN1_CONTEXT_SPECIFIC
| 2:
3134 appendStringContentProperty(properties
, SEC_DNS_NAME_KEY
, generalName
,
3135 kCFStringEncodingASCII
, localized
);
3137 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 3:
3138 appendUnparsedProperty(properties
, SEC_X400_ADDRESS_KEY
, NULL
,
3139 generalName
, localized
);
3141 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 4:
3143 CFArrayRef directory_plist
=
3144 createPropertiesForX501Name(CFGetAllocator(properties
),
3145 generalName
, localized
);
3146 appendProperty(properties
, kSecPropertyTypeSection
,
3147 SEC_DIRECTORY_NAME_KEY
, NULL
, directory_plist
, localized
);
3148 CFRelease(directory_plist
);
3151 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 5:
3152 appendUnparsedProperty(properties
, SEC_EDI_PARTY_NAME_KEY
, NULL
,
3153 generalName
, localized
);
3155 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
3156 /* Technically I don't think this is valid, but there are certs out
3157 in the wild that use a constructed IA5String. In particular the
3158 VeriSign Time Stamping Authority CA.cer does this. */
3159 appendURLProperty(properties
, SEC_URI_KEY
, generalName
, localized
);
3161 case ASN1_CONTEXT_SPECIFIC
| 6:
3162 appendURLContentProperty(properties
, SEC_URI_KEY
, generalName
, localized
);
3164 case ASN1_CONTEXT_SPECIFIC
| 7:
3165 appendIPAddressContentProperty(properties
, SEC_IP_ADDRESS_KEY
,
3166 generalName
, localized
);
3168 case ASN1_CONTEXT_SPECIFIC
| 8:
3169 appendOIDProperty(properties
, SEC_REGISTERED_ID_KEY
, NULL
,
3170 generalName
, localized
);
3181 static void appendGeneralNameProperty(CFMutableArrayRef properties
,
3182 const DERItem
*generalName
, bool localized
) {
3183 DERDecodedInfo generalNameContent
;
3184 DERReturn drtn
= DERDecodeItem(generalName
, &generalNameContent
);
3185 require_noerr_quiet(drtn
, badDER
);
3186 if (appendGeneralNameContentProperty(properties
, generalNameContent
.tag
,
3187 &generalNameContent
.content
, localized
))
3190 appendInvalidProperty(properties
, SEC_GENERAL_NAME_KEY
,
3191 generalName
, localized
);
3196 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
3198 static void appendGeneralNamesContent(CFMutableArrayRef properties
,
3199 const DERItem
*generalNamesContent
, bool localized
) {
3201 DERReturn drtn
= DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
);
3202 require_noerr_quiet(drtn
, badDER
);
3203 DERDecodedInfo generalNameContent
;
3204 while ((drtn
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) ==
3206 if (!appendGeneralNameContentProperty(properties
,
3207 generalNameContent
.tag
, &generalNameContent
.content
, localized
)) {
3211 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3214 appendInvalidProperty(properties
, SEC_GENERAL_NAMES_KEY
,
3215 generalNamesContent
, localized
);
3218 static void appendGeneralNames(CFMutableArrayRef properties
,
3219 const DERItem
*generalNames
, bool localized
) {
3220 DERDecodedInfo generalNamesContent
;
3221 DERReturn drtn
= DERDecodeItem(generalNames
, &generalNamesContent
);
3222 require_noerr_quiet(drtn
, badDER
);
3223 require_quiet(generalNamesContent
.tag
== ASN1_CONSTR_SEQUENCE
,
3225 appendGeneralNamesContent(properties
, &generalNamesContent
.content
,
3229 appendInvalidProperty(properties
, SEC_GENERAL_NAMES_KEY
,
3230 generalNames
, localized
);
3234 BasicConstraints ::= SEQUENCE {
3235 cA BOOLEAN DEFAULT FALSE,
3236 pathLenConstraint INTEGER (0..MAX) OPTIONAL }
3238 static void appendBasicConstraints(CFMutableArrayRef properties
,
3239 const DERItem
*extnValue
, bool localized
) {
3240 DERBasicConstraints basicConstraints
;
3241 DERReturn drtn
= DERParseSequence(extnValue
,
3242 DERNumBasicConstraintsItemSpecs
, DERBasicConstraintsItemSpecs
,
3243 &basicConstraints
, sizeof(basicConstraints
));
3244 require_noerr_quiet(drtn
, badDER
);
3246 appendBooleanProperty(properties
, SEC_CERT_AUTHORITY_KEY
,
3247 &basicConstraints
.cA
, false, localized
);
3249 if (basicConstraints
.pathLenConstraint
.length
!= 0) {
3250 appendIntegerProperty(properties
, SEC_PATH_LEN_CONSTRAINT_KEY
,
3251 &basicConstraints
.pathLenConstraint
, localized
);
3255 appendInvalidProperty(properties
, SEC_BASIC_CONSTRAINTS_KEY
,
3256 extnValue
, localized
);
3260 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
3262 * NameConstraints ::= SEQUENCE {
3263 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
3264 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
3266 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
3268 * GeneralSubtree ::= SEQUENCE {
3270 * minimum [0] BaseDistance DEFAULT 0,
3271 * maximum [1] BaseDistance OPTIONAL }
3273 * BaseDistance ::= INTEGER (0..MAX)
3275 static void appendNameConstraints(CFMutableArrayRef properties
,
3276 const DERItem
*extnValue
, bool localized
) {
3277 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3278 DERNameConstraints nc
;
3280 drtn
= DERParseSequence(extnValue
,
3281 DERNumNameConstraintsItemSpecs
,
3282 DERNameConstraintsItemSpecs
,
3284 require_noerr_quiet(drtn
, badDER
);
3285 if (nc
.permittedSubtrees
.length
) {
3287 require_noerr_quiet(DERDecodeSeqContentInit(&nc
.permittedSubtrees
, &gsSeq
), badDER
);
3288 DERDecodedInfo gsContent
;
3289 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
3290 DERGeneralSubtree derGS
;
3291 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
3292 drtn
= DERParseSequenceContent(&gsContent
.content
,
3293 DERNumGeneralSubtreeItemSpecs
,
3294 DERGeneralSubtreeItemSpecs
,
3295 &derGS
, sizeof(derGS
));
3296 require_noerr_quiet(drtn
, badDER
);
3297 if (derGS
.minimum
.length
) {
3298 appendIntegerProperty(properties
, SEC_PERMITTED_MINIMUM_KEY
,
3299 &derGS
.minimum
, localized
);
3301 if (derGS
.maximum
.length
) {
3302 appendIntegerProperty(properties
, SEC_PERMITTED_MAXIMUM_KEY
,
3303 &derGS
.maximum
, localized
);
3305 if (derGS
.generalName
.length
) {
3306 CFMutableArrayRef base
= CFArrayCreateMutable(allocator
, 0,
3307 &kCFTypeArrayCallBacks
);
3308 appendProperty(properties
, kSecPropertyTypeSection
,
3309 SEC_PERMITTED_NAME_KEY
, NULL
, base
, localized
);
3310 appendGeneralNameProperty(base
, &derGS
.generalName
, localized
);
3314 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3316 if (nc
.excludedSubtrees
.length
) {
3318 require_noerr_quiet(DERDecodeSeqContentInit(&nc
.excludedSubtrees
, &gsSeq
), badDER
);
3319 DERDecodedInfo gsContent
;
3320 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
3321 DERGeneralSubtree derGS
;
3322 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
3323 drtn
= DERParseSequenceContent(&gsContent
.content
,
3324 DERNumGeneralSubtreeItemSpecs
,
3325 DERGeneralSubtreeItemSpecs
,
3326 &derGS
, sizeof(derGS
));
3327 require_noerr_quiet(drtn
, badDER
);
3328 if (derGS
.minimum
.length
) {
3329 appendIntegerProperty(properties
, SEC_EXCLUDED_MINIMUM_KEY
,
3330 &derGS
.minimum
, localized
);
3332 if (derGS
.maximum
.length
) {
3333 appendIntegerProperty(properties
, SEC_EXCLUDED_MAXIMUM_KEY
,
3334 &derGS
.maximum
, localized
);
3336 if (derGS
.generalName
.length
) {
3337 CFMutableArrayRef base
= CFArrayCreateMutable(allocator
, 0,
3338 &kCFTypeArrayCallBacks
);
3339 appendProperty(properties
, kSecPropertyTypeSection
,
3340 SEC_EXCLUDED_NAME_KEY
, NULL
, base
, localized
);
3341 appendGeneralNameProperty(base
, &derGS
.generalName
, localized
);
3345 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3350 appendInvalidProperty(properties
, SEC_NAME_CONSTRAINTS_KEY
,
3351 extnValue
, localized
);
3355 CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
3357 DistributionPoint ::= SEQUENCE {
3358 distributionPoint [0] DistributionPointName OPTIONAL,
3359 reasons [1] ReasonFlags OPTIONAL,
3360 cRLIssuer [2] GeneralNames OPTIONAL }
3362 DistributionPointName ::= CHOICE {
3363 fullName [0] GeneralNames,
3364 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
3366 ReasonFlags ::= BIT STRING {
3370 affiliationChanged (3),
3372 cessationOfOperation (5),
3373 certificateHold (6),
3374 privilegeWithdrawn (7),
3377 static void appendCrlDistributionPoints(CFMutableArrayRef properties
,
3378 const DERItem
*extnValue
, bool localized
) {
3379 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3382 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &dpSeq
);
3383 require_noerr_quiet(drtn
, badDER
);
3384 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3385 DERDecodedInfo dpSeqContent
;
3386 while ((drtn
= DERDecodeSeqNext(&dpSeq
, &dpSeqContent
)) == DR_Success
) {
3387 require_quiet(dpSeqContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3388 DERDistributionPoint dp
;
3389 drtn
= DERParseSequenceContent(&dpSeqContent
.content
,
3390 DERNumDistributionPointItemSpecs
,
3391 DERDistributionPointItemSpecs
,
3393 require_noerr_quiet(drtn
, badDER
);
3394 if (dp
.distributionPoint
.length
) {
3395 DERDecodedInfo distributionPointName
;
3396 drtn
= DERDecodeItem(&dp
.distributionPoint
, &distributionPointName
);
3397 require_noerr_quiet(drtn
, badDER
);
3398 if (distributionPointName
.tag
==
3399 (ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0)) {
3401 appendGeneralNamesContent(properties
,
3402 &distributionPointName
.content
, localized
);
3403 } else if (distributionPointName
.tag
==
3404 (ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1)) {
3405 CFArrayRef rdn_props
= createPropertiesForRDNContent(allocator
,
3406 &dp
.reasons
, localized
);
3407 appendProperty(properties
, kSecPropertyTypeSection
,
3408 SEC_NAME_REL_CRL_ISSUER_KEY
, NULL
, rdn_props
, localized
);
3409 CFRelease(rdn_props
);
3414 if (dp
.reasons
.length
) {
3415 static const CFStringRef reasonNames
[] = {
3417 SEC_KEY_COMPROMISE_KEY
,
3418 SEC_CA_COMPROMISE_KEY
,
3419 SEC_AFFILIATION_CHANGED_KEY
,
3421 SEC_CESSATION_OF_OPER_KEY
,
3422 SEC_CERTIFICATE_HOLD_KEY
,
3423 SEC_PRIV_WITHDRAWN_KEY
,
3424 SEC_AA_COMPROMISE_KEY
3426 appendBitStringContentNames(properties
, SEC_REASONS_KEY
,
3428 reasonNames
, array_size(reasonNames
), localized
);
3430 if (dp
.cRLIssuer
.length
) {
3431 CFMutableArrayRef crlIssuer
= CFArrayCreateMutable(allocator
, 0,
3432 &kCFTypeArrayCallBacks
);
3433 appendProperty(properties
, kSecPropertyTypeSection
,
3434 SEC_CRL_ISSUER_KEY
, NULL
, crlIssuer
, localized
);
3435 CFRelease(crlIssuer
);
3436 appendGeneralNames(crlIssuer
, &dp
.cRLIssuer
, localized
);
3439 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3442 appendInvalidProperty(properties
, SEC_CRL_DISTR_POINTS_KEY
,
3443 extnValue
, localized
);
3447 Decode a sequence of integers into a comma separated list of ints.
3449 static void appendIntegerSequenceContent(CFMutableArrayRef properties
,
3450 CFStringRef label
, const DERItem
*intSequenceContent
,
3452 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3454 CFStringRef fmt
= NULL
, value
= NULL
, intDesc
= NULL
, v
= NULL
;
3455 DERReturn drtn
= DERDecodeSeqContentInit(intSequenceContent
, &intSeq
);
3456 require_noerr_quiet(drtn
, badDER
);
3457 DERDecodedInfo intContent
;
3459 SecCopyCertString(SEC_STRING_LIST_KEY
) : SEC_STRING_LIST_KEY
;
3460 require_quiet(fmt
, badDER
);
3461 while ((drtn
= DERDecodeSeqNext(&intSeq
, &intContent
)) == DR_Success
) {
3462 require_quiet(intContent
.tag
== ASN1_INTEGER
, badDER
);
3463 intDesc
= copyIntegerContentDescription(
3464 allocator
, &intContent
.content
);
3465 require_quiet(intDesc
, badDER
);
3467 v
= CFStringCreateWithFormat(allocator
, NULL
, fmt
, value
, intDesc
);
3468 CFReleaseNull(value
);
3469 require_quiet(v
, badDER
);
3472 value
= CFStringCreateMutableCopy(allocator
, 0, intDesc
);
3473 require_quiet(value
, badDER
);
3475 CFReleaseNull(intDesc
);
3478 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3480 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
3485 /* DROPTHOUGH if !value. */
3488 CFReleaseNull(intDesc
);
3489 CFReleaseNull(value
);
3490 appendInvalidProperty(properties
, label
, intSequenceContent
, localized
);
3493 static void appendCertificatePolicies(CFMutableArrayRef properties
,
3494 const DERItem
*extnValue
, bool localized
) {
3495 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3496 CFStringRef piLabel
= NULL
, piFmt
= NULL
, lpiLabel
= NULL
;
3497 CFStringRef pqLabel
= NULL
, pqFmt
= NULL
, lpqLabel
= NULL
;
3500 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &piSeq
);
3501 require_noerr_quiet(drtn
, badDER
);
3502 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3503 DERDecodedInfo piContent
;
3505 while ((drtn
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) {
3506 require_quiet(piContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3507 DERPolicyInformation pi
;
3508 drtn
= DERParseSequenceContent(&piContent
.content
,
3509 DERNumPolicyInformationItemSpecs
,
3510 DERPolicyInformationItemSpecs
,
3512 require_noerr_quiet(drtn
, badDER
);
3513 piLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3514 SEC_POLICY_IDENTIFIER_KEY
, pin
);
3515 require_quiet(piLabel
, badDER
);
3516 piFmt
= (localized
) ?
3517 SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY
) : SEC_POLICY_IDENTIFIER_KEY
;
3518 require_quiet(piFmt
, badDER
);
3519 lpiLabel
= CFStringCreateWithFormat(allocator
, NULL
, piFmt
, pin
++);
3520 require_quiet(lpiLabel
, badDER
);
3521 CFReleaseNull(piFmt
);
3522 appendOIDProperty(properties
, piLabel
, lpiLabel
,
3523 &pi
.policyIdentifier
, localized
);
3524 CFReleaseNull(piLabel
);
3525 CFReleaseNull(lpiLabel
);
3526 if (pi
.policyQualifiers
.length
== 0)
3530 drtn
= DERDecodeSeqContentInit(&pi
.policyQualifiers
, &pqSeq
);
3531 require_noerr_quiet(drtn
, badDER
);
3532 DERDecodedInfo pqContent
;
3534 while ((drtn
= DERDecodeSeqNext(&pqSeq
, &pqContent
)) == DR_Success
) {
3535 DERPolicyQualifierInfo pqi
;
3536 drtn
= DERParseSequenceContent(&pqContent
.content
,
3537 DERNumPolicyQualifierInfoItemSpecs
,
3538 DERPolicyQualifierInfoItemSpecs
,
3540 require_noerr_quiet(drtn
, badDER
);
3541 DERDecodedInfo qualifierContent
;
3542 drtn
= DERDecodeItem(&pqi
.qualifier
, &qualifierContent
);
3543 require_noerr_quiet(drtn
, badDER
);
3544 pqLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3545 SEC_POLICY_QUALIFIER_KEY
, pqn
);
3546 require_quiet(pqLabel
, badDER
);
3547 pqFmt
= (localized
) ?
3548 SecCopyCertString(SEC_POLICY_QUALIFIER_KEY
) : SEC_POLICY_QUALIFIER_KEY
;
3549 require_quiet(pqFmt
, badDER
);
3550 lpqLabel
= CFStringCreateWithFormat(allocator
, NULL
, pqFmt
, pqn
++);
3551 require_quiet(lpqLabel
, badDER
);
3552 CFReleaseNull(pqFmt
);
3553 appendOIDProperty(properties
, pqLabel
, lpqLabel
,
3554 &pqi
.policyQualifierID
, localized
);
3555 CFReleaseNull(pqLabel
);
3556 CFReleaseNull(lpqLabel
);
3557 if (DEROidCompare(&oidQtCps
, &pqi
.policyQualifierID
)) {
3558 require_quiet(qualifierContent
.tag
== ASN1_IA5_STRING
, badDER
);
3559 appendURLContentProperty(properties
, SEC_CPS_URI_KEY
,
3560 &qualifierContent
.content
, localized
);
3561 } else if (DEROidCompare(&oidQtUNotice
, &pqi
.policyQualifierID
)) {
3562 require_quiet(qualifierContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3564 drtn
= DERParseSequenceContent(&qualifierContent
.content
,
3565 DERNumUserNoticeItemSpecs
,
3566 DERUserNoticeItemSpecs
,
3568 require_noerr_quiet(drtn
, badDER
);
3569 if (un
.noticeRef
.length
) {
3570 DERNoticeReference nr
;
3571 drtn
= DERParseSequenceContent(&un
.noticeRef
,
3572 DERNumNoticeReferenceItemSpecs
,
3573 DERNoticeReferenceItemSpecs
,
3575 require_noerr_quiet(drtn
, badDER
);
3576 appendDERThingProperty(properties
,
3577 SEC_ORGANIZATION_KEY
, NULL
,
3578 &nr
.organization
, localized
);
3579 appendIntegerSequenceContent(properties
,
3580 SEC_NOTICE_NUMBERS_KEY
, &nr
.noticeNumbers
, localized
);
3582 if (un
.explicitText
.length
) {
3583 appendDERThingProperty(properties
, SEC_EXPLICIT_TEXT_KEY
,
3584 NULL
, &un
.explicitText
, localized
);
3587 appendUnparsedProperty(properties
, SEC_QUALIFIER_KEY
, NULL
,
3588 &pqi
.qualifier
, localized
);
3591 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3593 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3596 CFReleaseNull(piFmt
);
3597 CFReleaseNull(piLabel
);
3598 CFReleaseNull(lpiLabel
);
3599 CFReleaseNull(pqFmt
);
3600 CFReleaseNull(pqLabel
);
3601 CFReleaseNull(lpqLabel
);
3602 appendInvalidProperty(properties
, SEC_CERT_POLICIES_KEY
,
3603 extnValue
, localized
);
3606 static void appendSubjectKeyIdentifier(CFMutableArrayRef properties
,
3607 const DERItem
*extnValue
, bool localized
) {
3609 DERDecodedInfo keyIdentifier
;
3610 drtn
= DERDecodeItem(extnValue
, &keyIdentifier
);
3611 require_noerr_quiet(drtn
, badDER
);
3612 require_quiet(keyIdentifier
.tag
== ASN1_OCTET_STRING
, badDER
);
3613 appendDataProperty(properties
, SEC_KEY_IDENTIFIER_KEY
, NULL
,
3614 &keyIdentifier
.content
, localized
);
3618 appendInvalidProperty(properties
, SEC_SUBJ_KEY_ID_KEY
,
3619 extnValue
, localized
);
3623 AuthorityKeyIdentifier ::= SEQUENCE {
3624 keyIdentifier [0] KeyIdentifier OPTIONAL,
3625 authorityCertIssuer [1] GeneralNames OPTIONAL,
3626 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
3627 -- authorityCertIssuer and authorityCertSerialNumber MUST both
3628 -- be present or both be absent
3630 KeyIdentifier ::= OCTET STRING
3632 static void appendAuthorityKeyIdentifier(CFMutableArrayRef properties
,
3633 const DERItem
*extnValue
, bool localized
) {
3634 DERAuthorityKeyIdentifier akid
;
3636 drtn
= DERParseSequence(extnValue
,
3637 DERNumAuthorityKeyIdentifierItemSpecs
,
3638 DERAuthorityKeyIdentifierItemSpecs
,
3639 &akid
, sizeof(akid
));
3640 require_noerr_quiet(drtn
, badDER
);
3641 if (akid
.keyIdentifier
.length
) {
3642 appendDataProperty(properties
, SEC_KEY_IDENTIFIER_KEY
, NULL
,
3643 &akid
.keyIdentifier
, localized
);
3645 if (akid
.authorityCertIssuer
.length
||
3646 akid
.authorityCertSerialNumber
.length
) {
3647 require_quiet(akid
.authorityCertIssuer
.length
&&
3648 akid
.authorityCertSerialNumber
.length
, badDER
);
3649 /* Perhaps put in a subsection called Authority Certificate Issuer. */
3650 appendGeneralNamesContent(properties
,
3651 &akid
.authorityCertIssuer
, localized
);
3652 appendIntegerProperty(properties
, SEC_AUTH_CERT_SERIAL_KEY
,
3653 &akid
.authorityCertSerialNumber
, localized
);
3658 appendInvalidProperty(properties
, SEC_AUTHORITY_KEY_ID_KEY
,
3659 extnValue
, localized
);
3663 PolicyConstraints ::= SEQUENCE {
3664 requireExplicitPolicy [0] SkipCerts OPTIONAL,
3665 inhibitPolicyMapping [1] SkipCerts OPTIONAL }
3667 SkipCerts ::= INTEGER (0..MAX)
3669 static void appendPolicyConstraints(CFMutableArrayRef properties
,
3670 const DERItem
*extnValue
, bool localized
) {
3671 DERPolicyConstraints pc
;
3673 drtn
= DERParseSequence(extnValue
,
3674 DERNumPolicyConstraintsItemSpecs
,
3675 DERPolicyConstraintsItemSpecs
,
3677 require_noerr_quiet(drtn
, badDER
);
3678 if (pc
.requireExplicitPolicy
.length
) {
3679 appendIntegerProperty(properties
, SEC_REQUIRE_EXPL_POLICY_KEY
,
3680 &pc
.requireExplicitPolicy
, localized
);
3682 if (pc
.inhibitPolicyMapping
.length
) {
3683 appendIntegerProperty(properties
, SEC_INHIBIT_POLICY_MAP_KEY
,
3684 &pc
.inhibitPolicyMapping
, localized
);
3690 appendInvalidProperty(properties
, SEC_POLICY_CONSTRAINTS_KEY
,
3691 extnValue
, localized
);
3695 extendedKeyUsage EXTENSION ::= {
3696 SYNTAX SEQUENCE SIZE (1..MAX) OF KeyPurposeId
3697 IDENTIFIED BY id-ce-extKeyUsage }
3699 KeyPurposeId ::= OBJECT IDENTIFIER
3701 static void appendExtendedKeyUsage(CFMutableArrayRef properties
,
3702 const DERItem
*extnValue
, bool localized
) {
3705 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &derSeq
);
3706 require_noerr_quiet(drtn
, badDER
);
3707 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3708 DERDecodedInfo currDecoded
;
3709 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
3710 require_quiet(currDecoded
.tag
== ASN1_OBJECT_ID
, badDER
);
3711 appendOIDProperty(properties
, SEC_PURPOSE_KEY
, NULL
,
3712 &currDecoded
.content
, localized
);
3714 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3717 appendInvalidProperty(properties
, SEC_EXTENDED_KEY_USAGE_KEY
,
3718 extnValue
, localized
);
3722 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
3724 AuthorityInfoAccessSyntax ::=
3725 SEQUENCE SIZE (1..MAX) OF AccessDescription
3727 AccessDescription ::= SEQUENCE {
3728 accessMethod OBJECT IDENTIFIER,
3729 accessLocation GeneralName }
3731 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
3733 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
3735 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
3737 static void appendInfoAccess(CFMutableArrayRef properties
,
3738 const DERItem
*extnValue
, bool localized
) {
3741 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &adSeq
);
3742 require_noerr_quiet(drtn
, badDER
);
3743 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3744 DERDecodedInfo adContent
;
3745 while ((drtn
= DERDecodeSeqNext(&adSeq
, &adContent
)) == DR_Success
) {
3746 require_quiet(adContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3747 DERAccessDescription ad
;
3748 drtn
= DERParseSequenceContent(&adContent
.content
,
3749 DERNumAccessDescriptionItemSpecs
,
3750 DERAccessDescriptionItemSpecs
,
3752 require_noerr_quiet(drtn
, badDER
);
3753 appendOIDProperty(properties
, SEC_ACCESS_METHOD_KEY
, NULL
,
3754 &ad
.accessMethod
, localized
);
3755 //TODO: Do something with SEC_ACCESS_LOCATION_KEY
3756 appendGeneralNameProperty(properties
, &ad
.accessLocation
, localized
);
3758 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3761 appendInvalidProperty(properties
, SEC_AUTH_INFO_ACCESS_KEY
,
3762 extnValue
, localized
);
3765 static void appendNetscapeCertType(CFMutableArrayRef properties
,
3766 const DERItem
*extnValue
, bool localized
) {
3767 static const CFStringRef certTypes
[] = {
3771 SEC_OBJECT_SIGNING_KEY
,
3775 SEC_OBJECT_SIGNING_CA_KEY
3777 appendBitStringNames(properties
, SEC_USAGE_KEY
, extnValue
,
3778 certTypes
, array_size(certTypes
), localized
);
3781 static bool appendPrintableDERSequence(CFMutableArrayRef properties
,
3782 CFStringRef label
, const DERItem
*sequence
, bool localized
) {
3785 DERReturn drtn
= DERDecodeSeqInit(sequence
, &tag
, &derSeq
);
3786 require_noerr_quiet(drtn
, badSequence
);
3787 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badSequence
);
3788 DERDecodedInfo currDecoded
;
3789 bool appendedSomething
= false;
3790 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
3791 switch (currDecoded
.tag
)
3794 case ASN1_SEQUENCE
: // 16
3795 case ASN1_SET
: // 17
3796 // skip constructed object lengths
3799 case ASN1_UTF8_STRING
: // 12
3800 case ASN1_NUMERIC_STRING
: // 18
3801 case ASN1_PRINTABLE_STRING
: // 19
3802 case ASN1_T61_STRING
: // 20, also ASN1_TELETEX_STRING
3803 case ASN1_VIDEOTEX_STRING
: // 21
3804 case ASN1_IA5_STRING
: // 22
3805 case ASN1_GRAPHIC_STRING
: // 25
3806 case ASN1_VISIBLE_STRING
: // 26, also ASN1_ISO646_STRING
3807 case ASN1_GENERAL_STRING
: // 27
3808 case ASN1_UNIVERSAL_STRING
: // 28
3810 CFStringRef string
=
3811 copyDERThingContentDescription(CFGetAllocator(properties
),
3812 currDecoded
.tag
, &currDecoded
.content
, false, localized
);
3813 require_quiet(string
, badSequence
);
3815 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
3817 CFReleaseNull(string
);
3818 appendedSomething
= true;
3825 require_quiet(drtn
== DR_EndOfSequence
, badSequence
);
3826 return appendedSomething
;
3831 static void appendExtension(CFMutableArrayRef parent
,
3832 const SecCertificateExtension
*extn
,
3834 CFAllocatorRef allocator
= CFGetAllocator(parent
);
3835 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
3836 &kCFTypeArrayCallBacks
);
3838 *extnID
= &extn
->extnID
,
3839 *extnValue
= &extn
->extnValue
;
3840 CFStringRef label
= NULL
;
3841 CFStringRef localizedLabel
= NULL
;
3843 appendBoolProperty(properties
, SEC_CRITICAL_KEY
, extn
->critical
, localized
);
3844 require_quiet(extnID
, xit
);
3846 bool handled
= true;
3847 /* Extensions that we know how to handle ourselves... */
3848 if (extnID
->length
== oidSubjectKeyIdentifier
.length
&&
3849 !memcmp(extnID
->data
, oidSubjectKeyIdentifier
.data
, extnID
->length
- 1))
3851 switch (extnID
->data
[extnID
->length
- 1]) {
3852 case 14: /* SubjectKeyIdentifier id-ce 14 */
3853 appendSubjectKeyIdentifier(properties
, extnValue
, localized
);
3855 case 15: /* KeyUsage id-ce 15 */
3856 appendKeyUsage(properties
, extnValue
, localized
);
3858 case 16: /* PrivateKeyUsagePeriod id-ce 16 */
3859 appendPrivateKeyUsagePeriod(properties
, extnValue
, localized
);
3861 case 17: /* SubjectAltName id-ce 17 */
3862 case 18: /* IssuerAltName id-ce 18 */
3863 appendGeneralNames(properties
, extnValue
, localized
);
3865 case 19: /* BasicConstraints id-ce 19 */
3866 appendBasicConstraints(properties
, extnValue
, localized
);
3868 case 30: /* NameConstraints id-ce 30 */
3869 appendNameConstraints(properties
, extnValue
, localized
);
3871 case 31: /* CRLDistributionPoints id-ce 31 */
3872 appendCrlDistributionPoints(properties
, extnValue
, localized
);
3874 case 32: /* CertificatePolicies id-ce 32 */
3875 appendCertificatePolicies(properties
, extnValue
, localized
);
3877 case 33: /* PolicyMappings id-ce 33 */
3880 case 35: /* AuthorityKeyIdentifier id-ce 35 */
3881 appendAuthorityKeyIdentifier(properties
, extnValue
, localized
);
3883 case 36: /* PolicyConstraints id-ce 36 */
3884 appendPolicyConstraints(properties
, extnValue
, localized
);
3886 case 37: /* ExtKeyUsage id-ce 37 */
3887 appendExtendedKeyUsage(properties
, extnValue
, localized
);
3889 case 46: /* FreshestCRL id-ce 46 */
3892 case 54: /* InhibitAnyPolicy id-ce 54 */
3899 } else if (extnID
->length
== oidAuthorityInfoAccess
.length
&&
3900 !memcmp(extnID
->data
, oidAuthorityInfoAccess
.data
, extnID
->length
- 1))
3902 switch (extnID
->data
[extnID
->length
- 1]) {
3903 case 1: /* AuthorityInfoAccess id-pe 1 */
3904 appendInfoAccess(properties
, extnValue
, localized
);
3906 case 3: /* QCStatements id-pe 3 */
3909 case 11: /* SubjectInfoAccess id-pe 11 */
3910 appendInfoAccess(properties
, extnValue
, localized
);
3916 } else if (DEROidCompare(extnID
, &oidNetscapeCertType
)) {
3917 /* 2.16.840.1.113730.1.1 netscape 1 1 */
3918 appendNetscapeCertType(properties
, extnValue
, localized
);
3924 /* Try to parse and display printable string(s). */
3925 if (appendPrintableDERSequence(properties
, SEC_DATA_KEY
, extnValue
, localized
)) {
3926 /* Nothing to do here appendPrintableDERSequence did the work. */
3928 /* Couldn't parse extension; dump the raw unparsed data as hex. */
3929 appendUnparsedProperty(properties
, SEC_DATA_KEY
, NULL
, extnValue
, localized
);
3932 label
= SecDERItemCopyOIDDecimalRepresentation(allocator
, extnID
);
3933 localizedLabel
= copyOidDescription(allocator
, extnID
, localized
);
3934 appendProperty(parent
, kSecPropertyTypeSection
, label
, localizedLabel
,
3935 properties
, localized
);
3937 CFReleaseSafe(localizedLabel
);
3938 CFReleaseSafe(label
);
3939 CFReleaseSafe(properties
);
3942 /* Different types of summary types from least desired to most desired. */
3945 kSummaryTypePrintable
,
3946 kSummaryTypeOrganizationName
,
3947 kSummaryTypeOrganizationalUnitName
,
3948 kSummaryTypeCommonName
,
3952 enum SummaryType type
;
3953 CFStringRef summary
;
3954 CFStringRef description
;
3957 static OSStatus
obtainSummaryFromX501Name(void *context
,
3958 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
,
3960 struct Summary
*summary
= (struct Summary
*)context
;
3961 enum SummaryType stype
= kSummaryTypeNone
;
3962 CFStringRef string
= NULL
;
3963 if (DEROidCompare(type
, &oidCommonName
)) {
3964 stype
= kSummaryTypeCommonName
;
3965 } else if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
3966 stype
= kSummaryTypeOrganizationalUnitName
;
3967 } else if (DEROidCompare(type
, &oidOrganizationName
)) {
3968 stype
= kSummaryTypeOrganizationName
;
3969 } else if (DEROidCompare(type
, &oidDescription
)) {
3970 string
= copyDERThingDescription(kCFAllocatorDefault
, value
,
3973 if (summary
->description
) {
3974 CFStringRef fmt
= (localized
) ?
3975 SecCopyCertString(SEC_STRING_LIST_KEY
) : SEC_STRING_LIST_KEY
;
3976 CFStringRef newDescription
= CFStringCreateWithFormat(kCFAllocatorDefault
,
3977 NULL
, fmt
, string
, summary
->description
);
3979 CFRelease(summary
->description
);
3980 summary
->description
= newDescription
;
3982 summary
->description
= string
;
3985 stype
= kSummaryTypePrintable
;
3988 stype
= kSummaryTypePrintable
;
3991 /* Build a string with all instances of the most desired
3992 component type in reverse order encountered comma separated list,
3993 The order of desirability is defined by enum SummaryType. */
3994 if (summary
->type
<= stype
) {
3996 string
= copyDERThingDescription(kCFAllocatorDefault
, value
,
4000 if (summary
->type
== stype
) {
4001 CFStringRef fmt
= (localized
) ?
4002 SecCopyCertString(SEC_STRING_LIST_KEY
) : SEC_STRING_LIST_KEY
;
4003 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
,
4004 NULL
, fmt
, string
, summary
->summary
);
4007 string
= newSummary
;
4009 summary
->type
= stype
;
4011 CFReleaseSafe(summary
->summary
);
4012 summary
->summary
= string
;
4015 CFReleaseSafe(string
);
4018 return errSecSuccess
;
4021 CFStringRef
SecCertificateCopySubjectSummary(SecCertificateRef certificate
) {
4022 struct Summary summary
= {};
4023 OSStatus status
= parseX501NameContent(&certificate
->_subject
, &summary
, obtainSummaryFromX501Name
, true);
4024 if (status
!= errSecSuccess
) {
4027 /* If we found a description and a common name we change the summary to
4028 CommonName (Description). */
4029 if (summary
.description
) {
4030 if (summary
.type
== kSummaryTypeCommonName
) {
4031 CFStringRef fmt
= SecCopyCertString(SEC_COMMON_NAME_DESC_KEY
);
4032 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, summary
.summary
, summary
.description
);
4034 CFRelease(summary
.summary
);
4035 summary
.summary
= newSummary
;
4037 CFRelease(summary
.description
);
4040 if (!summary
.summary
) {
4041 /* If we didn't find a suitable printable string in the subject at all, we try
4042 the first email address in the certificate instead. */
4043 CFArrayRef names
= SecCertificateCopyRFC822Names(certificate
);
4045 /* If we didn't find any email addresses in the certificate, we try finding
4046 a DNS name instead. */
4047 names
= SecCertificateCopyDNSNames(certificate
);
4050 summary
.summary
= CFArrayGetValueAtIndex(names
, 0);
4051 CFRetain(summary
.summary
);
4056 return summary
.summary
;
4059 CFStringRef
SecCertificateCopyIssuerSummary(SecCertificateRef certificate
) {
4060 struct Summary summary
= {};
4061 OSStatus status
= parseX501NameContent(&certificate
->_issuer
, &summary
, obtainSummaryFromX501Name
, true);
4062 if (status
!= errSecSuccess
) {
4065 /* If we found a description and a common name we change the summary to
4066 CommonName (Description). */
4067 if (summary
.description
) {
4068 if (summary
.type
== kSummaryTypeCommonName
) {
4069 CFStringRef fmt
= SecCopyCertString(SEC_COMMON_NAME_DESC_KEY
);
4070 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, summary
.summary
, summary
.description
);
4072 CFRelease(summary
.summary
);
4073 summary
.summary
= newSummary
;
4075 CFRelease(summary
.description
);
4078 return summary
.summary
;
4081 /* Return the earliest date on which all certificates in this chain are still
4083 static CFAbsoluteTime
SecCertificateGetChainsLastValidity(
4084 SecCertificateRef certificate
) {
4085 CFAbsoluteTime earliest
= certificate
->_notAfter
;
4087 while (certificate
->_parent
) {
4088 certificate
= certificate
->_parent
;
4089 if (earliest
> certificate
->_notAfter
)
4090 earliest
= certificate
->_notAfter
;
4097 /* Return the latest date on which all certificates in this chain will be
4099 static CFAbsoluteTime
SecCertificateGetChainsFirstValidity(
4100 SecCertificateRef certificate
) {
4101 CFAbsoluteTime latest
= certificate
->_notBefore
;
4103 while (certificate
->_parent
) {
4104 certificate
= certificate
->_parent
;
4105 if (latest
< certificate
->_notBefore
)
4106 latest
= certificate
->_notBefore
;
4113 bool SecCertificateIsValid(SecCertificateRef certificate
,
4114 CFAbsoluteTime verifyTime
) {
4115 return certificate
&& certificate
->_notBefore
<= verifyTime
&&
4116 verifyTime
<= certificate
->_notAfter
;
4119 CFIndex
SecCertificateVersion(SecCertificateRef certificate
) {
4120 return certificate
->_version
+ 1;
4123 CFAbsoluteTime
SecCertificateNotValidBefore(SecCertificateRef certificate
) {
4124 return certificate
->_notBefore
;
4127 CFAbsoluteTime
SecCertificateNotValidAfter(SecCertificateRef certificate
) {
4128 return certificate
->_notAfter
;
4131 CFMutableArrayRef
SecCertificateCopySummaryProperties(
4132 SecCertificateRef certificate
, CFAbsoluteTime verifyTime
) {
4133 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
4134 CFMutableArrayRef summary
= CFArrayCreateMutable(allocator
, 0,
4135 &kCFTypeArrayCallBacks
);
4136 bool localized
= true;
4138 /* First we put the subject summary name. */
4139 CFStringRef ssummary
= SecCertificateCopySubjectSummary(certificate
);
4141 appendProperty(summary
, kSecPropertyTypeTitle
,
4142 NULL
, NULL
, ssummary
, localized
);
4143 CFRelease(ssummary
);
4146 /* Let see if this certificate is currently valid. */
4148 CFAbsoluteTime when
;
4149 CFStringRef message
;
4151 if (verifyTime
> certificate
->_notAfter
) {
4152 label
= SEC_EXPIRED_KEY
;
4153 when
= certificate
->_notAfter
;
4154 ptype
= kSecPropertyTypeError
;
4155 message
= SEC_CERT_EXPIRED_KEY
;
4156 } else if (certificate
->_notBefore
> verifyTime
) {
4157 label
= SEC_VALID_FROM_KEY
;
4158 when
= certificate
->_notBefore
;
4159 ptype
= kSecPropertyTypeError
;
4160 message
= SEC_CERT_NOT_YET_VALID_KEY
;
4162 CFAbsoluteTime last
= SecCertificateGetChainsLastValidity(certificate
);
4163 CFAbsoluteTime first
= SecCertificateGetChainsFirstValidity(certificate
);
4164 if (verifyTime
> last
) {
4165 label
= SEC_EXPIRED_KEY
;
4167 ptype
= kSecPropertyTypeError
;
4168 message
= SEC_ISSUER_EXPIRED_KEY
;
4169 } else if (verifyTime
< first
) {
4170 label
= SEC_VALID_FROM_KEY
;
4172 ptype
= kSecPropertyTypeError
;
4173 message
= SEC_ISSR_NOT_YET_VALID_KEY
;
4175 label
= SEC_EXPIRES_KEY
;
4176 when
= certificate
->_notAfter
;
4177 ptype
= kSecPropertyTypeSuccess
;
4178 message
= SEC_CERT_VALID_KEY
;
4182 appendDateProperty(summary
, label
, when
, localized
);
4183 CFStringRef lmessage
= SecCopyCertString(message
);
4184 appendProperty(summary
, ptype
, NULL
, NULL
, lmessage
, localized
);
4185 CFRelease(lmessage
);
4190 CFArrayRef
SecCertificateCopyLegacyProperties(SecCertificateRef certificate
) {
4192 This function replicates the content returned by SecCertificateCopyProperties
4193 prior to 10.12.4, providing stable return values for SecCertificateCopyValues.
4194 Unlike SecCertificateCopyProperties, it does not cache the result and
4195 assumes the caller will do so.
4197 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
4198 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
,
4199 0, &kCFTypeArrayCallBacks
);
4202 CFArrayRef subject_plist
= createPropertiesForX501NameContent(allocator
,
4203 &certificate
->_subject
, false);
4204 appendProperty(properties
, kSecPropertyTypeSection
, CFSTR("Subject Name"),
4205 NULL
, subject_plist
, false);
4206 CFRelease(subject_plist
);
4209 CFArrayRef issuer_plist
= createPropertiesForX501NameContent(allocator
,
4210 &certificate
->_issuer
, false);
4211 appendProperty(properties
, kSecPropertyTypeSection
, CFSTR("Issuer Name"),
4212 NULL
, issuer_plist
, false);
4213 CFRelease(issuer_plist
);
4216 CFStringRef versionString
= CFStringCreateWithFormat(allocator
,
4217 NULL
, CFSTR("%d"), certificate
->_version
+ 1);
4218 appendProperty(properties
, kSecPropertyTypeString
, CFSTR("Version"),
4219 NULL
, versionString
, false);
4220 CFRelease(versionString
);
4223 if (certificate
->_serialNum
.length
) {
4224 appendIntegerProperty(properties
, CFSTR("Serial Number"),
4225 &certificate
->_serialNum
, false);
4228 /* Signature Algorithm */
4229 appendAlgorithmProperty(properties
, CFSTR("Signature Algorithm"),
4230 &certificate
->_tbsSigAlg
, false);
4232 /* Validity dates */
4233 appendDateProperty(properties
, CFSTR("Not Valid Before"), certificate
->_notBefore
, false);
4234 appendDateProperty(properties
, CFSTR("Not Valid After"), certificate
->_notAfter
, false);
4236 if (certificate
->_subjectUniqueID
.length
) {
4237 appendDataProperty(properties
, CFSTR("Subject Unique ID"),
4238 NULL
, &certificate
->_subjectUniqueID
, false);
4240 if (certificate
->_issuerUniqueID
.length
) {
4241 appendDataProperty(properties
, CFSTR("Issuer Unique ID"),
4242 NULL
, &certificate
->_issuerUniqueID
, false);
4245 /* Public Key Algorithm */
4246 appendAlgorithmProperty(properties
, CFSTR("Public Key Algorithm"),
4247 &certificate
->_algId
, false);
4249 /* Public Key Data */
4250 appendDataProperty(properties
, CFSTR("Public Key Data"),
4251 NULL
, &certificate
->_pubKeyDER
, false);
4254 appendDataProperty(properties
, CFSTR("Signature"),
4255 NULL
, &certificate
->_signature
, false);
4259 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
4260 appendExtension(properties
, &certificate
->_extensions
[ix
], false);
4264 appendFingerprintsProperty(properties
, CFSTR("Fingerprints"), certificate
, false);
4269 CFArrayRef
SecCertificateCopyProperties(SecCertificateRef certificate
) {
4270 if (!certificate
->_properties
) {
4271 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
4272 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
4273 &kCFTypeArrayCallBacks
);
4274 require_quiet(properties
, out
);
4275 bool localized
= true;
4277 /* First we put the Subject Name in the property list. */
4278 CFArrayRef subject_plist
= createPropertiesForX501NameContent(allocator
,
4279 &certificate
->_subject
,
4281 if (subject_plist
) {
4282 appendProperty(properties
, kSecPropertyTypeSection
,
4283 SEC_SUBJECT_NAME_KEY
, NULL
, subject_plist
, localized
);
4285 CFReleaseNull(subject_plist
);
4287 /* Next we put the Issuer Name in the property list. */
4288 CFArrayRef issuer_plist
= createPropertiesForX501NameContent(allocator
,
4289 &certificate
->_issuer
,
4292 appendProperty(properties
, kSecPropertyTypeSection
,
4293 SEC_ISSUER_NAME_KEY
, NULL
, issuer_plist
, localized
);
4295 CFReleaseNull(issuer_plist
);
4298 CFStringRef fmt
= SecCopyCertString(SEC_CERT_VERSION_VALUE_KEY
);
4299 CFStringRef versionString
= NULL
;
4301 versionString
= CFStringCreateWithFormat(allocator
, NULL
, fmt
,
4302 certificate
->_version
+ 1);
4305 if (versionString
) {
4306 appendProperty(properties
, kSecPropertyTypeString
,
4307 SEC_VERSION_KEY
, NULL
, versionString
, localized
);
4309 CFReleaseNull(versionString
);
4312 appendSerialNumberProperty(properties
, SEC_SERIAL_NUMBER_KEY
, &certificate
->_serialNum
, localized
);
4314 /* Validity dates. */
4315 appendValidityPeriodProperty(properties
, SEC_VALIDITY_PERIOD_KEY
, certificate
, localized
);
4317 if (certificate
->_subjectUniqueID
.length
) {
4318 appendDataProperty(properties
, SEC_SUBJECT_UNIQUE_ID_KEY
, NULL
,
4319 &certificate
->_subjectUniqueID
, localized
);
4321 if (certificate
->_issuerUniqueID
.length
) {
4322 appendDataProperty(properties
, SEC_ISSUER_UNIQUE_ID_KEY
, NULL
,
4323 &certificate
->_issuerUniqueID
, localized
);
4326 appendPublicKeyProperty(properties
, SEC_PUBLIC_KEY_KEY
, certificate
, localized
);
4329 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
4330 appendExtension(properties
, &certificate
->_extensions
[ix
], localized
);
4334 appendSignatureProperty(properties
, SEC_SIGNATURE_KEY
, certificate
, localized
);
4336 appendFingerprintsProperty(properties
, SEC_FINGERPRINTS_KEY
, certificate
, localized
);
4338 certificate
->_properties
= properties
;
4342 CFRetainSafe(certificate
->_properties
);
4343 return certificate
->_properties
;
4346 /* Unified serial number API */
4347 CFDataRef
SecCertificateCopySerialNumberData(
4348 SecCertificateRef certificate
,
4353 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidCertificate
, NULL
);
4357 if (certificate
->_serialNumber
) {
4358 CFRetain(certificate
->_serialNumber
);
4360 return certificate
->_serialNumber
;
4364 /* On OS X, the SecCertificateCopySerialNumber API takes two arguments. */
4365 CFDataRef
SecCertificateCopySerialNumber(
4366 SecCertificateRef certificate
,
4367 CFErrorRef
*error
) {
4368 return SecCertificateCopySerialNumberData(certificate
, error
);
4371 /* On iOS, the SecCertificateCopySerialNumber API takes one argument. */
4372 CFDataRef
SecCertificateCopySerialNumber(
4373 SecCertificateRef certificate
) {
4374 return SecCertificateCopySerialNumberData(certificate
, NULL
);
4378 CFDataRef
SecCertificateGetNormalizedIssuerContent(
4379 SecCertificateRef certificate
) {
4380 return certificate
->_normalizedIssuer
;
4383 CFDataRef
SecCertificateGetNormalizedSubjectContent(
4384 SecCertificateRef certificate
) {
4385 return certificate
->_normalizedSubject
;
4388 /* Verify that certificate was signed by issuerKey. */
4389 OSStatus
SecCertificateIsSignedBy(SecCertificateRef certificate
,
4390 SecKeyRef issuerKey
) {
4391 /* Setup algId in SecAsn1AlgId format. */
4393 algId
.algorithm
.Length
= certificate
->_tbsSigAlg
.oid
.length
;
4394 algId
.algorithm
.Data
= certificate
->_tbsSigAlg
.oid
.data
;
4395 algId
.parameters
.Length
= certificate
->_tbsSigAlg
.params
.length
;
4396 algId
.parameters
.Data
= certificate
->_tbsSigAlg
.params
.data
;
4398 /* RFC5280 4.1.1.2, 4.1.2.3 requires the actual signature algorithm
4399 must match the specified algorithm in the TBSCertificate. */
4400 bool sigAlgMatch
= DEROidCompare(&certificate
->_sigAlg
.oid
,
4401 &certificate
->_tbsSigAlg
.oid
);
4403 secwarning("Signature algorithm mismatch in certificate (see RFC5280 4.1.1.2)");
4406 CFErrorRef error
= NULL
;
4408 !SecVerifySignatureWithPublicKey(issuerKey
, &algId
,
4409 certificate
->_tbs
.data
, certificate
->_tbs
.length
,
4410 certificate
->_signature
.data
, certificate
->_signature
.length
, &error
))
4412 #if !defined(NDEBUG)
4413 secdebug("verify", "signature verify failed: %" PRIdOSStatus
, (error
) ? (OSStatus
)CFErrorGetCode(error
) : errSecNotSigner
);
4415 CFReleaseSafe(error
);
4416 return errSecNotSigner
;
4419 return errSecSuccess
;
4422 const DERItem
* SecCertificateGetSubjectAltName(SecCertificateRef certificate
) {
4423 if (!certificate
->_subjectAltName
) {
4426 return &certificate
->_subjectAltName
->extnValue
;
4429 static bool convertIPAddress(CFStringRef name
, CFDataRef
*dataIP
) {
4430 /* IPv4: 4 octets in decimal separated by dots. We don't support matching IPv6 already. */
4431 bool result
= false;
4433 if (CFStringGetLength(name
) < 7 || /* min size is #.#.#.# */
4434 CFStringGetLength(name
) > 15) { /* max size is ###.###.###.### */
4438 CFCharacterSetRef decimals
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("0123456789."));
4439 CFCharacterSetRef nonDecimals
= CFCharacterSetCreateInvertedSet(NULL
, decimals
);
4440 CFMutableDataRef data
= CFDataCreateMutable(NULL
, 0);
4441 CFArrayRef parts
= CFStringCreateArrayBySeparatingStrings(NULL
, name
, CFSTR("."));
4443 /* Check character set */
4444 if (CFStringFindCharacterFromSet(name
, nonDecimals
,
4445 CFRangeMake(0, CFStringGetLength(name
)),
4446 kCFCompareForcedOrdering
, NULL
)) {
4450 /* Check number of labels */
4451 if (CFArrayGetCount(parts
) != 4) {
4455 /* Check each label and convert */
4456 CFIndex i
, count
= CFArrayGetCount(parts
);
4457 for (i
= 0; i
< count
; i
++) {
4458 CFStringRef octet
= CFArrayGetValueAtIndex(parts
, i
);
4459 char *cString
= CFStringToCString(octet
);
4460 uint32_t value
= atoi(cString
);
4465 uint8_t byte
= value
;
4466 CFDataAppendBytes(data
, &byte
, 1);
4471 *dataIP
= CFRetain(data
);
4475 CFReleaseNull(data
);
4476 CFReleaseNull(parts
);
4477 CFReleaseNull(decimals
);
4478 CFReleaseNull(nonDecimals
);
4482 static OSStatus
appendIPAddressesFromGeneralNames(void *context
,
4483 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4484 CFMutableArrayRef ipAddresses
= (CFMutableArrayRef
)context
;
4485 if (gnType
== GNT_IPAddress
) {
4486 CFStringRef string
= copyIPAddressContentDescription(
4487 kCFAllocatorDefault
, generalName
);
4489 CFArrayAppendValue(ipAddresses
, string
);
4492 return errSecInvalidCertificate
;
4495 return errSecSuccess
;
4498 CFArrayRef
SecCertificateCopyIPAddresses(SecCertificateRef certificate
) {
4499 /* These can only exist in the subject alt name. */
4500 if (!certificate
->_subjectAltName
)
4503 CFMutableArrayRef ipAddresses
= CFArrayCreateMutable(kCFAllocatorDefault
,
4504 0, &kCFTypeArrayCallBacks
);
4505 OSStatus status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4506 ipAddresses
, appendIPAddressesFromGeneralNames
);
4507 if (status
|| CFArrayGetCount(ipAddresses
) == 0) {
4508 CFRelease(ipAddresses
);
4514 static OSStatus
appendIPAddressesFromX501Name(void *context
, const DERItem
*type
,
4515 const DERItem
*value
, CFIndex rdnIX
,
4517 CFMutableArrayRef addrs
= (CFMutableArrayRef
)context
;
4518 if (DEROidCompare(type
, &oidCommonName
)) {
4519 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4520 value
, true, localized
);
4522 CFDataRef data
= NULL
;
4523 if (convertIPAddress(string
, &data
)) {
4524 CFArrayAppendValue(addrs
, data
);
4525 CFReleaseNull(data
);
4529 return errSecInvalidCertificate
;
4532 return errSecSuccess
;
4535 CFArrayRef
SecCertificateCopyIPAddressesFromSubject(SecCertificateRef certificate
) {
4536 CFMutableArrayRef addrs
= CFArrayCreateMutable(kCFAllocatorDefault
,
4537 0, &kCFTypeArrayCallBacks
);
4538 OSStatus status
= parseX501NameContent(&certificate
->_subject
, addrs
,
4539 appendIPAddressesFromX501Name
, true);
4540 if (status
|| CFArrayGetCount(addrs
) == 0) {
4541 CFReleaseNull(addrs
);
4547 static OSStatus
appendDNSNamesFromGeneralNames(void *context
, SecCEGeneralNameType gnType
,
4548 const DERItem
*generalName
) {
4549 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4550 if (gnType
== GNT_DNSName
) {
4551 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorDefault
,
4552 generalName
->data
, generalName
->length
,
4553 kCFStringEncodingUTF8
, FALSE
);
4555 CFArrayAppendValue(dnsNames
, string
);
4558 return errSecInvalidCertificate
;
4561 return errSecSuccess
;
4564 /* Return true if the passed in string matches the
4565 Preferred name syntax from sections 2.3.1. in RFC 1035.
4566 With the added check that we disallow empty dns names.
4567 Also in order to support wildcard DNSNames we allow for the '*'
4568 character anywhere in a dns component where we currently allow
4571 <domain> ::= <subdomain> | " "
4573 <subdomain> ::= <label> | <subdomain> "." <label>
4575 <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
4577 <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
4579 <let-dig-hyp> ::= <let-dig> | "-"
4581 <let-dig> ::= <letter> | <digit>
4583 <letter> ::= any one of the 52 alphabetic characters A through Z in
4584 upper case and a through z in lower case
4586 <digit> ::= any one of the ten digits 0 through 9
4588 static bool isDNSName(CFStringRef string
) {
4589 CFStringInlineBuffer buf
= {};
4590 CFIndex ix
, labelLength
= 0, length
= CFStringGetLength(string
);
4591 /* From RFC 1035 2.3.4. Size limits:
4592 labels 63 octets or less
4593 names 255 octets or less */
4594 require_quiet(length
<= 255, notDNS
);
4595 CFRange range
= { 0, length
};
4596 CFStringInitInlineBuffer(string
, &buf
, range
);
4600 kDNSStateAfterAlpha
,
4601 kDNSStateAfterDigit
,
4603 } state
= kDNSStateInital
;
4605 for (ix
= 0; ix
< length
; ++ix
) {
4606 UniChar ch
= CFStringGetCharacterFromInlineBuffer(&buf
, ix
);
4609 require_quiet(labelLength
<= 64 &&
4610 (state
== kDNSStateAfterAlpha
|| state
== kDNSStateAfterDigit
),
4612 state
= kDNSStateAfterDot
;
4614 } else if (('A' <= ch
&& ch
<= 'Z') || ('a' <= ch
&& ch
<= 'z') ||
4616 state
= kDNSStateAfterAlpha
;
4617 } else if ('0' <= ch
&& ch
<= '9') {
4619 /* The requirement for labels to start with a letter was
4620 dropped so we don't check this anymore. */
4621 require_quiet(state
== kDNSStateAfterAlpha
||
4622 state
== kDNSStateAfterDigit
||
4623 state
== kDNSStateAfterDash
, notDNS
);
4625 state
= kDNSStateAfterDigit
;
4626 } else if (ch
== '-') {
4627 require_quiet(state
== kDNSStateAfterAlpha
||
4628 state
== kDNSStateAfterDigit
||
4629 state
== kDNSStateAfterDash
, notDNS
);
4630 state
= kDNSStateAfterDash
;
4636 /* We don't allow a dns name to end in a dot or dash. */
4637 require_quiet(labelLength
<= 63 &&
4638 (state
== kDNSStateAfterAlpha
|| state
== kDNSStateAfterDigit
),
4646 static OSStatus
appendDNSNamesFromX501Name(void *context
, const DERItem
*type
,
4647 const DERItem
*value
, CFIndex rdnIX
, bool localized
) {
4648 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4649 if (DEROidCompare(type
, &oidCommonName
)) {
4650 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4651 value
, true, localized
);
4653 if (isDNSName(string
)) {
4654 /* We found a common name that is formatted like a valid
4656 CFArrayAppendValue(dnsNames
, string
);
4660 return errSecInvalidCertificate
;
4663 return errSecSuccess
;
4666 CFArrayRef
SecCertificateCopyDNSNamesFromSubject(SecCertificateRef certificate
) {
4667 CFMutableArrayRef dnsNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4668 0, &kCFTypeArrayCallBacks
);
4669 OSStatus status
= parseX501NameContent(&certificate
->_subject
, dnsNames
,
4670 appendDNSNamesFromX501Name
, true);
4671 if (status
|| CFArrayGetCount(dnsNames
) == 0) {
4672 CFReleaseNull(dnsNames
);
4676 /* appendDNSNamesFromX501Name allows IP addresses, we don't want those for this function */
4677 __block CFMutableArrayRef result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
4678 CFArrayForEach(dnsNames
, ^(const void *value
) {
4679 CFStringRef name
= (CFStringRef
)value
;
4680 if (!convertIPAddress(name
, NULL
)) {
4681 CFArrayAppendValue(result
, name
);
4684 CFReleaseNull(dnsNames
);
4685 if (CFArrayGetCount(result
) == 0) {
4686 CFReleaseNull(result
);
4692 CFArrayRef
SecCertificateCopyDNSNamesFromSAN(SecCertificateRef certificate
) {
4693 CFMutableArrayRef dnsNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4694 0, &kCFTypeArrayCallBacks
);
4695 OSStatus status
= errSecSuccess
;
4696 if (certificate
->_subjectAltName
) {
4697 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4698 dnsNames
, appendDNSNamesFromGeneralNames
);
4701 if (status
|| CFArrayGetCount(dnsNames
) == 0) {
4702 CFReleaseNull(dnsNames
);
4707 /* Not everything returned by this function is going to be a proper DNS name,
4708 we also return the certificates common name entries from the subject,
4709 assuming they look like dns names as specified in RFC 1035. */
4710 CFArrayRef
SecCertificateCopyDNSNames(SecCertificateRef certificate
) {
4711 /* These can exist in the subject alt name or in the subject. */
4712 CFArrayRef sanNames
= SecCertificateCopyDNSNamesFromSAN(certificate
);
4713 if (sanNames
&& CFArrayGetCount(sanNames
) > 0) {
4716 CFReleaseNull(sanNames
);
4718 /* RFC 2818 section 3.1. Server Identity
4720 If a subjectAltName extension of type dNSName is present, that MUST
4721 be used as the identity. Otherwise, the (most specific) Common Name
4722 field in the Subject field of the certificate MUST be used. Although
4723 the use of the Common Name is existing practice, it is deprecated and
4724 Certification Authorities are encouraged to use the dNSName instead.
4727 This implies that if we found 1 or more DNSNames in the
4728 subjectAltName, we should not use the Common Name of the subject as
4732 /* To preserve bug for bug compatibility, we can't use SecCertificateCopyDNSNamesFromSubject
4733 * because that function filters out IP Addresses. This function is Private, but
4734 * SecCertificateCopyValues uses it and that's Public. */
4735 CFMutableArrayRef dnsNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4736 0, &kCFTypeArrayCallBacks
);
4737 OSStatus status
= parseX501NameContent(&certificate
->_subject
, dnsNames
,
4738 appendDNSNamesFromX501Name
, true);
4739 if (status
|| CFArrayGetCount(dnsNames
) == 0) {
4740 CFReleaseNull(dnsNames
);
4745 static OSStatus
appendRFC822NamesFromGeneralNames(void *context
,
4746 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4747 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4748 if (gnType
== GNT_RFC822Name
) {
4749 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorDefault
,
4750 generalName
->data
, generalName
->length
,
4751 kCFStringEncodingASCII
, FALSE
);
4753 CFArrayAppendValue(dnsNames
, string
);
4756 return errSecInvalidCertificate
;
4759 return errSecSuccess
;
4762 static OSStatus
appendRFC822NamesFromX501Name(void *context
, const DERItem
*type
,
4763 const DERItem
*value
, CFIndex rdnIX
, bool localized
) {
4764 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4765 if (DEROidCompare(type
, &oidEmailAddress
)) {
4766 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4767 value
, true, localized
);
4769 CFArrayAppendValue(dnsNames
, string
);
4772 return errSecInvalidCertificate
;
4775 return errSecSuccess
;
4778 CFArrayRef
SecCertificateCopyRFC822Names(SecCertificateRef certificate
) {
4779 /* These can exist in the subject alt name or in the subject. */
4780 CFMutableArrayRef rfc822Names
= CFArrayCreateMutable(kCFAllocatorDefault
,
4781 0, &kCFTypeArrayCallBacks
);
4782 OSStatus status
= errSecSuccess
;
4783 if (certificate
->_subjectAltName
) {
4784 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4785 rfc822Names
, appendRFC822NamesFromGeneralNames
);
4788 status
= parseX501NameContent(&certificate
->_subject
, rfc822Names
,
4789 appendRFC822NamesFromX501Name
, true);
4791 if (status
|| CFArrayGetCount(rfc822Names
) == 0) {
4792 CFRelease(rfc822Names
);
4798 OSStatus
SecCertificateCopyEmailAddresses(SecCertificateRef certificate
, CFArrayRef
* __nonnull CF_RETURNS_RETAINED emailAddresses
) {
4799 if (!certificate
|| !emailAddresses
) {
4802 *emailAddresses
= SecCertificateCopyRFC822Names(certificate
);
4803 if (*emailAddresses
== NULL
) {
4804 *emailAddresses
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
4806 return errSecSuccess
;
4809 CFArrayRef
SecCertificateCopyRFC822NamesFromSubject(SecCertificateRef certificate
) {
4810 CFMutableArrayRef rfc822Names
= CFArrayCreateMutable(kCFAllocatorDefault
,
4811 0, &kCFTypeArrayCallBacks
);
4812 OSStatus status
= parseX501NameContent(&certificate
->_subject
, rfc822Names
,
4813 appendRFC822NamesFromX501Name
, true);
4814 if (status
|| CFArrayGetCount(rfc822Names
) == 0) {
4815 CFRelease(rfc822Names
);
4821 static OSStatus
appendCommonNamesFromX501Name(void *context
,
4822 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
, bool localized
) {
4823 CFMutableArrayRef commonNames
= (CFMutableArrayRef
)context
;
4824 if (DEROidCompare(type
, &oidCommonName
)) {
4825 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4826 value
, true, localized
);
4828 CFArrayAppendValue(commonNames
, string
);
4831 return errSecInvalidCertificate
;
4834 return errSecSuccess
;
4837 CFArrayRef
SecCertificateCopyCommonNames(SecCertificateRef certificate
) {
4838 CFMutableArrayRef commonNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4839 0, &kCFTypeArrayCallBacks
);
4841 status
= parseX501NameContent(&certificate
->_subject
, commonNames
,
4842 appendCommonNamesFromX501Name
, true);
4843 if (status
|| CFArrayGetCount(commonNames
) == 0) {
4844 CFRelease(commonNames
);
4850 OSStatus
SecCertificateCopyCommonName(SecCertificateRef certificate
, CFStringRef
*commonName
)
4855 CFArrayRef commonNames
= SecCertificateCopyCommonNames(certificate
);
4857 return errSecInternal
;
4861 CFIndex count
= CFArrayGetCount(commonNames
);
4862 *commonName
= CFRetainSafe(CFArrayGetValueAtIndex(commonNames
, count
-1));
4864 CFReleaseSafe(commonNames
);
4865 return errSecSuccess
;
4868 static OSStatus
appendOrganizationFromX501Name(void *context
,
4869 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
, bool localized
) {
4870 CFMutableArrayRef organization
= (CFMutableArrayRef
)context
;
4871 if (DEROidCompare(type
, &oidOrganizationName
)) {
4872 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4873 value
, true, localized
);
4875 CFArrayAppendValue(organization
, string
);
4878 return errSecInvalidCertificate
;
4881 return errSecSuccess
;
4884 CFArrayRef
SecCertificateCopyOrganization(SecCertificateRef certificate
) {
4885 CFMutableArrayRef organization
= CFArrayCreateMutable(kCFAllocatorDefault
,
4886 0, &kCFTypeArrayCallBacks
);
4888 status
= parseX501NameContent(&certificate
->_subject
, organization
,
4889 appendOrganizationFromX501Name
, true);
4890 if (status
|| CFArrayGetCount(organization
) == 0) {
4891 CFRelease(organization
);
4892 organization
= NULL
;
4894 return organization
;
4897 static OSStatus
appendOrganizationalUnitFromX501Name(void *context
,
4898 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
, bool localized
) {
4899 CFMutableArrayRef organizationalUnit
= (CFMutableArrayRef
)context
;
4900 if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
4901 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4902 value
, true, localized
);
4904 CFArrayAppendValue(organizationalUnit
, string
);
4907 return errSecInvalidCertificate
;
4910 return errSecSuccess
;
4913 CFArrayRef
SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate
) {
4914 CFMutableArrayRef organizationalUnit
= CFArrayCreateMutable(kCFAllocatorDefault
,
4915 0, &kCFTypeArrayCallBacks
);
4917 status
= parseX501NameContent(&certificate
->_subject
, organizationalUnit
,
4918 appendOrganizationalUnitFromX501Name
, true);
4919 if (status
|| CFArrayGetCount(organizationalUnit
) == 0) {
4920 CFRelease(organizationalUnit
);
4921 organizationalUnit
= NULL
;
4923 return organizationalUnit
;
4926 static OSStatus
appendCountryFromX501Name(void *context
,
4927 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
, bool localized
) {
4928 CFMutableArrayRef countries
= (CFMutableArrayRef
)context
;
4929 if (DEROidCompare(type
, &oidCountryName
)) {
4930 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4931 value
, true, localized
);
4933 CFArrayAppendValue(countries
, string
);
4936 return errSecInvalidCertificate
;
4939 return errSecSuccess
;
4942 CFArrayRef
SecCertificateCopyCountry(SecCertificateRef certificate
) {
4943 CFMutableArrayRef countries
= CFArrayCreateMutable(kCFAllocatorDefault
,
4944 0, &kCFTypeArrayCallBacks
);
4946 status
= parseX501NameContent(&certificate
->_subject
, countries
,
4947 appendCountryFromX501Name
, true);
4948 if (status
|| CFArrayGetCount(countries
) == 0) {
4949 CFRelease(countries
);
4955 const SecCEBasicConstraints
*
4956 SecCertificateGetBasicConstraints(SecCertificateRef certificate
) {
4957 if (certificate
->_basicConstraints
.present
)
4958 return &certificate
->_basicConstraints
;
4963 CFArrayRef
SecCertificateGetPermittedSubtrees(SecCertificateRef certificate
) {
4964 return (certificate
->_permittedSubtrees
);
4967 CFArrayRef
SecCertificateGetExcludedSubtrees(SecCertificateRef certificate
) {
4968 return (certificate
->_excludedSubtrees
);
4971 const SecCEPolicyConstraints
*
4972 SecCertificateGetPolicyConstraints(SecCertificateRef certificate
) {
4973 if (certificate
->_policyConstraints
.present
)
4974 return &certificate
->_policyConstraints
;
4979 const SecCEPolicyMappings
*
4980 SecCertificateGetPolicyMappings(SecCertificateRef certificate
) {
4981 if (certificate
->_policyMappings
.present
) {
4982 return &certificate
->_policyMappings
;
4988 const SecCECertificatePolicies
*
4989 SecCertificateGetCertificatePolicies(SecCertificateRef certificate
) {
4990 if (certificate
->_certificatePolicies
.present
)
4991 return &certificate
->_certificatePolicies
;
4996 const SecCEInhibitAnyPolicy
*
4997 SecCertificateGetInhibitAnyPolicySkipCerts(SecCertificateRef certificate
) {
4998 if (certificate
->_inhibitAnyPolicySkipCerts
.present
) {
4999 return &certificate
->_inhibitAnyPolicySkipCerts
;
5005 static OSStatus
appendNTPrincipalNamesFromGeneralNames(void *context
,
5006 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
5007 CFMutableArrayRef ntPrincipalNames
= (CFMutableArrayRef
)context
;
5008 if (gnType
== GNT_OtherName
) {
5010 DERReturn drtn
= DERParseSequenceContent(generalName
,
5011 DERNumOtherNameItemSpecs
, DEROtherNameItemSpecs
,
5013 require_noerr_quiet(drtn
, badDER
);
5014 if (DEROidCompare(&on
.typeIdentifier
, &oidMSNTPrincipalName
)) {
5016 require_quiet(string
= copyDERThingDescription(kCFAllocatorDefault
,
5017 &on
.value
, true, true), badDER
);
5018 CFArrayAppendValue(ntPrincipalNames
, string
);
5022 return errSecSuccess
;
5025 return errSecInvalidCertificate
;
5029 CFArrayRef
SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate
) {
5030 CFMutableArrayRef ntPrincipalNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
5031 0, &kCFTypeArrayCallBacks
);
5032 OSStatus status
= errSecSuccess
;
5033 if (certificate
->_subjectAltName
) {
5034 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
5035 ntPrincipalNames
, appendNTPrincipalNamesFromGeneralNames
);
5037 if (status
|| CFArrayGetCount(ntPrincipalNames
) == 0) {
5038 CFRelease(ntPrincipalNames
);
5039 ntPrincipalNames
= NULL
;
5041 return ntPrincipalNames
;
5044 static OSStatus
appendToRFC2253String(void *context
,
5045 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
, bool localized
) {
5046 CFMutableStringRef string
= (CFMutableStringRef
)context
;
5050 ST stateOrProvinceName
5052 OU organizationalUnitName
5054 STREET streetAddress
5058 /* Prepend a + if this is not the first RDN in an RDN set.
5059 Otherwise prepend a , if this is not the first RDN. */
5061 CFStringAppend(string
, CFSTR("+"));
5062 else if (CFStringGetLength(string
)) {
5063 CFStringAppend(string
, CFSTR(","));
5066 CFStringRef label
, oid
= NULL
;
5067 /* @@@ Consider changing this to a dictionary lookup keyed by the
5068 decimal representation. */
5069 if (DEROidCompare(type
, &oidCommonName
)) {
5070 label
= CFSTR("CN");
5071 } else if (DEROidCompare(type
, &oidLocalityName
)) {
5073 } else if (DEROidCompare(type
, &oidStateOrProvinceName
)) {
5074 label
= CFSTR("ST");
5075 } else if (DEROidCompare(type
, &oidOrganizationName
)) {
5077 } else if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
5078 label
= CFSTR("OU");
5079 } else if (DEROidCompare(type
, &oidCountryName
)) {
5082 } else if (DEROidCompare(type
, &oidStreetAddress
)) {
5083 label
= CFSTR("STREET");
5084 } else if (DEROidCompare(type
, &oidDomainComponent
)) {
5085 label
= CFSTR("DC");
5086 } else if (DEROidCompare(type
, &oidUserID
)) {
5087 label
= CFSTR("UID");
5090 label
= oid
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, type
);
5093 CFStringAppend(string
, label
);
5094 CFStringAppend(string
, CFSTR("="));
5095 CFStringRef raw
= NULL
;
5097 raw
= copyDERThingDescription(kCFAllocatorDefault
, value
, true, localized
);
5100 /* Append raw to string while escaping:
5101 a space or "#" character occurring at the beginning of the string
5102 a space character occurring at the end of the string
5103 one of the characters ",", "+", """, "\", "<", ">" or ";"
5105 CFStringInlineBuffer buffer
= {};
5106 CFIndex ix
, length
= CFStringGetLength(raw
);
5107 CFRange range
= { 0, length
};
5108 CFStringInitInlineBuffer(raw
, &buffer
, range
);
5109 for (ix
= 0; ix
< length
; ++ix
) {
5110 UniChar ch
= CFStringGetCharacterFromInlineBuffer(&buffer
, ix
);
5112 CFStringAppendFormat(string
, NULL
, CFSTR("\\%02X"), ch
);
5113 } else if (ch
== ',' || ch
== '+' || ch
== '"' || ch
== '\\' ||
5114 ch
== '<' || ch
== '>' || ch
== ';' ||
5115 (ch
== ' ' && (ix
== 0 || ix
== length
- 1)) ||
5116 (ch
== '#' && ix
== 0)) {
5117 UniChar chars
[] = { '\\', ch
};
5118 CFStringAppendCharacters(string
, chars
, 2);
5120 CFStringAppendCharacters(string
, &ch
, 1);
5125 /* Append the value in hex. */
5126 CFStringAppend(string
, CFSTR("#"));
5128 for (ix
= 0; ix
< value
->length
; ++ix
)
5129 CFStringAppendFormat(string
, NULL
, CFSTR("%02X"), value
->data
[ix
]);
5134 return errSecSuccess
;
5137 CFStringRef
SecCertificateCopySubjectString(SecCertificateRef certificate
) {
5138 CFMutableStringRef string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
5139 OSStatus status
= parseX501NameContent(&certificate
->_subject
, string
, appendToRFC2253String
, true);
5140 if (status
|| CFStringGetLength(string
) == 0) {
5147 static OSStatus
appendToCompanyNameString(void *context
,
5148 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
, bool localized
) {
5149 CFMutableStringRef string
= (CFMutableStringRef
)context
;
5150 if (CFStringGetLength(string
) != 0)
5151 return errSecSuccess
;
5153 if (!DEROidCompare(type
, &oidOrganizationName
))
5154 return errSecSuccess
;
5157 raw
= copyDERThingDescription(kCFAllocatorDefault
, value
, true, localized
);
5159 return errSecSuccess
;
5160 CFStringAppend(string
, raw
);
5163 return errSecSuccess
;
5166 CFStringRef
SecCertificateCopyCompanyName(SecCertificateRef certificate
) {
5167 CFMutableStringRef string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
5168 OSStatus status
= parseX501NameContent(&certificate
->_subject
, string
,
5169 appendToCompanyNameString
, true);
5170 if (status
|| CFStringGetLength(string
) == 0) {
5177 CFDataRef
SecCertificateCopyIssuerSequence(
5178 SecCertificateRef certificate
) {
5179 return SecDERItemCopySequence(&certificate
->_issuer
);
5182 CFDataRef
SecCertificateCopySubjectSequence(
5183 SecCertificateRef certificate
) {
5184 return SecDERItemCopySequence(&certificate
->_subject
);
5187 CFDataRef
SecCertificateCopyNormalizedIssuerSequence(SecCertificateRef certificate
) {
5188 if (!certificate
|| !certificate
->_normalizedIssuer
) {
5191 return SecCopySequenceFromContent(certificate
->_normalizedIssuer
);
5194 CFDataRef
SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certificate
) {
5195 if (!certificate
|| !certificate
->_normalizedSubject
) {
5198 return SecCopySequenceFromContent(certificate
->_normalizedSubject
);
5201 const DERAlgorithmId
*SecCertificateGetPublicKeyAlgorithm(
5202 SecCertificateRef certificate
) {
5203 return &certificate
->_algId
;
5206 const DERItem
*SecCertificateGetPublicKeyData(SecCertificateRef certificate
) {
5207 return &certificate
->_pubKeyDER
;
5211 /* There is already a SecCertificateCopyPublicKey with different args on OS X,
5212 so we will refer to this one internally as SecCertificateCopyPublicKey_ios.
5214 __nullable SecKeyRef
SecCertificateCopyPublicKey_ios(SecCertificateRef certificate
)
5216 __nullable SecKeyRef
SecCertificateCopyPublicKey(SecCertificateRef certificate
)
5219 if (certificate
->_pubKey
== NULL
) {
5220 const DERAlgorithmId
*algId
=
5221 SecCertificateGetPublicKeyAlgorithm(certificate
);
5222 const DERItem
*keyData
= SecCertificateGetPublicKeyData(certificate
);
5223 const DERItem
*params
= NULL
;
5224 if (algId
->params
.length
!= 0) {
5225 params
= &algId
->params
;
5227 SecAsn1Oid oid1
= { .Data
= algId
->oid
.data
, .Length
= algId
->oid
.length
};
5228 SecAsn1Item params1
= {
5229 .Data
= params
? params
->data
: NULL
,
5230 .Length
= params
? params
->length
: 0
5232 SecAsn1Item keyData1
= {
5233 .Data
= keyData
? keyData
->data
: NULL
,
5234 .Length
= keyData
? keyData
->length
: 0
5236 certificate
->_pubKey
= SecKeyCreatePublicFromDER(kCFAllocatorDefault
, &oid1
, ¶ms1
,
5240 return CFRetainSafe(certificate
->_pubKey
);
5243 static CFIndex
SecCertificateGetPublicKeyAlgorithmIdAndSize(SecCertificateRef certificate
, size_t *keySizeInBytes
) {
5244 CFIndex keyAlgID
= kSecNullAlgorithmID
;
5247 SecKeyRef pubKey
= NULL
;
5248 require_quiet(certificate
, out
);
5250 require_quiet(pubKey
= SecCertificateCopyPublicKey_ios(certificate
), out
);
5252 require_quiet(pubKey
= SecCertificateCopyPublicKey(certificate
) ,out
);
5254 size
= SecKeyGetBlockSize(pubKey
);
5255 keyAlgID
= SecKeyGetAlgorithmId(pubKey
);
5258 CFReleaseNull(pubKey
);
5259 if (keySizeInBytes
) { *keySizeInBytes
= size
; }
5264 * Public keys in certificates may be considered "weak" or "strong" or neither
5265 * (that is, in between). Certificates using weak keys are not trusted at all.
5266 * Certificates using neither strong nor weak keys are only trusted in certain
5267 * contexts. SecPolicy and SecPolicyServer define the contexts by which we enforce
5268 * these (or stronger) key size trust policies.
5270 bool SecCertificateIsWeakKey(SecCertificateRef certificate
) {
5271 if (!certificate
) { return true; }
5275 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) {
5276 case kSecRSAAlgorithmID
:
5277 if (MIN_RSA_KEY_SIZE
<= size
) weak
= false;
5279 case kSecECDSAAlgorithmID
:
5280 if (MIN_EC_KEY_SIZE
<= size
) weak
= false;
5288 bool SecCertificateIsStrongKey(SecCertificateRef certificate
) {
5289 if (!certificate
) { return false; }
5291 bool strong
= false;
5293 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) {
5294 case kSecRSAAlgorithmID
:
5295 if (MIN_STRONG_RSA_KEY_SIZE
<= size
) strong
= true;
5297 case kSecECDSAAlgorithmID
:
5298 if (MIN_STRONG_EC_KEY_SIZE
<= size
) strong
= true;
5306 bool SecCertificateIsWeakHash(SecCertificateRef certificate
) {
5307 if (!certificate
) { return true; }
5308 SecSignatureHashAlgorithm certAlg
= 0;
5309 certAlg
= SecCertificateGetSignatureHashAlgorithm(certificate
);
5310 if (certAlg
== kSecSignatureHashAlgorithmUnknown
||
5311 certAlg
== kSecSignatureHashAlgorithmMD2
||
5312 certAlg
== kSecSignatureHashAlgorithmMD4
||
5313 certAlg
== kSecSignatureHashAlgorithmMD5
||
5314 certAlg
== kSecSignatureHashAlgorithmSHA1
) {
5320 bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate
,
5321 CFDictionaryRef keySizes
) {
5322 if (!certificate
) { return false; }
5324 bool goodSize
= false;
5326 CFNumberRef minSize
;
5327 size_t minSizeInBits
;
5328 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate
, &size
)) {
5329 case kSecRSAAlgorithmID
:
5330 if(CFDictionaryGetValueIfPresent(keySizes
, kSecAttrKeyTypeRSA
, (const void**)&minSize
)
5331 && minSize
&& CFNumberGetValue(minSize
, kCFNumberLongType
, &minSizeInBits
)) {
5332 if (size
>= (size_t)(minSizeInBits
+7)/8) goodSize
= true;
5335 case kSecECDSAAlgorithmID
:
5336 if(CFDictionaryGetValueIfPresent(keySizes
, kSecAttrKeyTypeEC
, (const void**)&minSize
)
5337 && minSize
&& CFNumberGetValue(minSize
, kCFNumberLongType
, &minSizeInBits
)) {
5338 if (size
>= (size_t)(minSizeInBits
+7)/8) goodSize
= true;
5347 CFDataRef
SecCertificateGetSHA1Digest(SecCertificateRef certificate
) {
5348 if (!certificate
|| !certificate
->_der
.data
) {
5351 if (!certificate
->_sha1Digest
) {
5352 certificate
->_sha1Digest
=
5353 SecSHA1DigestCreate(CFGetAllocator(certificate
),
5354 certificate
->_der
.data
, certificate
->_der
.length
);
5356 return certificate
->_sha1Digest
;
5359 CFDataRef
SecCertificateCopySHA256Digest(SecCertificateRef certificate
) {
5360 if (!certificate
|| !certificate
->_der
.data
) {
5363 return SecSHA256DigestCreate(CFGetAllocator(certificate
),
5364 certificate
->_der
.data
, certificate
->_der
.length
);
5367 CFDataRef
SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate
) {
5368 CFDataRef digest
= NULL
;
5369 CFDataRef issuer
= SecCertificateCopyIssuerSequence(certificate
);
5371 digest
= SecSHA1DigestCreate(kCFAllocatorDefault
,
5372 CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
));
5378 CFDataRef
SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate
) {
5379 if (!certificate
|| !certificate
->_pubKeyDER
.data
) {
5382 return SecSHA1DigestCreate(CFGetAllocator(certificate
),
5383 certificate
->_pubKeyDER
.data
, certificate
->_pubKeyDER
.length
);
5386 static CFDataRef
SecCertificateCopySPKIEncoded(SecCertificateRef certificate
) {
5387 /* SPKI is saved without the tag/length by libDER, so we need to re-encode */
5388 if (!certificate
|| !certificate
->_subjectPublicKeyInfo
.data
) {
5391 DERSize size
= DERLengthOfItem(ASN1_CONSTR_SEQUENCE
, certificate
->_subjectPublicKeyInfo
.length
);
5392 if (size
< certificate
->_subjectPublicKeyInfo
.length
) {
5395 uint8_t *temp
= malloc(size
);
5399 DERReturn drtn
= DEREncodeItem(ASN1_CONSTR_SEQUENCE
,
5400 certificate
->_subjectPublicKeyInfo
.length
,
5401 certificate
->_subjectPublicKeyInfo
.data
,
5403 CFDataRef encodedSPKI
= NULL
;
5404 if (drtn
== DR_Success
) {
5405 encodedSPKI
= CFDataCreate(NULL
, temp
, size
);
5411 CFDataRef
SecCertificateCopySubjectPublicKeyInfoSHA1Digest(SecCertificateRef certificate
) {
5412 CFDataRef encodedSPKI
= SecCertificateCopySPKIEncoded(certificate
);
5413 if (!encodedSPKI
) { return NULL
; }
5414 CFDataRef hash
= SecSHA1DigestCreate(CFGetAllocator(certificate
),
5415 CFDataGetBytePtr(encodedSPKI
),
5416 CFDataGetLength(encodedSPKI
));
5417 CFReleaseNull(encodedSPKI
);
5421 CFDataRef
SecCertificateCopySubjectPublicKeyInfoSHA256Digest(SecCertificateRef certificate
) {
5422 CFDataRef encodedSPKI
= SecCertificateCopySPKIEncoded(certificate
);
5423 if (!encodedSPKI
) { return NULL
; }
5424 CFDataRef hash
= SecSHA256DigestCreate(CFGetAllocator(certificate
),
5425 CFDataGetBytePtr(encodedSPKI
),
5426 CFDataGetLength(encodedSPKI
));
5427 CFReleaseNull(encodedSPKI
);
5431 CFTypeRef
SecCertificateCopyKeychainItem(SecCertificateRef certificate
)
5436 CFRetainSafe(certificate
->_keychain_item
);
5437 return certificate
->_keychain_item
;
5440 CFDataRef
SecCertificateGetAuthorityKeyID(SecCertificateRef certificate
) {
5444 if (!certificate
->_authorityKeyID
&&
5445 certificate
->_authorityKeyIdentifier
.length
) {
5446 certificate
->_authorityKeyID
= CFDataCreate(kCFAllocatorDefault
,
5447 certificate
->_authorityKeyIdentifier
.data
,
5448 certificate
->_authorityKeyIdentifier
.length
);
5451 return certificate
->_authorityKeyID
;
5454 CFDataRef
SecCertificateGetSubjectKeyID(SecCertificateRef certificate
) {
5458 if (!certificate
->_subjectKeyID
&&
5459 certificate
->_subjectKeyIdentifier
.length
) {
5460 certificate
->_subjectKeyID
= CFDataCreate(kCFAllocatorDefault
,
5461 certificate
->_subjectKeyIdentifier
.data
,
5462 certificate
->_subjectKeyIdentifier
.length
);
5465 return certificate
->_subjectKeyID
;
5468 CFArrayRef
SecCertificateGetCRLDistributionPoints(SecCertificateRef certificate
) {
5472 return certificate
->_crlDistributionPoints
;
5475 CFArrayRef
SecCertificateGetOCSPResponders(SecCertificateRef certificate
) {
5479 return certificate
->_ocspResponders
;
5482 CFArrayRef
SecCertificateGetCAIssuers(SecCertificateRef certificate
) {
5486 return certificate
->_caIssuers
;
5489 bool SecCertificateHasCriticalSubjectAltName(SecCertificateRef certificate
) {
5493 return certificate
->_subjectAltName
&&
5494 certificate
->_subjectAltName
->critical
;
5497 bool SecCertificateHasSubject(SecCertificateRef certificate
) {
5501 /* Since the _subject field is the content of the subject and not the
5502 whole thing, we can simply check for a 0 length subject here. */
5503 return certificate
->_subject
.length
!= 0;
5506 bool SecCertificateHasUnknownCriticalExtension(SecCertificateRef certificate
) {
5510 return certificate
->_foundUnknownCriticalExtension
;
5513 /* Private API functions. */
5514 void SecCertificateShow(SecCertificateRef certificate
) {
5516 fprintf(stderr
, "SecCertificate instance %p:\n", certificate
);
5517 fprintf(stderr
, "\n");
5521 CFDictionaryRef
SecCertificateCopyAttributeDictionary(
5522 SecCertificateRef certificate
) {
5523 if (!certificate
|| !(CFGetTypeID(certificate
) == SecCertificateGetTypeID())) {
5526 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
5527 CFNumberRef certificateType
= NULL
;
5528 CFNumberRef certificateEncoding
= NULL
;
5529 CFStringRef label
= NULL
;
5530 CFStringRef alias
= NULL
;
5531 CFDataRef skid
= NULL
;
5532 CFDataRef pubKeyDigest
= NULL
;
5533 CFDataRef certData
= NULL
;
5534 CFDictionaryRef dict
= NULL
;
5538 /* CSSM_CERT_X_509v1, CSSM_CERT_X_509v2 or CSSM_CERT_X_509v3 */
5539 SInt32 ctv
= certificate
->_version
+ 1;
5540 SInt32 cev
= 3; /* CSSM_CERT_ENCODING_DER */
5541 certificateType
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &ctv
);
5542 require_quiet(certificateType
!= NULL
, out
);
5543 certificateEncoding
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &cev
);
5544 require_quiet(certificateEncoding
!= NULL
, out
);
5545 certData
= SecCertificateCopyData(certificate
);
5546 require_quiet(certData
!= NULL
, out
);
5547 skid
= SecCertificateGetSubjectKeyID(certificate
);
5548 require_quiet(certificate
->_pubKeyDER
.data
!= NULL
&& certificate
->_pubKeyDER
.length
> 0, out
);
5549 pubKeyDigest
= SecSHA1DigestCreate(allocator
, certificate
->_pubKeyDER
.data
,
5550 certificate
->_pubKeyDER
.length
);
5551 require_quiet(pubKeyDigest
!= NULL
, out
);
5553 /* We still need to figure out how to deal with multi valued attributes. */
5554 alias
= SecCertificateCopyRFC822Names(certificate
);
5555 label
= SecCertificateCopySubjectSummary(certificate
);
5561 DICT_ADDPAIR(kSecClass
, kSecClassCertificate
);
5562 DICT_ADDPAIR(kSecAttrCertificateType
, certificateType
);
5563 DICT_ADDPAIR(kSecAttrCertificateEncoding
, certificateEncoding
);
5565 DICT_ADDPAIR(kSecAttrLabel
, label
);
5568 DICT_ADDPAIR(kSecAttrAlias
, alias
);
5570 if (isData(certificate
->_normalizedSubject
)) {
5571 DICT_ADDPAIR(kSecAttrSubject
, certificate
->_normalizedSubject
);
5573 require_quiet(isData(certificate
->_normalizedIssuer
), out
);
5574 DICT_ADDPAIR(kSecAttrIssuer
, certificate
->_normalizedIssuer
);
5575 require_quiet(isData(certificate
->_serialNumber
), out
);
5576 DICT_ADDPAIR(kSecAttrSerialNumber
, certificate
->_serialNumber
);
5578 DICT_ADDPAIR(kSecAttrSubjectKeyID
, skid
);
5580 DICT_ADDPAIR(kSecAttrPublicKeyHash
, pubKeyDigest
);
5581 DICT_ADDPAIR(kSecValueData
, certData
);
5582 dict
= DICT_CREATE(allocator
);
5585 CFReleaseSafe(label
);
5586 CFReleaseSafe(alias
);
5587 CFReleaseSafe(pubKeyDigest
);
5588 CFReleaseSafe(certData
);
5589 CFReleaseSafe(certificateEncoding
);
5590 CFReleaseSafe(certificateType
);
5595 SecCertificateRef
SecCertificateCreateFromAttributeDictionary(
5596 CFDictionaryRef refAttributes
) {
5597 /* @@@ Support having an allocator in refAttributes. */
5598 CFAllocatorRef allocator
= NULL
;
5599 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecValueData
);
5600 return data
? SecCertificateCreateWithData(allocator
, data
) : NULL
;
5604 static bool _SecCertificateIsSelfSigned(SecCertificateRef certificate
) {
5605 if (certificate
->_isSelfSigned
== kSecSelfSignedUnknown
) {
5606 certificate
->_isSelfSigned
= kSecSelfSignedFalse
;
5607 SecKeyRef publicKey
= NULL
;
5608 require(certificate
&& (CFGetTypeID(certificate
) == SecCertificateGetTypeID()), out
);
5610 require(publicKey
= SecCertificateCopyPublicKey_ios(certificate
), out
);
5612 require(publicKey
= SecCertificateCopyPublicKey(certificate
), out
);
5614 CFDataRef normalizedIssuer
=
5615 SecCertificateGetNormalizedIssuerContent(certificate
);
5616 CFDataRef normalizedSubject
=
5617 SecCertificateGetNormalizedSubjectContent(certificate
);
5618 require_quiet(normalizedIssuer
&& normalizedSubject
&&
5619 CFEqual(normalizedIssuer
, normalizedSubject
), out
);
5621 CFDataRef authorityKeyID
= SecCertificateGetAuthorityKeyID(certificate
);
5622 CFDataRef subjectKeyID
= SecCertificateGetSubjectKeyID(certificate
);
5623 if (authorityKeyID
) {
5624 require_quiet(subjectKeyID
&& CFEqual(subjectKeyID
, authorityKeyID
), out
);
5627 require_noerr_quiet(SecCertificateIsSignedBy(certificate
, publicKey
), out
);
5629 certificate
->_isSelfSigned
= kSecSelfSignedTrue
;
5631 CFReleaseSafe(publicKey
);
5634 return (certificate
->_isSelfSigned
== kSecSelfSignedTrue
);
5637 bool SecCertificateIsCA(SecCertificateRef certificate
) {
5638 bool result
= false;
5639 require(certificate
&& (CFGetTypeID(certificate
) == SecCertificateGetTypeID()), out
);
5640 if (SecCertificateVersion(certificate
) >= 3) {
5641 const SecCEBasicConstraints
*basicConstraints
= SecCertificateGetBasicConstraints(certificate
);
5642 result
= (basicConstraints
&& basicConstraints
->isCA
);
5645 result
= _SecCertificateIsSelfSigned(certificate
);
5651 bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate
) {
5652 return (_SecCertificateIsSelfSigned(certificate
) && SecCertificateIsCA(certificate
));
5655 OSStatus
SecCertificateIsSelfSigned(SecCertificateRef certificate
, Boolean
*isSelfSigned
) {
5656 if (!certificate
|| (CFGetTypeID(certificate
) != SecCertificateGetTypeID())) {
5657 return errSecInvalidCertificate
;
5659 if (!isSelfSigned
) {
5662 *isSelfSigned
= _SecCertificateIsSelfSigned(certificate
);
5663 return errSecSuccess
;
5666 SecKeyUsage
SecCertificateGetKeyUsage(SecCertificateRef certificate
) {
5668 return kSecKeyUsageUnspecified
;
5670 return certificate
->_keyUsage
;
5673 CFArrayRef
SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate
)
5675 CFMutableArrayRef extended_key_usage_oids
=
5676 CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
5677 require_quiet(certificate
&& extended_key_usage_oids
, out
);
5679 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5680 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5681 if (extn
->extnID
.length
== oidExtendedKeyUsage
.length
&&
5682 !memcmp(extn
->extnID
.data
, oidExtendedKeyUsage
.data
, extn
->extnID
.length
)) {
5685 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &derSeq
);
5686 require_noerr_quiet(drtn
, out
);
5687 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, out
);
5688 DERDecodedInfo currDecoded
;
5690 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
5691 require_quiet(currDecoded
.tag
== ASN1_OBJECT_ID
, out
);
5692 CFDataRef oid
= CFDataCreate(kCFAllocatorDefault
,
5693 currDecoded
.content
.data
, currDecoded
.content
.length
);
5694 require_quiet(oid
, out
);
5695 CFArrayAppendValue(extended_key_usage_oids
, oid
);
5698 require_quiet(drtn
== DR_EndOfSequence
, out
);
5699 return extended_key_usage_oids
;
5703 CFReleaseSafe(extended_key_usage_oids
);
5707 CFArrayRef
SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate
)
5709 require_quiet(certificate
, out
);
5712 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5713 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5714 if (extn
->extnID
.length
== oidGoogleEmbeddedSignedCertificateTimestamp
.length
&&
5715 !memcmp(extn
->extnID
.data
, oidGoogleEmbeddedSignedCertificateTimestamp
.data
, extn
->extnID
.length
)) {
5716 /* Got the SCT oid */
5717 DERDecodedInfo sctList
;
5718 DERReturn drtn
= DERDecodeItem(&extn
->extnValue
, &sctList
);
5719 require_noerr_quiet(drtn
, out
);
5720 require_quiet(sctList
.tag
== ASN1_OCTET_STRING
, out
);
5721 return SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sctList
.content
.data
, sctList
.content
.length
);
5729 static bool matches_expected(DERItem der
, CFTypeRef expected
) {
5730 if (der
.length
> 1) {
5731 DERDecodedInfo decoded
;
5732 DERDecodeItem(&der
, &decoded
);
5733 switch (decoded
.tag
) {
5736 return decoded
.content
.length
== 0 && expected
== NULL
;
5740 case ASN1_IA5_STRING
:
5741 case ASN1_UTF8_STRING
: {
5742 if (isString(expected
)) {
5743 CFStringRef expectedString
= (CFStringRef
) expected
;
5744 CFStringRef itemString
= CFStringCreateWithBytesNoCopy(kCFAllocatorDefault
, decoded
.content
.data
, decoded
.content
.length
, kCFStringEncodingUTF8
, false, kCFAllocatorNull
);
5746 bool result
= (kCFCompareEqualTo
== CFStringCompare(expectedString
, itemString
, 0));
5747 CFReleaseNull(itemString
);
5753 case ASN1_OCTET_STRING
: {
5754 if (isData(expected
)) {
5755 CFDataRef expectedData
= (CFDataRef
) expected
;
5756 CFDataRef itemData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, decoded
.content
.data
, decoded
.content
.length
, kCFAllocatorNull
);
5758 bool result
= CFEqual(expectedData
, itemData
);
5759 CFReleaseNull(itemData
);
5765 case ASN1_INTEGER
: {
5766 SInt32 expected_value
= 0;
5767 if (isString(expected
))
5769 CFStringRef aStr
= (CFStringRef
)expected
;
5770 expected_value
= CFStringGetIntValue(aStr
);
5772 else if (isNumber(expected
))
5774 CFNumberGetValue(expected
, kCFNumberSInt32Type
, &expected_value
);
5777 uint32_t num_value
= 0;
5778 if (!DERParseInteger(&decoded
.content
, &num_value
))
5780 return ((uint32_t)expected_value
== num_value
);
5793 static bool cert_contains_marker_extension_value(SecCertificateRef certificate
, CFDataRef oid
, CFTypeRef expectedValue
)
5796 const uint8_t *oid_data
= CFDataGetBytePtr(oid
);
5797 size_t oid_len
= CFDataGetLength(oid
);
5799 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5800 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5801 if (extn
->extnID
.length
== oid_len
5802 && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
))
5804 return matches_expected(extn
->extnValue
, expectedValue
);
5810 static bool cert_contains_marker_extension(SecCertificateRef certificate
, CFTypeRef oid
)
5812 return cert_contains_marker_extension_value(certificate
, oid
, NULL
);
5815 struct search_context
{
5817 SecCertificateRef certificate
;
5820 static bool GetDecimalValueOfString(CFStringRef string
, uint32_t* value
)
5822 CFCharacterSetRef nonDecimalDigit
= CFCharacterSetCreateInvertedSet(NULL
, CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
));
5823 bool result
= false;
5825 if ( CFStringGetLength(string
) > 0
5826 && !CFStringFindCharacterFromSet(string
, nonDecimalDigit
, CFRangeMake(0, CFStringGetLength(string
)), kCFCompareForcedOrdering
, NULL
))
5829 *value
= CFStringGetIntValue(string
);
5833 CFReleaseNull(nonDecimalDigit
);
5838 bool SecCertificateIsOidString(CFStringRef oid
)
5840 if (!oid
) return false;
5841 if (2 >= CFStringGetLength(oid
)) return false;
5844 /* oid string only has the allowed characters */
5845 CFCharacterSetRef decimalOid
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("0123456789."));
5846 CFCharacterSetRef nonDecimalOid
= CFCharacterSetCreateInvertedSet(NULL
, decimalOid
);
5847 if (CFStringFindCharacterFromSet(oid
, nonDecimalOid
, CFRangeMake(0, CFStringGetLength(oid
)), kCFCompareForcedOrdering
, NULL
)) {
5851 /* first arc is allowed */
5852 UniChar firstArc
[2];
5853 CFRange firstTwo
= {0, 2};
5854 CFStringGetCharacters(oid
, firstTwo
, firstArc
);
5855 if (firstArc
[1] != '.' ||
5856 (firstArc
[0] != '0' && firstArc
[0] != '1' && firstArc
[0] != '2')) {
5860 CFReleaseNull(decimalOid
);
5861 CFReleaseNull(nonDecimalOid
);
5866 CFDataRef
SecCertificateCreateOidDataFromString(CFAllocatorRef allocator
, CFStringRef string
)
5868 CFMutableDataRef currentResult
= NULL
;
5869 CFDataRef encodedResult
= NULL
;
5871 CFArrayRef parts
= NULL
;
5874 if (!string
|| !SecCertificateIsOidString(string
))
5877 parts
= CFStringCreateArrayBySeparatingStrings(NULL
, string
, CFSTR("."));
5882 count
= CFArrayGetCount(parts
);
5886 // assume no more than 5 bytes needed to represent any part of the oid,
5887 // since we limit parts to 32-bit values,
5888 // but the first two parts only need 1 byte
5889 currentResult
= CFDataCreateMutable(allocator
, 1+(count
-2)*5);
5895 part
= CFArrayGetValueAtIndex(parts
, 0);
5897 if (!GetDecimalValueOfString(part
, &x
) || x
> 6)
5904 part
= CFArrayGetValueAtIndex(parts
, 1);
5906 if (!GetDecimalValueOfString(part
, &x
) || x
> 39)
5912 CFDataAppendBytes(currentResult
, &firstByte
, 1);
5914 for (CFIndex i
= 2; i
< count
&& GetDecimalValueOfString(CFArrayGetValueAtIndex(parts
, i
), &x
); ++i
) {
5915 uint8_t b
[5] = {0, 0, 0, 0, 0};
5917 b
[3] = 0x80 | ((x
>> 7) & 0x7F);
5918 b
[2] = 0x80 | ((x
>> 14) & 0x7F);
5919 b
[1] = 0x80 | ((x
>> 21) & 0x7F);
5920 b
[0] = 0x80 | ((x
>> 28) & 0x7F);
5922 // Skip the unused extension bytes.
5923 size_t skipBytes
= 0;
5924 while (b
[skipBytes
] == 0x80)
5927 CFDataAppendBytes(currentResult
, b
+ skipBytes
, sizeof(b
) - skipBytes
);
5930 encodedResult
= currentResult
;
5931 currentResult
= NULL
;
5934 CFReleaseNull(parts
);
5935 CFReleaseNull(currentResult
);
5937 return encodedResult
;
5940 static void check_for_marker(const void *key
, const void *value
, void *context
)
5942 struct search_context
* search_ctx
= (struct search_context
*) context
;
5943 CFStringRef key_string
= (CFStringRef
) key
;
5944 CFTypeRef value_ref
= (CFTypeRef
) value
;
5946 // If we could have short circuted the iteration
5947 // we would have, but the best we can do
5948 // is not waste time comparing once a match
5950 if (search_ctx
->found
)
5953 if (CFGetTypeID(key_string
) != CFStringGetTypeID())
5956 CFDataRef key_data
= SecCertificateCreateOidDataFromString(NULL
, key_string
);
5958 if (NULL
== key_data
)
5961 if (cert_contains_marker_extension_value(search_ctx
->certificate
, key_data
, value_ref
))
5962 search_ctx
->found
= true;
5964 CFReleaseNull(key_data
);
5968 // CFType Ref is either:
5970 // CFData - OID to match with no data permitted
5971 // CFString - decimal OID to match
5972 // CFDictionary - OID -> Value table for expected values Single Object or Array
5973 // CFArray - Array of the above.
5975 // This returns true if any of the requirements are met.
5976 bool SecCertificateHasMarkerExtension(SecCertificateRef certificate
, CFTypeRef oids
)
5978 if (CFGetTypeID(oids
) == CFArrayGetTypeID()) {
5979 CFIndex ix
, length
= CFArrayGetCount(oids
);
5980 for (ix
= 0; ix
< length
; ix
++)
5981 if (SecCertificateHasMarkerExtension(certificate
, CFArrayGetValueAtIndex((CFArrayRef
)oids
, ix
)))
5983 } else if (CFGetTypeID(oids
) == CFDictionaryGetTypeID()) {
5984 struct search_context context
= { .found
= false, .certificate
= certificate
};
5985 CFDictionaryApplyFunction((CFDictionaryRef
) oids
, &check_for_marker
, &context
);
5986 return context
.found
;
5987 } else if (CFGetTypeID(oids
) == CFDataGetTypeID()) {
5988 return cert_contains_marker_extension(certificate
, oids
);
5989 } else if (CFGetTypeID(oids
) == CFStringGetTypeID()) {
5990 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, oids
);
5991 if (dataOid
== NULL
) return false;
5992 bool result
= cert_contains_marker_extension(certificate
, dataOid
);
5993 CFReleaseNull(dataOid
);
5999 static DERItem
*cert_extension_value_for_marker(SecCertificateRef certificate
, CFDataRef oid
) {
6001 const uint8_t *oid_data
= CFDataGetBytePtr(oid
);
6002 size_t oid_len
= CFDataGetLength(oid
);
6004 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
6005 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
6006 if (extn
->extnID
.length
== oid_len
6007 && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
))
6009 return (DERItem
*)&extn
->extnValue
;
6016 // CFType Ref is either:
6018 // CFData - OID to match with no data permitted
6019 // CFString - decimal OID to match
6021 DERItem
*SecCertificateGetExtensionValue(SecCertificateRef certificate
, CFTypeRef oid
) {
6022 if (!certificate
|| !oid
) {
6026 if(CFGetTypeID(oid
) == CFDataGetTypeID()) {
6027 return cert_extension_value_for_marker(certificate
, oid
);
6028 } else if (CFGetTypeID(oid
) == CFStringGetTypeID()) {
6029 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, oid
);
6030 if (dataOid
== NULL
) return NULL
;
6031 DERItem
*result
= cert_extension_value_for_marker(certificate
, dataOid
);
6032 CFReleaseNull(dataOid
);
6039 CFDataRef
SecCertificateCopyExtensionValue(SecCertificateRef certificate
, CFTypeRef extensionOID
, bool *isCritical
) {
6040 if (!certificate
|| !extensionOID
) {
6044 CFDataRef oid
= NULL
, extensionValue
= NULL
;
6045 if (CFGetTypeID(extensionOID
) == CFDataGetTypeID()) {
6046 oid
= CFRetainSafe(extensionOID
);
6047 } else if (CFGetTypeID(extensionOID
) == CFStringGetTypeID()) {
6048 oid
= SecCertificateCreateOidDataFromString(NULL
, extensionOID
);
6055 const uint8_t *oid_data
= CFDataGetBytePtr(oid
);
6056 size_t oid_len
= CFDataGetLength(oid
);
6058 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
6059 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
6060 if (extn
->extnID
.length
== oid_len
6061 && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
))
6064 *isCritical
= extn
->critical
;
6066 extensionValue
= CFDataCreate(NULL
, extn
->extnValue
.data
, extn
->extnValue
.length
);
6072 return extensionValue
;
6075 CFDataRef
SecCertificateCopyiAPAuthCapabilities(SecCertificateRef certificate
) {
6079 CFDataRef extensionData
= NULL
;
6080 DERItem
*extensionValue
= NULL
;
6081 extensionValue
= SecCertificateGetExtensionValue(certificate
,
6082 CFSTR("1.2.840.113635.100.6.36"));
6083 require_quiet(extensionValue
, out
);
6084 /* The extension is a octet string containing the DER-encoded 32-byte octet string */
6085 require_quiet(extensionValue
->length
== 34, out
);
6086 DERDecodedInfo decodedValue
;
6087 require_noerr_quiet(DERDecodeItem(extensionValue
, &decodedValue
), out
);
6088 if (decodedValue
.tag
== ASN1_OCTET_STRING
) {
6089 require_quiet(decodedValue
.content
.length
== 32, out
);
6090 extensionData
= CFDataCreate(NULL
, decodedValue
.content
.data
,
6091 decodedValue
.content
.length
);
6093 require_quiet(extensionValue
->data
[33] == 0x00 &&
6094 extensionValue
->data
[32] == 0x00, out
);
6095 extensionData
= CFDataCreate(NULL
, extensionValue
->data
, 32);
6098 return extensionData
;
6102 /* From iapd IAPAuthenticationTypes.h */
6103 typedef struct IapCertSerialNumber
6105 uint8_t xservID
; // Xserver ID
6106 uint8_t hsmID
; // Hardware security module ID (generated cert)
6107 uint8_t delimiter01
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6108 uint8_t dateYear
; // Date year cert was issued
6109 uint8_t dateMonth
; // Date month cert was issued
6110 uint8_t dateDay
; // Date day cert was issued
6111 uint8_t delimiter02
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6112 uint8_t devClass
; // iAP device class (maps to lingo permissions)
6113 uint8_t delimiter03
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6114 uint8_t batchNumHi
; // Batch number high byte (15:08)
6115 uint8_t batchNumLo
; // Batch number low byte (07:00)
6116 uint8_t delimiter04
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6117 uint8_t serialNumHi
; // Serial number high byte (23:16)
6118 uint8_t serialNumMid
; // Serial number middle byte (15:08)
6119 uint8_t serialNumLo
; // Serial number low byte (07:00)
6121 } IapCertSerialNumber_t
, *pIapCertSerialNumber_t
;
6124 #define IAP_CERT_FIELD_DELIMITER 0xAA // "Apple_Accessory" delimiter
6125 SeciAuthVersion
SecCertificateGetiAuthVersion(SecCertificateRef certificate
) {
6127 return kSeciAuthInvalid
;
6129 if (NULL
!= SecCertificateGetExtensionValue(certificate
,
6130 CFSTR("1.2.840.113635.100.6.36"))) {
6131 /* v3 Capabilities Extension */
6132 return kSeciAuthVersion3
;
6134 if (NULL
!= SecCertificateGetExtensionValue(certificate
,
6135 CFSTR("1.2.840.113635.100.6.59.1"))) {
6136 /* SW Auth General Capabilities Extension */
6137 return kSeciAuthVersionSW
;
6139 DERItem serialNumber
= certificate
->_serialNum
;
6140 require_quiet(serialNumber
.data
, out
);
6141 require_quiet(serialNumber
.length
== 15, out
);
6142 require_quiet(serialNumber
.data
[2] == IAP_CERT_FIELD_DELIMITER
&&
6143 serialNumber
.data
[6] == IAP_CERT_FIELD_DELIMITER
&&
6144 serialNumber
.data
[8] == IAP_CERT_FIELD_DELIMITER
&&
6145 serialNumber
.data
[11] == IAP_CERT_FIELD_DELIMITER
, out
);
6146 return kSeciAuthVersion2
;
6148 return kSeciAuthInvalid
;
6151 SecCertificateRef
SecCertificateCreateWithPEM(CFAllocatorRef allocator
,
6152 CFDataRef pem_certificate
)
6154 static const char begin_cert
[] = "-----BEGIN CERTIFICATE-----\n";
6155 static const char end_cert
[] = "-----END CERTIFICATE-----\n";
6156 uint8_t *base64_data
= NULL
;
6157 SecCertificateRef cert
= NULL
;
6158 const unsigned char *data
= CFDataGetBytePtr(pem_certificate
);
6159 //const size_t length = CFDataGetLength(pem_certificate);
6160 char *begin
= strstr((const char *)data
, begin_cert
);
6161 char *end
= strstr((const char *)data
, end_cert
);
6164 begin
+= sizeof(begin_cert
) - 1;
6165 size_t base64_length
= SecBase64Decode(begin
, end
- begin
, NULL
, 0);
6166 if (base64_length
&& (base64_length
< (size_t)CFDataGetLength(pem_certificate
))) {
6167 require_quiet(base64_data
= calloc(1, base64_length
), out
);
6168 require_action_quiet(base64_length
= SecBase64Decode(begin
, end
- begin
, base64_data
, base64_length
), out
, free(base64_data
));
6169 cert
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, base64_data
, base64_length
);
6178 // -- MARK -- XPC encoding/decoding
6181 bool SecCertificateAppendToXPCArray(SecCertificateRef certificate
, xpc_object_t xpc_certificates
, CFErrorRef
*error
) {
6183 return true; // NOOP
6185 size_t length
= SecCertificateGetLength(certificate
);
6186 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
6187 #if SECTRUST_VERBOSE_DEBUG
6188 secerror("cert=0x%lX length=%d bytes=0x%lX", (uintptr_t)certificate
, (int)length
, (uintptr_t)bytes
);
6190 if (!length
|| !bytes
) {
6191 return SecError(errSecParam
, error
, CFSTR("failed to der encode certificate"));
6193 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
6197 SecCertificateRef
SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates
, size_t index
, CFErrorRef
*error
) {
6198 SecCertificateRef certificate
= NULL
;
6200 const uint8_t *bytes
= xpc_array_get_data(xpc_certificates
, index
, &length
);
6202 certificate
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, bytes
, length
);
6205 SecError(errSecParam
, error
, CFSTR("certificates[%zu] failed to decode"), index
);
6210 xpc_object_t
SecCertificateArrayCopyXPCArray(CFArrayRef certificates
, CFErrorRef
*error
) {
6211 xpc_object_t xpc_certificates
;
6212 require_action_quiet(xpc_certificates
= xpc_array_create(NULL
, 0), exit
,
6213 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
6214 CFIndex ix
, count
= CFArrayGetCount(certificates
);
6215 for (ix
= 0; ix
< count
; ++ix
) {
6216 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
6217 #if SECTRUST_VERBOSE_DEBUG
6218 CFIndex length
= SecCertificateGetLength(certificate
);
6219 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
6220 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
);
6222 if (!SecCertificateAppendToXPCArray(certificate
, xpc_certificates
, error
)) {
6223 xpc_release(xpc_certificates
);
6224 xpc_certificates
= NULL
;
6230 return xpc_certificates
;
6233 CFArrayRef
SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates
, CFErrorRef
*error
) {
6234 CFMutableArrayRef certificates
= NULL
;
6235 require_action_quiet(xpc_get_type(xpc_certificates
) == XPC_TYPE_ARRAY
, exit
,
6236 SecError(errSecParam
, error
, CFSTR("certificates xpc value is not an array")));
6237 size_t count
= xpc_array_get_count(xpc_certificates
);
6238 require_action_quiet(certificates
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
), exit
,
6239 SecError(errSecAllocate
, error
, CFSTR("failed to create CFArray of capacity %zu"), count
));
6242 for (ix
= 0; ix
< count
; ++ix
) {
6243 SecCertificateRef cert
= SecCertificateCreateWithXPCArrayAtIndex(xpc_certificates
, ix
, error
);
6245 CFRelease(certificates
);
6248 CFArraySetValueAtIndex(certificates
, ix
, cert
);
6253 return certificates
;
6256 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
6259 static CFArrayRef
CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType
, CFErrorRef
* error
)
6261 __block CFArrayRef result
= NULL
;
6263 do_if_registered(ota_CopyEscrowCertificates
, escrowRootType
, error
);
6265 securityd_send_sync_and_do(kSecXPCOpOTAGetEscrowCertificates
, error
,
6266 ^bool(xpc_object_t message
, CFErrorRef
*error
)
6268 xpc_dictionary_set_uint64(message
, "escrowType", (uint64_t)escrowRootType
);
6271 ^bool(xpc_object_t response
, CFErrorRef
*error
)
6273 xpc_object_t xpc_array
= xpc_dictionary_get_value(response
, kSecXPCKeyResult
);
6275 if (response
&& (NULL
!= xpc_array
)) {
6276 result
= (CFArrayRef
)_CFXPCCreateCFObjectFromXPCObject(xpc_array
);
6279 return SecError(errSecInternal
, error
, CFSTR("Did not get the Escrow certificates"));
6281 return result
!= NULL
;
6286 CFArrayRef
SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType
)
6288 CFArrayRef result
= NULL
;
6290 CFDataRef certData
= NULL
;
6293 if (kSecCertificateBaselineEscrowRoot
== escrowRootType
||
6294 kSecCertificateBaselinePCSEscrowRoot
== escrowRootType
||
6295 kSecCertificateBaselineEscrowBackupRoot
== escrowRootType
||
6296 kSecCertificateBaselineEscrowEnrollmentRoot
== escrowRootType
)
6298 // The request is for the base line certificates.
6299 // Use the hard coded data to generate the return array.
6300 struct RootRecord
** pEscrowRoots
;
6301 switch (escrowRootType
) {
6302 case kSecCertificateBaselineEscrowRoot
:
6303 numRoots
= kNumberOfBaseLineEscrowRoots
;
6304 pEscrowRoots
= kBaseLineEscrowRoots
;
6306 case kSecCertificateBaselinePCSEscrowRoot
:
6307 numRoots
= kNumberOfBaseLinePCSEscrowRoots
;
6308 pEscrowRoots
= kBaseLinePCSEscrowRoots
;
6310 case kSecCertificateBaselineEscrowBackupRoot
:
6311 numRoots
= kNumberOfBaseLineEscrowBackupRoots
;
6312 pEscrowRoots
= kBaseLineEscrowBackupRoots
;
6314 case kSecCertificateBaselineEscrowEnrollmentRoot
:
6316 numRoots
= kNumberOfBaseLineEscrowEnrollmentRoots
;
6317 pEscrowRoots
= kBaseLineEscrowEnrollmentRoots
;
6321 // Get the hard coded set of roots
6322 SecCertificateRef baseLineCerts
[numRoots
];
6323 struct RootRecord
* pRootRecord
= NULL
;
6325 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6326 pRootRecord
= pEscrowRoots
[iCnt
];
6327 if (NULL
!= pRootRecord
&& pRootRecord
->_length
> 0 && NULL
!= pRootRecord
->_bytes
) {
6328 certData
= CFDataCreate(kCFAllocatorDefault
, pRootRecord
->_bytes
, pRootRecord
->_length
);
6329 if (NULL
!= certData
) {
6330 baseLineCerts
[iCnt
] = SecCertificateCreateWithData(kCFAllocatorDefault
, certData
);
6331 CFRelease(certData
);
6335 result
= CFArrayCreate(kCFAllocatorDefault
, (const void **)baseLineCerts
, numRoots
, &kCFTypeArrayCallBacks
);
6336 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6337 if (NULL
!= baseLineCerts
[iCnt
]) {
6338 CFRelease(baseLineCerts
[iCnt
]);
6343 // The request is for the current certificates.
6344 CFErrorRef error
= NULL
;
6345 CFArrayRef cert_datas
= CopyEscrowCertificates(escrowRootType
, &error
);
6346 if (NULL
!= error
|| NULL
== cert_datas
) {
6347 if (NULL
!= error
) {
6350 if (NULL
!= cert_datas
) {
6351 CFRelease(cert_datas
);
6356 numRoots
= (int)(CFArrayGetCount(cert_datas
));
6358 SecCertificateRef assetCerts
[numRoots
];
6359 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6360 certData
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, iCnt
);
6361 if (NULL
!= certData
) {
6362 SecCertificateRef aCertRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, certData
);
6363 assetCerts
[iCnt
] = aCertRef
;
6366 assetCerts
[iCnt
] = NULL
;
6371 result
= CFArrayCreate(kCFAllocatorDefault
, (const void **)assetCerts
, numRoots
, &kCFTypeArrayCallBacks
);
6372 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6373 if (NULL
!= assetCerts
[iCnt
]) {
6374 CFRelease(assetCerts
[iCnt
]);
6378 CFReleaseSafe(cert_datas
);
6383 SEC_CONST_DECL (kSecSignatureDigestAlgorithmUnknown
, "SignatureDigestUnknown");
6384 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD2
, "SignatureDigestMD2");
6385 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD4
, "SignatureDigestMD4");
6386 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD5
, "SignatureDigestMD5");
6387 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA1
, "SignatureDigestSHA1");
6388 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA224
, "SignatureDigestSHA224");
6389 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA256
, "SignatureDigestSHA256");
6390 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA384
, "SignatureDigestSHA284");
6391 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA512
, "SignatureDigestSHA512");
6393 SecSignatureHashAlgorithm
SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate
)
6395 SecSignatureHashAlgorithm result
= kSecSignatureHashAlgorithmUnknown
;
6396 DERAlgorithmId
*algId
= (certificate
) ? &certificate
->_tbsSigAlg
: NULL
;
6397 const DERItem
*algOid
= (algId
) ? &algId
->oid
: NULL
;
6399 if (!algOid
->data
|| !algOid
->length
) {
6402 /* classify the signature algorithm OID into one of our known types */
6403 if (DEROidCompare(algOid
, &oidSha512Ecdsa
) ||
6404 DEROidCompare(algOid
, &oidSha512Rsa
) ||
6405 DEROidCompare(algOid
, &oidSha512
)) {
6406 result
= kSecSignatureHashAlgorithmSHA512
;
6409 if (DEROidCompare(algOid
, &oidSha384Ecdsa
) ||
6410 DEROidCompare(algOid
, &oidSha384Rsa
) ||
6411 DEROidCompare(algOid
, &oidSha384
)) {
6412 result
= kSecSignatureHashAlgorithmSHA384
;
6415 if (DEROidCompare(algOid
, &oidSha256Ecdsa
) ||
6416 DEROidCompare(algOid
, &oidSha256Rsa
) ||
6417 DEROidCompare(algOid
, &oidSha256
)) {
6418 result
= kSecSignatureHashAlgorithmSHA256
;
6421 if (DEROidCompare(algOid
, &oidSha224Ecdsa
) ||
6422 DEROidCompare(algOid
, &oidSha224Rsa
) ||
6423 DEROidCompare(algOid
, &oidSha224
)) {
6424 result
= kSecSignatureHashAlgorithmSHA224
;
6427 if (DEROidCompare(algOid
, &oidSha1Ecdsa
) ||
6428 DEROidCompare(algOid
, &oidSha1Rsa
) ||
6429 DEROidCompare(algOid
, &oidSha1Dsa
) ||
6430 DEROidCompare(algOid
, &oidSha1DsaOIW
) ||
6431 DEROidCompare(algOid
, &oidSha1DsaCommonOIW
) ||
6432 DEROidCompare(algOid
, &oidSha1RsaOIW
) ||
6433 DEROidCompare(algOid
, &oidSha1Fee
) ||
6434 DEROidCompare(algOid
, &oidSha1
)) {
6435 result
= kSecSignatureHashAlgorithmSHA1
;
6438 if (DEROidCompare(algOid
, &oidMd5Rsa
) ||
6439 DEROidCompare(algOid
, &oidMd5Fee
) ||
6440 DEROidCompare(algOid
, &oidMd5
)) {
6441 result
= kSecSignatureHashAlgorithmMD5
;
6444 if (DEROidCompare(algOid
, &oidMd4Rsa
) ||
6445 DEROidCompare(algOid
, &oidMd4
)) {
6446 result
= kSecSignatureHashAlgorithmMD4
;
6449 if (DEROidCompare(algOid
, &oidMd2Rsa
) ||
6450 DEROidCompare(algOid
, &oidMd2
)) {
6451 result
= kSecSignatureHashAlgorithmMD2
;
6460 CFArrayRef
SecCertificateCopyiPhoneDeviceCAChain(void) {
6461 CFMutableArrayRef result
= NULL
;
6462 SecCertificateRef iPhoneDeviceCA
= NULL
, iPhoneCA
= NULL
, appleRoot
= NULL
;
6464 require_quiet(iPhoneDeviceCA
= SecCertificateCreateWithBytes(NULL
, _AppleiPhoneDeviceCA
, sizeof(_AppleiPhoneDeviceCA
)),
6466 require_quiet(iPhoneCA
= SecCertificateCreateWithBytes(NULL
, _AppleiPhoneCA
, sizeof(_AppleiPhoneCA
)),
6468 require_quiet(appleRoot
= SecCertificateCreateWithBytes(NULL
, _AppleRootCA
, sizeof(_AppleRootCA
)),
6471 require_quiet(result
= CFArrayCreateMutable(NULL
, 3, &kCFTypeArrayCallBacks
), errOut
);
6472 CFArrayAppendValue(result
, iPhoneDeviceCA
);
6473 CFArrayAppendValue(result
, iPhoneCA
);
6474 CFArrayAppendValue(result
, appleRoot
);
6477 CFReleaseNull(iPhoneDeviceCA
);
6478 CFReleaseNull(iPhoneCA
);
6479 CFReleaseNull(appleRoot
);