/* * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This 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. */ /* File: hdskkyex.c Contains: Support for key exchange and server key exchange Written by: Doug Mitchell, based on Netscape SSLRef 3.0 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved. */ /* ********************************************************************* File: hdskkyex.c SSLRef 3.0 Final -- 11/19/96 Copyright (c)1996 by Netscape Communications Corp. By retrieving this software you are bound by the licensing terms disclosed in the file "LICENSE.txt". Please read it, and if you don't accept the terms, delete this software. SSLRef 3.0 was developed by Netscape Communications Corp. of Mountain View, California and Consensus Development Corporation of Berkeley, California . ********************************************************************* File: hdskkyex.c Support for key exchange and server key exchange Encoding and decoding of key exchange and server key exchange messages in both the Diffie-Hellman and RSA variants; also, includes the necessary crypto library calls to support this negotiation. ****************************************************************** */ #ifndef _SSLCTX_H_ #include "sslctx.h" #endif #ifndef _SSLHDSHK_H_ #include "sslhdshk.h" #endif #ifndef _SSLALLOC_H_ #include "sslalloc.h" #endif #ifndef _SSL_DEBUG_H_ #include "sslDebug.h" #endif #ifndef _SSLUTIL_H_ #include "sslutil.h" #endif #ifndef _APPLE_CDSA_H_ #include "appleCdsa.h" #endif #ifndef _DIGESTS_H_ #include "digests.h" #endif #include #if _APPLE_CDSA_ /* * For this config, just for this file, we'll do this typedef.... */ typedef CSSM_KEY_PTR SSLRSAPrivateKey; #endif static SSLErr SSLEncodeRSAServerKeyExchange(SSLRecord *keyExch, SSLContext *ctx); static SSLErr SSLEncodeRSAKeyParams(SSLBuffer *keyParams, SSLRSAPrivateKey *key, SSLContext *ctx); static SSLErr SSLProcessRSAServerKeyExchange(SSLBuffer message, SSLContext *ctx); static SSLErr SSLDecodeRSAKeyExchange(SSLBuffer keyExchange, SSLContext *ctx); static SSLErr SSLEncodeRSAKeyExchange(SSLRecord *keyExchange, SSLContext *ctx); #if APPLE_DH static SSLErr SSLEncodeDHanonServerKeyExchange(SSLRecord *keyExch, SSLContext *ctx); static SSLErr SSLEncodeDHanonKeyExchange(SSLRecord *keyExchange, SSLContext *ctx); static SSLErr SSLDecodeDHanonKeyExchange(SSLBuffer keyExchange, SSLContext *ctx); static SSLErr SSLProcessDHanonServerKeyExchange(SSLBuffer message, SSLContext *ctx); #endif SSLErr SSLEncodeServerKeyExchange(SSLRecord *keyExch, SSLContext *ctx) { SSLErr err; switch (ctx->selectedCipherSpec->keyExchangeMethod) { case SSL_RSA: case SSL_RSA_EXPORT: if (ERR(err = SSLEncodeRSAServerKeyExchange(keyExch, ctx)) != 0) return err; break; #if APPLE_DH case SSL_DH_anon: if (ERR(err = SSLEncodeDHanonServerKeyExchange(keyExch, ctx)) != 0) return err; break; #endif default: return ERR(SSLUnsupportedErr); } return SSLNoErr; } static SSLErr SSLEncodeRSAServerKeyExchange(SSLRecord *keyExch, SSLContext *ctx) { SSLErr err; UInt8 *progress; int length; UInt32 outputLen, localKeyModulusLen; UInt8 hashes[36]; SSLBuffer exportKey,clientRandom,serverRandom,hashCtx, hash; exportKey.data = 0; hashCtx.data = 0; #if _APPLE_CDSA_ /* we have a public key here... */ CASSERT(ctx->encryptPubKey != NULL); CASSERT(ctx->protocolSide == SSL_ServerSide); if ((err = SSLEncodeRSAKeyParams(&exportKey, &ctx->encryptPubKey, ctx)) != 0) #else if (ERR(err = SSLEncodeRSAKeyParams(&exportKey, &ctx->exportKey, ctx)) != 0) #endif goto fail; #if RSAREF localKeyModulusLen = (ctx->localKey.bits + 7)/8; #elif BSAFE { A_RSA_KEY *keyInfo; int rsaResult; if ((rsaResult = B_GetKeyInfo((POINTER*)&keyInfo, ctx->localKey, KI_RSAPublic)) != 0) return SSLUnknownErr; localKeyModulusLen = keyInfo->modulus.len; } #elif _APPLE_CDSA_ CASSERT(ctx->signingPubKey != NULL); localKeyModulusLen = sslKeyLengthInBytes(ctx->signingPubKey); #else #error No Asymmetric crypto specified #endif /* RSAREF / BSAFE */ length = exportKey.length + 2 + localKeyModulusLen; /* RSA ouputs a block as long as the modulus */ keyExch->protocolVersion = SSL_Version_3_0; keyExch->contentType = SSL_handshake; if (ERR(err = SSLAllocBuffer(&keyExch->contents, length+4, &ctx->sysCtx)) != 0) goto fail; progress = keyExch->contents.data; *progress++ = SSL_server_key_exchange; progress = SSLEncodeInt(progress, length, 3); memcpy(progress, exportKey.data, exportKey.length); progress += exportKey.length; clientRandom.data = ctx->clientRandom; clientRandom.length = 32; serverRandom.data = ctx->serverRandom; serverRandom.length = 32; hash.data = &hashes[0]; hash.length = 16; if (ERR(err = ReadyHash(&SSLHashMD5, &hashCtx, ctx)) != 0) goto fail; if (ERR(err = SSLHashMD5.update(hashCtx, clientRandom)) != 0) goto fail; if (ERR(err = SSLHashMD5.update(hashCtx, serverRandom)) != 0) goto fail; if (ERR(err = SSLHashMD5.update(hashCtx, exportKey)) != 0) goto fail; if (ERR(err = SSLHashMD5.final(hashCtx, hash)) != 0) goto fail; if (ERR(err = SSLFreeBuffer(&hashCtx, &ctx->sysCtx)) != 0) goto fail; hash.data = &hashes[16]; hash.length = 20; if (ERR(err = ReadyHash(&SSLHashSHA1, &hashCtx, ctx)) != 0) goto fail; if (ERR(err = SSLHashSHA1.update(hashCtx, clientRandom)) != 0) goto fail; if (ERR(err = SSLHashSHA1.update(hashCtx, serverRandom)) != 0) goto fail; if (ERR(err = SSLHashSHA1.update(hashCtx, exportKey)) != 0) goto fail; if (ERR(err = SSLHashSHA1.final(hashCtx, hash)) != 0) goto fail; if (ERR(err = SSLFreeBuffer(&hashCtx, &ctx->sysCtx)) != 0) goto fail; progress = SSLEncodeInt(progress, localKeyModulusLen, 2); #if RSAREF if (RSAPrivateEncrypt(progress, &outputLen, hashes, 36, &ctx->localKey) != 0) /* Sign the structure */ return ERR(SSLUnknownErr); #elif BSAFE { B_ALGORITHM_OBJ rsa; B_ALGORITHM_METHOD *chooser[] = { &AM_RSA_ENCRYPT, &AM_RSA_CRT_ENCRYPT, 0 }; int rsaResult; UInt32 encryptedOut; if ((rsaResult = B_CreateAlgorithmObject(&rsa)) != 0) return SSLUnknownErr; if ((rsaResult = B_SetAlgorithmInfo(rsa, AI_PKCS_RSAPrivate, 0)) != 0) return SSLUnknownErr; if ((rsaResult = B_EncryptInit(rsa, ctx->localKey, chooser, NO_SURR)) != 0) return SSLUnknownErr; if ((rsaResult = B_EncryptUpdate(rsa, progress, &encryptedOut, localKeyModulusLen, hashes, 36, 0, NO_SURR)) != 0) return SSLUnknownErr; outputLen = encryptedOut; if ((rsaResult = B_EncryptFinal(rsa, progress+outputLen, &encryptedOut, localKeyModulusLen-outputLen, 0, NO_SURR)) != 0) return SSLUnknownErr; outputLen += encryptedOut; B_DestroyAlgorithmObject(&rsa); } #elif _APPLE_CDSA_ err = sslRsaRawSign(ctx, ctx->signingPrivKey, ctx->signingKeyCsp, hashes, 36, progress, length, &outputLen); if(err) { goto fail; } #endif /* RSAREF / BSAFE */ CASSERT(outputLen == localKeyModulusLen); err = SSLNoErr; fail: ERR(SSLFreeBuffer(&hashCtx, &ctx->sysCtx)); ERR(SSLFreeBuffer(&exportKey, &ctx->sysCtx)); return err; } static SSLErr SSLEncodeRSAKeyParams(SSLBuffer *keyParams, SSLRSAPrivateKey *key, SSLContext *ctx) { SSLErr err; SSLBuffer modulus, exponent; UInt8 *progress; #if RSAREF keyParams->data = 0; modulus.length = (key->bits + 7) / 8; modulus.data = key->modulus + MAX_RSA_MODULUS_LEN - modulus.length; exponent.length = MAX_RSA_MODULUS_LEN; exponent.data = key->publicExponent; /* Point at first byte */ while (*exponent.data == 0) { ++exponent.data; --exponent.length; } #elif BSAFE { A_RSA_KEY *keyInfo; int rsaResult; if ((rsaResult = B_GetKeyInfo((POINTER*)&keyInfo, *key, KI_RSAPublic)) != 0) return SSLUnknownErr; modulus.data = keyInfo->modulus.data; modulus.length = keyInfo->modulus.len; exponent.data = keyInfo->exponent.data; exponent.length = keyInfo->exponent.len; } #elif _APPLE_CDSA_ err = sslGetPubKeyBits(ctx, *key, ctx->encryptKeyCsp, &modulus, &exponent); if(err) { SSLFreeBuffer(&modulus, &ctx->sysCtx); SSLFreeBuffer(&exponent, &ctx->sysCtx); return err; } #else #error No assymetric crypto specified #endif /* RSAREF / BSAFE */ if (ERR(err = SSLAllocBuffer(keyParams, modulus.length + exponent.length + 4, &ctx->sysCtx)) != 0) return err; progress = keyParams->data; progress = SSLEncodeInt(progress, modulus.length, 2); memcpy(progress, modulus.data, modulus.length); progress += modulus.length; progress = SSLEncodeInt(progress, exponent.length, 2); memcpy(progress, exponent.data, exponent.length); #if _APPLE_CDSA_ /* these were mallocd by sslGetPubKeyBits() */ SSLFreeBuffer(&modulus, &ctx->sysCtx); SSLFreeBuffer(&exponent, &ctx->sysCtx); #endif return SSLNoErr; } #if APPLE_DH static SSLErr SSLEncodeDHanonServerKeyExchange(SSLRecord *keyExch, SSLContext *ctx) { SSLErr err; UInt32 length; UInt8 *progress; SSLRandomCtx random; int rsaErr; #if RSAREF length = 6 + ctx->dhAnonParams.primeLen + ctx->dhAnonParams.generatorLen + ctx->dhExchangePublic.length; keyExch->protocolVersion = SSL_Version_3_0; keyExch->contentType = SSL_handshake; if (ERR(err = SSLAllocBuffer(&keyExch->contents, length+4, &ctx->sysCtx)) != 0) return err; progress = keyExch->contents.data; *progress++ = SSL_server_key_exchange; progress = SSLEncodeInt(progress, length, 3); progress = SSLEncodeInt(progress, ctx->dhAnonParams.primeLen, 2); memcpy(progress, ctx->dhAnonParams.prime, ctx->dhAnonParams.primeLen); progress += ctx->dhAnonParams.primeLen; progress = SSLEncodeInt(progress, ctx->dhAnonParams.generatorLen, 2); memcpy(progress, ctx->dhAnonParams.generator, ctx->dhAnonParams.generatorLen); progress += ctx->dhAnonParams.generatorLen; if (ERR(err = SSLAllocBuffer(&ctx->dhExchangePublic, ctx->peerDHParams.primeLen, &ctx->sysCtx)) != 0) return err; if (ERR(err = SSLAllocBuffer(&ctx->dhPrivate, ctx->dhExchangePublic.length - 16, &ctx->sysCtx)) != 0) return err; if (ERR(err = ReadyRandom(&random, ctx)) != 0) return err; if ((rsaErr = R_SetupDHAgreement(ctx->dhExchangePublic.data, ctx->dhPrivate.data, ctx->dhPrivate.length, &ctx->dhAnonParams, &random)) != 0) { err = SSLUnknownErr; return err; } progress = SSLEncodeInt(progress, ctx->dhExchangePublic.length, 2); memcpy(progress, ctx->dhExchangePublic.data, ctx->dhExchangePublic.length); progress += ctx->dhExchangePublic.length; #elif BSAFE { A_DH_KEY_AGREE_PARAMS *params; unsigned int outputLen; if ((rsaErr = B_GetAlgorithmInfo((POINTER*)¶ms, ctx->dhAnonParams, AI_DHKeyAgree)) != 0) return SSLUnknownErr; if (ERR(err = ReadyRandom(&random, ctx)) != 0) return err; if (ERR(err = SSLAllocBuffer(&ctx->dhExchangePublic, 128, &ctx->sysCtx)) != 0) return err; if ((rsaErr = B_KeyAgreePhase1(ctx->dhAnonParams, ctx->dhExchangePublic.data, &outputLen, 128, random, NO_SURR)) != 0) { err = SSLUnknownErr; return err; } ctx->dhExchangePublic.length = outputLen; length = 6 + params->prime.len + params->base.len + ctx->dhExchangePublic.length; keyExch->protocolVersion = SSL_Version_3_0; keyExch->contentType = SSL_handshake; if (ERR(err = SSLAllocBuffer(&keyExch->contents, length+4, &ctx->sysCtx)) != 0) return err; progress = keyExch->contents.data; *progress++ = SSL_server_key_exchange; progress = SSLEncodeInt(progress, length, 3); progress = SSLEncodeInt(progress, params->prime.len, 2); memcpy(progress, params->prime.data, params->prime.len); progress += params->prime.len; progress = SSLEncodeInt(progress, params->base.len, 2); memcpy(progress, params->base.data, params->base.len); progress += params->base.len; progress = SSLEncodeInt(progress, ctx->dhExchangePublic.length, 2); memcpy(progress, ctx->dhExchangePublic.data, ctx->dhExchangePublic.length); progress += ctx->dhExchangePublic.length; } #endif /* RSAREF / BSAFE */ ASSERT(progress == keyExch->contents.data + keyExch->contents.length); return SSLNoErr; } #endif /* APPLE_DH */ SSLErr SSLProcessServerKeyExchange(SSLBuffer message, SSLContext *ctx) { SSLErr err; switch (ctx->selectedCipherSpec->keyExchangeMethod) { case SSL_RSA: case SSL_RSA_EXPORT: if (ERR(err = SSLProcessRSAServerKeyExchange(message, ctx)) != 0) return err; break; #if APPLE_DH case SSL_DH_anon: if (ERR(err = SSLProcessDHanonServerKeyExchange(message, ctx)) != 0) return err; break; #endif default: return ERR(SSLUnsupportedErr); } return SSLNoErr; } static SSLErr SSLProcessRSAServerKeyExchange(SSLBuffer message, SSLContext *ctx) { SSLErr err; SSLBuffer tempPubKey, hashOut, hashCtx, clientRandom, serverRandom; UInt16 modulusLen, exponentLen, signatureLen; UInt8 *progress, *modulus, *exponent, *signature; #if _APPLE_CDSA_ UInt8 hash[36]; #else UInt8 hash[20]; UInt32 outputLen; #endif /* _APPLE_CDSA_ */ SSLBuffer signedHashes; signedHashes.data = 0; hashCtx.data = 0; if (message.length < 2) { errorLog0("SSLProcessRSAServerKeyExchange: msg len error 2\n"); return ERR(SSLProtocolErr); } progress = message.data; modulusLen = SSLDecodeInt(progress, 2); modulus = progress + 2; progress += 2+modulusLen; if (message.length < 4 + modulusLen) { errorLog0("SSLProcessRSAServerKeyExchange: msg len error 2\n"); return ERR(SSLProtocolErr); } exponentLen = SSLDecodeInt(progress, 2); exponent = progress + 2; progress += 2+exponentLen; if (message.length < 6 + modulusLen + exponentLen) { errorLog0("SSLProcessRSAServerKeyExchange: msg len error 2\n"); return ERR(SSLProtocolErr); } signatureLen = SSLDecodeInt(progress, 2); signature = progress + 2; if (message.length != 6 + modulusLen + exponentLen + signatureLen) { errorLog0("SSLProcessRSAServerKeyExchange: msg len error 3\n"); return ERR(SSLProtocolErr); } #if RSAREF { /* Allocate room for the signed hashes; RSA can encrypt data as long as the modulus */ if (ERR(err = SSLAllocBuffer(&signedHashes, (ctx->peerKey.bits + 7)/8, &ctx->sysCtx)) != 0) return err; if ((RSAPublicDecrypt(signedHashes.data, &outputLen, signature, signatureLen, &ctx->peerKey)) != 0) { ERR(err = SSLUnknownErr); goto fail; } } #elif BSAFE { B_ALGORITHM_OBJ rsa; B_ALGORITHM_METHOD *chooser[] = { &AM_MD2, &AM_MD5, &AM_RSA_DECRYPT, 0 }; int rsaResult; unsigned int decryptLen; /* Allocate room for the signed hashes; BSAFE makes sure we don't decode too much data */ if (ERR(err = SSLAllocBuffer(&signedHashes, 36, &ctx->sysCtx)) != 0) return err; if ((rsaResult = B_CreateAlgorithmObject(&rsa)) != 0) return SSLUnknownErr; if ((rsaResult = B_SetAlgorithmInfo(rsa, AI_PKCS_RSAPublic, 0)) != 0) return SSLUnknownErr; if ((rsaResult = B_DecryptInit(rsa, ctx->peerKey, chooser, NO_SURR)) != 0) return SSLUnknownErr; if ((rsaResult = B_DecryptUpdate(rsa, signedHashes.data, &decryptLen, 36, signature, signatureLen, 0, NO_SURR)) != 0) return SSLUnknownErr; outputLen = decryptLen; if ((rsaResult = B_DecryptFinal(rsa, signedHashes.data+outputLen, &decryptLen, 36-outputLen, 0, NO_SURR)) != 0) return SSLUnknownErr; outputLen += decryptLen; B_DestroyAlgorithmObject(&rsa); } #elif _APPLE_CDSA_ /* not yet - calculate the hashes and then do a sig verify */ #else #error No Asymmetric crypto module #endif #ifndef _APPLE_CDSA_ if (outputLen != 36) { ERR(err = SSLProtocolErr); goto fail; } #endif clientRandom.data = ctx->clientRandom; clientRandom.length = 32; serverRandom.data = ctx->serverRandom; serverRandom.length = 32; tempPubKey.data = message.data; tempPubKey.length = modulusLen + exponentLen + 4; hashOut.data = hash; hashOut.length = 16; if (ERR(err = ReadyHash(&SSLHashMD5, &hashCtx, ctx)) != 0) goto fail; if (ERR(err = SSLHashMD5.update(hashCtx, clientRandom)) != 0) goto fail; if (ERR(err = SSLHashMD5.update(hashCtx, serverRandom)) != 0) goto fail; if (ERR(err = SSLHashMD5.update(hashCtx, tempPubKey)) != 0) goto fail; if (ERR(err = SSLHashMD5.final(hashCtx, hashOut)) != 0) goto fail; #if _APPLE_CDSA_ /* * SHA hash goes right after the MD5 hash */ hashOut.data = hash + 16; #else if ((memcmp(hash, signedHashes.data, 16)) != 0) { ERR(err = SSLProtocolErr); goto fail; } #endif /* _APPLE_CDSA_ */ hashOut.length = 20; if (ERR(err = SSLFreeBuffer(&hashCtx, &ctx->sysCtx)) != 0) goto fail; if (ERR(err = ReadyHash(&SSLHashSHA1, &hashCtx, ctx)) != 0) goto fail; if (ERR(err = SSLHashSHA1.update(hashCtx, clientRandom)) != 0) goto fail; if (ERR(err = SSLHashSHA1.update(hashCtx, serverRandom)) != 0) goto fail; if (ERR(err = SSLHashSHA1.update(hashCtx, tempPubKey)) != 0) goto fail; if (ERR(err = SSLHashSHA1.final(hashCtx, hashOut)) != 0) goto fail; #if _APPLE_CDSA_ err = sslRsaRawVerify(ctx, ctx->peerPubKey, ctx->peerPubKeyCsp, hash, /* plaintext */ 36, /* plaintext length */ signature, signatureLen); if(err) { errorLog1("SSLProcessRSAServerKeyExchange: sslRsaRawVerify returned %d\n", err); goto fail; } #else /* old BSAFE/RSAREF */ if ((memcmp(hash, signedHashes.data + 16, 20)) != 0) { ERR(err = SSLProtocolErr); goto fail; } #endif /* Signature matches; now replace server key with new key */ #if RSAREF memset(&ctx->peerKey, 0, sizeof(R_RSA_PUBLIC_KEY)); memcpy(ctx->peerKey.modulus + (MAX_RSA_MODULUS_LEN - modulusLen), modulus, modulusLen); memcpy(ctx->peerKey.exponent + (MAX_RSA_MODULUS_LEN - exponentLen), exponent, exponentLen); /* Adjust bit length for leading zeros in value; assume no more than 8 leading zero bits */ { unsigned int bitAdjust; UInt8 c; c = modulus[0]; bitAdjust = 8; while (c != 0) { --bitAdjust; c >>= 1; } ctx->peerKey.bits = modulusLen * 8 - bitAdjust; } err = SSLNoErr; #elif BSAFE { A_RSA_KEY pubKeyInfo; int rsaErr; pubKeyInfo.modulus.data = modulus; pubKeyInfo.modulus.len = modulusLen; pubKeyInfo.exponent.data = exponent; pubKeyInfo.exponent.len = exponentLen; if ((rsaErr = B_CreateKeyObject(&ctx->peerKey)) != 0) return SSLUnknownErr; if ((rsaErr = B_SetKeyInfo(ctx->peerKey, KI_RSAPublic, (POINTER)&pubKeyInfo)) != 0) return SSLUnknownErr; } err = SSLNoErr; #elif _APPLE_CDSA_ { SSLBuffer modBuf; SSLBuffer expBuf; /* first free existing peerKey */ sslFreeKey(ctx->peerPubKeyCsp, &ctx->peerPubKey, NULL); /* no KCItem */ /* and cook up a new one from raw bits */ modBuf.data = modulus; modBuf.length = modulusLen; expBuf.data = exponent; expBuf.length = exponentLen; err = sslGetPubKeyFromBits(ctx, &modBuf, &expBuf, &ctx->peerPubKey, &ctx->peerPubKeyCsp); } #else #error No Assymmetric crypto module #endif /* RSAREF / BSAFE */ fail: ERR(SSLFreeBuffer(&signedHashes, &ctx->sysCtx)); ERR(SSLFreeBuffer(&hashCtx, &ctx->sysCtx)); return err; } #if APPLE_DH static SSLErr SSLProcessDHanonServerKeyExchange(SSLBuffer message, SSLContext *ctx) { SSLErr err; UInt8 *progress; unsigned int totalLength; if (message.length < 6) { errorLog1("SSLProcessDHanonServerKeyExchange error: msg len %d\n", message.length); return ERR(SSLProtocolErr); } progress = message.data; totalLength = 0; #if RSAREF { SSLBuffer alloc; UInt8 *prime, *generator, *publicVal; ctx->peerDHParams.primeLen = SSLDecodeInt(progress, 2); progress += 2; prime = progress; progress += ctx->peerDHParams.primeLen; totalLength += ctx->peerDHParams.primeLen; if (message.length < 6 + totalLength) return ERR(SSLProtocolErr); ctx->peerDHParams.generatorLen = SSLDecodeInt(progress, 2); progress += 2; generator = progress; progress += ctx->peerDHParams.generatorLen; totalLength += ctx->peerDHParams.generatorLen; if (message.length < 6 + totalLength) return ERR(SSLProtocolErr); ctx->dhPeerPublic.length = SSLDecodeInt(progress, 2); progress += 2; publicVal = progress; progress += ctx->dhPeerPublic.length; totalLength += ctx->dhPeerPublic.length; if (message.length != 6 + totalLength) return ERR(SSLProtocolErr); ASSERT(progress == message.data + message.length); if (ERR(err = SSLAllocBuffer(&alloc, ctx->peerDHParams.primeLen + ctx->peerDHParams.generatorLen, &ctx->sysCtx)) != 0) return err; ctx->peerDHParams.prime = alloc.data; memcpy(ctx->peerDHParams.prime, prime, ctx->peerDHParams.primeLen); ctx->peerDHParams.generator = alloc.data + ctx->peerDHParams.primeLen; memcpy(ctx->peerDHParams.generator, generator, ctx->peerDHParams.generatorLen); if (ERR(err = SSLAllocBuffer(&ctx->dhPeerPublic, ctx->dhPeerPublic.length, &ctx->sysCtx)) != 0) return err; memcpy(ctx->dhPeerPublic.data, publicVal, ctx->dhPeerPublic.length); } #elif BSAFE { int rsaErr; unsigned char *publicVal; A_DH_KEY_AGREE_PARAMS params; B_ALGORITHM_METHOD *chooser[] = { &AM_DH_KEY_AGREE, 0 }; params.prime.len = SSLDecodeInt(progress, 2); progress += 2; params.prime.data = progress; progress += params.prime.len; totalLength += params.prime.len; if (message.length < 6 + totalLength) return ERR(SSLProtocolErr); params.base.len = SSLDecodeInt(progress, 2); progress += 2; params.base.data = progress; progress += params.base.len; totalLength += params.base.len; if (message.length < 6 + totalLength) return ERR(SSLProtocolErr); ctx->dhPeerPublic.length = SSLDecodeInt(progress, 2); if (ERR(err = SSLAllocBuffer(&ctx->dhPeerPublic, ctx->dhPeerPublic.length, &ctx->sysCtx)) != 0) return err; progress += 2; publicVal = progress; progress += ctx->dhPeerPublic.length; totalLength += ctx->dhPeerPublic.length; memcpy(ctx->dhPeerPublic.data, publicVal, ctx->dhPeerPublic.length); if (message.length != 6 + totalLength) return ERR(SSLProtocolErr); params.exponentBits = 8 * ctx->dhPeerPublic.length - 1; if ((rsaErr = B_CreateAlgorithmObject(&ctx->peerDHParams)) != 0) return SSLUnknownErr; if ((rsaErr = B_SetAlgorithmInfo(ctx->peerDHParams, AI_DHKeyAgree, (POINTER)¶ms)) != 0) return SSLUnknownErr; if ((rsaErr = B_KeyAgreeInit(ctx->peerDHParams, (B_KEY_OBJ) 0, chooser, NO_SURR)) != 0) return SSLUnknownErr; } #endif return SSLNoErr; } #endif SSLErr SSLProcessKeyExchange(SSLBuffer keyExchange, SSLContext *ctx) { SSLErr err; switch (ctx->selectedCipherSpec->keyExchangeMethod) { case SSL_RSA: case SSL_RSA_EXPORT: if (ERR(err = SSLDecodeRSAKeyExchange(keyExchange, ctx)) != 0) return err; break; #if APPLE_DH case SSL_DH_anon: if (ERR(err = SSLDecodeDHanonKeyExchange(keyExchange, ctx)) != 0) return err; break; #endif default: return ERR(SSLUnsupportedErr); } return SSLNoErr; } static SSLErr SSLDecodeRSAKeyExchange(SSLBuffer keyExchange, SSLContext *ctx) { SSLErr err; SSLBuffer result; UInt32 outputLen, localKeyModulusLen; SSLRSAPrivateKey *key; SSLProtocolVersion version; Boolean useEncryptKey = false; #if _APPLE_CDSA_ /* different key names, also need CSP handle */ CSSM_CSP_HANDLE cspHand; CASSERT(ctx->protocolSide == SSL_ServerSide); /* * FIXME - The original SSLRef looked at * ctx->selectedCipherSpec->keyExchangeMethod to decide which * key to use (exportKey or localKey). I really don't think we * want to use that - it's constant. We need to look at * whether the app specified encrypting certs, right? */ #if SSL_SERVER_KEYEXCH_HACK /* * the way we work with Netscape. * FIXME - maybe we should *require* an encryptPrivKey in this * situation? */ if((ctx->selectedCipherSpec->keyExchangeMethod == SSL_RSA_EXPORT) && (ctx->encryptPrivKey != NULL)) { useEncryptKey = true; } #else /* !SSL_SERVER_KEYEXCH_HACK */ /* The "correct" way, I think, which doesn't work with Netscape */ if (ctx->encryptPrivKey) { useEncryptKey = true; } #endif /* SSL_SERVER_KEYEXCH_HACK */ if (useEncryptKey) { key = &ctx->encryptPrivKey; cspHand = ctx->encryptKeyCsp; } else { key = &ctx->signingPrivKey; cspHand = ctx->signingKeyCsp; } #else /* original SSLRef3 */ if (ctx->selectedCipherSpec->keyExchangeMethod == SSL_RSA_EXPORT) key = &ctx->exportKey; else key = &ctx->localKey; #endif /* _APPLE_CDSA_ */ result.data = 0; #if RSAREF localKeyModulusLen = (key->bits + 7)/8; #elif BSAFE { A_RSA_KEY *keyInfo; int rsaResult; if ((rsaResult = B_GetKeyInfo((POINTER*)&keyInfo, *key, KI_RSAPublic)) != 0) return SSLUnknownErr; localKeyModulusLen = keyInfo->modulus.len; } #elif _APPLE_CDSA_ localKeyModulusLen = sslKeyLengthInBytes(*key); #else #error No assymetric crypto module #endif /* RSAREF / BSAFE */ if (keyExchange.length != localKeyModulusLen) { errorLog0("SSLDecodeRSAKeyExchange: length error\n"); return ERR(SSLProtocolErr); } #if RSAREF if (ERR(err = SSLAllocBuffer(&result, localKeyModulusLen, &ctx->sysCtx)) != 0) return err; if ((RSAPrivateDecrypt(result.data, &outputLen, keyExchange.data, keyExchange.length, key)) != 0) { ERR(err = SSLUnknownErr); goto fail; } #elif BSAFE { B_ALGORITHM_OBJ rsa; B_ALGORITHM_METHOD *chooser[] = { &AM_RSA_DECRYPT, &AM_RSA_CRT_DECRYPT, 0 }; int rsaResult; unsigned int decryptLen; /* Allocate room for the premaster secret; BSAFE makes sure we don't decode too much data */ if (ERR(err = SSLAllocBuffer(&result, 48, &ctx->sysCtx)) != 0) return err; if ((rsaResult = B_CreateAlgorithmObject(&rsa)) != 0) return SSLUnknownErr; if ((rsaResult = B_SetAlgorithmInfo(rsa, AI_PKCS_RSAPrivate, 0)) != 0) return SSLUnknownErr; #ifdef macintosh /* * I think this is an SSLRef bug - we need to use the right key here, * as the RSAREF case above does! */ if ((rsaResult = B_DecryptInit(rsa, *key, chooser, NO_SURR)) != 0) return SSLUnknownErr; #else /* the SSLRef way */ if ((rsaResult = B_DecryptInit(rsa, ctx->localKey, chooser, NO_SURR)) != 0) return SSLUnknownErr; #endif /* mac/SSLREF */ if ((rsaResult = B_DecryptUpdate(rsa, result.data, &decryptLen, 48, keyExchange.data, keyExchange.length, 0, NO_SURR)) != 0) return SSLUnknownErr; outputLen = decryptLen; if ((rsaResult = B_DecryptFinal(rsa, result.data+outputLen, &decryptLen, 48-outputLen, 0, NO_SURR)) != 0) return SSLUnknownErr; outputLen += decryptLen; B_DestroyAlgorithmObject(&rsa); } #elif _APPLE_CDSA_ err = sslRsaDecrypt(ctx, *key, cspHand, keyExchange.data, keyExchange.length, result.data, 48, &outputLen); if(err) { goto fail; } #endif if (outputLen != 48) { errorLog0("SSLDecodeRSAKeyExchange: outputLen error\n"); ERR(err = SSLProtocolErr); goto fail; } result.length = outputLen; version = (SSLProtocolVersion)SSLDecodeInt(result.data, 2); /* Modify this check to check against our maximum version with protocol revisions */ if (version > ctx->negProtocolVersion && version < SSL_Version_3_0) { errorLog0("SSLDecodeRSAKeyExchange: version error\n"); ERR(err = SSLProtocolErr); goto fail; } if (ERR(err = SSLAllocBuffer(&ctx->preMasterSecret, 48, &ctx->sysCtx)) != 0) goto fail; memcpy(ctx->preMasterSecret.data, result.data, 48); err = SSLNoErr; fail: ERR(SSLFreeBuffer(&result, &ctx->sysCtx)); return err; } #if APPLE_DH static SSLErr SSLDecodeDHanonKeyExchange(SSLBuffer keyExchange, SSLContext *ctx) { SSLErr err; unsigned int publicLen; int rsaResult; publicLen = SSLDecodeInt(keyExchange.data, 2); #if RSAREF if (keyExchange.length != publicLen + 2 || publicLen != ctx->dhAnonParams.primeLen) return ERR(SSLProtocolErr); if (ERR(err = SSLAllocBuffer(&ctx->preMasterSecret, ctx->dhAnonParams.primeLen, &ctx->sysCtx)) != 0) return err; if ((rsaResult = R_ComputeDHAgreedKey (ctx->preMasterSecret.data, ctx->dhPeerPublic.data, ctx->dhPrivate.data, ctx->dhPrivate.length, &ctx->dhAnonParams)) != 0) { err = SSLUnknownErr; return err; } #elif BSAFE { unsigned int amount; if (keyExchange.length != publicLen + 2) return ERR(SSLProtocolErr); if (ERR(err = SSLAllocBuffer(&ctx->preMasterSecret, 128, &ctx->sysCtx)) != 0) return err; if ((rsaResult = B_KeyAgreePhase2(ctx->dhAnonParams, ctx->preMasterSecret.data, &amount, 128, keyExchange.data+2, publicLen, NO_SURR)) != 0) return err; ctx->preMasterSecret.length = amount; } #endif return SSLNoErr; } #endif /* APPLE_DH */ SSLErr SSLEncodeKeyExchange(SSLRecord *keyExchange, SSLContext *ctx) { SSLErr err; CASSERT(ctx->protocolSide == SSL_ClientSide); switch (ctx->selectedCipherSpec->keyExchangeMethod) { case SSL_RSA: case SSL_RSA_EXPORT: if (ERR(err = SSLEncodeRSAKeyExchange(keyExchange, ctx)) != 0) return err; break; #if APPLE_DH case SSL_DH_anon: if (ERR(err = SSLEncodeDHanonKeyExchange(keyExchange, ctx)) != 0) return err; break; #endif default: return ERR(SSLUnsupportedErr); } return SSLNoErr; } static SSLErr SSLEncodeRSAKeyExchange(SSLRecord *keyExchange, SSLContext *ctx) { SSLErr err; UInt32 outputLen, peerKeyModulusLen; #if !_APPLE_CDSA_ SSLRandomCtx rsaRandom; int rsaResult; #endif if (ERR(err = SSLEncodeRSAPremasterSecret(ctx)) != 0) return err; #if !_APPLE_CDSA_ if (ERR(err = ReadyRandom(&rsaRandom, ctx)) != 0) return err; #endif keyExchange->contentType = SSL_handshake; keyExchange->protocolVersion = SSL_Version_3_0; #if RSAREF peerKeyModulusLen = (ctx->peerKey.bits + 7)/8; #elif BSAFE { A_RSA_KEY *keyInfo; if ((rsaResult = B_GetKeyInfo((POINTER*)&keyInfo, ctx->peerKey, KI_RSAPublic)) != 0) return SSLUnknownErr; peerKeyModulusLen = keyInfo->modulus.len; } #elif _APPLE_CDSA_ peerKeyModulusLen = sslKeyLengthInBytes(ctx->peerPubKey); #else #error No Assymetric Crypto #endif /* RSAREF / BSAFE */ if (ERR(err = SSLAllocBuffer(&keyExchange->contents,peerKeyModulusLen + 4,&ctx->sysCtx)) != 0) { #if RSAREF R_RandomFinal(&rsaRandom); #elif BSAFE B_DestroyAlgorithmObject(&rsaRandom); #endif return err; } keyExchange->contents.data[0] = SSL_client_key_exchange; SSLEncodeInt(keyExchange->contents.data + 1, peerKeyModulusLen, 3); #if RSAREF if ((rsaResult = RSAPublicEncrypt(keyExchange->contents.data+4, &outputLen, ctx->preMasterSecret.data, 48, &ctx->peerKey,&rsaRandom)) != 0) { R_RandomFinal(&rsaRandom); return ERR(SSLUnknownErr); } R_RandomFinal(&rsaRandom); #elif BSAFE { B_ALGORITHM_OBJ rsa; B_ALGORITHM_METHOD *chooser[] = { &AM_RSA_ENCRYPT, 0 }; int rsaResult; unsigned int encryptedOut; if ((rsaResult = B_CreateAlgorithmObject(&rsa)) != 0) return SSLUnknownErr; if ((rsaResult = B_SetAlgorithmInfo(rsa, AI_PKCS_RSAPublic, 0)) != 0) return SSLUnknownErr; if ((rsaResult = B_EncryptInit(rsa, ctx->peerKey, chooser, NO_SURR)) != 0) return SSLUnknownErr; if ((rsaResult = B_EncryptUpdate(rsa, keyExchange->contents.data+4, &encryptedOut, peerKeyModulusLen, ctx->preMasterSecret.data, 48, rsaRandom, NO_SURR)) != 0) return SSLUnknownErr; outputLen = encryptedOut; if ((rsaResult = B_EncryptFinal(rsa, keyExchange->contents.data+4+outputLen, &encryptedOut, peerKeyModulusLen-outputLen, rsaRandom, NO_SURR)) != 0) return SSLUnknownErr; outputLen += encryptedOut; B_DestroyAlgorithmObject(&rsa); } B_DestroyAlgorithmObject(&rsaRandom); #elif _APPLE_CDSA_ err = sslRsaEncrypt(ctx, ctx->peerPubKey, /* FIXME - maybe this should be ctx->cspHand */ ctx->peerPubKeyCsp, ctx->preMasterSecret.data, 48, keyExchange->contents.data+4, peerKeyModulusLen, &outputLen); if(err) { return err; } #endif CASSERT(outputLen + 4 == keyExchange->contents.length); return SSLNoErr; } #if APPLE_DH static SSLErr SSLEncodeDHanonKeyExchange(SSLRecord *keyExchange, SSLContext *ctx) { SSLErr err; unsigned int outputLen; if (ERR(err = SSLEncodeDHPremasterSecret(ctx)) != 0) return err; outputLen = ctx->dhExchangePublic.length + 2; keyExchange->contentType = SSL_handshake; keyExchange->protocolVersion = SSL_Version_3_0; if (ERR(err = SSLAllocBuffer(&keyExchange->contents,outputLen + 4,&ctx->sysCtx)) != 0) return err; keyExchange->contents.data[0] = SSL_client_key_exchange; SSLEncodeInt(keyExchange->contents.data+1, ctx->dhExchangePublic.length+2, 3); SSLEncodeInt(keyExchange->contents.data+4, ctx->dhExchangePublic.length, 2); memcpy(keyExchange->contents.data+6, ctx->dhExchangePublic.data, ctx->dhExchangePublic.length); return SSLNoErr; } #endif