IPSec Implementation in Linux
IPSEC Basic
| Security Scheme | Difference |
| IPSEC | Security scheme operating in the Internet Layer of the Internet Protocol Suite |
| TLS/SSH | Security scheme operating in the upper layers of the TCP/IP model, like transport layer |
| IPSEC Protocol | Note |
| AH (Authentication Header) | provides source authentication & data integrity for IP datagrams. But it is not designed to provide confidentiality. |
| ESP(Encapsulating Security Payload) | provides source authentication, data integrity, and confidentiality. |
| IPSEC Mode | Protocol | Note |
| Transport | AH | only the payload of the IP packet is usually authenticated |
| ESP | only the payload of the IP packet is usually encrypted and/or authenticated |
| Tunnel Mode | AH | the entire IP packet is authenticated |
| ESP | the entire IP packet is encrypted and/or authenticated |
Terms
| SP(Security policy) | a rule which decides whether a given flow needs to go for IPSec processing or not |
| SA(Security Association) | a bundle of algorithms and parameters (such as keys) that is being used to encrypt and authenticate a particular flow in one direction. IPsec uses the Security Parameter Index (SPI: an index to the security association database - SADB), along with the destination address in a packet header, which together uniquely identify a security association for that packet. |
Limux Implementation
UserSpace communication via NETLINK_XFRM
| XFRM_MSG_NEWSA | To add a new SA to SAD |
| XFRM_MSG_DELSA | To delete a new SA to SAD |
| XFRM_MSG_GETSA | To get a new SA to SAD |
| XFRM_MSG_FLUSHSA | To flush SAD |
| XFRM_MSG_NEWPOLICY | To add a new policy to SPD |
| XFRM_MSG_DELPOLICY | To delete a new policy to SPD |
| XFRM_MSG_GETPOLICY | To get a new policy to SPD |
| XFRM_MSG_FLUSHPOLICY | To flush SPD |
IPSec framework in kernel
| ESP Protocol | net/ipv4/esp4.c, net/ipv6/esp6.c |
| AH Protocol | net/ipv4/ah4.c, net/ipv6/ah6.c |
| XFRM framework | net/ipv4/xfrm4_policy.c and net/ipv6/xfrm6_policy.c |
| XFRM initialization | xfrm4_init() and xfrm6_init(). |
Kernel Terms
| aalg | Authentication algo pointer | |
| ealg | Encryption algo pointer | |
| calg | Compression algo pointer | |
| aead | Authentication Encryption with Associated Data pointer | Note: if (aead == NULL); then only authentication without any encryption |
| encap | Data for encapsulator, ie, for special UDP Encapsulation only | draft-ietf-ipsec-udp-encaps-06 |
Kernel cryptography
| acrypto | asynchronous crypto |
| cryptd | |
| pcrypto | for multicore environment |
Algo: DES, 3DES, AES, RC5, IDEA, 3-IDEA, CAST, BLOWFISH etc…
two IPSec stacks:
| native netkey stack | syncronous |
| traditional KLIPS stack | asynchronous |
To start with, the core object of xfrm is the 'xfrm' member of 'struct net'. i.e each network namespace has got a separate xfrm object. This object will be reffered to access the hash tables (remeber hash tables :) ) of SPD and SAD. Also holds the state garbage collector (state_gc_work)
Data structures
The building block of SPD (Policy Database) is struct xfrm_policy.
/* ################################################# */
struct xfrm_policy {
#ifdef CONFIG_NET_NS
struct net *xp_net;
#endif
struct hlist_node bydst;
struct hlist_node byidx;
/* This lock only affects elements except for entry. */
rwlock_t lock;
atomic_t refcnt;
struct timer_list timer;
struct flow_cache_object flo;
atomic_t genid;
u32 priority;
u32 index;
struct xfrm_mark mark;
struct xfrm_selector selector;
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
struct xfrm_policy_walk_entry walk;
struct xfrm_policy_queue polq;
u8 type;
u8 action;
u8 flags;
u8 xfrm_nr;
u16 family;
struct xfrm_sec_ctx *security;
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
Important Fields:
- refcnt is to hold the reference to the policy.
- which embedded xfrm_selector object to hold the source and destination IP addresses, source and destination ports, protocol, interface index etc. xfrm_selector_match() API checks if the given packet matches with the XFRM selector.
- lft: is the policy lifetime
- timer: to handle the policy expiry
- polq: is a queue to push the packets when there are no states associated with this policy.
- action: this field decides the fate of the traffic. (XFRM_POLICY_ALLOW and XFRM_POLICY_BLOCK)
- family (v4 or v6, as mentioned this structure is common for all protocols)
The building block of SAD (Association Database) is struct xfrm_state
/* Full description of state of transformer. */
struct xfrm_state {
#ifdef CONFIG_NET_NS
struct net *xs_net;
#endif
union {
struct hlist_node gclist;
struct hlist_node bydst;
};
struct hlist_node bysrc;
struct hlist_node byspi;
atomic_t refcnt;
spinlock_t lock;
struct xfrm_id id;
struct xfrm_selector sel;
/* Key manager bits */
struct xfrm_state_walk km;
/* Parameters of this state. */
struct {
u32 reqid;
u8 mode;
u8 replay_window;
u8 aalgo, ealgo, calgo;
u8 flags;
u16 family;
xfrm_address_t saddr;
int header_len;
int trailer_len;
u32 extra_flags;
} props;
struct xfrm_lifetime_cfg lft;
/* Data for transformer */
struct xfrm_algo_auth *aalg;
struct xfrm_algo *ealg;
struct xfrm_algo *calg;
struct xfrm_algo_aead *aead;
/* Data for encapsulator */
struct xfrm_encap_tmpl *encap;
--------------
-------------------
/* data for replay detection */
struct xfrm_replay_state replay;
struct xfrm_replay_state_esn *replay_esn;
struct xfrm_replay_state preplay;
struct xfrm_replay_state_esn *preplay_esn;
struct xfrm_replay *repl;
u32 replay_maxage;
u32 replay_maxdiff;
struct timer_list rtimer;
/* Statistics */
struct xfrm_stats stats;
struct xfrm_lifetime_cur curlft;
struct tasklet_hrtimer mtimer;
/* Last used time */
unsigned long lastused;
---------------------------
----------------------------
/* Private data of this transformer, format is opaque,
* interpreted by xfrm_type methods. */
void *data;
}
IPSec kernel APIs
| Xfrm_lookup() | xfrm lookup(SPD and SAD) method |
| Xfrm_input() | xfrm processing for an ingress packet |
| Xfrm_output() | xfrm processing for an egress packet |
| Xfrm4_rcv() | IPv4 specific Rx method |
| Xfrm6_rcv() | IPv6 specific Rx method |
| Esp_input() | ESP processing for an ingress packet |
| Esp_output() | ESP processing for an egress packet |
| Ah_input() | AH processing for an ingress packet |
| Ah_output() | AH processing for an egress packet |
| xfrm_policy_alloc() | allocates an SPD object |
| Xfrm_policy_destroy() | frees an SPD object |
| xfrm_ policy_lookup | SPD lookup |
| xfrm_policy_byid() | SPD lookup based on id |
| Xfrm_policy_insert() | Add an entry to SPD |
| Xfrm_Policy_delete() | remove an entry from SPD |
| Xfrm_bundle_create() | creates a xfrm bundle |
| Xfrm_policy_delete() | releases the resources of a policy object |
| Xfrm_state_add() | add an entry to SAD |
| Xfrm_state_delete() | free and SAD object |
| xfrm_state_alloc() | allocate an SAD object |
| xfrm_state_lookup_byaddr() | src address based SAD lookup |
| xfrm_state_find() | SAD look up based on dst |
| xfrm_state_lookup() | SAD lookup based on spi |
IPSec SA initialize
It is initialized by API: static int esp_init_state(struct xfrm_state *x), which is defined in file:
net/ipv4/esp4.c
net/ipv6/esp6.c
IPSec Tx steps
For better understanding I have divided the IPSec transmission process in 7 stepes as below
Step-1: Transport_layer_sendmsg()
Does TCP/UDP specific jobs are done here before going for route lookup
Step-2: ip_route_output_slow()
Xfrm_lookup()
Step-3: ip_local_output()
Step-4: ip_local_out()
LOCAL_OUT netfilter applies here.
Calls skb->dst->output(), which is xfrm4_output in case of ipv4 and xfrm6_output in the case of ipv6
Step-5: xfrm4_output/xfrm6_output
Step-6: esp_output()/ah_output()
Step-7: ip_output()
Step-8: dev_queue_xmit()
Egress QoS comes here.
Step-9: dev->ndo_start_xmit()
IPSec Rx steps
For better understanding I have divided the IPSec reception process in 7 stepes, they are below
Step-1: netif_receive_skb()
Step-2: ip_rcv()
Netfilter PRE_ROUTING applies here.
Step-3: ip_receive_finish
Calls ip_route_input_noref(). Which finds the route entry and set dst->output for local delivery, forwarding etc. But IPSec applies on the end systems ONLY. So we bothr if it is set for local delivery
Step-4: ip_local_deliver
LOCAL_IN Netfilter part here.
Step-5: ip_local_deliver_finish()
Based on the protocol field of ip header (IPPROTO_AH, IPPROTO_ESP), packet will be given to xfrm4_rcv() function
Step-6: xfrm4_rcv()
Step-7: xfrm_input()
Calls xfrm_state_lookup()
calls esp_input()/ah_input()
Once again applies the PRE_ROUTING Netfilter, but now for the decapsulated packet
Step-8: xfrm4_rcv_encap_finish()
Will do the route lookup again for the decapsulated packet using ip_route_input_noref(). Again route lookup should decide for local_delivery.
Step-9: ip_local_delivery()
again the LOCAL_IN Netfilter for decapsulated packet
now the protocol field will be TCP/UDP and the packet flows in the native reception methods of TCP/UDP and delivers to the socket
Step-10: transport_layer_rcvmsg()
-to userspace