xref: /linux/net/handshake/tlshd.c (revision 621cde16e49b3ecf7d59a8106a20aaebfb4a59a9)
12fd55320SChuck Lever // SPDX-License-Identifier: GPL-2.0-only
22fd55320SChuck Lever /*
32fd55320SChuck Lever  * Establish a TLS session for a kernel socket consumer
42fd55320SChuck Lever  * using the tlshd user space handler.
52fd55320SChuck Lever  *
62fd55320SChuck Lever  * Author: Chuck Lever <chuck.lever@oracle.com>
72fd55320SChuck Lever  *
82fd55320SChuck Lever  * Copyright (c) 2021-2023, Oracle and/or its affiliates.
92fd55320SChuck Lever  */
102fd55320SChuck Lever 
112fd55320SChuck Lever #include <linux/types.h>
122fd55320SChuck Lever #include <linux/socket.h>
132fd55320SChuck Lever #include <linux/kernel.h>
142fd55320SChuck Lever #include <linux/module.h>
152fd55320SChuck Lever #include <linux/slab.h>
162fd55320SChuck Lever #include <linux/key.h>
172fd55320SChuck Lever 
182fd55320SChuck Lever #include <net/sock.h>
192fd55320SChuck Lever #include <net/handshake.h>
202fd55320SChuck Lever #include <net/genetlink.h>
2135b1b538SChuck Lever #include <net/tls_prot.h>
222fd55320SChuck Lever 
232fd55320SChuck Lever #include <uapi/linux/keyctl.h>
242fd55320SChuck Lever #include <uapi/linux/handshake.h>
252fd55320SChuck Lever #include "handshake.h"
262fd55320SChuck Lever 
272fd55320SChuck Lever struct tls_handshake_req {
282fd55320SChuck Lever 	void			(*th_consumer_done)(void *data, int status,
292fd55320SChuck Lever 						    key_serial_t peerid);
302fd55320SChuck Lever 	void			*th_consumer_data;
312fd55320SChuck Lever 
322fd55320SChuck Lever 	int			th_type;
332fd55320SChuck Lever 	unsigned int		th_timeout_ms;
342fd55320SChuck Lever 	int			th_auth_mode;
3526fb5480SChuck Lever 	const char		*th_peername;
362fd55320SChuck Lever 	key_serial_t		th_keyring;
372fd55320SChuck Lever 	key_serial_t		th_certificate;
382fd55320SChuck Lever 	key_serial_t		th_privkey;
392fd55320SChuck Lever 
402fd55320SChuck Lever 	unsigned int		th_num_peerids;
412fd55320SChuck Lever 	key_serial_t		th_peerid[5];
422fd55320SChuck Lever };
432fd55320SChuck Lever 
442fd55320SChuck Lever static struct tls_handshake_req *
tls_handshake_req_init(struct handshake_req * req,const struct tls_handshake_args * args)452fd55320SChuck Lever tls_handshake_req_init(struct handshake_req *req,
462fd55320SChuck Lever 		       const struct tls_handshake_args *args)
472fd55320SChuck Lever {
482fd55320SChuck Lever 	struct tls_handshake_req *treq = handshake_req_private(req);
492fd55320SChuck Lever 
502fd55320SChuck Lever 	treq->th_timeout_ms = args->ta_timeout_ms;
512fd55320SChuck Lever 	treq->th_consumer_done = args->ta_done;
522fd55320SChuck Lever 	treq->th_consumer_data = args->ta_data;
5326fb5480SChuck Lever 	treq->th_peername = args->ta_peername;
542fd55320SChuck Lever 	treq->th_keyring = args->ta_keyring;
552fd55320SChuck Lever 	treq->th_num_peerids = 0;
562fd55320SChuck Lever 	treq->th_certificate = TLS_NO_CERT;
572fd55320SChuck Lever 	treq->th_privkey = TLS_NO_PRIVKEY;
582fd55320SChuck Lever 	return treq;
592fd55320SChuck Lever }
602fd55320SChuck Lever 
tls_handshake_remote_peerids(struct tls_handshake_req * treq,struct genl_info * info)612fd55320SChuck Lever static void tls_handshake_remote_peerids(struct tls_handshake_req *treq,
622fd55320SChuck Lever 					 struct genl_info *info)
632fd55320SChuck Lever {
642fd55320SChuck Lever 	struct nlattr *head = nlmsg_attrdata(info->nlhdr, GENL_HDRLEN);
652fd55320SChuck Lever 	int rem, len = nlmsg_attrlen(info->nlhdr, GENL_HDRLEN);
662fd55320SChuck Lever 	struct nlattr *nla;
672fd55320SChuck Lever 	unsigned int i;
682fd55320SChuck Lever 
692fd55320SChuck Lever 	i = 0;
702fd55320SChuck Lever 	nla_for_each_attr(nla, head, len, rem) {
712fd55320SChuck Lever 		if (nla_type(nla) == HANDSHAKE_A_DONE_REMOTE_AUTH)
722fd55320SChuck Lever 			i++;
732fd55320SChuck Lever 	}
742fd55320SChuck Lever 	if (!i)
752fd55320SChuck Lever 		return;
762fd55320SChuck Lever 	treq->th_num_peerids = min_t(unsigned int, i,
772fd55320SChuck Lever 				     ARRAY_SIZE(treq->th_peerid));
782fd55320SChuck Lever 
792fd55320SChuck Lever 	i = 0;
802fd55320SChuck Lever 	nla_for_each_attr(nla, head, len, rem) {
812fd55320SChuck Lever 		if (nla_type(nla) == HANDSHAKE_A_DONE_REMOTE_AUTH)
822fd55320SChuck Lever 			treq->th_peerid[i++] = nla_get_u32(nla);
832fd55320SChuck Lever 		if (i >= treq->th_num_peerids)
842fd55320SChuck Lever 			break;
852fd55320SChuck Lever 	}
862fd55320SChuck Lever }
872fd55320SChuck Lever 
882fd55320SChuck Lever /**
892fd55320SChuck Lever  * tls_handshake_done - callback to handle a CMD_DONE request
902fd55320SChuck Lever  * @req: socket on which the handshake was performed
912fd55320SChuck Lever  * @status: session status code
922fd55320SChuck Lever  * @info: full results of session establishment
932fd55320SChuck Lever  *
942fd55320SChuck Lever  */
tls_handshake_done(struct handshake_req * req,unsigned int status,struct genl_info * info)952fd55320SChuck Lever static void tls_handshake_done(struct handshake_req *req,
962fd55320SChuck Lever 			       unsigned int status, struct genl_info *info)
972fd55320SChuck Lever {
982fd55320SChuck Lever 	struct tls_handshake_req *treq = handshake_req_private(req);
992fd55320SChuck Lever 
1002fd55320SChuck Lever 	treq->th_peerid[0] = TLS_NO_PEERID;
1012fd55320SChuck Lever 	if (info)
1022fd55320SChuck Lever 		tls_handshake_remote_peerids(treq, info);
1032fd55320SChuck Lever 
10435b1b538SChuck Lever 	if (!status)
10535b1b538SChuck Lever 		set_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags);
10635b1b538SChuck Lever 
1072fd55320SChuck Lever 	treq->th_consumer_done(treq->th_consumer_data, -status,
1082fd55320SChuck Lever 			       treq->th_peerid[0]);
1092fd55320SChuck Lever }
1102fd55320SChuck Lever 
1112fd55320SChuck Lever #if IS_ENABLED(CONFIG_KEYS)
tls_handshake_private_keyring(struct tls_handshake_req * treq)1122fd55320SChuck Lever static int tls_handshake_private_keyring(struct tls_handshake_req *treq)
1132fd55320SChuck Lever {
1142fd55320SChuck Lever 	key_ref_t process_keyring_ref, keyring_ref;
1152fd55320SChuck Lever 	int ret;
1162fd55320SChuck Lever 
1172fd55320SChuck Lever 	if (treq->th_keyring == TLS_NO_KEYRING)
1182fd55320SChuck Lever 		return 0;
1192fd55320SChuck Lever 
1202fd55320SChuck Lever 	process_keyring_ref = lookup_user_key(KEY_SPEC_PROCESS_KEYRING,
1212fd55320SChuck Lever 					      KEY_LOOKUP_CREATE,
1222fd55320SChuck Lever 					      KEY_NEED_WRITE);
1232fd55320SChuck Lever 	if (IS_ERR(process_keyring_ref)) {
1242fd55320SChuck Lever 		ret = PTR_ERR(process_keyring_ref);
1252fd55320SChuck Lever 		goto out;
1262fd55320SChuck Lever 	}
1272fd55320SChuck Lever 
1282fd55320SChuck Lever 	keyring_ref = lookup_user_key(treq->th_keyring, KEY_LOOKUP_CREATE,
1292fd55320SChuck Lever 				      KEY_NEED_LINK);
1302fd55320SChuck Lever 	if (IS_ERR(keyring_ref)) {
1312fd55320SChuck Lever 		ret = PTR_ERR(keyring_ref);
1322fd55320SChuck Lever 		goto out_put_key;
1332fd55320SChuck Lever 	}
1342fd55320SChuck Lever 
1352fd55320SChuck Lever 	ret = key_link(key_ref_to_ptr(process_keyring_ref),
1362fd55320SChuck Lever 		       key_ref_to_ptr(keyring_ref));
1372fd55320SChuck Lever 
1382fd55320SChuck Lever 	key_ref_put(keyring_ref);
1392fd55320SChuck Lever out_put_key:
1402fd55320SChuck Lever 	key_ref_put(process_keyring_ref);
1412fd55320SChuck Lever out:
1422fd55320SChuck Lever 	return ret;
1432fd55320SChuck Lever }
1442fd55320SChuck Lever #else
tls_handshake_private_keyring(struct tls_handshake_req * treq)1452fd55320SChuck Lever static int tls_handshake_private_keyring(struct tls_handshake_req *treq)
1462fd55320SChuck Lever {
1472fd55320SChuck Lever 	return 0;
1482fd55320SChuck Lever }
1492fd55320SChuck Lever #endif
1502fd55320SChuck Lever 
tls_handshake_put_peer_identity(struct sk_buff * msg,struct tls_handshake_req * treq)1512fd55320SChuck Lever static int tls_handshake_put_peer_identity(struct sk_buff *msg,
1522fd55320SChuck Lever 					   struct tls_handshake_req *treq)
1532fd55320SChuck Lever {
1542fd55320SChuck Lever 	unsigned int i;
1552fd55320SChuck Lever 
1562fd55320SChuck Lever 	for (i = 0; i < treq->th_num_peerids; i++)
1572fd55320SChuck Lever 		if (nla_put_u32(msg, HANDSHAKE_A_ACCEPT_PEER_IDENTITY,
1582fd55320SChuck Lever 				treq->th_peerid[i]) < 0)
1592fd55320SChuck Lever 			return -EMSGSIZE;
1602fd55320SChuck Lever 	return 0;
1612fd55320SChuck Lever }
1622fd55320SChuck Lever 
tls_handshake_put_certificate(struct sk_buff * msg,struct tls_handshake_req * treq)1632fd55320SChuck Lever static int tls_handshake_put_certificate(struct sk_buff *msg,
1642fd55320SChuck Lever 					 struct tls_handshake_req *treq)
1652fd55320SChuck Lever {
1662fd55320SChuck Lever 	struct nlattr *entry_attr;
1672fd55320SChuck Lever 
1682fd55320SChuck Lever 	if (treq->th_certificate == TLS_NO_CERT &&
1692fd55320SChuck Lever 	    treq->th_privkey == TLS_NO_PRIVKEY)
1702fd55320SChuck Lever 		return 0;
1712fd55320SChuck Lever 
1722fd55320SChuck Lever 	entry_attr = nla_nest_start(msg, HANDSHAKE_A_ACCEPT_CERTIFICATE);
1732fd55320SChuck Lever 	if (!entry_attr)
1742fd55320SChuck Lever 		return -EMSGSIZE;
1752fd55320SChuck Lever 
176*160f4044SChuck Lever 	if (nla_put_s32(msg, HANDSHAKE_A_X509_CERT,
1772fd55320SChuck Lever 			treq->th_certificate) ||
178*160f4044SChuck Lever 	    nla_put_s32(msg, HANDSHAKE_A_X509_PRIVKEY,
1792fd55320SChuck Lever 			treq->th_privkey)) {
1802fd55320SChuck Lever 		nla_nest_cancel(msg, entry_attr);
1812fd55320SChuck Lever 		return -EMSGSIZE;
1822fd55320SChuck Lever 	}
1832fd55320SChuck Lever 
1842fd55320SChuck Lever 	nla_nest_end(msg, entry_attr);
1852fd55320SChuck Lever 	return 0;
1862fd55320SChuck Lever }
1872fd55320SChuck Lever 
1882fd55320SChuck Lever /**
1892fd55320SChuck Lever  * tls_handshake_accept - callback to construct a CMD_ACCEPT response
1902fd55320SChuck Lever  * @req: handshake parameters to return
1912fd55320SChuck Lever  * @info: generic netlink message context
1922fd55320SChuck Lever  * @fd: file descriptor to be returned
1932fd55320SChuck Lever  *
1942fd55320SChuck Lever  * Returns zero on success, or a negative errno on failure.
1952fd55320SChuck Lever  */
tls_handshake_accept(struct handshake_req * req,struct genl_info * info,int fd)1962fd55320SChuck Lever static int tls_handshake_accept(struct handshake_req *req,
1972fd55320SChuck Lever 				struct genl_info *info, int fd)
1982fd55320SChuck Lever {
1992fd55320SChuck Lever 	struct tls_handshake_req *treq = handshake_req_private(req);
2002fd55320SChuck Lever 	struct nlmsghdr *hdr;
2012fd55320SChuck Lever 	struct sk_buff *msg;
2022fd55320SChuck Lever 	int ret;
2032fd55320SChuck Lever 
2042fd55320SChuck Lever 	ret = tls_handshake_private_keyring(treq);
2052fd55320SChuck Lever 	if (ret < 0)
2062fd55320SChuck Lever 		goto out;
2072fd55320SChuck Lever 
2082fd55320SChuck Lever 	ret = -ENOMEM;
2092fd55320SChuck Lever 	msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
2102fd55320SChuck Lever 	if (!msg)
2112fd55320SChuck Lever 		goto out;
2122fd55320SChuck Lever 	hdr = handshake_genl_put(msg, info);
2132fd55320SChuck Lever 	if (!hdr)
2142fd55320SChuck Lever 		goto out_cancel;
2152fd55320SChuck Lever 
216a6b07a51SChuck Lever 	ret = nla_put_s32(msg, HANDSHAKE_A_ACCEPT_SOCKFD, fd);
2172fd55320SChuck Lever 	if (ret < 0)
2182fd55320SChuck Lever 		goto out_cancel;
2192fd55320SChuck Lever 	ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MESSAGE_TYPE, treq->th_type);
2202fd55320SChuck Lever 	if (ret < 0)
2212fd55320SChuck Lever 		goto out_cancel;
22226fb5480SChuck Lever 	if (treq->th_peername) {
22326fb5480SChuck Lever 		ret = nla_put_string(msg, HANDSHAKE_A_ACCEPT_PEERNAME,
22426fb5480SChuck Lever 				     treq->th_peername);
22526fb5480SChuck Lever 		if (ret < 0)
22626fb5480SChuck Lever 			goto out_cancel;
22726fb5480SChuck Lever 	}
2282fd55320SChuck Lever 	if (treq->th_timeout_ms) {
2292fd55320SChuck Lever 		ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_TIMEOUT, treq->th_timeout_ms);
2302fd55320SChuck Lever 		if (ret < 0)
2312fd55320SChuck Lever 			goto out_cancel;
2322fd55320SChuck Lever 	}
2332fd55320SChuck Lever 
2342fd55320SChuck Lever 	ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_AUTH_MODE,
2352fd55320SChuck Lever 			  treq->th_auth_mode);
2362fd55320SChuck Lever 	if (ret < 0)
2372fd55320SChuck Lever 		goto out_cancel;
2382fd55320SChuck Lever 	switch (treq->th_auth_mode) {
2392fd55320SChuck Lever 	case HANDSHAKE_AUTH_PSK:
2402fd55320SChuck Lever 		ret = tls_handshake_put_peer_identity(msg, treq);
2412fd55320SChuck Lever 		if (ret < 0)
2422fd55320SChuck Lever 			goto out_cancel;
2432fd55320SChuck Lever 		break;
2442fd55320SChuck Lever 	case HANDSHAKE_AUTH_X509:
2452fd55320SChuck Lever 		ret = tls_handshake_put_certificate(msg, treq);
2462fd55320SChuck Lever 		if (ret < 0)
2472fd55320SChuck Lever 			goto out_cancel;
2482fd55320SChuck Lever 		break;
2492fd55320SChuck Lever 	}
2502fd55320SChuck Lever 
2512fd55320SChuck Lever 	genlmsg_end(msg, hdr);
2522fd55320SChuck Lever 	return genlmsg_reply(msg, info);
2532fd55320SChuck Lever 
2542fd55320SChuck Lever out_cancel:
2552fd55320SChuck Lever 	genlmsg_cancel(msg, hdr);
2562fd55320SChuck Lever out:
2572fd55320SChuck Lever 	return ret;
2582fd55320SChuck Lever }
2592fd55320SChuck Lever 
2602fd55320SChuck Lever static const struct handshake_proto tls_handshake_proto = {
2612fd55320SChuck Lever 	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
2622fd55320SChuck Lever 	.hp_privsize		= sizeof(struct tls_handshake_req),
26388232ec1SChuck Lever 	.hp_flags		= BIT(HANDSHAKE_F_PROTO_NOTIFY),
2642fd55320SChuck Lever 
2652fd55320SChuck Lever 	.hp_accept		= tls_handshake_accept,
2662fd55320SChuck Lever 	.hp_done		= tls_handshake_done,
2672fd55320SChuck Lever };
2682fd55320SChuck Lever 
2692fd55320SChuck Lever /**
2702fd55320SChuck Lever  * tls_client_hello_anon - request an anonymous TLS handshake on a socket
2712fd55320SChuck Lever  * @args: socket and handshake parameters for this request
2722fd55320SChuck Lever  * @flags: memory allocation control flags
2732fd55320SChuck Lever  *
2742fd55320SChuck Lever  * Return values:
2752fd55320SChuck Lever  *   %0: Handshake request enqueue; ->done will be called when complete
2762fd55320SChuck Lever  *   %-ESRCH: No user agent is available
2772fd55320SChuck Lever  *   %-ENOMEM: Memory allocation failed
2782fd55320SChuck Lever  */
tls_client_hello_anon(const struct tls_handshake_args * args,gfp_t flags)2792fd55320SChuck Lever int tls_client_hello_anon(const struct tls_handshake_args *args, gfp_t flags)
2802fd55320SChuck Lever {
2812fd55320SChuck Lever 	struct tls_handshake_req *treq;
2822fd55320SChuck Lever 	struct handshake_req *req;
2832fd55320SChuck Lever 
2842fd55320SChuck Lever 	req = handshake_req_alloc(&tls_handshake_proto, flags);
2852fd55320SChuck Lever 	if (!req)
2862fd55320SChuck Lever 		return -ENOMEM;
2872fd55320SChuck Lever 	treq = tls_handshake_req_init(req, args);
2882fd55320SChuck Lever 	treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
2892fd55320SChuck Lever 	treq->th_auth_mode = HANDSHAKE_AUTH_UNAUTH;
2902fd55320SChuck Lever 
2912fd55320SChuck Lever 	return handshake_req_submit(args->ta_sock, req, flags);
2922fd55320SChuck Lever }
2932fd55320SChuck Lever EXPORT_SYMBOL(tls_client_hello_anon);
2942fd55320SChuck Lever 
2952fd55320SChuck Lever /**
2962fd55320SChuck Lever  * tls_client_hello_x509 - request an x.509-based TLS handshake on a socket
2972fd55320SChuck Lever  * @args: socket and handshake parameters for this request
2982fd55320SChuck Lever  * @flags: memory allocation control flags
2992fd55320SChuck Lever  *
3002fd55320SChuck Lever  * Return values:
3012fd55320SChuck Lever  *   %0: Handshake request enqueue; ->done will be called when complete
3022fd55320SChuck Lever  *   %-ESRCH: No user agent is available
3032fd55320SChuck Lever  *   %-ENOMEM: Memory allocation failed
3042fd55320SChuck Lever  */
tls_client_hello_x509(const struct tls_handshake_args * args,gfp_t flags)3052fd55320SChuck Lever int tls_client_hello_x509(const struct tls_handshake_args *args, gfp_t flags)
3062fd55320SChuck Lever {
3072fd55320SChuck Lever 	struct tls_handshake_req *treq;
3082fd55320SChuck Lever 	struct handshake_req *req;
3092fd55320SChuck Lever 
3102fd55320SChuck Lever 	req = handshake_req_alloc(&tls_handshake_proto, flags);
3112fd55320SChuck Lever 	if (!req)
3122fd55320SChuck Lever 		return -ENOMEM;
3132fd55320SChuck Lever 	treq = tls_handshake_req_init(req, args);
3142fd55320SChuck Lever 	treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
3152fd55320SChuck Lever 	treq->th_auth_mode = HANDSHAKE_AUTH_X509;
3162fd55320SChuck Lever 	treq->th_certificate = args->ta_my_cert;
3172fd55320SChuck Lever 	treq->th_privkey = args->ta_my_privkey;
3182fd55320SChuck Lever 
3192fd55320SChuck Lever 	return handshake_req_submit(args->ta_sock, req, flags);
3202fd55320SChuck Lever }
3212fd55320SChuck Lever EXPORT_SYMBOL(tls_client_hello_x509);
3222fd55320SChuck Lever 
3232fd55320SChuck Lever /**
3242fd55320SChuck Lever  * tls_client_hello_psk - request a PSK-based TLS handshake on a socket
3252fd55320SChuck Lever  * @args: socket and handshake parameters for this request
3262fd55320SChuck Lever  * @flags: memory allocation control flags
3272fd55320SChuck Lever  *
3282fd55320SChuck Lever  * Return values:
3292fd55320SChuck Lever  *   %0: Handshake request enqueue; ->done will be called when complete
3302fd55320SChuck Lever  *   %-EINVAL: Wrong number of local peer IDs
3312fd55320SChuck Lever  *   %-ESRCH: No user agent is available
3322fd55320SChuck Lever  *   %-ENOMEM: Memory allocation failed
3332fd55320SChuck Lever  */
tls_client_hello_psk(const struct tls_handshake_args * args,gfp_t flags)3342fd55320SChuck Lever int tls_client_hello_psk(const struct tls_handshake_args *args, gfp_t flags)
3352fd55320SChuck Lever {
3362fd55320SChuck Lever 	struct tls_handshake_req *treq;
3372fd55320SChuck Lever 	struct handshake_req *req;
3382fd55320SChuck Lever 	unsigned int i;
3392fd55320SChuck Lever 
3402fd55320SChuck Lever 	if (!args->ta_num_peerids ||
3412fd55320SChuck Lever 	    args->ta_num_peerids > ARRAY_SIZE(treq->th_peerid))
3422fd55320SChuck Lever 		return -EINVAL;
3432fd55320SChuck Lever 
3442fd55320SChuck Lever 	req = handshake_req_alloc(&tls_handshake_proto, flags);
3452fd55320SChuck Lever 	if (!req)
3462fd55320SChuck Lever 		return -ENOMEM;
3472fd55320SChuck Lever 	treq = tls_handshake_req_init(req, args);
3482fd55320SChuck Lever 	treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
3492fd55320SChuck Lever 	treq->th_auth_mode = HANDSHAKE_AUTH_PSK;
3502fd55320SChuck Lever 	treq->th_num_peerids = args->ta_num_peerids;
3512fd55320SChuck Lever 	for (i = 0; i < args->ta_num_peerids; i++)
3522fd55320SChuck Lever 		treq->th_peerid[i] = args->ta_my_peerids[i];
3532fd55320SChuck Lever 
3542fd55320SChuck Lever 	return handshake_req_submit(args->ta_sock, req, flags);
3552fd55320SChuck Lever }
3562fd55320SChuck Lever EXPORT_SYMBOL(tls_client_hello_psk);
3572fd55320SChuck Lever 
3582fd55320SChuck Lever /**
3592fd55320SChuck Lever  * tls_server_hello_x509 - request a server TLS handshake on a socket
3602fd55320SChuck Lever  * @args: socket and handshake parameters for this request
3612fd55320SChuck Lever  * @flags: memory allocation control flags
3622fd55320SChuck Lever  *
3632fd55320SChuck Lever  * Return values:
3642fd55320SChuck Lever  *   %0: Handshake request enqueue; ->done will be called when complete
3652fd55320SChuck Lever  *   %-ESRCH: No user agent is available
3662fd55320SChuck Lever  *   %-ENOMEM: Memory allocation failed
3672fd55320SChuck Lever  */
tls_server_hello_x509(const struct tls_handshake_args * args,gfp_t flags)3682fd55320SChuck Lever int tls_server_hello_x509(const struct tls_handshake_args *args, gfp_t flags)
3692fd55320SChuck Lever {
3702fd55320SChuck Lever 	struct tls_handshake_req *treq;
3712fd55320SChuck Lever 	struct handshake_req *req;
3722fd55320SChuck Lever 
3732fd55320SChuck Lever 	req = handshake_req_alloc(&tls_handshake_proto, flags);
3742fd55320SChuck Lever 	if (!req)
3752fd55320SChuck Lever 		return -ENOMEM;
3762fd55320SChuck Lever 	treq = tls_handshake_req_init(req, args);
3772fd55320SChuck Lever 	treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO;
3782fd55320SChuck Lever 	treq->th_auth_mode = HANDSHAKE_AUTH_X509;
3792fd55320SChuck Lever 	treq->th_certificate = args->ta_my_cert;
3802fd55320SChuck Lever 	treq->th_privkey = args->ta_my_privkey;
3812fd55320SChuck Lever 
3822fd55320SChuck Lever 	return handshake_req_submit(args->ta_sock, req, flags);
3832fd55320SChuck Lever }
3842fd55320SChuck Lever EXPORT_SYMBOL(tls_server_hello_x509);
3852fd55320SChuck Lever 
3862fd55320SChuck Lever /**
3872fd55320SChuck Lever  * tls_server_hello_psk - request a server TLS handshake on a socket
3882fd55320SChuck Lever  * @args: socket and handshake parameters for this request
3892fd55320SChuck Lever  * @flags: memory allocation control flags
3902fd55320SChuck Lever  *
3912fd55320SChuck Lever  * Return values:
3922fd55320SChuck Lever  *   %0: Handshake request enqueue; ->done will be called when complete
3932fd55320SChuck Lever  *   %-ESRCH: No user agent is available
3942fd55320SChuck Lever  *   %-ENOMEM: Memory allocation failed
3952fd55320SChuck Lever  */
tls_server_hello_psk(const struct tls_handshake_args * args,gfp_t flags)3962fd55320SChuck Lever int tls_server_hello_psk(const struct tls_handshake_args *args, gfp_t flags)
3972fd55320SChuck Lever {
3982fd55320SChuck Lever 	struct tls_handshake_req *treq;
3992fd55320SChuck Lever 	struct handshake_req *req;
4002fd55320SChuck Lever 
4012fd55320SChuck Lever 	req = handshake_req_alloc(&tls_handshake_proto, flags);
4022fd55320SChuck Lever 	if (!req)
4032fd55320SChuck Lever 		return -ENOMEM;
4042fd55320SChuck Lever 	treq = tls_handshake_req_init(req, args);
4052fd55320SChuck Lever 	treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO;
4062fd55320SChuck Lever 	treq->th_auth_mode = HANDSHAKE_AUTH_PSK;
4072fd55320SChuck Lever 	treq->th_num_peerids = 1;
4082fd55320SChuck Lever 	treq->th_peerid[0] = args->ta_my_peerids[0];
4092fd55320SChuck Lever 
4102fd55320SChuck Lever 	return handshake_req_submit(args->ta_sock, req, flags);
4112fd55320SChuck Lever }
4122fd55320SChuck Lever EXPORT_SYMBOL(tls_server_hello_psk);
4132fd55320SChuck Lever 
4142fd55320SChuck Lever /**
4152fd55320SChuck Lever  * tls_handshake_cancel - cancel a pending handshake
4162fd55320SChuck Lever  * @sk: socket on which there is an ongoing handshake
4172fd55320SChuck Lever  *
4182fd55320SChuck Lever  * Request cancellation races with request completion. To determine
4192fd55320SChuck Lever  * who won, callers examine the return value from this function.
4202fd55320SChuck Lever  *
4212fd55320SChuck Lever  * Return values:
4222fd55320SChuck Lever  *   %true - Uncompleted handshake request was canceled
4232fd55320SChuck Lever  *   %false - Handshake request already completed or not found
4242fd55320SChuck Lever  */
tls_handshake_cancel(struct sock * sk)4252fd55320SChuck Lever bool tls_handshake_cancel(struct sock *sk)
4262fd55320SChuck Lever {
4272fd55320SChuck Lever 	return handshake_req_cancel(sk);
4282fd55320SChuck Lever }
4292fd55320SChuck Lever EXPORT_SYMBOL(tls_handshake_cancel);
43035b1b538SChuck Lever 
43135b1b538SChuck Lever /**
43235b1b538SChuck Lever  * tls_handshake_close - send a Closure alert
43335b1b538SChuck Lever  * @sock: an open socket
43435b1b538SChuck Lever  *
43535b1b538SChuck Lever  */
tls_handshake_close(struct socket * sock)43635b1b538SChuck Lever void tls_handshake_close(struct socket *sock)
43735b1b538SChuck Lever {
43835b1b538SChuck Lever 	struct handshake_req *req;
43935b1b538SChuck Lever 
44035b1b538SChuck Lever 	req = handshake_req_hash_lookup(sock->sk);
44135b1b538SChuck Lever 	if (!req)
44235b1b538SChuck Lever 		return;
44335b1b538SChuck Lever 	if (!test_and_clear_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags))
44435b1b538SChuck Lever 		return;
44535b1b538SChuck Lever 	tls_alert_send(sock, TLS_ALERT_LEVEL_WARNING,
44635b1b538SChuck Lever 		       TLS_ALERT_DESC_CLOSE_NOTIFY);
44735b1b538SChuck Lever }
44835b1b538SChuck Lever EXPORT_SYMBOL(tls_handshake_close);
449