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