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