mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
client: add alpn processing on mbedtls and openssl
This just supports "http/1.1" alpn and lets the client know it can use keepalive earlier if it affirmitively negotiated "http/1.1" on alpn. mbedTLS wrapper needed a small adaptation to also allow per-client-ssl control of the alpn negotiation list.
This commit is contained in:
parent
04e1661411
commit
b45956fcb9
9 changed files with 111 additions and 10 deletions
|
@ -1298,6 +1298,8 @@ CHECK_FUNCTION_EXISTS(X509_VERIFY_PARAM_set1_host LWS_HAVE_X509_VERIFY_PARAM_set
|
|||
CHECK_FUNCTION_EXISTS(RSA_set0_key LWS_HAVE_RSA_SET0_KEY)
|
||||
CHECK_FUNCTION_EXISTS(X509_get_key_usage LWS_HAVE_X509_get_key_usage)
|
||||
CHECK_FUNCTION_EXISTS(SSL_CTX_get0_certificate LWS_HAVE_SSL_CTX_get0_certificate)
|
||||
CHECK_FUNCTION_EXISTS(SSL_get0_alpn_selected LWS_HAVE_SSL_get0_alpn_selected)
|
||||
CHECK_FUNCTION_EXISTS(SSL_set_alpn_protos LWS_HAVE_SSL_set_alpn_protos)
|
||||
if (LWS_WITH_SSL AND NOT LWS_WITH_MBEDTLS)
|
||||
CHECK_SYMBOL_EXISTS(SSL_CTX_get_extra_chain_certs_only openssl/ssl.h LWS_HAVE_SSL_EXTRA_CHAIN_CERTS)
|
||||
endif()
|
||||
|
|
|
@ -163,6 +163,8 @@
|
|||
#cmakedefine LWS_HAVE_TLSV1_2_CLIENT_METHOD
|
||||
#cmakedefine LWS_HAVE_SSL_SET_INFO_CALLBACK
|
||||
#cmakedefine LWS_HAVE_SSL_EXTRA_CHAIN_CERTS
|
||||
#cmakedefine LWS_HAVE_SSL_get0_alpn_selected
|
||||
#cmakedefine LWS_HAVE_SSL_set_alpn_protos
|
||||
|
||||
#cmakedefine LWS_HAS_INTPTR_T
|
||||
|
||||
|
|
|
@ -3269,6 +3269,7 @@ enum lws_client_connect_ssl_connection_flags {
|
|||
LCCSCF_ALLOW_SELFSIGNED = (1 << 1),
|
||||
LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK = (1 << 2),
|
||||
LCCSCF_ALLOW_EXPIRED = (1 << 3),
|
||||
LCCSCF_NOT_H2 = (1 << 4),
|
||||
|
||||
LCCSCF_PIPELINE = (1 << 16),
|
||||
/**< Serialize / pipeline multiple client connections
|
||||
|
|
|
@ -27,6 +27,14 @@ OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct alpn_ctx {
|
||||
unsigned char *data;
|
||||
unsigned short len;
|
||||
};
|
||||
|
||||
static struct alpn_ctx protos = { (unsigned char *)
|
||||
"\x08http/1.1", 3 + 9 };
|
||||
|
||||
int
|
||||
lws_ssl_client_bio_create(struct lws *wsi)
|
||||
{
|
||||
|
@ -57,6 +65,8 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
if (!wsi->ssl)
|
||||
return -1;
|
||||
|
||||
SSL_set_alpn_select_cb(wsi->ssl, &protos);
|
||||
|
||||
if (wsi->vhost->ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
|
||||
|
||||
|
@ -89,9 +99,24 @@ enum lws_ssl_capable_status
|
|||
lws_tls_client_connect(struct lws *wsi)
|
||||
{
|
||||
int m, n = SSL_connect(wsi->ssl);
|
||||
const unsigned char *prot;
|
||||
unsigned int len;
|
||||
|
||||
if (n == 1) {
|
||||
SSL_get0_alpn_selected(wsi->ssl, &prot, &len);
|
||||
|
||||
if (prot && !strcmp((char *)prot, "http/1.1"))
|
||||
/*
|
||||
* If alpn asserts it is http/1.1, KA is mandatory.
|
||||
*
|
||||
* Knowing this lets us proceed with sending
|
||||
* pipelined headers before we received the first
|
||||
* response headers.
|
||||
*/
|
||||
wsi->keepalive_active = 1;
|
||||
|
||||
if (n == 1)
|
||||
return LWS_SSL_CAPABLE_DONE;
|
||||
}
|
||||
|
||||
m = SSL_get_error(wsi->ssl, n);
|
||||
|
||||
|
|
|
@ -203,6 +203,8 @@ struct ssl_st
|
|||
|
||||
const SSL_METHOD *method;
|
||||
|
||||
const char **alpn_protos;
|
||||
|
||||
RECORD_LAYER rlayer;
|
||||
|
||||
/* where we are */
|
||||
|
|
|
@ -321,6 +321,7 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
|
|||
void *arg),
|
||||
void *arg);
|
||||
|
||||
void SSL_set_alpn_select_cb(SSL *ssl, void *arg);
|
||||
|
||||
/**
|
||||
* @brief set the SSL context ALPN select protocol
|
||||
|
|
|
@ -351,6 +351,9 @@ void SSL_free(SSL *ssl)
|
|||
|
||||
SSL_SESSION_free(ssl->session);
|
||||
|
||||
if (ssl->alpn_protos)
|
||||
ssl_mem_free(ssl->alpn_protos);
|
||||
|
||||
ssl_mem_free(ssl);
|
||||
}
|
||||
|
||||
|
@ -1649,11 +1652,12 @@ struct alpn_ctx {
|
|||
unsigned short len;
|
||||
};
|
||||
|
||||
void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, next_proto_cb cb, void *arg)
|
||||
static void
|
||||
_openssl_alpn_to_mbedtls(struct alpn_ctx *ac, char ***palpn_protos)
|
||||
{
|
||||
struct alpn_ctx *ac = arg;
|
||||
unsigned char *p = ac->data, *q;
|
||||
unsigned char len;
|
||||
char **alpn_protos;
|
||||
int count = 0;
|
||||
|
||||
/* find out how many entries he gave us */
|
||||
|
@ -1675,18 +1679,20 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, next_proto_cb cb, void *arg)
|
|||
|
||||
/* allocate space for count + 1 pointers and the data afterwards */
|
||||
|
||||
ctx->alpn_protos = ssl_mem_zalloc((count + 1) * sizeof(char *) + ac->len + 1);
|
||||
if (!ctx->alpn_protos)
|
||||
alpn_protos = ssl_mem_zalloc((count + 1) * sizeof(char *) + ac->len + 1);
|
||||
if (!alpn_protos)
|
||||
return;
|
||||
|
||||
*palpn_protos = alpn_protos;
|
||||
|
||||
/* convert to mbedtls format */
|
||||
|
||||
q = (unsigned char *)ctx->alpn_protos + (count + 1) * sizeof(char *);
|
||||
q = (unsigned char *)alpn_protos + (count + 1) * sizeof(char *);
|
||||
p = ac->data;
|
||||
count = 0;
|
||||
|
||||
len = *p++;
|
||||
ctx->alpn_protos[count] = (char *)q;
|
||||
alpn_protos[count] = (char *)q;
|
||||
while (p - ac->data < ac->len) {
|
||||
if (len--) {
|
||||
*q++ = *p++;
|
||||
|
@ -1695,11 +1701,27 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, next_proto_cb cb, void *arg)
|
|||
*q++ = '\0';
|
||||
count++;
|
||||
len = *p++;
|
||||
ctx->alpn_protos[count] = (char *)q;
|
||||
alpn_protos[count] = (char *)q;
|
||||
if (!len)
|
||||
break;
|
||||
}
|
||||
ctx->alpn_protos[count] = NULL; /* last pointer ends list with NULL */
|
||||
alpn_protos[count] = NULL; /* last pointer ends list with NULL */
|
||||
}
|
||||
|
||||
void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, next_proto_cb cb, void *arg)
|
||||
{
|
||||
struct alpn_ctx *ac = arg;
|
||||
|
||||
ctx->alpn_cb = cb;
|
||||
|
||||
_openssl_alpn_to_mbedtls(ac, (char ***)&ctx->alpn_protos);
|
||||
}
|
||||
|
||||
void SSL_set_alpn_select_cb(SSL *ssl, void *arg)
|
||||
{
|
||||
struct alpn_ctx *ac = arg;
|
||||
|
||||
_openssl_alpn_to_mbedtls(ac, (char ***)&ssl->alpn_protos);
|
||||
|
||||
_ssl_set_alpn_list(ssl);
|
||||
}
|
||||
|
|
|
@ -829,6 +829,12 @@ int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
|
|||
|
||||
void _ssl_set_alpn_list(const SSL *ssl)
|
||||
{
|
||||
if (ssl->alpn_protos) {
|
||||
if (mbedtls_ssl_conf_alpn_protocols(&((struct ssl_pm *)(ssl->ssl_pm))->conf, ssl->alpn_protos))
|
||||
fprintf(stderr, "mbedtls_ssl_conf_alpn_protocols failed\n");
|
||||
|
||||
return;
|
||||
}
|
||||
if (!ssl->ctx->alpn_protos)
|
||||
return;
|
||||
if (mbedtls_ssl_conf_alpn_protocols(&((struct ssl_pm *)(ssl->ssl_pm))->conf, ssl->ctx->alpn_protos))
|
||||
|
|
|
@ -86,6 +86,12 @@ OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(LWS_HAVE_SSL_set_alpn_protos) && defined(LWS_HAVE_SSL_get0_alpn_selected)
|
||||
static const unsigned char client_alpn_protocols[] = {
|
||||
8, 'h', 't', 't', 'p', '/', '1', '.', '1'
|
||||
};
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_ssl_client_bio_create(struct lws *wsi)
|
||||
{
|
||||
|
@ -93,6 +99,10 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
X509_VERIFY_PARAM *param;
|
||||
#endif
|
||||
char hostname[128], *p;
|
||||
#if defined(LWS_HAVE_SSL_set_alpn_protos) && defined(LWS_HAVE_SSL_get0_alpn_selected)
|
||||
const unsigned char *plist = client_alpn_protocols;
|
||||
int n = sizeof(client_alpn_protocols);
|
||||
#endif
|
||||
|
||||
if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
|
||||
_WSI_TOKEN_CLIENT_HOST) <= 0) {
|
||||
|
@ -122,6 +132,10 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
return -1;
|
||||
}
|
||||
|
||||
#if defined(LWS_HAVE_SSL_set_alpn_protos) && defined(LWS_HAVE_SSL_get0_alpn_selected)
|
||||
SSL_set_alpn_protos(wsi->ssl, plist, n);
|
||||
#endif
|
||||
|
||||
#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
|
||||
if (wsi->vhost->ssl_info_event_mask)
|
||||
SSL_set_info_callback(wsi->ssl, lws_ssl_info_callback);
|
||||
|
@ -205,10 +219,36 @@ lws_ssl_client_bio_create(struct lws *wsi)
|
|||
enum lws_ssl_capable_status
|
||||
lws_tls_client_connect(struct lws *wsi)
|
||||
{
|
||||
#if defined(LWS_HAVE_SSL_set_alpn_protos) && defined(LWS_HAVE_SSL_get0_alpn_selected)
|
||||
const unsigned char *prot;
|
||||
char a[32];
|
||||
unsigned int len;
|
||||
#endif
|
||||
int m, n = SSL_connect(wsi->ssl);
|
||||
|
||||
if (n == 1)
|
||||
if (n == 1) {
|
||||
#if defined(LWS_HAVE_SSL_set_alpn_protos) && defined(LWS_HAVE_SSL_get0_alpn_selected)
|
||||
SSL_get0_alpn_selected(wsi->ssl, &prot, &len);
|
||||
|
||||
if (len > sizeof(a))
|
||||
len = sizeof(a) - 1;
|
||||
memcpy(a, (const char *)prot, len);
|
||||
a[len] = '\0';
|
||||
|
||||
if (prot && !strcmp(a, "http/1.1"))
|
||||
/*
|
||||
* If alpn asserts it is http/1.1, KA is mandatory.
|
||||
*
|
||||
* Knowing this lets us proceed with sending
|
||||
* pipelined headers before we received the first
|
||||
* response headers.
|
||||
*/
|
||||
wsi->keepalive_active = 1;
|
||||
|
||||
lwsl_notice("client connect OK\n");
|
||||
#endif
|
||||
return LWS_SSL_CAPABLE_DONE;
|
||||
}
|
||||
|
||||
m = lws_ssl_get_error(wsi, n);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue