windows-nt/Source/XPSP1/NT/ds/security/protocols/schannel/spbase/sigsys.c
2020-09-26 16:20:57 +08:00

264 lines
6.5 KiB
C

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: sigsys.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 09-23-97 jbanes LSA integration stuff.
//
//----------------------------------------------------------------------------
#include <spbase.h>
#include <wincrypt.h>
#include <ssl2msg.h>
#include <ssl3msg.h>
SP_STATUS
SPVerifySignature(
HCRYPTPROV hProv,
DWORD dwCapiFlags,
PPUBLICKEY pPublic,
ALG_ID aiHash,
PBYTE pbData,
DWORD cbData,
PBYTE pbSig,
DWORD cbSig,
BOOL fHashData)
{
HCRYPTKEY hPublicKey = 0;
HCRYPTHASH hHash = 0;
PBYTE pbSigBuff = NULL;
SP_STATUS pctRet;
if(hProv == 0 || pPublic == NULL)
{
pctRet = SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
goto cleanup;
}
pbSigBuff = SPExternalAlloc(cbSig);
if(pbSigBuff == NULL)
{
pctRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY);
goto cleanup;
}
//
// Create public key.
//
if(!SchCryptImportKey(hProv,
(PBYTE)pPublic->pPublic,
pPublic->cbPublic,
0, 0,
&hPublicKey,
dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_ERR_ILLEGAL_MESSAGE;
goto cleanup;
}
//
// Hash data.
//
if(!SchCryptCreateHash(hProv, aiHash, 0, 0, &hHash, dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_ERR_ILLEGAL_MESSAGE;
goto cleanup;
}
if(!fHashData)
{
// set hash value
if(!SchCryptSetHashParam(hHash, HP_HASHVAL, pbData, 0, dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_ERR_ILLEGAL_MESSAGE;
goto cleanup;
}
}
else
{
if(!SchCryptHashData(hHash, pbData, cbData, 0, dwCapiFlags))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_ERR_ILLEGAL_MESSAGE;
goto cleanup;
}
}
if(pPublic->pPublic->aiKeyAlg == CALG_DSS_SIGN)
{
BYTE rgbTempSig[DSA_SIGNATURE_SIZE];
DWORD cbTempSig;
// Remove DSS ASN1 goo around signature and convert it to
// little endian.
cbTempSig = sizeof(rgbTempSig);
if(!CryptDecodeObject(X509_ASN_ENCODING,
X509_DSS_SIGNATURE,
pbSig,
cbSig,
0,
rgbTempSig,
&cbTempSig))
{
SP_LOG_RESULT(GetLastError());
pctRet = PCT_ERR_ILLEGAL_MESSAGE;
goto cleanup;
}
memcpy(pbSigBuff, rgbTempSig, cbTempSig);
cbSig = cbTempSig;
}
else
{
// Convert signature to little endian.
ReverseMemCopy(pbSigBuff, pbSig, cbSig);
}
if(!SchCryptVerifySignature(hHash,
pbSigBuff,
cbSig,
hPublicKey,
NULL, 0,
dwCapiFlags))
{
DebugLog((DEB_WARN, "Signature Verify Failed: %x\n", GetLastError()));
pctRet = SP_LOG_RESULT(PCT_INT_MSG_ALTERED);
goto cleanup;
}
pctRet = PCT_ERR_OK;
cleanup:
if(hPublicKey)
{
SchCryptDestroyKey(hPublicKey, dwCapiFlags);
}
if(hHash)
{
SchCryptDestroyHash(hHash, dwCapiFlags);
}
if(pbSigBuff != NULL)
{
SPExternalFree(pbSigBuff);
}
return pctRet;
}
SP_STATUS
SignHashUsingCred(
PSPCredential pCred,
ALG_ID aiHash,
PBYTE pbHash,
DWORD cbHash,
PBYTE pbSignature,
PDWORD pcbSignature)
{
HCRYPTHASH hHash;
DWORD cbSignatureBuffer;
SP_STATUS pctRet;
if(pCred == NULL)
{
return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
}
cbSignatureBuffer = *pcbSignature;
if(pCred->hProv)
{
// Sign hash using local CSP handle.
if(!CryptCreateHash(pCred->hProv, aiHash, 0, 0, &hHash))
{
SP_LOG_RESULT(GetLastError());
return PCT_ERR_ILLEGAL_MESSAGE;
}
if(!CryptSetHashParam(hHash, HP_HASHVAL, pbHash, 0))
{
SP_LOG_RESULT(GetLastError());
CryptDestroyHash(hHash);
return PCT_ERR_ILLEGAL_MESSAGE;
}
if(!CryptSignHash(hHash, pCred->dwKeySpec, NULL, 0, pbSignature, pcbSignature))
{
SP_LOG_RESULT(GetLastError());
CryptDestroyHash(hHash);
return PCT_ERR_ILLEGAL_MESSAGE;
}
CryptDestroyHash(hHash);
}
else if(pCred->hRemoteProv)
{
// Sign hash via a call to the application process.
pctRet = SignHashUsingCallback(pCred->hRemoteProv,
pCred->dwKeySpec,
aiHash,
pbHash,
cbHash,
pbSignature,
pcbSignature,
FALSE);
if(pctRet != PCT_ERR_OK)
{
return SP_LOG_RESULT(pctRet);
}
}
else
{
DebugLog((DEB_ERROR, "We have no key with which to sign!\n"));
return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR);
}
if(pCred->dwExchSpec == SP_EXCH_DH_PKCS3)
{
BYTE rgbTempSig[DSA_SIGNATURE_SIZE];
// Add DSS ASN1 goo around signature.
if(*pcbSignature != DSA_SIGNATURE_SIZE)
{
return SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE);
}
memcpy(rgbTempSig, pbSignature, DSA_SIGNATURE_SIZE);
*pcbSignature = cbSignatureBuffer;
if(!CryptEncodeObject(X509_ASN_ENCODING,
X509_DSS_SIGNATURE,
rgbTempSig,
pbSignature,
pcbSignature))
{
SP_LOG_RESULT(GetLastError());
return PCT_ERR_ILLEGAL_MESSAGE;
}
}
else
{
// Convert signature to big endian.
ReverseInPlace(pbSignature, *pcbSignature);
}
return PCT_ERR_OK;
}