"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.10/xssl.c" (25 Mar 2018, 63560 Bytes) of package /linux/misc/s-nail-14.9.10.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "xssl.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.9.9_vs_14.9.10.

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