2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 13:18:12 +00:00

postfix-2.11-20130616

This commit is contained in:
Wietse Venema 2013-06-16 00:00:00 -05:00 committed by Viktor Dukhovni
parent b7660498e2
commit 2da14e7e2c
13 changed files with 778 additions and 425 deletions

12
postfix/.indent.pro vendored
View 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
@ -116,6 +119,8 @@
-TDSN_BUF
-TDSN_SPLIT
-TDSN_STAT
-TEC_KEY
-TEC_GROUP
-TEDIT_FILE
-TEVENT_MASK
-TEVP_PKEY
@ -324,8 +329,10 @@
-TWATCHDOG
-TWATCH_FD
-TX509
-TX509_EXTENSION
-TX509_NAME
-TX509_STORE_CTX
-TX509V3_CTX
-TXSASL_CLIENT
-TXSASL_CLIENT_CREATE_ARGS
-TXSASL_CLIENT_IMPL
@ -342,6 +349,7 @@
-TXSASL_SERVER_IMPL
-TXSASL_SERVER_IMPL_INFO
-Tcipher_probe_t
-Tgeneral_name_stack_t
-Toff_t
-Tregex_t
-Tregmatch_t
@ -349,5 +357,9 @@
-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

View 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.

View 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

View File

@ -575,39 +575,59 @@ static RESPONSE *ehlo(STATE *state)
#ifdef USE_TLS
static void print_stack(STATE *state, x509_stack_t *sk, int trustout)
{
int i;
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);
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)
{
STACK_OF(X509) *sk = SSL_get_peer_cert_chain(state->tls_context->con);
x509_stack_t *sk = SSL_get_peer_cert_chain(state->tls_context->con);
if (sk != NULL) {
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;
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);
PEM_write_bio_X509(state->tls_bio, cert);
}
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 */
@ -615,7 +635,6 @@ static void print_trust_info(STATE *state)
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

View 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

View 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;

View 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
*/

View 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.

View File

@ -31,8 +31,15 @@
/* 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;
@ -68,17 +75,25 @@
/* 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
@ -109,6 +124,17 @@
/* 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.
@ -161,6 +187,7 @@
#include <events.h> /* event_time() */
#include <timecmp.h>
#include <ctable.h>
#include <hex_code.h>
#define STR(x) vstring_str(x)
@ -179,13 +206,45 @@
/* 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();
return (avail = 1);
/* 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();
#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 */

View 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)]);

View 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.

View 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);

View 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;
@ -32,12 +26,6 @@
/* 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.
@ -79,12 +67,6 @@
/* .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));