Variables: slightly tweak a_amv_var_canonify(); maxdistance: 6
[s-mailx.git] / xssl.c
blob2c4c4a3768e8b42e5a2e76cafe1440e9e2d0a6dd
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ OpenSSL client implementation according to: John Viega, Matt Messier,
3 *@ Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
4 *@ TODO This needs an overhaul -- there _are_ stack leaks!?
6 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
7 * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
8 */
9 /*
10 * Copyright (c) 2002
11 * Gunnar Ritter. All rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by Gunnar Ritter
24 * and his contributors.
25 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
41 #undef n_FILE
42 #define n_FILE xssl
44 #ifndef HAVE_AMALGAMATION
45 # include "nail.h"
46 #endif
48 EMPTY_FILE()
49 #ifdef HAVE_XSSL
50 #include <sys/socket.h>
52 #include <openssl/crypto.h>
53 #include <openssl/err.h>
54 #include <openssl/evp.h>
55 #include <openssl/opensslv.h>
56 #include <openssl/pem.h>
57 #include <openssl/rand.h>
58 #include <openssl/ssl.h>
59 #include <openssl/x509v3.h>
60 #include <openssl/x509.h>
62 #ifdef HAVE_XSSL_CONFIG
63 # include <openssl/conf.h>
64 #endif
66 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
67 # include <dirent.h>
68 #endif
70 /* Compatibility shims which assume 0/-1 cannot really happen */
71 #ifndef HAVE_XSSL_CONF_CTX
72 # ifndef SSL_OP_NO_SSLv2
73 # define SSL_OP_NO_SSLv2 0
74 # endif
75 # ifndef SSL_OP_NO_SSLv3
76 # define SSL_OP_NO_SSLv3 0
77 # endif
78 # ifndef SSL_OP_NO_TLSv1
79 # define SSL_OP_NO_TLSv1 0
80 # endif
81 # ifndef SSL_OP_NO_TLSv1_1
82 # define SSL_OP_NO_TLSv1_1 0
83 # endif
84 # ifndef SSL_OP_NO_TLSv1_2
85 # define SSL_OP_NO_TLSv1_2 0
86 # endif
87 # ifndef SSL_OP_NO_TLSv1_3
88 # define SSL_OP_NO_TLSv1_3 0
89 # endif
90 /* SSL_CONF_CTX and _OP_NO_SSL_MASK were both introduced with 1.0.2!?! */
91 # ifndef SSL_OP_NO_SSL_MASK
92 # define SSL_OP_NO_SSL_MASK \
93 (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |\
94 SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 |\
95 SSL_OP_NO_TLSv1_3)
96 # endif
98 # ifndef SSL2_VERSION
99 # define SSL2_VERSION 0
100 # endif
101 # ifndef SSL3_VERSION
102 # define SSL3_VERSION 0
103 # endif
104 # ifndef TLS1_VERSION
105 # define TLS1_VERSION 0
106 # endif
107 # ifndef TLS1_1_VERSION
108 # define TLS1_1_VERSION 0
109 # endif
110 # ifndef TLS1_2_VERSION
111 # define TLS1_2_VERSION 0
112 # endif
113 # ifndef TLS1_3_VERSION
114 # define TLS1_3_VERSION 0
115 # endif
116 #endif
118 #ifdef HAVE_XSSL_STACK_OF
119 # define n_XSSL_STACKOF(X) STACK_OF(X)
120 #else
121 # define n_XSSL_STACKOF(X) /*X*/STACK
122 #endif
124 #if OPENSSL_VERSION_NUMBER + 0 >= 0x0090581fL
125 # define a_XSSL_RAND_LOAD_FILE_MAXBYTES -1
126 #else
127 # define a_XSSL_RAND_LOAD_FILE_MAXBYTES 1024
128 #endif
130 /* Compatibility sighs (that sigh is _really_ a cute one) */
131 #if HAVE_XSSL_OPENSSL >= 0x10100
132 # define a_xssl_X509_get_notBefore X509_get0_notBefore
133 # define a_xssl_X509_get_notAfter X509_get0_notAfter
134 #else
135 # define a_xssl_X509_get_notBefore X509_get_notBefore
136 # define a_xssl_X509_get_notAfter X509_get_notAfter
137 #endif
139 /* X509_STORE_set_flags */
140 #undef a_XSSL_X509_V_ANY
141 #ifndef X509_V_FLAG_NO_ALT_CHAINS
142 # define X509_V_FLAG_NO_ALT_CHAINS -1
143 #else
144 # undef a_XSSL_X509_V_ANY
145 # define a_XSSL_X509_V_ANY
146 #endif
147 #ifndef X509_V_FLAG_NO_CHECK_TIME
148 # define X509_V_FLAG_NO_CHECK_TIME -1
149 #else
150 # undef a_XSSL_X509_V_ANY
151 # define a_XSSL_X509_V_ANY
152 #endif
153 #ifndef X509_V_FLAG_PARTIAL_CHAIN
154 # define X509_V_FLAG_PARTIAL_CHAIN -1
155 #else
156 # undef a_XSSL_X509_V_ANY
157 # define a_XSSL_X509_V_ANY
158 #endif
159 #ifndef X509_V_FLAG_X509_STRICT
160 # define X509_V_FLAG_X509_STRICT -1
161 #else
162 # undef a_XSSL_X509_V_ANY
163 # define a_XSSL_X509_V_ANY
164 #endif
165 #ifndef X509_V_FLAG_TRUSTED_FIRST
166 # define X509_V_FLAG_TRUSTED_FIRST -1
167 #else
168 # undef a_XSSL_X509_V_ANY
169 # define a_XSSL_X509_V_ANY
170 #endif
172 enum a_xssl_state{
173 a_XSSL_S_INIT = 1u<<0,
174 a_XSSL_S_RAND_INIT = 1u<<1,
175 a_XSSL_S_CONF_LOAD = 1u<<2,
177 #if HAVE_XSSL_OPENSSL < 0x10100
178 a_XSSL_S_EXIT_HDL = 1u<<8,
179 a_XSSL_S_ALGO_LOAD = 1u<<9,
180 #endif
182 a_XSSL_S_VERIFY_ERROR = 1u<<16
185 struct ssl_method { /* TODO v15 obsolete */
186 char const sm_name[8];
187 char const sm_map[16];
190 #ifndef HAVE_XSSL_CONF_CTX
191 struct a_xssl_protocol{
192 char const sp_name[8];
193 sl_i sp_op_no; /* SSL_OP_NO_* bit */
194 ui16_t sp_version; /* *_VERSION number */
195 bool_t sp_ok_minmaxproto; /* Valid for {Min,Max}Protocol= */
196 bool_t sp_ok_proto; /* Valid for Protocol= */
197 ui8_t sp__dummy[4];
199 #endif
201 struct a_xssl_smime_cipher{
202 char const sc_name[8];
203 EVP_CIPHER const *(*sc_fun)(void);
206 struct a_xssl_smime_digest{
207 char const sd_name[8];
208 EVP_MD const *(*sd_fun)(void);
211 struct a_xssl_x509_v_flags{
212 char const xvf_name[20];
213 si32_t xvf_flag;
216 /* Supported SSL/TLS methods: update manual on change! */
217 static struct ssl_method const _ssl_methods[] = { /* TODO obsolete */
218 {"auto", "ALL,-SSLv2"},
219 {"ssl3", "-ALL,SSLv3"},
220 {"tls1", "-ALL,TLSv1"},
221 {"tls1.1", "-ALL,TLSv1.1"},
222 {"tls1.2", "-ALL,TLSv1.2"}
225 /* Update manual on change!
226 * Ensure array size by adding \0 to longest entry.
227 * Strictly to be sorted new/up to old/down, [0]=ALL, [x-1]=None! */
228 #ifndef HAVE_XSSL_CONF_CTX
229 static struct a_xssl_protocol const a_xssl_protocols[] = {
230 {"ALL", SSL_OP_NO_SSL_MASK, 0, FAL0, TRU1, {0}},
231 {"TLSv1.3\0", SSL_OP_NO_TLSv1_3, TLS1_3_VERSION, TRU1, TRU1, {0}},
232 {"TLSv1.2", SSL_OP_NO_TLSv1_2, TLS1_2_VERSION, TRU1, TRU1, {0}},
233 {"TLSv1.1", SSL_OP_NO_TLSv1_1, TLS1_1_VERSION, TRU1, TRU1, {0}},
234 {"TLSv1", SSL_OP_NO_TLSv1, TLS1_VERSION, TRU1, TRU1, {0}},
235 {"SSLv3", SSL_OP_NO_SSLv3, SSL3_VERSION, TRU1, TRU1, {0}},
236 {"SSLv2", SSL_OP_NO_SSLv2, SSL2_VERSION, TRU1, TRU1, {0}},
237 {"None", SSL_OP_NO_SSL_MASK, 0, TRU1, FAL0, {0}}
239 #endif /* HAVE_XSSL_CONF_CTX */
241 /* Supported S/MIME cipher algorithms */
242 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers[] = { /* Manual! */
243 #ifndef OPENSSL_NO_AES
244 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_aes_128_cbc /* According to RFC 5751 */
245 {"aes128", &EVP_aes_128_cbc},
246 {"aes256", &EVP_aes_256_cbc},
247 {"aes192", &EVP_aes_192_cbc},
248 #endif
249 #ifndef OPENSSL_NO_DES
250 # ifndef a_XSSL_SMIME_DEFAULT_CIPHER
251 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_des_ede3_cbc
252 # endif
253 {"des3", &EVP_des_ede3_cbc},
254 {"des", &EVP_des_cbc},
255 #endif
257 #ifndef a_XSSL_SMIME_DEFAULT_CIPHER
258 # error Your OpenSSL library does not include the necessary
259 # error cipher algorithms that are required to support S/MIME
260 #endif
262 #ifndef OPENSSL_NO_AES
263 /* TODO obsolete a_xssl_smime_ciphers_obs */
264 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers_obs[] = {
265 {"aes-128", &EVP_aes_128_cbc},
266 {"aes-256", &EVP_aes_256_cbc},
267 {"aes-192", &EVP_aes_192_cbc}
269 #endif
271 /* Supported S/MIME message digest algorithms */
272 static struct a_xssl_smime_digest const a_xssl_smime_digests[] = { /* Manual! */
273 #define a_XSSL_SMIME_DEFAULT_DIGEST EVP_sha1 /* According to RFC 5751 */
274 #define a_XSSL_SMIME_DEFAULT_DIGEST_S "sha1"
275 {"sha1", &EVP_sha1},
276 {"sha256", &EVP_sha256},
277 {"sha512", &EVP_sha512},
278 {"sha384", &EVP_sha384},
279 {"sha224", &EVP_sha224},
280 #ifndef OPENSSL_NO_MD5
281 {"md5", &EVP_md5},
282 #endif
285 /* X509_STORE_set_flags() for *{smime,ssl}-ca-flags* */
286 static struct a_xssl_x509_v_flags const a_xssl_x509_v_flags[] = { /* Manual! */
287 {"no-alt-chains", X509_V_FLAG_NO_ALT_CHAINS},
288 {"no-check-time", X509_V_FLAG_NO_CHECK_TIME},
289 {"partial-chain", X509_V_FLAG_PARTIAL_CHAIN},
290 {"strict", X509_V_FLAG_X509_STRICT},
291 {"trusted-first", X509_V_FLAG_TRUSTED_FIRST},
294 static enum a_xssl_state a_xssl_state;
295 static size_t a_xssl_msgno;
297 static void a_xssl_rand_init(void);
298 static void a_xssl_init(void);
300 #if HAVE_XSSL_OPENSSL < 0x10100
301 # ifdef HAVE_SSL_ALL_ALGORITHMS
302 static void a_xssl__load_algos(void);
303 # define a_xssl_load_algos a_xssl__load_algos
304 # endif
305 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
306 static void a_xssl_atexit(void);
307 # endif
308 #endif
309 #ifndef a_xssl_load_algos
310 # define a_xssl_load_algos() do{;}while(0)
311 #endif
313 static bool_t _ssl_parse_asn1_time(ASN1_TIME const *atp,
314 char *bdat, size_t blen);
315 static int _ssl_verify_cb(int success, X509_STORE_CTX *store);
317 /* *smime-ca-flags*, *ssl-ca-flags* */
318 static void a_xssl_ca_flags(X509_STORE *store, char const *flags);
320 /* SSL_CTX configuration */
321 static void * a_xssl_conf_setup(SSL_CTX *ctxp, struct url const *urlp);
322 static bool_t a_xssl_conf(void *confp, char const *cmd, char const *value);
323 static bool_t a_xssl_conf_finish(void **confp, bool_t error);
325 static bool_t a_xssl_obsolete_conf_vars(void *confp, struct url const *urlp);
326 static bool_t a_xssl_config_pairs(void *confp, struct url const *urlp);
327 static bool_t a_xssl_load_verifications(SSL_CTX *ctxp, struct url const *urlp);
329 static enum okay ssl_check_host(struct sock *sp, struct url const *urlp);
331 static int smime_verify(struct message *m, int n,
332 n_XSSL_STACKOF(X509) *chain, X509_STORE *store);
333 static EVP_CIPHER const * _smime_cipher(char const *name);
334 static int ssl_password_cb(char *buf, int size, int rwflag,
335 void *userdata);
336 static FILE * smime_sign_cert(char const *xname, char const *xname2,
337 bool_t dowarn, char const **match);
338 static char const * _smime_sign_include_certs(char const *name);
339 static bool_t _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
340 char const *cfiles, char const *addr);
341 static EVP_MD const * _smime_sign_digest(char const *name,
342 char const **digname);
343 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
344 static enum okay load_crl1(X509_STORE *store, char const *name);
345 #endif
346 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
348 static void
349 a_xssl_rand_init(void){
350 #define a_XSSL_RAND_ENTROPY 32
351 char b64buf[a_XSSL_RAND_ENTROPY * 5 +1], *randfile;
352 char const *cp, *x;
353 bool_t err;
354 NYD2_ENTER;
356 a_xssl_state |= a_XSSL_S_RAND_INIT;
358 err = TRU1;
359 randfile = NULL;
361 #ifdef HAVE_XSSL_CONFIG
362 if(!(a_xssl_state & a_XSSL_S_INIT))
363 a_xssl_init();
364 #endif
366 /* Shall use some external daemon? */
367 if((cp = ok_vlook(ssl_rand_egd)) != NULL){
368 #ifdef HAVE_XSSL_RAND_EGD
369 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) != NULL &&
370 RAND_egd(cp = x) != -1){
371 err = FAL0;
372 goto jleave;
374 n_err(_("*ssl_rand_egd* daemon at %s not available\n"),
375 n_shexp_quote_cp(cp, FAL0));
376 #else
377 if(n_poption & n_PO_D_VV)
378 n_err(_("*ssl_rand_egd* (%s): unsupported by SSL library\n"),
379 n_shexp_quote_cp(cp, FAL0));
380 #endif
383 /* Prefer possible user setting */
384 if((cp = ok_vlook(ssl_rand_file)) != NULL){
385 x = NULL;
386 if(*cp != '\0'){
387 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
388 n_err(_("*ssl-rand-file*: expansion of %s failed "
389 "(using OpenSSL default)\n"),
390 n_shexp_quote_cp(cp, FAL0));
392 cp = x;
394 if(cp == NULL){
395 randfile = n_lofi_alloc(PATH_MAX);
396 if((cp = RAND_file_name(randfile, PATH_MAX)) == NULL){
397 n_err(_("*ssl-rand-file*: no SSL entropy file, can't seed PRNG\n"));
398 goto jleave;
402 (void)RAND_load_file(cp, a_XSSL_RAND_LOAD_FILE_MAXBYTES);
404 /* And feed in some data, then write the updated file.
405 * While this rather feeds the PRNG with itself in the n_RANDOM_IMPL_SSL
406 * case, let us stir the buffer a little bit.
407 * Estimate a low but likely still too high number of entropy bytes, use
408 * 20%: base64 uses 3 input = 4 output bytes relation, and the base64
409 * alphabet is a 6 bit one */
410 for(x = (char*)-1;;){
411 RAND_add(n_random_create_buf(b64buf, sizeof(b64buf) -1, NULL),
412 sizeof(b64buf) -1, a_XSSL_RAND_ENTROPY);
413 if((x = (char*)((uintptr_t)x >> (1
414 #if HAVE_RANDOM == n_RANDOM_IMPL_SSL
416 #endif
417 ))) == NULL){
418 err = (RAND_status() == 0);
419 break;
421 #if HAVE_RANDOM != n_RANDOM_IMPL_SSL
422 if(!(err = (RAND_status() == 0)))
423 break;
424 #endif
427 if(!err)
428 err = (RAND_write_file(cp) == -1);
430 jleave:
431 if(randfile != NULL)
432 n_lofi_free(randfile);
433 if(err)
434 n_panic(_("Cannot seed the *SSL PseudoRandomNumberGenerator, "
435 "RAND_status() is 0!\n"
436 " Please set *ssl-rand-file* to a file with sufficient entropy.\n"
437 " On a machine with entropy: "
438 "\"$ dd if=/dev/urandom of=FILE bs=1024 count=1\"\n"));
439 NYD2_LEAVE;
442 static void
443 a_xssl_init(void){
444 #ifdef HAVE_XSSL_CONFIG
445 char const *cp;
446 #endif
447 NYD2_ENTER;
449 if(a_xssl_state & a_XSSL_S_INIT)
450 goto jleave;
452 #if HAVE_XSSL_OPENSSL >= 0x10100
453 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS |
454 OPENSSL_INIT_LOAD_CRYPTO_STRINGS
455 # ifdef HAVE_SSL_ALL_ALGORITHMS
456 | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS
457 # endif
458 , NULL);
459 #else
460 SSL_load_error_strings();
461 SSL_library_init();
462 a_xssl_load_algos();
463 #endif
464 a_xssl_state |= a_XSSL_S_INIT;
467 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
468 #ifdef HAVE_XSSL_CONFIG
469 if((cp = ok_vlook(ssl_config_file)) != NULL){
470 char const *msg;
471 ul_i flags;
473 if(*cp == '\0'){
474 msg = "[default]";
475 cp = NULL;
476 flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
477 }else if((msg = cp, cp = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) != NULL)
478 flags = 0;
479 else{
480 n_err(_("*ssl-config-file*: file expansion failed: %s\n"),
481 n_shexp_quote_cp(msg, FAL0));
482 goto jefile;
485 if(CONF_modules_load_file(cp, n_uagent, flags) == 1){
486 a_xssl_state |= a_XSSL_S_CONF_LOAD;
487 # if HAVE_XSSL_OPENSSL < 0x10100
488 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
489 a_xssl_state |= a_XSSL_S_EXIT_HDL;
490 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
492 # endif
493 if(n_poption & n_PO_D_V)
494 n_err(_("Loaded SSL/TLS configuration for %s from %s\n"), n_uagent,
495 n_shexp_quote_cp(msg, FAL0));
496 jefile:;
497 }else
498 ssl_gen_err(_("SSL/TLS CONF_modules_load_file() load error"));
500 #endif /* HAVE_XSSL_CONFIG */
502 if(!(a_xssl_state & a_XSSL_S_RAND_INIT))
503 a_xssl_rand_init();
504 jleave:
505 NYD2_LEAVE;
508 #if HAVE_XSSL_OPENSSL < 0x10100
509 # ifdef HAVE_SSL_ALL_ALGORITHMS
510 static void
511 a_xssl__load_algos(void){
512 NYD2_ENTER;
513 if(!(a_xssl_state & a_XSSL_S_ALGO_LOAD)){
514 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
515 OpenSSL_add_all_algorithms();
517 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
518 a_xssl_state |= a_XSSL_S_EXIT_HDL;
519 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
522 NYD2_LEAVE;
524 # endif
526 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
527 static void
528 a_xssl_atexit(void){
529 NYD2_ENTER;
530 # ifdef HAVE_XSSL_CONFIG
531 if(a_xssl_state & a_XSSL_S_CONF_LOAD)
532 CONF_modules_free();
533 # endif
535 # ifdef HAVE_SSL_ALL_ALGORITHMS
536 if(a_xssl_state & a_XSSL_S_ALGO_LOAD)
537 EVP_cleanup();
538 # endif
539 NYD2_LEAVE;
541 # endif
542 #endif /* HAVE_XSSL_OPENSSL < 0x10100 */
544 static bool_t
545 _ssl_parse_asn1_time(ASN1_TIME const *atp, char *bdat, size_t blen)
547 BIO *mbp;
548 char *mcp;
549 long l;
550 NYD_ENTER;
552 mbp = BIO_new(BIO_s_mem());
554 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
555 snprintf(bdat, blen, "%.*s", (int)l, mcp);
556 else {
557 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
558 /*is (int)*/atp->length, (char const*)atp->data);
559 mcp = NULL;
562 BIO_free(mbp);
563 NYD_LEAVE;
564 return (mcp != NULL);
567 static int
568 _ssl_verify_cb(int success, X509_STORE_CTX *store)
570 char data[256];
571 X509 *cert;
572 int rv = TRU1;
573 NYD_ENTER;
575 if (success && !(n_poption & n_PO_D_V))
576 goto jleave;
578 if (a_xssl_msgno != 0) {
579 n_err(_("Message %lu:\n"), (ul_i)a_xssl_msgno);
580 a_xssl_msgno = 0;
582 n_err(_(" Certificate depth %d %s\n"),
583 X509_STORE_CTX_get_error_depth(store), (success ? n_empty : V_(n_error)));
585 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
586 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
587 n_err(_(" subject = %s\n"), data);
589 _ssl_parse_asn1_time(a_xssl_X509_get_notBefore(cert), data, sizeof data);
590 n_err(_(" notBefore = %s\n"), data);
592 _ssl_parse_asn1_time(a_xssl_X509_get_notAfter(cert), data, sizeof data);
593 n_err(_(" notAfter = %s\n"), data);
595 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
596 n_err(_(" issuer = %s\n"), data);
599 if (!success) {
600 int err = X509_STORE_CTX_get_error(store);
602 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
603 a_xssl_state |= a_XSSL_S_VERIFY_ERROR;
606 if (!success && ssl_verify_decide() != OKAY)
607 rv = FAL0;
608 jleave:
609 NYD_LEAVE;
610 return rv;
613 static void
614 a_xssl_ca_flags(X509_STORE *store, char const *flags){
615 NYD2_ENTER;
616 if(flags != NULL){
617 char *iolist, *cp;
619 iolist = savestr(flags);
620 jouter:
621 while((cp = n_strsep(&iolist, ',', TRU1)) != NULL){
622 struct a_xssl_x509_v_flags const *xvfp;
624 for(xvfp = &a_xssl_x509_v_flags[0];
625 xvfp < &a_xssl_x509_v_flags[n_NELEM(a_xssl_x509_v_flags)];
626 ++xvfp)
627 if(!asccasecmp(cp, xvfp->xvf_name)){
628 if(xvfp->xvf_flag != -1){
629 #ifdef a_XSSL_X509_V_ANY
630 X509_STORE_set_flags(store, xvfp->xvf_flag);
631 #endif
632 }else if(n_poption & n_PO_D_V)
633 n_err(_("*{smime,ssl}-ca-flags*: "
634 "directive not supported: %s\n"), cp);
635 goto jouter;
637 n_err(_("*{smime,ssl}-ca-flags*: invalid directive: %s\n"), cp);
640 NYD2_LEAVE;
643 #ifdef HAVE_XSSL_CONF_CTX
644 static void *
645 a_xssl_conf_setup(SSL_CTX *ctxp, struct url const *urlp){
646 char const *cp;
647 SSL_CONF_CTX *sccp;
648 NYD2_ENTER;
650 sccp = NULL;
652 if((cp = xok_vlook(ssl_config_module, urlp, OXM_ALL)) != NULL){
653 # ifdef HAVE_XSSL_CTX_CONFIG
654 if(!(a_xssl_state & a_XSSL_S_CONF_LOAD)){
655 n_err(_("*ssl-config-module*: no *ssl-config-file* loaded: %s\n"),
656 n_shexp_quote_cp(cp, FAL0));
657 goto jleave;
658 }else if(!SSL_CTX_config(ctxp, cp)){
659 ssl_gen_err(_("*ssl-config-module*: load error for %s, section [%s]"),
660 n_uagent, n_shexp_quote_cp(cp, FAL0));
661 goto jleave;
663 # else
664 n_err(_("*ssl-config-module*: set but not supported: %s\n"),
665 n_shexp_quote_cp(cp, FAL0));
666 goto jleave;
667 # endif
670 if((sccp = SSL_CONF_CTX_new()) != NULL){
671 SSL_CONF_CTX_set_flags(sccp,
672 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
673 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
675 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
676 }else
677 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
678 jleave:
679 NYD2_LEAVE;
680 return sccp;
683 static bool_t
684 a_xssl_conf(void *confp, char const *cmd, char const *value){
685 int rv;
686 SSL_CONF_CTX *sccp;
687 NYD2_ENTER;
689 if(n_poption & n_PO_D_V)
690 n_err(_("SSL/TLS: applying config: %s = %s\n"),
691 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(value, FAL0));
693 rv = SSL_CONF_cmd(sccp = confp, cmd, value);
694 if(rv == 2)
695 rv = 0;
696 else{
697 cmd = n_shexp_quote_cp(cmd, FAL0);
698 value = n_shexp_quote_cp(value, FAL0);
699 if(rv == 0)
700 ssl_gen_err(_("SSL/TLS: config failure: %s = %s"), cmd, value);
701 else{
702 char const *err;
704 switch(rv){
705 case -2: err = N_("SSL/TLS: config command not recognized"); break;
706 case -3: err = N_("SSL/TLS: missing required config argument"); break;
707 default: err = N_("SSL/TLS: unspecified config error"); break;
709 err = V_(err);
710 n_err(_("%s (%d): %s = %s\n"), err, rv, cmd, value);
712 rv = 1;
714 NYD2_LEAVE;
715 return (rv == 0);
718 static bool_t
719 a_xssl_conf_finish(void **confp, bool_t error){
720 SSL_CONF_CTX **sccp;
721 bool_t rv;
722 NYD2_ENTER;
724 sccp = (SSL_CONF_CTX**)confp;
726 if(!(rv = error))
727 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
729 SSL_CONF_CTX_free(*sccp);
731 *sccp = NULL;
732 NYD2_LEAVE;
733 return rv;
736 #else /* HAVE_XSSL_CONF_CTX */
737 # ifdef HAVE_XSSL_CTX_CONFIG
738 # error SSL_CTX_config(3) support unexpected without SSL_CONF_CTX support
739 # endif
741 static void *
742 a_xssl_conf_setup(SSL_CTX* ctxp, struct url const *urlp){
743 char const *cp;
744 NYD2_ENTER;
746 if((cp = xok_vlook(ssl_config_module, urlp, OXM_ALL)) != NULL){
747 n_err(_("*ssl-config-module*: set but not supported: %s\n"),
748 n_shexp_quote_cp(cp, FAL0));
749 ctxp = NULL;
751 NYD2_LEAVE;
752 return ctxp;
755 static bool_t
756 a_xssl_conf(void *confp, char const *cmd, char const *value){
757 char const *xcmd, *emsg;
758 SSL_CTX *ctxp;
759 NYD2_ENTER;
761 if(n_poption & n_PO_D_V)
762 n_err(_("SSL/TLS: applying config: %s = %s\n"),
763 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(value, FAL0));
765 ctxp = confp;
767 if(!asccasecmp(cmd, xcmd = "Certificate")){
768 if(SSL_CTX_use_certificate_chain_file(ctxp, value) != 1){
769 emsg = N_("SSL/TLS: %s: cannot load from file %s\n");
770 goto jerr;
772 }else if(!asccasecmp(cmd, xcmd = "CipherString") ||
773 !asccasecmp(cmd, xcmd = "CipherList")){
774 if(SSL_CTX_set_cipher_list(ctxp, value) != 1){
775 emsg = N_("SSL/TLS: %s: invalid: %s\n");
776 goto jerr;
778 }else if(!asccasecmp(cmd, xcmd = "Ciphersuites")){
779 #ifdef HAVE_XSSL_SET_CIPHERSUITES
780 if(SSL_CTX_set_ciphersuites(ctxp, value) != 1){
781 emsg = N_("SSL/TLS: %s: invalid: %s\n");
782 goto jerr;
784 #else
785 value = NULL;
786 emsg = N_("SSL/TLS: %s: directive not supported\n");
787 goto jxerr;
788 #endif
789 }else if(!asccasecmp(cmd, xcmd = "Curves")){
790 #ifdef SSL_CTRL_SET_CURVES_LIST
791 if(SSL_CTX_set1_curves_list(ctxp, value) != 1){
792 emsg = N_("SSL/TLS: %s: invalid: %s\n");
793 goto jerr;
795 #else
796 value = NULL;
797 emsg = N_("SSL/TLS: %s: directive not supported\n");
798 goto jxerr;
799 #endif
800 }else if((emsg = NULL, !asccasecmp(cmd, xcmd = "MaxProtocol")) ||
801 (emsg = (char*)-1, !asccasecmp(cmd, xcmd = "MinProtocol"))){
802 #ifndef HAVE_XSSL_SET_MIN_PROTO_VERSION
803 value = NULL;
804 emsg = N_("SSL/TLS: %s: directive not supported\n");
805 goto jxerr;
806 #else
807 struct a_xssl_protocol const *xpp;
808 size_t i;
810 for(i = 1 /* [0] == ALL */;;){
811 xpp = &a_xssl_protocols[i];
813 if(xpp->sp_ok_minmaxproto && !asccasecmp(value, xpp->sp_name))
814 break;
816 if(++i >= n_NELEM(a_xssl_protocols)){
817 emsg = N_("SSL/TLS: %s: unsupported element: %s\n");
818 goto jxerr;
822 if((emsg == NULL ? SSL_CTX_set_max_proto_version(ctxp, xpp->sp_version)
823 : SSL_CTX_set_min_proto_version(ctxp, xpp->sp_version)) != 1){
824 emsg = N_("SSL/TLS: %s: invalid protocol: %s\n");
825 goto jerr;
827 #endif /* !HAVE_XSSL_SET_MIN_PROTO_VERSION */
828 }else if(!asccasecmp(cmd, xcmd = "Options")){
829 if(asccasecmp(value, "Bugs")){
830 emsg = N_("SSL/TLS: %s: fallback only supports value \"Bugs\": %s\n");
831 goto jxerr;
833 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
834 }else if(!asccasecmp(cmd, xcmd = "PrivateKey")){
835 if(SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1){
836 emsg = N_("%s: cannot load from file %s\n");
837 goto jerr;
839 }else if(!asccasecmp(cmd, xcmd = "Protocol")){
840 char *iolist, *cp, addin;
841 size_t i;
842 sl_i opts;
844 opts = 0;
846 for(iolist = cp = savestr(value);
847 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;){
848 if(*cp == '\0'){
849 value = NULL;
850 emsg = N_("SSL/TLS: %s: empty elements are not supported\n");
851 goto jxerr;
854 addin = TRU1;
855 switch(cp[0]){
856 case '-': addin = FAL0; /* FALLTHRU */
857 case '+': ++cp; /* FALLTHRU */
858 default : break;
861 for(i = 0;;){
862 struct a_xssl_protocol const *xpp;
864 xpp = &a_xssl_protocols[i];
866 if(xpp->sp_ok_proto && !asccasecmp(cp, xpp->sp_name)){
867 /* We need to inverse the meaning of the _NO_s */
868 if(!addin)
869 opts |= xpp->sp_op_no;
870 else
871 opts &= ~xpp->sp_op_no;
872 break;
875 if(++i >= n_NELEM(a_xssl_protocols)){
876 emsg = N_("SSL/TLS: %s: unsupported element: %s\n");
877 goto jxerr;
882 SSL_CTX_clear_options(ctxp, SSL_OP_NO_SSL_MASK);
883 SSL_CTX_set_options(ctxp, opts);
884 }else{
885 xcmd = n_shexp_quote_cp(cmd, FAL0);
886 emsg = N_("SSL/TLS: unsupported directive: %s: value: %s\n");
887 goto jxerr;
890 jleave:
891 NYD2_LEAVE;
892 return (confp != NULL);
893 jerr:
894 ssl_gen_err(V_(emsg), xcmd, n_shexp_quote_cp(value, FAL0));
895 confp = NULL;
896 goto jleave;
897 jxerr:
898 if(value != NULL)
899 value = n_shexp_quote_cp(value, FAL0);
900 n_err(V_(emsg), xcmd, value);
901 confp = NULL;
902 goto jleave;
905 static bool_t
906 a_xssl_conf_finish(void **confp, bool_t error){
907 n_UNUSED(confp);
908 n_UNUSED(error);
909 return TRU1;
911 #endif /* !HAVE_XSSL_CONF_CTX */
913 static bool_t
914 a_xssl_obsolete_conf_vars(void *confp, struct url const *urlp){
915 char const *cp, *cp_base, *certchain;
916 bool_t rv;
917 NYD2_ENTER;
919 rv = FAL0;
921 /* Certificate via ssl-cert */
922 if((certchain = cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL){
923 n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-cert*"));
924 if((cp_base = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL){
925 n_err(_("*ssl-cert* value expansion failed: %s\n"),
926 n_shexp_quote_cp(cp, FAL0));
927 goto jleave;
929 if(!a_xssl_conf(confp, "Certificate", certchain = cp_base))
930 goto jleave;
933 /* CipherString via ssl-ciper-list */
934 if((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL){
935 n_OBSOLETE(_("please use *ssl-config-pairs* instead of "
936 "*ssl-cipher-list*"));
937 if(!a_xssl_conf(confp, "CipherString", cp))
938 goto jleave;
941 /* Curves via ssl-curves */
942 if((cp = xok_vlook(ssl_curves, urlp, OXM_ALL)) != NULL){
943 n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-curves*"));
944 if(!a_xssl_conf(confp, "Curves", cp))
945 goto jleave;
948 /* PrivateKey via ssl-key */
949 if((cp = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL){
950 n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-curves*"));
951 if((cp_base = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL){
952 n_err(_("*ssl-key* value expansion failed: %s\n"),
953 n_shexp_quote_cp(cp, FAL0));
954 goto jleave;
956 cp = cp_base;
957 if(certchain == NULL){
958 n_err(_("*ssl-key* can only be used together with *ssl-cert*! "
959 "And use *ssl-config-pairs*!\n"));
960 goto jleave;
963 if((cp != NULL || (cp = certchain) != NULL) &&
964 !a_xssl_conf(confp, "PrivateKey", cp))
965 goto jleave;
967 /* Protocol via ssl-method or ssl-protocol */
968 if((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL){
969 size_t i;
971 n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-method*"));
972 for(i = 0;;){
973 if(!asccasecmp(_ssl_methods[i].sm_name, cp)){
974 cp = _ssl_methods[i].sm_map;
975 break;
977 if(++i == n_NELEM(_ssl_methods)){
978 n_err(_("Unsupported TLS/SSL method: %s\n"), cp);
979 goto jleave;
983 if((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL){
984 n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-protocol*"));
985 if(cp != NULL && (n_poption & n_PO_D_V))
986 n_err(_("*ssl-protocol* overrides *ssl-method*! "
987 "And please use *ssl-config-pairs* instead!\n"));
988 cp = cp_base;
990 if(cp != NULL && !a_xssl_conf(confp, "Protocol", cp))
991 goto jleave;
993 rv = TRU1;
994 jleave:
995 NYD2_LEAVE;
996 return rv;
999 static bool_t
1000 a_xssl_config_pairs(void *confp, struct url const *urlp){
1001 /* Due to interdependencies some commands have to be delayed a bit */
1002 static char const cmdcert[] = "Certificate", cmdprivkey[] = "PrivateKey";
1003 char const *valcert, *valprivkey;
1004 char *pairs, *cp, *cmd, *val;
1005 NYD2_ENTER;
1007 if((pairs = n_UNCONST(xok_vlook(ssl_config_pairs, urlp, OXM_ALL))) == NULL)
1008 goto jleave;
1009 pairs = savestr(pairs);
1011 valcert = valprivkey = NULL;
1013 while((cp = n_strsep_esc(&pairs, ',', FAL0)) != NULL){
1014 char c;
1015 enum{
1016 a_NONE,
1017 a_EXPAND = 1u<<0,
1018 a_CERT = 1u<<1,
1019 a_PRIVKEY = 1u<<2,
1020 a_EXPAND_MASK = a_EXPAND | a_CERT | a_PRIVKEY
1021 } f;
1023 /* Directive, space trimmed */
1024 if((cmd = strchr(cp, '=')) == NULL){
1025 jenocmd:
1026 if(pairs == NULL)
1027 pairs = n_UNCONST(n_empty);
1028 n_err(_("*ssl-config-pairs*: missing directive: %s; rest: %s\n"),
1029 n_shexp_quote_cp(cp, FAL0), n_shexp_quote_cp(pairs, FAL0));
1030 goto jleave;
1032 val = &cmd[1];
1034 if((cmd > cp && cmd[-1] == '*')){
1035 --cmd;
1036 f = a_EXPAND;
1037 }else
1038 f = a_NONE;
1039 while(cmd > cp && (c = cmd[-1], blankspacechar(c)))
1040 --cmd;
1041 if(cmd == cp)
1042 goto jenocmd;
1043 *cmd = '\0';
1044 cmd = cp;
1046 /* Command with special treatment? */
1047 if(!asccasecmp(cmd, cmdcert))
1048 f |= a_CERT;
1049 else if(!asccasecmp(cmd, cmdprivkey))
1050 f |= a_PRIVKEY;
1052 /* Value, space trimmed */
1053 while((c = *val) != '\0' && blankspacechar(c))
1054 ++val;
1055 cp = &val[strlen(val)];
1056 while(cp > val && (c = cp[-1], blankspacechar(c)))
1057 --cp;
1058 *cp = '\0';
1059 if(cp == val){
1060 if(pairs == NULL)
1061 pairs = n_UNCONST(n_empty);
1062 n_err(_("*ssl-config-pairs*: missing value: %s; rest: %s\n"),
1063 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(pairs, FAL0));
1064 goto jleave;
1067 /* Filename transformations to be applied? */
1068 if(f & a_EXPAND_MASK){
1069 if((cp = fexpand(val, FEXP_LOCAL | FEXP_NOPROTO)) == NULL){
1070 if(pairs == NULL)
1071 pairs = n_UNCONST(n_empty);
1072 n_err(_("*ssl-config-pairs*: value expansion failed: %s: %s; "
1073 "rest: %s\n"),
1074 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(val, FAL0),
1075 n_shexp_quote_cp(pairs, FAL0));
1076 goto jleave;
1078 val = cp;
1081 /* Some things have to be delayed */
1082 if(f & a_CERT)
1083 valcert = val;
1084 else if(f & a_PRIVKEY)
1085 valprivkey = val;
1086 else if(!a_xssl_conf(confp, cmd, val)){
1087 pairs = n_UNCONST(n_empty);
1088 goto jleave;
1092 /* Work the delayed ones */
1093 if((valcert != NULL && !a_xssl_conf(confp, cmdcert, valcert)) ||
1094 ((valprivkey != NULL || (valprivkey = valcert) != NULL) &&
1095 !a_xssl_conf(confp, cmdprivkey, valprivkey)))
1096 pairs = n_UNCONST(n_empty);
1098 jleave:
1099 NYD2_LEAVE;
1100 return (pairs == NULL);
1103 static bool_t
1104 a_xssl_load_verifications(SSL_CTX *ctxp, struct url const *urlp){
1105 char *ca_dir, *ca_file;
1106 X509_STORE *store;
1107 bool_t rv;
1108 NYD2_ENTER;
1110 if(ssl_verify_level == SSL_VERIFY_IGNORE){
1111 rv = TRU1;
1112 goto jleave;
1114 rv = FAL0;
1116 if((ca_dir = xok_vlook(ssl_ca_dir, urlp, OXM_ALL)) != NULL)
1117 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
1118 if((ca_file = xok_vlook(ssl_ca_file, urlp, OXM_ALL)) != NULL)
1119 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
1121 if((ca_dir != NULL || ca_file != NULL) &&
1122 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1){
1123 char const *m1, *m2, *m3;
1125 if(ca_dir != NULL){
1126 m1 = ca_dir;
1127 m2 = (ca_file != NULL) ? _(" or ") : n_empty;
1128 }else
1129 m1 = m2 = n_empty;
1130 m3 = (ca_file != NULL) ? ca_file : n_empty;
1131 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
1132 goto jleave;
1135 /* C99 */{
1136 bool_t xv15;
1138 if((xv15 = ok_blook(ssl_no_default_ca)))
1139 n_OBSOLETE(_("please use *ssl-ca-no-defaults*, "
1140 "not *ssl-no-default-ca*"));
1141 if(!xok_blook(ssl_ca_no_defaults, urlp, OXM_ALL) && !xv15 &&
1142 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
1143 ssl_gen_err(_("Error loading built-in default CA locations\n"));
1144 goto jleave;
1148 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
1149 a_xssl_msgno = 0;
1150 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
1151 store = SSL_CTX_get_cert_store(ctxp);
1152 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
1153 a_xssl_ca_flags(store, xok_vlook(ssl_ca_flags, urlp, OXM_ALL));
1155 rv = TRU1;
1156 jleave:
1157 NYD2_LEAVE;
1158 return rv;
1161 static enum okay
1162 ssl_check_host(struct sock *sp, struct url const *urlp)
1164 char data[256];
1165 X509 *cert;
1166 n_XSSL_STACKOF(GENERAL_NAME) *gens;
1167 GENERAL_NAME *gen;
1168 X509_NAME *subj;
1169 enum okay rv = STOP;
1170 NYD_ENTER;
1172 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
1173 n_err(_("No certificate from: %s\n"), urlp->url_h_p.s);
1174 goto jleave;
1177 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
1178 if (gens != NULL) {
1179 int i;
1181 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
1182 gen = sk_GENERAL_NAME_value(gens, i);
1183 if (gen->type == GEN_DNS) {
1184 if (n_poption & n_PO_D_V)
1185 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
1186 urlp->url_host.s, (char*)gen->d.ia5->data);
1187 rv = rfc2595_hostname_match(urlp->url_host.s,
1188 (char*)gen->d.ia5->data);
1189 if (rv == OKAY)
1190 goto jdone;
1195 if ((subj = X509_get_subject_name(cert)) != NULL &&
1196 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
1197 > 0) {
1198 data[sizeof data - 1] = '\0';
1199 if (n_poption & n_PO_D_V)
1200 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
1201 urlp->url_host.s, data);
1202 rv = rfc2595_hostname_match(urlp->url_host.s, data);
1205 jdone:
1206 X509_free(cert);
1207 jleave:
1208 NYD_LEAVE;
1209 return rv;
1212 static int
1213 smime_verify(struct message *m, int n, n_XSSL_STACKOF(X509) *chain,
1214 X509_STORE *store)
1216 char data[LINESIZE], *sender, *to, *cc, *cnttype;
1217 int rv, c, i, j;
1218 struct message *x;
1219 FILE *fp, *ip;
1220 off_t size;
1221 BIO *fb, *pb;
1222 PKCS7 *pkcs7;
1223 n_XSSL_STACKOF(X509) *certs;
1224 n_XSSL_STACKOF(GENERAL_NAME) *gens;
1225 X509 *cert;
1226 X509_NAME *subj;
1227 GENERAL_NAME *gen;
1228 NYD_ENTER;
1230 rv = 1;
1231 fp = NULL;
1232 fb = pb = NULL;
1233 pkcs7 = NULL;
1234 certs = NULL;
1235 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
1236 a_xssl_msgno = (size_t)n;
1238 for (;;) {
1239 sender = getsender(m);
1240 to = hfield1("to", m);
1241 cc = hfield1("cc", m);
1242 cnttype = hfield1("content-type", m);
1244 #undef _X
1245 #undef _Y
1246 #define _X (sizeof("application/") -1)
1247 #define _Y(X) X, sizeof(X) -1
1248 if (cnttype && is_asccaseprefix("application/", cnttype) &&
1249 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
1250 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
1251 #undef _Y
1252 #undef _X
1253 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1254 goto jleave;
1255 if (x != (struct message*)-1) {
1256 m = x;
1257 continue;
1261 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1262 goto jleave;
1263 size = m->m_size;
1264 break;
1267 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1268 NULL) {
1269 n_perr(_("tempfile"), 0);
1270 goto jleave;
1272 while (size-- > 0) {
1273 c = getc(ip);
1274 putc(c, fp);
1276 fflush_rewind(fp);
1278 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1279 ssl_gen_err(_(
1280 "Error creating BIO verification object for message %d"), n);
1281 goto jleave;
1284 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1285 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1286 goto jleave;
1288 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
1289 ssl_gen_err(_("Error verifying message %d"), n);
1290 goto jleave;
1293 if (sender == NULL) {
1294 n_err(_("Warning: Message %d has no sender\n"), n);
1295 rv = 0;
1296 goto jleave;
1299 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1300 if (certs == NULL) {
1301 n_err(_("No certificates found in message %d\n"), n);
1302 goto jleave;
1305 for (i = 0; i < sk_X509_num(certs); ++i) {
1306 cert = sk_X509_value(certs, i);
1307 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
1308 if (gens != NULL) {
1309 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
1310 gen = sk_GENERAL_NAME_value(gens, j);
1311 if (gen->type == GEN_EMAIL) {
1312 if (n_poption & n_PO_D_V)
1313 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
1314 sender, (char*)gen->d.ia5->data);
1315 if (!asccasecmp((char*)gen->d.ia5->data, sender))
1316 goto jfound;
1321 if ((subj = X509_get_subject_name(cert)) != NULL &&
1322 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
1323 data, sizeof data) > 0) {
1324 data[sizeof data -1] = '\0';
1325 if (n_poption & n_PO_D_V)
1326 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
1327 sender, data);
1328 if (!asccasecmp(data, sender))
1329 goto jfound;
1332 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
1333 goto jleave;
1334 jfound:
1335 rv = ((a_xssl_state & a_XSSL_S_VERIFY_ERROR) != 0);
1336 if (!rv)
1337 fprintf(n_stdout, _("Message %d was verified successfully\n"), n);
1338 jleave:
1339 if (certs != NULL)
1340 sk_X509_free(certs);
1341 if (pb != NULL)
1342 BIO_free(pb);
1343 if (fb != NULL)
1344 BIO_free(fb);
1345 if (pkcs7 != NULL)
1346 PKCS7_free(pkcs7);
1347 if (fp != NULL)
1348 Fclose(fp);
1349 NYD_LEAVE;
1350 return rv;
1353 static EVP_CIPHER const *
1354 _smime_cipher(char const *name)
1356 EVP_CIPHER const *cipher;
1357 char *vn;
1358 char const *cp;
1359 size_t i;
1360 NYD_ENTER;
1362 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
1363 snprintf(vn, (int)i, "smime-cipher-%s", name);
1364 cp = n_var_vlook(vn, FAL0);
1365 ac_free(vn);
1367 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
1368 cipher = a_XSSL_SMIME_DEFAULT_CIPHER();
1369 goto jleave;
1371 cipher = NULL;
1373 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers); ++i)
1374 if (!asccasecmp(a_xssl_smime_ciphers[i].sc_name, cp)) {
1375 cipher = (*a_xssl_smime_ciphers[i].sc_fun)();
1376 goto jleave;
1378 #ifndef OPENSSL_NO_AES
1379 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers_obs); ++i) /* TODO obsolete */
1380 if (!asccasecmp(a_xssl_smime_ciphers_obs[i].sc_name, cp)) {
1381 n_OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
1382 cipher = (*a_xssl_smime_ciphers_obs[i].sc_fun)();
1383 goto jleave;
1385 #endif
1387 /* Not a built-in algorithm, but we may have dynamic support for more */
1388 #ifdef HAVE_SSL_ALL_ALGORITHMS
1389 if((cipher = EVP_get_cipherbyname(cp)) != NULL)
1390 goto jleave;
1391 #endif
1393 n_err(_("Invalid S/MIME cipher(s): %s\n"), cp);
1394 jleave:
1395 NYD_LEAVE;
1396 return cipher;
1399 static int
1400 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
1402 char *pass;
1403 size_t len;
1404 NYD_ENTER;
1405 n_UNUSED(rwflag);
1406 n_UNUSED(userdata);
1408 /* New-style */
1409 if(userdata != NULL){
1410 struct url url;
1411 struct ccred cred;
1413 if(url_parse(&url, CPROTO_CCRED, userdata)){
1414 if(ccred_lookup(&cred, &url)){
1415 ssize_t slen;
1417 if((slen = n_strscpy(buf, cred.cc_pass.s, size)) >= 0){
1418 size = (int)slen;
1419 goto jleave;
1422 size = 0;
1423 goto jleave;
1427 /* Old-style */
1428 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
1429 len = strlen(pass);
1430 if (UICMP(z, len, >=, size))
1431 len = size -1;
1432 memcpy(buf, pass, len);
1433 buf[len] = '\0';
1434 size = (int)len;
1435 } else
1436 size = 0;
1437 jleave:
1438 NYD_LEAVE;
1439 return size;
1442 static FILE *
1443 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn,
1444 char const **match)
1446 char *vn;
1447 int vs;
1448 struct name *np;
1449 char const *name = xname, *name2 = xname2, *cp;
1450 FILE *fp = NULL;
1451 NYD_ENTER;
1453 jloop:
1454 if (name) {
1455 np = lextract(name, GTO | GSKIN);
1456 while (np != NULL) {
1457 /* This needs to be more intelligent since it will currently take the
1458 * first name for which a private key is available regardless of
1459 * whether it is the right one for the message */
1460 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1461 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
1462 cp = n_var_vlook(vn, FAL0);
1463 ac_free(vn);
1464 if (cp != NULL) {
1465 if (match != NULL)
1466 *match = np->n_name;
1467 goto jopen;
1469 np = np->n_flink;
1471 if (name2 != NULL) {
1472 name = name2;
1473 name2 = NULL;
1474 goto jloop;
1478 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
1479 goto jerr;
1480 if(match != NULL)
1481 *match = NULL;
1482 jopen:
1483 if ((cp = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
1484 goto jleave;
1485 if ((fp = Fopen(cp, "r")) == NULL)
1486 n_perr(cp, 0);
1487 jleave:
1488 NYD_LEAVE;
1489 return fp;
1490 jerr:
1491 if (dowarn)
1492 n_err(_("Could not find a certificate for %s%s%s\n"),
1493 xname, (xname2 != NULL ? _("or ") : n_empty),
1494 (xname2 != NULL ? xname2 : n_empty));
1495 goto jleave;
1498 static char const *
1499 _smime_sign_include_certs(char const *name)
1501 char const *rv;
1502 NYD_ENTER;
1504 /* See comments in smime_sign_cert() for algorithm pitfalls */
1505 if (name != NULL) {
1506 struct name *np;
1508 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1509 int vs;
1510 char *vn;
1512 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1513 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1514 rv = n_var_vlook(vn, FAL0);
1515 ac_free(vn);
1516 if (rv != NULL)
1517 goto jleave;
1520 rv = ok_vlook(smime_sign_include_certs);
1521 jleave:
1522 NYD_LEAVE;
1523 return rv;
1526 static bool_t
1527 _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
1528 char const *cfiles, char const *addr)
1530 X509 *tmp;
1531 FILE *fp;
1532 char *nfield, *cfield, *x;
1533 NYD_ENTER;
1535 *chain = sk_X509_new_null();
1537 for (nfield = savestr(cfiles);
1538 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1539 if ((x = fexpand(cfield, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1540 (fp = Fopen(cfield = x, "r")) == NULL) {
1541 n_perr(cfiles, 0);
1542 goto jerr;
1544 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, n_UNCONST(addr))
1545 ) == NULL) {
1546 ssl_gen_err(_("Error reading certificate from %s"),
1547 n_shexp_quote_cp(cfield, FAL0));
1548 Fclose(fp);
1549 goto jerr;
1551 sk_X509_push(*chain, tmp);
1552 Fclose(fp);
1555 if (sk_X509_num(*chain) == 0) {
1556 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1557 goto jerr;
1559 jleave:
1560 NYD_LEAVE;
1561 return (*chain != NULL);
1562 jerr:
1563 sk_X509_pop_free(*chain, X509_free);
1564 *chain = NULL;
1565 goto jleave;
1568 static EVP_MD const *
1569 _smime_sign_digest(char const *name, char const **digname)
1571 EVP_MD const *digest;
1572 char const *cp;
1573 size_t i;
1574 NYD_ENTER;
1576 /* See comments in smime_sign_cert() for algorithm pitfalls */
1577 if (name != NULL) {
1578 struct name *np;
1580 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1581 int vs;
1582 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1583 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1584 cp = n_var_vlook(vn, FAL0);
1585 ac_free(vn);
1586 if (cp != NULL)
1587 goto jhave_name;
1591 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1592 digest = a_XSSL_SMIME_DEFAULT_DIGEST();
1593 *digname = a_XSSL_SMIME_DEFAULT_DIGEST_S;
1594 goto jleave;
1597 jhave_name:
1598 i = strlen(cp);
1599 { char *x = salloc(i +1);
1600 i_strcpy(x, cp, i +1);
1601 cp = x;
1603 *digname = cp;
1605 for (i = 0; i < n_NELEM(a_xssl_smime_digests); ++i)
1606 if (!asccasecmp(a_xssl_smime_digests[i].sd_name, cp)) {
1607 digest = (*a_xssl_smime_digests[i].sd_fun)();
1608 goto jleave;
1611 /* Not a built-in algorithm, but we may have dynamic support for more */
1612 #ifdef HAVE_SSL_ALL_ALGORITHMS
1613 if((digest = EVP_get_digestbyname(cp)) != NULL)
1614 goto jleave;
1615 #endif
1617 n_err(_("Invalid message digest: %s\n"), cp);
1618 digest = NULL;
1619 jleave:
1620 NYD_LEAVE;
1621 return digest;
1624 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1625 static enum okay
1626 load_crl1(X509_STORE *store, char const *name)
1628 X509_LOOKUP *lookup;
1629 enum okay rv = STOP;
1630 NYD_ENTER;
1632 if (n_poption & n_PO_D_V)
1633 n_err(_("Loading CRL from %s\n"), n_shexp_quote_cp(name, FAL0));
1634 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1635 ssl_gen_err(_("Error creating X509 lookup object"));
1636 goto jleave;
1638 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1639 ssl_gen_err(_("Error loading CRL from %s"), n_shexp_quote_cp(name, FAL0));
1640 goto jleave;
1642 rv = OKAY;
1643 jleave:
1644 NYD_LEAVE;
1645 return rv;
1647 #endif /* new OpenSSL */
1649 static enum okay
1650 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1652 char *crl_file, *crl_dir;
1653 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1654 DIR *dirp;
1655 struct dirent *dp;
1656 char *fn = NULL;
1657 int fs = 0, ds, es;
1658 #endif
1659 enum okay rv = STOP;
1660 NYD_ENTER;
1662 if ((crl_file = n_var_oklook(fok)) != NULL) {
1663 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1664 if ((crl_file = fexpand(crl_file, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1665 load_crl1(store, crl_file) != OKAY)
1666 goto jleave;
1667 #else
1668 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1669 goto jleave;
1670 #endif
1673 if ((crl_dir = n_var_oklook(dok)) != NULL) {
1674 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1675 char *x;
1676 if ((x = fexpand(crl_dir, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1677 (dirp = opendir(crl_dir = x)) == NULL) {
1678 n_perr(crl_dir, 0);
1679 goto jleave;
1682 ds = strlen(crl_dir);
1683 fn = smalloc(fs = ds + 20);
1684 memcpy(fn, crl_dir, ds);
1685 fn[ds] = '/';
1686 while ((dp = readdir(dirp)) != NULL) {
1687 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1688 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1689 continue;
1690 if (dp->d_name[0] == '.')
1691 continue;
1692 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1693 fn = srealloc(fn, fs = ds + es + 20);
1694 memcpy(fn + ds + 1, dp->d_name, es + 1);
1695 if (load_crl1(store, fn) != OKAY) {
1696 closedir(dirp);
1697 free(fn);
1698 goto jleave;
1701 closedir(dirp);
1702 free(fn);
1703 #else /* old OpenSSL */
1704 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1705 goto jleave;
1706 #endif
1708 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1709 if (crl_file || crl_dir)
1710 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1711 X509_V_FLAG_CRL_CHECK_ALL);
1712 #endif
1713 rv = OKAY;
1714 jleave:
1715 NYD_LEAVE;
1716 return rv;
1719 #if HAVE_RANDOM == n_RANDOM_IMPL_SSL
1720 FL void
1721 ssl_rand_bytes(void *buf, size_t blen){
1722 NYD_ENTER;
1724 if(!(a_xssl_state & a_XSSL_S_RAND_INIT))
1725 a_xssl_rand_init();
1727 while(blen > 0){
1728 si32_t i;
1730 i = n_MIN(SI32_MAX, blen);
1731 blen -= i;
1732 RAND_bytes(buf, i);
1733 buf = (ui8_t*)buf + i;
1735 NYD_LEAVE;
1737 #endif
1739 FL enum okay
1740 ssl_open(struct url const *urlp, struct sock *sp){
1741 void *confp;
1742 SSL_CTX *ctxp;
1743 enum okay rv;
1744 NYD_ENTER;
1746 a_xssl_init();
1748 rv = STOP;
1749 ssl_set_verify_level(urlp);
1751 if((ctxp = SSL_CTX_new(n_XSSL_CLIENT_METHOD())) == NULL){
1752 ssl_gen_err(_("SSL_CTX_new() failed"));
1753 goto jleave;
1756 /* Available with OpenSSL 0.9.6 or later */
1757 #ifdef SSL_MODE_AUTO_RETRY
1758 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1759 #endif
1761 if((confp = a_xssl_conf_setup(ctxp, urlp)) == NULL)
1762 goto jerr0;
1764 if(!a_xssl_obsolete_conf_vars(confp, urlp))
1765 goto jerr1;
1766 if(!a_xssl_config_pairs(confp, urlp))
1767 goto jerr1;
1768 if(!a_xssl_load_verifications(ctxp, urlp))
1769 goto jerr1;
1771 /* Done with context setup, create our new per-connection structure */
1772 if(!a_xssl_conf_finish(&confp, FAL0))
1773 goto jerr0;
1775 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1776 ssl_gen_err(_("SSL_new() failed"));
1777 goto jerr0;
1780 /* Try establish SNI extension; even though this is a TLS extension the
1781 * protocol isn't checked once the host name is set, and therefore i've
1782 * refrained from changing so much code just to check out whether we are
1783 * using SSLv3, which should become more and more rare */
1784 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1785 if((urlp->url_flags & n_URL_TLS_MASK) &&
1786 (urlp->url_flags & n_URL_HOST_IS_NAME)){
1787 if(!SSL_set_tlsext_host_name(sp->s_ssl, urlp->url_host.s) &&
1788 (n_poption & n_PO_D_V))
1789 n_err(_("Hostname cannot be used with ServerNameIndication "
1790 "TLS extension: %s\n"),
1791 n_shexp_quote_cp(urlp->url_host.s, FAL0));
1793 #endif
1795 SSL_set_fd(sp->s_ssl, sp->s_fd);
1797 if (SSL_connect(sp->s_ssl) < 0) {
1798 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1799 goto jerr2;
1802 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1803 if (ssl_check_host(sp, urlp) != OKAY) {
1804 n_err(_("Host certificate does not match: %s\n"), urlp->url_h_p.s);
1805 if (ssl_verify_decide() != OKAY)
1806 goto jerr2;
1810 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1811 * and free it right now -- it is reference counted by sp->s_ssl.. */
1812 SSL_CTX_free(ctxp);
1813 sp->s_use_ssl = 1;
1814 rv = OKAY;
1815 jleave:
1816 NYD_LEAVE;
1817 return rv;
1818 jerr2:
1819 SSL_free(sp->s_ssl);
1820 sp->s_ssl = NULL;
1821 jerr1:
1822 if (confp != NULL)
1823 a_xssl_conf_finish(&confp, TRU1);
1824 jerr0:
1825 SSL_CTX_free(ctxp);
1826 goto jleave;
1829 FL void
1830 ssl_gen_err(char const *fmt, ...)
1832 va_list ap;
1833 NYD_ENTER;
1835 va_start(ap, fmt);
1836 n_verr(fmt, ap);
1837 va_end(ap);
1839 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1840 NYD_LEAVE;
1843 FL int
1844 c_verify(void *vp)
1846 int *msgvec = vp, *ip, ec = 0, rv = 1;
1847 X509_STORE *store = NULL;
1848 char *ca_dir, *ca_file;
1849 NYD_ENTER;
1851 a_xssl_init();
1853 ssl_verify_level = SSL_VERIFY_STRICT;
1854 if ((store = X509_STORE_new()) == NULL) {
1855 ssl_gen_err(_("Error creating X509 store"));
1856 goto jleave;
1858 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1860 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1861 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
1862 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1863 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
1865 if((ca_dir != NULL || ca_file != NULL) &&
1866 X509_STORE_load_locations(store, ca_file, ca_dir) != 1){
1867 char const *m1, *m2, *m3;
1869 if(ca_dir != NULL){
1870 m1 = ca_dir;
1871 m2 = (ca_file != NULL) ? _(" or ") : n_empty;
1872 }else
1873 m1 = m2 = n_empty;
1874 m3 = (ca_file != NULL) ? ca_file : n_empty;
1875 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
1876 goto jleave;
1879 /* C99 */{
1880 bool_t xv15;
1882 if((xv15 = ok_blook(smime_no_default_ca)))
1883 n_OBSOLETE(_("please use *smime-ca-no-defaults*, "
1884 "not *smime-no-default-ca*"));
1885 if(!ok_blook(smime_ca_no_defaults) && !xv15 &&
1886 X509_STORE_set_default_paths(store) != 1) {
1887 ssl_gen_err(_("Error loading built-in default CA locations\n"));
1888 goto jleave;
1892 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1893 goto jleave;
1895 a_xssl_ca_flags(store, ok_vlook(smime_ca_flags));
1897 srelax_hold();
1898 for (ip = msgvec; *ip != 0; ++ip) {
1899 struct message *mp = message + *ip - 1;
1900 setdot(mp);
1901 ec |= smime_verify(mp, *ip, NULL, store);
1902 srelax();
1904 srelax_rele();
1906 if ((rv = ec) != 0)
1907 n_exit_status |= n_EXIT_ERR;
1908 jleave:
1909 if (store != NULL)
1910 X509_STORE_free(store);
1911 NYD_LEAVE;
1912 return rv;
1915 FL FILE *
1916 smime_sign(FILE *ip, char const *addr)
1918 FILE *rv, *sp, *fp, *bp, *hp;
1919 X509 *cert = NULL;
1920 n_XSSL_STACKOF(X509) *chain = NULL;
1921 EVP_PKEY *pkey = NULL;
1922 BIO *bb, *sb;
1923 PKCS7 *pkcs7;
1924 EVP_MD const *md;
1925 char const *name;
1926 bool_t bail = FAL0;
1927 NYD_ENTER;
1929 assert(addr != NULL);
1930 rv = sp = fp = bp = hp = NULL;
1932 a_xssl_init();
1934 if (addr == NULL) {
1935 n_err(_("No *from* address for signing specified\n"));
1936 goto jleave;
1938 if ((fp = smime_sign_cert(addr, NULL, 1, NULL)) == NULL)
1939 goto jleave;
1941 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb,
1942 savecat(addr, ".smime-cert-key"))) == NULL) {
1943 ssl_gen_err(_("Error reading private key from"));
1944 goto jleave;
1947 rewind(fp);
1948 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb,
1949 savecat(addr, ".smime-cert-cert"))) == NULL) {
1950 ssl_gen_err(_("Error reading signer certificate from"));
1951 goto jleave;
1953 Fclose(fp);
1954 fp = NULL;
1956 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1957 !_smime_sign_include_chain_creat(&chain, name,
1958 savecat(addr, ".smime-include-certs")))
1959 goto jleave;
1961 name = NULL;
1962 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1963 goto jleave;
1965 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1966 NULL) {
1967 n_perr(_("tempfile"), 0);
1968 goto jleave;
1971 rewind(ip);
1972 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1973 goto jleave;
1975 sb = NULL;
1976 pkcs7 = NULL;
1978 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1979 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1980 ssl_gen_err(_("Error creating BIO signing objects"));
1981 bail = TRU1;
1982 goto jerr;
1985 #undef _X
1986 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1987 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1988 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1989 bail = TRU1;
1990 goto jerr;
1992 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1993 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1994 bail = TRU1;
1995 goto jerr;
1997 if (!PKCS7_final(pkcs7, bb, _X)) {
1998 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1999 bail = TRU1;
2000 goto jerr;
2002 #undef _X
2004 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
2005 ssl_gen_err(_("Error writing signed S/MIME data"));
2006 bail = TRU1;
2007 /*goto jerr*/
2009 jerr:
2010 if (pkcs7 != NULL)
2011 PKCS7_free(pkcs7);
2012 if (sb != NULL)
2013 BIO_free(sb);
2014 if (bb != NULL)
2015 BIO_free(bb);
2016 if (!bail) {
2017 rewind(bp);
2018 fflush_rewind(sp);
2019 rv = smime_sign_assemble(hp, bp, sp, name);
2020 hp = bp = sp = NULL;
2023 jleave:
2024 if (chain != NULL)
2025 sk_X509_pop_free(chain, X509_free);
2026 if (cert != NULL)
2027 X509_free(cert);
2028 if (pkey != NULL)
2029 EVP_PKEY_free(pkey);
2030 if (fp != NULL)
2031 Fclose(fp);
2032 if (hp != NULL)
2033 Fclose(hp);
2034 if (bp != NULL)
2035 Fclose(bp);
2036 if (sp != NULL)
2037 Fclose(sp);
2038 NYD_LEAVE;
2039 return rv;
2042 FL FILE *
2043 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
2045 FILE *rv, *yp, *fp, *bp, *hp;
2046 X509 *cert;
2047 PKCS7 *pkcs7;
2048 BIO *bb, *yb;
2049 n_XSSL_STACKOF(X509) *certs;
2050 EVP_CIPHER const *cipher;
2051 char *certfile;
2052 bool_t bail;
2053 NYD_ENTER;
2055 bail = FAL0;
2056 rv = yp = fp = bp = hp = NULL;
2058 if ((certfile = fexpand(xcertfile, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
2059 goto jleave;
2061 a_xssl_init();
2063 if ((cipher = _smime_cipher(to)) == NULL)
2064 goto jleave;
2066 if ((fp = Fopen(certfile, "r")) == NULL) {
2067 n_perr(certfile, 0);
2068 goto jleave;
2070 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
2071 ssl_gen_err(_("Error reading encryption certificate from %s"),
2072 n_shexp_quote_cp(certfile, FAL0));
2073 bail = TRU1;
2075 if (bail)
2076 goto jleave;
2077 Fclose(fp);
2078 fp = NULL;
2079 bail = FAL0;
2081 certs = sk_X509_new_null();
2082 sk_X509_push(certs, cert);
2084 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
2085 NULL) {
2086 n_perr(_("tempfile"), 0);
2087 goto jerr1;
2090 rewind(ip);
2091 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
2092 goto jerr1;
2094 yb = NULL;
2095 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
2096 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
2097 ssl_gen_err(_("Error creating BIO encryption objects"));
2098 bail = TRU1;
2099 goto jerr2;
2101 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
2102 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
2103 bail = TRU1;
2104 goto jerr2;
2106 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
2107 ssl_gen_err(_("Error writing encrypted S/MIME data"));
2108 bail = TRU1;
2109 /* goto jerr2 */
2111 PKCS7_free(pkcs7);
2113 jerr2:
2114 if (bb != NULL)
2115 BIO_free(bb);
2116 if (yb != NULL)
2117 BIO_free(yb);
2118 Fclose(bp);
2119 bp = NULL;
2120 if (!bail) {
2121 fflush_rewind(yp);
2122 rv = smime_encrypt_assemble(hp, yp);
2123 hp = yp = NULL;
2125 jerr1:
2126 sk_X509_pop_free(certs, X509_free);
2127 jleave:
2128 if(yp != NULL)
2129 Fclose(yp);
2130 if(fp != NULL)
2131 Fclose(fp);
2132 if(bp != NULL)
2133 Fclose(bp);
2134 if(hp != NULL)
2135 Fclose(hp);
2136 NYD_LEAVE;
2137 return rv;
2140 FL struct message *
2141 smime_decrypt(struct message *m, char const *to, char const *cc,
2142 bool_t signcall)
2144 char const *myaddr;
2145 long size;
2146 struct message *rv;
2147 FILE *bp, *hp, *op;
2148 PKCS7 *pkcs7;
2149 BIO *ob, *bb, *pb;
2150 X509 *cert;
2151 EVP_PKEY *pkey;
2152 FILE *yp;
2153 NYD_ENTER;
2155 pkey = NULL;
2156 cert = NULL;
2157 ob = bb = pb = NULL;
2158 pkcs7 = NULL;
2159 bp = hp = op = NULL;
2160 rv = NULL;
2161 size = m->m_size;
2163 if((yp = setinput(&mb, m, NEED_BODY)) == NULL)
2164 goto jleave;
2166 a_xssl_init();
2168 if((op = smime_sign_cert(to, cc, 0, &myaddr)) != NULL){
2169 pkey = PEM_read_PrivateKey(op, NULL, &ssl_password_cb,
2170 savecat(myaddr, ".smime-cert-key"));
2171 if(pkey == NULL){
2172 ssl_gen_err(_("Error reading private key"));
2173 goto jleave;
2176 rewind(op);
2177 if((cert = PEM_read_X509(op, NULL, &ssl_password_cb,
2178 savecat(myaddr, ".smime-cert-cert"))) == NULL){
2179 ssl_gen_err(_("Error reading decryption certificate"));
2180 goto jleave;
2183 Fclose(op);
2184 op = NULL;
2187 if((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
2188 n_perr(_("tempfile"), 0);
2189 goto jleave;
2192 if(smime_split(yp, &hp, &bp, size, 1) == STOP)
2193 goto jleave;
2195 if((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
2196 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL){
2197 ssl_gen_err(_("Error creating BIO decryption objects"));
2198 goto jleave;
2201 if((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL){
2202 ssl_gen_err(_("Error reading PKCS#7 object"));
2203 goto jleave;
2206 if(PKCS7_type_is_signed(pkcs7)){
2207 if(signcall){
2208 setinput(&mb, m, NEED_BODY);
2209 rv = (struct message*)-1;
2210 goto jleave;
2212 if(PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
2213 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
2214 goto jerr;
2215 fseek(hp, 0L, SEEK_END);
2216 fprintf(hp, "X-Encryption-Cipher: none\n");
2217 fflush_rewind(hp);
2218 }else if(pkey == NULL){
2219 n_err(_("No appropriate private key found\n"));
2220 goto jleave;
2221 }else if(cert == NULL){
2222 n_err(_("No appropriate certificate found\n"));
2223 goto jleave;
2224 }else if(PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1){
2225 jerr:
2226 ssl_gen_err(_("Error decrypting PKCS#7 object"));
2227 goto jleave;
2229 fflush_rewind(op);
2230 Fclose(bp);
2231 bp = NULL;
2233 rv = smime_decrypt_assemble(m, hp, op);
2234 hp = op = NULL; /* xxx closed by decrypt_assemble */
2235 jleave:
2236 if(op != NULL)
2237 Fclose(op);
2238 if(hp != NULL)
2239 Fclose(hp);
2240 if(bp != NULL)
2241 Fclose(bp);
2242 if(bb != NULL)
2243 BIO_free(bb);
2244 if(ob != NULL)
2245 BIO_free(ob);
2246 if(pkcs7 != NULL)
2247 PKCS7_free(pkcs7);
2248 if(cert != NULL)
2249 X509_free(cert);
2250 if(pkey != NULL)
2251 EVP_PKEY_free(pkey);
2252 NYD_LEAVE;
2253 return rv;
2256 FL enum okay
2257 smime_certsave(struct message *m, int n, FILE *op)
2259 struct message *x;
2260 char *to, *cc, *cnttype;
2261 int c, i;
2262 FILE *fp, *ip;
2263 off_t size;
2264 BIO *fb, *pb;
2265 PKCS7 *pkcs7;
2266 n_XSSL_STACKOF(X509) *certs, *chain = NULL;
2267 X509 *cert;
2268 enum okay rv = STOP;
2269 NYD_ENTER;
2271 pkcs7 = NULL;
2273 a_xssl_msgno = (size_t)n;
2274 jloop:
2275 to = hfield1("to", m);
2276 cc = hfield1("cc", m);
2277 cnttype = hfield1("content-type", m);
2279 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
2280 goto jleave;
2282 #undef _X
2283 #undef _Y
2284 #define _X (sizeof("application/") -1)
2285 #define _Y(X) X, sizeof(X) -1
2286 if (cnttype && is_asccaseprefix("application/", cnttype) &&
2287 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
2288 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
2289 #undef _Y
2290 #undef _X
2291 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
2292 goto jleave;
2293 if (x != (struct message*)-1) {
2294 m = x;
2295 goto jloop;
2298 size = m->m_size;
2300 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
2301 NULL) {
2302 n_perr(_("tempfile"), 0);
2303 goto jleave;
2306 while (size-- > 0) {
2307 c = getc(ip);
2308 putc(c, fp);
2310 fflush(fp);
2312 rewind(fp);
2313 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
2314 ssl_gen_err("Error creating BIO object for message %d", n);
2315 Fclose(fp);
2316 goto jleave;
2319 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
2320 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
2321 BIO_free(fb);
2322 Fclose(fp);
2323 goto jleave;
2325 BIO_free(fb);
2326 Fclose(fp);
2328 certs = PKCS7_get0_signers(pkcs7, chain, 0);
2329 if (certs == NULL) {
2330 n_err(_("No certificates found in message %d\n"), n);
2331 goto jleave;
2334 for (i = 0; i < sk_X509_num(certs); ++i) {
2335 cert = sk_X509_value(certs, i);
2336 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
2337 ssl_gen_err(_("Error writing certificate %d from message %d"),
2338 i, n);
2339 goto jleave;
2342 rv = OKAY;
2343 jleave:
2344 if(pkcs7 != NULL)
2345 PKCS7_free(pkcs7);
2346 NYD_LEAVE;
2347 return rv;
2349 #endif /* HAVE_XSSL */
2351 /* s-it-mode */