390 lines
7.9 KiB
C
390 lines
7.9 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1994-1998 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
clicert.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Contains code related to the tshare certificate validation and data
|
||
|
encryption using server public key.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Madan Appiah (madana) 24-Jan-1998
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
User Mode - Win32
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include <seccom.h>
|
||
|
BOOL
|
||
|
UnpackServerCert(
|
||
|
LPBYTE pbCert,
|
||
|
DWORD dwCertLen,
|
||
|
PHydra_Server_Cert pServerCert
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function unpacks the blob of server certicate to server certificate
|
||
|
structure.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pbCert - pointer to the server public key blob.
|
||
|
|
||
|
dwCertLen - length of the above server public key.
|
||
|
|
||
|
pServerCert - pointer to a server certificate structure.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - if successfully unpacked.
|
||
|
FALSE - otherwise.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
LPBYTE pbScan;
|
||
|
DWORD cbScan;
|
||
|
//
|
||
|
// return if the pointer are invalid.
|
||
|
// return if the certificate is insufficient length.
|
||
|
//
|
||
|
|
||
|
if( (pbCert == NULL) ||
|
||
|
(dwCertLen < (3 * sizeof(DWORD) + 4 * sizeof(WORD))) ||
|
||
|
(pServerCert == NULL) ) {
|
||
|
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
pbScan = pbCert;
|
||
|
cbScan = dwCertLen;
|
||
|
//
|
||
|
// Assign dwVersion
|
||
|
//
|
||
|
|
||
|
pServerCert->dwVersion = *(DWORD UNALIGNED FAR *)pbScan;
|
||
|
pbScan += sizeof(DWORD);
|
||
|
cbScan -= sizeof(DWORD);
|
||
|
//
|
||
|
// Assign dwSigAlgID
|
||
|
//
|
||
|
|
||
|
pServerCert->dwSigAlgID = *(DWORD UNALIGNED FAR *)pbScan;
|
||
|
pbScan += sizeof(DWORD);
|
||
|
cbScan -= sizeof(DWORD);
|
||
|
//
|
||
|
// Assign dwSignID
|
||
|
//
|
||
|
|
||
|
pServerCert->dwKeyAlgID = *(DWORD UNALIGNED FAR *)pbScan;
|
||
|
pbScan += sizeof(DWORD);
|
||
|
cbScan -= sizeof(DWORD);
|
||
|
//
|
||
|
//Assign PublicKeyData
|
||
|
//
|
||
|
|
||
|
pServerCert->PublicKeyData.wBlobType = *(WORD UNALIGNED FAR *)pbScan;
|
||
|
pbScan += sizeof(WORD);
|
||
|
cbScan -= sizeof(WORD);
|
||
|
|
||
|
if( pServerCert->PublicKeyData.wBlobType != BB_RSA_KEY_BLOB ) {
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
pServerCert->PublicKeyData.wBlobLen = *(WORD UNALIGNED FAR *)pbScan;
|
||
|
pbScan += sizeof(WORD);
|
||
|
cbScan -= sizeof(WORD);
|
||
|
|
||
|
if( pServerCert->PublicKeyData.wBlobLen > 0 ) {
|
||
|
|
||
|
if(cbScan < pServerCert->PublicKeyData.wBlobLen) {
|
||
|
return ( FALSE );
|
||
|
}
|
||
|
pServerCert->PublicKeyData.pBlob = pbScan;
|
||
|
pbScan += pServerCert->PublicKeyData.wBlobLen;
|
||
|
cbScan -= pServerCert->PublicKeyData.wBlobLen;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
pServerCert->PublicKeyData.pBlob = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Assign SignatureBlob
|
||
|
//
|
||
|
|
||
|
if(cbScan < sizeof(WORD)) {
|
||
|
return ( FALSE );
|
||
|
}
|
||
|
pServerCert->SignatureBlob.wBlobType = *(WORD UNALIGNED *)pbScan;
|
||
|
pbScan += sizeof(WORD);
|
||
|
cbScan -= sizeof(WORD);
|
||
|
|
||
|
if( pServerCert->SignatureBlob.wBlobType != BB_RSA_SIGNATURE_BLOB ) {
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
if(cbScan < sizeof(WORD)) {
|
||
|
return ( FALSE );
|
||
|
}
|
||
|
pServerCert->SignatureBlob.wBlobLen = *(WORD UNALIGNED FAR *)pbScan;
|
||
|
pbScan += sizeof(WORD);
|
||
|
cbScan -= sizeof(WORD);
|
||
|
|
||
|
if( pServerCert->SignatureBlob.wBlobLen > 0 ) {
|
||
|
|
||
|
if(cbScan < pServerCert->SignatureBlob.wBlobLen) {
|
||
|
return ( FALSE );
|
||
|
}
|
||
|
pServerCert->SignatureBlob.pBlob = pbScan;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
pServerCert->SignatureBlob.pBlob = NULL;
|
||
|
}
|
||
|
|
||
|
return( TRUE );
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ValidateServerCert(
|
||
|
PHydra_Server_Cert pServerCert
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This function validate the server public key.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pSserverCert - pointer to a server certificate.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - if the server public key is valid.
|
||
|
FALSE - otherwise.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
DWORD dwLen;
|
||
|
LPBYTE pbSignature;
|
||
|
MD5_CTX HashState;
|
||
|
BYTE SignHash[0x48];
|
||
|
LPBYTE pbScan;
|
||
|
|
||
|
//
|
||
|
// pack the certificate data into a byte blob excluding the signature info.
|
||
|
//
|
||
|
|
||
|
dwLen =
|
||
|
3 * sizeof(DWORD) +
|
||
|
2 * sizeof(WORD) +
|
||
|
pServerCert->PublicKeyData.wBlobLen;
|
||
|
|
||
|
//
|
||
|
// allocated space for the binary blob.
|
||
|
//
|
||
|
|
||
|
pbSignature = malloc( (UINT)dwLen );
|
||
|
|
||
|
if( pbSignature == NULL ) {
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
pbScan = pbSignature;
|
||
|
|
||
|
memcpy( pbScan, &pServerCert->dwVersion, sizeof(DWORD));
|
||
|
pbScan += sizeof(DWORD);
|
||
|
|
||
|
memcpy( pbScan, &pServerCert->dwSigAlgID, sizeof(DWORD));
|
||
|
pbScan += sizeof(DWORD);
|
||
|
|
||
|
memcpy( pbScan, &pServerCert->dwKeyAlgID, sizeof(DWORD));
|
||
|
pbScan += sizeof(DWORD);
|
||
|
|
||
|
memcpy( pbScan, &pServerCert->PublicKeyData.wBlobType, sizeof(WORD));
|
||
|
pbScan += sizeof(WORD);
|
||
|
|
||
|
memcpy( pbScan, &pServerCert->PublicKeyData.wBlobLen, sizeof(WORD));
|
||
|
pbScan += sizeof(WORD);
|
||
|
|
||
|
memcpy(
|
||
|
pbScan,
|
||
|
pServerCert->PublicKeyData.pBlob,
|
||
|
pServerCert->PublicKeyData.wBlobLen);
|
||
|
|
||
|
//
|
||
|
// generate the hash on the data.
|
||
|
//
|
||
|
|
||
|
MD5Init( &HashState );
|
||
|
MD5Update( &HashState, pbSignature, dwLen );
|
||
|
MD5Final( &HashState );
|
||
|
|
||
|
//
|
||
|
// free the signature blob, we don't need it anymore.
|
||
|
//
|
||
|
|
||
|
free( pbSignature );
|
||
|
|
||
|
//
|
||
|
// initialize the pulic key.
|
||
|
//
|
||
|
|
||
|
g_pPublicKey = (LPBSAFE_PUB_KEY)g_abPublicKeyModulus;
|
||
|
|
||
|
g_pPublicKey->magic = RSA1;
|
||
|
g_pPublicKey->keylen = 0x48;
|
||
|
g_pPublicKey->bitlen = 0x0200;
|
||
|
g_pPublicKey->datalen = 0x3f;
|
||
|
g_pPublicKey->pubexp = 0xc0887b5b;
|
||
|
|
||
|
//
|
||
|
// decrypt the signature.
|
||
|
//
|
||
|
|
||
|
memset(SignHash, 0x00, 0x48);
|
||
|
BSafeEncPublic( g_pPublicKey, pServerCert->SignatureBlob.pBlob, SignHash);
|
||
|
|
||
|
//
|
||
|
// compare the hash value.
|
||
|
//
|
||
|
|
||
|
if( memcmp( SignHash, HashState.digest, 16 )) {
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// successfully validated the signature.
|
||
|
//
|
||
|
|
||
|
return( TRUE );
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
EncryptClientRandom(
|
||
|
LPBYTE pbSrvPublicKey,
|
||
|
DWORD dwSrvPublicKey,
|
||
|
LPBYTE pbRandomKey,
|
||
|
DWORD dwRandomKeyLen,
|
||
|
LPBYTE pbEncRandomKey,
|
||
|
LPDWORD pdwEncRandomKey
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Encrypt the client random using server's public key.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pbSrvPublicKey - pointer to the server public key.
|
||
|
|
||
|
dwSrvPublicKey - length of the server public key.
|
||
|
|
||
|
pbRandomKey - pointer to a buffer where the client random key.
|
||
|
|
||
|
dwRandomKeyLen - length of the random key passed in.
|
||
|
|
||
|
pbEncRandomKey - pointer to a buffer where the encrypted client random is
|
||
|
returned.
|
||
|
|
||
|
pdwEncRandomKey - pointer to a place where the length of the above buffer is
|
||
|
passed in and length of the buffer used/required is returned.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE - if the key is encrypted successfully.
|
||
|
FALSE - otherwise.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
LPBSAFE_PUB_KEY pSrvPublicKey;
|
||
|
BYTE abInputBuffer[512];
|
||
|
|
||
|
ASSERT( pbSrvPublicKey != NULL );
|
||
|
pSrvPublicKey = (LPBSAFE_PUB_KEY)pbSrvPublicKey;
|
||
|
|
||
|
//
|
||
|
// check to see buffer length pointer is valid.
|
||
|
//
|
||
|
|
||
|
if( pdwEncRandomKey == NULL ) {
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// check to see a output buffer is specified and
|
||
|
// the encrypt buffer length is sufficient.
|
||
|
//
|
||
|
|
||
|
if( (pbEncRandomKey == NULL) ||
|
||
|
(*pdwEncRandomKey < pSrvPublicKey->keylen) ) {
|
||
|
|
||
|
*pdwEncRandomKey = pSrvPublicKey->keylen;
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// make sure the random key data and its length are valid.
|
||
|
//
|
||
|
|
||
|
ASSERT( pbRandomKey != NULL );
|
||
|
ASSERT( dwRandomKeyLen <= pSrvPublicKey->datalen );
|
||
|
ASSERT( pSrvPublicKey->datalen < pSrvPublicKey->keylen );
|
||
|
ASSERT( pSrvPublicKey->keylen <= sizeof(abInputBuffer) );
|
||
|
|
||
|
//
|
||
|
// init the input buffer.
|
||
|
//
|
||
|
|
||
|
memset( abInputBuffer, 0x0, (UINT)pSrvPublicKey->keylen );
|
||
|
|
||
|
//
|
||
|
// copy data to be encrypted in the input buffer.
|
||
|
//
|
||
|
|
||
|
memcpy( abInputBuffer, pbRandomKey, (UINT)dwRandomKeyLen );
|
||
|
|
||
|
//
|
||
|
// initialize the output buffer.
|
||
|
//
|
||
|
|
||
|
memset( pbEncRandomKey, 0x0, (UINT)pSrvPublicKey->keylen );
|
||
|
|
||
|
//
|
||
|
// encrypt data now.
|
||
|
//
|
||
|
|
||
|
if( !BSafeEncPublic(
|
||
|
pSrvPublicKey,
|
||
|
(LPBYTE)abInputBuffer,
|
||
|
pbEncRandomKey ) ) {
|
||
|
|
||
|
*pdwEncRandomKey = 0;
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// successfully encrypted the client random,
|
||
|
// return the encrypted data length.
|
||
|
//
|
||
|
|
||
|
*pdwEncRandomKey = pSrvPublicKey->keylen;
|
||
|
return( TRUE );
|
||
|
}
|
||
|
|