1/* see license file for copyright and license details */
2#include "../tls.h"
3#include "../util.h"
4
5#include <errno.h>
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11
12#if FEATURE_USE_LIBRESSL
13#include <tls.h>
14
15struct TlsSocket {
16 int fd;
17 int is_tls;
18 struct tls *ctx;
19};
20
21#elif FEATURE_USE_BEARSSL
22#include <bearssl.h>
23
24struct my_x509_context {
25 const br_x509_class *vtable;
26 br_x509_minimal_context minimal;
27};
28
29struct TlsSocket {
30 int fd;
31 int is_tls;
32 br_ssl_client_context sc;
33 struct my_x509_context my_x509;
34 unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
35 br_sslio_context ioc;
36};
37
38struct dn_accum {
39 unsigned char *data;
40 size_t len;
41 size_t cap;
42};
43
44static void
45append_dn_callback(void *dn_ctx, const void *src, size_t len)
46{
47 struct dn_accum *accum = dn_ctx;
48 if (accum->len + len > accum->cap) {
49 accum->cap = accum->len + len + 256;
50 accum->data = erealloc(accum->data, accum->cap);
51 }
52 memcpy(accum->data + accum->len, src, len);
53 accum->len += len;
54}
55
56static void
57my_start_chain(const br_x509_class **ctx, const char *server_name)
58{
59 struct my_x509_context *t = (struct my_x509_context *)ctx;
60 br_x509_minimal_vtable.start_chain((const br_x509_class **)&t->minimal, server_name);
61}
62
63static void
64my_start_cert(const br_x509_class **ctx, uint32_t length)
65{
66 struct my_x509_context *t = (struct my_x509_context *)ctx;
67 br_x509_minimal_vtable.start_cert((const br_x509_class **)&t->minimal, length);
68}
69
70static void
71my_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
72{
73 struct my_x509_context *t = (struct my_x509_context *)ctx;
74 br_x509_minimal_vtable.append((const br_x509_class **)&t->minimal, buf, len);
75}
76
77static void
78my_end_cert(const br_x509_class **ctx)
79{
80 struct my_x509_context *t = (struct my_x509_context *)ctx;
81 br_x509_minimal_vtable.end_cert((const br_x509_class **)&t->minimal);
82}
83
84static unsigned
85my_end_chain(const br_x509_class **ctx)
86{
87 struct my_x509_context *t = (struct my_x509_context *)ctx;
88 (void)br_x509_minimal_vtable.end_chain((const br_x509_class **)&t->minimal);
89 /* always succeed and accept certificate when check_cert is 0 */
90 return 0;
91}
92
93static const br_x509_pkey *
94my_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
95{
96 const struct my_x509_context *t = (const struct my_x509_context *)ctx;
97 return br_x509_minimal_vtable.get_pkey((const br_x509_class *const *)&t->minimal, usages);
98}
99
100static const br_x509_class my_x509_vtable = {
101 sizeof(struct my_x509_context),
102 my_start_chain,
103 my_start_cert,
104 my_append,
105 my_end_cert,
106 my_end_chain,
107 my_get_pkey
108};
109
110static int
111sock_read(void *ctx, unsigned char *buf, size_t len)
112{
113 int fd = *(int *)ctx;
114 for (;;) {
115 ssize_t rlen = read(fd, buf, len);
116 if (rlen <= 0) {
117 if (rlen < 0 && errno == EINTR)
118 continue;
119 return -1;
120 }
121 return (int)rlen;
122 }
123}
124
125static int
126sock_write(void *ctx, const unsigned char *buf, size_t len)
127{
128 int fd = *(int *)ctx;
129 for (;;) {
130 ssize_t wlen = write(fd, buf, len);
131 if (wlen <= 0) {
132 if (wlen < 0 && errno == EINTR)
133 continue;
134 return -1;
135 }
136 return (int)wlen;
137 }
138}
139
140static int
141b64_decode_char(char c)
142{
143 if (c >= 'A' && c <= 'Z') return c - 'A';
144 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
145 if (c >= '0' && c <= '9') return c - '0' + 52;
146 if (c == '+') return 62;
147 if (c == '/') return 63;
148 return -1;
149}
150
151static size_t
152b64_decode(const char *src, size_t src_len, unsigned char *dst)
153{
154 size_t i, j = 0;
155 int val = 0, valb = -8;
156 for (i = 0; i < src_len; i++) {
157 int c = b64_decode_char(src[i]);
158 if (c >= 0) {
159 val = (val << 6) | c;
160 valb += 6;
161 if (valb >= 0) {
162 dst[j++] = (val >> valb) & 0xFF;
163 valb -= 8;
164 }
165 }
166 }
167 return j;
168}
169
170static int
171decode_cert_der(const unsigned char *der, size_t der_len, br_x509_trust_anchor *ta)
172{
173 br_x509_decoder_context dc;
174 struct dn_accum accum = { NULL, 0, 0 };
175 const br_x509_pkey *pk;
176
177 br_x509_decoder_init(&dc, append_dn_callback, &accum);
178 br_x509_decoder_push(&dc, der, der_len);
179 if (br_x509_decoder_last_error(&dc) != 0) {
180 free(accum.data);
181 return 0;
182 }
183 pk = br_x509_decoder_get_pkey(&dc);
184 if (!pk) {
185 free(accum.data);
186 return 0;
187 }
188
189 ta->dn.data = accum.data;
190 ta->dn.len = accum.len;
191 ta->flags = br_x509_decoder_isCA(&dc) ? BR_X509_TA_CA : 0;
192 ta->pkey.key_type = pk->key_type;
193
194 if (pk->key_type == BR_KEYTYPE_RSA) {
195 ta->pkey.key.rsa.nlen = pk->key.rsa.nlen;
196 ta->pkey.key.rsa.n = emalloc(pk->key.rsa.nlen);
197 memcpy(ta->pkey.key.rsa.n, pk->key.rsa.n, pk->key.rsa.nlen);
198 ta->pkey.key.rsa.elen = pk->key.rsa.elen;
199 ta->pkey.key.rsa.e = emalloc(pk->key.rsa.elen);
200 memcpy(ta->pkey.key.rsa.e, pk->key.rsa.e, pk->key.rsa.elen);
201 } else if (pk->key_type == BR_KEYTYPE_EC) {
202 ta->pkey.key.ec.curve = pk->key.ec.curve;
203 ta->pkey.key.ec.qlen = pk->key.ec.qlen;
204 ta->pkey.key.ec.q = emalloc(pk->key.ec.qlen);
205 memcpy(ta->pkey.key.ec.q, pk->key.ec.q, pk->key.ec.qlen);
206 } else {
207 free(accum.data);
208 return 0;
209 }
210 return 1;
211}
212
213static br_x509_trust_anchor *tas = NULL;
214static size_t tas_num = 0;
215
216static void
217load_ca_certs(void)
218{
219 static const char *ca_paths[] = {
220 "/etc/ssl/certs/ca-certificates.crt",
221 "/etc/ssl/cert.pem",
222 "/etc/pki/tls/certs/ca-bundle.crt",
223 };
224 FILE *fp = NULL;
225 size_t i;
226 char line[512];
227 struct {
228 char *data;
229 size_t len;
230 size_t cap;
231 } pem = { NULL, 0, 0 };
232 int in_cert = 0;
233
234 for (i = 0; i < LEN(ca_paths); i++) {
235 if ((fp = fopen(ca_paths[i], "r")))
236 break;
237 }
238 if (!fp) {
239 weprintf("no CA certificates found, TLS verification will fail\n");
240 return;
241 }
242
243 while (fgets(line, sizeof(line), fp)) {
244 if (strncmp(line, "-----BEGIN CERTIFICATE-----", 27) == 0) {
245 in_cert = 1;
246 pem.len = 0;
247 } else if (strncmp(line, "-----END CERTIFICATE-----", 25) == 0) {
248 if (in_cert) {
249 unsigned char *der = emalloc(pem.len);
250 size_t der_len = b64_decode(pem.data, pem.len, der);
251 br_x509_trust_anchor ta;
252 if (decode_cert_der(der, der_len, &ta)) {
253 tas = ereallocarray(tas, tas_num + 1, sizeof(*tas));
254 tas[tas_num++] = ta;
255 }
256 free(der);
257 in_cert = 0;
258 }
259 } else if (in_cert) {
260 size_t llen = strlen(line);
261 while (llen > 0 && (line[llen-1] == '\r' || line[llen-1] == '\n'))
262 llen--;
263 if (pem.len + llen > pem.cap) {
264 pem.cap = pem.len + llen + 1024;
265 pem.data = erealloc(pem.data, pem.cap);
266 }
267 memcpy(pem.data + pem.len, line, llen);
268 pem.len += llen;
269 }
270 }
271 free(pem.data);
272 fclose(fp);
273}
274#else
275struct TlsSocket {
276 int fd;
277 int is_tls;
278};
279#endif
280
281struct TlsSocket *
282tls_connect(int fd, const char *host, int check_cert, int is_tls)
283{
284 struct TlsSocket *s;
285
286 s = emalloc(sizeof(*s));
287 s->fd = fd;
288 s->is_tls = is_tls;
289
290 if (!is_tls)
291 return s;
292
293#if FEATURE_USE_LIBRESSL
294 {
295 struct tls_config *cfg;
296
297 s->ctx = tls_client();
298 if (!s->ctx) {
299 weprintf("tls_client failed\n");
300 free(s);
301 return NULL;
302 }
303 cfg = tls_config_new();
304 if (!cfg) {
305 weprintf("tls_config_new failed\n");
306 tls_free(s->ctx);
307 free(s);
308 return NULL;
309 }
310 if (!check_cert) {
311 tls_config_insecure_noverifycert(cfg);
312 tls_config_insecure_noverifyname(cfg);
313 }
314 if (tls_configure(s->ctx, cfg) < 0) {
315 weprintf("tls_configure: %s\n", tls_error(s->ctx));
316 tls_config_free(cfg);
317 tls_free(s->ctx);
318 free(s);
319 return NULL;
320 }
321 tls_config_free(cfg);
322
323 if (tls_connect_socket(s->ctx, fd, host) < 0) {
324 weprintf("tls_connect_socket: %s\n", tls_error(s->ctx));
325 tls_free(s->ctx);
326 free(s);
327 return NULL;
328 }
329 }
330#elif FEATURE_USE_BEARSSL
331 {
332 signal(SIGPIPE, SIG_IGN);
333
334 if (check_cert) {
335 static int ca_loaded = 0;
336 if (!ca_loaded) {
337 load_ca_certs();
338 ca_loaded = 1;
339 }
340 br_ssl_client_init_full(&s->sc, &s->my_x509.minimal, tas, tas_num);
341 } else {
342 br_ssl_client_init_full(&s->sc, &s->my_x509.minimal, NULL, 0);
343 s->my_x509.vtable = &my_x509_vtable;
344 br_ssl_engine_set_x509(&s->sc.eng, &s->my_x509.vtable);
345 }
346
347 br_ssl_engine_set_buffer(&s->sc.eng, s->iobuf, sizeof(s->iobuf), 1);
348 br_ssl_client_reset(&s->sc, host, 0);
349 br_sslio_init(&s->ioc, &s->sc.eng, sock_read, &s->fd, sock_write, &s->fd);
350
351 if (br_sslio_flush(&s->ioc) < 0) {
352 weprintf("TLS handshake failed with %s\n", host);
353 free(s);
354 return NULL;
355 }
356 }
357#else
358 weprintf("TLS not supported, compile with FEATURE_USE_LIBRESSL or FEATURE_USE_BEARSSL\n");
359 free(s);
360 return NULL;
361#endif
362
363 return s;
364}
365
366ssize_t
367tls_read(struct TlsSocket *s, void *buf, size_t len)
368{
369 if (!s->is_tls) {
370 for (;;) {
371 ssize_t r = read(s->fd, buf, len);
372 if (r < 0 && errno == EINTR)
373 continue;
374 return r;
375 }
376 }
377#if FEATURE_USE_LIBRESSL
378 for (;;) {
379 ssize_t r = tls_read(s->ctx, buf, len);
380 if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT)
381 continue;
382 return r;
383 }
384#elif FEATURE_USE_BEARSSL
385 return br_sslio_read(&s->ioc, buf, len);
386#else
387 return -1;
388#endif
389}
390
391ssize_t
392tls_write(struct TlsSocket *s, const void *buf, size_t len)
393{
394 if (!s->is_tls) {
395 for (;;) {
396 ssize_t r = write(s->fd, buf, len);
397 if (r < 0 && errno == EINTR)
398 continue;
399 return r;
400 }
401 }
402#if FEATURE_USE_LIBRESSL
403 for (;;) {
404 ssize_t r = tls_write(s->ctx, buf, len);
405 if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT)
406 continue;
407 return r;
408 }
409#elif FEATURE_USE_BEARSSL
410 {
411 int r = br_sslio_write_all(&s->ioc, buf, len);
412 if (r < 0)
413 return -1;
414 if (br_sslio_flush(&s->ioc) < 0)
415 return -1;
416 return len;
417 }
418#else
419 return -1;
420#endif
421}
422
423void
424tls_close(struct TlsSocket *s, int close_fd)
425{
426 if (s->is_tls) {
427#if FEATURE_USE_LIBRESSL
428 tls_close(s->ctx);
429 tls_free(s->ctx);
430#elif FEATURE_USE_BEARSSL
431 br_sslio_close(&s->ioc);
432#endif
433 }
434 if (close_fd)
435 close(s->fd);
436 free(s);
437}