Skip to content

Commit

Permalink
1.12.0: [FEATURE, API Change] Certificate verification
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitri Tikhonov committed Aug 17, 2018
1 parent de1c35d commit 7f2bd84
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 17 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
2018-08-17

- 1.12.0
- [FEATURE, API Change] Add support for certificate verification

2018-08-16

- 1.11.1
Expand Down
32 changes: 30 additions & 2 deletions include/lsquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ extern "C" {
#endif

#define LSQUIC_MAJOR_VERSION 1
#define LSQUIC_MINOR_VERSION 11
#define LSQUIC_PATCH_VERSION 1
#define LSQUIC_MINOR_VERSION 12
#define LSQUIC_PATCH_VERSION 0

/**
* Engine flags:
Expand Down Expand Up @@ -496,6 +496,8 @@ struct lsquic_packout_mem_if
void (*pmi_release) (void *pmi_ctx, void *obj);
};

struct stack_st_X509;

/* TODO: describe this important data structure */
typedef struct lsquic_engine_api
{
Expand All @@ -509,6 +511,20 @@ typedef struct lsquic_engine_api
*/
const struct lsquic_packout_mem_if *ea_pmi;
void *ea_pmi_ctx;
/**
* Function to verify server certificate. The chain contains at least
* one element. The first element in the chain is the server
* certificate. The chain belongs to the library. If you want to
* retain it, call sk_X509_up_ref().
*
* 0 is returned on success, -1 on error.
*
* If the function pointer is not set, no verification is performed
* (the connection is allowed to proceed).
*/
int (*ea_verify_cert)(void *verify_ctx,
struct stack_st_X509 *chain);
void *ea_verify_ctx;
} lsquic_engine_api_t;

/**
Expand Down Expand Up @@ -685,6 +701,18 @@ int lsquic_stream_shutdown(lsquic_stream_t *s, int how);

int lsquic_stream_close(lsquic_stream_t *s);

/**
* Get certificate chain returned by the server. This can be used for
* server certificate verifiction.
*
* If server certificate cannot be verified, the connection can be closed
* using lsquic_conn_cert_verification_failed().
*
* The caller releases the stack using sk_X509_free().
*/
struct stack_st_X509 *
lsquic_conn_get_server_cert_chain (lsquic_conn_t *);

/** Returns ID of the stream */
uint32_t
lsquic_stream_id (const lsquic_stream_t *s);
Expand Down
2 changes: 1 addition & 1 deletion src/liblsquic/lshpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ SOFTWARE.
#if LS_HPACK_EMIT_TEST_CODE
#include "lshpack-test.h"
#endif
#include "lsquic_xxhash.h"
#include XXH_HEADER_NAME

#define HPACK_STATIC_TABLE_SIZE 61
#define INITIAL_DYNAMIC_TABLE_SIZE 4096
Expand Down
8 changes: 0 additions & 8 deletions src/liblsquic/lsquic_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -609,14 +609,6 @@ int gen_prof(const uint8_t *chlo_data, size_t chlo_data_len,
}


int verify_cert(const char *buf, int len)
{
//X509_verify_cert();

return 0;
}


int verify_prof(const uint8_t *chlo_data, size_t chlo_data_len, lsquic_str_t * scfg,
const EVP_PKEY *pub_key, const uint8_t *buf, size_t len)
{
Expand Down
2 changes: 2 additions & 0 deletions src/liblsquic/lsquic_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ lsquic_engine_new (unsigned flags,
engine->pub.enp_pmi = &stock_pmi;
engine->pub.enp_pmi_ctx = NULL;
}
engine->pub.enp_verify_cert = api->ea_verify_cert;
engine->pub.enp_verify_ctx = api->ea_verify_ctx;
engine->pub.enp_engine = engine;
conn_hash_init(&engine->conns_hash,
hash_conns_by_addr(engine) ? CHF_USE_ADDR : 0);
Expand Down
4 changes: 4 additions & 0 deletions src/liblsquic/lsquic_engine_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@

struct lsquic_conn;
struct lsquic_engine;
struct stack_st_X509;

struct lsquic_engine_public {
struct lsquic_mm enp_mm;
struct lsquic_engine_settings enp_settings;
int (*enp_verify_cert)(void *verify_ctx,
struct stack_st_X509 *chain);
void *enp_verify_ctx;
const struct lsquic_packout_mem_if
*enp_pmi;
void *enp_pmi_ctx;
Expand Down
7 changes: 6 additions & 1 deletion src/liblsquic/lsquic_full_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -2677,7 +2677,7 @@ immediate_close (struct full_conn *conn)
return TICK_CLOSE;
}

assert(conn->fc_flags & (FC_ERROR|FC_ABORTED|FC_TIMED_OUT));
assert(conn->fc_flags & (FC_ERROR|FC_ABORTED|FC_TIMED_OUT|FC_HSK_FAILED));
if (conn->fc_flags & FC_ERROR)
{
error_code = 0x01; /* QUIC_INTERNAL_ERROR */
Expand All @@ -2693,6 +2693,11 @@ immediate_close (struct full_conn *conn)
error_code = 0x19; /* QUIC_NETWORK_IDLE_TIMEOUT */
error_reason = "connection timed out";
}
else if (conn->fc_flags & FC_HSK_FAILED)
{
error_code = 0x2A; /* QUIC_PROOF_INVALID */
error_reason = "handshake failed";
}
else
{
error_code = 0x10; /* QUIC_PEER_GOING_AWAY */
Expand Down
75 changes: 71 additions & 4 deletions src/liblsquic/lsquic_handshake.c
Original file line number Diff line number Diff line change
Expand Up @@ -1108,23 +1108,54 @@ static int handle_chlo_reply_verify_prof(lsquic_enc_session_t *enc_session,
in + lsquic_str_len(&enc_session->hs_ctx.crt);
EVP_PKEY *pub_key;
int ret;
X509 *cert;
size_t i;
X509 *cert, *server_cert;
STACK_OF(X509) *chain = NULL;
ret = decompress_certs(in, in_end,cached_certs, cached_certs_count,
out_certs, out_certs_count);
if (ret)
return ret;

cert = bio_to_crt((const char *)lsquic_str_cstr(out_certs[0]),
server_cert = bio_to_crt((const char *)lsquic_str_cstr(out_certs[0]),
lsquic_str_len(out_certs[0]), 0);
pub_key = X509_get_pubkey(cert);
pub_key = X509_get_pubkey(server_cert);
ret = verify_prof((const uint8_t *)lsquic_str_cstr(&enc_session->chlo),
(size_t)lsquic_str_len(&enc_session->chlo),
&enc_session->info->scfg,
pub_key,
(const uint8_t *)lsquic_str_cstr(&enc_session->hs_ctx.prof),
lsquic_str_len(&enc_session->hs_ctx.prof));
EVP_PKEY_free(pub_key);
X509_free(cert);
if (ret != 0)
goto cleanup;

if (enc_session->enpub->enp_verify_cert)
{
chain = sk_X509_new_null();
sk_X509_push(chain, server_cert);
for (i = 1; i < *out_certs_count; ++i)
{
cert = bio_to_crt((const char *)lsquic_str_cstr(out_certs[i]),
lsquic_str_len(out_certs[i]), 0);
if (cert)
sk_X509_push(chain, cert);
else
{
LSQ_WARN("cannot push certificate to stack");
ret = -1;
goto cleanup;
}
}
ret = enc_session->enpub->enp_verify_cert(
enc_session->enpub->enp_verify_ctx, chain);
LSQ_INFO("server certificate verification %ssuccessful",
ret == 0 ? "" : "not ");
}

cleanup:
if (chain)
sk_X509_free(chain);
X509_free(server_cert);
return ret;
}

Expand Down Expand Up @@ -1837,6 +1868,41 @@ lsquic_enc_session_verify_reset_token (lsquic_enc_session_t *enc_session,
}


static STACK_OF(X509) *
lsquic_enc_session_get_server_cert_chain (lsquic_enc_session_t *enc_session)
{
const struct cert_hash_item_st *item;
STACK_OF(X509) *chain;
X509 *cert;
int i;

item = c_find_certs(&enc_session->hs_ctx.sni);
if (!item)
{
LSQ_WARN("could not find certificates for `%.*s'",
(int) lsquic_str_len(&enc_session->hs_ctx.sni),
lsquic_str_cstr(&enc_session->hs_ctx.sni));
return NULL;
}

chain = sk_X509_new_null();
for (i = 0; i < item->count; ++i)
{
cert = bio_to_crt(lsquic_str_cstr(&item->crts[i]),
lsquic_str_len(&item->crts[i]), 0);
if (cert)
sk_X509_push(chain, cert);
else
{
sk_X509_free(chain);
return NULL;
}
}

return chain;
}


#ifdef NDEBUG
const
#endif
Expand All @@ -1859,6 +1925,7 @@ struct enc_session_funcs lsquic_enc_session_gquic_1 =
.esf_handle_chlo_reply = lsquic_enc_session_handle_chlo_reply,
.esf_mem_used = lsquic_enc_session_mem_used,
.esf_verify_reset_token = lsquic_enc_session_verify_reset_token,
.esf_get_server_cert_chain = lsquic_enc_session_get_server_cert_chain,
};


Expand Down
4 changes: 4 additions & 0 deletions src/liblsquic/lsquic_handshake.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

struct lsquic_engine_public;
struct lsquic_enc_session;
struct stack_st_X509;

typedef struct lsquic_enc_session lsquic_enc_session_t;

Expand Down Expand Up @@ -139,6 +140,9 @@ struct enc_session_funcs
int
(*esf_verify_reset_token) (lsquic_enc_session_t *, const unsigned char *,
size_t);

struct stack_st_X509 *
(*esf_get_server_cert_chain) (lsquic_enc_session_t *);
};

extern
Expand Down
Loading

0 comments on commit 7f2bd84

Please sign in to comment.