25#include <freerdp/config.h>
27#include <winpr/assert.h>
28#include <winpr/path.h>
30#include <freerdp/settings.h>
32#include <freerdp/crypto/crypto.h>
33#include <freerdp/crypto/certificate_data.h>
35#include "certificate.h"
36#include <freerdp/log.h>
37#define TAG FREERDP_TAG("crypto.certificate_data")
39struct rdp_certificate_data
45 char cached_hash[MAX_PATH + 10];
48 char* cached_fingerprint;
50 char* cached_pem_chain;
56static char* ensure_lowercase(
char* str,
size_t length)
58 const size_t len = strnlen(str, length);
59 for (
size_t x = 0; x < len; x++)
60 str[x] = (
char)tolower(str[x]);
64static char* ensure_valid_charset(
char* str,
size_t length)
66 const size_t len = strnlen(str, length);
67 for (
size_t x = 0; x < len; x++)
86static const char* freerdp_certificate_data_hash_(
const char* hostname, UINT16 port,
char* name,
89 (void)_snprintf(name, length,
"%s_%" PRIu16
".pem", hostname, port);
90 return ensure_lowercase(ensure_valid_charset(name, length), length);
93static BOOL freerdp_certificate_data_load_cache(rdpCertificateData* data)
99 freerdp_certificate_data_hash_(data->hostname, data->port, data->cached_hash,
100 sizeof(data->cached_hash) - 1);
101 const size_t len = strnlen(data->cached_hash,
sizeof(data->cached_hash));
102 if ((len == 0) || (len >=
sizeof(data->cached_hash)))
105 data->cached_subject = freerdp_certificate_get_subject(data->cert);
106 if (!data->cached_subject)
107 data->cached_subject = calloc(1, 1);
111 data->cached_pem = freerdp_certificate_get_pem_ex(data->cert, &pemlen, FALSE);
113 if (!data->cached_pem)
117 size_t pemchainlen = 0;
118 data->cached_pem_chain = freerdp_certificate_get_pem_ex(data->cert, &pemchainlen, TRUE);
119 if (!data->cached_pem_chain)
123 data->cached_fingerprint = freerdp_certificate_get_fingerprint(data->cert);
124 if (!data->cached_fingerprint)
127 data->cached_issuer = freerdp_certificate_get_issuer(data->cert);
128 if (!data->cached_issuer)
129 data->cached_issuer = calloc(1, 1);
136static rdpCertificateData* freerdp_certificate_data_new_nocopy(
const char* hostname, UINT16 port,
137 rdpCertificate* xcert)
139 rdpCertificateData* certdata = NULL;
141 if (!hostname || !xcert)
143 if (strnlen(hostname, MAX_PATH) >= MAX_PATH)
145 WLog_ERR(TAG,
"hostname exceeds length limits");
149 certdata = (rdpCertificateData*)calloc(1,
sizeof(rdpCertificateData));
154 certdata->port = port;
155 certdata->hostname = _strdup(hostname);
156 if (!certdata->hostname)
158 ensure_lowercase(certdata->hostname, strlen(certdata->hostname));
160 certdata->cert = xcert;
161 if (!freerdp_certificate_data_load_cache(certdata))
163 certdata->cert = NULL;
169 freerdp_certificate_data_free(certdata);
173rdpCertificateData* freerdp_certificate_data_new(
const char* hostname, UINT16 port,
174 const rdpCertificate* xcert)
176 rdpCertificate* copy = freerdp_certificate_clone(xcert);
177 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, copy);
179 freerdp_certificate_free(copy);
183rdpCertificateData* freerdp_certificate_data_new_from_pem(
const char* hostname, UINT16 port,
184 const char* pem,
size_t length)
186 if (!pem || (length == 0))
189 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
190 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, cert);
192 freerdp_certificate_free(cert);
196rdpCertificateData* freerdp_certificate_data_new_from_file(
const char* hostname, UINT16 port,
202 rdpCertificate* cert = freerdp_certificate_new_from_file(file);
203 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, cert);
205 freerdp_certificate_free(cert);
209void freerdp_certificate_data_free(rdpCertificateData* data)
214 free(data->hostname);
215 freerdp_certificate_free(data->cert);
216 free(data->cached_subject);
217 free(data->cached_issuer);
218 free(data->cached_fingerprint);
219 free(data->cached_pem);
220 free(data->cached_pem_chain);
225const char* freerdp_certificate_data_get_host(
const rdpCertificateData* cert)
229 return cert->hostname;
232UINT16 freerdp_certificate_data_get_port(
const rdpCertificateData* cert)
239const char* freerdp_certificate_data_get_pem(
const rdpCertificateData* cert)
241 return freerdp_certificate_data_get_pem_ex(cert, TRUE);
244const char* freerdp_certificate_data_get_pem_ex(
const rdpCertificateData* cert, BOOL withFullChain)
249 return cert->cached_pem_chain;
250 return cert->cached_pem;
253const char* freerdp_certificate_data_get_subject(
const rdpCertificateData* cert)
258 return cert->cached_subject;
261const char* freerdp_certificate_data_get_issuer(
const rdpCertificateData* cert)
266 return cert->cached_issuer;
268const char* freerdp_certificate_data_get_fingerprint(
const rdpCertificateData* cert)
273 return cert->cached_fingerprint;
276BOOL freerdp_certificate_data_equal(
const rdpCertificateData* a,
const rdpCertificateData* b)
283 if (strcmp(a->hostname, b->hostname) != 0)
285 if (a->port != b->port)
288 const char* pem1 = freerdp_certificate_data_get_fingerprint(a);
289 const char* pem2 = freerdp_certificate_data_get_fingerprint(b);
291 rc = strcmp(pem1, pem2) == 0;
298const char* freerdp_certificate_data_get_hash(
const rdpCertificateData* cert)
303 return cert->cached_hash;
306char* freerdp_certificate_data_hash(
const char* hostname, UINT16 port)
308 char name[MAX_PATH + 10] = { 0 };
309 freerdp_certificate_data_hash_(hostname, port, name,
sizeof(name));
310 return strndup(name,
sizeof(name));