xref: /openbsd-src/usr.sbin/smtpd/ssl.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: ssl.c,v 1.45 2012/01/29 11:37:32 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5  * Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/queue.h>
22 #include <sys/tree.h>
23 #include <sys/param.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 <pwd.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 
37 #include <openssl/ssl.h>
38 #include <openssl/engine.h>
39 #include <openssl/err.h>
40 
41 #include "smtpd.h"
42 #include "log.h"
43 
44 #define SSL_CIPHERS	"HIGH"
45 
46 void	 ssl_error(const char *);
47 char	*ssl_load_file(const char *, off_t *);
48 SSL_CTX	*ssl_ctx_create(void);
49 
50 SSL	*ssl_client_init(int, char *, size_t, char *, size_t);
51 
52 DH	*get_dh1024(void);
53 DH	*get_dh_from_memory(char *, size_t);
54 void	 ssl_set_ephemeral_key_exchange(SSL_CTX *, DH *);
55 
56 extern int ssl_ctx_load_verify_memory(SSL_CTX *, char *, off_t);
57 
58 int
59 ssl_cmp(struct ssl *s1, struct ssl *s2)
60 {
61 	return (strcmp(s1->ssl_name, s2->ssl_name));
62 }
63 
64 SPLAY_GENERATE(ssltree, ssl, ssl_nodes, ssl_cmp);
65 
66 char *
67 ssl_load_file(const char *name, off_t *len)
68 {
69 	struct stat	 st;
70 	off_t		 size;
71 	char		*buf = NULL;
72 	int		 fd;
73 
74 	if ((fd = open(name, O_RDONLY)) == -1)
75 		return (NULL);
76 	if (fstat(fd, &st) != 0)
77 		goto fail;
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 	if (buf != NULL)
90 		free(buf);
91 	close(fd);
92 	return (NULL);
93 }
94 
95 SSL_CTX *
96 ssl_ctx_create(void)
97 {
98 	SSL_CTX	*ctx;
99 
100 	ctx = SSL_CTX_new(SSLv23_method());
101 	if (ctx == NULL) {
102 		ssl_error("ssl_ctx_create");
103 		fatal("ssl_ctx_create: could not create SSL context");
104 	}
105 
106 	SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
107 	SSL_CTX_set_timeout(ctx, SMTPD_SESSION_TIMEOUT);
108 	SSL_CTX_set_options(ctx,
109 	    SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET);
110 	SSL_CTX_set_options(ctx,
111 	    SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
112 
113 	if (!SSL_CTX_set_cipher_list(ctx, SSL_CIPHERS)) {
114 		ssl_error("ssl_ctx_create");
115 		fatal("ssl_ctx_create: could not set cipher list");
116 	}
117 
118 	return (ctx);
119 }
120 
121 int
122 ssl_load_certfile(const char *name, u_int8_t flags)
123 {
124 	struct ssl	*s;
125 	struct ssl	 key;
126 	char		 certfile[PATH_MAX];
127 
128 	if (strlcpy(key.ssl_name, name, sizeof(key.ssl_name))
129 	    >= sizeof(key.ssl_name)) {
130 		log_warn("ssl_load_certfile: certificate name truncated");
131 		return -1;
132 	}
133 
134 	s = SPLAY_FIND(ssltree, env->sc_ssl, &key);
135 	if (s != NULL) {
136 		s->flags |= flags;
137 		return 0;
138 	}
139 
140 	if ((s = calloc(1, sizeof(*s))) == NULL)
141 		fatal(NULL);
142 
143 	s->flags = flags;
144 	(void)strlcpy(s->ssl_name, key.ssl_name, sizeof(s->ssl_name));
145 
146 	if (! bsnprintf(certfile, sizeof(certfile),
147 		"/etc/mail/certs/%s.crt", name))
148 		goto err;
149 
150 	if ((s->ssl_cert = ssl_load_file(certfile, &s->ssl_cert_len)) == NULL)
151 		goto err;
152 
153 	if (! bsnprintf(certfile, sizeof(certfile),
154 		"/etc/mail/certs/%s.key", name))
155 		goto err;
156 
157 	if ((s->ssl_key = ssl_load_file(certfile, &s->ssl_key_len)) == NULL)
158 		goto err;
159 
160 	if (! bsnprintf(certfile, sizeof(certfile),
161 		"/etc/mail/certs/%s.ca", name))
162 		goto err;
163 
164 	if ((s->ssl_ca = ssl_load_file(certfile,
165 		    &s->ssl_ca_len)) == NULL) {
166 		log_info("no CA found in %s", certfile);
167 	}
168 
169 	if (! bsnprintf(certfile, sizeof(certfile),
170 		"/etc/mail/certs/%s.dh", name))
171 		goto err;
172 
173 	if ((s->ssl_dhparams = ssl_load_file(certfile,
174 		    &s->ssl_dhparams_len)) == NULL) {
175 		log_info("no DH parameters found in %s", certfile);
176 		log_info("using built-in DH parameters");
177 	}
178 
179 	SPLAY_INSERT(ssltree, env->sc_ssl, s);
180 
181 	return (0);
182 err:
183 	if (s->ssl_cert != NULL)
184 		free(s->ssl_cert);
185 	if (s->ssl_key != NULL)
186 		free(s->ssl_key);
187 	if (s->ssl_dhparams != NULL)
188 		free(s->ssl_dhparams);
189 	if (s != NULL)
190 		free(s);
191 	return (-1);
192 }
193 
194 void
195 ssl_init(void)
196 {
197 	SSL_library_init();
198 	SSL_load_error_strings();
199 
200 	OpenSSL_add_all_algorithms();
201 
202 	/* Init hardware crypto engines. */
203 	ENGINE_load_builtin_engines();
204 	ENGINE_register_all_complete();
205 }
206 
207 void
208 ssl_setup(struct listener *l)
209 {
210 	struct ssl	key;
211 	DH *dh;
212 
213 	if (!(l->flags & F_SSL))
214 		return;
215 
216 	if (strlcpy(key.ssl_name, l->ssl_cert_name, sizeof(key.ssl_name))
217 	    >= sizeof(key.ssl_name))
218 		fatal("ssl_setup: certificate name truncated");
219 
220 	if ((l->ssl = SPLAY_FIND(ssltree, env->sc_ssl, &key)) == NULL)
221 		fatal("ssl_setup: certificate tree corrupted");
222 
223 	l->ssl_ctx = ssl_ctx_create();
224 
225 	if (l->ssl->ssl_ca != NULL) {
226 		if (! ssl_ctx_load_verify_memory(l->ssl_ctx,
227 			l->ssl->ssl_ca, l->ssl->ssl_ca_len))
228 			goto err;
229 	}
230 
231 	if (!ssl_ctx_use_certificate_chain(l->ssl_ctx,
232 	    l->ssl->ssl_cert, l->ssl->ssl_cert_len))
233 		goto err;
234 	if (!ssl_ctx_use_private_key(l->ssl_ctx,
235 	    l->ssl->ssl_key, l->ssl->ssl_key_len))
236 		goto err;
237 
238 	if (!SSL_CTX_check_private_key(l->ssl_ctx))
239 		goto err;
240 	if (!SSL_CTX_set_session_id_context(l->ssl_ctx,
241 		(const unsigned char *)l->ssl_cert_name,
242 		strlen(l->ssl_cert_name) + 1))
243 		goto err;
244 
245 	if (l->ssl->ssl_dhparams_len == 0)
246 		dh = get_dh1024();
247 	else
248 		dh = get_dh_from_memory(l->ssl->ssl_dhparams,
249 		    l->ssl->ssl_dhparams_len);
250 	ssl_set_ephemeral_key_exchange(l->ssl_ctx, dh);
251 	DH_free(dh);
252 
253 	log_debug("ssl_setup: ssl setup finished for listener: %p", l);
254 	return;
255 
256 err:
257 	if (l->ssl_ctx != NULL)
258 		SSL_CTX_free(l->ssl_ctx);
259 	ssl_error("ssl_setup");
260 	fatal("ssl_setup: cannot set SSL up");
261 	return;
262 }
263 
264 void
265 ssl_error(const char *where)
266 {
267 	unsigned long	code;
268 	char		errbuf[128];
269 	extern int	debug;
270 
271 	if (!debug)
272 		return;
273 	for (; (code = ERR_get_error()) != 0 ;) {
274 		ERR_error_string_n(code, errbuf, sizeof(errbuf));
275 		log_debug("SSL library error: %s: %s", where, errbuf);
276 	}
277 }
278 
279 SSL *
280 ssl_client_init(int fd, char *cert, size_t certsz, char *key, size_t keysz)
281 {
282 	SSL_CTX		*ctx;
283 	SSL		*ssl = NULL;
284 	int		 rv = -1;
285 
286 	ctx = ssl_ctx_create();
287 
288 	if (cert && key) {
289 		if (!ssl_ctx_use_certificate_chain(ctx, cert, certsz))
290 			goto done;
291 		else if (!ssl_ctx_use_private_key(ctx, key, keysz))
292 			goto done;
293 		else if (!SSL_CTX_check_private_key(ctx))
294 			goto done;
295 	}
296 
297 	if ((ssl = SSL_new(ctx)) == NULL)
298 		goto done;
299 	SSL_CTX_free(ctx);
300 
301 	if (!SSL_set_ssl_method(ssl, SSLv23_client_method()))
302 		goto done;
303 	if (!SSL_set_fd(ssl, fd))
304 		goto done;
305 	SSL_set_connect_state(ssl);
306 
307 	rv = 0;
308 done:
309 	if (rv) {
310 		if (ssl)
311 			SSL_free(ssl);
312 		else if (ctx)
313 			SSL_CTX_free(ctx);
314 		ssl = NULL;
315 	}
316 	return (ssl);
317 }
318 
319 void *
320 ssl_mta_init(struct ssl *s)
321 {
322 	SSL_CTX		*ctx;
323 	SSL		*ssl = NULL;
324 	int		 rv = -1;
325 
326 	ctx = ssl_ctx_create();
327 
328 	if (s && s->ssl_cert && s->ssl_key) {
329 		if (!ssl_ctx_use_certificate_chain(ctx,
330 		    s->ssl_cert, s->ssl_cert_len))
331 			goto done;
332 		else if (!ssl_ctx_use_private_key(ctx,
333 		    s->ssl_key, s->ssl_key_len))
334 			goto done;
335 		else if (!SSL_CTX_check_private_key(ctx))
336 			goto done;
337 	}
338 
339 	if ((ssl = SSL_new(ctx)) == NULL)
340 		goto done;
341 	SSL_CTX_free(ctx);
342 
343 	if (!SSL_set_ssl_method(ssl, SSLv23_client_method()))
344 		goto done;
345 
346 	rv = 0;
347 done:
348 	if (rv) {
349 		if (ssl)
350 			SSL_free(ssl);
351 		else if (ctx)
352 			SSL_CTX_free(ctx);
353 		ssl = NULL;
354 	}
355 	return (void*)(ssl);
356 }
357 
358 void
359 ssl_session_init(struct session *s)
360 {
361 	struct listener	*l;
362 	SSL            	*ssl;
363 
364 	l = s->s_l;
365 
366         log_debug("session_start_ssl: switching to SSL");
367 
368         ssl = SSL_new(l->ssl_ctx);
369         if (ssl == NULL)
370                 goto err;
371 
372         if (!SSL_set_ssl_method(ssl, SSLv23_server_method()))
373                 goto err;
374 
375         s->s_ssl = ssl;
376         return;
377 
378     err:
379 	if (ssl != NULL)
380 		SSL_free(ssl);
381 	ssl_error("ssl_session_init");
382 }
383 
384 
385 /* From OpenSSL's documentation:
386  *
387  * If "strong" primes were used to generate the DH parameters, it is
388  * not strictly necessary to generate a new key for each handshake
389  * but it does improve forward secrecy.
390  *
391  * -- gilles@
392  */
393 DH *
394 get_dh1024(void)
395 {
396 	DH *dh;
397 	unsigned char dh1024_p[] = {
398 		0xAD,0x37,0xBB,0x26,0x75,0x01,0x27,0x75,
399 		0x06,0xB5,0xE7,0x1E,0x1F,0x2B,0xBC,0x51,
400 		0xC0,0xF4,0xEB,0x42,0x7A,0x2A,0x83,0x1E,
401 		0xE8,0xD1,0xD8,0xCC,0x9E,0xE6,0x15,0x1D,
402 		0x06,0x46,0x50,0x94,0xB9,0xEE,0xB6,0x89,
403 		0xB7,0x3C,0xAC,0x07,0x5E,0x29,0x37,0xCC,
404 		0x8F,0xDF,0x48,0x56,0x85,0x83,0x26,0x02,
405 		0xB8,0xB6,0x63,0xAF,0x2D,0x4A,0x57,0x93,
406 		0x6B,0x54,0xE1,0x8F,0x28,0x76,0x9C,0x5D,
407 		0x90,0x65,0xD1,0x07,0xFE,0x5B,0x05,0x65,
408 		0xDA,0xD2,0xE2,0xAF,0x23,0xCA,0x2F,0xD6,
409 		0x4B,0xD2,0x04,0xFE,0xDF,0x21,0x2A,0xE1,
410 		0xCD,0x1B,0x70,0x76,0xB3,0x51,0xA4,0xC9,
411 		0x2B,0x68,0xE3,0xDD,0xCB,0x97,0xDA,0x59,
412 		0x50,0x93,0xEE,0xDB,0xBF,0xC7,0xFA,0xA7,
413 		0x47,0xC4,0x4D,0xF0,0xC6,0x09,0x4A,0x4B
414 	};
415 	unsigned char dh1024_g[] = {
416 		0x02
417 	};
418 
419         if ((dh = DH_new()) == NULL)
420 		return NULL;
421 
422         dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
423         dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
424         if (dh->p == NULL || dh->g == NULL) {
425 		DH_free(dh);
426 		return NULL;
427 	}
428 
429         return dh;
430 }
431 
432 DH *
433 get_dh_from_memory(char *params, size_t len)
434 {
435 	BIO *mem;
436         DH *dh;
437 
438 	mem = BIO_new_mem_buf(params, len);
439 	if (mem == NULL)
440 		return NULL;
441 	dh = PEM_read_bio_DHparams(mem, NULL, NULL, NULL);
442 	if (dh == NULL)
443 		goto err;
444         if (dh->p == NULL || dh->g == NULL)
445 		goto err;
446 	return dh;
447 
448 err:
449 	if (mem != NULL)
450 		BIO_free(mem);
451 	if (dh != NULL)
452 		DH_free(dh);
453 	return NULL;
454 }
455 
456 
457 void
458 ssl_set_ephemeral_key_exchange(SSL_CTX *ctx, DH *dh)
459 {
460 	if (dh == NULL || !SSL_CTX_set_tmp_dh(ctx, dh)) {
461 		ssl_error("ssl_set_ephemeral_key_exchange");
462 		fatal("ssl_set_ephemeral_key_exchange: cannot set tmp dh");
463 	}
464 }
465