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