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.

3413 lines
113 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: msgstrm.cpp
  8. //
  9. // Contents: Cryptographic Message Streaming API support
  10. //
  11. // APIs:
  12. //
  13. // History: 20-Feb-97 kevinr created
  14. //
  15. //--------------------------------------------------------------------------
  16. #include "global.hxx"
  17. #define ICMS_NOCRYPT 0
  18. #if (DBG && ICMS_NOCRYPT)
  19. #define CryptEncrypt ICMS_PlainEncrypt
  20. #define CryptDecrypt ICMS_PlainDecrypt
  21. //+-------------------------------------------------------------------------
  22. // Encrypt a buffer using a NOP algorithm, ie. ciphertext == plaintext
  23. // Assumes that all but the last block are a multiple of the block
  24. // size in length.
  25. //--------------------------------------------------------------------------
  26. BOOL
  27. WINAPI
  28. ICMS_PlainEncrypt(
  29. IN HCRYPTKEY hkeyCrypt,
  30. IN HCRYPTHASH hHash,
  31. IN BOOL fFinal,
  32. IN DWORD dwFlags,
  33. IN OUT PBYTE pbData,
  34. IN OUT PDWORD pcbData,
  35. IN DWORD cbBuf)
  36. {
  37. BOOL fRet;
  38. DWORD cbBlockLen;
  39. BOOL fBlockCipher;
  40. DWORD cbCipher;
  41. DWORD cbPlain = *pcbData;
  42. DWORD cbPad;
  43. DWORD i;
  44. if (!fFinal)
  45. goto SuccessReturn;
  46. if (!ICM_GetKeyBlockSize( hkeyCrypt, &cbBlockLen, &fBlockCipher))
  47. goto GetKeyBlockSizeError;
  48. if (!fBlockCipher)
  49. goto SuccessReturn; // if stream, cipher == plain
  50. cbCipher = cbPlain;
  51. cbCipher += cbBlockLen;
  52. cbCipher -= cbCipher % cbBlockLen; // make a multiple of block size
  53. cbPad = cbCipher - cbPlain;
  54. if (cbCipher > cbBuf)
  55. goto BufferTooSmallError;
  56. // pad the "ciphertext"
  57. FillMemory( pbData + cbPlain, cbPad, cbPad);
  58. *pcbData = cbCipher;
  59. SuccessReturn:
  60. fRet = TRUE;
  61. CommonReturn:
  62. return fRet;
  63. ErrorReturn:
  64. fRet = FALSE;
  65. goto CommonReturn;
  66. TRACE_ERROR(GetKeyBlockSizeError) // error already set
  67. TRACE_ERROR(BufferTooSmallError) // error already set
  68. }
  69. //+-------------------------------------------------------------------------
  70. // Decrypt a buffer using a NOP algorithm, ie. ciphertext == plaintext
  71. // Assumes all input sizes are multiples of the block size.
  72. //--------------------------------------------------------------------------
  73. BOOL
  74. WINAPI
  75. ICMS_PlainDecrypt(
  76. IN HCRYPTKEY hkeyCrypt,
  77. IN HCRYPTHASH hHash,
  78. IN BOOL fFinal,
  79. IN DWORD dwFlags,
  80. IN OUT PBYTE pbData,
  81. IN OUT PDWORD pcbData)
  82. {
  83. BOOL fRet;
  84. PBYTE pb;
  85. DWORD cbBlockLen;
  86. BOOL fBlockCipher;
  87. DWORD cbCipher = *pcbData;
  88. DWORD cbPlain;
  89. DWORD cbPad;
  90. if (!fFinal)
  91. goto SuccessReturn;
  92. if (!ICM_GetKeyBlockSize( hkeyCrypt, &cbBlockLen, &fBlockCipher))
  93. goto GetKeyBlockSizeError;
  94. if (!fBlockCipher)
  95. goto SuccessReturn; // if stream, cipher == plain
  96. cbPad = (DWORD)(*(pbData + cbCipher - 1)); // check last byte
  97. if (cbCipher < cbPad)
  98. goto CipherTextTooSmallError;
  99. cbPlain = cbCipher - cbPad;
  100. *pcbData = cbPlain;
  101. SuccessReturn:
  102. fRet = TRUE;
  103. CommonReturn:
  104. return fRet;
  105. ErrorReturn:
  106. fRet = FALSE;
  107. goto CommonReturn;
  108. TRACE_ERROR(GetKeyBlockSizeError) // error already set
  109. TRACE_ERROR(CipherTextTooSmallError) // error already set
  110. }
  111. #endif // (DBG && ICMS_NOCRYPT)
  112. //+-------------------------------------------------------------------------
  113. // Do a CryptMsgGetParam to a buffer alloc'd by ICM_Alloc
  114. //--------------------------------------------------------------------------
  115. BOOL
  116. WINAPI
  117. ICMS_AllocGetParam(
  118. IN HCRYPTMSG hCryptMsg,
  119. IN DWORD dwParamType,
  120. IN DWORD dwIndex,
  121. OUT PBYTE *ppbData,
  122. OUT DWORD *pcbData)
  123. {
  124. BOOL fRet;
  125. DWORD cb;
  126. PBYTE pb = NULL;
  127. if (!CryptMsgGetParam(
  128. hCryptMsg,
  129. dwParamType,
  130. dwIndex,
  131. NULL,
  132. &cb))
  133. goto GetEncodedSizeError;
  134. if (NULL == (pb = (PBYTE)ICM_Alloc(cb)))
  135. goto AllocEncodedError;
  136. if (!CryptMsgGetParam(
  137. hCryptMsg,
  138. dwParamType,
  139. dwIndex,
  140. pb,
  141. &cb))
  142. goto GetEncodedError;
  143. fRet = TRUE;
  144. CommonReturn:
  145. *ppbData = pb;
  146. *pcbData = cb;
  147. return fRet;
  148. ErrorReturn:
  149. ICM_Free(pb);
  150. pb = NULL;
  151. cb = 0;
  152. fRet = FALSE;
  153. goto CommonReturn;
  154. TRACE_ERROR(GetEncodedSizeError)
  155. TRACE_ERROR(AllocEncodedError)
  156. TRACE_ERROR(GetEncodedError)
  157. }
  158. //+-------------------------------------------------------------------------
  159. // Peel off the identifier and length octets.
  160. //--------------------------------------------------------------------------
  161. BOOL
  162. WINAPI
  163. ICMS_ExtractContent(
  164. IN PCRYPT_MSG_INFO pcmi,
  165. IN const BYTE *pbDER,
  166. IN DWORD cbDER,
  167. OUT PDWORD pcbContent,
  168. OUT const BYTE **ppbContent)
  169. {
  170. BOOL fRet;
  171. LONG cbSkipped = 0;
  172. DWORD cbEntireContent;
  173. if (!pcmi->fStreamContentExtracted) {
  174. if (0 > (cbSkipped = Asn1UtilExtractContent(
  175. pbDER,
  176. cbDER,
  177. &cbEntireContent,
  178. ppbContent)))
  179. goto ExtractContentError;
  180. pcmi->fStreamContentExtracted = TRUE;
  181. } else {
  182. *ppbContent = pbDER;
  183. }
  184. *pcbContent = cbDER - cbSkipped;
  185. fRet = TRUE;
  186. CommonReturn:
  187. return fRet;
  188. ErrorReturn:
  189. fRet = FALSE;
  190. goto CommonReturn;
  191. TRACE_ERROR(ExtractContentError) // error already set
  192. }
  193. //+-------------------------------------------------------------------------
  194. // Get the next token from the buffer.
  195. // If the encoding is definite-length, set *pcbContent to be the size of the
  196. // contents octets.
  197. //
  198. // Here, a "token" is either identifier/length octets, or the double-NULL
  199. // terminating an indefinite-length encoding.
  200. //--------------------------------------------------------------------------
  201. BOOL
  202. WINAPI
  203. ICMS_GetToken(
  204. IN PICM_BUFFER pbuf,
  205. OUT PDWORD pdwToken,
  206. OUT OPTIONAL PDWORD pcbContent)
  207. {
  208. DWORD dwError = ERROR_SUCCESS;
  209. BOOL fRet;
  210. DWORD dwToken;
  211. LONG lth;
  212. DWORD cbContent = 0;
  213. const BYTE *pbContent;
  214. PBYTE pbData = pbuf->pbData + pbuf->cbDead;
  215. DWORD cbData = pbuf->cbUsed - pbuf->cbDead;
  216. DWORD cbConsumed = 0;
  217. if (2 > cbData) {
  218. dwToken = ICMS_TOKEN_INCOMPLETE;
  219. } else if (0 == pbData[0] && 0 == pbData[1]) {
  220. dwToken = ICMS_TOKEN_NULLPAIR;
  221. cbConsumed = 2;
  222. } else {
  223. if (0 > (lth = Asn1UtilExtractContent(
  224. pbData,
  225. cbData,
  226. &cbContent,
  227. &pbContent))) {
  228. if (ASN1UTIL_INSUFFICIENT_DATA != lth)
  229. goto ExtractContentError;
  230. dwToken = ICMS_TOKEN_INCOMPLETE;
  231. } else {
  232. dwToken = (CMSG_INDEFINITE_LENGTH == cbContent) ?
  233. ICMS_TOKEN_INDEFINITE : ICMS_TOKEN_DEFINITE;
  234. cbConsumed = (DWORD)lth;
  235. }
  236. }
  237. if (ICMS_TOKEN_INCOMPLETE != dwToken)
  238. pbuf->cbDead += cbConsumed;
  239. fRet = TRUE;
  240. CommonReturn:
  241. *pdwToken = dwToken;
  242. if (pcbContent)
  243. *pcbContent = cbContent;
  244. ICM_SetLastError(dwError);
  245. return fRet;
  246. ErrorReturn:
  247. dwError = GetLastError();
  248. dwToken = 0;
  249. cbContent = 0;
  250. fRet = FALSE;
  251. goto CommonReturn;
  252. TRACE_ERROR(ExtractContentError) // error already set
  253. }
  254. //+-------------------------------------------------------------------------
  255. // Process incremental content data, for a string.
  256. //--------------------------------------------------------------------------
  257. BOOL
  258. WINAPI
  259. ICMS_ProcessStringContent(
  260. IN PICM_BUFFER pbuf,
  261. IN OUT PDWORD paflStream,
  262. IN OUT PDWORD pcbPending,
  263. IN OUT PDWORD pcLevelIndefiniteInner,
  264. IN POSTRCALLBACK postrcbk,
  265. IN const void *pvArg)
  266. {
  267. BOOL fRet;
  268. DWORD dwToken;
  269. DWORD cbContent;
  270. while (TRUE) {
  271. if (*pcbPending) {
  272. // *pcbPending bytes need to be processed, so we process
  273. // as many as possible from the buffer.
  274. if (!postrcbk( pvArg, pbuf, pcbPending, FALSE))
  275. goto CallbackError;
  276. }
  277. if (0 == *pcbPending) {
  278. // No bytes currently counted for processing. One of:
  279. // 1. first time through
  280. // 2. last time through
  281. // 3. nested within an indefinite-length encoding
  282. if (0 == *pcLevelIndefiniteInner) {
  283. // The first time through, and also when we have processed the
  284. // entire octet string, we get here. The flag is clear
  285. // the first time (so we set it after getting a token, which
  286. // either sets *pcbPending or bumps *pcLevelIndefiniteInner),
  287. // and set afterwards (so we mark done and bail).
  288. if (*paflStream & ICMS_PROCESS_CONTENT_BEGUN) {
  289. // 2. last time through
  290. if (!postrcbk( pvArg, pbuf, pcbPending, TRUE))
  291. goto CallbackFinalError;
  292. *paflStream |= ICMS_PROCESS_CONTENT_DONE;
  293. goto SuccessReturn; // All done
  294. }
  295. }
  296. // One of:
  297. // 1. first time through
  298. // 3. nested within an indefinite-length encoding
  299. if (!ICMS_GetToken( pbuf, &dwToken, &cbContent))
  300. goto GetTokenError;
  301. switch(dwToken) {
  302. case ICMS_TOKEN_INDEFINITE: ++*pcLevelIndefiniteInner; break;
  303. case ICMS_TOKEN_NULLPAIR: --*pcLevelIndefiniteInner; break;
  304. case ICMS_TOKEN_DEFINITE: *pcbPending = cbContent; break;
  305. case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn; // need input
  306. default: goto InvalidTokenError;
  307. }
  308. *paflStream |= ICMS_PROCESS_CONTENT_BEGUN;
  309. } else {
  310. // More definite-length data remains to be copied out, but it
  311. // is not yet in the buffer.
  312. break;
  313. }
  314. }
  315. SuccessReturn:
  316. fRet = TRUE;
  317. CommonReturn:
  318. return fRet;
  319. ErrorReturn:
  320. fRet = FALSE;
  321. goto CommonReturn;
  322. TRACE_ERROR(InvalidTokenError) // error already set
  323. TRACE_ERROR(GetTokenError) // error already set
  324. TRACE_ERROR(CallbackError) // error already set
  325. TRACE_ERROR(CallbackFinalError) // error already set
  326. }
  327. //+-------------------------------------------------------------------------
  328. // Queue data to the buffer.
  329. //--------------------------------------------------------------------------
  330. BOOL
  331. WINAPI
  332. ICMS_QueueToBuffer(
  333. IN PICM_BUFFER pbuf,
  334. IN PBYTE pbData,
  335. IN DWORD cbData)
  336. {
  337. BOOL fRet;
  338. DWORD cbNewSize;
  339. DWORD cbNewUsed;
  340. if (0 == cbData)
  341. goto SuccessReturn;
  342. if (pbuf->pbData && pbuf->cbDead) {
  343. // Move the still-active bytes up to the front of the buffer.
  344. // NB- Might overlap, so use MoveMemory.
  345. MoveMemory(
  346. pbuf->pbData,
  347. pbuf->pbData + pbuf->cbDead,
  348. pbuf->cbUsed - pbuf->cbDead);
  349. pbuf->cbUsed -= pbuf->cbDead;
  350. pbuf->cbDead = 0;
  351. }
  352. for (cbNewUsed=pbuf->cbUsed + cbData, cbNewSize=pbuf->cbSize;
  353. cbNewUsed > cbNewSize;
  354. cbNewSize += ICM_BUFFER_SIZE_INCR)
  355. ;
  356. if (cbNewSize > pbuf->cbSize) {
  357. if (NULL == (pbuf->pbData=(PBYTE)ICM_ReAlloc( pbuf->pbData, cbNewSize)))
  358. goto ReAllocBufferError;
  359. pbuf->cbSize = cbNewSize;
  360. }
  361. CopyMemory( pbuf->pbData + pbuf->cbUsed, pbData, cbData);
  362. pbuf->cbUsed += cbData;
  363. SuccessReturn:
  364. fRet = TRUE;
  365. CommonReturn:
  366. return fRet;
  367. ErrorReturn:
  368. fRet = FALSE;
  369. goto CommonReturn;
  370. TRACE_ERROR(ReAllocBufferError) // error already set
  371. }
  372. //+-------------------------------------------------------------------------
  373. // Copy out or queue some data eventually destined for the callback.
  374. //--------------------------------------------------------------------------
  375. BOOL
  376. WINAPI
  377. ICMS_Output(
  378. IN PCRYPT_MSG_INFO pcmi,
  379. IN PBYTE pbData,
  380. IN DWORD cbData,
  381. IN BOOL fFinal)
  382. {
  383. BOOL fRet;
  384. PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
  385. PFN_CMSG_STREAM_OUTPUT pfnStreamOutput = pcsi->pfnStreamOutput;
  386. void *pvArg = pcsi->pvArg;
  387. PICM_BUFFER pbuf = &pcmi->bufOutput;
  388. if (pcmi->fStreamCallbackOutput) {
  389. if (pbuf->cbUsed) {
  390. // Copy out the queued data
  391. if (!pfnStreamOutput( pvArg, pbuf->pbData, pbuf->cbUsed, FALSE))
  392. goto OutputBufferError;
  393. pbuf->cbUsed = 0;
  394. }
  395. if (cbData || fFinal) {
  396. if (!pfnStreamOutput( pvArg, pbData, cbData, fFinal))
  397. goto OutputError;
  398. }
  399. } else {
  400. if (!ICMS_QueueToBuffer( pbuf, pbData, cbData))
  401. goto QueueOutputError;
  402. }
  403. fRet = TRUE;
  404. CommonReturn:
  405. return fRet;
  406. ErrorReturn:
  407. fRet = FALSE;
  408. goto CommonReturn;
  409. TRACE_ERROR(OutputBufferError) // error already set
  410. TRACE_ERROR(QueueOutputError) // error already set
  411. TRACE_ERROR(OutputError) // error already set
  412. }
  413. //+-------------------------------------------------------------------------
  414. // Copy out the pair of NULLs following the contents octets of an indefinite-
  415. // length encoding.
  416. //--------------------------------------------------------------------------
  417. BOOL
  418. WINAPI
  419. ICMS_OutputNullPairs(
  420. IN PCRYPT_MSG_INFO pcmi,
  421. IN DWORD cPairs,
  422. IN BOOL fFinal)
  423. {
  424. BOOL fRet;
  425. BYTE abNULL[8*2]; ZEROSTRUCT(abNULL);
  426. if (cPairs > (sizeof(abNULL)/2))
  427. goto CountOfNullPairsTooLargeError;
  428. if (!ICMS_Output( pcmi, abNULL, cPairs * 2, fFinal))
  429. goto OutputError;
  430. fRet = TRUE;
  431. CommonReturn:
  432. return fRet;
  433. ErrorReturn:
  434. fRet = FALSE;
  435. goto CommonReturn;
  436. TRACE_ERROR(CountOfNullPairsTooLargeError) // error already set
  437. TRACE_ERROR(OutputError) // error already set
  438. }
  439. //+-------------------------------------------------------------------------
  440. // Copy out the part of the encoding preceding the contents octets.
  441. //--------------------------------------------------------------------------
  442. BOOL
  443. WINAPI
  444. ICMS_OutputEncodedPrefix(
  445. IN PCRYPT_MSG_INFO pcmi,
  446. IN BYTE bTag,
  447. IN DWORD cbData)
  448. {
  449. BOOL fRet;
  450. DWORD dwError = ERROR_SUCCESS;
  451. BYTE abPrefix[6];
  452. DWORD cbPrefix;
  453. abPrefix[0] = bTag;
  454. if (CMSG_INDEFINITE_LENGTH == cbData) {
  455. abPrefix[1] = ICM_LENGTH_INDEFINITE;
  456. cbPrefix = 1;
  457. } else {
  458. cbPrefix = sizeof(abPrefix) - 1;
  459. ICM_GetLengthOctets( cbData, abPrefix + 1, &cbPrefix);
  460. }
  461. if (!ICMS_Output( pcmi, abPrefix, cbPrefix + 1, FALSE))
  462. goto OutputError;
  463. fRet = TRUE;
  464. CommonReturn:
  465. ICM_SetLastError(dwError);
  466. return fRet;
  467. ErrorReturn:
  468. dwError = GetLastError();
  469. fRet = FALSE;
  470. goto CommonReturn;
  471. TRACE_ERROR(OutputError) // error already set
  472. }
  473. //+-------------------------------------------------------------------------
  474. // Copy out the part of the ContentInfo encoding preceding
  475. // the content's content.
  476. //--------------------------------------------------------------------------
  477. BOOL
  478. WINAPI
  479. ICMS_OutputEncodedPrefixContentInfo(
  480. IN PCRYPT_MSG_INFO pcmi,
  481. IN LPSTR pszContentType,
  482. IN DWORD cbData,
  483. IN DWORD dwFlags = 0)
  484. {
  485. BOOL fRet;
  486. DWORD dwError = ERROR_SUCCESS;
  487. ASN1error_e Asn1Err;
  488. ASN1encoding_t pEnc = ICM_GetEncoder();
  489. PBYTE pbEncoded = NULL;
  490. DWORD cbEncoded;
  491. ObjectID ossObjID;
  492. BYTE abContentInfo[6];
  493. DWORD cbContentInfo;
  494. BYTE abContent[6];
  495. DWORD cbContent = 0;
  496. BYTE abContentOctetString[6];
  497. DWORD cbContentOctetString = 0;
  498. DWORD cbSize = cbData;
  499. if (dwFlags & CMSG_DETACHED_FLAG) {
  500. // NoContent
  501. if (CMSG_INDEFINITE_LENGTH != cbData)
  502. cbSize = 0;
  503. } else {
  504. if (NULL == pszContentType
  505. #ifdef CMS_PKCS7
  506. || (dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
  507. #endif // CMS_PKCS7
  508. ) {
  509. // The content is not already encoded, so encode it as an octet string.
  510. abContentOctetString[0] = ICM_TAG_OCTETSTRING;
  511. if (CMSG_INDEFINITE_LENGTH == cbData) {
  512. abContentOctetString[0] |= ICM_TAG_CONSTRUCTED;
  513. abContentOctetString[1] = ICM_LENGTH_INDEFINITE;
  514. cbContentOctetString = 1;
  515. } else {
  516. cbContentOctetString = sizeof(abContentOctetString) - 1;
  517. ICM_GetLengthOctets(
  518. cbData,
  519. abContentOctetString + 1,
  520. &cbContentOctetString);
  521. cbSize += 1 + cbContentOctetString;
  522. }
  523. }
  524. // content, [0] EXPLICIT
  525. abContent[0] = ICM_TAG_CONSTRUCTED | ICM_TAG_CONTEXT_0;
  526. if (CMSG_INDEFINITE_LENGTH == cbData) {
  527. abContent[1] = ICM_LENGTH_INDEFINITE;
  528. cbContent = 1;
  529. } else {
  530. cbContent = sizeof(abContent) - 1;
  531. ICM_GetLengthOctets( cbSize, abContent + 1, &cbContent);
  532. cbSize += 1 + cbContent;
  533. }
  534. }
  535. // contentType
  536. ossObjID.count = SIZE_OSS_OID;
  537. if (!PkiAsn1ToObjectIdentifier(
  538. pszContentType ? pszContentType : pszObjIdDataType,
  539. &ossObjID.count,
  540. ossObjID.value))
  541. goto ConvToObjectIdentifierError;
  542. if (0 != (Asn1Err = PkiAsn1Encode(
  543. pEnc,
  544. &ossObjID,
  545. ObjectIdentifierType_PDU,
  546. &pbEncoded,
  547. &cbEncoded)))
  548. goto EncodeObjectIdentifierError;
  549. cbSize += cbEncoded;
  550. abContentInfo[0] = ICM_TAG_SEQ;
  551. if (CMSG_INDEFINITE_LENGTH == cbData) {
  552. abContentInfo[1] = ICM_LENGTH_INDEFINITE;
  553. cbContentInfo = 1;
  554. } else {
  555. cbContentInfo = sizeof(abContentInfo) - 1;
  556. ICM_GetLengthOctets( cbSize, abContentInfo + 1, &cbContentInfo);
  557. }
  558. if (!ICMS_Output( pcmi, abContentInfo, cbContentInfo + 1, FALSE))
  559. goto OutputContentInfoError;
  560. if (!ICMS_Output( pcmi, pbEncoded, cbEncoded, FALSE))
  561. goto OutputContentTypeError;
  562. if (0 == (dwFlags & CMSG_DETACHED_FLAG)) {
  563. if (!ICMS_Output( pcmi, abContent, cbContent + 1, FALSE))
  564. goto OutputContentError;
  565. if (NULL == pszContentType
  566. #ifdef CMS_PKCS7
  567. || (dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
  568. #endif // CMS_PKCS7
  569. ) {
  570. if (!ICMS_Output(
  571. pcmi,
  572. abContentOctetString,
  573. cbContentOctetString + 1,
  574. FALSE))
  575. goto OutputContentOctetStringError;
  576. }
  577. }
  578. fRet = TRUE;
  579. CommonReturn:
  580. PkiAsn1FreeEncoded(pEnc, pbEncoded);
  581. ICM_SetLastError(dwError);
  582. return fRet;
  583. ErrorReturn:
  584. dwError = GetLastError();
  585. fRet = FALSE;
  586. goto CommonReturn;
  587. SET_ERROR_VAR(EncodeObjectIdentifierError, PkiAsn1ErrToHr(Asn1Err))
  588. TRACE_ERROR(ConvToObjectIdentifierError) // error already set
  589. TRACE_ERROR(OutputContentInfoError) // error already set
  590. TRACE_ERROR(OutputContentTypeError) // error already set
  591. TRACE_ERROR(OutputContentError) // error already set
  592. TRACE_ERROR(OutputContentOctetStringError) // error already set
  593. }
  594. //+-------------------------------------------------------------------------
  595. // Copy out the part of the EncryptedContentInfo encoding preceding
  596. // the content's content.
  597. //--------------------------------------------------------------------------
  598. BOOL
  599. WINAPI
  600. ICMS_OutputEncodedPrefixEncryptedContentInfo(
  601. IN PCRYPT_MSG_INFO pcmi,
  602. IN LPSTR pszContentType,
  603. IN AlgorithmIdentifier *poaiContentEncryption,
  604. IN DWORD cbData)
  605. {
  606. BOOL fRet;
  607. DWORD dwError = ERROR_SUCCESS;
  608. ASN1error_e Asn1Err;
  609. ASN1encoding_t pEnc = ICM_GetEncoder();
  610. PBYTE pbEncodedContentType = NULL;
  611. DWORD cbEncodedContentType;
  612. PBYTE pbEncodedContentEncryptionAlgorithm = NULL;
  613. DWORD cbEncodedContentEncryptionAlgorithm;
  614. ObjectID ossObjID;
  615. BYTE abEncryptedContentInfo[6];
  616. DWORD cbEncryptedContentInfo;
  617. BYTE abEncryptedContent[6];
  618. DWORD cbEncryptedContent;
  619. DWORD cbSize = 0;
  620. DWORD cbCipher = cbData;
  621. DWORD cbBlockSize = pcmi->cbBlockSize;
  622. if (pcmi->fBlockCipher && 0 < cbCipher) {
  623. cbCipher += cbBlockSize;
  624. cbCipher -= cbCipher % cbBlockSize;
  625. }
  626. // encryptedContent, [0] IMPLICIT
  627. abEncryptedContent[0] = ICM_TAG_CONTEXT_0;
  628. if (CMSG_INDEFINITE_LENGTH == cbData) {
  629. abEncryptedContent[0] |= ICM_TAG_CONSTRUCTED;
  630. abEncryptedContent[1] = ICM_LENGTH_INDEFINITE;
  631. cbEncryptedContent = 1;
  632. } else {
  633. // NOTE: for nonData, either encapsulated or the cbData excludes
  634. // the outer tag and length octets.
  635. cbEncryptedContent = sizeof(abEncryptedContent) - 1;
  636. ICM_GetLengthOctets( cbCipher, abEncryptedContent + 1, &cbEncryptedContent);
  637. cbSize = 1 + cbEncryptedContent + cbCipher;
  638. }
  639. // contentType
  640. ossObjID.count = SIZE_OSS_OID;
  641. if (!PkiAsn1ToObjectIdentifier(
  642. pszContentType ? pszContentType : pszObjIdDataType,
  643. &ossObjID.count,
  644. ossObjID.value))
  645. goto ConvToObjectIdentifierError;
  646. if (0 != (Asn1Err = PkiAsn1Encode(
  647. pEnc,
  648. &ossObjID,
  649. ObjectIdentifierType_PDU,
  650. &pbEncodedContentType,
  651. &cbEncodedContentType)))
  652. goto EncodeObjectIdentifierError;
  653. cbSize += cbEncodedContentType;
  654. // contentEncryptionAlgorithm
  655. if (0 != (Asn1Err = PkiAsn1Encode(
  656. pEnc,
  657. poaiContentEncryption,
  658. AlgorithmIdentifier_PDU,
  659. &pbEncodedContentEncryptionAlgorithm,
  660. &cbEncodedContentEncryptionAlgorithm)))
  661. goto EncodeContentEncryptionAlgorithmError;
  662. cbSize += cbEncodedContentEncryptionAlgorithm;
  663. // EncryptedContentInfo
  664. abEncryptedContentInfo[0] = ICM_TAG_SEQ;
  665. if (CMSG_INDEFINITE_LENGTH == cbData) {
  666. abEncryptedContentInfo[1] = ICM_LENGTH_INDEFINITE;
  667. cbEncryptedContentInfo = 1;
  668. } else {
  669. cbEncryptedContentInfo = sizeof(abEncryptedContentInfo) - 1;
  670. ICM_GetLengthOctets(
  671. cbSize,
  672. abEncryptedContentInfo + 1,
  673. &cbEncryptedContentInfo);
  674. }
  675. // Queue the encoded header
  676. if (!ICMS_Output(
  677. pcmi,
  678. abEncryptedContentInfo,
  679. cbEncryptedContentInfo + 1,
  680. FALSE))
  681. goto OutputContentInfoError;
  682. if (!ICMS_Output(
  683. pcmi,
  684. pbEncodedContentType,
  685. cbEncodedContentType,
  686. FALSE))
  687. goto OutputContentTypeError;
  688. if (!ICMS_Output(
  689. pcmi,
  690. pbEncodedContentEncryptionAlgorithm,
  691. cbEncodedContentEncryptionAlgorithm,
  692. FALSE))
  693. goto OutputContentEncryptionAlgorithmError;
  694. if (!ICMS_Output(
  695. pcmi,
  696. abEncryptedContent,
  697. cbEncryptedContent + 1,
  698. FALSE))
  699. goto OutputEncryptedContentError;
  700. fRet = TRUE;
  701. CommonReturn:
  702. PkiAsn1FreeEncoded(pEnc, pbEncodedContentType);
  703. PkiAsn1FreeEncoded(pEnc, pbEncodedContentEncryptionAlgorithm);
  704. ICM_SetLastError(dwError);
  705. return fRet;
  706. ErrorReturn:
  707. dwError = GetLastError();
  708. fRet = FALSE;
  709. goto CommonReturn;
  710. SET_ERROR_VAR(EncodeObjectIdentifierError, PkiAsn1ErrToHr(Asn1Err))
  711. SET_ERROR_VAR(EncodeContentEncryptionAlgorithmError, PkiAsn1ErrToHr(Asn1Err))
  712. TRACE_ERROR(ConvToObjectIdentifierError) // error already set
  713. TRACE_ERROR(OutputContentInfoError) // error already set
  714. TRACE_ERROR(OutputContentTypeError) // error already set
  715. TRACE_ERROR(OutputContentEncryptionAlgorithmError) // error already set
  716. TRACE_ERROR(OutputEncryptedContentError) // error already set
  717. }
  718. //+-------------------------------------------------------------------------
  719. // Copy out the encoding of an OSS type.
  720. //--------------------------------------------------------------------------
  721. BOOL
  722. WINAPI
  723. ICMS_OutputEncoded(
  724. IN PCRYPT_MSG_INFO pcmi,
  725. IN int iPDU,
  726. IN OPTIONAL BYTE bTag,
  727. IN PVOID pv,
  728. IN BOOL fFinal)
  729. {
  730. BOOL fRet;
  731. DWORD dwError = ERROR_SUCCESS;
  732. ASN1error_e Asn1Err;
  733. ASN1encoding_t pEnc = ICM_GetEncoder();
  734. PBYTE pbEncoded = NULL;
  735. DWORD cbEncoded;
  736. if (0 != (Asn1Err = PkiAsn1Encode(
  737. pEnc,
  738. pv,
  739. iPDU,
  740. &pbEncoded,
  741. &cbEncoded)))
  742. goto EncodeError;
  743. if (bTag)
  744. pbEncoded[0] = bTag; // poke in the right tag
  745. if (!ICMS_Output(pcmi, pbEncoded, cbEncoded, fFinal))
  746. goto OutputError;
  747. fRet = TRUE;
  748. CommonReturn:
  749. PkiAsn1FreeEncoded(pEnc, pbEncoded);
  750. ICM_SetLastError(dwError);
  751. return fRet;
  752. ErrorReturn:
  753. dwError = GetLastError();
  754. fRet = FALSE;
  755. goto CommonReturn;
  756. SET_ERROR_VAR(EncodeError, PkiAsn1ErrToHr(Asn1Err))
  757. TRACE_ERROR(OutputError) // error already set
  758. }
  759. //+-------------------------------------------------------------------------
  760. // Create the buffer for an enveloped message.
  761. //--------------------------------------------------------------------------
  762. BOOL
  763. WINAPI
  764. ICMS_CreateEnvelopedBuffer(
  765. IN PCRYPT_MSG_INFO pcmi)
  766. {
  767. DWORD dwError = ERROR_SUCCESS;
  768. BOOL fRet;
  769. PBYTE pbBuffer = NULL;
  770. DWORD cbBuffer;
  771. DWORD cbAlloc;
  772. DWORD cbBlockSize;
  773. BOOL fBlockCipher;
  774. PICM_BUFFER pbuf = &pcmi->bufCrypt;
  775. if (!ICM_GetKeyBlockSize(
  776. pcmi->hkeyContentCrypt,
  777. &cbBlockSize,
  778. &fBlockCipher))
  779. goto GetEncryptBlockSizeError;
  780. pcmi->cbBlockSize = cbBlockSize;
  781. pcmi->fBlockCipher = fBlockCipher;
  782. cbBuffer = min( cbBlockSize * CMSGP_STREAM_CRYPT_BLOCK_COUNT,
  783. CMSGP_STREAM_MAX_ENCRYPT_BUFFER);
  784. if (fBlockCipher) {
  785. cbBuffer += cbBlockSize;
  786. cbBuffer -= cbBuffer % cbBlockSize; // make a multiple of block size
  787. }
  788. // Add one block for growth during encrypt, and to save during decrypt.
  789. cbAlloc = cbBuffer + 1 * cbBlockSize;
  790. // Block ciphers pad the ciphertext, and if the plaintext is a
  791. // multiple of the block size the padding is one block.
  792. if (NULL == (pbBuffer = (PBYTE)ICM_Alloc( cbAlloc)))
  793. goto AllocBufferError;
  794. pbuf->pbData = pbBuffer;
  795. pbuf->cbSize = cbBuffer;
  796. fRet = TRUE;
  797. CommonReturn:
  798. ICM_SetLastError(dwError);
  799. return fRet;
  800. ErrorReturn:
  801. dwError = GetLastError();
  802. ICM_Free( pbBuffer);
  803. fRet = FALSE;
  804. goto CommonReturn;
  805. TRACE_ERROR(GetEncryptBlockSizeError) // error already set
  806. TRACE_ERROR(AllocBufferError) // error already set
  807. }
  808. //+-------------------------------------------------------------------------
  809. // Encode and copy out the part of the data message up to the inner content.
  810. //--------------------------------------------------------------------------
  811. BOOL
  812. WINAPI
  813. ICMS_OpenToEncodeData(
  814. IN PCRYPT_MSG_INFO pcmi)
  815. {
  816. BOOL fRet;
  817. DWORD dwError = ERROR_SUCCESS;
  818. DWORD cbData = pcmi->pStreamInfo->cbContent;
  819. if (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG) {
  820. BYTE bTag;
  821. if (CMSG_INDEFINITE_LENGTH == cbData)
  822. bTag = ICM_TAG_OCTETSTRING | ICM_TAG_CONSTRUCTED;
  823. else
  824. bTag = ICM_TAG_OCTETSTRING;
  825. // Output octet string
  826. if (!ICMS_OutputEncodedPrefix(
  827. pcmi,
  828. bTag,
  829. cbData))
  830. goto OutputOctetStringError;
  831. } else {
  832. // Output ContentInfo
  833. if (!ICMS_OutputEncodedPrefixContentInfo(
  834. pcmi,
  835. NULL,
  836. cbData))
  837. goto OutputContentInfoError;
  838. }
  839. fRet = TRUE;
  840. CommonReturn:
  841. ICM_SetLastError(dwError);
  842. return fRet;
  843. ErrorReturn:
  844. dwError = GetLastError();
  845. fRet = FALSE;
  846. goto CommonReturn;
  847. TRACE_ERROR(OutputContentInfoError) // error already set
  848. TRACE_ERROR(OutputOctetStringError) // error already set
  849. }
  850. //+-------------------------------------------------------------------------
  851. // Encode and copy out the part of the data message after the inner content.
  852. //--------------------------------------------------------------------------
  853. BOOL
  854. WINAPI
  855. ICMS_UpdateEncodingData(
  856. IN PCRYPT_MSG_INFO pcmi,
  857. IN PBYTE pbData,
  858. IN DWORD cbData,
  859. IN BOOL fFinal)
  860. {
  861. BOOL fRet;
  862. DWORD dwError = ERROR_SUCCESS;
  863. BOOL fDefinite = (CMSG_INDEFINITE_LENGTH != pcmi->pStreamInfo->cbContent);
  864. DWORD cNullPairs;
  865. pcmi->fStreamCallbackOutput = TRUE; // Enable the callback
  866. if (!fDefinite) {
  867. // The content is an indefinite-length octet string encoded by us,
  868. // so make each output chunk definite-length.
  869. if (!ICMS_OutputEncodedPrefix(
  870. pcmi,
  871. ICM_TAG_OCTETSTRING,
  872. cbData))
  873. goto OutputOctetStringError;
  874. }
  875. if (!ICMS_Output( pcmi, pbData, cbData, fFinal && fDefinite))
  876. goto OutputError;
  877. if (fFinal && !fDefinite) {
  878. // End of indefinite-length encoding, so emit some NULL pairs
  879. cNullPairs = 1; // content
  880. if (0 == (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG))
  881. cNullPairs += 2;
  882. if (!ICMS_OutputNullPairs( pcmi, cNullPairs, TRUE))
  883. goto OutputNullPairsError;
  884. }
  885. fRet = TRUE;
  886. CommonReturn:
  887. ICM_SetLastError(dwError);
  888. return fRet;
  889. ErrorReturn:
  890. dwError = GetLastError();
  891. fRet = FALSE;
  892. goto CommonReturn;
  893. TRACE_ERROR(OutputOctetStringError) // error already set
  894. TRACE_ERROR(OutputError) // error already set
  895. TRACE_ERROR(OutputNullPairsError) // error already set
  896. }
  897. //+-------------------------------------------------------------------------
  898. // Encode and copy out the part of the signed message up to the inner content.
  899. //--------------------------------------------------------------------------
  900. BOOL
  901. WINAPI
  902. ICMS_OpenToEncodeSignedData(
  903. IN PCRYPT_MSG_INFO pcmi,
  904. IN PCMSG_SIGNED_ENCODE_INFO psmei)
  905. {
  906. BOOL fRet;
  907. DWORD dwError = ERROR_SUCCESS;
  908. SignedData *psd = (SignedData *)pcmi->pvMsg;
  909. DWORD cbData = pcmi->pStreamInfo->cbContent;
  910. LPSTR pszInnerContentObjID = pcmi->pszInnerContentObjID;
  911. DWORD cbSigned;
  912. DWORD cbSignedDataContent;
  913. // Output ContentInfo, if appropriate
  914. if (CMSG_INDEFINITE_LENGTH == cbData) {
  915. cbSigned = CMSG_INDEFINITE_LENGTH;
  916. cbSignedDataContent = CMSG_INDEFINITE_LENGTH;
  917. } else {
  918. if (INVALID_ENCODING_SIZE == (cbSigned = ICM_LengthSigned(
  919. psmei,
  920. pcmi->dwFlags,
  921. pszInnerContentObjID,
  922. cbData,
  923. &cbSignedDataContent)))
  924. goto LengthSignedError;
  925. }
  926. if (0 == (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG)) {
  927. if (!ICMS_OutputEncodedPrefixContentInfo(
  928. pcmi,
  929. szOID_RSA_signedData,
  930. cbSigned))
  931. goto OutputContentInfoError;
  932. }
  933. if (!ICMS_OutputEncodedPrefix(
  934. pcmi,
  935. ICM_TAG_SEQ,
  936. cbSignedDataContent))
  937. goto OutputSignedDataError;
  938. // version
  939. if (!ICMS_OutputEncoded(
  940. pcmi,
  941. IntegerType_PDU,
  942. 0, // bTag
  943. &psd->version,
  944. FALSE))
  945. goto OutputIntegerError;
  946. // digestAlgorithms
  947. if (!ICMS_OutputEncoded(
  948. pcmi,
  949. AlgorithmIdentifiers_PDU,
  950. 0, // bTag
  951. &psd->digestAlgorithms,
  952. FALSE))
  953. goto OutputAlgorithmIdentifiersError;
  954. // contentInfo
  955. if (!ICMS_OutputEncodedPrefixContentInfo(
  956. pcmi,
  957. pcmi->pszInnerContentObjID,
  958. cbData,
  959. pcmi->dwFlags))
  960. goto OutputInnerContentInfoError;
  961. fRet = TRUE;
  962. CommonReturn:
  963. ICM_SetLastError(dwError);
  964. return fRet;
  965. ErrorReturn:
  966. dwError = GetLastError();
  967. fRet = FALSE;
  968. goto CommonReturn;
  969. TRACE_ERROR(LengthSignedError) // error already set
  970. TRACE_ERROR(OutputContentInfoError) // error already set
  971. TRACE_ERROR(OutputSignedDataError) // error already set
  972. TRACE_ERROR(OutputIntegerError) // error already set
  973. TRACE_ERROR(OutputAlgorithmIdentifiersError) // error already set
  974. TRACE_ERROR(OutputInnerContentInfoError) // error already set
  975. }
  976. //+-------------------------------------------------------------------------
  977. // Encode and copy out the part of the signed message after the inner content.
  978. //--------------------------------------------------------------------------
  979. BOOL
  980. WINAPI
  981. ICMS_UpdateEncodingSignedData(
  982. IN PCRYPT_MSG_INFO pcmi,
  983. IN PBYTE pbData,
  984. IN DWORD cbData,
  985. IN BOOL fFinal)
  986. {
  987. BOOL fRet;
  988. DWORD dwError = ERROR_SUCCESS;
  989. SignedData *psd = (SignedData *)pcmi->pvMsg;
  990. PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
  991. BOOL fDefinite = (CMSG_INDEFINITE_LENGTH != pcsi->cbContent);
  992. DWORD cNullPairs;
  993. if (pcmi->pszInnerContentObjID
  994. #ifdef CMS_PKCS7
  995. && 0 == (pcmi->dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
  996. #endif // CMS_PKCS7
  997. ) {
  998. if (0 == (pcmi->aflStream & ICMS_PROCESS_CONTENT_DONE)) {
  999. if (!ICMS_HashContent( pcmi, pbData, cbData))
  1000. goto HashContentError;
  1001. }
  1002. } else {
  1003. if (!ICM_UpdateListDigest( pcmi->pHashList, pbData, cbData))
  1004. goto UpdateDigestError;
  1005. }
  1006. pcmi->fStreamCallbackOutput = TRUE; // Enable the callback
  1007. if (0 == (pcmi->dwFlags & CMSG_DETACHED_FLAG)) {
  1008. if (!fDefinite && (NULL == pcmi->pszInnerContentObjID
  1009. #ifdef CMS_PKCS7
  1010. || (pcmi->dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
  1011. #endif // CMS_PKCS7
  1012. )) {
  1013. // The content is an indefinite-length octet string encoded by us,
  1014. // so make each output chunk definite-length.
  1015. if (!ICMS_OutputEncodedPrefix(
  1016. pcmi,
  1017. ICM_TAG_OCTETSTRING,
  1018. cbData))
  1019. goto OutputOctetStringError;
  1020. }
  1021. if (!ICMS_Output( pcmi, pbData, cbData, FALSE))
  1022. goto OutputError;
  1023. }
  1024. // else
  1025. // detached => don't output the detached content to be hashed
  1026. if (fFinal) {
  1027. if (!fDefinite) {
  1028. // End of indefinite-length encoding, so emit some NULL pairs
  1029. cNullPairs = 1; // ContentInfo
  1030. if (0 == (pcmi->dwFlags & CMSG_DETACHED_FLAG)) {
  1031. cNullPairs++; // [0] EXPLICIT
  1032. if (NULL == pcmi->pszInnerContentObjID
  1033. #ifdef CMS_PKCS7
  1034. || (pcmi->dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
  1035. #endif // CMS_PKCS7
  1036. )
  1037. cNullPairs++; // We did the octet string encoding
  1038. }
  1039. // else
  1040. // detached => no content ([0] EXPLICIT)
  1041. if (!ICMS_OutputNullPairs( pcmi, cNullPairs, FALSE))
  1042. goto OutputNullPairsError;
  1043. }
  1044. if ((psd->bit_mask & certificates_present) &&
  1045. !ICMS_OutputEncoded(
  1046. pcmi,
  1047. SetOfAny_PDU,
  1048. ICM_TAG_CONSTRUCTED | ICM_TAG_CONTEXT_0,
  1049. &psd->certificates,
  1050. FALSE))
  1051. goto OutputCertsError;
  1052. if ((psd->bit_mask & crls_present) &&
  1053. !ICMS_OutputEncoded(
  1054. pcmi,
  1055. SetOfAny_PDU,
  1056. ICM_TAG_CONSTRUCTED | ICM_TAG_CONTEXT_1,
  1057. &psd->crls,
  1058. FALSE))
  1059. goto OutputCrlsError;
  1060. #ifdef CMS_PKCS7
  1061. if (pcmi->rgSignerEncodeDataInfo) {
  1062. if (!ICM_FillSignerEncodeEncryptedDigests(
  1063. pcmi,
  1064. fDefinite)) // fMaxLength
  1065. goto FillSignerEncodeEncryptedDigestsError;
  1066. }
  1067. #else
  1068. if (pcmi->pHashList) {
  1069. if (!ICM_FillSignerEncryptedDigest(
  1070. psd->signerInfos.value,
  1071. pcmi->pszInnerContentObjID,
  1072. pcmi->pHashList->Head(),
  1073. pcmi->dwKeySpec,
  1074. fDefinite)) // fMaxLength
  1075. goto FillSignerEncryptedDigestError;
  1076. }
  1077. #endif // CMS_PKCS7
  1078. if (!ICMS_OutputEncoded(
  1079. pcmi,
  1080. SignerInfos_PDU,
  1081. 0, // bTag
  1082. &psd->signerInfos,
  1083. fDefinite))
  1084. goto OutputSignerInfosError;
  1085. if (!fDefinite) {
  1086. // End of indefinite-length encoding, so emit some NULL pairs
  1087. cNullPairs = 1; // SignedData
  1088. if (0 == (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG))
  1089. cNullPairs += 2;
  1090. if (!ICMS_OutputNullPairs( pcmi, cNullPairs, TRUE))
  1091. goto OutputNullPairsError;
  1092. }
  1093. }
  1094. fRet = TRUE;
  1095. CommonReturn:
  1096. ICM_SetLastError(dwError);
  1097. return fRet;
  1098. ErrorReturn:
  1099. dwError = GetLastError();
  1100. fRet = FALSE;
  1101. goto CommonReturn;
  1102. TRACE_ERROR(HashContentError) // error already set
  1103. TRACE_ERROR(UpdateDigestError) // error already set
  1104. TRACE_ERROR(OutputOctetStringError) // error already set
  1105. TRACE_ERROR(OutputError) // error already set
  1106. TRACE_ERROR(OutputCertsError) // error already set
  1107. TRACE_ERROR(OutputCrlsError) // error already set
  1108. #ifdef CMS_PKCS7
  1109. TRACE_ERROR(FillSignerEncodeEncryptedDigestsError) // error already set
  1110. #else
  1111. TRACE_ERROR(FillSignerEncryptedDigestError) // error already set
  1112. #endif // CMS_PKCS7
  1113. TRACE_ERROR(OutputSignerInfosError) // error already set
  1114. TRACE_ERROR(OutputNullPairsError) // error already set
  1115. }
  1116. //+-------------------------------------------------------------------------
  1117. // Encode and copy out the part of the enveloped message up to the inner
  1118. // content.
  1119. //--------------------------------------------------------------------------
  1120. BOOL
  1121. WINAPI
  1122. ICMS_OpenToEncodeEnvelopedData(
  1123. IN PCRYPT_MSG_INFO pcmi,
  1124. IN PCMSG_ENVELOPED_ENCODE_INFO pemei)
  1125. {
  1126. DWORD dwError = ERROR_SUCCESS;
  1127. BOOL fRet;
  1128. #ifdef CMS_PKCS7
  1129. CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
  1130. #else
  1131. EnvelopedData *ped = (EnvelopedData *)pcmi->pvMsg;
  1132. #endif // CMS_PKCS7
  1133. DWORD cbData = pcmi->pStreamInfo->cbContent;
  1134. LPSTR pszInnerContentObjID = pcmi->pszInnerContentObjID;
  1135. DWORD cbEnveloped;
  1136. DWORD cbEnvelopedDataContent;
  1137. if (!ICMS_CreateEnvelopedBuffer( pcmi))
  1138. goto CreateEnvelopedBufferError;
  1139. // Output ContentInfo, if appropriate
  1140. if (CMSG_INDEFINITE_LENGTH == cbData) {
  1141. cbEnveloped = CMSG_INDEFINITE_LENGTH;
  1142. cbEnvelopedDataContent = CMSG_INDEFINITE_LENGTH;
  1143. } else {
  1144. // NOTE: for nonData, either encapsulated or cbData excludes the
  1145. // outer tag and length octets.
  1146. if (INVALID_ENCODING_SIZE == (cbEnveloped = ICM_LengthEnveloped(
  1147. pemei,
  1148. pcmi->dwFlags,
  1149. pszInnerContentObjID,
  1150. cbData,
  1151. &cbEnvelopedDataContent)))
  1152. goto LengthEnvelopedError;
  1153. }
  1154. if (0 == (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG)) {
  1155. if (!ICMS_OutputEncodedPrefixContentInfo(
  1156. pcmi,
  1157. szOID_RSA_envelopedData,
  1158. cbEnveloped))
  1159. goto OutputContentInfoError;
  1160. }
  1161. if (!ICMS_OutputEncodedPrefix(
  1162. pcmi,
  1163. ICM_TAG_SEQ,
  1164. cbEnvelopedDataContent))
  1165. goto OutputEnvelopedDataError;
  1166. // version
  1167. if (!ICMS_OutputEncoded(
  1168. pcmi,
  1169. IntegerType_PDU,
  1170. 0, // bTag
  1171. &ped->version,
  1172. FALSE))
  1173. goto OutputIntegerError;
  1174. #ifdef CMS_PKCS7
  1175. // originatorInfo OPTIONAL
  1176. if (ped->bit_mask & originatorInfo_present) {
  1177. if (!ICMS_OutputEncoded(
  1178. pcmi,
  1179. OriginatorInfo_PDU,
  1180. ICM_TAG_CONSTRUCTED | ICM_TAG_CONTEXT_0,
  1181. &ped->originatorInfo,
  1182. FALSE))
  1183. goto OutputOriginatorInfoError;
  1184. }
  1185. #endif // CMS_PKCS7
  1186. // recipientInfos
  1187. if (!ICMS_OutputEncoded(
  1188. pcmi,
  1189. #ifdef CMS_PKCS7
  1190. CmsRecipientInfos_PDU,
  1191. #else
  1192. RecipientInfos_PDU,
  1193. #endif // CMS_PKCS7
  1194. 0, // bTag
  1195. &ped->recipientInfos,
  1196. FALSE))
  1197. goto OutputRecipientInfosError;
  1198. // encryptedContentInfo
  1199. if (!ICMS_OutputEncodedPrefixEncryptedContentInfo(
  1200. pcmi,
  1201. pcmi->pszInnerContentObjID,
  1202. &ped->encryptedContentInfo.contentEncryptionAlgorithm,
  1203. cbData))
  1204. goto OutputInnerContentInfoError;
  1205. fRet = TRUE;
  1206. CommonReturn:
  1207. ICM_SetLastError(dwError);
  1208. return fRet;
  1209. ErrorReturn:
  1210. dwError = GetLastError();
  1211. fRet = FALSE;
  1212. goto CommonReturn;
  1213. TRACE_ERROR(CreateEnvelopedBufferError) // error already set
  1214. TRACE_ERROR(LengthEnvelopedError) // error already set
  1215. TRACE_ERROR(OutputContentInfoError) // error already set
  1216. TRACE_ERROR(OutputEnvelopedDataError) // error already set
  1217. TRACE_ERROR(OutputIntegerError) // error already set
  1218. #ifdef CMS_PKCS7
  1219. TRACE_ERROR(OutputOriginatorInfoError) // error already set
  1220. #endif // CMS_PKCS7
  1221. TRACE_ERROR(OutputRecipientInfosError) // error already set
  1222. TRACE_ERROR(OutputInnerContentInfoError) // error already set
  1223. }
  1224. //+-------------------------------------------------------------------------
  1225. // Encrypt and copy out some bytes.
  1226. //--------------------------------------------------------------------------
  1227. BOOL
  1228. WINAPI
  1229. ICMS_EncodeEncryptAndOutput(
  1230. IN PCRYPT_MSG_INFO pcmi,
  1231. IN const BYTE *pbPlainOrg,
  1232. IN DWORD cbPlainOrg,
  1233. IN BOOL fFinal)
  1234. {
  1235. DWORD dwError = ERROR_SUCCESS;
  1236. BOOL fRet;
  1237. BOOL fDefinite = (CMSG_INDEFINITE_LENGTH != pcmi->pStreamInfo->cbContent);
  1238. BOOL fBlockCipher = pcmi->fBlockCipher;
  1239. PICM_BUFFER pbufCrypt = &pcmi->bufCrypt;
  1240. PBYTE pbPlain;
  1241. DWORD cbPlainRemain;
  1242. DWORD cb;
  1243. for (cbPlainRemain = cbPlainOrg, pbPlain = (PBYTE)pbPlainOrg;
  1244. cbPlainRemain > 0;) {
  1245. cb = min( cbPlainRemain, pbufCrypt->cbSize - pbufCrypt->cbUsed); // must fit
  1246. CopyMemory(
  1247. pbufCrypt->pbData + pbufCrypt->cbUsed,
  1248. pbPlain,
  1249. cb);
  1250. pbufCrypt->cbUsed += cb;
  1251. pbPlain += cb;
  1252. cbPlainRemain -= cb;
  1253. if (pbufCrypt->cbSize == pbufCrypt->cbUsed) {
  1254. // Encrypt and copy out the buffer
  1255. cb = pbufCrypt->cbSize;
  1256. if (fBlockCipher) {
  1257. // Leave the last block
  1258. cb -= pcmi->cbBlockSize;
  1259. }
  1260. if (!CryptEncrypt(
  1261. pcmi->hkeyContentCrypt,
  1262. NULL, // hHash
  1263. FALSE, // fFinal
  1264. 0, // dwFlags
  1265. pbufCrypt->pbData,
  1266. &cb,
  1267. pbufCrypt->cbSize + pcmi->cbBlockSize))
  1268. goto EncryptError;
  1269. if (!fDefinite) {
  1270. // The ciphertext is indefinite-length, so make each
  1271. // output chunk definite-length.
  1272. if (!ICMS_OutputEncodedPrefix(
  1273. pcmi,
  1274. ICM_TAG_OCTETSTRING,
  1275. cb))
  1276. goto OutputOctetStringError;
  1277. }
  1278. if (!ICMS_Output(
  1279. pcmi,
  1280. pbufCrypt->pbData,
  1281. cb,
  1282. FALSE)) // fFinal
  1283. goto OutputError;
  1284. if (fBlockCipher) {
  1285. // Move the last block to the beginning of the buffer
  1286. // and reset the count to start after this block.
  1287. // Since we are sure the src and dst do not overlap,
  1288. // use CopyMemory (faster than MoveMemory).
  1289. cb = pbufCrypt->cbSize - pcmi->cbBlockSize;
  1290. CopyMemory(
  1291. pbufCrypt->pbData,
  1292. pbufCrypt->pbData + cb,
  1293. pcmi->cbBlockSize);
  1294. pbufCrypt->cbUsed = pcmi->cbBlockSize;
  1295. } else {
  1296. pbufCrypt->cbUsed = 0;
  1297. }
  1298. }
  1299. }
  1300. if (fFinal) {
  1301. #ifdef CMS_PKCS7
  1302. CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
  1303. #else
  1304. EnvelopedData *ped = (EnvelopedData *)pcmi->pvMsg;
  1305. #endif // CMS_PKCS7
  1306. if (cb = pbufCrypt->cbUsed) {
  1307. if (!CryptEncrypt(
  1308. pcmi->hkeyContentCrypt,
  1309. NULL, // hHash
  1310. TRUE, // fFinal
  1311. 0, // dwFlags
  1312. pbufCrypt->pbData,
  1313. &cb,
  1314. pbufCrypt->cbSize + pcmi->cbBlockSize))
  1315. goto FinalEncryptError;
  1316. }
  1317. if (!fDefinite && cb) {
  1318. // The ciphertext is indefinite-length, so make each
  1319. // output chunk definite-length.
  1320. if (!ICMS_OutputEncodedPrefix(
  1321. pcmi,
  1322. ICM_TAG_OCTETSTRING,
  1323. cb))
  1324. goto OutputOctetStringError;
  1325. }
  1326. if (!ICMS_Output(
  1327. pcmi,
  1328. pbufCrypt->pbData,
  1329. cb,
  1330. fDefinite &&
  1331. 0 == (ped->bit_mask & unprotectedAttrs_present) // fFinal
  1332. ))
  1333. goto FinalOutputError;
  1334. }
  1335. fRet = TRUE;
  1336. CommonReturn:
  1337. ICM_SetLastError(dwError);
  1338. return fRet;
  1339. ErrorReturn:
  1340. dwError = GetLastError();
  1341. fRet = FALSE;
  1342. goto CommonReturn;
  1343. TRACE_ERROR(EncryptError) // error already set
  1344. TRACE_ERROR(FinalEncryptError) // error already set
  1345. TRACE_ERROR(OutputOctetStringError) // error already set
  1346. TRACE_ERROR(OutputError) // error already set
  1347. TRACE_ERROR(FinalOutputError) // error already set
  1348. }
  1349. //+-------------------------------------------------------------------------
  1350. // Encode encrypt callback for octet string.
  1351. //--------------------------------------------------------------------------
  1352. BOOL
  1353. WINAPI
  1354. ICMS_EncryptCallback(
  1355. IN const void *pvArg,
  1356. IN OUT PICM_BUFFER pbuf,
  1357. IN OUT PDWORD pcbPending,
  1358. IN BOOL fFinal)
  1359. {
  1360. DWORD dwError = ERROR_SUCCESS;
  1361. BOOL fRet;
  1362. PBYTE pbData = pbuf->pbData + pbuf->cbDead;
  1363. DWORD cbData = min( *pcbPending, pbuf->cbUsed - pbuf->cbDead);
  1364. if (!ICMS_EncodeEncryptAndOutput(
  1365. (PCRYPT_MSG_INFO)pvArg,
  1366. pbData,
  1367. cbData,
  1368. fFinal))
  1369. goto EncodeEncryptAndOutputError;
  1370. pbuf->cbDead += cbData;
  1371. *pcbPending -= cbData;
  1372. fRet = TRUE;
  1373. CommonReturn:
  1374. ICM_SetLastError(dwError);
  1375. return fRet;
  1376. ErrorReturn:
  1377. dwError = GetLastError();
  1378. fRet = FALSE;
  1379. goto CommonReturn;
  1380. TRACE_ERROR(EncodeEncryptAndOutputError) // error already set
  1381. }
  1382. //+-------------------------------------------------------------------------
  1383. // Encode and copy out the part of the enveloped message after the inner content.
  1384. //--------------------------------------------------------------------------
  1385. BOOL
  1386. WINAPI
  1387. ICMS_UpdateEncodingEnvelopedData(
  1388. IN PCRYPT_MSG_INFO pcmi,
  1389. IN const BYTE *pbPlain,
  1390. IN DWORD cbPlain,
  1391. IN BOOL fFinal)
  1392. {
  1393. DWORD dwError = ERROR_SUCCESS;
  1394. BOOL fRet;
  1395. BOOL fDefinite = (CMSG_INDEFINITE_LENGTH != pcmi->pStreamInfo->cbContent);
  1396. DWORD cNullPairs;
  1397. if (!pcmi->fStreamCallbackOutput) {
  1398. pcmi->fStreamCallbackOutput = TRUE; // Enable the callback
  1399. if (!ICMS_Output( pcmi, NULL, 0, FALSE)) // Flush the header
  1400. goto FlushOutputError;
  1401. }
  1402. if (pcmi->pszInnerContentObjID
  1403. #ifdef CMS_PKCS7
  1404. && 0 == (pcmi->dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
  1405. #endif // CMS_PKCS7
  1406. ) {
  1407. if (!ICMS_QueueToBuffer( &pcmi->bufEncode, (PBYTE)pbPlain, cbPlain))
  1408. goto QueueToBufferError;
  1409. if (!ICMS_ProcessStringContent(
  1410. &pcmi->bufEncode,
  1411. &pcmi->aflStream,
  1412. &pcmi->cbDefiniteRemain,
  1413. &pcmi->cLevelIndefiniteInner,
  1414. ICMS_EncryptCallback,
  1415. pcmi))
  1416. goto ProcessContentError;
  1417. } else {
  1418. if (!ICMS_EncodeEncryptAndOutput(
  1419. pcmi,
  1420. pbPlain,
  1421. cbPlain,
  1422. fFinal))
  1423. goto EncodeEncryptAndOutputError;
  1424. }
  1425. if (fFinal) {
  1426. #ifdef CMS_PKCS7
  1427. CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
  1428. #else
  1429. EnvelopedData *ped = (EnvelopedData *)pcmi->pvMsg;
  1430. #endif // CMS_PKCS7
  1431. if (!fDefinite) {
  1432. // End of indefinite-length encoding, so emit some NULL pairs,
  1433. // one each for encryptedContent, encryptedContentInfo
  1434. if (!ICMS_OutputNullPairs( pcmi, 2, FALSE))
  1435. goto OutputNullPairsError;
  1436. }
  1437. if (ped->bit_mask & unprotectedAttrs_present) {
  1438. #ifdef CMS_PKCS7
  1439. if (!ICMS_OutputEncoded(
  1440. pcmi,
  1441. Attributes_PDU,
  1442. ICM_TAG_CONSTRUCTED | ICM_TAG_CONTEXT_1,
  1443. &ped->unprotectedAttrs,
  1444. fDefinite)) // fFinal
  1445. goto OutputAttributesError;
  1446. #endif // CMS_PKCS7
  1447. }
  1448. if (!fDefinite) {
  1449. // End of indefinite-length encoding, so emit some NULL pairs
  1450. cNullPairs = 1; // EnvelopedData
  1451. if (0 == (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG))
  1452. cNullPairs += 2;
  1453. if (!ICMS_OutputNullPairs( pcmi, cNullPairs, TRUE))
  1454. goto OutputNullPairsError;
  1455. }
  1456. }
  1457. fRet = TRUE;
  1458. CommonReturn:
  1459. ICM_SetLastError(dwError);
  1460. return fRet;
  1461. ErrorReturn:
  1462. dwError = GetLastError();
  1463. fRet = FALSE;
  1464. goto CommonReturn;
  1465. TRACE_ERROR(FlushOutputError) // error already set
  1466. TRACE_ERROR(QueueToBufferError) // error already set
  1467. TRACE_ERROR(ProcessContentError) // error already set
  1468. TRACE_ERROR(EncodeEncryptAndOutputError) // error already set
  1469. TRACE_ERROR(OutputNullPairsError) // error already set
  1470. #ifdef CMS_PKCS7
  1471. TRACE_ERROR(OutputAttributesError) // error already set
  1472. #endif // CMS_PKCS7
  1473. }
  1474. //+-------------------------------------------------------------------------
  1475. // Decode a PDU from the decode buffer.
  1476. //--------------------------------------------------------------------------
  1477. BOOL
  1478. WINAPI
  1479. ICMS_DecodePDU(
  1480. IN PCRYPT_MSG_INFO pcmi,
  1481. IN ASN1decoding_t pDec,
  1482. IN ASN1uint32_t pdunum,
  1483. OUT PVOID *ppvPDU,
  1484. OUT OPTIONAL PDWORD pcbConsumed = NULL)
  1485. {
  1486. DWORD dwError = ERROR_SUCCESS;
  1487. BOOL fRet;
  1488. ASN1error_e Asn1Err;
  1489. PICM_BUFFER pbuf = &pcmi->bufDecode;
  1490. PVOID pvPDU = NULL;
  1491. DWORD cbBufSizeOrg;
  1492. PBYTE pbData = pbuf->pbData + pbuf->cbDead;
  1493. DWORD cbData = pbuf->cbUsed - pbuf->cbDead;
  1494. #if DBG && defined(OSS_CRYPT_ASN1)
  1495. DWORD dwDecodingFlags;
  1496. dwDecodingFlags = ossGetDecodingFlags((OssGlobal *) pDec);
  1497. ossSetDecodingFlags( (OssGlobal *) pDec, RELAXBER); // turn off squirties
  1498. #endif
  1499. cbBufSizeOrg = cbData;
  1500. if (0 != (Asn1Err = PkiAsn1Decode2(
  1501. pDec,
  1502. &pvPDU,
  1503. pdunum,
  1504. &pbData,
  1505. &cbData))) {
  1506. if (ASN1_ERR_EOD != Asn1Err)
  1507. goto DecodeError;
  1508. }
  1509. #if DBG && defined(OSS_CRYPT_ASN1)
  1510. ossSetDecodingFlags( (OssGlobal *) pDec, dwDecodingFlags); // restore
  1511. #endif
  1512. if (ASN1_ERR_EOD == Asn1Err ||
  1513. (cbData > pbuf->cbUsed - pbuf->cbDead)) {
  1514. PkiAsn1FreeInfo(pDec, pdunum, pvPDU);
  1515. pvPDU = NULL;
  1516. cbData = cbBufSizeOrg;
  1517. }
  1518. pbuf->cbDead += cbBufSizeOrg - cbData;
  1519. if (pcbConsumed)
  1520. *pcbConsumed = cbBufSizeOrg - cbData;
  1521. fRet = TRUE;
  1522. CommonReturn:
  1523. *ppvPDU = pvPDU;
  1524. ICM_SetLastError(dwError);
  1525. return fRet;
  1526. ErrorReturn:
  1527. dwError = GetLastError();
  1528. if (pcbConsumed)
  1529. *pcbConsumed = 0;
  1530. pvPDU = NULL;
  1531. fRet = FALSE;
  1532. goto CommonReturn;
  1533. SET_ERROR_VAR(DecodeError, PkiAsn1ErrToHr(Asn1Err))
  1534. }
  1535. //+-------------------------------------------------------------------------
  1536. // Decode a ContentInfo prefix
  1537. //--------------------------------------------------------------------------
  1538. BOOL
  1539. WINAPI
  1540. ICMS_DecodePrefixContentInfo(
  1541. IN PCRYPT_MSG_INFO pcmi,
  1542. OUT ObjectIdentifierType **ppooidContentType,
  1543. IN OUT PDWORD pcTrailingNullPairs,
  1544. IN OUT PDWORD pafl,
  1545. OUT BOOL *pfNoContent)
  1546. {
  1547. DWORD dwError = ERROR_SUCCESS;
  1548. BOOL fRet;
  1549. ASN1decoding_t pDec = ICM_GetDecoder();
  1550. DWORD dwToken;
  1551. // ContentInfo sequence, step into it
  1552. if (0 == (*pafl & ICMS_DECODED_CONTENTINFO_SEQ)) {
  1553. if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, &pcmi->cbContentInfo))
  1554. goto ContentInfoGetTokenError;
  1555. switch (dwToken) {
  1556. case ICMS_TOKEN_INDEFINITE: ++*pcTrailingNullPairs; break;
  1557. case ICMS_TOKEN_DEFINITE: break;
  1558. case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn;
  1559. default: goto InvalidTokenError;
  1560. }
  1561. *pafl |= ICMS_DECODED_CONTENTINFO_SEQ;
  1562. }
  1563. // contentType, decode it
  1564. if (NULL == *ppooidContentType) {
  1565. DWORD cbConsumed;
  1566. if (!ICMS_DecodePDU(
  1567. pcmi,
  1568. pDec,
  1569. ObjectIdentifierType_PDU,
  1570. (void **)ppooidContentType,
  1571. &cbConsumed))
  1572. goto DecodeContentTypeError;
  1573. if (NULL != *ppooidContentType &&
  1574. CMSG_INDEFINITE_LENGTH != pcmi->cbContentInfo &&
  1575. cbConsumed == pcmi->cbContentInfo) {
  1576. // Only has contentType. The optional content has
  1577. // been omitted.
  1578. *pfNoContent = TRUE;
  1579. *pafl |= ICMS_DECODED_CONTENTINFO_CONTENT;
  1580. goto SuccessReturn;
  1581. }
  1582. }
  1583. if (NULL == *ppooidContentType)
  1584. goto SuccessReturn; // not enough data
  1585. // [0] EXPLICIT, step into it
  1586. if (0 == (*pafl & ICMS_DECODED_CONTENTINFO_CONTENT)) {
  1587. if (CMSG_INDEFINITE_LENGTH == pcmi->cbContentInfo) {
  1588. PICM_BUFFER pbuf = &pcmi->bufDecode;
  1589. if (pbuf->cbUsed > pbuf->cbDead) {
  1590. // Check for trailing Null Pairs (00, 00)
  1591. if (ICM_TAG_NULL == *(pbuf->pbData + pbuf->cbDead)) {
  1592. // Only has contentType. The optional content has
  1593. // been omitted.
  1594. *pfNoContent = TRUE;
  1595. *pafl |= ICMS_DECODED_CONTENTINFO_CONTENT;
  1596. goto SuccessReturn;
  1597. }
  1598. } else
  1599. goto SuccessReturn; // not enough data
  1600. }
  1601. if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, NULL))
  1602. goto ContentGetTokenError;
  1603. switch (dwToken) {
  1604. case ICMS_TOKEN_INDEFINITE: ++*pcTrailingNullPairs; break;
  1605. case ICMS_TOKEN_DEFINITE: break;
  1606. case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn;
  1607. default: goto InvalidTokenError;
  1608. }
  1609. *pfNoContent = FALSE;
  1610. *pafl |= ICMS_DECODED_CONTENTINFO_CONTENT;
  1611. }
  1612. SuccessReturn:
  1613. fRet = TRUE;
  1614. CommonReturn:
  1615. ICM_SetLastError(dwError);
  1616. return fRet;
  1617. ErrorReturn:
  1618. dwError = GetLastError();
  1619. fRet = FALSE;
  1620. goto CommonReturn;
  1621. TRACE_ERROR(DecodeContentTypeError) // error already set
  1622. TRACE_ERROR(ContentGetTokenError) // error already set
  1623. TRACE_ERROR(InvalidTokenError) // error already set
  1624. TRACE_ERROR(ContentInfoGetTokenError) // error already set
  1625. }
  1626. //+-------------------------------------------------------------------------
  1627. // Consume the NULL pairs which terminate the indefinite-length encoding.
  1628. //--------------------------------------------------------------------------
  1629. BOOL
  1630. WINAPI
  1631. ICMS_ConsumeTrailingNulls(
  1632. IN PCRYPT_MSG_INFO pcmi,
  1633. IN OUT PDWORD pcNullPairs,
  1634. IN BOOL fFinal)
  1635. {
  1636. BOOL fRet;
  1637. DWORD dwToken;
  1638. for (; *pcNullPairs; (*pcNullPairs)--) {
  1639. if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, NULL))
  1640. goto GetTokenError;
  1641. if ((ICMS_TOKEN_INCOMPLETE == dwToken) && !fFinal)
  1642. goto SuccessReturn;
  1643. if (ICMS_TOKEN_NULLPAIR != dwToken)
  1644. goto WrongTokenError;
  1645. }
  1646. SuccessReturn:
  1647. fRet = TRUE;
  1648. CommonReturn:
  1649. return fRet;
  1650. ErrorReturn:
  1651. fRet = FALSE;
  1652. goto CommonReturn;
  1653. TRACE_ERROR(GetTokenError) // error already set
  1654. TRACE_ERROR(WrongTokenError) // error already set
  1655. }
  1656. //+-------------------------------------------------------------------------
  1657. // Handle incremental suffix data to be decoded, for a data message.
  1658. //--------------------------------------------------------------------------
  1659. BOOL
  1660. WINAPI
  1661. ICMS_DecodeSuffixData(
  1662. IN PCRYPT_MSG_INFO pcmi,
  1663. IN BOOL fFinal)
  1664. {
  1665. BOOL fRet;
  1666. if (!ICMS_ConsumeTrailingNulls( pcmi, &pcmi->cEndNullPairs, fFinal))
  1667. goto ConsumeTrailingNullsError;
  1668. if (0 == pcmi->cEndNullPairs)
  1669. pcmi->aflStream |= ICMS_DECODED_SUFFIX;
  1670. if (fFinal && (pcmi->bufDecode.cbUsed > pcmi->bufDecode.cbDead))
  1671. goto ExcessDataError;
  1672. fRet = TRUE;
  1673. CommonReturn:
  1674. return fRet;
  1675. ErrorReturn:
  1676. fRet = FALSE;
  1677. goto CommonReturn;
  1678. TRACE_ERROR(ConsumeTrailingNullsError) // error already set
  1679. TRACE_ERROR(ExcessDataError) // error already set
  1680. }
  1681. //+-------------------------------------------------------------------------
  1682. // Handle incremental suffix data to be decoded, for a signed message.
  1683. //--------------------------------------------------------------------------
  1684. BOOL
  1685. WINAPI
  1686. ICMS_DecodeSuffixSigned(
  1687. IN PCRYPT_MSG_INFO pcmi,
  1688. IN BOOL fFinal)
  1689. {
  1690. DWORD dwError = ERROR_SUCCESS;
  1691. BOOL fRet;
  1692. ASN1decoding_t pDec = ICM_GetDecoder();
  1693. PSIGNED_DATA_INFO psdi = pcmi->psdi;
  1694. PICM_BUFFER pbuf = &pcmi->bufDecode;
  1695. CertificatesNC *pCertificates = NULL;
  1696. CrlsNC *pCrls = NULL;
  1697. SignerInfosNC *pSignerInfos = NULL;
  1698. Any *pAny;
  1699. DWORD i;
  1700. if (!ICMS_ConsumeTrailingNulls( pcmi, &pcmi->cInnerNullPairs, fFinal))
  1701. goto ConsumeInnerNullsError;
  1702. if (pcmi->cInnerNullPairs)
  1703. goto SuccessReturn;
  1704. // certificates
  1705. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_CERTIFICATES)) {
  1706. if (pbuf->cbUsed > pbuf->cbDead) {
  1707. if (ICM_TAG_CONSTRUCTED_CONTEXT_0 ==
  1708. *(pbuf->pbData + pbuf->cbDead)) {
  1709. // Detected the [0] IMPLICIT indicating certificates.
  1710. // Change the identifier octet so it will decode properly.
  1711. *(pbuf->pbData + pbuf->cbDead) = ICM_TAG_SET;
  1712. if (!ICMS_DecodePDU(
  1713. pcmi,
  1714. pDec,
  1715. CertificatesNC_PDU,
  1716. (void **)&pCertificates))
  1717. goto DecodeCertificatesError;
  1718. if (pCertificates) {
  1719. for (i=pCertificates->count,
  1720. #ifdef OSS_CRYPT_ASN1
  1721. pAny=pCertificates->certificates;
  1722. #else
  1723. pAny=pCertificates->value;
  1724. #endif // OSS_CRYPT_ASN1
  1725. i>0;
  1726. i--, pAny++) {
  1727. if (!ICM_InsertTailBlob( psdi->pCertificateList, pAny))
  1728. goto CertInsertTailBlobError;
  1729. }
  1730. pcmi->aflDecode |= ICMS_DECODED_SIGNED_CERTIFICATES;
  1731. } else {
  1732. // The decode failed, presumably due to insufficient data.
  1733. // Restore the original tag, so we will enter this block
  1734. // and try again on the next call.
  1735. *(pbuf->pbData + pbuf->cbDead) = ICM_TAG_CONSTRUCTED_CONTEXT_0;
  1736. }
  1737. } else {
  1738. // Certificates not present. Mark them as decoded.
  1739. pcmi->aflDecode |= ICMS_DECODED_SIGNED_CERTIFICATES;
  1740. }
  1741. }
  1742. }
  1743. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_CERTIFICATES))
  1744. goto SuccessReturn;
  1745. // crls
  1746. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_CRLS)) {
  1747. if (pbuf->cbUsed > pbuf->cbDead) {
  1748. if (ICM_TAG_CONSTRUCTED_CONTEXT_1 ==
  1749. *(pbuf->pbData + pbuf->cbDead)) {
  1750. // Detected the [1] IMPLICIT indicating crls.
  1751. // Change the identifier octet so it will decode properly.
  1752. *(pbuf->pbData + pbuf->cbDead) = ICM_TAG_SET;
  1753. if (!ICMS_DecodePDU(
  1754. pcmi,
  1755. pDec,
  1756. CrlsNC_PDU,
  1757. (void **)&pCrls))
  1758. goto DecodeCrlsError;
  1759. if (pCrls) {
  1760. for (i=pCrls->count,
  1761. #ifdef OSS_CRYPT_ASN1
  1762. pAny=pCrls->crls;
  1763. #else
  1764. pAny=pCrls->value;
  1765. #endif // OSS_CRYPT_ASN1
  1766. i>0;
  1767. i--, pAny++) {
  1768. if (!ICM_InsertTailBlob( psdi->pCrlList, pAny))
  1769. goto CrlInsertTailBlobError;
  1770. }
  1771. pcmi->aflDecode |= ICMS_DECODED_SIGNED_CRLS;
  1772. } else {
  1773. // The decode failed, presumably due to insufficient data.
  1774. // Restore the original tag, so we will enter this block
  1775. // and try again on the next call.
  1776. *(pbuf->pbData + pbuf->cbDead) = ICM_TAG_CONSTRUCTED_CONTEXT_1;
  1777. }
  1778. } else {
  1779. // Crls not present. Mark them as decoded.
  1780. pcmi->aflDecode |= ICMS_DECODED_SIGNED_CRLS;
  1781. }
  1782. }
  1783. }
  1784. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_CRLS))
  1785. goto SuccessReturn;
  1786. // signerInfos
  1787. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_SIGNERINFOS)) {
  1788. if (!ICMS_DecodePDU(
  1789. pcmi,
  1790. pDec,
  1791. SignerInfosNC_PDU,
  1792. (void **)&pSignerInfos))
  1793. goto DecodeSignerInfosError;
  1794. if (pSignerInfos) {
  1795. for (i=pSignerInfos->count, pAny=pSignerInfos->value;
  1796. i>0;
  1797. i--, pAny++) {
  1798. if (!ICM_InsertTailSigner( psdi->pSignerList, pAny))
  1799. goto SignerInfoInsertTailBlobError;
  1800. }
  1801. pcmi->aflDecode |= ICMS_DECODED_SIGNED_SIGNERINFOS;
  1802. }
  1803. }
  1804. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_SIGNERINFOS))
  1805. goto SuccessReturn;
  1806. if (!ICMS_ConsumeTrailingNulls( pcmi, &pcmi->cEndNullPairs, fFinal))
  1807. goto ConsumeEndNullsError;
  1808. if (0 == pcmi->cEndNullPairs)
  1809. pcmi->aflStream |= ICMS_DECODED_SUFFIX;
  1810. SuccessReturn:
  1811. fRet = TRUE;
  1812. CommonReturn:
  1813. PkiAsn1FreeInfo( pDec, CertificatesNC_PDU, pCertificates);
  1814. PkiAsn1FreeInfo( pDec, CrlsNC_PDU, pCrls);
  1815. PkiAsn1FreeInfo( pDec, SignerInfosNC_PDU, pSignerInfos);
  1816. ICM_SetLastError(dwError);
  1817. return fRet;
  1818. ErrorReturn:
  1819. dwError = GetLastError();
  1820. fRet = FALSE;
  1821. goto CommonReturn;
  1822. TRACE_ERROR(ConsumeInnerNullsError) // error already set
  1823. TRACE_ERROR(DecodeCertificatesError) // error already set
  1824. TRACE_ERROR(CertInsertTailBlobError) // error already set
  1825. TRACE_ERROR(DecodeCrlsError) // error already set
  1826. TRACE_ERROR(CrlInsertTailBlobError) // error already set
  1827. TRACE_ERROR(DecodeSignerInfosError) // error already set
  1828. TRACE_ERROR(SignerInfoInsertTailBlobError) // error already set
  1829. TRACE_ERROR(ConsumeEndNullsError) // error already set
  1830. }
  1831. //+-------------------------------------------------------------------------
  1832. // Handle incremental suffix data to be decoded, for an enveloped message.
  1833. //--------------------------------------------------------------------------
  1834. BOOL
  1835. WINAPI
  1836. ICMS_DecodeSuffixEnveloped(
  1837. IN PCRYPT_MSG_INFO pcmi,
  1838. IN BOOL fFinal)
  1839. {
  1840. BOOL fRet;
  1841. ASN1decoding_t pDec = ICM_GetDecoder();
  1842. PICM_BUFFER pbuf = &pcmi->bufDecode;
  1843. Attributes *pAttributes = NULL;
  1844. #ifdef CMS_PKCS7
  1845. CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
  1846. #endif // CMS_PKCS7
  1847. OSS_DECODE_INFO odi;
  1848. COssDecodeInfoNode *pnOssDecodeInfo;
  1849. if (!ICMS_ConsumeTrailingNulls( pcmi, &pcmi->cInnerNullPairs, fFinal))
  1850. goto ConsumeInnerNullsError;
  1851. if (pcmi->cInnerNullPairs)
  1852. goto SuccessReturn;
  1853. // unprotectedAttrs[1] IMPLICIT UnprotectedAttributes OPTIONAL
  1854. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ATTR)) {
  1855. if (pbuf->cbUsed > pbuf->cbDead) {
  1856. if (ICM_TAG_CONSTRUCTED_CONTEXT_1 ==
  1857. *(pbuf->pbData + pbuf->cbDead)) {
  1858. // Detected the [1] IMPLICIT indicating unprotectedAttrs.
  1859. // Change the identifier octet so it will decode properly.
  1860. *(pbuf->pbData + pbuf->cbDead) = ICM_TAG_SET;
  1861. if (!ICMS_DecodePDU(
  1862. pcmi,
  1863. pDec,
  1864. Attributes_PDU,
  1865. (void **)&pAttributes))
  1866. goto DecodeAttributesError;
  1867. if (pAttributes) {
  1868. #ifdef CMS_PKCS7
  1869. ped->unprotectedAttrs = *pAttributes;
  1870. ped->bit_mask |= unprotectedAttrs_present;
  1871. #endif // CMS_PKCS7
  1872. odi.iPDU = Attributes_PDU;
  1873. odi.pvPDU = pAttributes;
  1874. if (NULL == (pnOssDecodeInfo =
  1875. new COssDecodeInfoNode( &odi))) {
  1876. PkiAsn1FreeInfo( pDec, odi.iPDU, odi.pvPDU);
  1877. goto NewOssDecodeInfoNodeError;
  1878. }
  1879. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ATTR;
  1880. pcmi->plDecodeInfo->InsertTail( pnOssDecodeInfo);
  1881. } else {
  1882. // The decode failed, presumably due to insufficient data.
  1883. // Restore the original tag, so we will enter this block
  1884. // and try again on the next call.
  1885. *(pbuf->pbData + pbuf->cbDead) =
  1886. ICM_TAG_CONSTRUCTED_CONTEXT_1;
  1887. }
  1888. } else {
  1889. // unprotectedAttrs not present. Mark them as decoded.
  1890. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ATTR;
  1891. }
  1892. } else if (fFinal)
  1893. // unprotectedAttrs not present. Mark them as decoded.
  1894. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ATTR;
  1895. }
  1896. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ATTR))
  1897. goto SuccessReturn;
  1898. if (!ICMS_ConsumeTrailingNulls( pcmi, &pcmi->cEndNullPairs, fFinal))
  1899. goto ConsumeEndNullsError;
  1900. if (0 == pcmi->cEndNullPairs)
  1901. pcmi->aflStream |= ICMS_DECODED_SUFFIX;
  1902. SuccessReturn:
  1903. fRet = TRUE;
  1904. CommonReturn:
  1905. return fRet;
  1906. ErrorReturn:
  1907. fRet = FALSE;
  1908. goto CommonReturn;
  1909. TRACE_ERROR(ConsumeInnerNullsError) // error already set
  1910. TRACE_ERROR(DecodeAttributesError) // error already set
  1911. TRACE_ERROR(NewOssDecodeInfoNodeError) // error already set
  1912. TRACE_ERROR(ConsumeEndNullsError) // error already set
  1913. }
  1914. //+-------------------------------------------------------------------------
  1915. // Handle incremental suffix data to be decoded.
  1916. //--------------------------------------------------------------------------
  1917. BOOL
  1918. WINAPI
  1919. ICMS_DecodeSuffix(
  1920. IN PCRYPT_MSG_INFO pcmi,
  1921. IN BOOL fFinal)
  1922. {
  1923. DWORD dwError = ERROR_SUCCESS;
  1924. BOOL fRet;
  1925. switch (pcmi->dwMsgType) {
  1926. case CMSG_DATA:
  1927. fRet = ICMS_DecodeSuffixData( pcmi, fFinal);
  1928. break;
  1929. case CMSG_SIGNED:
  1930. fRet = ICMS_DecodeSuffixSigned( pcmi, fFinal);
  1931. break;
  1932. case CMSG_ENVELOPED:
  1933. fRet = ICMS_DecodeSuffixEnveloped( pcmi, fFinal);
  1934. break;
  1935. case CMSG_HASHED:
  1936. // fRet = ICMS_DecodeSuffixDigested( pcmi, fFinal);
  1937. // break;
  1938. case CMSG_SIGNED_AND_ENVELOPED:
  1939. case CMSG_ENCRYPTED:
  1940. goto MessageTypeNotSupportedYet;
  1941. default:
  1942. goto InvalidMsgType;
  1943. }
  1944. if (!fRet)
  1945. goto ErrorReturn;
  1946. CommonReturn:
  1947. ICM_SetLastError(dwError);
  1948. return fRet;
  1949. ErrorReturn:
  1950. dwError = GetLastError();
  1951. fRet = FALSE;
  1952. goto CommonReturn;
  1953. SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
  1954. TRACE_ERROR(InvalidMsgType) // error already set
  1955. }
  1956. //+-------------------------------------------------------------------------
  1957. // Decrypt and output pending decode data.
  1958. //--------------------------------------------------------------------------
  1959. BOOL
  1960. WINAPI
  1961. ICMS_DecodeDecryptAndOutput(
  1962. IN PCRYPT_MSG_INFO pcmi,
  1963. IN OUT PICM_BUFFER pbufDecode,
  1964. IN OUT PDWORD pcbPending,
  1965. IN BOOL fFinal)
  1966. {
  1967. DWORD dwError = ERROR_SUCCESS;
  1968. BOOL fRet;
  1969. BOOL fBlockCipher = pcmi->fBlockCipher;
  1970. PICM_BUFFER pbufCrypt = &pcmi->bufCrypt;
  1971. DWORD cbCipher;
  1972. DWORD cb;
  1973. for (cbCipher = min( *pcbPending, pbufDecode->cbUsed - pbufDecode->cbDead);
  1974. cbCipher > 0;) {
  1975. cb = min( cbCipher, pbufCrypt->cbSize - pbufCrypt->cbUsed); // must fit
  1976. CopyMemory(
  1977. pbufCrypt->pbData + pbufCrypt->cbUsed,
  1978. pbufDecode->pbData + pbufDecode->cbDead,
  1979. cb);
  1980. pbufCrypt->cbUsed += cb;
  1981. pbufDecode->cbDead += cb;
  1982. *pcbPending -= cb;
  1983. cbCipher -= cb;
  1984. if (pbufCrypt->cbSize == pbufCrypt->cbUsed) {
  1985. // Decrypt and copy out the buffer
  1986. cb = pbufCrypt->cbSize;
  1987. if (fBlockCipher) {
  1988. // Keep the last block
  1989. cb -= pcmi->cbBlockSize;
  1990. }
  1991. if (!CryptDecrypt(
  1992. pcmi->hkeyContentCrypt,
  1993. NULL, // hHash
  1994. FALSE, // fFinal
  1995. 0, // dwFlags
  1996. pbufCrypt->pbData,
  1997. &cb))
  1998. goto DecryptError;
  1999. if (!ICMS_Output(
  2000. pcmi,
  2001. pbufCrypt->pbData,
  2002. cb,
  2003. FALSE)) // fFinal
  2004. goto OutputError;
  2005. if (fBlockCipher) {
  2006. // Move the last block to the beginning of the buffer
  2007. // and reset the count to start after this block.
  2008. // Since we are sure the src and dst do not overlap,
  2009. // use CopyMemory (faster than MoveMemory).
  2010. cb = pbufCrypt->cbSize - pcmi->cbBlockSize;
  2011. CopyMemory(
  2012. pbufCrypt->pbData,
  2013. pbufCrypt->pbData + cb,
  2014. pcmi->cbBlockSize);
  2015. pbufCrypt->cbUsed = pcmi->cbBlockSize;
  2016. } else {
  2017. pbufCrypt->cbUsed = 0;
  2018. }
  2019. }
  2020. }
  2021. if (fFinal) {
  2022. if (cb = pbufCrypt->cbUsed) {
  2023. if (!CryptDecrypt(
  2024. pcmi->hkeyContentCrypt,
  2025. NULL, // hHash
  2026. TRUE, // fFinal
  2027. 0, // dwFlags
  2028. pbufCrypt->pbData,
  2029. &cb))
  2030. goto FinalDecryptError;
  2031. }
  2032. if (!ICMS_Output(
  2033. pcmi,
  2034. pbufCrypt->pbData,
  2035. cb,
  2036. TRUE)) // fFinal
  2037. goto FinalOutputError;
  2038. }
  2039. fRet = TRUE;
  2040. CommonReturn:
  2041. ICM_SetLastError(dwError);
  2042. return fRet;
  2043. ErrorReturn:
  2044. dwError = GetLastError();
  2045. fRet = FALSE;
  2046. goto CommonReturn;
  2047. TRACE_ERROR(DecryptError) // error already set
  2048. TRACE_ERROR(FinalDecryptError) // error already set
  2049. TRACE_ERROR(OutputError) // error already set
  2050. TRACE_ERROR(FinalOutputError) // error already set
  2051. }
  2052. //+-------------------------------------------------------------------------
  2053. // Given a key for decryption, prepare for the decryption to proceed.
  2054. //--------------------------------------------------------------------------
  2055. BOOL
  2056. WINAPI
  2057. ICMS_SetDecryptKey(
  2058. IN PCRYPT_MSG_INFO pcmi,
  2059. IN HCRYPTKEY hkeyDecrypt)
  2060. {
  2061. BOOL fRet;
  2062. DWORD cbPending;
  2063. PICM_BUFFER pbufPendingCrypt = &pcmi->bufPendingCrypt;
  2064. if (pcmi->hkeyContentCrypt) {
  2065. SetLastError((DWORD) CRYPT_E_ALREADY_DECRYPTED);
  2066. return FALSE;
  2067. }
  2068. pcmi->hkeyContentCrypt = hkeyDecrypt;
  2069. if (!ICMS_CreateEnvelopedBuffer( pcmi))
  2070. goto CreateEnvelopedBufferError;
  2071. pcmi->bufCrypt.cbSize += pcmi->cbBlockSize; // use whole thing for decode
  2072. // Decrypt any pending ciphertext
  2073. cbPending = pbufPendingCrypt->cbUsed - pbufPendingCrypt->cbDead;
  2074. if (!ICMS_DecodeDecryptAndOutput(
  2075. pcmi,
  2076. pbufPendingCrypt,
  2077. &cbPending,
  2078. 0 != (pcmi->aflStream & (ICMS_DECODED_CONTENT | ICMS_FINAL))))
  2079. goto DecryptAndOutputError;
  2080. fRet = TRUE;
  2081. CommonReturn:
  2082. return fRet;
  2083. ErrorReturn:
  2084. pcmi->hkeyContentCrypt = 0; // caller closes hkeyDecrypt on
  2085. // error
  2086. fRet = FALSE;
  2087. goto CommonReturn;
  2088. TRACE_ERROR(CreateEnvelopedBufferError) // error already set
  2089. TRACE_ERROR(DecryptAndOutputError) // error already set
  2090. }
  2091. //+-------------------------------------------------------------------------
  2092. // Decode callback.
  2093. //--------------------------------------------------------------------------
  2094. BOOL
  2095. WINAPI
  2096. ICMS_DecodeCallback(
  2097. IN const void *pvArg,
  2098. IN OUT PICM_BUFFER pbuf,
  2099. IN OUT PDWORD pcbPending,
  2100. IN BOOL fFinal)
  2101. {
  2102. DWORD dwError = ERROR_SUCCESS;
  2103. BOOL fRet;
  2104. PCRYPT_MSG_INFO pcmi = (PCRYPT_MSG_INFO)pvArg;
  2105. PBYTE pbData = pbuf->pbData + pbuf->cbDead;
  2106. DWORD cbData = min( *pcbPending, pbuf->cbUsed - pbuf->cbDead);
  2107. if (CMSG_ENVELOPED == pcmi->dwMsgType) {
  2108. if (NULL == pcmi->hkeyContentCrypt) {
  2109. // Allow ciphertext to pile up until the decrypt key is set via
  2110. // CryptMsgControl(... CMSG_CTRL_DECRYPT ...)
  2111. if (!ICMS_QueueToBuffer(&pcmi->bufPendingCrypt, pbData, cbData))
  2112. goto QueuePendingCryptError;
  2113. pbuf->cbDead += cbData;
  2114. *pcbPending -= cbData;
  2115. } else if (!ICMS_DecodeDecryptAndOutput(
  2116. pcmi,
  2117. pbuf,
  2118. pcbPending,
  2119. fFinal))
  2120. goto DecryptAndOutputError;
  2121. } else {
  2122. if (cbData && pcmi->pHashList) {
  2123. if (!ICM_UpdateListDigest( pcmi->pHashList, pbData, cbData))
  2124. goto UpdateDigestError;
  2125. }
  2126. pbuf->cbDead += cbData;
  2127. *pcbPending -= cbData;
  2128. if (!ICMS_Output( pcmi, pbData, cbData, fFinal))
  2129. goto OutputError;
  2130. }
  2131. fRet = TRUE;
  2132. CommonReturn:
  2133. ICM_SetLastError(dwError);
  2134. return fRet;
  2135. ErrorReturn:
  2136. dwError = GetLastError();
  2137. fRet = FALSE;
  2138. goto CommonReturn;
  2139. TRACE_ERROR(QueuePendingCryptError) // error already set
  2140. TRACE_ERROR(DecryptAndOutputError) // error already set
  2141. TRACE_ERROR(UpdateDigestError) // error already set
  2142. TRACE_ERROR(OutputError) // error already set
  2143. }
  2144. //+-------------------------------------------------------------------------
  2145. // Hash callback.
  2146. //--------------------------------------------------------------------------
  2147. BOOL
  2148. WINAPI
  2149. ICMS_HashCallback(
  2150. IN const void *pvArg,
  2151. IN OUT PICM_BUFFER pbuf,
  2152. IN OUT PDWORD pcbPending,
  2153. IN BOOL fFinal)
  2154. {
  2155. DWORD dwError = ERROR_SUCCESS;
  2156. BOOL fRet;
  2157. PBYTE pbData = pbuf->pbData + pbuf->cbDead;
  2158. DWORD cbData = min( *pcbPending, pbuf->cbUsed - pbuf->cbDead);
  2159. if (pvArg) {
  2160. if (!ICM_UpdateListDigest( (CHashList *)pvArg, pbData, cbData))
  2161. goto UpdateDigestError;
  2162. }
  2163. pbuf->cbDead += cbData;
  2164. *pcbPending -= cbData;
  2165. fRet = TRUE;
  2166. CommonReturn:
  2167. ICM_SetLastError(dwError);
  2168. return fRet;
  2169. ErrorReturn:
  2170. dwError = GetLastError();
  2171. fRet = FALSE;
  2172. goto CommonReturn;
  2173. TRACE_ERROR(UpdateDigestError) // error already set
  2174. fFinal;
  2175. }
  2176. //+-------------------------------------------------------------------------
  2177. // Hash incremental content data to be encoded, for an octet string.
  2178. //--------------------------------------------------------------------------
  2179. BOOL
  2180. WINAPI
  2181. ICMS_HashContent(
  2182. IN PCRYPT_MSG_INFO pcmi,
  2183. IN PBYTE pbData,
  2184. IN DWORD cbData)
  2185. {
  2186. BOOL fRet;
  2187. if (!ICMS_QueueToBuffer( &pcmi->bufEncode, (PBYTE)pbData, cbData))
  2188. goto QueueToBufferError;
  2189. if (!ICMS_ProcessStringContent(
  2190. &pcmi->bufEncode,
  2191. &pcmi->aflStream,
  2192. &pcmi->cbDefiniteRemain,
  2193. &pcmi->cLevelIndefiniteInner,
  2194. ICMS_HashCallback,
  2195. pcmi->pHashList))
  2196. goto ProcessStringContentError;
  2197. fRet = TRUE;
  2198. CommonReturn:
  2199. return fRet;
  2200. ErrorReturn:
  2201. fRet = FALSE;
  2202. goto CommonReturn;
  2203. TRACE_ERROR(QueueToBufferError) // error already set
  2204. TRACE_ERROR(ProcessStringContentError) // error already set
  2205. }
  2206. //+-------------------------------------------------------------------------
  2207. // Handle incremental content data to be decoded, for an octet string.
  2208. //--------------------------------------------------------------------------
  2209. BOOL
  2210. WINAPI
  2211. ICMS_DecodeContentOctetString(
  2212. IN PCRYPT_MSG_INFO pcmi,
  2213. IN BOOL fFinal)
  2214. {
  2215. BOOL fRet;
  2216. if (!ICMS_ProcessStringContent(
  2217. &pcmi->bufDecode,
  2218. &pcmi->aflStream,
  2219. &pcmi->cbDefiniteRemain,
  2220. &pcmi->cLevelIndefiniteInner,
  2221. ICMS_DecodeCallback,
  2222. pcmi))
  2223. goto ProcessStringContentError;
  2224. if (pcmi->aflStream & ICMS_PROCESS_CONTENT_DONE)
  2225. pcmi->aflStream |= ICMS_DECODED_CONTENT;
  2226. if (fFinal &&
  2227. (pcmi->cbDefiniteRemain ||
  2228. pcmi->cLevelIndefiniteInner ||
  2229. (0 == (pcmi->aflStream & ICMS_DECODED_CONTENT)))) {
  2230. goto PrematureFinalError;
  2231. }
  2232. fRet = TRUE;
  2233. CommonReturn:
  2234. return fRet;
  2235. ErrorReturn:
  2236. fRet = FALSE;
  2237. goto CommonReturn;
  2238. SET_ERROR(PrematureFinalError,CRYPT_E_STREAM_INSUFFICIENT_DATA)
  2239. TRACE_ERROR(ProcessStringContentError) // error already set
  2240. }
  2241. //+-------------------------------------------------------------------------
  2242. // Handle incremental content data to be decoded, for a sequence.
  2243. //--------------------------------------------------------------------------
  2244. BOOL
  2245. WINAPI
  2246. ICMS_DecodeContentSequence(
  2247. IN PCRYPT_MSG_INFO pcmi,
  2248. IN BOOL fFinal)
  2249. {
  2250. BOOL fRet;
  2251. PICM_BUFFER pbuf = &pcmi->bufDecode;
  2252. PBYTE pbData = pbuf->pbData + pbuf->cbDead;
  2253. DWORD cbData = pbuf->cbUsed - pbuf->cbDead;
  2254. LONG lSkipped;
  2255. DWORD cbContent;
  2256. const BYTE *pbContent;
  2257. if (pcmi->aflStream & ICMS_PROCESS_CONTENT_BEGUN)
  2258. goto MultipleContentSequenceError;
  2259. // Get the tag and length for the inner content
  2260. if (0 > (lSkipped = Asn1UtilExtractContent(
  2261. pbData,
  2262. cbData,
  2263. &cbContent,
  2264. &pbContent))) {
  2265. if (ASN1UTIL_INSUFFICIENT_DATA != lSkipped)
  2266. goto ExtractContentError;
  2267. else
  2268. goto SuccessReturn;
  2269. }
  2270. if (CMSG_INDEFINITE_LENGTH == cbContent)
  2271. goto IndefiniteLengthInnerContentNotImplemented;
  2272. // Output the tag and length octets for the encoded inner content.
  2273. // Note, not included in the content to be verified in a signature.
  2274. if (!ICMS_Output( pcmi, pbData, (DWORD) lSkipped, FALSE))
  2275. goto OutputError;
  2276. pcmi->aflStream |= ICMS_INNER_OCTETSTRING;
  2277. // Decode as an octet string. Will skip the tag and length octets
  2278. fRet = ICMS_DecodeContentOctetString(pcmi, fFinal);
  2279. CommonReturn:
  2280. return fRet;
  2281. SuccessReturn:
  2282. fRet = TRUE;
  2283. goto CommonReturn;
  2284. ErrorReturn:
  2285. fRet = FALSE;
  2286. goto CommonReturn;
  2287. SET_ERROR(MultipleContentSequenceError, CRYPT_E_MSG_ERROR)
  2288. TRACE_ERROR(ExtractContentError)
  2289. SET_ERROR(IndefiniteLengthInnerContentNotImplemented, E_NOTIMPL)
  2290. TRACE_ERROR(OutputError)
  2291. }
  2292. //+-------------------------------------------------------------------------
  2293. // Handle incremental prefix data to be decoded.
  2294. //--------------------------------------------------------------------------
  2295. BOOL
  2296. WINAPI
  2297. ICMS_DecodeContent(
  2298. IN PCRYPT_MSG_INFO pcmi,
  2299. IN BOOL fFinal)
  2300. {
  2301. DWORD dwError = ERROR_SUCCESS;
  2302. BOOL fRet;
  2303. PICM_BUFFER pbuf = &pcmi->bufDecode;
  2304. if (pcmi->aflStream & ICMS_RAW_DATA) {
  2305. // Should be able to skip bufDecode for this case.
  2306. if (!ICMS_Output(
  2307. pcmi,
  2308. pbuf->pbData + pbuf->cbDead,
  2309. pbuf->cbUsed - pbuf->cbDead,
  2310. fFinal))
  2311. goto RawOutputError;
  2312. pbuf->cbDead = pbuf->cbUsed;
  2313. if (fFinal)
  2314. pcmi->aflStream |= ICMS_DECODED_CONTENT | ICMS_DECODED_SUFFIX;
  2315. } else if (pcmi->aflStream & ICMS_INNER_OCTETSTRING) {
  2316. if (!ICMS_DecodeContentOctetString( pcmi, fFinal))
  2317. goto DecodeContentOctetStringError;
  2318. } else {
  2319. if (!ICMS_DecodeContentSequence( pcmi, fFinal))
  2320. goto DecodeContentSequenceError;
  2321. }
  2322. fRet = TRUE;
  2323. CommonReturn:
  2324. ICM_SetLastError(dwError);
  2325. return fRet;
  2326. ErrorReturn:
  2327. dwError = GetLastError();
  2328. fRet = FALSE;
  2329. goto CommonReturn;
  2330. TRACE_ERROR(RawOutputError) // error already set
  2331. TRACE_ERROR(DecodeContentOctetStringError) // error already set
  2332. TRACE_ERROR(DecodeContentSequenceError) // error already set
  2333. }
  2334. //+-------------------------------------------------------------------------
  2335. // Handle incremental prefix data to be decoded, for a data message.
  2336. //--------------------------------------------------------------------------
  2337. BOOL
  2338. WINAPI
  2339. ICMS_DecodePrefixData(
  2340. IN PCRYPT_MSG_INFO pcmi,
  2341. IN BOOL fFinal)
  2342. {
  2343. if (0 ==(pcmi->aflStream & ICMS_NONBARE))
  2344. pcmi->aflStream |= ICMS_RAW_DATA;
  2345. pcmi->aflStream |= ICMS_DECODED_PREFIX | ICMS_INNER_OCTETSTRING;
  2346. return TRUE;
  2347. }
  2348. //+-------------------------------------------------------------------------
  2349. // Handle incremental prefix data to be decoded, for a signed message.
  2350. //--------------------------------------------------------------------------
  2351. BOOL
  2352. WINAPI
  2353. ICMS_DecodePrefixSigned(
  2354. IN PCRYPT_MSG_INFO pcmi,
  2355. IN BOOL fFinal)
  2356. {
  2357. DWORD dwError = ERROR_SUCCESS;
  2358. BOOL fRet;
  2359. ASN1decoding_t pDec = ICM_GetDecoder();
  2360. PSIGNED_DATA_INFO psdi = pcmi->psdi;
  2361. DWORD dwToken;
  2362. int *piVersion = NULL;
  2363. DigestAlgorithmIdentifiersNC *pDigestAlgorithms = NULL;
  2364. Any *pAny;
  2365. DWORD cb;
  2366. DWORD i;
  2367. BOOL fNoContent;
  2368. if (NULL == psdi) {
  2369. if (NULL == (psdi = (PSIGNED_DATA_INFO)ICM_AllocZero(
  2370. sizeof(SIGNED_DATA_INFO))))
  2371. goto SdiAllocError;
  2372. pcmi->psdi = psdi;
  2373. if (NULL == (psdi->pAlgidList = new CBlobList))
  2374. goto NewAlgidListError;
  2375. if (NULL == (psdi->pCertificateList = new CBlobList))
  2376. goto NewCertificateListError;
  2377. if (NULL == (psdi->pCrlList = new CBlobList))
  2378. goto NewCrlListError;
  2379. if (NULL == (psdi->pSignerList = new CSignerList))
  2380. goto NewSignerListError;
  2381. }
  2382. // SignedData sequence
  2383. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_SEQ)) {
  2384. if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, NULL))
  2385. goto GetTokenError;
  2386. switch(dwToken) {
  2387. case ICMS_TOKEN_INDEFINITE: pcmi->cEndNullPairs++; break;
  2388. case ICMS_TOKEN_DEFINITE: break;
  2389. case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn;
  2390. default: goto InvalidTokenError;
  2391. }
  2392. pcmi->aflDecode |= ICMS_DECODED_SIGNED_SEQ;
  2393. }
  2394. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_SEQ))
  2395. goto SuccessReturn;
  2396. // version
  2397. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_VERSION)) {
  2398. if (!ICMS_DecodePDU(
  2399. pcmi,
  2400. pDec,
  2401. IntegerType_PDU,
  2402. (void **)&piVersion))
  2403. goto DecodeVersionError;
  2404. if (piVersion) {
  2405. psdi->version = *piVersion;
  2406. pcmi->aflDecode |= ICMS_DECODED_SIGNED_VERSION;
  2407. }
  2408. }
  2409. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_VERSION))
  2410. goto SuccessReturn;
  2411. // digestAlgorithms
  2412. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_DIGESTALGOS)) {
  2413. if (!ICMS_DecodePDU(
  2414. pcmi,
  2415. pDec,
  2416. DigestAlgorithmIdentifiersNC_PDU,
  2417. (void **)&pDigestAlgorithms))
  2418. goto DecodeDigestAlgorithmsError;
  2419. if (pDigestAlgorithms) {
  2420. for (i=pDigestAlgorithms->count, pAny=pDigestAlgorithms->value;
  2421. i>0;
  2422. i--, pAny++) {
  2423. if (!ICM_InsertTailBlob( psdi->pAlgidList, pAny))
  2424. goto DigestAlgorithmInsertTailBlobError;
  2425. }
  2426. // We have the algorithms. Now create the hash handles.
  2427. if (!ICM_CreateHashList(
  2428. pcmi->hCryptProv,
  2429. &pcmi->pHashList,
  2430. pcmi->psdi->pAlgidList))
  2431. goto CreateHashListError;
  2432. pcmi->aflDecode |= ICMS_DECODED_SIGNED_DIGESTALGOS;
  2433. }
  2434. }
  2435. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_DIGESTALGOS))
  2436. goto SuccessReturn;
  2437. // contentInfo
  2438. if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_CONTENTINFO)) {
  2439. if (!ICMS_DecodePrefixContentInfo(
  2440. pcmi,
  2441. &pcmi->pooid,
  2442. &pcmi->cInnerNullPairs,
  2443. &pcmi->aflInner,
  2444. &fNoContent))
  2445. goto DecodePrefixSignedContentInfoError;
  2446. if (pcmi->aflInner & ICMS_DECODED_CONTENTINFO_CONTENT) {
  2447. // We cracked the whole header.
  2448. // Translate the inner contentType oid into a string.
  2449. if (!PkiAsn1FromObjectIdentifier(
  2450. pcmi->pooid->count,
  2451. pcmi->pooid->value,
  2452. NULL,
  2453. &cb))
  2454. goto PkiAsn1FromObjectIdentifierSizeError;
  2455. if (NULL == (psdi->pci = (PCONTENT_INFO)ICM_Alloc(
  2456. cb + INFO_LEN_ALIGN(sizeof(CONTENT_INFO)))))
  2457. goto AllocContentInfoError;
  2458. psdi->pci->pszContentType = (LPSTR)(psdi->pci) +
  2459. INFO_LEN_ALIGN(sizeof(CONTENT_INFO));
  2460. psdi->pci->content.cbData = 0;
  2461. psdi->pci->content.pbData = NULL;
  2462. if (!PkiAsn1FromObjectIdentifier(
  2463. pcmi->pooid->count,
  2464. pcmi->pooid->value,
  2465. psdi->pci->pszContentType,
  2466. &cb))
  2467. goto PkiAsn1FromObjectIdentifierError;
  2468. PkiAsn1FreeDecoded(pDec, pcmi->pooid, ObjectIdentifierType_PDU);
  2469. pcmi->pooid = NULL;
  2470. pcmi->aflDecode |= ICMS_DECODED_SIGNED_CONTENTINFO;
  2471. if (fNoContent) {
  2472. // No content. Output final flag with no content.
  2473. if (!ICMS_Output(pcmi, NULL, 0, TRUE))
  2474. goto OutputError;
  2475. pcmi->aflStream |= ICMS_DECODED_CONTENT;
  2476. } else {
  2477. if (0 == strcmp( psdi->pci->pszContentType, pszObjIdDataType)
  2478. #ifdef CMS_PKCS7
  2479. || psdi->version >= CMSG_SIGNED_DATA_V3
  2480. #endif // CMS_PKCS7
  2481. )
  2482. pcmi->aflStream |= ICMS_INNER_OCTETSTRING;
  2483. }
  2484. pcmi->aflStream |= ICMS_DECODED_PREFIX;
  2485. }
  2486. }
  2487. SuccessReturn:
  2488. fRet = TRUE;
  2489. CommonReturn:
  2490. PkiAsn1FreeInfo( pDec, IntegerType_PDU, piVersion);
  2491. PkiAsn1FreeInfo( pDec, DigestAlgorithmIdentifiersNC_PDU, pDigestAlgorithms);
  2492. ICM_SetLastError(dwError);
  2493. return fRet;
  2494. ErrorReturn:
  2495. dwError = GetLastError();
  2496. // note, pcmi->psdi and pcmi->pooid are freed in CryptMsgClose
  2497. fRet = FALSE;
  2498. goto CommonReturn;
  2499. TRACE_ERROR(SdiAllocError) // error already set
  2500. TRACE_ERROR(NewAlgidListError) // error already set
  2501. TRACE_ERROR(NewCertificateListError) // error already set
  2502. TRACE_ERROR(NewCrlListError) // error already set
  2503. TRACE_ERROR(NewSignerListError) // error already set
  2504. TRACE_ERROR(GetTokenError) // error already set
  2505. TRACE_ERROR(InvalidTokenError) // error already set
  2506. TRACE_ERROR(DecodeVersionError) // error already set
  2507. TRACE_ERROR(DecodeDigestAlgorithmsError) // error already set
  2508. TRACE_ERROR(DigestAlgorithmInsertTailBlobError) // error already set
  2509. TRACE_ERROR(CreateHashListError) // error already set
  2510. TRACE_ERROR(DecodePrefixSignedContentInfoError) // error already set
  2511. TRACE_ERROR(PkiAsn1FromObjectIdentifierSizeError) // error already set
  2512. TRACE_ERROR(AllocContentInfoError) // error already set
  2513. TRACE_ERROR(PkiAsn1FromObjectIdentifierError) // error already set
  2514. TRACE_ERROR(OutputError) // error already set
  2515. }
  2516. //+-------------------------------------------------------------------------
  2517. // Handle incremental prefix data to be decoded, for an enveloped message.
  2518. //--------------------------------------------------------------------------
  2519. BOOL
  2520. WINAPI
  2521. ICMS_DecodePrefixEnveloped(
  2522. IN PCRYPT_MSG_INFO pcmi,
  2523. IN BOOL fFinal)
  2524. {
  2525. DWORD dwError = ERROR_SUCCESS;
  2526. BOOL fRet;
  2527. ASN1decoding_t pDec = ICM_GetDecoder();
  2528. PICM_BUFFER pbuf = &pcmi->bufDecode;
  2529. #ifdef CMS_PKCS7
  2530. CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
  2531. #else
  2532. EnvelopedData *ped = (EnvelopedData *)pcmi->pvMsg;
  2533. #endif // CMS_PKCS7
  2534. DWORD dwToken;
  2535. int *piVersion = NULL;
  2536. #ifdef CMS_PKCS7
  2537. CmsRecipientInfos *pRecipientInfos = NULL;
  2538. #else
  2539. RecipientInfos *pRecipientInfos = NULL;
  2540. #endif // CMS_PKCS7
  2541. ObjectIdentifierType *pooidContentType = NULL;
  2542. AlgorithmIdentifier *poaidContentEncryption = NULL;
  2543. COssDecodeInfoNode *pnOssDecodeInfo;
  2544. OSS_DECODE_INFO odi;
  2545. DWORD cbConsumed;
  2546. #ifdef CMS_PKCS7
  2547. OriginatorInfoNC *pOriginatorInfo = NULL;
  2548. Any *pAny;
  2549. DWORD i;
  2550. #endif // CMS_PKCS7
  2551. if (NULL == ped) {
  2552. #ifdef CMS_PKCS7
  2553. if (NULL == (ped = (CmsEnvelopedData *)ICM_AllocZero(
  2554. sizeof(CmsEnvelopedData))))
  2555. #else
  2556. if (NULL == (ped = (EnvelopedData *)ICM_AllocZero(
  2557. sizeof(EnvelopedData))))
  2558. #endif // CMS_PKCS7
  2559. goto AllocEnvelopedDataError;
  2560. pcmi->pvMsg = ped;
  2561. if (NULL == (pcmi->plDecodeInfo = new COssDecodeInfoList))
  2562. goto NewCOssDecodeInfoListError;
  2563. #ifdef CMS_PKCS7
  2564. if (NULL == (pcmi->pCertificateList = new CBlobList))
  2565. goto NewCertificateListError;
  2566. if (NULL == (pcmi->pCrlList = new CBlobList))
  2567. goto NewCrlListError;
  2568. #endif // CMS_PKCS7
  2569. }
  2570. // EnvelopedData SEQ
  2571. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_SEQ)) {
  2572. if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, NULL))
  2573. goto EnvelopedDataSeqGetTokenError;
  2574. switch(dwToken) {
  2575. case ICMS_TOKEN_INDEFINITE: pcmi->cEndNullPairs++; break;
  2576. case ICMS_TOKEN_DEFINITE: break;
  2577. case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn;
  2578. default: goto InvalidTokenError;
  2579. }
  2580. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_SEQ;
  2581. }
  2582. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_SEQ))
  2583. goto SuccessReturn;
  2584. // version
  2585. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_VERSION)) {
  2586. if (!ICMS_DecodePDU(
  2587. pcmi,
  2588. pDec,
  2589. IntegerType_PDU,
  2590. (void **)&piVersion))
  2591. goto DecodeVersionError;
  2592. if (piVersion) {
  2593. ped->version = *piVersion;
  2594. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_VERSION;
  2595. }
  2596. }
  2597. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_VERSION))
  2598. goto SuccessReturn;
  2599. #ifdef CMS_PKCS7
  2600. // originatorInfo OPTIONAL
  2601. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ORIGINATOR)) {
  2602. if (pbuf->cbUsed > pbuf->cbDead) {
  2603. if (ICM_TAG_CONSTRUCTED_CONTEXT_0 ==
  2604. *(pbuf->pbData + pbuf->cbDead)) {
  2605. // Detected the [0] IMPLICIT indicating originatorInfo.
  2606. // Change the identifier octet so it will decode properly.
  2607. *(pbuf->pbData + pbuf->cbDead) = ICM_TAG_SEQ;
  2608. if (!ICMS_DecodePDU(
  2609. pcmi,
  2610. pDec,
  2611. OriginatorInfoNC_PDU,
  2612. (void **)&pOriginatorInfo))
  2613. goto DecodeOriginatorInfoError;
  2614. if (pOriginatorInfo) {
  2615. if (pOriginatorInfo->bit_mask & certificates_present) {
  2616. for (i=pOriginatorInfo->certificates.count,
  2617. #ifdef OSS_CRYPT_ASN1
  2618. pAny=pOriginatorInfo->certificates.certificates;
  2619. #else
  2620. pAny=pOriginatorInfo->certificates.value;
  2621. #endif // OSS_CRYPT_ASN1
  2622. i>0;
  2623. i--, pAny++) {
  2624. if (!ICM_InsertTailBlob( pcmi->pCertificateList,
  2625. pAny))
  2626. goto CertInsertTailBlobError;
  2627. }
  2628. }
  2629. if (pOriginatorInfo->bit_mask & crls_present) {
  2630. for (i=pOriginatorInfo->crls.count,
  2631. #ifdef OSS_CRYPT_ASN1
  2632. pAny=pOriginatorInfo->crls.crls;
  2633. #else
  2634. pAny=pOriginatorInfo->crls.value;
  2635. #endif // OSS_CRYPT_ASN1
  2636. i>0;
  2637. i--, pAny++) {
  2638. if (!ICM_InsertTailBlob( pcmi->pCrlList, pAny))
  2639. goto CrlInsertTailBlobError;
  2640. }
  2641. }
  2642. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ORIGINATOR;
  2643. } else {
  2644. // The decode failed, presumably due to insufficient data.
  2645. // Restore the original tag, so we will enter this block
  2646. // and try again on the next call.
  2647. *(pbuf->pbData + pbuf->cbDead) =
  2648. ICM_TAG_CONSTRUCTED_CONTEXT_0;
  2649. }
  2650. } else {
  2651. // originatorInfo not present. Mark as decoded.
  2652. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ORIGINATOR;
  2653. }
  2654. }
  2655. }
  2656. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ORIGINATOR))
  2657. goto SuccessReturn;
  2658. #endif // CMS_PKCS7
  2659. // recipientInfos
  2660. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_RECIPINFOS)) {
  2661. if (!ICMS_DecodePDU(
  2662. pcmi,
  2663. pDec,
  2664. #ifdef CMS_PKCS7
  2665. CmsRecipientInfos_PDU,
  2666. #else
  2667. RecipientInfos_PDU,
  2668. #endif // CMS_PKCS7
  2669. (void **)&pRecipientInfos))
  2670. goto DecodeRecipientInfosError;
  2671. if (pRecipientInfos) {
  2672. ped->recipientInfos = *pRecipientInfos;
  2673. #ifdef CMS_PKCS7
  2674. odi.iPDU = CmsRecipientInfos_PDU;
  2675. #else
  2676. odi.iPDU = RecipientInfos_PDU;
  2677. #endif // CMS_PKCS7
  2678. odi.pvPDU = pRecipientInfos;
  2679. if (NULL == (pnOssDecodeInfo = new COssDecodeInfoNode( &odi))) {
  2680. PkiAsn1FreeInfo( pDec, odi.iPDU, odi.pvPDU);
  2681. goto NewOssDecodeInfoNodeError;
  2682. }
  2683. pcmi->plDecodeInfo->InsertTail( pnOssDecodeInfo);
  2684. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_RECIPINFOS;
  2685. }
  2686. }
  2687. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_RECIPINFOS))
  2688. goto SuccessReturn;
  2689. // encryptedContentInfo SEQ
  2690. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECISEQ)) {
  2691. if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, &pcmi->cbContentInfo))
  2692. goto EncryptedContentInfoSeqGetTokenError;
  2693. switch(dwToken) {
  2694. case ICMS_TOKEN_INDEFINITE: pcmi->cInnerNullPairs++; break;
  2695. case ICMS_TOKEN_DEFINITE: break;
  2696. case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn;
  2697. default: goto InvalidTokenError;
  2698. }
  2699. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECISEQ;
  2700. }
  2701. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECISEQ))
  2702. goto SuccessReturn;
  2703. // contentType
  2704. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECITYPE)) {
  2705. if (!ICMS_DecodePDU(
  2706. pcmi,
  2707. pDec,
  2708. ObjectIdentifierType_PDU,
  2709. (void **)&pooidContentType,
  2710. &cbConsumed))
  2711. goto DecodeContentTypeError;
  2712. if (pooidContentType) {
  2713. ICM_CopyOssObjectIdentifier(&ped->encryptedContentInfo.contentType,
  2714. pooidContentType);
  2715. // NB- Since ContentType is self-contained and we have saved
  2716. // a copy, we can always free pooidContentType when this
  2717. // routine exits.
  2718. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECITYPE;
  2719. if (CMSG_INDEFINITE_LENGTH != pcmi->cbContentInfo) {
  2720. if (cbConsumed > pcmi->cbContentInfo)
  2721. goto InvalidEncryptedContentInfoLength;
  2722. pcmi->cbContentInfo -= cbConsumed;
  2723. }
  2724. }
  2725. }
  2726. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECITYPE))
  2727. goto SuccessReturn;
  2728. // contentEncryptionAlgorithm
  2729. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECIALGID)) {
  2730. if (!ICMS_DecodePDU(
  2731. pcmi,
  2732. pDec,
  2733. AlgorithmIdentifier_PDU,
  2734. (void **)&poaidContentEncryption,
  2735. &cbConsumed))
  2736. goto DecodeContentEncryptionAlgorithmError;
  2737. if (poaidContentEncryption) {
  2738. ped->encryptedContentInfo.contentEncryptionAlgorithm =
  2739. *poaidContentEncryption;
  2740. odi.iPDU = AlgorithmIdentifier_PDU;
  2741. odi.pvPDU = poaidContentEncryption;
  2742. if (NULL == (pnOssDecodeInfo = new COssDecodeInfoNode( &odi))) {
  2743. PkiAsn1FreeInfo( pDec, AlgorithmIdentifier_PDU,
  2744. poaidContentEncryption);
  2745. goto NewOssDecodeInfoNodeError;
  2746. }
  2747. pcmi->plDecodeInfo->InsertTail( pnOssDecodeInfo);
  2748. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECIALGID;
  2749. if (CMSG_INDEFINITE_LENGTH != pcmi->cbContentInfo &&
  2750. cbConsumed == pcmi->cbContentInfo) {
  2751. // The encryptedContent has been omitted
  2752. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECICONTENT;
  2753. pcmi->aflStream |= ICMS_DECODED_PREFIX | ICMS_DECODED_CONTENT;
  2754. if (pcmi->hkeyContentCrypt) {
  2755. if (!ICMS_Output(
  2756. pcmi,
  2757. NULL, // pbData
  2758. 0, // cbData
  2759. TRUE)) // fFinal
  2760. goto FinalOutputError;
  2761. }
  2762. }
  2763. }
  2764. }
  2765. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECIALGID))
  2766. goto SuccessReturn;
  2767. // encryptedContent [0] IMPLICIT OPTIONAL
  2768. //
  2769. // Only support DATA or encapsulated encrypted content.
  2770. if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECICONTENT)) {
  2771. BOOL fNoEncryptedContent = FALSE;
  2772. if (pbuf->cbUsed > pbuf->cbDead) {
  2773. BYTE bTag = *(pbuf->pbData + pbuf->cbDead);
  2774. if (ICM_TAG_CONTEXT_0 == (bTag & ~ICM_TAG_CONSTRUCTED)) {
  2775. // Detected the [0] IMPLICIT indicating encryptedContent.
  2776. // Change the identifier octet so it will decode properly.
  2777. *(pbuf->pbData + pbuf->cbDead) = ICM_TAG_OCTETSTRING |
  2778. (bTag & ICM_TAG_CONSTRUCTED);
  2779. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECICONTENT;
  2780. // The inner type is always OCTET STRING
  2781. pcmi->aflStream |= ICMS_DECODED_PREFIX | ICMS_INNER_OCTETSTRING;
  2782. } else
  2783. fNoEncryptedContent = TRUE;
  2784. } else if (fFinal)
  2785. fNoEncryptedContent = TRUE;
  2786. if (fNoEncryptedContent) {
  2787. // The encryptedContent has been omitted
  2788. pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECICONTENT;
  2789. pcmi->aflStream |= ICMS_DECODED_PREFIX | ICMS_DECODED_CONTENT;
  2790. if (pcmi->hkeyContentCrypt) {
  2791. if (!ICMS_Output(
  2792. pcmi,
  2793. NULL, // pbData
  2794. 0, // cbData
  2795. TRUE)) // fFinal
  2796. goto FinalOutputError;
  2797. }
  2798. }
  2799. }
  2800. SuccessReturn:
  2801. fRet = TRUE;
  2802. CommonReturn:
  2803. PkiAsn1FreeInfo( pDec, IntegerType_PDU, piVersion);
  2804. #ifdef CMS_PKCS7
  2805. PkiAsn1FreeInfo( pDec, OriginatorInfoNC_PDU, pOriginatorInfo);
  2806. #endif // CMS_PKCS7
  2807. PkiAsn1FreeInfo( pDec, ObjectIdentifierType_PDU, pooidContentType);
  2808. ICM_SetLastError(dwError);
  2809. return fRet;
  2810. ErrorReturn:
  2811. dwError = GetLastError();
  2812. fRet = FALSE;
  2813. goto CommonReturn;
  2814. TRACE_ERROR(EnvelopedDataSeqGetTokenError) // error already set
  2815. TRACE_ERROR(EncryptedContentInfoSeqGetTokenError) // error already set
  2816. TRACE_ERROR(InvalidTokenError) // error already set
  2817. TRACE_ERROR(DecodeVersionError) // error already set
  2818. TRACE_ERROR(AllocEnvelopedDataError) // error already set
  2819. TRACE_ERROR(NewCOssDecodeInfoListError) // error already set
  2820. #ifdef CMS_PKCS7
  2821. TRACE_ERROR(NewCertificateListError) // error already set
  2822. TRACE_ERROR(NewCrlListError) // error already set
  2823. TRACE_ERROR(DecodeOriginatorInfoError) // error already set
  2824. TRACE_ERROR(CertInsertTailBlobError) // error already set
  2825. TRACE_ERROR(CrlInsertTailBlobError) // error already set
  2826. #endif // CMS_PKCS7
  2827. TRACE_ERROR(DecodeRecipientInfosError) // error already set
  2828. TRACE_ERROR(DecodeContentTypeError) // error already set
  2829. SET_ERROR(InvalidEncryptedContentInfoLength, CRYPT_E_MSG_ERROR)
  2830. TRACE_ERROR(DecodeContentEncryptionAlgorithmError) // error already set
  2831. TRACE_ERROR(NewOssDecodeInfoNodeError) // error already set
  2832. TRACE_ERROR(FinalOutputError) // error already set
  2833. }
  2834. //+-------------------------------------------------------------------------
  2835. // Handle incremental prefix data to be decoded.
  2836. //--------------------------------------------------------------------------
  2837. BOOL
  2838. WINAPI
  2839. ICMS_DecodePrefix(
  2840. IN PCRYPT_MSG_INFO pcmi,
  2841. IN BOOL fFinal)
  2842. {
  2843. DWORD dwError = ERROR_SUCCESS;
  2844. BOOL fRet;
  2845. LONG lth;
  2846. BOOL fNoContent;
  2847. if (0 == pcmi->dwMsgType) {
  2848. pcmi->aflStream |= ICMS_NONBARE;
  2849. if (!ICMS_DecodePrefixContentInfo(
  2850. pcmi,
  2851. &pcmi->pooid,
  2852. &pcmi->cEndNullPairs,
  2853. &pcmi->aflOuter,
  2854. &fNoContent))
  2855. goto DecodePrefixContentInfoError;
  2856. if (pcmi->aflOuter & ICMS_DECODED_CONTENTINFO_CONTENT) {
  2857. // We cracked the whole header.
  2858. // Translate the contentType oid into a message type.
  2859. if (0 == (lth = ICM_ObjIdToIndex( pcmi->pooid)))
  2860. goto UnknownContentTypeError;
  2861. pcmi->dwMsgType = (DWORD)lth;
  2862. PkiAsn1FreeDecoded(ICM_GetDecoder(), pcmi->pooid,
  2863. ObjectIdentifierType_PDU);
  2864. pcmi->pooid = NULL;
  2865. // Address case of no content
  2866. }
  2867. }
  2868. switch (pcmi->dwMsgType) {
  2869. case 0:
  2870. if (fFinal)
  2871. goto FinalWithoutMessageTypeError;
  2872. break;
  2873. case CMSG_DATA:
  2874. if (!ICMS_DecodePrefixData( pcmi, fFinal))
  2875. goto DecodePrefixDataError;
  2876. break;
  2877. case CMSG_SIGNED:
  2878. if (!ICMS_DecodePrefixSigned( pcmi, fFinal))
  2879. goto DecodePrefixSignedError;
  2880. break;
  2881. case CMSG_ENVELOPED:
  2882. if (!ICMS_DecodePrefixEnveloped( pcmi, fFinal))
  2883. goto DecodePrefixEnvelopedError;
  2884. break;
  2885. case CMSG_HASHED:
  2886. // if (!ICMS_DecodePrefixDigested( pcmi, fFinal))
  2887. // goto DecodePrefixDigestedError;
  2888. // break;
  2889. case CMSG_SIGNED_AND_ENVELOPED:
  2890. case CMSG_ENCRYPTED:
  2891. goto MessageTypeNotSupportedYet;
  2892. default:
  2893. goto InvalidMsgType;
  2894. }
  2895. fRet = TRUE;
  2896. CommonReturn:
  2897. ICM_SetLastError(dwError);
  2898. return fRet;
  2899. ErrorReturn:
  2900. dwError = GetLastError();
  2901. fRet = FALSE;
  2902. goto CommonReturn;
  2903. SET_ERROR(FinalWithoutMessageTypeError,CRYPT_E_STREAM_INSUFFICIENT_DATA)
  2904. TRACE_ERROR(UnknownContentTypeError) // error already set
  2905. TRACE_ERROR(DecodePrefixContentInfoError) // error already set
  2906. TRACE_ERROR(DecodePrefixDataError) // error already set
  2907. TRACE_ERROR(DecodePrefixSignedError) // error already set
  2908. TRACE_ERROR(DecodePrefixEnvelopedError) // error already set
  2909. SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
  2910. TRACE_ERROR(InvalidMsgType) // error already set
  2911. }
  2912. //+-------------------------------------------------------------------------
  2913. // Handle incremental data to be decoded (work done here).
  2914. //--------------------------------------------------------------------------
  2915. BOOL
  2916. WINAPI
  2917. ICMS_UpdateDecodingInner(
  2918. IN PCRYPT_MSG_INFO pcmi,
  2919. IN BOOL fFinal)
  2920. {
  2921. DWORD dwError = ERROR_SUCCESS;
  2922. BOOL fRet;
  2923. if (0 == (pcmi->aflStream & ICMS_DECODED_PREFIX)) {
  2924. if (!ICMS_DecodePrefix( pcmi, fFinal))
  2925. goto DecodePrefixError;
  2926. }
  2927. if (0 == (pcmi->aflStream & ICMS_DECODED_PREFIX))
  2928. goto SuccessReturn;
  2929. if (0 == (pcmi->aflStream & ICMS_DECODED_CONTENT)) {
  2930. if (!ICMS_DecodeContent( pcmi, fFinal))
  2931. goto DecodeContentError; // NB- Do not trash err from callback!
  2932. }
  2933. if (0 == (pcmi->aflStream & ICMS_DECODED_CONTENT))
  2934. goto SuccessReturn;
  2935. if (0 == (pcmi->aflStream & ICMS_DECODED_SUFFIX)) {
  2936. if (!ICMS_DecodeSuffix( pcmi, fFinal))
  2937. goto DecodeSuffixError;
  2938. }
  2939. if (0 == (pcmi->aflStream & ICMS_DECODED_SUFFIX))
  2940. goto SuccessReturn;
  2941. SuccessReturn:
  2942. fRet = TRUE;
  2943. CommonReturn:
  2944. ICM_SetLastError(dwError);
  2945. return fRet;
  2946. ErrorReturn:
  2947. dwError = GetLastError();
  2948. fRet = FALSE;
  2949. goto CommonReturn;
  2950. TRACE_ERROR(DecodePrefixError) // error already set
  2951. TRACE_ERROR(DecodeContentError) // error already set
  2952. TRACE_ERROR(DecodeSuffixError) // error already set
  2953. }
  2954. //+-------------------------------------------------------------------------
  2955. // Handle incremental data to be decoded.
  2956. //
  2957. // Note, the buffer to be decoded may have some of its tags modified.
  2958. // Therefore, we always need to copy to our own decode buffer.
  2959. //--------------------------------------------------------------------------
  2960. BOOL
  2961. WINAPI
  2962. ICMS_UpdateDecoding(
  2963. IN PCRYPT_MSG_INFO pcmi,
  2964. IN const BYTE *pbData,
  2965. IN DWORD cbData,
  2966. IN BOOL fFinal)
  2967. {
  2968. DWORD dwError = ERROR_SUCCESS;
  2969. BOOL fRet;
  2970. pcmi->fStreamCallbackOutput = TRUE;
  2971. if (!ICMS_QueueToBuffer( &pcmi->bufDecode, (PBYTE)pbData, cbData))
  2972. goto QueueToBufferError;
  2973. if (!ICMS_UpdateDecodingInner( pcmi, fFinal))
  2974. goto UpdateDecodingInnerError;
  2975. if (fFinal) {
  2976. if (pcmi->bufDecode.cbUsed > pcmi->bufDecode.cbDead)
  2977. goto ExcessDataError;
  2978. pcmi->aflStream |= ICMS_FINAL;
  2979. }
  2980. fRet = TRUE;
  2981. CommonReturn:
  2982. ICM_SetLastError(dwError);
  2983. return fRet;
  2984. ErrorReturn:
  2985. dwError = GetLastError();
  2986. fRet = FALSE;
  2987. goto CommonReturn;
  2988. TRACE_ERROR(QueueToBufferError) // error already set
  2989. TRACE_ERROR(UpdateDecodingInnerError) // error already set
  2990. SET_ERROR(ExcessDataError, CRYPT_E_MSG_ERROR)
  2991. }
  2992. #if 0
  2993. // When we fix the decoding of [0] Certificates and [1] Crls not to modify
  2994. // the encoded data we can replace the above with the following:
  2995. //+-------------------------------------------------------------------------
  2996. // Handle incremental data to be decoded.
  2997. //--------------------------------------------------------------------------
  2998. BOOL
  2999. WINAPI
  3000. ICMS_UpdateDecoding(
  3001. IN PCRYPT_MSG_INFO pcmi,
  3002. IN const BYTE *pbData,
  3003. IN DWORD cbData,
  3004. IN BOOL fFinal)
  3005. {
  3006. DWORD dwError = ERROR_SUCCESS;
  3007. BOOL fRet;
  3008. PICM_BUFFER pbuf = &pcmi->bufDecode;
  3009. BOOL fNoCopy;
  3010. pcmi->fStreamCallbackOutput = TRUE;
  3011. if (fFinal && NULL == pbuf->pbData) {
  3012. // We're able to use the input buffer without copying
  3013. fNoCopy = TRUE;
  3014. assert(0 == pbuf->cbSize && 0 == pbuf->cbUsed && 0 == pbuf->cbDead);
  3015. pbuf->pbData = (PBYTE) pbData;
  3016. pbuf->cbSize = cbData;
  3017. pbuf->cbUsed = cbData;
  3018. pbuf->cbDead = 0;
  3019. } else {
  3020. fNoCopy = FALSE;
  3021. if (!ICMS_QueueToBuffer( pbuf, (PBYTE)pbData, cbData))
  3022. goto QueueToBufferError;
  3023. }
  3024. if (!ICMS_UpdateDecodingInner( pcmi, fFinal))
  3025. goto UpdateDecodingInnerError;
  3026. if (fFinal) {
  3027. if (pcmi->bufDecode.cbUsed > pcmi->bufDecode.cbDead)
  3028. goto ExcessDataError;
  3029. pcmi->aflStream |= ICMS_FINAL;
  3030. }
  3031. fRet = TRUE;
  3032. CommonReturn:
  3033. if (fNoCopy)
  3034. memset(pbuf, 0, sizeof(*pbuf));
  3035. ICM_SetLastError(dwError);
  3036. return fRet;
  3037. ErrorReturn:
  3038. dwError = GetLastError();
  3039. fRet = FALSE;
  3040. goto CommonReturn;
  3041. TRACE_ERROR(QueueToBufferError) // error already set
  3042. TRACE_ERROR(UpdateDecodingInnerError) // error already set
  3043. SET_ERROR(ExcessDataError, CRYPT_E_MSG_ERROR)
  3044. }
  3045. #endif