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.

1460 lines
33 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1999
  3. Module Name:
  4. Verify
  5. Abstract:
  6. This module implements the CSPDK CSP Module signature verification routine.
  7. Author:
  8. Doug Barlow (dbarlow) 12/8/1999
  9. Notes:
  10. ?Notes?
  11. --*/
  12. #ifndef WIN32_LEAN_AND_MEAN
  13. #define WIN32_LEAN_AND_MEAN
  14. #endif
  15. #include <windows.h>
  16. #include "logcsp.h"
  17. #include <rsa.h>
  18. #include <rc4.h>
  19. #include <md5.h>
  20. #include <sha.h>
  21. #include "..\cspdkMaster.c"
  22. #define KEYSIZE1024 0x88
  23. static DWORD
  24. FCryptDecodeObject(
  25. IN DWORD dwCertEncodingType,
  26. IN LPCSTR lpszStructType,
  27. IN const BYTE *pbEncoded,
  28. IN DWORD cbEncoded,
  29. IN DWORD dwFlags,
  30. OUT CBuffer &bfStructInfo);
  31. static DWORD
  32. MakeBSafeKey(
  33. PUBLICKEYSTRUC *pKeyBlob,
  34. CBuffer &bfBSafe);
  35. static DWORD
  36. GetCspdkKey(
  37. CBuffer &bfBSafeKey);
  38. static DWORD
  39. HashFileExtractSig(
  40. IN LPCTSTR szImage,
  41. OUT MD5_CTX *pmd5Hash,
  42. OUT CBuffer &bfSig);
  43. static DWORD
  44. HashFile(
  45. IN LPCTSTR szImage,
  46. OUT MD5_CTX *pmd5Hash);
  47. static DWORD
  48. VerifySignature(
  49. IN MD5_CTX *pmd5Hash,
  50. IN LPCBYTE pbSig,
  51. IN BSAFE_PUB_KEY *pbsKey);
  52. static DWORD
  53. CompareSignatureToHash(
  54. IN LPCBYTE pbSignature,
  55. IN DWORD cbSignature,
  56. IN LPCBYTE pbHash,
  57. IN DWORD cbHash,
  58. IN LPCBYTE pbHashOid,
  59. IN DWORD cbHashOid);
  60. static DWORD
  61. DecryptKey(
  62. IN LPCBYTE pbKey,
  63. IN DWORD cbKey,
  64. IN BYTE bVal,
  65. OUT CBuffer &bfKey);
  66. static const TCHAR
  67. l_szCryptReg[] = TEXT("SOFTWARE\\Microsoft\\Cryptography"),
  68. l_szCspdkReg[] = TEXT("SOFTWARE\\Microsoft\\Cryptography\\CSPDK"),
  69. l_szCspdk[] = TEXT("CSPDK"),
  70. l_szKeyPair[] = TEXT("Key Pair"),
  71. l_szCertificate[] = TEXT("Certificate");
  72. #ifdef MS_INTERNAL_KEY
  73. static struct _mskey {
  74. BSAFE_PUB_KEY PUB;
  75. unsigned char pubmodulus[KEYSIZE1024];
  76. } MSKEY = {
  77. {
  78. 0x2bad85ae,
  79. 0x883adacc,
  80. 0xb32ebd68,
  81. 0xa7ec8b06,
  82. 0x58dbeb81,
  83. },
  84. {
  85. 0x42, 0x34, 0xb7, 0xab, 0x45, 0x0f, 0x60, 0xcd,
  86. 0x8f, 0x77, 0xb5, 0xd1, 0x79, 0x18, 0x34, 0xbe,
  87. 0x66, 0xcb, 0x5c, 0x66, 0x4a, 0x9f, 0x03, 0x18,
  88. 0x13, 0x36, 0x8e, 0x88, 0x21, 0x78, 0xb1, 0x94,
  89. 0xa1, 0xd5, 0x8f, 0x8c, 0xa5, 0xd3, 0x9f, 0x86,
  90. 0x43, 0x89, 0x05, 0xa0, 0xe3, 0xee, 0xe2, 0xd0,
  91. 0xe5, 0x1d, 0x5f, 0xaf, 0xff, 0x85, 0x71, 0x7a,
  92. 0x0a, 0xdb, 0x2e, 0xd8, 0xc3, 0x5f, 0x2f, 0xb1,
  93. 0xf0, 0x53, 0x98, 0x3b, 0x44, 0xee, 0x7f, 0xc9,
  94. 0x54, 0x26, 0xdb, 0xdd, 0xfe, 0x1f, 0xd0, 0xda,
  95. 0x96, 0x89, 0xc8, 0x9e, 0x2b, 0x5d, 0x96, 0xd1,
  96. 0xf7, 0x52, 0x14, 0x04, 0xfb, 0xf8, 0xee, 0x4d,
  97. 0x92, 0xd1, 0xb6, 0x37, 0x6a, 0xe0, 0xaf, 0xde,
  98. 0xc7, 0x41, 0x06, 0x7a, 0xe5, 0x6e, 0xb1, 0x8c,
  99. 0x8f, 0x17, 0xf0, 0x63, 0x8d, 0xaf, 0x63, 0xfd,
  100. 0x22, 0xc5, 0xad, 0x1a, 0xb1, 0xe4, 0x7a, 0x6b,
  101. 0x1e, 0x0e, 0xea, 0x60, 0x56, 0xbd, 0x49, 0xd0,
  102. }
  103. };
  104. #endif
  105. static struct _key {
  106. BSAFE_PUB_KEY PUB;
  107. unsigned char pubmodulus[KEYSIZE1024];
  108. } KEY = {
  109. {
  110. 0x3fcbf1a9,
  111. 0x08f597db,
  112. 0xe4aecab4,
  113. 0x75360f90,
  114. 0x9d6c0f00,
  115. },
  116. {
  117. 0x85, 0xdd, 0x9b, 0xf4, 0x4d, 0x0b, 0xc4, 0x96,
  118. 0x3e, 0x79, 0x86, 0x30, 0x6d, 0x27, 0x31, 0xee,
  119. 0x4a, 0x85, 0xf5, 0xff, 0xbb, 0xa9, 0xbd, 0x81,
  120. 0x86, 0xf2, 0x4f, 0x87, 0x6c, 0x57, 0x55, 0x19,
  121. 0xe4, 0xf4, 0x49, 0xa3, 0x19, 0x27, 0x08, 0x82,
  122. 0x9e, 0xf9, 0x8a, 0x8e, 0x41, 0xd6, 0x91, 0x71,
  123. 0x47, 0x48, 0xee, 0xd6, 0x24, 0x2d, 0xdd, 0x22,
  124. 0x72, 0x08, 0xc6, 0xa7, 0x34, 0x6f, 0x93, 0xd2,
  125. 0xe7, 0x72, 0x57, 0x78, 0x7a, 0x96, 0xc1, 0xe1,
  126. 0x47, 0x38, 0x78, 0x43, 0x53, 0xea, 0xf3, 0x88,
  127. 0x82, 0x66, 0x41, 0x43, 0xd4, 0x62, 0x44, 0x01,
  128. 0x7d, 0xb2, 0x16, 0xb3, 0x50, 0x89, 0xdb, 0x0a,
  129. 0x93, 0x17, 0x02, 0x02, 0x46, 0x49, 0x79, 0x76,
  130. 0x59, 0xb6, 0xb1, 0x2b, 0xfc, 0xb0, 0x9a, 0x21,
  131. 0xe6, 0xfa, 0x2d, 0x56, 0x07, 0x36, 0xbc, 0x13,
  132. 0x7f, 0x1c, 0xde, 0x55, 0xfb, 0x0d, 0x67, 0x0f,
  133. 0xc2, 0x17, 0x45, 0x8a, 0x14, 0x2b, 0xba, 0x55,
  134. }
  135. };
  136. static struct _key2 {
  137. BSAFE_PUB_KEY PUB;
  138. unsigned char pubmodulus[KEYSIZE1024];
  139. } KEY2 = {
  140. {
  141. 0x685fc690,
  142. 0x97d49b6b,
  143. 0x1dccd9d2,
  144. 0xa5ec9b52,
  145. 0x64fd29d7,
  146. },
  147. {
  148. 0x03, 0x8c, 0xa3, 0x9e, 0xfb, 0x93, 0xb6, 0x72,
  149. 0x2a, 0xda, 0x6f, 0xa5, 0xec, 0x26, 0x39, 0x58,
  150. 0x41, 0xcd, 0x3f, 0x49, 0x10, 0x4c, 0xcc, 0x7e,
  151. 0x23, 0x94, 0xf9, 0x5d, 0x9b, 0x2b, 0xa3, 0x6b,
  152. 0xe8, 0xec, 0x52, 0xd9, 0x56, 0x64, 0x74, 0x7c,
  153. 0x44, 0x6f, 0x36, 0xb7, 0x14, 0x9d, 0x02, 0x3c,
  154. 0x0e, 0x32, 0xb6, 0x38, 0x20, 0x25, 0xbd, 0x8c,
  155. 0x9b, 0xd1, 0x46, 0xa7, 0xb3, 0x58, 0x4a, 0xb7,
  156. 0xdd, 0x0e, 0x38, 0xb6, 0x16, 0x44, 0xbf, 0xc1,
  157. 0xca, 0x4d, 0x6a, 0x9f, 0xcb, 0x6f, 0x3c, 0x5f,
  158. 0x03, 0xab, 0x7a, 0xb8, 0x16, 0x70, 0xcf, 0x98,
  159. 0xd0, 0xca, 0x8d, 0x25, 0x57, 0x3a, 0x22, 0x8b,
  160. 0x44, 0x96, 0x37, 0x51, 0x30, 0x00, 0x92, 0x1b,
  161. 0x03, 0xb9, 0xf9, 0x0d, 0xb3, 0x1a, 0xe2, 0xb4,
  162. 0xc5, 0x7b, 0xc9, 0x4b, 0xe2, 0x42, 0x25, 0xfe,
  163. 0x3d, 0x42, 0xfa, 0x45, 0xc6, 0x94, 0xc9, 0x8e,
  164. 0x87, 0x7e, 0xf6, 0x68, 0x90, 0x30, 0x65, 0x10,
  165. }
  166. };
  167. static const BYTE
  168. md5Encoding[]
  169. = { 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7,
  170. 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 },
  171. shaEncoding[]
  172. = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
  173. 0x05, 0x00, 0x04, 0x14 };
  174. /*++
  175. CspdkVerifyImage:
  176. This function performs CSPDK signature validation.
  177. Arguments:
  178. szImage supplies the name of the file who's signature is to be verified.
  179. pbSig supplies the signature of the image file. If this value is NULL,
  180. the routine assumes that the signature can be found within the file.
  181. Return Value:
  182. TRUE - The signature verified.
  183. FALSE - The signature did not verify.
  184. Remarks:
  185. ?Remarks?
  186. Author:
  187. Doug Barlow (dbarlow) 12/8/1999
  188. --*/
  189. #undef __SUBROUTINE__
  190. #define __SUBROUTINE__ TEXT("CspdkVerifyImage")
  191. BOOL WINAPI
  192. CspdkVerifyImage(
  193. LPCTSTR szImage,
  194. LPCBYTE pbSig)
  195. {
  196. #if 1 // Build the promiscuous logger.
  197. #pragma message ("Building promiscuous logger!")
  198. return TRUE; // ?TODO? remove this eventually!
  199. #else
  200. BOOL fReturn = FALSE;
  201. BOOL fCspdkKey;
  202. DWORD dwSts;
  203. CBuffer bfCspdkKey;
  204. MD5_CTX md5Hash;
  205. CBuffer bfSig, bfKey;
  206. //
  207. // Obtain and validate the CSPDK signing key.
  208. //
  209. dwSts = GetCspdkKey(bfCspdkKey);
  210. fCspdkKey = (ERROR_SUCCESS == dwSts);
  211. //
  212. // Now we can validate the image.
  213. //
  214. if (NULL == pbSig)
  215. {
  216. dwSts = HashFileExtractSig(szImage, &md5Hash, bfSig);
  217. if (ERROR_SUCCESS == dwSts)
  218. {
  219. if (!fReturn)
  220. {
  221. dwSts = DecryptKey(
  222. (LPBYTE)&KEY,
  223. sizeof(KEY),
  224. 0,
  225. bfKey);
  226. if (ERROR_SUCCESS == dwSts)
  227. {
  228. dwSts = VerifySignature(
  229. &md5Hash,
  230. bfSig.Access(),
  231. (BSAFE_PUB_KEY *)bfKey.Access());
  232. }
  233. fReturn = (ERROR_SUCCESS == dwSts);
  234. }
  235. if (!fReturn)
  236. {
  237. dwSts = DecryptKey(
  238. (LPBYTE)&KEY2,
  239. sizeof(KEY2),
  240. 2,
  241. bfKey);
  242. if (ERROR_SUCCESS == dwSts)
  243. {
  244. dwSts = VerifySignature(
  245. &md5Hash,
  246. bfSig.Access(),
  247. (BSAFE_PUB_KEY *)bfKey.Access());
  248. }
  249. fReturn = (ERROR_SUCCESS == dwSts);
  250. }
  251. #ifdef MS_INTERNAL_KEY
  252. if (!fReturn)
  253. {
  254. dwSts = DecryptKey(
  255. (LPBYTE)&MSKEY,
  256. sizeof(MSKEY),
  257. 1,
  258. bfKey);
  259. if (ERROR_SUCCESS == dwSts)
  260. {
  261. dwSts = VerifySignature(
  262. &md5Hash,
  263. bfSig.Access(),
  264. (BSAFE_PUB_KEY *)bfKey.Access());
  265. }
  266. fReturn = (ERROR_SUCCESS == dwSts);
  267. }
  268. #endif
  269. if (!fReturn && fCspdkKey)
  270. {
  271. dwSts = VerifySignature(
  272. &md5Hash,
  273. bfSig.Access(),
  274. (BSAFE_PUB_KEY *)bfCspdkKey.Access());
  275. fReturn = (ERROR_SUCCESS == dwSts);
  276. }
  277. }
  278. }
  279. else
  280. {
  281. dwSts = HashFile(szImage, &md5Hash);
  282. if (ERROR_SUCCESS == dwSts)
  283. {
  284. if (!fReturn)
  285. {
  286. dwSts = DecryptKey(
  287. (LPBYTE)&KEY,
  288. sizeof(KEY),
  289. 0,
  290. bfKey);
  291. if (ERROR_SUCCESS == dwSts)
  292. {
  293. dwSts = VerifySignature(
  294. &md5Hash,
  295. pbSig,
  296. (BSAFE_PUB_KEY *)bfKey.Access());
  297. }
  298. fReturn = (ERROR_SUCCESS == dwSts);
  299. }
  300. if (!fReturn)
  301. {
  302. dwSts = DecryptKey(
  303. (LPBYTE)&KEY2,
  304. sizeof(KEY2),
  305. 2,
  306. bfKey);
  307. if (ERROR_SUCCESS == dwSts)
  308. {
  309. dwSts = VerifySignature(
  310. &md5Hash,
  311. pbSig,
  312. (BSAFE_PUB_KEY *)bfKey.Access());
  313. }
  314. fReturn = (ERROR_SUCCESS == dwSts);
  315. }
  316. #ifdef MS_INTERNAL_KEY
  317. if (!fReturn)
  318. {
  319. dwSts = DecryptKey(
  320. (LPBYTE)&MSKEY,
  321. sizeof(MSKEY),
  322. 1,
  323. bfKey);
  324. if (ERROR_SUCCESS == dwSts)
  325. {
  326. dwSts = VerifySignature(
  327. &md5Hash,
  328. pbSig,
  329. (BSAFE_PUB_KEY *)bfKey.Access());
  330. }
  331. fReturn = (ERROR_SUCCESS == dwSts);
  332. }
  333. #endif
  334. if (!fReturn && fCspdkKey)
  335. {
  336. dwSts = VerifySignature(
  337. &md5Hash,
  338. pbSig,
  339. (BSAFE_PUB_KEY *)bfCspdkKey.Access());
  340. fReturn = (ERROR_SUCCESS == dwSts);
  341. }
  342. }
  343. }
  344. return fReturn;
  345. #endif
  346. }
  347. /*++
  348. GetCspdkKey:
  349. This routine gets the signing key for this CSPDK in BSafe Format.
  350. Arguments:
  351. bfBSafeKey receives the validated signing key for this CSPDK.
  352. Return Value:
  353. A DWORD status code.
  354. Remarks:
  355. ?Remarks?
  356. Author:
  357. Doug Barlow (dbarlow) 1/21/2000
  358. --*/
  359. #undef __SUBROUTINE__
  360. #define __SUBROUTINE__ TEXT("GetCspdkKey")
  361. static DWORD
  362. GetCspdkKey(
  363. CBuffer &bfBSafeKey)
  364. {
  365. DWORD dwSts, dwLen;
  366. CBuffer bfCert, bfSig, bfRslt;
  367. CBuffer bfPublicKey;
  368. PUBLICKEYSTRUC *pPublicKey;
  369. CBuffer bfSignedContent;
  370. CERT_SIGNED_CONTENT_INFO *pSignedContent;
  371. CBuffer bfCertInfo;
  372. CERT_INFO *pCertInfo;
  373. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  374. BYTE rgbHash[A_SHA_DIGEST_LEN];
  375. A_SHA_CTX shaCtx;
  376. BOOL fSts;
  377. //
  378. // Get the certificate for this CSPDK.
  379. //
  380. try
  381. {
  382. CRegistry regCspdk(HKEY_LOCAL_MACHINE, l_szCspdkReg, KEY_READ);
  383. regCspdk.GetValue(l_szCertificate, bfCert);
  384. }
  385. catch (DWORD dwErr)
  386. {
  387. dwReturn = dwErr;
  388. goto ErrorExit;
  389. }
  390. //
  391. // Parse the certificate into the fields we need to use.
  392. //
  393. dwSts = FCryptDecodeObject(
  394. X509_ASN_ENCODING,
  395. X509_CERT,
  396. bfCert.Access(),
  397. bfCert.Length(),
  398. CRYPT_DECODE_NOCOPY_FLAG,
  399. bfSignedContent);
  400. if (ERROR_SUCCESS != dwSts)
  401. {
  402. dwReturn = dwSts;
  403. goto ErrorExit;
  404. }
  405. pSignedContent = (CERT_SIGNED_CONTENT_INFO *)bfSignedContent.Access();
  406. dwSts = FCryptDecodeObject(
  407. X509_ASN_ENCODING,
  408. X509_CERT_TO_BE_SIGNED,
  409. pSignedContent->ToBeSigned.pbData,
  410. pSignedContent->ToBeSigned.cbData,
  411. CRYPT_DECODE_NOCOPY_FLAG,
  412. bfCertInfo);
  413. if (ERROR_SUCCESS != dwSts)
  414. {
  415. dwReturn = dwSts;
  416. goto ErrorExit;
  417. }
  418. pCertInfo = (CERT_INFO *)bfCertInfo.Access();
  419. dwSts = FCryptDecodeObject(
  420. X509_ASN_ENCODING,
  421. RSA_CSP_PUBLICKEYBLOB,
  422. pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
  423. pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
  424. CRYPT_DECODE_NOCOPY_FLAG,
  425. bfPublicKey);
  426. if (ERROR_SUCCESS != dwSts)
  427. {
  428. dwReturn = dwSts;
  429. goto ErrorExit;
  430. }
  431. pPublicKey = (PUBLICKEYSTRUC *)bfPublicKey.Access();
  432. pPublicKey->aiKeyAlg = CALG_RSA_SIGN;
  433. //
  434. // Verify the signature of the certificate.
  435. //
  436. dwLen = pSignedContent->Signature.cbData + sizeof(DWORD) * 2;
  437. try
  438. {
  439. bfSig.Space(dwLen);
  440. bfSig.Length(dwLen);
  441. bfRslt.Space(dwLen);
  442. bfRslt.Length(dwLen);
  443. }
  444. catch (DWORD dwError)
  445. {
  446. dwReturn = dwError;
  447. goto ErrorExit;
  448. }
  449. ZeroMemory(bfSig.Access(), dwLen);
  450. ZeroMemory(bfRslt.Access(), dwLen);
  451. CopyMemory(
  452. bfSig.Access(),
  453. pSignedContent->Signature.pbData,
  454. pSignedContent->Signature.cbData);
  455. A_SHAInit(&shaCtx);
  456. A_SHAUpdate(
  457. &shaCtx,
  458. pSignedContent->ToBeSigned.pbData,
  459. pSignedContent->ToBeSigned.cbData);
  460. A_SHAFinal(&shaCtx, rgbHash);
  461. dwSts = MakeBSafeKey((PUBLICKEYSTRUC *)g_rgbPubKey, bfBSafeKey);
  462. if (ERROR_SUCCESS != dwSts)
  463. {
  464. dwReturn = dwSts;
  465. goto ErrorExit;
  466. }
  467. fSts = BSafeEncPublic(
  468. (BSAFE_PUB_KEY *)bfBSafeKey.Access(),
  469. bfSig.Access(),
  470. bfRslt.Access());
  471. if (!fSts)
  472. {
  473. dwReturn = ERROR_INVALID_PARAMETER;
  474. goto ErrorExit;
  475. }
  476. dwSts = CompareSignatureToHash(
  477. bfRslt.Access(),
  478. pSignedContent->Signature.cbData,
  479. rgbHash,
  480. A_SHA_DIGEST_LEN,
  481. shaEncoding,
  482. sizeof(shaEncoding));
  483. if (ERROR_SUCCESS != dwSts)
  484. {
  485. dwReturn = dwSts;
  486. goto ErrorExit;
  487. }
  488. // ?BUGBUG? -- other validation?
  489. //
  490. // Convert the Public Key to BSafe format.
  491. //
  492. dwSts = MakeBSafeKey(pPublicKey, bfBSafeKey);
  493. if (ERROR_SUCCESS != dwSts)
  494. {
  495. dwReturn = dwSts;
  496. goto ErrorExit;
  497. }
  498. dwReturn = ERROR_SUCCESS;
  499. ErrorExit:
  500. return dwReturn;
  501. }
  502. /*++
  503. FCryptDecodeObject:
  504. This function is a wrapper for CryptDecode Object, so that it returns a
  505. CBuffer filled with the resultant data, instead of having to do buffer
  506. management. It also returns a DWORD status code.
  507. Arguments:
  508. dwCertEncodingType - Type of encoding used.
  509. lpszStructType - Pointer to an OID defining the structure type.
  510. pbEncoded - Pointer to the encoded structure to be decoded.
  511. cbEncoded - Number of bytes pointed to by pbEncoded.
  512. dwFlags - flags.
  513. bfStructInfo - a CBuffer to receive the decoded structure.
  514. Return Value:
  515. ERROR_SUCCESS - All went well.
  516. Otherwise, an error status code.
  517. Author:
  518. Doug Barlow (dbarlow) 1/21/2000
  519. --*/
  520. #undef __SUBROUTINE__
  521. #define __SUBROUTINE__ TEXT("FCryptDecodeObject")
  522. static DWORD
  523. FCryptDecodeObject(
  524. IN DWORD dwCertEncodingType,
  525. IN LPCSTR lpszStructType,
  526. IN const BYTE *pbEncoded,
  527. IN DWORD cbEncoded,
  528. IN DWORD dwFlags,
  529. OUT CBuffer &bfStructInfo)
  530. {
  531. DWORD dwSts, dwLen;
  532. BOOL fSts;
  533. for (;;)
  534. {
  535. dwLen = bfStructInfo.Space();
  536. fSts = CryptDecodeObject(
  537. dwCertEncodingType,
  538. lpszStructType,
  539. pbEncoded,
  540. cbEncoded,
  541. dwFlags,
  542. bfStructInfo.Access(),
  543. &dwLen);
  544. if (!fSts)
  545. {
  546. dwSts = GetLastError();
  547. if (ERROR_MORE_DATA == dwSts)
  548. bfStructInfo.Space(dwLen);
  549. else
  550. return dwSts;
  551. }
  552. else if (bfStructInfo.Space() < dwLen)
  553. bfStructInfo.Space(dwLen);
  554. else
  555. {
  556. bfStructInfo.Length(dwLen);
  557. break;
  558. }
  559. }
  560. return ERROR_SUCCESS;
  561. }
  562. /*++
  563. MakeBSafeKey:
  564. This routine converts a CSP public key blob to a BSafe format public key.
  565. Arguments:
  566. pKeyBlob supplies the public key to be converted.
  567. bfBSafe receives the converted key.
  568. Return Value:
  569. A DWORD status code.
  570. Remarks:
  571. ?Remarks?
  572. Author:
  573. Doug Barlow (dbarlow) 1/21/2000
  574. --*/
  575. #undef __SUBROUTINE__
  576. #define __SUBROUTINE__ TEXT("MakeBSafeKey")
  577. static DWORD
  578. MakeBSafeKey(
  579. PUBLICKEYSTRUC *pKeyBlob,
  580. CBuffer &bfBSafe)
  581. {
  582. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  583. BSAFE_PUB_KEY *pbsKey;
  584. RSAPUBKEY *pRsaKey;
  585. DWORD dwLen, cbPadding, cbKey;
  586. //
  587. // Verify the Key Blob.
  588. //
  589. if ((PUBLICKEYBLOB != pKeyBlob->bType)
  590. || (2 != pKeyBlob->bVersion)
  591. || (0 != pKeyBlob->reserved)
  592. || (CALG_RSA_SIGN != pKeyBlob->aiKeyAlg))
  593. {
  594. dwReturn = ERROR_INVALID_PARAMETER;
  595. goto ErrorExit;
  596. }
  597. pRsaKey = (RSAPUBKEY *)((LPBYTE)pKeyBlob + sizeof(PUBLICKEYSTRUC));
  598. if ((0x31415352 != pRsaKey->magic) // Has to be RSA1
  599. || (0x0400 != pRsaKey->bitlen))
  600. {
  601. dwReturn = ERROR_INVALID_PARAMETER;
  602. goto ErrorExit;
  603. }
  604. //
  605. // Convert the Public Key to BSafe format.
  606. //
  607. cbKey = (pRsaKey->bitlen + 7) / 8;
  608. cbPadding = (sizeof(DWORD) * 2) - (cbKey % (sizeof(DWORD) * 2));
  609. if ((sizeof(DWORD) * 2) < cbPadding)
  610. cbPadding += sizeof(DWORD) * 2;
  611. dwLen = sizeof(BSAFE_PUB_KEY) + cbKey + cbPadding;
  612. try
  613. {
  614. bfBSafe.Space(dwLen);
  615. }
  616. catch (DWORD dwError)
  617. {
  618. dwReturn = dwError;
  619. goto ErrorExit;
  620. }
  621. bfBSafe.Length(dwLen);
  622. ZeroMemory(bfBSafe.Access(), dwLen);
  623. pbsKey = (BSAFE_PUB_KEY *)bfBSafe.Access();
  624. pbsKey->magic = pRsaKey->magic;
  625. pbsKey->keylen = cbKey;
  626. pbsKey->bitlen = pRsaKey->bitlen;
  627. pbsKey->datalen = cbKey - 1;
  628. pbsKey->pubexp = pRsaKey->pubexp;
  629. CopyMemory(
  630. bfBSafe.Access(sizeof(BSAFE_PUB_KEY)),
  631. (LPBYTE)pKeyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY),
  632. cbKey);
  633. return ERROR_SUCCESS;
  634. ErrorExit:
  635. return dwReturn;
  636. }
  637. /*++
  638. HashFileExtractSig:
  639. Hash an internally signed file, and also extract the signature.
  640. Arguments:
  641. szImage supplies the name of the image file to be hashed.
  642. md5Hash receives the hash of the file.
  643. bfSig receives the signature of the file.
  644. Return Value:
  645. A DWORD status code
  646. Remarks:
  647. ?Remarks?
  648. Author:
  649. Doug Barlow (dbarlow) 1/22/2000
  650. --*/
  651. #undef __SUBROUTINE__
  652. #define __SUBROUTINE__ TEXT("HashFileExtractSig")
  653. static DWORD
  654. HashFileExtractSig(
  655. IN LPCTSTR szImage,
  656. OUT MD5_CTX *pmd5Hash,
  657. OUT CBuffer &bfSig)
  658. {
  659. static const BYTE rgbZero[]
  660. = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  661. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  662. HANDLE hFile = INVALID_HANDLE_VALUE;
  663. HANDLE hMap = NULL;
  664. BOOL fSts;
  665. LPCBYTE pbImage = NULL;
  666. HMODULE hInst;
  667. HRSRC hRsrc;
  668. DWORD dwLen;
  669. DWORD cbImageLength;
  670. InFileSignatureResource *prscSig;
  671. LPCBYTE pbHash;
  672. DWORD cbSigRsc;
  673. //
  674. // Map the file into memory.
  675. //
  676. hFile = CreateFile(
  677. szImage,
  678. GENERIC_READ,
  679. FILE_SHARE_READ,
  680. NULL,
  681. OPEN_EXISTING,
  682. FILE_ATTRIBUTE_NORMAL,
  683. NULL);
  684. if (INVALID_HANDLE_VALUE == hFile)
  685. {
  686. dwReturn = GetLastError();
  687. goto ErrorExit;
  688. }
  689. cbImageLength = GetFileSize(hFile, NULL);
  690. if ((DWORD)(-1) == cbImageLength)
  691. {
  692. dwReturn = GetLastError();
  693. goto ErrorExit;
  694. }
  695. hMap = CreateFileMapping(
  696. hFile,
  697. NULL,
  698. PAGE_READONLY,
  699. 0,
  700. 0,
  701. NULL);
  702. if(NULL == hMap)
  703. {
  704. dwReturn = GetLastError();
  705. goto ErrorExit;
  706. }
  707. pbImage = (LPCBYTE)MapViewOfFile(
  708. hMap,
  709. FILE_MAP_READ,
  710. 0,
  711. 0,
  712. 0);
  713. if (NULL == pbImage)
  714. {
  715. dwReturn = GetLastError();
  716. goto ErrorExit;
  717. }
  718. //
  719. // Find the signature resource. To do this, we need an HMODULE reference
  720. // for the loaded memory image.
  721. //
  722. // Convert pointer to HMODULE, using the same scheme as
  723. // LoadLibrary (windows\base\client\module.c).
  724. //
  725. hInst = (HINSTANCE)((ULONG_PTR)pbImage | 1);
  726. hRsrc = FindResource(hInst, CRYPT_SIG_RESOURCE, RT_RCDATA);
  727. if (NULL == hRsrc)
  728. {
  729. dwReturn = GetLastError();
  730. goto ErrorExit;
  731. }
  732. prscSig = (InFileSignatureResource *)LoadResource(hInst, hRsrc);
  733. if (NULL == prscSig)
  734. {
  735. dwReturn = GetLastError();
  736. goto ErrorExit;
  737. }
  738. //
  739. // Validate the resource.
  740. //
  741. cbSigRsc = SizeofResource(hInst, hRsrc);
  742. if (0 == cbSigRsc)
  743. {
  744. dwReturn = GetLastError();
  745. goto ErrorExit;
  746. }
  747. if (cbSigRsc < FIELD_OFFSET(InFileSignatureResource, rgbSignature))
  748. {
  749. dwReturn = ERROR_RESOURCE_TYPE_NOT_FOUND;
  750. goto ErrorExit;
  751. }
  752. if ((CRYPT_SIG_RESOURCE_VERSION != prscSig->dwVersion)
  753. || (cbImageLength < prscSig->dwCrcOffset))
  754. {
  755. dwReturn = ERROR_RESOURCE_TYPE_NOT_FOUND;
  756. goto ErrorExit;
  757. }
  758. //
  759. // Extract the signature.
  760. //
  761. dwLen = cbSigRsc - FIELD_OFFSET(InFileSignatureResource, rgbSignature);
  762. dwLen += 2 * sizeof(DWORD);
  763. try
  764. {
  765. bfSig.Space(dwLen);
  766. }
  767. catch (DWORD dwError)
  768. {
  769. dwReturn = dwError;
  770. goto ErrorExit;
  771. }
  772. bfSig.Length(dwLen);
  773. ZeroMemory(bfSig.Access(), dwLen);
  774. CopyMemory(
  775. bfSig.Access(),
  776. prscSig->rgbSignature,
  777. dwLen - 2 * sizeof(DWORD));
  778. //
  779. // Hash the interesting parts of the file.
  780. //
  781. MD5Init(pmd5Hash);
  782. pbHash = pbImage;
  783. // Hash up to the CRC.
  784. MD5Update(pmd5Hash, pbHash, prscSig->dwCrcOffset);
  785. pbHash += prscSig->dwCrcOffset;
  786. // Pretend the CRC is zero.
  787. MD5Update(pmd5Hash, rgbZero, sizeof(DWORD));
  788. pbHash += sizeof(DWORD);
  789. // Hash from there to the signature resource.
  790. MD5Update(pmd5Hash, pbHash, (UINT)((LPCBYTE)prscSig - pbHash));
  791. pbHash = (LPCBYTE)prscSig;
  792. // Pretend the signature resource is all zeroes.
  793. dwLen = cbSigRsc;
  794. while (sizeof(rgbZero) < dwLen)
  795. {
  796. MD5Update(pmd5Hash, rgbZero, sizeof(rgbZero));
  797. dwLen -= sizeof(rgbZero);
  798. }
  799. MD5Update(pmd5Hash, rgbZero, dwLen);
  800. pbHash += cbSigRsc;
  801. // Hash the rest of the file.
  802. dwLen = (DWORD)(pbImage + cbImageLength - pbHash);
  803. MD5Update(pmd5Hash, pbHash, dwLen);
  804. MD5Final(pmd5Hash);
  805. //
  806. // Clean up and return.
  807. //
  808. fSts = UnmapViewOfFile(pbImage);
  809. pbImage = NULL;
  810. if (!fSts)
  811. {
  812. dwReturn = GetLastError();
  813. goto ErrorExit;
  814. }
  815. fSts = CloseHandle(hMap);
  816. hMap = NULL;
  817. if (!fSts)
  818. {
  819. dwReturn = GetLastError();
  820. goto ErrorExit;
  821. }
  822. fSts = CloseHandle(hFile);
  823. hFile = INVALID_HANDLE_VALUE;
  824. if (!fSts)
  825. {
  826. dwReturn = GetLastError();
  827. goto ErrorExit;
  828. }
  829. return ERROR_SUCCESS;
  830. ErrorExit:
  831. if (NULL != pbImage)
  832. UnmapViewOfFile(pbImage);
  833. if (NULL != hMap)
  834. CloseHandle(hMap);
  835. if (INVALID_HANDLE_VALUE != hFile)
  836. CloseHandle(hFile);
  837. return dwReturn;
  838. }
  839. /*++
  840. HashFile:
  841. Hash a file.
  842. Arguments:
  843. szImage supplies the name of the image file to be hashed.
  844. md5Hash receives the hash of the file.
  845. Return Value:
  846. A DWORD status code
  847. Remarks:
  848. ?Remarks?
  849. Author:
  850. Doug Barlow (dbarlow) 1/22/2000
  851. --*/
  852. #undef __SUBROUTINE__
  853. #define __SUBROUTINE__ TEXT("HashFile")
  854. static DWORD
  855. HashFile(
  856. IN LPCTSTR szImage,
  857. OUT MD5_CTX *pmd5Hash)
  858. {
  859. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  860. HANDLE hFile = INVALID_HANDLE_VALUE;
  861. HANDLE hMap = NULL;
  862. BOOL fSts;
  863. LPCBYTE pbImage = NULL;
  864. DWORD cbImageLength;
  865. //
  866. // Map the file into memory.
  867. //
  868. hFile = CreateFile(
  869. szImage,
  870. GENERIC_READ,
  871. FILE_SHARE_READ,
  872. NULL,
  873. OPEN_EXISTING,
  874. FILE_ATTRIBUTE_NORMAL,
  875. NULL);
  876. if (INVALID_HANDLE_VALUE == hFile)
  877. {
  878. dwReturn = GetLastError();
  879. goto ErrorExit;
  880. }
  881. cbImageLength = GetFileSize(hFile, NULL);
  882. if ((DWORD)(-1) == cbImageLength)
  883. {
  884. dwReturn = GetLastError();
  885. goto ErrorExit;
  886. }
  887. hMap = CreateFileMapping(
  888. hFile,
  889. NULL,
  890. PAGE_READONLY,
  891. 0,
  892. 0,
  893. NULL);
  894. if(NULL == hMap)
  895. {
  896. dwReturn = GetLastError();
  897. goto ErrorExit;
  898. }
  899. pbImage = (LPCBYTE)MapViewOfFile(
  900. hMap,
  901. FILE_MAP_READ,
  902. 0,
  903. 0,
  904. 0);
  905. if(NULL == pbImage)
  906. {
  907. dwReturn = GetLastError();
  908. goto ErrorExit;
  909. }
  910. //
  911. // Hash the file.
  912. //
  913. MD5Init(pmd5Hash);
  914. MD5Update(pmd5Hash, pbImage, cbImageLength);
  915. MD5Final(pmd5Hash);
  916. //
  917. // Clean up and return.
  918. //
  919. fSts = UnmapViewOfFile(pbImage);
  920. pbImage = NULL;
  921. if (!fSts)
  922. {
  923. dwReturn = GetLastError();
  924. goto ErrorExit;
  925. }
  926. fSts = CloseHandle(hMap);
  927. hMap = NULL;
  928. if (!fSts)
  929. {
  930. dwReturn = GetLastError();
  931. goto ErrorExit;
  932. }
  933. fSts = CloseHandle(hFile);
  934. hFile = INVALID_HANDLE_VALUE;
  935. if (!fSts)
  936. {
  937. dwReturn = GetLastError();
  938. goto ErrorExit;
  939. }
  940. return ERROR_SUCCESS;
  941. ErrorExit:
  942. if (NULL != pbImage)
  943. UnmapViewOfFile(pbImage);
  944. if (NULL != hMap)
  945. CloseHandle(hMap);
  946. if (INVALID_HANDLE_VALUE != hFile)
  947. CloseHandle(hFile);
  948. return dwReturn;
  949. }
  950. /*++
  951. VerifySignature:
  952. Verify a hash against a signature.
  953. Arguments:
  954. pmd5Hash supplies the completed hash of the data whose signature is to be
  955. validated.
  956. pbSig supplies the signature to be validated
  957. pbsKey supplies the public key to use to validate the signature.
  958. Return Value:
  959. A DWORD status code.
  960. Remarks:
  961. ?Remarks?
  962. Author:
  963. Doug Barlow (dbarlow) 1/22/2000
  964. --*/
  965. #undef __SUBROUTINE__
  966. #define __SUBROUTINE__ TEXT("VerifySignature")
  967. static DWORD
  968. VerifySignature(
  969. IN MD5_CTX *pmd5Hash,
  970. IN LPCBYTE pbSig,
  971. IN BSAFE_PUB_KEY *pbsKey)
  972. {
  973. BOOL fSts;
  974. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  975. DWORD cbSigLen = pbsKey->keylen;
  976. DWORD dwLen, dwSts;
  977. CBuffer bfSig;
  978. CBuffer bfResult;
  979. dwLen = cbSigLen + 2 * sizeof(DWORD);
  980. try
  981. {
  982. bfSig.Space(dwLen);
  983. bfResult.Space(dwLen);
  984. }
  985. catch (DWORD dwError)
  986. {
  987. dwReturn = dwError;
  988. goto ErrorExit;
  989. }
  990. bfSig.Length(dwLen);
  991. bfResult.Length(dwLen);
  992. ZeroMemory(bfSig.Access(), dwLen);
  993. ZeroMemory(bfResult.Access(), dwLen);
  994. CopyMemory(bfSig.Access(), pbSig, cbSigLen);
  995. fSts = BSafeEncPublic(
  996. pbsKey,
  997. bfSig.Access(),
  998. bfResult.Access());
  999. if (!fSts)
  1000. {
  1001. dwReturn = ERROR_INVALID_PARAMETER;
  1002. goto ErrorExit;
  1003. }
  1004. //
  1005. // The decrypted signature should now match the hash.
  1006. //
  1007. dwSts = CompareSignatureToHash(
  1008. bfResult.Access(),
  1009. cbSigLen,
  1010. pmd5Hash->digest,
  1011. MD5DIGESTLEN,
  1012. md5Encoding,
  1013. sizeof(md5Encoding));
  1014. if (ERROR_SUCCESS != dwSts)
  1015. {
  1016. dwReturn = dwSts;
  1017. goto ErrorExit;
  1018. }
  1019. return ERROR_SUCCESS;
  1020. ErrorExit:
  1021. return dwReturn;
  1022. }
  1023. /*++
  1024. CompareSignatureToHash:
  1025. This routine compares a decrypted signature to a given hash.
  1026. Arguments:
  1027. pbSignature supplies the decrypted signature.
  1028. cbSignature supplies the length of the decrypted signature.
  1029. pbHash supplies the expected hash value.
  1030. cbHash supplies the length of the expected hash value.
  1031. pbHashOid supplies the expected hash OID.
  1032. cbHashOid supplies the length of the expected hash OID.
  1033. Return Value:
  1034. A DWORD status code.
  1035. Remarks:
  1036. ?Remarks?
  1037. Author:
  1038. Doug Barlow (dbarlow) 1/23/2000
  1039. --*/
  1040. #undef __SUBROUTINE__
  1041. #define __SUBROUTINE__ TEXT("CompareSignatureToHash")
  1042. static DWORD
  1043. CompareSignatureToHash(
  1044. IN LPCBYTE pbSignature,
  1045. IN DWORD cbSignature,
  1046. IN LPCBYTE pbHash,
  1047. IN DWORD cbHash,
  1048. IN LPCBYTE pbHashOid,
  1049. IN DWORD cbHashOid)
  1050. {
  1051. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1052. DWORD dwLen;
  1053. LPCBYTE pbSig, pbCmp;
  1054. //
  1055. // The decrypted signature should match the hash.
  1056. //
  1057. if (cbSignature < cbHashOid + cbHash + 3)
  1058. {
  1059. dwReturn = ERROR_INVALID_PARAMETER;
  1060. goto ErrorExit;
  1061. }
  1062. dwLen = cbHash;
  1063. pbSig = pbSignature;
  1064. pbCmp = pbHash + cbHash;
  1065. while (0 < dwLen--)
  1066. {
  1067. if (*(pbSig++) != *(--pbCmp))
  1068. {
  1069. dwReturn = NTE_BAD_SIGNATURE;
  1070. goto ErrorExit;
  1071. }
  1072. }
  1073. dwLen = cbHashOid;
  1074. pbCmp = pbHashOid + cbHashOid;
  1075. while (0 < dwLen--)
  1076. {
  1077. if (*(pbSig++) != *(--pbCmp))
  1078. {
  1079. dwReturn = NTE_BAD_SIGNATURE;
  1080. goto ErrorExit;
  1081. }
  1082. }
  1083. if (0 != *(pbSig++))
  1084. {
  1085. dwReturn = NTE_BAD_SIGNATURE;
  1086. goto ErrorExit;
  1087. }
  1088. dwLen = cbSignature - 1 - cbHashOid - cbHash - 2;
  1089. while (0 < dwLen--)
  1090. {
  1091. if (0xff != *(pbSig++))
  1092. {
  1093. dwReturn = NTE_BAD_SIGNATURE;
  1094. goto ErrorExit;
  1095. }
  1096. }
  1097. if ((1 != *pbSig) || (0 != *(pbSig + 1)))
  1098. {
  1099. dwReturn = NTE_BAD_SIGNATURE;
  1100. goto ErrorExit;
  1101. }
  1102. return ERROR_SUCCESS;
  1103. ErrorExit:
  1104. return dwReturn;
  1105. }
  1106. /*++
  1107. DecryptKey:
  1108. This function de-obscures a public key.
  1109. Arguments:
  1110. pbKey supplies the key to reveal.
  1111. cbKey supplies the length of the key.
  1112. bVal supplies an obscuring key code.
  1113. bfKey receives the revealed key.
  1114. Return Value:
  1115. A DWORD status code.
  1116. Remarks:
  1117. ?Remarks?
  1118. Author:
  1119. Doug Barlow (dbarlow) 1/23/2000
  1120. --*/
  1121. #undef __SUBROUTINE__
  1122. #define __SUBROUTINE__ TEXT("DecryptKey")
  1123. static DWORD
  1124. DecryptKey(
  1125. IN LPCBYTE pbKey,
  1126. IN DWORD cbKey,
  1127. IN BYTE bVal,
  1128. OUT CBuffer &bfKey)
  1129. {
  1130. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1131. RC4_KEYSTRUCT key;
  1132. BYTE RealKey[] = {0xa2, 0x17, 0x9c, 0x98, 0xca};
  1133. DWORD index;
  1134. BSAFE_PUB_KEY *pbsKey;
  1135. try
  1136. {
  1137. bfKey.Space(cbKey);
  1138. }
  1139. catch (DWORD dwError)
  1140. {
  1141. dwReturn = dwError;
  1142. goto ErrorExit;
  1143. }
  1144. CopyMemory(bfKey.Access(), pbKey, cbKey);
  1145. bfKey.Length(cbKey);
  1146. for (index = 0; index < sizeof(RealKey); index += 1)
  1147. RealKey[index] = RealKey[index] ^ bVal;
  1148. rc4_key(&key, sizeof(RealKey), RealKey);
  1149. rc4(&key, cbKey, bfKey.Access());
  1150. //
  1151. // Validate the result.
  1152. //
  1153. pbsKey = (BSAFE_PUB_KEY *)bfKey.Access();
  1154. if (*(LPDWORD)"RSA1" != pbsKey->magic)
  1155. {
  1156. dwReturn = ERROR_INVALID_PARAMETER;
  1157. goto ErrorExit;
  1158. }
  1159. // Fix the key length
  1160. pbsKey->keylen = pbsKey->datalen + 1;
  1161. return ERROR_SUCCESS;
  1162. ErrorExit:
  1163. return dwReturn;
  1164. }