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