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