The callers were also changed to add the reason to error messages.
static bool
openssl_iostream_cert_match_name(struct ssl_iostream *ssl_io,
- const char *verify_name)
+ const char *verify_name, const char **reason_r)
{
- const char *reason;
-
- if (!ssl_iostream_has_valid_client_cert(ssl_io))
+ if (!ssl_iostream_has_valid_client_cert(ssl_io)) {
+ *reason_r = "Invalid certificate";
return FALSE;
+ }
- return openssl_cert_match_name(ssl_io->ssl, verify_name, &reason);
+ return openssl_cert_match_name(ssl_io->ssl, verify_name, reason_r);
}
static int openssl_iostream_handshake(struct ssl_iostream *ssl_io)
{
- const char *error = NULL;
+ const char *reason, *error = NULL;
int ret;
i_assert(!ssl_io->handshaked);
ssl_io->handshake_failed = TRUE;
}
} else if (ssl_io->connected_host != NULL && !ssl_io->handshake_failed) {
- if (!ssl_iostream_cert_match_name(ssl_io, ssl_io->connected_host)) {
+ if (!ssl_iostream_cert_match_name(ssl_io, ssl_io->connected_host, &reason)) {
openssl_iostream_set_error(ssl_io, t_strdup_printf(
- "SSL certificate doesn't match expected host name %s",
- ssl_io->connected_host));
+ "SSL certificate doesn't match expected host name %s: %s",
+ ssl_io->connected_host, reason));
ssl_io->handshake_failed = TRUE;
}
}
bool (*has_handshake_failed)(const struct ssl_iostream *ssl_io);
bool (*has_valid_client_cert)(const struct ssl_iostream *ssl_io);
bool (*has_broken_client_cert)(struct ssl_iostream *ssl_io);
- bool (*cert_match_name)(struct ssl_iostream *ssl_io, const char *name);
+ bool (*cert_match_name)(struct ssl_iostream *ssl_io, const char *name,
+ const char **reason_r);
const char *(*get_peer_name)(struct ssl_iostream *ssl_io);
const char *(*get_server_name)(struct ssl_iostream *ssl_io);
const char *(*get_compression)(struct ssl_iostream *ssl_io);
return ssl_vfuncs->has_broken_client_cert(ssl_io);
}
-bool ssl_iostream_cert_match_name(struct ssl_iostream *ssl_io, const char *name)
+bool ssl_iostream_cert_match_name(struct ssl_iostream *ssl_io, const char *name,
+ const char **reason_r)
{
- return ssl_vfuncs->cert_match_name(ssl_io, name);
+ return ssl_vfuncs->cert_match_name(ssl_io, name, reason_r);
}
int ssl_iostream_check_cert_validity(struct ssl_iostream *ssl_io,
const char *host, const char **error_r)
{
+ const char *reason;
+
if (!ssl_iostream_has_valid_client_cert(ssl_io)) {
if (!ssl_iostream_has_broken_client_cert(ssl_io))
*error_r = "SSL certificate not received";
*error_r = "Received invalid SSL certificate";
}
return -1;
- } else if (!ssl_iostream_cert_match_name(ssl_io, host)) {
+ } else if (!ssl_iostream_cert_match_name(ssl_io, host, &reason)) {
*error_r = t_strdup_printf(
- "SSL certificate doesn't match expected host name %s",
- host);
+ "SSL certificate doesn't match expected host name %s: %s",
+ host, reason);
return -1;
}
return 0;
bool ssl_iostream_has_broken_client_cert(struct ssl_iostream *ssl_io);
int ssl_iostream_check_cert_validity(struct ssl_iostream *ssl_io,
const char *host, const char **error_r);
-/* Returns TRUE if the given name matches the SSL stream's certificate. */
-bool ssl_iostream_cert_match_name(struct ssl_iostream *ssl_io, const char *name);
+/* Returns TRUE if the given name matches the SSL stream's certificate.
+ The returned reason is a human-readable string explaining what exactly
+ matched the name, or why nothing matched. Note that this function works
+ only if the certificate was valid - using it when certificate is invalid
+ will always return FALSE before even checking the hostname. */
+bool ssl_iostream_cert_match_name(struct ssl_iostream *ssl_io, const char *name,
+ const char **reason_r);
const char *ssl_iostream_get_peer_name(struct ssl_iostream *ssl_io);
const char *ssl_iostream_get_compression(struct ssl_iostream *ssl_io);
const char *ssl_iostream_get_server_name(struct ssl_iostream *ssl_io);