Access ssl->hostname through abstractions
New abstractions to access ssl->hostname:
mbedtls_ssl_has_set_hostname_been_called() (only implemented approximatively
for now), mbedtls_ssl_get_hostname_pointer(), mbedtls_ssl_free_hostname().
Only access ssl->hostname directly in these functions and in
mbedtls_ssl_set_hostname().
Use these abstractions to access the hostname with the opportunity for
extra checks in mbedtls_ssl_verify_certificate().
No behavior change except for a new log message.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/library/ssl_client.c b/library/ssl_client.c
index 345e608..0bd00cd 100644
--- a/library/ssl_client.c
+++ b/library/ssl_client.c
@@ -29,19 +29,20 @@
size_t *olen)
{
unsigned char *p = buf;
+ const char *hostname = mbedtls_ssl_get_hostname_pointer(ssl);
size_t hostname_len;
*olen = 0;
- if (ssl->hostname == NULL) {
+ if (hostname == NULL) {
return 0;
}
MBEDTLS_SSL_DEBUG_MSG(3,
("client hello, adding server name extension: %s",
- ssl->hostname));
+ hostname));
- hostname_len = strlen(ssl->hostname);
+ hostname_len = strlen(hostname);
MBEDTLS_SSL_CHK_BUF_PTR(p, end, hostname_len + 9);
@@ -85,7 +86,7 @@
MBEDTLS_PUT_UINT16_BE(hostname_len, p, 0);
p += 2;
- memcpy(p, ssl->hostname, hostname_len);
+ memcpy(p, hostname, hostname_len);
*olen = hostname_len + 9;
@@ -881,13 +882,14 @@
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && \
defined(MBEDTLS_SSL_SESSION_TICKETS) && \
defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+ const char *context_hostname = mbedtls_ssl_get_hostname_pointer(ssl);
if (ssl->tls_version == MBEDTLS_SSL_VERSION_TLS1_3 &&
ssl->handshake->resume) {
- int hostname_mismatch = ssl->hostname != NULL ||
+ int hostname_mismatch = context_hostname != NULL ||
session_negotiate->hostname != NULL;
- if (ssl->hostname != NULL && session_negotiate->hostname != NULL) {
+ if (context_hostname != NULL && session_negotiate->hostname != NULL) {
hostname_mismatch = strcmp(
- ssl->hostname, session_negotiate->hostname) != 0;
+ context_hostname, session_negotiate->hostname) != 0;
}
if (hostname_mismatch) {
@@ -898,7 +900,7 @@
}
} else {
return mbedtls_ssl_session_set_hostname(session_negotiate,
- ssl->hostname);
+ context_hostname);
}
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 &&
MBEDTLS_SSL_SESSION_TICKETS &&
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index 7495ae3..37d26b4 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -2899,6 +2899,18 @@
unsigned char *buf, unsigned char *end);
#endif /* MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED */
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+/** Get the host name from the SSL context.
+ *
+ * \param[in] ssl SSL context
+ *
+ * \return The \p hostname pointer from the SSL context.
+ * \c NULL if mbedtls_ssl_set_hostname() has never been called on
+ * \p ssl or if it was last called with \p NULL.
+ */
+const char *mbedtls_ssl_get_hostname_pointer(const mbedtls_ssl_context *ssl);
+#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
+
#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && \
defined(MBEDTLS_SSL_SESSION_TICKETS) && \
defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && \
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index c773365..c3b7497 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -2757,6 +2757,46 @@
}
#if defined(MBEDTLS_X509_CRT_PARSE_C)
+
+#if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
+/** Whether mbedtls_ssl_set_hostname() has been called.
+ *
+ * \param[in] ssl SSL context
+ *
+ * \return \c 1 if mbedtls_ssl_set_hostname() has been called on \p ssl
+ * (including `mbedtls_ssl_set_hostname(ssl, NULL)`),
+ * otherwise \c 0.
+ */
+static int mbedtls_ssl_has_set_hostname_been_called(
+ const mbedtls_ssl_context *ssl)
+{
+ /* We can't tell the difference between the case where
+ * mbedtls_ssl_set_hostname() has not been called at all, and
+ * the case where it was last called with NULL. For the time
+ * being, we assume the latter, i.e. we behave as if there had
+ * been an implicit call to mbedtls_ssl_set_hostname(ssl, NULL). */
+ return ssl->hostname != NULL;
+}
+#endif
+
+/* Micro-optimization: don't export this function if it isn't needed outside
+ * of this source file. */
+#if !defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+static
+#endif
+const char *mbedtls_ssl_get_hostname_pointer(const mbedtls_ssl_context *ssl)
+{
+ return ssl->hostname;
+}
+
+static void mbedtls_ssl_free_hostname(mbedtls_ssl_context *ssl)
+{
+ if (ssl->hostname != NULL) {
+ mbedtls_zeroize_and_free(ssl->hostname, strlen(ssl->hostname));
+ }
+ ssl->hostname = NULL;
+}
+
int mbedtls_ssl_set_hostname(mbedtls_ssl_context *ssl, const char *hostname)
{
/* Initialize to suppress unnecessary compiler warning */
@@ -2774,10 +2814,7 @@
/* Now it's clear that we will overwrite the old hostname,
* so we can free it safely */
-
- if (ssl->hostname != NULL) {
- mbedtls_zeroize_and_free(ssl->hostname, strlen(ssl->hostname));
- }
+ mbedtls_ssl_free_hostname(ssl);
/* Passing NULL as hostname shall clear the old one */
@@ -5571,9 +5608,7 @@
}
#if defined(MBEDTLS_X509_CRT_PARSE_C)
- if (ssl->hostname != NULL) {
- mbedtls_zeroize_and_free(ssl->hostname, strlen(ssl->hostname));
- }
+ mbedtls_ssl_free_hostname(ssl);
#endif
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C)
@@ -9784,6 +9819,21 @@
return ret;
}
+static int get_hostname_for_verification(mbedtls_ssl_context *ssl,
+ const char **hostname)
+{
+ if (!mbedtls_ssl_has_set_hostname_been_called(ssl)) {
+ MBEDTLS_SSL_DEBUG_MSG(1, ("Certificate verification without having set hostname"));
+ }
+
+ *hostname = mbedtls_ssl_get_hostname_pointer(ssl);
+ if (*hostname == NULL) {
+ MBEDTLS_SSL_DEBUG_MSG(2, ("Certificate verification without CN verification"));
+ }
+
+ return 0;
+}
+
int mbedtls_ssl_verify_certificate(mbedtls_ssl_context *ssl,
int authmode,
mbedtls_x509_crt *chain,
@@ -9809,7 +9859,13 @@
p_vrfy = ssl->conf->p_vrfy;
}
- int ret = 0;
+ const char *hostname = "";
+ int ret = get_hostname_for_verification(ssl, &hostname);
+ if (ret != 0) {
+ MBEDTLS_SSL_DEBUG_RET(1, "get_hostname_for_verification", ret);
+ return ret;
+ }
+
int have_ca_chain_or_callback = 0;
#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
if (ssl->conf->f_ca_cb != NULL) {
@@ -9822,7 +9878,7 @@
ssl->conf->f_ca_cb,
ssl->conf->p_ca_cb,
ssl->conf->cert_profile,
- ssl->hostname,
+ hostname,
&ssl->session_negotiate->verify_result,
f_vrfy, p_vrfy);
} else
@@ -9849,7 +9905,7 @@
chain,
ca_chain, ca_crl,
ssl->conf->cert_profile,
- ssl->hostname,
+ hostname,
&ssl->session_negotiate->verify_result,
f_vrfy, p_vrfy, rs_ctx);
}