|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: keyxmsdh.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 10-21-97 jbanes CAPI integration stuff.
//
//----------------------------------------------------------------------------
#include <spbase.h>
#include <align.h>
// PROV_DH_SCHANNEL handle used for client and server operations. This is
// where the schannel ephemeral DH key lives.
HCRYPTPROV g_hDhSchannelProv = 0; PROV_ENUMALGS_EX * g_pDhSchannelAlgs = NULL; DWORD g_cDhSchannelAlgs = 0;
SP_STATUS WINAPI DHGenerateServerExchangeValue( SPContext * pContext, // in
PUCHAR pServerExchangeValue, // out
DWORD * pcbServerExchangeValue // in/out
);
SP_STATUS WINAPI DHGenerateClientExchangeValue( SPContext * pContext, // in
PUCHAR pServerExchangeValue, // in
DWORD cbServerExchangeValue, // in
PUCHAR pClientClearValue, // out
DWORD * pcbClientClearValue, // in/out
PUCHAR pClientExchangeValue, // out
DWORD * pcbClientExchangeValue // in/out
);
SP_STATUS WINAPI DHGenerateServerMasterKey( SPContext * pContext, // in
PUCHAR pClientClearValue, // in
DWORD cbClientClearValue, // in
PUCHAR pClientExchangeValue, // in
DWORD cbClientExchangeValue // in
);
KeyExchangeSystem keyexchDH = { SP_EXCH_DH_PKCS3, "Diffie Hellman", DHGenerateServerExchangeValue, DHGenerateClientExchangeValue, DHGenerateServerMasterKey, };
SP_STATUS SPSignDssParams( PSPContext pContext, PSPCredential pCred, PBYTE pbParams, DWORD cbParams, PBYTE pbEncodedSignature, PDWORD pcbEncodedSignature) { HCRYPTHASH hHash; BYTE rgbSignature[DSA_SIGNATURE_SIZE]; DWORD cbSignature;
if(pCred == NULL) { return SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE); }
if(!CryptCreateHash(pCred->hProv, CALG_SHA, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); return PCT_ERR_ILLEGAL_MESSAGE; }
if(!CryptHashData(hHash, pContext->rgbS3CRandom, 32, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_ERR_ILLEGAL_MESSAGE; }
if(!CryptHashData(hHash, pContext->rgbS3SRandom, 32, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_ERR_ILLEGAL_MESSAGE; }
if(!CryptHashData(hHash, pbParams, cbParams, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_ERR_ILLEGAL_MESSAGE; }
cbSignature = sizeof(rgbSignature); if(!CryptSignHash(hHash, pCred->dwKeySpec, NULL, 0, rgbSignature, &cbSignature)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_ERR_ILLEGAL_MESSAGE; }
CryptDestroyHash(hHash);
if(!CryptEncodeObject(X509_ASN_ENCODING, X509_DSS_SIGNATURE, rgbSignature, pbEncodedSignature, pcbEncodedSignature)) { SP_LOG_RESULT(GetLastError()); return PCT_ERR_ILLEGAL_MESSAGE; }
// Return success.
return PCT_ERR_OK; }
SP_STATUS SPVerifyDssParams( PSPContext pContext, HCRYPTPROV hProv, HCRYPTKEY hPublicKey, PBYTE pbParams, DWORD cbParams, PBYTE pbEncodedSignature, DWORD cbEncodedSignature) { HCRYPTHASH hHash; BYTE rgbSignature[DSA_SIGNATURE_SIZE]; DWORD cbSignature;
// Decode the signature.
cbSignature = sizeof(rgbSignature); if(!CryptDecodeObject(X509_ASN_ENCODING, X509_DSS_SIGNATURE, pbEncodedSignature, cbEncodedSignature, 0, rgbSignature, &cbSignature)) { SP_LOG_RESULT(GetLastError()); return PCT_ERR_ILLEGAL_MESSAGE; }
if(!CryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash)) { SP_LOG_RESULT(GetLastError()); return PCT_ERR_ILLEGAL_MESSAGE; }
if(!CryptHashData(hHash, pContext->rgbS3CRandom, 32, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_ERR_ILLEGAL_MESSAGE; }
if(!CryptHashData(hHash, pContext->rgbS3SRandom, 32, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_ERR_ILLEGAL_MESSAGE; }
if(!CryptHashData(hHash, pbParams, cbParams, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_ERR_ILLEGAL_MESSAGE; }
if(!CryptVerifySignature(hHash, rgbSignature, cbSignature, hPublicKey, NULL, 0)) { SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return PCT_INT_MSG_ALTERED; }
CryptDestroyHash(hHash);
return PCT_ERR_OK; }
SP_STATUS GetDHEphemKey( PSPContext pContext, HCRYPTPROV * phProv, HCRYPTKEY * phTek) { PSPCredentialGroup pCredGroup; PSPCredential pCred; DWORD dwKeySize; DWORD cbData; DWORD Status;
pCredGroup = pContext->RipeZombie->pServerCred; if(pCredGroup == NULL) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
pCred = pContext->RipeZombie->pActiveServerCred; if(pCredGroup == NULL) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
LockCredentialExclusive(pCredGroup);
if(phProv) { *phProv = pCred->hProv; }
dwKeySize = 1024;
// Determine if we've already created an ephemeral key.
if(pCred->hTek) { *phTek = pCred->hTek; Status = PCT_ERR_OK; goto cleanup; }
// Generate the ephemeral key.
if(!CryptGenKey(pCred->hProv, CALG_DH_EPHEM, dwKeySize << 16, phTek)) { SP_LOG_RESULT(GetLastError()); Status = PCT_INT_INTERNAL_ERROR; goto cleanup; }
pCred->hTek = *phTek;
Status = PCT_ERR_OK;
cleanup:
if(Status == PCT_ERR_OK) { // Determine size of key exchange key.
cbData = sizeof(DWORD); if(!CryptGetKeyParam(*phTek, KP_BLOCKLEN, (PBYTE)&pContext->RipeZombie->dwExchStrength, &cbData, 0)) { SP_LOG_RESULT(GetLastError()); pContext->RipeZombie->dwExchStrength = 0; } }
UnlockCredential(pCredGroup);
return Status; }
//+---------------------------------------------------------------------------
//
// Function: DHGenerateServerExchangeValue
//
// Synopsis: Create a ServerKeyExchange message, containing an ephemeral
// DH key.
//
// Arguments: [pContext] -- Schannel context.
// [pServerExchangeValue] --
// [pcbServerExchangeValue] --
//
// History: 03-24-98 jbanes Added CAPI integration.
//
// Notes: The following data is placed in the output buffer by
// this routine:
//
// struct {
// opaque dh_p<1..2^16-1>;
// opaque dh_g<1..2^16-1>;
// opaque dh_Ys<1..2^16-1>;
// } ServerDHParams;
//
// struct {
// ServerDHParams params;
// Signature signed_params;
// } ServerKeyExchange;
//
//----------------------------------------------------------------------------
SP_STATUS WINAPI DHGenerateServerExchangeValue( PSPContext pContext, // in
PBYTE pServerExchangeValue, // out
DWORD * pcbServerExchangeValue) // in/out
{ PSPCredential pCred; HCRYPTPROV hProv = 0; HCRYPTKEY hServerDhKey = 0;
PBYTE pbMessage; DWORD cbMessage; DWORD cbBytesLeft; DWORD cbData; DWORD cbP; DWORD cbG; DWORD cbY; DWORD cbSignature; SP_STATUS pctRet; BOOL fImpersonating = FALSE;
pCred = pContext->RipeZombie->pActiveServerCred; if(pCred == NULL) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
if(pContext->RipeZombie->fProtocol != SP_PROT_SSL3_SERVER && pContext->RipeZombie->fProtocol != SP_PROT_TLS1_SERVER) { // SSL2 and PCT do not support DH.
return SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH); }
// Always send a ServerKeyExchange message.
pContext->fExchKey = TRUE;
fImpersonating = SslImpersonateClient();
//
// Generate ephemeral DH key.
//
pctRet = GetDHEphemKey(pContext, &hProv, &hServerDhKey); if(pctRet != PCT_ERR_OK) { SP_LOG_RESULT(pctRet); goto cleanup; }
//
// Estimate sizes of P, G, and Y.
//
if(!CryptGetKeyParam(hServerDhKey, KP_P, NULL, &cbP, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
if(!CryptGetKeyParam(hServerDhKey, KP_G, NULL, &cbG, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
if(!CryptExportKey(hServerDhKey, 0, PUBLICKEYBLOB, 0, NULL, &cbY)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; }
//
// Compute approximate size of ServerKeyExchange message.
//
cbMessage = 2 + cbP + 2 + cbG + 2 + cbY + sizeof(DWORD) + 2 + MAX_DSA_ENCODED_SIGNATURE_SIZE;
if(pServerExchangeValue == NULL) { *pcbServerExchangeValue = cbMessage; pctRet = PCT_ERR_OK; goto cleanup; } if(*pcbServerExchangeValue < cbMessage) { *pcbServerExchangeValue = cbMessage; pctRet = SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL); goto cleanup; }
//
// Build the ServerDHParams structure.
//
pbMessage = pServerExchangeValue; cbBytesLeft = cbMessage;
// Get P.
if(!CryptGetKeyParam(hServerDhKey, KP_P, pbMessage + 2, &cbP, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } ReverseInPlace(pbMessage + 2, cbP);
pbMessage[0] = MSBOF(cbP); pbMessage[1] = LSBOF(cbP); pbMessage += 2 + cbP; cbBytesLeft -= 2 + cbP;
// Get G.
if(!CryptGetKeyParam(hServerDhKey, KP_G, pbMessage + 2, &cbG, 0)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } ReverseInPlace(pbMessage + 2, cbG);
pbMessage[0] = MSBOF(cbG); pbMessage[1] = LSBOF(cbG); pbMessage += 2 + cbG; cbBytesLeft -= 2 + cbG;
// Get Ys.
{ BLOBHEADER *pBlobHeader; DHPUBKEY * pDHPubKey; PBYTE pbKey; DWORD cbKey;
pBlobHeader = (BLOBHEADER *)ROUND_UP_POINTER(pbMessage, ALIGN_DWORD); cbData = cbBytesLeft - sizeof(DWORD);
if(!CryptExportKey(hServerDhKey, 0, PUBLICKEYBLOB, 0, (PBYTE)pBlobHeader, &cbData)) { SP_LOG_RESULT(GetLastError()); pctRet = PCT_INT_INTERNAL_ERROR; goto cleanup; } pDHPubKey = (DHPUBKEY *)(pBlobHeader + 1); pbKey = (BYTE *)(pDHPubKey + 1);
cbKey = pDHPubKey->bitlen / 8; if(pDHPubKey->bitlen % 8) cbKey++;
MoveMemory(pbMessage + 2, pbKey, cbKey); ReverseInPlace(pbMessage + 2, cbKey);
pbMessage[0] = MSBOF(cbKey); pbMessage[1] = LSBOF(cbKey); pbMessage += 2 + cbKey; cbBytesLeft -= 2 + cbKey; }
//
// Sign the ServerDHParams structure.
//
cbSignature = cbBytesLeft - 2; pctRet = SPSignDssParams(pContext, pCred, pServerExchangeValue, (DWORD)(pbMessage - pServerExchangeValue), pbMessage + 2, &cbSignature); if(pctRet != PCT_ERR_OK) { SP_LOG_RESULT(pctRet); goto cleanup; } pbMessage[0] = MSBOF(cbSignature); pbMessage[1] = LSBOF(cbSignature); pbMessage += 2 + cbSignature; cbBytesLeft -= 2 + cbSignature;
//
// Update function outputs.
//
SP_ASSERT(cbBytesLeft < cbMessage);
*pcbServerExchangeValue = (DWORD)(pbMessage - pServerExchangeValue);
// Use ephemeral key for the new connection.
pContext->RipeZombie->hMasterProv = hProv;
pctRet = PCT_ERR_OK;
cleanup:
if(fImpersonating) { RevertToSelf(); }
return pctRet; }
SP_STATUS ParseServerKeyExchange( PSPContext pContext, // in
PBYTE pbMessage, // in
DWORD cbMessage, // in
PBYTE * ppbServerP, // out
PDWORD pcbServerP, // out
PBYTE * ppbServerG, // out
PDWORD pcbServerG, // out
PBYTE * ppbServerY, // out
PDWORD pcbServerY, // out
BOOL fValidateSig) // in
{ PBYTE pbData; BLOBHEADER *pPublicBlob; DWORD cbPublicBlob; HCRYPTKEY hServerPublic = 0; PBYTE pbSignature; DWORD cbSignature; DWORD cbSignedData; SP_STATUS pctRet;
//
// Parse out ServerKeyExchange message fields
//
pbData = pbMessage;
if(pbData + 2 > pbMessage + cbMessage) { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); }
*pcbServerP = MAKEWORD(pbData[1], pbData[0]); *ppbServerP = pbData + 2; pbData += 2 + *pcbServerP;
if(pbData + 2 > pbMessage + cbMessage) { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); }
*pcbServerG = MAKEWORD(pbData[1], pbData[0]); *ppbServerG = pbData + 2; pbData += 2 + *pcbServerG;
if(pbData + 2 > pbMessage + cbMessage) { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); }
*pcbServerY = MAKEWORD(pbData[1], pbData[0]); *ppbServerY = pbData + 2; pbData += 2 + *pcbServerY;
if(pbData + 2 > pbMessage + cbMessage) { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); }
cbSignedData = (DWORD)(pbData - pbMessage);
cbSignature = MAKEWORD(pbData[1], pbData[0]); pbSignature = pbData + 2; pbData += 2 + cbSignature;
if(pbData != pbMessage + cbMessage) { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); }
if(fValidateSig == FALSE) { return PCT_ERR_OK; }
//
// Validate signature.
//
pPublicBlob = pContext->RipeZombie->pRemotePublic->pPublic; cbPublicBlob = pContext->RipeZombie->pRemotePublic->cbPublic;
if(!CryptImportKey(pContext->RipeZombie->hMasterProv, (PBYTE)pPublicBlob, cbPublicBlob, 0, 0, &hServerPublic)) { return SP_LOG_RESULT(GetLastError()); }
pctRet = SPVerifyDssParams( pContext, pContext->RipeZombie->hMasterProv, hServerPublic, pbMessage, cbSignedData, pbSignature, cbSignature); if(pctRet != PCT_ERR_OK) { CryptDestroyKey(hServerPublic); return SP_LOG_RESULT(pctRet); }
CryptDestroyKey(hServerPublic);
return PCT_ERR_OK; }
//+---------------------------------------------------------------------------
//
// Function: DHGenerateClientExchangeValue
//
// Synopsis: Create a ClientKeyExchange message, containing an ephemeral
// DH key.
//
// Arguments:
//
// History: 03-24-98 jbanes Added CAPI integration.
//
// Notes: The following data is placed in the output buffer by
// this routine:
//
// struct {
// opaque dh_Yc<1..2^16-1>;
// } ClientDiffieHellmanPublic;
//
//----------------------------------------------------------------------------
SP_STATUS WINAPI DHGenerateClientExchangeValue( SPContext * pContext, // in
PUCHAR pServerExchangeValue, // in
DWORD cbServerExchangeValue, // in
PUCHAR pClientClearValue, // out
DWORD * pcbClientClearValue, // in/out
PUCHAR pClientExchangeValue, // out
DWORD * pcbClientExchangeValue) // in/out
{ HCRYPTKEY hClientDHKey = 0; PSessCacheItem pZombie; CRYPT_DATA_BLOB Data; ALG_ID Algid; DWORD cbHeader; SP_STATUS pctRet;
PBYTE pbServerP = NULL; DWORD cbServerP; PBYTE pbServerG = NULL; DWORD cbServerG; PBYTE pbServerY = NULL; DWORD cbServerY; PBYTE pbClientY = NULL; DWORD cbClientY;
PBYTE pbBlob = NULL; DWORD cbBlob; DWORD cbData; DWORD dwKeySize;
UNREFERENCED_PARAMETER(pClientClearValue); UNREFERENCED_PARAMETER(pcbClientClearValue);
pZombie = pContext->RipeZombie; if(pZombie == NULL) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
if(pZombie->hMasterProv == 0) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
// We're doing a full handshake.
pContext->Flags |= CONTEXT_FLAG_FULL_HANDSHAKE;
if(pZombie->fProtocol == SP_PROT_SSL3_CLIENT) { Algid = CALG_SSL3_MASTER; } else if(pZombie->fProtocol == SP_PROT_TLS1_CLIENT) { Algid = CALG_TLS1_MASTER; } else { return SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH); }
if(pServerExchangeValue == NULL) { return SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); }
//
// Is the output buffer large enough?
//
pctRet = ParseServerKeyExchange(pContext, pServerExchangeValue, cbServerExchangeValue, &pbServerP, &cbServerP, &pbServerG, &cbServerG, &pbServerY, &cbServerY, FALSE); if(pctRet != PCT_ERR_OK) { return pctRet; }
cbBlob = sizeof(BLOBHEADER) + sizeof(DHPUBKEY) + cbServerY + 20;
if(pClientExchangeValue == NULL) { *pcbClientExchangeValue = cbBlob; return PCT_ERR_OK; }
if(*pcbClientExchangeValue < cbBlob) { *pcbClientExchangeValue = cbBlob; return SP_LOG_RESULT(PCT_INT_BUFF_TOO_SMALL); }
//
// Parse the ServerKeyExchange message.
//
pctRet = ParseServerKeyExchange(pContext, pServerExchangeValue, cbServerExchangeValue, &pbServerP, &cbServerP, &pbServerG, &cbServerG, &pbServerY, &cbServerY, TRUE); if(pctRet != PCT_ERR_OK) { return pctRet; }
//
// Create buffer to use for endian-izing data.
//
cbBlob = sizeof(BLOBHEADER) + sizeof(DHPUBKEY) + cbServerY; cbBlob = max(cbBlob, cbServerP); cbBlob = max(cbBlob, cbServerG);
SafeAllocaAllocate(pbBlob, cbBlob); if(pbBlob == NULL) { pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); goto cleanup; }
//
// Generate and set the parameters on the client DH key.
//
dwKeySize = cbServerP * 8;
if(!CryptGenKey(pZombie->hMasterProv, CALG_DH_EPHEM, (dwKeySize << 16) | CRYPT_PREGEN, &hClientDHKey)) { pctRet = SP_LOG_RESULT(GetLastError()); goto cleanup; }
ReverseMemCopy(pbBlob, pbServerP, cbServerP); Data.pbData = pbBlob; Data.cbData = cbServerP; if(!CryptSetKeyParam(hClientDHKey, KP_P, (PBYTE)&Data, 0)) { pctRet = SP_LOG_RESULT(GetLastError()); goto cleanup; }
ReverseMemCopy(pbBlob, pbServerG, cbServerG); Data.pbData = pbBlob; Data.cbData = cbServerG; if(cbServerG < cbServerP) { // Expand G so that it's the same size as P.
ZeroMemory(pbBlob + cbServerG, cbServerP - cbServerG); Data.cbData = cbServerP; } if(!CryptSetKeyParam(hClientDHKey, KP_G, (PBYTE)&Data, 0)) { pctRet = SP_LOG_RESULT(GetLastError()); goto cleanup; }
// actually create the client private DH key
if(!CryptSetKeyParam(hClientDHKey, KP_X, NULL, 0)) { pctRet = SP_LOG_RESULT(GetLastError()); goto cleanup; }
//
// Import the server's public key and generate the master secret.
//
{ BLOBHEADER * pBlobHeader; DHPUBKEY * pDHPubKey; PBYTE pbKey;
// Build PUBLICKEYBLOB around the server's public key.
pBlobHeader = (BLOBHEADER *)pbBlob; pDHPubKey = (DHPUBKEY *)(pBlobHeader + 1); pbKey = (PBYTE)(pDHPubKey + 1);
pBlobHeader->bType = PUBLICKEYBLOB; pBlobHeader->bVersion = CUR_BLOB_VERSION; pBlobHeader->reserved = 0; pBlobHeader->aiKeyAlg = CALG_DH_EPHEM;
pDHPubKey->magic = MAGIC_DH1; pDHPubKey->bitlen = cbServerY * 8;
ReverseMemCopy(pbKey, pbServerY, cbServerY);
if(!CryptImportKey(pZombie->hMasterProv, pbBlob, cbBlob, hClientDHKey, 0, &pZombie->hMasterKey)) { pctRet = GetLastError(); goto cleanup; } }
// Determine size of key exchange key.
cbData = sizeof(DWORD); if(!CryptGetKeyParam(hClientDHKey, KP_BLOCKLEN, (PBYTE)&pZombie->dwExchStrength, &cbData, 0)) { SP_LOG_RESULT(GetLastError()); pContext->RipeZombie->dwExchStrength = 0; }
//
// Convert the agreed key to the appropriate master key type.
//
if(!CryptSetKeyParam(pZombie->hMasterKey, KP_ALGID, (PBYTE)&Algid, 0)) { pctRet = SP_LOG_RESULT(GetLastError()); goto cleanup; }
//
// Export the client public key, strip off the blob header
// goo and attach a two byte length field. This will make up our
// ClientKeyExchange message.
//
if(!CryptExportKey(hClientDHKey, 0, PUBLICKEYBLOB, 0, pClientExchangeValue, pcbClientExchangeValue)) { pctRet = SP_LOG_RESULT(GetLastError()); goto cleanup; }
cbHeader = sizeof(BLOBHEADER) + sizeof(DHPUBKEY);
cbClientY = *pcbClientExchangeValue - cbHeader; pbClientY = pClientExchangeValue + cbHeader;
pClientExchangeValue[0] = MSBOF(cbClientY); pClientExchangeValue[1] = LSBOF(cbClientY);
ReverseInPlace(pbClientY, cbClientY); MoveMemory(pClientExchangeValue + 2, pbClientY, cbClientY);
*pcbClientExchangeValue = 2 + cbClientY;
//
// Build the session keys.
//
pctRet = MakeSessionKeys(pContext, pZombie->hMasterProv, pZombie->hMasterKey); if(pctRet != PCT_ERR_OK) { goto cleanup; }
// Update perf counter.
InterlockedIncrement(&g_cClientHandshakes);
pctRet = PCT_ERR_OK;
cleanup:
if(pbBlob) { SafeAllocaFree(pbBlob); }
if(hClientDHKey) { CryptDestroyKey(hClientDHKey); }
return pctRet; }
//+---------------------------------------------------------------------------
//
// Function: PkcsGenerateServerMasterKey
//
// Synopsis: Decrypt the master secret (from the ClientKeyExchange message)
// and derive the session keys from it.
//
// Arguments: [pContext] -- Schannel context.
// [pClientClearValue] -- Not used.
// [cbClientClearValue] -- Not used.
// [pClientExchangeValue] --
// [cbClientExchangeValue] --
//
// History: 03-25-98 jbanes Created.
//
// Notes: The following data is supposed to be in the input buffer:
//
// struct {
// opaque dh_Yc<1..2^16-1>;
// } ClientDiffieHellmanPublic;
//
//----------------------------------------------------------------------------
SP_STATUS WINAPI DHGenerateServerMasterKey( SPContext * pContext, // in
PUCHAR pClientClearValue, // in
DWORD cbClientClearValue, // in
PUCHAR pClientExchangeValue, // in
DWORD cbClientExchangeValue) // in
{ PSessCacheItem pZombie; ALG_ID Algid; SP_STATUS pctRet; PBYTE pbClientY; DWORD cbClientY; HCRYPTKEY hTek; BOOL fImpersonating = FALSE;
UNREFERENCED_PARAMETER(pClientClearValue); UNREFERENCED_PARAMETER(cbClientClearValue);
pZombie = pContext->RipeZombie; if(pZombie == NULL) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
if(pZombie->hMasterProv == 0) { return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
// We're doing a full handshake.
pContext->Flags |= CONTEXT_FLAG_FULL_HANDSHAKE;
fImpersonating = SslImpersonateClient();
pctRet = GetDHEphemKey(pContext, NULL, &hTek); if(pctRet != PCT_ERR_OK) { SP_LOG_RESULT(pctRet); goto cleanup; }
if(pZombie->fProtocol == SP_PROT_SSL3_SERVER) { Algid = CALG_SSL3_MASTER; } else if(pZombie->fProtocol == SP_PROT_TLS1_SERVER) { Algid = CALG_TLS1_MASTER; } else { pctRet = SP_LOG_RESULT(PCT_INT_SPECS_MISMATCH); goto cleanup; }
//
// Parse ClientKeyExchange message.
//
if(pClientExchangeValue == NULL || cbClientExchangeValue <= 2) { pctRet = SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); goto cleanup; }
cbClientY = MAKEWORD(pClientExchangeValue[1], pClientExchangeValue[0]); pbClientY = pClientExchangeValue + 2;
if(2 + cbClientY != cbClientExchangeValue) { pctRet = SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); goto cleanup; }
if(cbClientY == 0) { pctRet = SP_LOG_RESULT(PCT_INT_ILLEGAL_MSG); goto cleanup; }
//
// Import the client's public key and generate the master secret.
//
{ BLOBHEADER * pBlobHeader; DHPUBKEY * pDHPubKey; PBYTE pbKey; PBYTE pbBlob; DWORD cbBlob;
// Build PUBLICKEYBLOB around the server's public key.
cbBlob = sizeof(BLOBHEADER) + sizeof(DHPUBKEY) + cbClientY; SafeAllocaAllocate(pbBlob, cbBlob); if(pbBlob == NULL) { pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); goto cleanup; }
pBlobHeader = (BLOBHEADER *)pbBlob; pDHPubKey = (DHPUBKEY *)(pBlobHeader + 1); pbKey = (PBYTE)(pDHPubKey + 1);
pBlobHeader->bType = PUBLICKEYBLOB; pBlobHeader->bVersion = CUR_BLOB_VERSION; pBlobHeader->reserved = 0; pBlobHeader->aiKeyAlg = CALG_DH_EPHEM;
pDHPubKey->magic = MAGIC_DH1; pDHPubKey->bitlen = cbClientY * 8;
ReverseMemCopy(pbKey, pbClientY, cbClientY);
if(!CryptImportKey(pZombie->hMasterProv, pbBlob, cbBlob, hTek, 0, &pZombie->hMasterKey)) { pctRet = GetLastError(); SafeAllocaFree(pbBlob); goto cleanup; }
SafeAllocaFree(pbBlob); }
//
// Convert the agreed key to the appropriate master key type.
//
if(!CryptSetKeyParam(pZombie->hMasterKey, KP_ALGID, (PBYTE)&Algid, 0)) { pctRet = SP_LOG_RESULT(GetLastError()); goto cleanup; }
//
// Build the session keys.
//
pctRet = MakeSessionKeys(pContext, pZombie->hMasterProv, pZombie->hMasterKey); if(pctRet != PCT_ERR_OK) { goto cleanup; }
// Update perf counter.
InterlockedIncrement(&g_cServerHandshakes);
pctRet = PCT_ERR_OK;
cleanup:
if(fImpersonating) { RevertToSelf(); }
return pctRet; }
void ReverseInPlace(PUCHAR pByte, DWORD cbByte) { DWORD i; BYTE bSave;
for(i=0; i< cbByte/2; i++) { bSave = pByte[i]; pByte[i] = pByte[cbByte-i-1]; pByte[cbByte-i-1] = bSave; } }
|