#include "ssl.h"
#if USE_CDSA_CRYPTO
#include "appleCdsa.h"
#include "sslCrypto.h"
#include "CipherSuite.h"
#include "sslContext.h"
#include "sslMemory.h"
#include "sslUtils.h"
#include "sslDebug.h"
#include "sslBER.h"
#include "ModuleAttacher.h"
#ifndef _SSL_KEYCHAIN_H_
#include "sslKeychain.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <Security/cssm.h>
#include <Security/cssmapple.h>
#include <Security/Security.h>
#include <Security/SecTrustPriv.h>
#include <Security/SecPolicyPriv.h>
#include <Security/SecKeyPriv.h>
#include <Security/x509defs.h>
#include <Security/oidsalg.h>
#include <Security/oidscert.h>
#pragma mark -
#pragma mark Utilities
OSStatus sslSetUpSymmKey(
CSSM_KEY_PTR symKey,
CSSM_ALGORITHMS alg,
CSSM_KEYUSE keyUse, CSSM_BOOL copyKey, uint8 *keyData,
size_t keyDataLen) {
OSStatus serr;
CSSM_KEYHEADER *hdr;
memset(symKey, 0, sizeof(CSSM_KEY));
if(copyKey) {
serr = stSetUpCssmData(&symKey->KeyData, keyDataLen);
if(serr) {
return serr;
}
memmove(symKey->KeyData.Data, keyData, keyDataLen);
}
else {
symKey->KeyData.Data = keyData;
symKey->KeyData.Length = keyDataLen;
}
hdr = &symKey->KeyHeader;
hdr->BlobType = CSSM_KEYBLOB_RAW;
hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
hdr->AlgorithmId = alg;
hdr->KeyClass = CSSM_KEYCLASS_SESSION_KEY;
hdr->LogicalKeySizeInBits = keyDataLen * 8;
hdr->KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE;
hdr->KeyUsage = keyUse;
hdr->WrapAlgorithmId = CSSM_ALGID_NONE;
return noErr;
}
OSStatus sslFreeKey(
CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR *key,
#if ST_KC_KEYS_NEED_REF
SecKeychainRef *kcItem)
#else
void *kcItem)
#endif
{
assert(key != NULL);
if(*key != NULL) {
if(cspHand != 0) {
CSSM_FreeKey(cspHand, NULL, *key, CSSM_FALSE);
}
stAppFree(*key, NULL); *key = NULL;
}
#if ST_KC_KEYS_NEED_REF
if((kcItem != NULL) && (*kcItem != NULL)) {
KCReleaseItem(kcItem);
*kcItem = NULL;
}
#endif
return noErr;
}
void * stAppMalloc (size_t size, void *allocRef) {
return( malloc(size) );
}
void stAppFree (void *mem_ptr, void *allocRef) {
free(mem_ptr);
return;
}
void * stAppRealloc (void *ptr, size_t size, void *allocRef) {
return( realloc( ptr, size ) );
}
void * stAppCalloc (uint32_t num, size_t size, void *allocRef) {
return( calloc( num, size ) );
}
OSStatus attachToCsp(SSLContext *ctx)
{
assert(ctx != NULL);
if(ctx->cspHand != 0) {
return noErr;
}
else {
return errSSLModuleAttach;
}
}
OSStatus attachToCl(SSLContext *ctx)
{
assert(ctx != NULL);
if(ctx->clHand != 0) {
return noErr;
}
else {
return errSSLModuleAttach;
}
}
OSStatus attachToTp(SSLContext *ctx)
{
assert(ctx != NULL);
if(ctx->tpHand != 0) {
return noErr;
}
else {
return errSSLModuleAttach;
}
}
OSStatus attachToAll(SSLContext *ctx)
{
CSSM_RETURN crtn;
assert(ctx != NULL);
crtn = attachToModules(&ctx->cspHand, &ctx->clHand, &ctx->tpHand);
if(crtn) {
return errSSLModuleAttach;
}
else {
return noErr;
}
}
OSStatus detachFromAll(SSLContext *ctx)
{
#if 0
assert(ctx != NULL);
if(ctx->cspHand != 0) {
CSSM_ModuleDetach(ctx->cspHand);
ctx->cspHand = 0;
}
if(ctx->tpHand != 0) {
CSSM_ModuleDetach(ctx->tpHand);
ctx->tpHand = 0;
}
if(ctx->clHand != 0) {
CSSM_ModuleDetach(ctx->clHand);
ctx->clHand = 0;
}
#endif
return noErr;
}
static CSSM_RETURN sslAddBlindingAttr(
CSSM_CC_HANDLE ccHand)
{
CSSM_CONTEXT_ATTRIBUTE newAttr;
CSSM_RETURN crtn;
newAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
newAttr.AttributeLength = sizeof(uint32_t);
newAttr.Attribute.Uint32 = 1;
crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr);
if(crtn) {
stPrintCdsaError("CSSM_UpdateContextAttributes", crtn);
}
return crtn;
}
static OSStatus sslGetKeyParts(
SecKeyRef keyRef,
const CSSM_KEY **cssmKey,
CSSM_CSP_HANDLE *cspHand)
{
OSStatus ortn = SecKeyGetCSSMKey(keyRef, cssmKey);
if(ortn) {
sslErrorLog("sslGetKeyParts: SecKeyGetCSSMKey err %d\n",
(int)ortn);
return ortn;
}
ortn = SecKeyGetCSPHandle(keyRef, cspHand);
if(ortn) {
sslErrorLog("sslGetKeyParts: SecKeyGetCSPHandle err %d\n",
(int)ortn);
}
return ortn;
}
static SecCertificateRef sslGetMatchingCertInArray(
SecCertificateRef certRef,
CFArrayRef certArray)
{
CSSM_DATA certData;
OSStatus ortn;
int idx, count;
if(certRef == NULL || certArray == NULL) {
return NULL;
}
ortn = SecCertificateGetData(certRef, &certData);
if(!ortn) {
count = CFArrayGetCount(certArray);
for(idx=0; idx<count; idx++) {
CSSM_DATA aData = { 0, NULL };
SecCertificateRef aCert = (SecCertificateRef)CFArrayGetValueAtIndex(certArray, idx);
ortn = SecCertificateGetData(aCert, &aData);
if (!ortn && aData.Length == certData.Length &&
!memcmp(aData.Data, certData.Data, certData.Length)) {
return aCert;
}
}
}
return NULL;
}
#pragma mark -
#pragma mark CSSM_DATA routines
CSSM_DATA_PTR stMallocCssmData(
size_t size)
{
CSSM_DATA_PTR rtn = (CSSM_DATA_PTR)stAppMalloc(sizeof(CSSM_DATA), NULL);
if(rtn == NULL) {
return NULL;
}
rtn->Length = size;
if(size == 0) {
rtn->Data = NULL;
}
else {
rtn->Data = (uint8 *)stAppMalloc(size, NULL);
}
return rtn;
}
void stFreeCssmData(
CSSM_DATA_PTR data,
CSSM_BOOL freeStruct)
{
if(data == NULL) {
return;
}
if(data->Data != NULL) {
stAppFree(data->Data, NULL);
data->Data = NULL;
}
data->Length = 0;
if(freeStruct) {
stAppFree(data, NULL);
}
}
OSStatus stSetUpCssmData(
CSSM_DATA_PTR data,
size_t length)
{
assert(data != NULL);
if(data->Length == 0) {
data->Data = (uint8 *)stAppMalloc(length, NULL);
if(data->Data == NULL) {
return memFullErr;
}
}
else if(data->Length < length) {
sslErrorLog("stSetUpCssmData: length too small\n");
return memFullErr;
}
data->Length = length;
return noErr;
}
static OSStatus sslKeyToSigAlg(
const CSSM_KEY *cssmKey,
CSSM_ALGORITHMS *sigAlg)
{
OSStatus ortn = noErr;
switch(cssmKey->KeyHeader.AlgorithmId) {
case CSSM_ALGID_RSA:
*sigAlg = CSSM_ALGID_RSA;
break;
case CSSM_ALGID_DSA:
*sigAlg = CSSM_ALGID_DSA;
break;
case CSSM_ALGID_ECDSA:
*sigAlg = CSSM_ALGID_ECDSA;
break;
default:
ortn = errSSLBadConfiguration;
break;
}
return ortn;
}
#pragma mark -
#pragma mark Public CSP Functions
OSStatus sslRawSign(
SSLContext *ctx,
SecKeyRef privKeyRef,
const UInt8 *plainText,
size_t plainTextLen,
UInt8 *sig, size_t sigLen, size_t *actualBytes) {
CSSM_CC_HANDLE sigHand = 0;
CSSM_RETURN crtn;
OSStatus serr;
CSSM_DATA sigData;
CSSM_DATA ptextData;
CSSM_CSP_HANDLE cspHand;
const CSSM_KEY *privKey;
const CSSM_ACCESS_CREDENTIALS *creds;
assert(ctx != NULL);
if((privKeyRef == NULL) ||
(plainText == NULL) ||
(sig == NULL) ||
(actualBytes == NULL)) {
sslErrorLog("sslRsaRawSign: bad arguments\n");
return errSSLInternal;
}
*actualBytes = 0;
serr = sslGetKeyParts(privKeyRef, &privKey, &cspHand);
if(serr) {
return serr;
}
assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY);
CSSM_ALGORITHMS sigAlg;
serr = sslKeyToSigAlg(privKey, &sigAlg);
if(serr) {
return serr;
}
serr = SecKeyGetCredentials(privKeyRef,
CSSM_ACL_AUTHORIZATION_SIGN,
kSecCredentialTypeDefault,
&creds);
if(serr) {
sslErrorLog("sslRawSign: SecKeyGetCredentials err %lu\n", (unsigned long)serr);
return serr;
}
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
sigAlg,
creds,
privKey,
&sigHand);
if(crtn) {
stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn);
return errSSLCrypto;
}
if((ctx->rsaBlindingEnable) &&
(privKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA)) {
crtn = sslAddBlindingAttr(sigHand);
if(crtn) {
return crtn;
}
}
ptextData.Data = (uint8 *)plainText;
ptextData.Length = plainTextLen;
sigData.Data = sig;
sigData.Length = sigLen;
crtn = CSSM_SignData(sigHand,
&ptextData,
1,
CSSM_ALGID_NONE, &sigData);
if(crtn) {
stPrintCdsaError("CSSM_SignData", crtn);
serr = errSSLCrypto;
}
else {
*actualBytes = sigData.Length;
serr = noErr;
}
if(sigHand != 0) {
CSSM_DeleteContext(sigHand);
}
return serr;
}
OSStatus sslRawVerify(
SSLContext *ctx,
const SSLPubKey *sslPubKey,
const UInt8 *plainText,
size_t plainTextLen,
const UInt8 *sig,
size_t sigLen)
{
CSSM_CC_HANDLE sigHand = 0;
CSSM_RETURN crtn;
OSStatus serr;
CSSM_DATA sigData;
CSSM_DATA ptextData;
const CSSM_KEY *pubKey;
CSSM_CSP_HANDLE cspHand;
assert(ctx != NULL);
if((sslPubKey == NULL) ||
(sslPubKey->key == NULL) ||
(sslPubKey->csp == 0) ||
(plainText == NULL) ||
(sig == NULL)) {
sslErrorLog("sslRawVerify: bad arguments\n");
return errSSLInternal;
}
pubKey = &sslPubKey->key;
cspHand = sslPubKey->csp;
CSSM_ALGORITHMS sigAlg;
serr = sslKeyToSigAlg(pubKey, &sigAlg);
if(serr) {
return serr;
}
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
sigAlg,
NULL, pubKey,
&sigHand);
if(sigHand == 0) {
stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn);
return errSSLCrypto;
}
ptextData.Data = (uint8 *)plainText;
ptextData.Length = plainTextLen;
sigData.Data = (uint8 *)sig;
sigData.Length = sigLen;
crtn = CSSM_VerifyData(sigHand,
&ptextData,
1,
CSSM_ALGID_NONE, &sigData);
if(crtn) {
stPrintCdsaError("CSSM_VerifyData", crtn);
serr = errSSLCrypto;
}
else {
serr = noErr;
}
if(sigHand != 0) {
CSSM_DeleteContext(sigHand);
}
return serr;
}
OSStatus sslRsaEncrypt(
SSLContext *ctx,
const CSSM_KEY *pubKey,
CSSM_CSP_HANDLE cspHand,
CSSM_PADDING padding, const UInt8 *plainText,
size_t plainTextLen,
UInt8 *cipherText, size_t cipherTextLen, size_t *actualBytes) {
CSSM_DATA ctextData = {0, NULL};
CSSM_DATA ptextData;
CSSM_DATA remData = {0, NULL};
CSSM_CC_HANDLE cryptHand = 0;
OSStatus serr = errSSLInternal;
CSSM_RETURN crtn;
size_t bytesMoved = 0;
CSSM_ACCESS_CREDENTIALS creds;
assert(ctx != NULL);
assert(actualBytes != NULL);
*actualBytes = 0;
if((pubKey == NULL) || (cspHand == 0)) {
sslErrorLog("sslRsaEncrypt: bad pubKey/cspHand\n");
return errSSLInternal;
}
assert(pubKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY);
#if RSA_PUB_KEY_USAGE_HACK
((CSSM_KEY_PTR)pubKey)->KeyHeader.KeyUsage |= CSSM_KEYUSE_ENCRYPT;
#endif
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
CSSM_ALGID_RSA,
&creds,
pubKey,
padding,
&cryptHand);
if(crtn) {
stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
return errSSLCrypto;
}
ptextData.Data = (uint8 *)plainText;
ptextData.Length = plainTextLen;
crtn = CSSM_EncryptData(cryptHand,
&ptextData,
1,
&ctextData,
1,
&bytesMoved,
&remData);
if(crtn == CSSM_OK) {
if(bytesMoved > cipherTextLen) {
sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %lu bytesMoved %lu\n",
cipherTextLen, bytesMoved);
serr = errSSLCrypto;
}
else {
size_t toMoveCtext;
size_t toMoveRem;
*actualBytes = bytesMoved;
if(ctextData.Length > bytesMoved) {
toMoveCtext = bytesMoved;
toMoveRem = 0;
}
else {
toMoveCtext = ctextData.Length;
toMoveRem = bytesMoved - toMoveCtext; }
if(toMoveCtext) {
memmove(cipherText, ctextData.Data, toMoveCtext);
}
if(toMoveRem) {
memmove(cipherText + toMoveCtext, remData.Data,
toMoveRem);
}
serr = noErr;
}
}
else {
stPrintCdsaError("CSSM_EncryptData", crtn);
serr = errSSLCrypto;
}
if(cryptHand != 0) {
CSSM_DeleteContext(cryptHand);
}
stFreeCssmData(&ctextData, CSSM_FALSE);
stFreeCssmData(&remData, CSSM_FALSE);
return serr;
}
OSStatus sslRsaDecrypt(
SSLContext *ctx,
SecKeyRef privKeyRef,
CSSM_PADDING padding, const UInt8 *cipherText,
size_t cipherTextLen,
UInt8 *plainText, size_t plainTextLen, size_t *actualBytes) {
CSSM_DATA ptextData = {0, NULL};
CSSM_DATA ctextData;
CSSM_DATA remData = {0, NULL};
CSSM_CC_HANDLE cryptHand = 0;
OSStatus serr = errSSLInternal;
CSSM_RETURN crtn;
size_t bytesMoved = 0;
CSSM_CSP_HANDLE cspHand;
const CSSM_KEY *privKey;
const CSSM_ACCESS_CREDENTIALS *creds;
assert(ctx != NULL);
assert(actualBytes != NULL);
*actualBytes = 0;
if(privKeyRef == NULL) {
sslErrorLog("sslRsaDecrypt: bad privKey\n");
return errSSLInternal;
}
serr = sslGetKeyParts(privKeyRef, &privKey, &cspHand);
if(serr) {
return serr;
}
assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY);
serr = SecKeyGetCredentials(privKeyRef,
CSSM_ACL_AUTHORIZATION_DECRYPT,
kSecCredentialTypeDefault,
&creds);
if(serr) {
sslErrorLog("sslRsaDecrypt: SecKeyGetCredentials err %lu\n", (unsigned long)serr);
return serr;
}
crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
CSSM_ALGID_RSA,
creds,
privKey,
padding,
&cryptHand);
if(crtn) {
stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
return errSSLCrypto;
}
ctextData.Data = (uint8 *)cipherText;
ctextData.Length = cipherTextLen;
if((ctx->rsaBlindingEnable) &&
(privKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA)) {
crtn = sslAddBlindingAttr(cryptHand);
if(crtn) {
return crtn;
}
}
crtn = CSSM_DecryptData(cryptHand,
&ctextData,
1,
&ptextData,
1,
&bytesMoved,
&remData);
if(crtn == CSSM_OK) {
if(bytesMoved > plainTextLen) {
sslErrorLog("sslRsaDecrypt overflow; plainTextLen %lu bytesMoved %lu\n",
plainTextLen, bytesMoved);
serr = errSSLCrypto;
}
else {
size_t toMovePtext;
size_t toMoveRem;
*actualBytes = bytesMoved;
if(ptextData.Length > bytesMoved) {
toMovePtext = bytesMoved;
toMoveRem = 0;
}
else {
toMovePtext = ptextData.Length;
toMoveRem = bytesMoved - toMovePtext; }
if(toMovePtext) {
memmove(plainText, ptextData.Data, toMovePtext);
}
if(toMoveRem) {
memmove(plainText + toMovePtext, remData.Data,
toMoveRem);
}
serr = noErr;
}
}
else {
stPrintCdsaError("CSSM_DecryptData", crtn);
serr = errSSLCrypto;
}
if(cryptHand != 0) {
CSSM_DeleteContext(cryptHand);
}
stFreeCssmData(&ptextData, CSSM_FALSE);
stFreeCssmData(&remData, CSSM_FALSE);
return serr;
}
uint32_t sslPrivKeyLengthInBytes(const SSLPrivKey *sslKey)
{
const CSSM_KEY *cssmKey;
assert(sslKey != NULL);
assert(sslKey->key != NULL);
err = SecKeyGetCSSMKey(sslKey->key, &cssmKey);
if(err) {
sslErrorLog("sslKeyLengthInBytes: SecKeyGetCSSMKey err %d\n", (int)err);
return 0;
}
return (((cssmKey->KeyHeader.LogicalKeySizeInBits) + 7) / 8);
}
uint32_t sslPubKeyLengthInBytes(const SSLPubKey *sslKey)
{
const CSSM_KEY *cssmKey;
assert(sslKey != NULL);
assert(sslKey->key != NULL);
return (((sslKey->key.KeyHeader.LogicalKeySizeInBits) + 7) / 8);
}
OSStatus sslGetMaxSigSize(
const CSSM_KEY *privKey,
uint32_t *maxSigSize)
{
OSStatus ortn = noErr;
assert(privKey != NULL);
assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY);
switch(privKey->KeyHeader.AlgorithmId) {
case CSSM_ALGID_RSA:
*maxSigSize = sslPrivKeyLengthInBytes(privKey);
break;
case CSSM_ALGID_DSA:
{
uint32_t sizeOfOneInt;
sizeOfOneInt = (160 / 8) + 1 + 2; *maxSigSize = (2 * sizeOfOneInt) + 5;
break;
}
default:
ortn = errSSLBadConfiguration;
break;
}
return ortn;
}
OSStatus sslGetPubKeyBits(
SSLContext *ctx,
const CSSM_KEY *pubKey,
CSSM_CSP_HANDLE cspHand,
SSLBuffer *modulus, SSLBuffer *exponent) {
CSSM_KEY wrappedKey;
CSSM_BOOL didWrap = CSSM_FALSE;
const CSSM_KEYHEADER *hdr;
SSLBuffer pubKeyBlob;
OSStatus srtn;
assert(ctx != NULL);
assert(modulus != NULL);
assert(exponent != NULL);
assert(pubKey != NULL);
hdr = &pubKey->KeyHeader;
if(hdr->KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) {
sslErrorLog("sslGetPubKeyBits: bad keyClass (%ld)\n", (long)hdr->KeyClass);
return errSSLInternal;
}
if(hdr->AlgorithmId != CSSM_ALGID_RSA) {
sslErrorLog("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", (long)hdr->AlgorithmId);
return errSSLInternal;
}
assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
switch(hdr->BlobType) {
case CSSM_KEYBLOB_RAW:
CSSM_TO_SSLBUF(&pubKey->KeyData, &pubKeyBlob);
break;
case CSSM_KEYBLOB_REFERENCE:
sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
(long)hdr->BlobType);
return errSSLInternal;
#if 0
srtn = attachToCsp(ctx);
if(srtn) {
return srtn;
}
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
crtn = CSSM_CSP_CreateSymmetricContext(ctx->cspHand,
CSSM_ALGID_NONE,
CSSM_ALGMODE_NONE,
&creds, pubKey,
NULL, CSSM_PADDING_NONE,
0, &ccHand);
if(crtn) {
stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn);
return errSSLCrypto;
}
memset(&wrappedKey, 0, sizeof(CSSM_KEY));
crtn = CSSM_WrapKey(ccHand,
&creds,
pubKey,
NULL, &wrappedKey);
CSSM_DeleteContext(ccHand);
if(crtn) {
stPrintCdsaError("CSSM_WrapKey", crtn);
return errSSLCrypto;
}
hdr = &wrappedKey.KeyHeader;
if(hdr->BlobType != CSSM_KEYBLOB_RAW) {
sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
hdr->BlobType);
return errSSLCrypto;
}
didWrap = CSSM_TRUE;
CSSM_TO_SSLBUF(&wrappedKey.KeyData, &pubKeyBlob);
break;
#endif
default:
sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
(long)hdr->BlobType);
return errSSLInternal;
}
assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
srtn = sslDecodeRsaBlob(&pubKeyBlob, modulus, exponent);
if(didWrap) {
CSSM_FreeKey(ctx->cspHand, NULL, &wrappedKey, CSSM_FALSE);
}
return srtn;
}
OSStatus sslGetPubKeyFromBits(
SSLContext *ctx,
const SSLBuffer *modulus,
const SSLBuffer *exponent,
CSSM_KEY_PTR *pubKey, CSSM_CSP_HANDLE *cspHand) {
CSSM_KEY_PTR key = NULL;
OSStatus serr;
SSLBuffer blob;
CSSM_KEYHEADER_PTR hdr;
CSSM_KEY_SIZE keySize;
CSSM_RETURN crtn;
assert((ctx != NULL) && (modulus != NULL) && (exponent != NULL));
assert((pubKey != NULL) && (cspHand != NULL));
*pubKey = NULL;
*cspHand = 0;
serr = attachToCsp(ctx);
if(serr) {
return serr;
}
serr = sslEncodeRsaBlob(modulus, exponent, &blob);
if(serr) {
return serr;
}
key = (CSSM_KEY_PTR)sslMalloc(sizeof(CSSM_KEY));
if(key == NULL) {
return memFullErr;
}
memset(key, 0, sizeof(CSSM_KEY));
hdr = &key->KeyHeader;
hdr->HeaderVersion = CSSM_KEYHEADER_VERSION;
hdr->BlobType = CSSM_KEYBLOB_RAW;
hdr->AlgorithmId = CSSM_ALGID_RSA;
hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
hdr->KeyUsage = CSSM_KEYUSE_VERIFY;
hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
hdr->WrapAlgorithmId = CSSM_ALGID_NONE;
hdr->WrapMode = CSSM_ALGMODE_NONE;
SSLBUF_TO_CSSM(&blob, &key->KeyData);
crtn = CSSM_QueryKeySizeInBits(ctx->cspHand, CSSM_INVALID_HANDLE, key, &keySize);
if(crtn) {
stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn);
serr = errSSLCrypto;
goto abort;
}
hdr->LogicalKeySizeInBits = keySize.EffectiveKeySizeInBits;
*pubKey = key;
*cspHand = ctx->cspHand;
return noErr;
abort:
sslFreeKey(ctx->cspHand, &key, NULL);
return serr;
}
#ifdef UNUSED_FUNCTIONS
static OSStatus sslNullUnwrapKey(
CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR rawKey,
CSSM_KEY_PTR refKey)
{
CSSM_DATA descData = {0, 0};
CSSM_RETURN crtn;
CSSM_CC_HANDLE ccHand;
CSSM_ACCESS_CREDENTIALS creds;
CSSM_DATA labelData = {4, (uint8 *)"none"};
uint32 keyAttr;
OSStatus ortn = noErr;
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
memset(refKey, 0, sizeof(CSSM_KEY));
crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
CSSM_ALGID_NONE,
CSSM_ALGMODE_NONE,
&creds,
NULL, NULL, CSSM_PADDING_NONE,
0, &ccHand);
if(crtn) {
stPrintCdsaError("sslNullUnwrapKey: CSSM_CSP_CreateSymmetricContext\n", crtn);
return errSSLCrypto;
}
keyAttr = rawKey->KeyHeader.KeyAttr;
keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE |
CSSM_KEYATTR_MODIFIABLE);
keyAttr |= CSSM_KEYATTR_RETURN_REF;
if(rawKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
keyAttr |= CSSM_KEYATTR_EXTRACTABLE;
}
crtn = CSSM_UnwrapKey(ccHand,
NULL, rawKey,
rawKey->KeyHeader.KeyUsage,
keyAttr,
&labelData,
NULL, refKey,
&descData); if(crtn != CSSM_OK) {
stPrintCdsaError("sslNullUnwrapKey: CSSM_UnwrapKey\n", crtn);
ortn = errSSLCrypto;
}
if(CSSM_DeleteContext(ccHand)) {
printf("CSSM_DeleteContext failure\n");
}
return crtn;
}
#endif
static OSStatus sslNullWrapKey(
CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR refKey,
CSSM_KEY_PTR rawKey)
{
CSSM_DATA descData = {0, 0};
CSSM_RETURN crtn;
CSSM_CC_HANDLE ccHand;
CSSM_ACCESS_CREDENTIALS creds;
uint32 keyAttr;
OSStatus ortn = noErr;
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
memset(rawKey, 0, sizeof(CSSM_KEY));
crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
CSSM_ALGID_NONE,
CSSM_ALGMODE_NONE,
&creds,
NULL, NULL, CSSM_PADDING_NONE,
0, &ccHand);
if(crtn) {
stPrintCdsaError("sslNullWrapKey: CSSM_CSP_CreateSymmetricContext\n", crtn);
return errSSLCrypto;
}
keyAttr = rawKey->KeyHeader.KeyAttr;
keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE |
CSSM_KEYATTR_MODIFIABLE);
keyAttr |= CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
crtn = CSSM_WrapKey(ccHand,
&creds,
refKey,
&descData,
rawKey);
if(crtn != CSSM_OK) {
stPrintCdsaError("sslNullWrapKey: CSSM_WrapKey\n", crtn);
ortn = errSSLCrypto;
}
if(CSSM_DeleteContext(ccHand)) {
printf("CSSM_DeleteContext failure\n");
}
return crtn;
}
#pragma mark -
#pragma mark Public Certificate Functions
OSStatus sslPubKeyFromCert(
SSLContext *ctx,
const SSLBuffer *derCert,
SSLPubKey *pubKey) {
OSStatus serr;
CSSM_DATA certData;
CSSM_RETURN crtn;
assert(ctx != NULL);
assert(pubKey != NULL);
pubKey->key = NULL;
pubKey->cspHand = 0;
serr = attachToCl(ctx);
if(serr) {
return serr;
}
serr = attachToCsp(ctx);
if(serr) {
return serr;
}
SSLBUF_TO_CSSM(derCert, &certData);
crtn = CSSM_CL_CertGetKeyInfo(ctx->clHand, &certData, &pubKey->key);
if(crtn) {
return errSSLBadCert;
}
else {
pubKey->cspHand = ctx->cspHand;
return noErr;
}
}
static void sslReleaseArray(
CFArrayRef a)
{
CFIndex num = CFArrayGetCount(a);
CFIndex dex;
for(dex=0; dex<num; dex++) {
CFTypeRef elmt = (CFTypeRef)CFArrayGetValueAtIndex(a, dex);
secdebug("sslcert", "Freeing cert %p", elmt);
CFRelease(elmt);
}
}
OSStatus sslVerifyCertChain(
SSLContext *ctx,
const SSLCertificate *certChain,
bool arePeerCerts)
{
uint32_t numCerts;
int i;
OSStatus serr;
SSLCertificate *c = (SSLCertificate *)certChain;
CSSM_RETURN crtn;
CSSM_APPLE_TP_SSL_OPTIONS sslOpts;
CSSM_APPLE_TP_ACTION_DATA tpActionData;
SecPolicyRef policy = NULL;
SecPolicySearchRef policySearch = NULL;
CFDataRef actionData = NULL;
CSSM_DATA sslOptsData;
CFMutableArrayRef anchors = NULL;
SecCertificateRef cert; SecTrustResultType secTrustResult;
CFMutableArrayRef kcList = NULL;
SecTrustRef theTrust = NULL;
if(ctx->peerSecTrust && arePeerCerts) {
CFRelease(ctx->peerSecTrust);
ctx->peerSecTrust = NULL;
}
numCerts = SSLGetCertificateChainLength(certChain);
if(numCerts == 0) {
return errSSLBadCert;
}
CFMutableArrayRef certGroup = CFArrayCreateMutable(NULL, numCerts,
&kCFTypeArrayCallBacks);
if(certGroup == NULL) {
return memFullErr;
}
for(i=numCerts-1; i>=0; i--) {
CSSM_DATA cdata;
SSLBUF_TO_CSSM(&c->derCert, &cdata);
serr = SecCertificateCreateFromData(&cdata, CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER, &cert);
if(serr) {
goto errOut;
}
secdebug("sslcert", "Adding cert %p", cert);
CFArrayInsertValueAtIndex(certGroup, 0, cert);
c = c->next;
}
serr = SecPolicySearchCreate(CSSM_CERT_X_509v3,
&CSSMOID_APPLE_TP_SSL,
NULL,
&policySearch);
if(serr) {
sslErrorLog("***sslVerifyCertChain: SecPolicySearchCreate rtn %d\n",
(int)serr);
goto errOut;
}
serr = SecPolicySearchCopyNext(policySearch, &policy);
if(serr) {
sslErrorLog("***sslVerifyCertChain: SecPolicySearchCopyNext rtn %d\n",
(int)serr);
goto errOut;
}
sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
if(arePeerCerts) {
sslOpts.ServerNameLen = ctx->peerDomainNameLen;
sslOpts.ServerName = ctx->peerDomainName;
}
else {
sslOpts.ServerNameLen = 0;
sslOpts.ServerName = NULL;
}
sslOpts.Flags = 0;
if(ctx->protocolSide == kSSLServerSide) {
sslOpts.Flags |= CSSM_APPLE_TP_SSL_CLIENT;
}
sslOptsData.Data = (uint8 *)&sslOpts;
sslOptsData.Length = sizeof(sslOpts);
serr = SecPolicySetValue(policy, &sslOptsData);
if(serr) {
sslErrorLog("***sslVerifyCertChain: SecPolicySetValue rtn %d\n",
(int)serr);
goto errOut;
}
serr = SecTrustCreateWithCertificates(certGroup, policy, &theTrust);
if(serr) {
sslErrorLog("***sslVerifyCertChain: SecTrustCreateWithCertificates "
"rtn %d\n", (int)serr);
goto errOut;
}
if(ctx->trustedCerts != NULL) {
serr = SecTrustSetAnchorCertificates(theTrust, ctx->trustedCerts);
if(serr) {
sslErrorLog("***sslVerifyCertChain: SecTrustSetAnchorCertificates "
"rtn %d\n", (int)serr);
goto errOut;
}
}
tpActionData.Version = CSSM_APPLE_TP_ACTION_VERSION;
tpActionData.ActionFlags = 0;
if(ctx->allowExpiredCerts) {
tpActionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED;
}
if(ctx->allowExpiredRoots) {
tpActionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT;
}
actionData = CFDataCreate(NULL, (UInt8 *)&tpActionData, sizeof(tpActionData));
serr = SecTrustSetParameters(theTrust, CSSM_TP_ACTION_DEFAULT,
actionData);
if(serr) {
sslErrorLog("***sslVerifyCertChain: SecTrustSetParameters rtn %d\n",
(int)serr);
goto errOut;
}
#if 0
kcList = CFArrayCreateMutable(NULL, 0, NULL);
if(kcList == NULL) {
sslErrorLog("***sslVerifyCertChain: error creating null kcList\n");
serr = memFullErr;
goto errOut;
}
serr = SecTrustSetKeychains(theTrust, kcList);
if(serr) {
sslErrorLog("***sslVerifyCertChain: SecTrustSetKeychains rtn %d\n",
(int)serr);
goto errOut;
}
#endif
if(arePeerCerts) {
ctx->peerSecTrust = theTrust;
CFRetain(theTrust);
}
if(!ctx->enableCertVerify) {
serr = noErr;
goto errOut;
}
if(ctx->trustedLeafCerts) {
if (sslGetMatchingCertInArray((SecCertificateRef)CFArrayGetValueAtIndex(certGroup, 0),
ctx->trustedLeafCerts)) {
serr = noErr;
goto errOut;
}
}
serr = SecTrustEvaluate(theTrust, &secTrustResult);
if(serr) {
sslErrorLog("***sslVerifyCertChain: SecTrustEvaluate rtn %d\n",
(int)serr);
goto errOut;
}
switch(secTrustResult) {
case kSecTrustResultUnspecified:
case kSecTrustResultProceed:
crtn = CSSM_OK;
break;
case kSecTrustResultDeny:
case kSecTrustResultConfirm:
crtn = CSSMERR_TP_NOT_TRUSTED;
break;
default:
{
OSStatus osCrtn;
serr = SecTrustGetCssmResultCode(theTrust, &osCrtn);
if(serr) {
sslErrorLog("***sslVerifyCertChain: SecTrustGetCssmResultCode"
" rtn %d\n", (int)serr);
goto errOut;
}
crtn = osCrtn;
}
}
if(crtn) {
switch(crtn) {
case CSSMERR_TP_INVALID_ANCHOR_CERT:
if(ctx->allowAnyRoot) {
serr = noErr;
sslErrorLog("***Warning: accepting unknown root cert\n");
}
else {
serr = errSSLUnknownRootCert;
}
break;
case CSSMERR_TP_NOT_TRUSTED:
if(ctx->allowAnyRoot) {
sslErrorLog("***Warning: accepting unverified cert chain\n");
serr = noErr;
}
else {
serr = errSSLNoRootCert;
}
break;
case CSSMERR_TP_CERT_EXPIRED:
assert(!ctx->allowExpiredCerts);
serr = errSSLCertExpired;
break;
case CSSMERR_TP_CERT_NOT_VALID_YET:
serr = errSSLCertNotYetValid;
break;
case CSSMERR_APPLETP_HOSTNAME_MISMATCH:
serr = errSSLHostNameMismatch;
break;
case errSecInvalidTrustSettings:
serr = crtn;
break;
default:
stPrintCdsaError("sslVerifyCertChain: SecTrustEvaluate returned",
crtn);
serr = errSSLXCertChainInvalid;
break;
}
}
errOut:
if(policy) {
CFRelease(policy);
}
if(policySearch) {
CFRelease(policySearch);
}
if(actionData) {
CFRelease(actionData);
}
if(anchors) {
sslReleaseArray(anchors);
CFRelease(anchors);
}
if(certGroup) {
sslReleaseArray(certGroup);
CFRelease(certGroup);
}
if(kcList) {
CFRelease(kcList);
}
if(theTrust) {
CFRelease(theTrust);
}
return serr;
}
#ifndef NDEBUG
void stPrintCdsaError(const char *op, CSSM_RETURN crtn)
{
cssmPerror(op, crtn);
}
#endif
#pragma mark -
#pragma mark Diffie-Hellman Support
OSStatus sslDhGenKeyPairClient(
SSLContext *ctx,
const SSLBuffer *prime,
const SSLBuffer *generator,
CSSM_KEY_PTR publicKey, CSSM_KEY_PTR privateKey) {
assert((prime->data != NULL) && (generator->data != NULL));
if(prime->data && !generator->data) {
return errSSLProtocol;
}
if(!prime->data && generator->data) {
return errSSLProtocol;
}
SSLBuffer sParam;
OSStatus ortn = sslEncodeDhParams(prime, generator, &sParam);
if(ortn) {
sslErrorLog("***sslDhGenerateKeyPairClient: DH param error\n");
return ortn;
}
ortn = sslDhGenerateKeyPair(ctx, &sParam, prime->length * 8, publicKey, privateKey);
SSLFreeBuffer(&sParam, ctx);
return ortn;
}
OSStatus sslDhGenerateKeyPair(
SSLContext *ctx,
const SSLBuffer *paramBlob,
uint32_t keySizeInBits,
CSSM_KEY_PTR publicKey, CSSM_KEY_PTR privateKey) {
CSSM_RETURN crtn;
CSSM_CC_HANDLE ccHandle;
CSSM_DATA labelData = {8, (uint8 *)"tempKey"};
OSStatus ortn = noErr;
CSSM_DATA cParamBlob;
assert(ctx != NULL);
assert(ctx->cspHand != 0);
memset(publicKey, 0, sizeof(CSSM_KEY));
memset(privateKey, 0, sizeof(CSSM_KEY));
SSLBUF_TO_CSSM(paramBlob, &cParamBlob);
crtn = CSSM_CSP_CreateKeyGenContext(ctx->cspHand,
CSSM_ALGID_DH,
keySizeInBits,
NULL, NULL, NULL, NULL, &cParamBlob,
&ccHandle);
if(crtn) {
stPrintCdsaError("DH CSSM_CSP_CreateKeyGenContext", crtn);
return errSSLCrypto;
}
crtn = CSSM_GenerateKeyPair(ccHandle,
CSSM_KEYUSE_DERIVE, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
&labelData,
publicKey,
CSSM_KEYUSE_DERIVE,
CSSM_KEYATTR_RETURN_REF,
&labelData, NULL, privateKey);
if(crtn) {
stPrintCdsaError("DH CSSM_GenerateKeyPair", crtn);
ortn = errSSLCrypto;
}
CSSM_DeleteContext(ccHandle);
return ortn;
}
#define DERIVE_KEY_ALG CSSM_ALGID_RC5
OSStatus sslDhKeyExchange(
SSLContext *ctx,
uint32_t deriveSizeInBits,
SSLBuffer *exchanged)
{
CSSM_RETURN crtn;
CSSM_ACCESS_CREDENTIALS creds;
CSSM_CC_HANDLE ccHandle;
CSSM_DATA labelData = {8, (uint8 *)"tempKey"};
CSSM_KEY derivedKey;
OSStatus ortn = noErr;
assert(ctx != NULL);
assert(ctx->cspHand != 0);
assert(ctx->dhPrivate != NULL);
if(ctx->dhPeerPublic.length == 0) {
sslErrorLog("cdsaDhKeyExchange: null peer public key\n");
return errSSLProtocol;
}
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
memset(&derivedKey, 0, sizeof(CSSM_KEY));
crtn = CSSM_CSP_CreateDeriveKeyContext(ctx->cspHand,
CSSM_ALGID_DH,
DERIVE_KEY_ALG,
deriveSizeInBits,
&creds,
ctx->dhPrivate, 0, 0, 0, &ccHandle);
if(crtn) {
stPrintCdsaError("DH CSSM_CSP_CreateDeriveKeyContext", crtn);
return errSSLCrypto;
}
CSSM_DATA theirPubKeyData;
SSLBUF_TO_CSSM(&ctx->dhPeerPublic, &theirPubKeyData);
crtn = CSSM_DeriveKey(ccHandle,
&theirPubKeyData,
CSSM_KEYUSE_ANY,
CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
&labelData,
NULL, &derivedKey);
if(crtn) {
stPrintCdsaError("DH CSSM_DeriveKey", crtn);
ortn = errSSLCrypto;
}
else {
CSSM_TO_SSLBUF(&derivedKey.KeyData, exchanged);
}
CSSM_DeleteContext(ccHandle);
return ortn;
}
#pragma mark -
#pragma mark *** ECDSA support ***
typedef enum {
CAT_Uint32,
CAT_Ptr
} ContextAttrType;
static CSSM_RETURN sslAddContextAttribute(CSSM_CC_HANDLE CCHandle,
uint32 AttributeType,
uint32 AttributeLength,
ContextAttrType attrType,
const void *AttributePtr,
uint32 attributeInt)
{
CSSM_CONTEXT_ATTRIBUTE newAttr;
CSSM_RETURN crtn;
newAttr.AttributeType = AttributeType;
newAttr.AttributeLength = AttributeLength;
if(attrType == CAT_Uint32) {
newAttr.Attribute.Uint32 = attributeInt;
}
else {
newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr;
}
crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
if(crtn) {
stPrintCdsaError("CSSM_UpdateContextAttributes", crtn);
}
return crtn;
}
OSStatus sslEcdhGenerateKeyPair(
SSLContext *ctx,
SSL_ECDSA_NamedCurve namedCurve)
{
CSSM_RETURN crtn;
CSSM_CC_HANDLE ccHandle = 0;
CSSM_DATA labelData = {8, (uint8 *)"ecdsaKey"};
OSStatus ortn = noErr;
CSSM_KEY pubKey;
uint32 keySizeInBits;
assert(ctx != NULL);
assert(ctx->cspHand != 0);
sslFreeKey(ctx->ecdhPrivCspHand, &ctx->ecdhPrivate, NULL);
SSLFreeBuffer(&ctx->ecdhExchangePublic, ctx);
switch(namedCurve) {
case SSL_Curve_secp256r1:
keySizeInBits = 256;
break;
case SSL_Curve_secp384r1:
keySizeInBits = 384;
break;
case SSL_Curve_secp521r1:
keySizeInBits = 521;
break;
default:
sslErrorLog("sslEcdhGenerateKeyPair: bad namedCurve (%u)\n",
(unsigned)namedCurve);
return errSSLInternal;
}
ctx->ecdhPrivate = (CSSM_KEY *)sslMalloc(sizeof(CSSM_KEY));
memset(ctx->ecdhPrivate, 0, sizeof(CSSM_KEY));
memset(&pubKey, 0, sizeof(CSSM_KEY));
crtn = CSSM_CSP_CreateKeyGenContext(ctx->cspHand,
CSSM_ALGID_ECDSA,
keySizeInBits,
NULL, NULL, NULL, NULL, NULL, &ccHandle);
if(crtn) {
stPrintCdsaError("ECDH CSSM_CSP_CreateKeyGenContext", crtn);
return errSSLCrypto;
}
crtn = sslAddContextAttribute(ccHandle,
CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
sizeof(uint32),
CAT_Uint32,
NULL,
CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING);
if(crtn) {
ortn = errSSLCrypto;
goto errOut;
}
crtn = CSSM_GenerateKeyPair(ccHandle,
CSSM_KEYUSE_DERIVE, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
&labelData,
&pubKey,
CSSM_KEYUSE_DERIVE,
CSSM_KEYATTR_RETURN_REF,
&labelData, NULL, ctx->ecdhPrivate);
if(crtn) {
stPrintCdsaError("ECDH CSSM_GenerateKeyPair", crtn);
ortn = errSSLCrypto;
goto errOut;
}
ctx->ecdhPrivCspHand = ctx->cspHand;
ortn = SSLCopyBufferFromData(pubKey.KeyData.Data, pubKey.KeyData.Length,
&ctx->ecdhExchangePublic);
CSSM_FreeKey(ctx->cspHand, NULL, &pubKey, CSSM_FALSE);
errOut:
if(ccHandle != 0) {
CSSM_DeleteContext(ccHandle);
}
return ortn;
}
OSStatus sslEcdhKeyExchange(
SSLContext *ctx,
SSLBuffer *exchanged)
{
CSSM_RETURN crtn;
CSSM_ACCESS_CREDENTIALS creds;
const CSSM_ACCESS_CREDENTIALS *secCreds;
const CSSM_ACCESS_CREDENTIALS *useCreds = &creds;
CSSM_CC_HANDLE ccHandle;
CSSM_DATA labelData = {8, (uint8 *)"tempKey"};
CSSM_KEY derivedKey;
OSStatus ortn = noErr;
CSSM_KEY rawKey;
bool useRefKeys = false;
uint32 keyAttr;
SSLBuffer pubKeyBits = {0, NULL};
assert(ctx != NULL);
assert(ctx->ecdhPrivCspHand != 0);
assert(ctx->ecdhPrivate != NULL);
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
memset(&derivedKey, 0, sizeof(CSSM_KEY));
memset(&rawKey, 0, sizeof(CSSM_KEY));
switch(ctx->selectedCipherSpec.keyExchangeMethod) {
case SSL_ECDH_ECDSA:
case SSL_ECDH_RSA:
if(ctx->cspHand != ctx->ecdhPrivCspHand) {
useRefKeys = true;
}
break;
default:
break;
}
if(useRefKeys) {
assert(ctx->signingPrivKeyRef != NULL);
ortn = SecKeyGetCredentials(ctx->signingPrivKeyRef,
CSSM_ACL_AUTHORIZATION_DERIVE,
kSecCredentialTypeDefault,
&secCreds);
if(ortn) {
stPrintCdsaError("ECDH SecKeyGetCredentials", ortn);
return ortn;
}
useCreds = secCreds;
}
crtn = CSSM_CSP_CreateDeriveKeyContext(ctx->ecdhPrivCspHand,
CSSM_ALGID_ECDH,
DERIVE_KEY_ALG,
ctx->ecdhPrivate->KeyHeader.LogicalKeySizeInBits,
useCreds,
ctx->ecdhPrivate, 0, 0, 0, &ccHandle);
if(crtn) {
stPrintCdsaError("ECDH CSSM_CSP_CreateDeriveKeyContext", crtn);
return errSSLCrypto;
}
CSSM_DATA theirPubKeyData = {0, NULL};
switch(ctx->selectedCipherSpec.keyExchangeMethod) {
case SSL_ECDHE_ECDSA:
case SSL_ECDHE_RSA:
if(ctx->ecdhPeerPublic.length == 0) {
sslErrorLog("sslEcdhKeyExchange: null peer public key\n");
ortn = errSSLProtocol;
goto errOut;
}
SSLBUF_TO_CSSM(&ctx->ecdhPeerPublic, &theirPubKeyData);
break;
case SSL_ECDH_ECDSA:
case SSL_ECDH_RSA:
if(ctx->peerPubKey == NULL) {
sslErrorLog("sslEcdhKeyExchange: no peer key\n");
ortn = errSSLInternal;
goto errOut;
}
if(useRefKeys) {
ortn = sslEcdsaPubKeyBits(ctx->peerPubKey, &pubKeyBits);
if(ortn) {
goto errOut;
}
SSLBUF_TO_CSSM(&pubKeyBits, &theirPubKeyData);
}
else {
crtn = sslAddContextAttribute(ccHandle,
CSSM_ATTRIBUTE_PUBLIC_KEY,
sizeof(CSSM_KEY),
CAT_Ptr,
(void *)ctx->peerPubKey,
0);
if(crtn) {
stPrintCdsaError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY)",
crtn);
ortn = errSSLInternal;
goto errOut;
}
}
break;
default:
assert(0);
ortn = errSSLInternal;
goto errOut;
}
if(useRefKeys) {
keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
}
else {
keyAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
}
crtn = CSSM_DeriveKey(ccHandle,
&theirPubKeyData,
CSSM_KEYUSE_ANY,
keyAttr,
&labelData,
NULL, &derivedKey);
if(crtn) {
stPrintCdsaError("ECDH CSSM_DeriveKey", crtn);
ortn = errSSLCrypto;
goto errOut;
}
if(useRefKeys) {
ortn = sslNullWrapKey(ctx->ecdhPrivCspHand, &derivedKey, &rawKey);
if(ortn) {
goto errOut;
}
ortn = SSLCopyBufferFromData(rawKey.KeyData.Data, rawKey.KeyData.Length,
exchanged);
}
else {
ortn = SSLCopyBufferFromData(derivedKey.KeyData.Data,
derivedKey.KeyData.Length, exchanged);
}
errOut:
CSSM_DeleteContext(ccHandle);
if(useRefKeys) {
if(pubKeyBits.length) {
SSLFreeBuffer(&pubKeyBits, ctx);
}
if(rawKey.KeyData.Length) {
CSSM_FreeKey(ctx->ecdhPrivCspHand, NULL, &rawKey, CSSM_FALSE);
}
}
return ortn;
}
OSStatus sslVerifySelectedCipher(
SSLContext *ctx,
const SSLCipherSpec *selectedCipherSpec)
{
if(ctx->protocolSide == kSSLClientSide) {
return noErr;
}
#if SSL_PAC_SERVER_ENABLE
if((ctx->masterSecretCallback != NULL) &&
(ctx->sessionTicket.data != NULL)) {
return noErr;
}
#endif
CSSM_ALGORITHMS requireAlg = CSSM_ALGID_NONE;
if(selectedCipherSpec == NULL) {
return errSSLInternal;
}
switch (selectedCipherSpec->keyExchangeMethod) {
case SSL_RSA:
case SSL_RSA_EXPORT:
case SSL_DH_RSA:
case SSL_DH_RSA_EXPORT:
case SSL_DHE_RSA:
case SSL_DHE_RSA_EXPORT:
requireAlg = CSSM_ALGID_RSA;
break;
case SSL_DHE_DSS:
case SSL_DHE_DSS_EXPORT:
case SSL_DH_DSS:
case SSL_DH_DSS_EXPORT:
requireAlg = CSSM_ALGID_DSA;
break;
case SSL_DH_anon:
case SSL_DH_anon_EXPORT:
break;
#if SSL_ECDSA_SERVER
#error Work needed in sslVerifySelectedCipher
#endif
default:
assert(0);
return errSSLInternal;
}
if(requireAlg == CSSM_ALGID_NONE) {
return noErr;
}
if(ctx->signingPrivKeyRef == NULL) {
sslErrorLog("sslVerifySelectedCipher: no signing key\n");
return errSSLBadConfiguration;
}
{
const CSSM_KEY *cssmKey;
OSStatus ortn = SecKeyGetCSSMKey(ctx->signingPrivKeyRef, &cssmKey);
if(ortn) {
sslErrorLog("sslVerifySelectedCipher: SecKeyGetCSSMKey err %d\n",
(int)ortn);
return ortn;
}
if(cssmKey->KeyHeader.AlgorithmId != requireAlg) {
sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n");
return errSSLBadConfiguration;
}
}
return noErr;
}
#endif