Prepare variable handling for future bit extension etc.
[s-mailx.git] / xssl.c
blobdca485469d3b99aa531a406b267fd85a3a2b5640
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 enum a_xssl_state{
156 a_XSSL_S_INIT = 1u<<0,
157 a_XSSL_S_RAND_INIT = 1u<<1,
158 a_XSSL_S_CONF_LOAD = 1u<<2,
160 #if HAVE_XSSL_OPENSSL < 0x10100
161 a_XSSL_S_EXIT_HDL = 1u<<8,
162 a_XSSL_S_ALGO_LOAD = 1u<<9,
163 #endif
165 a_XSSL_S_VERIFY_ERROR = 1u<<16
168 /* We go for the OpenSSL v1.0.2+ SSL_CONF_CTX if available even if
169 * the library does internally what we'd otherwise do ourselfs.
170 * But eventually we can drop the direct use cases */
171 enum a_xssl_conf_type{
172 a_XSSL_CT_CERTIFICATE,
173 a_XSSL_CT_CIPHER_STRING,
174 a_XSSL_CT_CURVES,
175 a_XSSL_CT_PRIVATE_KEY,
176 a_XSSL_CT_OPTIONS,
177 a_XSSL_CT_PROTOCOL
180 struct ssl_method { /* TODO v15 obsolete */
181 char const sm_name[8];
182 char const sm_map[16];
185 #ifndef HAVE_XSSL_CONF_CTX
186 struct a_xssl_protocol{
187 char const *sp_name;
188 sl_i sp_flag;
190 #endif
192 struct a_xssl_smime_cipher{
193 char const sc_name[8];
194 EVP_CIPHER const *(*sc_fun)(void);
197 struct a_xssl_smime_digest{
198 char const sd_name[8];
199 EVP_MD const *(*sd_fun)(void);
202 struct a_xssl_x509_v_flags{
203 char const xvf_name[20];
204 si32_t xvf_flag;
207 /* Supported SSL/TLS methods: update manual on change! */
209 static struct ssl_method const _ssl_methods[] = { /* TODO obsolete */
210 {"auto", "ALL,-SSLv2"},
211 {"ssl3", "-ALL,SSLv3"},
212 {"tls1", "-ALL,TLSv1"},
213 {"tls1.1", "-ALL,TLSv1.1"},
214 {"tls1.2", "-ALL,TLSv1.2"}
217 /* Update manual on change! */
218 #ifndef HAVE_XSSL_CONF_CTX
219 static struct a_xssl_protocol const a_xssl_protocols[] = {
220 {"ALL", SSL_OP_NO_SSL_MASK},
221 {"TLSv1.2", SSL_OP_NO_TLSv1_2},
222 {"TLSv1.1", SSL_OP_NO_TLSv1_1},
223 {"TLSv1", SSL_OP_NO_TLSv1},
224 {"SSLv3", SSL_OP_NO_SSLv3},
225 {"SSLv2", 0}
227 #endif
229 /* Supported S/MIME cipher algorithms */
230 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers[] = { /* Manual! */
231 #ifndef OPENSSL_NO_AES
232 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_aes_128_cbc /* According to RFC 5751 */
233 {"aes128", &EVP_aes_128_cbc},
234 {"aes256", &EVP_aes_256_cbc},
235 {"aes192", &EVP_aes_192_cbc},
236 #endif
237 #ifndef OPENSSL_NO_DES
238 # ifndef a_XSSL_SMIME_DEFAULT_CIPHER
239 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_des_ede3_cbc
240 # endif
241 {"des3", &EVP_des_ede3_cbc},
242 {"des", &EVP_des_cbc},
243 #endif
245 #ifndef a_XSSL_SMIME_DEFAULT_CIPHER
246 # error Your OpenSSL library does not include the necessary
247 # error cipher algorithms that are required to support S/MIME
248 #endif
250 #ifndef OPENSSL_NO_AES
251 /* TODO obsolete a_xssl_smime_ciphers_obs */
252 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers_obs[] = {
253 {"aes-128", &EVP_aes_128_cbc},
254 {"aes-256", &EVP_aes_256_cbc},
255 {"aes-192", &EVP_aes_192_cbc}
257 #endif
259 /* Supported S/MIME message digest algorithms */
260 static struct a_xssl_smime_digest const a_xssl_smime_digests[] = { /* Manual! */
261 #define a_XSSL_SMIME_DEFAULT_DIGEST EVP_sha1 /* According to RFC 5751 */
262 #define a_XSSL_SMIME_DEFAULT_DIGEST_S "sha1"
263 {"sha1", &EVP_sha1},
264 {"sha256", &EVP_sha256},
265 {"sha512", &EVP_sha512},
266 {"sha384", &EVP_sha384},
267 {"sha224", &EVP_sha224},
268 #ifndef OPENSSL_NO_MD5
269 {"md5", &EVP_md5},
270 #endif
273 /* X509_STORE_set_flags() for *{smime,ssl}-ca-flags* */
274 static struct a_xssl_x509_v_flags const a_xssl_x509_v_flags[] = { /* Manual! */
275 {"no-alt-chains", X509_V_FLAG_NO_ALT_CHAINS},
276 {"no-check-time", X509_V_FLAG_NO_CHECK_TIME},
277 {"partial-chain", X509_V_FLAG_PARTIAL_CHAIN},
278 {"strict", X509_V_FLAG_X509_STRICT},
279 {"trusted-first", X509_V_FLAG_TRUSTED_FIRST},
282 static enum a_xssl_state a_xssl_state;
283 static size_t a_xssl_msgno;
285 static bool_t a_xssl_rand_init(void);
286 #if HAVE_XSSL_OPENSSL < 0x10100
287 # ifdef HAVE_SSL_ALL_ALGORITHMS
288 static void a_xssl__load_algos(void);
289 # define a_xssl_load_algos a_xssl__load_algos
290 # endif
291 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
292 static void a_xssl_atexit(void);
293 # endif
294 #endif
295 #ifndef a_xssl_load_algos
296 # define a_xssl_load_algos() do{;}while(0)
297 #endif
299 static bool_t _ssl_parse_asn1_time(ASN1_TIME const *atp,
300 char *bdat, size_t blen);
301 static int _ssl_verify_cb(int success, X509_STORE_CTX *store);
303 /* *smime-ca-flags*, *ssl-ca-flags* */
304 static void a_xssl_ca_flags(X509_STORE *store, char const *flags);
306 /* SSL_CTX configuration */
307 static void * _ssl_conf_setup(SSL_CTX *ctxp);
308 static bool_t _ssl_conf(void *confp, enum a_xssl_conf_type ct,
309 char const *value);
310 static bool_t _ssl_conf_finish(void **confp, bool_t error);
312 static bool_t _ssl_load_verifications(SSL_CTX *ctxp);
314 static enum okay ssl_check_host(struct sock *sp, struct url const *urlp);
316 static int smime_verify(struct message *m, int n,
317 n_XSSL_STACKOF(X509) *chain, X509_STORE *store);
318 static EVP_CIPHER const * _smime_cipher(char const *name);
319 static int ssl_password_cb(char *buf, int size, int rwflag,
320 void *userdata);
321 static FILE * smime_sign_cert(char const *xname, char const *xname2,
322 bool_t dowarn, char const **match);
323 static char const * _smime_sign_include_certs(char const *name);
324 static bool_t _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
325 char const *cfiles, char const *addr);
326 static EVP_MD const * _smime_sign_digest(char const *name,
327 char const **digname);
328 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
329 static enum okay load_crl1(X509_STORE *store, char const *name);
330 #endif
331 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
333 static bool_t
334 a_xssl_rand_init(void){
335 #define a_XSSL_RAND_ENTROPY 32
336 char b64buf[a_XSSL_RAND_ENTROPY * 5 +1], *randfile;
337 char const *cp, *x;
338 bool_t err;
339 NYD2_ENTER;
341 err = TRU1;
342 randfile = NULL;
344 /* Shall use some external daemon? */ /* TODO obsolete *ssl_rand_egd* */
345 if((cp = ok_vlook(ssl_rand_egd)) != NULL){ /* TODO no one supports it now! */
346 n_OBSOLETE(_("all *SSL libraries removed *ssl-rand-egd* support"));
347 #ifdef HAVE_XSSL_RAND_EGD
348 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) != NULL &&
349 RAND_egd(cp = x) != -1){
350 err = FAL0;
351 goto jleave;
353 n_err(_("*ssl_rand_egd* daemon at %s not available\n"),
354 n_shexp_quote_cp(cp, FAL0));
355 #else
356 if(n_poption & n_PO_D_VV)
357 n_err(_("*ssl_rand_egd* (%s): unsupported by SSL library\n"),
358 n_shexp_quote_cp(cp, FAL0));
359 #endif
362 /* Prefer possible user setting */
363 if((cp = ok_vlook(ssl_rand_file)) != NULL){
364 x = NULL;
365 if(*cp != '\0'){
366 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
367 n_err(_("*ssl-rand-file*: expansion of %s failed "
368 "(using OpenSSL default)\n"),
369 n_shexp_quote_cp(cp, FAL0));
371 cp = x;
373 if(cp == NULL){
374 randfile = n_lofi_alloc(PATH_MAX);
375 if((cp = RAND_file_name(randfile, PATH_MAX)) == NULL){
376 n_err(_("*ssl-rand-file*: no SSL entropy file, can't seed PRNG\n"));
377 goto jleave;
381 (void)RAND_load_file(cp, a_XSSL_RAND_LOAD_FILE_MAXBYTES);
383 /* And feed in some data, then write the updated file.
384 * While this rather feeds the PRNG with itself in the n_RANDOM_USE_XSSL
385 * case, let us stir the buffer a little bit.
386 * Estimate a low but likely still too high number of entropy bytes, use
387 * 20%: base64 uses 3 input = 4 output bytes relation, and the base64
388 * alphabet is a 6 bit one */
389 n_LCTAV(n_RANDOM_USE_XSSL == 0 || n_RANDOM_USE_XSSL == 1);
390 for(x = (char*)-1;;){
391 RAND_add(n_random_create_buf(b64buf, sizeof(b64buf) -1, NULL),
392 sizeof(b64buf) -1, a_XSSL_RAND_ENTROPY);
393 if((x = (char*)((uintptr_t)x >> (1 + (n_RANDOM_USE_XSSL * 3)))) == NULL){
394 err = (RAND_status() == 0);
395 break;
397 #if !n_RANDOM_USE_XSSL
398 if(!(err = (RAND_status() == 0)))
399 break;
400 #endif
403 if(!err)
404 err = (RAND_write_file(cp) == -1);
406 jleave:
407 if(randfile != NULL)
408 n_lofi_free(randfile);
409 if(err)
410 n_panic(_("Cannot seed the *SSL PseudoRandomNumberGenerator, "
411 "RAND_status() is 0!\n"
412 " Please set *ssl-rand-file* to a file with sufficient entropy.\n"
413 " On a machine with entropy: "
414 "\"$ dd if=/dev/urandom of=FILE bs=1024 count=1\"\n"));
415 NYD2_LEAVE;
416 return err;
419 static void
420 a_xssl_init(void)
422 #ifdef HAVE_XSSL_CONFIG
423 char const *cp;
424 #endif
425 NYD_ENTER;
427 if(!(a_xssl_state & a_XSSL_S_INIT)){
428 #if HAVE_XSSL_OPENSSL >= 0x10100
429 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS |
430 OPENSSL_INIT_LOAD_CRYPTO_STRINGS
431 # ifdef HAVE_SSL_ALL_ALGORITHMS
432 | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS
433 # endif
434 , NULL);
436 #else /* OPENSSL >= 0x10100 */
437 SSL_load_error_strings();
438 SSL_library_init();
439 a_xssl_load_algos();
440 #endif
441 a_xssl_state |= a_XSSL_S_INIT;
444 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
445 #ifdef HAVE_XSSL_CONFIG
446 if(!(a_xssl_state & a_XSSL_S_CONF_LOAD) &&
447 (cp = ok_vlook(ssl_config_file)) != NULL){
448 ul_i flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
450 if(*cp == '\0'){
451 cp = NULL;
452 flags = 0;
454 if(CONF_modules_load_file(cp, n_uagent, flags) == 1){
455 a_xssl_state |= a_XSSL_S_CONF_LOAD;
456 # if HAVE_XSSL_OPENSSL < 0x10100
457 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
458 a_xssl_state |= a_XSSL_S_EXIT_HDL;
459 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
461 # endif
462 }else
463 ssl_gen_err(_("Ignoring CONF_modules_load_file() load error"));
465 #endif
467 if(!(a_xssl_state & a_XSSL_S_RAND_INIT) && a_xssl_rand_init())
468 a_xssl_state |= a_XSSL_S_RAND_INIT;
469 NYD_LEAVE;
472 #if HAVE_XSSL_OPENSSL < 0x10100
473 # ifdef HAVE_SSL_ALL_ALGORITHMS
474 static void
475 a_xssl__load_algos(void){
476 NYD2_ENTER;
477 if(!(a_xssl_state & a_XSSL_S_ALGO_LOAD)){
478 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
479 OpenSSL_add_all_algorithms();
481 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
482 a_xssl_state |= a_XSSL_S_EXIT_HDL;
483 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
486 NYD2_LEAVE;
488 # endif
490 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
491 static void
492 a_xssl_atexit(void){
493 NYD2_ENTER;
494 # ifdef HAVE_XSSL_CONFIG
495 if(a_xssl_state & a_XSSL_S_CONF_LOAD)
496 CONF_modules_free();
497 # endif
499 # ifdef HAVE_SSL_ALL_ALGORITHMS
500 if(a_xssl_state & a_XSSL_S_ALGO_LOAD)
501 EVP_cleanup();
502 # endif
503 NYD2_LEAVE;
505 # endif
506 #endif /* HAVE_XSSL_OPENSSL < 0x10100 */
508 static bool_t
509 _ssl_parse_asn1_time(ASN1_TIME const *atp, char *bdat, size_t blen)
511 BIO *mbp;
512 char *mcp;
513 long l;
514 NYD_ENTER;
516 mbp = BIO_new(BIO_s_mem());
518 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
519 snprintf(bdat, blen, "%.*s", (int)l, mcp);
520 else {
521 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
522 /*is (int)*/atp->length, (char const*)atp->data);
523 mcp = NULL;
526 BIO_free(mbp);
527 NYD_LEAVE;
528 return (mcp != NULL);
531 static int
532 _ssl_verify_cb(int success, X509_STORE_CTX *store)
534 char data[256];
535 X509 *cert;
536 int rv = TRU1;
537 NYD_ENTER;
539 if (success && !(n_poption & n_PO_D_V))
540 goto jleave;
542 if (a_xssl_msgno != 0) {
543 n_err(_("Message %lu:\n"), (ul_i)a_xssl_msgno);
544 a_xssl_msgno = 0;
546 n_err(_(" Certificate depth %d %s\n"),
547 X509_STORE_CTX_get_error_depth(store), (success ? n_empty : V_(n_error)));
549 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
550 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
551 n_err(_(" subject = %s\n"), data);
553 _ssl_parse_asn1_time(a_xssl_X509_get_notBefore(cert), data, sizeof data);
554 n_err(_(" notBefore = %s\n"), data);
556 _ssl_parse_asn1_time(a_xssl_X509_get_notAfter(cert), data, sizeof data);
557 n_err(_(" notAfter = %s\n"), data);
559 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
560 n_err(_(" issuer = %s\n"), data);
563 if (!success) {
564 int err = X509_STORE_CTX_get_error(store);
566 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
567 a_xssl_state |= a_XSSL_S_VERIFY_ERROR;
570 if (!success && ssl_verify_decide() != OKAY)
571 rv = FAL0;
572 jleave:
573 NYD_LEAVE;
574 return rv;
577 static void
578 a_xssl_ca_flags(X509_STORE *store, char const *flags){
579 NYD2_ENTER;
580 if(flags != NULL){
581 char *iolist, *cp;
583 iolist = savestr(flags);
584 jouter:
585 while((cp = n_strsep(&iolist, ',', TRU1)) != NULL){
586 struct a_xssl_x509_v_flags const *xvfp;
588 for(xvfp = &a_xssl_x509_v_flags[0];
589 xvfp < &a_xssl_x509_v_flags[n_NELEM(a_xssl_x509_v_flags)];
590 ++xvfp)
591 if(!asccasecmp(cp, xvfp->xvf_name)){
592 if(xvfp->xvf_flag != -1){
593 #ifdef a_XSSL_X509_V_ANY
594 X509_STORE_set_flags(store, xvfp->xvf_flag);
595 #endif
596 }else if(n_poption & n_PO_D_V)
597 n_err(_("*{smime,ssl}-ca-flags*: "
598 "directive not supported: %s\n"), cp);
599 goto jouter;
601 n_err(_("*{smime,ssl}-ca-flags*: invalid directive: %s\n"), cp);
604 NYD2_LEAVE;
607 #ifdef HAVE_XSSL_CONF_CTX
608 static void *
609 _ssl_conf_setup(SSL_CTX *ctxp)
611 SSL_CONF_CTX *sccp;
612 NYD_ENTER;
614 if ((sccp = SSL_CONF_CTX_new()) != NULL) {
615 SSL_CONF_CTX_set_flags(sccp,
616 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
617 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
619 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
620 } else
621 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
623 NYD_LEAVE;
624 return sccp;
627 static bool_t
628 _ssl_conf(void *confp, enum a_xssl_conf_type ct, char const *value)
630 int rv;
631 char const *cmsg;
632 SSL_CONF_CTX *sccp = (SSL_CONF_CTX*)confp;
633 NYD_ENTER;
635 switch (ct) {
636 case a_XSSL_CT_CERTIFICATE:
637 cmsg = "ssl-cert";
638 rv = SSL_CONF_cmd(sccp, "Certificate", value);
639 break;
640 case a_XSSL_CT_CIPHER_STRING:
641 cmsg = "ssl-cipher-list";
642 rv = SSL_CONF_cmd(sccp, "CipherString", value);
643 break;
644 case a_XSSL_CT_PRIVATE_KEY:
645 cmsg = "ssl-key";
646 rv = SSL_CONF_cmd(sccp, "PrivateKey", value);
647 break;
648 default:
649 case a_XSSL_CT_OPTIONS:
650 cmsg = "ssl-options";
651 rv = SSL_CONF_cmd(sccp, "Options", "Bugs");
652 break;
653 case a_XSSL_CT_PROTOCOL:
654 cmsg = "ssl-protocol";
655 rv = SSL_CONF_cmd(sccp, "Protocol", value);
656 break;
657 case a_XSSL_CT_CURVES:
658 cmsg = "ssl-curves";
659 rv = SSL_CONF_cmd(sccp, "Curves", value);
660 break;
663 if (rv == 2)
664 rv = 0;
665 else {
666 if (rv == 0)
667 ssl_gen_err(_("SSL_CONF_CTX_cmd() failed for *%s*"), cmsg);
668 else
669 n_err(_("%s: *%s* implementation error, please report this\n"),
670 n_uagent, cmsg);
671 rv = 1;
674 NYD_LEAVE;
675 return (rv == 0);
678 static bool_t
679 _ssl_conf_finish(void **confp, bool_t error)
681 SSL_CONF_CTX **sccp = (SSL_CONF_CTX**)confp;
682 bool_t rv;
683 NYD_ENTER;
685 if (!(rv = error))
686 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
688 SSL_CONF_CTX_free(*sccp);
690 *sccp = NULL;
691 NYD_LEAVE;
692 return rv;
695 #else /* HAVE_XSSL_CONF_CTX */
696 static void *
697 _ssl_conf_setup(SSL_CTX* ctxp)
699 return ctxp;
702 static bool_t
703 _ssl_conf(void *confp, enum a_xssl_conf_type ct, char const *value){
704 SSL_CTX *ctxp;
705 NYD2_ENTER;
707 ctxp = confp;
709 switch(ct){
710 case a_XSSL_CT_CERTIFICATE:
711 if(SSL_CTX_use_certificate_chain_file(ctxp, value) != 1){
712 ssl_gen_err(_("Can't load certificate from file %s\n"),
713 n_shexp_quote_cp(value, FAL0));
714 confp = NULL;
716 break;
717 case a_XSSL_CT_CIPHER_STRING:
718 if(SSL_CTX_set_cipher_list(ctxp, value) != 1){
719 ssl_gen_err(_("Invalid cipher string: %s\n"), value);
720 confp = NULL;
722 break;
723 case a_XSSL_CT_CURVES:
724 #ifdef SSL_CTRL_SET_CURVES_LIST
725 if(SSL_CTX_set1_curves_list(ctxp, value) != 1){
726 ssl_gen_err(_("Invalid curves string: %s\n"), value);
727 confp = NULL;
729 #else
730 n_err(_("*ssl-curves*: as such not supported\n"));
731 confp = NULL;
732 #endif
733 break;
734 case a_XSSL_CT_PRIVATE_KEY:
735 if(SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1){
736 ssl_gen_err(_("Can't load private key from file %s\n"),
737 n_shexp_quote_cp(value, FAL0));
738 confp = NULL;
740 break;
741 case a_XSSL_CT_OPTIONS:
742 /* "Options"="Bugs" TODO *ssl-options* */
743 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
744 break;
745 case a_XSSL_CT_PROTOCOL:{
746 char *iolist, *cp, addin;
747 size_t i;
748 sl_i opts = 0;
750 confp = NULL;
751 for(iolist = cp = savestr(value);
752 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;){
753 if(*cp == '\0'){
754 n_err(_("*ssl-protocol*: empty arguments are not supported\n"));
755 goto jleave;
758 addin = TRU1;
759 switch(cp[0]){
760 case '-': addin = FAL0; /* FALLTHRU */
761 case '+': ++cp; /* FALLTHRU */
762 default : break;
765 for(i = 0;;){
766 if(!asccasecmp(cp, a_xssl_protocols[i].sp_name)){
767 /* We need to inverse the meaning of the _NO_s */
768 if(!addin)
769 opts |= a_xssl_protocols[i].sp_flag;
770 else
771 opts &= ~a_xssl_protocols[i].sp_flag;
772 break;
774 if(++i < n_NELEM(a_xssl_protocols))
775 continue;
776 n_err(_("*ssl-protocol*: unsupported value: %s\n"), cp);
777 goto jleave;
780 confp = ctxp;
781 SSL_CTX_set_options(ctxp, opts);
782 } break;
784 jleave:
785 NYD2_LEAVE;
786 return (confp != NULL);
789 static bool_t
790 _ssl_conf_finish(void **confp, bool_t error)
792 n_UNUSED(confp);
793 n_UNUSED(error);
794 return TRU1;
796 #endif /* !HAVE_XSSL_CONF_CTX */
798 static bool_t
799 _ssl_load_verifications(SSL_CTX *ctxp)
801 char *ca_dir, *ca_file;
802 X509_STORE *store;
803 bool_t rv = FAL0;
804 NYD_ENTER;
806 if (ssl_verify_level == SSL_VERIFY_IGNORE) {
807 rv = TRU1;
808 goto jleave;
811 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
812 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
813 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
814 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
816 if ((ca_dir != NULL || ca_file != NULL) &&
817 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1) {
818 char const *m1, *m2, *m3;
820 if (ca_dir != NULL) {
821 m1 = ca_dir;
822 m2 = (ca_file != NULL) ? _(" or ") : n_empty;
823 } else
824 m1 = m2 = n_empty;
825 m3 = (ca_file != NULL) ? ca_file : n_empty;
826 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
827 goto jleave;
830 /* C99 */{
831 bool_t xv15;
833 if((xv15 = ok_blook(ssl_no_default_ca)))
834 n_OBSOLETE(_("please use *ssl-ca-no-defaults*, "
835 "not *ssl-no-default-ca*"));
836 if(!ok_blook(ssl_ca_no_defaults) && !xv15 &&
837 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
838 ssl_gen_err(_("Error loading built-in default CA locations\n"));
839 goto jleave;
843 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
844 a_xssl_msgno = 0;
845 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
846 store = SSL_CTX_get_cert_store(ctxp);
847 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
848 a_xssl_ca_flags(store, ok_vlook(ssl_ca_flags));
850 rv = TRU1;
851 jleave:
852 NYD_LEAVE;
853 return rv;
856 static enum okay
857 ssl_check_host(struct sock *sp, struct url const *urlp)
859 char data[256];
860 X509 *cert;
861 n_XSSL_STACKOF(GENERAL_NAME) *gens;
862 GENERAL_NAME *gen;
863 X509_NAME *subj;
864 enum okay rv = STOP;
865 NYD_ENTER;
867 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
868 n_err(_("No certificate from: %s\n"), urlp->url_h_p.s);
869 goto jleave;
872 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
873 if (gens != NULL) {
874 int i;
876 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
877 gen = sk_GENERAL_NAME_value(gens, i);
878 if (gen->type == GEN_DNS) {
879 if (n_poption & n_PO_D_V)
880 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
881 urlp->url_host.s, (char*)gen->d.ia5->data);
882 rv = rfc2595_hostname_match(urlp->url_host.s,
883 (char*)gen->d.ia5->data);
884 if (rv == OKAY)
885 goto jdone;
890 if ((subj = X509_get_subject_name(cert)) != NULL &&
891 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
892 > 0) {
893 data[sizeof data - 1] = '\0';
894 if (n_poption & n_PO_D_V)
895 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
896 urlp->url_host.s, data);
897 rv = rfc2595_hostname_match(urlp->url_host.s, data);
900 jdone:
901 X509_free(cert);
902 jleave:
903 NYD_LEAVE;
904 return rv;
907 static int
908 smime_verify(struct message *m, int n, n_XSSL_STACKOF(X509) *chain,
909 X509_STORE *store)
911 char data[LINESIZE], *sender, *to, *cc, *cnttype;
912 int rv, c, i, j;
913 struct message *x;
914 FILE *fp, *ip;
915 off_t size;
916 BIO *fb, *pb;
917 PKCS7 *pkcs7;
918 n_XSSL_STACKOF(X509) *certs;
919 n_XSSL_STACKOF(GENERAL_NAME) *gens;
920 X509 *cert;
921 X509_NAME *subj;
922 GENERAL_NAME *gen;
923 NYD_ENTER;
925 rv = 1;
926 fp = NULL;
927 fb = pb = NULL;
928 pkcs7 = NULL;
929 certs = NULL;
930 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
931 a_xssl_msgno = (size_t)n;
933 for (;;) {
934 sender = getsender(m);
935 to = hfield1("to", m);
936 cc = hfield1("cc", m);
937 cnttype = hfield1("content-type", m);
939 #undef _X
940 #undef _Y
941 #define _X (sizeof("application/") -1)
942 #define _Y(X) X, sizeof(X) -1
943 if (cnttype && is_asccaseprefix("application/", cnttype) &&
944 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
945 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
946 #undef _Y
947 #undef _X
948 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
949 goto jleave;
950 if (x != (struct message*)-1) {
951 m = x;
952 continue;
956 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
957 goto jleave;
958 size = m->m_size;
959 break;
962 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
963 NULL) {
964 n_perr(_("tempfile"), 0);
965 goto jleave;
967 while (size-- > 0) {
968 c = getc(ip);
969 putc(c, fp);
971 fflush_rewind(fp);
973 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
974 ssl_gen_err(_(
975 "Error creating BIO verification object for message %d"), n);
976 goto jleave;
979 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
980 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
981 goto jleave;
983 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
984 ssl_gen_err(_("Error verifying message %d"), n);
985 goto jleave;
988 if (sender == NULL) {
989 n_err(_("Warning: Message %d has no sender\n"), n);
990 rv = 0;
991 goto jleave;
994 certs = PKCS7_get0_signers(pkcs7, chain, 0);
995 if (certs == NULL) {
996 n_err(_("No certificates found in message %d\n"), n);
997 goto jleave;
1000 for (i = 0; i < sk_X509_num(certs); ++i) {
1001 cert = sk_X509_value(certs, i);
1002 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
1003 if (gens != NULL) {
1004 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
1005 gen = sk_GENERAL_NAME_value(gens, j);
1006 if (gen->type == GEN_EMAIL) {
1007 if (n_poption & n_PO_D_V)
1008 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
1009 sender, (char*)gen->d.ia5->data);
1010 if (!asccasecmp((char*)gen->d.ia5->data, sender))
1011 goto jfound;
1016 if ((subj = X509_get_subject_name(cert)) != NULL &&
1017 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
1018 data, sizeof data) > 0) {
1019 data[sizeof data -1] = '\0';
1020 if (n_poption & n_PO_D_V)
1021 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
1022 sender, data);
1023 if (!asccasecmp(data, sender))
1024 goto jfound;
1027 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
1028 goto jleave;
1029 jfound:
1030 rv = ((a_xssl_state & a_XSSL_S_VERIFY_ERROR) != 0);
1031 if (!rv)
1032 fprintf(n_stdout, _("Message %d was verified successfully\n"), n);
1033 jleave:
1034 if (certs != NULL)
1035 sk_X509_free(certs);
1036 if (pb != NULL)
1037 BIO_free(pb);
1038 if (fb != NULL)
1039 BIO_free(fb);
1040 if (pkcs7 != NULL)
1041 PKCS7_free(pkcs7);
1042 if (fp != NULL)
1043 Fclose(fp);
1044 NYD_LEAVE;
1045 return rv;
1048 static EVP_CIPHER const *
1049 _smime_cipher(char const *name)
1051 EVP_CIPHER const *cipher;
1052 char *vn;
1053 char const *cp;
1054 size_t i;
1055 NYD_ENTER;
1057 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
1058 snprintf(vn, (int)i, "smime-cipher-%s", name);
1059 cp = n_var_vlook(vn, FAL0);
1060 ac_free(vn);
1062 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
1063 cipher = a_XSSL_SMIME_DEFAULT_CIPHER();
1064 goto jleave;
1066 cipher = NULL;
1068 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers); ++i)
1069 if (!asccasecmp(a_xssl_smime_ciphers[i].sc_name, cp)) {
1070 cipher = (*a_xssl_smime_ciphers[i].sc_fun)();
1071 goto jleave;
1073 #ifndef OPENSSL_NO_AES
1074 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers_obs); ++i) /* TODO obsolete */
1075 if (!asccasecmp(a_xssl_smime_ciphers_obs[i].sc_name, cp)) {
1076 n_OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
1077 cipher = (*a_xssl_smime_ciphers_obs[i].sc_fun)();
1078 goto jleave;
1080 #endif
1082 /* Not a built-in algorithm, but we may have dynamic support for more */
1083 #ifdef HAVE_SSL_ALL_ALGORITHMS
1084 if((cipher = EVP_get_cipherbyname(cp)) != NULL)
1085 goto jleave;
1086 #endif
1088 n_err(_("Invalid S/MIME cipher(s): %s\n"), cp);
1089 jleave:
1090 NYD_LEAVE;
1091 return cipher;
1094 static int
1095 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
1097 char *pass;
1098 size_t len;
1099 NYD_ENTER;
1100 n_UNUSED(rwflag);
1101 n_UNUSED(userdata);
1103 /* New-style */
1104 if(userdata != NULL){
1105 struct url url;
1106 struct ccred cred;
1108 if(url_parse(&url, CPROTO_CCRED, userdata)){
1109 if(ccred_lookup(&cred, &url)){
1110 ssize_t slen;
1112 if((slen = n_strscpy(buf, cred.cc_pass.s, size)) >= 0){
1113 size = (int)slen;
1114 goto jleave;
1117 size = 0;
1118 goto jleave;
1122 /* Old-style */
1123 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
1124 len = strlen(pass);
1125 if (UICMP(z, len, >=, size))
1126 len = size -1;
1127 memcpy(buf, pass, len);
1128 buf[len] = '\0';
1129 size = (int)len;
1130 } else
1131 size = 0;
1132 jleave:
1133 NYD_LEAVE;
1134 return size;
1137 static FILE *
1138 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn,
1139 char const **match)
1141 char *vn;
1142 int vs;
1143 struct name *np;
1144 char const *name = xname, *name2 = xname2, *cp;
1145 FILE *fp = NULL;
1146 NYD_ENTER;
1148 jloop:
1149 if (name) {
1150 np = lextract(name, GTO | GSKIN);
1151 while (np != NULL) {
1152 /* This needs to be more intelligent since it will currently take the
1153 * first name for which a private key is available regardless of
1154 * whether it is the right one for the message */
1155 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1156 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
1157 cp = n_var_vlook(vn, FAL0);
1158 ac_free(vn);
1159 if (cp != NULL) {
1160 if (match != NULL)
1161 *match = np->n_name;
1162 goto jopen;
1164 np = np->n_flink;
1166 if (name2 != NULL) {
1167 name = name2;
1168 name2 = NULL;
1169 goto jloop;
1173 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
1174 goto jerr;
1175 if(match != NULL)
1176 *match = NULL;
1177 jopen:
1178 if ((cp = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
1179 goto jleave;
1180 if ((fp = Fopen(cp, "r")) == NULL)
1181 n_perr(cp, 0);
1182 jleave:
1183 NYD_LEAVE;
1184 return fp;
1185 jerr:
1186 if (dowarn)
1187 n_err(_("Could not find a certificate for %s%s%s\n"),
1188 xname, (xname2 != NULL ? _("or ") : n_empty),
1189 (xname2 != NULL ? xname2 : n_empty));
1190 goto jleave;
1193 static char const *
1194 _smime_sign_include_certs(char const *name)
1196 char const *rv;
1197 NYD_ENTER;
1199 /* See comments in smime_sign_cert() for algorithm pitfalls */
1200 if (name != NULL) {
1201 struct name *np;
1203 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1204 int vs;
1205 char *vn;
1207 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1208 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1209 rv = n_var_vlook(vn, FAL0);
1210 ac_free(vn);
1211 if (rv != NULL)
1212 goto jleave;
1215 rv = ok_vlook(smime_sign_include_certs);
1216 jleave:
1217 NYD_LEAVE;
1218 return rv;
1221 static bool_t
1222 _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
1223 char const *cfiles, char const *addr)
1225 X509 *tmp;
1226 FILE *fp;
1227 char *nfield, *cfield, *x;
1228 NYD_ENTER;
1230 *chain = sk_X509_new_null();
1232 for (nfield = savestr(cfiles);
1233 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1234 if ((x = fexpand(cfield, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1235 (fp = Fopen(cfield = x, "r")) == NULL) {
1236 n_perr(cfiles, 0);
1237 goto jerr;
1239 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, n_UNCONST(addr))
1240 ) == NULL) {
1241 ssl_gen_err(_("Error reading certificate from %s"),
1242 n_shexp_quote_cp(cfield, FAL0));
1243 Fclose(fp);
1244 goto jerr;
1246 sk_X509_push(*chain, tmp);
1247 Fclose(fp);
1250 if (sk_X509_num(*chain) == 0) {
1251 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1252 goto jerr;
1254 jleave:
1255 NYD_LEAVE;
1256 return (*chain != NULL);
1257 jerr:
1258 sk_X509_pop_free(*chain, X509_free);
1259 *chain = NULL;
1260 goto jleave;
1263 static EVP_MD const *
1264 _smime_sign_digest(char const *name, char const **digname)
1266 EVP_MD const *digest;
1267 char const *cp;
1268 size_t i;
1269 NYD_ENTER;
1271 /* See comments in smime_sign_cert() for algorithm pitfalls */
1272 if (name != NULL) {
1273 struct name *np;
1275 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1276 int vs;
1277 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1278 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1279 cp = n_var_vlook(vn, FAL0);
1280 ac_free(vn);
1281 if (cp != NULL)
1282 goto jhave_name;
1286 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1287 digest = a_XSSL_SMIME_DEFAULT_DIGEST();
1288 *digname = a_XSSL_SMIME_DEFAULT_DIGEST_S;
1289 goto jleave;
1292 jhave_name:
1293 i = strlen(cp);
1294 { char *x = salloc(i +1);
1295 i_strcpy(x, cp, i +1);
1296 cp = x;
1298 *digname = cp;
1300 for (i = 0; i < n_NELEM(a_xssl_smime_digests); ++i)
1301 if (!asccasecmp(a_xssl_smime_digests[i].sd_name, cp)) {
1302 digest = (*a_xssl_smime_digests[i].sd_fun)();
1303 goto jleave;
1306 /* Not a built-in algorithm, but we may have dynamic support for more */
1307 #ifdef HAVE_SSL_ALL_ALGORITHMS
1308 if((digest = EVP_get_digestbyname(cp)) != NULL)
1309 goto jleave;
1310 #endif
1312 n_err(_("Invalid message digest: %s\n"), cp);
1313 digest = NULL;
1314 jleave:
1315 NYD_LEAVE;
1316 return digest;
1319 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1320 static enum okay
1321 load_crl1(X509_STORE *store, char const *name)
1323 X509_LOOKUP *lookup;
1324 enum okay rv = STOP;
1325 NYD_ENTER;
1327 if (n_poption & n_PO_D_V)
1328 n_err(_("Loading CRL from %s\n"), n_shexp_quote_cp(name, FAL0));
1329 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1330 ssl_gen_err(_("Error creating X509 lookup object"));
1331 goto jleave;
1333 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1334 ssl_gen_err(_("Error loading CRL from %s"), n_shexp_quote_cp(name, FAL0));
1335 goto jleave;
1337 rv = OKAY;
1338 jleave:
1339 NYD_LEAVE;
1340 return rv;
1342 #endif /* new OpenSSL */
1344 static enum okay
1345 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1347 char *crl_file, *crl_dir;
1348 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1349 DIR *dirp;
1350 struct dirent *dp;
1351 char *fn = NULL;
1352 int fs = 0, ds, es;
1353 #endif
1354 enum okay rv = STOP;
1355 NYD_ENTER;
1357 if ((crl_file = n_var_oklook(fok)) != NULL) {
1358 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1359 if ((crl_file = fexpand(crl_file, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1360 load_crl1(store, crl_file) != OKAY)
1361 goto jleave;
1362 #else
1363 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1364 goto jleave;
1365 #endif
1368 if ((crl_dir = n_var_oklook(dok)) != NULL) {
1369 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1370 char *x;
1371 if ((x = fexpand(crl_dir, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1372 (dirp = opendir(crl_dir = x)) == NULL) {
1373 n_perr(crl_dir, 0);
1374 goto jleave;
1377 ds = strlen(crl_dir);
1378 fn = smalloc(fs = ds + 20);
1379 memcpy(fn, crl_dir, ds);
1380 fn[ds] = '/';
1381 while ((dp = readdir(dirp)) != NULL) {
1382 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1383 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1384 continue;
1385 if (dp->d_name[0] == '.')
1386 continue;
1387 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1388 fn = srealloc(fn, fs = ds + es + 20);
1389 memcpy(fn + ds + 1, dp->d_name, es + 1);
1390 if (load_crl1(store, fn) != OKAY) {
1391 closedir(dirp);
1392 free(fn);
1393 goto jleave;
1396 closedir(dirp);
1397 free(fn);
1398 #else /* old OpenSSL */
1399 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1400 goto jleave;
1401 #endif
1403 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1404 if (crl_file || crl_dir)
1405 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1406 X509_V_FLAG_CRL_CHECK_ALL);
1407 #endif
1408 rv = OKAY;
1409 jleave:
1410 NYD_LEAVE;
1411 return rv;
1414 #if n_RANDOM_USE_XSSL
1415 FL void
1416 ssl_rand_bytes(void *buf, size_t blen){
1417 NYD_ENTER;
1419 if(!(a_xssl_state & a_XSSL_S_RAND_INIT) && a_xssl_rand_init())
1420 a_xssl_state |= a_XSSL_S_RAND_INIT;
1422 while(blen > 0){
1423 si32_t i;
1425 i = n_MIN(SI32_MAX, blen);
1426 blen -= i;
1427 RAND_bytes(buf, i);
1428 buf = (ui8_t*)buf + i;
1430 NYD_LEAVE;
1432 #endif
1434 FL enum okay
1435 ssl_open(struct url const *urlp, struct sock *sp)
1437 SSL_CTX *ctxp;
1438 void *confp;
1439 char const *cp, *cp_base;
1440 size_t i;
1441 enum okay rv = STOP;
1442 NYD_ENTER;
1444 a_xssl_init();
1446 ssl_set_verify_level(urlp);
1448 if ((ctxp = SSL_CTX_new(n_XSSL_CLIENT_METHOD())) == NULL) {
1449 ssl_gen_err(_("SSL_CTX_new() failed"));
1450 goto jleave;
1453 /* Available with OpenSSL 0.9.6 or later */
1454 #ifdef SSL_MODE_AUTO_RETRY
1455 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1456 #endif
1458 if ((confp = _ssl_conf_setup(ctxp)) == NULL)
1459 goto jerr0;
1461 /* TODO obsolete Check for *ssl-method*, warp to a *ssl-protocol* value */
1462 if ((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL) {
1463 n_OBSOLETE(_("please use *ssl-protocol* instead of *ssl-method*"));
1464 if (n_poption & n_PO_D_V)
1465 n_err(_("*ssl-method*: %s\n"), cp);
1466 for (i = 0;;) {
1467 if (!asccasecmp(_ssl_methods[i].sm_name, cp)) {
1468 cp = _ssl_methods[i].sm_map;
1469 break;
1471 if (++i == n_NELEM(_ssl_methods)) {
1472 n_err(_("Unsupported TLS/SSL method: %s\n"), cp);
1473 goto jerr1;
1477 /* *ssl-protocol* */
1478 if ((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL) {
1479 if (n_poption & n_PO_D_V)
1480 n_err(_("*ssl-protocol*: %s\n"), cp_base);
1481 cp = cp_base;
1483 cp = (cp != NULL ? savecatsep(cp, ',', n_XSSL_DISABLED_PROTOCOLS)
1484 : n_XSSL_DISABLED_PROTOCOLS);
1485 if (!_ssl_conf(confp, a_XSSL_CT_PROTOCOL, cp))
1486 goto jerr1;
1488 /* *ssl-cert* */
1489 if ((cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL) {
1490 if (n_poption & n_PO_D_V)
1491 n_err(_("*ssl-cert* %s\n"), n_shexp_quote_cp(cp, FAL0));
1492 if ((cp_base = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL) {
1493 n_err(_("*ssl-cert* value expansion failed: %s\n"),
1494 n_shexp_quote_cp(cp, FAL0));
1495 goto jerr1;
1497 cp = cp_base;
1498 if (!_ssl_conf(confp, a_XSSL_CT_CERTIFICATE, cp))
1499 goto jerr1;
1501 /* *ssl-key* */
1502 if ((cp_base = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL) {
1503 if (n_poption & n_PO_D_V)
1504 n_err(_("*ssl-key* %s\n"), n_shexp_quote_cp(cp_base, FAL0));
1505 if ((cp = fexpand(cp_base, FEXP_LOCAL | FEXP_NOPROTO)) == NULL) {
1506 n_err(_("*ssl-key* value expansion failed: %s\n"),
1507 n_shexp_quote_cp(cp_base, FAL0));
1508 goto jerr1;
1511 if (!_ssl_conf(confp, a_XSSL_CT_PRIVATE_KEY, cp))
1512 goto jerr1;
1515 if ((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL &&
1516 !_ssl_conf(confp, a_XSSL_CT_CIPHER_STRING, cp))
1517 goto jerr1;
1518 if ((cp = xok_vlook(ssl_curves, urlp, OXM_ALL)) != NULL &&
1519 !_ssl_conf(confp, a_XSSL_CT_CURVES, cp))
1520 goto jerr1;
1522 if (!_ssl_load_verifications(ctxp))
1523 goto jerr1;
1525 if (!_ssl_conf(confp, a_XSSL_CT_OPTIONS, NULL)) /* TODO *ssl-options* */
1526 goto jerr1;
1528 /* Done with context setup, create our new per-connection structure */
1529 if (!_ssl_conf_finish(&confp, FAL0))
1530 goto jerr0;
1532 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1533 ssl_gen_err(_("SSL_new() failed"));
1534 goto jerr0;
1537 /* Try establish SNI extension; even though this is a TLS extension the
1538 * protocol isn't checked once the host name is set, and therefore i've
1539 * refrained from changing so much code just to check out whether we are
1540 * using SSLv3, which should become rarer and rarer */
1541 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1542 if((urlp->url_flags & n_URL_TLS_MASK) &&
1543 (urlp->url_flags & n_URL_HOST_IS_NAME)){
1544 if(!SSL_set_tlsext_host_name(sp->s_ssl, urlp->url_host.s) &&
1545 (n_poption & n_PO_D_V))
1546 n_err(_("Hostname cannot be used with ServerNameIndication "
1547 "TLS extension: %s\n"),
1548 n_shexp_quote_cp(urlp->url_host.s, FAL0));
1550 #endif
1552 SSL_set_fd(sp->s_ssl, sp->s_fd);
1554 if (SSL_connect(sp->s_ssl) < 0) {
1555 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1556 goto jerr2;
1559 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1560 if (ssl_check_host(sp, urlp) != OKAY) {
1561 n_err(_("Host certificate does not match: %s\n"), urlp->url_h_p.s);
1562 if (ssl_verify_decide() != OKAY)
1563 goto jerr2;
1567 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1568 * and free it right now -- it is reference counted by sp->s_ssl.. */
1569 SSL_CTX_free(ctxp);
1570 sp->s_use_ssl = 1;
1571 rv = OKAY;
1572 jleave:
1573 NYD_LEAVE;
1574 return rv;
1575 jerr2:
1576 SSL_free(sp->s_ssl);
1577 sp->s_ssl = NULL;
1578 jerr1:
1579 if (confp != NULL)
1580 _ssl_conf_finish(&confp, TRU1);
1581 jerr0:
1582 SSL_CTX_free(ctxp);
1583 goto jleave;
1586 FL void
1587 ssl_gen_err(char const *fmt, ...)
1589 va_list ap;
1590 NYD_ENTER;
1592 va_start(ap, fmt);
1593 n_verr(fmt, ap);
1594 va_end(ap);
1596 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1597 NYD_LEAVE;
1600 FL int
1601 c_verify(void *vp)
1603 int *msgvec = vp, *ip, ec = 0, rv = 1;
1604 X509_STORE *store = NULL;
1605 char *ca_dir, *ca_file;
1606 NYD_ENTER;
1608 a_xssl_init();
1610 ssl_verify_level = SSL_VERIFY_STRICT;
1611 if ((store = X509_STORE_new()) == NULL) {
1612 ssl_gen_err(_("Error creating X509 store"));
1613 goto jleave;
1615 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1617 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1618 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
1619 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1620 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
1622 if (ca_dir != NULL || ca_file != NULL) {
1623 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
1624 ssl_gen_err(_("Error loading %s"),
1625 (ca_file != NULL) ? ca_file : ca_dir);
1626 goto jleave;
1630 /* C99 */{
1631 bool_t xv15;
1633 if((xv15 = ok_blook(smime_no_default_ca)))
1634 n_OBSOLETE(_("please use *smime-ca-no-defaults*, "
1635 "not *smime-no-default-ca*"));
1636 if(!ok_blook(smime_ca_no_defaults) && !xv15 &&
1637 X509_STORE_set_default_paths(store) != 1) {
1638 ssl_gen_err(_("Error loading built-in default CA locations\n"));
1639 goto jleave;
1643 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1644 goto jleave;
1646 a_xssl_ca_flags(store, ok_vlook(smime_ca_flags));
1648 srelax_hold();
1649 for (ip = msgvec; *ip != 0; ++ip) {
1650 struct message *mp = message + *ip - 1;
1651 setdot(mp);
1652 ec |= smime_verify(mp, *ip, NULL, store);
1653 srelax();
1655 srelax_rele();
1657 if ((rv = ec) != 0)
1658 n_exit_status |= n_EXIT_ERR;
1659 jleave:
1660 if (store != NULL)
1661 X509_STORE_free(store);
1662 NYD_LEAVE;
1663 return rv;
1666 FL FILE *
1667 smime_sign(FILE *ip, char const *addr)
1669 FILE *rv, *sp, *fp, *bp, *hp;
1670 X509 *cert = NULL;
1671 n_XSSL_STACKOF(X509) *chain = NULL;
1672 EVP_PKEY *pkey = NULL;
1673 BIO *bb, *sb;
1674 PKCS7 *pkcs7;
1675 EVP_MD const *md;
1676 char const *name;
1677 bool_t bail = FAL0;
1678 NYD_ENTER;
1680 assert(addr != NULL);
1681 rv = sp = fp = bp = hp = NULL;
1683 a_xssl_init();
1685 if (addr == NULL) {
1686 n_err(_("No *from* address for signing specified\n"));
1687 goto jleave;
1689 if ((fp = smime_sign_cert(addr, NULL, 1, NULL)) == NULL)
1690 goto jleave;
1692 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb,
1693 savecat(addr, ".smime-cert-key"))) == NULL) {
1694 ssl_gen_err(_("Error reading private key from"));
1695 goto jleave;
1698 rewind(fp);
1699 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb,
1700 savecat(addr, ".smime-cert-cert"))) == NULL) {
1701 ssl_gen_err(_("Error reading signer certificate from"));
1702 goto jleave;
1704 Fclose(fp);
1705 fp = NULL;
1707 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1708 !_smime_sign_include_chain_creat(&chain, name,
1709 savecat(addr, ".smime-include-certs")))
1710 goto jleave;
1712 name = NULL;
1713 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1714 goto jleave;
1716 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1717 NULL) {
1718 n_perr(_("tempfile"), 0);
1719 goto jleave;
1722 rewind(ip);
1723 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1724 goto jleave;
1726 sb = NULL;
1727 pkcs7 = NULL;
1729 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1730 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1731 ssl_gen_err(_("Error creating BIO signing objects"));
1732 bail = TRU1;
1733 goto jerr;
1736 #undef _X
1737 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1738 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1739 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1740 bail = TRU1;
1741 goto jerr;
1743 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1744 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1745 bail = TRU1;
1746 goto jerr;
1748 if (!PKCS7_final(pkcs7, bb, _X)) {
1749 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1750 bail = TRU1;
1751 goto jerr;
1753 #undef _X
1755 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1756 ssl_gen_err(_("Error writing signed S/MIME data"));
1757 bail = TRU1;
1758 /*goto jerr*/
1760 jerr:
1761 if (pkcs7 != NULL)
1762 PKCS7_free(pkcs7);
1763 if (sb != NULL)
1764 BIO_free(sb);
1765 if (bb != NULL)
1766 BIO_free(bb);
1767 if (!bail) {
1768 rewind(bp);
1769 fflush_rewind(sp);
1770 rv = smime_sign_assemble(hp, bp, sp, name);
1771 hp = bp = sp = NULL;
1774 jleave:
1775 if (chain != NULL)
1776 sk_X509_pop_free(chain, X509_free);
1777 if (cert != NULL)
1778 X509_free(cert);
1779 if (pkey != NULL)
1780 EVP_PKEY_free(pkey);
1781 if (fp != NULL)
1782 Fclose(fp);
1783 if (hp != NULL)
1784 Fclose(hp);
1785 if (bp != NULL)
1786 Fclose(bp);
1787 if (sp != NULL)
1788 Fclose(sp);
1789 NYD_LEAVE;
1790 return rv;
1793 FL FILE *
1794 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1796 FILE *rv, *yp, *fp, *bp, *hp;
1797 X509 *cert;
1798 PKCS7 *pkcs7;
1799 BIO *bb, *yb;
1800 n_XSSL_STACKOF(X509) *certs;
1801 EVP_CIPHER const *cipher;
1802 char *certfile;
1803 bool_t bail;
1804 NYD_ENTER;
1806 bail = FAL0;
1807 rv = yp = fp = bp = hp = NULL;
1809 if ((certfile = fexpand(xcertfile, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
1810 goto jleave;
1812 a_xssl_init();
1814 if ((cipher = _smime_cipher(to)) == NULL)
1815 goto jleave;
1817 if ((fp = Fopen(certfile, "r")) == NULL) {
1818 n_perr(certfile, 0);
1819 goto jleave;
1821 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1822 ssl_gen_err(_("Error reading encryption certificate from %s"),
1823 n_shexp_quote_cp(certfile, FAL0));
1824 bail = TRU1;
1826 if (bail)
1827 goto jleave;
1828 Fclose(fp);
1829 fp = NULL;
1830 bail = FAL0;
1832 certs = sk_X509_new_null();
1833 sk_X509_push(certs, cert);
1835 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1836 NULL) {
1837 n_perr(_("tempfile"), 0);
1838 goto jerr1;
1841 rewind(ip);
1842 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1843 goto jerr1;
1845 yb = NULL;
1846 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1847 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1848 ssl_gen_err(_("Error creating BIO encryption objects"));
1849 bail = TRU1;
1850 goto jerr2;
1852 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1853 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
1854 bail = TRU1;
1855 goto jerr2;
1857 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1858 ssl_gen_err(_("Error writing encrypted S/MIME data"));
1859 bail = TRU1;
1860 /* goto jerr2 */
1862 PKCS7_free(pkcs7);
1864 jerr2:
1865 if (bb != NULL)
1866 BIO_free(bb);
1867 if (yb != NULL)
1868 BIO_free(yb);
1869 Fclose(bp);
1870 bp = NULL;
1871 if (!bail) {
1872 fflush_rewind(yp);
1873 rv = smime_encrypt_assemble(hp, yp);
1874 hp = yp = NULL;
1876 jerr1:
1877 sk_X509_pop_free(certs, X509_free);
1878 jleave:
1879 if(yp != NULL)
1880 Fclose(yp);
1881 if(fp != NULL)
1882 Fclose(fp);
1883 if(bp != NULL)
1884 Fclose(bp);
1885 if(hp != NULL)
1886 Fclose(hp);
1887 NYD_LEAVE;
1888 return rv;
1891 FL struct message *
1892 smime_decrypt(struct message *m, char const *to, char const *cc,
1893 bool_t signcall)
1895 char const *myaddr;
1896 long size;
1897 struct message *rv;
1898 FILE *bp, *hp, *op;
1899 PKCS7 *pkcs7;
1900 BIO *ob, *bb, *pb;
1901 X509 *cert;
1902 EVP_PKEY *pkey;
1903 FILE *yp;
1904 NYD_ENTER;
1906 pkey = NULL;
1907 cert = NULL;
1908 ob = bb = pb = NULL;
1909 pkcs7 = NULL;
1910 bp = hp = op = NULL;
1911 rv = NULL;
1912 size = m->m_size;
1914 if((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1915 goto jleave;
1917 a_xssl_init();
1919 if((op = smime_sign_cert(to, cc, 0, &myaddr)) != NULL){
1920 pkey = PEM_read_PrivateKey(op, NULL, &ssl_password_cb,
1921 savecat(myaddr, ".smime-cert-key"));
1922 if(pkey == NULL){
1923 ssl_gen_err(_("Error reading private key"));
1924 goto jleave;
1927 rewind(op);
1928 if((cert = PEM_read_X509(op, NULL, &ssl_password_cb,
1929 savecat(myaddr, ".smime-cert-cert"))) == NULL){
1930 ssl_gen_err(_("Error reading decryption certificate"));
1931 goto jleave;
1934 Fclose(op);
1935 op = NULL;
1938 if((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
1939 n_perr(_("tempfile"), 0);
1940 goto jleave;
1943 if(smime_split(yp, &hp, &bp, size, 1) == STOP)
1944 goto jleave;
1946 if((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1947 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL){
1948 ssl_gen_err(_("Error creating BIO decryption objects"));
1949 goto jleave;
1952 if((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL){
1953 ssl_gen_err(_("Error reading PKCS#7 object"));
1954 goto jleave;
1957 if(PKCS7_type_is_signed(pkcs7)){
1958 if(signcall){
1959 setinput(&mb, m, NEED_BODY);
1960 rv = (struct message*)-1;
1961 goto jleave;
1963 if(PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1964 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1965 goto jerr;
1966 fseek(hp, 0L, SEEK_END);
1967 fprintf(hp, "X-Encryption-Cipher: none\n");
1968 fflush_rewind(hp);
1969 }else if(pkey == NULL){
1970 n_err(_("No appropriate private key found\n"));
1971 goto jleave;
1972 }else if(cert == NULL){
1973 n_err(_("No appropriate certificate found\n"));
1974 goto jleave;
1975 }else if(PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1){
1976 jerr:
1977 ssl_gen_err(_("Error decrypting PKCS#7 object"));
1978 goto jleave;
1980 fflush_rewind(op);
1981 Fclose(bp);
1982 bp = NULL;
1984 rv = smime_decrypt_assemble(m, hp, op);
1985 hp = op = NULL; /* xxx closed by decrypt_assemble */
1986 jleave:
1987 if(op != NULL)
1988 Fclose(op);
1989 if(hp != NULL)
1990 Fclose(hp);
1991 if(bp != NULL)
1992 Fclose(bp);
1993 if(bb != NULL)
1994 BIO_free(bb);
1995 if(ob != NULL)
1996 BIO_free(ob);
1997 if(pkcs7 != NULL)
1998 PKCS7_free(pkcs7);
1999 if(cert != NULL)
2000 X509_free(cert);
2001 if(pkey != NULL)
2002 EVP_PKEY_free(pkey);
2003 NYD_LEAVE;
2004 return rv;
2007 FL enum okay
2008 smime_certsave(struct message *m, int n, FILE *op)
2010 struct message *x;
2011 char *to, *cc, *cnttype;
2012 int c, i;
2013 FILE *fp, *ip;
2014 off_t size;
2015 BIO *fb, *pb;
2016 PKCS7 *pkcs7;
2017 n_XSSL_STACKOF(X509) *certs, *chain = NULL;
2018 X509 *cert;
2019 enum okay rv = STOP;
2020 NYD_ENTER;
2022 pkcs7 = NULL;
2024 a_xssl_msgno = (size_t)n;
2025 jloop:
2026 to = hfield1("to", m);
2027 cc = hfield1("cc", m);
2028 cnttype = hfield1("content-type", m);
2030 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
2031 goto jleave;
2033 #undef _X
2034 #undef _Y
2035 #define _X (sizeof("application/") -1)
2036 #define _Y(X) X, sizeof(X) -1
2037 if (cnttype && is_asccaseprefix("application/", cnttype) &&
2038 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
2039 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
2040 #undef _Y
2041 #undef _X
2042 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
2043 goto jleave;
2044 if (x != (struct message*)-1) {
2045 m = x;
2046 goto jloop;
2049 size = m->m_size;
2051 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
2052 NULL) {
2053 n_perr(_("tempfile"), 0);
2054 goto jleave;
2057 while (size-- > 0) {
2058 c = getc(ip);
2059 putc(c, fp);
2061 fflush(fp);
2063 rewind(fp);
2064 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
2065 ssl_gen_err("Error creating BIO object for message %d", n);
2066 Fclose(fp);
2067 goto jleave;
2070 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
2071 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
2072 BIO_free(fb);
2073 Fclose(fp);
2074 goto jleave;
2076 BIO_free(fb);
2077 Fclose(fp);
2079 certs = PKCS7_get0_signers(pkcs7, chain, 0);
2080 if (certs == NULL) {
2081 n_err(_("No certificates found in message %d\n"), n);
2082 goto jleave;
2085 for (i = 0; i < sk_X509_num(certs); ++i) {
2086 cert = sk_X509_value(certs, i);
2087 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
2088 ssl_gen_err(_("Error writing certificate %d from message %d"),
2089 i, n);
2090 goto jleave;
2093 rv = OKAY;
2094 jleave:
2095 if(pkcs7 != NULL)
2096 PKCS7_free(pkcs7);
2097 NYD_LEAVE;
2098 return rv;
2100 #endif /* HAVE_XSSL */
2102 /* s-it-mode */