1 #include <linux/err.h> 2 #include <linux/module.h> 3 #include <net/ip.h> 4 #include <net/xfrm.h> 5 #include <net/ah.h> 6 #include <linux/crypto.h> 7 #include <linux/pfkeyv2.h> 8 #include <linux/spinlock.h> 9 #include <net/icmp.h> 10 #include <net/protocol.h> 11 #include <asm/scatterlist.h> 12 13 14 /* Clear mutable options and find final destination to substitute 15 * into IP header for icv calculation. Options are already checked 16 * for validity, so paranoia is not required. */ 17 18 static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr) 19 { 20 unsigned char * optptr = (unsigned char*)(iph+1); 21 int l = iph->ihl*4 - sizeof(struct iphdr); 22 int optlen; 23 24 while (l > 0) { 25 switch (*optptr) { 26 case IPOPT_END: 27 return 0; 28 case IPOPT_NOOP: 29 l--; 30 optptr++; 31 continue; 32 } 33 optlen = optptr[1]; 34 if (optlen<2 || optlen>l) 35 return -EINVAL; 36 switch (*optptr) { 37 case IPOPT_SEC: 38 case 0x85: /* Some "Extended Security" crap. */ 39 case IPOPT_CIPSO: 40 case IPOPT_RA: 41 case 0x80|21: /* RFC1770 */ 42 break; 43 case IPOPT_LSRR: 44 case IPOPT_SSRR: 45 if (optlen < 6) 46 return -EINVAL; 47 memcpy(daddr, optptr+optlen-4, 4); 48 /* Fall through */ 49 default: 50 memset(optptr, 0, optlen); 51 } 52 l -= optlen; 53 optptr += optlen; 54 } 55 return 0; 56 } 57 58 static int ah_output(struct xfrm_state *x, struct sk_buff *skb) 59 { 60 int err; 61 struct iphdr *iph, *top_iph; 62 struct ip_auth_hdr *ah; 63 struct ah_data *ahp; 64 union { 65 struct iphdr iph; 66 char buf[60]; 67 } tmp_iph; 68 69 skb_push(skb, -skb_network_offset(skb)); 70 top_iph = ip_hdr(skb); 71 iph = &tmp_iph.iph; 72 73 iph->tos = top_iph->tos; 74 iph->ttl = top_iph->ttl; 75 iph->frag_off = top_iph->frag_off; 76 77 if (top_iph->ihl != 5) { 78 iph->daddr = top_iph->daddr; 79 memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); 80 err = ip_clear_mutable_options(top_iph, &top_iph->daddr); 81 if (err) 82 goto error; 83 } 84 85 ah = ip_auth_hdr(skb); 86 ah->nexthdr = *skb_mac_header(skb); 87 *skb_mac_header(skb) = IPPROTO_AH; 88 89 top_iph->tos = 0; 90 top_iph->tot_len = htons(skb->len); 91 top_iph->frag_off = 0; 92 top_iph->ttl = 0; 93 top_iph->check = 0; 94 95 ahp = x->data; 96 ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; 97 98 ah->reserved = 0; 99 ah->spi = x->id.spi; 100 ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq); 101 102 spin_lock_bh(&x->lock); 103 err = ah_mac_digest(ahp, skb, ah->auth_data); 104 memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); 105 spin_unlock_bh(&x->lock); 106 107 if (err) 108 goto error; 109 110 top_iph->tos = iph->tos; 111 top_iph->ttl = iph->ttl; 112 top_iph->frag_off = iph->frag_off; 113 if (top_iph->ihl != 5) { 114 top_iph->daddr = iph->daddr; 115 memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); 116 } 117 118 err = 0; 119 120 error: 121 return err; 122 } 123 124 static int ah_input(struct xfrm_state *x, struct sk_buff *skb) 125 { 126 int ah_hlen; 127 int ihl; 128 int nexthdr; 129 int err = -EINVAL; 130 struct iphdr *iph; 131 struct ip_auth_hdr *ah; 132 struct ah_data *ahp; 133 char work_buf[60]; 134 135 if (!pskb_may_pull(skb, sizeof(*ah))) 136 goto out; 137 138 ah = (struct ip_auth_hdr *)skb->data; 139 ahp = x->data; 140 nexthdr = ah->nexthdr; 141 ah_hlen = (ah->hdrlen + 2) << 2; 142 143 if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) && 144 ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len)) 145 goto out; 146 147 if (!pskb_may_pull(skb, ah_hlen)) 148 goto out; 149 150 /* We are going to _remove_ AH header to keep sockets happy, 151 * so... Later this can change. */ 152 if (skb_cloned(skb) && 153 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) 154 goto out; 155 156 skb->ip_summed = CHECKSUM_NONE; 157 158 ah = (struct ip_auth_hdr *)skb->data; 159 iph = ip_hdr(skb); 160 161 ihl = skb->data - skb_network_header(skb); 162 memcpy(work_buf, iph, ihl); 163 164 iph->ttl = 0; 165 iph->tos = 0; 166 iph->frag_off = 0; 167 iph->check = 0; 168 if (ihl > sizeof(*iph)) { 169 __be32 dummy; 170 if (ip_clear_mutable_options(iph, &dummy)) 171 goto out; 172 } 173 { 174 u8 auth_data[MAX_AH_AUTH_LEN]; 175 176 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); 177 skb_push(skb, ihl); 178 err = ah_mac_digest(ahp, skb, ah->auth_data); 179 if (err) 180 goto out; 181 err = -EINVAL; 182 if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) { 183 x->stats.integrity_failed++; 184 goto out; 185 } 186 } 187 skb->network_header += ah_hlen; 188 memcpy(skb_network_header(skb), work_buf, ihl); 189 skb->transport_header = skb->network_header; 190 __skb_pull(skb, ah_hlen + ihl); 191 192 return nexthdr; 193 194 out: 195 return err; 196 } 197 198 static void ah4_err(struct sk_buff *skb, u32 info) 199 { 200 struct iphdr *iph = (struct iphdr*)skb->data; 201 struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2)); 202 struct xfrm_state *x; 203 204 if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH || 205 icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) 206 return; 207 208 x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); 209 if (!x) 210 return; 211 printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/%08x\n", 212 ntohl(ah->spi), ntohl(iph->daddr)); 213 xfrm_state_put(x); 214 } 215 216 static int ah_init_state(struct xfrm_state *x) 217 { 218 struct ah_data *ahp = NULL; 219 struct xfrm_algo_desc *aalg_desc; 220 struct crypto_hash *tfm; 221 222 if (!x->aalg) 223 goto error; 224 225 if (x->encap) 226 goto error; 227 228 ahp = kzalloc(sizeof(*ahp), GFP_KERNEL); 229 if (ahp == NULL) 230 return -ENOMEM; 231 232 tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); 233 if (IS_ERR(tfm)) 234 goto error; 235 236 ahp->tfm = tfm; 237 if (crypto_hash_setkey(tfm, x->aalg->alg_key, 238 (x->aalg->alg_key_len + 7) / 8)) 239 goto error; 240 241 /* 242 * Lookup the algorithm description maintained by xfrm_algo, 243 * verify crypto transform properties, and store information 244 * we need for AH processing. This lookup cannot fail here 245 * after a successful crypto_alloc_hash(). 246 */ 247 aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 248 BUG_ON(!aalg_desc); 249 250 if (aalg_desc->uinfo.auth.icv_fullbits/8 != 251 crypto_hash_digestsize(tfm)) { 252 printk(KERN_INFO "AH: %s digestsize %u != %hu\n", 253 x->aalg->alg_name, crypto_hash_digestsize(tfm), 254 aalg_desc->uinfo.auth.icv_fullbits/8); 255 goto error; 256 } 257 258 ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; 259 ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; 260 261 BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); 262 263 ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); 264 if (!ahp->work_icv) 265 goto error; 266 267 x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + 268 ahp->icv_trunc_len); 269 if (x->props.mode == XFRM_MODE_TUNNEL) 270 x->props.header_len += sizeof(struct iphdr); 271 x->data = ahp; 272 273 return 0; 274 275 error: 276 if (ahp) { 277 kfree(ahp->work_icv); 278 crypto_free_hash(ahp->tfm); 279 kfree(ahp); 280 } 281 return -EINVAL; 282 } 283 284 static void ah_destroy(struct xfrm_state *x) 285 { 286 struct ah_data *ahp = x->data; 287 288 if (!ahp) 289 return; 290 291 kfree(ahp->work_icv); 292 ahp->work_icv = NULL; 293 crypto_free_hash(ahp->tfm); 294 ahp->tfm = NULL; 295 kfree(ahp); 296 } 297 298 299 static struct xfrm_type ah_type = 300 { 301 .description = "AH4", 302 .owner = THIS_MODULE, 303 .proto = IPPROTO_AH, 304 .flags = XFRM_TYPE_REPLAY_PROT, 305 .init_state = ah_init_state, 306 .destructor = ah_destroy, 307 .input = ah_input, 308 .output = ah_output 309 }; 310 311 static struct net_protocol ah4_protocol = { 312 .handler = xfrm4_rcv, 313 .err_handler = ah4_err, 314 .no_policy = 1, 315 }; 316 317 static int __init ah4_init(void) 318 { 319 if (xfrm_register_type(&ah_type, AF_INET) < 0) { 320 printk(KERN_INFO "ip ah init: can't add xfrm type\n"); 321 return -EAGAIN; 322 } 323 if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) { 324 printk(KERN_INFO "ip ah init: can't add protocol\n"); 325 xfrm_unregister_type(&ah_type, AF_INET); 326 return -EAGAIN; 327 } 328 return 0; 329 } 330 331 static void __exit ah4_fini(void) 332 { 333 if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0) 334 printk(KERN_INFO "ip ah close: can't remove protocol\n"); 335 if (xfrm_unregister_type(&ah_type, AF_INET) < 0) 336 printk(KERN_INFO "ip ah close: can't remove xfrm type\n"); 337 } 338 339 module_init(ah4_init); 340 module_exit(ah4_fini); 341 MODULE_LICENSE("GPL"); 342 MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_AH); 343