xref: /openbsd-src/usr.sbin/smtpd/ssl.c (revision 5a38ef86d0b61900239c7913d24a05e7b88a58f0)
1 /*	$OpenBSD: ssl.c,v 1.96 2021/06/14 17:58:16 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/stat.h>
22 
23 #include <fcntl.h>
24 #include <limits.h>
25 #include <openssl/engine.h>
26 #include <openssl/err.h>
27 #include <openssl/ssl.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include "log.h"
32 #include "ssl.h"
33 
34 void
35 ssl_init(void)
36 {
37 	static int	inited = 0;
38 
39 	if (inited)
40 		return;
41 
42 	SSL_library_init();
43 	SSL_load_error_strings();
44 
45 	OpenSSL_add_all_algorithms();
46 
47 	/* Init hardware crypto engines. */
48 	ENGINE_load_builtin_engines();
49 	ENGINE_register_all_complete();
50 	inited = 1;
51 }
52 
53 static char *
54 ssl_load_file(const char *name, off_t *len, mode_t perm)
55 {
56 	struct stat	 st;
57 	off_t		 size;
58 	char		*buf = NULL;
59 	int		 fd, saved_errno;
60 	char		 mode[12];
61 
62 	if ((fd = open(name, O_RDONLY)) == -1)
63 		return (NULL);
64 	if (fstat(fd, &st) != 0)
65 		goto fail;
66 	if (st.st_uid != 0) {
67 		log_warnx("warn:  %s: not owned by uid 0", name);
68 		errno = EACCES;
69 		goto fail;
70 	}
71 	if (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO) & ~perm) {
72 		strmode(perm, mode);
73 		log_warnx("warn:  %s: insecure permissions: must be at most %s",
74 		    name, &mode[1]);
75 		errno = EACCES;
76 		goto fail;
77 	}
78 	size = st.st_size;
79 	if ((buf = calloc(1, size + 1)) == NULL)
80 		goto fail;
81 	if (read(fd, buf, size) != size)
82 		goto fail;
83 	close(fd);
84 
85 	*len = size + 1;
86 	return (buf);
87 
88 fail:
89 	free(buf);
90 	saved_errno = errno;
91 	close(fd);
92 	errno = saved_errno;
93 	return (NULL);
94 }
95 
96 #if 0
97 static int
98 ssl_password_cb(char *buf, int size, int rwflag, void *u)
99 {
100 	size_t	len;
101 	if (u == NULL) {
102 		explicit_bzero(buf, size);
103 		return (0);
104 	}
105 	if ((len = strlcpy(buf, u, size)) >= (size_t)size)
106 		return (0);
107 	return (len);
108 }
109 #endif
110 
111 static int
112 ssl_password_cb(char *buf, int size, int rwflag, void *u)
113 {
114 	int	ret = 0;
115 	size_t	len;
116 	char	*pass;
117 
118 	pass = getpass((const char *)u);
119 	if (pass == NULL)
120 		return 0;
121 	len = strlen(pass);
122 	if (strlcpy(buf, pass, size) >= (size_t)size)
123 		goto end;
124 	ret = len;
125 end:
126 	if (len)
127 		explicit_bzero(pass, len);
128 	return ret;
129 }
130 
131 static char *
132 ssl_load_key(const char *name, off_t *len, char *pass, mode_t perm, const char *pkiname)
133 {
134 	FILE		*fp = NULL;
135 	EVP_PKEY	*key = NULL;
136 	BIO		*bio = NULL;
137 	long		 size;
138 	char		*data, *buf, *filebuf;
139 	struct stat	 st;
140 	char		 mode[12];
141 	char		 prompt[2048];
142 
143 	/* Initialize SSL library once */
144 	ssl_init();
145 
146 	/*
147 	 * Read (possibly) encrypted key from file
148 	 */
149 	if ((fp = fopen(name, "r")) == NULL)
150 		return (NULL);
151 	if ((filebuf = malloc_conceal(BUFSIZ)) == NULL)
152 		goto fail;
153 	setvbuf(fp, filebuf, _IOFBF, BUFSIZ);
154 
155 	if (fstat(fileno(fp), &st) != 0)
156 		goto fail;
157 	if (st.st_uid != 0) {
158 		log_warnx("warn:  %s: not owned by uid 0", name);
159 		errno = EACCES;
160 		goto fail;
161 	}
162 	if (st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO) & ~perm) {
163 		strmode(perm, mode);
164 		log_warnx("warn:  %s: insecure permissions: must be at most %s",
165 		    name, &mode[1]);
166 		errno = EACCES;
167 		goto fail;
168 	}
169 
170 	(void)snprintf(prompt, sizeof prompt, "passphrase for %s: ", pkiname);
171 	key = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, prompt);
172 	fclose(fp);
173 	fp = NULL;
174 	freezero(filebuf, BUFSIZ);
175 	filebuf = NULL;
176 	if (key == NULL)
177 		goto fail;
178 	/*
179 	 * Write unencrypted key to memory buffer
180 	 */
181 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
182 		goto fail;
183 	if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL))
184 		goto fail;
185 	if ((size = BIO_get_mem_data(bio, &data)) <= 0)
186 		goto fail;
187 	if ((buf = calloc_conceal(1, size + 1)) == NULL)
188 		goto fail;
189 	memcpy(buf, data, size);
190 
191 	BIO_free_all(bio);
192 	EVP_PKEY_free(key);
193 
194 	*len = (off_t)size + 1;
195 	return (buf);
196 
197 fail:
198 	ssl_error("ssl_load_key");
199 	BIO_free_all(bio);
200 	EVP_PKEY_free(key);
201 	if (fp)
202 		fclose(fp);
203 	freezero(filebuf, BUFSIZ);
204 	return (NULL);
205 }
206 
207 int
208 ssl_load_certificate(struct pki *p, const char *pathname)
209 {
210 	p->pki_cert = ssl_load_file(pathname, &p->pki_cert_len, 0755);
211 	if (p->pki_cert == NULL)
212 		return 0;
213 	return 1;
214 }
215 
216 int
217 ssl_load_keyfile(struct pki *p, const char *pathname, const char *pkiname)
218 {
219 	char	pass[1024];
220 
221 	p->pki_key = ssl_load_key(pathname, &p->pki_key_len, pass, 0740, pkiname);
222 	if (p->pki_key == NULL)
223 		return 0;
224 	return 1;
225 }
226 
227 int
228 ssl_load_cafile(struct ca *c, const char *pathname)
229 {
230 	c->ca_cert = ssl_load_file(pathname, &c->ca_cert_len, 0755);
231 	if (c->ca_cert == NULL)
232 		return 0;
233 	return 1;
234 }
235 
236 void
237 ssl_error(const char *where)
238 {
239 	unsigned long	code;
240 	char		errbuf[128];
241 
242 	for (; (code = ERR_get_error()) != 0 ;) {
243 		ERR_error_string_n(code, errbuf, sizeof(errbuf));
244 		log_debug("debug: SSL library error: %s: %s", where, errbuf);
245 	}
246 }
247 
248 static void
249 hash_x509(X509 *cert, char *hash, size_t hashlen)
250 {
251 	static const char	hex[] = "0123456789abcdef";
252 	size_t			off;
253 	char			digest[EVP_MAX_MD_SIZE];
254 	int		 	dlen, i;
255 
256 	if (X509_pubkey_digest(cert, EVP_sha256(), digest, &dlen) != 1)
257 		fatalx("%s: X509_pubkey_digest failed", __func__);
258 
259 	if (hashlen < 2 * dlen + sizeof("SHA256:"))
260 		fatalx("%s: hash buffer to small", __func__);
261 
262 	off = strlcpy(hash, "SHA256:", hashlen);
263 
264 	for (i = 0; i < dlen; i++) {
265 		hash[off++] = hex[(digest[i] >> 4) & 0x0f];
266 		hash[off++] = hex[digest[i] & 0x0f];
267 	}
268 	hash[off] = 0;
269 }
270 
271 char *
272 ssl_pubkey_hash(const char *buf, off_t len)
273 {
274 #define TLS_CERT_HASH_SIZE	128
275 	BIO		*in;
276 	X509		*x509 = NULL;
277 	char		*hash = NULL;
278 
279 	if ((in = BIO_new_mem_buf(buf, len)) == NULL) {
280 		log_warnx("%s: BIO_new_mem_buf failed", __func__);
281 		return NULL;
282 	}
283 
284 	if ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL)) == NULL) {
285 		log_warnx("%s: PEM_read_bio_X509 failed", __func__);
286 		goto fail;
287 	}
288 
289 	if ((hash = malloc(TLS_CERT_HASH_SIZE)) == NULL) {
290 		log_warn("%s: malloc", __func__);
291 		goto fail;
292 	}
293 	hash_x509(x509, hash, TLS_CERT_HASH_SIZE);
294 
295 fail:
296 	BIO_free(in);
297 
298 	if (x509)
299 		X509_free(x509);
300 
301 	return hash;
302 }
303