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.

548 lines
16 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: msghlpr.cpp
  8. //
  9. // Contents: Cryptographic Message Helper APIs
  10. //
  11. // APIs: CryptMsgGetAndVerifySigner
  12. // CryptMsgSignCTL
  13. // CryptMsgEncodeAndSignCTL
  14. //
  15. // History: 02-May-97 philh created
  16. //--------------------------------------------------------------------------
  17. #include "global.hxx"
  18. #include "pkialloc.h"
  19. void *ICM_AllocAndGetMsgParam(
  20. IN HCRYPTMSG hMsg,
  21. IN DWORD dwParamType,
  22. IN DWORD dwIndex
  23. )
  24. {
  25. void *pvData;
  26. DWORD cbData;
  27. if (!CryptMsgGetParam(
  28. hMsg,
  29. dwParamType,
  30. dwIndex,
  31. NULL, // pvData
  32. &cbData) || 0 == cbData)
  33. goto GetParamError;
  34. if (NULL == (pvData = ICM_Alloc(cbData)))
  35. goto OutOfMemory;
  36. if (!CryptMsgGetParam(
  37. hMsg,
  38. dwParamType,
  39. dwIndex,
  40. pvData,
  41. &cbData)) {
  42. ICM_Free(pvData);
  43. goto GetParamError;
  44. }
  45. CommonReturn:
  46. return pvData;
  47. ErrorReturn:
  48. pvData = NULL;
  49. goto CommonReturn;
  50. TRACE_ERROR(OutOfMemory)
  51. TRACE_ERROR(GetParamError)
  52. }
  53. #ifdef CMS_PKCS7
  54. BOOL ICM_GetAndVerifySigner(
  55. IN HCRYPTMSG hCryptMsg,
  56. IN DWORD dwSignerIndex,
  57. IN DWORD cSignerStore,
  58. IN OPTIONAL HCERTSTORE *rghSignerStore,
  59. IN DWORD dwFlags,
  60. OUT OPTIONAL PCCERT_CONTEXT *ppSigner
  61. )
  62. {
  63. BOOL fResult;
  64. PCERT_INFO pSignerId = NULL;
  65. PCCERT_CONTEXT pSigner = NULL;
  66. DWORD dwCertEncodingType;
  67. DWORD dwVerifyErr = 0;
  68. HCERTSTORE hCollection = NULL;
  69. if (NULL == (pSignerId = (PCERT_INFO) ICM_AllocAndGetMsgParam(
  70. hCryptMsg,
  71. CMSG_SIGNER_CERT_INFO_PARAM,
  72. dwSignerIndex
  73. ))) goto GetSignerError;
  74. // If no CertEncodingType, then, use the MsgEncodingType
  75. dwCertEncodingType = ((PCRYPT_MSG_INFO) hCryptMsg)->dwEncodingType;
  76. if (0 == (dwCertEncodingType & CERT_ENCODING_TYPE_MASK))
  77. dwCertEncodingType =
  78. (dwCertEncodingType >> 16) & CERT_ENCODING_TYPE_MASK;
  79. if (NULL == (hCollection = CertOpenStore(
  80. CERT_STORE_PROV_COLLECTION,
  81. 0, // dwEncodingType
  82. 0, // hCryptProv
  83. 0, // dwFlags
  84. NULL // pvPara
  85. )))
  86. goto OpenCollectionStoreError;
  87. if (0 == (dwFlags & CMSG_TRUSTED_SIGNER_FLAG)) {
  88. HCERTSTORE hMsgCertStore;
  89. // Open a cert store initialized with certs from the message
  90. // and add to collection
  91. if (hMsgCertStore = CertOpenStore(
  92. CERT_STORE_PROV_MSG,
  93. dwCertEncodingType,
  94. 0, // hCryptProv
  95. 0, // dwFlags
  96. hCryptMsg // pvPara
  97. )) {
  98. CertAddStoreToCollection(
  99. hCollection,
  100. hMsgCertStore,
  101. CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
  102. 0 // dwPriority
  103. );
  104. CertCloseStore(hMsgCertStore, 0);
  105. }
  106. }
  107. // Add all the signer stores to the collection
  108. for ( ; cSignerStore > 0; cSignerStore--, rghSignerStore++) {
  109. HCERTSTORE hSignerStore = *rghSignerStore;
  110. if (NULL == hSignerStore)
  111. continue;
  112. CertAddStoreToCollection(
  113. hCollection,
  114. hSignerStore,
  115. CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
  116. 0 // dwPriority
  117. );
  118. }
  119. if (pSigner = CertGetSubjectCertificateFromStore(hCollection,
  120. dwCertEncodingType, pSignerId)) {
  121. CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA CtrlPara;
  122. if (dwFlags & CMSG_SIGNER_ONLY_FLAG)
  123. goto SuccessReturn;
  124. memset(&CtrlPara, 0, sizeof(CtrlPara));
  125. CtrlPara.cbSize = sizeof(CtrlPara);
  126. // CtrlPara.hCryptProv =
  127. CtrlPara.dwSignerIndex = dwSignerIndex;
  128. CtrlPara.dwSignerType = CMSG_VERIFY_SIGNER_CERT;
  129. CtrlPara.pvSigner = (void *) pSigner;
  130. if (CryptMsgControl(
  131. hCryptMsg,
  132. 0, // dwFlags
  133. CMSG_CTRL_VERIFY_SIGNATURE_EX,
  134. &CtrlPara)) goto SuccessReturn;
  135. else {
  136. dwVerifyErr = GetLastError();
  137. if (CRYPT_E_MISSING_PUBKEY_PARA == dwVerifyErr) {
  138. PCCERT_CHAIN_CONTEXT pChainContext;
  139. CERT_CHAIN_PARA ChainPara;
  140. // Build a chain. Hopefully, the signer inherit's its public key
  141. // parameters from up the chain
  142. memset(&ChainPara, 0, sizeof(ChainPara));
  143. ChainPara.cbSize = sizeof(ChainPara);
  144. if (CertGetCertificateChain(
  145. NULL, // hChainEngine
  146. pSigner,
  147. NULL, // pTime
  148. hCollection,
  149. &ChainPara,
  150. CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL,
  151. NULL, // pvReserved
  152. &pChainContext
  153. ))
  154. CertFreeCertificateChain(pChainContext);
  155. // Try again. Hopefully the above chain building updated the
  156. // signer's context property with the missing public key
  157. // parameters
  158. if (CryptMsgControl(
  159. hCryptMsg,
  160. 0, // dwFlags
  161. CMSG_CTRL_VERIFY_SIGNATURE_EX,
  162. &CtrlPara)) goto SuccessReturn;
  163. }
  164. }
  165. CertFreeCertificateContext(pSigner);
  166. pSigner = NULL;
  167. }
  168. if (dwVerifyErr)
  169. goto VerifySignatureError;
  170. else
  171. goto NoSignerError;
  172. SuccessReturn:
  173. fResult = TRUE;
  174. CommonReturn:
  175. if (hCollection)
  176. CertCloseStore(hCollection, 0);
  177. ICM_Free(pSignerId);
  178. if (ppSigner)
  179. *ppSigner = pSigner;
  180. else if (pSigner)
  181. CertFreeCertificateContext(pSigner);
  182. return fResult;
  183. ErrorReturn:
  184. fResult = FALSE;
  185. goto CommonReturn;
  186. TRACE_ERROR(OpenCollectionStoreError)
  187. TRACE_ERROR(GetSignerError)
  188. SET_ERROR(NoSignerError, CRYPT_E_NO_TRUSTED_SIGNER)
  189. SET_ERROR_VAR(VerifySignatureError, dwVerifyErr)
  190. }
  191. #else
  192. BOOL ICM_GetAndVerifySigner(
  193. IN HCRYPTMSG hCryptMsg,
  194. IN DWORD dwSignerIndex,
  195. IN DWORD cSignerStore,
  196. IN OPTIONAL HCERTSTORE *rghSignerStore,
  197. IN DWORD dwFlags,
  198. OUT OPTIONAL PCCERT_CONTEXT *ppSigner
  199. )
  200. {
  201. BOOL fResult;
  202. PCERT_INFO pSignerId = NULL;
  203. PCCERT_CONTEXT pSigner = NULL;
  204. DWORD dwCertEncodingType;
  205. DWORD dwVerifyErr = 0;
  206. if (NULL == (pSignerId = (PCERT_INFO) ICM_AllocAndGetMsgParam(
  207. hCryptMsg,
  208. CMSG_SIGNER_CERT_INFO_PARAM,
  209. dwSignerIndex
  210. ))) goto GetSignerError;
  211. // If no CertEncodingType, then, use the MsgEncodingType
  212. dwCertEncodingType = ((PCRYPT_MSG_INFO) hCryptMsg)->dwEncodingType;
  213. if (0 == (dwCertEncodingType & CERT_ENCODING_TYPE_MASK))
  214. dwCertEncodingType =
  215. (dwCertEncodingType >> 16) & CERT_ENCODING_TYPE_MASK;
  216. if (0 == (dwFlags & CMSG_TRUSTED_SIGNER_FLAG)) {
  217. HCERTSTORE hMsgCertStore;
  218. // Open a cert store initialized with certs from the message
  219. if (hMsgCertStore = CertOpenStore(
  220. CERT_STORE_PROV_MSG,
  221. dwCertEncodingType,
  222. 0, // hCryptProv
  223. 0, // dwFlags
  224. hCryptMsg // pvPara
  225. )) {
  226. pSigner = CertGetSubjectCertificateFromStore(hMsgCertStore,
  227. dwCertEncodingType, pSignerId);
  228. CertCloseStore(hMsgCertStore, 0);
  229. }
  230. if (pSigner) {
  231. if (dwFlags & CMSG_SIGNER_ONLY_FLAG)
  232. goto SuccessReturn;
  233. if (CryptMsgControl(
  234. hCryptMsg,
  235. 0, // dwFlags
  236. CMSG_CTRL_VERIFY_SIGNATURE,
  237. pSigner->pCertInfo)) goto SuccessReturn;
  238. else
  239. dwVerifyErr = GetLastError();
  240. CertFreeCertificateContext(pSigner);
  241. pSigner = NULL;
  242. }
  243. }
  244. for ( ; cSignerStore > 0; cSignerStore--, rghSignerStore++) {
  245. HCERTSTORE hSignerStore = *rghSignerStore;
  246. if (NULL == hSignerStore)
  247. continue;
  248. if (pSigner = CertGetSubjectCertificateFromStore(hSignerStore,
  249. dwCertEncodingType, pSignerId)) {
  250. if (dwFlags & CMSG_SIGNER_ONLY_FLAG)
  251. goto SuccessReturn;
  252. if (CryptMsgControl(
  253. hCryptMsg,
  254. 0, // dwFlags
  255. CMSG_CTRL_VERIFY_SIGNATURE,
  256. pSigner->pCertInfo)) goto SuccessReturn;
  257. else
  258. dwVerifyErr = GetLastError();
  259. CertFreeCertificateContext(pSigner);
  260. pSigner = NULL;
  261. }
  262. }
  263. if (dwVerifyErr)
  264. goto VerifySignatureError;
  265. else
  266. goto NoSignerError;
  267. SuccessReturn:
  268. fResult = TRUE;
  269. CommonReturn:
  270. ICM_Free(pSignerId);
  271. if (ppSigner)
  272. *ppSigner = pSigner;
  273. else if (pSigner)
  274. CertFreeCertificateContext(pSigner);
  275. return fResult;
  276. ErrorReturn:
  277. fResult = FALSE;
  278. goto CommonReturn;
  279. TRACE_ERROR(GetSignerError)
  280. SET_ERROR(NoSignerError, CRYPT_E_NO_TRUSTED_SIGNER)
  281. SET_ERROR_VAR(VerifySignatureError, dwVerifyErr)
  282. }
  283. #endif // CMS_PKCS7
  284. //+-------------------------------------------------------------------------
  285. // Get and verify the signer of a cryptographic message.
  286. //
  287. // If CMSG_TRUSTED_SIGNER_FLAG is set, then, treat the Signer stores as being
  288. // trusted and only search them to find the certificate corresponding to the
  289. // signer's issuer and serial number. Otherwise, the SignerStores are
  290. // optionally provided to supplement the message's store of certificates.
  291. // If a signer certificate is found, its public key is used to verify
  292. // the message signature. The CMSG_SIGNER_ONLY_FLAG can be set to
  293. // return the signer without doing the signature verify.
  294. //
  295. // If CMSG_USE_SIGNER_INDEX_FLAG is set, then, only get the signer specified
  296. // by *pdwSignerIndex. Otherwise, iterate through all the signers
  297. // until a signer verifies or no more signers.
  298. //
  299. // For a verified signature, *ppSigner is updated with certificate context
  300. // of the signer and *pdwSignerIndex is updated with the index of the signer.
  301. // ppSigner and/or pdwSignerIndex can be NULL, indicating the caller isn't
  302. // interested in getting the CertContext and/or index of the signer.
  303. //--------------------------------------------------------------------------
  304. BOOL
  305. WINAPI
  306. CryptMsgGetAndVerifySigner(
  307. IN HCRYPTMSG hCryptMsg,
  308. IN DWORD cSignerStore,
  309. IN OPTIONAL HCERTSTORE *rghSignerStore,
  310. IN DWORD dwFlags,
  311. OUT OPTIONAL PCCERT_CONTEXT *ppSigner,
  312. IN OUT OPTIONAL DWORD *pdwSignerIndex
  313. )
  314. {
  315. BOOL fResult = FALSE;
  316. DWORD dwSignerCount;
  317. DWORD dwSignerIndex;
  318. if (dwFlags & CMSG_USE_SIGNER_INDEX_FLAG) {
  319. dwSignerCount = 1;
  320. dwSignerIndex = *pdwSignerIndex;
  321. } else {
  322. DWORD cbData;
  323. dwSignerIndex = 0;
  324. if (pdwSignerIndex)
  325. *pdwSignerIndex = 0;
  326. cbData = sizeof(dwSignerCount);
  327. if (!CryptMsgGetParam(
  328. hCryptMsg,
  329. CMSG_SIGNER_COUNT_PARAM,
  330. 0, // dwIndex
  331. &dwSignerCount,
  332. &cbData) || 0 == dwSignerCount)
  333. goto NoSignerError;
  334. }
  335. // Minimum of one iteration
  336. for ( ; dwSignerCount > 0; dwSignerCount--, dwSignerIndex++) {
  337. if (fResult = ICM_GetAndVerifySigner(
  338. hCryptMsg,
  339. dwSignerIndex,
  340. cSignerStore,
  341. rghSignerStore,
  342. dwFlags,
  343. ppSigner)) {
  344. if (pdwSignerIndex && 0 == (dwFlags & CMSG_USE_SIGNER_INDEX_FLAG))
  345. *pdwSignerIndex = dwSignerIndex;
  346. break;
  347. }
  348. }
  349. CommonReturn:
  350. return fResult;
  351. ErrorReturn:
  352. if (ppSigner)
  353. *ppSigner = NULL;
  354. fResult = FALSE;
  355. goto CommonReturn;
  356. SET_ERROR(NoSignerError, CRYPT_E_NO_TRUSTED_SIGNER)
  357. }
  358. //+-------------------------------------------------------------------------
  359. // Sign an encoded CTL.
  360. //--------------------------------------------------------------------------
  361. BOOL
  362. WINAPI
  363. CryptMsgSignCTL(
  364. IN DWORD dwMsgEncodingType,
  365. IN BYTE *pbCtlContent,
  366. IN DWORD cbCtlContent,
  367. IN PCMSG_SIGNED_ENCODE_INFO pSignInfo,
  368. IN DWORD dwFlags,
  369. OUT BYTE *pbEncoded,
  370. IN OUT DWORD *pcbEncoded
  371. )
  372. {
  373. BOOL fResult;
  374. HCRYPTMSG hMsg = NULL;
  375. DWORD dwMsgFlags;
  376. #ifdef CMS_PKCS7
  377. if (dwFlags & CMSG_CMS_ENCAPSULATED_CTL_FLAG)
  378. dwMsgFlags = CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
  379. else
  380. dwMsgFlags = 0;
  381. #else
  382. dwMsgFlags = 0;
  383. #endif // CMS_PKCS7
  384. if (NULL == pbEncoded) {
  385. if (0 == (*pcbEncoded = CryptMsgCalculateEncodedLength(
  386. dwMsgEncodingType,
  387. dwMsgFlags,
  388. CMSG_SIGNED,
  389. pSignInfo,
  390. szOID_CTL,
  391. cbCtlContent))) goto CalculateEncodedLengthError;
  392. fResult = TRUE;
  393. } else {
  394. if (NULL == (hMsg = CryptMsgOpenToEncode(
  395. dwMsgEncodingType,
  396. dwMsgFlags,
  397. CMSG_SIGNED,
  398. pSignInfo,
  399. szOID_CTL,
  400. NULL // pStreamInfo
  401. ))) goto OpenToEncodeError;
  402. if (!CryptMsgUpdate(
  403. hMsg,
  404. pbCtlContent,
  405. cbCtlContent,
  406. TRUE // fFinal
  407. )) goto UpdateError;
  408. fResult = CryptMsgGetParam(
  409. hMsg,
  410. CMSG_CONTENT_PARAM,
  411. 0, // dwIndex
  412. pbEncoded,
  413. pcbEncoded);
  414. }
  415. CommonReturn:
  416. if (hMsg)
  417. CryptMsgClose(hMsg);
  418. return fResult;
  419. ErrorReturn:
  420. *pcbEncoded = 0;
  421. fResult = FALSE;
  422. goto CommonReturn;
  423. TRACE_ERROR(CalculateEncodedLengthError)
  424. TRACE_ERROR(OpenToEncodeError)
  425. TRACE_ERROR(UpdateError)
  426. }
  427. //+-------------------------------------------------------------------------
  428. // Encode the CTL and create a signed message containing the encoded CTL.
  429. //--------------------------------------------------------------------------
  430. BOOL
  431. WINAPI
  432. CryptMsgEncodeAndSignCTL(
  433. IN DWORD dwMsgEncodingType,
  434. IN PCTL_INFO pCtlInfo,
  435. IN PCMSG_SIGNED_ENCODE_INFO pSignInfo,
  436. IN DWORD dwFlags,
  437. OUT BYTE *pbEncoded,
  438. IN OUT DWORD *pcbEncoded
  439. )
  440. {
  441. BOOL fResult;
  442. BYTE *pbContent = NULL;
  443. DWORD cbContent;
  444. DWORD dwEncodingType;
  445. LPCSTR lpszStructType;
  446. DWORD dwEncodeFlags;
  447. dwEncodingType = (dwMsgEncodingType >> 16) & CERT_ENCODING_TYPE_MASK;
  448. assert(dwEncodingType != 0);
  449. if (0 == dwEncodingType)
  450. goto InvalidArg;
  451. dwEncodeFlags = CRYPT_ENCODE_ALLOC_FLAG;
  452. if (dwFlags & CMSG_ENCODE_SORTED_CTL_FLAG) {
  453. lpszStructType = PKCS_SORTED_CTL;
  454. if (dwFlags & CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG)
  455. dwEncodeFlags |=
  456. CRYPT_SORTED_CTL_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG;
  457. } else {
  458. lpszStructType = PKCS_CTL;
  459. }
  460. if (!CryptEncodeObjectEx(
  461. dwEncodingType,
  462. lpszStructType,
  463. pCtlInfo,
  464. dwEncodeFlags,
  465. &PkiEncodePara,
  466. (void *) &pbContent,
  467. &cbContent
  468. )) goto EncodeError;
  469. fResult = CryptMsgSignCTL(
  470. dwMsgEncodingType,
  471. pbContent,
  472. cbContent,
  473. pSignInfo,
  474. dwFlags,
  475. pbEncoded,
  476. pcbEncoded
  477. );
  478. CommonReturn:
  479. PkiFree(pbContent);
  480. return fResult;
  481. ErrorReturn:
  482. *pcbEncoded = 0;
  483. fResult = FALSE;
  484. goto CommonReturn;
  485. SET_ERROR(InvalidArg, E_INVALIDARG)
  486. TRACE_ERROR(EncodeError)
  487. }