1afd46503SJoe Perches #define pr_fmt(fmt) "IPsec: " fmt 2afd46503SJoe Perches 338320c70SHerbert Xu #include <crypto/aead.h> 438320c70SHerbert Xu #include <crypto/authenc.h> 56b7326c8SHerbert Xu #include <linux/err.h> 61da177e4SLinus Torvalds #include <linux/module.h> 71da177e4SLinus Torvalds #include <net/ip.h> 81da177e4SLinus Torvalds #include <net/xfrm.h> 91da177e4SLinus Torvalds #include <net/esp.h> 1072998d8cSAdrian Bunk #include <linux/scatterlist.h> 11a02a6422SHerbert Xu #include <linux/kernel.h> 121da177e4SLinus Torvalds #include <linux/pfkeyv2.h> 1338320c70SHerbert Xu #include <linux/rtnetlink.h> 1438320c70SHerbert Xu #include <linux/slab.h> 15b7c6538cSHerbert Xu #include <linux/spinlock.h> 162017a72cSThomas Graf #include <linux/in6.h> 171da177e4SLinus Torvalds #include <net/icmp.h> 1814c85021SArnaldo Carvalho de Melo #include <net/protocol.h> 191da177e4SLinus Torvalds #include <net/udp.h> 201da177e4SLinus Torvalds 2138320c70SHerbert Xu struct esp_skb_cb { 2238320c70SHerbert Xu struct xfrm_skb_cb xfrm; 2338320c70SHerbert Xu void *tmp; 2438320c70SHerbert Xu }; 2538320c70SHerbert Xu 2638320c70SHerbert Xu #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0])) 2738320c70SHerbert Xu 28d979e20fSMartin Willi static u32 esp4_get_mtu(struct xfrm_state *x, int mtu); 29d979e20fSMartin Willi 3038320c70SHerbert Xu /* 3138320c70SHerbert Xu * Allocate an AEAD request structure with extra space for SG and IV. 3238320c70SHerbert Xu * 3338320c70SHerbert Xu * For alignment considerations the IV is placed at the front, followed 3438320c70SHerbert Xu * by the request and finally the SG list. 3538320c70SHerbert Xu * 3638320c70SHerbert Xu * TODO: Use spare space in skb for this where possible. 3738320c70SHerbert Xu */ 380dc49e9bSSteffen Klassert static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int seqhilen) 3938320c70SHerbert Xu { 4038320c70SHerbert Xu unsigned int len; 4138320c70SHerbert Xu 420dc49e9bSSteffen Klassert len = seqhilen; 430dc49e9bSSteffen Klassert 440dc49e9bSSteffen Klassert len += crypto_aead_ivsize(aead); 450dc49e9bSSteffen Klassert 4638320c70SHerbert Xu if (len) { 4738320c70SHerbert Xu len += crypto_aead_alignmask(aead) & 4838320c70SHerbert Xu ~(crypto_tfm_ctx_alignment() - 1); 4938320c70SHerbert Xu len = ALIGN(len, crypto_tfm_ctx_alignment()); 5038320c70SHerbert Xu } 5138320c70SHerbert Xu 5238320c70SHerbert Xu len += sizeof(struct aead_givcrypt_request) + crypto_aead_reqsize(aead); 5338320c70SHerbert Xu len = ALIGN(len, __alignof__(struct scatterlist)); 5438320c70SHerbert Xu 5538320c70SHerbert Xu len += sizeof(struct scatterlist) * nfrags; 5638320c70SHerbert Xu 5738320c70SHerbert Xu return kmalloc(len, GFP_ATOMIC); 5838320c70SHerbert Xu } 5938320c70SHerbert Xu 600dc49e9bSSteffen Klassert static inline __be32 *esp_tmp_seqhi(void *tmp) 610dc49e9bSSteffen Klassert { 620dc49e9bSSteffen Klassert return PTR_ALIGN((__be32 *)tmp, __alignof__(__be32)); 630dc49e9bSSteffen Klassert } 640dc49e9bSSteffen Klassert static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp, int seqhilen) 6538320c70SHerbert Xu { 6638320c70SHerbert Xu return crypto_aead_ivsize(aead) ? 670dc49e9bSSteffen Klassert PTR_ALIGN((u8 *)tmp + seqhilen, 680dc49e9bSSteffen Klassert crypto_aead_alignmask(aead) + 1) : tmp + seqhilen; 6938320c70SHerbert Xu } 7038320c70SHerbert Xu 7138320c70SHerbert Xu static inline struct aead_givcrypt_request *esp_tmp_givreq( 7238320c70SHerbert Xu struct crypto_aead *aead, u8 *iv) 7338320c70SHerbert Xu { 7438320c70SHerbert Xu struct aead_givcrypt_request *req; 7538320c70SHerbert Xu 7638320c70SHerbert Xu req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead), 7738320c70SHerbert Xu crypto_tfm_ctx_alignment()); 7838320c70SHerbert Xu aead_givcrypt_set_tfm(req, aead); 7938320c70SHerbert Xu return req; 8038320c70SHerbert Xu } 8138320c70SHerbert Xu 8238320c70SHerbert Xu static inline struct aead_request *esp_tmp_req(struct crypto_aead *aead, u8 *iv) 8338320c70SHerbert Xu { 8438320c70SHerbert Xu struct aead_request *req; 8538320c70SHerbert Xu 8638320c70SHerbert Xu req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead), 8738320c70SHerbert Xu crypto_tfm_ctx_alignment()); 8838320c70SHerbert Xu aead_request_set_tfm(req, aead); 8938320c70SHerbert Xu return req; 9038320c70SHerbert Xu } 9138320c70SHerbert Xu 9238320c70SHerbert Xu static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead, 9338320c70SHerbert Xu struct aead_request *req) 9438320c70SHerbert Xu { 9538320c70SHerbert Xu return (void *)ALIGN((unsigned long)(req + 1) + 9638320c70SHerbert Xu crypto_aead_reqsize(aead), 9738320c70SHerbert Xu __alignof__(struct scatterlist)); 9838320c70SHerbert Xu } 9938320c70SHerbert Xu 10038320c70SHerbert Xu static inline struct scatterlist *esp_givreq_sg( 10138320c70SHerbert Xu struct crypto_aead *aead, struct aead_givcrypt_request *req) 10238320c70SHerbert Xu { 10338320c70SHerbert Xu return (void *)ALIGN((unsigned long)(req + 1) + 10438320c70SHerbert Xu crypto_aead_reqsize(aead), 10538320c70SHerbert Xu __alignof__(struct scatterlist)); 10638320c70SHerbert Xu } 10738320c70SHerbert Xu 10838320c70SHerbert Xu static void esp_output_done(struct crypto_async_request *base, int err) 10938320c70SHerbert Xu { 11038320c70SHerbert Xu struct sk_buff *skb = base->data; 11138320c70SHerbert Xu 11238320c70SHerbert Xu kfree(ESP_SKB_CB(skb)->tmp); 11338320c70SHerbert Xu xfrm_output_resume(skb, err); 11438320c70SHerbert Xu } 11538320c70SHerbert Xu 1161da177e4SLinus Torvalds static int esp_output(struct xfrm_state *x, struct sk_buff *skb) 1171da177e4SLinus Torvalds { 1181da177e4SLinus Torvalds int err; 1191da177e4SLinus Torvalds struct ip_esp_hdr *esph; 12038320c70SHerbert Xu struct crypto_aead *aead; 12138320c70SHerbert Xu struct aead_givcrypt_request *req; 12238320c70SHerbert Xu struct scatterlist *sg; 12338320c70SHerbert Xu struct scatterlist *asg; 1241da177e4SLinus Torvalds struct esp_data *esp; 1251da177e4SLinus Torvalds struct sk_buff *trailer; 12638320c70SHerbert Xu void *tmp; 12738320c70SHerbert Xu u8 *iv; 12827a884dcSArnaldo Carvalho de Melo u8 *tail; 1291da177e4SLinus Torvalds int blksize; 1301da177e4SLinus Torvalds int clen; 1311da177e4SLinus Torvalds int alen; 132d979e20fSMartin Willi int plen; 133d979e20fSMartin Willi int tfclen; 1341da177e4SLinus Torvalds int nfrags; 1350dc49e9bSSteffen Klassert int assoclen; 1360dc49e9bSSteffen Klassert int sglists; 1370dc49e9bSSteffen Klassert int seqhilen; 1380dc49e9bSSteffen Klassert __be32 *seqhi; 1391da177e4SLinus Torvalds 1407b277b1aSHerbert Xu /* skb is pure payload to encrypt */ 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds esp = x->data; 14338320c70SHerbert Xu aead = esp->aead; 14438320c70SHerbert Xu alen = crypto_aead_authsize(aead); 1451da177e4SLinus Torvalds 146d979e20fSMartin Willi tfclen = 0; 147d979e20fSMartin Willi if (x->tfcpad) { 148d979e20fSMartin Willi struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); 149d979e20fSMartin Willi u32 padto; 150d979e20fSMartin Willi 151d979e20fSMartin Willi padto = min(x->tfcpad, esp4_get_mtu(x, dst->child_mtu_cached)); 152d979e20fSMartin Willi if (skb->len < padto) 153d979e20fSMartin Willi tfclen = padto - skb->len; 154d979e20fSMartin Willi } 15538320c70SHerbert Xu blksize = ALIGN(crypto_aead_blocksize(aead), 4); 156d979e20fSMartin Willi clen = ALIGN(skb->len + 2 + tfclen, blksize); 15738320c70SHerbert Xu if (esp->padlen) 15838320c70SHerbert Xu clen = ALIGN(clen, esp->padlen); 159d979e20fSMartin Willi plen = clen - skb->len - tfclen; 16038320c70SHerbert Xu 161d979e20fSMartin Willi err = skb_cow_data(skb, tfclen + plen + alen, &trailer); 162d979e20fSMartin Willi if (err < 0) 1631da177e4SLinus Torvalds goto error; 16438320c70SHerbert Xu nfrags = err; 16538320c70SHerbert Xu 1660dc49e9bSSteffen Klassert assoclen = sizeof(*esph); 1670dc49e9bSSteffen Klassert sglists = 1; 1680dc49e9bSSteffen Klassert seqhilen = 0; 1690dc49e9bSSteffen Klassert 1700dc49e9bSSteffen Klassert if (x->props.flags & XFRM_STATE_ESN) { 1710dc49e9bSSteffen Klassert sglists += 2; 1720dc49e9bSSteffen Klassert seqhilen += sizeof(__be32); 1730dc49e9bSSteffen Klassert assoclen += seqhilen; 1740dc49e9bSSteffen Klassert } 1750dc49e9bSSteffen Klassert 1760dc49e9bSSteffen Klassert tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen); 17706848c10SWei Yongjun if (!tmp) { 17806848c10SWei Yongjun err = -ENOMEM; 17938320c70SHerbert Xu goto error; 18006848c10SWei Yongjun } 18138320c70SHerbert Xu 1820dc49e9bSSteffen Klassert seqhi = esp_tmp_seqhi(tmp); 1830dc49e9bSSteffen Klassert iv = esp_tmp_iv(aead, tmp, seqhilen); 18438320c70SHerbert Xu req = esp_tmp_givreq(aead, iv); 18538320c70SHerbert Xu asg = esp_givreq_sg(aead, req); 1860dc49e9bSSteffen Klassert sg = asg + sglists; 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds /* Fill padding... */ 18927a884dcSArnaldo Carvalho de Melo tail = skb_tail_pointer(trailer); 190d979e20fSMartin Willi if (tfclen) { 191d979e20fSMartin Willi memset(tail, 0, tfclen); 192d979e20fSMartin Willi tail += tfclen; 193d979e20fSMartin Willi } 1941da177e4SLinus Torvalds do { 1951da177e4SLinus Torvalds int i; 196d979e20fSMartin Willi for (i = 0; i < plen - 2; i++) 19727a884dcSArnaldo Carvalho de Melo tail[i] = i + 1; 1981da177e4SLinus Torvalds } while (0); 199d979e20fSMartin Willi tail[plen - 2] = plen - 2; 200d979e20fSMartin Willi tail[plen - 1] = *skb_mac_header(skb); 20138320c70SHerbert Xu pskb_put(skb, trailer, clen - skb->len + alen); 2021da177e4SLinus Torvalds 2037b277b1aSHerbert Xu skb_push(skb, -skb_network_offset(skb)); 20487bdc48dSHerbert Xu esph = ip_esp_hdr(skb); 20537fedd3aSHerbert Xu *skb_mac_header(skb) = IPPROTO_ESP; 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds /* this is non-NULL only with UDP Encapsulation */ 2081da177e4SLinus Torvalds if (x->encap) { 2091da177e4SLinus Torvalds struct xfrm_encap_tmpl *encap = x->encap; 2101da177e4SLinus Torvalds struct udphdr *uh; 211d5a0a1e3SAl Viro __be32 *udpdata32; 2125e226e4dSAl Viro __be16 sport, dport; 21338320c70SHerbert Xu int encap_type; 21438320c70SHerbert Xu 21538320c70SHerbert Xu spin_lock_bh(&x->lock); 21638320c70SHerbert Xu sport = encap->encap_sport; 21738320c70SHerbert Xu dport = encap->encap_dport; 21838320c70SHerbert Xu encap_type = encap->encap_type; 21938320c70SHerbert Xu spin_unlock_bh(&x->lock); 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds uh = (struct udphdr *)esph; 22238320c70SHerbert Xu uh->source = sport; 22338320c70SHerbert Xu uh->dest = dport; 22438320c70SHerbert Xu uh->len = htons(skb->len - skb_transport_offset(skb)); 2251da177e4SLinus Torvalds uh->check = 0; 2261da177e4SLinus Torvalds 22738320c70SHerbert Xu switch (encap_type) { 2281da177e4SLinus Torvalds default: 2291da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP: 2301da177e4SLinus Torvalds esph = (struct ip_esp_hdr *)(uh + 1); 2311da177e4SLinus Torvalds break; 2321da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP_NON_IKE: 233d5a0a1e3SAl Viro udpdata32 = (__be32 *)(uh + 1); 2341da177e4SLinus Torvalds udpdata32[0] = udpdata32[1] = 0; 2351da177e4SLinus Torvalds esph = (struct ip_esp_hdr *)(udpdata32 + 2); 2361da177e4SLinus Torvalds break; 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds 23937fedd3aSHerbert Xu *skb_mac_header(skb) = IPPROTO_UDP; 24037fedd3aSHerbert Xu } 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds esph->spi = x->id.spi; 2431ce3644aSSteffen Klassert esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low); 2441da177e4SLinus Torvalds 245ed0e7e0cSDavid S. Miller sg_init_table(sg, nfrags); 24651c739d1SDavid S. Miller skb_to_sgvec(skb, sg, 24738320c70SHerbert Xu esph->enc_data + crypto_aead_ivsize(aead) - skb->data, 24838320c70SHerbert Xu clen + alen); 2490dc49e9bSSteffen Klassert 2500dc49e9bSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) { 2510dc49e9bSSteffen Klassert sg_init_table(asg, 3); 2520dc49e9bSSteffen Klassert sg_set_buf(asg, &esph->spi, sizeof(__be32)); 2530dc49e9bSSteffen Klassert *seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi); 2540dc49e9bSSteffen Klassert sg_set_buf(asg + 1, seqhi, seqhilen); 2550dc49e9bSSteffen Klassert sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32)); 2560dc49e9bSSteffen Klassert } else 25738320c70SHerbert Xu sg_init_one(asg, esph, sizeof(*esph)); 2581da177e4SLinus Torvalds 25938320c70SHerbert Xu aead_givcrypt_set_callback(req, 0, esp_output_done, skb); 26038320c70SHerbert Xu aead_givcrypt_set_crypt(req, sg, sg, clen, iv); 2610dc49e9bSSteffen Klassert aead_givcrypt_set_assoc(req, asg, assoclen); 262b318e0e4SHerbert Xu aead_givcrypt_set_giv(req, esph->enc_data, 2631ce3644aSSteffen Klassert XFRM_SKB_CB(skb)->seq.output.low); 2646b7326c8SHerbert Xu 26538320c70SHerbert Xu ESP_SKB_CB(skb)->tmp = tmp; 26638320c70SHerbert Xu err = crypto_aead_givencrypt(req); 26738320c70SHerbert Xu if (err == -EINPROGRESS) 26838320c70SHerbert Xu goto error; 2691da177e4SLinus Torvalds 27038320c70SHerbert Xu if (err == -EBUSY) 27138320c70SHerbert Xu err = NET_XMIT_DROP; 2721da177e4SLinus Torvalds 27338320c70SHerbert Xu kfree(tmp); 274b7c6538cSHerbert Xu 2751da177e4SLinus Torvalds error: 2761da177e4SLinus Torvalds return err; 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 27938320c70SHerbert Xu static int esp_input_done2(struct sk_buff *skb, int err) 2801da177e4SLinus Torvalds { 281b71d1d42SEric Dumazet const struct iphdr *iph; 28238320c70SHerbert Xu struct xfrm_state *x = xfrm_input_state(skb); 2831da177e4SLinus Torvalds struct esp_data *esp = x->data; 28438320c70SHerbert Xu struct crypto_aead *aead = esp->aead; 28538320c70SHerbert Xu int alen = crypto_aead_authsize(aead); 28638320c70SHerbert Xu int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead); 28738320c70SHerbert Xu int elen = skb->len - hlen; 28831a4ab93SHerbert Xu int ihl; 2894bf05eceSHerbert Xu u8 nexthdr[2]; 2904bf05eceSHerbert Xu int padlen; 2911da177e4SLinus Torvalds 29238320c70SHerbert Xu kfree(ESP_SKB_CB(skb)->tmp); 2930ebea8efSHerbert Xu 2946b7326c8SHerbert Xu if (unlikely(err)) 295668dc8afSHerbert Xu goto out; 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) 2981da177e4SLinus Torvalds BUG(); 2991da177e4SLinus Torvalds 300668dc8afSHerbert Xu err = -EINVAL; 3011da177e4SLinus Torvalds padlen = nexthdr[0]; 30238320c70SHerbert Xu if (padlen + 2 + alen >= elen) 3031da177e4SLinus Torvalds goto out; 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds /* ... check padding bits here. Silly. :-) */ 3061da177e4SLinus Torvalds 307eddc9ec5SArnaldo Carvalho de Melo iph = ip_hdr(skb); 30831a4ab93SHerbert Xu ihl = iph->ihl * 4; 30931a4ab93SHerbert Xu 3101da177e4SLinus Torvalds if (x->encap) { 311752c1f4cSHerbert Xu struct xfrm_encap_tmpl *encap = x->encap; 312d56f90a7SArnaldo Carvalho de Melo struct udphdr *uh = (void *)(skb_network_header(skb) + ihl); 313752c1f4cSHerbert Xu 3141da177e4SLinus Torvalds /* 3151da177e4SLinus Torvalds * 1) if the NAT-T peer's IP or port changed then 3161da177e4SLinus Torvalds * advertize the change to the keying daemon. 3171da177e4SLinus Torvalds * This is an inbound SA, so just compare 3181da177e4SLinus Torvalds * SRC ports. 3191da177e4SLinus Torvalds */ 320752c1f4cSHerbert Xu if (iph->saddr != x->props.saddr.a4 || 321752c1f4cSHerbert Xu uh->source != encap->encap_sport) { 3221da177e4SLinus Torvalds xfrm_address_t ipaddr; 3231da177e4SLinus Torvalds 324752c1f4cSHerbert Xu ipaddr.a4 = iph->saddr; 325752c1f4cSHerbert Xu km_new_mapping(x, &ipaddr, uh->source); 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds /* XXX: perhaps add an extra 3281da177e4SLinus Torvalds * policy check here, to see 3291da177e4SLinus Torvalds * if we should allow or 3301da177e4SLinus Torvalds * reject a packet from a 3311da177e4SLinus Torvalds * different source 3321da177e4SLinus Torvalds * address/port. 3331da177e4SLinus Torvalds */ 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds /* 3371da177e4SLinus Torvalds * 2) ignore UDP/TCP checksums in case 3381da177e4SLinus Torvalds * of NAT-T in Transport Mode, or 3391da177e4SLinus Torvalds * perform other post-processing fixes 340752c1f4cSHerbert Xu * as per draft-ietf-ipsec-udp-encaps-06, 3411da177e4SLinus Torvalds * section 3.1.2 3421da177e4SLinus Torvalds */ 3438bd17075SHerbert Xu if (x->props.mode == XFRM_MODE_TRANSPORT) 3441da177e4SLinus Torvalds skb->ip_summed = CHECKSUM_UNNECESSARY; 345752c1f4cSHerbert Xu } 3461da177e4SLinus Torvalds 347752c1f4cSHerbert Xu pskb_trim(skb, skb->len - alen - padlen - 2); 34838320c70SHerbert Xu __skb_pull(skb, hlen); 3497143dfacSLi RongQing if (x->props.mode == XFRM_MODE_TUNNEL) 3507143dfacSLi RongQing skb_reset_transport_header(skb); 3517143dfacSLi RongQing else 352967b05f6SArnaldo Carvalho de Melo skb_set_transport_header(skb, -ihl); 353752c1f4cSHerbert Xu 35438320c70SHerbert Xu err = nexthdr[1]; 35538320c70SHerbert Xu 35638320c70SHerbert Xu /* RFC4303: Drop dummy packets without any error */ 35738320c70SHerbert Xu if (err == IPPROTO_NONE) 35838320c70SHerbert Xu err = -EINVAL; 35938320c70SHerbert Xu 36038320c70SHerbert Xu out: 36138320c70SHerbert Xu return err; 36238320c70SHerbert Xu } 36338320c70SHerbert Xu 36438320c70SHerbert Xu static void esp_input_done(struct crypto_async_request *base, int err) 36538320c70SHerbert Xu { 36638320c70SHerbert Xu struct sk_buff *skb = base->data; 36738320c70SHerbert Xu 36838320c70SHerbert Xu xfrm_input_resume(skb, esp_input_done2(skb, err)); 36938320c70SHerbert Xu } 37038320c70SHerbert Xu 37138320c70SHerbert Xu /* 37238320c70SHerbert Xu * Note: detecting truncated vs. non-truncated authentication data is very 37338320c70SHerbert Xu * expensive, so we only support truncated data, which is the recommended 37438320c70SHerbert Xu * and common case. 37538320c70SHerbert Xu */ 37638320c70SHerbert Xu static int esp_input(struct xfrm_state *x, struct sk_buff *skb) 37738320c70SHerbert Xu { 37838320c70SHerbert Xu struct ip_esp_hdr *esph; 37938320c70SHerbert Xu struct esp_data *esp = x->data; 38038320c70SHerbert Xu struct crypto_aead *aead = esp->aead; 38138320c70SHerbert Xu struct aead_request *req; 38238320c70SHerbert Xu struct sk_buff *trailer; 38338320c70SHerbert Xu int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead); 38438320c70SHerbert Xu int nfrags; 3850dc49e9bSSteffen Klassert int assoclen; 3860dc49e9bSSteffen Klassert int sglists; 3870dc49e9bSSteffen Klassert int seqhilen; 3880dc49e9bSSteffen Klassert __be32 *seqhi; 38938320c70SHerbert Xu void *tmp; 39038320c70SHerbert Xu u8 *iv; 39138320c70SHerbert Xu struct scatterlist *sg; 39238320c70SHerbert Xu struct scatterlist *asg; 39338320c70SHerbert Xu int err = -EINVAL; 39438320c70SHerbert Xu 395920fc941SThomas Graf if (!pskb_may_pull(skb, sizeof(*esph) + crypto_aead_ivsize(aead))) 39638320c70SHerbert Xu goto out; 39738320c70SHerbert Xu 39838320c70SHerbert Xu if (elen <= 0) 39938320c70SHerbert Xu goto out; 40038320c70SHerbert Xu 40138320c70SHerbert Xu if ((err = skb_cow_data(skb, 0, &trailer)) < 0) 40238320c70SHerbert Xu goto out; 40338320c70SHerbert Xu nfrags = err; 40438320c70SHerbert Xu 4050dc49e9bSSteffen Klassert assoclen = sizeof(*esph); 4060dc49e9bSSteffen Klassert sglists = 1; 4070dc49e9bSSteffen Klassert seqhilen = 0; 4080dc49e9bSSteffen Klassert 4090dc49e9bSSteffen Klassert if (x->props.flags & XFRM_STATE_ESN) { 4100dc49e9bSSteffen Klassert sglists += 2; 4110dc49e9bSSteffen Klassert seqhilen += sizeof(__be32); 4120dc49e9bSSteffen Klassert assoclen += seqhilen; 4130dc49e9bSSteffen Klassert } 4140dc49e9bSSteffen Klassert 41538320c70SHerbert Xu err = -ENOMEM; 4160dc49e9bSSteffen Klassert tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen); 41738320c70SHerbert Xu if (!tmp) 41838320c70SHerbert Xu goto out; 41938320c70SHerbert Xu 42038320c70SHerbert Xu ESP_SKB_CB(skb)->tmp = tmp; 4210dc49e9bSSteffen Klassert seqhi = esp_tmp_seqhi(tmp); 4220dc49e9bSSteffen Klassert iv = esp_tmp_iv(aead, tmp, seqhilen); 42338320c70SHerbert Xu req = esp_tmp_req(aead, iv); 42438320c70SHerbert Xu asg = esp_req_sg(aead, req); 4250dc49e9bSSteffen Klassert sg = asg + sglists; 42638320c70SHerbert Xu 42738320c70SHerbert Xu skb->ip_summed = CHECKSUM_NONE; 42838320c70SHerbert Xu 42938320c70SHerbert Xu esph = (struct ip_esp_hdr *)skb->data; 43038320c70SHerbert Xu 43138320c70SHerbert Xu /* Get ivec. This can be wrong, check against another impls. */ 43238320c70SHerbert Xu iv = esph->enc_data; 43338320c70SHerbert Xu 43438320c70SHerbert Xu sg_init_table(sg, nfrags); 43538320c70SHerbert Xu skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen); 4360dc49e9bSSteffen Klassert 4370dc49e9bSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) { 4380dc49e9bSSteffen Klassert sg_init_table(asg, 3); 4390dc49e9bSSteffen Klassert sg_set_buf(asg, &esph->spi, sizeof(__be32)); 4400dc49e9bSSteffen Klassert *seqhi = XFRM_SKB_CB(skb)->seq.input.hi; 4410dc49e9bSSteffen Klassert sg_set_buf(asg + 1, seqhi, seqhilen); 4420dc49e9bSSteffen Klassert sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32)); 4430dc49e9bSSteffen Klassert } else 44438320c70SHerbert Xu sg_init_one(asg, esph, sizeof(*esph)); 44538320c70SHerbert Xu 44638320c70SHerbert Xu aead_request_set_callback(req, 0, esp_input_done, skb); 44738320c70SHerbert Xu aead_request_set_crypt(req, sg, sg, elen, iv); 4480dc49e9bSSteffen Klassert aead_request_set_assoc(req, asg, assoclen); 44938320c70SHerbert Xu 45038320c70SHerbert Xu err = crypto_aead_decrypt(req); 45138320c70SHerbert Xu if (err == -EINPROGRESS) 45238320c70SHerbert Xu goto out; 45338320c70SHerbert Xu 45438320c70SHerbert Xu err = esp_input_done2(skb, err); 455752c1f4cSHerbert Xu 456752c1f4cSHerbert Xu out: 457668dc8afSHerbert Xu return err; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 460c5c25238SPatrick McHardy static u32 esp4_get_mtu(struct xfrm_state *x, int mtu) 4611da177e4SLinus Torvalds { 4621da177e4SLinus Torvalds struct esp_data *esp = x->data; 46338320c70SHerbert Xu u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4); 46438320c70SHerbert Xu u32 align = max_t(u32, blksize, esp->padlen); 46591657eafSBenjamin Poirier unsigned int net_adj; 4661da177e4SLinus Torvalds 4670a69452cSDiego Beltrami switch (x->props.mode) { 46891657eafSBenjamin Poirier case XFRM_MODE_TRANSPORT: 46991657eafSBenjamin Poirier case XFRM_MODE_BEET: 47091657eafSBenjamin Poirier net_adj = sizeof(struct iphdr); 47191657eafSBenjamin Poirier break; 4720a69452cSDiego Beltrami case XFRM_MODE_TUNNEL: 47391657eafSBenjamin Poirier net_adj = 0; 4740a69452cSDiego Beltrami break; 4750a69452cSDiego Beltrami default: 47691657eafSBenjamin Poirier BUG(); 4771da177e4SLinus Torvalds } 4780a69452cSDiego Beltrami 47991657eafSBenjamin Poirier return ((mtu - x->props.header_len - crypto_aead_authsize(esp->aead) - 48091657eafSBenjamin Poirier net_adj) & ~(align - 1)) + (net_adj - 2); 4811da177e4SLinus Torvalds } 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds static void esp4_err(struct sk_buff *skb, u32 info) 4841da177e4SLinus Torvalds { 4854fb236baSAlexey Dobriyan struct net *net = dev_net(skb->dev); 486b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *)skb->data; 4871da177e4SLinus Torvalds struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2)); 4881da177e4SLinus Torvalds struct xfrm_state *x; 4891da177e4SLinus Torvalds 49055be7a9cSDavid S. Miller switch (icmp_hdr(skb)->type) { 49155be7a9cSDavid S. Miller case ICMP_DEST_UNREACH: 49255be7a9cSDavid S. Miller if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) 4931da177e4SLinus Torvalds return; 49455be7a9cSDavid S. Miller case ICMP_REDIRECT: 49555be7a9cSDavid S. Miller break; 49655be7a9cSDavid S. Miller default: 49755be7a9cSDavid S. Miller return; 49855be7a9cSDavid S. Miller } 4991da177e4SLinus Torvalds 500b71d1d42SEric Dumazet x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, 501b71d1d42SEric Dumazet esph->spi, IPPROTO_ESP, AF_INET); 5021da177e4SLinus Torvalds if (!x) 5031da177e4SLinus Torvalds return; 50455be7a9cSDavid S. Miller 505*387aa65aSTimo Teräs if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) 50636393395SDavid S. Miller ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0); 507*387aa65aSTimo Teräs else 50855be7a9cSDavid S. Miller ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0); 5091da177e4SLinus Torvalds xfrm_state_put(x); 5101da177e4SLinus Torvalds } 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds static void esp_destroy(struct xfrm_state *x) 5131da177e4SLinus Torvalds { 5141da177e4SLinus Torvalds struct esp_data *esp = x->data; 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds if (!esp) 5171da177e4SLinus Torvalds return; 5181da177e4SLinus Torvalds 51938320c70SHerbert Xu crypto_free_aead(esp->aead); 5201da177e4SLinus Torvalds kfree(esp); 5211da177e4SLinus Torvalds } 5221da177e4SLinus Torvalds 5231a6509d9SHerbert Xu static int esp_init_aead(struct xfrm_state *x) 5241da177e4SLinus Torvalds { 5251a6509d9SHerbert Xu struct esp_data *esp = x->data; 5261a6509d9SHerbert Xu struct crypto_aead *aead; 5271a6509d9SHerbert Xu int err; 5281a6509d9SHerbert Xu 5291a6509d9SHerbert Xu aead = crypto_alloc_aead(x->aead->alg_name, 0, 0); 5301a6509d9SHerbert Xu err = PTR_ERR(aead); 5311a6509d9SHerbert Xu if (IS_ERR(aead)) 5321a6509d9SHerbert Xu goto error; 5331a6509d9SHerbert Xu 5341a6509d9SHerbert Xu esp->aead = aead; 5351a6509d9SHerbert Xu 5361a6509d9SHerbert Xu err = crypto_aead_setkey(aead, x->aead->alg_key, 5371a6509d9SHerbert Xu (x->aead->alg_key_len + 7) / 8); 5381a6509d9SHerbert Xu if (err) 5391a6509d9SHerbert Xu goto error; 5401a6509d9SHerbert Xu 5411a6509d9SHerbert Xu err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8); 5421a6509d9SHerbert Xu if (err) 5431a6509d9SHerbert Xu goto error; 5441a6509d9SHerbert Xu 5451a6509d9SHerbert Xu error: 5461a6509d9SHerbert Xu return err; 5471a6509d9SHerbert Xu } 5481a6509d9SHerbert Xu 5491a6509d9SHerbert Xu static int esp_init_authenc(struct xfrm_state *x) 5501a6509d9SHerbert Xu { 5511a6509d9SHerbert Xu struct esp_data *esp = x->data; 55238320c70SHerbert Xu struct crypto_aead *aead; 55338320c70SHerbert Xu struct crypto_authenc_key_param *param; 55438320c70SHerbert Xu struct rtattr *rta; 55538320c70SHerbert Xu char *key; 55638320c70SHerbert Xu char *p; 55738320c70SHerbert Xu char authenc_name[CRYPTO_MAX_ALG_NAME]; 55838320c70SHerbert Xu unsigned int keylen; 55938320c70SHerbert Xu int err; 5601da177e4SLinus Torvalds 5611a6509d9SHerbert Xu err = -EINVAL; 5621da177e4SLinus Torvalds if (x->ealg == NULL) 5631a6509d9SHerbert Xu goto error; 56438320c70SHerbert Xu 5651a6509d9SHerbert Xu err = -ENAMETOOLONG; 5660dc49e9bSSteffen Klassert 5670dc49e9bSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) { 5680dc49e9bSSteffen Klassert if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, 5690dc49e9bSSteffen Klassert "authencesn(%s,%s)", 57038320c70SHerbert Xu x->aalg ? x->aalg->alg_name : "digest_null", 57138320c70SHerbert Xu x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) 5721a6509d9SHerbert Xu goto error; 5730dc49e9bSSteffen Klassert } else { 5740dc49e9bSSteffen Klassert if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, 5750dc49e9bSSteffen Klassert "authenc(%s,%s)", 5760dc49e9bSSteffen Klassert x->aalg ? x->aalg->alg_name : "digest_null", 5770dc49e9bSSteffen Klassert x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) 5780dc49e9bSSteffen Klassert goto error; 5790dc49e9bSSteffen Klassert } 58038320c70SHerbert Xu 58138320c70SHerbert Xu aead = crypto_alloc_aead(authenc_name, 0, 0); 58238320c70SHerbert Xu err = PTR_ERR(aead); 58338320c70SHerbert Xu if (IS_ERR(aead)) 58438320c70SHerbert Xu goto error; 58538320c70SHerbert Xu 58638320c70SHerbert Xu esp->aead = aead; 58738320c70SHerbert Xu 58838320c70SHerbert Xu keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) + 58938320c70SHerbert Xu (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param)); 59038320c70SHerbert Xu err = -ENOMEM; 59138320c70SHerbert Xu key = kmalloc(keylen, GFP_KERNEL); 59238320c70SHerbert Xu if (!key) 59338320c70SHerbert Xu goto error; 59438320c70SHerbert Xu 59538320c70SHerbert Xu p = key; 59638320c70SHerbert Xu rta = (void *)p; 59738320c70SHerbert Xu rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM; 59838320c70SHerbert Xu rta->rta_len = RTA_LENGTH(sizeof(*param)); 59938320c70SHerbert Xu param = RTA_DATA(rta); 60038320c70SHerbert Xu p += RTA_SPACE(sizeof(*param)); 60138320c70SHerbert Xu 6021da177e4SLinus Torvalds if (x->aalg) { 6031da177e4SLinus Torvalds struct xfrm_algo_desc *aalg_desc; 6041da177e4SLinus Torvalds 60538320c70SHerbert Xu memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8); 60638320c70SHerbert Xu p += (x->aalg->alg_key_len + 7) / 8; 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 6091da177e4SLinus Torvalds BUG_ON(!aalg_desc); 6101da177e4SLinus Torvalds 61138320c70SHerbert Xu err = -EINVAL; 6121da177e4SLinus Torvalds if (aalg_desc->uinfo.auth.icv_fullbits/8 != 61338320c70SHerbert Xu crypto_aead_authsize(aead)) { 61464ce2073SPatrick McHardy NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n", 6151da177e4SLinus Torvalds x->aalg->alg_name, 61638320c70SHerbert Xu crypto_aead_authsize(aead), 61764ce2073SPatrick McHardy aalg_desc->uinfo.auth.icv_fullbits/8); 61838320c70SHerbert Xu goto free_key; 6191da177e4SLinus Torvalds } 6201da177e4SLinus Torvalds 62138320c70SHerbert Xu err = crypto_aead_setauthsize( 6228f8a088cSMartin Willi aead, x->aalg->alg_trunc_len / 8); 62338320c70SHerbert Xu if (err) 62438320c70SHerbert Xu goto free_key; 6251da177e4SLinus Torvalds } 6264b7137ffSHerbert Xu 62738320c70SHerbert Xu param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8); 62838320c70SHerbert Xu memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8); 62938320c70SHerbert Xu 63038320c70SHerbert Xu err = crypto_aead_setkey(aead, key, keylen); 63138320c70SHerbert Xu 63238320c70SHerbert Xu free_key: 63338320c70SHerbert Xu kfree(key); 63438320c70SHerbert Xu 6351a6509d9SHerbert Xu error: 6361a6509d9SHerbert Xu return err; 6371a6509d9SHerbert Xu } 6381a6509d9SHerbert Xu 6391a6509d9SHerbert Xu static int esp_init_state(struct xfrm_state *x) 6401a6509d9SHerbert Xu { 6411a6509d9SHerbert Xu struct esp_data *esp; 6421a6509d9SHerbert Xu struct crypto_aead *aead; 6431a6509d9SHerbert Xu u32 align; 6441a6509d9SHerbert Xu int err; 6451a6509d9SHerbert Xu 6461a6509d9SHerbert Xu esp = kzalloc(sizeof(*esp), GFP_KERNEL); 6471a6509d9SHerbert Xu if (esp == NULL) 6481a6509d9SHerbert Xu return -ENOMEM; 6491a6509d9SHerbert Xu 6501a6509d9SHerbert Xu x->data = esp; 6511a6509d9SHerbert Xu 6521a6509d9SHerbert Xu if (x->aead) 6531a6509d9SHerbert Xu err = esp_init_aead(x); 6541a6509d9SHerbert Xu else 6551a6509d9SHerbert Xu err = esp_init_authenc(x); 6561a6509d9SHerbert Xu 65738320c70SHerbert Xu if (err) 6581da177e4SLinus Torvalds goto error; 65938320c70SHerbert Xu 6601a6509d9SHerbert Xu aead = esp->aead; 6611a6509d9SHerbert Xu 6621a6509d9SHerbert Xu esp->padlen = 0; 6631a6509d9SHerbert Xu 66438320c70SHerbert Xu x->props.header_len = sizeof(struct ip_esp_hdr) + 66538320c70SHerbert Xu crypto_aead_ivsize(aead); 6667e49e6deSMasahide NAKAMURA if (x->props.mode == XFRM_MODE_TUNNEL) 6671da177e4SLinus Torvalds x->props.header_len += sizeof(struct iphdr); 668eb49e630SJoakim Koskela else if (x->props.mode == XFRM_MODE_BEET && x->sel.family != AF_INET6) 669ac758e3cSPatrick McHardy x->props.header_len += IPV4_BEET_PHMAXLEN; 6701da177e4SLinus Torvalds if (x->encap) { 6711da177e4SLinus Torvalds struct xfrm_encap_tmpl *encap = x->encap; 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds switch (encap->encap_type) { 6741da177e4SLinus Torvalds default: 6751da177e4SLinus Torvalds goto error; 6761da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP: 6771da177e4SLinus Torvalds x->props.header_len += sizeof(struct udphdr); 6781da177e4SLinus Torvalds break; 6791da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP_NON_IKE: 6801da177e4SLinus Torvalds x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32); 6811da177e4SLinus Torvalds break; 6821da177e4SLinus Torvalds } 6831da177e4SLinus Torvalds } 68438320c70SHerbert Xu 68538320c70SHerbert Xu align = ALIGN(crypto_aead_blocksize(aead), 4); 68638320c70SHerbert Xu if (esp->padlen) 68738320c70SHerbert Xu align = max_t(u32, align, esp->padlen); 68838320c70SHerbert Xu x->props.trailer_len = align + 1 + crypto_aead_authsize(esp->aead); 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds error: 69138320c70SHerbert Xu return err; 6921da177e4SLinus Torvalds } 6931da177e4SLinus Torvalds 694533cb5b0SEric Dumazet static const struct xfrm_type esp_type = 6951da177e4SLinus Torvalds { 6961da177e4SLinus Torvalds .description = "ESP4", 6971da177e4SLinus Torvalds .owner = THIS_MODULE, 6981da177e4SLinus Torvalds .proto = IPPROTO_ESP, 699436a0a40SHerbert Xu .flags = XFRM_TYPE_REPLAY_PROT, 7001da177e4SLinus Torvalds .init_state = esp_init_state, 7011da177e4SLinus Torvalds .destructor = esp_destroy, 702c5c25238SPatrick McHardy .get_mtu = esp4_get_mtu, 7031da177e4SLinus Torvalds .input = esp_input, 7041da177e4SLinus Torvalds .output = esp_output 7051da177e4SLinus Torvalds }; 7061da177e4SLinus Torvalds 70732613090SAlexey Dobriyan static const struct net_protocol esp4_protocol = { 7081da177e4SLinus Torvalds .handler = xfrm4_rcv, 7091da177e4SLinus Torvalds .err_handler = esp4_err, 7101da177e4SLinus Torvalds .no_policy = 1, 7114fb236baSAlexey Dobriyan .netns_ok = 1, 7121da177e4SLinus Torvalds }; 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds static int __init esp4_init(void) 7151da177e4SLinus Torvalds { 7161da177e4SLinus Torvalds if (xfrm_register_type(&esp_type, AF_INET) < 0) { 717058bd4d2SJoe Perches pr_info("%s: can't add xfrm type\n", __func__); 7181da177e4SLinus Torvalds return -EAGAIN; 7191da177e4SLinus Torvalds } 7201da177e4SLinus Torvalds if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) { 721058bd4d2SJoe Perches pr_info("%s: can't add protocol\n", __func__); 7221da177e4SLinus Torvalds xfrm_unregister_type(&esp_type, AF_INET); 7231da177e4SLinus Torvalds return -EAGAIN; 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds return 0; 7261da177e4SLinus Torvalds } 7271da177e4SLinus Torvalds 7281da177e4SLinus Torvalds static void __exit esp4_fini(void) 7291da177e4SLinus Torvalds { 7301da177e4SLinus Torvalds if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0) 731058bd4d2SJoe Perches pr_info("%s: can't remove protocol\n", __func__); 7321da177e4SLinus Torvalds if (xfrm_unregister_type(&esp_type, AF_INET) < 0) 733058bd4d2SJoe Perches pr_info("%s: can't remove xfrm type\n", __func__); 7341da177e4SLinus Torvalds } 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds module_init(esp4_init); 7371da177e4SLinus Torvalds module_exit(esp4_fini); 7381da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 739d3d6dd3aSMasahide NAKAMURA MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_ESP); 740