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