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.

1078 lines
32 KiB

  1. // IISCertRequest.cpp : Implementation of CIISCertRequest
  2. #include "stdafx.h"
  3. #include "common.h"
  4. #include "CertObj.h"
  5. #include "IISCertRequest.h"
  6. #include "base64.h"
  7. #include "certca.h"
  8. #include "certcli.h"
  9. #include "certutil.h"
  10. #include <strsafe.h>
  11. #ifdef USE_CERT_REQUEST_OBJECT
  12. const CLSID CLSID_CEnroll =
  13. {0x43F8F289, 0x7A20, 0x11D0, {0x8F, 0x06, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xE1}};
  14. const IID IID_IEnroll =
  15. {0xacaa7838, 0x4585, 0x11d1, {0xab, 0x57, 0x00, 0xc0, 0x4f, 0xc2, 0x95, 0xe1}};
  16. const IID IID_ICEnroll2 =
  17. {0x704ca730, 0xc90b, 0x11d1, {0x9b, 0xec, 0x00, 0xc0, 0x4f, 0xc2, 0x95, 0xe1}};
  18. const CLSID CLSID_CCertRequest =
  19. {0x98aff3f0, 0x5524, 0x11d0, {0x88, 0x12, 0x00, 0xa0, 0xc9, 0x03, 0xb8, 0x3c}};
  20. const IID IID_ICertRequest =
  21. {0x014e4840, 0x5523, 0x11d0, {0x88, 0x12, 0x00, 0xa0, 0xc9, 0x03, 0xb8, 0x3c}};
  22. // defines taken from the old KeyGen utility
  23. #define MESSAGE_HEADER _T("-----BEGIN NEW CERTIFICATE REQUEST-----\r\n")
  24. #define MESSAGE_TRAILER _T("-----END NEW CERTIFICATE REQUEST-----\r\n")
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CIISCertRequest
  27. CIISCertRequest::CIISCertRequest()
  28. {
  29. m_ServerName = _T("");
  30. m_UserName = _T("");
  31. m_UserPassword = _T("");
  32. m_InstanceName = _T("");
  33. m_Info_CommonName = _T("");
  34. m_Info_FriendlyName = _T("");
  35. m_Info_Country = _T("");
  36. m_Info_State = _T("");
  37. m_Info_Locality = _T("");
  38. m_Info_Organization = _T("");
  39. m_Info_OrganizationUnit = _T("");
  40. m_Info_CAName = _T("");
  41. m_Info_ExpirationDate = _T("");
  42. m_Info_Usage = _T("");
  43. m_Info_AltSubject = _T("");
  44. // other
  45. m_Info_ConfigCA = _T("");
  46. m_Info_CertificateTemplate = wszCERTTYPE_WEBSERVER;
  47. m_Info_DefaultProviderType = PROV_RSA_SCHANNEL;
  48. m_Info_CustomProviderType = PROV_RSA_SCHANNEL;
  49. m_Info_DefaultCSP = TRUE;
  50. m_Info_CspName = _T("");
  51. m_KeyLength = 512;
  52. m_SGCcertificat = FALSE;
  53. m_pEnroll = NULL;
  54. return;
  55. }
  56. CIISCertRequest::~CIISCertRequest()
  57. {
  58. return;
  59. }
  60. IIISCertRequest * CIISCertRequest::GetObject(HRESULT * phr)
  61. {
  62. IIISCertRequest * pObj = NULL;
  63. pObj = GetObject(phr,m_ServerName,m_UserName,m_UserPassword);
  64. return pObj;
  65. }
  66. IIISCertRequest * CIISCertRequest::GetObject(HRESULT * phr,CString csServerName,CString csUserName,CString csUserPassword)
  67. {
  68. if (csServerName.IsEmpty())
  69. {
  70. // object is null, but it's the local machine, so just return back this pointer
  71. m_pObj = this;
  72. goto GetObject_Exit;
  73. }
  74. // There is a servername specified...
  75. // check if it's the local machine that was specified!
  76. if (IsServerLocal(csServerName))
  77. {
  78. m_pObj = this;
  79. goto GetObject_Exit;
  80. }
  81. else
  82. {
  83. // there is a remote servername specified
  84. // let's see if the machine has the com object that we want....
  85. // we are using the user/name password that are in this object
  86. // so were probably on the local machine
  87. CComAuthInfo auth(csServerName,csUserName,csUserPassword);
  88. // RPC_C_AUTHN_LEVEL_DEFAULT 0
  89. // RPC_C_AUTHN_LEVEL_NONE 1
  90. // RPC_C_AUTHN_LEVEL_CONNECT 2
  91. // RPC_C_AUTHN_LEVEL_CALL 3
  92. // RPC_C_AUTHN_LEVEL_PKT 4
  93. // RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
  94. // RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6
  95. COSERVERINFO * pcsiName = auth.CreateServerInfoStruct(RPC_C_AUTHN_LEVEL_PKT_PRIVACY);
  96. MULTI_QI res[1] =
  97. {
  98. {&__uuidof(IIISCertRequest), NULL, 0}
  99. };
  100. // this one seems to work with surrogates..
  101. *phr = CoCreateInstanceEx(CLSID_IISCertRequest,NULL,CLSCTX_LOCAL_SERVER,pcsiName,1,res);
  102. if (FAILED(*phr))
  103. {
  104. IISDebugOutput(_T("CIISCertRequest::GetObject:CoCreateInstanceEx failed:0x%x, csServerName=%s,csUserName=%s\n"),*phr,(LPCTSTR) csServerName,(LPCTSTR) csUserName);
  105. goto GetObject_Exit;
  106. }
  107. // at this point we were able to instantiate the com object on the server (local or remote)
  108. m_pObj = (IIISCertRequest *)res[0].pItf;
  109. if (auth.UsesImpersonation())
  110. {
  111. *phr = auth.ApplyProxyBlanket(m_pObj);
  112. // There is a remote IUnknown interface that lurks behind IUnknown.
  113. // If that is not set, then the Release call can return access denied.
  114. IUnknown * pUnk = NULL;
  115. if(FAILED(m_pObj->QueryInterface(IID_IUnknown, (void **)&pUnk)))
  116. {
  117. goto GetObject_Exit;
  118. }
  119. if (FAILED(auth.ApplyProxyBlanket(pUnk)))
  120. {
  121. goto GetObject_Exit;
  122. }
  123. pUnk->Release();pUnk = NULL;
  124. }
  125. auth.FreeServerInfoStruct(pcsiName);
  126. }
  127. GetObject_Exit:
  128. //ASSERT(m_pObj != NULL);
  129. return m_pObj;
  130. }
  131. STDMETHODIMP CIISCertRequest::put_ServerName(BSTR newVal)
  132. {
  133. // buffer overflow paranoia, make sure it's less than 255 characters long
  134. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  135. m_ServerName = newVal;
  136. return S_OK;
  137. }
  138. STDMETHODIMP CIISCertRequest::put_UserName(BSTR newVal)
  139. {
  140. // buffer overflow paranoia, make sure it's less than 255 characters long
  141. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  142. m_UserName = newVal;
  143. return S_OK;
  144. }
  145. STDMETHODIMP CIISCertRequest::put_UserPassword(BSTR newVal)
  146. {
  147. // buffer overflow paranoia, make sure it's less than 255 characters long
  148. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  149. m_UserPassword = newVal;
  150. return S_OK;
  151. }
  152. STDMETHODIMP CIISCertRequest::put_InstanceName(BSTR newVal)
  153. {
  154. // buffer overflow paranoia, make sure it's less than 255 characters long
  155. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  156. m_InstanceName = newVal;
  157. return S_OK;
  158. }
  159. STDMETHODIMP CIISCertRequest::get_Info_CommonName(BSTR *pVal)
  160. {
  161. _bstr_t bstrTempName = (LPCTSTR) m_Info_CommonName;
  162. *pVal = bstrTempName.copy();
  163. return S_OK;
  164. }
  165. STDMETHODIMP CIISCertRequest::put_Info_CommonName(BSTR newVal)
  166. {
  167. // buffer overflow paranoia, make sure it's less than 255 characters long
  168. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  169. m_Info_CommonName = newVal;
  170. return S_OK;
  171. }
  172. STDMETHODIMP CIISCertRequest::get_Info_FriendlyName(BSTR *pVal)
  173. {
  174. _bstr_t bstrTempName = (LPCTSTR) m_Info_FriendlyName;
  175. *pVal = bstrTempName.copy();
  176. return S_OK;
  177. }
  178. STDMETHODIMP CIISCertRequest::put_Info_FriendlyName(BSTR newVal)
  179. {
  180. // buffer overflow paranoia, make sure it's less than 255 characters long
  181. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  182. m_Info_FriendlyName = newVal;
  183. return S_OK;
  184. }
  185. STDMETHODIMP CIISCertRequest::get_Info_Country(BSTR *pVal)
  186. {
  187. _bstr_t bstrTempName = (LPCTSTR) m_Info_Country;
  188. *pVal = bstrTempName.copy();
  189. return S_OK;
  190. }
  191. STDMETHODIMP CIISCertRequest::put_Info_Country(BSTR newVal)
  192. {
  193. // buffer overflow paranoia, make sure it's less than 255 characters long
  194. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  195. m_Info_Country = newVal;
  196. return S_OK;
  197. }
  198. STDMETHODIMP CIISCertRequest::get_Info_State(BSTR *pVal)
  199. {
  200. _bstr_t bstrTempName = (LPCTSTR) m_Info_State;
  201. *pVal = bstrTempName.copy();
  202. return S_OK;
  203. }
  204. STDMETHODIMP CIISCertRequest::put_Info_State(BSTR newVal)
  205. {
  206. // buffer overflow paranoia, make sure it's less than 255 characters long
  207. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  208. m_Info_State = newVal;
  209. return S_OK;
  210. }
  211. STDMETHODIMP CIISCertRequest::get_Info_Locality(BSTR *pVal)
  212. {
  213. _bstr_t bstrTempName = (LPCTSTR) m_Info_Locality;
  214. *pVal = bstrTempName.copy();
  215. return S_OK;
  216. }
  217. STDMETHODIMP CIISCertRequest::put_Info_Locality(BSTR newVal)
  218. {
  219. // buffer overflow paranoia, make sure it's less than 255 characters long
  220. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  221. m_Info_Locality = newVal;
  222. return S_OK;
  223. }
  224. STDMETHODIMP CIISCertRequest::get_Info_Organization(BSTR *pVal)
  225. {
  226. _bstr_t bstrTempName = (LPCTSTR) m_Info_Organization;
  227. *pVal = bstrTempName.copy();
  228. return S_OK;
  229. }
  230. STDMETHODIMP CIISCertRequest::put_Info_Organization(BSTR newVal)
  231. {
  232. // buffer overflow paranoia, make sure it's less than 255 characters long
  233. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  234. m_Info_Organization = newVal;
  235. return S_OK;
  236. }
  237. STDMETHODIMP CIISCertRequest::get_Info_OrganizationUnit(BSTR *pVal)
  238. {
  239. _bstr_t bstrTempName = (LPCTSTR) m_Info_OrganizationUnit;
  240. *pVal = bstrTempName.copy();
  241. return S_OK;
  242. }
  243. STDMETHODIMP CIISCertRequest::put_Info_OrganizationUnit(BSTR newVal)
  244. {
  245. // buffer overflow paranoia, make sure it's less than 255 characters long
  246. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  247. m_Info_OrganizationUnit = newVal;
  248. return S_OK;
  249. }
  250. STDMETHODIMP CIISCertRequest::get_Info_CAName(BSTR *pVal)
  251. {
  252. _bstr_t bstrTempName = (LPCTSTR) m_Info_CAName;
  253. *pVal = bstrTempName.copy();
  254. return S_OK;
  255. }
  256. STDMETHODIMP CIISCertRequest::put_Info_CAName(BSTR newVal)
  257. {
  258. // buffer overflow paranoia, make sure it's less than 255 characters long
  259. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  260. m_Info_CAName = newVal;
  261. return S_OK;
  262. }
  263. STDMETHODIMP CIISCertRequest::get_Info_ExpirationDate(BSTR *pVal)
  264. {
  265. _bstr_t bstrTempName = (LPCTSTR) m_Info_ExpirationDate;
  266. *pVal = bstrTempName.copy();
  267. return S_OK;
  268. }
  269. STDMETHODIMP CIISCertRequest::put_Info_ExpirationDate(BSTR newVal)
  270. {
  271. // buffer overflow paranoia, make sure it's less than 255 characters long
  272. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  273. m_Info_ExpirationDate = newVal;
  274. return S_OK;
  275. }
  276. STDMETHODIMP CIISCertRequest::get_Info_Usage(BSTR *pVal)
  277. {
  278. _bstr_t bstrTempName = (LPCTSTR) m_Info_Usage;
  279. *pVal = bstrTempName.copy();
  280. return S_OK;
  281. }
  282. STDMETHODIMP CIISCertRequest::put_Info_Usage(BSTR newVal)
  283. {
  284. // buffer overflow paranoia, make sure it's less than 255 characters long
  285. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  286. m_Info_Usage = newVal;
  287. return S_OK;
  288. }
  289. STDMETHODIMP CIISCertRequest::get_Info_AltSubject(BSTR *pVal)
  290. {
  291. _bstr_t bstrTempName = (LPCTSTR) m_Info_AltSubject;
  292. *pVal = bstrTempName.copy();
  293. return S_OK;
  294. }
  295. STDMETHODIMP CIISCertRequest::put_Info_AltSubject(BSTR newVal)
  296. {
  297. // buffer overflow paranoia, make sure it's less than 255 characters long
  298. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  299. m_Info_Usage = newVal;
  300. return S_OK;
  301. }
  302. STDMETHODIMP CIISCertRequest::get_DispositionMessage(BSTR *pVal)
  303. {
  304. _bstr_t bstrTempName = (LPCTSTR) m_DispositionMessage;
  305. *pVal = bstrTempName.copy();
  306. return S_OK;
  307. }
  308. STDMETHODIMP CIISCertRequest::put_DispositionMessage(BSTR newVal)
  309. {
  310. // buffer overflow paranoia, make sure it's less than 255 characters long
  311. if (wcslen(newVal) > _MAX_PATH){return RPC_S_STRING_TOO_LONG;}
  312. m_DispositionMessage = newVal;
  313. return S_OK;
  314. }
  315. HRESULT CIISCertRequest::CreateDN(CString& str)
  316. {
  317. str.Empty();
  318. str += _T("CN=") + m_Info_CommonName;
  319. str += _T("\n,OU=") + m_Info_OrganizationUnit;
  320. str += _T("\n,O=") + m_Info_Organization;
  321. str += _T("\n,L=") + m_Info_Locality;
  322. str += _T("\n,S=") + m_Info_State;
  323. str += _T("\n,C=") + m_Info_Country;
  324. return S_OK;
  325. }
  326. void CIISCertRequest::GetCertificateTemplate(CString& str)
  327. {
  328. str = _T("CertificateTemplate:");
  329. str += m_Info_CertificateTemplate;
  330. }
  331. IEnroll * CIISCertRequest::GetEnrollObject()
  332. {
  333. if (m_pEnroll == NULL)
  334. {
  335. m_hResult = CoCreateInstance(CLSID_CEnroll,NULL,CLSCTX_INPROC_SERVER,IID_IEnroll,(void **)&m_pEnroll);
  336. // now we need to change defaults for this
  337. // object to LOCAL_MACHINE
  338. if (m_pEnroll != NULL)
  339. {
  340. long dwFlags;
  341. VERIFY(SUCCEEDED(m_pEnroll->get_MyStoreFlags(&dwFlags)));
  342. dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
  343. dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
  344. // following call will change Request store flags also
  345. VERIFY(SUCCEEDED(m_pEnroll->put_MyStoreFlags(dwFlags)));
  346. VERIFY(SUCCEEDED(m_pEnroll->get_GenKeyFlags(&dwFlags)));
  347. dwFlags |= CRYPT_EXPORTABLE;
  348. VERIFY(SUCCEEDED(m_pEnroll->put_GenKeyFlags(dwFlags)));
  349. VERIFY(SUCCEEDED(m_pEnroll->put_KeySpec(AT_KEYEXCHANGE)));
  350. VERIFY(SUCCEEDED(m_pEnroll->put_ProviderType(m_Info_DefaultProviderType)));
  351. VERIFY(SUCCEEDED(m_pEnroll->put_DeleteRequestCert(TRUE)));
  352. }
  353. }
  354. ASSERT(m_pEnroll != NULL);
  355. return m_pEnroll;
  356. }
  357. PCCERT_CONTEXT CIISCertRequest::GetInstalledCert()
  358. {
  359. if (m_pInstalledCert == NULL)
  360. {
  361. m_pInstalledCert = ::GetInstalledCert(m_ServerName,m_InstanceName,GetEnrollObject(),&m_hResult);
  362. }
  363. return m_pInstalledCert;
  364. }
  365. PCCERT_CONTEXT CIISCertRequest::GetPendingRequest()
  366. {
  367. if (m_pPendingRequest == NULL)
  368. {
  369. ASSERT(!m_InstanceName.IsEmpty());
  370. m_pPendingRequest = GetPendingDummyCert(m_InstanceName, GetEnrollObject(), &m_hResult);
  371. }
  372. return m_pPendingRequest;
  373. }
  374. STDMETHODIMP CIISCertRequest::SubmitRequest()
  375. {
  376. HRESULT hRes = E_INVALIDARG;
  377. BOOL bTryToGetDispositionErrorString = FALSE;
  378. ICertRequest * pCertRequest = NULL;
  379. LONG ldisposition;
  380. BSTR bstrRequest = NULL;
  381. BSTR bstrOutCert = NULL;
  382. CString strAttrib;
  383. CString strDN;
  384. // validate input to see that we have everything we need...
  385. if (m_Info_ConfigCA.IsEmpty())
  386. {
  387. hRes = E_INVALIDARG;
  388. goto SubmitRequest_Exit;
  389. }
  390. if (FAILED(hRes = CoCreateInstance(CLSID_CCertRequest, NULL, CLSCTX_INPROC_SERVER, IID_ICertRequest, (void **)&pCertRequest)))
  391. {
  392. goto SubmitRequest_Exit;
  393. }
  394. if (!pCertRequest)
  395. {
  396. hRes = E_FAIL;
  397. goto SubmitRequest_Exit;
  398. }
  399. if (FAILED(hRes = CreateDN(strDN)))
  400. {
  401. goto SubmitRequest_Exit;
  402. }
  403. if (FAILED(hRes = CreateRequest_Base64((BSTR)(LPCTSTR)strDN, GetEnrollObject(),
  404. m_Info_DefaultCSP ? NULL : (LPTSTR)(LPCTSTR)m_Info_CspName,
  405. m_Info_DefaultCSP ? m_Info_DefaultProviderType : m_Info_CustomProviderType,
  406. &bstrRequest)))
  407. {
  408. goto SubmitRequest_Exit;
  409. }
  410. bTryToGetDispositionErrorString = TRUE;
  411. GetCertificateTemplate(strAttrib);
  412. if (FAILED(hRes = pCertRequest->Submit(CR_IN_BASE64 | CR_IN_PKCS10, bstrRequest, (BSTR)(LPCTSTR)strAttrib, (LPTSTR)(LPCTSTR)m_Info_ConfigCA, &ldisposition)))
  413. {
  414. IISDebugOutput(_T("Submit bstrRequest returned HRESULT 0x%x; Disposition %x\n"), hRes, ldisposition);
  415. goto SubmitRequest_Exit;
  416. }
  417. if (ldisposition != CR_DISP_ISSUED)
  418. {
  419. switch (ldisposition)
  420. {
  421. case CR_DISP_INCOMPLETE:
  422. case CR_DISP_ERROR:
  423. case CR_DISP_DENIED:
  424. case CR_DISP_ISSUED_OUT_OF_BAND:
  425. case CR_DISP_UNDER_SUBMISSION:
  426. {
  427. HRESULT hrLastStatus = 0;
  428. if (SUCCEEDED(pCertRequest->GetLastStatus(&hrLastStatus)))
  429. {
  430. hRes = hrLastStatus;
  431. }
  432. }
  433. break;
  434. default:
  435. {
  436. if (SUCCEEDED(hRes))
  437. {
  438. hRes = E_FAIL;
  439. }
  440. break;
  441. }
  442. }
  443. goto SubmitRequest_Exit;
  444. }
  445. if (FAILED(hRes = pCertRequest->GetCertificate(CR_OUT_BASE64 /*| CR_OUT_CHAIN */, &bstrOutCert)))
  446. {
  447. goto SubmitRequest_Exit;
  448. }
  449. CRYPT_DATA_BLOB blob;
  450. blob.cbData = SysStringByteLen(bstrOutCert);
  451. blob.pbData = (BYTE *)bstrOutCert;
  452. if (FAILED(hRes = GetEnrollObject()->acceptPKCS7Blob(&blob)))
  453. {
  454. goto SubmitRequest_Exit;
  455. }
  456. PCCERT_CONTEXT pContext = GetCertContextFromPKCS7(blob.pbData, blob.cbData, NULL, &hRes);
  457. ASSERT(pContext != NULL);
  458. if (pContext != NULL)
  459. {
  460. BYTE HashBuffer[40]; // give it some extra size
  461. DWORD dwHashSize = sizeof(HashBuffer);
  462. if (CertGetCertificateContextProperty(pContext,CERT_SHA1_HASH_PROP_ID,(VOID *) HashBuffer,&dwHashSize))
  463. {
  464. CRYPT_HASH_BLOB hash_blob = {dwHashSize, HashBuffer};
  465. InstallHashToMetabase(&hash_blob,m_ServerName,m_InstanceName,&hRes);
  466. }
  467. CertFreeCertificateContext(pContext);
  468. }
  469. // now put extra properties to the installed cert
  470. if (NULL != (pContext = GetInstalledCert()))
  471. {
  472. if (!(AttachFriendlyName(pContext, m_Info_FriendlyName, &hRes)))
  473. {
  474. // forget the error if we can't attach the friendly name..
  475. }
  476. }
  477. SubmitRequest_Exit:
  478. if (FAILED(hRes))
  479. {
  480. // CreateRequest_Base64 failed.
  481. // likely with "NTE_BAD_ALGID _HRESULT_TYPEDEF_(0x80090008L)"
  482. LPTSTR lpBuffer = NULL;
  483. if (0 != FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL,hRes,MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR)&lpBuffer,0,NULL))
  484. {
  485. if (lpBuffer)
  486. {
  487. m_DispositionMessage = lpBuffer;
  488. }
  489. }
  490. if (bTryToGetDispositionErrorString)
  491. {
  492. if (NULL == lpBuffer)
  493. {
  494. BSTR bstr = NULL;
  495. if (SUCCEEDED(pCertRequest->GetDispositionMessage(&bstr)))
  496. {
  497. m_DispositionMessage = bstr;
  498. if (bstr) {SysFreeString(bstr);}
  499. }
  500. }
  501. }
  502. if (lpBuffer) {LocalFree (lpBuffer);}
  503. }
  504. if (bstrOutCert)
  505. {
  506. SysFreeString(bstrOutCert);bstrOutCert=NULL;
  507. }
  508. if (bstrRequest)
  509. {
  510. SysFreeString(bstrRequest);bstrRequest=NULL;
  511. }
  512. if (pCertRequest)
  513. {
  514. pCertRequest->Release();pCertRequest=NULL;
  515. }
  516. IISDebugOutput(_T("SubmitRequest:end:hres=0x%x;\n"), hRes);
  517. m_hResult = hRes;
  518. return hRes;
  519. }
  520. // Instead of renewal we create new certificate based on parameters
  521. // from the current one. After creation we install this certificate in place
  522. // of current one and deleting the old one from store. Even if IIS has an
  523. // opened SSL connection it should get a notification and update the certificate
  524. // data.
  525. //
  526. STDMETHODIMP CIISCertRequest::SubmitRenewalRequest()
  527. {
  528. HRESULT hRes = E_FAIL;
  529. if (LoadRenewalData())
  530. {
  531. if (SetSecuritySettings())
  532. {
  533. PCCERT_CONTEXT pCurrent = GetInstalledCert();
  534. m_pInstalledCert = NULL;
  535. hRes = SubmitRequest();
  536. if (SUCCEEDED(hRes))
  537. {
  538. CertDeleteCertificateFromStore(pCurrent);
  539. }
  540. }
  541. }
  542. return hRes;
  543. }
  544. BOOL CIISCertRequest::SetSecuritySettings()
  545. {
  546. long dwGenKeyFlags;
  547. if (SUCCEEDED(GetEnrollObject()->get_GenKeyFlags(&dwGenKeyFlags)))
  548. {
  549. dwGenKeyFlags &= 0x0000FFFF;
  550. dwGenKeyFlags |= (m_KeyLength << 16);
  551. if (m_SGCcertificat)
  552. {
  553. dwGenKeyFlags |= CRYPT_SGCKEY;
  554. }
  555. return (SUCCEEDED(GetEnrollObject()->put_GenKeyFlags(dwGenKeyFlags)));
  556. }
  557. return FALSE;
  558. }
  559. BOOL CIISCertRequest::GetCertDescription(PCCERT_CONTEXT pCert,CERT_DESCRIPTION& desc)
  560. {
  561. BOOL bRes = FALSE;
  562. DWORD cb;
  563. UINT i, j;
  564. CERT_NAME_INFO * pNameInfo;
  565. if (pCert == NULL)
  566. goto ErrExit;
  567. if ( !CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME,
  568. pCert->pCertInfo->Subject.pbData,
  569. pCert->pCertInfo->Subject.cbData,
  570. 0, NULL, &cb)
  571. || NULL == (pNameInfo = (CERT_NAME_INFO *)_alloca(cb))
  572. || !CryptDecodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME,
  573. pCert->pCertInfo->Subject.pbData,
  574. pCert->pCertInfo->Subject.cbData,
  575. 0,
  576. pNameInfo, &cb)
  577. )
  578. {
  579. goto ErrExit;
  580. }
  581. for (i = 0; i < pNameInfo->cRDN; i++)
  582. {
  583. CERT_RDN rdn = pNameInfo->rgRDN[i];
  584. for (j = 0; j < rdn.cRDNAttr; j++)
  585. {
  586. CERT_RDN_ATTR attr = rdn.rgRDNAttr[j];
  587. if (strcmp(attr.pszObjId, szOID_COMMON_NAME) == 0)
  588. {
  589. FormatRdnAttr(desc.m_Info_CommonName, attr.dwValueType, attr.Value, FALSE);
  590. }
  591. else if (strcmp(attr.pszObjId, szOID_COUNTRY_NAME) == 0)
  592. {
  593. FormatRdnAttr(desc.m_Info_Country, attr.dwValueType, attr.Value, TRUE);
  594. }
  595. else if (strcmp(attr.pszObjId, szOID_LOCALITY_NAME) == 0)
  596. {
  597. FormatRdnAttr(desc.m_Info_Locality, attr.dwValueType, attr.Value, TRUE);
  598. }
  599. else if (strcmp(attr.pszObjId, szOID_STATE_OR_PROVINCE_NAME) == 0)
  600. {
  601. FormatRdnAttr(desc.m_Info_State, attr.dwValueType, attr.Value, TRUE);
  602. }
  603. else if (strcmp(attr.pszObjId, szOID_ORGANIZATION_NAME) == 0)
  604. {
  605. FormatRdnAttr(desc.m_Info_Organization, attr.dwValueType, attr.Value, TRUE);
  606. }
  607. else if (strcmp(attr.pszObjId, szOID_ORGANIZATIONAL_UNIT_NAME) == 0)
  608. {
  609. FormatRdnAttr(desc.m_Info_OrganizationUnit, attr.dwValueType, attr.Value, TRUE);
  610. }
  611. }
  612. }
  613. // issued to
  614. if (!GetNameString(pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, desc.m_Info_CAName, &m_hResult))
  615. {
  616. goto ErrExit;
  617. }
  618. // expiration date
  619. if (!FormatDateString(desc.m_Info_ExpirationDate, pCert->pCertInfo->NotAfter, FALSE, FALSE))
  620. {
  621. goto ErrExit;
  622. }
  623. // purpose
  624. if (!FormatEnhancedKeyUsageString(desc.m_Info_Usage, pCert, FALSE, FALSE, &m_hResult))
  625. {
  626. // According to local experts, we should also use certs without this property set
  627. ASSERT(FALSE);
  628. //goto ErrExit;
  629. }
  630. // friendly name
  631. if (!GetFriendlyName(pCert, desc.m_Info_FriendlyName, &m_hResult))
  632. {
  633. //desc.m_Info_FriendlyName.LoadString(IDS_FRIENDLYNAME_NONE);
  634. desc.m_Info_FriendlyName = _T("<>");
  635. }
  636. // get the alternate subject name if subject is empty
  637. // will use this as display only if subject name does not exist.
  638. if (desc.m_Info_CommonName.IsEmpty())
  639. {
  640. TCHAR * pwszOut = NULL;
  641. GetAlternateSubjectName(pCert,&pwszOut);
  642. if (pwszOut)
  643. {
  644. desc.m_Info_AltSubject = pwszOut;
  645. LocalFree(pwszOut);pwszOut = NULL;
  646. }
  647. }
  648. bRes = TRUE;
  649. ErrExit:
  650. return bRes;
  651. }
  652. BOOL CIISCertRequest::LoadRenewalData()
  653. {
  654. // we need to obtain data from the installed cert
  655. CERT_DESCRIPTION desc;
  656. ASSERT(GetInstalledCert() != NULL);
  657. BOOL res = FALSE;
  658. DWORD cbData;
  659. BYTE * pByte = NULL;
  660. DWORD len = 0;
  661. if (!GetCertDescription(GetInstalledCert(), desc))
  662. {
  663. res = FALSE;
  664. goto ErrorExit;
  665. }
  666. m_Info_CommonName = desc.m_Info_CommonName;
  667. m_Info_FriendlyName = desc.m_Info_FriendlyName;
  668. m_Info_Country = desc.m_Info_Country;
  669. m_Info_State = desc.m_Info_State;
  670. m_Info_Locality = desc.m_Info_Locality;
  671. m_Info_Organization = desc.m_Info_Organization;
  672. m_Info_OrganizationUnit = desc.m_Info_OrganizationUnit;
  673. len = CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &GetInstalledCert()->pCertInfo->SubjectPublicKeyInfo);
  674. if (len == 0)
  675. {
  676. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  677. goto ErrorExit;
  678. }
  679. //
  680. m_KeyLength = len;
  681. // compare property value
  682. if (CertGetCertificateContextProperty(GetInstalledCert(), CERT_KEY_PROV_INFO_PROP_ID, NULL, &cbData)
  683. && (NULL != (pByte = (BYTE *)_alloca(cbData)))
  684. && CertGetCertificateContextProperty(GetInstalledCert(), CERT_KEY_PROV_INFO_PROP_ID, pByte, &cbData)
  685. )
  686. {
  687. CRYPT_KEY_PROV_INFO * pProvInfo = (CRYPT_KEY_PROV_INFO *)pByte;
  688. if (pProvInfo->dwProvType != m_Info_DefaultProviderType)
  689. {
  690. m_Info_DefaultCSP = FALSE;
  691. m_Info_CustomProviderType = pProvInfo->dwProvType;
  692. m_Info_CspName = pProvInfo->pwszProvName;
  693. }
  694. LPCSTR rgbpszUsageArray[2];
  695. SecureZeroMemory( &rgbpszUsageArray, sizeof(rgbpszUsageArray) );
  696. rgbpszUsageArray[0] = szOID_SERVER_GATED_CRYPTO;
  697. rgbpszUsageArray[1] = szOID_SGC_NETSCAPE;
  698. DWORD dwCount=sizeof(rgbpszUsageArray)/sizeof(rgbpszUsageArray[0]);
  699. m_SGCcertificat = FALSE;
  700. if (1 == ContainsKeyUsageProperty(GetInstalledCert(),rgbpszUsageArray,dwCount,&m_hResult))
  701. {
  702. m_SGCcertificat = TRUE;
  703. }
  704. res = TRUE;
  705. }
  706. else
  707. {
  708. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  709. goto ErrorExit;
  710. }
  711. ErrorExit:
  712. return res;
  713. }
  714. BOOL CIISCertRequest::PrepareRequestString(CString& request_text, CCryptBlob& request_blob, BOOL bLoadFromRenewalData)
  715. {
  716. BOOL bReturn = FALSE;
  717. CString strDN;
  718. LPSTR pNewMessage = NULL;
  719. TCHAR szUsage[] = _T(szOID_PKIX_KP_SERVER_AUTH);
  720. if (TRUE == bLoadFromRenewalData)
  721. {
  722. if (FALSE == LoadRenewalData())
  723. {
  724. goto PrepareRequestString_Exit;
  725. }
  726. if (FALSE == SetSecuritySettings())
  727. {
  728. goto PrepareRequestString_Exit;
  729. }
  730. }
  731. CreateDN(strDN);
  732. ASSERT(!strDN.IsEmpty());
  733. GetEnrollObject()->put_ProviderType(m_Info_DefaultCSP ? m_Info_DefaultProviderType : m_Info_CustomProviderType);
  734. if (!m_Info_DefaultCSP)
  735. {
  736. GetEnrollObject()->put_ProviderNameWStr((LPTSTR)(LPCTSTR)m_Info_CspName);
  737. // We are supporting only these two types of CSP, it is pretty safe to
  738. // have just two options, because we are using the same two types when
  739. // we are populating CSP selection list.
  740. if (m_Info_CustomProviderType == PROV_DH_SCHANNEL)
  741. {
  742. GetEnrollObject()->put_KeySpec(AT_SIGNATURE);
  743. }
  744. else if (m_Info_CustomProviderType == PROV_RSA_SCHANNEL)
  745. {
  746. GetEnrollObject()->put_KeySpec(AT_KEYEXCHANGE);
  747. }
  748. }
  749. if (FAILED(m_hResult = GetEnrollObject()->createPKCS10WStr((LPTSTR)(LPCTSTR)strDN,szUsage,request_blob)))
  750. {
  751. goto PrepareRequestString_Exit;
  752. }
  753. // BASE64 encode pkcs 10
  754. DWORD cch = 0;
  755. TCHAR * psz = NULL;
  756. if (FAILED(Base64EncodeW(request_blob.GetData(), request_blob.GetSize(), NULL, &cch)))
  757. {
  758. goto PrepareRequestString_Exit;
  759. }
  760. psz = (TCHAR *) LocalAlloc(LPTR, (cch+1) * sizeof(TCHAR));
  761. if (NULL == psz)
  762. {
  763. goto PrepareRequestString_Exit;
  764. }
  765. if (FAILED(Base64EncodeW(request_blob.GetData(), request_blob.GetSize(), psz, &cch)))
  766. {
  767. goto PrepareRequestString_Exit;
  768. }
  769. psz[cch] = '\0';
  770. request_text = MESSAGE_HEADER;
  771. request_text += psz;
  772. request_text += MESSAGE_TRAILER;
  773. bReturn = TRUE;
  774. PrepareRequestString_Exit:
  775. if (psz){LocalFree(psz);psz=NULL;}
  776. return bReturn;
  777. }
  778. BOOL CIISCertRequest::WriteRequestString(CString& request)
  779. {
  780. ASSERT(!PathIsRelative(m_ReqFileName));
  781. BOOL bRes = FALSE;
  782. TCHAR szPath[_MAX_PATH];
  783. if (m_ReqFileName.GetLength() > _MAX_PATH)
  784. {
  785. m_hResult = E_INVALIDARG;
  786. return FALSE;
  787. }
  788. StringCbCopy(szPath,sizeof(szPath),m_ReqFileName);
  789. PathRemoveFileSpec(szPath);
  790. if (!PathIsDirectory(szPath))
  791. {
  792. if (!CreateDirectoryFromPath(szPath, NULL))
  793. {
  794. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  795. return FALSE;
  796. }
  797. }
  798. HANDLE hFile = ::CreateFile(m_ReqFileName,GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  799. if (hFile != INVALID_HANDLE_VALUE)
  800. {
  801. DWORD cb = request.GetLength();
  802. char * ascii_buf = (char *) LocalAlloc(LPTR,cb);
  803. if (ascii_buf)
  804. {
  805. wcstombs(ascii_buf, request, cb);
  806. bRes = ::WriteFile(hFile, ascii_buf, cb, &cb, NULL);
  807. ::CloseHandle(hFile);
  808. LocalFree(ascii_buf);ascii_buf=NULL;
  809. }
  810. else
  811. {
  812. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  813. }
  814. }
  815. else
  816. {
  817. m_hResult = HRESULT_FROM_WIN32(GetLastError());
  818. }
  819. return bRes;
  820. }
  821. STDMETHODIMP CIISCertRequest::SaveRequestToFile()
  822. {
  823. HRESULT hRes = E_FAIL;
  824. CString request_text;
  825. CCryptBlobIMalloc request_blob;
  826. CCryptBlobLocal name_blob, request_store_blob, status_blob;
  827. PCERT_REQUEST_INFO pReqInfo = NULL;
  828. HCERTSTORE hStore = NULL;
  829. PCCERT_CONTEXT pDummyCert = NULL;
  830. // AARONL CHANGED
  831. BOOL bLoadFromRenewalData = FALSE;
  832. IISDebugOutput(_T("SaveRequestToFile:start\r\n"));
  833. if (!PrepareRequestString(request_text,request_blob,bLoadFromRenewalData))
  834. {
  835. goto SaveRequestToFile_Exit;
  836. }
  837. if (!WriteRequestString(request_text))
  838. {
  839. goto SaveRequestToFile_Exit;
  840. }
  841. // prepare data we want to attach to dummy request
  842. if (!EncodeString(m_InstanceName, name_blob, &hRes))
  843. {
  844. goto SaveRequestToFile_Exit;
  845. }
  846. if (!EncodeInteger(m_status_code, status_blob, &hRes))
  847. {
  848. goto SaveRequestToFile_Exit;
  849. }
  850. // get back request from encoded data
  851. if (!GetRequestInfoFromPKCS10(request_blob, &pReqInfo, &hRes))
  852. {
  853. goto SaveRequestToFile_Exit;
  854. }
  855. // find dummy cert put to request store by createPKCS10 call
  856. hStore = OpenRequestStore(GetEnrollObject(), &hRes);
  857. if (NULL == hStore)
  858. {
  859. goto SaveRequestToFile_Exit;
  860. }
  861. pDummyCert = CertFindCertificateInStore(hStore,CRYPT_ASN_ENCODING,0,CERT_FIND_PUBLIC_KEY,(void *)&pReqInfo->SubjectPublicKeyInfo,NULL);
  862. if (NULL == pDummyCert)
  863. {
  864. goto SaveRequestToFile_Cleanup;
  865. }
  866. if (!CertSetCertificateContextProperty(pDummyCert,CERTWIZ_INSTANCE_NAME_PROP_ID, 0, name_blob))
  867. {
  868. hRes = HRESULT_FROM_WIN32(GetLastError());
  869. goto SaveRequestToFile_Cleanup;
  870. }
  871. if (!CertSetCertificateContextProperty(pDummyCert,CERTWIZ_REQUEST_FLAG_PROP_ID, 0, status_blob))
  872. {
  873. hRes = HRESULT_FROM_WIN32(GetLastError());
  874. goto SaveRequestToFile_Cleanup;
  875. }
  876. // put friendly name to dummy cert -- we will reuse it later
  877. if (!AttachFriendlyName(pDummyCert, m_Info_FriendlyName, &hRes))
  878. {
  879. hRes = HRESULT_FROM_WIN32(GetLastError());
  880. goto SaveRequestToFile_Cleanup;
  881. }
  882. hRes = S_OK;
  883. // put certificate text to the clipboard
  884. if (OpenClipboard(GetFocus()))
  885. {
  886. size_t len = request_text.GetLength() + 1;
  887. HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, len);
  888. LPSTR pMem = (LPSTR)GlobalLock(hMem);
  889. if (pMem != NULL)
  890. {
  891. wcstombs(pMem, request_text, len);
  892. GlobalUnlock(hMem);
  893. SetClipboardData(CF_TEXT, hMem);
  894. }
  895. CloseClipboard();
  896. }
  897. SaveRequestToFile_Cleanup:
  898. if (NULL != pDummyCert)
  899. {
  900. CertFreeCertificateContext(pDummyCert);pDummyCert = NULL;
  901. }
  902. if (NULL != hStore)
  903. {
  904. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);hStore = NULL;
  905. }
  906. SaveRequestToFile_Exit:
  907. if (pReqInfo)
  908. {
  909. LocalFree(pReqInfo);pReqInfo = NULL;
  910. }
  911. m_hResult = hRes;
  912. IISDebugOutput(_T("SaveRequestToFile:end ret=0x%x\r\n"),m_hResult);
  913. return hRes;
  914. }
  915. STDMETHODIMP CIISCertRequest::Info_Dump()
  916. {
  917. m_ReqFileName = _T("c:\\reqtest1.txt");
  918. IISDebugOutput(_T("m_ServerName:%s\r\n"),(LPCTSTR) m_ServerName);
  919. IISDebugOutput(_T("m_UserName:%s\r\n"),(LPCTSTR) m_UserName);
  920. //IISDebugOutput(_T("m_UserPassword:%s\r\n"),(LPCTSTR) m_UserPassword);
  921. IISDebugOutput(_T("m_InstanceName:%s\r\n"),(LPCTSTR) m_InstanceName);
  922. // Certificate Request Info
  923. IISDebugOutput(_T("m_Info_CommonName=:%s\r\n"),(LPCTSTR) m_Info_CommonName);
  924. IISDebugOutput(_T("m_Info_FriendlyName:%s\r\n"),(LPCTSTR) m_Info_FriendlyName);
  925. IISDebugOutput(_T("m_Info_Country:%s\r\n"),(LPCTSTR) m_Info_Country);
  926. IISDebugOutput(_T("m_Info_State:%s\r\n"),(LPCTSTR) m_Info_State);
  927. IISDebugOutput(_T("m_Info_Locality:%s\r\n"),(LPCTSTR) m_Info_Locality);
  928. IISDebugOutput(_T("m_Info_Organization:%s\r\n"),(LPCTSTR) m_Info_Organization);
  929. IISDebugOutput(_T("m_Info_OrganizationUnit:%s\r\n"),(LPCTSTR) m_Info_OrganizationUnit);
  930. IISDebugOutput(_T("m_Info_CAName:%s\r\n"),(LPCTSTR) m_Info_CAName);
  931. IISDebugOutput(_T("m_Info_ExpirationDate:%s\r\n"),(LPCTSTR) m_Info_ExpirationDate);
  932. IISDebugOutput(_T("m_Info_Usage:%s\r\n"),(LPCTSTR) m_Info_Usage);
  933. IISDebugOutput(_T("m_Info_AltSubject:%s\r\n"),(LPCTSTR) m_Info_AltSubject);
  934. // other
  935. IISDebugOutput(_T("m_Info_ConfigCA:%s\r\n"),(LPCTSTR) m_Info_ConfigCA);
  936. IISDebugOutput(_T("m_Info_CertificateTemplate:%s\r\n"),(LPCTSTR) m_Info_CertificateTemplate);
  937. IISDebugOutput(_T("m_Info_DefaultProviderType:%d\r\n"),m_Info_DefaultProviderType);
  938. IISDebugOutput(_T("m_Info_CustomProviderType:%d\r\n"),m_Info_CustomProviderType);
  939. IISDebugOutput(_T("m_Info_DefaultCSP:%d\r\n"), m_Info_DefaultCSP);
  940. IISDebugOutput(_T("m_Info_CspName:%s\r\n"),(LPCTSTR) m_Info_CspName);
  941. IISDebugOutput(_T("m_pInstalledCert:%p\r\n"), m_pInstalledCert);
  942. IISDebugOutput(_T("m_ReqFileName:%s\r\n"),(LPCTSTR) m_ReqFileName);
  943. IISDebugOutput(_T("m_hResult:0x%x\r\n"), m_hResult);
  944. IISDebugOutput(_T("m_DispositionMessage:%s\r\n"),(LPCTSTR) m_DispositionMessage);
  945. return S_OK;
  946. }
  947. #endif