diff options
Diffstat (limited to 'lib/vquic/ngtcp2.c')
| -rw-r--r-- | lib/vquic/ngtcp2.c | 107 |
1 files changed, 87 insertions, 20 deletions
diff --git a/lib/vquic/ngtcp2.c b/lib/vquic/ngtcp2.c index 9fcfe81..1596049 100644 --- a/lib/vquic/ngtcp2.c +++ b/lib/vquic/ngtcp2.c @@ -29,8 +29,10 @@ #ifdef USE_OPENSSL #include <openssl/err.h> #include <ngtcp2/ngtcp2_crypto_openssl.h> +#include "vtls/openssl.h" #elif defined(USE_GNUTLS) #include <ngtcp2/ngtcp2_crypto_gnutls.h> +#include "vtls/gtls.h" #endif #include "urldata.h" #include "sendf.h" @@ -61,6 +63,7 @@ #endif #define H3_ALPN_H3_29 "\x5h3-29" +#define H3_ALPN_H3 "\x2h3" /* * This holds outgoing HTTP/3 stream data that is used by nghttp3 until acked. @@ -286,6 +289,27 @@ static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback); } + { + struct connectdata *conn = data->conn; + const char * const ssl_cafile = conn->ssl_config.CAfile; + const char * const ssl_capath = conn->ssl_config.CApath; + + if(conn->ssl_config.verifypeer) { + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); + /* tell OpenSSL where to find CA certificates that are used to verify + the server's certificate. */ + if(!SSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return NULL; + } + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } + } return ssl_ctx; } @@ -303,9 +327,10 @@ static int quic_init_ssl(struct quicsocket *qs) SSL_set_app_data(qs->ssl, qs); SSL_set_connect_state(qs->ssl); + SSL_set_quic_use_legacy_codepoint(qs->ssl, 0); - alpn = (const uint8_t *)H3_ALPN_H3_29; - alpnlen = sizeof(H3_ALPN_H3_29) - 1; + alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3; + alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1; if(alpn) SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen); @@ -417,7 +442,7 @@ static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata) static int quic_init_ssl(struct quicsocket *qs) { - gnutls_datum_t alpn = {NULL, 0}; + gnutls_datum_t alpn[2]; /* this will need some attention when HTTPS proxy over QUIC get fixed */ const char * const hostname = qs->conn->host.name; int rc; @@ -439,12 +464,10 @@ static int quic_init_ssl(struct quicsocket *qs) gnutls_alert_set_read_function(qs->ssl, alert_read_func); rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters", - 0xffa5, GNUTLS_EXT_TLS, - tp_recv_func, tp_send_func, - NULL, NULL, NULL, - GNUTLS_EXT_FLAG_TLS | - GNUTLS_EXT_FLAG_CLIENT_HELLO | - GNUTLS_EXT_FLAG_EE); + NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1, GNUTLS_EXT_TLS, + tp_recv_func, tp_send_func, NULL, NULL, NULL, + GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_EE); if(rc < 0) { H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n", gnutls_strerror(rc))); @@ -484,10 +507,12 @@ static int quic_init_ssl(struct quicsocket *qs) } /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */ - alpn.data = (unsigned char *)H3_ALPN_H3_29 + 1; - alpn.size = sizeof(H3_ALPN_H3_29) - 2; - if(alpn.data) - gnutls_alpn_set_protocols(qs->ssl, &alpn, 1, 0); + alpn[0].data = (unsigned char *)H3_ALPN_H3_29 + 1; + alpn[0].size = sizeof(H3_ALPN_H3_29) - 2; + alpn[1].data = (unsigned char *)H3_ALPN_H3 + 1; + alpn[1].size = sizeof(H3_ALPN_H3) - 2; + + gnutls_alpn_set_protocols(qs->ssl, alpn, 2, GNUTLS_ALPN_MANDATORY); /* set SNI */ gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname)); @@ -648,6 +673,20 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id, return 0; } +static void cb_rand(uint8_t *dest, size_t destlen, + const ngtcp2_rand_ctx *rand_ctx) +{ + CURLcode result; + (void)rand_ctx; + + result = Curl_rand(NULL, dest, destlen); + if(result) { + /* cb_rand is only used for non-cryptographic context. If Curl_rand + failed, just fill 0 and call it *random*. */ + memset(dest, 0, destlen); + } +} + static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, uint8_t *token, size_t cidlen, void *user_data) @@ -685,7 +724,7 @@ static ngtcp2_callbacks ng_callbacks = { ngtcp2_crypto_recv_retry_cb, cb_extend_max_local_streams_bidi, NULL, /* extend_max_local_streams_uni */ - NULL, /* rand */ + cb_rand, cb_get_new_connection_id, NULL, /* remove_connection_id */ ngtcp2_crypto_update_key_cb, /* update_key */ @@ -703,7 +742,7 @@ static ngtcp2_callbacks ng_callbacks = { NULL, /* recv_datagram */ NULL, /* ack_datagram */ NULL, /* lost_datagram */ - NULL, /* get_path_challenge_data */ + ngtcp2_crypto_get_path_challenge_data_cb, cb_stream_stop_sending }; @@ -776,7 +815,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, ngtcp2_addr_init(&path.remote, addr, addrlen); rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path, - NGTCP2_PROTO_VER_MIN, &ng_callbacks, + NGTCP2_PROTO_VER_V1, &ng_callbacks, &qs->settings, &qs->transport_params, NULL, qs); if(rc) return CURLE_QUIC_CONNECT_ERROR; @@ -792,7 +831,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, void Curl_quic_ver(char *p, size_t len) { const ngtcp2_info *ng2 = ngtcp2_version(0); - nghttp3_info *ht3 = nghttp3_version(0); + const nghttp3_info *ht3 = nghttp3_version(0); (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s", ng2->version_str, ht3->version_str); } @@ -1622,8 +1661,10 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data, return sent; } -static void ng_has_connected(struct connectdata *conn, int tempindex) +static CURLcode ng_has_connected(struct Curl_easy *data, + struct connectdata *conn, int tempindex) { + CURLcode result = CURLE_OK; conn->recv[FIRSTSOCKET] = ngh3_stream_recv; conn->send[FIRSTSOCKET] = ngh3_stream_send; conn->handler = &Curl_handler_http3; @@ -1631,6 +1672,27 @@ static void ng_has_connected(struct connectdata *conn, int tempindex) conn->httpversion = 30; conn->bundle->multiuse = BUNDLE_MULTIPLEX; conn->quic = &conn->hequic[tempindex]; + + if(conn->ssl_config.verifyhost) { +#ifdef USE_OPENSSL + X509 *server_cert; + CURLcode result; + server_cert = SSL_get_peer_certificate(conn->quic->ssl); + if(!server_cert) { + return CURLE_PEER_FAILED_VERIFICATION; + } + result = Curl_ossl_verifyhost(data, conn, server_cert); + X509_free(server_cert); + if(result) + return result; + infof(data, "Verified certificate just fine"); +#else + result = Curl_gtls_verifyserver(data, conn, conn->quic->ssl, FIRSTSOCKET); +#endif + } + else + infof(data, "Skipped certificate verification"); + return result; } /* @@ -1654,8 +1716,9 @@ CURLcode Curl_quic_is_connected(struct Curl_easy *data, goto error; if(ngtcp2_conn_get_handshake_completed(qs->qconn)) { - *done = TRUE; - ng_has_connected(conn, sockindex); + result = ng_has_connected(data, conn, sockindex); + if(!result) + *done = TRUE; } return result; @@ -1702,6 +1765,10 @@ static CURLcode ng_process_ingress(struct Curl_easy *data, rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts); if(rv) { /* TODO Send CONNECTION_CLOSE if possible */ + if(rv == NGTCP2_ERR_CRYPTO) + /* this is a "TLS problem", but a failed certificate verification + is a common reason for this */ + return CURLE_PEER_FAILED_VERIFICATION; return CURLE_RECV_ERROR; } } |
