cc-test.sh: do a simple \`Resend' test
[s-mailx.git] / openssl.c
blob3942c4c700f6f952d67cd96220f19c2368d0cb43
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 #if defined HAVE_DEVEL && defined HAVE_OPENSSL_MEMHOOKS && defined HAVE_DEBUG
226 static void _ssl_free(void *vp);
227 #endif
228 #ifdef HAVE_SSL_ALL_ALGORITHMS
229 static void _ssl_load_algos(void);
230 #endif
231 #if defined HAVE_OPENSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
232 static void _ssl_atexit(void);
233 #endif
235 static bool_t _ssl_parse_asn1_time(ASN1_TIME *atp,
236 char *bdat, size_t blen);
237 static int _ssl_verify_cb(int success, X509_STORE_CTX *store);
239 /* SSL_CTX configuration */
240 static void * _ssl_conf_setup(SSL_CTX *ctxp);
241 static bool_t _ssl_conf(void *confp, enum ssl_conf_type sct,
242 char const *value);
243 static bool_t _ssl_conf_finish(void **confp, bool_t error);
245 static bool_t _ssl_load_verifications(SSL_CTX *ctxp);
247 static enum okay ssl_check_host(struct sock *sp, struct url const *urlp);
249 static int smime_verify(struct message *m, int n, _STACKOF(X509) *chain,
250 X509_STORE *store);
251 static EVP_CIPHER const * _smime_cipher(char const *name);
252 static int ssl_password_cb(char *buf, int size, int rwflag,
253 void *userdata);
254 static FILE * smime_sign_cert(char const *xname, char const *xname2,
255 bool_t dowarn);
256 static char * _smime_sign_include_certs(char const *name);
257 static bool_t _smime_sign_include_chain_creat(_STACKOF(X509) **chain,
258 char const *cfiles);
259 static EVP_MD const * _smime_sign_digest(char const *name,
260 char const **digname);
261 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
262 static enum okay load_crl1(X509_STORE *store, char const *name);
263 #endif
264 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
266 static int
267 _ssl_rand_init(void)
269 char *cp, *x;
270 int state = 0;
271 NYD_ENTER;
273 #ifdef HAVE_OPENSSL_RAND_EGD
274 if ((cp = ok_vlook(ssl_rand_egd)) != NULL) {
275 if ((x = file_expand(cp)) == NULL || RAND_egd(cp = x) == -1)
276 n_err(_("Entropy daemon at \"%s\" not available\n"), cp);
277 else
278 state = 1;
279 } else
280 #endif
281 if ((cp = ok_vlook(ssl_rand_file)) != NULL) {
282 if ((x = file_expand(cp)) == NULL || RAND_load_file(cp = x, 1024) == -1)
283 n_err(_("Entropy file at \"%s\" not available\n"), cp);
284 else {
285 struct stat st;
287 if (!stat(cp, &st) && S_ISREG(st.st_mode) && !access(cp, W_OK)) {
288 if (RAND_write_file(cp) == -1) {
289 n_err(_("Writing entropy data to \"%s\" failed\n"), cp);
292 state = 1;
295 NYD_LEAVE;
296 return state;
299 static void
300 _ssl_init(void)
302 #ifdef HAVE_OPENSSL_CONFIG
303 char const *cp;
304 #endif
305 NYD_ENTER;
307 if (!(_ssl_state & SS_INIT)) {
308 #if defined HAVE_DEVEL && defined HAVE_OPENSSL_MEMHOOKS
309 # ifdef HAVE_DEBUG
310 CRYPTO_set_mem_ex_functions(&smalloc, &srealloc, &_ssl_free);
311 # else
312 CRYPTO_set_mem_functions(&smalloc, &srealloc, &free);
313 # endif
314 #endif
315 SSL_library_init();
316 SSL_load_error_strings();
317 _ssl_state |= SS_INIT;
320 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
321 #ifdef HAVE_OPENSSL_CONFIG
322 if (!(_ssl_state & SS_CONF_LOAD) &&
323 (cp = ok_vlook(ssl_config_file)) != NULL) {
324 ul_i flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
326 if (*cp == '\0') {
327 cp = NULL;
328 flags = 0;
330 if (CONF_modules_load_file(cp, uagent, flags) == 1) {
331 _ssl_state |= SS_CONF_LOAD;
332 if (!(_ssl_state & SS_EXIT_HDL)) {
333 _ssl_state |= SS_EXIT_HDL;
334 atexit(&_ssl_atexit); /* TODO generic program-wide event mech. */
336 } else
337 ssl_gen_err(_("Ignoring CONF_modules_load_file() load error"));
339 #endif
341 if (!(_ssl_state & SS_RAND_INIT) && _ssl_rand_init())
342 _ssl_state |= SS_RAND_INIT;
343 NYD_LEAVE;
346 #if defined HAVE_DEVEL && defined HAVE_OPENSSL_MEMHOOKS && defined HAVE_DEBUG
347 static void
348 _ssl_free(void *vp)
350 NYD_ENTER;
351 if (vp != NULL)
352 free(vp);
353 NYD_LEAVE;
355 #endif
357 #ifdef HAVE_SSL_ALL_ALGORITHMS
358 static void
359 _ssl_load_algos(void)
361 NYD_ENTER;
362 if (!(_ssl_state & SS_ALGO_LOAD)) {
363 _ssl_state |= SS_ALGO_LOAD;
364 OpenSSL_add_all_algorithms();
366 if (!(_ssl_state & SS_EXIT_HDL)) {
367 _ssl_state |= SS_EXIT_HDL;
368 atexit(&_ssl_atexit); /* TODO generic program-wide event mech. */
371 NYD_LEAVE;
373 #endif
375 #if defined HAVE_OPENSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
376 static void
377 _ssl_atexit(void)
379 NYD_ENTER;
380 # ifdef HAVE_SSL_ALL_ALGORITHMS
381 if (_ssl_state & SS_ALGO_LOAD)
382 EVP_cleanup();
383 # endif
384 # ifdef HAVE_OPENSSL_CONFIG
385 if (_ssl_state & SS_CONF_LOAD)
386 CONF_modules_free();
387 # endif
388 NYD_LEAVE;
390 #endif
392 static bool_t
393 _ssl_parse_asn1_time(ASN1_TIME *atp, char *bdat, size_t blen)
395 BIO *mbp;
396 char *mcp;
397 long l;
398 NYD_ENTER;
400 mbp = BIO_new(BIO_s_mem());
402 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
403 snprintf(bdat, blen, "%.*s", (int)l, mcp);
404 else {
405 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
406 /*is (int)*/atp->length, (char const*)atp->data);
407 mcp = NULL;
410 BIO_free(mbp);
411 NYD_LEAVE;
412 return (mcp != NULL);
415 static int
416 _ssl_verify_cb(int success, X509_STORE_CTX *store)
418 char data[256];
419 X509 *cert;
420 int rv = TRU1;
421 NYD_ENTER;
423 if (success && !(options & OPT_VERB))
424 goto jleave;
426 if (_ssl_msgno != 0) {
427 n_err(_("Message %lu:\n"), (ul_i)_ssl_msgno);
428 _ssl_msgno = 0;
430 n_err(_(" Certificate depth %d %s\n"),
431 X509_STORE_CTX_get_error_depth(store), (success ? "" : _("ERROR")));
433 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
434 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
435 n_err(_(" subject = %s\n"), data);
437 _ssl_parse_asn1_time(X509_get_notBefore(cert), data, sizeof data);
438 n_err(_(" notBefore = %s\n"), data);
440 _ssl_parse_asn1_time(X509_get_notAfter(cert), data, sizeof data);
441 n_err(_(" notAfter = %s\n"), data);
443 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
444 n_err(_(" issuer = %s\n"), data);
447 if (!success) {
448 int err = X509_STORE_CTX_get_error(store);
450 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
451 _ssl_state |= SS_VERIFY_ERROR;
454 if (!success && ssl_verify_decide() != OKAY)
455 rv = FAL0;
456 jleave:
457 NYD_LEAVE;
458 return rv;
461 #ifdef HAVE_OPENSSL_CONF_CTX
462 static void *
463 _ssl_conf_setup(SSL_CTX *ctxp)
465 SSL_CONF_CTX *sccp;
466 NYD_ENTER;
468 if ((sccp = SSL_CONF_CTX_new()) != NULL) {
469 SSL_CONF_CTX_set_flags(sccp,
470 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
471 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
473 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
474 } else
475 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
477 NYD_LEAVE;
478 return sccp;
481 static bool_t
482 _ssl_conf(void *confp, enum ssl_conf_type sct, char const *value)
484 int rv;
485 char const *cmsg;
486 SSL_CONF_CTX *sccp = (SSL_CONF_CTX*)confp;
487 NYD_ENTER;
489 switch (sct) {
490 case SCT_CERTIFICATE:
491 cmsg = "ssl-cert";
492 rv = SSL_CONF_cmd(sccp, "Certificate", value);
493 break;
494 case SCT_CIPHER_STRING:
495 cmsg = "ssl-cipher-list";
496 rv = SSL_CONF_cmd(sccp, "CipherString", value);
497 break;
498 case SCT_PRIVATE_KEY:
499 cmsg = "ssl-key";
500 rv = SSL_CONF_cmd(sccp, "PrivateKey", value);
501 break;
502 default:
503 case SCT_OPTIONS:
504 cmsg = "ssl-options";
505 rv = SSL_CONF_cmd(sccp, "Options", "Bugs");
506 break;
507 case SCT_PROTOCOL:
508 cmsg = "ssl-protocol";
509 rv = SSL_CONF_cmd(sccp, "Protocol", value);
510 break;
513 if (rv == 2)
514 rv = 0;
515 else {
516 if (rv == 0)
517 ssl_gen_err(_("SSL_CONF_CTX_cmd() failed for *%s*"), cmsg);
518 else
519 n_err(_("%s: *%s* implementation error, please report this\n"),
520 uagent, cmsg);
521 rv = 1;
524 NYD_LEAVE;
525 return (rv == 0);
528 static bool_t
529 _ssl_conf_finish(void **confp, bool_t error)
531 SSL_CONF_CTX **sccp = (SSL_CONF_CTX**)confp;
532 bool_t rv;
533 NYD_ENTER;
535 if (!(rv = error))
536 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
538 SSL_CONF_CTX_free(*sccp);
540 *sccp = NULL;
541 NYD_LEAVE;
542 return rv;
545 #else /* HAVE_OPENSSL_CONF_CTX */
546 static void *
547 _ssl_conf_setup(SSL_CTX* ctxp)
549 return ctxp;
552 static bool_t
553 _ssl_conf(void *confp, enum ssl_conf_type sct, char const *value)
555 SSL_CTX *ctxp = (SSL_CTX*)confp;
556 NYD_ENTER;
558 switch (sct) {
559 case SCT_CERTIFICATE:
560 if (SSL_CTX_use_certificate_chain_file(ctxp, value) != 1) {
561 ssl_gen_err(_("Can't load certificate from file \"%s\"\n"), value);
562 confp = NULL;
564 break;
565 case SCT_CIPHER_STRING:
566 if (SSL_CTX_set_cipher_list(ctxp, value) != 1) {
567 ssl_gen_err(_("Invalid cipher string: \"%s\"\n"), value);
568 confp = NULL;
570 break;
571 case SCT_PRIVATE_KEY:
572 if (SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1) {
573 ssl_gen_err(_("Can't load private key from file \"%s\"\n"), value);
574 confp = NULL;
576 break;
577 case SCT_OPTIONS:
578 /* "Options"="Bugs" TODO *ssl-options* */
579 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
580 break;
581 case SCT_PROTOCOL: {
582 char *iolist, *cp, addin;
583 size_t i;
584 sl_i opts = 0;
586 confp = NULL;
587 for (iolist = cp = savestr(value);
588 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;) {
589 if (*cp == '\0') {
590 n_err(_("*ssl-protocol*: empty arguments are not supported\n"));
591 goto jleave;
594 addin = TRU1;
595 switch (cp[0]) {
596 case '-': addin = FAL0; /* FALLTHRU */
597 case '+': ++cp; /* FALLTHRU */
598 default : break;
601 for (i = 0;;) {
602 if (!asccasecmp(cp, _ssl_protocols[i].sp_name)) {
603 /* We need to inverse the meaning of the _NO_s */
604 if (!addin)
605 opts |= _ssl_protocols[i].sp_flag;
606 else
607 opts &= ~_ssl_protocols[i].sp_flag;
608 break;
610 if (++i < NELEM(_ssl_protocols))
611 continue;
612 n_err(_("*ssl-protocol*: unsupported value \"%s\"\n"), cp);
613 goto jleave;
616 confp = ctxp;
617 SSL_CTX_set_options(ctxp, opts);
618 break;
621 jleave:
622 NYD_LEAVE;
623 return (confp != NULL);
626 static bool_t
627 _ssl_conf_finish(void **confp, bool_t error)
629 UNUSED(confp);
630 UNUSED(error);
631 return TRU1;
633 #endif /* !HAVE_OPENSSL_CONF_CTX */
635 static bool_t
636 _ssl_load_verifications(SSL_CTX *ctxp)
638 char *ca_dir, *ca_file;
639 X509_STORE *store;
640 bool_t rv = FAL0;
641 NYD_ENTER;
643 if (ssl_verify_level == SSL_VERIFY_IGNORE) {
644 rv = TRU1;
645 goto jleave;
648 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
649 ca_dir = file_expand(ca_dir);
650 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
651 ca_file = file_expand(ca_file);
653 if ((ca_dir != NULL || ca_file != NULL) &&
654 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1) {
655 char const *m1, *m2, *m3;
657 if (ca_dir != NULL) {
658 m1 = ca_dir;
659 m2 = (ca_file != NULL) ? _(" or ") : "";
660 } else
661 m1 = m2 = "";
662 m3 = (ca_file != NULL) ? ca_file : "";
663 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
664 goto jleave;
667 if (!ok_blook(ssl_no_default_ca) &&
668 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
669 ssl_gen_err(_("Error loading default CA locations\n"));
670 goto jleave;
673 _ssl_state &= ~SS_VERIFY_ERROR;
674 _ssl_msgno = 0;
675 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
676 store = SSL_CTX_get_cert_store(ctxp);
677 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
679 rv = TRU1;
680 jleave:
681 NYD_LEAVE;
682 return rv;
685 static enum okay
686 ssl_check_host(struct sock *sp, struct url const *urlp)
688 char data[256];
689 X509 *cert;
690 _STACKOF(GENERAL_NAME) *gens;
691 GENERAL_NAME *gen;
692 X509_NAME *subj;
693 enum okay rv = STOP;
694 NYD_ENTER;
696 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
697 n_err(_("No certificate from \"%s\"\n"), urlp->url_h_p.s);
698 goto jleave;
701 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
702 if (gens != NULL) {
703 int i;
705 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
706 gen = sk_GENERAL_NAME_value(gens, i);
707 if (gen->type == GEN_DNS) {
708 if (options & OPT_VERB)
709 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
710 urlp->url_host.s, (char*)gen->d.ia5->data);
711 rv = rfc2595_hostname_match(urlp->url_host.s,
712 (char*)gen->d.ia5->data);
713 if (rv == OKAY)
714 goto jdone;
719 if ((subj = X509_get_subject_name(cert)) != NULL &&
720 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
721 > 0) {
722 data[sizeof data - 1] = '\0';
723 if (options & OPT_VERB)
724 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
725 urlp->url_host.s, data);
726 rv = rfc2595_hostname_match(urlp->url_host.s, data);
729 jdone:
730 X509_free(cert);
731 jleave:
732 NYD_LEAVE;
733 return rv;
736 static int
737 smime_verify(struct message *m, int n, _STACKOF(X509) *chain, X509_STORE *store)
739 char data[LINESIZE], *sender, *to, *cc, *cnttype;
740 int rv, c, i, j;
741 struct message *x;
742 FILE *fp, *ip;
743 off_t size;
744 BIO *fb, *pb;
745 PKCS7 *pkcs7;
746 _STACKOF(X509) *certs;
747 _STACKOF(GENERAL_NAME) *gens;
748 X509 *cert;
749 X509_NAME *subj;
750 GENERAL_NAME *gen;
751 NYD_ENTER;
753 rv = 1;
754 fp = NULL;
755 fb = NULL;
756 _ssl_state &= ~SS_VERIFY_ERROR;
757 _ssl_msgno = (size_t)n;
759 for (;;) {
760 sender = getsender(m);
761 to = hfield1("to", m);
762 cc = hfield1("cc", m);
763 cnttype = hfield1("content-type", m);
765 #undef _X
766 #undef _Y
767 #define _X (sizeof("application/") -1)
768 #define _Y(X) X, sizeof(X) -1
769 if (cnttype && is_asccaseprefix(cnttype, "application/") &&
770 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
771 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
772 #undef _Y
773 #undef _X
774 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
775 goto jleave;
776 if (x != (struct message*)-1) {
777 m = x;
778 continue;
782 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
783 goto jleave;
784 size = m->m_size;
785 break;
788 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
789 NULL) {
790 n_perr(_("tempfile"), 0);
791 goto jleave;
793 while (size-- > 0) {
794 c = getc(ip);
795 putc(c, fp);
797 fflush_rewind(fp);
799 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
800 ssl_gen_err(_(
801 "Error creating BIO verification object for message %d"), n);
802 goto jleave;
805 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
806 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
807 goto jleave;
809 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
810 ssl_gen_err(_("Error verifying message %d"), n);
811 goto jleave;
814 if (sender == NULL) {
815 n_err(_("Warning: Message %d has no sender\n"), n);
816 rv = 0;
817 goto jleave;
820 certs = PKCS7_get0_signers(pkcs7, chain, 0);
821 if (certs == NULL) {
822 n_err(_("No certificates found in message %d\n"), n);
823 goto jleave;
826 for (i = 0; i < sk_X509_num(certs); ++i) {
827 cert = sk_X509_value(certs, i);
828 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
829 if (gens != NULL) {
830 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
831 gen = sk_GENERAL_NAME_value(gens, j);
832 if (gen->type == GEN_EMAIL) {
833 if (options & OPT_VERB)
834 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
835 sender, (char*)gen->d.ia5->data);
836 if (!asccasecmp((char*)gen->d.ia5->data, sender))
837 goto jfound;
842 if ((subj = X509_get_subject_name(cert)) != NULL &&
843 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
844 data, sizeof data) > 0) {
845 data[sizeof data -1] = '\0';
846 if (options & OPT_VERB)
847 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
848 sender, data);
849 if (!asccasecmp(data, sender))
850 goto jfound;
853 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
854 goto jleave;
855 jfound:
856 rv = ((_ssl_state & SS_VERIFY_ERROR) != 0);
857 if (!rv)
858 printf(_("Message %d was verified successfully\n"), n);
859 jleave:
860 if (fb != NULL)
861 BIO_free(fb);
862 if (fp != NULL)
863 Fclose(fp);
864 NYD_LEAVE;
865 return rv;
868 static EVP_CIPHER const *
869 _smime_cipher(char const *name)
871 EVP_CIPHER const *cipher;
872 char *vn;
873 char const *cp;
874 size_t i;
875 NYD_ENTER;
877 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
878 snprintf(vn, (int)i, "smime-cipher-%s", name);
879 cp = vok_vlook(vn);
880 ac_free(vn);
882 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
883 cipher = _SMIME_DEFAULT_CIPHER();
884 goto jleave;
886 cipher = NULL;
888 for (i = 0; i < NELEM(_smime_ciphers); ++i)
889 if (!asccasecmp(_smime_ciphers[i].sc_name, cp)) {
890 cipher = (*_smime_ciphers[i].sc_fun)();
891 goto jleave;
893 #ifndef OPENSSL_NO_AES
894 for (i = 0; i < NELEM(_smime_ciphers_obs); ++i) /* TODO obsolete */
895 if (!asccasecmp(_smime_ciphers_obs[i].sc_name, cp)) {
896 OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
897 cipher = (*_smime_ciphers_obs[i].sc_fun)();
898 goto jleave;
900 #endif
902 /* Not a builtin algorithm, but we may have dynamic support for more */
903 #ifdef HAVE_SSL_ALL_ALGORITHMS
904 _ssl_load_algos();
905 if ((cipher = EVP_get_cipherbyname(cp)) != NULL)
906 goto jleave;
907 #endif
909 n_err(_("Invalid S/MIME cipher(s): \"%s\"\n"), cp);
910 jleave:
911 NYD_LEAVE;
912 return cipher;
915 static int
916 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
918 char *pass;
919 size_t len;
920 NYD_ENTER;
921 UNUSED(rwflag);
922 UNUSED(userdata);
924 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
925 len = strlen(pass);
926 if (UICMP(z, len, >=, size))
927 len = size -1;
928 memcpy(buf, pass, len);
929 buf[len] = '\0';
930 } else
931 len = 0;
932 NYD_LEAVE;
933 return (int)len;
936 static FILE *
937 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn)
939 char *vn, *cp;
940 int vs;
941 struct name *np;
942 char const *name = xname, *name2 = xname2;
943 FILE *fp = NULL;
944 NYD_ENTER;
946 jloop:
947 if (name) {
948 np = lextract(name, GTO | GSKIN);
949 while (np != NULL) {
950 /* This needs to be more intelligent since it will currently take the
951 * first name for which a private key is available regardless of
952 * whether it is the right one for the message */
953 vn = ac_alloc(vs = strlen(np->n_name) + 30);
954 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
955 cp = vok_vlook(vn);
956 ac_free(vn);
957 if (cp != NULL)
958 goto jopen;
959 np = np->n_flink;
961 if (name2 != NULL) {
962 name = name2;
963 name2 = NULL;
964 goto jloop;
968 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
969 goto jerr;
970 jopen:
971 if ((cp = file_expand(cp)) == NULL)
972 goto jleave;
973 if ((fp = Fopen(cp, "r")) == NULL)
974 n_perr(cp, 0);
975 jleave:
976 NYD_LEAVE;
977 return fp;
978 jerr:
979 if (dowarn)
980 n_err(_("Could not find a certificate for %s%s%s\n"),
981 xname, (xname2 != NULL ? _("or ") : ""),
982 (xname2 != NULL ? xname2 : ""));
983 goto jleave;
986 static char *
987 _smime_sign_include_certs(char const *name)
989 char *rv;
990 NYD_ENTER;
992 /* See comments in smime_sign_cert() for algorithm pitfalls */
993 if (name != NULL) {
994 struct name *np;
996 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
997 int vs;
998 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
999 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1000 rv = vok_vlook(vn);
1001 ac_free(vn);
1002 if (rv != NULL)
1003 goto jleave;
1006 rv = ok_vlook(smime_sign_include_certs);
1007 jleave:
1008 NYD_LEAVE;
1009 return rv;
1012 static bool_t
1013 _smime_sign_include_chain_creat(_STACKOF(X509) **chain, char const *cfiles)
1015 X509 *tmp;
1016 FILE *fp;
1017 char *nfield, *cfield, *x;
1018 NYD_ENTER;
1020 *chain = sk_X509_new_null();
1022 for (nfield = savestr(cfiles);
1023 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1024 if ((x = file_expand(cfield)) == NULL ||
1025 (fp = Fopen(cfield = x, "r")) == NULL) {
1026 n_perr(cfiles, 0);
1027 goto jerr;
1029 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1030 ssl_gen_err(_("Error reading certificate from \"%s\""), cfield);
1031 Fclose(fp);
1032 goto jerr;
1034 sk_X509_push(*chain, tmp);
1035 Fclose(fp);
1038 if (sk_X509_num(*chain) == 0) {
1039 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1040 goto jerr;
1042 jleave:
1043 NYD_LEAVE;
1044 return (*chain != NULL);
1045 jerr:
1046 sk_X509_pop_free(*chain, X509_free);
1047 *chain = NULL;
1048 goto jleave;
1051 static EVP_MD const *
1052 _smime_sign_digest(char const *name, char const **digname)
1054 EVP_MD const *digest;
1055 char const *cp;
1056 size_t i;
1057 NYD_ENTER;
1059 /* See comments in smime_sign_cert() for algorithm pitfalls */
1060 if (name != NULL) {
1061 struct name *np;
1063 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1064 int vs;
1065 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1066 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1067 cp = vok_vlook(vn);
1068 ac_free(vn);
1069 if (cp != NULL)
1070 goto jhave_name;
1074 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1075 digest = _SMIME_DEFAULT_DIGEST();
1076 *digname = _SMIME_DEFAULT_DIGEST_S;
1077 goto jleave;
1080 jhave_name:
1081 i = strlen(cp);
1082 { char *x = salloc(i +1);
1083 i_strcpy(x, cp, i +1);
1084 cp = x;
1086 *digname = cp;
1088 for (i = 0; i < NELEM(_smime_digests); ++i)
1089 if (!strcmp(_smime_digests[i].sd_name, cp)) {
1090 digest = (*_smime_digests[i].sd_fun)();
1091 goto jleave;
1094 /* Not a builtin algorithm, but we may have dynamic support for more */
1095 #ifdef HAVE_SSL_ALL_ALGORITHMS
1096 _ssl_load_algos();
1097 if ((digest = EVP_get_digestbyname(cp)) != NULL)
1098 goto jleave;
1099 #endif
1101 n_err(_("Invalid message digest: \"%s\"\n"), cp);
1102 digest = NULL;
1103 jleave:
1104 NYD_LEAVE;
1105 return digest;
1108 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1109 static enum okay
1110 load_crl1(X509_STORE *store, char const *name)
1112 X509_LOOKUP *lookup;
1113 enum okay rv = STOP;
1114 NYD_ENTER;
1116 if (options & OPT_VERB)
1117 n_err(_("Loading CRL from \"%s\"\n"), name);
1118 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1119 ssl_gen_err(_("Error creating X509 lookup object"));
1120 goto jleave;
1122 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1123 ssl_gen_err(_("Error loading CRL from \"%s\""), name);
1124 goto jleave;
1126 rv = OKAY;
1127 jleave:
1128 NYD_LEAVE;
1129 return rv;
1131 #endif /* new OpenSSL */
1133 static enum okay
1134 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1136 char *crl_file, *crl_dir;
1137 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1138 DIR *dirp;
1139 struct dirent *dp;
1140 char *fn = NULL;
1141 int fs = 0, ds, es;
1142 #endif
1143 enum okay rv = STOP;
1144 NYD_ENTER;
1146 if ((crl_file = _var_oklook(fok)) != NULL) {
1147 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1148 if ((crl_file = file_expand(crl_file)) == NULL ||
1149 load_crl1(store, crl_file) != OKAY)
1150 goto jleave;
1151 #else
1152 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1153 goto jleave;
1154 #endif
1157 if ((crl_dir = _var_oklook(dok)) != NULL) {
1158 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1159 char *x;
1160 if ((x = file_expand(crl_dir)) == NULL ||
1161 (dirp = opendir(crl_dir = x)) == NULL) {
1162 n_perr(crl_dir, 0);
1163 goto jleave;
1166 ds = strlen(crl_dir);
1167 fn = smalloc(fs = ds + 20);
1168 memcpy(fn, crl_dir, ds);
1169 fn[ds] = '/';
1170 while ((dp = readdir(dirp)) != NULL) {
1171 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1172 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1173 continue;
1174 if (dp->d_name[0] == '.')
1175 continue;
1176 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1177 fn = srealloc(fn, fs = ds + es + 20);
1178 memcpy(fn + ds + 1, dp->d_name, es + 1);
1179 if (load_crl1(store, fn) != OKAY) {
1180 closedir(dirp);
1181 free(fn);
1182 goto jleave;
1185 closedir(dirp);
1186 free(fn);
1187 #else /* old OpenSSL */
1188 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1189 goto jleave;
1190 #endif
1192 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1193 if (crl_file || crl_dir)
1194 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1195 X509_V_FLAG_CRL_CHECK_ALL);
1196 #endif
1197 rv = OKAY;
1198 jleave:
1199 NYD_LEAVE;
1200 return rv;
1203 FL enum okay
1204 ssl_open(struct url const *urlp, struct sock *sp)
1206 SSL_CTX *ctxp;
1207 void *confp;
1208 char const *cp, *cp_base;
1209 size_t i;
1210 enum okay rv = STOP;
1211 NYD_ENTER;
1213 _ssl_init();
1215 ssl_set_verify_level(urlp);
1217 if ((ctxp = SSL_CTX_new(_SSL_CLIENT_METHOD())) == NULL) {
1218 ssl_gen_err(_("SSL_CTX_new() failed"));
1219 goto jleave;
1222 /* Available with OpenSSL 0.9.6 or later */
1223 #ifdef SSL_MODE_AUTO_RETRY
1224 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1225 #endif
1227 if ((confp = _ssl_conf_setup(ctxp)) == NULL)
1228 goto jerr0;
1230 /* TODO obsolete Check for *ssl-method*, warp to a *ssl-protocol* value */
1231 if ((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL) {
1232 OBSOLETE(_("please use *ssl-protocol* instead of *ssl-method*"));
1233 if (options & OPT_VERB)
1234 n_err(_("*ssl-method*: \"%s\"\n"), cp);
1235 for (i = 0;;) {
1236 if (!asccasecmp(_ssl_methods[i].sm_name, cp)) {
1237 cp = _ssl_methods[i].sm_map;
1238 break;
1240 if (++i == NELEM(_ssl_methods)) {
1241 n_err(_("Unsupported TLS/SSL method \"%s\"\n"), cp);
1242 goto jerr1;
1246 /* *ssl-protocol* */
1247 if ((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL) {
1248 if (options & OPT_VERB)
1249 n_err(_("*ssl-protocol*: \"%s\"\n"), cp_base);
1250 cp = cp_base;
1252 cp = (cp != NULL ? savecatsep(cp, ',', SSL_DISABLED_PROTOCOLS)
1253 : SSL_DISABLED_PROTOCOLS);
1254 if (!_ssl_conf(confp, SCT_PROTOCOL, cp))
1255 goto jerr1;
1257 /* *ssl-cert* */
1258 if ((cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL) {
1259 if (options & OPT_VERB)
1260 n_err(_("*ssl-cert* \"%s\"\n"), cp);
1261 if ((cp_base = file_expand(cp)) == NULL) {
1262 n_err(_("*ssl-cert* value expansion failed: \"%s\"\n"), cp);
1263 goto jerr1;
1265 cp = cp_base;
1266 if (!_ssl_conf(confp, SCT_CERTIFICATE, cp))
1267 goto jerr1;
1269 /* *ssl-key* */
1270 if ((cp_base = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL) {
1271 if (options & OPT_VERB)
1272 n_err(_("*ssl-key* \"%s\"\n"), cp_base);
1273 if ((cp = file_expand(cp_base)) == NULL) {
1274 n_err(_("*ssl-key* value expansion failed: \"%s\"\n"), cp_base);
1275 goto jerr1;
1278 if (!_ssl_conf(confp, SCT_PRIVATE_KEY, cp))
1279 goto jerr1;
1282 if ((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL &&
1283 !_ssl_conf(confp, SCT_CIPHER_STRING, cp))
1284 goto jerr1;
1286 if (!_ssl_load_verifications(ctxp))
1287 goto jerr1;
1289 if (!_ssl_conf(confp, SCT_OPTIONS, NULL)) /* TODO *ssl-options* */
1290 goto jerr1;
1292 /* Done with context setup, create our new per-connection structure */
1293 if (!_ssl_conf_finish(&confp, FAL0))
1294 goto jerr0;
1296 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1297 ssl_gen_err(_("SSL_new() failed"));
1298 goto jerr0;
1301 SSL_set_fd(sp->s_ssl, sp->s_fd);
1303 if (SSL_connect(sp->s_ssl) < 0) {
1304 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1305 goto jerr2;
1308 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1309 if (ssl_check_host(sp, urlp) != OKAY) {
1310 n_err(_("Host certificate does not match \"%s\"\n"),
1311 urlp->url_h_p.s);
1312 if (ssl_verify_decide() != OKAY)
1313 goto jerr2;
1317 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1318 * and free it right now -- it is reference counted by sp->s_ssl.. */
1319 SSL_CTX_free(ctxp);
1320 sp->s_use_ssl = 1;
1321 rv = OKAY;
1322 jleave:
1323 NYD_LEAVE;
1324 return rv;
1325 jerr2:
1326 SSL_free(sp->s_ssl);
1327 sp->s_ssl = NULL;
1328 jerr1:
1329 if (confp != NULL)
1330 _ssl_conf_finish(&confp, TRU1);
1331 jerr0:
1332 SSL_CTX_free(ctxp);
1333 goto jleave;
1336 FL void
1337 ssl_gen_err(char const *fmt, ...)
1339 va_list ap;
1340 NYD_ENTER;
1342 va_start(ap, fmt);
1343 n_verr(fmt, ap);
1344 va_end(ap);
1346 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1347 NYD_LEAVE;
1350 FL int
1351 c_verify(void *vp)
1353 int *msgvec = vp, *ip, ec = 0, rv = 1;
1354 _STACKOF(X509) *chain = NULL;
1355 X509_STORE *store = NULL;
1356 char *ca_dir, *ca_file;
1357 NYD_ENTER;
1359 _ssl_init();
1361 ssl_verify_level = SSL_VERIFY_STRICT;
1362 if ((store = X509_STORE_new()) == NULL) {
1363 ssl_gen_err(_("Error creating X509 store"));
1364 goto jleave;
1366 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1368 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1369 ca_dir = file_expand(ca_dir);
1370 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1371 ca_file = file_expand(ca_file);
1373 if (ca_dir != NULL || ca_file != NULL) {
1374 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
1375 ssl_gen_err(_("Error loading %s"),
1376 (ca_file != NULL) ? ca_file : ca_dir);
1377 goto jleave;
1380 if (!ok_blook(smime_no_default_ca)) {
1381 if (X509_STORE_set_default_paths(store) != 1) {
1382 ssl_gen_err(_("Error loading default CA locations"));
1383 goto jleave;
1387 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1388 goto jleave;
1390 for (ip = msgvec; *ip != 0; ++ip) {
1391 struct message *mp = message + *ip - 1;
1392 setdot(mp);
1393 ec |= smime_verify(mp, *ip, chain, store);
1395 if ((rv = ec) != 0)
1396 exit_status |= EXIT_ERR;
1397 jleave:
1398 if (store != NULL)
1399 X509_STORE_free(store);
1400 NYD_LEAVE;
1401 return rv;
1404 FL FILE *
1405 smime_sign(FILE *ip, char const *addr)
1407 FILE *rv = NULL, *sp = NULL, *fp = NULL, *bp, *hp;
1408 X509 *cert = NULL;
1409 _STACKOF(X509) *chain = NULL;
1410 EVP_PKEY *pkey = NULL;
1411 BIO *bb, *sb;
1412 PKCS7 *pkcs7;
1413 EVP_MD const *md;
1414 char const *name;
1415 bool_t bail = FAL0;
1416 NYD_ENTER;
1418 _ssl_init();
1420 if (addr == NULL) {
1421 n_err(_("No *from* address for signing specified\n"));
1422 goto jleave;
1424 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
1425 goto jleave;
1427 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1428 ssl_gen_err(_("Error reading private key from"));
1429 goto jleave;
1432 rewind(fp);
1433 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1434 ssl_gen_err(_("Error reading signer certificate from"));
1435 goto jleave;
1437 Fclose(fp);
1438 fp = NULL;
1440 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1441 !_smime_sign_include_chain_creat(&chain, name))
1442 goto jleave;
1444 name = NULL;
1445 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1446 goto jleave;
1448 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600))
1449 == NULL) {
1450 n_perr(_("tempfile"), 0);
1451 goto jleave;
1454 rewind(ip);
1455 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1456 goto jerr1;
1458 sb = NULL;
1459 pkcs7 = NULL;
1461 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1462 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1463 ssl_gen_err(_("Error creating BIO signing objects"));
1464 bail = TRU1;
1465 goto jerr;
1468 #undef _X
1469 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1470 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1471 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1472 bail = TRU1;
1473 goto jerr;
1475 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1476 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1477 bail = TRU1;
1478 goto jerr;
1480 if (!PKCS7_final(pkcs7, bb, _X)) {
1481 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1482 bail = TRU1;
1483 goto jerr;
1485 #undef _X
1487 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1488 ssl_gen_err(_("Error writing signed S/MIME data"));
1489 bail = TRU1;
1490 /*goto jerr*/
1492 jerr:
1493 if (pkcs7 != NULL)
1494 PKCS7_free(pkcs7);
1495 if (sb != NULL)
1496 BIO_free(sb);
1497 if (bb != NULL)
1498 BIO_free(bb);
1499 if (!bail) {
1500 rewind(bp);
1501 fflush_rewind(sp);
1502 rv = smime_sign_assemble(hp, bp, sp, name);
1503 } else
1504 jerr1:
1505 Fclose(sp);
1507 jleave:
1508 if (chain != NULL)
1509 sk_X509_pop_free(chain, X509_free);
1510 if (cert != NULL)
1511 X509_free(cert);
1512 if (pkey != NULL)
1513 EVP_PKEY_free(pkey);
1514 if (fp != NULL)
1515 Fclose(fp);
1516 NYD_LEAVE;
1517 return rv;
1520 FL FILE *
1521 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1523 FILE *rv = NULL, *yp, *fp, *bp, *hp;
1524 X509 *cert;
1525 PKCS7 *pkcs7;
1526 BIO *bb, *yb;
1527 _STACKOF(X509) *certs;
1528 EVP_CIPHER const *cipher;
1529 char *certfile;
1530 bool_t bail = FAL0;
1531 NYD_ENTER;
1533 if ((certfile = file_expand(xcertfile)) == NULL)
1534 goto jleave;
1536 _ssl_init();
1538 if ((cipher = _smime_cipher(to)) == NULL)
1539 goto jleave;
1540 if ((fp = Fopen(certfile, "r")) == NULL) {
1541 n_perr(certfile, 0);
1542 goto jleave;
1545 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1546 ssl_gen_err(_("Error reading encryption certificate from \"%s\""),
1547 certfile);
1548 bail = TRU1;
1550 Fclose(fp);
1551 if (bail)
1552 goto jleave;
1553 bail = FAL0;
1555 certs = sk_X509_new_null();
1556 sk_X509_push(certs, cert);
1558 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
1559 NULL) {
1560 n_perr(_("tempfile"), 0);
1561 goto jerr1;
1564 rewind(ip);
1565 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1566 Fclose(yp);
1567 goto jerr1;
1570 yb = NULL;
1571 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1572 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1573 ssl_gen_err(_("Error creating BIO encryption objects"));
1574 bail = TRU1;
1575 goto jerr2;
1577 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1578 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
1579 bail = TRU1;
1580 goto jerr2;
1582 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1583 ssl_gen_err(_("Error writing encrypted S/MIME data"));
1584 bail = TRU1;
1585 /* goto jerr2 */
1588 jerr2:
1589 if (bb != NULL)
1590 BIO_free(bb);
1591 if (yb != NULL)
1592 BIO_free(yb);
1593 Fclose(bp);
1594 if (bail)
1595 Fclose(yp);
1596 else {
1597 fflush_rewind(yp);
1598 rv = smime_encrypt_assemble(hp, yp);
1600 jerr1:
1601 sk_X509_pop_free(certs, X509_free);
1602 jleave:
1603 NYD_LEAVE;
1604 return rv;
1607 FL struct message *
1608 smime_decrypt(struct message *m, char const *to, char const *cc, int signcall)
1610 struct message *rv;
1611 FILE *fp, *bp, *hp, *op;
1612 X509 *cert;
1613 PKCS7 *pkcs7;
1614 EVP_PKEY *pkey;
1615 BIO *bb, *pb, *ob;
1616 long size;
1617 FILE *yp;
1618 NYD_ENTER;
1620 rv = NULL;
1621 cert = NULL;
1622 pkey = NULL;
1623 size = m->m_size;
1625 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1626 goto jleave;
1628 _ssl_init();
1630 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
1631 pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL);
1632 if (pkey == NULL) {
1633 ssl_gen_err(_("Error reading private key"));
1634 Fclose(fp);
1635 goto jleave;
1637 rewind(fp);
1639 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1640 ssl_gen_err(_("Error reading decryption certificate"));
1641 Fclose(fp);
1642 EVP_PKEY_free(pkey);
1643 goto jleave;
1645 Fclose(fp);
1648 if ((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
1649 NULL) {
1650 n_perr(_("tempfile"), 0);
1651 goto j_ferr;
1654 if (smime_split(yp, &hp, &bp, size, 1) == STOP)
1655 goto jferr;
1657 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1658 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
1659 ssl_gen_err(_("Error creating BIO decryption objects"));
1660 goto jferr;
1662 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
1663 ssl_gen_err(_("Error reading PKCS#7 object"));
1664 jferr:
1665 Fclose(op);
1666 j_ferr:
1667 if (cert)
1668 X509_free(cert);
1669 if (pkey)
1670 EVP_PKEY_free(pkey);
1671 goto jleave;
1674 if (PKCS7_type_is_signed(pkcs7)) {
1675 if (signcall) {
1676 setinput(&mb, m, NEED_BODY);
1677 rv = (struct message*)-1;
1678 goto jerr2;
1680 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1681 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1682 goto jerr;
1683 fseek(hp, 0L, SEEK_END);
1684 fprintf(hp, "X-Encryption-Cipher: none\n");
1685 fflush(hp);
1686 rewind(hp);
1687 } else if (pkey == NULL) {
1688 n_err(_("No appropriate private key found\n"));
1689 goto jerr2;
1690 } else if (cert == NULL) {
1691 n_err(_("No appropriate certificate found\n"));
1692 goto jerr2;
1693 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
1694 jerr:
1695 ssl_gen_err(_("Error decrypting PKCS#7 object"));
1696 jerr2:
1697 BIO_free(bb);
1698 BIO_free(ob);
1699 Fclose(op);
1700 Fclose(bp);
1701 Fclose(hp);
1702 if (cert != NULL)
1703 X509_free(cert);
1704 if (pkey != NULL)
1705 EVP_PKEY_free(pkey);
1706 goto jleave;
1708 BIO_free(bb);
1709 BIO_free(ob);
1710 if (cert)
1711 X509_free(cert);
1712 if (pkey)
1713 EVP_PKEY_free(pkey);
1714 fflush_rewind(op);
1715 Fclose(bp);
1717 rv = smime_decrypt_assemble(m, hp, op);
1718 jleave:
1719 NYD_LEAVE;
1720 return rv;
1723 FL enum okay
1724 smime_certsave(struct message *m, int n, FILE *op)
1726 struct message *x;
1727 char *to, *cc, *cnttype;
1728 int c, i;
1729 FILE *fp, *ip;
1730 off_t size;
1731 BIO *fb, *pb;
1732 PKCS7 *pkcs7;
1733 _STACKOF(X509) *certs, *chain = NULL;
1734 X509 *cert;
1735 enum okay rv = STOP;
1736 NYD_ENTER;
1738 _ssl_msgno = (size_t)n;
1739 jloop:
1740 to = hfield1("to", m);
1741 cc = hfield1("cc", m);
1742 cnttype = hfield1("content-type", m);
1744 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1745 goto jleave;
1747 #undef _X
1748 #undef _Y
1749 #define _X (sizeof("application/") -1)
1750 #define _Y(X) X, sizeof(X) -1
1751 if (cnttype && is_asccaseprefix(cnttype, "application/") &&
1752 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
1753 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
1754 #undef _Y
1755 #undef _X
1756 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1757 goto jleave;
1758 if (x != (struct message*)-1) {
1759 m = x;
1760 goto jloop;
1763 size = m->m_size;
1765 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600))
1766 == NULL) {
1767 n_perr(_("tempfile"), 0);
1768 goto jleave;
1771 while (size-- > 0) {
1772 c = getc(ip);
1773 putc(c, fp);
1775 fflush(fp);
1777 rewind(fp);
1778 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1779 ssl_gen_err("Error creating BIO object for message %d", n);
1780 Fclose(fp);
1781 goto jleave;
1784 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1785 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1786 BIO_free(fb);
1787 Fclose(fp);
1788 goto jleave;
1790 BIO_free(fb);
1791 Fclose(fp);
1793 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1794 if (certs == NULL) {
1795 n_err(_("No certificates found in message %d\n"), n);
1796 goto jleave;
1799 for (i = 0; i < sk_X509_num(certs); ++i) {
1800 cert = sk_X509_value(certs, i);
1801 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
1802 ssl_gen_err(_("Error writing certificate %d from message %d"),
1803 i, n);
1804 goto jleave;
1807 rv = OKAY;
1808 jleave:
1809 NYD_LEAVE;
1810 return rv;
1812 #endif /* HAVE_OPENSSL */
1814 /* s-it-mode */