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}
61static const char* freerdp_certificate_data_hash_(const char* hostname, UINT16 port, char* name,
62 size_t length)
63{
64 (void)_snprintf(name, length, "%s_%" PRIu16 ".pem", hostname, port);
65 return ensure_lowercase(name, length);
66}
67
68static BOOL freerdp_certificate_data_load_cache(rdpCertificateData* data)
69{
70 BOOL rc = FALSE;
71
72 WINPR_ASSERT(data);
73
74 freerdp_certificate_data_hash_(data->hostname, data->port, data->cached_hash,
75 sizeof(data->cached_hash));
76 if (strnlen(data->cached_hash, sizeof(data->cached_hash)) == 0)
77 goto fail;
78
79 data->cached_subject = freerdp_certificate_get_subject(data->cert);
80 if (!data->cached_subject)
81 data->cached_subject = calloc(1, 1);
82
83 size_t pemlen = 0;
84 data->cached_pem = freerdp_certificate_get_pem_ex(data->cert, &pemlen, FALSE);
85 if (!data->cached_pem)
86 goto fail;
87
88 size_t pemchainlen = 0;
89 data->cached_pem_chain = freerdp_certificate_get_pem_ex(data->cert, &pemchainlen, TRUE);
90 if (!data->cached_pem_chain)
91 goto fail;
92
93 data->cached_fingerprint = freerdp_certificate_get_fingerprint(data->cert);
94 if (!data->cached_fingerprint)
95 goto fail;
96
97 data->cached_issuer = freerdp_certificate_get_issuer(data->cert);
98 if (!data->cached_issuer)
99 data->cached_issuer = calloc(1, 1);
100
101 rc = TRUE;
102fail:
103 return rc;
104}
105
106static rdpCertificateData* freerdp_certificate_data_new_nocopy(const char* hostname, UINT16 port,
107 rdpCertificate* xcert)
108{
109 rdpCertificateData* certdata = NULL;
110
111 if (!hostname || !xcert)
112 goto fail;
113
114 certdata = (rdpCertificateData*)calloc(1, sizeof(rdpCertificateData));
115
116 if (!certdata)
117 goto fail;
118
119 certdata->port = port;
120 certdata->hostname = _strdup(hostname);
121 if (!certdata->hostname)
122 goto fail;
123 ensure_lowercase(certdata->hostname, strlen(certdata->hostname));
124
125 certdata->cert = xcert;
126 if (!freerdp_certificate_data_load_cache(certdata))
127 {
128 certdata->cert = NULL;
129 goto fail;
130 }
131
132 return certdata;
133fail:
134 freerdp_certificate_data_free(certdata);
135 return NULL;
136}
137
138rdpCertificateData* freerdp_certificate_data_new(const char* hostname, UINT16 port,
139 const rdpCertificate* xcert)
140{
141 rdpCertificate* copy = freerdp_certificate_clone(xcert);
142 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, copy);
143 if (!data)
144 freerdp_certificate_free(copy);
145 return data;
146}
147
148rdpCertificateData* freerdp_certificate_data_new_from_pem(const char* hostname, UINT16 port,
149 const char* pem, size_t length)
150{
151 if (!pem || (length == 0))
152 return NULL;
153
154 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
155 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, cert);
156 if (!data)
157 freerdp_certificate_free(cert);
158 return data;
159}
160
161rdpCertificateData* freerdp_certificate_data_new_from_file(const char* hostname, UINT16 port,
162 const char* file)
163{
164 if (!file)
165 return NULL;
166
167 rdpCertificate* cert = freerdp_certificate_new_from_file(file);
168 rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, cert);
169 if (!data)
170 freerdp_certificate_free(cert);
171 return data;
172}
173
174void freerdp_certificate_data_free(rdpCertificateData* data)
175{
176 if (data == NULL)
177 return;
178
179 free(data->hostname);
180 freerdp_certificate_free(data->cert);
181 free(data->cached_subject);
182 free(data->cached_issuer);
183 free(data->cached_fingerprint);
184 free(data->cached_pem);
185 free(data->cached_pem_chain);
186
187 free(data);
188}
189
190const char* freerdp_certificate_data_get_host(const rdpCertificateData* cert)
191{
192 if (!cert)
193 return NULL;
194 return cert->hostname;
195}
196
197UINT16 freerdp_certificate_data_get_port(const rdpCertificateData* cert)
198{
199 if (!cert)
200 return 0;
201 return cert->port;
202}
203
204const char* freerdp_certificate_data_get_pem(const rdpCertificateData* cert)
205{
206 return freerdp_certificate_data_get_pem_ex(cert, TRUE);
207}
208
209const char* freerdp_certificate_data_get_pem_ex(const rdpCertificateData* cert, BOOL withFullChain)
210{
211 if (!cert)
212 return NULL;
213 if (withFullChain)
214 return cert->cached_pem_chain;
215 return cert->cached_pem;
216}
217
218const char* freerdp_certificate_data_get_subject(const rdpCertificateData* cert)
219{
220 if (!cert)
221 return NULL;
222
223 return cert->cached_subject;
224}
225
226const char* freerdp_certificate_data_get_issuer(const rdpCertificateData* cert)
227{
228 if (!cert)
229 return NULL;
230
231 return cert->cached_issuer;
232}
233const char* freerdp_certificate_data_get_fingerprint(const rdpCertificateData* cert)
234{
235 if (!cert)
236 return NULL;
237
238 return cert->cached_fingerprint;
239}
240
241BOOL freerdp_certificate_data_equal(const rdpCertificateData* a, const rdpCertificateData* b)
242{
243 BOOL rc = FALSE;
244
245 WINPR_ASSERT(a);
246 WINPR_ASSERT(b);
247
248 if (strcmp(a->hostname, b->hostname) != 0)
249 return FALSE;
250 if (a->port != b->port)
251 return FALSE;
252
253 const char* pem1 = freerdp_certificate_data_get_fingerprint(a);
254 const char* pem2 = freerdp_certificate_data_get_fingerprint(b);
255 if (pem1 && pem2)
256 rc = strcmp(pem1, pem2) == 0;
257 else
258 rc = pem1 == pem2;
259
260 return rc;
261}
262
263const char* freerdp_certificate_data_get_hash(const rdpCertificateData* cert)
264{
265 if (!cert)
266 return NULL;
267
268 return cert->cached_hash;
269}
270
271char* freerdp_certificate_data_hash(const char* hostname, UINT16 port)
272{
273 char name[MAX_PATH + 10] = { 0 };
274 freerdp_certificate_data_hash_(hostname, port, name, sizeof(name));
275 return _strdup(name);
276}