**IPSec Implementation in Linux** | Reference | {{:mywiki:linux:chapter10_ipsec.pdf| ipsec_xfrm }} | ====== 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