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