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