diff --git a/docs/apiref.rst b/docs/apiref.rst index 8453086e..fe7511e0 100644 --- a/docs/apiref.rst +++ b/docs/apiref.rst @@ -1970,6 +1970,13 @@ Miscellaneous Connection Functions The caller releases the stack using sk_X509_free(). +.. function:: struct stack_st_X509 * lsquic_conn_get_full_cert_chain (lsquic_conn_t *conn) + + Get full certificate chain returned by the server/client. This can be used for + server/client certificate verification. + + The caller releases the stack using sk_X509_free(). + .. function:: lsquic_conn_ctx_t * lsquic_conn_get_ctx (const lsquic_conn_t *conn) Get user-supplied context associated with the connection. diff --git a/include/lsquic.h b/include/lsquic.h index e287dae1..13af2e35 100644 --- a/include/lsquic.h +++ b/include/lsquic.h @@ -1784,6 +1784,16 @@ lsquic_stream_has_unacked_data (lsquic_stream_t *s); struct stack_st_X509 * lsquic_conn_get_server_cert_chain (lsquic_conn_t *); +/** + * Get the full certificate chain returned by the server/lient. + * This can be used for server/client certificate verification. + * + * The caller releases the stack using sk_X509_free(). + */ +struct stack_st_X509 * +lsquic_conn_get_full_cert_chain (lsquic_conn_t *); + + /** Returns ID of the stream */ lsquic_stream_id_t lsquic_stream_id (const lsquic_stream_t *s); diff --git a/src/liblsquic/lsquic_conn.c b/src/liblsquic/lsquic_conn.c index ebbb19b0..46ae4d86 100644 --- a/src/liblsquic/lsquic_conn.c +++ b/src/liblsquic/lsquic_conn.c @@ -138,6 +138,16 @@ lsquic_conn_get_server_cert_chain (struct lsquic_conn *lconn) } +struct stack_st_X509 * +lsquic_conn_get_full_cert_chain (struct lsquic_conn *lconn) +{ + if (lconn->cn_enc_session) + return lconn->cn_esf_c->esf_get_full_cert_chain(lconn->cn_enc_session); + else + return NULL; +} + + void lsquic_conn_make_stream (struct lsquic_conn *lconn) { diff --git a/src/liblsquic/lsquic_enc_sess.h b/src/liblsquic/lsquic_enc_sess.h index 6baec61a..56dd99a8 100644 --- a/src/liblsquic/lsquic_enc_sess.h +++ b/src/liblsquic/lsquic_enc_sess.h @@ -118,6 +118,9 @@ struct enc_session_funcs_common struct stack_st_X509 * (*esf_get_server_cert_chain) (enc_session_t *); + struct stack_st_X509 * + (*esf_get_full_cert_chain) (enc_session_t *); + int (*esf_verify_reset_token) (enc_session_t *, const unsigned char *, size_t); diff --git a/src/liblsquic/lsquic_enc_sess_ietf.c b/src/liblsquic/lsquic_enc_sess_ietf.c index ae522233..66d020f4 100644 --- a/src/liblsquic/lsquic_enc_sess_ietf.c +++ b/src/liblsquic/lsquic_enc_sess_ietf.c @@ -89,6 +89,9 @@ free_handshake_keys (struct enc_sess_iquic *); static struct stack_st_X509 * iquic_esf_get_server_cert_chain (enc_session_t *); +static struct stack_st_X509 * +iquic_esf_get_full_cert_chain (enc_session_t *); + static void maybe_drop_SSL (struct enc_sess_iquic *); @@ -2612,6 +2615,22 @@ iquic_esf_get_server_cert_chain (enc_session_t *enc_session_p) } +static struct stack_st_X509 * +iquic_esf_get_full_cert_chain (enc_session_t *enc_session_p) +{ + struct enc_sess_iquic *const enc_sess = enc_session_p; + STACK_OF(X509) *chain; + + if (enc_sess->esi_ssl) + { + chain = SSL_get_peer_full_cert_chain(enc_sess->esi_ssl); + return X509_chain_up_ref(chain); + } + else + return NULL; +} + + static const char * iquic_esf_cipher (enc_session_t *enc_session_p) { @@ -2864,6 +2883,8 @@ const struct enc_session_funcs_common lsquic_enc_session_common_ietf_v1 = .esf_tag_len = IQUIC_TAG_LEN, .esf_get_server_cert_chain = iquic_esf_get_server_cert_chain, + .esf_get_full_cert_chain + = iquic_esf_get_full_cert_chain, .esf_get_sni = iquic_esf_get_sni, .esf_cipher = iquic_esf_cipher, .esf_keysize = iquic_esf_keysize, @@ -2883,6 +2904,8 @@ const struct enc_session_funcs_common lsquic_enc_session_common_ietf_v1_no_flush .esf_tag_len = IQUIC_TAG_LEN, .esf_get_server_cert_chain = iquic_esf_get_server_cert_chain, + .esf_get_full_cert_chain + = iquic_esf_get_full_cert_chain, .esf_get_sni = iquic_esf_get_sni, .esf_cipher = iquic_esf_cipher, .esf_keysize = iquic_esf_keysize,