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