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.

899 lines
18 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. data.c
  5. Abstract:
  6. Data encryption/decryption routines for the IIS cryptographic
  7. package.
  8. The following routines are exported by this module:
  9. IISCryptoEncryptDataBlob
  10. IISCryptoDecryptDataBlob
  11. Author:
  12. Keith Moore (keithmo) 02-Dec-1996
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. //
  18. // Private constants.
  19. //
  20. //
  21. // Private types.
  22. //
  23. //
  24. // The IC_DATA structure allows us to store our own private data
  25. // along with the data we're encrypting for the application.
  26. //
  27. typedef struct _IC_DATA {
  28. DWORD RegType;
  29. // BYTE Data[];
  30. } IC_DATA;
  31. typedef UNALIGNED64 IC_DATA *PIC_DATA;
  32. //
  33. // Private globals.
  34. //
  35. //
  36. // Private prototypes.
  37. //
  38. //
  39. // Public functions.
  40. //
  41. HRESULT
  42. WINAPI
  43. IISCryptoEncryptDataBlob(
  44. OUT PIIS_CRYPTO_BLOB * ppDataBlob,
  45. IN PVOID pBuffer,
  46. IN DWORD dwBufferLength,
  47. IN DWORD dwRegType,
  48. IN HCRYPTPROV hProv,
  49. IN HCRYPTKEY hSessionKey
  50. )
  51. /*++
  52. Routine Description:
  53. This routine encrypts a block of data, resulting in a data blob.
  54. The data blob contains the encrypted data and a digital signature
  55. validating the data.
  56. Arguments:
  57. ppDataBlob - Receives a pointer to the newly created data blob if
  58. successful.
  59. pBuffer - The buffer to encrypt.
  60. dwBufferLength - The length of the buffer.
  61. dwRegType - The REG_* type to associate with this data.
  62. hProv - A handle to a crypto service provider.
  63. hSessionKey - The key used to encrypt the data.
  64. Return Value:
  65. HRESULT - Completion status, 0 if successful, !0 otherwise.
  66. --*/
  67. {
  68. HRESULT result;
  69. HCRYPTHASH hash;
  70. PIC_BLOB blob;
  71. PIC_DATA data;
  72. DWORD dataLength;
  73. DWORD hashLength;
  74. //
  75. // Sanity check.
  76. //
  77. DBG_ASSERT( IcpGlobals.Initialized );
  78. DBG_ASSERT( ppDataBlob != NULL );
  79. DBG_ASSERT( pBuffer != NULL );
  80. DBG_ASSERT( hProv != CRYPT_NULL );
  81. DBG_ASSERT( hSessionKey != CRYPT_NULL );
  82. //
  83. // Short-circuit if cryptography is disabled.
  84. //
  85. if( !IcpGlobals.EnableCryptography ) {
  86. if( hProv == DUMMY_HPROV &&
  87. hSessionKey == DUMMY_HSESSIONKEY ) {
  88. return IISCryptoCreateCleartextBlob(
  89. ppDataBlob,
  90. pBuffer,
  91. dwBufferLength
  92. );
  93. } else {
  94. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  95. }
  96. }
  97. //
  98. // Setup our locals so we know how to cleanup on exit.
  99. //
  100. blob = NULL;
  101. hash = CRYPT_NULL;
  102. //
  103. // Create a hash object.
  104. //
  105. result = IISCryptoCreateHash(
  106. &hash,
  107. hProv
  108. );
  109. if( FAILED(result) ) {
  110. goto fatal;
  111. }
  112. //
  113. // Determine the hash data length.
  114. //
  115. result = IcpGetHashLength(
  116. &hashLength,
  117. hProv
  118. );
  119. if( FAILED(result) ) {
  120. goto fatal;
  121. }
  122. //
  123. // Determine the required size of the encrypted data.
  124. //
  125. dwBufferLength += sizeof(*data);
  126. dataLength = dwBufferLength;
  127. //
  128. // session key should not be used concurrently by multiple threads
  129. //
  130. IcpAcquireGlobalLock();
  131. if( !CryptEncrypt(
  132. hSessionKey,
  133. CRYPT_NULL,
  134. TRUE,
  135. 0,
  136. NULL,
  137. &dataLength,
  138. dwBufferLength
  139. ) ) {
  140. result = IcpGetLastError();
  141. IcpReleaseGlobalLock();
  142. goto fatal;
  143. }
  144. IcpReleaseGlobalLock();
  145. //
  146. // Create a new blob.
  147. //
  148. blob = IcpCreateBlob(
  149. DATA_BLOB_SIGNATURE,
  150. dataLength,
  151. hashLength
  152. );
  153. if( blob == NULL ) {
  154. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  155. goto fatal;
  156. }
  157. //
  158. // Copy the data into the blob, then encrypt it.
  159. //
  160. data = (PIC_DATA)BLOB_TO_DATA(blob);
  161. data->RegType = dwRegType;
  162. RtlCopyMemory(
  163. data + 1,
  164. pBuffer,
  165. dwBufferLength - sizeof(*data)
  166. );
  167. //
  168. // session key should not be used concurrently by multiple threads
  169. //
  170. IcpAcquireGlobalLock();
  171. if( !CryptEncrypt(
  172. hSessionKey,
  173. hash,
  174. TRUE,
  175. 0,
  176. BLOB_TO_DATA(blob),
  177. &dwBufferLength,
  178. dataLength
  179. ) ) {
  180. result = IcpGetLastError();
  181. IcpReleaseGlobalLock();
  182. goto fatal;
  183. }
  184. IcpReleaseGlobalLock();
  185. DBG_ASSERT( dataLength == blob->DataLength );
  186. //
  187. // Generate the signature.
  188. //
  189. if( !CryptSignHash(
  190. hash,
  191. AT_SIGNATURE,
  192. NULL,
  193. 0,
  194. BLOB_TO_SIGNATURE(blob),
  195. &hashLength
  196. ) ) {
  197. result = IcpGetLastError();
  198. goto fatal;
  199. }
  200. DBG_ASSERT( hashLength == blob->SignatureLength );
  201. //
  202. // Success!
  203. //
  204. DBG_ASSERT( IISCryptoIsValidBlob( (PIIS_CRYPTO_BLOB)blob ) );
  205. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  206. *ppDataBlob = (PIIS_CRYPTO_BLOB)blob;
  207. UpdateBlobsCreated();
  208. return NO_ERROR;
  209. fatal:
  210. if( hash != CRYPT_NULL ) {
  211. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  212. }
  213. if( blob != NULL ) {
  214. IcpFreeMemory( blob );
  215. }
  216. DBG_ASSERT( FAILED(result) );
  217. return result;
  218. } // IISCryptoEncryptDataBlob
  219. HRESULT
  220. WINAPI
  221. IISCryptoEncryptDataBlob2(
  222. OUT PIIS_CRYPTO_BLOB * ppDataBlob,
  223. IN PVOID pBuffer,
  224. IN DWORD dwBufferLength,
  225. IN DWORD dwRegType,
  226. IN HCRYPTPROV hProv,
  227. IN HCRYPTKEY hSessionKey
  228. )
  229. /*++
  230. Routine Description:
  231. This routine encrypts a block of data, resulting in a data blob.
  232. The data blob contains the encrypted data and a digital signature
  233. validating the data.
  234. Arguments:
  235. ppDataBlob - Receives a pointer to the newly created data blob if
  236. successful.
  237. pBuffer - The buffer to encrypt.
  238. dwBufferLength - The length of the buffer.
  239. dwRegType - The REG_* type to associate with this data.
  240. hProv - A handle to a crypto service provider.
  241. hSessionKey - The key used to encrypt the data.
  242. Return Value:
  243. HRESULT - Completion status, 0 if successful, !0 otherwise.
  244. --*/
  245. {
  246. HRESULT result;
  247. HCRYPTHASH hash;
  248. PIC_BLOB blob;
  249. PIC_DATA data;
  250. DWORD dataLength;
  251. DWORD hashLength;
  252. //
  253. // Sanity check.
  254. //
  255. DBG_ASSERT( IcpGlobals.Initialized );
  256. DBG_ASSERT( ppDataBlob != NULL );
  257. DBG_ASSERT( pBuffer != NULL );
  258. DBG_ASSERT( hProv != CRYPT_NULL );
  259. DBG_ASSERT( hSessionKey != CRYPT_NULL );
  260. //
  261. // Short-circuit if cryptography is disabled.
  262. //
  263. if( !IcpGlobals.EnableCryptography ) {
  264. if( hProv == DUMMY_HPROV &&
  265. hSessionKey == DUMMY_HSESSIONKEY ) {
  266. return IISCryptoCreateCleartextBlob(
  267. ppDataBlob,
  268. pBuffer,
  269. dwBufferLength
  270. );
  271. } else {
  272. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  273. }
  274. }
  275. //
  276. // Setup our locals so we know how to cleanup on exit.
  277. //
  278. blob = NULL;
  279. hash = CRYPT_NULL;
  280. //
  281. // Create a hash object.
  282. //
  283. result = IISCryptoCreateHash(
  284. &hash,
  285. hProv
  286. );
  287. if( FAILED(result) ) {
  288. goto fatal;
  289. }
  290. //
  291. // Determine the hash data length.
  292. //
  293. result = IcpGetHashLength(
  294. &hashLength,
  295. hProv
  296. );
  297. if( FAILED(result) ) {
  298. goto fatal;
  299. }
  300. //
  301. // Determine the required size of the encrypted data.
  302. //
  303. dwBufferLength += sizeof(*data);
  304. dataLength = dwBufferLength;
  305. //
  306. // session key should not be used concurrently by multiple threads
  307. //
  308. IcpAcquireGlobalLock();
  309. if( !CryptEncrypt(
  310. hSessionKey,
  311. CRYPT_NULL,
  312. TRUE,
  313. 0,
  314. NULL,
  315. &dataLength,
  316. dwBufferLength
  317. ) ) {
  318. result = IcpGetLastError();
  319. IcpReleaseGlobalLock();
  320. goto fatal;
  321. }
  322. IcpReleaseGlobalLock();
  323. //
  324. // Create a new blob.
  325. //
  326. blob = IcpCreateBlob(
  327. DATA_BLOB_SIGNATURE,
  328. dataLength,
  329. hashLength
  330. );
  331. if( blob == NULL ) {
  332. result = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  333. goto fatal;
  334. }
  335. //
  336. // Copy the data into the blob, then encrypt it.
  337. //
  338. data = (PIC_DATA)BLOB_TO_DATA(blob);
  339. data->RegType = dwRegType;
  340. RtlCopyMemory(
  341. data + 1,
  342. pBuffer,
  343. dwBufferLength - sizeof(*data)
  344. );
  345. //
  346. // session key should not be used concurrently by multiple threads
  347. //
  348. IcpAcquireGlobalLock();
  349. if( !CryptEncrypt(
  350. hSessionKey,
  351. hash,
  352. TRUE,
  353. 0,
  354. BLOB_TO_DATA(blob),
  355. &dwBufferLength,
  356. dataLength
  357. ) ) {
  358. result = IcpGetLastError();
  359. IcpReleaseGlobalLock();
  360. goto fatal;
  361. }
  362. IcpReleaseGlobalLock();
  363. DBG_ASSERT( dataLength == blob->DataLength );
  364. //
  365. // Success!
  366. //
  367. DBG_ASSERT( IISCryptoIsValidBlob( (PIIS_CRYPTO_BLOB)blob ) );
  368. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  369. *ppDataBlob = (PIIS_CRYPTO_BLOB)blob;
  370. UpdateBlobsCreated();
  371. return NO_ERROR;
  372. fatal:
  373. if( hash != CRYPT_NULL ) {
  374. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  375. }
  376. if( blob != NULL ) {
  377. IcpFreeMemory( blob );
  378. }
  379. DBG_ASSERT( FAILED(result) );
  380. return result;
  381. } // IISCryptoEncryptDataBlob2
  382. HRESULT
  383. WINAPI
  384. IISCryptoDecryptDataBlob(
  385. OUT PVOID * ppBuffer,
  386. OUT LPDWORD pdwBufferLength,
  387. OUT LPDWORD pdwRegType,
  388. IN PIIS_CRYPTO_BLOB pDataBlob,
  389. IN HCRYPTPROV hProv,
  390. IN HCRYPTKEY hSessionKey,
  391. IN HCRYPTKEY hSignatureKey
  392. )
  393. /*++
  394. Routine Description:
  395. This routine validates and decrypts a data blob, resulting in a
  396. buffer containing plaintext.
  397. N.B. This routine effectively destroys the blob; once the data
  398. is decrypted, it cannot be decrypted again, as the data is
  399. decrypted "in place".
  400. N.B. The pointer returned in *ppBuffer points within the blob.
  401. This pointer will become invalid when the blob is freed. Note also
  402. that the calling application is still responsible for calling
  403. IISCryptoFreeBlob() on the data blob.
  404. Arguments:
  405. ppBuffer - Receives a pointer to the data buffer if successful.
  406. pdwBufferLength - Receives the length of the data buffer.
  407. pdwRegType - Receives the REG_* type of the data.
  408. pDataBlob - The data blob to decrypt.
  409. hProv - A handle to a crypto service provider.
  410. hSessionKey - The key used to decrypt the data.
  411. hSignatureKey - Handle to the encryption key to use when validating
  412. the digital signature.
  413. Return Value:
  414. HRESULT - Completion status, 0 if successful, !0 otherwise.
  415. --*/
  416. {
  417. HRESULT result;
  418. HCRYPTHASH hash;
  419. PIC_BLOB blob;
  420. PIC_DATA data;
  421. DWORD dataLength;
  422. //
  423. // Sanity check.
  424. //
  425. DBG_ASSERT( IcpGlobals.Initialized );
  426. DBG_ASSERT( ppBuffer != NULL );
  427. DBG_ASSERT( pdwBufferLength != NULL );
  428. DBG_ASSERT( pdwRegType != NULL );
  429. DBG_ASSERT( pDataBlob != NULL );
  430. DBG_ASSERT( IISCryptoIsValidBlob( pDataBlob ) );
  431. DBG_ASSERT( hProv != CRYPT_NULL );
  432. DBG_ASSERT( hSessionKey != CRYPT_NULL );
  433. DBG_ASSERT( hSignatureKey != CRYPT_NULL );
  434. //
  435. // Short-circuit if cryptography is disabled.
  436. //
  437. if( !IcpGlobals.EnableCryptography ) {
  438. if( hProv == DUMMY_HPROV &&
  439. hSessionKey == DUMMY_HSESSIONKEY &&
  440. hSignatureKey == DUMMY_HSIGNATUREKEY &&
  441. pDataBlob->BlobSignature == CLEARTEXT_BLOB_SIGNATURE
  442. ) {
  443. *ppBuffer = (PVOID)( pDataBlob + 1 );
  444. *pdwBufferLength = pDataBlob->BlobDataLength;
  445. return NO_ERROR;
  446. } else {
  447. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  448. }
  449. }
  450. //
  451. // Short-circuit for cleartext blobs.
  452. //
  453. if( pDataBlob->BlobSignature == CLEARTEXT_BLOB_SIGNATURE ) {
  454. *ppBuffer = (PVOID)( pDataBlob + 1 );
  455. *pdwBufferLength = pDataBlob->BlobDataLength;
  456. return NO_ERROR;
  457. }
  458. //
  459. // Setup our locals so we know how to cleanup on exit.
  460. //
  461. hash = CRYPT_NULL;
  462. blob = (PIC_BLOB)pDataBlob;
  463. //
  464. // Create a hash object.
  465. //
  466. result = IISCryptoCreateHash(
  467. &hash,
  468. hProv
  469. );
  470. if( FAILED(result) ) {
  471. goto fatal;
  472. }
  473. //
  474. // Decrypt the data.
  475. //
  476. dataLength = blob->DataLength;
  477. //
  478. // session key should not be used concurrently by multiple threads
  479. //
  480. IcpAcquireGlobalLock();
  481. if( !CryptDecrypt(
  482. hSessionKey,
  483. hash,
  484. TRUE,
  485. 0,
  486. BLOB_TO_DATA(blob),
  487. &dataLength
  488. ) ) {
  489. result = IcpGetLastError();
  490. IcpReleaseGlobalLock();
  491. goto fatal;
  492. }
  493. IcpReleaseGlobalLock();
  494. //
  495. // Verify the signature.
  496. //
  497. if( !CryptVerifySignature(
  498. hash,
  499. BLOB_TO_SIGNATURE(blob),
  500. blob->SignatureLength,
  501. hSignatureKey,
  502. NULL,
  503. 0
  504. ) ) {
  505. result = IcpGetLastError();
  506. goto fatal;
  507. }
  508. //
  509. // Success!
  510. //
  511. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  512. data = (PIC_DATA)BLOB_TO_DATA(blob);
  513. *ppBuffer = data + 1;
  514. *pdwBufferLength = dataLength - sizeof(*data);
  515. *pdwRegType = data->RegType;
  516. return NO_ERROR;
  517. fatal:
  518. if( hash != CRYPT_NULL ) {
  519. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  520. }
  521. DBG_ASSERT( FAILED(result) );
  522. return result;
  523. } // IISCryptoDecryptDataBlob
  524. HRESULT
  525. WINAPI
  526. IISCryptoDecryptDataBlob2(
  527. OUT PVOID * ppBuffer,
  528. OUT LPDWORD pdwBufferLength,
  529. OUT LPDWORD pdwRegType,
  530. IN PIIS_CRYPTO_BLOB pDataBlob,
  531. IN HCRYPTPROV hProv,
  532. IN HCRYPTKEY hSessionKey
  533. )
  534. /*++
  535. Routine Description:
  536. This routine validates and decrypts a data blob, resulting in a
  537. buffer containing plaintext.
  538. N.B. This routine effectively destroys the blob; once the data
  539. is decrypted, it cannot be decrypted again, as the data is
  540. decrypted "in place".
  541. N.B. The pointer returned in *ppBuffer points within the blob.
  542. This pointer will become invalid when the blob is freed. Note also
  543. that the calling application is still responsible for calling
  544. IISCryptoFreeBlob() on the data blob.
  545. Arguments:
  546. ppBuffer - Receives a pointer to the data buffer if successful.
  547. pdwBufferLength - Receives the length of the data buffer.
  548. pdwRegType - Receives the REG_* type of the data.
  549. pDataBlob - The data blob to decrypt.
  550. hProv - A handle to a crypto service provider.
  551. hSessionKey - The key used to decrypt the data.
  552. Return Value:
  553. HRESULT - Completion status, 0 if successful, !0 otherwise.
  554. --*/
  555. {
  556. HRESULT result;
  557. HCRYPTHASH hash;
  558. PIC_BLOB blob;
  559. PIC_DATA data;
  560. DWORD dataLength;
  561. //
  562. // Sanity check.
  563. //
  564. DBG_ASSERT( IcpGlobals.Initialized );
  565. DBG_ASSERT( ppBuffer != NULL );
  566. DBG_ASSERT( pdwBufferLength != NULL );
  567. DBG_ASSERT( pdwRegType != NULL );
  568. DBG_ASSERT( pDataBlob != NULL );
  569. DBG_ASSERT( IISCryptoIsValidBlob( pDataBlob ) );
  570. DBG_ASSERT( hProv != CRYPT_NULL );
  571. DBG_ASSERT( hSessionKey != CRYPT_NULL );
  572. //
  573. // Short-circuit if cryptography is disabled.
  574. //
  575. if( !IcpGlobals.EnableCryptography ) {
  576. if( hProv == DUMMY_HPROV &&
  577. hSessionKey == DUMMY_HSESSIONKEY &&
  578. pDataBlob->BlobSignature == CLEARTEXT_BLOB_SIGNATURE
  579. ) {
  580. *ppBuffer = (PVOID)( pDataBlob + 1 );
  581. *pdwBufferLength = pDataBlob->BlobDataLength;
  582. return NO_ERROR;
  583. } else {
  584. return RETURNCODETOHRESULT( ERROR_INVALID_PARAMETER );
  585. }
  586. }
  587. //
  588. // Short-circuit for cleartext blobs.
  589. //
  590. if( pDataBlob->BlobSignature == CLEARTEXT_BLOB_SIGNATURE ) {
  591. *ppBuffer = (PVOID)( pDataBlob + 1 );
  592. *pdwBufferLength = pDataBlob->BlobDataLength;
  593. return NO_ERROR;
  594. }
  595. //
  596. // Setup our locals so we know how to cleanup on exit.
  597. //
  598. hash = CRYPT_NULL;
  599. blob = (PIC_BLOB)pDataBlob;
  600. //
  601. // Create a hash object.
  602. //
  603. result = IISCryptoCreateHash(
  604. &hash,
  605. hProv
  606. );
  607. if( FAILED(result) ) {
  608. goto fatal;
  609. }
  610. //
  611. // Decrypt the data.
  612. //
  613. dataLength = blob->DataLength;
  614. //
  615. // session key should not be used concurrently by multiple threads
  616. //
  617. IcpAcquireGlobalLock();
  618. if( !CryptDecrypt(
  619. hSessionKey,
  620. hash,
  621. TRUE,
  622. 0,
  623. BLOB_TO_DATA(blob),
  624. &dataLength
  625. ) ) {
  626. result = IcpGetLastError();
  627. IcpReleaseGlobalLock();
  628. goto fatal;
  629. }
  630. IcpReleaseGlobalLock();
  631. //
  632. // Success!
  633. //
  634. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  635. data = (PIC_DATA)BLOB_TO_DATA(blob);
  636. *ppBuffer = data + 1;
  637. *pdwBufferLength = dataLength - sizeof(*data);
  638. *pdwRegType = data->RegType;
  639. return NO_ERROR;
  640. fatal:
  641. if( hash != CRYPT_NULL ) {
  642. DBG_REQUIRE( SUCCEEDED( IISCryptoDestroyHash( hash ) ) );
  643. }
  644. DBG_ASSERT( FAILED(result) );
  645. return result;
  646. } // IISCryptoDecryptDataBlob2
  647. //
  648. // Private functions.
  649. //