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