Commit 3b3009ea authored by Chuck Lever's avatar Chuck Lever Committed by Jakub Kicinski
Browse files

net/handshake: Create a NETLINK service for handling handshake requests



When a kernel consumer needs a transport layer security session, it
first needs a handshake to negotiate and establish a session. This
negotiation can be done in user space via one of the several
existing library implementations, or it can be done in the kernel.

No in-kernel handshake implementations yet exist. In their absence,
we add a netlink service that can:

a. Notify a user space daemon that a handshake is needed.

b. Once notified, the daemon calls the kernel back via this
   netlink service to get the handshake parameters, including an
   open socket on which to establish the session.

c. Once the handshake is complete, the daemon reports the
   session status and other information via a second netlink
   operation. This operation marks that it is safe for the
   kernel to use the open socket and the security session
   established there.

The notification service uses a multicast group. Each handshake
mechanism (eg, tlshd) adopts its own group number so that the
handshake services are completely independent of one another. The
kernel can then tell via netlink_has_listeners() whether a handshake
service is active and prepared to handle a handshake request.

A new netlink operation, ACCEPT, acts like accept(2) in that it
instantiates a file descriptor in the user space daemon's fd table.
If this operation is successful, the reply carries the fd number,
which can be treated as an open and ready file descriptor.

While user space is performing the handshake, the kernel keeps its
muddy paws off the open socket. A second new netlink operation,
DONE, indicates that the user space daemon is finished with the
socket and it is safe for the kernel to use again. The operation
also indicates whether a session was established successfully.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 2bc42f48
Loading
Loading
Loading
Loading
+122 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
#
# Author: Chuck Lever <chuck.lever@oracle.com>
#
# Copyright (c) 2023, Oracle and/or its affiliates.
#

name: handshake

protocol: genetlink

doc: Netlink protocol to request a transport layer security handshake.

definitions:
  -
    type: enum
    name: handler-class
    value-start: 0
    entries: [ none, max ]
  -
    type: enum
    name: msg-type
    value-start: 0
    entries: [ unspec, clienthello, serverhello ]
  -
    type: enum
    name: auth
    value-start: 0
    entries: [ unspec, unauth, psk, x509 ]

attribute-sets:
  -
    name: x509
    attributes:
      -
        name: cert
        type: u32
      -
        name: privkey
        type: u32
  -
    name: accept
    attributes:
      -
        name: sockfd
        type: u32
      -
        name: handler-class
        type: u32
        enum: handler-class
      -
        name: message-type
        type: u32
        enum: msg-type
      -
        name: timeout
        type: u32
      -
        name: auth-mode
        type: u32
        enum: auth
      -
        name: peer-identity
        type: u32
        multi-attr: true
      -
        name: certificate
        type: nest
        nested-attributes: x509
        multi-attr: true
  -
    name: done
    attributes:
      -
        name: status
        type: u32
      -
        name: sockfd
        type: u32
      -
        name: remote-auth
        type: u32
        multi-attr: true

operations:
  list:
    -
      name: ready
      doc: Notify handlers that a new handshake request is waiting
      notify: accept
    -
      name: accept
      doc: Handler retrieves next queued handshake request
      attribute-set: accept
      flags: [ admin-perm ]
      do:
        request:
          attributes:
            - handler-class
        reply:
          attributes:
            - sockfd
            - message-type
            - timeout
            - auth-mode
            - peer-identity
            - certificate
    -
      name: done
      doc: Handler reports handshake completion
      attribute-set: done
      do:
        request:
          attributes:
            - status
            - sockfd
            - remote-auth

mcast-groups:
  list:
    -
      name: none
+9 −0
Original line number Diff line number Diff line
@@ -8947,6 +8947,15 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/
T:	git git://linuxtv.org/anttip/media_tree.git
F:	drivers/media/usb/hackrf/
HANDSHAKE UPCALL FOR TRANSPORT LAYER SECURITY
M:	Chuck Lever <chuck.lever@oracle.com>
L:	kernel-tls-handshake@lists.linux.dev
L:	netdev@vger.kernel.org
S:	Maintained
F:	Documentation/netlink/specs/handshake.yaml
F:	include/trace/events/handshake.h
F:	net/handshake/
HANTRO VPU CODEC DRIVER
M:	Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
M:	Philipp Zabel <p.zabel@pengutronix.de>
+159 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM handshake

#if !defined(_TRACE_HANDSHAKE_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HANDSHAKE_H

#include <linux/net.h>
#include <linux/tracepoint.h>

DECLARE_EVENT_CLASS(handshake_event_class,
	TP_PROTO(
		const struct net *net,
		const struct handshake_req *req,
		const struct sock *sk
	),
	TP_ARGS(net, req, sk),
	TP_STRUCT__entry(
		__field(const void *, req)
		__field(const void *, sk)
		__field(unsigned int, netns_ino)
	),
	TP_fast_assign(
		__entry->req = req;
		__entry->sk = sk;
		__entry->netns_ino = net->ns.inum;
	),
	TP_printk("req=%p sk=%p",
		__entry->req, __entry->sk
	)
);
#define DEFINE_HANDSHAKE_EVENT(name)				\
	DEFINE_EVENT(handshake_event_class, name,		\
		TP_PROTO(					\
			const struct net *net,			\
			const struct handshake_req *req,	\
			const struct sock *sk			\
		),						\
		TP_ARGS(net, req, sk))

DECLARE_EVENT_CLASS(handshake_fd_class,
	TP_PROTO(
		const struct net *net,
		const struct handshake_req *req,
		const struct sock *sk,
		int fd
	),
	TP_ARGS(net, req, sk, fd),
	TP_STRUCT__entry(
		__field(const void *, req)
		__field(const void *, sk)
		__field(int, fd)
		__field(unsigned int, netns_ino)
	),
	TP_fast_assign(
		__entry->req = req;
		__entry->sk = req->hr_sk;
		__entry->fd = fd;
		__entry->netns_ino = net->ns.inum;
	),
	TP_printk("req=%p sk=%p fd=%d",
		__entry->req, __entry->sk, __entry->fd
	)
);
#define DEFINE_HANDSHAKE_FD_EVENT(name)				\
	DEFINE_EVENT(handshake_fd_class, name,			\
		TP_PROTO(					\
			const struct net *net,			\
			const struct handshake_req *req,	\
			const struct sock *sk,			\
			int fd					\
		),						\
		TP_ARGS(net, req, sk, fd))

DECLARE_EVENT_CLASS(handshake_error_class,
	TP_PROTO(
		const struct net *net,
		const struct handshake_req *req,
		const struct sock *sk,
		int err
	),
	TP_ARGS(net, req, sk, err),
	TP_STRUCT__entry(
		__field(const void *, req)
		__field(const void *, sk)
		__field(int, err)
		__field(unsigned int, netns_ino)
	),
	TP_fast_assign(
		__entry->req = req;
		__entry->sk = sk;
		__entry->err = err;
		__entry->netns_ino = net->ns.inum;
	),
	TP_printk("req=%p sk=%p err=%d",
		__entry->req, __entry->sk, __entry->err
	)
);
#define DEFINE_HANDSHAKE_ERROR(name)				\
	DEFINE_EVENT(handshake_error_class, name,		\
		TP_PROTO(					\
			const struct net *net,			\
			const struct handshake_req *req,	\
			const struct sock *sk,			\
			int err					\
		),						\
		TP_ARGS(net, req, sk, err))


/*
 * Request lifetime events
 */

DEFINE_HANDSHAKE_EVENT(handshake_submit);
DEFINE_HANDSHAKE_ERROR(handshake_submit_err);
DEFINE_HANDSHAKE_EVENT(handshake_cancel);
DEFINE_HANDSHAKE_EVENT(handshake_cancel_none);
DEFINE_HANDSHAKE_EVENT(handshake_cancel_busy);
DEFINE_HANDSHAKE_EVENT(handshake_destruct);


TRACE_EVENT(handshake_complete,
	TP_PROTO(
		const struct net *net,
		const struct handshake_req *req,
		const struct sock *sk,
		int status
	),
	TP_ARGS(net, req, sk, status),
	TP_STRUCT__entry(
		__field(const void *, req)
		__field(const void *, sk)
		__field(int, status)
		__field(unsigned int, netns_ino)
	),
	TP_fast_assign(
		__entry->req = req;
		__entry->sk = sk;
		__entry->status = status;
		__entry->netns_ino = net->ns.inum;
	),
	TP_printk("req=%p sk=%p status=%d",
		__entry->req, __entry->sk, __entry->status
	)
);

/*
 * Netlink events
 */

DEFINE_HANDSHAKE_ERROR(handshake_notify_err);
DEFINE_HANDSHAKE_FD_EVENT(handshake_cmd_accept);
DEFINE_HANDSHAKE_ERROR(handshake_cmd_accept_err);
DEFINE_HANDSHAKE_FD_EVENT(handshake_cmd_done);
DEFINE_HANDSHAKE_ERROR(handshake_cmd_done_err);

#endif /* _TRACE_HANDSHAKE_H */

#include <trace/define_trace.h>
+71 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/* Do not edit directly, auto-generated from: */
/*	Documentation/netlink/specs/handshake.yaml */
/* YNL-GEN uapi header */

#ifndef _UAPI_LINUX_HANDSHAKE_H
#define _UAPI_LINUX_HANDSHAKE_H

#define HANDSHAKE_FAMILY_NAME		"handshake"
#define HANDSHAKE_FAMILY_VERSION	1

enum handshake_handler_class {
	HANDSHAKE_HANDLER_CLASS_NONE,
	HANDSHAKE_HANDLER_CLASS_MAX,
};

enum handshake_msg_type {
	HANDSHAKE_MSG_TYPE_UNSPEC,
	HANDSHAKE_MSG_TYPE_CLIENTHELLO,
	HANDSHAKE_MSG_TYPE_SERVERHELLO,
};

enum handshake_auth {
	HANDSHAKE_AUTH_UNSPEC,
	HANDSHAKE_AUTH_UNAUTH,
	HANDSHAKE_AUTH_PSK,
	HANDSHAKE_AUTH_X509,
};

enum {
	HANDSHAKE_A_X509_CERT = 1,
	HANDSHAKE_A_X509_PRIVKEY,

	__HANDSHAKE_A_X509_MAX,
	HANDSHAKE_A_X509_MAX = (__HANDSHAKE_A_X509_MAX - 1)
};

enum {
	HANDSHAKE_A_ACCEPT_SOCKFD = 1,
	HANDSHAKE_A_ACCEPT_HANDLER_CLASS,
	HANDSHAKE_A_ACCEPT_MESSAGE_TYPE,
	HANDSHAKE_A_ACCEPT_TIMEOUT,
	HANDSHAKE_A_ACCEPT_AUTH_MODE,
	HANDSHAKE_A_ACCEPT_PEER_IDENTITY,
	HANDSHAKE_A_ACCEPT_CERTIFICATE,

	__HANDSHAKE_A_ACCEPT_MAX,
	HANDSHAKE_A_ACCEPT_MAX = (__HANDSHAKE_A_ACCEPT_MAX - 1)
};

enum {
	HANDSHAKE_A_DONE_STATUS = 1,
	HANDSHAKE_A_DONE_SOCKFD,
	HANDSHAKE_A_DONE_REMOTE_AUTH,

	__HANDSHAKE_A_DONE_MAX,
	HANDSHAKE_A_DONE_MAX = (__HANDSHAKE_A_DONE_MAX - 1)
};

enum {
	HANDSHAKE_CMD_READY = 1,
	HANDSHAKE_CMD_ACCEPT,
	HANDSHAKE_CMD_DONE,

	__HANDSHAKE_CMD_MAX,
	HANDSHAKE_CMD_MAX = (__HANDSHAKE_CMD_MAX - 1)
};

#define HANDSHAKE_MCGRP_NONE	"none"

#endif /* _UAPI_LINUX_HANDSHAKE_H */
+5 −0
Original line number Diff line number Diff line
@@ -68,6 +68,11 @@ source "net/iucv/Kconfig"
source "net/smc/Kconfig"
source "net/xdp/Kconfig"

config NET_HANDSHAKE
	bool
	depends on SUNRPC || NVME_TARGET_TCP || NVME_TCP
	default y

config INET
	bool "TCP/IP networking"
	help
Loading