File Index
Files and directories
Sign in
FILE

tlshd.c

File preview with syntax highlighting.

linux-6.19.14/net/handshake/tlshd.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Establish a TLS session for a kernel socket consumer
  4 * using the tlshd user space handler.
  5 *
  6 * Author: Chuck Lever <chuck.lever@oracle.com>
  7 *
  8 * Copyright (c) 2021-2023, Oracle and/or its affiliates.
  9 */
 10
 11#include <linux/types.h>
 12#include <linux/socket.h>
 13#include <linux/kernel.h>
 14#include <linux/module.h>
 15#include <linux/slab.h>
 16#include <linux/key.h>
 17
 18#include <net/sock.h>
 19#include <net/handshake.h>
 20#include <net/genetlink.h>
 21#include <net/tls_prot.h>
 22
 23#include <uapi/linux/keyctl.h>
 24#include <uapi/linux/handshake.h>
 25#include "handshake.h"
 26
 27struct tls_handshake_req {
 28	void			(*th_consumer_done)(void *data, int status,
 29						    key_serial_t peerid);
 30	void			*th_consumer_data;
 31
 32	int			th_type;
 33	unsigned int		th_timeout_ms;
 34	int			th_auth_mode;
 35	const char		*th_peername;
 36	key_serial_t		th_keyring;
 37	key_serial_t		th_certificate;
 38	key_serial_t		th_privkey;
 39
 40	unsigned int		th_num_peerids;
 41	key_serial_t		th_peerid[5];
 42};
 43
 44static struct tls_handshake_req *
 45tls_handshake_req_init(struct handshake_req *req,
 46		       const struct tls_handshake_args *args)
 47{
 48	struct tls_handshake_req *treq = handshake_req_private(req);
 49
 50	treq->th_timeout_ms = args->ta_timeout_ms;
 51	treq->th_consumer_done = args->ta_done;
 52	treq->th_consumer_data = args->ta_data;
 53	treq->th_peername = args->ta_peername;
 54	treq->th_keyring = args->ta_keyring;
 55	treq->th_num_peerids = 0;
 56	treq->th_certificate = TLS_NO_CERT;
 57	treq->th_privkey = TLS_NO_PRIVKEY;
 58	return treq;
 59}
 60
 61static void tls_handshake_remote_peerids(struct tls_handshake_req *treq,
 62					 struct genl_info *info)
 63{
 64	struct nlattr *head = nlmsg_attrdata(info->nlhdr, GENL_HDRLEN);
 65	int rem, len = nlmsg_attrlen(info->nlhdr, GENL_HDRLEN);
 66	struct nlattr *nla;
 67	unsigned int i;
 68
 69	i = 0;
 70	nla_for_each_attr(nla, head, len, rem) {
 71		if (nla_type(nla) == HANDSHAKE_A_DONE_REMOTE_AUTH)
 72			i++;
 73	}
 74	if (!i)
 75		return;
 76	treq->th_num_peerids = min_t(unsigned int, i,
 77				     ARRAY_SIZE(treq->th_peerid));
 78
 79	i = 0;
 80	nla_for_each_attr(nla, head, len, rem) {
 81		if (nla_type(nla) == HANDSHAKE_A_DONE_REMOTE_AUTH)
 82			treq->th_peerid[i++] = nla_get_u32(nla);
 83		if (i >= treq->th_num_peerids)
 84			break;
 85	}
 86}
 87
 88/**
 89 * tls_handshake_done - callback to handle a CMD_DONE request
 90 * @req: socket on which the handshake was performed
 91 * @status: session status code
 92 * @info: full results of session establishment
 93 *
 94 */
 95static void tls_handshake_done(struct handshake_req *req,
 96			       unsigned int status, struct genl_info *info)
 97{
 98	struct tls_handshake_req *treq = handshake_req_private(req);
 99
100	treq->th_peerid[0] = TLS_NO_PEERID;
101	if (info)
102		tls_handshake_remote_peerids(treq, info);
103
104	if (!status)
105		set_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags);
106
107	treq->th_consumer_done(treq->th_consumer_data, -status,
108			       treq->th_peerid[0]);
109}
110
111#if IS_ENABLED(CONFIG_KEYS)
112static int tls_handshake_private_keyring(struct tls_handshake_req *treq)
113{
114	key_ref_t process_keyring_ref, keyring_ref;
115	int ret;
116
117	if (treq->th_keyring == TLS_NO_KEYRING)
118		return 0;
119
120	process_keyring_ref = lookup_user_key(KEY_SPEC_PROCESS_KEYRING,
121					      KEY_LOOKUP_CREATE,
122					      KEY_NEED_WRITE);
123	if (IS_ERR(process_keyring_ref)) {
124		ret = PTR_ERR(process_keyring_ref);
125		goto out;
126	}
127
128	keyring_ref = lookup_user_key(treq->th_keyring, KEY_LOOKUP_CREATE,
129				      KEY_NEED_LINK);
130	if (IS_ERR(keyring_ref)) {
131		ret = PTR_ERR(keyring_ref);
132		goto out_put_key;
133	}
134
135	ret = key_link(key_ref_to_ptr(process_keyring_ref),
136		       key_ref_to_ptr(keyring_ref));
137
138	key_ref_put(keyring_ref);
139out_put_key:
140	key_ref_put(process_keyring_ref);
141out:
142	return ret;
143}
144#else
145static int tls_handshake_private_keyring(struct tls_handshake_req *treq)
146{
147	return 0;
148}
149#endif
150
151static int tls_handshake_put_peer_identity(struct sk_buff *msg,
152					   struct tls_handshake_req *treq)
153{
154	unsigned int i;
155
156	for (i = 0; i < treq->th_num_peerids; i++)
157		if (nla_put_u32(msg, HANDSHAKE_A_ACCEPT_PEER_IDENTITY,
158				treq->th_peerid[i]) < 0)
159			return -EMSGSIZE;
160	return 0;
161}
162
163static int tls_handshake_put_certificate(struct sk_buff *msg,
164					 struct tls_handshake_req *treq)
165{
166	struct nlattr *entry_attr;
167
168	if (treq->th_certificate == TLS_NO_CERT &&
169	    treq->th_privkey == TLS_NO_PRIVKEY)
170		return 0;
171
172	entry_attr = nla_nest_start(msg, HANDSHAKE_A_ACCEPT_CERTIFICATE);
173	if (!entry_attr)
174		return -EMSGSIZE;
175
176	if (nla_put_s32(msg, HANDSHAKE_A_X509_CERT,
177			treq->th_certificate) ||
178	    nla_put_s32(msg, HANDSHAKE_A_X509_PRIVKEY,
179			treq->th_privkey)) {
180		nla_nest_cancel(msg, entry_attr);
181		return -EMSGSIZE;
182	}
183
184	nla_nest_end(msg, entry_attr);
185	return 0;
186}
187
188/**
189 * tls_handshake_accept - callback to construct a CMD_ACCEPT response
190 * @req: handshake parameters to return
191 * @info: generic netlink message context
192 * @fd: file descriptor to be returned
193 *
194 * Returns zero on success, or a negative errno on failure.
195 */
196static int tls_handshake_accept(struct handshake_req *req,
197				struct genl_info *info, int fd)
198{
199	struct tls_handshake_req *treq = handshake_req_private(req);
200	struct nlmsghdr *hdr;
201	struct sk_buff *msg;
202	int ret;
203
204	ret = tls_handshake_private_keyring(treq);
205	if (ret < 0)
206		goto out;
207
208	ret = -ENOMEM;
209	msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
210	if (!msg)
211		goto out;
212	hdr = handshake_genl_put(msg, info);
213	if (!hdr)
214		goto out_cancel;
215
216	ret = nla_put_s32(msg, HANDSHAKE_A_ACCEPT_SOCKFD, fd);
217	if (ret < 0)
218		goto out_cancel;
219	ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MESSAGE_TYPE, treq->th_type);
220	if (ret < 0)
221		goto out_cancel;
222	if (treq->th_peername) {
223		ret = nla_put_string(msg, HANDSHAKE_A_ACCEPT_PEERNAME,
224				     treq->th_peername);
225		if (ret < 0)
226			goto out_cancel;
227	}
228	if (treq->th_timeout_ms) {
229		ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_TIMEOUT, treq->th_timeout_ms);
230		if (ret < 0)
231			goto out_cancel;
232	}
233	if (treq->th_keyring) {
234		ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_KEYRING,
235				  treq->th_keyring);
236		if (ret < 0)
237			goto out_cancel;
238	}
239
240	ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_AUTH_MODE,
241			  treq->th_auth_mode);
242	if (ret < 0)
243		goto out_cancel;
244	switch (treq->th_auth_mode) {
245	case HANDSHAKE_AUTH_PSK:
246		ret = tls_handshake_put_peer_identity(msg, treq);
247		if (ret < 0)
248			goto out_cancel;
249		break;
250	case HANDSHAKE_AUTH_X509:
251		ret = tls_handshake_put_certificate(msg, treq);
252		if (ret < 0)
253			goto out_cancel;
254		break;
255	}
256
257	genlmsg_end(msg, hdr);
258	return genlmsg_reply(msg, info);
259
260out_cancel:
261	genlmsg_cancel(msg, hdr);
262	nlmsg_free(msg);
263out:
264	return ret;
265}
266
267static const struct handshake_proto tls_handshake_proto = {
268	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
269	.hp_privsize		= sizeof(struct tls_handshake_req),
270	.hp_flags		= BIT(HANDSHAKE_F_PROTO_NOTIFY),
271
272	.hp_accept		= tls_handshake_accept,
273	.hp_done		= tls_handshake_done,
274};
275
276/**
277 * tls_client_hello_anon - request an anonymous TLS handshake on a socket
278 * @args: socket and handshake parameters for this request
279 * @flags: memory allocation control flags
280 *
281 * Return values:
282 *   %0: Handshake request enqueue; ->done will be called when complete
283 *   %-ESRCH: No user agent is available
284 *   %-ENOMEM: Memory allocation failed
285 */
286int tls_client_hello_anon(const struct tls_handshake_args *args, gfp_t flags)
287{
288	struct tls_handshake_req *treq;
289	struct handshake_req *req;
290
291	req = handshake_req_alloc(&tls_handshake_proto, flags);
292	if (!req)
293		return -ENOMEM;
294	treq = tls_handshake_req_init(req, args);
295	treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
296	treq->th_auth_mode = HANDSHAKE_AUTH_UNAUTH;
297
298	return handshake_req_submit(args->ta_sock, req, flags);
299}
300EXPORT_SYMBOL(tls_client_hello_anon);
301
302/**
303 * tls_client_hello_x509 - request an x.509-based TLS handshake on a socket
304 * @args: socket and handshake parameters for this request
305 * @flags: memory allocation control flags
306 *
307 * Return values:
308 *   %0: Handshake request enqueue; ->done will be called when complete
309 *   %-ESRCH: No user agent is available
310 *   %-ENOMEM: Memory allocation failed
311 */
312int tls_client_hello_x509(const struct tls_handshake_args *args, gfp_t flags)
313{
314	struct tls_handshake_req *treq;
315	struct handshake_req *req;
316
317	req = handshake_req_alloc(&tls_handshake_proto, flags);
318	if (!req)
319		return -ENOMEM;
320	treq = tls_handshake_req_init(req, args);
321	treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
322	treq->th_auth_mode = HANDSHAKE_AUTH_X509;
323	treq->th_certificate = args->ta_my_cert;
324	treq->th_privkey = args->ta_my_privkey;
325
326	return handshake_req_submit(args->ta_sock, req, flags);
327}
328EXPORT_SYMBOL(tls_client_hello_x509);
329
330/**
331 * tls_client_hello_psk - request a PSK-based TLS handshake on a socket
332 * @args: socket and handshake parameters for this request
333 * @flags: memory allocation control flags
334 *
335 * Return values:
336 *   %0: Handshake request enqueue; ->done will be called when complete
337 *   %-EINVAL: Wrong number of local peer IDs
338 *   %-ESRCH: No user agent is available
339 *   %-ENOMEM: Memory allocation failed
340 */
341int tls_client_hello_psk(const struct tls_handshake_args *args, gfp_t flags)
342{
343	struct tls_handshake_req *treq;
344	struct handshake_req *req;
345	unsigned int i;
346
347	if (!args->ta_num_peerids ||
348	    args->ta_num_peerids > ARRAY_SIZE(treq->th_peerid))
349		return -EINVAL;
350
351	req = handshake_req_alloc(&tls_handshake_proto, flags);
352	if (!req)
353		return -ENOMEM;
354	treq = tls_handshake_req_init(req, args);
355	treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
356	treq->th_auth_mode = HANDSHAKE_AUTH_PSK;
357	treq->th_num_peerids = args->ta_num_peerids;
358	for (i = 0; i < args->ta_num_peerids; i++)
359		treq->th_peerid[i] = args->ta_my_peerids[i];
360
361	return handshake_req_submit(args->ta_sock, req, flags);
362}
363EXPORT_SYMBOL(tls_client_hello_psk);
364
365/**
366 * tls_server_hello_x509 - request a server TLS handshake on a socket
367 * @args: socket and handshake parameters for this request
368 * @flags: memory allocation control flags
369 *
370 * Return values:
371 *   %0: Handshake request enqueue; ->done will be called when complete
372 *   %-ESRCH: No user agent is available
373 *   %-ENOMEM: Memory allocation failed
374 */
375int tls_server_hello_x509(const struct tls_handshake_args *args, gfp_t flags)
376{
377	struct tls_handshake_req *treq;
378	struct handshake_req *req;
379
380	req = handshake_req_alloc(&tls_handshake_proto, flags);
381	if (!req)
382		return -ENOMEM;
383	treq = tls_handshake_req_init(req, args);
384	treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO;
385	treq->th_auth_mode = HANDSHAKE_AUTH_X509;
386	treq->th_certificate = args->ta_my_cert;
387	treq->th_privkey = args->ta_my_privkey;
388
389	return handshake_req_submit(args->ta_sock, req, flags);
390}
391EXPORT_SYMBOL(tls_server_hello_x509);
392
393/**
394 * tls_server_hello_psk - request a server TLS handshake on a socket
395 * @args: socket and handshake parameters for this request
396 * @flags: memory allocation control flags
397 *
398 * Return values:
399 *   %0: Handshake request enqueue; ->done will be called when complete
400 *   %-ESRCH: No user agent is available
401 *   %-ENOMEM: Memory allocation failed
402 */
403int tls_server_hello_psk(const struct tls_handshake_args *args, gfp_t flags)
404{
405	struct tls_handshake_req *treq;
406	struct handshake_req *req;
407
408	req = handshake_req_alloc(&tls_handshake_proto, flags);
409	if (!req)
410		return -ENOMEM;
411	treq = tls_handshake_req_init(req, args);
412	treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO;
413	treq->th_auth_mode = HANDSHAKE_AUTH_PSK;
414	treq->th_num_peerids = 1;
415	treq->th_peerid[0] = args->ta_my_peerids[0];
416
417	return handshake_req_submit(args->ta_sock, req, flags);
418}
419EXPORT_SYMBOL(tls_server_hello_psk);
420
421/**
422 * tls_handshake_cancel - cancel a pending handshake
423 * @sk: socket on which there is an ongoing handshake
424 *
425 * Request cancellation races with request completion. To determine
426 * who won, callers examine the return value from this function.
427 *
428 * Return values:
429 *   %true - Uncompleted handshake request was canceled
430 *   %false - Handshake request already completed or not found
431 */
432bool tls_handshake_cancel(struct sock *sk)
433{
434	return handshake_req_cancel(sk);
435}
436EXPORT_SYMBOL(tls_handshake_cancel);
437
438/**
439 * tls_handshake_close - send a Closure alert
440 * @sock: an open socket
441 *
442 */
443void tls_handshake_close(struct socket *sock)
444{
445	struct handshake_req *req;
446
447	req = handshake_req_hash_lookup(sock->sk);
448	if (!req)
449		return;
450	if (!test_and_clear_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags))
451		return;
452	tls_alert_send(sock, TLS_ALERT_LEVEL_WARNING,
453		       TLS_ALERT_DESC_CLOSE_NOTIFY);
454}
455EXPORT_SYMBOL(tls_handshake_close);
~/ Read-only file preview.