mirror of https://github.com/getdnsapi/getdns.git
Wrap hostname/certificate verification.
This removes the last OpenSSL items from stub.c.
This commit is contained in:
parent
fb73bcb77e
commit
1b0a09a23f
|
@ -34,7 +34,9 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/conf.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
@ -42,8 +44,35 @@
|
||||||
#include <openssl/opensslv.h>
|
#include <openssl/opensslv.h>
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "context.h"
|
||||||
|
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
|
|
||||||
|
static int _getdns_tls_verify_always_ok(int ok, X509_STORE_CTX *ctx)
|
||||||
|
{
|
||||||
|
# if defined(STUB_DEBUG) && STUB_DEBUG
|
||||||
|
char buf[8192];
|
||||||
|
X509 *cert;
|
||||||
|
int err;
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||||
|
err = X509_STORE_CTX_get_error(ctx);
|
||||||
|
depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||||
|
|
||||||
|
if (cert)
|
||||||
|
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
|
||||||
|
else
|
||||||
|
strcpy(buf, "<unknown>");
|
||||||
|
DEBUG_STUB("DEBUG Cert verify: depth=%d verify=%d err=%d subject=%s errorstr=%s\n", depth, ok, err, buf, X509_verify_cert_error_string(err));
|
||||||
|
# else /* defined(STUB_DEBUG) && STUB_DEBUG */
|
||||||
|
(void)ok;
|
||||||
|
(void)ctx;
|
||||||
|
# endif /* #else defined(STUB_DEBUG) && STUB_DEBUG */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static _getdns_tls_x509* _getdns_tls_x509_new(X509* cert)
|
static _getdns_tls_x509* _getdns_tls_x509_new(X509* cert)
|
||||||
{
|
{
|
||||||
_getdns_tls_x509* res;
|
_getdns_tls_x509* res;
|
||||||
|
@ -394,6 +423,76 @@ getdns_return_t _getdns_tls_connection_is_session_reused(_getdns_tls_connection*
|
||||||
return GETDNS_RETURN_TLS_CONNECTION_FRESH;
|
return GETDNS_RETURN_TLS_CONNECTION_FRESH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getdns_return_t _getdns_tls_connection_setup_hostname_auth(_getdns_tls_connection* conn, const char* auth_name)
|
||||||
|
{
|
||||||
|
if (!conn || !conn->ssl || !auth_name)
|
||||||
|
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
SSL_set_tlsext_host_name(conn->ssl, auth_name);
|
||||||
|
/* Set up native OpenSSL hostname verification */
|
||||||
|
X509_VERIFY_PARAM *param;
|
||||||
|
param = SSL_get0_param(conn->ssl);
|
||||||
|
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||||
|
X509_VERIFY_PARAM_set1_host(param, auth_name, 0);
|
||||||
|
return GETDNS_RETURN_GOOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* conn, const char* auth_name, const sha256_pin_t* pinset)
|
||||||
|
{
|
||||||
|
if (!conn || !conn->ssl || !auth_name)
|
||||||
|
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
int osr = SSL_dane_enable(conn->ssl, *auth_name ? auth_name : NULL);
|
||||||
|
(void) osr;
|
||||||
|
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_enable(\"%s\") -> %d\n"
|
||||||
|
, STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name, osr);
|
||||||
|
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok);
|
||||||
|
const sha256_pin_t *pin_p;
|
||||||
|
size_t n_pins = 0;
|
||||||
|
for (pin_p = pinset; pin_p; pin_p = pin_p->next) {
|
||||||
|
osr = SSL_dane_tlsa_add(conn->ssl, 2, 1, 1,
|
||||||
|
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
|
||||||
|
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n"
|
||||||
|
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
|
||||||
|
if (osr > 0)
|
||||||
|
++n_pins;
|
||||||
|
osr = SSL_dane_tlsa_add(conn->ssl, 3, 1, 1,
|
||||||
|
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
|
||||||
|
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n"
|
||||||
|
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
|
||||||
|
if (osr > 0)
|
||||||
|
++n_pins;
|
||||||
|
}
|
||||||
|
return GETDNS_RETURN_GOOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
getdns_return_t _getdns_tls_connection_verify(_getdns_tls_connection* conn, long* errnum, const char** errmsg)
|
||||||
|
{
|
||||||
|
if (!conn || !conn->ssl)
|
||||||
|
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
long verify_result = SSL_get_verify_result(conn->ssl);
|
||||||
|
switch (verify_result) {
|
||||||
|
case X509_V_OK:
|
||||||
|
return GETDNS_RETURN_GOOD;
|
||||||
|
|
||||||
|
case X509_V_ERR_DANE_NO_MATCH:
|
||||||
|
if (errnum)
|
||||||
|
*errnum = 0;
|
||||||
|
if (errmsg)
|
||||||
|
*errmsg = "Pinset validation failure";
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (errnum)
|
||||||
|
*errnum = verify_result;
|
||||||
|
if (errmsg)
|
||||||
|
*errmsg = X509_verify_cert_error_string(verify_result);
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getdns_return_t _getdns_tls_connection_read(_getdns_tls_connection* conn, uint8_t* buf, size_t to_read, size_t* read)
|
getdns_return_t _getdns_tls_connection_read(_getdns_tls_connection* conn, uint8_t* buf, size_t to_read, size_t* read)
|
||||||
{
|
{
|
||||||
int sread;
|
int sread;
|
||||||
|
|
127
src/stub.c
127
src/stub.c
|
@ -39,9 +39,6 @@
|
||||||
#define INTERCEPT_COM_DS 0
|
#define INTERCEPT_COM_DS 0
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include <openssl/err.h>
|
|
||||||
#include <openssl/conf.h>
|
|
||||||
#include <openssl/x509v3.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "stub.h"
|
#include "stub.h"
|
||||||
#include "gldns/gbuffer.h"
|
#include "gldns/gbuffer.h"
|
||||||
|
@ -826,31 +823,6 @@ tls_requested(getdns_network_req *netreq)
|
||||||
1 : 0;
|
1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
_getdns_tls_verify_always_ok(int ok, X509_STORE_CTX *ctx)
|
|
||||||
{
|
|
||||||
# if defined(STUB_DEBUG) && STUB_DEBUG
|
|
||||||
char buf[8192];
|
|
||||||
X509 *cert;
|
|
||||||
int err;
|
|
||||||
int depth;
|
|
||||||
|
|
||||||
cert = X509_STORE_CTX_get_current_cert(ctx);
|
|
||||||
err = X509_STORE_CTX_get_error(ctx);
|
|
||||||
depth = X509_STORE_CTX_get_error_depth(ctx);
|
|
||||||
|
|
||||||
if (cert)
|
|
||||||
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
|
|
||||||
else
|
|
||||||
strcpy(buf, "<unknown>");
|
|
||||||
DEBUG_STUB("DEBUG Cert verify: depth=%d verify=%d err=%d subject=%s errorstr=%s\n", depth, ok, err, buf, X509_verify_cert_error_string(err));
|
|
||||||
# else /* defined(STUB_DEBUG) && STUB_DEBUG */
|
|
||||||
(void)ok;
|
|
||||||
(void)ctx;
|
|
||||||
# endif /* #else defined(STUB_DEBUG) && STUB_DEBUG */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _getdns_tls_connection*
|
static _getdns_tls_connection*
|
||||||
tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
|
tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
|
||||||
{
|
{
|
||||||
|
@ -881,12 +853,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
|
||||||
/*Request certificate for the auth_name*/
|
/*Request certificate for the auth_name*/
|
||||||
DEBUG_STUB("%s %-35s: Hostname verification requested for: %s\n",
|
DEBUG_STUB("%s %-35s: Hostname verification requested for: %s\n",
|
||||||
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name);
|
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name);
|
||||||
SSL_set_tlsext_host_name(tls->ssl, upstream->tls_auth_name);
|
_getdns_tls_connection_setup_hostname_auth(tls, upstream->tls_auth_name);
|
||||||
/* Set up native OpenSSL hostname verification */
|
|
||||||
X509_VERIFY_PARAM *param;
|
|
||||||
param = SSL_get0_param(tls->ssl);
|
|
||||||
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
|
||||||
X509_VERIFY_PARAM_set1_host(param, upstream->tls_auth_name, 0);
|
|
||||||
/* Allow fallback to opportunistic if settings permit it*/
|
/* Allow fallback to opportunistic if settings permit it*/
|
||||||
if (dnsreq->netreqs[0]->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED)
|
if (dnsreq->netreqs[0]->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED)
|
||||||
upstream->tls_fallback_ok = 1;
|
upstream->tls_fallback_ok = 1;
|
||||||
|
@ -926,32 +893,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
|
||||||
__FUNC__);
|
__FUNC__);
|
||||||
}
|
}
|
||||||
|
|
||||||
int osr;
|
_getdns_tls_connection_set_host_pinset(tls, upstream->tls_auth_name, upstream->tls_pubkey_pinset);
|
||||||
# if defined(STUB_DEBUG) && STUB_DEBUG
|
|
||||||
osr =
|
|
||||||
# else
|
|
||||||
(void)
|
|
||||||
# endif
|
|
||||||
SSL_dane_enable(tls->ssl, *upstream->tls_auth_name ? upstream->tls_auth_name : NULL);
|
|
||||||
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_enable(\"%s\") -> %d\n"
|
|
||||||
, STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name, osr);
|
|
||||||
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok);
|
|
||||||
sha256_pin_t *pin_p;
|
|
||||||
size_t n_pins = 0;
|
|
||||||
for (pin_p = upstream->tls_pubkey_pinset; pin_p; pin_p = pin_p->next) {
|
|
||||||
osr = SSL_dane_tlsa_add(tls->ssl, 2, 1, 1,
|
|
||||||
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
|
|
||||||
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n"
|
|
||||||
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
|
|
||||||
if (osr > 0)
|
|
||||||
++n_pins;
|
|
||||||
osr = SSL_dane_tlsa_add(tls->ssl, 3, 1, 1,
|
|
||||||
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
|
|
||||||
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n"
|
|
||||||
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
|
|
||||||
if (osr > 0)
|
|
||||||
++n_pins;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Session resumption. There are trade-offs here. Want to do it when
|
/* Session resumption. There are trade-offs here. Want to do it when
|
||||||
possible only if we have the right type of connection. Note a change
|
possible only if we have the right type of connection. Note a change
|
||||||
|
@ -1005,12 +947,9 @@ tls_do_handshake(getdns_upstream *upstream)
|
||||||
upstream->tls_auth_state = upstream->last_tls_auth_state;
|
upstream->tls_auth_state = upstream->last_tls_auth_state;
|
||||||
|
|
||||||
else if (upstream->tls_pubkey_pinset || upstream->tls_auth_name[0]) {
|
else if (upstream->tls_pubkey_pinset || upstream->tls_auth_name[0]) {
|
||||||
X509 *peer_cert = SSL_get_peer_certificate(upstream->tls_obj->ssl);
|
_getdns_tls_x509* peer_cert = _getdns_tls_connection_get_peer_certificate(upstream->tls_obj);
|
||||||
long verify_result = SSL_get_verify_result(upstream->tls_obj->ssl);
|
|
||||||
|
|
||||||
upstream->tls_auth_state = peer_cert && verify_result == X509_V_OK
|
if (!peer_cert) {
|
||||||
? GETDNS_AUTH_OK : GETDNS_AUTH_FAILED;
|
|
||||||
if (!peer_cert)
|
|
||||||
_getdns_upstream_log(upstream,
|
_getdns_upstream_log(upstream,
|
||||||
GETDNS_LOG_UPSTREAM_STATS,
|
GETDNS_LOG_UPSTREAM_STATS,
|
||||||
( upstream->tls_fallback_ok
|
( upstream->tls_fallback_ok
|
||||||
|
@ -1021,38 +960,42 @@ tls_do_handshake(getdns_upstream *upstream)
|
||||||
( upstream->tls_fallback_ok
|
( upstream->tls_fallback_ok
|
||||||
? "Tolerated because of Opportunistic profile"
|
? "Tolerated because of Opportunistic profile"
|
||||||
: "*Failure*" ));
|
: "*Failure*" ));
|
||||||
|
upstream->tls_auth_state = GETDNS_AUTH_FAILED;
|
||||||
|
} else {
|
||||||
|
long verify_errno;
|
||||||
|
const char* verify_errmsg;
|
||||||
|
|
||||||
/* Since we don't have DANE validation yet, DANE validation
|
if (!_getdns_tls_connection_verify(upstream->tls_obj, &verify_errno, &verify_errmsg)) {
|
||||||
* failures are always pinset validation failures
|
upstream->tls_auth_state = GETDNS_AUTH_OK;
|
||||||
*/
|
if (verify_errno != 0) {
|
||||||
else if (verify_result == X509_V_ERR_DANE_NO_MATCH)
|
_getdns_upstream_log(upstream,
|
||||||
_getdns_upstream_log(upstream,
|
GETDNS_LOG_UPSTREAM_STATS,
|
||||||
GETDNS_LOG_UPSTREAM_STATS,
|
( upstream->tls_fallback_ok
|
||||||
( upstream->tls_fallback_ok
|
? GETDNS_LOG_INFO : GETDNS_LOG_ERR), "%-40s : Verify failed : TLS - %s - "
|
||||||
? GETDNS_LOG_INFO : GETDNS_LOG_ERR),
|
"(%d) \"%s\"\n", upstream->addr_str,
|
||||||
"%-40s : Verify failed : TLS - %s - "
|
( upstream->tls_fallback_ok
|
||||||
"Pinset validation failure\n", upstream->addr_str,
|
? "Tolerated because of Opportunistic profile"
|
||||||
( upstream->tls_fallback_ok
|
: "*Failure*" ),
|
||||||
? "Tolerated because of Opportunistic profile"
|
verify_errno, verify_errmsg);
|
||||||
: "*Failure*" ));
|
} else {
|
||||||
else if (verify_result != X509_V_OK)
|
_getdns_upstream_log(upstream,
|
||||||
_getdns_upstream_log(upstream,
|
GETDNS_LOG_UPSTREAM_STATS,
|
||||||
GETDNS_LOG_UPSTREAM_STATS,
|
( upstream->tls_fallback_ok
|
||||||
( upstream->tls_fallback_ok
|
? GETDNS_LOG_INFO : GETDNS_LOG_ERR), "%-40s : Verify failed : TLS - %s - "
|
||||||
? GETDNS_LOG_INFO : GETDNS_LOG_ERR),
|
"%s\n", upstream->addr_str,
|
||||||
"%-40s : Verify failed : TLS - %s - "
|
( upstream->tls_fallback_ok
|
||||||
"(%d) \"%s\"\n", upstream->addr_str,
|
? "Tolerated because of Opportunistic profile"
|
||||||
( upstream->tls_fallback_ok
|
: "*Failure*" ),
|
||||||
? "Tolerated because of Opportunistic profile"
|
verify_errno, verify_errmsg);
|
||||||
: "*Failure*" ), verify_result,
|
}
|
||||||
X509_verify_cert_error_string(verify_result));
|
} else {
|
||||||
else
|
|
||||||
_getdns_upstream_log(upstream,
|
_getdns_upstream_log(upstream,
|
||||||
GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG,
|
GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG,
|
||||||
"%-40s : Verify passed : TLS\n",
|
"%-40s : Verify passed : TLS\n",
|
||||||
upstream->addr_str);
|
upstream->addr_str);
|
||||||
|
}
|
||||||
X509_free(peer_cert);
|
_getdns_tls_x509_free(peer_cert);
|
||||||
|
}
|
||||||
if (upstream->tls_auth_state == GETDNS_AUTH_FAILED
|
if (upstream->tls_auth_state == GETDNS_AUTH_FAILED
|
||||||
&& !upstream->tls_fallback_ok)
|
&& !upstream->tls_fallback_ok)
|
||||||
return STUB_SETUP_ERROR;
|
return STUB_SETUP_ERROR;
|
||||||
|
|
36
src/tls.h
36
src/tls.h
|
@ -38,6 +38,10 @@
|
||||||
|
|
||||||
#include "tls-internal.h"
|
#include "tls-internal.h"
|
||||||
|
|
||||||
|
/* Forward declare type. */
|
||||||
|
struct sha256_pin;
|
||||||
|
typedef struct sha256_pin sha256_pin_t;
|
||||||
|
|
||||||
/* Additional return codes required by TLS abstraction. Internal use only. */
|
/* Additional return codes required by TLS abstraction. Internal use only. */
|
||||||
#define GETDNS_RETURN_TLS_WANT_READ ((getdns_return_t) 420)
|
#define GETDNS_RETURN_TLS_WANT_READ ((getdns_return_t) 420)
|
||||||
#define GETDNS_RETURN_TLS_WANT_WRITE ((getdns_return_t) 421)
|
#define GETDNS_RETURN_TLS_WANT_WRITE ((getdns_return_t) 421)
|
||||||
|
@ -100,6 +104,38 @@ _getdns_tls_x509* _getdns_tls_connection_get_peer_certificate(_getdns_tls_connec
|
||||||
*/
|
*/
|
||||||
getdns_return_t _getdns_tls_connection_is_session_reused(_getdns_tls_connection* conn);
|
getdns_return_t _getdns_tls_connection_is_session_reused(_getdns_tls_connection* conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up host name verification.
|
||||||
|
*
|
||||||
|
* @param conn the connection.
|
||||||
|
* @param auth_name the hostname.
|
||||||
|
* @return GETDNS_RETURN_GOOD if all OK.
|
||||||
|
* @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL.
|
||||||
|
*/
|
||||||
|
getdns_return_t _getdns_tls_connection_setup_hostname_auth(_getdns_tls_connection* conn, const char* auth_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set host pinset.
|
||||||
|
*
|
||||||
|
* @param conn the connection.
|
||||||
|
* @param auth_name the hostname.
|
||||||
|
* @return GETDNS_RETURN_GOOD if all OK.
|
||||||
|
* @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL.
|
||||||
|
*/
|
||||||
|
getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* conn, const char* auth_name, const sha256_pin_t* pinset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get result of certificate verification.
|
||||||
|
*
|
||||||
|
* @param conn the connection.
|
||||||
|
* @param errno failure error number.
|
||||||
|
* @param errmsg failure error message.
|
||||||
|
* @return GETDNS_RETURN_GOOD if all OK.
|
||||||
|
* @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL.
|
||||||
|
* @return GETDNS_RETURN_GENERIC_ERROR if verification failed.
|
||||||
|
*/
|
||||||
|
getdns_return_t _getdns_tls_connection_verify(_getdns_tls_connection* conn, long* errnum, const char** errmsg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read from TLS.
|
* Read from TLS.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue