#include "ssl.h"
#include "sslContext.h"
#include "sslMemory.h"
#include "sslCrypto.h"
#ifdef USE_CDSA_CRYPTO
#include <Security/Security.h>
#else
#include <Security/SecBase.h>
#include <Security/SecCertificate.h>
#include <Security/SecIdentity.h>
#include <Security/SecPolicy.h>
#include <Security/SecTrust.h>
#endif
#include "utilities/SecCFRelease.h"
#include "sslDebug.h"
#include "sslKeychain.h"
#include "sslUtils.h"
#include <string.h>
#include <assert.h>
#if TARGET_OS_IPHONE
#include "utilities/SecCFRelease.h"
#endif
#ifdef USE_SSLCERTIFICATE
static OSStatus secCertToSslCert(
SSLContext *ctx,
SecCertificateRef certRef,
SSLCertificate **sslCert)
{
CSSM_DATA certData; OSStatus ortn;
SSLCertificate *thisSslCert = NULL;
ortn = SecCertificateGetData(certRef, &certData);
if(ortn) {
sslErrorLog("SecCertificateGetData() returned %d\n", (int)ortn);
return ortn;
}
thisSslCert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate));
if(thisSslCert == NULL) {
return errSecAllocate;
}
if(SSLAllocBuffer(&thisSslCert->derCert, certData.Length,
ctx)) {
return errSecAllocate;
}
memcpy(thisSslCert->derCert.data, certData.Data, certData.Length);
thisSslCert->derCert.length = certData.Length;
*sslCert = thisSslCert;
return errSecSuccess;
}
static OSStatus sslCertSignerAlg(
SecCertificateRef certRef,
CSSM_ALGORITHMS *signerAlg)
{
OSStatus ortn;
CSSM_DATA_PTR fieldPtr;
CSSM_X509_ALGORITHM_IDENTIFIER *algId;
CSSM_ALGORITHMS sigAlg;
*signerAlg = CSSM_ALGID_NONE;
ortn = SecCertificateCopyFirstFieldValue(certRef,
&CSSMOID_X509V1SignatureAlgorithm,
&fieldPtr);
if(ortn) {
return ortn;
}
if(fieldPtr->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)) {
sslErrorLog("sslCertSignerAlg() length error\n");
ortn = errSSLCrypto;
goto errOut;
}
algId = (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldPtr->Data;
if(!cssmOidToAlg(&algId->algorithm, &sigAlg)) {
sslErrorLog("sslCertSignerAlg() bad sigAlg OID\n");
ortn = errSecParam;
goto errOut;
}
switch(sigAlg) {
case CSSM_ALGID_RSA:
case CSSM_ALGID_MD2WithRSA:
case CSSM_ALGID_MD5WithRSA:
case CSSM_ALGID_SHA1WithRSA:
case CSSM_ALGID_SHA224WithRSA:
case CSSM_ALGID_SHA256WithRSA:
case CSSM_ALGID_SHA384WithRSA:
case CSSM_ALGID_SHA512WithRSA:
*signerAlg = CSSM_ALGID_RSA;
break;
case CSSM_ALGID_SHA1WithECDSA:
case CSSM_ALGID_SHA224WithECDSA:
case CSSM_ALGID_SHA256WithECDSA:
case CSSM_ALGID_SHA384WithECDSA:
case CSSM_ALGID_SHA512WithECDSA:
case CSSM_ALGID_ECDSA:
case CSSM_ALGID_ECDSA_SPECIFIED:
*signerAlg = CSSM_ALGID_ECDSA;
break;
case CSSM_ALGID_DSA:
case CSSM_ALGID_SHA1WithDSA:
*signerAlg = CSSM_ALGID_DSA;
break;
default:
sslErrorLog("sslCertSignerAlg() unknown sigAlg\n");
ortn = errSecParam;
break;
}
errOut:
SecCertificateReleaseFirstFieldValue(certRef,
&CSSMOID_X509V1SignatureAlgorithm, fieldPtr);
return ortn;
}
OSStatus
parseIncomingCerts(
SSLContext *ctx,
CFArrayRef certs,
SSLCertificate **destCert,
CSSM_KEY_PTR *pubKey,
SecKeyRef *privKeyRef,
CSSM_ALGORITHMS *signerAlg)
{
CFIndex numCerts;
CFIndex cert;
SSLCertificate *certChain = NULL;
SSLCertificate *thisSslCert;
OSStatus ortn;
SecIdentityRef identity;
SecCertificateRef certRef;
SecKeyRef keyRef;
CSSM_DATA certData;
CSSM_CL_HANDLE clHand; CSSM_RETURN crtn;
CSSM_KEY_PTR *pubKey;
SecKeyRef *privKeyRef;
assert(ctx != NULL);
assert(destCert != NULL);
assert(sslPubKey != NULL);
assert(sslPrivKeyRef != NULL);
pubKey = &sslPubKey->key;
privKeyRef = &sslPrivKey->key;
sslDeleteCertificateChain(*destCert, ctx);
*destCert = NULL;
*pubKey = NULL;
*privKeyRef = NULL;
if(certs == NULL) {
sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
return errSSLBadCert;
}
numCerts = CFArrayGetCount(certs);
if(numCerts == 0) {
sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
return errSSLBadCert;
}
identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
if(identity == NULL) {
sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
return errSecParam;
}
if(CFGetTypeID(identity) != SecIdentityGetTypeID()) {
sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
return errSecParam;
}
ortn = SecIdentityCopyCertificate(identity, &certRef);
if(ortn) {
sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
return ortn;
}
ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
if(ortn) {
sslErrorLog("parseIncomingCerts: bad cert array (4)\n");
return ortn;
}
thisSslCert->next = certChain;
certChain = thisSslCert;
if(signerAlg != NULL) {
ortn = sslCertSignerAlg(certRef, signerAlg);
if(ortn) {
return ortn;
}
}
ortn = SecIdentityCopyPrivateKey(identity, &keyRef);
if(ortn) {
sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
(int)ortn);
return ortn;
}
*privKeyRef = keyRef;
ortn = SecCertificateGetCLHandle(certRef, &clHand);
if(ortn) {
sslErrorLog("parseIncomingCerts: SecCertificateGetCLHandle err %d\n",
(int)ortn);
return ortn;
}
certData.Data = thisSslCert->derCert.data;
certData.Length = thisSslCert->derCert.length;
crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, pubKey);
if(crtn) {
sslErrorLog("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n");
return (OSStatus)crtn;
}
for(cert=1; cert<numCerts; cert++) {
certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certs, cert);
if(certRef == NULL) {
sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
return errSecParam;
}
if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) {
sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
return errSecParam;
}
ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
if(ortn) {
sslErrorLog("parseIncomingCerts: bad cert array (7)\n");
return ortn;
}
thisSslCert->next = certChain;
certChain = thisSslCert;
}
*destCert = certChain;
return errSecSuccess;
sslDeleteCertificateChain(certChain, ctx);
return ortn;
}
#else
OSStatus
parseIncomingCerts(
SSLContext *ctx,
CFArrayRef certs,
CFArrayRef *destCertChain,
SSLPubKey **sslPubKey,
SSLPrivKey **sslPrivKey,
CFIndex *signerAlg)
{
OSStatus ortn;
CFIndex ix, numCerts;
SecIdentityRef identity;
CFMutableArrayRef certChain = NULL;
SecCertificateRef leafCert = NULL;
SecKeyRef pubKey = NULL;
SecKeyRef privKey = NULL;
SecTrustRef trust = NULL;
assert(ctx != NULL);
assert(destCertChain != NULL);
assert(sslPubKey != NULL);
assert(sslPrivKey != NULL);
if (certs == NULL) {
sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
ortn = errSSLBadCert;
goto errOut;
}
numCerts = CFArrayGetCount(certs);
if (numCerts == 0) {
sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
ortn = errSSLBadCert;
goto errOut;
}
identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
if (identity == NULL) {
sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
ortn = errSecParam;
goto errOut;
}
if (CFGetTypeID(identity) != SecIdentityGetTypeID()) {
sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
ortn = errSecParam;
goto errOut;
}
ortn = SecIdentityCopyCertificate(identity, &leafCert);
if (ortn) {
sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
goto errOut;
}
ortn = SecIdentityCopyPrivateKey(identity, &privKey);
if (ortn) {
sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
(int)ortn);
goto errOut;
}
certChain = CFArrayCreateMutable(kCFAllocatorDefault, numCerts,
&kCFTypeArrayCallBacks);
if (!certChain) {
ortn = errSecAllocate;
goto errOut;
}
CFArrayAppendValue(certChain, leafCert);
for (ix = 1; ix < numCerts; ++ix) {
SecCertificateRef intermediate =
(SecCertificateRef)CFArrayGetValueAtIndex(certs, ix);
if (intermediate == NULL) {
sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
ortn = errSecParam;
goto errOut;
}
if (CFGetTypeID(intermediate) != SecCertificateGetTypeID()) {
sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
ortn = errSecParam;
goto errOut;
}
CFArrayAppendValue(certChain, intermediate);
}
#if TARGET_OS_IPHONE
ortn = SecTrustCreateWithCertificates(certChain, NULL, &trust);
#else
{
SecPolicyRef policy = SecPolicyCreateBasicX509();
ortn = SecTrustCreateWithCertificates(certChain, policy, &trust);
CFReleaseSafe(policy);
if (!ortn) {
CFArrayRef emptyArray = CFArrayCreate(NULL, NULL, 0, NULL);
(void)SecTrustSetAnchorCertificates(trust, emptyArray);
(void)SecTrustSetKeychains(trust, emptyArray);
CFReleaseSafe(emptyArray);
}
}
#endif
if (ortn) {
sslErrorLog("parseIncomingCerts: SecTrustCreateWithCertificates err %d\n",
(int)ortn);
goto errOut;
}
#if !TARGET_OS_IPHONE
SecTrustResultType trustResult;
ortn = SecTrustEvaluate(trust, &trustResult);
if (ortn) {
sslErrorLog("parseIncomingCerts: SecTrustEvaluate err %d\n",
(int)ortn);
goto errOut;
}
#endif
pubKey = SecTrustCopyPublicKey(trust);
if (!pubKey) {
sslErrorLog("parseIncomingCerts: SecTrustCopyPublicKey failed\n");
ortn = errSecParam;
goto errOut;
}
errOut:
CFReleaseSafe(trust);
CFReleaseSafe(leafCert);
CFReleaseSafe(*destCertChain);
sslFreePubKey(sslPubKey);
sslFreePrivKey(sslPrivKey);
if (ortn) {
CFReleaseSafe(certChain);
CFReleaseSafe(pubKey);
CFReleaseSafe(privKey);
*destCertChain = NULL;
} else {
*destCertChain = certChain;
*sslPubKey = (SSLPubKey*)pubKey;
*sslPrivKey = (SSLPrivKey*)privKey;
}
return ortn;
}
#endif