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