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