knot_tls_pin@Base 3.4.0
knot_tls_pin_check@Base 3.4.0
knot_tls_priority@Base 3.4.7
- knot_tls_recv_dns@Base 3.4.0
- knot_tls_send_dns@Base 3.4.0
+ knot_tls_recv@Base 3.5.0
+ knot_tls_send@Base 3.5.0
knot_tls_session@Base 3.4.0
knot_tls_session_available@Base 3.4.1
knot_tls_session_load@Base 3.4.1
}
if (net_is_stream(req->fd) && req->tls_req_ctx.conn != NULL) {
- (void)knot_tls_send_dns(req->tls_req_ctx.conn,
- req->resp->wire, req->resp->size);
+ (void)knot_tls_send(req->tls_req_ctx.conn,
+ req->resp->wire, req->resp->size);
knot_tls_conn_block(req->tls_req_ctx.conn, false);
}
#ifdef ENABLE_QUIC
/* Send query. */
if (use_tls(request)) {
- ret = knot_tls_send_dns(request->tls_req_ctx.conn, wire, wire_len);
+ ret = knot_tls_send(request->tls_req_ctx.conn, wire, wire_len);
knot_tls_req_ctx_maint(&request->tls_req_ctx, request);
} else if (use_quic(request)) {
#ifdef ENABLE_QUIC
/* Receive it */
if (use_tls(request)) {
- ret = knot_tls_recv_dns(request->tls_req_ctx.conn, resp->wire, resp->max_size);
+ ret = knot_tls_recv(request->tls_req_ctx.conn, resp->wire, resp->max_size);
knot_tls_req_ctx_maint(&request->tls_req_ctx, request);
} else if (use_quic(request)) {
#ifdef ENABLE_QUIC
}
// Use HS = 4x IO timeout, as the RMT IO timeout is usually high.
- ctx->ctx = knot_tls_ctx_new(creds, io_timeout_ms, 4 * io_timeout_ms, false);
+ ctx->ctx = knot_tls_ctx_new(creds, io_timeout_ms, 4 * io_timeout_ms,
+ KNOT_TLS_CLIENT | KNOT_TLS_DNS | KNOT_TLS_EARLY_DATA);
if (ctx->ctx == NULL) {
knot_creds_free(creds);
return KNOT_ENOMEM;
case KNOT_NET_EAGAIN: // Unfinished handshake, continue later.
return KNOT_EOK;
case KNOT_EOK: // Finished handshake, continue with receiving message.
- recv = knot_tls_recv_dns(params->tls_conn, rx->iov_base, rx->iov_len);
+ recv = knot_tls_recv(params->tls_conn, rx->iov_base, rx->iov_len);
break;
default: // E.g. handshake timeout.
assert(ret < 0);
if (ans->size > 0 && send_state(tcp->layer.state)) {
int sent;
if (params->tls_conn != NULL) {
- sent = knot_tls_send_dns(params->tls_conn, ans->wire, ans->size);
+ sent = knot_tls_send(params->tls_conn, ans->wire, ans->size);
} else {
sent = net_dns_tcp_send(params->socket, ans->wire, ans->size,
tcp->io_timeout, NULL);
if (tls) {
// Set the HS timeout to 8x the RMT IO one as the HS duration can be up to 4*roundtrip.
tcp.tls_ctx = knot_tls_ctx_new(handler->server->quic_creds,
- tcp.io_timeout, 8 * tcp.io_timeout, true);
+ tcp.io_timeout, 8 * tcp.io_timeout,
+ KNOT_TLS_SERVER | KNOT_TLS_DNS | KNOT_TLS_EARLY_DATA);
if (tcp.tls_ctx == NULL) {
ret = KNOT_ENOMEM;
goto finish;
static int tls_init_conn_session(knot_quic_conn_t *conn, bool server)
{
int ret = knot_tls_session(&conn->tls_session, conn->quic_table->creds,
- conn->quic_table->priority, true,
- true, server);
+ conn->quic_table->priority,
+ (server ? KNOT_TLS_SERVER : KNOT_TLS_CLIENT) |
+ KNOT_TLS_QUIC | KNOT_TLS_DNS | KNOT_TLS_EARLY_DATA);
if (ret != KNOT_EOK) {
return TLS_CALLBACK_ERR;
}
_public_
knot_tls_ctx_t *knot_tls_ctx_new(struct knot_creds *creds, unsigned io_timeout,
- unsigned hs_timeout, bool server)
+ unsigned hs_timeout, knot_tls_flag_t flags)
{
knot_tls_ctx_t *res = calloc(1, sizeof(*res));
if (res == NULL) {
res->creds = creds;
res->handshake_timeout = hs_timeout;
res->io_timeout = io_timeout;
- res->server = server;
+ res->flags = flags;
int ret = gnutls_priority_init2(&res->priority, knot_tls_priority(false), NULL,
GNUTLS_PRIORITY_INIT_DEF_APPEND);
res->fd = sock_fd;
int ret = knot_tls_session(&res->session, ctx->creds, ctx->priority,
- false, true, ctx->server);
+ ctx->flags);
if (ret != KNOT_EOK) {
goto fail;
}
*timeout_ptr = MAX(*timeout_ptr - running_ms, 0); \
}
-static ssize_t recv_data(knot_tls_conn_t *conn, void *data, size_t size, int *timeout_ptr)
+static ssize_t recv_data(knot_tls_conn_t *conn, void *data, size_t size,
+ int *timeout_ptr, bool oneshot)
{
gnutls_record_set_timeout(conn->session, *timeout_ptr);
TIMEOUT_CTX_INIT
res = gnutls_record_recv(conn->session, data + total, size - total);
if (res > 0) {
+ if (oneshot) {
+ return res;
+ }
total += res;
} else if (res == 0) {
return KNOT_ECONNRESET;
}
_public_
-ssize_t knot_tls_recv_dns(knot_tls_conn_t *conn, void *data, size_t size)
+ssize_t knot_tls_recv(knot_tls_conn_t *conn, void *data, size_t size)
{
if (conn == NULL || data == NULL) {
return KNOT_EINVAL;
int timeout = conn->ctx->io_timeout;
- uint16_t msg_len;
- ret = recv_data(conn, &msg_len, sizeof(msg_len), &timeout);
- if (ret != sizeof(msg_len)) {
- return ret;
- }
+ if (conn->ctx->flags & KNOT_TLS_DNS) {
+ uint16_t msg_len;
+ ret = recv_data(conn, &msg_len, sizeof(msg_len), &timeout, false);
+ if (ret != sizeof(msg_len)) {
+ return ret;
+ }
- msg_len = ntohs(msg_len);
- if (size < msg_len) {
- return KNOT_ESPACE;
- }
+ msg_len = ntohs(msg_len);
+ if (size < msg_len) {
+ return KNOT_ESPACE;
+ }
- ret = recv_data(conn, data, msg_len, &timeout);
- if (ret != size) {
- return ret;
- }
+ ret = recv_data(conn, data, msg_len, &timeout, false);
+ if (ret != size) {
+ return ret;
+ }
- return msg_len;
+ return msg_len;
+ } else {
+ return recv_data(conn, data, size, &timeout, true);
+ }
}
_public_
-ssize_t knot_tls_send_dns(knot_tls_conn_t *conn, void *data, size_t size)
+ssize_t knot_tls_send(knot_tls_conn_t *conn, void *data, size_t size)
{
if (conn == NULL || data == NULL || size > UINT16_MAX) {
return KNOT_EINVAL;
// Enable data buffering.
gnutls_record_cork(conn->session);
- uint16_t msg_len = htons(size);
- res = gnutls_record_send(conn->session, &msg_len, sizeof(msg_len));
- if (res != sizeof(msg_len)) {
- return KNOT_NET_ESEND;
+ if (conn->ctx->flags & KNOT_TLS_DNS) {
+ uint16_t msg_len = htons(size);
+ res = gnutls_record_send(conn->session, &msg_len, sizeof(msg_len));
+ if (res != sizeof(msg_len)) {
+ return KNOT_NET_ESEND;
+ }
}
res = gnutls_record_send(conn->session, data, size);
#include <stdint.h>
#include <sys/types.h>
+#include <libknot/quic/tls_common.h>
+
struct gnutls_priority_st;
typedef enum {
typedef struct knot_tls_ctx {
struct knot_creds *creds;
struct gnutls_priority_st *priority;
+ knot_tls_flag_t flags;
unsigned handshake_timeout;
unsigned io_timeout;
- bool server;
} knot_tls_ctx_t;
typedef struct knot_tls_conn {
* \param creds Certificate credentials.
* \param io_timeout Connections' IO-timeout (in milliseconds).
* \param hs_timeout Handshake timeout (in milliseconds).
- * \param server Server context (otherwise client).
+ * \param flags Specify client/server mode and common/dns format.
*
* \return Initialized context or NULL.
*/
knot_tls_ctx_t *knot_tls_ctx_new(struct knot_creds *creds, unsigned io_timeout,
- unsigned hs_timeout, bool server);
+ unsigned hs_timeout, knot_tls_flag_t flags);
/*!
* \brief Free DoT answering context.
int knot_tls_handshake(knot_tls_conn_t *conn, bool oneshot);
/*!
- * \brief Receive a size-word-prefixed DNS message.
+ * \brief Receive a data blob.
+ *
+ * \note In the DNS mode, the two-byte-size prefix is stripped upon reception,
+ * not stored to the buffer.
*
* \param conn DoT connection.
* \param data Destination buffer.
* \param size Maximum buffer size.
*
* \return Either the DNS message size received or negative error code.
- *
- * \note The two-byte-size-prefix is stripped upon reception, not stored to the buffer.
*/
-ssize_t knot_tls_recv_dns(knot_tls_conn_t *conn, void *data, size_t size);
+ssize_t knot_tls_recv(knot_tls_conn_t *conn, void *data, size_t size);
/*!
- * \brief Send a size-word-prefixed DNS message.
+ * \brief Send a data blob.
+ *
+ * \note In the DNS mode, the two-byte-size prefix is sended before the data
+ * blob itself.
*
* \param conn DoT connection.
* \param data DNS payload.
*
* \return Either exactly 'size' or a negative error code.
*/
-ssize_t knot_tls_send_dns(knot_tls_conn_t *conn, void *data, size_t size);
+ssize_t knot_tls_send(knot_tls_conn_t *conn, void *data, size_t size);
/*!
* \brief Set or unset the conection's BLOCKED flag.
int knot_tls_session(struct gnutls_session_int **session,
struct knot_creds *creds,
struct gnutls_priority_st *priority,
- bool quic,
- bool early_data,
- bool server)
+ knot_tls_flag_t flags)
{
if (session == NULL || creds == NULL || priority == NULL) {
return KNOT_EINVAL;
}
- const char *alpn = quic ? "\x03""doq" : "\x03""dot";
- gnutls_init_flags_t flags = GNUTLS_NO_SIGNAL;
+ bool server = flags & KNOT_TLS_SERVER;
+ bool quic = flags & KNOT_TLS_QUIC;
+ bool early_data = flags & KNOT_TLS_EARLY_DATA;
+
+ const char *alpn = NULL;
+ if (flags & KNOT_TLS_DNS) {
+ alpn = quic ? "\x03""doq" : "\x03""dot";
+ }
+
+ gnutls_init_flags_t tls_flags = GNUTLS_NO_SIGNAL;
if (early_data) {
- flags |= GNUTLS_ENABLE_EARLY_DATA;
+ tls_flags |= GNUTLS_ENABLE_EARLY_DATA;
#ifdef ENABLE_QUIC // Next flags aren't available in older GnuTLS versions.
if (quic) {
- flags |= GNUTLS_NO_END_OF_EARLY_DATA;
+ tls_flags |= GNUTLS_NO_END_OF_EARLY_DATA;
}
#endif
}
- int ret = gnutls_init(session, (server ? GNUTLS_SERVER : GNUTLS_CLIENT) | flags);
+ int ret = gnutls_init(session, (server ? GNUTLS_SERVER : GNUTLS_CLIENT) | tls_flags);
if (ret == GNUTLS_E_SUCCESS) {
gnutls_certificate_send_x509_rdn_sequence(*session, 1);
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_REQUEST);
ret = gnutls_session_ticket_enable_server(*session, &creds->tls_ticket_key);
}
if (ret == GNUTLS_E_SUCCESS) {
- const gnutls_datum_t alpn_datum = { (void *)&alpn[1], alpn[0] };
- gnutls_alpn_set_protocols(*session, &alpn_datum, 1, GNUTLS_ALPN_MANDATORY);
+ if (alpn != NULL) {
+ const gnutls_datum_t alpn_datum = { (void *)&alpn[1], alpn[0] };
+ gnutls_alpn_set_protocols(*session, &alpn_datum, 1, GNUTLS_ALPN_MANDATORY);
+ }
if (early_data) {
gnutls_record_set_max_early_data_size(*session, 0xffffffffu);
}
struct knot_creds;
struct knot_tls_session;
+typedef enum {
+ KNOT_TLS_CLIENT = 0,
+ KNOT_TLS_SERVER = (1 << 0),
+ KNOT_TLS_QUIC = (1 << 1),
+ KNOT_TLS_DNS = (1 << 2),
+ KNOT_TLS_EARLY_DATA = (1 << 3),
+} knot_tls_flag_t;
+
/*!
* \brief Get priority string for GnuTLS priority initialization.
*
* \param session Out: initialized GnuTLS session struct.
* \param creds Certificate credentials.
* \param priority Session priority configuration.
- * \param quic Session is for ngtcp2/QUIC (otherwise TLS).
- * \param early_data Allow early data.
- * \param server Should be server session (otherwise client).
+ * \param flags TLS-related flags.
*
* \return KNOT_E*
*/
int knot_tls_session(struct gnutls_session_int **session,
struct knot_creds *creds,
struct gnutls_priority_st *priority,
- bool quic,
- bool early_data,
- bool server);
+ knot_tls_flag_t flags);
/*!
* \brief Gets local or remote certificate pin.