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