diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/kernel/kernel_interface.c | 13 | ||||
-rw-r--r-- | src/charon/kernel/kernel_interface.h | 12 | ||||
-rw-r--r-- | src/charon/kernel/kernel_ipsec.h | 12 | ||||
-rw-r--r-- | src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c | 164 | ||||
-rw-r--r-- | src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 127 | ||||
-rw-r--r-- | src/charon/sa/child_sa.c | 125 | ||||
-rw-r--r-- | src/charon/sa/ike_sa.c | 20 |
7 files changed, 263 insertions, 210 deletions
diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c index e2d508dc1..f71e3c5b0 100644 --- a/src/charon/kernel/kernel_interface.c +++ b/src/charon/kernel/kernel_interface.c @@ -85,14 +85,13 @@ static status_t get_cpi(private_kernel_interface_t *this, host_t *src, host_t *d static status_t add_sa(private_kernel_interface_t *this, host_t *src, host_t *dst, u_int32_t spi, protocol_id_t protocol, u_int32_t reqid, u_int64_t expire_soft, u_int64_t expire_hard, - u_int16_t enc_alg, u_int16_t enc_size, - u_int16_t int_alg, u_int16_t int_size, - prf_plus_t *prf_plus, ipsec_mode_t mode, u_int16_t ipcomp, bool encap, - bool update) + u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, + ipsec_mode_t mode, u_int16_t ipcomp, bool encap, bool update) { return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid, - expire_soft, expire_hard, enc_alg, enc_size, int_alg, int_size, - prf_plus, mode, ipcomp, encap, update); + expire_soft, expire_hard, enc_alg, enc_key, int_alg, int_key, + mode, ipcomp, encap, update); } /** @@ -371,7 +370,7 @@ kernel_interface_t *kernel_interface_create() this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi; this->public.get_cpi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi; - this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,u_int16_t,u_int16_t,u_int16_t,prf_plus_t*,ipsec_mode_t,u_int16_t,bool,bool))add_sa; + this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,bool,bool))add_sa; this->public.update_sa = (status_t(*)(kernel_interface_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa; this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa; this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,ipsec_mode_t,u_int16_t))add_policy; diff --git a/src/charon/kernel/kernel_interface.h b/src/charon/kernel/kernel_interface.h index a2a83b608..aec492424 100644 --- a/src/charon/kernel/kernel_interface.h +++ b/src/charon/kernel/kernel_interface.h @@ -101,10 +101,9 @@ struct kernel_interface_t { * @param expire_soft lifetime in seconds before rekeying * @param expire_hard lifetime in seconds before delete * @param enc_alg Algorithm to use for encryption (ESP only) - * @param enc_size key length of encryption algorithm, if dynamic + * @param enc_key key to use for encryption * @param int_alg Algorithm to use for integrity protection - * @param int_size key length of integrity algorithm, if dynamic - * @param prf_plus PRF to derive keys from + * @param int_key key to use for integrity protection * @param mode mode of the SA (tunnel, transport) * @param ipcomp IPComp transform to use * @param encap enable UDP encapsulation for NAT traversal @@ -115,10 +114,9 @@ struct kernel_interface_t { host_t *src, host_t *dst, u_int32_t spi, protocol_id_t protocol, u_int32_t reqid, u_int64_t expire_soft, u_int64_t expire_hard, - u_int16_t enc_alg, u_int16_t enc_size, - u_int16_t int_alg, u_int16_t int_size, - prf_plus_t *prf_plus, ipsec_mode_t mode, - u_int16_t ipcomp, bool encap, + u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, + ipsec_mode_t mode, u_int16_t ipcomp, bool encap, bool update); /** diff --git a/src/charon/kernel/kernel_ipsec.h b/src/charon/kernel/kernel_ipsec.h index 8fa5fb006..bef496a88 100644 --- a/src/charon/kernel/kernel_ipsec.h +++ b/src/charon/kernel/kernel_ipsec.h @@ -133,10 +133,9 @@ struct kernel_ipsec_t { * @param expire_soft lifetime in seconds before rekeying * @param expire_hard lifetime in seconds before delete * @param enc_alg Algorithm to use for encryption (ESP only) - * @param enc_size key length of encryption algorithm, if dynamic + * @param enc_key key to use for encryption * @param int_alg Algorithm to use for integrity protection - * @param int_size key length of integrity algorithm, if dynamic - * @param prf_plus PRF to derive keys from + * @param int_key key to use for integrity protection * @param mode mode of the SA (tunnel, transport) * @param ipcomp IPComp transform to use * @param encap enable UDP encapsulation for NAT traversal @@ -147,10 +146,9 @@ struct kernel_ipsec_t { host_t *src, host_t *dst, u_int32_t spi, protocol_id_t protocol, u_int32_t reqid, u_int64_t expire_soft, u_int64_t expire_hard, - u_int16_t enc_alg, u_int16_t enc_size, - u_int16_t int_alg, u_int16_t int_size, - prf_plus_t *prf_plus, ipsec_mode_t mode, - u_int16_t ipcomp, bool encap, + u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, + ipsec_mode_t mode, u_int16_t ipcomp, bool encap, bool update); /** diff --git a/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 7fb6a260f..1b526e6f0 100644 --- a/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2006-2008 Tobias Brunner - * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -76,24 +76,18 @@ typedef struct kernel_algorithm_t kernel_algorithm_t; /** - * Mapping from the algorithms defined in IKEv2 to - * kernel level algorithm names and their key length + * Mapping of IKEv2 kernel identifier to linux crypto API names */ struct kernel_algorithm_t { /** * Identifier specified in IKEv2 */ - int ikev2_id; + int ikev2; /** - * Name of the algorithm, as used as kernel identifier + * Name of the algorithm in linux crypto API */ char *name; - - /** - * Key length in bits, if fixed size - */ - u_int key_size; }; #define END_OF_LIST -1 @@ -102,71 +96,65 @@ struct kernel_algorithm_t { * Algorithms for encryption */ static kernel_algorithm_t encryption_algs[] = { -/* {ENCR_DES_IV64, "***", 0}, */ - {ENCR_DES, "des", 64}, - {ENCR_3DES, "des3_ede", 192}, -/* {ENCR_RC5, "***", 0}, */ -/* {ENCR_IDEA, "***", 0}, */ - {ENCR_CAST, "cast128", 0}, - {ENCR_BLOWFISH, "blowfish", 0}, -/* {ENCR_3IDEA, "***", 0}, */ -/* {ENCR_DES_IV32, "***", 0}, */ - {ENCR_NULL, "cipher_null", 0}, - {ENCR_AES_CBC, "aes", 0}, -/* {ENCR_AES_CTR, "***", 0}, */ - {ENCR_AES_CCM_ICV8, "rfc4309(ccm(aes))", 64}, /* key_size = ICV size */ - {ENCR_AES_CCM_ICV12, "rfc4309(ccm(aes))", 96}, /* key_size = ICV size */ - {ENCR_AES_CCM_ICV16, "rfc4309(ccm(aes))", 128}, /* key_size = ICV size */ - {ENCR_AES_GCM_ICV8, "rfc4106(gcm(aes))", 64}, /* key_size = ICV size */ - {ENCR_AES_GCM_ICV12, "rfc4106(gcm(aes))", 96}, /* key_size = ICV size */ - {ENCR_AES_GCM_ICV16, "rfc4106(gcm(aes))", 128}, /* key_size = ICV size */ - {END_OF_LIST, NULL, 0}, +/* {ENCR_DES_IV64, "***" }, */ + {ENCR_DES, "des" }, + {ENCR_3DES, "des3_ede" }, +/* {ENCR_RC5, "***" }, */ +/* {ENCR_IDEA, "***" }, */ + {ENCR_CAST, "cast128" }, + {ENCR_BLOWFISH, "blowfish" }, +/* {ENCR_3IDEA, "***" }, */ +/* {ENCR_DES_IV32, "***" }, */ + {ENCR_NULL, "cipher_null" }, + {ENCR_AES_CBC, "aes" }, +/* {ENCR_AES_CTR, "***" }, */ + {ENCR_AES_CCM_ICV8, "rfc4309(ccm(aes))" }, + {ENCR_AES_CCM_ICV12, "rfc4309(ccm(aes))" }, + {ENCR_AES_CCM_ICV16, "rfc4309(ccm(aes))" }, + {ENCR_AES_GCM_ICV8, "rfc4106(gcm(aes))" }, + {ENCR_AES_GCM_ICV12, "rfc4106(gcm(aes))" }, + {ENCR_AES_GCM_ICV16, "rfc4106(gcm(aes))" }, + {END_OF_LIST, NULL }, }; /** * Algorithms for integrity protection */ static kernel_algorithm_t integrity_algs[] = { - {AUTH_HMAC_MD5_96, "md5", 128}, - {AUTH_HMAC_SHA1_96, "sha1", 160}, - {AUTH_HMAC_SHA2_256_128, "sha256", 256}, - {AUTH_HMAC_SHA2_384_192, "sha384", 384}, - {AUTH_HMAC_SHA2_512_256, "sha512", 512}, -/* {AUTH_DES_MAC, "***", 0}, */ -/* {AUTH_KPDK_MD5, "***", 0}, */ - {AUTH_AES_XCBC_96, "xcbc(aes)", 128}, - {END_OF_LIST, NULL, 0}, + {AUTH_HMAC_MD5_96, "md5" }, + {AUTH_HMAC_SHA1_96, "sha1" }, + {AUTH_HMAC_SHA2_256_128, "sha256" }, + {AUTH_HMAC_SHA2_384_192, "sha384" }, + {AUTH_HMAC_SHA2_512_256, "sha512" }, +/* {AUTH_DES_MAC, "***" }, */ +/* {AUTH_KPDK_MD5, "***" }, */ + {AUTH_AES_XCBC_96, "xcbc(aes)" }, + {END_OF_LIST, NULL }, }; /** * Algorithms for IPComp */ static kernel_algorithm_t compression_algs[] = { -/* {IPCOMP_OUI, "***", 0}, */ - {IPCOMP_DEFLATE, "deflate", 0}, - {IPCOMP_LZS, "lzs", 0}, - {IPCOMP_LZJH, "lzjh", 0}, - {END_OF_LIST, NULL, 0}, +/* {IPCOMP_OUI, "***" }, */ + {IPCOMP_DEFLATE, "deflate" }, + {IPCOMP_LZS, "lzs" }, + {IPCOMP_LZJH, "lzjh" }, + {END_OF_LIST, NULL }, }; /** * Look up a kernel algorithm name and its key size */ -static char* lookup_algorithm(kernel_algorithm_t *kernel_algo, - u_int16_t ikev2_algo, u_int16_t *key_size) +static char* lookup_algorithm(kernel_algorithm_t *list, int ikev2) { - while (kernel_algo->ikev2_id != END_OF_LIST) + while (list->ikev2 != END_OF_LIST) { - if (ikev2_algo == kernel_algo->ikev2_id) + if (list->ikev2 == ikev2) { - /* match, evaluate key length */ - if (key_size && *key_size == 0) - { /* update key size if not set */ - *key_size = kernel_algo->key_size; - } - return kernel_algo->name; + return list->name; } - kernel_algo++; + list++; } return NULL; } @@ -688,23 +676,22 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst, u_int32_t spi, protocol_id_t protocol, u_int32_t reqid, u_int64_t expire_soft, u_int64_t expire_hard, - u_int16_t enc_alg, u_int16_t enc_size, - u_int16_t int_alg, u_int16_t int_size, - prf_plus_t *prf_plus, ipsec_mode_t mode, - u_int16_t ipcomp, bool encap, + u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, + ipsec_mode_t mode, u_int16_t ipcomp, bool encap, bool replace) { unsigned char request[NETLINK_BUFFER_SIZE]; char *alg_name; - /* additional 4 octets KEYMAT required for AES-GCM as of RFC4106 8.1. */ - u_int16_t add_keymat = 32; struct nlmsghdr *hdr; struct xfrm_usersa_info *sa; + u_int16_t icv_size = 64; memset(&request, 0, sizeof(request)); - DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%d}", ntohl(spi), reqid); - + DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%d}", + ntohl(spi), reqid); + hdr = (struct nlmsghdr*)request; hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; hdr->nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; @@ -741,19 +728,19 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, case ENCR_UNDEFINED: /* no encryption */ break; - case ENCR_AES_CCM_ICV8: - case ENCR_AES_CCM_ICV12: case ENCR_AES_CCM_ICV16: - /* AES-CCM needs only 3 additional octets KEYMAT as of RFC 4309 7.1. */ - add_keymat = 24; - /* fall-through */ - case ENCR_AES_GCM_ICV8: - case ENCR_AES_GCM_ICV12: case ENCR_AES_GCM_ICV16: + icv_size += 32; + /* FALL */ + case ENCR_AES_CCM_ICV12: + case ENCR_AES_GCM_ICV12: + icv_size += 32; + /* FALL */ + case ENCR_AES_CCM_ICV8: + case ENCR_AES_GCM_ICV8: { - u_int16_t icv_size = 0; rthdr->rta_type = XFRMA_ALG_AEAD; - alg_name = lookup_algorithm(encryption_algs, enc_alg, &icv_size); + alg_name = lookup_algorithm(encryption_algs, enc_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", @@ -761,12 +748,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, return FAILED; } DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", - encryption_algorithm_names, enc_alg, enc_size); - - /* additional KEYMAT required */ - enc_size += add_keymat; + encryption_algorithm_names, enc_alg, enc_key.len * 8); - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_size / 8); + rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo_aead) + enc_key.len); hdr->nlmsg_len += rthdr->rta_len; if (hdr->nlmsg_len > sizeof(request)) { @@ -774,10 +758,10 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, } struct xfrm_algo_aead* algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr); - algo->alg_key_len = enc_size; + algo->alg_key_len = enc_key.len * 8; algo->alg_icv_len = icv_size; strcpy(algo->alg_name, alg_name); - prf_plus->get_bytes(prf_plus, enc_size / 8, algo->alg_key); + memcpy(algo->alg_key, enc_key.ptr, enc_key.len); rthdr = XFRM_RTA_NEXT(rthdr); break; @@ -785,7 +769,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, default: { rthdr->rta_type = XFRMA_ALG_CRYPT; - alg_name = lookup_algorithm(encryption_algs, enc_alg, &enc_size); + alg_name = lookup_algorithm(encryption_algs, enc_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", @@ -793,9 +777,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, return FAILED; } DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", - encryption_algorithm_names, enc_alg, enc_size); + encryption_algorithm_names, enc_alg, enc_key.len * 8); - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_size / 8); + rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + enc_key.len); hdr->nlmsg_len += rthdr->rta_len; if (hdr->nlmsg_len > sizeof(request)) { @@ -803,9 +787,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, } struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); - algo->alg_key_len = enc_size; + algo->alg_key_len = enc_key.len * 8; strcpy(algo->alg_name, alg_name); - prf_plus->get_bytes(prf_plus, enc_size / 8, algo->alg_key); + memcpy(algo->alg_key, enc_key.ptr, enc_key.len); rthdr = XFRM_RTA_NEXT(rthdr); break; @@ -815,7 +799,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, if (int_alg != AUTH_UNDEFINED) { rthdr->rta_type = XFRMA_ALG_AUTH; - alg_name = lookup_algorithm(integrity_algs, int_alg, &int_size); + alg_name = lookup_algorithm(integrity_algs, int_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", @@ -823,9 +807,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, return FAILED; } DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", - integrity_algorithm_names, int_alg, int_size); + integrity_algorithm_names, int_alg, int_key.len * 8); - rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_size / 8); + rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_algo) + int_key.len); hdr->nlmsg_len += rthdr->rta_len; if (hdr->nlmsg_len > sizeof(request)) { @@ -833,9 +817,9 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, } struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); - algo->alg_key_len = int_size; + algo->alg_key_len = int_key.len * 8; strcpy(algo->alg_name, alg_name); - prf_plus->get_bytes(prf_plus, int_size / 8, algo->alg_key); + memcpy(algo->alg_key, int_key.ptr, int_key.len); rthdr = XFRM_RTA_NEXT(rthdr); } @@ -843,7 +827,7 @@ static status_t add_sa(private_kernel_netlink_ipsec_t *this, if (ipcomp != IPCOMP_NONE) { rthdr->rta_type = XFRMA_ALG_COMP; - alg_name = lookup_algorithm(compression_algs, ipcomp, NULL); + alg_name = lookup_algorithm(compression_algs, ipcomp); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", @@ -1559,7 +1543,7 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() /* public functions */ this->public.interface.get_spi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi; this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi; - this->public.interface.add_sa = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,u_int16_t,u_int16_t,u_int16_t,prf_plus_t*,ipsec_mode_t,u_int16_t,bool,bool))add_sa; + this->public.interface.add_sa = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,bool,bool))add_sa; this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa; this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,u_int32_t,protocol_id_t))del_sa; this->public.interface.add_policy = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,ipsec_mode_t,u_int16_t))add_policy; diff --git a/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index dec43e259..50d6322a8 100644 --- a/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/charon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -384,24 +384,18 @@ static u_int8_t dir2kernel(policy_dir_t dir) typedef struct kernel_algorithm_t kernel_algorithm_t; /** - * Mapping from the algorithms defined in IKEv2 to - * kernel level algorithm identifiers and their key length + * Mapping of IKEv2 algorithms to PF_KEY algorithms */ struct kernel_algorithm_t { /** * Identifier specified in IKEv2 */ - int ikev2_id; + int ikev2; /** * Identifier as defined in pfkeyv2.h */ - int kernel_id; - - /** - * Key length in bits, if fixed size - */ - u_int key_size; + int kernel; }; #define END_OF_LIST -1 @@ -410,71 +404,65 @@ struct kernel_algorithm_t { * Algorithms for encryption */ static kernel_algorithm_t encryption_algs[] = { -/* {ENCR_DES_IV64, 0, 0}, */ - {ENCR_DES, SADB_EALG_DESCBC, 64}, - {ENCR_3DES, SADB_EALG_3DESCBC, 192}, -/* {ENCR_RC5, 0, 0}, */ -/* {ENCR_IDEA, 0, 0}, */ - {ENCR_CAST, SADB_X_EALG_CASTCBC, 0}, - {ENCR_BLOWFISH, SADB_X_EALG_BLOWFISHCBC, 0}, -/* {ENCR_3IDEA, 0, 0}, */ -/* {ENCR_DES_IV32, 0, 0}, */ - {ENCR_NULL, SADB_EALG_NULL, 0}, - {ENCR_AES_CBC, SADB_X_EALG_AESCBC, 0}, -/* {ENCR_AES_CTR, 0, 0}, */ -/* {ENCR_AES_CCM_ICV8, 0, 64}, */ /* key_size = ICV size */ -/* {ENCR_AES_CCM_ICV12, 0, 96}, */ /* key_size = ICV size */ -/* {ENCR_AES_CCM_ICV16, 0, 128},*/ /* key_size = ICV size */ -/* {ENCR_AES_GCM_ICV8, 0, 64}, */ /* key_size = ICV size */ -/* {ENCR_AES_GCM_ICV12, 0, 96}, */ /* key_size = ICV size */ -/* {ENCR_AES_GCM_ICV16, 0, 128},*/ /* key_size = ICV size */ - {END_OF_LIST, 0, 0}, +/* {ENCR_DES_IV64, 0 }, */ + {ENCR_DES, SADB_EALG_DESCBC }, + {ENCR_3DES, SADB_EALG_3DESCBC }, +/* {ENCR_RC5, 0 }, */ +/* {ENCR_IDEA, 0 }, */ + {ENCR_CAST, SADB_X_EALG_CASTCBC }, + {ENCR_BLOWFISH, SADB_X_EALG_BLOWFISHCBC }, +/* {ENCR_3IDEA, 0 }, */ +/* {ENCR_DES_IV32, 0 }, */ + {ENCR_NULL, SADB_EALG_NULL }, + {ENCR_AES_CBC, SADB_X_EALG_AESCBC }, +/* {ENCR_AES_CTR, 0 }, */ +/* {ENCR_AES_CCM_ICV8, 0 }, */ +/* {ENCR_AES_CCM_ICV12, 0 }, */ +/* {ENCR_AES_CCM_ICV16, 0 }, */ +/* {ENCR_AES_GCM_ICV8, 0 }, */ +/* {ENCR_AES_GCM_ICV12, 0 }, */ +/* {ENCR_AES_GCM_ICV16, 0 }, */ + {END_OF_LIST, 0 }, }; /** * Algorithms for integrity protection */ static kernel_algorithm_t integrity_algs[] = { - {AUTH_HMAC_MD5_96, SADB_AALG_MD5HMAC, 128}, - {AUTH_HMAC_SHA1_96, SADB_AALG_SHA1HMAC, 160}, - {AUTH_HMAC_SHA2_256_128, SADB_X_AALG_SHA2_256HMAC, 256}, - {AUTH_HMAC_SHA2_384_192, SADB_X_AALG_SHA2_384HMAC, 384}, - {AUTH_HMAC_SHA2_512_256, SADB_X_AALG_SHA2_512HMAC, 512}, -/* {AUTH_DES_MAC, 0, 0}, */ -/* {AUTH_KPDK_MD5, 0, 0}, */ - {AUTH_AES_XCBC_96, SADB_X_AALG_AES_XCBC_MAC, 128}, - {END_OF_LIST, 0, 0}, + {AUTH_HMAC_MD5_96, SADB_AALG_MD5HMAC }, + {AUTH_HMAC_SHA1_96, SADB_AALG_SHA1HMAC }, + {AUTH_HMAC_SHA2_256_128, SADB_X_AALG_SHA2_256HMAC }, + {AUTH_HMAC_SHA2_384_192, SADB_X_AALG_SHA2_384HMAC }, + {AUTH_HMAC_SHA2_512_256, SADB_X_AALG_SHA2_512HMAC }, +/* {AUTH_DES_MAC, 0, }, */ +/* {AUTH_KPDK_MD5, 0, }, */ + {AUTH_AES_XCBC_96, SADB_X_AALG_AES_XCBC_MAC, }, + {END_OF_LIST, 0, }, }; /** * Algorithms for IPComp */ static kernel_algorithm_t compression_algs[] = { -/* {IPCOMP_OUI, 0, 0}, */ - {IPCOMP_DEFLATE, SADB_X_CALG_DEFLATE, 0}, - {IPCOMP_LZS, SADB_X_CALG_LZS, 0}, - {IPCOMP_LZJH, SADB_X_CALG_LZJH, 0}, - {END_OF_LIST, 0, 0}, +/* {IPCOMP_OUI, 0 }, */ + {IPCOMP_DEFLATE, SADB_X_CALG_DEFLATE }, + {IPCOMP_LZS, SADB_X_CALG_LZS }, + {IPCOMP_LZJH, SADB_X_CALG_LZJH }, + {END_OF_LIST, 0 }, }; /** * Look up a kernel algorithm ID and its key size */ -static int lookup_algorithm(kernel_algorithm_t *kernel_algo, - u_int16_t ikev2_algo, u_int16_t *key_size) +static int lookup_algorithm(kernel_algorithm_t *list, int ikev2) { - while (kernel_algo->ikev2_id != END_OF_LIST) + while (list->ikev2 != END_OF_LIST) { - if (ikev2_algo == kernel_algo->ikev2_id) + if (ikev2 == list->ikev2) { - /* match, evaluate key length */ - if (key_size && *key_size == 0) - { /* update key size if not set */ - *key_size = kernel_algo->key_size; - } - return kernel_algo->kernel_id; + return list->kernel; } - kernel_algo++; + list++; } return 0; } @@ -977,10 +965,9 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst, u_int32_t spi, protocol_id_t protocol, u_int32_t reqid, u_int64_t expire_soft, u_int64_t expire_hard, - u_int16_t enc_alg, u_int16_t enc_size, - u_int16_t int_alg, u_int16_t int_size, - prf_plus_t *prf_plus, ipsec_mode_t mode, - u_int16_t ipcomp, bool encap, + u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, + ipsec_mode_t mode, u_int16_t ipcomp, bool encap, bool replace) { unsigned char request[PFKEY_BUFFER_SIZE]; @@ -1007,10 +994,8 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this, sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa)); sa->sadb_sa_spi = spi; sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32; - sa->sadb_sa_auth = lookup_algorithm(integrity_algs, - int_alg, &int_size); - sa->sadb_sa_encrypt = lookup_algorithm(encryption_algs, - enc_alg, &enc_size); + sa->sadb_sa_auth = lookup_algorithm(integrity_algs, int_alg); + sa->sadb_sa_encrypt = lookup_algorithm(encryption_algs, enc_alg); PFKEY_EXT_ADD(msg, sa); sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg); @@ -1047,17 +1032,17 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this, if (!sa->sadb_sa_encrypt) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", - encryption_algorithm_names, enc_alg); + encryption_algorithm_names, enc_alg); return FAILED; } DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", - encryption_algorithm_names, enc_alg, enc_size); + encryption_algorithm_names, enc_alg, enc_key.len * 8); key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg); key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; - key->sadb_key_bits = enc_size; - key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + enc_size / 8); - prf_plus->get_bytes(prf_plus, enc_size / 8, (void*)(key + 1)); + key->sadb_key_bits = enc_key.len * 8; + key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + enc_key.len); + memcpy(key + 1, enc_key.ptr, enc_key.len); PFKEY_EXT_ADD(msg, key); } @@ -1071,13 +1056,13 @@ static status_t add_sa(private_kernel_pfkey_ipsec_t *this, return FAILED; } DBG2(DBG_KNL, " using integrity algorithm %N with key size %d", - integrity_algorithm_names, int_alg, int_size); + integrity_algorithm_names, int_alg, int_key.len * 8); key = (struct sadb_key*)PFKEY_EXT_ADD_NEXT(msg); key->sadb_key_exttype = SADB_EXT_KEY_AUTH; - key->sadb_key_bits = int_size; - key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + int_size / 8); - prf_plus->get_bytes(prf_plus, int_size / 8, (void*)(key + 1)); + key->sadb_key_bits = int_key.len * 8; + key->sadb_key_len = PFKEY_LEN(sizeof(struct sadb_key) + int_key.len); + memcpy(key + 1, int_key.ptr, int_key.len); PFKEY_EXT_ADD(msg, key); } @@ -1765,7 +1750,7 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create() /* public functions */ this->public.interface.get_spi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi; this->public.interface.get_cpi = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,u_int32_t,u_int16_t*))get_cpi; - this->public.interface.add_sa = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,u_int16_t,u_int16_t,u_int16_t,prf_plus_t*,ipsec_mode_t,u_int16_t,bool,bool))add_sa; + this->public.interface.add_sa = (status_t(*)(kernel_ipsec_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,u_int16_t,chunk_t,u_int16_t,chunk_t,ipsec_mode_t,u_int16_t,bool,bool))add_sa; this->public.interface.update_sa = (status_t(*)(kernel_ipsec_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa; this->public.interface.del_sa = (status_t(*)(kernel_ipsec_t*,host_t*,u_int32_t,protocol_id_t))del_sa; this->public.interface.add_policy = (status_t(*)(kernel_ipsec_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,ipsec_mode_t,u_int16_t))add_policy; diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index 2dc2ec5ed..4b56d5571 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -182,6 +182,58 @@ struct private_child_sa_t { char *iface; }; +typedef struct keylen_entry_t keylen_entry_t; + +/** + * Implicit key length for an algorithm + */ +struct keylen_entry_t { + /** IKEv2 algorithm identifier */ + int algo; + /** key length in bits */ + int len; +}; + +#define END_OF_LIST -1 + +/** + * Keylen for encryption algos + */ +keylen_entry_t keylen_enc[] = { + {ENCR_DES, 64}, + {ENCR_3DES, 192}, + {END_OF_LIST, 0} +}; + +/** + * Keylen for integrity algos + */ +keylen_entry_t keylen_int[] = { + {AUTH_HMAC_MD5_96, 128}, + {AUTH_HMAC_SHA1_96, 160}, + {AUTH_HMAC_SHA2_256_128, 256}, + {AUTH_HMAC_SHA2_384_192, 384}, + {AUTH_HMAC_SHA2_512_256, 512}, + {AUTH_AES_XCBC_96, 128}, + {END_OF_LIST, 0} +}; + +/** + * Lookup key length of an algorithm + */ +static int lookup_keylen(keylen_entry_t *list, int algo) +{ + while (list->algo != END_OF_LIST) + { + if (algo == list->algo) + { + return list->len; + } + list++; + } + return 0; +} + /** * Implementation of child_sa_t.get_name. */ @@ -530,10 +582,11 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals) static status_t install(private_child_sa_t *this, proposal_t *proposal, ipsec_mode_t mode, prf_plus_t *prf_plus, bool mine) { - u_int32_t spi, soft, hard; - host_t *src; - host_t *dst; + u_int32_t spi, cpi, soft, hard; + host_t *src, *dst; status_t status; + chunk_t enc_key = chunk_empty, int_key = chunk_empty; + int add_keymat; this->protocol = proposal->get_protocol(proposal); @@ -549,8 +602,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, this->me.spi = this->alloc_esp_spi; if (this->alloc_ah_spi) { - charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr, - this->alloc_ah_spi, PROTO_AH); + charon->kernel_interface->del_sa(charon->kernel_interface, + this->me.addr, this->alloc_ah_spi, PROTO_AH); } } else @@ -558,8 +611,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, this->me.spi = this->alloc_ah_spi; if (this->alloc_esp_spi) { - charon->kernel_interface->del_sa(charon->kernel_interface, this->me.addr, - this->alloc_esp_spi, PROTO_ESP); + charon->kernel_interface->del_sa(charon->kernel_interface, + this->me.addr, this->alloc_esp_spi, PROTO_ESP); } } spi = this->me.spi; @@ -577,23 +630,55 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, DBG2(DBG_CHD, "adding %s %N SA", mine ? "inbound" : "outbound", protocol_id_names, this->protocol); - /* select encryption algo */ + /* select encryption algo, derive key */ if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &this->enc_alg, &this->enc_size)) { DBG2(DBG_CHD, " using %N for encryption", encryption_algorithm_names, this->enc_alg); } + if (!this->enc_size) + { + this->enc_size = lookup_keylen(keylen_enc, this->enc_alg); + } + if (this->enc_size && this->enc_alg != ENCR_UNDEFINED) + { + /* CCM/GCM needs additional keymat */ + switch (this->enc_alg) + { + case ENCR_AES_CCM_ICV8: + case ENCR_AES_CCM_ICV12: + case ENCR_AES_CCM_ICV16: + add_keymat = 3; + break; + case ENCR_AES_GCM_ICV8: + case ENCR_AES_GCM_ICV12: + case ENCR_AES_GCM_ICV16: + add_keymat = 4; + break; + default: + add_keymat = 0; + break; + } + prf_plus->allocate_bytes(prf_plus, this->enc_size / 8 + add_keymat, + &enc_key); + } - /* select integrity algo */ + /* select integrity algo, derive key */ if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &this->int_alg, &this->int_size)) { DBG2(DBG_CHD, " using %N for integrity", integrity_algorithm_names, this->int_alg); } - soft = this->config->get_lifetime(this->config, TRUE); - hard = this->config->get_lifetime(this->config, FALSE); + if (!this->int_size) + { + this->int_size = lookup_keylen(keylen_int, this->int_alg); + } + if (this->int_size && this->int_alg != AUTH_UNDEFINED) + { + prf_plus->allocate_bytes(prf_plus, this->int_size / 8, &int_key); + } /* send SA down to the kernel */ DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst); @@ -601,18 +686,22 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, if (this->ipcomp != IPCOMP_NONE) { /* we install an additional IPComp SA */ - u_int32_t cpi = htonl(ntohs(mine ? this->me.cpi : this->other.cpi)); - status = charon->kernel_interface->add_sa(charon->kernel_interface, + cpi = htonl(ntohs(mine ? this->me.cpi : this->other.cpi)); + charon->kernel_interface->add_sa(charon->kernel_interface, src, dst, cpi, IPPROTO_COMP, this->reqid, 0, 0, - ENCR_UNDEFINED, 0, AUTH_UNDEFINED, 0, NULL, mode, - this->ipcomp, FALSE, mine); + ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty, + mode, this->ipcomp, FALSE, mine); } + soft = this->config->get_lifetime(this->config, TRUE); + hard = this->config->get_lifetime(this->config, FALSE); status = charon->kernel_interface->add_sa(charon->kernel_interface, src, dst, spi, this->protocol, this->reqid, mine ? soft : 0, hard, - this->enc_alg, this->enc_size, this->int_alg, this->int_size, - prf_plus, mode, IPCOMP_NONE, this->encap, mine); - + this->enc_alg, enc_key, this->int_alg, int_key, + mode, IPCOMP_NONE, this->encap, mine); + + chunk_clear(&enc_key); + chunk_clear(&int_key); this->install_time = time(NULL); this->rekey_time = this->install_time + soft; return status; diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 5dd522dee..28241cfb7 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -1658,8 +1658,8 @@ static status_t derive_keys(private_ike_sa_t *this, this->prf->allocate_bytes(this->prf, secret, &skeyseed); DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed); this->prf->set_key(this->prf, skeyseed); - chunk_free(&skeyseed); - chunk_free(&secret); + chunk_clear(&skeyseed); + chunk_clear(&secret); prf_plus = prf_plus_create(this->prf, prf_plus_seed); } else @@ -1670,13 +1670,13 @@ static status_t derive_keys(private_ike_sa_t *this, child_prf->allocate_bytes(child_prf, secret, &skeyseed); DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed); old_prf->set_key(old_prf, skeyseed); - chunk_free(&skeyseed); - chunk_free(&secret); + chunk_clear(&skeyseed); + chunk_clear(&secret); prf_plus = prf_plus_create(old_prf, prf_plus_seed); } chunk_free(&full_nonce); chunk_free(&fixed_nonce); - chunk_free(&prf_plus_seed); + chunk_clear(&prf_plus_seed); /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */ @@ -1687,7 +1687,7 @@ static status_t derive_keys(private_ike_sa_t *this, prf_plus->allocate_bytes(prf_plus, key_size, &key); DBG4(DBG_IKE, "Sk_d secret %B", &key); this->child_prf->set_key(this->child_prf, key); - chunk_free(&key); + chunk_clear(&key); /* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */ if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL)) @@ -1711,12 +1711,12 @@ static status_t derive_keys(private_ike_sa_t *this, prf_plus->allocate_bytes(prf_plus, key_size, &key); DBG4(DBG_IKE, "Sk_ai secret %B", &key); signer_i->set_key(signer_i, key); - chunk_free(&key); + chunk_clear(&key); prf_plus->allocate_bytes(prf_plus, key_size, &key); DBG4(DBG_IKE, "Sk_ar secret %B", &key); signer_r->set_key(signer_r, key); - chunk_free(&key); + chunk_clear(&key); if (initiator) { @@ -1752,12 +1752,12 @@ static status_t derive_keys(private_ike_sa_t *this, prf_plus->allocate_bytes(prf_plus, key_size, &key); DBG4(DBG_IKE, "Sk_ei secret %B", &key); crypter_i->set_key(crypter_i, key); - chunk_free(&key); + chunk_clear(&key); prf_plus->allocate_bytes(prf_plus, key_size, &key); DBG4(DBG_IKE, "Sk_er secret %B", &key); crypter_r->set_key(crypter_r, key); - chunk_free(&key); + chunk_clear(&key); if (initiator) { |