2023-02-03 13:40:35 +03:00
|
|
|
/**
|
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
|
|
* Certificate Handling
|
|
|
|
*
|
|
|
|
* Copyright 2011 Jiten Pathy
|
|
|
|
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
2023-02-09 10:48:11 +03:00
|
|
|
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
|
|
|
* Copyright 2023 Thincast Technologies GmbH
|
2023-02-03 13:40:35 +03:00
|
|
|
*
|
|
|
|
* 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 <freerdp/config.h>
|
|
|
|
|
|
|
|
#include <winpr/assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include <winpr/crypto.h>
|
|
|
|
#include <winpr/crt.h>
|
|
|
|
#include <winpr/file.h>
|
|
|
|
#include <winpr/path.h>
|
|
|
|
|
|
|
|
#include <freerdp/settings.h>
|
|
|
|
|
|
|
|
#include <freerdp/crypto/crypto.h>
|
|
|
|
#include <freerdp/crypto/certificate_store.h>
|
|
|
|
#include <freerdp/log.h>
|
|
|
|
|
|
|
|
struct rdp_certificate_store
|
|
|
|
{
|
|
|
|
char* certs_path;
|
|
|
|
char* server_path;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char certificate_store_dir[] = "certs";
|
|
|
|
static const char certificate_server_dir[] = "server";
|
|
|
|
|
2023-07-29 12:13:15 +03:00
|
|
|
static char* freerdp_certificate_store_file_path(const rdpCertificateStore* store, const char* hash)
|
2023-02-03 13:40:35 +03:00
|
|
|
{
|
|
|
|
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;
|
2023-07-29 12:13:15 +03:00
|
|
|
|
|
|
|
WINPR_ASSERT(store);
|
|
|
|
|
2023-02-03 13:40:35 +03:00
|
|
|
const char* hash = freerdp_certificate_data_get_hash(data);
|
2023-07-29 12:13:15 +03:00
|
|
|
if (!hash)
|
|
|
|
return FALSE;
|
2023-02-03 13:40:35 +03:00
|
|
|
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;
|
|
|
|
|
2024-08-26 16:39:33 +03:00
|
|
|
(void)fprintf(fp, "%s", freerdp_certificate_data_get_pem_ex(data, FALSE));
|
2023-02-03 13:40:35 +03:00
|
|
|
|
|
|
|
rc = TRUE;
|
|
|
|
fail:
|
2023-04-27 10:23:51 +03:00
|
|
|
if (fp)
|
2024-08-26 16:39:33 +03:00
|
|
|
(void)fclose(fp);
|
2023-02-03 13:40:35 +03:00
|
|
|
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);
|
|
|
|
|
2023-07-29 12:13:15 +03:00
|
|
|
path = freerdp_certificate_store_get_cert_path(store, host, port);
|
2023-02-03 13:40:35 +03:00
|
|
|
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:
|
2024-02-04 13:11:29 +03:00
|
|
|
WINPR_PRAGMA_DIAG_PUSH
|
|
|
|
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
2023-02-03 13:40:35 +03:00
|
|
|
freerdp_certificate_store_free(store);
|
2024-02-04 13:11:29 +03:00
|
|
|
WINPR_PRAGMA_DIAG_POP
|
2023-02-03 13:40:35 +03:00
|
|
|
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;
|
|
|
|
}
|
2023-07-29 12:13:15 +03:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|