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