Skip to content

Commit

Permalink
ipv6: sr: add core files for SR HMAC support
Browse files Browse the repository at this point in the history
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: David Lebrun <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
David Lebrun authored and davem330 committed Nov 10, 2016
1 parent 6c8702c commit bf355b8
Show file tree
Hide file tree
Showing 10 changed files with 612 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/linux/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ struct ipv6_devconf {
__s32 use_oif_addrs_only;
__s32 keep_addr_on_down;
__s32 seg6_enabled;
#ifdef CONFIG_IPV6_SEG6_HMAC
__s32 seg6_require_hmac;
#endif

struct ctl_table_header *sysctl_header;
};
Expand Down
6 changes: 6 additions & 0 deletions include/linux/seg6_hmac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef _LINUX_SEG6_HMAC_H
#define _LINUX_SEG6_HMAC_H

#include <uapi/linux/seg6_hmac.h>

#endif
4 changes: 4 additions & 0 deletions include/net/seg6.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/ipv6.h>
#include <net/lwtunnel.h>
#include <linux/seg6.h>
#include <linux/rhashtable.h>

static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,
__be32 to)
Expand All @@ -41,6 +42,9 @@ static inline void update_csum_diff16(struct sk_buff *skb, __be32 *from,
struct seg6_pernet_data {
struct mutex lock;
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)
Expand Down
62 changes: 62 additions & 0 deletions include/net/seg6_hmac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* SR-IPv6 implementation
*
* Author:
* David Lebrun <[email protected]>
*
*
* 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
1 change: 1 addition & 0 deletions include/uapi/linux/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ enum {
DEVCONF_KEEP_ADDR_ON_DOWN,
DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
DEVCONF_SEG6_ENABLED,
DEVCONF_SEG6_REQUIRE_HMAC,
DEVCONF_MAX
};

Expand Down
21 changes: 21 additions & 0 deletions include/uapi/linux/seg6_hmac.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#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
12 changes: 12 additions & 0 deletions net/ipv6/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -301,4 +301,16 @@ config IPV6_SEG6_INLINE

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
1 change: 1 addition & 0 deletions net/ipv6/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
obj-$(CONFIG_IPV6_GRE) += ip6_gre.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-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
Expand Down
18 changes: 18 additions & 0 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
.ignore_routes_with_linkdown = 0,
.keep_addr_on_down = 0,
.seg6_enabled = 0,
#ifdef CONFIG_IPV6_SEG6_HMAC
.seg6_require_hmac = 0,
#endif
};

static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
Expand Down Expand Up @@ -286,6 +289,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
.ignore_routes_with_linkdown = 0,
.keep_addr_on_down = 0,
.seg6_enabled = 0,
#ifdef CONFIG_IPV6_SEG6_HMAC
.seg6_require_hmac = 0,
#endif
};

/* Check if a valid qdisc is available */
Expand Down Expand Up @@ -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_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down;
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)
Expand Down Expand Up @@ -6045,6 +6054,15 @@ static const struct ctl_table addrconf_sysctl[] = {
.mode = 0644,
.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 */
}
Expand Down
Loading

0 comments on commit bf355b8

Please sign in to comment.