]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
kdig: netio init quic connection ctx
authorJan Hák <jan.hak@nic.cz>
Mon, 2 May 2022 13:46:48 +0000 (15:46 +0200)
committerDaniel Salzman <daniel.salzman@nic.cz>
Wed, 22 Jun 2022 08:00:23 +0000 (10:00 +0200)
src/utils/common/netio.c
src/utils/common/netio.h
src/utils/common/quic.c
src/utils/common/quic.h
src/utils/common/tls.c
src/utils/common/tls.h
src/utils/kdig/kdig_exec.c
src/utils/knsupdate/knsupdate_exec.c

index 233b5d8d023088faf85948154f0f49e34f21459f..de0729b9070dd75e97e6ad2ce75fbd4847d331c3 100644 (file)
@@ -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,
index adea1f220c6aeda6dd374550351f5246b9209732..fae025120d1284d2b52d52b8e5dfc59950ec2552 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     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);
 
 /*!
index 0daa01b5c0b5c863deb744491573665832c88451..730aa8b63f70142b8773a285e172dba462035109 100644 (file)
     along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+#include <assert.h>
 #include <stddef.h>
+#include <gnutls/crypto.h>
+
+#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
index 56aee39732762e4e68eefe94541698240d85be91..8b7b537412e039b387c3711c40233c73807e0080 100644 (file)
@@ -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 <ngtcp2/ngtcp2.h>
+
+#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
index b792b0df4a9d66d342db3839648003b54c643345..e66fd3fc65007e5acf1c5d2ee83b7c8f748446e8 100644 (file)
@@ -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) {
index ddf3d4f5e19885387e4708c183cf304668f85dab..25201e261fa2c4fb6c2f2b910ee077f0a8861f48 100644 (file)
@@ -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);
index 2c463ae42f6ac3591420e1fd569c30c8f435315f..eb4031cb9c771902da68028b6c1b41762736c430 100644 (file)
@@ -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);
index 06bb9070c350d41a9b2fb37a014fbc1f736c3f72..3adfa30b168223e0128192a156f3f85fc06a6a46 100644 (file)
@@ -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;