reactos/dll/win32/crypt32/message.c
2011-05-24 18:40:34 +00:00

404 lines
13 KiB
C

/*
* Copyright 2007 Juan Lang
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "wincrypt.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
HCERTSTORE WINAPI CryptGetMessageCertificates(DWORD dwMsgAndCertEncodingType,
HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const BYTE* pbSignedBlob,
DWORD cbSignedBlob)
{
CRYPT_DATA_BLOB blob = { cbSignedBlob, (LPBYTE)pbSignedBlob };
TRACE("(%08x, %ld, %d08x %p, %d)\n", dwMsgAndCertEncodingType, hCryptProv,
dwFlags, pbSignedBlob, cbSignedBlob);
return CertOpenStore(CERT_STORE_PROV_PKCS7, dwMsgAndCertEncodingType,
hCryptProv, dwFlags, &blob);
}
LONG WINAPI CryptGetMessageSignerCount(DWORD dwMsgEncodingType,
const BYTE *pbSignedBlob, DWORD cbSignedBlob)
{
HCRYPTMSG msg;
LONG count = -1;
TRACE("(%08x, %p, %d)\n", dwMsgEncodingType, pbSignedBlob, cbSignedBlob);
msg = CryptMsgOpenToDecode(dwMsgEncodingType, 0, 0, 0, NULL, NULL);
if (msg)
{
if (CryptMsgUpdate(msg, pbSignedBlob, cbSignedBlob, TRUE))
{
DWORD size = sizeof(count);
CryptMsgGetParam(msg, CMSG_SIGNER_COUNT_PARAM, 0, &count, &size);
}
CryptMsgClose(msg);
}
return count;
}
static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
DWORD dwSignerIndex)
{
CERT_INFO *certInfo = NULL;
DWORD size;
if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
&size))
{
certInfo = CryptMemAlloc(size);
if (certInfo)
{
if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
dwSignerIndex, certInfo, &size))
{
CryptMemFree(certInfo);
certInfo = NULL;
}
}
}
else
SetLastError(CRYPT_E_UNEXPECTED_MSG_TYPE);
return certInfo;
}
static PCCERT_CONTEXT WINAPI CRYPT_DefaultGetSignerCertificate(void *pvGetArg,
DWORD dwCertEncodingType, PCERT_INFO pSignerId, HCERTSTORE hMsgCertStore)
{
return CertFindCertificateInStore(hMsgCertStore, dwCertEncodingType, 0,
CERT_FIND_SUBJECT_CERT, pSignerId, NULL);
}
static inline PCCERT_CONTEXT CRYPT_GetSignerCertificate(HCRYPTMSG msg,
PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, PCERT_INFO certInfo, HCERTSTORE store)
{
PFN_CRYPT_GET_SIGNER_CERTIFICATE getCert;
if (pVerifyPara->pfnGetSignerCertificate)
getCert = pVerifyPara->pfnGetSignerCertificate;
else
getCert = CRYPT_DefaultGetSignerCertificate;
return getCert(pVerifyPara->pvGetArg,
pVerifyPara->dwMsgAndCertEncodingType, certInfo, store);
}
BOOL WINAPI CryptVerifyDetachedMessageSignature(
PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, DWORD dwSignerIndex,
const BYTE *pbDetachedSignBlob, DWORD cbDetachedSignBlob, DWORD cToBeSigned,
const BYTE *rgpbToBeSigned[], DWORD rgcbToBeSigned[],
PCCERT_CONTEXT *ppSignerCert)
{
BOOL ret = FALSE;
HCRYPTMSG msg;
TRACE("(%p, %d, %p, %d, %d, %p, %p, %p)\n", pVerifyPara, dwSignerIndex,
pbDetachedSignBlob, cbDetachedSignBlob, cToBeSigned, rgpbToBeSigned,
rgcbToBeSigned, ppSignerCert);
if (ppSignerCert)
*ppSignerCert = NULL;
if (!pVerifyPara ||
pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) ||
GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) !=
PKCS_7_ASN_ENCODING)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
msg = CryptMsgOpenToDecode(pVerifyPara->dwMsgAndCertEncodingType,
CMSG_DETACHED_FLAG, 0, pVerifyPara->hCryptProv, NULL, NULL);
if (msg)
{
ret = CryptMsgUpdate(msg, pbDetachedSignBlob, cbDetachedSignBlob, TRUE);
if (ret)
{
DWORD i;
for (i = 0; ret && i < cToBeSigned; i++)
ret = CryptMsgUpdate(msg, rgpbToBeSigned[i], rgcbToBeSigned[i],
i == cToBeSigned - 1 ? TRUE : FALSE);
}
if (ret)
{
CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg,
dwSignerIndex);
ret = FALSE;
if (certInfo)
{
HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG,
pVerifyPara->dwMsgAndCertEncodingType,
pVerifyPara->hCryptProv, 0, msg);
if (store)
{
PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate(
msg, pVerifyPara, certInfo, store);
if (cert)
{
ret = CryptMsgControl(msg, 0,
CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo);
if (ret && ppSignerCert)
*ppSignerCert = cert;
else
CertFreeCertificateContext(cert);
}
else
SetLastError(CRYPT_E_NOT_FOUND);
CertCloseStore(store, 0);
}
CryptMemFree(certInfo);
}
}
CryptMsgClose(msg);
}
TRACE("returning %d\n", ret);
return ret;
}
BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,
DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
{
BOOL ret = FALSE;
HCRYPTMSG msg;
TRACE("(%p, %d, %p, %d, %p, %p, %p)\n",
pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
pbDecoded, pcbDecoded, ppSignerCert);
if (ppSignerCert)
*ppSignerCert = NULL;
if (pcbDecoded)
*pcbDecoded = 0;
if (!pVerifyPara ||
pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) ||
GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) !=
PKCS_7_ASN_ENCODING)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
msg = CryptMsgOpenToDecode(pVerifyPara->dwMsgAndCertEncodingType, 0, 0,
pVerifyPara->hCryptProv, NULL, NULL);
if (msg)
{
ret = CryptMsgUpdate(msg, pbSignedBlob, cbSignedBlob, TRUE);
if (ret && pcbDecoded)
ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, pbDecoded,
pcbDecoded);
if (ret)
{
CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg,
dwSignerIndex);
ret = FALSE;
if (certInfo)
{
HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG,
pVerifyPara->dwMsgAndCertEncodingType,
pVerifyPara->hCryptProv, 0, msg);
if (store)
{
PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate(
msg, pVerifyPara, certInfo, store);
if (cert)
{
ret = CryptMsgControl(msg, 0,
CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo);
if (ret && ppSignerCert)
*ppSignerCert = cert;
else
CertFreeCertificateContext(cert);
}
CertCloseStore(store, 0);
}
}
CryptMemFree(certInfo);
}
CryptMsgClose(msg);
}
TRACE("returning %d\n", ret);
return ret;
}
BOOL WINAPI CryptHashMessage(PCRYPT_HASH_MESSAGE_PARA pHashPara,
BOOL fDetachedHash, DWORD cToBeHashed, const BYTE *rgpbToBeHashed[],
DWORD rgcbToBeHashed[], BYTE *pbHashedBlob, DWORD *pcbHashedBlob,
BYTE *pbComputedHash, DWORD *pcbComputedHash)
{
DWORD i, flags;
BOOL ret = FALSE;
HCRYPTMSG msg;
CMSG_HASHED_ENCODE_INFO info;
TRACE("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n", pHashPara, fDetachedHash,
cToBeHashed, rgpbToBeHashed, rgcbToBeHashed, pbHashedBlob, pcbHashedBlob,
pbComputedHash, pcbComputedHash);
if (pHashPara->cbSize != sizeof(CRYPT_HASH_MESSAGE_PARA))
{
SetLastError(E_INVALIDARG);
return FALSE;
}
/* Native seems to ignore any encoding type other than the expected
* PKCS_7_ASN_ENCODING
*/
if (GET_CMSG_ENCODING_TYPE(pHashPara->dwMsgEncodingType) !=
PKCS_7_ASN_ENCODING)
return TRUE;
/* Native also seems to do nothing if the output parameter isn't given */
if (!pcbHashedBlob)
return TRUE;
flags = fDetachedHash ? CMSG_DETACHED_FLAG : 0;
memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
info.hCryptProv = pHashPara->hCryptProv;
memcpy(&info.HashAlgorithm, &pHashPara->HashAlgorithm,
sizeof(info.HashAlgorithm));
info.pvHashAuxInfo = pHashPara->pvHashAuxInfo;
msg = CryptMsgOpenToEncode(pHashPara->dwMsgEncodingType, flags, CMSG_HASHED,
&info, NULL, NULL);
if (msg)
{
for (i = 0, ret = TRUE; ret && i < cToBeHashed; i++)
ret = CryptMsgUpdate(msg, rgpbToBeHashed[i], rgcbToBeHashed[i],
i == cToBeHashed - 1 ? TRUE : FALSE);
if (ret)
{
ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, pbHashedBlob,
pcbHashedBlob);
if (ret && pcbComputedHash)
ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
pbComputedHash, pcbComputedHash);
}
CryptMsgClose(msg);
}
return ret;
}
BOOL WINAPI CryptVerifyDetachedMessageHash(PCRYPT_HASH_MESSAGE_PARA pHashPara,
BYTE *pbDetachedHashBlob, DWORD cbDetachedHashBlob, DWORD cToBeHashed,
const BYTE *rgpbToBeHashed[], DWORD rgcbToBeHashed[], BYTE *pbComputedHash,
DWORD *pcbComputedHash)
{
HCRYPTMSG msg;
BOOL ret = FALSE;
TRACE("(%p, %p, %d, %d, %p, %p, %p, %p)\n", pHashPara, pbDetachedHashBlob,
cbDetachedHashBlob, cToBeHashed, rgpbToBeHashed, rgcbToBeHashed,
pbComputedHash, pcbComputedHash);
if (pHashPara->cbSize != sizeof(CRYPT_HASH_MESSAGE_PARA))
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if (GET_CMSG_ENCODING_TYPE(pHashPara->dwMsgEncodingType) !=
PKCS_7_ASN_ENCODING)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
msg = CryptMsgOpenToDecode(pHashPara->dwMsgEncodingType, CMSG_DETACHED_FLAG,
0, pHashPara->hCryptProv, NULL, NULL);
if (msg)
{
DWORD i;
ret = CryptMsgUpdate(msg, pbDetachedHashBlob, cbDetachedHashBlob, TRUE);
if (ret)
{
if (cToBeHashed)
{
for (i = 0; ret && i < cToBeHashed; i++)
{
ret = CryptMsgUpdate(msg, rgpbToBeHashed[i],
rgcbToBeHashed[i], i == cToBeHashed - 1 ? TRUE : FALSE);
}
}
else
ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
}
if (ret)
{
ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL);
if (ret && pcbComputedHash)
ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
pbComputedHash, pcbComputedHash);
}
CryptMsgClose(msg);
}
return ret;
}
BOOL WINAPI CryptVerifyMessageHash(PCRYPT_HASH_MESSAGE_PARA pHashPara,
BYTE *pbHashedBlob, DWORD cbHashedBlob, BYTE *pbToBeHashed,
DWORD *pcbToBeHashed, BYTE *pbComputedHash, DWORD *pcbComputedHash)
{
HCRYPTMSG msg;
BOOL ret = FALSE;
TRACE("(%p, %p, %d, %p, %p, %p, %p)\n", pHashPara, pbHashedBlob,
cbHashedBlob, pbToBeHashed, pcbToBeHashed, pbComputedHash,
pcbComputedHash);
if (pHashPara->cbSize != sizeof(CRYPT_HASH_MESSAGE_PARA))
{
SetLastError(E_INVALIDARG);
return FALSE;
}
if (GET_CMSG_ENCODING_TYPE(pHashPara->dwMsgEncodingType) !=
PKCS_7_ASN_ENCODING)
{
SetLastError(E_INVALIDARG);
return FALSE;
}
msg = CryptMsgOpenToDecode(pHashPara->dwMsgEncodingType, 0, 0,
pHashPara->hCryptProv, NULL, NULL);
if (msg)
{
ret = CryptMsgUpdate(msg, pbHashedBlob, cbHashedBlob, TRUE);
if (ret)
{
ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL);
if (ret && pcbToBeHashed)
ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0,
pbToBeHashed, pcbToBeHashed);
if (ret && pcbComputedHash)
ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
pbComputedHash, pcbComputedHash);
}
CryptMsgClose(msg);
}
return ret;
}