"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.7/xssl.c" (16 Feb 2018, 63549 Bytes) of package /linux/misc/s-nail-14.9.7.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.6_vs_14.9.7.

    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_USE_XSSL
  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    n_LCTAV(n_RANDOM_USE_XSSL == 0 || n_RANDOM_USE_XSSL == 1);
  403    for(x = (char*)-1;;){
  404       RAND_add(n_random_create_buf(b64buf, sizeof(b64buf) -1, NULL),
  405          sizeof(b64buf) -1, a_XSSL_RAND_ENTROPY);
  406       if((x = (char*)((uintptr_t)x >> (1 + (n_RANDOM_USE_XSSL * 3)))) == NULL){
  407          err = (RAND_status() == 0);
  408          break;
  409       }
  410 #if !n_RANDOM_USE_XSSL
  411       if(!(err = (RAND_status() == 0)))
  412          break;
  413 #endif
  414    }
  415 
  416    if(!err)
  417       err = (RAND_write_file(cp) == -1);
  418 
  419 jleave:
  420    if(randfile != NULL)
  421       n_lofi_free(randfile);
  422    if(err)
  423       n_panic(_("Cannot seed the *SSL PseudoRandomNumberGenerator, "
  424             "RAND_status() is 0!\n"
  425          "  Please set *ssl-rand-file* to a file with sufficient entropy.\n"
  426          "  On a machine with entropy: "
  427             "\"$ dd if=/dev/urandom of=FILE bs=1024 count=1\"\n"));
  428    NYD2_LEAVE;
  429 }
  430 
  431 static void
  432 a_xssl_init(void){
  433 #ifdef HAVE_XSSL_CONFIG
  434    char const *cp;
  435 #endif
  436    NYD2_ENTER;
  437 
  438    if(a_xssl_state & a_XSSL_S_INIT)
  439       goto jleave;
  440 
  441 #if HAVE_XSSL_OPENSSL >= 0x10100
  442    OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS |
  443       OPENSSL_INIT_LOAD_CRYPTO_STRINGS
  444 # ifdef HAVE_SSL_ALL_ALGORITHMS
  445          | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS
  446 # endif
  447       , NULL);
  448 #else
  449    SSL_load_error_strings();
  450    SSL_library_init();
  451    a_xssl_load_algos();
  452 #endif
  453    a_xssl_state |= a_XSSL_S_INIT;
  454 
  455 
  456    /* Load openssl.cnf or whatever was given in *ssl-config-file* */
  457 #ifdef HAVE_XSSL_CONFIG
  458    if((cp = ok_vlook(ssl_config_file)) != NULL){
  459       char const *msg;
  460       ul_i flags;
  461 
  462       if(*cp == '\0'){
  463          msg = "[default]";
  464          cp = NULL;
  465          flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
  466       }else if((msg = cp, cp = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) != NULL)
  467          flags = 0;
  468       else{
  469          n_err(_("*ssl-config-file*: file expansion failed: %s\n"),
  470             n_shexp_quote_cp(msg, FAL0));
  471          goto jefile;
  472       }
  473 
  474       if(CONF_modules_load_file(cp, n_uagent, flags) == 1){
  475          a_xssl_state |= a_XSSL_S_CONF_LOAD;
  476 # if HAVE_XSSL_OPENSSL < 0x10100
  477          if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
  478             a_xssl_state |= a_XSSL_S_EXIT_HDL;
  479             atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
  480          }
  481 # endif
  482          if(n_poption & n_PO_D_V)
  483             n_err(_("Loaded SSL/TLS configuration for %s from %s\n"), n_uagent,
  484                n_shexp_quote_cp(msg, FAL0));
  485 jefile:;
  486       }else
  487          ssl_gen_err(_("SSL/TLS CONF_modules_load_file() load error"));
  488    }
  489 #endif /* HAVE_XSSL_CONFIG */
  490 
  491    if(!(a_xssl_state & a_XSSL_S_RAND_INIT))
  492       a_xssl_rand_init();
  493 jleave:
  494    NYD2_LEAVE;
  495 }
  496 
  497 #if HAVE_XSSL_OPENSSL < 0x10100
  498 # ifdef HAVE_SSL_ALL_ALGORITHMS
  499 static void
  500 a_xssl__load_algos(void){
  501    NYD2_ENTER;
  502    if(!(a_xssl_state & a_XSSL_S_ALGO_LOAD)){
  503       a_xssl_state |= a_XSSL_S_ALGO_LOAD;
  504       OpenSSL_add_all_algorithms();
  505 
  506       if(!(a_xssl_state & a_XSSL_S_EXIT_HDL)){
  507          a_xssl_state |= a_XSSL_S_EXIT_HDL;
  508          atexit(&a_xssl_atexit); /* TODO generic program-wide event mech. */
  509       }
  510    }
  511    NYD2_LEAVE;
  512 }
  513 # endif
  514 
  515 # if defined HAVE_XSSL_CONFIG || defined HAVE_SSL_ALL_ALGORITHMS
  516 static void
  517 a_xssl_atexit(void){
  518    NYD2_ENTER;
  519 #  ifdef HAVE_XSSL_CONFIG
  520    if(a_xssl_state & a_XSSL_S_CONF_LOAD)
  521       CONF_modules_free();
  522 #  endif
  523 
  524 #  ifdef HAVE_SSL_ALL_ALGORITHMS
  525    if(a_xssl_state & a_XSSL_S_ALGO_LOAD)
  526       EVP_cleanup();
  527 #  endif
  528    NYD2_LEAVE;
  529 }
  530 # endif
  531 #endif /* HAVE_XSSL_OPENSSL < 0x10100 */
  532 
  533 static bool_t
  534 _ssl_parse_asn1_time(ASN1_TIME const *atp, char *bdat, size_t blen)
  535 {
  536    BIO *mbp;
  537    char *mcp;
  538    long l;
  539    NYD_ENTER;
  540 
  541    mbp = BIO_new(BIO_s_mem());
  542 
  543    if (ASN1_TIME_print(mbp, atp) && (l = BIO_get_mem_data(mbp, &mcp)) > 0)
  544       snprintf(bdat, blen, "%.*s", (int)l, mcp);
  545    else {
  546       snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
  547          /*is (int)*/atp->length, (char const*)atp->data);
  548       mcp = NULL;
  549    }
  550 
  551    BIO_free(mbp);
  552    NYD_LEAVE;
  553    return (mcp != NULL);
  554 }
  555 
  556 static int
  557 _ssl_verify_cb(int success, X509_STORE_CTX *store)
  558 {
  559    char data[256];
  560    X509 *cert;
  561    int rv = TRU1;
  562    NYD_ENTER;
  563 
  564    if (success && !(n_poption & n_PO_D_V))
  565       goto jleave;
  566 
  567    if (a_xssl_msgno != 0) {
  568       n_err(_("Message %lu:\n"), (ul_i)a_xssl_msgno);
  569       a_xssl_msgno = 0;
  570    }
  571    n_err(_(" Certificate depth %d %s\n"),
  572       X509_STORE_CTX_get_error_depth(store), (success ? n_empty : V_(n_error)));
  573 
  574    if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
  575       X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
  576       n_err(_("  subject = %s\n"), data);
  577 
  578       _ssl_parse_asn1_time(a_xssl_X509_get_notBefore(cert), data, sizeof data);
  579       n_err(_("  notBefore = %s\n"), data);
  580 
  581       _ssl_parse_asn1_time(a_xssl_X509_get_notAfter(cert), data, sizeof data);
  582       n_err(_("  notAfter = %s\n"), data);
  583 
  584       X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
  585       n_err(_("  issuer = %s\n"), data);
  586    }
  587 
  588    if (!success) {
  589       int err = X509_STORE_CTX_get_error(store);
  590 
  591       n_err(_("  err %i: %s\n"), err, X509_verify_cert_error_string(err));
  592       a_xssl_state |= a_XSSL_S_VERIFY_ERROR;
  593    }
  594 
  595    if (!success && ssl_verify_decide() != OKAY)
  596       rv = FAL0;
  597 jleave:
  598    NYD_LEAVE;
  599    return rv;
  600 }
  601 
  602 static void
  603 a_xssl_ca_flags(X509_STORE *store, char const *flags){
  604    NYD2_ENTER;
  605    if(flags != NULL){
  606       char *iolist, *cp;
  607 
  608       iolist = savestr(flags);
  609 jouter:
  610       while((cp = n_strsep(&iolist, ',', TRU1)) != NULL){
  611          struct a_xssl_x509_v_flags const *xvfp;
  612 
  613          for(xvfp = &a_xssl_x509_v_flags[0];
  614                xvfp < &a_xssl_x509_v_flags[n_NELEM(a_xssl_x509_v_flags)];
  615                ++xvfp)
  616             if(!asccasecmp(cp, xvfp->xvf_name)){
  617                if(xvfp->xvf_flag != -1){
  618 #ifdef a_XSSL_X509_V_ANY
  619                   X509_STORE_set_flags(store, xvfp->xvf_flag);
  620 #endif
  621                }else if(n_poption & n_PO_D_V)
  622                   n_err(_("*{smime,ssl}-ca-flags*: "
  623                      "directive not supported: %s\n"), cp);
  624                goto jouter;
  625             }
  626          n_err(_("*{smime,ssl}-ca-flags*: invalid directive: %s\n"), cp);
  627       }
  628    }
  629    NYD2_LEAVE;
  630 }
  631 
  632 #ifdef HAVE_XSSL_CONF_CTX
  633 static void *
  634 a_xssl_conf_setup(SSL_CTX *ctxp, struct url const *urlp){
  635    char const *cp;
  636    SSL_CONF_CTX *sccp;
  637    NYD2_ENTER;
  638 
  639    sccp = NULL;
  640 
  641    if((cp = xok_vlook(ssl_config_module, urlp, OXM_ALL)) != NULL){
  642 # ifdef HAVE_XSSL_CTX_CONFIG
  643       if(!(a_xssl_state & a_XSSL_S_CONF_LOAD)){
  644          n_err(_("*ssl-config-module*: no *ssl-config-file* loaded: %s\n"),
  645             n_shexp_quote_cp(cp, FAL0));
  646          goto jleave;
  647       }else if(!SSL_CTX_config(ctxp, cp)){
  648          ssl_gen_err(_("*ssl-config-module*: load error for %s, section [%s]"),
  649                n_uagent, n_shexp_quote_cp(cp, FAL0));
  650          goto jleave;
  651       }
  652 # else
  653       n_err(_("*ssl-config-module*: set but not supported: %s\n"),
  654          n_shexp_quote_cp(cp, FAL0));
  655       goto jleave;
  656 # endif
  657    }
  658 
  659    if((sccp = SSL_CONF_CTX_new()) != NULL){
  660       SSL_CONF_CTX_set_flags(sccp,
  661          SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
  662          SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
  663 
  664       SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
  665    }else
  666       ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
  667 jleave:
  668    NYD2_LEAVE;
  669    return sccp;
  670 }
  671 
  672 static bool_t
  673 a_xssl_conf(void *confp, char const *cmd, char const *value){
  674    int rv;
  675    SSL_CONF_CTX *sccp;
  676    NYD2_ENTER;
  677 
  678    if(n_poption & n_PO_D_V)
  679       n_err(_("SSL/TLS: applying config: %s = %s\n"),
  680             n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(value, FAL0));
  681 
  682    rv = SSL_CONF_cmd(sccp = confp, cmd, value);
  683    if(rv == 2)
  684       rv = 0;
  685    else{
  686       cmd = n_shexp_quote_cp(cmd, FAL0);
  687       value = n_shexp_quote_cp(value, FAL0);
  688       if(rv == 0)
  689          ssl_gen_err(_("SSL/TLS: config failure: %s = %s"), cmd, value);
  690       else
  691          n_err(_("SSL/TLS: please report this config error: %s = %s\n"),
  692             cmd, value);
  693       rv = 1;
  694    }
  695    NYD2_LEAVE;
  696    return (rv == 0);
  697 }
  698 
  699 static bool_t
  700 a_xssl_conf_finish(void **confp, bool_t error){
  701    SSL_CONF_CTX **sccp;
  702    bool_t rv;
  703    NYD2_ENTER;
  704 
  705    sccp = (SSL_CONF_CTX**)confp;
  706 
  707    if(!(rv = error))
  708       rv = (SSL_CONF_CTX_finish(*sccp) != 0);
  709 
  710    SSL_CONF_CTX_free(*sccp);
  711 
  712    *sccp = NULL;
  713    NYD2_LEAVE;
  714    return rv;
  715 }
  716 
  717 #else /* HAVE_XSSL_CONF_CTX */
  718 # ifdef HAVE_XSSL_CTX_CONFIG
  719 #  error SSL_CTX_config(3) support unexpected without SSL_CONF_CTX support
  720 # endif
  721 
  722 static void *
  723 a_xssl_conf_setup(SSL_CTX* ctxp, struct url const *urlp){
  724    char const *cp;
  725    NYD2_ENTER;
  726 
  727    if((cp = xok_vlook(ssl_config_module, urlp, OXM_ALL)) != NULL){
  728       n_err(_("*ssl-config-module*: set but not supported: %s\n"),
  729          n_shexp_quote_cp(cp, FAL0));
  730       ctxp = NULL;
  731    }
  732    NYD2_LEAVE;
  733    return ctxp;
  734 }
  735 
  736 static bool_t
  737 a_xssl_conf(void *confp, char const *cmd, char const *value){
  738    char const *xcmd, *emsg;
  739    SSL_CTX *ctxp;
  740    NYD2_ENTER;
  741 
  742    if(n_poption & n_PO_D_V)
  743       n_err(_("SSL/TLS: applying config: %s = %s\n"),
  744             n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(value, FAL0));
  745 
  746    ctxp = confp;
  747 
  748    if(!asccasecmp(cmd, xcmd = "Certificate")){
  749       if(SSL_CTX_use_certificate_chain_file(ctxp, value) != 1){
  750          emsg = N_("SSL/TLS: %s: cannot load from file %s\n");
  751          goto jerr;
  752       }
  753    }else if(!asccasecmp(cmd, xcmd = "CipherList")){
  754       if(SSL_CTX_set_cipher_list(ctxp, value) != 1){
  755          emsg = N_("SSL/TLS: %s: invalid: %s\n");
  756          goto jerr;
  757       }
  758    }else if(!asccasecmp(cmd, xcmd = "Curves")){
  759 #ifdef SSL_CTRL_SET_CURVES_LIST
  760       if(SSL_CTX_set1_curves_list(ctxp, value) != 1){
  761          emsg = N_("SSL/TLS: %s: invalid: %s\n");
  762          goto jerr;
  763       }
  764 #else
  765       value = NULL;
  766       emsg = N_("SSL/TLS: %s: directive not supported\n");
  767       goto jxerr;
  768 #endif
  769    }else if((emsg = NULL, !asccasecmp(cmd, xcmd = "MaxProtocol")) ||
  770          (emsg = (char*)-1, !asccasecmp(cmd, xcmd = "MinProtocol"))){
  771 #ifndef HAVE_XSSL_SET_MIN_PROTO_VERSION
  772       value = NULL;
  773       emsg = N_("SSL/TLS: %s: directive not supported\n");
  774       goto jxerr;
  775 #else
  776       struct a_xssl_protocol const *xpp;
  777       size_t i;
  778 
  779       for(i = 1 /* [0] == ALL */;;){
  780          xpp = &a_xssl_protocols[i];
  781 
  782          if(xpp->sp_ok_minmaxproto && !asccasecmp(value, xpp->sp_name))
  783             break;
  784 
  785          if(++i >= n_NELEM(a_xssl_protocols)){
  786             emsg = N_("SSL/TLS: %s: unsupported element: %s\n");
  787             goto jxerr;
  788          }
  789       }
  790 
  791       if((emsg == NULL ? SSL_CTX_set_max_proto_version(ctxp, xpp->sp_version)
  792             : SSL_CTX_set_min_proto_version(ctxp, xpp->sp_version)) != 1){
  793          emsg = N_("SSL/TLS: %s: invalid protocol: %s\n");
  794          goto jerr;
  795       }
  796 #endif /* !HAVE_XSSL_SET_MIN_PROTO_VERSION */
  797    }else if(!asccasecmp(cmd, xcmd = "Options")){
  798       if(asccasecmp(value, "Bugs")){
  799          emsg = N_("SSL/TLS: %s: fallback only supports value \"Bugs\": %s\n");
  800          goto jxerr;
  801       }
  802       SSL_CTX_set_options(ctxp, SSL_OP_ALL);
  803    }else if(!asccasecmp(cmd, xcmd = "PrivateKey")){
  804       if(SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1){
  805          emsg = N_("%s: cannot load from file %s\n");
  806          goto jerr;
  807       }
  808    }else if(!asccasecmp(cmd, xcmd = "Protocol")){
  809       char *iolist, *cp, addin;
  810       size_t i;
  811       sl_i opts;
  812 
  813       opts = 0;
  814 
  815       for(iolist = cp = savestr(value);
  816             (cp = n_strsep(&iolist, ',', FAL0)) != NULL;){
  817          if(*cp == '\0'){
  818             value = NULL;
  819             emsg = N_("SSL/TLS: %s: empty elements are not supported\n");
  820             goto jxerr;
  821          }
  822 
  823          addin = TRU1;
  824          switch(cp[0]){
  825          case '-': addin = FAL0; /* FALLTHRU */
  826          case '+': ++cp; /* FALLTHRU */
  827          default : break;
  828          }
  829 
  830          for(i = 0;;){
  831             struct a_xssl_protocol const *xpp;
  832 
  833             xpp = &a_xssl_protocols[i];
  834 
  835             if(xpp->sp_ok_proto && !asccasecmp(cp, xpp->sp_name)){
  836                /* We need to inverse the meaning of the _NO_s */
  837                if(!addin)
  838                   opts |= xpp->sp_op_no;
  839                else
  840                   opts &= ~xpp->sp_op_no;
  841                break;
  842             }
  843 
  844             if(++i >= n_NELEM(a_xssl_protocols)){
  845                emsg = N_("SSL/TLS: %s: unsupported element: %s\n");
  846                goto jxerr;
  847             }
  848          }
  849       }
  850 
  851       SSL_CTX_clear_options(ctxp, SSL_OP_NO_SSL_MASK);
  852       SSL_CTX_set_options(ctxp, opts);
  853    }else{
  854       xcmd = n_shexp_quote_cp(cmd, FAL0);
  855       emsg = N_("SSL/TLS: unsupported directive: %s: value: %s\n");
  856       goto jxerr;
  857    }
  858 
  859 jleave:
  860    NYD2_LEAVE;
  861    return (confp != NULL);
  862 jerr:
  863    ssl_gen_err(V_(emsg), xcmd, n_shexp_quote_cp(value, FAL0));
  864    confp = NULL;
  865    goto jleave;
  866 jxerr:
  867    if(value != NULL)
  868       value = n_shexp_quote_cp(value, FAL0);
  869    n_err(V_(emsg), xcmd, value);
  870    confp = NULL;
  871    goto jleave;
  872 }
  873 
  874 static bool_t
  875 a_xssl_conf_finish(void **confp, bool_t error){
  876    n_UNUSED(confp);
  877    n_UNUSED(error);
  878    return TRU1;
  879 }
  880 #endif /* !HAVE_XSSL_CONF_CTX */
  881 
  882 static bool_t
  883 a_xssl_obsolete_conf_vars(void *confp, struct url const *urlp){
  884    char const *cp, *cp_base, *certchain;
  885    bool_t rv;
  886    NYD2_ENTER;
  887 
  888    rv = FAL0;
  889 
  890    /* Certificate via ssl-cert */
  891    if((certchain = cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL){
  892       n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-cert*"));
  893       if((cp_base = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL){
  894          n_err(_("*ssl-cert* value expansion failed: %s\n"),
  895             n_shexp_quote_cp(cp, FAL0));
  896          goto jleave;
  897       }
  898       if(!a_xssl_conf(confp, "Certificate", certchain = cp_base))
  899          goto jleave;
  900    }
  901 
  902    /* CipherList via ssl-ciper-list */
  903    if((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL){
  904       n_OBSOLETE(_("please use *ssl-config-pairs* instead of "
  905          "*ssl-cipher-list*"));
  906       if(!a_xssl_conf(confp, "CipherList", cp))
  907          goto jleave;
  908    }
  909 
  910    /* Curves via ssl-curves */
  911    if((cp = xok_vlook(ssl_curves, urlp, OXM_ALL)) != NULL){
  912       n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-curves*"));
  913       if(!a_xssl_conf(confp, "Curves", cp))
  914          goto jleave;
  915    }
  916 
  917    /* PrivateKey via ssl-key */
  918    if((cp = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL){
  919       n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-curves*"));
  920       if((cp_base = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL){
  921          n_err(_("*ssl-key* value expansion failed: %s\n"),
  922             n_shexp_quote_cp(cp, FAL0));
  923          goto jleave;
  924       }
  925       cp = cp_base;
  926       if(certchain == NULL){
  927          n_err(_("*ssl-key* can only be used together with *ssl-cert*! "
  928             "And use *ssl-config-pairs*!\n"));
  929          goto jleave;
  930       }
  931    }
  932    if((cp != NULL || (cp = certchain) != NULL) &&
  933          !a_xssl_conf(confp, "PrivateKey", cp))
  934       goto jleave;
  935 
  936    /* Protocol via ssl-method or ssl-protocol */
  937    if((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL){
  938       size_t i;
  939 
  940       n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-method*"));
  941       for(i = 0;;){
  942          if(!asccasecmp(_ssl_methods[i].sm_name, cp)){
  943             cp = _ssl_methods[i].sm_map;
  944             break;
  945          }
  946          if(++i == n_NELEM(_ssl_methods)){
  947             n_err(_("Unsupported TLS/SSL method: %s\n"), cp);
  948             goto jleave;
  949          }
  950       }
  951    }
  952    if((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL){
  953       n_OBSOLETE(_("please use *ssl-config-pairs* instead of *ssl-protocol*"));
  954       if(cp != NULL && (n_poption & n_PO_D_V))
  955          n_err(_("*ssl-protocol* overrides *ssl-method*! "
  956             "And please use *ssl-config-pairs* instead!\n"));
  957       cp = cp_base;
  958    }
  959    if(cp != NULL && !a_xssl_conf(confp, "Protocol", cp))
  960       goto jleave;
  961 
  962    rv = TRU1;
  963 jleave:
  964    NYD2_LEAVE;
  965    return rv;
  966 }
  967 
  968 static bool_t
  969 a_xssl_config_pairs(void *confp, struct url const *urlp){
  970    /* Due to interdependencies some commands have to be delayed a bit */
  971    static char const cmdcert[] = "Certificate", cmdprivkey[] = "PrivateKey";
  972    char const *valcert, *valprivkey;
  973    char *pairs, *cp, *cmd, *val;
  974    NYD2_ENTER;
  975 
  976    if((pairs = n_UNCONST(xok_vlook(ssl_config_pairs, urlp, OXM_ALL))) == NULL)
  977       goto jleave;
  978    pairs = savestr(pairs);
  979 
  980    valcert = valprivkey = NULL;
  981 
  982    while((cp = n_strsep_esc(&pairs, ',', FAL0)) != NULL){
  983       char c;
  984       enum{
  985          a_NONE,
  986          a_EXPAND = 1u<<0,
  987          a_CERT = 1u<<1,
  988          a_PRIVKEY = 1u<<2,
  989          a_EXPAND_MASK = a_EXPAND | a_CERT | a_PRIVKEY
  990       } f;
  991 
  992       /* Directive, space trimmed */
  993       if((cmd = strchr(cp, '=')) == NULL){
  994 jenocmd:
  995          if(pairs == NULL)
  996             pairs = n_UNCONST(n_empty);
  997          n_err(_("*ssl-config-pairs*: missing directive: %s; rest: %s\n"),
  998             n_shexp_quote_cp(cp, FAL0), n_shexp_quote_cp(pairs, FAL0));
  999          goto jleave;
 1000       }
 1001       val = &cmd[1];
 1002 
 1003       if((cmd > cp && cmd[-1] == '*')){
 1004          --cmd;
 1005          f = a_EXPAND;
 1006       }else
 1007          f = a_NONE;
 1008       while(cmd > cp && (c = cmd[-1], blankspacechar(c)))
 1009          --cmd;
 1010       if(cmd == cp)
 1011          goto jenocmd;
 1012       *cmd = '\0';
 1013       cmd = cp;
 1014 
 1015       /* Command with special treatment? */
 1016       if(!asccasecmp(cmd, cmdcert))
 1017          f |= a_CERT;
 1018       else if(!asccasecmp(cmd, cmdprivkey))
 1019          f |= a_PRIVKEY;
 1020 
 1021       /* Value, space trimmed */
 1022       while((c = *val) != '\0' && blankspacechar(c))
 1023          ++val;
 1024       cp = &val[strlen(val)];
 1025       while(cp > val && (c = cp[-1], blankspacechar(c)))
 1026          --cp;
 1027       *cp = '\0';
 1028       if(cp == val){
 1029          if(pairs == NULL)
 1030             pairs = n_UNCONST(n_empty);
 1031          n_err(_("*ssl-config-pairs*: missing value: %s; rest: %s\n"),
 1032             n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(pairs, FAL0));
 1033          goto jleave;
 1034       }
 1035 
 1036       /* Filename transformations to be applied? */
 1037       if(f & a_EXPAND_MASK){
 1038          if((cp = fexpand(val, FEXP_LOCAL | FEXP_NOPROTO)) == NULL){
 1039             if(pairs == NULL)
 1040                pairs = n_UNCONST(n_empty);
 1041             n_err(_("*ssl-config-pairs*: value expansion failed: %s: %s; "
 1042                   "rest: %s\n"),
 1043                n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(val, FAL0),
 1044                n_shexp_quote_cp(pairs, FAL0));
 1045             goto jleave;
 1046          }
 1047          val = cp;
 1048       }
 1049 
 1050       /* Some things have to be delayed */
 1051       if(f & a_CERT)
 1052          valcert = val;
 1053       else if(f & a_PRIVKEY)
 1054          valprivkey = val;
 1055       else if(!a_xssl_conf(confp, cmd, val)){
 1056          pairs = n_UNCONST(n_empty);
 1057          goto jleave;
 1058       }
 1059    }
 1060 
 1061    /* Work the delayed ones */
 1062    if((valcert != NULL && !a_xssl_conf(confp, cmdcert, valcert)) ||
 1063          ((valprivkey != NULL || (valprivkey = valcert) != NULL) &&
 1064           !a_xssl_conf(confp, cmdprivkey, valprivkey)))
 1065       pairs = n_UNCONST(n_empty);
 1066 
 1067 jleave:
 1068    NYD2_LEAVE;
 1069    return (pairs == NULL);
 1070 }
 1071 
 1072 static bool_t
 1073 a_xssl_load_verifications(SSL_CTX *ctxp, struct url const *urlp){
 1074    char *ca_dir, *ca_file;
 1075    X509_STORE *store;
 1076    bool_t rv;
 1077    NYD2_ENTER;
 1078 
 1079    if(ssl_verify_level == SSL_VERIFY_IGNORE){
 1080       rv = TRU1;
 1081       goto jleave;
 1082    }
 1083    rv = FAL0;
 1084 
 1085    if((ca_dir = xok_vlook(ssl_ca_dir, urlp, OXM_ALL)) != NULL)
 1086       ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
 1087    if((ca_file = xok_vlook(ssl_ca_file, urlp, OXM_ALL)) != NULL)
 1088       ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
 1089 
 1090    if((ca_dir != NULL || ca_file != NULL) &&
 1091          SSL_CTX_load_verify_locations(ctxp, ca_file, ca_dir) != 1){
 1092       char const *m1, *m2, *m3;
 1093 
 1094       if(ca_dir != NULL){
 1095          m1 = ca_dir;
 1096          m2 = (ca_file != NULL) ? _(" or ") : n_empty;
 1097       }else
 1098          m1 = m2 = n_empty;
 1099       m3 = (ca_file != NULL) ? ca_file : n_empty;
 1100       ssl_gen_err(_("Error loading %s%s%s\n"), m1, m2, m3);
 1101       goto jleave;
 1102    }
 1103 
 1104    /* C99 */{
 1105       bool_t xv15;
 1106 
 1107       if((xv15 = ok_blook(ssl_no_default_ca)))
 1108          n_OBSOLETE(_("please use *ssl-ca-no-defaults*, "
 1109             "not *ssl-no-default-ca*"));
 1110       if(!xok_blook(ssl_ca_no_defaults, urlp, OXM_ALL) && !xv15 &&
 1111             SSL_CTX_set_default_verify_paths(ctxp) != 1) {
 1112          ssl_gen_err(_("Error loading built-in default CA locations\n"));
 1113          goto jleave;
 1114       }
 1115    }
 1116 
 1117    a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
 1118    a_xssl_msgno = 0;
 1119    SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &_ssl_verify_cb);
 1120    store = SSL_CTX_get_cert_store(ctxp);
 1121    load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
 1122    a_xssl_ca_flags(store, xok_vlook(ssl_ca_flags, urlp, OXM_ALL));
 1123 
 1124    rv = TRU1;
 1125 jleave:
 1126    NYD2_LEAVE;
 1127    return rv;
 1128 }
 1129 
 1130 static enum okay
 1131 ssl_check_host(struct sock *sp, struct url const *urlp)
 1132 {
 1133    char data[256];
 1134    X509 *cert;
 1135    n_XSSL_STACKOF(GENERAL_NAME) *gens;
 1136    GENERAL_NAME *gen;
 1137    X509_NAME *subj;
 1138    enum okay rv = STOP;
 1139    NYD_ENTER;
 1140 
 1141    if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
 1142       n_err(_("No certificate from: %s\n"), urlp->url_h_p.s);
 1143       goto jleave;
 1144    }
 1145 
 1146    gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
 1147    if (gens != NULL) {
 1148       int i;
 1149 
 1150       for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
 1151          gen = sk_GENERAL_NAME_value(gens, i);
 1152          if (gen->type == GEN_DNS) {
 1153             if (n_poption & n_PO_D_V)
 1154                n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
 1155                   urlp->url_host.s, (char*)gen->d.ia5->data);
 1156             rv = rfc2595_hostname_match(urlp->url_host.s,
 1157                   (char*)gen->d.ia5->data);
 1158             if (rv == OKAY)
 1159                goto jdone;
 1160          }
 1161       }
 1162    }
 1163 
 1164    if ((subj = X509_get_subject_name(cert)) != NULL &&
 1165          X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
 1166             > 0) {
 1167       data[sizeof data - 1] = '\0';
 1168       if (n_poption & n_PO_D_V)
 1169          n_err(_("Comparing commonName: need<%s> is<%s>\n"),
 1170             urlp->url_host.s, data);
 1171       rv = rfc2595_hostname_match(urlp->url_host.s, data);
 1172    }
 1173 
 1174 jdone:
 1175    X509_free(cert);
 1176 jleave:
 1177    NYD_LEAVE;
 1178    return rv;
 1179 }
 1180 
 1181 static int
 1182 smime_verify(struct message *m, int n, n_XSSL_STACKOF(X509) *chain,
 1183    X509_STORE *store)
 1184 {
 1185    char data[LINESIZE], *sender, *to, *cc, *cnttype;
 1186    int rv, c, i, j;
 1187    struct message *x;
 1188    FILE *fp, *ip;
 1189    off_t size;
 1190    BIO *fb, *pb;
 1191    PKCS7 *pkcs7;
 1192    n_XSSL_STACKOF(X509) *certs;
 1193    n_XSSL_STACKOF(GENERAL_NAME) *gens;
 1194    X509 *cert;
 1195    X509_NAME *subj;
 1196    GENERAL_NAME *gen;
 1197    NYD_ENTER;
 1198 
 1199    rv = 1;
 1200    fp = NULL;
 1201    fb = pb = NULL;
 1202    pkcs7 = NULL;
 1203    certs = NULL;
 1204    a_xssl_state &= ~a_XSSL_S_VERIFY_ERROR;
 1205    a_xssl_msgno = (size_t)n;
 1206 
 1207    for (;;) {
 1208       sender = getsender(m);
 1209       to = hfield1("to", m);
 1210       cc = hfield1("cc", m);
 1211       cnttype = hfield1("content-type", m);
 1212 
 1213 #undef _X
 1214 #undef _Y
 1215 #define _X     (sizeof("application/") -1)
 1216 #define _Y(X)  X, sizeof(X) -1
 1217       if (cnttype && is_asccaseprefix("application/", cnttype) &&
 1218             (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
 1219              !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
 1220 #undef _Y
 1221 #undef _X
 1222          if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
 1223             goto jleave;
 1224          if (x != (struct message*)-1) {
 1225             m = x;
 1226             continue;
 1227          }
 1228       }
 1229 
 1230       if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
 1231          goto jleave;
 1232       size = m->m_size;
 1233       break;
 1234    }
 1235 
 1236    if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
 1237          NULL) {
 1238       n_perr(_("tempfile"), 0);
 1239       goto jleave;
 1240    }
 1241    while (size-- > 0) {
 1242       c = getc(ip);
 1243       putc(c, fp);
 1244    }
 1245    fflush_rewind(fp);
 1246 
 1247    if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
 1248       ssl_gen_err(_(
 1249          "Error creating BIO verification object for message %d"), n);
 1250       goto jleave;
 1251    }
 1252 
 1253    if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
 1254       ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
 1255       goto jleave;
 1256    }
 1257    if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
 1258       ssl_gen_err(_("Error verifying message %d"), n);
 1259       goto jleave;
 1260    }
 1261 
 1262    if (sender == NULL) {
 1263       n_err(_("Warning: Message %d has no sender\n"), n);
 1264       rv = 0;
 1265       goto jleave;
 1266    }
 1267 
 1268    certs = PKCS7_get0_signers(pkcs7, chain, 0);
 1269    if (certs == NULL) {
 1270       n_err(_("No certificates found in message %d\n"), n);
 1271       goto jleave;
 1272    }
 1273 
 1274    for (i = 0; i < sk_X509_num(certs); ++i) {
 1275       cert = sk_X509_value(certs, i);
 1276       gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
 1277       if (gens != NULL) {
 1278          for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
 1279             gen = sk_GENERAL_NAME_value(gens, j);
 1280             if (gen->type == GEN_EMAIL) {
 1281                if (n_poption & n_PO_D_V)
 1282                   n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
 1283                      sender, (char*)gen->d.ia5->data);
 1284                if (!asccasecmp((char*)gen->d.ia5->data, sender))
 1285                   goto jfound;
 1286             }
 1287          }
 1288       }
 1289 
 1290       if ((subj = X509_get_subject_name(cert)) != NULL &&
 1291             X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
 1292                data, sizeof data) > 0) {
 1293          data[sizeof data -1] = '\0';
 1294          if (n_poption & n_PO_D_V)
 1295             n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
 1296                sender, data);
 1297          if (!asccasecmp(data, sender))
 1298             goto jfound;
 1299       }
 1300    }
 1301    n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
 1302    goto jleave;
 1303 jfound:
 1304    rv = ((a_xssl_state & a_XSSL_S_VERIFY_ERROR) != 0);
 1305    if (!rv)
 1306       fprintf(n_stdout, _("Message %d was verified successfully\n"), n);
 1307 jleave:
 1308    if (certs != NULL)
 1309       sk_X509_free(certs);
 1310    if (pb != NULL)
 1311       BIO_free(pb);
 1312    if (fb != NULL)
 1313       BIO_free(fb);
 1314    if (pkcs7 != NULL)
 1315       PKCS7_free(pkcs7);
 1316    if (fp != NULL)
 1317       Fclose(fp);
 1318    NYD_LEAVE;
 1319    return rv;
 1320 }
 1321 
 1322 static EVP_CIPHER const *
 1323 _smime_cipher(char const *name)
 1324 {
 1325    EVP_CIPHER const *cipher;
 1326    char *vn;
 1327    char const *cp;
 1328    size_t i;
 1329    NYD_ENTER;
 1330 
 1331    vn = ac_alloc(i = strlen(name) + sizeof("smime-cipher-") -1 +1);
 1332    snprintf(vn, (int)i, "smime-cipher-%s", name);
 1333    cp = n_var_vlook(vn, FAL0);
 1334    ac_free(vn);
 1335 
 1336    if (cp == NULL && (cp = ok_vlook(smime_cipher)) == NULL) {
 1337       cipher = a_XSSL_SMIME_DEFAULT_CIPHER();
 1338       goto jleave;
 1339    }
 1340    cipher = NULL;
 1341 
 1342    for (i = 0; i < n_NELEM(a_xssl_smime_ciphers); ++i)
 1343       if (!asccasecmp(a_xssl_smime_ciphers[i].sc_name, cp)) {
 1344          cipher = (*a_xssl_smime_ciphers[i].sc_fun)();
 1345          goto jleave;
 1346       }
 1347 #ifndef OPENSSL_NO_AES
 1348    for (i = 0; i < n_NELEM(a_xssl_smime_ciphers_obs); ++i) /* TODO obsolete */
 1349       if (!asccasecmp(a_xssl_smime_ciphers_obs[i].sc_name, cp)) {
 1350          n_OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
 1351          cipher = (*a_xssl_smime_ciphers_obs[i].sc_fun)();
 1352          goto jleave;
 1353       }
 1354 #endif
 1355 
 1356    /* Not a built-in algorithm, but we may have dynamic support for more */
 1357 #ifdef HAVE_SSL_ALL_ALGORITHMS
 1358    if((cipher = EVP_get_cipherbyname(cp)) != NULL)
 1359       goto jleave;
 1360 #endif
 1361 
 1362    n_err(_("Invalid S/MIME cipher(s): %s\n"), cp);
 1363 jleave:
 1364    NYD_LEAVE;
 1365    return cipher;
 1366 }
 1367 
 1368 static int
 1369 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
 1370 {
 1371    char *pass;
 1372    size_t len;
 1373    NYD_ENTER;
 1374    n_UNUSED(rwflag);
 1375    n_UNUSED(userdata);
 1376 
 1377    /* New-style */
 1378    if(userdata != NULL){
 1379       struct url url;
 1380       struct ccred cred;
 1381 
 1382       if(url_parse(&url, CPROTO_CCRED, userdata)){
 1383          if(ccred_lookup(&cred, &url)){
 1384             ssize_t slen;
 1385 
 1386             if((slen = n_strscpy(buf, cred.cc_pass.s, size)) >= 0){
 1387                size = (int)slen;
 1388                goto jleave;
 1389             }
 1390          }
 1391          size = 0;
 1392          goto jleave;
 1393       }
 1394    }
 1395 
 1396    /* Old-style */
 1397    if ((pass = getpassword("PEM pass phrase:")) != NULL) {
 1398       len = strlen(pass);
 1399       if (UICMP(z, len, >=, size))
 1400          len = size -1;
 1401       memcpy(buf, pass, len);
 1402       buf[len] = '\0';
 1403       size = (int)len;
 1404    } else
 1405       size = 0;
 1406 jleave:
 1407    NYD_LEAVE;
 1408    return size;
 1409 }
 1410 
 1411 static FILE *
 1412 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn,
 1413    char const **match)
 1414 {
 1415    char *vn;
 1416    int vs;
 1417    struct name *np;
 1418    char const *name = xname, *name2 = xname2, *cp;
 1419    FILE *fp = NULL;
 1420    NYD_ENTER;
 1421 
 1422 jloop:
 1423    if (name) {
 1424       np = lextract(name, GTO | GSKIN);
 1425       while (np != NULL) {
 1426          /* This needs to be more intelligent since it will currently take the
 1427           * first name for which a private key is available regardless of
 1428           * whether it is the right one for the message */
 1429          vn = ac_alloc(vs = strlen(np->n_name) + 30);
 1430          snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
 1431          cp = n_var_vlook(vn, FAL0);
 1432          ac_free(vn);
 1433          if (cp != NULL) {
 1434             if (match != NULL)
 1435                *match = np->n_name;
 1436             goto jopen;
 1437          }
 1438          np = np->n_flink;
 1439       }
 1440       if (name2 != NULL) {
 1441          name = name2;
 1442          name2 = NULL;
 1443          goto jloop;
 1444       }
 1445    }
 1446 
 1447    if ((cp = ok_vlook(smime_sign_cert)) == NULL)
 1448       goto jerr;
 1449    if(match != NULL)
 1450       *match = NULL;
 1451 jopen:
 1452    if ((cp = fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
 1453       goto jleave;
 1454    if ((fp = Fopen(cp, "r")) == NULL)
 1455       n_perr(cp, 0);
 1456 jleave:
 1457    NYD_LEAVE;
 1458    return fp;
 1459 jerr:
 1460    if (dowarn)
 1461       n_err(_("Could not find a certificate for %s%s%s\n"),
 1462          xname, (xname2 != NULL ? _("or ") : n_empty),
 1463          (xname2 != NULL ? xname2 : n_empty));
 1464    goto jleave;
 1465 }
 1466 
 1467 static char const *
 1468 _smime_sign_include_certs(char const *name)
 1469 {
 1470    char const *rv;
 1471    NYD_ENTER;
 1472 
 1473    /* See comments in smime_sign_cert() for algorithm pitfalls */
 1474    if (name != NULL) {
 1475       struct name *np;
 1476 
 1477       for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
 1478          int vs;
 1479          char *vn;
 1480 
 1481          vn = ac_alloc(vs = strlen(np->n_name) + 30);
 1482          snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
 1483          rv = n_var_vlook(vn, FAL0);
 1484          ac_free(vn);
 1485          if (rv != NULL)
 1486             goto jleave;
 1487       }
 1488    }
 1489    rv = ok_vlook(smime_sign_include_certs);
 1490 jleave:
 1491    NYD_LEAVE;
 1492    return rv;
 1493 }
 1494 
 1495 static bool_t
 1496 _smime_sign_include_chain_creat(n_XSSL_STACKOF(X509) **chain,
 1497    char const *cfiles, char const *addr)
 1498 {
 1499    X509 *tmp;
 1500    FILE *fp;
 1501    char *nfield, *cfield, *x;
 1502    NYD_ENTER;
 1503 
 1504    *chain = sk_X509_new_null();
 1505 
 1506    for (nfield = savestr(cfiles);
 1507          (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
 1508       if ((x = fexpand(cfield, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
 1509             (fp = Fopen(cfield = x, "r")) == NULL) {
 1510          n_perr(cfiles, 0);
 1511          goto jerr;
 1512       }
 1513       if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, n_UNCONST(addr))
 1514             ) == NULL) {
 1515          ssl_gen_err(_("Error reading certificate from %s"),
 1516             n_shexp_quote_cp(cfield, FAL0));
 1517          Fclose(fp);
 1518          goto jerr;
 1519       }
 1520       sk_X509_push(*chain, tmp);
 1521       Fclose(fp);
 1522    }
 1523 
 1524    if (sk_X509_num(*chain) == 0) {
 1525       n_err(_("*smime-sign-include-certs* defined but empty\n"));
 1526       goto jerr;
 1527    }
 1528 jleave:
 1529    NYD_LEAVE;
 1530    return (*chain != NULL);
 1531 jerr:
 1532    sk_X509_pop_free(*chain, X509_free);
 1533    *chain = NULL;
 1534    goto jleave;
 1535 }
 1536 
 1537 static EVP_MD const *
 1538 _smime_sign_digest(char const *name, char const **digname)
 1539 {
 1540    EVP_MD const *digest;
 1541    char const *cp;
 1542    size_t i;
 1543    NYD_ENTER;
 1544 
 1545    /* See comments in smime_sign_cert() for algorithm pitfalls */
 1546    if (name != NULL) {
 1547       struct name *np;
 1548 
 1549       for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
 1550          int vs;
 1551          char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
 1552          snprintf(vn, vs, "smime-sign-message-digest-%s", np->n_name);
 1553          cp = n_var_vlook(vn, FAL0);
 1554          ac_free(vn);
 1555          if (cp != NULL)
 1556             goto jhave_name;
 1557       }
 1558    }
 1559 
 1560    if ((cp = ok_vlook(smime_sign_message_digest)) == NULL) {
 1561       digest = a_XSSL_SMIME_DEFAULT_DIGEST();
 1562       *digname = a_XSSL_SMIME_DEFAULT_DIGEST_S;
 1563       goto jleave;
 1564    }
 1565 
 1566 jhave_name:
 1567    i = strlen(cp);
 1568    {  char *x = salloc(i +1);
 1569       i_strcpy(x, cp, i +1);
 1570       cp = x;
 1571    }
 1572    *digname = cp;
 1573 
 1574    for (i = 0; i < n_NELEM(a_xssl_smime_digests); ++i)
 1575       if (!asccasecmp(a_xssl_smime_digests[i].sd_name, cp)) {
 1576          digest = (*a_xssl_smime_digests[i].sd_fun)();
 1577          goto jleave;
 1578       }
 1579 
 1580    /* Not a built-in algorithm, but we may have dynamic support for more */
 1581 #ifdef HAVE_SSL_ALL_ALGORITHMS
 1582    if((digest = EVP_get_digestbyname(cp)) != NULL)
 1583       goto jleave;
 1584 #endif
 1585 
 1586    n_err(_("Invalid message digest: %s\n"), cp);
 1587    digest = NULL;
 1588 jleave:
 1589    NYD_LEAVE;
 1590    return digest;
 1591 }
 1592 
 1593 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
 1594 static enum okay
 1595 load_crl1(X509_STORE *store, char const *name)
 1596 {
 1597    X509_LOOKUP *lookup;
 1598    enum okay rv = STOP;
 1599    NYD_ENTER;
 1600 
 1601    if (n_poption & n_PO_D_V)
 1602       n_err(_("Loading CRL from %s\n"), n_shexp_quote_cp(name, FAL0));
 1603    if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
 1604       ssl_gen_err(_("Error creating X509 lookup object"));
 1605       goto jleave;
 1606    }
 1607    if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
 1608       ssl_gen_err(_("Error loading CRL from %s"), n_shexp_quote_cp(name, FAL0));
 1609       goto jleave;
 1610    }
 1611    rv = OKAY;
 1612 jleave:
 1613    NYD_LEAVE;
 1614    return rv;
 1615 }
 1616 #endif /* new OpenSSL */
 1617 
 1618 static enum okay
 1619 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
 1620 {
 1621    char *crl_file, *crl_dir;
 1622 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
 1623    DIR *dirp;
 1624    struct dirent *dp;
 1625    char *fn = NULL;
 1626    int fs = 0, ds, es;
 1627 #endif
 1628    enum okay rv = STOP;
 1629    NYD_ENTER;
 1630 
 1631    if ((crl_file = n_var_oklook(fok)) != NULL) {
 1632 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
 1633       if ((crl_file = fexpand(crl_file, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
 1634             load_crl1(store, crl_file) != OKAY)
 1635          goto jleave;
 1636 #else
 1637       n_err(_("This OpenSSL version is too old to use CRLs\n"));
 1638       goto jleave;
 1639 #endif
 1640    }
 1641 
 1642    if ((crl_dir = n_var_oklook(dok)) != NULL) {
 1643 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
 1644       char *x;
 1645       if ((x = fexpand(crl_dir, FEXP_LOCAL | FEXP_NOPROTO)) == NULL ||
 1646             (dirp = opendir(crl_dir = x)) == NULL) {
 1647          n_perr(crl_dir, 0);
 1648          goto jleave;
 1649       }
 1650 
 1651       ds = strlen(crl_dir);
 1652       fn = smalloc(fs = ds + 20);
 1653       memcpy(fn, crl_dir, ds);
 1654       fn[ds] = '/';
 1655       while ((dp = readdir(dirp)) != NULL) {
 1656          if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
 1657                (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
 1658             continue;
 1659          if (dp->d_name[0] == '.')
 1660             continue;
 1661          if (ds + (es = strlen(dp->d_name)) + 2 < fs)
 1662             fn = srealloc(fn, fs = ds + es + 20);
 1663          memcpy(fn + ds + 1, dp->d_name, es + 1);
 1664          if (load_crl1(store, fn) != OKAY) {
 1665             closedir(dirp);
 1666             free(fn);
 1667             goto jleave;
 1668          }
 1669       }
 1670       closedir(dirp);
 1671       free(fn);
 1672 #else /* old OpenSSL */
 1673       n_err(_("This OpenSSL version is too old to use CRLs\n"));
 1674       goto jleave;
 1675 #endif
 1676    }
 1677 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
 1678    if (crl_file || crl_dir)
 1679       X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
 1680          X509_V_FLAG_CRL_CHECK_ALL);
 1681 #endif
 1682    rv = OKAY;
 1683 jleave:
 1684    NYD_LEAVE;
 1685    return rv;
 1686 }
 1687 
 1688 #if n_RANDOM_USE_XSSL
 1689 FL void
 1690 ssl_rand_bytes(void *buf, size_t blen){
 1691    NYD_ENTER;
 1692 
 1693    if(!(a_xssl_state & a_XSSL_S_RAND_INIT))
 1694       a_xssl_rand_init();
 1695 
 1696    while(blen > 0){
 1697       si32_t i;
 1698 
 1699       i = n_MIN(SI32_MAX, blen);
 1700       blen -= i;
 1701       RAND_bytes(buf, i);
 1702       buf = (ui8_t*)buf + i;
 1703    }
 1704    NYD_LEAVE;
 1705 }
 1706 #endif
 1707 
 1708 FL enum okay
 1709 ssl_open(struct url const *urlp, struct sock *sp){
 1710    void *confp;
 1711    SSL_CTX *ctxp;
 1712    enum okay rv;
 1713    NYD_ENTER;
 1714 
 1715    a_xssl_init();
 1716 
 1717    rv = STOP;
 1718    ssl_set_verify_level(urlp);
 1719 
 1720    if((ctxp = SSL_CTX_new(n_XSSL_CLIENT_METHOD())) == NULL){
 1721       ssl_gen_err(_("SSL_CTX_new() failed"));
 1722       goto jleave;
 1723    }
 1724 
 1725    /* Available with OpenSSL 0.9.6 or later */
 1726 #ifdef SSL_MODE_AUTO_RETRY
 1727    SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
 1728 #endif
 1729 
 1730    if((confp = a_xssl_conf_setup(ctxp, urlp)) == NULL)
 1731       goto jerr0;
 1732 
 1733    if(!a_xssl_obsolete_conf_vars(confp, urlp))
 1734       goto jerr1;
 1735    if(!a_xssl_config_pairs(confp, urlp))
 1736       goto jerr1;
 1737    if(!a_xssl_load_verifications(ctxp, urlp))
 1738       goto jerr1;
 1739 
 1740    /* Done with context setup, create our new per-connection structure */
 1741    if(!a_xssl_conf_finish(&confp, FAL0))
 1742       goto jerr0;
 1743 
 1744    if ((sp->s_ssl = SSL_new(ctxp)) == NULL) {
 1745       ssl_gen_err(_("SSL_new() failed"));
 1746       goto jerr0;
 1747    }
 1748 
 1749    /* Try establish SNI extension; even though this is a TLS extension the
 1750     * protocol isn't checked once the host name is set, and therefore i've
 1751     * refrained from changing so much code just to check out whether we are
 1752     * using SSLv3, which should become more and more rare */
 1753 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
 1754    if((urlp->url_flags & n_URL_TLS_MASK) &&
 1755          (urlp->url_flags & n_URL_HOST_IS_NAME)){
 1756       if(!SSL_set_tlsext_host_name(sp->s_ssl, urlp->url_host.s) &&
 1757             (n_poption & n_PO_D_V))
 1758          n_err(_("Hostname cannot be used with ServerNameIndication "
 1759                "TLS extension: %s\n"),
 1760             n_shexp_quote_cp(urlp->url_host.s, FAL0));
 1761    }
 1762 #endif
 1763 
 1764    SSL_set_fd(sp->s_ssl, sp->s_fd);
 1765 
 1766    if (SSL_connect(sp->s_ssl) < 0) {
 1767       ssl_gen_err(_("could not initiate SSL/TLS connection"));
 1768       goto jerr2;
 1769    }
 1770 
 1771    if (ssl_verify_level != SSL_VERIFY_IGNORE) {
 1772       if (ssl_check_host(sp, urlp) != OKAY) {
 1773          n_err(_("Host certificate does not match: %s\n"), urlp->url_h_p.s);
 1774          if (ssl_verify_decide() != OKAY)
 1775             goto jerr2;
 1776       }
 1777    }
 1778 
 1779    /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
 1780     * and free it right now -- it is reference counted by sp->s_ssl.. */
 1781    SSL_CTX_free(ctxp);
 1782    sp->s_use_ssl = 1;
 1783    rv = OKAY;
 1784 jleave:
 1785    NYD_LEAVE;
 1786    return rv;
 1787 jerr2:
 1788    SSL_free(sp->s_ssl);
 1789    sp->s_ssl = NULL;
 1790 jerr1:
 1791    if (confp != NULL)
 1792       a_xssl_conf_finish(&confp, TRU1);
 1793 jerr0:
 1794    SSL_CTX_free(ctxp);
 1795    goto jleave;
 1796 }
 1797 
 1798 FL void
 1799 ssl_gen_err(char const *fmt, ...)
 1800 {
 1801    va_list ap;
 1802    NYD_ENTER;
 1803 
 1804    va_start(ap, fmt);
 1805    n_verr(fmt, ap);
 1806    va_end(ap);
 1807 
 1808    n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
 1809    NYD_LEAVE;
 1810 }
 1811 
 1812 FL int
 1813 c_verify(void *vp)
 1814 {
 1815    int *msgvec = vp, *ip, ec = 0, rv = 1;
 1816    X509_STORE *store = NULL;
 1817    char *ca_dir, *ca_file;
 1818    NYD_ENTER;
 1819 
 1820    a_xssl_init();
 1821 
 1822    ssl_verify_level = SSL_VERIFY_STRICT;
 1823    if ((store = X509_STORE_new()) == NULL) {
 1824       ssl_gen_err(_("Error creating X509 store"));
 1825       goto jleave;
 1826    }
 1827    X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
 1828 
 1829    if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
 1830       ca_dir = fexpand(ca_dir, FEXP_LOCAL | FEXP_NOPROTO);
 1831    if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
 1832       ca_file = fexpand(ca_file, FEXP_LOCAL | FEXP_NOPROTO);
 1833 
 1834    if (ca_dir != NULL || ca_file != NULL) {
 1835       if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
 1836          ssl_gen_err(_("Error loading %s"),
 1837             (ca_file != NULL) ? ca_file : ca_dir);
 1838          goto jleave;
 1839       }
 1840    }
 1841 
 1842    /* C99 */{
 1843       bool_t xv15;
 1844 
 1845       if((xv15 = ok_blook(smime_no_default_ca)))
 1846          n_OBSOLETE(_("please use *smime-ca-no-defaults*, "
 1847             "not *smime-no-default-ca*"));
 1848       if(!ok_blook(smime_ca_no_defaults) && !xv15 &&
 1849             X509_STORE_set_default_paths(store) != 1) {
 1850          ssl_gen_err(_("Error loading built-in default CA locations\n"));
 1851          goto jleave;
 1852       }
 1853    }
 1854 
 1855    if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
 1856       goto jleave;
 1857 
 1858    a_xssl_ca_flags(store, ok_vlook(smime_ca_flags));
 1859 
 1860    srelax_hold();
 1861    for (ip = msgvec; *ip != 0; ++ip) {
 1862       struct message *mp = message + *ip - 1;
 1863       setdot(mp);
 1864       ec |= smime_verify(mp, *ip, NULL, store);
 1865       srelax();
 1866    }
 1867    srelax_rele();
 1868 
 1869    if ((rv = ec) != 0)
 1870       n_exit_status |= n_EXIT_ERR;
 1871 jleave:
 1872    if (store != NULL)
 1873       X509_STORE_free(store);
 1874    NYD_LEAVE;
 1875    return rv;
 1876 }
 1877 
 1878 FL FILE *
 1879 smime_sign(FILE *ip, char const *addr)
 1880 {
 1881    FILE *rv, *sp, *fp, *bp, *hp;
 1882    X509 *cert = NULL;
 1883    n_XSSL_STACKOF(X509) *chain = NULL;
 1884    EVP_PKEY *pkey = NULL;
 1885    BIO *bb, *sb;
 1886    PKCS7 *pkcs7;
 1887    EVP_MD const *md;
 1888    char const *name;
 1889    bool_t bail = FAL0;
 1890    NYD_ENTER;
 1891 
 1892    assert(addr != NULL);
 1893    rv = sp = fp = bp = hp = NULL;
 1894 
 1895    a_xssl_init();
 1896 
 1897    if (addr == NULL) {
 1898       n_err(_("No *from* address for signing specified\n"));
 1899       goto jleave;
 1900    }
 1901    if ((fp = smime_sign_cert(addr, NULL, 1, NULL)) == NULL)
 1902       goto jleave;
 1903 
 1904    if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb,
 1905          savecat(addr, ".smime-cert-key"))) == NULL) {
 1906       ssl_gen_err(_("Error reading private key from"));
 1907       goto jleave;
 1908    }
 1909 
 1910    rewind(fp);
 1911    if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb,
 1912          savecat(addr, ".smime-cert-cert"))) == NULL) {
 1913       ssl_gen_err(_("Error reading signer certificate from"));
 1914       goto jleave;
 1915    }
 1916    Fclose(fp);
 1917    fp = NULL;
 1918 
 1919    if ((name = _smime_sign_include_certs(addr)) != NULL &&
 1920          !_smime_sign_include_chain_creat(&chain, name,
 1921             savecat(addr, ".smime-include-certs")))
 1922       goto jleave;
 1923 
 1924    name = NULL;
 1925    if ((md = _smime_sign_digest(addr, &name)) == NULL)
 1926       goto jleave;
 1927 
 1928    if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
 1929          NULL) {
 1930       n_perr(_("tempfile"), 0);
 1931       goto jleave;
 1932    }
 1933 
 1934    rewind(ip);
 1935    if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
 1936       goto jleave;
 1937 
 1938    sb = NULL;
 1939    pkcs7 = NULL;
 1940 
 1941    if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
 1942          (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
 1943       ssl_gen_err(_("Error creating BIO signing objects"));
 1944       bail = TRU1;
 1945       goto jerr;
 1946    }
 1947 
 1948 #undef _X
 1949 #define _X  PKCS7_DETACHED | PKCS7_PARTIAL
 1950    if ((pkcs7 = PKCS7_sign(NULL, NULL, chain, bb, _X)) == NULL) {
 1951       ssl_gen_err(_("Error creating the PKCS#7 signing object"));
 1952       bail = TRU1;
 1953       goto jerr;
 1954    }
 1955    if (PKCS7_sign_add_signer(pkcs7, cert, pkey, md, _X) == NULL) {
 1956       ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
 1957       bail = TRU1;
 1958       goto jerr;
 1959    }
 1960    if (!PKCS7_final(pkcs7, bb, _X)) {
 1961       ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
 1962       bail = TRU1;
 1963       goto jerr;
 1964    }
 1965 #undef _X
 1966 
 1967    if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
 1968       ssl_gen_err(_("Error writing signed S/MIME data"));
 1969       bail = TRU1;
 1970       /*goto jerr*/
 1971    }
 1972 jerr:
 1973    if (pkcs7 != NULL)
 1974       PKCS7_free(pkcs7);
 1975    if (sb != NULL)
 1976       BIO_free(sb);
 1977    if (bb != NULL)
 1978       BIO_free(bb);
 1979    if (!bail) {
 1980       rewind(bp);
 1981       fflush_rewind(sp);
 1982       rv = smime_sign_assemble(hp, bp, sp, name);
 1983       hp = bp = sp = NULL;
 1984    }
 1985 
 1986 jleave:
 1987    if (chain != NULL)
 1988       sk_X509_pop_free(chain, X509_free);
 1989    if (cert != NULL)
 1990       X509_free(cert);
 1991    if (pkey != NULL)
 1992       EVP_PKEY_free(pkey);
 1993    if (fp != NULL)
 1994       Fclose(fp);
 1995    if (hp != NULL)
 1996       Fclose(hp);
 1997    if (bp != NULL)
 1998       Fclose(bp);
 1999    if (sp != NULL)
 2000       Fclose(sp);
 2001    NYD_LEAVE;
 2002    return rv;
 2003 }
 2004 
 2005 FL FILE *
 2006 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
 2007 {
 2008    FILE *rv, *yp, *fp, *bp, *hp;
 2009    X509 *cert;
 2010    PKCS7 *pkcs7;
 2011    BIO *bb, *yb;
 2012    n_XSSL_STACKOF(X509) *certs;
 2013    EVP_CIPHER const *cipher;
 2014    char *certfile;
 2015    bool_t bail;
 2016    NYD_ENTER;
 2017 
 2018    bail = FAL0;
 2019    rv = yp = fp = bp = hp = NULL;
 2020 
 2021    if ((certfile = fexpand(xcertfile, FEXP_LOCAL | FEXP_NOPROTO)) == NULL)
 2022       goto jleave;
 2023 
 2024    a_xssl_init();
 2025 
 2026    if ((cipher = _smime_cipher(to)) == NULL)
 2027       goto jleave;
 2028 
 2029    if ((fp = Fopen(certfile, "r")) == NULL) {
 2030       n_perr(certfile, 0);
 2031       goto jleave;
 2032    }
 2033    if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
 2034       ssl_gen_err(_("Error reading encryption certificate from %s"),
 2035          n_shexp_quote_cp(certfile, FAL0));
 2036       bail = TRU1;
 2037    }
 2038    if (bail)
 2039       goto jleave;
 2040    Fclose(fp);
 2041    fp = NULL;
 2042    bail = FAL0;
 2043 
 2044    certs = sk_X509_new_null();
 2045    sk_X509_push(certs, cert);
 2046 
 2047    if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
 2048          NULL) {
 2049       n_perr(_("tempfile"), 0);
 2050       goto jerr1;
 2051    }
 2052 
 2053    rewind(ip);
 2054    if (smime_split(ip, &hp, &bp, -1, 0) == STOP)
 2055       goto jerr1;
 2056 
 2057    yb = NULL;
 2058    if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
 2059          (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
 2060       ssl_gen_err(_("Error creating BIO encryption objects"));
 2061       bail = TRU1;
 2062       goto jerr2;
 2063    }
 2064    if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
 2065       ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
 2066       bail = TRU1;
 2067       goto jerr2;
 2068    }
 2069    if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
 2070       ssl_gen_err(_("Error writing encrypted S/MIME data"));
 2071       bail = TRU1;
 2072       /* goto jerr2 */
 2073    }
 2074    PKCS7_free(pkcs7);
 2075 
 2076 jerr2:
 2077    if (bb != NULL)
 2078       BIO_free(bb);
 2079    if (yb != NULL)
 2080       BIO_free(yb);
 2081    Fclose(bp);
 2082    bp = NULL;
 2083    if (!bail) {
 2084       fflush_rewind(yp);
 2085       rv = smime_encrypt_assemble(hp, yp);
 2086       hp = yp = NULL;
 2087    }
 2088 jerr1:
 2089    sk_X509_pop_free(certs, X509_free);
 2090 jleave:
 2091    if(yp != NULL)
 2092       Fclose(yp);
 2093    if(fp != NULL)
 2094       Fclose(fp);
 2095    if(bp != NULL)
 2096       Fclose(bp);
 2097    if(hp != NULL)
 2098       Fclose(hp);
 2099    NYD_LEAVE;
 2100    return rv;
 2101 }
 2102 
 2103 FL struct message *
 2104 smime_decrypt(struct message *m, char const *to, char const *cc,
 2105    bool_t signcall)
 2106 {
 2107    char const *myaddr;
 2108    long size;
 2109    struct message *rv;
 2110    FILE *bp, *hp, *op;
 2111    PKCS7 *pkcs7;
 2112    BIO *ob, *bb, *pb;
 2113    X509 *cert;
 2114    EVP_PKEY *pkey;
 2115    FILE *yp;
 2116    NYD_ENTER;
 2117 
 2118    pkey = NULL;
 2119    cert = NULL;
 2120    ob = bb = pb = NULL;
 2121    pkcs7 = NULL;
 2122    bp = hp = op = NULL;
 2123    rv = NULL;
 2124    size = m->m_size;
 2125 
 2126    if((yp = setinput(&mb, m, NEED_BODY)) == NULL)
 2127       goto jleave;
 2128 
 2129    a_xssl_init();
 2130 
 2131    if((op = smime_sign_cert(to, cc, 0, &myaddr)) != NULL){
 2132       pkey = PEM_read_PrivateKey(op, NULL, &ssl_password_cb,
 2133             savecat(myaddr, ".smime-cert-key"));
 2134       if(pkey == NULL){
 2135          ssl_gen_err(_("Error reading private key"));
 2136          goto jleave;
 2137       }
 2138 
 2139       rewind(op);
 2140       if((cert = PEM_read_X509(op, NULL, &ssl_password_cb,
 2141             savecat(myaddr, ".smime-cert-cert"))) == NULL){
 2142          ssl_gen_err(_("Error reading decryption certificate"));
 2143          goto jleave;
 2144       }
 2145 
 2146       Fclose(op);
 2147       op = NULL;
 2148    }
 2149 
 2150    if((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER)) == NULL){
 2151       n_perr(_("tempfile"), 0);
 2152       goto jleave;
 2153    }
 2154 
 2155    if(smime_split(yp, &hp, &bp, size, 1) == STOP)
 2156       goto jleave;
 2157 
 2158    if((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
 2159          (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL){
 2160       ssl_gen_err(_("Error creating BIO decryption objects"));
 2161       goto jleave;
 2162    }
 2163 
 2164    if((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL){
 2165       ssl_gen_err(_("Error reading PKCS#7 object"));
 2166       goto jleave;
 2167    }
 2168 
 2169    if(PKCS7_type_is_signed(pkcs7)){
 2170       if(signcall){
 2171          setinput(&mb, m, NEED_BODY);
 2172          rv = (struct message*)-1;
 2173          goto jleave;
 2174       }
 2175       if(PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
 2176             PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
 2177          goto jerr;
 2178       fseek(hp, 0L, SEEK_END);
 2179       fprintf(hp, "X-Encryption-Cipher: none\n");
 2180       fflush_rewind(hp);
 2181    }else if(pkey == NULL){
 2182       n_err(_("No appropriate private key found\n"));
 2183       goto jleave;
 2184    }else if(cert == NULL){
 2185       n_err(_("No appropriate certificate found\n"));
 2186       goto jleave;
 2187    }else if(PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1){
 2188 jerr:
 2189       ssl_gen_err(_("Error decrypting PKCS#7 object"));
 2190       goto jleave;
 2191    }
 2192    fflush_rewind(op);
 2193    Fclose(bp);
 2194    bp = NULL;
 2195 
 2196    rv = smime_decrypt_assemble(m, hp, op);
 2197    hp = op = NULL; /* xxx closed by decrypt_assemble */
 2198 jleave:
 2199    if(op != NULL)
 2200       Fclose(op);
 2201    if(hp != NULL)
 2202       Fclose(hp);
 2203    if(bp != NULL)
 2204       Fclose(bp);
 2205    if(bb != NULL)
 2206       BIO_free(bb);
 2207    if(ob != NULL)
 2208       BIO_free(ob);
 2209    if(pkcs7 != NULL)
 2210       PKCS7_free(pkcs7);
 2211    if(cert != NULL)
 2212       X509_free(cert);
 2213    if(pkey != NULL)
 2214       EVP_PKEY_free(pkey);
 2215    NYD_LEAVE;
 2216    return rv;
 2217 }
 2218 
 2219 FL enum okay
 2220 smime_certsave(struct message *m, int n, FILE *op)
 2221 {
 2222    struct message *x;
 2223    char *to, *cc, *cnttype;
 2224    int c, i;
 2225    FILE *fp, *ip;
 2226    off_t size;
 2227    BIO *fb, *pb;
 2228    PKCS7 *pkcs7;
 2229    n_XSSL_STACKOF(X509) *certs, *chain = NULL;
 2230    X509 *cert;
 2231    enum okay rv = STOP;
 2232    NYD_ENTER;
 2233 
 2234    pkcs7 = NULL;
 2235 
 2236    a_xssl_msgno = (size_t)n;
 2237 jloop:
 2238    to = hfield1("to", m);
 2239    cc = hfield1("cc", m);
 2240    cnttype = hfield1("content-type", m);
 2241 
 2242    if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
 2243       goto jleave;
 2244 
 2245 #undef _X
 2246 #undef _Y
 2247 #define _X     (sizeof("application/") -1)
 2248 #define _Y(X)  X, sizeof(X) -1
 2249    if (cnttype && is_asccaseprefix("application/", cnttype) &&
 2250          (!ascncasecmp(cnttype + _X, _Y("pkcs7-mime")) ||
 2251           !ascncasecmp(cnttype + _X, _Y("x-pkcs7-mime")))) {
 2252 #undef _Y
 2253 #undef _X
 2254       if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
 2255          goto jleave;
 2256       if (x != (struct message*)-1) {
 2257          m = x;
 2258          goto jloop;
 2259       }
 2260    }
 2261    size = m->m_size;
 2262 
 2263    if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER)) ==
 2264          NULL) {
 2265       n_perr(_("tempfile"), 0);
 2266       goto jleave;
 2267    }
 2268 
 2269    while (size-- > 0) {
 2270       c = getc(ip);
 2271       putc(c, fp);
 2272    }
 2273    fflush(fp);
 2274 
 2275    rewind(fp);
 2276    if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
 2277       ssl_gen_err("Error creating BIO object for message %d", n);
 2278       Fclose(fp);
 2279       goto jleave;
 2280    }
 2281 
 2282    if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
 2283       ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
 2284       BIO_free(fb);
 2285       Fclose(fp);
 2286       goto jleave;
 2287    }
 2288    BIO_free(fb);
 2289    Fclose(fp);
 2290 
 2291    certs = PKCS7_get0_signers(pkcs7, chain, 0);
 2292    if (certs == NULL) {
 2293       n_err(_("No certificates found in message %d\n"), n);
 2294       goto jleave;
 2295    }
 2296 
 2297    for (i = 0; i < sk_X509_num(certs); ++i) {
 2298       cert = sk_X509_value(certs, i);
 2299       if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
 2300          ssl_gen_err(_("Error writing certificate %d from message %d"),
 2301             i, n);
 2302          goto jleave;
 2303       }
 2304    }
 2305    rv = OKAY;
 2306 jleave:
 2307    if(pkcs7 != NULL)
 2308       PKCS7_free(pkcs7);
 2309    NYD_LEAVE;
 2310    return rv;
 2311 }
 2312 #endif /* HAVE_XSSL */
 2313 
 2314 /* s-it-mode */