Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

548 lines
16 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: msghlpr.cpp
//
// Contents: Cryptographic Message Helper APIs
//
// APIs: CryptMsgGetAndVerifySigner
// CryptMsgSignCTL
// CryptMsgEncodeAndSignCTL
//
// History: 02-May-97 philh created
//--------------------------------------------------------------------------
#include "global.hxx"
#include "pkialloc.h"
void *ICM_AllocAndGetMsgParam(
IN HCRYPTMSG hMsg,
IN DWORD dwParamType,
IN DWORD dwIndex
)
{
void *pvData;
DWORD cbData;
if (!CryptMsgGetParam(
hMsg,
dwParamType,
dwIndex,
NULL, // pvData
&cbData) || 0 == cbData)
goto GetParamError;
if (NULL == (pvData = ICM_Alloc(cbData)))
goto OutOfMemory;
if (!CryptMsgGetParam(
hMsg,
dwParamType,
dwIndex,
pvData,
&cbData)) {
ICM_Free(pvData);
goto GetParamError;
}
CommonReturn:
return pvData;
ErrorReturn:
pvData = NULL;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(GetParamError)
}
#ifdef CMS_PKCS7
BOOL ICM_GetAndVerifySigner(
IN HCRYPTMSG hCryptMsg,
IN DWORD dwSignerIndex,
IN DWORD cSignerStore,
IN OPTIONAL HCERTSTORE *rghSignerStore,
IN DWORD dwFlags,
OUT OPTIONAL PCCERT_CONTEXT *ppSigner
)
{
BOOL fResult;
PCERT_INFO pSignerId = NULL;
PCCERT_CONTEXT pSigner = NULL;
DWORD dwCertEncodingType;
DWORD dwVerifyErr = 0;
HCERTSTORE hCollection = NULL;
if (NULL == (pSignerId = (PCERT_INFO) ICM_AllocAndGetMsgParam(
hCryptMsg,
CMSG_SIGNER_CERT_INFO_PARAM,
dwSignerIndex
))) goto GetSignerError;
// If no CertEncodingType, then, use the MsgEncodingType
dwCertEncodingType = ((PCRYPT_MSG_INFO) hCryptMsg)->dwEncodingType;
if (0 == (dwCertEncodingType & CERT_ENCODING_TYPE_MASK))
dwCertEncodingType =
(dwCertEncodingType >> 16) & CERT_ENCODING_TYPE_MASK;
if (NULL == (hCollection = CertOpenStore(
CERT_STORE_PROV_COLLECTION,
0, // dwEncodingType
0, // hCryptProv
0, // dwFlags
NULL // pvPara
)))
goto OpenCollectionStoreError;
if (0 == (dwFlags & CMSG_TRUSTED_SIGNER_FLAG)) {
HCERTSTORE hMsgCertStore;
// Open a cert store initialized with certs from the message
// and add to collection
if (hMsgCertStore = CertOpenStore(
CERT_STORE_PROV_MSG,
dwCertEncodingType,
0, // hCryptProv
0, // dwFlags
hCryptMsg // pvPara
)) {
CertAddStoreToCollection(
hCollection,
hMsgCertStore,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
0 // dwPriority
);
CertCloseStore(hMsgCertStore, 0);
}
}
// Add all the signer stores to the collection
for ( ; cSignerStore > 0; cSignerStore--, rghSignerStore++) {
HCERTSTORE hSignerStore = *rghSignerStore;
if (NULL == hSignerStore)
continue;
CertAddStoreToCollection(
hCollection,
hSignerStore,
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
0 // dwPriority
);
}
if (pSigner = CertGetSubjectCertificateFromStore(hCollection,
dwCertEncodingType, pSignerId)) {
CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA CtrlPara;
if (dwFlags & CMSG_SIGNER_ONLY_FLAG)
goto SuccessReturn;
memset(&CtrlPara, 0, sizeof(CtrlPara));
CtrlPara.cbSize = sizeof(CtrlPara);
// CtrlPara.hCryptProv =
CtrlPara.dwSignerIndex = dwSignerIndex;
CtrlPara.dwSignerType = CMSG_VERIFY_SIGNER_CERT;
CtrlPara.pvSigner = (void *) pSigner;
if (CryptMsgControl(
hCryptMsg,
0, // dwFlags
CMSG_CTRL_VERIFY_SIGNATURE_EX,
&CtrlPara)) goto SuccessReturn;
else {
dwVerifyErr = GetLastError();
if (CRYPT_E_MISSING_PUBKEY_PARA == dwVerifyErr) {
PCCERT_CHAIN_CONTEXT pChainContext;
CERT_CHAIN_PARA ChainPara;
// Build a chain. Hopefully, the signer inherit's its public key
// parameters from up the chain
memset(&ChainPara, 0, sizeof(ChainPara));
ChainPara.cbSize = sizeof(ChainPara);
if (CertGetCertificateChain(
NULL, // hChainEngine
pSigner,
NULL, // pTime
hCollection,
&ChainPara,
CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL,
NULL, // pvReserved
&pChainContext
))
CertFreeCertificateChain(pChainContext);
// Try again. Hopefully the above chain building updated the
// signer's context property with the missing public key
// parameters
if (CryptMsgControl(
hCryptMsg,
0, // dwFlags
CMSG_CTRL_VERIFY_SIGNATURE_EX,
&CtrlPara)) goto SuccessReturn;
}
}
CertFreeCertificateContext(pSigner);
pSigner = NULL;
}
if (dwVerifyErr)
goto VerifySignatureError;
else
goto NoSignerError;
SuccessReturn:
fResult = TRUE;
CommonReturn:
if (hCollection)
CertCloseStore(hCollection, 0);
ICM_Free(pSignerId);
if (ppSigner)
*ppSigner = pSigner;
else if (pSigner)
CertFreeCertificateContext(pSigner);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(OpenCollectionStoreError)
TRACE_ERROR(GetSignerError)
SET_ERROR(NoSignerError, CRYPT_E_NO_TRUSTED_SIGNER)
SET_ERROR_VAR(VerifySignatureError, dwVerifyErr)
}
#else
BOOL ICM_GetAndVerifySigner(
IN HCRYPTMSG hCryptMsg,
IN DWORD dwSignerIndex,
IN DWORD cSignerStore,
IN OPTIONAL HCERTSTORE *rghSignerStore,
IN DWORD dwFlags,
OUT OPTIONAL PCCERT_CONTEXT *ppSigner
)
{
BOOL fResult;
PCERT_INFO pSignerId = NULL;
PCCERT_CONTEXT pSigner = NULL;
DWORD dwCertEncodingType;
DWORD dwVerifyErr = 0;
if (NULL == (pSignerId = (PCERT_INFO) ICM_AllocAndGetMsgParam(
hCryptMsg,
CMSG_SIGNER_CERT_INFO_PARAM,
dwSignerIndex
))) goto GetSignerError;
// If no CertEncodingType, then, use the MsgEncodingType
dwCertEncodingType = ((PCRYPT_MSG_INFO) hCryptMsg)->dwEncodingType;
if (0 == (dwCertEncodingType & CERT_ENCODING_TYPE_MASK))
dwCertEncodingType =
(dwCertEncodingType >> 16) & CERT_ENCODING_TYPE_MASK;
if (0 == (dwFlags & CMSG_TRUSTED_SIGNER_FLAG)) {
HCERTSTORE hMsgCertStore;
// Open a cert store initialized with certs from the message
if (hMsgCertStore = CertOpenStore(
CERT_STORE_PROV_MSG,
dwCertEncodingType,
0, // hCryptProv
0, // dwFlags
hCryptMsg // pvPara
)) {
pSigner = CertGetSubjectCertificateFromStore(hMsgCertStore,
dwCertEncodingType, pSignerId);
CertCloseStore(hMsgCertStore, 0);
}
if (pSigner) {
if (dwFlags & CMSG_SIGNER_ONLY_FLAG)
goto SuccessReturn;
if (CryptMsgControl(
hCryptMsg,
0, // dwFlags
CMSG_CTRL_VERIFY_SIGNATURE,
pSigner->pCertInfo)) goto SuccessReturn;
else
dwVerifyErr = GetLastError();
CertFreeCertificateContext(pSigner);
pSigner = NULL;
}
}
for ( ; cSignerStore > 0; cSignerStore--, rghSignerStore++) {
HCERTSTORE hSignerStore = *rghSignerStore;
if (NULL == hSignerStore)
continue;
if (pSigner = CertGetSubjectCertificateFromStore(hSignerStore,
dwCertEncodingType, pSignerId)) {
if (dwFlags & CMSG_SIGNER_ONLY_FLAG)
goto SuccessReturn;
if (CryptMsgControl(
hCryptMsg,
0, // dwFlags
CMSG_CTRL_VERIFY_SIGNATURE,
pSigner->pCertInfo)) goto SuccessReturn;
else
dwVerifyErr = GetLastError();
CertFreeCertificateContext(pSigner);
pSigner = NULL;
}
}
if (dwVerifyErr)
goto VerifySignatureError;
else
goto NoSignerError;
SuccessReturn:
fResult = TRUE;
CommonReturn:
ICM_Free(pSignerId);
if (ppSigner)
*ppSigner = pSigner;
else if (pSigner)
CertFreeCertificateContext(pSigner);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(GetSignerError)
SET_ERROR(NoSignerError, CRYPT_E_NO_TRUSTED_SIGNER)
SET_ERROR_VAR(VerifySignatureError, dwVerifyErr)
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Get and verify the signer of a cryptographic message.
//
// If CMSG_TRUSTED_SIGNER_FLAG is set, then, treat the Signer stores as being
// trusted and only search them to find the certificate corresponding to the
// signer's issuer and serial number. Otherwise, the SignerStores are
// optionally provided to supplement the message's store of certificates.
// If a signer certificate is found, its public key is used to verify
// the message signature. The CMSG_SIGNER_ONLY_FLAG can be set to
// return the signer without doing the signature verify.
//
// If CMSG_USE_SIGNER_INDEX_FLAG is set, then, only get the signer specified
// by *pdwSignerIndex. Otherwise, iterate through all the signers
// until a signer verifies or no more signers.
//
// For a verified signature, *ppSigner is updated with certificate context
// of the signer and *pdwSignerIndex is updated with the index of the signer.
// ppSigner and/or pdwSignerIndex can be NULL, indicating the caller isn't
// interested in getting the CertContext and/or index of the signer.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptMsgGetAndVerifySigner(
IN HCRYPTMSG hCryptMsg,
IN DWORD cSignerStore,
IN OPTIONAL HCERTSTORE *rghSignerStore,
IN DWORD dwFlags,
OUT OPTIONAL PCCERT_CONTEXT *ppSigner,
IN OUT OPTIONAL DWORD *pdwSignerIndex
)
{
BOOL fResult = FALSE;
DWORD dwSignerCount;
DWORD dwSignerIndex;
if (dwFlags & CMSG_USE_SIGNER_INDEX_FLAG) {
dwSignerCount = 1;
dwSignerIndex = *pdwSignerIndex;
} else {
DWORD cbData;
dwSignerIndex = 0;
if (pdwSignerIndex)
*pdwSignerIndex = 0;
cbData = sizeof(dwSignerCount);
if (!CryptMsgGetParam(
hCryptMsg,
CMSG_SIGNER_COUNT_PARAM,
0, // dwIndex
&dwSignerCount,
&cbData) || 0 == dwSignerCount)
goto NoSignerError;
}
// Minimum of one iteration
for ( ; dwSignerCount > 0; dwSignerCount--, dwSignerIndex++) {
if (fResult = ICM_GetAndVerifySigner(
hCryptMsg,
dwSignerIndex,
cSignerStore,
rghSignerStore,
dwFlags,
ppSigner)) {
if (pdwSignerIndex && 0 == (dwFlags & CMSG_USE_SIGNER_INDEX_FLAG))
*pdwSignerIndex = dwSignerIndex;
break;
}
}
CommonReturn:
return fResult;
ErrorReturn:
if (ppSigner)
*ppSigner = NULL;
fResult = FALSE;
goto CommonReturn;
SET_ERROR(NoSignerError, CRYPT_E_NO_TRUSTED_SIGNER)
}
//+-------------------------------------------------------------------------
// Sign an encoded CTL.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptMsgSignCTL(
IN DWORD dwMsgEncodingType,
IN BYTE *pbCtlContent,
IN DWORD cbCtlContent,
IN PCMSG_SIGNED_ENCODE_INFO pSignInfo,
IN DWORD dwFlags,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
BOOL fResult;
HCRYPTMSG hMsg = NULL;
DWORD dwMsgFlags;
#ifdef CMS_PKCS7
if (dwFlags & CMSG_CMS_ENCAPSULATED_CTL_FLAG)
dwMsgFlags = CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
else
dwMsgFlags = 0;
#else
dwMsgFlags = 0;
#endif // CMS_PKCS7
if (NULL == pbEncoded) {
if (0 == (*pcbEncoded = CryptMsgCalculateEncodedLength(
dwMsgEncodingType,
dwMsgFlags,
CMSG_SIGNED,
pSignInfo,
szOID_CTL,
cbCtlContent))) goto CalculateEncodedLengthError;
fResult = TRUE;
} else {
if (NULL == (hMsg = CryptMsgOpenToEncode(
dwMsgEncodingType,
dwMsgFlags,
CMSG_SIGNED,
pSignInfo,
szOID_CTL,
NULL // pStreamInfo
))) goto OpenToEncodeError;
if (!CryptMsgUpdate(
hMsg,
pbCtlContent,
cbCtlContent,
TRUE // fFinal
)) goto UpdateError;
fResult = CryptMsgGetParam(
hMsg,
CMSG_CONTENT_PARAM,
0, // dwIndex
pbEncoded,
pcbEncoded);
}
CommonReturn:
if (hMsg)
CryptMsgClose(hMsg);
return fResult;
ErrorReturn:
*pcbEncoded = 0;
fResult = FALSE;
goto CommonReturn;
TRACE_ERROR(CalculateEncodedLengthError)
TRACE_ERROR(OpenToEncodeError)
TRACE_ERROR(UpdateError)
}
//+-------------------------------------------------------------------------
// Encode the CTL and create a signed message containing the encoded CTL.
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptMsgEncodeAndSignCTL(
IN DWORD dwMsgEncodingType,
IN PCTL_INFO pCtlInfo,
IN PCMSG_SIGNED_ENCODE_INFO pSignInfo,
IN DWORD dwFlags,
OUT BYTE *pbEncoded,
IN OUT DWORD *pcbEncoded
)
{
BOOL fResult;
BYTE *pbContent = NULL;
DWORD cbContent;
DWORD dwEncodingType;
LPCSTR lpszStructType;
DWORD dwEncodeFlags;
dwEncodingType = (dwMsgEncodingType >> 16) & CERT_ENCODING_TYPE_MASK;
assert(dwEncodingType != 0);
if (0 == dwEncodingType)
goto InvalidArg;
dwEncodeFlags = CRYPT_ENCODE_ALLOC_FLAG;
if (dwFlags & CMSG_ENCODE_SORTED_CTL_FLAG) {
lpszStructType = PKCS_SORTED_CTL;
if (dwFlags & CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG)
dwEncodeFlags |=
CRYPT_SORTED_CTL_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG;
} else {
lpszStructType = PKCS_CTL;
}
if (!CryptEncodeObjectEx(
dwEncodingType,
lpszStructType,
pCtlInfo,
dwEncodeFlags,
&PkiEncodePara,
(void *) &pbContent,
&cbContent
)) goto EncodeError;
fResult = CryptMsgSignCTL(
dwMsgEncodingType,
pbContent,
cbContent,
pSignInfo,
dwFlags,
pbEncoded,
pcbEncoded
);
CommonReturn:
PkiFree(pbContent);
return fResult;
ErrorReturn:
*pcbEncoded = 0;
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(EncodeError)
}