a_coll_ocds__mac(): fix NOTEACHED function return
[s-mailx.git] / xssl.c
blobf44c078050797736d6705e36888abee114ea67eb
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 - 2017 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, char const **match);
270 static char const * _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, char const *addr);
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 n_OBSOLETE(_("all *SSL libraries removed *ssl-rand-egd* support"));
291 #ifdef HAVE_XSSL_RAND_EGD
292 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) != NULL &&
293 RAND_egd(cp = x) != -1){
294 rv = TRU1;
295 goto jleave;
297 n_err(_("*ssl_rand_egd* daemon at %s not available\n"),
298 n_shexp_quote_cp(cp, FAL0));
299 #else
300 if(n_poption & n_PO_D_VV)
301 n_err(_("*ssl_rand_egd* (%s): unsupported by SSL library\n"),
302 n_shexp_quote_cp(cp, FAL0));
303 #endif
306 /* Prefer possible user setting */
307 if((cp = ok_vlook(ssl_rand_file)) != NULL){
308 x = NULL;
309 if(*cp != '\0'){
310 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
311 n_err(_("*ssl-rand-file*: filename expansion of %s failed\n"),
312 n_shexp_quote_cp(cp, FAL0));
314 cp = x;
317 /* If the SSL PRNG is initialized don't put any more effort in this if the
318 * user defined entropy isn't usable */
319 if(cp == NULL){
320 if(RAND_status()){
321 rv = TRU1;
322 goto jleave;
325 if((cp = RAND_file_name(salloc(PATH_MAX), PATH_MAX)) == NULL){
326 n_err(_("*ssl-rand-file*: no SSL entropy file, can't seed PRNG\n"));
327 goto jleave;
331 if(RAND_load_file(cp, a_XSSL_RAND_LOAD_FILE_MAXBYTES) != -1){
332 for(x = (char*)-1;;){
333 RAND_seed(getrandstring(32), 32);
334 if((rv = (RAND_status() != 0)))
335 break;
336 if((x = (char*)((uintptr_t)x >> 1)) == NULL){
337 n_err(_("*ssl-rand-file*: can't seed SSL PRNG with entropy\n"));
338 goto jleave;
342 if(RAND_write_file(cp) == -1)
343 n_err(_("*ssl-rand-file*: writing entropy to %s failed\n"),
344 n_shexp_quote_cp(cp, FAL0));
345 }else
346 n_err(_("*ssl-rand-file*: %s cannot be loaded\n"),
347 n_shexp_quote_cp(cp, FAL0));
348 jleave:
349 NYD_LEAVE;
350 return rv;
353 static void
354 a_xssl_init(void)
356 #ifdef HAVE_XSSL_CONFIG
357 char const *cp;
358 #endif
359 NYD_ENTER;
361 if(!(a_xssl_state & a_XSSL_S_INIT)){
362 #if HAVE_XSSL_OPENSSL >= 0x10100
363 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS |
364 OPENSSL_INIT_LOAD_CRYPTO_STRINGS
365 # ifdef HAVE_SSL_ALL_ALGORITHMS
366 | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS
367 # endif
368 , NULL);
369 # ifdef HAVE_SSL_ALL_ALGORITHMS
370 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
371 # endif
372 #else
373 SSL_load_error_strings();
374 SSL_library_init();
375 #endif
376 a_xssl_state |= a_XSSL_S_INIT;
379 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
380 #ifdef HAVE_XSSL_CONFIG
381 if(!(a_xssl_state & a_XSSL_S_CONF_LOAD) &&
382 (cp = ok_vlook(ssl_config_file)) != NULL){
383 ul_i flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
385 if(*cp == '\0'){
386 cp = NULL;
387 flags = 0;
389 if(CONF_modules_load_file(cp, n_uagent, flags) == 1){
390 a_xssl_state |= a_XSSL_S_CONF_LOAD;
391 # if HAVE_XSSL_OPENSSL < 0x10100
392 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
393 a_xssl_state |= a_XSSL_S_EXIT_HDL;
394 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
396 # endif
397 }else
398 ssl_gen_err(_("Ignoring CONF_modules_load_file() load error"));
400 #endif
402 if(!(a_xssl_state & a_XSSL_S_RAND_INIT) && a_xssl_rand_init())
403 a_xssl_state |= a_XSSL_S_RAND_INIT;
404 NYD_LEAVE;
407 #if HAVE_XSSL_OPENSSL < 0x10100
408 # ifdef HAVE_SSL_ALL_ALGORITHMS
409 static void
410 a_xssl__load_algos(void){
411 NYD2_ENTER;
412 if(!(a_xssl_state & a_XSSL_S_ALGO_LOAD)){
413 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
414 OpenSSL_add_all_algorithms();
416 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
417 a_xssl_state |= a_XSSL_S_EXIT_HDL;
418 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
421 NYD2_LEAVE;
423 # endif
425 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
426 static void
427 a_xssl_atexit(void){
428 NYD2_ENTER;
429 # ifdef HAVE_XSSL_CONFIG
430 if(a_xssl_state & a_XSSL_S_CONF_LOAD)
431 CONF_modules_free();
432 # endif
434 # ifdef HAVE_SSL_ALL_ALGORITHMS
435 if(a_xssl_state & a_XSSL_S_ALGO_LOAD)
436 EVP_cleanup();
437 # endif
438 NYD2_LEAVE;
440 # endif
441 #endif /* HAVE_XSSL_OPENSSL < 0x10100 */
443 static bool_t
444 _ssl_parse_asn1_time(ASN1_TIME const *atp, char *bdat, size_t blen)
446 BIO *mbp;
447 char *mcp;
448 long l;
449 NYD_ENTER;
451 mbp = BIO_new(BIO_s_mem());
453 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
454 snprintf(bdat, blen, "%.*s", (int)l, mcp);
455 else {
456 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
457 /*is (int)*/atp->length, (char const*)atp->data);
458 mcp = NULL;
461 BIO_free(mbp);
462 NYD_LEAVE;
463 return (mcp != NULL);
466 static int
467 _ssl_verify_cb(int success, X509_STORE_CTX *store)
469 char data[256];
470 X509 *cert;
471 int rv = TRU1;
472 NYD_ENTER;
474 if (success && !(n_poption & n_PO_D_V))
475 goto jleave;
477 if (a_xssl_msgno != 0) {
478 n_err(_("Message %lu:\n"), (ul_i)a_xssl_msgno);
479 a_xssl_msgno = 0;
481 n_err(_(" Certificate depth %d %s\n"),
482 X509_STORE_CTX_get_error_depth(store), (success ? n_empty : V_(n_error)));
484 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
485 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
486 n_err(_(" subject = %s\n"), data);
488 _ssl_parse_asn1_time(a_xssl_X509_get_notBefore(cert), data, sizeof data);
489 n_err(_(" notBefore = %s\n"), data);
491 _ssl_parse_asn1_time(a_xssl_X509_get_notAfter(cert), data, sizeof data);
492 n_err(_(" notAfter = %s\n"), data);
494 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
495 n_err(_(" issuer = %s\n"), data);
498 if (!success) {
499 int err = X509_STORE_CTX_get_error(store);
501 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
502 a_xssl_state |= a_XSSL_S_VERIFY_ERROR;
505 if (!success && ssl_verify_decide() != OKAY)
506 rv = FAL0;
507 jleave:
508 NYD_LEAVE;
509 return rv;
512 #ifdef HAVE_XSSL_CONF_CTX
513 static void *
514 _ssl_conf_setup(SSL_CTX *ctxp)
516 SSL_CONF_CTX *sccp;
517 NYD_ENTER;
519 if ((sccp = SSL_CONF_CTX_new()) != NULL) {
520 SSL_CONF_CTX_set_flags(sccp,
521 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
522 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
524 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
525 } else
526 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
528 NYD_LEAVE;
529 return sccp;
532 static bool_t
533 _ssl_conf(void *confp, enum a_xssl_conf_type ct, char const *value)
535 int rv;
536 char const *cmsg;
537 SSL_CONF_CTX *sccp = (SSL_CONF_CTX*)confp;
538 NYD_ENTER;
540 switch (ct) {
541 case a_XSSL_CT_CERTIFICATE:
542 cmsg = "ssl-cert";
543 rv = SSL_CONF_cmd(sccp, "Certificate", value);
544 break;
545 case a_XSSL_CT_CIPHER_STRING:
546 cmsg = "ssl-cipher-list";
547 rv = SSL_CONF_cmd(sccp, "CipherString", value);
548 break;
549 case a_XSSL_CT_PRIVATE_KEY:
550 cmsg = "ssl-key";
551 rv = SSL_CONF_cmd(sccp, "PrivateKey", value);
552 break;
553 default:
554 case a_XSSL_CT_OPTIONS:
555 cmsg = "ssl-options";
556 rv = SSL_CONF_cmd(sccp, "Options", "Bugs");
557 break;
558 case a_XSSL_CT_PROTOCOL:
559 cmsg = "ssl-protocol";
560 rv = SSL_CONF_cmd(sccp, "Protocol", value);
561 break;
564 if (rv == 2)
565 rv = 0;
566 else {
567 if (rv == 0)
568 ssl_gen_err(_("SSL_CONF_CTX_cmd() failed for *%s*"), cmsg);
569 else
570 n_err(_("%s: *%s* implementation error, please report this\n"),
571 n_uagent, cmsg);
572 rv = 1;
575 NYD_LEAVE;
576 return (rv == 0);
579 static bool_t
580 _ssl_conf_finish(void **confp, bool_t error)
582 SSL_CONF_CTX **sccp = (SSL_CONF_CTX**)confp;
583 bool_t rv;
584 NYD_ENTER;
586 if (!(rv = error))
587 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
589 SSL_CONF_CTX_free(*sccp);
591 *sccp = NULL;
592 NYD_LEAVE;
593 return rv;
596 #else /* HAVE_XSSL_CONF_CTX */
597 static void *
598 _ssl_conf_setup(SSL_CTX* ctxp)
600 return ctxp;
603 static bool_t
604 _ssl_conf(void *confp, enum a_xssl_conf_type ct, char const *value)
606 SSL_CTX *ctxp = (SSL_CTX*)confp;
607 NYD_ENTER;
609 switch (ct) {
610 case a_XSSL_CT_CERTIFICATE:
611 if (SSL_CTX_use_certificate_chain_file(ctxp, value) != 1) {
612 ssl_gen_err(_("Can't load certificate from file %s\n"),
613 n_shexp_quote_cp(value, FAL0));
614 confp = NULL;
616 break;
617 case a_XSSL_CT_CIPHER_STRING:
618 if (SSL_CTX_set_cipher_list(ctxp, value) != 1) {
619 ssl_gen_err(_("Invalid cipher string: %s\n"), value);
620 confp = NULL;
622 break;
623 case a_XSSL_CT_PRIVATE_KEY:
624 if (SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1) {
625 ssl_gen_err(_("Can't load private key from file %s\n"),
626 n_shexp_quote_cp(value, FAL0));
627 confp = NULL;
629 break;
630 case a_XSSL_CT_OPTIONS:
631 /* "Options"="Bugs" TODO *ssl-options* */
632 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
633 break;
634 case a_XSSL_CT_PROTOCOL: {
635 char *iolist, *cp, addin;
636 size_t i;
637 sl_i opts = 0;
639 confp = NULL;
640 for (iolist = cp = savestr(value);
641 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;) {
642 if (*cp == '\0') {
643 n_err(_("*ssl-protocol*: empty arguments are not supported\n"));
644 goto jleave;
647 addin = TRU1;
648 switch (cp[0]) {
649 case '-': addin = FAL0; /* FALLTHRU */
650 case '+': ++cp; /* FALLTHRU */
651 default : break;
654 for (i = 0;;) {
655 if (!asccasecmp(cp, a_xssl_protocols[i].sp_name)) {
656 /* We need to inverse the meaning of the _NO_s */
657 if (!addin)
658 opts |= a_xssl_protocols[i].sp_flag;
659 else
660 opts &= ~a_xssl_protocols[i].sp_flag;
661 break;
663 if (++i < n_NELEM(a_xssl_protocols))
664 continue;
665 n_err(_("*ssl-protocol*: unsupported value: %s\n"), cp);
666 goto jleave;
669 confp = ctxp;
670 SSL_CTX_set_options(ctxp, opts);
671 break;
674 jleave:
675 NYD_LEAVE;
676 return (confp != NULL);
679 static bool_t
680 _ssl_conf_finish(void **confp, bool_t error)
682 n_UNUSED(confp);
683 n_UNUSED(error);
684 return TRU1;
686 #endif /* !HAVE_XSSL_CONF_CTX */
688 static bool_t
689 _ssl_load_verifications(SSL_CTX *ctxp)
691 char *ca_dir, *ca_file;
692 X509_STORE *store;
693 bool_t rv = FAL0;
694 NYD_ENTER;
696 if (ssl_verify_level == SSL_VERIFY_IGNORE) {
697 rv = TRU1;
698 goto jleave;
701 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
702 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
703 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
704 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
706 if ((ca_dir != NULL || ca_file != NULL) &&
707 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1) {
708 char const *m1, *m2, *m3;
710 if (ca_dir != NULL) {
711 m1 = ca_dir;
712 m2 = (ca_file != NULL) ? _(" or ") : n_empty;
713 } else
714 m1 = m2 = n_empty;
715 m3 = (ca_file != NULL) ? ca_file : n_empty;
716 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
717 goto jleave;
720 if (!ok_blook(ssl_no_default_ca) &&
721 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
722 ssl_gen_err(_("Error loading default CA locations\n"));
723 goto jleave;
726 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
727 a_xssl_msgno = 0;
728 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
729 store = SSL_CTX_get_cert_store(ctxp);
730 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
732 rv = TRU1;
733 jleave:
734 NYD_LEAVE;
735 return rv;
738 static enum okay
739 ssl_check_host(struct sock *sp, struct url const *urlp)
741 char data[256];
742 X509 *cert;
743 n_XSSL_STACKOF(GENERAL_NAME) *gens;
744 GENERAL_NAME *gen;
745 X509_NAME *subj;
746 enum okay rv = STOP;
747 NYD_ENTER;
749 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
750 n_err(_("No certificate from: %s\n"), urlp->url_h_p.s);
751 goto jleave;
754 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
755 if (gens != NULL) {
756 int i;
758 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
759 gen = sk_GENERAL_NAME_value(gens, i);
760 if (gen->type == GEN_DNS) {
761 if (n_poption & n_PO_D_V)
762 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
763 urlp->url_host.s, (char*)gen->d.ia5->data);
764 rv = rfc2595_hostname_match(urlp->url_host.s,
765 (char*)gen->d.ia5->data);
766 if (rv == OKAY)
767 goto jdone;
772 if ((subj = X509_get_subject_name(cert)) != NULL &&
773 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
774 > 0) {
775 data[sizeof data - 1] = '\0';
776 if (n_poption & n_PO_D_V)
777 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
778 urlp->url_host.s, data);
779 rv = rfc2595_hostname_match(urlp->url_host.s, data);
782 jdone:
783 X509_free(cert);
784 jleave:
785 NYD_LEAVE;
786 return rv;
789 static int
790 smime_verify(struct message *m, int n, n_XSSL_STACKOF(X509) *chain,
791 X509_STORE *store)
793 char data[LINESIZE], *sender, *to, *cc, *cnttype;
794 int rv, c, i, j;
795 struct message *x;
796 FILE *fp, *ip;
797 off_t size;
798 BIO *fb, *pb;
799 PKCS7 *pkcs7;
800 n_XSSL_STACKOF(X509) *certs;
801 n_XSSL_STACKOF(GENERAL_NAME) *gens;
802 X509 *cert;
803 X509_NAME *subj;
804 GENERAL_NAME *gen;
805 NYD_ENTER;
807 rv = 1;
808 fp = NULL;
809 fb = NULL;
810 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
811 a_xssl_msgno = (size_t)n;
813 for (;;) {
814 sender = getsender(m);
815 to = hfield1("to", m);
816 cc = hfield1("cc", m);
817 cnttype = hfield1("content-type", m);
819 #undef _X
820 #undef _Y
821 #define _X (sizeof("application/") -1)
822 #define _Y(X) X, sizeof(X) -1
823 if (cnttype && is_asccaseprefix("application/", cnttype) &&
824 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
825 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
826 #undef _Y
827 #undef _X
828 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
829 goto jleave;
830 if (x != (struct message*)-1) {
831 m = x;
832 continue;
836 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
837 goto jleave;
838 size = m->m_size;
839 break;
842 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
843 NULL) {
844 n_perr(_("tempfile"), 0);
845 goto jleave;
847 while (size-- > 0) {
848 c = getc(ip);
849 putc(c, fp);
851 fflush_rewind(fp);
853 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
854 ssl_gen_err(_(
855 "Error creating BIO verification object for message %d"), n);
856 goto jleave;
859 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
860 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
861 goto jleave;
863 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
864 ssl_gen_err(_("Error verifying message %d"), n);
865 goto jleave;
868 if (sender == NULL) {
869 n_err(_("Warning: Message %d has no sender\n"), n);
870 rv = 0;
871 goto jleave;
874 certs = PKCS7_get0_signers(pkcs7, chain, 0);
875 if (certs == NULL) {
876 n_err(_("No certificates found in message %d\n"), n);
877 goto jleave;
880 for (i = 0; i < sk_X509_num(certs); ++i) {
881 cert = sk_X509_value(certs, i);
882 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
883 if (gens != NULL) {
884 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
885 gen = sk_GENERAL_NAME_value(gens, j);
886 if (gen->type == GEN_EMAIL) {
887 if (n_poption & n_PO_D_V)
888 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
889 sender, (char*)gen->d.ia5->data);
890 if (!asccasecmp((char*)gen->d.ia5->data, sender))
891 goto jfound;
896 if ((subj = X509_get_subject_name(cert)) != NULL &&
897 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
898 data, sizeof data) > 0) {
899 data[sizeof data -1] = '\0';
900 if (n_poption & n_PO_D_V)
901 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
902 sender, data);
903 if (!asccasecmp(data, sender))
904 goto jfound;
907 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
908 goto jleave;
909 jfound:
910 rv = ((a_xssl_state & a_XSSL_S_VERIFY_ERROR) != 0);
911 if (!rv)
912 fprintf(n_stdout, _("Message %d was verified successfully\n"), n);
913 jleave:
914 if (fb != NULL)
915 BIO_free(fb);
916 if (fp != NULL)
917 Fclose(fp);
918 NYD_LEAVE;
919 return rv;
922 static EVP_CIPHER const *
923 _smime_cipher(char const *name)
925 EVP_CIPHER const *cipher;
926 char *vn;
927 char const *cp;
928 size_t i;
929 NYD_ENTER;
931 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
932 snprintf(vn, (int)i, "smime-cipher-%s", name);
933 cp = n_var_vlook(vn, FAL0);
934 ac_free(vn);
936 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
937 cipher = a_XSSL_SMIME_DEFAULT_CIPHER();
938 goto jleave;
940 cipher = NULL;
942 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers); ++i)
943 if (!asccasecmp(a_xssl_smime_ciphers[i].sc_name, cp)) {
944 cipher = (*a_xssl_smime_ciphers[i].sc_fun)();
945 goto jleave;
947 #ifndef OPENSSL_NO_AES
948 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers_obs); ++i) /* TODO obsolete */
949 if (!asccasecmp(a_xssl_smime_ciphers_obs[i].sc_name, cp)) {
950 n_OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
951 cipher = (*a_xssl_smime_ciphers_obs[i].sc_fun)();
952 goto jleave;
954 #endif
956 /* Not a builtin algorithm, but we may have dynamic support for more */
957 #ifdef HAVE_SSL_ALL_ALGORITHMS
958 a_xssl_load_algos();
959 if((cipher = EVP_get_cipherbyname(cp)) != NULL)
960 goto jleave;
961 #endif
963 n_err(_("Invalid S/MIME cipher(s): %s\n"), cp);
964 jleave:
965 NYD_LEAVE;
966 return cipher;
969 static int
970 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
972 char *pass;
973 size_t len;
974 NYD_ENTER;
975 n_UNUSED(rwflag);
976 n_UNUSED(userdata);
978 /* New-style */
979 if(userdata != NULL){
980 struct url url;
981 struct ccred cred;
983 if(url_parse(&url, CPROTO_CCRED, userdata)){
984 if(ccred_lookup(&cred, &url)){
985 ssize_t slen;
987 if((slen = n_strscpy(buf, cred.cc_pass.s, size)) >= 0){
988 size = (int)slen;
989 goto jleave;
992 size = 0;
993 goto jleave;
997 /* Old-style */
998 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
999 len = strlen(pass);
1000 if (UICMP(z, len, >=, size))
1001 len = size -1;
1002 memcpy(buf, pass, len);
1003 buf[len] = '\0';
1004 size = (int)len;
1005 } else
1006 size = 0;
1007 jleave:
1008 NYD_LEAVE;
1009 return size;
1012 static FILE *
1013 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn,
1014 char const **match)
1016 char *vn;
1017 int vs;
1018 struct name *np;
1019 char const *name = xname, *name2 = xname2, *cp;
1020 FILE *fp = NULL;
1021 NYD_ENTER;
1023 jloop:
1024 if (name) {
1025 np = lextract(name, GTO | GSKIN);
1026 while (np != NULL) {
1027 /* This needs to be more intelligent since it will currently take the
1028 * first name for which a private key is available regardless of
1029 * whether it is the right one for the message */
1030 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1031 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
1032 cp = n_var_vlook(vn, FAL0);
1033 ac_free(vn);
1034 if (cp != NULL) {
1035 if (match != NULL)
1036 *match = np->n_name;
1037 goto jopen;
1039 np = np->n_flink;
1041 if (name2 != NULL) {
1042 name = name2;
1043 name2 = NULL;
1044 goto jloop;
1048 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
1049 goto jerr;
1050 if(match != NULL)
1051 *match = NULL;
1052 jopen:
1053 if ((cp = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
1054 goto jleave;
1055 if ((fp = Fopen(cp, "r")) == NULL)
1056 n_perr(cp, 0);
1057 jleave:
1058 NYD_LEAVE;
1059 return fp;
1060 jerr:
1061 if (dowarn)
1062 n_err(_("Could not find a certificate for %s%s%s\n"),
1063 xname, (xname2 != NULL ? _("or ") : n_empty),
1064 (xname2 != NULL ? xname2 : n_empty));
1065 goto jleave;
1068 static char const *
1069 _smime_sign_include_certs(char const *name)
1071 char const *rv;
1072 NYD_ENTER;
1074 /* See comments in smime_sign_cert() for algorithm pitfalls */
1075 if (name != NULL) {
1076 struct name *np;
1078 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1079 int vs;
1080 char *vn;
1082 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1083 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1084 rv = n_var_vlook(vn, FAL0);
1085 ac_free(vn);
1086 if (rv != NULL)
1087 goto jleave;
1090 rv = ok_vlook(smime_sign_include_certs);
1091 jleave:
1092 NYD_LEAVE;
1093 return rv;
1096 static bool_t
1097 _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
1098 char const *cfiles, char const *addr)
1100 X509 *tmp;
1101 FILE *fp;
1102 char *nfield, *cfield, *x;
1103 NYD_ENTER;
1105 *chain = sk_X509_new_null();
1107 for (nfield = savestr(cfiles);
1108 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1109 if ((x = fexpand(cfield, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1110 (fp = Fopen(cfield = x, "r")) == NULL) {
1111 n_perr(cfiles, 0);
1112 goto jerr;
1114 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, n_UNCONST(addr))
1115 ) == NULL) {
1116 ssl_gen_err(_("Error reading certificate from %s"),
1117 n_shexp_quote_cp(cfield, FAL0));
1118 Fclose(fp);
1119 goto jerr;
1121 sk_X509_push(*chain, tmp);
1122 Fclose(fp);
1125 if (sk_X509_num(*chain) == 0) {
1126 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1127 goto jerr;
1129 jleave:
1130 NYD_LEAVE;
1131 return (*chain != NULL);
1132 jerr:
1133 sk_X509_pop_free(*chain, X509_free);
1134 *chain = NULL;
1135 goto jleave;
1138 static EVP_MD const *
1139 _smime_sign_digest(char const *name, char const **digname)
1141 EVP_MD const *digest;
1142 char const *cp;
1143 size_t i;
1144 NYD_ENTER;
1146 /* See comments in smime_sign_cert() for algorithm pitfalls */
1147 if (name != NULL) {
1148 struct name *np;
1150 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1151 int vs;
1152 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1153 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1154 cp = n_var_vlook(vn, FAL0);
1155 ac_free(vn);
1156 if (cp != NULL)
1157 goto jhave_name;
1161 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1162 digest = a_XSSL_SMIME_DEFAULT_DIGEST();
1163 *digname = a_XSSL_SMIME_DEFAULT_DIGEST_S;
1164 goto jleave;
1167 jhave_name:
1168 i = strlen(cp);
1169 { char *x = salloc(i +1);
1170 i_strcpy(x, cp, i +1);
1171 cp = x;
1173 *digname = cp;
1175 for (i = 0; i < n_NELEM(a_xssl_smime_digests); ++i)
1176 if (!asccasecmp(a_xssl_smime_digests[i].sd_name, cp)) {
1177 digest = (*a_xssl_smime_digests[i].sd_fun)();
1178 goto jleave;
1181 /* Not a builtin algorithm, but we may have dynamic support for more */
1182 #ifdef HAVE_SSL_ALL_ALGORITHMS
1183 a_xssl_load_algos();
1184 if((digest = EVP_get_digestbyname(cp)) != NULL)
1185 goto jleave;
1186 #endif
1188 n_err(_("Invalid message digest: %s\n"), cp);
1189 digest = NULL;
1190 jleave:
1191 NYD_LEAVE;
1192 return digest;
1195 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1196 static enum okay
1197 load_crl1(X509_STORE *store, char const *name)
1199 X509_LOOKUP *lookup;
1200 enum okay rv = STOP;
1201 NYD_ENTER;
1203 if (n_poption & n_PO_D_V)
1204 n_err(_("Loading CRL from %s\n"), n_shexp_quote_cp(name, FAL0));
1205 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1206 ssl_gen_err(_("Error creating X509 lookup object"));
1207 goto jleave;
1209 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1210 ssl_gen_err(_("Error loading CRL from %s"), n_shexp_quote_cp(name, FAL0));
1211 goto jleave;
1213 rv = OKAY;
1214 jleave:
1215 NYD_LEAVE;
1216 return rv;
1218 #endif /* new OpenSSL */
1220 static enum okay
1221 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1223 char *crl_file, *crl_dir;
1224 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1225 DIR *dirp;
1226 struct dirent *dp;
1227 char *fn = NULL;
1228 int fs = 0, ds, es;
1229 #endif
1230 enum okay rv = STOP;
1231 NYD_ENTER;
1233 if ((crl_file = n_var_oklook(fok)) != NULL) {
1234 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1235 if ((crl_file = fexpand(crl_file, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1236 load_crl1(store, crl_file) != OKAY)
1237 goto jleave;
1238 #else
1239 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1240 goto jleave;
1241 #endif
1244 if ((crl_dir = n_var_oklook(dok)) != NULL) {
1245 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1246 char *x;
1247 if ((x = fexpand(crl_dir, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1248 (dirp = opendir(crl_dir = x)) == NULL) {
1249 n_perr(crl_dir, 0);
1250 goto jleave;
1253 ds = strlen(crl_dir);
1254 fn = smalloc(fs = ds + 20);
1255 memcpy(fn, crl_dir, ds);
1256 fn[ds] = '/';
1257 while ((dp = readdir(dirp)) != NULL) {
1258 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1259 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1260 continue;
1261 if (dp->d_name[0] == '.')
1262 continue;
1263 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1264 fn = srealloc(fn, fs = ds + es + 20);
1265 memcpy(fn + ds + 1, dp->d_name, es + 1);
1266 if (load_crl1(store, fn) != OKAY) {
1267 closedir(dirp);
1268 free(fn);
1269 goto jleave;
1272 closedir(dirp);
1273 free(fn);
1274 #else /* old OpenSSL */
1275 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1276 goto jleave;
1277 #endif
1279 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1280 if (crl_file || crl_dir)
1281 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1282 X509_V_FLAG_CRL_CHECK_ALL);
1283 #endif
1284 rv = OKAY;
1285 jleave:
1286 NYD_LEAVE;
1287 return rv;
1290 FL enum okay
1291 ssl_open(struct url const *urlp, struct sock *sp)
1293 SSL_CTX *ctxp;
1294 void *confp;
1295 char const *cp, *cp_base;
1296 size_t i;
1297 enum okay rv = STOP;
1298 NYD_ENTER;
1300 a_xssl_init();
1302 ssl_set_verify_level(urlp);
1304 if ((ctxp = SSL_CTX_new(n_XSSL_CLIENT_METHOD())) == NULL) {
1305 ssl_gen_err(_("SSL_CTX_new() failed"));
1306 goto jleave;
1309 /* Available with OpenSSL 0.9.6 or later */
1310 #ifdef SSL_MODE_AUTO_RETRY
1311 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1312 #endif
1314 if ((confp = _ssl_conf_setup(ctxp)) == NULL)
1315 goto jerr0;
1317 /* TODO obsolete Check for *ssl-method*, warp to a *ssl-protocol* value */
1318 if ((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL) {
1319 n_OBSOLETE(_("please use *ssl-protocol* instead of *ssl-method*"));
1320 if (n_poption & n_PO_D_V)
1321 n_err(_("*ssl-method*: %s\n"), cp);
1322 for (i = 0;;) {
1323 if (!asccasecmp(_ssl_methods[i].sm_name, cp)) {
1324 cp = _ssl_methods[i].sm_map;
1325 break;
1327 if (++i == n_NELEM(_ssl_methods)) {
1328 n_err(_("Unsupported TLS/SSL method: %s\n"), cp);
1329 goto jerr1;
1333 /* *ssl-protocol* */
1334 if ((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL) {
1335 if (n_poption & n_PO_D_V)
1336 n_err(_("*ssl-protocol*: %s\n"), cp_base);
1337 cp = cp_base;
1339 cp = (cp != NULL ? savecatsep(cp, ',', n_XSSL_DISABLED_PROTOCOLS)
1340 : n_XSSL_DISABLED_PROTOCOLS);
1341 if (!_ssl_conf(confp, a_XSSL_CT_PROTOCOL, cp))
1342 goto jerr1;
1344 /* *ssl-cert* */
1345 if ((cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL) {
1346 if (n_poption & n_PO_D_V)
1347 n_err(_("*ssl-cert* %s\n"), n_shexp_quote_cp(cp, FAL0));
1348 if ((cp_base = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL) {
1349 n_err(_("*ssl-cert* value expansion failed: %s\n"),
1350 n_shexp_quote_cp(cp, FAL0));
1351 goto jerr1;
1353 cp = cp_base;
1354 if (!_ssl_conf(confp, a_XSSL_CT_CERTIFICATE, cp))
1355 goto jerr1;
1357 /* *ssl-key* */
1358 if ((cp_base = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL) {
1359 if (n_poption & n_PO_D_V)
1360 n_err(_("*ssl-key* %s\n"), n_shexp_quote_cp(cp_base, FAL0));
1361 if ((cp = fexpand(cp_base, FEXP_LOCAL | FEXP_NOPROTO)) == NULL) {
1362 n_err(_("*ssl-key* value expansion failed: %s\n"),
1363 n_shexp_quote_cp(cp_base, FAL0));
1364 goto jerr1;
1367 if (!_ssl_conf(confp, a_XSSL_CT_PRIVATE_KEY, cp))
1368 goto jerr1;
1371 if ((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL &&
1372 !_ssl_conf(confp, a_XSSL_CT_CIPHER_STRING, cp))
1373 goto jerr1;
1375 if (!_ssl_load_verifications(ctxp))
1376 goto jerr1;
1378 if (!_ssl_conf(confp, a_XSSL_CT_OPTIONS, NULL)) /* TODO *ssl-options* */
1379 goto jerr1;
1381 /* Done with context setup, create our new per-connection structure */
1382 if (!_ssl_conf_finish(&confp, FAL0))
1383 goto jerr0;
1385 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1386 ssl_gen_err(_("SSL_new() failed"));
1387 goto jerr0;
1390 SSL_set_fd(sp->s_ssl, sp->s_fd);
1392 if (SSL_connect(sp->s_ssl) < 0) {
1393 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1394 goto jerr2;
1397 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1398 if (ssl_check_host(sp, urlp) != OKAY) {
1399 n_err(_("Host certificate does not match: %s\n"), urlp->url_h_p.s);
1400 if (ssl_verify_decide() != OKAY)
1401 goto jerr2;
1405 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1406 * and free it right now -- it is reference counted by sp->s_ssl.. */
1407 SSL_CTX_free(ctxp);
1408 sp->s_use_ssl = 1;
1409 rv = OKAY;
1410 jleave:
1411 NYD_LEAVE;
1412 return rv;
1413 jerr2:
1414 SSL_free(sp->s_ssl);
1415 sp->s_ssl = NULL;
1416 jerr1:
1417 if (confp != NULL)
1418 _ssl_conf_finish(&confp, TRU1);
1419 jerr0:
1420 SSL_CTX_free(ctxp);
1421 goto jleave;
1424 FL void
1425 ssl_gen_err(char const *fmt, ...)
1427 va_list ap;
1428 NYD_ENTER;
1430 va_start(ap, fmt);
1431 n_verr(fmt, ap);
1432 va_end(ap);
1434 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1435 NYD_LEAVE;
1438 FL int
1439 c_verify(void *vp)
1441 int *msgvec = vp, *ip, ec = 0, rv = 1;
1442 n_XSSL_STACKOF(X509) *chain = NULL;
1443 X509_STORE *store = NULL;
1444 char *ca_dir, *ca_file;
1445 NYD_ENTER;
1447 a_xssl_init();
1449 ssl_verify_level = SSL_VERIFY_STRICT;
1450 if ((store = X509_STORE_new()) == NULL) {
1451 ssl_gen_err(_("Error creating X509 store"));
1452 goto jleave;
1454 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1456 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1457 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
1458 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1459 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
1461 if (ca_dir != NULL || ca_file != NULL) {
1462 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
1463 ssl_gen_err(_("Error loading %s"),
1464 (ca_file != NULL) ? ca_file : ca_dir);
1465 goto jleave;
1468 if (!ok_blook(smime_no_default_ca)) {
1469 if (X509_STORE_set_default_paths(store) != 1) {
1470 ssl_gen_err(_("Error loading default CA locations"));
1471 goto jleave;
1475 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1476 goto jleave;
1478 srelax_hold();
1479 for (ip = msgvec; *ip != 0; ++ip) {
1480 struct message *mp = message + *ip - 1;
1481 setdot(mp);
1482 ec |= smime_verify(mp, *ip, chain, store);
1483 srelax();
1485 srelax_rele();
1487 if ((rv = ec) != 0)
1488 n_exit_status |= n_EXIT_ERR;
1489 jleave:
1490 if (store != NULL)
1491 X509_STORE_free(store);
1492 NYD_LEAVE;
1493 return rv;
1496 FL FILE *
1497 smime_sign(FILE *ip, char const *addr)
1499 FILE *rv = NULL, *sp = NULL, *fp = NULL, *bp, *hp;
1500 X509 *cert = NULL;
1501 n_XSSL_STACKOF(X509) *chain = NULL;
1502 EVP_PKEY *pkey = NULL;
1503 BIO *bb, *sb;
1504 PKCS7 *pkcs7;
1505 EVP_MD const *md;
1506 char const *name;
1507 bool_t bail = FAL0;
1508 NYD_ENTER;
1510 assert(addr != NULL);
1512 a_xssl_init();
1514 if (addr == NULL) {
1515 n_err(_("No *from* address for signing specified\n"));
1516 goto jleave;
1518 if ((fp = smime_sign_cert(addr, NULL, 1, NULL)) == NULL)
1519 goto jleave;
1521 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb,
1522 savecat(addr, ".smime-cert-key"))) == NULL) {
1523 ssl_gen_err(_("Error reading private key from"));
1524 goto jleave;
1527 rewind(fp);
1528 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb,
1529 savecat(addr, ".smime-cert-cert"))) == NULL) {
1530 ssl_gen_err(_("Error reading signer certificate from"));
1531 goto jleave;
1533 Fclose(fp);
1534 fp = NULL;
1536 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1537 !_smime_sign_include_chain_creat(&chain, name,
1538 savecat(addr, ".smime-include-certs")))
1539 goto jleave;
1541 name = NULL;
1542 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1543 goto jleave;
1545 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1546 NULL) {
1547 n_perr(_("tempfile"), 0);
1548 goto jleave;
1551 rewind(ip);
1552 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1553 goto jerr1;
1555 sb = NULL;
1556 pkcs7 = NULL;
1558 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1559 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1560 ssl_gen_err(_("Error creating BIO signing objects"));
1561 bail = TRU1;
1562 goto jerr;
1565 #undef _X
1566 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1567 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1568 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1569 bail = TRU1;
1570 goto jerr;
1572 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1573 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1574 bail = TRU1;
1575 goto jerr;
1577 if (!PKCS7_final(pkcs7, bb, _X)) {
1578 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1579 bail = TRU1;
1580 goto jerr;
1582 #undef _X
1584 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1585 ssl_gen_err(_("Error writing signed S/MIME data"));
1586 bail = TRU1;
1587 /*goto jerr*/
1589 jerr:
1590 if (pkcs7 != NULL)
1591 PKCS7_free(pkcs7);
1592 if (sb != NULL)
1593 BIO_free(sb);
1594 if (bb != NULL)
1595 BIO_free(bb);
1596 if (!bail) {
1597 rewind(bp);
1598 fflush_rewind(sp);
1599 rv = smime_sign_assemble(hp, bp, sp, name);
1600 } else
1601 jerr1:
1602 Fclose(sp);
1604 jleave:
1605 if (chain != NULL)
1606 sk_X509_pop_free(chain, X509_free);
1607 if (cert != NULL)
1608 X509_free(cert);
1609 if (pkey != NULL)
1610 EVP_PKEY_free(pkey);
1611 if (fp != NULL)
1612 Fclose(fp);
1613 NYD_LEAVE;
1614 return rv;
1617 FL FILE *
1618 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1620 FILE *rv = NULL, *yp, *fp, *bp, *hp;
1621 X509 *cert;
1622 PKCS7 *pkcs7;
1623 BIO *bb, *yb;
1624 n_XSSL_STACKOF(X509) *certs;
1625 EVP_CIPHER const *cipher;
1626 char *certfile;
1627 bool_t bail = FAL0;
1628 NYD_ENTER;
1630 if ((certfile = fexpand(xcertfile, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
1631 goto jleave;
1633 a_xssl_init();
1635 if ((cipher = _smime_cipher(to)) == NULL)
1636 goto jleave;
1637 if ((fp = Fopen(certfile, "r")) == NULL) {
1638 n_perr(certfile, 0);
1639 goto jleave;
1642 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1643 ssl_gen_err(_("Error reading encryption certificate from %s"),
1644 n_shexp_quote_cp(certfile, FAL0));
1645 bail = TRU1;
1647 Fclose(fp);
1648 if (bail)
1649 goto jleave;
1650 bail = FAL0;
1652 certs = sk_X509_new_null();
1653 sk_X509_push(certs, cert);
1655 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1656 NULL) {
1657 n_perr(_("tempfile"), 0);
1658 goto jerr1;
1661 rewind(ip);
1662 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1663 Fclose(yp);
1664 goto jerr1;
1667 yb = NULL;
1668 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1669 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1670 ssl_gen_err(_("Error creating BIO encryption objects"));
1671 bail = TRU1;
1672 goto jerr2;
1674 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1675 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
1676 bail = TRU1;
1677 goto jerr2;
1679 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1680 ssl_gen_err(_("Error writing encrypted S/MIME data"));
1681 bail = TRU1;
1682 /* goto jerr2 */
1685 jerr2:
1686 if (bb != NULL)
1687 BIO_free(bb);
1688 if (yb != NULL)
1689 BIO_free(yb);
1690 Fclose(bp);
1691 if (bail)
1692 Fclose(yp);
1693 else {
1694 fflush_rewind(yp);
1695 rv = smime_encrypt_assemble(hp, yp);
1697 jerr1:
1698 sk_X509_pop_free(certs, X509_free);
1699 jleave:
1700 NYD_LEAVE;
1701 return rv;
1704 FL struct message *
1705 smime_decrypt(struct message *m, char const *to, char const *cc,
1706 bool_t signcall)
1708 struct message *rv;
1709 FILE *fp, *bp, *hp, *op;
1710 X509 *cert;
1711 PKCS7 *pkcs7;
1712 EVP_PKEY *pkey;
1713 BIO *bb, *pb, *ob;
1714 char const *myaddr;
1715 long size;
1716 FILE *yp;
1717 NYD_ENTER;
1719 rv = NULL;
1720 cert = NULL;
1721 pkey = NULL;
1722 size = m->m_size;
1724 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1725 goto jleave;
1727 a_xssl_init();
1729 if ((fp = smime_sign_cert(to, cc, 0, &myaddr)) != NULL) {
1730 pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb,
1731 savecat(myaddr, ".smime-cert-key"));
1732 if (pkey == NULL) {
1733 ssl_gen_err(_("Error reading private key"));
1734 Fclose(fp);
1735 goto jleave;
1737 rewind(fp);
1739 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb,
1740 savecat(myaddr, ".smime-cert-cert"))) == NULL) {
1741 ssl_gen_err(_("Error reading decryption certificate"));
1742 Fclose(fp);
1743 EVP_PKEY_free(pkey);
1744 goto jleave;
1746 Fclose(fp);
1749 if ((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1750 NULL) {
1751 n_perr(_("tempfile"), 0);
1752 goto j_ferr;
1755 if (smime_split(yp, &hp, &bp, size, 1) == STOP)
1756 goto jferr;
1758 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1759 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
1760 ssl_gen_err(_("Error creating BIO decryption objects"));
1761 goto jferr;
1763 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
1764 ssl_gen_err(_("Error reading PKCS#7 object"));
1765 jferr:
1766 Fclose(op);
1767 j_ferr:
1768 if (cert)
1769 X509_free(cert);
1770 if (pkey)
1771 EVP_PKEY_free(pkey);
1772 goto jleave;
1775 if (PKCS7_type_is_signed(pkcs7)) {
1776 if (signcall) {
1777 setinput(&mb, m, NEED_BODY);
1778 rv = (struct message*)-1;
1779 goto jerr2;
1781 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1782 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1783 goto jerr;
1784 fseek(hp, 0L, SEEK_END);
1785 fprintf(hp, "X-Encryption-Cipher: none\n");
1786 fflush(hp);
1787 rewind(hp);
1788 } else if (pkey == NULL) {
1789 n_err(_("No appropriate private key found\n"));
1790 goto jerr2;
1791 } else if (cert == NULL) {
1792 n_err(_("No appropriate certificate found\n"));
1793 goto jerr2;
1794 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
1795 jerr:
1796 ssl_gen_err(_("Error decrypting PKCS#7 object"));
1797 jerr2:
1798 BIO_free(bb);
1799 BIO_free(ob);
1800 Fclose(op);
1801 Fclose(bp);
1802 Fclose(hp);
1803 if (cert != NULL)
1804 X509_free(cert);
1805 if (pkey != NULL)
1806 EVP_PKEY_free(pkey);
1807 goto jleave;
1809 BIO_free(bb);
1810 BIO_free(ob);
1811 if (cert)
1812 X509_free(cert);
1813 if (pkey)
1814 EVP_PKEY_free(pkey);
1815 fflush_rewind(op);
1816 Fclose(bp);
1818 rv = smime_decrypt_assemble(m, hp, op);
1819 jleave:
1820 NYD_LEAVE;
1821 return rv;
1824 FL enum okay
1825 smime_certsave(struct message *m, int n, FILE *op)
1827 struct message *x;
1828 char *to, *cc, *cnttype;
1829 int c, i;
1830 FILE *fp, *ip;
1831 off_t size;
1832 BIO *fb, *pb;
1833 PKCS7 *pkcs7;
1834 n_XSSL_STACKOF(X509) *certs, *chain = NULL;
1835 X509 *cert;
1836 enum okay rv = STOP;
1837 NYD_ENTER;
1839 a_xssl_msgno = (size_t)n;
1840 jloop:
1841 to = hfield1("to", m);
1842 cc = hfield1("cc", m);
1843 cnttype = hfield1("content-type", m);
1845 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1846 goto jleave;
1848 #undef _X
1849 #undef _Y
1850 #define _X (sizeof("application/") -1)
1851 #define _Y(X) X, sizeof(X) -1
1852 if (cnttype && is_asccaseprefix("application/", cnttype) &&
1853 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
1854 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
1855 #undef _Y
1856 #undef _X
1857 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1858 goto jleave;
1859 if (x != (struct message*)-1) {
1860 m = x;
1861 goto jloop;
1864 size = m->m_size;
1866 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1867 NULL) {
1868 n_perr(_("tempfile"), 0);
1869 goto jleave;
1872 while (size-- > 0) {
1873 c = getc(ip);
1874 putc(c, fp);
1876 fflush(fp);
1878 rewind(fp);
1879 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1880 ssl_gen_err("Error creating BIO object for message %d", n);
1881 Fclose(fp);
1882 goto jleave;
1885 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1886 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1887 BIO_free(fb);
1888 Fclose(fp);
1889 goto jleave;
1891 BIO_free(fb);
1892 Fclose(fp);
1894 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1895 if (certs == NULL) {
1896 n_err(_("No certificates found in message %d\n"), n);
1897 goto jleave;
1900 for (i = 0; i < sk_X509_num(certs); ++i) {
1901 cert = sk_X509_value(certs, i);
1902 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
1903 ssl_gen_err(_("Error writing certificate %d from message %d"),
1904 i, n);
1905 goto jleave;
1908 rv = OKAY;
1909 jleave:
1910 NYD_LEAVE;
1911 return rv;
1913 #endif /* HAVE_XSSL */
1915 /* s-it-mode */