1*e6d77be9Sop /* $OpenBSD: tls_util.c,v 1.16 2023/05/14 07:26:25 op Exp $ */
2b600beedSjsing /*
3b600beedSjsing * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
415ba8e50Sjsing * Copyright (c) 2014 Ted Unangst <tedu@openbsd.org>
5cbcdaa48Sreyk * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
6b600beedSjsing *
7b600beedSjsing * Permission to use, copy, modify, and distribute this software for any
8b600beedSjsing * purpose with or without fee is hereby granted, provided that the above
9b600beedSjsing * copyright notice and this permission notice appear in all copies.
10b600beedSjsing *
11b600beedSjsing * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12b600beedSjsing * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13b600beedSjsing * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14b600beedSjsing * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15b600beedSjsing * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16b600beedSjsing * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17b600beedSjsing * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18b600beedSjsing */
19b600beedSjsing
20cbcdaa48Sreyk #include <sys/stat.h>
21b600beedSjsing
22cbcdaa48Sreyk #include <stdlib.h>
23*e6d77be9Sop #include <string.h>
24cbcdaa48Sreyk #include <unistd.h>
25cbcdaa48Sreyk #include <fcntl.h>
26cbcdaa48Sreyk
27cbcdaa48Sreyk #include "tls.h"
28b600beedSjsing #include "tls_internal.h"
29b600beedSjsing
30bb4cb1b0Sjsing static void *
memdup(const void * in,size_t len)31bb4cb1b0Sjsing memdup(const void *in, size_t len)
32bb4cb1b0Sjsing {
33bb4cb1b0Sjsing void *out;
34bb4cb1b0Sjsing
35bb4cb1b0Sjsing if ((out = malloc(len)) == NULL)
36bb4cb1b0Sjsing return NULL;
37bb4cb1b0Sjsing memcpy(out, in, len);
38bb4cb1b0Sjsing return out;
39bb4cb1b0Sjsing }
40bb4cb1b0Sjsing
41bb4cb1b0Sjsing int
tls_set_mem(char ** dest,size_t * destlen,const void * src,size_t srclen)42bb4cb1b0Sjsing tls_set_mem(char **dest, size_t *destlen, const void *src, size_t srclen)
43bb4cb1b0Sjsing {
44bb4cb1b0Sjsing free(*dest);
45bb4cb1b0Sjsing *dest = NULL;
46bb4cb1b0Sjsing *destlen = 0;
47a2b2c537Sjsing if (src != NULL) {
48bb4cb1b0Sjsing if ((*dest = memdup(src, srclen)) == NULL)
49bb4cb1b0Sjsing return -1;
50bb4cb1b0Sjsing *destlen = srclen;
51a2b2c537Sjsing }
52bb4cb1b0Sjsing return 0;
53bb4cb1b0Sjsing }
54bb4cb1b0Sjsing
55bb4cb1b0Sjsing int
tls_set_string(const char ** dest,const char * src)56bb4cb1b0Sjsing tls_set_string(const char **dest, const char *src)
57bb4cb1b0Sjsing {
58bb4cb1b0Sjsing free((char *)*dest);
59bb4cb1b0Sjsing *dest = NULL;
60bb4cb1b0Sjsing if (src != NULL)
61bb4cb1b0Sjsing if ((*dest = strdup(src)) == NULL)
62bb4cb1b0Sjsing return -1;
63bb4cb1b0Sjsing return 0;
64bb4cb1b0Sjsing }
65bb4cb1b0Sjsing
66b600beedSjsing /*
67b600beedSjsing * Extract the host and port from a colon separated value. For a literal IPv6
68b600beedSjsing * address the address must be contained with square braces. If a host and
69b600beedSjsing * port are successfully extracted, the function will return 0 and the
70b600beedSjsing * caller is responsible for freeing the host and port. If no port is found
71b600beedSjsing * then the function will return 1, with both host and port being NULL.
72b600beedSjsing * On memory allocation failure -1 will be returned.
73b600beedSjsing */
74b600beedSjsing int
tls_host_port(const char * hostport,char ** host,char ** port)75b600beedSjsing tls_host_port(const char *hostport, char **host, char **port)
76b600beedSjsing {
77b600beedSjsing char *h, *p, *s;
78b600beedSjsing int rv = 1;
79b600beedSjsing
80b600beedSjsing *host = NULL;
81b600beedSjsing *port = NULL;
82b600beedSjsing
83b600beedSjsing if ((s = strdup(hostport)) == NULL)
847add217bSjsing goto err;
85b600beedSjsing
86b600beedSjsing h = p = s;
87b600beedSjsing
88b600beedSjsing /* See if this is an IPv6 literal with square braces. */
89b600beedSjsing if (p[0] == '[') {
90b600beedSjsing h++;
91b600beedSjsing if ((p = strchr(s, ']')) == NULL)
92b600beedSjsing goto done;
93b600beedSjsing *p++ = '\0';
94b600beedSjsing }
95b600beedSjsing
96718d8d98Stb /* Find the port separator. */
97b600beedSjsing if ((p = strchr(p, ':')) == NULL)
98b600beedSjsing goto done;
99b600beedSjsing
100b600beedSjsing /* If there is another separator then we have issues. */
101b600beedSjsing if (strchr(p + 1, ':') != NULL)
102b600beedSjsing goto done;
103b600beedSjsing
104b600beedSjsing *p++ = '\0';
105b600beedSjsing
1060f235647Stb if (asprintf(host, "%s", h) == -1) {
1070f235647Stb *host = NULL;
1087add217bSjsing goto err;
1090f235647Stb }
1100f235647Stb if (asprintf(port, "%s", p) == -1) {
1110f235647Stb *port = NULL;
1127add217bSjsing goto err;
1130f235647Stb }
114b600beedSjsing
115b600beedSjsing rv = 0;
116b600beedSjsing goto done;
117b600beedSjsing
1187add217bSjsing err:
119b600beedSjsing free(*host);
120b600beedSjsing *host = NULL;
121b600beedSjsing free(*port);
122b600beedSjsing *port = NULL;
123b600beedSjsing rv = -1;
124b600beedSjsing
125b600beedSjsing done:
126b600beedSjsing free(s);
127b600beedSjsing
128b600beedSjsing return (rv);
129b600beedSjsing }
130cbcdaa48Sreyk
131a192468aSjsing int
tls_password_cb(char * buf,int size,int rwflag,void * u)132cbcdaa48Sreyk tls_password_cb(char *buf, int size, int rwflag, void *u)
133cbcdaa48Sreyk {
134cbcdaa48Sreyk size_t len;
135dad7bfe2Sjsing
136dad7bfe2Sjsing if (size < 0)
137dad7bfe2Sjsing return (0);
138dad7bfe2Sjsing
139cbcdaa48Sreyk if (u == NULL) {
140cbcdaa48Sreyk memset(buf, 0, size);
141cbcdaa48Sreyk return (0);
142cbcdaa48Sreyk }
143dad7bfe2Sjsing
144cbcdaa48Sreyk if ((len = strlcpy(buf, u, size)) >= (size_t)size)
145cbcdaa48Sreyk return (0);
146dad7bfe2Sjsing
147cbcdaa48Sreyk return (len);
148cbcdaa48Sreyk }
149cbcdaa48Sreyk
150cbcdaa48Sreyk uint8_t *
tls_load_file(const char * name,size_t * len,char * password)151cbcdaa48Sreyk tls_load_file(const char *name, size_t *len, char *password)
152cbcdaa48Sreyk {
153cbcdaa48Sreyk FILE *fp;
154cbcdaa48Sreyk EVP_PKEY *key = NULL;
155cbcdaa48Sreyk BIO *bio = NULL;
156b97593a4Sbcook char *data;
157b97593a4Sbcook uint8_t *buf = NULL;
158cbcdaa48Sreyk struct stat st;
15954356a5dSjsing size_t size = 0;
160cbcdaa48Sreyk int fd = -1;
161dad7bfe2Sjsing ssize_t n;
162cbcdaa48Sreyk
163cbcdaa48Sreyk *len = 0;
164cbcdaa48Sreyk
165cbcdaa48Sreyk if ((fd = open(name, O_RDONLY)) == -1)
166cbcdaa48Sreyk return (NULL);
167cbcdaa48Sreyk
168cbcdaa48Sreyk /* Just load the file into memory without decryption */
169cbcdaa48Sreyk if (password == NULL) {
170cbcdaa48Sreyk if (fstat(fd, &st) != 0)
1717add217bSjsing goto err;
172dad7bfe2Sjsing if (st.st_size < 0)
1737add217bSjsing goto err;
174dad7bfe2Sjsing size = (size_t)st.st_size;
175dad7bfe2Sjsing if ((buf = malloc(size)) == NULL)
1767add217bSjsing goto err;
177dad7bfe2Sjsing n = read(fd, buf, size);
178dad7bfe2Sjsing if (n < 0 || (size_t)n != size)
1797add217bSjsing goto err;
180cbcdaa48Sreyk close(fd);
181cbcdaa48Sreyk goto done;
182cbcdaa48Sreyk }
183cbcdaa48Sreyk
184cbcdaa48Sreyk /* Or read the (possibly) encrypted key from file */
185cbcdaa48Sreyk if ((fp = fdopen(fd, "r")) == NULL)
1867add217bSjsing goto err;
187cbcdaa48Sreyk fd = -1;
188cbcdaa48Sreyk
189cbcdaa48Sreyk key = PEM_read_PrivateKey(fp, NULL, tls_password_cb, password);
190cbcdaa48Sreyk fclose(fp);
191cbcdaa48Sreyk if (key == NULL)
1927add217bSjsing goto err;
193cbcdaa48Sreyk
194cbcdaa48Sreyk /* Write unencrypted key to memory buffer */
195cbcdaa48Sreyk if ((bio = BIO_new(BIO_s_mem())) == NULL)
1967add217bSjsing goto err;
197cbcdaa48Sreyk if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL))
1987add217bSjsing goto err;
199cbcdaa48Sreyk if ((size = BIO_get_mem_data(bio, &data)) <= 0)
2007add217bSjsing goto err;
20154356a5dSjsing if ((buf = malloc(size)) == NULL)
2027add217bSjsing goto err;
203cbcdaa48Sreyk memcpy(buf, data, size);
204cbcdaa48Sreyk
205cbcdaa48Sreyk BIO_free_all(bio);
206cbcdaa48Sreyk EVP_PKEY_free(key);
207cbcdaa48Sreyk
208cbcdaa48Sreyk done:
209cbcdaa48Sreyk *len = size;
210cbcdaa48Sreyk return (buf);
211cbcdaa48Sreyk
2127add217bSjsing err:
213cbcdaa48Sreyk if (fd != -1)
214cbcdaa48Sreyk close(fd);
21554356a5dSjsing freezero(buf, size);
216cbcdaa48Sreyk BIO_free_all(bio);
217cbcdaa48Sreyk EVP_PKEY_free(key);
218cbcdaa48Sreyk
219cbcdaa48Sreyk return (NULL);
220cbcdaa48Sreyk }
221028ca023Sjsing
222028ca023Sjsing void
tls_unload_file(uint8_t * buf,size_t len)223028ca023Sjsing tls_unload_file(uint8_t *buf, size_t len)
224028ca023Sjsing {
225028ca023Sjsing freezero(buf, len);
226028ca023Sjsing }
227