lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-ID: <8BF1087A-3977-40FA-B71C-AF4BFE5E5148@oracle.com> Date: Mon, 27 Feb 2023 15:01:56 +0000 From: Chuck Lever III <chuck.lever@...cle.com> To: Hannes Reinecke <hare@...e.de> CC: Chuck Lever <cel@...nel.org>, Jakub Kicinski <kuba@...nel.org>, Paolo Abeni <pabeni@...hat.com>, Eric Dumazet <edumazet@...gle.com>, "open list:NETWORKING [GENERAL]" <netdev@...r.kernel.org>, "kernel-tls-handshake@...ts.linux.dev" <kernel-tls-handshake@...ts.linux.dev> Subject: Re: [PATCH v5 2/2] net/tls: Add kernel APIs for requesting a TLSv1.3 handshake > On Feb 27, 2023, at 4:36 AM, Hannes Reinecke <hare@...e.de> wrote: > > On 2/24/23 20:19, Chuck Lever wrote: >> From: Chuck Lever <chuck.lever@...cle.com> >> To enable kernel consumers of TLS to request a TLS handshake, add >> support to net/tls/ to send a handshake upcall. This patch also >> acts as a template for adding handshake upcall support to other >> transport layer security mechanisms. >> Signed-off-by: Chuck Lever <chuck.lever@...cle.com> >> --- >> Documentation/netlink/specs/handshake.yaml | 4 >> Documentation/networking/index.rst | 1 >> Documentation/networking/tls-handshake.rst | 146 ++++++++++ >> include/net/tls.h | 27 ++ >> include/uapi/linux/handshake.h | 2 >> net/handshake/netlink.c | 1 >> net/tls/Makefile | 2 >> net/tls/tls_handshake.c | 423 ++++++++++++++++++++++++++++ >> 8 files changed, 604 insertions(+), 2 deletions(-) >> create mode 100644 Documentation/networking/tls-handshake.rst >> create mode 100644 net/tls/tls_handshake.c >> diff --git a/Documentation/netlink/specs/handshake.yaml b/Documentation/netlink/specs/handshake.yaml >> index 683a8f2df0a7..c2f6bfff2326 100644 >> --- a/Documentation/netlink/specs/handshake.yaml >> +++ b/Documentation/netlink/specs/handshake.yaml >> @@ -21,7 +21,7 @@ definitions: >> name: handler-class >> enum-name: >> value-start: 0 >> - entries: [ none ] >> + entries: [ none, tlshd ] >> - >> type: enum >> name: msg-type >> @@ -132,3 +132,5 @@ mcast-groups: >> list: >> - >> name: none >> + - >> + name: tlshd >> diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst >> index 4ddcae33c336..189517f4ea96 100644 >> --- a/Documentation/networking/index.rst >> +++ b/Documentation/networking/index.rst >> @@ -36,6 +36,7 @@ Contents: >> scaling >> tls >> tls-offload >> + tls-handshake >> nfc >> 6lowpan >> 6pack >> diff --git a/Documentation/networking/tls-handshake.rst b/Documentation/networking/tls-handshake.rst >> new file mode 100644 >> index 000000000000..f09fc6c09580 >> --- /dev/null >> +++ b/Documentation/networking/tls-handshake.rst >> @@ -0,0 +1,146 @@ >> +.. SPDX-License-Identifier: GPL-2.0 >> + >> +======================= >> +In-Kernel TLS Handshake >> +======================= >> + >> +Overview >> +======== >> + >> +Transport Layer Security (TLS) is a Upper Layer Protocol (ULP) that runs >> +over TCP. TLS provides end-to-end data integrity and confidentiality, >> +in addition to peer authentication. >> + >> +The kernel's kTLS implementation handles the TLS record subprotocol, but >> +does not handle the TLS handshake subprotocol which is used to establish >> +a TLS session. Kernel consumers can use the API described here to >> +request TLS session establishment. >> + >> +There are several possible ways to provide a handshake service in the >> +kernel. The API described here is designed to hide the details of those >> +implementations so that in-kernel TLS consumers do not need to be >> +aware of how the handshake gets done. >> + >> + >> +User handshake agent >> +==================== >> + >> +As of this writing, there is no TLS handshake implementation in the >> +Linux kernel. Thus, with the current implementation, a user agent is >> +started in each network namespace where a kernel consumer might require >> +a TLS handshake. This agent listens for events sent from the kernel >> +that request a handshake on an open and connected TCP socket. >> + >> +The open socket is passed to user space via a netlink operation, which >> +creates a socket descriptor in the agent's file descriptor table. If the >> +handshake completes successfully, the user agent promotes the socket to >> +use the TLS ULP and sets the session information using the SOL_TLS socket >> +options. The user agent returns the socket to the kernel via a second >> +netlink operation. >> + >> + >> +Kernel Handshake API >> +==================== >> + >> +A kernel TLS consumer initiates a client-side TLS handshake on an open >> +socket by invoking one of the tls_client_hello() functions. For example: >> + >> +.. code-block:: c >> + >> + ret = tls_client_hello_x509(sock, done_func, cookie, priorities, >> + cert, privkey); >> + >> +The function returns zero when the handshake request is under way. A >> +zero return guarantees the callback function @done_func will be invoked >> +for this socket. >> + >> +The function returns a negative errno if the handshake could not be >> +started. A negative errno guarantees the callback function @done_func >> +will not be invoked on this socket. >> + >> +The @sock argument is an open and connected socket. The caller must hold >> +a reference on the socket to prevent it from being destroyed while the >> +handshake is in progress. >> + >> +@...e_func and @cookie are a callback function that is invoked when the >> +handshake has completed. The success status of the handshake is returned >> +via the @status parameter of the callback function. A good practice is >> +to close and destroy the socket immediately if the handshake has failed. >> + >> +@...orities is a GnuTLS priorities string that controls the handshake. >> +The special value TLS_DEFAULT_PRIORITIES causes the handshake to >> +operate using default TLS priorities. However, the caller can use the >> +string to (for example) adjust the handshake to use a restricted set >> +of ciphers (say, if the kernel consumer wishes to mandate only a >> +limited set of ciphers). >> + >> +@...t is the serial number of a key that contains a DER format x.509 >> +certificate that the handshake agent presents to the remote as the local >> +peer's identity. >> + >> +@...vkey is the serial number of a key that contains a DER-format >> +private key associated with the x.509 certificate. >> + >> + >> +To initiate a client-side TLS handshake with a pre-shared key, use: >> + >> +.. code-block:: c >> + >> + ret = tls_client_hello_psk(sock, done_func, cookie, priorities, >> + peerid); >> + >> +@...rid is the serial number of a key that contains the pre-shared >> +key to be used for the handshake. >> + >> +The other parameters are as above. >> + >> + >> +To initiate an anonymous client-side TLS handshake use: >> + >> +.. code-block:: c >> + >> + ret = tls_client_hello_anon(sock, done_func, cookie, priorities); >> + >> +The parameters are as above. >> + >> +The handshake agent presents no peer identity information to the >> +remote during the handshake. Only server authentication is performed >> +during the handshake. Thus the established session uses encryption >> +only. >> + >> + >> +Consumers that are in-kernel servers use: >> + >> +.. code-block:: c >> + >> + ret = tls_server_hello(sock, done_func, cookie, priorities); >> + >> +The parameters for this operation are as above. >> + >> + >> +Lastly, if the consumer needs to cancel the handshake request, say, >> +due to a ^C or other exigent event, the handshake core provides >> +this API: >> + >> +.. code-block:: c >> + >> + handshake_cancel(sock); >> + >> + >> +Other considerations >> +-------------------- >> + >> +While a handshake is under way, the kernel consumer must alter the >> +socket's sk_data_ready callback function to ignore all incoming data. >> +Once the handshake completion callback function has been invoked, >> +normal receive operation can be resumed. >> + >> +Once a TLS session is established, the consumer must provide a buffer >> +for and then examine the control message (CMSG) that is part of every >> +subsequent sock_recvmsg(). Each control message indicates whether the >> +received message data is TLS record data or session metadata. >> + >> +See tls.rst for details on how a kTLS consumer recognizes incoming >> +(decrypted) application data, alerts, and handshake packets once the >> +socket has been promoted to use the TLS ULP. >> + >> diff --git a/include/net/tls.h b/include/net/tls.h >> index 154949c7b0c8..505b23992ef0 100644 >> --- a/include/net/tls.h >> +++ b/include/net/tls.h >> @@ -512,4 +512,31 @@ static inline bool tls_is_sk_rx_device_offloaded(struct sock *sk) >> return tls_get_ctx(sk)->rx_conf == TLS_HW; >> } >> #endif >> + >> +#define TLS_DEFAULT_PRIORITIES (NULL) >> + > > Hmm? What is the point in this? > It's not that we can overwrite it later on ... > >> +enum { >> + TLS_NO_PEERID = 0, >> + TLS_NO_CERT = 0, >> + TLS_NO_PRIVKEY = 0, >> +}; >> + >> +typedef void (*tls_done_func_t)(void *data, int status, >> + key_serial_t peerid); >> + >> +int tls_client_hello_anon(struct socket *sock, tls_done_func_t done, >> + void *data, const char *priorities); >> +int tls_client_hello_x509(struct socket *sock, tls_done_func_t done, >> + void *data, const char *priorities, >> + key_serial_t cert, key_serial_t privkey); >> +int tls_client_hello_psk(struct socket *sock, tls_done_func_t done, >> + void *data, const char *priorities, >> + key_serial_t peerid); >> +int tls_server_hello_x509(struct socket *sock, tls_done_func_t done, >> + void *data, const char *priorities); >> +int tls_server_hello_psk(struct socket *sock, tls_done_func_t done, >> + void *data, const char *priorities); >> + >> +int tls_handshake_cancel(struct socket *sock); >> + >> #endif /* _TLS_OFFLOAD_H */ >> diff --git a/include/uapi/linux/handshake.h b/include/uapi/linux/handshake.h >> index 09fd7c37cba4..dad8227939a1 100644 >> --- a/include/uapi/linux/handshake.h >> +++ b/include/uapi/linux/handshake.h >> @@ -11,6 +11,7 @@ >> enum { >> HANDSHAKE_HANDLER_CLASS_NONE, >> + HANDSHAKE_HANDLER_CLASS_TLSHD, >> }; >> enum { >> @@ -59,5 +60,6 @@ enum { >> }; >> #define HANDSHAKE_MCGRP_NONE "none" >> +#define HANDSHAKE_MCGRP_TLSHD "tlshd" >> #endif /* _UAPI_LINUX_HANDSHAKE_H */ >> diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c >> index 581e382236cf..88775f784305 100644 >> --- a/net/handshake/netlink.c >> +++ b/net/handshake/netlink.c >> @@ -255,6 +255,7 @@ static const struct genl_split_ops handshake_nl_ops[] = { >> static const struct genl_multicast_group handshake_nl_mcgrps[] = { >> [HANDSHAKE_HANDLER_CLASS_NONE] = { .name = HANDSHAKE_MCGRP_NONE, }, >> + [HANDSHAKE_HANDLER_CLASS_TLSHD] = { .name = HANDSHAKE_MCGRP_TLSHD, }, >> }; >> static struct genl_family __ro_after_init handshake_genl_family = { >> diff --git a/net/tls/Makefile b/net/tls/Makefile >> index e41c800489ac..7e56b57f14f6 100644 >> --- a/net/tls/Makefile >> +++ b/net/tls/Makefile >> @@ -7,7 +7,7 @@ CFLAGS_trace.o := -I$(src) >> obj-$(CONFIG_TLS) += tls.o >> -tls-y := tls_main.o tls_sw.o tls_proc.o trace.o tls_strp.o >> +tls-y := tls_handshake.o tls_main.o tls_sw.o tls_proc.o trace.o tls_strp.o >> > I'd rather tack the new file at the end, but that might be personal preference ... > >> tls-$(CONFIG_TLS_TOE) += tls_toe.o >> tls-$(CONFIG_TLS_DEVICE) += tls_device.o tls_device_fallback.o >> diff --git a/net/tls/tls_handshake.c b/net/tls/tls_handshake.c >> new file mode 100644 >> index 000000000000..74d32a9ca857 >> --- /dev/null >> +++ b/net/tls/tls_handshake.c >> @@ -0,0 +1,423 @@ >> +// SPDX-License-Identifier: GPL-2.0-only >> +/* >> + * Establish a TLS session for a kernel socket consumer >> + * >> + * Author: Chuck Lever <chuck.lever@...cle.com> >> + * >> + * Copyright (c) 2021-2023, Oracle and/or its affiliates. >> + */ >> + >> +#include <linux/types.h> >> +#include <linux/socket.h> >> +#include <linux/kernel.h> >> +#include <linux/module.h> >> +#include <linux/slab.h> >> + >> +#include <net/sock.h> >> +#include <net/tls.h> >> +#include <net/genetlink.h> >> +#include <net/handshake.h> >> + >> +#include <uapi/linux/handshake.h> >> + >> +/* >> + * TLS priorities string passed to the GnuTLS library. >> + * >> + * Specifically for kernel TLS consumers: enable only TLS v1.3 and the >> + * ciphers that are supported by kTLS. >> + * >> + * Currently this list is generated by hand from the supported ciphers >> + * found in include/uapi/linux/tls.h. >> + */ >> +#define KTLS_DEFAULT_PRIORITIES \ >> + "SECURE256:+SECURE128:-COMP-ALL" \ >> + ":-VERS-ALL:+VERS-TLS1.3:%NO_TICKETS" \ >> + ":-CIPHER-ALL:+CHACHA20-POLY1305:+AES-256-GCM:+AES-128-GCM:+AES-128-CCM" >> + >> +struct tls_handshake_req { >> + void (*th_consumer_done)(void *data, int status, >> + key_serial_t peerid); >> + void *th_consumer_data; >> + >> + const char *th_priorities; >> + int th_type; >> + int th_auth_type; >> + key_serial_t th_peerid; >> + key_serial_t th_certificate; >> + key_serial_t th_privkey; >> + >> +}; >> + >> +static const char *tls_handshake_dup_priorities(const char *priorities, >> + gfp_t flags) >> +{ >> + const char *tp; >> + >> + if (priorities != TLS_DEFAULT_PRIORITIES && strlen(priorities)) > See above. At TLS_DEFAULT_PRIORITIES is NULL we can leave out the first condition. strlen() crashes if it's passed a NULL pointer. What I'm thinking of instead is to simply remove the "priorities" argument from tls_{client,server}_hello, and leave it as something that is between net/tls/tls_handshake.c and tlshd. >> + tp = priorities; >> + else >> + tp = KTLS_DEFAULT_PRIORITIES; >> + return kstrdup(tp, flags); >> +} >> + >> +static struct tls_handshake_req * >> +tls_handshake_req_init(struct handshake_req *req, tls_done_func_t done, >> + void *data, const char *priorities) >> +{ >> + struct tls_handshake_req *treq = handshake_req_private(req); >> + >> + treq->th_consumer_done = done; >> + treq->th_consumer_data = data; >> + treq->th_priorities = priorities; >> + treq->th_peerid = TLS_NO_PEERID; >> + treq->th_certificate = TLS_NO_CERT; >> + treq->th_privkey = TLS_NO_PRIVKEY; >> + return treq; >> +} >> + >> +/** >> + * tls_handshake_destroy - callback to release a handshake request >> + * @req: handshake parameters to release >> + * >> + */ >> +static void tls_handshake_destroy(struct handshake_req *req) >> +{ >> + struct tls_handshake_req *treq = handshake_req_private(req); >> + >> + kfree(treq->th_priorities); >> +} >> + >> +/** >> + * tls_handshake_done - callback to handle a CMD_DONE request >> + * @req: socket on which the handshake was performed >> + * @status: session status code >> + * @tb: other results of session establishment >> + * >> + * Eventually this will return information about the established >> + * session: whether it is authenticated, and if so, who the remote >> + * is. >> + */ >> +static void tls_handshake_done(struct handshake_req *req, int status, >> + struct nlattr **tb) >> +{ >> + struct tls_handshake_req *treq = handshake_req_private(req); >> + key_serial_t peerid = TLS_NO_PEERID; >> + >> + if (tb[HANDSHAKE_A_DONE_REMOTE_PEERID]) >> + peerid = nla_get_u32(tb[HANDSHAKE_A_DONE_REMOTE_PEERID]); >> + >> + treq->th_consumer_done(treq->th_consumer_data, status, peerid); >> +} >> + >> +static int tls_handshake_put_accept_resp(struct sk_buff *msg, >> + struct tls_handshake_req *treq) >> +{ >> + int ret; >> + >> + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MESSAGE_TYPE, treq->th_type); >> + if (ret < 0) >> + goto out; >> + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_AUTH, treq->th_auth_type); >> + if (ret < 0) >> + goto out; >> + switch (treq->th_auth_type) { >> + case HANDSHAKE_AUTH_X509: >> + if (treq->th_certificate != TLS_NO_CERT) { >> + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MY_PEERID, >> + treq->th_certificate); >> + if (ret < 0) >> + goto out; >> + } >> + if (treq->th_privkey != TLS_NO_PRIVKEY) { >> + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MY_PRIVKEY, >> + treq->th_privkey); >> + if (ret < 0) >> + goto out; >> + } >> + break; >> + case HANDSHAKE_AUTH_PSK: >> + if (treq->th_peerid != TLS_NO_PEERID) { >> + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MY_PEERID, >> + treq->th_peerid); >> + if (ret < 0) >> + goto out; >> + } >> + break; >> + } >> + >> + ret = nla_put_string(msg, HANDSHAKE_A_ACCEPT_GNUTLS_PRIORITIES, >> + treq->th_priorities); >> + if (ret < 0) >> + goto out; >> + >> + ret = 0; >> + >> +out: >> + return ret; >> +} >> + >> +/** >> + * tls_handshake_accept - callback to construct a CMD_ACCEPT response >> + * @req: handshake parameters to return >> + * @gi: generic netlink message context >> + * @fd: file descriptor to be returned >> + * >> + * Returns zero on success, or a negative errno on failure. >> + */ >> +static int tls_handshake_accept(struct handshake_req *req, >> + struct genl_info *gi, int fd) >> +{ >> + struct tls_handshake_req *treq = handshake_req_private(req); >> + struct nlmsghdr *hdr; >> + struct sk_buff *msg; >> + int ret; >> + >> + ret = -ENOMEM; >> + msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); >> + if (!msg) >> + goto out; >> + hdr = handshake_genl_put(msg, gi); >> + if (!hdr) >> + goto out_cancel; >> + >> + ret = -EMSGSIZE; >> + ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_SOCKFD, fd); >> + if (ret < 0) >> + goto out_cancel; >> + >> + ret = tls_handshake_put_accept_resp(msg, treq); >> + if (ret < 0) >> + goto out_cancel; >> + >> + genlmsg_end(msg, hdr); >> + return genlmsg_reply(msg, gi); >> + >> +out_cancel: >> + genlmsg_cancel(msg, hdr); >> +out: >> + return ret; >> +} >> + >> +static const struct handshake_proto tls_handshake_proto = { >> + .hp_handler_class = HANDSHAKE_HANDLER_CLASS_TLSHD, >> + .hp_privsize = sizeof(struct tls_handshake_req), >> + >> + .hp_accept = tls_handshake_accept, >> + .hp_done = tls_handshake_done, >> + .hp_destroy = tls_handshake_destroy, >> +}; >> + >> +/** >> + * tls_client_hello_anon - request an anonymous TLS handshake on a socket >> + * @sock: connected socket on which to perform the handshake >> + * @done: function to call when the handshake has completed >> + * @data: token to pass back to @done >> + * @priorities: GnuTLS TLS priorities string, or NULL >> + * >> + * Return values: >> + * %0: Handshake request enqueue; ->done will be called when complete >> + * %-ENOENT: No user agent is available >> + * %-ENOMEM: Memory allocation failed >> + */ >> +int tls_client_hello_anon(struct socket *sock, tls_done_func_t done, >> + void *data, const char *priorities) >> +{ >> + struct tls_handshake_req *treq; >> + struct handshake_req *req; >> + gfp_t flags = GFP_NOWAIT; >> + const char *tp; >> + >> + tp = tls_handshake_dup_priorities(priorities, flags); >> + if (!tp) >> + return -ENOMEM; >> + >> + req = handshake_req_alloc(sock, &tls_handshake_proto, flags); >> + if (!req) { >> + kfree(tp); >> + return -ENOMEM; >> + } >> + >> + treq = tls_handshake_req_init(req, done, data, tp); >> + treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO; >> + treq->th_auth_type = HANDSHAKE_AUTH_UNAUTH; >> + >> + return handshake_req_submit(req, flags); >> +} >> +EXPORT_SYMBOL(tls_client_hello_anon); >> + >> +/** >> + * tls_client_hello_x509 - request an x.509-based TLS handshake on a socket >> + * @sock: connected socket on which to perform the handshake >> + * @done: function to call when the handshake has completed >> + * @data: token to pass back to @done >> + * @priorities: GnuTLS TLS priorities string >> + * @cert: serial number of key containing client's x.509 certificate >> + * @privkey: serial number of key containing client's private key >> + * >> + * Return values: >> + * %0: Handshake request enqueue; ->done will be called when complete >> + * %-ENOENT: No user agent is available >> + * %-ENOMEM: Memory allocation failed >> + */ >> +int tls_client_hello_x509(struct socket *sock, tls_done_func_t done, >> + void *data, const char *priorities, >> + key_serial_t cert, key_serial_t privkey) >> +{ >> + struct tls_handshake_req *treq; >> + struct handshake_req *req; >> + gfp_t flags = GFP_NOWAIT; >> + const char *tp; >> + >> + tp = tls_handshake_dup_priorities(priorities, flags); >> + if (!tp) >> + return -ENOMEM; >> + >> + req = handshake_req_alloc(sock, &tls_handshake_proto, flags); >> + if (!req) { >> + kfree(tp); >> + return -ENOMEM; >> + } >> + >> + treq = tls_handshake_req_init(req, done, data, tp); >> + treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO; >> + treq->th_auth_type = HANDSHAKE_AUTH_X509; >> + treq->th_certificate = cert; >> + treq->th_privkey = privkey; >> + >> + return handshake_req_submit(req, flags); >> +} >> +EXPORT_SYMBOL(tls_client_hello_x509); >> + >> +/** >> + * tls_client_hello_psk - request a PSK-based TLS handshake on a socket >> + * @sock: connected socket on which to perform the handshake >> + * @done: function to call when the handshake has completed >> + * @data: token to pass back to @done >> + * @priorities: GnuTLS TLS priorities string >> + * @peerid: serial number of key containing TLS identity >> + * >> + * Return values: >> + * %0: Handshake request enqueue; ->done will be called when complete >> + * %-ENOENT: No user agent is available >> + * %-ENOMEM: Memory allocation failed >> + */ >> +int tls_client_hello_psk(struct socket *sock, tls_done_func_t done, >> + void *data, const char *priorities, >> + key_serial_t peerid) >> +{ >> + struct tls_handshake_req *treq; >> + struct handshake_req *req; >> + gfp_t flags = GFP_NOWAIT; >> + const char *tp; >> + >> + tp = tls_handshake_dup_priorities(priorities, flags); >> + if (!tp) >> + return -ENOMEM; >> + >> + req = handshake_req_alloc(sock, &tls_handshake_proto, flags); >> + if (!req) { >> + kfree(tp); >> + return -ENOMEM; >> + } >> + >> + treq = tls_handshake_req_init(req, done, data, tp); >> + treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO; >> + treq->th_auth_type = HANDSHAKE_AUTH_PSK; >> + treq->th_peerid = peerid; >> + >> + return handshake_req_submit(req, flags); >> +} >> +EXPORT_SYMBOL(tls_client_hello_psk); >> + >> +/** >> + * tls_server_hello_x509 - request a server TLS handshake on a socket >> + * @sock: connected socket on which to perform the handshake >> + * @done: function to call when the handshake has completed >> + * @data: token to pass back to @done >> + * @priorities: GnuTLS TLS priorities string >> + * >> + * Return values: >> + * %0: Handshake request enqueue; ->done will be called when complete >> + * %-ENOENT: No user agent is available >> + * %-ENOMEM: Memory allocation failed >> + */ >> +int tls_server_hello_x509(struct socket *sock, tls_done_func_t done, >> + void *data, const char *priorities) >> +{ >> + struct tls_handshake_req *treq; >> + struct handshake_req *req; >> + gfp_t flags = GFP_KERNEL; >> + const char *tp; >> + >> + tp = tls_handshake_dup_priorities(priorities, flags); >> + if (!tp) >> + return -ENOMEM; >> + >> + req = handshake_req_alloc(sock, &tls_handshake_proto, flags); >> + if (!req) { >> + kfree(tp); >> + return -ENOMEM; >> + } >> + >> + treq = tls_handshake_req_init(req, done, data, tp); >> + treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO; >> + treq->th_auth_type = HANDSHAKE_AUTH_X509; >> + >> + return handshake_req_submit(req, flags); >> +} >> +EXPORT_SYMBOL(tls_server_hello_x509); >> + >> +/** >> + * tls_server_hello_psk - request a server TLS handshake on a socket >> + * @sock: connected socket on which to perform the handshake >> + * @done: function to call when the handshake has completed >> + * @data: token to pass back to @done >> + * @priorities: GnuTLS TLS priorities string >> + * >> + * Return values: >> + * %0: Handshake request enqueue; ->done will be called when complete >> + * %-ENOENT: No user agent is available >> + * %-ENOMEM: Memory allocation failed >> + */ >> +int tls_server_hello_psk(struct socket *sock, tls_done_func_t done, >> + void *data, const char *priorities) >> +{ >> + struct tls_handshake_req *treq; >> + struct handshake_req *req; >> + gfp_t flags = GFP_KERNEL; >> + const char *tp; >> + >> + tp = tls_handshake_dup_priorities(priorities, flags); >> + if (!tp) >> + return -ENOMEM; >> + >> + req = handshake_req_alloc(sock, &tls_handshake_proto, flags); >> + if (!req) { >> + kfree(tp); >> + return -ENOMEM; >> + } >> + >> + treq = tls_handshake_req_init(req, done, data, tp); >> + treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO; >> + treq->th_auth_type = HANDSHAKE_AUTH_PSK; >> + >> + return handshake_req_submit(req, flags); >> +} >> +EXPORT_SYMBOL(tls_server_hello_psk); >> + >> +/** >> + * tls_handshake_cancel - cancel a pending handshake >> + * @sock: socket on which there is an ongoing handshake >> + * >> + * Request cancellation races with request completion. To determine >> + * who won, callers examine the return value from this function. >> + * >> + * Return values: >> + * %0 - Uncompleted handshake request was canceled >> + * %-EBUSY - Handshake request already completed >> + */ >> +int tls_handshake_cancel(struct socket *sock) >> +{ >> + return handshake_req_cancel(sock); >> +} >> +EXPORT_SYMBOL(tls_handshake_cancel); > > Cheers, > > Hannes > > -- Chuck Lever
Powered by blists - more mailing lists