xref: /dragonfly/crypto/libressl/tls/tls_util.c (revision de0e0e4d)
1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: tls_util.c,v 1.15 2021/08/16 13:54:38 tb Exp $ */
2f5b1c8a1SJohn Marino /*
3f5b1c8a1SJohn Marino  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
472c33676SMaxim Ag  * Copyright (c) 2014 Ted Unangst <tedu@openbsd.org>
5f5b1c8a1SJohn Marino  * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
6f5b1c8a1SJohn Marino  *
7f5b1c8a1SJohn Marino  * Permission to use, copy, modify, and distribute this software for any
8f5b1c8a1SJohn Marino  * purpose with or without fee is hereby granted, provided that the above
9f5b1c8a1SJohn Marino  * copyright notice and this permission notice appear in all copies.
10f5b1c8a1SJohn Marino  *
11f5b1c8a1SJohn Marino  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12f5b1c8a1SJohn Marino  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13f5b1c8a1SJohn Marino  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14f5b1c8a1SJohn Marino  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15f5b1c8a1SJohn Marino  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16f5b1c8a1SJohn Marino  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17f5b1c8a1SJohn Marino  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18f5b1c8a1SJohn Marino  */
19f5b1c8a1SJohn Marino 
20f5b1c8a1SJohn Marino #include <sys/stat.h>
21f5b1c8a1SJohn Marino 
22f5b1c8a1SJohn Marino #include <stdlib.h>
23f5b1c8a1SJohn Marino #include <unistd.h>
24f5b1c8a1SJohn Marino #include <fcntl.h>
25f5b1c8a1SJohn Marino 
26f5b1c8a1SJohn Marino #include "tls.h"
27f5b1c8a1SJohn Marino #include "tls_internal.h"
28f5b1c8a1SJohn Marino 
2972c33676SMaxim Ag static void *
memdup(const void * in,size_t len)3072c33676SMaxim Ag memdup(const void *in, size_t len)
3172c33676SMaxim Ag {
3272c33676SMaxim Ag 	void *out;
3372c33676SMaxim Ag 
3472c33676SMaxim Ag 	if ((out = malloc(len)) == NULL)
3572c33676SMaxim Ag 		return NULL;
3672c33676SMaxim Ag 	memcpy(out, in, len);
3772c33676SMaxim Ag 	return out;
3872c33676SMaxim Ag }
3972c33676SMaxim Ag 
4072c33676SMaxim Ag int
tls_set_mem(char ** dest,size_t * destlen,const void * src,size_t srclen)4172c33676SMaxim Ag tls_set_mem(char **dest, size_t *destlen, const void *src, size_t srclen)
4272c33676SMaxim Ag {
4372c33676SMaxim Ag 	free(*dest);
4472c33676SMaxim Ag 	*dest = NULL;
4572c33676SMaxim Ag 	*destlen = 0;
4672c33676SMaxim Ag 	if (src != NULL) {
4772c33676SMaxim Ag 		if ((*dest = memdup(src, srclen)) == NULL)
4872c33676SMaxim Ag 			return -1;
4972c33676SMaxim Ag 		*destlen = srclen;
5072c33676SMaxim Ag 	}
5172c33676SMaxim Ag 	return 0;
5272c33676SMaxim Ag }
5372c33676SMaxim Ag 
5472c33676SMaxim Ag int
tls_set_string(const char ** dest,const char * src)5572c33676SMaxim Ag tls_set_string(const char **dest, const char *src)
5672c33676SMaxim Ag {
5772c33676SMaxim Ag 	free((char *)*dest);
5872c33676SMaxim Ag 	*dest = NULL;
5972c33676SMaxim Ag 	if (src != NULL)
6072c33676SMaxim Ag 		if ((*dest = strdup(src)) == NULL)
6172c33676SMaxim Ag 			return -1;
6272c33676SMaxim Ag 	return 0;
6372c33676SMaxim Ag }
6472c33676SMaxim Ag 
65f5b1c8a1SJohn Marino /*
66f5b1c8a1SJohn Marino  * Extract the host and port from a colon separated value. For a literal IPv6
67f5b1c8a1SJohn Marino  * address the address must be contained with square braces. If a host and
68f5b1c8a1SJohn Marino  * port are successfully extracted, the function will return 0 and the
69f5b1c8a1SJohn Marino  * caller is responsible for freeing the host and port. If no port is found
70f5b1c8a1SJohn Marino  * then the function will return 1, with both host and port being NULL.
71f5b1c8a1SJohn Marino  * On memory allocation failure -1 will be returned.
72f5b1c8a1SJohn Marino  */
73f5b1c8a1SJohn Marino int
tls_host_port(const char * hostport,char ** host,char ** port)74f5b1c8a1SJohn Marino tls_host_port(const char *hostport, char **host, char **port)
75f5b1c8a1SJohn Marino {
76f5b1c8a1SJohn Marino 	char *h, *p, *s;
77f5b1c8a1SJohn Marino 	int rv = 1;
78f5b1c8a1SJohn Marino 
79f5b1c8a1SJohn Marino 	*host = NULL;
80f5b1c8a1SJohn Marino 	*port = NULL;
81f5b1c8a1SJohn Marino 
82f5b1c8a1SJohn Marino 	if ((s = strdup(hostport)) == NULL)
8372c33676SMaxim Ag 		goto err;
84f5b1c8a1SJohn Marino 
85f5b1c8a1SJohn Marino 	h = p = s;
86f5b1c8a1SJohn Marino 
87f5b1c8a1SJohn Marino 	/* See if this is an IPv6 literal with square braces. */
88f5b1c8a1SJohn Marino 	if (p[0] == '[') {
89f5b1c8a1SJohn Marino 		h++;
90f5b1c8a1SJohn Marino 		if ((p = strchr(s, ']')) == NULL)
91f5b1c8a1SJohn Marino 			goto done;
92f5b1c8a1SJohn Marino 		*p++ = '\0';
93f5b1c8a1SJohn Marino 	}
94f5b1c8a1SJohn Marino 
95*de0e0e4dSAntonio Huete Jimenez 	/* Find the port separator. */
96f5b1c8a1SJohn Marino 	if ((p = strchr(p, ':')) == NULL)
97f5b1c8a1SJohn Marino 		goto done;
98f5b1c8a1SJohn Marino 
99f5b1c8a1SJohn Marino 	/* If there is another separator then we have issues. */
100f5b1c8a1SJohn Marino 	if (strchr(p + 1, ':') != NULL)
101f5b1c8a1SJohn Marino 		goto done;
102f5b1c8a1SJohn Marino 
103f5b1c8a1SJohn Marino 	*p++ = '\0';
104f5b1c8a1SJohn Marino 
105cca6fc52SDaniel Fojt 	if (asprintf(host, "%s", h) == -1) {
106cca6fc52SDaniel Fojt 		*host = NULL;
10772c33676SMaxim Ag 		goto err;
108cca6fc52SDaniel Fojt 	}
109cca6fc52SDaniel Fojt 	if (asprintf(port, "%s", p) == -1) {
110cca6fc52SDaniel Fojt 		*port = NULL;
11172c33676SMaxim Ag 		goto err;
112cca6fc52SDaniel Fojt 	}
113f5b1c8a1SJohn Marino 
114f5b1c8a1SJohn Marino 	rv = 0;
115f5b1c8a1SJohn Marino 	goto done;
116f5b1c8a1SJohn Marino 
11772c33676SMaxim Ag  err:
118f5b1c8a1SJohn Marino 	free(*host);
119f5b1c8a1SJohn Marino 	*host = NULL;
120f5b1c8a1SJohn Marino 	free(*port);
121f5b1c8a1SJohn Marino 	*port = NULL;
122f5b1c8a1SJohn Marino 	rv = -1;
123f5b1c8a1SJohn Marino 
124f5b1c8a1SJohn Marino  done:
125f5b1c8a1SJohn Marino 	free(s);
126f5b1c8a1SJohn Marino 
127f5b1c8a1SJohn Marino 	return (rv);
128f5b1c8a1SJohn Marino }
129f5b1c8a1SJohn Marino 
13072c33676SMaxim Ag int
tls_password_cb(char * buf,int size,int rwflag,void * u)131f5b1c8a1SJohn Marino tls_password_cb(char *buf, int size, int rwflag, void *u)
132f5b1c8a1SJohn Marino {
133f5b1c8a1SJohn Marino 	size_t len;
13472c33676SMaxim Ag 
13572c33676SMaxim Ag 	if (size < 0)
13672c33676SMaxim Ag 		return (0);
13772c33676SMaxim Ag 
138f5b1c8a1SJohn Marino 	if (u == NULL) {
139f5b1c8a1SJohn Marino 		memset(buf, 0, size);
140f5b1c8a1SJohn Marino 		return (0);
141f5b1c8a1SJohn Marino 	}
14272c33676SMaxim Ag 
143f5b1c8a1SJohn Marino 	if ((len = strlcpy(buf, u, size)) >= (size_t)size)
144f5b1c8a1SJohn Marino 		return (0);
14572c33676SMaxim Ag 
146f5b1c8a1SJohn Marino 	return (len);
147f5b1c8a1SJohn Marino }
148f5b1c8a1SJohn Marino 
149f5b1c8a1SJohn Marino uint8_t *
tls_load_file(const char * name,size_t * len,char * password)150f5b1c8a1SJohn Marino tls_load_file(const char *name, size_t *len, char *password)
151f5b1c8a1SJohn Marino {
152f5b1c8a1SJohn Marino 	FILE *fp;
153f5b1c8a1SJohn Marino 	EVP_PKEY *key = NULL;
154f5b1c8a1SJohn Marino 	BIO *bio = NULL;
15572c33676SMaxim Ag 	char *data;
15672c33676SMaxim Ag 	uint8_t *buf = NULL;
157f5b1c8a1SJohn Marino 	struct stat st;
15872c33676SMaxim Ag 	size_t size = 0;
159f5b1c8a1SJohn Marino 	int fd = -1;
16072c33676SMaxim Ag 	ssize_t n;
161f5b1c8a1SJohn Marino 
162f5b1c8a1SJohn Marino 	*len = 0;
163f5b1c8a1SJohn Marino 
164f5b1c8a1SJohn Marino 	if ((fd = open(name, O_RDONLY)) == -1)
165f5b1c8a1SJohn Marino 		return (NULL);
166f5b1c8a1SJohn Marino 
167f5b1c8a1SJohn Marino 	/* Just load the file into memory without decryption */
168f5b1c8a1SJohn Marino 	if (password == NULL) {
169f5b1c8a1SJohn Marino 		if (fstat(fd, &st) != 0)
17072c33676SMaxim Ag 			goto err;
17172c33676SMaxim Ag 		if (st.st_size < 0)
17272c33676SMaxim Ag 			goto err;
173f5b1c8a1SJohn Marino 		size = (size_t)st.st_size;
17472c33676SMaxim Ag 		if ((buf = malloc(size)) == NULL)
17572c33676SMaxim Ag 			goto err;
17672c33676SMaxim Ag 		n = read(fd, buf, size);
17772c33676SMaxim Ag 		if (n < 0 || (size_t)n != size)
17872c33676SMaxim Ag 			goto err;
179f5b1c8a1SJohn Marino 		close(fd);
180f5b1c8a1SJohn Marino 		goto done;
181f5b1c8a1SJohn Marino 	}
182f5b1c8a1SJohn Marino 
183f5b1c8a1SJohn Marino 	/* Or read the (possibly) encrypted key from file */
184f5b1c8a1SJohn Marino 	if ((fp = fdopen(fd, "r")) == NULL)
18572c33676SMaxim Ag 		goto err;
186f5b1c8a1SJohn Marino 	fd = -1;
187f5b1c8a1SJohn Marino 
188f5b1c8a1SJohn Marino 	key = PEM_read_PrivateKey(fp, NULL, tls_password_cb, password);
189f5b1c8a1SJohn Marino 	fclose(fp);
190f5b1c8a1SJohn Marino 	if (key == NULL)
19172c33676SMaxim Ag 		goto err;
192f5b1c8a1SJohn Marino 
193f5b1c8a1SJohn Marino 	/* Write unencrypted key to memory buffer */
194f5b1c8a1SJohn Marino 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
19572c33676SMaxim Ag 		goto err;
196f5b1c8a1SJohn Marino 	if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL))
19772c33676SMaxim Ag 		goto err;
198f5b1c8a1SJohn Marino 	if ((size = BIO_get_mem_data(bio, &data)) <= 0)
19972c33676SMaxim Ag 		goto err;
20072c33676SMaxim Ag 	if ((buf = malloc(size)) == NULL)
20172c33676SMaxim Ag 		goto err;
202f5b1c8a1SJohn Marino 	memcpy(buf, data, size);
203f5b1c8a1SJohn Marino 
204f5b1c8a1SJohn Marino 	BIO_free_all(bio);
205f5b1c8a1SJohn Marino 	EVP_PKEY_free(key);
206f5b1c8a1SJohn Marino 
207f5b1c8a1SJohn Marino  done:
208f5b1c8a1SJohn Marino 	*len = size;
209f5b1c8a1SJohn Marino 	return (buf);
210f5b1c8a1SJohn Marino 
21172c33676SMaxim Ag  err:
212f5b1c8a1SJohn Marino 	if (fd != -1)
213f5b1c8a1SJohn Marino 		close(fd);
21472c33676SMaxim Ag 	freezero(buf, size);
215f5b1c8a1SJohn Marino 	BIO_free_all(bio);
216f5b1c8a1SJohn Marino 	EVP_PKEY_free(key);
217f5b1c8a1SJohn Marino 
218f5b1c8a1SJohn Marino 	return (NULL);
219f5b1c8a1SJohn Marino }
22072c33676SMaxim Ag 
22172c33676SMaxim Ag void
tls_unload_file(uint8_t * buf,size_t len)22272c33676SMaxim Ag tls_unload_file(uint8_t *buf, size_t len)
22372c33676SMaxim Ag {
22472c33676SMaxim Ag 	freezero(buf, len);
22572c33676SMaxim Ag }
226