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