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 "wine/unicode.h" 25 #include "crypt32_private.h" 26 27 WINE_DEFAULT_DEBUG_CHANNEL(crypt); 28 29 typedef struct _WINE_FILESTOREINFO 30 { 31 DWORD dwOpenFlags; 32 HCERTSTORE memStore; 33 HANDLE file; 34 DWORD type; 35 BOOL dirty; 36 } WINE_FILESTOREINFO; 37 38 static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) 39 { 40 WINE_FILESTOREINFO *store = hCertStore; 41 42 TRACE("(%p, %08x)\n", store, dwFlags); 43 if (store->dirty) 44 CertSaveStore(store->memStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 45 store->type, CERT_STORE_SAVE_TO_FILE, store->file, 0); 46 CloseHandle(store->file); 47 CryptMemFree(store); 48 } 49 50 static BOOL WINAPI CRYPT_FileWriteCert(HCERTSTORE hCertStore, 51 PCCERT_CONTEXT cert, DWORD dwFlags) 52 { 53 WINE_FILESTOREINFO *store = hCertStore; 54 55 TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags); 56 store->dirty = TRUE; 57 return TRUE; 58 } 59 60 static BOOL WINAPI CRYPT_FileDeleteCert(HCERTSTORE hCertStore, 61 PCCERT_CONTEXT pCertContext, DWORD dwFlags) 62 { 63 WINE_FILESTOREINFO *store = hCertStore; 64 65 TRACE("(%p, %p, %08x)\n", hCertStore, pCertContext, dwFlags); 66 store->dirty = TRUE; 67 return TRUE; 68 } 69 70 static BOOL WINAPI CRYPT_FileWriteCRL(HCERTSTORE hCertStore, 71 PCCRL_CONTEXT crl, DWORD dwFlags) 72 { 73 WINE_FILESTOREINFO *store = hCertStore; 74 75 TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags); 76 store->dirty = TRUE; 77 return TRUE; 78 } 79 80 static BOOL WINAPI CRYPT_FileDeleteCRL(HCERTSTORE hCertStore, 81 PCCRL_CONTEXT pCrlContext, DWORD dwFlags) 82 { 83 WINE_FILESTOREINFO *store = hCertStore; 84 85 TRACE("(%p, %p, %08x)\n", hCertStore, pCrlContext, dwFlags); 86 store->dirty = TRUE; 87 return TRUE; 88 } 89 90 static BOOL WINAPI CRYPT_FileWriteCTL(HCERTSTORE hCertStore, 91 PCCTL_CONTEXT ctl, DWORD dwFlags) 92 { 93 WINE_FILESTOREINFO *store = hCertStore; 94 95 TRACE("(%p, %p, %d)\n", hCertStore, ctl, dwFlags); 96 store->dirty = TRUE; 97 return TRUE; 98 } 99 100 static BOOL WINAPI CRYPT_FileDeleteCTL(HCERTSTORE hCertStore, 101 PCCTL_CONTEXT pCtlContext, DWORD dwFlags) 102 { 103 WINE_FILESTOREINFO *store = hCertStore; 104 105 TRACE("(%p, %p, %08x)\n", hCertStore, pCtlContext, dwFlags); 106 store->dirty = TRUE; 107 return TRUE; 108 } 109 110 static BOOL CRYPT_ReadBlobFromFile(HANDLE file, PCERT_BLOB blob) 111 { 112 BOOL ret = TRUE; 113 114 blob->cbData = GetFileSize(file, NULL); 115 if (blob->cbData) 116 { 117 blob->pbData = CryptMemAlloc(blob->cbData); 118 if (blob->pbData) 119 { 120 DWORD read; 121 122 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL) && read == blob->cbData; 123 if (!ret) CryptMemFree(blob->pbData); 124 } 125 else 126 ret = FALSE; 127 } 128 return ret; 129 } 130 131 static BOOL WINAPI CRYPT_FileControl(HCERTSTORE hCertStore, DWORD dwFlags, 132 DWORD dwCtrlType, void const *pvCtrlPara) 133 { 134 WINE_FILESTOREINFO *store = hCertStore; 135 BOOL ret; 136 137 TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, 138 pvCtrlPara); 139 140 switch (dwCtrlType) 141 { 142 case CERT_STORE_CTRL_RESYNC: 143 store->dirty = FALSE; 144 if (store->type == CERT_STORE_SAVE_AS_STORE) 145 { 146 HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 147 CERT_STORE_CREATE_NEW_FLAG, NULL); 148 149 /* FIXME: if I could translate a handle to a path, I could use 150 * CryptQueryObject instead, but there's no API to do so yet. 151 */ 152 ret = CRYPT_ReadSerializedStoreFromFile(store->file, memStore); 153 if (ret) 154 I_CertUpdateStore(store->memStore, memStore, 0, 0); 155 CertCloseStore(memStore, 0); 156 } 157 else if (store->type == CERT_STORE_SAVE_AS_PKCS7) 158 { 159 CERT_BLOB blob = { 0, NULL }; 160 161 ret = CRYPT_ReadBlobFromFile(store->file, &blob); 162 if (ret) 163 { 164 HCERTSTORE messageStore; 165 166 ret = CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &blob, 167 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED, 168 CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, 169 &messageStore, NULL, NULL); 170 I_CertUpdateStore(store->memStore, messageStore, 0, 0); 171 CertCloseStore(messageStore, 0); 172 CryptMemFree(blob.pbData); 173 } 174 } 175 else 176 { 177 WARN("unknown type %d\n", store->type); 178 ret = FALSE; 179 } 180 break; 181 case CERT_STORE_CTRL_COMMIT: 182 if (!(store->dwOpenFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)) 183 { 184 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 185 ret = FALSE; 186 } 187 else if (store->dirty) 188 ret = CertSaveStore(store->memStore, 189 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 190 store->type, CERT_STORE_SAVE_TO_FILE, store->file, 0); 191 else 192 ret = TRUE; 193 break; 194 default: 195 FIXME("%d: stub\n", dwCtrlType); 196 ret = FALSE; 197 } 198 return ret; 199 } 200 201 static void *fileProvFuncs[] = { 202 CRYPT_FileCloseStore, 203 NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */ 204 CRYPT_FileWriteCert, 205 CRYPT_FileDeleteCert, 206 NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */ 207 NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */ 208 CRYPT_FileWriteCRL, 209 CRYPT_FileDeleteCRL, 210 NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */ 211 NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */ 212 CRYPT_FileWriteCTL, 213 CRYPT_FileDeleteCTL, 214 NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */ 215 CRYPT_FileControl, 216 }; 217 218 static WINECRYPT_CERTSTORE *CRYPT_CreateFileStore(DWORD dwFlags, 219 HCERTSTORE memStore, HANDLE file, DWORD type) 220 { 221 WINECRYPT_CERTSTORE *store = NULL; 222 WINE_FILESTOREINFO *info = CryptMemAlloc(sizeof(WINE_FILESTOREINFO)); 223 224 if (info) 225 { 226 CERT_STORE_PROV_INFO provInfo = { 0 }; 227 228 info->dwOpenFlags = dwFlags; 229 info->memStore = memStore; 230 info->file = file; 231 info->type = type; 232 info->dirty = FALSE; 233 provInfo.cbSize = sizeof(provInfo); 234 provInfo.cStoreProvFunc = ARRAY_SIZE(fileProvFuncs); 235 provInfo.rgpvStoreProvFunc = fileProvFuncs; 236 provInfo.hStoreProv = info; 237 store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo); 238 } 239 return store; 240 } 241 242 WINECRYPT_CERTSTORE *CRYPT_FileOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, 243 const void *pvPara) 244 { 245 WINECRYPT_CERTSTORE *store = NULL; 246 HANDLE file = (HANDLE)pvPara; 247 248 TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); 249 250 if (!pvPara) 251 { 252 SetLastError(ERROR_INVALID_HANDLE); 253 return NULL; 254 } 255 if (dwFlags & CERT_STORE_DELETE_FLAG) 256 { 257 SetLastError(E_INVALIDARG); 258 return NULL; 259 } 260 if ((dwFlags & CERT_STORE_READONLY_FLAG) && 261 (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)) 262 { 263 SetLastError(E_INVALIDARG); 264 return NULL; 265 } 266 267 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara, 268 GetCurrentProcess(), &file, dwFlags & CERT_STORE_READONLY_FLAG ? 269 GENERIC_READ : GENERIC_READ | GENERIC_WRITE, TRUE, 0)) 270 { 271 HCERTSTORE memStore; 272 273 memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 274 CERT_STORE_CREATE_NEW_FLAG, NULL); 275 if (memStore) 276 { 277 if (CRYPT_ReadSerializedStoreFromFile(file, memStore)) 278 { 279 store = CRYPT_CreateFileStore(dwFlags, memStore, file, 280 CERT_STORE_SAVE_AS_STORE); 281 /* File store doesn't need crypto provider, so close it */ 282 if (hCryptProv && 283 !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) 284 CryptReleaseContext(hCryptProv, 0); 285 } 286 } 287 } 288 TRACE("returning %p\n", store); 289 return store; 290 } 291 292 WINECRYPT_CERTSTORE *CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv, 293 DWORD dwFlags, const void *pvPara) 294 { 295 HCERTSTORE store = 0; 296 LPCWSTR fileName = pvPara; 297 DWORD access, create; 298 HANDLE file; 299 300 TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, debugstr_w(fileName)); 301 302 if (!fileName) 303 { 304 SetLastError(ERROR_PATH_NOT_FOUND); 305 return NULL; 306 } 307 if ((dwFlags & CERT_STORE_READONLY_FLAG) && 308 (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)) 309 { 310 SetLastError(E_INVALIDARG); 311 return NULL; 312 } 313 314 access = GENERIC_READ; 315 if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG) 316 access |= GENERIC_WRITE; 317 if (dwFlags & CERT_STORE_CREATE_NEW_FLAG) 318 create = CREATE_NEW; 319 else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG) 320 create = OPEN_EXISTING; 321 else 322 create = OPEN_ALWAYS; 323 file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, create, 324 FILE_ATTRIBUTE_NORMAL, NULL); 325 if (file != INVALID_HANDLE_VALUE) 326 { 327 HCERTSTORE memStore = NULL; 328 DWORD size = GetFileSize(file, NULL), type = 0; 329 330 /* If the file isn't empty, try to get the type from the file itself */ 331 if (size) 332 { 333 DWORD contentType; 334 BOOL ret; 335 336 /* Close the file so CryptQueryObject can succeed.. */ 337 CloseHandle(file); 338 ret = CryptQueryObject(CERT_QUERY_OBJECT_FILE, fileName, 339 CERT_QUERY_CONTENT_FLAG_CERT | 340 CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE | 341 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED, 342 CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &contentType, NULL, 343 &memStore, NULL, NULL); 344 if (ret) 345 { 346 if (contentType == CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) 347 type = CERT_STORE_SAVE_AS_PKCS7; 348 else 349 type = CERT_STORE_SAVE_AS_STORE; 350 /* and reopen the file. */ 351 file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, 352 create, FILE_ATTRIBUTE_NORMAL, NULL); 353 } 354 } 355 else 356 { 357 static const WCHAR spc[] = { 's','p','c',0 }; 358 static const WCHAR p7c[] = { 'p','7','c',0 }; 359 LPCWSTR ext = strrchrW(fileName, '.'); 360 361 if (ext) 362 { 363 ext++; 364 if (!lstrcmpiW(ext, spc) || !lstrcmpiW(ext, p7c)) 365 type = CERT_STORE_SAVE_AS_PKCS7; 366 } 367 if (!type) 368 type = CERT_STORE_SAVE_AS_STORE; 369 memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 370 CERT_STORE_CREATE_NEW_FLAG, NULL); 371 } 372 if (memStore) 373 { 374 store = CRYPT_CreateFileStore(dwFlags, memStore, file, type); 375 /* File store doesn't need crypto provider, so close it */ 376 if (hCryptProv && !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) 377 CryptReleaseContext(hCryptProv, 0); 378 } 379 } 380 return store; 381 } 382 383 WINECRYPT_CERTSTORE *CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv, 384 DWORD dwFlags, const void *pvPara) 385 { 386 int len; 387 WINECRYPT_CERTSTORE *ret = NULL; 388 389 TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, 390 debugstr_a(pvPara)); 391 392 if (!pvPara) 393 { 394 SetLastError(ERROR_FILE_NOT_FOUND); 395 return NULL; 396 } 397 len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0); 398 if (len) 399 { 400 LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR)); 401 402 if (storeName) 403 { 404 MultiByteToWideChar(CP_ACP, 0, pvPara, -1, storeName, len); 405 ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName); 406 CryptMemFree(storeName); 407 } 408 } 409 return ret; 410 } 411