/*++ 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 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 ); }