/** * FreeRDP: A Remote Desktop Protocol Implementation * Certificate Handling * * Copyright 2011 Jiten Pathy * Copyright 2011-2012 Marc-Andre Moreau * Copyright 2023 Armin Novak * Copyright 2023 Thincast Technologies GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TAG FREERDP_TAG("crypto") struct rdp_certificate_store { char* certs_path; char* server_path; }; static const char certificate_store_dir[] = "certs"; static const char certificate_server_dir[] = "server"; static char* freerdp_certificate_store_file_path(const rdpCertificateStore* store, const char* hash) { const char* hosts = freerdp_certificate_store_get_hosts_path(store); if (!hosts || !hash) return NULL; return GetCombinedPath(hosts, hash); } freerdp_certificate_store_result freerdp_certificate_store_contains_data(rdpCertificateStore* store, const rdpCertificateData* data) { freerdp_certificate_store_result rc = CERT_STORE_NOT_FOUND; const char* host = freerdp_certificate_data_get_host(data); const UINT16 port = freerdp_certificate_data_get_port(data); rdpCertificateData* loaded = freerdp_certificate_store_load_data(store, host, port); if (!loaded) goto fail; rc = freerdp_certificate_data_equal(data, loaded) ? CERT_STORE_MATCH : CERT_STORE_MISMATCH; fail: freerdp_certificate_data_free(loaded); return rc; } BOOL freerdp_certificate_store_remove_data(rdpCertificateStore* store, const rdpCertificateData* data) { BOOL rc = TRUE; WINPR_ASSERT(store); const char* hash = freerdp_certificate_data_get_hash(data); if (!hash) return FALSE; char* path = freerdp_certificate_store_file_path(store, hash); if (!path) return FALSE; if (winpr_PathFileExists(path)) rc = winpr_DeleteFile(path); free(path); return rc; } BOOL freerdp_certificate_store_save_data(rdpCertificateStore* store, const rdpCertificateData* data) { BOOL rc = FALSE; const char* base = freerdp_certificate_store_get_hosts_path(store); const char* hash = freerdp_certificate_data_get_hash(data); char* path = freerdp_certificate_store_file_path(store, hash); FILE* fp = NULL; if (!winpr_PathFileExists(base)) { if (!winpr_PathMakePath(base, NULL)) goto fail; } fp = winpr_fopen(path, "w"); if (!fp) goto fail; (void)fprintf(fp, "%s", freerdp_certificate_data_get_pem_ex(data, FALSE)); rc = TRUE; fail: if (fp) (void)fclose(fp); free(path); return rc; } rdpCertificateData* freerdp_certificate_store_load_data(rdpCertificateStore* store, const char* host, UINT16 port) { char* path = NULL; rdpCertificateData* data = NULL; WINPR_ASSERT(store); path = freerdp_certificate_store_get_cert_path(store, host, port); if (!path) goto fail; data = freerdp_certificate_data_new_from_file(host, port, path); fail: free(path); return data; } rdpCertificateStore* freerdp_certificate_store_new(const rdpSettings* settings) { rdpCertificateStore* store = (rdpCertificateStore*)calloc(1, sizeof(rdpCertificateStore)); if (!store) return NULL; const char* base = freerdp_settings_get_string(settings, FreeRDP_ConfigPath); if (!base) goto fail; store->certs_path = GetCombinedPath(base, certificate_store_dir); store->server_path = GetCombinedPath(base, certificate_server_dir); if (!store->certs_path || !store->server_path) goto fail; return store; fail: WINPR_PRAGMA_DIAG_PUSH WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC freerdp_certificate_store_free(store); WINPR_PRAGMA_DIAG_POP return NULL; } void freerdp_certificate_store_free(rdpCertificateStore* store) { if (!store) return; free(store->certs_path); free(store->server_path); free(store); } const char* freerdp_certificate_store_get_certs_path(const rdpCertificateStore* store) { WINPR_ASSERT(store); return store->certs_path; } const char* freerdp_certificate_store_get_hosts_path(const rdpCertificateStore* store) { WINPR_ASSERT(store); return store->server_path; } char* freerdp_certificate_store_get_cert_path(const rdpCertificateStore* store, const char* host, UINT16 port) { WINPR_ASSERT(store); char* hash = freerdp_certificate_data_hash(host, port); if (!hash) return NULL; char* path = freerdp_certificate_store_file_path(store, hash); free(hash); return path; }