API: add ea_alpn that is used when not in HTTP mode

This commit is contained in:
Dmitri Tikhonov 2020-02-18 09:38:41 -05:00
parent abc972dafe
commit fa4561dcea
4 changed files with 69 additions and 24 deletions

View file

@ -1019,6 +1019,12 @@ struct lsquic_engine_api
*/
const struct lsquic_keylog_if *ea_keylog_if;
void *ea_keylog_ctx;
/**
* The optional ALPN string is used by the client @ref LSENG_HTTP
* is not set.
*/
const char *ea_alpn;
};
/**

View file

@ -70,7 +70,7 @@
static const struct alpn_map {
enum lsquic_version version;
const unsigned char *alpn;
} s_alpns[] = {
} s_h3_alpns[] = {
{ LSQVER_ID25, (unsigned char *) "\x05h3-25", },
{ LSQVER_ID27, (unsigned char *) "\x05h3-27", },
{ LSQVER_VERNEG, (unsigned char *) "\x05h3-27", },
@ -1097,17 +1097,19 @@ iquic_esfi_init_server (enc_session_t *enc_session_p)
unsigned char trans_params[sizeof(struct transport_params)];
} u;
for (am = s_alpns; am < s_alpns + sizeof(s_alpns)
/ sizeof(s_alpns[0]); ++am)
if (am->version == enc_sess->esi_conn->cn_version)
goto ok;
LSQ_ERROR("version %s has no matching ALPN",
lsquic_ver2str[enc_sess->esi_conn->cn_version]);
return -1;
ok:
enc_sess->esi_alpn = am->alpn;
if (enc_sess->esi_enpub->enp_alpn)
enc_sess->esi_alpn = enc_sess->esi_enpub->enp_alpn;
else if (enc_sess->esi_enpub->enp_flags & ENPUB_HTTP)
{
for (am = s_h3_alpns; am < s_h3_alpns + sizeof(s_h3_alpns)
/ sizeof(s_h3_alpns[0]); ++am)
if (am->version == enc_sess->esi_conn->cn_version)
goto ok;
LSQ_ERROR("version %s has no matching ALPN",
lsquic_ver2str[enc_sess->esi_conn->cn_version]);
return -1;
ok: enc_sess->esi_alpn = am->alpn;
}
ssl_ctx = enc_sess->esi_enpub->enp_get_ssl_ctx(
lsquic_conn_get_peer_ctx(enc_sess->esi_conn, NULL));
@ -1261,17 +1263,20 @@ init_client (struct enc_sess_iquic *const enc_sess)
#endif
];
for (am = s_alpns; am < s_alpns + sizeof(s_alpns)
/ sizeof(s_alpns[0]); ++am)
if (am->version == enc_sess->esi_ver_neg->vn_ver)
goto ok;
if (enc_sess->esi_enpub->enp_alpn)
enc_sess->esi_alpn = enc_sess->esi_enpub->enp_alpn;
else if (enc_sess->esi_enpub->enp_flags & ENPUB_HTTP)
{
for (am = s_h3_alpns; am < s_h3_alpns + sizeof(s_h3_alpns)
/ sizeof(s_h3_alpns[0]); ++am)
if (am->version == enc_sess->esi_ver_neg->vn_ver)
goto ok;
LSQ_ERROR("version %s has no matching ALPN",
lsquic_ver2str[enc_sess->esi_ver_neg->vn_ver]);
return -1;
ok: enc_sess->esi_alpn = am->alpn;
}
LSQ_ERROR("version %s has no matching ALPN",
lsquic_ver2str[enc_sess->esi_ver_neg->vn_ver]);
return -1;
ok:
enc_sess->esi_alpn = am->alpn;
LSQ_DEBUG("Create new SSL_CTX");
ssl_ctx = SSL_CTX_new(TLS_method());
if (!ssl_ctx)
@ -1320,7 +1325,9 @@ init_client (struct enc_sess_iquic *const enc_sess)
ERR_error_string(ERR_get_error(), errbuf));
goto err;
}
if (0 != SSL_set_alpn_protos(enc_sess->esi_ssl, am->alpn, am->alpn[0] + 1))
if (enc_sess->esi_alpn &&
0 != SSL_set_alpn_protos(enc_sess->esi_ssl, enc_sess->esi_alpn,
enc_sess->esi_alpn[0] + 1))
{
LSQ_ERROR("cannot set ALPN: %s",
ERR_error_string(ERR_get_error(), errbuf));
@ -2437,7 +2444,8 @@ cry_sm_set_encryption_secret (SSL *ssl, enum ssl_encryption_level_t level,
if (!enc_sess)
return 0;
if ((enc_sess->esi_flags & (ESI_ALPN_CHECKED|ESI_SERVER)) == ESI_SERVER)
if ((enc_sess->esi_flags & (ESI_ALPN_CHECKED|ESI_SERVER)) == ESI_SERVER
&& enc_sess->esi_alpn)
{
enc_sess->esi_flags |= ESI_ALPN_CHECKED;
SSL_get0_alpn_selected(enc_sess->esi_ssl, &alpn, &alpn_len);

View file

@ -463,6 +463,7 @@ lsquic_engine_new (unsigned flags,
const struct lsquic_engine_api *api)
{
lsquic_engine_t *engine;
size_t alpn_len;
char err_buf[100];
if (!api->ea_packets_out)
@ -477,6 +478,18 @@ lsquic_engine_new (unsigned flags,
return NULL;
}
if (!(flags & LSENG_HTTP) && api->ea_alpn)
{
alpn_len = strlen(api->ea_alpn);
if (alpn_len < 1 || alpn_len > 255)
{
LSQ_ERROR("ALPN string length invalid: %zd bytes", alpn_len);
return NULL;
}
}
else
alpn_len = 0;
if (api->ea_settings &&
0 != lsquic_engine_check_settings(api->ea_settings, flags,
err_buf, sizeof(err_buf)))
@ -605,6 +618,21 @@ lsquic_engine_new (unsigned flags,
}
}
if (alpn_len)
{
engine->pub.enp_alpn = malloc(alpn_len + 1);
if (!engine->pub.enp_alpn)
{
lsquic_engine_destroy(engine);
return NULL;
}
engine->pub.enp_alpn[0] = alpn_len;
memcpy(engine->pub.enp_alpn + 1, api->ea_alpn, alpn_len);
}
if (flags & LSENG_HTTP)
engine->pub.enp_flags |= ENPUB_HTTP;
#ifndef NDEBUG
{
const char *env;
@ -1458,6 +1486,7 @@ lsquic_engine_destroy (lsquic_engine_t *engine)
#endif
if (engine->pub.enp_retry_aead_ctx)
EVP_AEAD_CTX_cleanup(engine->pub.enp_retry_aead_ctx);
free(engine->pub.enp_alpn);
free(engine);
}

View file

@ -59,11 +59,13 @@ struct lsquic_engine_public {
* functions.
*/
ENPUB_CAN_SEND = (1 << 1),
ENPUB_HTTP = (1 << 2), /* Engine in HTTP mode */
} enp_flags;
unsigned char enp_ver_tags_buf[ sizeof(lsquic_ver_tag_t) * N_LSQVER ];
unsigned enp_ver_tags_len;
struct crand *enp_crand;
struct evp_aead_ctx_st *enp_retry_aead_ctx;
unsigned char *enp_alpn; /* May be set if not HTTP */
};
/* Put connection onto the Tickable Queue if it is not already on it. If