|
|
/*-----------------------------------------------------------------------------
* Copyright (C) Microsoft Corporation, 1995 - 1999 * All rights reserved. * * This file is part of the Microsoft Private Communication Technology * reference implementation, version 1.0 * * The Private Communication Technology reference implementation, version 1.0 * ("PCTRef"), is being provided by Microsoft to encourage the development and * enhancement of an open standard for secure general-purpose business and * personal communications on open networks. Microsoft is distributing PCTRef * at no charge irrespective of whether you use PCTRef for non-commercial or * commercial use. * * Microsoft expressly disclaims any warranty for PCTRef and all derivatives of * it. PCTRef and any related documentation is provided "as is" without * warranty of any kind, either express or implied, including, without * limitation, the implied warranties or merchantability, fitness for a * particular purpose, or noninfringement. Microsoft shall have no obligation * to provide maintenance, support, upgrades or new releases to you or to anyone * receiving from you PCTRef or your modifications. The entire risk arising out * of use or performance of PCTRef remains with you. * * Please see the file LICENSE.txt, * or http://pct.microsoft.com/pct/pctlicen.txt
* for more information on licensing. * * Please see http://pct.microsoft.com/pct/pct.htm for The Private
* Communication Technology Specification version 1.0 ("PCT Specification") * * 1/23/96 *----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------
* RSA Public Key Cryptosystem, RC4, MD2, MD5 and RSA are trademarks * of RSA Data Security, Inc. *----------------------------------------------------------------------------*/
#include <spbase.h>
#include <wincrypt.h>
#ifdef __cplusplus
extern "C" { #endif
#include <rsa.h>
#include <md2.h>
#include <md5.h>
#ifdef __cplusplus
} #endif
static unsigned char MD5_PRELUDE[] = { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 };
static unsigned char MD2_PRELUDE[] = { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x02, 0x05, 0x00, 0x04, 0x10 };
static VOID ReverseMemCopy( PUCHAR Dest, PUCHAR Source, ULONG Size) { PUCHAR p;
p = Dest + Size - 1; do { *p-- = *Source++; } while (p >= Dest); }
BOOL WINAPI SigRSAMD2Sign( PUCHAR pData, DWORD cbData, PUCHAR pSigned, DWORD *pcbSigned, PctPrivateKey *pKey);
BOOL WINAPI SigRSAMD5Sign( PUCHAR pData, DWORD cbData, PUCHAR pSigned, DWORD *pcbSigned, PctPrivateKey *pKey);
BOOL WINAPI SigRSASHAMD5Sign( PUCHAR pData, DWORD cbData, PUCHAR pSigned, DWORD *pcbSigned, PctPrivateKey *pKey);
BOOL WINAPI SigRSAMD2Verify( PUCHAR pData, DWORD cbData, PUCHAR pSigned, DWORD cbSigned, PctPublicKey *pKey);
BOOL WINAPI SigRSAMD5Verify( PUCHAR pData, DWORD cbData, PUCHAR pSigned, DWORD cbSigned, PctPublicKey *pKey);
BOOL WINAPI SigRSASHAMD5Verify( PUCHAR pData, DWORD cbData, PUCHAR pSigned, DWORD cbSigned, PctPublicKey *pKey);
#define ADVAPI32_PATH TEXT("advapi32.dll")
#define CRYPT_CREATE_HASH_NAME TEXT("CryptCreateHash")
#define CRYPT_HASH_DATA_NAME TEXT("CryptHashData")
#define CRYPT_SIGN_HASH_NAMEA TEXT("CryptSignHashA")
#define CRYPT_SIGN_HASH_NAMEW TEXT("CryptSignHashW")
#define CRYPT_DESTROY_HASH_NAME TEXT("CryptDestroyHash")
#define CRYPT_SET_HASH_PARAM_NAME TEXT("CryptSetHashParam")
typedef BOOL ( WINAPI * CRYPT_CREATE_HASH_FN)( HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash);
typedef BOOL ( WINAPI * CRYPT_HASH_DATA_FN)( HCRYPTHASH hHash, CONST BYTE *pbData, DWORD dwDataLen, DWORD dwFlags);
typedef BOOL ( WINAPI * CRYPT_DESTROY_HASH_FN) ( HCRYPTHASH hHash);
typedef BOOL ( WINAPI * CRYPT_SIGN_HASH_FNA)( HCRYPTHASH hHash, DWORD dwKeySpec, LPCSTR sDescription, DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen);
typedef BOOL ( WINAPI * CRYPT_SIGN_HASH_FNW)( HCRYPTHASH hHash, DWORD dwKeySpec, LPCWSTR sDescription, DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen);
typedef BOOL ( WINAPI * CRYPT_SET_HASH_PARAM_FN)( HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD dwFlags);
HINSTANCE g_hAdvapi32 = NULL; CRYPT_CREATE_HASH_FN g_CryptCreateHash = NULL; CRYPT_HASH_DATA_FN g_CryptHashData = NULL; CRYPT_DESTROY_HASH_FN g_CryptDestroyHash = NULL; CRYPT_SIGN_HASH_FNA g_CryptSignHashA = NULL; CRYPT_SIGN_HASH_FNW g_CryptSignHashW = NULL; CRYPT_SET_HASH_PARAM_FN g_CryptSetHashParam = NULL;
SignatureSystem sigRSAMD2 = { SP_SIG_RSA_MD2, SigRSAMD2Sign, SigRSAMD2Verify}; SignatureSystem sigRSAMD5 = { SP_SIG_RSA_MD5, SigRSAMD5Sign, SigRSAMD5Verify}; SignatureSystem sigRSASHAMD5 = { SP_SIG_RSA_SHAMD5, SigRSASHAMD5Sign, SigRSASHAMD5Verify};
BOOL WINAPI capiCryptCreateHash( HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash) { if(!g_hAdvapi32) { g_hAdvapi32 = LoadLibrary(ADVAPI32_PATH); if(!g_hAdvapi32) { return FALSE; } }
if(!g_CryptCreateHash) { g_CryptCreateHash = (CRYPT_CREATE_HASH_FN)GetProcAddress(g_hAdvapi32, CRYPT_CREATE_HASH_NAME); if(!g_CryptCreateHash) { return FALSE; } } return g_CryptCreateHash(hProv, Algid, hKey, dwFlags, phHash); }
BOOL WINAPI capiCryptHashData( HCRYPTHASH hHash, CONST BYTE *pbData, DWORD dwDataLen, DWORD dwFlags) { if(!g_hAdvapi32) { g_hAdvapi32 = LoadLibrary(ADVAPI32_PATH); if(!g_hAdvapi32) { return FALSE; } }
if(!g_CryptHashData) { g_CryptHashData = (CRYPT_HASH_DATA_FN)GetProcAddress(g_hAdvapi32, CRYPT_HASH_DATA_NAME); if(!g_CryptHashData) { return FALSE; } } return g_CryptHashData(hHash, pbData, dwDataLen, dwFlags); }
BOOL WINAPI capiCryptDestroyHash( HCRYPTHASH hHash) { if(!g_hAdvapi32) { g_hAdvapi32 = LoadLibrary(ADVAPI32_PATH); if(!g_hAdvapi32) { return FALSE; } }
if(!g_CryptDestroyHash) { g_CryptDestroyHash = (CRYPT_DESTROY_HASH_FN)GetProcAddress(g_hAdvapi32, CRYPT_DESTROY_HASH_NAME); if(!g_CryptDestroyHash) { return FALSE; } } return g_CryptDestroyHash(hHash); }
BOOL WINAPI capiCryptSignHashA( HCRYPTHASH hHash, DWORD dwKeySpec, LPCSTR sDescription, DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen) { if(!g_hAdvapi32) { g_hAdvapi32 = LoadLibrary(ADVAPI32_PATH); if(!g_hAdvapi32) { return FALSE; } }
if(!g_CryptSignHashA) { g_CryptSignHashA = (CRYPT_SIGN_HASH_FNA)GetProcAddress(g_hAdvapi32, CRYPT_SIGN_HASH_NAMEA); if(!g_CryptSignHashA) { return FALSE; } } return g_CryptSignHashA(hHash, dwKeySpec, sDescription, dwFlags, pbSignature, pdwSigLen); }
BOOL WINAPI capiCryptSignHashW( HCRYPTHASH hHash, DWORD dwKeySpec, LPCWSTR sDescription, DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen) { if(!g_hAdvapi32) { g_hAdvapi32 = LoadLibrary(ADVAPI32_PATH); if(!g_hAdvapi32) { return FALSE; } }
if(!g_CryptSignHashW) { g_CryptSignHashW = (CRYPT_SIGN_HASH_FNW)GetProcAddress(g_hAdvapi32, CRYPT_SIGN_HASH_NAMEW); if(!g_CryptSignHashW) { return FALSE; } } return g_CryptSignHashW(hHash, dwKeySpec, sDescription, dwFlags, pbSignature, pdwSigLen); }
BOOL WINAPI capiCryptSetHashParam( HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD dwFlags) { if(!g_hAdvapi32) { g_hAdvapi32 = LoadLibrary(ADVAPI32_PATH); if(!g_hAdvapi32) { return FALSE; } }
if(!g_CryptSetHashParam) { g_CryptSetHashParam = (CRYPT_SET_HASH_PARAM_FN)GetProcAddress(g_hAdvapi32, CRYPT_SET_HASH_PARAM_NAME); if(!g_CryptSetHashParam) { return FALSE; } } return g_CryptSetHashParam(hHash, dwParam, pbData, dwFlags); }
#ifdef UNICODE
#define capiCryptSignHash capiCryptSignHashW
#else
#define capiCryptSignHash capiCryptSignHashA
#endif // !UNICODE
BOOL WINAPI SigRSAMD5Sign( PUCHAR pData, DWORD cbData, PUCHAR pSigned, DWORD *pcbSigned, PctPrivateKey *pKey) { MD5_CTX DigCtx; BSAFE_PRV_KEY *pk = (BSAFE_PRV_KEY *)pKey->pKey; UCHAR LocalBuffer[300]; UCHAR LocalOutput[300];
unsigned int cbSize;
if(pk->magic != RSA2 && pKey->cbKey == sizeof(HCRYPTPROV)) { // This isn't a bsafe key, and it's the right size, so it must be a
// CAPI key. This a heuristic.
HCRYPTHASH hHash; DWORD cbSigned; HCRYPTPROV hProv = *((HCRYPTPROV *)pKey->pKey);
if(!capiCryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) { return FALSE; } if(!capiCryptHashData(hHash, pData, cbData, 0)) { capiCryptDestroyHash(hHash); return FALSE; } cbSigned = sizeof(LocalOutput); if(!capiCryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, LocalOutput, &cbSigned)) { capiCryptDestroyHash(hHash); return FALSE; } capiCryptDestroyHash(hHash); ReverseMemCopy(pSigned, LocalOutput, cbSigned); *pcbSigned = cbSigned; return TRUE; } else if(pk->magic != RSA2) { // This isn't a bsafe key or a CAPI key, so it must be a WinSock 2
// LSP key.
SSLSIGNATUREFUNC pSignHook; LPVOID pSignArg;
/* Generate the checksum */ MD5Init(&DigCtx); MD5Update(&DigCtx, pData, cbData); MD5Final(&DigCtx);
// Get the prelude data and the hash value.
CopyMemory(LocalBuffer, MD5_PRELUDE, sizeof(MD5_PRELUDE)); CopyMemory(LocalBuffer + sizeof(MD5_PRELUDE), DigCtx.digest, MD5DIGESTLEN); // Get pointer to callback function.
pSignHook = ((PSCH_CRED_SECRET_WINSOCK2)pKey->pKey)->pSignatureHookFunc; pSignArg = ((PSCH_CRED_SECRET_WINSOCK2)pKey->pKey)->pSignatureHookArg;
// Invoke the callback function.
if(pSignHook) { if(pSignHook(SSL_SIGN_RSA, pSignArg, LocalBuffer, sizeof(MD5_PRELUDE) + MD5DIGESTLEN, 0, pSigned, pcbSigned) != SSL_ERR_OKAY) { return FALSE; } } else { DebugLog((DEB_ERROR, "Null signature callback function!\n")); }
// Return success.
return TRUE; }
cbSize = sizeof(MD5_PRELUDE)+16; if(pk->datalen > sizeof(LocalBuffer)) { return FALSE; }
/* Generate the checksum */ MD5Init(&DigCtx); MD5Update(&DigCtx, pData, cbData); MD5Final(&DigCtx);
FillMemory(LocalBuffer, pk->keylen, 0);
ReverseMemCopy(LocalBuffer, DigCtx.digest, 16); ReverseMemCopy(LocalBuffer+16, MD5_PRELUDE, sizeof(MD5_PRELUDE)); LocalBuffer[cbSize++]=0; while(cbSize < pk->datalen-1) { LocalBuffer[cbSize++] = 0xff; }
/* Make into pkcs block type 1 */ LocalBuffer[pk->datalen-1] = 1;
*pcbSigned = pk->datalen+1;
if(!BSafeDecPrivate(pk, LocalBuffer, LocalOutput)) { return FALSE; } ReverseMemCopy(pSigned, LocalOutput, *pcbSigned); return TRUE; }
BOOL WINAPI SigRSAMD2Sign( PUCHAR pData, DWORD cbData, PUCHAR pSigned, DWORD *pcbSigned, PctPrivateKey *pKey) { MD2_CTX DigCtx; BSAFE_PRV_KEY *pk = (BSAFE_PRV_KEY *)pKey->pKey; UCHAR LocalBuffer[500]; UCHAR LocalOutput[500];
unsigned int cbSize; if(pk->magic != RSA2) { // This is not a bsafe key, so it must be a CAPI
// key.
HCRYPTHASH hHash; DWORD cbSigned; HCRYPTPROV hProv = *((HCRYPTPROV *)pKey->pKey);
if(!capiCryptCreateHash(hProv, CALG_MD2, 0, 0, &hHash)) { return FALSE; } if(!capiCryptHashData(hHash, pData, cbData, 0)) { capiCryptDestroyHash(hHash); return FALSE; } cbSigned = sizeof(LocalOutput); if(!capiCryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, LocalOutput, &cbSigned)) { capiCryptDestroyHash(hHash); return FALSE; } capiCryptDestroyHash(hHash); ReverseMemCopy(pSigned, LocalOutput, cbSigned); *pcbSigned = cbSigned; return TRUE; }
cbSize = sizeof(MD2_PRELUDE)+16; if(pk->datalen > sizeof(LocalBuffer)) { return FALSE; }
//MD2Init(&DigCtx);
FillMemory( &DigCtx, sizeof( DigCtx ), 0 );
MD2Update(&DigCtx, pData, cbData); MD2Final(&DigCtx); FillMemory(LocalBuffer, pk->keylen, 0); ReverseMemCopy(LocalBuffer, DigCtx.state, 16); ReverseMemCopy(LocalBuffer+16, MD2_PRELUDE, sizeof(MD2_PRELUDE)); LocalBuffer[cbSize++]=0; while(cbSize < pk->datalen-1) { LocalBuffer[cbSize++] = 0xff; }
/* Make into pkcs block type 1 */ LocalBuffer[pk->datalen-1] = 1;
*pcbSigned = pk->datalen+1;
if(!BSafeDecPrivate(pk, LocalBuffer, LocalOutput)) { return FALSE; } ReverseMemCopy(pSigned, LocalOutput, *pcbSigned); return TRUE; }
BOOL WINAPI SigRSAMD5Verify( PUCHAR pData, DWORD cbData, PUCHAR pSigned, DWORD cbSigned, PctPublicKey *pKey) { MD5_CTX DigCtx; BSAFE_PUB_KEY *pk = (BSAFE_PUB_KEY *)pKey->pKey; UCHAR Buffer[500]; UCHAR SigBuffer[500]; DWORD iLoc;
if(pk->datalen > sizeof(Buffer) || cbSigned != pk->datalen+1) { return FALSE; }
MD5Init(&DigCtx); MD5Update(&DigCtx, pData, cbData); MD5Final(&DigCtx);
FillMemory(SigBuffer, pk->keylen, 0); FillMemory(Buffer, pk->keylen, 0);
ReverseMemCopy(SigBuffer, pSigned, cbSigned);
if(!BSafeEncPublic(pk, SigBuffer, Buffer)) { return FALSE; }
ReverseMemCopy(SigBuffer, Buffer, cbSigned);
/* Make sure pkcs block type 1 */ if(SigBuffer[0] != 0 || SigBuffer[1] != 1) { return FALSE; }
for(iLoc = 2; iLoc < pk->datalen; iLoc++ ){ if(!SigBuffer[iLoc]) { break; } if(SigBuffer[iLoc] != 0xff) { return FALSE; } }
if(iLoc == pk->datalen) return FALSE;
iLoc++; /* skip past separator */
if(memcmp(&SigBuffer[iLoc], MD5_PRELUDE, sizeof(MD5_PRELUDE)) != 0) { return FALSE; }
iLoc += sizeof(MD5_PRELUDE); if(memcmp(&SigBuffer[iLoc], DigCtx.digest, 16) != 0) { return FALSE; }
return TRUE; }
BOOL WINAPI SigRSAMD2Verify( PUCHAR pData, DWORD cbData, PUCHAR pSigned, DWORD cbSigned, PctPublicKey *pKey) { MD2_CTX DigCtx; BSAFE_PUB_KEY *pk = (BSAFE_PUB_KEY *)pKey->pKey; UCHAR Buffer[500]; UCHAR SigBuffer[500]; DWORD iLoc;
if ((pk->datalen > sizeof(Buffer)) || (cbSigned != pk->datalen + 1)) { return FALSE; }
// MD2Init(&DigCtx);
FillMemory( &DigCtx, sizeof( DigCtx ), 0 );
MD2Update(&DigCtx, pData, cbData);
MD2Final(&DigCtx);
FillMemory(SigBuffer, pk->keylen, 0); FillMemory(Buffer, pk->keylen, 0);
ReverseMemCopy(SigBuffer, pSigned, cbSigned);
if(!BSafeEncPublic(pk, SigBuffer, Buffer)) { return FALSE; }
ReverseMemCopy(SigBuffer, Buffer, cbSigned);
/* Make sure pkcs block type 1 */ if(SigBuffer[0] != 0 || SigBuffer[1] != 1) { return FALSE; }
for(iLoc = 2; iLoc < pk->datalen; iLoc++ ) { if(!SigBuffer[iLoc]) { break; }
if(SigBuffer[iLoc] != 0xff) { return FALSE; } }
if(iLoc == pk->datalen) { return FALSE; }
iLoc++; /* skip past separator */
if(memcmp(&SigBuffer[iLoc], MD2_PRELUDE, sizeof(MD2_PRELUDE)) != 0) { return FALSE; } iLoc += sizeof(MD2_PRELUDE); if(memcmp(&SigBuffer[iLoc], DigCtx.state, 16) != 0) { return FALSE; }
return TRUE; }
BOOL WINAPI SigRSASHAMD5Sign( PUCHAR pData, // pointer to hash value
DWORD cbData, // always 36
PUCHAR pSigned, DWORD *pcbSigned, PctPrivateKey *pKey) { BSAFE_PRV_KEY *pk = (BSAFE_PRV_KEY *)pKey->pKey;
if(pk->magic == RSA2) { // BSAFE key
UCHAR LocalBuffer[500]; UCHAR LocalOutput[500];
pk = (BSAFE_PRV_KEY *)pKey; if(pk->keylen > sizeof(LocalBuffer)) { return FALSE; }
FillMemory(LocalBuffer, pk->keylen, 0); ReverseMemCopy(LocalBuffer, pData, cbData);
LocalBuffer[cbData++] = 0;
while(cbData < pk->datalen-1) { LocalBuffer[cbData++] = 0xff; }
/* Make into pkcs block type 1 */ LocalBuffer[pk->datalen-1] = 1;
*pcbSigned = pk->datalen+1;
BSafeDecPrivate(pk, LocalBuffer, LocalOutput); ReverseMemCopy(pSigned, LocalOutput, *pcbSigned);
return TRUE; } else { // capiCryptoAPI key
HCRYPTPROV hProv; HCRYPTHASH hHash; DWORD dwAlgid; DWORD i; DWORD dwT;
// get handle to CSP
hProv = *((HCRYPTPROV *)pKey->pKey);
// create hash object
dwAlgid = ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5; if(RCRYPT_FAILED(capiCryptCreateHash(hProv, dwAlgid, 0, 0, &hHash))) { return FALSE; }
// set hash value
if(RCRYPT_FAILED(capiCryptSetHashParam(hHash, HP_HASHVAL, pData, 0))) { capiCryptDestroyHash(hHash); return FALSE; }
// sign hash
if(RCRYPT_FAILED(capiCryptSignHash(hHash, AT_KEYEXCHANGE, NULL, 0, pSigned, pcbSigned))) { capiCryptDestroyHash(hHash); return FALSE; }
// free hash object
capiCryptDestroyHash(hHash);
//Convert to Big-endian
dwT = *pcbSigned; for( i = 0 ; i < dwT/2 ; i++) { BYTE bT = pSigned[i]; pSigned[i] = pSigned[dwT-1-i]; pSigned[dwT-1-i] = bT; } return TRUE; } }
BOOL WINAPI SigRSASHAMD5Verify( PUCHAR pData, // pointer to hash value
DWORD cbData, // always 36
PUCHAR pSigned, DWORD cbSigned, PctPublicKey *pKey) { BSAFE_PUB_KEY *pk = (BSAFE_PUB_KEY *)pKey->pKey; UCHAR Buffer[500]; UCHAR SigBuffer[500]; DWORD iLoc;
if(pk->keylen > sizeof(Buffer) || cbSigned != pk->datalen + 1) { return FALSE; }
FillMemory(SigBuffer, pk->keylen, 0); FillMemory(Buffer, pk->keylen, 0);
ReverseMemCopy(SigBuffer, pSigned, cbSigned);
BSafeEncPublic(pk, SigBuffer, Buffer);
ReverseMemCopy(SigBuffer, Buffer, cbSigned);
/* Make sure pkcs block type 1 */ if(SigBuffer[0] != 0 || SigBuffer[1] != 1) return FALSE;
for(iLoc = 2; iLoc < pk->datalen; iLoc++ ){ if(!SigBuffer[iLoc]) break; if(SigBuffer[iLoc] != 0xff) return FALSE; }
if(iLoc == pk->datalen) return FALSE;
iLoc++; /* skip past separator */
if(memcmp(&SigBuffer[iLoc], pData, cbData) != 0) return FALSE;
return TRUE; }
|