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