--- /dev/null
+/*
+ * Copyright (c) 2003,2011-2012,2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "cert.h"
+#include "cmstpriv.h"
+#include "cmslocal.h"
+#include "secitem.h"
+#include <security_asn1/secerr.h>
+#include <Security/SecKeychain.h>
+#include <Security/SecKeychainItem.h>
+#include <Security/SecKeychainSearch.h>
+#include <Security/SecIdentity.h>
+#include <Security/SecIdentityPriv.h>
+#include <Security/SecIdentitySearch.h>
+#include <Security/SecCertificatePriv.h>
+#include <Security/SecPolicySearch.h>
+#include <Security/oidsalg.h>
+#include <Security/cssmapi.h>
+#include <Security/oidscert.h>
+#include <Security/oidscert.h>
+#include <syslog.h>
+
+/* for errKCDuplicateItem */
+#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
+
+#define CERT_DEBUG 0
+#if CERT_DEBUG
+#define dprintf(args...) fprintf(stderr, args)
+#else
+#define dprintf(args...)
+#endif
+
+/* @@@ Remove this once it's back in the appropriate header. */
+static const uint8 X509V1IssuerNameStd[] = {INTEL_X509V3_CERT_R08, 23};
+static const CSSM_OID OID_X509V1IssuerNameStd = {INTEL_X509V3_CERT_R08_LENGTH+1, (uint8 *)X509V1IssuerNameStd};
+
+/*
+ * Normalize a Printable String. Per RFC2459 (4.1.2.4), printable strings are case
+ * insensitive and we're supposed to ignore leading and trailing
+ * whitespace, and collapse multiple whitespace characters into one.
+ */
+static void
+CERT_NormalizeString(CSSM_DATA_PTR string)
+{
+ char *pD, *pCh, *pEos;
+
+ if (!string->Length)
+ return;
+
+ pD = pCh = (char *)string->Data;
+ pEos = pCh + string->Length - 1;
+
+ /* Strip trailing NULL terminators */
+ while(*pEos == 0)
+ pEos--;
+
+ /* Remove trailing spaces */
+ while(isspace(*pEos))
+ pEos--;
+
+ /* Point to one past last non-space character */
+ pEos++;
+
+ /* skip all leading whitespace */
+ while(isspace(*pCh) && (pCh < pEos))
+ pCh++;
+
+ /* Eliminate multiple whitespace and convent to upper case.
+ * pCh points to first non-white char.
+ * pD still points to start of string. */
+ while(pCh < pEos)
+ {
+ char ch = *pCh++;
+ *pD++ = toupper(ch);
+ if(isspace(ch))
+ {
+ /* skip 'til next nonwhite */
+ while(isspace(*pCh) && (pCh < pEos))
+ pCh++;
+ }
+ }
+
+ string->Length = pD - (char *)string->Data;
+}
+
+/*
+ * Normalize an RDN. Per RFC2459 (4.1.2.4), printable strings are case
+ * insensitive and we're supposed to ignore leading and trailing
+ * whitespace, and collapse multiple whitespace characters into one.
+ *
+ * Incoming NSS_Name is assumed to be entirely within specifed coder's
+ * address space; we'll be munging some of that and possibly replacing
+ * some pointers with others allocated from the same space.
+ */
+void
+CERT_NormalizeX509NameNSS(NSS_Name *nssName)
+{
+ NSS_RDN *rdn;
+
+ for (rdn = *nssName->rdns; rdn; ++rdn)
+ {
+ NSS_ATV *attr;
+ for (attr = *rdn->atvs; attr; ++attr)
+ {
+ /*
+ * attr->value is an ASN_ANY containing an encoded
+ * string. We only normalize Prinatable String types.
+ * If we find one, decode it, normalize it, encode the
+ * result, and put the encoding back in attr->value.
+ * We temporarily "leak" the original string, which only
+ * has a lifetime of the incoming SecNssCoder.
+ */
+ NSS_TaggedItem *attrVal = &attr->value;
+ if(attrVal->tag != SEC_ASN1_PRINTABLE_STRING)
+ continue;
+
+ CERT_NormalizeString(&attrVal->item);
+ }
+ }
+}
+
+SecCertificateRef CERT_FindCertByNicknameOrEmailAddr(SecKeychainRef keychainOrArray, char *name)
+{
+ SecCertificateRef certificate;
+ OSStatus status=SecCertificateFindByEmail(keychainOrArray,name,&certificate);
+ return status==noErr?certificate:NULL;
+}
+
+SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
+{
+ CFRetain(pubKey);
+ return pubKey;
+}
+
+void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey)
+{
+ CFRelease(pubKey);
+}
+
+SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
+{
+ CFRetain(privKey);
+ return privKey;
+}
+
+void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
+{
+ CFRelease(privKey);
+}
+
+void CERT_DestroyCertificate(SecCertificateRef cert)
+{
+ CFRelease(cert);
+}
+
+SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
+{
+ CFRetain(cert);
+ return cert;
+}
+
+SecIdentityRef CERT_FindIdentityByUsage(SecKeychainRef keychainOrArray,
+ char *nickname, SECCertUsage usage, Boolean validOnly, void *proto_win)
+{
+ SecIdentityRef identityRef = NULL;
+ SecCertificateRef cert = CERT_FindCertByNicknameOrEmailAddr(keychainOrArray, nickname);
+ if (!cert)
+ return NULL;
+
+ SecIdentityCreateWithCertificate(keychainOrArray, cert, &identityRef);
+ CFRelease(cert);
+
+ return identityRef;
+}
+
+SecCertificateRef CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray,
+ char *nickname,SECCertUsage usage,Boolean validOnly,void *proto_win)
+{
+ SecItemClass itemClass = kSecCertificateItemClass;
+ SecKeychainSearchRef searchRef;
+ SecKeychainItemRef itemRef = NULL;
+ OSStatus status;
+ SecKeychainAttribute attrs[1];
+ const char *serialNumber = "12345678";
+ // const SecKeychainAttributeList attrList;
+#if 0
+ attrs[0].tag = kSecLabelItemAttr;
+ attrs[0].length = strlen(nickname)+1;
+ attrs[0].data = nickname;
+#else
+ attrs[0].tag = kSecSerialNumberItemAttr;
+ attrs[0].length = (UInt32)strlen(serialNumber)+1;
+ attrs[0].data = (uint8 *)serialNumber;
+#endif
+ SecKeychainAttributeList attrList = { 0, attrs };
+ // 12 34 56 78
+ status = SecKeychainSearchCreateFromAttributes(keychainOrArray,itemClass,&attrList,&searchRef);
+ if (status)
+ {
+ printf("CERT_FindUserCertByUsage: SecKeychainSearchCreateFromAttributes:%d",(int)status);
+ return NULL;
+ }
+ status = SecKeychainSearchCopyNext(searchRef,&itemRef);
+ if (status)
+ printf("CERT_FindUserCertByUsage: SecKeychainSearchCopyNext:%d",(int)status);
+ CFRelease(searchRef);
+ return (SecCertificateRef)itemRef;
+}
+
+/*
+startNewClass(X509Certificate)
+CertType, kSecCertTypeItemAttr, "CertType", 0, NULL, UINT32)
+CertEncoding, kSecCertEncodingItemAttr, "CertEncoding", 0, NULL, UINT32)
+PrintName, kSecLabelItemAttr, "PrintName", 0, NULL, BLOB)
+Alias, kSecAlias, "Alias", 0, NULL, BLOB)
+Subject, kSecSubjectItemAttr, "Subject", 0, NULL, BLOB)
+Issuer, kSecIssuerItemAttr, "Issuer", 0, NULL, BLOB)
+SerialNumber, kSecSerialNumberItemAttr, "SerialNumber", 0, NULL, BLOB)
+SubjectKeyIdentifier, kSecSubjectKeyIdentifierItemAttr, "SubjectKeyIdentifier", 0, NULL, BLOB)
+PublicKeyHash, kSecPublicKeyHashItemAttr, "PublicKeyHash", 0, NULL, BLOB)
+endNewClass()
+*/
+
+CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot)
+{
+ SecPolicySearchRef searchRef = NULL;
+ SecPolicyRef policy = NULL;
+ CFArrayRef wrappedCert = NULL;
+ SecTrustRef trust = NULL;
+ CFArrayRef certChain = NULL;
+ CSSM_TP_APPLE_EVIDENCE_INFO *statusChain;
+ CFDataRef actionData = NULL;
+ OSStatus status = 0;
+
+ if (!cert)
+ goto loser;
+
+ status = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
+ if (status)
+ goto loser;
+ status = SecPolicySearchCopyNext(searchRef, &policy);
+ if (status)
+ goto loser;
+
+ wrappedCert = CERT_CertListFromCert(cert);
+ status = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
+ if (status)
+ goto loser;
+
+ /* Tell SecTrust that we don't care if any certs in the chain have expired,
+ nor do we want to stop when encountering a cert with a trust setting;
+ we always want to build the full chain.
+ */
+ CSSM_APPLE_TP_ACTION_DATA localActionData = {
+ CSSM_APPLE_TP_ACTION_VERSION,
+ CSSM_TP_ACTION_ALLOW_EXPIRED | CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
+ };
+ actionData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)&localActionData, sizeof(localActionData), kCFAllocatorNull);
+ if (!actionData)
+ goto loser;
+
+ status = SecTrustSetParameters(trust, CSSM_TP_ACTION_DEFAULT, actionData);
+ if (status)
+ goto loser;
+
+ status = SecTrustEvaluate(trust, NULL);
+ if (status)
+ goto loser;
+
+ status = SecTrustGetResult(trust, NULL, &certChain, &statusChain);
+ if (status)
+ goto loser;
+
+ /* We don't drop the root if there is only 1 (self signed) certificate in the chain. */
+ if (!includeRoot && CFArrayGetCount(certChain) > 1)
+ {
+ CFMutableArrayRef subChain = CFArrayCreateMutableCopy(NULL, 0, certChain);
+ CFRelease(certChain);
+ certChain = subChain;
+ if (subChain)
+ CFArrayRemoveValueAtIndex(subChain, CFArrayGetCount(subChain) - 1);
+ }
+
+loser:
+ if (searchRef)
+ CFRelease(searchRef);
+ if (policy)
+ CFRelease(policy);
+ if (wrappedCert)
+ CFRelease(wrappedCert);
+ if (trust)
+ CFRelease(trust);
+ if (actionData)
+ CFRelease(actionData);
+ if (certChain && status)
+ {
+ CFRelease(certChain);
+ certChain = NULL;
+ }
+
+ return certChain;
+}
+
+CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
+{
+ const void *value = cert;
+ return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
+}
+
+CFArrayRef CERT_DupCertList(CFArrayRef oldList)
+{
+ CFRetain(oldList);
+ return oldList;
+}
+
+// Extract a public key object from a SubjectPublicKeyInfo
+SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
+{
+ SecPublicKeyRef keyRef = NULL;
+ SecCertificateCopyPublicKey(cert,&keyRef);
+ return keyRef;
+}
+
+SECStatus CERT_CheckCertUsage (SecCertificateRef cert,unsigned char usage)
+{
+ // abort();
+ // @@@ It's all good, it's ok.
+ return SECSuccess;
+}
+
+// Find a certificate in the database by a email address
+// "emailAddr" is the email address to look up
+SecCertificateRef CERT_FindCertByEmailAddr(SecKeychainRef keychainOrArray, char *emailAddr)
+{
+ abort();
+ return NULL;
+}
+
+// Find a certificate in the database by a DER encoded certificate
+// "derCert" is the DER encoded certificate
+SecCertificateRef CERT_FindCertByDERCert(SecKeychainRef keychainOrArray, const SECItem *derCert)
+{
+ // @@@ Technically this should look though keychainOrArray for a cert matching this one I guess.
+ SecCertificateRef cert = NULL;
+ OSStatus rv;
+
+ rv = SecCertificateCreateFromData(derCert, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
+ if (rv && cert)
+ {
+ PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
+ CFRelease(cert);
+ cert = NULL;
+ }
+
+ return cert;
+}
+
+static int compareCssmData(
+ const CSSM_DATA *d1,
+ const CSSM_DATA *d2)
+{
+ if((d1 == NULL) || (d2 == NULL)) {
+ return 0;
+ }
+ if(d1->Length != d2->Length) {
+ return 0;
+ }
+ if(memcmp(d1->Data, d2->Data, d1->Length)) {
+ return 0;
+ }
+ return 1;
+}
+
+// Generate a certificate key from the issuer and serialnumber, then look it up in the database.
+// Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
+SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray,
+ CSSM_DATA_PTR *rawCerts, PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN)
+{
+ SecCertificateRef certificate;
+ int numRawCerts = SecCmsArrayCount((void **)rawCerts);
+ int dex;
+ OSStatus ortn;
+
+ /*
+ * First search the rawCerts array.
+ */
+ for(dex=0; dex<numRawCerts; dex++) {
+ ortn = SecCertificateCreateFromData(rawCerts[dex],
+ CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
+ &certificate);
+ if(ortn) {
+ continue;
+ }
+ SecCmsIssuerAndSN *isn = CERT_GetCertIssuerAndSN(pl, certificate);
+ if(isn == NULL) {
+ CFRelease(certificate);
+ continue;
+ }
+ if(!compareCssmData(&isn->derIssuer, &issuerAndSN->derIssuer)) {
+ CFRelease(certificate);
+ continue;
+ }
+ if(!compareCssmData(&isn->serialNumber, &issuerAndSN->serialNumber)) {
+ CFRelease(certificate);
+ continue;
+ }
+ /* got it */
+ dprintf("CERT_FindCertByIssuerAndSN: found cert %p\n", certificate);
+ return certificate;
+ }
+
+ /* now search keychain(s) */
+ OSStatus status = SecCertificateFindByIssuerAndSN(keychainOrArray, &issuerAndSN->derIssuer,
+ &issuerAndSN->serialNumber, &certificate);
+ if (status)
+ {
+ PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
+ certificate = NULL;
+ }
+
+ return certificate;
+}
+
+SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray,
+ CSSM_DATA_PTR *rawCerts, const SECItem *subjKeyID)
+{
+ SecCertificateRef certificate;
+ int numRawCerts = SecCmsArrayCount((void **)rawCerts);
+ int dex;
+ OSStatus ortn;
+ SECItem skid;
+
+ /*
+ * First search the rawCerts array.
+ */
+ for(dex=0; dex<numRawCerts; dex++) {
+ int match;
+ ortn = SecCertificateCreateFromData(rawCerts[dex],
+ CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
+ &certificate);
+ if(ortn) {
+ continue;
+ }
+ if(CERT_FindSubjectKeyIDExtension(certificate, &skid)) {
+ CFRelease(certificate);
+ /* not present */
+ continue;
+ }
+ match = compareCssmData(subjKeyID, &skid);
+ SECITEM_FreeItem(&skid, PR_FALSE);
+ if(match) {
+ /* got it */
+ return certificate;
+ }
+ CFRelease(certificate);
+ }
+
+ /* now search keychain(s) */
+ OSStatus status = SecCertificateFindBySubjectKeyID(keychainOrArray,subjKeyID,&certificate);
+ if (status)
+ {
+ PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
+ certificate = NULL;
+ }
+
+ return certificate;
+}
+
+static SecIdentityRef
+CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray, SecCertificateRef certificate)
+{
+ SecIdentityRef identity = NULL;
+ SecIdentityCreateWithCertificate(keychainOrArray, certificate, &identity);
+ if (!identity)
+ PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
+
+ return identity;
+}
+
+SecIdentityRef
+CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
+{
+ SecCertificateRef certificate = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, issuerAndSN);
+ if (!certificate)
+ return NULL;
+
+ return CERT_FindIdentityByCertificate(keychainOrArray, certificate);
+}
+
+SecIdentityRef
+CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SECItem *subjKeyID)
+{
+ SecCertificateRef certificate = CERT_FindCertBySubjectKeyID(keychainOrArray, NULL, subjKeyID);
+ if (!certificate)
+ return NULL;
+
+ return CERT_FindIdentityByCertificate(keychainOrArray, certificate);
+}
+
+// find the smime symmetric capabilities profile for a given cert
+SECItem *CERT_FindSMimeProfile(SecCertificateRef cert)
+{
+ return NULL;
+}
+
+// Return the decoded value of the subjectKeyID extension. The caller should
+// free up the storage allocated in retItem->data.
+SECStatus CERT_FindSubjectKeyIDExtension (SecCertificateRef cert, SECItem *retItem)
+{
+ CSSM_DATA_PTR fieldValue = NULL;
+ OSStatus ortn;
+ CSSM_X509_EXTENSION *extp;
+ CE_SubjectKeyID *skid;
+
+ ortn = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier,
+ &fieldValue);
+ if(ortn || (fieldValue == NULL)) {
+ /* this cert doesn't have that extension */
+ return SECFailure;
+ }
+ extp = (CSSM_X509_EXTENSION *)fieldValue->Data;
+ skid = (CE_SubjectKeyID *)extp->value.parsedValue;
+ retItem->Data = (uint8 *)PORT_Alloc(skid->Length);
+ retItem->Length = skid->Length;
+ memmove(retItem->Data, skid->Data, retItem->Length);
+ SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier,
+ fieldValue);
+ return SECSuccess;
+}
+
+// Extract the issuer and serial number from a certificate
+SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
+{
+ OSStatus status;
+ SecCmsIssuerAndSN *certIssuerAndSN;
+ SecCertificateRef certRef;
+ SecCertificateRef itemImplRef = NULL;
+ CSSM_CL_HANDLE clHandle;
+ CSSM_DATA_PTR serialNumber = 0;
+ CSSM_DATA_PTR issuer = 0;
+ CSSM_DATA certData = {};
+ CSSM_HANDLE resultsHandle = 0;
+ uint32 numberOfFields = 0;
+ CSSM_RETURN result;
+ void *mark;
+
+ mark = PORT_ArenaMark(pl);
+
+ /* Retain input cert and get pointer to its data */
+ certRef = (SecCertificateRef)((cert) ? CFRetain(cert) : NULL);
+ status = SecCertificateGetData(certRef, &certData);
+ if (status)
+ goto loser;
+#if 1
+ // Convert unified input certRef to itemImpl instance.
+ // note: must not release this instance while we're using its CL handle!
+ itemImplRef = SecCertificateCreateItemImplInstance(cert);
+ status = SecCertificateGetCLHandle_legacy(itemImplRef, &clHandle);
+#else
+ status = SecCertificateGetCLHandle(certRef, &clHandle);
+#endif
+ if (status)
+ goto loser;
+
+ /* Get the issuer from the cert. */
+ result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
+ &OID_X509V1IssuerNameStd, &resultsHandle, &numberOfFields, &issuer);
+
+ if (result || numberOfFields < 1)
+ goto loser;
+ result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
+ if (result)
+ goto loser;
+
+ /* Get the serialNumber from the cert. */
+ result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
+ &CSSMOID_X509V1SerialNumber, &resultsHandle, &numberOfFields, &serialNumber);
+ if (result || numberOfFields < 1)
+ goto loser;
+ result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
+ if (result)
+ goto loser;
+
+ /* Allocate the SecCmsIssuerAndSN struct. */
+ certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
+ if (certIssuerAndSN == NULL)
+ goto loser;
+
+ /* Copy the issuer. */
+ certIssuerAndSN->derIssuer.Data = (uint8 *) PORT_ArenaAlloc(pl, issuer->Length);
+ if (!certIssuerAndSN->derIssuer.Data)
+ goto loser;
+ PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer->Data, issuer->Length);
+ certIssuerAndSN->derIssuer.Length = issuer->Length;
+
+ /* Copy the serialNumber. */
+ certIssuerAndSN->serialNumber.Data = (uint8 *) PORT_ArenaAlloc(pl, serialNumber->Length);
+ if (!certIssuerAndSN->serialNumber.Data)
+ goto loser;
+ PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber->Data, serialNumber->Length);
+ certIssuerAndSN->serialNumber.Length = serialNumber->Length;
+
+ PORT_ArenaUnmark(pl, mark);
+
+ CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
+ CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
+
+ if (itemImplRef)
+ CFRelease(itemImplRef);
+ if (certRef)
+ CFRelease(certRef);
+
+ return certIssuerAndSN;
+
+loser:
+ PORT_ArenaRelease(pl, mark);
+
+ if (serialNumber)
+ CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
+ if (issuer)
+ CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
+ if (itemImplRef)
+ CFRelease(itemImplRef);
+ if (certRef)
+ CFRelease(certRef);
+
+ PORT_SetError(SEC_INTERNAL_ONLY);
+ return NULL;
+}
+
+// import a collection of certs into the temporary or permanent cert database
+SECStatus CERT_ImportCerts(SecKeychainRef keychain, SECCertUsage usage, unsigned int ncerts,
+ SECItem **derCerts, SecCertificateRef **retCerts, Boolean keepCerts, Boolean caOnly, char *nickname)
+{
+ OSStatus rv = SECFailure;
+ SecCertificateRef cert;
+ unsigned int ci;
+
+ // @@@ Do something with caOnly and nickname
+ if (caOnly || nickname)
+ abort();
+
+ for (ci = 0; ci < ncerts; ++ci)
+ {
+ rv = SecCertificateCreateFromData(derCerts[ci], CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
+ if (rv)
+ break;
+ if (keepCerts)
+ {
+ rv = SecCertificateAddToKeychain(cert, keychain);
+ if (rv)
+ {
+ if (rv == errKCDuplicateItem)
+ rv = noErr;
+ else
+ {
+ CFRelease(cert);
+ break;
+ }
+ }
+ }
+
+ if (retCerts)
+ {
+ // @@@ not yet
+ abort();
+ }
+ else
+ CFRelease(cert);
+ }
+
+ return rv;
+}
+
+SECStatus CERT_SaveSMimeProfile(SecCertificateRef cert, SECItem *emailProfile,SECItem *profileTime)
+{
+ fprintf(stderr, "WARNING: CERT_SaveSMimeProfile unimplemented\n");
+ return SECSuccess;
+}
+
+// Check the hostname to make sure that it matches the shexp that
+// is given in the common name of the certificate.
+SECStatus CERT_VerifyCertName(SecCertificateRef cert, const char *hostname)
+{
+ fprintf(stderr, "WARNING: CERT_VerifyCertName unimplemented\n");
+ return SECSuccess;
+}
+
+/*
+** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
+** verify a certificate by checking validity times against a certain time,
+** that we trust the issuer, and that the signature on the certificate is
+** valid.
+** "cert" the certificate to verify
+** "checkSig" only check signatures if true
+*/
+SECStatus
+CERT_VerifyCert(SecKeychainRef keychainOrArray, SecCertificateRef cert,
+ const CSSM_DATA_PTR *otherCerts, /* intermediates */
+ CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
+{
+ CFMutableArrayRef certificates = NULL;
+ SecTrustRef trust = NULL;
+ OSStatus rv;
+ int numOtherCerts = SecCmsArrayCount((void **)otherCerts);
+ int dex;
+
+ /*
+ * Certs to evaluate: first the leaf - our cert - then all the rest we know
+ * about. It's OK for otherCerts to contain a copy of the leaf.
+ */
+ certificates = CFArrayCreateMutable(NULL, numOtherCerts + 1, &kCFTypeArrayCallBacks);
+ CFArrayAppendValue(certificates, cert);
+ for(dex=0; dex<numOtherCerts; dex++) {
+ SecCertificateRef intCert;
+
+ rv = SecCertificateCreateFromData(otherCerts[dex],
+ CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
+ &intCert);
+ if(rv) {
+ goto loser;
+ }
+ CFArrayAppendValue(certificates, intCert);
+ CFRelease(intCert);
+ }
+ rv = SecTrustCreateWithCertificates(certificates, policies, &trust);
+ CFRelease(certificates);
+ certificates = NULL;
+ if (rv)
+ goto loser;
+
+ rv = SecTrustSetKeychains(trust, keychainOrArray);
+ if (rv)
+ goto loser;
+
+ CFDateRef verifyDate = CFDateCreate(NULL, stime);
+ rv = SecTrustSetVerifyDate(trust, verifyDate);
+ CFRelease(verifyDate);
+ if (rv)
+ goto loser;
+
+ if (trustRef)
+ {
+ *trustRef = trust;
+ }
+ else
+ {
+ SecTrustResultType result;
+ /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
+ rv = SecTrustEvaluate(trust, &result);
+ if (rv)
+ goto loser;
+
+ switch (result)
+ {
+ case kSecTrustResultProceed:
+ case kSecTrustResultUnspecified:
+ /* TP Verification succeeded and there was either a UserTurst entry
+ telling us to procceed, or no user trust setting was specified. */
+ CFRelease(trust);
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
+ rv = SECFailure;
+ goto loser;
+ break;
+ }
+ }
+
+ return SECSuccess;
+loser:
+#if 0 /* debugging */
+ syslog(LOG_ERR, "CERT_VerifyCert has failed with %d (input policies and output trust follow)",
+ (int)rv);
+ if (policies) CFShow(policies);
+ if (trust) CFShow(trust);
+#endif
+ if (trust)
+ CFRelease(trust);
+ if(certificates)
+ CFRelease(certificates);
+ return rv;
+}
+
+CFTypeRef
+CERT_PolicyForCertUsage(SECCertUsage certUsage)
+{
+ SecPolicySearchRef search = NULL;
+ SecPolicyRef policy = NULL;
+ const CSSM_OID *policyOID;
+ OSStatus rv;
+
+ switch (certUsage)
+ {
+ case certUsageSSLServerWithStepUp:
+ case certUsageSSLCA:
+ case certUsageVerifyCA:
+ case certUsageAnyCA:
+ goto loser;
+ break;
+ case certUsageSSLClient:
+ case certUsageSSLServer:
+ policyOID = &CSSMOID_APPLE_TP_SSL;
+ break;
+ case certUsageUserCertImport:
+ policyOID = &CSSMOID_APPLE_TP_CSR_GEN;
+ break;
+ case certUsageStatusResponder:
+ policyOID = &CSSMOID_APPLE_TP_REVOCATION_OCSP;
+ break;
+ case certUsageObjectSigner:
+ case certUsageProtectedObjectSigner:
+ policyOID = &CSSMOID_APPLE_ISIGN;
+ break;
+ case certUsageEmailSigner:
+ case certUsageEmailRecipient:
+ policyOID = &CSSMOID_APPLE_X509_BASIC;
+ break;
+ default:
+ goto loser;
+ }
+ rv = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &search);
+ if (rv)
+ goto loser;
+
+ rv = SecPolicySearchCopyNext(search, &policy);
+ if (rv)
+ goto loser;
+
+loser:
+ if(search) CFRelease(search);
+ return policy;
+}