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