diff options
Diffstat (limited to 'net/tls/tls_main.c')
-rw-r--r-- | net/tls/tls_main.c | 487 |
1 files changed, 487 insertions, 0 deletions
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c new file mode 100644 index 000000000000..2ebc328bda96 --- /dev/null +++ b/net/tls/tls_main.c | |||
@@ -0,0 +1,487 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved. | ||
3 | * Copyright (c) 2016-2017, Dave Watson <davejwatson@fb.com>. All rights reserved. | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the | ||
9 | * OpenIB.org BSD license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or | ||
12 | * without modification, are permitted provided that the following | ||
13 | * conditions are met: | ||
14 | * | ||
15 | * - Redistributions of source code must retain the above | ||
16 | * copyright notice, this list of conditions and the following | ||
17 | * disclaimer. | ||
18 | * | ||
19 | * - Redistributions in binary form must reproduce the above | ||
20 | * copyright notice, this list of conditions and the following | ||
21 | * disclaimer in the documentation and/or other materials | ||
22 | * provided with the distribution. | ||
23 | * | ||
24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
25 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
26 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
27 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
28 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
29 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
30 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
31 | * SOFTWARE. | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | |||
36 | #include <net/tcp.h> | ||
37 | #include <net/inet_common.h> | ||
38 | #include <linux/highmem.h> | ||
39 | #include <linux/netdevice.h> | ||
40 | #include <linux/sched/signal.h> | ||
41 | |||
42 | #include <net/tls.h> | ||
43 | |||
44 | MODULE_AUTHOR("Mellanox Technologies"); | ||
45 | MODULE_DESCRIPTION("Transport Layer Security Support"); | ||
46 | MODULE_LICENSE("Dual BSD/GPL"); | ||
47 | |||
48 | static struct proto tls_base_prot; | ||
49 | static struct proto tls_sw_prot; | ||
50 | |||
51 | int wait_on_pending_writer(struct sock *sk, long *timeo) | ||
52 | { | ||
53 | int rc = 0; | ||
54 | DEFINE_WAIT_FUNC(wait, woken_wake_function); | ||
55 | |||
56 | add_wait_queue(sk_sleep(sk), &wait); | ||
57 | while (1) { | ||
58 | if (!*timeo) { | ||
59 | rc = -EAGAIN; | ||
60 | break; | ||
61 | } | ||
62 | |||
63 | if (signal_pending(current)) { | ||
64 | rc = sock_intr_errno(*timeo); | ||
65 | break; | ||
66 | } | ||
67 | |||
68 | if (sk_wait_event(sk, timeo, !sk->sk_write_pending, &wait)) | ||
69 | break; | ||
70 | } | ||
71 | remove_wait_queue(sk_sleep(sk), &wait); | ||
72 | return rc; | ||
73 | } | ||
74 | |||
75 | int tls_push_sg(struct sock *sk, | ||
76 | struct tls_context *ctx, | ||
77 | struct scatterlist *sg, | ||
78 | u16 first_offset, | ||
79 | int flags) | ||
80 | { | ||
81 | int sendpage_flags = flags | MSG_SENDPAGE_NOTLAST; | ||
82 | int ret = 0; | ||
83 | struct page *p; | ||
84 | size_t size; | ||
85 | int offset = first_offset; | ||
86 | |||
87 | size = sg->length - offset; | ||
88 | offset += sg->offset; | ||
89 | |||
90 | while (1) { | ||
91 | if (sg_is_last(sg)) | ||
92 | sendpage_flags = flags; | ||
93 | |||
94 | /* is sending application-limited? */ | ||
95 | tcp_rate_check_app_limited(sk); | ||
96 | p = sg_page(sg); | ||
97 | retry: | ||
98 | ret = do_tcp_sendpages(sk, p, offset, size, sendpage_flags); | ||
99 | |||
100 | if (ret != size) { | ||
101 | if (ret > 0) { | ||
102 | offset += ret; | ||
103 | size -= ret; | ||
104 | goto retry; | ||
105 | } | ||
106 | |||
107 | offset -= sg->offset; | ||
108 | ctx->partially_sent_offset = offset; | ||
109 | ctx->partially_sent_record = (void *)sg; | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | put_page(p); | ||
114 | sk_mem_uncharge(sk, sg->length); | ||
115 | sg = sg_next(sg); | ||
116 | if (!sg) | ||
117 | break; | ||
118 | |||
119 | offset = sg->offset; | ||
120 | size = sg->length; | ||
121 | } | ||
122 | |||
123 | clear_bit(TLS_PENDING_CLOSED_RECORD, &ctx->flags); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int tls_handle_open_record(struct sock *sk, int flags) | ||
129 | { | ||
130 | struct tls_context *ctx = tls_get_ctx(sk); | ||
131 | |||
132 | if (tls_is_pending_open_record(ctx)) | ||
133 | return ctx->push_pending_record(sk, flags); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | int tls_proccess_cmsg(struct sock *sk, struct msghdr *msg, | ||
139 | unsigned char *record_type) | ||
140 | { | ||
141 | struct cmsghdr *cmsg; | ||
142 | int rc = -EINVAL; | ||
143 | |||
144 | for_each_cmsghdr(cmsg, msg) { | ||
145 | if (!CMSG_OK(msg, cmsg)) | ||
146 | return -EINVAL; | ||
147 | if (cmsg->cmsg_level != SOL_TLS) | ||
148 | continue; | ||
149 | |||
150 | switch (cmsg->cmsg_type) { | ||
151 | case TLS_SET_RECORD_TYPE: | ||
152 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(*record_type))) | ||
153 | return -EINVAL; | ||
154 | |||
155 | if (msg->msg_flags & MSG_MORE) | ||
156 | return -EINVAL; | ||
157 | |||
158 | rc = tls_handle_open_record(sk, msg->msg_flags); | ||
159 | if (rc) | ||
160 | return rc; | ||
161 | |||
162 | *record_type = *(unsigned char *)CMSG_DATA(cmsg); | ||
163 | rc = 0; | ||
164 | break; | ||
165 | default: | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | return rc; | ||
171 | } | ||
172 | |||
173 | int tls_push_pending_closed_record(struct sock *sk, struct tls_context *ctx, | ||
174 | int flags, long *timeo) | ||
175 | { | ||
176 | struct scatterlist *sg; | ||
177 | u16 offset; | ||
178 | |||
179 | if (!tls_is_partially_sent_record(ctx)) | ||
180 | return ctx->push_pending_record(sk, flags); | ||
181 | |||
182 | sg = ctx->partially_sent_record; | ||
183 | offset = ctx->partially_sent_offset; | ||
184 | |||
185 | ctx->partially_sent_record = NULL; | ||
186 | return tls_push_sg(sk, ctx, sg, offset, flags); | ||
187 | } | ||
188 | |||
189 | static void tls_write_space(struct sock *sk) | ||
190 | { | ||
191 | struct tls_context *ctx = tls_get_ctx(sk); | ||
192 | |||
193 | if (!sk->sk_write_pending && tls_is_pending_closed_record(ctx)) { | ||
194 | gfp_t sk_allocation = sk->sk_allocation; | ||
195 | int rc; | ||
196 | long timeo = 0; | ||
197 | |||
198 | sk->sk_allocation = GFP_ATOMIC; | ||
199 | rc = tls_push_pending_closed_record(sk, ctx, | ||
200 | MSG_DONTWAIT | | ||
201 | MSG_NOSIGNAL, | ||
202 | &timeo); | ||
203 | sk->sk_allocation = sk_allocation; | ||
204 | |||
205 | if (rc < 0) | ||
206 | return; | ||
207 | } | ||
208 | |||
209 | ctx->sk_write_space(sk); | ||
210 | } | ||
211 | |||
212 | static void tls_sk_proto_close(struct sock *sk, long timeout) | ||
213 | { | ||
214 | struct tls_context *ctx = tls_get_ctx(sk); | ||
215 | long timeo = sock_sndtimeo(sk, 0); | ||
216 | void (*sk_proto_close)(struct sock *sk, long timeout); | ||
217 | |||
218 | lock_sock(sk); | ||
219 | |||
220 | if (!tls_complete_pending_work(sk, ctx, 0, &timeo)) | ||
221 | tls_handle_open_record(sk, 0); | ||
222 | |||
223 | if (ctx->partially_sent_record) { | ||
224 | struct scatterlist *sg = ctx->partially_sent_record; | ||
225 | |||
226 | while (1) { | ||
227 | put_page(sg_page(sg)); | ||
228 | sk_mem_uncharge(sk, sg->length); | ||
229 | |||
230 | if (sg_is_last(sg)) | ||
231 | break; | ||
232 | sg++; | ||
233 | } | ||
234 | } | ||
235 | ctx->free_resources(sk); | ||
236 | kfree(ctx->rec_seq); | ||
237 | kfree(ctx->iv); | ||
238 | |||
239 | sk_proto_close = ctx->sk_proto_close; | ||
240 | kfree(ctx); | ||
241 | |||
242 | release_sock(sk); | ||
243 | sk_proto_close(sk, timeout); | ||
244 | } | ||
245 | |||
246 | static int do_tls_getsockopt_tx(struct sock *sk, char __user *optval, | ||
247 | int __user *optlen) | ||
248 | { | ||
249 | int rc = 0; | ||
250 | struct tls_context *ctx = tls_get_ctx(sk); | ||
251 | struct tls_crypto_info *crypto_info; | ||
252 | int len; | ||
253 | |||
254 | if (get_user(len, optlen)) | ||
255 | return -EFAULT; | ||
256 | |||
257 | if (!optval || (len < sizeof(*crypto_info))) { | ||
258 | rc = -EINVAL; | ||
259 | goto out; | ||
260 | } | ||
261 | |||
262 | if (!ctx) { | ||
263 | rc = -EBUSY; | ||
264 | goto out; | ||
265 | } | ||
266 | |||
267 | /* get user crypto info */ | ||
268 | crypto_info = &ctx->crypto_send; | ||
269 | |||
270 | if (!TLS_CRYPTO_INFO_READY(crypto_info)) { | ||
271 | rc = -EBUSY; | ||
272 | goto out; | ||
273 | } | ||
274 | |||
275 | if (len == sizeof(crypto_info)) { | ||
276 | rc = copy_to_user(optval, crypto_info, sizeof(*crypto_info)); | ||
277 | goto out; | ||
278 | } | ||
279 | |||
280 | switch (crypto_info->cipher_type) { | ||
281 | case TLS_CIPHER_AES_GCM_128: { | ||
282 | struct tls12_crypto_info_aes_gcm_128 * | ||
283 | crypto_info_aes_gcm_128 = | ||
284 | container_of(crypto_info, | ||
285 | struct tls12_crypto_info_aes_gcm_128, | ||
286 | info); | ||
287 | |||
288 | if (len != sizeof(*crypto_info_aes_gcm_128)) { | ||
289 | rc = -EINVAL; | ||
290 | goto out; | ||
291 | } | ||
292 | lock_sock(sk); | ||
293 | memcpy(crypto_info_aes_gcm_128->iv, ctx->iv, | ||
294 | TLS_CIPHER_AES_GCM_128_IV_SIZE); | ||
295 | release_sock(sk); | ||
296 | rc = copy_to_user(optval, | ||
297 | crypto_info_aes_gcm_128, | ||
298 | sizeof(*crypto_info_aes_gcm_128)); | ||
299 | break; | ||
300 | } | ||
301 | default: | ||
302 | rc = -EINVAL; | ||
303 | } | ||
304 | |||
305 | out: | ||
306 | return rc; | ||
307 | } | ||
308 | |||
309 | static int do_tls_getsockopt(struct sock *sk, int optname, | ||
310 | char __user *optval, int __user *optlen) | ||
311 | { | ||
312 | int rc = 0; | ||
313 | |||
314 | switch (optname) { | ||
315 | case TLS_TX: | ||
316 | rc = do_tls_getsockopt_tx(sk, optval, optlen); | ||
317 | break; | ||
318 | default: | ||
319 | rc = -ENOPROTOOPT; | ||
320 | break; | ||
321 | } | ||
322 | return rc; | ||
323 | } | ||
324 | |||
325 | static int tls_getsockopt(struct sock *sk, int level, int optname, | ||
326 | char __user *optval, int __user *optlen) | ||
327 | { | ||
328 | struct tls_context *ctx = tls_get_ctx(sk); | ||
329 | |||
330 | if (level != SOL_TLS) | ||
331 | return ctx->getsockopt(sk, level, optname, optval, optlen); | ||
332 | |||
333 | return do_tls_getsockopt(sk, optname, optval, optlen); | ||
334 | } | ||
335 | |||
336 | static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval, | ||
337 | unsigned int optlen) | ||
338 | { | ||
339 | struct tls_crypto_info *crypto_info, tmp_crypto_info; | ||
340 | struct tls_context *ctx = tls_get_ctx(sk); | ||
341 | struct proto *prot = NULL; | ||
342 | int rc = 0; | ||
343 | |||
344 | if (!optval || (optlen < sizeof(*crypto_info))) { | ||
345 | rc = -EINVAL; | ||
346 | goto out; | ||
347 | } | ||
348 | |||
349 | rc = copy_from_user(&tmp_crypto_info, optval, sizeof(*crypto_info)); | ||
350 | if (rc) { | ||
351 | rc = -EFAULT; | ||
352 | goto out; | ||
353 | } | ||
354 | |||
355 | /* check version */ | ||
356 | if (tmp_crypto_info.version != TLS_1_2_VERSION) { | ||
357 | rc = -ENOTSUPP; | ||
358 | goto out; | ||
359 | } | ||
360 | |||
361 | /* get user crypto info */ | ||
362 | crypto_info = &ctx->crypto_send; | ||
363 | |||
364 | /* Currently we don't support set crypto info more than one time */ | ||
365 | if (TLS_CRYPTO_INFO_READY(crypto_info)) | ||
366 | goto out; | ||
367 | |||
368 | switch (tmp_crypto_info.cipher_type) { | ||
369 | case TLS_CIPHER_AES_GCM_128: { | ||
370 | if (optlen != sizeof(struct tls12_crypto_info_aes_gcm_128)) { | ||
371 | rc = -EINVAL; | ||
372 | goto out; | ||
373 | } | ||
374 | rc = copy_from_user( | ||
375 | crypto_info, | ||
376 | optval, | ||
377 | sizeof(struct tls12_crypto_info_aes_gcm_128)); | ||
378 | |||
379 | if (rc) { | ||
380 | rc = -EFAULT; | ||
381 | goto err_crypto_info; | ||
382 | } | ||
383 | break; | ||
384 | } | ||
385 | default: | ||
386 | rc = -EINVAL; | ||
387 | goto out; | ||
388 | } | ||
389 | |||
390 | ctx->sk_write_space = sk->sk_write_space; | ||
391 | sk->sk_write_space = tls_write_space; | ||
392 | |||
393 | ctx->sk_proto_close = sk->sk_prot->close; | ||
394 | |||
395 | /* currently SW is default, we will have ethtool in future */ | ||
396 | rc = tls_set_sw_offload(sk, ctx); | ||
397 | prot = &tls_sw_prot; | ||
398 | if (rc) | ||
399 | goto err_crypto_info; | ||
400 | |||
401 | sk->sk_prot = prot; | ||
402 | goto out; | ||
403 | |||
404 | err_crypto_info: | ||
405 | memset(crypto_info, 0, sizeof(*crypto_info)); | ||
406 | out: | ||
407 | return rc; | ||
408 | } | ||
409 | |||
410 | static int do_tls_setsockopt(struct sock *sk, int optname, | ||
411 | char __user *optval, unsigned int optlen) | ||
412 | { | ||
413 | int rc = 0; | ||
414 | |||
415 | switch (optname) { | ||
416 | case TLS_TX: | ||
417 | lock_sock(sk); | ||
418 | rc = do_tls_setsockopt_tx(sk, optval, optlen); | ||
419 | release_sock(sk); | ||
420 | break; | ||
421 | default: | ||
422 | rc = -ENOPROTOOPT; | ||
423 | break; | ||
424 | } | ||
425 | return rc; | ||
426 | } | ||
427 | |||
428 | static int tls_setsockopt(struct sock *sk, int level, int optname, | ||
429 | char __user *optval, unsigned int optlen) | ||
430 | { | ||
431 | struct tls_context *ctx = tls_get_ctx(sk); | ||
432 | |||
433 | if (level != SOL_TLS) | ||
434 | return ctx->setsockopt(sk, level, optname, optval, optlen); | ||
435 | |||
436 | return do_tls_setsockopt(sk, optname, optval, optlen); | ||
437 | } | ||
438 | |||
439 | static int tls_init(struct sock *sk) | ||
440 | { | ||
441 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
442 | struct tls_context *ctx; | ||
443 | int rc = 0; | ||
444 | |||
445 | /* allocate tls context */ | ||
446 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | ||
447 | if (!ctx) { | ||
448 | rc = -ENOMEM; | ||
449 | goto out; | ||
450 | } | ||
451 | icsk->icsk_ulp_data = ctx; | ||
452 | ctx->setsockopt = sk->sk_prot->setsockopt; | ||
453 | ctx->getsockopt = sk->sk_prot->getsockopt; | ||
454 | sk->sk_prot = &tls_base_prot; | ||
455 | out: | ||
456 | return rc; | ||
457 | } | ||
458 | |||
459 | static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = { | ||
460 | .name = "tls", | ||
461 | .owner = THIS_MODULE, | ||
462 | .init = tls_init, | ||
463 | }; | ||
464 | |||
465 | static int __init tls_register(void) | ||
466 | { | ||
467 | tls_base_prot = tcp_prot; | ||
468 | tls_base_prot.setsockopt = tls_setsockopt; | ||
469 | tls_base_prot.getsockopt = tls_getsockopt; | ||
470 | |||
471 | tls_sw_prot = tls_base_prot; | ||
472 | tls_sw_prot.sendmsg = tls_sw_sendmsg; | ||
473 | tls_sw_prot.sendpage = tls_sw_sendpage; | ||
474 | tls_sw_prot.close = tls_sk_proto_close; | ||
475 | |||
476 | tcp_register_ulp(&tcp_tls_ulp_ops); | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static void __exit tls_unregister(void) | ||
482 | { | ||
483 | tcp_unregister_ulp(&tcp_tls_ulp_ops); | ||
484 | } | ||
485 | |||
486 | module_init(tls_register); | ||
487 | module_exit(tls_unregister); | ||