Bug#1106788: unblock: ktls-utils/1.0.0-1 (7/10)
From
Ben Hutchings@1:229/2 to
All on Thu May 29 22:40:01 2025
[continued from previous message]
+static int quic_handshake_sendmsg(int sockfd, struct tlshd_quic_msg *msg)
+{
+ char outcmsg[CMSG_SPACE(sizeof(struct quic_handshake_info))];
+ struct quic_handshake_info *info;
+ struct msghdr outmsg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ int flags = 0;
+
+ outmsg.msg_name = NULL;
+ outmsg.msg_namelen = 0;
+ outmsg.msg_iov = &iov;
+ iov.iov_base = (void *)msg->data;
+ iov.iov_len = msg->len;
+ outmsg.msg_iovlen = 1;
+
+ outmsg.msg_control = outcmsg;
+ outmsg.msg_controllen = sizeof(outcmsg);
+ outmsg.msg_flags = 0;
+ if (msg->next)
+ flags = MSG_MORE;
+
+ cmsg = CMSG_FIRSTHDR(&outmsg);
+ cmsg->cmsg_level = SOL_QUIC;
+ cmsg->cmsg_type = QUIC_HANDSHAKE_INFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*info));
+
+ info = (struct quic_handshake_info *)CMSG_DATA(cmsg);
+ info->crypto_level = msg->level;
+
+ return sendmsg(sockfd, &outmsg, flags);
+}
+
+static int quic_handshake_recvmsg(int sockfd, struct tlshd_quic_msg *msg)
+{
+ char incmsg[CMSG_SPACE(sizeof(struct quic_handshake_info))];
+ struct quic_handshake_info info;
+ struct cmsghdr *cmsg = NULL;
+ struct msghdr inmsg;
+ struct iovec iov;
+ int ret;
+
+ msg->len = 0;
+ memset(&inmsg, 0, sizeof(inmsg));
+
+ iov.iov_base = msg->data;
+ iov.iov_len = sizeof(msg->data);
+
+ inmsg.msg_name = NULL;
+ inmsg.msg_namelen = 0;
+ inmsg.msg_iov = &iov;
+ inmsg.msg_iovlen = 1;
+ inmsg.msg_control = incmsg;
+ inmsg.msg_controllen = sizeof(incmsg);
+
+ ret = recvmsg(sockfd, &inmsg, MSG_DONTWAIT);
+ if (ret < 0)
+ return ret;
+ msg->len = ret;
+
+ for (cmsg = CMSG_FIRSTHDR(&inmsg); cmsg != NULL; cmsg = CMSG_NXTHDR(&inmsg, cmsg))
+ if (SOL_QUIC == cmsg->cmsg_level && QUIC_HANDSHAKE_INFO == cmsg->cmsg_type)
+ break;
+ if (cmsg) {
+ memcpy(&info, CMSG_DATA(cmsg), sizeof(info));
+ msg->level = info.crypto_level;
+ }
+
+ return ret;
+}
+
+static int quic_handshake_completed(struct tlshd_quic_conn *conn)
+{
+ return conn->completed || conn->errcode;
+}
+
+static int quic_handshake_crypto_data(struct tlshd_quic_conn *conn, uint8_t level,
+ const uint8_t *data, size_t datalen)
+{
+ gnutls_session_t session = conn->session;
+ int ret;
+
+ level = quic_get_encryption_level(level);
+ if (datalen > 0) {
+ ret = gnutls_handshake_write(session, level, data, datalen);
+ if (ret != 0) {
+ if (!gnutls_error_is_fatal(ret))
+ return 0;
+ goto err;
+ }
+ }
+
+ ret = gnutls_handshake(session);
+ if (ret < 0) {
+ if (!gnutls_error_is_fatal(ret))
+ return 0;
+ goto err;
+ }
+ return 0;
+err:
+ gnutls_alert_send_appropriate(session, ret);
+ tlshd_log_gnutls_error(ret);
+ return ret;
+}
+
+/**
+ * tlshd_quic_conn_create - Create a context for QUIC handshake
+ * @conn_p: pointer to accept the QUIC handshake context created
+ * @parms: handshake parameters
+ *
+ * Returns: %0 on success, or a negative error code
+ */
+int tlshd_quic_conn_create(struct tlshd_quic_conn **conn_p, struct tlshd_handshake_parms *parms)
+{
+ struct tlshd_quic_conn *conn;
+ int ret;
+
+ conn = malloc(sizeof(*conn));
+ if (!conn) {
+ tlshd_log_error("conn malloc error %d", ENOMEM);
+ return -ENOMEM;
+ }
+
+ memset(conn, 0, sizeof(*conn));
+ conn->parms = parms;
+
+ if (quic_conn_get_config(conn)) {
+ ret = -errno;
+ goto err;
+ }
+
+ if (quic_conn_setup_timer(conn)) {
+ ret = -errno;
+ goto err;
+ }
+
+ *conn_p = conn;
+ return 0;
+err:
+ tlshd_quic_conn_destroy(conn);
+ return ret;
+}
+
+/**
+ * tlshd_quic_conn_destroy - Destroy a context for QUIC handshake
+ * @conn: QUIC handshake context to destroy
+ *
+ */
+void tlshd_quic_conn_destroy(struct tlshd_quic_conn *conn)
+{
+ struct tlshd_quic_msg *msg = conn->send_list;
+
+ while (msg) {
+ conn->send_list = msg->next;
+ free(msg);
+ msg = conn->send_list;
+ }
+
+ quic_conn_delete_timer(conn);
+ gnutls_deinit(conn->session);
+ free(conn);
+}
+
+#define QUIC_TLSEXT_TP_PARAM 0x39u
+
+static int tlshd_quic_session_configure(struct tlshd_quic_conn *conn)
+{
+ gnutls_session_t session = conn->session;
+ int ret;
+
+ ret = quic_session_set_priority(session, conn->cipher);
+ if (ret)
+ return ret;
+
+ if (conn->alpns[0]) {
+ ret = quic_session_set_alpns(session, conn->alpns);
+ if (ret)
+ return ret;
+ }
+
+ gnutls_handshake_set_secret_function(session, quic_secret_func);
+ gnutls_handshake_set_read_function(session, quic_read_func);
+ gnutls_alert_set_read_function(session, quic_alert_read_func);
+
+ return gnutls_session_ext_register(
+ session, "QUIC Transport Parameters", QUIC_TLSEXT_TP_PARAM,
+ GNUTLS_EXT_TLS, quic_tp_recv_func, quic_tp_send_func, NULL, NULL, NULL,
+ GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_EE);
+}
+
+static void tlshd_quic_recv_session_ticket(struct tlshd_quic_conn *conn)
+{
+ gnutls_session_t session = conn->session;
+ int i, ret, sockfd = conn->parms->sockfd;
+ unsigned int len;
+ size_t size;
+
+ if (conn->is_serv || !conn->recv_ticket)
+ return;
+
+ for (i = 0; i < 10 * conn->recv_ticket; i++) { /* wait and try for conn->recv_ticket secs */
+ len = sizeof(conn->ticket);
+ ret = getsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_SESSION_TICKET, conn->ticket, &len);
+ if (ret) {
+ tlshd_log_error("socket getsockopt session ticket error %d", errno);
+ conn->errcode = errno;
+ return;
+ }
+ if (len)
+ break;
+ usleep(100000);
+ }
+ if (i == 10 * conn->recv_ticket)
+ return;
+
+ /* process new session ticket msg and get the generated session data */ + ret = quic_handshake_crypto_data(conn, QUIC_CRYPTO_APP, conn->ticket, len);
+ if (ret) {
+ conn->errcode = -ret;
+ return;
+ }
+ size = sizeof(conn->ticket);
+ ret = gnutls_session_get_data(session, conn->ticket, &size);
+ if (ret) {
+ tlshd_log_gnutls_error(ret);
+ conn->errcode = -ret;
+ return;
+ }
+
+ /* set it back to kernel for session resumption of next connection */
+ len = size;
+ ret = setsockopt(sockfd, SOL_QUIC, QUIC_SOCKOPT_SESSION_TICKET, conn->ticket, len);
+ if (ret) {
+ tlshd_log_error("socket setsockopt session ticket error %d %u", errno, len);
+ conn->errcode = errno;
+ }
+}
+
+/**
+ * tlshd_quic_start_handshake - Drive the handshake interaction
+ * @conn: QUIC handshake context
+ *
+ */
+void tlshd_quic_start_handshake(struct tlshd_quic_conn *conn)
+{
+ int ret, sockfd = conn->parms->sockfd;
+ struct timeval tv = {1, 0};
+ struct tlshd_quic_msg *msg;
+ fd_set readfds;
+
+ FD_ZERO(&readfds);
+ FD_SET(sockfd, &readfds);
+
+ ret = tlshd_quic_session_configure(conn);
+ if (ret) {
+ tlshd_log_gnutls_error(ret);
+ conn->errcode = -ret;
+ return;
+ }
+
+ if (!conn->is_serv) {
+ ret = quic_handshake_crypto_data(conn, QUIC_CRYPTO_INITIAL, NULL, 0);
+ if (ret) {
+ conn->errcode = -ret;
+ return;
+ }
+
+ msg = conn->send_list;
+ while (msg) {
+ tlshd_log_debug("< Handshake SEND: %d %d", msg->len, msg->level);
+ ret = quic_handshake_sendmsg(sockfd, msg);
+ if (ret < 0) {
+ tlshd_log_error("socket sendmsg error %d", errno);
+ conn->errcode = errno;
+ return;
+ }
+ conn->send_list = msg->next;
+ free(msg);
+ msg = conn->send_list;
+ }
+ }
+
+ while (!quic_handshake_completed(conn)) {
+ ret = select(sockfd + 1, &readfds, NULL, NULL, &tv);
+ if (ret < 0) {
+ conn->errcode = errno;
+ return tlshd_log_error("socket select error %d", errno);
+ }
+ msg = &conn->recv_msg;
+ while (!quic_handshake_completed(conn)) {
+ ret = quic_handshake_recvmsg(sockfd, msg);
+ if (ret <= 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
[continued in next message]
--- SoupGate-Win32 v1.05
* Origin: you cannot sedate... all the things you hate (1:229/2)