FIX: really_rewind() for pre POSIX Issue 7
[s-mailx.git] / openssl.c
blob2db79ea6ce408edf38f91e01de8dfd11ec413121
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 enum ssl_state {
113 SS_INIT = 1<<0,
114 SS_RAND_INIT = 1<<1,
115 SS_EXIT_HDL = 1<<2,
116 SS_CONF_LOAD = 1<<3,
117 SS_ALGO_LOAD = 1<<4,
119 SS_VERIFY_ERROR = 1<<7
122 /* We go for the OpenSSL v1.0.2+ SSL_CONF_CTX if available even if that means
123 * that the library does internally what we'd otherwise do ourselfs.
124 * Eventually we can drop the direct use cases */
125 enum ssl_conf_type {
126 SCT_CERTIFICATE,
127 SCT_CIPHER_STRING,
128 SCT_PRIVATE_KEY,
129 SCT_OPTIONS,
130 SCT_PROTOCOL
133 struct ssl_method { /* TODO obsolete */
134 char const sm_name[8];
135 char const sm_map[16];
138 #ifndef HAVE_OPENSSL_CONF_CTX /* TODO obsolete the fallback */
139 struct ssl_protocol {
140 char const *sp_name;
141 sl_i sp_flag;
143 #endif
145 struct smime_cipher {
146 char const sc_name[8];
147 EVP_CIPHER const *(*sc_fun)(void);
150 struct smime_digest {
151 char const sd_name[8];
152 EVP_MD const *(*sd_fun)(void);
155 /* Supported SSL/TLS methods: update manual on change! */
157 static struct ssl_method const _ssl_methods[] = { /* TODO obsolete */
158 {"auto", "ALL,-SSLv2"},
159 {"ssl3", "-ALL,SSLv3"},
160 {"tls1", "-ALL,TLSv1"},
161 {"tls1.1", "-ALL,TLSv1.1"},
162 {"tls1.2", "-ALL,TLSv1.2"}
165 /* Update manual on change! */
166 #ifndef HAVE_OPENSSL_CONF_CTX /* TODO obsolete the fallback */
167 static struct ssl_protocol const _ssl_protocols[] = {
168 {"ALL", SSL_OP_NO_SSL_MASK},
169 {"TLSv1.2", SSL_OP_NO_TLSv1_2},
170 {"TLSv1.1", SSL_OP_NO_TLSv1_1},
171 {"TLSv1", SSL_OP_NO_TLSv1},
172 {"SSLv3", SSL_OP_NO_SSLv3},
173 {"SSLv2", 0}
175 #endif
177 /* Supported S/MIME cipher algorithms */
178 static struct smime_cipher const _smime_ciphers[] = { /* Manual!! */
179 #ifndef OPENSSL_NO_AES
180 # define _SMIME_DEFAULT_CIPHER EVP_aes_128_cbc /* According to RFC 5751 */
181 {"aes128", &EVP_aes_128_cbc},
182 {"aes256", &EVP_aes_256_cbc},
183 {"aes192", &EVP_aes_192_cbc},
184 #endif
185 #ifndef OPENSSL_NO_DES
186 # ifndef _SMIME_DEFAULT_CIPHER
187 # define _SMIME_DEFAULT_CIPHER EVP_des_ede3_cbc
188 # endif
189 {"des3", &EVP_des_ede3_cbc},
190 {"des", &EVP_des_cbc},
191 #endif
193 #ifndef _SMIME_DEFAULT_CIPHER
194 # error Your OpenSSL library does not include the necessary
195 # error cipher algorithms that are required to support S/MIME
196 #endif
198 #ifndef OPENSSL_NO_AES
199 static struct smime_cipher const _smime_ciphers_obs[] = { /* TODO obsolete */
200 {"aes-128", &EVP_aes_128_cbc},
201 {"aes-256", &EVP_aes_256_cbc},
202 {"aes-192", &EVP_aes_192_cbc}
204 #endif
206 /* Supported S/MIME message digest algorithms */
207 static struct smime_digest const _smime_digests[] = { /* Manual!! */
208 #define _SMIME_DEFAULT_DIGEST EVP_sha1 /* According to RFC 5751 */
209 #define _SMIME_DEFAULT_DIGEST_S "sha1"
210 {"sha1", &EVP_sha1},
211 {"sha256", &EVP_sha256},
212 {"sha512", &EVP_sha512},
213 {"sha384", &EVP_sha384},
214 {"sha224", &EVP_sha224},
215 #ifndef OPENSSL_NO_MD5
216 {"md5", &EVP_md5},
217 #endif
220 static enum ssl_state _ssl_state;
221 static size_t _ssl_msgno;
223 static int _ssl_rand_init(void);
224 static void _ssl_init(void);
225 #ifdef HAVE_SSL_ALL_ALGORITHMS
226 static void _ssl_load_algos(void);
227 #endif
228 #if defined HAVE_OPENSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
229 static void _ssl_atexit(void);
230 #endif
232 static bool_t _ssl_parse_asn1_time(ASN1_TIME *atp,
233 char *bdat, size_t blen);
234 static int _ssl_verify_cb(int success, X509_STORE_CTX *store);
236 /* SSL_CTX configuration */
237 static void * _ssl_conf_setup(SSL_CTX *ctxp);
238 static bool_t _ssl_conf(void *confp, enum ssl_conf_type sct,
239 char const *value);
240 static bool_t _ssl_conf_finish(void **confp, bool_t error);
242 static bool_t _ssl_load_verifications(SSL_CTX *ctxp);
244 static enum okay ssl_check_host(struct sock *sp, struct url const *urlp);
246 static int smime_verify(struct message *m, int n, _STACKOF(X509) *chain,
247 X509_STORE *store);
248 static EVP_CIPHER const * _smime_cipher(char const *name);
249 static int ssl_password_cb(char *buf, int size, int rwflag,
250 void *userdata);
251 static FILE * smime_sign_cert(char const *xname, char const *xname2,
252 bool_t dowarn);
253 static char * _smime_sign_include_certs(char const *name);
254 static bool_t _smime_sign_include_chain_creat(_STACKOF(X509) **chain,
255 char const *cfiles);
256 static EVP_MD const * _smime_sign_digest(char const *name,
257 char const **digname);
258 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
259 static enum okay load_crl1(X509_STORE *store, char const *name);
260 #endif
261 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
263 static int
264 _ssl_rand_init(void)
266 char *cp, *x;
267 int state = 0;
268 NYD_ENTER;
270 #ifdef HAVE_OPENSSL_RAND_EGD
271 if ((cp = ok_vlook(ssl_rand_egd)) != NULL) {
272 if ((x = file_expand(cp)) == NULL || RAND_egd(cp = x) == -1)
273 n_err(_("Entropy daemon at \"%s\" not available\n"), cp);
274 else
275 state = 1;
276 } else
277 #endif
278 if ((cp = ok_vlook(ssl_rand_file)) != NULL) {
279 if ((x = file_expand(cp)) == NULL || RAND_load_file(cp = x, 1024) == -1)
280 n_err(_("Entropy file at \"%s\" not available\n"), cp);
281 else {
282 struct stat st;
284 if (!stat(cp, &st) && S_ISREG(st.st_mode) && !access(cp, W_OK)) {
285 if (RAND_write_file(cp) == -1) {
286 n_err(_("Writing entropy data to \"%s\" failed\n"), cp);
289 state = 1;
292 NYD_LEAVE;
293 return state;
296 static void
297 _ssl_init(void)
299 #ifdef HAVE_OPENSSL_CONFIG
300 char const *cp;
301 #endif
302 NYD_ENTER;
304 if (!(_ssl_state & SS_INIT)) {
305 SSL_library_init();
306 SSL_load_error_strings();
307 _ssl_state |= SS_INIT;
310 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
311 #ifdef HAVE_OPENSSL_CONFIG
312 if (!(_ssl_state & SS_CONF_LOAD) &&
313 (cp = ok_vlook(ssl_config_file)) != NULL) {
314 ul_i flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
316 if (*cp == '\0') {
317 cp = NULL;
318 flags = 0;
320 if (CONF_modules_load_file(cp, uagent, flags) == 1) {
321 _ssl_state |= SS_CONF_LOAD;
322 if (!(_ssl_state & SS_EXIT_HDL)) {
323 _ssl_state |= SS_EXIT_HDL;
324 atexit(&_ssl_atexit); /* TODO generic program-wide event mech. */
326 } else
327 ssl_gen_err(_("Ignoring CONF_modules_load_file() load error"));
329 #endif
331 if (!(_ssl_state & SS_RAND_INIT) && _ssl_rand_init())
332 _ssl_state |= SS_RAND_INIT;
333 NYD_LEAVE;
336 #ifdef HAVE_SSL_ALL_ALGORITHMS
337 static void
338 _ssl_load_algos(void)
340 NYD_ENTER;
341 if (!(_ssl_state & SS_ALGO_LOAD)) {
342 _ssl_state |= SS_ALGO_LOAD;
343 OpenSSL_add_all_algorithms();
345 if (!(_ssl_state & SS_EXIT_HDL)) {
346 _ssl_state |= SS_EXIT_HDL;
347 atexit(&_ssl_atexit); /* TODO generic program-wide event mech. */
350 NYD_LEAVE;
352 #endif
354 #if defined HAVE_OPENSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
355 static void
356 _ssl_atexit(void)
358 NYD_ENTER;
359 # ifdef HAVE_SSL_ALL_ALGORITHMS
360 if (_ssl_state & SS_ALGO_LOAD)
361 EVP_cleanup();
362 # endif
363 # ifdef HAVE_OPENSSL_CONFIG
364 if (_ssl_state & SS_CONF_LOAD)
365 CONF_modules_free();
366 # endif
367 NYD_LEAVE;
369 #endif
371 static bool_t
372 _ssl_parse_asn1_time(ASN1_TIME *atp, char *bdat, size_t blen)
374 BIO *mbp;
375 char *mcp;
376 long l;
377 NYD_ENTER;
379 mbp = BIO_new(BIO_s_mem());
381 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
382 snprintf(bdat, blen, "%.*s", (int)l, mcp);
383 else {
384 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
385 /*is (int)*/atp->length, (char const*)atp->data);
386 mcp = NULL;
389 BIO_free(mbp);
390 NYD_LEAVE;
391 return (mcp != NULL);
394 static int
395 _ssl_verify_cb(int success, X509_STORE_CTX *store)
397 char data[256];
398 X509 *cert;
399 int rv = TRU1;
400 NYD_ENTER;
402 if (success && !(options & OPT_VERB))
403 goto jleave;
405 if (_ssl_msgno != 0) {
406 n_err(_("Message %lu:\n"), (ul_i)_ssl_msgno);
407 _ssl_msgno = 0;
409 n_err(_(" Certificate depth %d %s\n"),
410 X509_STORE_CTX_get_error_depth(store), (success ? "" : _("ERROR")));
412 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
413 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
414 n_err(_(" subject = %s\n"), data);
416 _ssl_parse_asn1_time(X509_get_notBefore(cert), data, sizeof data);
417 n_err(_(" notBefore = %s\n"), data);
419 _ssl_parse_asn1_time(X509_get_notAfter(cert), data, sizeof data);
420 n_err(_(" notAfter = %s\n"), data);
422 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
423 n_err(_(" issuer = %s\n"), data);
426 if (!success) {
427 int err = X509_STORE_CTX_get_error(store);
429 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
430 _ssl_state |= SS_VERIFY_ERROR;
433 if (!success && ssl_verify_decide() != OKAY)
434 rv = FAL0;
435 jleave:
436 NYD_LEAVE;
437 return rv;
440 #ifdef HAVE_OPENSSL_CONF_CTX
441 static void *
442 _ssl_conf_setup(SSL_CTX *ctxp)
444 SSL_CONF_CTX *sccp;
445 NYD_ENTER;
447 if ((sccp = SSL_CONF_CTX_new()) != NULL) {
448 SSL_CONF_CTX_set_flags(sccp,
449 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
450 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
452 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
453 } else
454 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
456 NYD_LEAVE;
457 return sccp;
460 static bool_t
461 _ssl_conf(void *confp, enum ssl_conf_type sct, char const *value)
463 int rv;
464 char const *cmsg;
465 SSL_CONF_CTX *sccp = (SSL_CONF_CTX*)confp;
466 NYD_ENTER;
468 switch (sct) {
469 case SCT_CERTIFICATE:
470 cmsg = "ssl-cert";
471 rv = SSL_CONF_cmd(sccp, "Certificate", value);
472 break;
473 case SCT_CIPHER_STRING:
474 cmsg = "ssl-cipher-list";
475 rv = SSL_CONF_cmd(sccp, "CipherString", value);
476 break;
477 case SCT_PRIVATE_KEY:
478 cmsg = "ssl-key";
479 rv = SSL_CONF_cmd(sccp, "PrivateKey", value);
480 break;
481 default:
482 case SCT_OPTIONS:
483 cmsg = "ssl-options";
484 rv = SSL_CONF_cmd(sccp, "Options", "Bugs");
485 break;
486 case SCT_PROTOCOL:
487 cmsg = "ssl-protocol";
488 rv = SSL_CONF_cmd(sccp, "Protocol", value);
489 break;
492 if (rv == 2)
493 rv = 0;
494 else {
495 if (rv == 0)
496 ssl_gen_err(_("SSL_CONF_CTX_cmd() failed for *%s*"), cmsg);
497 else
498 n_err(_("%s: *%s* implementation error, please report this\n"),
499 uagent, cmsg);
500 rv = 1;
503 NYD_LEAVE;
504 return (rv == 0);
507 static bool_t
508 _ssl_conf_finish(void **confp, bool_t error)
510 SSL_CONF_CTX **sccp = (SSL_CONF_CTX**)confp;
511 bool_t rv;
512 NYD_ENTER;
514 if (!(rv = error))
515 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
517 SSL_CONF_CTX_free(*sccp);
519 *sccp = NULL;
520 NYD_LEAVE;
521 return rv;
524 #else /* HAVE_OPENSSL_CONF_CTX */
525 static void *
526 _ssl_conf_setup(SSL_CTX* ctxp)
528 return ctxp;
531 static bool_t
532 _ssl_conf(void *confp, enum ssl_conf_type sct, char const *value)
534 SSL_CTX *ctxp = (SSL_CTX*)confp;
535 NYD_ENTER;
537 switch (sct) {
538 case SCT_CERTIFICATE:
539 if (SSL_CTX_use_certificate_chain_file(ctxp, value) != 1) {
540 ssl_gen_err(_("Can't load certificate from file \"%s\"\n"), value);
541 confp = NULL;
543 break;
544 case SCT_CIPHER_STRING:
545 if (SSL_CTX_set_cipher_list(ctxp, value) != 1) {
546 ssl_gen_err(_("Invalid cipher string: \"%s\"\n"), value);
547 confp = NULL;
549 break;
550 case SCT_PRIVATE_KEY:
551 if (SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1) {
552 ssl_gen_err(_("Can't load private key from file \"%s\"\n"), value);
553 confp = NULL;
555 break;
556 case SCT_OPTIONS:
557 /* "Options"="Bugs" TODO *ssl-options* */
558 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
559 break;
560 case SCT_PROTOCOL: {
561 char *iolist, *cp, addin;
562 size_t i;
563 sl_i opts = 0;
565 confp = NULL;
566 for (iolist = cp = savestr(value);
567 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;) {
568 if (*cp == '\0') {
569 n_err(_("*ssl-protocol*: empty arguments are not supported\n"));
570 goto jleave;
573 addin = TRU1;
574 switch (cp[0]) {
575 case '-': addin = FAL0; /* FALLTHRU */
576 case '+': ++cp; /* FALLTHRU */
577 default : break;
580 for (i = 0;;) {
581 if (!asccasecmp(cp, _ssl_protocols[i].sp_name)) {
582 /* We need to inverse the meaning of the _NO_s */
583 if (!addin)
584 opts |= _ssl_protocols[i].sp_flag;
585 else
586 opts &= ~_ssl_protocols[i].sp_flag;
587 break;
589 if (++i < NELEM(_ssl_protocols))
590 continue;
591 n_err(_("*ssl-protocol*: unsupported value \"%s\"\n"), cp);
592 goto jleave;
595 confp = ctxp;
596 SSL_CTX_set_options(ctxp, opts);
597 break;
600 jleave:
601 NYD_LEAVE;
602 return (confp != NULL);
605 static bool_t
606 _ssl_conf_finish(void **confp, bool_t error)
608 UNUSED(confp);
609 UNUSED(error);
610 return TRU1;
612 #endif /* !HAVE_OPENSSL_CONF_CTX */
614 static bool_t
615 _ssl_load_verifications(SSL_CTX *ctxp)
617 char *ca_dir, *ca_file;
618 X509_STORE *store;
619 bool_t rv = FAL0;
620 NYD_ENTER;
622 if (ssl_verify_level == SSL_VERIFY_IGNORE) {
623 rv = TRU1;
624 goto jleave;
627 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
628 ca_dir = file_expand(ca_dir);
629 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
630 ca_file = file_expand(ca_file);
632 if ((ca_dir != NULL || ca_file != NULL) &&
633 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1) {
634 char const *m1, *m2, *m3;
636 if (ca_dir != NULL) {
637 m1 = ca_dir;
638 m2 = (ca_file != NULL) ? _(" or ") : "";
639 } else
640 m1 = m2 = "";
641 m3 = (ca_file != NULL) ? ca_file : "";
642 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
643 goto jleave;
646 if (!ok_blook(ssl_no_default_ca) &&
647 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
648 ssl_gen_err(_("Error loading default CA locations\n"));
649 goto jleave;
652 _ssl_state &= ~SS_VERIFY_ERROR;
653 _ssl_msgno = 0;
654 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
655 store = SSL_CTX_get_cert_store(ctxp);
656 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
658 rv = TRU1;
659 jleave:
660 NYD_LEAVE;
661 return rv;
664 static enum okay
665 ssl_check_host(struct sock *sp, struct url const *urlp)
667 char data[256];
668 X509 *cert;
669 _STACKOF(GENERAL_NAME) *gens;
670 GENERAL_NAME *gen;
671 X509_NAME *subj;
672 enum okay rv = STOP;
673 NYD_ENTER;
675 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
676 n_err(_("No certificate from \"%s\"\n"), urlp->url_h_p.s);
677 goto jleave;
680 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
681 if (gens != NULL) {
682 int i;
684 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
685 gen = sk_GENERAL_NAME_value(gens, i);
686 if (gen->type == GEN_DNS) {
687 if (options & OPT_VERB)
688 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
689 urlp->url_host.s, (char*)gen->d.ia5->data);
690 rv = rfc2595_hostname_match(urlp->url_host.s,
691 (char*)gen->d.ia5->data);
692 if (rv == OKAY)
693 goto jdone;
698 if ((subj = X509_get_subject_name(cert)) != NULL &&
699 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
700 > 0) {
701 data[sizeof data - 1] = '\0';
702 if (options & OPT_VERB)
703 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
704 urlp->url_host.s, data);
705 rv = rfc2595_hostname_match(urlp->url_host.s, data);
708 jdone:
709 X509_free(cert);
710 jleave:
711 NYD_LEAVE;
712 return rv;
715 static int
716 smime_verify(struct message *m, int n, _STACKOF(X509) *chain, X509_STORE *store)
718 char data[LINESIZE], *sender, *to, *cc, *cnttype;
719 int rv, c, i, j;
720 struct message *x;
721 FILE *fp, *ip;
722 off_t size;
723 BIO *fb, *pb;
724 PKCS7 *pkcs7;
725 _STACKOF(X509) *certs;
726 _STACKOF(GENERAL_NAME) *gens;
727 X509 *cert;
728 X509_NAME *subj;
729 GENERAL_NAME *gen;
730 NYD_ENTER;
732 rv = 1;
733 fp = NULL;
734 fb = NULL;
735 _ssl_state &= ~SS_VERIFY_ERROR;
736 _ssl_msgno = (size_t)n;
738 for (;;) {
739 sender = getsender(m);
740 to = hfield1("to", m);
741 cc = hfield1("cc", m);
742 cnttype = hfield1("content-type", m);
744 #undef _X
745 #undef _Y
746 #define _X (sizeof("application/") -1)
747 #define _Y(X) X, sizeof(X) -1
748 if (cnttype && is_asccaseprefix(cnttype, "application/") &&
749 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
750 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
751 #undef _Y
752 #undef _X
753 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
754 goto jleave;
755 if (x != (struct message*)-1) {
756 m = x;
757 continue;
761 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
762 goto jleave;
763 size = m->m_size;
764 break;
767 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
768 NULL) {
769 n_perr(_("tempfile"), 0);
770 goto jleave;
772 while (size-- > 0) {
773 c = getc(ip);
774 putc(c, fp);
776 fflush_rewind(fp);
778 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
779 ssl_gen_err(_(
780 "Error creating BIO verification object for message %d"), n);
781 goto jleave;
784 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
785 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
786 goto jleave;
788 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
789 ssl_gen_err(_("Error verifying message %d"), n);
790 goto jleave;
793 if (sender == NULL) {
794 n_err(_("Warning: Message %d has no sender\n"), n);
795 rv = 0;
796 goto jleave;
799 certs = PKCS7_get0_signers(pkcs7, chain, 0);
800 if (certs == NULL) {
801 n_err(_("No certificates found in message %d\n"), n);
802 goto jleave;
805 for (i = 0; i < sk_X509_num(certs); ++i) {
806 cert = sk_X509_value(certs, i);
807 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
808 if (gens != NULL) {
809 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
810 gen = sk_GENERAL_NAME_value(gens, j);
811 if (gen->type == GEN_EMAIL) {
812 if (options & OPT_VERB)
813 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
814 sender, (char*)gen->d.ia5->data);
815 if (!asccasecmp((char*)gen->d.ia5->data, sender))
816 goto jfound;
821 if ((subj = X509_get_subject_name(cert)) != NULL &&
822 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
823 data, sizeof data) > 0) {
824 data[sizeof data -1] = '\0';
825 if (options & OPT_VERB)
826 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
827 sender, data);
828 if (!asccasecmp(data, sender))
829 goto jfound;
832 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
833 goto jleave;
834 jfound:
835 rv = ((_ssl_state & SS_VERIFY_ERROR) != 0);
836 if (!rv)
837 printf(_("Message %d was verified successfully\n"), n);
838 jleave:
839 if (fb != NULL)
840 BIO_free(fb);
841 if (fp != NULL)
842 Fclose(fp);
843 NYD_LEAVE;
844 return rv;
847 static EVP_CIPHER const *
848 _smime_cipher(char const *name)
850 EVP_CIPHER const *cipher;
851 char *vn;
852 char const *cp;
853 size_t i;
854 NYD_ENTER;
856 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
857 snprintf(vn, (int)i, "smime-cipher-%s", name);
858 cp = vok_vlook(vn);
859 ac_free(vn);
861 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
862 cipher = _SMIME_DEFAULT_CIPHER();
863 goto jleave;
865 cipher = NULL;
867 for (i = 0; i < NELEM(_smime_ciphers); ++i)
868 if (!asccasecmp(_smime_ciphers[i].sc_name, cp)) {
869 cipher = (*_smime_ciphers[i].sc_fun)();
870 goto jleave;
872 #ifndef OPENSSL_NO_AES
873 for (i = 0; i < NELEM(_smime_ciphers_obs); ++i) /* TODO obsolete */
874 if (!asccasecmp(_smime_ciphers_obs[i].sc_name, cp)) {
875 OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
876 cipher = (*_smime_ciphers_obs[i].sc_fun)();
877 goto jleave;
879 #endif
881 /* Not a builtin algorithm, but we may have dynamic support for more */
882 #ifdef HAVE_SSL_ALL_ALGORITHMS
883 _ssl_load_algos();
884 if ((cipher = EVP_get_cipherbyname(cp)) != NULL)
885 goto jleave;
886 #endif
888 n_err(_("Invalid S/MIME cipher(s): \"%s\"\n"), cp);
889 jleave:
890 NYD_LEAVE;
891 return cipher;
894 static int
895 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
897 char *pass;
898 size_t len;
899 NYD_ENTER;
900 UNUSED(rwflag);
901 UNUSED(userdata);
903 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
904 len = strlen(pass);
905 if (UICMP(z, len, >=, size))
906 len = size -1;
907 memcpy(buf, pass, len);
908 buf[len] = '\0';
909 } else
910 len = 0;
911 NYD_LEAVE;
912 return (int)len;
915 static FILE *
916 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn)
918 char *vn, *cp;
919 int vs;
920 struct name *np;
921 char const *name = xname, *name2 = xname2;
922 FILE *fp = NULL;
923 NYD_ENTER;
925 jloop:
926 if (name) {
927 np = lextract(name, GTO | GSKIN);
928 while (np != NULL) {
929 /* This needs to be more intelligent since it will currently take the
930 * first name for which a private key is available regardless of
931 * whether it is the right one for the message */
932 vn = ac_alloc(vs = strlen(np->n_name) + 30);
933 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
934 cp = vok_vlook(vn);
935 ac_free(vn);
936 if (cp != NULL)
937 goto jopen;
938 np = np->n_flink;
940 if (name2 != NULL) {
941 name = name2;
942 name2 = NULL;
943 goto jloop;
947 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
948 goto jerr;
949 jopen:
950 if ((cp = file_expand(cp)) == NULL)
951 goto jleave;
952 if ((fp = Fopen(cp, "r")) == NULL)
953 n_perr(cp, 0);
954 jleave:
955 NYD_LEAVE;
956 return fp;
957 jerr:
958 if (dowarn)
959 n_err(_("Could not find a certificate for %s%s%s\n"),
960 xname, (xname2 != NULL ? _("or ") : ""),
961 (xname2 != NULL ? xname2 : ""));
962 goto jleave;
965 static char *
966 _smime_sign_include_certs(char const *name)
968 char *rv;
969 NYD_ENTER;
971 /* See comments in smime_sign_cert() for algorithm pitfalls */
972 if (name != NULL) {
973 struct name *np;
975 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
976 int vs;
977 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
978 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
979 rv = vok_vlook(vn);
980 ac_free(vn);
981 if (rv != NULL)
982 goto jleave;
985 rv = ok_vlook(smime_sign_include_certs);
986 jleave:
987 NYD_LEAVE;
988 return rv;
991 static bool_t
992 _smime_sign_include_chain_creat(_STACKOF(X509) **chain, char const *cfiles)
994 X509 *tmp;
995 FILE *fp;
996 char *nfield, *cfield, *x;
997 NYD_ENTER;
999 *chain = sk_X509_new_null();
1001 for (nfield = savestr(cfiles);
1002 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1003 if ((x = file_expand(cfield)) == NULL ||
1004 (fp = Fopen(cfield = x, "r")) == NULL) {
1005 n_perr(cfiles, 0);
1006 goto jerr;
1008 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1009 ssl_gen_err(_("Error reading certificate from \"%s\""), cfield);
1010 Fclose(fp);
1011 goto jerr;
1013 sk_X509_push(*chain, tmp);
1014 Fclose(fp);
1017 if (sk_X509_num(*chain) == 0) {
1018 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1019 goto jerr;
1021 jleave:
1022 NYD_LEAVE;
1023 return (*chain != NULL);
1024 jerr:
1025 sk_X509_pop_free(*chain, X509_free);
1026 *chain = NULL;
1027 goto jleave;
1030 static EVP_MD const *
1031 _smime_sign_digest(char const *name, char const **digname)
1033 EVP_MD const *digest;
1034 char const *cp;
1035 size_t i;
1036 NYD_ENTER;
1038 /* See comments in smime_sign_cert() for algorithm pitfalls */
1039 if (name != NULL) {
1040 struct name *np;
1042 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1043 int vs;
1044 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1045 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1046 cp = vok_vlook(vn);
1047 ac_free(vn);
1048 if (cp != NULL)
1049 goto jhave_name;
1053 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1054 digest = _SMIME_DEFAULT_DIGEST();
1055 *digname = _SMIME_DEFAULT_DIGEST_S;
1056 goto jleave;
1059 jhave_name:
1060 i = strlen(cp);
1061 { char *x = salloc(i +1);
1062 i_strcpy(x, cp, i +1);
1063 cp = x;
1065 *digname = cp;
1067 for (i = 0; i < NELEM(_smime_digests); ++i)
1068 if (!strcmp(_smime_digests[i].sd_name, cp)) {
1069 digest = (*_smime_digests[i].sd_fun)();
1070 goto jleave;
1073 /* Not a builtin algorithm, but we may have dynamic support for more */
1074 #ifdef HAVE_SSL_ALL_ALGORITHMS
1075 _ssl_load_algos();
1076 if ((digest = EVP_get_digestbyname(cp)) != NULL)
1077 goto jleave;
1078 #endif
1080 n_err(_("Invalid message digest: \"%s\"\n"), cp);
1081 digest = NULL;
1082 jleave:
1083 NYD_LEAVE;
1084 return digest;
1087 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1088 static enum okay
1089 load_crl1(X509_STORE *store, char const *name)
1091 X509_LOOKUP *lookup;
1092 enum okay rv = STOP;
1093 NYD_ENTER;
1095 if (options & OPT_VERB)
1096 n_err(_("Loading CRL from \"%s\"\n"), name);
1097 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1098 ssl_gen_err(_("Error creating X509 lookup object"));
1099 goto jleave;
1101 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1102 ssl_gen_err(_("Error loading CRL from \"%s\""), name);
1103 goto jleave;
1105 rv = OKAY;
1106 jleave:
1107 NYD_LEAVE;
1108 return rv;
1110 #endif /* new OpenSSL */
1112 static enum okay
1113 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1115 char *crl_file, *crl_dir;
1116 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1117 DIR *dirp;
1118 struct dirent *dp;
1119 char *fn = NULL;
1120 int fs = 0, ds, es;
1121 #endif
1122 enum okay rv = STOP;
1123 NYD_ENTER;
1125 if ((crl_file = _var_oklook(fok)) != NULL) {
1126 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1127 if ((crl_file = file_expand(crl_file)) == NULL ||
1128 load_crl1(store, crl_file) != OKAY)
1129 goto jleave;
1130 #else
1131 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1132 goto jleave;
1133 #endif
1136 if ((crl_dir = _var_oklook(dok)) != NULL) {
1137 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1138 char *x;
1139 if ((x = file_expand(crl_dir)) == NULL ||
1140 (dirp = opendir(crl_dir = x)) == NULL) {
1141 n_perr(crl_dir, 0);
1142 goto jleave;
1145 ds = strlen(crl_dir);
1146 fn = smalloc(fs = ds + 20);
1147 memcpy(fn, crl_dir, ds);
1148 fn[ds] = '/';
1149 while ((dp = readdir(dirp)) != NULL) {
1150 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1151 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1152 continue;
1153 if (dp->d_name[0] == '.')
1154 continue;
1155 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1156 fn = srealloc(fn, fs = ds + es + 20);
1157 memcpy(fn + ds + 1, dp->d_name, es + 1);
1158 if (load_crl1(store, fn) != OKAY) {
1159 closedir(dirp);
1160 free(fn);
1161 goto jleave;
1164 closedir(dirp);
1165 free(fn);
1166 #else /* old OpenSSL */
1167 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1168 goto jleave;
1169 #endif
1171 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1172 if (crl_file || crl_dir)
1173 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1174 X509_V_FLAG_CRL_CHECK_ALL);
1175 #endif
1176 rv = OKAY;
1177 jleave:
1178 NYD_LEAVE;
1179 return rv;
1182 FL enum okay
1183 ssl_open(struct url const *urlp, struct sock *sp)
1185 SSL_CTX *ctxp;
1186 void *confp;
1187 char const *cp, *cp_base;
1188 size_t i;
1189 enum okay rv = STOP;
1190 NYD_ENTER;
1192 _ssl_init();
1194 ssl_set_verify_level(urlp);
1196 if ((ctxp = SSL_CTX_new(_SSL_CLIENT_METHOD())) == NULL) {
1197 ssl_gen_err(_("SSL_CTX_new() failed"));
1198 goto jleave;
1201 /* Available with OpenSSL 0.9.6 or later */
1202 #ifdef SSL_MODE_AUTO_RETRY
1203 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1204 #endif
1206 if ((confp = _ssl_conf_setup(ctxp)) == NULL)
1207 goto jerr0;
1209 /* TODO obsolete Check for *ssl-method*, warp to a *ssl-protocol* value */
1210 if ((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL) {
1211 OBSOLETE(_("please use *ssl-protocol* instead of *ssl-method*"));
1212 if (options & OPT_VERB)
1213 n_err(_("*ssl-method*: \"%s\"\n"), cp);
1214 for (i = 0;;) {
1215 if (!asccasecmp(_ssl_methods[i].sm_name, cp)) {
1216 cp = _ssl_methods[i].sm_map;
1217 break;
1219 if (++i == NELEM(_ssl_methods)) {
1220 n_err(_("Unsupported TLS/SSL method \"%s\"\n"), cp);
1221 goto jerr1;
1225 /* *ssl-protocol* */
1226 if ((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL) {
1227 if (options & OPT_VERB)
1228 n_err(_("*ssl-protocol*: \"%s\"\n"), cp_base);
1229 cp = cp_base;
1231 cp = (cp != NULL ? savecatsep(cp, ',', SSL_DISABLED_PROTOCOLS)
1232 : SSL_DISABLED_PROTOCOLS);
1233 if (!_ssl_conf(confp, SCT_PROTOCOL, cp))
1234 goto jerr1;
1236 /* *ssl-cert* */
1237 if ((cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL) {
1238 if (options & OPT_VERB)
1239 n_err(_("*ssl-cert* \"%s\"\n"), cp);
1240 if ((cp_base = file_expand(cp)) == NULL) {
1241 n_err(_("*ssl-cert* value expansion failed: \"%s\"\n"), cp);
1242 goto jerr1;
1244 cp = cp_base;
1245 if (!_ssl_conf(confp, SCT_CERTIFICATE, cp))
1246 goto jerr1;
1248 /* *ssl-key* */
1249 if ((cp_base = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL) {
1250 if (options & OPT_VERB)
1251 n_err(_("*ssl-key* \"%s\"\n"), cp_base);
1252 if ((cp = file_expand(cp_base)) == NULL) {
1253 n_err(_("*ssl-key* value expansion failed: \"%s\"\n"), cp_base);
1254 goto jerr1;
1257 if (!_ssl_conf(confp, SCT_PRIVATE_KEY, cp))
1258 goto jerr1;
1261 if ((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL &&
1262 !_ssl_conf(confp, SCT_CIPHER_STRING, cp))
1263 goto jerr1;
1265 if (!_ssl_load_verifications(ctxp))
1266 goto jerr1;
1268 if (!_ssl_conf(confp, SCT_OPTIONS, NULL)) /* TODO *ssl-options* */
1269 goto jerr1;
1271 /* Done with context setup, create our new per-connection structure */
1272 if (!_ssl_conf_finish(&confp, FAL0))
1273 goto jerr0;
1275 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1276 ssl_gen_err(_("SSL_new() failed"));
1277 goto jerr0;
1280 SSL_set_fd(sp->s_ssl, sp->s_fd);
1282 if (SSL_connect(sp->s_ssl) < 0) {
1283 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1284 goto jerr2;
1287 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1288 if (ssl_check_host(sp, urlp) != OKAY) {
1289 n_err(_("Host certificate does not match \"%s\"\n"),
1290 urlp->url_h_p.s);
1291 if (ssl_verify_decide() != OKAY)
1292 goto jerr2;
1296 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1297 * and free it right now -- it is reference counted by sp->s_ssl.. */
1298 SSL_CTX_free(ctxp);
1299 sp->s_use_ssl = 1;
1300 rv = OKAY;
1301 jleave:
1302 NYD_LEAVE;
1303 return rv;
1304 jerr2:
1305 SSL_free(sp->s_ssl);
1306 sp->s_ssl = NULL;
1307 jerr1:
1308 if (confp != NULL)
1309 _ssl_conf_finish(&confp, TRU1);
1310 jerr0:
1311 SSL_CTX_free(ctxp);
1312 goto jleave;
1315 FL void
1316 ssl_gen_err(char const *fmt, ...)
1318 va_list ap;
1319 NYD_ENTER;
1321 va_start(ap, fmt);
1322 n_verr(fmt, ap);
1323 va_end(ap);
1325 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1326 NYD_LEAVE;
1329 FL int
1330 c_verify(void *vp)
1332 int *msgvec = vp, *ip, ec = 0, rv = 1;
1333 _STACKOF(X509) *chain = NULL;
1334 X509_STORE *store = NULL;
1335 char *ca_dir, *ca_file;
1336 NYD_ENTER;
1338 _ssl_init();
1340 ssl_verify_level = SSL_VERIFY_STRICT;
1341 if ((store = X509_STORE_new()) == NULL) {
1342 ssl_gen_err(_("Error creating X509 store"));
1343 goto jleave;
1345 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1347 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1348 ca_dir = file_expand(ca_dir);
1349 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1350 ca_file = file_expand(ca_file);
1352 if (ca_dir != NULL || ca_file != NULL) {
1353 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
1354 ssl_gen_err(_("Error loading %s"),
1355 (ca_file != NULL) ? ca_file : ca_dir);
1356 goto jleave;
1359 if (!ok_blook(smime_no_default_ca)) {
1360 if (X509_STORE_set_default_paths(store) != 1) {
1361 ssl_gen_err(_("Error loading default CA locations"));
1362 goto jleave;
1366 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1367 goto jleave;
1369 for (ip = msgvec; *ip != 0; ++ip) {
1370 struct message *mp = message + *ip - 1;
1371 setdot(mp);
1372 ec |= smime_verify(mp, *ip, chain, store);
1374 if ((rv = ec) != 0)
1375 exit_status |= EXIT_ERR;
1376 jleave:
1377 if (store != NULL)
1378 X509_STORE_free(store);
1379 NYD_LEAVE;
1380 return rv;
1383 FL FILE *
1384 smime_sign(FILE *ip, char const *addr)
1386 FILE *rv = NULL, *sp = NULL, *fp = NULL, *bp, *hp;
1387 X509 *cert = NULL;
1388 _STACKOF(X509) *chain = NULL;
1389 EVP_PKEY *pkey = NULL;
1390 BIO *bb, *sb;
1391 PKCS7 *pkcs7;
1392 EVP_MD const *md;
1393 char const *name;
1394 bool_t bail = FAL0;
1395 NYD_ENTER;
1397 _ssl_init();
1399 if (addr == NULL) {
1400 n_err(_("No *from* address for signing specified\n"));
1401 goto jleave;
1403 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
1404 goto jleave;
1406 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1407 ssl_gen_err(_("Error reading private key from"));
1408 goto jleave;
1411 rewind(fp);
1412 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1413 ssl_gen_err(_("Error reading signer certificate from"));
1414 goto jleave;
1416 Fclose(fp);
1417 fp = NULL;
1419 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1420 !_smime_sign_include_chain_creat(&chain, name))
1421 goto jleave;
1423 name = NULL;
1424 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1425 goto jleave;
1427 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600))
1428 == NULL) {
1429 n_perr(_("tempfile"), 0);
1430 goto jleave;
1433 rewind(ip);
1434 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1435 goto jerr1;
1437 sb = NULL;
1438 pkcs7 = NULL;
1440 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1441 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1442 ssl_gen_err(_("Error creating BIO signing objects"));
1443 bail = TRU1;
1444 goto jerr;
1447 #undef _X
1448 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1449 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1450 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1451 bail = TRU1;
1452 goto jerr;
1454 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1455 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1456 bail = TRU1;
1457 goto jerr;
1459 if (!PKCS7_final(pkcs7, bb, _X)) {
1460 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1461 bail = TRU1;
1462 goto jerr;
1464 #undef _X
1466 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1467 ssl_gen_err(_("Error writing signed S/MIME data"));
1468 bail = TRU1;
1469 /*goto jerr*/
1471 jerr:
1472 if (pkcs7 != NULL)
1473 PKCS7_free(pkcs7);
1474 if (sb != NULL)
1475 BIO_free(sb);
1476 if (bb != NULL)
1477 BIO_free(bb);
1478 if (!bail) {
1479 rewind(bp);
1480 fflush_rewind(sp);
1481 rv = smime_sign_assemble(hp, bp, sp, name);
1482 } else
1483 jerr1:
1484 Fclose(sp);
1486 jleave:
1487 if (chain != NULL)
1488 sk_X509_pop_free(chain, X509_free);
1489 if (cert != NULL)
1490 X509_free(cert);
1491 if (pkey != NULL)
1492 EVP_PKEY_free(pkey);
1493 if (fp != NULL)
1494 Fclose(fp);
1495 NYD_LEAVE;
1496 return rv;
1499 FL FILE *
1500 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1502 FILE *rv = NULL, *yp, *fp, *bp, *hp;
1503 X509 *cert;
1504 PKCS7 *pkcs7;
1505 BIO *bb, *yb;
1506 _STACKOF(X509) *certs;
1507 EVP_CIPHER const *cipher;
1508 char *certfile;
1509 bool_t bail = FAL0;
1510 NYD_ENTER;
1512 if ((certfile = file_expand(xcertfile)) == NULL)
1513 goto jleave;
1515 _ssl_init();
1517 if ((cipher = _smime_cipher(to)) == NULL)
1518 goto jleave;
1519 if ((fp = Fopen(certfile, "r")) == NULL) {
1520 n_perr(certfile, 0);
1521 goto jleave;
1524 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1525 ssl_gen_err(_("Error reading encryption certificate from \"%s\""),
1526 certfile);
1527 bail = TRU1;
1529 Fclose(fp);
1530 if (bail)
1531 goto jleave;
1532 bail = FAL0;
1534 certs = sk_X509_new_null();
1535 sk_X509_push(certs, cert);
1537 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
1538 NULL) {
1539 n_perr(_("tempfile"), 0);
1540 goto jerr1;
1543 rewind(ip);
1544 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1545 Fclose(yp);
1546 goto jerr1;
1549 yb = NULL;
1550 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1551 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1552 ssl_gen_err(_("Error creating BIO encryption objects"));
1553 bail = TRU1;
1554 goto jerr2;
1556 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1557 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
1558 bail = TRU1;
1559 goto jerr2;
1561 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1562 ssl_gen_err(_("Error writing encrypted S/MIME data"));
1563 bail = TRU1;
1564 /* goto jerr2 */
1567 jerr2:
1568 if (bb != NULL)
1569 BIO_free(bb);
1570 if (yb != NULL)
1571 BIO_free(yb);
1572 Fclose(bp);
1573 if (bail)
1574 Fclose(yp);
1575 else {
1576 fflush_rewind(yp);
1577 rv = smime_encrypt_assemble(hp, yp);
1579 jerr1:
1580 sk_X509_pop_free(certs, X509_free);
1581 jleave:
1582 NYD_LEAVE;
1583 return rv;
1586 FL struct message *
1587 smime_decrypt(struct message *m, char const *to, char const *cc, int signcall)
1589 struct message *rv;
1590 FILE *fp, *bp, *hp, *op;
1591 X509 *cert;
1592 PKCS7 *pkcs7;
1593 EVP_PKEY *pkey;
1594 BIO *bb, *pb, *ob;
1595 long size;
1596 FILE *yp;
1597 NYD_ENTER;
1599 rv = NULL;
1600 cert = NULL;
1601 pkey = NULL;
1602 size = m->m_size;
1604 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1605 goto jleave;
1607 _ssl_init();
1609 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
1610 pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL);
1611 if (pkey == NULL) {
1612 ssl_gen_err(_("Error reading private key"));
1613 Fclose(fp);
1614 goto jleave;
1616 rewind(fp);
1618 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1619 ssl_gen_err(_("Error reading decryption certificate"));
1620 Fclose(fp);
1621 EVP_PKEY_free(pkey);
1622 goto jleave;
1624 Fclose(fp);
1627 if ((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
1628 NULL) {
1629 n_perr(_("tempfile"), 0);
1630 goto j_ferr;
1633 if (smime_split(yp, &hp, &bp, size, 1) == STOP)
1634 goto jferr;
1636 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1637 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
1638 ssl_gen_err(_("Error creating BIO decryption objects"));
1639 goto jferr;
1641 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
1642 ssl_gen_err(_("Error reading PKCS#7 object"));
1643 jferr:
1644 Fclose(op);
1645 j_ferr:
1646 if (cert)
1647 X509_free(cert);
1648 if (pkey)
1649 EVP_PKEY_free(pkey);
1650 goto jleave;
1653 if (PKCS7_type_is_signed(pkcs7)) {
1654 if (signcall) {
1655 setinput(&mb, m, NEED_BODY);
1656 rv = (struct message*)-1;
1657 goto jerr2;
1659 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1660 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1661 goto jerr;
1662 fseek(hp, 0L, SEEK_END);
1663 fprintf(hp, "X-Encryption-Cipher: none\n");
1664 fflush(hp);
1665 rewind(hp);
1666 } else if (pkey == NULL) {
1667 n_err(_("No appropriate private key found\n"));
1668 goto jerr2;
1669 } else if (cert == NULL) {
1670 n_err(_("No appropriate certificate found\n"));
1671 goto jerr2;
1672 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
1673 jerr:
1674 ssl_gen_err(_("Error decrypting PKCS#7 object"));
1675 jerr2:
1676 BIO_free(bb);
1677 BIO_free(ob);
1678 Fclose(op);
1679 Fclose(bp);
1680 Fclose(hp);
1681 if (cert != NULL)
1682 X509_free(cert);
1683 if (pkey != NULL)
1684 EVP_PKEY_free(pkey);
1685 goto jleave;
1687 BIO_free(bb);
1688 BIO_free(ob);
1689 if (cert)
1690 X509_free(cert);
1691 if (pkey)
1692 EVP_PKEY_free(pkey);
1693 fflush_rewind(op);
1694 Fclose(bp);
1696 rv = smime_decrypt_assemble(m, hp, op);
1697 jleave:
1698 NYD_LEAVE;
1699 return rv;
1702 FL enum okay
1703 smime_certsave(struct message *m, int n, FILE *op)
1705 struct message *x;
1706 char *to, *cc, *cnttype;
1707 int c, i;
1708 FILE *fp, *ip;
1709 off_t size;
1710 BIO *fb, *pb;
1711 PKCS7 *pkcs7;
1712 _STACKOF(X509) *certs, *chain = NULL;
1713 X509 *cert;
1714 enum okay rv = STOP;
1715 NYD_ENTER;
1717 _ssl_msgno = (size_t)n;
1718 jloop:
1719 to = hfield1("to", m);
1720 cc = hfield1("cc", m);
1721 cnttype = hfield1("content-type", m);
1723 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1724 goto jleave;
1726 #undef _X
1727 #undef _Y
1728 #define _X (sizeof("application/") -1)
1729 #define _Y(X) X, sizeof(X) -1
1730 if (cnttype && is_asccaseprefix(cnttype, "application/") &&
1731 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
1732 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
1733 #undef _Y
1734 #undef _X
1735 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1736 goto jleave;
1737 if (x != (struct message*)-1) {
1738 m = x;
1739 goto jloop;
1742 size = m->m_size;
1744 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600))
1745 == NULL) {
1746 n_perr(_("tempfile"), 0);
1747 goto jleave;
1750 while (size-- > 0) {
1751 c = getc(ip);
1752 putc(c, fp);
1754 fflush(fp);
1756 rewind(fp);
1757 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1758 ssl_gen_err("Error creating BIO object for message %d", n);
1759 Fclose(fp);
1760 goto jleave;
1763 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1764 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1765 BIO_free(fb);
1766 Fclose(fp);
1767 goto jleave;
1769 BIO_free(fb);
1770 Fclose(fp);
1772 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1773 if (certs == NULL) {
1774 n_err(_("No certificates found in message %d\n"), n);
1775 goto jleave;
1778 for (i = 0; i < sk_X509_num(certs); ++i) {
1779 cert = sk_X509_value(certs, i);
1780 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
1781 ssl_gen_err(_("Error writing certificate %d from message %d"),
1782 i, n);
1783 goto jleave;
1786 rv = OKAY;
1787 jleave:
1788 NYD_LEAVE;
1789 return rv;
1791 #endif /* HAVE_OPENSSL */
1793 /* s-it-mode */