From: Jan Hák Date: Mon, 2 May 2022 13:46:48 +0000 (+0200) Subject: kdig: netio init quic connection ctx X-Git-Tag: v3.3.dev~92^2~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c6063eacaaa26cfb48177ead86c4d5f2f014af60;p=thirdparty%2Fknot-dns.git kdig: netio init quic connection ctx --- diff --git a/src/utils/common/netio.c b/src/utils/common/netio.c index 233b5d8d02..de0729b907 100644 --- a/src/utils/common/netio.c +++ b/src/utils/common/netio.c @@ -179,6 +179,7 @@ int net_init(const srv_info_t *local, const net_flags_t flags, const tls_params_t *tls_params, const https_params_t *https_params, + const quic_params_t *quic_params, net_t *net) { if (remote == NULL || net == NULL) { @@ -236,6 +237,23 @@ int net_init(const srv_info_t *local, } } else #endif //LIBNGHTTP2 +#ifdef LIBNGTCP2 + if (quic_params != NULL && quic_params->enable) { + ret = tls_ctx_init(&net->tls, tls_params, + GNUTLS_NONBLOCK | GNUTLS_ENABLE_EARLY_DATA | + GNUTLS_NO_END_OF_EARLY_DATA, net->wait, + quic_alpn, 4, QUIC_PRIORITY); // TODO will be 1 on release + if (ret != KNOT_EOK) { + net_clean(net); + return ret; + } + ret = quic_ctx_init(&net->quic, &net->tls, quic_params); + if (ret != KNOT_EOK) { + net_clean(net); + return ret; + } + } else +#endif //LIBNGTCP2 { ret = tls_ctx_init(&net->tls, tls_params, GNUTLS_NONBLOCK, net->wait, diff --git a/src/utils/common/netio.h b/src/utils/common/netio.h index adea1f220c..fae025120d 100644 --- a/src/utils/common/netio.h +++ b/src/utils/common/netio.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 CZ.NIC, z.s.p.o. +/* Copyright (C) 2022 CZ.NIC, z.s.p.o. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ #include "utils/common/https.h" #include "utils/common/params.h" +#include "utils/common/quic.h" #include "utils/common/tls.h" /*! \brief Structure containing server information. */ @@ -80,6 +81,10 @@ typedef struct { /*! HTTPS context. */ https_ctx_t https; #endif +#ifdef LIBNGTCP2 + /*! QUIC context. */ + quic_ctx_t quic; +#endif } net_t; /*! @@ -164,6 +169,7 @@ int net_init(const srv_info_t *local, const net_flags_t flags, const tls_params_t *tls_params, const https_params_t *https_params, + const quic_params_t *quic_params, net_t *net); /*! diff --git a/src/utils/common/quic.c b/src/utils/common/quic.c index 0daa01b5c0..730aa8b63f 100644 --- a/src/utils/common/quic.c +++ b/src/utils/common/quic.c @@ -14,7 +14,13 @@ along with this program. If not, see . */ +#include #include +#include + +#include "libdnssec/error.h" +#include "libdnssec/random.h" + #include "libknot/errcode.h" #include "utils/common/quic.h" @@ -37,3 +43,79 @@ void quic_params_clean(quic_params_t *params) params->enable = false; } + +#ifdef LIBNGTCP2 + +const gnutls_datum_t quic_alpn[] = { + { + .data = (unsigned char *)"doq", + .size = 3 + },{ + .data = (unsigned char *)"doq-i12", + .size = 7 + },{ + .data = (unsigned char *)"doq-i11", + .size = 7 + },{ + .data = (unsigned char *)"doq-i03", + .size = 7 + } +}; + +uint64_t quic_timestamp(void) +{ + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { + return 0; + } + + return (uint64_t)ts.tv_sec * NGTCP2_SECONDS + (uint64_t)ts.tv_nsec; +} + +int quic_generate_secret(uint8_t *buf, size_t buflen) +{ + assert(buf != NULL && buflen > 0 && buflen <= 32); + uint8_t rand[16], hash[32]; + int ret = dnssec_random_buffer(rand, sizeof(rand)); + if (ret != DNSSEC_EOK) { + return ret; + } + ret = gnutls_hash_fast(GNUTLS_DIG_SHA256, rand, sizeof(rand), hash); + if (ret != 0) { + return ret; + } + memcpy(buf, hash, buflen); + return KNOT_EOK; +} + + +static int verify_certificate(gnutls_session_t session) +{ + quic_ctx_t *ctx = gnutls_session_get_ptr(session); + return tls_certificate_verification(ctx->tls); +} + +int quic_ctx_init(quic_ctx_t *ctx, tls_ctx_t *tls_ctx, const quic_params_t *params) +{ + if (ctx == NULL || tls_ctx == NULL || params == NULL) { + return KNOT_EINVAL; + } + + ctx->params = *params; + ctx->tls = tls_ctx; + ctx->state = OPENING; + ctx->stream.id = -1; + ctx->timestamp = quic_timestamp(); + if (quic_generate_secret(ctx->secret, sizeof(ctx->secret)) != KNOT_EOK) { + tls_ctx_deinit(ctx->tls); + return KNOT_ENOMEM; + } + + gnutls_certificate_set_verify_function(tls_ctx->credentials, + verify_certificate); + + return KNOT_EOK; +} + + +#endif diff --git a/src/utils/common/quic.h b/src/utils/common/quic.h index 56aee39732..8b7b537412 100644 --- a/src/utils/common/quic.h +++ b/src/utils/common/quic.h @@ -28,3 +28,54 @@ int quic_params_copy(quic_params_t *dst, const quic_params_t *src); void quic_params_clean(quic_params_t *params); +#ifdef LIBNGTCP2 + +#include + +#include "utils/common/tls.h" + +#define QUIC_DEFAULT_VERSION "-VERS-ALL:+VERS-TLS1.3" +#define QUIC_DEFAULT_CIPHERS "-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:+CHACHA20-POLY1305:+AES-128-CCM" +#define QUIC_DEFAULT_GROUPS "-GROUP-ALL:+GROUP-SECP256R1:+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1" +#define QUIC_PRIORITY "%DISABLE_TLS13_COMPAT_MODE:NORMAL:"QUIC_DEFAULT_VERSION":"QUIC_DEFAULT_CIPHERS":"QUIC_DEFAULT_GROUPS + + +typedef enum { + OPENING, + CONNECTED, + CLOSING +} quic_state_t; + +typedef struct { + // Parameters + quic_params_t params; + + // Context + ngtcp2_settings settings; + struct { + int64_t id; + uint64_t out_ack; + struct iovec in_buffer; + struct iovec *in_parsed; + size_t in_parsed_size; + size_t in_parsed_total; + size_t in_parsed_it; + } stream; + ngtcp2_connection_close_error last_err; + uint8_t secret[32]; + tls_ctx_t *tls; + ngtcp2_conn *conn; + ngtcp2_pkt_info pi; + quic_state_t state; + uint64_t idle_ts; +} quic_ctx_t; + +extern const gnutls_datum_t quic_alpn[]; + +uint64_t quic_timestamp(void); + +int quic_generate_secret(uint8_t *buf, size_t buflen); + +int quic_ctx_init(quic_ctx_t *ctx, tls_ctx_t *tls_ctx, const quic_params_t *params); + +#endif //LIBNGTCP2 diff --git a/src/utils/common/tls.c b/src/utils/common/tls.c index b792b0df4a..e66fd3fc65 100644 --- a/src/utils/common/tls.c +++ b/src/utils/common/tls.c @@ -367,10 +367,9 @@ static bool do_verification(const tls_params_t *params) !EMPTY_LIST(params->ca_files) || params->ocsp_stapling > 0; } -static int verify_certificate(gnutls_session_t session) +int tls_certificate_verification(tls_ctx_t *ctx) { - tls_ctx_t *ctx = gnutls_session_get_ptr(session); - + gnutls_session_t session = ctx->session; // Check for pinned certificates and print certificate hierarchy. int ret = check_certificates(session, &ctx->params->pins); if (ret != GNUTLS_E_SUCCESS) { @@ -421,6 +420,12 @@ static int verify_certificate(gnutls_session_t session) return GNUTLS_E_SUCCESS; } +static int verify_certificate(gnutls_session_t session) +{ + tls_ctx_t *ctx = gnutls_session_get_ptr(session); + return tls_certificate_verification(ctx); +} + int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params, unsigned int flags, int wait, const gnutls_datum_t *alpn, size_t alpn_size, const char *priority) @@ -468,7 +473,7 @@ int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params, } } - // gnutls_certificate_set_verify_function(ctx->credentials, verify_certificate); + gnutls_certificate_set_verify_function(ctx->credentials, verify_certificate); // Setup client keypair if specified. Both key and cert files must be provided. if (params->keyfile != NULL && params->certfile != NULL) { diff --git a/src/utils/common/tls.h b/src/utils/common/tls.h index ddf3d4f5e1..25201e261f 100644 --- a/src/utils/common/tls.h +++ b/src/utils/common/tls.h @@ -65,6 +65,8 @@ void tls_params_init(tls_params_t *params); int tls_params_copy(tls_params_t *dst, const tls_params_t *src); void tls_params_clean(tls_params_t *params); +int tls_certificate_verification(tls_ctx_t *ctx); + int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params, unsigned int flags, int wait, const gnutls_datum_t *alpn, size_t alpn_size, const char *priority); diff --git a/src/utils/kdig/kdig_exec.c b/src/utils/kdig/kdig_exec.c index 2c463ae42f..eb4031cb9c 100644 --- a/src/utils/kdig/kdig_exec.c +++ b/src/utils/kdig/kdig_exec.c @@ -862,7 +862,8 @@ static int process_query(const query_t *query, net_t *net) for (size_t i = 0; i <= query->retries; i++) { // Initialize network structure for current server. ret = net_init(query->local, remote, iptype, socktype, - query->wait, flags, &query->tls, &query->https, net); + query->wait, flags, &query->tls, + &query->https, &query->quic, net); if (ret != KNOT_EOK) { if (ret == KNOT_NET_EADDR) { // Requested address family not available. @@ -1171,7 +1172,7 @@ static int process_xfr(const query_t *query, net_t *net) // Initialize network structure. ret = net_init(query->local, remote, iptype, socktype, query->wait, - flags, &query->tls, &query->https, net); + flags, &query->tls, &query->https, &query->quic, net); if (ret != KNOT_EOK) { sign_context_deinit(&sign_ctx); knot_pkt_free(out_packet); diff --git a/src/utils/knsupdate/knsupdate_exec.c b/src/utils/knsupdate/knsupdate_exec.c index 06bb9070c3..3adfa30b16 100644 --- a/src/utils/knsupdate/knsupdate_exec.c +++ b/src/utils/knsupdate/knsupdate_exec.c @@ -438,6 +438,7 @@ static int pkt_sendrecv(knsupdate_params_t *params) NET_FLAGS_NONE, NULL, NULL, + NULL, &net); if (ret != KNOT_EOK) { return -1;