FreeRDP
Loading...
Searching...
No Matches
certificate_data.c
1
23#include <ctype.h>
24
25#include <freerdp/config.h>
26
27#include <winpr/assert.h>
28#include <winpr/path.h>
29
30#include <freerdp/settings.h>
31
32#include <freerdp/crypto/crypto.h>
33#include <freerdp/crypto/certificate_data.h>
34
35#include "certificate.h"
36
37struct rdp_certificate_data
38{
39 char* hostname;
40 UINT16 port;
41 rdpCertificate* cert;
42
43 char cached_hash[MAX_PATH + 10];
44 char* cached_subject;
45 char* cached_issuer;
46 char* cached_fingerprint;
47 char* cached_pem;
48 char* cached_pem_chain;
49};
50
51/* ensure our hostnames (and therefore filenames) always use the same capitalization.
52 * the user might have input random case, but we always need to have a sane
53 * baseline to compare against. */
54static char* ensure_lowercase(char* str, size_t length)
55{
56 const size_t len = strnlen(str, length);
57 for (size_t x = 0; x < len; x++)
58 str[x] = (char)tolower(str[x]);
59 return str;
60}
61
62static char* ensure_valid_charset(char* str, size_t length)
63{
64 const size_t len = strnlen(str, length);
65 for (size_t x = 0; x < len; x++)
66 {
67 char cur = str[x];
68 switch (cur)
69 {
70 case ':':
71 str[x] = '.';
72 break;
73 case '/':
74 case '\\':
75 str[x] = '_';
76 break;
77 default:
78 break;
79 }
80 }
81 return str;
82}
83
84static const char* freerdp_certificate_data_hash_(const char* hostname, UINT16 port, char* name,
85 size_t length)
86{
87 (void)_snprintf(name, length, "%s_%" PRIu16 ".pem", hostname, port);
88 return ensure_lowercase(ensure_valid_charset(name, length), length);
89}
90
91static BOOL freerdp_certificate_data_load_cache(rdpCertificateData* data)
92{
93 BOOL rc = FALSE;
94
95 WINPR_ASSERT(data);
96
97 freerdp_certificate_data_hash_(data->hostname, data->port, data->cached_hash,
98 sizeof(data->cached_hash));
99 if (strnlen(data->cached_hash, sizeof(data->cached_hash)) == 0)
100 goto fail;
101
102 data->cached_subject = freerdp_certificate_get_subject(data->cert);
103 if (!data->cached_subject)
104 data->cached_subject = calloc(1, 1);
105
106 size_t pemlen = 0;
107 data->cached_pem = freerdp_certificate_get_pem_ex(data->cert, &pemlen, FALSE);
108 if (!data->cached_pem)
109 goto fail;
110
111 size_t pemchainlen = 0;
112 data->cached_pem_chain = freerdp_certificate_get_pem_ex(data->cert, &pemchainlen, TRUE);
113 if (!data->cached_pem_chain)
114 goto fail;
115
116 data->cached_fingerprint = freerdp_certificate_get_fingerprint(data->cert);
117 if (!data->cached_fingerprint)
118 goto fail;
119
120 data->cached_issuer = freerdp_certificate_get_issuer(data->cert);
121 if (!data->cached_issuer)
122 data->cached_issuer = calloc(1, 1);
123
124 rc = TRUE;
125fail:
126 return rc;
127}
128
129static rdpCertificateData* freerdp_certificate_data_new_nocopy(const char* hostname, UINT16 port,
130 rdpCertificate* xcert)
131{
132 rdpCertificateData* certdata = NULL;
133
134 if (!hostname || !xcert)
135 goto fail;
136
137 certdata = (rdpCertificateData*)calloc(1, sizeof(rdpCertificateData));
138
139 if (!certdata)
140 goto fail;
141
142 certdata->port = port;
143 certdata->hostname = _strdup(hostname);
144 if (!certdata->hostname)
145 goto fail;
146 ensure_lowercase(certdata->hostname, strlen(certdata->hostname));
147
148 certdata->cert = xcert;
149 if (!freerdp_certificate_data_load_cache(certdata))
150 {
151 certdata->cert = NULL;
152 goto fail;
153 }
154
155 return certdata;
156fail:
157 freerdp_certificate_data_free(certdata);
158 return NULL;
159}
160
161rdpCertificateData* freerdp_certificate_data_new(const char* hostname, UINT16 port,
162 const rdpCertificate* xcert)
163{
164 rdpCertificate* copy = freerdp_certificate_clone(xcert);
165 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, copy);
166 if (!data)
167 freerdp_certificate_free(copy);
168 return data;
169}
170
171rdpCertificateData* freerdp_certificate_data_new_from_pem(const char* hostname, UINT16 port,
172 const char* pem, size_t length)
173{
174 if (!pem || (length == 0))
175 return NULL;
176
177 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
178 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, cert);
179 if (!data)
180 freerdp_certificate_free(cert);
181 return data;
182}
183
184rdpCertificateData* freerdp_certificate_data_new_from_file(const char* hostname, UINT16 port,
185 const char* file)
186{
187 if (!file)
188 return NULL;
189
190 rdpCertificate* cert = freerdp_certificate_new_from_file(file);
191 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, cert);
192 if (!data)
193 freerdp_certificate_free(cert);
194 return data;
195}
196
197void freerdp_certificate_data_free(rdpCertificateData* data)
198{
199 if (data == NULL)
200 return;
201
202 free(data->hostname);
203 freerdp_certificate_free(data->cert);
204 free(data->cached_subject);
205 free(data->cached_issuer);
206 free(data->cached_fingerprint);
207 free(data->cached_pem);
208 free(data->cached_pem_chain);
209
210 free(data);
211}
212
213const char* freerdp_certificate_data_get_host(const rdpCertificateData* cert)
214{
215 if (!cert)
216 return NULL;
217 return cert->hostname;
218}
219
220UINT16 freerdp_certificate_data_get_port(const rdpCertificateData* cert)
221{
222 if (!cert)
223 return 0;
224 return cert->port;
225}
226
227const char* freerdp_certificate_data_get_pem(const rdpCertificateData* cert)
228{
229 return freerdp_certificate_data_get_pem_ex(cert, TRUE);
230}
231
232const char* freerdp_certificate_data_get_pem_ex(const rdpCertificateData* cert, BOOL withFullChain)
233{
234 if (!cert)
235 return NULL;
236 if (withFullChain)
237 return cert->cached_pem_chain;
238 return cert->cached_pem;
239}
240
241const char* freerdp_certificate_data_get_subject(const rdpCertificateData* cert)
242{
243 if (!cert)
244 return NULL;
245
246 return cert->cached_subject;
247}
248
249const char* freerdp_certificate_data_get_issuer(const rdpCertificateData* cert)
250{
251 if (!cert)
252 return NULL;
253
254 return cert->cached_issuer;
255}
256const char* freerdp_certificate_data_get_fingerprint(const rdpCertificateData* cert)
257{
258 if (!cert)
259 return NULL;
260
261 return cert->cached_fingerprint;
262}
263
264BOOL freerdp_certificate_data_equal(const rdpCertificateData* a, const rdpCertificateData* b)
265{
266 BOOL rc = FALSE;
267
268 WINPR_ASSERT(a);
269 WINPR_ASSERT(b);
270
271 if (strcmp(a->hostname, b->hostname) != 0)
272 return FALSE;
273 if (a->port != b->port)
274 return FALSE;
275
276 const char* pem1 = freerdp_certificate_data_get_fingerprint(a);
277 const char* pem2 = freerdp_certificate_data_get_fingerprint(b);
278 if (pem1 && pem2)
279 rc = strcmp(pem1, pem2) == 0;
280 else
281 rc = pem1 == pem2;
282
283 return rc;
284}
285
286const char* freerdp_certificate_data_get_hash(const rdpCertificateData* cert)
287{
288 if (!cert)
289 return NULL;
290
291 return cert->cached_hash;
292}
293
294char* freerdp_certificate_data_hash(const char* hostname, UINT16 port)
295{
296 char name[MAX_PATH + 10] = { 0 };
297 freerdp_certificate_data_hash_(hostname, port, name, sizeof(name));
298 return _strdup(name);
299}