xref: /dflybsd-src/crypto/libressl/tls/tls_util.c (revision f5b1c8a1e6dbe9333aed363dba27c2ff58be6174)
1*f5b1c8a1SJohn Marino /* $OpenBSD: tls_util.c,v 1.2 2015/02/07 23:25:37 reyk Exp $ */
2*f5b1c8a1SJohn Marino /*
3*f5b1c8a1SJohn Marino  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4*f5b1c8a1SJohn Marino  * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
5*f5b1c8a1SJohn Marino  *
6*f5b1c8a1SJohn Marino  * Permission to use, copy, modify, and distribute this software for any
7*f5b1c8a1SJohn Marino  * purpose with or without fee is hereby granted, provided that the above
8*f5b1c8a1SJohn Marino  * copyright notice and this permission notice appear in all copies.
9*f5b1c8a1SJohn Marino  *
10*f5b1c8a1SJohn Marino  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*f5b1c8a1SJohn Marino  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*f5b1c8a1SJohn Marino  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*f5b1c8a1SJohn Marino  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*f5b1c8a1SJohn Marino  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*f5b1c8a1SJohn Marino  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*f5b1c8a1SJohn Marino  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*f5b1c8a1SJohn Marino  */
18*f5b1c8a1SJohn Marino 
19*f5b1c8a1SJohn Marino #include <sys/stat.h>
20*f5b1c8a1SJohn Marino 
21*f5b1c8a1SJohn Marino #include <stdlib.h>
22*f5b1c8a1SJohn Marino #include <unistd.h>
23*f5b1c8a1SJohn Marino #include <fcntl.h>
24*f5b1c8a1SJohn Marino 
25*f5b1c8a1SJohn Marino #include "tls.h"
26*f5b1c8a1SJohn Marino #include "tls_internal.h"
27*f5b1c8a1SJohn Marino 
28*f5b1c8a1SJohn Marino /*
29*f5b1c8a1SJohn Marino  * Extract the host and port from a colon separated value. For a literal IPv6
30*f5b1c8a1SJohn Marino  * address the address must be contained with square braces. If a host and
31*f5b1c8a1SJohn Marino  * port are successfully extracted, the function will return 0 and the
32*f5b1c8a1SJohn Marino  * caller is responsible for freeing the host and port. If no port is found
33*f5b1c8a1SJohn Marino  * then the function will return 1, with both host and port being NULL.
34*f5b1c8a1SJohn Marino  * On memory allocation failure -1 will be returned.
35*f5b1c8a1SJohn Marino  */
36*f5b1c8a1SJohn Marino int
37*f5b1c8a1SJohn Marino tls_host_port(const char *hostport, char **host, char **port)
38*f5b1c8a1SJohn Marino {
39*f5b1c8a1SJohn Marino 	char *h, *p, *s;
40*f5b1c8a1SJohn Marino 	int rv = 1;
41*f5b1c8a1SJohn Marino 
42*f5b1c8a1SJohn Marino 	*host = NULL;
43*f5b1c8a1SJohn Marino 	*port = NULL;
44*f5b1c8a1SJohn Marino 
45*f5b1c8a1SJohn Marino 	if ((s = strdup(hostport)) == NULL)
46*f5b1c8a1SJohn Marino 		goto fail;
47*f5b1c8a1SJohn Marino 
48*f5b1c8a1SJohn Marino 	h = p = s;
49*f5b1c8a1SJohn Marino 
50*f5b1c8a1SJohn Marino 	/* See if this is an IPv6 literal with square braces. */
51*f5b1c8a1SJohn Marino 	if (p[0] == '[') {
52*f5b1c8a1SJohn Marino 		h++;
53*f5b1c8a1SJohn Marino 		if ((p = strchr(s, ']')) == NULL)
54*f5b1c8a1SJohn Marino 			goto done;
55*f5b1c8a1SJohn Marino 		*p++ = '\0';
56*f5b1c8a1SJohn Marino 	}
57*f5b1c8a1SJohn Marino 
58*f5b1c8a1SJohn Marino 	/* Find the port seperator. */
59*f5b1c8a1SJohn Marino 	if ((p = strchr(p, ':')) == NULL)
60*f5b1c8a1SJohn Marino 		goto done;
61*f5b1c8a1SJohn Marino 
62*f5b1c8a1SJohn Marino 	/* If there is another separator then we have issues. */
63*f5b1c8a1SJohn Marino 	if (strchr(p + 1, ':') != NULL)
64*f5b1c8a1SJohn Marino 		goto done;
65*f5b1c8a1SJohn Marino 
66*f5b1c8a1SJohn Marino 	*p++ = '\0';
67*f5b1c8a1SJohn Marino 
68*f5b1c8a1SJohn Marino 	if (asprintf(host, "%s", h) == -1)
69*f5b1c8a1SJohn Marino 		goto fail;
70*f5b1c8a1SJohn Marino 	if (asprintf(port, "%s", p) == -1)
71*f5b1c8a1SJohn Marino 		goto fail;
72*f5b1c8a1SJohn Marino 
73*f5b1c8a1SJohn Marino 	rv = 0;
74*f5b1c8a1SJohn Marino 	goto done;
75*f5b1c8a1SJohn Marino 
76*f5b1c8a1SJohn Marino  fail:
77*f5b1c8a1SJohn Marino 	free(*host);
78*f5b1c8a1SJohn Marino 	*host = NULL;
79*f5b1c8a1SJohn Marino 	free(*port);
80*f5b1c8a1SJohn Marino 	*port = NULL;
81*f5b1c8a1SJohn Marino 	rv = -1;
82*f5b1c8a1SJohn Marino 
83*f5b1c8a1SJohn Marino  done:
84*f5b1c8a1SJohn Marino 	free(s);
85*f5b1c8a1SJohn Marino 
86*f5b1c8a1SJohn Marino 	return (rv);
87*f5b1c8a1SJohn Marino }
88*f5b1c8a1SJohn Marino 
89*f5b1c8a1SJohn Marino static int
90*f5b1c8a1SJohn Marino tls_password_cb(char *buf, int size, int rwflag, void *u)
91*f5b1c8a1SJohn Marino {
92*f5b1c8a1SJohn Marino 	size_t	len;
93*f5b1c8a1SJohn Marino 	if (u == NULL) {
94*f5b1c8a1SJohn Marino 		memset(buf, 0, size);
95*f5b1c8a1SJohn Marino 		return (0);
96*f5b1c8a1SJohn Marino 	}
97*f5b1c8a1SJohn Marino 	if ((len = strlcpy(buf, u, size)) >= (size_t)size)
98*f5b1c8a1SJohn Marino 		return (0);
99*f5b1c8a1SJohn Marino 	return (len);
100*f5b1c8a1SJohn Marino }
101*f5b1c8a1SJohn Marino 
102*f5b1c8a1SJohn Marino uint8_t *
103*f5b1c8a1SJohn Marino tls_load_file(const char *name, size_t *len, char *password)
104*f5b1c8a1SJohn Marino {
105*f5b1c8a1SJohn Marino 	FILE *fp;
106*f5b1c8a1SJohn Marino 	EVP_PKEY *key = NULL;
107*f5b1c8a1SJohn Marino 	BIO *bio = NULL;
108*f5b1c8a1SJohn Marino 	char *data, *buf = NULL;
109*f5b1c8a1SJohn Marino 	struct stat st;
110*f5b1c8a1SJohn Marino 	size_t size;
111*f5b1c8a1SJohn Marino 	int fd = -1;
112*f5b1c8a1SJohn Marino 
113*f5b1c8a1SJohn Marino 	*len = 0;
114*f5b1c8a1SJohn Marino 
115*f5b1c8a1SJohn Marino 	if ((fd = open(name, O_RDONLY)) == -1)
116*f5b1c8a1SJohn Marino 		return (NULL);
117*f5b1c8a1SJohn Marino 
118*f5b1c8a1SJohn Marino 	/* Just load the file into memory without decryption */
119*f5b1c8a1SJohn Marino 	if (password == NULL) {
120*f5b1c8a1SJohn Marino 		if (fstat(fd, &st) != 0)
121*f5b1c8a1SJohn Marino 			goto fail;
122*f5b1c8a1SJohn Marino 		size = (size_t)st.st_size;
123*f5b1c8a1SJohn Marino 		if ((buf = calloc(1, size + 1)) == NULL)
124*f5b1c8a1SJohn Marino 			goto fail;
125*f5b1c8a1SJohn Marino 		if (read(fd, buf, size) != size)
126*f5b1c8a1SJohn Marino 			goto fail;
127*f5b1c8a1SJohn Marino 		close(fd);
128*f5b1c8a1SJohn Marino 		goto done;
129*f5b1c8a1SJohn Marino 	}
130*f5b1c8a1SJohn Marino 
131*f5b1c8a1SJohn Marino 	/* Or read the (possibly) encrypted key from file */
132*f5b1c8a1SJohn Marino 	if ((fp = fdopen(fd, "r")) == NULL)
133*f5b1c8a1SJohn Marino 		goto fail;
134*f5b1c8a1SJohn Marino 	fd = -1;
135*f5b1c8a1SJohn Marino 
136*f5b1c8a1SJohn Marino 	key = PEM_read_PrivateKey(fp, NULL, tls_password_cb, password);
137*f5b1c8a1SJohn Marino 	fclose(fp);
138*f5b1c8a1SJohn Marino 	if (key == NULL)
139*f5b1c8a1SJohn Marino 		goto fail;
140*f5b1c8a1SJohn Marino 
141*f5b1c8a1SJohn Marino 	/* Write unencrypted key to memory buffer */
142*f5b1c8a1SJohn Marino 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
143*f5b1c8a1SJohn Marino 		goto fail;
144*f5b1c8a1SJohn Marino 	if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL))
145*f5b1c8a1SJohn Marino 		goto fail;
146*f5b1c8a1SJohn Marino 	if ((size = BIO_get_mem_data(bio, &data)) <= 0)
147*f5b1c8a1SJohn Marino 		goto fail;
148*f5b1c8a1SJohn Marino 	if ((buf = calloc(1, size)) == NULL)
149*f5b1c8a1SJohn Marino 		goto fail;
150*f5b1c8a1SJohn Marino 	memcpy(buf, data, size);
151*f5b1c8a1SJohn Marino 
152*f5b1c8a1SJohn Marino 	BIO_free_all(bio);
153*f5b1c8a1SJohn Marino 	EVP_PKEY_free(key);
154*f5b1c8a1SJohn Marino 
155*f5b1c8a1SJohn Marino  done:
156*f5b1c8a1SJohn Marino 	*len = size;
157*f5b1c8a1SJohn Marino 	return (buf);
158*f5b1c8a1SJohn Marino 
159*f5b1c8a1SJohn Marino  fail:
160*f5b1c8a1SJohn Marino 	free(buf);
161*f5b1c8a1SJohn Marino 	if (fd != -1)
162*f5b1c8a1SJohn Marino 		close(fd);
163*f5b1c8a1SJohn Marino 	if (bio != NULL)
164*f5b1c8a1SJohn Marino 		BIO_free_all(bio);
165*f5b1c8a1SJohn Marino 	if (key != NULL)
166*f5b1c8a1SJohn Marino 		EVP_PKEY_free(key);
167*f5b1c8a1SJohn Marino 
168*f5b1c8a1SJohn Marino 	return (NULL);
169*f5b1c8a1SJohn Marino }
170