#include "ssl.h"
#include "sslctx.h"
#include "sslalloc.h"
#include "appleCdsa.h"
#include "sslerrs.h"
#include "sslutil.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/x509defs.h>
#include <Security/oidsalg.h>
#include <Security/oidscert.h>
#pragma mark *** Utilities ***
SSLErr sslSetUpSymmKey(
CSSM_KEY_PTR symKey,
CSSM_ALGORITHMS alg,
CSSM_KEYUSE keyUse, CSSM_BOOL copyKey, uint8 *keyData,
uint32 keyDataLen) {
SSLErr 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 SSLNoErr;
}
SSLErr sslFreeKey(
CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR *key,
#if ST_KEYCHAIN_ENABLE && ST_KC_KEYS_NEED_REF
SecKeychainRef *kcItem)
#else
void *kcItem)
#endif
{
CASSERT(key != NULL);
if(*key != NULL) {
if(cspHand != 0) {
CSSM_FreeKey(cspHand, NULL, *key, CSSM_FALSE);
}
sslFree(*key);
*key = NULL;
}
#if ST_KEYCHAIN_ENABLE && ST_KC_KEYS_NEED_REF
if((kcItem != NULL) && (*kcItem != NULL)) {
KCReleaseItem(kcItem);
*kcItem = NULL;
}
#endif
return SSLNoErr;
}
void * stAppMalloc (uint32 size, void *allocRef) {
return( malloc(size) );
}
void stAppFree (void *mem_ptr, void *allocRef) {
free(mem_ptr);
return;
}
void * stAppRealloc (void *ptr, uint32 size, void *allocRef) {
return( realloc( ptr, size ) );
}
void * stAppCalloc (uint32 num, uint32 size, void *allocRef) {
return( calloc( num, size ) );
}
SSLErr attachToCsp(SSLContext *ctx)
{
CASSERT(ctx != NULL);
if(ctx->cspHand != 0) {
return SSLNoErr;
}
else {
return SSLAttachFailure;
}
}
SSLErr attachToCl(SSLContext *ctx)
{
CASSERT(ctx != NULL);
if(ctx->clHand != 0) {
return SSLNoErr;
}
else {
return SSLAttachFailure;
}
}
SSLErr attachToTp(SSLContext *ctx)
{
CASSERT(ctx != NULL);
if(ctx->tpHand != 0) {
return SSLNoErr;
}
else {
return SSLAttachFailure;
}
}
SSLErr attachToAll(SSLContext *ctx)
{
CSSM_RETURN crtn;
CASSERT(ctx != NULL);
crtn = attachToModules(&ctx->cspHand, &ctx->clHand,
&ctx->tpHand
#if ST_FAKE_KEYCHAIN || ST_FAKE_GET_CSPDL_HANDLE
,
&ctx->cspDlHand
#endif
);
if(crtn) {
return SSLAttachFailure;
}
else {
return SSLNoErr;
}
}
SSLErr detachFromAll(SSLContext *ctx)
{
#if 0
CASSERT(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 SSLNoErr;
}
#pragma mark -
#pragma mark *** CSSM_DATA routines ***
CSSM_DATA_PTR stMallocCssmData(
uint32 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);
}
}
SSLErr stSetUpCssmData(
CSSM_DATA_PTR data,
uint32 length)
{
CASSERT(data != NULL);
if(data->Length == 0) {
data->Data = (uint8 *)stAppMalloc(length, NULL);
if(data->Data == NULL) {
return SSLMemoryErr;
}
}
else if(data->Length < length) {
errorLog0("stSetUpCssmData: length too small\n");
return SSLMemoryErr;
}
data->Length = length;
return SSLNoErr;
}
#pragma mark -
#pragma mark *** Public CSP Functions ***
SSLErr sslRand(SSLContext *ctx, SSLBuffer *buf)
{
CSSM_RETURN crtn;
CSSM_CC_HANDLE rngHand;
CSSM_DATA randData;
SSLErr serr;
CASSERT(ctx != NULL);
CASSERT(buf != NULL);
CASSERT(buf->data != NULL);
serr = attachToCsp(ctx);
if(serr) {
return serr;
}
if(buf->length == 0) {
dprintf0("sslRand: zero buf->length\n");
return SSLNoErr;
}
crtn = CSSM_CSP_CreateRandomGenContext(ctx->cspHand,
CSSM_ALGID_APPLE_YARROW,
NULL,
buf->length,
&rngHand);
if(crtn) {
stPrintCdsaError("CSSM_CSP_CreateRandomGenContext", crtn);
return SSLCryptoError;
}
SSLBUF_TO_CSSM(buf, &randData);
crtn = CSSM_GenerateRandom(rngHand, &randData);
if(crtn) {
stPrintCdsaError("CSSM_GenerateRandom", crtn);
serr = SSLCryptoError;
}
CSSM_DeleteContext(rngHand);
return serr;
}
#define SIGN_VFY_VIA_ENCR_DECR 0
#if SIGN_VFY_VIA_ENCR_DECR
SSLErr sslRsaRawSign(
SSLContext *ctx,
const CSSM_KEY *privKey,
CSSM_CSP_HANDLE cspHand,
const UInt8 *plainText,
UInt32 plainTextLen,
UInt8 *sig, UInt32 sigLen, UInt32 *actualBytes) {
SSLErr serr;
CSSM_KEYUSE savedKeyUse = privKey->KeyHeader.KeyUsage;
privKey->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
serr = sslRsaEncrypt(ctx,
privKey,
cspHand,
plainText,
plainTextLen,
sig,
sigLen,
actualBytes);
privKey->KeyHeader.KeyUsage = savedKeyUse;
return serr;
}
SSLErr sslRsaRawVerify(
SSLContext *ctx,
const CSSM_KEY *pubKey,
CSSM_CSP_HANDLE cspHand,
const UInt8 *plainText,
UInt32 plainTextLen,
const UInt8 *sig,
UInt32 sigLen)
{
UInt32 actualBytes;
SSLErr serr;
UInt8 *digest;
CSSM_KEYUSE savedKeyUse = pubKey->KeyHeader.KeyUsage;
pubKey->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
digest = sslMalloc(plainTextLen);
if(digest == NULL) {
return SSLMemoryErr;
}
serr = sslRsaDecrypt(ctx,
pubKey,
cspHand,
sig,
sigLen,
digest,
plainTextLen,
&actualBytes);
pubKey->KeyHeader.KeyUsage = savedKeyUse;
if(serr) {
goto errOut;
}
if((actualBytes != plainTextLen) ||
(memcmp(plainText, digest, plainTextLen))) {
errorLog0("sslRsaRawVerify: sig miscompare\n");
serr = SSLCryptoError;
}
else {
serr = SSLNoErr;
}
errOut:
sslFree(digest);
return serr;
}
#else
SSLErr sslRsaRawSign(
SSLContext *ctx,
const CSSM_KEY *privKey,
CSSM_CSP_HANDLE cspHand,
const UInt8 *plainText,
UInt32 plainTextLen,
UInt8 *sig, UInt32 sigLen, UInt32 *actualBytes) {
CSSM_CC_HANDLE sigHand = 0;
CSSM_RETURN crtn;
SSLErr serr;
CSSM_DATA sigData;
CSSM_DATA ptextData;
CASSERT(ctx != NULL);
if((privKey == NULL) ||
(cspHand == 0) ||
(plainText == NULL) ||
(sig == NULL) ||
(actualBytes == NULL)) {
errorLog0("sslRsaRawSign: bad arguments\n");
return SSLInternalError;
}
*actualBytes = 0;
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
CSSM_ALGID_RSA,
NULL, privKey,
&sigHand);
if(crtn) {
stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn);
return SSLCryptoError;
}
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 = SSLCryptoError;
}
else {
*actualBytes = sigData.Length;
serr = SSLNoErr;
}
if(sigHand != 0) {
CSSM_DeleteContext(sigHand);
}
return serr;
}
SSLErr sslRsaRawVerify(
SSLContext *ctx,
const CSSM_KEY *pubKey,
CSSM_CSP_HANDLE cspHand,
const UInt8 *plainText,
UInt32 plainTextLen,
const UInt8 *sig,
UInt32 sigLen)
{
CSSM_CC_HANDLE sigHand = 0;
CSSM_RETURN crtn;
SSLErr serr;
CSSM_DATA sigData;
CSSM_DATA ptextData;
CASSERT(ctx != NULL);
if((pubKey == NULL) ||
(cspHand == 0) ||
(plainText == NULL) ||
(sig == NULL)) {
errorLog0("sslRsaRawVerify: bad arguments\n");
return SSLInternalError;
}
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
CSSM_ALGID_RSA,
NULL, pubKey,
&sigHand);
if(sigHand == 0) {
stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn);
return SSLCryptoError;
}
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 = SSLCryptoError;
}
else {
serr = SSLNoErr;
}
if(sigHand != 0) {
CSSM_DeleteContext(sigHand);
}
return serr;
}
#endif
#if APPLE_DOMESTIC_CSP_REQUIRED
SSLErr sslRsaEncrypt(
SSLContext *ctx,
const CSSM_KEY *pubKey,
CSSM_CSP_HANDLE cspHand,
const UInt8 *plainText,
UInt32 plainTextLen,
UInt8 *cipherText, UInt32 cipherTextLen, UInt32 *actualBytes) {
CSSM_DATA ctextData = {0, NULL};
CSSM_DATA ptextData;
CSSM_DATA remData = {0, NULL};
CSSM_CC_HANDLE cryptHand = 0;
SSLErr serr = SSLInternalError;
CSSM_RETURN crtn;
uint32 bytesMoved = 0;
CSSM_ACCESS_CREDENTIALS creds;
CASSERT(ctx != NULL);
CASSERT(actualBytes != NULL);
*actualBytes = 0;
if((pubKey == NULL) || (cspHand == 0)) {
errorLog0("sslRsaEncrypt: bad pubKey/cspHand\n");
return SSLInternalError;
}
#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,
CSSM_PADDING_PKCS1,
&cryptHand);
if(crtn) {
stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
return SSLCryptoError;
}
ptextData.Data = (uint8 *)plainText;
ptextData.Length = plainTextLen;
if(pubKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) {
CSSM_CONTEXT_ATTRIBUTE modeAttr;
modeAttr.AttributeType = CSSM_ATTRIBUTE_MODE;
modeAttr.AttributeLength = sizeof(uint32);
modeAttr.Attribute.Uint32 = CSSM_ALGMODE_PRIVATE_KEY;
crtn = CSSM_UpdateContextAttributes(cryptHand, 1, &modeAttr);
if(crtn) {
stPrintCdsaError("CSSM_UpdateContextAttributes", crtn);
CSSM_DeleteContext(cryptHand);
return SSLCryptoError;
}
}
crtn = CSSM_EncryptData(cryptHand,
&ptextData,
1,
&ctextData,
1,
&bytesMoved,
&remData);
if(crtn == CSSM_OK) {
if(bytesMoved > cipherTextLen) {
errorLog2("sslRsaEncrypt overflow; cipherTextLen %ld bytesMoved %ld\n",
cipherTextLen, bytesMoved);
serr = SSLDataOverflow;
}
else {
UInt32 toMoveCtext;
UInt32 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 = SSLNoErr;
}
}
else {
stPrintCdsaError("CSSM_EncryptData", crtn);
serr = SSLCryptoError;
}
if(cryptHand != 0) {
CSSM_DeleteContext(cryptHand);
}
stFreeCssmData(&ctextData, CSSM_FALSE);
stFreeCssmData(&remData, CSSM_FALSE);
return serr;
}
SSLErr sslRsaDecrypt(
SSLContext *ctx,
const CSSM_KEY *privKey,
CSSM_CSP_HANDLE cspHand,
const UInt8 *cipherText,
UInt32 cipherTextLen,
UInt8 *plainText, UInt32 plainTextLen, UInt32 *actualBytes) {
CSSM_DATA ptextData = {0, NULL};
CSSM_DATA ctextData;
CSSM_DATA remData = {0, NULL};
CSSM_CC_HANDLE cryptHand = 0;
SSLErr serr = SSLInternalError;
CSSM_RETURN crtn;
uint32 bytesMoved = 0;
CSSM_ACCESS_CREDENTIALS creds;
CASSERT(ctx != NULL);
CASSERT(actualBytes != NULL);
*actualBytes = 0;
if((privKey == NULL) || (cspHand == 0)) {
errorLog0("sslRsaDecrypt: bad privKey/cspHand\n");
return SSLInternalError;
}
memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
CSSM_ALGID_RSA,
&creds,
privKey,
CSSM_PADDING_PKCS1,
&cryptHand);
if(crtn) {
stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
return SSLCryptoError;
}
ctextData.Data = (uint8 *)cipherText;
ctextData.Length = cipherTextLen;
if(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
CSSM_CONTEXT_ATTRIBUTE modeAttr;
modeAttr.AttributeType = CSSM_ATTRIBUTE_MODE;
modeAttr.AttributeLength = sizeof(uint32);
modeAttr.Attribute.Uint32 = CSSM_ALGMODE_PUBLIC_KEY;
crtn = CSSM_UpdateContextAttributes(cryptHand, 1, &modeAttr);
if(crtn) {
stPrintCdsaError("CSSM_UpdateContextAttributes", crtn);
CSSM_DeleteContext(cryptHand);
return SSLCryptoError;
}
}
crtn = CSSM_DecryptData(cryptHand,
&ctextData,
1,
&ptextData,
1,
&bytesMoved,
&remData);
if(crtn == CSSM_OK) {
if(bytesMoved > plainTextLen) {
errorLog2("sslRsaDecrypt overflow; plainTextLen %ld bytesMoved %ld\n",
plainTextLen, bytesMoved);
serr = SSLDataOverflow;
}
else {
UInt32 toMovePtext;
UInt32 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 = SSLNoErr;
}
}
else {
stPrintCdsaError("CSSM_DecryptData", crtn);
serr = SSLCryptoError;
}
if(cryptHand != 0) {
CSSM_DeleteContext(cryptHand);
}
stFreeCssmData(&ptextData, CSSM_FALSE);
stFreeCssmData(&remData, CSSM_FALSE);
return serr;
}
#endif
UInt32 sslKeyLengthInBytes(const CSSM_KEY *key)
{
CASSERT(key != NULL);
return (((key->KeyHeader.LogicalKeySizeInBits) + 7) / 8);
}
SSLErr 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;
CSSM_CC_HANDLE ccHand;
CSSM_RETURN crtn;
SSLBuffer pubKeyBlob;
SSLErr srtn;
CSSM_ACCESS_CREDENTIALS creds;
CASSERT(ctx != NULL);
CASSERT(modulus != NULL);
CASSERT(exponent != NULL);
CASSERT(pubKey != NULL);
hdr = &pubKey->KeyHeader;
if(hdr->KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) {
errorLog1("sslGetPubKeyBits: bad keyClass (%ld)\n", hdr->KeyClass);
return SSLInternalError;
}
if(hdr->AlgorithmId != CSSM_ALGID_RSA) {
errorLog1("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", hdr->AlgorithmId);
return SSLInternalError;
}
switch(hdr->BlobType) {
case CSSM_KEYBLOB_RAW:
CSSM_TO_SSLBUF(&pubKey->KeyData, &pubKeyBlob);
break;
case CSSM_KEYBLOB_REFERENCE:
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 SSLMemoryErr;
}
memset(&wrappedKey, 0, sizeof(CSSM_KEY));
crtn = CSSM_WrapKey(ccHand,
&creds,
pubKey,
NULL, &wrappedKey);
CSSM_DeleteContext(ccHand);
if(crtn) {
stPrintCdsaError("CSSM_WrapKey", crtn);
return SSLCryptoError;
}
hdr = &wrappedKey.KeyHeader;
if(hdr->BlobType != CSSM_KEYBLOB_RAW) {
errorLog1("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
hdr->BlobType);
return SSLCryptoError;
}
didWrap = CSSM_TRUE;
CSSM_TO_SSLBUF(&wrappedKey.KeyData, &pubKeyBlob);
break;
default:
errorLog1("sslGetPubKeyBits: bad BlobType (%ld)\n",
hdr->BlobType);
return SSLInternalError;
}
CASSERT(hdr->BlobType == CSSM_KEYBLOB_RAW);
srtn = sslDecodeRsaBlob(&pubKeyBlob, modulus, exponent);
if(didWrap) {
CSSM_FreeKey(ctx->cspHand, NULL, &wrappedKey, CSSM_FALSE);
}
return srtn;
}
SSLErr sslGetPubKeyFromBits(
SSLContext *ctx,
const SSLBuffer *modulus,
const SSLBuffer *exponent,
CSSM_KEY_PTR *pubKey, CSSM_CSP_HANDLE *cspHand) {
CSSM_KEY_PTR key = NULL;
SSLErr serr;
SSLBuffer blob;
CSSM_KEYHEADER_PTR hdr;
CSSM_KEY_SIZE keySize;
CSSM_RETURN crtn;
CASSERT((ctx != NULL) && (modulus != NULL) && (exponent != NULL));
CASSERT((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 = sslMalloc(sizeof(CSSM_KEY));
if(key == NULL) {
return SSLMemoryErr;
}
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 = SSLCryptoError;
goto abort;
}
hdr->LogicalKeySizeInBits = keySize.EffectiveKeySizeInBits;
*pubKey = key;
*cspHand = ctx->cspHand;
return SSLNoErr;
abort:
sslFreeKey(ctx->cspHand, &key, NULL);
return serr;
}
#pragma mark -
#pragma mark *** Public Certificate Functions ***
SSLErr sslPubKeyFromCert(
SSLContext *ctx,
const SSLBuffer *derCert,
CSSM_KEY_PTR *pubKey, CSSM_CSP_HANDLE *cspHand) {
SSLErr serr;
CSSM_DATA certData;
CSSM_RETURN crtn;
CASSERT(ctx != NULL);
CASSERT(derCert != NULL);
CASSERT(pubKey != NULL);
CASSERT(cspHand != NULL);
*pubKey = NULL;
*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);
if(crtn) {
return SSLBadCert;
}
else {
*cspHand = ctx->cspHand;
return SSLNoErr;
}
}
#if 0
#include <Files.h>
#include <Errors.h>
static OSErr writeBlob(const CSSM_DATA_PTR blob,
const char *fileName)
{
OSErr err = noErr;
FSSpec fsp;
short fileRef;
long count = blob->Length;
int len = strlen(fileName);
fsp.vRefNum = 0;
fsp.parID = 0;
fsp.name[0] = len;
memmove(&fsp.name[1], fileName, len);
err = FSpCreate(&fsp, 0, 0, 0);
if(err && (err != dupFNErr)) {
dprintf1("***FSpCreate() returned %d\n", err);
return err;
}
err = FSpOpenDF(&fsp, fsRdWrPerm, &fileRef);
if(err) {
dprintf1("***FSpOpenDF() returned %d\n", err);
return err;
}
err = FSWrite(fileRef, &count, blob->Data);
if(err) {
dprintf1("***FSWrite() returned %d\n", err);
return err;
}
err = FSClose(fileRef);
if(err) {
dprintf1("***FSClose() returned %d\n", err);
return err;
}
return 0;
}
void writeBufBlob(const SSLBuffer *blob,
const char *fileName)
{
CSSM_DATA d;
SSLBUF_TO_CSSM(blob, &d)
writeBlob(&d, fileName);
}
#endif
#if ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS
static SSLErr sslHandleNewRoot(
SSLContext *ctx,
CSSM_CERTGROUP_PTR certGroup)
{
int i;
CSSM_DATA_PTR rootCert;
CSSM_BOOL expired;
SSLErr serr;
CSSM_BOOL brtn;
CASSERT(ctx != NULL);
CASSERT(certGroup != NULL);
if(ctx->newRootCertKc == NULL) {
return SSLUnknownRootCert;
}
for(i=0; i<certGroup->NumCerts; i++) {
rootCert = &certGroup->CertList[i];
if(sslVerifyCert(ctx, rootCert, rootCert, ctx->cspHand, &expired)) {
break;
}
}
if(i == certGroup->NumCerts) {
errorLog0("sslHandleNewRoot: no root cert!\n");
return SSLInternalError;
}
serr = sslAddNewRoot(ctx, rootCert);
if(serr) {
return serr;
}
brtn = CSSM_TP_CertGroupVerify(
ctx->tpHand,
ctx->clHand,
ctx->cspHand,
NULL, NULL, 0, CSSM_TP_STOP_ON_POLICY,
certGroup,
ctx->trustedCerts, ctx->numTrustedCerts,
NULL, 0, 0, 0, NULL, NULL); if(brtn == CSSM_FALSE) {
errorLog0("sslHandleNewRoot: adding new root did not help!\n");
return SSLUnknownRootCert;
}
return SSLNoErr;
}
#endif
static void sslFreeCertGroup(
CSSM_CERTGROUP_PTR certGroup,
CSSM_BOOL freeCerts, CSSM_BOOL freeStruct) {
unsigned dex;
if(certGroup == NULL) {
return;
}
if(certGroup->GroupList.CertList) {
if(freeCerts) {
for(dex=0; dex<certGroup->NumCerts; dex++) {
stFreeCssmData(&certGroup->GroupList.CertList[dex], CSSM_FALSE);
}
}
stAppFree(certGroup->GroupList.CertList, NULL);
}
if(freeStruct) {
stAppFree(certGroup, NULL);
}
}
SSLErr sslVerifyCertChain(
SSLContext *ctx,
const SSLCertificate *certChain)
{
UInt32 numCerts;
CSSM_CERTGROUP certGroup;
int i;
SSLErr serr;
SSLCertificate *c = (SSLCertificate *)certChain;
CSSM_RETURN crtn;
CSSM_TP_VERIFY_CONTEXT vfyCtx;
CSSM_TP_CALLERAUTH_CONTEXT authCtx;
CSSM_FIELD policyId;
CSSM_DL_DB_LIST dbList;
CSSM_APPLE_TP_SSL_OPTIONS sslOpts;
CSSM_APPLE_TP_ACTION_DATA actionData;
numCerts = SSLGetCertificateChainLength(certChain);
if(numCerts == 0) {
return SSLBadCert;
}
#if 0
serr = attachToAll(ctx);
if(serr) {
return serr;
}
#endif
certGroup.GroupList.CertList =
(CSSM_DATA_PTR)sslMalloc(numCerts * sizeof(CSSM_DATA));
if(certGroup.GroupList.CertList == NULL) {
return SSLMemoryErr;
}
certGroup.CertGroupType = CSSM_CERTGROUP_DATA;
certGroup.CertType = CSSM_CERT_X_509v3;
certGroup.CertEncoding = CSSM_CERT_ENCODING_DER;
certGroup.NumCerts = numCerts;
memset(certGroup.GroupList.CertList, 0, numCerts * sizeof(CSSM_DATA));
for(i=numCerts-1; i>=0; i--) {
SSLBUF_TO_CSSM(&c->derCert, &certGroup.GroupList.CertList[i]);
c = c->next;
}
memset(&vfyCtx, 0, sizeof(CSSM_TP_VERIFY_CONTEXT));
vfyCtx.Action = CSSM_TP_ACTION_DEFAULT;
vfyCtx.Cred = &authCtx;
sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
sslOpts.ServerNameLen = ctx->peerDomainNameLen;
sslOpts.ServerName = ctx->peerDomainName;
actionData.Version = CSSM_APPLE_TP_ACTION_VERSION;
actionData.ActionFlags = 0x80000000; if(ctx->allowExpiredCerts) {
actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED;
}
vfyCtx.ActionData.Data = (uint8 *)&actionData;
vfyCtx.ActionData.Length = sizeof(actionData);
policyId.FieldOid = CSSMOID_APPLE_TP_SSL;
policyId.FieldValue.Data = (uint8 *)&sslOpts;
policyId.FieldValue.Length = sizeof(sslOpts);
authCtx.Policy.NumberOfPolicyIds = 1;
authCtx.Policy.PolicyIds = &policyId;
authCtx.VerifyTime = NULL;
authCtx.VerificationAbortOn = CSSM_TP_STOP_ON_POLICY;
authCtx.CallbackWithVerifiedCert = NULL;
authCtx.NumberOfAnchorCerts = ctx->numTrustedCerts;
authCtx.AnchorCerts = ctx->trustedCerts;
memset(&dbList, 0, sizeof(CSSM_DL_DB_LIST));
authCtx.DBList = &dbList;
authCtx.CallerCredentials = NULL;
crtn = CSSM_TP_CertGroupVerify(ctx->tpHand,
ctx->clHand,
ctx->cspHand,
&certGroup,
&vfyCtx,
NULL);
serr = SSLNoErr;
if(crtn) {
switch(crtn) {
case CSSMERR_TP_INVALID_ANCHOR_CERT:
if(ctx->allowAnyRoot) {
dprintf0("***Warning: accepting unknown root cert\n");
break;
}
#if ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS
if(ctx->newRootCertKc != NULL) {
serr = sslHandleNewRoot(ctx, &certGroup);
}
else {
serr = SSLUnknownRootCert;
}
#else
serr = SSLUnknownRootCert;
#endif
break;
case CSSMERR_TP_NOT_TRUSTED:
if(ctx->allowAnyRoot) {
dprintf0("***Warning: accepting unverified cert chain\n");
break;
}
serr = SSLNoRootCert;
break;
case CSSMERR_TP_CERT_EXPIRED:
assert(!ctx->allowExpiredCerts);
serr = SSLCertExpired;
break;
case CSSMERR_TP_CERT_NOT_VALID_YET:
serr = SSLCertNotYetValid;
break;
default:
stPrintCdsaError(
"sslVerifyCertChain: CSSM_TP_CertGroupVerify returned", crtn);
serr = X509CertChainInvalidErr;
break;
}
}
sslFreeCertGroup(&certGroup, CSSM_FALSE, CSSM_FALSE);
return serr;
}
#if 0
CSSM_BOOL sslVerifyCert(
SSLContext *ctx,
const CSSM_DATA_PTR subjectCert,
const CSSM_DATA_PTR issuerCert,
CSSM_CSP_HANDLE cspHand, CSSM_BOOL *subjectExpired) {
CSSM_KEY_PTR issuerPubKey = NULL;
CSSM_DATA_PTR sigOid = NULL;
CSSM_HANDLE ResultsHandle;
uint32 NumberOfFields;
CSSM_ERROR_PTR pErr = NULL;
CSSM_BOOL brtn;
uint32 *algId = NULL; CSSM_CC_HANDLE ccHand = 0;
*subjectExpired = CSSM_FALSE;
if(attachToCl(ctx)) {
return CSSM_FALSE;
}
if(attachToTp(ctx)) {
return CSSM_FALSE;
}
issuerPubKey = CSSM_CL_CertGetKeyInfo(ctx->clHand, issuerCert);
if(issuerPubKey == NULL) {
return CSSM_FALSE;
}
sigOid = CSSM_CL_CertGetFirstFieldValue(ctx->clHand,
subjectCert,
&CSSMOID_X509V1SignatureAlgorithm,
&ResultsHandle,
&NumberOfFields);
if(sigOid == NULL) {
stPrintCdsaError("CSSM_CL_CertGetFirstFieldValue");
brtn = CSSM_FALSE;
CSSM_CL_CertAbortQuery(ctx->clHand, ResultsHandle);
goto abort;
}
CSSM_CL_CertAbortQuery(ctx->clHand, ResultsHandle);
algId = (uint32 *)CSSM_CL_PassThrough(ctx->clHand,
0, INTEL_X509V3_PASSTHROUGH_ALGOID_TO_ALGID,
sigOid);
if(*algId == CSSM_ALGID_NONE) {
brtn = CSSM_FALSE;
goto abort;
}
ccHand = CSSM_CSP_CreateSignatureContext(cspHand,
*algId,
NULL, issuerPubKey);
if(ccHand == 0) {
brtn = CSSM_FALSE;
goto abort;
}
brtn = CSSM_CL_CertVerify(ctx->clHand,
ccHand,
subjectCert,
issuerCert,
NULL, 0); if(!brtn && (CSSM_GetError()->error == CSSM_CL_CERT_EXPIRED)) {
*subjectExpired = CSSM_TRUE;
}
abort:
if(issuerPubKey != NULL) {
CSSM_Free(issuerPubKey->KeyData.Data);
CSSM_Free(issuerPubKey);
}
if(sigOid != NULL) {
CSSM_Free(sigOid->Data);
CSSM_Free(sigOid);
}
if(ccHand != 0) {
CSSM_DeleteContext(ccHand);
}
if(algId != NULL) {
CSSM_Free(algId);
}
return brtn;
}
#endif
#if ST_KEYCHAIN_ENABLE
CSSM_DATA_PTR sslGetCertSubjectName(
SSLContext *ctx,
const CSSM_DATA_PTR cert)
{
uint32 NumberOfFields = 0;
CSSM_HANDLE ResultsHandle = 0;
CSSM_DATA_PTR pEncodedName = NULL;
CSSM_RETURN crtn;
if(attachToCl(ctx)) {
return NULL;
}
crtn = CSSM_CL_CertGetFirstFieldValue(
ctx->clHand,
cert,
&CSSMOID_X509V1SubjectName,
&ResultsHandle,
&NumberOfFields,
&pEncodedName);
if(crtn) {
stPrintCdsaError("CertGetFirstFieldValue", crtn);
}
CSSM_CL_CertAbortQuery(ctx->clHand, ResultsHandle);
return pEncodedName;
}
#endif ST_KEYCHAIN_ENABLE
#if (SSL_DEBUG && ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS)
void verifyTrustedRoots(SSLContext *ctx,
CSSM_DATA_PTR certs,
unsigned numCerts)
{
int i;
CSSM_DATA_PTR cert;
CSSM_BOOL expired;
for(i=0; i<numCerts; i++) {
cert = &certs[i];
if(!sslVerifyCert(ctx,
cert,
cert,
ctx->cspHand,
&expired)) {
sslPanic("Bad trusted cert!\n");
}
}
}
#endif