]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCertificate.c
Security-58286.230.21.tar.gz
[apple/security.git] / OSX / sec / Security / SecCertificate.c
1 /*
2 * Copyright (c) 2006-2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecCertificate.c - CoreFoundation based certificate object
26 */
27
28 #ifdef STANDALONE
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__
32 #endif
33
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>
45 #include <string.h>
46 #include <AssertMacros.h>
47 #include <libDER/DER_CertCrl.h>
48 #include <libDER/DER_Encode.h>
49 #include <libDER/DER_Keys.h>
50 #include <libDER/asn1Types.h>
51 #include <libDER/oids.h>
52 #include "SecBasePriv.h"
53 #include "SecRSAKey.h"
54 #include "SecFramework.h"
55 #include "SecItem.h"
56 #include "SecItemPriv.h"
57 #include "SecSignatureVerificationSupport.h"
58 #include <stdbool.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>
64 #include <stdlib.h>
65 #include <libkern/OSByteOrder.h>
66 #include <ctype.h>
67 #include <Security/SecInternal.h>
68 #include <Security/SecFrameworkStrings.h>
69 #include "SecBase64.h"
70 #include "AppleBaselineEscrowCertificates.h"
71 #include "AppleiPhoneDeviceCACertificates.h"
72 #include <ipc/securityd_client.h>
73 #include <Security/SecKeyInternal.h>
74
75 #pragma clang diagnostic ignored "-Wformat=2"
76
77 /* The minimum key sizes necessary to not be considered "weak" */
78 #define MIN_RSA_KEY_SIZE 128 // 1024-bit
79 #define MIN_EC_KEY_SIZE 20 // 160-bit
80
81 /* The minimum key sizes necessary to be considered "strong" */
82 #define MIN_STRONG_RSA_KEY_SIZE 256 // 2048-bit
83 #define MIN_STRONG_EC_KEY_SIZE 28 // 224-bit
84
85 typedef struct SecCertificateExtension {
86 DERItem extnID;
87 bool critical;
88 DERItem extnValue;
89 } SecCertificateExtension;
90
91 enum {
92 kSecSelfSignedUnknown = 0,
93 kSecSelfSignedFalse,
94 kSecSelfSignedTrue,
95 };
96
97 struct __SecCertificate {
98 CFRuntimeBase _base;
99
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. */
104
105 UInt8 _version;
106 DERItem _serialNum; /* Integer. */
107 DERAlgorithmId _tbsSigAlg; /* sig alg MUST be same as _sigAlg. */
108 DERItem _issuer; /* Sequence of RDN. */
109 CFAbsoluteTime _notBefore;
110 CFAbsoluteTime _notAfter;
111 DERItem _subject; /* Sequence of RDN. */
112 DERItem _subjectPublicKeyInfo; /* SPKI (without tag/length) */
113 DERAlgorithmId _algId; /* oid and params of _pubKeyDER. */
114 DERItem _pubKeyDER; /* contents of bit string */
115 DERItem _issuerUniqueID; /* bit string, optional */
116 DERItem _subjectUniqueID; /* bit string, optional */
117
118 bool _foundUnknownCriticalExtension;
119
120 /* Well known certificate extensions. */
121 SecCEBasicConstraints _basicConstraints;
122 SecCEPolicyConstraints _policyConstraints;
123 SecCEPolicyMappings _policyMappings;
124 SecCECertificatePolicies _certificatePolicies;
125 SecCEInhibitAnyPolicy _inhibitAnyPolicySkipCerts;
126
127 /* If KeyUsage extension is not present this is 0, otherwise it's
128 the value of the extension. */
129 SecKeyUsage _keyUsage;
130
131 /* OCTETS of SubjectKeyIdentifier extensions KeyIdentifier.
132 Length = 0 if not present. */
133 DERItem _subjectKeyIdentifier;
134
135 /* OCTETS of AuthorityKeyIdentifier extensions KeyIdentifier.
136 Length = 0 if not present. */
137 DERItem _authorityKeyIdentifier;
138 /* AuthorityKeyIdentifier extension _authorityKeyIdentifierIssuer and
139 _authorityKeyIdentifierSerialNumber have non zero length if present.
140 Both are either present or absent together. */
141 DERItem _authorityKeyIdentifierIssuer;
142 DERItem _authorityKeyIdentifierSerialNumber;
143
144 /* Subject alt name extension, if present. Not malloced, it's just a
145 pointer to an element in the _extensions array. */
146 const SecCertificateExtension *_subjectAltName;
147
148 /* Parsed extension values. */
149
150 /* Array of CFURLRefs containing the URI values of crlDistributionPoints. */
151 CFMutableArrayRef _crlDistributionPoints;
152
153 /* Array of CFURLRefs containing the URI values of accessLocations of each
154 id-ad-ocsp AccessDescription in the Authority Information Access
155 extension. */
156 CFMutableArrayRef _ocspResponders;
157
158 /* Array of CFURLRefs containing the URI values of accessLocations of each
159 id-ad-caIssuers AccessDescription in the Authority Information Access
160 extension. */
161 CFMutableArrayRef _caIssuers;
162
163 /* Array of CFDataRefs containing the generalNames for permittedSubtrees
164 Name Constraints.*/
165 CFArrayRef _permittedSubtrees;
166
167 /* Array of CFDataRefs containing the generalNames for excludedSubtrees
168 Name Constraints. */
169 CFArrayRef _excludedSubtrees;
170
171 CFMutableArrayRef _embeddedSCTs;
172
173 /* All other (non known) extensions. The _extensions array is malloced. */
174 CFIndex _extensionCount;
175 SecCertificateExtension *_extensions;
176
177 /* Optional cached fields. */
178 SecKeyRef _pubKey;
179 CFDataRef _der_data;
180 CFArrayRef _properties;
181 CFDataRef _serialNumber;
182 CFDataRef _normalizedIssuer;
183 CFDataRef _normalizedSubject;
184 CFDataRef _authorityKeyID;
185 CFDataRef _subjectKeyID;
186
187 CFDataRef _sha1Digest;
188 CFTypeRef _keychain_item;
189 uint8_t _isSelfSigned;
190
191 };
192
193 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
194
195 SEC_CONST_DECL (kSecCertificateProductionEscrowKey, "ProductionEscrowKey");
196 SEC_CONST_DECL (kSecCertificateProductionPCSEscrowKey, "ProductionPCSEscrowKey");
197 SEC_CONST_DECL (kSecCertificateEscrowFileName, "AppleESCertificates");
198
199 /* Public Constants for property list keys. */
200 SEC_CONST_DECL (kSecPropertyKeyType, "type");
201 SEC_CONST_DECL (kSecPropertyKeyLabel, "label");
202 SEC_CONST_DECL (kSecPropertyKeyLocalizedLabel, "localized label");
203 SEC_CONST_DECL (kSecPropertyKeyValue, "value");
204
205 /* Public Constants for property list values. */
206 SEC_CONST_DECL (kSecPropertyTypeWarning, "warning");
207 SEC_CONST_DECL (kSecPropertyTypeError, "error");
208 SEC_CONST_DECL (kSecPropertyTypeSuccess, "success");
209 SEC_CONST_DECL (kSecPropertyTypeTitle, "title");
210 SEC_CONST_DECL (kSecPropertyTypeSection, "section");
211 SEC_CONST_DECL (kSecPropertyTypeData, "data");
212 SEC_CONST_DECL (kSecPropertyTypeString, "string");
213 SEC_CONST_DECL (kSecPropertyTypeURL, "url");
214 SEC_CONST_DECL (kSecPropertyTypeDate, "date");
215
216 /* Extension parsing routine. */
217 typedef bool (*SecCertificateExtensionParser)(SecCertificateRef certificate,
218 const SecCertificateExtension *extn);
219
220 /* Mapping from extension OIDs (as a DERItem *) to
221 SecCertificateExtensionParser extension parsing routines. */
222 static CFDictionaryRef sExtensionParsers;
223
224 /* Forward declarations of static functions. */
225 static CFStringRef SecCertificateCopyDescription(CFTypeRef cf);
226 static void SecCertificateDestroy(CFTypeRef cf);
227 static bool derDateGetAbsoluteTime(const DERItem *dateChoice,
228 CFAbsoluteTime *absTime) __attribute__((__nonnull__));
229
230 /* Static functions. */
231 static CFStringRef SecCertificateCopyDescription(CFTypeRef cf) {
232 SecCertificateRef certificate = (SecCertificateRef)cf;
233 CFStringRef subject = SecCertificateCopySubjectSummary(certificate);
234 CFStringRef issuer = SecCertificateCopyIssuerSummary(certificate);
235 CFStringRef desc = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
236 CFSTR("<cert(%p) s: %@ i: %@>"), certificate, subject, issuer);
237 CFReleaseSafe(issuer);
238 CFReleaseSafe(subject);
239 return desc;
240 }
241
242 static void SecCertificateDestroy(CFTypeRef cf) {
243 SecCertificateRef certificate = (SecCertificateRef)cf;
244 if (certificate->_certificatePolicies.policies) {
245 free(certificate->_certificatePolicies.policies);
246 certificate->_certificatePolicies.policies = NULL;
247 }
248 if (certificate->_policyMappings.mappings) {
249 free(certificate->_policyMappings.mappings);
250 certificate->_policyMappings.mappings = NULL;
251 }
252 CFReleaseNull(certificate->_crlDistributionPoints);
253 CFReleaseNull(certificate->_ocspResponders);
254 CFReleaseNull(certificate->_caIssuers);
255 if (certificate->_extensions) {
256 free(certificate->_extensions);
257 certificate->_extensions = NULL;
258 }
259 CFReleaseNull(certificate->_pubKey);
260 CFReleaseNull(certificate->_der_data);
261 CFReleaseNull(certificate->_properties);
262 CFReleaseNull(certificate->_serialNumber);
263 CFReleaseNull(certificate->_normalizedIssuer);
264 CFReleaseNull(certificate->_normalizedSubject);
265 CFReleaseNull(certificate->_authorityKeyID);
266 CFReleaseNull(certificate->_subjectKeyID);
267 CFReleaseNull(certificate->_sha1Digest);
268 CFReleaseNull(certificate->_keychain_item);
269 CFReleaseNull(certificate->_permittedSubtrees);
270 CFReleaseNull(certificate->_excludedSubtrees);
271 }
272
273 static Boolean SecCertificateEqual(CFTypeRef cf1, CFTypeRef cf2) {
274 SecCertificateRef cert1 = (SecCertificateRef)cf1;
275 SecCertificateRef cert2 = (SecCertificateRef)cf2;
276 if (cert1 == cert2)
277 return true;
278 if (!cert2 || cert1->_der.length != cert2->_der.length)
279 return false;
280 return !memcmp(cert1->_der.data, cert2->_der.data, cert1->_der.length);
281 }
282
283 /* Hash of the certificate is der length + signature length + last 4 bytes
284 of signature. */
285 static CFHashCode SecCertificateHash(CFTypeRef cf) {
286 SecCertificateRef certificate = (SecCertificateRef)cf;
287 size_t der_length = certificate->_der.length;
288 size_t sig_length = certificate->_signature.length;
289 size_t ix = (sig_length > 4) ? sig_length - 4 : 0;
290 CFHashCode hashCode = 0;
291 for (; ix < sig_length; ++ix)
292 hashCode = (hashCode << 8) + certificate->_signature.data[ix];
293
294 return (hashCode + der_length + sig_length);
295 }
296
297 #if 1
298
299 /************************************************************************/
300 /************************* General Name Parsing *************************/
301 /************************************************************************/
302 /*
303 GeneralName ::= CHOICE {
304 otherName [0] OtherName,
305 rfc822Name [1] IA5String,
306 dNSName [2] IA5String,
307 x400Address [3] ORAddress,
308 directoryName [4] Name,
309 ediPartyName [5] EDIPartyName,
310 uniformResourceIdentifier [6] IA5String,
311 iPAddress [7] OCTET STRING,
312 registeredID [8] OBJECT IDENTIFIER}
313
314 OtherName ::= SEQUENCE {
315 type-id OBJECT IDENTIFIER,
316 value [0] EXPLICIT ANY DEFINED BY type-id }
317
318 EDIPartyName ::= SEQUENCE {
319 nameAssigner [0] DirectoryString OPTIONAL,
320 partyName [1] DirectoryString }
321 */
322 OSStatus SecCertificateParseGeneralNameContentProperty(DERTag tag,
323 const DERItem *generalNameContent,
324 void *context, parseGeneralNameCallback callback) {
325 switch (tag) {
326 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0:
327 return callback(context, GNT_OtherName, generalNameContent);
328 case ASN1_CONTEXT_SPECIFIC | 1:
329 return callback(context, GNT_RFC822Name, generalNameContent);
330 case ASN1_CONTEXT_SPECIFIC | 2:
331 return callback(context, GNT_DNSName, generalNameContent);
332 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3:
333 return callback(context, GNT_X400Address, generalNameContent);
334 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4:
335 return callback(context, GNT_DirectoryName, generalNameContent);
336 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5:
337 return callback(context, GNT_EdiPartyName, generalNameContent);
338 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6:
339 {
340 /* Technically I don't think this is valid, but there are certs out
341 in the wild that use a constructed IA5String. In particular the
342 VeriSign Time Stamping Authority CA.cer does this. */
343 DERDecodedInfo uriContent;
344 require_noerr(DERDecodeItem(generalNameContent, &uriContent), badDER);
345 require(uriContent.tag == ASN1_IA5_STRING, badDER);
346 return callback(context, GNT_URI, &uriContent.content);
347 }
348 case ASN1_CONTEXT_SPECIFIC | 6:
349 return callback(context, GNT_URI, generalNameContent);
350 case ASN1_CONTEXT_SPECIFIC | 7:
351 return callback(context, GNT_IPAddress, generalNameContent);
352 case ASN1_CONTEXT_SPECIFIC | 8:
353 return callback(context, GNT_RegisteredID, generalNameContent);
354 default:
355 goto badDER;
356 }
357 badDER:
358 return errSecInvalidCertificate;
359 }
360
361 static OSStatus parseGeneralNamesContent(const DERItem *generalNamesContent,
362 void *context, parseGeneralNameCallback callback) {
363 DERSequence gnSeq;
364 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq);
365 require_noerr_quiet(drtn, badDER);
366 DERDecodedInfo generalNameContent;
367 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) ==
368 DR_Success) {
369 OSStatus status = SecCertificateParseGeneralNameContentProperty(
370 generalNameContent.tag, &generalNameContent.content, context,
371 callback);
372 if (status)
373 return status;
374 }
375 require_quiet(drtn == DR_EndOfSequence, badDER);
376 return errSecSuccess;
377
378 badDER:
379 return errSecInvalidCertificate;
380 }
381
382 OSStatus SecCertificateParseGeneralNames(const DERItem *generalNames, void *context,
383 parseGeneralNameCallback callback) {
384 DERDecodedInfo generalNamesContent;
385 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent);
386 require_noerr_quiet(drtn, badDER);
387 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
388 return parseGeneralNamesContent(&generalNamesContent.content, context,
389 callback);
390 badDER:
391 return errSecInvalidCertificate;
392 }
393
394 #else
395
396 /*
397 GeneralName ::= CHOICE {
398 otherName [0] OtherName,
399 rfc822Name [1] IA5String,
400 dNSName [2] IA5String,
401 x400Address [3] ORAddress,
402 directoryName [4] Name,
403 ediPartyName [5] EDIPartyName,
404 uniformResourceIdentifier [6] IA5String,
405 iPAddress [7] OCTET STRING,
406 registeredID [8] OBJECT IDENTIFIER}
407
408 EDIPartyName ::= SEQUENCE {
409 nameAssigner [0] DirectoryString OPTIONAL,
410 partyName [1] DirectoryString }
411 */
412 static OSStatus parseGeneralNameContentProperty(DERTag tag,
413 const DERItem *generalNameContent, SecCEGeneralName *generalName) {
414 switch (tag) {
415 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0:
416 generalName->nameType = GNT_OtherName;
417 generalName->berEncoded = true;
418 generalName->name = *generalNameContent;
419 break;
420 case ASN1_CONTEXT_SPECIFIC | 1:
421 /* IA5String. */
422 generalName->nameType = GNT_RFC822Name;
423 generalName->berEncoded = false;
424 generalName->name = *generalNameContent;
425 break;
426 case ASN1_CONTEXT_SPECIFIC | 2:
427 /* IA5String. */
428 generalName->nameType = GNT_DNSName;
429 generalName->berEncoded = false;
430 generalName->name = *generalNameContent;
431 break;
432 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3:
433 generalName->nameType = GNT_X400Address;
434 generalName->berEncoded = true;
435 generalName->name = *generalNameContent;
436 break;
437 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4:
438 generalName->nameType = GNT_DirectoryName;
439 generalName->berEncoded = true;
440 generalName->name = *generalNameContent;
441 break;
442 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5:
443 generalName->nameType = GNT_EdiPartyName;
444 generalName->berEncoded = true;
445 generalName->name = *generalNameContent;
446 break;
447 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6:
448 {
449 /* Technically I don't think this is valid, but there are certs out
450 in the wild that use a constructed IA5String. In particular the
451 VeriSign Time Stamping Authority CA.cer does this. */
452 DERDecodedInfo decoded;
453 require_noerr(DERDecodeItem(generalNameContent, &decoded), badDER);
454 require(decoded.tag == ASN1_IA5_STRING, badDER);
455 generalName->nameType = GNT_URI;
456 generalName->berEncoded = false;
457 generalName->name = decoded.content;
458 break;
459 }
460 case ASN1_CONTEXT_SPECIFIC | 6:
461 generalName->nameType = GNT_URI;
462 generalName->berEncoded = false;
463 generalName->name = *generalNameContent;
464 break;
465 case ASN1_CONTEXT_SPECIFIC | 7:
466 /* @@@ This is the IP Address as an OCTECT STRING. For IPv4 it's
467 8 octects, addr/mask for ipv6 it's 32. */
468 generalName->nameType = GNT_IPAddress;
469 generalName->berEncoded = false;
470 generalName->name = *generalNameContent;
471 break;
472 case ASN1_CONTEXT_SPECIFIC | 8:
473 /* name is the content of an OID. */
474 generalName->nameType = GNT_RegisteredID;
475 generalName->berEncoded = false;
476 generalName->name = *generalNameContent;
477 break;
478 default:
479 goto badDER;
480 break;
481 }
482 return errSecSuccess;
483 badDER:
484 return errSecInvalidCertificate;
485 }
486
487 /*
488 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
489 */
490 static OSStatus parseGeneralNamesContent(const DERItem *generalNamesContent,
491 CFIndex *count, SecCEGeneralName **name) {
492 SecCEGeneralName *generalNames = NULL;
493 DERSequence gnSeq;
494 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq);
495 require_noerr_quiet(drtn, badDER);
496 DERDecodedInfo generalNameContent;
497 CFIndex generalNamesCount = 0;
498 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) ==
499 DR_Success) {
500 ++generalNamesCount;
501 }
502 require_quiet(drtn == DR_EndOfSequence, badDER);
503
504 require(generalNames = calloc(generalNamesCount, sizeof(SecCEGeneralName)),
505 badDER);
506 DERDecodeSeqContentInit(generalNamesContent, &gnSeq);
507 CFIndex ix = 0;
508 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) ==
509 DR_Success) {
510 if (!parseGeneralNameContentProperty(generalNameContent.tag,
511 &generalNameContent.content, &generalNames[ix])) {
512 goto badDER;
513 }
514 ++ix;
515 }
516 *count = generalNamesCount;
517 *name = generalNames;
518 return errSecSuccess;
519
520 badDER:
521 if (generalNames)
522 free(generalNames);
523 return errSecInvalidCertificate;
524 }
525
526 static OSStatus parseGeneralNames(const DERItem *generalNames,
527 CFIndex *count, SecCEGeneralName **name) {
528 DERDecodedInfo generalNamesContent;
529 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent);
530 require_noerr_quiet(drtn, badDER);
531 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE,
532 badDER);
533 parseGeneralNamesContent(&generalNamesContent.content, count, name);
534 return errSecSuccess;
535 badDER:
536 return errSecInvalidCertificate;
537 }
538 #endif
539
540 /************************************************************************/
541 /************************** X.509 Name Parsing **************************/
542 /************************************************************************/
543
544 typedef OSStatus (*parseX501NameCallback)(void *context, const DERItem *type,
545 const DERItem *value, CFIndex rdnIX, bool localized);
546
547 static OSStatus parseRDNContent(const DERItem *rdnSetContent, void *context,
548 parseX501NameCallback callback, bool localized) {
549 DERSequence rdn;
550 DERReturn drtn = DERDecodeSeqContentInit(rdnSetContent, &rdn);
551 require_noerr_quiet(drtn, badDER);
552 DERDecodedInfo atvContent;
553 CFIndex rdnIX = 0;
554 while ((drtn = DERDecodeSeqNext(&rdn, &atvContent)) == DR_Success) {
555 require_quiet(atvContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
556 DERAttributeTypeAndValue atv;
557 drtn = DERParseSequenceContent(&atvContent.content,
558 DERNumAttributeTypeAndValueItemSpecs,
559 DERAttributeTypeAndValueItemSpecs,
560 &atv, sizeof(atv));
561 require_noerr_quiet(drtn, badDER);
562 require_quiet(atv.type.length != 0, badDER);
563 OSStatus status = callback(context, &atv.type, &atv.value, rdnIX++, localized);
564 if (status) {
565 return status;
566 }
567 }
568 require_quiet(drtn == DR_EndOfSequence, badDER);
569
570 return errSecSuccess;
571 badDER:
572 return errSecInvalidCertificate;
573 }
574
575 static OSStatus parseX501NameContent(const DERItem *x501NameContent, void *context,
576 parseX501NameCallback callback, bool localized) {
577 DERSequence derSeq;
578 DERReturn drtn = DERDecodeSeqContentInit(x501NameContent, &derSeq);
579 require_noerr_quiet(drtn, badDER);
580 DERDecodedInfo currDecoded;
581 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
582 require_quiet(currDecoded.tag == ASN1_CONSTR_SET, badDER);
583 OSStatus status = parseRDNContent(&currDecoded.content, context,
584 callback, localized);
585 if (status) {
586 return status;
587 }
588 }
589 require_quiet(drtn == DR_EndOfSequence, badDER);
590
591 return errSecSuccess;
592
593 badDER:
594 return errSecInvalidCertificate;
595 }
596
597 static OSStatus parseX501Name(const DERItem *x501Name, void *context,
598 parseX501NameCallback callback, bool localized) {
599 DERDecodedInfo x501NameContent;
600 if (DERDecodeItem(x501Name, &x501NameContent) ||
601 x501NameContent.tag != ASN1_CONSTR_SEQUENCE) {
602 return errSecInvalidCertificate;
603 } else {
604 return parseX501NameContent(&x501NameContent.content, context,
605 callback, localized);
606 }
607 }
608
609 /************************************************************************/
610 /********************** Extension Parsing Routines **********************/
611 /************************************************************************/
612
613 static bool SecCEPSubjectKeyIdentifier(SecCertificateRef certificate,
614 const SecCertificateExtension *extn) {
615 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
616 DERDecodedInfo keyIdentifier;
617 DERReturn drtn = DERDecodeItem(&extn->extnValue, &keyIdentifier);
618 require_noerr_quiet(drtn, badDER);
619 require_quiet(keyIdentifier.tag == ASN1_OCTET_STRING, badDER);
620 certificate->_subjectKeyIdentifier = keyIdentifier.content;
621
622 return true;
623 badDER:
624 secwarning("Invalid SubjectKeyIdentifier Extension");
625 return false;
626 }
627
628 static bool SecCEPKeyUsage(SecCertificateRef certificate,
629 const SecCertificateExtension *extn) {
630 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
631 SecKeyUsage keyUsage = extn->critical ? kSecKeyUsageCritical : 0;
632 DERDecodedInfo bitStringContent;
633 DERReturn drtn = DERDecodeItem(&extn->extnValue, &bitStringContent);
634 require_noerr_quiet(drtn, badDER);
635 require_quiet(bitStringContent.tag == ASN1_BIT_STRING, badDER);
636 DERSize len = bitStringContent.content.length - 1;
637 require_quiet(len == 1 || len == 2, badDER);
638 DERByte numUnusedBits = bitStringContent.content.data[0];
639 require_quiet(numUnusedBits < 8, badDER);
640 /* Flip the bits in the bit string so the first bit in the lsb. */
641 uint_fast16_t bits = 8 * len - numUnusedBits;
642 uint_fast16_t value = bitStringContent.content.data[1];
643 uint_fast16_t mask;
644 if (len > 1) {
645 value = (value << 8) + bitStringContent.content.data[2];
646 mask = 0x8000;
647 } else {
648 mask = 0x80;
649 }
650 uint_fast16_t ix;
651 for (ix = 0; ix < bits; ++ix) {
652 if (value & mask) {
653 keyUsage |= 1 << ix;
654 }
655 mask >>= 1;
656 }
657 certificate->_keyUsage = keyUsage;
658 return true;
659 badDER:
660 certificate->_keyUsage = kSecKeyUsageUnspecified;
661 secwarning("Invalid KeyUsage Extension");
662 return false;
663 }
664
665 static bool SecCEPPrivateKeyUsagePeriod(SecCertificateRef certificate,
666 const SecCertificateExtension *extn) {
667 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
668 return true;
669 }
670
671 static bool SecCEPSubjectAltName(SecCertificateRef certificate,
672 const SecCertificateExtension *extn) {
673 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
674 certificate->_subjectAltName = extn;
675 return true;
676 }
677
678 static bool SecCEPIssuerAltName(SecCertificateRef certificate,
679 const SecCertificateExtension *extn) {
680 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
681 return true;
682 }
683
684 static bool SecCEPBasicConstraints(SecCertificateRef certificate,
685 const SecCertificateExtension *extn) {
686 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
687 DERBasicConstraints basicConstraints;
688 require_noerr_quiet(DERParseSequence(&extn->extnValue,
689 DERNumBasicConstraintsItemSpecs, DERBasicConstraintsItemSpecs,
690 &basicConstraints, sizeof(basicConstraints)), badDER);
691 require_noerr_quiet(DERParseBooleanWithDefault(&basicConstraints.cA, false,
692 &certificate->_basicConstraints.isCA), badDER);
693 if (basicConstraints.pathLenConstraint.length != 0) {
694 require_noerr_quiet(DERParseInteger(
695 &basicConstraints.pathLenConstraint,
696 &certificate->_basicConstraints.pathLenConstraint), badDER);
697 certificate->_basicConstraints.pathLenConstraintPresent = true;
698 }
699 certificate->_basicConstraints.present = true;
700 certificate->_basicConstraints.critical = extn->critical;
701 return true;
702 badDER:
703 certificate->_basicConstraints.present = false;
704 secwarning("Invalid BasicConstraints Extension");
705 return false;
706 }
707
708
709 /*
710 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
711 *
712 * NameConstraints ::= SEQUENCE {
713 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
714 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
715 *
716 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
717 *
718 * GeneralSubtree ::= SEQUENCE {
719 * base GeneralName,
720 * minimum [0] BaseDistance DEFAULT 0,
721 * maximum [1] BaseDistance OPTIONAL }
722 *
723 * BaseDistance ::= INTEGER (0..MAX)
724 */
725 static DERReturn parseGeneralSubtrees(DERItem *derSubtrees, CFArrayRef *generalSubtrees) {
726 CFMutableArrayRef gs = NULL;
727 DERSequence gsSeq;
728 DERReturn drtn = DERDecodeSeqContentInit(derSubtrees, &gsSeq);
729 require_noerr_quiet(drtn, badDER);
730 DERDecodedInfo gsContent;
731 require_quiet(gs = CFArrayCreateMutable(kCFAllocatorDefault, 0,
732 &kCFTypeArrayCallBacks),
733 badDER);
734 while ((drtn = DERDecodeSeqNext(&gsSeq, &gsContent)) == DR_Success) {
735 DERGeneralSubtree derGS;
736 require_quiet(gsContent.tag==ASN1_CONSTR_SEQUENCE, badDER);
737 drtn = DERParseSequenceContent(&gsContent.content,
738 DERNumGeneralSubtreeItemSpecs,
739 DERGeneralSubtreeItemSpecs,
740 &derGS, sizeof(derGS));
741 require_noerr_quiet(drtn, badDER);
742 /*
743 * RFC 5280 4.2.1.10
744 * Within this profile, the minimum and maximum fields are not used with
745 * any name forms, thus, the minimum MUST be zero, and maximum MUST be
746 * absent.
747 *
748 * Because minimum DEFAULT 0, absence equivalent to present and 0.
749 */
750 if (derGS.minimum.length) {
751 uint32_t minimum;
752 require_noerr_quiet(DERParseInteger(&derGS.minimum, &minimum),
753 badDER);
754 require_quiet(minimum == 0, badDER);
755 }
756 require_quiet(derGS.maximum.length == 0, badDER);
757 require_quiet(derGS.generalName.length != 0, badDER);
758
759 CFDataRef generalName = NULL;
760 require_quiet(generalName = CFDataCreate(kCFAllocatorDefault,
761 derGS.generalName.data,
762 derGS.generalName.length),
763 badDER);
764 CFArrayAppendValue(gs, generalName);
765 CFReleaseNull(generalName);
766 }
767 require_quiet(drtn == DR_EndOfSequence, badDER);
768
769 // since generalSubtrees is a pointer to an instance variable,
770 // make sure we release the existing array before assignment.
771 CFReleaseSafe(*generalSubtrees);
772 *generalSubtrees = gs;
773
774 return DR_Success;
775
776 badDER:
777 CFReleaseNull(gs);
778 secdebug("cert","failed to parse GeneralSubtrees");
779 return drtn;
780 }
781
782 static bool SecCEPNameConstraints(SecCertificateRef certificate,
783 const SecCertificateExtension *extn) {
784 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
785 DERNameConstraints nc;
786 DERReturn drtn;
787 drtn = DERParseSequence(&extn->extnValue,
788 DERNumNameConstraintsItemSpecs,
789 DERNameConstraintsItemSpecs,
790 &nc, sizeof(nc));
791 require_noerr_quiet(drtn, badDER);
792 if (nc.permittedSubtrees.length) {
793 require_noerr_quiet(parseGeneralSubtrees(&nc.permittedSubtrees, &certificate->_permittedSubtrees), badDER);
794 }
795 if (nc.excludedSubtrees.length) {
796 require_noerr_quiet(parseGeneralSubtrees(&nc.excludedSubtrees, &certificate->_excludedSubtrees), badDER);
797 }
798
799 return true;
800 badDER:
801 secwarning("Invalid Name Constraints extension");
802 return false;
803 }
804
805 static OSStatus appendCRLDPFromGeneralNames(void *context, SecCEGeneralNameType type,
806 const DERItem *value) {
807 CFMutableArrayRef *crlDPs = (CFMutableArrayRef *)context;
808 if (type == GNT_URI) {
809 CFURLRef url = NULL;
810 url = CFURLCreateWithBytes(NULL, value->data, value->length, kCFStringEncodingASCII, NULL);
811 if (url) {
812 if (!*crlDPs) {
813 *crlDPs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
814 }
815 CFArrayAppendValue(*crlDPs, url);
816 CFRelease(url);
817 }
818 }
819 return errSecSuccess;
820 }
821
822 /*
823 id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 }
824
825 CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
826
827 DistributionPoint ::= SEQUENCE {
828 distributionPoint [0] DistributionPointName OPTIONAL,
829 reasons [1] ReasonFlags OPTIONAL,
830 cRLIssuer [2] GeneralNames OPTIONAL }
831
832 DistributionPointName ::= CHOICE {
833 fullName [0] GeneralNames,
834 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
835 */
836 static bool SecCEPCrlDistributionPoints(SecCertificateRef certificate,
837 const SecCertificateExtension *extn) {
838 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
839 DERSequence crlDPSeq;
840 DERTag tag;
841 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &crlDPSeq);
842 require_noerr_quiet(drtn, badDER);
843 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
844 DERDecodedInfo dpContent;
845 while ((drtn = DERDecodeSeqNext(&crlDPSeq, &dpContent)) == DR_Success) {
846 require_quiet(dpContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
847 DERDistributionPoint dp;
848 drtn = DERParseSequenceContent(&dpContent.content, DERNumDistributionPointItemSpecs,
849 DERDistributionPointItemSpecs, &dp, sizeof(dp));
850 require_noerr_quiet(drtn, badDER);
851 require_quiet(dp.distributionPoint.data || dp.cRLIssuer.data, badDER);
852 if (dp.distributionPoint.data) {
853 DERDecodedInfo dpName;
854 drtn = DERDecodeItem(&dp.distributionPoint, &dpName);
855 require_noerr_quiet(drtn, badDER);
856 switch (dpName.tag) {
857 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0:
858 drtn = parseGeneralNamesContent(&dpName.content, &certificate->_crlDistributionPoints,
859 appendCRLDPFromGeneralNames);
860 require_noerr_quiet(drtn, badDER);
861 break;
862 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1:
863 /* RelativeDistinguishName. Nothing we can do with that. */
864 break;
865 default:
866 goto badDER;
867 }
868 }
869 if (dp.cRLIssuer.data) {
870 drtn = SecCertificateParseGeneralNames(&dp.cRLIssuer, &certificate->_crlDistributionPoints,
871 appendCRLDPFromGeneralNames);
872 require_noerr_quiet(drtn, badDER);
873 }
874 }
875 require_quiet(drtn == DR_EndOfSequence, badDER);
876 return true;
877 badDER:
878 secwarning("Invalid CRL Distribution Points extension");
879 return false;
880 }
881
882 /*
883 certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
884
885 PolicyInformation ::= SEQUENCE {
886 policyIdentifier CertPolicyId,
887 policyQualifiers SEQUENCE SIZE (1..MAX) OF
888 PolicyQualifierInfo OPTIONAL }
889
890 CertPolicyId ::= OBJECT IDENTIFIER
891
892 PolicyQualifierInfo ::= SEQUENCE {
893 policyQualifierId PolicyQualifierId,
894 qualifier ANY DEFINED BY policyQualifierId }
895 */
896 /* maximum number of policies of 8192 seems more than adequate */
897 #define MAX_CERTIFICATE_POLICIES 8192
898 static bool SecCEPCertificatePolicies(SecCertificateRef certificate,
899 const SecCertificateExtension *extn) {
900 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
901 DERTag tag;
902 DERSequence piSeq;
903 SecCEPolicyInformation *policies = NULL;
904 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &piSeq);
905 require_noerr_quiet(drtn, badDER);
906 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
907 DERDecodedInfo piContent;
908 DERSize policy_count = 0;
909 while ((policy_count < MAX_CERTIFICATE_POLICIES) &&
910 (drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) {
911 require_quiet(piContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
912 policy_count++;
913 }
914 require_quiet(drtn == DR_EndOfSequence, badDER);
915 require_quiet(policies = (SecCEPolicyInformation *)malloc(sizeof(SecCEPolicyInformation)
916 * (policy_count > 0 ? policy_count : 1)),
917 badDER);
918 drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &piSeq);
919 require_noerr_quiet(drtn, badDER);
920 DERSize policy_ix = 0;
921 while ((policy_ix < (policy_count > 0 ? policy_count : 1)) &&
922 (drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) {
923 DERPolicyInformation pi;
924 drtn = DERParseSequenceContent(&piContent.content,
925 DERNumPolicyInformationItemSpecs,
926 DERPolicyInformationItemSpecs,
927 &pi, sizeof(pi));
928 require_noerr_quiet(drtn, badDER);
929 policies[policy_ix].policyIdentifier = pi.policyIdentifier;
930 policies[policy_ix++].policyQualifiers = pi.policyQualifiers;
931 }
932 certificate->_certificatePolicies.present = true;
933 certificate->_certificatePolicies.critical = extn->critical;
934 certificate->_certificatePolicies.numPolicies = policy_count;
935 certificate->_certificatePolicies.policies = policies;
936 return true;
937 badDER:
938 if (policies)
939 free(policies);
940 certificate->_certificatePolicies.present = false;
941 secwarning("Invalid CertificatePolicies Extension");
942 return false;
943 }
944
945 /*
946 id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 }
947
948 PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
949 issuerDomainPolicy CertPolicyId,
950 subjectDomainPolicy CertPolicyId }
951 */
952 #define MAX_POLICY_MAPPINGS 8192
953 static bool SecCEPPolicyMappings(SecCertificateRef certificate,
954 const SecCertificateExtension *extn) {
955 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
956 DERTag tag;
957 DERSequence pmSeq;
958 SecCEPolicyMapping *mappings = NULL;
959 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &pmSeq);
960 require_noerr_quiet(drtn, badDER);
961 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
962 DERDecodedInfo pmContent;
963 DERSize mapping_count = 0;
964 while ((mapping_count < MAX_POLICY_MAPPINGS) &&
965 (drtn = DERDecodeSeqNext(&pmSeq, &pmContent)) == DR_Success) {
966 require_quiet(pmContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
967 mapping_count++;
968 }
969 require_quiet(drtn == DR_EndOfSequence, badDER);
970 require_quiet(mappings = (SecCEPolicyMapping *)malloc(sizeof(SecCEPolicyMapping)
971 * (mapping_count > 0 ? mapping_count : 1)),
972 badDER);
973 drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &pmSeq);
974 require_noerr_quiet(drtn, badDER);
975 DERSize mapping_ix = 0;
976 while ((mapping_ix < (mapping_count > 0 ? mapping_count : 1)) &&
977 (drtn = DERDecodeSeqNext(&pmSeq, &pmContent)) == DR_Success) {
978 require_quiet(pmContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
979 DERPolicyMapping pm;
980 drtn = DERParseSequenceContent(&pmContent.content,
981 DERNumPolicyMappingItemSpecs,
982 DERPolicyMappingItemSpecs,
983 &pm, sizeof(pm));
984 require_noerr_quiet(drtn, badDER);
985 mappings[mapping_ix].issuerDomainPolicy = pm.issuerDomainPolicy;
986 mappings[mapping_ix++].subjectDomainPolicy = pm.subjectDomainPolicy;
987 }
988 certificate->_policyMappings.present = true;
989 certificate->_policyMappings.critical = extn->critical;
990 certificate->_policyMappings.numMappings = mapping_count;
991 certificate->_policyMappings.mappings = mappings;
992 return true;
993 badDER:
994 if (mappings) {
995 free(mappings);
996 }
997 certificate->_policyMappings.present = false;
998 secwarning("Invalid CertificatePolicies Extension");
999 return false;
1000 }
1001
1002 /*
1003 AuthorityKeyIdentifier ::= SEQUENCE {
1004 keyIdentifier [0] KeyIdentifier OPTIONAL,
1005 authorityCertIssuer [1] GeneralNames OPTIONAL,
1006 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
1007 -- authorityCertIssuer and authorityCertSerialNumber MUST both
1008 -- be present or both be absent
1009
1010 KeyIdentifier ::= OCTET STRING
1011 */
1012 static bool SecCEPAuthorityKeyIdentifier(SecCertificateRef certificate,
1013 const SecCertificateExtension *extn) {
1014 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
1015 DERAuthorityKeyIdentifier akid;
1016 DERReturn drtn;
1017 drtn = DERParseSequence(&extn->extnValue,
1018 DERNumAuthorityKeyIdentifierItemSpecs,
1019 DERAuthorityKeyIdentifierItemSpecs,
1020 &akid, sizeof(akid));
1021 require_noerr_quiet(drtn, badDER);
1022 if (akid.keyIdentifier.length) {
1023 certificate->_authorityKeyIdentifier = akid.keyIdentifier;
1024 }
1025 if (akid.authorityCertIssuer.length ||
1026 akid.authorityCertSerialNumber.length) {
1027 require_quiet(akid.authorityCertIssuer.length &&
1028 akid.authorityCertSerialNumber.length, badDER);
1029 /* Perhaps put in a subsection called Authority Certificate Issuer. */
1030 certificate->_authorityKeyIdentifierIssuer = akid.authorityCertIssuer;
1031 certificate->_authorityKeyIdentifierSerialNumber = akid.authorityCertSerialNumber;
1032 }
1033
1034 return true;
1035 badDER:
1036 secwarning("Invalid AuthorityKeyIdentifier Extension");
1037 return false;
1038 }
1039
1040 static bool SecCEPPolicyConstraints(SecCertificateRef certificate,
1041 const SecCertificateExtension *extn) {
1042 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
1043 DERPolicyConstraints pc;
1044 DERReturn drtn;
1045 drtn = DERParseSequence(&extn->extnValue,
1046 DERNumPolicyConstraintsItemSpecs,
1047 DERPolicyConstraintsItemSpecs,
1048 &pc, sizeof(pc));
1049 require_noerr_quiet(drtn, badDER);
1050 if (pc.requireExplicitPolicy.length) {
1051 require_noerr_quiet(DERParseInteger(
1052 &pc.requireExplicitPolicy,
1053 &certificate->_policyConstraints.requireExplicitPolicy), badDER);
1054 certificate->_policyConstraints.requireExplicitPolicyPresent = true;
1055 }
1056 if (pc.inhibitPolicyMapping.length) {
1057 require_noerr_quiet(DERParseInteger(
1058 &pc.inhibitPolicyMapping,
1059 &certificate->_policyConstraints.inhibitPolicyMapping), badDER);
1060 certificate->_policyConstraints.inhibitPolicyMappingPresent = true;
1061 }
1062
1063 certificate->_policyConstraints.present = true;
1064 certificate->_policyConstraints.critical = extn->critical;
1065
1066 return true;
1067 badDER:
1068 certificate->_policyConstraints.present = false;
1069 secwarning("Invalid PolicyConstraints Extension");
1070 return false;
1071 }
1072
1073 static bool SecCEPExtendedKeyUsage(SecCertificateRef certificate,
1074 const SecCertificateExtension *extn) {
1075 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
1076 return true;
1077 }
1078
1079 /*
1080 InhibitAnyPolicy ::= SkipCerts
1081
1082 SkipCerts ::= INTEGER (0..MAX)
1083 */
1084 static bool SecCEPInhibitAnyPolicy(SecCertificateRef certificate,
1085 const SecCertificateExtension *extn) {
1086 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
1087 DERDecodedInfo iapContent;
1088 require_noerr_quiet(DERDecodeItem(&extn->extnValue, &iapContent), badDER);
1089 require_quiet(iapContent.tag == ASN1_INTEGER, badDER);
1090 require_noerr_quiet(DERParseInteger(
1091 &iapContent.content,
1092 &certificate->_inhibitAnyPolicySkipCerts.skipCerts), badDER);
1093
1094 certificate->_inhibitAnyPolicySkipCerts.present = true;
1095 certificate->_inhibitAnyPolicySkipCerts.critical = extn->critical;
1096 return true;
1097 badDER:
1098 certificate->_inhibitAnyPolicySkipCerts.present = false;
1099 secwarning("Invalid InhibitAnyPolicy Extension");
1100 return false;
1101 }
1102
1103 /*
1104 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
1105
1106 AuthorityInfoAccessSyntax ::=
1107 SEQUENCE SIZE (1..MAX) OF AccessDescription
1108
1109 AccessDescription ::= SEQUENCE {
1110 accessMethod OBJECT IDENTIFIER,
1111 accessLocation GeneralName }
1112
1113 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
1114
1115 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
1116
1117 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
1118 */
1119 static bool SecCEPAuthorityInfoAccess(SecCertificateRef certificate,
1120 const SecCertificateExtension *extn) {
1121 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
1122 DERTag tag;
1123 DERSequence adSeq;
1124 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &adSeq);
1125 require_noerr_quiet(drtn, badDER);
1126 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
1127 DERDecodedInfo adContent;
1128 while ((drtn = DERDecodeSeqNext(&adSeq, &adContent)) == DR_Success) {
1129 require_quiet(adContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
1130 DERAccessDescription ad;
1131 drtn = DERParseSequenceContent(&adContent.content,
1132 DERNumAccessDescriptionItemSpecs,
1133 DERAccessDescriptionItemSpecs,
1134 &ad, sizeof(ad));
1135 require_noerr_quiet(drtn, badDER);
1136 CFMutableArrayRef *urls;
1137 if (DEROidCompare(&ad.accessMethod, &oidAdOCSP))
1138 urls = &certificate->_ocspResponders;
1139 else if (DEROidCompare(&ad.accessMethod, &oidAdCAIssuer))
1140 urls = &certificate->_caIssuers;
1141 else
1142 continue;
1143
1144 DERDecodedInfo generalNameContent;
1145 drtn = DERDecodeItem(&ad.accessLocation, &generalNameContent);
1146 require_noerr_quiet(drtn, badDER);
1147 switch (generalNameContent.tag) {
1148 #if 0
1149 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6:
1150 /* Technically I don't think this is valid, but there are certs out
1151 in the wild that use a constructed IA5String. In particular the
1152 VeriSign Time Stamping Authority CA.cer does this. */
1153 #endif
1154 case ASN1_CONTEXT_SPECIFIC | 6:
1155 {
1156 CFURLRef url = CFURLCreateWithBytes(kCFAllocatorDefault,
1157 generalNameContent.content.data, generalNameContent.content.length,
1158 kCFStringEncodingASCII, NULL);
1159 if (url) {
1160 if (!*urls)
1161 *urls = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1162 CFArrayAppendValue(*urls, url);
1163 CFRelease(url);
1164 }
1165 break;
1166 }
1167 default:
1168 secdebug("cert", "bad general name for id-ad-ocsp AccessDescription t: 0x%02llx v: %.*s",
1169 generalNameContent.tag, (int) generalNameContent.content.length, generalNameContent.content.data);
1170 goto badDER;
1171 break;
1172 }
1173 }
1174 require_quiet(drtn == DR_EndOfSequence, badDER);
1175 return true;
1176 badDER:
1177 secwarning("Invalid Authority Information Access extension");
1178 return false;
1179 }
1180
1181 /* Apple Worldwide Developer Relations Certificate Authority subject name.
1182 * This is a DER sequence with the leading tag and length bytes removed,
1183 * to match what tbsCert.issuer contains.
1184 */
1185 static const unsigned char Apple_WWDR_CA_Subject_Name[]={
1186 0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
1187 0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
1188 0x20,0x49,0x6E,0x63,0x2E,0x31,0x2C,0x30,0x2A,0x06,0x03,0x55,0x04,0x0B,0x0C,0x23,
1189 0x41,0x70,0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20,
1190 0x44,0x65,0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,
1191 0x6F,0x6E,0x73,0x31,0x44,0x30,0x42,0x06,0x03,0x55,0x04,0x03,0x0C,0x3B,0x41,0x70,
1192 0x70,0x6C,0x65,0x20,0x57,0x6F,0x72,0x6C,0x64,0x77,0x69,0x64,0x65,0x20,0x44,0x65,
1193 0x76,0x65,0x6C,0x6F,0x70,0x65,0x72,0x20,0x52,0x65,0x6C,0x61,0x74,0x69,0x6F,0x6E,
1194 0x73,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,
1195 0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79
1196 };
1197
1198 static void checkForMissingRevocationInfo(SecCertificateRef certificate) {
1199 if (!certificate ||
1200 certificate->_crlDistributionPoints ||
1201 certificate->_ocspResponders) {
1202 /* We already have an OCSP or CRL URI (or no cert) */
1203 return;
1204 }
1205 /* Specify an appropriate OCSP responder if we recognize the issuer. */
1206 CFURLRef url = NULL;
1207 if (sizeof(Apple_WWDR_CA_Subject_Name) == certificate->_issuer.length &&
1208 !memcmp(certificate->_issuer.data, Apple_WWDR_CA_Subject_Name,
1209 sizeof(Apple_WWDR_CA_Subject_Name))) {
1210 const char *WWDR_OCSP_URI = "http://ocsp.apple.com/ocsp-wwdr01";
1211 url = CFURLCreateWithBytes(kCFAllocatorDefault,
1212 (const UInt8*)WWDR_OCSP_URI, strlen(WWDR_OCSP_URI),
1213 kCFStringEncodingASCII, NULL);
1214 }
1215 if (url) {
1216 CFMutableArrayRef *urls = &certificate->_ocspResponders;
1217 *urls = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1218 CFArrayAppendValue(*urls, url);
1219 CFRelease(url);
1220 }
1221 }
1222
1223 static bool SecCEPSubjectInfoAccess(SecCertificateRef certificate,
1224 const SecCertificateExtension *extn) {
1225 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
1226 return true;
1227 }
1228
1229 static bool SecCEPNetscapeCertType(SecCertificateRef certificate,
1230 const SecCertificateExtension *extn) {
1231 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
1232 return true;
1233 }
1234
1235 static bool SecCEPEntrustVersInfo(SecCertificateRef certificate,
1236 const SecCertificateExtension *extn) {
1237 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
1238 return true;
1239 }
1240
1241 static bool SecCEPEscrowMarker(SecCertificateRef certificate,
1242 const SecCertificateExtension *extn) {
1243 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
1244 return true;
1245 }
1246
1247 static bool SecCEPOCSPNoCheck(SecCertificateRef certificate,
1248 const SecCertificateExtension *extn) {
1249 secdebug("cert", "ocsp-nocheck critical: %s", extn->critical ? "yes" : "no");
1250 return true;
1251 }
1252
1253 /* Dictionary key callback for comparing to DERItems. */
1254 static Boolean SecDERItemEqual(const void *value1, const void *value2) {
1255 return DEROidCompare((const DERItem *)value1, (const DERItem *)value2);
1256 }
1257
1258 /* Dictionary key callback calculating the hash of a DERItem. */
1259 static CFHashCode SecDERItemHash(const void *value) {
1260 const DERItem *derItem = (const DERItem *)value;
1261 CFHashCode hash = derItem->length;
1262 DERSize ix = derItem->length > 8 ? derItem->length - 8 : 0;
1263 for (; ix < derItem->length; ++ix) {
1264 hash = (hash << 9) + (hash >> 23) + derItem->data[ix];
1265 }
1266
1267 return hash;
1268 }
1269
1270 /* Dictionary key callbacks using the above 2 functions. */
1271 static const CFDictionaryKeyCallBacks SecDERItemKeyCallBacks = {
1272 0, /* version */
1273 NULL, /* retain */
1274 NULL, /* release */
1275 NULL, /* copyDescription */
1276 SecDERItemEqual, /* equal */
1277 SecDERItemHash /* hash */
1278 };
1279
1280 static void SecCertificateInitializeExtensionParsers(void) {
1281 /* Build a dictionary that maps from extension OIDs to callback functions
1282 which can parse the extension of the type given. */
1283 static const void *extnOIDs[] = {
1284 &oidSubjectKeyIdentifier,
1285 &oidKeyUsage,
1286 &oidPrivateKeyUsagePeriod,
1287 &oidSubjectAltName,
1288 &oidIssuerAltName,
1289 &oidBasicConstraints,
1290 &oidNameConstraints,
1291 &oidCrlDistributionPoints,
1292 &oidCertificatePolicies,
1293 &oidPolicyMappings,
1294 &oidAuthorityKeyIdentifier,
1295 &oidPolicyConstraints,
1296 &oidExtendedKeyUsage,
1297 &oidInhibitAnyPolicy,
1298 &oidAuthorityInfoAccess,
1299 &oidSubjectInfoAccess,
1300 &oidNetscapeCertType,
1301 &oidEntrustVersInfo,
1302 &oidApplePolicyEscrowService,
1303 &oidOCSPNoCheck,
1304 };
1305 static const void *extnParsers[] = {
1306 SecCEPSubjectKeyIdentifier,
1307 SecCEPKeyUsage,
1308 SecCEPPrivateKeyUsagePeriod,
1309 SecCEPSubjectAltName,
1310 SecCEPIssuerAltName,
1311 SecCEPBasicConstraints,
1312 SecCEPNameConstraints,
1313 SecCEPCrlDistributionPoints,
1314 SecCEPCertificatePolicies,
1315 SecCEPPolicyMappings,
1316 SecCEPAuthorityKeyIdentifier,
1317 SecCEPPolicyConstraints,
1318 SecCEPExtendedKeyUsage,
1319 SecCEPInhibitAnyPolicy,
1320 SecCEPAuthorityInfoAccess,
1321 SecCEPSubjectInfoAccess,
1322 SecCEPNetscapeCertType,
1323 SecCEPEntrustVersInfo,
1324 SecCEPEscrowMarker,
1325 SecCEPOCSPNoCheck,
1326 };
1327 sExtensionParsers = CFDictionaryCreate(kCFAllocatorDefault, extnOIDs,
1328 extnParsers, array_size(extnOIDs),
1329 &SecDERItemKeyCallBacks, NULL);
1330 }
1331
1332 CFGiblisWithFunctions(SecCertificate, NULL, NULL, SecCertificateDestroy, SecCertificateEqual, SecCertificateHash, NULL, SecCertificateCopyDescription, NULL, NULL, ^{
1333 SecCertificateInitializeExtensionParsers();
1334 })
1335
1336 static bool isAppleExtensionOID(const DERItem *extnID)
1337 {
1338 static const uint8_t appleExtension[8] = { 0x2a,0x86,0x48,0x86,0xf7,0x63,0x64,0x06 };
1339 return (extnID && extnID->data &&
1340 extnID->length > sizeof(appleExtension) &&
1341 !memcmp(extnID->data, appleExtension, sizeof(appleExtension)));
1342 }
1343
1344 /* Given the contents of an X.501 Name return the contents of a normalized
1345 X.501 name. */
1346 CFDataRef createNormalizedX501Name(CFAllocatorRef allocator,
1347 const DERItem *x501name) {
1348 CFMutableDataRef result = CFDataCreateMutable(allocator, x501name->length);
1349 CFIndex length = x501name->length;
1350 CFDataSetLength(result, length);
1351 UInt8 *base = CFDataGetMutableBytePtr(result);
1352
1353 DERSequence rdnSeq;
1354 DERReturn drtn = DERDecodeSeqContentInit(x501name, &rdnSeq);
1355
1356 require_noerr_quiet(drtn, badDER);
1357 DERDecodedInfo rdn;
1358
1359 /* Always points to last rdn tag. */
1360 const DERByte *rdnTag = rdnSeq.nextItem;
1361 /* Offset relative to base of current rdn set tag. */
1362 CFIndex rdnTagLocation = 0;
1363 while ((drtn = DERDecodeSeqNext(&rdnSeq, &rdn)) == DR_Success) {
1364 require_quiet(rdn.tag == ASN1_CONSTR_SET, badDER);
1365 /* We don't allow empty RDNs. */
1366 require_quiet(rdn.content.length != 0, badDER);
1367 /* Length of the tag and length of the current rdn. */
1368 CFIndex rdnTLLength = rdn.content.data - rdnTag;
1369 CFIndex rdnContentLength = rdn.content.length;
1370 /* Copy the tag and length of the RDN. */
1371 memcpy(base + rdnTagLocation, rdnTag, rdnTLLength);
1372
1373 DERSequence atvSeq;
1374 drtn = DERDecodeSeqContentInit(&rdn.content, &atvSeq);
1375 require_quiet(drtn == DR_Success, badDER);
1376
1377 DERDecodedInfo atv;
1378 /* Always points to tag of current atv sequence. */
1379 const DERByte *atvTag = atvSeq.nextItem;
1380 /* Offset relative to base of current atv sequence tag. */
1381 CFIndex atvTagLocation = rdnTagLocation + rdnTLLength;
1382 while ((drtn = DERDecodeSeqNext(&atvSeq, &atv)) == DR_Success) {
1383 require_quiet(atv.tag == ASN1_CONSTR_SEQUENCE, badDER);
1384 /* Length of the tag and length of the current atv. */
1385 CFIndex atvTLLength = atv.content.data - atvTag;
1386 CFIndex atvContentLength = atv.content.length;
1387 /* Copy the tag and length of the atv and the atv itself. */
1388 memcpy(base + atvTagLocation, atvTag,
1389 atvTLLength + atv.content.length);
1390
1391 /* Now decode the atv sequence. */
1392 DERAttributeTypeAndValue atvPair;
1393 drtn = DERParseSequenceContent(&atv.content,
1394 DERNumAttributeTypeAndValueItemSpecs,
1395 DERAttributeTypeAndValueItemSpecs,
1396 &atvPair, sizeof(atvPair));
1397 require_noerr_quiet(drtn, badDER);
1398 require_quiet(atvPair.type.length != 0, badDER);
1399 DERDecodedInfo value;
1400 drtn = DERDecodeItem(&atvPair.value, &value);
1401 require_noerr_quiet(drtn, badDER);
1402
1403 /* (c) attribute values in PrintableString are not case sensitive
1404 (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and
1405
1406 (d) attribute values in PrintableString are compared after
1407 removing leading and trailing white space and converting internal
1408 substrings of one or more consecutive white space characters to a
1409 single space. */
1410 if (value.tag == ASN1_PRINTABLE_STRING) {
1411 /* Offset relative to base of current value tag. */
1412 CFIndex valueTagLocation = atvTagLocation + atvPair.value.data - atvTag;
1413 CFIndex valueTLLength = value.content.data - atvPair.value.data;
1414 CFIndex valueContentLength = value.content.length;
1415
1416 /* Now copy all the bytes, but convert to upper case while
1417 doing so and convert multiple whitespace chars into a
1418 single space. */
1419 bool lastWasBlank = false;
1420 CFIndex valueLocation = valueTagLocation + valueTLLength;
1421 CFIndex valueCurrentLocation = valueLocation;
1422 CFIndex ix;
1423 for (ix = 0; ix < valueContentLength; ++ix) {
1424 UInt8 ch = value.content.data[ix];
1425 if (isblank(ch)) {
1426 if (lastWasBlank) {
1427 continue;
1428 } else {
1429 /* Don't insert a space for first character
1430 we encounter. */
1431 if (valueCurrentLocation > valueLocation) {
1432 base[valueCurrentLocation++] = ' ';
1433 }
1434 lastWasBlank = true;
1435 }
1436 } else {
1437 lastWasBlank = false;
1438 if ('a' <= ch && ch <= 'z') {
1439 base[valueCurrentLocation++] = ch + 'A' - 'a';
1440 } else {
1441 base[valueCurrentLocation++] = ch;
1442 }
1443 }
1444 }
1445 /* Finally if lastWasBlank remove the trailing space. */
1446 if (lastWasBlank && valueCurrentLocation > valueLocation) {
1447 valueCurrentLocation--;
1448 }
1449 /* Adjust content length to normalized length. */
1450 valueContentLength = valueCurrentLocation - valueLocation;
1451
1452 /* Number of bytes by which the length should be shorted. */
1453 CFIndex lengthDiff = value.content.length - valueContentLength;
1454 if (lengthDiff == 0) {
1455 /* Easy case no need to adjust lengths. */
1456 } else {
1457 /* Hard work we need to go back and fix up length fields
1458 for:
1459 1) The value itself.
1460 2) The ATV Sequence containing type/value
1461 3) The RDN Set containing one or more atv pairs.
1462 4) The result.
1463 */
1464
1465 /* Step 1 fix up length of value. */
1466 /* Length of value tag and length minus the tag. */
1467 DERSize newValueTLLength = valueTLLength - 1;
1468 drtn = DEREncodeLength(valueContentLength,
1469 base + valueTagLocation + 1, &newValueTLLength);
1470 require(drtn == DR_Success, badDER);
1471 /* Add the length of the tag back in. */
1472 newValueTLLength++;
1473 CFIndex valueLLDiff = valueTLLength - newValueTLLength;
1474 if (valueLLDiff) {
1475 /* The size of the length field changed, let's slide
1476 the value back by valueLLDiff bytes. */
1477 memmove(base + valueTagLocation + newValueTLLength,
1478 base + valueTagLocation + valueTLLength,
1479 valueContentLength);
1480 /* The length diff for the enclosing object. */
1481 lengthDiff += valueLLDiff;
1482 }
1483
1484 /* Step 2 fix up length of the enclosing ATV Sequence. */
1485 atvContentLength -= lengthDiff;
1486 DERSize newATVTLLength = atvTLLength - 1;
1487 drtn = DEREncodeLength(atvContentLength,
1488 base + atvTagLocation + 1, &newATVTLLength);
1489 require(drtn == DR_Success, badDER);
1490 /* Add the length of the tag back in. */
1491 newATVTLLength++;
1492 CFIndex atvLLDiff = atvTLLength - newATVTLLength;
1493 if (atvLLDiff) {
1494 /* The size of the length field changed, let's slide
1495 the value back by valueLLDiff bytes. */
1496 memmove(base + atvTagLocation + newATVTLLength,
1497 base + atvTagLocation + atvTLLength,
1498 atvContentLength);
1499 /* The length diff for the enclosing object. */
1500 lengthDiff += atvLLDiff;
1501 atvTLLength = newATVTLLength;
1502 }
1503
1504 /* Step 3 fix up length of enclosing RDN Set. */
1505 rdnContentLength -= lengthDiff;
1506 DERSize newRDNTLLength = rdnTLLength - 1;
1507 drtn = DEREncodeLength(rdnContentLength,
1508 base + rdnTagLocation + 1, &newRDNTLLength);
1509 require_quiet(drtn == DR_Success, badDER);
1510 /* Add the length of the tag back in. */
1511 newRDNTLLength++;
1512 CFIndex rdnLLDiff = rdnTLLength - newRDNTLLength;
1513 if (rdnLLDiff) {
1514 /* The size of the length field changed, let's slide
1515 the value back by valueLLDiff bytes. */
1516 memmove(base + rdnTagLocation + newRDNTLLength,
1517 base + rdnTagLocation + rdnTLLength,
1518 rdnContentLength);
1519 /* The length diff for the enclosing object. */
1520 lengthDiff += rdnLLDiff;
1521 rdnTLLength = newRDNTLLength;
1522
1523 /* Adjust the locations that might have changed due to
1524 this slide. */
1525 atvTagLocation -= rdnLLDiff;
1526 }
1527 (void) lengthDiff; // No next object, silence analyzer
1528 }
1529 }
1530 atvTagLocation += atvTLLength + atvContentLength;
1531 atvTag = atvSeq.nextItem;
1532 }
1533 require_quiet(drtn == DR_EndOfSequence, badDER);
1534 rdnTagLocation += rdnTLLength + rdnContentLength;
1535 rdnTag = rdnSeq.nextItem;
1536 }
1537 require_quiet(drtn == DR_EndOfSequence, badDER);
1538 /* Truncate the result to the proper length. */
1539 CFDataSetLength(result, rdnTagLocation);
1540
1541 return result;
1542
1543 badDER:
1544 CFRelease(result);
1545 return NULL;
1546 }
1547
1548 static CFDataRef SecDERItemCopySequence(DERItem *content) {
1549 DERSize seq_len_length = DERLengthOfLength(content->length);
1550 size_t sequence_length = 1 + seq_len_length + content->length;
1551 CFMutableDataRef sequence = CFDataCreateMutable(kCFAllocatorDefault,
1552 sequence_length);
1553 CFDataSetLength(sequence, sequence_length);
1554 uint8_t *sequence_ptr = CFDataGetMutableBytePtr(sequence);
1555 *sequence_ptr++ = ONE_BYTE_ASN1_CONSTR_SEQUENCE;
1556 require_noerr_quiet(DEREncodeLength(content->length,
1557 sequence_ptr, &seq_len_length), out);
1558 sequence_ptr += seq_len_length;
1559 memcpy(sequence_ptr, content->data, content->length);
1560 return sequence;
1561 out:
1562 CFReleaseSafe(sequence);
1563 return NULL;
1564 }
1565
1566 static CFDataRef SecCopySequenceFromContent(CFDataRef content) {
1567 DERItem tmpItem;
1568 tmpItem.data = (void *)CFDataGetBytePtr(content);
1569 tmpItem.length = CFDataGetLength(content);
1570
1571 return SecDERItemCopySequence(&tmpItem);
1572 }
1573
1574 CFDataRef SecDistinguishedNameCopyNormalizedContent(CFDataRef distinguished_name)
1575 {
1576 const DERItem name = { (unsigned char *)CFDataGetBytePtr(distinguished_name), CFDataGetLength(distinguished_name) };
1577 DERDecodedInfo content;
1578 /* Decode top level sequence into DERItem */
1579 if (!DERDecodeItem(&name, &content) && (content.tag == ASN1_CONSTR_SEQUENCE))
1580 return createNormalizedX501Name(kCFAllocatorDefault, &content.content);
1581 return NULL;
1582 }
1583
1584 CFDataRef SecDistinguishedNameCopyNormalizedSequence(CFDataRef distinguished_name)
1585 {
1586 if (!distinguished_name) { return NULL; }
1587 CFDataRef normalizedContent = SecDistinguishedNameCopyNormalizedContent(distinguished_name);
1588 if (!normalizedContent) { return NULL; }
1589 CFDataRef result = SecCopySequenceFromContent(normalizedContent);
1590 CFReleaseNull(normalizedContent);
1591 return result;
1592 }
1593
1594 /* AUDIT[securityd]:
1595 certificate->_der is a caller provided data of any length (might be 0).
1596
1597 Top level certificate decode.
1598 */
1599 static bool SecCertificateParse(SecCertificateRef certificate)
1600 {
1601 DERReturn drtn;
1602
1603 check(certificate);
1604 require_quiet(certificate, badCert);
1605 CFAllocatorRef allocator = CFGetAllocator(certificate);
1606
1607 /* top level decode */
1608 DERSignedCertCrl signedCert;
1609 drtn = DERParseSequence(&certificate->_der, DERNumSignedCertCrlItemSpecs,
1610 DERSignedCertCrlItemSpecs, &signedCert,
1611 sizeof(signedCert));
1612 require_noerr_quiet(drtn, badCert);
1613 /* Store tbs since we need to digest it for verification later on. */
1614 certificate->_tbs = signedCert.tbs;
1615
1616 /* decode the TBSCert - it was saved in full DER form */
1617 DERTBSCert tbsCert;
1618 drtn = DERParseSequence(&signedCert.tbs,
1619 DERNumTBSCertItemSpecs, DERTBSCertItemSpecs,
1620 &tbsCert, sizeof(tbsCert));
1621 require_noerr_quiet(drtn, badCert);
1622
1623 /* sequence we're given: decode the signedCerts Signature Algorithm. */
1624 /* This MUST be the same as the certificate->_tbsSigAlg with the exception
1625 of the params field. */
1626 drtn = DERParseSequenceContent(&signedCert.sigAlg,
1627 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs,
1628 &certificate->_sigAlg, sizeof(certificate->_sigAlg));
1629 require_noerr_quiet(drtn, badCert);
1630
1631 /* The contents of signedCert.sig is a bit string whose contents
1632 are the signature itself. */
1633 DERByte numUnusedBits;
1634 drtn = DERParseBitString(&signedCert.sig,
1635 &certificate->_signature, &numUnusedBits);
1636 require_noerr_quiet(drtn, badCert);
1637
1638 /* Now decode the tbsCert. */
1639
1640 /* First we turn the optional version into an int. */
1641 if (tbsCert.version.length) {
1642 DERDecodedInfo decoded;
1643 drtn = DERDecodeItem(&tbsCert.version, &decoded);
1644 require_noerr_quiet(drtn, badCert);
1645 require_quiet(decoded.tag == ASN1_INTEGER, badCert);
1646 require_quiet(decoded.content.length == 1, badCert);
1647 certificate->_version = decoded.content.data[0];
1648 if (certificate->_version > 2) {
1649 secwarning("Invalid certificate version (%d), must be 0..2",
1650 certificate->_version);
1651 }
1652 require_quiet(certificate->_version > 0, badCert);
1653 require_quiet(certificate->_version < 3, badCert);
1654 } else {
1655 certificate->_version = 0;
1656 }
1657
1658 /* The serial number is in the tbsCert.serialNum - it was saved in
1659 INTEGER form without the tag and length. */
1660 certificate->_serialNum = tbsCert.serialNum;
1661
1662 /* Note: RFC5280 4.1.2.2 limits serial number values to 20 octets.
1663 For now, we warn about larger values, but will still create the
1664 certificate with values up to 36 octets to avoid breaking some
1665 nonconforming certs with slightly longer serial numbers.
1666 We also explicitly allow serial numbers of 21 octets where the
1667 leading byte is 0x00 which is used to make a negative 20 octet
1668 value positive.
1669 */
1670 if (tbsCert.serialNum.length < 1 || tbsCert.serialNum.length > 21 ||
1671 (tbsCert.serialNum.length == 21 && tbsCert.serialNum.data[0] != 0x00)) {
1672 secwarning("Invalid serial number length (%ld), must be 1..20",
1673 tbsCert.serialNum.length);
1674 }
1675 require_quiet(tbsCert.serialNum.data != NULL &&
1676 tbsCert.serialNum.length >= 1 &&
1677 tbsCert.serialNum.length <= 37, badCert);
1678 certificate->_serialNumber = CFDataCreate(allocator,
1679 tbsCert.serialNum.data, tbsCert.serialNum.length);
1680
1681 /* sequence we're given: decode the tbsCerts TBS Signature Algorithm. */
1682 drtn = DERParseSequenceContent(&tbsCert.tbsSigAlg,
1683 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs,
1684 &certificate->_tbsSigAlg, sizeof(certificate->_tbsSigAlg));
1685 require_noerr_quiet(drtn, badCert);
1686
1687 /* The issuer is in the tbsCert.issuer - it's a sequence without the tag
1688 and length fields. */
1689 certificate->_issuer = tbsCert.issuer;
1690 certificate->_normalizedIssuer = createNormalizedX501Name(allocator,
1691 &tbsCert.issuer);
1692
1693 /* sequence we're given: decode the tbsCerts Validity sequence. */
1694 DERValidity validity;
1695 drtn = DERParseSequenceContent(&tbsCert.validity,
1696 DERNumValidityItemSpecs, DERValidityItemSpecs,
1697 &validity, sizeof(validity));
1698 require_noerr_quiet(drtn, badCert);
1699 require_quiet(derDateGetAbsoluteTime(&validity.notBefore,
1700 &certificate->_notBefore), badCert);
1701 require_quiet(derDateGetAbsoluteTime(&validity.notAfter,
1702 &certificate->_notAfter), badCert);
1703
1704 /* The subject is in the tbsCert.subject - it's a sequence without the tag
1705 and length fields. */
1706 certificate->_subject = tbsCert.subject;
1707 certificate->_normalizedSubject = createNormalizedX501Name(allocator,
1708 &tbsCert.subject);
1709
1710 /* Keep the SPKI around for CT */
1711 certificate->_subjectPublicKeyInfo = tbsCert.subjectPubKey;
1712
1713 /* sequence we're given: encoded DERSubjPubKeyInfo */
1714 DERSubjPubKeyInfo pubKeyInfo;
1715 drtn = DERParseSequenceContent(&tbsCert.subjectPubKey,
1716 DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs,
1717 &pubKeyInfo, sizeof(pubKeyInfo));
1718 require_noerr_quiet(drtn, badCert);
1719
1720 /* sequence we're given: decode the pubKeyInfos DERAlgorithmId */
1721 drtn = DERParseSequenceContent(&pubKeyInfo.algId,
1722 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs,
1723 &certificate->_algId, sizeof(certificate->_algId));
1724 require_noerr_quiet(drtn, badCert);
1725
1726 /* Now we can figure out the key's algorithm id and params based on
1727 certificate->_algId.oid. */
1728
1729 /* The contents of pubKeyInfo.pubKey is a bit string whose contents
1730 are a PKCS1 format RSA key. */
1731 drtn = DERParseBitString(&pubKeyInfo.pubKey,
1732 &certificate->_pubKeyDER, &numUnusedBits);
1733 require_noerr_quiet(drtn, badCert);
1734
1735 /* The contents of tbsCert.issuerID is a bit string. */
1736 certificate->_issuerUniqueID = tbsCert.issuerID;
1737
1738 /* The contents of tbsCert.subjectID is a bit string. */
1739 certificate->_subjectUniqueID = tbsCert.subjectID;
1740
1741 /* Extensions. */
1742 if (tbsCert.extensions.length) {
1743 CFIndex extensionCount = 0;
1744 DERSequence derSeq;
1745 DERTag tag;
1746 drtn = DERDecodeSeqInit(&tbsCert.extensions, &tag,
1747 &derSeq);
1748 require_noerr_quiet(drtn, badCert);
1749 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badCert);
1750 DERDecodedInfo currDecoded;
1751 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
1752 #if 0
1753 /* ! = MUST recognize ? = SHOULD recognize
1754 */
1755
1756 KnownExtension _subjectKeyID; /* ?SubjectKeyIdentifier id-ce 14 */
1757 KnownExtension _keyUsage; /* !KeyUsage id-ce 15 */
1758 KnownExtension _subjectAltName; /* !SubjectAltName id-ce 17 */
1759 KnownExtension _basicConstraints; /* !BasicConstraints id-ce 19 */
1760 KnownExtension _authorityKeyID; /* ?AuthorityKeyIdentifier id-ce 35 */
1761 KnownExtension _extKeyUsage; /* !ExtKeyUsage id-ce 37 */
1762 KnownExtension _netscapeCertType; /* 2.16.840.1.113730.1.1 netscape 1 1 */
1763 KnownExtension _qualCertStatements; /* QCStatements id-pe 3 */
1764
1765 KnownExtension _issuerAltName; /* IssuerAltName id-ce 18 */
1766 KnownExtension _nameConstraints; /* !NameConstraints id-ce 30 */
1767 KnownExtension _cRLDistributionPoints; /* CRLDistributionPoints id-ce 31 */
1768 KnownExtension _certificatePolicies; /* !CertificatePolicies id-ce 32 */
1769 KnownExtension _policyMappings; /* ?PolicyMappings id-ce 33 */
1770 KnownExtension _policyConstraints; /* !PolicyConstraints id-ce 36 */
1771 KnownExtension _freshestCRL; /* FreshestCRL id-ce 46 */
1772 KnownExtension _inhibitAnyPolicy; /* !InhibitAnyPolicy id-ce 54 */
1773
1774 KnownExtension _authorityInfoAccess; /* AuthorityInfoAccess id-pe 1 */
1775 KnownExtension _subjectInfoAccess; /* SubjectInfoAccess id-pe 11 */
1776 #endif
1777
1778 extensionCount++;
1779 }
1780 require_quiet(drtn == DR_EndOfSequence, badCert);
1781
1782 /* Put some upper limit on the number of extensions allowed. */
1783 require_quiet(extensionCount < 10000, badCert);
1784 certificate->_extensionCount = extensionCount;
1785 certificate->_extensions =
1786 malloc(sizeof(SecCertificateExtension) * (extensionCount > 0 ? extensionCount : 1));
1787 require_quiet(certificate->_extensions, badCert);
1788
1789 CFIndex ix = 0;
1790 drtn = DERDecodeSeqInit(&tbsCert.extensions, &tag, &derSeq);
1791 require_noerr_quiet(drtn, badCert);
1792 for (ix = 0; ix < extensionCount; ++ix) {
1793 drtn = DERDecodeSeqNext(&derSeq, &currDecoded);
1794 require_quiet(drtn == DR_Success ||
1795 (ix == extensionCount - 1 && drtn == DR_EndOfSequence), badCert);
1796 require_quiet(currDecoded.tag == ASN1_CONSTR_SEQUENCE, badCert);
1797 DERExtension extn;
1798 drtn = DERParseSequenceContent(&currDecoded.content,
1799 DERNumExtensionItemSpecs, DERExtensionItemSpecs,
1800 &extn, sizeof(extn));
1801 require_noerr_quiet(drtn, badCert);
1802 /* Copy stuff into certificate->extensions[ix]. */
1803 certificate->_extensions[ix].extnID = extn.extnID;
1804 require_noerr_quiet(drtn = DERParseBooleanWithDefault(&extn.critical, false,
1805 &certificate->_extensions[ix].critical), badCert);
1806 certificate->_extensions[ix].extnValue = extn.extnValue;
1807
1808 SecCertificateExtensionParser parser =
1809 (SecCertificateExtensionParser)CFDictionaryGetValue(
1810 sExtensionParsers, &certificate->_extensions[ix].extnID);
1811 if (parser) {
1812 /* Invoke the parser. If the extension is critical and the
1813 * parser fails, fail the cert. */
1814 require_quiet(parser(certificate, &certificate->_extensions[ix]) ||
1815 !certificate->_extensions[ix].critical, badCert);
1816 } else if (certificate->_extensions[ix].critical) {
1817 if (isAppleExtensionOID(&extn.extnID)) {
1818 continue;
1819 }
1820 secdebug("cert", "Found unknown critical extension");
1821 certificate->_foundUnknownCriticalExtension = true;
1822 } else {
1823 secdebug("cert", "Found unknown non critical extension");
1824 }
1825 }
1826 }
1827 checkForMissingRevocationInfo(certificate);
1828
1829 return true;
1830
1831 badCert:
1832 return false;
1833 }
1834
1835
1836 /* Public API functions. */
1837 SecCertificateRef SecCertificateCreateWithBytes(CFAllocatorRef allocator,
1838 const UInt8 *der_bytes, CFIndex der_length) {
1839 if (der_bytes == NULL) return NULL;
1840 if (der_length == 0) return NULL;
1841
1842 CFIndex size = sizeof(struct __SecCertificate) + der_length;
1843 SecCertificateRef result = (SecCertificateRef)_CFRuntimeCreateInstance(
1844 allocator, SecCertificateGetTypeID(), size - sizeof(CFRuntimeBase), 0);
1845 if (result) {
1846 memset((char*)result + sizeof(result->_base), 0,
1847 sizeof(*result) - sizeof(result->_base));
1848 result->_der.data = ((DERByte *)result + sizeof(*result));
1849 result->_der.length = der_length;
1850 memcpy(result->_der.data, der_bytes, der_length);
1851 if (!SecCertificateParse(result)) {
1852 CFRelease(result);
1853 return NULL;
1854 }
1855 }
1856 return result;
1857 }
1858
1859 /* @@@ Placeholder until <rdar://problem/5701851> iap submits a binary is fixed. */
1860 SecCertificateRef SecCertificateCreate(CFAllocatorRef allocator,
1861 const UInt8 *der_bytes, CFIndex der_length);
1862
1863 SecCertificateRef SecCertificateCreate(CFAllocatorRef allocator,
1864 const UInt8 *der_bytes, CFIndex der_length) {
1865 return SecCertificateCreateWithBytes(allocator, der_bytes, der_length);
1866 }
1867 /* @@@ End of placeholder. */
1868
1869 /* AUDIT[securityd](done):
1870 der_certificate is a caller provided data of any length (might be 0), only
1871 its cf type has been checked.
1872 */
1873 SecCertificateRef SecCertificateCreateWithData(CFAllocatorRef allocator,
1874 CFDataRef der_certificate) {
1875 if (!der_certificate) {
1876 return NULL;
1877 }
1878 CFIndex size = sizeof(struct __SecCertificate);
1879 SecCertificateRef result = (SecCertificateRef)_CFRuntimeCreateInstance(
1880 allocator, SecCertificateGetTypeID(), size - sizeof(CFRuntimeBase), 0);
1881 if (result) {
1882 memset((char*)result + sizeof(result->_base), 0, size - sizeof(result->_base));
1883 result->_der_data = CFDataCreateCopy(allocator, der_certificate);
1884 result->_der.data = (DERByte *)CFDataGetBytePtr(result->_der_data);
1885 result->_der.length = CFDataGetLength(result->_der_data);
1886 if (!SecCertificateParse(result)) {
1887 CFRelease(result);
1888 return NULL;
1889 }
1890 }
1891 return result;
1892 }
1893
1894 SecCertificateRef SecCertificateCreateWithKeychainItem(CFAllocatorRef allocator,
1895 CFDataRef der_certificate,
1896 CFTypeRef keychain_item)
1897 {
1898 SecCertificateRef result = SecCertificateCreateWithData(allocator, der_certificate);
1899 if (result) {
1900 CFRetainSafe(keychain_item);
1901 result->_keychain_item = keychain_item;
1902 }
1903 return result;
1904 }
1905
1906 OSStatus SecCertificateSetKeychainItem(SecCertificateRef certificate,
1907 CFTypeRef keychain_item)
1908 {
1909 if (!certificate) {
1910 return errSecParam;
1911 }
1912 CFRetainSafe(keychain_item);
1913 CFReleaseSafe(certificate->_keychain_item);
1914 certificate->_keychain_item = keychain_item;
1915 return errSecSuccess;
1916 }
1917
1918 CFDataRef SecCertificateCopyData(SecCertificateRef certificate) {
1919 check(certificate);
1920 CFDataRef result = NULL;
1921 if (!certificate) {
1922 return result;
1923 }
1924 if (certificate->_der_data) {
1925 CFRetain(certificate->_der_data);
1926 result = certificate->_der_data;
1927 } else {
1928 result = CFDataCreate(CFGetAllocator(certificate),
1929 certificate->_der.data, certificate->_der.length);
1930 #if 0
1931 /* FIXME: If we wish to cache result we need to lock the certificate.
1932 Also this create 2 copies of the certificate data which is somewhat
1933 suboptimal. */
1934 CFRetain(result);
1935 certificate->_der_data = result;
1936 #endif
1937 }
1938
1939 return result;
1940 }
1941
1942 CFIndex SecCertificateGetLength(SecCertificateRef certificate) {
1943 return certificate->_der.length;
1944 }
1945
1946 const UInt8 *SecCertificateGetBytePtr(SecCertificateRef certificate) {
1947 return certificate->_der.data;
1948 }
1949
1950 /* Used to recreate preCert from cert for Certificate Transparency */
1951 CFDataRef SecCertificateCopyPrecertTBS(SecCertificateRef certificate)
1952 {
1953 CFDataRef outData = NULL;
1954 DERItem tbsIn = certificate->_tbs;
1955 DERItem tbsOut = {0,};
1956 DERItem extensionsOut = {0,};
1957 DERItem *extensionsList = malloc(sizeof(DERItem)*certificate->_extensionCount); /* This maybe one too many */
1958 DERItemSpec *extensionsListSpecs = malloc(sizeof(DERItemSpec)*certificate->_extensionCount);
1959 DERTBSCert tbsCert;
1960 DERReturn drtn;
1961
1962 require_quiet(extensionsList && extensionsListSpecs, out);
1963
1964 /* decode the TBSCert - it was saved in full DER form */
1965 drtn = DERParseSequence(&tbsIn,
1966 DERNumTBSCertItemSpecs, DERTBSCertItemSpecs,
1967 &tbsCert, sizeof(tbsCert));
1968 require_noerr_quiet(drtn, out);
1969
1970 /* Go over extensions and filter any SCT extension */
1971 CFIndex extensionsCount = 0;
1972
1973 if (tbsCert.extensions.length) {
1974 DERSequence derSeq;
1975 DERTag tag;
1976 drtn = DERDecodeSeqInit(&tbsCert.extensions, &tag,
1977 &derSeq);
1978 require_noerr_quiet(drtn, out);
1979 require_quiet(tag == ASN1_CONSTR_SEQUENCE, out);
1980 DERDecodedInfo currDecoded;
1981 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
1982
1983 require_quiet(currDecoded.tag == ASN1_CONSTR_SEQUENCE, out);
1984 DERExtension extn;
1985 drtn = DERParseSequenceContent(&currDecoded.content,
1986 DERNumExtensionItemSpecs, DERExtensionItemSpecs,
1987 &extn, sizeof(extn));
1988 require_noerr_quiet(drtn, out);
1989
1990 if (extn.extnID.length == oidGoogleEmbeddedSignedCertificateTimestamp.length &&
1991 !memcmp(extn.extnID.data, oidGoogleEmbeddedSignedCertificateTimestamp.data, extn.extnID.length))
1992 continue;
1993
1994 extensionsList[extensionsCount] = currDecoded.content;
1995 extensionsListSpecs[extensionsCount].offset = sizeof(DERItem)*extensionsCount;
1996 extensionsListSpecs[extensionsCount].options = 0;
1997 extensionsListSpecs[extensionsCount].tag = ASN1_CONSTR_SEQUENCE;
1998
1999 extensionsCount++;
2000 }
2001
2002 require_quiet(drtn == DR_EndOfSequence, out);
2003
2004 }
2005
2006 /* Encode extensions */
2007 extensionsOut.length = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, extensionsList, extensionsCount, extensionsListSpecs);
2008 extensionsOut.data = malloc(extensionsOut.length);
2009 require_quiet(extensionsOut.data, out);
2010 drtn = DEREncodeSequence(ASN1_CONSTR_SEQUENCE, extensionsList, extensionsCount, extensionsListSpecs, extensionsOut.data, &extensionsOut.length);
2011 require_noerr_quiet(drtn, out);
2012
2013 tbsCert.extensions = extensionsOut;
2014
2015 tbsOut.length = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &tbsCert, DERNumTBSCertItemSpecs, DERTBSCertItemSpecs);
2016 tbsOut.data = malloc(tbsOut.length);
2017 require_quiet(tbsOut.data, out);
2018 drtn = DEREncodeSequence(ASN1_CONSTR_SEQUENCE, &tbsCert, DERNumTBSCertItemSpecs, DERTBSCertItemSpecs, tbsOut.data, &tbsOut.length);
2019 require_noerr_quiet(drtn, out);
2020
2021 outData = CFDataCreate(kCFAllocatorDefault, tbsOut.data, tbsOut.length);
2022
2023 out:
2024 if (extensionsOut.data) free(extensionsOut.data);
2025 if (tbsOut.data) free(tbsOut.data);
2026 if (extensionsList) free(extensionsList);
2027 if (extensionsListSpecs) free(extensionsListSpecs);
2028 return outData;
2029
2030 }
2031
2032 /* From rfc3280 - Appendix B. ASN.1 Notes
2033
2034 Object Identifiers (OIDs) are used throughout this specification to
2035 identify certificate policies, public key and signature algorithms,
2036 certificate extensions, etc. There is no maximum size for OIDs.
2037 This specification mandates support for OIDs which have arc elements
2038 with values that are less than 2^28, that is, they MUST be between 0
2039 and 268,435,455, inclusive. This allows each arc element to be
2040 represented within a single 32 bit word. Implementations MUST also
2041 support OIDs where the length of the dotted decimal (see [RFC 2252],
2042 section 4.1) string representation can be up to 100 bytes
2043 (inclusive). Implementations MUST be able to handle OIDs with up to
2044 20 elements (inclusive). CAs SHOULD NOT issue certificates which
2045 contain OIDs that exceed these requirements. Likewise, CRL issuers
2046 SHOULD NOT issue CRLs which contain OIDs that exceed these
2047 requirements.
2048 */
2049
2050 /* Oids longer than this are considered invalid. */
2051 #define MAX_OID_SIZE 32
2052
2053 CFStringRef SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator,
2054 const DERItem *oid) {
2055
2056 if (oid->length == 0) {
2057 return SecCopyCertString(SEC_NULL_KEY);
2058 }
2059 if (oid->length > MAX_OID_SIZE) {
2060 return SecCopyCertString(SEC_OID_TOO_LONG_KEY);
2061 }
2062
2063 CFMutableStringRef result = CFStringCreateMutable(allocator, 0);
2064
2065 // The first two levels are encoded into one byte, since the root level
2066 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then
2067 // y may be > 39, so we have to add special-case handling for this.
2068 uint32_t x = oid->data[0] / 40;
2069 uint32_t y = oid->data[0] % 40;
2070 if (x > 2)
2071 {
2072 // Handle special case for large y if x = 2
2073 y += (x - 2) * 40;
2074 x = 2;
2075 }
2076 CFStringAppendFormat(result, NULL, CFSTR("%u.%u"), x, y);
2077
2078 uint32_t value = 0;
2079 for (x = 1; x < oid->length; ++x)
2080 {
2081 value = (value << 7) | (oid->data[x] & 0x7F);
2082 /* @@@ value may not span more than 4 bytes. */
2083 /* A max number of 20 values is allowed. */
2084 if (!(oid->data[x] & 0x80))
2085 {
2086 CFStringAppendFormat(result, NULL, CFSTR(".%" PRIu32), value);
2087 value = 0;
2088 }
2089 }
2090 return result;
2091 }
2092
2093 static CFStringRef copyOidDescription(CFAllocatorRef allocator,
2094 const DERItem *oid, bool localized) {
2095 if (!oid || oid->length == 0) {
2096 return (localized) ? SecCopyCertString(SEC_NULL_KEY) : SEC_NULL_KEY;
2097 }
2098
2099 CFStringRef name = SecDERItemCopyOIDDecimalRepresentation(allocator, oid);
2100 if (!localized) {
2101 return name;
2102 }
2103
2104 /* Build the key we use to lookup the localized OID description. */
2105 CFMutableStringRef oidKey = CFStringCreateMutable(allocator,
2106 oid->length * 3 + 5);
2107 CFStringAppendFormat(oidKey, NULL, CFSTR("06 %02lX"), oid->length);
2108 for (DERSize ix = 0; ix < oid->length; ++ix) {
2109 CFStringAppendFormat(oidKey, NULL, CFSTR(" %02X"), oid->data[ix]);
2110 }
2111 CFStringRef locname = SecFrameworkCopyLocalizedString(oidKey, CFSTR("OID"));
2112 if (locname && !CFEqual(oidKey, locname)) {
2113 /* Found localized description string, so use it instead of OID. */
2114 CFReleaseSafe(name);
2115 name = locname;
2116 } else {
2117 CFReleaseSafe(locname);
2118 }
2119 CFRelease(oidKey);
2120
2121 return name;
2122 }
2123
2124 /* Return the ipAddress as a dotted quad for ipv4, or as 8 colon separated
2125 4 digit hex strings for ipv6. Return NULL if the provided IP doesn't
2126 have a length of exactly 4 or 16 octets.
2127 */
2128 static CFStringRef copyIPAddressContentDescription(CFAllocatorRef allocator,
2129 const DERItem *ip) {
2130 /* This is the IP Address as an OCTET STRING.
2131 For IPv4 it's 4 octets addr, or 8 octets, addr/mask.
2132 For IPv6 it's 16 octets addr, or 32 octets addr/mask.
2133 */
2134 CFStringRef value = NULL;
2135 if (ip->length == 4) {
2136 value = CFStringCreateWithFormat(allocator, NULL,
2137 CFSTR("%u.%u.%u.%u"),
2138 ip->data[0], ip->data[1], ip->data[2], ip->data[3]);
2139 } else if (ip->length == 16) {
2140 value = CFStringCreateWithFormat(allocator, NULL,
2141 CFSTR("%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
2142 "%02x%02x:%02x%02x:%02x%02x:%02x%02x"),
2143 ip->data[0], ip->data[1], ip->data[2], ip->data[3],
2144 ip->data[4], ip->data[5], ip->data[6], ip->data[7],
2145 ip->data[8], ip->data[9], ip->data[10], ip->data[11],
2146 ip->data[12], ip->data[13], ip->data[14], ip->data[15]);
2147 }
2148
2149 return value;
2150 }
2151
2152 void appendProperty(CFMutableArrayRef properties, CFStringRef propertyType,
2153 CFStringRef label, CFStringRef localizedLabel, CFTypeRef value,
2154 bool localized) {
2155 CFDictionaryRef property;
2156 if (label) {
2157 CFStringRef ll = NULL;
2158 if (!localized) {
2159 /* use unlocalized label, overriding localizedLabel */
2160 ll = localizedLabel = (CFStringRef) CFRetainSafe(label);
2161 } else if (!localizedLabel) {
2162 /* copy localized label for unlocalized label */
2163 ll = localizedLabel = SecCopyCertString(label);
2164 }
2165 const void *all_keys[4];
2166 all_keys[0] = kSecPropertyKeyType;
2167 all_keys[1] = kSecPropertyKeyLabel;
2168 all_keys[2] = kSecPropertyKeyLocalizedLabel;
2169 all_keys[3] = kSecPropertyKeyValue;
2170 const void *property_values[] = {
2171 propertyType,
2172 label,
2173 localizedLabel,
2174 value,
2175 };
2176 property = CFDictionaryCreate(CFGetAllocator(properties),
2177 all_keys, property_values, value ? 4 : 3,
2178 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2179 CFReleaseSafe(ll);
2180 } else {
2181 const void *nolabel_keys[2];
2182 nolabel_keys[0] = kSecPropertyKeyType;
2183 nolabel_keys[1] = kSecPropertyKeyValue;
2184 const void *property_values[] = {
2185 propertyType,
2186 value,
2187 };
2188 property = CFDictionaryCreate(CFGetAllocator(properties),
2189 nolabel_keys, property_values, 2,
2190 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2191 }
2192
2193 CFArrayAppendValue(properties, property);
2194 CFRelease(property);
2195 }
2196
2197 /* YYMMDDhhmmZ */
2198 #define UTC_TIME_NOSEC_ZULU_LEN 11
2199 /* YYMMDDhhmmssZ */
2200 #define UTC_TIME_ZULU_LEN 13
2201 /* YYMMDDhhmmssThhmm */
2202 #define UTC_TIME_LOCALIZED_LEN 17
2203 /* YYYYMMDDhhmmssZ */
2204 #define GENERALIZED_TIME_ZULU_LEN 15
2205 /* YYYYMMDDhhmmssThhmm */
2206 #define GENERALIZED_TIME_LOCALIZED_LEN 19
2207
2208 /* Parse 2 digits at (*p)[0] and (*p)[1] and return the result. Also
2209 advance *p by 2. */
2210 static inline int parseDecimalPair(const DERByte **p) {
2211 const DERByte *cp = *p;
2212 *p += 2;
2213 return 10 * (cp[0] - '0') + cp[1] - '0';
2214 }
2215
2216 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime.
2217 Return a CFErrorRef in the error parameter if decoding fails.
2218 Note that this is needed to distinguish an error condition from a
2219 valid time which specifies 2001-01-01 00:00:00 (i.e. a value of 0).
2220 */
2221 static CFAbsoluteTime SecAbsoluteTimeFromDateContentWithError(DERTag tag,
2222 const uint8_t *bytes,
2223 size_t length,
2224 CFErrorRef *error) {
2225 if (error) {
2226 *error = NULL;
2227 }
2228 if (NULL == bytes || 0 == length) {
2229 goto decodeErr;
2230 }
2231
2232 bool isUtcLength = false;
2233 bool isLocalized = false;
2234 bool noSeconds = false;
2235 switch (length) {
2236 case UTC_TIME_NOSEC_ZULU_LEN: /* YYMMDDhhmmZ */
2237 isUtcLength = true;
2238 noSeconds = true;
2239 break;
2240 case UTC_TIME_ZULU_LEN: /* YYMMDDhhmmssZ */
2241 isUtcLength = true;
2242 break;
2243 case GENERALIZED_TIME_ZULU_LEN: /* YYYYMMDDhhmmssZ */
2244 break;
2245 case UTC_TIME_LOCALIZED_LEN: /* YYMMDDhhmmssThhmm (where T=[+,-]) */
2246 isUtcLength = true;
2247 /*DROPTHROUGH*/
2248 case GENERALIZED_TIME_LOCALIZED_LEN:/* YYYYMMDDhhmmssThhmm (where T=[+,-]) */
2249 isLocalized = true;
2250 break;
2251 default: /* unknown format */
2252 goto decodeErr;
2253 }
2254
2255 /* Make sure the der tag fits the thing inside it. */
2256 if (tag == ASN1_UTC_TIME) {
2257 if (!isUtcLength) {
2258 goto decodeErr;
2259 }
2260 } else if (tag == ASN1_GENERALIZED_TIME) {
2261 if (isUtcLength) {
2262 goto decodeErr;
2263 }
2264 } else {
2265 goto decodeErr;
2266 }
2267
2268 const DERByte *cp = bytes;
2269 /* Check that all characters are digits, except if localized the timezone
2270 indicator or if not localized the 'Z' at the end. */
2271 DERSize ix;
2272 for (ix = 0; ix < length; ++ix) {
2273 if (!(isdigit(cp[ix]))) {
2274 if ((isLocalized && ix == length - 5 &&
2275 (cp[ix] == '+' || cp[ix] == '-')) ||
2276 (!isLocalized && ix == length - 1 && cp[ix] == 'Z')) {
2277 continue;
2278 }
2279 goto decodeErr;
2280 }
2281 }
2282
2283 /* Parse the date and time fields. */
2284 int year, month, day, hour, minute, second;
2285 if (isUtcLength) {
2286 year = parseDecimalPair(&cp);
2287 if (year < 50) {
2288 /* 0 <= year < 50 : assume century 21 */
2289 year += 2000;
2290 } else if (year < 70) {
2291 /* 50 <= year < 70 : illegal per PKIX */
2292 return false;
2293 } else {
2294 /* 70 < year <= 99 : assume century 20 */
2295 year += 1900;
2296 }
2297 } else {
2298 year = 100 * parseDecimalPair(&cp) + parseDecimalPair(&cp);
2299 }
2300 month = parseDecimalPair(&cp);
2301 day = parseDecimalPair(&cp);
2302 hour = parseDecimalPair(&cp);
2303 minute = parseDecimalPair(&cp);
2304 if (noSeconds) {
2305 second = 0;
2306 } else {
2307 second = parseDecimalPair(&cp);
2308 }
2309
2310 CFTimeInterval timeZoneOffset;
2311 if (isLocalized) {
2312 /* ZONE INDICATOR */
2313 int multiplier = *cp++ == '+' ? 60 : -60;
2314 timeZoneOffset = multiplier *
2315 (parseDecimalPair(&cp) * 60 + parseDecimalPair(&cp));
2316 } else {
2317 timeZoneOffset = 0;
2318 }
2319
2320 secdebug("dateparse",
2321 "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g",
2322 (int) length, bytes, year, month,
2323 day, hour, minute, second,
2324 timeZoneOffset / 60);
2325
2326 static int mdays[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
2327 int is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) ? 1 : 0;
2328 if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59
2329 || (month == 2 && day > mdays[month] - mdays[month - 1] + is_leap_year)
2330 || (month != 2 && day > mdays[month] - mdays[month - 1])) {
2331 /* Invalid date. */
2332 goto decodeErr;
2333 }
2334
2335 int dy = year - 2001;
2336 if (dy < 0) {
2337 dy += 1;
2338 day -= 1;
2339 }
2340 int leap_days = dy / 4 - dy / 100 + dy / 400;
2341 day += ((year - 2001) * 365 + leap_days) + mdays[month - 1] - 1;
2342 if (month > 2)
2343 day += is_leap_year;
2344
2345 CFAbsoluteTime absTime = (CFAbsoluteTime)((day * 24.0 + hour) * 60.0 + minute) * 60.0 + second;
2346 return absTime - timeZoneOffset;
2347
2348 decodeErr:
2349 if (error) {
2350 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidCertificate, NULL);
2351 }
2352 return NULL_TIME;
2353 }
2354
2355 CFAbsoluteTime SecAbsoluteTimeFromDateContent(DERTag tag, const uint8_t *bytes,
2356 size_t length) {
2357 return SecAbsoluteTimeFromDateContentWithError(tag, bytes, length, NULL);
2358 }
2359
2360 __attribute__((__nonnull__)) static bool derDateContentGetAbsoluteTime(DERTag tag, const DERItem *date,
2361 CFAbsoluteTime *pabsTime) {
2362 CFErrorRef error = NULL;
2363 CFAbsoluteTime absTime = SecAbsoluteTimeFromDateContentWithError(tag, date->data,
2364 date->length, &error);
2365 if (error) {
2366 secwarning("Invalid date specification in certificate (see RFC5280 4.1.2.5)");
2367 CFRelease(error);
2368 return false;
2369 }
2370
2371 *pabsTime = absTime;
2372 return true;
2373 }
2374
2375 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return
2376 true if the date was valid and properly decoded, also return the result in
2377 absTime. Return false otherwise. */
2378 __attribute__((__nonnull__)) static bool derDateGetAbsoluteTime(const DERItem *dateChoice,
2379 CFAbsoluteTime *absTime) {
2380 if (dateChoice->length == 0) return false;
2381
2382 DERDecodedInfo decoded;
2383 if (DERDecodeItem(dateChoice, &decoded))
2384 return false;
2385
2386 return derDateContentGetAbsoluteTime(decoded.tag, &decoded.content,
2387 absTime);
2388 }
2389
2390 static void appendDataProperty(CFMutableArrayRef properties,
2391 CFStringRef label, CFStringRef localizedLabel, const DERItem *der_data,
2392 bool localized) {
2393 CFDataRef data = CFDataCreate(CFGetAllocator(properties),
2394 der_data->data, der_data->length);
2395 appendProperty(properties, kSecPropertyTypeData, label, localizedLabel,
2396 data, localized);
2397 CFRelease(data);
2398 }
2399
2400 static void appendRelabeledProperty(CFMutableArrayRef properties,
2401 CFStringRef label,
2402 CFStringRef localizedLabel,
2403 const DERItem *der_data,
2404 CFStringRef labelFormat,
2405 bool localized) {
2406 CFStringRef newLabel =
2407 CFStringCreateWithFormat(CFGetAllocator(properties), NULL,
2408 labelFormat, label);
2409 CFStringRef ll = NULL;
2410 CFStringRef localizedLabelFormat = NULL;
2411 if (!localized) {
2412 /* use provided label and format strings; do not localize */
2413 ll = localizedLabel = (CFStringRef) CFRetainSafe(label);
2414 localizedLabelFormat = (CFStringRef) CFRetainSafe(labelFormat);
2415 } else {
2416 if (!localizedLabel) {
2417 /* copy localized label for provided label */
2418 ll = localizedLabel = SecCopyCertString(label);
2419 }
2420 /* copy localized format for provided format */
2421 localizedLabelFormat = SecCopyCertString(labelFormat);
2422 }
2423
2424 CFStringRef newLocalizedLabel =
2425 CFStringCreateWithFormat(CFGetAllocator(properties), NULL,
2426 localizedLabelFormat, localizedLabel);
2427 CFReleaseSafe(ll);
2428 CFReleaseSafe(localizedLabelFormat);
2429 appendDataProperty(properties, newLabel, newLocalizedLabel, der_data, localized);
2430 CFReleaseSafe(newLabel);
2431 CFReleaseSafe(newLocalizedLabel);
2432 }
2433
2434
2435 static void appendUnparsedProperty(CFMutableArrayRef properties,
2436 CFStringRef label, CFStringRef localizedLabel,
2437 const DERItem *der_data, bool localized) {
2438 appendRelabeledProperty(properties, label, localizedLabel, der_data,
2439 SEC_UNPARSED_KEY, localized);
2440 }
2441
2442 static void appendInvalidProperty(CFMutableArrayRef properties,
2443 CFStringRef label, const DERItem *der_data, bool localized) {
2444 appendRelabeledProperty(properties, label, NULL, der_data,
2445 SEC_INVALID_KEY, localized);
2446 }
2447
2448 static void appendDateContentProperty(CFMutableArrayRef properties,
2449 CFStringRef label, DERTag tag,
2450 const DERItem *dateContent, bool localized) {
2451 CFAbsoluteTime absTime;
2452 if (!derDateContentGetAbsoluteTime(tag, dateContent, &absTime)) {
2453 /* Date decode failure; insert hex bytes instead. */
2454 return appendInvalidProperty(properties, label, dateContent, localized);
2455 }
2456 CFDateRef date = CFDateCreate(CFGetAllocator(properties), absTime);
2457 appendProperty(properties, kSecPropertyTypeDate, label, NULL, date, localized);
2458 CFRelease(date);
2459 }
2460
2461 static void appendDateProperty(CFMutableArrayRef properties,
2462 CFStringRef label, CFAbsoluteTime absTime, bool localized) {
2463 CFDateRef date = CFDateCreate(CFGetAllocator(properties), absTime);
2464 appendProperty(properties, kSecPropertyTypeDate, label, NULL, date, localized);
2465 CFRelease(date);
2466 }
2467
2468 static void appendValidityPeriodProperty(CFMutableArrayRef parent, CFStringRef label,
2469 SecCertificateRef certificate, bool localized) {
2470 CFAllocatorRef allocator = CFGetAllocator(parent);
2471 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2472
2473 appendDateProperty(properties, SEC_NOT_VALID_BEFORE_KEY,
2474 certificate->_notBefore, localized);
2475 appendDateProperty(properties, SEC_NOT_VALID_AFTER_KEY,
2476 certificate->_notAfter, localized);
2477
2478 appendProperty(parent, kSecPropertyTypeSection, label, NULL, properties, localized);
2479 CFReleaseNull(properties);
2480 }
2481
2482 static void appendIPAddressContentProperty(CFMutableArrayRef properties,
2483 CFStringRef label, const DERItem *ip, bool localized) {
2484 CFStringRef value =
2485 copyIPAddressContentDescription(CFGetAllocator(properties), ip);
2486 if (value) {
2487 appendProperty(properties, kSecPropertyTypeString, label, NULL, value, localized);
2488 CFRelease(value);
2489 } else {
2490 appendUnparsedProperty(properties, label, NULL, ip, localized);
2491 }
2492 }
2493
2494 static void appendURLContentProperty(CFMutableArrayRef properties,
2495 CFStringRef label, const DERItem *urlContent, bool localized) {
2496 CFURLRef url = CFURLCreateWithBytes(CFGetAllocator(properties),
2497 urlContent->data, urlContent->length, kCFStringEncodingASCII, NULL);
2498 if (url) {
2499 appendProperty(properties, kSecPropertyTypeURL, label, NULL, url, localized);
2500 CFRelease(url);
2501 } else {
2502 appendInvalidProperty(properties, label, urlContent, localized);
2503 }
2504 }
2505
2506 static void appendURLProperty(CFMutableArrayRef properties,
2507 CFStringRef label, const DERItem *url, bool localized) {
2508 DERDecodedInfo decoded;
2509 DERReturn drtn;
2510
2511 drtn = DERDecodeItem(url, &decoded);
2512 if (drtn || decoded.tag != ASN1_IA5_STRING) {
2513 appendInvalidProperty(properties, label, url, localized);
2514 } else {
2515 appendURLContentProperty(properties, label, &decoded.content, localized);
2516 }
2517 }
2518
2519 static void appendOIDProperty(CFMutableArrayRef properties,
2520 CFStringRef label, CFStringRef llabel, const DERItem *oid, bool localized) {
2521 CFStringRef oid_string =
2522 copyOidDescription(CFGetAllocator(properties), oid, localized);
2523 appendProperty(properties, kSecPropertyTypeString, label, llabel,
2524 oid_string, localized);
2525 CFRelease(oid_string);
2526 }
2527
2528 static void appendAlgorithmProperty(CFMutableArrayRef properties,
2529 CFStringRef label, const DERAlgorithmId *algorithm, bool localized) {
2530 CFMutableArrayRef alg_props =
2531 CFArrayCreateMutable(CFGetAllocator(properties), 0,
2532 &kCFTypeArrayCallBacks);
2533 appendOIDProperty(alg_props, SEC_ALGORITHM_KEY, NULL,
2534 &algorithm->oid, localized);
2535 if (algorithm->params.length) {
2536 if (algorithm->params.length == 2 &&
2537 algorithm->params.data[0] == ASN1_NULL &&
2538 algorithm->params.data[1] == 0) {
2539 CFStringRef value = SecCopyCertString(SEC_NONE_KEY);
2540 appendProperty(alg_props, kSecPropertyTypeString,
2541 SEC_PARAMETERS_KEY, NULL, value, localized);
2542 CFRelease(value);
2543 } else {
2544 appendUnparsedProperty(alg_props, SEC_PARAMETERS_KEY, NULL,
2545 &algorithm->params, localized);
2546 }
2547 }
2548 appendProperty(properties, kSecPropertyTypeSection, label, NULL,
2549 alg_props, localized);
2550 CFRelease(alg_props);
2551 }
2552
2553 static void appendPublicKeyProperty(CFMutableArrayRef parent, CFStringRef label,
2554 SecCertificateRef certificate, bool localized) {
2555 CFAllocatorRef allocator = CFGetAllocator(parent);
2556 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2557
2558 /* Public key algorithm. */
2559 appendAlgorithmProperty(properties, SEC_PUBLIC_KEY_ALG_KEY,
2560 &certificate->_algId, localized);
2561
2562 /* Public Key Size */
2563 SecKeyRef publicKey = SecCertificateCopyKey(certificate);
2564 if (publicKey) {
2565 size_t sizeInBytes = SecKeyGetBlockSize(publicKey);
2566 CFStringRef sizeInBitsString = CFStringCreateWithFormat(allocator, NULL,
2567 CFSTR("%ld"), (sizeInBytes*8));
2568 if (sizeInBitsString) {
2569 appendProperty(properties, kSecPropertyTypeString, SEC_PUBLIC_KEY_SIZE_KEY,
2570 NULL, sizeInBitsString, localized);
2571 }
2572 CFReleaseNull(sizeInBitsString);
2573 }
2574 CFReleaseNull(publicKey);
2575
2576 /* Consider breaking down an RSA public key into modulus and
2577 exponent? */
2578 appendDataProperty(properties, SEC_PUBLIC_KEY_DATA_KEY, NULL,
2579 &certificate->_pubKeyDER, localized);
2580
2581 appendProperty(parent, kSecPropertyTypeSection, label, NULL,
2582 properties, localized);
2583 CFReleaseNull(properties);
2584 }
2585
2586 static void appendSignatureProperty(CFMutableArrayRef parent, CFStringRef label,
2587 SecCertificateRef certificate, bool localized) {
2588 CFAllocatorRef allocator = CFGetAllocator(parent);
2589 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2590
2591 appendAlgorithmProperty(properties, SEC_SIGNATURE_ALGORITHM_KEY,
2592 &certificate->_tbsSigAlg, localized);
2593
2594 appendDataProperty(properties, SEC_SIGNATURE_DATA_KEY, NULL,
2595 &certificate->_signature, localized);
2596
2597 appendProperty(parent, kSecPropertyTypeSection, label, NULL,
2598 properties, localized);
2599 CFReleaseNull(properties);
2600 }
2601
2602 static void appendFingerprintsProperty(CFMutableArrayRef parent, CFStringRef label,
2603 SecCertificateRef certificate, bool localized) {
2604 CFAllocatorRef allocator = CFGetAllocator(parent);
2605 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2606
2607 CFDataRef sha256Fingerprint = SecCertificateCopySHA256Digest(certificate);
2608 if (sha256Fingerprint) {
2609 appendProperty(properties, kSecPropertyTypeData, SEC_SHA2_FINGERPRINT_KEY,
2610 NULL, sha256Fingerprint, localized);
2611 }
2612 CFReleaseNull(sha256Fingerprint);
2613
2614 appendProperty(properties, kSecPropertyTypeData, SEC_SHA1_FINGERPRINT_KEY,
2615 NULL, SecCertificateGetSHA1Digest(certificate), localized);
2616
2617 appendProperty(parent, kSecPropertyTypeSection, label, NULL,
2618 properties, localized);
2619 CFReleaseNull(properties);
2620 }
2621
2622 static CFStringRef copyHexDescription(CFAllocatorRef allocator,
2623 const DERItem *blob) {
2624 CFIndex ix, length = blob->length /* < 24 ? blob->length : 24 */;
2625 CFMutableStringRef string = CFStringCreateMutable(allocator,
2626 blob->length * 3 - 1);
2627 for (ix = 0; ix < length; ++ix)
2628 if (ix == 0)
2629 CFStringAppendFormat(string, NULL, CFSTR("%02X"), blob->data[ix]);
2630 else
2631 CFStringAppendFormat(string, NULL, CFSTR(" %02X"), blob->data[ix]);
2632
2633 return string;
2634 }
2635
2636 static CFStringRef copyBlobString(CFAllocatorRef allocator,
2637 CFStringRef blobType, CFStringRef quanta,
2638 const DERItem *blob, bool localized) {
2639 CFStringRef localizedBlobType = (localized) ?
2640 SecCopyCertString(blobType) : (CFStringRef) CFRetainSafe(blobType);
2641 CFStringRef localizedQuanta = (localized) ?
2642 SecCopyCertString(quanta) : (CFStringRef) CFRetainSafe(quanta);
2643 /* "format string for encoded field data (e.g. Sequence; 128 bytes; "
2644 "data = 00 00 ...)" */
2645 CFStringRef blobFormat = (localized) ?
2646 SecCopyCertString(SEC_BLOB_KEY) : SEC_BLOB_KEY;
2647 CFStringRef hex = copyHexDescription(allocator, blob);
2648 CFStringRef result = CFStringCreateWithFormat(allocator, NULL,
2649 blobFormat, localizedBlobType, blob->length, localizedQuanta, hex);
2650 CFRelease(hex);
2651 CFRelease(blobFormat);
2652 CFReleaseSafe(localizedQuanta);
2653 CFReleaseSafe(localizedBlobType);
2654
2655 return result;
2656 }
2657
2658 /* Return a string verbatim (unlocalized) from a DER field. */
2659 static CFStringRef copyContentString(CFAllocatorRef allocator,
2660 const DERItem *string, CFStringEncoding encoding,
2661 bool printableOnly) {
2662 /* Strip potential bogus trailing zero from printable strings. */
2663 DERSize length = string->length;
2664 if (length && string->data[length - 1] == 0) {
2665 /* Don't mess with the length of UTF16 strings though. */
2666 if (encoding != kCFStringEncodingUTF16)
2667 length--;
2668 }
2669 /* A zero length string isn't considered printable. */
2670 if (!length && printableOnly)
2671 return NULL;
2672
2673 /* Passing true for the 5th paramater to CFStringCreateWithBytes() makes
2674 it treat kCFStringEncodingUTF16 as big endian by default, whereas
2675 passing false makes it treat it as native endian by default. */
2676 CFStringRef result = CFStringCreateWithBytes(allocator, string->data,
2677 length, encoding, encoding == kCFStringEncodingUTF16);
2678 if (result)
2679 return result;
2680
2681 return printableOnly ? NULL : copyHexDescription(allocator, string);
2682 }
2683
2684 /* From rfc3280 - Appendix B. ASN.1 Notes
2685
2686 CAs MUST force the serialNumber to be a non-negative integer, that
2687 is, the sign bit in the DER encoding of the INTEGER value MUST be
2688 zero - this can be done by adding a leading (leftmost) `00'H octet if
2689 necessary. This removes a potential ambiguity in mapping between a
2690 string of octets and an integer value.
2691
2692 As noted in section 4.1.2.2, serial numbers can be expected to
2693 contain long integers. Certificate users MUST be able to handle
2694 serialNumber values up to 20 octets in length. Conformant CAs MUST
2695 NOT use serialNumber values longer than 20 octets.
2696 */
2697
2698 /* Return the given numeric data as a string: decimal up to 64 bits,
2699 hex otherwise.
2700 */
2701 static CFStringRef copyIntegerContentDescription(CFAllocatorRef allocator,
2702 const DERItem *integer) {
2703 uint64_t value = 0;
2704 CFIndex ix, length = integer->length;
2705
2706 if (length == 0 || length > 8)
2707 return copyHexDescription(allocator, integer);
2708
2709 for(ix = 0; ix < length; ++ix) {
2710 value <<= 8;
2711 value += integer->data[ix];
2712 }
2713
2714 return CFStringCreateWithFormat(allocator, NULL, CFSTR("%llu"), value);
2715 }
2716
2717 static CFStringRef copyDERThingContentDescription(CFAllocatorRef allocator,
2718 DERTag tag, const DERItem *derThing, bool printableOnly, bool localized) {
2719 if (!derThing) { return NULL; }
2720 switch(tag) {
2721 case ASN1_INTEGER:
2722 case ASN1_BOOLEAN:
2723 return printableOnly ? NULL : copyIntegerContentDescription(allocator, derThing);
2724 case ASN1_PRINTABLE_STRING:
2725 case ASN1_IA5_STRING:
2726 return copyContentString(allocator, derThing, kCFStringEncodingASCII, printableOnly);
2727 case ASN1_UTF8_STRING:
2728 case ASN1_GENERAL_STRING:
2729 case ASN1_UNIVERSAL_STRING:
2730 return copyContentString(allocator, derThing, kCFStringEncodingUTF8, printableOnly);
2731 case ASN1_T61_STRING: // 20, also BER_TAG_TELETEX_STRING
2732 case ASN1_VIDEOTEX_STRING: // 21
2733 case ASN1_VISIBLE_STRING: // 26
2734 return copyContentString(allocator, derThing, kCFStringEncodingISOLatin1, printableOnly);
2735 case ASN1_BMP_STRING: // 30
2736 return copyContentString(allocator, derThing, kCFStringEncodingUTF16, printableOnly);
2737 case ASN1_OCTET_STRING:
2738 return printableOnly ? NULL :
2739 copyBlobString(allocator, SEC_BYTE_STRING_KEY, SEC_BYTES_KEY,
2740 derThing, localized);
2741 case ASN1_BIT_STRING:
2742 return printableOnly ? NULL :
2743 copyBlobString(allocator, SEC_BIT_STRING_KEY, SEC_BITS_KEY,
2744 derThing, localized);
2745 case ASN1_CONSTR_SEQUENCE:
2746 return printableOnly ? NULL :
2747 copyBlobString(allocator, SEC_SEQUENCE_KEY, SEC_BYTES_KEY,
2748 derThing, localized);
2749 case ASN1_CONSTR_SET:
2750 return printableOnly ? NULL :
2751 copyBlobString(allocator, SEC_SET_KEY, SEC_BYTES_KEY,
2752 derThing, localized);
2753 case ASN1_OBJECT_ID:
2754 return printableOnly ? NULL : copyOidDescription(allocator, derThing, localized);
2755 default:
2756 if (printableOnly) {
2757 return NULL;
2758 } else {
2759 CFStringRef fmt = (localized) ?
2760 SecCopyCertString(SEC_NOT_DISPLAYED_KEY) : SEC_NOT_DISPLAYED_KEY;
2761 if (!fmt) { return NULL; }
2762 CFStringRef result = CFStringCreateWithFormat(allocator, NULL, fmt,
2763 (unsigned long)tag, (unsigned long)derThing->length);
2764 CFRelease(fmt);
2765 return result;
2766 }
2767 }
2768 }
2769
2770 static CFStringRef copyDERThingDescription(CFAllocatorRef allocator,
2771 const DERItem *derThing, bool printableOnly, bool localized) {
2772 DERDecodedInfo decoded;
2773 DERReturn drtn;
2774
2775 drtn = DERDecodeItem(derThing, &decoded);
2776 if (drtn) {
2777 /* TODO: Perhaps put something in the label saying we couldn't parse
2778 the DER? */
2779 return printableOnly ? NULL : copyHexDescription(allocator, derThing);
2780 } else {
2781 return copyDERThingContentDescription(allocator, decoded.tag,
2782 &decoded.content, false, localized);
2783 }
2784 }
2785
2786 static void appendDERThingProperty(CFMutableArrayRef properties,
2787 CFStringRef label, CFStringRef localizedLabel,
2788 const DERItem *derThing, bool localized) {
2789 CFStringRef value = copyDERThingDescription(CFGetAllocator(properties),
2790 derThing, false, localized);
2791 if (value) {
2792 appendProperty(properties, kSecPropertyTypeString, label, localizedLabel,
2793 value, localized);
2794 }
2795 CFReleaseSafe(value);
2796 }
2797
2798 static OSStatus appendRDNProperty(void *context, const DERItem *rdnType,
2799 const DERItem *rdnValue, CFIndex rdnIX,
2800 bool localized) {
2801 CFMutableArrayRef properties = (CFMutableArrayRef)context;
2802 if (rdnIX > 0) {
2803 /* If there is more than one value pair we create a subsection for the
2804 second pair, and append things to the subsection for subsequent
2805 pairs. */
2806 CFIndex lastIX = CFArrayGetCount(properties) - 1;
2807 CFTypeRef lastValue = CFArrayGetValueAtIndex(properties, lastIX);
2808 if (rdnIX == 1) {
2809 /* Since this is the second rdn pair for a given rdn, we setup a
2810 new subsection for this rdn. We remove the first property
2811 from the properties array and make it the first element in the
2812 subsection instead. */
2813 CFMutableArrayRef rdn_props = CFArrayCreateMutable(
2814 CFGetAllocator(properties), 0, &kCFTypeArrayCallBacks);
2815 CFArrayAppendValue(rdn_props, lastValue);
2816 CFArrayRemoveValueAtIndex(properties, lastIX);
2817 appendProperty(properties, kSecPropertyTypeSection, NULL, NULL,
2818 rdn_props, localized);
2819 properties = rdn_props;
2820 // rdn_props is now retained by the original properties array
2821 CFReleaseSafe(rdn_props);
2822 } else {
2823 /* Since this is the third or later rdn pair we have already
2824 created a subsection in the top level properties array. Instead
2825 of appending to that directly we append to the array inside the
2826 subsection. */
2827 properties = (CFMutableArrayRef)CFDictionaryGetValue(
2828 (CFDictionaryRef)lastValue, kSecPropertyKeyValue);
2829 }
2830 }
2831
2832 /* Finally we append the new rdn value to the property array. */
2833 CFStringRef label =
2834 SecDERItemCopyOIDDecimalRepresentation(CFGetAllocator(properties),
2835 rdnType);
2836 CFStringRef localizedLabel = copyOidDescription(CFGetAllocator(properties),
2837 rdnType, localized);
2838 appendDERThingProperty(properties, label, localizedLabel,
2839 rdnValue, localized);
2840 CFReleaseSafe(label);
2841 CFReleaseSafe(localizedLabel);
2842 return errSecSuccess;
2843 }
2844
2845 static CFArrayRef createPropertiesForRDNContent(CFAllocatorRef allocator,
2846 const DERItem *rdnSetContent, bool localized) {
2847 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
2848 &kCFTypeArrayCallBacks);
2849 OSStatus status = parseRDNContent(rdnSetContent, properties,
2850 appendRDNProperty, localized);
2851 if (status) {
2852 CFArrayRemoveAllValues(properties);
2853 appendInvalidProperty(properties, SEC_RDN_KEY, rdnSetContent,
2854 localized);
2855 }
2856
2857 return properties;
2858 }
2859
2860 /*
2861 From rfc3739 - 3.1.2. Subject
2862
2863 When parsing the subject here are some tips for a short name of the cert.
2864 Choice I: commonName
2865 Choice II: givenName
2866 Choice III: pseudonym
2867
2868 The commonName attribute value SHALL, when present, contain a name
2869 of the subject. This MAY be in the subject's preferred
2870 presentation format, or a format preferred by the CA, or some
2871 other format. Pseudonyms, nicknames, and names with spelling
2872 other than defined by the registered name MAY be used. To
2873 understand the nature of the name presented in commonName,
2874 complying applications MAY have to examine present values of the
2875 givenName and surname attributes, or the pseudonym attribute.
2876
2877 */
2878 static CFArrayRef createPropertiesForX501NameContent(CFAllocatorRef allocator,
2879 const DERItem *x501NameContent, bool localized) {
2880 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
2881 &kCFTypeArrayCallBacks);
2882 OSStatus status = parseX501NameContent(x501NameContent, properties,
2883 appendRDNProperty, localized);
2884 if (status) {
2885 CFArrayRemoveAllValues(properties);
2886 appendInvalidProperty(properties, SEC_X501_NAME_KEY,
2887 x501NameContent, localized);
2888 }
2889
2890 return properties;
2891 }
2892
2893 static CFArrayRef createPropertiesForX501Name(CFAllocatorRef allocator,
2894 const DERItem *x501Name, bool localized) {
2895 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
2896 &kCFTypeArrayCallBacks);
2897 OSStatus status = parseX501Name(x501Name, properties, appendRDNProperty, localized);
2898 if (status) {
2899 CFArrayRemoveAllValues(properties);
2900 appendInvalidProperty(properties, SEC_X501_NAME_KEY,
2901 x501Name, localized);
2902 }
2903
2904 return properties;
2905 }
2906
2907 static void appendIntegerProperty(CFMutableArrayRef properties,
2908 CFStringRef label, const DERItem *integer, bool localized) {
2909 CFStringRef string = copyIntegerContentDescription(
2910 CFGetAllocator(properties), integer);
2911 appendProperty(properties, kSecPropertyTypeString, label, NULL,
2912 string, localized);
2913 CFRelease(string);
2914 }
2915
2916 static void appendBoolProperty(CFMutableArrayRef properties,
2917 CFStringRef label, bool boolean, bool localized) {
2918 CFStringRef key = (boolean) ? SEC_YES_KEY : SEC_NO_KEY;
2919 CFStringRef value = (localized) ? SecCopyCertString(key) : key;
2920 appendProperty(properties, kSecPropertyTypeString, label, NULL,
2921 value, localized);
2922 CFRelease(value);
2923 }
2924
2925 static void appendBooleanProperty(CFMutableArrayRef properties,
2926 CFStringRef label, const DERItem *boolean,
2927 bool defaultValue, bool localized) {
2928 bool result;
2929 DERReturn drtn = DERParseBooleanWithDefault(boolean, defaultValue, &result);
2930 if (drtn) {
2931 /* Couldn't parse boolean; dump the raw unparsed data as hex. */
2932 appendInvalidProperty(properties, label, boolean, localized);
2933 } else {
2934 appendBoolProperty(properties, label, result, localized);
2935 }
2936 }
2937
2938 static void appendSerialNumberProperty(CFMutableArrayRef parent, CFStringRef label,
2939 DERItem *serialNum, bool localized) {
2940 CFAllocatorRef allocator = CFGetAllocator(parent);
2941 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2942
2943 if (serialNum->length) {
2944 appendIntegerProperty(properties, SEC_SERIAL_NUMBER_KEY,
2945 serialNum, localized);
2946 appendProperty(parent, kSecPropertyTypeSection, label, NULL,
2947 properties, localized);
2948 }
2949
2950 CFReleaseNull(properties);
2951 }
2952
2953 static void appendBitStringContentNames(CFMutableArrayRef properties,
2954 CFStringRef label, const DERItem *bitStringContent,
2955 const CFStringRef *names, CFIndex namesCount,
2956 bool localized) {
2957 DERSize len = bitStringContent->length - 1;
2958 require_quiet(len == 1 || len == 2, badDER);
2959 DERByte numUnusedBits = bitStringContent->data[0];
2960 require_quiet(numUnusedBits < 8, badDER);
2961 uint_fast16_t bits = 8 * len - numUnusedBits;
2962 require_quiet(bits <= (uint_fast16_t)namesCount, badDER);
2963 uint_fast16_t value = bitStringContent->data[1];
2964 uint_fast16_t mask;
2965 if (len > 1) {
2966 value = (value << 8) + bitStringContent->data[2];
2967 mask = 0x8000;
2968 } else {
2969 mask = 0x80;
2970 }
2971 uint_fast16_t ix;
2972 CFStringRef fmt = (localized) ?
2973 SecCopyCertString(SEC_STRING_LIST_KEY) : SEC_STRING_LIST_KEY;
2974 CFStringRef string = NULL;
2975 for (ix = 0; ix < bits; ++ix) {
2976 if (value & mask) {
2977 if (string) {
2978 CFStringRef s =
2979 CFStringCreateWithFormat(CFGetAllocator(properties),
2980 NULL, fmt, string, names[ix]);
2981 CFRelease(string);
2982 string = s;
2983 } else {
2984 string = names[ix];
2985 CFRetain(string);
2986 }
2987 }
2988 mask >>= 1;
2989 }
2990 CFRelease(fmt);
2991 appendProperty(properties, kSecPropertyTypeString, label, NULL,
2992 string ? string : CFSTR(""), localized);
2993 CFReleaseSafe(string);
2994 return;
2995 badDER:
2996 appendInvalidProperty(properties, label, bitStringContent, localized);
2997 }
2998
2999 static void appendBitStringNames(CFMutableArrayRef properties,
3000 CFStringRef label, const DERItem *bitString,
3001 const CFStringRef *names, CFIndex namesCount,
3002 bool localized) {
3003 DERDecodedInfo bitStringContent;
3004 DERReturn drtn = DERDecodeItem(bitString, &bitStringContent);
3005 require_noerr_quiet(drtn, badDER);
3006 require_quiet(bitStringContent.tag == ASN1_BIT_STRING, badDER);
3007 appendBitStringContentNames(properties, label, &bitStringContent.content,
3008 names, namesCount, localized);
3009 return;
3010 badDER:
3011 appendInvalidProperty(properties, label, bitString, localized);
3012 }
3013
3014 static void appendKeyUsage(CFMutableArrayRef properties,
3015 const DERItem *extnValue, bool localized) {
3016 static const CFStringRef usageNames[] = {
3017 SEC_DIGITAL_SIGNATURE_KEY,
3018 SEC_NON_REPUDIATION_KEY,
3019 SEC_KEY_ENCIPHERMENT_KEY,
3020 SEC_DATA_ENCIPHERMENT_KEY,
3021 SEC_KEY_AGREEMENT_KEY,
3022 SEC_CERT_SIGN_KEY,
3023 SEC_CRL_SIGN_KEY,
3024 SEC_ENCIPHER_ONLY_KEY,
3025 SEC_DECIPHER_ONLY_KEY
3026 };
3027 appendBitStringNames(properties, SEC_USAGE_KEY, extnValue,
3028 usageNames, array_size(usageNames), localized);
3029 }
3030
3031 static void appendPrivateKeyUsagePeriod(CFMutableArrayRef properties,
3032 const DERItem *extnValue, bool localized) {
3033 DERPrivateKeyUsagePeriod pkup;
3034 DERReturn drtn = DERParseSequence(extnValue,
3035 DERNumPrivateKeyUsagePeriodItemSpecs, DERPrivateKeyUsagePeriodItemSpecs,
3036 &pkup, sizeof(pkup));
3037 require_noerr_quiet(drtn, badDER);
3038 if (pkup.notBefore.length) {
3039 appendDateContentProperty(properties, SEC_NOT_VALID_BEFORE_KEY,
3040 ASN1_GENERALIZED_TIME, &pkup.notBefore, localized);
3041 }
3042 if (pkup.notAfter.length) {
3043 appendDateContentProperty(properties, SEC_NOT_VALID_AFTER_KEY,
3044 ASN1_GENERALIZED_TIME, &pkup.notAfter, localized);
3045 }
3046 return;
3047 badDER:
3048 appendInvalidProperty(properties, SEC_PRIVATE_KU_PERIOD_KEY,
3049 extnValue, localized);
3050 }
3051
3052 static void appendStringContentProperty(CFMutableArrayRef properties,
3053 CFStringRef label, const DERItem *stringContent,
3054 CFStringEncoding encoding, bool localized) {
3055 CFStringRef string = CFStringCreateWithBytes(CFGetAllocator(properties),
3056 stringContent->data, stringContent->length, encoding, FALSE);
3057 if (string) {
3058 appendProperty(properties, kSecPropertyTypeString, label, NULL,
3059 string, localized);
3060 CFRelease(string);
3061 } else {
3062 appendInvalidProperty(properties, label, stringContent, localized);
3063 }
3064 }
3065
3066 /*
3067 OtherName ::= SEQUENCE {
3068 type-id OBJECT IDENTIFIER,
3069 value [0] EXPLICIT ANY DEFINED BY type-id }
3070 */
3071 static void appendOtherNameContentProperty(CFMutableArrayRef properties,
3072 const DERItem *otherNameContent, bool localized) {
3073 DEROtherName on;
3074 DERReturn drtn = DERParseSequenceContent(otherNameContent,
3075 DERNumOtherNameItemSpecs, DEROtherNameItemSpecs,
3076 &on, sizeof(on));
3077 require_noerr_quiet(drtn, badDER);
3078 CFAllocatorRef allocator = CFGetAllocator(properties);
3079 CFStringRef label =
3080 SecDERItemCopyOIDDecimalRepresentation(allocator, &on.typeIdentifier);
3081 CFStringRef localizedLabel =
3082 copyOidDescription(allocator, &on.typeIdentifier, localized);
3083 CFStringRef value_string = copyDERThingDescription(allocator, &on.value,
3084 false, localized);
3085 if (value_string) {
3086 appendProperty(properties, kSecPropertyTypeString, label,
3087 localizedLabel, value_string, localized);
3088 } else {
3089 appendUnparsedProperty(properties, label, localizedLabel,
3090 &on.value, localized);
3091 }
3092 CFReleaseSafe(value_string);
3093 CFReleaseSafe(label);
3094 CFReleaseSafe(localizedLabel);
3095 return;
3096 badDER:
3097 appendInvalidProperty(properties, SEC_OTHER_NAME_KEY,
3098 otherNameContent, localized);
3099 }
3100
3101 /*
3102 GeneralName ::= CHOICE {
3103 otherName [0] OtherName,
3104 rfc822Name [1] IA5String,
3105 dNSName [2] IA5String,
3106 x400Address [3] ORAddress,
3107 directoryName [4] Name,
3108 ediPartyName [5] EDIPartyName,
3109 uniformResourceIdentifier [6] IA5String,
3110 iPAddress [7] OCTET STRING,
3111 registeredID [8] OBJECT IDENTIFIER}
3112
3113 EDIPartyName ::= SEQUENCE {
3114 nameAssigner [0] DirectoryString OPTIONAL,
3115 partyName [1] DirectoryString }
3116 */
3117 static bool appendGeneralNameContentProperty(CFMutableArrayRef properties,
3118 DERTag tag, const DERItem *generalName, bool localized) {
3119 switch (tag) {
3120 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0:
3121 appendOtherNameContentProperty(properties, generalName, localized);
3122 break;
3123 case ASN1_CONTEXT_SPECIFIC | 1:
3124 /* IA5String. */
3125 appendStringContentProperty(properties, SEC_EMAIL_ADDRESS_KEY,
3126 generalName, kCFStringEncodingASCII, localized);
3127 break;
3128 case ASN1_CONTEXT_SPECIFIC | 2:
3129 /* IA5String. */
3130 appendStringContentProperty(properties, SEC_DNS_NAME_KEY, generalName,
3131 kCFStringEncodingASCII, localized);
3132 break;
3133 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3:
3134 appendUnparsedProperty(properties, SEC_X400_ADDRESS_KEY, NULL,
3135 generalName, localized);
3136 break;
3137 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4:
3138 {
3139 CFArrayRef directory_plist =
3140 createPropertiesForX501Name(CFGetAllocator(properties),
3141 generalName, localized);
3142 appendProperty(properties, kSecPropertyTypeSection,
3143 SEC_DIRECTORY_NAME_KEY, NULL, directory_plist, localized);
3144 CFRelease(directory_plist);
3145 break;
3146 }
3147 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5:
3148 appendUnparsedProperty(properties, SEC_EDI_PARTY_NAME_KEY, NULL,
3149 generalName, localized);
3150 break;
3151 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6:
3152 /* Technically I don't think this is valid, but there are certs out
3153 in the wild that use a constructed IA5String. In particular the
3154 VeriSign Time Stamping Authority CA.cer does this. */
3155 appendURLProperty(properties, SEC_URI_KEY, generalName, localized);
3156 break;
3157 case ASN1_CONTEXT_SPECIFIC | 6:
3158 appendURLContentProperty(properties, SEC_URI_KEY, generalName, localized);
3159 break;
3160 case ASN1_CONTEXT_SPECIFIC | 7:
3161 appendIPAddressContentProperty(properties, SEC_IP_ADDRESS_KEY,
3162 generalName, localized);
3163 break;
3164 case ASN1_CONTEXT_SPECIFIC | 8:
3165 appendOIDProperty(properties, SEC_REGISTERED_ID_KEY, NULL,
3166 generalName, localized);
3167 break;
3168 default:
3169 goto badDER;
3170 break;
3171 }
3172 return true;
3173 badDER:
3174 return false;
3175 }
3176
3177 static void appendGeneralNameProperty(CFMutableArrayRef properties,
3178 const DERItem *generalName, bool localized) {
3179 DERDecodedInfo generalNameContent;
3180 DERReturn drtn = DERDecodeItem(generalName, &generalNameContent);
3181 require_noerr_quiet(drtn, badDER);
3182 if (appendGeneralNameContentProperty(properties, generalNameContent.tag,
3183 &generalNameContent.content, localized))
3184 return;
3185 badDER:
3186 appendInvalidProperty(properties, SEC_GENERAL_NAME_KEY,
3187 generalName, localized);
3188 }
3189
3190
3191 /*
3192 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
3193 */
3194 static void appendGeneralNamesContent(CFMutableArrayRef properties,
3195 const DERItem *generalNamesContent, bool localized) {
3196 DERSequence gnSeq;
3197 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq);
3198 require_noerr_quiet(drtn, badDER);
3199 DERDecodedInfo generalNameContent;
3200 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) ==
3201 DR_Success) {
3202 if (!appendGeneralNameContentProperty(properties,
3203 generalNameContent.tag, &generalNameContent.content, localized)) {
3204 goto badDER;
3205 }
3206 }
3207 require_quiet(drtn == DR_EndOfSequence, badDER);
3208 return;
3209 badDER:
3210 appendInvalidProperty(properties, SEC_GENERAL_NAMES_KEY,
3211 generalNamesContent, localized);
3212 }
3213
3214 static void appendGeneralNames(CFMutableArrayRef properties,
3215 const DERItem *generalNames, bool localized) {
3216 DERDecodedInfo generalNamesContent;
3217 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent);
3218 require_noerr_quiet(drtn, badDER);
3219 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE,
3220 badDER);
3221 appendGeneralNamesContent(properties, &generalNamesContent.content,
3222 localized);
3223 return;
3224 badDER:
3225 appendInvalidProperty(properties, SEC_GENERAL_NAMES_KEY,
3226 generalNames, localized);
3227 }
3228
3229 /*
3230 BasicConstraints ::= SEQUENCE {
3231 cA BOOLEAN DEFAULT FALSE,
3232 pathLenConstraint INTEGER (0..MAX) OPTIONAL }
3233 */
3234 static void appendBasicConstraints(CFMutableArrayRef properties,
3235 const DERItem *extnValue, bool localized) {
3236 DERBasicConstraints basicConstraints;
3237 DERReturn drtn = DERParseSequence(extnValue,
3238 DERNumBasicConstraintsItemSpecs, DERBasicConstraintsItemSpecs,
3239 &basicConstraints, sizeof(basicConstraints));
3240 require_noerr_quiet(drtn, badDER);
3241
3242 appendBooleanProperty(properties, SEC_CERT_AUTHORITY_KEY,
3243 &basicConstraints.cA, false, localized);
3244
3245 if (basicConstraints.pathLenConstraint.length != 0) {
3246 appendIntegerProperty(properties, SEC_PATH_LEN_CONSTRAINT_KEY,
3247 &basicConstraints.pathLenConstraint, localized);
3248 }
3249 return;
3250 badDER:
3251 appendInvalidProperty(properties, SEC_BASIC_CONSTRAINTS_KEY,
3252 extnValue, localized);
3253 }
3254
3255 /*
3256 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
3257 *
3258 * NameConstraints ::= SEQUENCE {
3259 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
3260 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
3261 *
3262 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
3263 *
3264 * GeneralSubtree ::= SEQUENCE {
3265 * base GeneralName,
3266 * minimum [0] BaseDistance DEFAULT 0,
3267 * maximum [1] BaseDistance OPTIONAL }
3268 *
3269 * BaseDistance ::= INTEGER (0..MAX)
3270 */
3271 static void appendNameConstraints(CFMutableArrayRef properties,
3272 const DERItem *extnValue, bool localized) {
3273 CFAllocatorRef allocator = CFGetAllocator(properties);
3274 DERNameConstraints nc;
3275 DERReturn drtn;
3276 drtn = DERParseSequence(extnValue,
3277 DERNumNameConstraintsItemSpecs,
3278 DERNameConstraintsItemSpecs,
3279 &nc, sizeof(nc));
3280 require_noerr_quiet(drtn, badDER);
3281 if (nc.permittedSubtrees.length) {
3282 DERSequence gsSeq;
3283 require_noerr_quiet(DERDecodeSeqContentInit(&nc.permittedSubtrees, &gsSeq), badDER);
3284 DERDecodedInfo gsContent;
3285 while ((drtn = DERDecodeSeqNext(&gsSeq, &gsContent)) == DR_Success) {
3286 DERGeneralSubtree derGS;
3287 require_quiet(gsContent.tag==ASN1_CONSTR_SEQUENCE, badDER);
3288 drtn = DERParseSequenceContent(&gsContent.content,
3289 DERNumGeneralSubtreeItemSpecs,
3290 DERGeneralSubtreeItemSpecs,
3291 &derGS, sizeof(derGS));
3292 require_noerr_quiet(drtn, badDER);
3293 if (derGS.minimum.length) {
3294 appendIntegerProperty(properties, SEC_PERMITTED_MINIMUM_KEY,
3295 &derGS.minimum, localized);
3296 }
3297 if (derGS.maximum.length) {
3298 appendIntegerProperty(properties, SEC_PERMITTED_MAXIMUM_KEY,
3299 &derGS.maximum, localized);
3300 }
3301 if (derGS.generalName.length) {
3302 CFMutableArrayRef base = CFArrayCreateMutable(allocator, 0,
3303 &kCFTypeArrayCallBacks);
3304 appendProperty(properties, kSecPropertyTypeSection,
3305 SEC_PERMITTED_NAME_KEY, NULL, base, localized);
3306 appendGeneralNameProperty(base, &derGS.generalName, localized);
3307 CFRelease(base);
3308 }
3309 }
3310 require_quiet(drtn == DR_EndOfSequence, badDER);
3311 }
3312 if (nc.excludedSubtrees.length) {
3313 DERSequence gsSeq;
3314 require_noerr_quiet(DERDecodeSeqContentInit(&nc.excludedSubtrees, &gsSeq), badDER);
3315 DERDecodedInfo gsContent;
3316 while ((drtn = DERDecodeSeqNext(&gsSeq, &gsContent)) == DR_Success) {
3317 DERGeneralSubtree derGS;
3318 require_quiet(gsContent.tag==ASN1_CONSTR_SEQUENCE, badDER);
3319 drtn = DERParseSequenceContent(&gsContent.content,
3320 DERNumGeneralSubtreeItemSpecs,
3321 DERGeneralSubtreeItemSpecs,
3322 &derGS, sizeof(derGS));
3323 require_noerr_quiet(drtn, badDER);
3324 if (derGS.minimum.length) {
3325 appendIntegerProperty(properties, SEC_EXCLUDED_MINIMUM_KEY,
3326 &derGS.minimum, localized);
3327 }
3328 if (derGS.maximum.length) {
3329 appendIntegerProperty(properties, SEC_EXCLUDED_MAXIMUM_KEY,
3330 &derGS.maximum, localized);
3331 }
3332 if (derGS.generalName.length) {
3333 CFMutableArrayRef base = CFArrayCreateMutable(allocator, 0,
3334 &kCFTypeArrayCallBacks);
3335 appendProperty(properties, kSecPropertyTypeSection,
3336 SEC_EXCLUDED_NAME_KEY, NULL, base, localized);
3337 appendGeneralNameProperty(base, &derGS.generalName, localized);
3338 CFRelease(base);
3339 }
3340 }
3341 require_quiet(drtn == DR_EndOfSequence, badDER);
3342 }
3343
3344 return;
3345 badDER:
3346 appendInvalidProperty(properties, SEC_NAME_CONSTRAINTS_KEY,
3347 extnValue, localized);
3348 }
3349
3350 /*
3351 CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
3352
3353 DistributionPoint ::= SEQUENCE {
3354 distributionPoint [0] DistributionPointName OPTIONAL,
3355 reasons [1] ReasonFlags OPTIONAL,
3356 cRLIssuer [2] GeneralNames OPTIONAL }
3357
3358 DistributionPointName ::= CHOICE {
3359 fullName [0] GeneralNames,
3360 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
3361
3362 ReasonFlags ::= BIT STRING {
3363 unused (0),
3364 keyCompromise (1),
3365 cACompromise (2),
3366 affiliationChanged (3),
3367 superseded (4),
3368 cessationOfOperation (5),
3369 certificateHold (6),
3370 privilegeWithdrawn (7),
3371 aACompromise (8) }
3372 */
3373 static void appendCrlDistributionPoints(CFMutableArrayRef properties,
3374 const DERItem *extnValue, bool localized) {
3375 CFAllocatorRef allocator = CFGetAllocator(properties);
3376 DERTag tag;
3377 DERSequence dpSeq;
3378 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &dpSeq);
3379 require_noerr_quiet(drtn, badDER);
3380 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3381 DERDecodedInfo dpSeqContent;
3382 while ((drtn = DERDecodeSeqNext(&dpSeq, &dpSeqContent)) == DR_Success) {
3383 require_quiet(dpSeqContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3384 DERDistributionPoint dp;
3385 drtn = DERParseSequenceContent(&dpSeqContent.content,
3386 DERNumDistributionPointItemSpecs,
3387 DERDistributionPointItemSpecs,
3388 &dp, sizeof(dp));
3389 require_noerr_quiet(drtn, badDER);
3390 if (dp.distributionPoint.length) {
3391 DERDecodedInfo distributionPointName;
3392 drtn = DERDecodeItem(&dp.distributionPoint, &distributionPointName);
3393 require_noerr_quiet(drtn, badDER);
3394 if (distributionPointName.tag ==
3395 (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0)) {
3396 /* Full Name */
3397 appendGeneralNamesContent(properties,
3398 &distributionPointName.content, localized);
3399 } else if (distributionPointName.tag ==
3400 (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1)) {
3401 CFArrayRef rdn_props = createPropertiesForRDNContent(allocator,
3402 &dp.reasons, localized);
3403 appendProperty(properties, kSecPropertyTypeSection,
3404 SEC_NAME_REL_CRL_ISSUER_KEY, NULL, rdn_props, localized);
3405 CFRelease(rdn_props);
3406 } else {
3407 goto badDER;
3408 }
3409 }
3410 if (dp.reasons.length) {
3411 static const CFStringRef reasonNames[] = {
3412 SEC_UNUSED_KEY,
3413 SEC_KEY_COMPROMISE_KEY,
3414 SEC_CA_COMPROMISE_KEY,
3415 SEC_AFFILIATION_CHANGED_KEY,
3416 SEC_SUPERSEDED_KEY,
3417 SEC_CESSATION_OF_OPER_KEY,
3418 SEC_CERTIFICATE_HOLD_KEY,
3419 SEC_PRIV_WITHDRAWN_KEY,
3420 SEC_AA_COMPROMISE_KEY
3421 };
3422 appendBitStringContentNames(properties, SEC_REASONS_KEY,
3423 &dp.reasons,
3424 reasonNames, array_size(reasonNames), localized);
3425 }
3426 if (dp.cRLIssuer.length) {
3427 CFMutableArrayRef crlIssuer = CFArrayCreateMutable(allocator, 0,
3428 &kCFTypeArrayCallBacks);
3429 appendProperty(properties, kSecPropertyTypeSection,
3430 SEC_CRL_ISSUER_KEY, NULL, crlIssuer, localized);
3431 CFRelease(crlIssuer);
3432 appendGeneralNames(crlIssuer, &dp.cRLIssuer, localized);
3433 }
3434 }
3435 require_quiet(drtn == DR_EndOfSequence, badDER);
3436 return;
3437 badDER:
3438 appendInvalidProperty(properties, SEC_CRL_DISTR_POINTS_KEY,
3439 extnValue, localized);
3440 }
3441
3442 /*
3443 Decode a sequence of integers into a comma separated list of ints.
3444 */
3445 static void appendIntegerSequenceContent(CFMutableArrayRef properties,
3446 CFStringRef label, const DERItem *intSequenceContent,
3447 bool localized) {
3448 CFAllocatorRef allocator = CFGetAllocator(properties);
3449 DERSequence intSeq;
3450 CFStringRef fmt = NULL, value = NULL, intDesc = NULL, v = NULL;
3451 DERReturn drtn = DERDecodeSeqContentInit(intSequenceContent, &intSeq);
3452 require_noerr_quiet(drtn, badDER);
3453 DERDecodedInfo intContent;
3454 fmt = (localized) ?
3455 SecCopyCertString(SEC_STRING_LIST_KEY) : SEC_STRING_LIST_KEY;
3456 require_quiet(fmt, badDER);
3457 while ((drtn = DERDecodeSeqNext(&intSeq, &intContent)) == DR_Success) {
3458 require_quiet(intContent.tag == ASN1_INTEGER, badDER);
3459 intDesc = copyIntegerContentDescription(
3460 allocator, &intContent.content);
3461 require_quiet(intDesc, badDER);
3462 if (value) {
3463 v = CFStringCreateWithFormat(allocator, NULL, fmt, value, intDesc);
3464 CFReleaseNull(value);
3465 require_quiet(v, badDER);
3466 value = v;
3467 } else {
3468 value = CFStringCreateMutableCopy(allocator, 0, intDesc);
3469 require_quiet(value, badDER);
3470 }
3471 CFReleaseNull(intDesc);
3472 }
3473 CFReleaseNull(fmt);
3474 require_quiet(drtn == DR_EndOfSequence, badDER);
3475 if (value) {
3476 appendProperty(properties, kSecPropertyTypeString, label, NULL,
3477 value, localized);
3478 CFRelease(value);
3479 return;
3480 }
3481 /* DROPTHOUGH if !value. */
3482 badDER:
3483 CFReleaseNull(fmt);
3484 CFReleaseNull(intDesc);
3485 CFReleaseNull(value);
3486 appendInvalidProperty(properties, label, intSequenceContent, localized);
3487 }
3488
3489 static void appendCertificatePolicies(CFMutableArrayRef properties,
3490 const DERItem *extnValue, bool localized) {
3491 CFAllocatorRef allocator = CFGetAllocator(properties);
3492 CFStringRef piLabel = NULL, piFmt = NULL, lpiLabel = NULL;
3493 CFStringRef pqLabel = NULL, pqFmt = NULL, lpqLabel = NULL;
3494 DERTag tag;
3495 DERSequence piSeq;
3496 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &piSeq);
3497 require_noerr_quiet(drtn, badDER);
3498 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3499 DERDecodedInfo piContent;
3500 int pin = 1;
3501 while ((drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) {
3502 require_quiet(piContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3503 DERPolicyInformation pi;
3504 drtn = DERParseSequenceContent(&piContent.content,
3505 DERNumPolicyInformationItemSpecs,
3506 DERPolicyInformationItemSpecs,
3507 &pi, sizeof(pi));
3508 require_noerr_quiet(drtn, badDER);
3509 piLabel = CFStringCreateWithFormat(allocator, NULL,
3510 SEC_POLICY_IDENTIFIER_KEY, pin);
3511 require_quiet(piLabel, badDER);
3512 piFmt = (localized) ?
3513 SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY) : SEC_POLICY_IDENTIFIER_KEY;
3514 require_quiet(piFmt, badDER);
3515 lpiLabel = CFStringCreateWithFormat(allocator, NULL, piFmt, pin++);
3516 require_quiet(lpiLabel, badDER);
3517 CFReleaseNull(piFmt);
3518 appendOIDProperty(properties, piLabel, lpiLabel,
3519 &pi.policyIdentifier, localized);
3520 CFReleaseNull(piLabel);
3521 CFReleaseNull(lpiLabel);
3522 if (pi.policyQualifiers.length == 0)
3523 continue;
3524
3525 DERSequence pqSeq;
3526 drtn = DERDecodeSeqContentInit(&pi.policyQualifiers, &pqSeq);
3527 require_noerr_quiet(drtn, badDER);
3528 DERDecodedInfo pqContent;
3529 int pqn = 1;
3530 while ((drtn = DERDecodeSeqNext(&pqSeq, &pqContent)) == DR_Success) {
3531 DERPolicyQualifierInfo pqi;
3532 drtn = DERParseSequenceContent(&pqContent.content,
3533 DERNumPolicyQualifierInfoItemSpecs,
3534 DERPolicyQualifierInfoItemSpecs,
3535 &pqi, sizeof(pqi));
3536 require_noerr_quiet(drtn, badDER);
3537 DERDecodedInfo qualifierContent;
3538 drtn = DERDecodeItem(&pqi.qualifier, &qualifierContent);
3539 require_noerr_quiet(drtn, badDER);
3540 pqLabel = CFStringCreateWithFormat(allocator, NULL,
3541 SEC_POLICY_QUALIFIER_KEY, pqn);
3542 require_quiet(pqLabel, badDER);
3543 pqFmt = (localized) ?
3544 SecCopyCertString(SEC_POLICY_QUALIFIER_KEY) : SEC_POLICY_QUALIFIER_KEY;
3545 require_quiet(pqFmt, badDER);
3546 lpqLabel = CFStringCreateWithFormat(allocator, NULL, pqFmt, pqn++);
3547 require_quiet(lpqLabel, badDER);
3548 CFReleaseNull(pqFmt);
3549 appendOIDProperty(properties, pqLabel, lpqLabel,
3550 &pqi.policyQualifierID, localized);
3551 CFReleaseNull(pqLabel);
3552 CFReleaseNull(lpqLabel);
3553 if (DEROidCompare(&oidQtCps, &pqi.policyQualifierID)) {
3554 require_quiet(qualifierContent.tag == ASN1_IA5_STRING, badDER);
3555 appendURLContentProperty(properties, SEC_CPS_URI_KEY,
3556 &qualifierContent.content, localized);
3557 } else if (DEROidCompare(&oidQtUNotice, &pqi.policyQualifierID)) {
3558 require_quiet(qualifierContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3559 DERUserNotice un;
3560 drtn = DERParseSequenceContent(&qualifierContent.content,
3561 DERNumUserNoticeItemSpecs,
3562 DERUserNoticeItemSpecs,
3563 &un, sizeof(un));
3564 require_noerr_quiet(drtn, badDER);
3565 if (un.noticeRef.length) {
3566 DERNoticeReference nr;
3567 drtn = DERParseSequenceContent(&un.noticeRef,
3568 DERNumNoticeReferenceItemSpecs,
3569 DERNoticeReferenceItemSpecs,
3570 &nr, sizeof(nr));
3571 require_noerr_quiet(drtn, badDER);
3572 appendDERThingProperty(properties,
3573 SEC_ORGANIZATION_KEY, NULL,
3574 &nr.organization, localized);
3575 appendIntegerSequenceContent(properties,
3576 SEC_NOTICE_NUMBERS_KEY, &nr.noticeNumbers, localized);
3577 }
3578 if (un.explicitText.length) {
3579 appendDERThingProperty(properties, SEC_EXPLICIT_TEXT_KEY,
3580 NULL, &un.explicitText, localized);
3581 }
3582 } else {
3583 appendUnparsedProperty(properties, SEC_QUALIFIER_KEY, NULL,
3584 &pqi.qualifier, localized);
3585 }
3586 }
3587 require_quiet(drtn == DR_EndOfSequence, badDER);
3588 }
3589 require_quiet(drtn == DR_EndOfSequence, badDER);
3590 return;
3591 badDER:
3592 CFReleaseNull(piFmt);
3593 CFReleaseNull(piLabel);
3594 CFReleaseNull(lpiLabel);
3595 CFReleaseNull(pqFmt);
3596 CFReleaseNull(pqLabel);
3597 CFReleaseNull(lpqLabel);
3598 appendInvalidProperty(properties, SEC_CERT_POLICIES_KEY,
3599 extnValue, localized);
3600 }
3601
3602 static void appendSubjectKeyIdentifier(CFMutableArrayRef properties,
3603 const DERItem *extnValue, bool localized) {
3604 DERReturn drtn;
3605 DERDecodedInfo keyIdentifier;
3606 drtn = DERDecodeItem(extnValue, &keyIdentifier);
3607 require_noerr_quiet(drtn, badDER);
3608 require_quiet(keyIdentifier.tag == ASN1_OCTET_STRING, badDER);
3609 appendDataProperty(properties, SEC_KEY_IDENTIFIER_KEY, NULL,
3610 &keyIdentifier.content, localized);
3611
3612 return;
3613 badDER:
3614 appendInvalidProperty(properties, SEC_SUBJ_KEY_ID_KEY,
3615 extnValue, localized);
3616 }
3617
3618 /*
3619 AuthorityKeyIdentifier ::= SEQUENCE {
3620 keyIdentifier [0] KeyIdentifier OPTIONAL,
3621 authorityCertIssuer [1] GeneralNames OPTIONAL,
3622 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
3623 -- authorityCertIssuer and authorityCertSerialNumber MUST both
3624 -- be present or both be absent
3625
3626 KeyIdentifier ::= OCTET STRING
3627 */
3628 static void appendAuthorityKeyIdentifier(CFMutableArrayRef properties,
3629 const DERItem *extnValue, bool localized) {
3630 DERAuthorityKeyIdentifier akid;
3631 DERReturn drtn;
3632 drtn = DERParseSequence(extnValue,
3633 DERNumAuthorityKeyIdentifierItemSpecs,
3634 DERAuthorityKeyIdentifierItemSpecs,
3635 &akid, sizeof(akid));
3636 require_noerr_quiet(drtn, badDER);
3637 if (akid.keyIdentifier.length) {
3638 appendDataProperty(properties, SEC_KEY_IDENTIFIER_KEY, NULL,
3639 &akid.keyIdentifier, localized);
3640 }
3641 if (akid.authorityCertIssuer.length ||
3642 akid.authorityCertSerialNumber.length) {
3643 require_quiet(akid.authorityCertIssuer.length &&
3644 akid.authorityCertSerialNumber.length, badDER);
3645 /* Perhaps put in a subsection called Authority Certificate Issuer. */
3646 appendGeneralNamesContent(properties,
3647 &akid.authorityCertIssuer, localized);
3648 appendIntegerProperty(properties, SEC_AUTH_CERT_SERIAL_KEY,
3649 &akid.authorityCertSerialNumber, localized);
3650 }
3651
3652 return;
3653 badDER:
3654 appendInvalidProperty(properties, SEC_AUTHORITY_KEY_ID_KEY,
3655 extnValue, localized);
3656 }
3657
3658 /*
3659 PolicyConstraints ::= SEQUENCE {
3660 requireExplicitPolicy [0] SkipCerts OPTIONAL,
3661 inhibitPolicyMapping [1] SkipCerts OPTIONAL }
3662
3663 SkipCerts ::= INTEGER (0..MAX)
3664 */
3665 static void appendPolicyConstraints(CFMutableArrayRef properties,
3666 const DERItem *extnValue, bool localized) {
3667 DERPolicyConstraints pc;
3668 DERReturn drtn;
3669 drtn = DERParseSequence(extnValue,
3670 DERNumPolicyConstraintsItemSpecs,
3671 DERPolicyConstraintsItemSpecs,
3672 &pc, sizeof(pc));
3673 require_noerr_quiet(drtn, badDER);
3674 if (pc.requireExplicitPolicy.length) {
3675 appendIntegerProperty(properties, SEC_REQUIRE_EXPL_POLICY_KEY,
3676 &pc.requireExplicitPolicy, localized);
3677 }
3678 if (pc.inhibitPolicyMapping.length) {
3679 appendIntegerProperty(properties, SEC_INHIBIT_POLICY_MAP_KEY,
3680 &pc.inhibitPolicyMapping, localized);
3681 }
3682
3683 return;
3684
3685 badDER:
3686 appendInvalidProperty(properties, SEC_POLICY_CONSTRAINTS_KEY,
3687 extnValue, localized);
3688 }
3689
3690 /*
3691 extendedKeyUsage EXTENSION ::= {
3692 SYNTAX SEQUENCE SIZE (1..MAX) OF KeyPurposeId
3693 IDENTIFIED BY id-ce-extKeyUsage }
3694
3695 KeyPurposeId ::= OBJECT IDENTIFIER
3696 */
3697 static void appendExtendedKeyUsage(CFMutableArrayRef properties,
3698 const DERItem *extnValue, bool localized) {
3699 DERTag tag;
3700 DERSequence derSeq;
3701 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &derSeq);
3702 require_noerr_quiet(drtn, badDER);
3703 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3704 DERDecodedInfo currDecoded;
3705 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
3706 require_quiet(currDecoded.tag == ASN1_OBJECT_ID, badDER);
3707 appendOIDProperty(properties, SEC_PURPOSE_KEY, NULL,
3708 &currDecoded.content, localized);
3709 }
3710 require_quiet(drtn == DR_EndOfSequence, badDER);
3711 return;
3712 badDER:
3713 appendInvalidProperty(properties, SEC_EXTENDED_KEY_USAGE_KEY,
3714 extnValue, localized);
3715 }
3716
3717 /*
3718 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
3719
3720 AuthorityInfoAccessSyntax ::=
3721 SEQUENCE SIZE (1..MAX) OF AccessDescription
3722
3723 AccessDescription ::= SEQUENCE {
3724 accessMethod OBJECT IDENTIFIER,
3725 accessLocation GeneralName }
3726
3727 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
3728
3729 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
3730
3731 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
3732 */
3733 static void appendInfoAccess(CFMutableArrayRef properties,
3734 const DERItem *extnValue, bool localized) {
3735 DERTag tag;
3736 DERSequence adSeq;
3737 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &adSeq);
3738 require_noerr_quiet(drtn, badDER);
3739 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3740 DERDecodedInfo adContent;
3741 while ((drtn = DERDecodeSeqNext(&adSeq, &adContent)) == DR_Success) {
3742 require_quiet(adContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3743 DERAccessDescription ad;
3744 drtn = DERParseSequenceContent(&adContent.content,
3745 DERNumAccessDescriptionItemSpecs,
3746 DERAccessDescriptionItemSpecs,
3747 &ad, sizeof(ad));
3748 require_noerr_quiet(drtn, badDER);
3749 appendOIDProperty(properties, SEC_ACCESS_METHOD_KEY, NULL,
3750 &ad.accessMethod, localized);
3751 //TODO: Do something with SEC_ACCESS_LOCATION_KEY
3752 appendGeneralNameProperty(properties, &ad.accessLocation, localized);
3753 }
3754 require_quiet(drtn == DR_EndOfSequence, badDER);
3755 return;
3756 badDER:
3757 appendInvalidProperty(properties, SEC_AUTH_INFO_ACCESS_KEY,
3758 extnValue, localized);
3759 }
3760
3761 static void appendNetscapeCertType(CFMutableArrayRef properties,
3762 const DERItem *extnValue, bool localized) {
3763 static const CFStringRef certTypes[] = {
3764 SEC_SSL_CLIENT_KEY,
3765 SEC_SSL_SERVER_KEY,
3766 SEC_SMIME_KEY,
3767 SEC_OBJECT_SIGNING_KEY,
3768 SEC_RESERVED_KEY,
3769 SEC_SSL_CA_KEY,
3770 SEC_SMIME_CA_KEY,
3771 SEC_OBJECT_SIGNING_CA_KEY
3772 };
3773 appendBitStringNames(properties, SEC_USAGE_KEY, extnValue,
3774 certTypes, array_size(certTypes), localized);
3775 }
3776
3777 static bool appendPrintableDERSequence(CFMutableArrayRef properties,
3778 CFStringRef label, const DERItem *sequence, bool localized) {
3779 DERTag tag;
3780 DERSequence derSeq;
3781 DERReturn drtn = DERDecodeSeqInit(sequence, &tag, &derSeq);
3782 require_noerr_quiet(drtn, badSequence);
3783 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badSequence);
3784 DERDecodedInfo currDecoded;
3785 bool appendedSomething = false;
3786 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
3787 switch (currDecoded.tag)
3788 {
3789 case 0: // 0
3790 case ASN1_SEQUENCE: // 16
3791 case ASN1_SET: // 17
3792 // skip constructed object lengths
3793 break;
3794
3795 case ASN1_UTF8_STRING: // 12
3796 case ASN1_NUMERIC_STRING: // 18
3797 case ASN1_PRINTABLE_STRING: // 19
3798 case ASN1_T61_STRING: // 20, also ASN1_TELETEX_STRING
3799 case ASN1_VIDEOTEX_STRING: // 21
3800 case ASN1_IA5_STRING: // 22
3801 case ASN1_GRAPHIC_STRING: // 25
3802 case ASN1_VISIBLE_STRING: // 26, also ASN1_ISO646_STRING
3803 case ASN1_GENERAL_STRING: // 27
3804 case ASN1_UNIVERSAL_STRING: // 28
3805 {
3806 CFStringRef string =
3807 copyDERThingContentDescription(CFGetAllocator(properties),
3808 currDecoded.tag, &currDecoded.content, false, localized);
3809 require_quiet(string, badSequence);
3810
3811 appendProperty(properties, kSecPropertyTypeString, label, NULL,
3812 string, localized);
3813 CFReleaseNull(string);
3814 appendedSomething = true;
3815 break;
3816 }
3817 default:
3818 break;
3819 }
3820 }
3821 require_quiet(drtn == DR_EndOfSequence, badSequence);
3822 return appendedSomething;
3823 badSequence:
3824 return false;
3825 }
3826
3827 static void appendExtension(CFMutableArrayRef parent,
3828 const SecCertificateExtension *extn,
3829 bool localized) {
3830 CFAllocatorRef allocator = CFGetAllocator(parent);
3831 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
3832 &kCFTypeArrayCallBacks);
3833 const DERItem
3834 *extnID = &extn->extnID,
3835 *extnValue = &extn->extnValue;
3836 CFStringRef label = NULL;
3837 CFStringRef localizedLabel = NULL;
3838
3839 appendBoolProperty(properties, SEC_CRITICAL_KEY, extn->critical, localized);
3840 require_quiet(extnID, xit);
3841
3842 bool handled = true;
3843 /* Extensions that we know how to handle ourselves... */
3844 if (extnID->length == oidSubjectKeyIdentifier.length &&
3845 !memcmp(extnID->data, oidSubjectKeyIdentifier.data, extnID->length - 1))
3846 {
3847 switch (extnID->data[extnID->length - 1]) {
3848 case 14: /* SubjectKeyIdentifier id-ce 14 */
3849 appendSubjectKeyIdentifier(properties, extnValue, localized);
3850 break;
3851 case 15: /* KeyUsage id-ce 15 */
3852 appendKeyUsage(properties, extnValue, localized);
3853 break;
3854 case 16: /* PrivateKeyUsagePeriod id-ce 16 */
3855 appendPrivateKeyUsagePeriod(properties, extnValue, localized);
3856 break;
3857 case 17: /* SubjectAltName id-ce 17 */
3858 case 18: /* IssuerAltName id-ce 18 */
3859 appendGeneralNames(properties, extnValue, localized);
3860 break;
3861 case 19: /* BasicConstraints id-ce 19 */
3862 appendBasicConstraints(properties, extnValue, localized);
3863 break;
3864 case 30: /* NameConstraints id-ce 30 */
3865 appendNameConstraints(properties, extnValue, localized);
3866 break;
3867 case 31: /* CRLDistributionPoints id-ce 31 */
3868 appendCrlDistributionPoints(properties, extnValue, localized);
3869 break;
3870 case 32: /* CertificatePolicies id-ce 32 */
3871 appendCertificatePolicies(properties, extnValue, localized);
3872 break;
3873 case 33: /* PolicyMappings id-ce 33 */
3874 handled = false;
3875 break;
3876 case 35: /* AuthorityKeyIdentifier id-ce 35 */
3877 appendAuthorityKeyIdentifier(properties, extnValue, localized);
3878 break;
3879 case 36: /* PolicyConstraints id-ce 36 */
3880 appendPolicyConstraints(properties, extnValue, localized);
3881 break;
3882 case 37: /* ExtKeyUsage id-ce 37 */
3883 appendExtendedKeyUsage(properties, extnValue, localized);
3884 break;
3885 case 46: /* FreshestCRL id-ce 46 */
3886 handled = false;
3887 break;
3888 case 54: /* InhibitAnyPolicy id-ce 54 */
3889 handled = false;
3890 break;
3891 default:
3892 handled = false;
3893 break;
3894 }
3895 } else if (extnID->length == oidAuthorityInfoAccess.length &&
3896 !memcmp(extnID->data, oidAuthorityInfoAccess.data, extnID->length - 1))
3897 {
3898 switch (extnID->data[extnID->length - 1]) {
3899 case 1: /* AuthorityInfoAccess id-pe 1 */
3900 appendInfoAccess(properties, extnValue, localized);
3901 break;
3902 case 3: /* QCStatements id-pe 3 */
3903 handled = false;
3904 break;
3905 case 11: /* SubjectInfoAccess id-pe 11 */
3906 appendInfoAccess(properties, extnValue, localized);
3907 break;
3908 default:
3909 handled = false;
3910 break;
3911 }
3912 } else if (DEROidCompare(extnID, &oidNetscapeCertType)) {
3913 /* 2.16.840.1.113730.1.1 netscape 1 1 */
3914 appendNetscapeCertType(properties, extnValue, localized);
3915 } else {
3916 handled = false;
3917 }
3918
3919 if (!handled) {
3920 /* Try to parse and display printable string(s). */
3921 if (appendPrintableDERSequence(properties, SEC_DATA_KEY, extnValue, localized)) {
3922 /* Nothing to do here appendPrintableDERSequence did the work. */
3923 } else {
3924 /* Couldn't parse extension; dump the raw unparsed data as hex. */
3925 appendUnparsedProperty(properties, SEC_DATA_KEY, NULL, extnValue, localized);
3926 }
3927 }
3928 label = SecDERItemCopyOIDDecimalRepresentation(allocator, extnID);
3929 localizedLabel = copyOidDescription(allocator, extnID, localized);
3930 appendProperty(parent, kSecPropertyTypeSection, label, localizedLabel,
3931 properties, localized);
3932 xit:
3933 CFReleaseSafe(localizedLabel);
3934 CFReleaseSafe(label);
3935 CFReleaseSafe(properties);
3936 }
3937
3938 /* Different types of summary types from least desired to most desired. */
3939 enum SummaryType {
3940 kSummaryTypeNone,
3941 kSummaryTypePrintable,
3942 kSummaryTypeOrganizationName,
3943 kSummaryTypeOrganizationalUnitName,
3944 kSummaryTypeCommonName,
3945 };
3946
3947 struct Summary {
3948 enum SummaryType type;
3949 CFStringRef summary;
3950 CFStringRef description;
3951 };
3952
3953 static OSStatus obtainSummaryFromX501Name(void *context,
3954 const DERItem *type, const DERItem *value, CFIndex rdnIX,
3955 bool localized) {
3956 struct Summary *summary = (struct Summary *)context;
3957 enum SummaryType stype = kSummaryTypeNone;
3958 CFStringRef string = NULL;
3959 if (DEROidCompare(type, &oidCommonName)) {
3960 stype = kSummaryTypeCommonName;
3961 } else if (DEROidCompare(type, &oidOrganizationalUnitName)) {
3962 stype = kSummaryTypeOrganizationalUnitName;
3963 } else if (DEROidCompare(type, &oidOrganizationName)) {
3964 stype = kSummaryTypeOrganizationName;
3965 } else if (DEROidCompare(type, &oidDescription)) {
3966 string = copyDERThingDescription(kCFAllocatorDefault, value,
3967 true, localized);
3968 if (string) {
3969 if (summary->description) {
3970 CFStringRef fmt = (localized) ?
3971 SecCopyCertString(SEC_STRING_LIST_KEY) : SEC_STRING_LIST_KEY;
3972 CFStringRef newDescription = CFStringCreateWithFormat(kCFAllocatorDefault,
3973 NULL, fmt, string, summary->description);
3974 CFRelease(fmt);
3975 CFRelease(summary->description);
3976 summary->description = newDescription;
3977 } else {
3978 summary->description = string;
3979 CFRetain(string);
3980 }
3981 stype = kSummaryTypePrintable;
3982 }
3983 } else {
3984 stype = kSummaryTypePrintable;
3985 }
3986
3987 /* Build a string with all instances of the most desired
3988 component type in reverse order encountered comma separated list,
3989 The order of desirability is defined by enum SummaryType. */
3990 if (summary->type <= stype) {
3991 if (!string) {
3992 string = copyDERThingDescription(kCFAllocatorDefault, value,
3993 true, localized);
3994 }
3995 if (string) {
3996 if (summary->type == stype) {
3997 CFStringRef fmt = (localized) ?
3998 SecCopyCertString(SEC_STRING_LIST_KEY) : SEC_STRING_LIST_KEY;
3999 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault,
4000 NULL, fmt, string, summary->summary);
4001 CFRelease(fmt);
4002 CFRelease(string);
4003 string = newSummary;
4004 } else {
4005 summary->type = stype;
4006 }
4007 CFReleaseSafe(summary->summary);
4008 summary->summary = string;
4009 }
4010 } else {
4011 CFReleaseSafe(string);
4012 }
4013
4014 return errSecSuccess;
4015 }
4016
4017 CFStringRef SecCertificateCopySubjectSummary(SecCertificateRef certificate) {
4018 struct Summary summary = {};
4019 OSStatus status = parseX501NameContent(&certificate->_subject, &summary, obtainSummaryFromX501Name, true);
4020 if (status != errSecSuccess) {
4021 return NULL;
4022 }
4023 /* If we found a description and a common name we change the summary to
4024 CommonName (Description). */
4025 if (summary.description) {
4026 if (summary.type == kSummaryTypeCommonName) {
4027 CFStringRef fmt = SecCopyCertString(SEC_COMMON_NAME_DESC_KEY);
4028 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, summary.summary, summary.description);
4029 CFRelease(fmt);
4030 CFRelease(summary.summary);
4031 summary.summary = newSummary;
4032 }
4033 CFRelease(summary.description);
4034 }
4035
4036 if (!summary.summary) {
4037 /* If we didn't find a suitable printable string in the subject at all, we try
4038 the first email address in the certificate instead. */
4039 CFArrayRef names = SecCertificateCopyRFC822Names(certificate);
4040 if (!names) {
4041 /* If we didn't find any email addresses in the certificate, we try finding
4042 a DNS name instead. */
4043 names = SecCertificateCopyDNSNames(certificate);
4044 }
4045 if (names) {
4046 summary.summary = CFArrayGetValueAtIndex(names, 0);
4047 CFRetain(summary.summary);
4048 CFRelease(names);
4049 }
4050 }
4051
4052 return summary.summary;
4053 }
4054
4055 CFStringRef SecCertificateCopyIssuerSummary(SecCertificateRef certificate) {
4056 struct Summary summary = {};
4057 OSStatus status = parseX501NameContent(&certificate->_issuer, &summary, obtainSummaryFromX501Name, true);
4058 if (status != errSecSuccess) {
4059 return NULL;
4060 }
4061 /* If we found a description and a common name we change the summary to
4062 CommonName (Description). */
4063 if (summary.description) {
4064 if (summary.type == kSummaryTypeCommonName) {
4065 CFStringRef fmt = SecCopyCertString(SEC_COMMON_NAME_DESC_KEY);
4066 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, summary.summary, summary.description);
4067 CFRelease(fmt);
4068 CFRelease(summary.summary);
4069 summary.summary = newSummary;
4070 }
4071 CFRelease(summary.description);
4072 }
4073
4074 return summary.summary;
4075 }
4076
4077 /* Return the earliest date on which all certificates in this chain are still
4078 valid. */
4079 static CFAbsoluteTime SecCertificateGetChainsLastValidity(
4080 SecCertificateRef certificate) {
4081 CFAbsoluteTime earliest = certificate->_notAfter;
4082 #if 0
4083 while (certificate->_parent) {
4084 certificate = certificate->_parent;
4085 if (earliest > certificate->_notAfter)
4086 earliest = certificate->_notAfter;
4087 }
4088 #endif
4089
4090 return earliest;
4091 }
4092
4093 /* Return the latest date on which all certificates in this chain will be
4094 valid. */
4095 static CFAbsoluteTime SecCertificateGetChainsFirstValidity(
4096 SecCertificateRef certificate) {
4097 CFAbsoluteTime latest = certificate->_notBefore;
4098 #if 0
4099 while (certificate->_parent) {
4100 certificate = certificate->_parent;
4101 if (latest < certificate->_notBefore)
4102 latest = certificate->_notBefore;
4103 }
4104 #endif
4105
4106 return latest;
4107 }
4108
4109 bool SecCertificateIsValid(SecCertificateRef certificate,
4110 CFAbsoluteTime verifyTime) {
4111 return certificate && certificate->_notBefore <= verifyTime &&
4112 verifyTime <= certificate->_notAfter;
4113 }
4114
4115 CFIndex SecCertificateVersion(SecCertificateRef certificate) {
4116 return certificate->_version + 1;
4117 }
4118
4119 CFAbsoluteTime SecCertificateNotValidBefore(SecCertificateRef certificate) {
4120 return certificate->_notBefore;
4121 }
4122
4123 CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate) {
4124 return certificate->_notAfter;
4125 }
4126
4127 CFMutableArrayRef SecCertificateCopySummaryProperties(
4128 SecCertificateRef certificate, CFAbsoluteTime verifyTime) {
4129 CFAllocatorRef allocator = CFGetAllocator(certificate);
4130 CFMutableArrayRef summary = CFArrayCreateMutable(allocator, 0,
4131 &kCFTypeArrayCallBacks);
4132 bool localized = true;
4133
4134 /* First we put the subject summary name. */
4135 CFStringRef ssummary = SecCertificateCopySubjectSummary(certificate);
4136 if (ssummary) {
4137 appendProperty(summary, kSecPropertyTypeTitle,
4138 NULL, NULL, ssummary, localized);
4139 CFRelease(ssummary);
4140 }
4141
4142 /* Let see if this certificate is currently valid. */
4143 CFStringRef label;
4144 CFAbsoluteTime when;
4145 CFStringRef message;
4146 CFStringRef ptype;
4147 if (verifyTime > certificate->_notAfter) {
4148 label = SEC_EXPIRED_KEY;
4149 when = certificate->_notAfter;
4150 ptype = kSecPropertyTypeError;
4151 message = SEC_CERT_EXPIRED_KEY;
4152 } else if (certificate->_notBefore > verifyTime) {
4153 label = SEC_VALID_FROM_KEY;
4154 when = certificate->_notBefore;
4155 ptype = kSecPropertyTypeError;
4156 message = SEC_CERT_NOT_YET_VALID_KEY;
4157 } else {
4158 CFAbsoluteTime last = SecCertificateGetChainsLastValidity(certificate);
4159 CFAbsoluteTime first = SecCertificateGetChainsFirstValidity(certificate);
4160 if (verifyTime > last) {
4161 label = SEC_EXPIRED_KEY;
4162 when = last;
4163 ptype = kSecPropertyTypeError;
4164 message = SEC_ISSUER_EXPIRED_KEY;
4165 } else if (verifyTime < first) {
4166 label = SEC_VALID_FROM_KEY;
4167 when = first;
4168 ptype = kSecPropertyTypeError;
4169 message = SEC_ISSR_NOT_YET_VALID_KEY;
4170 } else {
4171 label = SEC_EXPIRES_KEY;
4172 when = certificate->_notAfter;
4173 ptype = kSecPropertyTypeSuccess;
4174 message = SEC_CERT_VALID_KEY;
4175 }
4176 }
4177
4178 appendDateProperty(summary, label, when, localized);
4179 CFStringRef lmessage = SecCopyCertString(message);
4180 appendProperty(summary, ptype, NULL, NULL, lmessage, localized);
4181 CFRelease(lmessage);
4182
4183 return summary;
4184 }
4185
4186 CFArrayRef SecCertificateCopyLegacyProperties(SecCertificateRef certificate) {
4187 /*
4188 This function replicates the content returned by SecCertificateCopyProperties
4189 prior to 10.12.4, providing stable return values for SecCertificateCopyValues.
4190 Unlike SecCertificateCopyProperties, it does not cache the result and
4191 assumes the caller will do so.
4192 */
4193 CFAllocatorRef allocator = CFGetAllocator(certificate);
4194 CFMutableArrayRef properties = CFArrayCreateMutable(allocator,
4195 0, &kCFTypeArrayCallBacks);
4196
4197 /* Subject Name */
4198 CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator,
4199 &certificate->_subject, false);
4200 appendProperty(properties, kSecPropertyTypeSection, CFSTR("Subject Name"),
4201 NULL, subject_plist, false);
4202 CFRelease(subject_plist);
4203
4204 /* Issuer Name */
4205 CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator,
4206 &certificate->_issuer, false);
4207 appendProperty(properties, kSecPropertyTypeSection, CFSTR("Issuer Name"),
4208 NULL, issuer_plist, false);
4209 CFRelease(issuer_plist);
4210
4211 /* Version */
4212 CFStringRef versionString = CFStringCreateWithFormat(allocator,
4213 NULL, CFSTR("%d"), certificate->_version + 1);
4214 appendProperty(properties, kSecPropertyTypeString, CFSTR("Version"),
4215 NULL, versionString, false);
4216 CFRelease(versionString);
4217
4218 /* Serial Number */
4219 if (certificate->_serialNum.length) {
4220 appendIntegerProperty(properties, CFSTR("Serial Number"),
4221 &certificate->_serialNum, false);
4222 }
4223
4224 /* Signature Algorithm */
4225 appendAlgorithmProperty(properties, CFSTR("Signature Algorithm"),
4226 &certificate->_tbsSigAlg, false);
4227
4228 /* Validity dates */
4229 appendDateProperty(properties, CFSTR("Not Valid Before"), certificate->_notBefore, false);
4230 appendDateProperty(properties, CFSTR("Not Valid After"), certificate->_notAfter, false);
4231
4232 if (certificate->_subjectUniqueID.length) {
4233 appendDataProperty(properties, CFSTR("Subject Unique ID"),
4234 NULL, &certificate->_subjectUniqueID, false);
4235 }
4236 if (certificate->_issuerUniqueID.length) {
4237 appendDataProperty(properties, CFSTR("Issuer Unique ID"),
4238 NULL, &certificate->_issuerUniqueID, false);
4239 }
4240
4241 /* Public Key Algorithm */
4242 appendAlgorithmProperty(properties, CFSTR("Public Key Algorithm"),
4243 &certificate->_algId, false);
4244
4245 /* Public Key Data */
4246 appendDataProperty(properties, CFSTR("Public Key Data"),
4247 NULL, &certificate->_pubKeyDER, false);
4248
4249 /* Signature */
4250 appendDataProperty(properties, CFSTR("Signature"),
4251 NULL, &certificate->_signature, false);
4252
4253 /* Extensions */
4254 CFIndex ix;
4255 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
4256 appendExtension(properties, &certificate->_extensions[ix], false);
4257 }
4258
4259 /* Fingerprints */
4260 appendFingerprintsProperty(properties, CFSTR("Fingerprints"), certificate, false);
4261
4262 return properties;
4263 }
4264
4265 CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate) {
4266 if (!certificate->_properties) {
4267 CFAllocatorRef allocator = CFGetAllocator(certificate);
4268 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
4269 &kCFTypeArrayCallBacks);
4270 require_quiet(properties, out);
4271 bool localized = true;
4272
4273 /* First we put the Subject Name in the property list. */
4274 CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator,
4275 &certificate->_subject,
4276 localized);
4277 if (subject_plist) {
4278 appendProperty(properties, kSecPropertyTypeSection,
4279 SEC_SUBJECT_NAME_KEY, NULL, subject_plist, localized);
4280 }
4281 CFReleaseNull(subject_plist);
4282
4283 /* Next we put the Issuer Name in the property list. */
4284 CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator,
4285 &certificate->_issuer,
4286 localized);
4287 if (issuer_plist) {
4288 appendProperty(properties, kSecPropertyTypeSection,
4289 SEC_ISSUER_NAME_KEY, NULL, issuer_plist, localized);
4290 }
4291 CFReleaseNull(issuer_plist);
4292
4293 /* Version */
4294 CFStringRef fmt = SecCopyCertString(SEC_CERT_VERSION_VALUE_KEY);
4295 CFStringRef versionString = NULL;
4296 if (fmt) {
4297 versionString = CFStringCreateWithFormat(allocator, NULL, fmt,
4298 certificate->_version + 1);
4299 }
4300 CFReleaseNull(fmt);
4301 if (versionString) {
4302 appendProperty(properties, kSecPropertyTypeString,
4303 SEC_VERSION_KEY, NULL, versionString, localized);
4304 }
4305 CFReleaseNull(versionString);
4306
4307 /* Serial Number */
4308 appendSerialNumberProperty(properties, SEC_SERIAL_NUMBER_KEY, &certificate->_serialNum, localized);
4309
4310 /* Validity dates. */
4311 appendValidityPeriodProperty(properties, SEC_VALIDITY_PERIOD_KEY, certificate, localized);
4312
4313 if (certificate->_subjectUniqueID.length) {
4314 appendDataProperty(properties, SEC_SUBJECT_UNIQUE_ID_KEY, NULL,
4315 &certificate->_subjectUniqueID, localized);
4316 }
4317 if (certificate->_issuerUniqueID.length) {
4318 appendDataProperty(properties, SEC_ISSUER_UNIQUE_ID_KEY, NULL,
4319 &certificate->_issuerUniqueID, localized);
4320 }
4321
4322 appendPublicKeyProperty(properties, SEC_PUBLIC_KEY_KEY, certificate, localized);
4323
4324 CFIndex ix;
4325 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
4326 appendExtension(properties, &certificate->_extensions[ix], localized);
4327 }
4328
4329 /* Signature */
4330 appendSignatureProperty(properties, SEC_SIGNATURE_KEY, certificate, localized);
4331
4332 appendFingerprintsProperty(properties, SEC_FINGERPRINTS_KEY, certificate, localized);
4333
4334 certificate->_properties = properties;
4335 }
4336
4337 out:
4338 CFRetainSafe(certificate->_properties);
4339 return certificate->_properties;
4340 }
4341
4342 /* Unified serial number API */
4343 CFDataRef SecCertificateCopySerialNumberData(
4344 SecCertificateRef certificate,
4345 CFErrorRef *error)
4346 {
4347 if (!certificate) {
4348 if (error) {
4349 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidCertificate, NULL);
4350 }
4351 return NULL;
4352 }
4353 if (certificate->_serialNumber) {
4354 CFRetain(certificate->_serialNumber);
4355 }
4356 return certificate->_serialNumber;
4357 }
4358
4359 #if !TARGET_OS_OSX
4360 /* On iOS, the SecCertificateCopySerialNumber API takes one argument. */
4361 CFDataRef SecCertificateCopySerialNumber(
4362 SecCertificateRef certificate) {
4363 return SecCertificateCopySerialNumberData(certificate, NULL);
4364 }
4365 #endif
4366
4367 CFDataRef SecCertificateGetNormalizedIssuerContent(
4368 SecCertificateRef certificate) {
4369 return certificate->_normalizedIssuer;
4370 }
4371
4372 CFDataRef SecCertificateGetNormalizedSubjectContent(
4373 SecCertificateRef certificate) {
4374 return certificate->_normalizedSubject;
4375 }
4376
4377 /* Verify that certificate was signed by issuerKey. */
4378 OSStatus SecCertificateIsSignedBy(SecCertificateRef certificate,
4379 SecKeyRef issuerKey) {
4380 /* Setup algId in SecAsn1AlgId format. */
4381 SecAsn1AlgId algId;
4382 algId.algorithm.Length = certificate->_tbsSigAlg.oid.length;
4383 algId.algorithm.Data = certificate->_tbsSigAlg.oid.data;
4384 algId.parameters.Length = certificate->_tbsSigAlg.params.length;
4385 algId.parameters.Data = certificate->_tbsSigAlg.params.data;
4386
4387 /* RFC5280 4.1.1.2, 4.1.2.3 requires the actual signature algorithm
4388 must match the specified algorithm in the TBSCertificate. */
4389 bool sigAlgMatch = DEROidCompare(&certificate->_sigAlg.oid,
4390 &certificate->_tbsSigAlg.oid);
4391 if (!sigAlgMatch) {
4392 secwarning("Signature algorithm mismatch in certificate (see RFC5280 4.1.1.2)");
4393 }
4394
4395 CFErrorRef error = NULL;
4396 if (!sigAlgMatch ||
4397 !SecVerifySignatureWithPublicKey(issuerKey, &algId,
4398 certificate->_tbs.data, certificate->_tbs.length,
4399 certificate->_signature.data, certificate->_signature.length, &error))
4400 {
4401 #if !defined(NDEBUG)
4402 secdebug("verify", "signature verify failed: %" PRIdOSStatus, (error) ? (OSStatus)CFErrorGetCode(error) : errSecNotSigner);
4403 #endif
4404 CFReleaseSafe(error);
4405 return errSecNotSigner;
4406 }
4407
4408 return errSecSuccess;
4409 }
4410
4411 const DERItem * SecCertificateGetSubjectAltName(SecCertificateRef certificate) {
4412 if (!certificate->_subjectAltName) {
4413 return NULL;
4414 }
4415 return &certificate->_subjectAltName->extnValue;
4416 }
4417
4418 static bool convertIPAddress(CFStringRef name, CFDataRef *dataIP) {
4419 /* IPv4: 4 octets in decimal separated by dots. We don't support matching IPv6 already. */
4420 bool result = false;
4421 /* Check size */
4422 if (CFStringGetLength(name) < 7 || /* min size is #.#.#.# */
4423 CFStringGetLength(name) > 15) { /* max size is ###.###.###.### */
4424 return false;
4425 }
4426
4427 CFCharacterSetRef decimals = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("0123456789."));
4428 CFCharacterSetRef nonDecimals = CFCharacterSetCreateInvertedSet(NULL, decimals);
4429 CFMutableDataRef data = CFDataCreateMutable(NULL, 0);
4430 CFArrayRef parts = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR("."));
4431
4432 /* Check character set */
4433 if (CFStringFindCharacterFromSet(name, nonDecimals,
4434 CFRangeMake(0, CFStringGetLength(name)),
4435 kCFCompareForcedOrdering, NULL)) {
4436 goto out;
4437 }
4438
4439 /* Check number of labels */
4440 if (CFArrayGetCount(parts) != 4) {
4441 goto out;
4442 }
4443
4444 /* Check each label and convert */
4445 CFIndex i, count = CFArrayGetCount(parts);
4446 for (i = 0; i < count; i++) {
4447 CFStringRef octet = CFArrayGetValueAtIndex(parts, i);
4448 char *cString = CFStringToCString(octet);
4449 uint32_t value = atoi(cString);
4450 free(cString);
4451 if (value > 255) {
4452 goto out;
4453 } else {
4454 uint8_t byte = value;
4455 CFDataAppendBytes(data, &byte, 1);
4456 }
4457 }
4458 result = true;
4459 if (dataIP) {
4460 *dataIP = CFRetain(data);
4461 }
4462
4463 out:
4464 CFReleaseNull(data);
4465 CFReleaseNull(parts);
4466 CFReleaseNull(decimals);
4467 CFReleaseNull(nonDecimals);
4468 return result;
4469 }
4470
4471 static OSStatus appendIPAddressesFromGeneralNames(void *context,
4472 SecCEGeneralNameType gnType, const DERItem *generalName) {
4473 CFMutableArrayRef ipAddresses = (CFMutableArrayRef)context;
4474 if (gnType == GNT_IPAddress) {
4475 CFStringRef string = copyIPAddressContentDescription(
4476 kCFAllocatorDefault, generalName);
4477 if (string) {
4478 CFArrayAppendValue(ipAddresses, string);
4479 CFRelease(string);
4480 } else {
4481 return errSecInvalidCertificate;
4482 }
4483 }
4484 return errSecSuccess;
4485 }
4486
4487 CFArrayRef SecCertificateCopyIPAddresses(SecCertificateRef certificate) {
4488 /* These can only exist in the subject alt name. */
4489 if (!certificate->_subjectAltName)
4490 return NULL;
4491
4492 CFMutableArrayRef ipAddresses = CFArrayCreateMutable(kCFAllocatorDefault,
4493 0, &kCFTypeArrayCallBacks);
4494 OSStatus status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
4495 ipAddresses, appendIPAddressesFromGeneralNames);
4496 if (status || CFArrayGetCount(ipAddresses) == 0) {
4497 CFRelease(ipAddresses);
4498 ipAddresses = NULL;
4499 }
4500 return ipAddresses;
4501 }
4502
4503 static OSStatus appendIPAddressesFromX501Name(void *context, const DERItem *type,
4504 const DERItem *value, CFIndex rdnIX,
4505 bool localized) {
4506 CFMutableArrayRef addrs = (CFMutableArrayRef)context;
4507 if (DEROidCompare(type, &oidCommonName)) {
4508 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4509 value, true, localized);
4510 if (string) {
4511 CFDataRef data = NULL;
4512 if (convertIPAddress(string, &data)) {
4513 CFArrayAppendValue(addrs, data);
4514 CFReleaseNull(data);
4515 }
4516 CFRelease(string);
4517 } else {
4518 return errSecInvalidCertificate;
4519 }
4520 }
4521 return errSecSuccess;
4522 }
4523
4524 CFArrayRef SecCertificateCopyIPAddressesFromSubject(SecCertificateRef certificate) {
4525 CFMutableArrayRef addrs = CFArrayCreateMutable(kCFAllocatorDefault,
4526 0, &kCFTypeArrayCallBacks);
4527 OSStatus status = parseX501NameContent(&certificate->_subject, addrs,
4528 appendIPAddressesFromX501Name, true);
4529 if (status || CFArrayGetCount(addrs) == 0) {
4530 CFReleaseNull(addrs);
4531 return NULL;
4532 }
4533 return addrs;
4534 }
4535
4536 static OSStatus appendDNSNamesFromGeneralNames(void *context, SecCEGeneralNameType gnType,
4537 const DERItem *generalName) {
4538 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4539 if (gnType == GNT_DNSName) {
4540 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault,
4541 generalName->data, generalName->length,
4542 kCFStringEncodingUTF8, FALSE);
4543 if (string) {
4544 CFArrayAppendValue(dnsNames, string);
4545 CFRelease(string);
4546 } else {
4547 return errSecInvalidCertificate;
4548 }
4549 }
4550 return errSecSuccess;
4551 }
4552
4553 /* Return true if the passed in string matches the
4554 Preferred name syntax from sections 2.3.1. in RFC 1035.
4555 With the added check that we disallow empty dns names.
4556 Also in order to support wildcard DNSNames we allow for the '*'
4557 character anywhere in a dns component where we currently allow
4558 a letter.
4559
4560 <domain> ::= <subdomain> | " "
4561
4562 <subdomain> ::= <label> | <subdomain> "." <label>
4563
4564 <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
4565
4566 <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
4567
4568 <let-dig-hyp> ::= <let-dig> | "-"
4569
4570 <let-dig> ::= <letter> | <digit>
4571
4572 <letter> ::= any one of the 52 alphabetic characters A through Z in
4573 upper case and a through z in lower case
4574
4575 <digit> ::= any one of the ten digits 0 through 9
4576 */
4577 static bool isDNSName(CFStringRef string) {
4578 CFStringInlineBuffer buf = {};
4579 CFIndex ix, labelLength = 0, length = CFStringGetLength(string);
4580 /* From RFC 1035 2.3.4. Size limits:
4581 labels 63 octets or less
4582 names 255 octets or less */
4583 require_quiet(length <= 255, notDNS);
4584 CFRange range = { 0, length };
4585 CFStringInitInlineBuffer(string, &buf, range);
4586 enum {
4587 kDNSStateInital,
4588 kDNSStateAfterDot,
4589 kDNSStateAfterAlpha,
4590 kDNSStateAfterDigit,
4591 kDNSStateAfterDash,
4592 } state = kDNSStateInital;
4593
4594 for (ix = 0; ix < length; ++ix) {
4595 UniChar ch = CFStringGetCharacterFromInlineBuffer(&buf, ix);
4596 labelLength++;
4597 if (ch == '.') {
4598 require_quiet(labelLength <= 64 &&
4599 (state == kDNSStateAfterAlpha || state == kDNSStateAfterDigit),
4600 notDNS);
4601 state = kDNSStateAfterDot;
4602 labelLength = 0;
4603 } else if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') ||
4604 ch == '*') {
4605 state = kDNSStateAfterAlpha;
4606 } else if ('0' <= ch && ch <= '9') {
4607 #if 0
4608 /* The requirement for labels to start with a letter was
4609 dropped so we don't check this anymore. */
4610 require_quiet(state == kDNSStateAfterAlpha ||
4611 state == kDNSStateAfterDigit ||
4612 state == kDNSStateAfterDash, notDNS);
4613 #endif
4614 state = kDNSStateAfterDigit;
4615 } else if (ch == '-') {
4616 require_quiet(state == kDNSStateAfterAlpha ||
4617 state == kDNSStateAfterDigit ||
4618 state == kDNSStateAfterDash, notDNS);
4619 state = kDNSStateAfterDash;
4620 } else {
4621 goto notDNS;
4622 }
4623 }
4624
4625 /* We don't allow a dns name to end in a dot or dash. */
4626 require_quiet(labelLength <= 63 &&
4627 (state == kDNSStateAfterAlpha || state == kDNSStateAfterDigit),
4628 notDNS);
4629
4630 return true;
4631 notDNS:
4632 return false;
4633 }
4634
4635 static OSStatus appendDNSNamesFromX501Name(void *context, const DERItem *type,
4636 const DERItem *value, CFIndex rdnIX, bool localized) {
4637 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4638 if (DEROidCompare(type, &oidCommonName)) {
4639 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4640 value, true, localized);
4641 if (string) {
4642 if (isDNSName(string)) {
4643 /* We found a common name that is formatted like a valid
4644 dns name. */
4645 CFArrayAppendValue(dnsNames, string);
4646 }
4647 CFRelease(string);
4648 } else {
4649 return errSecInvalidCertificate;
4650 }
4651 }
4652 return errSecSuccess;
4653 }
4654
4655 CFArrayRef SecCertificateCopyDNSNamesFromSubject(SecCertificateRef certificate) {
4656 CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault,
4657 0, &kCFTypeArrayCallBacks);
4658 OSStatus status = parseX501NameContent(&certificate->_subject, dnsNames,
4659 appendDNSNamesFromX501Name, true);
4660 if (status || CFArrayGetCount(dnsNames) == 0) {
4661 CFReleaseNull(dnsNames);
4662 return NULL;
4663 }
4664
4665 /* appendDNSNamesFromX501Name allows IP addresses, we don't want those for this function */
4666 __block CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
4667 CFArrayForEach(dnsNames, ^(const void *value) {
4668 CFStringRef name = (CFStringRef)value;
4669 if (!convertIPAddress(name, NULL)) {
4670 CFArrayAppendValue(result, name);
4671 }
4672 });
4673 CFReleaseNull(dnsNames);
4674 if (CFArrayGetCount(result) == 0) {
4675 CFReleaseNull(result);
4676 }
4677
4678 return result;
4679 }
4680
4681 CFArrayRef SecCertificateCopyDNSNamesFromSAN(SecCertificateRef certificate) {
4682 CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault,
4683 0, &kCFTypeArrayCallBacks);
4684 OSStatus status = errSecSuccess;
4685 if (certificate->_subjectAltName) {
4686 status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
4687 dnsNames, appendDNSNamesFromGeneralNames);
4688 }
4689
4690 if (status || CFArrayGetCount(dnsNames) == 0) {
4691 CFReleaseNull(dnsNames);
4692 }
4693 return dnsNames;
4694 }
4695
4696 /* Not everything returned by this function is going to be a proper DNS name,
4697 we also return the certificates common name entries from the subject,
4698 assuming they look like dns names as specified in RFC 1035. */
4699 CFArrayRef SecCertificateCopyDNSNames(SecCertificateRef certificate) {
4700 /* These can exist in the subject alt name or in the subject. */
4701 CFArrayRef sanNames = SecCertificateCopyDNSNamesFromSAN(certificate);
4702 if (sanNames && CFArrayGetCount(sanNames) > 0) {
4703 return sanNames;
4704 }
4705 CFReleaseNull(sanNames);
4706
4707 /* RFC 2818 section 3.1. Server Identity
4708 [...]
4709 If a subjectAltName extension of type dNSName is present, that MUST
4710 be used as the identity. Otherwise, the (most specific) Common Name
4711 field in the Subject field of the certificate MUST be used. Although
4712 the use of the Common Name is existing practice, it is deprecated and
4713 Certification Authorities are encouraged to use the dNSName instead.
4714 [...]
4715
4716 This implies that if we found 1 or more DNSNames in the
4717 subjectAltName, we should not use the Common Name of the subject as
4718 a DNSName.
4719 */
4720
4721 /* To preserve bug for bug compatibility, we can't use SecCertificateCopyDNSNamesFromSubject
4722 * because that function filters out IP Addresses. This function is Private, but
4723 * SecCertificateCopyValues uses it and that's Public. */
4724 CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault,
4725 0, &kCFTypeArrayCallBacks);
4726 OSStatus status = parseX501NameContent(&certificate->_subject, dnsNames,
4727 appendDNSNamesFromX501Name, true);
4728 if (status || CFArrayGetCount(dnsNames) == 0) {
4729 CFReleaseNull(dnsNames);
4730 }
4731 return dnsNames;
4732 }
4733
4734 static OSStatus appendRFC822NamesFromGeneralNames(void *context,
4735 SecCEGeneralNameType gnType, const DERItem *generalName) {
4736 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4737 if (gnType == GNT_RFC822Name) {
4738 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault,
4739 generalName->data, generalName->length,
4740 kCFStringEncodingASCII, FALSE);
4741 if (string) {
4742 CFArrayAppendValue(dnsNames, string);
4743 CFRelease(string);
4744 } else {
4745 return errSecInvalidCertificate;
4746 }
4747 }
4748 return errSecSuccess;
4749 }
4750
4751 static OSStatus appendRFC822NamesFromX501Name(void *context, const DERItem *type,
4752 const DERItem *value, CFIndex rdnIX, bool localized) {
4753 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4754 if (DEROidCompare(type, &oidEmailAddress)) {
4755 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4756 value, true, localized);
4757 if (string) {
4758 CFArrayAppendValue(dnsNames, string);
4759 CFRelease(string);
4760 } else {
4761 return errSecInvalidCertificate;
4762 }
4763 }
4764 return errSecSuccess;
4765 }
4766
4767 CFArrayRef SecCertificateCopyRFC822Names(SecCertificateRef certificate) {
4768 /* These can exist in the subject alt name or in the subject. */
4769 CFMutableArrayRef rfc822Names = CFArrayCreateMutable(kCFAllocatorDefault,
4770 0, &kCFTypeArrayCallBacks);
4771 OSStatus status = errSecSuccess;
4772 if (certificate->_subjectAltName) {
4773 status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
4774 rfc822Names, appendRFC822NamesFromGeneralNames);
4775 }
4776 if (!status) {
4777 status = parseX501NameContent(&certificate->_subject, rfc822Names,
4778 appendRFC822NamesFromX501Name, true);
4779 }
4780 if (status || CFArrayGetCount(rfc822Names) == 0) {
4781 CFRelease(rfc822Names);
4782 rfc822Names = NULL;
4783 }
4784 return rfc822Names;
4785 }
4786
4787 OSStatus SecCertificateCopyEmailAddresses(SecCertificateRef certificate, CFArrayRef * __nonnull CF_RETURNS_RETAINED emailAddresses) {
4788 if (!certificate || !emailAddresses) {
4789 return errSecParam;
4790 }
4791 *emailAddresses = SecCertificateCopyRFC822Names(certificate);
4792 if (*emailAddresses == NULL) {
4793 *emailAddresses = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
4794 }
4795 return errSecSuccess;
4796 }
4797
4798 CFArrayRef SecCertificateCopyRFC822NamesFromSubject(SecCertificateRef certificate) {
4799 CFMutableArrayRef rfc822Names = CFArrayCreateMutable(kCFAllocatorDefault,
4800 0, &kCFTypeArrayCallBacks);
4801 OSStatus status = parseX501NameContent(&certificate->_subject, rfc822Names,
4802 appendRFC822NamesFromX501Name, true);
4803 if (status || CFArrayGetCount(rfc822Names) == 0) {
4804 CFRelease(rfc822Names);
4805 rfc822Names = NULL;
4806 }
4807 return rfc822Names;
4808 }
4809
4810 static OSStatus appendCommonNamesFromX501Name(void *context,
4811 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
4812 CFMutableArrayRef commonNames = (CFMutableArrayRef)context;
4813 if (DEROidCompare(type, &oidCommonName)) {
4814 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4815 value, true, localized);
4816 if (string) {
4817 CFArrayAppendValue(commonNames, string);
4818 CFRelease(string);
4819 } else {
4820 return errSecInvalidCertificate;
4821 }
4822 }
4823 return errSecSuccess;
4824 }
4825
4826 CFArrayRef SecCertificateCopyCommonNames(SecCertificateRef certificate) {
4827 CFMutableArrayRef commonNames = CFArrayCreateMutable(kCFAllocatorDefault,
4828 0, &kCFTypeArrayCallBacks);
4829 OSStatus status;
4830 status = parseX501NameContent(&certificate->_subject, commonNames,
4831 appendCommonNamesFromX501Name, true);
4832 if (status || CFArrayGetCount(commonNames) == 0) {
4833 CFRelease(commonNames);
4834 commonNames = NULL;
4835 }
4836 return commonNames;
4837 }
4838
4839 OSStatus SecCertificateCopyCommonName(SecCertificateRef certificate, CFStringRef *commonName)
4840 {
4841 if (!certificate) {
4842 return errSecParam;
4843 }
4844 CFArrayRef commonNames = SecCertificateCopyCommonNames(certificate);
4845 if (!commonNames) {
4846 return errSecInternal;
4847 }
4848
4849 if (commonName) {
4850 CFIndex count = CFArrayGetCount(commonNames);
4851 *commonName = CFRetainSafe(CFArrayGetValueAtIndex(commonNames, count-1));
4852 }
4853 CFReleaseSafe(commonNames);
4854 return errSecSuccess;
4855 }
4856
4857 static OSStatus appendOrganizationFromX501Name(void *context,
4858 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
4859 CFMutableArrayRef organization = (CFMutableArrayRef)context;
4860 if (DEROidCompare(type, &oidOrganizationName)) {
4861 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4862 value, true, localized);
4863 if (string) {
4864 CFArrayAppendValue(organization, string);
4865 CFRelease(string);
4866 } else {
4867 return errSecInvalidCertificate;
4868 }
4869 }
4870 return errSecSuccess;
4871 }
4872
4873 CFArrayRef SecCertificateCopyOrganizationFromX501NameContent(const DERItem *nameContent) {
4874 CFMutableArrayRef organization = CFArrayCreateMutable(kCFAllocatorDefault,
4875 0, &kCFTypeArrayCallBacks);
4876 OSStatus status;
4877 status = parseX501NameContent(nameContent, organization,
4878 appendOrganizationFromX501Name, true);
4879 if (status || CFArrayGetCount(organization) == 0) {
4880 CFRelease(organization);
4881 organization = NULL;
4882 }
4883 return organization;
4884 }
4885
4886 CFArrayRef SecCertificateCopyOrganization(SecCertificateRef certificate) {
4887 return SecCertificateCopyOrganizationFromX501NameContent(&certificate->_subject);
4888 }
4889
4890 static OSStatus appendOrganizationalUnitFromX501Name(void *context,
4891 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
4892 CFMutableArrayRef organizationalUnit = (CFMutableArrayRef)context;
4893 if (DEROidCompare(type, &oidOrganizationalUnitName)) {
4894 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4895 value, true, localized);
4896 if (string) {
4897 CFArrayAppendValue(organizationalUnit, string);
4898 CFRelease(string);
4899 } else {
4900 return errSecInvalidCertificate;
4901 }
4902 }
4903 return errSecSuccess;
4904 }
4905
4906 CFArrayRef SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate) {
4907 CFMutableArrayRef organizationalUnit = CFArrayCreateMutable(kCFAllocatorDefault,
4908 0, &kCFTypeArrayCallBacks);
4909 OSStatus status;
4910 status = parseX501NameContent(&certificate->_subject, organizationalUnit,
4911 appendOrganizationalUnitFromX501Name, true);
4912 if (status || CFArrayGetCount(organizationalUnit) == 0) {
4913 CFRelease(organizationalUnit);
4914 organizationalUnit = NULL;
4915 }
4916 return organizationalUnit;
4917 }
4918
4919 static OSStatus appendCountryFromX501Name(void *context,
4920 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
4921 CFMutableArrayRef countries = (CFMutableArrayRef)context;
4922 if (DEROidCompare(type, &oidCountryName)) {
4923 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4924 value, true, localized);
4925 if (string) {
4926 CFArrayAppendValue(countries, string);
4927 CFRelease(string);
4928 } else {
4929 return errSecInvalidCertificate;
4930 }
4931 }
4932 return errSecSuccess;
4933 }
4934
4935 CFArrayRef SecCertificateCopyCountry(SecCertificateRef certificate) {
4936 CFMutableArrayRef countries = CFArrayCreateMutable(kCFAllocatorDefault,
4937 0, &kCFTypeArrayCallBacks);
4938 OSStatus status;
4939 status = parseX501NameContent(&certificate->_subject, countries,
4940 appendCountryFromX501Name, true);
4941 if (status || CFArrayGetCount(countries) == 0) {
4942 CFRelease(countries);
4943 countries = NULL;
4944 }
4945 return countries;
4946 }
4947
4948 const SecCEBasicConstraints *
4949 SecCertificateGetBasicConstraints(SecCertificateRef certificate) {
4950 if (certificate->_basicConstraints.present)
4951 return &certificate->_basicConstraints;
4952 else
4953 return NULL;
4954 }
4955
4956 CFArrayRef SecCertificateGetPermittedSubtrees(SecCertificateRef certificate) {
4957 return (certificate->_permittedSubtrees);
4958 }
4959
4960 CFArrayRef SecCertificateGetExcludedSubtrees(SecCertificateRef certificate) {
4961 return (certificate->_excludedSubtrees);
4962 }
4963
4964 const SecCEPolicyConstraints *
4965 SecCertificateGetPolicyConstraints(SecCertificateRef certificate) {
4966 if (certificate->_policyConstraints.present)
4967 return &certificate->_policyConstraints;
4968 else
4969 return NULL;
4970 }
4971
4972 const SecCEPolicyMappings *
4973 SecCertificateGetPolicyMappings(SecCertificateRef certificate) {
4974 if (certificate->_policyMappings.present) {
4975 return &certificate->_policyMappings;
4976 } else {
4977 return NULL;
4978 }
4979 }
4980
4981 const SecCECertificatePolicies *
4982 SecCertificateGetCertificatePolicies(SecCertificateRef certificate) {
4983 if (certificate->_certificatePolicies.present)
4984 return &certificate->_certificatePolicies;
4985 else
4986 return NULL;
4987 }
4988
4989 const SecCEInhibitAnyPolicy *
4990 SecCertificateGetInhibitAnyPolicySkipCerts(SecCertificateRef certificate) {
4991 if (certificate->_inhibitAnyPolicySkipCerts.present) {
4992 return &certificate->_inhibitAnyPolicySkipCerts;
4993 } else {
4994 return NULL;
4995 }
4996 }
4997
4998 static OSStatus appendNTPrincipalNamesFromGeneralNames(void *context,
4999 SecCEGeneralNameType gnType, const DERItem *generalName) {
5000 CFMutableArrayRef ntPrincipalNames = (CFMutableArrayRef)context;
5001 if (gnType == GNT_OtherName) {
5002 DEROtherName on;
5003 DERReturn drtn = DERParseSequenceContent(generalName,
5004 DERNumOtherNameItemSpecs, DEROtherNameItemSpecs,
5005 &on, sizeof(on));
5006 require_noerr_quiet(drtn, badDER);
5007 if (DEROidCompare(&on.typeIdentifier, &oidMSNTPrincipalName)) {
5008 CFStringRef string;
5009 require_quiet(string = copyDERThingDescription(kCFAllocatorDefault,
5010 &on.value, true, true), badDER);
5011 CFArrayAppendValue(ntPrincipalNames, string);
5012 CFRelease(string);
5013 }
5014 }
5015 return errSecSuccess;
5016
5017 badDER:
5018 return errSecInvalidCertificate;
5019
5020 }
5021
5022 CFArrayRef SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate) {
5023 CFMutableArrayRef ntPrincipalNames = CFArrayCreateMutable(kCFAllocatorDefault,
5024 0, &kCFTypeArrayCallBacks);
5025 OSStatus status = errSecSuccess;
5026 if (certificate->_subjectAltName) {
5027 status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
5028 ntPrincipalNames, appendNTPrincipalNamesFromGeneralNames);
5029 }
5030 if (status || CFArrayGetCount(ntPrincipalNames) == 0) {
5031 CFRelease(ntPrincipalNames);
5032 ntPrincipalNames = NULL;
5033 }
5034 return ntPrincipalNames;
5035 }
5036
5037 static OSStatus appendToRFC2253String(void *context,
5038 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
5039 CFMutableStringRef string = (CFMutableStringRef)context;
5040 /*
5041 CN commonName
5042 L localityName
5043 ST stateOrProvinceName
5044 O organizationName
5045 OU organizationalUnitName
5046 C countryName
5047 STREET streetAddress
5048 DC domainComponent
5049 UID userid
5050 */
5051 /* Prepend a + if this is not the first RDN in an RDN set.
5052 Otherwise prepend a , if this is not the first RDN. */
5053 if (rdnIX > 0)
5054 CFStringAppend(string, CFSTR("+"));
5055 else if (CFStringGetLength(string)) {
5056 CFStringAppend(string, CFSTR(","));
5057 }
5058
5059 CFStringRef label, oid = NULL;
5060 /* @@@ Consider changing this to a dictionary lookup keyed by the
5061 decimal representation. */
5062 if (DEROidCompare(type, &oidCommonName)) {
5063 label = CFSTR("CN");
5064 } else if (DEROidCompare(type, &oidLocalityName)) {
5065 label = CFSTR("L");
5066 } else if (DEROidCompare(type, &oidStateOrProvinceName)) {
5067 label = CFSTR("ST");
5068 } else if (DEROidCompare(type, &oidOrganizationName)) {
5069 label = CFSTR("O");
5070 } else if (DEROidCompare(type, &oidOrganizationalUnitName)) {
5071 label = CFSTR("OU");
5072 } else if (DEROidCompare(type, &oidCountryName)) {
5073 label = CFSTR("C");
5074 #if 0
5075 } else if (DEROidCompare(type, &oidStreetAddress)) {
5076 label = CFSTR("STREET");
5077 } else if (DEROidCompare(type, &oidDomainComponent)) {
5078 label = CFSTR("DC");
5079 } else if (DEROidCompare(type, &oidUserID)) {
5080 label = CFSTR("UID");
5081 #endif
5082 } else {
5083 label = oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, type);
5084 }
5085
5086 CFStringAppend(string, label);
5087 CFStringAppend(string, CFSTR("="));
5088 CFStringRef raw = NULL;
5089 if (!oid)
5090 raw = copyDERThingDescription(kCFAllocatorDefault, value, true, localized);
5091
5092 if (raw) {
5093 /* Append raw to string while escaping:
5094 a space or "#" character occurring at the beginning of the string
5095 a space character occurring at the end of the string
5096 one of the characters ",", "+", """, "\", "<", ">" or ";"
5097 */
5098 CFStringInlineBuffer buffer = {};
5099 CFIndex ix, length = CFStringGetLength(raw);
5100 CFRange range = { 0, length };
5101 CFStringInitInlineBuffer(raw, &buffer, range);
5102 for (ix = 0; ix < length; ++ix) {
5103 UniChar ch = CFStringGetCharacterFromInlineBuffer(&buffer, ix);
5104 if (ch < 0x20) {
5105 CFStringAppendFormat(string, NULL, CFSTR("\\%02X"), ch);
5106 } else if (ch == ',' || ch == '+' || ch == '"' || ch == '\\' ||
5107 ch == '<' || ch == '>' || ch == ';' ||
5108 (ch == ' ' && (ix == 0 || ix == length - 1)) ||
5109 (ch == '#' && ix == 0)) {
5110 UniChar chars[] = { '\\', ch };
5111 CFStringAppendCharacters(string, chars, 2);
5112 } else {
5113 CFStringAppendCharacters(string, &ch, 1);
5114 }
5115 }
5116 CFRelease(raw);
5117 } else {
5118 /* Append the value in hex. */
5119 CFStringAppend(string, CFSTR("#"));
5120 DERSize ix;
5121 for (ix = 0; ix < value->length; ++ix)
5122 CFStringAppendFormat(string, NULL, CFSTR("%02X"), value->data[ix]);
5123 }
5124
5125 CFReleaseSafe(oid);
5126
5127 return errSecSuccess;
5128 }
5129
5130 CFStringRef SecCertificateCopySubjectString(SecCertificateRef certificate) {
5131 CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0);
5132 OSStatus status = parseX501NameContent(&certificate->_subject, string, appendToRFC2253String, true);
5133 if (status || CFStringGetLength(string) == 0) {
5134 CFRelease(string);
5135 string = NULL;
5136 }
5137 return string;
5138 }
5139
5140 static OSStatus appendToCompanyNameString(void *context,
5141 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
5142 CFMutableStringRef string = (CFMutableStringRef)context;
5143 if (CFStringGetLength(string) != 0)
5144 return errSecSuccess;
5145
5146 if (!DEROidCompare(type, &oidOrganizationName))
5147 return errSecSuccess;
5148
5149 CFStringRef raw;
5150 raw = copyDERThingDescription(kCFAllocatorDefault, value, true, localized);
5151 if (!raw)
5152 return errSecSuccess;
5153 CFStringAppend(string, raw);
5154 CFRelease(raw);
5155
5156 return errSecSuccess;
5157 }
5158
5159 CFStringRef SecCertificateCopyCompanyName(SecCertificateRef certificate) {
5160 CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0);
5161 OSStatus status = parseX501NameContent(&certificate->_subject, string,
5162 appendToCompanyNameString, true);
5163 if (status || CFStringGetLength(string) == 0) {
5164 CFRelease(string);
5165 string = NULL;
5166 }
5167 return string;
5168 }
5169
5170 CFDataRef SecCertificateCopyIssuerSequence(
5171 SecCertificateRef certificate) {
5172 return SecDERItemCopySequence(&certificate->_issuer);
5173 }
5174
5175 CFDataRef SecCertificateCopySubjectSequence(
5176 SecCertificateRef certificate) {
5177 return SecDERItemCopySequence(&certificate->_subject);
5178 }
5179
5180 CFDataRef SecCertificateCopyNormalizedIssuerSequence(SecCertificateRef certificate) {
5181 if (!certificate || !certificate->_normalizedIssuer) {
5182 return NULL;
5183 }
5184 return SecCopySequenceFromContent(certificate->_normalizedIssuer);
5185 }
5186
5187 CFDataRef SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certificate) {
5188 if (!certificate || !certificate->_normalizedSubject) {
5189 return NULL;
5190 }
5191 return SecCopySequenceFromContent(certificate->_normalizedSubject);
5192 }
5193
5194 const DERAlgorithmId *SecCertificateGetPublicKeyAlgorithm(
5195 SecCertificateRef certificate) {
5196 return &certificate->_algId;
5197 }
5198
5199 const DERItem *SecCertificateGetPublicKeyData(SecCertificateRef certificate) {
5200 return &certificate->_pubKeyDER;
5201 }
5202
5203 #if TARGET_OS_OSX
5204 /* There is already a SecCertificateCopyPublicKey with different args on OS X,
5205 so we will refer to this one internally as SecCertificateCopyPublicKey_ios.
5206 */
5207 __nullable SecKeyRef SecCertificateCopyPublicKey_ios(SecCertificateRef certificate)
5208 #else
5209 __nullable SecKeyRef SecCertificateCopyPublicKey(SecCertificateRef certificate)
5210 #endif
5211 {
5212 return SecCertificateCopyKey(certificate);
5213 }
5214
5215 SecKeyRef SecCertificateCopyKey(SecCertificateRef certificate) {
5216 if (certificate->_pubKey == NULL) {
5217 const DERAlgorithmId *algId =
5218 SecCertificateGetPublicKeyAlgorithm(certificate);
5219 const DERItem *keyData = SecCertificateGetPublicKeyData(certificate);
5220 const DERItem *params = NULL;
5221 if (algId->params.length != 0) {
5222 params = &algId->params;
5223 }
5224 SecAsn1Oid oid1 = { .Data = algId->oid.data, .Length = algId->oid.length };
5225 SecAsn1Item params1 = {
5226 .Data = params ? params->data : NULL,
5227 .Length = params ? params->length : 0
5228 };
5229 SecAsn1Item keyData1 = {
5230 .Data = keyData ? keyData->data : NULL,
5231 .Length = keyData ? keyData->length : 0
5232 };
5233 certificate->_pubKey = SecKeyCreatePublicFromDER(kCFAllocatorDefault, &oid1, &params1,
5234 &keyData1);
5235 }
5236
5237 return CFRetainSafe(certificate->_pubKey);
5238 }
5239
5240 static CFIndex SecCertificateGetPublicKeyAlgorithmIdAndSize(SecCertificateRef certificate, size_t *keySizeInBytes) {
5241 CFIndex keyAlgID = kSecNullAlgorithmID;
5242 size_t size = 0;
5243
5244 SecKeyRef pubKey = NULL;
5245 require_quiet(certificate, out);
5246 require_quiet(pubKey = SecCertificateCopyKey(certificate) ,out);
5247 size = SecKeyGetBlockSize(pubKey);
5248 keyAlgID = SecKeyGetAlgorithmId(pubKey);
5249
5250 out:
5251 CFReleaseNull(pubKey);
5252 if (keySizeInBytes) { *keySizeInBytes = size; }
5253 return keyAlgID;
5254 }
5255
5256 /*
5257 * Public keys in certificates may be considered "weak" or "strong" or neither
5258 * (that is, in between). Certificates using weak keys are not trusted at all.
5259 * Certificates using neither strong nor weak keys are only trusted in certain
5260 * contexts. SecPolicy and SecPolicyServer define the contexts by which we enforce
5261 * these (or stronger) key size trust policies.
5262 */
5263 bool SecCertificateIsWeakKey(SecCertificateRef certificate) {
5264 if (!certificate) { return true; }
5265
5266 bool weak = true;
5267 size_t size = 0;
5268 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) {
5269 case kSecRSAAlgorithmID:
5270 if (MIN_RSA_KEY_SIZE <= size) weak = false;
5271 break;
5272 case kSecECDSAAlgorithmID:
5273 if (MIN_EC_KEY_SIZE <= size) weak = false;
5274 break;
5275 default:
5276 weak = true;
5277 }
5278 return weak;
5279 }
5280
5281 bool SecCertificateIsStrongKey(SecCertificateRef certificate) {
5282 if (!certificate) { return false; }
5283
5284 bool strong = false;
5285 size_t size = 0;
5286 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) {
5287 case kSecRSAAlgorithmID:
5288 if (MIN_STRONG_RSA_KEY_SIZE <= size) strong = true;
5289 break;
5290 case kSecECDSAAlgorithmID:
5291 if (MIN_STRONG_EC_KEY_SIZE <= size) strong = true;
5292 break;
5293 default:
5294 strong = false;
5295 }
5296 return strong;
5297 }
5298
5299 bool SecCertificateIsWeakHash(SecCertificateRef certificate) {
5300 if (!certificate) { return true; }
5301 SecSignatureHashAlgorithm certAlg = 0;
5302 certAlg = SecCertificateGetSignatureHashAlgorithm(certificate);
5303 if (certAlg == kSecSignatureHashAlgorithmUnknown ||
5304 certAlg == kSecSignatureHashAlgorithmMD2 ||
5305 certAlg == kSecSignatureHashAlgorithmMD4 ||
5306 certAlg == kSecSignatureHashAlgorithmMD5 ||
5307 certAlg == kSecSignatureHashAlgorithmSHA1) {
5308 return true;
5309 }
5310 return false;
5311 }
5312
5313 bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate,
5314 CFDictionaryRef keySizes) {
5315 if (!certificate) { return false; }
5316
5317 bool goodSize = false;
5318 size_t size = 0;
5319 CFNumberRef minSize;
5320 size_t minSizeInBits;
5321 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) {
5322 case kSecRSAAlgorithmID:
5323 if(CFDictionaryGetValueIfPresent(keySizes, kSecAttrKeyTypeRSA, (const void**)&minSize)
5324 && minSize && CFNumberGetValue(minSize, kCFNumberLongType, &minSizeInBits)) {
5325 if (size >= (size_t)(minSizeInBits+7)/8) goodSize = true;
5326 }
5327 break;
5328 case kSecECDSAAlgorithmID:
5329 if(CFDictionaryGetValueIfPresent(keySizes, kSecAttrKeyTypeEC, (const void**)&minSize)
5330 && minSize && CFNumberGetValue(minSize, kCFNumberLongType, &minSizeInBits)) {
5331 if (size >= (size_t)(minSizeInBits+7)/8) goodSize = true;
5332 }
5333 break;
5334 default:
5335 goodSize = false;
5336 }
5337 return goodSize;
5338 }
5339
5340 CFDataRef SecCertificateGetSHA1Digest(SecCertificateRef certificate) {
5341 if (!certificate || !certificate->_der.data) {
5342 return NULL;
5343 }
5344 if (!certificate->_sha1Digest) {
5345 certificate->_sha1Digest =
5346 SecSHA1DigestCreate(CFGetAllocator(certificate),
5347 certificate->_der.data, certificate->_der.length);
5348 }
5349 return certificate->_sha1Digest;
5350 }
5351
5352 CFDataRef SecCertificateCopySHA256Digest(SecCertificateRef certificate) {
5353 if (!certificate || !certificate->_der.data) {
5354 return NULL;
5355 }
5356 return SecSHA256DigestCreate(CFGetAllocator(certificate),
5357 certificate->_der.data, certificate->_der.length);
5358 }
5359
5360 CFDataRef SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate) {
5361 CFDataRef digest = NULL;
5362 CFDataRef issuer = SecCertificateCopyIssuerSequence(certificate);
5363 if (issuer) {
5364 digest = SecSHA1DigestCreate(kCFAllocatorDefault,
5365 CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
5366 CFRelease(issuer);
5367 }
5368 return digest;
5369 }
5370
5371 CFDataRef SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate) {
5372 if (!certificate || !certificate->_pubKeyDER.data) {
5373 return NULL;
5374 }
5375 return SecSHA1DigestCreate(CFGetAllocator(certificate),
5376 certificate->_pubKeyDER.data, certificate->_pubKeyDER.length);
5377 }
5378
5379 static CFDataRef SecCertificateCopySPKIEncoded(SecCertificateRef certificate) {
5380 /* SPKI is saved without the tag/length by libDER, so we need to re-encode */
5381 if (!certificate || !certificate->_subjectPublicKeyInfo.data) {
5382 return NULL;
5383 }
5384 DERSize size = DERLengthOfItem(ASN1_CONSTR_SEQUENCE, certificate->_subjectPublicKeyInfo.length);
5385 if (size < certificate->_subjectPublicKeyInfo.length) {
5386 return NULL;
5387 }
5388 uint8_t *temp = malloc(size);
5389 if (!temp) {
5390 return NULL;
5391 }
5392 DERReturn drtn = DEREncodeItem(ASN1_CONSTR_SEQUENCE,
5393 certificate->_subjectPublicKeyInfo.length,
5394 certificate->_subjectPublicKeyInfo.data,
5395 temp, &size);
5396 CFDataRef encodedSPKI = NULL;
5397 if (drtn == DR_Success) {
5398 encodedSPKI = CFDataCreate(NULL, temp, size);
5399 }
5400 free(temp);
5401 return encodedSPKI;
5402 }
5403
5404 CFDataRef SecCertificateCopySubjectPublicKeyInfoSHA1Digest(SecCertificateRef certificate) {
5405 CFDataRef encodedSPKI = SecCertificateCopySPKIEncoded(certificate);
5406 if (!encodedSPKI) { return NULL; }
5407 CFDataRef hash = SecSHA1DigestCreate(CFGetAllocator(certificate),
5408 CFDataGetBytePtr(encodedSPKI),
5409 CFDataGetLength(encodedSPKI));
5410 CFReleaseNull(encodedSPKI);
5411 return hash;
5412 }
5413
5414 CFDataRef SecCertificateCopySubjectPublicKeyInfoSHA256Digest(SecCertificateRef certificate) {
5415 CFDataRef encodedSPKI = SecCertificateCopySPKIEncoded(certificate);
5416 if (!encodedSPKI) { return NULL; }
5417 CFDataRef hash = SecSHA256DigestCreate(CFGetAllocator(certificate),
5418 CFDataGetBytePtr(encodedSPKI),
5419 CFDataGetLength(encodedSPKI));
5420 CFReleaseNull(encodedSPKI);
5421 return hash;
5422 }
5423
5424 CFTypeRef SecCertificateCopyKeychainItem(SecCertificateRef certificate)
5425 {
5426 if (!certificate) {
5427 return NULL;
5428 }
5429 CFRetainSafe(certificate->_keychain_item);
5430 return certificate->_keychain_item;
5431 }
5432
5433 CFDataRef SecCertificateGetAuthorityKeyID(SecCertificateRef certificate) {
5434 if (!certificate) {
5435 return NULL;
5436 }
5437 if (!certificate->_authorityKeyID &&
5438 certificate->_authorityKeyIdentifier.length) {
5439 certificate->_authorityKeyID = CFDataCreate(kCFAllocatorDefault,
5440 certificate->_authorityKeyIdentifier.data,
5441 certificate->_authorityKeyIdentifier.length);
5442 }
5443
5444 return certificate->_authorityKeyID;
5445 }
5446
5447 CFDataRef SecCertificateGetSubjectKeyID(SecCertificateRef certificate) {
5448 if (!certificate) {
5449 return NULL;
5450 }
5451 if (!certificate->_subjectKeyID &&
5452 certificate->_subjectKeyIdentifier.length) {
5453 certificate->_subjectKeyID = CFDataCreate(kCFAllocatorDefault,
5454 certificate->_subjectKeyIdentifier.data,
5455 certificate->_subjectKeyIdentifier.length);
5456 }
5457
5458 return certificate->_subjectKeyID;
5459 }
5460
5461 CFArrayRef SecCertificateGetCRLDistributionPoints(SecCertificateRef certificate) {
5462 if (!certificate) {
5463 return NULL;
5464 }
5465 return certificate->_crlDistributionPoints;
5466 }
5467
5468 CFArrayRef SecCertificateGetOCSPResponders(SecCertificateRef certificate) {
5469 if (!certificate) {
5470 return NULL;
5471 }
5472 return certificate->_ocspResponders;
5473 }
5474
5475 CFArrayRef SecCertificateGetCAIssuers(SecCertificateRef certificate) {
5476 if (!certificate) {
5477 return NULL;
5478 }
5479 return certificate->_caIssuers;
5480 }
5481
5482 bool SecCertificateHasCriticalSubjectAltName(SecCertificateRef certificate) {
5483 if (!certificate) {
5484 return false;
5485 }
5486 return certificate->_subjectAltName &&
5487 certificate->_subjectAltName->critical;
5488 }
5489
5490 bool SecCertificateHasSubject(SecCertificateRef certificate) {
5491 if (!certificate) {
5492 return false;
5493 }
5494 /* Since the _subject field is the content of the subject and not the
5495 whole thing, we can simply check for a 0 length subject here. */
5496 return certificate->_subject.length != 0;
5497 }
5498
5499 bool SecCertificateHasUnknownCriticalExtension(SecCertificateRef certificate) {
5500 if (!certificate) {
5501 return false;
5502 }
5503 return certificate->_foundUnknownCriticalExtension;
5504 }
5505
5506 /* Private API functions. */
5507 void SecCertificateShow(SecCertificateRef certificate) {
5508 check(certificate);
5509 fprintf(stderr, "SecCertificate instance %p:\n", certificate);
5510 fprintf(stderr, "\n");
5511 }
5512
5513 #ifndef STANDALONE
5514 CFDictionaryRef SecCertificateCopyAttributeDictionary(
5515 SecCertificateRef certificate) {
5516 if (!certificate || !(CFGetTypeID(certificate) == SecCertificateGetTypeID())) {
5517 return NULL;
5518 }
5519 CFAllocatorRef allocator = CFGetAllocator(certificate);
5520 CFNumberRef certificateType = NULL;
5521 CFNumberRef certificateEncoding = NULL;
5522 CFStringRef label = NULL;
5523 CFStringRef alias = NULL;
5524 CFDataRef skid = NULL;
5525 CFDataRef pubKeyDigest = NULL;
5526 CFDataRef certData = NULL;
5527 CFDictionaryRef dict = NULL;
5528
5529 DICT_DECLARE(11);
5530
5531 /* CSSM_CERT_X_509v1, CSSM_CERT_X_509v2 or CSSM_CERT_X_509v3 */
5532 SInt32 ctv = certificate->_version + 1;
5533 SInt32 cev = 3; /* CSSM_CERT_ENCODING_DER */
5534 certificateType = CFNumberCreate(allocator, kCFNumberSInt32Type, &ctv);
5535 require_quiet(certificateType != NULL, out);
5536 certificateEncoding = CFNumberCreate(allocator, kCFNumberSInt32Type, &cev);
5537 require_quiet(certificateEncoding != NULL, out);
5538 certData = SecCertificateCopyData(certificate);
5539 require_quiet(certData != NULL, out);
5540 skid = SecCertificateGetSubjectKeyID(certificate);
5541 require_quiet(certificate->_pubKeyDER.data != NULL && certificate->_pubKeyDER.length > 0, out);
5542 pubKeyDigest = SecSHA1DigestCreate(allocator, certificate->_pubKeyDER.data,
5543 certificate->_pubKeyDER.length);
5544 require_quiet(pubKeyDigest != NULL, out);
5545 #if 0
5546 /* We still need to figure out how to deal with multi valued attributes. */
5547 alias = SecCertificateCopyRFC822Names(certificate);
5548 label = SecCertificateCopySubjectSummary(certificate);
5549 #else
5550 alias = NULL;
5551 label = NULL;
5552 #endif
5553
5554 DICT_ADDPAIR(kSecClass, kSecClassCertificate);
5555 DICT_ADDPAIR(kSecAttrCertificateType, certificateType);
5556 DICT_ADDPAIR(kSecAttrCertificateEncoding, certificateEncoding);
5557 if (label) {
5558 DICT_ADDPAIR(kSecAttrLabel, label);
5559 }
5560 if (alias) {
5561 DICT_ADDPAIR(kSecAttrAlias, alias);
5562 }
5563 if (isData(certificate->_normalizedSubject)) {
5564 DICT_ADDPAIR(kSecAttrSubject, certificate->_normalizedSubject);
5565 }
5566 require_quiet(isData(certificate->_normalizedIssuer), out);
5567 DICT_ADDPAIR(kSecAttrIssuer, certificate->_normalizedIssuer);
5568 require_quiet(isData(certificate->_serialNumber), out);
5569 DICT_ADDPAIR(kSecAttrSerialNumber, certificate->_serialNumber);
5570 if (skid) {
5571 DICT_ADDPAIR(kSecAttrSubjectKeyID, skid);
5572 }
5573 DICT_ADDPAIR(kSecAttrPublicKeyHash, pubKeyDigest);
5574 DICT_ADDPAIR(kSecValueData, certData);
5575 dict = DICT_CREATE(allocator);
5576
5577 out:
5578 CFReleaseSafe(label);
5579 CFReleaseSafe(alias);
5580 CFReleaseSafe(pubKeyDigest);
5581 CFReleaseSafe(certData);
5582 CFReleaseSafe(certificateEncoding);
5583 CFReleaseSafe(certificateType);
5584
5585 return dict;
5586 }
5587
5588 SecCertificateRef SecCertificateCreateFromAttributeDictionary(
5589 CFDictionaryRef refAttributes) {
5590 /* @@@ Support having an allocator in refAttributes. */
5591 CFAllocatorRef allocator = NULL;
5592 CFDataRef data = CFDictionaryGetValue(refAttributes, kSecValueData);
5593 return data ? SecCertificateCreateWithData(allocator, data) : NULL;
5594 }
5595 #endif
5596
5597 static bool _SecCertificateIsSelfSigned(SecCertificateRef certificate) {
5598 if (certificate->_isSelfSigned == kSecSelfSignedUnknown) {
5599 certificate->_isSelfSigned = kSecSelfSignedFalse;
5600 SecKeyRef publicKey = NULL;
5601 require(certificate && (CFGetTypeID(certificate) == SecCertificateGetTypeID()), out);
5602 require(publicKey = SecCertificateCopyKey(certificate), out);
5603 CFDataRef normalizedIssuer =
5604 SecCertificateGetNormalizedIssuerContent(certificate);
5605 CFDataRef normalizedSubject =
5606 SecCertificateGetNormalizedSubjectContent(certificate);
5607 require_quiet(normalizedIssuer && normalizedSubject &&
5608 CFEqual(normalizedIssuer, normalizedSubject), out);
5609
5610 CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(certificate);
5611 CFDataRef subjectKeyID = SecCertificateGetSubjectKeyID(certificate);
5612 if (authorityKeyID) {
5613 require_quiet(subjectKeyID && CFEqual(subjectKeyID, authorityKeyID), out);
5614 }
5615
5616 require_noerr_quiet(SecCertificateIsSignedBy(certificate, publicKey), out);
5617
5618 certificate->_isSelfSigned = kSecSelfSignedTrue;
5619 out:
5620 CFReleaseSafe(publicKey);
5621 }
5622
5623 return (certificate->_isSelfSigned == kSecSelfSignedTrue);
5624 }
5625
5626 bool SecCertificateIsCA(SecCertificateRef certificate) {
5627 bool result = false;
5628 require(certificate && (CFGetTypeID(certificate) == SecCertificateGetTypeID()), out);
5629 if (SecCertificateVersion(certificate) >= 3) {
5630 const SecCEBasicConstraints *basicConstraints = SecCertificateGetBasicConstraints(certificate);
5631 result = (basicConstraints && basicConstraints->isCA);
5632 }
5633 else {
5634 result = _SecCertificateIsSelfSigned(certificate);
5635 }
5636 out:
5637 return result;
5638 }
5639
5640 bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate) {
5641 return (_SecCertificateIsSelfSigned(certificate) && SecCertificateIsCA(certificate));
5642 }
5643
5644 OSStatus SecCertificateIsSelfSigned(SecCertificateRef certificate, Boolean *isSelfSigned) {
5645 if (!certificate || (CFGetTypeID(certificate) != SecCertificateGetTypeID())) {
5646 return errSecInvalidCertificate;
5647 }
5648 if (!isSelfSigned) {
5649 return errSecParam;
5650 }
5651 *isSelfSigned = _SecCertificateIsSelfSigned(certificate);
5652 return errSecSuccess;
5653 }
5654
5655 SecKeyUsage SecCertificateGetKeyUsage(SecCertificateRef certificate) {
5656 if (!certificate) {
5657 return kSecKeyUsageUnspecified;
5658 }
5659 return certificate->_keyUsage;
5660 }
5661
5662 CFArrayRef SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate)
5663 {
5664 CFMutableArrayRef extended_key_usage_oids =
5665 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
5666 require_quiet(certificate && extended_key_usage_oids, out);
5667 int ix;
5668 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5669 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5670 if (extn->extnID.length == oidExtendedKeyUsage.length &&
5671 !memcmp(extn->extnID.data, oidExtendedKeyUsage.data, extn->extnID.length)) {
5672 DERTag tag;
5673 DERSequence derSeq;
5674 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &derSeq);
5675 require_noerr_quiet(drtn, out);
5676 require_quiet(tag == ASN1_CONSTR_SEQUENCE, out);
5677 DERDecodedInfo currDecoded;
5678
5679 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
5680 require_quiet(currDecoded.tag == ASN1_OBJECT_ID, out);
5681 CFDataRef oid = CFDataCreate(kCFAllocatorDefault,
5682 currDecoded.content.data, currDecoded.content.length);
5683 require_quiet(oid, out);
5684 CFArrayAppendValue(extended_key_usage_oids, oid);
5685 CFReleaseNull(oid);
5686 }
5687 require_quiet(drtn == DR_EndOfSequence, out);
5688 return extended_key_usage_oids;
5689 }
5690 }
5691 out:
5692 CFReleaseSafe(extended_key_usage_oids);
5693 return NULL;
5694 }
5695
5696 CFArrayRef SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate)
5697 {
5698 require_quiet(certificate, out);
5699 int ix;
5700
5701 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5702 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5703 if (extn->extnID.length == oidGoogleEmbeddedSignedCertificateTimestamp.length &&
5704 !memcmp(extn->extnID.data, oidGoogleEmbeddedSignedCertificateTimestamp.data, extn->extnID.length)) {
5705 /* Got the SCT oid */
5706 DERDecodedInfo sctList;
5707 DERReturn drtn = DERDecodeItem(&extn->extnValue, &sctList);
5708 require_noerr_quiet(drtn, out);
5709 require_quiet(sctList.tag == ASN1_OCTET_STRING, out);
5710 return SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sctList.content.data, sctList.content.length);
5711 }
5712 }
5713 out:
5714 return NULL;
5715 }
5716
5717
5718 static bool matches_expected(DERItem der, CFTypeRef expected) {
5719 if (der.length > 1) {
5720 DERDecodedInfo decoded;
5721 DERDecodeItem(&der, &decoded);
5722 switch (decoded.tag) {
5723 case ASN1_NULL:
5724 {
5725 return decoded.content.length == 0 && expected == NULL;
5726 }
5727 break;
5728
5729 case ASN1_IA5_STRING:
5730 case ASN1_UTF8_STRING: {
5731 if (isString(expected)) {
5732 CFStringRef expectedString = (CFStringRef) expected;
5733 CFStringRef itemString = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, decoded.content.data, decoded.content.length, kCFStringEncodingUTF8, false, kCFAllocatorNull);
5734
5735 bool result = (kCFCompareEqualTo == CFStringCompare(expectedString, itemString, 0));
5736 CFReleaseNull(itemString);
5737 return result;
5738 }
5739 }
5740 break;
5741
5742 case ASN1_OCTET_STRING: {
5743 if (isData(expected)) {
5744 CFDataRef expectedData = (CFDataRef) expected;
5745 CFDataRef itemData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, decoded.content.data, decoded.content.length, kCFAllocatorNull);
5746
5747 bool result = CFEqual(expectedData, itemData);
5748 CFReleaseNull(itemData);
5749 return result;
5750 }
5751 }
5752 break;
5753
5754 case ASN1_INTEGER: {
5755 SInt32 expected_value = 0;
5756 if (isString(expected))
5757 {
5758 CFStringRef aStr = (CFStringRef)expected;
5759 expected_value = CFStringGetIntValue(aStr);
5760 }
5761 else if (isNumber(expected))
5762 {
5763 CFNumberGetValue(expected, kCFNumberSInt32Type, &expected_value);
5764 }
5765
5766 uint32_t num_value = 0;
5767 if (!DERParseInteger(&decoded.content, &num_value))
5768 {
5769 return ((uint32_t)expected_value == num_value);
5770 }
5771 }
5772 break;
5773
5774 default:
5775 break;
5776 }
5777 }
5778
5779 return false;
5780 }
5781
5782 static bool cert_contains_marker_extension_value(SecCertificateRef certificate, CFDataRef oid, CFTypeRef expectedValue)
5783 {
5784 CFIndex ix;
5785 const uint8_t *oid_data = CFDataGetBytePtr(oid);
5786 size_t oid_len = CFDataGetLength(oid);
5787
5788 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5789 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5790 if (extn->extnID.length == oid_len
5791 && !memcmp(extn->extnID.data, oid_data, extn->extnID.length))
5792 {
5793 return matches_expected(extn->extnValue, expectedValue);
5794 }
5795 }
5796 return false;
5797 }
5798
5799 static bool cert_contains_marker_extension(SecCertificateRef certificate, CFTypeRef oid)
5800 {
5801 return cert_contains_marker_extension_value(certificate, oid, NULL);
5802 }
5803
5804 struct search_context {
5805 bool found;
5806 SecCertificateRef certificate;
5807 };
5808
5809 static bool GetDecimalValueOfString(CFStringRef string, uint32_t* value)
5810 {
5811 CFCharacterSetRef nonDecimalDigit = CFCharacterSetCreateInvertedSet(NULL, CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit));
5812 bool result = false;
5813
5814 if ( CFStringGetLength(string) > 0
5815 && !CFStringFindCharacterFromSet(string, nonDecimalDigit, CFRangeMake(0, CFStringGetLength(string)), kCFCompareForcedOrdering, NULL))
5816 {
5817 if (value)
5818 *value = CFStringGetIntValue(string);
5819 result = true;
5820 }
5821
5822 CFReleaseNull(nonDecimalDigit);
5823
5824 return result;
5825 }
5826
5827 bool SecCertificateIsOidString(CFStringRef oid)
5828 {
5829 if (!oid) return false;
5830 if (2 >= CFStringGetLength(oid)) return false;
5831 bool result = true;
5832
5833 /* oid string only has the allowed characters */
5834 CFCharacterSetRef decimalOid = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("0123456789."));
5835 CFCharacterSetRef nonDecimalOid = CFCharacterSetCreateInvertedSet(NULL, decimalOid);
5836 if (CFStringFindCharacterFromSet(oid, nonDecimalOid, CFRangeMake(0, CFStringGetLength(oid)), kCFCompareForcedOrdering, NULL)) {
5837 result = false;
5838 }
5839
5840 /* first arc is allowed */
5841 UniChar firstArc[2];
5842 CFRange firstTwo = {0, 2};
5843 CFStringGetCharacters(oid, firstTwo, firstArc);
5844 if (firstArc[1] != '.' ||
5845 (firstArc[0] != '0' && firstArc[0] != '1' && firstArc[0] != '2')) {
5846 result = false;
5847 }
5848
5849 CFReleaseNull(decimalOid);
5850 CFReleaseNull(nonDecimalOid);
5851
5852 return result;
5853 }
5854
5855 CFDataRef SecCertificateCreateOidDataFromString(CFAllocatorRef allocator, CFStringRef string)
5856 {
5857 CFMutableDataRef currentResult = NULL;
5858 CFDataRef encodedResult = NULL;
5859
5860 CFArrayRef parts = NULL;
5861 CFIndex count = 0;
5862
5863 if (!string || !SecCertificateIsOidString(string))
5864 goto exit;
5865
5866 parts = CFStringCreateArrayBySeparatingStrings(NULL, string, CFSTR("."));
5867
5868 if (!parts)
5869 goto exit;
5870
5871 count = CFArrayGetCount(parts);
5872 if (count == 0)
5873 goto exit;
5874
5875 // assume no more than 5 bytes needed to represent any part of the oid,
5876 // since we limit parts to 32-bit values,
5877 // but the first two parts only need 1 byte
5878 currentResult = CFDataCreateMutable(allocator, 1+(count-2)*5);
5879
5880 CFStringRef part;
5881 uint32_t x;
5882 uint8_t firstByte;
5883
5884 part = CFArrayGetValueAtIndex(parts, 0);
5885
5886 if (!GetDecimalValueOfString(part, &x) || x > 6)
5887 goto exit;
5888
5889 firstByte = x * 40;
5890
5891
5892 if (count > 1) {
5893 part = CFArrayGetValueAtIndex(parts, 1);
5894
5895 if (!GetDecimalValueOfString(part, &x) || x > 39)
5896 goto exit;
5897
5898 firstByte += x;
5899 }
5900
5901 CFDataAppendBytes(currentResult, &firstByte, 1);
5902
5903 for (CFIndex i = 2; i < count && GetDecimalValueOfString(CFArrayGetValueAtIndex(parts, i), &x); ++i) {
5904 uint8_t b[5] = {0, 0, 0, 0, 0};
5905 b[4] = (x & 0x7F);
5906 b[3] = 0x80 | ((x >> 7) & 0x7F);
5907 b[2] = 0x80 | ((x >> 14) & 0x7F);
5908 b[1] = 0x80 | ((x >> 21) & 0x7F);
5909 b[0] = 0x80 | ((x >> 28) & 0x7F);
5910
5911 // Skip the unused extension bytes.
5912 size_t skipBytes = 0;
5913 while (b[skipBytes] == 0x80)
5914 ++skipBytes;
5915
5916 CFDataAppendBytes(currentResult, b + skipBytes, sizeof(b) - skipBytes);
5917 }
5918
5919 encodedResult = currentResult;
5920 currentResult = NULL;
5921
5922 exit:
5923 CFReleaseNull(parts);
5924 CFReleaseNull(currentResult);
5925
5926 return encodedResult;
5927 }
5928
5929 static void check_for_marker(const void *key, const void *value, void *context)
5930 {
5931 struct search_context * search_ctx = (struct search_context *) context;
5932 CFStringRef key_string = (CFStringRef) key;
5933 CFTypeRef value_ref = (CFTypeRef) value;
5934
5935 // If we could have short circuted the iteration
5936 // we would have, but the best we can do
5937 // is not waste time comparing once a match
5938 // was found.
5939 if (search_ctx->found)
5940 return;
5941
5942 if (CFGetTypeID(key_string) != CFStringGetTypeID())
5943 return;
5944
5945 CFDataRef key_data = SecCertificateCreateOidDataFromString(NULL, key_string);
5946
5947 if (NULL == key_data)
5948 return;
5949
5950 if (cert_contains_marker_extension_value(search_ctx->certificate, key_data, value_ref))
5951 search_ctx->found = true;
5952
5953 CFReleaseNull(key_data);
5954 }
5955
5956 //
5957 // CFType Ref is either:
5958 //
5959 // CFData - OID to match with no data permitted
5960 // CFString - decimal OID to match
5961 // CFDictionary - OID -> Value table for expected values Single Object or Array
5962 // CFArray - Array of the above.
5963 //
5964 // This returns true if any of the requirements are met.
5965 bool SecCertificateHasMarkerExtension(SecCertificateRef certificate, CFTypeRef oids)
5966 {
5967 if (CFGetTypeID(oids) == CFArrayGetTypeID()) {
5968 CFIndex ix, length = CFArrayGetCount(oids);
5969 for (ix = 0; ix < length; ix++)
5970 if (SecCertificateHasMarkerExtension(certificate, CFArrayGetValueAtIndex((CFArrayRef)oids, ix)))
5971 return true;
5972 } else if (CFGetTypeID(oids) == CFDictionaryGetTypeID()) {
5973 struct search_context context = { .found = false, .certificate = certificate };
5974 CFDictionaryApplyFunction((CFDictionaryRef) oids, &check_for_marker, &context);
5975 return context.found;
5976 } else if (CFGetTypeID(oids) == CFDataGetTypeID()) {
5977 return cert_contains_marker_extension(certificate, oids);
5978 } else if (CFGetTypeID(oids) == CFStringGetTypeID()) {
5979 CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, oids);
5980 if (dataOid == NULL) return false;
5981 bool result = cert_contains_marker_extension(certificate, dataOid);
5982 CFReleaseNull(dataOid);
5983 return result;
5984 }
5985 return false;
5986 }
5987
5988 static DERItem *cert_extension_value_for_marker(SecCertificateRef certificate, CFDataRef oid) {
5989 CFIndex ix;
5990 const uint8_t *oid_data = CFDataGetBytePtr(oid);
5991 size_t oid_len = CFDataGetLength(oid);
5992
5993 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5994 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5995 if (extn->extnID.length == oid_len
5996 && !memcmp(extn->extnID.data, oid_data, extn->extnID.length))
5997 {
5998 return (DERItem *)&extn->extnValue;
5999 }
6000 }
6001 return NULL;
6002 }
6003
6004 //
6005 // CFType Ref is either:
6006 //
6007 // CFData - OID to match with no data permitted
6008 // CFString - decimal OID to match
6009 //
6010 DERItem *SecCertificateGetExtensionValue(SecCertificateRef certificate, CFTypeRef oid) {
6011 if (!certificate || !oid) {
6012 return NULL;
6013 }
6014
6015 if(CFGetTypeID(oid) == CFDataGetTypeID()) {
6016 return cert_extension_value_for_marker(certificate, oid);
6017 } else if (CFGetTypeID(oid) == CFStringGetTypeID()) {
6018 CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, oid);
6019 if (dataOid == NULL) return NULL;
6020 DERItem *result = cert_extension_value_for_marker(certificate, dataOid);
6021 CFReleaseNull(dataOid);
6022 return result;
6023 }
6024
6025 return NULL;
6026 }
6027
6028 CFDataRef SecCertificateCopyExtensionValue(SecCertificateRef certificate, CFTypeRef extensionOID, bool *isCritical) {
6029 if (!certificate || !extensionOID) {
6030 return NULL;
6031 }
6032
6033 CFDataRef oid = NULL, extensionValue = NULL;
6034 if (CFGetTypeID(extensionOID) == CFDataGetTypeID()) {
6035 oid = CFRetainSafe(extensionOID);
6036 } else if (CFGetTypeID(extensionOID) == CFStringGetTypeID()) {
6037 oid = SecCertificateCreateOidDataFromString(NULL, extensionOID);
6038 }
6039 if (!oid) {
6040 return NULL;
6041 }
6042
6043 CFIndex ix;
6044 const uint8_t *oid_data = CFDataGetBytePtr(oid);
6045 size_t oid_len = CFDataGetLength(oid);
6046
6047 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
6048 const SecCertificateExtension *extn = &certificate->_extensions[ix];
6049 if (extn->extnID.length == oid_len
6050 && !memcmp(extn->extnID.data, oid_data, extn->extnID.length))
6051 {
6052 if (isCritical) {
6053 *isCritical = extn->critical;
6054 }
6055 extensionValue = CFDataCreate(NULL, extn->extnValue.data, extn->extnValue.length);
6056 break;
6057 }
6058 }
6059
6060 CFReleaseNull(oid);
6061 return extensionValue;
6062 }
6063
6064 CFDataRef SecCertificateCopyiAPAuthCapabilities(SecCertificateRef certificate) {
6065 if (!certificate) {
6066 return NULL;
6067 }
6068 CFDataRef extensionData = NULL;
6069 DERItem *extensionValue = NULL;
6070 extensionValue = SecCertificateGetExtensionValue(certificate,
6071 CFSTR("1.2.840.113635.100.6.36"));
6072 require_quiet(extensionValue, out);
6073 /* The extension is a octet string containing the DER-encoded 32-byte octet string */
6074 require_quiet(extensionValue->length == 34, out);
6075 DERDecodedInfo decodedValue;
6076 require_noerr_quiet(DERDecodeItem(extensionValue, &decodedValue), out);
6077 if (decodedValue.tag == ASN1_OCTET_STRING) {
6078 require_quiet(decodedValue.content.length == 32, out);
6079 extensionData = CFDataCreate(NULL, decodedValue.content.data,
6080 decodedValue.content.length);
6081 } else {
6082 require_quiet(extensionValue->data[33] == 0x00 &&
6083 extensionValue->data[32] == 0x00, out);
6084 extensionData = CFDataCreate(NULL, extensionValue->data, 32);
6085 }
6086 out:
6087 return extensionData;
6088 }
6089
6090 #if 0
6091 /* From iapd IAPAuthenticationTypes.h */
6092 typedef struct IapCertSerialNumber
6093 {
6094 uint8_t xservID; // Xserver ID
6095 uint8_t hsmID; // Hardware security module ID (generated cert)
6096 uint8_t delimiter01; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6097 uint8_t dateYear; // Date year cert was issued
6098 uint8_t dateMonth; // Date month cert was issued
6099 uint8_t dateDay; // Date day cert was issued
6100 uint8_t delimiter02; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6101 uint8_t devClass; // iAP device class (maps to lingo permissions)
6102 uint8_t delimiter03; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6103 uint8_t batchNumHi; // Batch number high byte (15:08)
6104 uint8_t batchNumLo; // Batch number low byte (07:00)
6105 uint8_t delimiter04; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6106 uint8_t serialNumHi; // Serial number high byte (23:16)
6107 uint8_t serialNumMid; // Serial number middle byte (15:08)
6108 uint8_t serialNumLo; // Serial number low byte (07:00)
6109
6110 } IapCertSerialNumber_t, *pIapCertSerialNumber_t;
6111 #endif
6112
6113 #define IAP_CERT_FIELD_DELIMITER 0xAA // "Apple_Accessory" delimiter
6114 SeciAuthVersion SecCertificateGetiAuthVersion(SecCertificateRef certificate) {
6115 if (!certificate) {
6116 return kSeciAuthInvalid;
6117 }
6118 if (NULL != SecCertificateGetExtensionValue(certificate,
6119 CFSTR("1.2.840.113635.100.6.36"))) {
6120 /* v3 Capabilities Extension */
6121 return kSeciAuthVersion3;
6122 }
6123 if (NULL != SecCertificateGetExtensionValue(certificate,
6124 CFSTR("1.2.840.113635.100.6.59.1"))) {
6125 /* SW Auth General Capabilities Extension */
6126 return kSeciAuthVersionSW;
6127 }
6128 DERItem serialNumber = certificate->_serialNum;
6129 require_quiet(serialNumber.data, out);
6130 require_quiet(serialNumber.length == 15, out);
6131 require_quiet(serialNumber.data[2] == IAP_CERT_FIELD_DELIMITER &&
6132 serialNumber.data[6] == IAP_CERT_FIELD_DELIMITER &&
6133 serialNumber.data[8] == IAP_CERT_FIELD_DELIMITER &&
6134 serialNumber.data[11] == IAP_CERT_FIELD_DELIMITER, out);
6135 return kSeciAuthVersion2;
6136 out:
6137 return kSeciAuthInvalid;
6138 }
6139
6140 static CFStringRef SecCertificateiAPSWAuthCapabilitiesTypeToOID(SeciAPSWAuthCapabilitiesType type) {
6141 CFStringRef extensionOID = NULL;
6142 /* Get the oid for the type */
6143 if (type == kSeciAPSWAuthGeneralCapabilities) {
6144 extensionOID = CFSTR("1.2.840.113635.100.6.59.1");
6145 } else if (type == kSeciAPSWAuthAirPlayCapabilities) {
6146 extensionOID = CFSTR("1.2.840.113635.100.6.59.2");
6147 } else if (type == kSeciAPSWAuthHomeKitCapabilities) {
6148 extensionOID = CFSTR("1.2.840.113635.100.6.59.3");
6149 }
6150 return extensionOID;
6151 }
6152
6153 CFDataRef SecCertificateCopyiAPSWAuthCapabilities(SecCertificateRef certificate, SeciAPSWAuthCapabilitiesType type) {
6154 if (!certificate) {
6155 return NULL;
6156 }
6157 CFDataRef extensionData = NULL;
6158 DERItem *extensionValue = NULL;
6159 CFStringRef extensionOID = SecCertificateiAPSWAuthCapabilitiesTypeToOID(type);
6160 require_quiet(extensionOID, out);
6161 extensionValue = SecCertificateGetExtensionValue(certificate, extensionOID);
6162 require_quiet(extensionValue, out);
6163 /* The extension is a octet string containing the DER-encoded variable-length octet string */
6164 DERDecodedInfo decodedValue;
6165 require_noerr_quiet(DERDecodeItem(extensionValue, &decodedValue), out);
6166 if (decodedValue.tag == ASN1_OCTET_STRING) {
6167 extensionData = CFDataCreate(NULL, decodedValue.content.data,
6168 decodedValue.content.length);
6169 }
6170 out:
6171 return extensionData;
6172 }
6173
6174 SecCertificateRef SecCertificateCreateWithPEM(CFAllocatorRef allocator,
6175 CFDataRef pem_certificate)
6176 {
6177 static const char begin_cert[] = "-----BEGIN CERTIFICATE-----\n";
6178 static const char end_cert[] = "-----END CERTIFICATE-----\n";
6179 uint8_t *base64_data = NULL;
6180 SecCertificateRef cert = NULL;
6181 const unsigned char *data = CFDataGetBytePtr(pem_certificate);
6182 //const size_t length = CFDataGetLength(pem_certificate);
6183 char *begin = strstr((const char *)data, begin_cert);
6184 char *end = strstr((const char *)data, end_cert);
6185 if (!begin || !end)
6186 return NULL;
6187 begin += sizeof(begin_cert) - 1;
6188 size_t base64_length = SecBase64Decode(begin, end - begin, NULL, 0);
6189 if (base64_length && (base64_length < (size_t)CFDataGetLength(pem_certificate))) {
6190 require_quiet(base64_data = calloc(1, base64_length), out);
6191 require_action_quiet(base64_length = SecBase64Decode(begin, end - begin, base64_data, base64_length), out, free(base64_data));
6192 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, base64_data, base64_length);
6193 free(base64_data);
6194 }
6195 out:
6196 return cert;
6197 }
6198
6199
6200 //
6201 // -- MARK -- XPC encoding/decoding
6202 //
6203
6204 bool SecCertificateAppendToXPCArray(SecCertificateRef certificate, xpc_object_t xpc_certificates, CFErrorRef *error) {
6205 if (!certificate)
6206 return true; // NOOP
6207
6208 size_t length = SecCertificateGetLength(certificate);
6209 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
6210 #if SECTRUST_VERBOSE_DEBUG
6211 secerror("cert=0x%lX length=%d bytes=0x%lX", (uintptr_t)certificate, (int)length, (uintptr_t)bytes);
6212 #endif
6213 if (!length || !bytes) {
6214 return SecError(errSecParam, error, CFSTR("failed to der encode certificate"));
6215 }
6216 xpc_array_set_data(xpc_certificates, XPC_ARRAY_APPEND, bytes, length);
6217 return true;
6218 }
6219
6220 SecCertificateRef SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates, size_t index, CFErrorRef *error) {
6221 SecCertificateRef certificate = NULL;
6222 size_t length = 0;
6223 const uint8_t *bytes = xpc_array_get_data(xpc_certificates, index, &length);
6224 if (bytes) {
6225 certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length);
6226 }
6227 if (!certificate) {
6228 SecError(errSecParam, error, CFSTR("certificates[%zu] failed to decode"), index);
6229 }
6230 return certificate;
6231 }
6232
6233 xpc_object_t SecCertificateArrayCopyXPCArray(CFArrayRef certificates, CFErrorRef *error) {
6234 xpc_object_t xpc_certificates;
6235 require_action_quiet(xpc_certificates = xpc_array_create(NULL, 0), exit,
6236 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array")));
6237 CFIndex ix, count = CFArrayGetCount(certificates);
6238 for (ix = 0; ix < count; ++ix) {
6239 SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, ix);
6240 #if SECTRUST_VERBOSE_DEBUG
6241 CFIndex length = SecCertificateGetLength(certificate);
6242 const UInt8 *bytes = SecCertificateGetBytePtr(certificate);
6243 secerror("idx=%d of %d; cert=0x%lX length=%ld bytes=0x%lX", (int)ix, (int)count, (uintptr_t)certificate, (size_t)length, (uintptr_t)bytes);
6244 #endif
6245 if (!SecCertificateAppendToXPCArray(certificate, xpc_certificates, error)) {
6246 xpc_release(xpc_certificates);
6247 xpc_certificates = NULL;
6248 break;
6249 }
6250 }
6251
6252 exit:
6253 return xpc_certificates;
6254 }
6255
6256 CFArrayRef SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates, CFErrorRef *error) {
6257 CFMutableArrayRef certificates = NULL;
6258 require_action_quiet(xpc_get_type(xpc_certificates) == XPC_TYPE_ARRAY, exit,
6259 SecError(errSecParam, error, CFSTR("certificates xpc value is not an array")));
6260 size_t count = xpc_array_get_count(xpc_certificates);
6261 require_action_quiet(certificates = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit,
6262 SecError(errSecAllocate, error, CFSTR("failed to create CFArray of capacity %zu"), count));
6263
6264 size_t ix;
6265 for (ix = 0; ix < count; ++ix) {
6266 SecCertificateRef cert = SecCertificateCreateWithXPCArrayAtIndex(xpc_certificates, ix, error);
6267 if (!cert) {
6268 CFRelease(certificates);
6269 return NULL;
6270 }
6271 CFArraySetValueAtIndex(certificates, ix, cert);
6272 CFRelease(cert);
6273 }
6274
6275 exit:
6276 return certificates;
6277 }
6278
6279 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
6280
6281
6282 static CFArrayRef CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType, CFErrorRef* error)
6283 {
6284 __block CFArrayRef result = NULL;
6285
6286 do_if_registered(ota_CopyEscrowCertificates, escrowRootType, error);
6287
6288 securityd_send_sync_and_do(kSecXPCOpOTAGetEscrowCertificates, error,
6289 ^bool(xpc_object_t message, CFErrorRef *error)
6290 {
6291 xpc_dictionary_set_uint64(message, "escrowType", (uint64_t)escrowRootType);
6292 return true;
6293 },
6294 ^bool(xpc_object_t response, CFErrorRef *error)
6295 {
6296 xpc_object_t xpc_array = xpc_dictionary_get_value(response, kSecXPCKeyResult);
6297
6298 if (response && (NULL != xpc_array)) {
6299 result = (CFArrayRef)_CFXPCCreateCFObjectFromXPCObject(xpc_array);
6300 }
6301 else {
6302 return SecError(errSecInternal, error, CFSTR("Did not get the Escrow certificates"));
6303 }
6304 return result != NULL;
6305 });
6306 return result;
6307 }
6308
6309 CFArrayRef SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType)
6310 {
6311 CFArrayRef result = NULL;
6312 int iCnt;
6313 CFDataRef certData = NULL;
6314 int numRoots = 0;
6315
6316 if (kSecCertificateBaselineEscrowRoot == escrowRootType ||
6317 kSecCertificateBaselinePCSEscrowRoot == escrowRootType ||
6318 kSecCertificateBaselineEscrowBackupRoot == escrowRootType ||
6319 kSecCertificateBaselineEscrowEnrollmentRoot == escrowRootType)
6320 {
6321 // The request is for the base line certificates.
6322 // Use the hard coded data to generate the return array.
6323 struct RootRecord** pEscrowRoots;
6324 switch (escrowRootType) {
6325 case kSecCertificateBaselineEscrowRoot:
6326 numRoots = kNumberOfBaseLineEscrowRoots;
6327 pEscrowRoots = kBaseLineEscrowRoots;
6328 break;
6329 case kSecCertificateBaselinePCSEscrowRoot:
6330 numRoots = kNumberOfBaseLinePCSEscrowRoots;
6331 pEscrowRoots = kBaseLinePCSEscrowRoots;
6332 break;
6333 case kSecCertificateBaselineEscrowBackupRoot:
6334 numRoots = kNumberOfBaseLineEscrowBackupRoots;
6335 pEscrowRoots = kBaseLineEscrowBackupRoots;
6336 break;
6337 case kSecCertificateBaselineEscrowEnrollmentRoot:
6338 default:
6339 numRoots = kNumberOfBaseLineEscrowEnrollmentRoots;
6340 pEscrowRoots = kBaseLineEscrowEnrollmentRoots;
6341 break;
6342 }
6343
6344 // Get the hard coded set of roots
6345 SecCertificateRef baseLineCerts[numRoots];
6346 struct RootRecord* pRootRecord = NULL;
6347
6348 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6349 pRootRecord = pEscrowRoots[iCnt];
6350 if (NULL != pRootRecord && pRootRecord->_length > 0 && NULL != pRootRecord->_bytes) {
6351 certData = CFDataCreate(kCFAllocatorDefault, pRootRecord->_bytes, pRootRecord->_length);
6352 if (NULL != certData) {
6353 baseLineCerts[iCnt] = SecCertificateCreateWithData(kCFAllocatorDefault, certData);
6354 CFRelease(certData);
6355 }
6356 }
6357 }
6358 result = CFArrayCreate(kCFAllocatorDefault, (const void **)baseLineCerts, numRoots, &kCFTypeArrayCallBacks);
6359 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6360 if (NULL != baseLineCerts[iCnt]) {
6361 CFRelease(baseLineCerts[iCnt]);
6362 }
6363 }
6364 }
6365 else {
6366 // The request is for the current certificates.
6367 CFErrorRef error = NULL;
6368 CFArrayRef cert_datas = CopyEscrowCertificates(escrowRootType, &error);
6369 if (NULL != error || NULL == cert_datas) {
6370 if (NULL != error) {
6371 CFRelease(error);
6372 }
6373 if (NULL != cert_datas) {
6374 CFRelease(cert_datas);
6375 }
6376 return result;
6377 }
6378
6379 numRoots = (int)(CFArrayGetCount(cert_datas));
6380
6381 SecCertificateRef assetCerts[numRoots];
6382 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6383 certData = (CFDataRef)CFArrayGetValueAtIndex(cert_datas, iCnt);
6384 if (NULL != certData) {
6385 SecCertificateRef aCertRef = SecCertificateCreateWithData(kCFAllocatorDefault, certData);
6386 assetCerts[iCnt] = aCertRef;
6387 }
6388 else {
6389 assetCerts[iCnt] = NULL;
6390 }
6391 }
6392
6393 if (numRoots > 0) {
6394 result = CFArrayCreate(kCFAllocatorDefault, (const void **)assetCerts, numRoots, &kCFTypeArrayCallBacks);
6395 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6396 if (NULL != assetCerts[iCnt]) {
6397 CFRelease(assetCerts[iCnt]);
6398 }
6399 }
6400 }
6401 CFReleaseSafe(cert_datas);
6402 }
6403 return result;
6404 }
6405
6406 SEC_CONST_DECL (kSecSignatureDigestAlgorithmUnknown, "SignatureDigestUnknown");
6407 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD2, "SignatureDigestMD2");
6408 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD4, "SignatureDigestMD4");
6409 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD5, "SignatureDigestMD5");
6410 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA1, "SignatureDigestSHA1");
6411 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA224, "SignatureDigestSHA224");
6412 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA256, "SignatureDigestSHA256");
6413 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA384, "SignatureDigestSHA284");
6414 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA512, "SignatureDigestSHA512");
6415
6416 SecSignatureHashAlgorithm SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate)
6417 {
6418 SecSignatureHashAlgorithm result = kSecSignatureHashAlgorithmUnknown;
6419 DERAlgorithmId *algId = (certificate) ? &certificate->_tbsSigAlg : NULL;
6420 const DERItem *algOid = (algId) ? &algId->oid : NULL;
6421 while (algOid) {
6422 if (!algOid->data || !algOid->length) {
6423 break;
6424 }
6425 /* classify the signature algorithm OID into one of our known types */
6426 if (DEROidCompare(algOid, &oidSha512Ecdsa) ||
6427 DEROidCompare(algOid, &oidSha512Rsa) ||
6428 DEROidCompare(algOid, &oidSha512)) {
6429 result = kSecSignatureHashAlgorithmSHA512;
6430 break;
6431 }
6432 if (DEROidCompare(algOid, &oidSha384Ecdsa) ||
6433 DEROidCompare(algOid, &oidSha384Rsa) ||
6434 DEROidCompare(algOid, &oidSha384)) {
6435 result = kSecSignatureHashAlgorithmSHA384;
6436 break;
6437 }
6438 if (DEROidCompare(algOid, &oidSha256Ecdsa) ||
6439 DEROidCompare(algOid, &oidSha256Rsa) ||
6440 DEROidCompare(algOid, &oidSha256)) {
6441 result = kSecSignatureHashAlgorithmSHA256;
6442 break;
6443 }
6444 if (DEROidCompare(algOid, &oidSha224Ecdsa) ||
6445 DEROidCompare(algOid, &oidSha224Rsa) ||
6446 DEROidCompare(algOid, &oidSha224)) {
6447 result = kSecSignatureHashAlgorithmSHA224;
6448 break;
6449 }
6450 if (DEROidCompare(algOid, &oidSha1Ecdsa) ||
6451 DEROidCompare(algOid, &oidSha1Rsa) ||
6452 DEROidCompare(algOid, &oidSha1Dsa) ||
6453 DEROidCompare(algOid, &oidSha1DsaOIW) ||
6454 DEROidCompare(algOid, &oidSha1DsaCommonOIW) ||
6455 DEROidCompare(algOid, &oidSha1RsaOIW) ||
6456 DEROidCompare(algOid, &oidSha1Fee) ||
6457 DEROidCompare(algOid, &oidSha1)) {
6458 result = kSecSignatureHashAlgorithmSHA1;
6459 break;
6460 }
6461 if (DEROidCompare(algOid, &oidMd5Rsa) ||
6462 DEROidCompare(algOid, &oidMd5Fee) ||
6463 DEROidCompare(algOid, &oidMd5)) {
6464 result = kSecSignatureHashAlgorithmMD5;
6465 break;
6466 }
6467 if (DEROidCompare(algOid, &oidMd4Rsa) ||
6468 DEROidCompare(algOid, &oidMd4)) {
6469 result = kSecSignatureHashAlgorithmMD4;
6470 break;
6471 }
6472 if (DEROidCompare(algOid, &oidMd2Rsa) ||
6473 DEROidCompare(algOid, &oidMd2)) {
6474 result = kSecSignatureHashAlgorithmMD2;
6475 break;
6476 }
6477 break;
6478 }
6479
6480 return result;
6481 }
6482
6483 CFArrayRef SecCertificateCopyiPhoneDeviceCAChain(void) {
6484 CFMutableArrayRef result = NULL;
6485 SecCertificateRef iPhoneDeviceCA = NULL, iPhoneCA = NULL, appleRoot = NULL;
6486
6487 require_quiet(iPhoneDeviceCA = SecCertificateCreateWithBytes(NULL, _AppleiPhoneDeviceCA, sizeof(_AppleiPhoneDeviceCA)),
6488 errOut);
6489 require_quiet(iPhoneCA = SecCertificateCreateWithBytes(NULL, _AppleiPhoneCA, sizeof(_AppleiPhoneCA)),
6490 errOut);
6491 require_quiet(appleRoot = SecCertificateCreateWithBytes(NULL, _AppleRootCA, sizeof(_AppleRootCA)),
6492 errOut);
6493
6494 require_quiet(result = CFArrayCreateMutable(NULL, 3, &kCFTypeArrayCallBacks), errOut);
6495 CFArrayAppendValue(result, iPhoneDeviceCA);
6496 CFArrayAppendValue(result, iPhoneCA);
6497 CFArrayAppendValue(result, appleRoot);
6498
6499 errOut:
6500 CFReleaseNull(iPhoneDeviceCA);
6501 CFReleaseNull(iPhoneCA);
6502 CFReleaseNull(appleRoot);
6503 return result;
6504 }