2 * Copyright (c) 2006-2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * SecCertificate.c - CoreFoundation based certificate object
29 /* Allows us to build genanchors against the BaseSDK. */
30 #undef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
31 #undef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
34 #include <Security/SecCertificateInternal.h>
35 #include <utilities/SecIOFormat.h>
36 #include <CommonCrypto/CommonDigest.h>
37 #include <CoreFoundation/CFRuntime.h>
38 #include <CoreFoundation/CFString.h>
39 #include <CoreFoundation/CFBundle.h>
40 #include <CoreFoundation/CFDictionary.h>
41 #include <CoreFoundation/CFNumber.h>
42 #include <CoreFoundation/CFCalendar.h>
43 #include <CoreFoundation/CFTimeZone.h>
44 #include <CoreFoundation/CFXPCBridge.h>
46 #include <AssertMacros.h>
47 #include <libDER/DER_CertCrl.h>
48 #include <libDER/DER_Encode.h>
49 #include <libDER/DER_Keys.h>
50 #include <libDER/asn1Types.h>
51 #include <libDER/oidsPriv.h>
52 #include "SecBasePriv.h"
53 #include "SecRSAKey.h"
54 #include "SecFramework.h"
56 #include "SecItemPriv.h"
57 #include "SecSignatureVerificationSupport.h"
59 #include <utilities/debugging.h>
60 #include <utilities/SecCFWrappers.h>
61 #include <utilities/SecCFError.h>
62 #include <utilities/SecSCTUtils.h>
63 #include <utilities/array_size.h>
65 #include <libkern/OSByteOrder.h>
67 #include <Security/SecInternal.h>
68 #include <Security/SecFrameworkStrings.h>
69 #include "SecBase64.h"
70 #include "AppleBaselineEscrowCertificates.h"
71 #include <ipc/securityd_client.h>
72 #include <Security/SecKeyInternal.h>
74 /* The minimum key sizes necessary to not be considered "weak" */
75 #define MIN_RSA_KEY_SIZE 128 // 1024-bit
76 #define MIN_EC_KEY_SIZE 20 // 160-bit
78 typedef struct SecCertificateExtension
{
82 } SecCertificateExtension
;
85 typedef struct KnownExtension
{
92 kSecSelfSignedUnknown
= 0,
97 struct __SecCertificate
{
100 DERItem _der
; /* Entire certificate in DER form. */
101 DERItem _tbs
; /* To Be Signed cert DER bytes. */
102 DERAlgorithmId _sigAlg
; /* Top level signature algorithm. */
103 DERItem _signature
; /* The content of the sig bit string. */
106 DERItem _serialNum
; /* Integer. */
107 DERAlgorithmId _tbsSigAlg
; /* sig alg MUST be same as _sigAlg. */
108 DERItem _issuer
; /* Sequence of RDN. */
109 CFAbsoluteTime _notBefore
;
110 CFAbsoluteTime _notAfter
;
111 DERItem _subject
; /* Sequence of RDN. */
112 DERItem _subjectPublicKeyInfo
; /* SPKI */
113 DERAlgorithmId _algId
; /* oid and params of _pubKeyDER. */
114 DERItem _pubKeyDER
; /* contents of bit string */
115 DERItem _issuerUniqueID
; /* bit string, optional */
116 DERItem _subjectUniqueID
; /* bit string, optional */
119 /* Known extensions if the certificate contains them,
120 extnValue.length will be > 0. */
121 KnownExtension _authorityKeyID
;
123 /* This extension is used to uniquely identify a certificate from among
124 several that have the same subject name. If the extension is not
125 present, its value is calculated by performing a SHA-1 hash of the
126 certificate's DER encoded subjectPublicKeyInfo, as recommended by
128 KnownExtension _subjectKeyID
;
129 KnownExtension _keyUsage
;
130 KnownExtension _extendedKeyUsage
;
131 KnownExtension _basicConstraints
;
132 KnownExtension _netscapeCertType
;
133 KnownExtension _subjectAltName
;
134 KnownExtension _qualCertStatements
;
137 bool _foundUnknownCriticalExtension
;
139 /* Well known certificate extensions. */
140 SecCEBasicConstraints _basicConstraints
;
141 SecCEPolicyConstraints _policyConstraints
;
142 CFDictionaryRef _policyMappings
;
143 SecCECertificatePolicies _certificatePolicies
;
145 /* If InhibitAnyPolicy extension is not present or invalid UINT32_MAX,
146 value of the SkipCerts field of the InhibitAnyPolicy extension
148 uint32_t _inhibitAnyPolicySkipCerts
;
150 /* If KeyUsage extension is not present this is 0, otherwise it's
151 the value of the extension. */
152 SecKeyUsage _keyUsage
;
154 /* OCTETS of SubjectKeyIdentifier extensions KeyIdentifier.
155 Length = 0 if not present. */
156 DERItem _subjectKeyIdentifier
;
158 /* OCTETS of AuthorityKeyIdentifier extensions KeyIdentifier.
159 Length = 0 if not present. */
160 DERItem _authorityKeyIdentifier
;
161 /* AuthorityKeyIdentifier extension _authorityKeyIdentifierIssuer and
162 _authorityKeyIdentifierSerialNumber have non zero length if present.
163 Both are either present or absent together. */
164 DERItem _authorityKeyIdentifierIssuer
;
165 DERItem _authorityKeyIdentifierSerialNumber
;
167 /* Subject alt name extension, if present. Not malloced, it's just a
168 pointer to an element in the _extensions array. */
169 const SecCertificateExtension
*_subjectAltName
;
171 /* Parsed extension values. */
173 /* Array of CFURLRefs containing the URI values of crlDistributionPoints. */
174 CFMutableArrayRef _crlDistributionPoints
;
176 /* Array of CFURLRefs containing the URI values of accessLocations of each
177 id-ad-ocsp AccessDescription in the Authority Information Access
179 CFMutableArrayRef _ocspResponders
;
181 /* Array of CFURLRefs containing the URI values of accessLocations of each
182 id-ad-caIssuers AccessDescription in the Authority Information Access
184 CFMutableArrayRef _caIssuers
;
186 /* Array of CFDataRefs containing the generalNames for permittedSubtrees
188 CFArrayRef _permittedSubtrees
;
190 /* Array of CFDataRefs containing the generalNames for excludedSubtrees
192 CFArrayRef _excludedSubtrees
;
194 CFMutableArrayRef _embeddedSCTs
;
196 /* All other (non known) extensions. The _extensions array is malloced. */
197 CFIndex _extensionCount
;
198 SecCertificateExtension
*_extensions
;
200 /* Optional cached fields. */
203 CFArrayRef _properties
;
204 CFDataRef _serialNumber
;
205 CFDataRef _normalizedIssuer
;
206 CFDataRef _normalizedSubject
;
207 CFDataRef _authorityKeyID
;
208 CFDataRef _subjectKeyID
;
210 CFDataRef _sha1Digest
;
211 CFTypeRef _keychain_item
;
212 uint8_t _isSelfSigned
;
216 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
218 SEC_CONST_DECL (kSecCertificateProductionEscrowKey
, "ProductionEscrowKey");
219 SEC_CONST_DECL (kSecCertificateProductionPCSEscrowKey
, "ProductionPCSEscrowKey");
220 SEC_CONST_DECL (kSecCertificateEscrowFileName
, "AppleESCertificates");
222 /* Public Constants for property list keys. */
223 SEC_CONST_DECL (kSecPropertyKeyType
, "type");
224 SEC_CONST_DECL (kSecPropertyKeyLabel
, "label");
225 SEC_CONST_DECL (kSecPropertyKeyLocalizedLabel
, "localized label");
226 SEC_CONST_DECL (kSecPropertyKeyValue
, "value");
228 /* Public Constants for property list values. */
229 SEC_CONST_DECL (kSecPropertyTypeWarning
, "warning");
230 SEC_CONST_DECL (kSecPropertyTypeError
, "error");
231 SEC_CONST_DECL (kSecPropertyTypeSuccess
, "success");
232 SEC_CONST_DECL (kSecPropertyTypeTitle
, "title");
233 SEC_CONST_DECL (kSecPropertyTypeSection
, "section");
234 SEC_CONST_DECL (kSecPropertyTypeData
, "data");
235 SEC_CONST_DECL (kSecPropertyTypeString
, "string");
236 SEC_CONST_DECL (kSecPropertyTypeURL
, "url");
237 SEC_CONST_DECL (kSecPropertyTypeDate
, "date");
239 /* Extension parsing routine. */
240 typedef void (*SecCertificateExtensionParser
)(SecCertificateRef certificate
,
241 const SecCertificateExtension
*extn
);
243 /* Mapping from extension OIDs (as a DERItem *) to
244 SecCertificateExtensionParser extension parsing routines. */
245 static CFDictionaryRef sExtensionParsers
;
247 /* Forward declarations of static functions. */
248 static CFStringRef
SecCertificateDescribe(CFTypeRef cf
);
249 static void SecCertificateDestroy(CFTypeRef cf
);
250 static bool derDateGetAbsoluteTime(const DERItem
*dateChoice
,
251 CFAbsoluteTime
*absTime
) __attribute__((__nonnull__
));
253 /* Static functions. */
254 static CF_RETURNS_RETAINED CFStringRef
SecCertificateDescribe(CFTypeRef cf
) {
255 SecCertificateRef certificate
= (SecCertificateRef
)cf
;
256 CFStringRef subject
= SecCertificateCopySubjectSummary(certificate
);
257 CFStringRef issuer
= SecCertificateCopyIssuerSummary(certificate
);
258 CFStringRef desc
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
259 CFSTR("<cert(%p) s: %@ i: %@>"), certificate
, subject
, issuer
);
260 CFReleaseSafe(issuer
);
261 CFReleaseSafe(subject
);
265 static void SecCertificateDestroy(CFTypeRef cf
) {
266 SecCertificateRef certificate
= (SecCertificateRef
)cf
;
267 if (certificate
->_certificatePolicies
.policies
)
268 free(certificate
->_certificatePolicies
.policies
);
269 CFReleaseSafe(certificate
->_policyMappings
);
270 CFReleaseSafe(certificate
->_crlDistributionPoints
);
271 CFReleaseSafe(certificate
->_ocspResponders
);
272 CFReleaseSafe(certificate
->_caIssuers
);
273 if (certificate
->_extensions
) {
274 free(certificate
->_extensions
);
276 CFReleaseSafe(certificate
->_pubKey
);
277 CFReleaseSafe(certificate
->_der_data
);
278 CFReleaseSafe(certificate
->_properties
);
279 CFReleaseSafe(certificate
->_serialNumber
);
280 CFReleaseSafe(certificate
->_normalizedIssuer
);
281 CFReleaseSafe(certificate
->_normalizedSubject
);
282 CFReleaseSafe(certificate
->_authorityKeyID
);
283 CFReleaseSafe(certificate
->_subjectKeyID
);
284 CFReleaseSafe(certificate
->_sha1Digest
);
285 CFReleaseSafe(certificate
->_keychain_item
);
286 CFReleaseSafe(certificate
->_permittedSubtrees
);
287 CFReleaseSafe(certificate
->_excludedSubtrees
);
290 static Boolean
SecCertificateEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
291 SecCertificateRef cert1
= (SecCertificateRef
)cf1
;
292 SecCertificateRef cert2
= (SecCertificateRef
)cf2
;
295 if (!cert2
|| cert1
->_der
.length
!= cert2
->_der
.length
)
297 return !memcmp(cert1
->_der
.data
, cert2
->_der
.data
, cert1
->_der
.length
);
300 /* Hash of the certificate is der length + signature length + last 4 bytes
302 static CFHashCode
SecCertificateHash(CFTypeRef cf
) {
303 SecCertificateRef certificate
= (SecCertificateRef
)cf
;
304 size_t der_length
= certificate
->_der
.length
;
305 size_t sig_length
= certificate
->_signature
.length
;
306 size_t ix
= (sig_length
> 4) ? sig_length
- 4 : 0;
307 CFHashCode hashCode
= 0;
308 for (; ix
< sig_length
; ++ix
)
309 hashCode
= (hashCode
<< 8) + certificate
->_signature
.data
[ix
];
311 return (hashCode
+ der_length
+ sig_length
);
316 /************************************************************************/
317 /************************* General Name Parsing *************************/
318 /************************************************************************/
320 GeneralName ::= CHOICE {
321 otherName [0] OtherName,
322 rfc822Name [1] IA5String,
323 dNSName [2] IA5String,
324 x400Address [3] ORAddress,
325 directoryName [4] Name,
326 ediPartyName [5] EDIPartyName,
327 uniformResourceIdentifier [6] IA5String,
328 iPAddress [7] OCTET STRING,
329 registeredID [8] OBJECT IDENTIFIER}
331 OtherName ::= SEQUENCE {
332 type-id OBJECT IDENTIFIER,
333 value [0] EXPLICIT ANY DEFINED BY type-id }
335 EDIPartyName ::= SEQUENCE {
336 nameAssigner [0] DirectoryString OPTIONAL,
337 partyName [1] DirectoryString }
339 OSStatus
SecCertificateParseGeneralNameContentProperty(DERTag tag
,
340 const DERItem
*generalNameContent
,
341 void *context
, parseGeneralNameCallback callback
) {
343 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
344 return callback(context
, GNT_OtherName
, generalNameContent
);
345 case ASN1_CONTEXT_SPECIFIC
| 1:
346 return callback(context
, GNT_RFC822Name
, generalNameContent
);
347 case ASN1_CONTEXT_SPECIFIC
| 2:
348 return callback(context
, GNT_DNSName
, generalNameContent
);
349 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 3:
350 return callback(context
, GNT_X400Address
, generalNameContent
);
351 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 4:
352 return callback(context
, GNT_DirectoryName
, generalNameContent
);
353 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 5:
354 return callback(context
, GNT_EdiPartyName
, generalNameContent
);
355 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
357 /* Technically I don't think this is valid, but there are certs out
358 in the wild that use a constructed IA5String. In particular the
359 VeriSign Time Stamping Authority CA.cer does this. */
360 DERDecodedInfo uriContent
;
361 require_noerr(DERDecodeItem(generalNameContent
, &uriContent
), badDER
);
362 require(uriContent
.tag
== ASN1_IA5_STRING
, badDER
);
363 return callback(context
, GNT_URI
, &uriContent
.content
);
365 case ASN1_CONTEXT_SPECIFIC
| 6:
366 return callback(context
, GNT_URI
, generalNameContent
);
367 case ASN1_CONTEXT_SPECIFIC
| 7:
368 return callback(context
, GNT_IPAddress
, generalNameContent
);
369 case ASN1_CONTEXT_SPECIFIC
| 8:
370 return callback(context
, GNT_RegisteredID
, generalNameContent
);
375 return errSecInvalidCertificate
;
378 static OSStatus
parseGeneralNamesContent(const DERItem
*generalNamesContent
,
379 void *context
, parseGeneralNameCallback callback
) {
381 DERReturn drtn
= DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
);
382 require_noerr_quiet(drtn
, badDER
);
383 DERDecodedInfo generalNameContent
;
384 while ((drtn
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) ==
386 OSStatus status
= SecCertificateParseGeneralNameContentProperty(
387 generalNameContent
.tag
, &generalNameContent
.content
, context
,
392 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
393 return errSecSuccess
;
396 return errSecInvalidCertificate
;
399 OSStatus
SecCertificateParseGeneralNames(const DERItem
*generalNames
, void *context
,
400 parseGeneralNameCallback callback
) {
401 DERDecodedInfo generalNamesContent
;
402 DERReturn drtn
= DERDecodeItem(generalNames
, &generalNamesContent
);
403 require_noerr_quiet(drtn
, badDER
);
404 require_quiet(generalNamesContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
405 return parseGeneralNamesContent(&generalNamesContent
.content
, context
,
408 return errSecInvalidCertificate
;
414 GeneralName ::= CHOICE {
415 otherName [0] OtherName,
416 rfc822Name [1] IA5String,
417 dNSName [2] IA5String,
418 x400Address [3] ORAddress,
419 directoryName [4] Name,
420 ediPartyName [5] EDIPartyName,
421 uniformResourceIdentifier [6] IA5String,
422 iPAddress [7] OCTET STRING,
423 registeredID [8] OBJECT IDENTIFIER}
425 EDIPartyName ::= SEQUENCE {
426 nameAssigner [0] DirectoryString OPTIONAL,
427 partyName [1] DirectoryString }
429 static OSStatus
parseGeneralNameContentProperty(DERTag tag
,
430 const DERItem
*generalNameContent
, SecCEGeneralName
*generalName
) {
432 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
433 generalName
->nameType
= GNT_OtherName
;
434 generalName
->berEncoded
= true;
435 generalName
->name
= *generalNameContent
;
437 case ASN1_CONTEXT_SPECIFIC
| 1:
439 generalName
->nameType
= GNT_RFC822Name
;
440 generalName
->berEncoded
= false;
441 generalName
->name
= *generalNameContent
;
443 case ASN1_CONTEXT_SPECIFIC
| 2:
445 generalName
->nameType
= GNT_DNSName
;
446 generalName
->berEncoded
= false;
447 generalName
->name
= *generalNameContent
;
449 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 3:
450 generalName
->nameType
= GNT_X400Address
;
451 generalName
->berEncoded
= true;
452 generalName
->name
= *generalNameContent
;
454 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 4:
455 generalName
->nameType
= GNT_DirectoryName
;
456 generalName
->berEncoded
= true;
457 generalName
->name
= *generalNameContent
;
459 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 5:
460 generalName
->nameType
= GNT_EdiPartyName
;
461 generalName
->berEncoded
= true;
462 generalName
->name
= *generalNameContent
;
464 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
466 /* Technically I don't think this is valid, but there are certs out
467 in the wild that use a constructed IA5String. In particular the
468 VeriSign Time Stamping Authority CA.cer does this. */
469 DERDecodedInfo decoded
;
470 require_noerr(DERDecodeItem(generalNameContent
, &decoded
), badDER
);
471 require(decoded
.tag
== ASN1_IA5_STRING
, badDER
);
472 generalName
->nameType
= GNT_URI
;
473 generalName
->berEncoded
= false;
474 generalName
->name
= decoded
.content
;
477 case ASN1_CONTEXT_SPECIFIC
| 6:
478 generalName
->nameType
= GNT_URI
;
479 generalName
->berEncoded
= false;
480 generalName
->name
= *generalNameContent
;
482 case ASN1_CONTEXT_SPECIFIC
| 7:
483 /* @@@ This is the IP Address as an OCTECT STRING. For IPv4 it's
484 8 octects, addr/mask for ipv6 it's 32. */
485 generalName
->nameType
= GNT_IPAddress
;
486 generalName
->berEncoded
= false;
487 generalName
->name
= *generalNameContent
;
489 case ASN1_CONTEXT_SPECIFIC
| 8:
490 /* name is the content of an OID. */
491 generalName
->nameType
= GNT_RegisteredID
;
492 generalName
->berEncoded
= false;
493 generalName
->name
= *generalNameContent
;
499 return errSecSuccess
;
501 return errSecInvalidCertificate
;
505 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
507 static OSStatus
parseGeneralNamesContent(const DERItem
*generalNamesContent
,
508 CFIndex
*count
, SecCEGeneralName
**name
) {
509 SecCEGeneralName
*generalNames
= NULL
;
511 DERReturn drtn
= DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
);
512 require_noerr_quiet(drtn
, badDER
);
513 DERDecodedInfo generalNameContent
;
514 CFIndex generalNamesCount
= 0;
515 while ((drtn
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) ==
519 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
521 require(generalNames
= calloc(generalNamesCount
, sizeof(SecCEGeneralName
)),
523 DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
);
525 while ((drtn
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) ==
527 if (!parseGeneralNameContentProperty(generalNameContent
.tag
,
528 &generalNameContent
.content
, &generalNames
[ix
])) {
533 *count
= generalNamesCount
;
534 *name
= generalNames
;
535 return errSecSuccess
;
540 return errSecInvalidCertificate
;
543 static OSStatus
parseGeneralNames(const DERItem
*generalNames
,
544 CFIndex
*count
, SecCEGeneralName
**name
) {
545 DERDecodedInfo generalNamesContent
;
546 DERReturn drtn
= DERDecodeItem(generalNames
, &generalNamesContent
);
547 require_noerr_quiet(drtn
, badDER
);
548 require_quiet(generalNamesContent
.tag
== ASN1_CONSTR_SEQUENCE
,
550 parseGeneralNamesContent(&generalNamesContent
.content
, count
, name
);
551 return errSecSuccess
;
553 return errSecInvalidCertificate
;
557 /************************************************************************/
558 /************************** X.509 Name Parsing **************************/
559 /************************************************************************/
561 typedef OSStatus (*parseX501NameCallback
)(void *context
, const DERItem
*type
,
562 const DERItem
*value
, CFIndex rdnIX
);
564 static OSStatus
parseRDNContent(const DERItem
*rdnSetContent
, void *context
,
565 parseX501NameCallback callback
) {
567 DERReturn drtn
= DERDecodeSeqContentInit(rdnSetContent
, &rdn
);
568 require_noerr_quiet(drtn
, badDER
);
569 DERDecodedInfo atvContent
;
571 while ((drtn
= DERDecodeSeqNext(&rdn
, &atvContent
)) == DR_Success
) {
572 require_quiet(atvContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
573 DERAttributeTypeAndValue atv
;
574 drtn
= DERParseSequenceContent(&atvContent
.content
,
575 DERNumAttributeTypeAndValueItemSpecs
,
576 DERAttributeTypeAndValueItemSpecs
,
578 require_noerr_quiet(drtn
, badDER
);
579 require_quiet(atv
.type
.length
!= 0, badDER
);
580 OSStatus status
= callback(context
, &atv
.type
, &atv
.value
, rdnIX
++);
584 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
586 return errSecSuccess
;
588 return errSecInvalidCertificate
;
591 static OSStatus
parseX501NameContent(const DERItem
*x501NameContent
, void *context
,
592 parseX501NameCallback callback
) {
594 DERReturn drtn
= DERDecodeSeqContentInit(x501NameContent
, &derSeq
);
595 require_noerr_quiet(drtn
, badDER
);
596 DERDecodedInfo currDecoded
;
597 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
598 require_quiet(currDecoded
.tag
== ASN1_CONSTR_SET
, badDER
);
599 OSStatus status
= parseRDNContent(&currDecoded
.content
, context
,
604 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
606 return errSecSuccess
;
609 return errSecInvalidCertificate
;
612 static OSStatus
parseX501Name(const DERItem
*x501Name
, void *context
,
613 parseX501NameCallback callback
) {
614 DERDecodedInfo x501NameContent
;
615 if (DERDecodeItem(x501Name
, &x501NameContent
) ||
616 x501NameContent
.tag
!= ASN1_CONSTR_SEQUENCE
) {
617 return errSecInvalidCertificate
;
619 return parseX501NameContent(&x501NameContent
.content
, context
,
624 /************************************************************************/
625 /********************** Extension Parsing Routines **********************/
626 /************************************************************************/
628 static void SecCEPSubjectKeyIdentifier(SecCertificateRef certificate
,
629 const SecCertificateExtension
*extn
) {
630 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
631 DERDecodedInfo keyIdentifier
;
632 DERReturn drtn
= DERDecodeItem(&extn
->extnValue
, &keyIdentifier
);
633 require_noerr_quiet(drtn
, badDER
);
634 require_quiet(keyIdentifier
.tag
== ASN1_OCTET_STRING
, badDER
);
635 certificate
->_subjectKeyIdentifier
= keyIdentifier
.content
;
639 secwarning("Invalid SubjectKeyIdentifier Extension");
642 static void SecCEPKeyUsage(SecCertificateRef certificate
,
643 const SecCertificateExtension
*extn
) {
644 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
645 SecKeyUsage keyUsage
= extn
->critical
? kSecKeyUsageCritical
: 0;
646 DERDecodedInfo bitStringContent
;
647 DERReturn drtn
= DERDecodeItem(&extn
->extnValue
, &bitStringContent
);
648 require_noerr_quiet(drtn
, badDER
);
649 require_quiet(bitStringContent
.tag
== ASN1_BIT_STRING
, badDER
);
650 DERSize len
= bitStringContent
.content
.length
- 1;
651 require_quiet(len
== 1 || len
== 2, badDER
);
652 DERByte numUnusedBits
= bitStringContent
.content
.data
[0];
653 require_quiet(numUnusedBits
< 8, badDER
);
654 /* Flip the bits in the bit string so the first bit in the lsb. */
655 uint_fast16_t bits
= 8 * len
- numUnusedBits
;
656 uint_fast16_t value
= bitStringContent
.content
.data
[1];
659 value
= (value
<< 8) + bitStringContent
.content
.data
[2];
665 for (ix
= 0; ix
< bits
; ++ix
) {
671 certificate
->_keyUsage
= keyUsage
;
674 certificate
->_keyUsage
= kSecKeyUsageUnspecified
;
677 static void SecCEPPrivateKeyUsagePeriod(SecCertificateRef certificate
,
678 const SecCertificateExtension
*extn
) {
679 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
682 static void SecCEPSubjectAltName(SecCertificateRef certificate
,
683 const SecCertificateExtension
*extn
) {
684 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
685 certificate
->_subjectAltName
= extn
;
688 static void SecCEPIssuerAltName(SecCertificateRef certificate
,
689 const SecCertificateExtension
*extn
) {
690 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
693 static void SecCEPBasicConstraints(SecCertificateRef certificate
,
694 const SecCertificateExtension
*extn
) {
695 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
696 DERBasicConstraints basicConstraints
;
697 require_noerr_quiet(DERParseSequence(&extn
->extnValue
,
698 DERNumBasicConstraintsItemSpecs
, DERBasicConstraintsItemSpecs
,
699 &basicConstraints
, sizeof(basicConstraints
)), badDER
);
700 require_noerr_quiet(DERParseBooleanWithDefault(&basicConstraints
.cA
, false,
701 &certificate
->_basicConstraints
.isCA
), badDER
);
702 if (basicConstraints
.pathLenConstraint
.length
!= 0) {
703 require_noerr_quiet(DERParseInteger(
704 &basicConstraints
.pathLenConstraint
,
705 &certificate
->_basicConstraints
.pathLenConstraint
), badDER
);
706 certificate
->_basicConstraints
.pathLenConstraintPresent
= true;
708 certificate
->_basicConstraints
.present
= true;
709 certificate
->_basicConstraints
.critical
= extn
->critical
;
712 certificate
->_basicConstraints
.present
= false;
713 secwarning("Invalid BasicConstraints Extension");
718 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
720 * NameConstraints ::= SEQUENCE {
721 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
722 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
724 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
726 * GeneralSubtree ::= SEQUENCE {
728 * minimum [0] BaseDistance DEFAULT 0,
729 * maximum [1] BaseDistance OPTIONAL }
731 * BaseDistance ::= INTEGER (0..MAX)
733 static DERReturn
parseGeneralSubtrees(DERItem
*derSubtrees
, CFArrayRef
*generalSubtrees
) {
734 CFMutableArrayRef gs
= NULL
;
736 DERReturn drtn
= DERDecodeSeqContentInit(derSubtrees
, &gsSeq
);
737 require_noerr_quiet(drtn
, badDER
);
738 DERDecodedInfo gsContent
;
739 require_quiet(gs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
740 &kCFTypeArrayCallBacks
),
742 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
743 DERGeneralSubtree derGS
;
744 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
745 drtn
= DERParseSequenceContent(&gsContent
.content
,
746 DERNumGeneralSubtreeItemSpecs
,
747 DERGeneralSubtreeItemSpecs
,
748 &derGS
, sizeof(derGS
));
749 require_noerr_quiet(drtn
, badDER
);
752 * Within this profile, the minimum and maximum fields are not used with
753 * any name forms, thus, the minimum MUST be zero, and maximum MUST be
756 * Because minimum DEFAULT 0, absence equivalent to present and 0.
758 if (derGS
.minimum
.length
) {
760 require_noerr_quiet(DERParseInteger(&derGS
.minimum
, &minimum
),
762 require_quiet(minimum
== 0, badDER
);
764 require_quiet(derGS
.maximum
.length
== 0, badDER
);
765 require_quiet(derGS
.generalName
.length
!= 0, badDER
);
767 CFDataRef generalName
= NULL
;
768 require_quiet(generalName
= CFDataCreate(kCFAllocatorDefault
,
769 derGS
.generalName
.data
,
770 derGS
.generalName
.length
),
772 CFArrayAppendValue(gs
, generalName
);
773 CFReleaseNull(generalName
);
776 // since generalSubtrees is a pointer to an instance variable,
777 // make sure we release the existing array before assignment.
778 CFReleaseSafe(*generalSubtrees
);
779 *generalSubtrees
= gs
;
781 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
786 secdebug("cert","failed to parse GeneralSubtrees");
790 static void SecCEPNameConstraints(SecCertificateRef certificate
,
791 const SecCertificateExtension
*extn
) {
792 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
793 DERNameConstraints nc
;
795 drtn
= DERParseSequence(&extn
->extnValue
,
796 DERNumNameConstraintsItemSpecs
,
797 DERNameConstraintsItemSpecs
,
799 require_noerr_quiet(drtn
, badDER
);
800 if (nc
.permittedSubtrees
.length
) {
801 require_noerr_quiet(parseGeneralSubtrees(&nc
.permittedSubtrees
, &certificate
->_permittedSubtrees
), badDER
);
803 if (nc
.excludedSubtrees
.length
) {
804 require_noerr_quiet(parseGeneralSubtrees(&nc
.excludedSubtrees
, &certificate
->_excludedSubtrees
), badDER
);
809 secdebug("cert", "failed to parse Name Constraints extension");
812 static OSStatus
appendCRLDPFromGeneralNames(void *context
, SecCEGeneralNameType type
,
813 const DERItem
*value
) {
814 CFMutableArrayRef
*crlDPs
= (CFMutableArrayRef
*)context
;
815 if (type
== GNT_URI
) {
817 url
= CFURLCreateWithBytes(NULL
, value
->data
, value
->length
, kCFStringEncodingASCII
, NULL
);
820 *crlDPs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
822 CFArrayAppendValue(*crlDPs
, url
);
826 return errSecSuccess
;
830 id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 }
832 CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
834 DistributionPoint ::= SEQUENCE {
835 distributionPoint [0] DistributionPointName OPTIONAL,
836 reasons [1] ReasonFlags OPTIONAL,
837 cRLIssuer [2] GeneralNames OPTIONAL }
839 DistributionPointName ::= CHOICE {
840 fullName [0] GeneralNames,
841 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
843 static void SecCEPCrlDistributionPoints(SecCertificateRef certificate
,
844 const SecCertificateExtension
*extn
) {
845 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
846 DERSequence crlDPSeq
;
848 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &crlDPSeq
);
849 require_noerr_quiet(drtn
, badDER
);
850 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
851 DERDecodedInfo dpContent
;
852 while ((drtn
= DERDecodeSeqNext(&crlDPSeq
, &dpContent
)) == DR_Success
) {
853 require_quiet(dpContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
854 DERDistributionPoint dp
;
855 drtn
= DERParseSequenceContent(&dpContent
.content
, DERNumDistributionPointItemSpecs
,
856 DERDistributionPointItemSpecs
, &dp
, sizeof(dp
));
857 require_noerr_quiet(drtn
, badDER
);
858 require_quiet(dp
.distributionPoint
.data
|| dp
.cRLIssuer
.data
, badDER
);
859 if (dp
.distributionPoint
.data
) {
860 DERDecodedInfo dpName
;
861 drtn
= DERDecodeItem(&dp
.distributionPoint
, &dpName
);
862 require_noerr_quiet(drtn
, badDER
);
863 switch (dpName
.tag
) {
864 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
865 drtn
= parseGeneralNamesContent(&dpName
.content
, &certificate
->_crlDistributionPoints
,
866 appendCRLDPFromGeneralNames
);
867 require_noerr_quiet(drtn
, badDER
);
869 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1:
870 /* RelativeDistinguishName. Nothing we can do with that. */
876 if (dp
.cRLIssuer
.data
) {
877 drtn
= SecCertificateParseGeneralNames(&dp
.cRLIssuer
, &certificate
->_crlDistributionPoints
,
878 appendCRLDPFromGeneralNames
);
879 require_noerr_quiet(drtn
, badDER
);
882 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
885 secdebug("cert", "failed to parse CRL Distribution Points extension");
889 certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
891 PolicyInformation ::= SEQUENCE {
892 policyIdentifier CertPolicyId,
893 policyQualifiers SEQUENCE SIZE (1..MAX) OF
894 PolicyQualifierInfo OPTIONAL }
896 CertPolicyId ::= OBJECT IDENTIFIER
898 PolicyQualifierInfo ::= SEQUENCE {
899 policyQualifierId PolicyQualifierId,
900 qualifier ANY DEFINED BY policyQualifierId }
902 /* maximum number of policies of 8192 seems more than adequate */
903 #define MAX_CERTIFICATE_POLICIES 8192
904 static void SecCEPCertificatePolicies(SecCertificateRef certificate
,
905 const SecCertificateExtension
*extn
) {
906 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
909 SecCEPolicyInformation
*policies
= NULL
;
910 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &piSeq
);
911 require_noerr_quiet(drtn
, badDER
);
912 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
913 DERDecodedInfo piContent
;
914 DERSize policy_count
= 0;
915 while ((policy_count
< MAX_CERTIFICATE_POLICIES
) &&
916 (drtn
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) {
917 require_quiet(piContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
920 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
921 policies
= (SecCEPolicyInformation
*)malloc(sizeof(SecCEPolicyInformation
)
922 * (policy_count
> 0 ? policy_count
: 1));
923 DERDecodeSeqInit(&extn
->extnValue
, &tag
, &piSeq
);
924 DERSize policy_ix
= 0;
925 while ((policy_ix
< (policy_count
> 0 ? policy_count
: 1)) &&
926 (drtn
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) {
927 DERPolicyInformation pi
;
928 drtn
= DERParseSequenceContent(&piContent
.content
,
929 DERNumPolicyInformationItemSpecs
,
930 DERPolicyInformationItemSpecs
,
932 require_noerr_quiet(drtn
, badDER
);
933 policies
[policy_ix
].policyIdentifier
= pi
.policyIdentifier
;
934 policies
[policy_ix
++].policyQualifiers
= pi
.policyQualifiers
;
936 certificate
->_certificatePolicies
.present
= true;
937 certificate
->_certificatePolicies
.critical
= extn
->critical
;
938 certificate
->_certificatePolicies
.numPolicies
= policy_count
;
939 certificate
->_certificatePolicies
.policies
= policies
;
944 certificate
->_certificatePolicies
.present
= false;
945 secwarning("Invalid CertificatePolicies Extension");
949 id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 }
951 PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
952 issuerDomainPolicy CertPolicyId,
953 subjectDomainPolicy CertPolicyId }
956 static void SecCEPPolicyMappings(SecCertificateRef certificate
,
957 const SecCertificateExtension
*extn
) {
958 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
961 SecCEPolicyMapping
*mappings
= NULL
;
962 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &pmSeq
);
963 require_noerr_quiet(drtn
, badDER
);
964 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
965 DERDecodedInfo pmContent
;
966 DERSize mapping_count
= 0;
967 while ((drtn
= DERDecodeSeqNext(&pmSeq
, &pmContent
)) == DR_Success
) {
968 require_quiet(pmContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
971 mappings
= (SecCEPolicyMapping
*)malloc(sizeof(SecCEPolicyMapping
)
973 DERDecodeSeqInit(&extn
->extnValue
, &tag
, &pmSeq
);
974 DERSize mapping_ix
= 0;
975 while ((drtn
= DERDecodeSeqNext(&pmSeq
, &pmContent
)) == DR_Success
) {
977 drtn
= DERParseSequenceContent(&pmContent
.content
,
978 DERNumPolicyMappingItemSpecs
,
979 DERPolicyMappingItemSpecs
,
981 require_noerr_quiet(drtn
, badDER
);
982 mappings
[mapping_ix
].issuerDomainPolicy
= pm
.issuerDomainPolicy
;
983 mappings
[mapping_ix
++].subjectDomainPolicy
= pm
.subjectDomainPolicy
;
985 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
986 certificate
->_policyMappings
.present
= true;
987 certificate
->_policyMappings
.critical
= extn
->critical
;
988 certificate
->_policyMappings
.numMappings
= mapping_count
;
989 certificate
->_policyMappings
.mappings
= mappings
;
994 CFReleaseSafe(mappings
);
995 certificate
->_policyMappings
.present
= false;
996 secwarning("Invalid CertificatePolicies Extension");
999 static void SecCEPPolicyMappings(SecCertificateRef certificate
,
1000 const SecCertificateExtension
*extn
) {
1001 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1004 CFMutableDictionaryRef mappings
= NULL
;
1005 CFDataRef idp
= NULL
, sdp
= NULL
;
1006 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &pmSeq
);
1007 require_noerr_quiet(drtn
, badDER
);
1008 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1009 DERDecodedInfo pmContent
;
1010 require_quiet(mappings
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
1011 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
),
1013 while ((drtn
= DERDecodeSeqNext(&pmSeq
, &pmContent
)) == DR_Success
) {
1014 require_quiet(pmContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1015 DERPolicyMapping pm
;
1016 drtn
= DERParseSequenceContent(&pmContent
.content
,
1017 DERNumPolicyMappingItemSpecs
,
1018 DERPolicyMappingItemSpecs
,
1020 require_noerr_quiet(drtn
, badDER
);
1021 require_quiet(idp
= CFDataCreate(kCFAllocatorDefault
,
1022 pm
.issuerDomainPolicy
.data
, pm
.issuerDomainPolicy
.length
), badDER
);
1023 require_quiet(sdp
= CFDataCreate(kCFAllocatorDefault
,
1024 pm
.subjectDomainPolicy
.data
, pm
.subjectDomainPolicy
.length
), badDER
);
1025 CFMutableArrayRef sdps
=
1026 (CFMutableArrayRef
)CFDictionaryGetValue(mappings
, idp
);
1028 CFArrayAppendValue(sdps
, sdp
);
1030 require_quiet(sdps
= CFArrayCreateMutable(kCFAllocatorDefault
, 0,
1031 &kCFTypeArrayCallBacks
), badDER
);
1032 CFDictionarySetValue(mappings
, idp
, sdps
);
1038 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
1039 certificate
->_policyMappings
= mappings
;
1044 CFReleaseSafe(mappings
);
1045 certificate
->_policyMappings
= NULL
;
1046 secwarning("Invalid CertificatePolicies Extension");
1051 AuthorityKeyIdentifier ::= SEQUENCE {
1052 keyIdentifier [0] KeyIdentifier OPTIONAL,
1053 authorityCertIssuer [1] GeneralNames OPTIONAL,
1054 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
1055 -- authorityCertIssuer and authorityCertSerialNumber MUST both
1056 -- be present or both be absent
1058 KeyIdentifier ::= OCTET STRING
1060 static void SecCEPAuthorityKeyIdentifier(SecCertificateRef certificate
,
1061 const SecCertificateExtension
*extn
) {
1062 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1063 DERAuthorityKeyIdentifier akid
;
1065 drtn
= DERParseSequence(&extn
->extnValue
,
1066 DERNumAuthorityKeyIdentifierItemSpecs
,
1067 DERAuthorityKeyIdentifierItemSpecs
,
1068 &akid
, sizeof(akid
));
1069 require_noerr_quiet(drtn
, badDER
);
1070 if (akid
.keyIdentifier
.length
) {
1071 certificate
->_authorityKeyIdentifier
= akid
.keyIdentifier
;
1073 if (akid
.authorityCertIssuer
.length
||
1074 akid
.authorityCertSerialNumber
.length
) {
1075 require_quiet(akid
.authorityCertIssuer
.length
&&
1076 akid
.authorityCertSerialNumber
.length
, badDER
);
1077 /* Perhaps put in a subsection called Authority Certificate Issuer. */
1078 certificate
->_authorityKeyIdentifierIssuer
= akid
.authorityCertIssuer
;
1079 certificate
->_authorityKeyIdentifierSerialNumber
= akid
.authorityCertSerialNumber
;
1084 secwarning("Invalid AuthorityKeyIdentifier Extension");
1087 static void SecCEPPolicyConstraints(SecCertificateRef certificate
,
1088 const SecCertificateExtension
*extn
) {
1089 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1090 DERPolicyConstraints pc
;
1092 drtn
= DERParseSequence(&extn
->extnValue
,
1093 DERNumPolicyConstraintsItemSpecs
,
1094 DERPolicyConstraintsItemSpecs
,
1096 require_noerr_quiet(drtn
, badDER
);
1097 if (pc
.requireExplicitPolicy
.length
) {
1098 require_noerr_quiet(DERParseInteger(
1099 &pc
.requireExplicitPolicy
,
1100 &certificate
->_policyConstraints
.requireExplicitPolicy
), badDER
);
1101 certificate
->_policyConstraints
.requireExplicitPolicyPresent
= true;
1103 if (pc
.inhibitPolicyMapping
.length
) {
1104 require_noerr_quiet(DERParseInteger(
1105 &pc
.inhibitPolicyMapping
,
1106 &certificate
->_policyConstraints
.inhibitPolicyMapping
), badDER
);
1107 certificate
->_policyConstraints
.inhibitPolicyMappingPresent
= true;
1110 certificate
->_policyConstraints
.present
= true;
1111 certificate
->_policyConstraints
.critical
= extn
->critical
;
1115 certificate
->_policyConstraints
.present
= false;
1116 secwarning("Invalid PolicyConstraints Extension");
1119 static void SecCEPExtendedKeyUsage(SecCertificateRef certificate
,
1120 const SecCertificateExtension
*extn
) {
1121 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1125 InhibitAnyPolicy ::= SkipCerts
1127 SkipCerts ::= INTEGER (0..MAX)
1129 static void SecCEPInhibitAnyPolicy(SecCertificateRef certificate
,
1130 const SecCertificateExtension
*extn
) {
1131 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1132 require_noerr_quiet(DERParseInteger(
1134 &certificate
->_inhibitAnyPolicySkipCerts
), badDER
);
1137 certificate
->_inhibitAnyPolicySkipCerts
= UINT32_MAX
;
1138 secwarning("Invalid InhibitAnyPolicy Extension");
1142 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
1144 AuthorityInfoAccessSyntax ::=
1145 SEQUENCE SIZE (1..MAX) OF AccessDescription
1147 AccessDescription ::= SEQUENCE {
1148 accessMethod OBJECT IDENTIFIER,
1149 accessLocation GeneralName }
1151 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
1153 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
1155 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
1157 static void SecCEPAuthorityInfoAccess(SecCertificateRef certificate
,
1158 const SecCertificateExtension
*extn
) {
1159 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1162 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &adSeq
);
1163 require_noerr_quiet(drtn
, badDER
);
1164 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1165 DERDecodedInfo adContent
;
1166 while ((drtn
= DERDecodeSeqNext(&adSeq
, &adContent
)) == DR_Success
) {
1167 require_quiet(adContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1168 DERAccessDescription ad
;
1169 drtn
= DERParseSequenceContent(&adContent
.content
,
1170 DERNumAccessDescriptionItemSpecs
,
1171 DERAccessDescriptionItemSpecs
,
1173 require_noerr_quiet(drtn
, badDER
);
1174 CFMutableArrayRef
*urls
;
1175 if (DEROidCompare(&ad
.accessMethod
, &oidAdOCSP
))
1176 urls
= &certificate
->_ocspResponders
;
1177 else if (DEROidCompare(&ad
.accessMethod
, &oidAdCAIssuer
))
1178 urls
= &certificate
->_caIssuers
;
1182 DERDecodedInfo generalNameContent
;
1183 drtn
= DERDecodeItem(&ad
.accessLocation
, &generalNameContent
);
1184 require_noerr_quiet(drtn
, badDER
);
1185 switch (generalNameContent
.tag
) {
1187 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
1188 /* Technically I don't think this is valid, but there are certs out
1189 in the wild that use a constructed IA5String. In particular the
1190 VeriSign Time Stamping Authority CA.cer does this. */
1192 case ASN1_CONTEXT_SPECIFIC
| 6:
1194 CFURLRef url
= CFURLCreateWithBytes(kCFAllocatorDefault
,
1195 generalNameContent
.content
.data
, generalNameContent
.content
.length
,
1196 kCFStringEncodingASCII
, NULL
);
1199 *urls
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1200 CFArrayAppendValue(*urls
, url
);
1206 secdebug("cert", "bad general name for id-ad-ocsp AccessDescription t: 0x%02llx v: %.*s",
1207 generalNameContent
.tag
, (int) generalNameContent
.content
.length
, generalNameContent
.content
.data
);
1212 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
1215 secdebug("cert", "failed to parse Authority Information Access extension");
1218 /* Apple Worldwide Developer Relations Certificate Authority subject name.
1219 * This is a DER sequence with the leading tag and length bytes removed,
1220 * to match what tbsCert.issuer contains.
1222 static const unsigned char Apple_WWDR_CA_Subject_Name
[]={
1223 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
1224 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
1225 0x20,0x49,0x6E,0x63,0x2E,0x31,0x2C,0x30,0x2A,0x06,0x03,0x55,0x04,0x0B,0x0C,0x23,
1226 0x41,0x70,0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20,
1227 0x44,0x65,0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,
1228 0x6F,0x6E,0x73,0x31,0x44,0x30,0x42,0x06,0x03,0x55,0x04,0x03,0x0C,0x3B,0x41,0x70,
1229 0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20,0x44,0x65,
1230 0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,0x6F,0x6E,
1231 0x73,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,
1232 0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79
1235 static void checkForMissingRevocationInfo(SecCertificateRef certificate
) {
1237 certificate
->_crlDistributionPoints
||
1238 certificate
->_ocspResponders
) {
1239 /* We already have an OCSP or CRL URI (or no cert) */
1242 /* Specify an appropriate OCSP responder if we recognize the issuer. */
1243 CFURLRef url
= NULL
;
1244 if (sizeof(Apple_WWDR_CA_Subject_Name
) == certificate
->_issuer
.length
&&
1245 !memcmp(certificate
->_issuer
.data
, Apple_WWDR_CA_Subject_Name
,
1246 sizeof(Apple_WWDR_CA_Subject_Name
))) {
1247 const char *WWDR_OCSP_URI
= "http://ocsp.apple.com/ocsp-wwdr01";
1248 url
= CFURLCreateWithBytes(kCFAllocatorDefault
,
1249 (const UInt8
*)WWDR_OCSP_URI
, strlen(WWDR_OCSP_URI
),
1250 kCFStringEncodingASCII
, NULL
);
1253 CFMutableArrayRef
*urls
= &certificate
->_ocspResponders
;
1254 *urls
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1255 CFArrayAppendValue(*urls
, url
);
1260 static void SecCEPSubjectInfoAccess(SecCertificateRef certificate
,
1261 const SecCertificateExtension
*extn
) {
1262 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1265 static void SecCEPNetscapeCertType(SecCertificateRef certificate
,
1266 const SecCertificateExtension
*extn
) {
1267 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1270 static void SecCEPEntrustVersInfo(SecCertificateRef certificate
,
1271 const SecCertificateExtension
*extn
) {
1272 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1275 static void SecCEPEscrowMarker(SecCertificateRef certificate
,
1276 const SecCertificateExtension
*extn
) {
1277 secdebug("cert", "critical: %s", extn
->critical
? "yes" : "no");
1281 /* Dictionary key callback for comparing to DERItems. */
1282 static Boolean
SecDERItemEqual(const void *value1
, const void *value2
) {
1283 return DEROidCompare((const DERItem
*)value1
, (const DERItem
*)value2
);
1286 /* Dictionary key callback calculating the hash of a DERItem. */
1287 static CFHashCode
SecDERItemHash(const void *value
) {
1288 const DERItem
*derItem
= (const DERItem
*)value
;
1289 CFHashCode hash
= derItem
->length
;
1290 DERSize ix
= derItem
->length
> 8 ? derItem
->length
- 8 : 0;
1291 for (; ix
< derItem
->length
; ++ix
) {
1292 hash
= (hash
<< 9) + (hash
>> 23) + derItem
->data
[ix
];
1298 /* Dictionary key callbacks using the above 2 functions. */
1299 static const CFDictionaryKeyCallBacks SecDERItemKeyCallBacks
= {
1303 NULL
, /* copyDescription */
1304 SecDERItemEqual
, /* equal */
1305 SecDERItemHash
/* hash */
1308 static void SecCertificateInitializeExtensionParsers(void) {
1309 /* Build a dictionary that maps from extension OIDs to callback functions
1310 which can parse the extension of the type given. */
1311 static const void *extnOIDs
[] = {
1312 &oidSubjectKeyIdentifier
,
1314 &oidPrivateKeyUsagePeriod
,
1317 &oidBasicConstraints
,
1318 &oidNameConstraints
,
1319 &oidCrlDistributionPoints
,
1320 &oidCertificatePolicies
,
1322 &oidAuthorityKeyIdentifier
,
1323 &oidPolicyConstraints
,
1324 &oidExtendedKeyUsage
,
1325 &oidInhibitAnyPolicy
,
1326 &oidAuthorityInfoAccess
,
1327 &oidSubjectInfoAccess
,
1328 &oidNetscapeCertType
,
1329 &oidEntrustVersInfo
,
1330 &oidApplePolicyEscrowService
1332 static const void *extnParsers
[] = {
1333 SecCEPSubjectKeyIdentifier
,
1335 SecCEPPrivateKeyUsagePeriod
,
1336 SecCEPSubjectAltName
,
1337 SecCEPIssuerAltName
,
1338 SecCEPBasicConstraints
,
1339 SecCEPNameConstraints
,
1340 SecCEPCrlDistributionPoints
,
1341 SecCEPCertificatePolicies
,
1342 SecCEPPolicyMappings
,
1343 SecCEPAuthorityKeyIdentifier
,
1344 SecCEPPolicyConstraints
,
1345 SecCEPExtendedKeyUsage
,
1346 SecCEPInhibitAnyPolicy
,
1347 SecCEPAuthorityInfoAccess
,
1348 SecCEPSubjectInfoAccess
,
1349 SecCEPNetscapeCertType
,
1350 SecCEPEntrustVersInfo
,
1353 sExtensionParsers
= CFDictionaryCreate(kCFAllocatorDefault
, extnOIDs
,
1354 extnParsers
, array_size(extnOIDs
),
1355 &SecDERItemKeyCallBacks
, NULL
);
1358 CFGiblisWithFunctions(SecCertificate
, NULL
, NULL
, SecCertificateDestroy
, SecCertificateEqual
, SecCertificateHash
, NULL
, SecCertificateDescribe
, NULL
, NULL
, ^{
1359 SecCertificateInitializeExtensionParsers();
1362 static bool isAppleExtensionOID(const DERItem
*extnID
)
1364 static const uint8_t appleExtension
[8] = { 0x2a,0x86,0x48,0x86,0xf7,0x63,0x64,0x06 };
1365 return (extnID
&& extnID
->data
&&
1366 extnID
->length
> sizeof(appleExtension
) &&
1367 !memcmp(extnID
->data
, appleExtension
, sizeof(appleExtension
)));
1370 /* Given the contents of an X.501 Name return the contents of a normalized
1372 CFDataRef
createNormalizedX501Name(CFAllocatorRef allocator
,
1373 const DERItem
*x501name
) {
1374 CFMutableDataRef result
= CFDataCreateMutable(allocator
, x501name
->length
);
1375 CFIndex length
= x501name
->length
;
1376 CFDataSetLength(result
, length
);
1377 UInt8
*base
= CFDataGetMutableBytePtr(result
);
1380 DERReturn drtn
= DERDecodeSeqContentInit(x501name
, &rdnSeq
);
1382 require_noerr_quiet(drtn
, badDER
);
1385 /* Always points to last rdn tag. */
1386 const DERByte
*rdnTag
= rdnSeq
.nextItem
;
1387 /* Offset relative to base of current rdn set tag. */
1388 CFIndex rdnTagLocation
= 0;
1389 while ((drtn
= DERDecodeSeqNext(&rdnSeq
, &rdn
)) == DR_Success
) {
1390 require_quiet(rdn
.tag
== ASN1_CONSTR_SET
, badDER
);
1391 /* We don't allow empty RDNs. */
1392 require_quiet(rdn
.content
.length
!= 0, badDER
);
1393 /* Length of the tag and length of the current rdn. */
1394 CFIndex rdnTLLength
= rdn
.content
.data
- rdnTag
;
1395 CFIndex rdnContentLength
= rdn
.content
.length
;
1396 /* Copy the tag and length of the RDN. */
1397 memcpy(base
+ rdnTagLocation
, rdnTag
, rdnTLLength
);
1400 drtn
= DERDecodeSeqContentInit(&rdn
.content
, &atvSeq
);
1401 require_quiet(drtn
== DR_Success
, badDER
);
1404 /* Always points to tag of current atv sequence. */
1405 const DERByte
*atvTag
= atvSeq
.nextItem
;
1406 /* Offset relative to base of current atv sequence tag. */
1407 CFIndex atvTagLocation
= rdnTagLocation
+ rdnTLLength
;
1408 while ((drtn
= DERDecodeSeqNext(&atvSeq
, &atv
)) == DR_Success
) {
1409 require_quiet(atv
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
1410 /* Length of the tag and length of the current atv. */
1411 CFIndex atvTLLength
= atv
.content
.data
- atvTag
;
1412 CFIndex atvContentLength
= atv
.content
.length
;
1413 /* Copy the tag and length of the atv and the atv itself. */
1414 memcpy(base
+ atvTagLocation
, atvTag
,
1415 atvTLLength
+ atv
.content
.length
);
1417 /* Now decode the atv sequence. */
1418 DERAttributeTypeAndValue atvPair
;
1419 drtn
= DERParseSequenceContent(&atv
.content
,
1420 DERNumAttributeTypeAndValueItemSpecs
,
1421 DERAttributeTypeAndValueItemSpecs
,
1422 &atvPair
, sizeof(atvPair
));
1423 require_noerr_quiet(drtn
, badDER
);
1424 require_quiet(atvPair
.type
.length
!= 0, badDER
);
1425 DERDecodedInfo value
;
1426 drtn
= DERDecodeItem(&atvPair
.value
, &value
);
1427 require_noerr_quiet(drtn
, badDER
);
1429 /* (c) attribute values in PrintableString are not case sensitive
1430 (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and
1432 (d) attribute values in PrintableString are compared after
1433 removing leading and trailing white space and converting internal
1434 substrings of one or more consecutive white space characters to a
1436 if (value
.tag
== ASN1_PRINTABLE_STRING
) {
1437 /* Offset relative to base of current value tag. */
1438 CFIndex valueTagLocation
= atvTagLocation
+ atvPair
.value
.data
- atvTag
;
1439 CFIndex valueTLLength
= value
.content
.data
- atvPair
.value
.data
;
1440 CFIndex valueContentLength
= value
.content
.length
;
1442 /* Now copy all the bytes, but convert to upper case while
1443 doing so and convert multiple whitespace chars into a
1445 bool lastWasBlank
= false;
1446 CFIndex valueLocation
= valueTagLocation
+ valueTLLength
;
1447 CFIndex valueCurrentLocation
= valueLocation
;
1449 for (ix
= 0; ix
< valueContentLength
; ++ix
) {
1450 UInt8 ch
= value
.content
.data
[ix
];
1455 /* Don't insert a space for first character
1457 if (valueCurrentLocation
> valueLocation
) {
1458 base
[valueCurrentLocation
++] = ' ';
1460 lastWasBlank
= true;
1463 lastWasBlank
= false;
1464 if ('a' <= ch
&& ch
<= 'z') {
1465 base
[valueCurrentLocation
++] = ch
+ 'A' - 'a';
1467 base
[valueCurrentLocation
++] = ch
;
1471 /* Finally if lastWasBlank remove the trailing space. */
1472 if (lastWasBlank
&& valueCurrentLocation
> valueLocation
) {
1473 valueCurrentLocation
--;
1475 /* Adjust content length to normalized length. */
1476 valueContentLength
= valueCurrentLocation
- valueLocation
;
1478 /* Number of bytes by which the length should be shorted. */
1479 CFIndex lengthDiff
= value
.content
.length
- valueContentLength
;
1480 if (lengthDiff
== 0) {
1481 /* Easy case no need to adjust lengths. */
1483 /* Hard work we need to go back and fix up length fields
1485 1) The value itself.
1486 2) The ATV Sequence containing type/value
1487 3) The RDN Set containing one or more atv pairs.
1491 /* Step 1 fix up length of value. */
1492 /* Length of value tag and length minus the tag. */
1493 DERSize newValueTLLength
= valueTLLength
- 1;
1494 drtn
= DEREncodeLength(valueContentLength
,
1495 base
+ valueTagLocation
+ 1, &newValueTLLength
);
1496 require(drtn
== DR_Success
, badDER
);
1497 /* Add the length of the tag back in. */
1499 CFIndex valueLLDiff
= valueTLLength
- newValueTLLength
;
1501 /* The size of the length field changed, let's slide
1502 the value back by valueLLDiff bytes. */
1503 memmove(base
+ valueTagLocation
+ newValueTLLength
,
1504 base
+ valueTagLocation
+ valueTLLength
,
1505 valueContentLength
);
1506 /* The length diff for the enclosing object. */
1507 lengthDiff
+= valueLLDiff
;
1510 /* Step 2 fix up length of the enclosing ATV Sequence. */
1511 atvContentLength
-= lengthDiff
;
1512 DERSize newATVTLLength
= atvTLLength
- 1;
1513 drtn
= DEREncodeLength(atvContentLength
,
1514 base
+ atvTagLocation
+ 1, &newATVTLLength
);
1515 require(drtn
== DR_Success
, badDER
);
1516 /* Add the length of the tag back in. */
1518 CFIndex atvLLDiff
= atvTLLength
- newATVTLLength
;
1520 /* The size of the length field changed, let's slide
1521 the value back by valueLLDiff bytes. */
1522 memmove(base
+ atvTagLocation
+ newATVTLLength
,
1523 base
+ atvTagLocation
+ atvTLLength
,
1525 /* The length diff for the enclosing object. */
1526 lengthDiff
+= atvLLDiff
;
1527 atvTLLength
= newATVTLLength
;
1530 /* Step 3 fix up length of enclosing RDN Set. */
1531 rdnContentLength
-= lengthDiff
;
1532 DERSize newRDNTLLength
= rdnTLLength
- 1;
1533 drtn
= DEREncodeLength(rdnContentLength
,
1534 base
+ rdnTagLocation
+ 1, &newRDNTLLength
);
1535 require_quiet(drtn
== DR_Success
, badDER
);
1536 /* Add the length of the tag back in. */
1538 CFIndex rdnLLDiff
= rdnTLLength
- newRDNTLLength
;
1540 /* The size of the length field changed, let's slide
1541 the value back by valueLLDiff bytes. */
1542 memmove(base
+ rdnTagLocation
+ newRDNTLLength
,
1543 base
+ rdnTagLocation
+ rdnTLLength
,
1545 /* The length diff for the enclosing object. */
1546 lengthDiff
+= rdnLLDiff
;
1547 rdnTLLength
= newRDNTLLength
;
1549 /* Adjust the locations that might have changed due to
1551 atvTagLocation
-= rdnLLDiff
;
1553 (void) lengthDiff
; // No next object, silence analyzer
1556 atvTagLocation
+= atvTLLength
+ atvContentLength
;
1557 atvTag
= atvSeq
.nextItem
;
1559 rdnTagLocation
+= rdnTLLength
+ rdnContentLength
;
1560 rdnTag
= rdnSeq
.nextItem
;
1562 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
1563 /* Truncate the result to the proper length. */
1564 CFDataSetLength(result
, rdnTagLocation
);
1573 CFDataRef
SecDistinguishedNameCopyNormalizedContent(CFDataRef distinguished_name
)
1575 const DERItem name
= { (unsigned char *)CFDataGetBytePtr(distinguished_name
), CFDataGetLength(distinguished_name
) };
1576 DERDecodedInfo content
;
1577 /* Decode top level sequence into DERItem */
1578 if (!DERDecodeItem(&name
, &content
) && (content
.tag
== ASN1_CONSTR_SEQUENCE
))
1579 return createNormalizedX501Name(kCFAllocatorDefault
, &content
.content
);
1583 /* AUDIT[securityd]:
1584 certificate->_der is a caller provided data of any length (might be 0).
1586 Top level certificate decode.
1588 static bool SecCertificateParse(SecCertificateRef certificate
)
1593 require_quiet(certificate
, badCert
);
1594 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
1596 /* top level decode */
1597 DERSignedCertCrl signedCert
;
1598 drtn
= DERParseSequence(&certificate
->_der
, DERNumSignedCertCrlItemSpecs
,
1599 DERSignedCertCrlItemSpecs
, &signedCert
,
1600 sizeof(signedCert
));
1601 require_noerr_quiet(drtn
, badCert
);
1602 /* Store tbs since we need to digest it for verification later on. */
1603 certificate
->_tbs
= signedCert
.tbs
;
1605 /* decode the TBSCert - it was saved in full DER form */
1607 drtn
= DERParseSequence(&signedCert
.tbs
,
1608 DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
,
1609 &tbsCert
, sizeof(tbsCert
));
1610 require_noerr_quiet(drtn
, badCert
);
1612 /* sequence we're given: decode the signedCerts Signature Algorithm. */
1613 /* This MUST be the same as the certificate->_tbsSigAlg with the exception
1614 of the params field. */
1615 drtn
= DERParseSequenceContent(&signedCert
.sigAlg
,
1616 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
1617 &certificate
->_sigAlg
, sizeof(certificate
->_sigAlg
));
1618 require_noerr_quiet(drtn
, badCert
);
1620 /* The contents of signedCert.sig is a bit string whose contents
1621 are the signature itself. */
1622 DERByte numUnusedBits
;
1623 drtn
= DERParseBitString(&signedCert
.sig
,
1624 &certificate
->_signature
, &numUnusedBits
);
1625 require_noerr_quiet(drtn
, badCert
);
1627 /* Now decode the tbsCert. */
1629 /* First we turn the optional version into an int. */
1630 if (tbsCert
.version
.length
) {
1631 DERDecodedInfo decoded
;
1632 drtn
= DERDecodeItem(&tbsCert
.version
, &decoded
);
1633 require_noerr_quiet(drtn
, badCert
);
1634 require_quiet(decoded
.tag
== ASN1_INTEGER
, badCert
);
1635 require_quiet(decoded
.content
.length
== 1, badCert
);
1636 certificate
->_version
= decoded
.content
.data
[0];
1637 require_quiet(certificate
->_version
> 0, badCert
);
1638 require_quiet(certificate
->_version
< 3, badCert
);
1640 certificate
->_version
= 0;
1643 /* The serial number is in the tbsCert.serialNum - it was saved in
1644 INTEGER form without the tag and length. */
1645 certificate
->_serialNum
= tbsCert
.serialNum
;
1646 certificate
->_serialNumber
= CFDataCreate(allocator
,
1647 tbsCert
.serialNum
.data
, tbsCert
.serialNum
.length
);
1649 /* sequence we're given: decode the tbsCerts TBS Signature Algorithm. */
1650 drtn
= DERParseSequenceContent(&tbsCert
.tbsSigAlg
,
1651 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
1652 &certificate
->_tbsSigAlg
, sizeof(certificate
->_tbsSigAlg
));
1653 require_noerr_quiet(drtn
, badCert
);
1654 require_quiet(DEROidCompare(&certificate
->_sigAlg
.oid
,
1655 &certificate
->_tbsSigAlg
.oid
), badCert
);
1657 /* The issuer is in the tbsCert.issuer - it's a sequence without the tag
1658 and length fields. */
1659 certificate
->_issuer
= tbsCert
.issuer
;
1660 certificate
->_normalizedIssuer
= createNormalizedX501Name(allocator
,
1663 /* sequence we're given: decode the tbsCerts Validity sequence. */
1664 DERValidity validity
;
1665 drtn
= DERParseSequenceContent(&tbsCert
.validity
,
1666 DERNumValidityItemSpecs
, DERValidityItemSpecs
,
1667 &validity
, sizeof(validity
));
1668 require_noerr_quiet(drtn
, badCert
);
1669 require_quiet(derDateGetAbsoluteTime(&validity
.notBefore
,
1670 &certificate
->_notBefore
), badCert
);
1671 require_quiet(derDateGetAbsoluteTime(&validity
.notAfter
,
1672 &certificate
->_notAfter
), badCert
);
1674 /* The subject is in the tbsCert.subject - it's a sequence without the tag
1675 and length fields. */
1676 certificate
->_subject
= tbsCert
.subject
;
1677 certificate
->_normalizedSubject
= createNormalizedX501Name(allocator
,
1680 /* Keep the SPKI around for CT */
1681 certificate
->_subjectPublicKeyInfo
= tbsCert
.subjectPubKey
;
1683 /* sequence we're given: encoded DERSubjPubKeyInfo - it was saved in full DER form */
1684 DERSubjPubKeyInfo pubKeyInfo
;
1685 drtn
= DERParseSequence(&tbsCert
.subjectPubKey
,
1686 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
1687 &pubKeyInfo
, sizeof(pubKeyInfo
));
1688 require_noerr_quiet(drtn
, badCert
);
1690 /* sequence we're given: decode the pubKeyInfos DERAlgorithmId */
1691 drtn
= DERParseSequenceContent(&pubKeyInfo
.algId
,
1692 DERNumAlgorithmIdItemSpecs
, DERAlgorithmIdItemSpecs
,
1693 &certificate
->_algId
, sizeof(certificate
->_algId
));
1694 require_noerr_quiet(drtn
, badCert
);
1696 /* Now we can figure out the key's algorithm id and params based on
1697 certificate->_algId.oid. */
1699 /* The contents of pubKeyInfo.pubKey is a bit string whose contents
1700 are a PKCS1 format RSA key. */
1701 drtn
= DERParseBitString(&pubKeyInfo
.pubKey
,
1702 &certificate
->_pubKeyDER
, &numUnusedBits
);
1703 require_noerr_quiet(drtn
, badCert
);
1705 /* The contents of tbsCert.issuerID is a bit string. */
1706 certificate
->_issuerUniqueID
= tbsCert
.issuerID
;
1708 /* The contents of tbsCert.subjectID is a bit string. */
1709 certificate
->_subjectUniqueID
= tbsCert
.subjectID
;
1712 if (tbsCert
.extensions
.length
) {
1713 CFIndex extensionCount
= 0;
1716 drtn
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
,
1718 require_noerr_quiet(drtn
, badCert
);
1719 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badCert
);
1720 DERDecodedInfo currDecoded
;
1721 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
1723 /* ! = MUST recognize ? = SHOULD recognize
1726 KnownExtension _subjectKeyID
; /* ?SubjectKeyIdentifier id-ce 14 */
1727 KnownExtension _keyUsage
; /* !KeyUsage id-ce 15 */
1728 KnownExtension _subjectAltName
; /* !SubjectAltName id-ce 17 */
1729 KnownExtension _basicConstraints
; /* !BasicConstraints id-ce 19 */
1730 KnownExtension _authorityKeyID
; /* ?AuthorityKeyIdentifier id-ce 35 */
1731 KnownExtension _extKeyUsage
; /* !ExtKeyUsage id-ce 37 */
1732 KnownExtension _netscapeCertType
; /* 2.16.840.1.113730.1.1 netscape 1 1 */
1733 KnownExtension _qualCertStatements
; /* QCStatements id-pe 3 */
1735 KnownExtension _issuerAltName
; /* IssuerAltName id-ce 18 */
1736 KnownExtension _nameConstraints
; /* !NameConstraints id-ce 30 */
1737 KnownExtension _cRLDistributionPoints
; /* CRLDistributionPoints id-ce 31 */
1738 KnownExtension _certificatePolicies
; /* !CertificatePolicies id-ce 32 */
1739 KnownExtension _policyMappings
; /* ?PolicyMappings id-ce 33 */
1740 KnownExtension _policyConstraints
; /* !PolicyConstraints id-ce 36 */
1741 KnownExtension _freshestCRL
; /* FreshestCRL id-ce 46 */
1742 KnownExtension _inhibitAnyPolicy
; /* !InhibitAnyPolicy id-ce 54 */
1744 KnownExtension _authorityInfoAccess
; /* AuthorityInfoAccess id-pe 1 */
1745 KnownExtension _subjectInfoAccess
; /* SubjectInfoAccess id-pe 11 */
1750 require_quiet(drtn
== DR_EndOfSequence
, badCert
);
1752 /* Put some upper limit on the number of extensions allowed. */
1753 require_quiet(extensionCount
< 10000, badCert
);
1754 certificate
->_extensionCount
= extensionCount
;
1755 certificate
->_extensions
=
1756 malloc(sizeof(SecCertificateExtension
) * (extensionCount
> 0 ? extensionCount
: 1));
1759 drtn
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
, &derSeq
);
1760 require_noerr_quiet(drtn
, badCert
);
1761 for (ix
= 0; ix
< extensionCount
; ++ix
) {
1762 drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
);
1763 require_quiet(drtn
== DR_Success
||
1764 (ix
== extensionCount
- 1 && drtn
== DR_EndOfSequence
), badCert
);
1765 require_quiet(currDecoded
.tag
== ASN1_CONSTR_SEQUENCE
, badCert
);
1767 drtn
= DERParseSequenceContent(&currDecoded
.content
,
1768 DERNumExtensionItemSpecs
, DERExtensionItemSpecs
,
1769 &extn
, sizeof(extn
));
1770 require_noerr_quiet(drtn
, badCert
);
1771 /* Copy stuff into certificate->extensions[ix]. */
1772 certificate
->_extensions
[ix
].extnID
= extn
.extnID
;
1773 require_noerr_quiet(drtn
= DERParseBooleanWithDefault(&extn
.critical
, false,
1774 &certificate
->_extensions
[ix
].critical
), badCert
);
1775 certificate
->_extensions
[ix
].extnValue
= extn
.extnValue
;
1777 SecCertificateExtensionParser parser
=
1778 (SecCertificateExtensionParser
)CFDictionaryGetValue(
1779 sExtensionParsers
, &certificate
->_extensions
[ix
].extnID
);
1781 /* Invoke the parser. */
1782 parser(certificate
, &certificate
->_extensions
[ix
]);
1783 } else if (certificate
->_extensions
[ix
].critical
) {
1784 if (isAppleExtensionOID(&extn
.extnID
)) {
1787 secdebug("cert", "Found unknown critical extension");
1788 certificate
->_foundUnknownCriticalExtension
= true;
1790 secdebug("cert", "Found unknown non critical extension");
1794 checkForMissingRevocationInfo(certificate
);
1803 /* Public API functions. */
1804 SecCertificateRef
SecCertificateCreateWithBytes(CFAllocatorRef allocator
,
1805 const UInt8
*der_bytes
, CFIndex der_length
) {
1806 if (der_bytes
== NULL
) return NULL
;
1807 if (der_length
== 0) return NULL
;
1809 CFIndex size
= sizeof(struct __SecCertificate
) + der_length
;
1810 SecCertificateRef result
= (SecCertificateRef
)_CFRuntimeCreateInstance(
1811 allocator
, SecCertificateGetTypeID(), size
- sizeof(CFRuntimeBase
), 0);
1813 memset((char*)result
+ sizeof(result
->_base
), 0,
1814 sizeof(*result
) - sizeof(result
->_base
));
1815 result
->_der
.data
= ((DERByte
*)result
+ sizeof(*result
));
1816 result
->_der
.length
= der_length
;
1817 memcpy(result
->_der
.data
, der_bytes
, der_length
);
1818 if (!SecCertificateParse(result
)) {
1826 /* @@@ Placeholder until <rdar://problem/5701851> iap submits a binary is fixed. */
1827 SecCertificateRef
SecCertificateCreate(CFAllocatorRef allocator
,
1828 const UInt8
*der_bytes
, CFIndex der_length
);
1830 SecCertificateRef
SecCertificateCreate(CFAllocatorRef allocator
,
1831 const UInt8
*der_bytes
, CFIndex der_length
) {
1832 return SecCertificateCreateWithBytes(allocator
, der_bytes
, der_length
);
1834 /* @@@ End of placeholder. */
1836 /* AUDIT[securityd](done):
1837 der_certificate is a caller provided data of any length (might be 0), only
1838 its cf type has been checked.
1840 SecCertificateRef
SecCertificateCreateWithData(CFAllocatorRef allocator
,
1841 CFDataRef der_certificate
) {
1842 if (!der_certificate
) {
1845 CFIndex size
= sizeof(struct __SecCertificate
);
1846 SecCertificateRef result
= (SecCertificateRef
)_CFRuntimeCreateInstance(
1847 allocator
, SecCertificateGetTypeID(), size
- sizeof(CFRuntimeBase
), 0);
1849 memset((char*)result
+ sizeof(result
->_base
), 0, size
- sizeof(result
->_base
));
1850 result
->_der_data
= CFDataCreateCopy(allocator
, der_certificate
);
1851 result
->_der
.data
= (DERByte
*)CFDataGetBytePtr(result
->_der_data
);
1852 result
->_der
.length
= CFDataGetLength(result
->_der_data
);
1853 if (!SecCertificateParse(result
)) {
1861 SecCertificateRef
SecCertificateCreateWithKeychainItem(CFAllocatorRef allocator
,
1862 CFDataRef der_certificate
,
1863 CFTypeRef keychain_item
)
1865 SecCertificateRef result
= SecCertificateCreateWithData(allocator
, der_certificate
);
1867 CFRetainSafe(keychain_item
);
1868 result
->_keychain_item
= keychain_item
;
1873 OSStatus
SecCertificateSetKeychainItem(SecCertificateRef certificate
,
1874 CFTypeRef keychain_item
)
1879 CFRetainSafe(keychain_item
);
1880 CFReleaseSafe(certificate
->_keychain_item
);
1881 certificate
->_keychain_item
= keychain_item
;
1882 return errSecSuccess
;
1885 CFDataRef
SecCertificateCopyData(SecCertificateRef certificate
) {
1887 CFDataRef result
= NULL
;
1891 if (certificate
->_der_data
) {
1892 CFRetain(certificate
->_der_data
);
1893 result
= certificate
->_der_data
;
1895 result
= CFDataCreate(CFGetAllocator(certificate
),
1896 certificate
->_der
.data
, certificate
->_der
.length
);
1898 /* FIXME: If we wish to cache result we need to lock the certificate.
1899 Also this create 2 copies of the certificate data which is somewhat
1902 certificate
->_der_data
= result
;
1909 CFIndex
SecCertificateGetLength(SecCertificateRef certificate
) {
1910 return certificate
->_der
.length
;
1913 const UInt8
*SecCertificateGetBytePtr(SecCertificateRef certificate
) {
1914 return certificate
->_der
.data
;
1917 /* Used to recreate preCert from cert for Certificate Transparency */
1918 CFDataRef
SecCertificateCopyPrecertTBS(SecCertificateRef certificate
)
1920 CFDataRef outData
= NULL
;
1921 DERItem tbsIn
= certificate
->_tbs
;
1922 DERItem tbsOut
= {0,};
1923 DERItem extensionsOut
= {0,};
1924 DERItem
*extensionsList
= malloc(sizeof(DERItem
)*certificate
->_extensionCount
); /* This maybe one too many */
1925 DERItemSpec
*extensionsListSpecs
= malloc(sizeof(DERItemSpec
)*certificate
->_extensionCount
);
1929 /* decode the TBSCert - it was saved in full DER form */
1930 drtn
= DERParseSequence(&tbsIn
,
1931 DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
,
1932 &tbsCert
, sizeof(tbsCert
));
1933 require_noerr_quiet(drtn
, out
);
1935 /* Go over extensions and filter any SCT extension */
1936 CFIndex extensionsCount
= 0;
1938 if (tbsCert
.extensions
.length
) {
1941 drtn
= DERDecodeSeqInit(&tbsCert
.extensions
, &tag
,
1943 require_noerr_quiet(drtn
, out
);
1944 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, out
);
1945 DERDecodedInfo currDecoded
;
1946 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
1948 require_quiet(currDecoded
.tag
== ASN1_CONSTR_SEQUENCE
, out
);
1950 drtn
= DERParseSequenceContent(&currDecoded
.content
,
1951 DERNumExtensionItemSpecs
, DERExtensionItemSpecs
,
1952 &extn
, sizeof(extn
));
1953 require_noerr_quiet(drtn
, out
);
1955 if (extn
.extnID
.length
== oidGoogleEmbeddedSignedCertificateTimestamp
.length
&&
1956 !memcmp(extn
.extnID
.data
, oidGoogleEmbeddedSignedCertificateTimestamp
.data
, extn
.extnID
.length
))
1959 extensionsList
[extensionsCount
] = currDecoded
.content
;
1960 extensionsListSpecs
[extensionsCount
].offset
= sizeof(DERItem
)*extensionsCount
;
1961 extensionsListSpecs
[extensionsCount
].options
= 0;
1962 extensionsListSpecs
[extensionsCount
].tag
= ASN1_CONSTR_SEQUENCE
;
1967 require_quiet(drtn
== DR_EndOfSequence
, out
);
1971 /* Encode extensions */
1972 extensionsOut
.length
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, extensionsList
, extensionsCount
, extensionsListSpecs
);
1973 extensionsOut
.data
= malloc(extensionsOut
.length
);
1974 require_quiet(extensionsOut
.data
, out
);
1975 drtn
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, extensionsList
, extensionsCount
, extensionsListSpecs
, extensionsOut
.data
, &extensionsOut
.length
);
1976 require_noerr_quiet(drtn
, out
);
1978 tbsCert
.extensions
= extensionsOut
;
1980 tbsOut
.length
= DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE
, &tbsCert
, DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
);
1981 tbsOut
.data
= malloc(tbsOut
.length
);
1982 require_quiet(tbsOut
.data
, out
);
1983 drtn
= DEREncodeSequence(ASN1_CONSTR_SEQUENCE
, &tbsCert
, DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
, tbsOut
.data
, &tbsOut
.length
);
1984 require_noerr_quiet(drtn
, out
);
1986 outData
= CFDataCreate(kCFAllocatorDefault
, tbsOut
.data
, tbsOut
.length
);
1989 free(extensionsOut
.data
);
1991 free(extensionsList
);
1992 free(extensionsListSpecs
);
1997 /* From rfc3280 - Appendix B. ASN.1 Notes
1999 Object Identifiers (OIDs) are used throughout this specification to
2000 identify certificate policies, public key and signature algorithms,
2001 certificate extensions, etc. There is no maximum size for OIDs.
2002 This specification mandates support for OIDs which have arc elements
2003 with values that are less than 2^28, that is, they MUST be between 0
2004 and 268,435,455, inclusive. This allows each arc element to be
2005 represented within a single 32 bit word. Implementations MUST also
2006 support OIDs where the length of the dotted decimal (see [RFC 2252],
2007 section 4.1) string representation can be up to 100 bytes
2008 (inclusive). Implementations MUST be able to handle OIDs with up to
2009 20 elements (inclusive). CAs SHOULD NOT issue certificates which
2010 contain OIDs that exceed these requirements. Likewise, CRL issuers
2011 SHOULD NOT issue CRLs which contain OIDs that exceed these
2015 /* Oids longer than this are considered invalid. */
2016 #define MAX_OID_SIZE 32
2018 CFStringRef
SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator
,
2019 const DERItem
*oid
) {
2021 if (oid
->length
== 0) {
2022 return SecCopyCertString(SEC_NULL_KEY
);
2024 if (oid
->length
> MAX_OID_SIZE
) {
2025 return SecCopyCertString(SEC_OID_TOO_LONG_KEY
);
2028 CFMutableStringRef result
= CFStringCreateMutable(allocator
, 0);
2030 // The first two levels are encoded into one byte, since the root level
2031 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then
2032 // y may be > 39, so we have to add special-case handling for this.
2033 uint32_t x
= oid
->data
[0] / 40;
2034 uint32_t y
= oid
->data
[0] % 40;
2037 // Handle special case for large y if x = 2
2041 CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
);
2044 for (x
= 1; x
< oid
->length
; ++x
)
2046 value
= (value
<< 7) | (oid
->data
[x
] & 0x7F);
2047 /* @@@ value may not span more than 4 bytes. */
2048 /* A max number of 20 values is allowed. */
2049 if (!(oid
->data
[x
] & 0x80))
2051 CFStringAppendFormat(result
, NULL
, CFSTR(".%" PRIu32
), value
);
2058 static CFStringRef
copyLocalizedOidDescription(CFAllocatorRef allocator
,
2059 const DERItem
*oid
) {
2060 if (oid
->length
== 0) {
2061 return SecCopyCertString(SEC_NULL_KEY
);
2064 /* Build the key we use to lookup the localized OID description. */
2065 CFMutableStringRef oidKey
= CFStringCreateMutable(allocator
,
2066 oid
->length
* 3 + 5);
2067 CFStringAppendFormat(oidKey
, NULL
, CFSTR("06 %02lX"), oid
->length
);
2069 for (ix
= 0; ix
< oid
->length
; ++ix
)
2070 CFStringAppendFormat(oidKey
, NULL
, CFSTR(" %02X"), oid
->data
[ix
]);
2072 CFStringRef name
= SecFrameworkCopyLocalizedString(oidKey
, CFSTR("OID"));
2073 if (CFEqual(oidKey
, name
)) {
2075 name
= SecDERItemCopyOIDDecimalRepresentation(allocator
, oid
);
2082 /* Return the ipAddress as a dotted quad for ipv4 or as 8 colon separated
2083 4 digit hex strings for ipv6. Return NULL if the passed in IP doesn't
2084 have a length of exactly 4 or 16 octects. */
2085 static CFStringRef
copyIPAddressContentDescription(CFAllocatorRef allocator
,
2086 const DERItem
*ip
) {
2087 /* @@@ This is the IP Address as an OCTECT STRING. For IPv4 it's
2088 4 octects addr, or 8 octects, addr/mask for ipv6 it's
2089 16 octects addr, or 32 octects addr/mask. */
2090 CFStringRef value
= NULL
;
2091 if (ip
->length
== 4) {
2092 value
= CFStringCreateWithFormat(allocator
, NULL
,
2093 CFSTR("%u.%u.%u.%u"),
2094 ip
->data
[0], ip
->data
[1], ip
->data
[2], ip
->data
[3]);
2095 } else if (ip
->length
== 16) {
2096 value
= CFStringCreateWithFormat(allocator
, NULL
,
2097 CFSTR("%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
2098 "%02x%02x:%02x%02x:%02x%02x:%02x%02x"),
2099 ip
->data
[0], ip
->data
[1], ip
->data
[2], ip
->data
[3],
2100 ip
->data
[4], ip
->data
[5], ip
->data
[6], ip
->data
[7],
2101 ip
->data
[8], ip
->data
[9], ip
->data
[10], ip
->data
[11],
2102 ip
->data
[12], ip
->data
[13], ip
->data
[14], ip
->data
[15]);
2109 static CFStringRef
copyFullOidDescription(CFAllocatorRef allocator
,
2110 const DERItem
*oid
) {
2111 CFStringRef decimal
= SecDERItemCopyOIDDecimalRepresentation(allocator
, oid
);
2112 CFStringRef name
= copyLocalizedOidDescription(allocator
, oid
);
2113 CFStringRef oid_string
= CFStringCreateWithFormat(allocator
, NULL
,
2114 CFSTR("%@ (%@)"), name
, decimal
);
2121 void appendProperty(CFMutableArrayRef properties
, CFStringRef propertyType
,
2122 CFStringRef label
, CFStringRef localizedLabel
, CFTypeRef value
) {
2123 CFDictionaryRef property
;
2126 if (localizedLabel
) {
2129 ll
= localizedLabel
= SecCopyCertString(label
);
2131 const void *all_keys
[4];
2132 all_keys
[0] = kSecPropertyKeyType
;
2133 all_keys
[1] = kSecPropertyKeyLabel
;
2134 all_keys
[2] = kSecPropertyKeyLocalizedLabel
;
2135 all_keys
[3] = kSecPropertyKeyValue
;
2136 const void *property_values
[] = {
2142 property
= CFDictionaryCreate(CFGetAllocator(properties
),
2143 all_keys
, property_values
, value
? 4 : 3,
2144 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2147 const void *nolabel_keys
[2];
2148 nolabel_keys
[0] = kSecPropertyKeyType
;
2149 nolabel_keys
[1] = kSecPropertyKeyValue
;
2150 const void *property_values
[] = {
2154 property
= CFDictionaryCreate(CFGetAllocator(properties
),
2155 nolabel_keys
, property_values
, 2,
2156 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2159 CFArrayAppendValue(properties
, property
);
2160 CFRelease(property
);
2164 #define UTC_TIME_NOSEC_ZULU_LEN 11
2166 #define UTC_TIME_ZULU_LEN 13
2167 /* YYMMDDhhmmssThhmm */
2168 #define UTC_TIME_LOCALIZED_LEN 17
2169 /* YYYYMMDDhhmmssZ */
2170 #define GENERALIZED_TIME_ZULU_LEN 15
2171 /* YYYYMMDDhhmmssThhmm */
2172 #define GENERALIZED_TIME_LOCALIZED_LEN 19
2174 /* Parse 2 digits at (*p)[0] and (*p)[1] and return the result. Also
2176 static inline int parseDecimalPair(const DERByte
**p
) {
2177 const DERByte
*cp
= *p
;
2179 return 10 * (cp
[0] - '0') + cp
[1] - '0';
2182 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return
2183 true if the date was valid and properly decoded, also return the result in
2184 absTime. Return false otherwise. */
2185 CFAbsoluteTime
SecAbsoluteTimeFromDateContent(DERTag tag
, const uint8_t *bytes
,
2192 bool isUtcLength
= false;
2193 bool isLocalized
= false;
2194 bool noSeconds
= false;
2196 case UTC_TIME_NOSEC_ZULU_LEN
: /* YYMMDDhhmmZ */
2200 case UTC_TIME_ZULU_LEN
: /* YYMMDDhhmmssZ */
2203 case GENERALIZED_TIME_ZULU_LEN
: /* YYYYMMDDhhmmssZ */
2205 case UTC_TIME_LOCALIZED_LEN
: /* YYMMDDhhmmssThhmm (where T=[+,-]) */
2208 case GENERALIZED_TIME_LOCALIZED_LEN
:/* YYYYMMDDhhmmssThhmm (where T=[+,-]) */
2211 default: /* unknown format */
2215 /* Make sure the der tag fits the thing inside it. */
2216 if (tag
== ASN1_UTC_TIME
) {
2219 } else if (tag
== ASN1_GENERALIZED_TIME
) {
2226 const DERByte
*cp
= bytes
;
2227 /* Check that all characters are digits, except if localized the timezone
2228 indicator or if not localized the 'Z' at the end. */
2230 for (ix
= 0; ix
< length
; ++ix
) {
2231 if (!(isdigit(cp
[ix
]))) {
2232 if ((isLocalized
&& ix
== length
- 5 &&
2233 (cp
[ix
] == '+' || cp
[ix
] == '-')) ||
2234 (!isLocalized
&& ix
== length
- 1 && cp
[ix
] == 'Z')) {
2241 /* Parse the date and time fields. */
2242 int year
, month
, day
, hour
, minute
, second
;
2244 year
= parseDecimalPair(&cp
);
2246 /* 0 <= year < 50 : assume century 21 */
2248 } else if (year
< 70) {
2249 /* 50 <= year < 70 : illegal per PKIX */
2252 /* 70 < year <= 99 : assume century 20 */
2256 year
= 100 * parseDecimalPair(&cp
) + parseDecimalPair(&cp
);
2258 month
= parseDecimalPair(&cp
);
2259 day
= parseDecimalPair(&cp
);
2260 hour
= parseDecimalPair(&cp
);
2261 minute
= parseDecimalPair(&cp
);
2265 second
= parseDecimalPair(&cp
);
2268 CFTimeInterval timeZoneOffset
;
2270 /* ZONE INDICATOR */
2271 int multiplier
= *cp
++ == '+' ? 60 : -60;
2272 timeZoneOffset
= multiplier
*
2273 (parseDecimalPair(&cp
) * 60 + parseDecimalPair(&cp
));
2278 secdebug("dateparse",
2279 "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g",
2280 (int) length
, bytes
, year
, month
,
2281 day
, hour
, minute
, second
,
2282 timeZoneOffset
/ 60);
2284 static int mdays
[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
2285 int is_leap_year
= year
% 4 == 0 && (year
% 100 != 0 || year
% 400 == 0) ? 1 : 0;
2286 if (month
< 1 || month
> 12 || day
< 1 || day
> 31 || hour
> 23 || minute
> 59 || second
> 59
2287 || (month
== 2 && day
> mdays
[month
] - mdays
[month
- 1] + is_leap_year
)
2288 || (month
!= 2 && day
> mdays
[month
] - mdays
[month
- 1])) {
2293 int dy
= year
- 2001;
2298 int leap_days
= dy
/ 4 - dy
/ 100 + dy
/ 400;
2299 day
+= ((year
- 2001) * 365 + leap_days
) + mdays
[month
- 1] - 1;
2301 day
+= is_leap_year
;
2303 CFAbsoluteTime absTime
= (CFAbsoluteTime
)((day
* 24.0 + hour
) * 60.0 + minute
) * 60.0 + second
;
2304 return absTime
- timeZoneOffset
;
2307 __attribute__((__nonnull__
)) static bool derDateContentGetAbsoluteTime(DERTag tag
, const DERItem
*date
,
2308 CFAbsoluteTime
*pabsTime
) {
2309 CFAbsoluteTime absTime
= SecAbsoluteTimeFromDateContent(tag
, date
->data
,
2311 if (absTime
== NULL_TIME
)
2314 *pabsTime
= absTime
;
2318 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return
2319 true if the date was valid and properly decoded, also return the result in
2320 absTime. Return false otherwise. */
2321 __attribute__((__nonnull__
)) static bool derDateGetAbsoluteTime(const DERItem
*dateChoice
,
2322 CFAbsoluteTime
*absTime
) {
2323 if (dateChoice
->length
== 0) return false;
2325 DERDecodedInfo decoded
;
2326 if (DERDecodeItem(dateChoice
, &decoded
))
2329 return derDateContentGetAbsoluteTime(decoded
.tag
, &decoded
.content
,
2333 static void appendDataProperty(CFMutableArrayRef properties
,
2334 CFStringRef label
, CFStringRef localizedLabel
, const DERItem
*der_data
) {
2335 CFDataRef data
= CFDataCreate(CFGetAllocator(properties
),
2336 der_data
->data
, der_data
->length
);
2337 appendProperty(properties
, kSecPropertyTypeData
, label
, localizedLabel
,
2342 static void appendRelabeledProperty(CFMutableArrayRef properties
,
2344 CFStringRef localizedLabel
,
2345 const DERItem
*der_data
,
2346 CFStringRef labelFormat
) {
2347 CFStringRef newLabel
=
2348 CFStringCreateWithFormat(CFGetAllocator(properties
), NULL
,
2349 labelFormat
, label
);
2351 if (localizedLabel
) {
2354 ll
= localizedLabel
= SecCopyCertString(label
);
2356 CFStringRef localizedLabelFormat
= SecCopyCertString(labelFormat
);
2357 CFStringRef newLocalizedLabel
=
2358 CFStringCreateWithFormat(CFGetAllocator(properties
), NULL
,
2359 localizedLabelFormat
, localizedLabel
);
2361 CFReleaseSafe(localizedLabelFormat
);
2362 appendDataProperty(properties
, newLabel
, newLocalizedLabel
, der_data
);
2363 CFReleaseSafe(newLabel
);
2364 CFReleaseSafe(newLocalizedLabel
);
2368 static void appendUnparsedProperty(CFMutableArrayRef properties
,
2369 CFStringRef label
, CFStringRef localizedLabel
, const DERItem
*der_data
) {
2370 appendRelabeledProperty(properties
, label
, localizedLabel
, der_data
,
2374 static void appendInvalidProperty(CFMutableArrayRef properties
,
2375 CFStringRef label
, const DERItem
*der_data
) {
2376 appendRelabeledProperty(properties
, label
, NULL
, der_data
, SEC_INVALID_KEY
);
2379 static void appendDateContentProperty(CFMutableArrayRef properties
,
2380 CFStringRef label
, DERTag tag
,
2381 const DERItem
*dateContent
) {
2382 CFAbsoluteTime absTime
;
2383 if (!derDateContentGetAbsoluteTime(tag
, dateContent
, &absTime
)) {
2384 /* Date decode failure insert hex bytes instead. */
2385 return appendInvalidProperty(properties
, label
, dateContent
);
2387 CFDateRef date
= CFDateCreate(CFGetAllocator(properties
), absTime
);
2388 appendProperty(properties
, kSecPropertyTypeDate
, label
, NULL
, date
);
2392 static void appendDateProperty(CFMutableArrayRef properties
,
2393 CFStringRef label
, CFAbsoluteTime absTime
) {
2394 CFDateRef date
= CFDateCreate(CFGetAllocator(properties
), absTime
);
2395 appendProperty(properties
, kSecPropertyTypeDate
, label
, NULL
, date
);
2399 static void appendIPAddressContentProperty(CFMutableArrayRef properties
,
2400 CFStringRef label
, const DERItem
*ip
) {
2402 copyIPAddressContentDescription(CFGetAllocator(properties
), ip
);
2404 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, value
);
2407 appendUnparsedProperty(properties
, label
, NULL
, ip
);
2411 static void appendURLContentProperty(CFMutableArrayRef properties
,
2412 CFStringRef label
, const DERItem
*urlContent
) {
2413 CFURLRef url
= CFURLCreateWithBytes(CFGetAllocator(properties
),
2414 urlContent
->data
, urlContent
->length
, kCFStringEncodingASCII
, NULL
);
2416 appendProperty(properties
, kSecPropertyTypeURL
, label
, NULL
, url
);
2419 appendInvalidProperty(properties
, label
, urlContent
);
2423 static void appendURLProperty(CFMutableArrayRef properties
,
2424 CFStringRef label
, const DERItem
*url
) {
2425 DERDecodedInfo decoded
;
2428 drtn
= DERDecodeItem(url
, &decoded
);
2429 if (drtn
|| decoded
.tag
!= ASN1_IA5_STRING
) {
2430 appendInvalidProperty(properties
, label
, url
);
2432 appendURLContentProperty(properties
, label
, &decoded
.content
);
2436 static void appendOIDProperty(CFMutableArrayRef properties
,
2437 CFStringRef label
, CFStringRef llabel
, const DERItem
*oid
) {
2438 CFStringRef oid_string
=
2439 copyLocalizedOidDescription(CFGetAllocator(properties
), oid
);
2440 appendProperty(properties
, kSecPropertyTypeString
, label
, llabel
,
2442 CFRelease(oid_string
);
2445 static void appendAlgorithmProperty(CFMutableArrayRef properties
,
2446 CFStringRef label
, const DERAlgorithmId
*algorithm
) {
2447 CFMutableArrayRef alg_props
=
2448 CFArrayCreateMutable(CFGetAllocator(properties
), 0,
2449 &kCFTypeArrayCallBacks
);
2450 appendOIDProperty(alg_props
, SEC_ALGORITHM_KEY
, NULL
, &algorithm
->oid
);
2451 if (algorithm
->params
.length
) {
2452 if (algorithm
->params
.length
== 2 &&
2453 algorithm
->params
.data
[0] == ASN1_NULL
&&
2454 algorithm
->params
.data
[1] == 0) {
2455 CFStringRef value
= SecCopyCertString(SEC_NONE_KEY
);
2456 appendProperty(alg_props
, kSecPropertyTypeString
,
2457 SEC_PARAMETERS_KEY
, NULL
, value
);
2460 appendUnparsedProperty(alg_props
, SEC_PARAMETERS_KEY
, NULL
,
2461 &algorithm
->params
);
2464 appendProperty(properties
, kSecPropertyTypeSection
, label
, NULL
, alg_props
);
2465 CFRelease(alg_props
);
2468 static CFStringRef
copyHexDescription(CFAllocatorRef allocator
,
2469 const DERItem
*blob
) {
2470 CFIndex ix
, length
= blob
->length
/* < 24 ? blob->length : 24 */;
2471 CFMutableStringRef string
= CFStringCreateMutable(allocator
,
2472 blob
->length
* 3 - 1);
2473 for (ix
= 0; ix
< length
; ++ix
)
2475 CFStringAppendFormat(string
, NULL
, CFSTR("%02X"), blob
->data
[ix
]);
2477 CFStringAppendFormat(string
, NULL
, CFSTR(" %02X"), blob
->data
[ix
]);
2482 /* Returns a (localized) blob string. */
2483 static CFStringRef
copyBlobString(CFAllocatorRef allocator
,
2484 CFStringRef blobType
, CFStringRef quanta
, const DERItem
*blob
) {
2485 CFStringRef localizedBlobType
= SecCopyCertString(blobType
);
2486 CFStringRef localizedQuanta
= SecCopyCertString(quanta
);
2487 /* "format string for encoded field data (e.g. Sequence; 128 bytes; "
2488 "data = 00 00 ...)" */
2489 CFStringRef blobFormat
= SecCopyCertString(SEC_BLOB_KEY
);
2490 CFStringRef hex
= copyHexDescription(allocator
, blob
);
2491 CFStringRef result
= CFStringCreateWithFormat(allocator
, NULL
,
2492 blobFormat
, localizedBlobType
, blob
->length
, localizedQuanta
, hex
);
2494 CFRelease(blobFormat
);
2495 CFReleaseSafe(localizedQuanta
);
2496 CFReleaseSafe(localizedBlobType
);
2501 /* Return a string verbatim (unlocalized) from a DER field. */
2502 static CFStringRef
copyContentString(CFAllocatorRef allocator
,
2503 const DERItem
*string
, CFStringEncoding encoding
,
2504 bool printableOnly
) {
2505 /* Strip potential bogus trailing zero from printable strings. */
2506 DERSize length
= string
->length
;
2507 if (length
&& string
->data
[length
- 1] == 0) {
2508 /* Don't mess with the length of UTF16 strings though. */
2509 if (encoding
!= kCFStringEncodingUTF16
)
2512 /* A zero length string isn't considered printable. */
2513 if (!length
&& printableOnly
)
2516 /* Passing true for the 5th paramater to CFStringCreateWithBytes() makes
2517 it treat kCFStringEncodingUTF16 as big endian by default, whereas
2518 passing false makes it treat it as native endian by default. */
2519 CFStringRef result
= CFStringCreateWithBytes(allocator
, string
->data
,
2520 length
, encoding
, encoding
== kCFStringEncodingUTF16
);
2524 return printableOnly
? NULL
: copyHexDescription(allocator
, string
);
2527 /* From rfc3280 - Appendix B. ASN.1 Notes
2529 CAs MUST force the serialNumber to be a non-negative integer, that
2530 is, the sign bit in the DER encoding of the INTEGER value MUST be
2531 zero - this can be done by adding a leading (leftmost) `00'H octet if
2532 necessary. This removes a potential ambiguity in mapping between a
2533 string of octets and an integer value.
2535 As noted in section 4.1.2.2, serial numbers can be expected to
2536 contain long integers. Certificate users MUST be able to handle
2537 serialNumber values up to 20 octets in length. Conformant CAs MUST
2538 NOT use serialNumber values longer than 20 octets.
2541 /* Return the given numeric data as a string: decimal up to 64 bits,
2543 static CFStringRef
copyIntegerContentDescription(CFAllocatorRef allocator
,
2544 const DERItem
*integer
) {
2546 CFIndex ix
, length
= integer
->length
;
2548 if (length
== 0 || length
> 8)
2549 return copyHexDescription(allocator
, integer
);
2551 for(ix
= 0; ix
< length
; ++ix
) {
2553 value
+= integer
->data
[ix
];
2556 return CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%llu"), value
);
2559 static CFStringRef
copyDERThingContentDescription(CFAllocatorRef allocator
,
2560 DERTag tag
, const DERItem
*derThing
, bool printableOnly
) {
2564 return printableOnly
? NULL
: copyIntegerContentDescription(allocator
, derThing
);
2565 case ASN1_PRINTABLE_STRING
:
2566 case ASN1_IA5_STRING
:
2567 return copyContentString(allocator
, derThing
, kCFStringEncodingASCII
, printableOnly
);
2568 case ASN1_UTF8_STRING
:
2569 case ASN1_GENERAL_STRING
:
2570 case ASN1_UNIVERSAL_STRING
:
2571 return copyContentString(allocator
, derThing
, kCFStringEncodingUTF8
, printableOnly
);
2572 case ASN1_T61_STRING
: // 20, also BER_TAG_TELETEX_STRING
2573 case ASN1_VIDEOTEX_STRING
: // 21
2574 case ASN1_VISIBLE_STRING
: // 26
2575 return copyContentString(allocator
, derThing
, kCFStringEncodingISOLatin1
, printableOnly
);
2576 case ASN1_BMP_STRING
: // 30
2577 return copyContentString(allocator
, derThing
, kCFStringEncodingUTF16
, printableOnly
);
2578 case ASN1_OCTET_STRING
:
2579 return printableOnly
? NULL
:
2580 copyBlobString(allocator
, SEC_BYTE_STRING_KEY
, SEC_BYTES_KEY
,
2582 //return copyBlobString(BYTE_STRING_STR, BYTES_STR, derThing);
2583 case ASN1_BIT_STRING
:
2584 return printableOnly
? NULL
:
2585 copyBlobString(allocator
, SEC_BIT_STRING_KEY
, SEC_BITS_KEY
,
2587 case ASN1_CONSTR_SEQUENCE
:
2588 return printableOnly
? NULL
:
2589 copyBlobString(allocator
, SEC_SEQUENCE_KEY
, SEC_BYTES_KEY
,
2591 case ASN1_CONSTR_SET
:
2592 return printableOnly
? NULL
:
2593 copyBlobString(allocator
, SEC_SET_KEY
, SEC_BYTES_KEY
, derThing
);
2594 case ASN1_OBJECT_ID
:
2595 return printableOnly
? NULL
: copyLocalizedOidDescription(allocator
, derThing
);
2597 if (printableOnly
) {
2600 CFStringRef fmt
= SecCopyCertString(SEC_NOT_DISPLAYED_KEY
);
2601 CFStringRef result
= CFStringCreateWithFormat(allocator
, NULL
, fmt
,
2602 tag
, derThing
->length
);
2609 static CFStringRef
copyDERThingDescription(CFAllocatorRef allocator
,
2610 const DERItem
*derThing
, bool printableOnly
) {
2611 DERDecodedInfo decoded
;
2614 drtn
= DERDecodeItem(derThing
, &decoded
);
2616 /* TODO: Perhaps put something in the label saying we couldn't parse
2618 return printableOnly
? NULL
: copyHexDescription(allocator
, derThing
);
2620 return copyDERThingContentDescription(allocator
, decoded
.tag
,
2621 &decoded
.content
, false);
2625 static void appendDERThingProperty(CFMutableArrayRef properties
,
2626 CFStringRef label
, CFStringRef localizedLabel
, const DERItem
*derThing
) {
2627 CFStringRef value
= copyDERThingDescription(CFGetAllocator(properties
),
2629 appendProperty(properties
, kSecPropertyTypeString
, label
, localizedLabel
,
2631 CFReleaseSafe(value
);
2634 static OSStatus
appendRDNProperty(void *context
, const DERItem
*rdnType
,
2635 const DERItem
*rdnValue
, CFIndex rdnIX
) {
2636 CFMutableArrayRef properties
= (CFMutableArrayRef
)context
;
2638 /* If there is more than one value pair we create a subsection for the
2639 second pair, and append things to the subsection for subsequent
2641 CFIndex lastIX
= CFArrayGetCount(properties
) - 1;
2642 CFTypeRef lastValue
= CFArrayGetValueAtIndex(properties
, lastIX
);
2644 /* Since this is the second rdn pair for a given rdn, we setup a
2645 new subsection for this rdn. We remove the first property
2646 from the properties array and make it the first element in the
2647 subsection instead. */
2648 CFMutableArrayRef rdn_props
= CFArrayCreateMutable(
2649 CFGetAllocator(properties
), 0, &kCFTypeArrayCallBacks
);
2650 CFArrayAppendValue(rdn_props
, lastValue
);
2651 CFArrayRemoveValueAtIndex(properties
, lastIX
);
2652 appendProperty(properties
, kSecPropertyTypeSection
, NULL
, NULL
,
2654 properties
= rdn_props
;
2656 /* Since this is the third or later rdn pair we have already
2657 created a subsection in the top level properties array. Instead
2658 of appending to that directly we append to the array inside the
2660 properties
= (CFMutableArrayRef
)CFDictionaryGetValue(
2661 (CFDictionaryRef
)lastValue
, kSecPropertyKeyValue
);
2665 /* Finally we append the new rdn value to the property array. */
2666 CFStringRef label
= SecDERItemCopyOIDDecimalRepresentation(
2667 CFGetAllocator(properties
), rdnType
);
2668 CFStringRef localizedLabel
=
2669 copyLocalizedOidDescription(CFGetAllocator(properties
), rdnType
);
2670 appendDERThingProperty(properties
, label
, localizedLabel
, rdnValue
);
2671 CFReleaseSafe(label
);
2672 CFReleaseSafe(localizedLabel
);
2673 return errSecSuccess
;
2676 static CFArrayRef
createPropertiesForRDNContent(CFAllocatorRef allocator
,
2677 const DERItem
*rdnSetContent
) {
2678 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2679 &kCFTypeArrayCallBacks
);
2680 OSStatus status
= parseRDNContent(rdnSetContent
, properties
,
2683 CFArrayRemoveAllValues(properties
);
2684 appendInvalidProperty(properties
, SEC_RDN_KEY
, rdnSetContent
);
2691 From rfc3739 - 3.1.2. Subject
2693 When parsing the subject here are some tips for a short name of the cert.
2694 Choice I: commonName
2695 Choice II: givenName
2696 Choice III: pseudonym
2698 The commonName attribute value SHALL, when present, contain a name
2699 of the subject. This MAY be in the subject's preferred
2700 presentation format, or a format preferred by the CA, or some
2701 other format. Pseudonyms, nicknames, and names with spelling
2702 other than defined by the registered name MAY be used. To
2703 understand the nature of the name presented in commonName,
2704 complying applications MAY have to examine present values of the
2705 givenName and surname attributes, or the pseudonym attribute.
2708 static CFArrayRef
createPropertiesForX501NameContent(CFAllocatorRef allocator
,
2709 const DERItem
*x501NameContent
) {
2710 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2711 &kCFTypeArrayCallBacks
);
2712 OSStatus status
= parseX501NameContent(x501NameContent
, properties
,
2715 CFArrayRemoveAllValues(properties
);
2716 appendInvalidProperty(properties
, SEC_X501_NAME_KEY
, x501NameContent
);
2722 static CFArrayRef
createPropertiesForX501Name(CFAllocatorRef allocator
,
2723 const DERItem
*x501Name
) {
2724 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
2725 &kCFTypeArrayCallBacks
);
2726 OSStatus status
= parseX501Name(x501Name
, properties
, appendRDNProperty
);
2728 CFArrayRemoveAllValues(properties
);
2729 appendInvalidProperty(properties
, SEC_X501_NAME_KEY
, x501Name
);
2735 static void appendIntegerProperty(CFMutableArrayRef properties
,
2736 CFStringRef label
, const DERItem
*integer
) {
2737 CFStringRef string
= copyIntegerContentDescription(
2738 CFGetAllocator(properties
), integer
);
2739 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, string
);
2743 static void appendBoolProperty(CFMutableArrayRef properties
,
2744 CFStringRef label
, bool boolean
) {
2745 CFStringRef value
= SecCopyCertString(boolean
? SEC_YES_KEY
: SEC_NO_KEY
);
2746 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, value
);
2750 static void appendBooleanProperty(CFMutableArrayRef properties
,
2751 CFStringRef label
, const DERItem
*boolean
, bool defaultValue
) {
2753 DERReturn drtn
= DERParseBooleanWithDefault(boolean
, defaultValue
, &result
);
2755 /* Couldn't parse boolean; dump the raw unparsed data as hex. */
2756 appendInvalidProperty(properties
, label
, boolean
);
2758 appendBoolProperty(properties
, label
, result
);
2762 static void appendBitStringContentNames(CFMutableArrayRef properties
,
2763 CFStringRef label
, const DERItem
*bitStringContent
,
2764 const CFStringRef
*names
, CFIndex namesCount
) {
2765 DERSize len
= bitStringContent
->length
- 1;
2766 require_quiet(len
== 1 || len
== 2, badDER
);
2767 DERByte numUnusedBits
= bitStringContent
->data
[0];
2768 require_quiet(numUnusedBits
< 8, badDER
);
2769 uint_fast16_t bits
= 8 * len
- numUnusedBits
;
2770 require_quiet(bits
<= (uint_fast16_t)namesCount
, badDER
);
2771 uint_fast16_t value
= bitStringContent
->data
[1];
2774 value
= (value
<< 8) + bitStringContent
->data
[2];
2780 CFStringRef fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
2781 CFStringRef string
= NULL
;
2782 for (ix
= 0; ix
< bits
; ++ix
) {
2786 CFStringCreateWithFormat(CFGetAllocator(properties
),
2787 NULL
, fmt
, string
, names
[ix
]);
2798 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
2799 string
? string
: CFSTR(""));
2800 CFReleaseSafe(string
);
2803 appendInvalidProperty(properties
, label
, bitStringContent
);
2806 static void appendBitStringNames(CFMutableArrayRef properties
,
2807 CFStringRef label
, const DERItem
*bitString
,
2808 const CFStringRef
*names
, CFIndex namesCount
) {
2809 DERDecodedInfo bitStringContent
;
2810 DERReturn drtn
= DERDecodeItem(bitString
, &bitStringContent
);
2811 require_noerr_quiet(drtn
, badDER
);
2812 require_quiet(bitStringContent
.tag
== ASN1_BIT_STRING
, badDER
);
2813 appendBitStringContentNames(properties
, label
, &bitStringContent
.content
,
2817 appendInvalidProperty(properties
, label
, bitString
);
2821 typedef uint16_t SecKeyUsage
;
2823 #define kSecKeyUsageDigitalSignature 0x8000
2824 #define kSecKeyUsageNonRepudiation 0x4000
2825 #define kSecKeyUsageKeyEncipherment 0x2000
2826 #define kSecKeyUsageDataEncipherment 0x1000
2827 #define kSecKeyUsageKeyAgreement 0x0800
2828 #define kSecKeyUsageKeyCertSign 0x0400
2829 #define kSecKeyUsageCRLSign 0x0200
2830 #define kSecKeyUsageEncipherOnly 0x0100
2831 #define kSecKeyUsageDecipherOnly 0x0080
2834 KeyUsage ::= BIT STRING {
2835 digitalSignature (0),
2837 keyEncipherment (2),
2838 dataEncipherment (3),
2845 static void appendKeyUsage(CFMutableArrayRef properties
,
2846 const DERItem
*extnValue
) {
2847 if ((extnValue
->length
!= 4 && extnValue
->length
!= 5) ||
2848 extnValue
->data
[0] != ASN1_BIT_STRING
||
2849 extnValue
->data
[1] < 2 || extnValue
->data
[1] > 3 ||
2850 extnValue
->data
[2] > 7) {
2851 appendInvalidProperty(properties
, CFSTR("KeyUsage Extension"),
2854 CFMutableStringRef string
=
2855 CFStringCreateMutable(CFGetAllocator(properties
), 0);
2856 SecKeyUsage usage
= (extnValue
->data
[3] << 8);
2857 if (extnValue
->length
== 5)
2858 usage
+= extnValue
->data
[4];
2859 secdebug("keyusage", "keyusage: %04X", usage
);
2860 static const CFStringRef usageNames
[] = {
2861 CFSTR("Digital Signature"),
2862 CFSTR("Non-Repudiation"),
2863 CFSTR("Key Encipherment"),
2864 CFSTR("Data Encipherment"),
2865 CFSTR("Key Agreement"),
2871 bool didOne
= false;
2872 SecKeyUsage mask
= kSecKeyUsageDigitalSignature
;
2873 CFIndex ix
, bits
= (extnValue
->data
[1] - 1) * 8 - extnValue
->data
[2];
2874 for (ix
= 0; ix
< bits
; ++ix
) {
2877 CFStringAppend(string
, CFSTR(", "));
2881 /* @@@ Localize usageNames[ix]. */
2882 CFStringAppend(string
, usageNames
[ix
]);
2886 appendProperty(properties
, kSecPropertyTypeString
, CFSTR("Usage"),
2892 static void appendKeyUsage(CFMutableArrayRef properties
,
2893 const DERItem
*extnValue
) {
2894 static const CFStringRef usageNames
[] = {
2895 SEC_DIGITAL_SIGNATURE_KEY
,
2896 SEC_NON_REPUDIATION_KEY
,
2897 SEC_KEY_ENCIPHERMENT_KEY
,
2898 SEC_DATA_ENCIPHERMENT_KEY
,
2899 SEC_KEY_AGREEMENT_KEY
,
2902 SEC_ENCIPHER_ONLY_KEY
,
2903 SEC_DECIPHER_ONLY_KEY
2905 appendBitStringNames(properties
, SEC_USAGE_KEY
, extnValue
,
2906 usageNames
, array_size(usageNames
));
2910 static void appendPrivateKeyUsagePeriod(CFMutableArrayRef properties
,
2911 const DERItem
*extnValue
) {
2912 DERPrivateKeyUsagePeriod pkup
;
2913 DERReturn drtn
= DERParseSequence(extnValue
,
2914 DERNumPrivateKeyUsagePeriodItemSpecs
, DERPrivateKeyUsagePeriodItemSpecs
,
2915 &pkup
, sizeof(pkup
));
2916 require_noerr_quiet(drtn
, badDER
);
2917 if (pkup
.notBefore
.length
) {
2918 appendDateContentProperty(properties
, SEC_NOT_VALID_BEFORE_KEY
,
2919 ASN1_GENERALIZED_TIME
, &pkup
.notBefore
);
2921 if (pkup
.notAfter
.length
) {
2922 appendDateContentProperty(properties
, SEC_NOT_VALID_AFTER_KEY
,
2923 ASN1_GENERALIZED_TIME
, &pkup
.notAfter
);
2927 appendInvalidProperty(properties
, SEC_PRIVATE_KU_PERIOD_KEY
, extnValue
);
2930 static void appendStringContentProperty(CFMutableArrayRef properties
,
2931 CFStringRef label
, const DERItem
*stringContent
,
2932 CFStringEncoding encoding
) {
2933 CFStringRef string
= CFStringCreateWithBytes(CFGetAllocator(properties
),
2934 stringContent
->data
, stringContent
->length
, encoding
, FALSE
);
2936 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, string
);
2939 appendInvalidProperty(properties
, label
, stringContent
);
2944 OtherName ::= SEQUENCE {
2945 type-id OBJECT IDENTIFIER,
2946 value [0] EXPLICIT ANY DEFINED BY type-id }
2948 static void appendOtherNameContentProperty(CFMutableArrayRef properties
,
2949 const DERItem
*otherNameContent
) {
2951 DERReturn drtn
= DERParseSequenceContent(otherNameContent
,
2952 DERNumOtherNameItemSpecs
, DEROtherNameItemSpecs
,
2954 require_noerr_quiet(drtn
, badDER
);
2955 CFAllocatorRef allocator
= CFGetAllocator(properties
);
2957 SecDERItemCopyOIDDecimalRepresentation(allocator
, &on
.typeIdentifier
);
2958 CFStringRef localizedLabel
=
2959 copyLocalizedOidDescription(allocator
, &on
.typeIdentifier
);
2960 CFStringRef value_string
= copyDERThingDescription(allocator
, &on
.value
, false);
2962 appendProperty(properties
, kSecPropertyTypeString
, label
,
2963 localizedLabel
, value_string
);
2965 appendUnparsedProperty(properties
, label
, localizedLabel
, &on
.value
);
2967 CFReleaseSafe(value_string
);
2968 CFReleaseSafe(label
);
2969 CFReleaseSafe(localizedLabel
);
2972 appendInvalidProperty(properties
, SEC_OTHER_NAME_KEY
, otherNameContent
);
2976 GeneralName ::= CHOICE {
2977 otherName [0] OtherName,
2978 rfc822Name [1] IA5String,
2979 dNSName [2] IA5String,
2980 x400Address [3] ORAddress,
2981 directoryName [4] Name,
2982 ediPartyName [5] EDIPartyName,
2983 uniformResourceIdentifier [6] IA5String,
2984 iPAddress [7] OCTET STRING,
2985 registeredID [8] OBJECT IDENTIFIER}
2987 EDIPartyName ::= SEQUENCE {
2988 nameAssigner [0] DirectoryString OPTIONAL,
2989 partyName [1] DirectoryString }
2991 static bool appendGeneralNameContentProperty(CFMutableArrayRef properties
,
2992 DERTag tag
, const DERItem
*generalName
) {
2994 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0:
2995 appendOtherNameContentProperty(properties
, generalName
);
2997 case ASN1_CONTEXT_SPECIFIC
| 1:
2999 appendStringContentProperty(properties
, SEC_EMAIL_ADDRESS_KEY
,
3000 generalName
, kCFStringEncodingASCII
);
3002 case ASN1_CONTEXT_SPECIFIC
| 2:
3004 appendStringContentProperty(properties
, SEC_DNS_NAME_KEY
, generalName
,
3005 kCFStringEncodingASCII
);
3007 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 3:
3008 appendUnparsedProperty(properties
, SEC_X400_ADDRESS_KEY
, NULL
,
3011 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 4:
3013 CFArrayRef directory_plist
=
3014 createPropertiesForX501Name(CFGetAllocator(properties
),
3016 appendProperty(properties
, kSecPropertyTypeSection
,
3017 SEC_DIRECTORY_NAME_KEY
, NULL
, directory_plist
);
3018 CFRelease(directory_plist
);
3021 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 5:
3022 appendUnparsedProperty(properties
, SEC_EDI_PARTY_NAME_KEY
, NULL
,
3025 case ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 6:
3026 /* Technically I don't think this is valid, but there are certs out
3027 in the wild that use a constructed IA5String. In particular the
3028 VeriSign Time Stamping Authority CA.cer does this. */
3029 appendURLProperty(properties
, SEC_URI_KEY
, generalName
);
3031 case ASN1_CONTEXT_SPECIFIC
| 6:
3032 appendURLContentProperty(properties
, SEC_URI_KEY
, generalName
);
3034 case ASN1_CONTEXT_SPECIFIC
| 7:
3035 appendIPAddressContentProperty(properties
, SEC_IP_ADDRESS_KEY
,
3038 case ASN1_CONTEXT_SPECIFIC
| 8:
3039 appendOIDProperty(properties
, SEC_REGISTERED_ID_KEY
, NULL
, generalName
);
3050 static void appendGeneralNameProperty(CFMutableArrayRef properties
,
3051 const DERItem
*generalName
) {
3052 DERDecodedInfo generalNameContent
;
3053 DERReturn drtn
= DERDecodeItem(generalName
, &generalNameContent
);
3054 require_noerr_quiet(drtn
, badDER
);
3055 if (appendGeneralNameContentProperty(properties
, generalNameContent
.tag
,
3056 &generalNameContent
.content
))
3059 appendInvalidProperty(properties
, SEC_GENERAL_NAME_KEY
, generalName
);
3064 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
3066 static void appendGeneralNamesContent(CFMutableArrayRef properties
,
3067 const DERItem
*generalNamesContent
) {
3069 DERReturn drtn
= DERDecodeSeqContentInit(generalNamesContent
, &gnSeq
);
3070 require_noerr_quiet(drtn
, badDER
);
3071 DERDecodedInfo generalNameContent
;
3072 while ((drtn
= DERDecodeSeqNext(&gnSeq
, &generalNameContent
)) ==
3074 if (!appendGeneralNameContentProperty(properties
,
3075 generalNameContent
.tag
, &generalNameContent
.content
)) {
3079 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3082 appendInvalidProperty(properties
, SEC_GENERAL_NAMES_KEY
,
3083 generalNamesContent
);
3086 static void appendGeneralNames(CFMutableArrayRef properties
,
3087 const DERItem
*generalNames
) {
3088 DERDecodedInfo generalNamesContent
;
3089 DERReturn drtn
= DERDecodeItem(generalNames
, &generalNamesContent
);
3090 require_noerr_quiet(drtn
, badDER
);
3091 require_quiet(generalNamesContent
.tag
== ASN1_CONSTR_SEQUENCE
,
3093 appendGeneralNamesContent(properties
, &generalNamesContent
.content
);
3096 appendInvalidProperty(properties
, SEC_GENERAL_NAMES_KEY
, generalNames
);
3100 BasicConstraints ::= SEQUENCE {
3101 cA BOOLEAN DEFAULT FALSE,
3102 pathLenConstraint INTEGER (0..MAX) OPTIONAL }
3104 static void appendBasicConstraints(CFMutableArrayRef properties
,
3105 const DERItem
*extnValue
) {
3106 DERBasicConstraints basicConstraints
;
3107 DERReturn drtn
= DERParseSequence(extnValue
,
3108 DERNumBasicConstraintsItemSpecs
, DERBasicConstraintsItemSpecs
,
3109 &basicConstraints
, sizeof(basicConstraints
));
3110 require_noerr_quiet(drtn
, badDER
);
3112 appendBooleanProperty(properties
, SEC_CERT_AUTHORITY_KEY
,
3113 &basicConstraints
.cA
, false);
3115 if (basicConstraints
.pathLenConstraint
.length
!= 0) {
3116 appendIntegerProperty(properties
, SEC_PATH_LEN_CONSTRAINT_KEY
,
3117 &basicConstraints
.pathLenConstraint
);
3121 appendInvalidProperty(properties
, SEC_BASIC_CONSTRAINTS_KEY
, extnValue
);
3125 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
3127 * NameConstraints ::= SEQUENCE {
3128 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
3129 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
3131 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
3133 * GeneralSubtree ::= SEQUENCE {
3135 * minimum [0] BaseDistance DEFAULT 0,
3136 * maximum [1] BaseDistance OPTIONAL }
3138 * BaseDistance ::= INTEGER (0..MAX)
3140 static void appendNameConstraints(CFMutableArrayRef properties
,
3141 const DERItem
*extnValue
) {
3142 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3143 DERNameConstraints nc
;
3145 drtn
= DERParseSequence(extnValue
,
3146 DERNumNameConstraintsItemSpecs
,
3147 DERNameConstraintsItemSpecs
,
3149 require_noerr_quiet(drtn
, badDER
);
3150 if (nc
.permittedSubtrees
.length
) {
3152 require_noerr_quiet(DERDecodeSeqContentInit(&nc
.permittedSubtrees
, &gsSeq
), badDER
);
3153 DERDecodedInfo gsContent
;
3154 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
3155 DERGeneralSubtree derGS
;
3156 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
3157 drtn
= DERParseSequenceContent(&gsContent
.content
,
3158 DERNumGeneralSubtreeItemSpecs
,
3159 DERGeneralSubtreeItemSpecs
,
3160 &derGS
, sizeof(derGS
));
3161 require_noerr_quiet(drtn
, badDER
);
3162 if (derGS
.minimum
.length
) {
3163 appendIntegerProperty(properties
, SEC_PERMITTED_MINIMUM_KEY
, &derGS
.minimum
);
3165 if (derGS
.maximum
.length
) {
3166 appendIntegerProperty(properties
, SEC_PERMITTED_MAXIMUM_KEY
, &derGS
.maximum
);
3168 if (derGS
.generalName
.length
) {
3169 CFMutableArrayRef base
= CFArrayCreateMutable(allocator
, 0,
3170 &kCFTypeArrayCallBacks
);
3171 appendProperty(properties
, kSecPropertyTypeSection
,
3172 SEC_PERMITTED_NAME_KEY
, NULL
, base
);
3173 appendGeneralNameProperty(base
, &derGS
.generalName
);
3178 if (nc
.excludedSubtrees
.length
) {
3180 require_noerr_quiet(DERDecodeSeqContentInit(&nc
.excludedSubtrees
, &gsSeq
), badDER
);
3181 DERDecodedInfo gsContent
;
3182 while ((drtn
= DERDecodeSeqNext(&gsSeq
, &gsContent
)) == DR_Success
) {
3183 DERGeneralSubtree derGS
;
3184 require_quiet(gsContent
.tag
==ASN1_CONSTR_SEQUENCE
, badDER
);
3185 drtn
= DERParseSequenceContent(&gsContent
.content
,
3186 DERNumGeneralSubtreeItemSpecs
,
3187 DERGeneralSubtreeItemSpecs
,
3188 &derGS
, sizeof(derGS
));
3189 require_noerr_quiet(drtn
, badDER
);
3190 if (derGS
.minimum
.length
) {
3191 appendIntegerProperty(properties
, SEC_EXCLUDED_MINIMUM_KEY
, &derGS
.minimum
);
3193 if (derGS
.maximum
.length
) {
3194 appendIntegerProperty(properties
, SEC_EXCLUDED_MAXIMUM_KEY
, &derGS
.maximum
);
3196 if (derGS
.generalName
.length
) {
3197 CFMutableArrayRef base
= CFArrayCreateMutable(allocator
, 0,
3198 &kCFTypeArrayCallBacks
);
3199 appendProperty(properties
, kSecPropertyTypeSection
,
3200 SEC_EXCLUDED_NAME_KEY
, NULL
, base
);
3201 appendGeneralNameProperty(base
, &derGS
.generalName
);
3209 appendInvalidProperty(properties
, SEC_NAME_CONSTRAINTS_KEY
, extnValue
);
3213 CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
3215 DistributionPoint ::= SEQUENCE {
3216 distributionPoint [0] DistributionPointName OPTIONAL,
3217 reasons [1] ReasonFlags OPTIONAL,
3218 cRLIssuer [2] GeneralNames OPTIONAL }
3220 DistributionPointName ::= CHOICE {
3221 fullName [0] GeneralNames,
3222 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
3224 ReasonFlags ::= BIT STRING {
3228 affiliationChanged (3),
3230 cessationOfOperation (5),
3231 certificateHold (6),
3232 privilegeWithdrawn (7),
3235 static void appendCrlDistributionPoints(CFMutableArrayRef properties
,
3236 const DERItem
*extnValue
) {
3237 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3240 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &dpSeq
);
3241 require_noerr_quiet(drtn
, badDER
);
3242 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3243 DERDecodedInfo dpSeqContent
;
3244 while ((drtn
= DERDecodeSeqNext(&dpSeq
, &dpSeqContent
)) == DR_Success
) {
3245 require_quiet(dpSeqContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3246 DERDistributionPoint dp
;
3247 drtn
= DERParseSequenceContent(&dpSeqContent
.content
,
3248 DERNumDistributionPointItemSpecs
,
3249 DERDistributionPointItemSpecs
,
3251 require_noerr_quiet(drtn
, badDER
);
3252 if (dp
.distributionPoint
.length
) {
3253 DERDecodedInfo distributionPointName
;
3254 drtn
= DERDecodeItem(&dp
.distributionPoint
, &distributionPointName
);
3255 require_noerr_quiet(drtn
, badDER
);
3256 if (distributionPointName
.tag
==
3257 (ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 0)) {
3259 appendGeneralNamesContent(properties
,
3260 &distributionPointName
.content
);
3261 } else if (distributionPointName
.tag
==
3262 (ASN1_CONTEXT_SPECIFIC
| ASN1_CONSTRUCTED
| 1)) {
3263 CFArrayRef rdn_props
= createPropertiesForRDNContent(allocator
,
3265 appendProperty(properties
, kSecPropertyTypeSection
,
3266 SEC_NAME_REL_CRL_ISSUER_KEY
, NULL
, rdn_props
);
3267 CFRelease(rdn_props
);
3272 if (dp
.reasons
.length
) {
3273 static const CFStringRef reasonNames
[] = {
3275 SEC_KEY_COMPROMISE_KEY
,
3276 SEC_CA_COMPROMISE_KEY
,
3277 SEC_AFFILIATION_CHANGED_KEY
,
3279 SEC_CESSATION_OF_OPER_KEY
,
3280 SEC_CERTIFICATE_HOLD_KEY
,
3281 SEC_PRIV_WITHDRAWN_KEY
,
3282 SEC_AA_COMPROMISE_KEY
3284 appendBitStringContentNames(properties
, SEC_REASONS_KEY
,
3286 reasonNames
, array_size(reasonNames
));
3288 if (dp
.cRLIssuer
.length
) {
3289 CFMutableArrayRef crlIssuer
= CFArrayCreateMutable(allocator
, 0,
3290 &kCFTypeArrayCallBacks
);
3291 appendProperty(properties
, kSecPropertyTypeSection
,
3292 SEC_CRL_ISSUER_KEY
, NULL
, crlIssuer
);
3293 CFRelease(crlIssuer
);
3294 appendGeneralNames(crlIssuer
, &dp
.cRLIssuer
);
3297 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3300 appendInvalidProperty(properties
, SEC_CRL_DISTR_POINTS_KEY
, extnValue
);
3303 /* Decode a sequence of integers into a comma separated list of ints. */
3304 static void appendIntegerSequenceContent(CFMutableArrayRef properties
,
3305 CFStringRef label
, const DERItem
*intSequenceContent
) {
3306 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3308 DERReturn drtn
= DERDecodeSeqContentInit(intSequenceContent
, &intSeq
);
3309 require_noerr_quiet(drtn
, badDER
);
3310 DERDecodedInfo intContent
;
3311 CFStringRef value
= NULL
;
3312 CFStringRef fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
3313 while ((drtn
= DERDecodeSeqNext(&intSeq
, &intContent
)) == DR_Success
) {
3314 require_quiet(intContent
.tag
== ASN1_INTEGER
, badDER
);
3315 CFStringRef intDesc
= copyIntegerContentDescription(
3316 allocator
, &intContent
.content
);
3319 v
= CFStringCreateWithFormat(allocator
, NULL
, fmt
, value
, intDesc
);
3328 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3330 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
, value
);
3334 /* DROPTHOUGH if !value. */
3336 appendInvalidProperty(properties
, label
, intSequenceContent
);
3339 static void appendCertificatePolicies(CFMutableArrayRef properties
,
3340 const DERItem
*extnValue
) {
3341 CFAllocatorRef allocator
= CFGetAllocator(properties
);
3344 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &piSeq
);
3345 require_noerr_quiet(drtn
, badDER
);
3346 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3347 DERDecodedInfo piContent
;
3349 while ((drtn
= DERDecodeSeqNext(&piSeq
, &piContent
)) == DR_Success
) {
3350 require_quiet(piContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3351 DERPolicyInformation pi
;
3352 drtn
= DERParseSequenceContent(&piContent
.content
,
3353 DERNumPolicyInformationItemSpecs
,
3354 DERPolicyInformationItemSpecs
,
3356 require_noerr_quiet(drtn
, badDER
);
3357 CFStringRef piLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3358 SEC_POLICY_IDENTIFIER_KEY
, pin
);
3359 CFStringRef piFmt
= SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY
);
3360 CFStringRef lpiLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3363 appendOIDProperty(properties
, piLabel
, lpiLabel
, &pi
.policyIdentifier
);
3365 CFRelease(lpiLabel
);
3366 if (pi
.policyQualifiers
.length
== 0)
3370 drtn
= DERDecodeSeqContentInit(&pi
.policyQualifiers
, &pqSeq
);
3371 require_noerr_quiet(drtn
, badDER
);
3372 DERDecodedInfo pqContent
;
3374 while ((drtn
= DERDecodeSeqNext(&pqSeq
, &pqContent
)) == DR_Success
) {
3375 DERPolicyQualifierInfo pqi
;
3376 drtn
= DERParseSequenceContent(&pqContent
.content
,
3377 DERNumPolicyQualifierInfoItemSpecs
,
3378 DERPolicyQualifierInfoItemSpecs
,
3380 require_noerr_quiet(drtn
, badDER
);
3381 DERDecodedInfo qualifierContent
;
3382 drtn
= DERDecodeItem(&pqi
.qualifier
, &qualifierContent
);
3383 require_noerr_quiet(drtn
, badDER
);
3384 CFStringRef pqLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3385 SEC_POLICY_QUALIFIER_KEY
, pqn
);
3386 CFStringRef pqFmt
= SecCopyCertString(SEC_POLICY_QUALIFIER_KEY
);
3387 CFStringRef lpqLabel
= CFStringCreateWithFormat(allocator
, NULL
,
3390 appendOIDProperty(properties
, pqLabel
, lpqLabel
,
3391 &pqi
.policyQualifierID
);
3393 CFRelease(lpqLabel
);
3394 if (DEROidCompare(&oidQtCps
, &pqi
.policyQualifierID
)) {
3395 require_quiet(qualifierContent
.tag
== ASN1_IA5_STRING
, badDER
);
3396 appendURLContentProperty(properties
, SEC_CPS_URI_KEY
,
3397 &qualifierContent
.content
);
3398 } else if (DEROidCompare(&oidQtUNotice
, &pqi
.policyQualifierID
)) {
3399 require_quiet(qualifierContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3401 drtn
= DERParseSequenceContent(&qualifierContent
.content
,
3402 DERNumUserNoticeItemSpecs
,
3403 DERUserNoticeItemSpecs
,
3405 require_noerr_quiet(drtn
, badDER
);
3406 if (un
.noticeRef
.length
) {
3407 DERNoticeReference nr
;
3408 drtn
= DERParseSequenceContent(&un
.noticeRef
,
3409 DERNumNoticeReferenceItemSpecs
,
3410 DERNoticeReferenceItemSpecs
,
3412 require_noerr_quiet(drtn
, badDER
);
3413 appendDERThingProperty(properties
,
3414 SEC_ORGANIZATION_KEY
, NULL
,
3416 appendIntegerSequenceContent(properties
,
3417 SEC_NOTICE_NUMBERS_KEY
, &nr
.noticeNumbers
);
3419 if (un
.explicitText
.length
) {
3420 appendDERThingProperty(properties
, SEC_EXPLICIT_TEXT_KEY
,
3421 NULL
, &un
.explicitText
);
3424 appendUnparsedProperty(properties
, SEC_QUALIFIER_KEY
, NULL
,
3429 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3432 appendInvalidProperty(properties
, SEC_CERT_POLICIES_KEY
, extnValue
);
3435 static void appendSubjectKeyIdentifier(CFMutableArrayRef properties
,
3436 const DERItem
*extnValue
) {
3438 DERDecodedInfo keyIdentifier
;
3439 drtn
= DERDecodeItem(extnValue
, &keyIdentifier
);
3440 require_noerr_quiet(drtn
, badDER
);
3441 require_quiet(keyIdentifier
.tag
== ASN1_OCTET_STRING
, badDER
);
3442 appendDataProperty(properties
, SEC_KEY_IDENTIFIER_KEY
, NULL
,
3443 &keyIdentifier
.content
);
3447 appendInvalidProperty(properties
, SEC_SUBJ_KEY_ID_KEY
,
3452 AuthorityKeyIdentifier ::= SEQUENCE {
3453 keyIdentifier [0] KeyIdentifier OPTIONAL,
3454 authorityCertIssuer [1] GeneralNames OPTIONAL,
3455 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
3456 -- authorityCertIssuer and authorityCertSerialNumber MUST both
3457 -- be present or both be absent
3459 KeyIdentifier ::= OCTET STRING
3461 static void appendAuthorityKeyIdentifier(CFMutableArrayRef properties
,
3462 const DERItem
*extnValue
) {
3463 DERAuthorityKeyIdentifier akid
;
3465 drtn
= DERParseSequence(extnValue
,
3466 DERNumAuthorityKeyIdentifierItemSpecs
,
3467 DERAuthorityKeyIdentifierItemSpecs
,
3468 &akid
, sizeof(akid
));
3469 require_noerr_quiet(drtn
, badDER
);
3470 if (akid
.keyIdentifier
.length
) {
3471 appendDataProperty(properties
, SEC_KEY_IDENTIFIER_KEY
, NULL
,
3472 &akid
.keyIdentifier
);
3474 if (akid
.authorityCertIssuer
.length
||
3475 akid
.authorityCertSerialNumber
.length
) {
3476 require_quiet(akid
.authorityCertIssuer
.length
&&
3477 akid
.authorityCertSerialNumber
.length
, badDER
);
3478 /* Perhaps put in a subsection called Authority Certificate Issuer. */
3479 appendGeneralNamesContent(properties
,
3480 &akid
.authorityCertIssuer
);
3481 appendIntegerProperty(properties
, SEC_AUTH_CERT_SERIAL_KEY
,
3482 &akid
.authorityCertSerialNumber
);
3487 appendInvalidProperty(properties
, SEC_AUTHORITY_KEY_ID_KEY
, extnValue
);
3491 PolicyConstraints ::= SEQUENCE {
3492 requireExplicitPolicy [0] SkipCerts OPTIONAL,
3493 inhibitPolicyMapping [1] SkipCerts OPTIONAL }
3495 SkipCerts ::= INTEGER (0..MAX)
3497 static void appendPolicyConstraints(CFMutableArrayRef properties
,
3498 const DERItem
*extnValue
) {
3499 DERPolicyConstraints pc
;
3501 drtn
= DERParseSequence(extnValue
,
3502 DERNumPolicyConstraintsItemSpecs
,
3503 DERPolicyConstraintsItemSpecs
,
3505 require_noerr_quiet(drtn
, badDER
);
3506 if (pc
.requireExplicitPolicy
.length
) {
3507 appendIntegerProperty(properties
, SEC_REQUIRE_EXPL_POLICY_KEY
,
3508 &pc
.requireExplicitPolicy
);
3510 if (pc
.inhibitPolicyMapping
.length
) {
3511 appendIntegerProperty(properties
, SEC_INHIBIT_POLICY_MAP_KEY
,
3512 &pc
.inhibitPolicyMapping
);
3518 appendInvalidProperty(properties
, SEC_POLICY_CONSTRAINTS_KEY
, extnValue
);
3522 extendedKeyUsage EXTENSION ::= {
3523 SYNTAX SEQUENCE SIZE (1..MAX) OF KeyPurposeId
3524 IDENTIFIED BY id-ce-extKeyUsage }
3526 KeyPurposeId ::= OBJECT IDENTIFIER
3528 static void appendExtendedKeyUsage(CFMutableArrayRef properties
,
3529 const DERItem
*extnValue
) {
3532 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &derSeq
);
3533 require_noerr_quiet(drtn
, badDER
);
3534 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3535 DERDecodedInfo currDecoded
;
3536 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
3537 require_quiet(currDecoded
.tag
== ASN1_OBJECT_ID
, badDER
);
3538 appendOIDProperty(properties
, SEC_PURPOSE_KEY
, NULL
,
3539 &currDecoded
.content
);
3541 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3544 appendInvalidProperty(properties
, SEC_EXTENDED_KEY_USAGE_KEY
, extnValue
);
3548 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
3550 AuthorityInfoAccessSyntax ::=
3551 SEQUENCE SIZE (1..MAX) OF AccessDescription
3553 AccessDescription ::= SEQUENCE {
3554 accessMethod OBJECT IDENTIFIER,
3555 accessLocation GeneralName }
3557 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
3559 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
3561 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
3563 static void appendInfoAccess(CFMutableArrayRef properties
,
3564 const DERItem
*extnValue
) {
3567 DERReturn drtn
= DERDecodeSeqInit(extnValue
, &tag
, &adSeq
);
3568 require_noerr_quiet(drtn
, badDER
);
3569 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3570 DERDecodedInfo adContent
;
3571 while ((drtn
= DERDecodeSeqNext(&adSeq
, &adContent
)) == DR_Success
) {
3572 require_quiet(adContent
.tag
== ASN1_CONSTR_SEQUENCE
, badDER
);
3573 DERAccessDescription ad
;
3574 drtn
= DERParseSequenceContent(&adContent
.content
,
3575 DERNumAccessDescriptionItemSpecs
,
3576 DERAccessDescriptionItemSpecs
,
3578 require_noerr_quiet(drtn
, badDER
);
3579 appendOIDProperty(properties
, SEC_ACCESS_METHOD_KEY
, NULL
,
3581 //TODO: Do something with SEC_ACCESS_LOCATION_KEY
3582 appendGeneralNameProperty(properties
, &ad
.accessLocation
);
3584 require_quiet(drtn
== DR_EndOfSequence
, badDER
);
3587 appendInvalidProperty(properties
, SEC_AUTH_INFO_ACCESS_KEY
, extnValue
);
3590 static void appendNetscapeCertType(CFMutableArrayRef properties
,
3591 const DERItem
*extnValue
) {
3592 static const CFStringRef certTypes
[] = {
3596 SEC_OBJECT_SIGNING_KEY
,
3600 SEC_OBJECT_SIGNING_CA_KEY
3602 appendBitStringNames(properties
, SEC_USAGE_KEY
, extnValue
,
3603 certTypes
, array_size(certTypes
));
3607 static void appendEntrustVersInfo(CFMutableArrayRef properties
,
3608 const DERItem
*extnValue
) {
3612 * The list of Qualified Cert Statement statementIds we understand, even though
3613 * we don't actually do anything with them; if these are found in a Qualified
3614 * Cert Statement that's critical, we can truthfully say "yes we understand this".
3616 static const CSSM_OID_PTR knownQualifiedCertStatements
[] =
3618 /* id-qcs := { id-pkix 11 } */
3619 (const CSSM_OID_PTR
)&CSSMOID_OID_QCS_SYNTAX_V1
, /* id-qcs 1 */
3620 (const CSSM_OID_PTR
)&CSSMOID_OID_QCS_SYNTAX_V2
, /* id-qcs 2 */
3621 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_COMPLIANCE
,
3622 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_LIMIT_VALUE
,
3623 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_RETENTION
,
3624 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_SSCD
3626 #define NUM_KNOWN_QUAL_CERT_STATEMENTS (sizeof(knownQualifiedCertStatements) / sizeof(CSSM_OID_PTR))
3628 static void appendQCCertStatements(CFMutableArrayRef properties
,
3629 const DERItem
*extnValue
) {
3634 static bool appendPrintableDERSequence(CFMutableArrayRef properties
,
3635 CFStringRef label
, const DERItem
*sequence
) {
3638 DERReturn drtn
= DERDecodeSeqInit(sequence
, &tag
, &derSeq
);
3639 require_noerr_quiet(drtn
, badSequence
);
3640 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, badSequence
);
3641 DERDecodedInfo currDecoded
;
3642 bool appendedSomething
= false;
3643 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
3644 switch (currDecoded
.tag
)
3647 case ASN1_SEQUENCE
: // 16
3648 case ASN1_SET
: // 17
3649 // skip constructed object lengths
3652 case ASN1_UTF8_STRING
: // 12
3653 case ASN1_NUMERIC_STRING
: // 18
3654 case ASN1_PRINTABLE_STRING
: // 19
3655 case ASN1_T61_STRING
: // 20, also ASN1_TELETEX_STRING
3656 case ASN1_VIDEOTEX_STRING
: // 21
3657 case ASN1_IA5_STRING
: // 22
3658 case ASN1_GRAPHIC_STRING
: // 25
3659 case ASN1_VISIBLE_STRING
: // 26, also ASN1_ISO646_STRING
3660 case ASN1_GENERAL_STRING
: // 27
3661 case ASN1_UNIVERSAL_STRING
: // 28
3663 CFStringRef string
=
3664 copyDERThingContentDescription(CFGetAllocator(properties
),
3665 currDecoded
.tag
, &currDecoded
.content
, false);
3666 //CFStringRef cleanString = copyStringRemovingPercentEscapes(string);
3668 appendProperty(properties
, kSecPropertyTypeString
, label
, NULL
,
3671 appendedSomething
= true;
3678 require_quiet(drtn
== DR_EndOfSequence
, badSequence
);
3679 return appendedSomething
;
3684 static void appendExtension(CFMutableArrayRef parent
,
3685 const SecCertificateExtension
*extn
) {
3686 CFAllocatorRef allocator
= CFGetAllocator(parent
);
3687 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
3688 &kCFTypeArrayCallBacks
);
3690 *extnID
= &extn
->extnID
,
3691 *extnValue
= &extn
->extnValue
;
3692 CFStringRef label
= NULL
;
3693 CFStringRef localizedLabel
= NULL
;
3695 appendBoolProperty(properties
, SEC_CRITICAL_KEY
, extn
->critical
);
3696 require_quiet(extnID
, xit
);
3699 bool handled
= true;
3700 /* Extensions that we know how to handle ourselves... */
3701 if (extnID
->length
== oidSubjectKeyIdentifier
.length
&&
3702 !memcmp(extnID
->data
, oidSubjectKeyIdentifier
.data
, extnID
->length
- 1))
3704 switch (extnID
->data
[extnID
->length
- 1]) {
3705 case 14: /* SubjectKeyIdentifier id-ce 14 */
3706 appendSubjectKeyIdentifier(properties
, extnValue
);
3708 case 15: /* KeyUsage id-ce 15 */
3709 appendKeyUsage(properties
, extnValue
);
3711 case 16: /* PrivateKeyUsagePeriod id-ce 16 */
3712 appendPrivateKeyUsagePeriod(properties
, extnValue
);
3714 case 17: /* SubjectAltName id-ce 17 */
3715 case 18: /* IssuerAltName id-ce 18 */
3716 appendGeneralNames(properties
, extnValue
);
3718 case 19: /* BasicConstraints id-ce 19 */
3719 appendBasicConstraints(properties
, extnValue
);
3721 case 30: /* NameConstraints id-ce 30 */
3722 appendNameConstraints(properties
, extnValue
);
3724 case 31: /* CRLDistributionPoints id-ce 31 */
3725 appendCrlDistributionPoints(properties
, extnValue
);
3727 case 32: /* CertificatePolicies id-ce 32 */
3728 appendCertificatePolicies(properties
, extnValue
);
3730 case 33: /* PolicyMappings id-ce 33 */
3733 case 35: /* AuthorityKeyIdentifier id-ce 35 */
3734 appendAuthorityKeyIdentifier(properties
, extnValue
);
3736 case 36: /* PolicyConstraints id-ce 36 */
3737 appendPolicyConstraints(properties
, extnValue
);
3739 case 37: /* ExtKeyUsage id-ce 37 */
3740 appendExtendedKeyUsage(properties
, extnValue
);
3742 case 46: /* FreshestCRL id-ce 46 */
3745 case 54: /* InhibitAnyPolicy id-ce 54 */
3752 } else if (extnID
->length
== oidAuthorityInfoAccess
.length
&&
3753 !memcmp(extnID
->data
, oidAuthorityInfoAccess
.data
, extnID
->length
- 1))
3755 switch (extnID
->data
[extnID
->length
- 1]) {
3756 case 1: /* AuthorityInfoAccess id-pe 1 */
3757 appendInfoAccess(properties
, extnValue
);
3759 case 3: /* QCStatements id-pe 3 */
3762 case 11: /* SubjectInfoAccess id-pe 11 */
3763 appendInfoAccess(properties
, extnValue
);
3769 } else if (DEROidCompare(extnID
, &oidNetscapeCertType
)) {
3770 /* 2.16.840.1.113730.1.1 netscape 1 1 */
3771 appendNetscapeCertType(properties
, extnValue
);
3777 /* Try to parse and display printable string(s). */
3778 if (appendPrintableDERSequence(properties
, SEC_DATA_KEY
, extnValue
)) {
3779 /* Nothing to do here appendPrintableDERSequence did the work. */
3781 /* Couldn't parse extension; dump the raw unparsed data as hex. */
3782 appendUnparsedProperty(properties
, SEC_DATA_KEY
, NULL
, extnValue
);
3786 /* Extensions that we know how to handle ourselves... */
3787 if (DEROidCompare(extnID
, &oidSubjectKeyIdentifier
)) {
3788 appendSubjectKeyIdentifier(properties
, extnValue
);
3789 } else if (DEROidCompare(extnID
, &oidKeyUsage
)) {
3790 appendKeyUsage(properties
, extnValue
);
3791 } else if (DEROidCompare(extnID
, &oidPrivateKeyUsagePeriod
)) {
3792 appendPrivateKeyUsagePeriod(properties
, extnValue
);
3793 } else if (DEROidCompare(extnID
, &oidSubjectAltName
)) {
3794 appendGeneralNames(properties
, extnValue
);
3795 } else if (DEROidCompare(extnID
, &oidIssuerAltName
)) {
3796 appendGeneralNames(properties
, extnValue
);
3797 } else if (DEROidCompare(extnID
, &oidBasicConstraints
)) {
3798 appendBasicConstraints(properties
, extnValue
);
3799 } else if (DEROidCompare(extnID
, &oidNameConstraints
)) {
3800 appendNameConstraints(properties
, extnValue
);
3801 } else if (DEROidCompare(extnID
, &oidCrlDistributionPoints
)) {
3802 appendCrlDistributionPoints(properties
, extnValue
);
3803 } else if (DEROidCompare(extnID
, &oidCertificatePolicies
)) {
3804 appendCertificatePolicies(properties
, extnValue
);
3805 } else if (DEROidCompare(extnID
, &oidAuthorityKeyIdentifier
)) {
3806 appendAuthorityKeyIdentifier(properties
, extnValue
);
3807 } else if (DEROidCompare(extnID
, &oidPolicyConstraints
)) {
3808 appendPolicyConstraints(properties
, extnValue
);
3809 } else if (DEROidCompare(extnID
, &oidExtendedKeyUsage
)) {
3810 appendExtendedKeyUsage(properties
, extnValue
);
3811 } else if (DEROidCompare(extnID
, &oidAuthorityInfoAccess
)) {
3812 appendInfoAccess(properties
, extnValue
);
3813 } else if (DEROidCompare(extnID
, &oidSubjectInfoAccess
)) {
3814 appendInfoAccess(properties
, extnValue
);
3815 } else if (DEROidCompare(extnID
, &oidNetscapeCertType
)) {
3816 appendNetscapeCertType(properties
, extnValue
);
3818 } else if (DEROidCompare(extnID
, &oidEntrustVersInfo
)) {
3819 appendEntrustVersInfo(properties
, extnValue
);
3822 /* Try to parse and display printable string(s). */
3823 if (appendPrintableDERSequence(properties
, SEC_DATA_KEY
, extnValue
)) {
3824 /* Nothing to do here appendPrintableDERSequence did the work. */
3826 /* Couldn't parse extension; dump the raw unparsed data as hex. */
3827 appendUnparsedProperty(properties
, SEC_DATA_KEY
, NULL
, extnValue
);
3830 label
= SecDERItemCopyOIDDecimalRepresentation(allocator
, extnID
);
3831 localizedLabel
= copyLocalizedOidDescription(allocator
, extnID
);
3832 appendProperty(parent
, kSecPropertyTypeSection
, label
, localizedLabel
, properties
);
3835 CFReleaseSafe(localizedLabel
);
3836 CFReleaseSafe(label
);
3837 CFReleaseSafe(properties
);
3840 /* Different types of summary types from least desired to most desired. */
3843 kSummaryTypePrintable
,
3844 kSummaryTypeOrganizationName
,
3845 kSummaryTypeOrganizationalUnitName
,
3846 kSummaryTypeCommonName
,
3850 enum SummaryType type
;
3851 CFStringRef summary
;
3852 CFStringRef description
;
3855 static OSStatus
obtainSummaryFromX501Name(void *context
,
3856 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
3857 struct Summary
*summary
= (struct Summary
*)context
;
3858 enum SummaryType stype
= kSummaryTypeNone
;
3859 CFStringRef string
= NULL
;
3860 if (DEROidCompare(type
, &oidCommonName
)) {
3861 stype
= kSummaryTypeCommonName
;
3862 } else if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
3863 stype
= kSummaryTypeOrganizationalUnitName
;
3864 } else if (DEROidCompare(type
, &oidOrganizationName
)) {
3865 stype
= kSummaryTypeOrganizationName
;
3866 } else if (DEROidCompare(type
, &oidDescription
)) {
3867 string
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
3869 if (summary
->description
) {
3870 CFStringRef fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
3871 CFStringRef newDescription
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, string
, summary
->description
);
3873 CFRelease(summary
->description
);
3874 summary
->description
= newDescription
;
3876 summary
->description
= string
;
3879 stype
= kSummaryTypePrintable
;
3882 stype
= kSummaryTypePrintable
;
3885 /* Build a string with all instances of the most desired
3886 component type in reverse order encountered comma separated list,
3887 The order of desirability is defined by enum SummaryType. */
3888 if (summary
->type
<= stype
) {
3890 string
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
3893 if (summary
->type
== stype
) {
3894 CFStringRef fmt
= SecCopyCertString(SEC_STRING_LIST_KEY
);
3895 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, string
, summary
->summary
);
3898 string
= newSummary
;
3900 summary
->type
= stype
;
3902 CFReleaseSafe(summary
->summary
);
3903 summary
->summary
= string
;
3906 CFReleaseSafe(string
);
3909 return errSecSuccess
;
3912 CFStringRef
SecCertificateCopySubjectSummary(SecCertificateRef certificate
) {
3913 struct Summary summary
= {};
3914 parseX501NameContent(&certificate
->_subject
, &summary
, obtainSummaryFromX501Name
);
3915 /* If we found a description and a common name we change the summary to
3916 CommonName (Description). */
3917 if (summary
.description
) {
3918 if (summary
.type
== kSummaryTypeCommonName
) {
3919 CFStringRef fmt
= SecCopyCertString(SEC_COMMON_NAME_DESC_KEY
);
3920 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, summary
.summary
, summary
.description
);
3922 CFRelease(summary
.summary
);
3923 summary
.summary
= newSummary
;
3925 CFRelease(summary
.description
);
3928 if (!summary
.summary
) {
3929 /* If we didn't find a suitable printable string in the subject at all, we try
3930 the first email address in the certificate instead. */
3931 CFArrayRef names
= SecCertificateCopyRFC822Names(certificate
);
3933 /* If we didn't find any email addresses in the certificate, we try finding
3934 a DNS name instead. */
3935 names
= SecCertificateCopyDNSNames(certificate
);
3938 summary
.summary
= CFArrayGetValueAtIndex(names
, 0);
3939 CFRetain(summary
.summary
);
3944 return summary
.summary
;
3947 CFStringRef
SecCertificateCopyIssuerSummary(SecCertificateRef certificate
) {
3948 struct Summary summary
= {};
3949 parseX501NameContent(&certificate
->_issuer
, &summary
, obtainSummaryFromX501Name
);
3950 /* If we found a description and a common name we change the summary to
3951 CommonName (Description). */
3952 if (summary
.description
) {
3953 if (summary
.type
== kSummaryTypeCommonName
) {
3954 CFStringRef fmt
= SecCopyCertString(SEC_COMMON_NAME_DESC_KEY
);
3955 CFStringRef newSummary
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, fmt
, summary
.summary
, summary
.description
);
3957 CFRelease(summary
.summary
);
3958 summary
.summary
= newSummary
;
3960 CFRelease(summary
.description
);
3963 return summary
.summary
;
3966 /* Return the earliest date on which all certificates in this chain are still
3968 static CFAbsoluteTime
SecCertificateGetChainsLastValidity(
3969 SecCertificateRef certificate
) {
3970 CFAbsoluteTime earliest
= certificate
->_notAfter
;
3972 while (certificate
->_parent
) {
3973 certificate
= certificate
->_parent
;
3974 if (earliest
> certificate
->_notAfter
)
3975 earliest
= certificate
->_notAfter
;
3982 /* Return the latest date on which all certificates in this chain will be
3984 static CFAbsoluteTime
SecCertificateGetChainsFirstValidity(
3985 SecCertificateRef certificate
) {
3986 CFAbsoluteTime latest
= certificate
->_notBefore
;
3988 while (certificate
->_parent
) {
3989 certificate
= certificate
->_parent
;
3990 if (latest
< certificate
->_notBefore
)
3991 latest
= certificate
->_notBefore
;
3998 bool SecCertificateIsValid(SecCertificateRef certificate
,
3999 CFAbsoluteTime verifyTime
) {
4000 return certificate
&& certificate
->_notBefore
<= verifyTime
&&
4001 verifyTime
<= certificate
->_notAfter
;
4004 CFIndex
SecCertificateVersion(SecCertificateRef certificate
) {
4005 return certificate
->_version
+ 1;
4008 CFAbsoluteTime
SecCertificateNotValidBefore(SecCertificateRef certificate
) {
4009 return certificate
->_notBefore
;
4012 CFAbsoluteTime
SecCertificateNotValidAfter(SecCertificateRef certificate
) {
4013 return certificate
->_notAfter
;
4016 CFMutableArrayRef
SecCertificateCopySummaryProperties(
4017 SecCertificateRef certificate
, CFAbsoluteTime verifyTime
) {
4018 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
4019 CFMutableArrayRef summary
= CFArrayCreateMutable(allocator
, 0,
4020 &kCFTypeArrayCallBacks
);
4022 /* First we put the subject summary name. */
4023 CFStringRef ssummary
= SecCertificateCopySubjectSummary(certificate
);
4025 appendProperty(summary
, kSecPropertyTypeTitle
,
4026 NULL
, NULL
, ssummary
);
4027 CFRelease(ssummary
);
4030 CFStringRef isummary
= SEC_ISSUER_SUMMARY_KEY
;
4031 appendProperty(summary
, kSecPropertyTypeString
,
4032 SEC_ISSUED_BY_KEY
, isummary
);
4033 CFRelease(isummary
);
4036 /* Let see if this certificate is currently valid. */
4038 CFAbsoluteTime when
;
4039 CFStringRef message
;
4041 if (verifyTime
> certificate
->_notAfter
) {
4042 label
= SEC_EXPIRED_KEY
;
4043 when
= certificate
->_notAfter
;
4044 ptype
= kSecPropertyTypeError
;
4045 message
= SEC_CERT_EXPIRED_KEY
;
4046 } else if (certificate
->_notBefore
> verifyTime
) {
4047 label
= SEC_VALID_FROM_KEY
;
4048 when
= certificate
->_notBefore
;
4049 ptype
= kSecPropertyTypeError
;
4050 message
= SEC_CERT_NOT_YET_VALID_KEY
;
4052 CFAbsoluteTime last
= SecCertificateGetChainsLastValidity(certificate
);
4053 CFAbsoluteTime first
= SecCertificateGetChainsFirstValidity(certificate
);
4054 if (verifyTime
> last
) {
4055 label
= SEC_EXPIRED_KEY
;
4057 ptype
= kSecPropertyTypeError
;
4058 message
= SEC_ISSUER_EXPIRED_KEY
;
4059 } else if (verifyTime
< first
) {
4060 label
= SEC_VALID_FROM_KEY
;
4062 ptype
= kSecPropertyTypeError
;
4063 message
= SEC_ISSR_NOT_YET_VALID_KEY
;
4065 label
= SEC_EXPIRES_KEY
;
4066 when
= certificate
->_notAfter
;
4067 ptype
= kSecPropertyTypeSuccess
;
4068 message
= SEC_CERT_VALID_KEY
;
4072 appendDateProperty(summary
, label
, when
);
4073 CFStringRef lmessage
= SecCopyCertString(message
);
4074 appendProperty(summary
, ptype
, NULL
, NULL
, lmessage
);
4075 CFRelease(lmessage
);
4080 CFArrayRef
SecCertificateCopyProperties(SecCertificateRef certificate
) {
4081 if (!certificate
->_properties
) {
4082 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
4083 CFMutableArrayRef properties
= CFArrayCreateMutable(allocator
, 0,
4084 &kCFTypeArrayCallBacks
);
4086 /* First we put the Subject Name in the property list. */
4087 CFArrayRef subject_plist
= createPropertiesForX501NameContent(allocator
,
4088 &certificate
->_subject
);
4089 appendProperty(properties
, kSecPropertyTypeSection
,
4090 SEC_SUBJECT_NAME_KEY
, NULL
, subject_plist
);
4091 CFRelease(subject_plist
);
4094 /* Put Normalized subject in for testing. */
4095 if (certificate
->_normalizedSubject
) {
4096 DERItem nsubject
= {
4097 (DERByte
*)CFDataGetBytePtr(certificate
->_normalizedSubject
),
4098 CFDataGetLength(certificate
->_normalizedSubject
)
4100 CFArrayRef nsubject_plist
= createPropertiesForX501NameContent(allocator
,
4102 appendProperty(properties
, kSecPropertyTypeSection
,
4103 CFSTR("Normalized Subject Name"), nsubject_plist
);
4104 CFRelease(nsubject_plist
);
4108 /* Next we put the Issuer Name in the property list. */
4109 CFArrayRef issuer_plist
= createPropertiesForX501NameContent(allocator
,
4110 &certificate
->_issuer
);
4111 appendProperty(properties
, kSecPropertyTypeSection
,
4112 SEC_ISSUER_NAME_KEY
, NULL
, issuer_plist
);
4113 CFRelease(issuer_plist
);
4116 /* Certificate version/type. */
4117 bool isRoot
= false;
4118 CFStringRef fmt
= SecCopyCertString(SEC_X509_VERSION_KEY
);
4119 CFStringRef typeString
= CFStringCreateWithFormat(allocator
, NULL
,
4120 fmt
, certificate
->_version
+ 1, isRoot
? "root " : "");
4122 appendProperty(properties
, kSecPropertyTypeString
,
4123 SEC_CERTIFICATE_TYPE_KEY
, typeString
);
4124 CFRelease(typeString
);
4128 CFStringRef fmt
= SecCopyCertString(SEC_CERT_VERSION_VALUE_KEY
);
4129 CFStringRef versionString
= CFStringCreateWithFormat(allocator
,
4130 NULL
, fmt
, certificate
->_version
+ 1);
4132 appendProperty(properties
, kSecPropertyTypeString
,
4133 SEC_VERSION_KEY
, NULL
, versionString
);
4134 CFRelease(versionString
);
4137 if (certificate
->_serialNum
.length
) {
4138 appendIntegerProperty(properties
, SEC_SERIAL_NUMBER_KEY
,
4139 &certificate
->_serialNum
);
4142 /* Signature algorithm. */
4144 appendAlgorithmProperty(properties
, SEC_SIGNATURE_ALGORITHM_KEY
,
4145 &certificate
->_sigAlg
);
4147 appendAlgorithmProperty(properties
, SEC_SIGNATURE_ALGORITHM_KEY
,
4148 &certificate
->_tbsSigAlg
);
4151 /* Validity dates. */
4152 appendDateProperty(properties
, SEC_NOT_VALID_BEFORE_KEY
,
4153 certificate
->_notBefore
);
4154 appendDateProperty(properties
, SEC_NOT_VALID_AFTER_KEY
,
4155 certificate
->_notAfter
);
4157 if (certificate
->_subjectUniqueID
.length
) {
4158 appendDataProperty(properties
, SEC_SUBJECT_UNIQUE_ID_KEY
, NULL
,
4159 &certificate
->_subjectUniqueID
);
4161 if (certificate
->_issuerUniqueID
.length
) {
4162 appendDataProperty(properties
, SEC_ISSUER_UNIQUE_ID_KEY
, NULL
,
4163 &certificate
->_issuerUniqueID
);
4166 /* Public key algorithm. */
4167 appendAlgorithmProperty(properties
, SEC_PUBLIC_KEY_ALG_KEY
,
4168 &certificate
->_algId
);
4170 /* Consider breaking down an RSA public key into modulus and
4172 appendDataProperty(properties
, SEC_PULIC_KEY_DATA_KEY
, NULL
,
4173 &certificate
->_pubKeyDER
);
4174 /* TODO: Add Key Size. */
4175 /* TODO: Add Key Usage. */
4177 appendDataProperty(properties
, SEC_SIGNATURE_KEY
, NULL
,
4178 &certificate
->_signature
);
4181 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
4182 appendExtension(properties
, &certificate
->_extensions
[ix
]);
4185 /* TODO: Certificate/Key Fingerprints. */
4187 certificate
->_properties
= properties
;
4190 CFRetain(certificate
->_properties
);
4191 return certificate
->_properties
;
4194 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
4195 /* On OS X, the SecCertificateCopySerialNumber API takes two arguments. */
4196 CFDataRef
SecCertificateCopySerialNumber(
4197 SecCertificateRef certificate
,
4198 CFErrorRef
*error
) {
4201 *error
= CFErrorCreate(NULL
, kCFErrorDomainOSStatus
, errSecInvalidCertificate
, NULL
);
4205 if (certificate
->_serialNumber
) {
4206 CFRetain(certificate
->_serialNumber
);
4208 return certificate
->_serialNumber
;
4211 /* On iOS, the SecCertificateCopySerialNumber API takes one argument. */
4212 CFDataRef
SecCertificateCopySerialNumber(
4213 SecCertificateRef certificate
) {
4214 if (certificate
->_serialNumber
) {
4215 CFRetain(certificate
->_serialNumber
);
4217 return certificate
->_serialNumber
;
4221 CFDataRef
SecCertificateGetNormalizedIssuerContent(
4222 SecCertificateRef certificate
) {
4223 return certificate
->_normalizedIssuer
;
4226 CFDataRef
SecCertificateGetNormalizedSubjectContent(
4227 SecCertificateRef certificate
) {
4228 return certificate
->_normalizedSubject
;
4231 /* Verify that certificate was signed by issuerKey. */
4232 OSStatus
SecCertificateIsSignedBy(SecCertificateRef certificate
,
4233 SecKeyRef issuerKey
) {
4234 /* Setup algId in SecAsn1AlgId format. */
4236 algId
.algorithm
.Length
= certificate
->_tbsSigAlg
.oid
.length
;
4237 algId
.algorithm
.Data
= certificate
->_tbsSigAlg
.oid
.data
;
4238 algId
.parameters
.Length
= certificate
->_tbsSigAlg
.params
.length
;
4239 algId
.parameters
.Data
= certificate
->_tbsSigAlg
.params
.data
;
4241 CFErrorRef error
= NULL
;
4242 if (!SecVerifySignatureWithPublicKey(issuerKey
, &algId
,
4243 certificate
->_tbs
.data
, certificate
->_tbs
.length
,
4244 certificate
->_signature
.data
, certificate
->_signature
.length
, &error
))
4246 #if !defined(NDEBUG)
4247 secdebug("verify", "signature verify failed: %" PRIdOSStatus
, (error
) ? (OSStatus
)CFErrorGetCode(error
) : errSecNotSigner
);
4249 CFReleaseSafe(error
);
4250 return errSecNotSigner
;
4253 return errSecSuccess
;
4257 static OSStatus
SecCertificateIsIssuedBy(SecCertificateRef certificate
,
4258 SecCertificateRef issuer
, bool signatureCheckOnly
) {
4259 if (!signatureCheckOnly
) {
4260 /* It turns out we don't actually need to use normalized subject and
4261 issuer according to rfc2459. */
4263 /* If present we should check issuerID against the issuer subjectID. */
4265 /* If we have an AuthorityKeyIdentifier extension that has a keyIdentifier
4266 then we should look for a SubjectKeyIdentifier in the issuer
4268 If we have a authorityCertSerialNumber we can use that for chaining.
4269 If we have a authorityCertIssuer we can use that? (or not) */
4271 /* Verify that this cert was issued by issuer. Do so by chaining
4272 either issuerID to subjectID or normalized issuer to normalized
4274 CFDataRef normalizedIssuer
=
4275 SecCertificateGetNormalizedIssuerContent(certificate
);
4276 CFDataRef normalizedIssuerSubject
=
4277 SecCertificateGetNormalizedSubjectContent(issuer
);
4278 if (normalizedIssuer
&& normalizedIssuerSubject
&&
4279 !CFEqual(normalizedIssuer
, normalizedIssuerSubject
))
4280 return errSecIssuerMismatch
;
4283 /* Next verify that this cert was signed by issuer. */
4284 SecKeyRef issuerKey
= SecCertificateGetPublicKey(issuer
);
4286 /* Get the encodedDigestInfo from the digest of the subject's TBSCert */
4287 /* FIXME: We sould cache this (or at least the digest) until we find
4288 a suitable issuer. */
4289 uint8_t signedData
[DER_SHA1_DIGEST_INFO_LEN
];
4290 CFIndex signedDataLength
;
4291 CertVerifyReturn crtn
;
4292 if (DEROidCompare(&certificate
->_tbsSigAlg
.oid
, &oidSha1Rsa
)) {
4293 signedDataLength
= DER_SHA1_DIGEST_INFO_LEN
;
4294 crtn
= sha1DigestInfo(&certificate
->_tbs
, signedData
);
4295 } else if(DEROidCompare(&certificate
->_tbsSigAlg
.oid
, &oidMd5Rsa
)) {
4296 signedDataLength
= DER_MD_DIGEST_INFO_LEN
;
4297 crtn
= mdDigestInfo(WD_MD5
, &certificate
->_tbs
, signedData
);
4298 } else if(DEROidCompare(&certificate
->_tbsSigAlg
.oid
, &oidMd2Rsa
)) {
4299 signedDataLength
= DER_MD_DIGEST_INFO_LEN
;
4300 crtn
= mdDigestInfo(WD_MD2
, &certificate
->_tbs
, signedData
);
4302 secdebug("verify", "unsupported algorithm");
4303 return errSecUnsupportedAlgorithm
;
4306 secdebug("verify", "*DigestInfo returned: %d", crtn
);
4307 /* FIXME: Do proper error code translation. */
4308 return errSecUnsupportedAlgorithm
;
4311 OSStatus status
= SecKeyRawVerify(issuerKey
, kSecPaddingPKCS1
,
4312 signedData
, signedDataLength
,
4313 certificate
->_signature
.data
, certificate
->_signature
.length
);
4315 secdebug("verify", "signature verify failed: %d", status
);
4316 return errSecNotSigner
;
4319 return errSecSuccess
;
4322 static OSStatus
_SecCertificateSetParent(SecCertificateRef certificate
,
4323 SecCertificateRef issuer
, bool signatureCheckOnly
) {
4325 if (certificate
->_parent
) {
4326 /* Setting a certificates issuer twice is only allowed if the new
4327 issuer is equal to the current one. */
4328 return issuer
&& CFEqual(certificate
->_parent
, issuer
);
4332 OSStatus status
= SecCertificateIsIssuedBy(certificate
, issuer
,
4333 signatureCheckOnly
);
4335 OSStatus status
= errSecSuccess
;
4338 if (CFEqual(certificate
, issuer
)) {
4339 /* We don't retain ourselves cause that would be bad mojo,
4340 however we do record that we are properly self signed. */
4341 certificate
->_isSelfSigned
= kSecSelfSignedTrue
;
4342 secdebug("cert", "set self as parent");
4343 return errSecSuccess
;
4347 certificate
->_parent
= issuer
;
4348 certificate
->_isSelfSigned
= kSecSelfSignedFalse
;
4354 /* Return true iff we were able to set our own parent from one of the
4355 certificates in other_certificates, return false otherwise. If
4356 signatureCheckOnly is true, we can skip the subject == issuer or
4357 authorityKeyIdentifier tests. */
4358 static bool SecCertificateSetParentFrom(SecCertificateRef certificate
,
4359 CFArrayRef other_certificates
, bool signatureCheckOnly
) {
4360 CFIndex count
= CFArrayGetCount(other_certificates
);
4362 for (ix
= 0; ix
< count
; ++ix
) {
4363 SecCertificateRef candidate
= (SecCertificateRef
)
4364 CFArrayGetValueAtIndex(other_certificates
, ix
);
4365 if (_SecCertificateSetParent(certificate
, candidate
,
4366 signatureCheckOnly
))
4372 /* Lookup the parent of certificate in the keychain and set it. */
4373 static bool SecCertificateFindParent(SecCertificateRef certificate
) {
4374 /* FIXME: Search for things other than just subject of our issuer if we
4375 have a subjectID or authorityKeyIdentifier. */
4376 CFDataRef normalizedIssuer
=
4377 SecCertificateGetNormalizedIssuerContent(certificate
);
4378 const void *keys
[] = {
4385 kSecClassCertificate
,
4390 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
, 4,
4391 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
4393 OSStatus status
= SecItemCopyMatching(query
, &results
);
4396 secdebug("cert", "SecCertificateFindParent: SecItemCopyMatching: %d",
4400 CFArrayRef certs
= (CFArrayRef
)results
;
4401 /* Since we already know the certificates we are providing as candidates
4402 have been checked for subject matching, we can ask
4403 SecCertificateSetParentFrom to skip everything except the signature
4405 bool result
= SecCertificateSetParentFrom(certificate
, certs
, true);
4410 OSStatus
SecCertificateCompleteChain(SecCertificateRef certificate
,
4411 CFArrayRef other_certificates
) {
4413 if (certificate
->_parent
== NULL
) {
4414 Boolean isSelfSigned
= false;
4415 OSStatus status
= SecCertificateIsSelfSigned(certificate
, &isSelfSigned
);
4416 if (!status
&& isSelfSigned
)
4417 return errSecSuccess
;
4418 if (!other_certificates
||
4419 !SecCertificateSetParentFrom(certificate
, other_certificates
,
4421 if (!SecCertificateFindParent(certificate
))
4422 return errSecIssuerNotFound
;
4425 certificate
= certificate
->_parent
;
4430 const DERItem
* SecCertificateGetSubjectAltName(SecCertificateRef certificate
) {
4431 if (!certificate
->_subjectAltName
) {
4434 return &certificate
->_subjectAltName
->extnValue
;
4437 static OSStatus
appendIPAddressesFromGeneralNames(void *context
,
4438 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4439 CFMutableArrayRef ipAddresses
= (CFMutableArrayRef
)context
;
4440 if (gnType
== GNT_IPAddress
) {
4441 CFStringRef string
= copyIPAddressContentDescription(
4442 kCFAllocatorDefault
, generalName
);
4444 CFArrayAppendValue(ipAddresses
, string
);
4447 return errSecInvalidCertificate
;
4450 return errSecSuccess
;
4453 CFArrayRef
SecCertificateCopyIPAddresses(SecCertificateRef certificate
) {
4454 /* These can only exist in the subject alt name. */
4455 if (!certificate
->_subjectAltName
)
4458 CFMutableArrayRef ipAddresses
= CFArrayCreateMutable(kCFAllocatorDefault
,
4459 0, &kCFTypeArrayCallBacks
);
4460 OSStatus status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4461 ipAddresses
, appendIPAddressesFromGeneralNames
);
4462 if (status
|| CFArrayGetCount(ipAddresses
) == 0) {
4463 CFRelease(ipAddresses
);
4469 static OSStatus
appendDNSNamesFromGeneralNames(void *context
, SecCEGeneralNameType gnType
,
4470 const DERItem
*generalName
) {
4471 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4472 if (gnType
== GNT_DNSName
) {
4473 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorDefault
,
4474 generalName
->data
, generalName
->length
,
4475 kCFStringEncodingUTF8
, FALSE
);
4477 CFArrayAppendValue(dnsNames
, string
);
4480 return errSecInvalidCertificate
;
4483 return errSecSuccess
;
4486 /* Return true if the passed in string matches the
4487 Preferred name syntax from sections 2.3.1. in RFC 1035.
4488 With the added check that we disallow empty dns names.
4489 Also in order to support wildcard DNSNames we allow for the '*'
4490 character anywhere in a dns component where we currently allow
4493 <domain> ::= <subdomain> | " "
4495 <subdomain> ::= <label> | <subdomain> "." <label>
4497 <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
4499 <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
4501 <let-dig-hyp> ::= <let-dig> | "-"
4503 <let-dig> ::= <letter> | <digit>
4505 <letter> ::= any one of the 52 alphabetic characters A through Z in
4506 upper case and a through z in lower case
4508 <digit> ::= any one of the ten digits 0 through 9
4510 static bool isDNSName(CFStringRef string
) {
4511 CFStringInlineBuffer buf
= {};
4512 CFIndex ix
, labelLength
= 0, length
= CFStringGetLength(string
);
4513 /* From RFC 1035 2.3.4. Size limits:
4514 labels 63 octets or less
4515 names 255 octets or less */
4516 require_quiet(length
<= 255, notDNS
);
4517 CFRange range
= { 0, length
};
4518 CFStringInitInlineBuffer(string
, &buf
, range
);
4522 kDNSStateAfterAlpha
,
4523 kDNSStateAfterDigit
,
4525 } state
= kDNSStateInital
;
4527 for (ix
= 0; ix
< length
; ++ix
) {
4528 UniChar ch
= CFStringGetCharacterFromInlineBuffer(&buf
, ix
);
4531 require_quiet(labelLength
<= 64 &&
4532 (state
== kDNSStateAfterAlpha
|| state
== kDNSStateAfterDigit
),
4534 state
= kDNSStateAfterDot
;
4536 } else if (('A' <= ch
&& ch
<= 'Z') || ('a' <= ch
&& ch
<= 'z') ||
4538 state
= kDNSStateAfterAlpha
;
4539 } else if ('0' <= ch
&& ch
<= '9') {
4541 /* The requirement for labels to start with a letter was
4542 dropped so we don't check this anymore. */
4543 require_quiet(state
== kDNSStateAfterAlpha
||
4544 state
== kDNSStateAfterDigit
||
4545 state
== kDNSStateAfterDash
, notDNS
);
4547 state
= kDNSStateAfterDigit
;
4548 } else if (ch
== '-') {
4549 require_quiet(state
== kDNSStateAfterAlpha
||
4550 state
== kDNSStateAfterDigit
||
4551 state
== kDNSStateAfterDash
, notDNS
);
4552 state
= kDNSStateAfterDash
;
4558 /* We don't allow a dns name to end in a dot or dash. */
4559 require_quiet(labelLength
<= 63 &&
4560 (state
== kDNSStateAfterAlpha
|| state
== kDNSStateAfterDigit
),
4568 static OSStatus
appendDNSNamesFromX501Name(void *context
, const DERItem
*type
,
4569 const DERItem
*value
, CFIndex rdnIX
) {
4570 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4571 if (DEROidCompare(type
, &oidCommonName
)) {
4572 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4575 if (isDNSName(string
)) {
4576 /* We found a common name that is formatted like a valid
4578 CFArrayAppendValue(dnsNames
, string
);
4582 return errSecInvalidCertificate
;
4585 return errSecSuccess
;
4588 /* Not everything returned by this function is going to be a proper DNS name,
4589 we also return the certificates common name entries from the subject,
4590 assuming they look like dns names as specified in RFC 1035. */
4591 CFArrayRef
SecCertificateCopyDNSNames(SecCertificateRef certificate
) {
4592 /* These can exist in the subject alt name or in the subject. */
4593 CFMutableArrayRef dnsNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4594 0, &kCFTypeArrayCallBacks
);
4595 OSStatus status
= errSecSuccess
;
4596 if (certificate
->_subjectAltName
) {
4597 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4598 dnsNames
, appendDNSNamesFromGeneralNames
);
4600 /* RFC 2818 section 3.1. Server Identity
4602 If a subjectAltName extension of type dNSName is present, that MUST
4603 be used as the identity. Otherwise, the (most specific) Common Name
4604 field in the Subject field of the certificate MUST be used. Although
4605 the use of the Common Name is existing practice, it is deprecated and
4606 Certification Authorities are encouraged to use the dNSName instead.
4609 This implies that if we found 1 or more DNSNames in the
4610 subjectAltName, we should not use the Common Name of the subject as
4613 if (!status
&& CFArrayGetCount(dnsNames
) == 0) {
4614 status
= parseX501NameContent(&certificate
->_subject
, dnsNames
,
4615 appendDNSNamesFromX501Name
);
4617 if (status
|| CFArrayGetCount(dnsNames
) == 0) {
4618 CFRelease(dnsNames
);
4624 static OSStatus
appendRFC822NamesFromGeneralNames(void *context
,
4625 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4626 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4627 if (gnType
== GNT_RFC822Name
) {
4628 CFStringRef string
= CFStringCreateWithBytes(kCFAllocatorDefault
,
4629 generalName
->data
, generalName
->length
,
4630 kCFStringEncodingASCII
, FALSE
);
4632 CFArrayAppendValue(dnsNames
, string
);
4635 return errSecInvalidCertificate
;
4638 return errSecSuccess
;
4641 static OSStatus
appendRFC822NamesFromX501Name(void *context
, const DERItem
*type
,
4642 const DERItem
*value
, CFIndex rdnIX
) {
4643 CFMutableArrayRef dnsNames
= (CFMutableArrayRef
)context
;
4644 if (DEROidCompare(type
, &oidEmailAddress
)) {
4645 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4648 CFArrayAppendValue(dnsNames
, string
);
4651 return errSecInvalidCertificate
;
4654 return errSecSuccess
;
4657 CFArrayRef
SecCertificateCopyRFC822Names(SecCertificateRef certificate
) {
4658 /* These can exist in the subject alt name or in the subject. */
4659 CFMutableArrayRef rfc822Names
= CFArrayCreateMutable(kCFAllocatorDefault
,
4660 0, &kCFTypeArrayCallBacks
);
4661 OSStatus status
= errSecSuccess
;
4662 if (certificate
->_subjectAltName
) {
4663 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4664 rfc822Names
, appendRFC822NamesFromGeneralNames
);
4667 status
= parseX501NameContent(&certificate
->_subject
, rfc822Names
,
4668 appendRFC822NamesFromX501Name
);
4670 if (status
|| CFArrayGetCount(rfc822Names
) == 0) {
4671 CFRelease(rfc822Names
);
4677 static OSStatus
appendCommonNamesFromX501Name(void *context
,
4678 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4679 CFMutableArrayRef commonNames
= (CFMutableArrayRef
)context
;
4680 if (DEROidCompare(type
, &oidCommonName
)) {
4681 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4684 CFArrayAppendValue(commonNames
, string
);
4687 return errSecInvalidCertificate
;
4690 return errSecSuccess
;
4693 CFArrayRef
SecCertificateCopyCommonNames(SecCertificateRef certificate
) {
4694 CFMutableArrayRef commonNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4695 0, &kCFTypeArrayCallBacks
);
4697 status
= parseX501NameContent(&certificate
->_subject
, commonNames
,
4698 appendCommonNamesFromX501Name
);
4699 if (status
|| CFArrayGetCount(commonNames
) == 0) {
4700 CFRelease(commonNames
);
4706 static OSStatus
appendOrganizationFromX501Name(void *context
,
4707 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4708 CFMutableArrayRef organization
= (CFMutableArrayRef
)context
;
4709 if (DEROidCompare(type
, &oidOrganizationName
)) {
4710 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4713 CFArrayAppendValue(organization
, string
);
4716 return errSecInvalidCertificate
;
4719 return errSecSuccess
;
4722 CFArrayRef
SecCertificateCopyOrganization(SecCertificateRef certificate
) {
4723 CFMutableArrayRef organization
= CFArrayCreateMutable(kCFAllocatorDefault
,
4724 0, &kCFTypeArrayCallBacks
);
4726 status
= parseX501NameContent(&certificate
->_subject
, organization
,
4727 appendOrganizationFromX501Name
);
4728 if (status
|| CFArrayGetCount(organization
) == 0) {
4729 CFRelease(organization
);
4730 organization
= NULL
;
4732 return organization
;
4735 static OSStatus
appendOrganizationalUnitFromX501Name(void *context
,
4736 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4737 CFMutableArrayRef organizationalUnit
= (CFMutableArrayRef
)context
;
4738 if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
4739 CFStringRef string
= copyDERThingDescription(kCFAllocatorDefault
,
4742 CFArrayAppendValue(organizationalUnit
, string
);
4745 return errSecInvalidCertificate
;
4748 return errSecSuccess
;
4751 CFArrayRef
SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate
) {
4752 CFMutableArrayRef organizationalUnit
= CFArrayCreateMutable(kCFAllocatorDefault
,
4753 0, &kCFTypeArrayCallBacks
);
4755 status
= parseX501NameContent(&certificate
->_subject
, organizationalUnit
,
4756 appendOrganizationalUnitFromX501Name
);
4757 if (status
|| CFArrayGetCount(organizationalUnit
) == 0) {
4758 CFRelease(organizationalUnit
);
4759 organizationalUnit
= NULL
;
4761 return organizationalUnit
;
4764 const SecCEBasicConstraints
*
4765 SecCertificateGetBasicConstraints(SecCertificateRef certificate
) {
4766 if (certificate
->_basicConstraints
.present
)
4767 return &certificate
->_basicConstraints
;
4772 CFArrayRef
SecCertificateGetPermittedSubtrees(SecCertificateRef certificate
) {
4773 return (certificate
->_permittedSubtrees
);
4776 CFArrayRef
SecCertificateGetExcludedSubtrees(SecCertificateRef certificate
) {
4777 return (certificate
->_excludedSubtrees
);
4780 const SecCEPolicyConstraints
*
4781 SecCertificateGetPolicyConstraints(SecCertificateRef certificate
) {
4782 if (certificate
->_policyConstraints
.present
)
4783 return &certificate
->_policyConstraints
;
4789 SecCertificateGetPolicyMappings(SecCertificateRef certificate
) {
4790 return certificate
->_policyMappings
;
4793 const SecCECertificatePolicies
*
4794 SecCertificateGetCertificatePolicies(SecCertificateRef certificate
) {
4795 if (certificate
->_certificatePolicies
.present
)
4796 return &certificate
->_certificatePolicies
;
4802 SecCertificateGetInhibitAnyPolicySkipCerts(SecCertificateRef certificate
) {
4803 return certificate
->_inhibitAnyPolicySkipCerts
;
4806 static OSStatus
appendNTPrincipalNamesFromGeneralNames(void *context
,
4807 SecCEGeneralNameType gnType
, const DERItem
*generalName
) {
4808 CFMutableArrayRef ntPrincipalNames
= (CFMutableArrayRef
)context
;
4809 if (gnType
== GNT_OtherName
) {
4811 DERReturn drtn
= DERParseSequenceContent(generalName
,
4812 DERNumOtherNameItemSpecs
, DEROtherNameItemSpecs
,
4814 require_noerr_quiet(drtn
, badDER
);
4815 if (DEROidCompare(&on
.typeIdentifier
, &oidMSNTPrincipalName
)) {
4817 require_quiet(string
= copyDERThingDescription(kCFAllocatorDefault
,
4818 &on
.value
, true), badDER
);
4819 CFArrayAppendValue(ntPrincipalNames
, string
);
4823 return errSecSuccess
;
4826 return errSecInvalidCertificate
;
4830 CFArrayRef
SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate
) {
4831 CFMutableArrayRef ntPrincipalNames
= CFArrayCreateMutable(kCFAllocatorDefault
,
4832 0, &kCFTypeArrayCallBacks
);
4833 OSStatus status
= errSecSuccess
;
4834 if (certificate
->_subjectAltName
) {
4835 status
= SecCertificateParseGeneralNames(&certificate
->_subjectAltName
->extnValue
,
4836 ntPrincipalNames
, appendNTPrincipalNamesFromGeneralNames
);
4838 if (status
|| CFArrayGetCount(ntPrincipalNames
) == 0) {
4839 CFRelease(ntPrincipalNames
);
4840 ntPrincipalNames
= NULL
;
4842 return ntPrincipalNames
;
4845 static OSStatus
appendToRFC2253String(void *context
,
4846 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4847 CFMutableStringRef string
= (CFMutableStringRef
)context
;
4851 ST stateOrProvinceName
4853 OU organizationalUnitName
4855 STREET streetAddress
4859 /* Prepend a + if this is not the first RDN in an RDN set.
4860 Otherwise prepend a , if this is not the first RDN. */
4862 CFStringAppend(string
, CFSTR("+"));
4863 else if (CFStringGetLength(string
)) {
4864 CFStringAppend(string
, CFSTR(","));
4867 CFStringRef label
, oid
= NULL
;
4868 /* @@@ Consider changing this to a dictionary lookup keyed by the
4869 decimal representation. */
4870 if (DEROidCompare(type
, &oidCommonName
)) {
4871 label
= CFSTR("CN");
4872 } else if (DEROidCompare(type
, &oidLocalityName
)) {
4874 } else if (DEROidCompare(type
, &oidStateOrProvinceName
)) {
4875 label
= CFSTR("ST");
4876 } else if (DEROidCompare(type
, &oidOrganizationName
)) {
4878 } else if (DEROidCompare(type
, &oidOrganizationalUnitName
)) {
4879 label
= CFSTR("OU");
4880 } else if (DEROidCompare(type
, &oidCountryName
)) {
4883 } else if (DEROidCompare(type
, &oidStreetAddress
)) {
4884 label
= CFSTR("STREET");
4885 } else if (DEROidCompare(type
, &oidDomainComponent
)) {
4886 label
= CFSTR("DC");
4887 } else if (DEROidCompare(type
, &oidUserID
)) {
4888 label
= CFSTR("UID");
4891 label
= oid
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, type
);
4894 CFStringAppend(string
, label
);
4895 CFStringAppend(string
, CFSTR("="));
4896 CFStringRef raw
= NULL
;
4898 raw
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
4901 /* Append raw to string while escaping:
4902 a space or "#" character occurring at the beginning of the string
4903 a space character occurring at the end of the string
4904 one of the characters ",", "+", """, "\", "<", ">" or ";"
4906 CFStringInlineBuffer buffer
= {};
4907 CFIndex ix
, length
= CFStringGetLength(raw
);
4908 CFRange range
= { 0, length
};
4909 CFStringInitInlineBuffer(raw
, &buffer
, range
);
4910 for (ix
= 0; ix
< length
; ++ix
) {
4911 UniChar ch
= CFStringGetCharacterFromInlineBuffer(&buffer
, ix
);
4913 CFStringAppendFormat(string
, NULL
, CFSTR("\\%02X"), ch
);
4914 } else if (ch
== ',' || ch
== '+' || ch
== '"' || ch
== '\\' ||
4915 ch
== '<' || ch
== '>' || ch
== ';' ||
4916 (ch
== ' ' && (ix
== 0 || ix
== length
- 1)) ||
4917 (ch
== '#' && ix
== 0)) {
4918 UniChar chars
[] = { '\\', ch
};
4919 CFStringAppendCharacters(string
, chars
, 2);
4921 CFStringAppendCharacters(string
, &ch
, 1);
4926 /* Append the value in hex. */
4927 CFStringAppend(string
, CFSTR("#"));
4929 for (ix
= 0; ix
< value
->length
; ++ix
)
4930 CFStringAppendFormat(string
, NULL
, CFSTR("%02X"), value
->data
[ix
]);
4935 return errSecSuccess
;
4938 CFStringRef
SecCertificateCopySubjectString(SecCertificateRef certificate
) {
4939 CFMutableStringRef string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
4940 OSStatus status
= parseX501NameContent(&certificate
->_subject
, string
, appendToRFC2253String
);
4941 if (status
|| CFStringGetLength(string
) == 0) {
4948 static OSStatus
appendToCompanyNameString(void *context
,
4949 const DERItem
*type
, const DERItem
*value
, CFIndex rdnIX
) {
4950 CFMutableStringRef string
= (CFMutableStringRef
)context
;
4951 if (CFStringGetLength(string
) != 0)
4952 return errSecSuccess
;
4954 if (!DEROidCompare(type
, &oidOrganizationName
))
4955 return errSecSuccess
;
4958 raw
= copyDERThingDescription(kCFAllocatorDefault
, value
, true);
4960 return errSecSuccess
;
4961 CFStringAppend(string
, raw
);
4964 return errSecSuccess
;
4967 CFStringRef
SecCertificateCopyCompanyName(SecCertificateRef certificate
) {
4968 CFMutableStringRef string
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
4969 OSStatus status
= parseX501NameContent(&certificate
->_subject
, string
,
4970 appendToCompanyNameString
);
4971 if (status
|| CFStringGetLength(string
) == 0) {
4978 static CFDataRef
SecDERItemCopySequence(DERItem
*content
) {
4979 DERSize seq_len_length
= DERLengthOfLength(content
->length
);
4980 size_t sequence_length
= 1 + seq_len_length
+ content
->length
;
4981 CFMutableDataRef sequence
= CFDataCreateMutable(kCFAllocatorDefault
,
4983 CFDataSetLength(sequence
, sequence_length
);
4984 uint8_t *sequence_ptr
= CFDataGetMutableBytePtr(sequence
);
4985 *sequence_ptr
++ = ONE_BYTE_ASN1_CONSTR_SEQUENCE
;
4986 require_noerr_quiet(DEREncodeLength(content
->length
,
4987 sequence_ptr
, &seq_len_length
), out
);
4988 sequence_ptr
+= seq_len_length
;
4989 memcpy(sequence_ptr
, content
->data
, content
->length
);
4992 CFReleaseSafe(sequence
);
4996 CFDataRef
SecCertificateCopyIssuerSequence(
4997 SecCertificateRef certificate
) {
4998 return SecDERItemCopySequence(&certificate
->_issuer
);
5001 CFDataRef
SecCertificateCopySubjectSequence(
5002 SecCertificateRef certificate
) {
5003 return SecDERItemCopySequence(&certificate
->_subject
);
5006 const DERAlgorithmId
*SecCertificateGetPublicKeyAlgorithm(
5007 SecCertificateRef certificate
) {
5008 return &certificate
->_algId
;
5011 const DERItem
*SecCertificateGetPublicKeyData(SecCertificateRef certificate
) {
5012 return &certificate
->_pubKeyDER
;
5016 /* There is already a SecCertificateCopyPublicKey with different args on OS X,
5017 so we will refer to this one internally as SecCertificateCopyPublicKey_ios.
5019 SecKeyRef
SecCertificateCopyPublicKey_ios(SecCertificateRef certificate
)
5021 SecKeyRef
SecCertificateCopyPublicKey(SecCertificateRef certificate
)
5024 if (certificate
->_pubKey
== NULL
) {
5025 const DERAlgorithmId
*algId
=
5026 SecCertificateGetPublicKeyAlgorithm(certificate
);
5027 const DERItem
*keyData
= SecCertificateGetPublicKeyData(certificate
);
5028 const DERItem
*params
= NULL
;
5029 if (algId
->params
.length
!= 0) {
5030 params
= &algId
->params
;
5032 SecAsn1Oid oid1
= { .Data
= algId
->oid
.data
, .Length
= algId
->oid
.length
};
5033 SecAsn1Item params1
= {
5034 .Data
= params
? params
->data
: NULL
,
5035 .Length
= params
? params
->length
: 0
5037 SecAsn1Item keyData1
= {
5038 .Data
= keyData
? keyData
->data
: NULL
,
5039 .Length
= keyData
? keyData
->length
: 0
5041 certificate
->_pubKey
= SecKeyCreatePublicFromDER(kCFAllocatorDefault
, &oid1
, ¶ms1
,
5045 return CFRetainSafe(certificate
->_pubKey
);
5048 bool SecCertificateIsWeak(SecCertificateRef certificate
) {
5050 SecKeyRef pubKey
= NULL
;
5052 require_quiet(pubKey
= SecCertificateCopyPublicKey_ios(certificate
), out
);
5054 require_quiet(pubKey
= SecCertificateCopyPublicKey(certificate
) ,out
);
5056 size_t size
= SecKeyGetBlockSize(pubKey
);
5057 switch (SecKeyGetAlgorithmIdentifier(pubKey
)) {
5058 case kSecRSAAlgorithmID
:
5059 if (MIN_RSA_KEY_SIZE
<= size
) weak
= false;
5061 case kSecECDSAAlgorithmID
:
5062 if (MIN_EC_KEY_SIZE
<= size
) weak
= false;
5069 CFReleaseSafe(pubKey
);
5073 bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate
,
5074 CFDictionaryRef keySizes
) {
5075 bool goodSize
= false;
5076 SecKeyRef pubKey
= NULL
;
5078 require_quiet(pubKey
= SecCertificateCopyPublicKey_ios(certificate
), out
);
5080 require_quiet(pubKey
= SecCertificateCopyPublicKey(certificate
) ,out
);
5082 size_t size
= SecKeyGetBlockSize(pubKey
);
5083 CFNumberRef minSize
;
5084 size_t minSizeInBits
;
5085 switch (SecKeyGetAlgorithmIdentifier(pubKey
)) {
5086 case kSecRSAAlgorithmID
:
5087 if(CFDictionaryGetValueIfPresent(keySizes
, kSecAttrKeyTypeRSA
, (const void**)&minSize
)
5088 && minSize
&& CFNumberGetValue(minSize
, kCFNumberLongType
, &minSizeInBits
)) {
5089 if (size
>= (size_t)(minSizeInBits
+7)/8) goodSize
= true;
5092 case kSecECDSAAlgorithmID
:
5093 if(CFDictionaryGetValueIfPresent(keySizes
, kSecAttrKeyTypeEC
, (const void**)&minSize
)
5094 && minSize
&& CFNumberGetValue(minSize
, kCFNumberLongType
, &minSizeInBits
)) {
5095 if (size
>= (size_t)(minSizeInBits
+7)/8) goodSize
= true;
5102 CFReleaseSafe(pubKey
);
5106 CFDataRef
SecCertificateGetSHA1Digest(SecCertificateRef certificate
) {
5107 if (!certificate
|| !certificate
->_der
.data
) {
5110 if (!certificate
->_sha1Digest
) {
5111 certificate
->_sha1Digest
=
5112 SecSHA1DigestCreate(CFGetAllocator(certificate
),
5113 certificate
->_der
.data
, certificate
->_der
.length
);
5115 return certificate
->_sha1Digest
;
5118 CFDataRef
SecCertificateCopySHA256Digest(SecCertificateRef certificate
) {
5119 if (!certificate
|| !certificate
->_der
.data
) {
5122 return SecSHA256DigestCreate(CFGetAllocator(certificate
),
5123 certificate
->_der
.data
, certificate
->_der
.length
);
5126 CFDataRef
SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate
) {
5127 CFDataRef digest
= NULL
;
5128 CFDataRef issuer
= SecCertificateCopyIssuerSequence(certificate
);
5130 digest
= SecSHA1DigestCreate(kCFAllocatorDefault
,
5131 CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
));
5137 CFDataRef
SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate
) {
5138 if (!certificate
|| !certificate
->_pubKeyDER
.data
) {
5141 return SecSHA1DigestCreate(CFGetAllocator(certificate
),
5142 certificate
->_pubKeyDER
.data
, certificate
->_pubKeyDER
.length
);
5145 CFDataRef
SecCertificateCopySubjectPublicKeyInfoSHA1Digest(SecCertificateRef certificate
) {
5146 if (!certificate
|| !certificate
->_subjectPublicKeyInfo
.data
) {
5149 return SecSHA1DigestCreate(CFGetAllocator(certificate
),
5150 certificate
->_subjectPublicKeyInfo
.data
, certificate
->_subjectPublicKeyInfo
.length
);
5153 CFDataRef
SecCertificateCopySubjectPublicKeyInfoSHA256Digest(SecCertificateRef certificate
) {
5154 if (!certificate
|| !certificate
->_subjectPublicKeyInfo
.data
) {
5157 return SecSHA256DigestCreate(CFGetAllocator(certificate
),
5158 certificate
->_subjectPublicKeyInfo
.data
, certificate
->_subjectPublicKeyInfo
.length
);
5161 CFTypeRef
SecCertificateCopyKeychainItem(SecCertificateRef certificate
)
5166 CFRetainSafe(certificate
->_keychain_item
);
5167 return certificate
->_keychain_item
;
5170 CFDataRef
SecCertificateGetAuthorityKeyID(SecCertificateRef certificate
) {
5174 if (!certificate
->_authorityKeyID
&&
5175 certificate
->_authorityKeyIdentifier
.length
) {
5176 certificate
->_authorityKeyID
= CFDataCreate(kCFAllocatorDefault
,
5177 certificate
->_authorityKeyIdentifier
.data
,
5178 certificate
->_authorityKeyIdentifier
.length
);
5181 return certificate
->_authorityKeyID
;
5184 CFDataRef
SecCertificateGetSubjectKeyID(SecCertificateRef certificate
) {
5188 if (!certificate
->_subjectKeyID
&&
5189 certificate
->_subjectKeyIdentifier
.length
) {
5190 certificate
->_subjectKeyID
= CFDataCreate(kCFAllocatorDefault
,
5191 certificate
->_subjectKeyIdentifier
.data
,
5192 certificate
->_subjectKeyIdentifier
.length
);
5195 return certificate
->_subjectKeyID
;
5198 CFArrayRef
SecCertificateGetCRLDistributionPoints(SecCertificateRef certificate
) {
5202 return certificate
->_crlDistributionPoints
;
5205 CFArrayRef
SecCertificateGetOCSPResponders(SecCertificateRef certificate
) {
5209 return certificate
->_ocspResponders
;
5212 CFArrayRef
SecCertificateGetCAIssuers(SecCertificateRef certificate
) {
5216 return certificate
->_caIssuers
;
5219 bool SecCertificateHasCriticalSubjectAltName(SecCertificateRef certificate
) {
5223 return certificate
->_subjectAltName
&&
5224 certificate
->_subjectAltName
->critical
;
5227 bool SecCertificateHasSubject(SecCertificateRef certificate
) {
5231 /* Since the _subject field is the content of the subject and not the
5232 whole thing, we can simply check for a 0 length subject here. */
5233 return certificate
->_subject
.length
!= 0;
5236 bool SecCertificateHasUnknownCriticalExtension(SecCertificateRef certificate
) {
5240 return certificate
->_foundUnknownCriticalExtension
;
5243 /* Private API functions. */
5244 void SecCertificateShow(SecCertificateRef certificate
) {
5246 fprintf(stderr
, "SecCertificate instance %p:\n", certificate
);
5247 fprintf(stderr
, "\n");
5251 CFDictionaryRef
SecCertificateCopyAttributeDictionary(
5252 SecCertificateRef certificate
) {
5253 CFAllocatorRef allocator
= CFGetAllocator(certificate
);
5254 CFNumberRef certificateType
, certificateEncoding
;
5255 CFStringRef label
, alias
;
5256 CFDataRef skid
, pubKeyDigest
, certData
;
5257 CFDictionaryRef dict
= NULL
;
5261 /* CSSM_CERT_X_509v1, CSSM_CERT_X_509v2 or CSSM_CERT_X_509v3 */
5262 SInt32 ctv
= certificate
->_version
+ 1;
5263 SInt32 cev
= 3; /* CSSM_CERT_ENCODING_DER */
5264 certificateType
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &ctv
);
5265 certificateEncoding
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, &cev
);
5266 certData
= SecCertificateCopyData(certificate
);
5267 skid
= SecCertificateGetSubjectKeyID(certificate
);
5268 pubKeyDigest
= SecSHA1DigestCreate(allocator
, certificate
->_pubKeyDER
.data
,
5269 certificate
->_pubKeyDER
.length
);
5271 /* We still need to figure out how to deal with multi valued attributes. */
5272 alias
= SecCertificateCopyRFC822Names(certificate
);
5273 label
= SecCertificateCopySubjectSummary(certificate
);
5279 DICT_ADDPAIR(kSecClass
, kSecClassCertificate
);
5280 DICT_ADDPAIR(kSecAttrCertificateType
, certificateType
);
5281 DICT_ADDPAIR(kSecAttrCertificateEncoding
, certificateEncoding
);
5283 DICT_ADDPAIR(kSecAttrLabel
, label
);
5285 DICT_ADDPAIR(kSecAttrAlias
, alias
);
5286 DICT_ADDPAIR(kSecAttrSubject
, certificate
->_normalizedSubject
);
5287 DICT_ADDPAIR(kSecAttrIssuer
, certificate
->_normalizedIssuer
);
5288 DICT_ADDPAIR(kSecAttrSerialNumber
, certificate
->_serialNumber
);
5290 DICT_ADDPAIR(kSecAttrSubjectKeyID
, skid
);
5291 DICT_ADDPAIR(kSecAttrPublicKeyHash
, pubKeyDigest
);
5292 DICT_ADDPAIR(kSecValueData
, certData
);
5293 dict
= DICT_CREATE(allocator
);
5295 CFReleaseSafe(label
);
5296 CFReleaseSafe(pubKeyDigest
);
5297 CFReleaseSafe(certData
);
5298 CFReleaseSafe(certificateEncoding
);
5299 CFReleaseSafe(certificateType
);
5304 SecCertificateRef
SecCertificateCreateFromAttributeDictionary(
5305 CFDictionaryRef refAttributes
) {
5306 /* @@@ Support having an allocator in refAttributes. */
5307 CFAllocatorRef allocator
= NULL
;
5308 CFDataRef data
= CFDictionaryGetValue(refAttributes
, kSecValueData
);
5309 return data
? SecCertificateCreateWithData(allocator
, data
) : NULL
;
5313 static bool _SecCertificateIsSelfSigned(SecCertificateRef certificate
) {
5314 if (certificate
->_isSelfSigned
== kSecSelfSignedUnknown
) {
5315 certificate
->_isSelfSigned
= kSecSelfSignedFalse
;
5316 SecKeyRef publicKey
= NULL
;
5317 require(certificate
&& (CFGetTypeID(certificate
) == SecCertificateGetTypeID()), out
);
5319 require(publicKey
= SecCertificateCopyPublicKey_ios(certificate
), out
);
5321 require(publicKey
= SecCertificateCopyPublicKey(certificate
), out
);
5323 CFDataRef normalizedIssuer
=
5324 SecCertificateGetNormalizedIssuerContent(certificate
);
5325 CFDataRef normalizedSubject
=
5326 SecCertificateGetNormalizedSubjectContent(certificate
);
5327 require_quiet(normalizedIssuer
&& normalizedSubject
&&
5328 CFEqual(normalizedIssuer
, normalizedSubject
), out
);
5330 CFDataRef authorityKeyID
= SecCertificateGetAuthorityKeyID(certificate
);
5331 CFDataRef subjectKeyID
= SecCertificateGetSubjectKeyID(certificate
);
5332 if (authorityKeyID
) {
5333 require_quiet(subjectKeyID
&& CFEqual(subjectKeyID
, authorityKeyID
), out
);
5336 require_noerr_quiet(SecCertificateIsSignedBy(certificate
, publicKey
), out
);
5338 certificate
->_isSelfSigned
= kSecSelfSignedTrue
;
5340 CFReleaseSafe(publicKey
);
5343 return (certificate
->_isSelfSigned
== kSecSelfSignedTrue
);
5346 bool SecCertificateIsCA(SecCertificateRef certificate
) {
5347 bool result
= false;
5348 require(certificate
&& (CFGetTypeID(certificate
) == SecCertificateGetTypeID()), out
);
5349 if (SecCertificateVersion(certificate
) >= 3) {
5350 const SecCEBasicConstraints
*basicConstraints
= SecCertificateGetBasicConstraints(certificate
);
5351 result
= (basicConstraints
&& basicConstraints
->isCA
);
5354 result
= _SecCertificateIsSelfSigned(certificate
);
5360 bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate
) {
5361 return (_SecCertificateIsSelfSigned(certificate
) && SecCertificateIsCA(certificate
));
5364 OSStatus
SecCertificateIsSelfSigned(SecCertificateRef certificate
, Boolean
*isSelfSigned
) {
5365 if (!certificate
|| (CFGetTypeID(certificate
) != SecCertificateGetTypeID())) {
5366 return errSecInvalidCertificate
;
5368 if (!isSelfSigned
) {
5371 *isSelfSigned
= _SecCertificateIsSelfSigned(certificate
);
5372 return errSecSuccess
;
5375 SecKeyUsage
SecCertificateGetKeyUsage(SecCertificateRef certificate
) {
5377 return kSecKeyUsageUnspecified
;
5379 return certificate
->_keyUsage
;
5382 CFArrayRef
SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate
)
5384 CFMutableArrayRef extended_key_usage_oids
=
5385 CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
5386 require_quiet(certificate
&& extended_key_usage_oids
, out
);
5388 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5389 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5390 if (extn
->extnID
.length
== oidExtendedKeyUsage
.length
&&
5391 !memcmp(extn
->extnID
.data
, oidExtendedKeyUsage
.data
, extn
->extnID
.length
)) {
5394 DERReturn drtn
= DERDecodeSeqInit(&extn
->extnValue
, &tag
, &derSeq
);
5395 require_noerr_quiet(drtn
, out
);
5396 require_quiet(tag
== ASN1_CONSTR_SEQUENCE
, out
);
5397 DERDecodedInfo currDecoded
;
5399 while ((drtn
= DERDecodeSeqNext(&derSeq
, &currDecoded
)) == DR_Success
) {
5400 require_quiet(currDecoded
.tag
== ASN1_OBJECT_ID
, out
);
5401 CFDataRef oid
= CFDataCreate(kCFAllocatorDefault
,
5402 currDecoded
.content
.data
, currDecoded
.content
.length
);
5404 CFArrayAppendValue(extended_key_usage_oids
, oid
);
5408 require_quiet(drtn
== DR_EndOfSequence
, out
);
5409 return extended_key_usage_oids
;
5413 CFReleaseSafe(extended_key_usage_oids
);
5417 CFArrayRef
SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate
)
5419 require_quiet(certificate
, out
);
5422 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5423 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5424 if (extn
->extnID
.length
== oidGoogleEmbeddedSignedCertificateTimestamp
.length
&&
5425 !memcmp(extn
->extnID
.data
, oidGoogleEmbeddedSignedCertificateTimestamp
.data
, extn
->extnID
.length
)) {
5426 /* Got the SCT oid */
5427 DERDecodedInfo sctList
;
5428 DERReturn drtn
= DERDecodeItem(&extn
->extnValue
, &sctList
);
5429 require_noerr_quiet(drtn
, out
);
5430 require_quiet(sctList
.tag
== ASN1_OCTET_STRING
, out
);
5431 return SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sctList
.content
.data
, sctList
.content
.length
);
5439 static bool matches_expected(DERItem der
, CFTypeRef expected
) {
5440 if (der
.length
> 1) {
5441 DERDecodedInfo decoded
;
5442 DERDecodeItem(&der
, &decoded
);
5443 switch (decoded
.tag
) {
5446 return decoded
.content
.length
== 0 && expected
== NULL
;
5450 case ASN1_IA5_STRING
:
5451 case ASN1_UTF8_STRING
: {
5452 if (isString(expected
)) {
5453 CFStringRef expectedString
= (CFStringRef
) expected
;
5454 CFStringRef itemString
= CFStringCreateWithBytesNoCopy(kCFAllocatorDefault
, decoded
.content
.data
, decoded
.content
.length
, kCFStringEncodingUTF8
, false, kCFAllocatorNull
);
5456 bool result
= (kCFCompareEqualTo
== CFStringCompare(expectedString
, itemString
, 0));
5457 CFReleaseNull(itemString
);
5463 case ASN1_OCTET_STRING
: {
5464 if (isData(expected
)) {
5465 CFDataRef expectedData
= (CFDataRef
) expected
;
5466 CFDataRef itemData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, decoded
.content
.data
, decoded
.content
.length
, kCFAllocatorNull
);
5468 bool result
= CFEqual(expectedData
, itemData
);
5469 CFReleaseNull(itemData
);
5475 case ASN1_INTEGER
: {
5476 SInt32 expected_value
= 0;
5477 if (isString(expected
))
5479 CFStringRef aStr
= (CFStringRef
)expected
;
5480 expected_value
= CFStringGetIntValue(aStr
);
5482 else if (isNumber(expected
))
5484 CFNumberGetValue(expected
, kCFNumberSInt32Type
, &expected_value
);
5487 uint32_t num_value
= 0;
5488 if (!DERParseInteger(&decoded
.content
, &num_value
))
5490 return ((uint32_t)expected_value
== num_value
);
5503 static bool cert_contains_marker_extension_value(SecCertificateRef certificate
, CFDataRef oid
, CFTypeRef expectedValue
)
5506 const uint8_t *oid_data
= CFDataGetBytePtr(oid
);
5507 size_t oid_len
= CFDataGetLength(oid
);
5509 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5510 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5511 if (extn
->extnID
.length
== oid_len
5512 && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
))
5514 return matches_expected(extn
->extnValue
, expectedValue
);
5520 static bool cert_contains_marker_extension(SecCertificateRef certificate
, CFTypeRef oid
)
5522 return cert_contains_marker_extension_value(certificate
, oid
, NULL
);
5525 struct search_context
{
5527 SecCertificateRef certificate
;
5530 static bool GetDecimalValueOfString(CFStringRef string
, uint32_t* value
)
5532 CFCharacterSetRef nonDecimalDigit
= CFCharacterSetCreateInvertedSet(NULL
, CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit
));
5533 bool result
= false;
5535 if ( CFStringGetLength(string
) > 0
5536 && !CFStringFindCharacterFromSet(string
, nonDecimalDigit
, CFRangeMake(0, CFStringGetLength(string
)), kCFCompareForcedOrdering
, NULL
))
5539 *value
= CFStringGetIntValue(string
);
5543 CFReleaseNull(nonDecimalDigit
);
5548 bool SecCertificateIsOidString(CFStringRef oid
)
5550 if (!oid
) return false;
5551 if (2 >= CFStringGetLength(oid
)) return false;
5554 /* oid string only has the allowed characters */
5555 CFCharacterSetRef decimalOid
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("0123456789."));
5556 CFCharacterSetRef nonDecimalOid
= CFCharacterSetCreateInvertedSet(NULL
, decimalOid
);
5557 if (CFStringFindCharacterFromSet(oid
, nonDecimalOid
, CFRangeMake(0, CFStringGetLength(oid
)), kCFCompareForcedOrdering
, NULL
)) {
5561 /* first arc is allowed */
5562 UniChar firstArc
[2];
5563 CFRange firstTwo
= {0, 2};
5564 CFStringGetCharacters(oid
, firstTwo
, firstArc
);
5565 if (firstArc
[1] != '.' ||
5566 (firstArc
[0] != '0' && firstArc
[0] != '1' && firstArc
[0] != '2')) {
5570 CFReleaseNull(decimalOid
);
5571 CFReleaseNull(nonDecimalOid
);
5576 CFDataRef
SecCertificateCreateOidDataFromString(CFAllocatorRef allocator
, CFStringRef string
)
5578 CFMutableDataRef currentResult
= NULL
;
5579 CFDataRef encodedResult
= NULL
;
5581 CFArrayRef parts
= NULL
;
5584 if (!string
|| !SecCertificateIsOidString(string
))
5587 parts
= CFStringCreateArrayBySeparatingStrings(NULL
, string
, CFSTR("."));
5592 count
= CFArrayGetCount(parts
);
5596 // assume no more than 5 bytes needed to represent any part of the oid,
5597 // since we limit parts to 32-bit values,
5598 // but the first two parts only need 1 byte
5599 currentResult
= CFDataCreateMutable(allocator
, 1+(count
-2)*5);
5605 part
= CFArrayGetValueAtIndex(parts
, 0);
5607 if (!GetDecimalValueOfString(part
, &x
) || x
> 6)
5614 part
= CFArrayGetValueAtIndex(parts
, 1);
5616 if (!GetDecimalValueOfString(part
, &x
) || x
> 39)
5622 CFDataAppendBytes(currentResult
, &firstByte
, 1);
5624 for (CFIndex i
= 2; i
< count
&& GetDecimalValueOfString(CFArrayGetValueAtIndex(parts
, i
), &x
); ++i
) {
5625 uint8_t b
[5] = {0, 0, 0, 0, 0};
5627 b
[3] = 0x80 | ((x
>> 7) & 0x7F);
5628 b
[2] = 0x80 | ((x
>> 14) & 0x7F);
5629 b
[1] = 0x80 | ((x
>> 21) & 0x7F);
5630 b
[0] = 0x80 | ((x
>> 28) & 0x7F);
5632 // Skip the unused extension bytes.
5633 size_t skipBytes
= 0;
5634 while (b
[skipBytes
] == 0x80)
5637 CFDataAppendBytes(currentResult
, b
+ skipBytes
, sizeof(b
) - skipBytes
);
5640 encodedResult
= currentResult
;
5641 currentResult
= NULL
;
5644 CFReleaseNull(parts
);
5645 CFReleaseNull(currentResult
);
5647 return encodedResult
;
5650 static void check_for_marker(const void *key
, const void *value
, void *context
)
5652 struct search_context
* search_ctx
= (struct search_context
*) context
;
5653 CFStringRef key_string
= (CFStringRef
) key
;
5654 CFTypeRef value_ref
= (CFTypeRef
) value
;
5656 // If we could have short circuted the iteration
5657 // we would have, but the best we can do
5658 // is not waste time comparing once a match
5660 if (search_ctx
->found
)
5663 if (CFGetTypeID(key_string
) != CFStringGetTypeID())
5666 CFDataRef key_data
= SecCertificateCreateOidDataFromString(NULL
, key_string
);
5668 if (NULL
== key_data
)
5671 if (cert_contains_marker_extension_value(search_ctx
->certificate
, key_data
, value_ref
))
5672 search_ctx
->found
= true;
5674 CFReleaseNull(key_data
);
5678 // CFType Ref is either:
5680 // CFData - OID to match with no data permitted
5681 // CFString - decimal OID to match
5682 // CFDictionary - OID -> Value table for expected values Single Object or Array
5683 // CFArray - Array of the above.
5685 // This returns true if any of the requirements are met.
5686 bool SecCertificateHasMarkerExtension(SecCertificateRef certificate
, CFTypeRef oids
)
5688 if (CFGetTypeID(oids
) == CFArrayGetTypeID()) {
5689 CFIndex ix
, length
= CFArrayGetCount(oids
);
5690 for (ix
= 0; ix
< length
; ix
++)
5691 if (SecCertificateHasMarkerExtension(certificate
, CFArrayGetValueAtIndex((CFArrayRef
)oids
, ix
)))
5693 } else if (CFGetTypeID(oids
) == CFDictionaryGetTypeID()) {
5694 struct search_context context
= { .found
= false, .certificate
= certificate
};
5695 CFDictionaryApplyFunction((CFDictionaryRef
) oids
, &check_for_marker
, &context
);
5696 return context
.found
;
5697 } else if (CFGetTypeID(oids
) == CFDataGetTypeID()) {
5698 return cert_contains_marker_extension(certificate
, oids
);
5699 } else if (CFGetTypeID(oids
) == CFStringGetTypeID()) {
5700 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, oids
);
5701 if (dataOid
== NULL
) return false;
5702 bool result
= cert_contains_marker_extension(certificate
, dataOid
);
5703 CFReleaseNull(dataOid
);
5709 static DERItem
*cert_extension_value_for_marker(SecCertificateRef certificate
, CFDataRef oid
) {
5711 const uint8_t *oid_data
= CFDataGetBytePtr(oid
);
5712 size_t oid_len
= CFDataGetLength(oid
);
5714 for (ix
= 0; ix
< certificate
->_extensionCount
; ++ix
) {
5715 const SecCertificateExtension
*extn
= &certificate
->_extensions
[ix
];
5716 if (extn
->extnID
.length
== oid_len
5717 && !memcmp(extn
->extnID
.data
, oid_data
, extn
->extnID
.length
))
5719 return (DERItem
*)&extn
->extnValue
;
5726 // CFType Ref is either:
5728 // CFData - OID to match with no data permitted
5729 // CFString - decimal OID to match
5731 DERItem
*SecCertificateGetExtensionValue(SecCertificateRef certificate
, CFTypeRef oid
) {
5732 if (!certificate
|| !oid
) {
5736 if(CFGetTypeID(oid
) == CFDataGetTypeID()) {
5737 return cert_extension_value_for_marker(certificate
, oid
);
5738 } else if (CFGetTypeID(oid
) == CFStringGetTypeID()) {
5739 CFDataRef dataOid
= SecCertificateCreateOidDataFromString(NULL
, oid
);
5740 if (dataOid
== NULL
) return NULL
;
5741 DERItem
*result
= cert_extension_value_for_marker(certificate
, dataOid
);
5742 CFReleaseNull(dataOid
);
5749 CFDataRef
SecCertificateCopyiAPAuthCapabilities(SecCertificateRef certificate
) {
5753 CFDataRef extensionData
= NULL
;
5754 DERItem
*extensionValue
= NULL
;
5755 extensionValue
= SecCertificateGetExtensionValue(certificate
,
5756 CFSTR("1.2.840.113635.100.6.36"));
5757 require_quiet(extensionValue
, out
);
5758 /* The extension is a octet string containing the DER-encoded 32-byte octet string */
5759 require_quiet(extensionValue
->length
== 34, out
);
5760 DERDecodedInfo decodedValue
;
5761 require_noerr_quiet(DERDecodeItem(extensionValue
, &decodedValue
), out
);
5762 if (decodedValue
.tag
== ASN1_OCTET_STRING
) {
5763 require_quiet(decodedValue
.content
.length
== 32, out
);
5764 extensionData
= CFDataCreate(NULL
, decodedValue
.content
.data
,
5765 decodedValue
.content
.length
);
5767 require_quiet(extensionValue
->data
[33] == 0x00 &&
5768 extensionValue
->data
[32] == 0x00, out
);
5769 extensionData
= CFDataCreate(NULL
, extensionValue
->data
, 32);
5772 return extensionData
;
5776 /* From iapd IAPAuthenticationTypes.h */
5777 typedef struct IapCertSerialNumber
5779 uint8_t xservID
; // Xserver ID
5780 uint8_t hsmID
; // Hardware security module ID (generated cert)
5781 uint8_t delimiter01
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5782 uint8_t dateYear
; // Date year cert was issued
5783 uint8_t dateMonth
; // Date month cert was issued
5784 uint8_t dateDay
; // Date day cert was issued
5785 uint8_t delimiter02
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5786 uint8_t devClass
; // iAP device class (maps to lingo permissions)
5787 uint8_t delimiter03
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5788 uint8_t batchNumHi
; // Batch number high byte (15:08)
5789 uint8_t batchNumLo
; // Batch number low byte (07:00)
5790 uint8_t delimiter04
; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5791 uint8_t serialNumHi
; // Serial number high byte (23:16)
5792 uint8_t serialNumMid
; // Serial number middle byte (15:08)
5793 uint8_t serialNumLo
; // Serial number low byte (07:00)
5795 } IapCertSerialNumber_t
, *pIapCertSerialNumber_t
;
5798 #define IAP_CERT_FIELD_DELIMITER 0xAA // "Apple_Accessory" delimiter
5799 SeciAuthVersion
SecCertificateGetiAuthVersion(SecCertificateRef certificate
) {
5801 return kSeciAuthInvalid
;
5803 if (NULL
!= SecCertificateGetExtensionValue(certificate
,
5804 CFSTR("1.2.840.113635.100.6.36"))) {
5805 return kSeciAuthVersion3
;
5807 DERItem serialNumber
= certificate
->_serialNum
;
5808 require_quiet(serialNumber
.data
, out
);
5809 require_quiet(serialNumber
.length
== 15, out
);
5810 require_quiet(serialNumber
.data
[2] == IAP_CERT_FIELD_DELIMITER
&&
5811 serialNumber
.data
[6] == IAP_CERT_FIELD_DELIMITER
&&
5812 serialNumber
.data
[8] == IAP_CERT_FIELD_DELIMITER
&&
5813 serialNumber
.data
[11] == IAP_CERT_FIELD_DELIMITER
, out
);
5814 return kSeciAuthVersion2
;
5816 return kSeciAuthInvalid
;
5819 SecCertificateRef
SecCertificateCreateWithPEM(CFAllocatorRef allocator
,
5820 CFDataRef pem_certificate
)
5822 static const char begin_cert
[] = "-----BEGIN CERTIFICATE-----\n";
5823 static const char end_cert
[] = "-----END CERTIFICATE-----\n";
5824 uint8_t *base64_data
= NULL
;
5825 SecCertificateRef cert
= NULL
;
5826 const unsigned char *data
= CFDataGetBytePtr(pem_certificate
);
5827 //const size_t length = CFDataGetLength(pem_certificate);
5828 char *begin
= strstr((const char *)data
, begin_cert
);
5829 char *end
= strstr((const char *)data
, end_cert
);
5832 begin
+= sizeof(begin_cert
) - 1;
5833 size_t base64_length
= SecBase64Decode(begin
, end
- begin
, NULL
, 0);
5834 if (base64_length
) {
5835 require_quiet(base64_data
= calloc(1, base64_length
), out
);
5836 require_quiet(base64_length
= SecBase64Decode(begin
, end
- begin
, base64_data
, base64_length
), out
);
5837 cert
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, base64_data
, base64_length
);
5846 // -- MARK -- XPC encoding/decoding
5849 bool SecCertificateAppendToXPCArray(SecCertificateRef certificate
, xpc_object_t xpc_certificates
, CFErrorRef
*error
) {
5851 return true; // NOOP
5853 size_t length
= SecCertificateGetLength(certificate
);
5854 const uint8_t *bytes
= SecCertificateGetBytePtr(certificate
);
5855 #if SECTRUST_VERBOSE_DEBUG
5856 secerror("cert=0x%lX length=%d bytes=0x%lX", (uintptr_t)certificate
, (int)length
, (uintptr_t)bytes
);
5858 if (!length
|| !bytes
) {
5859 return SecError(errSecParam
, error
, CFSTR("failed to der encode certificate"));
5861 xpc_array_set_data(xpc_certificates
, XPC_ARRAY_APPEND
, bytes
, length
);
5865 SecCertificateRef
SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates
, size_t index
, CFErrorRef
*error
) {
5866 SecCertificateRef certificate
= NULL
;
5868 const uint8_t *bytes
= xpc_array_get_data(xpc_certificates
, index
, &length
);
5870 certificate
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, bytes
, length
);
5873 SecError(errSecParam
, error
, CFSTR("certificates[%zu] failed to decode"), index
);
5878 xpc_object_t
SecCertificateArrayCopyXPCArray(CFArrayRef certificates
, CFErrorRef
*error
) {
5879 xpc_object_t xpc_certificates
;
5880 require_action_quiet(xpc_certificates
= xpc_array_create(NULL
, 0), exit
,
5881 SecError(errSecAllocate
, error
, CFSTR("failed to create xpc_array")));
5882 CFIndex ix
, count
= CFArrayGetCount(certificates
);
5883 for (ix
= 0; ix
< count
; ++ix
) {
5884 SecCertificateRef certificate
= (SecCertificateRef
) CFArrayGetValueAtIndex(certificates
, ix
);
5885 #if SECTRUST_VERBOSE_DEBUG
5886 CFIndex length
= SecCertificateGetLength(certificate
);
5887 const UInt8
*bytes
= SecCertificateGetBytePtr(certificate
);
5888 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
);
5890 if (!SecCertificateAppendToXPCArray(certificate
, xpc_certificates
, error
)) {
5891 xpc_release(xpc_certificates
);
5892 xpc_certificates
= NULL
;
5898 return xpc_certificates
;
5901 CFArrayRef
SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates
, CFErrorRef
*error
) {
5902 CFMutableArrayRef certificates
= NULL
;
5903 require_action_quiet(xpc_get_type(xpc_certificates
) == XPC_TYPE_ARRAY
, exit
,
5904 SecError(errSecParam
, error
, CFSTR("certificates xpc value is not an array")));
5905 size_t count
= xpc_array_get_count(xpc_certificates
);
5906 require_action_quiet(certificates
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
), exit
,
5907 SecError(errSecAllocate
, error
, CFSTR("failed to create CFArray of capacity %zu"), count
));
5910 for (ix
= 0; ix
< count
; ++ix
) {
5911 SecCertificateRef cert
= SecCertificateCreateWithXPCArrayAtIndex(xpc_certificates
, ix
, error
);
5913 CFRelease(certificates
);
5916 CFArraySetValueAtIndex(certificates
, ix
, cert
);
5921 return certificates
;
5924 #define do_if_registered(sdp, ...) if (gSecurityd && gSecurityd->sdp) { return gSecurityd->sdp(__VA_ARGS__); }
5927 static CFArrayRef
CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType
, CFErrorRef
* error
)
5929 __block CFArrayRef result
= NULL
;
5931 do_if_registered(ota_CopyEscrowCertificates
, escrowRootType
, error
);
5933 securityd_send_sync_and_do(kSecXPCOpOTAGetEscrowCertificates
, error
,
5934 ^bool(xpc_object_t message
, CFErrorRef
*error
)
5936 xpc_dictionary_set_uint64(message
, "escrowType", (uint64_t)escrowRootType
);
5939 ^bool(xpc_object_t response
, CFErrorRef
*error
)
5941 xpc_object_t xpc_array
= xpc_dictionary_get_value(response
, kSecXPCKeyResult
);
5943 if (response
&& (NULL
!= xpc_array
)) {
5944 result
= (CFArrayRef
)_CFXPCCreateCFObjectFromXPCObject(xpc_array
);
5947 return SecError(errSecInternal
, error
, CFSTR("Did not get the Escrow certificates"));
5949 return result
!= NULL
;
5954 CFArrayRef
SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType
)
5956 CFArrayRef result
= NULL
;
5958 CFDataRef certData
= NULL
;
5961 if (kSecCertificateBaselineEscrowRoot
== escrowRootType
||
5962 kSecCertificateBaselinePCSEscrowRoot
== escrowRootType
||
5963 kSecCertificateBaselineEscrowBackupRoot
== escrowRootType
||
5964 kSecCertificateBaselineEscrowEnrollmentRoot
== escrowRootType
)
5966 // The request is for the base line certificates.
5967 // Use the hard coded data to generate the return array.
5968 struct RootRecord
** pEscrowRoots
;
5969 switch (escrowRootType
) {
5970 case kSecCertificateBaselineEscrowRoot
:
5971 numRoots
= kNumberOfBaseLineEscrowRoots
;
5972 pEscrowRoots
= kBaseLineEscrowRoots
;
5974 case kSecCertificateBaselinePCSEscrowRoot
:
5975 numRoots
= kNumberOfBaseLinePCSEscrowRoots
;
5976 pEscrowRoots
= kBaseLinePCSEscrowRoots
;
5978 case kSecCertificateBaselineEscrowBackupRoot
:
5979 numRoots
= kNumberOfBaseLineEscrowBackupRoots
;
5980 pEscrowRoots
= kBaseLineEscrowBackupRoots
;
5982 case kSecCertificateBaselineEscrowEnrollmentRoot
:
5984 numRoots
= kNumberOfBaseLineEscrowEnrollmentRoots
;
5985 pEscrowRoots
= kBaseLineEscrowEnrollmentRoots
;
5989 // Get the hard coded set of roots
5990 SecCertificateRef baseLineCerts
[numRoots
];
5991 struct RootRecord
* pRootRecord
= NULL
;
5993 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
5994 pRootRecord
= pEscrowRoots
[iCnt
];
5995 if (NULL
!= pRootRecord
&& pRootRecord
->_length
> 0 && NULL
!= pRootRecord
->_bytes
) {
5996 certData
= CFDataCreate(kCFAllocatorDefault
, pRootRecord
->_bytes
, pRootRecord
->_length
);
5997 if (NULL
!= certData
) {
5998 baseLineCerts
[iCnt
] = SecCertificateCreateWithData(kCFAllocatorDefault
, certData
);
5999 CFRelease(certData
);
6003 result
= CFArrayCreate(kCFAllocatorDefault
, (const void **)baseLineCerts
, numRoots
, &kCFTypeArrayCallBacks
);
6004 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6005 if (NULL
!= baseLineCerts
[iCnt
]) {
6006 CFRelease(baseLineCerts
[iCnt
]);
6011 // The request is for the current certificates.
6012 CFErrorRef error
= NULL
;
6013 CFArrayRef cert_datas
= CopyEscrowCertificates(escrowRootType
, &error
);
6014 if (NULL
!= error
|| NULL
== cert_datas
) {
6015 if (NULL
!= error
) {
6018 if (NULL
!= cert_datas
) {
6019 CFRelease(cert_datas
);
6024 numRoots
= (int)(CFArrayGetCount(cert_datas
));
6026 SecCertificateRef assetCerts
[numRoots
];
6027 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6028 certData
= (CFDataRef
)CFArrayGetValueAtIndex(cert_datas
, iCnt
);
6029 if (NULL
!= certData
) {
6030 SecCertificateRef aCertRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, certData
);
6031 assetCerts
[iCnt
] = aCertRef
;
6034 assetCerts
[iCnt
] = NULL
;
6039 result
= CFArrayCreate(kCFAllocatorDefault
, (const void **)assetCerts
, numRoots
, &kCFTypeArrayCallBacks
);
6040 for (iCnt
= 0; iCnt
< numRoots
; iCnt
++) {
6041 if (NULL
!= assetCerts
[iCnt
]) {
6042 CFRelease(assetCerts
[iCnt
]);
6046 CFReleaseSafe(cert_datas
);
6051 SEC_CONST_DECL (kSecSignatureDigestAlgorithmUnknown
, "SignatureDigestUnknown");
6052 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD2
, "SignatureDigestMD2");
6053 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD4
, "SignatureDigestMD4");
6054 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD5
, "SignatureDigestMD5");
6055 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA1
, "SignatureDigestSHA1");
6056 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA224
, "SignatureDigestSHA224");
6057 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA256
, "SignatureDigestSHA256");
6058 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA384
, "SignatureDigestSHA284");
6059 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA512
, "SignatureDigestSHA512");
6061 SecSignatureHashAlgorithm
SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate
)
6063 SecSignatureHashAlgorithm result
= kSecSignatureHashAlgorithmUnknown
;
6064 DERAlgorithmId
*algId
= (certificate
) ? &certificate
->_tbsSigAlg
: NULL
;
6065 const DERItem
*algOid
= (algId
) ? &algId
->oid
: NULL
;
6067 if (!algOid
->data
|| !algOid
->length
) {
6070 /* classify the signature algorithm OID into one of our known types */
6071 if (DEROidCompare(algOid
, &oidSha512Ecdsa
) ||
6072 DEROidCompare(algOid
, &oidSha512Rsa
) ||
6073 DEROidCompare(algOid
, &oidSha512
)) {
6074 result
= kSecSignatureHashAlgorithmSHA512
;
6077 if (DEROidCompare(algOid
, &oidSha384Ecdsa
) ||
6078 DEROidCompare(algOid
, &oidSha384Rsa
) ||
6079 DEROidCompare(algOid
, &oidSha384
)) {
6080 result
= kSecSignatureHashAlgorithmSHA384
;
6083 if (DEROidCompare(algOid
, &oidSha256Ecdsa
) ||
6084 DEROidCompare(algOid
, &oidSha256Rsa
) ||
6085 DEROidCompare(algOid
, &oidSha256
)) {
6086 result
= kSecSignatureHashAlgorithmSHA256
;
6089 if (DEROidCompare(algOid
, &oidSha224Ecdsa
) ||
6090 DEROidCompare(algOid
, &oidSha224Rsa
) ||
6091 DEROidCompare(algOid
, &oidSha224
)) {
6092 result
= kSecSignatureHashAlgorithmSHA224
;
6095 if (DEROidCompare(algOid
, &oidSha1Ecdsa
) ||
6096 DEROidCompare(algOid
, &oidSha1Rsa
) ||
6097 DEROidCompare(algOid
, &oidSha1Dsa
) ||
6098 DEROidCompare(algOid
, &oidSha1DsaOIW
) ||
6099 DEROidCompare(algOid
, &oidSha1DsaCommonOIW
) ||
6100 DEROidCompare(algOid
, &oidSha1RsaOIW
) ||
6101 DEROidCompare(algOid
, &oidSha1Fee
) ||
6102 DEROidCompare(algOid
, &oidSha1
)) {
6103 result
= kSecSignatureHashAlgorithmSHA1
;
6106 if (DEROidCompare(algOid
, &oidMd5Rsa
) ||
6107 DEROidCompare(algOid
, &oidMd5Fee
) ||
6108 DEROidCompare(algOid
, &oidMd5
)) {
6109 result
= kSecSignatureHashAlgorithmMD5
;
6112 if (DEROidCompare(algOid
, &oidMd4Rsa
) ||
6113 DEROidCompare(algOid
, &oidMd4
)) {
6114 result
= kSecSignatureHashAlgorithmMD4
;
6117 if (DEROidCompare(algOid
, &oidMd2Rsa
) ||
6118 DEROidCompare(algOid
, &oidMd2
)) {
6119 result
= kSecSignatureHashAlgorithmMD2
;