1 /*
2  * PROJECT:     ReactOS certutil
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     CertUtil stub
5  * COPYRIGHT:   Copyright 2020 Mark Jansen (mark.jansen@reactos.org)
6  *
7  * Note: Only -hashfile is implemented for now, the rest is not present!
8  */
9 
10 #include "precomp.h"
11 #include <wincrypt.h>
12 #include <stdlib.h>
13 
14 
15 static BOOL hash_file(LPCWSTR Filename)
16 {
17     HCRYPTPROV hProv;
18     BOOL bSuccess = FALSE;
19 
20     HANDLE hFile = CreateFileW(Filename, GENERIC_READ, FILE_SHARE_READ, NULL,
21                                OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
22 
23     if (hFile == INVALID_HANDLE_VALUE)
24     {
25         ConPrintf(StdOut, L"CertUtil: -hashfile command failed: %d\n", GetLastError());
26         return bSuccess;
27     }
28 
29     if (CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
30     {
31         HCRYPTHASH hHash;
32 
33         if (CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
34         {
35             BYTE Buffer[2048];
36             DWORD cbRead;
37 
38             while ((bSuccess = ReadFile(hFile, Buffer, sizeof(Buffer), &cbRead, NULL)))
39             {
40                 if (cbRead == 0)
41                     break;
42 
43                 if (!CryptHashData(hHash, Buffer, cbRead, 0))
44                 {
45                     bSuccess = FALSE;
46                     ConPrintf(StdOut, L"CertUtil: -hashfile command failed to hash: %d\n", GetLastError());
47                     break;
48                 }
49             }
50 
51             if (bSuccess)
52             {
53                 BYTE rgbHash[20];
54                 DWORD cbHash, n;
55 
56                 if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
57                 {
58                     ConPrintf(StdOut, L"SHA1 hash of %s:\n", Filename);
59                     for (n = 0; n < cbHash; ++n)
60                     {
61                         ConPrintf(StdOut, L"%02x", rgbHash[n]);
62                     }
63                     ConPuts(StdOut, L"\n");
64                 }
65                 else
66                 {
67                     ConPrintf(StdOut, L"CertUtil: -hashfile command failed to extract hash: %d\n", GetLastError());
68                     bSuccess = FALSE;
69                 }
70             }
71 
72             CryptDestroyHash(hHash);
73         }
74         else
75         {
76             ConPrintf(StdOut, L"CertUtil: -hashfile command no algorithm: %d\n", GetLastError());
77         }
78 
79         CryptReleaseContext(hProv, 0);
80     }
81     else
82     {
83         ConPrintf(StdOut, L"CertUtil: -hashfile command no context: %d\n", GetLastError());
84     }
85 
86     CloseHandle(hFile);
87     return bSuccess;
88 }
89 
90 
91 static void print_usage()
92 {
93     ConPuts(StdOut, L"Verbs:\n");
94     ConPuts(StdOut, L"  -hashfile           -- Display cryptographic hash over a file\n");
95     ConPuts(StdOut, L"\n");
96     ConPuts(StdOut, L"CertUtil -?           -- Display a list of all verbs\n");
97     ConPuts(StdOut, L"CertUtil -hashfile -? -- Display help text for the 'hashfile' verb\n");
98 }
99 
100 int wmain(int argc, WCHAR *argv[])
101 {
102     int n;
103 
104     /* Initialize the Console Standard Streams */
105     ConInitStdStreams();
106 
107     if (argc == 1) /* i.e. no commandline arguments given */
108     {
109         print_usage();
110         return EXIT_SUCCESS;
111     }
112 
113     for (n = 1; n < argc; ++n)
114     {
115         if (!_wcsicmp(argv[n], L"-?"))
116         {
117             print_usage();
118             return EXIT_SUCCESS;
119         }
120         else if (!_wcsicmp(argv[n], L"-hashfile"))
121         {
122             if (argc == 3)
123             {
124                 if (!_wcsicmp(argv[n+1], L"-?"))
125                 {
126                     print_usage();
127                     return EXIT_SUCCESS;
128                 }
129                 else
130                 {
131                     if (!hash_file(argv[n+1]))
132                     {
133                         /* hash_file prints the failure itself */
134                         return EXIT_FAILURE;
135                     }
136 
137                     ConPuts(StdOut, L"CertUtil: -hashfile command completed successfully\n");
138                     return EXIT_SUCCESS;
139                 }
140             }
141             else
142             {
143                 ConPrintf(StdOut, L"CertUtil: -hashfile expected 1 argument, got %d\n", argc - 2);
144                 return EXIT_FAILURE;
145             }
146         }
147         else
148         {
149             ConPrintf(StdOut, L"CertUtil: Unknown verb: %s\n", argv[n]);
150             return EXIT_FAILURE;
151         }
152     }
153 
154     return EXIT_SUCCESS;
155 }
156