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.

1267 lines
37 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // NmMkCert - NetMeeting internal certificate generator
  4. //
  5. // Generates NetMeeting default user certificates. The NetMeeting
  6. // root key and certificate are stored as a program resource.
  7. //
  8. // ClausGi 7/29/98 created based on MAKECERT
  9. //
  10. //--------------------------------------------------------------------------
  11. #include "global.h"
  12. #include <oprahcom.h>
  13. #ifdef DEBUG
  14. HDBGZONE ghDbgZone = NULL;
  15. static PTCHAR _rgZonesNmMkCert[] = { TEXT("nmmkcert"), };
  16. #endif /* DEBUG */
  17. //+-------------------------------------------------------------------------
  18. // contants
  19. //--------------------------------------------------------------------------
  20. //allow max 10 extensions per certificate
  21. #define MAX_EXT_CNT 10
  22. //+-------------------------------------------------------------------------
  23. // globals
  24. //--------------------------------------------------------------------------
  25. WCHAR* g_wszSubjectKey = L"_NmMkCert";
  26. WCHAR* g_wszSubjectStore = WSZNMSTORE;
  27. DWORD g_dwSubjectStoreFlag = CERT_SYSTEM_STORE_CURRENT_USER;
  28. DWORD g_dwIssuerKeySpec = AT_SIGNATURE;
  29. DWORD g_dwSubjectKeySpec = AT_KEYEXCHANGE;
  30. WCHAR *g_wszSubjectDisplayName = NULL; // BUGBUG set this?
  31. LPWSTR g_wszIssuerProviderName = NULL;
  32. LPWSTR g_wszSubjectProviderName = NULL;
  33. WCHAR* g_wszSubjectX500Name;
  34. DWORD g_dwProvType = PROV_RSA_FULL;
  35. HMODULE hModule=NULL;
  36. BOOL MakeCert(DWORD dwFlags);
  37. BOOL WINAPI DllMain(HINSTANCE hDllInst, DWORD fdwReason, LPVOID)
  38. {
  39. switch (fdwReason)
  40. {
  41. case DLL_PROCESS_ATTACH:
  42. {
  43. hModule = hDllInst;
  44. ASSERT (hModule != NULL);
  45. DBGINIT(&ghDbgZone, _rgZonesNmMkCert);
  46. DisableThreadLibraryCalls (hDllInst);
  47. DBG_INIT_MEMORY_TRACKING(hDllInst);
  48. break;
  49. }
  50. case DLL_PROCESS_DETACH:
  51. {
  52. DBG_CHECK_MEMORY_TRACKING(hDllInst);
  53. hModule = NULL;
  54. break;
  55. }
  56. default:
  57. break;
  58. }
  59. return (TRUE);
  60. }
  61. //
  62. // X.509 cert strings must be from X.208 printable character set... this
  63. // function enforces that.
  64. //
  65. static const char szPrintable[] = " '()+,-./:=?\""; // along with A-Za-z0-9
  66. VOID MkPrintableString ( LPSTR szString )
  67. {
  68. CHAR * p = szString;
  69. while ( *p )
  70. {
  71. if (!(('a' <= *p && *p <='z') ||
  72. ('A' <= *p && *p <='Z') ||
  73. ('0' <= *p && *p <='9') ||
  74. _StrChr(szPrintable,*p)))
  75. {
  76. *p = '-';
  77. }
  78. p++;
  79. }
  80. }
  81. DWORD WINAPI NmMakeCert( LPCSTR szFirstName,
  82. LPCSTR szLastName,
  83. LPCSTR szEmailName,
  84. LPCSTR szCity,
  85. LPCSTR szCountry,
  86. DWORD flags)
  87. {
  88. DWORD dwRet = -1;
  89. WARNING_OUT(("NmMakeCert called"));
  90. // Form the unencoded X500 subject string. It would be nice to
  91. // use official constants for the below... CertRDNValueToString?
  92. UINT cbX500Name = ( szFirstName ? lstrlen(szFirstName) : 0 ) +
  93. ( szLastName ? lstrlen(szLastName) : 0 ) +
  94. ( szEmailName ? lstrlen(szEmailName) : 0 ) +
  95. ( szCity ? lstrlen(szCity) : 0 ) +
  96. ( szCountry ? lstrlen(szCountry) : 0 ) +
  97. 128; // Extra is for RDN OID strings: CN= etc.
  98. char * pX500Name = new char[cbX500Name];
  99. if ( NULL == pX500Name )
  100. {
  101. ERROR_OUT(("couldn't allocate %d bytes for x500 name", cbX500Name));
  102. goto cleanup;
  103. }
  104. ASSERT( ( szFirstName && *szFirstName ) || ( szLastName && *szLastName ) );
  105. wsprintf( pX500Name, "CN=\"%s %s\"", szFirstName ? szFirstName : "", szLastName ? szLastName : "" );
  106. if ( szEmailName && *szEmailName )
  107. wsprintf( pX500Name + lstrlen(pX500Name), ", E=\"%s\"", szEmailName );
  108. if ( szCity && *szCity )
  109. wsprintf( pX500Name + lstrlen(pX500Name), ", S=\"%s\"", szCity );
  110. if ( szCountry && *szCountry )
  111. wsprintf( pX500Name + lstrlen(pX500Name), ", C=\"%s\"", szCountry );
  112. MkPrintableString ( pX500Name );
  113. g_wszSubjectX500Name = AnsiToUnicode ( pX500Name );
  114. ASSERT(g_wszSubjectX500Name);
  115. if ( flags & NMMKCERT_F_LOCAL_MACHINE )
  116. {
  117. // We are being asked to generate a local machine cert...
  118. // change the subject store flag and the key container name
  119. g_dwSubjectStoreFlag = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  120. g_wszSubjectKey = L"_NmMkMchCert";
  121. }
  122. // If we're on NT5 we have to generate the cert using the
  123. // PROV_RSA_SCHANNEL provider, on other platforms this provider type
  124. // doesn't exist.
  125. OSVERSIONINFO osVersion;
  126. ZeroMemory(&osVersion, sizeof(osVersion));
  127. osVersion.dwOSVersionInfoSize = sizeof(osVersion);
  128. GetVersionEx(&osVersion);
  129. if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT &&
  130. osVersion.dwMajorVersion >= 5)
  131. {
  132. g_dwProvType = PROV_RSA_SCHANNEL;
  133. }
  134. // Get to work and make the certificate
  135. if (!MakeCert(flags))
  136. {
  137. WARNING_OUT(("NmMakeCert failed."));
  138. }
  139. else
  140. {
  141. dwRet = 1;
  142. }
  143. cleanup:
  144. if ( NULL != g_wszSubjectX500Name )
  145. {
  146. delete g_wszSubjectX500Name;
  147. }
  148. if ( NULL != pX500Name )
  149. {
  150. delete [] pX500Name;
  151. }
  152. return dwRet;
  153. }
  154. // RUNDLL entry point for certificate uninstall... the prototype is given
  155. // by RUNDLL32.EXE requirements!
  156. void CALLBACK NmMakeCertCleanup ( HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow )
  157. {
  158. // Clean up exisint certs and private keys
  159. MakeCert(NMMKCERT_F_CLEANUP_ONLY);
  160. g_dwSubjectStoreFlag = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  161. g_wszSubjectKey = L"_NmMkMchCert";
  162. MakeCert(NMMKCERT_F_LOCAL_MACHINE|NMMKCERT_F_CLEANUP_ONLY);
  163. }
  164. //+=========================================================================
  165. // Local Support Functions
  166. //==========================================================================
  167. //+=========================================================================
  168. // MakeCert support functions
  169. //==========================================================================
  170. BOOL VerifyIssuerKey( IN HCRYPTPROV hProv,
  171. IN PCERT_PUBLIC_KEY_INFO pIssuerKeyInfo);
  172. HCRYPTPROV GetSubjectProv(OUT LPWSTR *ppwszTmpContainer);
  173. BOOL GetPublicKey(
  174. HCRYPTPROV hProv,
  175. PCERT_PUBLIC_KEY_INFO *ppPubKeyInfo
  176. );
  177. BOOL EncodeSubject(
  178. OUT BYTE **ppbEncoded,
  179. IN OUT DWORD *pcbEncoded
  180. );
  181. BOOL CreateSpcCommonName(
  182. OUT BYTE **ppbEncoded,
  183. IN OUT DWORD *pcbEncoded
  184. );
  185. BOOL CreateEnhancedKeyUsage(
  186. OUT BYTE **ppbEncoded,
  187. IN OUT DWORD *pcbEncoded
  188. );
  189. BOOL SaveCertToStore(HCRYPTPROV hProv,
  190. HCERTSTORE hStore,
  191. DWORD dwFlag,
  192. BYTE *pbEncodedCert,
  193. DWORD cbEncodedCert,
  194. LPWSTR wszPvk,
  195. DWORD dwKeySpecification,
  196. LPWSTR wszCapiProv,
  197. DWORD dwCapiProvType);
  198. //+-------------------------------------------------------------------------
  199. // Get the root's certificate from the program's resources
  200. //--------------------------------------------------------------------------
  201. PCCERT_CONTEXT GetRootCertContext()
  202. {
  203. PCCERT_CONTEXT pCert = NULL;
  204. HRSRC hRes;
  205. //
  206. // The root certificate is stored as a resource of ours.
  207. // Load it...
  208. //
  209. if (0 != (hRes = FindResource(hModule, MAKEINTRESOURCE(IDR_ROOTCERTIFICATE),
  210. "CER"))) {
  211. HGLOBAL hglobRes;
  212. if (NULL != (hglobRes = LoadResource(hModule, hRes))) {
  213. BYTE *pbRes;
  214. DWORD cbRes;
  215. cbRes = SizeofResource(hModule, hRes);
  216. pbRes = (BYTE *) LockResource(hglobRes);
  217. if (cbRes && pbRes)
  218. pCert = CertCreateCertificateContext(X509_ASN_ENCODING,
  219. pbRes, cbRes);
  220. if ( NULL == pCert )
  221. {
  222. DWORD dwError = GetLastError();
  223. }
  224. UnlockResource(hglobRes);
  225. FreeResource(hglobRes);
  226. }
  227. }
  228. if (pCert == NULL)
  229. {
  230. ERROR_OUT(("Error creating root cert: %x", GetLastError()));
  231. }
  232. return pCert;
  233. }
  234. //+-------------------------------------------------------------------------
  235. // Get the root's private key from the program's resources and create
  236. // a temporary key provider container
  237. //--------------------------------------------------------------------------
  238. HCRYPTPROV GetRootProv(OUT LPWSTR *ppwszTmpContainer)
  239. {
  240. HCRYPTPROV hProv = 0;
  241. HRSRC hRes;
  242. WCHAR wszRootSig[] = L"Root Signature";
  243. *ppwszTmpContainer = NULL;
  244. if (0 != (hRes = FindResource(hModule,MAKEINTRESOURCE(IDR_PVKROOT),"PVK")))
  245. {
  246. HGLOBAL hglobRes;
  247. if (NULL != (hglobRes = LoadResource(hModule, hRes))) {
  248. BYTE *pbRes;
  249. DWORD cbRes;
  250. cbRes = SizeofResource(hModule, hRes);
  251. pbRes = (BYTE *) LockResource(hglobRes);
  252. if (cbRes && pbRes) {
  253. PvkPrivateKeyAcquireContextFromMemory(
  254. g_wszIssuerProviderName,
  255. PROV_RSA_FULL,
  256. pbRes,
  257. cbRes,
  258. NULL, // hwndOwner
  259. wszRootSig,
  260. &g_dwIssuerKeySpec,
  261. &hProv
  262. );
  263. }
  264. UnlockResource(hglobRes);
  265. FreeResource(hglobRes);
  266. }
  267. }
  268. if (hProv == 0)
  269. {
  270. ERROR_OUT(("couldn't create root key provider: %x", GetLastError()));
  271. }
  272. return hProv;
  273. }
  274. //+-------------------------------------------------------------------------
  275. // Make the subject certificate. If the subject doesn't have a private
  276. // key, then, create.
  277. //--------------------------------------------------------------------------
  278. BOOL MakeCert(DWORD dwFlags)
  279. {
  280. BOOL fResult;
  281. HCRYPTPROV hIssuerProv = 0;
  282. LPWSTR pwszTmpIssuerContainer = NULL;
  283. PCCERT_CONTEXT pIssuerCertContext = NULL;
  284. PCERT_INFO pIssuerCert =NULL; // not allocated
  285. HCRYPTPROV hSubjectProv = 0;
  286. LPWSTR pwszTmpSubjectContainer = NULL;
  287. PCERT_PUBLIC_KEY_INFO pSubjectPubKeyInfo = NULL; // not allocated
  288. PCERT_PUBLIC_KEY_INFO pAllocSubjectPubKeyInfo = NULL;
  289. BYTE *pbSubjectEncoded = NULL;
  290. DWORD cbSubjectEncoded =0;
  291. BYTE *pbSpcCommonNameEncoded = NULL;
  292. DWORD cbSpcCommonNameEncoded =0;
  293. BYTE *pbCertEncoded = NULL;
  294. DWORD cbCertEncoded =0;
  295. BYTE *pbEKUEncoded = NULL;
  296. DWORD cbEKUEncoded = 0;
  297. CERT_INFO Cert;
  298. GUID SerialNumber;
  299. HCERTSTORE hStore=NULL;
  300. CERT_EXTENSION rgExt[MAX_EXT_CNT];
  301. DWORD cExt = 0;
  302. CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm = {
  303. szOID_RSA_MD5RSA, 0, 0
  304. };
  305. if (0 == (hSubjectProv = GetSubjectProv(&pwszTmpSubjectContainer)))
  306. goto ErrorReturn;
  307. #define TEMP_CLEAN_CODE
  308. #ifdef TEMP_CLEAN_CODE
  309. // open the system store where we used to generate certs
  310. hStore=CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
  311. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  312. hSubjectProv,
  313. CERT_STORE_NO_CRYPT_RELEASE_FLAG | g_dwSubjectStoreFlag,
  314. L"MY" );
  315. if ( hStore )
  316. {
  317. //
  318. // Delete all old certs
  319. //
  320. PCCERT_CONTEXT pCertContext = NULL;
  321. // Clear out any certificate(s) we may have added before
  322. while ( pCertContext = CertEnumCertificatesInStore(
  323. hStore, (PCERT_CONTEXT)pCertContext ))
  324. {
  325. DWORD dwMagic;
  326. DWORD cbMagic;
  327. cbMagic = sizeof(dwMagic);
  328. if (CertGetCertificateContextProperty(pCertContext,
  329. CERT_FIRST_USER_PROP_ID, &dwMagic, &cbMagic) &&
  330. cbMagic == sizeof(dwMagic) && dwMagic == NMMKCERT_MAGIC )
  331. {
  332. CertDeleteCertificateFromStore(pCertContext);
  333. // Restart the enumeration
  334. pCertContext = NULL;
  335. continue;
  336. }
  337. }
  338. CertCloseStore(hStore,0);
  339. }
  340. #endif // TEMP_CLEAN_CODE
  341. // open a new cert store
  342. hStore=CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
  343. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  344. hSubjectProv,
  345. CERT_STORE_NO_CRYPT_RELEASE_FLAG | g_dwSubjectStoreFlag,
  346. g_wszSubjectStore);
  347. if(hStore==NULL)
  348. goto ErrorReturn;
  349. // Empty the store
  350. PCCERT_CONTEXT pCertContext;
  351. while ( pCertContext = CertEnumCertificatesInStore ( hStore, NULL ))
  352. {
  353. if ( !CertDeleteCertificateFromStore ( pCertContext ))
  354. {
  355. WARNING_OUT(("Failed to delete certificate: %x", GetLastError()));
  356. break;
  357. }
  358. }
  359. // If NMMKCERT_F_CLEANUP_ONLY is set, we are done
  360. if ( dwFlags & NMMKCERT_F_CLEANUP_ONLY )
  361. {
  362. // We've just deleted the existing certs, now delete the
  363. // private key container and exit.
  364. CryptAcquireContextU(
  365. &hSubjectProv,
  366. g_wszSubjectKey,
  367. g_wszSubjectProviderName,
  368. g_dwProvType,
  369. CRYPT_DELETEKEYSET |
  370. ( g_dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE ?
  371. CRYPT_MACHINE_KEYSET : 0 ));
  372. fResult = TRUE;
  373. goto CommonReturn;
  374. }
  375. //
  376. // Get access to the subject's (public) key, creating it if necessary
  377. //
  378. if (!GetPublicKey(hSubjectProv, &pAllocSubjectPubKeyInfo))
  379. goto ErrorReturn;
  380. pSubjectPubKeyInfo = pAllocSubjectPubKeyInfo;
  381. //
  382. // Encode the subject name
  383. //
  384. if (!EncodeSubject(&pbSubjectEncoded, &cbSubjectEncoded))
  385. goto ErrorReturn;
  386. //
  387. // Get access to the issuer's (private) key
  388. //
  389. hIssuerProv= GetRootProv(&pwszTmpIssuerContainer);
  390. if (NULL == (pIssuerCertContext = GetRootCertContext()))
  391. goto ErrorReturn;
  392. pIssuerCert = pIssuerCertContext->pCertInfo;
  393. if (!VerifyIssuerKey(hIssuerProv, &pIssuerCert->SubjectPublicKeyInfo))
  394. goto ErrorReturn;
  395. //
  396. // Update the CERT_INFO
  397. //
  398. ClearStruct(&Cert);
  399. Cert.dwVersion = CERT_V3;
  400. CoCreateGuid(&SerialNumber);
  401. Cert.SerialNumber.pbData = (BYTE *) &SerialNumber;
  402. Cert.SerialNumber.cbData = sizeof(SerialNumber);
  403. Cert.SignatureAlgorithm = SignatureAlgorithm;
  404. Cert.Issuer.pbData = pIssuerCert->Subject.pbData;
  405. Cert.Issuer.cbData = pIssuerCert->Subject.cbData;
  406. {
  407. SYSTEMTIME st;
  408. // Valid starting now...
  409. GetSystemTimeAsFileTime(&Cert.NotBefore);
  410. // Ending in 2039 (arbitrarily)
  411. ClearStruct(&st);
  412. st.wYear = 2039;
  413. st.wMonth = 12;
  414. st.wDay = 31;
  415. st.wHour = 23;
  416. st.wMinute= 59;
  417. st.wSecond= 59;
  418. SystemTimeToFileTime(&st, &Cert.NotAfter);
  419. }
  420. Cert.Subject.pbData = pbSubjectEncoded;
  421. Cert.Subject.cbData = cbSubjectEncoded;
  422. Cert.SubjectPublicKeyInfo = *pSubjectPubKeyInfo;
  423. // Cert Extensions
  424. if (!CreateEnhancedKeyUsage(
  425. &pbEKUEncoded,
  426. &cbEKUEncoded))
  427. goto ErrorReturn;
  428. rgExt[cExt].pszObjId = szOID_ENHANCED_KEY_USAGE;
  429. rgExt[cExt].fCritical = FALSE;
  430. rgExt[cExt].Value.pbData = pbEKUEncoded;
  431. rgExt[cExt].Value.cbData = cbEKUEncoded;
  432. cExt++;
  433. if (g_wszSubjectDisplayName) {
  434. if (!CreateSpcCommonName(
  435. &pbSpcCommonNameEncoded,
  436. &cbSpcCommonNameEncoded))
  437. goto ErrorReturn;
  438. rgExt[cExt].pszObjId = szOID_COMMON_NAME;
  439. rgExt[cExt].fCritical = FALSE;
  440. rgExt[cExt].Value.pbData = pbSpcCommonNameEncoded;
  441. rgExt[cExt].Value.cbData = cbSpcCommonNameEncoded;
  442. cExt++;
  443. }
  444. Cert.rgExtension = rgExt;
  445. Cert.cExtension = cExt;
  446. //
  447. // Sign and encode the certificate
  448. //
  449. cbCertEncoded = 0;
  450. CryptSignAndEncodeCertificate(
  451. hIssuerProv,
  452. g_dwIssuerKeySpec,
  453. X509_ASN_ENCODING,
  454. X509_CERT_TO_BE_SIGNED,
  455. &Cert,
  456. &Cert.SignatureAlgorithm,
  457. NULL, // pvHashAuxInfo
  458. NULL, // pbEncoded
  459. &cbCertEncoded
  460. );
  461. if (cbCertEncoded == 0) {
  462. ERROR_OUT(("CryptSignAndEncodeCertificate failed: %x", GetLastError()));
  463. goto ErrorReturn;
  464. }
  465. pbCertEncoded = new BYTE[cbCertEncoded];
  466. if (pbCertEncoded == NULL) goto ErrorReturn;
  467. if (!CryptSignAndEncodeCertificate(
  468. hIssuerProv,
  469. g_dwIssuerKeySpec,
  470. X509_ASN_ENCODING,
  471. X509_CERT_TO_BE_SIGNED,
  472. &Cert,
  473. &Cert.SignatureAlgorithm,
  474. NULL, // pvHashAuxInfo
  475. pbCertEncoded,
  476. &cbCertEncoded
  477. )) {
  478. ERROR_OUT(("CryptSignAndEncodeCertificate(2) failed: %x", GetLastError()));
  479. goto ErrorReturn;
  480. }
  481. // Output the encoded certificate to an cerificate store
  482. ASSERT(g_wszSubjectStore);
  483. ASSERT(AT_KEYEXCHANGE == g_dwSubjectKeySpec);
  484. if((!SaveCertToStore(hSubjectProv,
  485. hStore,
  486. g_dwSubjectStoreFlag,
  487. pbCertEncoded,
  488. cbCertEncoded,
  489. g_wszSubjectKey,
  490. g_dwSubjectKeySpec,
  491. g_wszSubjectProviderName,
  492. g_dwProvType)))
  493. {
  494. ERROR_OUT(("SaveCertToStore failed: %x", GetLastError()));
  495. goto ErrorReturn;
  496. }
  497. fResult = TRUE;
  498. goto CommonReturn;
  499. ErrorReturn:
  500. fResult = FALSE;
  501. CommonReturn:
  502. PvkFreeCryptProv(hSubjectProv, g_wszSubjectProviderName,
  503. g_dwProvType,pwszTmpSubjectContainer);
  504. //free the cert store
  505. if(hStore)
  506. CertCloseStore(hStore, 0);
  507. if (pIssuerCertContext)
  508. CertFreeCertificateContext(pIssuerCertContext);
  509. if (pAllocSubjectPubKeyInfo)
  510. delete (pAllocSubjectPubKeyInfo);
  511. if (pbSubjectEncoded)
  512. delete (pbSubjectEncoded);
  513. if (pbEKUEncoded)
  514. delete (pbEKUEncoded);
  515. if (pbSpcCommonNameEncoded)
  516. delete (pbSpcCommonNameEncoded);
  517. if (pbCertEncoded)
  518. delete [] (pbCertEncoded);
  519. if (hIssuerProv)
  520. CryptReleaseContext(hIssuerProv,0);
  521. return fResult;
  522. }
  523. //+-------------------------------------------------------------------------
  524. // save the certificate to a certificate store. Attach private key information
  525. // to the certificate
  526. //--------------------------------------------------------------------------
  527. BOOL SaveCertToStore(
  528. HCRYPTPROV hProv,
  529. HCERTSTORE hStore, DWORD dwFlag,
  530. BYTE *pbEncodedCert, DWORD cbEncodedCert,
  531. LPWSTR wszPvk,
  532. DWORD dwKeySpecification,
  533. LPWSTR wszCapiProv, DWORD dwCapiProvType)
  534. {
  535. BOOL fResult=FALSE;
  536. PCCERT_CONTEXT pCertContext=NULL;
  537. CRYPT_KEY_PROV_INFO KeyProvInfo;
  538. HCRYPTPROV hDefaultProvName=NULL;
  539. DWORD cbData=0;
  540. LPSTR pszName=NULL;
  541. LPWSTR pwszName=NULL;
  542. WCHAR *pwszFriendlyName = NULL;
  543. //init
  544. ClearStruct(&KeyProvInfo);
  545. //add the encoded certificate to store
  546. if(!CertAddEncodedCertificateToStore(
  547. hStore,
  548. X509_ASN_ENCODING,
  549. pbEncodedCert,
  550. cbEncodedCert,
  551. CERT_STORE_ADD_REPLACE_EXISTING,
  552. &pCertContext))
  553. goto CLEANUP;
  554. //add properties to the certificate
  555. KeyProvInfo.pwszContainerName=wszPvk;
  556. KeyProvInfo.pwszProvName=wszCapiProv,
  557. KeyProvInfo.dwProvType=dwCapiProvType,
  558. KeyProvInfo.dwKeySpec=dwKeySpecification;
  559. if ( g_dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE )
  560. {
  561. // If this is a local machine cert, set the keyset flags
  562. // indicating that the private key will be under HKLM
  563. KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
  564. }
  565. ASSERT(AT_KEYEXCHANGE == dwKeySpecification);
  566. //if wszCapiProv is NULL, we get the default provider name
  567. if(NULL==wszCapiProv)
  568. {
  569. //get the default provider
  570. if(CryptAcquireContext(&hDefaultProvName,
  571. NULL,
  572. NULL,
  573. KeyProvInfo.dwProvType,
  574. CRYPT_VERIFYCONTEXT))
  575. {
  576. //get the provider name
  577. if(CryptGetProvParam(hDefaultProvName,
  578. PP_NAME,
  579. NULL,
  580. &cbData,
  581. 0) && (0!=cbData))
  582. {
  583. if(pszName= new CHAR[cbData])
  584. {
  585. if(CryptGetProvParam(hDefaultProvName,
  586. PP_NAME,
  587. (BYTE *)pszName,
  588. &cbData,
  589. 0))
  590. {
  591. pwszName= AnsiToUnicode(pszName);
  592. KeyProvInfo.pwszProvName=pwszName;
  593. }
  594. }
  595. }
  596. }
  597. }
  598. //free the provider as we want
  599. if(hDefaultProvName)
  600. CryptReleaseContext(hDefaultProvName, 0);
  601. hDefaultProvName=NULL;
  602. //add property related to the key container
  603. if(!CertSetCertificateContextProperty(
  604. pCertContext,
  605. CERT_KEY_PROV_INFO_PROP_ID,
  606. 0,
  607. &KeyProvInfo))
  608. goto CLEANUP;
  609. //
  610. // Load the display name from resource and create a blob to
  611. // set the cert friendly name.
  612. //
  613. CHAR szFriendlyName[128];
  614. if (!LoadString(hModule, IDS_DEFNAME, szFriendlyName,
  615. sizeof(szFriendlyName)))
  616. {
  617. ERROR_OUT(("LoadString failed: %d", GetLastError()));
  618. goto CLEANUP;
  619. }
  620. pwszFriendlyName = AnsiToUnicode ( szFriendlyName );
  621. if ( NULL == pwszFriendlyName )
  622. {
  623. ERROR_OUT(("AnsiToUnicode failed"));
  624. goto CLEANUP;
  625. }
  626. CRYPT_DATA_BLOB FriendlyName;
  627. FriendlyName.pbData = (PBYTE)pwszFriendlyName;
  628. FriendlyName.cbData = ( lstrlenW(pwszFriendlyName) + 1 ) *
  629. sizeof(WCHAR);
  630. if(!CertSetCertificateContextProperty(
  631. pCertContext,
  632. CERT_FRIENDLY_NAME_PROP_ID,
  633. 0,
  634. &FriendlyName))
  635. goto CLEANUP;
  636. //
  637. // Add magic ID
  638. //
  639. CRYPT_DATA_BLOB MagicBlob;
  640. DWORD dwMagic;
  641. dwMagic = NMMKCERT_MAGIC;
  642. MagicBlob.pbData = (PBYTE)&dwMagic;
  643. MagicBlob.cbData = sizeof(dwMagic);
  644. if(!CertSetCertificateContextProperty(
  645. pCertContext,
  646. CERT_FIRST_USER_PROP_ID,
  647. 0,
  648. &MagicBlob))
  649. goto CLEANUP;
  650. fResult=TRUE;
  651. CLEANUP:
  652. if (pwszFriendlyName)
  653. delete [] pwszFriendlyName;
  654. //free the cert context
  655. if(pCertContext)
  656. CertFreeCertificateContext(pCertContext);
  657. if(pszName)
  658. delete [] (pszName);
  659. if(pwszName)
  660. delete [] pwszName;
  661. if(hDefaultProvName)
  662. CryptReleaseContext(hDefaultProvName, 0);
  663. return fResult;
  664. }
  665. //+-------------------------------------------------------------------------
  666. // Verify the issuer's certificate. The public key in the certificate
  667. // must match the public key associated with the private key in the
  668. // issuer's provider
  669. //--------------------------------------------------------------------------
  670. BOOL VerifyIssuerKey(
  671. IN HCRYPTPROV hProv,
  672. IN PCERT_PUBLIC_KEY_INFO pIssuerKeyInfo
  673. )
  674. {
  675. BOOL fResult;
  676. PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL;
  677. DWORD cbPubKeyInfo;
  678. // Get issuer's public key
  679. cbPubKeyInfo = 0;
  680. CryptExportPublicKeyInfo(
  681. hProv,
  682. g_dwIssuerKeySpec,
  683. X509_ASN_ENCODING,
  684. NULL, // pPubKeyInfo
  685. &cbPubKeyInfo
  686. );
  687. if (cbPubKeyInfo == 0)
  688. {
  689. ERROR_OUT(("CryptExportPublicKeyInfo failed: %x", GetLastError()));
  690. goto ErrorReturn;
  691. }
  692. if (NULL == (pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) new BYTE[cbPubKeyInfo]))
  693. goto ErrorReturn;
  694. if (!CryptExportPublicKeyInfo(
  695. hProv,
  696. g_dwIssuerKeySpec,
  697. X509_ASN_ENCODING,
  698. pPubKeyInfo,
  699. &cbPubKeyInfo
  700. )) {
  701. ERROR_OUT(("CrypteExportPublicKeyInfo(2) failed: %x", GetLastError()));
  702. goto ErrorReturn;
  703. }
  704. if (!CertComparePublicKeyInfo(
  705. X509_ASN_ENCODING,
  706. pIssuerKeyInfo,
  707. pPubKeyInfo)) {
  708. // BUGBUG:: This might be the test root with an incorrectly
  709. // encoded public key. Convert to the capi representation and
  710. // compare.
  711. BYTE rgProvKey[256]; //BUGBUG needs appropriate constant or calc
  712. BYTE rgCertKey[256]; //BUGBUG needs appropriate constant or calc
  713. DWORD cbProvKey = sizeof(rgProvKey);
  714. DWORD cbCertKey = sizeof(rgCertKey);
  715. if (!CryptDecodeObject(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB,
  716. pIssuerKeyInfo->PublicKey.pbData,
  717. pIssuerKeyInfo->PublicKey.cbData,
  718. 0, // dwFlags
  719. rgProvKey,
  720. &cbProvKey) ||
  721. !CryptDecodeObject(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB,
  722. pPubKeyInfo->PublicKey.pbData,
  723. pPubKeyInfo->PublicKey.cbData,
  724. 0, // dwFlags
  725. rgCertKey,
  726. &cbCertKey) ||
  727. cbProvKey == 0 || cbProvKey != cbCertKey ||
  728. memcmp(rgProvKey, rgCertKey, cbProvKey) != 0) {
  729. ERROR_OUT(("mismatch: %x", GetLastError()));
  730. goto ErrorReturn;
  731. }
  732. }
  733. fResult = TRUE;
  734. goto CommonReturn;
  735. ErrorReturn:
  736. fResult = FALSE;
  737. CommonReturn:
  738. if (pPubKeyInfo)
  739. delete [] (pPubKeyInfo);
  740. return fResult;
  741. }
  742. //+-------------------------------------------------------------------------
  743. // Get the subject's private key provider
  744. //--------------------------------------------------------------------------
  745. HCRYPTPROV GetSubjectProv(OUT LPWSTR *ppwszTmpContainer)
  746. {
  747. HCRYPTPROV hProv=0;
  748. WCHAR wszKeyName[40] = L"Subject Key";
  749. int ids;
  750. WCHAR *wszRegKeyName=NULL;
  751. BOOL fResult;
  752. HCRYPTKEY hKey=NULL;
  753. GUID TmpContainerUuid;
  754. //try to get the hProv from the private key container
  755. if(S_OK != PvkGetCryptProv(NULL,
  756. wszKeyName,
  757. g_wszSubjectProviderName,
  758. g_dwProvType,
  759. NULL,
  760. g_wszSubjectKey,
  761. &g_dwSubjectKeySpec,
  762. ppwszTmpContainer,
  763. &hProv))
  764. hProv=0;
  765. //generate the private keys
  766. if (0 == hProv)
  767. {
  768. //now that we have to generate private keys, generate
  769. //AT_KEYEXCHANGE key
  770. // If there is an existing container with the name of the
  771. // one we are about to create, attempt to delete it first so
  772. // that creating it won't fail. This should only happen if the
  773. // container exists but we were unable to acquire a context to
  774. // it previously.
  775. CryptAcquireContextU(
  776. &hProv,
  777. g_wszSubjectKey,
  778. g_wszSubjectProviderName,
  779. g_dwProvType,
  780. CRYPT_DELETEKEYSET |
  781. ( g_dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE ?
  782. CRYPT_MACHINE_KEYSET : 0 ));
  783. // Open a new key container
  784. if (!CryptAcquireContextU(
  785. &hProv,
  786. g_wszSubjectKey,
  787. g_wszSubjectProviderName,
  788. g_dwProvType,
  789. CRYPT_NEWKEYSET |
  790. ( g_dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE ?
  791. CRYPT_MACHINE_KEYSET : 0 )))
  792. {
  793. ERROR_OUT(("CryptAcquireContext failed: %x", GetLastError()));
  794. goto CreateKeyError;
  795. }
  796. //generate new keys in the key container - make sure its EXPORTABLE
  797. //for SCHANNEL! (Note: remove that when SCHANNEL no longer needs it).
  798. if (!CryptGenKey( hProv, g_dwSubjectKeySpec, CRYPT_EXPORTABLE, &hKey))
  799. {
  800. ERROR_OUT(("CryptGenKey failed: %x", GetLastError()));
  801. goto CreateKeyError;
  802. }
  803. else
  804. CryptDestroyKey(hKey);
  805. //try to get the user key
  806. if (CryptGetUserKey( hProv, g_dwSubjectKeySpec, &hKey))
  807. {
  808. CryptDestroyKey(hKey);
  809. }
  810. else
  811. {
  812. // Doesn't have the specified public key
  813. CryptReleaseContext(hProv, 0);
  814. hProv=0;
  815. }
  816. if (0 == hProv )
  817. {
  818. ERROR_OUT(("sub key error: %x", GetLastError()));
  819. goto ErrorReturn;
  820. }
  821. } //hProv==0
  822. goto CommonReturn;
  823. CreateKeyError:
  824. ErrorReturn:
  825. if (hProv)
  826. {
  827. CryptReleaseContext(hProv, 0);
  828. hProv = 0;
  829. }
  830. CommonReturn:
  831. if(wszRegKeyName)
  832. delete (wszRegKeyName);
  833. return hProv;
  834. }
  835. //+-------------------------------------------------------------------------
  836. // Allocate and get the public key info for the provider
  837. //--------------------------------------------------------------------------
  838. BOOL GetPublicKey(
  839. HCRYPTPROV hProv,
  840. PCERT_PUBLIC_KEY_INFO *ppPubKeyInfo
  841. )
  842. {
  843. BOOL fResult;
  844. PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL;
  845. DWORD cbPubKeyInfo;
  846. cbPubKeyInfo = 0;
  847. CryptExportPublicKeyInfo(
  848. hProv,
  849. g_dwSubjectKeySpec,
  850. X509_ASN_ENCODING,
  851. NULL, // pPubKeyInfo
  852. &cbPubKeyInfo
  853. );
  854. if (cbPubKeyInfo == 0) {
  855. ERROR_OUT(("CryptExportPublicKeyInfo failed: %x", GetLastError()));
  856. goto ErrorReturn;
  857. }
  858. if (NULL == (pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) new BYTE[cbPubKeyInfo]))
  859. goto ErrorReturn;
  860. if (!CryptExportPublicKeyInfo(
  861. hProv,
  862. g_dwSubjectKeySpec,
  863. X509_ASN_ENCODING,
  864. pPubKeyInfo,
  865. &cbPubKeyInfo
  866. )) {
  867. ERROR_OUT(("CryptExportPublicKeyInfo(2) failed: %x", GetLastError()));
  868. goto ErrorReturn;
  869. }
  870. fResult = TRUE;
  871. goto CommonReturn;
  872. ErrorReturn:
  873. fResult = FALSE;
  874. if (pPubKeyInfo) {
  875. delete [] (pPubKeyInfo);
  876. pPubKeyInfo = NULL;
  877. }
  878. CommonReturn:
  879. *ppPubKeyInfo = pPubKeyInfo;
  880. return fResult;
  881. }
  882. //+-------------------------------------------------------------------------
  883. // Convert and encode the subject's X500 formatted name
  884. //--------------------------------------------------------------------------
  885. BOOL EncodeSubject(
  886. OUT BYTE **ppbEncoded,
  887. IN OUT DWORD *pcbEncoded
  888. )
  889. {
  890. BOOL fResult;
  891. DWORD cbEncodedSubject=0;
  892. BYTE *pbEncodedSubject=NULL;
  893. BYTE *pbEncoded = NULL;
  894. DWORD cbEncoded;
  895. //encode the wszSubjectX500Name into an encoded X509_NAME
  896. if(!CertStrToNameW(
  897. X509_ASN_ENCODING,
  898. g_wszSubjectX500Name,
  899. 0,
  900. NULL,
  901. NULL,
  902. &cbEncodedSubject,
  903. NULL))
  904. {
  905. ERROR_OUT(("CertStrToNameW failed: %x", GetLastError()));
  906. goto ErrorReturn;
  907. }
  908. pbEncodedSubject = new BYTE[cbEncodedSubject];
  909. if (pbEncodedSubject == NULL) goto ErrorReturn;
  910. if(!CertStrToNameW(
  911. X509_ASN_ENCODING,
  912. g_wszSubjectX500Name,
  913. 0,
  914. NULL,
  915. pbEncodedSubject,
  916. &cbEncodedSubject,
  917. NULL))
  918. {
  919. ERROR_OUT(("CertStrToNameW(2) failed: %x", GetLastError()));
  920. goto ErrorReturn;
  921. }
  922. cbEncoded=cbEncodedSubject;
  923. pbEncoded=pbEncodedSubject;
  924. fResult = TRUE;
  925. goto CommonReturn;
  926. ErrorReturn:
  927. if (pbEncoded) {
  928. delete (pbEncoded);
  929. pbEncoded = NULL;
  930. }
  931. cbEncoded = 0;
  932. fResult = FALSE;
  933. CommonReturn:
  934. *ppbEncoded = pbEncoded;
  935. *pcbEncoded = cbEncoded;
  936. return fResult;
  937. }
  938. // The test root's public key isn't encoded properly in the certificate.
  939. // It's missing a leading zero to make it a unsigned integer.
  940. static BYTE rgbTestRoot[] = {
  941. #include "root.h"
  942. };
  943. static CERT_PUBLIC_KEY_INFO TestRootPublicKeyInfo = {
  944. szOID_RSA_RSA, 0, NULL, sizeof(rgbTestRoot), rgbTestRoot, 0
  945. };
  946. static BYTE rgbTestRootInfoAsn[] = {
  947. #include "rootasn.h"
  948. };
  949. //+-------------------------------------------------------------------------
  950. // X509 Extensions: Allocate and Encode functions
  951. //--------------------------------------------------------------------------
  952. BOOL CreateEnhancedKeyUsage(
  953. OUT BYTE **ppbEncoded,
  954. IN OUT DWORD *pcbEncoded
  955. )
  956. {
  957. BOOL fResult = TRUE;
  958. LPBYTE pbEncoded =NULL;
  959. DWORD cbEncoded;
  960. PCERT_ENHKEY_USAGE pUsage =NULL;
  961. //
  962. // Allocate a cert enhanced key usage structure and fill it in
  963. //
  964. pUsage = (PCERT_ENHKEY_USAGE) new BYTE[sizeof(CERT_ENHKEY_USAGE) +
  965. 2 * sizeof(LPSTR)];
  966. if ( pUsage != NULL )
  967. {
  968. pUsage->cUsageIdentifier = 2;
  969. pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage+sizeof(CERT_ENHKEY_USAGE));
  970. pUsage->rgpszUsageIdentifier[0] = szOID_PKIX_KP_CLIENT_AUTH;
  971. pUsage->rgpszUsageIdentifier[1] = szOID_PKIX_KP_SERVER_AUTH;
  972. }
  973. else
  974. {
  975. fResult = FALSE;
  976. }
  977. //
  978. // Encode the usage
  979. //
  980. if ( fResult == TRUE )
  981. {
  982. fResult = CryptEncodeObject(
  983. X509_ASN_ENCODING,
  984. szOID_ENHANCED_KEY_USAGE,
  985. pUsage,
  986. NULL,
  987. &cbEncoded
  988. );
  989. if ( fResult == TRUE )
  990. {
  991. pbEncoded = new BYTE[cbEncoded];
  992. if ( pbEncoded != NULL )
  993. {
  994. fResult = CryptEncodeObject(
  995. X509_ASN_ENCODING,
  996. szOID_ENHANCED_KEY_USAGE,
  997. pUsage,
  998. pbEncoded,
  999. &cbEncoded
  1000. );
  1001. }
  1002. else
  1003. {
  1004. fResult = FALSE;
  1005. }
  1006. }
  1007. }
  1008. //
  1009. // Cleanup
  1010. //
  1011. delete [] (pUsage);
  1012. if ( fResult == TRUE )
  1013. {
  1014. *ppbEncoded = pbEncoded;
  1015. *pcbEncoded = cbEncoded;
  1016. }
  1017. else
  1018. {
  1019. delete [] (pbEncoded);
  1020. }
  1021. return( fResult );
  1022. }
  1023. BOOL CreateSpcCommonName(
  1024. OUT BYTE **ppbEncoded,
  1025. IN OUT DWORD *pcbEncoded
  1026. )
  1027. {
  1028. BOOL fResult;
  1029. BYTE *pbEncoded = NULL;
  1030. DWORD cbEncoded;
  1031. CERT_NAME_VALUE NameValue;
  1032. NameValue.dwValueType = CERT_RDN_UNICODE_STRING;
  1033. NameValue.Value.pbData = (BYTE *) g_wszSubjectDisplayName;
  1034. NameValue.Value.cbData =0;
  1035. cbEncoded = 0;
  1036. CryptEncodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME_VALUE,
  1037. &NameValue,
  1038. NULL, // pbEncoded
  1039. &cbEncoded
  1040. );
  1041. if (cbEncoded == 0) {
  1042. ERROR_OUT(("CryptEncodeObject failed: %x", GetLastError()));
  1043. goto ErrorReturn;
  1044. }
  1045. pbEncoded = new BYTE[cbEncoded];
  1046. if (pbEncoded == NULL) goto ErrorReturn;
  1047. if (!CryptEncodeObject(X509_ASN_ENCODING, X509_UNICODE_NAME_VALUE,
  1048. &NameValue,
  1049. pbEncoded,
  1050. &cbEncoded
  1051. )) {
  1052. ERROR_OUT(("CryptEncodeObject failed: %x", GetLastError()));
  1053. goto ErrorReturn;
  1054. }
  1055. fResult = TRUE;
  1056. goto CommonReturn;
  1057. ErrorReturn:
  1058. if (pbEncoded) {
  1059. delete [] (pbEncoded);
  1060. pbEncoded = NULL;
  1061. }
  1062. cbEncoded = 0;
  1063. fResult = FALSE;
  1064. CommonReturn:
  1065. *ppbEncoded = pbEncoded;
  1066. *pcbEncoded = cbEncoded;
  1067. return fResult;
  1068. }