mk-release.inc: auto-append checksum file to announcement mail
[s-mailx.git] / openssl.c
blob999a31a063673ab0701c888dee35525de0aa6d6f
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 - 2016 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
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"),
285 n_shexp_quote_cp(cp, FAL0));
286 #else
287 if(options & OPT_D_VV)
288 n_err(_("*ssl_rand_egd* (%s): unsupported by SSL library\n"),
289 n_shexp_quote_cp(cp, FAL0));
290 #endif
293 /* Prefer possible user setting */
294 if((cp = ok_vlook(ssl_rand_file)) != NULL){
295 x = NULL;
296 if(*cp != '\0'){
297 if((x = file_expand(cp)) == NULL)
298 n_err(_("*ssl-rand-file*: filename expansion of %s failed\n"),
299 n_shexp_quote_cp(cp, FAL0));
301 cp = x;
304 /* If the SSL PRNG is initialized don't put any more effort in this if the
305 * user defined entropy isn't usable */
306 if(cp == NULL){
307 if(RAND_status()){
308 rv = TRU1;
309 goto jleave;
312 if((cp = RAND_file_name(salloc(PATH_MAX), PATH_MAX)) == NULL){
313 n_err(_("*ssl-rand-file*: no SSL entropy file, can't seed PRNG\n"));
314 goto jleave;
318 if(RAND_load_file(cp, _RAND_LOAD_FILE_MAXBYTES) != -1){
319 for(x = (char*)-1;;){
320 RAND_seed(getrandstring(32), 32);
321 if((rv = (RAND_status() != 0)))
322 break;
323 if((x = (char*)((uintptr_t)x >> 1)) == NULL){
324 n_err(_("*ssl-rand-file*: can't seed SSL PRNG with entropy\n"));
325 goto jleave;
329 if(RAND_write_file(cp) == -1)
330 n_err(_("*ssl-rand-file*: writing entropy to %s failed\n"),
331 n_shexp_quote_cp(cp, FAL0));
332 }else
333 n_err(_("*ssl-rand-file*: %s cannot be loaded\n"),
334 n_shexp_quote_cp(cp, FAL0));
335 jleave:
336 NYD_LEAVE;
337 return rv;
340 static void
341 _ssl_init(void)
343 #ifdef HAVE_OPENSSL_CONFIG
344 char const *cp;
345 #endif
346 NYD_ENTER;
348 if (!(_ssl_state & SS_INIT)) {
349 SSL_load_error_strings();
350 SSL_library_init();
351 _ssl_state |= SS_INIT;
354 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
355 #ifdef HAVE_OPENSSL_CONFIG
356 if (!(_ssl_state & SS_CONF_LOAD) &&
357 (cp = ok_vlook(ssl_config_file)) != NULL) {
358 ul_i flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
360 if (*cp == '\0') {
361 cp = NULL;
362 flags = 0;
364 if (CONF_modules_load_file(cp, uagent, flags) == 1) {
365 _ssl_state |= SS_CONF_LOAD;
366 if (!(_ssl_state & SS_EXIT_HDL)) {
367 _ssl_state |= SS_EXIT_HDL;
368 atexit(&_ssl_atexit); /* TODO generic program-wide event mech. */
370 } else
371 ssl_gen_err(_("Ignoring CONF_modules_load_file() load error"));
373 #endif
375 if (!(_ssl_state & SS_RAND_INIT) && _ssl_rand_init())
376 _ssl_state |= SS_RAND_INIT;
377 NYD_LEAVE;
380 #ifdef HAVE_SSL_ALL_ALGORITHMS
381 static void
382 _ssl_load_algos(void)
384 NYD_ENTER;
385 if (!(_ssl_state & SS_ALGO_LOAD)) {
386 _ssl_state |= SS_ALGO_LOAD;
387 OpenSSL_add_all_algorithms();
389 if (!(_ssl_state & SS_EXIT_HDL)) {
390 _ssl_state |= SS_EXIT_HDL;
391 atexit(&_ssl_atexit); /* TODO generic program-wide event mech. */
394 NYD_LEAVE;
396 #endif
398 #if defined HAVE_OPENSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
399 static void
400 _ssl_atexit(void)
402 NYD_ENTER;
403 # ifdef HAVE_SSL_ALL_ALGORITHMS
404 if (_ssl_state & SS_ALGO_LOAD)
405 EVP_cleanup();
406 # endif
407 # ifdef HAVE_OPENSSL_CONFIG
408 if (_ssl_state & SS_CONF_LOAD)
409 CONF_modules_free();
410 # endif
411 NYD_LEAVE;
413 #endif
415 static bool_t
416 _ssl_parse_asn1_time(ASN1_TIME *atp, char *bdat, size_t blen)
418 BIO *mbp;
419 char *mcp;
420 long l;
421 NYD_ENTER;
423 mbp = BIO_new(BIO_s_mem());
425 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
426 snprintf(bdat, blen, "%.*s", (int)l, mcp);
427 else {
428 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
429 /*is (int)*/atp->length, (char const*)atp->data);
430 mcp = NULL;
433 BIO_free(mbp);
434 NYD_LEAVE;
435 return (mcp != NULL);
438 static int
439 _ssl_verify_cb(int success, X509_STORE_CTX *store)
441 char data[256];
442 X509 *cert;
443 int rv = TRU1;
444 NYD_ENTER;
446 if (success && !(options & OPT_VERB))
447 goto jleave;
449 if (_ssl_msgno != 0) {
450 n_err(_("Message %lu:\n"), (ul_i)_ssl_msgno);
451 _ssl_msgno = 0;
453 n_err(_(" Certificate depth %d %s\n"),
454 X509_STORE_CTX_get_error_depth(store), (success ? "" : _("ERROR")));
456 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
457 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
458 n_err(_(" subject = %s\n"), data);
460 _ssl_parse_asn1_time(X509_get_notBefore(cert), data, sizeof data);
461 n_err(_(" notBefore = %s\n"), data);
463 _ssl_parse_asn1_time(X509_get_notAfter(cert), data, sizeof data);
464 n_err(_(" notAfter = %s\n"), data);
466 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
467 n_err(_(" issuer = %s\n"), data);
470 if (!success) {
471 int err = X509_STORE_CTX_get_error(store);
473 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
474 _ssl_state |= SS_VERIFY_ERROR;
477 if (!success && ssl_verify_decide() != OKAY)
478 rv = FAL0;
479 jleave:
480 NYD_LEAVE;
481 return rv;
484 #ifdef HAVE_OPENSSL_CONF_CTX
485 static void *
486 _ssl_conf_setup(SSL_CTX *ctxp)
488 SSL_CONF_CTX *sccp;
489 NYD_ENTER;
491 if ((sccp = SSL_CONF_CTX_new()) != NULL) {
492 SSL_CONF_CTX_set_flags(sccp,
493 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
494 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
496 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
497 } else
498 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
500 NYD_LEAVE;
501 return sccp;
504 static bool_t
505 _ssl_conf(void *confp, enum ssl_conf_type sct, char const *value)
507 int rv;
508 char const *cmsg;
509 SSL_CONF_CTX *sccp = (SSL_CONF_CTX*)confp;
510 NYD_ENTER;
512 switch (sct) {
513 case SCT_CERTIFICATE:
514 cmsg = "ssl-cert";
515 rv = SSL_CONF_cmd(sccp, "Certificate", value);
516 break;
517 case SCT_CIPHER_STRING:
518 cmsg = "ssl-cipher-list";
519 rv = SSL_CONF_cmd(sccp, "CipherString", value);
520 break;
521 case SCT_PRIVATE_KEY:
522 cmsg = "ssl-key";
523 rv = SSL_CONF_cmd(sccp, "PrivateKey", value);
524 break;
525 default:
526 case SCT_OPTIONS:
527 cmsg = "ssl-options";
528 rv = SSL_CONF_cmd(sccp, "Options", "Bugs");
529 break;
530 case SCT_PROTOCOL:
531 cmsg = "ssl-protocol";
532 rv = SSL_CONF_cmd(sccp, "Protocol", value);
533 break;
536 if (rv == 2)
537 rv = 0;
538 else {
539 if (rv == 0)
540 ssl_gen_err(_("SSL_CONF_CTX_cmd() failed for *%s*"), cmsg);
541 else
542 n_err(_("%s: *%s* implementation error, please report this\n"),
543 uagent, cmsg);
544 rv = 1;
547 NYD_LEAVE;
548 return (rv == 0);
551 static bool_t
552 _ssl_conf_finish(void **confp, bool_t error)
554 SSL_CONF_CTX **sccp = (SSL_CONF_CTX**)confp;
555 bool_t rv;
556 NYD_ENTER;
558 if (!(rv = error))
559 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
561 SSL_CONF_CTX_free(*sccp);
563 *sccp = NULL;
564 NYD_LEAVE;
565 return rv;
568 #else /* HAVE_OPENSSL_CONF_CTX */
569 static void *
570 _ssl_conf_setup(SSL_CTX* ctxp)
572 return ctxp;
575 static bool_t
576 _ssl_conf(void *confp, enum ssl_conf_type sct, char const *value)
578 SSL_CTX *ctxp = (SSL_CTX*)confp;
579 NYD_ENTER;
581 switch (sct) {
582 case SCT_CERTIFICATE:
583 if (SSL_CTX_use_certificate_chain_file(ctxp, value) != 1) {
584 ssl_gen_err(_("Can't load certificate from file %s\n"),
585 n_shexp_quote_cp(value, FAL0));
586 confp = NULL;
588 break;
589 case SCT_CIPHER_STRING:
590 if (SSL_CTX_set_cipher_list(ctxp, value) != 1) {
591 ssl_gen_err(_("Invalid cipher string: %s\n"), value);
592 confp = NULL;
594 break;
595 case SCT_PRIVATE_KEY:
596 if (SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1) {
597 ssl_gen_err(_("Can't load private key from file %s\n"),
598 n_shexp_quote_cp(value, FAL0));
599 confp = NULL;
601 break;
602 case SCT_OPTIONS:
603 /* "Options"="Bugs" TODO *ssl-options* */
604 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
605 break;
606 case SCT_PROTOCOL: {
607 char *iolist, *cp, addin;
608 size_t i;
609 sl_i opts = 0;
611 confp = NULL;
612 for (iolist = cp = savestr(value);
613 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;) {
614 if (*cp == '\0') {
615 n_err(_("*ssl-protocol*: empty arguments are not supported\n"));
616 goto jleave;
619 addin = TRU1;
620 switch (cp[0]) {
621 case '-': addin = FAL0; /* FALLTHRU */
622 case '+': ++cp; /* FALLTHRU */
623 default : break;
626 for (i = 0;;) {
627 if (!asccasecmp(cp, _ssl_protocols[i].sp_name)) {
628 /* We need to inverse the meaning of the _NO_s */
629 if (!addin)
630 opts |= _ssl_protocols[i].sp_flag;
631 else
632 opts &= ~_ssl_protocols[i].sp_flag;
633 break;
635 if (++i < NELEM(_ssl_protocols))
636 continue;
637 n_err(_("*ssl-protocol*: unsupported value: %s\n"), cp);
638 goto jleave;
641 confp = ctxp;
642 SSL_CTX_set_options(ctxp, opts);
643 break;
646 jleave:
647 NYD_LEAVE;
648 return (confp != NULL);
651 static bool_t
652 _ssl_conf_finish(void **confp, bool_t error)
654 UNUSED(confp);
655 UNUSED(error);
656 return TRU1;
658 #endif /* !HAVE_OPENSSL_CONF_CTX */
660 static bool_t
661 _ssl_load_verifications(SSL_CTX *ctxp)
663 char *ca_dir, *ca_file;
664 X509_STORE *store;
665 bool_t rv = FAL0;
666 NYD_ENTER;
668 if (ssl_verify_level == SSL_VERIFY_IGNORE) {
669 rv = TRU1;
670 goto jleave;
673 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
674 ca_dir = file_expand(ca_dir);
675 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
676 ca_file = file_expand(ca_file);
678 if ((ca_dir != NULL || ca_file != NULL) &&
679 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1) {
680 char const *m1, *m2, *m3;
682 if (ca_dir != NULL) {
683 m1 = ca_dir;
684 m2 = (ca_file != NULL) ? _(" or ") : "";
685 } else
686 m1 = m2 = "";
687 m3 = (ca_file != NULL) ? ca_file : "";
688 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
689 goto jleave;
692 if (!ok_blook(ssl_no_default_ca) &&
693 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
694 ssl_gen_err(_("Error loading default CA locations\n"));
695 goto jleave;
698 _ssl_state &= ~SS_VERIFY_ERROR;
699 _ssl_msgno = 0;
700 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
701 store = SSL_CTX_get_cert_store(ctxp);
702 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
704 rv = TRU1;
705 jleave:
706 NYD_LEAVE;
707 return rv;
710 static enum okay
711 ssl_check_host(struct sock *sp, struct url const *urlp)
713 char data[256];
714 X509 *cert;
715 _STACKOF(GENERAL_NAME) *gens;
716 GENERAL_NAME *gen;
717 X509_NAME *subj;
718 enum okay rv = STOP;
719 NYD_ENTER;
721 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
722 n_err(_("No certificate from: %s\n"), urlp->url_h_p.s);
723 goto jleave;
726 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
727 if (gens != NULL) {
728 int i;
730 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
731 gen = sk_GENERAL_NAME_value(gens, i);
732 if (gen->type == GEN_DNS) {
733 if (options & OPT_VERB)
734 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
735 urlp->url_host.s, (char*)gen->d.ia5->data);
736 rv = rfc2595_hostname_match(urlp->url_host.s,
737 (char*)gen->d.ia5->data);
738 if (rv == OKAY)
739 goto jdone;
744 if ((subj = X509_get_subject_name(cert)) != NULL &&
745 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
746 > 0) {
747 data[sizeof data - 1] = '\0';
748 if (options & OPT_VERB)
749 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
750 urlp->url_host.s, data);
751 rv = rfc2595_hostname_match(urlp->url_host.s, data);
754 jdone:
755 X509_free(cert);
756 jleave:
757 NYD_LEAVE;
758 return rv;
761 static int
762 smime_verify(struct message *m, int n, _STACKOF(X509) *chain, X509_STORE *store)
764 char data[LINESIZE], *sender, *to, *cc, *cnttype;
765 int rv, c, i, j;
766 struct message *x;
767 FILE *fp, *ip;
768 off_t size;
769 BIO *fb, *pb;
770 PKCS7 *pkcs7;
771 _STACKOF(X509) *certs;
772 _STACKOF(GENERAL_NAME) *gens;
773 X509 *cert;
774 X509_NAME *subj;
775 GENERAL_NAME *gen;
776 NYD_ENTER;
778 rv = 1;
779 fp = NULL;
780 fb = NULL;
781 _ssl_state &= ~SS_VERIFY_ERROR;
782 _ssl_msgno = (size_t)n;
784 for (;;) {
785 sender = getsender(m);
786 to = hfield1("to", m);
787 cc = hfield1("cc", m);
788 cnttype = hfield1("content-type", m);
790 #undef _X
791 #undef _Y
792 #define _X (sizeof("application/") -1)
793 #define _Y(X) X, sizeof(X) -1
794 if (cnttype && is_asccaseprefix(cnttype, "application/") &&
795 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
796 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
797 #undef _Y
798 #undef _X
799 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
800 goto jleave;
801 if (x != (struct message*)-1) {
802 m = x;
803 continue;
807 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
808 goto jleave;
809 size = m->m_size;
810 break;
813 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
814 NULL) {
815 n_perr(_("tempfile"), 0);
816 goto jleave;
818 while (size-- > 0) {
819 c = getc(ip);
820 putc(c, fp);
822 fflush_rewind(fp);
824 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
825 ssl_gen_err(_(
826 "Error creating BIO verification object for message %d"), n);
827 goto jleave;
830 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
831 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
832 goto jleave;
834 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
835 ssl_gen_err(_("Error verifying message %d"), n);
836 goto jleave;
839 if (sender == NULL) {
840 n_err(_("Warning: Message %d has no sender\n"), n);
841 rv = 0;
842 goto jleave;
845 certs = PKCS7_get0_signers(pkcs7, chain, 0);
846 if (certs == NULL) {
847 n_err(_("No certificates found in message %d\n"), n);
848 goto jleave;
851 for (i = 0; i < sk_X509_num(certs); ++i) {
852 cert = sk_X509_value(certs, i);
853 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
854 if (gens != NULL) {
855 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
856 gen = sk_GENERAL_NAME_value(gens, j);
857 if (gen->type == GEN_EMAIL) {
858 if (options & OPT_VERB)
859 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
860 sender, (char*)gen->d.ia5->data);
861 if (!asccasecmp((char*)gen->d.ia5->data, sender))
862 goto jfound;
867 if ((subj = X509_get_subject_name(cert)) != NULL &&
868 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
869 data, sizeof data) > 0) {
870 data[sizeof data -1] = '\0';
871 if (options & OPT_VERB)
872 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
873 sender, data);
874 if (!asccasecmp(data, sender))
875 goto jfound;
878 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
879 goto jleave;
880 jfound:
881 rv = ((_ssl_state & SS_VERIFY_ERROR) != 0);
882 if (!rv)
883 printf(_("Message %d was verified successfully\n"), n);
884 jleave:
885 if (fb != NULL)
886 BIO_free(fb);
887 if (fp != NULL)
888 Fclose(fp);
889 NYD_LEAVE;
890 return rv;
893 static EVP_CIPHER const *
894 _smime_cipher(char const *name)
896 EVP_CIPHER const *cipher;
897 char *vn;
898 char const *cp;
899 size_t i;
900 NYD_ENTER;
902 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
903 snprintf(vn, (int)i, "smime-cipher-%s", name);
904 cp = vok_vlook(vn);
905 ac_free(vn);
907 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
908 cipher = _SMIME_DEFAULT_CIPHER();
909 goto jleave;
911 cipher = NULL;
913 for (i = 0; i < NELEM(_smime_ciphers); ++i)
914 if (!asccasecmp(_smime_ciphers[i].sc_name, cp)) {
915 cipher = (*_smime_ciphers[i].sc_fun)();
916 goto jleave;
918 #ifndef OPENSSL_NO_AES
919 for (i = 0; i < NELEM(_smime_ciphers_obs); ++i) /* TODO obsolete */
920 if (!asccasecmp(_smime_ciphers_obs[i].sc_name, cp)) {
921 OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
922 cipher = (*_smime_ciphers_obs[i].sc_fun)();
923 goto jleave;
925 #endif
927 /* Not a builtin algorithm, but we may have dynamic support for more */
928 #ifdef HAVE_SSL_ALL_ALGORITHMS
929 _ssl_load_algos();
930 if ((cipher = EVP_get_cipherbyname(cp)) != NULL)
931 goto jleave;
932 #endif
934 n_err(_("Invalid S/MIME cipher(s): %s\n"), cp);
935 jleave:
936 NYD_LEAVE;
937 return cipher;
940 static int
941 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
943 char *pass;
944 size_t len;
945 NYD_ENTER;
946 UNUSED(rwflag);
947 UNUSED(userdata);
949 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
950 len = strlen(pass);
951 if (UICMP(z, len, >=, size))
952 len = size -1;
953 memcpy(buf, pass, len);
954 buf[len] = '\0';
955 } else
956 len = 0;
957 NYD_LEAVE;
958 return (int)len;
961 static FILE *
962 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn)
964 char *vn, *cp;
965 int vs;
966 struct name *np;
967 char const *name = xname, *name2 = xname2;
968 FILE *fp = NULL;
969 NYD_ENTER;
971 jloop:
972 if (name) {
973 np = lextract(name, GTO | GSKIN);
974 while (np != NULL) {
975 /* This needs to be more intelligent since it will currently take the
976 * first name for which a private key is available regardless of
977 * whether it is the right one for the message */
978 vn = ac_alloc(vs = strlen(np->n_name) + 30);
979 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
980 cp = vok_vlook(vn);
981 ac_free(vn);
982 if (cp != NULL)
983 goto jopen;
984 np = np->n_flink;
986 if (name2 != NULL) {
987 name = name2;
988 name2 = NULL;
989 goto jloop;
993 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
994 goto jerr;
995 jopen:
996 if ((cp = file_expand(cp)) == NULL)
997 goto jleave;
998 if ((fp = Fopen(cp, "r")) == NULL)
999 n_perr(cp, 0);
1000 jleave:
1001 NYD_LEAVE;
1002 return fp;
1003 jerr:
1004 if (dowarn)
1005 n_err(_("Could not find a certificate for %s%s%s\n"),
1006 xname, (xname2 != NULL ? _("or ") : ""),
1007 (xname2 != NULL ? xname2 : ""));
1008 goto jleave;
1011 static char *
1012 _smime_sign_include_certs(char const *name)
1014 char *rv;
1015 NYD_ENTER;
1017 /* See comments in smime_sign_cert() for algorithm pitfalls */
1018 if (name != NULL) {
1019 struct name *np;
1021 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1022 int vs;
1023 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1024 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1025 rv = vok_vlook(vn);
1026 ac_free(vn);
1027 if (rv != NULL)
1028 goto jleave;
1031 rv = ok_vlook(smime_sign_include_certs);
1032 jleave:
1033 NYD_LEAVE;
1034 return rv;
1037 static bool_t
1038 _smime_sign_include_chain_creat(_STACKOF(X509) **chain, char const *cfiles)
1040 X509 *tmp;
1041 FILE *fp;
1042 char *nfield, *cfield, *x;
1043 NYD_ENTER;
1045 *chain = sk_X509_new_null();
1047 for (nfield = savestr(cfiles);
1048 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1049 if ((x = file_expand(cfield)) == NULL ||
1050 (fp = Fopen(cfield = x, "r")) == NULL) {
1051 n_perr(cfiles, 0);
1052 goto jerr;
1054 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1055 ssl_gen_err(_("Error reading certificate from %s"),
1056 n_shexp_quote_cp(cfield, FAL0));
1057 Fclose(fp);
1058 goto jerr;
1060 sk_X509_push(*chain, tmp);
1061 Fclose(fp);
1064 if (sk_X509_num(*chain) == 0) {
1065 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1066 goto jerr;
1068 jleave:
1069 NYD_LEAVE;
1070 return (*chain != NULL);
1071 jerr:
1072 sk_X509_pop_free(*chain, X509_free);
1073 *chain = NULL;
1074 goto jleave;
1077 static EVP_MD const *
1078 _smime_sign_digest(char const *name, char const **digname)
1080 EVP_MD const *digest;
1081 char const *cp;
1082 size_t i;
1083 NYD_ENTER;
1085 /* See comments in smime_sign_cert() for algorithm pitfalls */
1086 if (name != NULL) {
1087 struct name *np;
1089 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1090 int vs;
1091 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1092 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1093 cp = vok_vlook(vn);
1094 ac_free(vn);
1095 if (cp != NULL)
1096 goto jhave_name;
1100 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1101 digest = _SMIME_DEFAULT_DIGEST();
1102 *digname = _SMIME_DEFAULT_DIGEST_S;
1103 goto jleave;
1106 jhave_name:
1107 i = strlen(cp);
1108 { char *x = salloc(i +1);
1109 i_strcpy(x, cp, i +1);
1110 cp = x;
1112 *digname = cp;
1114 for (i = 0; i < NELEM(_smime_digests); ++i)
1115 if (!strcmp(_smime_digests[i].sd_name, cp)) {
1116 digest = (*_smime_digests[i].sd_fun)();
1117 goto jleave;
1120 /* Not a builtin algorithm, but we may have dynamic support for more */
1121 #ifdef HAVE_SSL_ALL_ALGORITHMS
1122 _ssl_load_algos();
1123 if ((digest = EVP_get_digestbyname(cp)) != NULL)
1124 goto jleave;
1125 #endif
1127 n_err(_("Invalid message digest: %s\n"), cp);
1128 digest = NULL;
1129 jleave:
1130 NYD_LEAVE;
1131 return digest;
1134 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1135 static enum okay
1136 load_crl1(X509_STORE *store, char const *name)
1138 X509_LOOKUP *lookup;
1139 enum okay rv = STOP;
1140 NYD_ENTER;
1142 if (options & OPT_VERB)
1143 n_err(_("Loading CRL from %s\n"), n_shexp_quote_cp(name, FAL0));
1144 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1145 ssl_gen_err(_("Error creating X509 lookup object"));
1146 goto jleave;
1148 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1149 ssl_gen_err(_("Error loading CRL from %s"), n_shexp_quote_cp(name, FAL0));
1150 goto jleave;
1152 rv = OKAY;
1153 jleave:
1154 NYD_LEAVE;
1155 return rv;
1157 #endif /* new OpenSSL */
1159 static enum okay
1160 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1162 char *crl_file, *crl_dir;
1163 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1164 DIR *dirp;
1165 struct dirent *dp;
1166 char *fn = NULL;
1167 int fs = 0, ds, es;
1168 #endif
1169 enum okay rv = STOP;
1170 NYD_ENTER;
1172 if ((crl_file = n_var_oklook(fok)) != NULL) {
1173 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1174 if ((crl_file = file_expand(crl_file)) == NULL ||
1175 load_crl1(store, crl_file) != OKAY)
1176 goto jleave;
1177 #else
1178 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1179 goto jleave;
1180 #endif
1183 if ((crl_dir = n_var_oklook(dok)) != NULL) {
1184 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1185 char *x;
1186 if ((x = file_expand(crl_dir)) == NULL ||
1187 (dirp = opendir(crl_dir = x)) == NULL) {
1188 n_perr(crl_dir, 0);
1189 goto jleave;
1192 ds = strlen(crl_dir);
1193 fn = smalloc(fs = ds + 20);
1194 memcpy(fn, crl_dir, ds);
1195 fn[ds] = '/';
1196 while ((dp = readdir(dirp)) != NULL) {
1197 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1198 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1199 continue;
1200 if (dp->d_name[0] == '.')
1201 continue;
1202 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1203 fn = srealloc(fn, fs = ds + es + 20);
1204 memcpy(fn + ds + 1, dp->d_name, es + 1);
1205 if (load_crl1(store, fn) != OKAY) {
1206 closedir(dirp);
1207 free(fn);
1208 goto jleave;
1211 closedir(dirp);
1212 free(fn);
1213 #else /* old OpenSSL */
1214 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1215 goto jleave;
1216 #endif
1218 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1219 if (crl_file || crl_dir)
1220 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1221 X509_V_FLAG_CRL_CHECK_ALL);
1222 #endif
1223 rv = OKAY;
1224 jleave:
1225 NYD_LEAVE;
1226 return rv;
1229 FL enum okay
1230 ssl_open(struct url const *urlp, struct sock *sp)
1232 SSL_CTX *ctxp;
1233 void *confp;
1234 char const *cp, *cp_base;
1235 size_t i;
1236 enum okay rv = STOP;
1237 NYD_ENTER;
1239 _ssl_init();
1241 ssl_set_verify_level(urlp);
1243 if ((ctxp = SSL_CTX_new(_SSL_CLIENT_METHOD())) == NULL) {
1244 ssl_gen_err(_("SSL_CTX_new() failed"));
1245 goto jleave;
1248 /* Available with OpenSSL 0.9.6 or later */
1249 #ifdef SSL_MODE_AUTO_RETRY
1250 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1251 #endif
1253 if ((confp = _ssl_conf_setup(ctxp)) == NULL)
1254 goto jerr0;
1256 /* TODO obsolete Check for *ssl-method*, warp to a *ssl-protocol* value */
1257 if ((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL) {
1258 OBSOLETE(_("please use *ssl-protocol* instead of *ssl-method*"));
1259 if (options & OPT_VERB)
1260 n_err(_("*ssl-method*: %s\n"), cp);
1261 for (i = 0;;) {
1262 if (!asccasecmp(_ssl_methods[i].sm_name, cp)) {
1263 cp = _ssl_methods[i].sm_map;
1264 break;
1266 if (++i == NELEM(_ssl_methods)) {
1267 n_err(_("Unsupported TLS/SSL method: %s\n"), cp);
1268 goto jerr1;
1272 /* *ssl-protocol* */
1273 if ((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL) {
1274 if (options & OPT_VERB)
1275 n_err(_("*ssl-protocol*: %s\n"), cp_base);
1276 cp = cp_base;
1278 cp = (cp != NULL ? savecatsep(cp, ',', SSL_DISABLED_PROTOCOLS)
1279 : SSL_DISABLED_PROTOCOLS);
1280 if (!_ssl_conf(confp, SCT_PROTOCOL, cp))
1281 goto jerr1;
1283 /* *ssl-cert* */
1284 if ((cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL) {
1285 if (options & OPT_VERB)
1286 n_err(_("*ssl-cert* %s\n"), n_shexp_quote_cp(cp, FAL0));
1287 if ((cp_base = file_expand(cp)) == NULL) {
1288 n_err(_("*ssl-cert* value expansion failed: %s\n"),
1289 n_shexp_quote_cp(cp, FAL0));
1290 goto jerr1;
1292 cp = cp_base;
1293 if (!_ssl_conf(confp, SCT_CERTIFICATE, cp))
1294 goto jerr1;
1296 /* *ssl-key* */
1297 if ((cp_base = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL) {
1298 if (options & OPT_VERB)
1299 n_err(_("*ssl-key* %s\n"), n_shexp_quote_cp(cp_base, FAL0));
1300 if ((cp = file_expand(cp_base)) == NULL) {
1301 n_err(_("*ssl-key* value expansion failed: %s\n"),
1302 n_shexp_quote_cp(cp_base, FAL0));
1303 goto jerr1;
1306 if (!_ssl_conf(confp, SCT_PRIVATE_KEY, cp))
1307 goto jerr1;
1310 if ((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL &&
1311 !_ssl_conf(confp, SCT_CIPHER_STRING, cp))
1312 goto jerr1;
1314 if (!_ssl_load_verifications(ctxp))
1315 goto jerr1;
1317 if (!_ssl_conf(confp, SCT_OPTIONS, NULL)) /* TODO *ssl-options* */
1318 goto jerr1;
1320 /* Done with context setup, create our new per-connection structure */
1321 if (!_ssl_conf_finish(&confp, FAL0))
1322 goto jerr0;
1324 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1325 ssl_gen_err(_("SSL_new() failed"));
1326 goto jerr0;
1329 SSL_set_fd(sp->s_ssl, sp->s_fd);
1331 if (SSL_connect(sp->s_ssl) < 0) {
1332 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1333 goto jerr2;
1336 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1337 if (ssl_check_host(sp, urlp) != OKAY) {
1338 n_err(_("Host certificate does not match: %s\n"), urlp->url_h_p.s);
1339 if (ssl_verify_decide() != OKAY)
1340 goto jerr2;
1344 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1345 * and free it right now -- it is reference counted by sp->s_ssl.. */
1346 SSL_CTX_free(ctxp);
1347 sp->s_use_ssl = 1;
1348 rv = OKAY;
1349 jleave:
1350 NYD_LEAVE;
1351 return rv;
1352 jerr2:
1353 SSL_free(sp->s_ssl);
1354 sp->s_ssl = NULL;
1355 jerr1:
1356 if (confp != NULL)
1357 _ssl_conf_finish(&confp, TRU1);
1358 jerr0:
1359 SSL_CTX_free(ctxp);
1360 goto jleave;
1363 FL void
1364 ssl_gen_err(char const *fmt, ...)
1366 va_list ap;
1367 NYD_ENTER;
1369 va_start(ap, fmt);
1370 n_verr(fmt, ap);
1371 va_end(ap);
1373 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1374 NYD_LEAVE;
1377 FL int
1378 c_verify(void *vp)
1380 int *msgvec = vp, *ip, ec = 0, rv = 1;
1381 _STACKOF(X509) *chain = NULL;
1382 X509_STORE *store = NULL;
1383 char *ca_dir, *ca_file;
1384 NYD_ENTER;
1386 _ssl_init();
1388 ssl_verify_level = SSL_VERIFY_STRICT;
1389 if ((store = X509_STORE_new()) == NULL) {
1390 ssl_gen_err(_("Error creating X509 store"));
1391 goto jleave;
1393 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1395 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1396 ca_dir = file_expand(ca_dir);
1397 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1398 ca_file = file_expand(ca_file);
1400 if (ca_dir != NULL || ca_file != NULL) {
1401 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
1402 ssl_gen_err(_("Error loading %s"),
1403 (ca_file != NULL) ? ca_file : ca_dir);
1404 goto jleave;
1407 if (!ok_blook(smime_no_default_ca)) {
1408 if (X509_STORE_set_default_paths(store) != 1) {
1409 ssl_gen_err(_("Error loading default CA locations"));
1410 goto jleave;
1414 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1415 goto jleave;
1417 for (ip = msgvec; *ip != 0; ++ip) {
1418 struct message *mp = message + *ip - 1;
1419 setdot(mp);
1420 ec |= smime_verify(mp, *ip, chain, store);
1422 if ((rv = ec) != 0)
1423 exit_status |= EXIT_ERR;
1424 jleave:
1425 if (store != NULL)
1426 X509_STORE_free(store);
1427 NYD_LEAVE;
1428 return rv;
1431 FL FILE *
1432 smime_sign(FILE *ip, char const *addr)
1434 FILE *rv = NULL, *sp = NULL, *fp = NULL, *bp, *hp;
1435 X509 *cert = NULL;
1436 _STACKOF(X509) *chain = NULL;
1437 EVP_PKEY *pkey = NULL;
1438 BIO *bb, *sb;
1439 PKCS7 *pkcs7;
1440 EVP_MD const *md;
1441 char const *name;
1442 bool_t bail = FAL0;
1443 NYD_ENTER;
1445 _ssl_init();
1447 if (addr == NULL) {
1448 n_err(_("No *from* address for signing specified\n"));
1449 goto jleave;
1451 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
1452 goto jleave;
1454 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1455 ssl_gen_err(_("Error reading private key from"));
1456 goto jleave;
1459 rewind(fp);
1460 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1461 ssl_gen_err(_("Error reading signer certificate from"));
1462 goto jleave;
1464 Fclose(fp);
1465 fp = NULL;
1467 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1468 !_smime_sign_include_chain_creat(&chain, name))
1469 goto jleave;
1471 name = NULL;
1472 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1473 goto jleave;
1475 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1476 NULL) {
1477 n_perr(_("tempfile"), 0);
1478 goto jleave;
1481 rewind(ip);
1482 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1483 goto jerr1;
1485 sb = NULL;
1486 pkcs7 = NULL;
1488 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1489 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1490 ssl_gen_err(_("Error creating BIO signing objects"));
1491 bail = TRU1;
1492 goto jerr;
1495 #undef _X
1496 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1497 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1498 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1499 bail = TRU1;
1500 goto jerr;
1502 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1503 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1504 bail = TRU1;
1505 goto jerr;
1507 if (!PKCS7_final(pkcs7, bb, _X)) {
1508 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1509 bail = TRU1;
1510 goto jerr;
1512 #undef _X
1514 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1515 ssl_gen_err(_("Error writing signed S/MIME data"));
1516 bail = TRU1;
1517 /*goto jerr*/
1519 jerr:
1520 if (pkcs7 != NULL)
1521 PKCS7_free(pkcs7);
1522 if (sb != NULL)
1523 BIO_free(sb);
1524 if (bb != NULL)
1525 BIO_free(bb);
1526 if (!bail) {
1527 rewind(bp);
1528 fflush_rewind(sp);
1529 rv = smime_sign_assemble(hp, bp, sp, name);
1530 } else
1531 jerr1:
1532 Fclose(sp);
1534 jleave:
1535 if (chain != NULL)
1536 sk_X509_pop_free(chain, X509_free);
1537 if (cert != NULL)
1538 X509_free(cert);
1539 if (pkey != NULL)
1540 EVP_PKEY_free(pkey);
1541 if (fp != NULL)
1542 Fclose(fp);
1543 NYD_LEAVE;
1544 return rv;
1547 FL FILE *
1548 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1550 FILE *rv = NULL, *yp, *fp, *bp, *hp;
1551 X509 *cert;
1552 PKCS7 *pkcs7;
1553 BIO *bb, *yb;
1554 _STACKOF(X509) *certs;
1555 EVP_CIPHER const *cipher;
1556 char *certfile;
1557 bool_t bail = FAL0;
1558 NYD_ENTER;
1560 if ((certfile = file_expand(xcertfile)) == NULL)
1561 goto jleave;
1563 _ssl_init();
1565 if ((cipher = _smime_cipher(to)) == NULL)
1566 goto jleave;
1567 if ((fp = Fopen(certfile, "r")) == NULL) {
1568 n_perr(certfile, 0);
1569 goto jleave;
1572 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1573 ssl_gen_err(_("Error reading encryption certificate from %s"),
1574 n_shexp_quote_cp(certfile, FAL0));
1575 bail = TRU1;
1577 Fclose(fp);
1578 if (bail)
1579 goto jleave;
1580 bail = FAL0;
1582 certs = sk_X509_new_null();
1583 sk_X509_push(certs, cert);
1585 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1586 NULL) {
1587 n_perr(_("tempfile"), 0);
1588 goto jerr1;
1591 rewind(ip);
1592 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1593 Fclose(yp);
1594 goto jerr1;
1597 yb = NULL;
1598 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1599 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1600 ssl_gen_err(_("Error creating BIO encryption objects"));
1601 bail = TRU1;
1602 goto jerr2;
1604 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1605 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
1606 bail = TRU1;
1607 goto jerr2;
1609 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1610 ssl_gen_err(_("Error writing encrypted S/MIME data"));
1611 bail = TRU1;
1612 /* goto jerr2 */
1615 jerr2:
1616 if (bb != NULL)
1617 BIO_free(bb);
1618 if (yb != NULL)
1619 BIO_free(yb);
1620 Fclose(bp);
1621 if (bail)
1622 Fclose(yp);
1623 else {
1624 fflush_rewind(yp);
1625 rv = smime_encrypt_assemble(hp, yp);
1627 jerr1:
1628 sk_X509_pop_free(certs, X509_free);
1629 jleave:
1630 NYD_LEAVE;
1631 return rv;
1634 FL struct message *
1635 smime_decrypt(struct message *m, char const *to, char const *cc, int signcall)
1637 struct message *rv;
1638 FILE *fp, *bp, *hp, *op;
1639 X509 *cert;
1640 PKCS7 *pkcs7;
1641 EVP_PKEY *pkey;
1642 BIO *bb, *pb, *ob;
1643 long size;
1644 FILE *yp;
1645 NYD_ENTER;
1647 rv = NULL;
1648 cert = NULL;
1649 pkey = NULL;
1650 size = m->m_size;
1652 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1653 goto jleave;
1655 _ssl_init();
1657 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
1658 pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL);
1659 if (pkey == NULL) {
1660 ssl_gen_err(_("Error reading private key"));
1661 Fclose(fp);
1662 goto jleave;
1664 rewind(fp);
1666 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1667 ssl_gen_err(_("Error reading decryption certificate"));
1668 Fclose(fp);
1669 EVP_PKEY_free(pkey);
1670 goto jleave;
1672 Fclose(fp);
1675 if ((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1676 NULL) {
1677 n_perr(_("tempfile"), 0);
1678 goto j_ferr;
1681 if (smime_split(yp, &hp, &bp, size, 1) == STOP)
1682 goto jferr;
1684 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1685 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
1686 ssl_gen_err(_("Error creating BIO decryption objects"));
1687 goto jferr;
1689 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
1690 ssl_gen_err(_("Error reading PKCS#7 object"));
1691 jferr:
1692 Fclose(op);
1693 j_ferr:
1694 if (cert)
1695 X509_free(cert);
1696 if (pkey)
1697 EVP_PKEY_free(pkey);
1698 goto jleave;
1701 if (PKCS7_type_is_signed(pkcs7)) {
1702 if (signcall) {
1703 setinput(&mb, m, NEED_BODY);
1704 rv = (struct message*)-1;
1705 goto jerr2;
1707 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1708 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1709 goto jerr;
1710 fseek(hp, 0L, SEEK_END);
1711 fprintf(hp, "X-Encryption-Cipher: none\n");
1712 fflush(hp);
1713 rewind(hp);
1714 } else if (pkey == NULL) {
1715 n_err(_("No appropriate private key found\n"));
1716 goto jerr2;
1717 } else if (cert == NULL) {
1718 n_err(_("No appropriate certificate found\n"));
1719 goto jerr2;
1720 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
1721 jerr:
1722 ssl_gen_err(_("Error decrypting PKCS#7 object"));
1723 jerr2:
1724 BIO_free(bb);
1725 BIO_free(ob);
1726 Fclose(op);
1727 Fclose(bp);
1728 Fclose(hp);
1729 if (cert != NULL)
1730 X509_free(cert);
1731 if (pkey != NULL)
1732 EVP_PKEY_free(pkey);
1733 goto jleave;
1735 BIO_free(bb);
1736 BIO_free(ob);
1737 if (cert)
1738 X509_free(cert);
1739 if (pkey)
1740 EVP_PKEY_free(pkey);
1741 fflush_rewind(op);
1742 Fclose(bp);
1744 rv = smime_decrypt_assemble(m, hp, op);
1745 jleave:
1746 NYD_LEAVE;
1747 return rv;
1750 FL enum okay
1751 smime_certsave(struct message *m, int n, FILE *op)
1753 struct message *x;
1754 char *to, *cc, *cnttype;
1755 int c, i;
1756 FILE *fp, *ip;
1757 off_t size;
1758 BIO *fb, *pb;
1759 PKCS7 *pkcs7;
1760 _STACKOF(X509) *certs, *chain = NULL;
1761 X509 *cert;
1762 enum okay rv = STOP;
1763 NYD_ENTER;
1765 _ssl_msgno = (size_t)n;
1766 jloop:
1767 to = hfield1("to", m);
1768 cc = hfield1("cc", m);
1769 cnttype = hfield1("content-type", m);
1771 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1772 goto jleave;
1774 #undef _X
1775 #undef _Y
1776 #define _X (sizeof("application/") -1)
1777 #define _Y(X) X, sizeof(X) -1
1778 if (cnttype && is_asccaseprefix(cnttype, "application/") &&
1779 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
1780 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
1781 #undef _Y
1782 #undef _X
1783 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1784 goto jleave;
1785 if (x != (struct message*)-1) {
1786 m = x;
1787 goto jloop;
1790 size = m->m_size;
1792 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1793 NULL) {
1794 n_perr(_("tempfile"), 0);
1795 goto jleave;
1798 while (size-- > 0) {
1799 c = getc(ip);
1800 putc(c, fp);
1802 fflush(fp);
1804 rewind(fp);
1805 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1806 ssl_gen_err("Error creating BIO object for message %d", n);
1807 Fclose(fp);
1808 goto jleave;
1811 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1812 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1813 BIO_free(fb);
1814 Fclose(fp);
1815 goto jleave;
1817 BIO_free(fb);
1818 Fclose(fp);
1820 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1821 if (certs == NULL) {
1822 n_err(_("No certificates found in message %d\n"), n);
1823 goto jleave;
1826 for (i = 0; i < sk_X509_num(certs); ++i) {
1827 cert = sk_X509_value(certs, i);
1828 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
1829 ssl_gen_err(_("Error writing certificate %d from message %d"),
1830 i, n);
1831 goto jleave;
1834 rv = OKAY;
1835 jleave:
1836 NYD_LEAVE;
1837 return rv;
1839 #endif /* HAVE_OPENSSL */
1841 /* s-it-mode */