windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/pki/wincrmsg/msglen.cpp
2020-09-26 16:20:57 +08:00

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
}