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