xref: /openbsd/usr.sbin/smtpd/ssl.c (revision 771fbea0)
1 /*	$OpenBSD: ssl.c,v 1.95 2021/05/26 07:05:50 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5  * Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
6  * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/queue.h>
23 #include <sys/tree.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 
27 #include <ctype.h>
28 #include <event.h>
29 #include <fcntl.h>
30 #include <imsg.h>
31 #include <limits.h>
32 #include <pwd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include <openssl/ssl.h>
39 #include <openssl/engine.h>
40 #include <openssl/err.h>
41 #include <openssl/rsa.h>
42 #include <openssl/ecdsa.h>
43 #include <openssl/dh.h>
44 #include <openssl/bn.h>
45 
46 #include "log.h"
47 #include "ssl.h"
48 
49 void
50 ssl_init(void)
51 {
52 	static int	inited = 0;
53 
54 	if (inited)
55 		return;
56 
57 	SSL_library_init();
58 	SSL_load_error_strings();
59 
60 	OpenSSL_add_all_algorithms();
61 
62 	/* Init hardware crypto engines. */
63 	ENGINE_load_builtin_engines();
64 	ENGINE_register_all_complete();
65 	inited = 1;
66 }
67 
68 static char *
69 ssl_load_file(const char *name, off_t *len, mode_t perm)
70 {
71 	struct stat	 st;
72 	off_t		 size;
73 	char		*buf = NULL;
74 	int		 fd, saved_errno;
75 	char		 mode[12];
76 
77 	if ((fd = open(name, O_RDONLY)) == -1)
78 		return (NULL);
79 	if (fstat(fd, &st) != 0)
80 		goto fail;
81 	if (st.st_uid != 0) {
82 		log_warnx("warn:  %s: not owned by uid 0", name);
83 		errno = EACCES;
84 		goto fail;
85 	}
86 	if (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO) & ~perm) {
87 		strmode(perm, mode);
88 		log_warnx("warn:  %s: insecure permissions: must be at most %s",
89 		    name, &mode[1]);
90 		errno = EACCES;
91 		goto fail;
92 	}
93 	size = st.st_size;
94 	if ((buf = calloc(1, size + 1)) == NULL)
95 		goto fail;
96 	if (read(fd, buf, size) != size)
97 		goto fail;
98 	close(fd);
99 
100 	*len = size + 1;
101 	return (buf);
102 
103 fail:
104 	free(buf);
105 	saved_errno = errno;
106 	close(fd);
107 	errno = saved_errno;
108 	return (NULL);
109 }
110 
111 #if 0
112 static int
113 ssl_password_cb(char *buf, int size, int rwflag, void *u)
114 {
115 	size_t	len;
116 	if (u == NULL) {
117 		explicit_bzero(buf, size);
118 		return (0);
119 	}
120 	if ((len = strlcpy(buf, u, size)) >= (size_t)size)
121 		return (0);
122 	return (len);
123 }
124 #endif
125 
126 static int
127 ssl_password_cb(char *buf, int size, int rwflag, void *u)
128 {
129 	int	ret = 0;
130 	size_t	len;
131 	char	*pass;
132 
133 	pass = getpass((const char *)u);
134 	if (pass == NULL)
135 		return 0;
136 	len = strlen(pass);
137 	if (strlcpy(buf, pass, size) >= (size_t)size)
138 		goto end;
139 	ret = len;
140 end:
141 	if (len)
142 		explicit_bzero(pass, len);
143 	return ret;
144 }
145 
146 static char *
147 ssl_load_key(const char *name, off_t *len, char *pass, mode_t perm, const char *pkiname)
148 {
149 	FILE		*fp = NULL;
150 	EVP_PKEY	*key = NULL;
151 	BIO		*bio = NULL;
152 	long		 size;
153 	char		*data, *buf, *filebuf;
154 	struct stat	 st;
155 	char		 mode[12];
156 	char		 prompt[2048];
157 
158 	/* Initialize SSL library once */
159 	ssl_init();
160 
161 	/*
162 	 * Read (possibly) encrypted key from file
163 	 */
164 	if ((fp = fopen(name, "r")) == NULL)
165 		return (NULL);
166 	if ((filebuf = malloc_conceal(BUFSIZ)) == NULL)
167 		goto fail;
168 	setvbuf(fp, filebuf, _IOFBF, BUFSIZ);
169 
170 	if (fstat(fileno(fp), &st) != 0)
171 		goto fail;
172 	if (st.st_uid != 0) {
173 		log_warnx("warn:  %s: not owned by uid 0", name);
174 		errno = EACCES;
175 		goto fail;
176 	}
177 	if (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO) & ~perm) {
178 		strmode(perm, mode);
179 		log_warnx("warn:  %s: insecure permissions: must be at most %s",
180 		    name, &mode[1]);
181 		errno = EACCES;
182 		goto fail;
183 	}
184 
185 	(void)snprintf(prompt, sizeof prompt, "passphrase for %s: ", pkiname);
186 	key = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, prompt);
187 	fclose(fp);
188 	fp = NULL;
189 	freezero(filebuf, BUFSIZ);
190 	filebuf = NULL;
191 	if (key == NULL)
192 		goto fail;
193 	/*
194 	 * Write unencrypted key to memory buffer
195 	 */
196 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
197 		goto fail;
198 	if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL))
199 		goto fail;
200 	if ((size = BIO_get_mem_data(bio, &data)) <= 0)
201 		goto fail;
202 	if ((buf = calloc_conceal(1, size + 1)) == NULL)
203 		goto fail;
204 	memcpy(buf, data, size);
205 
206 	BIO_free_all(bio);
207 	EVP_PKEY_free(key);
208 
209 	*len = (off_t)size + 1;
210 	return (buf);
211 
212 fail:
213 	ssl_error("ssl_load_key");
214 	BIO_free_all(bio);
215 	EVP_PKEY_free(key);
216 	if (fp)
217 		fclose(fp);
218 	freezero(filebuf, BUFSIZ);
219 	return (NULL);
220 }
221 
222 int
223 ssl_load_certificate(struct pki *p, const char *pathname)
224 {
225 	p->pki_cert = ssl_load_file(pathname, &p->pki_cert_len, 0755);
226 	if (p->pki_cert == NULL)
227 		return 0;
228 	return 1;
229 }
230 
231 int
232 ssl_load_keyfile(struct pki *p, const char *pathname, const char *pkiname)
233 {
234 	char	pass[1024];
235 
236 	p->pki_key = ssl_load_key(pathname, &p->pki_key_len, pass, 0740, pkiname);
237 	if (p->pki_key == NULL)
238 		return 0;
239 	return 1;
240 }
241 
242 int
243 ssl_load_cafile(struct ca *c, const char *pathname)
244 {
245 	c->ca_cert = ssl_load_file(pathname, &c->ca_cert_len, 0755);
246 	if (c->ca_cert == NULL)
247 		return 0;
248 	return 1;
249 }
250 
251 void
252 ssl_error(const char *where)
253 {
254 	unsigned long	code;
255 	char		errbuf[128];
256 
257 	for (; (code = ERR_get_error()) != 0 ;) {
258 		ERR_error_string_n(code, errbuf, sizeof(errbuf));
259 		log_debug("debug: SSL library error: %s: %s", where, errbuf);
260 	}
261 }
262 
263 static void
264 hash_x509(X509 *cert, char *hash, size_t hashlen)
265 {
266 	static const char	hex[] = "0123456789abcdef";
267 	size_t			off;
268 	char			digest[EVP_MAX_MD_SIZE];
269 	int		 	dlen, i;
270 
271 	if (X509_pubkey_digest(cert, EVP_sha256(), digest, &dlen) != 1)
272 		fatalx("%s: X509_pubkey_digest failed", __func__);
273 
274 	if (hashlen < 2 * dlen + sizeof("SHA256:"))
275 		fatalx("%s: hash buffer to small", __func__);
276 
277 	off = strlcpy(hash, "SHA256:", hashlen);
278 
279 	for (i = 0; i < dlen; i++) {
280 		hash[off++] = hex[(digest[i] >> 4) & 0x0f];
281 		hash[off++] = hex[digest[i] & 0x0f];
282 	}
283 	hash[off] = 0;
284 }
285 
286 char *
287 ssl_pubkey_hash(const char *buf, off_t len)
288 {
289 #define TLS_CERT_HASH_SIZE	128
290 	BIO		*in;
291 	X509		*x509 = NULL;
292 	char		*hash = NULL;
293 
294 	if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
295 		log_warnx("%s: BIO_new_mem_buf failed", __func__);
296 		return NULL;
297 	}
298 
299 	if ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL)) == NULL) {
300 		log_warnx("%s: PEM_read_bio_X509 failed", __func__);
301 		goto fail;
302 	}
303 
304 	if ((hash = malloc(TLS_CERT_HASH_SIZE)) == NULL) {
305 		log_warn("%s: malloc", __func__);
306 		goto fail;
307 	}
308 	hash_x509(x509, hash, TLS_CERT_HASH_SIZE);
309 
310 fail:
311 	BIO_free(in);
312 
313 	if (x509)
314 		X509_free(x509);
315 
316 	return hash;
317 }
318