master xplshn/aruu / shared / libutil / tls.c
  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}