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.

1592 lines
35 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. key.c
  5. Abstract:
  6. Key manpulators for the IIS cryptographic package.
  7. The following routines are exported by this module:
  8. IISCryptoGetKeyDeriveKey
  9. IISCryptoGetKeyExchangeKey
  10. IISCryptoGetSignatureKey
  11. IISCryptoGenerateSessionKey
  12. IISCryptoCloseKey
  13. IISCryptoExportSessionKeyBlob
  14. IISCryptoExportSessionKeyBlob2
  15. IISCryptoImportSessionKeyBlob
  16. IISCryptoImportSessionKeyBlob2
  17. IISCryptoExportPublicKeyBlob
  18. IISCryptoImportPublicKeyBlob
  19. Author:
  20. Keith Moore (keithmo) 02-Dec-1996
  21. Revision History:
  22. --*/
  23. #include "precomp.h"
  24. #pragma hdrstop
  25. //
  26. // Private constants.
  27. //
  28. //
  29. // Private types.
  30. //
  31. //
  32. // Private globals.
  33. //
  34. //
  35. // Private prototypes.
  36. //
  37. HRESULT
  38. IcpGetKeyHelper(
  39. OUT HCRYPTKEY * phKey,
  40. IN HCRYPTPROV hProv,
  41. IN DWORD dwKeySpec
  42. );
  43. //
  44. // Public functions.
  45. //
  46. HRESULT
  47. WINAPI
  48. IISCryptoGetKeyDeriveKey2(
  49. OUT HCRYPTKEY * phKey,
  50. IN HCRYPTPROV hProv,
  51. IN HCRYPTHASH hHash
  52. )
  53. /*++
  54. Routine Description:
  55. This routine attempts to derive a key from a password in the given
  56. provider.
  57. Arguments:
  58. phKey - Receives the key handle if successful.
  59. hProv - A handle to a crypto service provider.
  60. hHash - A hash object from which the key will be derived
  61. Return Value:
  62. HRESULT - Completion status, 0 if successful, !0 otherwise.
  63. --*/
  64. {
  65. HRESULT hr;
  66. //
  67. // Sanity check.
  68. //
  69. DBG_ASSERT( IcpGlobals.Initialized );
  70. DBG_ASSERT( phKey != NULL );
  71. DBG_ASSERT( hProv != CRYPT_NULL );
  72. DBG_ASSERT( hHash != CRYPT_NULL );
  73. //
  74. // Short-circuit if cryptography is disabled.
  75. //
  76. if( !IcpGlobals.EnableCryptography ) {
  77. if( hProv == DUMMY_HPROV )
  78. {
  79. return NO_ERROR;
  80. }
  81. else
  82. {
  83. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  84. }
  85. }
  86. //
  87. // Create a key based on the hash of the password.
  88. //
  89. IcpAcquireGlobalLock();
  90. if( !CryptDeriveKey(
  91. hProv,
  92. CALG_RC4,
  93. hHash,
  94. CRYPT_EXPORTABLE,
  95. phKey ) )
  96. {
  97. hr = IcpGetLastError();
  98. IcpReleaseGlobalLock();
  99. DBG_ASSERT( FAILED( hr ) );
  100. return hr;
  101. }
  102. IcpReleaseGlobalLock();
  103. return NO_ERROR;
  104. }
  105. HRESULT
  106. WINAPI
  107. IISCryptoGetKeyExchangeKey(
  108. OUT HCRYPTKEY * phKey,
  109. IN HCRYPTPROV hProv
  110. )
  111. /*++
  112. Routine Description:
  113. This routine attempts to open the key exchange key in the given
  114. provider. If the key does not yet exist, this routine will attempt
  115. to create it.
  116. Arguments:
  117. phKey - Receives the key handle if successful.
  118. hProv - A handle to a crypto service provider.
  119. Return Value:
  120. HRESULT - Completion status, 0 if successful, !0 otherwise.
  121. --*/
  122. {
  123. HRESULT result;
  124. //
  125. // Sanity check.
  126. //
  127. DBG_ASSERT( IcpGlobals.Initialized );
  128. DBG_ASSERT( phKey != NULL );
  129. DBG_ASSERT( hProv != CRYPT_NULL );
  130. //
  131. // Let IcpGetKeyHelper() do the dirty work.
  132. //
  133. result = IcpGetKeyHelper(
  134. phKey,
  135. hProv,
  136. AT_KEYEXCHANGE
  137. );
  138. return result;
  139. } // IISCryptoGetKeyExchangeKey
  140. HRESULT
  141. WINAPI
  142. IISCryptoGetSignatureKey(
  143. OUT HCRYPTKEY * phKey,
  144. IN HCRYPTPROV hProv
  145. )
  146. /*++
  147. Routine Description:
  148. This routine attempts to open the signature key in the given provider.
  149. If the key does not yet exist, this routine will attempt to create it.
  150. Arguments:
  151. phKey - Receives the key handle if successful.
  152. hProv - A handle to a crypto service provider.
  153. Return Value:
  154. HRESULT - Completion status, 0 if successful, !0 otherwise.
  155. --*/
  156. {
  157. HRESULT result;
  158. //
  159. // Sanity check.
  160. //
  161. DBG_ASSERT( IcpGlobals.Initialized );
  162. DBG_ASSERT( phKey != NULL );
  163. DBG_ASSERT( hProv != CRYPT_NULL );
  164. //
  165. // Let IcpGetKeyHelper() do the dirty work.
  166. //
  167. result = IcpGetKeyHelper(
  168. phKey,
  169. hProv,
  170. AT_SIGNATURE
  171. );
  172. return result;
  173. } // IISCryptoGetSignatureKey
  174. HRESULT
  175. WINAPI
  176. IISCryptoGenerateSessionKey(
  177. OUT HCRYPTKEY * phKey,
  178. IN HCRYPTPROV hProv
  179. )
  180. /*++
  181. Routine Description:
  182. This routine generates a random session key.
  183. Arguments:
  184. phKey - Receives the key handle if successful.
  185. hProv - A handle to a crypto service provider.
  186. Return Value:
  187. HRESULT - Completion status, 0 if successful, !0 otherwise.
  188. --*/
  189. {
  190. HRESULT result = NO_ERROR;
  191. BOOL status;
  192. //
  193. // Sanity check.
  194. //
  195. DBG_ASSERT( IcpGlobals.Initialized );
  196. DBG_ASSERT( phKey != NULL );
  197. DBG_ASSERT( hProv != CRYPT_NULL );
  198. //
  199. // Short-circuit if cryptography is disabled.
  200. //
  201. if( !IcpGlobals.EnableCryptography ) {
  202. if( hProv == DUMMY_HPROV ) {
  203. *phKey = DUMMY_HSESSIONKEY;
  204. return NO_ERROR;
  205. } else {
  206. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  207. }
  208. }
  209. //
  210. // Generate the key.
  211. //
  212. status = CryptGenKey(
  213. hProv,
  214. CALG_RC4,
  215. CRYPT_EXPORTABLE,
  216. phKey
  217. );
  218. if( !status ) {
  219. result = IcpGetLastError();
  220. }
  221. if( SUCCEEDED(result) )
  222. {
  223. UpdateKeysOpened();
  224. }
  225. else
  226. {
  227. DBGPRINTF(( DBG_CONTEXT,"IISCryptoGenerateSessionKey.CryptGenKey (advapi32.dll) failed err=0x%x.\n",result));
  228. *phKey = CRYPT_NULL;
  229. }
  230. return result;
  231. } // IISCryptoGenerateSessionKey
  232. HRESULT
  233. WINAPI
  234. IISCryptoCloseKey(
  235. IN HCRYPTKEY hKey
  236. )
  237. /*++
  238. Routine Description:
  239. This routine closes the specified key.
  240. Arguments:
  241. hKey - A key handle.
  242. Return Value:
  243. HRESULT - Completion status, 0 if successful, !0 otherwise.
  244. --*/
  245. {
  246. BOOL status;
  247. //
  248. // Sanity check.
  249. //
  250. DBG_ASSERT( IcpGlobals.Initialized );
  251. DBG_ASSERT( hKey != CRYPT_NULL );
  252. //
  253. // Short-circuit if cryptography is disabled.
  254. //
  255. if( !IcpGlobals.EnableCryptography ) {
  256. if( hKey == DUMMY_HSESSIONKEY ||
  257. hKey == DUMMY_HSIGNATUREKEY ||
  258. hKey == DUMMY_HKEYEXCHANGEKEY ) {
  259. return NO_ERROR;
  260. } else {
  261. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  262. }
  263. }
  264. //
  265. // Close the key.
  266. //
  267. status = CryptDestroyKey(
  268. hKey
  269. );
  270. if( status ) {
  271. UpdateKeysClosed();
  272. return NO_ERROR;
  273. }
  274. return IcpGetLastError();
  275. } // IISCryptoCloseKey
  276. HRESULT
  277. WINAPI
  278. IISCryptoExportSessionKeyBlob(
  279. OUT PIIS_CRYPTO_BLOB * ppSessionKeyBlob,
  280. IN HCRYPTPROV hProv,
  281. IN HCRYPTKEY hSessionKey,
  282. IN HCRYPTKEY hKeyExchangeKey
  283. )
  284. /*++
  285. Routine Description:
  286. This routine exports a session key into a secure session key blob.
  287. The blob contains the session key (encrypted with the specified
  288. private key exchange key) and a digital signature (also encrypted).
  289. Arguments:
  290. ppSessionKeyBlob - Will receive a pointer to the newly created
  291. session key blob if successful.
  292. hProv - A handle to a crypto service provider.
  293. hSessionKey - The key to export.
  294. hKeyExchangeKey - The key to use when encrypting the session key.
  295. Return Value:
  296. HRESULT - Completion status, 0 if successful, !0 otherwise.
  297. --*/
  298. {
  299. HRESULT result = NO_ERROR;
  300. BOOL status;
  301. HCRYPTHASH hash;
  302. DWORD keyLength;
  303. DWORD hashLength;
  304. PIC_BLOB blob;
  305. //
  306. // Sanity check.
  307. //
  308. DBG_ASSERT( IcpGlobals.Initialized );
  309. DBG_ASSERT( ppSessionKeyBlob != NULL );
  310. DBG_ASSERT( hProv != CRYPT_NULL );
  311. DBG_ASSERT( hSessionKey != CRYPT_NULL );
  312. DBG_ASSERT( hKeyExchangeKey != CRYPT_NULL );
  313. //
  314. // Short-circuit if cryptography is disabled.
  315. //
  316. if( !IcpGlobals.EnableCryptography ) {
  317. if( hProv == DUMMY_HPROV &&
  318. hSessionKey == DUMMY_HSESSIONKEY &&
  319. hKeyExchangeKey == DUMMY_HKEYEXCHANGEKEY ) {
  320. return IISCryptoCreateCleartextBlob(
  321. ppSessionKeyBlob,
  322. (PVOID)"",
  323. 1
  324. );
  325. } else {
  326. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  327. }
  328. }
  329. //
  330. // Setup our locals so we know how to cleanup on exit.
  331. //
  332. blob = NULL;
  333. hash = CRYPT_NULL;
  334. //
  335. // Determine the required size of the key data.
  336. //
  337. status = CryptExportKey(
  338. hSessionKey,
  339. hKeyExchangeKey,
  340. SIMPLEBLOB,
  341. 0,
  342. NULL,
  343. &keyLength
  344. );
  345. if( !status ) {
  346. result = IcpGetLastError();
  347. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.CryptExportKey (advapi32.dll) failed err=0x%x.\n",result));
  348. goto fatal;
  349. }
  350. //
  351. // Determine the hash data length.
  352. //
  353. result = IcpGetHashLength(
  354. &hashLength,
  355. hProv
  356. );
  357. if( FAILED(result) ) {
  358. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.IcpGetHashLength failed err=0x%x.\n",result));
  359. goto fatal;
  360. }
  361. //
  362. // Create a new blob.
  363. //
  364. blob = IcpCreateBlob(
  365. KEY_BLOB_SIGNATURE,
  366. keyLength,
  367. hashLength
  368. );
  369. if( blob == NULL ) {
  370. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  371. goto fatal;
  372. }
  373. //
  374. // Export the key.
  375. //
  376. status = CryptExportKey(
  377. hSessionKey,
  378. hKeyExchangeKey,
  379. SIMPLEBLOB,
  380. 0,
  381. BLOB_TO_DATA(blob),
  382. &keyLength
  383. );
  384. if( !status ) {
  385. result = IcpGetLastError();
  386. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.CryptExportKey failed err=0x%x.\n",result));
  387. goto fatal;
  388. }
  389. DBG_ASSERT( keyLength == blob->DataLength );
  390. //
  391. // Create a hash object.
  392. //
  393. result = IISCryptoCreateHash(
  394. &hash,
  395. hProv
  396. );
  397. if( FAILED(result) ) {
  398. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.IISCryptoCreateHash failed err=0x%x.\n",result));
  399. goto fatal;
  400. }
  401. //
  402. // Hash the key and generate the signature.
  403. //
  404. status = CryptHashData(
  405. hash,
  406. BLOB_TO_DATA(blob),
  407. keyLength,
  408. 0
  409. );
  410. if( !status ) {
  411. result = IcpGetLastError();
  412. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.CryptHashData failed err=0x%x.\n",result));
  413. goto fatal;
  414. }
  415. status = CryptSignHash(
  416. hash,
  417. AT_SIGNATURE,
  418. NULL,
  419. 0,
  420. BLOB_TO_SIGNATURE(blob),
  421. &hashLength
  422. );
  423. if( !status ) {
  424. result = IcpGetLastError();
  425. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.CryptSignHash failed err=0x%x.\n",result));
  426. goto fatal;
  427. }
  428. DBG_ASSERT( hashLength == blob->SignatureLength );
  429. //
  430. // Success!
  431. //
  432. DBG_ASSERT( IISCryptoIsValidBlob( (PIIS_CRYPTO_BLOB)blob ) );
  433. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  434. *ppSessionKeyBlob = (PIIS_CRYPTO_BLOB)blob;
  435. UpdateBlobsCreated();
  436. return NO_ERROR;
  437. fatal:
  438. if( hash != CRYPT_NULL ) {
  439. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  440. }
  441. if( blob != NULL ) {
  442. IcpFreeMemory( blob );
  443. }
  444. DBG_ASSERT( FAILED(result) );
  445. return result;
  446. } // IISCryptoExportSessionKeyBlob
  447. HRESULT
  448. WINAPI
  449. IISCryptoImportSessionKeyBlob(
  450. OUT HCRYPTKEY * phSessionKey,
  451. IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
  452. IN HCRYPTPROV hProv,
  453. IN HCRYPTKEY hSignatureKey
  454. )
  455. /*++
  456. Routine Description:
  457. This routine takes the specified session key blob and creates the
  458. corresponding session key, iff the encrypted session key can be
  459. decrypted and the digital signature can be validated.
  460. Arguments:
  461. phSessionKey - Receives a pointer to the newly created session key
  462. if successful.
  463. pSessionKeyBlob - Pointer to a key blob created with
  464. IISCryptoExportSessionKeyBlob().
  465. hProv - A handle to a crypto service provider.
  466. hSignatureKey - Handle to the encryption key to use when validating
  467. the digital signature.
  468. Return Value:
  469. HRESULT - Completion status, 0 if successful, !0 otherwise.
  470. --*/
  471. {
  472. HRESULT result = NO_ERROR;
  473. BOOL status;
  474. HCRYPTHASH hash;
  475. PIC_BLOB blob;
  476. //
  477. // Sanity check.
  478. //
  479. DBG_ASSERT( IcpGlobals.Initialized );
  480. DBG_ASSERT( phSessionKey != NULL );
  481. DBG_ASSERT( pSessionKeyBlob != NULL );
  482. DBG_ASSERT( IISCryptoIsValidBlob( pSessionKeyBlob ) );
  483. DBG_ASSERT( hProv != CRYPT_NULL );
  484. DBG_ASSERT( hSignatureKey != CRYPT_NULL );
  485. //
  486. // Short-circuit if cryptography is disabled.
  487. //
  488. if( !IcpGlobals.EnableCryptography ) {
  489. if( hProv == DUMMY_HPROV &&
  490. hSignatureKey == DUMMY_HSIGNATUREKEY &&
  491. pSessionKeyBlob->BlobSignature == CLEARTEXT_BLOB_SIGNATURE
  492. ) {
  493. *phSessionKey = DUMMY_HSESSIONKEY;
  494. return NO_ERROR;
  495. } else {
  496. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  497. }
  498. }
  499. DBG_ASSERT( pSessionKeyBlob->BlobSignature == KEY_BLOB_SIGNATURE );
  500. //
  501. // Setup our locals so we know how to cleanup on exit.
  502. //
  503. hash = CRYPT_NULL;
  504. blob = (PIC_BLOB)pSessionKeyBlob;
  505. //
  506. // Validate the signature.
  507. //
  508. result = IISCryptoCreateHash(
  509. &hash,
  510. hProv
  511. );
  512. if( FAILED(result) ) {
  513. DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlob.IISCryptoCreateHash failed err=0x%x.\n",result));
  514. goto fatal;
  515. }
  516. status = CryptHashData(
  517. hash,
  518. BLOB_TO_DATA(blob),
  519. blob->DataLength,
  520. 0
  521. );
  522. if( !status ) {
  523. result = IcpGetLastError();
  524. DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlob.CryptHashData failed err=0x%x.\n",result));
  525. goto fatal;
  526. }
  527. status = CryptVerifySignature(
  528. hash,
  529. BLOB_TO_SIGNATURE(blob),
  530. blob->SignatureLength,
  531. hSignatureKey,
  532. NULL,
  533. 0
  534. );
  535. if( !status ) {
  536. result = IcpGetLastError();
  537. DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlob.CryptVerifySignature failed err=0x%x.\n",result));
  538. goto fatal;
  539. }
  540. //
  541. // OK, the signature looks good. Import the key into our CSP.
  542. //
  543. status = CryptImportKey(
  544. hProv,
  545. BLOB_TO_DATA(blob),
  546. blob->DataLength,
  547. CRYPT_NULL,
  548. 0,
  549. phSessionKey
  550. );
  551. if( !status ) {
  552. result = IcpGetLastError();
  553. DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlob.CryptImportKey failed err=0x%x.\n",result));
  554. }
  555. if( FAILED(result) ) {
  556. goto fatal;
  557. }
  558. //
  559. // Success!
  560. //
  561. DBG_ASSERT( *phSessionKey != CRYPT_NULL );
  562. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  563. UpdateKeysOpened();
  564. return NO_ERROR;
  565. fatal:
  566. if( hash != CRYPT_NULL ) {
  567. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  568. }
  569. DBG_ASSERT( FAILED(result) );
  570. return result;
  571. } // IISCryptoImportSessionKeyBlob
  572. HRESULT
  573. WINAPI
  574. IISCryptoExportSessionKeyBlob2(
  575. OUT PIIS_CRYPTO_BLOB * ppSessionKeyBlob,
  576. IN HCRYPTPROV hProv,
  577. IN HCRYPTKEY hSessionKey,
  578. IN LPSTR pszPasswd
  579. )
  580. /*++
  581. Routine Description:
  582. This routine exports a session key into a secure session key blob.
  583. The blob contains the session key (encrypted with the specified
  584. private key exchange key) and a digital signature (also encrypted).
  585. Arguments:
  586. ppSessionKeyBlob - Will receive a pointer to the newly created
  587. session key blob if successful.
  588. hProv - A handle to a crypto service provider.
  589. hSessionKey - The key to export.
  590. pszPasswd - The password to use to encrypt the session key.
  591. Return Value:
  592. HRESULT - Completion status, 0 if successful, !0 otherwise.
  593. --*/
  594. {
  595. HRESULT result = NO_ERROR;
  596. BOOL status;
  597. BYTE salt[ RANDOM_SALT_LENGTH ];
  598. HCRYPTHASH hash;
  599. DWORD keyLength;
  600. PIC_BLOB2 blob;
  601. HCRYPTKEY hKeyDerivedKey = CRYPT_NULL;
  602. //
  603. // Sanity check.
  604. //
  605. DBG_ASSERT( IcpGlobals.Initialized );
  606. DBG_ASSERT( ppSessionKeyBlob != NULL );
  607. DBG_ASSERT( hProv != CRYPT_NULL );
  608. DBG_ASSERT( hSessionKey != CRYPT_NULL );
  609. //
  610. // Short-circuit if cryptography is disabled.
  611. //
  612. if( !IcpGlobals.EnableCryptography ) {
  613. if( hProv == DUMMY_HPROV &&
  614. hSessionKey == DUMMY_HSESSIONKEY ) {
  615. return IISCryptoCreateCleartextBlob(
  616. ppSessionKeyBlob,
  617. (PVOID)"",
  618. 1
  619. );
  620. } else {
  621. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  622. }
  623. }
  624. //
  625. // Setup our locals so we know how to cleanup on exit.
  626. //
  627. blob = NULL;
  628. hash = CRYPT_NULL;
  629. //
  630. // Generate a random salt of at least 80 bits
  631. //
  632. if( !CryptGenRandom( hProv, RANDOM_SALT_LENGTH, salt ) )
  633. {
  634. result = IcpGetLastError();
  635. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.CryptGenRandom (advapi32.dll) failed err=0x%x.\n",result));
  636. goto fatal;
  637. }
  638. //
  639. // Create a hash object.
  640. //
  641. result = IISCryptoCreateHash( &hash, hProv );
  642. if( FAILED(result) )
  643. {
  644. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.IISCryptoCreateHash failed err=0x%x.\n",result));
  645. goto fatal;
  646. }
  647. //
  648. // Hash the random salt
  649. if( !CryptHashData( hash, salt, RANDOM_SALT_LENGTH, 0 ) )
  650. {
  651. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.CryptHashData failed err=0x%x.\n",result));
  652. goto fatal;
  653. }
  654. //
  655. // Hash the password string
  656. //
  657. if( !CryptHashData( hash, ( BYTE * )pszPasswd, ( DWORD )strlen( pszPasswd ), 0 ) )
  658. {
  659. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.CryptHashData failed err=0x%x.\n",result));
  660. goto fatal;
  661. }
  662. //
  663. // Derive a key from the supplied passwd
  664. //
  665. result = IISCryptoGetKeyDeriveKey2( &hKeyDerivedKey,
  666. hProv,
  667. hash
  668. );
  669. if( FAILED( result ) )
  670. {
  671. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.IISCryptoGetKeyDeriveKey2 failed err=0x%x.\n",result));
  672. goto fatal;
  673. }
  674. //
  675. // Determine the required size of the key data.
  676. //
  677. status = CryptExportKey(
  678. hSessionKey,
  679. hKeyDerivedKey,
  680. SYMMETRICWRAPKEYBLOB,
  681. 0,
  682. NULL,
  683. &keyLength
  684. );
  685. if( !status ) {
  686. result = IcpGetLastError();
  687. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.CryptExportKey (advapi32.dll) failed err=0x%x.\n",result));
  688. goto fatal;
  689. }
  690. //
  691. // Create a new blob.
  692. //
  693. blob = IcpCreateBlob2(
  694. SALT_BLOB_SIGNATURE,
  695. keyLength,
  696. RANDOM_SALT_LENGTH
  697. );
  698. if( blob == NULL ) {
  699. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  700. goto fatal;
  701. }
  702. //
  703. // Export the key.
  704. //
  705. status = CryptExportKey(
  706. hSessionKey,
  707. hKeyDerivedKey,
  708. SYMMETRICWRAPKEYBLOB,
  709. 0,
  710. BLOB_TO_DATA2(blob),
  711. &keyLength
  712. );
  713. if( !status ) {
  714. result = IcpGetLastError();
  715. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlob.CryptExportKey failed err=0x%x.\n",result));
  716. goto fatal;
  717. }
  718. status = CryptDestroyKey( hKeyDerivedKey );
  719. if( !status )
  720. {
  721. result = IcpGetLastError();
  722. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportSessionKeyBlobWithPasswd.CryptDestroyKey (advapi32.dll) failed err=0x%x.\n",result));
  723. goto fatal;
  724. }
  725. DBG_ASSERT( keyLength == blob->DataLength );
  726. memcpy( BLOB_TO_SALT2( blob ), salt, RANDOM_SALT_LENGTH );
  727. //
  728. // Success!
  729. //
  730. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  731. *ppSessionKeyBlob = (PIIS_CRYPTO_BLOB)blob;
  732. UpdateBlobsCreated();
  733. return NO_ERROR;
  734. fatal:
  735. if( hash != CRYPT_NULL ) {
  736. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  737. }
  738. if( blob != NULL ) {
  739. IcpFreeMemory( blob );
  740. }
  741. DBG_ASSERT( FAILED(result) );
  742. return result;
  743. } // IISCryptoExportSessionKeyBlob2
  744. HRESULT
  745. WINAPI
  746. IISCryptoImportSessionKeyBlob2(
  747. OUT HCRYPTKEY * phSessionKey,
  748. IN PIIS_CRYPTO_BLOB pSessionKeyBlob,
  749. IN HCRYPTPROV hProv,
  750. IN LPSTR pszPasswd
  751. )
  752. /*++
  753. Routine Description:
  754. This routine takes the specified session key blob and creates the
  755. corresponding session key, iff the encrypted session key can be
  756. decrypted and the digital signature can be validated.
  757. Arguments:
  758. phSessionKey - Receives a pointer to the newly created session key
  759. if successful.
  760. pSessionKeyBlob - Pointer to a key blob created with
  761. IISCryptoExportSessionKeyBlob().
  762. hProv - A handle to a crypto service provider.
  763. pszPasswd - The password to use to encrypt the session key.
  764. Return Value:
  765. HRESULT - Completion status, 0 if successful, !0 otherwise.
  766. --*/
  767. {
  768. HRESULT result = NO_ERROR;
  769. BOOL status;
  770. BYTE salt[ RANDOM_SALT_LENGTH ];
  771. HCRYPTKEY hKeyDerivedKey;
  772. HCRYPTHASH hash;
  773. PIC_BLOB2 blob;
  774. //
  775. // Sanity check.
  776. //
  777. DBG_ASSERT( IcpGlobals.Initialized );
  778. DBG_ASSERT( phSessionKey != NULL );
  779. DBG_ASSERT( pSessionKeyBlob != NULL );
  780. DBG_ASSERT( hProv != CRYPT_NULL );
  781. DBG_ASSERT( pszPasswd != NULL );
  782. //
  783. // Short-circuit if cryptography is disabled.
  784. //
  785. if( !IcpGlobals.EnableCryptography ) {
  786. if( hProv == DUMMY_HPROV &&
  787. pSessionKeyBlob->BlobSignature == CLEARTEXT_BLOB_SIGNATURE
  788. ) {
  789. *phSessionKey = DUMMY_HSESSIONKEY;
  790. return NO_ERROR;
  791. } else {
  792. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  793. }
  794. }
  795. DBG_ASSERT( pSessionKeyBlob->BlobSignature == SALT_BLOB_SIGNATURE );
  796. //
  797. // Setup our locals so we know how to cleanup on exit.
  798. //
  799. hash = CRYPT_NULL;
  800. blob = (PIC_BLOB2)pSessionKeyBlob;
  801. //
  802. // Get the random salt
  803. //
  804. memcpy( salt, BLOB_TO_SALT2( blob ), RANDOM_SALT_LENGTH );
  805. //
  806. // Create a hash object.
  807. //
  808. result = IISCryptoCreateHash( &hash, hProv );
  809. if( FAILED(result) )
  810. {
  811. DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlobWithPasswd.IISCryptoCreateHash failed err=0x%x.\n",result));
  812. goto fatal;
  813. }
  814. //
  815. // Hash the random salt
  816. if( !CryptHashData( hash, salt, RANDOM_SALT_LENGTH, 0 ) )
  817. {
  818. DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlobWithPasswd.CryptHashData failed err=0x%x.\n",result));
  819. goto fatal;
  820. }
  821. //
  822. // Hash the password string
  823. //
  824. if( !CryptHashData( hash, ( BYTE * )pszPasswd, ( DWORD )strlen( pszPasswd ), 0 ) )
  825. {
  826. DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlobWithPasswd.CryptHashData failed err=0x%x.\n",result));
  827. goto fatal;
  828. }
  829. //
  830. // Derive a key from the supplied passwd
  831. //
  832. result = IISCryptoGetKeyDeriveKey2( &hKeyDerivedKey,
  833. hProv,
  834. hash
  835. );
  836. if( FAILED( result ) )
  837. {
  838. DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlobWithPasswd.IISCryptoGetKeyDeriveKey2 failed err=0x%x.\n",result));
  839. goto fatal;
  840. }
  841. //
  842. // OK, import the key into our CSP.
  843. //
  844. status = CryptImportKey(
  845. hProv,
  846. BLOB_TO_DATA2(blob),
  847. blob->DataLength,
  848. hKeyDerivedKey,
  849. 0,
  850. phSessionKey
  851. );
  852. if( !status ) {
  853. //result = IcpGetLastError();
  854. result = HRESULT_FROM_WIN32( ERROR_WRONG_PASSWORD );
  855. DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportSessionKeyBlob.CryptImportKey failed err=0x%x.\n",result));
  856. }
  857. if( FAILED(result) ) {
  858. goto fatal;
  859. }
  860. //
  861. // Success!
  862. //
  863. DBG_ASSERT( *phSessionKey != CRYPT_NULL );
  864. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  865. UpdateKeysOpened();
  866. return NO_ERROR;
  867. fatal:
  868. if( hash != CRYPT_NULL ) {
  869. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  870. }
  871. DBG_ASSERT( FAILED(result) );
  872. return result;
  873. } // IISCryptoImportSessionKeyBlob2
  874. HRESULT
  875. WINAPI
  876. IISCryptoExportPublicKeyBlob(
  877. OUT PIIS_CRYPTO_BLOB * ppPublicKeyBlob,
  878. IN HCRYPTPROV hProv,
  879. IN HCRYPTKEY hPublicKey
  880. )
  881. /*++
  882. Routine Description:
  883. This routine exports a key into a public key blob. Note that since
  884. public keys are, well, public, then the data in the blob is neither
  885. encrypted nor signed.
  886. Arguments:
  887. ppPublicKeyBlob - Will receive a pointer to the newly created public
  888. key blob if successful.
  889. hProv - A handle to a crypto service provider.
  890. hPublicKey - The public key to export. This should identify either a
  891. key exchange key or a signature key.
  892. Return Value:
  893. HRESULT - Completion status, 0 if successful, !0 otherwise.
  894. --*/
  895. {
  896. HRESULT result = NO_ERROR;
  897. BOOL status;
  898. DWORD keyLength;
  899. PIC_BLOB blob;
  900. //
  901. // Sanity check.
  902. //
  903. DBG_ASSERT( IcpGlobals.Initialized );
  904. DBG_ASSERT( ppPublicKeyBlob != NULL );
  905. DBG_ASSERT( hProv != CRYPT_NULL );
  906. DBG_ASSERT( hPublicKey != CRYPT_NULL );
  907. //
  908. // Short-circuit if cryptography is disabled.
  909. //
  910. if( !IcpGlobals.EnableCryptography ) {
  911. if( hProv == DUMMY_HPROV &&
  912. ( hPublicKey == DUMMY_HKEYEXCHANGEKEY ||
  913. hPublicKey == DUMMY_HSIGNATUREKEY ) ) {
  914. return IISCryptoCreateCleartextBlob(
  915. ppPublicKeyBlob,
  916. (PVOID)&hPublicKey,
  917. sizeof(hPublicKey)
  918. );
  919. } else {
  920. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  921. }
  922. }
  923. //
  924. // Setup our locals so we know how to cleanup on exit.
  925. //
  926. blob = NULL;
  927. //
  928. // Determine the required size of the key data.
  929. //
  930. status = CryptExportKey(
  931. hPublicKey,
  932. CRYPT_NULL,
  933. PUBLICKEYBLOB,
  934. 0,
  935. NULL,
  936. &keyLength
  937. );
  938. if( !status ) {
  939. result = IcpGetLastError();
  940. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportPublicKeyBlob.CryptExportKey failed err=0x%x.\n",result));
  941. goto fatal;
  942. }
  943. //
  944. // Create a new blob.
  945. //
  946. blob = IcpCreateBlob(
  947. PUBLIC_KEY_BLOB_SIGNATURE,
  948. keyLength,
  949. 0
  950. );
  951. if( blob == NULL ) {
  952. result = ERROR_NOT_ENOUGH_MEMORY;
  953. goto fatal;
  954. }
  955. //
  956. // Export the key.
  957. //
  958. status = CryptExportKey(
  959. hPublicKey,
  960. CRYPT_NULL,
  961. PUBLICKEYBLOB,
  962. 0,
  963. BLOB_TO_DATA(blob),
  964. &keyLength
  965. );
  966. if( !status ) {
  967. result = IcpGetLastError();
  968. DBGPRINTF(( DBG_CONTEXT,"IISCryptoExportPublicKeyBlob.CryptExportKey failed err=0x%x.\n",result));
  969. goto fatal;
  970. }
  971. DBG_ASSERT( keyLength == blob->DataLength );
  972. //
  973. // Success!
  974. //
  975. DBG_ASSERT( IISCryptoIsValidBlob( (PIIS_CRYPTO_BLOB)blob ) );
  976. *ppPublicKeyBlob = (PIIS_CRYPTO_BLOB)blob;
  977. UpdateBlobsCreated();
  978. return NO_ERROR;
  979. fatal:
  980. if( blob != NULL ) {
  981. IcpFreeMemory( blob );
  982. }
  983. DBG_ASSERT( FAILED(result) );
  984. return result;
  985. } // IISCryptoExportPublicKeyBlob
  986. HRESULT
  987. WINAPI
  988. IISCryptoImportPublicKeyBlob(
  989. OUT HCRYPTKEY * phPublicKey,
  990. IN PIIS_CRYPTO_BLOB pPublicKeyBlob,
  991. IN HCRYPTPROV hProv
  992. )
  993. /*++
  994. Routine Description:
  995. This routine takes the specified public key blob and creates the
  996. corresponding key.
  997. Arguments:
  998. phPublicKey - Receives a pointer to the newly created public key if
  999. successful.
  1000. pPublicKeyBlob - Pointer to a public key blob created with
  1001. IISCryptoExportPublicKeyBlob().
  1002. hProv - A handle to a crypto service provider.
  1003. Return Value:
  1004. HRESULT - Completion status, 0 if successful, !0 otherwise.
  1005. --*/
  1006. {
  1007. HRESULT result = NO_ERROR;
  1008. BOOL status;
  1009. PIC_BLOB blob;
  1010. //
  1011. // Sanity check.
  1012. //
  1013. DBG_ASSERT( IcpGlobals.Initialized );
  1014. DBG_ASSERT( phPublicKey != NULL );
  1015. DBG_ASSERT( pPublicKeyBlob != NULL );
  1016. DBG_ASSERT( IISCryptoIsValidBlob( pPublicKeyBlob ) );
  1017. DBG_ASSERT( hProv != CRYPT_NULL );
  1018. //
  1019. // Short-circuit if cryptography is disabled.
  1020. //
  1021. if( !IcpGlobals.EnableCryptography ) {
  1022. if( hProv == DUMMY_HPROV &&
  1023. pPublicKeyBlob->BlobSignature == CLEARTEXT_BLOB_SIGNATURE
  1024. ) {
  1025. *phPublicKey = *(HCRYPTKEY *)( pPublicKeyBlob + 1 );
  1026. return NO_ERROR;
  1027. } else {
  1028. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  1029. }
  1030. }
  1031. DBG_ASSERT( pPublicKeyBlob->BlobSignature == PUBLIC_KEY_BLOB_SIGNATURE );
  1032. //
  1033. // Import the key into our CSP.
  1034. //
  1035. blob = (PIC_BLOB)pPublicKeyBlob;
  1036. status = CryptImportKey(
  1037. hProv,
  1038. BLOB_TO_DATA(blob),
  1039. blob->DataLength,
  1040. CRYPT_NULL,
  1041. 0,
  1042. phPublicKey
  1043. );
  1044. if( !status ) {
  1045. result = IcpGetLastError();
  1046. DBGPRINTF(( DBG_CONTEXT,"IISCryptoImportPublicKeyBlob.CryptImportKey failed err=0x%x.\n",result));
  1047. }
  1048. if( SUCCEEDED(result) ) {
  1049. DBG_ASSERT( *phPublicKey != CRYPT_NULL );
  1050. UpdateKeysOpened();
  1051. }
  1052. return result;
  1053. } // IISCryptoImportPublicKeyBlob
  1054. //
  1055. // Private functions.
  1056. //
  1057. HRESULT
  1058. IcpGetKeyHelper(
  1059. OUT HCRYPTKEY * phKey,
  1060. IN HCRYPTPROV hProv,
  1061. IN DWORD dwKeySpec
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This is a helper routine for IISCryptoGetKeyExchangeKey() and
  1066. IISCryptoGetSignatureKey(). It tries to get/generate the specific
  1067. key type within the given provider.
  1068. Arguments:
  1069. phKey - Receives the key handle if successful.
  1070. hProv - A handle to a crypto service provider.
  1071. dwKeySpec - The specification of the key to open/create.
  1072. Return Value:
  1073. HRESULT - Completion status, 0 if successful, !0 otherwise.
  1074. --*/
  1075. {
  1076. HRESULT result = NO_ERROR;
  1077. BOOL status;
  1078. //
  1079. // Sanity check.
  1080. //
  1081. DBG_ASSERT( IcpGlobals.Initialized );
  1082. DBG_ASSERT( phKey != NULL );
  1083. DBG_ASSERT( hProv != CRYPT_NULL );
  1084. //
  1085. // Short-circuit if cryptography is disabled.
  1086. //
  1087. if( !IcpGlobals.EnableCryptography ) {
  1088. if( hProv == DUMMY_HPROV ) {
  1089. if( dwKeySpec == AT_KEYEXCHANGE ) {
  1090. *phKey = DUMMY_HKEYEXCHANGEKEY;
  1091. } else {
  1092. ASSERT( dwKeySpec == AT_SIGNATURE );
  1093. *phKey = DUMMY_HSIGNATUREKEY;
  1094. }
  1095. return NO_ERROR;
  1096. } else {
  1097. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  1098. }
  1099. }
  1100. //
  1101. // Try to retrieve the key.
  1102. //
  1103. status = CryptGetUserKey(
  1104. hProv,
  1105. dwKeySpec,
  1106. phKey
  1107. );
  1108. if( status ) {
  1109. DBG_ASSERT( *phKey != CRYPT_NULL );
  1110. UpdateKeysOpened();
  1111. return NO_ERROR;
  1112. }
  1113. //
  1114. // Could not get the key. If the failure was anything other than
  1115. // NTE_NO_KEY, then we're toast.
  1116. //
  1117. result = IcpGetLastError();
  1118. if( result != NTE_NO_KEY ) {
  1119. DBGPRINTF(( DBG_CONTEXT,"IcpGetKeyHelper.CryptGetUserKey (advapi32.dll) failed err=0x%x.toast.\n",result));
  1120. return result;
  1121. }
  1122. //
  1123. // OK, CryptGetUserKey() failed with NTE_NO_KEY, meaning
  1124. // that the key does not yet exist, so generate it now.
  1125. //
  1126. // Note that we must be careful to handle the inevitable race
  1127. // conditions that can occur when multiple threads execute this
  1128. // code and each thinks they need to generate the key. We handle
  1129. // this by acquiring the global lock, then reattempting to get
  1130. // the key. If we still cannot get the key, only then do we attempt
  1131. // to generate one.
  1132. //
  1133. result = NO_ERROR; // until proven otherwise...
  1134. IcpAcquireGlobalLock();
  1135. status = CryptGetUserKey(
  1136. hProv,
  1137. dwKeySpec,
  1138. phKey
  1139. );
  1140. if( !status )
  1141. {
  1142. //
  1143. // We still cannot get the key, so try to generate one.
  1144. //
  1145. DBGPRINTF(( DBG_CONTEXT,"IcpGetKeyHelper.CryptGetUserKey:failed, lets try to generate another key.\n"));
  1146. status = CryptGenKey(
  1147. hProv,
  1148. dwKeySpec,
  1149. 0,
  1150. phKey
  1151. );
  1152. if( !status ) {
  1153. result = IcpGetLastError();
  1154. DBGPRINTF(( DBG_CONTEXT,"IcpGetKeyHelper.CryptGenKey (advapi32.dll) failed err=0x%x.\n",result));
  1155. }
  1156. else
  1157. {
  1158. DBGPRINTF(( DBG_CONTEXT,"IcpGetKeyHelper.CryptGenKey:key generated.\n"));
  1159. }
  1160. }
  1161. if( SUCCEEDED(result) )
  1162. {
  1163. UpdateKeysOpened();
  1164. }
  1165. else
  1166. {
  1167. *phKey = CRYPT_NULL;
  1168. }
  1169. IcpReleaseGlobalLock();
  1170. return result;
  1171. } // IcpGetKeyHelper