]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCertificate.c
Security-58286.31.2.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 <= 37, 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 // rdn_props is now retained by the original properties array
2779 CFReleaseSafe(rdn_props);
2780 } else {
2781 /* Since this is the third or later rdn pair we have already
2782 created a subsection in the top level properties array. Instead
2783 of appending to that directly we append to the array inside the
2784 subsection. */
2785 properties = (CFMutableArrayRef)CFDictionaryGetValue(
2786 (CFDictionaryRef)lastValue, kSecPropertyKeyValue);
2787 }
2788 }
2789
2790 /* Finally we append the new rdn value to the property array. */
2791 CFStringRef label = SecDERItemCopyOIDDecimalRepresentation(CFGetAllocator(properties),
2792 rdnType);
2793 CFStringRef localizedLabel =
2794 copyLocalizedOidDescription(CFGetAllocator(properties), rdnType);
2795 appendDERThingProperty(properties, label, localizedLabel, rdnValue);
2796 CFReleaseSafe(label);
2797 CFReleaseSafe(localizedLabel);
2798 return errSecSuccess;
2799 }
2800
2801 static CFArrayRef createPropertiesForRDNContent(CFAllocatorRef allocator,
2802 const DERItem *rdnSetContent) {
2803 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
2804 &kCFTypeArrayCallBacks);
2805 OSStatus status = parseRDNContent(rdnSetContent, properties,
2806 appendRDNProperty);
2807 if (status) {
2808 CFArrayRemoveAllValues(properties);
2809 appendInvalidProperty(properties, SEC_RDN_KEY, rdnSetContent);
2810 }
2811
2812 return properties;
2813 }
2814
2815 /*
2816 From rfc3739 - 3.1.2. Subject
2817
2818 When parsing the subject here are some tips for a short name of the cert.
2819 Choice I: commonName
2820 Choice II: givenName
2821 Choice III: pseudonym
2822
2823 The commonName attribute value SHALL, when present, contain a name
2824 of the subject. This MAY be in the subject's preferred
2825 presentation format, or a format preferred by the CA, or some
2826 other format. Pseudonyms, nicknames, and names with spelling
2827 other than defined by the registered name MAY be used. To
2828 understand the nature of the name presented in commonName,
2829 complying applications MAY have to examine present values of the
2830 givenName and surname attributes, or the pseudonym attribute.
2831
2832 */
2833 static CFArrayRef createPropertiesForX501NameContent(CFAllocatorRef allocator,
2834 const DERItem *x501NameContent) {
2835 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
2836 &kCFTypeArrayCallBacks);
2837 OSStatus status = parseX501NameContent(x501NameContent, properties,
2838 appendRDNProperty);
2839 if (status) {
2840 CFArrayRemoveAllValues(properties);
2841 appendInvalidProperty(properties, SEC_X501_NAME_KEY, x501NameContent);
2842 }
2843
2844 return properties;
2845 }
2846
2847 static CFArrayRef createPropertiesForX501Name(CFAllocatorRef allocator,
2848 const DERItem *x501Name) {
2849 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
2850 &kCFTypeArrayCallBacks);
2851 OSStatus status = parseX501Name(x501Name, properties, appendRDNProperty);
2852 if (status) {
2853 CFArrayRemoveAllValues(properties);
2854 appendInvalidProperty(properties, SEC_X501_NAME_KEY, x501Name);
2855 }
2856
2857 return properties;
2858 }
2859
2860 static void appendIntegerProperty(CFMutableArrayRef properties,
2861 CFStringRef label, const DERItem *integer) {
2862 CFStringRef string = copyIntegerContentDescription(
2863 CFGetAllocator(properties), integer);
2864 appendProperty(properties, kSecPropertyTypeString, label, NULL, string);
2865 CFRelease(string);
2866 }
2867
2868 static void appendBoolProperty(CFMutableArrayRef properties,
2869 CFStringRef label, bool boolean) {
2870 CFStringRef value = SecCopyCertString(boolean ? SEC_YES_KEY : SEC_NO_KEY);
2871 appendProperty(properties, kSecPropertyTypeString, label, NULL, value);
2872 CFRelease(value);
2873 }
2874
2875 static void appendBooleanProperty(CFMutableArrayRef properties,
2876 CFStringRef label, const DERItem *boolean, bool defaultValue) {
2877 bool result;
2878 DERReturn drtn = DERParseBooleanWithDefault(boolean, defaultValue, &result);
2879 if (drtn) {
2880 /* Couldn't parse boolean; dump the raw unparsed data as hex. */
2881 appendInvalidProperty(properties, label, boolean);
2882 } else {
2883 appendBoolProperty(properties, label, result);
2884 }
2885 }
2886
2887 static void appendSerialNumberProperty(CFMutableArrayRef parent, CFStringRef label,
2888 DERItem *serialNum) {
2889 CFAllocatorRef allocator = CFGetAllocator(parent);
2890 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2891
2892 if (serialNum->length) {
2893 appendIntegerProperty(properties, SEC_SERIAL_NUMBER_KEY,
2894 serialNum);
2895 appendProperty(parent, kSecPropertyTypeSection, label, NULL, properties);
2896 }
2897
2898 CFReleaseNull(properties);
2899 }
2900
2901 static void appendBitStringContentNames(CFMutableArrayRef properties,
2902 CFStringRef label, const DERItem *bitStringContent,
2903 const CFStringRef *names, CFIndex namesCount) {
2904 DERSize len = bitStringContent->length - 1;
2905 require_quiet(len == 1 || len == 2, badDER);
2906 DERByte numUnusedBits = bitStringContent->data[0];
2907 require_quiet(numUnusedBits < 8, badDER);
2908 uint_fast16_t bits = 8 * len - numUnusedBits;
2909 require_quiet(bits <= (uint_fast16_t)namesCount, badDER);
2910 uint_fast16_t value = bitStringContent->data[1];
2911 uint_fast16_t mask;
2912 if (len > 1) {
2913 value = (value << 8) + bitStringContent->data[2];
2914 mask = 0x8000;
2915 } else {
2916 mask = 0x80;
2917 }
2918 uint_fast16_t ix;
2919 CFStringRef fmt = SecCopyCertString(SEC_STRING_LIST_KEY);
2920 CFStringRef string = NULL;
2921 for (ix = 0; ix < bits; ++ix) {
2922 if (value & mask) {
2923 if (string) {
2924 CFStringRef s =
2925 CFStringCreateWithFormat(CFGetAllocator(properties),
2926 NULL, fmt, string, names[ix]);
2927 CFRelease(string);
2928 string = s;
2929 } else {
2930 string = names[ix];
2931 CFRetain(string);
2932 }
2933 }
2934 mask >>= 1;
2935 }
2936 CFRelease(fmt);
2937 appendProperty(properties, kSecPropertyTypeString, label, NULL,
2938 string ? string : CFSTR(""));
2939 CFReleaseSafe(string);
2940 return;
2941 badDER:
2942 appendInvalidProperty(properties, label, bitStringContent);
2943 }
2944
2945 static void appendBitStringNames(CFMutableArrayRef properties,
2946 CFStringRef label, const DERItem *bitString,
2947 const CFStringRef *names, CFIndex namesCount) {
2948 DERDecodedInfo bitStringContent;
2949 DERReturn drtn = DERDecodeItem(bitString, &bitStringContent);
2950 require_noerr_quiet(drtn, badDER);
2951 require_quiet(bitStringContent.tag == ASN1_BIT_STRING, badDER);
2952 appendBitStringContentNames(properties, label, &bitStringContent.content,
2953 names, namesCount);
2954 return;
2955 badDER:
2956 appendInvalidProperty(properties, label, bitString);
2957 }
2958
2959 static void appendKeyUsage(CFMutableArrayRef properties,
2960 const DERItem *extnValue) {
2961 static const CFStringRef usageNames[] = {
2962 SEC_DIGITAL_SIGNATURE_KEY,
2963 SEC_NON_REPUDIATION_KEY,
2964 SEC_KEY_ENCIPHERMENT_KEY,
2965 SEC_DATA_ENCIPHERMENT_KEY,
2966 SEC_KEY_AGREEMENT_KEY,
2967 SEC_CERT_SIGN_KEY,
2968 SEC_CRL_SIGN_KEY,
2969 SEC_ENCIPHER_ONLY_KEY,
2970 SEC_DECIPHER_ONLY_KEY
2971 };
2972 appendBitStringNames(properties, SEC_USAGE_KEY, extnValue,
2973 usageNames, array_size(usageNames));
2974 }
2975
2976 static void appendPrivateKeyUsagePeriod(CFMutableArrayRef properties,
2977 const DERItem *extnValue) {
2978 DERPrivateKeyUsagePeriod pkup;
2979 DERReturn drtn = DERParseSequence(extnValue,
2980 DERNumPrivateKeyUsagePeriodItemSpecs, DERPrivateKeyUsagePeriodItemSpecs,
2981 &pkup, sizeof(pkup));
2982 require_noerr_quiet(drtn, badDER);
2983 if (pkup.notBefore.length) {
2984 appendDateContentProperty(properties, SEC_NOT_VALID_BEFORE_KEY,
2985 ASN1_GENERALIZED_TIME, &pkup.notBefore);
2986 }
2987 if (pkup.notAfter.length) {
2988 appendDateContentProperty(properties, SEC_NOT_VALID_AFTER_KEY,
2989 ASN1_GENERALIZED_TIME, &pkup.notAfter);
2990 }
2991 return;
2992 badDER:
2993 appendInvalidProperty(properties, SEC_PRIVATE_KU_PERIOD_KEY, extnValue);
2994 }
2995
2996 static void appendStringContentProperty(CFMutableArrayRef properties,
2997 CFStringRef label, const DERItem *stringContent,
2998 CFStringEncoding encoding) {
2999 CFStringRef string = CFStringCreateWithBytes(CFGetAllocator(properties),
3000 stringContent->data, stringContent->length, encoding, FALSE);
3001 if (string) {
3002 appendProperty(properties, kSecPropertyTypeString, label, NULL, string);
3003 CFRelease(string);
3004 } else {
3005 appendInvalidProperty(properties, label, stringContent);
3006 }
3007 }
3008
3009 /*
3010 OtherName ::= SEQUENCE {
3011 type-id OBJECT IDENTIFIER,
3012 value [0] EXPLICIT ANY DEFINED BY type-id }
3013 */
3014 static void appendOtherNameContentProperty(CFMutableArrayRef properties,
3015 const DERItem *otherNameContent) {
3016 DEROtherName on;
3017 DERReturn drtn = DERParseSequenceContent(otherNameContent,
3018 DERNumOtherNameItemSpecs, DEROtherNameItemSpecs,
3019 &on, sizeof(on));
3020 require_noerr_quiet(drtn, badDER);
3021 CFAllocatorRef allocator = CFGetAllocator(properties);
3022 CFStringRef label =
3023 SecDERItemCopyOIDDecimalRepresentation(allocator, &on.typeIdentifier);
3024 CFStringRef localizedLabel =
3025 copyLocalizedOidDescription(allocator, &on.typeIdentifier);
3026 CFStringRef value_string = copyDERThingDescription(allocator, &on.value, false);
3027 if (value_string)
3028 appendProperty(properties, kSecPropertyTypeString, label,
3029 localizedLabel, value_string);
3030 else
3031 appendUnparsedProperty(properties, label, localizedLabel, &on.value);
3032
3033 CFReleaseSafe(value_string);
3034 CFReleaseSafe(label);
3035 CFReleaseSafe(localizedLabel);
3036 return;
3037 badDER:
3038 appendInvalidProperty(properties, SEC_OTHER_NAME_KEY, otherNameContent);
3039 }
3040
3041 /*
3042 GeneralName ::= CHOICE {
3043 otherName [0] OtherName,
3044 rfc822Name [1] IA5String,
3045 dNSName [2] IA5String,
3046 x400Address [3] ORAddress,
3047 directoryName [4] Name,
3048 ediPartyName [5] EDIPartyName,
3049 uniformResourceIdentifier [6] IA5String,
3050 iPAddress [7] OCTET STRING,
3051 registeredID [8] OBJECT IDENTIFIER}
3052
3053 EDIPartyName ::= SEQUENCE {
3054 nameAssigner [0] DirectoryString OPTIONAL,
3055 partyName [1] DirectoryString }
3056 */
3057 static bool appendGeneralNameContentProperty(CFMutableArrayRef properties,
3058 DERTag tag, const DERItem *generalName) {
3059 switch (tag) {
3060 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0:
3061 appendOtherNameContentProperty(properties, generalName);
3062 break;
3063 case ASN1_CONTEXT_SPECIFIC | 1:
3064 /* IA5String. */
3065 appendStringContentProperty(properties, SEC_EMAIL_ADDRESS_KEY,
3066 generalName, kCFStringEncodingASCII);
3067 break;
3068 case ASN1_CONTEXT_SPECIFIC | 2:
3069 /* IA5String. */
3070 appendStringContentProperty(properties, SEC_DNS_NAME_KEY, generalName,
3071 kCFStringEncodingASCII);
3072 break;
3073 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3:
3074 appendUnparsedProperty(properties, SEC_X400_ADDRESS_KEY, NULL,
3075 generalName);
3076 break;
3077 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4:
3078 {
3079 CFArrayRef directory_plist =
3080 createPropertiesForX501Name(CFGetAllocator(properties),
3081 generalName);
3082 appendProperty(properties, kSecPropertyTypeSection,
3083 SEC_DIRECTORY_NAME_KEY, NULL, directory_plist);
3084 CFRelease(directory_plist);
3085 break;
3086 }
3087 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5:
3088 appendUnparsedProperty(properties, SEC_EDI_PARTY_NAME_KEY, NULL,
3089 generalName);
3090 break;
3091 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6:
3092 /* Technically I don't think this is valid, but there are certs out
3093 in the wild that use a constructed IA5String. In particular the
3094 VeriSign Time Stamping Authority CA.cer does this. */
3095 appendURLProperty(properties, SEC_URI_KEY, generalName);
3096 break;
3097 case ASN1_CONTEXT_SPECIFIC | 6:
3098 appendURLContentProperty(properties, SEC_URI_KEY, generalName);
3099 break;
3100 case ASN1_CONTEXT_SPECIFIC | 7:
3101 appendIPAddressContentProperty(properties, SEC_IP_ADDRESS_KEY,
3102 generalName);
3103 break;
3104 case ASN1_CONTEXT_SPECIFIC | 8:
3105 appendOIDProperty(properties, SEC_REGISTERED_ID_KEY, NULL, generalName);
3106 break;
3107 default:
3108 goto badDER;
3109 break;
3110 }
3111 return true;
3112 badDER:
3113 return false;
3114 }
3115
3116 static void appendGeneralNameProperty(CFMutableArrayRef properties,
3117 const DERItem *generalName) {
3118 DERDecodedInfo generalNameContent;
3119 DERReturn drtn = DERDecodeItem(generalName, &generalNameContent);
3120 require_noerr_quiet(drtn, badDER);
3121 if (appendGeneralNameContentProperty(properties, generalNameContent.tag,
3122 &generalNameContent.content))
3123 return;
3124 badDER:
3125 appendInvalidProperty(properties, SEC_GENERAL_NAME_KEY, generalName);
3126 }
3127
3128
3129 /*
3130 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
3131 */
3132 static void appendGeneralNamesContent(CFMutableArrayRef properties,
3133 const DERItem *generalNamesContent) {
3134 DERSequence gnSeq;
3135 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq);
3136 require_noerr_quiet(drtn, badDER);
3137 DERDecodedInfo generalNameContent;
3138 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) ==
3139 DR_Success) {
3140 if (!appendGeneralNameContentProperty(properties,
3141 generalNameContent.tag, &generalNameContent.content)) {
3142 goto badDER;
3143 }
3144 }
3145 require_quiet(drtn == DR_EndOfSequence, badDER);
3146 return;
3147 badDER:
3148 appendInvalidProperty(properties, SEC_GENERAL_NAMES_KEY,
3149 generalNamesContent);
3150 }
3151
3152 static void appendGeneralNames(CFMutableArrayRef properties,
3153 const DERItem *generalNames) {
3154 DERDecodedInfo generalNamesContent;
3155 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent);
3156 require_noerr_quiet(drtn, badDER);
3157 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE,
3158 badDER);
3159 appendGeneralNamesContent(properties, &generalNamesContent.content);
3160 return;
3161 badDER:
3162 appendInvalidProperty(properties, SEC_GENERAL_NAMES_KEY, generalNames);
3163 }
3164
3165 /*
3166 BasicConstraints ::= SEQUENCE {
3167 cA BOOLEAN DEFAULT FALSE,
3168 pathLenConstraint INTEGER (0..MAX) OPTIONAL }
3169 */
3170 static void appendBasicConstraints(CFMutableArrayRef properties,
3171 const DERItem *extnValue) {
3172 DERBasicConstraints basicConstraints;
3173 DERReturn drtn = DERParseSequence(extnValue,
3174 DERNumBasicConstraintsItemSpecs, DERBasicConstraintsItemSpecs,
3175 &basicConstraints, sizeof(basicConstraints));
3176 require_noerr_quiet(drtn, badDER);
3177
3178 appendBooleanProperty(properties, SEC_CERT_AUTHORITY_KEY,
3179 &basicConstraints.cA, false);
3180
3181 if (basicConstraints.pathLenConstraint.length != 0) {
3182 appendIntegerProperty(properties, SEC_PATH_LEN_CONSTRAINT_KEY,
3183 &basicConstraints.pathLenConstraint);
3184 }
3185 return;
3186 badDER:
3187 appendInvalidProperty(properties, SEC_BASIC_CONSTRAINTS_KEY, extnValue);
3188 }
3189
3190 /*
3191 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
3192 *
3193 * NameConstraints ::= SEQUENCE {
3194 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
3195 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
3196 *
3197 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
3198 *
3199 * GeneralSubtree ::= SEQUENCE {
3200 * base GeneralName,
3201 * minimum [0] BaseDistance DEFAULT 0,
3202 * maximum [1] BaseDistance OPTIONAL }
3203 *
3204 * BaseDistance ::= INTEGER (0..MAX)
3205 */
3206 static void appendNameConstraints(CFMutableArrayRef properties,
3207 const DERItem *extnValue) {
3208 CFAllocatorRef allocator = CFGetAllocator(properties);
3209 DERNameConstraints nc;
3210 DERReturn drtn;
3211 drtn = DERParseSequence(extnValue,
3212 DERNumNameConstraintsItemSpecs,
3213 DERNameConstraintsItemSpecs,
3214 &nc, sizeof(nc));
3215 require_noerr_quiet(drtn, badDER);
3216 if (nc.permittedSubtrees.length) {
3217 DERSequence gsSeq;
3218 require_noerr_quiet(DERDecodeSeqContentInit(&nc.permittedSubtrees, &gsSeq), badDER);
3219 DERDecodedInfo gsContent;
3220 while ((drtn = DERDecodeSeqNext(&gsSeq, &gsContent)) == DR_Success) {
3221 DERGeneralSubtree derGS;
3222 require_quiet(gsContent.tag==ASN1_CONSTR_SEQUENCE, badDER);
3223 drtn = DERParseSequenceContent(&gsContent.content,
3224 DERNumGeneralSubtreeItemSpecs,
3225 DERGeneralSubtreeItemSpecs,
3226 &derGS, sizeof(derGS));
3227 require_noerr_quiet(drtn, badDER);
3228 if (derGS.minimum.length) {
3229 appendIntegerProperty(properties, SEC_PERMITTED_MINIMUM_KEY, &derGS.minimum);
3230 }
3231 if (derGS.maximum.length) {
3232 appendIntegerProperty(properties, SEC_PERMITTED_MAXIMUM_KEY, &derGS.maximum);
3233 }
3234 if (derGS.generalName.length) {
3235 CFMutableArrayRef base = CFArrayCreateMutable(allocator, 0,
3236 &kCFTypeArrayCallBacks);
3237 appendProperty(properties, kSecPropertyTypeSection,
3238 SEC_PERMITTED_NAME_KEY, NULL, base);
3239 appendGeneralNameProperty(base, &derGS.generalName);
3240 CFRelease(base);
3241 }
3242 }
3243 require_quiet(drtn == DR_EndOfSequence, badDER);
3244 }
3245 if (nc.excludedSubtrees.length) {
3246 DERSequence gsSeq;
3247 require_noerr_quiet(DERDecodeSeqContentInit(&nc.excludedSubtrees, &gsSeq), badDER);
3248 DERDecodedInfo gsContent;
3249 while ((drtn = DERDecodeSeqNext(&gsSeq, &gsContent)) == DR_Success) {
3250 DERGeneralSubtree derGS;
3251 require_quiet(gsContent.tag==ASN1_CONSTR_SEQUENCE, badDER);
3252 drtn = DERParseSequenceContent(&gsContent.content,
3253 DERNumGeneralSubtreeItemSpecs,
3254 DERGeneralSubtreeItemSpecs,
3255 &derGS, sizeof(derGS));
3256 require_noerr_quiet(drtn, badDER);
3257 if (derGS.minimum.length) {
3258 appendIntegerProperty(properties, SEC_EXCLUDED_MINIMUM_KEY, &derGS.minimum);
3259 }
3260 if (derGS.maximum.length) {
3261 appendIntegerProperty(properties, SEC_EXCLUDED_MAXIMUM_KEY, &derGS.maximum);
3262 }
3263 if (derGS.generalName.length) {
3264 CFMutableArrayRef base = CFArrayCreateMutable(allocator, 0,
3265 &kCFTypeArrayCallBacks);
3266 appendProperty(properties, kSecPropertyTypeSection,
3267 SEC_EXCLUDED_NAME_KEY, NULL, base);
3268 appendGeneralNameProperty(base, &derGS.generalName);
3269 CFRelease(base);
3270 }
3271 }
3272 require_quiet(drtn == DR_EndOfSequence, badDER);
3273 }
3274
3275 return;
3276 badDER:
3277 appendInvalidProperty(properties, SEC_NAME_CONSTRAINTS_KEY, extnValue);
3278 }
3279
3280 /*
3281 CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
3282
3283 DistributionPoint ::= SEQUENCE {
3284 distributionPoint [0] DistributionPointName OPTIONAL,
3285 reasons [1] ReasonFlags OPTIONAL,
3286 cRLIssuer [2] GeneralNames OPTIONAL }
3287
3288 DistributionPointName ::= CHOICE {
3289 fullName [0] GeneralNames,
3290 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
3291
3292 ReasonFlags ::= BIT STRING {
3293 unused (0),
3294 keyCompromise (1),
3295 cACompromise (2),
3296 affiliationChanged (3),
3297 superseded (4),
3298 cessationOfOperation (5),
3299 certificateHold (6),
3300 privilegeWithdrawn (7),
3301 aACompromise (8) }
3302 */
3303 static void appendCrlDistributionPoints(CFMutableArrayRef properties,
3304 const DERItem *extnValue) {
3305 CFAllocatorRef allocator = CFGetAllocator(properties);
3306 DERTag tag;
3307 DERSequence dpSeq;
3308 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &dpSeq);
3309 require_noerr_quiet(drtn, badDER);
3310 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3311 DERDecodedInfo dpSeqContent;
3312 while ((drtn = DERDecodeSeqNext(&dpSeq, &dpSeqContent)) == DR_Success) {
3313 require_quiet(dpSeqContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3314 DERDistributionPoint dp;
3315 drtn = DERParseSequenceContent(&dpSeqContent.content,
3316 DERNumDistributionPointItemSpecs,
3317 DERDistributionPointItemSpecs,
3318 &dp, sizeof(dp));
3319 require_noerr_quiet(drtn, badDER);
3320 if (dp.distributionPoint.length) {
3321 DERDecodedInfo distributionPointName;
3322 drtn = DERDecodeItem(&dp.distributionPoint, &distributionPointName);
3323 require_noerr_quiet(drtn, badDER);
3324 if (distributionPointName.tag ==
3325 (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0)) {
3326 /* Full Name */
3327 appendGeneralNamesContent(properties,
3328 &distributionPointName.content);
3329 } else if (distributionPointName.tag ==
3330 (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1)) {
3331 CFArrayRef rdn_props = createPropertiesForRDNContent(allocator,
3332 &dp.reasons);
3333 appendProperty(properties, kSecPropertyTypeSection,
3334 SEC_NAME_REL_CRL_ISSUER_KEY, NULL, rdn_props);
3335 CFRelease(rdn_props);
3336 } else {
3337 goto badDER;
3338 }
3339 }
3340 if (dp.reasons.length) {
3341 static const CFStringRef reasonNames[] = {
3342 SEC_UNUSED_KEY,
3343 SEC_KEY_COMPROMISE_KEY,
3344 SEC_CA_COMPROMISE_KEY,
3345 SEC_AFFILIATION_CHANGED_KEY,
3346 SEC_SUPERSEDED_KEY,
3347 SEC_CESSATION_OF_OPER_KEY,
3348 SEC_CERTIFICATE_HOLD_KEY,
3349 SEC_PRIV_WITHDRAWN_KEY,
3350 SEC_AA_COMPROMISE_KEY
3351 };
3352 appendBitStringContentNames(properties, SEC_REASONS_KEY,
3353 &dp.reasons,
3354 reasonNames, array_size(reasonNames));
3355 }
3356 if (dp.cRLIssuer.length) {
3357 CFMutableArrayRef crlIssuer = CFArrayCreateMutable(allocator, 0,
3358 &kCFTypeArrayCallBacks);
3359 appendProperty(properties, kSecPropertyTypeSection,
3360 SEC_CRL_ISSUER_KEY, NULL, crlIssuer);
3361 CFRelease(crlIssuer);
3362 appendGeneralNames(crlIssuer, &dp.cRLIssuer);
3363 }
3364 }
3365 require_quiet(drtn == DR_EndOfSequence, badDER);
3366 return;
3367 badDER:
3368 appendInvalidProperty(properties, SEC_CRL_DISTR_POINTS_KEY, extnValue);
3369 }
3370
3371 /* Decode a sequence of integers into a comma separated list of ints. */
3372 static void appendIntegerSequenceContent(CFMutableArrayRef properties,
3373 CFStringRef label, const DERItem *intSequenceContent) {
3374 CFAllocatorRef allocator = CFGetAllocator(properties);
3375 DERSequence intSeq;
3376 CFStringRef fmt = NULL, value = NULL, intDesc = NULL, v = NULL;
3377 DERReturn drtn = DERDecodeSeqContentInit(intSequenceContent, &intSeq);
3378 require_noerr_quiet(drtn, badDER);
3379 DERDecodedInfo intContent;
3380 fmt = SecCopyCertString(SEC_STRING_LIST_KEY);
3381 require_quiet(fmt, badDER);
3382 while ((drtn = DERDecodeSeqNext(&intSeq, &intContent)) == DR_Success) {
3383 require_quiet(intContent.tag == ASN1_INTEGER, badDER);
3384 intDesc = copyIntegerContentDescription(
3385 allocator, &intContent.content);
3386 require_quiet(intDesc, badDER);
3387 if (value) {
3388 v = CFStringCreateWithFormat(allocator, NULL, fmt, value, intDesc);
3389 CFReleaseNull(value);
3390 require_quiet(v, badDER);
3391 value = v;
3392 } else {
3393 value = CFStringCreateMutableCopy(allocator, 0, intDesc);
3394 require_quiet(value, badDER);
3395 }
3396 CFReleaseNull(intDesc);
3397 }
3398 CFReleaseNull(fmt);
3399 require_quiet(drtn == DR_EndOfSequence, badDER);
3400 if (value) {
3401 appendProperty(properties, kSecPropertyTypeString, label, NULL, value);
3402 CFRelease(value);
3403 return;
3404 }
3405 /* DROPTHOUGH if !value. */
3406 badDER:
3407 CFReleaseNull(fmt);
3408 CFReleaseNull(intDesc);
3409 CFReleaseNull(value);
3410 appendInvalidProperty(properties, label, intSequenceContent);
3411 }
3412
3413 static void appendCertificatePolicies(CFMutableArrayRef properties,
3414 const DERItem *extnValue) {
3415 CFAllocatorRef allocator = CFGetAllocator(properties);
3416 CFStringRef piLabel = NULL, piFmt = NULL, lpiLabel = NULL;
3417 CFStringRef pqLabel = NULL, pqFmt = NULL, lpqLabel = NULL;
3418 DERTag tag;
3419 DERSequence piSeq;
3420 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &piSeq);
3421 require_noerr_quiet(drtn, badDER);
3422 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3423 DERDecodedInfo piContent;
3424 int pin = 1;
3425 while ((drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) {
3426 require_quiet(piContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3427 DERPolicyInformation pi;
3428 drtn = DERParseSequenceContent(&piContent.content,
3429 DERNumPolicyInformationItemSpecs,
3430 DERPolicyInformationItemSpecs,
3431 &pi, sizeof(pi));
3432 require_noerr_quiet(drtn, badDER);
3433 require_quiet(piLabel = CFStringCreateWithFormat(allocator, NULL,
3434 SEC_POLICY_IDENTIFIER_KEY, pin), badDER);
3435 require_quiet(piFmt = SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY), badDER);
3436 require_quiet(lpiLabel = CFStringCreateWithFormat(allocator, NULL,
3437 piFmt, pin++), badDER);
3438 CFReleaseNull(piFmt);
3439 appendOIDProperty(properties, piLabel, lpiLabel, &pi.policyIdentifier);
3440 CFReleaseNull(piLabel);
3441 CFReleaseNull(lpiLabel);
3442 if (pi.policyQualifiers.length == 0)
3443 continue;
3444
3445 DERSequence pqSeq;
3446 drtn = DERDecodeSeqContentInit(&pi.policyQualifiers, &pqSeq);
3447 require_noerr_quiet(drtn, badDER);
3448 DERDecodedInfo pqContent;
3449 int pqn = 1;
3450 while ((drtn = DERDecodeSeqNext(&pqSeq, &pqContent)) == DR_Success) {
3451 DERPolicyQualifierInfo pqi;
3452 drtn = DERParseSequenceContent(&pqContent.content,
3453 DERNumPolicyQualifierInfoItemSpecs,
3454 DERPolicyQualifierInfoItemSpecs,
3455 &pqi, sizeof(pqi));
3456 require_noerr_quiet(drtn, badDER);
3457 DERDecodedInfo qualifierContent;
3458 drtn = DERDecodeItem(&pqi.qualifier, &qualifierContent);
3459 require_noerr_quiet(drtn, badDER);
3460 require_quiet(pqLabel = CFStringCreateWithFormat(allocator, NULL,
3461 SEC_POLICY_QUALIFIER_KEY, pqn), badDER);
3462 require_quiet(pqFmt = SecCopyCertString(SEC_POLICY_QUALIFIER_KEY), badDER);
3463 require_quiet(lpqLabel = CFStringCreateWithFormat(allocator, NULL,
3464 pqFmt, pqn++), badDER);
3465 CFReleaseNull(pqFmt);
3466 appendOIDProperty(properties, pqLabel, lpqLabel,
3467 &pqi.policyQualifierID);
3468 CFReleaseNull(pqLabel);
3469 CFReleaseNull(lpqLabel);
3470 if (DEROidCompare(&oidQtCps, &pqi.policyQualifierID)) {
3471 require_quiet(qualifierContent.tag == ASN1_IA5_STRING, badDER);
3472 appendURLContentProperty(properties, SEC_CPS_URI_KEY,
3473 &qualifierContent.content);
3474 } else if (DEROidCompare(&oidQtUNotice, &pqi.policyQualifierID)) {
3475 require_quiet(qualifierContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3476 DERUserNotice un;
3477 drtn = DERParseSequenceContent(&qualifierContent.content,
3478 DERNumUserNoticeItemSpecs,
3479 DERUserNoticeItemSpecs,
3480 &un, sizeof(un));
3481 require_noerr_quiet(drtn, badDER);
3482 if (un.noticeRef.length) {
3483 DERNoticeReference nr;
3484 drtn = DERParseSequenceContent(&un.noticeRef,
3485 DERNumNoticeReferenceItemSpecs,
3486 DERNoticeReferenceItemSpecs,
3487 &nr, sizeof(nr));
3488 require_noerr_quiet(drtn, badDER);
3489 appendDERThingProperty(properties,
3490 SEC_ORGANIZATION_KEY, NULL,
3491 &nr.organization);
3492 appendIntegerSequenceContent(properties,
3493 SEC_NOTICE_NUMBERS_KEY, &nr.noticeNumbers);
3494 }
3495 if (un.explicitText.length) {
3496 appendDERThingProperty(properties, SEC_EXPLICIT_TEXT_KEY,
3497 NULL, &un.explicitText);
3498 }
3499 } else {
3500 appendUnparsedProperty(properties, SEC_QUALIFIER_KEY, NULL,
3501 &pqi.qualifier);
3502 }
3503 }
3504 require_quiet(drtn == DR_EndOfSequence, badDER);
3505 }
3506 require_quiet(drtn == DR_EndOfSequence, badDER);
3507 return;
3508 badDER:
3509 CFReleaseNull(piFmt);
3510 CFReleaseNull(piLabel);
3511 CFReleaseNull(lpiLabel);
3512 CFReleaseNull(pqFmt);
3513 CFReleaseNull(pqLabel);
3514 CFReleaseNull(lpqLabel);
3515 appendInvalidProperty(properties, SEC_CERT_POLICIES_KEY, extnValue);
3516 }
3517
3518 static void appendSubjectKeyIdentifier(CFMutableArrayRef properties,
3519 const DERItem *extnValue) {
3520 DERReturn drtn;
3521 DERDecodedInfo keyIdentifier;
3522 drtn = DERDecodeItem(extnValue, &keyIdentifier);
3523 require_noerr_quiet(drtn, badDER);
3524 require_quiet(keyIdentifier.tag == ASN1_OCTET_STRING, badDER);
3525 appendDataProperty(properties, SEC_KEY_IDENTIFIER_KEY, NULL,
3526 &keyIdentifier.content);
3527
3528 return;
3529 badDER:
3530 appendInvalidProperty(properties, SEC_SUBJ_KEY_ID_KEY,
3531 extnValue);
3532 }
3533
3534 /*
3535 AuthorityKeyIdentifier ::= SEQUENCE {
3536 keyIdentifier [0] KeyIdentifier OPTIONAL,
3537 authorityCertIssuer [1] GeneralNames OPTIONAL,
3538 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
3539 -- authorityCertIssuer and authorityCertSerialNumber MUST both
3540 -- be present or both be absent
3541
3542 KeyIdentifier ::= OCTET STRING
3543 */
3544 static void appendAuthorityKeyIdentifier(CFMutableArrayRef properties,
3545 const DERItem *extnValue) {
3546 DERAuthorityKeyIdentifier akid;
3547 DERReturn drtn;
3548 drtn = DERParseSequence(extnValue,
3549 DERNumAuthorityKeyIdentifierItemSpecs,
3550 DERAuthorityKeyIdentifierItemSpecs,
3551 &akid, sizeof(akid));
3552 require_noerr_quiet(drtn, badDER);
3553 if (akid.keyIdentifier.length) {
3554 appendDataProperty(properties, SEC_KEY_IDENTIFIER_KEY, NULL,
3555 &akid.keyIdentifier);
3556 }
3557 if (akid.authorityCertIssuer.length ||
3558 akid.authorityCertSerialNumber.length) {
3559 require_quiet(akid.authorityCertIssuer.length &&
3560 akid.authorityCertSerialNumber.length, badDER);
3561 /* Perhaps put in a subsection called Authority Certificate Issuer. */
3562 appendGeneralNamesContent(properties,
3563 &akid.authorityCertIssuer);
3564 appendIntegerProperty(properties, SEC_AUTH_CERT_SERIAL_KEY,
3565 &akid.authorityCertSerialNumber);
3566 }
3567
3568 return;
3569 badDER:
3570 appendInvalidProperty(properties, SEC_AUTHORITY_KEY_ID_KEY, extnValue);
3571 }
3572
3573 /*
3574 PolicyConstraints ::= SEQUENCE {
3575 requireExplicitPolicy [0] SkipCerts OPTIONAL,
3576 inhibitPolicyMapping [1] SkipCerts OPTIONAL }
3577
3578 SkipCerts ::= INTEGER (0..MAX)
3579 */
3580 static void appendPolicyConstraints(CFMutableArrayRef properties,
3581 const DERItem *extnValue) {
3582 DERPolicyConstraints pc;
3583 DERReturn drtn;
3584 drtn = DERParseSequence(extnValue,
3585 DERNumPolicyConstraintsItemSpecs,
3586 DERPolicyConstraintsItemSpecs,
3587 &pc, sizeof(pc));
3588 require_noerr_quiet(drtn, badDER);
3589 if (pc.requireExplicitPolicy.length) {
3590 appendIntegerProperty(properties, SEC_REQUIRE_EXPL_POLICY_KEY,
3591 &pc.requireExplicitPolicy);
3592 }
3593 if (pc.inhibitPolicyMapping.length) {
3594 appendIntegerProperty(properties, SEC_INHIBIT_POLICY_MAP_KEY,
3595 &pc.inhibitPolicyMapping);
3596 }
3597
3598 return;
3599
3600 badDER:
3601 appendInvalidProperty(properties, SEC_POLICY_CONSTRAINTS_KEY, extnValue);
3602 }
3603
3604 /*
3605 extendedKeyUsage EXTENSION ::= {
3606 SYNTAX SEQUENCE SIZE (1..MAX) OF KeyPurposeId
3607 IDENTIFIED BY id-ce-extKeyUsage }
3608
3609 KeyPurposeId ::= OBJECT IDENTIFIER
3610 */
3611 static void appendExtendedKeyUsage(CFMutableArrayRef properties,
3612 const DERItem *extnValue) {
3613 DERTag tag;
3614 DERSequence derSeq;
3615 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &derSeq);
3616 require_noerr_quiet(drtn, badDER);
3617 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3618 DERDecodedInfo currDecoded;
3619 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
3620 require_quiet(currDecoded.tag == ASN1_OBJECT_ID, badDER);
3621 appendOIDProperty(properties, SEC_PURPOSE_KEY, NULL,
3622 &currDecoded.content);
3623 }
3624 require_quiet(drtn == DR_EndOfSequence, badDER);
3625 return;
3626 badDER:
3627 appendInvalidProperty(properties, SEC_EXTENDED_KEY_USAGE_KEY, extnValue);
3628 }
3629
3630 /*
3631 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
3632
3633 AuthorityInfoAccessSyntax ::=
3634 SEQUENCE SIZE (1..MAX) OF AccessDescription
3635
3636 AccessDescription ::= SEQUENCE {
3637 accessMethod OBJECT IDENTIFIER,
3638 accessLocation GeneralName }
3639
3640 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
3641
3642 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
3643
3644 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
3645 */
3646 static void appendInfoAccess(CFMutableArrayRef properties,
3647 const DERItem *extnValue) {
3648 DERTag tag;
3649 DERSequence adSeq;
3650 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &adSeq);
3651 require_noerr_quiet(drtn, badDER);
3652 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3653 DERDecodedInfo adContent;
3654 while ((drtn = DERDecodeSeqNext(&adSeq, &adContent)) == DR_Success) {
3655 require_quiet(adContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3656 DERAccessDescription ad;
3657 drtn = DERParseSequenceContent(&adContent.content,
3658 DERNumAccessDescriptionItemSpecs,
3659 DERAccessDescriptionItemSpecs,
3660 &ad, sizeof(ad));
3661 require_noerr_quiet(drtn, badDER);
3662 appendOIDProperty(properties, SEC_ACCESS_METHOD_KEY, NULL,
3663 &ad.accessMethod);
3664 //TODO: Do something with SEC_ACCESS_LOCATION_KEY
3665 appendGeneralNameProperty(properties, &ad.accessLocation);
3666 }
3667 require_quiet(drtn == DR_EndOfSequence, badDER);
3668 return;
3669 badDER:
3670 appendInvalidProperty(properties, SEC_AUTH_INFO_ACCESS_KEY, extnValue);
3671 }
3672
3673 static void appendNetscapeCertType(CFMutableArrayRef properties,
3674 const DERItem *extnValue) {
3675 static const CFStringRef certTypes[] = {
3676 SEC_SSL_CLIENT_KEY,
3677 SEC_SSL_SERVER_KEY,
3678 SEC_SMIME_KEY,
3679 SEC_OBJECT_SIGNING_KEY,
3680 SEC_RESERVED_KEY,
3681 SEC_SSL_CA_KEY,
3682 SEC_SMIME_CA_KEY,
3683 SEC_OBJECT_SIGNING_CA_KEY
3684 };
3685 appendBitStringNames(properties, SEC_USAGE_KEY, extnValue,
3686 certTypes, array_size(certTypes));
3687 }
3688
3689 static bool appendPrintableDERSequence(CFMutableArrayRef properties,
3690 CFStringRef label, const DERItem *sequence) {
3691 DERTag tag;
3692 DERSequence derSeq;
3693 DERReturn drtn = DERDecodeSeqInit(sequence, &tag, &derSeq);
3694 require_noerr_quiet(drtn, badSequence);
3695 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badSequence);
3696 DERDecodedInfo currDecoded;
3697 bool appendedSomething = false;
3698 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
3699 switch (currDecoded.tag)
3700 {
3701 case 0: // 0
3702 case ASN1_SEQUENCE: // 16
3703 case ASN1_SET: // 17
3704 // skip constructed object lengths
3705 break;
3706
3707 case ASN1_UTF8_STRING: // 12
3708 case ASN1_NUMERIC_STRING: // 18
3709 case ASN1_PRINTABLE_STRING: // 19
3710 case ASN1_T61_STRING: // 20, also ASN1_TELETEX_STRING
3711 case ASN1_VIDEOTEX_STRING: // 21
3712 case ASN1_IA5_STRING: // 22
3713 case ASN1_GRAPHIC_STRING: // 25
3714 case ASN1_VISIBLE_STRING: // 26, also ASN1_ISO646_STRING
3715 case ASN1_GENERAL_STRING: // 27
3716 case ASN1_UNIVERSAL_STRING: // 28
3717 {
3718 CFStringRef string =
3719 copyDERThingContentDescription(CFGetAllocator(properties),
3720 currDecoded.tag, &currDecoded.content, false);
3721 require_quiet(string, badSequence);
3722
3723 appendProperty(properties, kSecPropertyTypeString, label, NULL,
3724 string);
3725 CFReleaseNull(string);
3726 appendedSomething = true;
3727 break;
3728 }
3729 default:
3730 break;
3731 }
3732 }
3733 require_quiet(drtn == DR_EndOfSequence, badSequence);
3734 return appendedSomething;
3735 badSequence:
3736 return false;
3737 }
3738
3739 static void appendExtension(CFMutableArrayRef parent,
3740 const SecCertificateExtension *extn) {
3741 CFAllocatorRef allocator = CFGetAllocator(parent);
3742 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
3743 &kCFTypeArrayCallBacks);
3744 const DERItem
3745 *extnID = &extn->extnID,
3746 *extnValue = &extn->extnValue;
3747 CFStringRef label = NULL;
3748 CFStringRef localizedLabel = NULL;
3749
3750 appendBoolProperty(properties, SEC_CRITICAL_KEY, extn->critical);
3751 require_quiet(extnID, xit);
3752
3753 bool handled = true;
3754 /* Extensions that we know how to handle ourselves... */
3755 if (extnID->length == oidSubjectKeyIdentifier.length &&
3756 !memcmp(extnID->data, oidSubjectKeyIdentifier.data, extnID->length - 1))
3757 {
3758 switch (extnID->data[extnID->length - 1]) {
3759 case 14: /* SubjectKeyIdentifier id-ce 14 */
3760 appendSubjectKeyIdentifier(properties, extnValue);
3761 break;
3762 case 15: /* KeyUsage id-ce 15 */
3763 appendKeyUsage(properties, extnValue);
3764 break;
3765 case 16: /* PrivateKeyUsagePeriod id-ce 16 */
3766 appendPrivateKeyUsagePeriod(properties, extnValue);
3767 break;
3768 case 17: /* SubjectAltName id-ce 17 */
3769 case 18: /* IssuerAltName id-ce 18 */
3770 appendGeneralNames(properties, extnValue);
3771 break;
3772 case 19: /* BasicConstraints id-ce 19 */
3773 appendBasicConstraints(properties, extnValue);
3774 break;
3775 case 30: /* NameConstraints id-ce 30 */
3776 appendNameConstraints(properties, extnValue);
3777 break;
3778 case 31: /* CRLDistributionPoints id-ce 31 */
3779 appendCrlDistributionPoints(properties, extnValue);
3780 break;
3781 case 32: /* CertificatePolicies id-ce 32 */
3782 appendCertificatePolicies(properties, extnValue);
3783 break;
3784 case 33: /* PolicyMappings id-ce 33 */
3785 handled = false;
3786 break;
3787 case 35: /* AuthorityKeyIdentifier id-ce 35 */
3788 appendAuthorityKeyIdentifier(properties, extnValue);
3789 break;
3790 case 36: /* PolicyConstraints id-ce 36 */
3791 appendPolicyConstraints(properties, extnValue);
3792 break;
3793 case 37: /* ExtKeyUsage id-ce 37 */
3794 appendExtendedKeyUsage(properties, extnValue);
3795 break;
3796 case 46: /* FreshestCRL id-ce 46 */
3797 handled = false;
3798 break;
3799 case 54: /* InhibitAnyPolicy id-ce 54 */
3800 handled = false;
3801 break;
3802 default:
3803 handled = false;
3804 break;
3805 }
3806 } else if (extnID->length == oidAuthorityInfoAccess.length &&
3807 !memcmp(extnID->data, oidAuthorityInfoAccess.data, extnID->length - 1))
3808 {
3809 switch (extnID->data[extnID->length - 1]) {
3810 case 1: /* AuthorityInfoAccess id-pe 1 */
3811 appendInfoAccess(properties, extnValue);
3812 break;
3813 case 3: /* QCStatements id-pe 3 */
3814 handled = false;
3815 break;
3816 case 11: /* SubjectInfoAccess id-pe 11 */
3817 appendInfoAccess(properties, extnValue);
3818 break;
3819 default:
3820 handled = false;
3821 break;
3822 }
3823 } else if (DEROidCompare(extnID, &oidNetscapeCertType)) {
3824 /* 2.16.840.1.113730.1.1 netscape 1 1 */
3825 appendNetscapeCertType(properties, extnValue);
3826 } else {
3827 handled = false;
3828 }
3829
3830 if (!handled) {
3831 /* Try to parse and display printable string(s). */
3832 if (appendPrintableDERSequence(properties, SEC_DATA_KEY, extnValue)) {
3833 /* Nothing to do here appendPrintableDERSequence did the work. */
3834 } else {
3835 /* Couldn't parse extension; dump the raw unparsed data as hex. */
3836 appendUnparsedProperty(properties, SEC_DATA_KEY, NULL, extnValue);
3837 }
3838 }
3839 label = SecDERItemCopyOIDDecimalRepresentation(allocator, extnID);
3840 localizedLabel = copyLocalizedOidDescription(allocator, extnID);
3841 appendProperty(parent, kSecPropertyTypeSection, label, localizedLabel, properties);
3842
3843 xit:
3844 CFReleaseSafe(localizedLabel);
3845 CFReleaseSafe(label);
3846 CFReleaseSafe(properties);
3847 }
3848
3849 /* Different types of summary types from least desired to most desired. */
3850 enum SummaryType {
3851 kSummaryTypeNone,
3852 kSummaryTypePrintable,
3853 kSummaryTypeOrganizationName,
3854 kSummaryTypeOrganizationalUnitName,
3855 kSummaryTypeCommonName,
3856 };
3857
3858 struct Summary {
3859 enum SummaryType type;
3860 CFStringRef summary;
3861 CFStringRef description;
3862 };
3863
3864 static OSStatus obtainSummaryFromX501Name(void *context,
3865 const DERItem *type, const DERItem *value, CFIndex rdnIX) {
3866 struct Summary *summary = (struct Summary *)context;
3867 enum SummaryType stype = kSummaryTypeNone;
3868 CFStringRef string = NULL;
3869 if (DEROidCompare(type, &oidCommonName)) {
3870 stype = kSummaryTypeCommonName;
3871 } else if (DEROidCompare(type, &oidOrganizationalUnitName)) {
3872 stype = kSummaryTypeOrganizationalUnitName;
3873 } else if (DEROidCompare(type, &oidOrganizationName)) {
3874 stype = kSummaryTypeOrganizationName;
3875 } else if (DEROidCompare(type, &oidDescription)) {
3876 string = copyDERThingDescription(kCFAllocatorDefault, value, true);
3877 if (string) {
3878 if (summary->description) {
3879 CFStringRef fmt = SecCopyCertString(SEC_STRING_LIST_KEY);
3880 CFStringRef newDescription = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, string, summary->description);
3881 CFRelease(fmt);
3882 CFRelease(summary->description);
3883 summary->description = newDescription;
3884 } else {
3885 summary->description = string;
3886 CFRetain(string);
3887 }
3888 stype = kSummaryTypePrintable;
3889 }
3890 } else {
3891 stype = kSummaryTypePrintable;
3892 }
3893
3894 /* Build a string with all instances of the most desired
3895 component type in reverse order encountered comma separated list,
3896 The order of desirability is defined by enum SummaryType. */
3897 if (summary->type <= stype) {
3898 if (!string)
3899 string = copyDERThingDescription(kCFAllocatorDefault, value, true);
3900
3901 if (string) {
3902 if (summary->type == stype) {
3903 CFStringRef fmt = SecCopyCertString(SEC_STRING_LIST_KEY);
3904 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, string, summary->summary);
3905 CFRelease(fmt);
3906 CFRelease(string);
3907 string = newSummary;
3908 } else {
3909 summary->type = stype;
3910 }
3911 CFReleaseSafe(summary->summary);
3912 summary->summary = string;
3913 }
3914 } else {
3915 CFReleaseSafe(string);
3916 }
3917
3918 return errSecSuccess;
3919 }
3920
3921 CFStringRef SecCertificateCopySubjectSummary(SecCertificateRef certificate) {
3922 struct Summary summary = {};
3923 parseX501NameContent(&certificate->_subject, &summary, obtainSummaryFromX501Name);
3924 /* If we found a description and a common name we change the summary to
3925 CommonName (Description). */
3926 if (summary.description) {
3927 if (summary.type == kSummaryTypeCommonName) {
3928 CFStringRef fmt = SecCopyCertString(SEC_COMMON_NAME_DESC_KEY);
3929 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, summary.summary, summary.description);
3930 CFRelease(fmt);
3931 CFRelease(summary.summary);
3932 summary.summary = newSummary;
3933 }
3934 CFRelease(summary.description);
3935 }
3936
3937 if (!summary.summary) {
3938 /* If we didn't find a suitable printable string in the subject at all, we try
3939 the first email address in the certificate instead. */
3940 CFArrayRef names = SecCertificateCopyRFC822Names(certificate);
3941 if (!names) {
3942 /* If we didn't find any email addresses in the certificate, we try finding
3943 a DNS name instead. */
3944 names = SecCertificateCopyDNSNames(certificate);
3945 }
3946 if (names) {
3947 summary.summary = CFArrayGetValueAtIndex(names, 0);
3948 CFRetain(summary.summary);
3949 CFRelease(names);
3950 }
3951 }
3952
3953 return summary.summary;
3954 }
3955
3956 CFStringRef SecCertificateCopyIssuerSummary(SecCertificateRef certificate) {
3957 struct Summary summary = {};
3958 parseX501NameContent(&certificate->_issuer, &summary, obtainSummaryFromX501Name);
3959 /* If we found a description and a common name we change the summary to
3960 CommonName (Description). */
3961 if (summary.description) {
3962 if (summary.type == kSummaryTypeCommonName) {
3963 CFStringRef fmt = SecCopyCertString(SEC_COMMON_NAME_DESC_KEY);
3964 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, summary.summary, summary.description);
3965 CFRelease(fmt);
3966 CFRelease(summary.summary);
3967 summary.summary = newSummary;
3968 }
3969 CFRelease(summary.description);
3970 }
3971
3972 return summary.summary;
3973 }
3974
3975 /* Return the earliest date on which all certificates in this chain are still
3976 valid. */
3977 static CFAbsoluteTime SecCertificateGetChainsLastValidity(
3978 SecCertificateRef certificate) {
3979 CFAbsoluteTime earliest = certificate->_notAfter;
3980 #if 0
3981 while (certificate->_parent) {
3982 certificate = certificate->_parent;
3983 if (earliest > certificate->_notAfter)
3984 earliest = certificate->_notAfter;
3985 }
3986 #endif
3987
3988 return earliest;
3989 }
3990
3991 /* Return the latest date on which all certificates in this chain will be
3992 valid. */
3993 static CFAbsoluteTime SecCertificateGetChainsFirstValidity(
3994 SecCertificateRef certificate) {
3995 CFAbsoluteTime latest = certificate->_notBefore;
3996 #if 0
3997 while (certificate->_parent) {
3998 certificate = certificate->_parent;
3999 if (latest < certificate->_notBefore)
4000 latest = certificate->_notBefore;
4001 }
4002 #endif
4003
4004 return latest;
4005 }
4006
4007 bool SecCertificateIsValid(SecCertificateRef certificate,
4008 CFAbsoluteTime verifyTime) {
4009 return certificate && certificate->_notBefore <= verifyTime &&
4010 verifyTime <= certificate->_notAfter;
4011 }
4012
4013 CFIndex SecCertificateVersion(SecCertificateRef certificate) {
4014 return certificate->_version + 1;
4015 }
4016
4017 CFAbsoluteTime SecCertificateNotValidBefore(SecCertificateRef certificate) {
4018 return certificate->_notBefore;
4019 }
4020
4021 CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate) {
4022 return certificate->_notAfter;
4023 }
4024
4025 CFMutableArrayRef SecCertificateCopySummaryProperties(
4026 SecCertificateRef certificate, CFAbsoluteTime verifyTime) {
4027 CFAllocatorRef allocator = CFGetAllocator(certificate);
4028 CFMutableArrayRef summary = CFArrayCreateMutable(allocator, 0,
4029 &kCFTypeArrayCallBacks);
4030
4031 /* First we put the subject summary name. */
4032 CFStringRef ssummary = SecCertificateCopySubjectSummary(certificate);
4033 if (ssummary) {
4034 appendProperty(summary, kSecPropertyTypeTitle,
4035 NULL, NULL, ssummary);
4036 CFRelease(ssummary);
4037 }
4038
4039 /* Let see if this certificate is currently valid. */
4040 CFStringRef label;
4041 CFAbsoluteTime when;
4042 CFStringRef message;
4043 CFStringRef ptype;
4044 if (verifyTime > certificate->_notAfter) {
4045 label = SEC_EXPIRED_KEY;
4046 when = certificate->_notAfter;
4047 ptype = kSecPropertyTypeError;
4048 message = SEC_CERT_EXPIRED_KEY;
4049 } else if (certificate->_notBefore > verifyTime) {
4050 label = SEC_VALID_FROM_KEY;
4051 when = certificate->_notBefore;
4052 ptype = kSecPropertyTypeError;
4053 message = SEC_CERT_NOT_YET_VALID_KEY;
4054 } else {
4055 CFAbsoluteTime last = SecCertificateGetChainsLastValidity(certificate);
4056 CFAbsoluteTime first = SecCertificateGetChainsFirstValidity(certificate);
4057 if (verifyTime > last) {
4058 label = SEC_EXPIRED_KEY;
4059 when = last;
4060 ptype = kSecPropertyTypeError;
4061 message = SEC_ISSUER_EXPIRED_KEY;
4062 } else if (verifyTime < first) {
4063 label = SEC_VALID_FROM_KEY;
4064 when = first;
4065 ptype = kSecPropertyTypeError;
4066 message = SEC_ISSR_NOT_YET_VALID_KEY;
4067 } else {
4068 label = SEC_EXPIRES_KEY;
4069 when = certificate->_notAfter;
4070 ptype = kSecPropertyTypeSuccess;
4071 message = SEC_CERT_VALID_KEY;
4072 }
4073 }
4074
4075 appendDateProperty(summary, label, when);
4076 CFStringRef lmessage = SecCopyCertString(message);
4077 appendProperty(summary, ptype, NULL, NULL, lmessage);
4078 CFRelease(lmessage);
4079
4080 return summary;
4081 }
4082
4083 CFArrayRef SecCertificateCopyLegacyProperties(SecCertificateRef certificate) {
4084 /*
4085 This function replicates the content returned by SecCertificateCopyProperties
4086 prior to 10.12.4, providing stable return values for SecCertificateCopyValues.
4087 Unlike SecCertificateCopyProperties, it does not cache the result and
4088 assumes the caller will do so.
4089 */
4090 CFAllocatorRef allocator = CFGetAllocator(certificate);
4091 CFMutableArrayRef properties = CFArrayCreateMutable(allocator,
4092 0, &kCFTypeArrayCallBacks);
4093
4094 /* Subject Name */
4095 CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator,
4096 &certificate->_subject);
4097 appendProperty(properties, kSecPropertyTypeSection, CFSTR("Subject Name"),
4098 NULL, subject_plist);
4099 CFRelease(subject_plist);
4100
4101 /* Issuer Name */
4102 CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator,
4103 &certificate->_issuer);
4104 appendProperty(properties, kSecPropertyTypeSection, CFSTR("Issuer Name"),
4105 NULL, issuer_plist);
4106 CFRelease(issuer_plist);
4107
4108 /* Version */
4109 CFStringRef versionString = CFStringCreateWithFormat(allocator,
4110 NULL, CFSTR("%d"), certificate->_version + 1);
4111 appendProperty(properties, kSecPropertyTypeString, CFSTR("Version"),
4112 NULL, versionString);
4113 CFRelease(versionString);
4114
4115 /* Serial Number */
4116 if (certificate->_serialNum.length) {
4117 appendIntegerProperty(properties, CFSTR("Serial Number"),
4118 &certificate->_serialNum);
4119 }
4120
4121 /* Signature Algorithm */
4122 appendAlgorithmProperty(properties, CFSTR("Signature Algorithm"),
4123 &certificate->_tbsSigAlg);
4124
4125 /* Validity dates */
4126 appendDateProperty(properties, CFSTR("Not Valid Before"), certificate->_notBefore);
4127 appendDateProperty(properties, CFSTR("Not Valid After"), certificate->_notAfter);
4128
4129 if (certificate->_subjectUniqueID.length) {
4130 appendDataProperty(properties, CFSTR("Subject Unique ID"),
4131 NULL, &certificate->_subjectUniqueID);
4132 }
4133 if (certificate->_issuerUniqueID.length) {
4134 appendDataProperty(properties, CFSTR("Issuer Unique ID"),
4135 NULL, &certificate->_issuerUniqueID);
4136 }
4137
4138 /* Public Key Algorithm */
4139 appendAlgorithmProperty(properties, CFSTR("Public Key Algorithm"),
4140 &certificate->_algId);
4141
4142 /* Public Key Data */
4143 appendDataProperty(properties, CFSTR("Public Key Data"),
4144 NULL, &certificate->_pubKeyDER);
4145
4146 /* Signature */
4147 appendDataProperty(properties, CFSTR("Signature"),
4148 NULL, &certificate->_signature);
4149
4150 /* Extensions */
4151 CFIndex ix;
4152 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
4153 appendExtension(properties, &certificate->_extensions[ix]);
4154 }
4155
4156 /* Fingerprints */
4157 appendFingerprintsProperty(properties, CFSTR("Fingerprints"), certificate);
4158
4159 return properties;
4160 }
4161
4162 CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate) {
4163 if (!certificate->_properties) {
4164 CFAllocatorRef allocator = CFGetAllocator(certificate);
4165 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
4166 &kCFTypeArrayCallBacks);
4167 require_quiet(properties, out);
4168
4169
4170 /* First we put the Subject Name in the property list. */
4171 CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator,
4172 &certificate->_subject);
4173 if (subject_plist) {
4174 appendProperty(properties, kSecPropertyTypeSection,
4175 SEC_SUBJECT_NAME_KEY, NULL, subject_plist);
4176 }
4177 CFReleaseNull(subject_plist);
4178
4179 /* Next we put the Issuer Name in the property list. */
4180 CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator,
4181 &certificate->_issuer);
4182 if (issuer_plist) {
4183 appendProperty(properties, kSecPropertyTypeSection,
4184 SEC_ISSUER_NAME_KEY, NULL, issuer_plist);
4185 }
4186 CFReleaseNull(issuer_plist);
4187
4188 /* Version */
4189 CFStringRef fmt = SecCopyCertString(SEC_CERT_VERSION_VALUE_KEY);
4190 CFStringRef versionString = NULL;
4191 if (fmt) {
4192 versionString = CFStringCreateWithFormat(allocator, NULL, fmt,
4193 certificate->_version + 1);
4194 }
4195 CFReleaseNull(fmt);
4196 if (versionString) {
4197 appendProperty(properties, kSecPropertyTypeString,
4198 SEC_VERSION_KEY, NULL, versionString);
4199 }
4200 CFReleaseNull(versionString);
4201
4202 /* Serial Number */
4203 appendSerialNumberProperty(properties, SEC_SERIAL_NUMBER_KEY, &certificate->_serialNum);
4204
4205 /* Validity dates. */
4206 appendValidityPeriodProperty(properties, SEC_VALIDITY_PERIOD_KEY, certificate);
4207
4208 if (certificate->_subjectUniqueID.length) {
4209 appendDataProperty(properties, SEC_SUBJECT_UNIQUE_ID_KEY, NULL,
4210 &certificate->_subjectUniqueID);
4211 }
4212 if (certificate->_issuerUniqueID.length) {
4213 appendDataProperty(properties, SEC_ISSUER_UNIQUE_ID_KEY, NULL,
4214 &certificate->_issuerUniqueID);
4215 }
4216
4217 appendPublicKeyProperty(properties, SEC_PUBLIC_KEY_KEY, certificate);
4218
4219 CFIndex ix;
4220 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
4221 appendExtension(properties, &certificate->_extensions[ix]);
4222 }
4223
4224 /* Signature */
4225 appendSignatureProperty(properties, SEC_SIGNATURE_KEY, certificate);
4226
4227 appendFingerprintsProperty(properties, SEC_FINGERPRINTS_KEY, certificate);
4228
4229 certificate->_properties = properties;
4230 }
4231
4232 out:
4233 CFRetainSafe(certificate->_properties);
4234 return certificate->_properties;
4235 }
4236
4237 /* Unified serial number API */
4238 CFDataRef SecCertificateCopySerialNumberData(
4239 SecCertificateRef certificate,
4240 CFErrorRef *error)
4241 {
4242 if (!certificate) {
4243 if (error) {
4244 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidCertificate, NULL);
4245 }
4246 return NULL;
4247 }
4248 if (certificate->_serialNumber) {
4249 CFRetain(certificate->_serialNumber);
4250 }
4251 return certificate->_serialNumber;
4252 }
4253
4254 #if TARGET_OS_OSX
4255 /* On OS X, the SecCertificateCopySerialNumber API takes two arguments. */
4256 CFDataRef SecCertificateCopySerialNumber(
4257 SecCertificateRef certificate,
4258 CFErrorRef *error) {
4259 return SecCertificateCopySerialNumberData(certificate, error);
4260 }
4261 #else
4262 /* On iOS, the SecCertificateCopySerialNumber API takes one argument. */
4263 CFDataRef SecCertificateCopySerialNumber(
4264 SecCertificateRef certificate) {
4265 return SecCertificateCopySerialNumberData(certificate, NULL);
4266 }
4267 #endif
4268
4269 CFDataRef SecCertificateGetNormalizedIssuerContent(
4270 SecCertificateRef certificate) {
4271 return certificate->_normalizedIssuer;
4272 }
4273
4274 CFDataRef SecCertificateGetNormalizedSubjectContent(
4275 SecCertificateRef certificate) {
4276 return certificate->_normalizedSubject;
4277 }
4278
4279 /* Verify that certificate was signed by issuerKey. */
4280 OSStatus SecCertificateIsSignedBy(SecCertificateRef certificate,
4281 SecKeyRef issuerKey) {
4282 /* Setup algId in SecAsn1AlgId format. */
4283 SecAsn1AlgId algId;
4284 algId.algorithm.Length = certificate->_tbsSigAlg.oid.length;
4285 algId.algorithm.Data = certificate->_tbsSigAlg.oid.data;
4286 algId.parameters.Length = certificate->_tbsSigAlg.params.length;
4287 algId.parameters.Data = certificate->_tbsSigAlg.params.data;
4288
4289 /* RFC5280 4.1.1.2, 4.1.2.3 requires the actual signature algorithm
4290 must match the specified algorithm in the TBSCertificate. */
4291 bool sigAlgMatch = DEROidCompare(&certificate->_sigAlg.oid,
4292 &certificate->_tbsSigAlg.oid);
4293 if (!sigAlgMatch) {
4294 secwarning("Signature algorithm mismatch in certificate (see RFC5280 4.1.1.2)");
4295 }
4296
4297 CFErrorRef error = NULL;
4298 if (!sigAlgMatch ||
4299 !SecVerifySignatureWithPublicKey(issuerKey, &algId,
4300 certificate->_tbs.data, certificate->_tbs.length,
4301 certificate->_signature.data, certificate->_signature.length, &error))
4302 {
4303 #if !defined(NDEBUG)
4304 secdebug("verify", "signature verify failed: %" PRIdOSStatus, (error) ? (OSStatus)CFErrorGetCode(error) : errSecNotSigner);
4305 #endif
4306 CFReleaseSafe(error);
4307 return errSecNotSigner;
4308 }
4309
4310 return errSecSuccess;
4311 }
4312
4313 const DERItem * SecCertificateGetSubjectAltName(SecCertificateRef certificate) {
4314 if (!certificate->_subjectAltName) {
4315 return NULL;
4316 }
4317 return &certificate->_subjectAltName->extnValue;
4318 }
4319
4320 static OSStatus appendIPAddressesFromGeneralNames(void *context,
4321 SecCEGeneralNameType gnType, const DERItem *generalName) {
4322 CFMutableArrayRef ipAddresses = (CFMutableArrayRef)context;
4323 if (gnType == GNT_IPAddress) {
4324 CFStringRef string = copyIPAddressContentDescription(
4325 kCFAllocatorDefault, generalName);
4326 if (string) {
4327 CFArrayAppendValue(ipAddresses, string);
4328 CFRelease(string);
4329 } else {
4330 return errSecInvalidCertificate;
4331 }
4332 }
4333 return errSecSuccess;
4334 }
4335
4336 CFArrayRef SecCertificateCopyIPAddresses(SecCertificateRef certificate) {
4337 /* These can only exist in the subject alt name. */
4338 if (!certificate->_subjectAltName)
4339 return NULL;
4340
4341 CFMutableArrayRef ipAddresses = CFArrayCreateMutable(kCFAllocatorDefault,
4342 0, &kCFTypeArrayCallBacks);
4343 OSStatus status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
4344 ipAddresses, appendIPAddressesFromGeneralNames);
4345 if (status || CFArrayGetCount(ipAddresses) == 0) {
4346 CFRelease(ipAddresses);
4347 ipAddresses = NULL;
4348 }
4349 return ipAddresses;
4350 }
4351
4352 static OSStatus appendDNSNamesFromGeneralNames(void *context, SecCEGeneralNameType gnType,
4353 const DERItem *generalName) {
4354 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4355 if (gnType == GNT_DNSName) {
4356 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault,
4357 generalName->data, generalName->length,
4358 kCFStringEncodingUTF8, FALSE);
4359 if (string) {
4360 CFArrayAppendValue(dnsNames, string);
4361 CFRelease(string);
4362 } else {
4363 return errSecInvalidCertificate;
4364 }
4365 }
4366 return errSecSuccess;
4367 }
4368
4369 /* Return true if the passed in string matches the
4370 Preferred name syntax from sections 2.3.1. in RFC 1035.
4371 With the added check that we disallow empty dns names.
4372 Also in order to support wildcard DNSNames we allow for the '*'
4373 character anywhere in a dns component where we currently allow
4374 a letter.
4375
4376 <domain> ::= <subdomain> | " "
4377
4378 <subdomain> ::= <label> | <subdomain> "." <label>
4379
4380 <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
4381
4382 <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
4383
4384 <let-dig-hyp> ::= <let-dig> | "-"
4385
4386 <let-dig> ::= <letter> | <digit>
4387
4388 <letter> ::= any one of the 52 alphabetic characters A through Z in
4389 upper case and a through z in lower case
4390
4391 <digit> ::= any one of the ten digits 0 through 9
4392 */
4393 static bool isDNSName(CFStringRef string) {
4394 CFStringInlineBuffer buf = {};
4395 CFIndex ix, labelLength = 0, length = CFStringGetLength(string);
4396 /* From RFC 1035 2.3.4. Size limits:
4397 labels 63 octets or less
4398 names 255 octets or less */
4399 require_quiet(length <= 255, notDNS);
4400 CFRange range = { 0, length };
4401 CFStringInitInlineBuffer(string, &buf, range);
4402 enum {
4403 kDNSStateInital,
4404 kDNSStateAfterDot,
4405 kDNSStateAfterAlpha,
4406 kDNSStateAfterDigit,
4407 kDNSStateAfterDash,
4408 } state = kDNSStateInital;
4409
4410 for (ix = 0; ix < length; ++ix) {
4411 UniChar ch = CFStringGetCharacterFromInlineBuffer(&buf, ix);
4412 labelLength++;
4413 if (ch == '.') {
4414 require_quiet(labelLength <= 64 &&
4415 (state == kDNSStateAfterAlpha || state == kDNSStateAfterDigit),
4416 notDNS);
4417 state = kDNSStateAfterDot;
4418 labelLength = 0;
4419 } else if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') ||
4420 ch == '*') {
4421 state = kDNSStateAfterAlpha;
4422 } else if ('0' <= ch && ch <= '9') {
4423 #if 0
4424 /* The requirement for labels to start with a letter was
4425 dropped so we don't check this anymore. */
4426 require_quiet(state == kDNSStateAfterAlpha ||
4427 state == kDNSStateAfterDigit ||
4428 state == kDNSStateAfterDash, notDNS);
4429 #endif
4430 state = kDNSStateAfterDigit;
4431 } else if (ch == '-') {
4432 require_quiet(state == kDNSStateAfterAlpha ||
4433 state == kDNSStateAfterDigit ||
4434 state == kDNSStateAfterDash, notDNS);
4435 state = kDNSStateAfterDash;
4436 } else {
4437 goto notDNS;
4438 }
4439 }
4440
4441 /* We don't allow a dns name to end in a dot or dash. */
4442 require_quiet(labelLength <= 63 &&
4443 (state == kDNSStateAfterAlpha || state == kDNSStateAfterDigit),
4444 notDNS);
4445
4446 return true;
4447 notDNS:
4448 return false;
4449 }
4450
4451 static OSStatus appendDNSNamesFromX501Name(void *context, const DERItem *type,
4452 const DERItem *value, CFIndex rdnIX) {
4453 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4454 if (DEROidCompare(type, &oidCommonName)) {
4455 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4456 value, true);
4457 if (string) {
4458 if (isDNSName(string)) {
4459 /* We found a common name that is formatted like a valid
4460 dns name. */
4461 CFArrayAppendValue(dnsNames, string);
4462 }
4463 CFRelease(string);
4464 } else {
4465 return errSecInvalidCertificate;
4466 }
4467 }
4468 return errSecSuccess;
4469 }
4470
4471 /* Not everything returned by this function is going to be a proper DNS name,
4472 we also return the certificates common name entries from the subject,
4473 assuming they look like dns names as specified in RFC 1035. */
4474 CFArrayRef SecCertificateCopyDNSNames(SecCertificateRef certificate) {
4475 /* These can exist in the subject alt name or in the subject. */
4476 CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault,
4477 0, &kCFTypeArrayCallBacks);
4478 OSStatus status = errSecSuccess;
4479 if (certificate->_subjectAltName) {
4480 status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
4481 dnsNames, appendDNSNamesFromGeneralNames);
4482 }
4483 /* RFC 2818 section 3.1. Server Identity
4484 [...]
4485 If a subjectAltName extension of type dNSName is present, that MUST
4486 be used as the identity. Otherwise, the (most specific) Common Name
4487 field in the Subject field of the certificate MUST be used. Although
4488 the use of the Common Name is existing practice, it is deprecated and
4489 Certification Authorities are encouraged to use the dNSName instead.
4490 [...]
4491
4492 This implies that if we found 1 or more DNSNames in the
4493 subjectAltName, we should not use the Common Name of the subject as
4494 a DNSName.
4495 */
4496 if (!status && CFArrayGetCount(dnsNames) == 0) {
4497 status = parseX501NameContent(&certificate->_subject, dnsNames,
4498 appendDNSNamesFromX501Name);
4499 }
4500 if (status || CFArrayGetCount(dnsNames) == 0) {
4501 CFRelease(dnsNames);
4502 dnsNames = NULL;
4503 }
4504 return dnsNames;
4505 }
4506
4507 static OSStatus appendRFC822NamesFromGeneralNames(void *context,
4508 SecCEGeneralNameType gnType, const DERItem *generalName) {
4509 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4510 if (gnType == GNT_RFC822Name) {
4511 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault,
4512 generalName->data, generalName->length,
4513 kCFStringEncodingASCII, FALSE);
4514 if (string) {
4515 CFArrayAppendValue(dnsNames, string);
4516 CFRelease(string);
4517 } else {
4518 return errSecInvalidCertificate;
4519 }
4520 }
4521 return errSecSuccess;
4522 }
4523
4524 static OSStatus appendRFC822NamesFromX501Name(void *context, const DERItem *type,
4525 const DERItem *value, CFIndex rdnIX) {
4526 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4527 if (DEROidCompare(type, &oidEmailAddress)) {
4528 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4529 value, true);
4530 if (string) {
4531 CFArrayAppendValue(dnsNames, string);
4532 CFRelease(string);
4533 } else {
4534 return errSecInvalidCertificate;
4535 }
4536 }
4537 return errSecSuccess;
4538 }
4539
4540 CFArrayRef SecCertificateCopyRFC822Names(SecCertificateRef certificate) {
4541 /* These can exist in the subject alt name or in the subject. */
4542 CFMutableArrayRef rfc822Names = CFArrayCreateMutable(kCFAllocatorDefault,
4543 0, &kCFTypeArrayCallBacks);
4544 OSStatus status = errSecSuccess;
4545 if (certificate->_subjectAltName) {
4546 status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
4547 rfc822Names, appendRFC822NamesFromGeneralNames);
4548 }
4549 if (!status) {
4550 status = parseX501NameContent(&certificate->_subject, rfc822Names,
4551 appendRFC822NamesFromX501Name);
4552 }
4553 if (status || CFArrayGetCount(rfc822Names) == 0) {
4554 CFRelease(rfc822Names);
4555 rfc822Names = NULL;
4556 }
4557 return rfc822Names;
4558 }
4559
4560 OSStatus SecCertificateCopyEmailAddresses(SecCertificateRef certificate, CFArrayRef * __nonnull CF_RETURNS_RETAINED emailAddresses) {
4561 if (!certificate || !emailAddresses) {
4562 return errSecParam;
4563 }
4564 *emailAddresses = SecCertificateCopyRFC822Names(certificate);
4565 if (*emailAddresses == NULL) {
4566 *emailAddresses = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
4567 }
4568 return errSecSuccess;
4569 }
4570
4571 static OSStatus appendCommonNamesFromX501Name(void *context,
4572 const DERItem *type, const DERItem *value, CFIndex rdnIX) {
4573 CFMutableArrayRef commonNames = (CFMutableArrayRef)context;
4574 if (DEROidCompare(type, &oidCommonName)) {
4575 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4576 value, true);
4577 if (string) {
4578 CFArrayAppendValue(commonNames, string);
4579 CFRelease(string);
4580 } else {
4581 return errSecInvalidCertificate;
4582 }
4583 }
4584 return errSecSuccess;
4585 }
4586
4587 CFArrayRef SecCertificateCopyCommonNames(SecCertificateRef certificate) {
4588 CFMutableArrayRef commonNames = CFArrayCreateMutable(kCFAllocatorDefault,
4589 0, &kCFTypeArrayCallBacks);
4590 OSStatus status;
4591 status = parseX501NameContent(&certificate->_subject, commonNames,
4592 appendCommonNamesFromX501Name);
4593 if (status || CFArrayGetCount(commonNames) == 0) {
4594 CFRelease(commonNames);
4595 commonNames = NULL;
4596 }
4597 return commonNames;
4598 }
4599
4600 OSStatus SecCertificateCopyCommonName(SecCertificateRef certificate, CFStringRef *commonName)
4601 {
4602 if (!certificate) {
4603 return errSecParam;
4604 }
4605 CFArrayRef commonNames = SecCertificateCopyCommonNames(certificate);
4606 if (!commonNames) {
4607 return errSecInternal;
4608 }
4609
4610 if (commonName) {
4611 CFIndex count = CFArrayGetCount(commonNames);
4612 *commonName = CFRetainSafe(CFArrayGetValueAtIndex(commonNames, count-1));
4613 }
4614 CFReleaseSafe(commonNames);
4615 return errSecSuccess;
4616 }
4617
4618 static OSStatus appendOrganizationFromX501Name(void *context,
4619 const DERItem *type, const DERItem *value, CFIndex rdnIX) {
4620 CFMutableArrayRef organization = (CFMutableArrayRef)context;
4621 if (DEROidCompare(type, &oidOrganizationName)) {
4622 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4623 value, true);
4624 if (string) {
4625 CFArrayAppendValue(organization, string);
4626 CFRelease(string);
4627 } else {
4628 return errSecInvalidCertificate;
4629 }
4630 }
4631 return errSecSuccess;
4632 }
4633
4634 CFArrayRef SecCertificateCopyOrganization(SecCertificateRef certificate) {
4635 CFMutableArrayRef organization = CFArrayCreateMutable(kCFAllocatorDefault,
4636 0, &kCFTypeArrayCallBacks);
4637 OSStatus status;
4638 status = parseX501NameContent(&certificate->_subject, organization,
4639 appendOrganizationFromX501Name);
4640 if (status || CFArrayGetCount(organization) == 0) {
4641 CFRelease(organization);
4642 organization = NULL;
4643 }
4644 return organization;
4645 }
4646
4647 static OSStatus appendOrganizationalUnitFromX501Name(void *context,
4648 const DERItem *type, const DERItem *value, CFIndex rdnIX) {
4649 CFMutableArrayRef organizationalUnit = (CFMutableArrayRef)context;
4650 if (DEROidCompare(type, &oidOrganizationalUnitName)) {
4651 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4652 value, true);
4653 if (string) {
4654 CFArrayAppendValue(organizationalUnit, string);
4655 CFRelease(string);
4656 } else {
4657 return errSecInvalidCertificate;
4658 }
4659 }
4660 return errSecSuccess;
4661 }
4662
4663 CFArrayRef SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate) {
4664 CFMutableArrayRef organizationalUnit = CFArrayCreateMutable(kCFAllocatorDefault,
4665 0, &kCFTypeArrayCallBacks);
4666 OSStatus status;
4667 status = parseX501NameContent(&certificate->_subject, organizationalUnit,
4668 appendOrganizationalUnitFromX501Name);
4669 if (status || CFArrayGetCount(organizationalUnit) == 0) {
4670 CFRelease(organizationalUnit);
4671 organizationalUnit = NULL;
4672 }
4673 return organizationalUnit;
4674 }
4675
4676 static OSStatus appendCountryFromX501Name(void *context,
4677 const DERItem *type, const DERItem *value, CFIndex rdnIX) {
4678 CFMutableArrayRef countries = (CFMutableArrayRef)context;
4679 if (DEROidCompare(type, &oidCountryName)) {
4680 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4681 value, true);
4682 if (string) {
4683 CFArrayAppendValue(countries, string);
4684 CFRelease(string);
4685 } else {
4686 return errSecInvalidCertificate;
4687 }
4688 }
4689 return errSecSuccess;
4690 }
4691
4692 CFArrayRef SecCertificateCopyCountry(SecCertificateRef certificate) {
4693 CFMutableArrayRef countries = CFArrayCreateMutable(kCFAllocatorDefault,
4694 0, &kCFTypeArrayCallBacks);
4695 OSStatus status;
4696 status = parseX501NameContent(&certificate->_subject, countries,
4697 appendCountryFromX501Name);
4698 if (status || CFArrayGetCount(countries) == 0) {
4699 CFRelease(countries);
4700 countries = NULL;
4701 }
4702 return countries;
4703 }
4704
4705 const SecCEBasicConstraints *
4706 SecCertificateGetBasicConstraints(SecCertificateRef certificate) {
4707 if (certificate->_basicConstraints.present)
4708 return &certificate->_basicConstraints;
4709 else
4710 return NULL;
4711 }
4712
4713 CFArrayRef SecCertificateGetPermittedSubtrees(SecCertificateRef certificate) {
4714 return (certificate->_permittedSubtrees);
4715 }
4716
4717 CFArrayRef SecCertificateGetExcludedSubtrees(SecCertificateRef certificate) {
4718 return (certificate->_excludedSubtrees);
4719 }
4720
4721 const SecCEPolicyConstraints *
4722 SecCertificateGetPolicyConstraints(SecCertificateRef certificate) {
4723 if (certificate->_policyConstraints.present)
4724 return &certificate->_policyConstraints;
4725 else
4726 return NULL;
4727 }
4728
4729 const SecCEPolicyMappings *
4730 SecCertificateGetPolicyMappings(SecCertificateRef certificate) {
4731 if (certificate->_policyMappings.present) {
4732 return &certificate->_policyMappings;
4733 } else {
4734 return NULL;
4735 }
4736 }
4737
4738 const SecCECertificatePolicies *
4739 SecCertificateGetCertificatePolicies(SecCertificateRef certificate) {
4740 if (certificate->_certificatePolicies.present)
4741 return &certificate->_certificatePolicies;
4742 else
4743 return NULL;
4744 }
4745
4746 const SecCEInhibitAnyPolicy *
4747 SecCertificateGetInhibitAnyPolicySkipCerts(SecCertificateRef certificate) {
4748 if (certificate->_inhibitAnyPolicySkipCerts.present) {
4749 return &certificate->_inhibitAnyPolicySkipCerts;
4750 } else {
4751 return NULL;
4752 }
4753 }
4754
4755 static OSStatus appendNTPrincipalNamesFromGeneralNames(void *context,
4756 SecCEGeneralNameType gnType, const DERItem *generalName) {
4757 CFMutableArrayRef ntPrincipalNames = (CFMutableArrayRef)context;
4758 if (gnType == GNT_OtherName) {
4759 DEROtherName on;
4760 DERReturn drtn = DERParseSequenceContent(generalName,
4761 DERNumOtherNameItemSpecs, DEROtherNameItemSpecs,
4762 &on, sizeof(on));
4763 require_noerr_quiet(drtn, badDER);
4764 if (DEROidCompare(&on.typeIdentifier, &oidMSNTPrincipalName)) {
4765 CFStringRef string;
4766 require_quiet(string = copyDERThingDescription(kCFAllocatorDefault,
4767 &on.value, true), badDER);
4768 CFArrayAppendValue(ntPrincipalNames, string);
4769 CFRelease(string);
4770 }
4771 }
4772 return errSecSuccess;
4773
4774 badDER:
4775 return errSecInvalidCertificate;
4776
4777 }
4778
4779 CFArrayRef SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate) {
4780 CFMutableArrayRef ntPrincipalNames = CFArrayCreateMutable(kCFAllocatorDefault,
4781 0, &kCFTypeArrayCallBacks);
4782 OSStatus status = errSecSuccess;
4783 if (certificate->_subjectAltName) {
4784 status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
4785 ntPrincipalNames, appendNTPrincipalNamesFromGeneralNames);
4786 }
4787 if (status || CFArrayGetCount(ntPrincipalNames) == 0) {
4788 CFRelease(ntPrincipalNames);
4789 ntPrincipalNames = NULL;
4790 }
4791 return ntPrincipalNames;
4792 }
4793
4794 static OSStatus appendToRFC2253String(void *context,
4795 const DERItem *type, const DERItem *value, CFIndex rdnIX) {
4796 CFMutableStringRef string = (CFMutableStringRef)context;
4797 /*
4798 CN commonName
4799 L localityName
4800 ST stateOrProvinceName
4801 O organizationName
4802 OU organizationalUnitName
4803 C countryName
4804 STREET streetAddress
4805 DC domainComponent
4806 UID userid
4807 */
4808 /* Prepend a + if this is not the first RDN in an RDN set.
4809 Otherwise prepend a , if this is not the first RDN. */
4810 if (rdnIX > 0)
4811 CFStringAppend(string, CFSTR("+"));
4812 else if (CFStringGetLength(string)) {
4813 CFStringAppend(string, CFSTR(","));
4814 }
4815
4816 CFStringRef label, oid = NULL;
4817 /* @@@ Consider changing this to a dictionary lookup keyed by the
4818 decimal representation. */
4819 if (DEROidCompare(type, &oidCommonName)) {
4820 label = CFSTR("CN");
4821 } else if (DEROidCompare(type, &oidLocalityName)) {
4822 label = CFSTR("L");
4823 } else if (DEROidCompare(type, &oidStateOrProvinceName)) {
4824 label = CFSTR("ST");
4825 } else if (DEROidCompare(type, &oidOrganizationName)) {
4826 label = CFSTR("O");
4827 } else if (DEROidCompare(type, &oidOrganizationalUnitName)) {
4828 label = CFSTR("OU");
4829 } else if (DEROidCompare(type, &oidCountryName)) {
4830 label = CFSTR("C");
4831 #if 0
4832 } else if (DEROidCompare(type, &oidStreetAddress)) {
4833 label = CFSTR("STREET");
4834 } else if (DEROidCompare(type, &oidDomainComponent)) {
4835 label = CFSTR("DC");
4836 } else if (DEROidCompare(type, &oidUserID)) {
4837 label = CFSTR("UID");
4838 #endif
4839 } else {
4840 label = oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, type);
4841 }
4842
4843 CFStringAppend(string, label);
4844 CFStringAppend(string, CFSTR("="));
4845 CFStringRef raw = NULL;
4846 if (!oid)
4847 raw = copyDERThingDescription(kCFAllocatorDefault, value, true);
4848
4849 if (raw) {
4850 /* Append raw to string while escaping:
4851 a space or "#" character occurring at the beginning of the string
4852 a space character occurring at the end of the string
4853 one of the characters ",", "+", """, "\", "<", ">" or ";"
4854 */
4855 CFStringInlineBuffer buffer = {};
4856 CFIndex ix, length = CFStringGetLength(raw);
4857 CFRange range = { 0, length };
4858 CFStringInitInlineBuffer(raw, &buffer, range);
4859 for (ix = 0; ix < length; ++ix) {
4860 UniChar ch = CFStringGetCharacterFromInlineBuffer(&buffer, ix);
4861 if (ch < 0x20) {
4862 CFStringAppendFormat(string, NULL, CFSTR("\\%02X"), ch);
4863 } else if (ch == ',' || ch == '+' || ch == '"' || ch == '\\' ||
4864 ch == '<' || ch == '>' || ch == ';' ||
4865 (ch == ' ' && (ix == 0 || ix == length - 1)) ||
4866 (ch == '#' && ix == 0)) {
4867 UniChar chars[] = { '\\', ch };
4868 CFStringAppendCharacters(string, chars, 2);
4869 } else {
4870 CFStringAppendCharacters(string, &ch, 1);
4871 }
4872 }
4873 CFRelease(raw);
4874 } else {
4875 /* Append the value in hex. */
4876 CFStringAppend(string, CFSTR("#"));
4877 DERSize ix;
4878 for (ix = 0; ix < value->length; ++ix)
4879 CFStringAppendFormat(string, NULL, CFSTR("%02X"), value->data[ix]);
4880 }
4881
4882 CFReleaseSafe(oid);
4883
4884 return errSecSuccess;
4885 }
4886
4887 CFStringRef SecCertificateCopySubjectString(SecCertificateRef certificate) {
4888 CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0);
4889 OSStatus status = parseX501NameContent(&certificate->_subject, string, appendToRFC2253String);
4890 if (status || CFStringGetLength(string) == 0) {
4891 CFRelease(string);
4892 string = NULL;
4893 }
4894 return string;
4895 }
4896
4897 static OSStatus appendToCompanyNameString(void *context,
4898 const DERItem *type, const DERItem *value, CFIndex rdnIX) {
4899 CFMutableStringRef string = (CFMutableStringRef)context;
4900 if (CFStringGetLength(string) != 0)
4901 return errSecSuccess;
4902
4903 if (!DEROidCompare(type, &oidOrganizationName))
4904 return errSecSuccess;
4905
4906 CFStringRef raw;
4907 raw = copyDERThingDescription(kCFAllocatorDefault, value, true);
4908 if (!raw)
4909 return errSecSuccess;
4910 CFStringAppend(string, raw);
4911 CFRelease(raw);
4912
4913 return errSecSuccess;
4914 }
4915
4916 CFStringRef SecCertificateCopyCompanyName(SecCertificateRef certificate) {
4917 CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0);
4918 OSStatus status = parseX501NameContent(&certificate->_subject, string,
4919 appendToCompanyNameString);
4920 if (status || CFStringGetLength(string) == 0) {
4921 CFRelease(string);
4922 string = NULL;
4923 }
4924 return string;
4925 }
4926
4927 CFDataRef SecCertificateCopyIssuerSequence(
4928 SecCertificateRef certificate) {
4929 return SecDERItemCopySequence(&certificate->_issuer);
4930 }
4931
4932 CFDataRef SecCertificateCopySubjectSequence(
4933 SecCertificateRef certificate) {
4934 return SecDERItemCopySequence(&certificate->_subject);
4935 }
4936
4937 CFDataRef SecCertificateCopyNormalizedIssuerSequence(SecCertificateRef certificate) {
4938 if (!certificate || !certificate->_normalizedIssuer) {
4939 return NULL;
4940 }
4941 return SecCopySequenceFromContent(certificate->_normalizedIssuer);
4942 }
4943
4944 CFDataRef SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certificate) {
4945 if (!certificate || !certificate->_normalizedSubject) {
4946 return NULL;
4947 }
4948 return SecCopySequenceFromContent(certificate->_normalizedSubject);
4949 }
4950
4951 const DERAlgorithmId *SecCertificateGetPublicKeyAlgorithm(
4952 SecCertificateRef certificate) {
4953 return &certificate->_algId;
4954 }
4955
4956 const DERItem *SecCertificateGetPublicKeyData(SecCertificateRef certificate) {
4957 return &certificate->_pubKeyDER;
4958 }
4959
4960 #if TARGET_OS_OSX
4961 /* There is already a SecCertificateCopyPublicKey with different args on OS X,
4962 so we will refer to this one internally as SecCertificateCopyPublicKey_ios.
4963 */
4964 __nullable SecKeyRef SecCertificateCopyPublicKey_ios(SecCertificateRef certificate)
4965 #else
4966 __nullable SecKeyRef SecCertificateCopyPublicKey(SecCertificateRef certificate)
4967 #endif
4968 {
4969 if (certificate->_pubKey == NULL) {
4970 const DERAlgorithmId *algId =
4971 SecCertificateGetPublicKeyAlgorithm(certificate);
4972 const DERItem *keyData = SecCertificateGetPublicKeyData(certificate);
4973 const DERItem *params = NULL;
4974 if (algId->params.length != 0) {
4975 params = &algId->params;
4976 }
4977 SecAsn1Oid oid1 = { .Data = algId->oid.data, .Length = algId->oid.length };
4978 SecAsn1Item params1 = {
4979 .Data = params ? params->data : NULL,
4980 .Length = params ? params->length : 0
4981 };
4982 SecAsn1Item keyData1 = {
4983 .Data = keyData ? keyData->data : NULL,
4984 .Length = keyData ? keyData->length : 0
4985 };
4986 certificate->_pubKey = SecKeyCreatePublicFromDER(kCFAllocatorDefault, &oid1, &params1,
4987 &keyData1);
4988 }
4989
4990 return CFRetainSafe(certificate->_pubKey);
4991 }
4992
4993 static CFIndex SecCertificateGetPublicKeyAlgorithmIdAndSize(SecCertificateRef certificate, size_t *keySizeInBytes) {
4994 CFIndex keyAlgID = kSecNullAlgorithmID;
4995 size_t size = 0;
4996
4997 SecKeyRef pubKey = NULL;
4998 require_quiet(certificate, out);
4999 #if TARGET_OS_OSX
5000 require_quiet(pubKey = SecCertificateCopyPublicKey_ios(certificate), out);
5001 #else
5002 require_quiet(pubKey = SecCertificateCopyPublicKey(certificate) ,out);
5003 #endif
5004 size = SecKeyGetBlockSize(pubKey);
5005 keyAlgID = SecKeyGetAlgorithmId(pubKey);
5006
5007 out:
5008 CFReleaseNull(pubKey);
5009 if (keySizeInBytes) { *keySizeInBytes = size; }
5010 return keyAlgID;
5011 }
5012
5013 /*
5014 * Public keys in certificates may be considered "weak" or "strong" or neither
5015 * (that is, in between). Certificates using weak keys are not trusted at all.
5016 * Certificates using neither strong nor weak keys are only trusted in certain
5017 * contexts. SecPolicy and SecPolicyServer define the contexts by which we enforce
5018 * these (or stronger) key size trust policies.
5019 */
5020 bool SecCertificateIsWeakKey(SecCertificateRef certificate) {
5021 if (!certificate) { return true; }
5022
5023 bool weak = true;
5024 size_t size = 0;
5025 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) {
5026 case kSecRSAAlgorithmID:
5027 if (MIN_RSA_KEY_SIZE <= size) weak = false;
5028 break;
5029 case kSecECDSAAlgorithmID:
5030 if (MIN_EC_KEY_SIZE <= size) weak = false;
5031 break;
5032 default:
5033 weak = true;
5034 }
5035 return weak;
5036 }
5037
5038 bool SecCertificateIsStrongKey(SecCertificateRef certificate) {
5039 if (!certificate) { return false; }
5040
5041 bool strong = false;
5042 size_t size = 0;
5043 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) {
5044 case kSecRSAAlgorithmID:
5045 if (MIN_STRONG_RSA_KEY_SIZE <= size) strong = true;
5046 break;
5047 case kSecECDSAAlgorithmID:
5048 if (MIN_STRONG_EC_KEY_SIZE <= size) strong = true;
5049 break;
5050 default:
5051 strong = false;
5052 }
5053 return strong;
5054 }
5055
5056 bool SecCertificateIsWeakHash(SecCertificateRef certificate) {
5057 if (!certificate) { return true; }
5058 SecSignatureHashAlgorithm certAlg = 0;
5059 certAlg = SecCertificateGetSignatureHashAlgorithm(certificate);
5060 if (certAlg == kSecSignatureHashAlgorithmUnknown ||
5061 certAlg == kSecSignatureHashAlgorithmMD2 ||
5062 certAlg == kSecSignatureHashAlgorithmMD4 ||
5063 certAlg == kSecSignatureHashAlgorithmMD5 ||
5064 certAlg == kSecSignatureHashAlgorithmSHA1) {
5065 return true;
5066 }
5067 return false;
5068 }
5069
5070 bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate,
5071 CFDictionaryRef keySizes) {
5072 if (!certificate) { return false; }
5073
5074 bool goodSize = false;
5075 size_t size = 0;
5076 CFNumberRef minSize;
5077 size_t minSizeInBits;
5078 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) {
5079 case kSecRSAAlgorithmID:
5080 if(CFDictionaryGetValueIfPresent(keySizes, kSecAttrKeyTypeRSA, (const void**)&minSize)
5081 && minSize && CFNumberGetValue(minSize, kCFNumberLongType, &minSizeInBits)) {
5082 if (size >= (size_t)(minSizeInBits+7)/8) goodSize = true;
5083 }
5084 break;
5085 case kSecECDSAAlgorithmID:
5086 if(CFDictionaryGetValueIfPresent(keySizes, kSecAttrKeyTypeEC, (const void**)&minSize)
5087 && minSize && CFNumberGetValue(minSize, kCFNumberLongType, &minSizeInBits)) {
5088 if (size >= (size_t)(minSizeInBits+7)/8) goodSize = true;
5089 }
5090 break;
5091 default:
5092 goodSize = false;
5093 }
5094 return goodSize;
5095 }
5096
5097 CFDataRef SecCertificateGetSHA1Digest(SecCertificateRef certificate) {
5098 if (!certificate || !certificate->_der.data) {
5099 return NULL;
5100 }
5101 if (!certificate->_sha1Digest) {
5102 certificate->_sha1Digest =
5103 SecSHA1DigestCreate(CFGetAllocator(certificate),
5104 certificate->_der.data, certificate->_der.length);
5105 }
5106 return certificate->_sha1Digest;
5107 }
5108
5109 CFDataRef SecCertificateCopySHA256Digest(SecCertificateRef certificate) {
5110 if (!certificate || !certificate->_der.data) {
5111 return NULL;
5112 }
5113 return SecSHA256DigestCreate(CFGetAllocator(certificate),
5114 certificate->_der.data, certificate->_der.length);
5115 }
5116
5117 CFDataRef SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate) {
5118 CFDataRef digest = NULL;
5119 CFDataRef issuer = SecCertificateCopyIssuerSequence(certificate);
5120 if (issuer) {
5121 digest = SecSHA1DigestCreate(kCFAllocatorDefault,
5122 CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
5123 CFRelease(issuer);
5124 }
5125 return digest;
5126 }
5127
5128 CFDataRef SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate) {
5129 if (!certificate || !certificate->_pubKeyDER.data) {
5130 return NULL;
5131 }
5132 return SecSHA1DigestCreate(CFGetAllocator(certificate),
5133 certificate->_pubKeyDER.data, certificate->_pubKeyDER.length);
5134 }
5135
5136 CFDataRef SecCertificateCopySubjectPublicKeyInfoSHA1Digest(SecCertificateRef certificate) {
5137 if (!certificate || !certificate->_subjectPublicKeyInfo.data) {
5138 return NULL;
5139 }
5140 return SecSHA1DigestCreate(CFGetAllocator(certificate),
5141 certificate->_subjectPublicKeyInfo.data, certificate->_subjectPublicKeyInfo.length);
5142 }
5143
5144 CFDataRef SecCertificateCopySubjectPublicKeyInfoSHA256Digest(SecCertificateRef certificate) {
5145 if (!certificate || !certificate->_subjectPublicKeyInfo.data) {
5146 return NULL;
5147 }
5148 return SecSHA256DigestCreate(CFGetAllocator(certificate),
5149 certificate->_subjectPublicKeyInfo.data, certificate->_subjectPublicKeyInfo.length);
5150 }
5151
5152 CFTypeRef SecCertificateCopyKeychainItem(SecCertificateRef certificate)
5153 {
5154 if (!certificate) {
5155 return NULL;
5156 }
5157 CFRetainSafe(certificate->_keychain_item);
5158 return certificate->_keychain_item;
5159 }
5160
5161 CFDataRef SecCertificateGetAuthorityKeyID(SecCertificateRef certificate) {
5162 if (!certificate) {
5163 return NULL;
5164 }
5165 if (!certificate->_authorityKeyID &&
5166 certificate->_authorityKeyIdentifier.length) {
5167 certificate->_authorityKeyID = CFDataCreate(kCFAllocatorDefault,
5168 certificate->_authorityKeyIdentifier.data,
5169 certificate->_authorityKeyIdentifier.length);
5170 }
5171
5172 return certificate->_authorityKeyID;
5173 }
5174
5175 CFDataRef SecCertificateGetSubjectKeyID(SecCertificateRef certificate) {
5176 if (!certificate) {
5177 return NULL;
5178 }
5179 if (!certificate->_subjectKeyID &&
5180 certificate->_subjectKeyIdentifier.length) {
5181 certificate->_subjectKeyID = CFDataCreate(kCFAllocatorDefault,
5182 certificate->_subjectKeyIdentifier.data,
5183 certificate->_subjectKeyIdentifier.length);
5184 }
5185
5186 return certificate->_subjectKeyID;
5187 }
5188
5189 CFArrayRef SecCertificateGetCRLDistributionPoints(SecCertificateRef certificate) {
5190 if (!certificate) {
5191 return NULL;
5192 }
5193 return certificate->_crlDistributionPoints;
5194 }
5195
5196 CFArrayRef SecCertificateGetOCSPResponders(SecCertificateRef certificate) {
5197 if (!certificate) {
5198 return NULL;
5199 }
5200 return certificate->_ocspResponders;
5201 }
5202
5203 CFArrayRef SecCertificateGetCAIssuers(SecCertificateRef certificate) {
5204 if (!certificate) {
5205 return NULL;
5206 }
5207 return certificate->_caIssuers;
5208 }
5209
5210 bool SecCertificateHasCriticalSubjectAltName(SecCertificateRef certificate) {
5211 if (!certificate) {
5212 return false;
5213 }
5214 return certificate->_subjectAltName &&
5215 certificate->_subjectAltName->critical;
5216 }
5217
5218 bool SecCertificateHasSubject(SecCertificateRef certificate) {
5219 if (!certificate) {
5220 return false;
5221 }
5222 /* Since the _subject field is the content of the subject and not the
5223 whole thing, we can simply check for a 0 length subject here. */
5224 return certificate->_subject.length != 0;
5225 }
5226
5227 bool SecCertificateHasUnknownCriticalExtension(SecCertificateRef certificate) {
5228 if (!certificate) {
5229 return false;
5230 }
5231 return certificate->_foundUnknownCriticalExtension;
5232 }
5233
5234 /* Private API functions. */
5235 void SecCertificateShow(SecCertificateRef certificate) {
5236 check(certificate);
5237 fprintf(stderr, "SecCertificate instance %p:\n", certificate);
5238 fprintf(stderr, "\n");
5239 }
5240
5241 #ifndef STANDALONE
5242 CFDictionaryRef SecCertificateCopyAttributeDictionary(
5243 SecCertificateRef certificate) {
5244 if (!certificate || !(CFGetTypeID(certificate) == SecCertificateGetTypeID())) {
5245 return NULL;
5246 }
5247 CFAllocatorRef allocator = CFGetAllocator(certificate);
5248 CFNumberRef certificateType = NULL;
5249 CFNumberRef certificateEncoding = NULL;
5250 CFStringRef label = NULL;
5251 CFStringRef alias = NULL;
5252 CFDataRef skid = NULL;
5253 CFDataRef pubKeyDigest = NULL;
5254 CFDataRef certData = NULL;
5255 CFDictionaryRef dict = NULL;
5256
5257 DICT_DECLARE(11);
5258
5259 /* CSSM_CERT_X_509v1, CSSM_CERT_X_509v2 or CSSM_CERT_X_509v3 */
5260 SInt32 ctv = certificate->_version + 1;
5261 SInt32 cev = 3; /* CSSM_CERT_ENCODING_DER */
5262 certificateType = CFNumberCreate(allocator, kCFNumberSInt32Type, &ctv);
5263 require_quiet(certificateType != NULL, out);
5264 certificateEncoding = CFNumberCreate(allocator, kCFNumberSInt32Type, &cev);
5265 require_quiet(certificateEncoding != NULL, out);
5266 certData = SecCertificateCopyData(certificate);
5267 require_quiet(certData != NULL, out);
5268 skid = SecCertificateGetSubjectKeyID(certificate);
5269 require_quiet(certificate->_pubKeyDER.data != NULL && certificate->_pubKeyDER.length > 0, out);
5270 pubKeyDigest = SecSHA1DigestCreate(allocator, certificate->_pubKeyDER.data,
5271 certificate->_pubKeyDER.length);
5272 require_quiet(pubKeyDigest != NULL, out);
5273 #if 0
5274 /* We still need to figure out how to deal with multi valued attributes. */
5275 alias = SecCertificateCopyRFC822Names(certificate);
5276 label = SecCertificateCopySubjectSummary(certificate);
5277 #else
5278 alias = NULL;
5279 label = NULL;
5280 #endif
5281
5282 DICT_ADDPAIR(kSecClass, kSecClassCertificate);
5283 DICT_ADDPAIR(kSecAttrCertificateType, certificateType);
5284 DICT_ADDPAIR(kSecAttrCertificateEncoding, certificateEncoding);
5285 if (label) {
5286 DICT_ADDPAIR(kSecAttrLabel, label);
5287 }
5288 if (alias) {
5289 DICT_ADDPAIR(kSecAttrAlias, alias);
5290 }
5291 if (isData(certificate->_normalizedSubject)) {
5292 DICT_ADDPAIR(kSecAttrSubject, certificate->_normalizedSubject);
5293 }
5294 require_quiet(isData(certificate->_normalizedIssuer), out);
5295 DICT_ADDPAIR(kSecAttrIssuer, certificate->_normalizedIssuer);
5296 require_quiet(isData(certificate->_serialNumber), out);
5297 DICT_ADDPAIR(kSecAttrSerialNumber, certificate->_serialNumber);
5298 if (skid) {
5299 DICT_ADDPAIR(kSecAttrSubjectKeyID, skid);
5300 }
5301 DICT_ADDPAIR(kSecAttrPublicKeyHash, pubKeyDigest);
5302 DICT_ADDPAIR(kSecValueData, certData);
5303 dict = DICT_CREATE(allocator);
5304
5305 out:
5306 CFReleaseSafe(label);
5307 CFReleaseSafe(alias);
5308 CFReleaseSafe(pubKeyDigest);
5309 CFReleaseSafe(certData);
5310 CFReleaseSafe(certificateEncoding);
5311 CFReleaseSafe(certificateType);
5312
5313 return dict;
5314 }
5315
5316 SecCertificateRef SecCertificateCreateFromAttributeDictionary(
5317 CFDictionaryRef refAttributes) {
5318 /* @@@ Support having an allocator in refAttributes. */
5319 CFAllocatorRef allocator = NULL;
5320 CFDataRef data = CFDictionaryGetValue(refAttributes, kSecValueData);
5321 return data ? SecCertificateCreateWithData(allocator, data) : NULL;
5322 }
5323 #endif
5324
5325 static bool _SecCertificateIsSelfSigned(SecCertificateRef certificate) {
5326 if (certificate->_isSelfSigned == kSecSelfSignedUnknown) {
5327 certificate->_isSelfSigned = kSecSelfSignedFalse;
5328 SecKeyRef publicKey = NULL;
5329 require(certificate && (CFGetTypeID(certificate) == SecCertificateGetTypeID()), out);
5330 #if TARGET_OS_OSX
5331 require(publicKey = SecCertificateCopyPublicKey_ios(certificate), out);
5332 #else
5333 require(publicKey = SecCertificateCopyPublicKey(certificate), out);
5334 #endif
5335 CFDataRef normalizedIssuer =
5336 SecCertificateGetNormalizedIssuerContent(certificate);
5337 CFDataRef normalizedSubject =
5338 SecCertificateGetNormalizedSubjectContent(certificate);
5339 require_quiet(normalizedIssuer && normalizedSubject &&
5340 CFEqual(normalizedIssuer, normalizedSubject), out);
5341
5342 CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(certificate);
5343 CFDataRef subjectKeyID = SecCertificateGetSubjectKeyID(certificate);
5344 if (authorityKeyID) {
5345 require_quiet(subjectKeyID && CFEqual(subjectKeyID, authorityKeyID), out);
5346 }
5347
5348 require_noerr_quiet(SecCertificateIsSignedBy(certificate, publicKey), out);
5349
5350 certificate->_isSelfSigned = kSecSelfSignedTrue;
5351 out:
5352 CFReleaseSafe(publicKey);
5353 }
5354
5355 return (certificate->_isSelfSigned == kSecSelfSignedTrue);
5356 }
5357
5358 bool SecCertificateIsCA(SecCertificateRef certificate) {
5359 bool result = false;
5360 require(certificate && (CFGetTypeID(certificate) == SecCertificateGetTypeID()), out);
5361 if (SecCertificateVersion(certificate) >= 3) {
5362 const SecCEBasicConstraints *basicConstraints = SecCertificateGetBasicConstraints(certificate);
5363 result = (basicConstraints && basicConstraints->isCA);
5364 }
5365 else {
5366 result = _SecCertificateIsSelfSigned(certificate);
5367 }
5368 out:
5369 return result;
5370 }
5371
5372 bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate) {
5373 return (_SecCertificateIsSelfSigned(certificate) && SecCertificateIsCA(certificate));
5374 }
5375
5376 OSStatus SecCertificateIsSelfSigned(SecCertificateRef certificate, Boolean *isSelfSigned) {
5377 if (!certificate || (CFGetTypeID(certificate) != SecCertificateGetTypeID())) {
5378 return errSecInvalidCertificate;
5379 }
5380 if (!isSelfSigned) {
5381 return errSecParam;
5382 }
5383 *isSelfSigned = _SecCertificateIsSelfSigned(certificate);
5384 return errSecSuccess;
5385 }
5386
5387 SecKeyUsage SecCertificateGetKeyUsage(SecCertificateRef certificate) {
5388 if (!certificate) {
5389 return kSecKeyUsageUnspecified;
5390 }
5391 return certificate->_keyUsage;
5392 }
5393
5394 CFArrayRef SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate)
5395 {
5396 CFMutableArrayRef extended_key_usage_oids =
5397 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
5398 require_quiet(certificate && extended_key_usage_oids, out);
5399 int ix;
5400 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5401 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5402 if (extn->extnID.length == oidExtendedKeyUsage.length &&
5403 !memcmp(extn->extnID.data, oidExtendedKeyUsage.data, extn->extnID.length)) {
5404 DERTag tag;
5405 DERSequence derSeq;
5406 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &derSeq);
5407 require_noerr_quiet(drtn, out);
5408 require_quiet(tag == ASN1_CONSTR_SEQUENCE, out);
5409 DERDecodedInfo currDecoded;
5410
5411 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
5412 require_quiet(currDecoded.tag == ASN1_OBJECT_ID, out);
5413 CFDataRef oid = CFDataCreate(kCFAllocatorDefault,
5414 currDecoded.content.data, currDecoded.content.length);
5415 require_quiet(oid, out);
5416 CFArrayAppendValue(extended_key_usage_oids, oid);
5417 CFReleaseNull(oid);
5418 }
5419 require_quiet(drtn == DR_EndOfSequence, out);
5420 return extended_key_usage_oids;
5421 }
5422 }
5423 out:
5424 CFReleaseSafe(extended_key_usage_oids);
5425 return NULL;
5426 }
5427
5428 CFArrayRef SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate)
5429 {
5430 require_quiet(certificate, out);
5431 int ix;
5432
5433 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5434 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5435 if (extn->extnID.length == oidGoogleEmbeddedSignedCertificateTimestamp.length &&
5436 !memcmp(extn->extnID.data, oidGoogleEmbeddedSignedCertificateTimestamp.data, extn->extnID.length)) {
5437 /* Got the SCT oid */
5438 DERDecodedInfo sctList;
5439 DERReturn drtn = DERDecodeItem(&extn->extnValue, &sctList);
5440 require_noerr_quiet(drtn, out);
5441 require_quiet(sctList.tag == ASN1_OCTET_STRING, out);
5442 return SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sctList.content.data, sctList.content.length);
5443 }
5444 }
5445 out:
5446 return NULL;
5447 }
5448
5449
5450 static bool matches_expected(DERItem der, CFTypeRef expected) {
5451 if (der.length > 1) {
5452 DERDecodedInfo decoded;
5453 DERDecodeItem(&der, &decoded);
5454 switch (decoded.tag) {
5455 case ASN1_NULL:
5456 {
5457 return decoded.content.length == 0 && expected == NULL;
5458 }
5459 break;
5460
5461 case ASN1_IA5_STRING:
5462 case ASN1_UTF8_STRING: {
5463 if (isString(expected)) {
5464 CFStringRef expectedString = (CFStringRef) expected;
5465 CFStringRef itemString = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, decoded.content.data, decoded.content.length, kCFStringEncodingUTF8, false, kCFAllocatorNull);
5466
5467 bool result = (kCFCompareEqualTo == CFStringCompare(expectedString, itemString, 0));
5468 CFReleaseNull(itemString);
5469 return result;
5470 }
5471 }
5472 break;
5473
5474 case ASN1_OCTET_STRING: {
5475 if (isData(expected)) {
5476 CFDataRef expectedData = (CFDataRef) expected;
5477 CFDataRef itemData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, decoded.content.data, decoded.content.length, kCFAllocatorNull);
5478
5479 bool result = CFEqual(expectedData, itemData);
5480 CFReleaseNull(itemData);
5481 return result;
5482 }
5483 }
5484 break;
5485
5486 case ASN1_INTEGER: {
5487 SInt32 expected_value = 0;
5488 if (isString(expected))
5489 {
5490 CFStringRef aStr = (CFStringRef)expected;
5491 expected_value = CFStringGetIntValue(aStr);
5492 }
5493 else if (isNumber(expected))
5494 {
5495 CFNumberGetValue(expected, kCFNumberSInt32Type, &expected_value);
5496 }
5497
5498 uint32_t num_value = 0;
5499 if (!DERParseInteger(&decoded.content, &num_value))
5500 {
5501 return ((uint32_t)expected_value == num_value);
5502 }
5503 }
5504 break;
5505
5506 default:
5507 break;
5508 }
5509 }
5510
5511 return false;
5512 }
5513
5514 static bool cert_contains_marker_extension_value(SecCertificateRef certificate, CFDataRef oid, CFTypeRef expectedValue)
5515 {
5516 CFIndex ix;
5517 const uint8_t *oid_data = CFDataGetBytePtr(oid);
5518 size_t oid_len = CFDataGetLength(oid);
5519
5520 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5521 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5522 if (extn->extnID.length == oid_len
5523 && !memcmp(extn->extnID.data, oid_data, extn->extnID.length))
5524 {
5525 return matches_expected(extn->extnValue, expectedValue);
5526 }
5527 }
5528 return false;
5529 }
5530
5531 static bool cert_contains_marker_extension(SecCertificateRef certificate, CFTypeRef oid)
5532 {
5533 return cert_contains_marker_extension_value(certificate, oid, NULL);
5534 }
5535
5536 struct search_context {
5537 bool found;
5538 SecCertificateRef certificate;
5539 };
5540
5541 static bool GetDecimalValueOfString(CFStringRef string, uint32_t* value)
5542 {
5543 CFCharacterSetRef nonDecimalDigit = CFCharacterSetCreateInvertedSet(NULL, CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit));
5544 bool result = false;
5545
5546 if ( CFStringGetLength(string) > 0
5547 && !CFStringFindCharacterFromSet(string, nonDecimalDigit, CFRangeMake(0, CFStringGetLength(string)), kCFCompareForcedOrdering, NULL))
5548 {
5549 if (value)
5550 *value = CFStringGetIntValue(string);
5551 result = true;
5552 }
5553
5554 CFReleaseNull(nonDecimalDigit);
5555
5556 return result;
5557 }
5558
5559 bool SecCertificateIsOidString(CFStringRef oid)
5560 {
5561 if (!oid) return false;
5562 if (2 >= CFStringGetLength(oid)) return false;
5563 bool result = true;
5564
5565 /* oid string only has the allowed characters */
5566 CFCharacterSetRef decimalOid = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("0123456789."));
5567 CFCharacterSetRef nonDecimalOid = CFCharacterSetCreateInvertedSet(NULL, decimalOid);
5568 if (CFStringFindCharacterFromSet(oid, nonDecimalOid, CFRangeMake(0, CFStringGetLength(oid)), kCFCompareForcedOrdering, NULL)) {
5569 result = false;
5570 }
5571
5572 /* first arc is allowed */
5573 UniChar firstArc[2];
5574 CFRange firstTwo = {0, 2};
5575 CFStringGetCharacters(oid, firstTwo, firstArc);
5576 if (firstArc[1] != '.' ||
5577 (firstArc[0] != '0' && firstArc[0] != '1' && firstArc[0] != '2')) {
5578 result = false;
5579 }
5580
5581 CFReleaseNull(decimalOid);
5582 CFReleaseNull(nonDecimalOid);
5583
5584 return result;
5585 }
5586
5587 CFDataRef SecCertificateCreateOidDataFromString(CFAllocatorRef allocator, CFStringRef string)
5588 {
5589 CFMutableDataRef currentResult = NULL;
5590 CFDataRef encodedResult = NULL;
5591
5592 CFArrayRef parts = NULL;
5593 CFIndex count = 0;
5594
5595 if (!string || !SecCertificateIsOidString(string))
5596 goto exit;
5597
5598 parts = CFStringCreateArrayBySeparatingStrings(NULL, string, CFSTR("."));
5599
5600 if (!parts)
5601 goto exit;
5602
5603 count = CFArrayGetCount(parts);
5604 if (count == 0)
5605 goto exit;
5606
5607 // assume no more than 5 bytes needed to represent any part of the oid,
5608 // since we limit parts to 32-bit values,
5609 // but the first two parts only need 1 byte
5610 currentResult = CFDataCreateMutable(allocator, 1+(count-2)*5);
5611
5612 CFStringRef part;
5613 uint32_t x;
5614 uint8_t firstByte;
5615
5616 part = CFArrayGetValueAtIndex(parts, 0);
5617
5618 if (!GetDecimalValueOfString(part, &x) || x > 6)
5619 goto exit;
5620
5621 firstByte = x * 40;
5622
5623
5624 if (count > 1) {
5625 part = CFArrayGetValueAtIndex(parts, 1);
5626
5627 if (!GetDecimalValueOfString(part, &x) || x > 39)
5628 goto exit;
5629
5630 firstByte += x;
5631 }
5632
5633 CFDataAppendBytes(currentResult, &firstByte, 1);
5634
5635 for (CFIndex i = 2; i < count && GetDecimalValueOfString(CFArrayGetValueAtIndex(parts, i), &x); ++i) {
5636 uint8_t b[5] = {0, 0, 0, 0, 0};
5637 b[4] = (x & 0x7F);
5638 b[3] = 0x80 | ((x >> 7) & 0x7F);
5639 b[2] = 0x80 | ((x >> 14) & 0x7F);
5640 b[1] = 0x80 | ((x >> 21) & 0x7F);
5641 b[0] = 0x80 | ((x >> 28) & 0x7F);
5642
5643 // Skip the unused extension bytes.
5644 size_t skipBytes = 0;
5645 while (b[skipBytes] == 0x80)
5646 ++skipBytes;
5647
5648 CFDataAppendBytes(currentResult, b + skipBytes, sizeof(b) - skipBytes);
5649 }
5650
5651 encodedResult = currentResult;
5652 currentResult = NULL;
5653
5654 exit:
5655 CFReleaseNull(parts);
5656 CFReleaseNull(currentResult);
5657
5658 return encodedResult;
5659 }
5660
5661 static void check_for_marker(const void *key, const void *value, void *context)
5662 {
5663 struct search_context * search_ctx = (struct search_context *) context;
5664 CFStringRef key_string = (CFStringRef) key;
5665 CFTypeRef value_ref = (CFTypeRef) value;
5666
5667 // If we could have short circuted the iteration
5668 // we would have, but the best we can do
5669 // is not waste time comparing once a match
5670 // was found.
5671 if (search_ctx->found)
5672 return;
5673
5674 if (CFGetTypeID(key_string) != CFStringGetTypeID())
5675 return;
5676
5677 CFDataRef key_data = SecCertificateCreateOidDataFromString(NULL, key_string);
5678
5679 if (NULL == key_data)
5680 return;
5681
5682 if (cert_contains_marker_extension_value(search_ctx->certificate, key_data, value_ref))
5683 search_ctx->found = true;
5684
5685 CFReleaseNull(key_data);
5686 }
5687
5688 //
5689 // CFType Ref is either:
5690 //
5691 // CFData - OID to match with no data permitted
5692 // CFString - decimal OID to match
5693 // CFDictionary - OID -> Value table for expected values Single Object or Array
5694 // CFArray - Array of the above.
5695 //
5696 // This returns true if any of the requirements are met.
5697 bool SecCertificateHasMarkerExtension(SecCertificateRef certificate, CFTypeRef oids)
5698 {
5699 if (CFGetTypeID(oids) == CFArrayGetTypeID()) {
5700 CFIndex ix, length = CFArrayGetCount(oids);
5701 for (ix = 0; ix < length; ix++)
5702 if (SecCertificateHasMarkerExtension(certificate, CFArrayGetValueAtIndex((CFArrayRef)oids, ix)))
5703 return true;
5704 } else if (CFGetTypeID(oids) == CFDictionaryGetTypeID()) {
5705 struct search_context context = { .found = false, .certificate = certificate };
5706 CFDictionaryApplyFunction((CFDictionaryRef) oids, &check_for_marker, &context);
5707 return context.found;
5708 } else if (CFGetTypeID(oids) == CFDataGetTypeID()) {
5709 return cert_contains_marker_extension(certificate, oids);
5710 } else if (CFGetTypeID(oids) == CFStringGetTypeID()) {
5711 CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, oids);
5712 if (dataOid == NULL) return false;
5713 bool result = cert_contains_marker_extension(certificate, dataOid);
5714 CFReleaseNull(dataOid);
5715 return result;
5716 }
5717 return false;
5718 }
5719
5720 static DERItem *cert_extension_value_for_marker(SecCertificateRef certificate, CFDataRef oid) {
5721 CFIndex ix;
5722 const uint8_t *oid_data = CFDataGetBytePtr(oid);
5723 size_t oid_len = CFDataGetLength(oid);
5724
5725 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5726 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5727 if (extn->extnID.length == oid_len
5728 && !memcmp(extn->extnID.data, oid_data, extn->extnID.length))
5729 {
5730 return (DERItem *)&extn->extnValue;
5731 }
5732 }
5733 return NULL;
5734 }
5735
5736 //
5737 // CFType Ref is either:
5738 //
5739 // CFData - OID to match with no data permitted
5740 // CFString - decimal OID to match
5741 //
5742 DERItem *SecCertificateGetExtensionValue(SecCertificateRef certificate, CFTypeRef oid) {
5743 if (!certificate || !oid) {
5744 return NULL;
5745 }
5746
5747 if(CFGetTypeID(oid) == CFDataGetTypeID()) {
5748 return cert_extension_value_for_marker(certificate, oid);
5749 } else if (CFGetTypeID(oid) == CFStringGetTypeID()) {
5750 CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, oid);
5751 if (dataOid == NULL) return NULL;
5752 DERItem *result = cert_extension_value_for_marker(certificate, dataOid);
5753 CFReleaseNull(dataOid);
5754 return result;
5755 }
5756
5757 return NULL;
5758 }
5759
5760 CFDataRef SecCertificateCopyiAPAuthCapabilities(SecCertificateRef certificate) {
5761 if (!certificate) {
5762 return NULL;
5763 }
5764 CFDataRef extensionData = NULL;
5765 DERItem *extensionValue = NULL;
5766 extensionValue = SecCertificateGetExtensionValue(certificate,
5767 CFSTR("1.2.840.113635.100.6.36"));
5768 require_quiet(extensionValue, out);
5769 /* The extension is a octet string containing the DER-encoded 32-byte octet string */
5770 require_quiet(extensionValue->length == 34, out);
5771 DERDecodedInfo decodedValue;
5772 require_noerr_quiet(DERDecodeItem(extensionValue, &decodedValue), out);
5773 if (decodedValue.tag == ASN1_OCTET_STRING) {
5774 require_quiet(decodedValue.content.length == 32, out);
5775 extensionData = CFDataCreate(NULL, decodedValue.content.data,
5776 decodedValue.content.length);
5777 } else {
5778 require_quiet(extensionValue->data[33] == 0x00 &&
5779 extensionValue->data[32] == 0x00, out);
5780 extensionData = CFDataCreate(NULL, extensionValue->data, 32);
5781 }
5782 out:
5783 return extensionData;
5784 }
5785
5786 #if 0
5787 /* From iapd IAPAuthenticationTypes.h */
5788 typedef struct IapCertSerialNumber
5789 {
5790 uint8_t xservID; // Xserver ID
5791 uint8_t hsmID; // Hardware security module ID (generated cert)
5792 uint8_t delimiter01; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5793 uint8_t dateYear; // Date year cert was issued
5794 uint8_t dateMonth; // Date month cert was issued
5795 uint8_t dateDay; // Date day cert was issued
5796 uint8_t delimiter02; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5797 uint8_t devClass; // iAP device class (maps to lingo permissions)
5798 uint8_t delimiter03; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5799 uint8_t batchNumHi; // Batch number high byte (15:08)
5800 uint8_t batchNumLo; // Batch number low byte (07:00)
5801 uint8_t delimiter04; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
5802 uint8_t serialNumHi; // Serial number high byte (23:16)
5803 uint8_t serialNumMid; // Serial number middle byte (15:08)
5804 uint8_t serialNumLo; // Serial number low byte (07:00)
5805
5806 } IapCertSerialNumber_t, *pIapCertSerialNumber_t;
5807 #endif
5808
5809 #define IAP_CERT_FIELD_DELIMITER 0xAA // "Apple_Accessory" delimiter
5810 SeciAuthVersion SecCertificateGetiAuthVersion(SecCertificateRef certificate) {
5811 if (!certificate) {
5812 return kSeciAuthInvalid;
5813 }
5814 if (NULL != SecCertificateGetExtensionValue(certificate,
5815 CFSTR("1.2.840.113635.100.6.36"))) {
5816 return kSeciAuthVersion3;
5817 }
5818 DERItem serialNumber = certificate->_serialNum;
5819 require_quiet(serialNumber.data, out);
5820 require_quiet(serialNumber.length == 15, out);
5821 require_quiet(serialNumber.data[2] == IAP_CERT_FIELD_DELIMITER &&
5822 serialNumber.data[6] == IAP_CERT_FIELD_DELIMITER &&
5823 serialNumber.data[8] == IAP_CERT_FIELD_DELIMITER &&
5824 serialNumber.data[11] == IAP_CERT_FIELD_DELIMITER, out);
5825 return kSeciAuthVersion2;
5826 out:
5827 return kSeciAuthInvalid;
5828 }
5829
5830 SecCertificateRef SecCertificateCreateWithPEM(CFAllocatorRef allocator,
5831 CFDataRef pem_certificate)
5832 {
5833 static const char begin_cert[] = "-----BEGIN CERTIFICATE-----\n";
5834 static const char end_cert[] = "-----END CERTIFICATE-----\n";
5835 uint8_t *base64_data = NULL;
5836 SecCertificateRef cert = NULL;
5837 const unsigned char *data = CFDataGetBytePtr(pem_certificate);
5838 //const size_t length = CFDataGetLength(pem_certificate);
5839 char *begin = strstr((const char *)data, begin_cert);
5840 char *end = strstr((const char *)data, end_cert);
5841 if (!begin || !end)
5842 return NULL;
5843 begin += sizeof(begin_cert) - 1;
5844 size_t base64_length = SecBase64Decode(begin, end - begin, NULL, 0);
5845 if (base64_length && (base64_length < (size_t)CFDataGetLength(pem_certificate))) {
5846 require_quiet(base64_data = calloc(1, base64_length), out);
5847 require_action_quiet(base64_length = SecBase64Decode(begin, end - begin, base64_data, base64_length), out, free(base64_data));
5848 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, base64_data, base64_length);
5849 free(base64_data);
5850 }
5851 out:
5852 return cert;
5853 }
5854
5855
5856 //
5857 // -- MARK -- XPC encoding/decoding
5858 //
5859
5860 bool SecCertificateAppendToXPCArray(SecCertificateRef certificate, xpc_object_t xpc_certificates, CFErrorRef *error) {
5861 if (!certificate)
5862 return true; // NOOP
5863
5864 size_t length = SecCertificateGetLength(certificate);
5865 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
5866 #if SECTRUST_VERBOSE_DEBUG
5867 secerror("cert=0x%lX length=%d bytes=0x%lX", (uintptr_t)certificate, (int)length, (uintptr_t)bytes);
5868 #endif
5869 if (!length || !bytes) {
5870 return SecError(errSecParam, error, CFSTR("failed to der encode certificate"));
5871 }
5872 xpc_array_set_data(xpc_certificates, XPC_ARRAY_APPEND, bytes, length);
5873 return true;
5874 }
5875
5876 SecCertificateRef SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates, size_t index, CFErrorRef *error) {
5877 SecCertificateRef certificate = NULL;
5878 size_t length = 0;
5879 const uint8_t *bytes = xpc_array_get_data(xpc_certificates, index, &length);
5880 if (bytes) {
5881 certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length);
5882 }
5883 if (!certificate) {
5884 SecError(errSecParam, error, CFSTR("certificates[%zu] failed to decode"), index);
5885 }
5886 return certificate;
5887 }
5888
5889 xpc_object_t SecCertificateArrayCopyXPCArray(CFArrayRef certificates, CFErrorRef *error) {
5890 xpc_object_t xpc_certificates;
5891 require_action_quiet(xpc_certificates = xpc_array_create(NULL, 0), exit,
5892 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array")));
5893 CFIndex ix, count = CFArrayGetCount(certificates);
5894 for (ix = 0; ix < count; ++ix) {
5895 SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, ix);
5896 #if SECTRUST_VERBOSE_DEBUG
5897 CFIndex length = SecCertificateGetLength(certificate);
5898 const UInt8 *bytes = SecCertificateGetBytePtr(certificate);
5899 secerror("idx=%d of %d; cert=0x%lX length=%ld bytes=0x%lX", (int)ix, (int)count, (uintptr_t)certificate, (size_t)length, (uintptr_t)bytes);
5900 #endif
5901 if (!SecCertificateAppendToXPCArray(certificate, xpc_certificates, error)) {
5902 xpc_release(xpc_certificates);
5903 xpc_certificates = NULL;
5904 break;
5905 }
5906 }
5907
5908 exit:
5909 return xpc_certificates;
5910 }
5911
5912 CFArrayRef SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates, CFErrorRef *error) {
5913 CFMutableArrayRef certificates = NULL;
5914 require_action_quiet(xpc_get_type(xpc_certificates) == XPC_TYPE_ARRAY, exit,
5915 SecError(errSecParam, error, CFSTR("certificates xpc value is not an array")));
5916 size_t count = xpc_array_get_count(xpc_certificates);
5917 require_action_quiet(certificates = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit,
5918 SecError(errSecAllocate, error, CFSTR("failed to create CFArray of capacity %zu"), count));
5919
5920 size_t ix;
5921 for (ix = 0; ix < count; ++ix) {
5922 SecCertificateRef cert = SecCertificateCreateWithXPCArrayAtIndex(xpc_certificates, ix, error);
5923 if (!cert) {
5924 CFRelease(certificates);
5925 return NULL;
5926 }
5927 CFArraySetValueAtIndex(certificates, ix, cert);
5928 CFRelease(cert);
5929 }
5930
5931 exit:
5932 return certificates;
5933 }
5934
5935 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
5936
5937
5938 static CFArrayRef CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType, CFErrorRef* error)
5939 {
5940 __block CFArrayRef result = NULL;
5941
5942 do_if_registered(ota_CopyEscrowCertificates, escrowRootType, error);
5943
5944 securityd_send_sync_and_do(kSecXPCOpOTAGetEscrowCertificates, error,
5945 ^bool(xpc_object_t message, CFErrorRef *error)
5946 {
5947 xpc_dictionary_set_uint64(message, "escrowType", (uint64_t)escrowRootType);
5948 return true;
5949 },
5950 ^bool(xpc_object_t response, CFErrorRef *error)
5951 {
5952 xpc_object_t xpc_array = xpc_dictionary_get_value(response, kSecXPCKeyResult);
5953
5954 if (response && (NULL != xpc_array)) {
5955 result = (CFArrayRef)_CFXPCCreateCFObjectFromXPCObject(xpc_array);
5956 }
5957 else {
5958 return SecError(errSecInternal, error, CFSTR("Did not get the Escrow certificates"));
5959 }
5960 return result != NULL;
5961 });
5962 return result;
5963 }
5964
5965 CFArrayRef SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType)
5966 {
5967 CFArrayRef result = NULL;
5968 int iCnt;
5969 CFDataRef certData = NULL;
5970 int numRoots = 0;
5971
5972 if (kSecCertificateBaselineEscrowRoot == escrowRootType ||
5973 kSecCertificateBaselinePCSEscrowRoot == escrowRootType ||
5974 kSecCertificateBaselineEscrowBackupRoot == escrowRootType ||
5975 kSecCertificateBaselineEscrowEnrollmentRoot == escrowRootType)
5976 {
5977 // The request is for the base line certificates.
5978 // Use the hard coded data to generate the return array.
5979 struct RootRecord** pEscrowRoots;
5980 switch (escrowRootType) {
5981 case kSecCertificateBaselineEscrowRoot:
5982 numRoots = kNumberOfBaseLineEscrowRoots;
5983 pEscrowRoots = kBaseLineEscrowRoots;
5984 break;
5985 case kSecCertificateBaselinePCSEscrowRoot:
5986 numRoots = kNumberOfBaseLinePCSEscrowRoots;
5987 pEscrowRoots = kBaseLinePCSEscrowRoots;
5988 break;
5989 case kSecCertificateBaselineEscrowBackupRoot:
5990 numRoots = kNumberOfBaseLineEscrowBackupRoots;
5991 pEscrowRoots = kBaseLineEscrowBackupRoots;
5992 break;
5993 case kSecCertificateBaselineEscrowEnrollmentRoot:
5994 default:
5995 numRoots = kNumberOfBaseLineEscrowEnrollmentRoots;
5996 pEscrowRoots = kBaseLineEscrowEnrollmentRoots;
5997 break;
5998 }
5999
6000 // Get the hard coded set of roots
6001 SecCertificateRef baseLineCerts[numRoots];
6002 struct RootRecord* pRootRecord = NULL;
6003
6004 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6005 pRootRecord = pEscrowRoots[iCnt];
6006 if (NULL != pRootRecord && pRootRecord->_length > 0 && NULL != pRootRecord->_bytes) {
6007 certData = CFDataCreate(kCFAllocatorDefault, pRootRecord->_bytes, pRootRecord->_length);
6008 if (NULL != certData) {
6009 baseLineCerts[iCnt] = SecCertificateCreateWithData(kCFAllocatorDefault, certData);
6010 CFRelease(certData);
6011 }
6012 }
6013 }
6014 result = CFArrayCreate(kCFAllocatorDefault, (const void **)baseLineCerts, numRoots, &kCFTypeArrayCallBacks);
6015 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6016 if (NULL != baseLineCerts[iCnt]) {
6017 CFRelease(baseLineCerts[iCnt]);
6018 }
6019 }
6020 }
6021 else {
6022 // The request is for the current certificates.
6023 CFErrorRef error = NULL;
6024 CFArrayRef cert_datas = CopyEscrowCertificates(escrowRootType, &error);
6025 if (NULL != error || NULL == cert_datas) {
6026 if (NULL != error) {
6027 CFRelease(error);
6028 }
6029 if (NULL != cert_datas) {
6030 CFRelease(cert_datas);
6031 }
6032 return result;
6033 }
6034
6035 numRoots = (int)(CFArrayGetCount(cert_datas));
6036
6037 SecCertificateRef assetCerts[numRoots];
6038 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6039 certData = (CFDataRef)CFArrayGetValueAtIndex(cert_datas, iCnt);
6040 if (NULL != certData) {
6041 SecCertificateRef aCertRef = SecCertificateCreateWithData(kCFAllocatorDefault, certData);
6042 assetCerts[iCnt] = aCertRef;
6043 }
6044 else {
6045 assetCerts[iCnt] = NULL;
6046 }
6047 }
6048
6049 if (numRoots > 0) {
6050 result = CFArrayCreate(kCFAllocatorDefault, (const void **)assetCerts, numRoots, &kCFTypeArrayCallBacks);
6051 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6052 if (NULL != assetCerts[iCnt]) {
6053 CFRelease(assetCerts[iCnt]);
6054 }
6055 }
6056 }
6057 CFReleaseSafe(cert_datas);
6058 }
6059 return result;
6060 }
6061
6062 SEC_CONST_DECL (kSecSignatureDigestAlgorithmUnknown, "SignatureDigestUnknown");
6063 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD2, "SignatureDigestMD2");
6064 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD4, "SignatureDigestMD4");
6065 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD5, "SignatureDigestMD5");
6066 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA1, "SignatureDigestSHA1");
6067 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA224, "SignatureDigestSHA224");
6068 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA256, "SignatureDigestSHA256");
6069 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA384, "SignatureDigestSHA284");
6070 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA512, "SignatureDigestSHA512");
6071
6072 SecSignatureHashAlgorithm SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate)
6073 {
6074 SecSignatureHashAlgorithm result = kSecSignatureHashAlgorithmUnknown;
6075 DERAlgorithmId *algId = (certificate) ? &certificate->_tbsSigAlg : NULL;
6076 const DERItem *algOid = (algId) ? &algId->oid : NULL;
6077 while (algOid) {
6078 if (!algOid->data || !algOid->length) {
6079 break;
6080 }
6081 /* classify the signature algorithm OID into one of our known types */
6082 if (DEROidCompare(algOid, &oidSha512Ecdsa) ||
6083 DEROidCompare(algOid, &oidSha512Rsa) ||
6084 DEROidCompare(algOid, &oidSha512)) {
6085 result = kSecSignatureHashAlgorithmSHA512;
6086 break;
6087 }
6088 if (DEROidCompare(algOid, &oidSha384Ecdsa) ||
6089 DEROidCompare(algOid, &oidSha384Rsa) ||
6090 DEROidCompare(algOid, &oidSha384)) {
6091 result = kSecSignatureHashAlgorithmSHA384;
6092 break;
6093 }
6094 if (DEROidCompare(algOid, &oidSha256Ecdsa) ||
6095 DEROidCompare(algOid, &oidSha256Rsa) ||
6096 DEROidCompare(algOid, &oidSha256)) {
6097 result = kSecSignatureHashAlgorithmSHA256;
6098 break;
6099 }
6100 if (DEROidCompare(algOid, &oidSha224Ecdsa) ||
6101 DEROidCompare(algOid, &oidSha224Rsa) ||
6102 DEROidCompare(algOid, &oidSha224)) {
6103 result = kSecSignatureHashAlgorithmSHA224;
6104 break;
6105 }
6106 if (DEROidCompare(algOid, &oidSha1Ecdsa) ||
6107 DEROidCompare(algOid, &oidSha1Rsa) ||
6108 DEROidCompare(algOid, &oidSha1Dsa) ||
6109 DEROidCompare(algOid, &oidSha1DsaOIW) ||
6110 DEROidCompare(algOid, &oidSha1DsaCommonOIW) ||
6111 DEROidCompare(algOid, &oidSha1RsaOIW) ||
6112 DEROidCompare(algOid, &oidSha1Fee) ||
6113 DEROidCompare(algOid, &oidSha1)) {
6114 result = kSecSignatureHashAlgorithmSHA1;
6115 break;
6116 }
6117 if (DEROidCompare(algOid, &oidMd5Rsa) ||
6118 DEROidCompare(algOid, &oidMd5Fee) ||
6119 DEROidCompare(algOid, &oidMd5)) {
6120 result = kSecSignatureHashAlgorithmMD5;
6121 break;
6122 }
6123 if (DEROidCompare(algOid, &oidMd4Rsa) ||
6124 DEROidCompare(algOid, &oidMd4)) {
6125 result = kSecSignatureHashAlgorithmMD4;
6126 break;
6127 }
6128 if (DEROidCompare(algOid, &oidMd2Rsa) ||
6129 DEROidCompare(algOid, &oidMd2)) {
6130 result = kSecSignatureHashAlgorithmMD2;
6131 break;
6132 }
6133 break;
6134 }
6135
6136 return result;
6137 }
6138
6139 CFArrayRef SecCertificateCopyiPhoneDeviceCAChain(void) {
6140 CFMutableArrayRef result = NULL;
6141 SecCertificateRef iPhoneDeviceCA = NULL, iPhoneCA = NULL, appleRoot = NULL;
6142
6143 require_quiet(iPhoneDeviceCA = SecCertificateCreateWithBytes(NULL, _AppleiPhoneDeviceCA, sizeof(_AppleiPhoneDeviceCA)),
6144 errOut);
6145 require_quiet(iPhoneCA = SecCertificateCreateWithBytes(NULL, _AppleiPhoneCA, sizeof(_AppleiPhoneCA)),
6146 errOut);
6147 require_quiet(appleRoot = SecCertificateCreateWithBytes(NULL, _AppleRootCA, sizeof(_AppleRootCA)),
6148 errOut);
6149
6150 require_quiet(result = CFArrayCreateMutable(NULL, 3, &kCFTypeArrayCallBacks), errOut);
6151 CFArrayAppendValue(result, iPhoneDeviceCA);
6152 CFArrayAppendValue(result, iPhoneCA);
6153 CFArrayAppendValue(result, appleRoot);
6154
6155 errOut:
6156 CFReleaseNull(iPhoneDeviceCA);
6157 CFReleaseNull(iPhoneCA);
6158 CFReleaseNull(appleRoot);
6159 return result;
6160 }