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