diff options
Diffstat (limited to 'src/libcharon/sa/ikev1/tasks/quick_mode.c')
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/quick_mode.c | 91 |
1 files changed, 71 insertions, 20 deletions
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 6271e5b05..12ee594b9 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -165,6 +165,11 @@ struct private_quick_mode_t { */ ipsec_mode_t mode; + /* + * SA protocol (ESP|AH) negotiated + */ + protocol_id_t proto; + /** * Use UDP encapsulation */ @@ -722,7 +727,7 @@ static status_t send_notify(private_quick_mode_t *this, notify_type_t type) notify_payload_t *notify; notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, - PROTO_ESP, type); + this->proto, type); notify->set_spi(notify, this->spi_i); this->ike_sa->queue_task(this->ike_sa, @@ -733,6 +738,38 @@ static status_t send_notify(private_quick_mode_t *this, notify_type_t type) return ALREADY_DONE; } +/** + * Prepare a list of proposals from child_config containing only the specified + * DH group, unless it is set to MODP_NONE. + */ +static linked_list_t *get_proposals(private_quick_mode_t *this, + diffie_hellman_group_t group) +{ + linked_list_t *list; + proposal_t *proposal; + enumerator_t *enumerator; + + list = this->config->get_proposals(this->config, FALSE); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &proposal)) + { + if (group != MODP_NONE) + { + if (!proposal->has_dh_group(proposal, group)) + { + list->remove_at(list, enumerator); + proposal->destroy(proposal); + continue; + } + proposal->strip_dh(proposal, group); + } + proposal->set_spi(proposal, this->spi_i); + } + enumerator->destroy(enumerator); + + return list; +} + METHOD(task_t, build_i, status_t, private_quick_mode_t *this, message_t *message) { @@ -740,7 +777,6 @@ METHOD(task_t, build_i, status_t, { case QM_INIT: { - enumerator_t *enumerator; sa_payload_t *sa_payload; linked_list_t *list, *tsi, *tsr; proposal_t *proposal; @@ -770,42 +806,55 @@ METHOD(task_t, build_i, status_t, } } - this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); + list = this->config->get_proposals(this->config, MODP_NONE); + if (list->get_first(list, (void**)&proposal) == SUCCESS) + { + this->proto = proposal->get_protocol(proposal); + } + list->destroy_offset(list, offsetof(proposal_t, destroy)); + this->spi_i = this->child_sa->alloc_spi(this->child_sa, this->proto); if (!this->spi_i) { DBG1(DBG_IKE, "allocating SPI from kernel failed"); return FAILED; } + group = this->config->get_dh_group(this->config); if (group != MODP_NONE) { + proposal_t *proposal; + u_int16_t preferred_group; + + proposal = this->ike_sa->get_proposal(this->ike_sa); + proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, + &preferred_group, NULL); + /* try the negotiated DH group from IKE_SA */ + list = get_proposals(this, preferred_group); + if (list->get_count(list)) + { + group = preferred_group; + } + else + { + /* fall back to the first configured DH group */ + list->destroy(list); + list = get_proposals(this, group); + } + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, group); if (!this->dh) { DBG1(DBG_IKE, "configured DH group %N not supported", diffie_hellman_group_names, group); + list->destroy_offset(list, offsetof(proposal_t, destroy)); return FAILED; } } - - list = this->config->get_proposals(this->config, FALSE); - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &proposal)) + else { - if (group != MODP_NONE) - { - if (!proposal->has_dh_group(proposal, group)) - { - list->remove_at(list, enumerator); - proposal->destroy(proposal); - continue; - } - proposal->strip_dh(proposal, group); - } - proposal->set_spi(proposal, this->spi_i); + list = get_proposals(this, MODP_NONE); } - enumerator->destroy(enumerator); get_lifetimes(this); encap = get_encap(this->ike_sa, this->udp); @@ -1103,7 +1152,8 @@ METHOD(task_t, build_r, status_t, sa_payload_t *sa_payload; encap_t encap; - this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); + this->proto = this->proposal->get_protocol(this->proposal); + this->spi_r = this->child_sa->alloc_spi(this->child_sa, this->proto); if (!this->spi_r) { DBG1(DBG_IKE, "allocating SPI from kernel failed"); @@ -1311,6 +1361,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config, .state = QM_INIT, .tsi = tsi ? tsi->clone(tsi) : NULL, .tsr = tsr ? tsr->clone(tsr) : NULL, + .proto = PROTO_ESP, ); if (config) |