crypt32: Move certificate store functions to their own file.
[wine] / dlls / crypt32 / tests / cert.c
1 /*
2  * crypt32 cert functions tests
3  *
4  * Copyright 2005-2006 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <windef.h>
25 #include <winbase.h>
26 #include <winreg.h>
27 #include <winerror.h>
28 #include <wincrypt.h>
29
30 #include "wine/test.h"
31
32 static BOOL (WINAPI * pCryptVerifyCertificateSignatureEx)
33                         (HCRYPTPROV, DWORD, DWORD, void *, DWORD, void *, DWORD, void *);
34
35 #define CRYPT_GET_PROC(func)                                       \
36     p ## func = (void *)GetProcAddress(hCrypt32, #func);           \
37     if(!p ## func)                                                 \
38         trace("GetProcAddress(hCrypt32, \"%s\") failed\n", #func); \
39
40 static void init_function_pointers(void)
41 {
42     HMODULE hCrypt32;
43
44     pCryptVerifyCertificateSignatureEx = NULL;
45
46     hCrypt32 = GetModuleHandleA("crypt32.dll");
47     assert(hCrypt32);
48
49     CRYPT_GET_PROC(CryptVerifyCertificateSignatureEx);
50 }
51
52 static void testCryptHashCert(void)
53 {
54     static const BYTE emptyHash[] = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b,
55      0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07,
56      0x09 };
57     static const BYTE knownHash[] = { 0xae, 0x9d, 0xbf, 0x6d, 0xf5, 0x46, 0xee,
58      0x8b, 0xc5, 0x7a, 0x13, 0xba, 0xc2, 0xb1, 0x04, 0xf2, 0xbf, 0x52, 0xa8,
59      0xa2 };
60     static const BYTE toHash[] = "abcdefghijklmnopqrstuvwxyz0123456789.,;!?:";
61     BOOL ret;
62     BYTE hash[20];
63     DWORD hashLen = sizeof(hash);
64
65     /* NULL buffer and nonzero length crashes
66     ret = CryptHashCertificate(0, 0, 0, NULL, size, hash, &hashLen);
67        empty hash length also crashes
68     ret = CryptHashCertificate(0, 0, 0, buf, size, hash, NULL);
69      */
70     /* Test empty hash */
71     ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), NULL,
72      &hashLen);
73     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
74     ok(hashLen == sizeof(hash),
75      "Got unexpected size of hash %ld, expected %d\n", hashLen, sizeof(hash));
76     /* Test with empty buffer */
77     ret = CryptHashCertificate(0, 0, 0, NULL, 0, hash, &hashLen);
78     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
79     ok(!memcmp(hash, emptyHash, sizeof(emptyHash)),
80      "Unexpected hash of nothing\n");
81     /* Test a known value */
82     ret = CryptHashCertificate(0, 0, 0, toHash, sizeof(toHash), hash,
83      &hashLen);
84     ok(ret, "CryptHashCertificate failed: %08lx\n", GetLastError());
85     ok(!memcmp(hash, knownHash, sizeof(knownHash)), "Unexpected hash\n");
86 }
87
88 static const char cspName[] = "WineCryptTemp";
89
90 static void verifySig(HCRYPTPROV csp, const BYTE *toSign, size_t toSignLen,
91  const BYTE *sig, size_t sigLen)
92 {
93     HCRYPTHASH hash;
94     BOOL ret = CryptCreateHash(csp, CALG_SHA1, 0, 0, &hash);
95
96     ok(ret, "CryptCreateHash failed: %08lx\n", GetLastError());
97     if (ret)
98     {
99         BYTE mySig[64];
100         DWORD mySigSize = sizeof(mySig);
101
102         ret = CryptHashData(hash, toSign, toSignLen, 0);
103         ok(ret, "CryptHashData failed: %08lx\n", GetLastError());
104         /* use the A variant so the test can run on Win9x */
105         ret = CryptSignHashA(hash, AT_SIGNATURE, NULL, 0, mySig, &mySigSize);
106         ok(ret, "CryptSignHash failed: %08lx\n", GetLastError());
107         if (ret)
108         {
109             ok(mySigSize == sigLen, "Expected sig length %d, got %ld\n",
110              sigLen, mySigSize);
111             ok(!memcmp(mySig, sig, sigLen), "Unexpected signature\n");
112         }
113         CryptDestroyHash(hash);
114     }
115 }
116
117 /* Tests signing the certificate described by toBeSigned with the CSP passed in,
118  * using the algorithm with OID sigOID.  The CSP is assumed to be empty, and a
119  * keyset named AT_SIGNATURE will be added to it.  The signing key will be
120  * stored in *key, and the signature will be stored in sig.  sigLen should be
121  * at least 64 bytes.
122  */
123 static void testSignCert(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
124  LPCSTR sigOID, HCRYPTKEY *key, BYTE *sig, DWORD *sigLen)
125 {
126     BOOL ret;
127     DWORD size = 0;
128     CRYPT_ALGORITHM_IDENTIFIER algoID = { NULL, { 0, NULL } };
129
130     /* These all crash
131     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL);
132     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, &size);
133     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
134      NULL, NULL, NULL, &size);
135      */
136     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
137      &algoID, NULL, NULL, &size);
138     ok(!ret && GetLastError() == NTE_BAD_ALGID, 
139      "Expected NTE_BAD_ALGID, got %08lx\n", GetLastError());
140     algoID.pszObjId = (LPSTR)sigOID;
141     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
142      &algoID, NULL, NULL, &size);
143     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
144      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
145     ret = CryptSignCertificate(0, AT_SIGNATURE, 0, toBeSigned->pbData,
146      toBeSigned->cbData, &algoID, NULL, NULL, &size);
147     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
148      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
149
150     /* No keys exist in the new CSP yet.. */
151     ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
152      toBeSigned->cbData, &algoID, NULL, NULL, &size);
153     ok(!ret && (GetLastError() == NTE_BAD_KEYSET || GetLastError() ==
154      NTE_NO_KEY), "Expected NTE_BAD_KEYSET or NTE_NO_KEY, got %08lx\n",
155      GetLastError());
156     ret = CryptGenKey(csp, AT_SIGNATURE, 0, key);
157     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
158     if (ret)
159     {
160         ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
161          toBeSigned->cbData, &algoID, NULL, NULL, &size);
162         ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
163         ok(size <= *sigLen, "Expected size <= %ld, got %ld\n", *sigLen, size);
164         if (ret)
165         {
166             ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
167              toBeSigned->cbData, &algoID, NULL, sig, &size);
168             ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
169             if (ret)
170             {
171                 *sigLen = size;
172                 verifySig(csp, toBeSigned->pbData, toBeSigned->cbData, sig,
173                  size);
174             }
175         }
176     }
177 }
178
179 static void testVerifyCertSig(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
180  LPCSTR sigOID, const BYTE *sig, DWORD sigLen)
181 {
182     CERT_SIGNED_CONTENT_INFO info;
183     LPBYTE cert = NULL;
184     DWORD size = 0;
185     BOOL ret;
186
187     if(pCryptVerifyCertificateSignatureEx) {
188         ret = pCryptVerifyCertificateSignatureEx(0, 0, 0, NULL, 0, NULL, 0, NULL);
189         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
190          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
191          GetLastError());
192         ret = pCryptVerifyCertificateSignatureEx(csp, 0, 0, NULL, 0, NULL, 0, NULL);
193         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
194          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
195         GetLastError());
196         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, 0, NULL, 0,
197          NULL, 0, NULL);
198         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
199          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
200          GetLastError());
201         /* This crashes
202         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
203          CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, NULL, 0, NULL, 0, NULL);
204          */
205     }
206     info.ToBeSigned.cbData = toBeSigned->cbData;
207     info.ToBeSigned.pbData = toBeSigned->pbData;
208     info.SignatureAlgorithm.pszObjId = (LPSTR)sigOID;
209     info.SignatureAlgorithm.Parameters.cbData = 0;
210     info.Signature.cbData = sigLen;
211     info.Signature.pbData = (BYTE *)sig;
212     info.Signature.cUnusedBits = 0;
213     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, &info,
214      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&cert, &size);
215     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
216     if (cert)
217     {
218         CRYPT_DATA_BLOB certBlob = { 0, NULL };
219         PCERT_PUBLIC_KEY_INFO pubKeyInfo = NULL;
220
221         if(pCryptVerifyCertificateSignatureEx) {
222             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
223              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
224             ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
225              "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
226             certBlob.cbData = 1;
227             certBlob.pbData = (void *)0xdeadbeef;
228             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
229              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
230             ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
231              "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
232             certBlob.cbData = size;
233             certBlob.pbData = cert;
234             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
235              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
236             ok(!ret && GetLastError() ==
237              HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
238              "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
239              GetLastError());
240             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
241              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
242              CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL, NULL, 0, NULL);
243             ok(!ret && GetLastError() ==
244              HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
245              "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
246              GetLastError());
247             /* This crashes
248             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
249              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
250              CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, NULL, 0, NULL);
251              */
252         }
253         CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
254          (LPSTR)sigOID, 0, NULL, NULL, &size);
255         pubKeyInfo = HeapAlloc(GetProcessHeap(), 0, size);
256         if (pubKeyInfo)
257         {
258             ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
259              X509_ASN_ENCODING, (LPSTR)sigOID, 0, NULL, pubKeyInfo, &size);
260             ok(ret, "CryptExportKey failed: %08lx\n", GetLastError());
261             if (ret && pCryptVerifyCertificateSignatureEx)
262             {
263                 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
264                  CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
265                  CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pubKeyInfo, 0, NULL);
266                 ok(ret, "CryptVerifyCertificateSignatureEx failed: %08lx\n",
267                  GetLastError());
268             }
269             HeapFree(GetProcessHeap(), 0, pubKeyInfo);
270         }
271         LocalFree(cert);
272     }
273 }
274
275 static const BYTE emptyCert[] = { 0x30, 0x00 };
276
277 static void testCertSigs(void)
278 {
279     HCRYPTPROV csp;
280     CRYPT_DATA_BLOB toBeSigned = { sizeof(emptyCert), (LPBYTE)emptyCert };
281     BOOL ret;
282     HCRYPTKEY key;
283     BYTE sig[64];
284     DWORD sigSize = sizeof(sig);
285
286     /* Just in case a previous run failed, delete this thing */
287     CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
288      CRYPT_DELETEKEYSET);
289     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
290      CRYPT_NEWKEYSET);
291     ok(ret, "CryptAcquireContext failed: %08lx\n", GetLastError());
292
293     testSignCert(csp, &toBeSigned, szOID_RSA_SHA1RSA, &key, sig, &sigSize);
294     testVerifyCertSig(csp, &toBeSigned, szOID_RSA_SHA1RSA, sig, sigSize);
295
296     CryptDestroyKey(key);
297     CryptReleaseContext(csp, 0);
298     ret = CryptAcquireContextA(&csp, cspName, MS_DEF_PROV, PROV_RSA_FULL,
299      CRYPT_DELETEKEYSET);
300 }
301
302 START_TEST(cert)
303 {
304     init_function_pointers();
305     testCryptHashCert();
306     testCertSigs();
307 }