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