[openssl-dev] SSL_get0_dane_authority() and session reuse

Viktor Dukhovni openssl-users at dukhovni.org
Sat Jan 23 21:08:00 UTC 2016


> On Jan 23, 2016, at 6:42 AM, Claus Assmann <ca+ssl-dev at esmtp.org> wrote:
> 
> For SMTP STARTTLS I try to determine some properties of the TLS
> connection so the MTA can decide whether the connection should be
> aborted or continue.  Those properties are for example: cert issuer,
> cert subject, cipher bits, verification status, e.g., X509_V_OK,
> (all of which can be retrieved from SSL via some function calls),
> and in the last case I would like to know if DANE was
> (originally/successfully) used.
> 
> I could try to store that information somehow in the TLS session
> context (SSL) myself, but it would make things much easier if OpenSSL
> can provide that information.

The solution is to look at the return value of SSL_get_verify_result().
If this is X509_V_OK, then the peer's certificate chain was valid when
originally verified, and continues to be valid for the resumed session,
provided you're careful about which sessions are suitable for resuming
for a given nexthop domain and MX host.

Postfix is careful to make sure that for a DANE nexthop domain the
session lookup key hashes together all the relevant policy info:

Firstly:

    /*
     * The following assumes sites that use TLS in a perverse configuration:
     * multiple hosts per hostname, or even multiple hosts per IP address.
     * All this without a shared TLS session cache, and they still want to
     * use TLS session caching???
     *
     * The TLS session cache records the trust chain verification status of
     * cached sessions. Different transports may have different CAfile or
     * CApath settings, perhaps to allow authenticated connections to sites
     * with private CA certs without trusting said private certs for other
     * sites. So we cannot assume that a trust chain valid for one transport
     * is valid for another. Therefore the client session id must include
     * either the transport name or the values of CAfile and CApath. We use
     * the transport name.
     *
     * XXX: We store only one session per lookup key. Ideally the the key maps
     * 1-to-1 to a server TLS session cache. We use the IP address, port and
     * ehlo response name to build a lookup key that works for split caches
     * (that announce distinct names) behind a load balancer.
     *
     * XXX: The TLS library will salt the serverid with further details of the
     * protocol and cipher requirements including the server ehlo response.
     * Deferring the helo to the digested suffix results in more predictable
     * SSL session lookup key lengths.
     */
    serverid = vstring_alloc(10);
    smtp_key_prefix(serverid, "&", state->iterator, SMTP_KEY_FLAG_SERVICE
                    | SMTP_KEY_FLAG_NEXTHOP     /* With port */
                    | SMTP_KEY_FLAG_HOSTNAME
                    | SMTP_KEY_FLAG_ADDR);

Which means that the serverid lookup has a prefix of the form:

	<transport>&<nexthop_with_port>&<mxhostname>&<ipaddress>

This is followed by "&<digest>", where the digest (sha256) combines
all the key policy data that might affect the validity of a cached
verification status.

    /*
     * OpenSSL will ignore cached sessions that use the wrong protocol. So we
     * do not need to filter out cached sessions with the "wrong" protocol,
     * rather OpenSSL will simply negotiate a new session.
     *
     * We salt the session lookup key with the protocol list, so that sessions
     * found in the cache are plausibly acceptable.
     *
     * By the time a TLS client is negotiating ciphers it has already offered to
     * re-use a session, it is too late to renege on the offer. So we must
     * not attempt to re-use sessions whose ciphers are too weak. We salt the
     * session lookup key with the cipher list, so that sessions found in the
     * cache are always acceptable.
     *
     * With DANE, (more generally any TLScontext where we specified explicit
     * trust-anchor or end-entity certificates) the verification status of
     * the SSL session depends on the specified list.  Since we verify the
     * certificate only during the initial handshake, we must segregate
     * sessions with different TA lists.  Note, that TA re-verification is
     * not possible with cached sessions, since these don't hold the complete
     * peer trust chain.  Therefore, we compute a digest of the sorted TA
     * parameters and append it to the serverid.
     */
    myserverid = tls_serverid_digest(props, protomask, cipher_list);

Under the covers:

    mdctx = EVP_MD_CTX_create();
    checkok(EVP_DigestInit_ex(mdctx, md, NULL));
    digest_string(props->helo ? props->helo : "");
    digest_object(&sslversion);
    digest_object(&protomask);
    digest_string(ciphers);

The "helo" string is important for split caches where multiple hosts
sit behind a load balancer and don't share their session caches.  This
is taken from <server-name> in:

	C: EHLO <client-name>
	S: 250-<server-name> [WSP line-noise]?

Then we hash the library SSL version, because the cache is shared across
processes, but SSL_SESSION internals may change across library versions.
The the protocol support mask, and cipherlist.  This is followed by a
digest of the TLSA records or applicable destination-specific trust-anchors.
(Postfix uses the DANE code to implement destination-specific trust-anchors
 as synthetic TLSA records).

The result is that cached verification state is only valid for a particular
(transport, nexthop, mxhostname, ip address, helo-name, policy-digest).
This ensures that all the TLS policy bits are the same as at the time the
session was added to the cache.

With that, there is no need to examine anything other than the verification
status being X509_V_OK.  You can of course still extract the peer certificate
from the session, but not the full chain, or the DANE match details.

-- 
	Viktor.





More information about the openssl-dev mailing list