crypt32: Add more tests for getting issuer cert from store.
[wine] / dlls / crypt32 / filestore.c
1 /*
2  * Copyright 2004-2007 Juan Lang
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "wincrypt.h"
22 #include "winnls.h"
23 #include "wine/debug.h"
24 #include "crypt32_private.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
27
28 typedef struct _WINE_FILESTOREINFO
29 {
30     DWORD      dwOpenFlags;
31     HCERTSTORE memStore;
32     HANDLE     file;
33     BOOL       dirty;
34 } WINE_FILESTOREINFO, *PWINE_FILESTOREINFO;
35
36 static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
37 {
38     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
39
40     TRACE("(%p, %08x)\n", store, dwFlags);
41     if (store->dirty)
42         CRYPT_WriteSerializedFile(store->file, store->memStore);
43     CertCloseStore(store->memStore, dwFlags);
44     CloseHandle(store->file);
45     CryptMemFree(store);
46 }
47
48 static BOOL WINAPI CRYPT_FileWriteCert(HCERTSTORE hCertStore,
49  PCCERT_CONTEXT cert, DWORD dwFlags)
50 {
51     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
52
53     TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags);
54     store->dirty = TRUE;
55     return TRUE;
56 }
57
58 static BOOL WINAPI CRYPT_FileDeleteCert(HCERTSTORE hCertStore,
59  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
60 {
61     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
62
63     TRACE("(%p, %p, %08x)\n", hCertStore, pCertContext, dwFlags);
64     store->dirty = TRUE;
65     return TRUE;
66 }
67
68 static BOOL WINAPI CRYPT_FileWriteCRL(HCERTSTORE hCertStore,
69  PCCRL_CONTEXT crl, DWORD dwFlags)
70 {
71     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
72
73     TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags);
74     store->dirty = TRUE;
75     return TRUE;
76 }
77
78 static BOOL WINAPI CRYPT_FileDeleteCRL(HCERTSTORE hCertStore,
79  PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
80 {
81     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
82
83     TRACE("(%p, %p, %08x)\n", hCertStore, pCrlContext, dwFlags);
84     store->dirty = TRUE;
85     return TRUE;
86 }
87
88 static BOOL WINAPI CRYPT_FileControl(HCERTSTORE hCertStore, DWORD dwFlags,
89  DWORD dwCtrlType, void const *pvCtrlPara)
90 {
91     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
92     BOOL ret;
93
94     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
95      pvCtrlPara);
96
97     switch (dwCtrlType)
98     {
99     case CERT_STORE_CTRL_RESYNC:
100         CRYPT_EmptyStore(store->memStore);
101         CRYPT_ReadSerializedFile(store->file, store);
102         ret = TRUE;
103         break;
104     case CERT_STORE_CTRL_COMMIT:
105         if (!(store->dwOpenFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
106         {
107             SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
108             ret = FALSE;
109         }
110         else if (store->dirty)
111             ret = CRYPT_WriteSerializedFile(store->file, store->memStore);
112         else
113             ret = TRUE;
114         break;
115     default:
116         FIXME("%d: stub\n", dwCtrlType);
117         ret = FALSE;
118     }
119     return ret;
120 }
121
122 static void *fileProvFuncs[] = {
123     CRYPT_FileCloseStore,
124     NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
125     CRYPT_FileWriteCert,
126     CRYPT_FileDeleteCert,
127     NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
128     NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
129     CRYPT_FileWriteCRL,
130     CRYPT_FileDeleteCRL,
131     NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
132     NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
133     NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
134     NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
135     NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
136     CRYPT_FileControl,
137 };
138
139 PWINECRYPT_CERTSTORE CRYPT_FileOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags,
140  const void *pvPara)
141 {
142     PWINECRYPT_CERTSTORE store = NULL;
143     HANDLE file = (HANDLE)pvPara;
144
145     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
146
147     if (!pvPara)
148     {
149         SetLastError(ERROR_INVALID_HANDLE);
150         return NULL;
151     }
152     if (dwFlags & CERT_STORE_DELETE_FLAG)
153     {
154         SetLastError(E_INVALIDARG);
155         return NULL;
156     }
157     if ((dwFlags & CERT_STORE_READONLY_FLAG) &&
158      (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
159     {
160         SetLastError(E_INVALIDARG);
161         return NULL;
162     }
163
164     if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
165      GetCurrentProcess(), &file, dwFlags & CERT_STORE_READONLY_FLAG ?
166      GENERIC_READ : GENERIC_READ | GENERIC_WRITE, TRUE, 0))
167     {
168         PWINECRYPT_CERTSTORE memStore;
169
170         memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
171          CERT_STORE_CREATE_NEW_FLAG, NULL);
172         if (memStore)
173         {
174             if (CRYPT_ReadSerializedFile(file, memStore))
175             {
176                 PWINE_FILESTOREINFO info = CryptMemAlloc(
177                  sizeof(WINE_FILESTOREINFO));
178
179                 if (info)
180                 {
181                     CERT_STORE_PROV_INFO provInfo = { 0 };
182
183                     info->dwOpenFlags = dwFlags;
184                     info->memStore = memStore;
185                     info->file = file;
186                     info->dirty = FALSE;
187                     provInfo.cbSize = sizeof(provInfo);
188                     provInfo.cStoreProvFunc = sizeof(fileProvFuncs) /
189                      sizeof(fileProvFuncs[0]);
190                     provInfo.rgpvStoreProvFunc = fileProvFuncs;
191                     provInfo.hStoreProv = info;
192                     store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo);
193                     /* File store doesn't need crypto provider, so close it */
194                     if (hCryptProv &&
195                      !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
196                         CryptReleaseContext(hCryptProv, 0);
197                 }
198             }
199         }
200     }
201     TRACE("returning %p\n", store);
202     return store;
203 }
204
205 PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
206  DWORD dwFlags, const void *pvPara)
207 {
208     HCERTSTORE store = 0;
209     LPCWSTR fileName = (LPCWSTR)pvPara;
210     DWORD access, create;
211     HANDLE file;
212
213     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, debugstr_w(fileName));
214
215     if (!fileName)
216     {
217         SetLastError(ERROR_PATH_NOT_FOUND);
218         return NULL;
219     }
220
221     access = GENERIC_READ;
222     if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)
223         access |= GENERIC_WRITE;
224     if (dwFlags & CERT_STORE_CREATE_NEW_FLAG)
225         create = CREATE_NEW;
226     else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
227         create = OPEN_EXISTING;
228     else
229         create = OPEN_ALWAYS;
230     file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, create,
231      FILE_ATTRIBUTE_NORMAL, NULL);
232     if (file != INVALID_HANDLE_VALUE)
233     {
234         /* FIXME: need to check whether it's a serialized store; if not, fall
235          * back to a PKCS#7 signed message, then to a single serialized cert.
236          */
237         store = CertOpenStore(CERT_STORE_PROV_FILE, 0, hCryptProv, dwFlags,
238          file);
239         CloseHandle(file);
240     }
241     return (PWINECRYPT_CERTSTORE)store;
242 }
243
244 PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
245  DWORD dwFlags, const void *pvPara)
246 {
247     int len;
248     PWINECRYPT_CERTSTORE ret = NULL;
249
250     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
251      debugstr_a((LPCSTR)pvPara));
252
253     if (!pvPara)
254     {
255         SetLastError(ERROR_FILE_NOT_FOUND);
256         return NULL;
257     }
258     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
259     if (len)
260     {
261         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
262
263         if (storeName)
264         {
265             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
266             ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName);
267             CryptMemFree(storeName);
268         }
269     }
270     return ret;
271 }