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