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