162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Establish a TLS session for a kernel socket consumer
462306a36Sopenharmony_ci * using the tlshd user space handler.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Author: Chuck Lever <chuck.lever@oracle.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (c) 2021-2023, Oracle and/or its affiliates.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/types.h>
1262306a36Sopenharmony_ci#include <linux/socket.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/key.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <net/sock.h>
1962306a36Sopenharmony_ci#include <net/handshake.h>
2062306a36Sopenharmony_ci#include <net/genetlink.h>
2162306a36Sopenharmony_ci#include <net/tls_prot.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <uapi/linux/keyctl.h>
2462306a36Sopenharmony_ci#include <uapi/linux/handshake.h>
2562306a36Sopenharmony_ci#include "handshake.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct tls_handshake_req {
2862306a36Sopenharmony_ci	void			(*th_consumer_done)(void *data, int status,
2962306a36Sopenharmony_ci						    key_serial_t peerid);
3062306a36Sopenharmony_ci	void			*th_consumer_data;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	int			th_type;
3362306a36Sopenharmony_ci	unsigned int		th_timeout_ms;
3462306a36Sopenharmony_ci	int			th_auth_mode;
3562306a36Sopenharmony_ci	const char		*th_peername;
3662306a36Sopenharmony_ci	key_serial_t		th_keyring;
3762306a36Sopenharmony_ci	key_serial_t		th_certificate;
3862306a36Sopenharmony_ci	key_serial_t		th_privkey;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	unsigned int		th_num_peerids;
4162306a36Sopenharmony_ci	key_serial_t		th_peerid[5];
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic struct tls_handshake_req *
4562306a36Sopenharmony_citls_handshake_req_init(struct handshake_req *req,
4662306a36Sopenharmony_ci		       const struct tls_handshake_args *args)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct tls_handshake_req *treq = handshake_req_private(req);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	treq->th_timeout_ms = args->ta_timeout_ms;
5162306a36Sopenharmony_ci	treq->th_consumer_done = args->ta_done;
5262306a36Sopenharmony_ci	treq->th_consumer_data = args->ta_data;
5362306a36Sopenharmony_ci	treq->th_peername = args->ta_peername;
5462306a36Sopenharmony_ci	treq->th_keyring = args->ta_keyring;
5562306a36Sopenharmony_ci	treq->th_num_peerids = 0;
5662306a36Sopenharmony_ci	treq->th_certificate = TLS_NO_CERT;
5762306a36Sopenharmony_ci	treq->th_privkey = TLS_NO_PRIVKEY;
5862306a36Sopenharmony_ci	return treq;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void tls_handshake_remote_peerids(struct tls_handshake_req *treq,
6262306a36Sopenharmony_ci					 struct genl_info *info)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct nlattr *head = nlmsg_attrdata(info->nlhdr, GENL_HDRLEN);
6562306a36Sopenharmony_ci	int rem, len = nlmsg_attrlen(info->nlhdr, GENL_HDRLEN);
6662306a36Sopenharmony_ci	struct nlattr *nla;
6762306a36Sopenharmony_ci	unsigned int i;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	i = 0;
7062306a36Sopenharmony_ci	nla_for_each_attr(nla, head, len, rem) {
7162306a36Sopenharmony_ci		if (nla_type(nla) == HANDSHAKE_A_DONE_REMOTE_AUTH)
7262306a36Sopenharmony_ci			i++;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci	if (!i)
7562306a36Sopenharmony_ci		return;
7662306a36Sopenharmony_ci	treq->th_num_peerids = min_t(unsigned int, i,
7762306a36Sopenharmony_ci				     ARRAY_SIZE(treq->th_peerid));
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	i = 0;
8062306a36Sopenharmony_ci	nla_for_each_attr(nla, head, len, rem) {
8162306a36Sopenharmony_ci		if (nla_type(nla) == HANDSHAKE_A_DONE_REMOTE_AUTH)
8262306a36Sopenharmony_ci			treq->th_peerid[i++] = nla_get_u32(nla);
8362306a36Sopenharmony_ci		if (i >= treq->th_num_peerids)
8462306a36Sopenharmony_ci			break;
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/**
8962306a36Sopenharmony_ci * tls_handshake_done - callback to handle a CMD_DONE request
9062306a36Sopenharmony_ci * @req: socket on which the handshake was performed
9162306a36Sopenharmony_ci * @status: session status code
9262306a36Sopenharmony_ci * @info: full results of session establishment
9362306a36Sopenharmony_ci *
9462306a36Sopenharmony_ci */
9562306a36Sopenharmony_cistatic void tls_handshake_done(struct handshake_req *req,
9662306a36Sopenharmony_ci			       unsigned int status, struct genl_info *info)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct tls_handshake_req *treq = handshake_req_private(req);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	treq->th_peerid[0] = TLS_NO_PEERID;
10162306a36Sopenharmony_ci	if (info)
10262306a36Sopenharmony_ci		tls_handshake_remote_peerids(treq, info);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (!status)
10562306a36Sopenharmony_ci		set_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	treq->th_consumer_done(treq->th_consumer_data, -status,
10862306a36Sopenharmony_ci			       treq->th_peerid[0]);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_KEYS)
11262306a36Sopenharmony_cistatic int tls_handshake_private_keyring(struct tls_handshake_req *treq)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	key_ref_t process_keyring_ref, keyring_ref;
11562306a36Sopenharmony_ci	int ret;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	if (treq->th_keyring == TLS_NO_KEYRING)
11862306a36Sopenharmony_ci		return 0;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	process_keyring_ref = lookup_user_key(KEY_SPEC_PROCESS_KEYRING,
12162306a36Sopenharmony_ci					      KEY_LOOKUP_CREATE,
12262306a36Sopenharmony_ci					      KEY_NEED_WRITE);
12362306a36Sopenharmony_ci	if (IS_ERR(process_keyring_ref)) {
12462306a36Sopenharmony_ci		ret = PTR_ERR(process_keyring_ref);
12562306a36Sopenharmony_ci		goto out;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	keyring_ref = lookup_user_key(treq->th_keyring, KEY_LOOKUP_CREATE,
12962306a36Sopenharmony_ci				      KEY_NEED_LINK);
13062306a36Sopenharmony_ci	if (IS_ERR(keyring_ref)) {
13162306a36Sopenharmony_ci		ret = PTR_ERR(keyring_ref);
13262306a36Sopenharmony_ci		goto out_put_key;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	ret = key_link(key_ref_to_ptr(process_keyring_ref),
13662306a36Sopenharmony_ci		       key_ref_to_ptr(keyring_ref));
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	key_ref_put(keyring_ref);
13962306a36Sopenharmony_ciout_put_key:
14062306a36Sopenharmony_ci	key_ref_put(process_keyring_ref);
14162306a36Sopenharmony_ciout:
14262306a36Sopenharmony_ci	return ret;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci#else
14562306a36Sopenharmony_cistatic int tls_handshake_private_keyring(struct tls_handshake_req *treq)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci#endif
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic int tls_handshake_put_peer_identity(struct sk_buff *msg,
15262306a36Sopenharmony_ci					   struct tls_handshake_req *treq)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	unsigned int i;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	for (i = 0; i < treq->th_num_peerids; i++)
15762306a36Sopenharmony_ci		if (nla_put_u32(msg, HANDSHAKE_A_ACCEPT_PEER_IDENTITY,
15862306a36Sopenharmony_ci				treq->th_peerid[i]) < 0)
15962306a36Sopenharmony_ci			return -EMSGSIZE;
16062306a36Sopenharmony_ci	return 0;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int tls_handshake_put_certificate(struct sk_buff *msg,
16462306a36Sopenharmony_ci					 struct tls_handshake_req *treq)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct nlattr *entry_attr;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (treq->th_certificate == TLS_NO_CERT &&
16962306a36Sopenharmony_ci	    treq->th_privkey == TLS_NO_PRIVKEY)
17062306a36Sopenharmony_ci		return 0;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	entry_attr = nla_nest_start(msg, HANDSHAKE_A_ACCEPT_CERTIFICATE);
17362306a36Sopenharmony_ci	if (!entry_attr)
17462306a36Sopenharmony_ci		return -EMSGSIZE;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (nla_put_u32(msg, HANDSHAKE_A_X509_CERT,
17762306a36Sopenharmony_ci			treq->th_certificate) ||
17862306a36Sopenharmony_ci	    nla_put_u32(msg, HANDSHAKE_A_X509_PRIVKEY,
17962306a36Sopenharmony_ci			treq->th_privkey)) {
18062306a36Sopenharmony_ci		nla_nest_cancel(msg, entry_attr);
18162306a36Sopenharmony_ci		return -EMSGSIZE;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	nla_nest_end(msg, entry_attr);
18562306a36Sopenharmony_ci	return 0;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/**
18962306a36Sopenharmony_ci * tls_handshake_accept - callback to construct a CMD_ACCEPT response
19062306a36Sopenharmony_ci * @req: handshake parameters to return
19162306a36Sopenharmony_ci * @info: generic netlink message context
19262306a36Sopenharmony_ci * @fd: file descriptor to be returned
19362306a36Sopenharmony_ci *
19462306a36Sopenharmony_ci * Returns zero on success, or a negative errno on failure.
19562306a36Sopenharmony_ci */
19662306a36Sopenharmony_cistatic int tls_handshake_accept(struct handshake_req *req,
19762306a36Sopenharmony_ci				struct genl_info *info, int fd)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct tls_handshake_req *treq = handshake_req_private(req);
20062306a36Sopenharmony_ci	struct nlmsghdr *hdr;
20162306a36Sopenharmony_ci	struct sk_buff *msg;
20262306a36Sopenharmony_ci	int ret;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	ret = tls_handshake_private_keyring(treq);
20562306a36Sopenharmony_ci	if (ret < 0)
20662306a36Sopenharmony_ci		goto out;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	ret = -ENOMEM;
20962306a36Sopenharmony_ci	msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
21062306a36Sopenharmony_ci	if (!msg)
21162306a36Sopenharmony_ci		goto out;
21262306a36Sopenharmony_ci	hdr = handshake_genl_put(msg, info);
21362306a36Sopenharmony_ci	if (!hdr)
21462306a36Sopenharmony_ci		goto out_cancel;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	ret = -EMSGSIZE;
21762306a36Sopenharmony_ci	ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_SOCKFD, fd);
21862306a36Sopenharmony_ci	if (ret < 0)
21962306a36Sopenharmony_ci		goto out_cancel;
22062306a36Sopenharmony_ci	ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MESSAGE_TYPE, treq->th_type);
22162306a36Sopenharmony_ci	if (ret < 0)
22262306a36Sopenharmony_ci		goto out_cancel;
22362306a36Sopenharmony_ci	if (treq->th_peername) {
22462306a36Sopenharmony_ci		ret = nla_put_string(msg, HANDSHAKE_A_ACCEPT_PEERNAME,
22562306a36Sopenharmony_ci				     treq->th_peername);
22662306a36Sopenharmony_ci		if (ret < 0)
22762306a36Sopenharmony_ci			goto out_cancel;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci	if (treq->th_timeout_ms) {
23062306a36Sopenharmony_ci		ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_TIMEOUT, treq->th_timeout_ms);
23162306a36Sopenharmony_ci		if (ret < 0)
23262306a36Sopenharmony_ci			goto out_cancel;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_AUTH_MODE,
23662306a36Sopenharmony_ci			  treq->th_auth_mode);
23762306a36Sopenharmony_ci	if (ret < 0)
23862306a36Sopenharmony_ci		goto out_cancel;
23962306a36Sopenharmony_ci	switch (treq->th_auth_mode) {
24062306a36Sopenharmony_ci	case HANDSHAKE_AUTH_PSK:
24162306a36Sopenharmony_ci		ret = tls_handshake_put_peer_identity(msg, treq);
24262306a36Sopenharmony_ci		if (ret < 0)
24362306a36Sopenharmony_ci			goto out_cancel;
24462306a36Sopenharmony_ci		break;
24562306a36Sopenharmony_ci	case HANDSHAKE_AUTH_X509:
24662306a36Sopenharmony_ci		ret = tls_handshake_put_certificate(msg, treq);
24762306a36Sopenharmony_ci		if (ret < 0)
24862306a36Sopenharmony_ci			goto out_cancel;
24962306a36Sopenharmony_ci		break;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	genlmsg_end(msg, hdr);
25362306a36Sopenharmony_ci	return genlmsg_reply(msg, info);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ciout_cancel:
25662306a36Sopenharmony_ci	genlmsg_cancel(msg, hdr);
25762306a36Sopenharmony_ciout:
25862306a36Sopenharmony_ci	return ret;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic const struct handshake_proto tls_handshake_proto = {
26262306a36Sopenharmony_ci	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
26362306a36Sopenharmony_ci	.hp_privsize		= sizeof(struct tls_handshake_req),
26462306a36Sopenharmony_ci	.hp_flags		= BIT(HANDSHAKE_F_PROTO_NOTIFY),
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	.hp_accept		= tls_handshake_accept,
26762306a36Sopenharmony_ci	.hp_done		= tls_handshake_done,
26862306a36Sopenharmony_ci};
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/**
27162306a36Sopenharmony_ci * tls_client_hello_anon - request an anonymous TLS handshake on a socket
27262306a36Sopenharmony_ci * @args: socket and handshake parameters for this request
27362306a36Sopenharmony_ci * @flags: memory allocation control flags
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci * Return values:
27662306a36Sopenharmony_ci *   %0: Handshake request enqueue; ->done will be called when complete
27762306a36Sopenharmony_ci *   %-ESRCH: No user agent is available
27862306a36Sopenharmony_ci *   %-ENOMEM: Memory allocation failed
27962306a36Sopenharmony_ci */
28062306a36Sopenharmony_ciint tls_client_hello_anon(const struct tls_handshake_args *args, gfp_t flags)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct tls_handshake_req *treq;
28362306a36Sopenharmony_ci	struct handshake_req *req;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	req = handshake_req_alloc(&tls_handshake_proto, flags);
28662306a36Sopenharmony_ci	if (!req)
28762306a36Sopenharmony_ci		return -ENOMEM;
28862306a36Sopenharmony_ci	treq = tls_handshake_req_init(req, args);
28962306a36Sopenharmony_ci	treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
29062306a36Sopenharmony_ci	treq->th_auth_mode = HANDSHAKE_AUTH_UNAUTH;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return handshake_req_submit(args->ta_sock, req, flags);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ciEXPORT_SYMBOL(tls_client_hello_anon);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci/**
29762306a36Sopenharmony_ci * tls_client_hello_x509 - request an x.509-based TLS handshake on a socket
29862306a36Sopenharmony_ci * @args: socket and handshake parameters for this request
29962306a36Sopenharmony_ci * @flags: memory allocation control flags
30062306a36Sopenharmony_ci *
30162306a36Sopenharmony_ci * Return values:
30262306a36Sopenharmony_ci *   %0: Handshake request enqueue; ->done will be called when complete
30362306a36Sopenharmony_ci *   %-ESRCH: No user agent is available
30462306a36Sopenharmony_ci *   %-ENOMEM: Memory allocation failed
30562306a36Sopenharmony_ci */
30662306a36Sopenharmony_ciint tls_client_hello_x509(const struct tls_handshake_args *args, gfp_t flags)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	struct tls_handshake_req *treq;
30962306a36Sopenharmony_ci	struct handshake_req *req;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	req = handshake_req_alloc(&tls_handshake_proto, flags);
31262306a36Sopenharmony_ci	if (!req)
31362306a36Sopenharmony_ci		return -ENOMEM;
31462306a36Sopenharmony_ci	treq = tls_handshake_req_init(req, args);
31562306a36Sopenharmony_ci	treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
31662306a36Sopenharmony_ci	treq->th_auth_mode = HANDSHAKE_AUTH_X509;
31762306a36Sopenharmony_ci	treq->th_certificate = args->ta_my_cert;
31862306a36Sopenharmony_ci	treq->th_privkey = args->ta_my_privkey;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return handshake_req_submit(args->ta_sock, req, flags);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ciEXPORT_SYMBOL(tls_client_hello_x509);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci/**
32562306a36Sopenharmony_ci * tls_client_hello_psk - request a PSK-based TLS handshake on a socket
32662306a36Sopenharmony_ci * @args: socket and handshake parameters for this request
32762306a36Sopenharmony_ci * @flags: memory allocation control flags
32862306a36Sopenharmony_ci *
32962306a36Sopenharmony_ci * Return values:
33062306a36Sopenharmony_ci *   %0: Handshake request enqueue; ->done will be called when complete
33162306a36Sopenharmony_ci *   %-EINVAL: Wrong number of local peer IDs
33262306a36Sopenharmony_ci *   %-ESRCH: No user agent is available
33362306a36Sopenharmony_ci *   %-ENOMEM: Memory allocation failed
33462306a36Sopenharmony_ci */
33562306a36Sopenharmony_ciint tls_client_hello_psk(const struct tls_handshake_args *args, gfp_t flags)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	struct tls_handshake_req *treq;
33862306a36Sopenharmony_ci	struct handshake_req *req;
33962306a36Sopenharmony_ci	unsigned int i;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (!args->ta_num_peerids ||
34262306a36Sopenharmony_ci	    args->ta_num_peerids > ARRAY_SIZE(treq->th_peerid))
34362306a36Sopenharmony_ci		return -EINVAL;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	req = handshake_req_alloc(&tls_handshake_proto, flags);
34662306a36Sopenharmony_ci	if (!req)
34762306a36Sopenharmony_ci		return -ENOMEM;
34862306a36Sopenharmony_ci	treq = tls_handshake_req_init(req, args);
34962306a36Sopenharmony_ci	treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
35062306a36Sopenharmony_ci	treq->th_auth_mode = HANDSHAKE_AUTH_PSK;
35162306a36Sopenharmony_ci	treq->th_num_peerids = args->ta_num_peerids;
35262306a36Sopenharmony_ci	for (i = 0; i < args->ta_num_peerids; i++)
35362306a36Sopenharmony_ci		treq->th_peerid[i] = args->ta_my_peerids[i];
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return handshake_req_submit(args->ta_sock, req, flags);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ciEXPORT_SYMBOL(tls_client_hello_psk);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci/**
36062306a36Sopenharmony_ci * tls_server_hello_x509 - request a server TLS handshake on a socket
36162306a36Sopenharmony_ci * @args: socket and handshake parameters for this request
36262306a36Sopenharmony_ci * @flags: memory allocation control flags
36362306a36Sopenharmony_ci *
36462306a36Sopenharmony_ci * Return values:
36562306a36Sopenharmony_ci *   %0: Handshake request enqueue; ->done will be called when complete
36662306a36Sopenharmony_ci *   %-ESRCH: No user agent is available
36762306a36Sopenharmony_ci *   %-ENOMEM: Memory allocation failed
36862306a36Sopenharmony_ci */
36962306a36Sopenharmony_ciint tls_server_hello_x509(const struct tls_handshake_args *args, gfp_t flags)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct tls_handshake_req *treq;
37262306a36Sopenharmony_ci	struct handshake_req *req;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	req = handshake_req_alloc(&tls_handshake_proto, flags);
37562306a36Sopenharmony_ci	if (!req)
37662306a36Sopenharmony_ci		return -ENOMEM;
37762306a36Sopenharmony_ci	treq = tls_handshake_req_init(req, args);
37862306a36Sopenharmony_ci	treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO;
37962306a36Sopenharmony_ci	treq->th_auth_mode = HANDSHAKE_AUTH_X509;
38062306a36Sopenharmony_ci	treq->th_certificate = args->ta_my_cert;
38162306a36Sopenharmony_ci	treq->th_privkey = args->ta_my_privkey;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return handshake_req_submit(args->ta_sock, req, flags);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ciEXPORT_SYMBOL(tls_server_hello_x509);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/**
38862306a36Sopenharmony_ci * tls_server_hello_psk - request a server TLS handshake on a socket
38962306a36Sopenharmony_ci * @args: socket and handshake parameters for this request
39062306a36Sopenharmony_ci * @flags: memory allocation control flags
39162306a36Sopenharmony_ci *
39262306a36Sopenharmony_ci * Return values:
39362306a36Sopenharmony_ci *   %0: Handshake request enqueue; ->done will be called when complete
39462306a36Sopenharmony_ci *   %-ESRCH: No user agent is available
39562306a36Sopenharmony_ci *   %-ENOMEM: Memory allocation failed
39662306a36Sopenharmony_ci */
39762306a36Sopenharmony_ciint tls_server_hello_psk(const struct tls_handshake_args *args, gfp_t flags)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct tls_handshake_req *treq;
40062306a36Sopenharmony_ci	struct handshake_req *req;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	req = handshake_req_alloc(&tls_handshake_proto, flags);
40362306a36Sopenharmony_ci	if (!req)
40462306a36Sopenharmony_ci		return -ENOMEM;
40562306a36Sopenharmony_ci	treq = tls_handshake_req_init(req, args);
40662306a36Sopenharmony_ci	treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO;
40762306a36Sopenharmony_ci	treq->th_auth_mode = HANDSHAKE_AUTH_PSK;
40862306a36Sopenharmony_ci	treq->th_num_peerids = 1;
40962306a36Sopenharmony_ci	treq->th_peerid[0] = args->ta_my_peerids[0];
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	return handshake_req_submit(args->ta_sock, req, flags);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ciEXPORT_SYMBOL(tls_server_hello_psk);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/**
41662306a36Sopenharmony_ci * tls_handshake_cancel - cancel a pending handshake
41762306a36Sopenharmony_ci * @sk: socket on which there is an ongoing handshake
41862306a36Sopenharmony_ci *
41962306a36Sopenharmony_ci * Request cancellation races with request completion. To determine
42062306a36Sopenharmony_ci * who won, callers examine the return value from this function.
42162306a36Sopenharmony_ci *
42262306a36Sopenharmony_ci * Return values:
42362306a36Sopenharmony_ci *   %true - Uncompleted handshake request was canceled
42462306a36Sopenharmony_ci *   %false - Handshake request already completed or not found
42562306a36Sopenharmony_ci */
42662306a36Sopenharmony_cibool tls_handshake_cancel(struct sock *sk)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	return handshake_req_cancel(sk);
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ciEXPORT_SYMBOL(tls_handshake_cancel);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci/**
43362306a36Sopenharmony_ci * tls_handshake_close - send a Closure alert
43462306a36Sopenharmony_ci * @sock: an open socket
43562306a36Sopenharmony_ci *
43662306a36Sopenharmony_ci */
43762306a36Sopenharmony_civoid tls_handshake_close(struct socket *sock)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct handshake_req *req;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	req = handshake_req_hash_lookup(sock->sk);
44262306a36Sopenharmony_ci	if (!req)
44362306a36Sopenharmony_ci		return;
44462306a36Sopenharmony_ci	if (!test_and_clear_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags))
44562306a36Sopenharmony_ci		return;
44662306a36Sopenharmony_ci	tls_alert_send(sock, TLS_ALERT_LEVEL_WARNING,
44762306a36Sopenharmony_ci		       TLS_ALERT_DESC_CLOSE_NOTIFY);
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ciEXPORT_SYMBOL(tls_handshake_close);
450