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);
110 data->cached_pem = freerdp_certificate_get_pem_ex(data->cert, &pemlen, FALSE);
111 if (!data->cached_pem)
114 size_t pemchainlen = 0;
115 data->cached_pem_chain = freerdp_certificate_get_pem_ex(data->cert, &pemchainlen, TRUE);
116 if (!data->cached_pem_chain)
119 data->cached_fingerprint = freerdp_certificate_get_fingerprint(data->cert);
120 if (!data->cached_fingerprint)
123 data->cached_issuer = freerdp_certificate_get_issuer(data->cert);
124 if (!data->cached_issuer)
125 data->cached_issuer = calloc(1, 1);
132static rdpCertificateData* freerdp_certificate_data_new_nocopy(
const char* hostname, UINT16 port,
133 rdpCertificate* xcert)
135 rdpCertificateData* certdata = NULL;
137 if (!hostname || !xcert)
139 if (strnlen(hostname, MAX_PATH) >= MAX_PATH)
141 WLog_ERR(TAG,
"hostname exceeds length limits");
145 certdata = (rdpCertificateData*)calloc(1,
sizeof(rdpCertificateData));
150 certdata->port = port;
151 certdata->hostname = _strdup(hostname);
152 if (!certdata->hostname)
154 ensure_lowercase(certdata->hostname, strlen(certdata->hostname));
156 certdata->cert = xcert;
157 if (!freerdp_certificate_data_load_cache(certdata))
159 certdata->cert = NULL;
165 freerdp_certificate_data_free(certdata);
169rdpCertificateData* freerdp_certificate_data_new(
const char* hostname, UINT16 port,
170 const rdpCertificate* xcert)
172 rdpCertificate* copy = freerdp_certificate_clone(xcert);
173 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, copy);
175 freerdp_certificate_free(copy);
179rdpCertificateData* freerdp_certificate_data_new_from_pem(
const char* hostname, UINT16 port,
180 const char* pem,
size_t length)
182 if (!pem || (length == 0))
185 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
186 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, cert);
188 freerdp_certificate_free(cert);
192rdpCertificateData* freerdp_certificate_data_new_from_file(
const char* hostname, UINT16 port,
198 rdpCertificate* cert = freerdp_certificate_new_from_file(file);
199 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, cert);
201 freerdp_certificate_free(cert);
205void freerdp_certificate_data_free(rdpCertificateData* data)
210 free(data->hostname);
211 freerdp_certificate_free(data->cert);
212 free(data->cached_subject);
213 free(data->cached_issuer);
214 free(data->cached_fingerprint);
215 free(data->cached_pem);
216 free(data->cached_pem_chain);
221const char* freerdp_certificate_data_get_host(
const rdpCertificateData* cert)
225 return cert->hostname;
228UINT16 freerdp_certificate_data_get_port(
const rdpCertificateData* cert)
235const char* freerdp_certificate_data_get_pem(
const rdpCertificateData* cert)
237 return freerdp_certificate_data_get_pem_ex(cert, TRUE);
240const char* freerdp_certificate_data_get_pem_ex(
const rdpCertificateData* cert, BOOL withFullChain)
245 return cert->cached_pem_chain;
246 return cert->cached_pem;
249const char* freerdp_certificate_data_get_subject(
const rdpCertificateData* cert)
254 return cert->cached_subject;
257const char* freerdp_certificate_data_get_issuer(
const rdpCertificateData* cert)
262 return cert->cached_issuer;
264const char* freerdp_certificate_data_get_fingerprint(
const rdpCertificateData* cert)
269 return cert->cached_fingerprint;
272BOOL freerdp_certificate_data_equal(
const rdpCertificateData* a,
const rdpCertificateData* b)
279 if (strcmp(a->hostname, b->hostname) != 0)
281 if (a->port != b->port)
284 const char* pem1 = freerdp_certificate_data_get_fingerprint(a);
285 const char* pem2 = freerdp_certificate_data_get_fingerprint(b);
287 rc = strcmp(pem1, pem2) == 0;
294const char* freerdp_certificate_data_get_hash(
const rdpCertificateData* cert)
299 return cert->cached_hash;
302char* freerdp_certificate_data_hash(
const char* hostname, UINT16 port)
304 char name[MAX_PATH + 10] = { 0 };
305 freerdp_certificate_data_hash_(hostname, port, name,
sizeof(name));
306 return strndup(name,
sizeof(name));