/*
* Author: Viktor Dukhovni
* License: THIS CODE IS IN THE PUBLIC DOMAIN.
+ *
+ * Copyright (c) The Exim Maintainers 2014 - 2016
*/
#include <stdio.h>
#include <string.h>
# error "OpenSSL 1.0.0 or higher required"
#else /* remainder of file */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-#define X509_up_ref(x) CRYPTO_add(&((x)->references), 1, CRYPTO_LOCK_X509)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+# define X509_up_ref(x) CRYPTO_add(&((x)->references), 1, CRYPTO_LOCK_X509)
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+# define EXIM_HAVE_ASN1_MACROS
+# define EXIM_OPAQUE_X509
+#else
+# define X509_STORE_CTX_get_verify(ctx) (ctx)->verify
+# define X509_STORE_CTX_get_verify_cb(ctx) (ctx)->verify_cb
+# define X509_STORE_CTX_get0_cert(ctx) (ctx)->cert
+# define X509_STORE_CTX_get0_chain(ctx) (ctx)->chain
+# define X509_STORE_CTX_get0_untrusted(ctx) (ctx)->untrusted
+
+# define X509_STORE_CTX_set_verify(ctx, verify_chain) (ctx)->verify = (verify_chain)
+# define X509_STORE_CTX_set0_verified_chain(ctx, sk) (ctx)->chain = (sk)
+# define X509_STORE_CTX_set_error_depth(ctx, val) (ctx)->error_depth = (val)
+# define X509_STORE_CTX_set_current_cert(ctx, cert) (ctx)->current_cert = (cert)
#endif
+
#include "danessl.h"
#define DANESSL_F_ADD_SKID 100
# define X509_V_ERR_HOSTNAME_MISMATCH X509_V_ERR_APPLICATION_VERIFICATION
#endif
+
+
static int
match(dane_selector_list slist, X509 *cert, int depth)
{
if ( (akid = AUTHORITY_KEYID_new()) != 0
&& (akid->keyid = ASN1_OCTET_STRING_new()) != 0
+#ifdef EXIM_HAVE_ASN1_MACROS
+ && ASN1_OCTET_STRING_set(akid->keyid, (void *) &c, 1)
+#else
&& M_ASN1_OCTET_STRING_set(akid->keyid, (void *) &c, 1)
+#endif
&& X509_add1_ext_i2d(cert, nid, akid, 0, X509V3_ADD_APPEND))
ret = 1;
if (akid)
{
if (trusted && !X509_add1_trust_object(cert, serverAuth))
return 0;
+#ifdef EXIM_OPAQUE_X509
+ X509_up_ref(cert);
+#else
CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
+#endif
if (!sk_X509_push(*xs, cert))
{
X509_free(cert);
int depth = 0;
EVP_PKEY *takey;
X509 *ca;
-STACK_OF(X509) *in = ctx->untrusted; /* XXX: Accessor? */
+STACK_OF(X509) *in = X509_STORE_CTX_get0_untrusted(ctx);
if (!grow_chain(dane, UNTRUSTED, 0))
return -1;
dane->mdpth = 0;
dane->match = cert;
X509_up_ref(cert);
- if(!ctx->chain)
+ if(!X509_STORE_CTX_get0_chain(ctx))
{
- if ( (ctx->chain = sk_X509_new_null()) != 0
- && sk_X509_push(ctx->chain, cert))
+ STACK_OF(X509) * sk = sk_X509_new_null();
+ if (sk && sk_X509_push(sk, cert))
+ {
+ X509_STORE_CTX_set0_verified_chain(ctx, sk);
X509_up_ref(cert);
+ }
else
{
DANEerr(DANESSL_F_CHECK_END_ENTITY, ERR_R_MALLOC_FAILURE);
continue;
if (!(dane->mhost = OPENSSL_strdup(certid)))
matched = -1;
+ DEBUG(D_tls) debug_printf("Dane name_check: matched SAN %s\n", certid);
break;
}
}
* XXX: Should the subjectName be skipped when *any* altnames are present,
* or only when DNS altnames are present?
*/
-if (got_altname == 0)
+if (!got_altname)
{
char *certid = parse_subject_name(cert);
- if (certid != 0 && *certid
- && (matched = match_name(certid, dane)) != 0)
+ if (certid != 0 && *certid && (matched = match_name(certid, dane)) != 0)
+ {
+ DEBUG(D_tls) debug_printf("Dane name_check: matched SN %s\n", certid);
dane->mhost = OPENSSL_strdup(certid);
- if (certid)
- OPENSSL_free(certid);
+ }
+ if (certid)
+ OPENSSL_free(certid);
}
return matched;
}
static int
verify_chain(X509_STORE_CTX *ctx)
{
-dane_selector_list issuer_rrs;
-dane_selector_list leaf_rrs;
-int (*cb)(int, X509_STORE_CTX *) = ctx->verify_cb;
+int (*cb)(int, X509_STORE_CTX *) = X509_STORE_CTX_get_verify_cb(ctx);
+X509 *cert = X509_STORE_CTX_get0_cert(ctx);
+int chain_length = sk_X509_num(X509_STORE_CTX_get0_chain(ctx));
int ssl_idx = SSL_get_ex_data_X509_STORE_CTX_idx();
SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, ssl_idx);
ssl_dane *dane = SSL_get_ex_data(ssl, dane_idx);
-X509 *cert = ctx->cert; /* XXX: accessor? */
+dane_selector_list issuer_rrs = dane->selectors[DANESSL_USAGE_PKIX_TA];
+dane_selector_list leaf_rrs = dane->selectors[DANESSL_USAGE_PKIX_EE];
int matched = 0;
-int chain_length = sk_X509_num(ctx->chain);
-DEBUG(D_tls) debug_printf("Dane verify-chain\n");
+DEBUG(D_tls) debug_printf("Dane verify_chain\n");
-issuer_rrs = dane->selectors[DANESSL_USAGE_PKIX_TA];
-leaf_rrs = dane->selectors[DANESSL_USAGE_PKIX_EE];
-ctx->verify = dane->verify;
+X509_STORE_CTX_set_verify(ctx, dane->verify);
if ((matched = name_check(dane, cert)) < 0)
{
if (!matched)
{
- ctx->error_depth = 0;
- ctx->current_cert = cert;
+ X509_STORE_CTX_set_error_depth(ctx, 0);
+ X509_STORE_CTX_set_current_cert(ctx, cert);
X509_STORE_CTX_set_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH);
if (!cb(0, ctx))
return 0;
}
matched = 0;
- /*
- * Satisfy at least one usage 0 or 1 constraint, unless we've already
- * matched a usage 2 trust anchor.
- *
- * XXX: internal_verify() doesn't callback with top certs that are not
- * self-issued. This should be fixed in a future OpenSSL.
- */
- if (dane->roots && sk_X509_num(dane->roots))
- {
- X509 *top = sk_X509_value(ctx->chain, dane->depth);
+/*
+ * Satisfy at least one usage 0 or 1 constraint, unless we've already
+ * matched a usage 2 trust anchor.
+ *
+ * XXX: internal_verify() doesn't callback with top certs that are not
+ * self-issued. This should be fixed in a future OpenSSL.
+ */
+if (dane->roots && sk_X509_num(dane->roots))
+ {
+ X509 *top = sk_X509_value(X509_STORE_CTX_get0_chain(ctx), dane->depth);
- dane->mdpth = dane->depth;
- dane->match = top;
- X509_up_ref(top);
+ dane->mdpth = dane->depth;
+ dane->match = top;
+ X509_up_ref(top);
#ifndef NO_CALLBACK_WORKAROUND
- if (X509_check_issued(top, top) != X509_V_OK)
- {
- ctx->error_depth = dane->depth;
- ctx->current_cert = top;
- if (!cb(1, ctx))
- return 0;
- }
+ if (X509_check_issued(top, top) != X509_V_OK)
+ {
+ X509_STORE_CTX_set_error_depth(ctx, dane->depth);
+ X509_STORE_CTX_set_current_cert(ctx, top);
+ if (!cb(1, ctx))
+ return 0;
+ }
#endif
/* Pop synthetic trust-anchor ancestors off the chain! */
while (--chain_length > dane->depth)
- X509_free(sk_X509_pop(ctx->chain));
+ X509_free(sk_X509_pop(X509_STORE_CTX_get0_chain(ctx)));
}
else
{
*/
if (leaf_rrs)
matched = match(leaf_rrs, xn, 0);
+ if (matched) DEBUG(D_tls) debug_printf("Dane verify_chain: matched EE\n");
if (!matched && issuer_rrs)
for (n = chain_length-1; !matched && n >= 0; --n)
{
- xn = sk_X509_value(ctx->chain, n);
+ xn = sk_X509_value(X509_STORE_CTX_get0_chain(ctx), n);
if (n > 0 || X509_check_issued(xn, xn) == X509_V_OK)
matched = match(issuer_rrs, xn, n);
}
+ if (matched) DEBUG(D_tls) debug_printf("Dane verify_chain: matched %s\n",
+ n>0 ? "CA" : "selfisssued EE");
if (!matched)
{
- ctx->current_cert = cert;
- ctx->error_depth = 0;
+ X509_STORE_CTX_set_error_depth(ctx, 0);
+ X509_STORE_CTX_set_current_cert(ctx, cert);
X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_UNTRUSTED);
if (!cb(0, ctx))
return 0;
}
}
-return ctx->verify(ctx);
+return (X509_STORE_CTX_get_verify(ctx))(ctx);
}
static void
static int ssl_idx = -1;
SSL *ssl;
ssl_dane *dane;
-int (*cb)(int, X509_STORE_CTX *) = ctx->verify_cb;
+int (*cb)(int, X509_STORE_CTX *) = X509_STORE_CTX_get_verify_cb(ctx);
+X509 *cert = X509_STORE_CTX_get0_cert(ctx);
int matched;
-X509 *cert = ctx->cert; /* XXX: accessor? */
-DEBUG(D_tls) debug_printf("Dane verify-cert\n");
+DEBUG(D_tls) debug_printf("Dane verify_cert\n");
if (ssl_idx < 0)
ssl_idx = SSL_get_ex_data_X509_STORE_CTX_idx();
if (!(dane = SSL_get_ex_data(ssl, dane_idx)) || !cert)
return X509_verify_cert(ctx);
- /* Reset for verification of a new chain, perhaps a renegotiation. */
+/* Reset for verification of a new chain, perhaps a renegotiation. */
dane_reset(dane);
if (dane->selectors[DANESSL_USAGE_DANE_EE])
{
if ((matched = check_end_entity(ctx, dane, cert)) > 0)
{
- ctx->error_depth = 0;
- ctx->current_cert = cert;
+ X509_STORE_CTX_set_error_depth(ctx, 0);
+ X509_STORE_CTX_set_current_cert(ctx, cert);
return cb(1, ctx);
}
if (matched < 0)
*/
X509_STORE_CTX_trusted_stack(ctx, dane->roots);
X509_STORE_CTX_set_chain(ctx, dane->chain);
- OPENSSL_assert(ctx->untrusted == dane->chain);
+ OPENSSL_assert(X509_STORE_CTX_get0_untrusted(ctx) == dane->chain);
}
}
* X509_verify_cert() builds the full chain and calls our verify_chain()
* wrapper.
*/
- dane->verify = ctx->verify;
- ctx->verify = verify_chain;
+ dane->verify = X509_STORE_CTX_get_verify(ctx);
+ X509_STORE_CTX_set_verify(ctx, verify_chain);
if (X509_verify_cert(ctx))
return 1;