Leaked source code of windows server 2003
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.

724 lines
22 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000 - 2001.
  3. File: SignHlpr.cpp
  4. Content: Helper functions for signing.
  5. History: 11-15-99 dsie created
  6. ------------------------------------------------------------------------------*/
  7. #include "StdAfx.h"
  8. #include "CAPICOM.h"
  9. #include "SignHlpr.h"
  10. #include "Common.h"
  11. #include "CertHlpr.h"
  12. #include "Certificate.h"
  13. #include "Signer2.h"
  14. ////////////////////////////////////////////////////////////////////////////////
  15. //
  16. // Local functions.
  17. //
  18. ////////////////////////////////////////////////////////////////////////////////
  19. //
  20. // Exported functions.
  21. //
  22. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  23. Function : FreeAttributes
  24. Synopsis : Free elements of an attribute array.
  25. Parameter: DWORD cAttr - Number fo attributes
  26. PCRYPT_ATTRIBUTE rgAuthAttr - Pointer to CRYPT_ATTRIBUTE array.
  27. Remark :
  28. ------------------------------------------------------------------------------*/
  29. void FreeAttributes (DWORD cAttr,
  30. PCRYPT_ATTRIBUTE rgAttr)
  31. {
  32. DebugTrace("Entering FreeAttributes().\n");
  33. //
  34. // Free each element of the array.
  35. //
  36. for (DWORD i = 0; i < cAttr; i++)
  37. {
  38. //
  39. // Make sure pointer is valid.
  40. //
  41. if (rgAttr[i].rgValue)
  42. {
  43. for (DWORD j = 0; j < rgAttr[i].cValue; j++)
  44. {
  45. if (rgAttr[i].rgValue[j].pbData)
  46. {
  47. ::CoTaskMemFree((LPVOID) rgAttr[i].rgValue[j].pbData);
  48. }
  49. }
  50. ::CoTaskMemFree((LPVOID) rgAttr[i].rgValue);
  51. }
  52. }
  53. DebugTrace("Leaving FreeAttributes().\n");
  54. return;
  55. }
  56. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  57. Function : FreeAttributes
  58. Synopsis : Free memory allocated for all attributes.
  59. Parameter: PCRYPT_ATTRIBUTES pAttributes
  60. Remark :
  61. ------------------------------------------------------------------------------*/
  62. void FreeAttributes (PCRYPT_ATTRIBUTES pAttributes)
  63. {
  64. //
  65. // Sanity check.
  66. //
  67. ATLASSERT(pAttributes);
  68. //
  69. // Do we have any attribute?
  70. //
  71. if (pAttributes->rgAttr)
  72. {
  73. //
  74. // First free elements of array.
  75. //
  76. FreeAttributes(pAttributes->cAttr, pAttributes->rgAttr);
  77. //
  78. // Then free the array itself.
  79. //
  80. ::CoTaskMemFree((LPVOID) pAttributes->rgAttr);
  81. }
  82. ::ZeroMemory(pAttributes, sizeof(CRYPT_ATTRIBUTES));
  83. return;
  84. }
  85. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  86. Function : GetAuthenticatedAttributes
  87. Synopsis : Encode and return authenticated attributes of the specified signer.
  88. Parameter: ISigner * pISigner - Pointer to ISigner.
  89. PCRYPT_ATTRIBUTES pAttributes
  90. Remark :
  91. ------------------------------------------------------------------------------*/
  92. HRESULT GetAuthenticatedAttributes (ISigner * pISigner,
  93. PCRYPT_ATTRIBUTES pAttributes)
  94. {
  95. HRESULT hr = S_OK;
  96. long cAttr = 0;
  97. PCRYPT_ATTRIBUTE rgAttr = NULL;
  98. CComPtr<IAttributes> pIAttributes = NULL;
  99. DebugTrace("Entering GetAuthenticatedAttributes().\n");
  100. //
  101. // Sanity check.
  102. //
  103. ATLASSERT(pISigner);
  104. ATLASSERT(pAttributes);
  105. //
  106. // Initialize.
  107. //
  108. ::ZeroMemory(pAttributes, sizeof(CRYPT_ATTRIBUTES));
  109. //
  110. // Get authenticated attributes.
  111. //
  112. if (FAILED(hr = pISigner->get_AuthenticatedAttributes(&pIAttributes)))
  113. {
  114. DebugTrace("Error [%#x]: pISigner->get_AuthenticatedAttributes() failed.\n", hr);
  115. goto ErrorExit;
  116. }
  117. //
  118. // Get count of attributes.
  119. //
  120. if (FAILED(hr = pIAttributes->get_Count(&cAttr)))
  121. {
  122. DebugTrace("Error [%#x]: pIAttributes->get_Count() failed.\n", hr);
  123. goto ErrorExit;
  124. }
  125. if (0 < cAttr)
  126. {
  127. //
  128. // Allocate memory for attribute array.
  129. //
  130. if (!(rgAttr = (PCRYPT_ATTRIBUTE) ::CoTaskMemAlloc(sizeof(CRYPT_ATTRIBUTE) * cAttr)))
  131. {
  132. hr = E_OUTOFMEMORY;
  133. DebugTrace("Error: out of memory.\n");
  134. goto ErrorExit;
  135. }
  136. ::ZeroMemory(rgAttr, sizeof(CRYPT_ATTRIBUTE) * cAttr);
  137. //
  138. // Loop thru each attribute and add to the array.
  139. //
  140. for (long i = 0; i < cAttr; i++)
  141. {
  142. CAPICOM_ATTRIBUTE AttrName;
  143. CComVariant varValue;
  144. CComVariant varIAttribute;
  145. CComPtr<IAttribute> pIAttribute = NULL;
  146. //
  147. // Get next attribute.
  148. //
  149. if (FAILED(hr = pIAttributes->get_Item(i + 1, &varIAttribute)))
  150. {
  151. DebugTrace("Error [%#x]: pIAttributes->get_Item() failed.\n", hr);
  152. goto ErrorExit;
  153. }
  154. //
  155. // Get custom interface.
  156. //
  157. if (FAILED(hr = varIAttribute.pdispVal->QueryInterface(IID_IAttribute,
  158. (void **) &pIAttribute)))
  159. {
  160. DebugTrace("Error [%#x]: varIAttribute.pdispVal->QueryInterface() failed.\n", hr);
  161. goto ErrorExit;
  162. }
  163. //
  164. // Get attribute name.
  165. //
  166. if (FAILED(hr = pIAttribute->get_Name(&AttrName)))
  167. {
  168. DebugTrace("Error [%#x]: pIAttribute->get_Name() failed.\n", hr);
  169. goto ErrorExit;
  170. }
  171. //
  172. // Get attribute value.
  173. //
  174. if (FAILED(hr = pIAttribute->get_Value(&varValue)))
  175. {
  176. DebugTrace("Error [%#x]: pIAttribute->get_Value() failed.\n", hr);
  177. goto ErrorExit;
  178. }
  179. switch (AttrName)
  180. {
  181. case CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME:
  182. {
  183. FILETIME ft;
  184. SYSTEMTIME st;
  185. //
  186. // Conver to FILETIME.
  187. //
  188. if (!::VariantTimeToSystemTime(varValue.date, &st))
  189. {
  190. hr = CAPICOM_E_ATTRIBUTE_INVALID_VALUE;
  191. DebugTrace("Error [%#x]: VariantTimeToSystemTime() failed.\n");
  192. goto ErrorExit;
  193. }
  194. if (!::SystemTimeToFileTime(&st, &ft))
  195. {
  196. hr = CAPICOM_E_ATTRIBUTE_INVALID_VALUE;
  197. DebugTrace("Error [%#x]: VariantTimeToSystemTime() failed.\n");
  198. goto ErrorExit;
  199. }
  200. //
  201. // Now encode it.
  202. //
  203. rgAttr[i].cValue = 1;
  204. rgAttr[i].pszObjId = szOID_RSA_signingTime;
  205. if (!(rgAttr[i].rgValue = (CRYPT_ATTR_BLOB *) ::CoTaskMemAlloc(sizeof(CRYPT_ATTR_BLOB))))
  206. {
  207. hr = E_OUTOFMEMORY;
  208. DebugTrace("Error: out of memory.\n");
  209. goto ErrorExit;
  210. }
  211. if (FAILED(hr = ::EncodeObject((LPSTR) szOID_RSA_signingTime,
  212. (LPVOID) &ft,
  213. rgAttr[i].rgValue)))
  214. {
  215. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  216. goto ErrorExit;
  217. }
  218. break;
  219. }
  220. case CAPICOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_NAME:
  221. {
  222. CRYPT_DATA_BLOB NameBlob = {0, NULL};
  223. NameBlob.cbData = ::SysStringByteLen(varValue.bstrVal);
  224. NameBlob.pbData = (PBYTE) varValue.bstrVal;
  225. rgAttr[i].cValue = 1;
  226. rgAttr[i].pszObjId = szOID_CAPICOM_DOCUMENT_NAME;
  227. if (!(rgAttr[i].rgValue = (CRYPT_ATTR_BLOB *) ::CoTaskMemAlloc(sizeof(CRYPT_ATTR_BLOB))))
  228. {
  229. hr = E_OUTOFMEMORY;
  230. DebugTrace("Error: out of memory.\n");
  231. goto ErrorExit;
  232. }
  233. if (FAILED(hr = ::EncodeObject((LPSTR) X509_OCTET_STRING,
  234. (LPVOID) &NameBlob,
  235. rgAttr[i].rgValue)))
  236. {
  237. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  238. goto ErrorExit;
  239. }
  240. break;
  241. }
  242. case CAPICOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_DESCRIPTION:
  243. {
  244. CRYPT_DATA_BLOB DescBlob = {0, NULL};
  245. DescBlob.cbData = ::SysStringByteLen(varValue.bstrVal);
  246. DescBlob.pbData = (PBYTE) varValue.bstrVal;
  247. rgAttr[i].cValue = 1;
  248. rgAttr[i].pszObjId = szOID_CAPICOM_DOCUMENT_DESCRIPTION;
  249. if (!(rgAttr[i].rgValue = (CRYPT_ATTR_BLOB *) ::CoTaskMemAlloc(sizeof(CRYPT_ATTR_BLOB))))
  250. {
  251. hr = E_OUTOFMEMORY;
  252. DebugTrace("Error: out of memory.\n");
  253. goto ErrorExit;
  254. }
  255. if (FAILED(hr = ::EncodeObject((LPSTR) X509_OCTET_STRING,
  256. (LPVOID) &DescBlob,
  257. rgAttr[i].rgValue)))
  258. {
  259. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  260. goto ErrorExit;
  261. }
  262. break;
  263. }
  264. default:
  265. {
  266. hr = CAPICOM_E_ATTRIBUTE_INVALID_NAME;
  267. DebugTrace("Error [%#x]: unknown attribute name.\n", hr);
  268. goto ErrorExit;
  269. }
  270. }
  271. }
  272. //
  273. // Return attributes to caller.
  274. //
  275. pAttributes->cAttr = cAttr;
  276. pAttributes->rgAttr = rgAttr;
  277. }
  278. CommonExit:
  279. DebugTrace("Leaving GetAuthenticatedAttributes().\n");
  280. return hr;
  281. ErrorExit:
  282. //
  283. // Sanity check.
  284. //
  285. ATLASSERT(FAILED(hr));
  286. //
  287. // Free resources.
  288. //
  289. if (rgAttr)
  290. {
  291. ::FreeAttributes(cAttr, rgAttr);
  292. ::CoTaskMemFree(rgAttr);
  293. }
  294. goto CommonExit;
  295. }
  296. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  297. Function : IsValidForSigning
  298. Synopsis : Verify if the certificate is valid for signing.
  299. Parameter: PCCERT_CONTEXT pCertContext - CERT_CONTEXT of cert to verify.
  300. LPCSTR pszPolicy - Policy used to verify the cert (i.e.
  301. CERT_CHAIN_POLICY_BASE).
  302. Remark :
  303. ------------------------------------------------------------------------------*/
  304. HRESULT IsValidForSigning (PCCERT_CONTEXT pCertContext, LPCSTR pszPolicy)
  305. {
  306. HRESULT hr = S_OK;
  307. DWORD cb = 0;
  308. int nValidity = 0;
  309. DebugTrace("Entering IsValidForSigning().\n");
  310. //
  311. // Sanity check.
  312. //
  313. ATLASSERT(pCertContext);
  314. //
  315. // Make sure we have a private key.
  316. //
  317. if (!::CertGetCertificateContextProperty(pCertContext,
  318. CERT_KEY_PROV_INFO_PROP_ID,
  319. NULL,
  320. &cb))
  321. {
  322. hr = CAPICOM_E_CERTIFICATE_NO_PRIVATE_KEY;
  323. DebugTrace("Error: signer's private key is not available.\n");
  324. goto ErrorExit;
  325. }
  326. //
  327. // Check cert time validity.
  328. //
  329. if (0 != (nValidity = ::CertVerifyTimeValidity(NULL, pCertContext->pCertInfo)))
  330. {
  331. hr = HRESULT_FROM_WIN32(CERT_E_EXPIRED);
  332. DebugTrace("Info: SelectSignerCertCallback() - invalid time (%s).\n",
  333. nValidity < 0 ? "not yet valid" : "expired");
  334. goto ErrorExit;
  335. }
  336. #if (0) //DSIE: Flip this if we decide to build chain here.
  337. //
  338. // Make sure the cert is valid.
  339. //
  340. if (FAILED(hr = ::VerifyCertificate(pCertContext, NULL, pszPolicy)))
  341. {
  342. DebugTrace("Error [%#x]: VerifyCertificate() failed.\n", hr);
  343. goto ErrorExit;
  344. }
  345. #endif
  346. CommonExit:
  347. DebugTrace("Leaving IsValidForSigning().\n");
  348. return hr;
  349. ErrorExit:
  350. //
  351. // Sanity check.
  352. //
  353. ATLASSERT(FAILED(hr));
  354. goto CommonExit;
  355. }
  356. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  357. Function : GetSignerCert
  358. Synopsis : Retrieve signer's cert from ISigner object. If signer's cert is
  359. not available in the ISigner object, pop UI to prompt user to
  360. select a signing cert.
  361. Parameter: ISigner2 * pISigner2 - Pointer to ISigner2 or NULL.
  362. LPCSTR pszPolicy - Policy used to verify the cert (i.e.
  363. CERT_CHAIN_POLICY_BASE).
  364. CAPICOM_STORE_INFO StoreInfo - Store to select from.
  365. PFNCFILTERPROC pfnFilterCallback - Pointer to filter callback
  366. function.
  367. ISigner2 ** ppISigner2 - Pointer to pointer to ISigner2 to receive
  368. interface pointer.
  369. ICertificate ** ppICertificate - Pointer to pointer to ICertificate
  370. to receive interface pointer.
  371. PCCERT_CONTEXT * ppCertContext - Pointer to pointer to CERT_CONTEXT
  372. to receive cert context.
  373. Remark :
  374. ------------------------------------------------------------------------------*/
  375. HRESULT GetSignerCert (ISigner2 * pISigner2,
  376. LPCSTR pszPolicy,
  377. CAPICOM_STORE_INFO StoreInfo,
  378. PFNCFILTERPROC pfnFilterCallback,
  379. ISigner2 ** ppISigner2,
  380. ICertificate ** ppICertificate,
  381. PCCERT_CONTEXT * ppCertContext)
  382. {
  383. HRESULT hr = S_OK;
  384. BOOL bVerified = FALSE;
  385. CComPtr<ISigner2> pISelectedSigner2 = NULL;
  386. CComPtr<ICertificate> pISelectedCertificate = NULL;
  387. CComPtr<ICertificate2> pISelectedCertificate2 = NULL;
  388. PCCERT_CONTEXT pSelectedCertContext = NULL;
  389. DebugTrace("Entering GetSignerCert().\n");
  390. try
  391. {
  392. //
  393. // Initialize.
  394. //
  395. if (ppISigner2)
  396. {
  397. *ppISigner2 = NULL;
  398. }
  399. if (ppICertificate)
  400. {
  401. *ppICertificate = NULL;
  402. }
  403. if (ppCertContext)
  404. {
  405. *ppCertContext = NULL;
  406. }
  407. //
  408. // Did user pass us a signer?
  409. //
  410. if (pISigner2)
  411. {
  412. //
  413. // Retrieve the signer's cert.
  414. //
  415. if (FAILED(hr = pISigner2->get_Certificate((ICertificate **) &pISelectedCertificate)))
  416. {
  417. //
  418. // If signer's cert is not present, pop UI.
  419. //
  420. if (CAPICOM_E_SIGNER_NOT_INITIALIZED == hr)
  421. {
  422. //
  423. // Prompt user to select a certificate.
  424. //
  425. if (FAILED(hr = ::SelectCertificate(StoreInfo,
  426. pfnFilterCallback,
  427. &pISelectedCertificate2)))
  428. {
  429. DebugTrace("Error [%#x]: SelectCertificate() failed.\n", hr);
  430. goto ErrorExit;
  431. }
  432. //
  433. // QI for ICertificate.
  434. //
  435. if (FAILED(hr = pISelectedCertificate2->QueryInterface(&pISelectedCertificate)))
  436. {
  437. DebugTrace("Internal error [%#x]: pISelectedCertificate2->QueryInterface() failed.\n", hr);
  438. goto ErrorExit;
  439. }
  440. bVerified = TRUE;
  441. }
  442. else
  443. {
  444. DebugTrace("Error [%#x]: pISigner2->get_Certificate() failed.\n", hr);
  445. goto ErrorExit;
  446. }
  447. }
  448. //
  449. // Get cert context.
  450. //
  451. if (FAILED(hr = ::GetCertContext(pISelectedCertificate, &pSelectedCertContext)))
  452. {
  453. DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
  454. goto ErrorExit;
  455. }
  456. //
  457. // Verify cert, if not already done so.
  458. //
  459. if (!bVerified)
  460. {
  461. if (pfnFilterCallback && !pfnFilterCallback(pSelectedCertContext, NULL, NULL))
  462. {
  463. hr = CAPICOM_E_SIGNER_INVALID_USAGE;
  464. DebugTrace("Error [%#x]: Signing certificate is invalid.\n", hr);
  465. goto ErrorExit;
  466. }
  467. }
  468. //
  469. // QI for ISigner2.
  470. //
  471. if (FAILED(hr = pISigner2->QueryInterface(&pISelectedSigner2)))
  472. {
  473. DebugTrace("Unexpected error [%#x]: pISigner2->QueryInterface() failed.\n", hr);
  474. goto ErrorExit;
  475. }
  476. }
  477. else
  478. {
  479. CRYPT_ATTRIBUTES attributes = {0, NULL};
  480. //
  481. // No signer specified, so prompt user to select a certificate.
  482. //
  483. if (FAILED(hr = ::SelectCertificate(StoreInfo, pfnFilterCallback, &pISelectedCertificate2)))
  484. {
  485. DebugTrace("Error [%#x]: SelectCertificate() failed.\n", hr);
  486. goto ErrorExit;
  487. }
  488. //
  489. // QI for ICertificate.
  490. //
  491. if (FAILED(hr = pISelectedCertificate2->QueryInterface(&pISelectedCertificate)))
  492. {
  493. DebugTrace("Internal error [%#x]: pISelectedCertificate2->QueryInterface() failed.\n", hr);
  494. goto ErrorExit;
  495. }
  496. //
  497. // Get cert context.
  498. //
  499. if (FAILED(hr = ::GetCertContext(pISelectedCertificate, &pSelectedCertContext)))
  500. {
  501. DebugTrace("Error [%#x]: GetCertContext() failed.\n", hr);
  502. goto ErrorExit;
  503. }
  504. //
  505. // Create the ISigner2 object.
  506. //
  507. if (FAILED(hr = ::CreateSignerObject(pSelectedCertContext,
  508. &attributes,
  509. NULL,
  510. INTERFACESAFE_FOR_UNTRUSTED_CALLER |
  511. INTERFACESAFE_FOR_UNTRUSTED_DATA,
  512. &pISelectedSigner2)))
  513. {
  514. DebugTrace("Error [%#x]: CreateSignerObject() failed.\n", hr);
  515. goto ErrorExit;
  516. }
  517. }
  518. //
  519. // Make sure cert is valid for signing.
  520. //
  521. if (FAILED(hr = ::IsValidForSigning(pSelectedCertContext, pszPolicy)))
  522. {
  523. DebugTrace("Error [%#x]: IsValidForSigning() failed.\n", hr);
  524. goto ErrorExit;
  525. }
  526. //
  527. // Return values to caller.
  528. //
  529. if (ppISigner2)
  530. {
  531. if (FAILED(hr = pISelectedSigner2->QueryInterface(ppISigner2)))
  532. {
  533. DebugTrace("Unexpected error [%#x]: pISelectedSigner2->QueryInterface() failed.\n", hr);
  534. goto ErrorExit;
  535. }
  536. }
  537. if (ppICertificate)
  538. {
  539. if (FAILED(hr = pISelectedCertificate->QueryInterface(ppICertificate)))
  540. {
  541. DebugTrace("Unexpected error [%#x]: pISelectedCertificate->QueryInterface() failed.\n", hr);
  542. goto ErrorExit;
  543. }
  544. }
  545. if (ppCertContext)
  546. {
  547. *ppCertContext = pSelectedCertContext;
  548. }
  549. }
  550. catch(...)
  551. {
  552. hr = E_POINTER;
  553. DebugTrace("Exception: invalid parameter.\n");
  554. goto ErrorExit;
  555. }
  556. CommonExit:
  557. DebugTrace("Leaving GetSignerCert().\n");
  558. return hr;
  559. ErrorExit:
  560. //
  561. // Sanity check.
  562. //
  563. ATLASSERT(FAILED(hr));
  564. //
  565. // Free resource.
  566. //
  567. if (pSelectedCertContext)
  568. {
  569. ::CertFreeCertificateContext(pSelectedCertContext);
  570. }
  571. if (ppICertificate && *ppICertificate)
  572. {
  573. (*ppICertificate)->Release();
  574. *ppICertificate = NULL;
  575. }
  576. if (ppISigner2 && *ppISigner2)
  577. {
  578. (*ppISigner2)->Release();
  579. *ppISigner2 = NULL;
  580. }
  581. goto CommonExit;
  582. }