/* Reads certificates from the list of known locations. Stops when any * location contains any certificates, to prevent spending unnecessary time * adding redundant certificates, e.g. when both a certificate bundle and * individual certificates exist in the same directory. */ static PWINECRYPT_CERTSTORE CRYPT_RootOpenStoreFromKnownLocations(void) { HCERTSTORE root = NULL; HCERTSTORE from = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); HCERTSTORE to = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); if (from && to) { CERT_STORE_PROV_INFO provInfo = { sizeof(CERT_STORE_PROV_INFO), sizeof(rootProvFuncs) / sizeof(rootProvFuncs[0]), rootProvFuncs, NULL, 0, NULL }; DWORD i; BOOL ret = FALSE; for (i = 0; !ret && i < sizeof(CRYPT_knownLocations) / sizeof(CRYPT_knownLocations[0]); i++) ret = import_certs_from_path(CRYPT_knownLocations[i], from, TRUE); check_and_store_certs(from, to); root = CRYPT_ProvCreateStore(0, to, &provInfo); } CertCloseStore(from, 0); TRACE("returning %p\n", root); return root; }
/* Opens path, which must be a directory, and imports certificates from every * file in the directory into store. * Returns TRUE if any certificates were successfully imported. */ static BOOL import_certs_from_dir(LPCSTR path, HCERTSTORE store) { BOOL ret = FALSE; DIR *dir; TRACE("(%s, %p)\n", debugstr_a(path), store); dir = opendir(path); if (dir) { size_t bufsize = strlen(path) + 1 + PATH_MAX + 1; char *filebuf = CryptMemAlloc(bufsize); if (filebuf) { struct dirent *entry; while ((entry = readdir(dir))) { if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) { snprintf(filebuf, bufsize, "%s/%s", path, entry->d_name); if (import_certs_from_path(filebuf, store, FALSE) && !ret) ret = TRUE; } } closedir(dir); CryptMemFree(filebuf); } } return ret; }
/* Reads certificates from the list of known locations into store. Stops when * any location contains any certificates, to prevent spending unnecessary time * adding redundant certificates, e.g. when both a certificate bundle and * individual certificates exist in the same directory. */ static void read_trusted_roots_from_known_locations(HCERTSTORE store) { HCERTSTORE from = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); if (from) { DWORD i; BOOL ret = FALSE; #ifdef HAVE_SECURITY_SECURITY_H OSStatus status; CFArrayRef rootCerts; status = SecTrustCopyAnchorCertificates(&rootCerts); if (status == noErr) { int i; for (i = 0; i < CFArrayGetCount(rootCerts); i++) { SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(rootCerts, i); CFDataRef certData; if ((status = SecKeychainItemExport(cert, kSecFormatX509Cert, 0, NULL, &certData)) == noErr) { if (CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, CFDataGetBytePtr(certData), CFDataGetLength(certData), CERT_STORE_ADD_NEW, NULL)) ret = TRUE; else WARN("adding root cert %d failed: %08x\n", i, GetLastError()); CFRelease(certData); } else WARN("could not export certificate %d to X509 format: 0x%08x\n", i, (unsigned int)status); } CFRelease(rootCerts); } #endif for (i = 0; !ret && i < sizeof(CRYPT_knownLocations) / sizeof(CRYPT_knownLocations[0]); i++) ret = import_certs_from_path(CRYPT_knownLocations[i], from, TRUE); check_and_store_certs(from, store); } CertCloseStore(from, 0); }
/* Opens path, which must be a directory, and imports certificates from every * file in the directory into store. * Returns TRUE if any certificates were successfully imported. */ static BOOL import_certs_from_dir(LPCSTR path, HCERTSTORE store) { #ifdef HAVE_READDIR BOOL ret = FALSE; DIR *dir; TRACE("(%s, %p)\n", debugstr_a(path), store); dir = opendir(path); if (dir) { size_t path_len = strlen(path), bufsize = 0; char *filebuf = NULL; struct dirent *entry; while ((entry = readdir(dir))) { if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) { size_t name_len = strlen(entry->d_name); if (!check_buffer_resize(&filebuf, &bufsize, path_len + 1 + name_len + 1)) { ERR("Path buffer (re)allocation failed with out of memory condition\n"); break; } snprintf(filebuf, bufsize, "%s/%s", path, entry->d_name); if (import_certs_from_path(filebuf, store, FALSE) && !ret) ret = TRUE; } } CryptMemFree(filebuf); closedir(dir); } return ret; #else FIXME("not implemented without readdir available\n"); return FALSE; #endif }
/* Reads certificates from the list of known locations into store. Stops when * any location contains any certificates, to prevent spending unnecessary time * adding redundant certificates, e.g. when both a certificate bundle and * individual certificates exist in the same directory. */ static void read_trusted_roots_from_known_locations(HCERTSTORE store) { HCERTSTORE from = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); if (from) { DWORD i; BOOL ret = FALSE; #ifdef __APPLE__ OSStatus status; CFArrayRef rootCerts; KeychainExportFunc exportFunc = NULL; #ifdef HAVE_DLFCN_H /* SecKeychainItemExport is deprecated on OS X 10.7, replaced by SecItemExport. * Since their parameters match, we can simply get the function pointer. */ exportFunc = dlsym(RTLD_DEFAULT, "SecItemExport"); if (exportFunc == NULL) { exportFunc = dlsym(RTLD_DEFAULT, "SecKeychainItemExport"); if (exportFunc == NULL) WARN("unable to load a keychain export function: root certificates not loaded from Keychain\n"); else TRACE("using SecKeychainItemExport()\n"); } else TRACE("using SecItemExport()\n"); #else exportFunc = SecKeychainItemExport; #endif status = SecTrustCopyAnchorCertificates(&rootCerts); if (status == noErr && exportFunc != NULL) { int i; for (i = 0; i < CFArrayGetCount(rootCerts); i++) { SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(rootCerts, i); CFDataRef certData; if ((status = exportFunc(cert, kSecFormatX509Cert, 0, NULL, &certData)) == noErr) { if (CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, CFDataGetBytePtr(certData), CFDataGetLength(certData), CERT_STORE_ADD_NEW, NULL)) ret = TRUE; else WARN("adding root cert %d failed: %08x\n", i, GetLastError()); CFRelease(certData); } else WARN("could not export certificate %d to X509 format: 0x%08x\n", i, (unsigned int)status); } CFRelease(rootCerts); } #endif for (i = 0; !ret && i < sizeof(CRYPT_knownLocations) / sizeof(CRYPT_knownLocations[0]); i++) ret = import_certs_from_path(CRYPT_knownLocations[i], from, TRUE); check_and_store_certs(from, store); } CertCloseStore(from, 0); }