makefile: add d(evel)-b(uild) target
[s-mailx.git] / openssl.c
blob00b1c4524c13cebd8152bbd97433449f632cf960
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ OpenSSL functions. TODO this needs an overhaul -- there _are_ stack leaks!?
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
6 */
7 /*
8 * Copyright (c) 2002
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
39 #undef n_FILE
40 #define n_FILE openssl
42 #ifndef HAVE_AMALGAMATION
43 # include "nail.h"
44 #endif
46 EMPTY_FILE()
47 #ifdef HAVE_OPENSSL
48 #include <sys/socket.h>
50 #include <openssl/crypto.h>
51 #include <openssl/err.h>
52 #include <openssl/evp.h>
53 #include <openssl/pem.h>
54 #include <openssl/rand.h>
55 #include <openssl/ssl.h>
56 #include <openssl/x509v3.h>
57 #include <openssl/x509.h>
59 #ifdef HAVE_OPENSSL_CONFIG
60 # include <openssl/conf.h>
61 #endif
63 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
64 # include <dirent.h>
65 #endif
68 * OpenSSL client implementation according to: John Viega, Matt Messier,
69 * Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
72 /* Update manual on changes (for all those)! */
73 #define SSL_DISABLED_PROTOCOLS "-SSLv2"
75 #ifndef HAVE_OPENSSL_CONF_CTX /* TODO obsolete the fallback */
76 # ifndef SSL_OP_NO_SSLv2
77 # define SSL_OP_NO_SSLv2 0
78 # endif
79 # ifndef SSL_OP_NO_SSLv3
80 # define SSL_OP_NO_SSLv3 0
81 # endif
82 # ifndef SSL_OP_NO_TLSv1
83 # define SSL_OP_NO_TLSv1 0
84 # endif
85 # ifndef SSL_OP_NO_TLSv1_1
86 # define SSL_OP_NO_TLSv1_1 0
87 # endif
88 # ifndef SSL_OP_NO_TLSv1_2
89 # define SSL_OP_NO_TLSv1_2 0
90 # endif
92 /* SSL_CONF_CTX and _OP_NO_SSL_MASK were both introduced with 1.0.2!?! */
93 # ifndef SSL_OP_NO_SSL_MASK
94 # define SSL_OP_NO_SSL_MASK \
95 (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |\
96 SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2)
97 # endif
98 #endif
100 #if HAVE_OPENSSL < 10100
101 # define _SSL_CLIENT_METHOD() SSLv23_client_method()
102 #else
103 # define _SSL_CLIENT_METHOD() TLS_client_method()
104 #endif
106 #ifdef HAVE_OPENSSL_STACK_OF
107 # define _STACKOF(X) STACK_OF(X)
108 #else
109 # define _STACKOF(X) /*X*/STACK
110 #endif
112 #if defined OPENSSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER + 0 >= 0x0090581fL
113 # define _RAND_LOAD_FILE_MAXBYTES -1
114 #else
115 # define _RAND_LOAD_FILE_MAXBYTES 1024
116 #endif
118 enum ssl_state {
119 SS_INIT = 1<<0,
120 SS_RAND_INIT = 1<<1,
121 SS_EXIT_HDL = 1<<2,
122 SS_CONF_LOAD = 1<<3,
123 SS_ALGO_LOAD = 1<<4,
125 SS_VERIFY_ERROR = 1<<7
128 /* We go for the OpenSSL v1.0.2+ SSL_CONF_CTX if available even if that means
129 * that the library does internally what we'd otherwise do ourselfs.
130 * Eventually we can drop the direct use cases */
131 enum ssl_conf_type {
132 SCT_CERTIFICATE,
133 SCT_CIPHER_STRING,
134 SCT_PRIVATE_KEY,
135 SCT_OPTIONS,
136 SCT_PROTOCOL
139 struct ssl_method { /* TODO obsolete */
140 char const sm_name[8];
141 char const sm_map[16];
144 #ifndef HAVE_OPENSSL_CONF_CTX /* TODO obsolete the fallback */
145 struct ssl_protocol {
146 char const *sp_name;
147 sl_i sp_flag;
149 #endif
151 struct smime_cipher {
152 char const sc_name[8];
153 EVP_CIPHER const *(*sc_fun)(void);
156 struct smime_digest {
157 char const sd_name[8];
158 EVP_MD const *(*sd_fun)(void);
161 /* Supported SSL/TLS methods: update manual on change! */
163 static struct ssl_method const _ssl_methods[] = { /* TODO obsolete */
164 {"auto", "ALL,-SSLv2"},
165 {"ssl3", "-ALL,SSLv3"},
166 {"tls1", "-ALL,TLSv1"},
167 {"tls1.1", "-ALL,TLSv1.1"},
168 {"tls1.2", "-ALL,TLSv1.2"}
171 /* Update manual on change! */
172 #ifndef HAVE_OPENSSL_CONF_CTX /* TODO obsolete the fallback */
173 static struct ssl_protocol const _ssl_protocols[] = {
174 {"ALL", SSL_OP_NO_SSL_MASK},
175 {"TLSv1.2", SSL_OP_NO_TLSv1_2},
176 {"TLSv1.1", SSL_OP_NO_TLSv1_1},
177 {"TLSv1", SSL_OP_NO_TLSv1},
178 {"SSLv3", SSL_OP_NO_SSLv3},
179 {"SSLv2", 0}
181 #endif
183 /* Supported S/MIME cipher algorithms */
184 static struct smime_cipher const _smime_ciphers[] = { /* Manual!! */
185 #ifndef OPENSSL_NO_AES
186 # define _SMIME_DEFAULT_CIPHER EVP_aes_128_cbc /* According to RFC 5751 */
187 {"aes128", &EVP_aes_128_cbc},
188 {"aes256", &EVP_aes_256_cbc},
189 {"aes192", &EVP_aes_192_cbc},
190 #endif
191 #ifndef OPENSSL_NO_DES
192 # ifndef _SMIME_DEFAULT_CIPHER
193 # define _SMIME_DEFAULT_CIPHER EVP_des_ede3_cbc
194 # endif
195 {"des3", &EVP_des_ede3_cbc},
196 {"des", &EVP_des_cbc},
197 #endif
199 #ifndef _SMIME_DEFAULT_CIPHER
200 # error Your OpenSSL library does not include the necessary
201 # error cipher algorithms that are required to support S/MIME
202 #endif
204 #ifndef OPENSSL_NO_AES
205 static struct smime_cipher const _smime_ciphers_obs[] = { /* TODO obsolete */
206 {"aes-128", &EVP_aes_128_cbc},
207 {"aes-256", &EVP_aes_256_cbc},
208 {"aes-192", &EVP_aes_192_cbc}
210 #endif
212 /* Supported S/MIME message digest algorithms */
213 static struct smime_digest const _smime_digests[] = { /* Manual!! */
214 #define _SMIME_DEFAULT_DIGEST EVP_sha1 /* According to RFC 5751 */
215 #define _SMIME_DEFAULT_DIGEST_S "sha1"
216 {"sha1", &EVP_sha1},
217 {"sha256", &EVP_sha256},
218 {"sha512", &EVP_sha512},
219 {"sha384", &EVP_sha384},
220 {"sha224", &EVP_sha224},
221 #ifndef OPENSSL_NO_MD5
222 {"md5", &EVP_md5},
223 #endif
226 static enum ssl_state _ssl_state;
227 static size_t _ssl_msgno;
229 static bool_t _ssl_rand_init(void);
230 static void _ssl_init(void); /* TODO must return error! */
231 #ifdef HAVE_SSL_ALL_ALGORITHMS
232 static void _ssl_load_algos(void);
233 #endif
234 #if defined HAVE_OPENSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
235 static void _ssl_atexit(void);
236 #endif
238 static bool_t _ssl_parse_asn1_time(ASN1_TIME *atp,
239 char *bdat, size_t blen);
240 static int _ssl_verify_cb(int success, X509_STORE_CTX *store);
242 /* SSL_CTX configuration */
243 static void * _ssl_conf_setup(SSL_CTX *ctxp);
244 static bool_t _ssl_conf(void *confp, enum ssl_conf_type sct,
245 char const *value);
246 static bool_t _ssl_conf_finish(void **confp, bool_t error);
248 static bool_t _ssl_load_verifications(SSL_CTX *ctxp);
250 static enum okay ssl_check_host(struct sock *sp, struct url const *urlp);
252 static int smime_verify(struct message *m, int n, _STACKOF(X509) *chain,
253 X509_STORE *store);
254 static EVP_CIPHER const * _smime_cipher(char const *name);
255 static int ssl_password_cb(char *buf, int size, int rwflag,
256 void *userdata);
257 static FILE * smime_sign_cert(char const *xname, char const *xname2,
258 bool_t dowarn);
259 static char * _smime_sign_include_certs(char const *name);
260 static bool_t _smime_sign_include_chain_creat(_STACKOF(X509) **chain,
261 char const *cfiles);
262 static EVP_MD const * _smime_sign_digest(char const *name,
263 char const **digname);
264 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
265 static enum okay load_crl1(X509_STORE *store, char const *name);
266 #endif
267 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
269 static bool_t
270 _ssl_rand_init(void){
271 char const *cp, *x;
272 bool_t rv;
273 NYD_ENTER;
275 rv = FAL0;
277 /* Shall use some external daemon? */
278 if((cp = ok_vlook(ssl_rand_egd)) != NULL){
279 #ifdef HAVE_OPENSSL_RAND_EGD
280 if((x = file_expand(cp)) != NULL && RAND_egd(cp = x) != -1){
281 rv = TRU1;
282 goto jleave;
284 n_err(_("*ssl_rand_egd* daemon at \"%s\" not available\n"), cp);
285 #else
286 if(options & OPT_D_VV)
287 n_err(_("*ssl_rand_egd* (\"%s\"): unsupported by SSL library\n"), cp);
288 #endif
291 /* Prefer possible user setting */
292 if((cp = ok_vlook(ssl_rand_file)) != NULL){
293 x = NULL;
294 if(*cp != '\0'){
295 if((x = file_expand(cp)) == NULL)
296 n_err(_("*ssl-rand-file*: expansion of \"%s\" failed\n"), cp);
298 cp = x;
301 /* If the SSL PRNG is initialized don't put any more effort in this if the
302 * user defined entropy isn't usable */
303 if(cp == NULL){
304 if(RAND_status()){
305 rv = TRU1;
306 goto jleave;
309 if((cp = RAND_file_name(salloc(PATH_MAX), PATH_MAX)) == NULL){
310 n_err(_("*ssl-rand-file*: no SSL entropy file, can't seed PRNG\n"));
311 goto jleave;
315 if(RAND_load_file(cp, _RAND_LOAD_FILE_MAXBYTES) != -1){
316 for(x = (char*)-1;;){
317 RAND_seed(getrandstring(32), 32);
318 if((rv = (RAND_status() != 0)))
319 break;
320 if((x = (char*)((uintptr_t)x >> 1)) == NULL){
321 n_err(_("*ssl-rand-file*: can't seed SSL PRNG with entropy\n"));
322 goto jleave;
326 if(RAND_write_file(cp) == -1)
327 n_err(_("*ssl-rand-file*: writing entropy to \"%s\" failed\n"), cp);
328 }else
329 n_err(_("*ssl-rand-file*: \"%s\" cannot be loaded\n"), cp);
330 jleave:
331 NYD_LEAVE;
332 return rv;
335 static void
336 _ssl_init(void)
338 #ifdef HAVE_OPENSSL_CONFIG
339 char const *cp;
340 #endif
341 NYD_ENTER;
343 if (!(_ssl_state & SS_INIT)) {
344 SSL_load_error_strings();
345 SSL_library_init();
346 _ssl_state |= SS_INIT;
349 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
350 #ifdef HAVE_OPENSSL_CONFIG
351 if (!(_ssl_state & SS_CONF_LOAD) &&
352 (cp = ok_vlook(ssl_config_file)) != NULL) {
353 ul_i flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
355 if (*cp == '\0') {
356 cp = NULL;
357 flags = 0;
359 if (CONF_modules_load_file(cp, uagent, flags) == 1) {
360 _ssl_state |= SS_CONF_LOAD;
361 if (!(_ssl_state & SS_EXIT_HDL)) {
362 _ssl_state |= SS_EXIT_HDL;
363 atexit(&_ssl_atexit); /* TODO generic program-wide event mech. */
365 } else
366 ssl_gen_err(_("Ignoring CONF_modules_load_file() load error"));
368 #endif
370 if (!(_ssl_state & SS_RAND_INIT) && _ssl_rand_init())
371 _ssl_state |= SS_RAND_INIT;
372 NYD_LEAVE;
375 #ifdef HAVE_SSL_ALL_ALGORITHMS
376 static void
377 _ssl_load_algos(void)
379 NYD_ENTER;
380 if (!(_ssl_state & SS_ALGO_LOAD)) {
381 _ssl_state |= SS_ALGO_LOAD;
382 OpenSSL_add_all_algorithms();
384 if (!(_ssl_state & SS_EXIT_HDL)) {
385 _ssl_state |= SS_EXIT_HDL;
386 atexit(&_ssl_atexit); /* TODO generic program-wide event mech. */
389 NYD_LEAVE;
391 #endif
393 #if defined HAVE_OPENSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
394 static void
395 _ssl_atexit(void)
397 NYD_ENTER;
398 # ifdef HAVE_SSL_ALL_ALGORITHMS
399 if (_ssl_state & SS_ALGO_LOAD)
400 EVP_cleanup();
401 # endif
402 # ifdef HAVE_OPENSSL_CONFIG
403 if (_ssl_state & SS_CONF_LOAD)
404 CONF_modules_free();
405 # endif
406 NYD_LEAVE;
408 #endif
410 static bool_t
411 _ssl_parse_asn1_time(ASN1_TIME *atp, char *bdat, size_t blen)
413 BIO *mbp;
414 char *mcp;
415 long l;
416 NYD_ENTER;
418 mbp = BIO_new(BIO_s_mem());
420 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
421 snprintf(bdat, blen, "%.*s", (int)l, mcp);
422 else {
423 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
424 /*is (int)*/atp->length, (char const*)atp->data);
425 mcp = NULL;
428 BIO_free(mbp);
429 NYD_LEAVE;
430 return (mcp != NULL);
433 static int
434 _ssl_verify_cb(int success, X509_STORE_CTX *store)
436 char data[256];
437 X509 *cert;
438 int rv = TRU1;
439 NYD_ENTER;
441 if (success && !(options & OPT_VERB))
442 goto jleave;
444 if (_ssl_msgno != 0) {
445 n_err(_("Message %lu:\n"), (ul_i)_ssl_msgno);
446 _ssl_msgno = 0;
448 n_err(_(" Certificate depth %d %s\n"),
449 X509_STORE_CTX_get_error_depth(store), (success ? "" : _("ERROR")));
451 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
452 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
453 n_err(_(" subject = %s\n"), data);
455 _ssl_parse_asn1_time(X509_get_notBefore(cert), data, sizeof data);
456 n_err(_(" notBefore = %s\n"), data);
458 _ssl_parse_asn1_time(X509_get_notAfter(cert), data, sizeof data);
459 n_err(_(" notAfter = %s\n"), data);
461 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
462 n_err(_(" issuer = %s\n"), data);
465 if (!success) {
466 int err = X509_STORE_CTX_get_error(store);
468 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
469 _ssl_state |= SS_VERIFY_ERROR;
472 if (!success && ssl_verify_decide() != OKAY)
473 rv = FAL0;
474 jleave:
475 NYD_LEAVE;
476 return rv;
479 #ifdef HAVE_OPENSSL_CONF_CTX
480 static void *
481 _ssl_conf_setup(SSL_CTX *ctxp)
483 SSL_CONF_CTX *sccp;
484 NYD_ENTER;
486 if ((sccp = SSL_CONF_CTX_new()) != NULL) {
487 SSL_CONF_CTX_set_flags(sccp,
488 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
489 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
491 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
492 } else
493 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
495 NYD_LEAVE;
496 return sccp;
499 static bool_t
500 _ssl_conf(void *confp, enum ssl_conf_type sct, char const *value)
502 int rv;
503 char const *cmsg;
504 SSL_CONF_CTX *sccp = (SSL_CONF_CTX*)confp;
505 NYD_ENTER;
507 switch (sct) {
508 case SCT_CERTIFICATE:
509 cmsg = "ssl-cert";
510 rv = SSL_CONF_cmd(sccp, "Certificate", value);
511 break;
512 case SCT_CIPHER_STRING:
513 cmsg = "ssl-cipher-list";
514 rv = SSL_CONF_cmd(sccp, "CipherString", value);
515 break;
516 case SCT_PRIVATE_KEY:
517 cmsg = "ssl-key";
518 rv = SSL_CONF_cmd(sccp, "PrivateKey", value);
519 break;
520 default:
521 case SCT_OPTIONS:
522 cmsg = "ssl-options";
523 rv = SSL_CONF_cmd(sccp, "Options", "Bugs");
524 break;
525 case SCT_PROTOCOL:
526 cmsg = "ssl-protocol";
527 rv = SSL_CONF_cmd(sccp, "Protocol", value);
528 break;
531 if (rv == 2)
532 rv = 0;
533 else {
534 if (rv == 0)
535 ssl_gen_err(_("SSL_CONF_CTX_cmd() failed for *%s*"), cmsg);
536 else
537 n_err(_("%s: *%s* implementation error, please report this\n"),
538 uagent, cmsg);
539 rv = 1;
542 NYD_LEAVE;
543 return (rv == 0);
546 static bool_t
547 _ssl_conf_finish(void **confp, bool_t error)
549 SSL_CONF_CTX **sccp = (SSL_CONF_CTX**)confp;
550 bool_t rv;
551 NYD_ENTER;
553 if (!(rv = error))
554 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
556 SSL_CONF_CTX_free(*sccp);
558 *sccp = NULL;
559 NYD_LEAVE;
560 return rv;
563 #else /* HAVE_OPENSSL_CONF_CTX */
564 static void *
565 _ssl_conf_setup(SSL_CTX* ctxp)
567 return ctxp;
570 static bool_t
571 _ssl_conf(void *confp, enum ssl_conf_type sct, char const *value)
573 SSL_CTX *ctxp = (SSL_CTX*)confp;
574 NYD_ENTER;
576 switch (sct) {
577 case SCT_CERTIFICATE:
578 if (SSL_CTX_use_certificate_chain_file(ctxp, value) != 1) {
579 ssl_gen_err(_("Can't load certificate from file \"%s\"\n"), value);
580 confp = NULL;
582 break;
583 case SCT_CIPHER_STRING:
584 if (SSL_CTX_set_cipher_list(ctxp, value) != 1) {
585 ssl_gen_err(_("Invalid cipher string: \"%s\"\n"), value);
586 confp = NULL;
588 break;
589 case SCT_PRIVATE_KEY:
590 if (SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1) {
591 ssl_gen_err(_("Can't load private key from file \"%s\"\n"), value);
592 confp = NULL;
594 break;
595 case SCT_OPTIONS:
596 /* "Options"="Bugs" TODO *ssl-options* */
597 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
598 break;
599 case SCT_PROTOCOL: {
600 char *iolist, *cp, addin;
601 size_t i;
602 sl_i opts = 0;
604 confp = NULL;
605 for (iolist = cp = savestr(value);
606 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;) {
607 if (*cp == '\0') {
608 n_err(_("*ssl-protocol*: empty arguments are not supported\n"));
609 goto jleave;
612 addin = TRU1;
613 switch (cp[0]) {
614 case '-': addin = FAL0; /* FALLTHRU */
615 case '+': ++cp; /* FALLTHRU */
616 default : break;
619 for (i = 0;;) {
620 if (!asccasecmp(cp, _ssl_protocols[i].sp_name)) {
621 /* We need to inverse the meaning of the _NO_s */
622 if (!addin)
623 opts |= _ssl_protocols[i].sp_flag;
624 else
625 opts &= ~_ssl_protocols[i].sp_flag;
626 break;
628 if (++i < NELEM(_ssl_protocols))
629 continue;
630 n_err(_("*ssl-protocol*: unsupported value \"%s\"\n"), cp);
631 goto jleave;
634 confp = ctxp;
635 SSL_CTX_set_options(ctxp, opts);
636 break;
639 jleave:
640 NYD_LEAVE;
641 return (confp != NULL);
644 static bool_t
645 _ssl_conf_finish(void **confp, bool_t error)
647 UNUSED(confp);
648 UNUSED(error);
649 return TRU1;
651 #endif /* !HAVE_OPENSSL_CONF_CTX */
653 static bool_t
654 _ssl_load_verifications(SSL_CTX *ctxp)
656 char *ca_dir, *ca_file;
657 X509_STORE *store;
658 bool_t rv = FAL0;
659 NYD_ENTER;
661 if (ssl_verify_level == SSL_VERIFY_IGNORE) {
662 rv = TRU1;
663 goto jleave;
666 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
667 ca_dir = file_expand(ca_dir);
668 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
669 ca_file = file_expand(ca_file);
671 if ((ca_dir != NULL || ca_file != NULL) &&
672 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1) {
673 char const *m1, *m2, *m3;
675 if (ca_dir != NULL) {
676 m1 = ca_dir;
677 m2 = (ca_file != NULL) ? _(" or ") : "";
678 } else
679 m1 = m2 = "";
680 m3 = (ca_file != NULL) ? ca_file : "";
681 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
682 goto jleave;
685 if (!ok_blook(ssl_no_default_ca) &&
686 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
687 ssl_gen_err(_("Error loading default CA locations\n"));
688 goto jleave;
691 _ssl_state &= ~SS_VERIFY_ERROR;
692 _ssl_msgno = 0;
693 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
694 store = SSL_CTX_get_cert_store(ctxp);
695 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
697 rv = TRU1;
698 jleave:
699 NYD_LEAVE;
700 return rv;
703 static enum okay
704 ssl_check_host(struct sock *sp, struct url const *urlp)
706 char data[256];
707 X509 *cert;
708 _STACKOF(GENERAL_NAME) *gens;
709 GENERAL_NAME *gen;
710 X509_NAME *subj;
711 enum okay rv = STOP;
712 NYD_ENTER;
714 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
715 n_err(_("No certificate from \"%s\"\n"), urlp->url_h_p.s);
716 goto jleave;
719 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
720 if (gens != NULL) {
721 int i;
723 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
724 gen = sk_GENERAL_NAME_value(gens, i);
725 if (gen->type == GEN_DNS) {
726 if (options & OPT_VERB)
727 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
728 urlp->url_host.s, (char*)gen->d.ia5->data);
729 rv = rfc2595_hostname_match(urlp->url_host.s,
730 (char*)gen->d.ia5->data);
731 if (rv == OKAY)
732 goto jdone;
737 if ((subj = X509_get_subject_name(cert)) != NULL &&
738 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
739 > 0) {
740 data[sizeof data - 1] = '\0';
741 if (options & OPT_VERB)
742 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
743 urlp->url_host.s, data);
744 rv = rfc2595_hostname_match(urlp->url_host.s, data);
747 jdone:
748 X509_free(cert);
749 jleave:
750 NYD_LEAVE;
751 return rv;
754 static int
755 smime_verify(struct message *m, int n, _STACKOF(X509) *chain, X509_STORE *store)
757 char data[LINESIZE], *sender, *to, *cc, *cnttype;
758 int rv, c, i, j;
759 struct message *x;
760 FILE *fp, *ip;
761 off_t size;
762 BIO *fb, *pb;
763 PKCS7 *pkcs7;
764 _STACKOF(X509) *certs;
765 _STACKOF(GENERAL_NAME) *gens;
766 X509 *cert;
767 X509_NAME *subj;
768 GENERAL_NAME *gen;
769 NYD_ENTER;
771 rv = 1;
772 fp = NULL;
773 fb = NULL;
774 _ssl_state &= ~SS_VERIFY_ERROR;
775 _ssl_msgno = (size_t)n;
777 for (;;) {
778 sender = getsender(m);
779 to = hfield1("to", m);
780 cc = hfield1("cc", m);
781 cnttype = hfield1("content-type", m);
783 #undef _X
784 #undef _Y
785 #define _X (sizeof("application/") -1)
786 #define _Y(X) X, sizeof(X) -1
787 if (cnttype && is_asccaseprefix(cnttype, "application/") &&
788 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
789 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
790 #undef _Y
791 #undef _X
792 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
793 goto jleave;
794 if (x != (struct message*)-1) {
795 m = x;
796 continue;
800 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
801 goto jleave;
802 size = m->m_size;
803 break;
806 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
807 NULL) {
808 n_perr(_("tempfile"), 0);
809 goto jleave;
811 while (size-- > 0) {
812 c = getc(ip);
813 putc(c, fp);
815 fflush_rewind(fp);
817 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
818 ssl_gen_err(_(
819 "Error creating BIO verification object for message %d"), n);
820 goto jleave;
823 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
824 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
825 goto jleave;
827 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
828 ssl_gen_err(_("Error verifying message %d"), n);
829 goto jleave;
832 if (sender == NULL) {
833 n_err(_("Warning: Message %d has no sender\n"), n);
834 rv = 0;
835 goto jleave;
838 certs = PKCS7_get0_signers(pkcs7, chain, 0);
839 if (certs == NULL) {
840 n_err(_("No certificates found in message %d\n"), n);
841 goto jleave;
844 for (i = 0; i < sk_X509_num(certs); ++i) {
845 cert = sk_X509_value(certs, i);
846 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
847 if (gens != NULL) {
848 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
849 gen = sk_GENERAL_NAME_value(gens, j);
850 if (gen->type == GEN_EMAIL) {
851 if (options & OPT_VERB)
852 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
853 sender, (char*)gen->d.ia5->data);
854 if (!asccasecmp((char*)gen->d.ia5->data, sender))
855 goto jfound;
860 if ((subj = X509_get_subject_name(cert)) != NULL &&
861 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
862 data, sizeof data) > 0) {
863 data[sizeof data -1] = '\0';
864 if (options & OPT_VERB)
865 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
866 sender, data);
867 if (!asccasecmp(data, sender))
868 goto jfound;
871 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
872 goto jleave;
873 jfound:
874 rv = ((_ssl_state & SS_VERIFY_ERROR) != 0);
875 if (!rv)
876 printf(_("Message %d was verified successfully\n"), n);
877 jleave:
878 if (fb != NULL)
879 BIO_free(fb);
880 if (fp != NULL)
881 Fclose(fp);
882 NYD_LEAVE;
883 return rv;
886 static EVP_CIPHER const *
887 _smime_cipher(char const *name)
889 EVP_CIPHER const *cipher;
890 char *vn;
891 char const *cp;
892 size_t i;
893 NYD_ENTER;
895 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
896 snprintf(vn, (int)i, "smime-cipher-%s", name);
897 cp = vok_vlook(vn);
898 ac_free(vn);
900 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
901 cipher = _SMIME_DEFAULT_CIPHER();
902 goto jleave;
904 cipher = NULL;
906 for (i = 0; i < NELEM(_smime_ciphers); ++i)
907 if (!asccasecmp(_smime_ciphers[i].sc_name, cp)) {
908 cipher = (*_smime_ciphers[i].sc_fun)();
909 goto jleave;
911 #ifndef OPENSSL_NO_AES
912 for (i = 0; i < NELEM(_smime_ciphers_obs); ++i) /* TODO obsolete */
913 if (!asccasecmp(_smime_ciphers_obs[i].sc_name, cp)) {
914 OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
915 cipher = (*_smime_ciphers_obs[i].sc_fun)();
916 goto jleave;
918 #endif
920 /* Not a builtin algorithm, but we may have dynamic support for more */
921 #ifdef HAVE_SSL_ALL_ALGORITHMS
922 _ssl_load_algos();
923 if ((cipher = EVP_get_cipherbyname(cp)) != NULL)
924 goto jleave;
925 #endif
927 n_err(_("Invalid S/MIME cipher(s): \"%s\"\n"), cp);
928 jleave:
929 NYD_LEAVE;
930 return cipher;
933 static int
934 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
936 char *pass;
937 size_t len;
938 NYD_ENTER;
939 UNUSED(rwflag);
940 UNUSED(userdata);
942 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
943 len = strlen(pass);
944 if (UICMP(z, len, >=, size))
945 len = size -1;
946 memcpy(buf, pass, len);
947 buf[len] = '\0';
948 } else
949 len = 0;
950 NYD_LEAVE;
951 return (int)len;
954 static FILE *
955 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn)
957 char *vn, *cp;
958 int vs;
959 struct name *np;
960 char const *name = xname, *name2 = xname2;
961 FILE *fp = NULL;
962 NYD_ENTER;
964 jloop:
965 if (name) {
966 np = lextract(name, GTO | GSKIN);
967 while (np != NULL) {
968 /* This needs to be more intelligent since it will currently take the
969 * first name for which a private key is available regardless of
970 * whether it is the right one for the message */
971 vn = ac_alloc(vs = strlen(np->n_name) + 30);
972 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
973 cp = vok_vlook(vn);
974 ac_free(vn);
975 if (cp != NULL)
976 goto jopen;
977 np = np->n_flink;
979 if (name2 != NULL) {
980 name = name2;
981 name2 = NULL;
982 goto jloop;
986 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
987 goto jerr;
988 jopen:
989 if ((cp = file_expand(cp)) == NULL)
990 goto jleave;
991 if ((fp = Fopen(cp, "r")) == NULL)
992 n_perr(cp, 0);
993 jleave:
994 NYD_LEAVE;
995 return fp;
996 jerr:
997 if (dowarn)
998 n_err(_("Could not find a certificate for %s%s%s\n"),
999 xname, (xname2 != NULL ? _("or ") : ""),
1000 (xname2 != NULL ? xname2 : ""));
1001 goto jleave;
1004 static char *
1005 _smime_sign_include_certs(char const *name)
1007 char *rv;
1008 NYD_ENTER;
1010 /* See comments in smime_sign_cert() for algorithm pitfalls */
1011 if (name != NULL) {
1012 struct name *np;
1014 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1015 int vs;
1016 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1017 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1018 rv = vok_vlook(vn);
1019 ac_free(vn);
1020 if (rv != NULL)
1021 goto jleave;
1024 rv = ok_vlook(smime_sign_include_certs);
1025 jleave:
1026 NYD_LEAVE;
1027 return rv;
1030 static bool_t
1031 _smime_sign_include_chain_creat(_STACKOF(X509) **chain, char const *cfiles)
1033 X509 *tmp;
1034 FILE *fp;
1035 char *nfield, *cfield, *x;
1036 NYD_ENTER;
1038 *chain = sk_X509_new_null();
1040 for (nfield = savestr(cfiles);
1041 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1042 if ((x = file_expand(cfield)) == NULL ||
1043 (fp = Fopen(cfield = x, "r")) == NULL) {
1044 n_perr(cfiles, 0);
1045 goto jerr;
1047 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1048 ssl_gen_err(_("Error reading certificate from \"%s\""), cfield);
1049 Fclose(fp);
1050 goto jerr;
1052 sk_X509_push(*chain, tmp);
1053 Fclose(fp);
1056 if (sk_X509_num(*chain) == 0) {
1057 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1058 goto jerr;
1060 jleave:
1061 NYD_LEAVE;
1062 return (*chain != NULL);
1063 jerr:
1064 sk_X509_pop_free(*chain, X509_free);
1065 *chain = NULL;
1066 goto jleave;
1069 static EVP_MD const *
1070 _smime_sign_digest(char const *name, char const **digname)
1072 EVP_MD const *digest;
1073 char const *cp;
1074 size_t i;
1075 NYD_ENTER;
1077 /* See comments in smime_sign_cert() for algorithm pitfalls */
1078 if (name != NULL) {
1079 struct name *np;
1081 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1082 int vs;
1083 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1084 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1085 cp = vok_vlook(vn);
1086 ac_free(vn);
1087 if (cp != NULL)
1088 goto jhave_name;
1092 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1093 digest = _SMIME_DEFAULT_DIGEST();
1094 *digname = _SMIME_DEFAULT_DIGEST_S;
1095 goto jleave;
1098 jhave_name:
1099 i = strlen(cp);
1100 { char *x = salloc(i +1);
1101 i_strcpy(x, cp, i +1);
1102 cp = x;
1104 *digname = cp;
1106 for (i = 0; i < NELEM(_smime_digests); ++i)
1107 if (!strcmp(_smime_digests[i].sd_name, cp)) {
1108 digest = (*_smime_digests[i].sd_fun)();
1109 goto jleave;
1112 /* Not a builtin algorithm, but we may have dynamic support for more */
1113 #ifdef HAVE_SSL_ALL_ALGORITHMS
1114 _ssl_load_algos();
1115 if ((digest = EVP_get_digestbyname(cp)) != NULL)
1116 goto jleave;
1117 #endif
1119 n_err(_("Invalid message digest: \"%s\"\n"), cp);
1120 digest = NULL;
1121 jleave:
1122 NYD_LEAVE;
1123 return digest;
1126 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1127 static enum okay
1128 load_crl1(X509_STORE *store, char const *name)
1130 X509_LOOKUP *lookup;
1131 enum okay rv = STOP;
1132 NYD_ENTER;
1134 if (options & OPT_VERB)
1135 n_err(_("Loading CRL from \"%s\"\n"), name);
1136 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1137 ssl_gen_err(_("Error creating X509 lookup object"));
1138 goto jleave;
1140 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1141 ssl_gen_err(_("Error loading CRL from \"%s\""), name);
1142 goto jleave;
1144 rv = OKAY;
1145 jleave:
1146 NYD_LEAVE;
1147 return rv;
1149 #endif /* new OpenSSL */
1151 static enum okay
1152 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1154 char *crl_file, *crl_dir;
1155 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1156 DIR *dirp;
1157 struct dirent *dp;
1158 char *fn = NULL;
1159 int fs = 0, ds, es;
1160 #endif
1161 enum okay rv = STOP;
1162 NYD_ENTER;
1164 if ((crl_file = n_var_oklook(fok)) != NULL) {
1165 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1166 if ((crl_file = file_expand(crl_file)) == NULL ||
1167 load_crl1(store, crl_file) != OKAY)
1168 goto jleave;
1169 #else
1170 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1171 goto jleave;
1172 #endif
1175 if ((crl_dir = n_var_oklook(dok)) != NULL) {
1176 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1177 char *x;
1178 if ((x = file_expand(crl_dir)) == NULL ||
1179 (dirp = opendir(crl_dir = x)) == NULL) {
1180 n_perr(crl_dir, 0);
1181 goto jleave;
1184 ds = strlen(crl_dir);
1185 fn = smalloc(fs = ds + 20);
1186 memcpy(fn, crl_dir, ds);
1187 fn[ds] = '/';
1188 while ((dp = readdir(dirp)) != NULL) {
1189 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1190 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1191 continue;
1192 if (dp->d_name[0] == '.')
1193 continue;
1194 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1195 fn = srealloc(fn, fs = ds + es + 20);
1196 memcpy(fn + ds + 1, dp->d_name, es + 1);
1197 if (load_crl1(store, fn) != OKAY) {
1198 closedir(dirp);
1199 free(fn);
1200 goto jleave;
1203 closedir(dirp);
1204 free(fn);
1205 #else /* old OpenSSL */
1206 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1207 goto jleave;
1208 #endif
1210 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1211 if (crl_file || crl_dir)
1212 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1213 X509_V_FLAG_CRL_CHECK_ALL);
1214 #endif
1215 rv = OKAY;
1216 jleave:
1217 NYD_LEAVE;
1218 return rv;
1221 FL enum okay
1222 ssl_open(struct url const *urlp, struct sock *sp)
1224 SSL_CTX *ctxp;
1225 void *confp;
1226 char const *cp, *cp_base;
1227 size_t i;
1228 enum okay rv = STOP;
1229 NYD_ENTER;
1231 _ssl_init();
1233 ssl_set_verify_level(urlp);
1235 if ((ctxp = SSL_CTX_new(_SSL_CLIENT_METHOD())) == NULL) {
1236 ssl_gen_err(_("SSL_CTX_new() failed"));
1237 goto jleave;
1240 /* Available with OpenSSL 0.9.6 or later */
1241 #ifdef SSL_MODE_AUTO_RETRY
1242 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1243 #endif
1245 if ((confp = _ssl_conf_setup(ctxp)) == NULL)
1246 goto jerr0;
1248 /* TODO obsolete Check for *ssl-method*, warp to a *ssl-protocol* value */
1249 if ((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL) {
1250 OBSOLETE(_("please use *ssl-protocol* instead of *ssl-method*"));
1251 if (options & OPT_VERB)
1252 n_err(_("*ssl-method*: \"%s\"\n"), cp);
1253 for (i = 0;;) {
1254 if (!asccasecmp(_ssl_methods[i].sm_name, cp)) {
1255 cp = _ssl_methods[i].sm_map;
1256 break;
1258 if (++i == NELEM(_ssl_methods)) {
1259 n_err(_("Unsupported TLS/SSL method \"%s\"\n"), cp);
1260 goto jerr1;
1264 /* *ssl-protocol* */
1265 if ((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL) {
1266 if (options & OPT_VERB)
1267 n_err(_("*ssl-protocol*: \"%s\"\n"), cp_base);
1268 cp = cp_base;
1270 cp = (cp != NULL ? savecatsep(cp, ',', SSL_DISABLED_PROTOCOLS)
1271 : SSL_DISABLED_PROTOCOLS);
1272 if (!_ssl_conf(confp, SCT_PROTOCOL, cp))
1273 goto jerr1;
1275 /* *ssl-cert* */
1276 if ((cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL) {
1277 if (options & OPT_VERB)
1278 n_err(_("*ssl-cert* \"%s\"\n"), cp);
1279 if ((cp_base = file_expand(cp)) == NULL) {
1280 n_err(_("*ssl-cert* value expansion failed: \"%s\"\n"), cp);
1281 goto jerr1;
1283 cp = cp_base;
1284 if (!_ssl_conf(confp, SCT_CERTIFICATE, cp))
1285 goto jerr1;
1287 /* *ssl-key* */
1288 if ((cp_base = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL) {
1289 if (options & OPT_VERB)
1290 n_err(_("*ssl-key* \"%s\"\n"), cp_base);
1291 if ((cp = file_expand(cp_base)) == NULL) {
1292 n_err(_("*ssl-key* value expansion failed: \"%s\"\n"), cp_base);
1293 goto jerr1;
1296 if (!_ssl_conf(confp, SCT_PRIVATE_KEY, cp))
1297 goto jerr1;
1300 if ((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL &&
1301 !_ssl_conf(confp, SCT_CIPHER_STRING, cp))
1302 goto jerr1;
1304 if (!_ssl_load_verifications(ctxp))
1305 goto jerr1;
1307 if (!_ssl_conf(confp, SCT_OPTIONS, NULL)) /* TODO *ssl-options* */
1308 goto jerr1;
1310 /* Done with context setup, create our new per-connection structure */
1311 if (!_ssl_conf_finish(&confp, FAL0))
1312 goto jerr0;
1314 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1315 ssl_gen_err(_("SSL_new() failed"));
1316 goto jerr0;
1319 SSL_set_fd(sp->s_ssl, sp->s_fd);
1321 if (SSL_connect(sp->s_ssl) < 0) {
1322 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1323 goto jerr2;
1326 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1327 if (ssl_check_host(sp, urlp) != OKAY) {
1328 n_err(_("Host certificate does not match \"%s\"\n"),
1329 urlp->url_h_p.s);
1330 if (ssl_verify_decide() != OKAY)
1331 goto jerr2;
1335 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1336 * and free it right now -- it is reference counted by sp->s_ssl.. */
1337 SSL_CTX_free(ctxp);
1338 sp->s_use_ssl = 1;
1339 rv = OKAY;
1340 jleave:
1341 NYD_LEAVE;
1342 return rv;
1343 jerr2:
1344 SSL_free(sp->s_ssl);
1345 sp->s_ssl = NULL;
1346 jerr1:
1347 if (confp != NULL)
1348 _ssl_conf_finish(&confp, TRU1);
1349 jerr0:
1350 SSL_CTX_free(ctxp);
1351 goto jleave;
1354 FL void
1355 ssl_gen_err(char const *fmt, ...)
1357 va_list ap;
1358 NYD_ENTER;
1360 va_start(ap, fmt);
1361 n_verr(fmt, ap);
1362 va_end(ap);
1364 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1365 NYD_LEAVE;
1368 FL int
1369 c_verify(void *vp)
1371 int *msgvec = vp, *ip, ec = 0, rv = 1;
1372 _STACKOF(X509) *chain = NULL;
1373 X509_STORE *store = NULL;
1374 char *ca_dir, *ca_file;
1375 NYD_ENTER;
1377 _ssl_init();
1379 ssl_verify_level = SSL_VERIFY_STRICT;
1380 if ((store = X509_STORE_new()) == NULL) {
1381 ssl_gen_err(_("Error creating X509 store"));
1382 goto jleave;
1384 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1386 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1387 ca_dir = file_expand(ca_dir);
1388 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1389 ca_file = file_expand(ca_file);
1391 if (ca_dir != NULL || ca_file != NULL) {
1392 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
1393 ssl_gen_err(_("Error loading %s"),
1394 (ca_file != NULL) ? ca_file : ca_dir);
1395 goto jleave;
1398 if (!ok_blook(smime_no_default_ca)) {
1399 if (X509_STORE_set_default_paths(store) != 1) {
1400 ssl_gen_err(_("Error loading default CA locations"));
1401 goto jleave;
1405 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1406 goto jleave;
1408 for (ip = msgvec; *ip != 0; ++ip) {
1409 struct message *mp = message + *ip - 1;
1410 setdot(mp);
1411 ec |= smime_verify(mp, *ip, chain, store);
1413 if ((rv = ec) != 0)
1414 exit_status |= EXIT_ERR;
1415 jleave:
1416 if (store != NULL)
1417 X509_STORE_free(store);
1418 NYD_LEAVE;
1419 return rv;
1422 FL FILE *
1423 smime_sign(FILE *ip, char const *addr)
1425 FILE *rv = NULL, *sp = NULL, *fp = NULL, *bp, *hp;
1426 X509 *cert = NULL;
1427 _STACKOF(X509) *chain = NULL;
1428 EVP_PKEY *pkey = NULL;
1429 BIO *bb, *sb;
1430 PKCS7 *pkcs7;
1431 EVP_MD const *md;
1432 char const *name;
1433 bool_t bail = FAL0;
1434 NYD_ENTER;
1436 _ssl_init();
1438 if (addr == NULL) {
1439 n_err(_("No *from* address for signing specified\n"));
1440 goto jleave;
1442 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
1443 goto jleave;
1445 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1446 ssl_gen_err(_("Error reading private key from"));
1447 goto jleave;
1450 rewind(fp);
1451 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1452 ssl_gen_err(_("Error reading signer certificate from"));
1453 goto jleave;
1455 Fclose(fp);
1456 fp = NULL;
1458 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1459 !_smime_sign_include_chain_creat(&chain, name))
1460 goto jleave;
1462 name = NULL;
1463 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1464 goto jleave;
1466 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1467 NULL) {
1468 n_perr(_("tempfile"), 0);
1469 goto jleave;
1472 rewind(ip);
1473 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1474 goto jerr1;
1476 sb = NULL;
1477 pkcs7 = NULL;
1479 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1480 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1481 ssl_gen_err(_("Error creating BIO signing objects"));
1482 bail = TRU1;
1483 goto jerr;
1486 #undef _X
1487 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1488 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1489 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1490 bail = TRU1;
1491 goto jerr;
1493 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1494 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1495 bail = TRU1;
1496 goto jerr;
1498 if (!PKCS7_final(pkcs7, bb, _X)) {
1499 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1500 bail = TRU1;
1501 goto jerr;
1503 #undef _X
1505 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1506 ssl_gen_err(_("Error writing signed S/MIME data"));
1507 bail = TRU1;
1508 /*goto jerr*/
1510 jerr:
1511 if (pkcs7 != NULL)
1512 PKCS7_free(pkcs7);
1513 if (sb != NULL)
1514 BIO_free(sb);
1515 if (bb != NULL)
1516 BIO_free(bb);
1517 if (!bail) {
1518 rewind(bp);
1519 fflush_rewind(sp);
1520 rv = smime_sign_assemble(hp, bp, sp, name);
1521 } else
1522 jerr1:
1523 Fclose(sp);
1525 jleave:
1526 if (chain != NULL)
1527 sk_X509_pop_free(chain, X509_free);
1528 if (cert != NULL)
1529 X509_free(cert);
1530 if (pkey != NULL)
1531 EVP_PKEY_free(pkey);
1532 if (fp != NULL)
1533 Fclose(fp);
1534 NYD_LEAVE;
1535 return rv;
1538 FL FILE *
1539 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1541 FILE *rv = NULL, *yp, *fp, *bp, *hp;
1542 X509 *cert;
1543 PKCS7 *pkcs7;
1544 BIO *bb, *yb;
1545 _STACKOF(X509) *certs;
1546 EVP_CIPHER const *cipher;
1547 char *certfile;
1548 bool_t bail = FAL0;
1549 NYD_ENTER;
1551 if ((certfile = file_expand(xcertfile)) == NULL)
1552 goto jleave;
1554 _ssl_init();
1556 if ((cipher = _smime_cipher(to)) == NULL)
1557 goto jleave;
1558 if ((fp = Fopen(certfile, "r")) == NULL) {
1559 n_perr(certfile, 0);
1560 goto jleave;
1563 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1564 ssl_gen_err(_("Error reading encryption certificate from \"%s\""),
1565 certfile);
1566 bail = TRU1;
1568 Fclose(fp);
1569 if (bail)
1570 goto jleave;
1571 bail = FAL0;
1573 certs = sk_X509_new_null();
1574 sk_X509_push(certs, cert);
1576 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1577 NULL) {
1578 n_perr(_("tempfile"), 0);
1579 goto jerr1;
1582 rewind(ip);
1583 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1584 Fclose(yp);
1585 goto jerr1;
1588 yb = NULL;
1589 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1590 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1591 ssl_gen_err(_("Error creating BIO encryption objects"));
1592 bail = TRU1;
1593 goto jerr2;
1595 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1596 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
1597 bail = TRU1;
1598 goto jerr2;
1600 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1601 ssl_gen_err(_("Error writing encrypted S/MIME data"));
1602 bail = TRU1;
1603 /* goto jerr2 */
1606 jerr2:
1607 if (bb != NULL)
1608 BIO_free(bb);
1609 if (yb != NULL)
1610 BIO_free(yb);
1611 Fclose(bp);
1612 if (bail)
1613 Fclose(yp);
1614 else {
1615 fflush_rewind(yp);
1616 rv = smime_encrypt_assemble(hp, yp);
1618 jerr1:
1619 sk_X509_pop_free(certs, X509_free);
1620 jleave:
1621 NYD_LEAVE;
1622 return rv;
1625 FL struct message *
1626 smime_decrypt(struct message *m, char const *to, char const *cc, int signcall)
1628 struct message *rv;
1629 FILE *fp, *bp, *hp, *op;
1630 X509 *cert;
1631 PKCS7 *pkcs7;
1632 EVP_PKEY *pkey;
1633 BIO *bb, *pb, *ob;
1634 long size;
1635 FILE *yp;
1636 NYD_ENTER;
1638 rv = NULL;
1639 cert = NULL;
1640 pkey = NULL;
1641 size = m->m_size;
1643 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1644 goto jleave;
1646 _ssl_init();
1648 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
1649 pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL);
1650 if (pkey == NULL) {
1651 ssl_gen_err(_("Error reading private key"));
1652 Fclose(fp);
1653 goto jleave;
1655 rewind(fp);
1657 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1658 ssl_gen_err(_("Error reading decryption certificate"));
1659 Fclose(fp);
1660 EVP_PKEY_free(pkey);
1661 goto jleave;
1663 Fclose(fp);
1666 if ((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1667 NULL) {
1668 n_perr(_("tempfile"), 0);
1669 goto j_ferr;
1672 if (smime_split(yp, &hp, &bp, size, 1) == STOP)
1673 goto jferr;
1675 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1676 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
1677 ssl_gen_err(_("Error creating BIO decryption objects"));
1678 goto jferr;
1680 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
1681 ssl_gen_err(_("Error reading PKCS#7 object"));
1682 jferr:
1683 Fclose(op);
1684 j_ferr:
1685 if (cert)
1686 X509_free(cert);
1687 if (pkey)
1688 EVP_PKEY_free(pkey);
1689 goto jleave;
1692 if (PKCS7_type_is_signed(pkcs7)) {
1693 if (signcall) {
1694 setinput(&mb, m, NEED_BODY);
1695 rv = (struct message*)-1;
1696 goto jerr2;
1698 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1699 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1700 goto jerr;
1701 fseek(hp, 0L, SEEK_END);
1702 fprintf(hp, "X-Encryption-Cipher: none\n");
1703 fflush(hp);
1704 rewind(hp);
1705 } else if (pkey == NULL) {
1706 n_err(_("No appropriate private key found\n"));
1707 goto jerr2;
1708 } else if (cert == NULL) {
1709 n_err(_("No appropriate certificate found\n"));
1710 goto jerr2;
1711 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
1712 jerr:
1713 ssl_gen_err(_("Error decrypting PKCS#7 object"));
1714 jerr2:
1715 BIO_free(bb);
1716 BIO_free(ob);
1717 Fclose(op);
1718 Fclose(bp);
1719 Fclose(hp);
1720 if (cert != NULL)
1721 X509_free(cert);
1722 if (pkey != NULL)
1723 EVP_PKEY_free(pkey);
1724 goto jleave;
1726 BIO_free(bb);
1727 BIO_free(ob);
1728 if (cert)
1729 X509_free(cert);
1730 if (pkey)
1731 EVP_PKEY_free(pkey);
1732 fflush_rewind(op);
1733 Fclose(bp);
1735 rv = smime_decrypt_assemble(m, hp, op);
1736 jleave:
1737 NYD_LEAVE;
1738 return rv;
1741 FL enum okay
1742 smime_certsave(struct message *m, int n, FILE *op)
1744 struct message *x;
1745 char *to, *cc, *cnttype;
1746 int c, i;
1747 FILE *fp, *ip;
1748 off_t size;
1749 BIO *fb, *pb;
1750 PKCS7 *pkcs7;
1751 _STACKOF(X509) *certs, *chain = NULL;
1752 X509 *cert;
1753 enum okay rv = STOP;
1754 NYD_ENTER;
1756 _ssl_msgno = (size_t)n;
1757 jloop:
1758 to = hfield1("to", m);
1759 cc = hfield1("cc", m);
1760 cnttype = hfield1("content-type", m);
1762 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1763 goto jleave;
1765 #undef _X
1766 #undef _Y
1767 #define _X (sizeof("application/") -1)
1768 #define _Y(X) X, sizeof(X) -1
1769 if (cnttype && is_asccaseprefix(cnttype, "application/") &&
1770 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
1771 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
1772 #undef _Y
1773 #undef _X
1774 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1775 goto jleave;
1776 if (x != (struct message*)-1) {
1777 m = x;
1778 goto jloop;
1781 size = m->m_size;
1783 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1784 NULL) {
1785 n_perr(_("tempfile"), 0);
1786 goto jleave;
1789 while (size-- > 0) {
1790 c = getc(ip);
1791 putc(c, fp);
1793 fflush(fp);
1795 rewind(fp);
1796 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1797 ssl_gen_err("Error creating BIO object for message %d", n);
1798 Fclose(fp);
1799 goto jleave;
1802 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1803 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1804 BIO_free(fb);
1805 Fclose(fp);
1806 goto jleave;
1808 BIO_free(fb);
1809 Fclose(fp);
1811 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1812 if (certs == NULL) {
1813 n_err(_("No certificates found in message %d\n"), n);
1814 goto jleave;
1817 for (i = 0; i < sk_X509_num(certs); ++i) {
1818 cert = sk_X509_value(certs, i);
1819 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
1820 ssl_gen_err(_("Error writing certificate %d from message %d"),
1821 i, n);
1822 goto jleave;
1825 rv = OKAY;
1826 jleave:
1827 NYD_LEAVE;
1828 return rv;
1830 #endif /* HAVE_OPENSSL */
1832 /* s-it-mode */