Commit bf355b8d authored by David Lebrun's avatar David Lebrun Committed by David S. Miller

ipv6: sr: add core files for SR HMAC support

This patch adds the necessary functions to compute and check the HMAC signature
of an SR-enabled packet. Two HMAC algorithms are supported: hmac(sha1) and
hmac(sha256).

In order to avoid dynamic memory allocation for each HMAC computation,
a per-cpu ring buffer is allocated for this purpose.

A new per-interface sysctl called seg6_require_hmac is added, allowing a
user-defined policy for processing HMAC-signed SR-enabled packets.
A value of -1 means that the HMAC field will always be ignored.
A value of 0 means that if an HMAC field is present, its validity will
be enforced (the packet is dropped is the signature is incorrect).
Finally, a value of 1 means that any SR-enabled packet that does not
contain an HMAC signature or whose signature is incorrect will be dropped.
Signed-off-by: default avatarDavid Lebrun <david.lebrun@uclouvain.be>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6c8702c6
...@@ -65,6 +65,9 @@ struct ipv6_devconf { ...@@ -65,6 +65,9 @@ struct ipv6_devconf {
__s32 use_oif_addrs_only; __s32 use_oif_addrs_only;
__s32 keep_addr_on_down; __s32 keep_addr_on_down;
__s32 seg6_enabled; __s32 seg6_enabled;
#ifdef CONFIG_IPV6_SEG6_HMAC
__s32 seg6_require_hmac;
#endif
struct ctl_table_header *sysctl_header; struct ctl_table_header *sysctl_header;
}; };
......
#ifndef _LINUX_SEG6_HMAC_H
#define _LINUX_SEG6_HMAC_H
#include <uapi/linux/seg6_hmac.h>
#endif
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <net/lwtunnel.h> #include <net/lwtunnel.h>
#include <linux/seg6.h> #include <linux/seg6.h>
#include <linux/rhashtable.h>
static inline void update_csum_diff4(struct sk_buff *skb, __be32 from, static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,
__be32 to) __be32 to)
...@@ -41,6 +42,9 @@ static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from, ...@@ -41,6 +42,9 @@ static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,
struct seg6_pernet_data { struct seg6_pernet_data {
struct mutex lock; struct mutex lock;
struct in6_addr __rcu *tun_src; struct in6_addr __rcu *tun_src;
#ifdef CONFIG_IPV6_SEG6_HMAC
struct rhashtable hmac_infos;
#endif
}; };
static inline struct seg6_pernet_data *seg6_pernet(struct net *net) static inline struct seg6_pernet_data *seg6_pernet(struct net *net)
......
/*
* SR-IPv6 implementation
*
* Author:
* David Lebrun <david.lebrun@uclouvain.be>
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef _NET_SEG6_HMAC_H
#define _NET_SEG6_HMAC_H
#include <net/flow.h>
#include <net/ip6_fib.h>
#include <net/sock.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/route.h>
#include <net/seg6.h>
#include <linux/seg6_hmac.h>
#include <linux/rhashtable.h>
#define SEG6_HMAC_MAX_DIGESTSIZE 160
#define SEG6_HMAC_RING_SIZE 256
struct seg6_hmac_info {
struct rhash_head node;
struct rcu_head rcu;
u32 hmackeyid;
char secret[SEG6_HMAC_SECRET_LEN];
u8 slen;
u8 alg_id;
};
struct seg6_hmac_algo {
u8 alg_id;
char name[64];
struct crypto_shash * __percpu *tfms;
struct shash_desc * __percpu *shashs;
};
extern int seg6_hmac_compute(struct seg6_hmac_info *hinfo,
struct ipv6_sr_hdr *hdr, struct in6_addr *saddr,
u8 *output);
extern struct seg6_hmac_info *seg6_hmac_info_lookup(struct net *net, u32 key);
extern int seg6_hmac_info_add(struct net *net, u32 key,
struct seg6_hmac_info *hinfo);
extern int seg6_hmac_info_del(struct net *net, u32 key);
extern int seg6_push_hmac(struct net *net, struct in6_addr *saddr,
struct ipv6_sr_hdr *srh);
extern bool seg6_hmac_validate_skb(struct sk_buff *skb);
extern int seg6_hmac_init(void);
extern void seg6_hmac_exit(void);
extern int seg6_hmac_net_init(struct net *net);
extern void seg6_hmac_net_exit(struct net *net);
#endif
...@@ -180,6 +180,7 @@ enum { ...@@ -180,6 +180,7 @@ enum {
DEVCONF_KEEP_ADDR_ON_DOWN, DEVCONF_KEEP_ADDR_ON_DOWN,
DEVCONF_RTR_SOLICIT_MAX_INTERVAL, DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
DEVCONF_SEG6_ENABLED, DEVCONF_SEG6_ENABLED,
DEVCONF_SEG6_REQUIRE_HMAC,
DEVCONF_MAX DEVCONF_MAX
}; };
......
#ifndef _UAPI_LINUX_SEG6_HMAC_H
#define _UAPI_LINUX_SEG6_HMAC_H
#include <linux/seg6.h>
#define SEG6_HMAC_SECRET_LEN 64
#define SEG6_HMAC_FIELD_LEN 32
struct sr6_tlv_hmac {
struct sr6_tlv tlvhdr;
__u16 reserved;
__be32 hmackeyid;
__u8 hmac[SEG6_HMAC_FIELD_LEN];
};
enum {
SEG6_HMAC_ALGO_SHA1 = 1,
SEG6_HMAC_ALGO_SHA256 = 2,
};
#endif
...@@ -301,4 +301,16 @@ config IPV6_SEG6_INLINE ...@@ -301,4 +301,16 @@ config IPV6_SEG6_INLINE
If unsure, say N. If unsure, say N.
config IPV6_SEG6_HMAC
bool "IPv6: Segment Routing HMAC support"
depends on IPV6
select CRYPTO_HMAC
select CRYPTO_SHA1
select CRYPTO_SHA256
---help---
Support for HMAC signature generation and verification
of SR-enabled packets.
If unsure, say N.
endif # IPV6 endif # IPV6
...@@ -44,6 +44,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o ...@@ -44,6 +44,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
obj-$(CONFIG_IPV6_GRE) += ip6_gre.o obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
obj-$(CONFIG_IPV6_FOU) += fou6.o obj-$(CONFIG_IPV6_FOU) += fou6.o
obj-$(CONFIG_IPV6_SEG6_HMAC) += seg6_hmac.o
obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o
obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
......
...@@ -239,6 +239,9 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { ...@@ -239,6 +239,9 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
.ignore_routes_with_linkdown = 0, .ignore_routes_with_linkdown = 0,
.keep_addr_on_down = 0, .keep_addr_on_down = 0,
.seg6_enabled = 0, .seg6_enabled = 0,
#ifdef CONFIG_IPV6_SEG6_HMAC
.seg6_require_hmac = 0,
#endif
}; };
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
...@@ -286,6 +289,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { ...@@ -286,6 +289,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
.ignore_routes_with_linkdown = 0, .ignore_routes_with_linkdown = 0,
.keep_addr_on_down = 0, .keep_addr_on_down = 0,
.seg6_enabled = 0, .seg6_enabled = 0,
#ifdef CONFIG_IPV6_SEG6_HMAC
.seg6_require_hmac = 0,
#endif
}; };
/* Check if a valid qdisc is available */ /* Check if a valid qdisc is available */
...@@ -4947,6 +4953,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, ...@@ -4947,6 +4953,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
array[DEVCONF_DROP_UNSOLICITED_NA] = cnf->drop_unsolicited_na; array[DEVCONF_DROP_UNSOLICITED_NA] = cnf->drop_unsolicited_na;
array[DEVCONF_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down; array[DEVCONF_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down;
array[DEVCONF_SEG6_ENABLED] = cnf->seg6_enabled; array[DEVCONF_SEG6_ENABLED] = cnf->seg6_enabled;
#ifdef CONFIG_IPV6_SEG6_HMAC
array[DEVCONF_SEG6_REQUIRE_HMAC] = cnf->seg6_require_hmac;
#endif
} }
static inline size_t inet6_ifla6_size(void) static inline size_t inet6_ifla6_size(void)
...@@ -6045,6 +6054,15 @@ static const struct ctl_table addrconf_sysctl[] = { ...@@ -6045,6 +6054,15 @@ static const struct ctl_table addrconf_sysctl[] = {
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec, .proc_handler = proc_dointvec,
}, },
#ifdef CONFIG_IPV6_SEG6_HMAC
{
.procname = "seg6_require_hmac",
.data = &ipv6_devconf.seg6_require_hmac,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
},
#endif
{ {
/* sentinel */ /* sentinel */
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment