1/*
2 *  cert.c
3 *  security_smime
4 *
5 *  Created by john on Wed Mar 12 2003.
6 *  Copyright (c) 2003 __MyCompanyName__. All rights reserved.
7 *
8 */
9
10#include "cert.h"
11#include "cmstpriv.h"
12#include "cmslocal.h"
13#include "secitem.h"
14#include <security_asn1/secerr.h>
15#include <Security/SecKeychain.h>
16#include <Security/SecKeychainItem.h>
17#include <Security/SecKeychainSearch.h>
18#include <Security/SecIdentity.h>
19#include <Security/SecIdentityPriv.h>
20#include <Security/SecIdentitySearch.h>
21#include <Security/SecCertificatePriv.h>
22#include <Security/SecPolicySearch.h>
23#include <Security/oidsalg.h>
24#include <Security/cssmapi.h>
25#include <Security/oidscert.h>
26#include <Security/oidscert.h>
27
28/* for errKCDuplicateItem */
29#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
30
31#define CERT_DEBUG	0
32#if	CERT_DEBUG
33#define dprintf(args...)      printf(args)
34#else
35#define dprintf(args...)
36#endif
37
38/* @@@ Remove this once it's back in the appropriate header. */
39static const uint8 X509V1IssuerNameStd[] = {INTEL_X509V3_CERT_R08, 23};
40static const CSSM_OID OID_X509V1IssuerNameStd = {INTEL_X509V3_CERT_R08_LENGTH+1,  (uint8 *)X509V1IssuerNameStd};
41
42/*
43 * Normalize a Printable String. Per RFC2459 (4.1.2.4), printable strings are case
44 * insensitive and we're supposed to ignore leading and trailing
45 * whitespace, and collapse multiple whitespace characters into one.
46 */
47static void
48CERT_NormalizeString(CSSM_DATA_PTR string)
49{
50    char *pD, *pCh, *pEos;
51
52    if (!string->Length)
53	return;
54
55    pD = pCh = (char *)string->Data;
56    pEos = pCh + string->Length - 1;
57
58    /* Strip trailing NULL terminators */
59    while(*pEos == 0)
60	pEos--;
61
62    /* Remove trailing spaces */
63    while(isspace(*pEos))
64	pEos--;
65
66    /* Point to one past last non-space character */
67    pEos++;
68
69    /* skip all leading whitespace */
70    while(isspace(*pCh) && (pCh < pEos))
71	pCh++;
72
73    /* Eliminate multiple whitespace and convent to upper case.
74     * pCh points to first non-white char.
75     * pD still points to start of string. */
76    while(pCh < pEos)
77    {
78	char ch = *pCh++;
79	*pD++ = toupper(ch);
80	if(isspace(ch))
81	{
82	    /* skip 'til next nonwhite */
83	    while(isspace(*pCh) && (pCh < pEos))
84		pCh++;
85	}
86    }
87
88    string->Length = pD - (char *)string->Data;
89}
90
91/*
92 * Normalize an RDN. Per RFC2459 (4.1.2.4), printable strings are case
93 * insensitive and we're supposed to ignore leading and trailing
94 * whitespace, and collapse multiple whitespace characters into one.
95 *
96 * Incoming NSS_Name is assumed to be entirely within specifed coder's
97 * address space; we'll be munging some of that and possibly replacing
98 * some pointers with others allocated from the same space.
99 */
100void
101CERT_NormalizeX509NameNSS(NSS_Name *nssName)
102{
103    NSS_RDN *rdn;
104
105    for (rdn = *nssName->rdns; rdn; ++rdn)
106    {
107	NSS_ATV *attr;
108	for (attr = *rdn->atvs; attr; ++attr)
109	{
110	    /*
111		* attr->value is an ASN_ANY containing an encoded
112		* string. We only normalize Prinatable String types.
113		* If we find one, decode it, normalize it, encode the
114		* result, and put the encoding back in attr->value.
115		* We temporarily "leak" the original string, which only
116		* has a lifetime of the incoming SecNssCoder.
117		*/
118	    NSS_TaggedItem *attrVal = &attr->value;
119	    if(attrVal->tag != SEC_ASN1_PRINTABLE_STRING)
120		continue;
121
122	    CERT_NormalizeString(&attrVal->item);
123	}
124    }
125}
126
127SecCertificateRef CERT_FindCertByNicknameOrEmailAddr(SecKeychainRef keychainOrArray, char *name)
128{
129   SecCertificateRef certificate;
130    OSStatus status=SecCertificateFindByEmail(keychainOrArray,name,&certificate);
131    return status==noErr?certificate:NULL;
132}
133
134SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
135{
136    CFRetain(pubKey);
137    return pubKey;
138}
139
140void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey)
141{
142    CFRelease(pubKey);
143}
144
145SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
146{
147    CFRetain(privKey);
148    return privKey;
149}
150
151void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
152{
153    CFRelease(privKey);
154}
155
156void CERT_DestroyCertificate(SecCertificateRef cert)
157{
158    CFRelease(cert);
159}
160
161SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
162{
163    CFRetain(cert);
164    return cert;
165}
166
167SecIdentityRef CERT_FindIdentityByUsage(SecKeychainRef keychainOrArray,
168			 char *nickname, SECCertUsage usage, Boolean validOnly, void *proto_win)
169{
170    SecIdentityRef identityRef = NULL;
171    SecCertificateRef cert = CERT_FindCertByNicknameOrEmailAddr(keychainOrArray, nickname);
172    if (!cert)
173	return NULL;
174
175    SecIdentityCreateWithCertificate(keychainOrArray, cert, &identityRef);
176    CFRelease(cert);
177
178    return identityRef;
179}
180
181SecCertificateRef CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray,
182			 char *nickname,SECCertUsage usage,Boolean validOnly,void *proto_win)
183{
184    SecItemClass itemClass = kSecCertificateItemClass;
185    SecKeychainSearchRef searchRef;
186    SecKeychainItemRef itemRef = NULL;
187    OSStatus status;
188    SecKeychainAttribute attrs[1];
189    const char *serialNumber = "12345678";
190 //   const SecKeychainAttributeList attrList;
191#if 0
192    attrs[1].tag = kSecLabelItemAttr;
193    attrs[1].length = strlen(nickname)+1;
194    attrs[1].data = nickname;
195#else
196    attrs[1].tag = kSecSerialNumberItemAttr;
197    attrs[1].length = (UInt32)strlen(serialNumber)+1;
198    attrs[1].data = (uint8 *)serialNumber;
199#endif
200    SecKeychainAttributeList attrList = { 0, attrs };
201 //   12 34 56 78
202	status = SecKeychainSearchCreateFromAttributes(keychainOrArray,itemClass,&attrList,&searchRef);
203    if (status)
204    {
205        printf("CERT_FindUserCertByUsage: SecKeychainSearchCreateFromAttributes:%d",(int)status);
206        return NULL;
207    }
208	status = SecKeychainSearchCopyNext(searchRef,&itemRef);
209    if (status)
210    	printf("CERT_FindUserCertByUsage: SecKeychainSearchCopyNext:%d",(int)status);
211    CFRelease(searchRef);
212    return (SecCertificateRef)itemRef;
213}
214
215/*
216startNewClass(X509Certificate)
217CertType, kSecCertTypeItemAttr, "CertType", 0, NULL, UINT32)
218CertEncoding, kSecCertEncodingItemAttr, "CertEncoding", 0, NULL, UINT32)
219PrintName, kSecLabelItemAttr, "PrintName", 0, NULL, BLOB)
220Alias, kSecAlias, "Alias", 0, NULL, BLOB)
221Subject, kSecSubjectItemAttr, "Subject", 0, NULL, BLOB)
222Issuer, kSecIssuerItemAttr, "Issuer", 0, NULL, BLOB)
223SerialNumber, kSecSerialNumberItemAttr, "SerialNumber", 0, NULL, BLOB)
224SubjectKeyIdentifier, kSecSubjectKeyIdentifierItemAttr, "SubjectKeyIdentifier", 0, NULL, BLOB)
225PublicKeyHash, kSecPublicKeyHashItemAttr, "PublicKeyHash", 0, NULL, BLOB)
226endNewClass()
227*/
228
229CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot)
230{
231    SecPolicySearchRef searchRef = NULL;
232    SecPolicyRef policy = NULL;
233    CFArrayRef wrappedCert = NULL;
234    SecTrustRef trust = NULL;
235    CFArrayRef certChain = NULL;
236    CSSM_TP_APPLE_EVIDENCE_INFO *statusChain;
237    CFDataRef actionData = NULL;
238    OSStatus status = 0;
239
240    if (!cert)
241	goto loser;
242
243    status = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
244    if (status)
245	goto loser;
246    status = SecPolicySearchCopyNext(searchRef, &policy);
247    if (status)
248	goto loser;
249
250    wrappedCert = CERT_CertListFromCert(cert);
251    status = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
252    if (status)
253	goto loser;
254
255    /* Tell SecTrust that we don't care if any certs in the chain have expired,
256       nor do we want to stop when encountering a cert with a trust setting;
257       we always want to build the full chain.
258    */
259    CSSM_APPLE_TP_ACTION_DATA localActionData = {
260        CSSM_APPLE_TP_ACTION_VERSION,
261        CSSM_TP_ACTION_ALLOW_EXPIRED | CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
262    };
263    actionData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)&localActionData, sizeof(localActionData), kCFAllocatorNull);
264    if (!actionData)
265        goto loser;
266
267    status = SecTrustSetParameters(trust, CSSM_TP_ACTION_DEFAULT, actionData);
268    if (status)
269        goto loser;
270
271    status = SecTrustEvaluate(trust, NULL);
272    if (status)
273	goto loser;
274
275    status = SecTrustGetResult(trust, NULL, &certChain, &statusChain);
276    if (status)
277	goto loser;
278
279    /* We don't drop the root if there is only 1 (self signed) certificate in the chain. */
280    if (!includeRoot && CFArrayGetCount(certChain) > 1)
281    {
282	CFMutableArrayRef subChain =  CFArrayCreateMutableCopy(NULL, 0, certChain);
283	CFRelease(certChain);
284	certChain = subChain;
285	if (subChain)
286	    CFArrayRemoveValueAtIndex(subChain, CFArrayGetCount(subChain) - 1);
287    }
288
289loser:
290    if (searchRef)
291	CFRelease(searchRef);
292    if (policy)
293	CFRelease(policy);
294    if (wrappedCert)
295	CFRelease(wrappedCert);
296    if (trust)
297	CFRelease(trust);
298    if (actionData)
299	CFRelease(actionData);
300    if (certChain && status)
301    {
302	CFRelease(certChain);
303	certChain = NULL;
304    }
305
306    return certChain;
307}
308
309CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
310{
311    const void *value = cert;
312    return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
313}
314
315CFArrayRef CERT_DupCertList(CFArrayRef oldList)
316{
317    CFRetain(oldList);
318    return oldList;
319}
320
321// Extract a public key object from a SubjectPublicKeyInfo
322SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
323{
324    SecPublicKeyRef keyRef = NULL;
325    SecCertificateCopyPublicKey(cert,&keyRef);
326    return keyRef;
327}
328
329SECStatus CERT_CheckCertUsage (SecCertificateRef cert,unsigned char usage)
330{
331    // abort();
332    // @@@ It's all good, it's ok.
333    return SECSuccess;
334}
335
336// Find a certificate in the database by a email address
337// "emailAddr" is the email address to look up
338SecCertificateRef CERT_FindCertByEmailAddr(SecKeychainRef keychainOrArray, char *emailAddr)
339{
340    abort();
341    return NULL;
342}
343
344// Find a certificate in the database by a DER encoded certificate
345// "derCert" is the DER encoded certificate
346SecCertificateRef CERT_FindCertByDERCert(SecKeychainRef keychainOrArray, const SECItem *derCert)
347{
348    // @@@ Technically this should look though keychainOrArray for a cert matching this one I guess.
349    SecCertificateRef cert = NULL;
350    OSStatus rv;
351
352    rv = SecCertificateCreateFromData(derCert, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
353    if (rv && cert)
354    {
355	PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
356	CFRelease(cert);
357	cert = NULL;
358    }
359
360    return cert;
361}
362
363static int compareCssmData(
364    const CSSM_DATA *d1,
365    const CSSM_DATA *d2)
366{
367    if((d1 == NULL) || (d2 == NULL)) {
368	return 0;
369    }
370    if(d1->Length != d2->Length) {
371	return 0;
372    }
373    if(memcmp(d1->Data, d2->Data, d1->Length)) {
374	return 0;
375    }
376    return 1;
377}
378
379// Generate a certificate key from the issuer and serialnumber, then look it up in the database.
380// Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
381SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray,
382    CSSM_DATA_PTR *rawCerts, PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN)
383{
384    SecCertificateRef certificate;
385    int numRawCerts = SecCmsArrayCount((void **)rawCerts);
386    int dex;
387    OSStatus ortn;
388
389    /*
390     * First search the rawCerts array.
391     */
392    for(dex=0; dex<numRawCerts; dex++) {
393	ortn = SecCertificateCreateFromData(rawCerts[dex],
394	    CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
395	    &certificate);
396	if(ortn) {
397	    continue;
398	}
399	SecCmsIssuerAndSN *isn = CERT_GetCertIssuerAndSN(pl, certificate);
400	if(isn == NULL) {
401	    CFRelease(certificate);
402	    continue;
403	}
404	if(!compareCssmData(&isn->derIssuer, &issuerAndSN->derIssuer)) {
405	    CFRelease(certificate);
406	    continue;
407	}
408	if(!compareCssmData(&isn->serialNumber, &issuerAndSN->serialNumber)) {
409	    CFRelease(certificate);
410	    continue;
411	}
412	/* got it */
413	dprintf("CERT_FindCertByIssuerAndSN: found cert %p\n", certificate);
414	return certificate;
415    }
416
417    /* now search keychain(s) */
418    OSStatus status = SecCertificateFindByIssuerAndSN(keychainOrArray, &issuerAndSN->derIssuer,
419	&issuerAndSN->serialNumber, &certificate);
420    if (status)
421    {
422	PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
423	certificate = NULL;
424    }
425
426    return certificate;
427}
428
429SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray,
430    CSSM_DATA_PTR *rawCerts, const SECItem *subjKeyID)
431{
432    SecCertificateRef certificate;
433    int numRawCerts = SecCmsArrayCount((void **)rawCerts);
434    int dex;
435    OSStatus ortn;
436    SECItem skid;
437
438    /*
439     * First search the rawCerts array.
440     */
441    for(dex=0; dex<numRawCerts; dex++) {
442	int match;
443	ortn = SecCertificateCreateFromData(rawCerts[dex],
444	    CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
445	    &certificate);
446	if(ortn) {
447	    continue;
448	}
449	if(CERT_FindSubjectKeyIDExtension(certificate, &skid)) {
450	    CFRelease(certificate);
451	    /* not present */
452	    continue;
453	}
454	match = compareCssmData(subjKeyID, &skid);
455	SECITEM_FreeItem(&skid, PR_FALSE);
456	if(match) {
457	    /* got it */
458	    return certificate;
459	}
460	CFRelease(certificate);
461    }
462
463    /* now search keychain(s) */
464    OSStatus status = SecCertificateFindBySubjectKeyID(keychainOrArray,subjKeyID,&certificate);
465    if (status)
466    {
467	PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
468	certificate = NULL;
469    }
470
471    return certificate;
472}
473
474static SecIdentityRef
475CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray, SecCertificateRef certificate)
476{
477    SecIdentityRef  identity = NULL;
478    SecIdentityCreateWithCertificate(keychainOrArray, certificate, &identity);
479    if (!identity)
480	PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
481
482    return identity;
483}
484
485SecIdentityRef
486CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
487{
488    SecCertificateRef certificate = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, issuerAndSN);
489    if (!certificate)
490	return NULL;
491
492    return CERT_FindIdentityByCertificate(keychainOrArray, certificate);
493}
494
495SecIdentityRef
496CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SECItem *subjKeyID)
497{
498    SecCertificateRef certificate = CERT_FindCertBySubjectKeyID(keychainOrArray, NULL, subjKeyID);
499    if (!certificate)
500	return NULL;
501
502    return CERT_FindIdentityByCertificate(keychainOrArray, certificate);
503}
504
505// find the smime symmetric capabilities profile for a given cert
506SECItem *CERT_FindSMimeProfile(SecCertificateRef cert)
507{
508    return NULL;
509}
510
511// Return the decoded value of the subjectKeyID extension. The caller should
512// free up the storage allocated in retItem->data.
513SECStatus CERT_FindSubjectKeyIDExtension (SecCertificateRef cert, SECItem *retItem)
514{
515    CSSM_DATA_PTR fieldValue = NULL;
516    OSStatus ortn;
517    CSSM_X509_EXTENSION *extp;
518    CE_SubjectKeyID *skid;
519
520    ortn = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier,
521	&fieldValue);
522    if(ortn || (fieldValue == NULL)) {
523	/* this cert doesn't have that extension */
524	return SECFailure;
525    }
526    extp = (CSSM_X509_EXTENSION *)fieldValue->Data;
527    skid = (CE_SubjectKeyID *)extp->value.parsedValue;
528    retItem->Data = (uint8 *)PORT_Alloc(skid->Length);
529    retItem->Length = skid->Length;
530    memmove(retItem->Data, skid->Data, retItem->Length);
531    SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier,
532	fieldValue);
533    return SECSuccess;
534}
535
536// Extract the issuer and serial number from a certificate
537SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
538{
539    OSStatus status;
540    SecCmsIssuerAndSN *certIssuerAndSN;
541    CSSM_CL_HANDLE clHandle;
542    CSSM_DATA_PTR serialNumber = 0;
543    CSSM_DATA_PTR issuer = 0;
544    CSSM_DATA certData = {};
545    CSSM_HANDLE resultsHandle = 0;
546    uint32 numberOfFields = 0;
547    CSSM_RETURN result;
548    void *mark;
549
550    mark = PORT_ArenaMark(pl);
551
552    status = SecCertificateGetCLHandle(cert, &clHandle);
553    if (status)
554	goto loser;
555    status = SecCertificateGetData(cert, &certData);
556    if (status)
557	goto loser;
558
559    /* Get the issuer from the cert. */
560    result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
561	&OID_X509V1IssuerNameStd, &resultsHandle, &numberOfFields, &issuer);
562
563    if (result || numberOfFields < 1)
564	goto loser;
565    result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
566    if (result)
567	goto loser;
568
569
570    /* Get the serialNumber from the cert. */
571    result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
572	&CSSMOID_X509V1SerialNumber, &resultsHandle, &numberOfFields, &serialNumber);
573    if (result || numberOfFields < 1)
574	goto loser;
575    result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
576    if (result)
577	goto loser;
578
579    /* Allocate the SecCmsIssuerAndSN struct. */
580    certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
581    if (certIssuerAndSN == NULL)
582	goto loser;
583
584    /* Copy the issuer. */
585    certIssuerAndSN->derIssuer.Data = (uint8 *) PORT_ArenaAlloc(pl, issuer->Length);
586    if (!certIssuerAndSN->derIssuer.Data)
587	goto loser;
588    PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer->Data, issuer->Length);
589    certIssuerAndSN->derIssuer.Length = issuer->Length;
590
591    /* Copy the serialNumber. */
592    certIssuerAndSN->serialNumber.Data = (uint8 *) PORT_ArenaAlloc(pl, serialNumber->Length);
593    if (!certIssuerAndSN->serialNumber.Data)
594	goto loser;
595    PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber->Data, serialNumber->Length);
596    certIssuerAndSN->serialNumber.Length = serialNumber->Length;
597
598    PORT_ArenaUnmark(pl, mark);
599
600    CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
601    CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
602
603    return certIssuerAndSN;
604
605loser:
606    PORT_ArenaRelease(pl, mark);
607
608    if (serialNumber)
609	CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
610    if (issuer)
611	CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
612
613    PORT_SetError(SEC_INTERNAL_ONLY);
614    return NULL;
615}
616
617// import a collection of certs into the temporary or permanent cert database
618SECStatus CERT_ImportCerts(SecKeychainRef keychain, SECCertUsage usage, unsigned int ncerts,
619    SECItem **derCerts, SecCertificateRef **retCerts, Boolean keepCerts, Boolean caOnly, char *nickname)
620{
621    OSStatus rv = SECFailure;
622    SecCertificateRef cert;
623    unsigned int ci;
624
625    // @@@ Do something with caOnly and nickname
626    if (caOnly || nickname)
627	abort();
628
629    for (ci = 0; ci < ncerts; ++ci)
630    {
631	rv = SecCertificateCreateFromData(derCerts[ci], CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
632	if (rv)
633	    break;
634	if (keepCerts)
635	{
636	    rv = SecCertificateAddToKeychain(cert, keychain);
637	    if (rv)
638	    {
639		if (rv == errKCDuplicateItem)
640		    rv = noErr;
641		else
642		{
643		    CFRelease(cert);
644		    break;
645		}
646	    }
647	}
648
649	if (retCerts)
650	{
651	    // @@@ not yet
652	    abort();
653	}
654	else
655	    CFRelease(cert);
656    }
657
658    return rv;
659}
660
661SECStatus CERT_SaveSMimeProfile(SecCertificateRef cert, SECItem *emailProfile,SECItem *profileTime)
662{
663    fprintf(stderr, "WARNING: CERT_SaveSMimeProfile unimplemented\n");
664    return SECSuccess;
665}
666
667// Check the hostname to make sure that it matches the shexp that
668// is given in the common name of the certificate.
669SECStatus CERT_VerifyCertName(SecCertificateRef cert, const char *hostname)
670{
671    fprintf(stderr, "WARNING: CERT_VerifyCertName unimplemented\n");
672    return SECSuccess;
673}
674
675/*
676** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
677** verify a certificate by checking validity times against a certain time,
678** that we trust the issuer, and that the signature on the certificate is
679** valid.
680**	"cert" the certificate to verify
681**	"checkSig" only check signatures if true
682*/
683SECStatus
684CERT_VerifyCert(SecKeychainRef keychainOrArray, SecCertificateRef cert,
685		const CSSM_DATA_PTR *otherCerts,    /* intermediates */
686		CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
687{
688    CFMutableArrayRef certificates = NULL;
689    SecTrustRef trust = NULL;
690    OSStatus rv;
691    int numOtherCerts = SecCmsArrayCount((void **)otherCerts);
692    int dex;
693
694    /*
695     * Certs to evaluate: first the leaf - our cert - then all the rest we know
696     * about. It's OK for otherCerts to contain a copy of the leaf.
697     */
698    certificates = CFArrayCreateMutable(NULL, numOtherCerts + 1, &kCFTypeArrayCallBacks);
699    CFArrayAppendValue(certificates, cert);
700    for(dex=0; dex<numOtherCerts; dex++) {
701	SecCertificateRef intCert;
702
703	rv = SecCertificateCreateFromData(otherCerts[dex],
704	    CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
705	    &intCert);
706	if(rv) {
707	    goto loser;
708	}
709	CFArrayAppendValue(certificates, intCert);
710	CFRelease(intCert);
711    }
712    rv = SecTrustCreateWithCertificates(certificates, policies, &trust);
713    CFRelease(certificates);
714    certificates = NULL;
715    if (rv)
716	goto loser;
717
718    rv = SecTrustSetKeychains(trust, keychainOrArray);
719    if (rv)
720	goto loser;
721
722    CFDateRef verifyDate = CFDateCreate(NULL, stime);
723    rv = SecTrustSetVerifyDate(trust, verifyDate);
724    CFRelease(verifyDate);
725    if (rv)
726	goto loser;
727
728    if (trustRef)
729    {
730	*trustRef = trust;
731    }
732    else
733    {
734	SecTrustResultType result;
735	/* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
736	rv = SecTrustEvaluate(trust, &result);
737	if (rv)
738	    goto loser;
739
740	switch (result)
741	{
742	case kSecTrustResultProceed:
743	case kSecTrustResultUnspecified:
744	    /* TP Verification succeeded and there was either a UserTurst entry
745	       telling us to procceed, or no user trust setting was specified. */
746	    CFRelease(trust);
747	    break;
748	default:
749	    PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
750	    rv = SECFailure;
751	    goto loser;
752	    break;
753	}
754    }
755
756    return SECSuccess;
757loser:
758    if (trust)
759	CFRelease(trust);
760    if(certificates)
761	CFRelease(certificates);
762    return rv;
763}
764
765CFTypeRef
766CERT_PolicyForCertUsage(SECCertUsage certUsage)
767{
768    SecPolicySearchRef search = NULL;
769    SecPolicyRef policy = NULL;
770    const CSSM_OID *policyOID;
771    OSStatus rv;
772
773    switch (certUsage)
774    {
775    case certUsageSSLServerWithStepUp:
776    case certUsageSSLCA:
777    case certUsageVerifyCA:
778    case certUsageAnyCA:
779	goto loser;
780	break;
781    case certUsageSSLClient:
782    case certUsageSSLServer:
783	policyOID = &CSSMOID_APPLE_TP_SSL;
784	break;
785    case certUsageUserCertImport:
786	policyOID = &CSSMOID_APPLE_TP_CSR_GEN;
787	break;
788    case certUsageStatusResponder:
789	policyOID = &CSSMOID_APPLE_TP_REVOCATION_OCSP;
790	break;
791    case certUsageObjectSigner:
792    case certUsageProtectedObjectSigner:
793	policyOID = &CSSMOID_APPLE_ISIGN;
794	break;
795    case certUsageEmailSigner:
796    case certUsageEmailRecipient:
797	policyOID = &CSSMOID_APPLE_X509_BASIC;
798	break;
799    default:
800	goto loser;
801    }
802    rv = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &search);
803    if (rv)
804	goto loser;
805
806    rv = SecPolicySearchCopyNext(search, &policy);
807    if (rv)
808	goto loser;
809
810loser:
811    if(search) CFRelease(search);
812    return policy;
813}
814