Tweak previous, it added a bad memory access
[s-mailx.git] / xssl.c
blob94f7b4518217a61465b900a32dcfe6e3493254e5
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_PRIVATE_KEY,
173 a_XSSL_CT_OPTIONS,
174 a_XSSL_CT_PROTOCOL
177 struct ssl_method { /* TODO v15 obsolete */
178 char const sm_name[8];
179 char const sm_map[16];
182 #ifndef HAVE_XSSL_CONF_CTX
183 struct a_xssl_protocol{
184 char const *sp_name;
185 sl_i sp_flag;
187 #endif
189 struct a_xssl_smime_cipher{
190 char const sc_name[8];
191 EVP_CIPHER const *(*sc_fun)(void);
194 struct a_xssl_smime_digest{
195 char const sd_name[8];
196 EVP_MD const *(*sd_fun)(void);
199 struct a_xssl_x509_v_flags{
200 char const xvf_name[20];
201 si32_t xvf_flag;
204 /* Supported SSL/TLS methods: update manual on change! */
206 static struct ssl_method const _ssl_methods[] = { /* TODO obsolete */
207 {"auto", "ALL,-SSLv2"},
208 {"ssl3", "-ALL,SSLv3"},
209 {"tls1", "-ALL,TLSv1"},
210 {"tls1.1", "-ALL,TLSv1.1"},
211 {"tls1.2", "-ALL,TLSv1.2"}
214 /* Update manual on change! */
215 #ifndef HAVE_XSSL_CONF_CTX
216 static struct a_xssl_protocol const a_xssl_protocols[] = {
217 {"ALL", SSL_OP_NO_SSL_MASK},
218 {"TLSv1.2", SSL_OP_NO_TLSv1_2},
219 {"TLSv1.1", SSL_OP_NO_TLSv1_1},
220 {"TLSv1", SSL_OP_NO_TLSv1},
221 {"SSLv3", SSL_OP_NO_SSLv3},
222 {"SSLv2", 0}
224 #endif
226 /* Supported S/MIME cipher algorithms */
227 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers[] = { /* Manual! */
228 #ifndef OPENSSL_NO_AES
229 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_aes_128_cbc /* According to RFC 5751 */
230 {"aes128", &EVP_aes_128_cbc},
231 {"aes256", &EVP_aes_256_cbc},
232 {"aes192", &EVP_aes_192_cbc},
233 #endif
234 #ifndef OPENSSL_NO_DES
235 # ifndef a_XSSL_SMIME_DEFAULT_CIPHER
236 # define a_XSSL_SMIME_DEFAULT_CIPHER EVP_des_ede3_cbc
237 # endif
238 {"des3", &EVP_des_ede3_cbc},
239 {"des", &EVP_des_cbc},
240 #endif
242 #ifndef a_XSSL_SMIME_DEFAULT_CIPHER
243 # error Your OpenSSL library does not include the necessary
244 # error cipher algorithms that are required to support S/MIME
245 #endif
247 #ifndef OPENSSL_NO_AES
248 /* TODO obsolete a_xssl_smime_ciphers_obs */
249 static struct a_xssl_smime_cipher const a_xssl_smime_ciphers_obs[] = {
250 {"aes-128", &EVP_aes_128_cbc},
251 {"aes-256", &EVP_aes_256_cbc},
252 {"aes-192", &EVP_aes_192_cbc}
254 #endif
256 /* Supported S/MIME message digest algorithms */
257 static struct a_xssl_smime_digest const a_xssl_smime_digests[] = { /* Manual! */
258 #define a_XSSL_SMIME_DEFAULT_DIGEST EVP_sha1 /* According to RFC 5751 */
259 #define a_XSSL_SMIME_DEFAULT_DIGEST_S "sha1"
260 {"sha1", &EVP_sha1},
261 {"sha256", &EVP_sha256},
262 {"sha512", &EVP_sha512},
263 {"sha384", &EVP_sha384},
264 {"sha224", &EVP_sha224},
265 #ifndef OPENSSL_NO_MD5
266 {"md5", &EVP_md5},
267 #endif
270 /* X509_STORE_set_flags() for *{smime,ssl}-ca-flags* */
271 static struct a_xssl_x509_v_flags const a_xssl_x509_v_flags[] = { /* Manual! */
272 {"no-alt-chains", X509_V_FLAG_NO_ALT_CHAINS},
273 {"no-check-time", X509_V_FLAG_NO_CHECK_TIME},
274 {"partial-chain", X509_V_FLAG_PARTIAL_CHAIN},
275 {"strict", X509_V_FLAG_X509_STRICT},
276 {"trusted-first", X509_V_FLAG_TRUSTED_FIRST},
279 static enum a_xssl_state a_xssl_state;
280 static size_t a_xssl_msgno;
282 static bool_t a_xssl_rand_init(void);
283 #if HAVE_XSSL_OPENSSL < 0x10100
284 # ifdef HAVE_SSL_ALL_ALGORITHMS
285 static void a_xssl__load_algos(void);
286 # define a_xssl_load_algos a_xssl__load_algos
287 # endif
288 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
289 static void a_xssl_atexit(void);
290 # endif
291 #endif
292 #ifndef a_xssl_load_algos
293 # define a_xssl_load_algos() do{;}while(0)
294 #endif
296 static bool_t _ssl_parse_asn1_time(ASN1_TIME const *atp,
297 char *bdat, size_t blen);
298 static int _ssl_verify_cb(int success, X509_STORE_CTX *store);
300 /* *smime-ca-flags*, *ssl-ca-flags* */
301 static void a_xssl_ca_flags(X509_STORE *store, char const *flags);
303 /* SSL_CTX configuration */
304 static void * _ssl_conf_setup(SSL_CTX *ctxp);
305 static bool_t _ssl_conf(void *confp, enum a_xssl_conf_type ct,
306 char const *value);
307 static bool_t _ssl_conf_finish(void **confp, bool_t error);
309 static bool_t _ssl_load_verifications(SSL_CTX *ctxp);
311 static enum okay ssl_check_host(struct sock *sp, struct url const *urlp);
313 static int smime_verify(struct message *m, int n,
314 n_XSSL_STACKOF(X509) *chain, X509_STORE *store);
315 static EVP_CIPHER const * _smime_cipher(char const *name);
316 static int ssl_password_cb(char *buf, int size, int rwflag,
317 void *userdata);
318 static FILE * smime_sign_cert(char const *xname, char const *xname2,
319 bool_t dowarn, char const **match);
320 static char const * _smime_sign_include_certs(char const *name);
321 static bool_t _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
322 char const *cfiles, char const *addr);
323 static EVP_MD const * _smime_sign_digest(char const *name,
324 char const **digname);
325 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
326 static enum okay load_crl1(X509_STORE *store, char const *name);
327 #endif
328 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
330 static bool_t
331 a_xssl_rand_init(void){
332 char const *cp, *x;
333 bool_t rv;
334 NYD_ENTER;
336 rv = FAL0;
338 /* Shall use some external daemon? */ /* TODO obsolete *ssl_rand_egd* */
339 if((cp = ok_vlook(ssl_rand_egd)) != NULL){ /* TODO no one supports it now! */
340 n_OBSOLETE(_("all *SSL libraries removed *ssl-rand-egd* support"));
341 #ifdef HAVE_XSSL_RAND_EGD
342 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) != NULL &&
343 RAND_egd(cp = x) != -1){
344 rv = TRU1;
345 goto jleave;
347 n_err(_("*ssl_rand_egd* daemon at %s not available\n"),
348 n_shexp_quote_cp(cp, FAL0));
349 #else
350 if(n_poption & n_PO_D_VV)
351 n_err(_("*ssl_rand_egd* (%s): unsupported by SSL library\n"),
352 n_shexp_quote_cp(cp, FAL0));
353 #endif
356 /* Prefer possible user setting */
357 if((cp = ok_vlook(ssl_rand_file)) != NULL){
358 x = NULL;
359 if(*cp != '\0'){
360 if((x = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
361 n_err(_("*ssl-rand-file*: filename expansion of %s failed\n"),
362 n_shexp_quote_cp(cp, FAL0));
364 cp = x;
367 /* If the SSL PRNG is initialized don't put any more effort in this if the
368 * user defined entropy isn't usable */
369 if(cp == NULL){
370 if(RAND_status()){
371 rv = TRU1;
372 goto jleave;
375 if((cp = RAND_file_name(salloc(PATH_MAX), PATH_MAX)) == NULL){
376 n_err(_("*ssl-rand-file*: no SSL entropy file, can't seed PRNG\n"));
377 goto jleave;
381 if(RAND_load_file(cp, a_XSSL_RAND_LOAD_FILE_MAXBYTES) != -1){
382 for(x = (char*)-1;;){
383 RAND_seed(n_random_create_cp(32), 32);
384 if((rv = (RAND_status() != 0)))
385 break;
386 if((x = (char*)((uintptr_t)x >> 1)) == NULL){
387 n_err(_("*ssl-rand-file*: can't seed SSL PRNG with entropy\n"));
388 goto jleave;
392 if(RAND_write_file(cp) == -1)
393 n_err(_("*ssl-rand-file*: writing entropy to %s failed\n"),
394 n_shexp_quote_cp(cp, FAL0));
395 }else
396 n_err(_("*ssl-rand-file*: %s cannot be loaded\n"),
397 n_shexp_quote_cp(cp, FAL0));
398 jleave:
399 NYD_LEAVE;
400 return rv;
403 static void
404 a_xssl_init(void)
406 #ifdef HAVE_XSSL_CONFIG
407 char const *cp;
408 #endif
409 NYD_ENTER;
411 if(!(a_xssl_state & a_XSSL_S_INIT)){
412 #if HAVE_XSSL_OPENSSL >= 0x10100
413 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS |
414 OPENSSL_INIT_LOAD_CRYPTO_STRINGS
415 # ifdef HAVE_SSL_ALL_ALGORITHMS
416 | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS
417 # endif
418 , NULL);
419 # ifdef HAVE_SSL_ALL_ALGORITHMS
420 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
421 # endif
422 #else
423 SSL_load_error_strings();
424 SSL_library_init();
425 #endif
426 a_xssl_state |= a_XSSL_S_INIT;
429 /* Load openssl.cnf or whatever was given in *ssl-config-file* */
430 #ifdef HAVE_XSSL_CONFIG
431 if(!(a_xssl_state & a_XSSL_S_CONF_LOAD) &&
432 (cp = ok_vlook(ssl_config_file)) != NULL){
433 ul_i flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
435 if(*cp == '\0'){
436 cp = NULL;
437 flags = 0;
439 if(CONF_modules_load_file(cp, n_uagent, flags) == 1){
440 a_xssl_state |= a_XSSL_S_CONF_LOAD;
441 # if HAVE_XSSL_OPENSSL < 0x10100
442 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
443 a_xssl_state |= a_XSSL_S_EXIT_HDL;
444 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
446 # endif
447 }else
448 ssl_gen_err(_("Ignoring CONF_modules_load_file() load error"));
450 #endif
452 if(!(a_xssl_state & a_XSSL_S_RAND_INIT) && a_xssl_rand_init())
453 a_xssl_state |= a_XSSL_S_RAND_INIT;
454 NYD_LEAVE;
457 #if HAVE_XSSL_OPENSSL < 0x10100
458 # ifdef HAVE_SSL_ALL_ALGORITHMS
459 static void
460 a_xssl__load_algos(void){
461 NYD2_ENTER;
462 if(!(a_xssl_state & a_XSSL_S_ALGO_LOAD)){
463 a_xssl_state |= a_XSSL_S_ALGO_LOAD;
464 OpenSSL_add_all_algorithms();
466 if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
467 a_xssl_state |= a_XSSL_S_EXIT_HDL;
468 atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
471 NYD2_LEAVE;
473 # endif
475 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
476 static void
477 a_xssl_atexit(void){
478 NYD2_ENTER;
479 # ifdef HAVE_XSSL_CONFIG
480 if(a_xssl_state & a_XSSL_S_CONF_LOAD)
481 CONF_modules_free();
482 # endif
484 # ifdef HAVE_SSL_ALL_ALGORITHMS
485 if(a_xssl_state & a_XSSL_S_ALGO_LOAD)
486 EVP_cleanup();
487 # endif
488 NYD2_LEAVE;
490 # endif
491 #endif /* HAVE_XSSL_OPENSSL < 0x10100 */
493 static bool_t
494 _ssl_parse_asn1_time(ASN1_TIME const *atp, char *bdat, size_t blen)
496 BIO *mbp;
497 char *mcp;
498 long l;
499 NYD_ENTER;
501 mbp = BIO_new(BIO_s_mem());
503 if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
504 snprintf(bdat, blen, "%.*s", (int)l, mcp);
505 else {
506 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
507 /*is (int)*/atp->length, (char const*)atp->data);
508 mcp = NULL;
511 BIO_free(mbp);
512 NYD_LEAVE;
513 return (mcp != NULL);
516 static int
517 _ssl_verify_cb(int success, X509_STORE_CTX *store)
519 char data[256];
520 X509 *cert;
521 int rv = TRU1;
522 NYD_ENTER;
524 if (success && !(n_poption & n_PO_D_V))
525 goto jleave;
527 if (a_xssl_msgno != 0) {
528 n_err(_("Message %lu:\n"), (ul_i)a_xssl_msgno);
529 a_xssl_msgno = 0;
531 n_err(_(" Certificate depth %d %s\n"),
532 X509_STORE_CTX_get_error_depth(store), (success ? n_empty : V_(n_error)));
534 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
535 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
536 n_err(_(" subject = %s\n"), data);
538 _ssl_parse_asn1_time(a_xssl_X509_get_notBefore(cert), data, sizeof data);
539 n_err(_(" notBefore = %s\n"), data);
541 _ssl_parse_asn1_time(a_xssl_X509_get_notAfter(cert), data, sizeof data);
542 n_err(_(" notAfter = %s\n"), data);
544 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
545 n_err(_(" issuer = %s\n"), data);
548 if (!success) {
549 int err = X509_STORE_CTX_get_error(store);
551 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
552 a_xssl_state |= a_XSSL_S_VERIFY_ERROR;
555 if (!success && ssl_verify_decide() != OKAY)
556 rv = FAL0;
557 jleave:
558 NYD_LEAVE;
559 return rv;
562 static void
563 a_xssl_ca_flags(X509_STORE *store, char const *flags){
564 NYD2_ENTER;
565 if(flags != NULL){
566 char *iolist, *cp;
568 iolist = savestr(flags);
569 jouter:
570 while((cp = n_strsep(&iolist, ',', TRU1)) != NULL){
571 struct a_xssl_x509_v_flags const *xvfp;
573 for(xvfp = &a_xssl_x509_v_flags[0];
574 xvfp < &a_xssl_x509_v_flags[n_NELEM(a_xssl_x509_v_flags)];
575 ++xvfp)
576 if(!asccasecmp(cp, xvfp->xvf_name)){
577 if(xvfp->xvf_flag != -1){
578 #ifdef a_XSSL_X509_V_ANY
579 X509_STORE_set_flags(store, xvfp->xvf_flag);
580 #endif
581 }else if(n_poption & n_PO_D_V)
582 n_err(_("*{smime,ssl}-ca-flags*: "
583 "directive not supported: %s\n"), cp);
584 goto jouter;
586 n_err(_("*{smime,ssl}-ca-flags*: invalid directive: %s\n"), cp);
589 NYD2_LEAVE;
592 #ifdef HAVE_XSSL_CONF_CTX
593 static void *
594 _ssl_conf_setup(SSL_CTX *ctxp)
596 SSL_CONF_CTX *sccp;
597 NYD_ENTER;
599 if ((sccp = SSL_CONF_CTX_new()) != NULL) {
600 SSL_CONF_CTX_set_flags(sccp,
601 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
602 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
604 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
605 } else
606 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
608 NYD_LEAVE;
609 return sccp;
612 static bool_t
613 _ssl_conf(void *confp, enum a_xssl_conf_type ct, char const *value)
615 int rv;
616 char const *cmsg;
617 SSL_CONF_CTX *sccp = (SSL_CONF_CTX*)confp;
618 NYD_ENTER;
620 switch (ct) {
621 case a_XSSL_CT_CERTIFICATE:
622 cmsg = "ssl-cert";
623 rv = SSL_CONF_cmd(sccp, "Certificate", value);
624 break;
625 case a_XSSL_CT_CIPHER_STRING:
626 cmsg = "ssl-cipher-list";
627 rv = SSL_CONF_cmd(sccp, "CipherString", value);
628 break;
629 case a_XSSL_CT_PRIVATE_KEY:
630 cmsg = "ssl-key";
631 rv = SSL_CONF_cmd(sccp, "PrivateKey", value);
632 break;
633 default:
634 case a_XSSL_CT_OPTIONS:
635 cmsg = "ssl-options";
636 rv = SSL_CONF_cmd(sccp, "Options", "Bugs");
637 break;
638 case a_XSSL_CT_PROTOCOL:
639 cmsg = "ssl-protocol";
640 rv = SSL_CONF_cmd(sccp, "Protocol", value);
641 break;
644 if (rv == 2)
645 rv = 0;
646 else {
647 if (rv == 0)
648 ssl_gen_err(_("SSL_CONF_CTX_cmd() failed for *%s*"), cmsg);
649 else
650 n_err(_("%s: *%s* implementation error, please report this\n"),
651 n_uagent, cmsg);
652 rv = 1;
655 NYD_LEAVE;
656 return (rv == 0);
659 static bool_t
660 _ssl_conf_finish(void **confp, bool_t error)
662 SSL_CONF_CTX **sccp = (SSL_CONF_CTX**)confp;
663 bool_t rv;
664 NYD_ENTER;
666 if (!(rv = error))
667 rv = (SSL_CONF_CTX_finish(*sccp) != 0);
669 SSL_CONF_CTX_free(*sccp);
671 *sccp = NULL;
672 NYD_LEAVE;
673 return rv;
676 #else /* HAVE_XSSL_CONF_CTX */
677 static void *
678 _ssl_conf_setup(SSL_CTX* ctxp)
680 return ctxp;
683 static bool_t
684 _ssl_conf(void *confp, enum a_xssl_conf_type ct, char const *value)
686 SSL_CTX *ctxp = (SSL_CTX*)confp;
687 NYD_ENTER;
689 switch (ct) {
690 case a_XSSL_CT_CERTIFICATE:
691 if (SSL_CTX_use_certificate_chain_file(ctxp, value) != 1) {
692 ssl_gen_err(_("Can't load certificate from file %s\n"),
693 n_shexp_quote_cp(value, FAL0));
694 confp = NULL;
696 break;
697 case a_XSSL_CT_CIPHER_STRING:
698 if (SSL_CTX_set_cipher_list(ctxp, value) != 1) {
699 ssl_gen_err(_("Invalid cipher string: %s\n"), value);
700 confp = NULL;
702 break;
703 case a_XSSL_CT_PRIVATE_KEY:
704 if (SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1) {
705 ssl_gen_err(_("Can't load private key from file %s\n"),
706 n_shexp_quote_cp(value, FAL0));
707 confp = NULL;
709 break;
710 case a_XSSL_CT_OPTIONS:
711 /* "Options"="Bugs" TODO *ssl-options* */
712 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
713 break;
714 case a_XSSL_CT_PROTOCOL: {
715 char *iolist, *cp, addin;
716 size_t i;
717 sl_i opts = 0;
719 confp = NULL;
720 for (iolist = cp = savestr(value);
721 (cp = n_strsep(&iolist, ',', FAL0)) != NULL;) {
722 if (*cp == '\0') {
723 n_err(_("*ssl-protocol*: empty arguments are not supported\n"));
724 goto jleave;
727 addin = TRU1;
728 switch (cp[0]) {
729 case '-': addin = FAL0; /* FALLTHRU */
730 case '+': ++cp; /* FALLTHRU */
731 default : break;
734 for (i = 0;;) {
735 if (!asccasecmp(cp, a_xssl_protocols[i].sp_name)) {
736 /* We need to inverse the meaning of the _NO_s */
737 if (!addin)
738 opts |= a_xssl_protocols[i].sp_flag;
739 else
740 opts &= ~a_xssl_protocols[i].sp_flag;
741 break;
743 if (++i < n_NELEM(a_xssl_protocols))
744 continue;
745 n_err(_("*ssl-protocol*: unsupported value: %s\n"), cp);
746 goto jleave;
749 confp = ctxp;
750 SSL_CTX_set_options(ctxp, opts);
751 break;
754 jleave:
755 NYD_LEAVE;
756 return (confp != NULL);
759 static bool_t
760 _ssl_conf_finish(void **confp, bool_t error)
762 n_UNUSED(confp);
763 n_UNUSED(error);
764 return TRU1;
766 #endif /* !HAVE_XSSL_CONF_CTX */
768 static bool_t
769 _ssl_load_verifications(SSL_CTX *ctxp)
771 char *ca_dir, *ca_file;
772 X509_STORE *store;
773 bool_t rv = FAL0;
774 NYD_ENTER;
776 if (ssl_verify_level == SSL_VERIFY_IGNORE) {
777 rv = TRU1;
778 goto jleave;
781 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
782 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
783 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
784 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
786 if ((ca_dir != NULL || ca_file != NULL) &&
787 SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1) {
788 char const *m1, *m2, *m3;
790 if (ca_dir != NULL) {
791 m1 = ca_dir;
792 m2 = (ca_file != NULL) ? _(" or ") : n_empty;
793 } else
794 m1 = m2 = n_empty;
795 m3 = (ca_file != NULL) ? ca_file : n_empty;
796 ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
797 goto jleave;
800 /* C99 */{
801 bool_t xv15;
803 if((xv15 = ok_blook(ssl_no_default_ca)))
804 n_OBSOLETE(_("please use *ssl-ca-no-defaults*, "
805 "not *ssl-no-default-ca*"));
806 if(!ok_blook(ssl_ca_no_defaults) && !xv15 &&
807 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
808 ssl_gen_err(_("Error loading builtin default CA locations\n"));
809 goto jleave;
813 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
814 a_xssl_msgno = 0;
815 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
816 store = SSL_CTX_get_cert_store(ctxp);
817 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
818 a_xssl_ca_flags(store, ok_vlook(ssl_ca_flags));
820 rv = TRU1;
821 jleave:
822 NYD_LEAVE;
823 return rv;
826 static enum okay
827 ssl_check_host(struct sock *sp, struct url const *urlp)
829 char data[256];
830 X509 *cert;
831 n_XSSL_STACKOF(GENERAL_NAME) *gens;
832 GENERAL_NAME *gen;
833 X509_NAME *subj;
834 enum okay rv = STOP;
835 NYD_ENTER;
837 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
838 n_err(_("No certificate from: %s\n"), urlp->url_h_p.s);
839 goto jleave;
842 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
843 if (gens != NULL) {
844 int i;
846 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
847 gen = sk_GENERAL_NAME_value(gens, i);
848 if (gen->type == GEN_DNS) {
849 if (n_poption & n_PO_D_V)
850 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
851 urlp->url_host.s, (char*)gen->d.ia5->data);
852 rv = rfc2595_hostname_match(urlp->url_host.s,
853 (char*)gen->d.ia5->data);
854 if (rv == OKAY)
855 goto jdone;
860 if ((subj = X509_get_subject_name(cert)) != NULL &&
861 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
862 > 0) {
863 data[sizeof data - 1] = '\0';
864 if (n_poption & n_PO_D_V)
865 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
866 urlp->url_host.s, data);
867 rv = rfc2595_hostname_match(urlp->url_host.s, data);
870 jdone:
871 X509_free(cert);
872 jleave:
873 NYD_LEAVE;
874 return rv;
877 static int
878 smime_verify(struct message *m, int n, n_XSSL_STACKOF(X509) *chain,
879 X509_STORE *store)
881 char data[LINESIZE], *sender, *to, *cc, *cnttype;
882 int rv, c, i, j;
883 struct message *x;
884 FILE *fp, *ip;
885 off_t size;
886 BIO *fb, *pb;
887 PKCS7 *pkcs7;
888 n_XSSL_STACKOF(X509) *certs;
889 n_XSSL_STACKOF(GENERAL_NAME) *gens;
890 X509 *cert;
891 X509_NAME *subj;
892 GENERAL_NAME *gen;
893 NYD_ENTER;
895 rv = 1;
896 fp = NULL;
897 fb = NULL;
898 a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
899 a_xssl_msgno = (size_t)n;
901 for (;;) {
902 sender = getsender(m);
903 to = hfield1("to", m);
904 cc = hfield1("cc", m);
905 cnttype = hfield1("content-type", m);
907 #undef _X
908 #undef _Y
909 #define _X (sizeof("application/") -1)
910 #define _Y(X) X, sizeof(X) -1
911 if (cnttype && is_asccaseprefix("application/", cnttype) &&
912 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
913 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
914 #undef _Y
915 #undef _X
916 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
917 goto jleave;
918 if (x != (struct message*)-1) {
919 m = x;
920 continue;
924 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
925 goto jleave;
926 size = m->m_size;
927 break;
930 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
931 NULL) {
932 n_perr(_("tempfile"), 0);
933 goto jleave;
935 while (size-- > 0) {
936 c = getc(ip);
937 putc(c, fp);
939 fflush_rewind(fp);
941 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
942 ssl_gen_err(_(
943 "Error creating BIO verification object for message %d"), n);
944 goto jleave;
947 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
948 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
949 goto jleave;
951 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
952 ssl_gen_err(_("Error verifying message %d"), n);
953 goto jleave;
956 if (sender == NULL) {
957 n_err(_("Warning: Message %d has no sender\n"), n);
958 rv = 0;
959 goto jleave;
962 certs = PKCS7_get0_signers(pkcs7, chain, 0);
963 if (certs == NULL) {
964 n_err(_("No certificates found in message %d\n"), n);
965 goto jleave;
968 for (i = 0; i < sk_X509_num(certs); ++i) {
969 cert = sk_X509_value(certs, i);
970 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
971 if (gens != NULL) {
972 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
973 gen = sk_GENERAL_NAME_value(gens, j);
974 if (gen->type == GEN_EMAIL) {
975 if (n_poption & n_PO_D_V)
976 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
977 sender, (char*)gen->d.ia5->data);
978 if (!asccasecmp((char*)gen->d.ia5->data, sender))
979 goto jfound;
984 if ((subj = X509_get_subject_name(cert)) != NULL &&
985 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
986 data, sizeof data) > 0) {
987 data[sizeof data -1] = '\0';
988 if (n_poption & n_PO_D_V)
989 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
990 sender, data);
991 if (!asccasecmp(data, sender))
992 goto jfound;
995 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
996 goto jleave;
997 jfound:
998 rv = ((a_xssl_state & a_XSSL_S_VERIFY_ERROR) != 0);
999 if (!rv)
1000 fprintf(n_stdout, _("Message %d was verified successfully\n"), n);
1001 jleave:
1002 if (fb != NULL)
1003 BIO_free(fb);
1004 if (fp != NULL)
1005 Fclose(fp);
1006 NYD_LEAVE;
1007 return rv;
1010 static EVP_CIPHER const *
1011 _smime_cipher(char const *name)
1013 EVP_CIPHER const *cipher;
1014 char *vn;
1015 char const *cp;
1016 size_t i;
1017 NYD_ENTER;
1019 vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
1020 snprintf(vn, (int)i, "smime-cipher-%s", name);
1021 cp = n_var_vlook(vn, FAL0);
1022 ac_free(vn);
1024 if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
1025 cipher = a_XSSL_SMIME_DEFAULT_CIPHER();
1026 goto jleave;
1028 cipher = NULL;
1030 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers); ++i)
1031 if (!asccasecmp(a_xssl_smime_ciphers[i].sc_name, cp)) {
1032 cipher = (*a_xssl_smime_ciphers[i].sc_fun)();
1033 goto jleave;
1035 #ifndef OPENSSL_NO_AES
1036 for (i = 0; i < n_NELEM(a_xssl_smime_ciphers_obs); ++i) /* TODO obsolete */
1037 if (!asccasecmp(a_xssl_smime_ciphers_obs[i].sc_name, cp)) {
1038 n_OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
1039 cipher = (*a_xssl_smime_ciphers_obs[i].sc_fun)();
1040 goto jleave;
1042 #endif
1044 /* Not a builtin algorithm, but we may have dynamic support for more */
1045 #ifdef HAVE_SSL_ALL_ALGORITHMS
1046 a_xssl_load_algos();
1047 if((cipher = EVP_get_cipherbyname(cp)) != NULL)
1048 goto jleave;
1049 #endif
1051 n_err(_("Invalid S/MIME cipher(s): %s\n"), cp);
1052 jleave:
1053 NYD_LEAVE;
1054 return cipher;
1057 static int
1058 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
1060 char *pass;
1061 size_t len;
1062 NYD_ENTER;
1063 n_UNUSED(rwflag);
1064 n_UNUSED(userdata);
1066 /* New-style */
1067 if(userdata != NULL){
1068 struct url url;
1069 struct ccred cred;
1071 if(url_parse(&url, CPROTO_CCRED, userdata)){
1072 if(ccred_lookup(&cred, &url)){
1073 ssize_t slen;
1075 if((slen = n_strscpy(buf, cred.cc_pass.s, size)) >= 0){
1076 size = (int)slen;
1077 goto jleave;
1080 size = 0;
1081 goto jleave;
1085 /* Old-style */
1086 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
1087 len = strlen(pass);
1088 if (UICMP(z, len, >=, size))
1089 len = size -1;
1090 memcpy(buf, pass, len);
1091 buf[len] = '\0';
1092 size = (int)len;
1093 } else
1094 size = 0;
1095 jleave:
1096 NYD_LEAVE;
1097 return size;
1100 static FILE *
1101 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn,
1102 char const **match)
1104 char *vn;
1105 int vs;
1106 struct name *np;
1107 char const *name = xname, *name2 = xname2, *cp;
1108 FILE *fp = NULL;
1109 NYD_ENTER;
1111 jloop:
1112 if (name) {
1113 np = lextract(name, GTO | GSKIN);
1114 while (np != NULL) {
1115 /* This needs to be more intelligent since it will currently take the
1116 * first name for which a private key is available regardless of
1117 * whether it is the right one for the message */
1118 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1119 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
1120 cp = n_var_vlook(vn, FAL0);
1121 ac_free(vn);
1122 if (cp != NULL) {
1123 if (match != NULL)
1124 *match = np->n_name;
1125 goto jopen;
1127 np = np->n_flink;
1129 if (name2 != NULL) {
1130 name = name2;
1131 name2 = NULL;
1132 goto jloop;
1136 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
1137 goto jerr;
1138 if(match != NULL)
1139 *match = NULL;
1140 jopen:
1141 if ((cp = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
1142 goto jleave;
1143 if ((fp = Fopen(cp, "r")) == NULL)
1144 n_perr(cp, 0);
1145 jleave:
1146 NYD_LEAVE;
1147 return fp;
1148 jerr:
1149 if (dowarn)
1150 n_err(_("Could not find a certificate for %s%s%s\n"),
1151 xname, (xname2 != NULL ? _("or ") : n_empty),
1152 (xname2 != NULL ? xname2 : n_empty));
1153 goto jleave;
1156 static char const *
1157 _smime_sign_include_certs(char const *name)
1159 char const *rv;
1160 NYD_ENTER;
1162 /* See comments in smime_sign_cert() for algorithm pitfalls */
1163 if (name != NULL) {
1164 struct name *np;
1166 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1167 int vs;
1168 char *vn;
1170 vn = ac_alloc(vs = strlen(np->n_name) + 30);
1171 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1172 rv = n_var_vlook(vn, FAL0);
1173 ac_free(vn);
1174 if (rv != NULL)
1175 goto jleave;
1178 rv = ok_vlook(smime_sign_include_certs);
1179 jleave:
1180 NYD_LEAVE;
1181 return rv;
1184 static bool_t
1185 _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
1186 char const *cfiles, char const *addr)
1188 X509 *tmp;
1189 FILE *fp;
1190 char *nfield, *cfield, *x;
1191 NYD_ENTER;
1193 *chain = sk_X509_new_null();
1195 for (nfield = savestr(cfiles);
1196 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
1197 if ((x = fexpand(cfield, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1198 (fp = Fopen(cfield = x, "r")) == NULL) {
1199 n_perr(cfiles, 0);
1200 goto jerr;
1202 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, n_UNCONST(addr))
1203 ) == NULL) {
1204 ssl_gen_err(_("Error reading certificate from %s"),
1205 n_shexp_quote_cp(cfield, FAL0));
1206 Fclose(fp);
1207 goto jerr;
1209 sk_X509_push(*chain, tmp);
1210 Fclose(fp);
1213 if (sk_X509_num(*chain) == 0) {
1214 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1215 goto jerr;
1217 jleave:
1218 NYD_LEAVE;
1219 return (*chain != NULL);
1220 jerr:
1221 sk_X509_pop_free(*chain, X509_free);
1222 *chain = NULL;
1223 goto jleave;
1226 static EVP_MD const *
1227 _smime_sign_digest(char const *name, char const **digname)
1229 EVP_MD const *digest;
1230 char const *cp;
1231 size_t i;
1232 NYD_ENTER;
1234 /* See comments in smime_sign_cert() for algorithm pitfalls */
1235 if (name != NULL) {
1236 struct name *np;
1238 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1239 int vs;
1240 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1241 snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
1242 cp = n_var_vlook(vn, FAL0);
1243 ac_free(vn);
1244 if (cp != NULL)
1245 goto jhave_name;
1249 if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
1250 digest = a_XSSL_SMIME_DEFAULT_DIGEST();
1251 *digname = a_XSSL_SMIME_DEFAULT_DIGEST_S;
1252 goto jleave;
1255 jhave_name:
1256 i = strlen(cp);
1257 { char *x = salloc(i +1);
1258 i_strcpy(x, cp, i +1);
1259 cp = x;
1261 *digname = cp;
1263 for (i = 0; i < n_NELEM(a_xssl_smime_digests); ++i)
1264 if (!asccasecmp(a_xssl_smime_digests[i].sd_name, cp)) {
1265 digest = (*a_xssl_smime_digests[i].sd_fun)();
1266 goto jleave;
1269 /* Not a builtin algorithm, but we may have dynamic support for more */
1270 #ifdef HAVE_SSL_ALL_ALGORITHMS
1271 a_xssl_load_algos();
1272 if((digest = EVP_get_digestbyname(cp)) != NULL)
1273 goto jleave;
1274 #endif
1276 n_err(_("Invalid message digest: %s\n"), cp);
1277 digest = NULL;
1278 jleave:
1279 NYD_LEAVE;
1280 return digest;
1283 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1284 static enum okay
1285 load_crl1(X509_STORE *store, char const *name)
1287 X509_LOOKUP *lookup;
1288 enum okay rv = STOP;
1289 NYD_ENTER;
1291 if (n_poption & n_PO_D_V)
1292 n_err(_("Loading CRL from %s\n"), n_shexp_quote_cp(name, FAL0));
1293 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1294 ssl_gen_err(_("Error creating X509 lookup object"));
1295 goto jleave;
1297 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1298 ssl_gen_err(_("Error loading CRL from %s"), n_shexp_quote_cp(name, FAL0));
1299 goto jleave;
1301 rv = OKAY;
1302 jleave:
1303 NYD_LEAVE;
1304 return rv;
1306 #endif /* new OpenSSL */
1308 static enum okay
1309 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
1311 char *crl_file, *crl_dir;
1312 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1313 DIR *dirp;
1314 struct dirent *dp;
1315 char *fn = NULL;
1316 int fs = 0, ds, es;
1317 #endif
1318 enum okay rv = STOP;
1319 NYD_ENTER;
1321 if ((crl_file = n_var_oklook(fok)) != NULL) {
1322 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1323 if ((crl_file = fexpand(crl_file, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1324 load_crl1(store, crl_file) != OKAY)
1325 goto jleave;
1326 #else
1327 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1328 goto jleave;
1329 #endif
1332 if ((crl_dir = n_var_oklook(dok)) != NULL) {
1333 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1334 char *x;
1335 if ((x = fexpand(crl_dir, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
1336 (dirp = opendir(crl_dir = x)) == NULL) {
1337 n_perr(crl_dir, 0);
1338 goto jleave;
1341 ds = strlen(crl_dir);
1342 fn = smalloc(fs = ds + 20);
1343 memcpy(fn, crl_dir, ds);
1344 fn[ds] = '/';
1345 while ((dp = readdir(dirp)) != NULL) {
1346 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1347 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1348 continue;
1349 if (dp->d_name[0] == '.')
1350 continue;
1351 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1352 fn = srealloc(fn, fs = ds + es + 20);
1353 memcpy(fn + ds + 1, dp->d_name, es + 1);
1354 if (load_crl1(store, fn) != OKAY) {
1355 closedir(dirp);
1356 free(fn);
1357 goto jleave;
1360 closedir(dirp);
1361 free(fn);
1362 #else /* old OpenSSL */
1363 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1364 goto jleave;
1365 #endif
1367 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1368 if (crl_file || crl_dir)
1369 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1370 X509_V_FLAG_CRL_CHECK_ALL);
1371 #endif
1372 rv = OKAY;
1373 jleave:
1374 NYD_LEAVE;
1375 return rv;
1378 FL enum okay
1379 ssl_open(struct url const *urlp, struct sock *sp)
1381 SSL_CTX *ctxp;
1382 void *confp;
1383 char const *cp, *cp_base;
1384 size_t i;
1385 enum okay rv = STOP;
1386 NYD_ENTER;
1388 a_xssl_init();
1390 ssl_set_verify_level(urlp);
1392 if ((ctxp = SSL_CTX_new(n_XSSL_CLIENT_METHOD())) == NULL) {
1393 ssl_gen_err(_("SSL_CTX_new() failed"));
1394 goto jleave;
1397 /* Available with OpenSSL 0.9.6 or later */
1398 #ifdef SSL_MODE_AUTO_RETRY
1399 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
1400 #endif
1402 if ((confp = _ssl_conf_setup(ctxp)) == NULL)
1403 goto jerr0;
1405 /* TODO obsolete Check for *ssl-method*, warp to a *ssl-protocol* value */
1406 if ((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL) {
1407 n_OBSOLETE(_("please use *ssl-protocol* instead of *ssl-method*"));
1408 if (n_poption & n_PO_D_V)
1409 n_err(_("*ssl-method*: %s\n"), cp);
1410 for (i = 0;;) {
1411 if (!asccasecmp(_ssl_methods[i].sm_name, cp)) {
1412 cp = _ssl_methods[i].sm_map;
1413 break;
1415 if (++i == n_NELEM(_ssl_methods)) {
1416 n_err(_("Unsupported TLS/SSL method: %s\n"), cp);
1417 goto jerr1;
1421 /* *ssl-protocol* */
1422 if ((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL) {
1423 if (n_poption & n_PO_D_V)
1424 n_err(_("*ssl-protocol*: %s\n"), cp_base);
1425 cp = cp_base;
1427 cp = (cp != NULL ? savecatsep(cp, ',', n_XSSL_DISABLED_PROTOCOLS)
1428 : n_XSSL_DISABLED_PROTOCOLS);
1429 if (!_ssl_conf(confp, a_XSSL_CT_PROTOCOL, cp))
1430 goto jerr1;
1432 /* *ssl-cert* */
1433 if ((cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL) {
1434 if (n_poption & n_PO_D_V)
1435 n_err(_("*ssl-cert* %s\n"), n_shexp_quote_cp(cp, FAL0));
1436 if ((cp_base = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL) {
1437 n_err(_("*ssl-cert* value expansion failed: %s\n"),
1438 n_shexp_quote_cp(cp, FAL0));
1439 goto jerr1;
1441 cp = cp_base;
1442 if (!_ssl_conf(confp, a_XSSL_CT_CERTIFICATE, cp))
1443 goto jerr1;
1445 /* *ssl-key* */
1446 if ((cp_base = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL) {
1447 if (n_poption & n_PO_D_V)
1448 n_err(_("*ssl-key* %s\n"), n_shexp_quote_cp(cp_base, FAL0));
1449 if ((cp = fexpand(cp_base, FEXP_LOCAL | FEXP_NOPROTO)) == NULL) {
1450 n_err(_("*ssl-key* value expansion failed: %s\n"),
1451 n_shexp_quote_cp(cp_base, FAL0));
1452 goto jerr1;
1455 if (!_ssl_conf(confp, a_XSSL_CT_PRIVATE_KEY, cp))
1456 goto jerr1;
1459 if ((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL &&
1460 !_ssl_conf(confp, a_XSSL_CT_CIPHER_STRING, cp))
1461 goto jerr1;
1463 if (!_ssl_load_verifications(ctxp))
1464 goto jerr1;
1466 if (!_ssl_conf(confp, a_XSSL_CT_OPTIONS, NULL)) /* TODO *ssl-options* */
1467 goto jerr1;
1469 /* Done with context setup, create our new per-connection structure */
1470 if (!_ssl_conf_finish(&confp, FAL0))
1471 goto jerr0;
1473 if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
1474 ssl_gen_err(_("SSL_new() failed"));
1475 goto jerr0;
1478 /* Try establish SNI extension; even though this is a TLS extension the
1479 * protocol isn't checked once the host name is set, and therefore i've
1480 * refrained from changing so much code just to check out whether we are
1481 * using SSLv3, which should become rarer and rarer */
1482 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1483 if((urlp->url_flags & n_URL_TLS_MASK) &&
1484 (urlp->url_flags & n_URL_HOST_IS_NAME)){
1485 if(!SSL_set_tlsext_host_name(sp->s_ssl, urlp->url_host.s) &&
1486 (n_poption & n_PO_D_V))
1487 n_err(_("Hostname cannot be used with ServerNameIndication "
1488 "TLS extension: %s\n"),
1489 n_shexp_quote_cp(urlp->url_host.s, FAL0));
1491 #endif
1493 SSL_set_fd(sp->s_ssl, sp->s_fd);
1495 if (SSL_connect(sp->s_ssl) < 0) {
1496 ssl_gen_err(_("could not initiate SSL/TLS connection"));
1497 goto jerr2;
1500 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
1501 if (ssl_check_host(sp, urlp) != OKAY) {
1502 n_err(_("Host certificate does not match: %s\n"), urlp->url_h_p.s);
1503 if (ssl_verify_decide() != OKAY)
1504 goto jerr2;
1508 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
1509 * and free it right now -- it is reference counted by sp->s_ssl.. */
1510 SSL_CTX_free(ctxp);
1511 sp->s_use_ssl = 1;
1512 rv = OKAY;
1513 jleave:
1514 NYD_LEAVE;
1515 return rv;
1516 jerr2:
1517 SSL_free(sp->s_ssl);
1518 sp->s_ssl = NULL;
1519 jerr1:
1520 if (confp != NULL)
1521 _ssl_conf_finish(&confp, TRU1);
1522 jerr0:
1523 SSL_CTX_free(ctxp);
1524 goto jleave;
1527 FL void
1528 ssl_gen_err(char const *fmt, ...)
1530 va_list ap;
1531 NYD_ENTER;
1533 va_start(ap, fmt);
1534 n_verr(fmt, ap);
1535 va_end(ap);
1537 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
1538 NYD_LEAVE;
1541 FL int
1542 c_verify(void *vp)
1544 int *msgvec = vp, *ip, ec = 0, rv = 1;
1545 n_XSSL_STACKOF(X509) *chain = NULL;
1546 X509_STORE *store = NULL;
1547 char *ca_dir, *ca_file;
1548 NYD_ENTER;
1550 a_xssl_init();
1552 ssl_verify_level = SSL_VERIFY_STRICT;
1553 if ((store = X509_STORE_new()) == NULL) {
1554 ssl_gen_err(_("Error creating X509 store"));
1555 goto jleave;
1557 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
1559 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
1560 ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
1561 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
1562 ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
1564 if (ca_dir != NULL || ca_file != NULL) {
1565 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
1566 ssl_gen_err(_("Error loading %s"),
1567 (ca_file != NULL) ? ca_file : ca_dir);
1568 goto jleave;
1572 /* C99 */{
1573 bool_t xv15;
1575 if((xv15 = ok_blook(smime_no_default_ca)))
1576 n_OBSOLETE(_("please use *smime-ca-no-defaults*, "
1577 "not *smime-no-default-ca*"));
1578 if(!ok_blook(smime_ca_no_defaults) && !xv15 &&
1579 X509_STORE_set_default_paths(store) != 1) {
1580 ssl_gen_err(_("Error loading builtin default CA locations\n"));
1581 goto jleave;
1585 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
1586 goto jleave;
1588 a_xssl_ca_flags(store, ok_vlook(smime_ca_flags));
1590 srelax_hold();
1591 for (ip = msgvec; *ip != 0; ++ip) {
1592 struct message *mp = message + *ip - 1;
1593 setdot(mp);
1594 ec |= smime_verify(mp, *ip, chain, store);
1595 srelax();
1597 srelax_rele();
1599 if ((rv = ec) != 0)
1600 n_exit_status |= n_EXIT_ERR;
1601 jleave:
1602 if (store != NULL)
1603 X509_STORE_free(store);
1604 NYD_LEAVE;
1605 return rv;
1608 FL FILE *
1609 smime_sign(FILE *ip, char const *addr)
1611 FILE *rv = NULL, *sp = NULL, *fp = NULL, *bp, *hp;
1612 X509 *cert = NULL;
1613 n_XSSL_STACKOF(X509) *chain = NULL;
1614 EVP_PKEY *pkey = NULL;
1615 BIO *bb, *sb;
1616 PKCS7 *pkcs7;
1617 EVP_MD const *md;
1618 char const *name;
1619 bool_t bail = FAL0;
1620 NYD_ENTER;
1622 assert(addr != NULL);
1624 a_xssl_init();
1626 if (addr == NULL) {
1627 n_err(_("No *from* address for signing specified\n"));
1628 goto jleave;
1630 if ((fp = smime_sign_cert(addr, NULL, 1, NULL)) == NULL)
1631 goto jleave;
1633 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb,
1634 savecat(addr, ".smime-cert-key"))) == NULL) {
1635 ssl_gen_err(_("Error reading private key from"));
1636 goto jleave;
1639 rewind(fp);
1640 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb,
1641 savecat(addr, ".smime-cert-cert"))) == NULL) {
1642 ssl_gen_err(_("Error reading signer certificate from"));
1643 goto jleave;
1645 Fclose(fp);
1646 fp = NULL;
1648 if ((name = _smime_sign_include_certs(addr)) != NULL &&
1649 !_smime_sign_include_chain_creat(&chain, name,
1650 savecat(addr, ".smime-include-certs")))
1651 goto jleave;
1653 name = NULL;
1654 if ((md = _smime_sign_digest(addr, &name)) == NULL)
1655 goto jleave;
1657 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1658 NULL) {
1659 n_perr(_("tempfile"), 0);
1660 goto jleave;
1663 rewind(ip);
1664 if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
1665 goto jerr1;
1667 sb = NULL;
1668 pkcs7 = NULL;
1670 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1671 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1672 ssl_gen_err(_("Error creating BIO signing objects"));
1673 bail = TRU1;
1674 goto jerr;
1677 #undef _X
1678 #define _X PKCS7_DETACHED | PKCS7_PARTIAL
1679 if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
1680 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1681 bail = TRU1;
1682 goto jerr;
1684 if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
1685 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
1686 bail = TRU1;
1687 goto jerr;
1689 if (!PKCS7_final(pkcs7, bb, _X)) {
1690 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
1691 bail = TRU1;
1692 goto jerr;
1694 #undef _X
1696 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1697 ssl_gen_err(_("Error writing signed S/MIME data"));
1698 bail = TRU1;
1699 /*goto jerr*/
1701 jerr:
1702 if (pkcs7 != NULL)
1703 PKCS7_free(pkcs7);
1704 if (sb != NULL)
1705 BIO_free(sb);
1706 if (bb != NULL)
1707 BIO_free(bb);
1708 if (!bail) {
1709 rewind(bp);
1710 fflush_rewind(sp);
1711 rv = smime_sign_assemble(hp, bp, sp, name);
1712 } else
1713 jerr1:
1714 Fclose(sp);
1716 jleave:
1717 if (chain != NULL)
1718 sk_X509_pop_free(chain, X509_free);
1719 if (cert != NULL)
1720 X509_free(cert);
1721 if (pkey != NULL)
1722 EVP_PKEY_free(pkey);
1723 if (fp != NULL)
1724 Fclose(fp);
1725 NYD_LEAVE;
1726 return rv;
1729 FL FILE *
1730 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1732 FILE *rv = NULL, *yp, *fp, *bp, *hp;
1733 X509 *cert;
1734 PKCS7 *pkcs7;
1735 BIO *bb, *yb;
1736 n_XSSL_STACKOF(X509) *certs;
1737 EVP_CIPHER const *cipher;
1738 char *certfile;
1739 bool_t bail = FAL0;
1740 NYD_ENTER;
1742 if ((certfile = fexpand(xcertfile, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
1743 goto jleave;
1745 a_xssl_init();
1747 if ((cipher = _smime_cipher(to)) == NULL)
1748 goto jleave;
1749 if ((fp = Fopen(certfile, "r")) == NULL) {
1750 n_perr(certfile, 0);
1751 goto jleave;
1754 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1755 ssl_gen_err(_("Error reading encryption certificate from %s"),
1756 n_shexp_quote_cp(certfile, FAL0));
1757 bail = TRU1;
1759 Fclose(fp);
1760 if (bail)
1761 goto jleave;
1762 bail = FAL0;
1764 certs = sk_X509_new_null();
1765 sk_X509_push(certs, cert);
1767 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1768 NULL) {
1769 n_perr(_("tempfile"), 0);
1770 goto jerr1;
1773 rewind(ip);
1774 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1775 Fclose(yp);
1776 goto jerr1;
1779 yb = NULL;
1780 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1781 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1782 ssl_gen_err(_("Error creating BIO encryption objects"));
1783 bail = TRU1;
1784 goto jerr2;
1786 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1787 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
1788 bail = TRU1;
1789 goto jerr2;
1791 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1792 ssl_gen_err(_("Error writing encrypted S/MIME data"));
1793 bail = TRU1;
1794 /* goto jerr2 */
1797 jerr2:
1798 if (bb != NULL)
1799 BIO_free(bb);
1800 if (yb != NULL)
1801 BIO_free(yb);
1802 Fclose(bp);
1803 if (bail)
1804 Fclose(yp);
1805 else {
1806 fflush_rewind(yp);
1807 rv = smime_encrypt_assemble(hp, yp);
1809 jerr1:
1810 sk_X509_pop_free(certs, X509_free);
1811 jleave:
1812 NYD_LEAVE;
1813 return rv;
1816 FL struct message *
1817 smime_decrypt(struct message *m, char const *to, char const *cc,
1818 bool_t signcall)
1820 struct message *rv;
1821 FILE *fp, *bp, *hp, *op;
1822 X509 *cert;
1823 PKCS7 *pkcs7;
1824 EVP_PKEY *pkey;
1825 BIO *bb, *pb, *ob;
1826 char const *myaddr;
1827 long size;
1828 FILE *yp;
1829 NYD_ENTER;
1831 rv = NULL;
1832 cert = NULL;
1833 pkey = NULL;
1834 size = m->m_size;
1836 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1837 goto jleave;
1839 a_xssl_init();
1841 if ((fp = smime_sign_cert(to, cc, 0, &myaddr)) != NULL) {
1842 pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb,
1843 savecat(myaddr, ".smime-cert-key"));
1844 if (pkey == NULL) {
1845 ssl_gen_err(_("Error reading private key"));
1846 Fclose(fp);
1847 goto jleave;
1849 rewind(fp);
1851 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb,
1852 savecat(myaddr, ".smime-cert-cert"))) == NULL) {
1853 ssl_gen_err(_("Error reading decryption certificate"));
1854 Fclose(fp);
1855 EVP_PKEY_free(pkey);
1856 goto jleave;
1858 Fclose(fp);
1861 if ((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1862 NULL) {
1863 n_perr(_("tempfile"), 0);
1864 goto j_ferr;
1867 if (smime_split(yp, &hp, &bp, size, 1) == STOP)
1868 goto jferr;
1870 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1871 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
1872 ssl_gen_err(_("Error creating BIO decryption objects"));
1873 goto jferr;
1875 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
1876 ssl_gen_err(_("Error reading PKCS#7 object"));
1877 jferr:
1878 Fclose(op);
1879 j_ferr:
1880 if (cert)
1881 X509_free(cert);
1882 if (pkey)
1883 EVP_PKEY_free(pkey);
1884 goto jleave;
1887 if (PKCS7_type_is_signed(pkcs7)) {
1888 if (signcall) {
1889 setinput(&mb, m, NEED_BODY);
1890 rv = (struct message*)-1;
1891 goto jerr2;
1893 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1894 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1895 goto jerr;
1896 fseek(hp, 0L, SEEK_END);
1897 fprintf(hp, "X-Encryption-Cipher: none\n");
1898 fflush(hp);
1899 rewind(hp);
1900 } else if (pkey == NULL) {
1901 n_err(_("No appropriate private key found\n"));
1902 goto jerr2;
1903 } else if (cert == NULL) {
1904 n_err(_("No appropriate certificate found\n"));
1905 goto jerr2;
1906 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
1907 jerr:
1908 ssl_gen_err(_("Error decrypting PKCS#7 object"));
1909 jerr2:
1910 BIO_free(bb);
1911 BIO_free(ob);
1912 Fclose(op);
1913 Fclose(bp);
1914 Fclose(hp);
1915 if (cert != NULL)
1916 X509_free(cert);
1917 if (pkey != NULL)
1918 EVP_PKEY_free(pkey);
1919 goto jleave;
1921 BIO_free(bb);
1922 BIO_free(ob);
1923 if (cert)
1924 X509_free(cert);
1925 if (pkey)
1926 EVP_PKEY_free(pkey);
1927 fflush_rewind(op);
1928 Fclose(bp);
1930 rv = smime_decrypt_assemble(m, hp, op);
1931 jleave:
1932 NYD_LEAVE;
1933 return rv;
1936 FL enum okay
1937 smime_certsave(struct message *m, int n, FILE *op)
1939 struct message *x;
1940 char *to, *cc, *cnttype;
1941 int c, i;
1942 FILE *fp, *ip;
1943 off_t size;
1944 BIO *fb, *pb;
1945 PKCS7 *pkcs7;
1946 n_XSSL_STACKOF(X509) *certs, *chain = NULL;
1947 X509 *cert;
1948 enum okay rv = STOP;
1949 NYD_ENTER;
1951 a_xssl_msgno = (size_t)n;
1952 jloop:
1953 to = hfield1("to", m);
1954 cc = hfield1("cc", m);
1955 cnttype = hfield1("content-type", m);
1957 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1958 goto jleave;
1960 #undef _X
1961 #undef _Y
1962 #define _X (sizeof("application/") -1)
1963 #define _Y(X) X, sizeof(X) -1
1964 if (cnttype && is_asccaseprefix("application/", cnttype) &&
1965 (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
1966 !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
1967 #undef _Y
1968 #undef _X
1969 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1970 goto jleave;
1971 if (x != (struct message*)-1) {
1972 m = x;
1973 goto jloop;
1976 size = m->m_size;
1978 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
1979 NULL) {
1980 n_perr(_("tempfile"), 0);
1981 goto jleave;
1984 while (size-- > 0) {
1985 c = getc(ip);
1986 putc(c, fp);
1988 fflush(fp);
1990 rewind(fp);
1991 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1992 ssl_gen_err("Error creating BIO object for message %d", n);
1993 Fclose(fp);
1994 goto jleave;
1997 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1998 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1999 BIO_free(fb);
2000 Fclose(fp);
2001 goto jleave;
2003 BIO_free(fb);
2004 Fclose(fp);
2006 certs = PKCS7_get0_signers(pkcs7, chain, 0);
2007 if (certs == NULL) {
2008 n_err(_("No certificates found in message %d\n"), n);
2009 goto jleave;
2012 for (i = 0; i < sk_X509_num(certs); ++i) {
2013 cert = sk_X509_value(certs, i);
2014 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
2015 ssl_gen_err(_("Error writing certificate %d from message %d"),
2016 i, n);
2017 goto jleave;
2020 rv = OKAY;
2021 jleave:
2022 NYD_LEAVE;
2023 return rv;
2025 #endif /* HAVE_XSSL */
2027 /* s-it-mode */