quoteflt_dummy() usage: FIX usage without preceeding _reset() (Jürgen Bruckner)
[s-mailx.git] / xssl.c
blobb8f51f02bdc3dcca9ed33344191a90f60870a6f5
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 /* SSL_CONF_CTX and _OP_NO_SSL_MASK were both introduced with 1.0.2!?! */
88 # ifndef SSL_OP_NO_SSL_MASK
89 # define SSL_OP_NO_SSL_MASK \
90 (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |\
91 SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2)
92 # endif
94 # ifndef SSL2_VERSION
95 # define SSL2_VERSION 0
96 # endif
97 # ifndef SSL3_VERSION
98 # define SSL3_VERSION 0
99 # endif
100 # ifndef TLS1_VERSION
101 # define TLS1_VERSION 0
102 # endif
103 # ifndef TLS1_1_VERSION
104 # define TLS1_1_VERSION 0
105 # endif
106 # ifndef TLS1_2_VERSION
107 # define TLS1_2_VERSION 0
108 # endif
109 #endif
111 #ifdef HAVE_XSSL_STACK_OF
112 # define n_XSSL_STACKOF(X) STACK_OF(X)
113 #else
114 # define n_XSSL_STACKOF(X) /*X*/STACK
115 #endif
117 #if OPENSSL_VERSION_NUMBER + 0 >= 0x0090581fL
118 # define a_XSSL_RAND_LOAD_FILE_MAXBYTES -1
119 #else
120 # define a_XSSL_RAND_LOAD_FILE_MAXBYTES 1024
121 #endif
123 /* Compatibility sighs (that sigh is _really_ a cute one) */
124 #if HAVE_XSSL_OPENSSL >= 0x10100
125 # define a_xssl_X509_get_notBefore X509_get0_notBefore
126 # define a_xssl_X509_get_notAfter X509_get0_notAfter
127 #else
128 # define a_xssl_X509_get_notBefore X509_get_notBefore
129 # define a_xssl_X509_get_notAfter X509_get_notAfter
130 #endif
132 /* X509_STORE_set_flags */
133 #undef a_XSSL_X509_V_ANY
134 #ifndef X509_V_FLAG_NO_ALT_CHAINS
135 # define X509_V_FLAG_NO_ALT_CHAINS -1
136 #else
137 # undef a_XSSL_X509_V_ANY
138 # define a_XSSL_X509_V_ANY
139 #endif
140 #ifndef X509_V_FLAG_NO_CHECK_TIME
141 # define X509_V_FLAG_NO_CHECK_TIME -1
142 #else
143 # undef a_XSSL_X509_V_ANY
144 # define a_XSSL_X509_V_ANY
145 #endif
146 #ifndef X509_V_FLAG_PARTIAL_CHAIN
147 # define X509_V_FLAG_PARTIAL_CHAIN -1
148 #else
149 # undef a_XSSL_X509_V_ANY
150 # define a_XSSL_X509_V_ANY
151 #endif
152 #ifndef X509_V_FLAG_X509_STRICT
153 # define X509_V_FLAG_X509_STRICT -1
154 #else
155 # undef a_XSSL_X509_V_ANY
156 # define a_XSSL_X509_V_ANY
157 #endif
158 #ifndef X509_V_FLAG_TRUSTED_FIRST
159 # define X509_V_FLAG_TRUSTED_FIRST -1
160 #else
161 # undef a_XSSL_X509_V_ANY
162 # define a_XSSL_X509_V_ANY
163 #endif
165 enum a_xssl_state{
166 a_XSSL_S_INIT = 1u<<0,
167 a_XSSL_S_RAND_INIT = 1u<<1,
168 a_XSSL_S_CONF_LOAD = 1u<<2,
170 #if HAVE_XSSL_OPENSSL < 0x10100
171 a_XSSL_S_EXIT_HDL = 1u<<8,
172 a_XSSL_S_ALGO_LOAD = 1u<<9,
173 #endif
175 a_XSSL_S_VERIFY_ERROR = 1u<<16
178 struct ssl_method { /* TODO v15 obsolete */
179 char const sm_name[8];
180 char const sm_map[16];
183 #ifndef HAVE_XSSL_CONF_CTX
184 struct a_xssl_protocol{
185 char const sp_name[8];
186 sl_i sp_op_no; /* SSL_OP_NO_* bit */
187 ui16_t sp_version; /* *_VERSION number */
188 bool_t sp_ok_minmaxproto; /* Valid for {Min,Max}Protocol= */
189 bool_t sp_ok_proto; /* Valid for Protocol= */
190 ui8_t sp__dummy[4];
192 #endif
194 struct a_xssl_smime_cipher{
195 char const sc_name[8];
196 EVP_CIPHER const *(*sc_fun)(void);
199 struct a_xssl_smime_digest{
200 char const sd_name[8];
201 EVP_MD const *(*sd_fun)(void);
204 struct a_xssl_x509_v_flags{
205 char const xvf_name[20];
206 si32_t xvf_flag;
209 /* Supported SSL/TLS methods: update manual on change! */
210 static struct ssl_method const _ssl_methods[] = { /* TODO obsolete */
211 {"auto", "ALL,-SSLv2"},
212 {"ssl3", "-ALL,SSLv3"},
213 {"tls1", "-ALL,TLSv1"},
214 {"tls1.1", "-ALL,TLSv1.1"},
215 {"tls1.2", "-ALL,TLSv1.2"}
218 /* Update manual on change!
219 * Ensure array size by adding \0 to longest entry.
220 * Strictly to be sorted new/up to old/down, [0]=ALL, [x-1]=None! */
221 #ifndef HAVE_XSSL_CONF_CTX
222 static struct a_xssl_protocol const a_xssl_protocols[] = {
223 {"ALL", SSL_OP_NO_SSL_MASK, 0, FAL0, TRU1, {0}},
224 {"TLSv1.2\0", SSL_OP_NO_TLSv1_2, TLS1_2_VERSION, TRU1, TRU1, {0}},
225 {"TLSv1.1", SSL_OP_NO_TLSv1_1, TLS1_1_VERSION, TRU1, TRU1, {0}},
226 {"TLSv1", SSL_OP_NO_TLSv1, TLS1_VERSION, TRU1, TRU1, {0}},
227 {"SSLv3", SSL_OP_NO_SSLv3, SSL3_VERSION, TRU1, TRU1, {0}},
228 {"SSLv2", SSL_OP_NO_SSLv2, SSL2_VERSION, TRU1, TRU1, {0}},
229 {"None", SSL_OP_NO_SSL_MASK, 0, TRU1, FAL0, {0}}
231 #endif /* HAVE_XSSL_CONF_CTX */
233 /* Supported S/MIME cipher algorithms */
234 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers[] = { /* Manual! */
235 #ifndef OPENSSL_NO_AES
236 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_aes_128_cbc /* According to RFC 5751 */
237 {"aes128", &EVP_aes_128_cbc},
238 {"aes256", &EVP_aes_256_cbc},
239 {"aes192", &EVP_aes_192_cbc},
240 #endif
241 #ifndef OPENSSL_NO_DES
242 # ifndef a_XSSL_SMIME_DEFAULT_CIPHER
243 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_des_ede3_cbc
244 # endif
245 {"des3", &EVP_des_ede3_cbc},
246 {"des", &EVP_des_cbc},
247 #endif
249 #ifndef a_XSSL_SMIME_DEFAULT_CIPHER
250 # error Your OpenSSL library does not include the necessary
251 # error cipher algorithms that are required to support S/MIME
252 #endif
254 #ifndef OPENSSL_NO_AES
255 /* TODO obsolete a_xssl_smime_ciphers_obs */
256 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers_obs[] = {
257 {"aes-128", &EVP_aes_128_cbc},
258 {"aes-256", &EVP_aes_256_cbc},
259 {"aes-192", &EVP_aes_192_cbc}
261 #endif
263 /* Supported S/MIME message digest algorithms */
264 static struct a_xssl_smime_digest const a_xssl_smime_digests[] = { /* Manual! */
265 #define a_XSSL_SMIME_DEFAULT_DIGEST EVP_sha1 /* According to RFC 5751 */
266 #define a_XSSL_SMIME_DEFAULT_DIGEST_S "sha1"
267 {"sha1", &EVP_sha1},
268 {"sha256", &EVP_sha256},
269 {"sha512", &EVP_sha512},
270 {"sha384", &EVP_sha384},
271 {"sha224", &EVP_sha224},
272 #ifndef OPENSSL_NO_MD5
273 {"md5", &EVP_md5},
274 #endif
277 /* X509_STORE_set_flags() for *{smime,ssl}-ca-flags* */
278 static struct a_xssl_x509_v_flags const a_xssl_x509_v_flags[] = { /* Manual! */
279 {"no-alt-chains", X509_V_FLAG_NO_ALT_CHAINS},
280 {"no-check-time", X509_V_FLAG_NO_CHECK_TIME},
281 {"partial-chain", X509_V_FLAG_PARTIAL_CHAIN},
282 {"strict", X509_V_FLAG_X509_STRICT},
283 {"trusted-first", X509_V_FLAG_TRUSTED_FIRST},
286 static enum a_xssl_state a_xssl_state;
287 static size_t a_xssl_msgno;
289 static void a_xssl_rand_init(void);
290 static void a_xssl_init(void);
292 #if HAVE_XSSL_OPENSSL < 0x10100
293 # ifdef HAVE_SSL_ALL_ALGORITHMS
294 static void a_xssl__load_algos(void);
295 # define a_xssl_load_algos a_xssl__load_algos
296 # endif
297 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
298 static void a_xssl_atexit(void);
299 # endif
300 #endif
301 #ifndef a_xssl_load_algos
302 # define a_xssl_load_algos() do{;}while(0)
303 #endif
305 static bool_t _ssl_parse_asn1_time(ASN1_TIME const *atp,
306 char *bdat, size_t blen);
307 static int _ssl_verify_cb(int success, X509_STORE_CTX *store);
309 /* *smime-ca-flags*, *ssl-ca-flags* */
310 static void a_xssl_ca_flags(X509_STORE *store, char const *flags);
312 /* SSL_CTX configuration */
313 static void * a_xssl_conf_setup(SSL_CTX *ctxp, struct url const *urlp);
314 static bool_t a_xssl_conf(void *confp, char const *cmd, char const *value);
315 static bool_t a_xssl_conf_finish(void **confp, bool_t error);
317 static bool_t a_xssl_obsolete_conf_vars(void *confp, struct url const *urlp);
318 static bool_t a_xssl_config_pairs(void *confp, struct url const *urlp);
319 static bool_t a_xssl_load_verifications(SSL_CTX *ctxp, struct url const *urlp);
321 static enum okay ssl_check_host(struct sock *sp, struct url const *urlp);
323 static int smime_verify(struct message *m, int n,
324 n_XSSL_STACKOF(X509) *chain, X509_STORE *store);
325 static EVP_CIPHER const * _smime_cipher(char const *name);
326 static int ssl_password_cb(char *buf, int size, int rwflag,
327 void *userdata);
328 static FILE * smime_sign_cert(char const *xname, char const *xname2,
329 bool_t dowarn, char const **match);
330 static char const * _smime_sign_include_certs(char const *name);
331 static bool_t _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
332 char const *cfiles, char const *addr);
333 static EVP_MD const * _smime_sign_digest(char const *name,
334 char const **digname);
335 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
336 static enum okay load_crl1(X509_STORE *store, char const *name);
337 #endif
338 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
340 static void
341 a_xssl_rand_init(void){
342 #define a_XSSL_RAND_ENTROPY 32
343 char b64buf[a_XSSL_RAND_ENTROPY * 5 +1], *randfile;
344 char const *cp, *x;
345 bool_t err;
346 NYD2_ENTER;
348 a_xssl_state |= a_XSSL_S_RAND_INIT;
350 err = TRU1;
351 randfile = NULL;
353 #ifdef HAVE_XSSL_CONFIG
354 if(!(a_xssl_state & a_XSSL_S_INIT))
355 a_xssl_init();
356 #endif
358 /* Shall use some external daemon? */
359 if((cp = ok_vlook(ssl_rand_egd)) != NULL){
360 #ifdef HAVE_XSSL_RAND_EGD
361 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) != NULL &&
362 RAND_egd(cp = x) != -1){
363 err = FAL0;
364 goto jleave;
366 n_err(_("*ssl_rand_egd* daemon at %s not available\n"),
367 n_shexp_quote_cp(cp, FAL0));
368 #else
369 if(n_poption & n_PO_D_VV)
370 n_err(_("*ssl_rand_egd* (%s): unsupported by SSL library\n"),
371 n_shexp_quote_cp(cp, FAL0));
372 #endif
375 /* Prefer possible user setting */
376 if((cp = ok_vlook(ssl_rand_file)) != NULL){
377 x = NULL;
378 if(*cp != '\0'){
379 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
380 n_err(_("*ssl-rand-file*: expansion of %s failed "
381 "(using OpenSSL default)\n"),
382 n_shexp_quote_cp(cp, FAL0));
384 cp = x;
386 if(cp == NULL){
387 randfile = n_lofi_alloc(PATH_MAX);
388 if((cp = RAND_file_name(randfile, PATH_MAX)) == NULL){
389 n_err(_("*ssl-rand-file*: no SSL entropy file, can't seed PRNG\n"));
390 goto jleave;
394 (void)RAND_load_file(cp, a_XSSL_RAND_LOAD_FILE_MAXBYTES);
396 /* And feed in some data, then write the updated file.
397 * While this rather feeds the PRNG with itself in the n_RANDOM_IMPL_SSL
398 * case, let us stir the buffer a little bit.
399 * Estimate a low but likely still too high number of entropy bytes, use
400 * 20%: base64 uses 3 input = 4 output bytes relation, and the base64
401 * alphabet is a 6 bit one */
402 for(x = (char*)-1;;){
403 RAND_add(n_random_create_buf(b64buf, sizeof(b64buf) -1, NULL),
404 sizeof(b64buf) -1, a_XSSL_RAND_ENTROPY);
405 if((x = (char*)((uintptr_t)x >> (1
406 #if HAVE_RANDOM == n_RANDOM_IMPL_SSL
408 #endif
409 ))) == NULL){
410 err = (RAND_status() == 0);
411 break;
413 #if HAVE_RANDOM != n_RANDOM_IMPL_SSL
414 if(!(err = (RAND_status() == 0)))
415 break;
416 #endif
419 if(!err)
420 err = (RAND_write_file(cp) == -1);
422 jleave:
423 if(randfile != NULL)
424 n_lofi_free(randfile);
425 if(err)
426 n_panic(_("Cannot seed the *SSL PseudoRandomNumberGenerator, "
427 "RAND_status() is 0!\n"
428 " Please set *ssl-rand-file* to a file with sufficient entropy.\n"
429 " On a machine with entropy: "
430 "\"$ dd if=/dev/urandom of=FILE bs=1024 count=1\"\n"));
431 NYD2_LEAVE;
434 static void
435 a_xssl_init(void){
436 #ifdef HAVE_XSSL_CONFIG
437 char const *cp;
438 #endif
439 NYD2_ENTER;
441 if(a_xssl_state & a_XSSL_S_INIT)
442 goto jleave;
444 #if HAVE_XSSL_OPENSSL >= 0x10100
445 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS |
446 OPENSSL_INIT_LOAD_CRYPTO_STRINGS
447 # ifdef HAVE_SSL_ALL_ALGORITHMS
448 | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS
449 # endif
450 , NULL);
451 #else
452 SSL_load_error_strings();
453 SSL_library_init();
454 a_xssl_load_algos();
455 #endif
456 a_xssl_state |= a_XSSL_S_INIT;
459 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
460 #ifdef HAVE_XSSL_CONFIG
461 if((cp = ok_vlook(ssl_config_file)) != NULL){
462 char const *msg;
463 ul_i flags;
465 if(*cp == '\0'){
466 msg = "[default]";
467 cp = NULL;
468 flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
469 }else if((msg = cp, cp = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) != NULL)
470 flags = 0;
471 else{
472 n_err(_("*ssl-config-file*: file expansion failed: %s\n"),
473 n_shexp_quote_cp(msg, FAL0));
474 goto jefile;
477 if(CONF_modules_load_file(cp, n_uagent, flags) == 1){
478 a_xssl_state |= a_XSSL_S_CONF_LOAD;
479 # if HAVE_XSSL_OPENSSL < 0x10100
480 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
481 a_xssl_state |= a_XSSL_S_EXIT_HDL;
482 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
484 # endif
485 if(n_poption & n_PO_D_V)
486 n_err(_("Loaded SSL/TLS configuration for %s from %s\n"), n_uagent,
487 n_shexp_quote_cp(msg, FAL0));
488 jefile:;
489 }else
490 ssl_gen_err(_("SSL/TLS CONF_modules_load_file() load error"));
492 #endif /* HAVE_XSSL_CONFIG */
494 if(!(a_xssl_state & a_XSSL_S_RAND_INIT))
495 a_xssl_rand_init();
496 jleave:
497 NYD2_LEAVE;
500 #if HAVE_XSSL_OPENSSL < 0x10100
501 # ifdef HAVE_SSL_ALL_ALGORITHMS
502 static void
503 a_xssl__load_algos(void){
504 NYD2_ENTER;
505 if(!(a_xssl_state & a_XSSL_S_ALGO_LOAD)){
506 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
507 OpenSSL_add_all_algorithms();
509 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
510 a_xssl_state |= a_XSSL_S_EXIT_HDL;
511 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
514 NYD2_LEAVE;
516 # endif
518 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
519 static void
520 a_xssl_atexit(void){
521 NYD2_ENTER;
522 # ifdef HAVE_XSSL_CONFIG
523 if(a_xssl_state & a_XSSL_S_CONF_LOAD)
524 CONF_modules_free();
525 # endif
527 # ifdef HAVE_SSL_ALL_ALGORITHMS
528 if(a_xssl_state & a_XSSL_S_ALGO_LOAD)
529 EVP_cleanup();
530 # endif
531 NYD2_LEAVE;
533 # endif
534 #endif /* HAVE_XSSL_OPENSSL < 0x10100 */
536 static bool_t
537 _ssl_parse_asn1_time(ASN1_TIME const *atp, char *bdat, size_t blen)
539 BIO *mbp;
540 char *mcp;
541 long l;
542 NYD_ENTER;
544 mbp = BIO_new(BIO_s_mem());
546 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
547 snprintf(bdat, blen, "%.*s", (int)l, mcp);
548 else {
549 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
550 /*is (int)*/atp->length, (char const*)atp->data);
551 mcp = NULL;
554 BIO_free(mbp);
555 NYD_LEAVE;
556 return (mcp != NULL);
559 static int
560 _ssl_verify_cb(int success, X509_STORE_CTX *store)
562 char data[256];
563 X509 *cert;
564 int rv = TRU1;
565 NYD_ENTER;
567 if (success && !(n_poption & n_PO_D_V))
568 goto jleave;
570 if (a_xssl_msgno != 0) {
571 n_err(_("Message %lu:\n"), (ul_i)a_xssl_msgno);
572 a_xssl_msgno = 0;
574 n_err(_(" Certificate depth %d %s\n"),
575 X509_STORE_CTX_get_error_depth(store), (success ? n_empty : V_(n_error)));
577 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
578 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
579 n_err(_(" subject = %s\n"), data);
581 _ssl_parse_asn1_time(a_xssl_X509_get_notBefore(cert), data, sizeof data);
582 n_err(_(" notBefore = %s\n"), data);
584 _ssl_parse_asn1_time(a_xssl_X509_get_notAfter(cert), data, sizeof data);
585 n_err(_(" notAfter = %s\n"), data);
587 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
588 n_err(_(" issuer = %s\n"), data);
591 if (!success) {
592 int err = X509_STORE_CTX_get_error(store);
594 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
595 a_xssl_state |= a_XSSL_S_VERIFY_ERROR;
598 if (!success && ssl_verify_decide() != OKAY)
599 rv = FAL0;
600 jleave:
601 NYD_LEAVE;
602 return rv;
605 static void
606 a_xssl_ca_flags(X509_STORE *store, char const *flags){
607 NYD2_ENTER;
608 if(flags != NULL){
609 char *iolist, *cp;
611 iolist = savestr(flags);
612 jouter:
613 while((cp = n_strsep(&iolist, ',', TRU1)) != NULL){
614 struct a_xssl_x509_v_flags const *xvfp;
616 for(xvfp = &a_xssl_x509_v_flags[0];
617 xvfp < &a_xssl_x509_v_flags[n_NELEM(a_xssl_x509_v_flags)];
618 ++xvfp)
619 if(!asccasecmp(cp, xvfp->xvf_name)){
620 if(xvfp->xvf_flag != -1){
621 #ifdef a_XSSL_X509_V_ANY
622 X509_STORE_set_flags(store, xvfp->xvf_flag);
623 #endif
624 }else if(n_poption & n_PO_D_V)
625 n_err(_("*{smime,ssl}-ca-flags*: "
626 "directive not supported: %s\n"), cp);
627 goto jouter;
629 n_err(_("*{smime,ssl}-ca-flags*: invalid directive: %s\n"), cp);
632 NYD2_LEAVE;
635 #ifdef HAVE_XSSL_CONF_CTX
636 static void *
637 a_xssl_conf_setup(SSL_CTX *ctxp, struct url const *urlp){
638 char const *cp;
639 SSL_CONF_CTX *sccp;
640 NYD2_ENTER;
642 sccp = NULL;
644 if((cp = xok_vlook(ssl_config_module, urlp, OXM_ALL)) != NULL){
645 # ifdef HAVE_XSSL_CTX_CONFIG
646 if(!(a_xssl_state & a_XSSL_S_CONF_LOAD)){
647 n_err(_("*ssl-config-module*: no *ssl-config-file* loaded: %s\n"),
648 n_shexp_quote_cp(cp, FAL0));
649 goto jleave;
650 }else if(!SSL_CTX_config(ctxp, cp)){
651 ssl_gen_err(_("*ssl-config-module*: load error for %s, section [%s]"),
652 n_uagent, n_shexp_quote_cp(cp, FAL0));
653 goto jleave;
655 # else
656 n_err(_("*ssl-config-module*: set but not supported: %s\n"),
657 n_shexp_quote_cp(cp, FAL0));
658 goto jleave;
659 # endif
662 if((sccp = SSL_CONF_CTX_new()) != NULL){
663 SSL_CONF_CTX_set_flags(sccp,
664 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
665 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
667 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
668 }else
669 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
670 jleave:
671 NYD2_LEAVE;
672 return sccp;
675 static bool_t
676 a_xssl_conf(void *confp, char const *cmd, char const *value){
677 int rv;
678 SSL_CONF_CTX *sccp;
679 NYD2_ENTER;
681 if(n_poption & n_PO_D_V)
682 n_err(_("SSL/TLS: applying config: %s = %s\n"),
683 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(value, FAL0));
685 rv = SSL_CONF_cmd(sccp = confp, cmd, value);
686 if(rv == 2)
687 rv = 0;
688 else{
689 cmd = n_shexp_quote_cp(cmd, FAL0);
690 value = n_shexp_quote_cp(value, FAL0);
691 if(rv == 0)
692 ssl_gen_err(_("SSL/TLS: config failure: %s = %s"), cmd, value);
693 else{
694 char const *err;
696 switch(rv){
697 case -2: err = N_("SSL/TLS: config command not recognized"); break;
698 case -3: err = N_("SSL/TLS: missing required config argument"); break;
699 default: err = N_("SSL/TLS: unspecified config error"); break;
701 err = V_(err);
702 n_err(_("%s (%d): %s = %s\n"), err, rv, cmd, value);
704 rv = 1;
706 NYD2_LEAVE;
707 return (rv == 0);
710 static bool_t
711 a_xssl_conf_finish(void **confp, bool_t error){
712 SSL_CONF_CTX **sccp;
713 bool_t rv;
714 NYD2_ENTER;
716 sccp = (SSL_CONF_CTX**)confp;
718 if(!(rv = error))
719 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
721 SSL_CONF_CTX_free(*sccp);
723 *sccp = NULL;
724 NYD2_LEAVE;
725 return rv;
728 #else /* HAVE_XSSL_CONF_CTX */
729 # ifdef HAVE_XSSL_CTX_CONFIG
730 # error SSL_CTX_config(3) support unexpected without SSL_CONF_CTX support
731 # endif
733 static void *
734 a_xssl_conf_setup(SSL_CTX* ctxp, struct url const *urlp){
735 char const *cp;
736 NYD2_ENTER;
738 if((cp = xok_vlook(ssl_config_module, urlp, OXM_ALL)) != NULL){
739 n_err(_("*ssl-config-module*: set but not supported: %s\n"),
740 n_shexp_quote_cp(cp, FAL0));
741 ctxp = NULL;
743 NYD2_LEAVE;
744 return ctxp;
747 static bool_t
748 a_xssl_conf(void *confp, char const *cmd, char const *value){
749 char const *xcmd, *emsg;
750 SSL_CTX *ctxp;
751 NYD2_ENTER;
753 if(n_poption & n_PO_D_V)
754 n_err(_("SSL/TLS: applying config: %s = %s\n"),
755 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(value, FAL0));
757 ctxp = confp;
759 if(!asccasecmp(cmd, xcmd = "Certificate")){
760 if(SSL_CTX_use_certificate_chain_file(ctxp, value) != 1){
761 emsg = N_("SSL/TLS: %s: cannot load from file %s\n");
762 goto jerr;
764 }else if(!asccasecmp(cmd, xcmd = "CipherString") ||
765 !asccasecmp(cmd, xcmd = "CipherList")){
766 if(SSL_CTX_set_cipher_list(ctxp, value) != 1){
767 emsg = N_("SSL/TLS: %s: invalid: %s\n");
768 goto jerr;
770 }else if(!asccasecmp(cmd, xcmd = "Curves")){
771 #ifdef SSL_CTRL_SET_CURVES_LIST
772 if(SSL_CTX_set1_curves_list(ctxp, value) != 1){
773 emsg = N_("SSL/TLS: %s: invalid: %s\n");
774 goto jerr;
776 #else
777 value = NULL;
778 emsg = N_("SSL/TLS: %s: directive not supported\n");
779 goto jxerr;
780 #endif
781 }else if((emsg = NULL, !asccasecmp(cmd, xcmd = "MaxProtocol")) ||
782 (emsg = (char*)-1, !asccasecmp(cmd, xcmd = "MinProtocol"))){
783 #ifndef HAVE_XSSL_SET_MIN_PROTO_VERSION
784 value = NULL;
785 emsg = N_("SSL/TLS: %s: directive not supported\n");
786 goto jxerr;
787 #else
788 struct a_xssl_protocol const *xpp;
789 size_t i;
791 for(i = 1 /* [0] == ALL */;;){
792 xpp = &a_xssl_protocols[i];
794 if(xpp->sp_ok_minmaxproto && !asccasecmp(value, xpp->sp_name))
795 break;
797 if(++i >= n_NELEM(a_xssl_protocols)){
798 emsg = N_("SSL/TLS: %s: unsupported element: %s\n");
799 goto jxerr;
803 if((emsg == NULL ? SSL_CTX_set_max_proto_version(ctxp, xpp->sp_version)
804 : SSL_CTX_set_min_proto_version(ctxp, xpp->sp_version)) != 1){
805 emsg = N_("SSL/TLS: %s: invalid protocol: %s\n");
806 goto jerr;
808 #endif /* !HAVE_XSSL_SET_MIN_PROTO_VERSION */
809 }else if(!asccasecmp(cmd, xcmd = "Options")){
810 if(asccasecmp(value, "Bugs")){
811 emsg = N_("SSL/TLS: %s: fallback only supports value \"Bugs\": %s\n");
812 goto jxerr;
814 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
815 }else if(!asccasecmp(cmd, xcmd = "PrivateKey")){
816 if(SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1){
817 emsg = N_("%s: cannot load from file %s\n");
818 goto jerr;
820 }else if(!asccasecmp(cmd, xcmd = "Protocol")){
821 char *iolist, *cp, addin;
822 size_t i;
823 sl_i opts;
825 opts = 0;
827 for(iolist = cp = savestr(value);
828 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;){
829 if(*cp == '\0'){
830 value = NULL;
831 emsg = N_("SSL/TLS: %s: empty elements are not supported\n");
832 goto jxerr;
835 addin = TRU1;
836 switch(cp[0]){
837 case '-': addin = FAL0; /* FALLTHRU */
838 case '+': ++cp; /* FALLTHRU */
839 default : break;
842 for(i = 0;;){
843 struct a_xssl_protocol const *xpp;
845 xpp = &a_xssl_protocols[i];
847 if(xpp->sp_ok_proto && !asccasecmp(cp, xpp->sp_name)){
848 /* We need to inverse the meaning of the _NO_s */
849 if(!addin)
850 opts |= xpp->sp_op_no;
851 else
852 opts &= ~xpp->sp_op_no;
853 break;
856 if(++i >= n_NELEM(a_xssl_protocols)){
857 emsg = N_("SSL/TLS: %s: unsupported element: %s\n");
858 goto jxerr;
863 SSL_CTX_clear_options(ctxp, SSL_OP_NO_SSL_MASK);
864 SSL_CTX_set_options(ctxp, opts);
865 }else{
866 xcmd = n_shexp_quote_cp(cmd, FAL0);
867 emsg = N_("SSL/TLS: unsupported directive: %s: value: %s\n");
868 goto jxerr;
871 jleave:
872 NYD2_LEAVE;
873 return (confp != NULL);
874 jerr:
875 ssl_gen_err(V_(emsg), xcmd, n_shexp_quote_cp(value, FAL0));
876 confp = NULL;
877 goto jleave;
878 jxerr:
879 if(value != NULL)
880 value = n_shexp_quote_cp(value, FAL0);
881 n_err(V_(emsg), xcmd, value);
882 confp = NULL;
883 goto jleave;
886 static bool_t
887 a_xssl_conf_finish(void **confp, bool_t error){
888 n_UNUSED(confp);
889 n_UNUSED(error);
890 return TRU1;
892 #endif /* !HAVE_XSSL_CONF_CTX */
894 static bool_t
895 a_xssl_obsolete_conf_vars(void *confp, struct url const *urlp){
896 char const *cp, *cp_base, *certchain;
897 bool_t rv;
898 NYD2_ENTER;
900 rv = FAL0;
902 /* Certificate via ssl-cert */
903 if((certchain = cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL){
904 n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-cert*"));
905 if((cp_base = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL){
906 n_err(_("*ssl-cert* value expansion failed: %s\n"),
907 n_shexp_quote_cp(cp, FAL0));
908 goto jleave;
910 if(!a_xssl_conf(confp, "Certificate", certchain = cp_base))
911 goto jleave;
914 /* CipherString via ssl-ciper-list */
915 if((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL){
916 n_OBSOLETE(_("please use *ssl-config-pairs* instead of "
917 "*ssl-cipher-list*"));
918 if(!a_xssl_conf(confp, "CipherString", cp))
919 goto jleave;
922 /* Curves via ssl-curves */
923 if((cp = xok_vlook(ssl_curves, urlp, OXM_ALL)) != NULL){
924 n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-curves*"));
925 if(!a_xssl_conf(confp, "Curves", cp))
926 goto jleave;
929 /* PrivateKey via ssl-key */
930 if((cp = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL){
931 n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-curves*"));
932 if((cp_base = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL){
933 n_err(_("*ssl-key* value expansion failed: %s\n"),
934 n_shexp_quote_cp(cp, FAL0));
935 goto jleave;
937 cp = cp_base;
938 if(certchain == NULL){
939 n_err(_("*ssl-key* can only be used together with *ssl-cert*! "
940 "And use *ssl-config-pairs*!\n"));
941 goto jleave;
944 if((cp != NULL || (cp = certchain) != NULL) &&
945 !a_xssl_conf(confp, "PrivateKey", cp))
946 goto jleave;
948 /* Protocol via ssl-method or ssl-protocol */
949 if((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL){
950 size_t i;
952 n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-method*"));
953 for(i = 0;;){
954 if(!asccasecmp(_ssl_methods[i].sm_name, cp)){
955 cp = _ssl_methods[i].sm_map;
956 break;
958 if(++i == n_NELEM(_ssl_methods)){
959 n_err(_("Unsupported TLS/SSL method: %s\n"), cp);
960 goto jleave;
964 if((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL){
965 n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-protocol*"));
966 if(cp != NULL && (n_poption & n_PO_D_V))
967 n_err(_("*ssl-protocol* overrides *ssl-method*! "
968 "And please use *ssl-config-pairs* instead!\n"));
969 cp = cp_base;
971 if(cp != NULL && !a_xssl_conf(confp, "Protocol", cp))
972 goto jleave;
974 rv = TRU1;
975 jleave:
976 NYD2_LEAVE;
977 return rv;
980 static bool_t
981 a_xssl_config_pairs(void *confp, struct url const *urlp){
982 /* Due to interdependencies some commands have to be delayed a bit */
983 static char const cmdcert[] = "Certificate", cmdprivkey[] = "PrivateKey";
984 char const *valcert, *valprivkey;
985 char *pairs, *cp, *cmd, *val;
986 NYD2_ENTER;
988 if((pairs = n_UNCONST(xok_vlook(ssl_config_pairs, urlp, OXM_ALL))) == NULL)
989 goto jleave;
990 pairs = savestr(pairs);
992 valcert = valprivkey = NULL;
994 while((cp = n_strsep_esc(&pairs, ',', FAL0)) != NULL){
995 char c;
996 enum{
997 a_NONE,
998 a_EXPAND = 1u<<0,
999 a_CERT = 1u<<1,
1000 a_PRIVKEY = 1u<<2,
1001 a_EXPAND_MASK = a_EXPAND | a_CERT | a_PRIVKEY
1002 } f;
1004 /* Directive, space trimmed */
1005 if((cmd = strchr(cp, '=')) == NULL){
1006 jenocmd:
1007 if(pairs == NULL)
1008 pairs = n_UNCONST(n_empty);
1009 n_err(_("*ssl-config-pairs*: missing directive: %s; rest: %s\n"),
1010 n_shexp_quote_cp(cp, FAL0), n_shexp_quote_cp(pairs, FAL0));
1011 goto jleave;
1013 val = &cmd[1];
1015 if((cmd > cp && cmd[-1] == '*')){
1016 --cmd;
1017 f = a_EXPAND;
1018 }else
1019 f = a_NONE;
1020 while(cmd > cp && (c = cmd[-1], blankspacechar(c)))
1021 --cmd;
1022 if(cmd == cp)
1023 goto jenocmd;
1024 *cmd = '\0';
1025 cmd = cp;
1027 /* Command with special treatment? */
1028 if(!asccasecmp(cmd, cmdcert))
1029 f |= a_CERT;
1030 else if(!asccasecmp(cmd, cmdprivkey))
1031 f |= a_PRIVKEY;
1033 /* Value, space trimmed */
1034 while((c = *val) != '\0' && blankspacechar(c))
1035 ++val;
1036 cp = &val[strlen(val)];
1037 while(cp > val && (c = cp[-1], blankspacechar(c)))
1038 --cp;
1039 *cp = '\0';
1040 if(cp == val){
1041 if(pairs == NULL)
1042 pairs = n_UNCONST(n_empty);
1043 n_err(_("*ssl-config-pairs*: missing value: %s; rest: %s\n"),
1044 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(pairs, FAL0));
1045 goto jleave;
1048 /* Filename transformations to be applied? */
1049 if(f & a_EXPAND_MASK){
1050 if((cp = fexpand(val, FEXP_LOCAL | FEXP_NOPROTO)) == NULL){
1051 if(pairs == NULL)
1052 pairs = n_UNCONST(n_empty);
1053 n_err(_("*ssl-config-pairs*: value expansion failed: %s: %s; "
1054 "rest: %s\n"),
1055 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(val, FAL0),
1056 n_shexp_quote_cp(pairs, FAL0));
1057 goto jleave;
1059 val = cp;
1062 /* Some things have to be delayed */
1063 if(f & a_CERT)
1064 valcert = val;
1065 else if(f & a_PRIVKEY)
1066 valprivkey = val;
1067 else if(!a_xssl_conf(confp, cmd, val)){
1068 pairs = n_UNCONST(n_empty);
1069 goto jleave;
1073 /* Work the delayed ones */
1074 if((valcert != NULL && !a_xssl_conf(confp, cmdcert, valcert)) ||
1075 ((valprivkey != NULL || (valprivkey = valcert) != NULL) &&
1076 !a_xssl_conf(confp, cmdprivkey, valprivkey)))
1077 pairs = n_UNCONST(n_empty);
1079 jleave:
1080 NYD2_LEAVE;
1081 return (pairs == NULL);
1084 static bool_t
1085 a_xssl_load_verifications(SSL_CTX *ctxp, struct url const *urlp){
1086 char *ca_dir, *ca_file;
1087 X509_STORE *store;
1088 bool_t rv;
1089 NYD2_ENTER;
1091 if(ssl_verify_level == SSL_VERIFY_IGNORE){
1092 rv = TRU1;
1093 goto jleave;
1095 rv = FAL0;
1097 if((ca_dir = xok_vlook(ssl_ca_dir, urlp, OXM_ALL)) != NULL)
1098 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
1099 if((ca_file = xok_vlook(ssl_ca_file, urlp, OXM_ALL)) != NULL)
1100 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
1102 if((ca_dir != NULL || ca_file != NULL) &&
1103 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1){
1104 char const *m1, *m2, *m3;
1106 if(ca_dir != NULL){
1107 m1 = ca_dir;
1108 m2 = (ca_file != NULL) ? _(" or ") : n_empty;
1109 }else
1110 m1 = m2 = n_empty;
1111 m3 = (ca_file != NULL) ? ca_file : n_empty;
1112 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
1113 goto jleave;
1116 /* C99 */{
1117 bool_t xv15;
1119 if((xv15 = ok_blook(ssl_no_default_ca)))
1120 n_OBSOLETE(_("please use *ssl-ca-no-defaults*, "
1121 "not *ssl-no-default-ca*"));
1122 if(!xok_blook(ssl_ca_no_defaults, urlp, OXM_ALL) && !xv15 &&
1123 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
1124 ssl_gen_err(_("Error loading built-in default CA locations\n"));
1125 goto jleave;
1129 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
1130 a_xssl_msgno = 0;
1131 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
1132 store = SSL_CTX_get_cert_store(ctxp);
1133 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
1134 a_xssl_ca_flags(store, xok_vlook(ssl_ca_flags, urlp, OXM_ALL));
1136 rv = TRU1;
1137 jleave:
1138 NYD2_LEAVE;
1139 return rv;
1142 static enum okay
1143 ssl_check_host(struct sock *sp, struct url const *urlp)
1145 char data[256];
1146 X509 *cert;
1147 n_XSSL_STACKOF(GENERAL_NAME) *gens;
1148 GENERAL_NAME *gen;
1149 X509_NAME *subj;
1150 enum okay rv = STOP;
1151 NYD_ENTER;
1153 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
1154 n_err(_("No certificate from: %s\n"), urlp->url_h_p.s);
1155 goto jleave;
1158 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
1159 if (gens != NULL) {
1160 int i;
1162 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
1163 gen = sk_GENERAL_NAME_value(gens, i);
1164 if (gen->type == GEN_DNS) {
1165 if (n_poption & n_PO_D_V)
1166 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
1167 urlp->url_host.s, (char*)gen->d.ia5->data);
1168 rv = rfc2595_hostname_match(urlp->url_host.s,
1169 (char*)gen->d.ia5->data);
1170 if (rv == OKAY)
1171 goto jdone;
1176 if ((subj = X509_get_subject_name(cert)) != NULL &&
1177 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
1178 > 0) {
1179 data[sizeof data - 1] = '\0';
1180 if (n_poption & n_PO_D_V)
1181 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
1182 urlp->url_host.s, data);
1183 rv = rfc2595_hostname_match(urlp->url_host.s, data);
1186 jdone:
1187 X509_free(cert);
1188 jleave:
1189 NYD_LEAVE;
1190 return rv;
1193 static int
1194 smime_verify(struct message *m, int n, n_XSSL_STACKOF(X509) *chain,
1195 X509_STORE *store)
1197 char data[LINESIZE], *sender, *to, *cc, *cnttype;
1198 int rv, c, i, j;
1199 struct message *x;
1200 FILE *fp, *ip;
1201 off_t size;
1202 BIO *fb, *pb;
1203 PKCS7 *pkcs7;
1204 n_XSSL_STACKOF(X509) *certs;
1205 n_XSSL_STACKOF(GENERAL_NAME) *gens;
1206 X509 *cert;
1207 X509_NAME *subj;
1208 GENERAL_NAME *gen;
1209 NYD_ENTER;
1211 rv = 1;
1212 fp = NULL;
1213 fb = pb = NULL;
1214 pkcs7 = NULL;
1215 certs = NULL;
1216 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
1217 a_xssl_msgno = (size_t)n;
1219 for (;;) {
1220 sender = getsender(m);
1221 to = hfield1("to", m);
1222 cc = hfield1("cc", m);
1223 cnttype = hfield1("content-type", m);
1225 #undef _X
1226 #undef _Y
1227 #define _X (sizeof("application/") -1)
1228 #define _Y(X) X, sizeof(X) -1
1229 if (cnttype && is_asccaseprefix("application/", cnttype) &&
1230 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
1231 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
1232 #undef _Y
1233 #undef _X
1234 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1235 goto jleave;
1236 if (x != (struct message*)-1) {
1237 m = x;
1238 continue;
1242 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1243 goto jleave;
1244 size = m->m_size;
1245 break;
1248 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1249 NULL) {
1250 n_perr(_("tempfile"), 0);
1251 goto jleave;
1253 while (size-- > 0) {
1254 c = getc(ip);
1255 putc(c, fp);
1257 fflush_rewind(fp);
1259 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1260 ssl_gen_err(_(
1261 "Error creating BIO verification object for message %d"), n);
1262 goto jleave;
1265 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1266 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1267 goto jleave;
1269 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
1270 ssl_gen_err(_("Error verifying message %d"), n);
1271 goto jleave;
1274 if (sender == NULL) {
1275 n_err(_("Warning: Message %d has no sender\n"), n);
1276 rv = 0;
1277 goto jleave;
1280 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1281 if (certs == NULL) {
1282 n_err(_("No certificates found in message %d\n"), n);
1283 goto jleave;
1286 for (i = 0; i < sk_X509_num(certs); ++i) {
1287 cert = sk_X509_value(certs, i);
1288 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
1289 if (gens != NULL) {
1290 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
1291 gen = sk_GENERAL_NAME_value(gens, j);
1292 if (gen->type == GEN_EMAIL) {
1293 if (n_poption & n_PO_D_V)
1294 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
1295 sender, (char*)gen->d.ia5->data);
1296 if (!asccasecmp((char*)gen->d.ia5->data, sender))
1297 goto jfound;
1302 if ((subj = X509_get_subject_name(cert)) != NULL &&
1303 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
1304 data, sizeof data) > 0) {
1305 data[sizeof data -1] = '\0';
1306 if (n_poption & n_PO_D_V)
1307 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
1308 sender, data);
1309 if (!asccasecmp(data, sender))
1310 goto jfound;
1313 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
1314 goto jleave;
1315 jfound:
1316 rv = ((a_xssl_state & a_XSSL_S_VERIFY_ERROR) != 0);
1317 if (!rv)
1318 fprintf(n_stdout, _("Message %d was verified successfully\n"), n);
1319 jleave:
1320 if (certs != NULL)
1321 sk_X509_free(certs);
1322 if (pb != NULL)
1323 BIO_free(pb);
1324 if (fb != NULL)
1325 BIO_free(fb);
1326 if (pkcs7 != NULL)
1327 PKCS7_free(pkcs7);
1328 if (fp != NULL)
1329 Fclose(fp);
1330 NYD_LEAVE;
1331 return rv;
1334 static EVP_CIPHER const *
1335 _smime_cipher(char const *name)
1337 EVP_CIPHER const *cipher;
1338 char *vn;
1339 char const *cp;
1340 size_t i;
1341 NYD_ENTER;
1343 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
1344 snprintf(vn, (int)i, "smime-cipher-%s", name);
1345 cp = n_var_vlook(vn, FAL0);
1346 ac_free(vn);
1348 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
1349 cipher = a_XSSL_SMIME_DEFAULT_CIPHER();
1350 goto jleave;
1352 cipher = NULL;
1354 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers); ++i)
1355 if (!asccasecmp(a_xssl_smime_ciphers[i].sc_name, cp)) {
1356 cipher = (*a_xssl_smime_ciphers[i].sc_fun)();
1357 goto jleave;
1359 #ifndef OPENSSL_NO_AES
1360 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers_obs); ++i) /* TODO obsolete */
1361 if (!asccasecmp(a_xssl_smime_ciphers_obs[i].sc_name, cp)) {
1362 n_OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
1363 cipher = (*a_xssl_smime_ciphers_obs[i].sc_fun)();
1364 goto jleave;
1366 #endif
1368 /* Not a built-in algorithm, but we may have dynamic support for more */
1369 #ifdef HAVE_SSL_ALL_ALGORITHMS
1370 if((cipher = EVP_get_cipherbyname(cp)) != NULL)
1371 goto jleave;
1372 #endif
1374 n_err(_("Invalid S/MIME cipher(s): %s\n"), cp);
1375 jleave:
1376 NYD_LEAVE;
1377 return cipher;
1380 static int
1381 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
1383 char *pass;
1384 size_t len;
1385 NYD_ENTER;
1386 n_UNUSED(rwflag);
1387 n_UNUSED(userdata);
1389 /* New-style */
1390 if(userdata != NULL){
1391 struct url url;
1392 struct ccred cred;
1394 if(url_parse(&url, CPROTO_CCRED, userdata)){
1395 if(ccred_lookup(&cred, &url)){
1396 ssize_t slen;
1398 if((slen = n_strscpy(buf, cred.cc_pass.s, size)) >= 0){
1399 size = (int)slen;
1400 goto jleave;
1403 size = 0;
1404 goto jleave;
1408 /* Old-style */
1409 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
1410 len = strlen(pass);
1411 if (UICMP(z, len, >=, size))
1412 len = size -1;
1413 memcpy(buf, pass, len);
1414 buf[len] = '\0';
1415 size = (int)len;
1416 } else
1417 size = 0;
1418 jleave:
1419 NYD_LEAVE;
1420 return size;
1423 static FILE *
1424 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn,
1425 char const **match)
1427 char *vn;
1428 int vs;
1429 struct name *np;
1430 char const *name = xname, *name2 = xname2, *cp;
1431 FILE *fp = NULL;
1432 NYD_ENTER;
1434 jloop:
1435 if (name) {
1436 np = lextract(name, GTO | GSKIN);
1437 while (np != NULL) {
1438 /* This needs to be more intelligent since it will currently take the
1439 * first name for which a private key is available regardless of
1440 * whether it is the right one for the message */
1441 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1442 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
1443 cp = n_var_vlook(vn, FAL0);
1444 ac_free(vn);
1445 if (cp != NULL) {
1446 if (match != NULL)
1447 *match = np->n_name;
1448 goto jopen;
1450 np = np->n_flink;
1452 if (name2 != NULL) {
1453 name = name2;
1454 name2 = NULL;
1455 goto jloop;
1459 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
1460 goto jerr;
1461 if(match != NULL)
1462 *match = NULL;
1463 jopen:
1464 if ((cp = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
1465 goto jleave;
1466 if ((fp = Fopen(cp, "r")) == NULL)
1467 n_perr(cp, 0);
1468 jleave:
1469 NYD_LEAVE;
1470 return fp;
1471 jerr:
1472 if (dowarn)
1473 n_err(_("Could not find a certificate for %s%s%s\n"),
1474 xname, (xname2 != NULL ? _("or ") : n_empty),
1475 (xname2 != NULL ? xname2 : n_empty));
1476 goto jleave;
1479 static char const *
1480 _smime_sign_include_certs(char const *name)
1482 char const *rv;
1483 NYD_ENTER;
1485 /* See comments in smime_sign_cert() for algorithm pitfalls */
1486 if (name != NULL) {
1487 struct name *np;
1489 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1490 int vs;
1491 char *vn;
1493 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1494 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1495 rv = n_var_vlook(vn, FAL0);
1496 ac_free(vn);
1497 if (rv != NULL)
1498 goto jleave;
1501 rv = ok_vlook(smime_sign_include_certs);
1502 jleave:
1503 NYD_LEAVE;
1504 return rv;
1507 static bool_t
1508 _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
1509 char const *cfiles, char const *addr)
1511 X509 *tmp;
1512 FILE *fp;
1513 char *nfield, *cfield, *x;
1514 NYD_ENTER;
1516 *chain = sk_X509_new_null();
1518 for (nfield = savestr(cfiles);
1519 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1520 if ((x = fexpand(cfield, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1521 (fp = Fopen(cfield = x, "r")) == NULL) {
1522 n_perr(cfiles, 0);
1523 goto jerr;
1525 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, n_UNCONST(addr))
1526 ) == NULL) {
1527 ssl_gen_err(_("Error reading certificate from %s"),
1528 n_shexp_quote_cp(cfield, FAL0));
1529 Fclose(fp);
1530 goto jerr;
1532 sk_X509_push(*chain, tmp);
1533 Fclose(fp);
1536 if (sk_X509_num(*chain) == 0) {
1537 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1538 goto jerr;
1540 jleave:
1541 NYD_LEAVE;
1542 return (*chain != NULL);
1543 jerr:
1544 sk_X509_pop_free(*chain, X509_free);
1545 *chain = NULL;
1546 goto jleave;
1549 static EVP_MD const *
1550 _smime_sign_digest(char const *name, char const **digname)
1552 EVP_MD const *digest;
1553 char const *cp;
1554 size_t i;
1555 NYD_ENTER;
1557 /* See comments in smime_sign_cert() for algorithm pitfalls */
1558 if (name != NULL) {
1559 struct name *np;
1561 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1562 int vs;
1563 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1564 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1565 cp = n_var_vlook(vn, FAL0);
1566 ac_free(vn);
1567 if (cp != NULL)
1568 goto jhave_name;
1572 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1573 digest = a_XSSL_SMIME_DEFAULT_DIGEST();
1574 *digname = a_XSSL_SMIME_DEFAULT_DIGEST_S;
1575 goto jleave;
1578 jhave_name:
1579 i = strlen(cp);
1580 { char *x = salloc(i +1);
1581 i_strcpy(x, cp, i +1);
1582 cp = x;
1584 *digname = cp;
1586 for (i = 0; i < n_NELEM(a_xssl_smime_digests); ++i)
1587 if (!asccasecmp(a_xssl_smime_digests[i].sd_name, cp)) {
1588 digest = (*a_xssl_smime_digests[i].sd_fun)();
1589 goto jleave;
1592 /* Not a built-in algorithm, but we may have dynamic support for more */
1593 #ifdef HAVE_SSL_ALL_ALGORITHMS
1594 if((digest = EVP_get_digestbyname(cp)) != NULL)
1595 goto jleave;
1596 #endif
1598 n_err(_("Invalid message digest: %s\n"), cp);
1599 digest = NULL;
1600 jleave:
1601 NYD_LEAVE;
1602 return digest;
1605 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1606 static enum okay
1607 load_crl1(X509_STORE *store, char const *name)
1609 X509_LOOKUP *lookup;
1610 enum okay rv = STOP;
1611 NYD_ENTER;
1613 if (n_poption & n_PO_D_V)
1614 n_err(_("Loading CRL from %s\n"), n_shexp_quote_cp(name, FAL0));
1615 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1616 ssl_gen_err(_("Error creating X509 lookup object"));
1617 goto jleave;
1619 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1620 ssl_gen_err(_("Error loading CRL from %s"), n_shexp_quote_cp(name, FAL0));
1621 goto jleave;
1623 rv = OKAY;
1624 jleave:
1625 NYD_LEAVE;
1626 return rv;
1628 #endif /* new OpenSSL */
1630 static enum okay
1631 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1633 char *crl_file, *crl_dir;
1634 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1635 DIR *dirp;
1636 struct dirent *dp;
1637 char *fn = NULL;
1638 int fs = 0, ds, es;
1639 #endif
1640 enum okay rv = STOP;
1641 NYD_ENTER;
1643 if ((crl_file = n_var_oklook(fok)) != NULL) {
1644 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1645 if ((crl_file = fexpand(crl_file, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1646 load_crl1(store, crl_file) != OKAY)
1647 goto jleave;
1648 #else
1649 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1650 goto jleave;
1651 #endif
1654 if ((crl_dir = n_var_oklook(dok)) != NULL) {
1655 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1656 char *x;
1657 if ((x = fexpand(crl_dir, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1658 (dirp = opendir(crl_dir = x)) == NULL) {
1659 n_perr(crl_dir, 0);
1660 goto jleave;
1663 ds = strlen(crl_dir);
1664 fn = smalloc(fs = ds + 20);
1665 memcpy(fn, crl_dir, ds);
1666 fn[ds] = '/';
1667 while ((dp = readdir(dirp)) != NULL) {
1668 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1669 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1670 continue;
1671 if (dp->d_name[0] == '.')
1672 continue;
1673 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1674 fn = srealloc(fn, fs = ds + es + 20);
1675 memcpy(fn + ds + 1, dp->d_name, es + 1);
1676 if (load_crl1(store, fn) != OKAY) {
1677 closedir(dirp);
1678 free(fn);
1679 goto jleave;
1682 closedir(dirp);
1683 free(fn);
1684 #else /* old OpenSSL */
1685 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1686 goto jleave;
1687 #endif
1689 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1690 if (crl_file || crl_dir)
1691 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1692 X509_V_FLAG_CRL_CHECK_ALL);
1693 #endif
1694 rv = OKAY;
1695 jleave:
1696 NYD_LEAVE;
1697 return rv;
1700 #if HAVE_RANDOM == n_RANDOM_IMPL_SSL
1701 FL void
1702 ssl_rand_bytes(void *buf, size_t blen){
1703 NYD_ENTER;
1705 if(!(a_xssl_state & a_XSSL_S_RAND_INIT))
1706 a_xssl_rand_init();
1708 while(blen > 0){
1709 si32_t i;
1711 i = n_MIN(SI32_MAX, blen);
1712 blen -= i;
1713 RAND_bytes(buf, i);
1714 buf = (ui8_t*)buf + i;
1716 NYD_LEAVE;
1718 #endif
1720 FL enum okay
1721 ssl_open(struct url const *urlp, struct sock *sp){
1722 void *confp;
1723 SSL_CTX *ctxp;
1724 enum okay rv;
1725 NYD_ENTER;
1727 a_xssl_init();
1729 rv = STOP;
1730 ssl_set_verify_level(urlp);
1732 if((ctxp = SSL_CTX_new(n_XSSL_CLIENT_METHOD())) == NULL){
1733 ssl_gen_err(_("SSL_CTX_new() failed"));
1734 goto jleave;
1737 /* Available with OpenSSL 0.9.6 or later */
1738 #ifdef SSL_MODE_AUTO_RETRY
1739 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1740 #endif
1742 if((confp = a_xssl_conf_setup(ctxp, urlp)) == NULL)
1743 goto jerr0;
1745 if(!a_xssl_obsolete_conf_vars(confp, urlp))
1746 goto jerr1;
1747 if(!a_xssl_config_pairs(confp, urlp))
1748 goto jerr1;
1749 if(!a_xssl_load_verifications(ctxp, urlp))
1750 goto jerr1;
1752 /* Done with context setup, create our new per-connection structure */
1753 if(!a_xssl_conf_finish(&confp, FAL0))
1754 goto jerr0;
1756 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1757 ssl_gen_err(_("SSL_new() failed"));
1758 goto jerr0;
1761 /* Try establish SNI extension; even though this is a TLS extension the
1762 * protocol isn't checked once the host name is set, and therefore i've
1763 * refrained from changing so much code just to check out whether we are
1764 * using SSLv3, which should become more and more rare */
1765 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1766 if((urlp->url_flags & n_URL_TLS_MASK) &&
1767 (urlp->url_flags & n_URL_HOST_IS_NAME)){
1768 if(!SSL_set_tlsext_host_name(sp->s_ssl, urlp->url_host.s) &&
1769 (n_poption & n_PO_D_V))
1770 n_err(_("Hostname cannot be used with ServerNameIndication "
1771 "TLS extension: %s\n"),
1772 n_shexp_quote_cp(urlp->url_host.s, FAL0));
1774 #endif
1776 SSL_set_fd(sp->s_ssl, sp->s_fd);
1778 if (SSL_connect(sp->s_ssl) < 0) {
1779 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1780 goto jerr2;
1783 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1784 if (ssl_check_host(sp, urlp) != OKAY) {
1785 n_err(_("Host certificate does not match: %s\n"), urlp->url_h_p.s);
1786 if (ssl_verify_decide() != OKAY)
1787 goto jerr2;
1791 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1792 * and free it right now -- it is reference counted by sp->s_ssl.. */
1793 SSL_CTX_free(ctxp);
1794 sp->s_use_ssl = 1;
1795 rv = OKAY;
1796 jleave:
1797 NYD_LEAVE;
1798 return rv;
1799 jerr2:
1800 SSL_free(sp->s_ssl);
1801 sp->s_ssl = NULL;
1802 jerr1:
1803 if (confp != NULL)
1804 a_xssl_conf_finish(&confp, TRU1);
1805 jerr0:
1806 SSL_CTX_free(ctxp);
1807 goto jleave;
1810 FL void
1811 ssl_gen_err(char const *fmt, ...)
1813 va_list ap;
1814 NYD_ENTER;
1816 va_start(ap, fmt);
1817 n_verr(fmt, ap);
1818 va_end(ap);
1820 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1821 NYD_LEAVE;
1824 FL int
1825 c_verify(void *vp)
1827 int *msgvec = vp, *ip, ec = 0, rv = 1;
1828 X509_STORE *store = NULL;
1829 char *ca_dir, *ca_file;
1830 NYD_ENTER;
1832 a_xssl_init();
1834 ssl_verify_level = SSL_VERIFY_STRICT;
1835 if ((store = X509_STORE_new()) == NULL) {
1836 ssl_gen_err(_("Error creating X509 store"));
1837 goto jleave;
1839 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1841 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1842 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
1843 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1844 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
1846 if (ca_dir != NULL || ca_file != NULL) {
1847 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
1848 ssl_gen_err(_("Error loading %s"),
1849 (ca_file != NULL) ? ca_file : ca_dir);
1850 goto jleave;
1854 /* C99 */{
1855 bool_t xv15;
1857 if((xv15 = ok_blook(smime_no_default_ca)))
1858 n_OBSOLETE(_("please use *smime-ca-no-defaults*, "
1859 "not *smime-no-default-ca*"));
1860 if(!ok_blook(smime_ca_no_defaults) && !xv15 &&
1861 X509_STORE_set_default_paths(store) != 1) {
1862 ssl_gen_err(_("Error loading built-in default CA locations\n"));
1863 goto jleave;
1867 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1868 goto jleave;
1870 a_xssl_ca_flags(store, ok_vlook(smime_ca_flags));
1872 srelax_hold();
1873 for (ip = msgvec; *ip != 0; ++ip) {
1874 struct message *mp = message + *ip - 1;
1875 setdot(mp);
1876 ec |= smime_verify(mp, *ip, NULL, store);
1877 srelax();
1879 srelax_rele();
1881 if ((rv = ec) != 0)
1882 n_exit_status |= n_EXIT_ERR;
1883 jleave:
1884 if (store != NULL)
1885 X509_STORE_free(store);
1886 NYD_LEAVE;
1887 return rv;
1890 FL FILE *
1891 smime_sign(FILE *ip, char const *addr)
1893 FILE *rv, *sp, *fp, *bp, *hp;
1894 X509 *cert = NULL;
1895 n_XSSL_STACKOF(X509) *chain = NULL;
1896 EVP_PKEY *pkey = NULL;
1897 BIO *bb, *sb;
1898 PKCS7 *pkcs7;
1899 EVP_MD const *md;
1900 char const *name;
1901 bool_t bail = FAL0;
1902 NYD_ENTER;
1904 assert(addr != NULL);
1905 rv = sp = fp = bp = hp = NULL;
1907 a_xssl_init();
1909 if (addr == NULL) {
1910 n_err(_("No *from* address for signing specified\n"));
1911 goto jleave;
1913 if ((fp = smime_sign_cert(addr, NULL, 1, NULL)) == NULL)
1914 goto jleave;
1916 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb,
1917 savecat(addr, ".smime-cert-key"))) == NULL) {
1918 ssl_gen_err(_("Error reading private key from"));
1919 goto jleave;
1922 rewind(fp);
1923 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb,
1924 savecat(addr, ".smime-cert-cert"))) == NULL) {
1925 ssl_gen_err(_("Error reading signer certificate from"));
1926 goto jleave;
1928 Fclose(fp);
1929 fp = NULL;
1931 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1932 !_smime_sign_include_chain_creat(&chain, name,
1933 savecat(addr, ".smime-include-certs")))
1934 goto jleave;
1936 name = NULL;
1937 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1938 goto jleave;
1940 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1941 NULL) {
1942 n_perr(_("tempfile"), 0);
1943 goto jleave;
1946 rewind(ip);
1947 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1948 goto jleave;
1950 sb = NULL;
1951 pkcs7 = NULL;
1953 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1954 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1955 ssl_gen_err(_("Error creating BIO signing objects"));
1956 bail = TRU1;
1957 goto jerr;
1960 #undef _X
1961 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1962 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1963 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1964 bail = TRU1;
1965 goto jerr;
1967 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1968 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1969 bail = TRU1;
1970 goto jerr;
1972 if (!PKCS7_final(pkcs7, bb, _X)) {
1973 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1974 bail = TRU1;
1975 goto jerr;
1977 #undef _X
1979 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1980 ssl_gen_err(_("Error writing signed S/MIME data"));
1981 bail = TRU1;
1982 /*goto jerr*/
1984 jerr:
1985 if (pkcs7 != NULL)
1986 PKCS7_free(pkcs7);
1987 if (sb != NULL)
1988 BIO_free(sb);
1989 if (bb != NULL)
1990 BIO_free(bb);
1991 if (!bail) {
1992 rewind(bp);
1993 fflush_rewind(sp);
1994 rv = smime_sign_assemble(hp, bp, sp, name);
1995 hp = bp = sp = NULL;
1998 jleave:
1999 if (chain != NULL)
2000 sk_X509_pop_free(chain, X509_free);
2001 if (cert != NULL)
2002 X509_free(cert);
2003 if (pkey != NULL)
2004 EVP_PKEY_free(pkey);
2005 if (fp != NULL)
2006 Fclose(fp);
2007 if (hp != NULL)
2008 Fclose(hp);
2009 if (bp != NULL)
2010 Fclose(bp);
2011 if (sp != NULL)
2012 Fclose(sp);
2013 NYD_LEAVE;
2014 return rv;
2017 FL FILE *
2018 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
2020 FILE *rv, *yp, *fp, *bp, *hp;
2021 X509 *cert;
2022 PKCS7 *pkcs7;
2023 BIO *bb, *yb;
2024 n_XSSL_STACKOF(X509) *certs;
2025 EVP_CIPHER const *cipher;
2026 char *certfile;
2027 bool_t bail;
2028 NYD_ENTER;
2030 bail = FAL0;
2031 rv = yp = fp = bp = hp = NULL;
2033 if ((certfile = fexpand(xcertfile, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
2034 goto jleave;
2036 a_xssl_init();
2038 if ((cipher = _smime_cipher(to)) == NULL)
2039 goto jleave;
2041 if ((fp = Fopen(certfile, "r")) == NULL) {
2042 n_perr(certfile, 0);
2043 goto jleave;
2045 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
2046 ssl_gen_err(_("Error reading encryption certificate from %s"),
2047 n_shexp_quote_cp(certfile, FAL0));
2048 bail = TRU1;
2050 if (bail)
2051 goto jleave;
2052 Fclose(fp);
2053 fp = NULL;
2054 bail = FAL0;
2056 certs = sk_X509_new_null();
2057 sk_X509_push(certs, cert);
2059 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
2060 NULL) {
2061 n_perr(_("tempfile"), 0);
2062 goto jerr1;
2065 rewind(ip);
2066 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
2067 goto jerr1;
2069 yb = NULL;
2070 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
2071 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
2072 ssl_gen_err(_("Error creating BIO encryption objects"));
2073 bail = TRU1;
2074 goto jerr2;
2076 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
2077 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
2078 bail = TRU1;
2079 goto jerr2;
2081 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
2082 ssl_gen_err(_("Error writing encrypted S/MIME data"));
2083 bail = TRU1;
2084 /* goto jerr2 */
2086 PKCS7_free(pkcs7);
2088 jerr2:
2089 if (bb != NULL)
2090 BIO_free(bb);
2091 if (yb != NULL)
2092 BIO_free(yb);
2093 Fclose(bp);
2094 bp = NULL;
2095 if (!bail) {
2096 fflush_rewind(yp);
2097 rv = smime_encrypt_assemble(hp, yp);
2098 hp = yp = NULL;
2100 jerr1:
2101 sk_X509_pop_free(certs, X509_free);
2102 jleave:
2103 if(yp != NULL)
2104 Fclose(yp);
2105 if(fp != NULL)
2106 Fclose(fp);
2107 if(bp != NULL)
2108 Fclose(bp);
2109 if(hp != NULL)
2110 Fclose(hp);
2111 NYD_LEAVE;
2112 return rv;
2115 FL struct message *
2116 smime_decrypt(struct message *m, char const *to, char const *cc,
2117 bool_t signcall)
2119 char const *myaddr;
2120 long size;
2121 struct message *rv;
2122 FILE *bp, *hp, *op;
2123 PKCS7 *pkcs7;
2124 BIO *ob, *bb, *pb;
2125 X509 *cert;
2126 EVP_PKEY *pkey;
2127 FILE *yp;
2128 NYD_ENTER;
2130 pkey = NULL;
2131 cert = NULL;
2132 ob = bb = pb = NULL;
2133 pkcs7 = NULL;
2134 bp = hp = op = NULL;
2135 rv = NULL;
2136 size = m->m_size;
2138 if((yp = setinput(&mb, m, NEED_BODY)) == NULL)
2139 goto jleave;
2141 a_xssl_init();
2143 if((op = smime_sign_cert(to, cc, 0, &myaddr)) != NULL){
2144 pkey = PEM_read_PrivateKey(op, NULL, &ssl_password_cb,
2145 savecat(myaddr, ".smime-cert-key"));
2146 if(pkey == NULL){
2147 ssl_gen_err(_("Error reading private key"));
2148 goto jleave;
2151 rewind(op);
2152 if((cert = PEM_read_X509(op, NULL, &ssl_password_cb,
2153 savecat(myaddr, ".smime-cert-cert"))) == NULL){
2154 ssl_gen_err(_("Error reading decryption certificate"));
2155 goto jleave;
2158 Fclose(op);
2159 op = NULL;
2162 if((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
2163 n_perr(_("tempfile"), 0);
2164 goto jleave;
2167 if(smime_split(yp, &hp, &bp, size, 1) == STOP)
2168 goto jleave;
2170 if((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
2171 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL){
2172 ssl_gen_err(_("Error creating BIO decryption objects"));
2173 goto jleave;
2176 if((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL){
2177 ssl_gen_err(_("Error reading PKCS#7 object"));
2178 goto jleave;
2181 if(PKCS7_type_is_signed(pkcs7)){
2182 if(signcall){
2183 setinput(&mb, m, NEED_BODY);
2184 rv = (struct message*)-1;
2185 goto jleave;
2187 if(PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
2188 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
2189 goto jerr;
2190 fseek(hp, 0L, SEEK_END);
2191 fprintf(hp, "X-Encryption-Cipher: none\n");
2192 fflush_rewind(hp);
2193 }else if(pkey == NULL){
2194 n_err(_("No appropriate private key found\n"));
2195 goto jleave;
2196 }else if(cert == NULL){
2197 n_err(_("No appropriate certificate found\n"));
2198 goto jleave;
2199 }else if(PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1){
2200 jerr:
2201 ssl_gen_err(_("Error decrypting PKCS#7 object"));
2202 goto jleave;
2204 fflush_rewind(op);
2205 Fclose(bp);
2206 bp = NULL;
2208 rv = smime_decrypt_assemble(m, hp, op);
2209 hp = op = NULL; /* xxx closed by decrypt_assemble */
2210 jleave:
2211 if(op != NULL)
2212 Fclose(op);
2213 if(hp != NULL)
2214 Fclose(hp);
2215 if(bp != NULL)
2216 Fclose(bp);
2217 if(bb != NULL)
2218 BIO_free(bb);
2219 if(ob != NULL)
2220 BIO_free(ob);
2221 if(pkcs7 != NULL)
2222 PKCS7_free(pkcs7);
2223 if(cert != NULL)
2224 X509_free(cert);
2225 if(pkey != NULL)
2226 EVP_PKEY_free(pkey);
2227 NYD_LEAVE;
2228 return rv;
2231 FL enum okay
2232 smime_certsave(struct message *m, int n, FILE *op)
2234 struct message *x;
2235 char *to, *cc, *cnttype;
2236 int c, i;
2237 FILE *fp, *ip;
2238 off_t size;
2239 BIO *fb, *pb;
2240 PKCS7 *pkcs7;
2241 n_XSSL_STACKOF(X509) *certs, *chain = NULL;
2242 X509 *cert;
2243 enum okay rv = STOP;
2244 NYD_ENTER;
2246 pkcs7 = NULL;
2248 a_xssl_msgno = (size_t)n;
2249 jloop:
2250 to = hfield1("to", m);
2251 cc = hfield1("cc", m);
2252 cnttype = hfield1("content-type", m);
2254 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
2255 goto jleave;
2257 #undef _X
2258 #undef _Y
2259 #define _X (sizeof("application/") -1)
2260 #define _Y(X) X, sizeof(X) -1
2261 if (cnttype && is_asccaseprefix("application/", cnttype) &&
2262 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
2263 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
2264 #undef _Y
2265 #undef _X
2266 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
2267 goto jleave;
2268 if (x != (struct message*)-1) {
2269 m = x;
2270 goto jloop;
2273 size = m->m_size;
2275 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
2276 NULL) {
2277 n_perr(_("tempfile"), 0);
2278 goto jleave;
2281 while (size-- > 0) {
2282 c = getc(ip);
2283 putc(c, fp);
2285 fflush(fp);
2287 rewind(fp);
2288 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
2289 ssl_gen_err("Error creating BIO object for message %d", n);
2290 Fclose(fp);
2291 goto jleave;
2294 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
2295 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
2296 BIO_free(fb);
2297 Fclose(fp);
2298 goto jleave;
2300 BIO_free(fb);
2301 Fclose(fp);
2303 certs = PKCS7_get0_signers(pkcs7, chain, 0);
2304 if (certs == NULL) {
2305 n_err(_("No certificates found in message %d\n"), n);
2306 goto jleave;
2309 for (i = 0; i < sk_X509_num(certs); ++i) {
2310 cert = sk_X509_value(certs, i);
2311 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
2312 ssl_gen_err(_("Error writing certificate %d from message %d"),
2313 i, n);
2314 goto jleave;
2317 rv = OKAY;
2318 jleave:
2319 if(pkcs7 != NULL)
2320 PKCS7_free(pkcs7);
2321 NYD_LEAVE;
2322 return rv;
2324 #endif /* HAVE_XSSL */
2326 /* s-it-mode */