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