]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCertificate.c
Security-59306.61.1.tar.gz
[apple/security.git] / OSX / sec / Security / SecCertificate.c
1 /*
2 * Copyright (c) 2006-2019 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * SecCertificate.c - CoreFoundation based certificate object
26 */
27
28 #ifdef STANDALONE
29 /* Allows us to build genanchors against the BaseSDK. */
30 #undef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
31 #undef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
32 #endif
33
34 #include <Security/SecCertificateInternal.h>
35 #include <utilities/SecIOFormat.h>
36 #include <CommonCrypto/CommonDigest.h>
37 #include <CoreFoundation/CFRuntime.h>
38 #include <CoreFoundation/CFString.h>
39 #include <CoreFoundation/CFBundle.h>
40 #include <CoreFoundation/CFDictionary.h>
41 #include <CoreFoundation/CFNumber.h>
42 #include <CoreFoundation/CFCalendar.h>
43 #include <CoreFoundation/CFTimeZone.h>
44 #include <CoreFoundation/CFXPCBridge.h>
45 #include <string.h>
46 #include <AssertMacros.h>
47 #include <libDER/DER_CertCrl.h>
48 #include <libDER/DER_Encode.h>
49 #include <libDER/DER_Keys.h>
50 #include <libDER/asn1Types.h>
51 #include <libDER/oids.h>
52 #include <Security/SecBasePriv.h>
53 #include "SecRSAKey.h"
54 #include "SecFramework.h"
55 #include <Security/SecItem.h>
56 #include <Security/SecItemPriv.h>
57 #include "SecSignatureVerificationSupport.h"
58 #include <stdbool.h>
59 #include <utilities/debugging.h>
60 #include <utilities/SecCFWrappers.h>
61 #include <utilities/SecCFError.h>
62 #include <utilities/SecSCTUtils.h>
63 #include <utilities/array_size.h>
64 #include <stdlib.h>
65 #include <libkern/OSByteOrder.h>
66 #include <ctype.h>
67 #include <Security/SecInternal.h>
68 #include <Security/SecFrameworkStrings.h>
69 #include "SecBase64.h"
70 #include "AppleBaselineEscrowCertificates.h"
71 #include "AppleiPhoneDeviceCACertificates.h"
72 #include <ipc/securityd_client.h>
73 #include <Security/SecKeyInternal.h>
74
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 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 /* Some basic checks on the date, allowing leap seconds */
2371 if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 60
2372 || (month == 2 && day > mdays[month] - mdays[month - 1] + is_leap_year)
2373 || (month != 2 && day > mdays[month] - mdays[month - 1])) {
2374 /* Invalid date. */
2375 goto decodeErr;
2376 }
2377
2378 int dy = year - 2001;
2379 if (dy < 0) {
2380 dy += 1;
2381 day -= 1;
2382 }
2383 int leap_days = dy / 4 - dy / 100 + dy / 400;
2384 day += ((year - 2001) * 365 + leap_days) + mdays[month - 1] - 1;
2385 if (month > 2)
2386 day += is_leap_year;
2387
2388 CFAbsoluteTime absTime = (CFAbsoluteTime)((day * 24.0 + hour) * 60.0 + minute) * 60.0 + second;
2389 return absTime - timeZoneOffset;
2390
2391 decodeErr:
2392 if (error) {
2393 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidCertificate, NULL);
2394 }
2395 return NULL_TIME;
2396 }
2397
2398 CFAbsoluteTime SecAbsoluteTimeFromDateContent(DERTag tag, const uint8_t *bytes,
2399 size_t length) {
2400 return SecAbsoluteTimeFromDateContentWithError(tag, bytes, length, NULL);
2401 }
2402
2403 __attribute__((__nonnull__)) static bool derDateContentGetAbsoluteTime(DERTag tag, const DERItem *date,
2404 CFAbsoluteTime *pabsTime) {
2405 CFErrorRef error = NULL;
2406 CFAbsoluteTime absTime = SecAbsoluteTimeFromDateContentWithError(tag, date->data,
2407 date->length, &error);
2408 if (error) {
2409 secwarning("Invalid date specification in certificate (see RFC5280 4.1.2.5)");
2410 CFRelease(error);
2411 return false;
2412 }
2413
2414 *pabsTime = absTime;
2415 return true;
2416 }
2417
2418 /* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return
2419 true if the date was valid and properly decoded, also return the result in
2420 absTime. Return false otherwise. */
2421 __attribute__((__nonnull__)) static bool derDateGetAbsoluteTime(const DERItem *dateChoice,
2422 CFAbsoluteTime *absTime) {
2423 if (dateChoice->length == 0) return false;
2424
2425 DERDecodedInfo decoded;
2426 if (DERDecodeItem(dateChoice, &decoded))
2427 return false;
2428
2429 return derDateContentGetAbsoluteTime(decoded.tag, &decoded.content,
2430 absTime);
2431 }
2432
2433 static void appendDataProperty(CFMutableArrayRef properties,
2434 CFStringRef label, CFStringRef localizedLabel, const DERItem *der_data,
2435 bool localized) {
2436 CFDataRef data = CFDataCreate(CFGetAllocator(properties),
2437 der_data->data, der_data->length);
2438 appendProperty(properties, kSecPropertyTypeData, label, localizedLabel,
2439 data, localized);
2440 CFRelease(data);
2441 }
2442
2443 static void appendRelabeledProperty(CFMutableArrayRef properties,
2444 CFStringRef label,
2445 CFStringRef localizedLabel,
2446 const DERItem *der_data,
2447 CFStringRef labelFormat,
2448 bool localized) {
2449 CFStringRef newLabel =
2450 CFStringCreateWithFormat(CFGetAllocator(properties), NULL,
2451 labelFormat, label);
2452 CFStringRef ll = NULL;
2453 CFStringRef localizedLabelFormat = NULL;
2454 if (!localized) {
2455 /* use provided label and format strings; do not localize */
2456 ll = localizedLabel = (CFStringRef) CFRetainSafe(label);
2457 localizedLabelFormat = (CFStringRef) CFRetainSafe(labelFormat);
2458 } else {
2459 if (!localizedLabel) {
2460 /* copy localized label for provided label */
2461 ll = localizedLabel = SecCopyCertString(label);
2462 }
2463 /* copy localized format for provided format */
2464 localizedLabelFormat = SecCopyCertString(labelFormat);
2465 }
2466
2467 CFStringRef newLocalizedLabel =
2468 CFStringCreateWithFormat(CFGetAllocator(properties), NULL,
2469 localizedLabelFormat, localizedLabel);
2470 CFReleaseSafe(ll);
2471 CFReleaseSafe(localizedLabelFormat);
2472 appendDataProperty(properties, newLabel, newLocalizedLabel, der_data, localized);
2473 CFReleaseSafe(newLabel);
2474 CFReleaseSafe(newLocalizedLabel);
2475 }
2476
2477
2478 static void appendUnparsedProperty(CFMutableArrayRef properties,
2479 CFStringRef label, CFStringRef localizedLabel,
2480 const DERItem *der_data, bool localized) {
2481 appendRelabeledProperty(properties, label, localizedLabel, der_data,
2482 SEC_UNPARSED_KEY, localized);
2483 }
2484
2485 static void appendInvalidProperty(CFMutableArrayRef properties,
2486 CFStringRef label, const DERItem *der_data, bool localized) {
2487 appendRelabeledProperty(properties, label, NULL, der_data,
2488 SEC_INVALID_KEY, localized);
2489 }
2490
2491 static void appendDateContentProperty(CFMutableArrayRef properties,
2492 CFStringRef label, DERTag tag,
2493 const DERItem *dateContent, bool localized) {
2494 CFAbsoluteTime absTime;
2495 if (!derDateContentGetAbsoluteTime(tag, dateContent, &absTime)) {
2496 /* Date decode failure; insert hex bytes instead. */
2497 return appendInvalidProperty(properties, label, dateContent, localized);
2498 }
2499 CFDateRef date = CFDateCreate(CFGetAllocator(properties), absTime);
2500 appendProperty(properties, kSecPropertyTypeDate, label, NULL, date, localized);
2501 CFRelease(date);
2502 }
2503
2504 static void appendDateProperty(CFMutableArrayRef properties,
2505 CFStringRef label, CFAbsoluteTime absTime, bool localized) {
2506 CFDateRef date = CFDateCreate(CFGetAllocator(properties), absTime);
2507 appendProperty(properties, kSecPropertyTypeDate, label, NULL, date, localized);
2508 CFRelease(date);
2509 }
2510
2511 static void appendValidityPeriodProperty(CFMutableArrayRef parent, CFStringRef label,
2512 SecCertificateRef certificate, bool localized) {
2513 CFAllocatorRef allocator = CFGetAllocator(parent);
2514 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2515
2516 appendDateProperty(properties, SEC_NOT_VALID_BEFORE_KEY,
2517 certificate->_notBefore, localized);
2518 appendDateProperty(properties, SEC_NOT_VALID_AFTER_KEY,
2519 certificate->_notAfter, localized);
2520
2521 appendProperty(parent, kSecPropertyTypeSection, label, NULL, properties, localized);
2522 CFReleaseNull(properties);
2523 }
2524
2525 static void appendIPAddressContentProperty(CFMutableArrayRef properties,
2526 CFStringRef label, const DERItem *ip, bool localized) {
2527 CFStringRef value =
2528 copyIPAddressContentDescription(CFGetAllocator(properties), ip);
2529 if (value) {
2530 appendProperty(properties, kSecPropertyTypeString, label, NULL, value, localized);
2531 CFRelease(value);
2532 } else {
2533 appendUnparsedProperty(properties, label, NULL, ip, localized);
2534 }
2535 }
2536
2537 static void appendURLContentProperty(CFMutableArrayRef properties,
2538 CFStringRef label, const DERItem *urlContent, bool localized) {
2539 CFURLRef url = CFURLCreateWithBytes(CFGetAllocator(properties),
2540 urlContent->data, urlContent->length, kCFStringEncodingASCII, NULL);
2541 if (url) {
2542 appendProperty(properties, kSecPropertyTypeURL, label, NULL, url, localized);
2543 CFRelease(url);
2544 } else {
2545 appendInvalidProperty(properties, label, urlContent, localized);
2546 }
2547 }
2548
2549 static void appendURLProperty(CFMutableArrayRef properties,
2550 CFStringRef label, const DERItem *url, bool localized) {
2551 DERDecodedInfo decoded;
2552 DERReturn drtn;
2553
2554 drtn = DERDecodeItem(url, &decoded);
2555 if (drtn || decoded.tag != ASN1_IA5_STRING) {
2556 appendInvalidProperty(properties, label, url, localized);
2557 } else {
2558 appendURLContentProperty(properties, label, &decoded.content, localized);
2559 }
2560 }
2561
2562 static void appendOIDProperty(CFMutableArrayRef properties,
2563 CFStringRef label, CFStringRef llabel, const DERItem *oid, bool localized) {
2564 CFStringRef oid_string =
2565 copyOidDescription(CFGetAllocator(properties), oid, localized);
2566 appendProperty(properties, kSecPropertyTypeString, label, llabel,
2567 oid_string, localized);
2568 CFRelease(oid_string);
2569 }
2570
2571 static void appendAlgorithmProperty(CFMutableArrayRef properties,
2572 CFStringRef label, const DERAlgorithmId *algorithm, bool localized) {
2573 CFMutableArrayRef alg_props =
2574 CFArrayCreateMutable(CFGetAllocator(properties), 0,
2575 &kCFTypeArrayCallBacks);
2576 appendOIDProperty(alg_props, SEC_ALGORITHM_KEY, NULL,
2577 &algorithm->oid, localized);
2578 if (algorithm->params.length) {
2579 if (algorithm->params.length == 2 &&
2580 algorithm->params.data[0] == ASN1_NULL &&
2581 algorithm->params.data[1] == 0) {
2582 CFStringRef value = SecCopyCertString(SEC_NONE_KEY);
2583 appendProperty(alg_props, kSecPropertyTypeString,
2584 SEC_PARAMETERS_KEY, NULL, value, localized);
2585 CFRelease(value);
2586 } else {
2587 appendUnparsedProperty(alg_props, SEC_PARAMETERS_KEY, NULL,
2588 &algorithm->params, localized);
2589 }
2590 }
2591 appendProperty(properties, kSecPropertyTypeSection, label, NULL,
2592 alg_props, localized);
2593 CFRelease(alg_props);
2594 }
2595
2596 static void appendPublicKeyProperty(CFMutableArrayRef parent, CFStringRef label,
2597 SecCertificateRef certificate, bool localized) {
2598 CFAllocatorRef allocator = CFGetAllocator(parent);
2599 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2600
2601 /* Public key algorithm. */
2602 appendAlgorithmProperty(properties, SEC_PUBLIC_KEY_ALG_KEY,
2603 &certificate->_algId, localized);
2604
2605 /* Public Key Size */
2606 SecKeyRef publicKey = SecCertificateCopyKey(certificate);
2607 if (publicKey) {
2608 size_t sizeInBytes = SecKeyGetBlockSize(publicKey);
2609 CFStringRef sizeInBitsString = CFStringCreateWithFormat(allocator, NULL,
2610 CFSTR("%ld"), (sizeInBytes*8));
2611 if (sizeInBitsString) {
2612 appendProperty(properties, kSecPropertyTypeString, SEC_PUBLIC_KEY_SIZE_KEY,
2613 NULL, sizeInBitsString, localized);
2614 }
2615 CFReleaseNull(sizeInBitsString);
2616 }
2617 CFReleaseNull(publicKey);
2618
2619 /* Consider breaking down an RSA public key into modulus and
2620 exponent? */
2621 appendDataProperty(properties, SEC_PUBLIC_KEY_DATA_KEY, NULL,
2622 &certificate->_pubKeyDER, localized);
2623
2624 appendProperty(parent, kSecPropertyTypeSection, label, NULL,
2625 properties, localized);
2626 CFReleaseNull(properties);
2627 }
2628
2629 static void appendSignatureProperty(CFMutableArrayRef parent, CFStringRef label,
2630 SecCertificateRef certificate, bool localized) {
2631 CFAllocatorRef allocator = CFGetAllocator(parent);
2632 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2633
2634 appendAlgorithmProperty(properties, SEC_SIGNATURE_ALGORITHM_KEY,
2635 &certificate->_tbsSigAlg, localized);
2636
2637 appendDataProperty(properties, SEC_SIGNATURE_DATA_KEY, NULL,
2638 &certificate->_signature, localized);
2639
2640 appendProperty(parent, kSecPropertyTypeSection, label, NULL,
2641 properties, localized);
2642 CFReleaseNull(properties);
2643 }
2644
2645 static void appendFingerprintsProperty(CFMutableArrayRef parent, CFStringRef label,
2646 SecCertificateRef certificate, bool localized) {
2647 CFAllocatorRef allocator = CFGetAllocator(parent);
2648 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2649
2650 CFDataRef sha256Fingerprint = SecCertificateCopySHA256Digest(certificate);
2651 if (sha256Fingerprint) {
2652 appendProperty(properties, kSecPropertyTypeData, SEC_SHA2_FINGERPRINT_KEY,
2653 NULL, sha256Fingerprint, localized);
2654 }
2655 CFReleaseNull(sha256Fingerprint);
2656
2657 appendProperty(properties, kSecPropertyTypeData, SEC_SHA1_FINGERPRINT_KEY,
2658 NULL, SecCertificateGetSHA1Digest(certificate), localized);
2659
2660 appendProperty(parent, kSecPropertyTypeSection, label, NULL,
2661 properties, localized);
2662 CFReleaseNull(properties);
2663 }
2664
2665 static CFStringRef copyHexDescription(CFAllocatorRef allocator,
2666 const DERItem *blob) {
2667 CFIndex ix, length = blob->length /* < 24 ? blob->length : 24 */;
2668 CFMutableStringRef string = CFStringCreateMutable(allocator,
2669 blob->length * 3 - 1);
2670 for (ix = 0; ix < length; ++ix)
2671 if (ix == 0)
2672 CFStringAppendFormat(string, NULL, CFSTR("%02X"), blob->data[ix]);
2673 else
2674 CFStringAppendFormat(string, NULL, CFSTR(" %02X"), blob->data[ix]);
2675
2676 return string;
2677 }
2678
2679 static CFStringRef copyBlobString(CFAllocatorRef allocator,
2680 CFStringRef blobType, CFStringRef quanta,
2681 const DERItem *blob, bool localized) {
2682 CFStringRef localizedBlobType = (localized) ?
2683 SecCopyCertString(blobType) : (CFStringRef) CFRetainSafe(blobType);
2684 CFStringRef localizedQuanta = (localized) ?
2685 SecCopyCertString(quanta) : (CFStringRef) CFRetainSafe(quanta);
2686 /* "format string for encoded field data (e.g. Sequence; 128 bytes; "
2687 "data = 00 00 ...)" */
2688 CFStringRef blobFormat = (localized) ?
2689 SecCopyCertString(SEC_BLOB_KEY) : SEC_BLOB_KEY;
2690 CFStringRef hex = copyHexDescription(allocator, blob);
2691 CFStringRef result = CFStringCreateWithFormat(allocator, NULL,
2692 blobFormat, localizedBlobType, blob->length, localizedQuanta, hex);
2693 CFRelease(hex);
2694 CFRelease(blobFormat);
2695 CFReleaseSafe(localizedQuanta);
2696 CFReleaseSafe(localizedBlobType);
2697
2698 return result;
2699 }
2700
2701 /* Return a string verbatim (unlocalized) from a DER field. */
2702 static CFStringRef copyContentString(CFAllocatorRef allocator,
2703 const DERItem *string, CFStringEncoding encoding,
2704 bool printableOnly) {
2705 /* Strip potential bogus trailing zero from printable strings. */
2706 DERSize length = string->length;
2707 if (length && string->data[length - 1] == 0) {
2708 /* Don't mess with the length of UTF16 strings though. */
2709 if (encoding != kCFStringEncodingUTF16)
2710 length--;
2711 }
2712 /* A zero length string isn't considered printable. */
2713 if (!length && printableOnly)
2714 return NULL;
2715
2716 /* Passing true for the 5th paramater to CFStringCreateWithBytes() makes
2717 it treat kCFStringEncodingUTF16 as big endian by default, whereas
2718 passing false makes it treat it as native endian by default. */
2719 CFStringRef result = CFStringCreateWithBytes(allocator, string->data,
2720 length, encoding, encoding == kCFStringEncodingUTF16);
2721 if (result)
2722 return result;
2723
2724 return printableOnly ? NULL : copyHexDescription(allocator, string);
2725 }
2726
2727 /* From rfc3280 - Appendix B. ASN.1 Notes
2728
2729 CAs MUST force the serialNumber to be a non-negative integer, that
2730 is, the sign bit in the DER encoding of the INTEGER value MUST be
2731 zero - this can be done by adding a leading (leftmost) `00'H octet if
2732 necessary. This removes a potential ambiguity in mapping between a
2733 string of octets and an integer value.
2734
2735 As noted in section 4.1.2.2, serial numbers can be expected to
2736 contain long integers. Certificate users MUST be able to handle
2737 serialNumber values up to 20 octets in length. Conformant CAs MUST
2738 NOT use serialNumber values longer than 20 octets.
2739 */
2740
2741 /* Return the given numeric data as a string: decimal up to 64 bits,
2742 hex otherwise.
2743 */
2744 static CFStringRef copyIntegerContentDescription(CFAllocatorRef allocator,
2745 const DERItem *integer) {
2746 uint64_t value = 0;
2747 CFIndex ix, length = integer->length;
2748
2749 if (length == 0 || length > 8)
2750 return copyHexDescription(allocator, integer);
2751
2752 for(ix = 0; ix < length; ++ix) {
2753 value <<= 8;
2754 value += integer->data[ix];
2755 }
2756
2757 return CFStringCreateWithFormat(allocator, NULL, CFSTR("%llu"), value);
2758 }
2759
2760 static CFStringRef copyDERThingContentDescription(CFAllocatorRef allocator,
2761 DERTag tag, const DERItem *derThing, bool printableOnly, bool localized) {
2762 if (!derThing) { return NULL; }
2763 switch(tag) {
2764 case ASN1_INTEGER:
2765 case ASN1_BOOLEAN:
2766 return printableOnly ? NULL : copyIntegerContentDescription(allocator, derThing);
2767 case ASN1_PRINTABLE_STRING:
2768 case ASN1_IA5_STRING:
2769 return copyContentString(allocator, derThing, kCFStringEncodingASCII, printableOnly);
2770 case ASN1_UTF8_STRING:
2771 case ASN1_GENERAL_STRING:
2772 case ASN1_UNIVERSAL_STRING:
2773 return copyContentString(allocator, derThing, kCFStringEncodingUTF8, printableOnly);
2774 case ASN1_T61_STRING: // 20, also BER_TAG_TELETEX_STRING
2775 case ASN1_VIDEOTEX_STRING: // 21
2776 case ASN1_VISIBLE_STRING: // 26
2777 return copyContentString(allocator, derThing, kCFStringEncodingISOLatin1, printableOnly);
2778 case ASN1_BMP_STRING: // 30
2779 return copyContentString(allocator, derThing, kCFStringEncodingUTF16, printableOnly);
2780 case ASN1_OCTET_STRING:
2781 return printableOnly ? NULL :
2782 copyBlobString(allocator, SEC_BYTE_STRING_KEY, SEC_BYTES_KEY,
2783 derThing, localized);
2784 case ASN1_BIT_STRING:
2785 return printableOnly ? NULL :
2786 copyBlobString(allocator, SEC_BIT_STRING_KEY, SEC_BITS_KEY,
2787 derThing, localized);
2788 case ASN1_CONSTR_SEQUENCE:
2789 return printableOnly ? NULL :
2790 copyBlobString(allocator, SEC_SEQUENCE_KEY, SEC_BYTES_KEY,
2791 derThing, localized);
2792 case ASN1_CONSTR_SET:
2793 return printableOnly ? NULL :
2794 copyBlobString(allocator, SEC_SET_KEY, SEC_BYTES_KEY,
2795 derThing, localized);
2796 case ASN1_OBJECT_ID:
2797 return printableOnly ? NULL : copyOidDescription(allocator, derThing, localized);
2798 default:
2799 if (printableOnly) {
2800 return NULL;
2801 } else {
2802 CFStringRef fmt = (localized) ?
2803 SecCopyCertString(SEC_NOT_DISPLAYED_KEY) : SEC_NOT_DISPLAYED_KEY;
2804 if (!fmt) { return NULL; }
2805 CFStringRef result = CFStringCreateWithFormat(allocator, NULL, fmt,
2806 (unsigned long)tag, (unsigned long)derThing->length);
2807 CFRelease(fmt);
2808 return result;
2809 }
2810 }
2811 }
2812
2813 static CFStringRef copyDERThingDescription(CFAllocatorRef allocator,
2814 const DERItem *derThing, bool printableOnly, bool localized) {
2815 DERDecodedInfo decoded;
2816 DERReturn drtn;
2817
2818 drtn = DERDecodeItem(derThing, &decoded);
2819 if (drtn) {
2820 /* TODO: Perhaps put something in the label saying we couldn't parse
2821 the DER? */
2822 return printableOnly ? NULL : copyHexDescription(allocator, derThing);
2823 } else {
2824 return copyDERThingContentDescription(allocator, decoded.tag,
2825 &decoded.content, false, localized);
2826 }
2827 }
2828
2829 static void appendDERThingProperty(CFMutableArrayRef properties,
2830 CFStringRef label, CFStringRef localizedLabel,
2831 const DERItem *derThing, bool localized) {
2832 CFStringRef value = copyDERThingDescription(CFGetAllocator(properties),
2833 derThing, false, localized);
2834 if (value) {
2835 appendProperty(properties, kSecPropertyTypeString, label, localizedLabel,
2836 value, localized);
2837 }
2838 CFReleaseSafe(value);
2839 }
2840
2841 static OSStatus appendRDNProperty(void *context, const DERItem *rdnType,
2842 const DERItem *rdnValue, CFIndex rdnIX,
2843 bool localized) {
2844 CFMutableArrayRef properties = (CFMutableArrayRef)context;
2845 if (rdnIX > 0) {
2846 /* If there is more than one value pair we create a subsection for the
2847 second pair, and append things to the subsection for subsequent
2848 pairs. */
2849 CFIndex lastIX = CFArrayGetCount(properties) - 1;
2850 CFTypeRef lastValue = CFArrayGetValueAtIndex(properties, lastIX);
2851 if (rdnIX == 1) {
2852 /* Since this is the second rdn pair for a given rdn, we setup a
2853 new subsection for this rdn. We remove the first property
2854 from the properties array and make it the first element in the
2855 subsection instead. */
2856 CFMutableArrayRef rdn_props = CFArrayCreateMutable(
2857 CFGetAllocator(properties), 0, &kCFTypeArrayCallBacks);
2858 CFArrayAppendValue(rdn_props, lastValue);
2859 CFArrayRemoveValueAtIndex(properties, lastIX);
2860 appendProperty(properties, kSecPropertyTypeSection, NULL, NULL,
2861 rdn_props, localized);
2862 properties = rdn_props;
2863 // rdn_props is now retained by the original properties array
2864 CFReleaseSafe(rdn_props);
2865 } else {
2866 /* Since this is the third or later rdn pair we have already
2867 created a subsection in the top level properties array. Instead
2868 of appending to that directly we append to the array inside the
2869 subsection. */
2870 properties = (CFMutableArrayRef)CFDictionaryGetValue(
2871 (CFDictionaryRef)lastValue, kSecPropertyKeyValue);
2872 }
2873 }
2874
2875 /* Finally we append the new rdn value to the property array. */
2876 CFStringRef label =
2877 SecDERItemCopyOIDDecimalRepresentation(CFGetAllocator(properties),
2878 rdnType);
2879 CFStringRef localizedLabel = copyOidDescription(CFGetAllocator(properties),
2880 rdnType, localized);
2881 appendDERThingProperty(properties, label, localizedLabel,
2882 rdnValue, localized);
2883 CFReleaseSafe(label);
2884 CFReleaseSafe(localizedLabel);
2885 return errSecSuccess;
2886 }
2887
2888 static CFArrayRef createPropertiesForRDNContent(CFAllocatorRef allocator,
2889 const DERItem *rdnSetContent, bool localized) {
2890 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
2891 &kCFTypeArrayCallBacks);
2892 OSStatus status = parseRDNContent(rdnSetContent, properties,
2893 appendRDNProperty, localized);
2894 if (status) {
2895 CFArrayRemoveAllValues(properties);
2896 appendInvalidProperty(properties, SEC_RDN_KEY, rdnSetContent,
2897 localized);
2898 }
2899
2900 return properties;
2901 }
2902
2903 /*
2904 From rfc3739 - 3.1.2. Subject
2905
2906 When parsing the subject here are some tips for a short name of the cert.
2907 Choice I: commonName
2908 Choice II: givenName
2909 Choice III: pseudonym
2910
2911 The commonName attribute value SHALL, when present, contain a name
2912 of the subject. This MAY be in the subject's preferred
2913 presentation format, or a format preferred by the CA, or some
2914 other format. Pseudonyms, nicknames, and names with spelling
2915 other than defined by the registered name MAY be used. To
2916 understand the nature of the name presented in commonName,
2917 complying applications MAY have to examine present values of the
2918 givenName and surname attributes, or the pseudonym attribute.
2919
2920 */
2921 static CFArrayRef createPropertiesForX501NameContent(CFAllocatorRef allocator,
2922 const DERItem *x501NameContent, bool localized) {
2923 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
2924 &kCFTypeArrayCallBacks);
2925 OSStatus status = parseX501NameContent(x501NameContent, properties,
2926 appendRDNProperty, localized);
2927 if (status) {
2928 CFArrayRemoveAllValues(properties);
2929 appendInvalidProperty(properties, SEC_X501_NAME_KEY,
2930 x501NameContent, localized);
2931 }
2932
2933 return properties;
2934 }
2935
2936 static CFArrayRef createPropertiesForX501Name(CFAllocatorRef allocator,
2937 const DERItem *x501Name, bool localized) {
2938 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
2939 &kCFTypeArrayCallBacks);
2940 OSStatus status = parseX501Name(x501Name, properties, appendRDNProperty, localized);
2941 if (status) {
2942 CFArrayRemoveAllValues(properties);
2943 appendInvalidProperty(properties, SEC_X501_NAME_KEY,
2944 x501Name, localized);
2945 }
2946
2947 return properties;
2948 }
2949
2950 static void appendIntegerProperty(CFMutableArrayRef properties,
2951 CFStringRef label, const DERItem *integer, bool localized) {
2952 CFStringRef string = copyIntegerContentDescription(
2953 CFGetAllocator(properties), integer);
2954 appendProperty(properties, kSecPropertyTypeString, label, NULL,
2955 string, localized);
2956 CFRelease(string);
2957 }
2958
2959 static void appendBoolProperty(CFMutableArrayRef properties,
2960 CFStringRef label, bool boolean, bool localized) {
2961 CFStringRef key = (boolean) ? SEC_YES_KEY : SEC_NO_KEY;
2962 CFStringRef value = (localized) ? SecCopyCertString(key) : key;
2963 appendProperty(properties, kSecPropertyTypeString, label, NULL,
2964 value, localized);
2965 CFRelease(value);
2966 }
2967
2968 static void appendBooleanProperty(CFMutableArrayRef properties,
2969 CFStringRef label, const DERItem *boolean,
2970 bool defaultValue, bool localized) {
2971 bool result;
2972 DERReturn drtn = DERParseBooleanWithDefault(boolean, defaultValue, &result);
2973 if (drtn) {
2974 /* Couldn't parse boolean; dump the raw unparsed data as hex. */
2975 appendInvalidProperty(properties, label, boolean, localized);
2976 } else {
2977 appendBoolProperty(properties, label, result, localized);
2978 }
2979 }
2980
2981 static void appendSerialNumberProperty(CFMutableArrayRef parent, CFStringRef label,
2982 DERItem *serialNum, bool localized) {
2983 CFAllocatorRef allocator = CFGetAllocator(parent);
2984 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
2985
2986 if (serialNum->length) {
2987 appendIntegerProperty(properties, SEC_SERIAL_NUMBER_KEY,
2988 serialNum, localized);
2989 appendProperty(parent, kSecPropertyTypeSection, label, NULL,
2990 properties, localized);
2991 }
2992
2993 CFReleaseNull(properties);
2994 }
2995
2996 static void appendBitStringContentNames(CFMutableArrayRef properties,
2997 CFStringRef label, const DERItem *bitStringContent,
2998 const CFStringRef *names, CFIndex namesCount,
2999 bool localized) {
3000 DERSize len = bitStringContent->length - 1;
3001 require_quiet(len == 1 || len == 2, badDER);
3002 DERByte numUnusedBits = bitStringContent->data[0];
3003 require_quiet(numUnusedBits < 8, badDER);
3004 uint_fast16_t bits = 8 * len - numUnusedBits;
3005 require_quiet(bits <= (uint_fast16_t)namesCount, badDER);
3006 uint_fast16_t value = bitStringContent->data[1];
3007 uint_fast16_t mask;
3008 if (len > 1) {
3009 value = (value << 8) + bitStringContent->data[2];
3010 mask = 0x8000;
3011 } else {
3012 mask = 0x80;
3013 }
3014 uint_fast16_t ix;
3015 CFStringRef fmt = (localized) ?
3016 SecCopyCertString(SEC_STRING_LIST_KEY) : SEC_STRING_LIST_KEY;
3017 CFStringRef string = NULL;
3018 for (ix = 0; ix < bits; ++ix) {
3019 CFStringRef localizedName = (localized) ? SecCopyCertString(names[ix]) : CFRetainSafe(names[ix]);
3020 if (value & mask) {
3021 if (string) {
3022 CFStringRef s =
3023 CFStringCreateWithFormat(CFGetAllocator(properties),
3024 NULL, fmt, string, localizedName);
3025 CFRelease(string);
3026 string = s;
3027 } else {
3028 string = localizedName;
3029 CFRetain(string);
3030 }
3031 }
3032 mask >>= 1;
3033 CFReleaseNull(localizedName);
3034 }
3035 CFRelease(fmt);
3036 appendProperty(properties, kSecPropertyTypeString, label, NULL,
3037 string ? string : CFSTR(""), localized);
3038 CFReleaseSafe(string);
3039 return;
3040 badDER:
3041 appendInvalidProperty(properties, label, bitStringContent, localized);
3042 }
3043
3044 static void appendBitStringNames(CFMutableArrayRef properties,
3045 CFStringRef label, const DERItem *bitString,
3046 const CFStringRef *names, CFIndex namesCount,
3047 bool localized) {
3048 DERDecodedInfo bitStringContent;
3049 DERReturn drtn = DERDecodeItem(bitString, &bitStringContent);
3050 require_noerr_quiet(drtn, badDER);
3051 require_quiet(bitStringContent.tag == ASN1_BIT_STRING, badDER);
3052 appendBitStringContentNames(properties, label, &bitStringContent.content,
3053 names, namesCount, localized);
3054 return;
3055 badDER:
3056 appendInvalidProperty(properties, label, bitString, localized);
3057 }
3058
3059 static void appendKeyUsage(CFMutableArrayRef properties,
3060 const DERItem *extnValue, bool localized) {
3061 static const CFStringRef usageNames[] = {
3062 SEC_DIGITAL_SIGNATURE_KEY,
3063 SEC_NON_REPUDIATION_KEY,
3064 SEC_KEY_ENCIPHERMENT_KEY,
3065 SEC_DATA_ENCIPHERMENT_KEY,
3066 SEC_KEY_AGREEMENT_KEY,
3067 SEC_CERT_SIGN_KEY,
3068 SEC_CRL_SIGN_KEY,
3069 SEC_ENCIPHER_ONLY_KEY,
3070 SEC_DECIPHER_ONLY_KEY
3071 };
3072 appendBitStringNames(properties, SEC_USAGE_KEY, extnValue,
3073 usageNames, array_size(usageNames), localized);
3074 }
3075
3076 static void appendPrivateKeyUsagePeriod(CFMutableArrayRef properties,
3077 const DERItem *extnValue, bool localized) {
3078 DERPrivateKeyUsagePeriod pkup;
3079 DERReturn drtn = DERParseSequence(extnValue,
3080 DERNumPrivateKeyUsagePeriodItemSpecs, DERPrivateKeyUsagePeriodItemSpecs,
3081 &pkup, sizeof(pkup));
3082 require_noerr_quiet(drtn, badDER);
3083 if (pkup.notBefore.length) {
3084 appendDateContentProperty(properties, SEC_NOT_VALID_BEFORE_KEY,
3085 ASN1_GENERALIZED_TIME, &pkup.notBefore, localized);
3086 }
3087 if (pkup.notAfter.length) {
3088 appendDateContentProperty(properties, SEC_NOT_VALID_AFTER_KEY,
3089 ASN1_GENERALIZED_TIME, &pkup.notAfter, localized);
3090 }
3091 return;
3092 badDER:
3093 appendInvalidProperty(properties, SEC_PRIVATE_KU_PERIOD_KEY,
3094 extnValue, localized);
3095 }
3096
3097 static void appendStringContentProperty(CFMutableArrayRef properties,
3098 CFStringRef label, const DERItem *stringContent,
3099 CFStringEncoding encoding, bool localized) {
3100 CFStringRef string = CFStringCreateWithBytes(CFGetAllocator(properties),
3101 stringContent->data, stringContent->length, encoding, FALSE);
3102 if (string) {
3103 appendProperty(properties, kSecPropertyTypeString, label, NULL,
3104 string, localized);
3105 CFRelease(string);
3106 } else {
3107 appendInvalidProperty(properties, label, stringContent, localized);
3108 }
3109 }
3110
3111 /*
3112 OtherName ::= SEQUENCE {
3113 type-id OBJECT IDENTIFIER,
3114 value [0] EXPLICIT ANY DEFINED BY type-id }
3115 */
3116 static void appendOtherNameContentProperty(CFMutableArrayRef properties,
3117 const DERItem *otherNameContent, bool localized) {
3118 DEROtherName on;
3119 DERReturn drtn = DERParseSequenceContent(otherNameContent,
3120 DERNumOtherNameItemSpecs, DEROtherNameItemSpecs,
3121 &on, sizeof(on));
3122 require_noerr_quiet(drtn, badDER);
3123 CFAllocatorRef allocator = CFGetAllocator(properties);
3124 CFStringRef label =
3125 SecDERItemCopyOIDDecimalRepresentation(allocator, &on.typeIdentifier);
3126 CFStringRef localizedLabel =
3127 copyOidDescription(allocator, &on.typeIdentifier, localized);
3128 CFStringRef value_string = copyDERThingDescription(allocator, &on.value,
3129 false, localized);
3130 if (value_string) {
3131 appendProperty(properties, kSecPropertyTypeString, label,
3132 localizedLabel, value_string, localized);
3133 } else {
3134 appendUnparsedProperty(properties, label, localizedLabel,
3135 &on.value, localized);
3136 }
3137 CFReleaseSafe(value_string);
3138 CFReleaseSafe(label);
3139 CFReleaseSafe(localizedLabel);
3140 return;
3141 badDER:
3142 appendInvalidProperty(properties, SEC_OTHER_NAME_KEY,
3143 otherNameContent, localized);
3144 }
3145
3146 /*
3147 GeneralName ::= CHOICE {
3148 otherName [0] OtherName,
3149 rfc822Name [1] IA5String,
3150 dNSName [2] IA5String,
3151 x400Address [3] ORAddress,
3152 directoryName [4] Name,
3153 ediPartyName [5] EDIPartyName,
3154 uniformResourceIdentifier [6] IA5String,
3155 iPAddress [7] OCTET STRING,
3156 registeredID [8] OBJECT IDENTIFIER}
3157
3158 EDIPartyName ::= SEQUENCE {
3159 nameAssigner [0] DirectoryString OPTIONAL,
3160 partyName [1] DirectoryString }
3161 */
3162 static bool appendGeneralNameContentProperty(CFMutableArrayRef properties,
3163 DERTag tag, const DERItem *generalName, bool localized) {
3164 switch (tag) {
3165 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0:
3166 appendOtherNameContentProperty(properties, generalName, localized);
3167 break;
3168 case ASN1_CONTEXT_SPECIFIC | 1:
3169 /* IA5String. */
3170 appendStringContentProperty(properties, SEC_EMAIL_ADDRESS_KEY,
3171 generalName, kCFStringEncodingASCII, localized);
3172 break;
3173 case ASN1_CONTEXT_SPECIFIC | 2:
3174 /* IA5String. */
3175 appendStringContentProperty(properties, SEC_DNS_NAME_KEY, generalName,
3176 kCFStringEncodingASCII, localized);
3177 break;
3178 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3:
3179 appendUnparsedProperty(properties, SEC_X400_ADDRESS_KEY, NULL,
3180 generalName, localized);
3181 break;
3182 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4:
3183 {
3184 CFArrayRef directory_plist =
3185 createPropertiesForX501Name(CFGetAllocator(properties),
3186 generalName, localized);
3187 appendProperty(properties, kSecPropertyTypeSection,
3188 SEC_DIRECTORY_NAME_KEY, NULL, directory_plist, localized);
3189 CFRelease(directory_plist);
3190 break;
3191 }
3192 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5:
3193 appendUnparsedProperty(properties, SEC_EDI_PARTY_NAME_KEY, NULL,
3194 generalName, localized);
3195 break;
3196 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6:
3197 /* Technically I don't think this is valid, but there are certs out
3198 in the wild that use a constructed IA5String. In particular the
3199 VeriSign Time Stamping Authority CA.cer does this. */
3200 appendURLProperty(properties, SEC_URI_KEY, generalName, localized);
3201 break;
3202 case ASN1_CONTEXT_SPECIFIC | 6:
3203 appendURLContentProperty(properties, SEC_URI_KEY, generalName, localized);
3204 break;
3205 case ASN1_CONTEXT_SPECIFIC | 7:
3206 appendIPAddressContentProperty(properties, SEC_IP_ADDRESS_KEY,
3207 generalName, localized);
3208 break;
3209 case ASN1_CONTEXT_SPECIFIC | 8:
3210 appendOIDProperty(properties, SEC_REGISTERED_ID_KEY, NULL,
3211 generalName, localized);
3212 break;
3213 default:
3214 goto badDER;
3215 break;
3216 }
3217 return true;
3218 badDER:
3219 return false;
3220 }
3221
3222 static void appendGeneralNameProperty(CFMutableArrayRef properties,
3223 const DERItem *generalName, bool localized) {
3224 DERDecodedInfo generalNameContent;
3225 DERReturn drtn = DERDecodeItem(generalName, &generalNameContent);
3226 require_noerr_quiet(drtn, badDER);
3227 if (appendGeneralNameContentProperty(properties, generalNameContent.tag,
3228 &generalNameContent.content, localized))
3229 return;
3230 badDER:
3231 appendInvalidProperty(properties, SEC_GENERAL_NAME_KEY,
3232 generalName, localized);
3233 }
3234
3235
3236 /*
3237 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
3238 */
3239 static void appendGeneralNamesContent(CFMutableArrayRef properties,
3240 const DERItem *generalNamesContent, bool localized) {
3241 DERSequence gnSeq;
3242 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq);
3243 require_noerr_quiet(drtn, badDER);
3244 DERDecodedInfo generalNameContent;
3245 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) ==
3246 DR_Success) {
3247 if (!appendGeneralNameContentProperty(properties,
3248 generalNameContent.tag, &generalNameContent.content, localized)) {
3249 goto badDER;
3250 }
3251 }
3252 require_quiet(drtn == DR_EndOfSequence, badDER);
3253 return;
3254 badDER:
3255 appendInvalidProperty(properties, SEC_GENERAL_NAMES_KEY,
3256 generalNamesContent, localized);
3257 }
3258
3259 static void appendGeneralNames(CFMutableArrayRef properties,
3260 const DERItem *generalNames, bool localized) {
3261 DERDecodedInfo generalNamesContent;
3262 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent);
3263 require_noerr_quiet(drtn, badDER);
3264 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE,
3265 badDER);
3266 appendGeneralNamesContent(properties, &generalNamesContent.content,
3267 localized);
3268 return;
3269 badDER:
3270 appendInvalidProperty(properties, SEC_GENERAL_NAMES_KEY,
3271 generalNames, localized);
3272 }
3273
3274 /*
3275 BasicConstraints ::= SEQUENCE {
3276 cA BOOLEAN DEFAULT FALSE,
3277 pathLenConstraint INTEGER (0..MAX) OPTIONAL }
3278 */
3279 static void appendBasicConstraints(CFMutableArrayRef properties,
3280 const DERItem *extnValue, bool localized) {
3281 DERBasicConstraints basicConstraints;
3282 DERReturn drtn = DERParseSequence(extnValue,
3283 DERNumBasicConstraintsItemSpecs, DERBasicConstraintsItemSpecs,
3284 &basicConstraints, sizeof(basicConstraints));
3285 require_noerr_quiet(drtn, badDER);
3286
3287 appendBooleanProperty(properties, SEC_CERT_AUTHORITY_KEY,
3288 &basicConstraints.cA, false, localized);
3289
3290 if (basicConstraints.pathLenConstraint.length != 0) {
3291 appendIntegerProperty(properties, SEC_PATH_LEN_CONSTRAINT_KEY,
3292 &basicConstraints.pathLenConstraint, localized);
3293 }
3294 return;
3295 badDER:
3296 appendInvalidProperty(properties, SEC_BASIC_CONSTRAINTS_KEY,
3297 extnValue, localized);
3298 }
3299
3300 /*
3301 * id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
3302 *
3303 * NameConstraints ::= SEQUENCE {
3304 * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
3305 * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
3306 *
3307 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
3308 *
3309 * GeneralSubtree ::= SEQUENCE {
3310 * base GeneralName,
3311 * minimum [0] BaseDistance DEFAULT 0,
3312 * maximum [1] BaseDistance OPTIONAL }
3313 *
3314 * BaseDistance ::= INTEGER (0..MAX)
3315 */
3316 static void appendNameConstraints(CFMutableArrayRef properties,
3317 const DERItem *extnValue, bool localized) {
3318 CFAllocatorRef allocator = CFGetAllocator(properties);
3319 DERNameConstraints nc;
3320 DERReturn drtn;
3321 drtn = DERParseSequence(extnValue,
3322 DERNumNameConstraintsItemSpecs,
3323 DERNameConstraintsItemSpecs,
3324 &nc, sizeof(nc));
3325 require_noerr_quiet(drtn, badDER);
3326 if (nc.permittedSubtrees.length) {
3327 DERSequence gsSeq;
3328 require_noerr_quiet(DERDecodeSeqContentInit(&nc.permittedSubtrees, &gsSeq), badDER);
3329 DERDecodedInfo gsContent;
3330 while ((drtn = DERDecodeSeqNext(&gsSeq, &gsContent)) == DR_Success) {
3331 DERGeneralSubtree derGS;
3332 require_quiet(gsContent.tag==ASN1_CONSTR_SEQUENCE, badDER);
3333 drtn = DERParseSequenceContent(&gsContent.content,
3334 DERNumGeneralSubtreeItemSpecs,
3335 DERGeneralSubtreeItemSpecs,
3336 &derGS, sizeof(derGS));
3337 require_noerr_quiet(drtn, badDER);
3338 if (derGS.minimum.length) {
3339 appendIntegerProperty(properties, SEC_PERMITTED_MINIMUM_KEY,
3340 &derGS.minimum, localized);
3341 }
3342 if (derGS.maximum.length) {
3343 appendIntegerProperty(properties, SEC_PERMITTED_MAXIMUM_KEY,
3344 &derGS.maximum, localized);
3345 }
3346 if (derGS.generalName.length) {
3347 CFMutableArrayRef base = CFArrayCreateMutable(allocator, 0,
3348 &kCFTypeArrayCallBacks);
3349 appendProperty(properties, kSecPropertyTypeSection,
3350 SEC_PERMITTED_NAME_KEY, NULL, base, localized);
3351 appendGeneralNameProperty(base, &derGS.generalName, localized);
3352 CFRelease(base);
3353 }
3354 }
3355 require_quiet(drtn == DR_EndOfSequence, badDER);
3356 }
3357 if (nc.excludedSubtrees.length) {
3358 DERSequence gsSeq;
3359 require_noerr_quiet(DERDecodeSeqContentInit(&nc.excludedSubtrees, &gsSeq), badDER);
3360 DERDecodedInfo gsContent;
3361 while ((drtn = DERDecodeSeqNext(&gsSeq, &gsContent)) == DR_Success) {
3362 DERGeneralSubtree derGS;
3363 require_quiet(gsContent.tag==ASN1_CONSTR_SEQUENCE, badDER);
3364 drtn = DERParseSequenceContent(&gsContent.content,
3365 DERNumGeneralSubtreeItemSpecs,
3366 DERGeneralSubtreeItemSpecs,
3367 &derGS, sizeof(derGS));
3368 require_noerr_quiet(drtn, badDER);
3369 if (derGS.minimum.length) {
3370 appendIntegerProperty(properties, SEC_EXCLUDED_MINIMUM_KEY,
3371 &derGS.minimum, localized);
3372 }
3373 if (derGS.maximum.length) {
3374 appendIntegerProperty(properties, SEC_EXCLUDED_MAXIMUM_KEY,
3375 &derGS.maximum, localized);
3376 }
3377 if (derGS.generalName.length) {
3378 CFMutableArrayRef base = CFArrayCreateMutable(allocator, 0,
3379 &kCFTypeArrayCallBacks);
3380 appendProperty(properties, kSecPropertyTypeSection,
3381 SEC_EXCLUDED_NAME_KEY, NULL, base, localized);
3382 appendGeneralNameProperty(base, &derGS.generalName, localized);
3383 CFRelease(base);
3384 }
3385 }
3386 require_quiet(drtn == DR_EndOfSequence, badDER);
3387 }
3388
3389 return;
3390 badDER:
3391 appendInvalidProperty(properties, SEC_NAME_CONSTRAINTS_KEY,
3392 extnValue, localized);
3393 }
3394
3395 /*
3396 CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
3397
3398 DistributionPoint ::= SEQUENCE {
3399 distributionPoint [0] DistributionPointName OPTIONAL,
3400 reasons [1] ReasonFlags OPTIONAL,
3401 cRLIssuer [2] GeneralNames OPTIONAL }
3402
3403 DistributionPointName ::= CHOICE {
3404 fullName [0] GeneralNames,
3405 nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
3406
3407 ReasonFlags ::= BIT STRING {
3408 unused (0),
3409 keyCompromise (1),
3410 cACompromise (2),
3411 affiliationChanged (3),
3412 superseded (4),
3413 cessationOfOperation (5),
3414 certificateHold (6),
3415 privilegeWithdrawn (7),
3416 aACompromise (8) }
3417 */
3418 static void appendCrlDistributionPoints(CFMutableArrayRef properties,
3419 const DERItem *extnValue, bool localized) {
3420 CFAllocatorRef allocator = CFGetAllocator(properties);
3421 DERTag tag;
3422 DERSequence dpSeq;
3423 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &dpSeq);
3424 require_noerr_quiet(drtn, badDER);
3425 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3426 DERDecodedInfo dpSeqContent;
3427 while ((drtn = DERDecodeSeqNext(&dpSeq, &dpSeqContent)) == DR_Success) {
3428 require_quiet(dpSeqContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3429 DERDistributionPoint dp;
3430 drtn = DERParseSequenceContent(&dpSeqContent.content,
3431 DERNumDistributionPointItemSpecs,
3432 DERDistributionPointItemSpecs,
3433 &dp, sizeof(dp));
3434 require_noerr_quiet(drtn, badDER);
3435 if (dp.distributionPoint.length) {
3436 DERDecodedInfo distributionPointName;
3437 drtn = DERDecodeItem(&dp.distributionPoint, &distributionPointName);
3438 require_noerr_quiet(drtn, badDER);
3439 if (distributionPointName.tag ==
3440 (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0)) {
3441 /* Full Name */
3442 appendGeneralNamesContent(properties,
3443 &distributionPointName.content, localized);
3444 } else if (distributionPointName.tag ==
3445 (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1)) {
3446 CFArrayRef rdn_props = createPropertiesForRDNContent(allocator,
3447 &dp.reasons, localized);
3448 appendProperty(properties, kSecPropertyTypeSection,
3449 SEC_NAME_REL_CRL_ISSUER_KEY, NULL, rdn_props, localized);
3450 CFRelease(rdn_props);
3451 } else {
3452 goto badDER;
3453 }
3454 }
3455 if (dp.reasons.length) {
3456 static const CFStringRef reasonNames[] = {
3457 SEC_UNUSED_KEY,
3458 SEC_KEY_COMPROMISE_KEY,
3459 SEC_CA_COMPROMISE_KEY,
3460 SEC_AFFILIATION_CHANGED_KEY,
3461 SEC_SUPERSEDED_KEY,
3462 SEC_CESSATION_OF_OPER_KEY,
3463 SEC_CERTIFICATE_HOLD_KEY,
3464 SEC_PRIV_WITHDRAWN_KEY,
3465 SEC_AA_COMPROMISE_KEY
3466 };
3467 appendBitStringContentNames(properties, SEC_REASONS_KEY,
3468 &dp.reasons,
3469 reasonNames, array_size(reasonNames), localized);
3470 }
3471 if (dp.cRLIssuer.length) {
3472 CFMutableArrayRef crlIssuer = CFArrayCreateMutable(allocator, 0,
3473 &kCFTypeArrayCallBacks);
3474 appendProperty(properties, kSecPropertyTypeSection,
3475 SEC_CRL_ISSUER_KEY, NULL, crlIssuer, localized);
3476 CFRelease(crlIssuer);
3477 appendGeneralNames(crlIssuer, &dp.cRLIssuer, localized);
3478 }
3479 }
3480 require_quiet(drtn == DR_EndOfSequence, badDER);
3481 return;
3482 badDER:
3483 appendInvalidProperty(properties, SEC_CRL_DISTR_POINTS_KEY,
3484 extnValue, localized);
3485 }
3486
3487 /*
3488 Decode a sequence of integers into a comma separated list of ints.
3489 */
3490 static void appendIntegerSequenceContent(CFMutableArrayRef properties,
3491 CFStringRef label, const DERItem *intSequenceContent,
3492 bool localized) {
3493 CFAllocatorRef allocator = CFGetAllocator(properties);
3494 DERSequence intSeq;
3495 CFStringRef fmt = NULL, value = NULL, intDesc = NULL, v = NULL;
3496 DERReturn drtn = DERDecodeSeqContentInit(intSequenceContent, &intSeq);
3497 require_noerr_quiet(drtn, badDER);
3498 DERDecodedInfo intContent;
3499 fmt = (localized) ?
3500 SecCopyCertString(SEC_STRING_LIST_KEY) : SEC_STRING_LIST_KEY;
3501 require_quiet(fmt, badDER);
3502 while ((drtn = DERDecodeSeqNext(&intSeq, &intContent)) == DR_Success) {
3503 require_quiet(intContent.tag == ASN1_INTEGER, badDER);
3504 intDesc = copyIntegerContentDescription(
3505 allocator, &intContent.content);
3506 require_quiet(intDesc, badDER);
3507 if (value) {
3508 v = CFStringCreateWithFormat(allocator, NULL, fmt, value, intDesc);
3509 CFReleaseNull(value);
3510 require_quiet(v, badDER);
3511 value = v;
3512 } else {
3513 value = CFStringCreateMutableCopy(allocator, 0, intDesc);
3514 require_quiet(value, badDER);
3515 }
3516 CFReleaseNull(intDesc);
3517 }
3518 CFReleaseNull(fmt);
3519 require_quiet(drtn == DR_EndOfSequence, badDER);
3520 if (value) {
3521 appendProperty(properties, kSecPropertyTypeString, label, NULL,
3522 value, localized);
3523 CFRelease(value);
3524 return;
3525 }
3526 /* DROPTHOUGH if !value. */
3527 badDER:
3528 CFReleaseNull(fmt);
3529 CFReleaseNull(intDesc);
3530 CFReleaseNull(value);
3531 appendInvalidProperty(properties, label, intSequenceContent, localized);
3532 }
3533
3534 static void appendCertificatePolicies(CFMutableArrayRef properties,
3535 const DERItem *extnValue, bool localized) {
3536 CFAllocatorRef allocator = CFGetAllocator(properties);
3537 CFStringRef piLabel = NULL, piFmt = NULL, lpiLabel = NULL;
3538 CFStringRef pqLabel = NULL, pqFmt = NULL, lpqLabel = NULL;
3539 DERTag tag;
3540 DERSequence piSeq;
3541 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &piSeq);
3542 require_noerr_quiet(drtn, badDER);
3543 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3544 DERDecodedInfo piContent;
3545 int pin = 1;
3546 while ((drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) {
3547 require_quiet(piContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3548 DERPolicyInformation pi;
3549 drtn = DERParseSequenceContent(&piContent.content,
3550 DERNumPolicyInformationItemSpecs,
3551 DERPolicyInformationItemSpecs,
3552 &pi, sizeof(pi));
3553 require_noerr_quiet(drtn, badDER);
3554 piLabel = CFStringCreateWithFormat(allocator, NULL,
3555 SEC_POLICY_IDENTIFIER_KEY, pin);
3556 require_quiet(piLabel, badDER);
3557 piFmt = (localized) ?
3558 SecCopyCertString(SEC_POLICY_IDENTIFIER_KEY) : SEC_POLICY_IDENTIFIER_KEY;
3559 require_quiet(piFmt, badDER);
3560 lpiLabel = CFStringCreateWithFormat(allocator, NULL, piFmt, pin++);
3561 require_quiet(lpiLabel, badDER);
3562 CFReleaseNull(piFmt);
3563 appendOIDProperty(properties, piLabel, lpiLabel,
3564 &pi.policyIdentifier, localized);
3565 CFReleaseNull(piLabel);
3566 CFReleaseNull(lpiLabel);
3567 if (pi.policyQualifiers.length == 0)
3568 continue;
3569
3570 DERSequence pqSeq;
3571 drtn = DERDecodeSeqContentInit(&pi.policyQualifiers, &pqSeq);
3572 require_noerr_quiet(drtn, badDER);
3573 DERDecodedInfo pqContent;
3574 int pqn = 1;
3575 while ((drtn = DERDecodeSeqNext(&pqSeq, &pqContent)) == DR_Success) {
3576 DERPolicyQualifierInfo pqi;
3577 drtn = DERParseSequenceContent(&pqContent.content,
3578 DERNumPolicyQualifierInfoItemSpecs,
3579 DERPolicyQualifierInfoItemSpecs,
3580 &pqi, sizeof(pqi));
3581 require_noerr_quiet(drtn, badDER);
3582 DERDecodedInfo qualifierContent;
3583 drtn = DERDecodeItem(&pqi.qualifier, &qualifierContent);
3584 require_noerr_quiet(drtn, badDER);
3585 pqLabel = CFStringCreateWithFormat(allocator, NULL,
3586 SEC_POLICY_QUALIFIER_KEY, pqn);
3587 require_quiet(pqLabel, badDER);
3588 pqFmt = (localized) ?
3589 SecCopyCertString(SEC_POLICY_QUALIFIER_KEY) : SEC_POLICY_QUALIFIER_KEY;
3590 require_quiet(pqFmt, badDER);
3591 lpqLabel = CFStringCreateWithFormat(allocator, NULL, pqFmt, pqn++);
3592 require_quiet(lpqLabel, badDER);
3593 CFReleaseNull(pqFmt);
3594 appendOIDProperty(properties, pqLabel, lpqLabel,
3595 &pqi.policyQualifierID, localized);
3596 CFReleaseNull(pqLabel);
3597 CFReleaseNull(lpqLabel);
3598 if (DEROidCompare(&oidQtCps, &pqi.policyQualifierID)) {
3599 require_quiet(qualifierContent.tag == ASN1_IA5_STRING, badDER);
3600 appendURLContentProperty(properties, SEC_CPS_URI_KEY,
3601 &qualifierContent.content, localized);
3602 } else if (DEROidCompare(&oidQtUNotice, &pqi.policyQualifierID)) {
3603 require_quiet(qualifierContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3604 DERUserNotice un;
3605 drtn = DERParseSequenceContent(&qualifierContent.content,
3606 DERNumUserNoticeItemSpecs,
3607 DERUserNoticeItemSpecs,
3608 &un, sizeof(un));
3609 require_noerr_quiet(drtn, badDER);
3610 if (un.noticeRef.length) {
3611 DERNoticeReference nr;
3612 drtn = DERParseSequenceContent(&un.noticeRef,
3613 DERNumNoticeReferenceItemSpecs,
3614 DERNoticeReferenceItemSpecs,
3615 &nr, sizeof(nr));
3616 require_noerr_quiet(drtn, badDER);
3617 appendDERThingProperty(properties,
3618 SEC_ORGANIZATION_KEY, NULL,
3619 &nr.organization, localized);
3620 appendIntegerSequenceContent(properties,
3621 SEC_NOTICE_NUMBERS_KEY, &nr.noticeNumbers, localized);
3622 }
3623 if (un.explicitText.length) {
3624 appendDERThingProperty(properties, SEC_EXPLICIT_TEXT_KEY,
3625 NULL, &un.explicitText, localized);
3626 }
3627 } else {
3628 appendUnparsedProperty(properties, SEC_QUALIFIER_KEY, NULL,
3629 &pqi.qualifier, localized);
3630 }
3631 }
3632 require_quiet(drtn == DR_EndOfSequence, badDER);
3633 }
3634 require_quiet(drtn == DR_EndOfSequence, badDER);
3635 return;
3636 badDER:
3637 CFReleaseNull(piFmt);
3638 CFReleaseNull(piLabel);
3639 CFReleaseNull(lpiLabel);
3640 CFReleaseNull(pqFmt);
3641 CFReleaseNull(pqLabel);
3642 CFReleaseNull(lpqLabel);
3643 appendInvalidProperty(properties, SEC_CERT_POLICIES_KEY,
3644 extnValue, localized);
3645 }
3646
3647 static void appendSubjectKeyIdentifier(CFMutableArrayRef properties,
3648 const DERItem *extnValue, bool localized) {
3649 DERReturn drtn;
3650 DERDecodedInfo keyIdentifier;
3651 drtn = DERDecodeItem(extnValue, &keyIdentifier);
3652 require_noerr_quiet(drtn, badDER);
3653 require_quiet(keyIdentifier.tag == ASN1_OCTET_STRING, badDER);
3654 appendDataProperty(properties, SEC_KEY_IDENTIFIER_KEY, NULL,
3655 &keyIdentifier.content, localized);
3656
3657 return;
3658 badDER:
3659 appendInvalidProperty(properties, SEC_SUBJ_KEY_ID_KEY,
3660 extnValue, localized);
3661 }
3662
3663 /*
3664 AuthorityKeyIdentifier ::= SEQUENCE {
3665 keyIdentifier [0] KeyIdentifier OPTIONAL,
3666 authorityCertIssuer [1] GeneralNames OPTIONAL,
3667 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
3668 -- authorityCertIssuer and authorityCertSerialNumber MUST both
3669 -- be present or both be absent
3670
3671 KeyIdentifier ::= OCTET STRING
3672 */
3673 static void appendAuthorityKeyIdentifier(CFMutableArrayRef properties,
3674 const DERItem *extnValue, bool localized) {
3675 DERAuthorityKeyIdentifier akid;
3676 DERReturn drtn;
3677 drtn = DERParseSequence(extnValue,
3678 DERNumAuthorityKeyIdentifierItemSpecs,
3679 DERAuthorityKeyIdentifierItemSpecs,
3680 &akid, sizeof(akid));
3681 require_noerr_quiet(drtn, badDER);
3682 if (akid.keyIdentifier.length) {
3683 appendDataProperty(properties, SEC_KEY_IDENTIFIER_KEY, NULL,
3684 &akid.keyIdentifier, localized);
3685 }
3686 if (akid.authorityCertIssuer.length ||
3687 akid.authorityCertSerialNumber.length) {
3688 require_quiet(akid.authorityCertIssuer.length &&
3689 akid.authorityCertSerialNumber.length, badDER);
3690 /* Perhaps put in a subsection called Authority Certificate Issuer. */
3691 appendGeneralNamesContent(properties,
3692 &akid.authorityCertIssuer, localized);
3693 appendIntegerProperty(properties, SEC_AUTH_CERT_SERIAL_KEY,
3694 &akid.authorityCertSerialNumber, localized);
3695 }
3696
3697 return;
3698 badDER:
3699 appendInvalidProperty(properties, SEC_AUTHORITY_KEY_ID_KEY,
3700 extnValue, localized);
3701 }
3702
3703 /*
3704 PolicyConstraints ::= SEQUENCE {
3705 requireExplicitPolicy [0] SkipCerts OPTIONAL,
3706 inhibitPolicyMapping [1] SkipCerts OPTIONAL }
3707
3708 SkipCerts ::= INTEGER (0..MAX)
3709 */
3710 static void appendPolicyConstraints(CFMutableArrayRef properties,
3711 const DERItem *extnValue, bool localized) {
3712 DERPolicyConstraints pc;
3713 DERReturn drtn;
3714 drtn = DERParseSequence(extnValue,
3715 DERNumPolicyConstraintsItemSpecs,
3716 DERPolicyConstraintsItemSpecs,
3717 &pc, sizeof(pc));
3718 require_noerr_quiet(drtn, badDER);
3719 if (pc.requireExplicitPolicy.length) {
3720 appendIntegerProperty(properties, SEC_REQUIRE_EXPL_POLICY_KEY,
3721 &pc.requireExplicitPolicy, localized);
3722 }
3723 if (pc.inhibitPolicyMapping.length) {
3724 appendIntegerProperty(properties, SEC_INHIBIT_POLICY_MAP_KEY,
3725 &pc.inhibitPolicyMapping, localized);
3726 }
3727
3728 return;
3729
3730 badDER:
3731 appendInvalidProperty(properties, SEC_POLICY_CONSTRAINTS_KEY,
3732 extnValue, localized);
3733 }
3734
3735 /*
3736 extendedKeyUsage EXTENSION ::= {
3737 SYNTAX SEQUENCE SIZE (1..MAX) OF KeyPurposeId
3738 IDENTIFIED BY id-ce-extKeyUsage }
3739
3740 KeyPurposeId ::= OBJECT IDENTIFIER
3741 */
3742 static void appendExtendedKeyUsage(CFMutableArrayRef properties,
3743 const DERItem *extnValue, bool localized) {
3744 DERTag tag;
3745 DERSequence derSeq;
3746 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &derSeq);
3747 require_noerr_quiet(drtn, badDER);
3748 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3749 DERDecodedInfo currDecoded;
3750 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
3751 require_quiet(currDecoded.tag == ASN1_OBJECT_ID, badDER);
3752 appendOIDProperty(properties, SEC_PURPOSE_KEY, NULL,
3753 &currDecoded.content, localized);
3754 }
3755 require_quiet(drtn == DR_EndOfSequence, badDER);
3756 return;
3757 badDER:
3758 appendInvalidProperty(properties, SEC_EXTENDED_KEY_USAGE_KEY,
3759 extnValue, localized);
3760 }
3761
3762 /*
3763 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
3764
3765 AuthorityInfoAccessSyntax ::=
3766 SEQUENCE SIZE (1..MAX) OF AccessDescription
3767
3768 AccessDescription ::= SEQUENCE {
3769 accessMethod OBJECT IDENTIFIER,
3770 accessLocation GeneralName }
3771
3772 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
3773
3774 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
3775
3776 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
3777 */
3778 static void appendInfoAccess(CFMutableArrayRef properties,
3779 const DERItem *extnValue, bool localized) {
3780 DERTag tag;
3781 DERSequence adSeq;
3782 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &adSeq);
3783 require_noerr_quiet(drtn, badDER);
3784 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
3785 DERDecodedInfo adContent;
3786 while ((drtn = DERDecodeSeqNext(&adSeq, &adContent)) == DR_Success) {
3787 require_quiet(adContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
3788 DERAccessDescription ad;
3789 drtn = DERParseSequenceContent(&adContent.content,
3790 DERNumAccessDescriptionItemSpecs,
3791 DERAccessDescriptionItemSpecs,
3792 &ad, sizeof(ad));
3793 require_noerr_quiet(drtn, badDER);
3794 appendOIDProperty(properties, SEC_ACCESS_METHOD_KEY, NULL,
3795 &ad.accessMethod, localized);
3796 //TODO: Do something with SEC_ACCESS_LOCATION_KEY
3797 appendGeneralNameProperty(properties, &ad.accessLocation, localized);
3798 }
3799 require_quiet(drtn == DR_EndOfSequence, badDER);
3800 return;
3801 badDER:
3802 appendInvalidProperty(properties, SEC_AUTH_INFO_ACCESS_KEY,
3803 extnValue, localized);
3804 }
3805
3806 static void appendNetscapeCertType(CFMutableArrayRef properties,
3807 const DERItem *extnValue, bool localized) {
3808 static const CFStringRef certTypes[] = {
3809 SEC_SSL_CLIENT_KEY,
3810 SEC_SSL_SERVER_KEY,
3811 SEC_SMIME_KEY,
3812 SEC_OBJECT_SIGNING_KEY,
3813 SEC_RESERVED_KEY,
3814 SEC_SSL_CA_KEY,
3815 SEC_SMIME_CA_KEY,
3816 SEC_OBJECT_SIGNING_CA_KEY
3817 };
3818 appendBitStringNames(properties, SEC_USAGE_KEY, extnValue,
3819 certTypes, array_size(certTypes), localized);
3820 }
3821
3822 static bool appendPrintableDERSequence(CFMutableArrayRef properties,
3823 CFStringRef label, const DERItem *sequence, bool localized) {
3824 DERTag tag;
3825 DERSequence derSeq;
3826 DERReturn drtn = DERDecodeSeqInit(sequence, &tag, &derSeq);
3827 require_noerr_quiet(drtn, badSequence);
3828 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badSequence);
3829 DERDecodedInfo currDecoded;
3830 bool appendedSomething = false;
3831 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
3832 switch (currDecoded.tag)
3833 {
3834 case 0: // 0
3835 case ASN1_SEQUENCE: // 16
3836 case ASN1_SET: // 17
3837 // skip constructed object lengths
3838 break;
3839
3840 case ASN1_UTF8_STRING: // 12
3841 case ASN1_NUMERIC_STRING: // 18
3842 case ASN1_PRINTABLE_STRING: // 19
3843 case ASN1_T61_STRING: // 20, also ASN1_TELETEX_STRING
3844 case ASN1_VIDEOTEX_STRING: // 21
3845 case ASN1_IA5_STRING: // 22
3846 case ASN1_GRAPHIC_STRING: // 25
3847 case ASN1_VISIBLE_STRING: // 26, also ASN1_ISO646_STRING
3848 case ASN1_GENERAL_STRING: // 27
3849 case ASN1_UNIVERSAL_STRING: // 28
3850 {
3851 CFStringRef string =
3852 copyDERThingContentDescription(CFGetAllocator(properties),
3853 currDecoded.tag, &currDecoded.content, false, localized);
3854 require_quiet(string, badSequence);
3855
3856 appendProperty(properties, kSecPropertyTypeString, label, NULL,
3857 string, localized);
3858 CFReleaseNull(string);
3859 appendedSomething = true;
3860 break;
3861 }
3862 default:
3863 break;
3864 }
3865 }
3866 require_quiet(drtn == DR_EndOfSequence, badSequence);
3867 return appendedSomething;
3868 badSequence:
3869 return false;
3870 }
3871
3872 static void appendExtension(CFMutableArrayRef parent,
3873 const SecCertificateExtension *extn,
3874 bool localized) {
3875 CFAllocatorRef allocator = CFGetAllocator(parent);
3876 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
3877 &kCFTypeArrayCallBacks);
3878 const DERItem
3879 *extnID = &extn->extnID,
3880 *extnValue = &extn->extnValue;
3881 CFStringRef label = NULL;
3882 CFStringRef localizedLabel = NULL;
3883
3884 appendBoolProperty(properties, SEC_CRITICAL_KEY, extn->critical, localized);
3885 require_quiet(extnID, xit);
3886
3887 bool handled = true;
3888 /* Extensions that we know how to handle ourselves... */
3889 if (extnID->length == oidSubjectKeyIdentifier.length &&
3890 !memcmp(extnID->data, oidSubjectKeyIdentifier.data, extnID->length - 1))
3891 {
3892 switch (extnID->data[extnID->length - 1]) {
3893 case 14: /* SubjectKeyIdentifier id-ce 14 */
3894 appendSubjectKeyIdentifier(properties, extnValue, localized);
3895 break;
3896 case 15: /* KeyUsage id-ce 15 */
3897 appendKeyUsage(properties, extnValue, localized);
3898 break;
3899 case 16: /* PrivateKeyUsagePeriod id-ce 16 */
3900 appendPrivateKeyUsagePeriod(properties, extnValue, localized);
3901 break;
3902 case 17: /* SubjectAltName id-ce 17 */
3903 case 18: /* IssuerAltName id-ce 18 */
3904 appendGeneralNames(properties, extnValue, localized);
3905 break;
3906 case 19: /* BasicConstraints id-ce 19 */
3907 appendBasicConstraints(properties, extnValue, localized);
3908 break;
3909 case 30: /* NameConstraints id-ce 30 */
3910 appendNameConstraints(properties, extnValue, localized);
3911 break;
3912 case 31: /* CRLDistributionPoints id-ce 31 */
3913 appendCrlDistributionPoints(properties, extnValue, localized);
3914 break;
3915 case 32: /* CertificatePolicies id-ce 32 */
3916 appendCertificatePolicies(properties, extnValue, localized);
3917 break;
3918 case 33: /* PolicyMappings id-ce 33 */
3919 handled = false;
3920 break;
3921 case 35: /* AuthorityKeyIdentifier id-ce 35 */
3922 appendAuthorityKeyIdentifier(properties, extnValue, localized);
3923 break;
3924 case 36: /* PolicyConstraints id-ce 36 */
3925 appendPolicyConstraints(properties, extnValue, localized);
3926 break;
3927 case 37: /* ExtKeyUsage id-ce 37 */
3928 appendExtendedKeyUsage(properties, extnValue, localized);
3929 break;
3930 case 46: /* FreshestCRL id-ce 46 */
3931 handled = false;
3932 break;
3933 case 54: /* InhibitAnyPolicy id-ce 54 */
3934 handled = false;
3935 break;
3936 default:
3937 handled = false;
3938 break;
3939 }
3940 } else if (extnID->length == oidAuthorityInfoAccess.length &&
3941 !memcmp(extnID->data, oidAuthorityInfoAccess.data, extnID->length - 1))
3942 {
3943 switch (extnID->data[extnID->length - 1]) {
3944 case 1: /* AuthorityInfoAccess id-pe 1 */
3945 appendInfoAccess(properties, extnValue, localized);
3946 break;
3947 case 3: /* QCStatements id-pe 3 */
3948 handled = false;
3949 break;
3950 case 11: /* SubjectInfoAccess id-pe 11 */
3951 appendInfoAccess(properties, extnValue, localized);
3952 break;
3953 default:
3954 handled = false;
3955 break;
3956 }
3957 } else if (DEROidCompare(extnID, &oidNetscapeCertType)) {
3958 /* 2.16.840.1.113730.1.1 netscape 1 1 */
3959 appendNetscapeCertType(properties, extnValue, localized);
3960 } else {
3961 handled = false;
3962 }
3963
3964 if (!handled) {
3965 /* Try to parse and display printable string(s). */
3966 if (appendPrintableDERSequence(properties, SEC_DATA_KEY, extnValue, localized)) {
3967 /* Nothing to do here appendPrintableDERSequence did the work. */
3968 } else {
3969 /* Couldn't parse extension; dump the raw unparsed data as hex. */
3970 appendUnparsedProperty(properties, SEC_DATA_KEY, NULL, extnValue, localized);
3971 }
3972 }
3973 label = SecDERItemCopyOIDDecimalRepresentation(allocator, extnID);
3974 localizedLabel = copyOidDescription(allocator, extnID, localized);
3975 appendProperty(parent, kSecPropertyTypeSection, label, localizedLabel,
3976 properties, localized);
3977 xit:
3978 CFReleaseSafe(localizedLabel);
3979 CFReleaseSafe(label);
3980 CFReleaseSafe(properties);
3981 }
3982
3983 /* Different types of summary types from least desired to most desired. */
3984 enum SummaryType {
3985 kSummaryTypeNone,
3986 kSummaryTypePrintable,
3987 kSummaryTypeOrganizationName,
3988 kSummaryTypeOrganizationalUnitName,
3989 kSummaryTypeCommonName,
3990 };
3991
3992 struct Summary {
3993 enum SummaryType type;
3994 CFStringRef summary;
3995 CFStringRef description;
3996 };
3997
3998 static OSStatus obtainSummaryFromX501Name(void *context,
3999 const DERItem *type, const DERItem *value, CFIndex rdnIX,
4000 bool localized) {
4001 struct Summary *summary = (struct Summary *)context;
4002 enum SummaryType stype = kSummaryTypeNone;
4003 CFStringRef string = NULL;
4004 if (DEROidCompare(type, &oidCommonName)) {
4005 stype = kSummaryTypeCommonName;
4006 } else if (DEROidCompare(type, &oidOrganizationalUnitName)) {
4007 stype = kSummaryTypeOrganizationalUnitName;
4008 } else if (DEROidCompare(type, &oidOrganizationName)) {
4009 stype = kSummaryTypeOrganizationName;
4010 } else if (DEROidCompare(type, &oidDescription)) {
4011 string = copyDERThingDescription(kCFAllocatorDefault, value,
4012 true, localized);
4013 if (string) {
4014 if (summary->description) {
4015 CFStringRef fmt = (localized) ?
4016 SecCopyCertString(SEC_STRING_LIST_KEY) : SEC_STRING_LIST_KEY;
4017 CFStringRef newDescription = CFStringCreateWithFormat(kCFAllocatorDefault,
4018 NULL, fmt, string, summary->description);
4019 CFRelease(fmt);
4020 CFRelease(summary->description);
4021 summary->description = newDescription;
4022 } else {
4023 summary->description = string;
4024 CFRetain(string);
4025 }
4026 stype = kSummaryTypePrintable;
4027 }
4028 } else {
4029 stype = kSummaryTypePrintable;
4030 }
4031
4032 /* Build a string with all instances of the most desired
4033 component type in reverse order encountered comma separated list,
4034 The order of desirability is defined by enum SummaryType. */
4035 if (summary->type <= stype) {
4036 if (!string) {
4037 string = copyDERThingDescription(kCFAllocatorDefault, value,
4038 true, localized);
4039 }
4040 if (string) {
4041 if (summary->type == stype) {
4042 CFStringRef fmt = (localized) ?
4043 SecCopyCertString(SEC_STRING_LIST_KEY) : SEC_STRING_LIST_KEY;
4044 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault,
4045 NULL, fmt, string, summary->summary);
4046 CFRelease(fmt);
4047 CFRelease(string);
4048 string = newSummary;
4049 } else {
4050 summary->type = stype;
4051 }
4052 CFReleaseSafe(summary->summary);
4053 summary->summary = string;
4054 }
4055 } else {
4056 CFReleaseSafe(string);
4057 }
4058
4059 return errSecSuccess;
4060 }
4061
4062 CFStringRef SecCertificateCopySubjectSummary(SecCertificateRef certificate) {
4063 struct Summary summary = {};
4064 OSStatus status = parseX501NameContent(&certificate->_subject, &summary, obtainSummaryFromX501Name, true);
4065 if (status != errSecSuccess) {
4066 return NULL;
4067 }
4068 /* If we found a description and a common name we change the summary to
4069 CommonName (Description). */
4070 if (summary.description) {
4071 if (summary.type == kSummaryTypeCommonName) {
4072 CFStringRef fmt = SecCopyCertString(SEC_COMMON_NAME_DESC_KEY);
4073 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, summary.summary, summary.description);
4074 CFRelease(fmt);
4075 CFRelease(summary.summary);
4076 summary.summary = newSummary;
4077 }
4078 CFRelease(summary.description);
4079 }
4080
4081 if (!summary.summary) {
4082 /* If we didn't find a suitable printable string in the subject at all, we try
4083 the first email address in the certificate instead. */
4084 CFArrayRef names = SecCertificateCopyRFC822Names(certificate);
4085 if (!names) {
4086 /* If we didn't find any email addresses in the certificate, we try finding
4087 a DNS name instead. */
4088 names = SecCertificateCopyDNSNames(certificate);
4089 }
4090 if (names) {
4091 summary.summary = CFArrayGetValueAtIndex(names, 0);
4092 CFRetain(summary.summary);
4093 CFRelease(names);
4094 }
4095 }
4096
4097 return summary.summary;
4098 }
4099
4100 CFStringRef SecCertificateCopyIssuerSummary(SecCertificateRef certificate) {
4101 struct Summary summary = {};
4102 OSStatus status = parseX501NameContent(&certificate->_issuer, &summary, obtainSummaryFromX501Name, true);
4103 if (status != errSecSuccess) {
4104 return NULL;
4105 }
4106 /* If we found a description and a common name we change the summary to
4107 CommonName (Description). */
4108 if (summary.description) {
4109 if (summary.type == kSummaryTypeCommonName) {
4110 CFStringRef fmt = SecCopyCertString(SEC_COMMON_NAME_DESC_KEY);
4111 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, fmt, summary.summary, summary.description);
4112 CFRelease(fmt);
4113 CFRelease(summary.summary);
4114 summary.summary = newSummary;
4115 }
4116 CFRelease(summary.description);
4117 }
4118
4119 return summary.summary;
4120 }
4121
4122 /* Return the earliest date on which all certificates in this chain are still
4123 valid. */
4124 static CFAbsoluteTime SecCertificateGetChainsLastValidity(
4125 SecCertificateRef certificate) {
4126 CFAbsoluteTime earliest = certificate->_notAfter;
4127 #if 0
4128 while (certificate->_parent) {
4129 certificate = certificate->_parent;
4130 if (earliest > certificate->_notAfter)
4131 earliest = certificate->_notAfter;
4132 }
4133 #endif
4134
4135 return earliest;
4136 }
4137
4138 /* Return the latest date on which all certificates in this chain will be
4139 valid. */
4140 static CFAbsoluteTime SecCertificateGetChainsFirstValidity(
4141 SecCertificateRef certificate) {
4142 CFAbsoluteTime latest = certificate->_notBefore;
4143 #if 0
4144 while (certificate->_parent) {
4145 certificate = certificate->_parent;
4146 if (latest < certificate->_notBefore)
4147 latest = certificate->_notBefore;
4148 }
4149 #endif
4150
4151 return latest;
4152 }
4153
4154 bool SecCertificateIsValid(SecCertificateRef certificate,
4155 CFAbsoluteTime verifyTime) {
4156 return certificate && certificate->_notBefore <= verifyTime &&
4157 verifyTime <= certificate->_notAfter;
4158 }
4159
4160 CFIndex SecCertificateVersion(SecCertificateRef certificate) {
4161 return certificate->_version + 1;
4162 }
4163
4164 CFAbsoluteTime SecCertificateNotValidBefore(SecCertificateRef certificate) {
4165 return certificate->_notBefore;
4166 }
4167
4168 CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate) {
4169 return certificate->_notAfter;
4170 }
4171
4172 CFMutableArrayRef SecCertificateCopySummaryProperties(
4173 SecCertificateRef certificate, CFAbsoluteTime verifyTime) {
4174 CFAllocatorRef allocator = CFGetAllocator(certificate);
4175 CFMutableArrayRef summary = CFArrayCreateMutable(allocator, 0,
4176 &kCFTypeArrayCallBacks);
4177 bool localized = true;
4178
4179 /* First we put the subject summary name. */
4180 CFStringRef ssummary = SecCertificateCopySubjectSummary(certificate);
4181 if (ssummary) {
4182 appendProperty(summary, kSecPropertyTypeTitle,
4183 NULL, NULL, ssummary, localized);
4184 CFRelease(ssummary);
4185 }
4186
4187 /* Let see if this certificate is currently valid. */
4188 CFStringRef label;
4189 CFAbsoluteTime when;
4190 CFStringRef message;
4191 CFStringRef ptype;
4192 if (verifyTime > certificate->_notAfter) {
4193 label = SEC_EXPIRED_KEY;
4194 when = certificate->_notAfter;
4195 ptype = kSecPropertyTypeError;
4196 message = SEC_CERT_EXPIRED_KEY;
4197 } else if (certificate->_notBefore > verifyTime) {
4198 label = SEC_VALID_FROM_KEY;
4199 when = certificate->_notBefore;
4200 ptype = kSecPropertyTypeError;
4201 message = SEC_CERT_NOT_YET_VALID_KEY;
4202 } else {
4203 CFAbsoluteTime last = SecCertificateGetChainsLastValidity(certificate);
4204 CFAbsoluteTime first = SecCertificateGetChainsFirstValidity(certificate);
4205 if (verifyTime > last) {
4206 label = SEC_EXPIRED_KEY;
4207 when = last;
4208 ptype = kSecPropertyTypeError;
4209 message = SEC_ISSUER_EXPIRED_KEY;
4210 } else if (verifyTime < first) {
4211 label = SEC_VALID_FROM_KEY;
4212 when = first;
4213 ptype = kSecPropertyTypeError;
4214 message = SEC_ISSR_NOT_YET_VALID_KEY;
4215 } else {
4216 label = SEC_EXPIRES_KEY;
4217 when = certificate->_notAfter;
4218 ptype = kSecPropertyTypeSuccess;
4219 message = SEC_CERT_VALID_KEY;
4220 }
4221 }
4222
4223 appendDateProperty(summary, label, when, localized);
4224 CFStringRef lmessage = SecCopyCertString(message);
4225 appendProperty(summary, ptype, NULL, NULL, lmessage, localized);
4226 CFRelease(lmessage);
4227
4228 return summary;
4229 }
4230
4231 CFArrayRef SecCertificateCopyLegacyProperties(SecCertificateRef certificate) {
4232 /*
4233 This function replicates the content returned by SecCertificateCopyProperties
4234 prior to 10.12.4, providing stable return values for SecCertificateCopyValues.
4235 Unlike SecCertificateCopyProperties, it does not cache the result and
4236 assumes the caller will do so.
4237 */
4238 CFAllocatorRef allocator = CFGetAllocator(certificate);
4239 CFMutableArrayRef properties = CFArrayCreateMutable(allocator,
4240 0, &kCFTypeArrayCallBacks);
4241
4242 /* Subject Name */
4243 CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator,
4244 &certificate->_subject, false);
4245 appendProperty(properties, kSecPropertyTypeSection, CFSTR("Subject Name"),
4246 NULL, subject_plist, false);
4247 CFRelease(subject_plist);
4248
4249 /* Issuer Name */
4250 CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator,
4251 &certificate->_issuer, false);
4252 appendProperty(properties, kSecPropertyTypeSection, CFSTR("Issuer Name"),
4253 NULL, issuer_plist, false);
4254 CFRelease(issuer_plist);
4255
4256 /* Version */
4257 CFStringRef versionString = CFStringCreateWithFormat(allocator,
4258 NULL, CFSTR("%d"), certificate->_version + 1);
4259 appendProperty(properties, kSecPropertyTypeString, CFSTR("Version"),
4260 NULL, versionString, false);
4261 CFRelease(versionString);
4262
4263 /* Serial Number */
4264 if (certificate->_serialNum.length) {
4265 appendIntegerProperty(properties, CFSTR("Serial Number"),
4266 &certificate->_serialNum, false);
4267 }
4268
4269 /* Signature Algorithm */
4270 appendAlgorithmProperty(properties, CFSTR("Signature Algorithm"),
4271 &certificate->_tbsSigAlg, false);
4272
4273 /* Validity dates */
4274 appendDateProperty(properties, CFSTR("Not Valid Before"), certificate->_notBefore, false);
4275 appendDateProperty(properties, CFSTR("Not Valid After"), certificate->_notAfter, false);
4276
4277 if (certificate->_subjectUniqueID.length) {
4278 appendDataProperty(properties, CFSTR("Subject Unique ID"),
4279 NULL, &certificate->_subjectUniqueID, false);
4280 }
4281 if (certificate->_issuerUniqueID.length) {
4282 appendDataProperty(properties, CFSTR("Issuer Unique ID"),
4283 NULL, &certificate->_issuerUniqueID, false);
4284 }
4285
4286 /* Public Key Algorithm */
4287 appendAlgorithmProperty(properties, CFSTR("Public Key Algorithm"),
4288 &certificate->_algId, false);
4289
4290 /* Public Key Data */
4291 appendDataProperty(properties, CFSTR("Public Key Data"),
4292 NULL, &certificate->_pubKeyDER, false);
4293
4294 /* Signature */
4295 appendDataProperty(properties, CFSTR("Signature"),
4296 NULL, &certificate->_signature, false);
4297
4298 /* Extensions */
4299 CFIndex ix;
4300 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
4301 appendExtension(properties, &certificate->_extensions[ix], false);
4302 }
4303
4304 /* Fingerprints */
4305 appendFingerprintsProperty(properties, CFSTR("Fingerprints"), certificate, false);
4306
4307 return properties;
4308 }
4309
4310 static CFArrayRef CopyProperties(SecCertificateRef certificate, Boolean localized) {
4311 if (!certificate->_properties) {
4312 CFAllocatorRef allocator = CFGetAllocator(certificate);
4313 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0,
4314 &kCFTypeArrayCallBacks);
4315 require_quiet(properties, out);
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 CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate) {
4387 /*
4388 Wrapper function which defaults to localized string properties
4389 for compatibility with prior releases.
4390 */
4391 return CopyProperties(certificate, true);
4392 }
4393
4394 CFArrayRef SecCertificateCopyLocalizedProperties(SecCertificateRef certificate, Boolean localized) {
4395 /*
4396 Wrapper function which permits caller to specify whether
4397 localized string properties are used.
4398 */
4399 return CopyProperties(certificate, localized);
4400 }
4401
4402 /* Unified serial number API */
4403 CFDataRef SecCertificateCopySerialNumberData(
4404 SecCertificateRef certificate,
4405 CFErrorRef *error)
4406 {
4407 if (!certificate) {
4408 if (error) {
4409 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidCertificate, NULL);
4410 }
4411 return NULL;
4412 }
4413 if (certificate->_serialNumber) {
4414 CFRetain(certificate->_serialNumber);
4415 }
4416 return certificate->_serialNumber;
4417 }
4418
4419 #if !TARGET_OS_OSX
4420 /* On iOS, the SecCertificateCopySerialNumber API takes one argument. */
4421 CFDataRef SecCertificateCopySerialNumber(
4422 SecCertificateRef certificate) {
4423 return SecCertificateCopySerialNumberData(certificate, NULL);
4424 }
4425 #endif
4426
4427 CFDataRef SecCertificateGetNormalizedIssuerContent(
4428 SecCertificateRef certificate) {
4429 return certificate->_normalizedIssuer;
4430 }
4431
4432 CFDataRef SecCertificateGetNormalizedSubjectContent(
4433 SecCertificateRef certificate) {
4434 return certificate->_normalizedSubject;
4435 }
4436
4437 /* Verify that certificate was signed by issuerKey. */
4438 OSStatus SecCertificateIsSignedBy(SecCertificateRef certificate,
4439 SecKeyRef issuerKey) {
4440 #pragma clang diagnostic push
4441 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
4442 /* Setup algId in SecAsn1AlgId format. */
4443 SecAsn1AlgId algId;
4444 #pragma clang diagnostic pop
4445 algId.algorithm.Length = certificate->_tbsSigAlg.oid.length;
4446 algId.algorithm.Data = certificate->_tbsSigAlg.oid.data;
4447 algId.parameters.Length = certificate->_tbsSigAlg.params.length;
4448 algId.parameters.Data = certificate->_tbsSigAlg.params.data;
4449
4450 /* RFC5280 4.1.1.2, 4.1.2.3 requires the actual signature algorithm
4451 must match the specified algorithm in the TBSCertificate. */
4452 bool sigAlgMatch = DEROidCompare(&certificate->_sigAlg.oid,
4453 &certificate->_tbsSigAlg.oid);
4454 if (!sigAlgMatch) {
4455 secwarning("Signature algorithm mismatch in certificate (see RFC5280 4.1.1.2)");
4456 }
4457
4458 CFErrorRef error = NULL;
4459 if (!sigAlgMatch ||
4460 !SecVerifySignatureWithPublicKey(issuerKey, &algId,
4461 certificate->_tbs.data, certificate->_tbs.length,
4462 certificate->_signature.data, certificate->_signature.length, &error))
4463 {
4464 #if !defined(NDEBUG)
4465 secdebug("verify", "signature verify failed: %" PRIdOSStatus, (error) ? (OSStatus)CFErrorGetCode(error) : errSecNotSigner);
4466 #endif
4467 CFReleaseSafe(error);
4468 return errSecNotSigner;
4469 }
4470
4471 return errSecSuccess;
4472 }
4473
4474 const DERItem * SecCertificateGetSubjectAltName(SecCertificateRef certificate) {
4475 if (!certificate->_subjectAltName) {
4476 return NULL;
4477 }
4478 return &certificate->_subjectAltName->extnValue;
4479 }
4480
4481 /* Convert IPv4 address string to canonical data format (4 bytes) */
4482 static bool convertIPv4Address(CFStringRef name, CFDataRef *dataIP) {
4483 /* IPv4: 4 octets in decimal separated by dots. */
4484 bool result = false;
4485 /* Check size */
4486 if (CFStringGetLength(name) < 7 || /* min size is #.#.#.# */
4487 CFStringGetLength(name) > 15) { /* max size is ###.###.###.### */
4488 return false;
4489 }
4490
4491 CFCharacterSetRef allowed = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("0123456789."));
4492 CFCharacterSetRef disallowed = CFCharacterSetCreateInvertedSet(NULL, allowed);
4493 CFMutableDataRef data = CFDataCreateMutable(NULL, 0);
4494 CFArrayRef parts = CFStringCreateArrayBySeparatingStrings(NULL, name, CFSTR("."));
4495 CFIndex i, count = (parts) ? CFArrayGetCount(parts) : 0;
4496
4497 /* Check character set */
4498 if (CFStringFindCharacterFromSet(name, disallowed,
4499 CFRangeMake(0, CFStringGetLength(name)),
4500 kCFCompareForcedOrdering, NULL)) {
4501 goto out;
4502 }
4503
4504 /* Check number of labels */
4505 if (CFArrayGetCount(parts) != 4) {
4506 goto out;
4507 }
4508
4509 /* Check each label and convert */
4510 for (i = 0; i < count; i++) {
4511 CFStringRef octet = (CFStringRef) CFArrayGetValueAtIndex(parts, i);
4512 char *cString = CFStringToCString(octet);
4513 uint32_t value = atoi(cString);
4514 free(cString);
4515 if (value > 255) {
4516 goto out;
4517 } else {
4518 uint8_t byte = value;
4519 CFDataAppendBytes(data, &byte, 1);
4520 }
4521 }
4522 result = true;
4523 if (dataIP) {
4524 *dataIP = (CFDataRef) CFRetain(data);
4525 }
4526
4527 out:
4528 CFReleaseNull(data);
4529 CFReleaseNull(parts);
4530 CFReleaseNull(allowed);
4531 CFReleaseNull(disallowed);
4532 return result;
4533 }
4534
4535 /* Convert IPv6 address string to canonical data format (16 bytes) */
4536 static bool convertIPv6Address(CFStringRef name, CFDataRef *dataIP) {
4537 /* IPv6: 8 16-bit fields with colon delimiters. */
4538 /* Note: we don't support conversion of hybrid IPv4-mapped addresses here. */
4539 bool result = false;
4540 CFMutableStringRef addr = NULL;
4541 CFIndex length = (name) ? CFStringGetLength(name) : 0;
4542 /* Sanity check size */
4543 if (length < 2 || /* min size is '::' */
4544 length > 41) { /* max size is '[####:####:####:####:####:####:####:####]' */
4545 return result;
4546 }
4547 /* Remove literal brackets, if present */
4548 if (CFStringHasPrefix(name, CFSTR("[")) && CFStringHasSuffix(name, CFSTR("]"))) {
4549 CFStringRef tmpName = CFStringCreateWithSubstring(NULL, name, CFRangeMake(1, length-2));
4550 if (tmpName) {
4551 addr = CFStringCreateMutableCopy(NULL, 0, tmpName);
4552 CFRelease(tmpName);
4553 }
4554 }
4555 if (NULL == addr) {
4556 addr = CFStringCreateMutableCopy(NULL, 0, name);
4557 }
4558 CFStringUppercase(addr, CFLocaleGetSystem());
4559
4560 CFCharacterSetRef allowed = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("0123456789ABCDEF:"));
4561 CFCharacterSetRef disallowed = CFCharacterSetCreateInvertedSet(NULL, allowed);
4562 CFMutableDataRef data = CFDataCreateMutable(NULL, 0);
4563 CFArrayRef parts = CFStringCreateArrayBySeparatingStrings(NULL, addr, CFSTR(":"));
4564 CFIndex i, count = (parts) ? CFArrayGetCount(parts) : 0;
4565
4566 /* Check character set */
4567 if (CFStringFindCharacterFromSet(addr, disallowed,
4568 CFRangeMake(0, CFStringGetLength(addr)),
4569 kCFCompareForcedOrdering, NULL)) {
4570 goto out;
4571 }
4572
4573 /* Check number of fields (no fewer than 3, no more than 8) */
4574 if (CFArrayGetCount(parts) < 3 || CFArrayGetCount(parts) > 8) {
4575 goto out;
4576 }
4577
4578 /* Check each field and convert to network-byte-order value */
4579 for (i = 0; i < count; i++) {
4580 uint16_t svalue = 0;
4581 CFStringRef fieldValue = (CFStringRef) CFArrayGetValueAtIndex(parts, i);
4582 char *cString = CFStringToCString(fieldValue);
4583 length = (cString) ? strlen(cString) : 0;
4584 if (length == 0) {
4585 /* empty value indicates one or more zeros in the address */
4586 if (i == 0 || i == count-1) { /* leading or trailing part of '::' */
4587 CFDataAppendBytes(data, (const UInt8 *)&svalue, 2);
4588 } else { /* determine how many fields are missing, then zero-fill */
4589 CFIndex z, missing = (8 - count) + 1;
4590 for (z = 0; z < missing; z++) {
4591 CFDataAppendBytes(data, (const UInt8 *)&svalue, 2);
4592 }
4593 }
4594 } else if (length <= 4) {
4595 /* valid field value is 4 characters or less */
4596 unsigned long value = strtoul(cString, NULL, 16);
4597 svalue = htons(value & 0xFFFF);
4598 CFDataAppendBytes(data, (const UInt8 *)&svalue, 2);
4599 }
4600 free(cString);
4601 }
4602 if (CFDataGetLength(data) != IPv6ADDRLEN) {
4603 goto out; /* after expansion, data must be exactly 16 bytes */
4604 }
4605
4606 result = true;
4607 if (dataIP) {
4608 *dataIP = (CFDataRef) CFRetain(data);
4609 }
4610
4611 out:
4612 CFReleaseNull(data);
4613 CFReleaseNull(parts);
4614 CFReleaseNull(allowed);
4615 CFReleaseNull(disallowed);
4616 CFReleaseNull(addr);
4617 return result;
4618 }
4619
4620 static bool convertIPAddress(CFStringRef string, CFDataRef *dataIP) {
4621 if (NULL == string) {
4622 return false;
4623 }
4624 if (convertIPv4Address(string, dataIP) ||
4625 convertIPv6Address(string, dataIP)) {
4626 return true;
4627 }
4628 return false;
4629 }
4630
4631 bool SecFrameworkIsIPAddress(CFStringRef string) {
4632 return convertIPAddress(string, NULL);
4633 }
4634
4635 CFDataRef SecFrameworkCopyIPAddressData(CFStringRef string) {
4636 CFDataRef data = NULL;
4637 if (!convertIPAddress(string, &data)) {
4638 return NULL;
4639 }
4640 return data;
4641 }
4642
4643 static OSStatus appendIPAddressesFromGeneralNames(void *context,
4644 SecCEGeneralNameType gnType, const DERItem *generalName) {
4645 CFMutableArrayRef ipAddresses = (CFMutableArrayRef)context;
4646 if (gnType == GNT_IPAddress) {
4647 CFStringRef string = copyIPAddressContentDescription(
4648 kCFAllocatorDefault, generalName);
4649 if (string) {
4650 CFArrayAppendValue(ipAddresses, string);
4651 CFRelease(string);
4652 } else {
4653 return errSecInvalidCertificate;
4654 }
4655 }
4656 return errSecSuccess;
4657 }
4658
4659 CFArrayRef SecCertificateCopyIPAddresses(SecCertificateRef certificate) {
4660 /* These can only exist in the subject alt name. */
4661 if (!certificate->_subjectAltName)
4662 return NULL;
4663
4664 CFMutableArrayRef ipAddresses = CFArrayCreateMutable(kCFAllocatorDefault,
4665 0, &kCFTypeArrayCallBacks);
4666 OSStatus status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
4667 ipAddresses, appendIPAddressesFromGeneralNames);
4668 if (status || CFArrayGetCount(ipAddresses) == 0) {
4669 CFRelease(ipAddresses);
4670 ipAddresses = NULL;
4671 }
4672 return ipAddresses;
4673 }
4674
4675 static OSStatus appendIPAddressesFromX501Name(void *context, const DERItem *type,
4676 const DERItem *value, CFIndex rdnIX,
4677 bool localized) {
4678 CFMutableArrayRef addrs = (CFMutableArrayRef)context;
4679 if (DEROidCompare(type, &oidCommonName)) {
4680 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4681 value, true, localized);
4682 if (string) {
4683 CFDataRef data = NULL;
4684 if (convertIPAddress(string, &data)) {
4685 CFArrayAppendValue(addrs, data);
4686 CFReleaseNull(data);
4687 }
4688 CFRelease(string);
4689 } else {
4690 return errSecInvalidCertificate;
4691 }
4692 }
4693 return errSecSuccess;
4694 }
4695
4696 CFArrayRef SecCertificateCopyIPAddressesFromSubject(SecCertificateRef certificate) {
4697 CFMutableArrayRef addrs = CFArrayCreateMutable(kCFAllocatorDefault,
4698 0, &kCFTypeArrayCallBacks);
4699 OSStatus status = parseX501NameContent(&certificate->_subject, addrs,
4700 appendIPAddressesFromX501Name, true);
4701 if (status || CFArrayGetCount(addrs) == 0) {
4702 CFReleaseNull(addrs);
4703 return NULL;
4704 }
4705 return addrs;
4706 }
4707
4708 static OSStatus appendDNSNamesFromGeneralNames(void *context, SecCEGeneralNameType gnType,
4709 const DERItem *generalName) {
4710 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4711 if (gnType == GNT_DNSName) {
4712 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault,
4713 generalName->data, generalName->length,
4714 kCFStringEncodingUTF8, FALSE);
4715 if (string) {
4716 CFArrayAppendValue(dnsNames, string);
4717 CFRelease(string);
4718 } else {
4719 return errSecInvalidCertificate;
4720 }
4721 }
4722 return errSecSuccess;
4723 }
4724
4725 /* Return true if the passed in string matches the
4726 Preferred name syntax from sections 2.3.1. in RFC 1035.
4727 With the added check that we disallow empty dns names.
4728 Also in order to support wildcard DNSNames we allow for the '*'
4729 character anywhere in a dns component where we currently allow
4730 a letter.
4731
4732 <domain> ::= <subdomain> | " "
4733
4734 <subdomain> ::= <label> | <subdomain> "." <label>
4735
4736 <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
4737
4738 RFC 3696 redefined labels as:
4739 <label> ::= <let-dig> [ [ <ldh-str> ] <let-dig> ]
4740 with the caveat that the highest-level labels is never all-numeric.
4741
4742 <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
4743
4744 <let-dig-hyp> ::= <let-dig> | "-"
4745
4746 <let-dig> ::= <letter> | <digit>
4747
4748 <letter> ::= any one of the 52 alphabetic characters A through Z in
4749 upper case and a through z in lower case
4750
4751 <digit> ::= any one of the ten digits 0 through 9
4752 */
4753 bool SecFrameworkIsDNSName(CFStringRef string) {
4754 CFStringInlineBuffer buf = {};
4755 CFIndex ix, labelLength = 0, length = CFStringGetLength(string);
4756 /* From RFC 1035 2.3.4. Size limits:
4757 labels 63 octets or less
4758 names 255 octets or less */
4759 require_quiet(length <= 255, notDNS);
4760 CFRange range = { 0, length };
4761 CFStringInitInlineBuffer(string, &buf, range);
4762 enum {
4763 kDNSStateInital,
4764 kDNSStateAfterDot,
4765 kDNSStateAfterAlpha,
4766 kDNSStateAfterDigit,
4767 kDNSStateAfterDash,
4768 } state = kDNSStateInital;
4769 Boolean labelHasAlpha = false;
4770
4771 for (ix = 0; ix < length; ++ix) {
4772 UniChar ch = CFStringGetCharacterFromInlineBuffer(&buf, ix);
4773 labelLength++;
4774 if (ch == '.') {
4775 require_quiet(labelLength <= 64 &&
4776 (state == kDNSStateAfterAlpha || state == kDNSStateAfterDigit),
4777 notDNS);
4778 state = kDNSStateAfterDot;
4779 labelHasAlpha = false;
4780 labelLength = 0;
4781 } else if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') ||
4782 ch == '*') {
4783 state = kDNSStateAfterAlpha;
4784 labelHasAlpha = true;
4785 } else if ('0' <= ch && ch <= '9') {
4786 state = kDNSStateAfterDigit;
4787 } else if (ch == '-') {
4788 require_quiet(state == kDNSStateAfterAlpha ||
4789 state == kDNSStateAfterDigit ||
4790 state == kDNSStateAfterDash, notDNS);
4791 state = kDNSStateAfterDash;
4792 } else {
4793 goto notDNS;
4794 }
4795 }
4796
4797 /* We don't allow a dns name to end in a dot or dash. */
4798 require_quiet(labelLength <= 63 &&
4799 (state == kDNSStateAfterAlpha || state == kDNSStateAfterDigit),
4800 notDNS);
4801
4802 /* Additionally, the rightmost label must have letters in it. */
4803 require_quiet(labelHasAlpha == true, notDNS);
4804
4805 return true;
4806 notDNS:
4807 return false;
4808 }
4809
4810 static OSStatus appendDNSNamesFromX501Name(void *context, const DERItem *type,
4811 const DERItem *value, CFIndex rdnIX, bool localized) {
4812 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4813 if (DEROidCompare(type, &oidCommonName)) {
4814 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4815 value, true, localized);
4816 if (string) {
4817 if (SecFrameworkIsDNSName(string)) {
4818 /* We found a common name that is formatted like a valid
4819 dns name. */
4820 CFArrayAppendValue(dnsNames, string);
4821 }
4822 CFRelease(string);
4823 } else {
4824 return errSecInvalidCertificate;
4825 }
4826 }
4827 return errSecSuccess;
4828 }
4829
4830 CFArrayRef SecCertificateCopyDNSNamesFromSubject(SecCertificateRef certificate) {
4831 CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault,
4832 0, &kCFTypeArrayCallBacks);
4833 OSStatus status = parseX501NameContent(&certificate->_subject, dnsNames,
4834 appendDNSNamesFromX501Name, true);
4835 if (status || CFArrayGetCount(dnsNames) == 0) {
4836 CFReleaseNull(dnsNames);
4837 return NULL;
4838 }
4839
4840 /* appendDNSNamesFromX501Name allows IP addresses, we don't want those for this function */
4841 __block CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
4842 CFArrayForEach(dnsNames, ^(const void *value) {
4843 CFStringRef name = (CFStringRef)value;
4844 if (!convertIPAddress(name, NULL)) {
4845 CFArrayAppendValue(result, name);
4846 }
4847 });
4848 CFReleaseNull(dnsNames);
4849 if (CFArrayGetCount(result) == 0) {
4850 CFReleaseNull(result);
4851 }
4852
4853 return result;
4854 }
4855
4856 CFArrayRef SecCertificateCopyDNSNamesFromSAN(SecCertificateRef certificate) {
4857 CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault,
4858 0, &kCFTypeArrayCallBacks);
4859 OSStatus status = errSecSuccess;
4860 if (certificate->_subjectAltName) {
4861 status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
4862 dnsNames, appendDNSNamesFromGeneralNames);
4863 }
4864
4865 if (status || CFArrayGetCount(dnsNames) == 0) {
4866 CFReleaseNull(dnsNames);
4867 }
4868 return dnsNames;
4869 }
4870
4871 /* Not everything returned by this function is going to be a proper DNS name,
4872 we also return the certificates common name entries from the subject,
4873 assuming they look like dns names as specified in RFC 1035. */
4874 CFArrayRef SecCertificateCopyDNSNames(SecCertificateRef certificate) {
4875 /* These can exist in the subject alt name or in the subject. */
4876 CFArrayRef sanNames = SecCertificateCopyDNSNamesFromSAN(certificate);
4877 if (sanNames && CFArrayGetCount(sanNames) > 0) {
4878 return sanNames;
4879 }
4880 CFReleaseNull(sanNames);
4881
4882 /* RFC 2818 section 3.1. Server Identity
4883 [...]
4884 If a subjectAltName extension of type dNSName is present, that MUST
4885 be used as the identity. Otherwise, the (most specific) Common Name
4886 field in the Subject field of the certificate MUST be used. Although
4887 the use of the Common Name is existing practice, it is deprecated and
4888 Certification Authorities are encouraged to use the dNSName instead.
4889 [...]
4890
4891 This implies that if we found 1 or more DNSNames in the
4892 subjectAltName, we should not use the Common Name of the subject as
4893 a DNSName.
4894 */
4895
4896 /* To preserve bug for bug compatibility, we can't use SecCertificateCopyDNSNamesFromSubject
4897 * because that function filters out IP Addresses. This function is Private, but
4898 * SecCertificateCopyValues uses it and that's Public. */
4899 CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault,
4900 0, &kCFTypeArrayCallBacks);
4901 OSStatus status = parseX501NameContent(&certificate->_subject, dnsNames,
4902 appendDNSNamesFromX501Name, true);
4903 if (status || CFArrayGetCount(dnsNames) == 0) {
4904 CFReleaseNull(dnsNames);
4905 }
4906 return dnsNames;
4907 }
4908
4909 static OSStatus appendRFC822NamesFromGeneralNames(void *context,
4910 SecCEGeneralNameType gnType, const DERItem *generalName) {
4911 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4912 if (gnType == GNT_RFC822Name) {
4913 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault,
4914 generalName->data, generalName->length,
4915 kCFStringEncodingASCII, FALSE);
4916 if (string) {
4917 CFArrayAppendValue(dnsNames, string);
4918 CFRelease(string);
4919 } else {
4920 return errSecInvalidCertificate;
4921 }
4922 }
4923 return errSecSuccess;
4924 }
4925
4926 static OSStatus appendRFC822NamesFromX501Name(void *context, const DERItem *type,
4927 const DERItem *value, CFIndex rdnIX, bool localized) {
4928 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context;
4929 if (DEROidCompare(type, &oidEmailAddress)) {
4930 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4931 value, true, localized);
4932 if (string) {
4933 CFArrayAppendValue(dnsNames, string);
4934 CFRelease(string);
4935 } else {
4936 return errSecInvalidCertificate;
4937 }
4938 }
4939 return errSecSuccess;
4940 }
4941
4942 CFArrayRef SecCertificateCopyRFC822Names(SecCertificateRef certificate) {
4943 /* These can exist in the subject alt name or in the subject. */
4944 CFMutableArrayRef rfc822Names = CFArrayCreateMutable(kCFAllocatorDefault,
4945 0, &kCFTypeArrayCallBacks);
4946 OSStatus status = errSecSuccess;
4947 if (certificate->_subjectAltName) {
4948 status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
4949 rfc822Names, appendRFC822NamesFromGeneralNames);
4950 }
4951 if (!status) {
4952 status = parseX501NameContent(&certificate->_subject, rfc822Names,
4953 appendRFC822NamesFromX501Name, true);
4954 }
4955 if (status || CFArrayGetCount(rfc822Names) == 0) {
4956 CFRelease(rfc822Names);
4957 rfc822Names = NULL;
4958 }
4959 return rfc822Names;
4960 }
4961
4962 OSStatus SecCertificateCopyEmailAddresses(SecCertificateRef certificate, CFArrayRef * __nonnull CF_RETURNS_RETAINED emailAddresses) {
4963 if (!certificate || !emailAddresses) {
4964 return errSecParam;
4965 }
4966 *emailAddresses = SecCertificateCopyRFC822Names(certificate);
4967 if (*emailAddresses == NULL) {
4968 *emailAddresses = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
4969 }
4970 return errSecSuccess;
4971 }
4972
4973 CFArrayRef SecCertificateCopyRFC822NamesFromSubject(SecCertificateRef certificate) {
4974 CFMutableArrayRef rfc822Names = CFArrayCreateMutable(kCFAllocatorDefault,
4975 0, &kCFTypeArrayCallBacks);
4976 OSStatus status = parseX501NameContent(&certificate->_subject, rfc822Names,
4977 appendRFC822NamesFromX501Name, true);
4978 if (status || CFArrayGetCount(rfc822Names) == 0) {
4979 CFRelease(rfc822Names);
4980 rfc822Names = NULL;
4981 }
4982 return rfc822Names;
4983 }
4984
4985 static OSStatus appendCommonNamesFromX501Name(void *context,
4986 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
4987 CFMutableArrayRef commonNames = (CFMutableArrayRef)context;
4988 if (DEROidCompare(type, &oidCommonName)) {
4989 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
4990 value, true, localized);
4991 if (string) {
4992 CFArrayAppendValue(commonNames, string);
4993 CFRelease(string);
4994 } else {
4995 return errSecInvalidCertificate;
4996 }
4997 }
4998 return errSecSuccess;
4999 }
5000
5001 CFArrayRef SecCertificateCopyCommonNames(SecCertificateRef certificate) {
5002 CFMutableArrayRef commonNames = CFArrayCreateMutable(kCFAllocatorDefault,
5003 0, &kCFTypeArrayCallBacks);
5004 OSStatus status;
5005 status = parseX501NameContent(&certificate->_subject, commonNames,
5006 appendCommonNamesFromX501Name, true);
5007 if (status || CFArrayGetCount(commonNames) == 0) {
5008 CFRelease(commonNames);
5009 commonNames = NULL;
5010 }
5011 return commonNames;
5012 }
5013
5014 OSStatus SecCertificateCopyCommonName(SecCertificateRef certificate, CFStringRef *commonName)
5015 {
5016 if (!certificate) {
5017 return errSecParam;
5018 }
5019 CFArrayRef commonNames = SecCertificateCopyCommonNames(certificate);
5020 if (!commonNames) {
5021 return errSecInternal;
5022 }
5023
5024 if (commonName) {
5025 CFIndex count = CFArrayGetCount(commonNames);
5026 *commonName = CFRetainSafe(CFArrayGetValueAtIndex(commonNames, count-1));
5027 }
5028 CFReleaseSafe(commonNames);
5029 return errSecSuccess;
5030 }
5031
5032 static OSStatus appendOrganizationFromX501Name(void *context,
5033 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
5034 CFMutableArrayRef organization = (CFMutableArrayRef)context;
5035 if (DEROidCompare(type, &oidOrganizationName)) {
5036 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
5037 value, true, localized);
5038 if (string) {
5039 CFArrayAppendValue(organization, string);
5040 CFRelease(string);
5041 } else {
5042 return errSecInvalidCertificate;
5043 }
5044 }
5045 return errSecSuccess;
5046 }
5047
5048 CFArrayRef SecCertificateCopyOrganizationFromX501NameContent(const DERItem *nameContent) {
5049 CFMutableArrayRef organization = CFArrayCreateMutable(kCFAllocatorDefault,
5050 0, &kCFTypeArrayCallBacks);
5051 OSStatus status;
5052 status = parseX501NameContent(nameContent, organization,
5053 appendOrganizationFromX501Name, true);
5054 if (status || CFArrayGetCount(organization) == 0) {
5055 CFRelease(organization);
5056 organization = NULL;
5057 }
5058 return organization;
5059 }
5060
5061 CFArrayRef SecCertificateCopyOrganization(SecCertificateRef certificate) {
5062 return SecCertificateCopyOrganizationFromX501NameContent(&certificate->_subject);
5063 }
5064
5065 static OSStatus appendOrganizationalUnitFromX501Name(void *context,
5066 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
5067 CFMutableArrayRef organizationalUnit = (CFMutableArrayRef)context;
5068 if (DEROidCompare(type, &oidOrganizationalUnitName)) {
5069 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
5070 value, true, localized);
5071 if (string) {
5072 CFArrayAppendValue(organizationalUnit, string);
5073 CFRelease(string);
5074 } else {
5075 return errSecInvalidCertificate;
5076 }
5077 }
5078 return errSecSuccess;
5079 }
5080
5081 CFArrayRef SecCertificateCopyOrganizationalUnit(SecCertificateRef certificate) {
5082 CFMutableArrayRef organizationalUnit = CFArrayCreateMutable(kCFAllocatorDefault,
5083 0, &kCFTypeArrayCallBacks);
5084 OSStatus status;
5085 status = parseX501NameContent(&certificate->_subject, organizationalUnit,
5086 appendOrganizationalUnitFromX501Name, true);
5087 if (status || CFArrayGetCount(organizationalUnit) == 0) {
5088 CFRelease(organizationalUnit);
5089 organizationalUnit = NULL;
5090 }
5091 return organizationalUnit;
5092 }
5093
5094 static OSStatus appendCountryFromX501Name(void *context,
5095 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
5096 CFMutableArrayRef countries = (CFMutableArrayRef)context;
5097 if (DEROidCompare(type, &oidCountryName)) {
5098 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
5099 value, true, localized);
5100 if (string) {
5101 CFArrayAppendValue(countries, string);
5102 CFRelease(string);
5103 } else {
5104 return errSecInvalidCertificate;
5105 }
5106 }
5107 return errSecSuccess;
5108 }
5109
5110 CFArrayRef SecCertificateCopyCountry(SecCertificateRef certificate) {
5111 CFMutableArrayRef countries = CFArrayCreateMutable(kCFAllocatorDefault,
5112 0, &kCFTypeArrayCallBacks);
5113 OSStatus status;
5114 status = parseX501NameContent(&certificate->_subject, countries,
5115 appendCountryFromX501Name, true);
5116 if (status || CFArrayGetCount(countries) == 0) {
5117 CFRelease(countries);
5118 countries = NULL;
5119 }
5120 return countries;
5121 }
5122
5123 const SecCEBasicConstraints *
5124 SecCertificateGetBasicConstraints(SecCertificateRef certificate) {
5125 if (certificate->_basicConstraints.present)
5126 return &certificate->_basicConstraints;
5127 else
5128 return NULL;
5129 }
5130
5131 CFArrayRef SecCertificateGetPermittedSubtrees(SecCertificateRef certificate) {
5132 return (certificate->_permittedSubtrees);
5133 }
5134
5135 CFArrayRef SecCertificateGetExcludedSubtrees(SecCertificateRef certificate) {
5136 return (certificate->_excludedSubtrees);
5137 }
5138
5139 const SecCEPolicyConstraints *
5140 SecCertificateGetPolicyConstraints(SecCertificateRef certificate) {
5141 if (certificate->_policyConstraints.present)
5142 return &certificate->_policyConstraints;
5143 else
5144 return NULL;
5145 }
5146
5147 const SecCEPolicyMappings *
5148 SecCertificateGetPolicyMappings(SecCertificateRef certificate) {
5149 if (certificate->_policyMappings.present) {
5150 return &certificate->_policyMappings;
5151 } else {
5152 return NULL;
5153 }
5154 }
5155
5156 const SecCECertificatePolicies *
5157 SecCertificateGetCertificatePolicies(SecCertificateRef certificate) {
5158 if (certificate->_certificatePolicies.present)
5159 return &certificate->_certificatePolicies;
5160 else
5161 return NULL;
5162 }
5163
5164 const SecCEInhibitAnyPolicy *
5165 SecCertificateGetInhibitAnyPolicySkipCerts(SecCertificateRef certificate) {
5166 if (certificate->_inhibitAnyPolicySkipCerts.present) {
5167 return &certificate->_inhibitAnyPolicySkipCerts;
5168 } else {
5169 return NULL;
5170 }
5171 }
5172
5173 static OSStatus appendNTPrincipalNamesFromGeneralNames(void *context,
5174 SecCEGeneralNameType gnType, const DERItem *generalName) {
5175 CFMutableArrayRef ntPrincipalNames = (CFMutableArrayRef)context;
5176 if (gnType == GNT_OtherName) {
5177 DEROtherName on;
5178 DERReturn drtn = DERParseSequenceContent(generalName,
5179 DERNumOtherNameItemSpecs, DEROtherNameItemSpecs,
5180 &on, sizeof(on));
5181 require_noerr_quiet(drtn, badDER);
5182 if (DEROidCompare(&on.typeIdentifier, &oidMSNTPrincipalName)) {
5183 CFStringRef string;
5184 require_quiet(string = copyDERThingDescription(kCFAllocatorDefault,
5185 &on.value, true, true), badDER);
5186 CFArrayAppendValue(ntPrincipalNames, string);
5187 CFRelease(string);
5188 }
5189 }
5190 return errSecSuccess;
5191
5192 badDER:
5193 return errSecInvalidCertificate;
5194
5195 }
5196
5197 CFArrayRef SecCertificateCopyNTPrincipalNames(SecCertificateRef certificate) {
5198 CFMutableArrayRef ntPrincipalNames = CFArrayCreateMutable(kCFAllocatorDefault,
5199 0, &kCFTypeArrayCallBacks);
5200 OSStatus status = errSecSuccess;
5201 if (certificate->_subjectAltName) {
5202 status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
5203 ntPrincipalNames, appendNTPrincipalNamesFromGeneralNames);
5204 }
5205 if (status || CFArrayGetCount(ntPrincipalNames) == 0) {
5206 CFRelease(ntPrincipalNames);
5207 ntPrincipalNames = NULL;
5208 }
5209 return ntPrincipalNames;
5210 }
5211
5212 static OSStatus appendToRFC2253String(void *context,
5213 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
5214 CFMutableStringRef string = (CFMutableStringRef)context;
5215 /*
5216 CN commonName
5217 L localityName
5218 ST stateOrProvinceName
5219 O organizationName
5220 OU organizationalUnitName
5221 C countryName
5222 STREET streetAddress
5223 DC domainComponent
5224 UID userid
5225 */
5226 /* Prepend a + if this is not the first RDN in an RDN set.
5227 Otherwise prepend a , if this is not the first RDN. */
5228 if (rdnIX > 0)
5229 CFStringAppend(string, CFSTR("+"));
5230 else if (CFStringGetLength(string)) {
5231 CFStringAppend(string, CFSTR(","));
5232 }
5233
5234 CFStringRef label, oid = NULL;
5235 /* @@@ Consider changing this to a dictionary lookup keyed by the
5236 decimal representation. */
5237 if (DEROidCompare(type, &oidCommonName)) {
5238 label = CFSTR("CN");
5239 } else if (DEROidCompare(type, &oidLocalityName)) {
5240 label = CFSTR("L");
5241 } else if (DEROidCompare(type, &oidStateOrProvinceName)) {
5242 label = CFSTR("ST");
5243 } else if (DEROidCompare(type, &oidOrganizationName)) {
5244 label = CFSTR("O");
5245 } else if (DEROidCompare(type, &oidOrganizationalUnitName)) {
5246 label = CFSTR("OU");
5247 } else if (DEROidCompare(type, &oidCountryName)) {
5248 label = CFSTR("C");
5249 #if 0
5250 } else if (DEROidCompare(type, &oidStreetAddress)) {
5251 label = CFSTR("STREET");
5252 } else if (DEROidCompare(type, &oidDomainComponent)) {
5253 label = CFSTR("DC");
5254 } else if (DEROidCompare(type, &oidUserID)) {
5255 label = CFSTR("UID");
5256 #endif
5257 } else {
5258 label = oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, type);
5259 }
5260
5261 CFStringAppend(string, label);
5262 CFStringAppend(string, CFSTR("="));
5263 CFStringRef raw = NULL;
5264 if (!oid)
5265 raw = copyDERThingDescription(kCFAllocatorDefault, value, true, localized);
5266
5267 if (raw) {
5268 /* Append raw to string while escaping:
5269 a space or "#" character occurring at the beginning of the string
5270 a space character occurring at the end of the string
5271 one of the characters ",", "+", """, "\", "<", ">" or ";"
5272 */
5273 CFStringInlineBuffer buffer = {};
5274 CFIndex ix, length = CFStringGetLength(raw);
5275 CFRange range = { 0, length };
5276 CFStringInitInlineBuffer(raw, &buffer, range);
5277 for (ix = 0; ix < length; ++ix) {
5278 UniChar ch = CFStringGetCharacterFromInlineBuffer(&buffer, ix);
5279 if (ch < 0x20) {
5280 CFStringAppendFormat(string, NULL, CFSTR("\\%02X"), ch);
5281 } else if (ch == ',' || ch == '+' || ch == '"' || ch == '\\' ||
5282 ch == '<' || ch == '>' || ch == ';' ||
5283 (ch == ' ' && (ix == 0 || ix == length - 1)) ||
5284 (ch == '#' && ix == 0)) {
5285 UniChar chars[] = { '\\', ch };
5286 CFStringAppendCharacters(string, chars, 2);
5287 } else {
5288 CFStringAppendCharacters(string, &ch, 1);
5289 }
5290 }
5291 CFRelease(raw);
5292 } else {
5293 /* Append the value in hex. */
5294 CFStringAppend(string, CFSTR("#"));
5295 DERSize ix;
5296 for (ix = 0; ix < value->length; ++ix)
5297 CFStringAppendFormat(string, NULL, CFSTR("%02X"), value->data[ix]);
5298 }
5299
5300 CFReleaseSafe(oid);
5301
5302 return errSecSuccess;
5303 }
5304
5305 CFStringRef SecCertificateCopySubjectString(SecCertificateRef certificate) {
5306 CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0);
5307 OSStatus status = parseX501NameContent(&certificate->_subject, string, appendToRFC2253String, true);
5308 if (status || CFStringGetLength(string) == 0) {
5309 CFRelease(string);
5310 string = NULL;
5311 }
5312 return string;
5313 }
5314
5315 static OSStatus appendToCompanyNameString(void *context,
5316 const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
5317 CFMutableStringRef string = (CFMutableStringRef)context;
5318 if (CFStringGetLength(string) != 0)
5319 return errSecSuccess;
5320
5321 if (!DEROidCompare(type, &oidOrganizationName))
5322 return errSecSuccess;
5323
5324 CFStringRef raw;
5325 raw = copyDERThingDescription(kCFAllocatorDefault, value, true, localized);
5326 if (!raw)
5327 return errSecSuccess;
5328 CFStringAppend(string, raw);
5329 CFRelease(raw);
5330
5331 return errSecSuccess;
5332 }
5333
5334 CFStringRef SecCertificateCopyCompanyName(SecCertificateRef certificate) {
5335 CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0);
5336 OSStatus status = parseX501NameContent(&certificate->_subject, string,
5337 appendToCompanyNameString, true);
5338 if (status || CFStringGetLength(string) == 0) {
5339 CFRelease(string);
5340 string = NULL;
5341 }
5342 return string;
5343 }
5344
5345 CFDataRef SecCertificateCopyIssuerSequence(
5346 SecCertificateRef certificate) {
5347 return SecDERItemCopySequence(&certificate->_issuer);
5348 }
5349
5350 CFDataRef SecCertificateCopySubjectSequence(
5351 SecCertificateRef certificate) {
5352 return SecDERItemCopySequence(&certificate->_subject);
5353 }
5354
5355 CFDataRef SecCertificateCopyNormalizedIssuerSequence(SecCertificateRef certificate) {
5356 if (!certificate || !certificate->_normalizedIssuer) {
5357 return NULL;
5358 }
5359 return SecCopySequenceFromContent(certificate->_normalizedIssuer);
5360 }
5361
5362 CFDataRef SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certificate) {
5363 if (!certificate || !certificate->_normalizedSubject) {
5364 return NULL;
5365 }
5366 return SecCopySequenceFromContent(certificate->_normalizedSubject);
5367 }
5368
5369 const DERAlgorithmId *SecCertificateGetPublicKeyAlgorithm(
5370 SecCertificateRef certificate) {
5371 return &certificate->_algId;
5372 }
5373
5374 const DERItem *SecCertificateGetPublicKeyData(SecCertificateRef certificate) {
5375 return &certificate->_pubKeyDER;
5376 }
5377
5378 #if TARGET_OS_OSX
5379 /* There is already a SecCertificateCopyPublicKey with different args on OS X,
5380 so we will refer to this one internally as SecCertificateCopyPublicKey_ios.
5381 */
5382 __nullable SecKeyRef SecCertificateCopyPublicKey_ios(SecCertificateRef certificate)
5383 #else
5384 __nullable SecKeyRef SecCertificateCopyPublicKey(SecCertificateRef certificate)
5385 #endif
5386 {
5387 return SecCertificateCopyKey(certificate);
5388 }
5389
5390 SecKeyRef SecCertificateCopyKey(SecCertificateRef certificate) {
5391 if (certificate->_pubKey == NULL) {
5392 const DERAlgorithmId *algId =
5393 SecCertificateGetPublicKeyAlgorithm(certificate);
5394 const DERItem *keyData = SecCertificateGetPublicKeyData(certificate);
5395 const DERItem *params = NULL;
5396 if (algId->params.length != 0) {
5397 params = &algId->params;
5398 }
5399 SecAsn1Oid oid1 = { .Data = algId->oid.data, .Length = algId->oid.length };
5400 SecAsn1Item params1 = {
5401 .Data = params ? params->data : NULL,
5402 .Length = params ? params->length : 0
5403 };
5404 SecAsn1Item keyData1 = {
5405 .Data = keyData ? keyData->data : NULL,
5406 .Length = keyData ? keyData->length : 0
5407 };
5408 certificate->_pubKey = SecKeyCreatePublicFromDER(kCFAllocatorDefault, &oid1, &params1,
5409 &keyData1);
5410 }
5411
5412 return CFRetainSafe(certificate->_pubKey);
5413 }
5414
5415 static CFIndex SecCertificateGetPublicKeyAlgorithmIdAndSize(SecCertificateRef certificate, size_t *keySizeInBytes) {
5416 CFIndex keyAlgID = kSecNullAlgorithmID;
5417 size_t size = 0;
5418
5419 SecKeyRef pubKey = NULL;
5420 require_quiet(certificate, out);
5421 require_quiet(pubKey = SecCertificateCopyKey(certificate) ,out);
5422 size = SecKeyGetBlockSize(pubKey);
5423 keyAlgID = SecKeyGetAlgorithmId(pubKey);
5424
5425 out:
5426 CFReleaseNull(pubKey);
5427 if (keySizeInBytes) { *keySizeInBytes = size; }
5428 return keyAlgID;
5429 }
5430
5431 /*
5432 * Public keys in certificates may be considered "weak" or "strong" or neither
5433 * (that is, in between). Certificates using weak keys are not trusted at all.
5434 * Certificates using neither strong nor weak keys are only trusted in certain
5435 * contexts. SecPolicy and SecPolicyServer define the contexts by which we enforce
5436 * these (or stronger) key size trust policies.
5437 */
5438 bool SecCertificateIsWeakKey(SecCertificateRef certificate) {
5439 if (!certificate) { return true; }
5440
5441 bool weak = true;
5442 size_t size = 0;
5443 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) {
5444 case kSecRSAAlgorithmID:
5445 if (MIN_RSA_KEY_SIZE <= size) weak = false;
5446 break;
5447 case kSecECDSAAlgorithmID:
5448 if (MIN_EC_KEY_SIZE <= size) weak = false;
5449 break;
5450 default:
5451 weak = true;
5452 }
5453 return weak;
5454 }
5455
5456 bool SecCertificateIsStrongKey(SecCertificateRef certificate) {
5457 if (!certificate) { return false; }
5458
5459 bool strong = false;
5460 size_t size = 0;
5461 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) {
5462 case kSecRSAAlgorithmID:
5463 if (MIN_STRONG_RSA_KEY_SIZE <= size) strong = true;
5464 break;
5465 case kSecECDSAAlgorithmID:
5466 if (MIN_STRONG_EC_KEY_SIZE <= size) strong = true;
5467 break;
5468 default:
5469 strong = false;
5470 }
5471 return strong;
5472 }
5473
5474 bool SecCertificateIsWeakHash(SecCertificateRef certificate) {
5475 if (!certificate) { return true; }
5476 SecSignatureHashAlgorithm certAlg = 0;
5477 certAlg = SecCertificateGetSignatureHashAlgorithm(certificate);
5478 if (certAlg == kSecSignatureHashAlgorithmUnknown ||
5479 certAlg == kSecSignatureHashAlgorithmMD2 ||
5480 certAlg == kSecSignatureHashAlgorithmMD4 ||
5481 certAlg == kSecSignatureHashAlgorithmMD5 ||
5482 certAlg == kSecSignatureHashAlgorithmSHA1) {
5483 return true;
5484 }
5485 return false;
5486 }
5487
5488 bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate,
5489 CFDictionaryRef keySizes) {
5490 if (!certificate) { return false; }
5491
5492 bool goodSize = false;
5493 size_t size = 0;
5494 CFNumberRef minSize;
5495 size_t minSizeInBits;
5496 switch (SecCertificateGetPublicKeyAlgorithmIdAndSize(certificate, &size)) {
5497 case kSecRSAAlgorithmID:
5498 if(CFDictionaryGetValueIfPresent(keySizes, kSecAttrKeyTypeRSA, (const void**)&minSize)
5499 && minSize && CFNumberGetValue(minSize, kCFNumberLongType, &minSizeInBits)) {
5500 if (size >= (size_t)(minSizeInBits+7)/8) goodSize = true;
5501 }
5502 break;
5503 case kSecECDSAAlgorithmID:
5504 if(CFDictionaryGetValueIfPresent(keySizes, kSecAttrKeyTypeEC, (const void**)&minSize)
5505 && minSize && CFNumberGetValue(minSize, kCFNumberLongType, &minSizeInBits)) {
5506 if (size >= (size_t)(minSizeInBits+7)/8) goodSize = true;
5507 }
5508 break;
5509 default:
5510 goodSize = false;
5511 }
5512 return goodSize;
5513 }
5514
5515 CFDataRef SecCertificateGetSHA1Digest(SecCertificateRef certificate) {
5516 if (!certificate || !certificate->_der.data) {
5517 return NULL;
5518 }
5519 if (!certificate->_sha1Digest) {
5520 certificate->_sha1Digest =
5521 SecSHA1DigestCreate(CFGetAllocator(certificate),
5522 certificate->_der.data, certificate->_der.length);
5523 }
5524 return certificate->_sha1Digest;
5525 }
5526
5527 CFDataRef SecCertificateCopySHA256Digest(SecCertificateRef certificate) {
5528 if (!certificate || !certificate->_der.data) {
5529 return NULL;
5530 }
5531 return SecSHA256DigestCreate(CFGetAllocator(certificate),
5532 certificate->_der.data, certificate->_der.length);
5533 }
5534
5535 CFDataRef SecCertificateCopyIssuerSHA1Digest(SecCertificateRef certificate) {
5536 CFDataRef digest = NULL;
5537 CFDataRef issuer = SecCertificateCopyIssuerSequence(certificate);
5538 if (issuer) {
5539 digest = SecSHA1DigestCreate(kCFAllocatorDefault,
5540 CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
5541 CFRelease(issuer);
5542 }
5543 return digest;
5544 }
5545
5546 CFDataRef SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate) {
5547 if (!certificate || !certificate->_pubKeyDER.data) {
5548 return NULL;
5549 }
5550 return SecSHA1DigestCreate(CFGetAllocator(certificate),
5551 certificate->_pubKeyDER.data, certificate->_pubKeyDER.length);
5552 }
5553
5554 static CFDataRef SecCertificateCopySPKIEncoded(SecCertificateRef certificate) {
5555 /* SPKI is saved without the tag/length by libDER, so we need to re-encode */
5556 if (!certificate || !certificate->_subjectPublicKeyInfo.data) {
5557 return NULL;
5558 }
5559 DERSize size = DERLengthOfItem(ASN1_CONSTR_SEQUENCE, certificate->_subjectPublicKeyInfo.length);
5560 if (size < certificate->_subjectPublicKeyInfo.length) {
5561 return NULL;
5562 }
5563 uint8_t *temp = malloc(size);
5564 if (!temp) {
5565 return NULL;
5566 }
5567 DERReturn drtn = DEREncodeItem(ASN1_CONSTR_SEQUENCE,
5568 certificate->_subjectPublicKeyInfo.length,
5569 certificate->_subjectPublicKeyInfo.data,
5570 temp, &size);
5571 CFDataRef encodedSPKI = NULL;
5572 if (drtn == DR_Success) {
5573 encodedSPKI = CFDataCreate(NULL, temp, size);
5574 }
5575 free(temp);
5576 return encodedSPKI;
5577 }
5578
5579 CFDataRef SecCertificateCopySubjectPublicKeyInfoSHA1Digest(SecCertificateRef certificate) {
5580 CFDataRef encodedSPKI = SecCertificateCopySPKIEncoded(certificate);
5581 if (!encodedSPKI) { return NULL; }
5582 CFDataRef hash = SecSHA1DigestCreate(CFGetAllocator(certificate),
5583 CFDataGetBytePtr(encodedSPKI),
5584 CFDataGetLength(encodedSPKI));
5585 CFReleaseNull(encodedSPKI);
5586 return hash;
5587 }
5588
5589 CFDataRef SecCertificateCopySubjectPublicKeyInfoSHA256Digest(SecCertificateRef certificate) {
5590 CFDataRef encodedSPKI = SecCertificateCopySPKIEncoded(certificate);
5591 if (!encodedSPKI) { return NULL; }
5592 CFDataRef hash = SecSHA256DigestCreate(CFGetAllocator(certificate),
5593 CFDataGetBytePtr(encodedSPKI),
5594 CFDataGetLength(encodedSPKI));
5595 CFReleaseNull(encodedSPKI);
5596 return hash;
5597 }
5598
5599 CFTypeRef SecCertificateCopyKeychainItem(SecCertificateRef certificate)
5600 {
5601 if (!certificate) {
5602 return NULL;
5603 }
5604 CFRetainSafe(certificate->_keychain_item);
5605 return certificate->_keychain_item;
5606 }
5607
5608 CFDataRef SecCertificateGetAuthorityKeyID(SecCertificateRef certificate) {
5609 if (!certificate) {
5610 return NULL;
5611 }
5612 if (!certificate->_authorityKeyID &&
5613 certificate->_authorityKeyIdentifier.length) {
5614 certificate->_authorityKeyID = CFDataCreate(kCFAllocatorDefault,
5615 certificate->_authorityKeyIdentifier.data,
5616 certificate->_authorityKeyIdentifier.length);
5617 }
5618
5619 return certificate->_authorityKeyID;
5620 }
5621
5622 CFDataRef SecCertificateGetSubjectKeyID(SecCertificateRef certificate) {
5623 if (!certificate) {
5624 return NULL;
5625 }
5626 if (!certificate->_subjectKeyID &&
5627 certificate->_subjectKeyIdentifier.length) {
5628 certificate->_subjectKeyID = CFDataCreate(kCFAllocatorDefault,
5629 certificate->_subjectKeyIdentifier.data,
5630 certificate->_subjectKeyIdentifier.length);
5631 }
5632
5633 return certificate->_subjectKeyID;
5634 }
5635
5636 CFArrayRef SecCertificateGetCRLDistributionPoints(SecCertificateRef certificate) {
5637 if (!certificate) {
5638 return NULL;
5639 }
5640 return certificate->_crlDistributionPoints;
5641 }
5642
5643 CFArrayRef SecCertificateGetOCSPResponders(SecCertificateRef certificate) {
5644 if (!certificate) {
5645 return NULL;
5646 }
5647 return certificate->_ocspResponders;
5648 }
5649
5650 CFArrayRef SecCertificateGetCAIssuers(SecCertificateRef certificate) {
5651 if (!certificate) {
5652 return NULL;
5653 }
5654 return certificate->_caIssuers;
5655 }
5656
5657 bool SecCertificateHasCriticalSubjectAltName(SecCertificateRef certificate) {
5658 if (!certificate) {
5659 return false;
5660 }
5661 return certificate->_subjectAltName &&
5662 certificate->_subjectAltName->critical;
5663 }
5664
5665 bool SecCertificateHasSubject(SecCertificateRef certificate) {
5666 if (!certificate) {
5667 return false;
5668 }
5669 /* Since the _subject field is the content of the subject and not the
5670 whole thing, we can simply check for a 0 length subject here. */
5671 return certificate->_subject.length != 0;
5672 }
5673
5674 bool SecCertificateHasUnknownCriticalExtension(SecCertificateRef certificate) {
5675 if (!certificate) {
5676 return false;
5677 }
5678 return certificate->_foundUnknownCriticalExtension;
5679 }
5680
5681 /* Private API functions. */
5682 void SecCertificateShow(SecCertificateRef certificate) {
5683 check(certificate);
5684 fprintf(stderr, "SecCertificate instance %p:\n", certificate);
5685 fprintf(stderr, "\n");
5686 }
5687
5688 #ifndef STANDALONE
5689 CFDictionaryRef SecCertificateCopyAttributeDictionary(
5690 SecCertificateRef certificate) {
5691 if (!SecCertificateIsCertificate(certificate)) {
5692 return NULL;
5693 }
5694 CFAllocatorRef allocator = CFGetAllocator(certificate);
5695 CFNumberRef certificateType = NULL;
5696 CFNumberRef certificateEncoding = NULL;
5697 CFStringRef label = NULL;
5698 CFStringRef alias = NULL;
5699 CFDataRef skid = NULL;
5700 CFDataRef pubKeyDigest = NULL;
5701 CFDataRef certData = NULL;
5702 CFDictionaryRef dict = NULL;
5703
5704 DICT_DECLARE(11);
5705
5706 /* CSSM_CERT_X_509v1, CSSM_CERT_X_509v2 or CSSM_CERT_X_509v3 */
5707 SInt32 ctv = certificate->_version + 1;
5708 SInt32 cev = 3; /* CSSM_CERT_ENCODING_DER */
5709 certificateType = CFNumberCreate(allocator, kCFNumberSInt32Type, &ctv);
5710 require_quiet(certificateType != NULL, out);
5711 certificateEncoding = CFNumberCreate(allocator, kCFNumberSInt32Type, &cev);
5712 require_quiet(certificateEncoding != NULL, out);
5713 certData = SecCertificateCopyData(certificate);
5714 require_quiet(certData != NULL, out);
5715 skid = SecCertificateGetSubjectKeyID(certificate);
5716 require_quiet(certificate->_pubKeyDER.data != NULL && certificate->_pubKeyDER.length > 0, out);
5717 pubKeyDigest = SecSHA1DigestCreate(allocator, certificate->_pubKeyDER.data,
5718 certificate->_pubKeyDER.length);
5719 require_quiet(pubKeyDigest != NULL, out);
5720 #if 0
5721 /* We still need to figure out how to deal with multi valued attributes. */
5722 alias = SecCertificateCopyRFC822Names(certificate);
5723 label = SecCertificateCopySubjectSummary(certificate);
5724 #else
5725 alias = NULL;
5726 label = NULL;
5727 #endif
5728
5729 DICT_ADDPAIR(kSecClass, kSecClassCertificate);
5730 DICT_ADDPAIR(kSecAttrCertificateType, certificateType);
5731 DICT_ADDPAIR(kSecAttrCertificateEncoding, certificateEncoding);
5732 if (label) {
5733 DICT_ADDPAIR(kSecAttrLabel, label);
5734 }
5735 if (alias) {
5736 DICT_ADDPAIR(kSecAttrAlias, alias);
5737 }
5738 if (isData(certificate->_normalizedSubject)) {
5739 DICT_ADDPAIR(kSecAttrSubject, certificate->_normalizedSubject);
5740 }
5741 require_quiet(isData(certificate->_normalizedIssuer), out);
5742 DICT_ADDPAIR(kSecAttrIssuer, certificate->_normalizedIssuer);
5743 require_quiet(isData(certificate->_serialNumber), out);
5744 DICT_ADDPAIR(kSecAttrSerialNumber, certificate->_serialNumber);
5745 if (skid) {
5746 DICT_ADDPAIR(kSecAttrSubjectKeyID, skid);
5747 }
5748 DICT_ADDPAIR(kSecAttrPublicKeyHash, pubKeyDigest);
5749 DICT_ADDPAIR(kSecValueData, certData);
5750 dict = DICT_CREATE(allocator);
5751
5752 out:
5753 CFReleaseSafe(label);
5754 CFReleaseSafe(alias);
5755 CFReleaseSafe(pubKeyDigest);
5756 CFReleaseSafe(certData);
5757 CFReleaseSafe(certificateEncoding);
5758 CFReleaseSafe(certificateType);
5759
5760 return dict;
5761 }
5762
5763 SecCertificateRef SecCertificateCreateFromAttributeDictionary(
5764 CFDictionaryRef refAttributes) {
5765 /* @@@ Support having an allocator in refAttributes. */
5766 CFAllocatorRef allocator = NULL;
5767 CFDataRef data = CFDictionaryGetValue(refAttributes, kSecValueData);
5768 return data ? SecCertificateCreateWithData(allocator, data) : NULL;
5769 }
5770 #endif
5771
5772 static bool _SecCertificateIsSelfSigned(SecCertificateRef certificate) {
5773 if (certificate->_isSelfSigned == kSecSelfSignedUnknown) {
5774 certificate->_isSelfSigned = kSecSelfSignedFalse;
5775 SecKeyRef publicKey = NULL;
5776 require(SecCertificateIsCertificate(certificate), out);
5777 require(publicKey = SecCertificateCopyKey(certificate), out);
5778 CFDataRef normalizedIssuer =
5779 SecCertificateGetNormalizedIssuerContent(certificate);
5780 CFDataRef normalizedSubject =
5781 SecCertificateGetNormalizedSubjectContent(certificate);
5782 require_quiet(normalizedIssuer && normalizedSubject &&
5783 CFEqual(normalizedIssuer, normalizedSubject), out);
5784
5785 CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(certificate);
5786 CFDataRef subjectKeyID = SecCertificateGetSubjectKeyID(certificate);
5787 if (authorityKeyID) {
5788 require_quiet(subjectKeyID && CFEqual(subjectKeyID, authorityKeyID), out);
5789 }
5790
5791 require_noerr_quiet(SecCertificateIsSignedBy(certificate, publicKey), out);
5792
5793 certificate->_isSelfSigned = kSecSelfSignedTrue;
5794 out:
5795 CFReleaseSafe(publicKey);
5796 }
5797
5798 return (certificate->_isSelfSigned == kSecSelfSignedTrue);
5799 }
5800
5801 bool SecCertificateIsCA(SecCertificateRef certificate) {
5802 bool result = false;
5803 require(SecCertificateIsCertificate(certificate), out);
5804 if (SecCertificateVersion(certificate) >= 3) {
5805 const SecCEBasicConstraints *basicConstraints = SecCertificateGetBasicConstraints(certificate);
5806 result = (basicConstraints && basicConstraints->isCA);
5807 }
5808 else {
5809 result = _SecCertificateIsSelfSigned(certificate);
5810 }
5811 out:
5812 return result;
5813 }
5814
5815 bool SecCertificateIsSelfSignedCA(SecCertificateRef certificate) {
5816 return (_SecCertificateIsSelfSigned(certificate) && SecCertificateIsCA(certificate));
5817 }
5818
5819 OSStatus SecCertificateIsSelfSigned(SecCertificateRef certificate, Boolean *isSelfSigned) {
5820 if (!SecCertificateIsCertificate(certificate)) {
5821 return errSecInvalidCertificate;
5822 }
5823 if (!isSelfSigned) {
5824 return errSecParam;
5825 }
5826 *isSelfSigned = _SecCertificateIsSelfSigned(certificate);
5827 return errSecSuccess;
5828 }
5829
5830 SecKeyUsage SecCertificateGetKeyUsage(SecCertificateRef certificate) {
5831 if (!certificate) {
5832 return kSecKeyUsageUnspecified;
5833 }
5834 return certificate->_keyUsage;
5835 }
5836
5837 CFArrayRef SecCertificateCopyExtendedKeyUsage(SecCertificateRef certificate)
5838 {
5839 CFMutableArrayRef extended_key_usage_oids =
5840 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
5841 require_quiet(certificate && extended_key_usage_oids, out);
5842 int ix;
5843 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5844 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5845 if (extn->extnID.length == oidExtendedKeyUsage.length &&
5846 !memcmp(extn->extnID.data, oidExtendedKeyUsage.data, extn->extnID.length)) {
5847 DERTag tag;
5848 DERSequence derSeq;
5849 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &derSeq);
5850 require_noerr_quiet(drtn, out);
5851 require_quiet(tag == ASN1_CONSTR_SEQUENCE, out);
5852 DERDecodedInfo currDecoded;
5853
5854 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
5855 require_quiet(currDecoded.tag == ASN1_OBJECT_ID, out);
5856 CFDataRef oid = CFDataCreate(kCFAllocatorDefault,
5857 currDecoded.content.data, currDecoded.content.length);
5858 require_quiet(oid, out);
5859 CFArrayAppendValue(extended_key_usage_oids, oid);
5860 CFReleaseNull(oid);
5861 }
5862 require_quiet(drtn == DR_EndOfSequence, out);
5863 return extended_key_usage_oids;
5864 }
5865 }
5866 out:
5867 CFReleaseSafe(extended_key_usage_oids);
5868 return NULL;
5869 }
5870
5871 CFArrayRef SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate)
5872 {
5873 require_quiet(certificate, out);
5874 int ix;
5875
5876 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5877 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5878 if (extn->extnID.length == oidGoogleEmbeddedSignedCertificateTimestamp.length &&
5879 !memcmp(extn->extnID.data, oidGoogleEmbeddedSignedCertificateTimestamp.data, extn->extnID.length)) {
5880 /* Got the SCT oid */
5881 DERDecodedInfo sctList;
5882 DERReturn drtn = DERDecodeItem(&extn->extnValue, &sctList);
5883 require_noerr_quiet(drtn, out);
5884 require_quiet(sctList.tag == ASN1_OCTET_STRING, out);
5885 return SecCreateSignedCertificateTimestampsArrayFromSerializedSCTList(sctList.content.data, sctList.content.length);
5886 }
5887 }
5888 out:
5889 return NULL;
5890 }
5891
5892
5893 static bool matches_expected(DERItem der, CFTypeRef expected) {
5894 if (der.length > 1) {
5895 DERDecodedInfo decoded;
5896 DERDecodeItem(&der, &decoded);
5897 switch (decoded.tag) {
5898 case ASN1_NULL:
5899 {
5900 return decoded.content.length == 0 && expected == NULL;
5901 }
5902 break;
5903
5904 case ASN1_IA5_STRING:
5905 case ASN1_UTF8_STRING: {
5906 if (isString(expected)) {
5907 CFStringRef expectedString = (CFStringRef) expected;
5908 CFStringRef itemString = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, decoded.content.data, decoded.content.length, kCFStringEncodingUTF8, false, kCFAllocatorNull);
5909
5910 bool result = (kCFCompareEqualTo == CFStringCompare(expectedString, itemString, 0));
5911 CFReleaseNull(itemString);
5912 return result;
5913 }
5914 }
5915 break;
5916
5917 case ASN1_OCTET_STRING: {
5918 if (isData(expected)) {
5919 CFDataRef expectedData = (CFDataRef) expected;
5920 CFDataRef itemData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, decoded.content.data, decoded.content.length, kCFAllocatorNull);
5921
5922 bool result = CFEqual(expectedData, itemData);
5923 CFReleaseNull(itemData);
5924 return result;
5925 }
5926 }
5927 break;
5928
5929 case ASN1_INTEGER: {
5930 SInt32 expected_value = 0;
5931 if (isString(expected))
5932 {
5933 CFStringRef aStr = (CFStringRef)expected;
5934 expected_value = CFStringGetIntValue(aStr);
5935 }
5936 else if (isNumber(expected))
5937 {
5938 CFNumberGetValue(expected, kCFNumberSInt32Type, &expected_value);
5939 }
5940
5941 uint32_t num_value = 0;
5942 if (!DERParseInteger(&decoded.content, &num_value))
5943 {
5944 return ((uint32_t)expected_value == num_value);
5945 }
5946 }
5947 break;
5948
5949 default:
5950 break;
5951 }
5952 }
5953
5954 return false;
5955 }
5956
5957 static bool cert_contains_marker_extension_value(SecCertificateRef certificate, CFDataRef oid, CFTypeRef expectedValue)
5958 {
5959 CFIndex ix;
5960 const uint8_t *oid_data = CFDataGetBytePtr(oid);
5961 size_t oid_len = CFDataGetLength(oid);
5962
5963 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
5964 const SecCertificateExtension *extn = &certificate->_extensions[ix];
5965 if (extn->extnID.length == oid_len
5966 && !memcmp(extn->extnID.data, oid_data, extn->extnID.length))
5967 {
5968 return matches_expected(extn->extnValue, expectedValue);
5969 }
5970 }
5971 return false;
5972 }
5973
5974 static bool cert_contains_marker_extension(SecCertificateRef certificate, CFTypeRef oid)
5975 {
5976 return cert_contains_marker_extension_value(certificate, oid, NULL);
5977 }
5978
5979 struct search_context {
5980 bool found;
5981 SecCertificateRef certificate;
5982 };
5983
5984 static bool GetDecimalValueOfString(CFStringRef string, uint32_t* value)
5985 {
5986 CFCharacterSetRef nonDecimalDigit = CFCharacterSetCreateInvertedSet(NULL, CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit));
5987 bool result = false;
5988
5989 if ( CFStringGetLength(string) > 0
5990 && !CFStringFindCharacterFromSet(string, nonDecimalDigit, CFRangeMake(0, CFStringGetLength(string)), kCFCompareForcedOrdering, NULL))
5991 {
5992 if (value)
5993 *value = CFStringGetIntValue(string);
5994 result = true;
5995 }
5996
5997 CFReleaseNull(nonDecimalDigit);
5998
5999 return result;
6000 }
6001
6002 bool SecCertificateIsOidString(CFStringRef oid)
6003 {
6004 if (!oid) return false;
6005 if (2 >= CFStringGetLength(oid)) return false;
6006 bool result = true;
6007
6008 /* oid string only has the allowed characters */
6009 CFCharacterSetRef decimalOid = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("0123456789."));
6010 CFCharacterSetRef nonDecimalOid = CFCharacterSetCreateInvertedSet(NULL, decimalOid);
6011 if (CFStringFindCharacterFromSet(oid, nonDecimalOid, CFRangeMake(0, CFStringGetLength(oid)), kCFCompareForcedOrdering, NULL)) {
6012 result = false;
6013 }
6014
6015 /* first arc is allowed */
6016 UniChar firstArc[2];
6017 CFRange firstTwo = {0, 2};
6018 CFStringGetCharacters(oid, firstTwo, firstArc);
6019 if (firstArc[1] != '.' ||
6020 (firstArc[0] != '0' && firstArc[0] != '1' && firstArc[0] != '2')) {
6021 result = false;
6022 }
6023
6024 CFReleaseNull(decimalOid);
6025 CFReleaseNull(nonDecimalOid);
6026
6027 return result;
6028 }
6029
6030 CFDataRef SecCertificateCreateOidDataFromString(CFAllocatorRef allocator, CFStringRef string)
6031 {
6032 CFMutableDataRef currentResult = NULL;
6033 CFDataRef encodedResult = NULL;
6034
6035 CFArrayRef parts = NULL;
6036 CFIndex count = 0;
6037
6038 if (!string || !SecCertificateIsOidString(string))
6039 goto exit;
6040
6041 parts = CFStringCreateArrayBySeparatingStrings(allocator, string, CFSTR("."));
6042
6043 if (!parts)
6044 goto exit;
6045
6046 count = CFArrayGetCount(parts);
6047 if (count == 0)
6048 goto exit;
6049
6050 // assume no more than 5 bytes needed to represent any part of the oid,
6051 // since we limit parts to 32-bit values,
6052 // but the first two parts only need 1 byte
6053 currentResult = CFDataCreateMutable(allocator, 1+(count-2)*5);
6054
6055 CFStringRef part;
6056 uint32_t x;
6057 uint8_t firstByte;
6058
6059 part = CFArrayGetValueAtIndex(parts, 0);
6060
6061 if (!GetDecimalValueOfString(part, &x) || x > 6)
6062 goto exit;
6063
6064 firstByte = x * 40;
6065
6066
6067 if (count > 1) {
6068 part = CFArrayGetValueAtIndex(parts, 1);
6069
6070 if (!GetDecimalValueOfString(part, &x) || x > 39)
6071 goto exit;
6072
6073 firstByte += x;
6074 }
6075
6076 CFDataAppendBytes(currentResult, &firstByte, 1);
6077
6078 for (CFIndex i = 2; i < count && GetDecimalValueOfString(CFArrayGetValueAtIndex(parts, i), &x); ++i) {
6079 uint8_t b[5] = {0, 0, 0, 0, 0};
6080 b[4] = (x & 0x7F);
6081 b[3] = 0x80 | ((x >> 7) & 0x7F);
6082 b[2] = 0x80 | ((x >> 14) & 0x7F);
6083 b[1] = 0x80 | ((x >> 21) & 0x7F);
6084 b[0] = 0x80 | ((x >> 28) & 0x7F);
6085
6086 // Skip the unused extension bytes.
6087 size_t skipBytes = 0;
6088 while (b[skipBytes] == 0x80)
6089 ++skipBytes;
6090
6091 CFDataAppendBytes(currentResult, b + skipBytes, sizeof(b) - skipBytes);
6092 }
6093
6094 encodedResult = currentResult;
6095 currentResult = NULL;
6096
6097 exit:
6098 CFReleaseNull(parts);
6099 CFReleaseNull(currentResult);
6100
6101 return encodedResult;
6102 }
6103
6104 static void check_for_marker(const void *key, const void *value, void *context)
6105 {
6106 struct search_context * search_ctx = (struct search_context *) context;
6107 CFStringRef key_string = (CFStringRef) key;
6108 CFTypeRef value_ref = (CFTypeRef) value;
6109
6110 // If we could have short-circuited the iteration
6111 // we would have, but the best we can do
6112 // is not waste time comparing once a match
6113 // was found.
6114 if (search_ctx->found)
6115 return;
6116
6117 if (!isString(key_string))
6118 return;
6119
6120 CFDataRef key_data = SecCertificateCreateOidDataFromString(NULL, key_string);
6121
6122 if (!isData(key_data))
6123 return;
6124
6125 if (cert_contains_marker_extension_value(search_ctx->certificate, key_data, value_ref))
6126 search_ctx->found = true;
6127
6128 CFReleaseNull(key_data);
6129 }
6130
6131 //
6132 // CFType Ref is either:
6133 //
6134 // CFData - OID to match with no data permitted
6135 // CFString - decimal OID to match
6136 // CFDictionary - OID -> Value table for expected values Single Object or Array
6137 // CFArray - Array of the above.
6138 //
6139 // This returns true if any of the requirements are met.
6140 bool SecCertificateHasMarkerExtension(SecCertificateRef certificate, CFTypeRef oids)
6141 {
6142 if (NULL == certificate || NULL == oids) {
6143 return false;
6144 } else if (CFGetTypeID(oids) == CFArrayGetTypeID()) {
6145 CFIndex ix, length = CFArrayGetCount(oids);
6146 for (ix = 0; ix < length; ix++)
6147 if (SecCertificateHasMarkerExtension(certificate, CFArrayGetValueAtIndex((CFArrayRef)oids, ix)))
6148 return true;
6149 } else if (CFGetTypeID(oids) == CFDictionaryGetTypeID()) {
6150 struct search_context context = { .found = false, .certificate = certificate };
6151 CFDictionaryApplyFunction((CFDictionaryRef) oids, &check_for_marker, &context);
6152 return context.found;
6153 } else if (CFGetTypeID(oids) == CFDataGetTypeID()) {
6154 return cert_contains_marker_extension(certificate, oids);
6155 } else if (CFGetTypeID(oids) == CFStringGetTypeID()) {
6156 CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, oids);
6157 if (dataOid == NULL) return false;
6158 bool result = cert_contains_marker_extension(certificate, dataOid);
6159 CFReleaseNull(dataOid);
6160 return result;
6161 }
6162 return false;
6163 }
6164
6165 // Since trust evaluation checks for the id-pkix-ocsp-nocheck OID marker
6166 // in every certificate, this function caches the OID data once instead of
6167 // parsing the same OID string each time.
6168 //
6169 bool SecCertificateHasOCSPNoCheckMarkerExtension(SecCertificateRef certificate)
6170 {
6171 static CFDataRef sOCSPNoCheckOIDData = NULL;
6172 static dispatch_once_t onceToken;
6173
6174 dispatch_once(&onceToken, ^{
6175 sOCSPNoCheckOIDData = SecCertificateCreateOidDataFromString(NULL, CFSTR("1.3.6.1.5.5.7.48.1.5"));
6176 });
6177 return SecCertificateHasMarkerExtension(certificate, sOCSPNoCheckOIDData);
6178 }
6179
6180 static DERItem *cert_extension_value_for_marker(SecCertificateRef certificate, CFDataRef oid) {
6181 CFIndex ix;
6182 const uint8_t *oid_data = CFDataGetBytePtr(oid);
6183 size_t oid_len = CFDataGetLength(oid);
6184
6185 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
6186 const SecCertificateExtension *extn = &certificate->_extensions[ix];
6187 if (extn->extnID.length == oid_len
6188 && !memcmp(extn->extnID.data, oid_data, extn->extnID.length))
6189 {
6190 return (DERItem *)&extn->extnValue;
6191 }
6192 }
6193 return NULL;
6194 }
6195
6196 //
6197 // CFType Ref is either:
6198 //
6199 // CFData - OID to match with no data permitted
6200 // CFString - decimal OID to match
6201 //
6202 DERItem *SecCertificateGetExtensionValue(SecCertificateRef certificate, CFTypeRef oid) {
6203 if (!certificate || !oid) {
6204 return NULL;
6205 }
6206
6207 if(CFGetTypeID(oid) == CFDataGetTypeID()) {
6208 return cert_extension_value_for_marker(certificate, oid);
6209 } else if (CFGetTypeID(oid) == CFStringGetTypeID()) {
6210 CFDataRef dataOid = SecCertificateCreateOidDataFromString(NULL, oid);
6211 if (dataOid == NULL) return NULL;
6212 DERItem *result = cert_extension_value_for_marker(certificate, dataOid);
6213 CFReleaseNull(dataOid);
6214 return result;
6215 }
6216
6217 return NULL;
6218 }
6219
6220 CFDataRef SecCertificateCopyExtensionValue(SecCertificateRef certificate, CFTypeRef extensionOID, bool *isCritical) {
6221 if (!certificate || !extensionOID) {
6222 return NULL;
6223 }
6224
6225 CFDataRef oid = NULL, extensionValue = NULL;
6226 if (CFGetTypeID(extensionOID) == CFDataGetTypeID()) {
6227 oid = CFRetainSafe(extensionOID);
6228 } else if (CFGetTypeID(extensionOID) == CFStringGetTypeID()) {
6229 oid = SecCertificateCreateOidDataFromString(NULL, extensionOID);
6230 }
6231 if (!oid) {
6232 return NULL;
6233 }
6234
6235 CFIndex ix;
6236 const uint8_t *oid_data = CFDataGetBytePtr(oid);
6237 size_t oid_len = CFDataGetLength(oid);
6238
6239 for (ix = 0; ix < certificate->_extensionCount; ++ix) {
6240 const SecCertificateExtension *extn = &certificate->_extensions[ix];
6241 if (extn->extnID.length == oid_len
6242 && !memcmp(extn->extnID.data, oid_data, extn->extnID.length))
6243 {
6244 if (isCritical) {
6245 *isCritical = extn->critical;
6246 }
6247 extensionValue = CFDataCreate(NULL, extn->extnValue.data, extn->extnValue.length);
6248 break;
6249 }
6250 }
6251
6252 CFReleaseNull(oid);
6253 return extensionValue;
6254 }
6255
6256 CFDataRef SecCertificateCopyiAPAuthCapabilities(SecCertificateRef certificate) {
6257 if (!certificate) {
6258 return NULL;
6259 }
6260 CFDataRef extensionData = NULL;
6261 DERItem *extensionValue = NULL;
6262 extensionValue = SecCertificateGetExtensionValue(certificate,
6263 CFSTR("1.2.840.113635.100.6.36"));
6264 require_quiet(extensionValue, out);
6265 /* The extension is a octet string containing the DER-encoded 32-byte octet string */
6266 require_quiet(extensionValue->length == 34, out);
6267 DERDecodedInfo decodedValue;
6268 require_noerr_quiet(DERDecodeItem(extensionValue, &decodedValue), out);
6269 if (decodedValue.tag == ASN1_OCTET_STRING) {
6270 require_quiet(decodedValue.content.length == 32, out);
6271 extensionData = CFDataCreate(NULL, decodedValue.content.data,
6272 decodedValue.content.length);
6273 } else {
6274 require_quiet(extensionValue->data[33] == 0x00 &&
6275 extensionValue->data[32] == 0x00, out);
6276 extensionData = CFDataCreate(NULL, extensionValue->data, 32);
6277 }
6278 out:
6279 return extensionData;
6280 }
6281
6282 #if 0
6283 /* From iapd IAPAuthenticationTypes.h */
6284 typedef struct IapCertSerialNumber
6285 {
6286 uint8_t xservID; // Xserver ID
6287 uint8_t hsmID; // Hardware security module ID (generated cert)
6288 uint8_t delimiter01; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6289 uint8_t dateYear; // Date year cert was issued
6290 uint8_t dateMonth; // Date month cert was issued
6291 uint8_t dateDay; // Date day cert was issued
6292 uint8_t delimiter02; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6293 uint8_t devClass; // iAP device class (maps to lingo permissions)
6294 uint8_t delimiter03; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6295 uint8_t batchNumHi; // Batch number high byte (15:08)
6296 uint8_t batchNumLo; // Batch number low byte (07:00)
6297 uint8_t delimiter04; // Field delimiter (IAP_CERT_FIELD_DELIMITER)
6298 uint8_t serialNumHi; // Serial number high byte (23:16)
6299 uint8_t serialNumMid; // Serial number middle byte (15:08)
6300 uint8_t serialNumLo; // Serial number low byte (07:00)
6301
6302 } IapCertSerialNumber_t, *pIapCertSerialNumber_t;
6303 #endif
6304
6305 #define IAP_CERT_FIELD_DELIMITER 0xAA // "Apple_Accessory" delimiter
6306 SeciAuthVersion SecCertificateGetiAuthVersion(SecCertificateRef certificate) {
6307 if (!certificate) {
6308 return kSeciAuthInvalid;
6309 }
6310 if (NULL != SecCertificateGetExtensionValue(certificate,
6311 CFSTR("1.2.840.113635.100.6.36"))) {
6312 /* v3 Capabilities Extension */
6313 return kSeciAuthVersion3;
6314 }
6315 if (NULL != SecCertificateGetExtensionValue(certificate,
6316 CFSTR("1.2.840.113635.100.6.59.1"))) {
6317 /* SW Auth General Capabilities Extension */
6318 return kSeciAuthVersionSW;
6319 }
6320 DERItem serialNumber = certificate->_serialNum;
6321 require_quiet(serialNumber.data, out);
6322 require_quiet(serialNumber.length == 15, out);
6323 require_quiet(serialNumber.data[2] == IAP_CERT_FIELD_DELIMITER &&
6324 serialNumber.data[6] == IAP_CERT_FIELD_DELIMITER &&
6325 serialNumber.data[8] == IAP_CERT_FIELD_DELIMITER &&
6326 serialNumber.data[11] == IAP_CERT_FIELD_DELIMITER, out);
6327 return kSeciAuthVersion2;
6328 out:
6329 return kSeciAuthInvalid;
6330 }
6331
6332 static CFStringRef SecCertificateiAPSWAuthCapabilitiesTypeToOID(SeciAPSWAuthCapabilitiesType type) {
6333 CFStringRef extensionOID = NULL;
6334 /* Get the oid for the type */
6335 if (type == kSeciAPSWAuthGeneralCapabilities) {
6336 extensionOID = CFSTR("1.2.840.113635.100.6.59.1");
6337 } else if (type == kSeciAPSWAuthAirPlayCapabilities) {
6338 extensionOID = CFSTR("1.2.840.113635.100.6.59.2");
6339 } else if (type == kSeciAPSWAuthHomeKitCapabilities) {
6340 extensionOID = CFSTR("1.2.840.113635.100.6.59.3");
6341 }
6342 return extensionOID;
6343 }
6344
6345 CFDataRef SecCertificateCopyiAPSWAuthCapabilities(SecCertificateRef certificate, SeciAPSWAuthCapabilitiesType type) {
6346 if (!certificate) {
6347 return NULL;
6348 }
6349 CFDataRef extensionData = NULL;
6350 DERItem *extensionValue = NULL;
6351 CFStringRef extensionOID = SecCertificateiAPSWAuthCapabilitiesTypeToOID(type);
6352 require_quiet(extensionOID, out);
6353 extensionValue = SecCertificateGetExtensionValue(certificate, extensionOID);
6354 require_quiet(extensionValue, out);
6355 /* The extension is a octet string containing the DER-encoded variable-length octet string */
6356 DERDecodedInfo decodedValue;
6357 require_noerr_quiet(DERDecodeItem(extensionValue, &decodedValue), out);
6358 if (decodedValue.tag == ASN1_OCTET_STRING) {
6359 extensionData = CFDataCreate(NULL, decodedValue.content.data,
6360 decodedValue.content.length);
6361 }
6362 out:
6363 return extensionData;
6364 }
6365
6366 CFStringRef SecCertificateCopyComponentType(SecCertificateRef certificate) {
6367 if (!certificate) {
6368 return NULL;
6369 }
6370 CFStringRef componentType = NULL;
6371 DERItem *extensionValue = SecCertificateGetExtensionValue(certificate, CFSTR("1.2.840.113635.100.11.1"));
6372 require_quiet(extensionValue, out);
6373 /* The componentType is an IA5String */
6374 DERDecodedInfo decodedValue;
6375 require_noerr_quiet(DERDecodeItem(extensionValue, &decodedValue), out);
6376 if (decodedValue.tag == ASN1_IA5_STRING) {
6377 componentType = CFStringCreateWithBytes(NULL, decodedValue.content.data, decodedValue.content.length, kCFStringEncodingASCII, false);
6378 }
6379 out:
6380 return componentType;
6381 }
6382
6383 SecCertificateRef SecCertificateCreateWithPEM(CFAllocatorRef allocator,
6384 CFDataRef pem_certificate)
6385 {
6386 static const char begin_cert[] = "-----BEGIN CERTIFICATE-----\n";
6387 static const char end_cert[] = "-----END CERTIFICATE-----\n";
6388 uint8_t *base64_data = NULL;
6389 SecCertificateRef cert = NULL;
6390 const unsigned char *data = CFDataGetBytePtr(pem_certificate);
6391 const size_t length = CFDataGetLength(pem_certificate);
6392 char *begin = strnstr((const char *)data, begin_cert, length);
6393 char *end = strnstr((const char *)data, end_cert, length);
6394 if (!begin || !end)
6395 return NULL;
6396 begin += sizeof(begin_cert) - 1;
6397 size_t base64_length = SecBase64Decode(begin, end - begin, NULL, 0);
6398 if (base64_length && (base64_length < (size_t)CFDataGetLength(pem_certificate))) {
6399 require_quiet(base64_data = calloc(1, base64_length), out);
6400 require_action_quiet(base64_length = SecBase64Decode(begin, end - begin, base64_data, base64_length), out, free(base64_data));
6401 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, base64_data, base64_length);
6402 free(base64_data);
6403 }
6404 out:
6405 return cert;
6406 }
6407
6408
6409 //
6410 // -- MARK -- XPC encoding/decoding
6411 //
6412
6413 bool SecCertificateAppendToXPCArray(SecCertificateRef certificate, xpc_object_t xpc_certificates, CFErrorRef *error) {
6414 if (!certificate)
6415 return true; // NOOP
6416
6417 size_t length = SecCertificateGetLength(certificate);
6418 const uint8_t *bytes = SecCertificateGetBytePtr(certificate);
6419 #if SECTRUST_VERBOSE_DEBUG
6420 secerror("cert=0x%lX length=%d bytes=0x%lX", (uintptr_t)certificate, (int)length, (uintptr_t)bytes);
6421 #endif
6422 if (!length || !bytes) {
6423 return SecError(errSecParam, error, CFSTR("failed to der encode certificate"));
6424 }
6425 xpc_array_set_data(xpc_certificates, XPC_ARRAY_APPEND, bytes, length);
6426 return true;
6427 }
6428
6429 SecCertificateRef SecCertificateCreateWithXPCArrayAtIndex(xpc_object_t xpc_certificates, size_t index, CFErrorRef *error) {
6430 SecCertificateRef certificate = NULL;
6431 size_t length = 0;
6432 const uint8_t *bytes = xpc_array_get_data(xpc_certificates, index, &length);
6433 if (bytes) {
6434 certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length);
6435 }
6436 if (!certificate) {
6437 SecError(errSecParam, error, CFSTR("certificates[%zu] failed to decode"), index);
6438 }
6439 return certificate;
6440 }
6441
6442 xpc_object_t SecCertificateArrayCopyXPCArray(CFArrayRef certificates, CFErrorRef *error) {
6443 xpc_object_t xpc_certificates;
6444 require_action_quiet(xpc_certificates = xpc_array_create(NULL, 0), exit,
6445 SecError(errSecAllocate, error, CFSTR("failed to create xpc_array")));
6446 CFIndex ix, count = CFArrayGetCount(certificates);
6447 for (ix = 0; ix < count; ++ix) {
6448 SecCertificateRef certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, ix);
6449 #if SECTRUST_VERBOSE_DEBUG
6450 CFIndex length = SecCertificateGetLength(certificate);
6451 const UInt8 *bytes = SecCertificateGetBytePtr(certificate);
6452 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);
6453 #endif
6454 if (!SecCertificateAppendToXPCArray(certificate, xpc_certificates, error)) {
6455 xpc_release(xpc_certificates);
6456 xpc_certificates = NULL;
6457 break;
6458 }
6459 }
6460
6461 exit:
6462 return xpc_certificates;
6463 }
6464
6465 CFArrayRef SecCertificateXPCArrayCopyArray(xpc_object_t xpc_certificates, CFErrorRef *error) {
6466 CFMutableArrayRef certificates = NULL;
6467 require_action_quiet(xpc_get_type(xpc_certificates) == XPC_TYPE_ARRAY, exit,
6468 SecError(errSecParam, error, CFSTR("certificates xpc value is not an array")));
6469 size_t count = xpc_array_get_count(xpc_certificates);
6470 require_action_quiet(certificates = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks), exit,
6471 SecError(errSecAllocate, error, CFSTR("failed to create CFArray of capacity %zu"), count));
6472
6473 size_t ix;
6474 for (ix = 0; ix < count; ++ix) {
6475 SecCertificateRef cert = SecCertificateCreateWithXPCArrayAtIndex(xpc_certificates, ix, error);
6476 if (!cert) {
6477 CFRelease(certificates);
6478 return NULL;
6479 }
6480 CFArraySetValueAtIndex(certificates, ix, cert);
6481 CFRelease(cert);
6482 }
6483
6484 exit:
6485 return certificates;
6486 }
6487
6488 #define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
6489
6490
6491 static CFArrayRef CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType, CFErrorRef* error)
6492 {
6493 __block CFArrayRef result = NULL;
6494
6495 do_if_registered(ota_CopyEscrowCertificates, escrowRootType, error);
6496
6497 securityd_send_sync_and_do(kSecXPCOpOTAGetEscrowCertificates, error,
6498 ^bool(xpc_object_t message, CFErrorRef *blockError)
6499 {
6500 xpc_dictionary_set_uint64(message, "escrowType", (uint64_t)escrowRootType);
6501 return true;
6502 },
6503 ^bool(xpc_object_t response, CFErrorRef *blockError)
6504 {
6505 xpc_object_t xpc_array = xpc_dictionary_get_value(response, kSecXPCKeyResult);
6506
6507 if (response && (NULL != xpc_array)) {
6508 result = (CFArrayRef)_CFXPCCreateCFObjectFromXPCObject(xpc_array);
6509 }
6510 else {
6511 return SecError(errSecInternal, blockError, CFSTR("Did not get the Escrow certificates"));
6512 }
6513 return result != NULL;
6514 });
6515 return result;
6516 }
6517
6518 CFArrayRef SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType)
6519 {
6520 CFArrayRef result = NULL;
6521 int iCnt;
6522 CFDataRef certData = NULL;
6523 int numRoots = 0;
6524
6525 if (kSecCertificateBaselineEscrowRoot == escrowRootType ||
6526 kSecCertificateBaselinePCSEscrowRoot == escrowRootType ||
6527 kSecCertificateBaselineEscrowBackupRoot == escrowRootType ||
6528 kSecCertificateBaselineEscrowEnrollmentRoot == escrowRootType)
6529 {
6530 // The request is for the base line certificates.
6531 // Use the hard coded data to generate the return array.
6532 struct RootRecord** pEscrowRoots;
6533 switch (escrowRootType) {
6534 case kSecCertificateBaselineEscrowRoot:
6535 numRoots = kNumberOfBaseLineEscrowRoots;
6536 pEscrowRoots = kBaseLineEscrowRoots;
6537 break;
6538 case kSecCertificateBaselinePCSEscrowRoot:
6539 numRoots = kNumberOfBaseLinePCSEscrowRoots;
6540 pEscrowRoots = kBaseLinePCSEscrowRoots;
6541 break;
6542 case kSecCertificateBaselineEscrowBackupRoot:
6543 numRoots = kNumberOfBaseLineEscrowBackupRoots;
6544 pEscrowRoots = kBaseLineEscrowBackupRoots;
6545 break;
6546 case kSecCertificateBaselineEscrowEnrollmentRoot:
6547 default:
6548 numRoots = kNumberOfBaseLineEscrowEnrollmentRoots;
6549 pEscrowRoots = kBaseLineEscrowEnrollmentRoots;
6550 break;
6551 }
6552
6553 // Get the hard coded set of roots
6554 SecCertificateRef baseLineCerts[numRoots];
6555 struct RootRecord* pRootRecord = NULL;
6556
6557 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6558 pRootRecord = pEscrowRoots[iCnt];
6559 if (NULL != pRootRecord && pRootRecord->_length > 0 && NULL != pRootRecord->_bytes) {
6560 certData = CFDataCreate(kCFAllocatorDefault, pRootRecord->_bytes, pRootRecord->_length);
6561 if (NULL != certData) {
6562 baseLineCerts[iCnt] = SecCertificateCreateWithData(kCFAllocatorDefault, certData);
6563 CFRelease(certData);
6564 }
6565 }
6566 }
6567 result = CFArrayCreate(kCFAllocatorDefault, (const void **)baseLineCerts, numRoots, &kCFTypeArrayCallBacks);
6568 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6569 if (NULL != baseLineCerts[iCnt]) {
6570 CFRelease(baseLineCerts[iCnt]);
6571 }
6572 }
6573 } else {
6574 // The request is for the current certificates.
6575 CFErrorRef error = NULL;
6576 CFArrayRef cert_datas = CopyEscrowCertificates(escrowRootType, &error);
6577 if (NULL != error || NULL == cert_datas) {
6578 if (NULL != error) {
6579 CFRelease(error);
6580 }
6581 if (NULL != cert_datas) {
6582 CFRelease(cert_datas);
6583 }
6584 return result;
6585 }
6586
6587 numRoots = (int)(CFArrayGetCount(cert_datas));
6588
6589 SecCertificateRef assetCerts[numRoots];
6590 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6591 certData = (CFDataRef)CFArrayGetValueAtIndex(cert_datas, iCnt);
6592 if (NULL != certData) {
6593 SecCertificateRef aCertRef = SecCertificateCreateWithData(kCFAllocatorDefault, certData);
6594 assetCerts[iCnt] = aCertRef;
6595 }
6596 else {
6597 assetCerts[iCnt] = NULL;
6598 }
6599 }
6600
6601 if (numRoots > 0) {
6602 result = CFArrayCreate(kCFAllocatorDefault, (const void **)assetCerts, numRoots, &kCFTypeArrayCallBacks);
6603 for (iCnt = 0; iCnt < numRoots; iCnt++) {
6604 if (NULL != assetCerts[iCnt]) {
6605 CFRelease(assetCerts[iCnt]);
6606 }
6607 }
6608 }
6609 CFReleaseSafe(cert_datas);
6610 }
6611 return result;
6612 }
6613
6614 static CFDictionaryRef CopyTrustedCTLogs(CFErrorRef* error)
6615 {
6616 __block CFDictionaryRef result = NULL;
6617
6618 // call function directly and return if we are built in server mode
6619 do_if_registered(sec_ota_pki_copy_trusted_ct_logs, error);
6620
6621 securityd_send_sync_and_do(kSecXPCOpOTAPKICopyTrustedCTLogs, error,
6622 ^bool(xpc_object_t message, CFErrorRef *blockError) {
6623 // input: set message parameters here
6624 return true;
6625 }, ^bool(xpc_object_t response, CFErrorRef *blockError) {
6626 // output: get dictionary from response object
6627 xpc_object_t xpc_dictionary = NULL;
6628 if (response) {
6629 xpc_dictionary = xpc_dictionary_get_value(response, kSecXPCKeyResult);
6630 }
6631 if (xpc_dictionary && (xpc_get_type(xpc_dictionary) == XPC_TYPE_DICTIONARY)) {
6632 result = (CFDictionaryRef)_CFXPCCreateCFObjectFromXPCObject(xpc_dictionary);
6633 } else {
6634 return SecError(errSecInternal, blockError, CFSTR("Unable to get CT logs"));
6635 }
6636 return result != NULL;
6637 });
6638 return result;
6639 }
6640
6641 #define CTLOG_KEYID_LENGTH 32 /* key id data length */
6642
6643 static CFDictionaryRef CopyCTLogForKeyID(CFDataRef keyID, CFErrorRef* error)
6644 {
6645 __block CFDictionaryRef result = NULL;
6646 if (!isData(keyID)) {
6647 (void) SecError(errSecParam, error, CFSTR("keyID was not a valid CFDataRef"));
6648 return result;
6649 }
6650 const void *p = CFDataGetBytePtr(keyID);
6651 if (!p || CFDataGetLength(keyID) != CTLOG_KEYID_LENGTH) {
6652 (void) SecError(errSecParam, error, CFSTR("keyID data was not the expected length"));
6653 return result;
6654 }
6655 // call function directly and return if we are built in server mode
6656 do_if_registered(sec_ota_pki_copy_ct_log_for_keyid, keyID, error);
6657
6658 securityd_send_sync_and_do(kSecXPCOpOTAPKICopyCTLogForKeyID, error,
6659 ^bool(xpc_object_t message, CFErrorRef *blockError) {
6660 // input: set message parameters here
6661 xpc_dictionary_set_data(message, kSecXPCData, p, CTLOG_KEYID_LENGTH);
6662 return true;
6663 }, ^bool(xpc_object_t response, CFErrorRef *blockError) {
6664 // output: get dictionary from response object
6665 xpc_object_t xpc_dictionary = NULL;
6666 if (response) {
6667 xpc_dictionary = xpc_dictionary_get_value(response, kSecXPCKeyResult);
6668 }
6669 if (xpc_dictionary && (xpc_get_type(xpc_dictionary) == XPC_TYPE_DICTIONARY)) {
6670 result = (CFDictionaryRef)_CFXPCCreateCFObjectFromXPCObject(xpc_dictionary);
6671 } else {
6672 return SecError(errSecInternal, blockError, CFSTR("Unable to match CT log"));
6673 }
6674 return result != NULL;
6675 });
6676 return result;
6677 }
6678
6679 CFDictionaryRef SecCertificateCopyTrustedCTLogs(void)
6680 {
6681 CFErrorRef localError = NULL;
6682 CFDictionaryRef result = CopyTrustedCTLogs(&localError);
6683 CFReleaseSafe(localError);
6684 return result;
6685 }
6686
6687 CFDictionaryRef SecCertificateCopyCTLogForKeyID(CFDataRef keyID)
6688 {
6689 CFErrorRef localError = NULL;
6690 CFDictionaryRef result = CopyCTLogForKeyID(keyID, &localError);
6691 CFReleaseSafe(localError);
6692 return result;
6693 }
6694
6695 SEC_CONST_DECL (kSecSignatureDigestAlgorithmUnknown, "SignatureDigestUnknown");
6696 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD2, "SignatureDigestMD2");
6697 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD4, "SignatureDigestMD4");
6698 SEC_CONST_DECL (kSecSignatureDigestAlgorithmMD5, "SignatureDigestMD5");
6699 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA1, "SignatureDigestSHA1");
6700 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA224, "SignatureDigestSHA224");
6701 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA256, "SignatureDigestSHA256");
6702 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA384, "SignatureDigestSHA284");
6703 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA512, "SignatureDigestSHA512");
6704
6705 SecSignatureHashAlgorithm SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate)
6706 {
6707 SecSignatureHashAlgorithm result = kSecSignatureHashAlgorithmUnknown;
6708 DERAlgorithmId *algId = (certificate) ? &certificate->_tbsSigAlg : NULL;
6709 const DERItem *algOid = (algId) ? &algId->oid : NULL;
6710 while (algOid) {
6711 if (!algOid->data || !algOid->length) {
6712 break;
6713 }
6714 /* classify the signature algorithm OID into one of our known types */
6715 if (DEROidCompare(algOid, &oidSha512Ecdsa) ||
6716 DEROidCompare(algOid, &oidSha512Rsa) ||
6717 DEROidCompare(algOid, &oidSha512)) {
6718 result = kSecSignatureHashAlgorithmSHA512;
6719 break;
6720 }
6721 if (DEROidCompare(algOid, &oidSha384Ecdsa) ||
6722 DEROidCompare(algOid, &oidSha384Rsa) ||
6723 DEROidCompare(algOid, &oidSha384)) {
6724 result = kSecSignatureHashAlgorithmSHA384;
6725 break;
6726 }
6727 if (DEROidCompare(algOid, &oidSha256Ecdsa) ||
6728 DEROidCompare(algOid, &oidSha256Rsa) ||
6729 DEROidCompare(algOid, &oidSha256)) {
6730 result = kSecSignatureHashAlgorithmSHA256;
6731 break;
6732 }
6733 if (DEROidCompare(algOid, &oidSha224Ecdsa) ||
6734 DEROidCompare(algOid, &oidSha224Rsa) ||
6735 DEROidCompare(algOid, &oidSha224)) {
6736 result = kSecSignatureHashAlgorithmSHA224;
6737 break;
6738 }
6739 if (DEROidCompare(algOid, &oidSha1Ecdsa) ||
6740 DEROidCompare(algOid, &oidSha1Rsa) ||
6741 DEROidCompare(algOid, &oidSha1Dsa) ||
6742 DEROidCompare(algOid, &oidSha1DsaOIW) ||
6743 DEROidCompare(algOid, &oidSha1DsaCommonOIW) ||
6744 DEROidCompare(algOid, &oidSha1RsaOIW) ||
6745 DEROidCompare(algOid, &oidSha1Fee) ||
6746 DEROidCompare(algOid, &oidSha1)) {
6747 result = kSecSignatureHashAlgorithmSHA1;
6748 break;
6749 }
6750 if (DEROidCompare(algOid, &oidMd5Rsa) ||
6751 DEROidCompare(algOid, &oidMd5Fee) ||
6752 DEROidCompare(algOid, &oidMd5)) {
6753 result = kSecSignatureHashAlgorithmMD5;
6754 break;
6755 }
6756 if (DEROidCompare(algOid, &oidMd4Rsa) ||
6757 DEROidCompare(algOid, &oidMd4)) {
6758 result = kSecSignatureHashAlgorithmMD4;
6759 break;
6760 }
6761 if (DEROidCompare(algOid, &oidMd2Rsa) ||
6762 DEROidCompare(algOid, &oidMd2)) {
6763 result = kSecSignatureHashAlgorithmMD2;
6764 break;
6765 }
6766 break;
6767 }
6768
6769 return result;
6770 }
6771
6772 CFArrayRef SecCertificateCopyiPhoneDeviceCAChain(void) {
6773 CFMutableArrayRef result = NULL;
6774 SecCertificateRef iPhoneDeviceCA = NULL, iPhoneCA = NULL, appleRoot = NULL;
6775
6776 require_quiet(iPhoneDeviceCA = SecCertificateCreateWithBytes(NULL, _AppleiPhoneDeviceCA, sizeof(_AppleiPhoneDeviceCA)),
6777 errOut);
6778 require_quiet(iPhoneCA = SecCertificateCreateWithBytes(NULL, _AppleiPhoneCA, sizeof(_AppleiPhoneCA)),
6779 errOut);
6780 require_quiet(appleRoot = SecCertificateCreateWithBytes(NULL, _AppleRootCA, sizeof(_AppleRootCA)),
6781 errOut);
6782
6783 require_quiet(result = CFArrayCreateMutable(NULL, 3, &kCFTypeArrayCallBacks), errOut);
6784 CFArrayAppendValue(result, iPhoneDeviceCA);
6785 CFArrayAppendValue(result, iPhoneCA);
6786 CFArrayAppendValue(result, appleRoot);
6787
6788 errOut:
6789 CFReleaseNull(iPhoneDeviceCA);
6790 CFReleaseNull(iPhoneCA);
6791 CFReleaseNull(appleRoot);
6792 return result;
6793 }
6794
6795 bool SecCertificateGetDeveloperIDDate(SecCertificateRef certificate, CFAbsoluteTime *time, CFErrorRef *error) {
6796 if (!certificate || !time) {
6797 return SecError(errSecParam, error, CFSTR("DeveloperID Date parsing: missing required input"));
6798 }
6799 DERItem *extensionValue = SecCertificateGetExtensionValue(certificate, CFSTR("1.2.840.113635.100.6.1.33"));
6800 if (!extensionValue) {
6801 return SecError(errSecMissingRequiredExtension, error, CFSTR("DeveloperID Date parsing: extension not found"));
6802 }
6803 DERDecodedInfo decodedValue;
6804 if (DERDecodeItem(extensionValue, &decodedValue) != DR_Success) {
6805 return SecError(errSecDecode, error, CFSTR("DeveloperID Date parsing: extension value failed to decode"));
6806 }
6807 /* The extension value is a DERGeneralizedTime encoded in a UTF8String */
6808 CFErrorRef localError = NULL;
6809 if (decodedValue.tag == ASN1_UTF8_STRING) {
6810 *time = SecAbsoluteTimeFromDateContentWithError(ASN1_GENERALIZED_TIME, decodedValue.content.data, decodedValue.content.length, &localError);
6811 } else {
6812 return SecError(errSecDecode, error, CFSTR("DeveloperID Date parsing: extension value wrong tag"));
6813 }
6814 return CFErrorPropagate(localError, error);
6815 }
6816
6817 CFIndex SecCertificateGetUnparseableKnownExtension(SecCertificateRef certificate) {
6818 if (!certificate) {
6819 return kCFNotFound;
6820 }
6821 return certificate->_unparseableKnownExtensionIndex;
6822 }