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
24 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. certupgr.cxx
  5. Abstract:
  6. Functions used in upgrading server certs from K2 [server cert in metabase] to
  7. Avalanche [server cert in CAPI store].
  8. Author:
  9. Alex Mallet (amallet) 07-Dec-1997
  10. Boyd Multerer (boydm) 20-Jan-1998 Converted to be useful in setup
  11. --*/
  12. #include "stdafx.h"
  13. #include <objbase.h>
  14. #ifndef _CHICAGO_
  15. #include "oidenc.h"
  16. // keyring include
  17. //#include "intrlkey.h"
  18. // This stuff below is moved from above include
  19. #define REQUEST_HEADER_K2B2VERSION 0x0101
  20. #define REQUEST_HEADER_IDENTIFIER 'RHDR'
  21. #define REQUEST_HEADER_CURVERSION 0x0101
  22. typedef struct _KeyRequestHeader
  23. {
  24. DWORD Identifier; // must be 'RHDR'
  25. DWORD Version; // version of header record
  26. DWORD cbSizeOfHeader; // byte count of header. Afterwards is the request.
  27. DWORD cbRequestSize; // size of the request that follows
  28. BOOL fReqSentToOnlineCA;
  29. LONG longRequestID;
  30. BOOL fWaitingForApproval;
  31. char chCA[MAX_PATH];
  32. } KeyRequestHeader, *LPREQUEST_HEADER;
  33. ///--- end of #include "intrlkey.h"
  34. //
  35. //Local includes
  36. //
  37. #include "certupgr.h"
  38. //#include "certtools.h"
  39. // The below define is in some interal schannel header file. John Banes
  40. // told me to just redefine it below as such........ - Boyd
  41. LPCSTR SGC_KEY_SALT = "SGCKEYSALT";
  42. // prototypes
  43. BOOL DecodeAndImportPrivateKey( PBYTE pbEncodedPrivateKey IN,
  44. DWORD cbEncodedPrivateKey IN,
  45. PCHAR pszPassword IN,
  46. PWCHAR pszKeyContainerIN,
  47. CRYPT_KEY_PROV_INFO *pCryptKeyProvInfo );
  48. BOOL UpdateCSPInfo( PCCERT_CONTEXT pcCertContext );
  49. BOOL FImportAndStoreRequest( PCCERT_CONTEXT pCert, PVOID pbPKCS10req, DWORD cbPKCS10req );
  50. //-------------------------------------------------------------------------
  51. PCCERT_CONTEXT CopyKRCertToCAPIStore_A( PVOID pbPrivateKey, DWORD cbPrivateKey,
  52. PVOID pbPublicKey, DWORD cbPublicKey,
  53. PVOID pbPKCS10req, DWORD cbPKCS10req,
  54. PCHAR pszPassword,
  55. PCHAR pszCAPIStore,
  56. BOOL bOverWrite)
  57. {
  58. PCCERT_CONTEXT pCert = NULL;
  59. // prep the wide strings
  60. PWCHAR pszwCAPIStore = NULL;
  61. DWORD lenStore = (strlen(pszCAPIStore)+1) * sizeof(WCHAR);
  62. pszwCAPIStore = (PWCHAR)GlobalAlloc( GPTR, lenStore );
  63. if ( !pszwCAPIStore )
  64. goto cleanup;
  65. // convert the strings
  66. MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszCAPIStore, -1, pszwCAPIStore, lenStore );
  67. // do the real call
  68. pCert = CopyKRCertToCAPIStore_W(
  69. pbPrivateKey, cbPrivateKey,
  70. pbPublicKey, cbPublicKey,
  71. pbPKCS10req, cbPKCS10req,
  72. pszPassword,
  73. pszwCAPIStore,
  74. bOverWrite);
  75. cleanup:
  76. // preserve the last error state
  77. DWORD err = GetLastError();
  78. // clean up the strings
  79. if ( pszwCAPIStore )
  80. GlobalFree( pszwCAPIStore );
  81. // reset the last error state
  82. SetLastError( err );
  83. // return the cert
  84. return pCert;
  85. }
  86. //--------------------------------------------------------------------------------------------
  87. // Copies an old Key-Ring style cert to the CAPI store. This cert comes in as two binaries and a password.
  88. PCCERT_CONTEXT CopyKRCertToCAPIStore_W( PVOID pbPrivateKey, DWORD cbPrivateKey,
  89. PVOID pbPublicKey, DWORD cbPublicKey,
  90. PVOID pbPKCS10req, DWORD cbPKCS10req,
  91. PCHAR pszPassword,
  92. PWCHAR pszCAPIStore,
  93. BOOL bOverWrite)
  94. /*++
  95. Routine Description:
  96. Upgrades K2 server certs to Avalanche server certs - reads server cert out of K2
  97. metabase, creates cert context and stores it in CAPI2 "MY" store and writes
  98. relevant information back to metabase.
  99. Arguments:
  100. pMDObject - pointer to Metabase object
  101. pszOldMBPath - path to where server cert is stored in old MB, relative to SSL_W3_KEYS_MD_PATH
  102. pszNewMBPath - fully qualified path to where server cert info should be stored in new MB
  103. Returns:
  104. BOOL indicating success/failure
  105. --*/
  106. {
  107. BOOL fSuccess = FALSE;
  108. HCERTSTORE hStore = NULL;
  109. PCCERT_CONTEXT pcCertContext = NULL;
  110. LPOLESTR polestr = NULL;
  111. // start by opening the CAPI store that we will be saving the certificate into
  112. hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM,
  113. 0,
  114. NULL,
  115. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  116. pszCAPIStore );
  117. if ( !hStore )
  118. {
  119. // iisDebugOut((_T("Error 0x%x calling CertOpenStore \n"), GetLastError());
  120. goto EndUpgradeServerCert;
  121. }
  122. // at this point we check to see if a certificate was passed in. If none was, then we need
  123. // to create a dummy-temporary certificate that markes the private key as incomplete. That
  124. // way, then the real certificate comes back from verisign the regular tools can be used
  125. // to complete the key.
  126. //CertCreateSelfSignCertificate()
  127. //
  128. //Create cert context to be stored in CAPI store
  129. //
  130. pbPublicKey = (PVOID)((PBYTE)pbPublicKey + CERT_DER_PREFIX);
  131. cbPublicKey -= CERT_DER_PREFIX;
  132. pcCertContext = CertCreateCertificateContext( X509_ASN_ENCODING, (PUCHAR)pbPublicKey, cbPublicKey);
  133. if ( pcCertContext )
  134. {
  135. // the private key gets stored in a seperate location from the certificate and gets referred to
  136. // by the certificate. We should try to pick a unique name so that some other cert won't step
  137. // on it by accident. There is no formal format for this name whatsoever. Some groups use a
  138. // human-readable string, some use a hash of the cert, and some use a GUID string. All are valid
  139. // although for generated certs the hash or the GUID are probably better.
  140. // get the 128 big md5 hash of the cert for the name
  141. DWORD dwHashSize;
  142. BOOL fHash;
  143. BYTE MD5Hash[16]; // give it some extra size
  144. dwHashSize = sizeof(MD5Hash);
  145. fHash = CertGetCertificateContextProperty( pcCertContext,
  146. CERT_MD5_HASH_PROP_ID,
  147. (VOID *) MD5Hash,
  148. &dwHashSize );
  149. // Since the MD5 hash is the same size as a guid, we can use the guid utilities to make a
  150. // nice string out of it.
  151. HRESULT hresult;
  152. hresult = StringFromCLSID( (REFCLSID)MD5Hash, &polestr );
  153. //
  154. // Now decode private key blob and import it into CAPI1 private key
  155. //
  156. CRYPT_KEY_PROV_INFO CryptKeyProvInfo;
  157. if ( DecodeAndImportPrivateKey( (PUCHAR)pbPrivateKey, cbPrivateKey, pszPassword,
  158. polestr, &CryptKeyProvInfo ) )
  159. {
  160. //
  161. // Add the private key to the cert context
  162. //
  163. BOOL f;
  164. f = CertSetCertificateContextProperty( pcCertContext, CERT_KEY_PROV_INFO_PROP_ID,
  165. 0, &CryptKeyProvInfo );
  166. f = UpdateCSPInfo( pcCertContext );
  167. if ( f )
  168. {
  169. //
  170. // Store it in the provided store
  171. //
  172. if (bOverWrite)
  173. {
  174. if ( CertAddCertificateContextToStore( hStore, pcCertContext,
  175. CERT_STORE_ADD_REPLACE_EXISTING, NULL ) )
  176. {
  177. fSuccess = TRUE;
  178. // Write out the original request as a property on the cert
  179. FImportAndStoreRequest( pcCertContext, pbPKCS10req, cbPKCS10req );
  180. }
  181. else
  182. {
  183. // iisDebugOut((_T("Error 0x%x calling CertAddCertificateContextToStore"), GetLastError());
  184. }
  185. }
  186. else
  187. {
  188. if ( CertAddCertificateContextToStore( hStore, pcCertContext,
  189. CERT_STORE_ADD_NEW, NULL ) )
  190. {
  191. fSuccess = TRUE;
  192. // Write out the original request as a property on the cert
  193. FImportAndStoreRequest( pcCertContext, pbPKCS10req, cbPKCS10req );
  194. }
  195. else
  196. {
  197. // iisDebugOut((_T("Error 0x%x calling CertAddCertificateContextToStore"), GetLastError());
  198. }
  199. }
  200. }
  201. else
  202. {
  203. // iisDebugOut((_T("Error 0x%x calling CertSetCertificateContextProperty"), GetLastError());
  204. }
  205. }
  206. }
  207. else
  208. {
  209. // iisDebugOut((_T("Error 0x%x calling CertCreateCertificateContext"), GetLastError());
  210. }
  211. //
  212. //Cleanup that's done only on failure
  213. //
  214. if ( !fSuccess )
  215. {
  216. if ( pcCertContext )
  217. {
  218. CertFreeCertificateContext( pcCertContext );
  219. }
  220. pcCertContext = NULL;
  221. }
  222. EndUpgradeServerCert:
  223. // cleanup
  224. if ( hStore )
  225. CertCloseStore ( hStore, 0 );
  226. if ( polestr )
  227. CoTaskMemFree( polestr );
  228. // return the answer
  229. return pcCertContext;
  230. }
  231. //--------------------------------------------------------------------------------------------
  232. BOOL UpdateCSPInfo( PCCERT_CONTEXT pcCertContext )
  233. {
  234. BYTE cbData[1000];
  235. CRYPT_KEY_PROV_INFO* pProvInfo = (CRYPT_KEY_PROV_INFO *) cbData;
  236. DWORD dwFoo = 1000;
  237. BOOL fSuccess = TRUE;
  238. if ( ! CertGetCertificateContextProperty( pcCertContext,
  239. CERT_KEY_PROV_INFO_PROP_ID,
  240. pProvInfo,
  241. &dwFoo ) )
  242. {
  243. fSuccess = FALSE;
  244. // iisDebugOut((_T("Fudge. failed to get property : 0x%x"), GetLastError());
  245. }
  246. else
  247. {
  248. pProvInfo->dwProvType = PROV_RSA_SCHANNEL;
  249. pProvInfo->pwszProvName = NULL;
  250. if ( !CertSetCertificateContextProperty( pcCertContext,
  251. CERT_KEY_PROV_INFO_PROP_ID,
  252. 0,
  253. pProvInfo ) )
  254. {
  255. fSuccess = FALSE;
  256. // iisDebugOut((_T("Fudge. failed to set property : 0x%x"), GetLastError());
  257. }
  258. }
  259. // return success
  260. return fSuccess;
  261. }
  262. //--------------------------------------------------------------------------------------------
  263. BOOL DecodeAndImportPrivateKey( PBYTE pbEncodedPrivateKey IN,
  264. DWORD cbEncodedPrivateKey IN,
  265. PCHAR pszPassword IN,
  266. PWCHAR pszKeyContainer IN,
  267. CRYPT_KEY_PROV_INFO *pCryptKeyProvInfo )
  268. /*++
  269. Routine Description:
  270. Converts the private key stored in the metabase, in Schannel-internal format,
  271. into a key that can be imported via CryptImportKey() to create a CAP1 key blob.
  272. Arguments:
  273. pbEncodedPrivateKey - pointer to [encoded] private key
  274. cbEncodedPrivateKey - size of encoded private key blob
  275. pszPassword - password used to encode private key
  276. pszKeyContainer - container name for private key
  277. pCryptKeyProvInfo - pointer to CRYPT_KEY_PROV_INFO structure filled in on success
  278. Returns:
  279. BOOL indicating success/failure
  280. --*/
  281. {
  282. BOOL fSuccess = FALSE;
  283. DWORD cbPassword = strlen(pszPassword);
  284. PPRIVATE_KEY_FILE_ENCODE pPrivateFile = NULL;
  285. DWORD cbPrivateFile = 0;
  286. MD5_CTX md5Ctx;
  287. struct RC4_KEYSTRUCT rc4Key;
  288. DWORD i;
  289. HCRYPTPROV hProv = NULL;
  290. HCRYPTKEY hPrivateKey = NULL;
  291. DWORD cbDecodedPrivateKey = 0;
  292. PBYTE pbDecodedPrivateKey = NULL;
  293. DWORD err;
  294. //
  295. //HACK HACK HACK - need to make sure Schannel is initialized, so it registers
  296. //its custom decoders, which we make use of in the following code. So, make a
  297. //bogus call to an Schannel function
  298. // Note: on NT5, the AcquireCredentialsHandle operates in the lsass process and
  299. // thus will not properly initialize the stuff we need in our process. Thus we
  300. // call SslGenerateRandomBits instead.
  301. //
  302. DWORD dw;
  303. SslGenerateRandomBits( (PUCHAR)&dw, sizeof(dw) );
  304. // We have to do a little fixup here. Old versions of
  305. // schannel wrote the wrong header data into the ASN
  306. // for private key files, so we must fix the size data.
  307. pbEncodedPrivateKey[2] = (BYTE) (((cbEncodedPrivateKey - 4) & 0xFF00) >> 8); //Get MSB
  308. pbEncodedPrivateKey[3] = (BYTE) ((cbEncodedPrivateKey - 4) & 0xFF); //Get LSB
  309. //
  310. // ASN.1 decode the private key.
  311. //
  312. //
  313. // Figure out the size of the buffer needed
  314. //
  315. if( !CryptDecodeObject(X509_ASN_ENCODING,
  316. szPrivateKeyFileEncode,
  317. pbEncodedPrivateKey,
  318. cbEncodedPrivateKey,
  319. 0,
  320. NULL,
  321. &cbPrivateFile) )
  322. {
  323. err = GetLastError();
  324. // iisDebugOut((_T("Error 0x%x decoding the private key"), err);
  325. goto EndDecodeKey;
  326. }
  327. pPrivateFile = (PPRIVATE_KEY_FILE_ENCODE) LocalAlloc( LPTR, cbPrivateFile );
  328. if(pPrivateFile == NULL)
  329. {
  330. SetLastError( ERROR_OUTOFMEMORY );
  331. goto EndDecodeKey;
  332. }
  333. //
  334. // Actually fill in the buffer
  335. //
  336. if( !CryptDecodeObject( X509_ASN_ENCODING,
  337. szPrivateKeyFileEncode,
  338. pbEncodedPrivateKey,
  339. cbEncodedPrivateKey,
  340. 0,
  341. pPrivateFile,
  342. &cbPrivateFile ) )
  343. {
  344. err = GetLastError();
  345. // iisDebugOut((_T("Error 0x%x decoding the private key"), err);
  346. goto EndDecodeKey;
  347. }
  348. //
  349. // Decrypt the decoded private key using the password.
  350. //
  351. MD5Init(&md5Ctx);
  352. MD5Update(&md5Ctx, (PBYTE) pszPassword, cbPassword);
  353. MD5Final(&md5Ctx);
  354. rc4_key( &rc4Key, 16, md5Ctx.digest );
  355. // memset( &md5Ctx, 0, sizeof(md5Ctx) );
  356. rc4( &rc4Key,
  357. pPrivateFile->EncryptedBlob.cbData,
  358. pPrivateFile->EncryptedBlob.pbData );
  359. //
  360. // Build a PRIVATEKEYBLOB from the decrypted private key.
  361. //
  362. //
  363. // Figure out size of buffer needed
  364. //
  365. if( !CryptDecodeObject( X509_ASN_ENCODING,
  366. szPrivateKeyInfoEncode,
  367. pPrivateFile->EncryptedBlob.pbData,
  368. pPrivateFile->EncryptedBlob.cbData,
  369. 0,
  370. NULL,
  371. &cbDecodedPrivateKey ) )
  372. {
  373. // NOTE: This stuff is complicated!!! The following code came
  374. // from John Banes. Heck this whole routine pretty much came
  375. // from John Banes. -- Boyd
  376. // Maybe this was a SGC style key.
  377. // Re-encrypt it, and build the SGC decrypting
  378. // key, and re-decrypt it.
  379. BYTE md5Digest[MD5DIGESTLEN];
  380. rc4_key(&rc4Key, 16, md5Ctx.digest);
  381. rc4(&rc4Key,
  382. pPrivateFile->EncryptedBlob.cbData,
  383. pPrivateFile->EncryptedBlob.pbData);
  384. CopyMemory(md5Digest, md5Ctx.digest, MD5DIGESTLEN);
  385. MD5Init(&md5Ctx);
  386. MD5Update(&md5Ctx, md5Digest, MD5DIGESTLEN);
  387. MD5Update(&md5Ctx, (PUCHAR)SGC_KEY_SALT, strlen(SGC_KEY_SALT));
  388. MD5Final(&md5Ctx);
  389. rc4_key(&rc4Key, 16, md5Ctx.digest);
  390. rc4(&rc4Key,
  391. pPrivateFile->EncryptedBlob.cbData,
  392. pPrivateFile->EncryptedBlob.pbData);
  393. // Try again...
  394. if(!CryptDecodeObject(X509_ASN_ENCODING,
  395. szPrivateKeyInfoEncode,
  396. pPrivateFile->EncryptedBlob.pbData,
  397. pPrivateFile->EncryptedBlob.cbData,
  398. 0,
  399. NULL,
  400. &cbDecodedPrivateKey))
  401. {
  402. ZeroMemory(&md5Ctx, sizeof(md5Ctx));
  403. err = GetLastError();
  404. goto EndDecodeKey;
  405. }
  406. }
  407. pbDecodedPrivateKey = (PBYTE) LocalAlloc( LPTR, cbDecodedPrivateKey );
  408. if( pbDecodedPrivateKey == NULL )
  409. {
  410. SetLastError( ERROR_OUTOFMEMORY );
  411. goto EndDecodeKey;
  412. }
  413. //
  414. // Actually fill in the buffer
  415. //
  416. if( !CryptDecodeObject( X509_ASN_ENCODING,
  417. szPrivateKeyInfoEncode,
  418. pPrivateFile->EncryptedBlob.pbData,
  419. pPrivateFile->EncryptedBlob.cbData,
  420. 0,
  421. pbDecodedPrivateKey,
  422. &cbDecodedPrivateKey ) )
  423. {
  424. err = GetLastError();
  425. // iisDebugOut((_T("Error 0x%x decoding the private key"), err);
  426. goto EndDecodeKey;
  427. }
  428. // On NT 4 the ff holds true : <- from Alex Mallet
  429. // Although key is going to be used for key exchange, mark it as being
  430. // used for signing, because only 512-bit key exchange keys are supported
  431. // in the non-domestic rsabase.dll, whereas signing keys can be up to
  432. // 2048 bits.
  433. //
  434. // On NT 5, PROV_RSA_FULL should be changed to PROV_RSA_SCHANNEL, and
  435. // aiKeyAlg to CALG_RSA_KEYX, because PROV_RSA_SCHANNEL, which is only
  436. // installed on NT 5, supports 1024-bit private keys for key exchange
  437. //
  438. // On NT4, Schannel doesn't care whether a key is marked for signing or exchange,
  439. // but on NT5 it does, so aiKeyAlg must be set appropriately
  440. //
  441. ((BLOBHEADER *) pbDecodedPrivateKey)->aiKeyAlg = CALG_RSA_KEYX;
  442. //
  443. // Clean out the key container, pszKeyContainer
  444. //
  445. CryptAcquireContext(&hProv,
  446. pszKeyContainer,
  447. NULL,
  448. PROV_RSA_SCHANNEL,
  449. CRYPT_DELETEKEYSET | CRYPT_MACHINE_KEYSET);
  450. //
  451. // Create a CryptoAPI key container in which to store the key.
  452. //
  453. if( !CryptAcquireContext( &hProv,
  454. pszKeyContainer,
  455. NULL,
  456. PROV_RSA_SCHANNEL,
  457. CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
  458. {
  459. err = GetLastError();
  460. // iisDebugOut((_T("Error 0x%x calling CryptAcquireContext"), err);
  461. goto EndDecodeKey;
  462. }
  463. //
  464. // Import the private key blob into the key container.
  465. //
  466. if( !CryptImportKey( hProv,
  467. pbDecodedPrivateKey,
  468. cbDecodedPrivateKey,
  469. 0,
  470. CRYPT_EXPORTABLE, //so we can export it later
  471. &hPrivateKey ) )
  472. {
  473. err = GetLastError();
  474. // iisDebugOut((_T("Error 0x%x importing PRIVATEKEYBLOB"), err);
  475. goto EndDecodeKey;
  476. }
  477. //
  478. // Fill in the CRYPT_KEY_PROV_INFO structure, with the same parameters we
  479. // used in the call to CryptAcquireContext() above
  480. //
  481. //
  482. // container name in the structure is a unicode string, so we need to convert
  483. //
  484. if ( pszKeyContainer != NULL )
  485. {
  486. // point the key container name to the passed in string
  487. // WARNING: this does not actually copy the string, just the pointer
  488. // to it. So the strings needs to remain valid until the ProvInfo is commited.
  489. pCryptKeyProvInfo->pwszContainerName = pszKeyContainer;
  490. }
  491. else
  492. {
  493. pCryptKeyProvInfo->pwszContainerName = NULL;
  494. }
  495. pCryptKeyProvInfo->pwszProvName = NULL;
  496. pCryptKeyProvInfo->dwProvType = PROV_RSA_FULL;
  497. pCryptKeyProvInfo->dwFlags = 0x20; // allow the cert to be exchanged
  498. pCryptKeyProvInfo->cProvParam = 0;
  499. pCryptKeyProvInfo->rgProvParam = NULL;
  500. pCryptKeyProvInfo->dwKeySpec = AT_KEYEXCHANGE; // allow the cert to be exchanged
  501. fSuccess = TRUE;
  502. EndDecodeKey:
  503. //
  504. // Clean-up that happens regardless of success/failure
  505. //
  506. if ( pPrivateFile )
  507. {
  508. LocalFree( pPrivateFile );
  509. }
  510. if ( pbDecodedPrivateKey )
  511. {
  512. LocalFree( pbDecodedPrivateKey );
  513. }
  514. if ( hPrivateKey )
  515. {
  516. CryptDestroyKey( hPrivateKey );
  517. }
  518. if ( hProv )
  519. {
  520. CryptReleaseContext( hProv, 0 );
  521. }
  522. return fSuccess;
  523. } //DecodeAndImportPrivateKey
  524. //--------------------------------------------------------------------------------------------
  525. /*++
  526. Routine Description:
  527. Takes an incoming PKCS10 request and saves it as a property attached to the key. It also
  528. checks if the request is in the old internal Keyring format or not......
  529. Arguments:
  530. pCert - CAPI certificate context pointer for the cert to save the request on
  531. pbPKCS10req - pointer to the request
  532. cbPKCS10req - size of the request
  533. Returns:
  534. BOOL indicating success/failure
  535. --*/
  536. BOOL FImportAndStoreRequest( PCCERT_CONTEXT pCert, PVOID pbPKCS10req, DWORD cbPKCS10req )
  537. {
  538. BOOL f;
  539. DWORD err;
  540. // if any NULLS are passed in, fail gracefully
  541. if ( !pCert || !pbPKCS10req || !cbPKCS10req )
  542. return FALSE;
  543. // first, check if the incoming request is actually pointing to an old KeyRing internal
  544. // request format. That just means that the real request is actuall slightly into
  545. // the block. The way you tell is by testing the first DWORD to see it
  546. // is REQUEST_HEADER_IDENTIFIER
  547. // start by seeing if this is a new style key request
  548. LPREQUEST_HEADER pHeader = (LPREQUEST_HEADER)pbPKCS10req;
  549. if ( pHeader->Identifier == REQUEST_HEADER_IDENTIFIER )
  550. {
  551. // update the request pointer and data count
  552. pbPKCS10req = (PBYTE)pbPKCS10req + pHeader->cbSizeOfHeader;
  553. cbPKCS10req = pHeader->cbRequestSize;
  554. }
  555. // now save the request onto the key
  556. CRYPT_DATA_BLOB dataBlob;
  557. ZeroMemory( &dataBlob, sizeof(dataBlob) );
  558. dataBlob.pbData = (PBYTE)pbPKCS10req; // pointer to blob data
  559. dataBlob.cbData = cbPKCS10req; // blob length info
  560. f = CertSetCertificateContextProperty(
  561. pCert,
  562. CERTWIZ_REQUEST_PROP_ID,
  563. 0,
  564. &dataBlob
  565. );
  566. err = GetLastError();
  567. /*
  568. HRESULT hRes = CertTool_SetBinaryBlobProp(
  569. pCert, // cert context to set the prop on
  570. pbPKCS10req, // pointer to blob data
  571. cbPKCS10req, // blob length info
  572. CERTWIZ_REQUEST_PROP_ID,// property ID for context
  573. TRUE // the request is already encoded
  574. );
  575. */
  576. return f;
  577. }
  578. #endif //_CHICAGO_