windows-nt/Source/XPSP1/NT/ds/win32/ntcrypto/rsaaes/nt_sign.c
2020-09-26 16:20:57 +08:00

911 lines
25 KiB
C

/////////////////////////////////////////////////////////////////////////////
// FILE : nt_sign.c //
// DESCRIPTION : Crypto CP interfaces: //
// CPSignHash //
// CPVerifySignature //
// AUTHOR : //
// HISTORY : //
// Jan 25 1995 larrys Changed from Nametag //
// Feb 23 1995 larrys Changed NTag_SetLastError to SetLastError //
// Mar 23 1995 larrys Added variable key length //
// May 10 1995 larrys added private api calls //
// Aug 03 1995 larrys Fix for bug 10 //
// Aug 22 1995 larrys Added descriptions to sign and verify hash //
// Aug 30 1995 larrys Changed Algid to dwKeySpec //
// Aug 30 1995 larrys Removed RETURNASHVALUE from CryptGetHashValue //
// Aug 31 1995 larrys Fixed CryptSignHash for pbSignature == NULL //
// Aug 31 1995 larrys Fix for Bug 28 //
// Sep 12 1995 Jeffspel/ramas Merged STT onto SCP //
// Sep 12 1995 Jeffspel/ramas BUGS FIXED PKCS#1 Padding. //
// Sep 18 1995 larrys Removed flag fro CryptSignHash //
// Oct 13 1995 larrys Changed GetHashValue to GetHashParam //
// Oct 23 1995 larrys Added MD2 //
// Oct 25 1995 larrys Change length of sDescription string //
// Nov 10 1995 DBarlow Bug #61 //
// Dec 11 1995 larrys Added error return check //
// May 15 1996 larrys Changed NTE_NO_MEMORY to ERROR_NOT_ENOUGHT... //
// May 29 1996 larrys Bug 101 //
// Jun 6 1996 a-johnb Added support for SSL 3.0 signatures //
// May 23 1997 jeffspel Added provider type checking //
// May 5 2000 dbarlow Clean up error return codes //
// //
// Copyright (C) 1993 - 2000, Microsoft Corporation //
// All Rights Reserved //
/////////////////////////////////////////////////////////////////////////////
//#include <wtypes.h>
#include "precomp.h"
#include "ntagum.h"
#include "nt_rsa.h"
#include "protstor.h"
#include "swnt_pk.h"
extern CSP_STRINGS g_Strings;
//
// Reverse ASN.1 Encodings of possible hash identifiers. The leading byte is
// the length of the remaining byte string. The lists of possible identifiers
// is terminated with a '\x00' entry.
//
static const BYTE
#ifdef CSP_USE_MD2
*md2Encodings[]
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
= { (CONST BYTE *)"\x12\x10\x04\x00\x05\x02\x02\x0d\xf7\x86\x48\x86\x2a\x08\x06\x0c\x30\x20\x30",
(CONST BYTE *)"\x10\x10\x04\x02\x02\x0d\xf7\x86\x48\x86\x2a\x08\x06\x0a\x30\x1e\x30",
(CONST BYTE *)"\x00" },
#endif
#ifdef CSP_USE_MD4
*md4Encodings[]
= { (CONST BYTE *)"\x12\x10\x04\x00\x05\x04\x02\x0d\xf7\x86\x48\x86\x2a\x08\x06\x0c\x30\x20\x30",
(CONST BYTE *)"\x10\x10\x04\x04\x02\x0d\xf7\x86\x48\x86\x2a\x08\x06\x0a\x30\x1e\x30",
(CONST BYTE *)"\x00" },
#endif
#ifdef CSP_USE_MD5
*md5Encodings[]
= { (CONST BYTE *)"\x12\x10\x04\x00\x05\x05\x02\x0d\xf7\x86\x48\x86\x2a\x08\x06\x0c\x30\x20\x30",
(CONST BYTE *)"\x10\x10\x04\x05\x02\x0d\xf7\x86\x48\x86\x2a\x08\x06\x0a\x30\x1e\x30",
(CONST BYTE *)"\x00" },
#endif
#ifdef CSP_USE_SHA
*shaEncodings[]
= { (CONST BYTE *)"\x0f\x14\x04\x00\x05\x1a\x02\x03\x0e\x2b\x05\x06\x09\x30\x21\x30",
(CONST BYTE *)"\x0d\x14\x04\x1a\x02\x03\x0e\x2b\x05\x06\x07\x30\x1f\x30",
(CONST BYTE *)"\x00"},
#endif
*endEncodings[]
= { (CONST BYTE *)"\x00" };
/*
- ApplyPKCS1SigningFormat
-
* Purpose:
* Format a buffer with PKCS 1 for signing
*
*/
/*static*/ DWORD
ApplyPKCS1SigningFormat(
IN BSAFE_PUB_KEY *pPubKey,
IN ALG_ID HashAlgid,
IN BYTE *pbHash,
IN DWORD cbHash,
IN DWORD dwFlags,
OUT BYTE *pbPKCS1Format)
{
DWORD dwReturn = ERROR_INTERNAL_ERROR;
BYTE *pbStart;
BYTE *pbEnd;
BYTE bTmp;
DWORD i;
// insert the block type
pbPKCS1Format[pPubKey->datalen - 1] = 0x01;
// insert the type I padding
memset(pbPKCS1Format, 0xff, pPubKey->datalen-1);
// Reverse it
for (i = 0; i < cbHash; i++)
pbPKCS1Format[i] = pbHash[cbHash - (i + 1)];
if ( 0 == (CRYPT_NOHASHOID & dwFlags))
{
switch (HashAlgid)
{
#ifdef CSP_USE_MD2
case CALG_MD2:
// PKCS delimit the hash value
pbEnd = (LPBYTE)md2Encodings[0];
pbStart = pbPKCS1Format + cbHash;
bTmp = *pbEnd++;
while (0 < bTmp--)
*pbStart++ = *pbEnd++;
*pbStart++ = 0;
break;
#endif
#ifdef CSP_USE_MD4
case CALG_MD4:
// PKCS delimit the hash value
pbEnd = (LPBYTE)md4Encodings[0];
pbStart = pbPKCS1Format + cbHash;
bTmp = *pbEnd++;
while (0 < bTmp--)
*pbStart++ = *pbEnd++;
*pbStart++ = 0;
break;
#endif
#ifdef CSP_USE_MD5
case CALG_MD5:
// PKCS delimit the hash value
pbEnd = (LPBYTE)md5Encodings[0];
pbStart = pbPKCS1Format + cbHash;
bTmp = *pbEnd++;
while (0 < bTmp--)
*pbStart++ = *pbEnd++;
*pbStart++ = 0;
break;
#endif
#ifdef CSP_USE_SHA
case CALG_SHA:
// PKCS delimit the hash value
pbEnd = (LPBYTE)shaEncodings[0];
pbStart = pbPKCS1Format + cbHash;
bTmp = *pbEnd++;
while (0 < bTmp--)
*pbStart++ = *pbEnd++;
*pbStart++ = 0;
break;
#endif
#ifdef CSP_USE_SSL3SHAMD5
case CALG_SSL3_SHAMD5:
// Don't put in any PKCS crud
pbStart = pbPKCS1Format + cbHash;
*pbStart++ = 0;
break;
#endif
default:
dwReturn = (DWORD)NTE_BAD_ALGID;
goto ErrorExit;
}
}
else
{
pbPKCS1Format[cbHash] = 0x00;
}
dwReturn = ERROR_SUCCESS;
ErrorExit:
return dwReturn;
}
/*
- ApplyX931SigningFormat
-
* Purpose:
* Format a buffer with X.9.31 for signing, assumes
* the buffer to be formatted is at least the length
* of the signature (cbSig).
*
*/
/*static*/ void
ApplyX931SigningFormat(
IN DWORD cbSig,
IN BYTE *pbHash,
IN DWORD cbHash,
IN BOOL fDataInHash,
OUT BYTE *pbFormatted)
{
DWORD i;
// insert P3
pbFormatted[0] = 0xcc;
pbFormatted[1] = 0x33;
// Reverse it
for (i = 0; i < cbHash; i++)
pbFormatted[i + 2] = pbHash[cbHash - (i + 1)];
pbFormatted[22] = 0xba;
// insert P2
memset(pbFormatted + 23, 0xbb, cbSig - 24);
// insert P1
if (fDataInHash)
pbFormatted[cbSig - 1] = 0x6b;
else
pbFormatted[cbSig - 1] = 0x4b;
}
/*
- CPSignHash
-
* Purpose:
* Create a digital signature from a hash
*
*
* Parameters:
* IN hUID - Handle to the user identifcation
* IN hHash - Handle to hash object
* IN dwKeySpec - Key pair that is used to sign with
* algorithm to be used
* IN sDescription - Description of data to be signed
* IN dwFlags - Flags values
* OUT pbSignture - Pointer to signature data
* OUT dwHashLen - Pointer to the len of the signature data
*
* Returns:
*/
BOOL WINAPI
CPSignHash(
IN HCRYPTPROV hUID,
IN HCRYPTHASH hHash,
IN DWORD dwKeySpec,
IN LPCWSTR sDescription,
IN DWORD dwFlags,
OUT BYTE *pbSignature,
OUT DWORD *pdwSigLen)
{
DWORD dwReturn = ERROR_INTERNAL_ERROR;
PNTAGUserList pTmpUser = NULL;
PNTAGHashList pTmpHash;
BSAFE_PRV_KEY *pPrivKey = NULL;
MD2_object *pMD2Hash;
MD4_object *pMD4Hash;
MD5_object *pMD5Hash;
A_SHA_CTX *pSHAHash;
BYTE rgbTmpHash[SSL3_SHAMD5_LEN];
DWORD cbTmpHash = SSL3_SHAMD5_LEN;
BYTE *pbInput = NULL;
BYTE *pbSigT = NULL;
DWORD cbSigLen;
BOOL fSigKey;
BSAFE_PUB_KEY *pPubKey;
LPWSTR szPrompt;
BOOL fDataInHash = FALSE;
BOOL fRet;
DWORD dwSts;
EntryPoint
if ((dwFlags & ~(CRYPT_NOHASHOID | CRYPT_X931_FORMAT)) != 0)
{
dwReturn = (DWORD)NTE_BAD_FLAGS;
goto ErrorExit;
}
pTmpUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE);
if (NULL == pTmpUser)
{
dwReturn = (DWORD)NTE_BAD_UID;
goto ErrorExit;
}
// get the user's public key
if (dwKeySpec == AT_KEYEXCHANGE)
{
fSigKey = FALSE;
pPubKey = (BSAFE_PUB_KEY *)pTmpUser->ContInfo.pbExchPub;
szPrompt = g_Strings.pwszSignWExch;
}
else if (dwKeySpec == AT_SIGNATURE)
{
if (PROV_RSA_SCHANNEL == pTmpUser->dwProvType)
{
dwReturn = (DWORD)NTE_BAD_ALGID;
goto ErrorExit;
}
fSigKey = TRUE;
pPubKey = (BSAFE_PUB_KEY *)pTmpUser->ContInfo.pbSigPub;
szPrompt = g_Strings.pwszSigning;
}
else
{
dwReturn = (DWORD)NTE_BAD_ALGID;
goto ErrorExit;
}
// check to make sure the key exists
if (NULL == pPubKey)
{
dwReturn = (DWORD)NTE_BAD_KEYSET;
goto ErrorExit;
}
cbSigLen = (pPubKey->bitlen + 7) / 8;
if (pbSignature == NULL || *pdwSigLen < cbSigLen)
{
*pdwSigLen = cbSigLen;
dwReturn = (pbSignature == NULL) ? ERROR_SUCCESS : ERROR_MORE_DATA;
goto ErrorExit;
}
// check to see if the hash is in the hash list
dwSts = NTLValidate(hHash, hUID, HASH_HANDLE, &pTmpHash);
if (ERROR_SUCCESS != dwSts)
{
dwReturn = (dwSts == NTF_FAILED) ? (DWORD)NTE_BAD_HASH : dwSts;
goto ErrorExit;
}
// zero the output buffer
memset (pbSignature, 0, cbSigLen);
switch (pTmpHash->Algid)
{
#ifdef CSP_USE_MD2
case CALG_MD2:
pMD2Hash = (MD2_object *)pTmpHash->pHashData;
break;
#endif
#ifdef CSP_USE_MD4
case CALG_MD4:
pMD4Hash = (MD4_object *)pTmpHash->pHashData;
break;
#endif
#ifdef CSP_USE_MD5
case CALG_MD5:
pMD5Hash = (MD5_object *)pTmpHash->pHashData;
break;
#endif
#ifdef CSP_USE_SHA
case CALG_SHA:
pSHAHash = (A_SHA_CTX *)pTmpHash->pHashData;
break;
#endif
#ifdef CSP_USE_SSL3SHAMD5
case CALG_SSL3_SHAMD5:
// Hash value must have already been set.
if ((pTmpHash->HashFlags & HF_VALUE_SET) == 0)
{
dwReturn = (DWORD)NTE_BAD_HASH_STATE;
goto ErrorExit;
}
break;
#endif
default:
dwReturn = (DWORD)NTE_BAD_ALGID;
goto ErrorExit;
}
// WARNING: due to vulnerabilities sDescription field is should NO longer
// be used
if (sDescription != NULL)
{
if (!CPHashData(hUID, hHash, (LPBYTE) sDescription,
lstrlenW(sDescription) * sizeof(WCHAR), 0))
{
dwReturn = GetLastError(); // NTE_BAD_HASH
goto ErrorExit;
}
}
// check if this is a NULL hash (no data hashed) for X.9.31 format
if (pTmpHash->dwHashState & DATA_IN_HASH)
fDataInHash = TRUE;
// now copy the hash into the input buffer
cbTmpHash = pPubKey->keylen;
if (!CPGetHashParam(hUID, hHash, HP_HASHVAL, rgbTmpHash, &cbTmpHash, 0))
{
dwReturn = GetLastError();
goto ErrorExit;
}
pbInput = (BYTE *)_nt_malloc(pPubKey->keylen);
if (pbInput == NULL)
{
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorExit;
}
if (dwFlags & CRYPT_X931_FORMAT)
{
// use X.9.31 padding for FIPS certification
if (pTmpHash->Algid != CALG_SHA1)
{
dwReturn = (DWORD)NTE_BAD_ALGID;
goto ErrorExit;
}
ApplyX931SigningFormat(cbSigLen,
rgbTmpHash,
cbTmpHash,
fDataInHash,
pbInput);
}
else
{
// use PKCS #1 padding
dwSts = ApplyPKCS1SigningFormat(pPubKey, pTmpHash->Algid, rgbTmpHash,
cbTmpHash, dwFlags, pbInput);
if (ERROR_SUCCESS != dwSts)
{
dwReturn = dwSts;
goto ErrorExit;
}
}
// encrypt the hash value in input
pbSigT = (BYTE *)_nt_malloc(pPubKey->keylen);
if (NULL == pbSigT)
{
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorExit;
}
// load the appropriate key if necessary
dwSts = UnprotectPrivKey(pTmpUser, szPrompt, fSigKey, FALSE);
if (ERROR_SUCCESS != dwSts)
{
dwReturn = dwSts; // NTE_BAD_KEYSET
goto ErrorExit;
}
// get the user's private key
if (fSigKey)
pPrivKey = (BSAFE_PRV_KEY *)pTmpUser->pSigPrivKey;
else
pPrivKey = (BSAFE_PRV_KEY *)pTmpUser->pExchPrivKey;
if (pPrivKey == NULL)
{
dwReturn = (DWORD)NTE_NO_KEY;
goto ErrorExit;
}
if (pPubKey->keylen != pPrivKey->keylen)
{
dwReturn = (DWORD)NTE_KEYSET_ENTRY_BAD;
goto ErrorExit;
}
dwSts = RSAPrivateDecrypt(pTmpUser->pOffloadInfo, pPrivKey, pbInput,
pbSigT);
if (ERROR_SUCCESS != dwSts)
{
dwReturn = dwSts;
goto ErrorExit;
}
memcpy(pbSignature, pbSigT, cbSigLen);
*pdwSigLen = cbSigLen;
dwReturn = ERROR_SUCCESS;
ErrorExit:
fRet = (ERROR_SUCCESS == dwReturn);
if (pbSigT)
_nt_free (pbSigT, pPubKey->keylen);
if (pbInput)
_nt_free(pbInput, pPubKey->keylen);
if (!fRet)
SetLastError(dwReturn);
return fRet;
}
/*
- VerifyPKCS1SigningFormat
-
* Purpose:
* Check the format on a buffer to make sure the PKCS 1
* formatting is correct.
*
*/
/*static*/ DWORD
VerifyPKCS1SigningFormat(
IN BSAFE_PUB_KEY *pKey,
IN PNTAGHashList pTmpHash,
IN BYTE *pbHash,
IN DWORD cbHash,
IN DWORD dwFlags,
OUT BYTE *pbPKCS1Format)
{
DWORD dwReturn = ERROR_INTERNAL_ERROR;
MD2_object *pMD2Hash;
MD4_object *pMD4Hash;
MD5_object *pMD5Hash;
A_SHA_CTX *pSHAHash;
BYTE *pbTmp;
const BYTE **rgEncOptions;
BYTE rgbTmpHash[SSL3_SHAMD5_LEN];
DWORD i;
DWORD cb;
BYTE *pbStart;
DWORD cbTmp;
switch (pTmpHash->Algid)
{
#ifdef CSP_USE_MD2
case CALG_MD2:
pMD2Hash = (MD2_object *)pTmpHash->pHashData;
pbTmp = (BYTE *) &(pMD2Hash->MD);
rgEncOptions = md2Encodings;
break;
#endif
#ifdef CSP_USE_MD4
case CALG_MD4:
pMD4Hash = (MD4_object *)pTmpHash->pHashData;
pbTmp = (BYTE *) &(pMD4Hash->MD);
rgEncOptions = md4Encodings;
break;
#endif
#ifdef CSP_USE_MD5
case CALG_MD5:
pMD5Hash = (MD5_object *)pTmpHash->pHashData;
pbTmp = (BYTE *)pMD5Hash->digest;
rgEncOptions = md5Encodings;
break;
#endif
#ifdef CSP_USE_SHA
case CALG_SHA:
pSHAHash = (A_SHA_CTX *)pTmpHash->pHashData;
pbTmp = (BYTE *)pSHAHash->HashVal;
rgEncOptions = shaEncodings;
break;
#endif
#ifdef CSP_USE_SSL3SHAMD5
case CALG_SSL3_SHAMD5:
// Hash value must have already been set.
if ((pTmpHash->HashFlags & HF_VALUE_SET) == 0)
{
dwReturn = (DWORD)NTE_BAD_HASH;
goto ErrorExit;
}
pbTmp = pTmpHash->pHashData;
rgEncOptions = NULL;
break;
#endif
default:
dwReturn = (DWORD)NTE_BAD_HASH;
goto ErrorExit;
}
// Reverse the hash to match the signature.
for (i = 0; i < cbHash; i++)
rgbTmpHash[i] = pbHash[cbHash - (i + 1)];
// See if it matches.
if (0 != memcmp(rgbTmpHash, pbPKCS1Format, cbHash))
{
dwReturn = (DWORD)NTE_BAD_SIGNATURE;
goto ErrorExit;
}
cb = cbHash;
if (!(CRYPT_NOHASHOID & dwFlags))
{
// Check for any signature type identifiers
if (rgEncOptions != NULL)
{
for (i = 0; 0 != *rgEncOptions[i]; i += 1)
{
pbStart = (LPBYTE)rgEncOptions[i];
cbTmp = *pbStart++;
if (0 == memcmp(&pbPKCS1Format[cb], pbStart, cbTmp))
{
cb += cbTmp; // Adjust the end of the hash data.
break;
}
}
}
}
// check to make sure the rest of the PKCS #1 padding is correct
if ((0x00 != pbPKCS1Format[cb])
|| (0x00 != pbPKCS1Format[pKey->datalen])
|| (0x1 != pbPKCS1Format[pKey->datalen - 1]))
{
dwReturn = (DWORD)NTE_BAD_SIGNATURE;
goto ErrorExit;
}
for (i = cb + 1; i < (DWORD)pKey->datalen - 1; i++)
{
if (0xff != pbPKCS1Format[i])
{
dwReturn = (DWORD)NTE_BAD_SIGNATURE;
goto ErrorExit;
}
}
dwReturn = ERROR_SUCCESS;
ErrorExit:
return dwReturn;
}
/*
- VerifyX931SigningFormat
-
* Purpose:
* Check the format on a buffer to make sure the X.9.31
* formatting is correct.
*
*/
/*static*/ DWORD
VerifyX931SigningFormat(
IN BYTE *pbHash,
IN DWORD cbHash,
IN BOOL fDataInHash,
IN BYTE *pbFormatted,
IN DWORD cbFormatted)
{
DWORD dwReturn = ERROR_INTERNAL_ERROR;
BYTE rgbTmpHash[SSL3_SHAMD5_LEN];
DWORD i;
// check P3
if ((0xcc != pbFormatted[0]) || (0x33 != pbFormatted[1]) ||
(0xba != pbFormatted[cbHash + 2]))
{
dwReturn = (DWORD)NTE_BAD_SIGNATURE;
goto ErrorExit;
}
// Reverse the hash to match the signature and check if it matches.
for (i = 0; i < cbHash; i++)
rgbTmpHash[i] = pbHash[cbHash - (i + 1)];
if (0 != memcmp(rgbTmpHash, pbFormatted + 2, cbHash))
{
dwReturn = (DWORD)NTE_BAD_SIGNATURE;
goto ErrorExit;
}
// check P2
for (i = 23; i < (cbFormatted - 24); i++)
{
if (0xbb != pbFormatted[i])
{
dwReturn = (DWORD)NTE_BAD_SIGNATURE;
goto ErrorExit;
}
}
// check P1
if (fDataInHash)
{
if (0x6b != pbFormatted[cbFormatted - 1])
{
dwReturn = (DWORD)NTE_BAD_SIGNATURE;
goto ErrorExit;
}
}
else
{
if (0x4b != pbFormatted[cbFormatted - 1])
{
dwReturn = (DWORD)NTE_BAD_SIGNATURE;
goto ErrorExit;
}
}
dwReturn = ERROR_SUCCESS;
ErrorExit:
return dwReturn;
}
/*
- CPVerifySignature
-
* Purpose:
* Used to verify a signature against a hash object
*
*
* Parameters:
* IN hUID - Handle to the user identifcation
* IN hHash - Handle to hash object
* IN pbSignture - Pointer to signature data
* IN dwSigLen - Length of the signature data
* IN hPubKey - Handle to the public key for verifying
* the signature
* IN Algid - Algorithm identifier of the signature
* algorithm to be used
* IN sDescription - String describing the signed data
* IN dwFlags - Flags values
*
* Returns:
*/
BOOL WINAPI
CPVerifySignature(
IN HCRYPTPROV hUID,
IN HCRYPTHASH hHash,
IN CONST BYTE *pbSignature,
IN DWORD dwSigLen,
IN HCRYPTKEY hPubKey,
IN LPCWSTR sDescription,
IN DWORD dwFlags)
{
DWORD dwReturn = ERROR_INTERNAL_ERROR;
PNTAGUserList pTmpUser;
PNTAGHashList pTmpHash;
PNTAGKeyList pPubKey;
BSAFE_PUB_KEY *pKey;
BYTE *pOutput = NULL;
BSAFE_PUB_KEY *pBsafePubKey;
BYTE *pbSigT = NULL;
BYTE rgbTmpHash[SSL3_SHAMD5_LEN];
DWORD cbTmpHash = SSL3_SHAMD5_LEN;
DWORD cbLocalSigLen;
BOOL fDataInHash = FALSE;
BOOL fRet;
DWORD dwSts;
EntryPoint
if ((dwFlags & ~(CRYPT_NOHASHOID | CRYPT_X931_FORMAT)) != 0)
{
dwReturn = (DWORD)NTE_BAD_FLAGS;
goto ErrorExit;
}
// check the user identification
pTmpUser = (PNTAGUserList)NTLCheckList(hUID, USER_HANDLE);
if (NULL == pTmpUser)
{
dwReturn = (DWORD)NTE_BAD_UID;
goto ErrorExit;
}
// check to see if the hash is in the hash list
dwSts = NTLValidate(hHash, hUID, HASH_HANDLE, &pTmpHash);
if (ERROR_SUCCESS != dwSts)
{
// NTLValidate doesn't know what error to set
// so it set NTE_FAIL -- fix it up.
dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_HASH : dwSts;
goto ErrorExit;
}
if ((CALG_MD2 != pTmpHash->Algid) &&
(CALG_MD4 != pTmpHash->Algid) &&
(CALG_MD5 != pTmpHash->Algid) &&
(CALG_SHA != pTmpHash->Algid) &&
(CALG_SSL3_SHAMD5 != pTmpHash->Algid))
{
dwReturn = (DWORD)NTE_BAD_HASH;
goto ErrorExit;
}
switch (HNTAG_TO_HTYPE((HNTAG)hPubKey))
{
case SIGPUBKEY_HANDLE:
case EXCHPUBKEY_HANDLE:
dwSts = NTLValidate((HNTAG)hPubKey,
hUID, HNTAG_TO_HTYPE((HNTAG)hPubKey),
&pPubKey);
if (ERROR_SUCCESS != dwSts)
{
// NTLValidate doesn't know what error to set
// so it set NTE_FAIL -- fix it up.
dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts;
goto ErrorExit;
}
break;
default:
dwReturn = (DWORD)NTE_BAD_KEY;
goto ErrorExit;
}
pKey = (BSAFE_PUB_KEY *)pPubKey->pKeyValue;
pBsafePubKey = (BSAFE_PUB_KEY *) pKey;
cbLocalSigLen = (pBsafePubKey->bitlen+7)/8;
if (dwSigLen != cbLocalSigLen)
{
dwReturn = (DWORD)NTE_BAD_SIGNATURE;
goto ErrorExit;
}
pOutput = (BYTE *)_nt_malloc(pBsafePubKey->keylen);
if (NULL == pOutput)
{
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorExit;
}
// encrypt the hash value in output
pbSigT = (BYTE *)_nt_malloc(pBsafePubKey->keylen);
if (NULL == pbSigT)
{
dwReturn = ERROR_NOT_ENOUGH_MEMORY;
goto ErrorExit;
}
memset(pbSigT, 0, pBsafePubKey->keylen);
memcpy(pbSigT, pbSignature, cbLocalSigLen);
dwSts = RSAPublicEncrypt(pTmpUser->pOffloadInfo, pBsafePubKey,
pbSigT, pOutput);
if (ERROR_SUCCESS != dwSts)
{
dwReturn = dwSts; // NTE_BAD_SIGNATURE
goto ErrorExit;
}
// WARNING: due to vulnerabilities sDescription field is should NO longer
// be used
if (sDescription != NULL)
{
if (!CPHashData(hUID, hHash, (LPBYTE) sDescription,
lstrlenW(sDescription) * sizeof(WCHAR), 0))
{
dwReturn = GetLastError();
goto ErrorExit;
}
}
// check if this is a NULL hash (no data hashed) for X.9.31 format
if (pTmpHash->dwHashState & DATA_IN_HASH)
fDataInHash = TRUE;
if (!CPGetHashParam(hUID, hHash, HP_HASHVAL, rgbTmpHash, &cbTmpHash, 0))
{
dwReturn = GetLastError();
goto ErrorExit;
}
if (dwFlags & CRYPT_X931_FORMAT)
{
// use X.9.31 padding for FIPS certification
dwSts = VerifyX931SigningFormat(rgbTmpHash, cbTmpHash,
fDataInHash, pOutput,
(pBsafePubKey->bitlen + 7) / 8);
if (ERROR_SUCCESS != dwSts)
{
dwReturn = dwSts;
goto ErrorExit;
}
}
else
{
// use PKCS #1 padding
dwSts = VerifyPKCS1SigningFormat(pKey, pTmpHash, rgbTmpHash,
cbTmpHash, dwFlags, pOutput);
if (ERROR_SUCCESS != dwSts)
{
dwReturn = dwSts;
goto ErrorExit;
}
}
dwReturn = ERROR_SUCCESS;
ErrorExit:
fRet = (ERROR_SUCCESS == dwReturn);
if (pbSigT)
_nt_free(pbSigT, pBsafePubKey->keylen);
if (pOutput)
_nt_free(pOutput, pBsafePubKey->keylen);
if (!fRet)
SetLastError(dwReturn);
return fRet;
}