X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_ssl/lib/appleCdsa.c diff --git a/libsecurity_ssl/lib/appleCdsa.c b/libsecurity_ssl/lib/appleCdsa.c deleted file mode 100644 index fb5a1b3b..00000000 --- a/libsecurity_ssl/lib/appleCdsa.c +++ /dev/null @@ -1,2147 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005-2008,2010-2012 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@ - */ - -/* - * appleCdsa.c - CDSA based implementation of sslCrypto.h interfaces. - */ - -#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 -#include -#include - -#include -#include -#include -#include -#include -#include - -/* X.509 includes, from cssmapi */ -#include /* x.509 function and type defs */ -#include -#include - -// MARK: - -// MARK: Utilities - -/* - * Set up a Raw symmetric key with specified algorithm and key bits. - */ -OSStatus sslSetUpSymmKey( - CSSM_KEY_PTR symKey, - CSSM_ALGORITHMS alg, - CSSM_KEYUSE keyUse, // CSSM_KEYUSE_ENCRYPT, etc. - CSSM_BOOL copyKey, // true: copy keyData false: set by reference - uint8 *keyData, - size_t keyDataLen) // in bytes -{ - 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; - } - - /* set up the header */ - 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 errSecSuccess; -} - -/* - * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself. - */ -OSStatus sslFreeKey( - CSSM_CSP_HANDLE cspHand, - CSSM_KEY_PTR *key, /* so we can null it out */ - #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 mallocd by CL using our callback - *key = NULL; - } - #if ST_KC_KEYS_NEED_REF - if((kcItem != NULL) && (*kcItem != NULL)) { - KCReleaseItem(kcItem); /* does this NULL the referent? */ - *kcItem = NULL; - } - #endif - return errSecSuccess; -} - -/* - * Standard app-level memory functions required by CDSA. - */ -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 ) ); -} - -/* - * Ensure there's a connection to ctx->cspHand. If there - * already is one, fine. - * Note that as of 12/18/00, we assume we're connected to - * all modules all the time (since we do an attachToAll() in - * SSLNewContext()). - */ -OSStatus attachToCsp(SSLContext *ctx) -{ - assert(ctx != NULL); - if(ctx->cspHand != 0) { - return errSecSuccess; - } - else { - return errSSLModuleAttach; - } -} - -/* - * Connect to TP, CL; reusable. - */ -OSStatus attachToCl(SSLContext *ctx) -{ - assert(ctx != NULL); - if(ctx->clHand != 0) { - return errSecSuccess; - } - else { - return errSSLModuleAttach; - } -} - -OSStatus attachToTp(SSLContext *ctx) -{ - assert(ctx != NULL); - if(ctx->tpHand != 0) { - return errSecSuccess; - } - else { - return errSSLModuleAttach; - } -} - -/* - * Convenience function - attach to CSP, CL, TP. Reusable. - */ -OSStatus attachToAll(SSLContext *ctx) -{ - CSSM_RETURN crtn; - - assert(ctx != NULL); - crtn = attachToModules(&ctx->cspHand, &ctx->clHand, &ctx->tpHand); - if(crtn) { - return errSSLModuleAttach; - } - else { - return errSecSuccess; - } -} - -OSStatus detachFromAll(SSLContext *ctx) -{ - #if 0 - /* No more, attachments are kept on a global basis */ - 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 /* 0 */ - return errSecSuccess; -} - -/* - * Add a CSSM_ATTRIBUTE_RSA_BLINDING attribute to - * specified crypto context. - */ -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; -} - -/* Get CSP, key in CSSM format from a SecKeyRef */ -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; -} - -/* Return the first certificate reference from the supplied array - * whose data matches the given certificate, or NULL if none match. - */ - 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; idxLength = 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); - } -} - -/* - * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data. - * Malloc the Data ptr if necessary. - */ -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 errSecAllocate; - } - } - else if(data->Length < length) { - sslErrorLog("stSetUpCssmData: length too small\n"); - return errSecAllocate; - } - data->Length = length; - return errSecSuccess; -} - -/* All signature ops are "raw", with digest step done by us */ -static OSStatus sslKeyToSigAlg( - const CSSM_KEY *cssmKey, - CSSM_ALGORITHMS *sigAlg) /* RETURNED */ - -{ - OSStatus ortn = errSecSuccess; - 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; -} - -// MARK: - -// MARK: Public CSP Functions - -/* - * Raw RSA/DSA sign/verify. - */ -OSStatus sslRawSign( - SSLContext *ctx, - SecKeyRef privKeyRef, - const UInt8 *plainText, - size_t plainTextLen, - UInt8 *sig, // mallocd by caller; RETURNED - size_t sigLen, // available - size_t *actualBytes) // RETURNED -{ - 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; - - /* Get CSP, signing key in CSSM format */ - 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; - } - - /* - * Get default creds - * FIXME: per 3420180, this needs to allow app-specified creds via - * an new API - */ - 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)) { - /* - * Turn on RSA blinding to defeat timing attacks - */ - crtn = sslAddBlindingAttr(sigHand); - if(crtn) { - return crtn; - } - } - - ptextData.Data = (uint8 *)plainText; - ptextData.Length = plainTextLen; - - /* caller better get this right, or the SignData will fail */ - sigData.Data = sig; - sigData.Length = sigLen; - - crtn = CSSM_SignData(sigHand, - &ptextData, - 1, - CSSM_ALGID_NONE, // digestAlg for raw sign - &sigData); - if(crtn) { - stPrintCdsaError("CSSM_SignData", crtn); - serr = errSSLCrypto; - } - else { - *actualBytes = sigData.Length; - serr = errSecSuccess; - } - 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, // passPhrase - 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, // digestAlg - &sigData); - if(crtn) { - stPrintCdsaError("CSSM_VerifyData", crtn); - serr = errSSLCrypto; - } - else { - serr = errSecSuccess; - } - if(sigHand != 0) { - CSSM_DeleteContext(sigHand); - } - return serr; -} - -/* - * Encrypt/Decrypt - */ -OSStatus sslRsaEncrypt( - SSLContext *ctx, - const CSSM_KEY *pubKey, - CSSM_CSP_HANDLE cspHand, - CSSM_PADDING padding, // CSSM_PADDING_PKCS1, CSSM_PADDING_APPLE_SSLv2 - const UInt8 *plainText, - size_t plainTextLen, - UInt8 *cipherText, // mallocd by caller; RETURNED - size_t cipherTextLen, // available - size_t *actualBytes) // RETURNED -{ - 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; - - /* - * Have CSP malloc ciphertext - */ - crtn = CSSM_EncryptData(cryptHand, - &ptextData, - 1, - &ctextData, - 1, - &bytesMoved, - &remData); - if(crtn == CSSM_OK) { - /* - * ciphertext in both ctextData and remData; ensure it'll fit - * in caller's buf & copy - */ - if(bytesMoved > cipherTextLen) { - sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %lu bytesMoved %lu\n", - cipherTextLen, bytesMoved); - serr = errSSLCrypto; - } - else { - size_t toMoveCtext; - size_t toMoveRem; - - *actualBytes = bytesMoved; - /* - * Snag valid data from ctextData - its length or bytesMoved, - * whichever is less - */ - if(ctextData.Length > bytesMoved) { - /* everything's in ctext */ - toMoveCtext = bytesMoved; - toMoveRem = 0; - } - else { - /* must be some in remData too */ - toMoveCtext = ctextData.Length; - toMoveRem = bytesMoved - toMoveCtext; // remainder - } - if(toMoveCtext) { - memmove(cipherText, ctextData.Data, toMoveCtext); - } - if(toMoveRem) { - memmove(cipherText + toMoveCtext, remData.Data, - toMoveRem); - } - serr = errSecSuccess; - } - } - else { - stPrintCdsaError("CSSM_EncryptData", crtn); - serr = errSSLCrypto; - } - if(cryptHand != 0) { - CSSM_DeleteContext(cryptHand); - } - - /* free data mallocd by CSP */ - stFreeCssmData(&ctextData, CSSM_FALSE); - stFreeCssmData(&remData, CSSM_FALSE); - return serr; -} - -OSStatus sslRsaDecrypt( - SSLContext *ctx, - SecKeyRef privKeyRef, - CSSM_PADDING padding, // CSSM_PADDING_PKCS1, CSSM_PADDING_APPLE_SSLv2 - const UInt8 *cipherText, - size_t cipherTextLen, - UInt8 *plainText, // mallocd by caller; RETURNED - size_t plainTextLen, // available - size_t *actualBytes) // RETURNED -{ - 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; - } - - /* Get CSP, signing key in CSSM format */ - serr = sslGetKeyParts(privKeyRef, &privKey, &cspHand); - if(serr) { - return serr; - } - assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY); - - /* - * Get default creds - * FIXME: per 3420180, this needs to allow app-specified creds via - * an new API - */ - 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)) { - /* - * Turn on RSA blinding to defeat timing attacks - */ - crtn = sslAddBlindingAttr(cryptHand); - if(crtn) { - return crtn; - } - } - - /* - * Have CSP malloc plaintext - */ - crtn = CSSM_DecryptData(cryptHand, - &ctextData, - 1, - &ptextData, - 1, - &bytesMoved, - &remData); - if(crtn == CSSM_OK) { - /* - * plaintext in both ptextData and remData; ensure it'll fit - * in caller's buf & copy - */ - if(bytesMoved > plainTextLen) { - sslErrorLog("sslRsaDecrypt overflow; plainTextLen %lu bytesMoved %lu\n", - plainTextLen, bytesMoved); - serr = errSSLCrypto; - } - else { - size_t toMovePtext; - size_t toMoveRem; - - *actualBytes = bytesMoved; - /* - * Snag valid data from ptextData - its length or bytesMoved, - * whichever is less - */ - if(ptextData.Length > bytesMoved) { - /* everything's in ptext */ - toMovePtext = bytesMoved; - toMoveRem = 0; - } - else { - /* must be some in remData too */ - toMovePtext = ptextData.Length; - toMoveRem = bytesMoved - toMovePtext; // remainder - } - if(toMovePtext) { - memmove(plainText, ptextData.Data, toMovePtext); - } - if(toMoveRem) { - memmove(plainText + toMovePtext, remData.Data, - toMoveRem); - } - serr = errSecSuccess; - } - } - else { - stPrintCdsaError("CSSM_DecryptData", crtn); - serr = errSSLCrypto; - } - if(cryptHand != 0) { - CSSM_DeleteContext(cryptHand); - } - - /* free data mallocd by CSP */ - stFreeCssmData(&ptextData, CSSM_FALSE); - stFreeCssmData(&remData, CSSM_FALSE); - return serr; -} - -/* - * Obtain size of key in bytes. - */ -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); -} - -/* - * Obtain size of key in bytes. - */ -uint32_t sslPubKeyLengthInBytes(const SSLPubKey *sslKey) -{ - const CSSM_KEY *cssmKey; - - assert(sslKey != NULL); - assert(sslKey->key != NULL); - - return (((sslKey->key.KeyHeader.LogicalKeySizeInBits) + 7) / 8); -} - - -/* - * Obtain maximum size of signature in bytes. A bit of a kludge; we could - * ask the CSP to do this but that would be kind of expensive. - */ -OSStatus sslGetMaxSigSize( - const CSSM_KEY *privKey, - uint32_t *maxSigSize) -{ - OSStatus ortn = errSecSuccess; - 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: - { - /* DSA sig is DER sequence of two 160-bit integers */ - uint32_t sizeOfOneInt; - sizeOfOneInt = (160 / 8) + // the raw contents - 1 + // possible leading zero - 2; // tag + length (assume DER, not BER) - *maxSigSize = (2 * sizeOfOneInt) + 5; - break; - } - default: - ortn = errSSLBadConfiguration; - break; - } - return ortn; -} -/* - * Get raw key bits from an RSA public key. - */ -OSStatus sslGetPubKeyBits( - SSLContext *ctx, - const CSSM_KEY *pubKey, - CSSM_CSP_HANDLE cspHand, - SSLBuffer *modulus, // data mallocd and RETURNED - SSLBuffer *exponent) // data mallocd and RETURNED -{ - 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; - } - - /* Note currently ALL public keys are raw, obtained from the CL... */ - assert(hdr->BlobType == CSSM_KEYBLOB_RAW); - - /* - * Handle possible reference format - I think it should be in - * blob form since it came from the DL, but conversion is - * simple. - */ - switch(hdr->BlobType) { - case CSSM_KEYBLOB_RAW: - /* easy case */ - CSSM_TO_SSLBUF(&pubKey->KeyData, &pubKeyBlob); - break; - - case CSSM_KEYBLOB_REFERENCE: - - sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n", - (long)hdr->BlobType); - return errSSLInternal; - - #if 0 - /* - * Convert to a blob via "NULL wrap"; no wrapping key, - * ALGID_NONE - */ - 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, // creds - pubKey, - NULL, // InitVector - CSSM_PADDING_NONE, - 0, // reserved - &ccHand); - if(crtn) { - stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn); - return errSSLCrypto; - } - memset(&wrappedKey, 0, sizeof(CSSM_KEY)); - crtn = CSSM_WrapKey(ccHand, - &creds, - pubKey, - NULL, // descriptiveData - &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 /* 0 */ - - default: - sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n", - (long)hdr->BlobType); - return errSSLInternal; - - } /* switch BlobType */ - - assert(hdr->BlobType == CSSM_KEYBLOB_RAW); - srtn = sslDecodeRsaBlob(&pubKeyBlob, modulus, exponent); - if(didWrap) { - CSSM_FreeKey(ctx->cspHand, NULL, &wrappedKey, CSSM_FALSE); - } - return srtn; -} - -/* - * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in - * Server-initiated key exchange. - */ -OSStatus sslGetPubKeyFromBits( - SSLContext *ctx, - const SSLBuffer *modulus, - const SSLBuffer *exponent, - CSSM_KEY_PTR *pubKey, // mallocd and RETURNED - CSSM_CSP_HANDLE *cspHand) // RETURNED -{ - 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; - } - - /* the rest is boilerplate, cook up a good-looking public key */ - key = (CSSM_KEY_PTR)sslMalloc(sizeof(CSSM_KEY)); - if(key == NULL) { - return errSecAllocate; - } - memset(key, 0, sizeof(CSSM_KEY)); - hdr = &key->KeyHeader; - - hdr->HeaderVersion = CSSM_KEYHEADER_VERSION; - /* key_ptr->KeyHeader.CspId is unknown (remains 0) */ - hdr->BlobType = CSSM_KEYBLOB_RAW; - hdr->AlgorithmId = CSSM_ALGID_RSA; - hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; - hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; - /* comply with ASA requirements */ - hdr->KeyUsage = CSSM_KEYUSE_VERIFY; - hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE; - /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */ - /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */ - hdr->WrapAlgorithmId = CSSM_ALGID_NONE; - hdr->WrapMode = CSSM_ALGMODE_NONE; - - /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to - * actual key */ - SSLBUF_TO_CSSM(&blob, &key->KeyData); - - /* - * Get keySizeInBits. This also serves to validate the key blob - * we just cooked up. - */ - crtn = CSSM_QueryKeySizeInBits(ctx->cspHand, CSSM_INVALID_HANDLE, key, &keySize); - if(crtn) { - stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn); - serr = errSSLCrypto; - goto abort; - } - - /* success */ - hdr->LogicalKeySizeInBits = keySize.EffectiveKeySizeInBits; - *pubKey = key; - *cspHand = ctx->cspHand; - return errSecSuccess; - -abort: - /* note this frees the blob */ - sslFreeKey(ctx->cspHand, &key, NULL); - return serr; -} - -#ifdef UNUSED_FUNCTIONS -/* - * NULL-unwrap a raw key to a ref key. Caller must free the returned key. - */ -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 = errSecSuccess; - - 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, // unwrappingKey - NULL, // initVector - CSSM_PADDING_NONE, - 0, // Params - &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) { - /* CSP policy */ - keyAttr |= CSSM_KEYATTR_EXTRACTABLE; - } - crtn = CSSM_UnwrapKey(ccHand, - NULL, // PublicKey - rawKey, - rawKey->KeyHeader.KeyUsage, - keyAttr, - &labelData, - NULL, // CredAndAclEntry - refKey, - &descData); // required - if(crtn != CSSM_OK) { - stPrintCdsaError("sslNullUnwrapKey: CSSM_UnwrapKey\n", crtn); - ortn = errSSLCrypto; - } - if(CSSM_DeleteContext(ccHand)) { - printf("CSSM_DeleteContext failure\n"); - } - return crtn; -} -#endif - -/* - * NULL-wrap a ref key to a raw key. Caller must free the returned key. - */ -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 = errSecSuccess; - - 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, // unwrappingKey - NULL, // initVector - CSSM_PADDING_NONE, - 0, // Params - &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; -} - -// MARK: - -// MARK: Public Certificate Functions - -/* - * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR. - * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself. - * - * For now, the returned cspHand is a copy of ctx->cspHand, so it - * doesn't have to be detached later - this may change. - * - * Update: since CSSM_CL_CertGetKeyInfo() doesn't provide a means for - * us to tell the CL what CSP to use, we really have no way of knowing - * what is going on here...we return the process-wide (bare) cspHand, - * which is currently always able to deal with this raw public key. - */ -OSStatus sslPubKeyFromCert( - SSLContext *ctx, - const SSLBuffer *derCert, - SSLPubKey *pubKey) // RETURNED -{ - 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 errSecSuccess; - } -} - -/* - * Release each element in a CFArray. - */ -static void sslReleaseArray( - CFArrayRef a) -{ - CFIndex num = CFArrayGetCount(a); - CFIndex dex; - for(dex=0; dexpeerSecTrust. Otherwise - * we're just validating our own certs; no host name checking and - * peerSecTrust is transient. - */ - 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; // only lives in CFArrayRefs - SecTrustResultType secTrustResult; - CFMutableArrayRef kcList = NULL; - SecTrustRef theTrust = NULL; - - if(ctx->peerSecTrust && arePeerCerts) { - /* renegotiate - start with a new SecTrustRef */ - CFRelease(ctx->peerSecTrust); - ctx->peerSecTrust = NULL; - } - - numCerts = SSLGetCertificateChainLength(certChain); - if(numCerts == 0) { - /* nope */ - return errSSLBadCert; - } - - /* - * SSLCertificate chain --> CFArrayRef of SecCertificateRefs. - * TP Cert group has root at the end, opposite of - * SSLCertificate chain. - */ - CFMutableArrayRef certGroup = CFArrayCreateMutable(NULL, numCerts, - &kCFTypeArrayCallBacks); - if(certGroup == NULL) { - return errSecAllocate; - } - /* subsequent errors to errOut: */ - - 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; - } - /* - * Can't set a value at index i when there is an empty element - * at i=1! - */ - secdebug("sslcert", "Adding cert %p", cert); - CFArrayInsertValueAtIndex(certGroup, 0, cert); - c = c->next; - } - - /* - * Cook up an SSL-specific SecPolicyRef. This will persists as part - * of the SecTrustRef object we'll be creating. - */ - 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) { - /* we're evaluating a client cert */ - 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; - } - - /* now a SecTrustRef */ - serr = SecTrustCreateWithCertificates(certGroup, policy, &theTrust); - if(serr) { - sslErrorLog("***sslVerifyCertChain: SecTrustCreateWithCertificates " - "rtn %d\n", (int)serr); - goto errOut; - } - - /* anchors - default, or ours? */ - 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 - /* Disabled for Radar 3421314 */ - /* - * Avoid searching user keychains for intermediate certs by specifying - * an empty array of keychains - */ - kcList = CFArrayCreateMutable(NULL, 0, NULL); - if(kcList == NULL) { - sslErrorLog("***sslVerifyCertChain: error creating null kcList\n"); - serr = errSecAllocate; - goto errOut; - } - serr = SecTrustSetKeychains(theTrust, kcList); - if(serr) { - sslErrorLog("***sslVerifyCertChain: SecTrustSetKeychains rtn %d\n", - (int)serr); - goto errOut; - } - #endif - - /* - * Save this no matter what if we're evaluating peer certs. - * We do a retain here so we can unconditionally release theTrust - * at the end of this routine in case of previous error or - * !arePeerCerts. - */ - if(arePeerCerts) { - ctx->peerSecTrust = theTrust; - CFRetain(theTrust); - } - - if(!ctx->enableCertVerify) { - /* trivial case, this is caller's responsibility */ - serr = errSecSuccess; - goto errOut; - } - - /* - * If the caller provided a list of trusted leaf certs, check them here - */ - if(ctx->trustedLeafCerts) { - if (sslGetMatchingCertInArray((SecCertificateRef)CFArrayGetValueAtIndex(certGroup, 0), - ctx->trustedLeafCerts)) { - serr = errSecSuccess; - goto errOut; - } - } - - /* - * Here we go; hand it over to SecTrust/TP. - */ - serr = SecTrustEvaluate(theTrust, &secTrustResult); - if(serr) { - sslErrorLog("***sslVerifyCertChain: SecTrustEvaluate rtn %d\n", - (int)serr); - goto errOut; - } - switch(secTrustResult) { - case kSecTrustResultUnspecified: - /* cert chain valid, no special UserTrust assignments */ - case kSecTrustResultProceed: - /* cert chain valid AND user explicitly trusts this */ - crtn = CSSM_OK; - break; - case kSecTrustResultDeny: - case kSecTrustResultConfirm: - /* - * Cert chain may well have verified OK, but user has flagged - * one of these certs as untrustable. - */ - 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) { - /* get some detailed error info */ - switch(crtn) { - case CSSMERR_TP_INVALID_ANCHOR_CERT: - /* root found but we don't trust it */ - if(ctx->allowAnyRoot) { - serr = errSecSuccess; - sslErrorLog("***Warning: accepting unknown root cert\n"); - } - else { - serr = errSSLUnknownRootCert; - } - break; - case CSSMERR_TP_NOT_TRUSTED: - /* no root, not even in implicit SSL roots */ - if(ctx->allowAnyRoot) { - sslErrorLog("***Warning: accepting unverified cert chain\n"); - serr = errSecSuccess; - } - 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: - /* these get passed along unmodified */ - serr = crtn; - break; - default: - stPrintCdsaError("sslVerifyCertChain: SecTrustEvaluate returned", - crtn); - serr = errSSLXCertChainInvalid; - break; - } - } /* SecTrustEvaluate error */ - -errOut: - /* - * Free up resources - certGroup, policy, etc. Note that most of these - * will actually persist as long as the current SSLContext does since - * peerSecTrust holds references to these. - */ - 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) { - /* empty, no contents to release */ - CFRelease(kcList); - } - if(theTrust) { - CFRelease(theTrust); - } - return serr; -} - -#ifndef NDEBUG -void stPrintCdsaError(const char *op, CSSM_RETURN crtn) -{ - cssmPerror(op, crtn); -} -#endif - -// MARK: - -// MARK: Diffie-Hellman Support - -/* - * Generate a Diffie-Hellman key pair. Algorithm parameters always - * come from the server, so on client side we have the parameters - * as two SSLBuffers. On server side we have the pre-encoded block - * which comes from ServerDhParams. - */ -OSStatus sslDhGenKeyPairClient( - SSLContext *ctx, - const SSLBuffer *prime, - const SSLBuffer *generator, - CSSM_KEY_PTR publicKey, // RETURNED - CSSM_KEY_PTR privateKey) // RETURNED -{ - 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); - return ortn; -} - -OSStatus sslDhGenerateKeyPair( - SSLContext *ctx, - const SSLBuffer *paramBlob, - uint32_t keySizeInBits, - CSSM_KEY_PTR publicKey, // RETURNED - CSSM_KEY_PTR privateKey) // RETURNED -{ - CSSM_RETURN crtn; - CSSM_CC_HANDLE ccHandle; - CSSM_DATA labelData = {8, (uint8 *)"tempKey"}; - OSStatus ortn = errSecSuccess; - 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, // Seed - NULL, // Salt - NULL, // StartDate - NULL, // EndDate - &cParamBlob, - &ccHandle); - if(crtn) { - stPrintCdsaError("DH CSSM_CSP_CreateKeyGenContext", crtn); - return errSSLCrypto; - } - - crtn = CSSM_GenerateKeyPair(ccHandle, - CSSM_KEYUSE_DERIVE, // only legal use of a Diffie-Hellman key - CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, - &labelData, - publicKey, - /* private key specification */ - CSSM_KEYUSE_DERIVE, - CSSM_KEYATTR_RETURN_REF, - &labelData, // same labels - NULL, // CredAndAclEntry - privateKey); - if(crtn) { - stPrintCdsaError("DH CSSM_GenerateKeyPair", crtn); - ortn = errSSLCrypto; - } - CSSM_DeleteContext(ccHandle); - return ortn; -} - -/* - * Perform Diffie-Hellman key exchange. - * Valid on entry: - * ctx->dhPrivate - * ctx->dhPeerPublic - * - * This generates deriveSizeInBits of key-exchanged data. - */ - -/* the alg isn't important; we just want to be able to cook up lots of bits */ -#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 = errSecSuccess; - - assert(ctx != NULL); - assert(ctx->cspHand != 0); - assert(ctx->dhPrivate != NULL); - if(ctx->dhPeerPublic.length == 0) { - /* comes from peer, don't panic */ - 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, // BaseKey - 0, // IterationCount - 0, // Salt - 0, // Seed - &ccHandle); - if(crtn) { - stPrintCdsaError("DH CSSM_CSP_CreateDeriveKeyContext", crtn); - return errSSLCrypto; - } - - /* public key passed in as CSSM_DATA *Param */ - 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, // cread/acl - &derivedKey); - if(crtn) { - stPrintCdsaError("DH CSSM_DeriveKey", crtn); - ortn = errSSLCrypto; - } - else { - CSSM_TO_SSLBUF(&derivedKey.KeyData, exchanged); - } - CSSM_DeleteContext(ccHandle); - return ortn; -} - -// MARK: - -// MARK: *** ECDSA support *** - -/* specify either 32-bit integer or a pointer as an added attribute value */ -typedef enum { - CAT_Uint32, - CAT_Ptr -} ContextAttrType; - -/* - * Given a context specified via a CSSM_CC_HANDLE, add a new - * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType, - * AttributeLength, and an untyped pointer. - */ -static CSSM_RETURN sslAddContextAttribute(CSSM_CC_HANDLE CCHandle, - uint32 AttributeType, - uint32 AttributeLength, - ContextAttrType attrType, - /* specify exactly one of these */ - 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; -} - -/* - * Generate ECDH key pair with the given SSL_ECDSA_NamedCurve. - * Private key, in ref form, is placed in ctx->ecdhPrivate. - * Public key, in ECPoint form - which can NOT be used as - * a key in any CSP ops - is placed in ecdhExchangePublic. - */ -OSStatus sslEcdhGenerateKeyPair( - SSLContext *ctx, - SSL_ECDSA_NamedCurve namedCurve) -{ - CSSM_RETURN crtn; - CSSM_CC_HANDLE ccHandle = 0; - CSSM_DATA labelData = {8, (uint8 *)"ecdsaKey"}; - OSStatus ortn = errSecSuccess; - CSSM_KEY pubKey; - uint32 keySizeInBits; - - assert(ctx != NULL); - assert(ctx->cspHand != 0); - sslFreeKey(ctx->ecdhPrivCspHand, &ctx->ecdhPrivate, NULL); - SSLFreeBuffer(&ctx->ecdhExchangePublic); - - switch(namedCurve) { - case SSL_Curve_secp256r1: - keySizeInBits = 256; - break; - case SSL_Curve_secp384r1: - keySizeInBits = 384; - break; - case SSL_Curve_secp521r1: - keySizeInBits = 521; - break; - default: - /* should not have gotten this far */ - 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, // Seed - NULL, // Salt - NULL, // StartDate - NULL, // EndDate - NULL, // Params - &ccHandle); - if(crtn) { - stPrintCdsaError("ECDH CSSM_CSP_CreateKeyGenContext", crtn); - return errSSLCrypto; - } - /* subsequent errors to errOut: */ - - /* - * Here's how we get the raw ECPoint form of a public key - */ - 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, - /* public key specification */ - CSSM_KEYUSE_DERIVE, // only legal use - right? - CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, - &labelData, - &pubKey, - /* private key specification */ - CSSM_KEYUSE_DERIVE, - CSSM_KEYATTR_RETURN_REF, - &labelData, // same labels - NULL, // CredAndAclEntry - ctx->ecdhPrivate); - if(crtn) { - stPrintCdsaError("ECDH CSSM_GenerateKeyPair", crtn); - ortn = errSSLCrypto; - goto errOut; - } - ctx->ecdhPrivCspHand = ctx->cspHand; - - /* - * Take that public key data, drop it into ecdhExchangePublic, - * and free the key. - */ - 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; - -} - -/* - * Perform ECDH key exchange. Obtained key material is the same - * size as our private key. - * - * On entry, ecdhPrivate is our private key. The peer's public key - * is either ctx->ecdhPeerPublic for ECDHE exchange, or - * ctx->peerPubKey for ECDH exchange. - */ -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 = errSecSuccess; - 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)); - - /* - * If we're using an actual CSSM_KEY for the peer public key, and its - * cspHand differs from our private key, we do things a bit different - - * our key is in the CSPDL space, and it has a Sec-style ACL for which - * we need creds. Also, the peer public key and the derived key have - * to be in reference form. - */ - 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, // BaseKey - 0, // IterationCount - 0, // Salt - 0, // Seed - &ccHandle); - if(crtn) { - stPrintCdsaError("ECDH CSSM_CSP_CreateDeriveKeyContext", crtn); - return errSSLCrypto; - } - /* subsequent errors to errOut: */ - - CSSM_DATA theirPubKeyData = {0, NULL}; - - switch(ctx->selectedCipherSpec.keyExchangeMethod) { - case SSL_ECDHE_ECDSA: - case SSL_ECDHE_RSA: - /* public key passed in as CSSM_DATA *Param */ - if(ctx->ecdhPeerPublic.length == 0) { - /* comes from peer, don't panic */ - 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: - /* add pub key as a context attr */ - if(ctx->peerPubKey == NULL) { - sslErrorLog("sslEcdhKeyExchange: no peer key\n"); - ortn = errSSLInternal; - goto errOut; - } - - /* - * If we're using CSPDL, extract the raw public key bits in ECPoint - * form and transmit as CSSM_DATA *Param. - * The securityd can't transmit a public key in a DeriveKey context - * in any form. - */ - 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: - /* shouldn't be here */ - 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, // cred/acl - &derivedKey); - if(crtn) { - stPrintCdsaError("ECDH CSSM_DeriveKey", crtn); - ortn = errSSLCrypto; - goto errOut; - } - - if(useRefKeys) { - /* - * one more step: NULL-wrap the generated ref key to something we - * can use - */ - 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); - } - if(rawKey.KeyData.Length) { - CSSM_FreeKey(ctx->ecdhPrivCspHand, NULL, &rawKey, CSSM_FALSE); - } - } - return ortn; -} - - -/* - * After ciphersuite negotiation is complete, verify that we have - * the capability of actually performing the selected cipher. - * Currently we just verify that we have a cert and private signing - * key, if needed, and that the signing key's algorithm matches the - * expected key exchange method. - * - * This is currently called from FindCipherSpec(), after it sets - * ctx->selectedCipherSuite to a (supposedly) valid value, and from - * sslBuildCipherSuiteArray(), in server mode (pre-negotiation) only. - */ -OSStatus sslVerifySelectedCipher( - SSLContext *ctx, - const SSLCipherSpec *selectedCipherSpec) -{ - if(ctx->protocolSide == kSSLClientSide) { - return errSecSuccess; - } - #if SSL_PAC_SERVER_ENABLE - if((ctx->masterSecretCallback != NULL) && - (ctx->sessionTicket.data != NULL)) { - /* EAP via PAC resumption; we can do it */ - return errSecSuccess; - } - #endif /* SSL_PAC_SERVER_ENABLE */ - - 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: - /* CSSM_ALGID_NONE, no signing key */ - break; - /* - * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side, - * we'll need to add some logic here... - */ - #if SSL_ECDSA_SERVER - #error Work needed in sslVerifySelectedCipher - #endif - - default: - /* needs update per cipherSpecs.c */ - assert(0); - return errSSLInternal; - } - if(requireAlg == CSSM_ALGID_NONE) { - return errSecSuccess; - } - - /* private signing key required */ - 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 errSecSuccess; -} - -#endif /* USE_CDSA_CRYPTO */ -