From: Adrian-Ken Rueegsegger Date: Mon, 17 Sep 2012 15:19:58 +0000 (+0200) Subject: Implement ESA rekeying with and without PFS X-Git-Tag: 5.0.3rc1~39^2~49 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4a1529203b089eb14bb96af8af16dda542ae4f88;p=thirdparty%2Fstrongswan.git Implement ESA rekeying with and without PFS A child SA is being rekeyed if the esa information passed to the add_sa function contains nonces. If it also contains a valid Diffie-Hellman context id PFS is used. The fact that the encr_r encryption key is passed to add_sa in the inbound case can be used to determine if we are initiator or not by inspecting the is_encr_r flag of the esa information struct. --- diff --git a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c index eaec4c263f..95b378fde0 100644 --- a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c +++ b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c @@ -23,6 +23,7 @@ #include #include "tkm.h" +#include "tkm_utils.h" #include "tkm_types.h" #include "tkm_keymat.h" #include "tkm_kernel_sad.h" @@ -77,29 +78,112 @@ METHOD(kernel_ipsec_t, add_sa, status_t, u_int16_t cpi, bool encap, bool esn, bool inbound, traffic_selector_t* src_ts, traffic_selector_t* dst_ts) { - if (!inbound) + if (enc_key.ptr == NULL) { + DBG1(DBG_KNL, "Unable to get ESA information"); + return FAILED; + } + esa_info_t esa = *(esa_info_t *)(enc_key.ptr); + + /* only handle the case where we have both distinct ESP spi's available */ + if (esa.spi_r == spi) + { + chunk_free(&esa.nonce_i); + chunk_free(&esa.nonce_r); return SUCCESS; } - const esa_info_t esa = *(esa_info_t *)(enc_key.ptr); + + /* Initiator if encr_r is passed as enc_key to the inbound add_sa call */ + const bool initiator = esa.is_encr_r && inbound; + + esp_spi_type spi_loc, spi_rem; + host_t *local, *peer; + chunk_t *nonce_loc, *nonce_rem; + if (initiator) + { + spi_loc = spi; + spi_rem = esa.spi_r; + local = dst; + peer = src; + nonce_loc = &esa.nonce_i; + nonce_rem = &esa.nonce_r; + } + else + { + spi_loc = esa.spi_r; + spi_rem = spi; + local = src; + peer = dst; + nonce_loc = &esa.nonce_r; + nonce_rem = &esa.nonce_i; + } + + const nc_id_type nonce_loc_id = tkm->chunk_map->get_id(tkm->chunk_map, + nonce_loc); + const esa_id_type esa_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_ESA); - DBG1(DBG_KNL, "adding child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, " - "esp_spi_rem: %x)", esa_id, esa.isa_id, ntohl(spi), ntohl(esa.spi_r)); - if (!this->sad->insert(this->sad, esa_id, src, dst, spi, protocol)) + if (!this->sad->insert(this->sad, esa_id, peer, local, spi_loc, protocol)) { DBG1(DBG_KNL, "unable to add entry (%llu) to SAD", esa_id); - tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id); - return FAILED; + goto sad_failure; } - if (ike_esa_create_first(esa_id, esa.isa_id, 1, 1, ntohl(spi), - ntohl(esa.spi_r)) != TKM_OK) + + /* + * creation of first CHILD SA: + * no nonce and no dh contexts because the ones from the IKE SA are re-used + */ + if (nonce_loc_id == 0 && esa.dh_id == 0) { - DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id); - this->sad->remove(this->sad, esa_id); - tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id); - return FAILED; + if (ike_esa_create_first(esa_id, esa.isa_id, 1, 1, ntohl(spi_loc), + ntohl(spi_rem)) != TKM_OK) + { + DBG1(DBG_KNL, "child SA (%llu, first) creation failed", esa_id); + goto failure; + } } + /* creation of child SA without PFS: no dh context */ + else if (nonce_loc_id != 0 && esa.dh_id == 0) + { + nonce_type nc_rem; + chunk_to_sequence(nonce_rem, &nc_rem); + if (ike_esa_create_no_pfs(esa_id, esa.isa_id, 1, 1, nonce_loc_id, + nc_rem, initiator, ntohl(spi_loc), + ntohl(spi_rem)) != TKM_OK) + { + DBG1(DBG_KNL, "child SA (%llu, no PFS) creation failed", esa_id); + goto failure; + } + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id); + } + /* creation of subsequent child SA with PFS: nonce and dh context are set */ + else + { + nonce_type nc_rem; + chunk_to_sequence(nonce_rem, &nc_rem); + if (ike_esa_create(esa_id, esa.isa_id, 1, 1, esa.dh_id, nonce_loc_id, + nc_rem, initiator, ntohl(spi_loc), + ntohl(spi_rem)) != TKM_OK) + { + DBG1(DBG_KNL, "child SA (%llu) creation failed", esa_id); + goto failure; + } + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_NONCE, nonce_loc_id); + } + DBG1(DBG_KNL, "added child SA (esa: %llu, isa: %llu, esp_spi_loc: %x, " + "esp_spi_rem: %x, role: %s)", esa_id, esa.isa_id, ntohl(spi_loc), + ntohl(spi_rem), initiator ? "initiator" : "responder"); + chunk_free(&esa.nonce_i); + chunk_free(&esa.nonce_r); + return SUCCESS; + +failure: + this->sad->remove(this->sad, esa_id); +sad_failure: + tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_ESA, esa_id); + chunk_free(&esa.nonce_i); + chunk_free(&esa.nonce_r); + return FAILED; } METHOD(kernel_ipsec_t, query_sa, status_t,