1314 lines
42 KiB
C++
1314 lines
42 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
||
|
//
|
||
|
// File: msglen.cpp
|
||
|
//
|
||
|
// Contents: Cryptographic Message Length APIs
|
||
|
//
|
||
|
// APIs: CryptMsgCalculateEncodedLength
|
||
|
//
|
||
|
// History: 12-Dec-96 kevinr created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include "global.hxx"
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the OBJECT IDENTIFIER encoded blob.
|
||
|
// We do this by doing the encode using OSS and throwing away the result.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthObjId(
|
||
|
IN LPSTR pszObjId)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cb;
|
||
|
ASN1encodedOID_t eoid; ZEROSTRUCT(eoid);
|
||
|
ASN1encoding_t pEnc = ICM_GetEncoder();
|
||
|
|
||
|
if (0 == PkiAsn1DotValToEncodedOid(pEnc, pszObjId, &eoid))
|
||
|
goto DotValToEncodedOidError;
|
||
|
|
||
|
ICM_GetLengthOctets( eoid.length, NULL, &cb);
|
||
|
cbSize = 1 + cb + eoid.length; // OBJECT IDENTIFIER
|
||
|
|
||
|
PkiAsn1FreeEncodedOid(pEnc, &eoid);
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
SET_ERROR(DotValToEncodedOidError,CRYPT_E_OID_FORMAT)
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the AlgorithmIdentifier encoded blob.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthAlgorithmIdentifier(
|
||
|
IN PCRYPT_ALGORITHM_IDENTIFIER pai,
|
||
|
IN BOOL fNoNullParameters = FALSE
|
||
|
)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cb;
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthObjId( pai->pszObjId)))
|
||
|
goto CommonReturn;
|
||
|
if (!fNoNullParameters)
|
||
|
cbSize += max( 2, pai->Parameters.cbData);
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += cb + 1; // AlgorithmIdentifier seq
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the ContentInfo encoded blob.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthContentInfo(
|
||
|
IN DWORD dwFlags,
|
||
|
IN OPTIONAL LPSTR pszContentType,
|
||
|
IN DWORD cbData,
|
||
|
OUT OPTIONAL PDWORD pcbContent)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cbTmp;
|
||
|
DWORD cb;
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthObjId(
|
||
|
pszContentType ? pszContentType : pszObjIdDataType)))
|
||
|
goto LengthContentTypeError;
|
||
|
|
||
|
if (0 == (dwFlags & CMSG_DETACHED_FLAG)) {
|
||
|
cbTmp = cbData;
|
||
|
ICM_GetLengthOctets( cbTmp, NULL, &cb);
|
||
|
|
||
|
if (NULL == pszContentType
|
||
|
#ifdef CMS_PKCS7
|
||
|
|| ((dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG) &&
|
||
|
!ICM_IsData(pszContentType))
|
||
|
#endif // CMS_PKCS7
|
||
|
) {
|
||
|
// data, not already encoded
|
||
|
// Gets its own OCTET STRING wrapper.
|
||
|
cbTmp += 1 + cb; // OCTET STRING
|
||
|
ICM_GetLengthOctets( cbTmp, NULL, &cb);
|
||
|
}
|
||
|
cbSize += 1 + cb + cbTmp; // [0] EXPLICIT
|
||
|
}
|
||
|
|
||
|
if (pcbContent)
|
||
|
*pcbContent = cbSize;
|
||
|
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += 1 + cb; // ContentInfo seq
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
TRACE_ERROR(LengthContentTypeError) // error already set
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the EncryptedContentInfo encoded blob.
|
||
|
//
|
||
|
// The return length assumes the encrypted content is
|
||
|
// encapsulated.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthEncryptedContentInfo(
|
||
|
IN HCRYPTKEY hEncryptKey,
|
||
|
IN PCRYPT_ALGORITHM_IDENTIFIER paiContentEncryption,
|
||
|
IN OPTIONAL LPSTR pszContentTypeOrg,
|
||
|
IN DWORD cbData)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cb;
|
||
|
DWORD cbBlockSize;
|
||
|
BOOL fBlockCipher;
|
||
|
DWORD cbCipher;
|
||
|
LPSTR pszContentType = pszContentTypeOrg ? pszContentTypeOrg :
|
||
|
pszObjIdDataType;
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthObjId( pszContentType)))
|
||
|
goto LengthContentTypeError;
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier( paiContentEncryption)))
|
||
|
goto LengthAlgorithmIdentifierError;
|
||
|
cbSize += cb;
|
||
|
|
||
|
cbCipher = cbData;
|
||
|
if (0 < cbCipher) {
|
||
|
if (!ICM_GetKeyBlockSize(
|
||
|
hEncryptKey,
|
||
|
&cbBlockSize,
|
||
|
&fBlockCipher))
|
||
|
goto GetEncryptBlockSizeError;
|
||
|
|
||
|
if (fBlockCipher) {
|
||
|
cbCipher += cbBlockSize;
|
||
|
cbCipher -= cbCipher % cbBlockSize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ICM_GetLengthOctets( cbCipher, NULL, &cb); // encryptedContent
|
||
|
cbSize += 1 + cb + cbCipher; // [0] IMPLICIT
|
||
|
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += 1 + cb; // EncryptedContentInfo seq
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
TRACE_ERROR(LengthContentTypeError)
|
||
|
TRACE_ERROR(LengthAlgorithmIdentifierError)
|
||
|
TRACE_ERROR(GetEncryptBlockSizeError)
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef CMS_PKCS7
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the IssuerAndSerialNumber encoded blob.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthIssuerAndSerialNumber(
|
||
|
IN PCERT_INFO pCertInfo)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cb;
|
||
|
|
||
|
cbSize = pCertInfo->SerialNumber.cbData;
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += cb + 1; // SerialNumber INTEGER
|
||
|
cbSize += pCertInfo->Issuer.cbData; // Issuer already encoded
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += cb + 1; // IssuerAndSerialNumber seq
|
||
|
|
||
|
return cbSize;
|
||
|
}
|
||
|
#endif // CMS_PKCS7
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the CertId encoded blob.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthCertId(
|
||
|
IN PCERT_ID pCertId)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cb;
|
||
|
|
||
|
switch (pCertId->dwIdChoice) {
|
||
|
case CERT_ID_ISSUER_SERIAL_NUMBER:
|
||
|
cbSize = pCertId->IssuerSerialNumber.SerialNumber.cbData;
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += cb + 1; // SerialNumber INTEGER
|
||
|
cbSize += pCertId->IssuerSerialNumber.Issuer.cbData; // Issuer ANY
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += cb + 1; // IssuerSerialNumber seq
|
||
|
break;
|
||
|
case CERT_ID_KEY_IDENTIFIER:
|
||
|
cbSize = pCertId->KeyId.cbData;
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += cb + 1; // KeyId OCTET STRING
|
||
|
break;
|
||
|
default:
|
||
|
goto InvalidCertIdChoice;
|
||
|
};
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
SET_ERROR(InvalidCertIdChoice, E_INVALIDARG)
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the EncryptedDigest encoded blob plus the
|
||
|
// algorithm identifier
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthEncryptedDigestAndAlgorithm(
|
||
|
IN HCRYPTPROV hCryptProv,
|
||
|
IN DWORD dwKeySpec,
|
||
|
IN PCRYPT_ALGORITHM_IDENTIFIER paiDigest,
|
||
|
IN PCRYPT_ALGORITHM_IDENTIFIER paiDigestEncrypt)
|
||
|
{
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
DWORD cbSignature;
|
||
|
DWORD cbSize = 0;
|
||
|
DWORD cb;
|
||
|
HCRYPTHASH hHash = NULL;
|
||
|
PCCRYPT_OID_INFO pOIDInfo;
|
||
|
DWORD dwAlgIdDigest;
|
||
|
DWORD dwAlgIdPubKey;
|
||
|
DWORD dwAlgIdFlags;
|
||
|
CRYPT_ALGORITHM_IDENTIFIER aiDigestEncrypt;
|
||
|
BOOL fNoNullParameters;
|
||
|
|
||
|
dwAlgIdPubKey = 0;
|
||
|
dwAlgIdFlags = 0;
|
||
|
if (pOIDInfo = CryptFindOIDInfo(
|
||
|
CRYPT_OID_INFO_OID_KEY,
|
||
|
paiDigestEncrypt->pszObjId,
|
||
|
CRYPT_PUBKEY_ALG_OID_GROUP_ID)) {
|
||
|
dwAlgIdPubKey = pOIDInfo->Algid;
|
||
|
if (1 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD)) {
|
||
|
DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
|
||
|
dwAlgIdFlags = pdwExtra[0];
|
||
|
}
|
||
|
|
||
|
// Check if more than just the NULL parameters
|
||
|
if (2 < paiDigestEncrypt->Parameters.cbData) {
|
||
|
// Check if we should use the public key parameters
|
||
|
if (0 == (dwAlgIdFlags &
|
||
|
CRYPT_OID_USE_PUBKEY_PARA_FOR_PKCS7_FLAG)) {
|
||
|
memset(&aiDigestEncrypt, 0, sizeof(aiDigestEncrypt));
|
||
|
aiDigestEncrypt.pszObjId = paiDigestEncrypt->pszObjId;
|
||
|
paiDigestEncrypt = &aiDigestEncrypt;
|
||
|
}
|
||
|
}
|
||
|
} else if (pOIDInfo = CryptFindOIDInfo(
|
||
|
CRYPT_OID_INFO_OID_KEY,
|
||
|
paiDigestEncrypt->pszObjId,
|
||
|
CRYPT_SIGN_ALG_OID_GROUP_ID)) {
|
||
|
DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
|
||
|
|
||
|
if (1 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD))
|
||
|
dwAlgIdPubKey = pdwExtra[0];
|
||
|
if (2 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD))
|
||
|
dwAlgIdFlags = pdwExtra[1];
|
||
|
}
|
||
|
|
||
|
|
||
|
if (CALG_DSS_SIGN == dwAlgIdPubKey &&
|
||
|
0 == (dwAlgIdFlags & CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG))
|
||
|
cbSignature = CERT_MAX_ASN_ENCODED_DSS_SIGNATURE_LEN;
|
||
|
else {
|
||
|
if (dwKeySpec == 0)
|
||
|
dwKeySpec = AT_SIGNATURE;
|
||
|
|
||
|
if (!(ICM_GetCAPI(
|
||
|
CRYPT_HASH_ALG_OID_GROUP_ID,
|
||
|
paiDigest,
|
||
|
&dwAlgIdDigest) ||
|
||
|
ICM_GetCAPI(
|
||
|
CRYPT_SIGN_ALG_OID_GROUP_ID,
|
||
|
paiDigest,
|
||
|
&dwAlgIdDigest)))
|
||
|
goto DigestGetCAPIError;
|
||
|
if (!CryptCreateHash(
|
||
|
hCryptProv,
|
||
|
dwAlgIdDigest,
|
||
|
NULL, // hKey - optional for MAC
|
||
|
0, // dwFlags
|
||
|
&hHash))
|
||
|
goto CreateHashError;
|
||
|
if (!CryptHashData(
|
||
|
hHash,
|
||
|
(PBYTE)&cb,
|
||
|
sizeof(DWORD),
|
||
|
0)) // dwFlags
|
||
|
goto HashDataError;
|
||
|
|
||
|
if (CALG_NO_SIGN == dwAlgIdPubKey) {
|
||
|
if (!CryptGetHashParam(
|
||
|
hHash,
|
||
|
HP_HASHVAL,
|
||
|
NULL, // pbHash
|
||
|
&cbSignature,
|
||
|
0)) // dwFlags
|
||
|
goto GetHashParamSizeError;
|
||
|
} else {
|
||
|
if (!CryptSignHash(
|
||
|
hHash,
|
||
|
dwKeySpec,
|
||
|
NULL, // description
|
||
|
0, // dwFlags
|
||
|
NULL, // pb
|
||
|
&cbSignature))
|
||
|
goto SignHashSizeError;
|
||
|
}
|
||
|
}
|
||
|
ICM_GetLengthOctets( cbSignature, NULL, &cb);
|
||
|
cbSize += cbSignature + cb + 1; // OCTET STRING
|
||
|
|
||
|
if (0 == paiDigestEncrypt->Parameters.cbData &&
|
||
|
0 != (dwAlgIdFlags & CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG))
|
||
|
fNoNullParameters = TRUE;
|
||
|
// NO NULL parameters
|
||
|
else
|
||
|
fNoNullParameters = FALSE;
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier(
|
||
|
paiDigestEncrypt, fNoNullParameters)))
|
||
|
goto SubjectPublicKeyInfoAlgorithmError;
|
||
|
cbSize += cb;
|
||
|
|
||
|
CommonReturn:
|
||
|
if (hHash)
|
||
|
CryptDestroyHash(hHash);
|
||
|
ICM_SetLastError(dwError);
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
dwError = GetLastError();
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
SET_ERROR(DigestGetCAPIError,CRYPT_E_UNKNOWN_ALGO)
|
||
|
TRACE_ERROR(SubjectPublicKeyInfoAlgorithmError)
|
||
|
TRACE_ERROR(CreateHashError)
|
||
|
TRACE_ERROR(HashDataError)
|
||
|
TRACE_ERROR(GetHashParamSizeError)
|
||
|
TRACE_ERROR(SignHashSizeError)
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the Digest encoded blob.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthDigest(
|
||
|
IN HCRYPTPROV hCryptProv,
|
||
|
IN PCRYPT_ALGORITHM_IDENTIFIER paiDigest)
|
||
|
{
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
DWORD cbSize;
|
||
|
DWORD cb;
|
||
|
DWORD dwAlgIdDigest;
|
||
|
HCRYPTHASH hHash = NULL;
|
||
|
|
||
|
if (0 == hCryptProv) {
|
||
|
if (0 == (hCryptProv = I_CryptGetDefaultCryptProv(0)))
|
||
|
goto GetDefaultCryptProvError;
|
||
|
}
|
||
|
|
||
|
if (!ICM_GetCAPI(
|
||
|
CRYPT_HASH_ALG_OID_GROUP_ID,
|
||
|
paiDigest,
|
||
|
&dwAlgIdDigest))
|
||
|
goto DigestGetCAPIError;
|
||
|
if (!CryptCreateHash(
|
||
|
hCryptProv,
|
||
|
dwAlgIdDigest,
|
||
|
NULL, // hKey - optional for MAC
|
||
|
0, // dwFlags
|
||
|
&hHash))
|
||
|
goto CreateHashError;
|
||
|
if (!CryptHashData(
|
||
|
hHash,
|
||
|
(PBYTE)&cb,
|
||
|
sizeof(DWORD),
|
||
|
0)) // dwFlags
|
||
|
goto HashDataError;
|
||
|
if (!CryptGetHashParam(
|
||
|
hHash,
|
||
|
HP_HASHVAL,
|
||
|
NULL, // pbHash
|
||
|
&cbSize,
|
||
|
0)) // dwFlags
|
||
|
goto GetHashParamSizeError;
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += cb + 1; // OCTET STRING
|
||
|
|
||
|
CommonReturn:
|
||
|
if (hHash)
|
||
|
CryptDestroyHash(hHash);
|
||
|
ICM_SetLastError(dwError);
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
dwError = GetLastError();
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
TRACE_ERROR(GetDefaultCryptProvError)
|
||
|
SET_ERROR(DigestGetCAPIError,CRYPT_E_UNKNOWN_ALGO)
|
||
|
TRACE_ERROR(CreateHashError)
|
||
|
TRACE_ERROR(HashDataError)
|
||
|
TRACE_ERROR(GetHashParamSizeError)
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the Attributes encoded blob.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthAttributes(
|
||
|
IN HCRYPTPROV hCryptProv,
|
||
|
IN PCRYPT_ALGORITHM_IDENTIFIER paiDigest,
|
||
|
IN DWORD cAttr,
|
||
|
IN PCRYPT_ATTRIBUTE rgAttr,
|
||
|
IN LPSTR pszInnerContentObjID,
|
||
|
IN BOOL fAuthAttr)
|
||
|
{
|
||
|
DWORD cbSize = 0;
|
||
|
DWORD cbAttrS;
|
||
|
DWORD cbAttr;
|
||
|
DWORD cbTmp;
|
||
|
DWORD cb;
|
||
|
PCRYPT_ATTRIBUTE patr;
|
||
|
PCRYPT_ATTR_BLOB pblobAttr;
|
||
|
DWORD i;
|
||
|
DWORD j;
|
||
|
BOOL fDataType = !pszInnerContentObjID ||
|
||
|
(0 == strcmp( pszInnerContentObjID, pszObjIdDataType));
|
||
|
|
||
|
for (i=cAttr, patr=rgAttr, cbAttrS=0;
|
||
|
i>0;
|
||
|
i--, patr++) {
|
||
|
if (0 == (cbAttr = ICM_LengthObjId( patr->pszObjId)))
|
||
|
goto PatrLengthObjIdError;
|
||
|
for (j=patr->cValue, pblobAttr=patr->rgValue, cbTmp=0;
|
||
|
j>0;
|
||
|
j--, pblobAttr++)
|
||
|
cbTmp += pblobAttr->cbData;
|
||
|
ICM_GetLengthOctets( cbTmp, NULL, &cb);
|
||
|
cbAttr += cbTmp + cb + 1; // AttributeSetValue set
|
||
|
ICM_GetLengthOctets( cbAttr, NULL, &cb);
|
||
|
cbAttrS += cbAttr + cb + 1; // Attribute seq
|
||
|
}
|
||
|
|
||
|
if (fAuthAttr && (cAttr || !fDataType)) {
|
||
|
// content type
|
||
|
cbAttr = ICM_LengthObjId( szOID_RSA_contentType);
|
||
|
if (INVALID_ENCODING_SIZE == (cbTmp = ICM_LengthObjId(
|
||
|
pszInnerContentObjID ?
|
||
|
pszInnerContentObjID : pszObjIdDataType)))
|
||
|
goto InnerContentLengthObjIdError;
|
||
|
ICM_GetLengthOctets( cbTmp, NULL, &cb);
|
||
|
cbAttr += cbTmp + cb + 1; // AttributeSetValue set
|
||
|
ICM_GetLengthOctets( cbAttr, NULL, &cb);
|
||
|
cbAttrS += cbAttr + cb + 1; // Attribute seq
|
||
|
|
||
|
// message digest
|
||
|
cbAttr = ICM_LengthObjId( szOID_RSA_messageDigest);
|
||
|
if (INVALID_ENCODING_SIZE == (cbTmp = ICM_LengthDigest( hCryptProv, paiDigest)))
|
||
|
goto LengthDigestError;
|
||
|
ICM_GetLengthOctets( cbTmp, NULL, &cb);
|
||
|
cbAttr += cbTmp + cb + 1; // AttributeSetValue set
|
||
|
ICM_GetLengthOctets( cbAttr, NULL, &cb);
|
||
|
cbAttrS += cbAttr + cb + 1; // Attribute seq
|
||
|
}
|
||
|
|
||
|
if (cbAttrS) {
|
||
|
ICM_GetLengthOctets( cbAttrS, NULL, &cb);
|
||
|
cbSize = cbAttrS + cb + 1; // Attributes set
|
||
|
}
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
TRACE_ERROR(PatrLengthObjIdError) // error already set
|
||
|
TRACE_ERROR(InnerContentLengthObjIdError) // error already set
|
||
|
TRACE_ERROR(LengthDigestError) // error already set
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the SignerInfos encoded blob.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthSignerInfos(
|
||
|
IN DWORD cSigners,
|
||
|
IN PCMSG_SIGNER_ENCODE_INFO rgSigners,
|
||
|
IN LPSTR pszInnerContentObjID
|
||
|
#ifdef CMS_PKCS7
|
||
|
,
|
||
|
OUT BOOL *pfHasCmsSignerId
|
||
|
#endif // CMS_PKCS7
|
||
|
)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cbSigner;
|
||
|
DWORD cbSignerS;
|
||
|
DWORD cb;
|
||
|
PCMSG_SIGNER_ENCODE_INFO psei;
|
||
|
DWORD i;
|
||
|
PCRYPT_ALGORITHM_IDENTIFIER paiDigestEncrypt;
|
||
|
CERT_ID SignerId;
|
||
|
|
||
|
#ifdef CMS_PKCS7
|
||
|
*pfHasCmsSignerId = FALSE;
|
||
|
#endif // CMS_PKCS7
|
||
|
|
||
|
for (i=cSigners, psei=rgSigners, cbSignerS=0;
|
||
|
i>0;
|
||
|
i--,
|
||
|
#ifdef CMS_PKCS7
|
||
|
psei = (PCMSG_SIGNER_ENCODE_INFO) ((BYTE *) psei + psei->cbSize)) {
|
||
|
#else
|
||
|
psei++) {
|
||
|
#endif // CMS_PKCS7
|
||
|
cbSigner = 1 + 1 + 1; // version
|
||
|
|
||
|
if (!ICM_GetSignerIdFromSignerEncodeInfo(psei, &SignerId))
|
||
|
goto GetSignerIdError;
|
||
|
#ifdef CMS_PKCS7
|
||
|
if (CERT_ID_ISSUER_SERIAL_NUMBER != SignerId.dwIdChoice)
|
||
|
*pfHasCmsSignerId = TRUE;
|
||
|
#endif // CMS_PKCS7
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthCertId( &SignerId)))
|
||
|
goto CertIdError;
|
||
|
cbSigner += cb;
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier( &psei->HashAlgorithm)))
|
||
|
goto HashAlgorithmError;
|
||
|
cbSigner += cb;
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAttributes(
|
||
|
psei->hCryptProv,
|
||
|
&psei->HashAlgorithm,
|
||
|
psei->cAuthAttr,
|
||
|
psei->rgAuthAttr,
|
||
|
pszInnerContentObjID,
|
||
|
TRUE)))
|
||
|
goto AuthAttributesError;
|
||
|
cbSigner += cb;
|
||
|
#ifdef CMS_PKCS7
|
||
|
if (STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO, HashEncryptionAlgorithm) <=
|
||
|
psei->cbSize && psei->HashEncryptionAlgorithm.pszObjId)
|
||
|
paiDigestEncrypt = &psei->HashEncryptionAlgorithm;
|
||
|
else
|
||
|
#endif // CMS_PKCS7
|
||
|
paiDigestEncrypt = &psei->pCertInfo->SubjectPublicKeyInfo.Algorithm;
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cb =
|
||
|
ICM_LengthEncryptedDigestAndAlgorithm(
|
||
|
psei->hCryptProv,
|
||
|
psei->dwKeySpec,
|
||
|
&psei->HashAlgorithm,
|
||
|
paiDigestEncrypt)))
|
||
|
goto EncryptedDigestError;
|
||
|
cbSigner += cb;
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAttributes(
|
||
|
NULL,
|
||
|
NULL,
|
||
|
psei->cUnauthAttr,
|
||
|
psei->rgUnauthAttr,
|
||
|
NULL,
|
||
|
FALSE)))
|
||
|
goto UnauthAttributesError;
|
||
|
cbSigner += cb;
|
||
|
ICM_GetLengthOctets( cbSigner, NULL, &cb);
|
||
|
cbSignerS += cbSigner + cb + 1; // SignerInfo seq
|
||
|
}
|
||
|
ICM_GetLengthOctets( cbSignerS, NULL, &cb);
|
||
|
cbSize = cbSignerS + cb + 1; // SignerInfo seq
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
TRACE_ERROR(GetSignerIdError) // error already set
|
||
|
TRACE_ERROR(CertIdError) // error already set
|
||
|
TRACE_ERROR(HashAlgorithmError) // error already set
|
||
|
TRACE_ERROR(AuthAttributesError) // error already set
|
||
|
TRACE_ERROR(UnauthAttributesError) // error already set
|
||
|
TRACE_ERROR(EncryptedDigestError) // error already set
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the SignedData.digestAlgorithms encoded blob.
|
||
|
//
|
||
|
#ifndef CMS_PKCS7
|
||
|
// Assumes no duplicate removal. OK for single-signer case, which
|
||
|
// is only one currently supported.
|
||
|
#endif
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthSignedDigestAlgorithms(
|
||
|
IN DWORD cSigners,
|
||
|
IN PCMSG_SIGNER_ENCODE_INFO rgSigners)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cbAlgoS;
|
||
|
DWORD cb;
|
||
|
PCMSG_SIGNER_ENCODE_INFO psei;
|
||
|
DWORD i;
|
||
|
|
||
|
#ifdef CMS_PKCS7
|
||
|
for (i=cSigners, psei=rgSigners, cbAlgoS=0; i>0;
|
||
|
i--,
|
||
|
psei = (PCMSG_SIGNER_ENCODE_INFO) ((BYTE *) psei + psei->cbSize)) {
|
||
|
assert(STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO, rgUnauthAttr) <=
|
||
|
psei->cbSize);
|
||
|
if (ICM_IsDuplicateSignerEncodeHashAlgorithm(
|
||
|
rgSigners,
|
||
|
psei
|
||
|
))
|
||
|
continue;
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier( &psei->HashAlgorithm)))
|
||
|
goto HashAlgorithmError;
|
||
|
cbAlgoS += cb;
|
||
|
}
|
||
|
#else
|
||
|
for (i=cSigners, psei=rgSigners, cbAlgoS=0;
|
||
|
i>0;
|
||
|
i--, psei++) {
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier( &psei->HashAlgorithm)))
|
||
|
goto HashAlgorithmError;
|
||
|
cbAlgoS += cb;
|
||
|
}
|
||
|
#endif // CMS_PKCS7
|
||
|
ICM_GetLengthOctets( cbAlgoS, NULL, &cb);
|
||
|
cbSize = cbAlgoS + cb + 1; // digestAlgorithms set
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
TRACE_ERROR(HashAlgorithmError) // error already set
|
||
|
}
|
||
|
|
||
|
#ifdef CMS_PKCS7
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of an enveloped message.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthEnveloped(
|
||
|
IN PCMSG_ENVELOPED_ENCODE_INFO pemei,
|
||
|
IN DWORD dwFlags,
|
||
|
IN OPTIONAL LPSTR pszInnerContentObjID,
|
||
|
IN DWORD cbData,
|
||
|
OUT OPTIONAL PDWORD pcbContent)
|
||
|
{
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
DWORD cbSize;
|
||
|
DWORD cb;
|
||
|
|
||
|
CMSG_CONTENT_ENCRYPT_INFO ContentEncryptInfo;
|
||
|
ZEROSTRUCT(ContentEncryptInfo);
|
||
|
CmsRecipientInfos recipientInfos; ZEROSTRUCT(recipientInfos);
|
||
|
#ifdef OSS_CRYPT_ASN1
|
||
|
int version = 0;
|
||
|
#else
|
||
|
ASN1int32_t version = 0;
|
||
|
#endif // OSS_CRYPT_ASN1
|
||
|
|
||
|
ASN1error_e Asn1Err;
|
||
|
ASN1encoding_t pEnc = ICM_GetEncoder();
|
||
|
PBYTE pbEncoded = NULL;
|
||
|
DWORD cbEncoded;
|
||
|
|
||
|
assert(pemei->cbSize >= STRUCT_CBSIZE(CMSG_ENVELOPED_ENCODE_INFO,
|
||
|
rgpRecipients));
|
||
|
#ifdef CMS_PKCS7
|
||
|
if (pemei->cbSize <
|
||
|
STRUCT_CBSIZE(CMSG_ENVELOPED_ENCODE_INFO, rgpRecipients))
|
||
|
#else
|
||
|
assert(0 != pemei->cRecipients);
|
||
|
if (pemei->cbSize <
|
||
|
STRUCT_CBSIZE(CMSG_ENVELOPED_ENCODE_INFO, rgpRecipients) ||
|
||
|
0 == pemei->cRecipients)
|
||
|
#endif // CMS_PKCS7
|
||
|
goto InvalidArg;
|
||
|
|
||
|
// version
|
||
|
cbSize = 1 + 1 + 1;
|
||
|
|
||
|
// originatorInfo OPTIONAL
|
||
|
//
|
||
|
// unprotectedAttrs OPTIONAL
|
||
|
if (pemei->cbSize >= sizeof(CMSG_ENVELOPED_ENCODE_INFO)) {
|
||
|
DWORD cbOriginator = 0;
|
||
|
DWORD cbTmp;
|
||
|
DWORD i;
|
||
|
PCERT_BLOB pCert;
|
||
|
PCRL_BLOB pCrl;
|
||
|
cbOriginator = 0;
|
||
|
|
||
|
for (i = pemei->cCertEncoded, pCert = pemei->rgCertEncoded, cbTmp=0;
|
||
|
i > 0;
|
||
|
i--, pCert++)
|
||
|
cbTmp += pCert->cbData;
|
||
|
for (i = pemei->cAttrCertEncoded, pCert = pemei->rgAttrCertEncoded;
|
||
|
i > 0;
|
||
|
i--, pCert++)
|
||
|
cbTmp += pCert->cbData;
|
||
|
if (cbTmp) {
|
||
|
ICM_GetLengthOctets(cbTmp, NULL, &cb);
|
||
|
cbOriginator += 1 + cb + cbTmp; // [0] IMPLICIT Certificates
|
||
|
}
|
||
|
|
||
|
for (i = pemei->cCrlEncoded, pCrl = pemei->rgCrlEncoded, cbTmp=0;
|
||
|
i > 0;
|
||
|
i--, pCrl++)
|
||
|
cbTmp += pCrl->cbData;
|
||
|
if (cbTmp) {
|
||
|
ICM_GetLengthOctets(cbTmp, NULL, &cb);
|
||
|
cbOriginator += 1 + cb + cbTmp; // [1] IMPLICIT Crls
|
||
|
}
|
||
|
|
||
|
if (cbOriginator) {
|
||
|
ICM_GetLengthOctets(cbOriginator, NULL, &cb);
|
||
|
cbSize += 1 + cb + cbOriginator; // [0] IMPLICIT OriginatorInfo
|
||
|
}
|
||
|
|
||
|
if (0 < pemei->cUnprotectedAttr) {
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAttributes(
|
||
|
NULL,
|
||
|
NULL,
|
||
|
pemei->cUnprotectedAttr,
|
||
|
pemei->rgUnprotectedAttr,
|
||
|
NULL,
|
||
|
FALSE)))
|
||
|
goto UnprotectedAttrError;
|
||
|
cbSize += cb;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// recipientInfos
|
||
|
if (!ICM_InitializeContentEncryptInfo(pemei, &ContentEncryptInfo))
|
||
|
goto InitializeContentEncryptInfoError;
|
||
|
ContentEncryptInfo.dwEncryptFlags |=
|
||
|
CMSG_CONTENT_ENCRYPT_PAD_ENCODED_LEN_FLAG;
|
||
|
if (!ICM_FillOssCmsRecipientInfos(
|
||
|
&ContentEncryptInfo,
|
||
|
&recipientInfos,
|
||
|
&version
|
||
|
))
|
||
|
goto FillOssCmsRecipientInfosError;
|
||
|
if (0 != (Asn1Err = PkiAsn1Encode(
|
||
|
pEnc,
|
||
|
&recipientInfos,
|
||
|
CmsRecipientInfos_PDU,
|
||
|
&pbEncoded,
|
||
|
&cbEncoded)))
|
||
|
goto EncodeCmsRecipientInfosError;
|
||
|
cbSize += cbEncoded;
|
||
|
|
||
|
// encryptedContentInfo
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthEncryptedContentInfo(
|
||
|
ContentEncryptInfo.hContentEncryptKey,
|
||
|
&ContentEncryptInfo.ContentEncryptionAlgorithm,
|
||
|
pszInnerContentObjID,
|
||
|
cbData)))
|
||
|
goto LengthEncryptedContentInfoError;
|
||
|
cbSize += cb;
|
||
|
|
||
|
if (pcbContent)
|
||
|
*pcbContent = cbSize;
|
||
|
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += 1 + cb; // CmsEnvelopedData seq
|
||
|
|
||
|
CommonReturn:
|
||
|
PkiAsn1FreeEncoded(pEnc, pbEncoded);
|
||
|
ICM_FreeContentEncryptInfo(pemei, &ContentEncryptInfo);
|
||
|
ICM_FreeOssCmsRecipientInfos(&recipientInfos);
|
||
|
|
||
|
ICM_SetLastError(dwError);
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
dwError = GetLastError();
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
SET_ERROR(InvalidArg,E_INVALIDARG)
|
||
|
TRACE_ERROR(UnprotectedAttrError)
|
||
|
TRACE_ERROR(InitializeContentEncryptInfoError)
|
||
|
TRACE_ERROR(FillOssCmsRecipientInfosError)
|
||
|
SET_ERROR_VAR(EncodeCmsRecipientInfosError, PkiAsn1ErrToHr(Asn1Err))
|
||
|
TRACE_ERROR(LengthEncryptedContentInfoError)
|
||
|
}
|
||
|
#else
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the EncryptedKey encoded blob.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthEncryptedKey(
|
||
|
IN HCRYPTPROV hCryptProv,
|
||
|
IN HCRYPTKEY hEncryptKey,
|
||
|
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
|
||
|
IN DWORD dwEncryptFlags)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
// rgcbEncryptedKey[1] contains dwEncryptFlags
|
||
|
DWORD rgcbEncryptedKey[2];
|
||
|
DWORD cb;
|
||
|
|
||
|
rgcbEncryptedKey[1] = dwEncryptFlags;
|
||
|
|
||
|
// Length only export calculation
|
||
|
if (!ICM_ExportEncryptKey(
|
||
|
hCryptProv,
|
||
|
hEncryptKey,
|
||
|
pPublicKeyInfo,
|
||
|
NULL, // pbData
|
||
|
rgcbEncryptedKey) || 0 == rgcbEncryptedKey[0])
|
||
|
goto ExportKeyError;
|
||
|
|
||
|
// Add bytes for ASN.1 tag and length
|
||
|
ICM_GetLengthOctets(rgcbEncryptedKey[0], NULL, &cb);
|
||
|
cbSize = rgcbEncryptedKey[0] + cb + 1; // OCTET STRING
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
TRACE_ERROR(ExportKeyError)
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of the RecipientInfos encoded blob.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthRecipientInfos(
|
||
|
IN HCRYPTPROV hCryptProv,
|
||
|
IN HCRYPTKEY hEncryptKey,
|
||
|
IN DWORD cRecipients,
|
||
|
IN PCERT_INFO *rgpRecipients,
|
||
|
IN DWORD dwEncryptFlags)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cbRecipient;
|
||
|
DWORD cbRecipientS;
|
||
|
DWORD cb;
|
||
|
PCERT_INFO *ppCertInfo;
|
||
|
DWORD i;
|
||
|
|
||
|
for (i=cRecipients, ppCertInfo=rgpRecipients, cbRecipientS=0;
|
||
|
i>0;
|
||
|
i--, ppCertInfo++) {
|
||
|
cbRecipient = 1 + 1 + 1; // version
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthIssuerAndSerialNumber( *ppCertInfo)))
|
||
|
goto IssuerAndSerialNumberError;
|
||
|
cbRecipient += cb;
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier(
|
||
|
&(*ppCertInfo)->SubjectPublicKeyInfo.Algorithm)))
|
||
|
goto SubjectPublicKeyInfoAlgorithmError;
|
||
|
cbRecipient += cb;
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthEncryptedKey(
|
||
|
hCryptProv,
|
||
|
hEncryptKey,
|
||
|
&(*ppCertInfo)->SubjectPublicKeyInfo,
|
||
|
dwEncryptFlags)))
|
||
|
goto EncryptedKeyError;
|
||
|
cbRecipient += cb;
|
||
|
ICM_GetLengthOctets( cbRecipient, NULL, &cb);
|
||
|
cbRecipientS += cbRecipient + cb + 1; // RecipientInfo
|
||
|
}
|
||
|
ICM_GetLengthOctets( cbRecipientS, NULL, &cb);
|
||
|
cbSize = cbRecipientS + cb + 1; // RecipientInfos seq
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
TRACE_ERROR(IssuerAndSerialNumberError) // error already set
|
||
|
TRACE_ERROR(SubjectPublicKeyInfoAlgorithmError) // error already set
|
||
|
TRACE_ERROR(EncryptedKeyError) // error already set
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of an enveloped message.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthEnveloped(
|
||
|
IN PCMSG_ENVELOPED_ENCODE_INFO pemei,
|
||
|
IN DWORD dwFlags,
|
||
|
IN OPTIONAL LPSTR pszInnerContentObjID,
|
||
|
IN DWORD cbData,
|
||
|
OUT OPTIONAL PDWORD pcbContent)
|
||
|
{
|
||
|
DWORD dwError = ERROR_SUCCESS;
|
||
|
DWORD cbSize;
|
||
|
DWORD cb;
|
||
|
HCRYPTPROV hCryptProv;
|
||
|
HCRYPTKEY hEncryptKey = NULL;
|
||
|
|
||
|
CRYPT_ALGORITHM_IDENTIFIER ContentEncryptionAlgorithm;
|
||
|
PBYTE pbEncryptParameters = NULL;
|
||
|
|
||
|
// rgcbEncryptParameters[1] contains dwEncryptFlags
|
||
|
DWORD rgcbEncryptParameters[2];
|
||
|
|
||
|
// version
|
||
|
cbSize = 1 + 1 + 1;
|
||
|
|
||
|
if (0 == pemei->cRecipients)
|
||
|
goto InvalidArg;
|
||
|
hCryptProv = pemei->hCryptProv;
|
||
|
|
||
|
ContentEncryptionAlgorithm = pemei->ContentEncryptionAlgorithm;
|
||
|
rgcbEncryptParameters[0] = 0;
|
||
|
rgcbEncryptParameters[1] = 0; // dwEncryptFlags
|
||
|
if (!ICM_GenEncryptKey(
|
||
|
&hCryptProv,
|
||
|
&ContentEncryptionAlgorithm,
|
||
|
pemei->pvEncryptionAuxInfo,
|
||
|
&pemei->rgpRecipients[0]->SubjectPublicKeyInfo,
|
||
|
ICM_Alloc,
|
||
|
&hEncryptKey,
|
||
|
&pbEncryptParameters,
|
||
|
rgcbEncryptParameters))
|
||
|
goto GenKeyError;
|
||
|
if (rgcbEncryptParameters[0] && pbEncryptParameters) {
|
||
|
ContentEncryptionAlgorithm.Parameters.pbData = pbEncryptParameters;
|
||
|
ContentEncryptionAlgorithm.Parameters.cbData = rgcbEncryptParameters[0];
|
||
|
}
|
||
|
|
||
|
// recipientInfos
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthRecipientInfos(
|
||
|
hCryptProv,
|
||
|
hEncryptKey,
|
||
|
pemei->cRecipients,
|
||
|
pemei->rgpRecipients,
|
||
|
rgcbEncryptParameters[1]))) // dwEncryptFlags
|
||
|
goto LengthRecipientInfosError;
|
||
|
cbSize += cb;
|
||
|
|
||
|
// encryptedContentInfo
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthEncryptedContentInfo(
|
||
|
hEncryptKey,
|
||
|
&ContentEncryptionAlgorithm,
|
||
|
pszInnerContentObjID,
|
||
|
cbData)))
|
||
|
goto LengthEncryptedContentInfoError;
|
||
|
cbSize += cb;
|
||
|
|
||
|
if (pcbContent)
|
||
|
*pcbContent = cbSize;
|
||
|
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += 1 + cb; // EnvelopedData seq
|
||
|
|
||
|
CommonReturn:
|
||
|
if (hEncryptKey)
|
||
|
CryptDestroyKey(hEncryptKey);
|
||
|
ICM_Free(pbEncryptParameters);
|
||
|
ICM_SetLastError(dwError);
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
dwError = GetLastError();
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
SET_ERROR(InvalidArg,E_INVALIDARG)
|
||
|
TRACE_ERROR(GenKeyError)
|
||
|
TRACE_ERROR(LengthRecipientInfosError)
|
||
|
TRACE_ERROR(LengthEncryptedContentInfoError)
|
||
|
}
|
||
|
|
||
|
#endif // CMS_PKCS7
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of a signed message.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthSigned(
|
||
|
IN PCMSG_SIGNED_ENCODE_INFO psmei,
|
||
|
IN DWORD dwFlags,
|
||
|
IN OPTIONAL LPSTR pszInnerContentObjID,
|
||
|
IN DWORD cbData,
|
||
|
OUT OPTIONAL PDWORD pcbContent)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cbSignedData;
|
||
|
DWORD cbTmp;
|
||
|
DWORD cb;
|
||
|
DWORD i;
|
||
|
PCERT_BLOB pCert;
|
||
|
PCRL_BLOB pCrl;
|
||
|
|
||
|
#ifdef CMS_PKCS7
|
||
|
DWORD cAttrCertEncoded;
|
||
|
BOOL fHasCmsSignerId = FALSE;
|
||
|
#endif // CMS_PKCS7
|
||
|
|
||
|
cbSignedData = 1 + 1 + 1; // version
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthSignedDigestAlgorithms(
|
||
|
psmei->cSigners,
|
||
|
psmei->rgSigners)))
|
||
|
goto LengthSignedDigestAlgorithmsError;
|
||
|
cbSignedData += cb;
|
||
|
|
||
|
#ifdef CMS_PKCS7
|
||
|
if (psmei->cbSize >= STRUCT_CBSIZE(CMSG_SIGNED_ENCODE_INFO,
|
||
|
rgAttrCertEncoded)) {
|
||
|
cAttrCertEncoded = psmei->cAttrCertEncoded;
|
||
|
|
||
|
if (cAttrCertEncoded)
|
||
|
dwFlags |= CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
|
||
|
} else
|
||
|
cAttrCertEncoded = 0;
|
||
|
#endif // CMS_PKCS7
|
||
|
|
||
|
// Do this before the ContentInfo. Need to know if we need to
|
||
|
// encapsulate the content for KeyId Signers.
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthSignerInfos(
|
||
|
psmei->cSigners,
|
||
|
psmei->rgSigners,
|
||
|
pszInnerContentObjID
|
||
|
#ifdef CMS_PKCS7
|
||
|
,
|
||
|
&fHasCmsSignerId
|
||
|
#endif // CMS_PKCS7
|
||
|
)))
|
||
|
goto SignerInfosError;
|
||
|
cbSignedData += cb;
|
||
|
#ifdef CMS_PKCS7
|
||
|
if (fHasCmsSignerId)
|
||
|
dwFlags |= CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
|
||
|
#endif // CMS_PKCS7
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthContentInfo(
|
||
|
dwFlags,
|
||
|
pszInnerContentObjID,
|
||
|
cbData,
|
||
|
NULL)))
|
||
|
goto LengthContentInfoError;
|
||
|
cbSignedData += cb;
|
||
|
|
||
|
for (i = psmei->cCertEncoded, pCert = psmei->rgCertEncoded, cbTmp=0;
|
||
|
i > 0;
|
||
|
i--, pCert++)
|
||
|
cbTmp += pCert->cbData;
|
||
|
|
||
|
#ifdef CMS_PKCS7
|
||
|
if (cAttrCertEncoded) {
|
||
|
for (i = cAttrCertEncoded, pCert = psmei->rgAttrCertEncoded;
|
||
|
i > 0;
|
||
|
i--, pCert++)
|
||
|
cbTmp += pCert->cbData;
|
||
|
}
|
||
|
#endif // CMS_PKCS7
|
||
|
|
||
|
if (cbTmp) {
|
||
|
ICM_GetLengthOctets( cbTmp, NULL, &cb);
|
||
|
cbSignedData += 1 + cb + cbTmp; // [0] IMPLICIT Certificates
|
||
|
}
|
||
|
|
||
|
for (i = psmei->cCrlEncoded, pCrl = psmei->rgCrlEncoded, cbTmp=0;
|
||
|
i > 0;
|
||
|
i--, pCrl++)
|
||
|
cbTmp += pCrl->cbData;
|
||
|
if (cbTmp) {
|
||
|
ICM_GetLengthOctets( cbTmp, NULL, &cb);
|
||
|
cbSignedData += 1 + cb + cbTmp; // [1] IMPLICIT Crls
|
||
|
}
|
||
|
|
||
|
if (pcbContent)
|
||
|
*pcbContent = cbSignedData;
|
||
|
|
||
|
ICM_GetLengthOctets( cbSignedData, NULL, &cb);
|
||
|
cbSize = 1 + cb + cbSignedData; // SignedData seq
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
TRACE_ERROR(LengthSignedDigestAlgorithmsError) // error already set
|
||
|
TRACE_ERROR(LengthContentInfoError) // error already set
|
||
|
TRACE_ERROR(SignerInfosError) // error already set
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of a digested message.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
ICM_LengthDigested(
|
||
|
IN PCMSG_HASHED_ENCODE_INFO pdmei,
|
||
|
IN DWORD dwFlags,
|
||
|
IN OPTIONAL LPSTR pszInnerContentObjID,
|
||
|
IN DWORD cbData,
|
||
|
OUT OPTIONAL PDWORD pcbContent)
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
DWORD cb;
|
||
|
|
||
|
cbSize = 1 + 1 + 1; // version
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier( &pdmei->HashAlgorithm)))
|
||
|
goto HashAlgorithmError;
|
||
|
cbSize += cb;
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthContentInfo(
|
||
|
dwFlags,
|
||
|
pszInnerContentObjID,
|
||
|
cbData,
|
||
|
NULL)))
|
||
|
goto LengthContentInfoError;
|
||
|
cbSize += cb;
|
||
|
|
||
|
if (INVALID_ENCODING_SIZE == (cb = ICM_LengthDigest( pdmei->hCryptProv, &pdmei->HashAlgorithm)))
|
||
|
goto DigestError;
|
||
|
cbSize += cb;
|
||
|
|
||
|
if (pcbContent)
|
||
|
*pcbContent = cbSize;
|
||
|
|
||
|
ICM_GetLengthOctets( cbSize, NULL, &cb);
|
||
|
cbSize += 1 + cb; // DigestedData seq
|
||
|
|
||
|
CommonReturn:
|
||
|
return cbSize;
|
||
|
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
TRACE_ERROR(HashAlgorithmError) // error already set
|
||
|
TRACE_ERROR(LengthContentInfoError) // error already set
|
||
|
TRACE_ERROR(DigestError) // error already set
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
// Calculate the length of an encoded cryptographic message.
|
||
|
//
|
||
|
// Calculates the length of the encoded message given the
|
||
|
// message type, encoding parameters and total length of
|
||
|
// the data to be updated. Note, this might not be the exact length.
|
||
|
// However, it will always be greater than or equal to the actual length.
|
||
|
//--------------------------------------------------------------------------
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
CryptMsgCalculateEncodedLength(
|
||
|
IN DWORD dwEncodingType,
|
||
|
IN DWORD dwFlags,
|
||
|
IN DWORD dwMsgType,
|
||
|
IN void const *pvMsgEncodeInfo,
|
||
|
IN OPTIONAL LPSTR pszInnerContentObjID,
|
||
|
IN DWORD cbData)
|
||
|
{
|
||
|
DWORD cbSize = INVALID_ENCODING_SIZE;
|
||
|
LPSTR pszContentType = NULL;
|
||
|
DWORD cb;
|
||
|
DWORD cbContent = 0;
|
||
|
|
||
|
if (GET_CMSG_ENCODING_TYPE(dwEncodingType) != PKCS_7_ASN_ENCODING)
|
||
|
goto InvalidEncoding;
|
||
|
|
||
|
switch (dwMsgType) {
|
||
|
case CMSG_DATA:
|
||
|
if (NULL != pvMsgEncodeInfo)
|
||
|
goto InvalidEncodeInfo;
|
||
|
cbContent = cbData;
|
||
|
ICM_GetLengthOctets( cbData, NULL, &cb);
|
||
|
cbSize = 1 + cb + cbData; // OCTET STRING
|
||
|
pszContentType = pszObjIdDataType;
|
||
|
break;
|
||
|
|
||
|
case CMSG_SIGNED:
|
||
|
if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthSigned(
|
||
|
(PCMSG_SIGNED_ENCODE_INFO)pvMsgEncodeInfo,
|
||
|
dwFlags,
|
||
|
pszInnerContentObjID,
|
||
|
cbData,
|
||
|
&cbContent)))
|
||
|
goto LengthSignedError;
|
||
|
pszContentType = szOID_RSA_signedData;
|
||
|
break;
|
||
|
|
||
|
case CMSG_ENVELOPED:
|
||
|
if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthEnveloped(
|
||
|
(PCMSG_ENVELOPED_ENCODE_INFO)pvMsgEncodeInfo,
|
||
|
dwFlags,
|
||
|
pszInnerContentObjID,
|
||
|
cbData,
|
||
|
&cbContent)))
|
||
|
goto LengthEnvelopedError;
|
||
|
pszContentType = szOID_RSA_envelopedData;
|
||
|
break;
|
||
|
|
||
|
case CMSG_HASHED:
|
||
|
if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthDigested(
|
||
|
(PCMSG_HASHED_ENCODE_INFO)pvMsgEncodeInfo,
|
||
|
dwFlags,
|
||
|
pszInnerContentObjID,
|
||
|
cbData,
|
||
|
&cbContent)))
|
||
|
goto LengthDigestedError;
|
||
|
pszContentType = szOID_RSA_digestedData;
|
||
|
break;
|
||
|
|
||
|
case CMSG_SIGNED_AND_ENVELOPED:
|
||
|
case CMSG_ENCRYPTED:
|
||
|
goto MessageTypeNotSupportedYet;
|
||
|
|
||
|
default:
|
||
|
goto InvalidMsgType;
|
||
|
}
|
||
|
|
||
|
if (0 == (dwFlags & CMSG_BARE_CONTENT_FLAG)) {
|
||
|
if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthContentInfo(
|
||
|
0, // dwFlags
|
||
|
pszContentType,
|
||
|
cbSize,
|
||
|
&cbContent)))
|
||
|
goto LengthContentInfoError;
|
||
|
}
|
||
|
|
||
|
CommonReturn:
|
||
|
return (cbSize == INVALID_ENCODING_SIZE) ? 0 :
|
||
|
((dwFlags & CMSG_CONTENTS_OCTETS_FLAG) ? cbContent : cbSize);
|
||
|
|
||
|
ErrorReturn:
|
||
|
cbSize = INVALID_ENCODING_SIZE;
|
||
|
goto CommonReturn;
|
||
|
SET_ERROR(InvalidEncoding,E_INVALIDARG)
|
||
|
SET_ERROR(InvalidEncodeInfo,E_INVALIDARG)
|
||
|
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
|
||
|
SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
|
||
|
TRACE_ERROR(LengthSignedError) // error already set
|
||
|
TRACE_ERROR(LengthEnvelopedError) // error already set
|
||
|
TRACE_ERROR(LengthDigestedError) // error already set
|
||
|
TRACE_ERROR(LengthContentInfoError) // error already set
|
||
|
}
|
||
|
|
||
|
|
||
|
|