]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.11-20130616
authorWietse Venema <wietse@porcupine.org>
Sun, 16 Jun 2013 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Mon, 17 Jun 2013 03:00:56 +0000 (23:00 -0400)
13 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/src/global/mail_version.h
postfix/src/posttls-finger/posttls-finger.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtp/smtp_tls_policy.c
postfix/src/tls/tls.h
postfix/src/tls/tls_client.c
postfix/src/tls/tls_dane.c
postfix/src/tls/tls_fprint.c
postfix/src/tls/tls_misc.c
postfix/src/tls/tls_server.c
postfix/src/tls/tls_verify.c

index bd70a8bcbdb78d6703cdc28b00e2fe76a9c80738..3d53b41ca4a4039830b7d9edb5f9f101ec41f9da 100644 (file)
@@ -8,8 +8,11 @@
 -TANVIL_REMOTE
 -TANVIL_REQ_TABLE
 -TARGV
+-TASN1_INTEGER
+-TASN1_OBJECT
 -TATTR_CLNT
 -TATTR_TABLE
+-TAUTHORITY_KEYID
 -TAUTO_CLNT
 -TBH_TABLE
 -TBINATTR
 -TDSN_BUF
 -TDSN_SPLIT
 -TDSN_STAT
+-TEC_KEY
+-TEC_GROUP
 -TEDIT_FILE
 -TEVENT_MASK
 -TEVP_PKEY
 -TWATCHDOG
 -TWATCH_FD
 -TX509
+-TX509_EXTENSION
 -TX509_NAME
 -TX509_STORE_CTX
+-TX509V3_CTX
 -TXSASL_CLIENT
 -TXSASL_CLIENT_CREATE_ARGS
 -TXSASL_CLIENT_IMPL
 -TXSASL_SERVER_IMPL
 -TXSASL_SERVER_IMPL_INFO
 -Tcipher_probe_t
+-Tgeneral_name_stack_t
 -Toff_t
 -Tregex_t
 -Tregmatch_t
 -Tsasl_secret_t
 -Tsfsistat
 -Tsize_t
+-Tssl_cipher_stack_t
+-Tssl_comp_stack_t
 -Tssize_t
 -Ttime_t
+-Tx509_extension_stack_t
+-Tx509_stack_t
index 658fbe6c6609df0b974e169afecd62c4f5905266..1db43c1066a6f066ea3eac21732d2f6f94ec902f 100644 (file)
@@ -18716,3 +18716,28 @@ Apologies for any names omitted.
        posttls-finger/posttls-finger.c, smtp/smtp_tls_policy.c,
        tls/tls_dane.c.
 
+20130615
+
+       Interoperability: turn on SHA-2XX digests by force. This
+       improves interoperability with clients and servers with
+       ancient OpenSSL versions and that that prematurely deploy
+       SHA-2 certificates. Viktor Dukhovni. File: tls/tls_misc.c
+
+20130616
+
+       Workaround: The Postfix SMTP server TLS session cache was
+       broken because OpenSSL now enables session tickets by
+       default, resulting in different ticket encryption key for
+       each smtpd(8) process.  the workaround turns off session
+       tickets. In 2.11 we'll enable session tickets properly.
+       Viktor Dukhovni. File: tls/tls_server.c.
+
+       Updated DANE support (trust in DNS instead of PKI).  With
+       OpenSSL 1.0.2 (under development) trusted certificates don't
+       need to be self-signed roots.  Otherwise we use an ephemeral
+       root certificate to sign the trust anchor. Viktor Dukhovni.
+       Files: posttls-finger/posttls-finger.c, smtp/smtp_proto.c,
+       smtp/smtp_tls_policy.c, tls/tls.h, tls/tls_client.c,
+       tls/tls_dane.c, tls/tls_fprint.c, tls/tls_misc.c,
+       tls/tls_verify.c.
+
index 7132bde4196ee77c6c1830d9d592b770a05f6d26..fb0c0f83f25879d0bb621d63aa54de4a058c84ac 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20130613"
+#define MAIL_RELEASE_DATE      "20130616"
 #define MAIL_VERSION_NUMBER    "2.11"
 
 #ifdef SNAPSHOT
index 03dc1ead6675f8cffcb8107d8704007d7cf0d3a1..66edbe9f6a05baccee29cdb533c4c4fe59acbb85 100644 (file)
@@ -575,47 +575,66 @@ static RESPONSE *ehlo(STATE *state)
 
 #ifdef USE_TLS
 
-static void print_trust_info(STATE *state)
+static void print_stack(STATE *state, x509_stack_t *sk, int trustout)
 {
-    STACK_OF(X509) *sk = SSL_get_peer_cert_chain(state->tls_context->con);
-
-    if (sk != NULL) {
-       int     i;
+    int     i;
 
-       BIO_printf(state->tls_bio, "---\nCertificate chain\n");
-       for (i = 0; i < sk_X509_num(sk); i++) {
-           X509   *cert = sk_X509_value(sk, i);
-           char    buf[CCERT_BUFSIZ];
-           X509_NAME *xn;
-           char   *digest;
+    for (i = 0; i < sk_X509_num(sk); i++) {
+       X509   *cert = sk_X509_value(sk, i);
+       char    buf[CCERT_BUFSIZ];
+       X509_NAME *xn;
+       char   *digest;
 
-           if ((xn = X509_get_subject_name(cert)) != 0) {
-               X509_NAME_oneline(xn, buf, sizeof buf);
-               BIO_printf(state->tls_bio, "%2d subject: %s\n", i, buf);
-           }
-           if ((xn = X509_get_issuer_name(cert)) != 0) {
-               X509_NAME_oneline(xn, buf, sizeof buf);
-               BIO_printf(state->tls_bio, "    issuer: %s\n", buf);
-           }
-           digest = tls_cert_fprint(cert, state->mdalg);
-           BIO_printf(state->tls_bio, "   cert digest=%s\n", digest);
-           myfree(digest);
+       if ((xn = X509_get_subject_name(cert)) != 0) {
+           X509_NAME_oneline(xn, buf, sizeof buf);
+           BIO_printf(state->tls_bio, "%2d subject: %s\n", i, buf);
+       }
+       if ((xn = X509_get_issuer_name(cert)) != 0) {
+           X509_NAME_oneline(xn, buf, sizeof buf);
+           BIO_printf(state->tls_bio, "    issuer: %s\n", buf);
+       }
+       digest = tls_cert_fprint(cert, state->mdalg);
+       BIO_printf(state->tls_bio, "   cert digest=%s\n", digest);
+       myfree(digest);
 
-           digest = tls_pkey_fprint(cert, state->mdalg);
-           BIO_printf(state->tls_bio, "   pkey digest=%s\n", digest);
-           myfree(digest);
+       digest = tls_pkey_fprint(cert, state->mdalg);
+       BIO_printf(state->tls_bio, "   pkey digest=%s\n", digest);
+       myfree(digest);
 
+       if (trustout)
+           PEM_write_bio_X509_AUX(state->tls_bio, cert);
+       else
            PEM_write_bio_X509(state->tls_bio, cert);
-       }
     }
 }
 
+static void print_trust_info(STATE *state)
+{
+    x509_stack_t *sk = SSL_get_peer_cert_chain(state->tls_context->con);
+
+    if (sk != 0) {
+       BIO_printf(state->tls_bio, "\n---\nCertificate chain\n");
+       print_stack(state, sk, 0);
+    }
+#ifdef dane_verify_debug
+    /* print internally constructed untrusted chain */
+    if ((sk = state->tls_context->untrusted) != 0) {
+       BIO_printf(state->tls_bio, "\n---\nUntrusted chain\n");
+       print_stack(state, sk, 0);
+    }
+    /* print associated root CA */
+    if ((sk = state->tls_context->trusted) != 0) {
+       BIO_printf(state->tls_bio, "\n---\nTrusted chain\n");
+       print_stack(state, sk, 1);
+    }
+#endif
+}
+
 /* starttls - SMTP STARTTLS handshake */
 
 static int starttls(STATE *state)
 {
     VSTRING *cipher_exclusions;
-    VSTRING *serverid;
     int     except;
     RESPONSE *resp;
     VSTREAM *stream = state->stream;
@@ -662,9 +681,6 @@ static int starttls(STATE *state)
     else
        ADD_EXCLUDE(cipher_exclusions, "eNULL");
 
-    serverid = vstring_alloc(10);
-    vstring_sprintf(serverid, "%s:%s", var_procname, state->addrport);
-
     state->tls_context =
        TLS_CLIENT_START(&tls_props,
                         ctx = state->tls_ctx,
@@ -674,7 +690,7 @@ static int starttls(STATE *state)
                         nexthop = state->nexthop,
                         host = state->hostname,
                         namaddr = state->namaddrport,
-                        serverid = STR(serverid),
+                        serverid = state->addrport,
                         helo = state->helo ? state->helo : "",
                         protocols = state->protocols,
                         cipher_grade = state->grade,
@@ -684,7 +700,6 @@ static int starttls(STATE *state)
                         mdalg = state->mdalg,
                         dane = state->ddane ? state->ddane : state->dane);
     vstring_free(cipher_exclusions);
-    vstring_free(serverid);
     if (state->helo) {
        myfree(state->helo);
        state->helo = 0;
@@ -1466,10 +1481,12 @@ static void cleanup(STATE *state)
 static void usage(void)
 {
 #ifdef USE_TLS
-    fprintf(stderr, "usage: %s %s \\\n\t%s \\\n\t%s destination [match ...]\n",
-           var_procname, "[-acCStTv] [-d mdalg] [-g grade] [-p protocols] [-F CAfile.pem]",
-           "[-h host_lookup] [-l level] [-L logopts] [-m count]",
-           "[-o name=value] [-P CApath/] [-r delay]");
+    fprintf(stderr, "usage: %s %s \\\n\t%s \\\n\t%s \\\n\t%s"
+           " destination [match ...]\n", var_procname,
+           "[-acCSv] [-t conn_tmout] [-T cmd_tmout] [-L logopts]",
+        "[-h host_lookup] [-l level] [-d mdalg] [-g grade] [-p protocols]",
+           "[-A tafile] [-F CAfile.pem] [-P CApath/] [-m count] [-r delay]",
+           "[-o name=value]");
 #else
     fprintf(stderr, "usage: %s [-acStTv] [-h host_lookup] [-o name=value] destination\n",
            var_procname);
@@ -1713,7 +1730,6 @@ static void parse_match(STATE *state, int argc, char *argv[])
        while (*argv)
            tls_dane_split((TLS_DANE *) state->dane, TLS_DANE_EE, TLS_DANE_PKEY,
                           state->mdalg, *argv++, "");
-       tls_dane_final((TLS_DANE *) state->dane);
        break;
     case TLS_LEV_DANE:
        state->match = argv_alloc(2);
@@ -1745,7 +1761,6 @@ static void parse_tas(STATE *state)
        }
        if (*file)
            msg_fatal("Failed to load trust anchor file: %s", *file);
-       tls_dane_final((TLS_DANE *) state->dane);
        break;
     }
 #endif
index 7a69a5d9393b9657d86483431051f51e80979db0..5d442df4116cdcccb41099f42c35a55a3741a426 100644 (file)
@@ -780,9 +780,10 @@ static int smtp_start_tls(SMTP_STATE *state)
      * SSL session lookup key lengths.
      */
     serverid = vstring_alloc(10);
-    smtp_key_prefix(serverid, ":", state->iterator, SMTP_KEY_FLAG_SERVICE
-                   | SMTP_KEY_FLAG_ADDR
-                   | SMTP_KEY_FLAG_PORT);
+    smtp_key_prefix(serverid, "&", state->iterator, SMTP_KEY_FLAG_SERVICE
+                   | SMTP_KEY_FLAG_NEXTHOP     /* With port */
+                   | SMTP_KEY_FLAG_HOSTNAME
+                   | SMTP_KEY_FLAG_ADDR);
 
     /*
      * As of Postfix 2.5, tls_client_start() tries hard to always complete
index bad77d2af059cc58dff422a9013f1fa3f40c2842..c41cc99179b6528206b5b4a4a844b57d51e8a98a 100644 (file)
@@ -572,7 +572,6 @@ static void *policy_create(const char *unused_key, void *context)
                return ((void *) tls);
            }
        }
-       tls_dane_final(tls->dane);
        break;
     case TLS_LEV_VERIFY:
     case TLS_LEV_SECURE:
@@ -584,13 +583,10 @@ static void *policy_create(const char *unused_key, void *context)
        if (*var_smtp_tls_tafile) {
            if (tls->dane == 0)
                tls->dane = tls_dane_alloc(TLS_DANE_FLAG_MIXED);
-           if (!TLS_DANE_HASTA(tls->dane)) {
-               if (load_tas(tls->dane, var_smtp_tls_tafile))
-                   tls_dane_final(tls->dane);
-               else {
-                   MARK_INVALID(tls->why, &tls->level);
-                   return ((void *) tls);
-               }
+           if (!TLS_DANE_HASTA(tls->dane)
+               && !load_tas(tls->dane, var_smtp_tls_tafile)) {
+               MARK_INVALID(tls->why, &tls->level);
+               return ((void *) tls);
            }
        }
        break;
index 5519dcc5459fc26d358e3f6d1e425d6feaf26986..47f60e996c5c38b6dcf33866776aef8904edb1cc 100644 (file)
@@ -73,6 +73,13 @@ extern const NAME_CODE tls_level_table[];
 #include <openssl/rand.h>
 #include <openssl/ssl.h>
 
+ /* Appease indent(1) */
+#define x509_stack_t STACK_OF(X509)
+#define x509_extension_stack_t STACK_OF(X509_EXTENSION)
+#define general_name_stack_t STACK_OF(GENERAL_NAME)
+#define ssl_cipher_stack_t STACK_OF(SSL_CIPHER)
+#define ssl_comp_stack_t STACK_OF(SSL_COMP)
+
 #if (OPENSSL_VERSION_NUMBER < 0x00090700f)
 #error "need OpenSSL version 0.9.7 or later"
 #endif
@@ -101,10 +108,9 @@ extern const NAME_CODE tls_level_table[];
 #define TLS_DANE_PKEY  1               /* Match the public key digest */
 
 #define TLS_DANE_FLAG_MIXED    (1<<0)  /* Combined pkeys and certs */
-#define TLS_DANE_FLAG_FINAL    (1<<1)  /* No further changes */
-#define TLS_DANE_FLAG_NORRS    (1<<2)  /* Nothing found in DNS */
-#define TLS_DANE_FLAG_EMPTY    (1<<3)  /* Nothing usable found in DNS */
-#define TLS_DANE_FLAG_ERROR    (1<<4)  /* TLSA record lookup error */
+#define TLS_DANE_FLAG_NORRS    (1<<1)  /* Nothing found in DNS */
+#define TLS_DANE_FLAG_EMPTY    (1<<2)  /* Nothing usable found in DNS */
+#define TLS_DANE_FLAG_ERROR    (1<<3)  /* TLSA record lookup error */
 
 #define tls_dane_unusable(dane)        ((dane)->flags & TLS_DANE_FLAG_EMPTY)
 #define tls_dane_notfound(dane)        ((dane)->flags & TLS_DANE_FLAG_NORRS)
@@ -165,7 +171,6 @@ extern void tls_dane_verbose(int);
 extern TLS_DANE *tls_dane_alloc(int);
 extern void tls_dane_split(TLS_DANE *, int, int, const char *, const char *,
                                   const char *);
-extern TLS_DANE *tls_dane_final(TLS_DANE *);
 extern void tls_dane_free(TLS_DANE *);
 extern TLS_DANE *tls_dane_resolve(const char *, const char *, unsigned);
 extern int tls_dane_load_trustfile(TLS_DANE *, const char *);
@@ -202,11 +207,12 @@ typedef struct {
     VSTREAM *stream;                   /* Blocking-mode SMTP session */
     /* RFC 6698 DANE trust input and verification state */
     const TLS_DANE *dane;              /* DANE TLSA digests */
-    int     trustdepth;                        /* Chain depth of trusted cert */
     int     errordepth;                        /* Chain depth of error cert */
-    int     chaindepth;                        /* Chain depth of top cert */
+    int     tadepth;                   /* Chain depth of trust anchor */
     int     errorcode;                 /* First error at error depth */
     X509   *errorcert;                 /* Error certificate closest to leaf */
+    x509_stack_t *untrusted;           /* Certificate chain fodder */
+    x509_stack_t *trusted;             /* Internal root CA list */
 } TLS_SESS_STATE;
 
  /*
@@ -520,10 +526,15 @@ extern RSA *tls_tmp_rsa_cb(SSL *, int, int);
 extern char *tls_peer_CN(X509 *, const TLS_SESS_STATE *);
 extern char *tls_issuer_CN(X509 *, const TLS_SESS_STATE *);
 extern const char *tls_dns_name(const GENERAL_NAME *, const TLS_SESS_STATE *);
-extern int tls_cert_match(TLS_SESS_STATE *, int, X509 *, int);
 extern int tls_verify_certificate_callback(int, X509_STORE_CTX *);
 extern void tls_log_verify_error(TLS_SESS_STATE *);
 
+ /*
+  * tls_dane.c
+  */
+extern int tls_dane_match(TLS_SESS_STATE *, int, X509 *, int);
+extern void tls_dane_set_callback(SSL_CTX *, TLS_SESS_STATE *);
+
  /*
   * tls_fprint.c
   */
index 43d0fb2ed46dd7e03ba66c2eca0536a0f81beebd..321ed6575585a223bb4cfdbd3b881336b7644e7e 100644 (file)
@@ -491,7 +491,7 @@ TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props)
 /* match_servername -  match servername against pattern */
 
 static int match_servername(const char *certid,
-                                 const TLS_CLIENT_START_PROPS *props)
+                                   const TLS_CLIENT_START_PROPS *props)
 {
     const ARGV *cmatch_argv;
     const char *nexthop = props->nexthop;
@@ -570,8 +570,7 @@ static void verify_extract_name(TLS_SESS_STATE *TLScontext, X509 *peercert,
     int     verbose;
     const char *dnsname;
     const GENERAL_NAME *gn;
-
-    STACK_OF(GENERAL_NAME) * gens;
+    general_name_stack_t *gens;
 
     /*
      * On exit both peer_CN and issuer_CN should be set.
@@ -728,7 +727,7 @@ static void verify_extract_print(TLS_SESS_STATE *TLScontext, X509 *peercert,
      * untrusted in verify_extract_name().
      */
     if (TLS_DANE_HASEE(props->dane)
-       && tls_cert_match(TLScontext, TLS_DANE_EE, peercert, 0))
+       && tls_dane_match(TLScontext, TLS_DANE_EE, peercert, 0))
        TLScontext->peer_status |=
            TLS_CERT_FLAG_TRUSTED | TLS_CERT_FLAG_MATCHED;
 }
@@ -945,6 +944,8 @@ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props)
     if (log_mask & TLS_LOG_TLSPKTS)
        BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb);
 
+    tls_dane_set_callback(app_ctx->ssl_ctx, TLScontext);
+
     /*
      * Start TLS negotiations. This process is a black box that invokes our
      * call-backs for certificate verification.
index b9c327ff521e3ae8f4dee4926f0c223eb265a4aa..cc068af4a8fe216dc5ffa0cb2aeb7eb421baf6d3 100644 (file)
 /*     TLS_DANE *dane;
 /*     const char *tafile;
 /*
-/*     TLS_DANE *tls_dane_final(dane)
-/*     TLS_DANE *dane;
+/*     int     tls_dane_match(TLSContext, usage, cert, depth)
+/*     TLS_SESS_STATE *TLScontext;
+/*     int     usage;
+/*     X509    *cert;
+/*     int     depth;
+/*
+/*     void    tls_dane_set_callback(ssl_ctx, TLScontext)
+/*     SSL_CTX *ssl_ctx;
+/*     TLS_SESS_STATE *TLScontext;
 /*
 /*     TLS_DANE *tls_dane_resolve(host, proto, port)
 /*     const char *host;
 /*     delimiters and stores the results with the requested "certusage"
 /*     and "selector".  This is an incremental interface, that builds a
 /*     TLS_DANE structure outside the cache by manually adding entries.
-/*     Once all the entries have been added, the caller must call
-/*     tls_dane_final() to complete its construction.
 /*
 /*     tls_dane_load_trustfile() imports trust-anchor certificates and
 /*     public keys from a file (rather than DNS TLSA records).
 /*
-/*     tls_dane_final() completes the construction of a TLS_DANE structure,
-/*     obtained via tls_dane_alloc() and populated via tls_dane_split() or
-/*     tls_dane_load_trustfile().  After tls_dane_final() is called, the
-/*     structure must not be modified.  The return value is the input
-/*     argument.
+/*     tls_dane_match() matches the full and/or public key digest of
+/*     "cert" against each candidate digest in TLScontext->dane. If usage
+/*     is TLS_DANE_EE, the match is against end-entity digests, otherwise
+/*     it is against trust-anchor digests.  Returns true if a match is found,
+/*     false otherwise.
+/*
+/*     tls_dane_set_callback() wraps the SSL certificate verification logic
+/*     in a function that modifies the input trust chain and trusted
+/*     certificate store to map DANE TA validation onto the existing PKI
+/*     verification model.  When TLScontext is NULL the callback is
+/*     cleared, otherwise it is set.  This callback should only be set
+/*     when out-of-band trust-anchors (via DNSSEC DANE TLSA records or
+/*     per-destination local configuration) are provided.  Such trust
+/*     anchors always override the legacy public CA PKI.  Otherwise, the
+/*     callback MUST be cleared.
 /*
 /*     tls_dane_resolve() maps a (host, protocol, port) triple to a
 /*     a corresponding TLS_DANE policy structure found in the DNS.  The port
 /*     The TCP port in network byte order.
 /* .IP flags
 /*     Only one flag is part of the public interface at this time:
+/* .IP TLScontext
+/*     Client context with TA/EE matching data and related state.
+/* .IP usage
+/*     Trust anchor (TLS_DANE_TA) or end-entity (TLS_DANE_EE) digests?
+/* .IP cert
+/*     Certificate from peer trust chain (CA or leaf server).
+/* .IP depth
+/*     The certificate depth for logging.
+/* .IP ssl_ctx
+/*     The global SSL_CTX structure used to initialize child SSL
+/*     conenctions.
 /* .RS
 /* .IP TLS_DANE_FLAG_MIXED
 /*     Don't distinguish between certificate and public-key digests.
 #include <events.h>                    /* event_time() */
 #include <timecmp.h>
 #include <ctable.h>
+#include <hex_code.h>
 
 #define STR(x) vstring_str(x)
 
 
 /* Application-specific. */
 
+#undef TRUST_ANCHOR_SUPPORT
+#undef DANE_TLSA_SUPPORT
+#undef WRAP_SIGNED
+
+#if OPENSSL_VERSION_NUMBER >= 0x1000000fL && \
+       (defined(X509_V_FLAG_PARTIAL_CHAIN) || !defined(OPENSSL_NO_ECDH))
+#define TRUST_ANCHOR_SUPPORT
+
+#ifndef X509_V_FLAG_PARTIAL_CHAIN
+#define WRAP_SIGNED
+#endif
+
+#if defined(TLSEXT_MAXLEN_host_name) && RES_USE_DNSSEC && RES_USE_EDNS0
+#define DANE_TLSA_SUPPORT
+#endif
+
+#endif                                 /* OPENSSL_VERSION_NUMBER ... */
+
+#ifdef WRAP_SIGNED
+static int wrap_signed = 1;
+
+#else
+static int wrap_signed = 0;
+
+#endif
+static const EVP_MD *signmd;
+
+static EVP_PKEY *danekey;
+static ASN1_OBJECT *serverAuth;
+
 static const char *sha256 = "sha256";
-static const char *sha512 = "sha512";
+static const EVP_MD *sha256md;
 static int sha256len;
+
+static const char *sha512 = "sha512";
+static const EVP_MD *sha512md;
 static int sha512len;
-static int dane_verbose;
+
 static int digest_mask;
-static TLS_TLSA **dane_locate(TLS_TLSA **, const char *);
 
 #define TLS_DANE_ENABLE_CC     (1<<0)  /* ca-constraint digests OK */
 #define TLS_DANE_ENABLE_TAA    (1<<1)  /* trust-anchor-assertion digests OK */
@@ -199,6 +258,9 @@ static TLS_TLSA **dane_locate(TLS_TLSA **, const char *);
 #define CACHE_SIZE 20
 static CTABLE *dane_cache;
 
+static int dane_initialized;
+static int dane_verbose;
+
 /* tls_dane_verbose - enable/disable verbose logging */
 
 void    tls_dane_verbose(int on)
@@ -206,40 +268,82 @@ void    tls_dane_verbose(int on)
     dane_verbose = on;
 }
 
-/* tls_dane_avail - check for availability of dane required digests */
+/* gencakey - generate interal DANE root CA key */
 
-int     tls_dane_avail(void)
+static EVP_PKEY *gencakey(void)
+{
+    EVP_PKEY *key = 0;
+
+#ifdef WRAP_SIGNED
+    int     len;
+    unsigned char *p;
+    EC_KEY *eckey;
+    EC_GROUP *group;
+
+    ERR_clear_error();
+
+    if ((eckey = EC_KEY_new()) != 0
+       && (group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) != 0
+       && (EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE),
+           EC_KEY_set_group(eckey, group))
+       && EC_KEY_generate_key(eckey)
+       && (key = EVP_PKEY_new()) != 0
+       && !EVP_PKEY_set1_EC_KEY(key, eckey)) {
+       EVP_PKEY_free(key);
+       key = 0;
+    }
+    if (group)
+       EC_GROUP_free(group);
+    if (eckey)
+       EC_KEY_free(eckey);
+#endif
+    return (key);
+}
+
+/* dane_init - initialize DANE parameters */
+
+static void dane_init(void)
 {
-#ifdef TLSEXT_MAXLEN_host_name         /* DANE mandates client SNI. */
-    static int avail = -1;
-    const EVP_MD *sha256md;
-    const EVP_MD *sha512md;
     static NAME_MASK ta_dgsts[] = {
        TLS_DANE_CC, TLS_DANE_ENABLE_CC,
        TLS_DANE_TAA, TLS_DANE_ENABLE_TAA,
        0,
     };
 
-    if (avail >= 0)
-       return (avail);
-
-    sha256md = EVP_get_digestbyname(sha256);
-    sha512md = EVP_get_digestbyname(sha512);
-
-    if (sha256md == 0 || sha512md == 0
-       || RES_USE_DNSSEC == 0 || RES_USE_EDNS0 == 0)
-       return (avail = 0);
-
     digest_mask =
        name_mask_opt(VAR_TLS_DANE_TA_DGST, ta_dgsts, var_tls_dane_ta_dgst,
                      NAME_MASK_ANY_CASE | NAME_MASK_FATAL);
 
-    sha256len = EVP_MD_size(sha256md);
-    sha512len = EVP_MD_size(sha512md);
+    if ((sha256md = EVP_get_digestbyname(sha256)) != 0)
+       sha256len = EVP_MD_size(sha256md);
+    if ((sha512md = EVP_get_digestbyname(sha512)) != 0)
+       sha512len = EVP_MD_size(sha512md);
+    signmd = sha256md ? sha256md : EVP_sha1();
+
+    /* Don't report old news */
+    ERR_clear_error();
+
+#ifdef TRUST_ANCHOR_SUPPORT
+    if ((wrap_signed && (danekey = gencakey()) == 0)
+       || (serverAuth = OBJ_nid2obj(NID_server_auth)) == 0) {
+       msg_warn("cannot generate TA certificates, no DANE support");
+       tls_print_errors();
+    }
+#endif
+    dane_initialized = 1;
+}
+
+/* tls_dane_avail - check for availability of dane required digests */
+
+int     tls_dane_avail(void)
+{
+    if (!dane_initialized)
+       dane_init();
 
-    return (avail = 1);
+#ifdef DANE_TLSA_SUPPORT
+    return (sha256md && sha512md && serverAuth);
 #else
-            return (0);
+    return (0);
 #endif
 }
 
@@ -357,32 +461,6 @@ static void dane_free(void *dane, void *unused_context)
     tls_dane_free((TLS_DANE *) dane);
 }
 
-/* tlsa_sort - sort digests for a single certusage */
-
-static void tlsa_sort(TLS_TLSA *tlsa)
-{
-    for (; tlsa; tlsa = tlsa->next) {
-       if (tlsa->pkeys)
-           argv_sort(tlsa->pkeys);
-       if (tlsa->certs)
-           argv_sort(tlsa->certs);
-    }
-}
-
-/* tls_dane_final - finish by sorting into canonical order */
-
-TLS_DANE *tls_dane_final(TLS_DANE *dane)
-{
-
-    /*
-     * We only sort the trust anchors, see tls_serverid_digest().
-     */
-    if (dane->ta)
-       tlsa_sort(dane->ta);
-    dane->flags |= TLS_DANE_FLAG_FINAL;
-    return (dane);
-}
-
 /* dane_locate - list head address of TLSA sublist for given algorithm */
 
 static TLS_TLSA **dane_locate(TLS_TLSA **tlsap, const char *mdalg)
@@ -422,9 +500,6 @@ void    tls_dane_split(TLS_DANE *dane, int certusage, int selector,
     TLS_TLSA *tlsa;
     ARGV  **argvp;
 
-    if (dane->flags & TLS_DANE_FLAG_FINAL)
-       msg_panic("updating frozen TLS_DANE object");
-
     tlsap = (certusage == TLS_DANE_EE) ? &dane->ee : &dane->ta;
     tlsa = *(tlsap = dane_locate(tlsap, mdalg));
     argvp = ((dane->flags & TLS_DANE_FLAG_MIXED) || selector == TLS_DANE_PKEY) ?
@@ -457,9 +532,6 @@ static void dane_add(TLS_DANE *dane, int certusage, int selector,
     TLS_TLSA *tlsa;
     ARGV  **argvp;
 
-    if (dane->flags & TLS_DANE_FLAG_FINAL)
-       msg_panic("updating frozen TLS_DANE object");
-
     switch (certusage) {
     case DNS_TLSA_USAGE_CA_CONSTRAINT:
     case DNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
@@ -490,6 +562,17 @@ static void dane_add(TLS_DANE *dane, int certusage, int selector,
     argv_add(*argvp, digest, ARGV_END);
 }
 
+#ifdef DANE_TLSA_SUPPORT
+
+/* tlsa_rr_cmp - qsort TLSA rrs in case shuffled by name server */
+
+static int tlsa_rr_cmp(DNS_RR *a, DNS_RR *b)
+{
+    if (a->data_len == b->data_len)
+       return (memcmp(a->data, b->data, a->data_len));
+    return ((a->data_len > b->data_len) ? 1 : -1);
+}
+
 /* parse_tlsa_rrs - parse a validated TLSA RRset */
 
 static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
@@ -610,7 +693,6 @@ static void parse_tlsa_rrs(TLS_DANE *dane, DNS_RR *rr)
                             usage, selector, mtype);
                    continue;
                }
-
                /* Also unusable if public key is malformed */
                if ((k = X509_get_pubkey(x)) == 0) {
                    msg_warn("%s public key malformed in RR: "
@@ -714,9 +796,11 @@ static void *dane_lookup(const char *tlsa_fqdn, void *unused_ctx)
        /* One more second to account for discrete time */
        dane->expires = 1 + event_time() + rrs->ttl;
 
-       if (rrs->dnssec_valid)
+       if (rrs->dnssec_valid) {
+           /* Sort for deterministic digest in session cache lookup key */
+           rrs = dns_rr_sort(rrs, tlsa_rr_cmp);
            parse_tlsa_rrs(dane, rrs);
-       else
+       else
            dane->flags |= TLS_DANE_FLAG_NORRS;
 
        dns_rr_free(rrs);
@@ -733,19 +817,22 @@ static void *dane_lookup(const char *tlsa_fqdn, void *unused_ctx)
        break;
     }
 
-    return ((void *) tls_dane_final(dane));
+    return (void *) dane;
 }
 
+#endif
+
 /* tls_dane_resolve - cached map: (host, proto, port) -> TLS_DANE */
 
 TLS_DANE *tls_dane_resolve(const char *host, const char *proto,
                                   unsigned port)
 {
     static VSTRING *qname;
-    TLS_DANE *dane;
+    TLS_DANE *dane = 0;
 
+#ifdef DANE_TLSA_SUPPORT
     if (!tls_dane_avail())
-       return (0);
+       return (dane);
 
     if (!dane_cache)
        dane_cache = ctable_create(CACHE_SIZE, dane_lookup, dane_free, 0);
@@ -761,6 +848,7 @@ TLS_DANE *tls_dane_resolve(const char *host, const char *proto,
        return (0);
 
     ++dane->refs;
+#endif
     return (dane);
 }
 
@@ -768,6 +856,7 @@ TLS_DANE *tls_dane_resolve(const char *host, const char *proto,
 
 int     tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
 {
+#ifdef TRUST_ANCHOR_SUPPORT
     BIO    *bp;
     char   *name = 0;
     char   *header = 0;
@@ -775,11 +864,21 @@ int     tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
     long    len;
     int     tacount;
     char   *errtype = 0;               /* if error: cert or pkey? */
+    const char *mdalg;
 
     /* nop */
     if (tafile == 0 || *tafile == 0)
        return (1);
 
+    if (!dane_initialized)
+       dane_init();
+
+    if (serverAuth == 0) {
+       msg_warn("trust-anchor files not supported");
+       return (0);
+    }
+    mdalg = sha256md ? sha256 : "sha1";
+
     /*
      * On each call, PEM_read() wraps a stdio file in a BIO_NOCLOSE bio,
      * calls PEM_read_bio() and then frees the bio.  It is just as easy to
@@ -807,8 +906,8 @@ int     tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
 
            if (cert && (p - data) == len) {
                selector = DNS_TLSA_SELECTOR_FULL_CERTIFICATE;
-               digest = tls_data_fprint((char *) data, len, sha256);
-               dane_add(dane, usage, selector, sha256, digest);
+               digest = tls_data_fprint((char *) data, len, mdalg);
+               dane_add(dane, usage, selector, mdalg, digest);
                myfree(digest);
                ta_cert_insert(dane, cert);
            } else
@@ -820,8 +919,8 @@ int     tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
 
            if (pkey && (p - data) == len) {
                selector = DNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO;
-               digest = tls_data_fprint((char *) data, len, sha256);
-               dane_add(dane, usage, selector, sha256, digest);
+               digest = tls_data_fprint((char *) data, len, mdalg);
+               dane_add(dane, usage, selector, mdalg, digest);
                myfree(digest);
                ta_pkey_insert(dane, pkey);
            } else
@@ -852,7 +951,444 @@ int     tls_dane_load_trustfile(TLS_DANE *dane, const char *tafile)
     }
     /* Some other PEM read error */
     tls_print_errors();
+#else
+    msg_warn("Trust anchor files not supported");
+#endif
     return (0);
 }
 
-#endif
+/* tls_dane_match - match cert against given list of TA or EE digests */
+
+int     tls_dane_match(TLS_SESS_STATE *TLScontext, int usage,
+                              X509 *cert, int depth)
+{
+    const TLS_DANE *dane = TLScontext->dane;
+    TLS_TLSA *tlsa = (usage == TLS_DANE_EE) ? dane->ee : dane->ta;
+    const char *namaddr = TLScontext->namaddr;
+    const char *ustr = (usage == TLS_DANE_EE) ? "end entity" : "trust anchor";
+    int     mixed = (dane->flags & TLS_DANE_FLAG_MIXED);
+    int     matched;
+
+    for (matched = 0; tlsa && !matched; tlsa = tlsa->next) {
+       char  **dgst;
+       ARGV   *certs;
+
+       if (tlsa->pkeys) {
+           char   *pkey_dgst = tls_pkey_fprint(cert, tlsa->mdalg);
+
+           for (dgst = tlsa->pkeys->argv; !matched && *dgst; ++dgst)
+               if (strcasecmp(pkey_dgst, *dgst) == 0)
+                   matched = 1;
+           if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH)
+               && matched)
+               msg_info("%s: depth=%d matched %s public-key %s digest=%s",
+                        namaddr, depth, ustr, tlsa->mdalg, pkey_dgst);
+           myfree(pkey_dgst);
+       }
+
+       /*
+        * Backwards compatible "fingerprint" security level interface:
+        * 
+        * Certificate digests and public key digests are interchangeable, each
+        * leaf certificate is matched via either the public key digest or
+        * full certificate digest when "mixed" is true.  The combined set of
+        * digests is stored on the pkeys digest list and the certs list is
+        * empty.  An attacker would need a 2nd-preimage (not just a
+        * collision) that is feasible across types (given cert digest ==
+        * some key digest) while difficult within a type (e.g. given cert
+        * some other cert digest).  No such attacks are know at this time,
+        * and it is expected that if any are found they would work within as
+        * well as across the cert/key data types.
+        */
+       certs = mixed ? tlsa->pkeys : tlsa->certs;
+       if (certs != 0 && !matched) {
+           char   *cert_dgst = tls_cert_fprint(cert, tlsa->mdalg);
+
+           for (dgst = certs->argv; !matched && *dgst; ++dgst)
+               if (strcasecmp(cert_dgst, *dgst) == 0)
+                   matched = 1;
+           if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH)
+               && matched)
+               msg_info("%s: depth=%d matched %s certificate %s digest %s",
+                        namaddr, depth, ustr, tlsa->mdalg, cert_dgst);
+           myfree(cert_dgst);
+       }
+    }
+
+    return (matched);
+}
+
+/* add_ext - add simple extension (no config section references) */
+
+static int add_ext(X509 *issuer, X509 *subject, int ext_nid, char *ext_val)
+{
+    X509V3_CTX v3ctx;
+    X509_EXTENSION *ext;
+    x509_extension_stack_t *exts;
+
+    X509V3_set_ctx(&v3ctx, issuer, subject, 0, 0, 0);
+    if ((exts = subject->cert_info->extensions) == 0)
+       exts = subject->cert_info->extensions = sk_X509_EXTENSION_new_null();
+
+    if ((ext = X509V3_EXT_conf_nid(0, &v3ctx, ext_nid, ext_val)) != 0
+       && sk_X509_EXTENSION_push(exts, ext))
+       return (1);
+    if (ext)
+       X509_EXTENSION_free(ext);
+    return (0);
+}
+
+/* set_serial - set serial number to match akid or use subject's plus 1 */
+
+static int set_serial(X509 *cert, AUTHORITY_KEYID *akid, X509 *subject)
+{
+    int     ret = 0;
+    BIGNUM *bn;
+
+    if (akid && akid->serial)
+       return (X509_set_serialNumber(cert, akid->serial));
+
+    /*
+     * Add one to subject's serial to avoid collisions between TA serial and
+     * serial of signing root.
+     */
+    if ((bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(subject), 0)) != 0
+       && BN_add_word(bn, 1)
+       && BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(cert)))
+       ret = 1;
+
+    if (bn)
+       BN_free(bn);
+    return (ret);
+}
+
+/* add_akid - add authority key identifier */
+
+static int add_akid(X509 *cert, AUTHORITY_KEYID *akid)
+{
+    ASN1_STRING *id;
+    unsigned char c = 0;
+    int     ret = 0;
+
+    /*
+     * 0 will never be our subject keyid from a SHA-1 hash, but it could be
+     * our subject keyid if forced from child's akid.  If so, set our
+     * authority keyid to 1.  This way we are never self-signed, and thus
+     * exempt from any potential (off by default for now in OpenSSL)
+     * self-signature checks!
+     */
+    id = (ASN1_STRING *) ((akid && akid->keyid) ? akid->keyid : 0);
+    if (id && M_ASN1_STRING_length(id) == 1 && *M_ASN1_STRING_data(id) == c)
+       c = 1;
+
+    if ((akid = AUTHORITY_KEYID_new()) != 0
+       && (akid->keyid = ASN1_OCTET_STRING_new()) != 0
+       && M_ASN1_OCTET_STRING_set(akid->keyid, (void *) &c, 1)
+       && X509_add1_ext_i2d(cert, NID_authority_key_identifier, akid, 0, 0))
+       ret = 1;
+    if (akid)
+       AUTHORITY_KEYID_free(akid);
+    return (ret);
+}
+
+/* add_skid - add subject key identifier to match child's akid */
+
+static int add_skid(X509 *cert, AUTHORITY_KEYID *akid)
+{
+    int     ret;
+
+    if (akid && akid->keyid) {
+       VSTRING *hexid = vstring_alloc(2 * EVP_MAX_MD_SIZE);
+       ASN1_STRING *id = (ASN1_STRING *) (akid->keyid);
+
+       hex_encode(hexid, (char *) M_ASN1_STRING_data(id),
+                  M_ASN1_STRING_length(id));
+       ret = add_ext(0, cert, NID_subject_key_identifier, STR(hexid));
+       vstring_free(hexid);
+    } else {
+       ret = add_ext(0, cert, NID_subject_key_identifier, "hash");
+    }
+    return (ret);
+}
+
+/* set_issuer - set issuer DN to match akid if specified */
+
+static int set_issuer_name(X509 *cert, AUTHORITY_KEYID *akid)
+{
+
+    /*
+     * If subject's akid specifies an authority key identifer issuer name, we
+     * must use that.
+     */
+    if (akid && akid->issuer) {
+       int     i;
+       general_name_stack_t *gens = akid->issuer;
+
+       for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
+           GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i);
+
+           if (gn->type == GEN_DIRNAME)
+               return (X509_set_issuer_name(cert, gn->d.dirn));
+       }
+    }
+    return (X509_set_issuer_name(cert, X509_get_subject_name(cert)));
+}
+
+/* grow_chain - add certificate to chain */
+
+static void grow_chain(x509_stack_t **skptr, X509 *cert, ASN1_OBJECT *trust)
+{
+    if (!*skptr && (*skptr = sk_X509_new_null()) == 0)
+       msg_fatal("out of memory");
+    if (cert) {
+       if (trust && !X509_add1_trust_object(cert, trust))
+           msg_fatal("out of memory");
+       CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
+       if (!sk_X509_push(*skptr, cert))
+           msg_fatal("out of memory");
+    }
+}
+
+/* wrap_key - wrap TA "key" as issuer of "subject" */
+
+static int wrap_key(TLS_SESS_STATE *TLScontext, EVP_PKEY *key, X509 *subject,
+                           int depth)
+{
+    int     ret = 1;
+    X509   *cert = 0;
+    AUTHORITY_KEYID *akid;
+    X509_NAME *name = X509_get_issuer_name(subject);
+
+    /*
+     * Record the depth of the intermediate wrapper certificate, logged in
+     * the verify callback, unlike the parent root CA.
+     */
+    if (!key)
+       TLScontext->tadepth = depth;
+    else if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH))
+       msg_info("%s: depth=%d chain is trust-anchor signed",
+                TLScontext->namaddr, depth);
+
+    /*
+     * If key is NULL generate a self-signed root CA, with key "danekey",
+     * otherwise an intermediate CA signed by above.
+     */
+    if ((cert = X509_new()) == 0)
+       return (0);
+
+    akid = X509_get_ext_d2i(subject, NID_authority_key_identifier, 0, 0);
+
+    ERR_clear_error();
+
+    /* CA cert valid for +/- 30 days */
+    if (!X509_set_version(cert, 2)
+       || !set_serial(cert, akid, subject)
+       || !X509_set_subject_name(cert, name)
+       || !set_issuer_name(cert, akid)
+       || !X509_gmtime_adj(X509_get_notBefore(cert), -30 * 86400L)
+       || !X509_gmtime_adj(X509_get_notAfter(cert), 30 * 86400L)
+       || !X509_set_pubkey(cert, key ? key : danekey)
+       || !add_ext(0, cert, NID_basic_constraints, "CA:TRUE")
+       || (key && !add_akid(cert, akid))
+       || !add_skid(cert, akid)
+       || (wrap_signed
+           && (!X509_sign(cert, danekey, signmd)
+               || (key && !wrap_key(TLScontext, 0, cert, depth + 1))))) {
+       msg_warn("error generating DANE wrapper certificate");
+       tls_print_errors();
+       ret = 0;
+    }
+    if (akid)
+       AUTHORITY_KEYID_free(akid);
+    if (ret) {
+       if (key && wrap_signed)
+           grow_chain(&TLScontext->untrusted, cert, 0);
+       else
+           grow_chain(&TLScontext->trusted, cert, serverAuth);
+    }
+    if (cert)
+       X509_free(cert);
+    return (ret);
+}
+
+/* ta_signed - is certificate signed by a TLSA cert or pkey */
+
+static int ta_signed(TLS_SESS_STATE *TLScontext, X509 *cert, int depth)
+{
+    const TLS_DANE *dane = TLScontext->dane;
+    EVP_PKEY *pk;
+    TLS_PKEYS *k;
+    TLS_CERTS *x;
+    int     done = 0;
+
+    /*
+     * First check whether issued and signed by a TA cert, this is cheaper
+     * than the bare-public key checks below, since we can determine whether
+     * the candidate TA certificate issued the certificate to be checked
+     * first (name comparisons), before we bother with signature checks
+     * (public key operations).
+     */
+    for (x = dane->certs; !done && x; x = x->next) {
+       if (X509_check_issued(x->cert, cert) == X509_V_OK) {
+           if ((pk = X509_get_pubkey(x->cert)) == 0)
+               continue;
+           /* Check signature, since some other TA may work if not this. */
+           if (X509_verify(cert, pk) > 0)
+               done = wrap_key(TLScontext, pk, cert, depth);
+           EVP_PKEY_free(pk);
+       }
+    }
+
+    /*
+     * With bare TA public keys, we can't check whether the trust chain is
+     * issued by the key, but we can determine whether it is signed by the
+     * key, so we go with that.
+     * 
+     * Ideally, the corresponding certificate was presented in the chain, and we
+     * matched it by its public key digest one level up.  This code is here
+     * to handle adverse conditions imposed by sloppy administrators of
+     * receiving systems with poorly constructed chains.
+     * 
+     * We'd like to optimize out keys that should not match when the cert's
+     * authority key id does not match the key id of this key computed via
+     * the RFC keyid algorithm (SHA-1 digest of public key bit-string sans
+     * ASN1 tag and length thus also excluding the unused bits field that is
+     * logically part of the length).  However, some CAs have a non-standard
+     * authority keyid, so we lose.  Too bad.
+     */
+    for (k = dane->pkeys; !done && k; k = k->next)
+       if (X509_verify(cert, k->pkey) > 0)
+           done = wrap_key(TLScontext, k->pkey, cert, depth);
+
+    return (done);
+}
+
+/* set_trust - configure for DANE validation */
+
+static void set_trust(TLS_SESS_STATE *TLScontext, X509_STORE_CTX *ctx)
+{
+    int     n;
+    int     i;
+    int     depth = 0;
+    EVP_PKEY *takey;
+    X509   *ca;
+    X509   *cert = ctx->cert;          /* XXX: Accessor? */
+    x509_stack_t *in = ctx->untrusted; /* XXX: Accessor? */
+
+    /* shallow copy */
+    if ((in = sk_X509_dup(in)) == 0)
+       msg_fatal("out of memory");
+
+    /*
+     * At each iteration we consume the issuer of the current cert.  This
+     * reduces the length of the "in" chain by one.  If no issuer is found,
+     * we are done.  We also stop when a certificate matches a TA in the
+     * peer's TLSA RRset.
+     * 
+     * Caller ensures that the initial certificate is not self-signed.
+     */
+    for (n = sk_X509_num(in); n > 0; --n, ++depth) {
+       for (i = 0; i < n; ++i)
+           if (X509_check_issued(sk_X509_value(in, i), cert) == X509_V_OK)
+               break;
+
+       /*
+        * Final untrusted element with no issuer in the peer's chain, it may
+        * however be signed by a pkey or cert obtained via a TLSA RR.
+        */
+       if (i == n)
+           break;
+
+       /* Peer's chain contains an issuer ca. */
+       ca = sk_X509_delete(in, i);
+
+       /* Is it a trust anchor? */
+       if (tls_dane_match(TLScontext, TLS_DANE_TA, ca, depth + 1)) {
+           if ((takey = X509_get_pubkey(ca)) != 0
+               && wrap_key(TLScontext, takey, cert, depth))
+               EVP_PKEY_free(takey);
+           cert = 0;
+           break;
+       }
+       /* Add untrusted ca. */
+       grow_chain(&TLScontext->untrusted, ca, 0);
+
+       /* Final untrusted self-signed element? */
+       if (X509_check_issued(ca, ca) == X509_V_OK) {
+           cert = 0;
+           break;
+       }
+       /* Restart with issuer as subject */
+       cert = ca;
+    }
+
+    /*
+     * When the loop exits, if "cert" is set, it is not self-signed and has
+     * no issuer in the chain, we check for a possible signature via a DNS
+     * obtained TA cert or public key.  Otherwise, we found no TAs and no
+     * issuer, so set an empty list of TAs.
+     */
+    if (!cert || !ta_signed(TLScontext, cert, depth)) {
+       /* Create empty trust list if null, else NOP */
+       grow_chain(&TLScontext->trusted, 0, 0);
+    }
+    /* shallow free */
+    if (in)
+       sk_X509_free(in);
+}
+
+/* dane_cb - wrap chain verification for DANE */
+
+static int dane_cb(X509_STORE_CTX *ctx, void *app_ctx)
+{
+    const char *myname = "dane_cb";
+    TLS_SESS_STATE *TLScontext = (TLS_SESS_STATE *) app_ctx;
+    X509   *cert = ctx->cert;          /* XXX: accessor? */
+
+    /*
+     * Degenerate case: depth 0 self-signed cert.
+     * 
+     * XXX: Should we suppress name checks, ... when the leaf certificate is a
+     * TA.  After all they could sign any name they want.  However, this
+     * requires a bit of additional code.  For now we allow depth 0 TAs, but
+     * then the peer name has to match.
+     */
+    if (X509_check_issued(cert, cert) == X509_V_OK) {
+
+       /*
+        * Empty untrusted chain, could be NULL, but then ABI check less
+        * reliable, we may zero some other field, ...
+        */
+       grow_chain(&TLScontext->untrusted, 0, 0);
+       if (tls_dane_match(TLScontext, TLS_DANE_TA, cert, 0))
+           grow_chain(&TLScontext->trusted, cert, serverAuth);
+       else
+           grow_chain(&TLScontext->trusted, 0, 0);
+    } else {
+       set_trust(TLScontext, ctx);
+    }
+
+    /*
+     * Check that setting the untrusted chain updates the expected structure
+     * member at the expected offset.
+     */
+    X509_STORE_CTX_trusted_stack(ctx, TLScontext->trusted);
+    X509_STORE_CTX_set_chain(ctx, TLScontext->untrusted);
+    if (ctx->untrusted != TLScontext->untrusted)
+       msg_panic("%s: OpenSSL ABI change", myname);
+
+    return X509_verify_cert(ctx);
+}
+
+/* tls_dane_set_callback - set or clear verification wrapper callback */
+
+void    tls_dane_set_callback(SSL_CTX *ctx, TLS_SESS_STATE *TLScontext)
+{
+    if (!serverAuth || !TLS_DANE_HASTA(TLScontext->dane))
+       SSL_CTX_set_cert_verify_callback(ctx, 0, 0);
+    else
+       SSL_CTX_set_cert_verify_callback(ctx, dane_cb, (void *) TLScontext);
+}
+
+#endif                                 /* USE_TLS */
+
index 8f731e6eade40e64f80fdf8eec5ba6ff9c5c7aca..40746ea55fb4af8f25cbb47ce8a079d5b8e07f1c 100644 (file)
@@ -53,7 +53,7 @@
 /*     and the caller must eventually free it with myfree().
 /*
 /*     tls_serverid_digest() suffixes props->serverid computed by the SMTP
-/*     client with ":" plus a digest of additional parameters
+/*     client with "&" plus a digest of additional parameters
 /*     needed to ensure that re-used sessions are more likely to
 /*     be reused and that they will satisfy all protocol and
 /*     security requirements.
@@ -217,8 +217,6 @@ char   *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask,
      * matching data, which is checked separately each time.  So we exclude
      * the EE part of the DANE structure from the serverid digest.
      * 
-     * If this changes, also update tls_dane_final() in tls_dane.c.
-     * 
      * If the security level is "dane", we send SNI information to the peer.
      * This may cause it to respond with a non-default certificate.  Since
      * certificates for sessions with no or different SNI data may not match,
@@ -256,7 +254,7 @@ char   *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask,
      */
     result = vstring_alloc(strlen(props->serverid) + 1 + 2 * md_len);
     vstring_strcpy(result, props->serverid);
-    VSTRING_ADDCH(result, ':');
+    VSTRING_ADDCH(result, '&');
     for (i = 0; i < md_len; i++) {
        VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0xf0) >> 4U]);
        VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0x0f)]);
index fdbac74b5576a7dc0d23e328e39f141f6048dc92..da47305208d035e162146296be67547024e12c0f 100644 (file)
@@ -439,8 +439,7 @@ static const char *tls_exclude_missing(SSL_CTX *ctx, VSTRING *buf)
     const char *myname = "tls_exclude_missing";
     static ARGV *exclude;              /* Cached */
     SSL    *s = 0;
-
-    STACK_OF(SSL_CIPHER) * ciphers;
+    ssl_cipher_stack_t *ciphers;
     SSL_CIPHER *c;
     const cipher_probe_t *probe;
     int     alg_bits;
@@ -789,13 +788,13 @@ TLS_SESS_STATE *tls_alloc_sess_context(int log_mask, const char *namaddr)
     TLScontext->log_mask = log_mask;
     TLScontext->namaddr = lowercase(mystrdup(namaddr));
     TLScontext->mdalg = 0;                     /* Alias for props->mdalg */
-    TLScontext->dane = 0;                      /* Alias for client
-                                                * props->dane */
-    TLScontext->trustdepth = -1;
-    TLScontext->chaindepth = -1;
+    TLScontext->dane = 0;                      /* Alias for props->dane */
     TLScontext->errordepth = -1;
+    TLScontext->tadepth = -1;
     TLScontext->errorcode = X509_V_OK;
     TLScontext->errorcert = 0;
+    TLScontext->untrusted = 0;
+    TLScontext->trusted = 0;
 
     return (TLScontext);
 }
@@ -828,6 +827,10 @@ void    tls_free_context(TLS_SESS_STATE *TLScontext)
        myfree(TLScontext->peer_pkey_fprint);
     if (TLScontext->errorcert)
        X509_free(TLScontext->errorcert);
+    if (TLScontext->untrusted)
+       sk_X509_pop_free(TLScontext->untrusted, X509_free);
+    if (TLScontext->trusted)
+       sk_X509_pop_free(TLScontext->trusted, X509_free);
 
     myfree((char *) TLScontext);
 }
@@ -934,7 +937,7 @@ long    tls_bug_bits(void)
      * breaking on all 0.9.8[ab] systems that have zlib support enabled.
      */
     if (lib_version >= 0x00908000L && lib_version <= 0x0090802fL) {
-       STACK_OF(SSL_COMP) * comp_methods;
+       ssl_comp_stack_t *comp_methods = SSL_COMP_get_compression_methods();
 
        comp_methods = SSL_COMP_get_compression_methods();
        if (comp_methods != 0 && sk_SSL_COMP_num(comp_methods) > 0)
@@ -1128,6 +1131,24 @@ int     tls_validate_digest(const char *dgst)
     const EVP_MD *md_alg;
     unsigned int md_len;
 
+    /*
+     * Register SHA-2 digests, if implemented and not already registered.
+     * Improves interoperability with clients and servers that prematurely
+     * deploy SHA-2 certificates.  Also facilitates DANE and TA support.
+     */
+#if defined(LN_sha256) && defined(NID_sha256) && !defined(OPENSSL_NO_SHA256)
+    if (!EVP_get_digestbyname(LN_sha224))
+       EVP_add_digest(EVP_sha224());
+    if (!EVP_get_digestbyname(LN_sha256))
+       EVP_add_digest(EVP_sha256());
+#endif
+#if defined(LN_sha512) && defined(NID_sha512) && !defined(OPENSSL_NO_SHA512)
+    if (!EVP_get_digestbyname(LN_sha384))
+       EVP_add_digest(EVP_sha384());
+    if (!EVP_get_digestbyname(LN_sha512))
+       EVP_add_digest(EVP_sha512());
+#endif
+
     /*
      * If the administrator specifies an unsupported digest algorithm, fail
      * now, rather than in the middle of a TLS handshake.
index 37cfb8975b490e4a32c90861a61baabf5dba8e01..d31c772c1469f5feafae23437cbaf976fa4d845c 100644 (file)
@@ -383,6 +383,9 @@ TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props)
     /*
      * Protocol work-arounds, OpenSSL version dependent.
      */
+#ifdef SSL_OP_NO_TICKET
+    off |= SSL_OP_NO_TICKET;
+#endif
     off |= tls_bug_bits();
     SSL_CTX_set_options(server_ctx, off);
 
index b1fe441ce890e2e9ed3ecdf7e86e7d41ceec9d6d..cbaae83ccdbd8156604547e0753193171e1b5469 100644 (file)
@@ -7,12 +7,6 @@
 /*     #define TLS_INTERNAL
 /*     #include <tls.h>
 /*
-/*     int     tls_cert_match(TLSContext, usage, cert, depth)
-/*     TLS_SESS_STATE *TLScontext;
-/*     int     usage;
-/*     X509    *cert;
-/*     int     depth;
-/*
 /*     int     tls_verify_certificate_callback(ok, ctx)
 /*     int     ok;
 /*     X509_STORE_CTX *ctx;
 /*     const GENERAL_NAME *gn;
 /*     TLS_SESS_STATE *TLScontext;
 /* DESCRIPTION
-/*     tls_cert_match() matches the full and/or public key digest of
-/*     "cert" against each candidate digest in TLScontext->dane. If usage
-/*     is TLS_DANE_EE, the match is against end-entity digests, otherwise
-/*     it is against trust-anchor digests.  Returns true if a match is found,
-/*     false otherwise.
-/*
 /*     tls_verify_certificate_callback() is called several times (directly
 /*     or indirectly) from crypto/x509/x509_vfy.c. It collects errors
 /*     and trust information at each element of the trust chain.
 /* .IP gn
 /*     An OpenSSL GENERAL_NAME structure holding a DNS subjectAltName
 /*     to be decoded and checked for validity.
-/* .IP usage
-/*     Trust anchor (TLS_DANE_TA) or end-entity (TLS_DANE_EE) digests?
-/* .IP cert
-/*     Certificate from peer trust chain (CA or leaf server).
-/* .IP depth
-/*     The certificate depth for logging.
 /* .IP peercert
 /*     Server or client X.509 certificate.
 /* .IP TLScontext
@@ -144,8 +126,7 @@ static void update_error_state(TLS_SESS_STATE *TLScontext, int depth,
                                       X509 *errorcert, int errorcode)
 {
     /* No news is good news */
-    if ((TLScontext->trustdepth >= 0 && TLScontext->trustdepth < depth) ||
-       (TLScontext->errordepth >= 0 && TLScontext->errordepth <= depth))
+    if (TLScontext->errordepth >= 0 && TLScontext->errordepth <= depth)
        return;
 
     /*
@@ -160,171 +141,7 @@ static void update_error_state(TLS_SESS_STATE *TLScontext, int depth,
        CRYPTO_add(&errorcert->references, 1, CRYPTO_LOCK_X509);
     TLScontext->errorcert = errorcert;
     TLScontext->errorcode = errorcode;
-
-    /*
-     * Maintain an invariant, at most one of errordepth and trustdepth is
-     * non-negative at any given time.
-     */
     TLScontext->errordepth = depth;
-    TLScontext->trustdepth = -1;
-}
-
-/* update_trust_state - safely stash away trust state */
-
-static void update_trust_state(TLS_SESS_STATE *TLScontext, int depth)
-{
-    /* No news is bad news */
-    if ((TLScontext->trustdepth >= 0 && TLScontext->trustdepth <= depth)
-       || (TLScontext->errordepth >= 0 && TLScontext->errordepth <= depth))
-       return;
-
-    /*
-     * Maintain an invariant, at most one of errordepth and trustdepth is
-     * non-negative at any given time.
-     */
-    TLScontext->trustdepth = depth;
-    TLScontext->errordepth = -1;
-}
-
-/* tls_cert_match - match cert against given list of TA or EE digests */
-
-int     tls_cert_match(TLS_SESS_STATE *TLScontext, int usage, X509 *cert, int depth)
-{
-    const TLS_DANE *dane = TLScontext->dane;
-    TLS_TLSA *tlsa = (usage == TLS_DANE_EE) ? dane->ee : dane->ta;
-    const char *namaddr = TLScontext->namaddr;
-    const char *ustr = (usage == TLS_DANE_EE) ? "end entity" : "trust anchor";
-    int     mixed = (dane->flags & TLS_DANE_FLAG_MIXED);
-    int     matched;
-
-    for (matched = 0; tlsa && !matched; tlsa = tlsa->next) {
-       char  **dgst;
-       ARGV   *certs;
-
-       if (tlsa->pkeys) {
-           char   *pkey_dgst = tls_pkey_fprint(cert, tlsa->mdalg);
-
-           for (dgst = tlsa->pkeys->argv; !matched && *dgst; ++dgst)
-               if (strcasecmp(pkey_dgst, *dgst) == 0)
-                   matched = 1;
-           if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH))
-               msg_info("%s: depth=%d matched=%d %s public-key %s digest=%s",
-                    namaddr, depth, matched, ustr, tlsa->mdalg, pkey_dgst);
-           myfree(pkey_dgst);
-       }
-       certs = mixed ? tlsa->pkeys : tlsa->certs;
-       if (certs != 0 && !matched) {
-           char   *cert_dgst = tls_cert_fprint(cert, tlsa->mdalg);
-
-           for (dgst = certs->argv; !matched && *dgst; ++dgst)
-               if (strcasecmp(cert_dgst, *dgst) == 0)
-                   matched = 1;
-           if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH))
-               msg_info("%s: depth=%d matched=%d %s certificate %s digest %s",
-                    namaddr, depth, matched, ustr, tlsa->mdalg, cert_dgst);
-           myfree(cert_dgst);
-       }
-    }
-
-    return (matched);
-}
-
-/* ta_match - match cert against out-of-band TA keys or digests */
-
-static int ta_match(TLS_SESS_STATE *TLScontext, X509_STORE_CTX *ctx,
-                           X509 *cert, int depth, int expired)
-{
-    const TLS_DANE *dane = TLScontext->dane;
-    int     matched = tls_cert_match(TLScontext, TLS_DANE_TA, cert, depth);
-
-    /*
-     * If we are the TA, the first trusted certificate is one level below! As
-     * a degenerate case a self-signed TA at depth 0 is also treated as a TA
-     * validated trust chain, (even if the certificate is expired).
-     * 
-     * Note: OpenSSL will flag an error when the chain contains just one
-     * certificate that is not self-issued.
-     */
-    if (matched) {
-       if (--depth < 0)
-           depth = 0;
-       update_trust_state(TLScontext, depth);
-       return (1);
-    }
-
-    /*
-     * If expired, no need to check for a trust-anchor signature.  The TA
-     * itself is matched by its digest, so we're at best looking at some
-     * other expired certificate issued by the TA, which we don't accept.
-     */
-    if (expired)
-       return (0);
-
-    /*
-     * Compute the index of the topmost chain certificate; it may need to be
-     * verified via one of our out-of-band trust-anchors.  Since we're here,
-     * the chain contains at least one certificate.
-     * 
-     * Optimization: if the top is self-issued, we don't need to try to check
-     * whether it is signed by any ancestor TAs.  If it is trusted, it will
-     * be matched by its fingerprint.
-     */
-    if (TLScontext->trustdepth < 0 && TLScontext->chaindepth < 0) {
-       STACK_OF(X509) *chain = X509_STORE_CTX_get_chain(ctx);
-       int     i = sk_X509_num(chain) - 1;
-       X509   *top = sk_X509_value(chain, i);
-
-       if (X509_check_issued(top, top) == X509_V_OK)
-           TLScontext->chaindepth = i + 1;
-       else
-           TLScontext->chaindepth = i;
-    }
-
-    /*
-     * Last resort, check whether signed by out-of-band TA public key.
-     * 
-     * Only the top certificate of the server chain needs this logic, since any
-     * certs below are signed by their parent, which we checked against the
-     * TA list more cheaply.  Do this at most once (by incrementing the depth
-     * when we're done).
-     */
-    if (depth == TLScontext->chaindepth) {
-       TLS_PKEYS *k;
-       TLS_CERTS *x;
-
-       /*
-        * First check whether issued and signed by a TA cert, this is
-        * cheaper than the bare-public key checks below, since we can
-        * determine whether the candidate TA certificate issued the
-        * certificate to be checked first (name comparisons), before we
-        * bother with signature checks (public key operations).
-        */
-       for (x = dane->certs; !matched && x; x = x->next) {
-           if (X509_check_issued(x->cert, cert) == X509_V_OK) {
-               EVP_PKEY *pk = X509_get_pubkey(x->cert);
-
-               matched = pk && X509_verify(cert, pk) > 0;
-               EVP_PKEY_free(pk);
-           }
-       }
-
-       /*
-        * With bare TA public keys, we can't check whether the trust chain
-        * is issued by the key, but we can determine whether it is signed by
-        * the key, so we go with that.  Ideally, the corresponding
-        * certificate was presented in the chain, and we matched it by its
-        * public key digest one level up.  This code is here to handle
-        * adverse conditions imposed by sloppy administrators of receiving
-        * systems with poorly constructed chains.
-        */
-       for (k = dane->pkeys; !matched && k; k = k->next)
-           matched = X509_verify(cert, k->pkey) > 0;
-
-       if (matched)
-           update_trust_state(TLScontext, depth);
-       ++TLScontext->chaindepth;
-    }
-    return (matched);
 }
 
 /* tls_verify_certificate_callback - verify peer certificate info */
@@ -344,6 +161,11 @@ int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
     err = X509_STORE_CTX_get_error(ctx);
     con = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
     TLScontext = SSL_get_ex_data(con, TLScontext_index);
+    depth = X509_STORE_CTX_get_error_depth(ctx);
+
+    /* Don't log the internal root CA unless there's an unexpected error. */
+    if (ok && TLScontext->tadepth > 0 && depth > TLScontext->tadepth)
+       return (1);
 
     /*
      * Certificate chain depth limit violations are mis-reported by the
@@ -359,7 +181,6 @@ int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
      * present at this depth. This disambiguates trust chain truncation from
      * an incomplete trust chain.
      */
-    depth = X509_STORE_CTX_get_error_depth(ctx);
     max_depth = SSL_get_verify_depth(con) - 1;
 
     /*
@@ -367,101 +188,14 @@ int     tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx)
      * rather we allow the TLS handshake to continue, but mark the session as
      * unverified. The application is responsible for closing any sessions
      * with unverified credentials.
-     * 
-     * When we have an explicit list of trusted CA fingerprints, record the
-     * smallest depth at which we find a trusted certificate. If this below
-     * the smallest error depth we win and the chain is trusted. Otherwise,
-     * the chain is untrusted. We make this decision *each* time we are
-     * called with depth == 0 (yes we may be called more than once).
      */
     if (max_depth >= 0 && depth > max_depth) {
-       update_error_state(TLScontext, depth, cert,
-                          X509_V_ERR_CERT_CHAIN_TOO_LONG);
-       return (1);
-    }
-
-    /*
-     * Per RFC 5280 and its upstream ITU documents, a trust anchor is just a
-     * public key, no more no less, and thus certificates bearing the
-     * trust-anchor public key are just public keys in X.509v3 garb.  Any
-     * meaning attached to their expiration, ... is simply local policy.
-     * 
-     * We don't punish server administrators for including an expired optional
-     * TA certificate in their chain.  Had they left it out, and provided us
-     * instead with only the TA public-key via a "2 1 0" TLSA record, there'd
-     * be no TA certificate from which to learn the expiration dates.
-     * 
-     * Therefore, in the interests of consistent behavior, we only enforce
-     * expiration dates BELOW the TA signature.  When we find an expired
-     * certificate, we only check whether it is a TA, and not whether it is
-     * signed by a TA.
-     * 
-     * Other than allowing TA certificate expiration, the only errors we allow
-     * are failure to chain to a trusted root.  Our TA set includes
-     * out-of-band data not available to the X509_STORE_CTX.
-     * 
-     * More than one of the allowed errors may be reported at a given depth,
-     * trap all instances, but run the matching code at most once.  If the
-     * current cert is ok, we have a trusted ancestor, and we're not verbose,
-     * don't bother with matching.
-     */
-    if (cert != 0
-       && (ok == 0
-           || TLScontext->trustdepth < 0
-         || (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_CERTMATCH)))
-       && TLS_DANE_HASTA(TLScontext->dane)
-       && (TLScontext->trustdepth == -1 || depth <= TLScontext->trustdepth)
-      && (TLScontext->errordepth == -1 || depth < TLScontext->errordepth)) {
-       int     expired = 0;            /* or not yet valid */
-
-       switch (ok ? X509_V_OK : err) {
-       case X509_V_ERR_CERT_NOT_YET_VALID:
-       case X509_V_ERR_CERT_HAS_EXPIRED:
-           expired = 1;
-           /* FALLTHROUGH */
-       case X509_V_OK:
-       case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
-       case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
-       case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
-       case X509_V_ERR_CERT_UNTRUSTED:
-           if ((!expired && depth == TLScontext->trustdepth)
-               || ta_match(TLScontext, ctx, cert, depth, expired))
-               ok = 1;
-           break;
-       }
+       X509_STORE_CTX_set_error(ctx, err = X509_V_ERR_CERT_CHAIN_TOO_LONG);
+       ok = 0;
     }
     if (ok == 0)
        update_error_state(TLScontext, depth, cert, err);
 
-    /*
-     * Perhaps the chain is verified, or perhaps we'll get called again,
-     * either way the best we know is that if trust depth is below error
-     * depth we win and otherwise we lose. Set the error state accordingly.
-     * 
-     * If we are given explicit TA match list, we must match one of them at a
-     * non-negative depth below any errors, otherwise we just need no errors.
-     */
-    if (depth == 0) {
-       ok = 0;
-       if (TLScontext->trustdepth < 0 && TLS_DANE_HASTA(TLScontext->dane)) {
-           /* Required Policy or DANE certs not present */
-           if (TLScontext->errordepth < 0) {
-
-               /*
-                * For lack of a better choice log the trust problem against
-                * the leaf cert when PKI says yes, but local policy or DANE
-                * says no. Logging a root cert as untrusted would far more
-                * likely confuse users!
-                */
-               update_error_state(TLScontext, depth, cert,
-                                  X509_V_ERR_CERT_UNTRUSTED);
-           }
-       } else if (TLScontext->errordepth < 0) {
-           /* No PKI trust errors, or only above a good policy or DANE CA. */
-           ok = 1;
-       }
-       X509_STORE_CTX_set_error(ctx, ok ? X509_V_OK : TLScontext->errorcode);
-    }
     if (TLScontext->log_mask & TLS_LOG_VERBOSE) {
        if (cert)
            X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));