#include "ssl.h"
#include "sslContext.h"
#include "sslMemory.h"
#include "appleCdsa.h"
#include "sslDebug.h"
#include "sslKeychain.h"
#include "sslUtils.h"
#include <string.h>
#include <assert.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <Security/Security.h>
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 memFullErr;
}
if(SSLAllocBuffer(thisSslCert->derCert, certData.Length,
ctx)) {
return memFullErr;
}
memcpy(thisSslCert->derCert.data, certData.Data, certData.Length);
thisSslCert->derCert.length = certData.Length;
*sslCert = thisSslCert;
return noErr;
}
OSStatus
parseIncomingCerts(
SSLContext *ctx,
CFArrayRef certs,
SSLCertificate **destCert,
CSSM_KEY_PTR *pubKey,
CSSM_KEY_PTR *privKey,
CSSM_CSP_HANDLE *cspHand)
{
CFIndex numCerts;
CFIndex cert;
SSLCertificate *certChain = NULL;
SSLCertificate *thisSslCert;
SecKeychainRef kcRef;
OSStatus ortn;
SecIdentityRef identity;
SecCertificateRef certRef;
SecKeyRef keyRef;
CSSM_DATA certData;
CSSM_CL_HANDLE clHand; CSSM_RETURN crtn;
assert(ctx != NULL);
assert(destCert != NULL);
assert(pubKey != NULL);
assert(privKey != NULL);
assert(cspHand != NULL);
sslDeleteCertificateChain(*destCert, ctx);
*destCert = NULL;
*pubKey = NULL;
*privKey = NULL;
*cspHand = 0;
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 paramErr;
}
if(CFGetTypeID(identity) != SecIdentityGetTypeID()) {
sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
return paramErr;
}
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;
ortn = SecIdentityCopyPrivateKey(identity, &keyRef);
if(ortn) {
sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
(int)ortn);
return ortn;
}
ortn = SecKeyGetCSSMKey(keyRef, (const CSSM_KEY **)privKey);
if(ortn) {
sslErrorLog("parseIncomingCerts: SecKeyGetCSSMKey err %d\n",
(int)ortn);
return ortn;
}
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;
}
ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef);
if(ortn) {
sslErrorLog("parseIncomingCerts: SecKeychainItemCopyKeychain err %d\n",
(int)ortn);
return ortn;
}
ortn = SecKeychainGetCSPHandle(kcRef, cspHand);
if(ortn) {
sslErrorLog("parseIncomingCerts: SecKeychainGetCSPHandle err %d\n",
(int)ortn);
return ortn;
}
for(cert=1; cert<numCerts; cert++) {
certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certs, cert);
if(certRef == NULL) {
sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
return paramErr;
}
if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) {
sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
return paramErr;
}
ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
if(ortn) {
sslErrorLog("parseIncomingCerts: bad cert array (7)\n");
return ortn;
}
thisSslCert->next = certChain;
certChain = thisSslCert;
}
ortn = sslVerifyCertChain(ctx, *certChain, false);
if(ortn) {
goto errOut;
}
*destCert = certChain;
return noErr;
errOut:
sslDeleteCertificateChain(certChain, ctx);
return ortn;
}