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