//+------------------------------------------------------------------------- // // 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 }