Add certificate verification against system trust store
Verify the certificate from the peer against the system’s default trusted CAs. If certificate fails the verification a fallback to use the certificate cache is used. The certificate cache is used to give the user the option to add exceptions for invalid certificates. For example; self-signed certificates etc.
This commit is contained in:
parent
2a955dbf84
commit
18287bdacf
111
tcp.c
111
tcp.c
@ -589,6 +589,97 @@ bail:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback during handshake to verify peer certificate
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
cert_verify_callback(gnutls_session_t session)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
int type;
|
||||||
|
unsigned int status;
|
||||||
|
gnutls_x509_crt_t cert;
|
||||||
|
const gnutls_datum_t *cert_list;
|
||||||
|
unsigned int cert_list_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* verify certificate against system trust store
|
||||||
|
*/
|
||||||
|
rv = gnutls_certificate_verify_peers2(session, &status);
|
||||||
|
if (rv == GNUTLS_E_SUCCESS)
|
||||||
|
{
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
/* get list of certificates */
|
||||||
|
cert_list = NULL;
|
||||||
|
cert_list_size = 0;
|
||||||
|
|
||||||
|
type = gnutls_certificate_type_get(session);
|
||||||
|
if (type == GNUTLS_CRT_X509) {
|
||||||
|
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cert_list_size > 0)
|
||||||
|
{
|
||||||
|
/* validate hostname */
|
||||||
|
gnutls_x509_crt_init(&cert);
|
||||||
|
gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
|
||||||
|
if (gnutls_x509_crt_check_hostname(cert, g_last_server_name) != 0)
|
||||||
|
{
|
||||||
|
logger(Core, Notice, "%s(), certificate is valid", __func__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger(Core, Error, "%s(), certificate hostname mismatch", __func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger(Core, Error, "%s(), failed to verify certificate hostname", __func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger(Core, Debug, "%s(), certificate status flags: %x", __func__, status);
|
||||||
|
|
||||||
|
if (status&GNUTLS_CERT_INVALID)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "%s(), certificate is invalid", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status&GNUTLS_CERT_SIGNER_NOT_FOUND)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "%s(), certificate signed by unknown issuer", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status&GNUTLS_CERT_SIGNATURE_FAILURE)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "%s(), certificate has an invalid signature", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status&GNUTLS_CERT_REVOKED)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "%s(), certificate is revoked", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status&GNUTLS_CERT_EXPIRED)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "%s(), certificate has expired", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status&GNUTLS_CERT_INSECURE_ALGORITHM)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "%s(), certificate uses an insecure algorithm", __func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use local store as fallback
|
||||||
|
*/
|
||||||
|
return check_cert(session);
|
||||||
|
}
|
||||||
|
|
||||||
/* Establish a SSL/TLS 1.0 connection */
|
/* Establish a SSL/TLS 1.0 connection */
|
||||||
RD_BOOL
|
RD_BOOL
|
||||||
tcp_tls_connect(void)
|
tcp_tls_connect(void)
|
||||||
@ -616,6 +707,8 @@ tcp_tls_connect(void)
|
|||||||
CHECK(gnutls_priority_set_direct(g_tls_session, "NORMAL:%COMPAT", NULL));
|
CHECK(gnutls_priority_set_direct(g_tls_session, "NORMAL:%COMPAT", NULL));
|
||||||
CHECK(gnutls_certificate_allocate_credentials(&xcred));
|
CHECK(gnutls_certificate_allocate_credentials(&xcred));
|
||||||
CHECK(gnutls_credentials_set(g_tls_session, GNUTLS_CRD_CERTIFICATE, xcred));
|
CHECK(gnutls_credentials_set(g_tls_session, GNUTLS_CRD_CERTIFICATE, xcred));
|
||||||
|
CHECK(gnutls_certificate_set_x509_system_trust(xcred));
|
||||||
|
gnutls_certificate_set_verify_function(xcred, cert_verify_callback);
|
||||||
|
|
||||||
#if GNUTLS_VERSION_NUMBER >= 0x030109
|
#if GNUTLS_VERSION_NUMBER >= 0x030109
|
||||||
gnutls_transport_set_int(g_tls_session, g_sock);
|
gnutls_transport_set_int(g_tls_session, g_sock);
|
||||||
@ -632,8 +725,20 @@ tcp_tls_connect(void)
|
|||||||
err = gnutls_handshake(g_tls_session);
|
err = gnutls_handshake(g_tls_session);
|
||||||
} while (err < 0 && gnutls_error_is_fatal(err) == 0);
|
} while (err < 0 && gnutls_error_is_fatal(err) == 0);
|
||||||
|
|
||||||
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
||||||
|
if (err == GNUTLS_E_CERTIFICATE_ERROR)
|
||||||
|
{
|
||||||
|
logger(Core, Error, "%s(): Certificate error during TLS handshake", __func__);
|
||||||
|
|
||||||
|
/* TODO: Lookup if exit(1) is just plain wrong, its used here to breakout of
|
||||||
|
fallback code path for connection, eg. if TLS fails, a retry with plain
|
||||||
|
RDP is made.
|
||||||
|
*/
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
#if GNUTLS_VERSION_NUMBER >= 0x030406
|
#if GNUTLS_VERSION_NUMBER >= 0x030406
|
||||||
if (err == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR) {
|
if (err == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR) {
|
||||||
/* check certificate verification status */
|
/* check certificate verification status */
|
||||||
@ -655,12 +760,6 @@ tcp_tls_connect(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (check_cert(g_tls_session) != 0) goto fail;
|
|
||||||
if (check_cert(g_tls_session) != 0) {
|
|
||||||
fprintf(stdout, "%s: Failed to check certificate. Bailing out\n", __func__);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
Loading…
Reference in New Issue
Block a user