~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/handshake/tlshd.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Establish a TLS session for a kernel socket consumer
  4  * using the tlshd user space handler.
  5  *
  6  * Author: Chuck Lever <chuck.lever@oracle.com>
  7  *
  8  * Copyright (c) 2021-2023, Oracle and/or its affiliates.
  9  */
 10 
 11 #include <linux/types.h>
 12 #include <linux/socket.h>
 13 #include <linux/kernel.h>
 14 #include <linux/module.h>
 15 #include <linux/slab.h>
 16 #include <linux/key.h>
 17 
 18 #include <net/sock.h>
 19 #include <net/handshake.h>
 20 #include <net/genetlink.h>
 21 #include <net/tls_prot.h>
 22 
 23 #include <uapi/linux/keyctl.h>
 24 #include <uapi/linux/handshake.h>
 25 #include "handshake.h"
 26 
 27 struct tls_handshake_req {
 28         void                    (*th_consumer_done)(void *data, int status,
 29                                                     key_serial_t peerid);
 30         void                    *th_consumer_data;
 31 
 32         int                     th_type;
 33         unsigned int            th_timeout_ms;
 34         int                     th_auth_mode;
 35         const char              *th_peername;
 36         key_serial_t            th_keyring;
 37         key_serial_t            th_certificate;
 38         key_serial_t            th_privkey;
 39 
 40         unsigned int            th_num_peerids;
 41         key_serial_t            th_peerid[5];
 42 };
 43 
 44 static struct tls_handshake_req *
 45 tls_handshake_req_init(struct handshake_req *req,
 46                        const struct tls_handshake_args *args)
 47 {
 48         struct tls_handshake_req *treq = handshake_req_private(req);
 49 
 50         treq->th_timeout_ms = args->ta_timeout_ms;
 51         treq->th_consumer_done = args->ta_done;
 52         treq->th_consumer_data = args->ta_data;
 53         treq->th_peername = args->ta_peername;
 54         treq->th_keyring = args->ta_keyring;
 55         treq->th_num_peerids = 0;
 56         treq->th_certificate = TLS_NO_CERT;
 57         treq->th_privkey = TLS_NO_PRIVKEY;
 58         return treq;
 59 }
 60 
 61 static void tls_handshake_remote_peerids(struct tls_handshake_req *treq,
 62                                          struct genl_info *info)
 63 {
 64         struct nlattr *head = nlmsg_attrdata(info->nlhdr, GENL_HDRLEN);
 65         int rem, len = nlmsg_attrlen(info->nlhdr, GENL_HDRLEN);
 66         struct nlattr *nla;
 67         unsigned int i;
 68 
 69         i = 0;
 70         nla_for_each_attr(nla, head, len, rem) {
 71                 if (nla_type(nla) == HANDSHAKE_A_DONE_REMOTE_AUTH)
 72                         i++;
 73         }
 74         if (!i)
 75                 return;
 76         treq->th_num_peerids = min_t(unsigned int, i,
 77                                      ARRAY_SIZE(treq->th_peerid));
 78 
 79         i = 0;
 80         nla_for_each_attr(nla, head, len, rem) {
 81                 if (nla_type(nla) == HANDSHAKE_A_DONE_REMOTE_AUTH)
 82                         treq->th_peerid[i++] = nla_get_u32(nla);
 83                 if (i >= treq->th_num_peerids)
 84                         break;
 85         }
 86 }
 87 
 88 /**
 89  * tls_handshake_done - callback to handle a CMD_DONE request
 90  * @req: socket on which the handshake was performed
 91  * @status: session status code
 92  * @info: full results of session establishment
 93  *
 94  */
 95 static void tls_handshake_done(struct handshake_req *req,
 96                                unsigned int status, struct genl_info *info)
 97 {
 98         struct tls_handshake_req *treq = handshake_req_private(req);
 99 
100         treq->th_peerid[0] = TLS_NO_PEERID;
101         if (info)
102                 tls_handshake_remote_peerids(treq, info);
103 
104         if (!status)
105                 set_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags);
106 
107         treq->th_consumer_done(treq->th_consumer_data, -status,
108                                treq->th_peerid[0]);
109 }
110 
111 #if IS_ENABLED(CONFIG_KEYS)
112 static int tls_handshake_private_keyring(struct tls_handshake_req *treq)
113 {
114         key_ref_t process_keyring_ref, keyring_ref;
115         int ret;
116 
117         if (treq->th_keyring == TLS_NO_KEYRING)
118                 return 0;
119 
120         process_keyring_ref = lookup_user_key(KEY_SPEC_PROCESS_KEYRING,
121                                               KEY_LOOKUP_CREATE,
122                                               KEY_NEED_WRITE);
123         if (IS_ERR(process_keyring_ref)) {
124                 ret = PTR_ERR(process_keyring_ref);
125                 goto out;
126         }
127 
128         keyring_ref = lookup_user_key(treq->th_keyring, KEY_LOOKUP_CREATE,
129                                       KEY_NEED_LINK);
130         if (IS_ERR(keyring_ref)) {
131                 ret = PTR_ERR(keyring_ref);
132                 goto out_put_key;
133         }
134 
135         ret = key_link(key_ref_to_ptr(process_keyring_ref),
136                        key_ref_to_ptr(keyring_ref));
137 
138         key_ref_put(keyring_ref);
139 out_put_key:
140         key_ref_put(process_keyring_ref);
141 out:
142         return ret;
143 }
144 #else
145 static int tls_handshake_private_keyring(struct tls_handshake_req *treq)
146 {
147         return 0;
148 }
149 #endif
150 
151 static int tls_handshake_put_peer_identity(struct sk_buff *msg,
152                                            struct tls_handshake_req *treq)
153 {
154         unsigned int i;
155 
156         for (i = 0; i < treq->th_num_peerids; i++)
157                 if (nla_put_u32(msg, HANDSHAKE_A_ACCEPT_PEER_IDENTITY,
158                                 treq->th_peerid[i]) < 0)
159                         return -EMSGSIZE;
160         return 0;
161 }
162 
163 static int tls_handshake_put_certificate(struct sk_buff *msg,
164                                          struct tls_handshake_req *treq)
165 {
166         struct nlattr *entry_attr;
167 
168         if (treq->th_certificate == TLS_NO_CERT &&
169             treq->th_privkey == TLS_NO_PRIVKEY)
170                 return 0;
171 
172         entry_attr = nla_nest_start(msg, HANDSHAKE_A_ACCEPT_CERTIFICATE);
173         if (!entry_attr)
174                 return -EMSGSIZE;
175 
176         if (nla_put_s32(msg, HANDSHAKE_A_X509_CERT,
177                         treq->th_certificate) ||
178             nla_put_s32(msg, HANDSHAKE_A_X509_PRIVKEY,
179                         treq->th_privkey)) {
180                 nla_nest_cancel(msg, entry_attr);
181                 return -EMSGSIZE;
182         }
183 
184         nla_nest_end(msg, entry_attr);
185         return 0;
186 }
187 
188 /**
189  * tls_handshake_accept - callback to construct a CMD_ACCEPT response
190  * @req: handshake parameters to return
191  * @info: generic netlink message context
192  * @fd: file descriptor to be returned
193  *
194  * Returns zero on success, or a negative errno on failure.
195  */
196 static int tls_handshake_accept(struct handshake_req *req,
197                                 struct genl_info *info, int fd)
198 {
199         struct tls_handshake_req *treq = handshake_req_private(req);
200         struct nlmsghdr *hdr;
201         struct sk_buff *msg;
202         int ret;
203 
204         ret = tls_handshake_private_keyring(treq);
205         if (ret < 0)
206                 goto out;
207 
208         ret = -ENOMEM;
209         msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
210         if (!msg)
211                 goto out;
212         hdr = handshake_genl_put(msg, info);
213         if (!hdr)
214                 goto out_cancel;
215 
216         ret = nla_put_s32(msg, HANDSHAKE_A_ACCEPT_SOCKFD, fd);
217         if (ret < 0)
218                 goto out_cancel;
219         ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MESSAGE_TYPE, treq->th_type);
220         if (ret < 0)
221                 goto out_cancel;
222         if (treq->th_peername) {
223                 ret = nla_put_string(msg, HANDSHAKE_A_ACCEPT_PEERNAME,
224                                      treq->th_peername);
225                 if (ret < 0)
226                         goto out_cancel;
227         }
228         if (treq->th_timeout_ms) {
229                 ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_TIMEOUT, treq->th_timeout_ms);
230                 if (ret < 0)
231                         goto out_cancel;
232         }
233 
234         ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_AUTH_MODE,
235                           treq->th_auth_mode);
236         if (ret < 0)
237                 goto out_cancel;
238         switch (treq->th_auth_mode) {
239         case HANDSHAKE_AUTH_PSK:
240                 ret = tls_handshake_put_peer_identity(msg, treq);
241                 if (ret < 0)
242                         goto out_cancel;
243                 break;
244         case HANDSHAKE_AUTH_X509:
245                 ret = tls_handshake_put_certificate(msg, treq);
246                 if (ret < 0)
247                         goto out_cancel;
248                 break;
249         }
250 
251         genlmsg_end(msg, hdr);
252         return genlmsg_reply(msg, info);
253 
254 out_cancel:
255         genlmsg_cancel(msg, hdr);
256 out:
257         return ret;
258 }
259 
260 static const struct handshake_proto tls_handshake_proto = {
261         .hp_handler_class       = HANDSHAKE_HANDLER_CLASS_TLSHD,
262         .hp_privsize            = sizeof(struct tls_handshake_req),
263         .hp_flags               = BIT(HANDSHAKE_F_PROTO_NOTIFY),
264 
265         .hp_accept              = tls_handshake_accept,
266         .hp_done                = tls_handshake_done,
267 };
268 
269 /**
270  * tls_client_hello_anon - request an anonymous TLS handshake on a socket
271  * @args: socket and handshake parameters for this request
272  * @flags: memory allocation control flags
273  *
274  * Return values:
275  *   %0: Handshake request enqueue; ->done will be called when complete
276  *   %-ESRCH: No user agent is available
277  *   %-ENOMEM: Memory allocation failed
278  */
279 int tls_client_hello_anon(const struct tls_handshake_args *args, gfp_t flags)
280 {
281         struct tls_handshake_req *treq;
282         struct handshake_req *req;
283 
284         req = handshake_req_alloc(&tls_handshake_proto, flags);
285         if (!req)
286                 return -ENOMEM;
287         treq = tls_handshake_req_init(req, args);
288         treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
289         treq->th_auth_mode = HANDSHAKE_AUTH_UNAUTH;
290 
291         return handshake_req_submit(args->ta_sock, req, flags);
292 }
293 EXPORT_SYMBOL(tls_client_hello_anon);
294 
295 /**
296  * tls_client_hello_x509 - request an x.509-based TLS handshake on a socket
297  * @args: socket and handshake parameters for this request
298  * @flags: memory allocation control flags
299  *
300  * Return values:
301  *   %0: Handshake request enqueue; ->done will be called when complete
302  *   %-ESRCH: No user agent is available
303  *   %-ENOMEM: Memory allocation failed
304  */
305 int tls_client_hello_x509(const struct tls_handshake_args *args, gfp_t flags)
306 {
307         struct tls_handshake_req *treq;
308         struct handshake_req *req;
309 
310         req = handshake_req_alloc(&tls_handshake_proto, flags);
311         if (!req)
312                 return -ENOMEM;
313         treq = tls_handshake_req_init(req, args);
314         treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
315         treq->th_auth_mode = HANDSHAKE_AUTH_X509;
316         treq->th_certificate = args->ta_my_cert;
317         treq->th_privkey = args->ta_my_privkey;
318 
319         return handshake_req_submit(args->ta_sock, req, flags);
320 }
321 EXPORT_SYMBOL(tls_client_hello_x509);
322 
323 /**
324  * tls_client_hello_psk - request a PSK-based TLS handshake on a socket
325  * @args: socket and handshake parameters for this request
326  * @flags: memory allocation control flags
327  *
328  * Return values:
329  *   %0: Handshake request enqueue; ->done will be called when complete
330  *   %-EINVAL: Wrong number of local peer IDs
331  *   %-ESRCH: No user agent is available
332  *   %-ENOMEM: Memory allocation failed
333  */
334 int tls_client_hello_psk(const struct tls_handshake_args *args, gfp_t flags)
335 {
336         struct tls_handshake_req *treq;
337         struct handshake_req *req;
338         unsigned int i;
339 
340         if (!args->ta_num_peerids ||
341             args->ta_num_peerids > ARRAY_SIZE(treq->th_peerid))
342                 return -EINVAL;
343 
344         req = handshake_req_alloc(&tls_handshake_proto, flags);
345         if (!req)
346                 return -ENOMEM;
347         treq = tls_handshake_req_init(req, args);
348         treq->th_type = HANDSHAKE_MSG_TYPE_CLIENTHELLO;
349         treq->th_auth_mode = HANDSHAKE_AUTH_PSK;
350         treq->th_num_peerids = args->ta_num_peerids;
351         for (i = 0; i < args->ta_num_peerids; i++)
352                 treq->th_peerid[i] = args->ta_my_peerids[i];
353 
354         return handshake_req_submit(args->ta_sock, req, flags);
355 }
356 EXPORT_SYMBOL(tls_client_hello_psk);
357 
358 /**
359  * tls_server_hello_x509 - request a server TLS handshake on a socket
360  * @args: socket and handshake parameters for this request
361  * @flags: memory allocation control flags
362  *
363  * Return values:
364  *   %0: Handshake request enqueue; ->done will be called when complete
365  *   %-ESRCH: No user agent is available
366  *   %-ENOMEM: Memory allocation failed
367  */
368 int tls_server_hello_x509(const struct tls_handshake_args *args, gfp_t flags)
369 {
370         struct tls_handshake_req *treq;
371         struct handshake_req *req;
372 
373         req = handshake_req_alloc(&tls_handshake_proto, flags);
374         if (!req)
375                 return -ENOMEM;
376         treq = tls_handshake_req_init(req, args);
377         treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO;
378         treq->th_auth_mode = HANDSHAKE_AUTH_X509;
379         treq->th_certificate = args->ta_my_cert;
380         treq->th_privkey = args->ta_my_privkey;
381 
382         return handshake_req_submit(args->ta_sock, req, flags);
383 }
384 EXPORT_SYMBOL(tls_server_hello_x509);
385 
386 /**
387  * tls_server_hello_psk - request a server TLS handshake on a socket
388  * @args: socket and handshake parameters for this request
389  * @flags: memory allocation control flags
390  *
391  * Return values:
392  *   %0: Handshake request enqueue; ->done will be called when complete
393  *   %-ESRCH: No user agent is available
394  *   %-ENOMEM: Memory allocation failed
395  */
396 int tls_server_hello_psk(const struct tls_handshake_args *args, gfp_t flags)
397 {
398         struct tls_handshake_req *treq;
399         struct handshake_req *req;
400 
401         req = handshake_req_alloc(&tls_handshake_proto, flags);
402         if (!req)
403                 return -ENOMEM;
404         treq = tls_handshake_req_init(req, args);
405         treq->th_type = HANDSHAKE_MSG_TYPE_SERVERHELLO;
406         treq->th_auth_mode = HANDSHAKE_AUTH_PSK;
407         treq->th_num_peerids = 1;
408         treq->th_peerid[0] = args->ta_my_peerids[0];
409 
410         return handshake_req_submit(args->ta_sock, req, flags);
411 }
412 EXPORT_SYMBOL(tls_server_hello_psk);
413 
414 /**
415  * tls_handshake_cancel - cancel a pending handshake
416  * @sk: socket on which there is an ongoing handshake
417  *
418  * Request cancellation races with request completion. To determine
419  * who won, callers examine the return value from this function.
420  *
421  * Return values:
422  *   %true - Uncompleted handshake request was canceled
423  *   %false - Handshake request already completed or not found
424  */
425 bool tls_handshake_cancel(struct sock *sk)
426 {
427         return handshake_req_cancel(sk);
428 }
429 EXPORT_SYMBOL(tls_handshake_cancel);
430 
431 /**
432  * tls_handshake_close - send a Closure alert
433  * @sock: an open socket
434  *
435  */
436 void tls_handshake_close(struct socket *sock)
437 {
438         struct handshake_req *req;
439 
440         req = handshake_req_hash_lookup(sock->sk);
441         if (!req)
442                 return;
443         if (!test_and_clear_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags))
444                 return;
445         tls_alert_send(sock, TLS_ALERT_LEVEL_WARNING,
446                        TLS_ALERT_DESC_CLOSE_NOTIFY);
447 }
448 EXPORT_SYMBOL(tls_handshake_close);
449 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php