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