Source code of Windows XP (NT5)
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.

303 lines
7.6 KiB

  1. #include "windows.h"
  2. #include "wincrypt.h"
  3. #include "mscat.h"
  4. #include "stdio.h"
  5. #include "stdlib.h"
  6. VOID
  7. DumpBytes(PBYTE pbBuffer, DWORD dwLength)
  8. {
  9. for (DWORD dw = 0; dw < dwLength; dw++)
  10. {
  11. if (dw % 4 == 0 && dw)
  12. wprintf(L" ");
  13. if (dw % 32 == 0 && dw)
  14. wprintf(L"\n");
  15. wprintf(L"%02x", pbBuffer[dw]);
  16. }
  17. }
  18. #pragma pack(1)
  19. typedef struct _PublicKeyBlob
  20. {
  21. unsigned int SigAlgID;
  22. unsigned int HashAlgID;
  23. ULONG cbPublicKey;
  24. BYTE PublicKey[1];
  25. }
  26. PublicKeyBlob, *PPublicKeyBlob;
  27. VOID
  28. GenerateFusionStrongNameAndKeyFromCertificate(PCCERT_CONTEXT pContext)
  29. {
  30. HCRYPTPROV hProvider;
  31. HCRYPTKEY hKey;
  32. PBYTE pbFusionKeyBlob;
  33. BYTE pbBlobData[8192];
  34. DWORD cbBlobData = sizeof(pbBlobData);
  35. DWORD cbFusionKeyBlob, dwTemp;
  36. PPublicKeyBlob pFusionKeyStruct;
  37. if (!::CryptAcquireContextW(
  38. &hProvider,
  39. NULL,
  40. NULL,
  41. PROV_RSA_FULL,
  42. CRYPT_VERIFYCONTEXT))
  43. {
  44. wprintf(L"Failed opening the crypt context: 0x%08x", ::GetLastError());
  45. return;
  46. }
  47. //
  48. // Load the public key info into a key to start with
  49. //
  50. if (!CryptImportPublicKeyInfo(
  51. hProvider,
  52. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  53. &pContext->pCertInfo->SubjectPublicKeyInfo,
  54. &hKey))
  55. {
  56. wprintf(L"Failed importing public key info from the cert-context, 0x%08x", ::GetLastError());
  57. return;
  58. }
  59. //
  60. // Export the key info to a public-key blob
  61. //
  62. if (!CryptExportKey(
  63. hKey,
  64. NULL,
  65. PUBLICKEYBLOB,
  66. 0,
  67. pbBlobData,
  68. &cbBlobData))
  69. {
  70. wprintf(L"Failed exporting public key info back from an hcryptkey: 0x%08x\n", ::GetLastError());
  71. return;
  72. }
  73. //
  74. // Allocate the Fusion public key blob
  75. //
  76. cbFusionKeyBlob = sizeof(PublicKeyBlob) + cbBlobData - 1;
  77. pFusionKeyStruct = (PPublicKeyBlob)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbFusionKeyBlob);
  78. //
  79. // Key parameter for the signing algorithm
  80. //
  81. dwTemp = sizeof(pFusionKeyStruct->SigAlgID);
  82. CryptGetKeyParam(hKey, KP_ALGID, (PBYTE)&pFusionKeyStruct->SigAlgID, &dwTemp, 0);
  83. //
  84. // Move over the public key bits from CryptExportKey
  85. //
  86. pFusionKeyStruct->cbPublicKey = cbBlobData;
  87. pFusionKeyStruct->HashAlgID = CALG_SHA1;
  88. memcpy(pFusionKeyStruct->PublicKey, pbBlobData, cbBlobData);
  89. wprintf(L"\n Public key structure:\n");
  90. DumpBytes((PBYTE)pFusionKeyStruct, cbFusionKeyBlob);
  91. //
  92. // Now let's go hash it.
  93. //
  94. {
  95. HCRYPTHASH hKeyHash;
  96. BYTE bHashedKeyInfo[8192];
  97. DWORD cbHashedKeyInfo = sizeof(bHashedKeyInfo);
  98. if (!CryptCreateHash(hProvider, pFusionKeyStruct->HashAlgID, NULL, 0, &hKeyHash))
  99. {
  100. wprintf(L"Failed creating a hash for this key: 0x%08x\n", ::GetLastError());
  101. return;
  102. }
  103. if (!CryptHashData(hKeyHash, (PBYTE)pFusionKeyStruct, cbFusionKeyBlob, 0))
  104. {
  105. wprintf(L"Failed hashing data: 0x%08x\n", ::GetLastError());
  106. return;
  107. }
  108. if (!CryptGetHashParam(hKeyHash, HP_HASHVAL, bHashedKeyInfo, &cbHashedKeyInfo, 0))
  109. {
  110. wprintf(L"Can't get hashed key info 0x%08x\n", ::GetLastError());
  111. return;
  112. }
  113. CryptDestroyHash(hKeyHash);
  114. wprintf(L"\n Hash of public key bits: ");
  115. DumpBytes(bHashedKeyInfo, cbHashedKeyInfo);
  116. wprintf(L"\n Fusion-compatible strong name: ");
  117. DumpBytes(bHashedKeyInfo + (cbHashedKeyInfo - 8), 8);
  118. }
  119. }
  120. VOID
  121. PrintKeyContextInfo(PCCERT_CONTEXT pContext)
  122. {
  123. BYTE bHash[8192];
  124. DWORD cbHash;
  125. WCHAR wszBuffer[8192];
  126. DWORD cchBuffer = 8192;
  127. wprintf(L"\n\n");
  128. CertGetNameStringW(pContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
  129. 0, NULL, wszBuffer, cchBuffer);
  130. wprintf(L"Certificate owner: %ls\n", wszBuffer);
  131. //
  132. // Spit out the key bits
  133. //
  134. wprintf(L"Found key info:\n");
  135. DumpBytes(
  136. pContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
  137. pContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
  138. //
  139. // And now the "strong name" (ie: sha1 hash) of the public key bits
  140. //
  141. if (CryptHashPublicKeyInfo(
  142. NULL,
  143. CALG_SHA1,
  144. 0,
  145. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  146. &pContext->pCertInfo->SubjectPublicKeyInfo,
  147. bHash,
  148. &(cbHash = sizeof(bHash))))
  149. {
  150. wprintf(L"\nPublic key hash: ");
  151. DumpBytes(bHash, cbHash);
  152. wprintf(L"\nStrong name is: ");
  153. DumpBytes(bHash, cbHash < 8 ? cbHash : 8);
  154. }
  155. else
  156. {
  157. wprintf(L"Unable to hash public key info: 0x%08x\n", ::GetLastError());
  158. }
  159. GenerateFusionStrongNameAndKeyFromCertificate(pContext);
  160. wprintf(L"\n\n");
  161. }
  162. int __cdecl wmain(int argc, WCHAR* argv[])
  163. {
  164. HANDLE hCatalog;
  165. HANDLE hMapping;
  166. PBYTE pByte;
  167. SIZE_T cBytes;
  168. PCCTL_CONTEXT pContext;
  169. hCatalog = CreateFileW(argv[1], GENERIC_READ,
  170. FILE_SHARE_READ, NULL,
  171. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  172. if (hCatalog == INVALID_HANDLE_VALUE)
  173. {
  174. wprintf(L"Ensure that %ls exists.\n", argv[1]);
  175. return 0;
  176. }
  177. hMapping = CreateFileMapping(hCatalog, NULL, PAGE_READONLY, 0, 0, NULL);
  178. if (!hMapping || (hMapping == INVALID_HANDLE_VALUE))
  179. {
  180. CloseHandle(hCatalog);
  181. wprintf(L"Unable to map file into address space.\n");
  182. return 1;
  183. }
  184. pByte = (PBYTE)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
  185. CloseHandle(hMapping);
  186. if (!pByte)
  187. {
  188. wprintf(L"Unable to open view of file.\n");
  189. CloseHandle(hCatalog);
  190. return 2;
  191. }
  192. if (((cBytes = GetFileSize(hCatalog, NULL)) == -1) || (cBytes < 1))
  193. {
  194. wprintf(L"Bad file size %d\n", cBytes);
  195. return 3;
  196. }
  197. if (pByte[0] != 0x30)
  198. {
  199. wprintf(L"File is not a catalog.\n");
  200. return 4;
  201. }
  202. pContext = (PCCTL_CONTEXT)CertCreateCTLContext(
  203. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  204. pByte,
  205. cBytes);
  206. if (pContext)
  207. {
  208. BYTE bIdent[8192];
  209. DWORD cbIdent;
  210. PCERT_ID cIdent;
  211. if (!CryptMsgGetParam(
  212. pContext->hCryptMsg,
  213. CMSG_SIGNER_CERT_ID_PARAM,
  214. 0,
  215. bIdent,
  216. &(cbIdent = sizeof(bIdent))))
  217. {
  218. wprintf(L"Unable to get top-level signer's certificate ID: 0x%08x\n", ::GetLastError());
  219. return 6;
  220. }
  221. cIdent = (PCERT_ID)bIdent;
  222. HCERTSTORE hStore;
  223. //
  224. // Maybe it's there in the message?
  225. //
  226. {
  227. PCCERT_CONTEXT pThisContext = NULL;
  228. hStore = CertOpenStore(
  229. CERT_STORE_PROV_MSG,
  230. X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
  231. NULL,
  232. 0,
  233. pContext->hCryptMsg);
  234. if (hStore && (hStore != INVALID_HANDLE_VALUE))
  235. {
  236. while (pThisContext = CertEnumCertificatesInStore(hStore, pThisContext))
  237. {
  238. PCERT_INFO pInfo = pThisContext->pCertInfo;
  239. WCHAR wszBuffer[8192];
  240. DWORD cchBuffer = sizeof(wszBuffer)/sizeof(*wszBuffer);
  241. PrintKeyContextInfo(pThisContext);
  242. }
  243. }
  244. }
  245. }
  246. else
  247. {
  248. wprintf(L"Failed creating certificate context: 0x%08x\n", ::GetLastError());
  249. return 5;
  250. }
  251. }