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