Skip to content

Commit

Permalink
add ALPN as paramter to tls ctx init, add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
icing committed Jan 10, 2024
1 parent c86c8b6 commit 44c8794
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 28 deletions.
2 changes: 2 additions & 0 deletions lib/vquic/curl_ngtcp2.c
Expand Up @@ -2045,7 +2045,9 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
if(result)
return result;

#define H3_ALPN "\x2h3\x5h3-29"
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
H3_ALPN, sizeof(H3_ALPN) - 1,
tls_ctx_setup, &ctx->conn_ref);
if(result)
return result;
Expand Down
5 changes: 4 additions & 1 deletion lib/vquic/curl_quiche.c
Expand Up @@ -1232,7 +1232,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
sizeof(QUICHE_H3_APPLICATION_PROTOCOL)
- 1);

result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, NULL, cf);
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
QUICHE_H3_APPLICATION_PROTOCOL,
sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1,
NULL, cf);
if(result)
return result;

Expand Down
66 changes: 39 additions & 27 deletions lib/vquic/vquic-tls.c
Expand Up @@ -57,10 +57,9 @@
#include "curl_memory.h"
#include "memdebug.h"


#define H3_ALPN_H3_29 "\x5h3-29"
#define H3_ALPN_H3 "\x2h3"

#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif

#ifdef USE_OPENSSL
#define QUIC_CIPHERS \
Expand Down Expand Up @@ -209,22 +208,18 @@ static CURLcode curl_ossl_set_client_cert(struct quic_tls_ctx *ctx,
static CURLcode curl_ossl_init_ssl(struct quic_tls_ctx *ctx,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
void *user_data)
{
const uint8_t *alpn = NULL;
size_t alpnlen = 0;

DEBUGASSERT(!ctx->ssl);
ctx->ssl = SSL_new(ctx->ssl_ctx);

SSL_set_app_data(ctx->ssl, user_data);
SSL_set_connect_state(ctx->ssl);
SSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);

alpn = (const uint8_t *)H3_ALPN_H3 H3_ALPN_H3_29;
alpnlen = sizeof(H3_ALPN_H3) - 1 + sizeof(H3_ALPN_H3_29) - 1;
if(alpn)
SSL_set_alpn_protos(ctx->ssl, alpn, (int)alpnlen);
SSL_set_alpn_protos(ctx->ssl, (const uint8_t *)alpn, (int)alpn_len);

if(peer->sni) {
if(!SSL_set_tlsext_host_name(ctx->ssl, peer->sni)) {
Expand Down Expand Up @@ -257,12 +252,13 @@ static CURLcode curl_gtls_init_ctx(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
Curl_vquic_tls_ctx_setup *ctx_setup,
void *user_data)
{
struct ssl_primary_config *conn_config;
CURLcode result;
gnutls_datum_t alpn[2];
gnutls_datum_t alpns[5];
/* this will need some attention when HTTPS proxy over QUIC get fixed */
long * const pverifyresult = &data->set.ssl.certverifyresult;
int rc;
Expand Down Expand Up @@ -302,14 +298,31 @@ static CURLcode curl_gtls_init_ctx(struct quic_tls_ctx *ctx,
gnutls_session_set_keylog_function(ctx->gtls->session, keylog_callback);
}

/* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
alpn[0].data = (unsigned char *)H3_ALPN_H3 + 1;
alpn[0].size = sizeof(H3_ALPN_H3) - 2;
alpn[1].data = (unsigned char *)H3_ALPN_H3_29 + 1;
alpn[1].size = sizeof(H3_ALPN_H3_29) - 2;
/* convert the ALPN string from our arguments to a list of strings
* that gnutls wants and will convert internally back to this very
* string for sending to the server. nice. */
if(alpn) {
size_t i, alen = alpn_len;
unsigned char *s = (unsigned char *)alpn;
unsigned char slen;
for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) {
slen = s[0];
if(slen >= alen)
return CURLE_FAILED_INIT;
alpns[i].data = s + 1;
alpns[i].size = slen;
s += slen + 1;
alen -= slen + 1;
}
if(alen) /* not all alpn chars used, wrong format or too many */
return CURLE_FAILED_INIT;
if(i) {
gnutls_alpn_set_protocols(ctx->gtls->session,
alpns, (unsigned int)i,
GNUTLS_ALPN_MANDATORY);
}
}

gnutls_alpn_set_protocols(ctx->gtls->session,
alpn, 2, GNUTLS_ALPN_MANDATORY);
return CURLE_OK;
}
#elif defined(USE_WOLFSSL)
Expand Down Expand Up @@ -438,11 +451,9 @@ static CURLcode curl_wssl_init_ctx(struct quic_tls_ctx *ctx,
static CURLcode curl_wssl_init_ssl(struct quic_tls_ctx *ctx,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
void *user_data)
{
const uint8_t *alpn = NULL;
size_t alpnlen = 0;

(void)data;
DEBUGASSERT(!ctx->ssl);
DEBUGASSERT(ctx->ssl_ctx);
Expand All @@ -452,10 +463,9 @@ static CURLcode curl_wssl_init_ssl(struct quic_tls_ctx *ctx,
wolfSSL_set_connect_state(ctx->ssl);
wolfSSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);

alpn = (const uint8_t *)H3_ALPN_H3 H3_ALPN_H3_29;
alpnlen = sizeof(H3_ALPN_H3) - 1 + sizeof(H3_ALPN_H3_29) - 1;
if(alpn)
wolfSSL_set_alpn_protos(ctx->ssl, alpn, (int)alpnlen);
wolfSSL_set_alpn_protos(ctx->ssl, (const unsigned char *)alpn,
(int)alpn_len);

if(peer->sni) {
wolfSSL_UseSNI(ctx->ssl, WOLFSSL_SNI_HOST_NAME,
Expand All @@ -470,6 +480,7 @@ CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
Curl_vquic_tls_ctx_setup *ctx_setup,
void *user_data)
{
Expand All @@ -484,16 +495,17 @@ CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx,
if(result)
return result;

return curl_ossl_init_ssl(ctx, data, peer, user_data);
return curl_ossl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data);
#elif defined(USE_GNUTLS)
(void)result;
return curl_gtls_init_ctx(ctx, cf, data, peer, ctx_setup, user_data);
return curl_gtls_init_ctx(ctx, cf, data, peer, alpn, alpn_len,
ctx_setup, user_data);
#elif defined(USE_WOLFSSL)
result = curl_wssl_init_ctx(ctx, cf, data, ctx_setup);
if(result)
return result;

return curl_wssl_init_ssl(ctx, data, peer, user_data);
return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, user_data);
#else
#error "no TLS lib in used, should not happen"
return CURLE_FAILED_INIT;
Expand Down
28 changes: 28 additions & 0 deletions lib/vquic/vquic-tls.h
Expand Up @@ -43,23 +43,51 @@ struct quic_tls_ctx {
BIT(x509_store_setup); /* if x509 store has been set up */
};

/**
* Callback passed to `Curl_vquic_tls_init()` that can
* do early initializations on the not otherwise configured TLS
* instances created. This varies by TLS backend:
* - openssl/wolfssl: SSL_CTX* has just been created
* - gnutls: gtls_client_init() has run
*/
typedef CURLcode Curl_vquic_tls_ctx_setup(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data);

/**
* Initialize the QUIC TLS instances based of the SSL configurations
* for the connection filter, transfer and peer.
* @param ctx the TLS context to initialize
* @param cf the connection filter involved
* @param data the transfer involved
* @param peer the peer that will be connected to
* @param alpn the ALPN string in protocol format ((len+bytes+)+),
* may be NULL
* @param alpn_len the overall number of bytes in `alpn`
* @param ctx_setup optional callback for very early TLS config
* @param user_data optional pointer to set in TLS application context
*/
CURLcode Curl_vquic_tls_init(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const char *alpn, size_t alpn_len,
Curl_vquic_tls_ctx_setup *ctx_setup,
void *user_data);

/**
* Cleanup all data that has been initialized.
*/
void Curl_vquic_tls_cleanup(struct quic_tls_ctx *ctx);

CURLcode Curl_vquic_tls_before_recv(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data);

/**
* After the QUIC basic handshake has been, verify that the peer
* (and its certificate) fullfill our requirements.
*/
CURLcode Curl_vquic_tls_verify_peer(struct quic_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
Expand Down

0 comments on commit 44c8794

Please sign in to comment.