Commit 6fcc1ee9 authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Completed the test and fixed a couple issues

parent b78f77a6
......@@ -403,6 +403,13 @@ int fd_cnx_getproto(struct cnxctx * conn)
return conn->cc_proto;
}
/* Set the hostname to check during handshake */
void fd_cnx_sethostname(struct cnxctx * conn, char * hn)
{
CHECK_PARAMS_DO( conn, return );
conn->cc_tls_para.cn = hn;
}
/* Return the TLS state of a connection */
int fd_cnx_getTLS(struct cnxctx * conn)
{
......@@ -768,6 +775,86 @@ int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void *
return 0;
}
/* Verify remote credentials after successful handshake (return 0 if OK, EINVAL otherwise) */
int fd_tls_verify_credentials(gnutls_session_t session, struct cnxctx * conn)
{
int ret, i;
const gnutls_datum_t *cert_list;
unsigned int cert_list_size;
gnutls_x509_crt_t cert;
time_t now;
/* First, use built-in verification */
CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, &ret), return EINVAL );
if (ret) {
if (TRACE_BOOL(INFO)) {
fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
if (ret & GNUTLS_CERT_INVALID)
fd_log_debug(" - The certificate is not trusted (unknown CA?)\n");
if (ret & GNUTLS_CERT_REVOKED)
fd_log_debug(" - The certificate has been revoked.\n");
if (ret & GNUTLS_CERT_SIGNER_NOT_FOUND)
fd_log_debug(" - The certificate hasn't got a known issuer.\n");
if (ret & GNUTLS_CERT_SIGNER_NOT_CA)
fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n");
if (ret & GNUTLS_CERT_INSECURE_ALGORITHM)
fd_log_debug(" - The certificate signature uses a weak algorithm.\n");
}
return EINVAL;
}
/* Code from http://www.gnu.org/software/gnutls/manual/gnutls.html#Verifying-peer_0027s-certificate */
if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
return EINVAL;
cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
if (cert_list == NULL)
return EINVAL;
now = time(NULL);
/* Check validity of all the certificates */
for (i = 0; i < cert_list_size; i++)
{
time_t deadline;
CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return EINVAL);
CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER), return EINVAL);
deadline = gnutls_x509_crt_get_expiration_time(cert);
if ((deadline != (time_t)-1) && (deadline < now)) {
if (TRACE_BOOL(INFO)) {
fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
fd_log_debug(" - The certificate %d in the chain is expired\n", i);
}
return EINVAL;
}
deadline = gnutls_x509_crt_get_activation_time(cert);
if ((deadline != (time_t)-1) && (deadline > now)) {
if (TRACE_BOOL(INFO)) {
fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
fd_log_debug(" - The certificate %d in the chain is not yet activated\n", i);
}
return EINVAL;
}
if ((i == 0) && (conn->cc_tls_para.cn)) {
if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) {
if (TRACE_BOOL(INFO)) {
fd_log_debug("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :\n", conn->cc_socket, conn->cc_remid, conn->cc_id);
fd_log_debug(" - The certificate hostname does not match '%s'\n", conn->cc_tls_para.cn);
}
return EINVAL;
}
}
gnutls_x509_crt_deinit (cert);
}
return 0;
}
/* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */
int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds)
{
......@@ -812,23 +899,7 @@ int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt
} );
/* Now verify the remote credentials are valid -- only simple test here */
CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL );
if (ret) {
if (TRACE_BOOL(INFO)) {
fd_log_debug("TLS: Remote certificate invalid on socket %d (%s) :\n", conn->cc_socket, conn->cc_id);
if (ret & GNUTLS_CERT_INVALID)
fd_log_debug(" - The certificate is not trusted (unknown CA?)\n");
if (ret & GNUTLS_CERT_REVOKED)
fd_log_debug(" - The certificate has been revoked.\n");
if (ret & GNUTLS_CERT_SIGNER_NOT_FOUND)
fd_log_debug(" - The certificate hasn't got a known issuer.\n");
if (ret & GNUTLS_CERT_SIGNER_NOT_CA)
fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n");
if (ret & GNUTLS_CERT_INSECURE_ALGORITHM)
fd_log_debug(" - The certificate signature uses a weak algorithm.\n");
}
return EINVAL;
}
CHECK_FCT( fd_tls_verify_credentials(conn->cc_tls_para.session, conn) );
}
/* Multi-stream TLS: handshake other streams as well */
......
......@@ -42,7 +42,7 @@
struct cnxctx {
char cc_id[60]; /* The name of this connection */
char cc_remid[60]; /* Id of remote peer */
int cc_socket; /* The socket object of the connection -- <=0 if no socket is created */
int cc_proto; /* IPPROTO_TCP or IPPROTO_SCTP */
......@@ -57,6 +57,7 @@ struct cnxctx {
/* If cc_tls == true */
struct {
char *cn; /* If not NULL, remote certif will be checked to match this Common Name */
int mode; /* GNUTLS_CLIENT / GNUTLS_SERVER */
gnutls_session_t session; /* Session object (stream #0 in case of SCTP) */
} cc_tls_para;
......@@ -79,6 +80,7 @@ struct cnxctx {
/* TLS */
int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session);
int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds);
int fd_tls_verify_credentials(gnutls_session_t session, struct cnxctx * conn);
/* TCP */
int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen );
......
......@@ -224,6 +224,7 @@ struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv);
struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen);
struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
int fd_cnx_start_clear(struct cnxctx * conn, int loop);
void fd_cnx_sethostname(struct cnxctx * conn, char * hn);
int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds);
char * fd_cnx_getid(struct cnxctx * conn);
int fd_cnx_getproto(struct cnxctx * conn);
......
......@@ -430,6 +430,8 @@ static void set_resume_callbacks(gnutls_session_t session, struct cnxctx * conn)
static void * handshake_resume_th(void * arg)
{
struct sctps_ctx * ctx = (struct sctps_ctx *) arg;
int resumed;
TRACE_ENTRY("%p", arg);
/* Set the thread name */
......@@ -442,16 +444,20 @@ static void * handshake_resume_th(void * arg)
TRACE_DEBUG(FULL, "Starting TLS resumed handshake on stream %hu", ctx->strid);
CHECK_GNUTLS_DO( gnutls_handshake( ctx->session ), return NULL);
resumed = gnutls_session_is_resumed(ctx->session);
if (!resumed) {
/* Check the credentials here also */
CHECK_FCT_DO( fd_tls_verify_credentials(ctx->session, ctx->parent), return NULL );
}
if (TRACE_BOOL(FULL)) {
int resumed = gnutls_session_is_resumed(ctx->session);
if (resumed) {
fd_log_debug("Session was resumed successfully on stream %hu (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
} else {
fd_log_debug("Session was NOT resumed (full handshake) on stream %hu (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
fd_log_debug("Session was NOT resumed on stream %hu (full handshake + verif) (conn: '%s')\n", ctx->strid, fd_cnx_getid(ctx->parent));
}
}
/* Finish */
/* Finished, OK */
return arg;
}
......
This diff is collapsed.
......@@ -64,6 +64,7 @@
/* Define the macro to fail a test with a message */
#define FAILTEST( message... ){ \
fprintf(stderr, ## message); \
TRACE_DEBUG(INFO, "Test failed"); \
exit(FAIL); \
}
......@@ -92,7 +93,7 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL;
}{ \
__typeof__ (_val) __ret = (_assert); \
if (__ret != (_val)) { \
FAILTEST( "%s:%d: %s == %lx != %lx\n", \
FAILTEST( "%s:%d: CHECK FAILED : %s == %lx != %lx\n", \
__FILE__, \
__LINE__, \
#_assert, \
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment