18c2ecf20Sopenharmony_ci/* Copyright (c) 2018, Mellanox Technologies All rights reserved. 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 48c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 58c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 68c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 78c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 108c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 118c2ecf20Sopenharmony_ci * conditions are met: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 148c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 158c2ecf20Sopenharmony_ci * disclaimer. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 188c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 198c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 208c2ecf20Sopenharmony_ci * provided with the distribution. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 238c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 248c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 258c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 268c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 278c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 288c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 298c2ecf20Sopenharmony_ci * SOFTWARE. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <net/tls.h> 338c2ecf20Sopenharmony_ci#include <crypto/aead.h> 348c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 358c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic void chain_to_walk(struct scatterlist *sg, struct scatter_walk *walk) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct scatterlist *src = walk->sg; 408c2ecf20Sopenharmony_ci int diff = walk->offset - src->offset; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci sg_set_page(sg, sg_page(src), 438c2ecf20Sopenharmony_ci src->length - diff, walk->offset); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci scatterwalk_crypto_chain(sg, sg_next(src), 2); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int tls_enc_record(struct aead_request *aead_req, 498c2ecf20Sopenharmony_ci struct crypto_aead *aead, char *aad, 508c2ecf20Sopenharmony_ci char *iv, __be64 rcd_sn, 518c2ecf20Sopenharmony_ci struct scatter_walk *in, 528c2ecf20Sopenharmony_ci struct scatter_walk *out, int *in_len) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci unsigned char buf[TLS_HEADER_SIZE + TLS_CIPHER_AES_GCM_128_IV_SIZE]; 558c2ecf20Sopenharmony_ci struct scatterlist sg_in[3]; 568c2ecf20Sopenharmony_ci struct scatterlist sg_out[3]; 578c2ecf20Sopenharmony_ci u16 len; 588c2ecf20Sopenharmony_ci int rc; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci len = min_t(int, *in_len, ARRAY_SIZE(buf)); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci scatterwalk_copychunks(buf, in, len, 0); 638c2ecf20Sopenharmony_ci scatterwalk_copychunks(buf, out, len, 1); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci *in_len -= len; 668c2ecf20Sopenharmony_ci if (!*in_len) 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci scatterwalk_pagedone(in, 0, 1); 708c2ecf20Sopenharmony_ci scatterwalk_pagedone(out, 1, 1); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci len = buf[4] | (buf[3] << 8); 738c2ecf20Sopenharmony_ci len -= TLS_CIPHER_AES_GCM_128_IV_SIZE; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci tls_make_aad(aad, len - TLS_CIPHER_AES_GCM_128_TAG_SIZE, 768c2ecf20Sopenharmony_ci (char *)&rcd_sn, sizeof(rcd_sn), buf[0], 778c2ecf20Sopenharmony_ci TLS_1_2_VERSION); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci memcpy(iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, buf + TLS_HEADER_SIZE, 808c2ecf20Sopenharmony_ci TLS_CIPHER_AES_GCM_128_IV_SIZE); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci sg_init_table(sg_in, ARRAY_SIZE(sg_in)); 838c2ecf20Sopenharmony_ci sg_init_table(sg_out, ARRAY_SIZE(sg_out)); 848c2ecf20Sopenharmony_ci sg_set_buf(sg_in, aad, TLS_AAD_SPACE_SIZE); 858c2ecf20Sopenharmony_ci sg_set_buf(sg_out, aad, TLS_AAD_SPACE_SIZE); 868c2ecf20Sopenharmony_ci chain_to_walk(sg_in + 1, in); 878c2ecf20Sopenharmony_ci chain_to_walk(sg_out + 1, out); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci *in_len -= len; 908c2ecf20Sopenharmony_ci if (*in_len < 0) { 918c2ecf20Sopenharmony_ci *in_len += TLS_CIPHER_AES_GCM_128_TAG_SIZE; 928c2ecf20Sopenharmony_ci /* the input buffer doesn't contain the entire record. 938c2ecf20Sopenharmony_ci * trim len accordingly. The resulting authentication tag 948c2ecf20Sopenharmony_ci * will contain garbage, but we don't care, so we won't 958c2ecf20Sopenharmony_ci * include any of it in the output skb 968c2ecf20Sopenharmony_ci * Note that we assume the output buffer length 978c2ecf20Sopenharmony_ci * is larger then input buffer length + tag size 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci if (*in_len < 0) 1008c2ecf20Sopenharmony_ci len += *in_len; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci *in_len = 0; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (*in_len) { 1068c2ecf20Sopenharmony_ci scatterwalk_copychunks(NULL, in, len, 2); 1078c2ecf20Sopenharmony_ci scatterwalk_pagedone(in, 0, 1); 1088c2ecf20Sopenharmony_ci scatterwalk_copychunks(NULL, out, len, 2); 1098c2ecf20Sopenharmony_ci scatterwalk_pagedone(out, 1, 1); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci len -= TLS_CIPHER_AES_GCM_128_TAG_SIZE; 1138c2ecf20Sopenharmony_ci aead_request_set_crypt(aead_req, sg_in, sg_out, len, iv); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci rc = crypto_aead_encrypt(aead_req); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return rc; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic void tls_init_aead_request(struct aead_request *aead_req, 1218c2ecf20Sopenharmony_ci struct crypto_aead *aead) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci aead_request_set_tfm(aead_req, aead); 1248c2ecf20Sopenharmony_ci aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic struct aead_request *tls_alloc_aead_request(struct crypto_aead *aead, 1288c2ecf20Sopenharmony_ci gfp_t flags) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci unsigned int req_size = sizeof(struct aead_request) + 1318c2ecf20Sopenharmony_ci crypto_aead_reqsize(aead); 1328c2ecf20Sopenharmony_ci struct aead_request *aead_req; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci aead_req = kzalloc(req_size, flags); 1358c2ecf20Sopenharmony_ci if (aead_req) 1368c2ecf20Sopenharmony_ci tls_init_aead_request(aead_req, aead); 1378c2ecf20Sopenharmony_ci return aead_req; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic int tls_enc_records(struct aead_request *aead_req, 1418c2ecf20Sopenharmony_ci struct crypto_aead *aead, struct scatterlist *sg_in, 1428c2ecf20Sopenharmony_ci struct scatterlist *sg_out, char *aad, char *iv, 1438c2ecf20Sopenharmony_ci u64 rcd_sn, int len) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct scatter_walk out, in; 1468c2ecf20Sopenharmony_ci int rc; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci scatterwalk_start(&in, sg_in); 1498c2ecf20Sopenharmony_ci scatterwalk_start(&out, sg_out); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci do { 1528c2ecf20Sopenharmony_ci rc = tls_enc_record(aead_req, aead, aad, iv, 1538c2ecf20Sopenharmony_ci cpu_to_be64(rcd_sn), &in, &out, &len); 1548c2ecf20Sopenharmony_ci rcd_sn++; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci } while (rc == 0 && len); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci scatterwalk_done(&in, 0, 0); 1598c2ecf20Sopenharmony_ci scatterwalk_done(&out, 1, 0); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return rc; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* Can't use icsk->icsk_af_ops->send_check here because the ip addresses 1658c2ecf20Sopenharmony_ci * might have been changed by NAT. 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_cistatic void update_chksum(struct sk_buff *skb, int headln) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct tcphdr *th = tcp_hdr(skb); 1708c2ecf20Sopenharmony_ci int datalen = skb->len - headln; 1718c2ecf20Sopenharmony_ci const struct ipv6hdr *ipv6h; 1728c2ecf20Sopenharmony_ci const struct iphdr *iph; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* We only changed the payload so if we are using partial we don't 1758c2ecf20Sopenharmony_ci * need to update anything. 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ci if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) 1788c2ecf20Sopenharmony_ci return; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_PARTIAL; 1818c2ecf20Sopenharmony_ci skb->csum_start = skb_transport_header(skb) - skb->head; 1828c2ecf20Sopenharmony_ci skb->csum_offset = offsetof(struct tcphdr, check); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (skb->sk->sk_family == AF_INET6) { 1858c2ecf20Sopenharmony_ci ipv6h = ipv6_hdr(skb); 1868c2ecf20Sopenharmony_ci th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, 1878c2ecf20Sopenharmony_ci datalen, IPPROTO_TCP, 0); 1888c2ecf20Sopenharmony_ci } else { 1898c2ecf20Sopenharmony_ci iph = ip_hdr(skb); 1908c2ecf20Sopenharmony_ci th->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, 1918c2ecf20Sopenharmony_ci IPPROTO_TCP, 0); 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic void complete_skb(struct sk_buff *nskb, struct sk_buff *skb, int headln) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct sock *sk = skb->sk; 1988c2ecf20Sopenharmony_ci int delta; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci skb_copy_header(nskb, skb); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci skb_put(nskb, skb->len); 2038c2ecf20Sopenharmony_ci memcpy(nskb->data, skb->data, headln); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci nskb->destructor = skb->destructor; 2068c2ecf20Sopenharmony_ci nskb->sk = sk; 2078c2ecf20Sopenharmony_ci skb->destructor = NULL; 2088c2ecf20Sopenharmony_ci skb->sk = NULL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci update_chksum(nskb, headln); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* sock_efree means skb must gone through skb_orphan_partial() */ 2138c2ecf20Sopenharmony_ci if (nskb->destructor == sock_efree) 2148c2ecf20Sopenharmony_ci return; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci delta = nskb->truesize - skb->truesize; 2178c2ecf20Sopenharmony_ci if (likely(delta < 0)) 2188c2ecf20Sopenharmony_ci WARN_ON_ONCE(refcount_sub_and_test(-delta, &sk->sk_wmem_alloc)); 2198c2ecf20Sopenharmony_ci else if (delta) 2208c2ecf20Sopenharmony_ci refcount_add(delta, &sk->sk_wmem_alloc); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* This function may be called after the user socket is already 2248c2ecf20Sopenharmony_ci * closed so make sure we don't use anything freed during 2258c2ecf20Sopenharmony_ci * tls_sk_proto_close here 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic int fill_sg_in(struct scatterlist *sg_in, 2298c2ecf20Sopenharmony_ci struct sk_buff *skb, 2308c2ecf20Sopenharmony_ci struct tls_offload_context_tx *ctx, 2318c2ecf20Sopenharmony_ci u64 *rcd_sn, 2328c2ecf20Sopenharmony_ci s32 *sync_size, 2338c2ecf20Sopenharmony_ci int *resync_sgs) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb); 2368c2ecf20Sopenharmony_ci int payload_len = skb->len - tcp_payload_offset; 2378c2ecf20Sopenharmony_ci u32 tcp_seq = ntohl(tcp_hdr(skb)->seq); 2388c2ecf20Sopenharmony_ci struct tls_record_info *record; 2398c2ecf20Sopenharmony_ci unsigned long flags; 2408c2ecf20Sopenharmony_ci int remaining; 2418c2ecf20Sopenharmony_ci int i; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci spin_lock_irqsave(&ctx->lock, flags); 2448c2ecf20Sopenharmony_ci record = tls_get_record(ctx, tcp_seq, rcd_sn); 2458c2ecf20Sopenharmony_ci if (!record) { 2468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ctx->lock, flags); 2478c2ecf20Sopenharmony_ci return -EINVAL; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci *sync_size = tcp_seq - tls_record_start_seq(record); 2518c2ecf20Sopenharmony_ci if (*sync_size < 0) { 2528c2ecf20Sopenharmony_ci int is_start_marker = tls_record_is_start_marker(record); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ctx->lock, flags); 2558c2ecf20Sopenharmony_ci /* This should only occur if the relevant record was 2568c2ecf20Sopenharmony_ci * already acked. In that case it should be ok 2578c2ecf20Sopenharmony_ci * to drop the packet and avoid retransmission. 2588c2ecf20Sopenharmony_ci * 2598c2ecf20Sopenharmony_ci * There is a corner case where the packet contains 2608c2ecf20Sopenharmony_ci * both an acked and a non-acked record. 2618c2ecf20Sopenharmony_ci * We currently don't handle that case and rely 2628c2ecf20Sopenharmony_ci * on TCP to retranmit a packet that doesn't contain 2638c2ecf20Sopenharmony_ci * already acked payload. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_ci if (!is_start_marker) 2668c2ecf20Sopenharmony_ci *sync_size = 0; 2678c2ecf20Sopenharmony_ci return -EINVAL; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci remaining = *sync_size; 2718c2ecf20Sopenharmony_ci for (i = 0; remaining > 0; i++) { 2728c2ecf20Sopenharmony_ci skb_frag_t *frag = &record->frags[i]; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci __skb_frag_ref(frag); 2758c2ecf20Sopenharmony_ci sg_set_page(sg_in + i, skb_frag_page(frag), 2768c2ecf20Sopenharmony_ci skb_frag_size(frag), skb_frag_off(frag)); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci remaining -= skb_frag_size(frag); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (remaining < 0) 2818c2ecf20Sopenharmony_ci sg_in[i].length += remaining; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci *resync_sgs = i; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ctx->lock, flags); 2868c2ecf20Sopenharmony_ci if (skb_to_sgvec(skb, &sg_in[i], tcp_payload_offset, payload_len) < 0) 2878c2ecf20Sopenharmony_ci return -EINVAL; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void fill_sg_out(struct scatterlist sg_out[3], void *buf, 2938c2ecf20Sopenharmony_ci struct tls_context *tls_ctx, 2948c2ecf20Sopenharmony_ci struct sk_buff *nskb, 2958c2ecf20Sopenharmony_ci int tcp_payload_offset, 2968c2ecf20Sopenharmony_ci int payload_len, 2978c2ecf20Sopenharmony_ci int sync_size, 2988c2ecf20Sopenharmony_ci void *dummy_buf) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci sg_set_buf(&sg_out[0], dummy_buf, sync_size); 3018c2ecf20Sopenharmony_ci sg_set_buf(&sg_out[1], nskb->data + tcp_payload_offset, payload_len); 3028c2ecf20Sopenharmony_ci /* Add room for authentication tag produced by crypto */ 3038c2ecf20Sopenharmony_ci dummy_buf += sync_size; 3048c2ecf20Sopenharmony_ci sg_set_buf(&sg_out[2], dummy_buf, TLS_CIPHER_AES_GCM_128_TAG_SIZE); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic struct sk_buff *tls_enc_skb(struct tls_context *tls_ctx, 3088c2ecf20Sopenharmony_ci struct scatterlist sg_out[3], 3098c2ecf20Sopenharmony_ci struct scatterlist *sg_in, 3108c2ecf20Sopenharmony_ci struct sk_buff *skb, 3118c2ecf20Sopenharmony_ci s32 sync_size, u64 rcd_sn) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb); 3148c2ecf20Sopenharmony_ci struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx); 3158c2ecf20Sopenharmony_ci int payload_len = skb->len - tcp_payload_offset; 3168c2ecf20Sopenharmony_ci void *buf, *iv, *aad, *dummy_buf; 3178c2ecf20Sopenharmony_ci struct aead_request *aead_req; 3188c2ecf20Sopenharmony_ci struct sk_buff *nskb = NULL; 3198c2ecf20Sopenharmony_ci int buf_len; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci aead_req = tls_alloc_aead_request(ctx->aead_send, GFP_ATOMIC); 3228c2ecf20Sopenharmony_ci if (!aead_req) 3238c2ecf20Sopenharmony_ci return NULL; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci buf_len = TLS_CIPHER_AES_GCM_128_SALT_SIZE + 3268c2ecf20Sopenharmony_ci TLS_CIPHER_AES_GCM_128_IV_SIZE + 3278c2ecf20Sopenharmony_ci TLS_AAD_SPACE_SIZE + 3288c2ecf20Sopenharmony_ci sync_size + 3298c2ecf20Sopenharmony_ci TLS_CIPHER_AES_GCM_128_TAG_SIZE; 3308c2ecf20Sopenharmony_ci buf = kmalloc(buf_len, GFP_ATOMIC); 3318c2ecf20Sopenharmony_ci if (!buf) 3328c2ecf20Sopenharmony_ci goto free_req; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci iv = buf; 3358c2ecf20Sopenharmony_ci memcpy(iv, tls_ctx->crypto_send.aes_gcm_128.salt, 3368c2ecf20Sopenharmony_ci TLS_CIPHER_AES_GCM_128_SALT_SIZE); 3378c2ecf20Sopenharmony_ci aad = buf + TLS_CIPHER_AES_GCM_128_SALT_SIZE + 3388c2ecf20Sopenharmony_ci TLS_CIPHER_AES_GCM_128_IV_SIZE; 3398c2ecf20Sopenharmony_ci dummy_buf = aad + TLS_AAD_SPACE_SIZE; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci nskb = alloc_skb(skb_headroom(skb) + skb->len, GFP_ATOMIC); 3428c2ecf20Sopenharmony_ci if (!nskb) 3438c2ecf20Sopenharmony_ci goto free_buf; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci skb_reserve(nskb, skb_headroom(skb)); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci fill_sg_out(sg_out, buf, tls_ctx, nskb, tcp_payload_offset, 3488c2ecf20Sopenharmony_ci payload_len, sync_size, dummy_buf); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (tls_enc_records(aead_req, ctx->aead_send, sg_in, sg_out, aad, iv, 3518c2ecf20Sopenharmony_ci rcd_sn, sync_size + payload_len) < 0) 3528c2ecf20Sopenharmony_ci goto free_nskb; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci complete_skb(nskb, skb, tcp_payload_offset); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* validate_xmit_skb_list assumes that if the skb wasn't segmented 3578c2ecf20Sopenharmony_ci * nskb->prev will point to the skb itself 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ci nskb->prev = nskb; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cifree_buf: 3628c2ecf20Sopenharmony_ci kfree(buf); 3638c2ecf20Sopenharmony_cifree_req: 3648c2ecf20Sopenharmony_ci kfree(aead_req); 3658c2ecf20Sopenharmony_ci return nskb; 3668c2ecf20Sopenharmony_cifree_nskb: 3678c2ecf20Sopenharmony_ci kfree_skb(nskb); 3688c2ecf20Sopenharmony_ci nskb = NULL; 3698c2ecf20Sopenharmony_ci goto free_buf; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic struct sk_buff *tls_sw_fallback(struct sock *sk, struct sk_buff *skb) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb); 3758c2ecf20Sopenharmony_ci struct tls_context *tls_ctx = tls_get_ctx(sk); 3768c2ecf20Sopenharmony_ci struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx); 3778c2ecf20Sopenharmony_ci int payload_len = skb->len - tcp_payload_offset; 3788c2ecf20Sopenharmony_ci struct scatterlist *sg_in, sg_out[3]; 3798c2ecf20Sopenharmony_ci struct sk_buff *nskb = NULL; 3808c2ecf20Sopenharmony_ci int sg_in_max_elements; 3818c2ecf20Sopenharmony_ci int resync_sgs = 0; 3828c2ecf20Sopenharmony_ci s32 sync_size = 0; 3838c2ecf20Sopenharmony_ci u64 rcd_sn; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* worst case is: 3868c2ecf20Sopenharmony_ci * MAX_SKB_FRAGS in tls_record_info 3878c2ecf20Sopenharmony_ci * MAX_SKB_FRAGS + 1 in SKB head and frags. 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ci sg_in_max_elements = 2 * MAX_SKB_FRAGS + 1; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (!payload_len) 3928c2ecf20Sopenharmony_ci return skb; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci sg_in = kmalloc_array(sg_in_max_elements, sizeof(*sg_in), GFP_ATOMIC); 3958c2ecf20Sopenharmony_ci if (!sg_in) 3968c2ecf20Sopenharmony_ci goto free_orig; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci sg_init_table(sg_in, sg_in_max_elements); 3998c2ecf20Sopenharmony_ci sg_init_table(sg_out, ARRAY_SIZE(sg_out)); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (fill_sg_in(sg_in, skb, ctx, &rcd_sn, &sync_size, &resync_sgs)) { 4028c2ecf20Sopenharmony_ci /* bypass packets before kernel TLS socket option was set */ 4038c2ecf20Sopenharmony_ci if (sync_size < 0 && payload_len <= -sync_size) 4048c2ecf20Sopenharmony_ci nskb = skb_get(skb); 4058c2ecf20Sopenharmony_ci goto put_sg; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci nskb = tls_enc_skb(tls_ctx, sg_out, sg_in, skb, sync_size, rcd_sn); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ciput_sg: 4118c2ecf20Sopenharmony_ci while (resync_sgs) 4128c2ecf20Sopenharmony_ci put_page(sg_page(&sg_in[--resync_sgs])); 4138c2ecf20Sopenharmony_ci kfree(sg_in); 4148c2ecf20Sopenharmony_cifree_orig: 4158c2ecf20Sopenharmony_ci if (nskb) 4168c2ecf20Sopenharmony_ci consume_skb(skb); 4178c2ecf20Sopenharmony_ci else 4188c2ecf20Sopenharmony_ci kfree_skb(skb); 4198c2ecf20Sopenharmony_ci return nskb; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistruct sk_buff *tls_validate_xmit_skb(struct sock *sk, 4238c2ecf20Sopenharmony_ci struct net_device *dev, 4248c2ecf20Sopenharmony_ci struct sk_buff *skb) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci if (dev == tls_get_ctx(sk)->netdev) 4278c2ecf20Sopenharmony_ci return skb; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return tls_sw_fallback(sk, skb); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tls_validate_xmit_skb); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistruct sk_buff *tls_validate_xmit_skb_sw(struct sock *sk, 4348c2ecf20Sopenharmony_ci struct net_device *dev, 4358c2ecf20Sopenharmony_ci struct sk_buff *skb) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci return tls_sw_fallback(sk, skb); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistruct sk_buff *tls_encrypt_skb(struct sk_buff *skb) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci return tls_sw_fallback(skb->sk, skb); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tls_encrypt_skb); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ciint tls_sw_fallback_init(struct sock *sk, 4478c2ecf20Sopenharmony_ci struct tls_offload_context_tx *offload_ctx, 4488c2ecf20Sopenharmony_ci struct tls_crypto_info *crypto_info) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci const u8 *key; 4518c2ecf20Sopenharmony_ci int rc; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci offload_ctx->aead_send = 4548c2ecf20Sopenharmony_ci crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC); 4558c2ecf20Sopenharmony_ci if (IS_ERR(offload_ctx->aead_send)) { 4568c2ecf20Sopenharmony_ci rc = PTR_ERR(offload_ctx->aead_send); 4578c2ecf20Sopenharmony_ci pr_err_ratelimited("crypto_alloc_aead failed rc=%d\n", rc); 4588c2ecf20Sopenharmony_ci offload_ctx->aead_send = NULL; 4598c2ecf20Sopenharmony_ci goto err_out; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci key = ((struct tls12_crypto_info_aes_gcm_128 *)crypto_info)->key; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci rc = crypto_aead_setkey(offload_ctx->aead_send, key, 4658c2ecf20Sopenharmony_ci TLS_CIPHER_AES_GCM_128_KEY_SIZE); 4668c2ecf20Sopenharmony_ci if (rc) 4678c2ecf20Sopenharmony_ci goto free_aead; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci rc = crypto_aead_setauthsize(offload_ctx->aead_send, 4708c2ecf20Sopenharmony_ci TLS_CIPHER_AES_GCM_128_TAG_SIZE); 4718c2ecf20Sopenharmony_ci if (rc) 4728c2ecf20Sopenharmony_ci goto free_aead; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci return 0; 4758c2ecf20Sopenharmony_cifree_aead: 4768c2ecf20Sopenharmony_ci crypto_free_aead(offload_ctx->aead_send); 4778c2ecf20Sopenharmony_cierr_out: 4788c2ecf20Sopenharmony_ci return rc; 4798c2ecf20Sopenharmony_ci} 480