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

1313 lines
42 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: msglen.cpp
  8. //
  9. // Contents: Cryptographic Message Length APIs
  10. //
  11. // APIs: CryptMsgCalculateEncodedLength
  12. //
  13. // History: 12-Dec-96 kevinr created
  14. //
  15. //--------------------------------------------------------------------------
  16. #include "global.hxx"
  17. //+-------------------------------------------------------------------------
  18. // Calculate the length of the OBJECT IDENTIFIER encoded blob.
  19. // We do this by doing the encode using OSS and throwing away the result.
  20. //--------------------------------------------------------------------------
  21. DWORD
  22. WINAPI
  23. ICM_LengthObjId(
  24. IN LPSTR pszObjId)
  25. {
  26. DWORD cbSize;
  27. DWORD cb;
  28. ASN1encodedOID_t eoid; ZEROSTRUCT(eoid);
  29. ASN1encoding_t pEnc = ICM_GetEncoder();
  30. if (0 == PkiAsn1DotValToEncodedOid(pEnc, pszObjId, &eoid))
  31. goto DotValToEncodedOidError;
  32. ICM_GetLengthOctets( eoid.length, NULL, &cb);
  33. cbSize = 1 + cb + eoid.length; // OBJECT IDENTIFIER
  34. PkiAsn1FreeEncodedOid(pEnc, &eoid);
  35. CommonReturn:
  36. return cbSize;
  37. ErrorReturn:
  38. cbSize = INVALID_ENCODING_SIZE;
  39. goto CommonReturn;
  40. SET_ERROR(DotValToEncodedOidError,CRYPT_E_OID_FORMAT)
  41. }
  42. //+-------------------------------------------------------------------------
  43. // Calculate the length of the AlgorithmIdentifier encoded blob.
  44. //--------------------------------------------------------------------------
  45. DWORD
  46. WINAPI
  47. ICM_LengthAlgorithmIdentifier(
  48. IN PCRYPT_ALGORITHM_IDENTIFIER pai,
  49. IN BOOL fNoNullParameters = FALSE
  50. )
  51. {
  52. DWORD cbSize;
  53. DWORD cb;
  54. if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthObjId( pai->pszObjId)))
  55. goto CommonReturn;
  56. if (!fNoNullParameters)
  57. cbSize += max( 2, pai->Parameters.cbData);
  58. ICM_GetLengthOctets( cbSize, NULL, &cb);
  59. cbSize += cb + 1; // AlgorithmIdentifier seq
  60. CommonReturn:
  61. return cbSize;
  62. }
  63. //+-------------------------------------------------------------------------
  64. // Calculate the length of the ContentInfo encoded blob.
  65. //--------------------------------------------------------------------------
  66. DWORD
  67. WINAPI
  68. ICM_LengthContentInfo(
  69. IN DWORD dwFlags,
  70. IN OPTIONAL LPSTR pszContentType,
  71. IN DWORD cbData,
  72. OUT OPTIONAL PDWORD pcbContent)
  73. {
  74. DWORD cbSize;
  75. DWORD cbTmp;
  76. DWORD cb;
  77. if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthObjId(
  78. pszContentType ? pszContentType : pszObjIdDataType)))
  79. goto LengthContentTypeError;
  80. if (0 == (dwFlags & CMSG_DETACHED_FLAG)) {
  81. cbTmp = cbData;
  82. ICM_GetLengthOctets( cbTmp, NULL, &cb);
  83. if (NULL == pszContentType
  84. #ifdef CMS_PKCS7
  85. || ((dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG) &&
  86. !ICM_IsData(pszContentType))
  87. #endif // CMS_PKCS7
  88. ) {
  89. // data, not already encoded
  90. // Gets its own OCTET STRING wrapper.
  91. cbTmp += 1 + cb; // OCTET STRING
  92. ICM_GetLengthOctets( cbTmp, NULL, &cb);
  93. }
  94. cbSize += 1 + cb + cbTmp; // [0] EXPLICIT
  95. }
  96. if (pcbContent)
  97. *pcbContent = cbSize;
  98. ICM_GetLengthOctets( cbSize, NULL, &cb);
  99. cbSize += 1 + cb; // ContentInfo seq
  100. CommonReturn:
  101. return cbSize;
  102. ErrorReturn:
  103. cbSize = INVALID_ENCODING_SIZE;
  104. goto CommonReturn;
  105. TRACE_ERROR(LengthContentTypeError) // error already set
  106. }
  107. //+-------------------------------------------------------------------------
  108. // Calculate the length of the EncryptedContentInfo encoded blob.
  109. //
  110. // The return length assumes the encrypted content is
  111. // encapsulated.
  112. //--------------------------------------------------------------------------
  113. DWORD
  114. WINAPI
  115. ICM_LengthEncryptedContentInfo(
  116. IN HCRYPTKEY hEncryptKey,
  117. IN PCRYPT_ALGORITHM_IDENTIFIER paiContentEncryption,
  118. IN OPTIONAL LPSTR pszContentTypeOrg,
  119. IN DWORD cbData)
  120. {
  121. DWORD cbSize;
  122. DWORD cb;
  123. DWORD cbBlockSize;
  124. BOOL fBlockCipher;
  125. DWORD cbCipher;
  126. LPSTR pszContentType = pszContentTypeOrg ? pszContentTypeOrg :
  127. pszObjIdDataType;
  128. if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthObjId( pszContentType)))
  129. goto LengthContentTypeError;
  130. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier( paiContentEncryption)))
  131. goto LengthAlgorithmIdentifierError;
  132. cbSize += cb;
  133. cbCipher = cbData;
  134. if (0 < cbCipher) {
  135. if (!ICM_GetKeyBlockSize(
  136. hEncryptKey,
  137. &cbBlockSize,
  138. &fBlockCipher))
  139. goto GetEncryptBlockSizeError;
  140. if (fBlockCipher) {
  141. cbCipher += cbBlockSize;
  142. cbCipher -= cbCipher % cbBlockSize;
  143. }
  144. }
  145. ICM_GetLengthOctets( cbCipher, NULL, &cb); // encryptedContent
  146. cbSize += 1 + cb + cbCipher; // [0] IMPLICIT
  147. ICM_GetLengthOctets( cbSize, NULL, &cb);
  148. cbSize += 1 + cb; // EncryptedContentInfo seq
  149. CommonReturn:
  150. return cbSize;
  151. ErrorReturn:
  152. cbSize = INVALID_ENCODING_SIZE;
  153. goto CommonReturn;
  154. TRACE_ERROR(LengthContentTypeError)
  155. TRACE_ERROR(LengthAlgorithmIdentifierError)
  156. TRACE_ERROR(GetEncryptBlockSizeError)
  157. }
  158. #ifndef CMS_PKCS7
  159. //+-------------------------------------------------------------------------
  160. // Calculate the length of the IssuerAndSerialNumber encoded blob.
  161. //--------------------------------------------------------------------------
  162. DWORD
  163. WINAPI
  164. ICM_LengthIssuerAndSerialNumber(
  165. IN PCERT_INFO pCertInfo)
  166. {
  167. DWORD cbSize;
  168. DWORD cb;
  169. cbSize = pCertInfo->SerialNumber.cbData;
  170. ICM_GetLengthOctets( cbSize, NULL, &cb);
  171. cbSize += cb + 1; // SerialNumber INTEGER
  172. cbSize += pCertInfo->Issuer.cbData; // Issuer already encoded
  173. ICM_GetLengthOctets( cbSize, NULL, &cb);
  174. cbSize += cb + 1; // IssuerAndSerialNumber seq
  175. return cbSize;
  176. }
  177. #endif // CMS_PKCS7
  178. //+-------------------------------------------------------------------------
  179. // Calculate the length of the CertId encoded blob.
  180. //--------------------------------------------------------------------------
  181. DWORD
  182. WINAPI
  183. ICM_LengthCertId(
  184. IN PCERT_ID pCertId)
  185. {
  186. DWORD cbSize;
  187. DWORD cb;
  188. switch (pCertId->dwIdChoice) {
  189. case CERT_ID_ISSUER_SERIAL_NUMBER:
  190. cbSize = pCertId->IssuerSerialNumber.SerialNumber.cbData;
  191. ICM_GetLengthOctets( cbSize, NULL, &cb);
  192. cbSize += cb + 1; // SerialNumber INTEGER
  193. cbSize += pCertId->IssuerSerialNumber.Issuer.cbData; // Issuer ANY
  194. ICM_GetLengthOctets( cbSize, NULL, &cb);
  195. cbSize += cb + 1; // IssuerSerialNumber seq
  196. break;
  197. case CERT_ID_KEY_IDENTIFIER:
  198. cbSize = pCertId->KeyId.cbData;
  199. ICM_GetLengthOctets( cbSize, NULL, &cb);
  200. cbSize += cb + 1; // KeyId OCTET STRING
  201. break;
  202. default:
  203. goto InvalidCertIdChoice;
  204. };
  205. CommonReturn:
  206. return cbSize;
  207. ErrorReturn:
  208. cbSize = INVALID_ENCODING_SIZE;
  209. goto CommonReturn;
  210. SET_ERROR(InvalidCertIdChoice, E_INVALIDARG)
  211. }
  212. //+-------------------------------------------------------------------------
  213. // Calculate the length of the EncryptedDigest encoded blob plus the
  214. // algorithm identifier
  215. //--------------------------------------------------------------------------
  216. DWORD
  217. WINAPI
  218. ICM_LengthEncryptedDigestAndAlgorithm(
  219. IN HCRYPTPROV hCryptProv,
  220. IN DWORD dwKeySpec,
  221. IN PCRYPT_ALGORITHM_IDENTIFIER paiDigest,
  222. IN PCRYPT_ALGORITHM_IDENTIFIER paiDigestEncrypt)
  223. {
  224. DWORD dwError = ERROR_SUCCESS;
  225. DWORD cbSignature;
  226. DWORD cbSize = 0;
  227. DWORD cb;
  228. HCRYPTHASH hHash = NULL;
  229. PCCRYPT_OID_INFO pOIDInfo;
  230. DWORD dwAlgIdDigest;
  231. DWORD dwAlgIdPubKey;
  232. DWORD dwAlgIdFlags;
  233. CRYPT_ALGORITHM_IDENTIFIER aiDigestEncrypt;
  234. BOOL fNoNullParameters;
  235. dwAlgIdPubKey = 0;
  236. dwAlgIdFlags = 0;
  237. if (pOIDInfo = CryptFindOIDInfo(
  238. CRYPT_OID_INFO_OID_KEY,
  239. paiDigestEncrypt->pszObjId,
  240. CRYPT_PUBKEY_ALG_OID_GROUP_ID)) {
  241. dwAlgIdPubKey = pOIDInfo->Algid;
  242. if (1 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD)) {
  243. DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
  244. dwAlgIdFlags = pdwExtra[0];
  245. }
  246. // Check if more than just the NULL parameters
  247. if (2 < paiDigestEncrypt->Parameters.cbData) {
  248. // Check if we should use the public key parameters
  249. if (0 == (dwAlgIdFlags &
  250. CRYPT_OID_USE_PUBKEY_PARA_FOR_PKCS7_FLAG)) {
  251. memset(&aiDigestEncrypt, 0, sizeof(aiDigestEncrypt));
  252. aiDigestEncrypt.pszObjId = paiDigestEncrypt->pszObjId;
  253. paiDigestEncrypt = &aiDigestEncrypt;
  254. }
  255. }
  256. } else if (pOIDInfo = CryptFindOIDInfo(
  257. CRYPT_OID_INFO_OID_KEY,
  258. paiDigestEncrypt->pszObjId,
  259. CRYPT_SIGN_ALG_OID_GROUP_ID)) {
  260. DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
  261. if (1 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD))
  262. dwAlgIdPubKey = pdwExtra[0];
  263. if (2 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD))
  264. dwAlgIdFlags = pdwExtra[1];
  265. }
  266. if (CALG_DSS_SIGN == dwAlgIdPubKey &&
  267. 0 == (dwAlgIdFlags & CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG))
  268. cbSignature = CERT_MAX_ASN_ENCODED_DSS_SIGNATURE_LEN;
  269. else {
  270. if (dwKeySpec == 0)
  271. dwKeySpec = AT_SIGNATURE;
  272. if (!(ICM_GetCAPI(
  273. CRYPT_HASH_ALG_OID_GROUP_ID,
  274. paiDigest,
  275. &dwAlgIdDigest) ||
  276. ICM_GetCAPI(
  277. CRYPT_SIGN_ALG_OID_GROUP_ID,
  278. paiDigest,
  279. &dwAlgIdDigest)))
  280. goto DigestGetCAPIError;
  281. if (!CryptCreateHash(
  282. hCryptProv,
  283. dwAlgIdDigest,
  284. NULL, // hKey - optional for MAC
  285. 0, // dwFlags
  286. &hHash))
  287. goto CreateHashError;
  288. if (!CryptHashData(
  289. hHash,
  290. (PBYTE)&cb,
  291. sizeof(DWORD),
  292. 0)) // dwFlags
  293. goto HashDataError;
  294. if (CALG_NO_SIGN == dwAlgIdPubKey) {
  295. if (!CryptGetHashParam(
  296. hHash,
  297. HP_HASHVAL,
  298. NULL, // pbHash
  299. &cbSignature,
  300. 0)) // dwFlags
  301. goto GetHashParamSizeError;
  302. } else {
  303. if (!CryptSignHash(
  304. hHash,
  305. dwKeySpec,
  306. NULL, // description
  307. 0, // dwFlags
  308. NULL, // pb
  309. &cbSignature))
  310. goto SignHashSizeError;
  311. }
  312. }
  313. ICM_GetLengthOctets( cbSignature, NULL, &cb);
  314. cbSize += cbSignature + cb + 1; // OCTET STRING
  315. if (0 == paiDigestEncrypt->Parameters.cbData &&
  316. 0 != (dwAlgIdFlags & CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG))
  317. fNoNullParameters = TRUE;
  318. // NO NULL parameters
  319. else
  320. fNoNullParameters = FALSE;
  321. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier(
  322. paiDigestEncrypt, fNoNullParameters)))
  323. goto SubjectPublicKeyInfoAlgorithmError;
  324. cbSize += cb;
  325. CommonReturn:
  326. if (hHash)
  327. CryptDestroyHash(hHash);
  328. ICM_SetLastError(dwError);
  329. return cbSize;
  330. ErrorReturn:
  331. dwError = GetLastError();
  332. cbSize = INVALID_ENCODING_SIZE;
  333. goto CommonReturn;
  334. SET_ERROR(DigestGetCAPIError,CRYPT_E_UNKNOWN_ALGO)
  335. TRACE_ERROR(SubjectPublicKeyInfoAlgorithmError)
  336. TRACE_ERROR(CreateHashError)
  337. TRACE_ERROR(HashDataError)
  338. TRACE_ERROR(GetHashParamSizeError)
  339. TRACE_ERROR(SignHashSizeError)
  340. }
  341. //+-------------------------------------------------------------------------
  342. // Calculate the length of the Digest encoded blob.
  343. //--------------------------------------------------------------------------
  344. DWORD
  345. WINAPI
  346. ICM_LengthDigest(
  347. IN HCRYPTPROV hCryptProv,
  348. IN PCRYPT_ALGORITHM_IDENTIFIER paiDigest)
  349. {
  350. DWORD dwError = ERROR_SUCCESS;
  351. DWORD cbSize;
  352. DWORD cb;
  353. DWORD dwAlgIdDigest;
  354. HCRYPTHASH hHash = NULL;
  355. if (0 == hCryptProv) {
  356. if (0 == (hCryptProv = I_CryptGetDefaultCryptProv(0)))
  357. goto GetDefaultCryptProvError;
  358. }
  359. if (!ICM_GetCAPI(
  360. CRYPT_HASH_ALG_OID_GROUP_ID,
  361. paiDigest,
  362. &dwAlgIdDigest))
  363. goto DigestGetCAPIError;
  364. if (!CryptCreateHash(
  365. hCryptProv,
  366. dwAlgIdDigest,
  367. NULL, // hKey - optional for MAC
  368. 0, // dwFlags
  369. &hHash))
  370. goto CreateHashError;
  371. if (!CryptHashData(
  372. hHash,
  373. (PBYTE)&cb,
  374. sizeof(DWORD),
  375. 0)) // dwFlags
  376. goto HashDataError;
  377. if (!CryptGetHashParam(
  378. hHash,
  379. HP_HASHVAL,
  380. NULL, // pbHash
  381. &cbSize,
  382. 0)) // dwFlags
  383. goto GetHashParamSizeError;
  384. ICM_GetLengthOctets( cbSize, NULL, &cb);
  385. cbSize += cb + 1; // OCTET STRING
  386. CommonReturn:
  387. if (hHash)
  388. CryptDestroyHash(hHash);
  389. ICM_SetLastError(dwError);
  390. return cbSize;
  391. ErrorReturn:
  392. dwError = GetLastError();
  393. cbSize = INVALID_ENCODING_SIZE;
  394. goto CommonReturn;
  395. TRACE_ERROR(GetDefaultCryptProvError)
  396. SET_ERROR(DigestGetCAPIError,CRYPT_E_UNKNOWN_ALGO)
  397. TRACE_ERROR(CreateHashError)
  398. TRACE_ERROR(HashDataError)
  399. TRACE_ERROR(GetHashParamSizeError)
  400. }
  401. //+-------------------------------------------------------------------------
  402. // Calculate the length of the Attributes encoded blob.
  403. //--------------------------------------------------------------------------
  404. DWORD
  405. WINAPI
  406. ICM_LengthAttributes(
  407. IN HCRYPTPROV hCryptProv,
  408. IN PCRYPT_ALGORITHM_IDENTIFIER paiDigest,
  409. IN DWORD cAttr,
  410. IN PCRYPT_ATTRIBUTE rgAttr,
  411. IN LPSTR pszInnerContentObjID,
  412. IN BOOL fAuthAttr)
  413. {
  414. DWORD cbSize = 0;
  415. DWORD cbAttrS;
  416. DWORD cbAttr;
  417. DWORD cbTmp;
  418. DWORD cb;
  419. PCRYPT_ATTRIBUTE patr;
  420. PCRYPT_ATTR_BLOB pblobAttr;
  421. DWORD i;
  422. DWORD j;
  423. BOOL fDataType = !pszInnerContentObjID ||
  424. (0 == strcmp( pszInnerContentObjID, pszObjIdDataType));
  425. for (i=cAttr, patr=rgAttr, cbAttrS=0;
  426. i>0;
  427. i--, patr++) {
  428. if (0 == (cbAttr = ICM_LengthObjId( patr->pszObjId)))
  429. goto PatrLengthObjIdError;
  430. for (j=patr->cValue, pblobAttr=patr->rgValue, cbTmp=0;
  431. j>0;
  432. j--, pblobAttr++)
  433. cbTmp += pblobAttr->cbData;
  434. ICM_GetLengthOctets( cbTmp, NULL, &cb);
  435. cbAttr += cbTmp + cb + 1; // AttributeSetValue set
  436. ICM_GetLengthOctets( cbAttr, NULL, &cb);
  437. cbAttrS += cbAttr + cb + 1; // Attribute seq
  438. }
  439. if (fAuthAttr && (cAttr || !fDataType)) {
  440. // content type
  441. cbAttr = ICM_LengthObjId( szOID_RSA_contentType);
  442. if (INVALID_ENCODING_SIZE == (cbTmp = ICM_LengthObjId(
  443. pszInnerContentObjID ?
  444. pszInnerContentObjID : pszObjIdDataType)))
  445. goto InnerContentLengthObjIdError;
  446. ICM_GetLengthOctets( cbTmp, NULL, &cb);
  447. cbAttr += cbTmp + cb + 1; // AttributeSetValue set
  448. ICM_GetLengthOctets( cbAttr, NULL, &cb);
  449. cbAttrS += cbAttr + cb + 1; // Attribute seq
  450. // message digest
  451. cbAttr = ICM_LengthObjId( szOID_RSA_messageDigest);
  452. if (INVALID_ENCODING_SIZE == (cbTmp = ICM_LengthDigest( hCryptProv, paiDigest)))
  453. goto LengthDigestError;
  454. ICM_GetLengthOctets( cbTmp, NULL, &cb);
  455. cbAttr += cbTmp + cb + 1; // AttributeSetValue set
  456. ICM_GetLengthOctets( cbAttr, NULL, &cb);
  457. cbAttrS += cbAttr + cb + 1; // Attribute seq
  458. }
  459. if (cbAttrS) {
  460. ICM_GetLengthOctets( cbAttrS, NULL, &cb);
  461. cbSize = cbAttrS + cb + 1; // Attributes set
  462. }
  463. CommonReturn:
  464. return cbSize;
  465. ErrorReturn:
  466. cbSize = INVALID_ENCODING_SIZE;
  467. goto CommonReturn;
  468. TRACE_ERROR(PatrLengthObjIdError) // error already set
  469. TRACE_ERROR(InnerContentLengthObjIdError) // error already set
  470. TRACE_ERROR(LengthDigestError) // error already set
  471. }
  472. //+-------------------------------------------------------------------------
  473. // Calculate the length of the SignerInfos encoded blob.
  474. //--------------------------------------------------------------------------
  475. DWORD
  476. WINAPI
  477. ICM_LengthSignerInfos(
  478. IN DWORD cSigners,
  479. IN PCMSG_SIGNER_ENCODE_INFO rgSigners,
  480. IN LPSTR pszInnerContentObjID
  481. #ifdef CMS_PKCS7
  482. ,
  483. OUT BOOL *pfHasCmsSignerId
  484. #endif // CMS_PKCS7
  485. )
  486. {
  487. DWORD cbSize;
  488. DWORD cbSigner;
  489. DWORD cbSignerS;
  490. DWORD cb;
  491. PCMSG_SIGNER_ENCODE_INFO psei;
  492. DWORD i;
  493. PCRYPT_ALGORITHM_IDENTIFIER paiDigestEncrypt;
  494. CERT_ID SignerId;
  495. #ifdef CMS_PKCS7
  496. *pfHasCmsSignerId = FALSE;
  497. #endif // CMS_PKCS7
  498. for (i=cSigners, psei=rgSigners, cbSignerS=0;
  499. i>0;
  500. i--,
  501. #ifdef CMS_PKCS7
  502. psei = (PCMSG_SIGNER_ENCODE_INFO) ((BYTE *) psei + psei->cbSize)) {
  503. #else
  504. psei++) {
  505. #endif // CMS_PKCS7
  506. cbSigner = 1 + 1 + 1; // version
  507. if (!ICM_GetSignerIdFromSignerEncodeInfo(psei, &SignerId))
  508. goto GetSignerIdError;
  509. #ifdef CMS_PKCS7
  510. if (CERT_ID_ISSUER_SERIAL_NUMBER != SignerId.dwIdChoice)
  511. *pfHasCmsSignerId = TRUE;
  512. #endif // CMS_PKCS7
  513. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthCertId( &SignerId)))
  514. goto CertIdError;
  515. cbSigner += cb;
  516. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier( &psei->HashAlgorithm)))
  517. goto HashAlgorithmError;
  518. cbSigner += cb;
  519. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAttributes(
  520. psei->hCryptProv,
  521. &psei->HashAlgorithm,
  522. psei->cAuthAttr,
  523. psei->rgAuthAttr,
  524. pszInnerContentObjID,
  525. TRUE)))
  526. goto AuthAttributesError;
  527. cbSigner += cb;
  528. #ifdef CMS_PKCS7
  529. if (STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO, HashEncryptionAlgorithm) <=
  530. psei->cbSize && psei->HashEncryptionAlgorithm.pszObjId)
  531. paiDigestEncrypt = &psei->HashEncryptionAlgorithm;
  532. else
  533. #endif // CMS_PKCS7
  534. paiDigestEncrypt = &psei->pCertInfo->SubjectPublicKeyInfo.Algorithm;
  535. if (INVALID_ENCODING_SIZE == (cb =
  536. ICM_LengthEncryptedDigestAndAlgorithm(
  537. psei->hCryptProv,
  538. psei->dwKeySpec,
  539. &psei->HashAlgorithm,
  540. paiDigestEncrypt)))
  541. goto EncryptedDigestError;
  542. cbSigner += cb;
  543. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAttributes(
  544. NULL,
  545. NULL,
  546. psei->cUnauthAttr,
  547. psei->rgUnauthAttr,
  548. NULL,
  549. FALSE)))
  550. goto UnauthAttributesError;
  551. cbSigner += cb;
  552. ICM_GetLengthOctets( cbSigner, NULL, &cb);
  553. cbSignerS += cbSigner + cb + 1; // SignerInfo seq
  554. }
  555. ICM_GetLengthOctets( cbSignerS, NULL, &cb);
  556. cbSize = cbSignerS + cb + 1; // SignerInfo seq
  557. CommonReturn:
  558. return cbSize;
  559. ErrorReturn:
  560. cbSize = INVALID_ENCODING_SIZE;
  561. goto CommonReturn;
  562. TRACE_ERROR(GetSignerIdError) // error already set
  563. TRACE_ERROR(CertIdError) // error already set
  564. TRACE_ERROR(HashAlgorithmError) // error already set
  565. TRACE_ERROR(AuthAttributesError) // error already set
  566. TRACE_ERROR(UnauthAttributesError) // error already set
  567. TRACE_ERROR(EncryptedDigestError) // error already set
  568. }
  569. //+-------------------------------------------------------------------------
  570. // Calculate the length of the SignedData.digestAlgorithms encoded blob.
  571. //
  572. #ifndef CMS_PKCS7
  573. // Assumes no duplicate removal. OK for single-signer case, which
  574. // is only one currently supported.
  575. #endif
  576. //--------------------------------------------------------------------------
  577. DWORD
  578. WINAPI
  579. ICM_LengthSignedDigestAlgorithms(
  580. IN DWORD cSigners,
  581. IN PCMSG_SIGNER_ENCODE_INFO rgSigners)
  582. {
  583. DWORD cbSize;
  584. DWORD cbAlgoS;
  585. DWORD cb;
  586. PCMSG_SIGNER_ENCODE_INFO psei;
  587. DWORD i;
  588. #ifdef CMS_PKCS7
  589. for (i=cSigners, psei=rgSigners, cbAlgoS=0; i>0;
  590. i--,
  591. psei = (PCMSG_SIGNER_ENCODE_INFO) ((BYTE *) psei + psei->cbSize)) {
  592. assert(STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO, rgUnauthAttr) <=
  593. psei->cbSize);
  594. if (ICM_IsDuplicateSignerEncodeHashAlgorithm(
  595. rgSigners,
  596. psei
  597. ))
  598. continue;
  599. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier( &psei->HashAlgorithm)))
  600. goto HashAlgorithmError;
  601. cbAlgoS += cb;
  602. }
  603. #else
  604. for (i=cSigners, psei=rgSigners, cbAlgoS=0;
  605. i>0;
  606. i--, psei++) {
  607. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier( &psei->HashAlgorithm)))
  608. goto HashAlgorithmError;
  609. cbAlgoS += cb;
  610. }
  611. #endif // CMS_PKCS7
  612. ICM_GetLengthOctets( cbAlgoS, NULL, &cb);
  613. cbSize = cbAlgoS + cb + 1; // digestAlgorithms set
  614. CommonReturn:
  615. return cbSize;
  616. ErrorReturn:
  617. cbSize = INVALID_ENCODING_SIZE;
  618. goto CommonReturn;
  619. TRACE_ERROR(HashAlgorithmError) // error already set
  620. }
  621. #ifdef CMS_PKCS7
  622. //+-------------------------------------------------------------------------
  623. // Calculate the length of an enveloped message.
  624. //--------------------------------------------------------------------------
  625. DWORD
  626. WINAPI
  627. ICM_LengthEnveloped(
  628. IN PCMSG_ENVELOPED_ENCODE_INFO pemei,
  629. IN DWORD dwFlags,
  630. IN OPTIONAL LPSTR pszInnerContentObjID,
  631. IN DWORD cbData,
  632. OUT OPTIONAL PDWORD pcbContent)
  633. {
  634. DWORD dwError = ERROR_SUCCESS;
  635. DWORD cbSize;
  636. DWORD cb;
  637. CMSG_CONTENT_ENCRYPT_INFO ContentEncryptInfo;
  638. ZEROSTRUCT(ContentEncryptInfo);
  639. CmsRecipientInfos recipientInfos; ZEROSTRUCT(recipientInfos);
  640. #ifdef OSS_CRYPT_ASN1
  641. int version = 0;
  642. #else
  643. ASN1int32_t version = 0;
  644. #endif // OSS_CRYPT_ASN1
  645. ASN1error_e Asn1Err;
  646. ASN1encoding_t pEnc = ICM_GetEncoder();
  647. PBYTE pbEncoded = NULL;
  648. DWORD cbEncoded;
  649. assert(pemei->cbSize >= STRUCT_CBSIZE(CMSG_ENVELOPED_ENCODE_INFO,
  650. rgpRecipients));
  651. #ifdef CMS_PKCS7
  652. if (pemei->cbSize <
  653. STRUCT_CBSIZE(CMSG_ENVELOPED_ENCODE_INFO, rgpRecipients))
  654. #else
  655. assert(0 != pemei->cRecipients);
  656. if (pemei->cbSize <
  657. STRUCT_CBSIZE(CMSG_ENVELOPED_ENCODE_INFO, rgpRecipients) ||
  658. 0 == pemei->cRecipients)
  659. #endif // CMS_PKCS7
  660. goto InvalidArg;
  661. // version
  662. cbSize = 1 + 1 + 1;
  663. // originatorInfo OPTIONAL
  664. //
  665. // unprotectedAttrs OPTIONAL
  666. if (pemei->cbSize >= sizeof(CMSG_ENVELOPED_ENCODE_INFO)) {
  667. DWORD cbOriginator = 0;
  668. DWORD cbTmp;
  669. DWORD i;
  670. PCERT_BLOB pCert;
  671. PCRL_BLOB pCrl;
  672. cbOriginator = 0;
  673. for (i = pemei->cCertEncoded, pCert = pemei->rgCertEncoded, cbTmp=0;
  674. i > 0;
  675. i--, pCert++)
  676. cbTmp += pCert->cbData;
  677. for (i = pemei->cAttrCertEncoded, pCert = pemei->rgAttrCertEncoded;
  678. i > 0;
  679. i--, pCert++)
  680. cbTmp += pCert->cbData;
  681. if (cbTmp) {
  682. ICM_GetLengthOctets(cbTmp, NULL, &cb);
  683. cbOriginator += 1 + cb + cbTmp; // [0] IMPLICIT Certificates
  684. }
  685. for (i = pemei->cCrlEncoded, pCrl = pemei->rgCrlEncoded, cbTmp=0;
  686. i > 0;
  687. i--, pCrl++)
  688. cbTmp += pCrl->cbData;
  689. if (cbTmp) {
  690. ICM_GetLengthOctets(cbTmp, NULL, &cb);
  691. cbOriginator += 1 + cb + cbTmp; // [1] IMPLICIT Crls
  692. }
  693. if (cbOriginator) {
  694. ICM_GetLengthOctets(cbOriginator, NULL, &cb);
  695. cbSize += 1 + cb + cbOriginator; // [0] IMPLICIT OriginatorInfo
  696. }
  697. if (0 < pemei->cUnprotectedAttr) {
  698. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAttributes(
  699. NULL,
  700. NULL,
  701. pemei->cUnprotectedAttr,
  702. pemei->rgUnprotectedAttr,
  703. NULL,
  704. FALSE)))
  705. goto UnprotectedAttrError;
  706. cbSize += cb;
  707. }
  708. }
  709. // recipientInfos
  710. if (!ICM_InitializeContentEncryptInfo(pemei, &ContentEncryptInfo))
  711. goto InitializeContentEncryptInfoError;
  712. ContentEncryptInfo.dwEncryptFlags |=
  713. CMSG_CONTENT_ENCRYPT_PAD_ENCODED_LEN_FLAG;
  714. if (!ICM_FillOssCmsRecipientInfos(
  715. &ContentEncryptInfo,
  716. &recipientInfos,
  717. &version
  718. ))
  719. goto FillOssCmsRecipientInfosError;
  720. if (0 != (Asn1Err = PkiAsn1Encode(
  721. pEnc,
  722. &recipientInfos,
  723. CmsRecipientInfos_PDU,
  724. &pbEncoded,
  725. &cbEncoded)))
  726. goto EncodeCmsRecipientInfosError;
  727. cbSize += cbEncoded;
  728. // encryptedContentInfo
  729. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthEncryptedContentInfo(
  730. ContentEncryptInfo.hContentEncryptKey,
  731. &ContentEncryptInfo.ContentEncryptionAlgorithm,
  732. pszInnerContentObjID,
  733. cbData)))
  734. goto LengthEncryptedContentInfoError;
  735. cbSize += cb;
  736. if (pcbContent)
  737. *pcbContent = cbSize;
  738. ICM_GetLengthOctets( cbSize, NULL, &cb);
  739. cbSize += 1 + cb; // CmsEnvelopedData seq
  740. CommonReturn:
  741. PkiAsn1FreeEncoded(pEnc, pbEncoded);
  742. ICM_FreeContentEncryptInfo(pemei, &ContentEncryptInfo);
  743. ICM_FreeOssCmsRecipientInfos(&recipientInfos);
  744. ICM_SetLastError(dwError);
  745. return cbSize;
  746. ErrorReturn:
  747. dwError = GetLastError();
  748. cbSize = INVALID_ENCODING_SIZE;
  749. goto CommonReturn;
  750. SET_ERROR(InvalidArg,E_INVALIDARG)
  751. TRACE_ERROR(UnprotectedAttrError)
  752. TRACE_ERROR(InitializeContentEncryptInfoError)
  753. TRACE_ERROR(FillOssCmsRecipientInfosError)
  754. SET_ERROR_VAR(EncodeCmsRecipientInfosError, PkiAsn1ErrToHr(Asn1Err))
  755. TRACE_ERROR(LengthEncryptedContentInfoError)
  756. }
  757. #else
  758. //+-------------------------------------------------------------------------
  759. // Calculate the length of the EncryptedKey encoded blob.
  760. //--------------------------------------------------------------------------
  761. DWORD
  762. WINAPI
  763. ICM_LengthEncryptedKey(
  764. IN HCRYPTPROV hCryptProv,
  765. IN HCRYPTKEY hEncryptKey,
  766. IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
  767. IN DWORD dwEncryptFlags)
  768. {
  769. DWORD cbSize;
  770. // rgcbEncryptedKey[1] contains dwEncryptFlags
  771. DWORD rgcbEncryptedKey[2];
  772. DWORD cb;
  773. rgcbEncryptedKey[1] = dwEncryptFlags;
  774. // Length only export calculation
  775. if (!ICM_ExportEncryptKey(
  776. hCryptProv,
  777. hEncryptKey,
  778. pPublicKeyInfo,
  779. NULL, // pbData
  780. rgcbEncryptedKey) || 0 == rgcbEncryptedKey[0])
  781. goto ExportKeyError;
  782. // Add bytes for ASN.1 tag and length
  783. ICM_GetLengthOctets(rgcbEncryptedKey[0], NULL, &cb);
  784. cbSize = rgcbEncryptedKey[0] + cb + 1; // OCTET STRING
  785. CommonReturn:
  786. return cbSize;
  787. ErrorReturn:
  788. cbSize = INVALID_ENCODING_SIZE;
  789. goto CommonReturn;
  790. TRACE_ERROR(ExportKeyError)
  791. }
  792. //+-------------------------------------------------------------------------
  793. // Calculate the length of the RecipientInfos encoded blob.
  794. //--------------------------------------------------------------------------
  795. DWORD
  796. WINAPI
  797. ICM_LengthRecipientInfos(
  798. IN HCRYPTPROV hCryptProv,
  799. IN HCRYPTKEY hEncryptKey,
  800. IN DWORD cRecipients,
  801. IN PCERT_INFO *rgpRecipients,
  802. IN DWORD dwEncryptFlags)
  803. {
  804. DWORD cbSize;
  805. DWORD cbRecipient;
  806. DWORD cbRecipientS;
  807. DWORD cb;
  808. PCERT_INFO *ppCertInfo;
  809. DWORD i;
  810. for (i=cRecipients, ppCertInfo=rgpRecipients, cbRecipientS=0;
  811. i>0;
  812. i--, ppCertInfo++) {
  813. cbRecipient = 1 + 1 + 1; // version
  814. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthIssuerAndSerialNumber( *ppCertInfo)))
  815. goto IssuerAndSerialNumberError;
  816. cbRecipient += cb;
  817. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier(
  818. &(*ppCertInfo)->SubjectPublicKeyInfo.Algorithm)))
  819. goto SubjectPublicKeyInfoAlgorithmError;
  820. cbRecipient += cb;
  821. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthEncryptedKey(
  822. hCryptProv,
  823. hEncryptKey,
  824. &(*ppCertInfo)->SubjectPublicKeyInfo,
  825. dwEncryptFlags)))
  826. goto EncryptedKeyError;
  827. cbRecipient += cb;
  828. ICM_GetLengthOctets( cbRecipient, NULL, &cb);
  829. cbRecipientS += cbRecipient + cb + 1; // RecipientInfo
  830. }
  831. ICM_GetLengthOctets( cbRecipientS, NULL, &cb);
  832. cbSize = cbRecipientS + cb + 1; // RecipientInfos seq
  833. CommonReturn:
  834. return cbSize;
  835. ErrorReturn:
  836. cbSize = INVALID_ENCODING_SIZE;
  837. goto CommonReturn;
  838. TRACE_ERROR(IssuerAndSerialNumberError) // error already set
  839. TRACE_ERROR(SubjectPublicKeyInfoAlgorithmError) // error already set
  840. TRACE_ERROR(EncryptedKeyError) // error already set
  841. }
  842. //+-------------------------------------------------------------------------
  843. // Calculate the length of an enveloped message.
  844. //--------------------------------------------------------------------------
  845. DWORD
  846. WINAPI
  847. ICM_LengthEnveloped(
  848. IN PCMSG_ENVELOPED_ENCODE_INFO pemei,
  849. IN DWORD dwFlags,
  850. IN OPTIONAL LPSTR pszInnerContentObjID,
  851. IN DWORD cbData,
  852. OUT OPTIONAL PDWORD pcbContent)
  853. {
  854. DWORD dwError = ERROR_SUCCESS;
  855. DWORD cbSize;
  856. DWORD cb;
  857. HCRYPTPROV hCryptProv;
  858. HCRYPTKEY hEncryptKey = NULL;
  859. CRYPT_ALGORITHM_IDENTIFIER ContentEncryptionAlgorithm;
  860. PBYTE pbEncryptParameters = NULL;
  861. // rgcbEncryptParameters[1] contains dwEncryptFlags
  862. DWORD rgcbEncryptParameters[2];
  863. // version
  864. cbSize = 1 + 1 + 1;
  865. if (0 == pemei->cRecipients)
  866. goto InvalidArg;
  867. hCryptProv = pemei->hCryptProv;
  868. ContentEncryptionAlgorithm = pemei->ContentEncryptionAlgorithm;
  869. rgcbEncryptParameters[0] = 0;
  870. rgcbEncryptParameters[1] = 0; // dwEncryptFlags
  871. if (!ICM_GenEncryptKey(
  872. &hCryptProv,
  873. &ContentEncryptionAlgorithm,
  874. pemei->pvEncryptionAuxInfo,
  875. &pemei->rgpRecipients[0]->SubjectPublicKeyInfo,
  876. ICM_Alloc,
  877. &hEncryptKey,
  878. &pbEncryptParameters,
  879. rgcbEncryptParameters))
  880. goto GenKeyError;
  881. if (rgcbEncryptParameters[0] && pbEncryptParameters) {
  882. ContentEncryptionAlgorithm.Parameters.pbData = pbEncryptParameters;
  883. ContentEncryptionAlgorithm.Parameters.cbData = rgcbEncryptParameters[0];
  884. }
  885. // recipientInfos
  886. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthRecipientInfos(
  887. hCryptProv,
  888. hEncryptKey,
  889. pemei->cRecipients,
  890. pemei->rgpRecipients,
  891. rgcbEncryptParameters[1]))) // dwEncryptFlags
  892. goto LengthRecipientInfosError;
  893. cbSize += cb;
  894. // encryptedContentInfo
  895. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthEncryptedContentInfo(
  896. hEncryptKey,
  897. &ContentEncryptionAlgorithm,
  898. pszInnerContentObjID,
  899. cbData)))
  900. goto LengthEncryptedContentInfoError;
  901. cbSize += cb;
  902. if (pcbContent)
  903. *pcbContent = cbSize;
  904. ICM_GetLengthOctets( cbSize, NULL, &cb);
  905. cbSize += 1 + cb; // EnvelopedData seq
  906. CommonReturn:
  907. if (hEncryptKey)
  908. CryptDestroyKey(hEncryptKey);
  909. ICM_Free(pbEncryptParameters);
  910. ICM_SetLastError(dwError);
  911. return cbSize;
  912. ErrorReturn:
  913. dwError = GetLastError();
  914. cbSize = INVALID_ENCODING_SIZE;
  915. goto CommonReturn;
  916. SET_ERROR(InvalidArg,E_INVALIDARG)
  917. TRACE_ERROR(GenKeyError)
  918. TRACE_ERROR(LengthRecipientInfosError)
  919. TRACE_ERROR(LengthEncryptedContentInfoError)
  920. }
  921. #endif // CMS_PKCS7
  922. //+-------------------------------------------------------------------------
  923. // Calculate the length of a signed message.
  924. //--------------------------------------------------------------------------
  925. DWORD
  926. WINAPI
  927. ICM_LengthSigned(
  928. IN PCMSG_SIGNED_ENCODE_INFO psmei,
  929. IN DWORD dwFlags,
  930. IN OPTIONAL LPSTR pszInnerContentObjID,
  931. IN DWORD cbData,
  932. OUT OPTIONAL PDWORD pcbContent)
  933. {
  934. DWORD cbSize;
  935. DWORD cbSignedData;
  936. DWORD cbTmp;
  937. DWORD cb;
  938. DWORD i;
  939. PCERT_BLOB pCert;
  940. PCRL_BLOB pCrl;
  941. #ifdef CMS_PKCS7
  942. DWORD cAttrCertEncoded;
  943. BOOL fHasCmsSignerId = FALSE;
  944. #endif // CMS_PKCS7
  945. cbSignedData = 1 + 1 + 1; // version
  946. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthSignedDigestAlgorithms(
  947. psmei->cSigners,
  948. psmei->rgSigners)))
  949. goto LengthSignedDigestAlgorithmsError;
  950. cbSignedData += cb;
  951. #ifdef CMS_PKCS7
  952. if (psmei->cbSize >= STRUCT_CBSIZE(CMSG_SIGNED_ENCODE_INFO,
  953. rgAttrCertEncoded)) {
  954. cAttrCertEncoded = psmei->cAttrCertEncoded;
  955. if (cAttrCertEncoded)
  956. dwFlags |= CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
  957. } else
  958. cAttrCertEncoded = 0;
  959. #endif // CMS_PKCS7
  960. // Do this before the ContentInfo. Need to know if we need to
  961. // encapsulate the content for KeyId Signers.
  962. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthSignerInfos(
  963. psmei->cSigners,
  964. psmei->rgSigners,
  965. pszInnerContentObjID
  966. #ifdef CMS_PKCS7
  967. ,
  968. &fHasCmsSignerId
  969. #endif // CMS_PKCS7
  970. )))
  971. goto SignerInfosError;
  972. cbSignedData += cb;
  973. #ifdef CMS_PKCS7
  974. if (fHasCmsSignerId)
  975. dwFlags |= CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
  976. #endif // CMS_PKCS7
  977. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthContentInfo(
  978. dwFlags,
  979. pszInnerContentObjID,
  980. cbData,
  981. NULL)))
  982. goto LengthContentInfoError;
  983. cbSignedData += cb;
  984. for (i = psmei->cCertEncoded, pCert = psmei->rgCertEncoded, cbTmp=0;
  985. i > 0;
  986. i--, pCert++)
  987. cbTmp += pCert->cbData;
  988. #ifdef CMS_PKCS7
  989. if (cAttrCertEncoded) {
  990. for (i = cAttrCertEncoded, pCert = psmei->rgAttrCertEncoded;
  991. i > 0;
  992. i--, pCert++)
  993. cbTmp += pCert->cbData;
  994. }
  995. #endif // CMS_PKCS7
  996. if (cbTmp) {
  997. ICM_GetLengthOctets( cbTmp, NULL, &cb);
  998. cbSignedData += 1 + cb + cbTmp; // [0] IMPLICIT Certificates
  999. }
  1000. for (i = psmei->cCrlEncoded, pCrl = psmei->rgCrlEncoded, cbTmp=0;
  1001. i > 0;
  1002. i--, pCrl++)
  1003. cbTmp += pCrl->cbData;
  1004. if (cbTmp) {
  1005. ICM_GetLengthOctets( cbTmp, NULL, &cb);
  1006. cbSignedData += 1 + cb + cbTmp; // [1] IMPLICIT Crls
  1007. }
  1008. if (pcbContent)
  1009. *pcbContent = cbSignedData;
  1010. ICM_GetLengthOctets( cbSignedData, NULL, &cb);
  1011. cbSize = 1 + cb + cbSignedData; // SignedData seq
  1012. CommonReturn:
  1013. return cbSize;
  1014. ErrorReturn:
  1015. cbSize = INVALID_ENCODING_SIZE;
  1016. goto CommonReturn;
  1017. TRACE_ERROR(LengthSignedDigestAlgorithmsError) // error already set
  1018. TRACE_ERROR(LengthContentInfoError) // error already set
  1019. TRACE_ERROR(SignerInfosError) // error already set
  1020. }
  1021. //+-------------------------------------------------------------------------
  1022. // Calculate the length of a digested message.
  1023. //--------------------------------------------------------------------------
  1024. DWORD
  1025. WINAPI
  1026. ICM_LengthDigested(
  1027. IN PCMSG_HASHED_ENCODE_INFO pdmei,
  1028. IN DWORD dwFlags,
  1029. IN OPTIONAL LPSTR pszInnerContentObjID,
  1030. IN DWORD cbData,
  1031. OUT OPTIONAL PDWORD pcbContent)
  1032. {
  1033. DWORD cbSize;
  1034. DWORD cb;
  1035. cbSize = 1 + 1 + 1; // version
  1036. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthAlgorithmIdentifier( &pdmei->HashAlgorithm)))
  1037. goto HashAlgorithmError;
  1038. cbSize += cb;
  1039. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthContentInfo(
  1040. dwFlags,
  1041. pszInnerContentObjID,
  1042. cbData,
  1043. NULL)))
  1044. goto LengthContentInfoError;
  1045. cbSize += cb;
  1046. if (INVALID_ENCODING_SIZE == (cb = ICM_LengthDigest( pdmei->hCryptProv, &pdmei->HashAlgorithm)))
  1047. goto DigestError;
  1048. cbSize += cb;
  1049. if (pcbContent)
  1050. *pcbContent = cbSize;
  1051. ICM_GetLengthOctets( cbSize, NULL, &cb);
  1052. cbSize += 1 + cb; // DigestedData seq
  1053. CommonReturn:
  1054. return cbSize;
  1055. ErrorReturn:
  1056. cbSize = INVALID_ENCODING_SIZE;
  1057. goto CommonReturn;
  1058. TRACE_ERROR(HashAlgorithmError) // error already set
  1059. TRACE_ERROR(LengthContentInfoError) // error already set
  1060. TRACE_ERROR(DigestError) // error already set
  1061. }
  1062. //+-------------------------------------------------------------------------
  1063. // Calculate the length of an encoded cryptographic message.
  1064. //
  1065. // Calculates the length of the encoded message given the
  1066. // message type, encoding parameters and total length of
  1067. // the data to be updated. Note, this might not be the exact length.
  1068. // However, it will always be greater than or equal to the actual length.
  1069. //--------------------------------------------------------------------------
  1070. DWORD
  1071. WINAPI
  1072. CryptMsgCalculateEncodedLength(
  1073. IN DWORD dwEncodingType,
  1074. IN DWORD dwFlags,
  1075. IN DWORD dwMsgType,
  1076. IN void const *pvMsgEncodeInfo,
  1077. IN OPTIONAL LPSTR pszInnerContentObjID,
  1078. IN DWORD cbData)
  1079. {
  1080. DWORD cbSize = INVALID_ENCODING_SIZE;
  1081. LPSTR pszContentType = NULL;
  1082. DWORD cb;
  1083. DWORD cbContent = 0;
  1084. if (GET_CMSG_ENCODING_TYPE(dwEncodingType) != PKCS_7_ASN_ENCODING)
  1085. goto InvalidEncoding;
  1086. switch (dwMsgType) {
  1087. case CMSG_DATA:
  1088. if (NULL != pvMsgEncodeInfo)
  1089. goto InvalidEncodeInfo;
  1090. cbContent = cbData;
  1091. ICM_GetLengthOctets( cbData, NULL, &cb);
  1092. cbSize = 1 + cb + cbData; // OCTET STRING
  1093. pszContentType = pszObjIdDataType;
  1094. break;
  1095. case CMSG_SIGNED:
  1096. if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthSigned(
  1097. (PCMSG_SIGNED_ENCODE_INFO)pvMsgEncodeInfo,
  1098. dwFlags,
  1099. pszInnerContentObjID,
  1100. cbData,
  1101. &cbContent)))
  1102. goto LengthSignedError;
  1103. pszContentType = szOID_RSA_signedData;
  1104. break;
  1105. case CMSG_ENVELOPED:
  1106. if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthEnveloped(
  1107. (PCMSG_ENVELOPED_ENCODE_INFO)pvMsgEncodeInfo,
  1108. dwFlags,
  1109. pszInnerContentObjID,
  1110. cbData,
  1111. &cbContent)))
  1112. goto LengthEnvelopedError;
  1113. pszContentType = szOID_RSA_envelopedData;
  1114. break;
  1115. case CMSG_HASHED:
  1116. if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthDigested(
  1117. (PCMSG_HASHED_ENCODE_INFO)pvMsgEncodeInfo,
  1118. dwFlags,
  1119. pszInnerContentObjID,
  1120. cbData,
  1121. &cbContent)))
  1122. goto LengthDigestedError;
  1123. pszContentType = szOID_RSA_digestedData;
  1124. break;
  1125. case CMSG_SIGNED_AND_ENVELOPED:
  1126. case CMSG_ENCRYPTED:
  1127. goto MessageTypeNotSupportedYet;
  1128. default:
  1129. goto InvalidMsgType;
  1130. }
  1131. if (0 == (dwFlags & CMSG_BARE_CONTENT_FLAG)) {
  1132. if (INVALID_ENCODING_SIZE == (cbSize = ICM_LengthContentInfo(
  1133. 0, // dwFlags
  1134. pszContentType,
  1135. cbSize,
  1136. &cbContent)))
  1137. goto LengthContentInfoError;
  1138. }
  1139. CommonReturn:
  1140. return (cbSize == INVALID_ENCODING_SIZE) ? 0 :
  1141. ((dwFlags & CMSG_CONTENTS_OCTETS_FLAG) ? cbContent : cbSize);
  1142. ErrorReturn:
  1143. cbSize = INVALID_ENCODING_SIZE;
  1144. goto CommonReturn;
  1145. SET_ERROR(InvalidEncoding,E_INVALIDARG)
  1146. SET_ERROR(InvalidEncodeInfo,E_INVALIDARG)
  1147. SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
  1148. SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
  1149. TRACE_ERROR(LengthSignedError) // error already set
  1150. TRACE_ERROR(LengthEnvelopedError) // error already set
  1151. TRACE_ERROR(LengthDigestedError) // error already set
  1152. TRACE_ERROR(LengthContentInfoError) // error already set
  1153. }