advpack: Set the ldids of the install section in install_init.
[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 WCHAR cspNameW[] = { 'W','i','n','e','C','r','y','p','t','T','e',
89  'm','p',0 };
90
91 static void verifySig(HCRYPTPROV csp, const BYTE *toSign, size_t toSignLen,
92  const BYTE *sig, size_t sigLen)
93 {
94     HCRYPTHASH hash;
95     BOOL ret = CryptCreateHash(csp, CALG_SHA1, 0, 0, &hash);
96
97     ok(ret, "CryptCreateHash failed: %08lx\n", GetLastError());
98     if (ret)
99     {
100         BYTE mySig[64];
101         DWORD mySigSize = sizeof(mySig);
102
103         ret = CryptHashData(hash, toSign, toSignLen, 0);
104         ok(ret, "CryptHashData failed: %08lx\n", GetLastError());
105         /* use the A variant so the test can run on Win9x */
106         ret = CryptSignHashA(hash, AT_SIGNATURE, NULL, 0, mySig, &mySigSize);
107         ok(ret, "CryptSignHash failed: %08lx\n", GetLastError());
108         if (ret)
109         {
110             ok(mySigSize == sigLen, "Expected sig length %d, got %ld\n",
111              sigLen, mySigSize);
112             ok(!memcmp(mySig, sig, sigLen), "Unexpected signature\n");
113         }
114         CryptDestroyHash(hash);
115     }
116 }
117
118 /* Tests signing the certificate described by toBeSigned with the CSP passed in,
119  * using the algorithm with OID sigOID.  The CSP is assumed to be empty, and a
120  * keyset named AT_SIGNATURE will be added to it.  The signing key will be
121  * stored in *key, and the signature will be stored in sig.  sigLen should be
122  * at least 64 bytes.
123  */
124 static void testSignCert(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
125  LPCSTR sigOID, HCRYPTKEY *key, BYTE *sig, DWORD *sigLen)
126 {
127     BOOL ret;
128     DWORD size = 0;
129     CRYPT_ALGORITHM_IDENTIFIER algoID = { NULL, { 0, NULL } };
130
131     /* These all crash
132     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL);
133     ret = CryptSignCertificate(0, 0, 0, NULL, 0, NULL, NULL, NULL, &size);
134     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
135      NULL, NULL, NULL, &size);
136      */
137     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
138      &algoID, NULL, NULL, &size);
139     ok(!ret && GetLastError() == NTE_BAD_ALGID, 
140      "Expected NTE_BAD_ALGID, got %08lx\n", GetLastError());
141     algoID.pszObjId = (LPSTR)sigOID;
142     ret = CryptSignCertificate(0, 0, 0, toBeSigned->pbData, toBeSigned->cbData,
143      &algoID, NULL, NULL, &size);
144     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
145      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
146     ret = CryptSignCertificate(0, AT_SIGNATURE, 0, toBeSigned->pbData,
147      toBeSigned->cbData, &algoID, NULL, NULL, &size);
148     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
149      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
150
151     /* No keys exist in the new CSP yet.. */
152     ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
153      toBeSigned->cbData, &algoID, NULL, NULL, &size);
154     ok(!ret && (GetLastError() == NTE_BAD_KEYSET || GetLastError() ==
155      NTE_NO_KEY), "Expected NTE_BAD_KEYSET or NTE_NO_KEY, got %08lx\n",
156      GetLastError());
157     ret = CryptGenKey(csp, AT_SIGNATURE, 0, key);
158     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
159     if (ret)
160     {
161         ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
162          toBeSigned->cbData, &algoID, NULL, NULL, &size);
163         ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
164         ok(size <= *sigLen, "Expected size <= %ld, got %ld\n", *sigLen, size);
165         if (ret)
166         {
167             ret = CryptSignCertificate(csp, AT_SIGNATURE, 0, toBeSigned->pbData,
168              toBeSigned->cbData, &algoID, NULL, sig, &size);
169             ok(ret, "CryptSignCertificate failed: %08lx\n", GetLastError());
170             if (ret)
171             {
172                 *sigLen = size;
173                 verifySig(csp, toBeSigned->pbData, toBeSigned->cbData, sig,
174                  size);
175             }
176         }
177     }
178 }
179
180 static void testVerifyCertSig(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigned,
181  LPCSTR sigOID, const BYTE *sig, DWORD sigLen)
182 {
183     CERT_SIGNED_CONTENT_INFO info;
184     LPBYTE cert = NULL;
185     DWORD size = 0;
186     BOOL ret;
187
188     if(pCryptVerifyCertificateSignatureEx) {
189         ret = pCryptVerifyCertificateSignatureEx(0, 0, 0, NULL, 0, NULL, 0, NULL);
190         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
191          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
192          GetLastError());
193         ret = pCryptVerifyCertificateSignatureEx(csp, 0, 0, NULL, 0, NULL, 0, NULL);
194         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
195          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
196         GetLastError());
197         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING, 0, NULL, 0,
198          NULL, 0, NULL);
199         ok(!ret && GetLastError() == HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
200          "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
201          GetLastError());
202         /* This crashes
203         ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
204          CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, NULL, 0, NULL, 0, NULL);
205          */
206     }
207     info.ToBeSigned.cbData = toBeSigned->cbData;
208     info.ToBeSigned.pbData = toBeSigned->pbData;
209     info.SignatureAlgorithm.pszObjId = (LPSTR)sigOID;
210     info.SignatureAlgorithm.Parameters.cbData = 0;
211     info.Signature.cbData = sigLen;
212     info.Signature.pbData = (BYTE *)sig;
213     info.Signature.cUnusedBits = 0;
214     ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT, &info,
215      CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&cert, &size);
216     ok(ret, "CryptEncodeObjectEx failed: %08lx\n", GetLastError());
217     if (cert)
218     {
219         CRYPT_DATA_BLOB certBlob = { 0, NULL };
220         PCERT_PUBLIC_KEY_INFO pubKeyInfo = NULL;
221
222         if(pCryptVerifyCertificateSignatureEx) {
223             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
224              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
225             ok(!ret && GetLastError() == CRYPT_E_ASN1_EOD,
226              "Expected CRYPT_E_ASN1_EOD, got %08lx\n", GetLastError());
227             certBlob.cbData = 1;
228             certBlob.pbData = (void *)0xdeadbeef;
229             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
230              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
231             ok(!ret && GetLastError() == STATUS_ACCESS_VIOLATION,
232              "Expected STATUS_ACCESS_VIOLATION, got %08lx\n", GetLastError());
233             certBlob.cbData = size;
234             certBlob.pbData = cert;
235             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
236              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob, 0, NULL, 0, NULL);
237             ok(!ret && GetLastError() ==
238              HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
239              "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
240              GetLastError());
241             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
242              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
243              CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL, NULL, 0, NULL);
244             ok(!ret && GetLastError() ==
245              HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER),
246              "Expected HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), got %08lx\n",
247              GetLastError());
248             /* This crashes
249             ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
250              CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
251              CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, NULL, 0, NULL);
252              */
253         }
254         CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE, X509_ASN_ENCODING,
255          (LPSTR)sigOID, 0, NULL, NULL, &size);
256         pubKeyInfo = HeapAlloc(GetProcessHeap(), 0, size);
257         if (pubKeyInfo)
258         {
259             ret = CryptExportPublicKeyInfoEx(csp, AT_SIGNATURE,
260              X509_ASN_ENCODING, (LPSTR)sigOID, 0, NULL, pubKeyInfo, &size);
261             ok(ret, "CryptExportKey failed: %08lx\n", GetLastError());
262             if (ret && pCryptVerifyCertificateSignatureEx)
263             {
264                 ret = pCryptVerifyCertificateSignatureEx(csp, X509_ASN_ENCODING,
265                  CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &certBlob,
266                  CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pubKeyInfo, 0, NULL);
267                 ok(ret, "CryptVerifyCertificateSignatureEx failed: %08lx\n",
268                  GetLastError());
269             }
270             HeapFree(GetProcessHeap(), 0, pubKeyInfo);
271         }
272         LocalFree(cert);
273     }
274 }
275
276 static const BYTE emptyCert[] = { 0x30, 0x00 };
277
278 static void testCertSigs(void)
279 {
280     HCRYPTPROV csp;
281     CRYPT_DATA_BLOB toBeSigned = { sizeof(emptyCert), (LPBYTE)emptyCert };
282     BOOL ret;
283     HCRYPTKEY key;
284     BYTE sig[64];
285     DWORD sigSize = sizeof(sig);
286
287     /* Just in case a previous run failed, delete this thing */
288     CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
289      CRYPT_DELETEKEYSET);
290     ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
291      CRYPT_NEWKEYSET);
292     ok(ret, "CryptAcquireContext failed: %08lx\n", GetLastError());
293
294     testSignCert(csp, &toBeSigned, szOID_RSA_SHA1RSA, &key, sig, &sigSize);
295     testVerifyCertSig(csp, &toBeSigned, szOID_RSA_SHA1RSA, sig, sigSize);
296
297     CryptDestroyKey(key);
298     CryptReleaseContext(csp, 0);
299     ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
300      CRYPT_DELETEKEYSET);
301 }
302
303 static const BYTE subjectName[] = { 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06,
304  0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61,
305  0x6e, 0x67, 0x00 };
306
307 static void testCreateSelfSignCert(void)
308 {
309     PCCERT_CONTEXT context;
310     CERT_NAME_BLOB name = { sizeof(subjectName), (LPBYTE)subjectName };
311     HCRYPTPROV csp;
312     BOOL ret;
313     HCRYPTKEY key;
314
315     /* This crashes:
316     context = CertCreateSelfSignCertificate(0, NULL, 0, NULL, NULL, NULL, NULL,
317      NULL);
318      * Calling this with no first parameter creates a new key container, which
319      * lasts beyond the test, so I don't test that.  Nb: the generated key
320      * name is a GUID.
321     context = CertCreateSelfSignCertificate(0, &name, 0, NULL, NULL, NULL, NULL,
322      NULL);
323      */
324
325     /* Acquire a CSP */
326     CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
327      CRYPT_DELETEKEYSET);
328     ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
329      CRYPT_NEWKEYSET);
330     ok(ret, "CryptAcquireContext failed: %08lx\n", GetLastError());
331
332     context = CertCreateSelfSignCertificate(csp, &name, 0, NULL, NULL, NULL,
333      NULL, NULL);
334     ok(!context && GetLastError() == NTE_NO_KEY,
335      "Expected NTE_NO_KEY, got %08lx\n", GetLastError());
336     ret = CryptGenKey(csp, AT_SIGNATURE, 0, &key);
337     ok(ret, "CryptGenKey failed: %08lx\n", GetLastError());
338     if (ret)
339     {
340         context = CertCreateSelfSignCertificate(csp, &name, 0, NULL, NULL, NULL,
341          NULL, NULL);
342         ok(context != NULL, "CertCreateSelfSignCertificate failed: %08lx\n",
343          GetLastError());
344         if (context)
345         {
346             DWORD size = 0;
347             PCRYPT_KEY_PROV_INFO info;
348
349             /* The context must have a key provider info property */
350             ret = CertGetCertificateContextProperty(context,
351              CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
352             ok(ret && size, "Expected non-zero key provider info\n");
353             if (size)
354             {
355                 info = HeapAlloc(GetProcessHeap(), 0, size);
356                 if (info)
357                 {
358                     ret = CertGetCertificateContextProperty(context,
359                      CERT_KEY_PROV_INFO_PROP_ID, info, &size);
360                     ok(ret, "CertGetCertificateContextProperty failed: %08lx\n",
361                      GetLastError());
362                     if (ret)
363                     {
364                         /* Sanity-check the key provider */
365                         ok(!lstrcmpW(info->pwszContainerName, cspNameW),
366                          "Unexpected key container\n");
367                         ok(!lstrcmpW(info->pwszProvName, MS_DEF_PROV_W),
368                          "Unexpected provider\n");
369                         ok(info->dwKeySpec == AT_SIGNATURE,
370                          "Expected AT_SIGNATURE, got %ld\n", info->dwKeySpec);
371                     }
372                     HeapFree(GetProcessHeap(), 0, info);
373                 }
374             }
375
376             CertFreeCertificateContext(context);
377         }
378
379         CryptDestroyKey(key);
380     }
381
382     CryptReleaseContext(csp, 0);
383     ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
384      CRYPT_DELETEKEYSET);
385 }
386
387 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
388  0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
389  0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
390  0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
391  0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
392  0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
393  0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
394  0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
395  0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
396  0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
397
398 static const LPCSTR keyUsages[] = { szOID_PKIX_KP_CODE_SIGNING,
399  szOID_PKIX_KP_CLIENT_AUTH, szOID_RSA_RSA };
400
401 static const BYTE certWithUsage[] = { 0x30, 0x81, 0x93, 0x02, 0x01, 0x01, 0x30,
402  0x02, 0x06, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
403  0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00,
404  0x30, 0x22, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30,
405  0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30,
406  0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31,
407  0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61,
408  0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00,
409  0x03, 0x01, 0x00, 0xa3, 0x2f, 0x30, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x1d,
410  0x25, 0x01, 0x01, 0xff, 0x04, 0x21, 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01,
411  0x05, 0x05, 0x07, 0x03, 0x03, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
412  0x03, 0x02, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
413
414 static void testKeyUsage(void)
415 {
416     BOOL ret;
417     PCCERT_CONTEXT context;
418     DWORD size;
419
420     /* Test base cases */
421     ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, NULL);
422     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
423      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
424     size = 1;
425     ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size);
426     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
427      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
428     size = 0;
429     ret = CertGetEnhancedKeyUsage(NULL, 0, NULL, &size);
430     ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
431      "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
432     /* These crash
433     ret = CertSetEnhancedKeyUsage(NULL, NULL);
434     usage.cUsageIdentifier = 0;
435     ret = CertSetEnhancedKeyUsage(NULL, &usage);
436      */
437     /* Test with a cert with no enhanced key usage extension */
438     context = CertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
439      sizeof(bigCert));
440     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
441      GetLastError());
442     if (context)
443     {
444         static const char oid[] = "1.2.3.4";
445         BYTE buf[sizeof(CERT_ENHKEY_USAGE) + 2 * (sizeof(LPSTR) + sizeof(oid))];
446         PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
447
448         ret = CertGetEnhancedKeyUsage(context, 0, NULL, NULL);
449         ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
450          "Expected ERROR_INVALID_PARAMETER, got %08lx\n", GetLastError());
451         size = 1;
452         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &size);
453         if (ret)
454         {
455             /* Windows 2000, ME, or later: even though it succeeded, we expect
456              * CRYPT_E_NOT_FOUND, which indicates there is no enhanced key
457              * usage set for this cert (which implies it's valid for all uses.)
458              */
459             ok(GetLastError() == CRYPT_E_NOT_FOUND,
460              "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
461             ok(size == sizeof(CERT_ENHKEY_USAGE), "Expected size %d, got %ld\n",
462              sizeof(CERT_ENHKEY_USAGE), size);
463             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
464             ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
465             ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
466              pUsage->cUsageIdentifier);
467         }
468         else
469         {
470             /* Windows NT, 95, or 98: it fails, and the last error is
471              * CRYPT_E_NOT_FOUND.
472              */
473             ok(GetLastError() == CRYPT_E_NOT_FOUND,
474              "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
475         }
476         /* I can add a usage identifier when no key usage has been set */
477         ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
478         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
479          GetLastError());
480         size = sizeof(buf);
481         ret = CertGetEnhancedKeyUsage(context,
482          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
483         ok(ret && GetLastError() == 0,
484          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
485         ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %ld\n",
486          pUsage->cUsageIdentifier);
487         if (pUsage->cUsageIdentifier)
488             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
489              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
490         /* Now set an empty key usage */
491         pUsage->cUsageIdentifier = 0;
492         ret = CertSetEnhancedKeyUsage(context, pUsage);
493         ok(ret, "CertSetEnhancedKeyUsage failed: %08lx\n", GetLastError());
494         /* Shouldn't find it in the cert */
495         size = sizeof(buf);
496         ret = CertGetEnhancedKeyUsage(context,
497          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
498         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
499          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
500         /* Should find it as an extended property */
501         ret = CertGetEnhancedKeyUsage(context,
502          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
503         ok(ret && GetLastError() == 0,
504          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
505         ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
506          pUsage->cUsageIdentifier);
507         /* Should find it as either */
508         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
509         ok(ret && GetLastError() == 0,
510          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
511         ok(pUsage->cUsageIdentifier == 0, "Expected 0 usages, got %ld\n",
512          pUsage->cUsageIdentifier);
513         /* Add a usage identifier */
514         ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
515         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
516          GetLastError());
517         size = sizeof(buf);
518         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
519         ok(ret && GetLastError() == 0,
520          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
521         ok(pUsage->cUsageIdentifier == 1, "Expected 1 identifier, got %ld\n",
522          pUsage->cUsageIdentifier);
523         if (pUsage->cUsageIdentifier)
524             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
525              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
526         /* Yep, I can re-add the same usage identifier */
527         ret = CertAddEnhancedKeyUsageIdentifier(context, oid);
528         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
529          GetLastError());
530         size = sizeof(buf);
531         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
532         ok(ret && GetLastError() == 0,
533          "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
534         ok(pUsage->cUsageIdentifier == 2, "Expected 2 identifiers, got %ld\n",
535          pUsage->cUsageIdentifier);
536         if (pUsage->cUsageIdentifier)
537             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], oid),
538              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[0]);
539         if (pUsage->cUsageIdentifier >= 2)
540             ok(!strcmp(pUsage->rgpszUsageIdentifier[1], oid),
541              "Expected %s, got %s\n", oid, pUsage->rgpszUsageIdentifier[1]);
542         /* Now set a NULL extended property--this deletes the property. */
543         ret = CertSetEnhancedKeyUsage(context, NULL);
544         ok(ret, "CertSetEnhancedKeyUsage failed: %08lx\n", GetLastError());
545         SetLastError(0xbaadcafe);
546         size = sizeof(buf);
547         ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
548         ok(GetLastError() == CRYPT_E_NOT_FOUND,
549          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
550
551         CertFreeCertificateContext(context);
552     }
553     /* Now test with a cert with an enhanced key usage extension */
554     context = CertCreateCertificateContext(X509_ASN_ENCODING, certWithUsage,
555      sizeof(certWithUsage));
556     ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n",
557      GetLastError());
558     if (context)
559     {
560         LPBYTE buf = NULL;
561         DWORD bufSize = 0, i;
562
563         /* The size may depend on what flags are used to query it, so I
564          * realloc the buffer for each test.
565          */
566         ret = CertGetEnhancedKeyUsage(context,
567          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
568         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
569         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
570         if (buf)
571         {
572             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
573
574             /* Should find it in the cert */
575             size = bufSize;
576             ret = CertGetEnhancedKeyUsage(context,
577              CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
578             ok(ret && GetLastError() == 0,
579              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
580             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
581              pUsage->cUsageIdentifier);
582             for (i = 0; i < pUsage->cUsageIdentifier; i++)
583                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
584                  "Expected %s, got %s\n", keyUsages[i],
585                  pUsage->rgpszUsageIdentifier[i]);
586             HeapFree(GetProcessHeap(), 0, buf);
587         }
588         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
589         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
590         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
591         if (buf)
592         {
593             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
594
595             /* Should find it as either */
596             size = bufSize;
597             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
598             /* In Windows, GetLastError returns CRYPT_E_NOT_FOUND not found
599              * here, even though the return is successful and the usage id
600              * count is positive.  I don't enforce that here.
601              */
602             ok(ret,
603              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
604             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
605              pUsage->cUsageIdentifier);
606             for (i = 0; i < pUsage->cUsageIdentifier; i++)
607                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
608                  "Expected %s, got %s\n", keyUsages[i],
609                  pUsage->rgpszUsageIdentifier[i]);
610             HeapFree(GetProcessHeap(), 0, buf);
611         }
612         /* Shouldn't find it as an extended property */
613         ret = CertGetEnhancedKeyUsage(context,
614          CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size);
615         ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
616          "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
617         /* Adding a usage identifier overrides the cert's usage!? */
618         ret = CertAddEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA);
619         ok(ret, "CertAddEnhancedKeyUsageIdentifier failed: %08lx\n",
620          GetLastError());
621         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
622         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
623         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
624         if (buf)
625         {
626             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
627
628             /* Should find it as either */
629             size = bufSize;
630             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
631             ok(ret,
632              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
633             ok(pUsage->cUsageIdentifier == 1, "Expected 1 usage, got %ld\n",
634              pUsage->cUsageIdentifier);
635             ok(!strcmp(pUsage->rgpszUsageIdentifier[0], szOID_RSA_RSA),
636              "Expected %s, got %s\n", szOID_RSA_RSA,
637              pUsage->rgpszUsageIdentifier[0]);
638             HeapFree(GetProcessHeap(), 0, buf);
639         }
640         /* But querying the cert directly returns its usage */
641         ret = CertGetEnhancedKeyUsage(context,
642          CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, NULL, &bufSize);
643         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
644         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
645         if (buf)
646         {
647             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
648
649             size = bufSize;
650             ret = CertGetEnhancedKeyUsage(context,
651              CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
652             ok(ret,
653              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
654             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
655              pUsage->cUsageIdentifier);
656             for (i = 0; i < pUsage->cUsageIdentifier; i++)
657                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
658                  "Expected %s, got %s\n", keyUsages[i],
659                  pUsage->rgpszUsageIdentifier[i]);
660             HeapFree(GetProcessHeap(), 0, buf);
661         }
662         /* And removing the only usage identifier in the extended property
663          * results in the cert's key usage being found.
664          */
665         ret = CertRemoveEnhancedKeyUsageIdentifier(context, szOID_RSA_RSA);
666         ok(ret, "CertRemoveEnhancedKeyUsage failed: %08lx\n", GetLastError());
667         ret = CertGetEnhancedKeyUsage(context, 0, NULL, &bufSize);
668         ok(ret, "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
669         buf = HeapAlloc(GetProcessHeap(), 0, bufSize);
670         if (buf)
671         {
672             PCERT_ENHKEY_USAGE pUsage = (PCERT_ENHKEY_USAGE)buf;
673
674             /* Should find it as either */
675             size = bufSize;
676             ret = CertGetEnhancedKeyUsage(context, 0, pUsage, &size);
677             ok(ret,
678              "CertGetEnhancedKeyUsage failed: %08lx\n", GetLastError());
679             ok(pUsage->cUsageIdentifier == 3, "Expected 3 usages, got %ld\n",
680              pUsage->cUsageIdentifier);
681             for (i = 0; i < pUsage->cUsageIdentifier; i++)
682                 ok(!strcmp(pUsage->rgpszUsageIdentifier[i], keyUsages[i]),
683                  "Expected %s, got %s\n", keyUsages[i],
684                  pUsage->rgpszUsageIdentifier[i]);
685             HeapFree(GetProcessHeap(), 0, buf);
686         }
687
688         CertFreeCertificateContext(context);
689     }
690 }
691
692 START_TEST(cert)
693 {
694     init_function_pointers();
695     testCryptHashCert();
696     testCertSigs();
697     testCreateSelfSignCert();
698     testKeyUsage();
699 }