a_go_evaluate(), c_commandalias(): reserve "u" as command modifier
[s-mailx.git] / xssl.c
blobec6346285e02dda7cbe05bfa2f482a0fa677e12f
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ TLS/SSL functions. TODO this needs an overhaul -- there _are_ stack leaks!?
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
6 */
7 /*
8 * Copyright (c) 2002
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
39 #undef n_FILE
40 #define n_FILE xssl
42 #ifndef HAVE_AMALGAMATION
43 # include "nail.h"
44 #endif
46 EMPTY_FILE()
47 #ifdef HAVE_XSSL
48 #include <sys/socket.h>
50 #include <openssl/crypto.h>
51 #include <openssl/err.h>
52 #include <openssl/evp.h>
53 #include <openssl/opensslv.h>
54 #include <openssl/pem.h>
55 #include <openssl/rand.h>
56 #include <openssl/ssl.h>
57 #include <openssl/x509v3.h>
58 #include <openssl/x509.h>
60 #ifdef HAVE_XSSL_CONFIG
61 # include <openssl/conf.h>
62 #endif
64 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
65 # include <dirent.h>
66 #endif
69 * OpenSSL client implementation according to: John Viega, Matt Messier,
70 * Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
73 /* Update manual on changes (for all those)! */
74 #define n_XSSL_DISABLED_PROTOCOLS "-SSLv2"
76 #ifndef HAVE_XSSL_CONF_CTX
77 # ifndef SSL_OP_NO_SSLv2
78 # define SSL_OP_NO_SSLv2 0
79 # endif
80 # ifndef SSL_OP_NO_SSLv3
81 # define SSL_OP_NO_SSLv3 0
82 # endif
83 # ifndef SSL_OP_NO_TLSv1
84 # define SSL_OP_NO_TLSv1 0
85 # endif
86 # ifndef SSL_OP_NO_TLSv1_1
87 # define SSL_OP_NO_TLSv1_1 0
88 # endif
89 # ifndef SSL_OP_NO_TLSv1_2
90 # define SSL_OP_NO_TLSv1_2 0
91 # endif
93 /* SSL_CONF_CTX and _OP_NO_SSL_MASK were both introduced with 1.0.2!?! */
94 # ifndef SSL_OP_NO_SSL_MASK
95 # define SSL_OP_NO_SSL_MASK \
96 (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |\
97 SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2)
98 # endif
99 #endif
101 #ifdef HAVE_XSSL_STACK_OF
102 # define n_XSSL_STACKOF(X) STACK_OF(X)
103 #else
104 # define n_XSSL_STACKOF(X) /*X*/STACK
105 #endif
107 #if OPENSSL_VERSION_NUMBER + 0 >= 0x0090581fL
108 # define a_XSSL_RAND_LOAD_FILE_MAXBYTES -1
109 #else
110 # define a_XSSL_RAND_LOAD_FILE_MAXBYTES 1024
111 #endif
113 /* Compatibility sighs (that sigh is _really_ a cute one) */
114 #if HAVE_XSSL_OPENSSL >= 0x10100
115 # define a_xssl_X509_get_notBefore X509_get0_notBefore
116 # define a_xssl_X509_get_notAfter X509_get0_notAfter
117 #else
118 # define a_xssl_X509_get_notBefore X509_get_notBefore
119 # define a_xssl_X509_get_notAfter X509_get_notAfter
120 #endif
122 /* X509_STORE_set_flags */
123 #undef a_XSSL_X509_V_ANY
124 #ifndef X509_V_FLAG_NO_ALT_CHAINS
125 # define X509_V_FLAG_NO_ALT_CHAINS -1
126 #else
127 # undef a_XSSL_X509_V_ANY
128 # define a_XSSL_X509_V_ANY
129 #endif
130 #ifndef X509_V_FLAG_NO_CHECK_TIME
131 # define X509_V_FLAG_NO_CHECK_TIME -1
132 #else
133 # undef a_XSSL_X509_V_ANY
134 # define a_XSSL_X509_V_ANY
135 #endif
136 #ifndef X509_V_FLAG_PARTIAL_CHAIN
137 # define X509_V_FLAG_PARTIAL_CHAIN -1
138 #else
139 # undef a_XSSL_X509_V_ANY
140 # define a_XSSL_X509_V_ANY
141 #endif
142 #ifndef X509_V_FLAG_X509_STRICT
143 # define X509_V_FLAG_X509_STRICT -1
144 #else
145 # undef a_XSSL_X509_V_ANY
146 # define a_XSSL_X509_V_ANY
147 #endif
148 #ifndef X509_V_FLAG_TRUSTED_FIRST
149 # define X509_V_FLAG_TRUSTED_FIRST -1
150 #else
151 # undef a_XSSL_X509_V_ANY
152 # define a_XSSL_X509_V_ANY
153 #endif
155 /* Some became meaningless with HAVE_XSSL_OPENSSL>=0x10100 */
156 enum a_xssl_state{
157 a_XSSL_S_INIT = 1<<0,
158 a_XSSL_S_RAND_INIT = 1<<1,
159 a_XSSL_S_EXIT_HDL = 1<<2,
160 a_XSSL_S_CONF_LOAD = 1<<3,
161 a_XSSL_S_ALGO_LOAD = 1<<4,
163 a_XSSL_S_VERIFY_ERROR = 1<<7
166 /* We go for the OpenSSL v1.0.2+ SSL_CONF_CTX if available even if
167 * the library does internally what we'd otherwise do ourselfs.
168 * But eventually we can drop the direct use cases */
169 enum a_xssl_conf_type{
170 a_XSSL_CT_CERTIFICATE,
171 a_XSSL_CT_CIPHER_STRING,
172 a_XSSL_CT_CURVES,
173 a_XSSL_CT_PRIVATE_KEY,
174 a_XSSL_CT_OPTIONS,
175 a_XSSL_CT_PROTOCOL
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;
186 sl_i sp_flag;
188 #endif
190 struct a_xssl_smime_cipher{
191 char const sc_name[8];
192 EVP_CIPHER const *(*sc_fun)(void);
195 struct a_xssl_smime_digest{
196 char const sd_name[8];
197 EVP_MD const *(*sd_fun)(void);
200 struct a_xssl_x509_v_flags{
201 char const xvf_name[20];
202 si32_t xvf_flag;
205 /* Supported SSL/TLS methods: update manual on change! */
207 static struct ssl_method const _ssl_methods[] = { /* TODO obsolete */
208 {"auto", "ALL,-SSLv2"},
209 {"ssl3", "-ALL,SSLv3"},
210 {"tls1", "-ALL,TLSv1"},
211 {"tls1.1", "-ALL,TLSv1.1"},
212 {"tls1.2", "-ALL,TLSv1.2"}
215 /* Update manual on change! */
216 #ifndef HAVE_XSSL_CONF_CTX
217 static struct a_xssl_protocol const a_xssl_protocols[] = {
218 {"ALL", SSL_OP_NO_SSL_MASK},
219 {"TLSv1.2", SSL_OP_NO_TLSv1_2},
220 {"TLSv1.1", SSL_OP_NO_TLSv1_1},
221 {"TLSv1", SSL_OP_NO_TLSv1},
222 {"SSLv3", SSL_OP_NO_SSLv3},
223 {"SSLv2", 0}
225 #endif
227 /* Supported S/MIME cipher algorithms */
228 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers[] = { /* Manual! */
229 #ifndef OPENSSL_NO_AES
230 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_aes_128_cbc /* According to RFC 5751 */
231 {"aes128", &EVP_aes_128_cbc},
232 {"aes256", &EVP_aes_256_cbc},
233 {"aes192", &EVP_aes_192_cbc},
234 #endif
235 #ifndef OPENSSL_NO_DES
236 # ifndef a_XSSL_SMIME_DEFAULT_CIPHER
237 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_des_ede3_cbc
238 # endif
239 {"des3", &EVP_des_ede3_cbc},
240 {"des", &EVP_des_cbc},
241 #endif
243 #ifndef a_XSSL_SMIME_DEFAULT_CIPHER
244 # error Your OpenSSL library does not include the necessary
245 # error cipher algorithms that are required to support S/MIME
246 #endif
248 #ifndef OPENSSL_NO_AES
249 /* TODO obsolete a_xssl_smime_ciphers_obs */
250 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers_obs[] = {
251 {"aes-128", &EVP_aes_128_cbc},
252 {"aes-256", &EVP_aes_256_cbc},
253 {"aes-192", &EVP_aes_192_cbc}
255 #endif
257 /* Supported S/MIME message digest algorithms */
258 static struct a_xssl_smime_digest const a_xssl_smime_digests[] = { /* Manual! */
259 #define a_XSSL_SMIME_DEFAULT_DIGEST EVP_sha1 /* According to RFC 5751 */
260 #define a_XSSL_SMIME_DEFAULT_DIGEST_S "sha1"
261 {"sha1", &EVP_sha1},
262 {"sha256", &EVP_sha256},
263 {"sha512", &EVP_sha512},
264 {"sha384", &EVP_sha384},
265 {"sha224", &EVP_sha224},
266 #ifndef OPENSSL_NO_MD5
267 {"md5", &EVP_md5},
268 #endif
271 /* X509_STORE_set_flags() for *{smime,ssl}-ca-flags* */
272 static struct a_xssl_x509_v_flags const a_xssl_x509_v_flags[] = { /* Manual! */
273 {"no-alt-chains", X509_V_FLAG_NO_ALT_CHAINS},
274 {"no-check-time", X509_V_FLAG_NO_CHECK_TIME},
275 {"partial-chain", X509_V_FLAG_PARTIAL_CHAIN},
276 {"strict", X509_V_FLAG_X509_STRICT},
277 {"trusted-first", X509_V_FLAG_TRUSTED_FIRST},
280 static enum a_xssl_state a_xssl_state;
281 static size_t a_xssl_msgno;
283 static bool_t a_xssl_rand_init(void);
284 #if HAVE_XSSL_OPENSSL < 0x10100
285 # ifdef HAVE_SSL_ALL_ALGORITHMS
286 static void a_xssl__load_algos(void);
287 # define a_xssl_load_algos a_xssl__load_algos
288 # endif
289 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
290 static void a_xssl_atexit(void);
291 # endif
292 #endif
293 #ifndef a_xssl_load_algos
294 # define a_xssl_load_algos() do{;}while(0)
295 #endif
297 static bool_t _ssl_parse_asn1_time(ASN1_TIME const *atp,
298 char *bdat, size_t blen);
299 static int _ssl_verify_cb(int success, X509_STORE_CTX *store);
301 /* *smime-ca-flags*, *ssl-ca-flags* */
302 static void a_xssl_ca_flags(X509_STORE *store, char const *flags);
304 /* SSL_CTX configuration */
305 static void * _ssl_conf_setup(SSL_CTX *ctxp);
306 static bool_t _ssl_conf(void *confp, enum a_xssl_conf_type ct,
307 char const *value);
308 static bool_t _ssl_conf_finish(void **confp, bool_t error);
310 static bool_t _ssl_load_verifications(SSL_CTX *ctxp);
312 static enum okay ssl_check_host(struct sock *sp, struct url const *urlp);
314 static int smime_verify(struct message *m, int n,
315 n_XSSL_STACKOF(X509) *chain, X509_STORE *store);
316 static EVP_CIPHER const * _smime_cipher(char const *name);
317 static int ssl_password_cb(char *buf, int size, int rwflag,
318 void *userdata);
319 static FILE * smime_sign_cert(char const *xname, char const *xname2,
320 bool_t dowarn, char const **match);
321 static char const * _smime_sign_include_certs(char const *name);
322 static bool_t _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
323 char const *cfiles, char const *addr);
324 static EVP_MD const * _smime_sign_digest(char const *name,
325 char const **digname);
326 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
327 static enum okay load_crl1(X509_STORE *store, char const *name);
328 #endif
329 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
331 static bool_t
332 a_xssl_rand_init(void){
333 char const *cp, *x;
334 bool_t rv;
335 NYD_ENTER;
337 rv = FAL0;
339 /* Shall use some external daemon? */ /* TODO obsolete *ssl_rand_egd* */
340 if((cp = ok_vlook(ssl_rand_egd)) != NULL){ /* TODO no one supports it now! */
341 n_OBSOLETE(_("all *SSL libraries removed *ssl-rand-egd* support"));
342 #ifdef HAVE_XSSL_RAND_EGD
343 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) != NULL &&
344 RAND_egd(cp = x) != -1){
345 rv = TRU1;
346 goto jleave;
348 n_err(_("*ssl_rand_egd* daemon at %s not available\n"),
349 n_shexp_quote_cp(cp, FAL0));
350 #else
351 if(n_poption & n_PO_D_VV)
352 n_err(_("*ssl_rand_egd* (%s): unsupported by SSL library\n"),
353 n_shexp_quote_cp(cp, FAL0));
354 #endif
357 /* Prefer possible user setting */
358 if((cp = ok_vlook(ssl_rand_file)) != NULL){
359 x = NULL;
360 if(*cp != '\0'){
361 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
362 n_err(_("*ssl-rand-file*: filename expansion of %s failed\n"),
363 n_shexp_quote_cp(cp, FAL0));
365 cp = x;
368 /* If the SSL PRNG is initialized don't put any more effort in this if the
369 * user defined entropy isn't usable */
370 if(cp == NULL){
371 if(RAND_status()){
372 rv = TRU1;
373 goto jleave;
376 if((cp = RAND_file_name(salloc(PATH_MAX), PATH_MAX)) == NULL){
377 n_err(_("*ssl-rand-file*: no SSL entropy file, can't seed PRNG\n"));
378 goto jleave;
382 if(RAND_load_file(cp, a_XSSL_RAND_LOAD_FILE_MAXBYTES) != -1){
383 for(x = (char*)-1;;){
384 RAND_seed(n_random_create_cp(32, NULL), 32);
385 if((rv = (RAND_status() != 0)))
386 break;
387 if((x = (char*)((uintptr_t)x >> 1)) == NULL){
388 n_err(_("*ssl-rand-file*: can't seed SSL PRNG with entropy\n"));
389 goto jleave;
393 if(RAND_write_file(cp) == -1)
394 n_err(_("*ssl-rand-file*: writing entropy to %s failed\n"),
395 n_shexp_quote_cp(cp, FAL0));
396 }else
397 n_err(_("*ssl-rand-file*: %s cannot be loaded\n"),
398 n_shexp_quote_cp(cp, FAL0));
399 jleave:
400 NYD_LEAVE;
401 return rv;
404 static void
405 a_xssl_init(void)
407 #ifdef HAVE_XSSL_CONFIG
408 char const *cp;
409 #endif
410 NYD_ENTER;
412 if(!(a_xssl_state & a_XSSL_S_INIT)){
413 #if HAVE_XSSL_OPENSSL >= 0x10100
414 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS |
415 OPENSSL_INIT_LOAD_CRYPTO_STRINGS
416 # ifdef HAVE_SSL_ALL_ALGORITHMS
417 | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS
418 # endif
419 , NULL);
420 # ifdef HAVE_SSL_ALL_ALGORITHMS
421 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
422 # endif
423 #else
424 SSL_load_error_strings();
425 SSL_library_init();
426 #endif
427 a_xssl_state |= a_XSSL_S_INIT;
430 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
431 #ifdef HAVE_XSSL_CONFIG
432 if(!(a_xssl_state & a_XSSL_S_CONF_LOAD) &&
433 (cp = ok_vlook(ssl_config_file)) != NULL){
434 ul_i flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
436 if(*cp == '\0'){
437 cp = NULL;
438 flags = 0;
440 if(CONF_modules_load_file(cp, n_uagent, flags) == 1){
441 a_xssl_state |= a_XSSL_S_CONF_LOAD;
442 # if HAVE_XSSL_OPENSSL < 0x10100
443 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
444 a_xssl_state |= a_XSSL_S_EXIT_HDL;
445 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
447 # endif
448 }else
449 ssl_gen_err(_("Ignoring CONF_modules_load_file() load error"));
451 #endif
453 if(!(a_xssl_state & a_XSSL_S_RAND_INIT) && a_xssl_rand_init())
454 a_xssl_state |= a_XSSL_S_RAND_INIT;
455 NYD_LEAVE;
458 #if HAVE_XSSL_OPENSSL < 0x10100
459 # ifdef HAVE_SSL_ALL_ALGORITHMS
460 static void
461 a_xssl__load_algos(void){
462 NYD2_ENTER;
463 if(!(a_xssl_state & a_XSSL_S_ALGO_LOAD)){
464 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
465 OpenSSL_add_all_algorithms();
467 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
468 a_xssl_state |= a_XSSL_S_EXIT_HDL;
469 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
472 NYD2_LEAVE;
474 # endif
476 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
477 static void
478 a_xssl_atexit(void){
479 NYD2_ENTER;
480 # ifdef HAVE_XSSL_CONFIG
481 if(a_xssl_state & a_XSSL_S_CONF_LOAD)
482 CONF_modules_free();
483 # endif
485 # ifdef HAVE_SSL_ALL_ALGORITHMS
486 if(a_xssl_state & a_XSSL_S_ALGO_LOAD)
487 EVP_cleanup();
488 # endif
489 NYD2_LEAVE;
491 # endif
492 #endif /* HAVE_XSSL_OPENSSL < 0x10100 */
494 static bool_t
495 _ssl_parse_asn1_time(ASN1_TIME const *atp, char *bdat, size_t blen)
497 BIO *mbp;
498 char *mcp;
499 long l;
500 NYD_ENTER;
502 mbp = BIO_new(BIO_s_mem());
504 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
505 snprintf(bdat, blen, "%.*s", (int)l, mcp);
506 else {
507 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
508 /*is (int)*/atp->length, (char const*)atp->data);
509 mcp = NULL;
512 BIO_free(mbp);
513 NYD_LEAVE;
514 return (mcp != NULL);
517 static int
518 _ssl_verify_cb(int success, X509_STORE_CTX *store)
520 char data[256];
521 X509 *cert;
522 int rv = TRU1;
523 NYD_ENTER;
525 if (success && !(n_poption & n_PO_D_V))
526 goto jleave;
528 if (a_xssl_msgno != 0) {
529 n_err(_("Message %lu:\n"), (ul_i)a_xssl_msgno);
530 a_xssl_msgno = 0;
532 n_err(_(" Certificate depth %d %s\n"),
533 X509_STORE_CTX_get_error_depth(store), (success ? n_empty : V_(n_error)));
535 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
536 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
537 n_err(_(" subject = %s\n"), data);
539 _ssl_parse_asn1_time(a_xssl_X509_get_notBefore(cert), data, sizeof data);
540 n_err(_(" notBefore = %s\n"), data);
542 _ssl_parse_asn1_time(a_xssl_X509_get_notAfter(cert), data, sizeof data);
543 n_err(_(" notAfter = %s\n"), data);
545 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
546 n_err(_(" issuer = %s\n"), data);
549 if (!success) {
550 int err = X509_STORE_CTX_get_error(store);
552 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
553 a_xssl_state |= a_XSSL_S_VERIFY_ERROR;
556 if (!success && ssl_verify_decide() != OKAY)
557 rv = FAL0;
558 jleave:
559 NYD_LEAVE;
560 return rv;
563 static void
564 a_xssl_ca_flags(X509_STORE *store, char const *flags){
565 NYD2_ENTER;
566 if(flags != NULL){
567 char *iolist, *cp;
569 iolist = savestr(flags);
570 jouter:
571 while((cp = n_strsep(&iolist, ',', TRU1)) != NULL){
572 struct a_xssl_x509_v_flags const *xvfp;
574 for(xvfp = &a_xssl_x509_v_flags[0];
575 xvfp < &a_xssl_x509_v_flags[n_NELEM(a_xssl_x509_v_flags)];
576 ++xvfp)
577 if(!asccasecmp(cp, xvfp->xvf_name)){
578 if(xvfp->xvf_flag != -1){
579 #ifdef a_XSSL_X509_V_ANY
580 X509_STORE_set_flags(store, xvfp->xvf_flag);
581 #endif
582 }else if(n_poption & n_PO_D_V)
583 n_err(_("*{smime,ssl}-ca-flags*: "
584 "directive not supported: %s\n"), cp);
585 goto jouter;
587 n_err(_("*{smime,ssl}-ca-flags*: invalid directive: %s\n"), cp);
590 NYD2_LEAVE;
593 #ifdef HAVE_XSSL_CONF_CTX
594 static void *
595 _ssl_conf_setup(SSL_CTX *ctxp)
597 SSL_CONF_CTX *sccp;
598 NYD_ENTER;
600 if ((sccp = SSL_CONF_CTX_new()) != NULL) {
601 SSL_CONF_CTX_set_flags(sccp,
602 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
603 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
605 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
606 } else
607 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
609 NYD_LEAVE;
610 return sccp;
613 static bool_t
614 _ssl_conf(void *confp, enum a_xssl_conf_type ct, char const *value)
616 int rv;
617 char const *cmsg;
618 SSL_CONF_CTX *sccp = (SSL_CONF_CTX*)confp;
619 NYD_ENTER;
621 switch (ct) {
622 case a_XSSL_CT_CERTIFICATE:
623 cmsg = "ssl-cert";
624 rv = SSL_CONF_cmd(sccp, "Certificate", value);
625 break;
626 case a_XSSL_CT_CIPHER_STRING:
627 cmsg = "ssl-cipher-list";
628 rv = SSL_CONF_cmd(sccp, "CipherString", value);
629 break;
630 case a_XSSL_CT_PRIVATE_KEY:
631 cmsg = "ssl-key";
632 rv = SSL_CONF_cmd(sccp, "PrivateKey", value);
633 break;
634 default:
635 case a_XSSL_CT_OPTIONS:
636 cmsg = "ssl-options";
637 rv = SSL_CONF_cmd(sccp, "Options", "Bugs");
638 break;
639 case a_XSSL_CT_PROTOCOL:
640 cmsg = "ssl-protocol";
641 rv = SSL_CONF_cmd(sccp, "Protocol", value);
642 break;
643 case a_XSSL_CT_CURVES:
644 cmsg = "ssl-curves";
645 rv = SSL_CONF_cmd(sccp, "Curves", value);
646 break;
649 if (rv == 2)
650 rv = 0;
651 else {
652 if (rv == 0)
653 ssl_gen_err(_("SSL_CONF_CTX_cmd() failed for *%s*"), cmsg);
654 else
655 n_err(_("%s: *%s* implementation error, please report this\n"),
656 n_uagent, cmsg);
657 rv = 1;
660 NYD_LEAVE;
661 return (rv == 0);
664 static bool_t
665 _ssl_conf_finish(void **confp, bool_t error)
667 SSL_CONF_CTX **sccp = (SSL_CONF_CTX**)confp;
668 bool_t rv;
669 NYD_ENTER;
671 if (!(rv = error))
672 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
674 SSL_CONF_CTX_free(*sccp);
676 *sccp = NULL;
677 NYD_LEAVE;
678 return rv;
681 #else /* HAVE_XSSL_CONF_CTX */
682 static void *
683 _ssl_conf_setup(SSL_CTX* ctxp)
685 return ctxp;
688 static bool_t
689 _ssl_conf(void *confp, enum a_xssl_conf_type ct, char const *value){
690 SSL_CTX *ctxp;
691 NYD2_ENTER;
693 ctxp = confp;
695 switch(ct){
696 case a_XSSL_CT_CERTIFICATE:
697 if(SSL_CTX_use_certificate_chain_file(ctxp, value) != 1){
698 ssl_gen_err(_("Can't load certificate from file %s\n"),
699 n_shexp_quote_cp(value, FAL0));
700 confp = NULL;
702 break;
703 case a_XSSL_CT_CIPHER_STRING:
704 if(SSL_CTX_set_cipher_list(ctxp, value) != 1){
705 ssl_gen_err(_("Invalid cipher string: %s\n"), value);
706 confp = NULL;
708 break;
709 case a_XSSL_CT_CURVES:
710 #ifdef SSL_CTRL_SET_CURVES_LIST
711 if(SSL_CTX_set1_curves_list(ctxp, value) != 1){
712 ssl_gen_err(_("Invalid curves string: %s\n"), value);
713 confp = NULL;
715 #else
716 n_err(_("*ssl-curves*: as such not supported\n"));
717 confp = NULL;
718 #endif
719 break;
720 case a_XSSL_CT_PRIVATE_KEY:
721 if(SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1){
722 ssl_gen_err(_("Can't load private key from file %s\n"),
723 n_shexp_quote_cp(value, FAL0));
724 confp = NULL;
726 break;
727 case a_XSSL_CT_OPTIONS:
728 /* "Options"="Bugs" TODO *ssl-options* */
729 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
730 break;
731 case a_XSSL_CT_PROTOCOL:{
732 char *iolist, *cp, addin;
733 size_t i;
734 sl_i opts = 0;
736 confp = NULL;
737 for(iolist = cp = savestr(value);
738 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;){
739 if(*cp == '\0'){
740 n_err(_("*ssl-protocol*: empty arguments are not supported\n"));
741 goto jleave;
744 addin = TRU1;
745 switch(cp[0]){
746 case '-': addin = FAL0; /* FALLTHRU */
747 case '+': ++cp; /* FALLTHRU */
748 default : break;
751 for(i = 0;;){
752 if(!asccasecmp(cp, a_xssl_protocols[i].sp_name)){
753 /* We need to inverse the meaning of the _NO_s */
754 if(!addin)
755 opts |= a_xssl_protocols[i].sp_flag;
756 else
757 opts &= ~a_xssl_protocols[i].sp_flag;
758 break;
760 if(++i < n_NELEM(a_xssl_protocols))
761 continue;
762 n_err(_("*ssl-protocol*: unsupported value: %s\n"), cp);
763 goto jleave;
766 confp = ctxp;
767 SSL_CTX_set_options(ctxp, opts);
768 } break;
770 jleave:
771 NYD2_LEAVE;
772 return (confp != NULL);
775 static bool_t
776 _ssl_conf_finish(void **confp, bool_t error)
778 n_UNUSED(confp);
779 n_UNUSED(error);
780 return TRU1;
782 #endif /* !HAVE_XSSL_CONF_CTX */
784 static bool_t
785 _ssl_load_verifications(SSL_CTX *ctxp)
787 char *ca_dir, *ca_file;
788 X509_STORE *store;
789 bool_t rv = FAL0;
790 NYD_ENTER;
792 if (ssl_verify_level == SSL_VERIFY_IGNORE) {
793 rv = TRU1;
794 goto jleave;
797 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
798 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
799 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
800 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
802 if ((ca_dir != NULL || ca_file != NULL) &&
803 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1) {
804 char const *m1, *m2, *m3;
806 if (ca_dir != NULL) {
807 m1 = ca_dir;
808 m2 = (ca_file != NULL) ? _(" or ") : n_empty;
809 } else
810 m1 = m2 = n_empty;
811 m3 = (ca_file != NULL) ? ca_file : n_empty;
812 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
813 goto jleave;
816 /* C99 */{
817 bool_t xv15;
819 if((xv15 = ok_blook(ssl_no_default_ca)))
820 n_OBSOLETE(_("please use *ssl-ca-no-defaults*, "
821 "not *ssl-no-default-ca*"));
822 if(!ok_blook(ssl_ca_no_defaults) && !xv15 &&
823 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
824 ssl_gen_err(_("Error loading built-in default CA locations\n"));
825 goto jleave;
829 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
830 a_xssl_msgno = 0;
831 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
832 store = SSL_CTX_get_cert_store(ctxp);
833 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
834 a_xssl_ca_flags(store, ok_vlook(ssl_ca_flags));
836 rv = TRU1;
837 jleave:
838 NYD_LEAVE;
839 return rv;
842 static enum okay
843 ssl_check_host(struct sock *sp, struct url const *urlp)
845 char data[256];
846 X509 *cert;
847 n_XSSL_STACKOF(GENERAL_NAME) *gens;
848 GENERAL_NAME *gen;
849 X509_NAME *subj;
850 enum okay rv = STOP;
851 NYD_ENTER;
853 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
854 n_err(_("No certificate from: %s\n"), urlp->url_h_p.s);
855 goto jleave;
858 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
859 if (gens != NULL) {
860 int i;
862 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
863 gen = sk_GENERAL_NAME_value(gens, i);
864 if (gen->type == GEN_DNS) {
865 if (n_poption & n_PO_D_V)
866 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
867 urlp->url_host.s, (char*)gen->d.ia5->data);
868 rv = rfc2595_hostname_match(urlp->url_host.s,
869 (char*)gen->d.ia5->data);
870 if (rv == OKAY)
871 goto jdone;
876 if ((subj = X509_get_subject_name(cert)) != NULL &&
877 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
878 > 0) {
879 data[sizeof data - 1] = '\0';
880 if (n_poption & n_PO_D_V)
881 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
882 urlp->url_host.s, data);
883 rv = rfc2595_hostname_match(urlp->url_host.s, data);
886 jdone:
887 X509_free(cert);
888 jleave:
889 NYD_LEAVE;
890 return rv;
893 static int
894 smime_verify(struct message *m, int n, n_XSSL_STACKOF(X509) *chain,
895 X509_STORE *store)
897 char data[LINESIZE], *sender, *to, *cc, *cnttype;
898 int rv, c, i, j;
899 struct message *x;
900 FILE *fp, *ip;
901 off_t size;
902 BIO *fb, *pb;
903 PKCS7 *pkcs7;
904 n_XSSL_STACKOF(X509) *certs;
905 n_XSSL_STACKOF(GENERAL_NAME) *gens;
906 X509 *cert;
907 X509_NAME *subj;
908 GENERAL_NAME *gen;
909 NYD_ENTER;
911 rv = 1;
912 fp = NULL;
913 fb = pb = NULL;
914 pkcs7 = NULL;
915 certs = NULL;
916 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
917 a_xssl_msgno = (size_t)n;
919 for (;;) {
920 sender = getsender(m);
921 to = hfield1("to", m);
922 cc = hfield1("cc", m);
923 cnttype = hfield1("content-type", m);
925 #undef _X
926 #undef _Y
927 #define _X (sizeof("application/") -1)
928 #define _Y(X) X, sizeof(X) -1
929 if (cnttype && is_asccaseprefix("application/", cnttype) &&
930 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
931 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
932 #undef _Y
933 #undef _X
934 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
935 goto jleave;
936 if (x != (struct message*)-1) {
937 m = x;
938 continue;
942 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
943 goto jleave;
944 size = m->m_size;
945 break;
948 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
949 NULL) {
950 n_perr(_("tempfile"), 0);
951 goto jleave;
953 while (size-- > 0) {
954 c = getc(ip);
955 putc(c, fp);
957 fflush_rewind(fp);
959 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
960 ssl_gen_err(_(
961 "Error creating BIO verification object for message %d"), n);
962 goto jleave;
965 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
966 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
967 goto jleave;
969 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
970 ssl_gen_err(_("Error verifying message %d"), n);
971 goto jleave;
974 if (sender == NULL) {
975 n_err(_("Warning: Message %d has no sender\n"), n);
976 rv = 0;
977 goto jleave;
980 certs = PKCS7_get0_signers(pkcs7, chain, 0);
981 if (certs == NULL) {
982 n_err(_("No certificates found in message %d\n"), n);
983 goto jleave;
986 for (i = 0; i < sk_X509_num(certs); ++i) {
987 cert = sk_X509_value(certs, i);
988 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
989 if (gens != NULL) {
990 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
991 gen = sk_GENERAL_NAME_value(gens, j);
992 if (gen->type == GEN_EMAIL) {
993 if (n_poption & n_PO_D_V)
994 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
995 sender, (char*)gen->d.ia5->data);
996 if (!asccasecmp((char*)gen->d.ia5->data, sender))
997 goto jfound;
1002 if ((subj = X509_get_subject_name(cert)) != NULL &&
1003 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
1004 data, sizeof data) > 0) {
1005 data[sizeof data -1] = '\0';
1006 if (n_poption & n_PO_D_V)
1007 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
1008 sender, data);
1009 if (!asccasecmp(data, sender))
1010 goto jfound;
1013 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
1014 goto jleave;
1015 jfound:
1016 rv = ((a_xssl_state & a_XSSL_S_VERIFY_ERROR) != 0);
1017 if (!rv)
1018 fprintf(n_stdout, _("Message %d was verified successfully\n"), n);
1019 jleave:
1020 if (certs != NULL)
1021 sk_X509_free(certs);
1022 if (pb != NULL)
1023 BIO_free(pb);
1024 if (fb != NULL)
1025 BIO_free(fb);
1026 if (pkcs7 != NULL)
1027 PKCS7_free(pkcs7);
1028 if (fp != NULL)
1029 Fclose(fp);
1030 NYD_LEAVE;
1031 return rv;
1034 static EVP_CIPHER const *
1035 _smime_cipher(char const *name)
1037 EVP_CIPHER const *cipher;
1038 char *vn;
1039 char const *cp;
1040 size_t i;
1041 NYD_ENTER;
1043 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
1044 snprintf(vn, (int)i, "smime-cipher-%s", name);
1045 cp = n_var_vlook(vn, FAL0);
1046 ac_free(vn);
1048 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
1049 cipher = a_XSSL_SMIME_DEFAULT_CIPHER();
1050 goto jleave;
1052 cipher = NULL;
1054 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers); ++i)
1055 if (!asccasecmp(a_xssl_smime_ciphers[i].sc_name, cp)) {
1056 cipher = (*a_xssl_smime_ciphers[i].sc_fun)();
1057 goto jleave;
1059 #ifndef OPENSSL_NO_AES
1060 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers_obs); ++i) /* TODO obsolete */
1061 if (!asccasecmp(a_xssl_smime_ciphers_obs[i].sc_name, cp)) {
1062 n_OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
1063 cipher = (*a_xssl_smime_ciphers_obs[i].sc_fun)();
1064 goto jleave;
1066 #endif
1068 /* Not a built-in algorithm, but we may have dynamic support for more */
1069 #ifdef HAVE_SSL_ALL_ALGORITHMS
1070 a_xssl_load_algos();
1071 if((cipher = EVP_get_cipherbyname(cp)) != NULL)
1072 goto jleave;
1073 #endif
1075 n_err(_("Invalid S/MIME cipher(s): %s\n"), cp);
1076 jleave:
1077 NYD_LEAVE;
1078 return cipher;
1081 static int
1082 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
1084 char *pass;
1085 size_t len;
1086 NYD_ENTER;
1087 n_UNUSED(rwflag);
1088 n_UNUSED(userdata);
1090 /* New-style */
1091 if(userdata != NULL){
1092 struct url url;
1093 struct ccred cred;
1095 if(url_parse(&url, CPROTO_CCRED, userdata)){
1096 if(ccred_lookup(&cred, &url)){
1097 ssize_t slen;
1099 if((slen = n_strscpy(buf, cred.cc_pass.s, size)) >= 0){
1100 size = (int)slen;
1101 goto jleave;
1104 size = 0;
1105 goto jleave;
1109 /* Old-style */
1110 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
1111 len = strlen(pass);
1112 if (UICMP(z, len, >=, size))
1113 len = size -1;
1114 memcpy(buf, pass, len);
1115 buf[len] = '\0';
1116 size = (int)len;
1117 } else
1118 size = 0;
1119 jleave:
1120 NYD_LEAVE;
1121 return size;
1124 static FILE *
1125 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn,
1126 char const **match)
1128 char *vn;
1129 int vs;
1130 struct name *np;
1131 char const *name = xname, *name2 = xname2, *cp;
1132 FILE *fp = NULL;
1133 NYD_ENTER;
1135 jloop:
1136 if (name) {
1137 np = lextract(name, GTO | GSKIN);
1138 while (np != NULL) {
1139 /* This needs to be more intelligent since it will currently take the
1140 * first name for which a private key is available regardless of
1141 * whether it is the right one for the message */
1142 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1143 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
1144 cp = n_var_vlook(vn, FAL0);
1145 ac_free(vn);
1146 if (cp != NULL) {
1147 if (match != NULL)
1148 *match = np->n_name;
1149 goto jopen;
1151 np = np->n_flink;
1153 if (name2 != NULL) {
1154 name = name2;
1155 name2 = NULL;
1156 goto jloop;
1160 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
1161 goto jerr;
1162 if(match != NULL)
1163 *match = NULL;
1164 jopen:
1165 if ((cp = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
1166 goto jleave;
1167 if ((fp = Fopen(cp, "r")) == NULL)
1168 n_perr(cp, 0);
1169 jleave:
1170 NYD_LEAVE;
1171 return fp;
1172 jerr:
1173 if (dowarn)
1174 n_err(_("Could not find a certificate for %s%s%s\n"),
1175 xname, (xname2 != NULL ? _("or ") : n_empty),
1176 (xname2 != NULL ? xname2 : n_empty));
1177 goto jleave;
1180 static char const *
1181 _smime_sign_include_certs(char const *name)
1183 char const *rv;
1184 NYD_ENTER;
1186 /* See comments in smime_sign_cert() for algorithm pitfalls */
1187 if (name != NULL) {
1188 struct name *np;
1190 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1191 int vs;
1192 char *vn;
1194 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1195 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1196 rv = n_var_vlook(vn, FAL0);
1197 ac_free(vn);
1198 if (rv != NULL)
1199 goto jleave;
1202 rv = ok_vlook(smime_sign_include_certs);
1203 jleave:
1204 NYD_LEAVE;
1205 return rv;
1208 static bool_t
1209 _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
1210 char const *cfiles, char const *addr)
1212 X509 *tmp;
1213 FILE *fp;
1214 char *nfield, *cfield, *x;
1215 NYD_ENTER;
1217 *chain = sk_X509_new_null();
1219 for (nfield = savestr(cfiles);
1220 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1221 if ((x = fexpand(cfield, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1222 (fp = Fopen(cfield = x, "r")) == NULL) {
1223 n_perr(cfiles, 0);
1224 goto jerr;
1226 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, n_UNCONST(addr))
1227 ) == NULL) {
1228 ssl_gen_err(_("Error reading certificate from %s"),
1229 n_shexp_quote_cp(cfield, FAL0));
1230 Fclose(fp);
1231 goto jerr;
1233 sk_X509_push(*chain, tmp);
1234 Fclose(fp);
1237 if (sk_X509_num(*chain) == 0) {
1238 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1239 goto jerr;
1241 jleave:
1242 NYD_LEAVE;
1243 return (*chain != NULL);
1244 jerr:
1245 sk_X509_pop_free(*chain, X509_free);
1246 *chain = NULL;
1247 goto jleave;
1250 static EVP_MD const *
1251 _smime_sign_digest(char const *name, char const **digname)
1253 EVP_MD const *digest;
1254 char const *cp;
1255 size_t i;
1256 NYD_ENTER;
1258 /* See comments in smime_sign_cert() for algorithm pitfalls */
1259 if (name != NULL) {
1260 struct name *np;
1262 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1263 int vs;
1264 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1265 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1266 cp = n_var_vlook(vn, FAL0);
1267 ac_free(vn);
1268 if (cp != NULL)
1269 goto jhave_name;
1273 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1274 digest = a_XSSL_SMIME_DEFAULT_DIGEST();
1275 *digname = a_XSSL_SMIME_DEFAULT_DIGEST_S;
1276 goto jleave;
1279 jhave_name:
1280 i = strlen(cp);
1281 { char *x = salloc(i +1);
1282 i_strcpy(x, cp, i +1);
1283 cp = x;
1285 *digname = cp;
1287 for (i = 0; i < n_NELEM(a_xssl_smime_digests); ++i)
1288 if (!asccasecmp(a_xssl_smime_digests[i].sd_name, cp)) {
1289 digest = (*a_xssl_smime_digests[i].sd_fun)();
1290 goto jleave;
1293 /* Not a built-in algorithm, but we may have dynamic support for more */
1294 #ifdef HAVE_SSL_ALL_ALGORITHMS
1295 a_xssl_load_algos();
1296 if((digest = EVP_get_digestbyname(cp)) != NULL)
1297 goto jleave;
1298 #endif
1300 n_err(_("Invalid message digest: %s\n"), cp);
1301 digest = NULL;
1302 jleave:
1303 NYD_LEAVE;
1304 return digest;
1307 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1308 static enum okay
1309 load_crl1(X509_STORE *store, char const *name)
1311 X509_LOOKUP *lookup;
1312 enum okay rv = STOP;
1313 NYD_ENTER;
1315 if (n_poption & n_PO_D_V)
1316 n_err(_("Loading CRL from %s\n"), n_shexp_quote_cp(name, FAL0));
1317 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1318 ssl_gen_err(_("Error creating X509 lookup object"));
1319 goto jleave;
1321 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1322 ssl_gen_err(_("Error loading CRL from %s"), n_shexp_quote_cp(name, FAL0));
1323 goto jleave;
1325 rv = OKAY;
1326 jleave:
1327 NYD_LEAVE;
1328 return rv;
1330 #endif /* new OpenSSL */
1332 static enum okay
1333 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1335 char *crl_file, *crl_dir;
1336 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1337 DIR *dirp;
1338 struct dirent *dp;
1339 char *fn = NULL;
1340 int fs = 0, ds, es;
1341 #endif
1342 enum okay rv = STOP;
1343 NYD_ENTER;
1345 if ((crl_file = n_var_oklook(fok)) != NULL) {
1346 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1347 if ((crl_file = fexpand(crl_file, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1348 load_crl1(store, crl_file) != OKAY)
1349 goto jleave;
1350 #else
1351 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1352 goto jleave;
1353 #endif
1356 if ((crl_dir = n_var_oklook(dok)) != NULL) {
1357 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1358 char *x;
1359 if ((x = fexpand(crl_dir, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1360 (dirp = opendir(crl_dir = x)) == NULL) {
1361 n_perr(crl_dir, 0);
1362 goto jleave;
1365 ds = strlen(crl_dir);
1366 fn = smalloc(fs = ds + 20);
1367 memcpy(fn, crl_dir, ds);
1368 fn[ds] = '/';
1369 while ((dp = readdir(dirp)) != NULL) {
1370 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1371 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1372 continue;
1373 if (dp->d_name[0] == '.')
1374 continue;
1375 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1376 fn = srealloc(fn, fs = ds + es + 20);
1377 memcpy(fn + ds + 1, dp->d_name, es + 1);
1378 if (load_crl1(store, fn) != OKAY) {
1379 closedir(dirp);
1380 free(fn);
1381 goto jleave;
1384 closedir(dirp);
1385 free(fn);
1386 #else /* old OpenSSL */
1387 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1388 goto jleave;
1389 #endif
1391 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1392 if (crl_file || crl_dir)
1393 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1394 X509_V_FLAG_CRL_CHECK_ALL);
1395 #endif
1396 rv = OKAY;
1397 jleave:
1398 NYD_LEAVE;
1399 return rv;
1402 FL enum okay
1403 ssl_open(struct url const *urlp, struct sock *sp)
1405 SSL_CTX *ctxp;
1406 void *confp;
1407 char const *cp, *cp_base;
1408 size_t i;
1409 enum okay rv = STOP;
1410 NYD_ENTER;
1412 a_xssl_init();
1414 ssl_set_verify_level(urlp);
1416 if ((ctxp = SSL_CTX_new(n_XSSL_CLIENT_METHOD())) == NULL) {
1417 ssl_gen_err(_("SSL_CTX_new() failed"));
1418 goto jleave;
1421 /* Available with OpenSSL 0.9.6 or later */
1422 #ifdef SSL_MODE_AUTO_RETRY
1423 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1424 #endif
1426 if ((confp = _ssl_conf_setup(ctxp)) == NULL)
1427 goto jerr0;
1429 /* TODO obsolete Check for *ssl-method*, warp to a *ssl-protocol* value */
1430 if ((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL) {
1431 n_OBSOLETE(_("please use *ssl-protocol* instead of *ssl-method*"));
1432 if (n_poption & n_PO_D_V)
1433 n_err(_("*ssl-method*: %s\n"), cp);
1434 for (i = 0;;) {
1435 if (!asccasecmp(_ssl_methods[i].sm_name, cp)) {
1436 cp = _ssl_methods[i].sm_map;
1437 break;
1439 if (++i == n_NELEM(_ssl_methods)) {
1440 n_err(_("Unsupported TLS/SSL method: %s\n"), cp);
1441 goto jerr1;
1445 /* *ssl-protocol* */
1446 if ((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL) {
1447 if (n_poption & n_PO_D_V)
1448 n_err(_("*ssl-protocol*: %s\n"), cp_base);
1449 cp = cp_base;
1451 cp = (cp != NULL ? savecatsep(cp, ',', n_XSSL_DISABLED_PROTOCOLS)
1452 : n_XSSL_DISABLED_PROTOCOLS);
1453 if (!_ssl_conf(confp, a_XSSL_CT_PROTOCOL, cp))
1454 goto jerr1;
1456 /* *ssl-cert* */
1457 if ((cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL) {
1458 if (n_poption & n_PO_D_V)
1459 n_err(_("*ssl-cert* %s\n"), n_shexp_quote_cp(cp, FAL0));
1460 if ((cp_base = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL) {
1461 n_err(_("*ssl-cert* value expansion failed: %s\n"),
1462 n_shexp_quote_cp(cp, FAL0));
1463 goto jerr1;
1465 cp = cp_base;
1466 if (!_ssl_conf(confp, a_XSSL_CT_CERTIFICATE, cp))
1467 goto jerr1;
1469 /* *ssl-key* */
1470 if ((cp_base = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL) {
1471 if (n_poption & n_PO_D_V)
1472 n_err(_("*ssl-key* %s\n"), n_shexp_quote_cp(cp_base, FAL0));
1473 if ((cp = fexpand(cp_base, FEXP_LOCAL | FEXP_NOPROTO)) == NULL) {
1474 n_err(_("*ssl-key* value expansion failed: %s\n"),
1475 n_shexp_quote_cp(cp_base, FAL0));
1476 goto jerr1;
1479 if (!_ssl_conf(confp, a_XSSL_CT_PRIVATE_KEY, cp))
1480 goto jerr1;
1483 if ((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL &&
1484 !_ssl_conf(confp, a_XSSL_CT_CIPHER_STRING, cp))
1485 goto jerr1;
1486 if ((cp = xok_vlook(ssl_curves, urlp, OXM_ALL)) != NULL &&
1487 !_ssl_conf(confp, a_XSSL_CT_CURVES, cp))
1488 goto jerr1;
1490 if (!_ssl_load_verifications(ctxp))
1491 goto jerr1;
1493 if (!_ssl_conf(confp, a_XSSL_CT_OPTIONS, NULL)) /* TODO *ssl-options* */
1494 goto jerr1;
1496 /* Done with context setup, create our new per-connection structure */
1497 if (!_ssl_conf_finish(&confp, FAL0))
1498 goto jerr0;
1500 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1501 ssl_gen_err(_("SSL_new() failed"));
1502 goto jerr0;
1505 /* Try establish SNI extension; even though this is a TLS extension the
1506 * protocol isn't checked once the host name is set, and therefore i've
1507 * refrained from changing so much code just to check out whether we are
1508 * using SSLv3, which should become rarer and rarer */
1509 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1510 if((urlp->url_flags & n_URL_TLS_MASK) &&
1511 (urlp->url_flags & n_URL_HOST_IS_NAME)){
1512 if(!SSL_set_tlsext_host_name(sp->s_ssl, urlp->url_host.s) &&
1513 (n_poption & n_PO_D_V))
1514 n_err(_("Hostname cannot be used with ServerNameIndication "
1515 "TLS extension: %s\n"),
1516 n_shexp_quote_cp(urlp->url_host.s, FAL0));
1518 #endif
1520 SSL_set_fd(sp->s_ssl, sp->s_fd);
1522 if (SSL_connect(sp->s_ssl) < 0) {
1523 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1524 goto jerr2;
1527 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1528 if (ssl_check_host(sp, urlp) != OKAY) {
1529 n_err(_("Host certificate does not match: %s\n"), urlp->url_h_p.s);
1530 if (ssl_verify_decide() != OKAY)
1531 goto jerr2;
1535 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1536 * and free it right now -- it is reference counted by sp->s_ssl.. */
1537 SSL_CTX_free(ctxp);
1538 sp->s_use_ssl = 1;
1539 rv = OKAY;
1540 jleave:
1541 NYD_LEAVE;
1542 return rv;
1543 jerr2:
1544 SSL_free(sp->s_ssl);
1545 sp->s_ssl = NULL;
1546 jerr1:
1547 if (confp != NULL)
1548 _ssl_conf_finish(&confp, TRU1);
1549 jerr0:
1550 SSL_CTX_free(ctxp);
1551 goto jleave;
1554 FL void
1555 ssl_gen_err(char const *fmt, ...)
1557 va_list ap;
1558 NYD_ENTER;
1560 va_start(ap, fmt);
1561 n_verr(fmt, ap);
1562 va_end(ap);
1564 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1565 NYD_LEAVE;
1568 FL int
1569 c_verify(void *vp)
1571 int *msgvec = vp, *ip, ec = 0, rv = 1;
1572 X509_STORE *store = NULL;
1573 char *ca_dir, *ca_file;
1574 NYD_ENTER;
1576 a_xssl_init();
1578 ssl_verify_level = SSL_VERIFY_STRICT;
1579 if ((store = X509_STORE_new()) == NULL) {
1580 ssl_gen_err(_("Error creating X509 store"));
1581 goto jleave;
1583 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1585 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1586 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
1587 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1588 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
1590 if (ca_dir != NULL || ca_file != NULL) {
1591 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
1592 ssl_gen_err(_("Error loading %s"),
1593 (ca_file != NULL) ? ca_file : ca_dir);
1594 goto jleave;
1598 /* C99 */{
1599 bool_t xv15;
1601 if((xv15 = ok_blook(smime_no_default_ca)))
1602 n_OBSOLETE(_("please use *smime-ca-no-defaults*, "
1603 "not *smime-no-default-ca*"));
1604 if(!ok_blook(smime_ca_no_defaults) && !xv15 &&
1605 X509_STORE_set_default_paths(store) != 1) {
1606 ssl_gen_err(_("Error loading built-in default CA locations\n"));
1607 goto jleave;
1611 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1612 goto jleave;
1614 a_xssl_ca_flags(store, ok_vlook(smime_ca_flags));
1616 srelax_hold();
1617 for (ip = msgvec; *ip != 0; ++ip) {
1618 struct message *mp = message + *ip - 1;
1619 setdot(mp);
1620 ec |= smime_verify(mp, *ip, NULL, store);
1621 srelax();
1623 srelax_rele();
1625 if ((rv = ec) != 0)
1626 n_exit_status |= n_EXIT_ERR;
1627 jleave:
1628 if (store != NULL)
1629 X509_STORE_free(store);
1630 NYD_LEAVE;
1631 return rv;
1634 FL FILE *
1635 smime_sign(FILE *ip, char const *addr)
1637 FILE *rv, *sp, *fp, *bp, *hp;
1638 X509 *cert = NULL;
1639 n_XSSL_STACKOF(X509) *chain = NULL;
1640 EVP_PKEY *pkey = NULL;
1641 BIO *bb, *sb;
1642 PKCS7 *pkcs7;
1643 EVP_MD const *md;
1644 char const *name;
1645 bool_t bail = FAL0;
1646 NYD_ENTER;
1648 assert(addr != NULL);
1649 rv = sp = fp = bp = hp = NULL;
1651 a_xssl_init();
1653 if (addr == NULL) {
1654 n_err(_("No *from* address for signing specified\n"));
1655 goto jleave;
1657 if ((fp = smime_sign_cert(addr, NULL, 1, NULL)) == NULL)
1658 goto jleave;
1660 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb,
1661 savecat(addr, ".smime-cert-key"))) == NULL) {
1662 ssl_gen_err(_("Error reading private key from"));
1663 goto jleave;
1666 rewind(fp);
1667 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb,
1668 savecat(addr, ".smime-cert-cert"))) == NULL) {
1669 ssl_gen_err(_("Error reading signer certificate from"));
1670 goto jleave;
1672 Fclose(fp);
1673 fp = NULL;
1675 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1676 !_smime_sign_include_chain_creat(&chain, name,
1677 savecat(addr, ".smime-include-certs")))
1678 goto jleave;
1680 name = NULL;
1681 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1682 goto jleave;
1684 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1685 NULL) {
1686 n_perr(_("tempfile"), 0);
1687 goto jleave;
1690 rewind(ip);
1691 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1692 goto jleave;
1694 sb = NULL;
1695 pkcs7 = NULL;
1697 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1698 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1699 ssl_gen_err(_("Error creating BIO signing objects"));
1700 bail = TRU1;
1701 goto jerr;
1704 #undef _X
1705 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1706 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1707 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1708 bail = TRU1;
1709 goto jerr;
1711 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1712 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1713 bail = TRU1;
1714 goto jerr;
1716 if (!PKCS7_final(pkcs7, bb, _X)) {
1717 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1718 bail = TRU1;
1719 goto jerr;
1721 #undef _X
1723 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1724 ssl_gen_err(_("Error writing signed S/MIME data"));
1725 bail = TRU1;
1726 /*goto jerr*/
1728 jerr:
1729 if (pkcs7 != NULL)
1730 PKCS7_free(pkcs7);
1731 if (sb != NULL)
1732 BIO_free(sb);
1733 if (bb != NULL)
1734 BIO_free(bb);
1735 if (!bail) {
1736 rewind(bp);
1737 fflush_rewind(sp);
1738 rv = smime_sign_assemble(hp, bp, sp, name);
1739 hp = bp = sp = NULL;
1742 jleave:
1743 if (chain != NULL)
1744 sk_X509_pop_free(chain, X509_free);
1745 if (cert != NULL)
1746 X509_free(cert);
1747 if (pkey != NULL)
1748 EVP_PKEY_free(pkey);
1749 if (fp != NULL)
1750 Fclose(fp);
1751 if (hp != NULL)
1752 Fclose(hp);
1753 if (bp != NULL)
1754 Fclose(bp);
1755 if (sp != NULL)
1756 Fclose(sp);
1757 NYD_LEAVE;
1758 return rv;
1761 FL FILE *
1762 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1764 FILE *rv, *yp, *fp, *bp, *hp;
1765 X509 *cert;
1766 PKCS7 *pkcs7;
1767 BIO *bb, *yb;
1768 n_XSSL_STACKOF(X509) *certs;
1769 EVP_CIPHER const *cipher;
1770 char *certfile;
1771 bool_t bail;
1772 NYD_ENTER;
1774 bail = FAL0;
1775 rv = yp = fp = bp = hp = NULL;
1777 if ((certfile = fexpand(xcertfile, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
1778 goto jleave;
1780 a_xssl_init();
1782 if ((cipher = _smime_cipher(to)) == NULL)
1783 goto jleave;
1785 if ((fp = Fopen(certfile, "r")) == NULL) {
1786 n_perr(certfile, 0);
1787 goto jleave;
1789 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1790 ssl_gen_err(_("Error reading encryption certificate from %s"),
1791 n_shexp_quote_cp(certfile, FAL0));
1792 bail = TRU1;
1794 if (bail)
1795 goto jleave;
1796 Fclose(fp);
1797 fp = NULL;
1798 bail = FAL0;
1800 certs = sk_X509_new_null();
1801 sk_X509_push(certs, cert);
1803 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1804 NULL) {
1805 n_perr(_("tempfile"), 0);
1806 goto jerr1;
1809 rewind(ip);
1810 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1811 goto jerr1;
1813 yb = NULL;
1814 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1815 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1816 ssl_gen_err(_("Error creating BIO encryption objects"));
1817 bail = TRU1;
1818 goto jerr2;
1820 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1821 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
1822 bail = TRU1;
1823 goto jerr2;
1825 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1826 ssl_gen_err(_("Error writing encrypted S/MIME data"));
1827 bail = TRU1;
1828 /* goto jerr2 */
1830 PKCS7_free(pkcs7);
1832 jerr2:
1833 if (bb != NULL)
1834 BIO_free(bb);
1835 if (yb != NULL)
1836 BIO_free(yb);
1837 Fclose(bp);
1838 bp = NULL;
1839 if (!bail) {
1840 fflush_rewind(yp);
1841 rv = smime_encrypt_assemble(hp, yp);
1842 hp = yp = NULL;
1844 jerr1:
1845 sk_X509_pop_free(certs, X509_free);
1846 jleave:
1847 if(yp != NULL)
1848 Fclose(yp);
1849 if(fp != NULL)
1850 Fclose(fp);
1851 if(bp != NULL)
1852 Fclose(bp);
1853 if(hp != NULL)
1854 Fclose(hp);
1855 NYD_LEAVE;
1856 return rv;
1859 FL struct message *
1860 smime_decrypt(struct message *m, char const *to, char const *cc,
1861 bool_t signcall)
1863 char const *myaddr;
1864 long size;
1865 struct message *rv;
1866 FILE *bp, *hp, *op;
1867 PKCS7 *pkcs7;
1868 BIO *ob, *bb, *pb;
1869 X509 *cert;
1870 EVP_PKEY *pkey;
1871 FILE *yp;
1872 NYD_ENTER;
1874 pkey = NULL;
1875 cert = NULL;
1876 ob = bb = pb = NULL;
1877 pkcs7 = NULL;
1878 bp = hp = op = NULL;
1879 rv = NULL;
1880 size = m->m_size;
1882 if((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1883 goto jleave;
1885 a_xssl_init();
1887 if((op = smime_sign_cert(to, cc, 0, &myaddr)) != NULL){
1888 pkey = PEM_read_PrivateKey(op, NULL, &ssl_password_cb,
1889 savecat(myaddr, ".smime-cert-key"));
1890 if(pkey == NULL){
1891 ssl_gen_err(_("Error reading private key"));
1892 goto jleave;
1895 rewind(op);
1896 if((cert = PEM_read_X509(op, NULL, &ssl_password_cb,
1897 savecat(myaddr, ".smime-cert-cert"))) == NULL){
1898 ssl_gen_err(_("Error reading decryption certificate"));
1899 goto jleave;
1902 Fclose(op);
1903 op = NULL;
1906 if((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
1907 n_perr(_("tempfile"), 0);
1908 goto jleave;
1911 if(smime_split(yp, &hp, &bp, size, 1) == STOP)
1912 goto jleave;
1914 if((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1915 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL){
1916 ssl_gen_err(_("Error creating BIO decryption objects"));
1917 goto jleave;
1920 if((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL){
1921 ssl_gen_err(_("Error reading PKCS#7 object"));
1922 goto jleave;
1925 if(PKCS7_type_is_signed(pkcs7)){
1926 if(signcall){
1927 setinput(&mb, m, NEED_BODY);
1928 rv = (struct message*)-1;
1929 goto jleave;
1931 if(PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1932 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1933 goto jerr;
1934 fseek(hp, 0L, SEEK_END);
1935 fprintf(hp, "X-Encryption-Cipher: none\n");
1936 fflush_rewind(hp);
1937 }else if(pkey == NULL){
1938 n_err(_("No appropriate private key found\n"));
1939 goto jleave;
1940 }else if(cert == NULL){
1941 n_err(_("No appropriate certificate found\n"));
1942 goto jleave;
1943 }else if(PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1){
1944 jerr:
1945 ssl_gen_err(_("Error decrypting PKCS#7 object"));
1946 goto jleave;
1948 fflush_rewind(op);
1949 Fclose(bp);
1950 bp = NULL;
1952 rv = smime_decrypt_assemble(m, hp, op);
1953 hp = op = NULL; /* xxx closed by decrypt_assemble */
1954 jleave:
1955 if(op != NULL)
1956 Fclose(op);
1957 if(hp != NULL)
1958 Fclose(hp);
1959 if(bp != NULL)
1960 Fclose(bp);
1961 if(bb != NULL)
1962 BIO_free(bb);
1963 if(ob != NULL)
1964 BIO_free(ob);
1965 if(pkcs7 != NULL)
1966 PKCS7_free(pkcs7);
1967 if(cert != NULL)
1968 X509_free(cert);
1969 if(pkey != NULL)
1970 EVP_PKEY_free(pkey);
1971 NYD_LEAVE;
1972 return rv;
1975 FL enum okay
1976 smime_certsave(struct message *m, int n, FILE *op)
1978 struct message *x;
1979 char *to, *cc, *cnttype;
1980 int c, i;
1981 FILE *fp, *ip;
1982 off_t size;
1983 BIO *fb, *pb;
1984 PKCS7 *pkcs7;
1985 n_XSSL_STACKOF(X509) *certs, *chain = NULL;
1986 X509 *cert;
1987 enum okay rv = STOP;
1988 NYD_ENTER;
1990 pkcs7 = NULL;
1992 a_xssl_msgno = (size_t)n;
1993 jloop:
1994 to = hfield1("to", m);
1995 cc = hfield1("cc", m);
1996 cnttype = hfield1("content-type", m);
1998 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1999 goto jleave;
2001 #undef _X
2002 #undef _Y
2003 #define _X (sizeof("application/") -1)
2004 #define _Y(X) X, sizeof(X) -1
2005 if (cnttype && is_asccaseprefix("application/", cnttype) &&
2006 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
2007 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
2008 #undef _Y
2009 #undef _X
2010 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
2011 goto jleave;
2012 if (x != (struct message*)-1) {
2013 m = x;
2014 goto jloop;
2017 size = m->m_size;
2019 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
2020 NULL) {
2021 n_perr(_("tempfile"), 0);
2022 goto jleave;
2025 while (size-- > 0) {
2026 c = getc(ip);
2027 putc(c, fp);
2029 fflush(fp);
2031 rewind(fp);
2032 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
2033 ssl_gen_err("Error creating BIO object for message %d", n);
2034 Fclose(fp);
2035 goto jleave;
2038 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
2039 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
2040 BIO_free(fb);
2041 Fclose(fp);
2042 goto jleave;
2044 BIO_free(fb);
2045 Fclose(fp);
2047 certs = PKCS7_get0_signers(pkcs7, chain, 0);
2048 if (certs == NULL) {
2049 n_err(_("No certificates found in message %d\n"), n);
2050 goto jleave;
2053 for (i = 0; i < sk_X509_num(certs); ++i) {
2054 cert = sk_X509_value(certs, i);
2055 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
2056 ssl_gen_err(_("Error writing certificate %d from message %d"),
2057 i, n);
2058 goto jleave;
2061 rv = OKAY;
2062 jleave:
2063 if(pkcs7 != NULL)
2064 PKCS7_free(pkcs7);
2065 NYD_LEAVE;
2066 return rv;
2068 #endif /* HAVE_XSSL */
2070 /* s-it-mode */