tcp_ao.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * INET An implementation of the TCP Authentication Option (TCP-AO).
  4. * See RFC5925.
  5. *
  6. * Authors: Dmitry Safonov <dima@arista.com>
  7. * Francesco Ruggeri <fruggeri@arista.com>
  8. * Salam Noureddine <noureddine@arista.com>
  9. */
  10. #include <crypto/hash.h>
  11. #include <linux/tcp.h>
  12. #include <net/tcp.h>
  13. #include <net/ipv6.h>
  14. static int tcp_v6_ao_calc_key(struct tcp_ao_key *mkt, u8 *key,
  15. const struct in6_addr *saddr,
  16. const struct in6_addr *daddr,
  17. __be16 sport, __be16 dport,
  18. __be32 sisn, __be32 disn)
  19. {
  20. struct kdf_input_block {
  21. u8 counter;
  22. u8 label[6];
  23. struct tcp6_ao_context ctx;
  24. __be16 outlen;
  25. } __packed * tmp;
  26. struct tcp_sigpool hp;
  27. int err;
  28. err = tcp_sigpool_start(mkt->tcp_sigpool_id, &hp);
  29. if (err)
  30. return err;
  31. tmp = hp.scratch;
  32. tmp->counter = 1;
  33. memcpy(tmp->label, "TCP-AO", 6);
  34. tmp->ctx.saddr = *saddr;
  35. tmp->ctx.daddr = *daddr;
  36. tmp->ctx.sport = sport;
  37. tmp->ctx.dport = dport;
  38. tmp->ctx.sisn = sisn;
  39. tmp->ctx.disn = disn;
  40. tmp->outlen = htons(tcp_ao_digest_size(mkt) * 8); /* in bits */
  41. err = tcp_ao_calc_traffic_key(mkt, key, tmp, sizeof(*tmp), &hp);
  42. tcp_sigpool_end(&hp);
  43. return err;
  44. }
  45. int tcp_v6_ao_calc_key_skb(struct tcp_ao_key *mkt, u8 *key,
  46. const struct sk_buff *skb,
  47. __be32 sisn, __be32 disn)
  48. {
  49. const struct ipv6hdr *iph = ipv6_hdr(skb);
  50. const struct tcphdr *th = tcp_hdr(skb);
  51. return tcp_v6_ao_calc_key(mkt, key, &iph->saddr,
  52. &iph->daddr, th->source,
  53. th->dest, sisn, disn);
  54. }
  55. int tcp_v6_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
  56. const struct sock *sk, __be32 sisn,
  57. __be32 disn, bool send)
  58. {
  59. if (send)
  60. return tcp_v6_ao_calc_key(mkt, key, &sk->sk_v6_rcv_saddr,
  61. &sk->sk_v6_daddr, htons(sk->sk_num),
  62. sk->sk_dport, sisn, disn);
  63. else
  64. return tcp_v6_ao_calc_key(mkt, key, &sk->sk_v6_daddr,
  65. &sk->sk_v6_rcv_saddr, sk->sk_dport,
  66. htons(sk->sk_num), disn, sisn);
  67. }
  68. int tcp_v6_ao_calc_key_rsk(struct tcp_ao_key *mkt, u8 *key,
  69. struct request_sock *req)
  70. {
  71. struct inet_request_sock *ireq = inet_rsk(req);
  72. return tcp_v6_ao_calc_key(mkt, key,
  73. &ireq->ir_v6_loc_addr, &ireq->ir_v6_rmt_addr,
  74. htons(ireq->ir_num), ireq->ir_rmt_port,
  75. htonl(tcp_rsk(req)->snt_isn),
  76. htonl(tcp_rsk(req)->rcv_isn));
  77. }
  78. struct tcp_ao_key *tcp_v6_ao_lookup(const struct sock *sk,
  79. struct sock *addr_sk,
  80. int sndid, int rcvid)
  81. {
  82. int l3index = l3mdev_master_ifindex_by_index(sock_net(sk),
  83. addr_sk->sk_bound_dev_if);
  84. struct in6_addr *addr = &addr_sk->sk_v6_daddr;
  85. return tcp_ao_do_lookup(sk, l3index, (union tcp_ao_addr *)addr,
  86. AF_INET6, sndid, rcvid);
  87. }
  88. struct tcp_ao_key *tcp_v6_ao_lookup_rsk(const struct sock *sk,
  89. struct request_sock *req,
  90. int sndid, int rcvid)
  91. {
  92. struct inet_request_sock *ireq = inet_rsk(req);
  93. struct in6_addr *addr = &ireq->ir_v6_rmt_addr;
  94. int l3index;
  95. l3index = l3mdev_master_ifindex_by_index(sock_net(sk), ireq->ir_iif);
  96. return tcp_ao_do_lookup(sk, l3index, (union tcp_ao_addr *)addr,
  97. AF_INET6, sndid, rcvid);
  98. }
  99. int tcp_v6_ao_hash_pseudoheader(struct tcp_sigpool *hp,
  100. const struct in6_addr *daddr,
  101. const struct in6_addr *saddr, int nbytes)
  102. {
  103. struct tcp6_pseudohdr *bp;
  104. struct scatterlist sg;
  105. bp = hp->scratch;
  106. /* 1. TCP pseudo-header (RFC2460) */
  107. bp->saddr = *saddr;
  108. bp->daddr = *daddr;
  109. bp->len = cpu_to_be32(nbytes);
  110. bp->protocol = cpu_to_be32(IPPROTO_TCP);
  111. sg_init_one(&sg, bp, sizeof(*bp));
  112. ahash_request_set_crypt(hp->req, &sg, NULL, sizeof(*bp));
  113. return crypto_ahash_update(hp->req);
  114. }
  115. int tcp_v6_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
  116. const struct sock *sk, const struct sk_buff *skb,
  117. const u8 *tkey, int hash_offset, u32 sne)
  118. {
  119. return tcp_ao_hash_skb(AF_INET6, ao_hash, key, sk, skb, tkey,
  120. hash_offset, sne);
  121. }
  122. int tcp_v6_parse_ao(struct sock *sk, int cmd,
  123. sockptr_t optval, int optlen)
  124. {
  125. return tcp_parse_ao(sk, cmd, AF_INET6, optval, optlen);
  126. }
  127. int tcp_v6_ao_synack_hash(char *ao_hash, struct tcp_ao_key *ao_key,
  128. struct request_sock *req, const struct sk_buff *skb,
  129. int hash_offset, u32 sne)
  130. {
  131. void *hash_buf = NULL;
  132. int err;
  133. hash_buf = kmalloc(tcp_ao_digest_size(ao_key), GFP_ATOMIC);
  134. if (!hash_buf)
  135. return -ENOMEM;
  136. err = tcp_v6_ao_calc_key_rsk(ao_key, hash_buf, req);
  137. if (err)
  138. goto out;
  139. err = tcp_ao_hash_skb(AF_INET6, ao_hash, ao_key, req_to_sk(req), skb,
  140. hash_buf, hash_offset, sne);
  141. out:
  142. kfree(hash_buf);
  143. return err;
  144. }