blob: 3f1ec1586ae174d9bea18de2bcada31c3c88a5bb [file] [log] [blame]
David S. Miller6e5714e2011-08-03 20:50:44 -07001#include <linux/kernel.h>
2#include <linux/init.h>
3#include <linux/cryptohash.h>
4#include <linux/module.h>
5#include <linux/cache.h>
6#include <linux/random.h>
7#include <linux/hrtimer.h>
8#include <linux/ktime.h>
9#include <linux/string.h>
10
11#include <net/secure_seq.h>
12
Eric Dumazet9a3bab62013-09-24 06:19:57 -070013#define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4)
David S. Miller6e5714e2011-08-03 20:50:44 -070014
Eric Dumazet9a3bab62013-09-24 06:19:57 -070015static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned;
16
17static void net_secret_init(void)
David S. Miller6e5714e2011-08-03 20:50:44 -070018{
Eric Dumazet9a3bab62013-09-24 06:19:57 -070019 u32 tmp;
20 int i;
21
22 if (likely(net_secret[0]))
23 return;
24
25 for (i = NET_SECRET_SIZE; i > 0;) {
26 do {
27 get_random_bytes(&tmp, sizeof(tmp));
28 } while (!tmp);
29 cmpxchg(&net_secret[--i], 0, tmp);
30 }
David S. Miller6e5714e2011-08-03 20:50:44 -070031}
David S. Miller6e5714e2011-08-03 20:50:44 -070032
Stephen Boyd681090902011-12-06 08:04:40 +000033#ifdef CONFIG_INET
David S. Miller6e5714e2011-08-03 20:50:44 -070034static u32 seq_scale(u32 seq)
35{
36 /*
37 * As close as possible to RFC 793, which
38 * suggests using a 250 kHz clock.
39 * Further reading shows this assumes 2 Mb/s networks.
40 * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
41 * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
42 * we also need to limit the resolution so that the u32 seq
43 * overlaps less than one time per MSL (2 minutes).
44 * Choosing a clock of 64 ns period is OK. (period of 274 s)
45 */
46 return seq + (ktime_to_ns(ktime_get_real()) >> 6);
47}
Stephen Boyd681090902011-12-06 08:04:40 +000048#endif
David S. Miller6e5714e2011-08-03 20:50:44 -070049
Eric Dumazetdfd56b82011-12-10 09:48:31 +000050#if IS_ENABLED(CONFIG_IPV6)
Eric Dumazetcf533ea2011-10-21 05:22:42 -040051__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
David S. Miller6e5714e2011-08-03 20:50:44 -070052 __be16 sport, __be16 dport)
53{
54 u32 secret[MD5_MESSAGE_BYTES / 4];
55 u32 hash[MD5_DIGEST_WORDS];
56 u32 i;
57
Eric Dumazet9a3bab62013-09-24 06:19:57 -070058 net_secret_init();
David S. Miller6e5714e2011-08-03 20:50:44 -070059 memcpy(hash, saddr, 16);
60 for (i = 0; i < 4; i++)
Eric Dumazet747465e2012-01-16 19:27:39 +000061 secret[i] = net_secret[i] + (__force u32)daddr[i];
David S. Miller6e5714e2011-08-03 20:50:44 -070062 secret[4] = net_secret[4] +
63 (((__force u16)sport << 16) + (__force u16)dport);
64 for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
65 secret[i] = net_secret[i];
66
67 md5_transform(hash, secret);
68
69 return seq_scale(hash[0]);
70}
71EXPORT_SYMBOL(secure_tcpv6_sequence_number);
72
73u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
74 __be16 dport)
75{
76 u32 secret[MD5_MESSAGE_BYTES / 4];
77 u32 hash[MD5_DIGEST_WORDS];
78 u32 i;
79
Eric Dumazet9a3bab62013-09-24 06:19:57 -070080 net_secret_init();
David S. Miller6e5714e2011-08-03 20:50:44 -070081 memcpy(hash, saddr, 16);
82 for (i = 0; i < 4; i++)
83 secret[i] = net_secret[i] + (__force u32) daddr[i];
84 secret[4] = net_secret[4] + (__force u32)dport;
85 for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
86 secret[i] = net_secret[i];
87
88 md5_transform(hash, secret);
89
90 return hash[0];
91}
Patrick McHardy58a317f2012-08-26 19:14:12 +020092EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
David S. Miller6e5714e2011-08-03 20:50:44 -070093#endif
94
95#ifdef CONFIG_INET
96__u32 secure_ip_id(__be32 daddr)
97{
98 u32 hash[MD5_DIGEST_WORDS];
99
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700100 net_secret_init();
David S. Miller6e5714e2011-08-03 20:50:44 -0700101 hash[0] = (__force __u32) daddr;
102 hash[1] = net_secret[13];
103 hash[2] = net_secret[14];
104 hash[3] = net_secret[15];
105
106 md5_transform(hash, net_secret);
107
108 return hash[0];
109}
110
111__u32 secure_ipv6_id(const __be32 daddr[4])
112{
113 __u32 hash[4];
114
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700115 net_secret_init();
David S. Miller6e5714e2011-08-03 20:50:44 -0700116 memcpy(hash, daddr, 16);
117 md5_transform(hash, net_secret);
118
119 return hash[0];
120}
121
122__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
123 __be16 sport, __be16 dport)
124{
125 u32 hash[MD5_DIGEST_WORDS];
126
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700127 net_secret_init();
David S. Miller6e5714e2011-08-03 20:50:44 -0700128 hash[0] = (__force u32)saddr;
129 hash[1] = (__force u32)daddr;
130 hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
131 hash[3] = net_secret[15];
132
133 md5_transform(hash, net_secret);
134
135 return seq_scale(hash[0]);
136}
137
138u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
139{
140 u32 hash[MD5_DIGEST_WORDS];
141
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700142 net_secret_init();
David S. Miller6e5714e2011-08-03 20:50:44 -0700143 hash[0] = (__force u32)saddr;
144 hash[1] = (__force u32)daddr;
145 hash[2] = (__force u32)dport ^ net_secret[14];
146 hash[3] = net_secret[15];
147
148 md5_transform(hash, net_secret);
149
150 return hash[0];
151}
152EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
153#endif
154
Igor Maravića3bf7ae2011-12-12 02:58:22 +0000155#if IS_ENABLED(CONFIG_IP_DCCP)
David S. Miller6e5714e2011-08-03 20:50:44 -0700156u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
157 __be16 sport, __be16 dport)
158{
159 u32 hash[MD5_DIGEST_WORDS];
160 u64 seq;
161
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700162 net_secret_init();
David S. Miller6e5714e2011-08-03 20:50:44 -0700163 hash[0] = (__force u32)saddr;
164 hash[1] = (__force u32)daddr;
165 hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
166 hash[3] = net_secret[15];
167
168 md5_transform(hash, net_secret);
169
170 seq = hash[0] | (((u64)hash[1]) << 32);
171 seq += ktime_to_ns(ktime_get_real());
172 seq &= (1ull << 48) - 1;
173
174 return seq;
175}
176EXPORT_SYMBOL(secure_dccp_sequence_number);
177
Eric Dumazetdfd56b82011-12-10 09:48:31 +0000178#if IS_ENABLED(CONFIG_IPV6)
David S. Miller6e5714e2011-08-03 20:50:44 -0700179u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
180 __be16 sport, __be16 dport)
181{
182 u32 secret[MD5_MESSAGE_BYTES / 4];
183 u32 hash[MD5_DIGEST_WORDS];
184 u64 seq;
185 u32 i;
186
Eric Dumazet9a3bab62013-09-24 06:19:57 -0700187 net_secret_init();
David S. Miller6e5714e2011-08-03 20:50:44 -0700188 memcpy(hash, saddr, 16);
189 for (i = 0; i < 4; i++)
190 secret[i] = net_secret[i] + daddr[i];
191 secret[4] = net_secret[4] +
192 (((__force u16)sport << 16) + (__force u16)dport);
193 for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
194 secret[i] = net_secret[i];
195
196 md5_transform(hash, secret);
197
198 seq = hash[0] | (((u64)hash[1]) << 32);
199 seq += ktime_to_ns(ktime_get_real());
200 seq &= (1ull << 48) - 1;
201
202 return seq;
203}
204EXPORT_SYMBOL(secure_dccpv6_sequence_number);
205#endif
206#endif