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