summaryrefslogtreecommitdiffstats
path: root/0009-Check-names-in-the-server-s-cert-when-using-KKDCP.patch
diff options
context:
space:
mode:
Diffstat (limited to '0009-Check-names-in-the-server-s-cert-when-using-KKDCP.patch')
-rw-r--r--0009-Check-names-in-the-server-s-cert-when-using-KKDCP.patch562
1 files changed, 562 insertions, 0 deletions
diff --git a/0009-Check-names-in-the-server-s-cert-when-using-KKDCP.patch b/0009-Check-names-in-the-server-s-cert-when-using-KKDCP.patch
new file mode 100644
index 0000000..14e3354
--- /dev/null
+++ b/0009-Check-names-in-the-server-s-cert-when-using-KKDCP.patch
@@ -0,0 +1,562 @@
+From f7825e81b1ebf533c1dba9f84ae9ad36073a89cf Mon Sep 17 00:00:00 2001
+From: Nalin Dahyabhai <nalin@dahyabhai.net>
+Date: Thu, 17 Apr 2014 17:19:03 -0400
+Subject: [PATCH 09/13] Check names in the server's cert when using KKDCP
+
+When we connect to a KDC using an HTTPS proxy, check that the naming
+information in the certificate matches the name or address which we
+extracted from the server URL in the configuration.
+
+ticket: 7929
+---
+ src/include/k5-trace.h | 5 +
+ src/lib/krb5/os/Makefile.in | 3 +
+ src/lib/krb5/os/checkhost.c | 251 +++++++++++++++++++++++++++++++++++++++++++
+ src/lib/krb5/os/checkhost.h | 39 +++++++
+ src/lib/krb5/os/deps | 14 ++-
+ src/lib/krb5/os/sendto_kdc.c | 53 +++++++--
+ 6 files changed, 355 insertions(+), 10 deletions(-)
+ create mode 100644 src/lib/krb5/os/checkhost.c
+ create mode 100644 src/lib/krb5/os/checkhost.h
+
+diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
+index 046bc95..9e75b29 100644
+--- a/src/include/k5-trace.h
++++ b/src/include/k5-trace.h
+@@ -324,6 +324,11 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
+ TRACE(c, "Resolving hostname {str}", hostname)
+ #define TRACE_SENDTO_KDC_RESPONSE(c, len, raddr) \
+ TRACE(c, "Received answer ({int} bytes) from {raddr}", len, raddr)
++#define TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MISMATCH(c, hostname) \
++ TRACE(c, "HTTPS certificate name mismatch: server certificate is " \
++ "not for \"{str}\"", hostname)
++#define TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MATCH(c, hostname) \
++ TRACE(c, "HTTPS certificate name matched \"{str}\"", hostname)
+ #define TRACE_SENDTO_KDC_HTTPS_NO_REMOTE_CERTIFICATE(c) \
+ TRACE(c, "HTTPS server certificate not received")
+ #define TRACE_SENDTO_KDC_HTTPS_PROXY_CERTIFICATE_ERROR(c, depth, \
+diff --git a/src/lib/krb5/os/Makefile.in b/src/lib/krb5/os/Makefile.in
+index fb4001a..fa8a093 100644
+--- a/src/lib/krb5/os/Makefile.in
++++ b/src/lib/krb5/os/Makefile.in
+@@ -13,6 +13,7 @@ STLIBOBJS= \
+ c_ustime.o \
+ ccdefname.o \
+ changepw.o \
++ checkhost.o \
+ dnsglue.o \
+ dnssrv.o \
+ expand_path.o \
+@@ -59,6 +60,7 @@ OBJS= \
+ $(OUTPRE)c_ustime.$(OBJEXT) \
+ $(OUTPRE)ccdefname.$(OBJEXT) \
+ $(OUTPRE)changepw.$(OBJEXT) \
++ $(OUTPRE)checkhost.$(OBJEXT) \
+ $(OUTPRE)dnsglue.$(OBJEXT) \
+ $(OUTPRE)dnssrv.$(OBJEXT) \
+ $(OUTPRE)expand_path.$(OBJEXT) \
+@@ -105,6 +107,7 @@ SRCS= \
+ $(srcdir)/c_ustime.c \
+ $(srcdir)/ccdefname.c \
+ $(srcdir)/changepw.c \
++ $(srcdir)/checkhost.c \
+ $(srcdir)/dnsglue.c \
+ $(srcdir)/dnssrv.c \
+ $(srcdir)/expand_path.c \
+diff --git a/src/lib/krb5/os/checkhost.c b/src/lib/krb5/os/checkhost.c
+new file mode 100644
+index 0000000..a91615d
+--- /dev/null
++++ b/src/lib/krb5/os/checkhost.c
+@@ -0,0 +1,251 @@
++/*
++ * Copyright 2014 Red Hat, Inc. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ *
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
++ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "k5-int.h"
++#include "k5-utf8.h"
++
++#ifdef PROXY_TLS_IMPL_OPENSSL
++#include <openssl/ssl.h>
++#include <openssl/x509.h>
++#include <openssl/x509v3.h>
++#include "checkhost.h"
++
++/* Return the passed-in character, lower-cased if it's an ASCII character. */
++static inline char
++ascii_tolower(char p)
++{
++ if (KRB5_UPPER(p))
++ return p + ('a' - 'A');
++ return p;
++}
++
++/*
++ * Check a single label. If allow_wildcard is true, and the presented name
++ * includes a wildcard, return true and note that we matched a wildcard.
++ * Otherwise, for both the presented and expected values, do a case-insensitive
++ * comparison of ASCII characters, and a case-sensitive comparison of
++ * everything else.
++ */
++static krb5_boolean
++label_match(const char *presented, size_t plen, const char *expected,
++ size_t elen, krb5_boolean allow_wildcard, krb5_boolean *wildcard)
++{
++ unsigned int i;
++
++ if (allow_wildcard && plen == 1 && presented[0] == '*') {
++ *wildcard = TRUE;
++ return TRUE;
++ }
++
++ if (plen != elen)
++ return FALSE;
++
++ for (i = 0; i < elen; i++) {
++ if (ascii_tolower(presented[i]) != ascii_tolower(expected[i]))
++ return FALSE;
++ }
++ return TRUE;
++}
++
++/* Break up the two names and check them, label by label. */
++static krb5_boolean
++domain_match(const char *presented, size_t plen, const char *expected)
++{
++ const char *p, *q, *r, *s;
++ int n_label;
++ krb5_boolean used_wildcard = FALSE;
++
++ n_label = 0;
++ p = presented;
++ r = expected;
++ while (p < presented + plen && *r != '\0') {
++ q = memchr(p, '.', plen - (p - presented));
++ if (q == NULL)
++ q = presented + plen;
++ s = r + strcspn(r, ".");
++ if (!label_match(p, q - p, r, s - r, n_label == 0, &used_wildcard))
++ return FALSE;
++ p = q < presented + plen ? q + 1 : q;
++ r = *s ? s + 1 : s;
++ n_label++;
++ }
++ if (used_wildcard && n_label <= 2)
++ return FALSE;
++ if (p == presented + plen && *r == '\0')
++ return TRUE;
++ return FALSE;
++}
++
++/* Fetch the list of subjectAltNames from a certificate. */
++static GENERAL_NAMES *
++get_cert_sans(X509 *x)
++{
++ int ext;
++ X509_EXTENSION *san_ext;
++
++ ext = X509_get_ext_by_NID(x, NID_subject_alt_name, -1);
++ if (ext < 0)
++ return NULL;
++ san_ext = X509_get_ext(x, ext);
++ if (san_ext == NULL)
++ return NULL;
++ return X509V3_EXT_d2i(san_ext);
++}
++
++/* Fetch a CN value from the subjct name field, returning its length, or -1 if
++ * there is no subject name or it contains no CN value. */
++static ssize_t
++get_cert_cn(X509 *x, char *buf, size_t bufsize)
++{
++ X509_NAME *name;
++
++ name = X509_get_subject_name(x);
++ if (name == NULL)
++ return -1;
++ return X509_NAME_get_text_by_NID(name, NID_commonName, buf, bufsize);
++}
++
++/*
++ * Return true if the passed-in expected IP address matches any of the names we
++ * can recover from the server certificate, false otherwise.
++ */
++krb5_boolean
++k5_check_cert_address(X509 *x, const char *text)
++{
++ char buf[1024];
++ GENERAL_NAMES *sans;
++ GENERAL_NAME *san = NULL;
++ ASN1_OCTET_STRING *ip;
++ krb5_boolean found_ip_san = FALSE, matched = FALSE;
++ int n_sans, i;
++ size_t name_length;
++ union {
++ struct in_addr in;
++ struct in6_addr in6;
++ } name;
++
++ /* Parse the IP address into an octet string. */
++ ip = M_ASN1_OCTET_STRING_new();
++ if (ip == NULL)
++ return FALSE;
++
++ if (inet_aton(text, &name.in) == 1)
++ name_length = sizeof(name.in);
++ else if (inet_pton(AF_INET6, text, &name.in6) == 1)
++ name_length = sizeof(name.in6);
++ else
++ name_length = 0;
++
++ if (name_length == 0) {
++ ASN1_OCTET_STRING_free(ip);
++ return FALSE;
++ }
++ M_ASN1_OCTET_STRING_set(ip, &name, name_length);
++
++ /* Check for matches in ipaddress subjectAltName values. */
++ sans = get_cert_sans(x);
++ if (sans != NULL) {
++ n_sans = sk_GENERAL_NAME_num(sans);
++ for (i = 0; i < n_sans; i++) {
++ san = sk_GENERAL_NAME_value(sans, i);
++ if (san->type != GEN_IPADD)
++ continue;
++ found_ip_san = TRUE;
++ matched = ASN1_OCTET_STRING_cmp(ip, san->d.iPAddress) == 0;
++ if (matched)
++ break;
++ }
++ sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free);
++ }
++ ASN1_OCTET_STRING_free(ip);
++
++ if (matched)
++ return TRUE;
++ if (found_ip_san)
++ return matched;
++
++ /* Check for a match against the CN value in the peer's subject name. */
++ name_length = get_cert_cn(x, buf, sizeof(buf));
++ if (name_length >= 0) {
++ /* Do a string compare to check if it's an acceptable value. */
++ return strlen(text) == name_length &&
++ strncmp(text, buf, name_length) == 0;
++ }
++
++ /* We didn't find a match. */
++ return FALSE;
++}
++
++/*
++ * Return true if the passed-in expected name matches any of the names we can
++ * recover from a server certificate, false otherwise.
++ */
++krb5_boolean
++k5_check_cert_servername(X509 *x, const char *expected)
++{
++ char buf[1024];
++ GENERAL_NAMES *sans;
++ GENERAL_NAME *san = NULL;
++ unsigned char *dnsname;
++ krb5_boolean found_dns_san = FALSE, matched = FALSE;
++ int name_length, n_sans, i;
++
++ /* Check for matches in dnsname subjectAltName values. */
++ sans = get_cert_sans(x);
++ if (sans != NULL) {
++ n_sans = sk_GENERAL_NAME_num(sans);
++ for (i = 0; i < n_sans; i++) {
++ san = sk_GENERAL_NAME_value(sans, i);
++ if (san->type != GEN_DNS)
++ continue;
++ found_dns_san = TRUE;
++ dnsname = NULL;
++ name_length = ASN1_STRING_to_UTF8(&dnsname, san->d.dNSName);
++ if (dnsname == NULL)
++ continue;
++ matched = domain_match((char *)dnsname, name_length, expected);
++ OPENSSL_free(dnsname);
++ if (matched)
++ break;
++ }
++ sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free);
++ }
++
++ if (matched)
++ return TRUE;
++ if (found_dns_san)
++ return matched;
++
++ /* Check for a match against the CN value in the peer's subject name. */
++ name_length = get_cert_cn(x, buf, sizeof(buf));
++ if (name_length >= 0)
++ return domain_match(buf, name_length, expected);
++
++ /* We didn't find a match. */
++ return FALSE;
++}
++#endif
+diff --git a/src/lib/krb5/os/checkhost.h b/src/lib/krb5/os/checkhost.h
+new file mode 100644
+index 0000000..b9d751e
+--- /dev/null
++++ b/src/lib/krb5/os/checkhost.h
+@@ -0,0 +1,39 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/*
++ * Copyright 2014 Red Hat, Inc. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ *
++ * 2. Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
++ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
++ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
++ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
++ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
++ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
++ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/*
++ * Certificate subjectAltName check prototypes.
++ */
++
++#ifndef KRB5_LIBOS_CHECKHOST_PROTO__
++#define KRB5_LIBOS_CHECKHOST_PROTO__
++
++krb5_boolean k5_check_cert_servername(X509 *x, const char *expected);
++krb5_boolean k5_check_cert_address(X509 *x, const char *expected);
++
++#endif /* KRB5_LIBOS_CHECKHOST_PROTO__ */
+diff --git a/src/lib/krb5/os/deps b/src/lib/krb5/os/deps
+index 3dd6d46..d56ff30 100644
+--- a/src/lib/krb5/os/deps
++++ b/src/lib/krb5/os/deps
+@@ -49,6 +49,17 @@ changepw.so changepw.po $(OUTPRE)changepw.$(OBJEXT): \
+ $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ changepw.c os-proto.h
++checkhost.so checkhost.po $(OUTPRE)checkhost.$(OBJEXT): \
++ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
++ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
++ $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
++ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
++ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
++ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
++ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/k5-utf8.h \
++ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
++ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
++ $(top_srcdir)/include/socket-utils.h checkhost.c checkhost.h
+ dnsglue.so dnsglue.po $(OUTPRE)dnsglue.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
+@@ -418,7 +429,8 @@ sendto_kdc.so sendto_kdc.po $(OUTPRE)sendto_kdc.$(OBJEXT): \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/locate_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+- $(top_srcdir)/include/socket-utils.h os-proto.h sendto_kdc.c
++ $(top_srcdir)/include/socket-utils.h checkhost.h os-proto.h \
++ sendto_kdc.c
+ sn2princ.so sn2princ.po $(OUTPRE)sn2princ.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
+index 4bd8698..f083c0f 100644
+--- a/src/lib/krb5/os/sendto_kdc.c
++++ b/src/lib/krb5/os/sendto_kdc.c
+@@ -80,6 +80,7 @@
+ #include <openssl/x509.h>
+ #include <openssl/x509v3.h>
+ #include <dirent.h>
++#include "checkhost.h"
+ #endif
+
+ #define MAX_PASS 3
+@@ -148,6 +149,7 @@ struct conn_state {
+ krb5_boolean defer;
+ struct {
+ const char *uri_path;
++ const char *servername;
+ char *https_request;
+ #ifdef PROXY_TLS_IMPL_OPENSSL
+ SSL *ssl;
+@@ -158,6 +160,7 @@ struct conn_state {
+ #ifdef PROXY_TLS_IMPL_OPENSSL
+ /* Extra-data identifier, used to pass context into the verify callback. */
+ static int ssl_ex_context_id = -1;
++static int ssl_ex_conn_id = -1;
+ #endif
+
+ void
+@@ -169,6 +172,7 @@ k5_sendto_kdc_initialize(void)
+ OpenSSL_add_all_algorithms();
+
+ ssl_ex_context_id = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
++ ssl_ex_conn_id = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ #endif
+ }
+
+@@ -635,7 +639,8 @@ set_transport_message(struct conn_state *state, const krb5_data *realm,
+ static krb5_error_code
+ add_connection(struct conn_state **conns, k5_transport transport,
+ krb5_boolean defer, struct addrinfo *ai, size_t server_index,
+- const krb5_data *realm, const char *uri_path, char **udpbufp)
++ const krb5_data *realm, const char *hostname,
++ const char *uri_path, char **udpbufp)
+ {
+ struct conn_state *state, **tailptr;
+
+@@ -661,6 +666,7 @@ add_connection(struct conn_state **conns, k5_transport transport,
+ state->service_write = service_https_write;
+ state->service_read = service_https_read;
+ state->http.uri_path = uri_path;
++ state->http.servername = hostname;
+ } else {
+ state->service_connect = NULL;
+ state->service_write = NULL;
+@@ -760,8 +766,8 @@ resolve_server(krb5_context context, const krb5_data *realm,
+ ai.ai_addrlen = entry->addrlen;
+ ai.ai_addr = (struct sockaddr *)&entry->addr;
+ defer = (entry->transport != transport);
+- return add_connection(conns, entry->transport, defer, &ai, ind,
+- realm, entry->uri_path, udpbufp);
++ return add_connection(conns, entry->transport, defer, &ai, ind, realm,
++ NULL, entry->uri_path, udpbufp);
+ }
+
+ /* If the entry has a specified transport, use it. */
+@@ -787,7 +793,7 @@ resolve_server(krb5_context context, const krb5_data *realm,
+ retval = 0;
+ for (a = addrs; a != 0 && retval == 0; a = a->ai_next) {
+ retval = add_connection(conns, transport, FALSE, a, ind, realm,
+- entry->uri_path, udpbufp);
++ entry->hostname, entry->uri_path, udpbufp);
+ }
+
+ /* For TCP_OR_UDP entries, add each address again with the non-preferred
+@@ -797,7 +803,7 @@ resolve_server(krb5_context context, const krb5_data *realm,
+ for (a = addrs; a != 0 && retval == 0; a = a->ai_next) {
+ a->ai_socktype = socktype_for_transport(transport);
+ retval = add_connection(conns, transport, TRUE, a, ind, realm,
+- entry->uri_path, udpbufp);
++ entry->hostname, entry->uri_path, udpbufp);
+ }
+ }
+ freeaddrinfo(addrs);
+@@ -1260,6 +1266,20 @@ cleanup:
+ return err;
+ }
+
++static krb5_boolean
++ssl_check_name_or_ip(X509 *x, const char *expected_name)
++{
++ struct in_addr in;
++ struct in6_addr in6;
++
++ if (inet_aton(expected_name, &in) != 0 ||
++ inet_pton(AF_INET6, expected_name, &in6) != 0) {
++ return k5_check_cert_address(x, expected_name);
++ } else {
++ return k5_check_cert_servername(x, expected_name);
++ }
++}
++
+ static int
+ ssl_verify_callback(int preverify_ok, X509_STORE_CTX *store_ctx)
+ {
+@@ -1268,12 +1288,14 @@ ssl_verify_callback(int preverify_ok, X509_STORE_CTX *store_ctx)
+ BIO *bio;
+ krb5_context context;
+ int err, depth;
+- const char *cert = NULL, *errstr;
++ struct conn_state *conn = NULL;
++ const char *cert = NULL, *errstr, *expected_name;
+ size_t count;
+
+ ssl = X509_STORE_CTX_get_ex_data(store_ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+ context = SSL_get_ex_data(ssl, ssl_ex_context_id);
++ conn = SSL_get_ex_data(ssl, ssl_ex_conn_id);
+ /* We do have the peer's cert, right? */
+ x = X509_STORE_CTX_get_current_cert(store_ctx);
+ if (x == NULL) {
+@@ -1299,8 +1321,19 @@ ssl_verify_callback(int preverify_ok, X509_STORE_CTX *store_ctx)
+ }
+ return 0;
+ }
+- /* All done. */
+- return 1;
++ /* If we're not looking at the peer, we're done and everything's ok. */
++ if (depth != 0)
++ return 1;
++ /* Check if the name we expect to find is in the certificate. */
++ expected_name = conn->http.servername;
++ if (ssl_check_name_or_ip(x, expected_name)) {
++ TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MATCH(context, expected_name);
++ return 1;
++ } else {
++ TRACE_SENDTO_KDC_HTTPS_SERVER_NAME_MISMATCH(context, expected_name);
++ }
++ /* The name didn't match. */
++ return 0;
+ }
+
+ /*
+@@ -1317,7 +1350,7 @@ setup_ssl(krb5_context context, const krb5_data *realm,
+ SSL_CTX *ctx = NULL;
+ SSL *ssl = NULL;
+
+- if (ssl_ex_context_id == -1)
++ if (ssl_ex_context_id == -1 || ssl_ex_conn_id == -1)
+ goto kill_conn;
+
+ /* Do general SSL library setup. */
+@@ -1339,6 +1372,8 @@ setup_ssl(krb5_context context, const krb5_data *realm,
+
+ if (!SSL_set_ex_data(ssl, ssl_ex_context_id, context))
+ goto kill_conn;
++ if (!SSL_set_ex_data(ssl, ssl_ex_conn_id, conn))
++ goto kill_conn;
+
+ /* Tell the SSL library about the socket. */
+ if (!SSL_set_fd(ssl, conn->fd))
+--
+2.1.0
+