///////////////////////////////////////////////////////////////////////////// // 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 #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; }