• 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)