quit()+descendants: add hold_sigs_on argument, let'em handle it
[s-mailx.git] / xssl.c
blob2b75f109e11beec94eae76c65b6b43c77c07065a
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ TLS/SSL 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 xssl
42 #ifndef HAVE_AMALGAMATION
43 # include "nail.h"
44 #endif
46 EMPTY_FILE()
47 #ifdef HAVE_XSSL
48 #include <sys/socket.h>
50 #include <openssl/crypto.h>
51 #include <openssl/err.h>
52 #include <openssl/evp.h>
53 #include <openssl/opensslv.h>
54 #include <openssl/pem.h>
55 #include <openssl/rand.h>
56 #include <openssl/ssl.h>
57 #include <openssl/x509v3.h>
58 #include <openssl/x509.h>
60 #ifdef HAVE_XSSL_CONFIG
61 # include <openssl/conf.h>
62 #endif
64 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
65 # include <dirent.h>
66 #endif
69 * OpenSSL client implementation according to: John Viega, Matt Messier,
70 * Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
73 /* Update manual on changes (for all those)! */
74 #define n_XSSL_DISABLED_PROTOCOLS "-SSLv2"
76 #ifndef HAVE_XSSL_CONF_CTX
77 # ifndef SSL_OP_NO_SSLv2
78 # define SSL_OP_NO_SSLv2 0
79 # endif
80 # ifndef SSL_OP_NO_SSLv3
81 # define SSL_OP_NO_SSLv3 0
82 # endif
83 # ifndef SSL_OP_NO_TLSv1
84 # define SSL_OP_NO_TLSv1 0
85 # endif
86 # ifndef SSL_OP_NO_TLSv1_1
87 # define SSL_OP_NO_TLSv1_1 0
88 # endif
89 # ifndef SSL_OP_NO_TLSv1_2
90 # define SSL_OP_NO_TLSv1_2 0
91 # endif
93 /* SSL_CONF_CTX and _OP_NO_SSL_MASK were both introduced with 1.0.2!?! */
94 # ifndef SSL_OP_NO_SSL_MASK
95 # define SSL_OP_NO_SSL_MASK \
96 (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |\
97 SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2)
98 # endif
99 #endif
101 #ifdef HAVE_XSSL_STACK_OF
102 # define n_XSSL_STACKOF(X) STACK_OF(X)
103 #else
104 # define n_XSSL_STACKOF(X) /*X*/STACK
105 #endif
107 #if OPENSSL_VERSION_NUMBER + 0 >= 0x0090581fL
108 # define a_XSSL_RAND_LOAD_FILE_MAXBYTES -1
109 #else
110 # define a_XSSL_RAND_LOAD_FILE_MAXBYTES 1024
111 #endif
113 /* Compatibility sighs (that sigh is _really_ a cute one) */
114 #if HAVE_XSSL_OPENSSL >= 0x10100
115 # define a_xssl_X509_get_notBefore X509_get0_notBefore
116 # define a_xssl_X509_get_notAfter X509_get0_notAfter
117 #else
118 # define a_xssl_X509_get_notBefore X509_get_notBefore
119 # define a_xssl_X509_get_notAfter X509_get_notAfter
120 #endif
122 /* Some became meaningless with HAVE_XSSL_OPENSSL>=0x10100 */
123 enum a_xssl_state{
124 a_XSSL_S_INIT = 1<<0,
125 a_XSSL_S_RAND_INIT = 1<<1,
126 a_XSSL_S_EXIT_HDL = 1<<2,
127 a_XSSL_S_CONF_LOAD = 1<<3,
128 a_XSSL_S_ALGO_LOAD = 1<<4,
130 a_XSSL_S_VERIFY_ERROR = 1<<7
133 /* We go for the OpenSSL v1.0.2+ SSL_CONF_CTX if available even if
134 * the library does internally what we'd otherwise do ourselfs.
135 * But eventually we can drop the direct use cases */
136 enum a_xssl_conf_type{
137 a_XSSL_CT_CERTIFICATE,
138 a_XSSL_CT_CIPHER_STRING,
139 a_XSSL_CT_PRIVATE_KEY,
140 a_XSSL_CT_OPTIONS,
141 a_XSSL_CT_PROTOCOL
144 struct ssl_method { /* TODO v15 obsolete */
145 char const sm_name[8];
146 char const sm_map[16];
149 #ifndef HAVE_XSSL_CONF_CTX
150 struct a_xssl_protocol{
151 char const *sp_name;
152 sl_i sp_flag;
154 #endif
156 struct a_xssl_smime_cipher{
157 char const sc_name[8];
158 EVP_CIPHER const *(*sc_fun)(void);
161 struct a_xssl_smime_digest{
162 char const sd_name[8];
163 EVP_MD const *(*sd_fun)(void);
166 /* Supported SSL/TLS methods: update manual on change! */
168 static struct ssl_method const _ssl_methods[] = { /* TODO obsolete */
169 {"auto", "ALL,-SSLv2"},
170 {"ssl3", "-ALL,SSLv3"},
171 {"tls1", "-ALL,TLSv1"},
172 {"tls1.1", "-ALL,TLSv1.1"},
173 {"tls1.2", "-ALL,TLSv1.2"}
176 /* Update manual on change! */
177 #ifndef HAVE_XSSL_CONF_CTX
178 static struct a_xssl_protocol const a_xssl_protocols[] = {
179 {"ALL", SSL_OP_NO_SSL_MASK},
180 {"TLSv1.2", SSL_OP_NO_TLSv1_2},
181 {"TLSv1.1", SSL_OP_NO_TLSv1_1},
182 {"TLSv1", SSL_OP_NO_TLSv1},
183 {"SSLv3", SSL_OP_NO_SSLv3},
184 {"SSLv2", 0}
186 #endif
188 /* Supported S/MIME cipher algorithms */
189 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers[] = { /* Manual! */
190 #ifndef OPENSSL_NO_AES
191 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_aes_128_cbc /* According to RFC 5751 */
192 {"aes128", &EVP_aes_128_cbc},
193 {"aes256", &EVP_aes_256_cbc},
194 {"aes192", &EVP_aes_192_cbc},
195 #endif
196 #ifndef OPENSSL_NO_DES
197 # ifndef a_XSSL_SMIME_DEFAULT_CIPHER
198 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_des_ede3_cbc
199 # endif
200 {"des3", &EVP_des_ede3_cbc},
201 {"des", &EVP_des_cbc},
202 #endif
204 #ifndef a_XSSL_SMIME_DEFAULT_CIPHER
205 # error Your OpenSSL library does not include the necessary
206 # error cipher algorithms that are required to support S/MIME
207 #endif
209 #ifndef OPENSSL_NO_AES
210 /* TODO obsolete a_xssl_smime_ciphers_obs */
211 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers_obs[] = {
212 {"aes-128", &EVP_aes_128_cbc},
213 {"aes-256", &EVP_aes_256_cbc},
214 {"aes-192", &EVP_aes_192_cbc}
216 #endif
218 /* Supported S/MIME message digest algorithms */
219 static struct a_xssl_smime_digest const a_xssl_smime_digests[] = { /* Manual! */
220 #define a_XSSL_SMIME_DEFAULT_DIGEST EVP_sha1 /* According to RFC 5751 */
221 #define a_XSSL_SMIME_DEFAULT_DIGEST_S "sha1"
222 {"sha1", &EVP_sha1},
223 {"sha256", &EVP_sha256},
224 {"sha512", &EVP_sha512},
225 {"sha384", &EVP_sha384},
226 {"sha224", &EVP_sha224},
227 #ifndef OPENSSL_NO_MD5
228 {"md5", &EVP_md5},
229 #endif
232 static enum a_xssl_state a_xssl_state;
233 static size_t a_xssl_msgno;
235 static bool_t a_xssl_rand_init(void);
236 #if HAVE_XSSL_OPENSSL < 0x10100
237 # ifdef HAVE_SSL_ALL_ALGORITHMS
238 static void a_xssl__load_algos(void);
239 # define a_xssl_load_algos a_xssl__load_algos
240 # endif
241 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
242 static void a_xssl_atexit(void);
243 # endif
244 #endif
245 #ifndef a_xssl_load_algos
246 # define a_xssl_load_algos() do{;}while(0)
247 #endif
249 static bool_t _ssl_parse_asn1_time(ASN1_TIME const *atp,
250 char *bdat, size_t blen);
251 static int _ssl_verify_cb(int success, X509_STORE_CTX *store);
253 /* SSL_CTX configuration */
254 static void * _ssl_conf_setup(SSL_CTX *ctxp);
255 static bool_t _ssl_conf(void *confp, enum a_xssl_conf_type ct,
256 char const *value);
257 static bool_t _ssl_conf_finish(void **confp, bool_t error);
259 static bool_t _ssl_load_verifications(SSL_CTX *ctxp);
261 static enum okay ssl_check_host(struct sock *sp, struct url const *urlp);
263 static int smime_verify(struct message *m, int n,
264 n_XSSL_STACKOF(X509) *chain, X509_STORE *store);
265 static EVP_CIPHER const * _smime_cipher(char const *name);
266 static int ssl_password_cb(char *buf, int size, int rwflag,
267 void *userdata);
268 static FILE * smime_sign_cert(char const *xname, char const *xname2,
269 bool_t dowarn);
270 static char * _smime_sign_include_certs(char const *name);
271 static bool_t _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
272 char const *cfiles);
273 static EVP_MD const * _smime_sign_digest(char const *name,
274 char const **digname);
275 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
276 static enum okay load_crl1(X509_STORE *store, char const *name);
277 #endif
278 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
280 static bool_t
281 a_xssl_rand_init(void){
282 char const *cp, *x;
283 bool_t rv;
284 NYD_ENTER;
286 rv = FAL0;
288 /* Shall use some external daemon? */ /* TODO obsolete *ssl_rand_egd* */
289 if((cp = ok_vlook(ssl_rand_egd)) != NULL){ /* TODO no one supports it now! */
290 OBSOLETE(_("all *SSL libraries dropped support of *ssl-rand-egd*, thus"));
291 #ifdef HAVE_XSSL_RAND_EGD
292 if((x = file_expand(cp)) != NULL && RAND_egd(cp = x) != -1){
293 rv = TRU1;
294 goto jleave;
296 n_err(_("*ssl_rand_egd* daemon at %s not available\n"),
297 n_shexp_quote_cp(cp, FAL0));
298 #else
299 if(options & OPT_D_VV)
300 n_err(_("*ssl_rand_egd* (%s): unsupported by SSL library\n"),
301 n_shexp_quote_cp(cp, FAL0));
302 #endif
305 /* Prefer possible user setting */
306 if((cp = ok_vlook(ssl_rand_file)) != NULL){
307 x = NULL;
308 if(*cp != '\0'){
309 if((x = file_expand(cp)) == NULL)
310 n_err(_("*ssl-rand-file*: filename expansion of %s failed\n"),
311 n_shexp_quote_cp(cp, FAL0));
313 cp = x;
316 /* If the SSL PRNG is initialized don't put any more effort in this if the
317 * user defined entropy isn't usable */
318 if(cp == NULL){
319 if(RAND_status()){
320 rv = TRU1;
321 goto jleave;
324 if((cp = RAND_file_name(salloc(PATH_MAX), PATH_MAX)) == NULL){
325 n_err(_("*ssl-rand-file*: no SSL entropy file, can't seed PRNG\n"));
326 goto jleave;
330 if(RAND_load_file(cp, a_XSSL_RAND_LOAD_FILE_MAXBYTES) != -1){
331 for(x = (char*)-1;;){
332 RAND_seed(getrandstring(32), 32);
333 if((rv = (RAND_status() != 0)))
334 break;
335 if((x = (char*)((uintptr_t)x >> 1)) == NULL){
336 n_err(_("*ssl-rand-file*: can't seed SSL PRNG with entropy\n"));
337 goto jleave;
341 if(RAND_write_file(cp) == -1)
342 n_err(_("*ssl-rand-file*: writing entropy to %s failed\n"),
343 n_shexp_quote_cp(cp, FAL0));
344 }else
345 n_err(_("*ssl-rand-file*: %s cannot be loaded\n"),
346 n_shexp_quote_cp(cp, FAL0));
347 jleave:
348 NYD_LEAVE;
349 return rv;
352 static void
353 a_xssl_init(void)
355 #ifdef HAVE_XSSL_CONFIG
356 char const *cp;
357 #endif
358 NYD_ENTER;
360 if(!(a_xssl_state & a_XSSL_S_INIT)){
361 #if HAVE_XSSL_OPENSSL >= 0x10100
362 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS |
363 OPENSSL_INIT_LOAD_CRYPTO_STRINGS
364 # ifdef HAVE_SSL_ALL_ALGORITHMS
365 | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS
366 # endif
367 , NULL);
368 # ifdef HAVE_SSL_ALL_ALGORITHMS
369 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
370 # endif
371 #else
372 SSL_load_error_strings();
373 SSL_library_init();
374 #endif
375 a_xssl_state |= a_XSSL_S_INIT;
378 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
379 #ifdef HAVE_XSSL_CONFIG
380 if(!(a_xssl_state & a_XSSL_S_CONF_LOAD) &&
381 (cp = ok_vlook(ssl_config_file)) != NULL){
382 ul_i flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
384 if(*cp == '\0'){
385 cp = NULL;
386 flags = 0;
388 if(CONF_modules_load_file(cp, uagent, flags) == 1){
389 a_xssl_state |= a_XSSL_S_CONF_LOAD;
390 # if HAVE_XSSL_OPENSSL < 0x10100
391 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
392 a_xssl_state |= a_XSSL_S_EXIT_HDL;
393 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
395 # endif
396 }else
397 ssl_gen_err(_("Ignoring CONF_modules_load_file() load error"));
399 #endif
401 if(!(a_xssl_state & a_XSSL_S_RAND_INIT) && a_xssl_rand_init())
402 a_xssl_state |= a_XSSL_S_RAND_INIT;
403 NYD_LEAVE;
406 #if HAVE_XSSL_OPENSSL < 0x10100
407 # ifdef HAVE_SSL_ALL_ALGORITHMS
408 static void
409 a_xssl__load_algos(void){
410 NYD2_ENTER;
411 if(!(a_xssl_state & a_XSSL_S_ALGO_LOAD)){
412 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
413 OpenSSL_add_all_algorithms();
415 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
416 a_xssl_state |= a_XSSL_S_EXIT_HDL;
417 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
420 NYD2_LEAVE;
422 # endif
424 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
425 static void
426 a_xssl_atexit(void){
427 NYD2_ENTER;
428 # ifdef HAVE_XSSL_CONFIG
429 if(a_xssl_state & a_XSSL_S_CONF_LOAD)
430 CONF_modules_free();
431 # endif
433 # ifdef HAVE_SSL_ALL_ALGORITHMS
434 if(a_xssl_state & a_XSSL_S_ALGO_LOAD)
435 EVP_cleanup();
436 # endif
437 NYD2_LEAVE;
439 # endif
440 #endif /* HAVE_XSSL_OPENSSL < 0x10100 */
442 static bool_t
443 _ssl_parse_asn1_time(ASN1_TIME const *atp, char *bdat, size_t blen)
445 BIO *mbp;
446 char *mcp;
447 long l;
448 NYD_ENTER;
450 mbp = BIO_new(BIO_s_mem());
452 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
453 snprintf(bdat, blen, "%.*s", (int)l, mcp);
454 else {
455 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
456 /*is (int)*/atp->length, (char const*)atp->data);
457 mcp = NULL;
460 BIO_free(mbp);
461 NYD_LEAVE;
462 return (mcp != NULL);
465 static int
466 _ssl_verify_cb(int success, X509_STORE_CTX *store)
468 char data[256];
469 X509 *cert;
470 int rv = TRU1;
471 NYD_ENTER;
473 if (success && !(options & OPT_VERB))
474 goto jleave;
476 if (a_xssl_msgno != 0) {
477 n_err(_("Message %lu:\n"), (ul_i)a_xssl_msgno);
478 a_xssl_msgno = 0;
480 n_err(_(" Certificate depth %d %s\n"),
481 X509_STORE_CTX_get_error_depth(store), (success ? n_empty : V_(n_error)));
483 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
484 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
485 n_err(_(" subject = %s\n"), data);
487 _ssl_parse_asn1_time(a_xssl_X509_get_notBefore(cert), data, sizeof data);
488 n_err(_(" notBefore = %s\n"), data);
490 _ssl_parse_asn1_time(a_xssl_X509_get_notAfter(cert), data, sizeof data);
491 n_err(_(" notAfter = %s\n"), data);
493 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
494 n_err(_(" issuer = %s\n"), data);
497 if (!success) {
498 int err = X509_STORE_CTX_get_error(store);
500 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
501 a_xssl_state |= a_XSSL_S_VERIFY_ERROR;
504 if (!success && ssl_verify_decide() != OKAY)
505 rv = FAL0;
506 jleave:
507 NYD_LEAVE;
508 return rv;
511 #ifdef HAVE_XSSL_CONF_CTX
512 static void *
513 _ssl_conf_setup(SSL_CTX *ctxp)
515 SSL_CONF_CTX *sccp;
516 NYD_ENTER;
518 if ((sccp = SSL_CONF_CTX_new()) != NULL) {
519 SSL_CONF_CTX_set_flags(sccp,
520 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
521 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
523 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
524 } else
525 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
527 NYD_LEAVE;
528 return sccp;
531 static bool_t
532 _ssl_conf(void *confp, enum a_xssl_conf_type ct, char const *value)
534 int rv;
535 char const *cmsg;
536 SSL_CONF_CTX *sccp = (SSL_CONF_CTX*)confp;
537 NYD_ENTER;
539 switch (ct) {
540 case a_XSSL_CT_CERTIFICATE:
541 cmsg = "ssl-cert";
542 rv = SSL_CONF_cmd(sccp, "Certificate", value);
543 break;
544 case a_XSSL_CT_CIPHER_STRING:
545 cmsg = "ssl-cipher-list";
546 rv = SSL_CONF_cmd(sccp, "CipherString", value);
547 break;
548 case a_XSSL_CT_PRIVATE_KEY:
549 cmsg = "ssl-key";
550 rv = SSL_CONF_cmd(sccp, "PrivateKey", value);
551 break;
552 default:
553 case a_XSSL_CT_OPTIONS:
554 cmsg = "ssl-options";
555 rv = SSL_CONF_cmd(sccp, "Options", "Bugs");
556 break;
557 case a_XSSL_CT_PROTOCOL:
558 cmsg = "ssl-protocol";
559 rv = SSL_CONF_cmd(sccp, "Protocol", value);
560 break;
563 if (rv == 2)
564 rv = 0;
565 else {
566 if (rv == 0)
567 ssl_gen_err(_("SSL_CONF_CTX_cmd() failed for *%s*"), cmsg);
568 else
569 n_err(_("%s: *%s* implementation error, please report this\n"),
570 uagent, cmsg);
571 rv = 1;
574 NYD_LEAVE;
575 return (rv == 0);
578 static bool_t
579 _ssl_conf_finish(void **confp, bool_t error)
581 SSL_CONF_CTX **sccp = (SSL_CONF_CTX**)confp;
582 bool_t rv;
583 NYD_ENTER;
585 if (!(rv = error))
586 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
588 SSL_CONF_CTX_free(*sccp);
590 *sccp = NULL;
591 NYD_LEAVE;
592 return rv;
595 #else /* HAVE_XSSL_CONF_CTX */
596 static void *
597 _ssl_conf_setup(SSL_CTX* ctxp)
599 return ctxp;
602 static bool_t
603 _ssl_conf(void *confp, enum a_xssl_conf_type ct, char const *value)
605 SSL_CTX *ctxp = (SSL_CTX*)confp;
606 NYD_ENTER;
608 switch (ct) {
609 case a_XSSL_CT_CERTIFICATE:
610 if (SSL_CTX_use_certificate_chain_file(ctxp, value) != 1) {
611 ssl_gen_err(_("Can't load certificate from file %s\n"),
612 n_shexp_quote_cp(value, FAL0));
613 confp = NULL;
615 break;
616 case a_XSSL_CT_CIPHER_STRING:
617 if (SSL_CTX_set_cipher_list(ctxp, value) != 1) {
618 ssl_gen_err(_("Invalid cipher string: %s\n"), value);
619 confp = NULL;
621 break;
622 case a_XSSL_CT_PRIVATE_KEY:
623 if (SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1) {
624 ssl_gen_err(_("Can't load private key from file %s\n"),
625 n_shexp_quote_cp(value, FAL0));
626 confp = NULL;
628 break;
629 case a_XSSL_CT_OPTIONS:
630 /* "Options"="Bugs" TODO *ssl-options* */
631 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
632 break;
633 case a_XSSL_CT_PROTOCOL: {
634 char *iolist, *cp, addin;
635 size_t i;
636 sl_i opts = 0;
638 confp = NULL;
639 for (iolist = cp = savestr(value);
640 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;) {
641 if (*cp == '\0') {
642 n_err(_("*ssl-protocol*: empty arguments are not supported\n"));
643 goto jleave;
646 addin = TRU1;
647 switch (cp[0]) {
648 case '-': addin = FAL0; /* FALLTHRU */
649 case '+': ++cp; /* FALLTHRU */
650 default : break;
653 for (i = 0;;) {
654 if (!asccasecmp(cp, a_xssl_protocols[i].sp_name)) {
655 /* We need to inverse the meaning of the _NO_s */
656 if (!addin)
657 opts |= a_xssl_protocols[i].sp_flag;
658 else
659 opts &= ~a_xssl_protocols[i].sp_flag;
660 break;
662 if (++i < n_NELEM(a_xssl_protocols))
663 continue;
664 n_err(_("*ssl-protocol*: unsupported value: %s\n"), cp);
665 goto jleave;
668 confp = ctxp;
669 SSL_CTX_set_options(ctxp, opts);
670 break;
673 jleave:
674 NYD_LEAVE;
675 return (confp != NULL);
678 static bool_t
679 _ssl_conf_finish(void **confp, bool_t error)
681 n_UNUSED(confp);
682 n_UNUSED(error);
683 return TRU1;
685 #endif /* !HAVE_XSSL_CONF_CTX */
687 static bool_t
688 _ssl_load_verifications(SSL_CTX *ctxp)
690 char *ca_dir, *ca_file;
691 X509_STORE *store;
692 bool_t rv = FAL0;
693 NYD_ENTER;
695 if (ssl_verify_level == SSL_VERIFY_IGNORE) {
696 rv = TRU1;
697 goto jleave;
700 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
701 ca_dir = file_expand(ca_dir);
702 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
703 ca_file = file_expand(ca_file);
705 if ((ca_dir != NULL || ca_file != NULL) &&
706 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1) {
707 char const *m1, *m2, *m3;
709 if (ca_dir != NULL) {
710 m1 = ca_dir;
711 m2 = (ca_file != NULL) ? _(" or ") : n_empty;
712 } else
713 m1 = m2 = n_empty;
714 m3 = (ca_file != NULL) ? ca_file : n_empty;
715 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
716 goto jleave;
719 if (!ok_blook(ssl_no_default_ca) &&
720 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
721 ssl_gen_err(_("Error loading default CA locations\n"));
722 goto jleave;
725 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
726 a_xssl_msgno = 0;
727 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
728 store = SSL_CTX_get_cert_store(ctxp);
729 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
731 rv = TRU1;
732 jleave:
733 NYD_LEAVE;
734 return rv;
737 static enum okay
738 ssl_check_host(struct sock *sp, struct url const *urlp)
740 char data[256];
741 X509 *cert;
742 n_XSSL_STACKOF(GENERAL_NAME) *gens;
743 GENERAL_NAME *gen;
744 X509_NAME *subj;
745 enum okay rv = STOP;
746 NYD_ENTER;
748 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
749 n_err(_("No certificate from: %s\n"), urlp->url_h_p.s);
750 goto jleave;
753 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
754 if (gens != NULL) {
755 int i;
757 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
758 gen = sk_GENERAL_NAME_value(gens, i);
759 if (gen->type == GEN_DNS) {
760 if (options & OPT_VERB)
761 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
762 urlp->url_host.s, (char*)gen->d.ia5->data);
763 rv = rfc2595_hostname_match(urlp->url_host.s,
764 (char*)gen->d.ia5->data);
765 if (rv == OKAY)
766 goto jdone;
771 if ((subj = X509_get_subject_name(cert)) != NULL &&
772 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
773 > 0) {
774 data[sizeof data - 1] = '\0';
775 if (options & OPT_VERB)
776 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
777 urlp->url_host.s, data);
778 rv = rfc2595_hostname_match(urlp->url_host.s, data);
781 jdone:
782 X509_free(cert);
783 jleave:
784 NYD_LEAVE;
785 return rv;
788 static int
789 smime_verify(struct message *m, int n, n_XSSL_STACKOF(X509) *chain,
790 X509_STORE *store)
792 char data[LINESIZE], *sender, *to, *cc, *cnttype;
793 int rv, c, i, j;
794 struct message *x;
795 FILE *fp, *ip;
796 off_t size;
797 BIO *fb, *pb;
798 PKCS7 *pkcs7;
799 n_XSSL_STACKOF(X509) *certs;
800 n_XSSL_STACKOF(GENERAL_NAME) *gens;
801 X509 *cert;
802 X509_NAME *subj;
803 GENERAL_NAME *gen;
804 NYD_ENTER;
806 rv = 1;
807 fp = NULL;
808 fb = NULL;
809 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
810 a_xssl_msgno = (size_t)n;
812 for (;;) {
813 sender = getsender(m);
814 to = hfield1("to", m);
815 cc = hfield1("cc", m);
816 cnttype = hfield1("content-type", m);
818 #undef _X
819 #undef _Y
820 #define _X (sizeof("application/") -1)
821 #define _Y(X) X, sizeof(X) -1
822 if (cnttype && is_asccaseprefix(cnttype, "application/") &&
823 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
824 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
825 #undef _Y
826 #undef _X
827 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
828 goto jleave;
829 if (x != (struct message*)-1) {
830 m = x;
831 continue;
835 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
836 goto jleave;
837 size = m->m_size;
838 break;
841 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
842 NULL) {
843 n_perr(_("tempfile"), 0);
844 goto jleave;
846 while (size-- > 0) {
847 c = getc(ip);
848 putc(c, fp);
850 fflush_rewind(fp);
852 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
853 ssl_gen_err(_(
854 "Error creating BIO verification object for message %d"), n);
855 goto jleave;
858 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
859 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
860 goto jleave;
862 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
863 ssl_gen_err(_("Error verifying message %d"), n);
864 goto jleave;
867 if (sender == NULL) {
868 n_err(_("Warning: Message %d has no sender\n"), n);
869 rv = 0;
870 goto jleave;
873 certs = PKCS7_get0_signers(pkcs7, chain, 0);
874 if (certs == NULL) {
875 n_err(_("No certificates found in message %d\n"), n);
876 goto jleave;
879 for (i = 0; i < sk_X509_num(certs); ++i) {
880 cert = sk_X509_value(certs, i);
881 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
882 if (gens != NULL) {
883 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
884 gen = sk_GENERAL_NAME_value(gens, j);
885 if (gen->type == GEN_EMAIL) {
886 if (options & OPT_VERB)
887 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
888 sender, (char*)gen->d.ia5->data);
889 if (!asccasecmp((char*)gen->d.ia5->data, sender))
890 goto jfound;
895 if ((subj = X509_get_subject_name(cert)) != NULL &&
896 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
897 data, sizeof data) > 0) {
898 data[sizeof data -1] = '\0';
899 if (options & OPT_VERB)
900 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
901 sender, data);
902 if (!asccasecmp(data, sender))
903 goto jfound;
906 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
907 goto jleave;
908 jfound:
909 rv = ((a_xssl_state & a_XSSL_S_VERIFY_ERROR) != 0);
910 if (!rv)
911 printf(_("Message %d was verified successfully\n"), n);
912 jleave:
913 if (fb != NULL)
914 BIO_free(fb);
915 if (fp != NULL)
916 Fclose(fp);
917 NYD_LEAVE;
918 return rv;
921 static EVP_CIPHER const *
922 _smime_cipher(char const *name)
924 EVP_CIPHER const *cipher;
925 char *vn;
926 char const *cp;
927 size_t i;
928 NYD_ENTER;
930 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
931 snprintf(vn, (int)i, "smime-cipher-%s", name);
932 cp = vok_vlook(vn);
933 ac_free(vn);
935 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
936 cipher = a_XSSL_SMIME_DEFAULT_CIPHER();
937 goto jleave;
939 cipher = NULL;
941 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers); ++i)
942 if (!asccasecmp(a_xssl_smime_ciphers[i].sc_name, cp)) {
943 cipher = (*a_xssl_smime_ciphers[i].sc_fun)();
944 goto jleave;
946 #ifndef OPENSSL_NO_AES
947 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers_obs); ++i) /* TODO obsolete */
948 if (!asccasecmp(a_xssl_smime_ciphers_obs[i].sc_name, cp)) {
949 OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
950 cipher = (*a_xssl_smime_ciphers_obs[i].sc_fun)();
951 goto jleave;
953 #endif
955 /* Not a builtin algorithm, but we may have dynamic support for more */
956 #ifdef HAVE_SSL_ALL_ALGORITHMS
957 a_xssl_load_algos();
958 if((cipher = EVP_get_cipherbyname(cp)) != NULL)
959 goto jleave;
960 #endif
962 n_err(_("Invalid S/MIME cipher(s): %s\n"), cp);
963 jleave:
964 NYD_LEAVE;
965 return cipher;
968 static int
969 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
971 char *pass;
972 size_t len;
973 NYD_ENTER;
974 n_UNUSED(rwflag);
975 n_UNUSED(userdata);
977 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
978 len = strlen(pass);
979 if (UICMP(z, len, >=, size))
980 len = size -1;
981 memcpy(buf, pass, len);
982 buf[len] = '\0';
983 } else
984 len = 0;
985 NYD_LEAVE;
986 return (int)len;
989 static FILE *
990 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn)
992 char *vn, *cp;
993 int vs;
994 struct name *np;
995 char const *name = xname, *name2 = xname2;
996 FILE *fp = NULL;
997 NYD_ENTER;
999 jloop:
1000 if (name) {
1001 np = lextract(name, GTO | GSKIN);
1002 while (np != NULL) {
1003 /* This needs to be more intelligent since it will currently take the
1004 * first name for which a private key is available regardless of
1005 * whether it is the right one for the message */
1006 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1007 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
1008 cp = vok_vlook(vn);
1009 ac_free(vn);
1010 if (cp != NULL)
1011 goto jopen;
1012 np = np->n_flink;
1014 if (name2 != NULL) {
1015 name = name2;
1016 name2 = NULL;
1017 goto jloop;
1021 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
1022 goto jerr;
1023 jopen:
1024 if ((cp = file_expand(cp)) == NULL)
1025 goto jleave;
1026 if ((fp = Fopen(cp, "r")) == NULL)
1027 n_perr(cp, 0);
1028 jleave:
1029 NYD_LEAVE;
1030 return fp;
1031 jerr:
1032 if (dowarn)
1033 n_err(_("Could not find a certificate for %s%s%s\n"),
1034 xname, (xname2 != NULL ? _("or ") : n_empty),
1035 (xname2 != NULL ? xname2 : n_empty));
1036 goto jleave;
1039 static char *
1040 _smime_sign_include_certs(char const *name)
1042 char *rv;
1043 NYD_ENTER;
1045 /* See comments in smime_sign_cert() for algorithm pitfalls */
1046 if (name != NULL) {
1047 struct name *np;
1049 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1050 int vs;
1051 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1052 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1053 rv = vok_vlook(vn);
1054 ac_free(vn);
1055 if (rv != NULL)
1056 goto jleave;
1059 rv = ok_vlook(smime_sign_include_certs);
1060 jleave:
1061 NYD_LEAVE;
1062 return rv;
1065 static bool_t
1066 _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
1067 char const *cfiles)
1069 X509 *tmp;
1070 FILE *fp;
1071 char *nfield, *cfield, *x;
1072 NYD_ENTER;
1074 *chain = sk_X509_new_null();
1076 for (nfield = savestr(cfiles);
1077 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1078 if ((x = file_expand(cfield)) == NULL ||
1079 (fp = Fopen(cfield = x, "r")) == NULL) {
1080 n_perr(cfiles, 0);
1081 goto jerr;
1083 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1084 ssl_gen_err(_("Error reading certificate from %s"),
1085 n_shexp_quote_cp(cfield, FAL0));
1086 Fclose(fp);
1087 goto jerr;
1089 sk_X509_push(*chain, tmp);
1090 Fclose(fp);
1093 if (sk_X509_num(*chain) == 0) {
1094 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1095 goto jerr;
1097 jleave:
1098 NYD_LEAVE;
1099 return (*chain != NULL);
1100 jerr:
1101 sk_X509_pop_free(*chain, X509_free);
1102 *chain = NULL;
1103 goto jleave;
1106 static EVP_MD const *
1107 _smime_sign_digest(char const *name, char const **digname)
1109 EVP_MD const *digest;
1110 char const *cp;
1111 size_t i;
1112 NYD_ENTER;
1114 /* See comments in smime_sign_cert() for algorithm pitfalls */
1115 if (name != NULL) {
1116 struct name *np;
1118 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1119 int vs;
1120 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1121 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1122 cp = vok_vlook(vn);
1123 ac_free(vn);
1124 if (cp != NULL)
1125 goto jhave_name;
1129 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1130 digest = a_XSSL_SMIME_DEFAULT_DIGEST();
1131 *digname = a_XSSL_SMIME_DEFAULT_DIGEST_S;
1132 goto jleave;
1135 jhave_name:
1136 i = strlen(cp);
1137 { char *x = salloc(i +1);
1138 i_strcpy(x, cp, i +1);
1139 cp = x;
1141 *digname = cp;
1143 for (i = 0; i < n_NELEM(a_xssl_smime_digests); ++i)
1144 if (!strcmp(a_xssl_smime_digests[i].sd_name, cp)) {
1145 digest = (*a_xssl_smime_digests[i].sd_fun)();
1146 goto jleave;
1149 /* Not a builtin algorithm, but we may have dynamic support for more */
1150 #ifdef HAVE_SSL_ALL_ALGORITHMS
1151 a_xssl_load_algos();
1152 if((digest = EVP_get_digestbyname(cp)) != NULL)
1153 goto jleave;
1154 #endif
1156 n_err(_("Invalid message digest: %s\n"), cp);
1157 digest = NULL;
1158 jleave:
1159 NYD_LEAVE;
1160 return digest;
1163 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1164 static enum okay
1165 load_crl1(X509_STORE *store, char const *name)
1167 X509_LOOKUP *lookup;
1168 enum okay rv = STOP;
1169 NYD_ENTER;
1171 if (options & OPT_VERB)
1172 n_err(_("Loading CRL from %s\n"), n_shexp_quote_cp(name, FAL0));
1173 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1174 ssl_gen_err(_("Error creating X509 lookup object"));
1175 goto jleave;
1177 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1178 ssl_gen_err(_("Error loading CRL from %s"), n_shexp_quote_cp(name, FAL0));
1179 goto jleave;
1181 rv = OKAY;
1182 jleave:
1183 NYD_LEAVE;
1184 return rv;
1186 #endif /* new OpenSSL */
1188 static enum okay
1189 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1191 char *crl_file, *crl_dir;
1192 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1193 DIR *dirp;
1194 struct dirent *dp;
1195 char *fn = NULL;
1196 int fs = 0, ds, es;
1197 #endif
1198 enum okay rv = STOP;
1199 NYD_ENTER;
1201 if ((crl_file = n_var_oklook(fok)) != NULL) {
1202 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1203 if ((crl_file = file_expand(crl_file)) == NULL ||
1204 load_crl1(store, crl_file) != OKAY)
1205 goto jleave;
1206 #else
1207 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1208 goto jleave;
1209 #endif
1212 if ((crl_dir = n_var_oklook(dok)) != NULL) {
1213 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1214 char *x;
1215 if ((x = file_expand(crl_dir)) == NULL ||
1216 (dirp = opendir(crl_dir = x)) == NULL) {
1217 n_perr(crl_dir, 0);
1218 goto jleave;
1221 ds = strlen(crl_dir);
1222 fn = smalloc(fs = ds + 20);
1223 memcpy(fn, crl_dir, ds);
1224 fn[ds] = '/';
1225 while ((dp = readdir(dirp)) != NULL) {
1226 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1227 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1228 continue;
1229 if (dp->d_name[0] == '.')
1230 continue;
1231 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1232 fn = srealloc(fn, fs = ds + es + 20);
1233 memcpy(fn + ds + 1, dp->d_name, es + 1);
1234 if (load_crl1(store, fn) != OKAY) {
1235 closedir(dirp);
1236 free(fn);
1237 goto jleave;
1240 closedir(dirp);
1241 free(fn);
1242 #else /* old OpenSSL */
1243 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1244 goto jleave;
1245 #endif
1247 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1248 if (crl_file || crl_dir)
1249 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1250 X509_V_FLAG_CRL_CHECK_ALL);
1251 #endif
1252 rv = OKAY;
1253 jleave:
1254 NYD_LEAVE;
1255 return rv;
1258 FL enum okay
1259 ssl_open(struct url const *urlp, struct sock *sp)
1261 SSL_CTX *ctxp;
1262 void *confp;
1263 char const *cp, *cp_base;
1264 size_t i;
1265 enum okay rv = STOP;
1266 NYD_ENTER;
1268 a_xssl_init();
1270 ssl_set_verify_level(urlp);
1272 if ((ctxp = SSL_CTX_new(n_XSSL_CLIENT_METHOD())) == NULL) {
1273 ssl_gen_err(_("SSL_CTX_new() failed"));
1274 goto jleave;
1277 /* Available with OpenSSL 0.9.6 or later */
1278 #ifdef SSL_MODE_AUTO_RETRY
1279 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1280 #endif
1282 if ((confp = _ssl_conf_setup(ctxp)) == NULL)
1283 goto jerr0;
1285 /* TODO obsolete Check for *ssl-method*, warp to a *ssl-protocol* value */
1286 if ((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL) {
1287 OBSOLETE(_("please use *ssl-protocol* instead of *ssl-method*"));
1288 if (options & OPT_VERB)
1289 n_err(_("*ssl-method*: %s\n"), cp);
1290 for (i = 0;;) {
1291 if (!asccasecmp(_ssl_methods[i].sm_name, cp)) {
1292 cp = _ssl_methods[i].sm_map;
1293 break;
1295 if (++i == n_NELEM(_ssl_methods)) {
1296 n_err(_("Unsupported TLS/SSL method: %s\n"), cp);
1297 goto jerr1;
1301 /* *ssl-protocol* */
1302 if ((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL) {
1303 if (options & OPT_VERB)
1304 n_err(_("*ssl-protocol*: %s\n"), cp_base);
1305 cp = cp_base;
1307 cp = (cp != NULL ? savecatsep(cp, ',', n_XSSL_DISABLED_PROTOCOLS)
1308 : n_XSSL_DISABLED_PROTOCOLS);
1309 if (!_ssl_conf(confp, a_XSSL_CT_PROTOCOL, cp))
1310 goto jerr1;
1312 /* *ssl-cert* */
1313 if ((cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL) {
1314 if (options & OPT_VERB)
1315 n_err(_("*ssl-cert* %s\n"), n_shexp_quote_cp(cp, FAL0));
1316 if ((cp_base = file_expand(cp)) == NULL) {
1317 n_err(_("*ssl-cert* value expansion failed: %s\n"),
1318 n_shexp_quote_cp(cp, FAL0));
1319 goto jerr1;
1321 cp = cp_base;
1322 if (!_ssl_conf(confp, a_XSSL_CT_CERTIFICATE, cp))
1323 goto jerr1;
1325 /* *ssl-key* */
1326 if ((cp_base = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL) {
1327 if (options & OPT_VERB)
1328 n_err(_("*ssl-key* %s\n"), n_shexp_quote_cp(cp_base, FAL0));
1329 if ((cp = file_expand(cp_base)) == NULL) {
1330 n_err(_("*ssl-key* value expansion failed: %s\n"),
1331 n_shexp_quote_cp(cp_base, FAL0));
1332 goto jerr1;
1335 if (!_ssl_conf(confp, a_XSSL_CT_PRIVATE_KEY, cp))
1336 goto jerr1;
1339 if ((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL &&
1340 !_ssl_conf(confp, a_XSSL_CT_CIPHER_STRING, cp))
1341 goto jerr1;
1343 if (!_ssl_load_verifications(ctxp))
1344 goto jerr1;
1346 if (!_ssl_conf(confp, a_XSSL_CT_OPTIONS, NULL)) /* TODO *ssl-options* */
1347 goto jerr1;
1349 /* Done with context setup, create our new per-connection structure */
1350 if (!_ssl_conf_finish(&confp, FAL0))
1351 goto jerr0;
1353 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1354 ssl_gen_err(_("SSL_new() failed"));
1355 goto jerr0;
1358 SSL_set_fd(sp->s_ssl, sp->s_fd);
1360 if (SSL_connect(sp->s_ssl) < 0) {
1361 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1362 goto jerr2;
1365 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1366 if (ssl_check_host(sp, urlp) != OKAY) {
1367 n_err(_("Host certificate does not match: %s\n"), urlp->url_h_p.s);
1368 if (ssl_verify_decide() != OKAY)
1369 goto jerr2;
1373 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1374 * and free it right now -- it is reference counted by sp->s_ssl.. */
1375 SSL_CTX_free(ctxp);
1376 sp->s_use_ssl = 1;
1377 rv = OKAY;
1378 jleave:
1379 NYD_LEAVE;
1380 return rv;
1381 jerr2:
1382 SSL_free(sp->s_ssl);
1383 sp->s_ssl = NULL;
1384 jerr1:
1385 if (confp != NULL)
1386 _ssl_conf_finish(&confp, TRU1);
1387 jerr0:
1388 SSL_CTX_free(ctxp);
1389 goto jleave;
1392 FL void
1393 ssl_gen_err(char const *fmt, ...)
1395 va_list ap;
1396 NYD_ENTER;
1398 va_start(ap, fmt);
1399 n_verr(fmt, ap);
1400 va_end(ap);
1402 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1403 NYD_LEAVE;
1406 FL int
1407 c_verify(void *vp)
1409 int *msgvec = vp, *ip, ec = 0, rv = 1;
1410 n_XSSL_STACKOF(X509) *chain = NULL;
1411 X509_STORE *store = NULL;
1412 char *ca_dir, *ca_file;
1413 NYD_ENTER;
1415 a_xssl_init();
1417 ssl_verify_level = SSL_VERIFY_STRICT;
1418 if ((store = X509_STORE_new()) == NULL) {
1419 ssl_gen_err(_("Error creating X509 store"));
1420 goto jleave;
1422 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1424 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1425 ca_dir = file_expand(ca_dir);
1426 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1427 ca_file = file_expand(ca_file);
1429 if (ca_dir != NULL || ca_file != NULL) {
1430 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
1431 ssl_gen_err(_("Error loading %s"),
1432 (ca_file != NULL) ? ca_file : ca_dir);
1433 goto jleave;
1436 if (!ok_blook(smime_no_default_ca)) {
1437 if (X509_STORE_set_default_paths(store) != 1) {
1438 ssl_gen_err(_("Error loading default CA locations"));
1439 goto jleave;
1443 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1444 goto jleave;
1446 for (ip = msgvec; *ip != 0; ++ip) {
1447 struct message *mp = message + *ip - 1;
1448 setdot(mp);
1449 ec |= smime_verify(mp, *ip, chain, store);
1451 if ((rv = ec) != 0)
1452 exit_status |= EXIT_ERR;
1453 jleave:
1454 if (store != NULL)
1455 X509_STORE_free(store);
1456 NYD_LEAVE;
1457 return rv;
1460 FL FILE *
1461 smime_sign(FILE *ip, char const *addr)
1463 FILE *rv = NULL, *sp = NULL, *fp = NULL, *bp, *hp;
1464 X509 *cert = NULL;
1465 n_XSSL_STACKOF(X509) *chain = NULL;
1466 EVP_PKEY *pkey = NULL;
1467 BIO *bb, *sb;
1468 PKCS7 *pkcs7;
1469 EVP_MD const *md;
1470 char const *name;
1471 bool_t bail = FAL0;
1472 NYD_ENTER;
1474 assert(addr != NULL);
1476 a_xssl_init();
1478 if (addr == NULL) {
1479 n_err(_("No *from* address for signing specified\n"));
1480 goto jleave;
1482 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
1483 goto jleave;
1485 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1486 ssl_gen_err(_("Error reading private key from"));
1487 goto jleave;
1490 rewind(fp);
1491 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1492 ssl_gen_err(_("Error reading signer certificate from"));
1493 goto jleave;
1495 Fclose(fp);
1496 fp = NULL;
1498 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1499 !_smime_sign_include_chain_creat(&chain, name))
1500 goto jleave;
1502 name = NULL;
1503 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1504 goto jleave;
1506 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1507 NULL) {
1508 n_perr(_("tempfile"), 0);
1509 goto jleave;
1512 rewind(ip);
1513 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1514 goto jerr1;
1516 sb = NULL;
1517 pkcs7 = NULL;
1519 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1520 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1521 ssl_gen_err(_("Error creating BIO signing objects"));
1522 bail = TRU1;
1523 goto jerr;
1526 #undef _X
1527 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1528 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1529 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1530 bail = TRU1;
1531 goto jerr;
1533 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1534 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1535 bail = TRU1;
1536 goto jerr;
1538 if (!PKCS7_final(pkcs7, bb, _X)) {
1539 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1540 bail = TRU1;
1541 goto jerr;
1543 #undef _X
1545 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1546 ssl_gen_err(_("Error writing signed S/MIME data"));
1547 bail = TRU1;
1548 /*goto jerr*/
1550 jerr:
1551 if (pkcs7 != NULL)
1552 PKCS7_free(pkcs7);
1553 if (sb != NULL)
1554 BIO_free(sb);
1555 if (bb != NULL)
1556 BIO_free(bb);
1557 if (!bail) {
1558 rewind(bp);
1559 fflush_rewind(sp);
1560 rv = smime_sign_assemble(hp, bp, sp, name);
1561 } else
1562 jerr1:
1563 Fclose(sp);
1565 jleave:
1566 if (chain != NULL)
1567 sk_X509_pop_free(chain, X509_free);
1568 if (cert != NULL)
1569 X509_free(cert);
1570 if (pkey != NULL)
1571 EVP_PKEY_free(pkey);
1572 if (fp != NULL)
1573 Fclose(fp);
1574 NYD_LEAVE;
1575 return rv;
1578 FL FILE *
1579 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1581 FILE *rv = NULL, *yp, *fp, *bp, *hp;
1582 X509 *cert;
1583 PKCS7 *pkcs7;
1584 BIO *bb, *yb;
1585 n_XSSL_STACKOF(X509) *certs;
1586 EVP_CIPHER const *cipher;
1587 char *certfile;
1588 bool_t bail = FAL0;
1589 NYD_ENTER;
1591 if ((certfile = file_expand(xcertfile)) == NULL)
1592 goto jleave;
1594 a_xssl_init();
1596 if ((cipher = _smime_cipher(to)) == NULL)
1597 goto jleave;
1598 if ((fp = Fopen(certfile, "r")) == NULL) {
1599 n_perr(certfile, 0);
1600 goto jleave;
1603 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1604 ssl_gen_err(_("Error reading encryption certificate from %s"),
1605 n_shexp_quote_cp(certfile, FAL0));
1606 bail = TRU1;
1608 Fclose(fp);
1609 if (bail)
1610 goto jleave;
1611 bail = FAL0;
1613 certs = sk_X509_new_null();
1614 sk_X509_push(certs, cert);
1616 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1617 NULL) {
1618 n_perr(_("tempfile"), 0);
1619 goto jerr1;
1622 rewind(ip);
1623 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1624 Fclose(yp);
1625 goto jerr1;
1628 yb = NULL;
1629 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1630 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1631 ssl_gen_err(_("Error creating BIO encryption objects"));
1632 bail = TRU1;
1633 goto jerr2;
1635 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1636 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
1637 bail = TRU1;
1638 goto jerr2;
1640 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1641 ssl_gen_err(_("Error writing encrypted S/MIME data"));
1642 bail = TRU1;
1643 /* goto jerr2 */
1646 jerr2:
1647 if (bb != NULL)
1648 BIO_free(bb);
1649 if (yb != NULL)
1650 BIO_free(yb);
1651 Fclose(bp);
1652 if (bail)
1653 Fclose(yp);
1654 else {
1655 fflush_rewind(yp);
1656 rv = smime_encrypt_assemble(hp, yp);
1658 jerr1:
1659 sk_X509_pop_free(certs, X509_free);
1660 jleave:
1661 NYD_LEAVE;
1662 return rv;
1665 FL struct message *
1666 smime_decrypt(struct message *m, char const *to, char const *cc,
1667 bool_t signcall)
1669 struct message *rv;
1670 FILE *fp, *bp, *hp, *op;
1671 X509 *cert;
1672 PKCS7 *pkcs7;
1673 EVP_PKEY *pkey;
1674 BIO *bb, *pb, *ob;
1675 long size;
1676 FILE *yp;
1677 NYD_ENTER;
1679 rv = NULL;
1680 cert = NULL;
1681 pkey = NULL;
1682 size = m->m_size;
1684 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1685 goto jleave;
1687 a_xssl_init();
1689 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
1690 pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL);
1691 if (pkey == NULL) {
1692 ssl_gen_err(_("Error reading private key"));
1693 Fclose(fp);
1694 goto jleave;
1696 rewind(fp);
1698 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1699 ssl_gen_err(_("Error reading decryption certificate"));
1700 Fclose(fp);
1701 EVP_PKEY_free(pkey);
1702 goto jleave;
1704 Fclose(fp);
1707 if ((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1708 NULL) {
1709 n_perr(_("tempfile"), 0);
1710 goto j_ferr;
1713 if (smime_split(yp, &hp, &bp, size, 1) == STOP)
1714 goto jferr;
1716 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1717 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
1718 ssl_gen_err(_("Error creating BIO decryption objects"));
1719 goto jferr;
1721 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
1722 ssl_gen_err(_("Error reading PKCS#7 object"));
1723 jferr:
1724 Fclose(op);
1725 j_ferr:
1726 if (cert)
1727 X509_free(cert);
1728 if (pkey)
1729 EVP_PKEY_free(pkey);
1730 goto jleave;
1733 if (PKCS7_type_is_signed(pkcs7)) {
1734 if (signcall) {
1735 setinput(&mb, m, NEED_BODY);
1736 rv = (struct message*)-1;
1737 goto jerr2;
1739 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1740 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1741 goto jerr;
1742 fseek(hp, 0L, SEEK_END);
1743 fprintf(hp, "X-Encryption-Cipher: none\n");
1744 fflush(hp);
1745 rewind(hp);
1746 } else if (pkey == NULL) {
1747 n_err(_("No appropriate private key found\n"));
1748 goto jerr2;
1749 } else if (cert == NULL) {
1750 n_err(_("No appropriate certificate found\n"));
1751 goto jerr2;
1752 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
1753 jerr:
1754 ssl_gen_err(_("Error decrypting PKCS#7 object"));
1755 jerr2:
1756 BIO_free(bb);
1757 BIO_free(ob);
1758 Fclose(op);
1759 Fclose(bp);
1760 Fclose(hp);
1761 if (cert != NULL)
1762 X509_free(cert);
1763 if (pkey != NULL)
1764 EVP_PKEY_free(pkey);
1765 goto jleave;
1767 BIO_free(bb);
1768 BIO_free(ob);
1769 if (cert)
1770 X509_free(cert);
1771 if (pkey)
1772 EVP_PKEY_free(pkey);
1773 fflush_rewind(op);
1774 Fclose(bp);
1776 rv = smime_decrypt_assemble(m, hp, op);
1777 jleave:
1778 NYD_LEAVE;
1779 return rv;
1782 FL enum okay
1783 smime_certsave(struct message *m, int n, FILE *op)
1785 struct message *x;
1786 char *to, *cc, *cnttype;
1787 int c, i;
1788 FILE *fp, *ip;
1789 off_t size;
1790 BIO *fb, *pb;
1791 PKCS7 *pkcs7;
1792 n_XSSL_STACKOF(X509) *certs, *chain = NULL;
1793 X509 *cert;
1794 enum okay rv = STOP;
1795 NYD_ENTER;
1797 a_xssl_msgno = (size_t)n;
1798 jloop:
1799 to = hfield1("to", m);
1800 cc = hfield1("cc", m);
1801 cnttype = hfield1("content-type", m);
1803 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1804 goto jleave;
1806 #undef _X
1807 #undef _Y
1808 #define _X (sizeof("application/") -1)
1809 #define _Y(X) X, sizeof(X) -1
1810 if (cnttype && is_asccaseprefix(cnttype, "application/") &&
1811 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
1812 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
1813 #undef _Y
1814 #undef _X
1815 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1816 goto jleave;
1817 if (x != (struct message*)-1) {
1818 m = x;
1819 goto jloop;
1822 size = m->m_size;
1824 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1825 NULL) {
1826 n_perr(_("tempfile"), 0);
1827 goto jleave;
1830 while (size-- > 0) {
1831 c = getc(ip);
1832 putc(c, fp);
1834 fflush(fp);
1836 rewind(fp);
1837 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1838 ssl_gen_err("Error creating BIO object for message %d", n);
1839 Fclose(fp);
1840 goto jleave;
1843 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1844 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1845 BIO_free(fb);
1846 Fclose(fp);
1847 goto jleave;
1849 BIO_free(fb);
1850 Fclose(fp);
1852 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1853 if (certs == NULL) {
1854 n_err(_("No certificates found in message %d\n"), n);
1855 goto jleave;
1858 for (i = 0; i < sk_X509_num(certs); ++i) {
1859 cert = sk_X509_value(certs, i);
1860 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
1861 ssl_gen_err(_("Error writing certificate %d from message %d"),
1862 i, n);
1863 goto jleave;
1866 rv = OKAY;
1867 jleave:
1868 NYD_LEAVE;
1869 return rv;
1871 #endif /* HAVE_XSSL */
1873 /* s-it-mode */