* 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 "config.h"
+#include "wine/port.h"
+
#include <stdarg.h>
+#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "wincrypt.h"
typedef BOOL (*CryptMsgControlFunc)(HCRYPTMSG hCryptMsg, DWORD dwFlags,
DWORD dwCtrlType, const void *pvCtrlPara);
-BOOL CRYPT_DefaultMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
+static BOOL CRYPT_DefaultMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
DWORD dwCtrlType, const void *pvCtrlPara)
{
TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
typedef enum _CryptMsgState {
MsgStateInit,
MsgStateUpdated,
+ MsgStateDataFinalized,
MsgStateFinalized
} CryptMsgState;
if (pStreamInfo)
{
msg->streamed = TRUE;
- memcpy(&msg->stream_info, pStreamInfo, sizeof(msg->stream_info));
+ msg->stream_info = *pStreamInfo;
}
else
{
static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
{
- CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
+ CDataEncodeMsg *msg = hCryptMsg;
if (msg->bare_content != empty_data_content)
LocalFree(msg->bare_content);
}
-static WINAPI BOOL CRYPT_EncodeContentLength(DWORD dwCertEncodingType,
+static BOOL WINAPI CRYPT_EncodeContentLength(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
- const CDataEncodeMsg *msg = (const CDataEncodeMsg *)pvStructInfo;
+ DWORD dataLen = *(DWORD *)pvStructInfo;
DWORD lenBytes;
BOOL ret = TRUE;
* the message isn't available yet. The caller will use the length
* reported here to encode its length.
*/
- CRYPT_EncodeLen(msg->base.stream_info.cbContent, NULL, &lenBytes);
+ CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
if (!pbEncoded)
- *pcbEncoded = 1 + lenBytes + msg->base.stream_info.cbContent;
+ *pcbEncoded = 1 + lenBytes + dataLen;
else
{
if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
pbEncoded = *(BYTE **)pbEncoded;
*pbEncoded++ = ASN_OCTETSTRING;
- CRYPT_EncodeLen(msg->base.stream_info.cbContent, pbEncoded,
+ CRYPT_EncodeLen(dataLen, pbEncoded,
&lenBytes);
}
}
if (msg->base.streamed && msg->base.stream_info.cbContent == 0xffffffff)
{
- FIXME("unimplemented for indefinite-length encoding\n");
- header->cbData = 0;
- header->pbData = NULL;
- ret = TRUE;
+ static const BYTE headerValue[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48,
+ 0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x80,0x24,0x80 };
+
+ header->pbData = LocalAlloc(0, sizeof(headerValue));
+ if (header->pbData)
+ {
+ header->cbData = sizeof(headerValue);
+ memcpy(header->pbData, headerValue, sizeof(headerValue));
+ ret = TRUE;
+ }
+ else
+ ret = FALSE;
}
else
{
- struct AsnConstructedItem constructed = { 0, msg,
- CRYPT_EncodeContentLength };
+ struct AsnConstructedItem constructed = { 0,
+ &msg->base.stream_info.cbContent, CRYPT_EncodeContentLength };
struct AsnEncodeSequenceItem items[2] = {
{ szOID_RSA_data, CRYPT_AsnEncodeOid, 0 },
{ &constructed, CRYPT_AsnEncodeConstructed, 0 },
static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
DWORD cbData, BOOL fFinal)
{
- CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
+ CDataEncodeMsg *msg = hCryptMsg;
BOOL ret = FALSE;
- if (msg->base.streamed)
+ if (msg->base.state == MsgStateFinalized)
+ SetLastError(CRYPT_E_MSG_ERROR);
+ else if (msg->base.streamed)
{
__TRY
{
LocalFree(header.pbData);
}
}
+ /* Curiously, every indefinite-length streamed update appears to
+ * get its own tag and length, regardless of fFinal.
+ */
+ if (msg->base.stream_info.cbContent == 0xffffffff)
+ {
+ BYTE *header;
+ DWORD headerLen;
+
+ ret = CRYPT_EncodeContentLength(X509_ASN_ENCODING, NULL,
+ &cbData, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&header,
+ &headerLen);
+ if (ret)
+ {
+ ret = msg->base.stream_info.pfnStreamOutput(
+ msg->base.stream_info.pvArg, header, headerLen,
+ FALSE);
+ LocalFree(header);
+ }
+ }
if (!fFinal)
+ {
ret = msg->base.stream_info.pfnStreamOutput(
msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
FALSE);
+ msg->base.state = MsgStateUpdated;
+ }
else
{
+ msg->base.state = MsgStateFinalized;
if (msg->base.stream_info.cbContent == 0xffffffff)
{
BYTE indefinite_trailer[6] = { 0 };
}
else
{
+ msg->base.state = MsgStateFinalized;
if (!cbData)
SetLastError(E_INVALIDARG);
else
static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
DWORD dwIndex, void *pvData, DWORD *pcbData)
{
- CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
+ CDataEncodeMsg *msg = hCryptMsg;
BOOL ret = FALSE;
switch (dwParamType)
msg->bare_content_len = sizeof(empty_data_content);
msg->bare_content = (LPBYTE)empty_data_content;
}
- return (HCRYPTMSG)msg;
+ return msg;
}
typedef struct _CHashEncodeMsg
static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg)
{
- CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
+ CHashEncodeMsg *msg = hCryptMsg;
CryptMemFree(msg->data.pbData);
CryptDestroyHash(msg->hash);
static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
DWORD dwIndex, void *pvData, DWORD *pcbData)
{
- CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
+ CHashEncodeMsg *msg = hCryptMsg;
BOOL ret = FALSE;
TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
break;
}
case CMSG_COMPUTED_HASH_PARAM:
- ret = CryptGetHashParam(msg->hash, HP_HASHVAL, (BYTE *)pvData, pcbData,
- 0);
+ ret = CryptGetHashParam(msg->hash, HP_HASHVAL, pvData, pcbData, 0);
break;
case CMSG_VERSION_PARAM:
if (msg->base.state != MsgStateFinalized)
static BOOL CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
DWORD cbData, BOOL fFinal)
{
- CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
+ CHashEncodeMsg *msg = hCryptMsg;
BOOL ret = FALSE;
TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
- if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
+ if (msg->base.state == MsgStateFinalized)
+ SetLastError(CRYPT_E_MSG_ERROR);
+ else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
{
/* Doesn't do much, as stream output is never called, and you
* can't get the content.
*/
ret = CryptHashData(msg->hash, pbData, cbData, 0);
+ msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
}
else
{
else
ret = FALSE;
}
+ msg->base.state = MsgStateFinalized;
}
}
return ret;
LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
{
CHashEncodeMsg *msg;
- const CMSG_HASHED_ENCODE_INFO *info =
- (const CMSG_HASHED_ENCODE_INFO *)pvMsgEncodeInfo;
+ const CMSG_HASHED_ENCODE_INFO *info = pvMsgEncodeInfo;
HCRYPTPROV prov;
ALG_ID algID;
msg = NULL;
}
}
- return (HCRYPTMSG)msg;
+ return msg;
}
typedef struct _CMSG_SIGNER_ENCODE_INFO_WITH_CMS
SetLastError(E_INVALIDARG);
return FALSE;
}
- if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
+ if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO))
{
- FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n");
- return FALSE;
- }
- if (!signer->pCertInfo->SerialNumber.cbData)
- {
- SetLastError(E_INVALIDARG);
- return FALSE;
+ if (!signer->pCertInfo->SerialNumber.cbData)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ if (!signer->pCertInfo->Issuer.cbData)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
}
- if (!signer->pCertInfo->Issuer.cbData)
+ else if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
{
- SetLastError(E_INVALIDARG);
- return FALSE;
+ switch (signer->SignerId.dwIdChoice)
+ {
+ case 0:
+ if (!signer->pCertInfo->SerialNumber.cbData)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ if (!signer->pCertInfo->Issuer.cbData)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ break;
+ case CERT_ID_ISSUER_SERIAL_NUMBER:
+ if (!signer->SignerId.u.IssuerSerialNumber.SerialNumber.cbData)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ if (!signer->SignerId.u.IssuerSerialNumber.Issuer.cbData)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ break;
+ case CERT_ID_KEY_IDENTIFIER:
+ if (!signer->SignerId.u.KeyId.cbData)
+ {
+ SetLastError(E_INVALIDARG);
+ return FALSE;
+ }
+ break;
+ default:
+ SetLastError(E_INVALIDARG);
+ }
+ if (signer->HashEncryptionAlgorithm.pszObjId)
+ {
+ FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n");
+ return FALSE;
+ }
}
if (!signer->hCryptProv)
{
return TRUE;
}
-typedef struct _CSignerHandles
-{
- HCRYPTPROV prov;
- HCRYPTHASH contentHash;
- HCRYPTHASH authAttrHash;
- HCRYPTKEY key;
-} CSignerHandles;
-
static BOOL CRYPT_ConstructBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in)
{
BOOL ret = TRUE;
return ret;
}
-/* Constructs both a CSignerHandles and a CMSG_SIGNER_INFO from a
- * CMSG_SIGNER_ENCODE_INFO_WITH_CMS.
- */
-static BOOL CSignerInfo_Construct(CSignerHandles *handles,
- CMSG_SIGNER_INFO *info, CMSG_SIGNER_ENCODE_INFO_WITH_CMS *in, DWORD open_flags)
+/* Constructs a CMSG_CMS_SIGNER_INFO from a CMSG_SIGNER_ENCODE_INFO_WITH_CMS. */
+static BOOL CSignerInfo_Construct(CMSG_CMS_SIGNER_INFO *info,
+ const CMSG_SIGNER_ENCODE_INFO_WITH_CMS *in)
{
- ALG_ID algID;
BOOL ret;
- handles->prov = in->hCryptProv;
- if (!(open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG))
- CryptContextAddRef(handles->prov, NULL, 0);
- algID = CertOIDToAlgId(in->HashAlgorithm.pszObjId);
- ret = CryptCreateHash(handles->prov, algID, 0, 0, &handles->contentHash);
- if (ret && in->cAuthAttr)
- ret = CryptCreateHash(handles->prov, algID, 0, 0,
- &handles->authAttrHash);
- if (ret)
+ if (in->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO))
{
- /* Note: needs to change if CMS fields are supported */
info->dwVersion = CMSG_SIGNER_INFO_V1;
- ret = CRYPT_ConstructBlob(&info->Issuer, &in->pCertInfo->Issuer);
+ ret = CRYPT_ConstructBlob(&info->SignerId.u.IssuerSerialNumber.Issuer,
+ &in->pCertInfo->Issuer);
if (ret)
- ret = CRYPT_ConstructBlob(&info->SerialNumber,
+ ret = CRYPT_ConstructBlob(
+ &info->SignerId.u.IssuerSerialNumber.SerialNumber,
&in->pCertInfo->SerialNumber);
- /* Assumption: algorithm IDs will point to static strings, not
- * stack-based ones, so copying the pointer values is safe.
+ info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
+ }
+ else
+ {
+ /* Implicitly in->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS).
+ * See CRYPT_IsValidSigner.
*/
- info->HashAlgorithm.pszObjId = in->HashAlgorithm.pszObjId;
- if (ret)
- ret = CRYPT_ConstructBlob(&info->HashAlgorithm.Parameters,
- &in->HashAlgorithm.Parameters);
- memset(&info->HashEncryptionAlgorithm, 0,
- sizeof(info->HashEncryptionAlgorithm));
- if (ret)
- ret = CRYPT_ConstructAttributes(&info->AuthAttrs,
- (CRYPT_ATTRIBUTES *)&in->cAuthAttr);
- if (ret)
- ret = CRYPT_ConstructAttributes(&info->UnauthAttrs,
- (CRYPT_ATTRIBUTES *)&in->cUnauthAttr);
+ if (!in->SignerId.dwIdChoice)
+ {
+ info->dwVersion = CMSG_SIGNER_INFO_V1;
+ ret = CRYPT_ConstructBlob(&info->SignerId.u.IssuerSerialNumber.Issuer,
+ &in->pCertInfo->Issuer);
+ if (ret)
+ ret = CRYPT_ConstructBlob(
+ &info->SignerId.u.IssuerSerialNumber.SerialNumber,
+ &in->pCertInfo->SerialNumber);
+ info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
+ }
+ else if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
+ {
+ info->dwVersion = CMSG_SIGNER_INFO_V1;
+ info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
+ ret = CRYPT_ConstructBlob(&info->SignerId.u.IssuerSerialNumber.Issuer,
+ &in->SignerId.u.IssuerSerialNumber.Issuer);
+ if (ret)
+ ret = CRYPT_ConstructBlob(
+ &info->SignerId.u.IssuerSerialNumber.SerialNumber,
+ &in->SignerId.u.IssuerSerialNumber.SerialNumber);
+ }
+ else
+ {
+ /* Implicitly dwIdChoice == CERT_ID_KEY_IDENTIFIER */
+ info->dwVersion = CMSG_SIGNER_INFO_V3;
+ info->SignerId.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
+ ret = CRYPT_ConstructBlob(&info->SignerId.u.KeyId,
+ &in->SignerId.u.KeyId);
+ }
}
+ /* Assumption: algorithm IDs will point to static strings, not
+ * stack-based ones, so copying the pointer values is safe.
+ */
+ info->HashAlgorithm.pszObjId = in->HashAlgorithm.pszObjId;
+ if (ret)
+ ret = CRYPT_ConstructBlob(&info->HashAlgorithm.Parameters,
+ &in->HashAlgorithm.Parameters);
+ memset(&info->HashEncryptionAlgorithm, 0,
+ sizeof(info->HashEncryptionAlgorithm));
+ if (ret)
+ ret = CRYPT_ConstructAttributes(&info->AuthAttrs,
+ (CRYPT_ATTRIBUTES *)&in->cAuthAttr);
+ if (ret)
+ ret = CRYPT_ConstructAttributes(&info->UnauthAttrs,
+ (CRYPT_ATTRIBUTES *)&in->cUnauthAttr);
return ret;
}
-static void CSignerInfo_Free(CMSG_SIGNER_INFO *info)
+static void CSignerInfo_Free(CMSG_CMS_SIGNER_INFO *info)
{
DWORD i, j;
- CryptMemFree(info->Issuer.pbData);
- CryptMemFree(info->SerialNumber.pbData);
+ if (info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
+ {
+ CryptMemFree(info->SignerId.u.IssuerSerialNumber.Issuer.pbData);
+ CryptMemFree(info->SignerId.u.IssuerSerialNumber.SerialNumber.pbData);
+ }
+ else
+ CryptMemFree(info->SignerId.u.KeyId.pbData);
CryptMemFree(info->HashAlgorithm.Parameters.pbData);
CryptMemFree(info->EncryptedHash.pbData);
for (i = 0; i < info->AuthAttrs.cAttr; i++)
CryptMemFree(info->UnauthAttrs.rgAttr);
}
+typedef struct _CSignerHandles
+{
+ HCRYPTHASH contentHash;
+ HCRYPTHASH authAttrHash;
+} CSignerHandles;
+
typedef struct _CSignedMsgData
{
CRYPT_SIGNED_INFO *info;
+ DWORD cSignerHandle;
CSignerHandles *signerHandles;
} CSignedMsgData;
-typedef struct _CSignedEncodeMsg
+/* Constructs the signer handles for the signerIndex'th signer of msg_data.
+ * Assumes signerIndex is a valid idnex, and that msg_data's info has already
+ * been constructed.
+ */
+static BOOL CSignedMsgData_ConstructSignerHandles(CSignedMsgData *msg_data,
+ DWORD signerIndex, HCRYPTPROV crypt_prov)
{
- CryptMsgBase base;
- CRYPT_DATA_BLOB data;
- CSignedMsgData msg_data;
-} CSignedEncodeMsg;
+ ALG_ID algID;
+ BOOL ret;
+
+ algID = CertOIDToAlgId(
+ msg_data->info->rgSignerInfo[signerIndex].HashAlgorithm.pszObjId);
+ ret = CryptCreateHash(crypt_prov, algID, 0, 0,
+ &msg_data->signerHandles->contentHash);
+ if (ret && msg_data->info->rgSignerInfo[signerIndex].AuthAttrs.cAttr > 0)
+ ret = CryptCreateHash(crypt_prov, algID, 0, 0,
+ &msg_data->signerHandles->authAttrHash);
+ return ret;
+}
+
+/* Allocates a CSignedMsgData's handles. Assumes its info has already been
+ * constructed.
+ */
+static BOOL CSignedMsgData_AllocateHandles(CSignedMsgData *msg_data)
+{
+ BOOL ret = TRUE;
+
+ if (msg_data->info->cSignerInfo)
+ {
+ msg_data->signerHandles =
+ CryptMemAlloc(msg_data->info->cSignerInfo * sizeof(CSignerHandles));
+ if (msg_data->signerHandles)
+ {
+ msg_data->cSignerHandle = msg_data->info->cSignerInfo;
+ memset(msg_data->signerHandles, 0,
+ msg_data->info->cSignerInfo * sizeof(CSignerHandles));
+ }
+ else
+ {
+ msg_data->cSignerHandle = 0;
+ ret = FALSE;
+ }
+ }
+ else
+ {
+ msg_data->cSignerHandle = 0;
+ msg_data->signerHandles = NULL;
+ }
+ return ret;
+}
static void CSignedMsgData_CloseHandles(CSignedMsgData *msg_data)
{
DWORD i;
- for (i = 0; i < msg_data->info->cSignerInfo; i++)
+ for (i = 0; i < msg_data->cSignerHandle; i++)
{
- CryptDestroyKey(msg_data->signerHandles[i].key);
- CryptDestroyHash(msg_data->signerHandles[i].contentHash);
- CryptDestroyHash(msg_data->signerHandles[i].authAttrHash);
- CryptReleaseContext(msg_data->signerHandles[i].prov, 0);
+ if (msg_data->signerHandles[i].contentHash)
+ CryptDestroyHash(msg_data->signerHandles[i].contentHash);
+ if (msg_data->signerHandles[i].authAttrHash)
+ CryptDestroyHash(msg_data->signerHandles[i].authAttrHash);
}
CryptMemFree(msg_data->signerHandles);
+ msg_data->signerHandles = NULL;
+ msg_data->cSignerHandle = 0;
}
static BOOL CSignedMsgData_UpdateHash(CSignedMsgData *msg_data,
DWORD i;
BOOL ret = TRUE;
- for (i = 0; ret && i < msg_data->info->cSignerInfo; i++)
+ for (i = 0; ret && i < msg_data->cSignerHandle; i++)
ret = CryptHashData(msg_data->signerHandles[i].contentHash, pbData,
cbData, 0);
return ret;
}
-static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
-{
- CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
- DWORD i;
-
- CryptMemFree(msg->data.pbData);
- CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCertEncoded);
- CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCrlEncoded);
- for (i = 0; i < msg->msg_data.info->cSignerInfo; i++)
- CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]);
- CSignedMsgData_CloseHandles(&msg->msg_data);
- CryptMemFree(msg->msg_data.info->rgSignerInfo);
- CryptMemFree(msg->msg_data.info);
-}
-
-static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
- DWORD dwIndex, void *pvData, DWORD *pcbData)
-{
- CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
- BOOL ret = FALSE;
-
- switch (dwParamType)
- {
- case CMSG_CONTENT_PARAM:
- {
- CRYPT_CONTENT_INFO info;
-
- ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
- &info.Content.cbData);
- if (ret)
- {
- info.Content.pbData = CryptMemAlloc(info.Content.cbData);
- if (info.Content.pbData)
- {
- ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
- info.Content.pbData, &info.Content.cbData);
- if (ret)
- {
- char oid_rsa_signed[] = szOID_RSA_signedData;
-
- info.pszObjId = oid_rsa_signed;
- ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
- PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
- }
- CryptMemFree(info.Content.pbData);
- }
- else
- ret = FALSE;
- }
- break;
- }
- case CMSG_BARE_CONTENT_PARAM:
- {
- CRYPT_SIGNED_INFO info;
- char oid_rsa_data[] = szOID_RSA_data;
-
- memcpy(&info, msg->msg_data.info, sizeof(info));
- /* Quirk: OID is only encoded messages if an update has happened */
- if (msg->base.state != MsgStateInit)
- info.content.pszObjId = oid_rsa_data;
- else
- info.content.pszObjId = NULL;
- if (msg->data.cbData)
- {
- CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData };
-
- ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
- &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL,
- &info.content.Content.pbData, &info.content.Content.cbData);
- }
- else
- {
- info.content.Content.cbData = 0;
- info.content.Content.pbData = NULL;
- ret = TRUE;
- }
- if (ret)
- {
- ret = CRYPT_AsnEncodePKCSSignedInfo(&info, pvData, pcbData);
- LocalFree(info.content.Content.pbData);
- }
- break;
- }
- case CMSG_COMPUTED_HASH_PARAM:
- if (dwIndex >= msg->msg_data.info->cSignerInfo)
- SetLastError(CRYPT_E_INVALID_INDEX);
- else
- ret = CryptGetHashParam(
- msg->msg_data.signerHandles[dwIndex].contentHash, HP_HASHVAL,
- pvData, pcbData, 0);
- break;
- case CMSG_ENCODED_SIGNER:
- if (dwIndex >= msg->msg_data.info->cSignerInfo)
- SetLastError(CRYPT_E_INVALID_INDEX);
- else
- ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- PKCS7_SIGNER_INFO, &msg->msg_data.info->rgSignerInfo[dwIndex], 0,
- NULL, pvData, pcbData);
- break;
- case CMSG_VERSION_PARAM:
- ret = CRYPT_CopyParam(pvData, pcbData, &msg->msg_data.info->version,
- sizeof(msg->msg_data.info->version));
- break;
- default:
- SetLastError(CRYPT_E_INVALID_MSG_TYPE);
- }
- return ret;
-}
-
static BOOL CRYPT_AppendAttribute(CRYPT_ATTRIBUTES *out,
const CRYPT_ATTRIBUTE *in)
{
return ret;
}
+typedef enum {
+ Sign,
+ Verify
+} SignOrVerify;
+
static BOOL CSignedMsgData_UpdateAuthenticatedAttributes(
- CSignedMsgData *msg_data)
+ CSignedMsgData *msg_data, SignOrVerify flag)
{
DWORD i;
BOOL ret = TRUE;
{
if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr)
{
- BYTE oid_rsa_data_encoded[] = { 0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,
- 0x0d,0x01,0x07,0x01 };
- CRYPT_DATA_BLOB content = { sizeof(oid_rsa_data_encoded),
- oid_rsa_data_encoded };
- char contentType[] = szOID_RSA_contentType;
- CRYPT_ATTRIBUTE contentTypeAttr = { contentType, 1, &content };
-
- /* FIXME: does this depend on inner OID? */
- ret = CRYPT_AppendAttribute(
- &msg_data->info->rgSignerInfo[i].AuthAttrs, &contentTypeAttr);
- if (ret)
- ret = CSignedMsgData_AppendMessageDigestAttribute(msg_data, i);
+ if (flag == Sign)
+ {
+ BYTE oid_rsa_data_encoded[] = { 0x06,0x09,0x2a,0x86,0x48,0x86,
+ 0xf7,0x0d,0x01,0x07,0x01 };
+ CRYPT_DATA_BLOB content = { sizeof(oid_rsa_data_encoded),
+ oid_rsa_data_encoded };
+ char contentType[] = szOID_RSA_contentType;
+ CRYPT_ATTRIBUTE contentTypeAttr = { contentType, 1, &content };
+
+ /* FIXME: does this depend on inner OID? */
+ ret = CRYPT_AppendAttribute(
+ &msg_data->info->rgSignerInfo[i].AuthAttrs, &contentTypeAttr);
+ if (ret)
+ ret = CSignedMsgData_AppendMessageDigestAttribute(msg_data,
+ i);
+ }
if (ret)
{
LPBYTE encodedAttrs;
ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_ATTRIBUTES,
&msg_data->info->rgSignerInfo[i].AuthAttrs,
- CRYPT_ENCODE_ALLOC_FLAG, NULL, (LPBYTE)&encodedAttrs, &size);
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, &encodedAttrs, &size);
if (ret)
{
ret = CryptHashData(
}
static BOOL CSignedMsgData_Update(CSignedMsgData *msg_data,
- const BYTE *pbData, DWORD cbData, BOOL fFinal)
+ const BYTE *pbData, DWORD cbData, BOOL fFinal, SignOrVerify flag)
{
BOOL ret = CSignedMsgData_UpdateHash(msg_data, pbData, cbData);
if (ret && fFinal)
{
- ret = CSignedMsgData_UpdateAuthenticatedAttributes(msg_data);
- if (ret)
+ ret = CSignedMsgData_UpdateAuthenticatedAttributes(msg_data, flag);
+ if (ret && flag == Sign)
ret = CSignedMsgData_Sign(msg_data);
}
return ret;
}
-static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
- DWORD cbData, BOOL fFinal)
+typedef struct _CSignedEncodeMsg
+{
+ CryptMsgBase base;
+ LPSTR innerOID;
+ CRYPT_DATA_BLOB data;
+ CSignedMsgData msg_data;
+} CSignedEncodeMsg;
+
+static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
+{
+ CSignedEncodeMsg *msg = hCryptMsg;
+ DWORD i;
+
+ CryptMemFree(msg->innerOID);
+ CryptMemFree(msg->data.pbData);
+ CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCertEncoded);
+ CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCrlEncoded);
+ for (i = 0; i < msg->msg_data.info->cSignerInfo; i++)
+ CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]);
+ CSignedMsgData_CloseHandles(&msg->msg_data);
+ CryptMemFree(msg->msg_data.info->rgSignerInfo);
+ CryptMemFree(msg->msg_data.info);
+}
+
+static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
+ DWORD dwIndex, void *pvData, DWORD *pcbData)
{
- CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
+ CSignedEncodeMsg *msg = hCryptMsg;
BOOL ret = FALSE;
- if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
+ switch (dwParamType)
{
- ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, fFinal);
- if (msg->base.streamed)
- FIXME("streamed partial stub\n");
- }
- else
+ case CMSG_CONTENT_PARAM:
+ {
+ CRYPT_CONTENT_INFO info;
+
+ ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
+ &info.Content.cbData);
+ if (ret)
+ {
+ info.Content.pbData = CryptMemAlloc(info.Content.cbData);
+ if (info.Content.pbData)
+ {
+ ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
+ info.Content.pbData, &info.Content.cbData);
+ if (ret)
+ {
+ char oid_rsa_signed[] = szOID_RSA_signedData;
+
+ info.pszObjId = oid_rsa_signed;
+ ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
+ PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
+ }
+ CryptMemFree(info.Content.pbData);
+ }
+ else
+ ret = FALSE;
+ }
+ break;
+ }
+ case CMSG_BARE_CONTENT_PARAM:
+ {
+ CRYPT_SIGNED_INFO info;
+ BOOL freeContent = FALSE;
+
+ info = *msg->msg_data.info;
+ if (!msg->innerOID || !strcmp(msg->innerOID, szOID_RSA_data))
+ {
+ char oid_rsa_data[] = szOID_RSA_data;
+
+ /* Quirk: OID is only encoded messages if an update has happened */
+ if (msg->base.state != MsgStateInit)
+ info.content.pszObjId = oid_rsa_data;
+ else
+ info.content.pszObjId = NULL;
+ if (msg->data.cbData)
+ {
+ CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData };
+
+ ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
+ &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL,
+ &info.content.Content.pbData, &info.content.Content.cbData);
+ freeContent = TRUE;
+ }
+ else
+ {
+ info.content.Content.cbData = 0;
+ info.content.Content.pbData = NULL;
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ info.content.pszObjId = msg->innerOID;
+ info.content.Content.cbData = msg->data.cbData;
+ info.content.Content.pbData = msg->data.pbData;
+ ret = TRUE;
+ }
+ if (ret)
+ {
+ ret = CRYPT_AsnEncodeCMSSignedInfo(&info, pvData, pcbData);
+ if (freeContent)
+ LocalFree(info.content.Content.pbData);
+ }
+ break;
+ }
+ case CMSG_COMPUTED_HASH_PARAM:
+ if (dwIndex >= msg->msg_data.cSignerHandle)
+ SetLastError(CRYPT_E_INVALID_INDEX);
+ else
+ ret = CryptGetHashParam(
+ msg->msg_data.signerHandles[dwIndex].contentHash, HP_HASHVAL,
+ pvData, pcbData, 0);
+ break;
+ case CMSG_ENCODED_SIGNER:
+ if (dwIndex >= msg->msg_data.info->cSignerInfo)
+ SetLastError(CRYPT_E_INVALID_INDEX);
+ else
+ ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ CMS_SIGNER_INFO, &msg->msg_data.info->rgSignerInfo[dwIndex], 0,
+ NULL, pvData, pcbData);
+ break;
+ case CMSG_VERSION_PARAM:
+ ret = CRYPT_CopyParam(pvData, pcbData, &msg->msg_data.info->version,
+ sizeof(msg->msg_data.info->version));
+ break;
+ default:
+ SetLastError(CRYPT_E_INVALID_MSG_TYPE);
+ }
+ return ret;
+}
+
+static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
+ DWORD cbData, BOOL fFinal)
+{
+ CSignedEncodeMsg *msg = hCryptMsg;
+ BOOL ret = FALSE;
+
+ if (msg->base.state == MsgStateFinalized)
+ SetLastError(CRYPT_E_MSG_ERROR);
+ else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
+ {
+ ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, fFinal,
+ Sign);
+ if (msg->base.streamed)
+ FIXME("streamed partial stub\n");
+ msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
+ }
+ else
{
if (!fFinal)
SetLastError(CRYPT_E_MSG_ERROR);
ret = TRUE;
if (ret)
ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData,
- fFinal);
+ fFinal, Sign);
+ msg->base.state = MsgStateFinalized;
}
}
return ret;
const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
PCMSG_STREAM_INFO pStreamInfo)
{
- const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *info =
- (const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *)pvMsgEncodeInfo;
+ const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *info = pvMsgEncodeInfo;
DWORD i;
CSignedEncodeMsg *msg;
SetLastError(E_INVALIDARG);
return NULL;
}
- if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS))
+ if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS) &&
+ info->cAttrCertEncoded)
{
FIXME("CMSG_SIGNED_ENCODE_INFO with CMS fields unsupported\n");
return NULL;
CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
CSignedEncodeMsg_Close, CSignedEncodeMsg_GetParam,
CSignedEncodeMsg_Update, CRYPT_DefaultMsgControl);
+ if (pszInnerContentObjID)
+ {
+ msg->innerOID = CryptMemAlloc(strlen(pszInnerContentObjID) + 1);
+ if (msg->innerOID)
+ strcpy(msg->innerOID, pszInnerContentObjID);
+ else
+ ret = FALSE;
+ }
+ else
+ msg->innerOID = NULL;
msg->data.cbData = 0;
msg->data.pbData = NULL;
- msg->msg_data.info = CryptMemAlloc(sizeof(CRYPT_SIGNED_INFO));
+ if (ret)
+ msg->msg_data.info = CryptMemAlloc(sizeof(CRYPT_SIGNED_INFO));
+ else
+ msg->msg_data.info = NULL;
if (msg->msg_data.info)
{
memset(msg->msg_data.info, 0, sizeof(CRYPT_SIGNED_INFO));
}
else
ret = FALSE;
- if (ret && info->cSigners)
+ if (ret)
{
- msg->msg_data.signerHandles =
- CryptMemAlloc(info->cSigners * sizeof(CSignerHandles));
- if (msg->msg_data.signerHandles)
- msg->msg_data.info->rgSignerInfo =
- CryptMemAlloc(info->cSigners * sizeof(CMSG_SIGNER_INFO));
- else
+ if (info->cSigners)
{
- ret = FALSE;
- msg->msg_data.info->rgSignerInfo = NULL;
+ msg->msg_data.info->rgSignerInfo =
+ CryptMemAlloc(info->cSigners * sizeof(CMSG_CMS_SIGNER_INFO));
+ if (msg->msg_data.info->rgSignerInfo)
+ {
+ msg->msg_data.info->cSignerInfo = info->cSigners;
+ memset(msg->msg_data.info->rgSignerInfo, 0,
+ msg->msg_data.info->cSignerInfo *
+ sizeof(CMSG_CMS_SIGNER_INFO));
+ ret = CSignedMsgData_AllocateHandles(&msg->msg_data);
+ for (i = 0; ret && i < msg->msg_data.info->cSignerInfo; i++)
+ {
+ if (info->rgSigners[i].SignerId.dwIdChoice ==
+ CERT_ID_KEY_IDENTIFIER)
+ msg->msg_data.info->version = CMSG_SIGNED_DATA_V3;
+ ret = CSignerInfo_Construct(
+ &msg->msg_data.info->rgSignerInfo[i],
+ &info->rgSigners[i]);
+ if (ret)
+ {
+ ret = CSignedMsgData_ConstructSignerHandles(
+ &msg->msg_data, i, info->rgSigners[i].hCryptProv);
+ if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
+ CryptReleaseContext(info->rgSigners[i].hCryptProv,
+ 0);
+ }
+ }
+ }
+ else
+ ret = FALSE;
}
- if (msg->msg_data.info->rgSignerInfo)
+ else
{
- msg->msg_data.info->cSignerInfo = info->cSigners;
- memset(msg->msg_data.signerHandles, 0,
- msg->msg_data.info->cSignerInfo * sizeof(CSignerHandles));
- memset(msg->msg_data.info->rgSignerInfo, 0,
- msg->msg_data.info->cSignerInfo * sizeof(CMSG_SIGNER_INFO));
- for (i = 0; ret && i < msg->msg_data.info->cSignerInfo; i++)
- ret = CSignerInfo_Construct(&msg->msg_data.signerHandles[i],
- &msg->msg_data.info->rgSignerInfo[i],
- &info->rgSigners[i], dwFlags);
+ msg->msg_data.info->cSignerInfo = 0;
+ msg->msg_data.signerHandles = NULL;
+ msg->msg_data.cSignerHandle = 0;
}
- else
- ret = FALSE;
}
if (ret)
ret = CRYPT_ConstructBlobArray(
return msg;
}
-static inline const char *MSG_TYPE_STR(DWORD type)
-{
- switch (type)
- {
-#define _x(x) case (x): return #x
- _x(CMSG_DATA);
- _x(CMSG_SIGNED);
- _x(CMSG_ENVELOPED);
- _x(CMSG_SIGNED_AND_ENVELOPED);
- _x(CMSG_HASHED);
- _x(CMSG_ENCRYPTED);
-#undef _x
- default:
- return wine_dbg_sprintf("unknown (%d)", type);
- }
-}
-
HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags,
DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
PCMSG_STREAM_INFO pStreamInfo)
pszInnerContentObjID, pStreamInfo);
break;
case CMSG_ENVELOPED:
- FIXME("unimplemented for type %s\n", MSG_TYPE_STR(dwMsgType));
+ FIXME("unimplemented for type CMSG_ENVELOPED\n");
break;
case CMSG_SIGNED_AND_ENVELOPED:
case CMSG_ENCRYPTED:
CSignedMsgData signed_data;
} u;
CRYPT_DATA_BLOB msg_data;
+ CRYPT_DATA_BLOB detached_data;
PCONTEXT_PROPERTY_LIST properties;
} CDecodeMsg;
static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg)
{
- CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
+ CDecodeMsg *msg = hCryptMsg;
if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
CryptReleaseContext(msg->crypt_prov, 0);
break;
case CMSG_SIGNED:
if (msg->u.signed_data.info)
+ {
LocalFree(msg->u.signed_data.info);
+ CSignedMsgData_CloseHandles(&msg->u.signed_data);
+ }
break;
}
CryptMemFree(msg->msg_data.pbData);
+ CryptMemFree(msg->detached_data.pbData);
ContextPropertyList_Free(msg->properties);
}
-static BOOL CDecodeMsg_CopyData(CDecodeMsg *msg, const BYTE *pbData,
+static BOOL CDecodeMsg_CopyData(CRYPT_DATA_BLOB *blob, const BYTE *pbData,
DWORD cbData)
{
BOOL ret = TRUE;
if (cbData)
{
- if (msg->msg_data.cbData)
- msg->msg_data.pbData = CryptMemRealloc(msg->msg_data.pbData,
- msg->msg_data.cbData + cbData);
+ if (blob->cbData)
+ blob->pbData = CryptMemRealloc(blob->pbData,
+ blob->cbData + cbData);
else
- msg->msg_data.pbData = CryptMemAlloc(cbData);
- if (msg->msg_data.pbData)
+ blob->pbData = CryptMemAlloc(cbData);
+ if (blob->pbData)
{
- memcpy(msg->msg_data.pbData + msg->msg_data.cbData, pbData, cbData);
- msg->msg_data.cbData += cbData;
+ memcpy(blob->pbData + blob->cbData, pbData, cbData);
+ blob->cbData += cbData;
}
else
ret = FALSE;
DWORD size;
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
- blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&data,
- &size);
+ blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &data, &size);
if (ret)
{
ret = ContextPropertyList_SetProperty(msg->properties,
(const BYTE *)digestedData->ContentInfo.pszObjId,
digestedData->ContentInfo.pszObjId ?
strlen(digestedData->ContentInfo.pszObjId) + 1 : 0);
- if (digestedData->ContentInfo.Content.cbData)
- CDecodeMsg_DecodeDataContent(msg,
- &digestedData->ContentInfo.Content);
- else
- ContextPropertyList_SetProperty(msg->properties,
- CMSG_CONTENT_PARAM, NULL, 0);
+ if (!(msg->base.open_flags & CMSG_DETACHED_FLAG))
+ {
+ if (digestedData->ContentInfo.Content.cbData)
+ CDecodeMsg_DecodeDataContent(msg,
+ &digestedData->ContentInfo.Content);
+ else
+ ContextPropertyList_SetProperty(msg->properties,
+ CMSG_CONTENT_PARAM, NULL, 0);
+ }
ContextPropertyList_SetProperty(msg->properties, CMSG_HASH_DATA_PARAM,
digestedData->hash.pbData, digestedData->hash.cbData);
LocalFree(digestedData);
CRYPT_SIGNED_INFO *signedInfo;
DWORD size;
- ret = CRYPT_AsnDecodePKCSSignedInfo(blob->pbData, blob->cbData,
+ ret = CRYPT_AsnDecodeCMSSignedInfo(blob->pbData, blob->cbData,
CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_SIGNED_INFO *)&signedInfo,
&size);
if (ret)
msg->u.signed_data.info = signedInfo;
return ret;
}
+
/* Decodes the content in blob as the type given, and updates the value
* (type, parameters, etc.) of msg based on what blob contains.
* It doesn't just use msg's type, to allow a recursive call from an implicitly
msg->type = CMSG_HASHED;
break;
case CMSG_ENVELOPED:
- FIXME("unimplemented for type %s\n", MSG_TYPE_STR(type));
+ FIXME("unimplemented for type CMSG_ENVELOPED\n");
ret = TRUE;
break;
case CMSG_SIGNED:
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO,
msg->msg_data.pbData, msg->msg_data.cbData, CRYPT_DECODE_ALLOC_FLAG,
- NULL, (LPBYTE)&info, &size);
+ NULL, &info, &size);
if (ret)
{
if (!strcmp(info->pszObjId, szOID_RSA_data))
return ret;
}
+static BOOL CDecodeMsg_FinalizeHashedContent(CDecodeMsg *msg,
+ CRYPT_DER_BLOB *blob)
+{
+ CRYPT_ALGORITHM_IDENTIFIER *hashAlgoID = NULL;
+ DWORD size = 0;
+ ALG_ID algID = 0;
+ BOOL ret;
+
+ CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, NULL, &size);
+ hashAlgoID = CryptMemAlloc(size);
+ ret = CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, hashAlgoID,
+ &size);
+ if (ret)
+ algID = CertOIDToAlgId(hashAlgoID->pszObjId);
+ ret = CryptCreateHash(msg->crypt_prov, algID, 0, 0, &msg->u.hash);
+ if (ret)
+ {
+ CRYPT_DATA_BLOB content;
+
+ if (msg->base.open_flags & CMSG_DETACHED_FLAG)
+ {
+ /* Unlike for non-detached messages, the data were never stored as
+ * the content param, but were saved in msg->detached_data instead.
+ */
+ content.pbData = msg->detached_data.pbData;
+ content.cbData = msg->detached_data.cbData;
+ }
+ else
+ ret = ContextPropertyList_FindProperty(msg->properties,
+ CMSG_CONTENT_PARAM, &content);
+ if (ret)
+ ret = CryptHashData(msg->u.hash, content.pbData, content.cbData, 0);
+ }
+ CryptMemFree(hashAlgoID);
+ return ret;
+}
+
+static BOOL CDecodeMsg_FinalizeSignedContent(CDecodeMsg *msg,
+ CRYPT_DER_BLOB *blob)
+{
+ BOOL ret;
+ DWORD i, size;
+
+ ret = CSignedMsgData_AllocateHandles(&msg->u.signed_data);
+ for (i = 0; ret && i < msg->u.signed_data.info->cSignerInfo; i++)
+ ret = CSignedMsgData_ConstructSignerHandles(&msg->u.signed_data, i,
+ msg->crypt_prov);
+ if (ret)
+ {
+ CRYPT_DATA_BLOB *content;
+
+ /* Now that we have all the content, update the hash handles with
+ * it. If the message is a detached message, the content is stored
+ * in msg->detached_data rather than in the signed message's
+ * content.
+ */
+ if (msg->base.open_flags & CMSG_DETACHED_FLAG)
+ content = &msg->detached_data;
+ else
+ content = &msg->u.signed_data.info->content.Content;
+ if (content->cbData)
+ {
+ /* If the message is not detached, have to decode the message's
+ * content if the type is szOID_RSA_data.
+ */
+ if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) &&
+ !strcmp(msg->u.signed_data.info->content.pszObjId,
+ szOID_RSA_data))
+ {
+ CRYPT_DATA_BLOB *blob;
+
+ ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
+ X509_OCTET_STRING, content->pbData, content->cbData,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &blob, &size);
+ if (ret)
+ {
+ ret = CSignedMsgData_Update(&msg->u.signed_data,
+ blob->pbData, blob->cbData, TRUE, Verify);
+ LocalFree(blob);
+ }
+ }
+ else
+ ret = CSignedMsgData_Update(&msg->u.signed_data,
+ content->pbData, content->cbData, TRUE, Verify);
+ }
+ }
+ return ret;
+}
+
+static BOOL CDecodeMsg_FinalizeContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob)
+{
+ BOOL ret = FALSE;
+
+ switch (msg->type)
+ {
+ case CMSG_HASHED:
+ ret = CDecodeMsg_FinalizeHashedContent(msg, blob);
+ break;
+ case CMSG_SIGNED:
+ ret = CDecodeMsg_FinalizeSignedContent(msg, blob);
+ break;
+ default:
+ ret = TRUE;
+ }
+ return ret;
+}
+
static BOOL CDecodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
DWORD cbData, BOOL fFinal)
{
- CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
+ CDecodeMsg *msg = hCryptMsg;
BOOL ret = FALSE;
TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
- if (msg->base.streamed)
+ if (msg->base.state == MsgStateFinalized)
+ SetLastError(CRYPT_E_MSG_ERROR);
+ else if (msg->base.streamed)
{
- ret = CDecodeMsg_CopyData(msg, pbData, cbData);
FIXME("(%p, %p, %d, %d): streamed update stub\n", hCryptMsg, pbData,
cbData, fFinal);
+ switch (msg->base.state)
+ {
+ case MsgStateInit:
+ ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
+ if (fFinal)
+ {
+ if (msg->base.open_flags & CMSG_DETACHED_FLAG)
+ msg->base.state = MsgStateDataFinalized;
+ else
+ msg->base.state = MsgStateFinalized;
+ }
+ else
+ msg->base.state = MsgStateUpdated;
+ break;
+ case MsgStateUpdated:
+ ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
+ if (fFinal)
+ {
+ if (msg->base.open_flags & CMSG_DETACHED_FLAG)
+ msg->base.state = MsgStateDataFinalized;
+ else
+ msg->base.state = MsgStateFinalized;
+ }
+ break;
+ case MsgStateDataFinalized:
+ ret = CDecodeMsg_CopyData(&msg->detached_data, pbData, cbData);
+ if (fFinal)
+ msg->base.state = MsgStateFinalized;
+ break;
+ default:
+ SetLastError(CRYPT_E_MSG_ERROR);
+ break;
+ }
}
else
{
SetLastError(CRYPT_E_MSG_ERROR);
else
{
- ret = CDecodeMsg_CopyData(msg, pbData, cbData);
- if (ret)
- ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data, msg->type);
-
+ switch (msg->base.state)
+ {
+ case MsgStateInit:
+ ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
+ if (msg->base.open_flags & CMSG_DETACHED_FLAG)
+ msg->base.state = MsgStateDataFinalized;
+ else
+ msg->base.state = MsgStateFinalized;
+ break;
+ case MsgStateDataFinalized:
+ ret = CDecodeMsg_CopyData(&msg->detached_data, pbData, cbData);
+ msg->base.state = MsgStateFinalized;
+ break;
+ default:
+ SetLastError(CRYPT_E_MSG_ERROR);
+ }
}
}
+ if (ret && fFinal &&
+ ((msg->base.open_flags & CMSG_DETACHED_FLAG && msg->base.state ==
+ MsgStateDataFinalized) ||
+ (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->base.state ==
+ MsgStateFinalized)))
+ ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data, msg->type);
+ if (ret && msg->base.state == MsgStateFinalized)
+ ret = CDecodeMsg_FinalizeContent(msg, &msg->msg_data);
return ret;
}
{
ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
if (ret && pvData)
- CRYPT_FixUpAlgorithmID((CRYPT_ALGORITHM_IDENTIFIER *)pvData);
+ CRYPT_FixUpAlgorithmID(pvData);
}
else
SetLastError(CRYPT_E_INVALID_MSG_TYPE);
break;
}
case CMSG_COMPUTED_HASH_PARAM:
- if (!msg->u.hash)
- {
- CRYPT_ALGORITHM_IDENTIFIER *hashAlgoID = NULL;
- DWORD size = 0;
- ALG_ID algID = 0;
-
- CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, NULL, &size);
- hashAlgoID = CryptMemAlloc(size);
- ret = CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0,
- hashAlgoID, &size);
- if (ret)
- algID = CertOIDToAlgId(hashAlgoID->pszObjId);
- ret = CryptCreateHash(msg->crypt_prov, algID, 0, 0, &msg->u.hash);
- if (ret)
- {
- CRYPT_DATA_BLOB content;
-
- ret = ContextPropertyList_FindProperty(msg->properties,
- CMSG_CONTENT_PARAM, &content);
- if (ret)
- ret = CryptHashData(msg->u.hash, content.pbData,
- content.cbData, 0);
- }
- CryptMemFree(hashAlgoID);
- }
- else
- ret = TRUE;
- if (ret)
- ret = CryptGetHashParam(msg->u.hash, HP_HASHVAL, pvData, pcbData,
- 0);
+ ret = CryptGetHashParam(msg->u.hash, HP_HASHVAL, pvData, pcbData, 0);
break;
default:
{
{
DWORD i;
- if ((*nextData - (LPBYTE)0) % sizeof(DWORD))
- *nextData += (*nextData - (LPBYTE)0) % sizeof(DWORD);
+ *nextData = POINTER_ALIGN_DWORD_PTR(*nextData);
out->rgAttr = (CRYPT_ATTRIBUTE *)*nextData;
*nextData += in->cAttr * sizeof(CRYPT_ATTRIBUTE);
for (i = 0; i < in->cAttr; i++)
DWORD j;
out->rgAttr[i].cValue = in->rgAttr[i].cValue;
- if ((*nextData - (LPBYTE)0) % sizeof(DWORD))
- *nextData += (*nextData - (LPBYTE)0) % sizeof(DWORD);
+ *nextData = POINTER_ALIGN_DWORD_PTR(*nextData);
out->rgAttr[i].rgValue = (PCRYPT_DATA_BLOB)*nextData;
+ *nextData += in->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
for (j = 0; j < in->rgAttr[i].cValue; j++)
CRYPT_CopyBlob(&out->rgAttr[i].rgValue[j],
&in->rgAttr[i].rgValue[j], nextData);
if (attr->rgAttr[i].pszObjId)
size += strlen(attr->rgAttr[i].pszObjId) + 1;
/* align pointer */
- if (size % sizeof(DWORD))
- size += size % sizeof(DWORD);
+ size = ALIGN_DWORD_PTR(size);
size += attr->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
for (j = 0; j < attr->rgAttr[i].cValue; j++)
size += attr->rgAttr[i].rgValue[j].cbData;
}
+ /* align pointer again to be conservative */
+ size = ALIGN_DWORD_PTR(size);
return size;
}
+static DWORD CRYPT_SizeOfKeyIdAsIssuerAndSerial(const CRYPT_DATA_BLOB *keyId)
+{
+ static char oid_key_rdn[] = szOID_KEYID_RDN;
+ DWORD size = 0;
+ CERT_RDN_ATTR attr;
+ CERT_RDN rdn = { 1, &attr };
+ CERT_NAME_INFO name = { 1, &rdn };
+
+ attr.pszObjId = oid_key_rdn;
+ attr.dwValueType = CERT_RDN_OCTET_STRING;
+ attr.Value.cbData = keyId->cbData;
+ attr.Value.pbData = keyId->pbData;
+ if (CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &name, NULL, &size))
+ size++; /* Only include size of special zero serial number on success */
+ return size;
+}
+
+static BOOL CRYPT_CopyKeyIdAsIssuerAndSerial(CERT_NAME_BLOB *issuer,
+ CRYPT_INTEGER_BLOB *serialNumber, const CRYPT_DATA_BLOB *keyId, DWORD encodedLen,
+ LPBYTE *nextData)
+{
+ static char oid_key_rdn[] = szOID_KEYID_RDN;
+ CERT_RDN_ATTR attr;
+ CERT_RDN rdn = { 1, &attr };
+ CERT_NAME_INFO name = { 1, &rdn };
+ BOOL ret;
+
+ /* Encode special zero serial number */
+ serialNumber->cbData = 1;
+ serialNumber->pbData = *nextData;
+ **nextData = 0;
+ (*nextData)++;
+ /* Encode issuer */
+ issuer->pbData = *nextData;
+ attr.pszObjId = oid_key_rdn;
+ attr.dwValueType = CERT_RDN_OCTET_STRING;
+ attr.Value.cbData = keyId->cbData;
+ attr.Value.pbData = keyId->pbData;
+ ret = CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &name, *nextData,
+ &encodedLen);
+ if (ret)
+ {
+ *nextData += encodedLen;
+ issuer->cbData = encodedLen;
+ }
+ return ret;
+}
+
static BOOL CRYPT_CopySignerInfo(void *pvData, DWORD *pcbData,
- const CMSG_SIGNER_INFO *in)
+ const CMSG_CMS_SIGNER_INFO *in)
{
- DWORD size = sizeof(CMSG_SIGNER_INFO);
+ DWORD size = sizeof(CMSG_SIGNER_INFO), rdnSize = 0;
BOOL ret;
- size += in->Issuer.cbData;
- size += in->SerialNumber.cbData;
+ TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
+
+ if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
+ {
+ size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData;
+ size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData;
+ }
+ else
+ {
+ rdnSize = CRYPT_SizeOfKeyIdAsIssuerAndSerial(&in->SignerId.u.KeyId);
+ size += rdnSize;
+ }
if (in->HashAlgorithm.pszObjId)
size += strlen(in->HashAlgorithm.pszObjId) + 1;
size += in->HashAlgorithm.Parameters.cbData;
size += in->HashEncryptionAlgorithm.Parameters.cbData;
size += in->EncryptedHash.cbData;
/* align pointer */
- if (size % sizeof(DWORD))
- size += size % sizeof(DWORD);
+ size = ALIGN_DWORD_PTR(size);
size += CRYPT_SizeOfAttributes(&in->AuthAttrs);
size += CRYPT_SizeOfAttributes(&in->UnauthAttrs);
if (!pvData)
else
{
LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_SIGNER_INFO);
- CMSG_SIGNER_INFO *out = (CMSG_SIGNER_INFO *)pvData;
+ CMSG_SIGNER_INFO *out = pvData;
+ ret = TRUE;
out->dwVersion = in->dwVersion;
- CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData);
- CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData);
+ if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
+ {
+ CRYPT_CopyBlob(&out->Issuer,
+ &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData);
+ CRYPT_CopyBlob(&out->SerialNumber,
+ &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData);
+ }
+ else
+ ret = CRYPT_CopyKeyIdAsIssuerAndSerial(&out->Issuer, &out->SerialNumber,
+ &in->SignerId.u.KeyId, rdnSize, &nextData);
+ if (ret)
+ {
+ CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm,
+ &nextData);
+ CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm,
+ &in->HashEncryptionAlgorithm, &nextData);
+ CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData);
+ nextData = POINTER_ALIGN_DWORD_PTR(nextData);
+ CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData);
+ CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData);
+ }
+ }
+ TRACE("returning %d\n", ret);
+ return ret;
+}
+
+static BOOL CRYPT_CopyCMSSignerInfo(void *pvData, DWORD *pcbData,
+ const CMSG_CMS_SIGNER_INFO *in)
+{
+ DWORD size = sizeof(CMSG_CMS_SIGNER_INFO);
+ BOOL ret;
+
+ TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
+
+ if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
+ {
+ size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData;
+ size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData;
+ }
+ else
+ size += in->SignerId.u.KeyId.cbData;
+ if (in->HashAlgorithm.pszObjId)
+ size += strlen(in->HashAlgorithm.pszObjId) + 1;
+ size += in->HashAlgorithm.Parameters.cbData;
+ if (in->HashEncryptionAlgorithm.pszObjId)
+ size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1;
+ size += in->HashEncryptionAlgorithm.Parameters.cbData;
+ size += in->EncryptedHash.cbData;
+ /* align pointer */
+ size = ALIGN_DWORD_PTR(size);
+ size += CRYPT_SizeOfAttributes(&in->AuthAttrs);
+ size += CRYPT_SizeOfAttributes(&in->UnauthAttrs);
+ if (!pvData)
+ {
+ *pcbData = size;
+ ret = TRUE;
+ }
+ else if (*pcbData < size)
+ {
+ *pcbData = size;
+ SetLastError(ERROR_MORE_DATA);
+ ret = FALSE;
+ }
+ else
+ {
+ LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_CMS_SIGNER_INFO);
+ CMSG_CMS_SIGNER_INFO *out = pvData;
+
+ out->dwVersion = in->dwVersion;
+ out->SignerId.dwIdChoice = in->SignerId.dwIdChoice;
+ if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
+ {
+ CRYPT_CopyBlob(&out->SignerId.u.IssuerSerialNumber.Issuer,
+ &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData);
+ CRYPT_CopyBlob(&out->SignerId.u.IssuerSerialNumber.SerialNumber,
+ &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData);
+ }
+ else
+ CRYPT_CopyBlob(&out->SignerId.u.KeyId, &in->SignerId.u.KeyId, &nextData);
CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm,
&nextData);
CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm,
&in->HashEncryptionAlgorithm, &nextData);
CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData);
- /* align pointer */
- if ((nextData - (LPBYTE)0) % sizeof(DWORD))
- nextData += (nextData - (LPBYTE)0) % sizeof(DWORD);
+ nextData = POINTER_ALIGN_DWORD_PTR(nextData);
CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData);
CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData);
ret = TRUE;
}
+ TRACE("returning %d\n", ret);
return ret;
}
static BOOL CRYPT_CopySignerCertInfo(void *pvData, DWORD *pcbData,
- const CMSG_SIGNER_INFO *in)
+ const CMSG_CMS_SIGNER_INFO *in)
{
- DWORD size = sizeof(CERT_INFO);
+ DWORD size = sizeof(CERT_INFO), rdnSize = 0;
BOOL ret;
- size += in->Issuer.cbData;
- size += in->SerialNumber.cbData;
+ TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
+
+ if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
+ {
+ size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData;
+ size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData;
+ }
+ else
+ {
+ rdnSize = CRYPT_SizeOfKeyIdAsIssuerAndSerial(&in->SignerId.u.KeyId);
+ size += rdnSize;
+ }
if (!pvData)
{
*pcbData = size;
else
{
LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO);
- CERT_INFO *out = (CERT_INFO *)pvData;
+ CERT_INFO *out = pvData;
memset(out, 0, sizeof(CERT_INFO));
- CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData);
- CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData);
- ret = TRUE;
+ if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
+ {
+ CRYPT_CopyBlob(&out->Issuer,
+ &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData);
+ CRYPT_CopyBlob(&out->SerialNumber,
+ &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData);
+ ret = TRUE;
+ }
+ else
+ ret = CRYPT_CopyKeyIdAsIssuerAndSerial(&out->Issuer, &out->SerialNumber,
+ &in->SignerId.u.KeyId, rdnSize, &nextData);
}
+ TRACE("returning %d\n", ret);
return ret;
}
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
msg->u.signed_data.info->content.Content.pbData,
msg->u.signed_data.info->content.Content.cbData,
- CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&blob, &size);
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &blob, &size);
if (ret)
{
ret = CRYPT_CopyParam(pvData, pcbData, blob->pbData,
else
SetLastError(CRYPT_E_INVALID_MSG_TYPE);
break;
+ case CMSG_COMPUTED_HASH_PARAM:
+ if (msg->u.signed_data.info)
+ {
+ if (dwIndex >= msg->u.signed_data.cSignerHandle)
+ SetLastError(CRYPT_E_INVALID_INDEX);
+ else
+ ret = CryptGetHashParam(
+ msg->u.signed_data.signerHandles[dwIndex].contentHash,
+ HP_HASHVAL, pvData, pcbData, 0);
+ }
+ else
+ SetLastError(CRYPT_E_INVALID_MSG_TYPE);
+ break;
case CMSG_ATTR_CERT_COUNT_PARAM:
if (msg->u.signed_data.info)
{
else
SetLastError(CRYPT_E_INVALID_MSG_TYPE);
break;
+ case CMSG_CMS_SIGNER_INFO_PARAM:
+ if (msg->u.signed_data.info)
+ {
+ if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
+ SetLastError(CRYPT_E_INVALID_INDEX);
+ else
+ ret = CRYPT_CopyCMSSignerInfo(pvData, pcbData,
+ &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
+ }
+ else
+ SetLastError(CRYPT_E_INVALID_MSG_TYPE);
+ break;
default:
FIXME("unimplemented for %d\n", dwParamType);
SetLastError(CRYPT_E_INVALID_MSG_TYPE);
static BOOL CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
DWORD dwIndex, void *pvData, DWORD *pcbData)
{
- CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
+ CDecodeMsg *msg = hCryptMsg;
BOOL ret = FALSE;
switch (msg->type)
ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
computedHash, &computedHashSize);
if (ret)
- ret = !memcmp(hashBlob.pbData, computedHash,
- hashBlob.cbData);
+ {
+ if (memcmp(hashBlob.pbData, computedHash, hashBlob.cbData))
+ {
+ SetLastError(CRYPT_E_HASH_VALUE);
+ ret = FALSE;
+ }
+ }
+ CryptMemFree(computedHash);
}
else
+ {
+ SetLastError(ERROR_OUTOFMEMORY);
ret = FALSE;
+ }
+ }
+ else
+ {
+ SetLastError(CRYPT_E_HASH_VALUE);
+ ret = FALSE;
+ }
+ }
+ return ret;
+}
+
+static BOOL CDecodeSignedMsg_VerifySignatureWithKey(CDecodeMsg *msg,
+ HCRYPTPROV prov, DWORD signerIndex, PCERT_PUBLIC_KEY_INFO keyInfo)
+{
+ HCRYPTKEY key;
+ BOOL ret;
+
+ if (!prov)
+ prov = msg->crypt_prov;
+ ret = CryptImportPublicKeyInfo(prov, X509_ASN_ENCODING, keyInfo, &key);
+ if (ret)
+ {
+ HCRYPTHASH hash;
+ CRYPT_HASH_BLOB reversedHash;
+
+ if (msg->u.signed_data.info->rgSignerInfo[signerIndex].AuthAttrs.cAttr)
+ hash = msg->u.signed_data.signerHandles[signerIndex].authAttrHash;
+ else
+ hash = msg->u.signed_data.signerHandles[signerIndex].contentHash;
+ ret = CRYPT_ConstructBlob(&reversedHash,
+ &msg->u.signed_data.info->rgSignerInfo[signerIndex].EncryptedHash);
+ if (ret)
+ {
+ CRYPT_ReverseBytes(&reversedHash);
+ ret = CryptVerifySignatureW(hash, reversedHash.pbData,
+ reversedHash.cbData, key, NULL, 0);
+ CryptMemFree(reversedHash.pbData);
+ }
+ CryptDestroyKey(key);
+ }
+ return ret;
+}
+
+static BOOL CDecodeSignedMsg_VerifySignature(CDecodeMsg *msg, PCERT_INFO info)
+{
+ BOOL ret = FALSE;
+ DWORD i;
+
+ if (!msg->u.signed_data.signerHandles)
+ {
+ SetLastError(NTE_BAD_SIGNATURE);
+ return FALSE;
+ }
+ for (i = 0; !ret && i < msg->u.signed_data.info->cSignerInfo; i++)
+ {
+ PCMSG_CMS_SIGNER_INFO signerInfo =
+ &msg->u.signed_data.info->rgSignerInfo[i];
+
+ if (signerInfo->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
+ {
+ ret = CertCompareCertificateName(X509_ASN_ENCODING,
+ &signerInfo->SignerId.u.IssuerSerialNumber.Issuer,
+ &info->Issuer);
+ if (ret)
+ {
+ ret = CertCompareIntegerBlob(
+ &signerInfo->SignerId.u.IssuerSerialNumber.SerialNumber,
+ &info->SerialNumber);
+ if (ret)
+ break;
+ }
+ }
+ else
+ {
+ FIXME("signer %d: unimplemented for key id\n", i);
+ }
+ }
+ if (ret)
+ ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, 0, i,
+ &info->SubjectPublicKeyInfo);
+ else
+ SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
+
+ return ret;
+}
+
+static BOOL CDecodeSignedMsg_VerifySignatureEx(CDecodeMsg *msg,
+ PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para)
+{
+ BOOL ret = FALSE;
+
+ if (para->cbSize != sizeof(CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA))
+ SetLastError(ERROR_INVALID_PARAMETER);
+ else if (para->dwSignerIndex >= msg->u.signed_data.info->cSignerInfo)
+ SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
+ else if (!msg->u.signed_data.signerHandles)
+ SetLastError(NTE_BAD_SIGNATURE);
+ else
+ {
+ switch (para->dwSignerType)
+ {
+ case CMSG_VERIFY_SIGNER_PUBKEY:
+ ret = CDecodeSignedMsg_VerifySignatureWithKey(msg,
+ para->hCryptProv, para->dwSignerIndex, para->pvSigner);
+ break;
+ case CMSG_VERIFY_SIGNER_CERT:
+ {
+ PCCERT_CONTEXT cert = para->pvSigner;
+
+ ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, para->hCryptProv,
+ para->dwSignerIndex, &cert->pCertInfo->SubjectPublicKeyInfo);
+ break;
+ }
+ default:
+ FIXME("unimplemented for signer type %d\n", para->dwSignerType);
+ SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
}
}
return ret;
static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags,
DWORD dwCtrlType, const void *pvCtrlPara)
{
- CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
+ CDecodeMsg *msg = hCryptMsg;
BOOL ret = FALSE;
switch (dwCtrlType)
switch (msg->type)
{
case CMSG_SIGNED:
- FIXME("CMSG_CTRL_VERIFY_SIGNATURE: stub\n");
+ ret = CDecodeSignedMsg_VerifySignature(msg, (PCERT_INFO)pvCtrlPara);
break;
default:
SetLastError(CRYPT_E_INVALID_MSG_TYPE);
SetLastError(CRYPT_E_INVALID_MSG_TYPE);
}
break;
+ case CMSG_CTRL_VERIFY_SIGNATURE_EX:
+ switch (msg->type)
+ {
+ case CMSG_SIGNED:
+ ret = CDecodeSignedMsg_VerifySignatureEx(msg,
+ (PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)pvCtrlPara);
+ break;
+ default:
+ SetLastError(CRYPT_E_INVALID_MSG_TYPE);
+ }
+ break;
default:
SetLastError(CRYPT_E_CONTROL_TYPE);
}
memset(&msg->u, 0, sizeof(msg->u));
msg->msg_data.cbData = 0;
msg->msg_data.pbData = NULL;
+ msg->detached_data.cbData = 0;
+ msg->detached_data.pbData = NULL;
msg->properties = ContextPropertyList_Create();
}
return msg;
if (hCryptMsg)
{
- CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
+ CryptMsgBase *msg = hCryptMsg;
InterlockedIncrement(&msg->ref);
}
if (hCryptMsg)
{
- CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
+ CryptMsgBase *msg = hCryptMsg;
if (InterlockedDecrement(&msg->ref) == 0)
{
BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData,
DWORD cbData, BOOL fFinal)
{
- CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
- BOOL ret = FALSE;
+ CryptMsgBase *msg = hCryptMsg;
TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
- if (msg->state == MsgStateFinalized)
- SetLastError(CRYPT_E_MSG_ERROR);
- else
- {
- ret = msg->update(hCryptMsg, pbData, cbData, fFinal);
- msg->state = MsgStateUpdated;
- if (fFinal)
- msg->state = MsgStateFinalized;
- }
- return ret;
+ return msg->update(hCryptMsg, pbData, cbData, fFinal);
}
BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
DWORD dwIndex, void *pvData, DWORD *pcbData)
{
- CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
+ CryptMsgBase *msg = hCryptMsg;
TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
pvData, pcbData);
BOOL WINAPI CryptMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
DWORD dwCtrlType, const void *pvCtrlPara)
{
- CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
+ CryptMsgBase *msg = hCryptMsg;
TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType,
pvCtrlPara);
return msg->control(hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
}
+
+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;
+ }
+ }
+ }
+ return certInfo;
+}
+
+BOOL WINAPI CryptMsgGetAndVerifySigner(HCRYPTMSG hCryptMsg, DWORD cSignerStore,
+ HCERTSTORE *rghSignerStore, DWORD dwFlags, PCCERT_CONTEXT *ppSigner,
+ DWORD *pdwSignerIndex)
+{
+ HCERTSTORE store;
+ DWORD i, signerIndex = 0;
+ PCCERT_CONTEXT signerCert = NULL;
+ BOOL ret = FALSE;
+
+ TRACE("(%p, %d, %p, %08x, %p, %p)\n", hCryptMsg, cSignerStore,
+ rghSignerStore, dwFlags, ppSigner, pdwSignerIndex);
+
+ /* Clear output parameters */
+ if (ppSigner)
+ *ppSigner = NULL;
+ if (pdwSignerIndex && !(dwFlags & CMSG_USE_SIGNER_INDEX_FLAG))
+ *pdwSignerIndex = 0;
+
+ /* Create store to search for signer certificates */
+ store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
+ CERT_STORE_CREATE_NEW_FLAG, NULL);
+ if (!(dwFlags & CMSG_TRUSTED_SIGNER_FLAG))
+ {
+ HCERTSTORE msgStore = CertOpenStore(CERT_STORE_PROV_MSG, 0, 0, 0,
+ hCryptMsg);
+
+ CertAddStoreToCollection(store, msgStore, 0, 0);
+ CertCloseStore(msgStore, 0);
+ }
+ for (i = 0; i < cSignerStore; i++)
+ CertAddStoreToCollection(store, rghSignerStore[i], 0, 0);
+
+ /* Find signer cert */
+ if (dwFlags & CMSG_USE_SIGNER_INDEX_FLAG)
+ {
+ CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg,
+ *pdwSignerIndex);
+
+ if (signer)
+ {
+ signerIndex = *pdwSignerIndex;
+ signerCert = CertFindCertificateInStore(store, X509_ASN_ENCODING,
+ 0, CERT_FIND_SUBJECT_CERT, signer, NULL);
+ CryptMemFree(signer);
+ }
+ }
+ else
+ {
+ DWORD count, size = sizeof(count);
+
+ if (CryptMsgGetParam(hCryptMsg, CMSG_SIGNER_COUNT_PARAM, 0, &count,
+ &size))
+ {
+ for (i = 0; !signerCert && i < count; i++)
+ {
+ CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg,
+ i);
+
+ if (signer)
+ {
+ signerCert = CertFindCertificateInStore(store,
+ X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_CERT, signer,
+ NULL);
+ if (signerCert)
+ signerIndex = i;
+ CryptMemFree(signer);
+ }
+ }
+ }
+ if (!signerCert)
+ SetLastError(CRYPT_E_NO_TRUSTED_SIGNER);
+ }
+ if (signerCert)
+ {
+ if (!(dwFlags & CMSG_SIGNER_ONLY_FLAG))
+ ret = CryptMsgControl(hCryptMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE,
+ signerCert->pCertInfo);
+ else
+ ret = TRUE;
+ if (ret)
+ {
+ if (ppSigner)
+ *ppSigner = CertDuplicateCertificateContext(signerCert);
+ if (pdwSignerIndex)
+ *pdwSignerIndex = signerIndex;
+ }
+ CertFreeCertificateContext(signerCert);
+ }
+
+ CertCloseStore(store, 0);
+ return ret;
+}
+
+BOOL WINAPI CryptMsgVerifyCountersignatureEncodedEx(HCRYPTPROV_LEGACY hCryptProv,
+ DWORD dwEncodingType, PBYTE pbSignerInfo, DWORD cbSignerInfo,
+ PBYTE pbSignerInfoCountersignature, DWORD cbSignerInfoCountersignature,
+ DWORD dwSignerType, void *pvSigner, DWORD dwFlags, void *pvReserved)
+{
+ FIXME("(%08lx, %08x, %p, %d, %p, %d, %d, %p, %08x, %p): stub\n", hCryptProv,
+ dwEncodingType, pbSignerInfo, cbSignerInfo, pbSignerInfoCountersignature,
+ cbSignerInfoCountersignature, dwSignerType, pvSigner, dwFlags, pvReserved);
+ return FALSE;
+}
+
+BOOL WINAPI CryptMsgEncodeAndSignCTL(DWORD dwMsgEncodingType,
+ PCTL_INFO pCtlInfo, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags,
+ BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ BOOL ret;
+ BYTE *pbCtlContent;
+ DWORD cbCtlContent;
+
+ TRACE("(%08x, %p, %p, %08x, %p, %p)\n", dwMsgEncodingType, pCtlInfo,
+ pSignInfo, dwFlags, pbEncoded, pcbEncoded);
+
+ if (dwFlags)
+ {
+ FIXME("unimplemented for flags %08x\n", dwFlags);
+ return FALSE;
+ }
+ if ((ret = CryptEncodeObjectEx(dwMsgEncodingType, PKCS_CTL, pCtlInfo,
+ CRYPT_ENCODE_ALLOC_FLAG, NULL, &pbCtlContent, &cbCtlContent)))
+ {
+ ret = CryptMsgSignCTL(dwMsgEncodingType, pbCtlContent, cbCtlContent,
+ pSignInfo, dwFlags, pbEncoded, pcbEncoded);
+ LocalFree(pbCtlContent);
+ }
+ return ret;
+}
+
+BOOL WINAPI CryptMsgSignCTL(DWORD dwMsgEncodingType, BYTE *pbCtlContent,
+ DWORD cbCtlContent, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags,
+ BYTE *pbEncoded, DWORD *pcbEncoded)
+{
+ static char oid_ctl[] = szOID_CTL;
+ BOOL ret;
+ HCRYPTMSG msg;
+
+ TRACE("(%08x, %p, %d, %p, %08x, %p, %p)\n", dwMsgEncodingType,
+ pbCtlContent, cbCtlContent, pSignInfo, dwFlags, pbEncoded, pcbEncoded);
+
+ if (dwFlags)
+ {
+ FIXME("unimplemented for flags %08x\n", dwFlags);
+ return FALSE;
+ }
+ msg = CryptMsgOpenToEncode(dwMsgEncodingType, 0, CMSG_SIGNED, pSignInfo,
+ oid_ctl, NULL);
+ if (msg)
+ {
+ ret = CryptMsgUpdate(msg, pbCtlContent, cbCtlContent, TRUE);
+ if (ret)
+ ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, pbEncoded,
+ pcbEncoded);
+ CryptMsgClose(msg);
+ }
+ else
+ ret = FALSE;
+ return ret;
+}