moved CHILD_SA key derivation to keymat_t

passing key chunks to CHILD_SA, not the PRF
This commit is contained in:
Martin Willi
2008-10-29 16:06:16 +00:00
parent f65ba4e978
commit 80853d8498
7 changed files with 447 additions and 449 deletions
+26 -36
View File
@@ -136,9 +136,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
{
u_int32_t rekey, now = time(NULL);
u_int32_t use_in, use_out;
encryption_algorithm_t encr_alg;
integrity_algorithm_t int_alg;
chunk_t encr_key, int_key;
proposal_t *proposal;
fprintf(out, "%12s{%d}: %N, %N",
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
@@ -152,54 +150,46 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
child_sa->has_encap(child_sa) ? " in UDP": "",
ntohl(child_sa->get_spi(child_sa, TRUE)),
ntohl(child_sa->get_spi(child_sa, FALSE)));
if (child_sa->get_ipcomp(child_sa) != IPCOMP_NONE)
{
fprintf(out, ", IPCOMP CPIs: %.4x_i %.4x_o",
ntohs(child_sa->get_cpi(child_sa, TRUE)),
ntohs(child_sa->get_cpi(child_sa, FALSE)));
}
if (all)
{
fprintf(out, "\n%12s{%d}: ", child_sa->get_name(child_sa),
child_sa->get_reqid(child_sa));
if (child_sa->get_protocol(child_sa) == PROTO_ESP)
proposal = child_sa->get_proposal(child_sa);
if (proposal)
{
encr_alg = child_sa->get_encryption(child_sa, TRUE, &encr_key);
switch (encr_alg)
u_int16_t encr_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED;
u_int16_t encr_size = 0, int_size = 0;
proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
&encr_alg, &encr_size);
proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
&int_alg, &int_size);
if (encr_alg != ENCR_UNDEFINED)
{
/* Algorithms with variable key size.
* GCM/CCM keys are actually shorted than their key data. */
case ENCR_AES_GCM_ICV8:
case ENCR_AES_GCM_ICV12:
case ENCR_AES_GCM_ICV16:
encr_key.len -= 1;
/* FALL */
case ENCR_AES_CCM_ICV8:
case ENCR_AES_CCM_ICV12:
case ENCR_AES_CCM_ICV16:
encr_key.len -= 3;
/* FALL */
case ENCR_AES_CBC:
fprintf(out, "%N-%d", encryption_algorithm_names,
encr_alg, encr_key.len * 8);
break;
default:
fprintf(out, "%N", encryption_algorithm_names, encr_alg);
break;
fprintf(out, "%N", encryption_algorithm_names, encr_alg);
if (encr_size)
{
fprintf(out, "-%d", encr_size);
}
}
}
int_alg = child_sa->get_integrity(child_sa, TRUE, &int_key);
switch (int_alg)
{
case AUTH_UNDEFINED:
break;
default:
if (int_alg != AUTH_UNDEFINED)
{
fprintf(out, "/%N", integrity_algorithm_names, int_alg);
break;
if (int_size)
{
fprintf(out, "-%d", int_size);
}
}
}
fprintf(out, ", rekeying ");
+177 -319
View File
@@ -47,14 +47,45 @@ struct private_child_sa_t {
*/
child_sa_t public;
struct {
/** address of peer */
host_t *addr;
/** actual used SPI, 0 if unused */
u_int32_t spi;
/** Compression Parameter Index (CPI) used, 0 if unused */
u_int16_t cpi;
} me, other;
/**
* address of us
*/
host_t *my_addr;
/**
* address of remote
*/
host_t *other_addr;
/**
* our actually used SPI, 0 if unused
*/
u_int32_t my_spi;
/**
* others used SPI, 0 if unused
*/
u_int32_t other_spi;
/**
* our Compression Parameter Index (CPI) used, 0 if unused
*/
u_int16_t my_cpi;
/**
* others Compression Parameter Index (CPI) used, 0 if unused
*/
u_int16_t other_cpi;
/**
* List for local traffic selectors
*/
linked_list_t *my_ts;
/**
* List for remote traffic selectors
*/
linked_list_t *other_ts;
/**
* Allocated SPI for a ESP proposal candidates
@@ -71,41 +102,11 @@ struct private_child_sa_t {
*/
protocol_id_t protocol;
/**
* Separate list for local traffic selectors
*/
linked_list_t *my_ts;
/**
* Separate list for remote traffic selectors
*/
linked_list_t *other_ts;
/**
* reqid used for this child_sa
*/
u_int32_t reqid;
/**
* encryption algorithm used for this SA
*/
u_int16_t enc_alg;
/**
* Encryption key data, inbound and outbound
*/
chunk_t enc_key[2];
/**
* integrity protection algorithm used for this SA
*/
u_int16_t int_alg;
/**
* integrity key data, inbound and outbound
*/
chunk_t int_key[2];
/**
* absolute time when rekeying is scheduled
*/
@@ -141,66 +142,19 @@ struct private_child_sa_t {
*/
ipsec_mode_t mode;
/**
* selected proposal
*/
proposal_t *proposal;
/**
* config used to create this child
*/
child_cfg_t *config;
};
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.
* Implementation of child_sa_t.get_namy_
*/
static char *get_name(private_child_sa_t *this)
{
@@ -220,11 +174,7 @@ static u_int32_t get_reqid(private_child_sa_t *this)
*/
u_int32_t get_spi(private_child_sa_t *this, bool inbound)
{
if (inbound)
{
return this->me.spi;
}
return this->other.spi;
return inbound ? this->my_spi : this->other_spi;
}
/**
@@ -232,11 +182,7 @@ u_int32_t get_spi(private_child_sa_t *this, bool inbound)
*/
u_int16_t get_cpi(private_child_sa_t *this, bool inbound)
{
if (inbound)
{
return this->me.cpi;
}
return this->other.cpi;
return inbound ? this->my_cpi : this->other_cpi;
}
/**
@@ -247,6 +193,14 @@ protocol_id_t get_protocol(private_child_sa_t *this)
return this->protocol;
}
/**
* Implementation of child_sa_t.get_mode
*/
static ipsec_mode_t get_mode(private_child_sa_t *this)
{
return this->mode;
}
/**
* Implementation of child_sa_t.has_encap
*/
@@ -403,39 +357,7 @@ static u_int32_t get_usetime(private_child_sa_t *this, bool inbound)
*/
static u_int32_t get_lifetime(private_child_sa_t *this, bool hard)
{
if (hard)
{
return this->expire_time;
}
return this->rekey_time;
}
/**
* Implementation of child_sa_t.get_integrity
*/
static integrity_algorithm_t get_integrity(private_child_sa_t *this,
bool inbound, chunk_t *key)
{
*key = this->int_key[!!inbound];
return this->int_alg;
}
/**
* Implementation of child_sa_t.get_encryption
*/
static encryption_algorithm_t get_encryption(private_child_sa_t *this,
bool inbound, chunk_t *key)
{
*key = this->enc_key[!!inbound];
return this->enc_alg;
}
/**
* Implementation of child_sa_t.get_mode
*/
static ipsec_mode_t get_mode(private_child_sa_t *this)
{
return this->mode;
return hard ? this->expire_time : this->rekey_time;
}
/**
@@ -461,7 +383,7 @@ static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal)
{
if (charon->kernel_interface->get_spi(
charon->kernel_interface,
this->other.addr, this->me.addr,
this->other_addr, this->my_addr,
PROTO_AH, this->reqid,
&this->alloc_ah_spi) != SUCCESS)
{
@@ -477,7 +399,7 @@ static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal)
{
if (charon->kernel_interface->get_spi(
charon->kernel_interface,
this->other.addr, this->me.addr,
this->other_addr, this->my_addr,
PROTO_ESP, this->reqid,
&this->alloc_esp_spi) != SUCCESS)
{
@@ -489,7 +411,6 @@ static status_t alloc_proposal(private_child_sa_t *this, proposal_t *proposal)
return SUCCESS;
}
/**
* Implements child_sa_t.alloc
*/
@@ -512,138 +433,79 @@ static status_t alloc(private_child_sa_t *this, linked_list_t *proposals)
return SUCCESS;
}
/**
* Install an SA for one direction
*/
static status_t install(private_child_sa_t *this, proposal_t *proposal,
ipsec_mode_t mode, prf_plus_t *prf_plus, bool mine)
ipsec_mode_t mode, chunk_t integ, chunk_t encr, bool in)
{
u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
u_int32_t spi, cpi, soft, hard, now;
host_t *src, *dst;
status_t status;
int add_keymat;
u_int16_t enc_size, int_size;
this->protocol = proposal->get_protocol(proposal);
/* now we have to decide which spi to use. Use self allocated, if "mine",
* or the one in the proposal, if not "mine" (others). Additionally,
/* now we have to decide which spi to use. Use self allocated, if "in",
* or the one in the proposal, if not "in" (others). Additionally,
* source and dest host switch depending on the role */
if (mine)
if (in)
{
/* if we have allocated SPIs for AH and ESP, we must delete the unused
* one. */
if (this->protocol == PROTO_ESP)
{
this->me.spi = this->alloc_esp_spi;
this->my_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);
this->my_addr, this->alloc_ah_spi, PROTO_AH);
}
}
else
{
this->me.spi = this->alloc_ah_spi;
this->my_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);
this->my_addr, this->alloc_esp_spi, PROTO_ESP);
}
}
spi = this->me.spi;
dst = this->me.addr;
src = this->other.addr;
spi = this->my_spi;
dst = this->my_addr;
src = this->other_addr;
}
else
{
this->other.spi = proposal->get_spi(proposal);
spi = this->other.spi;
src = this->me.addr;
dst = this->other.addr;
this->other_spi = proposal->get_spi(proposal);
spi = this->other_spi;
src = this->my_addr;
dst = this->other_addr;
}
DBG2(DBG_CHD, "adding %s %N SA", mine ? "inbound" : "outbound",
DBG2(DBG_CHD, "adding %s %N SA", in ? "inbound" : "outbound",
protocol_id_names, this->protocol);
/* select encryption algo, derive key */
if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
&this->enc_alg, &enc_size))
{
DBG2(DBG_CHD, " using %N for encryption",
encryption_algorithm_names, this->enc_alg);
}
if (this->enc_alg != ENCR_UNDEFINED)
{
if (!enc_size)
{
enc_size = lookup_keylen(keylen_enc, this->enc_alg);
}
if (!enc_size)
{
DBG1(DBG_CHD, "no keylenth defined for %N",
encryption_algorithm_names, this->enc_alg);
return FAILED;
}
/* CCM/GCM needs additional keymat */
switch (this->enc_alg)
{
case ENCR_AES_CCM_ICV8:
case ENCR_AES_CCM_ICV12:
case ENCR_AES_CCM_ICV16:
enc_size += 24;
break;
case ENCR_AES_GCM_ICV8:
case ENCR_AES_GCM_ICV12:
case ENCR_AES_GCM_ICV16:
enc_size += 32;
break;
default:
add_keymat = 0;
break;
}
prf_plus->allocate_bytes(prf_plus, enc_size / 8, &this->enc_key[!!mine]);
}
/* select integrity algo, derive key */
if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
&this->int_alg, &int_size))
{
DBG2(DBG_CHD, " using %N for integrity",
integrity_algorithm_names, this->int_alg);
}
if (this->int_alg != AUTH_UNDEFINED)
{
if (!int_size)
{
int_size = lookup_keylen(keylen_int, this->int_alg);
}
if (!enc_size)
{
DBG1(DBG_CHD, "no keylenth defined for %N",
integrity_algorithm_names, this->int_alg);
return FAILED;
}
prf_plus->allocate_bytes(prf_plus, int_size / 8, &this->int_key[!!mine]);
}
/* send SA down to the kernel */
DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
if (this->ipcomp != IPCOMP_NONE)
{
/* we install an additional IPComp SA */
cpi = htonl(ntohs(mine ? this->me.cpi : this->other.cpi));
cpi = htonl(ntohs(in ? this->my_cpi : this->other_cpi));
charon->kernel_interface->add_sa(charon->kernel_interface,
src, dst, cpi, IPPROTO_COMP, this->reqid, 0, 0,
ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED, chunk_empty,
mode, this->ipcomp, FALSE, mine);
mode, this->ipcomp, FALSE, in);
}
proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_alg, &size);
proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &int_alg, &size);
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_key[!!mine],
this->int_alg, this->int_key[!!mine],
mode, IPCOMP_NONE, this->encap, mine);
status = charon->kernel_interface->add_sa(charon->kernel_interface,
src, dst, spi, this->protocol, this->reqid,
in ? soft : 0, hard, enc_alg, encr, int_alg, integ,
mode, IPCOMP_NONE, this->encap, in);
now = time(NULL);
this->rekey_time = now + soft;
@@ -651,63 +513,70 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
return status;
}
static status_t add(private_child_sa_t *this, proposal_t *proposal,
ipsec_mode_t mode, prf_plus_t *prf_plus)
/**
* Implementation of child_sa_t.add
*/
static status_t add(private_child_sa_t *this,
proposal_t *proposal, ipsec_mode_t mode,
chunk_t integ_in, chunk_t integ_out,
chunk_t encr_in, chunk_t encr_out)
{
u_int32_t outbound_spi, inbound_spi;
this->proposal = proposal->clone(proposal);
this->protocol = proposal->get_protocol(proposal);
/* backup outbound spi, as alloc overwrites it */
outbound_spi = proposal->get_spi(proposal);
/* get SPIs inbound SAs */
/* get SPIs for inbound SAs, write to proposal */
if (alloc_proposal(this, proposal) != SUCCESS)
{
return FAILED;
}
inbound_spi = proposal->get_spi(proposal);
/* install inbound SAs */
if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS)
/* install inbound SAs using allocated SPI */
if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS)
{
return FAILED;
}
/* install outbound SAs, restore spi*/
proposal->set_spi(proposal, outbound_spi);
if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS)
/* install outbound SAs using received SPI*/
if (install(this, this->proposal, mode, integ_out, encr_out, FALSE) != SUCCESS)
{
return FAILED;
}
proposal->set_spi(proposal, inbound_spi);
return SUCCESS;
}
static status_t update(private_child_sa_t *this, proposal_t *proposal,
ipsec_mode_t mode, prf_plus_t *prf_plus)
/**
* Implementation of child_sa_t.update
*/
static status_t update(private_child_sa_t *this,
proposal_t *proposal, ipsec_mode_t mode,
chunk_t integ_in, chunk_t integ_out,
chunk_t encr_in, chunk_t encr_out)
{
u_int32_t inbound_spi;
/* backup received spi, as install() overwrites it */
inbound_spi = proposal->get_spi(proposal);
this->proposal = proposal->clone(proposal);
this->protocol = proposal->get_protocol(proposal);
/* install outbound SAs */
if (install(this, proposal, mode, prf_plus, FALSE) != SUCCESS)
if (install(this, proposal, mode, integ_out, encr_out, FALSE) != SUCCESS)
{
return FAILED;
}
/* restore spi */
proposal->set_spi(proposal, inbound_spi);
/* install inbound SAs */
if (install(this, proposal, mode, prf_plus, TRUE) != SUCCESS)
if (install(this, proposal, mode, integ_in, encr_in, TRUE) != SUCCESS)
{
return FAILED;
}
return SUCCESS;
}
/**
* Implementation of child_sa_t.get_proposal
*/
static proposal_t* get_proposal(private_child_sa_t *this)
{
return this->proposal;
}
/**
* Implementation of child_sa_t.add_policies
*/
static status_t add_policies(private_child_sa_t *this,
linked_list_t *my_ts_list, linked_list_t *other_ts_list,
ipsec_mode_t mode, protocol_id_t proto)
@@ -746,15 +615,15 @@ static status_t add_policies(private_child_sa_t *this,
{
/* install 3 policies: out, in and forward */
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT,
this->my_addr, this->other_addr, my_ts, other_ts, POLICY_OUT,
this->protocol, this->reqid, high_prio, mode, this->ipcomp);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN,
this->other_addr, this->my_addr, other_ts, my_ts, POLICY_IN,
this->protocol, this->reqid, high_prio, mode, this->ipcomp);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD,
this->other_addr, this->my_addr, other_ts, my_ts, POLICY_FWD,
this->protocol, this->reqid, high_prio, mode, this->ipcomp);
if (status != SUCCESS)
@@ -782,11 +651,7 @@ static status_t add_policies(private_child_sa_t *this,
*/
static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local)
{
if (local)
{
return this->my_ts;
}
return this->other_ts;
return local ? this->my_ts : this->other_ts;
}
/**
@@ -798,8 +663,8 @@ static status_t update_hosts(private_child_sa_t *this,
child_sa_state_t old;
/* anything changed at all? */
if (me->equals(me, this->me.addr) &&
other->equals(other, this->other.addr) && this->encap == encap)
if (me->equals(me, this->my_addr) &&
other->equals(other, this->other_addr) && this->encap == encap)
{
return SUCCESS;
}
@@ -813,24 +678,24 @@ static status_t update_hosts(private_child_sa_t *this,
{
/* update our (initator) IPComp SA */
charon->kernel_interface->update_sa(charon->kernel_interface,
htonl(ntohs(this->me.cpi)), IPPROTO_COMP,
this->other.addr, this->me.addr, other, me, FALSE);
htonl(ntohs(this->my_cpi)), IPPROTO_COMP,
this->other_addr, this->my_addr, other, me, FALSE);
/* update his (responder) IPComp SA */
charon->kernel_interface->update_sa(charon->kernel_interface,
htonl(ntohs(this->other.cpi)), IPPROTO_COMP,
this->me.addr, this->other.addr, me, other, FALSE);
htonl(ntohs(this->other_cpi)), IPPROTO_COMP,
this->my_addr, this->other_addr, me, other, FALSE);
}
/* update our (initator) SA */
charon->kernel_interface->update_sa(charon->kernel_interface, this->me.spi,
this->protocol, this->other.addr, this->me.addr, other, me, encap);
charon->kernel_interface->update_sa(charon->kernel_interface, this->my_spi,
this->protocol, this->other_addr, this->my_addr, other, me, encap);
/* update his (responder) SA */
charon->kernel_interface->update_sa(charon->kernel_interface, this->other.spi,
this->protocol, this->me.addr, this->other.addr, me, other, encap);
charon->kernel_interface->update_sa(charon->kernel_interface, this->other_spi,
this->protocol, this->my_addr, this->other_addr, me, other, encap);
/* update policies */
if (!me->ip_equals(me, this->me.addr) ||
!other->ip_equals(other, this->other.addr))
if (!me->ip_equals(me, this->my_addr) ||
!other->ip_equals(other, this->other_addr))
{
enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts;
@@ -848,13 +713,13 @@ static status_t update_hosts(private_child_sa_t *this,
other_ts, my_ts, POLICY_FWD);
/* check whether we have to update a "dynamic" traffic selector */
if (!me->ip_equals(me, this->me.addr) &&
my_ts->is_host(my_ts, this->me.addr))
if (!me->ip_equals(me, this->my_addr) &&
my_ts->is_host(my_ts, this->my_addr))
{
my_ts->set_address(my_ts, me);
}
if (!other->ip_equals(other, this->other.addr) &&
other_ts->is_host(other_ts, this->other.addr))
if (!other->ip_equals(other, this->other_addr) &&
other_ts->is_host(other_ts, this->other_addr))
{
other_ts->set_address(other_ts, other);
}
@@ -882,15 +747,15 @@ static status_t update_hosts(private_child_sa_t *this,
}
/* apply hosts */
if (!me->equals(me, this->me.addr))
if (!me->equals(me, this->my_addr))
{
this->me.addr->destroy(this->me.addr);
this->me.addr = me->clone(me);
this->my_addr->destroy(this->my_addr);
this->my_addr = me->clone(me);
}
if (!other->equals(other, this->other.addr))
if (!other->equals(other, this->other_addr))
{
this->other.addr->destroy(this->other.addr);
this->other.addr = other->clone(other);
this->other_addr->destroy(this->other_addr);
this->other_addr = other->clone(other);
}
set_state(this, old);
@@ -905,7 +770,7 @@ static void activate_ipcomp(private_child_sa_t *this, ipcomp_transform_t ipcomp,
u_int16_t other_cpi)
{
this->ipcomp = ipcomp;
this->other.cpi = other_cpi;
this->other_cpi = other_cpi;
}
/**
@@ -916,10 +781,10 @@ static u_int16_t allocate_cpi(private_child_sa_t *this)
if (!this->cpi_allocated)
{
charon->kernel_interface->get_cpi(charon->kernel_interface,
this->other.addr, this->me.addr, this->reqid, &this->me.cpi);
this->other_addr, this->my_addr, this->reqid, &this->my_cpi);
this->cpi_allocated = TRUE;
}
return this->me.cpi;
return this->my_cpi;
}
/**
@@ -933,35 +798,35 @@ static void destroy(private_child_sa_t *this)
set_state(this, CHILD_DESTROYING);
/* delete SAs in the kernel, if they are set up */
if (this->me.spi)
if (this->my_spi)
{
charon->kernel_interface->del_sa(charon->kernel_interface,
this->me.addr, this->me.spi, this->protocol);
this->my_addr, this->my_spi, this->protocol);
}
if (this->alloc_esp_spi && this->alloc_esp_spi != this->me.spi)
if (this->alloc_esp_spi && this->alloc_esp_spi != this->my_spi)
{
charon->kernel_interface->del_sa(charon->kernel_interface,
this->me.addr, this->alloc_esp_spi, PROTO_ESP);
this->my_addr, this->alloc_esp_spi, PROTO_ESP);
}
if (this->alloc_ah_spi && this->alloc_ah_spi != this->me.spi)
if (this->alloc_ah_spi && this->alloc_ah_spi != this->my_spi)
{
charon->kernel_interface->del_sa(charon->kernel_interface,
this->me.addr, this->alloc_ah_spi, PROTO_AH);
this->my_addr, this->alloc_ah_spi, PROTO_AH);
}
if (this->other.spi)
if (this->other_spi)
{
charon->kernel_interface->del_sa(charon->kernel_interface,
this->other.addr, this->other.spi, this->protocol);
this->other_addr, this->other_spi, this->protocol);
}
if (this->me.cpi)
if (this->my_cpi)
{
charon->kernel_interface->del_sa(charon->kernel_interface,
this->me.addr, htonl(ntohs(this->me.cpi)), IPPROTO_COMP);
this->my_addr, htonl(ntohs(this->my_cpi)), IPPROTO_COMP);
}
if (this->other.cpi)
if (this->other_cpi)
{
charon->kernel_interface->del_sa(charon->kernel_interface,
this->other.addr, htonl(ntohs(this->other.cpi)), IPPROTO_COMP);
this->other_addr, htonl(ntohs(this->other_cpi)), IPPROTO_COMP);
}
/* delete all policies in the kernel */
@@ -977,14 +842,11 @@ static void destroy(private_child_sa_t *this)
}
enumerator->destroy(enumerator);
chunk_clear(&this->enc_key[0]);
chunk_clear(&this->enc_key[1]);
chunk_clear(&this->int_key[0]);
chunk_clear(&this->int_key[1]);
this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
this->me.addr->destroy(this->me.addr);
this->other.addr->destroy(this->other.addr);
this->my_addr->destroy(this->my_addr);
this->other_addr->destroy(this->other_addr);
DESTROY_IF(this->proposal);
this->config->destroy(this->config);
free(this);
}
@@ -1007,13 +869,12 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->public.get_mode = (ipsec_mode_t(*)(child_sa_t*))get_mode;
this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp;
this->public.has_encap = (bool(*)(child_sa_t*))has_encap;
this->public.get_encryption = (encryption_algorithm_t(*)(child_sa_t*, bool, chunk_t*))get_encryption;
this->public.get_integrity = (integrity_algorithm_t(*)(child_sa_t*, bool, chunk_t*))get_integrity;
this->public.get_lifetime = (u_int32_t(*)(child_sa_t*, bool))get_lifetime;
this->public.get_usetime = (u_int32_t(*)(child_sa_t*, bool))get_usetime;
this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
this->public.add = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,prf_plus_t*))add;
this->public.update = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,prf_plus_t*))update;
this->public.add = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))add;
this->public.update = (status_t(*)(child_sa_t*,proposal_t*,ipsec_mode_t,chunk_t,chunk_t,chunk_t,chunk_t))update;
this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal;
this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_t*,bool))update_hosts;
this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,ipsec_mode_t,protocol_id_t))add_policies;
this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors;
@@ -1026,12 +887,12 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->public.destroy = (void(*)(child_sa_t*))destroy;
/* private data */
this->me.addr = me->clone(me);
this->other.addr = other->clone(other);
this->me.spi = 0;
this->me.cpi = 0;
this->other.spi = 0;
this->other.cpi = 0;
this->my_addr = me->clone(me);
this->other_addr = other->clone(other);
this->my_spi = 0;
this->my_cpi = 0;
this->other_spi = 0;
this->other_cpi = 0;
this->alloc_ah_spi = 0;
this->alloc_esp_spi = 0;
this->encap = encap;
@@ -1040,14 +901,11 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->state = CHILD_CREATED;
/* reuse old reqid if we are rekeying an existing CHILD_SA */
this->reqid = rekey ? rekey : ++reqid;
this->enc_alg = ENCR_UNDEFINED;
this->enc_key[0] = this->enc_key[1] = chunk_empty;
this->int_alg = AUTH_UNDEFINED;
this->int_key[0] = this->int_key[1] = chunk_empty;
this->my_ts = linked_list_create();
this->other_ts = linked_list_create();
this->protocol = PROTO_NONE;
this->mode = MODE_TUNNEL;
this->proposal = NULL;
this->config = config;
config->get_ref(config);
+19 -24
View File
@@ -168,24 +168,6 @@ struct child_sa_t {
*/
bool (*has_encap)(child_sa_t *this);
/**
* Get the IPsec encryption key.
*
* @param inbound TRUE for inbound, FALSE for outbound key
* @param key chunk where to write key pointer and length
* @return encryption algorithm
*/
encryption_algorithm_t (*get_encryption)(child_sa_t *this, bool inbound,
chunk_t *key);
/**
* Get the IPsec integrity.
*
* @param inbound TRUE for inbound, FALSE for outbound key
* @param key chunk where to write key pointer and length
* @return integrity algorithm
*/
integrity_algorithm_t (*get_integrity)(child_sa_t *this, bool inbound,
chunk_t *key);
/**
* Get the lifetime of the CHILD_SA.
*
@@ -220,12 +202,15 @@ struct child_sa_t {
*
* @param proposal proposal for which SPIs are allocated
* @param mode mode for the CHILD_SA
* @param prf_plus key material to use for key derivation
* @param integ_in integrity key for inbound traffic
* @param integ_out integrity key for outbound traffic
* @param encr_in encryption key for inbound traffic
* @param enc_out encryption key for outbound traffic
* @return SUCCESS or FAILED
*/
status_t (*add)(child_sa_t *this, proposal_t *proposal, ipsec_mode_t mode,
prf_plus_t *prf_plus);
chunk_t integ_in, chunk_t integ_out,
chunk_t encr_in, chunk_t encr_out);
/**
* Install the kernel SAs for a proposal, after SPIs have been allocated.
*
@@ -233,12 +218,22 @@ struct child_sa_t {
*
* @param proposal proposal for which SPIs are allocated
* @param mode mode for the CHILD_SA
* @param prf_plus key material to use for key derivation
* @param integ_in integrity key for inbound traffic
* @param integ_out integrity key for outbound traffic
* @param encr_in encryption key for inbound traffic
* @param enc_out encryption key for outbound traffic
* @return SUCCESS or FAILED
*/
status_t (*update)(child_sa_t *this, proposal_t *proposal, ipsec_mode_t mode,
prf_plus_t *prf_plus);
chunk_t integ_in, chunk_t integ_out,
chunk_t encr_in, chunk_t encr_out);
/**
* Get the selected proposal passed to add()/update().
*
* @return selected proposal
*/
proposal_t* (*get_proposal)(child_sa_t *this);
/**
* Update the hosts in the kernel SAs and policies.
*
+151 -13
View File
@@ -83,6 +83,58 @@ struct private_keymat_t {
proposal_t *proposal;
};
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 keymat_t.create_dh
*/
@@ -95,9 +147,10 @@ static diffie_hellman_t* create_dh(private_keymat_t *this,
/**
* Implementation of keymat_t.derive_keys
*/
static bool derive_keys(private_keymat_t *this, proposal_t *proposal,
diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
ike_sa_id_t *id, private_keymat_t *rekey)
static bool derive_ike_keys(private_keymat_t *this, proposal_t *proposal,
diffie_hellman_t *dh, chunk_t nonce_i,
chunk_t nonce_r, ike_sa_id_t *id,
private_keymat_t *rekey)
{
chunk_t skeyseed, key, secret, full_nonce, fixed_nonce, prf_plus_seed;
chunk_t spi_i, spi_r;
@@ -307,6 +360,99 @@ static bool derive_keys(private_keymat_t *this, proposal_t *proposal,
return TRUE;
}
/**
* Implementation of keymat_t.derive_child_keys
*/
static bool derive_child_keys(private_keymat_t *this,
proposal_t *proposal, diffie_hellman_t *dh,
chunk_t nonce_i, chunk_t nonce_r,
chunk_t *encr_i, chunk_t *integ_i,
chunk_t *encr_r, chunk_t *integ_r)
{
u_int16_t enc_alg, int_alg, enc_size, int_size;
chunk_t seed, secret = chunk_empty;
prf_plus_t *prf_plus;
if (dh)
{
if (dh->get_shared_secret(dh, &secret) != SUCCESS)
{
return FALSE;
}
DBG4(DBG_CHD, "DH secret %B", &secret);
}
seed = chunk_cata("mcc", secret, nonce_i, nonce_r);
DBG4(DBG_CHD, "seed %B", &seed);
if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
&enc_alg, &enc_size))
{
DBG2(DBG_CHD, " using %N for encryption",
encryption_algorithm_names, enc_alg);
if (!enc_size)
{
enc_size = lookup_keylen(keylen_enc, enc_alg);
}
if (!enc_size)
{
DBG1(DBG_CHD, "no keylenth defined for %N",
encryption_algorithm_names, enc_alg);
return FALSE;
}
/* to bytes */
enc_size /= 8;
/* CCM/GCM needs additional bytes */
switch (enc_alg)
{
case ENCR_AES_CCM_ICV8:
case ENCR_AES_CCM_ICV12:
case ENCR_AES_CCM_ICV16:
enc_size += 3;
break;
case ENCR_AES_GCM_ICV8:
case ENCR_AES_GCM_ICV12:
case ENCR_AES_GCM_ICV16:
enc_size += 4;
break;
default:
break;
}
}
if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
&int_alg, &int_size))
{
DBG2(DBG_CHD, " using %N for integrity",
integrity_algorithm_names, int_alg);
if (!int_size)
{
int_size = lookup_keylen(keylen_int, int_alg);
}
if (!int_size)
{
DBG1(DBG_CHD, "no keylenth defined for %N",
integrity_algorithm_names, int_alg);
return FALSE;
}
/* to bytes */
int_size /= 8;
}
prf_plus = prf_plus_create(this->child_prf, seed);
prf_plus->allocate_bytes(prf_plus, enc_size, encr_i);
prf_plus->allocate_bytes(prf_plus, int_size, integ_i);
prf_plus->allocate_bytes(prf_plus, enc_size, encr_r);
prf_plus->allocate_bytes(prf_plus, int_size, integ_r);
prf_plus->destroy(prf_plus);
return TRUE;
}
/**
* Implementation of keymat_t.get_proposal
*/
@@ -331,14 +477,6 @@ static crypter_t* get_crypter(private_keymat_t *this, bool in)
return in ? this->crypter_in : this->crypter_out;
}
/**
* Implementation of keymat_t.get_child_prf
*/
static prf_t* get_child_prf(private_keymat_t *this)
{
return this->child_prf;
}
/**
* Implementation of keymat_t.get_auth_octets
*/
@@ -426,11 +564,11 @@ keymat_t *keymat_create(bool initiator)
private_keymat_t *this = malloc_thing(private_keymat_t);
this->public.create_dh = (diffie_hellman_t*(*)(keymat_t*, diffie_hellman_group_t group))create_dh;
this->public.derive_keys = (bool(*)(keymat_t*, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, keymat_t *rekey))derive_keys;
this->public.derive_ike_keys = (bool(*)(keymat_t*, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, keymat_t *rekey))derive_ike_keys;
this->public.derive_child_keys = (bool(*)(keymat_t*, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, chunk_t *encr_r, chunk_t *integ_r))derive_child_keys;
this->public.get_proposal = (proposal_t*(*)(keymat_t*))get_proposal;
this->public.get_signer = (signer_t*(*)(keymat_t*, bool in))get_signer;
this->public.get_crypter = (crypter_t*(*)(keymat_t*, bool in))get_crypter;
this->public.get_child_prf = (prf_t*(*)(keymat_t*))get_child_prf;
this->public.get_auth_octets = (chunk_t(*)(keymat_t *, bool verify, chunk_t ike_sa_init, chunk_t nonce, identification_t *id))get_auth_octets;
this->public.get_psk_sig = (chunk_t(*)(keymat_t*, bool verify, chunk_t ike_sa_init, chunk_t nonce, chunk_t secret, identification_t *id))get_psk_sig;
this->public.destroy = (void(*)(keymat_t*))destroy;
+33 -13
View File
@@ -43,7 +43,7 @@ struct keymat_t {
*
* The diffie hellman is either for IKE negotiation/rekeying or
* CHILD_SA rekeying (using PFS). The resulting DH object must be passed
* to derive_ike_keys or to derive_child_keys and destroyed after use
* to derive_keys or to derive_child_keys and destroyed after use
*
* @param group diffie hellman group
* @return DH object, NULL if group not supported
@@ -51,18 +51,45 @@ struct keymat_t {
diffie_hellman_t* (*create_dh)(keymat_t *this, diffie_hellman_group_t group);
/**
* Derive keys from the shared secret.
* Derive keys for the IKE_SA.
*
* These keys are not handed out, but are used by the associated signers,
* crypters and authentication functions.
*
* @param proposal selected algorithms
* @param dh diffie hellman key allocated by create_dh()
* @param nonce_i initiators nonce value
* @param nonce_r responders nonce value
* @param id IKE_SA identifier
* @param rekey keymat of old SA if we are rekeying
* @return TRUE on success
*/
bool (*derive_keys)(keymat_t *this, proposal_t *proposal,
diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
ike_sa_id_t *id, keymat_t *rekey);
bool (*derive_ike_keys)(keymat_t *this, proposal_t *proposal,
diffie_hellman_t *dh, chunk_t nonce_i,
chunk_t nonce_r, ike_sa_id_t *id, keymat_t *rekey);
/**
* Derive keys for a CHILD_SA.
*
* The keys for the CHILD_SA are allocated in the integ and encr chunks.
* An implementation might hand out encrypted keys only, which are
* decrypted in the kernel before use.
* If no PFS is used for the CHILD_SA, dh can be NULL.
*
* @param proposal selected algorithms
* @param dh diffie hellman key allocated by create_dh(), or NULL
* @param nonce_i initiators nonce value
* @param nonce_r responders nonce value
* @param encr_i chunk to write initiators encryption key to
* @param integ_i chunk to write initiators integrity key to
* @param encr_r chunk to write responders encryption key to
* @param integ_r chunk to write responders integrity key to
* @return TRUE on success
*/
bool (*derive_child_keys)(keymat_t *this,
proposal_t *proposal, diffie_hellman_t *dh,
chunk_t nonce_i, chunk_t nonce_r,
chunk_t *encr_i, chunk_t *integ_i,
chunk_t *encr_r, chunk_t *integ_r);
/**
* Get a signer to sign/verify IKE messages.
*
@@ -80,14 +107,7 @@ struct keymat_t {
crypter_t* (*get_crypter)(keymat_t *this, bool in);
/**
* Get a keyed PRF to derive keymat for children.
*
* @return PRF to derive CHILD_SA keymat from
*/
prf_t* (*get_child_prf)(keymat_t *this);
/**
* Get the selected proposal passed to derive_keys().
* Get the selected proposal passed to derive_ike_keys().
*
* @return selected proposal
*/
+39 -42
View File
@@ -96,6 +96,11 @@ struct private_child_create_t {
*/
diffie_hellman_group_t dh_group;
/**
* IKE_SAs keymat
*/
keymat_t *keymat;
/**
* mode the new CHILD_SA uses (transport/tunnel/beet)
*/
@@ -191,12 +196,10 @@ static bool ts_list_is_host(linked_list_t *list, host_t *host)
*/
static status_t select_and_install(private_child_create_t *this, bool no_dh)
{
prf_plus_t *prf_plus;
status_t status;
chunk_t nonce_i, nonce_r, secret, seed;
chunk_t encr_i, integ_i, encr_r, integ_r;
linked_list_t *my_ts, *other_ts;
host_t *me, *other, *other_vip, *my_vip;
keymat_t *keymat;
if (this->proposals == NULL)
{
@@ -209,21 +212,6 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
return NOT_FOUND;
}
if (this->initiator)
{
nonce_i = this->my_nonce;
nonce_r = this->other_nonce;
my_ts = this->tsi;
other_ts = this->tsr;
}
else
{
nonce_r = this->my_nonce;
nonce_i = this->other_nonce;
my_ts = this->tsr;
other_ts = this->tsi;
}
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
@@ -266,6 +254,16 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
other_vip = other;
}
if (this->initiator)
{
my_ts = this->tsi;
other_ts = this->tsr;
}
else
{
my_ts = this->tsr;
other_ts = this->tsi;
}
my_ts = this->config->get_traffic_selectors(this->config, TRUE, my_ts,
my_vip);
other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts,
@@ -323,21 +321,6 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
}
}
if (this->dh)
{
if (this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
{
DBG1(DBG_IKE, "DH exchange incomplete");
return FAILED;
}
DBG3(DBG_IKE, "DH secret %B", &secret);
seed = chunk_cata("mcc", secret, nonce_i, nonce_r);
}
else
{
seed = chunk_cata("cc", nonce_i, nonce_r);
}
if (this->ipcomp != IPCOMP_NONE)
{
this->child_sa->activate_ipcomp(this->child_sa, this->ipcomp,
@@ -352,19 +335,32 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
return NOT_FOUND;
}
keymat = this->ike_sa->get_keymat(this->ike_sa);
prf_plus = prf_plus_create(keymat->get_child_prf(keymat), seed);
status = FAILED;
if (this->initiator)
{
status = this->child_sa->update(this->child_sa, this->proposal,
this->mode, prf_plus);
if (this->keymat->derive_child_keys(this->keymat, this->proposal,
this->dh, this->my_nonce, this->other_nonce,
&encr_i, &integ_i, &encr_r, &integ_r))
{
status = this->child_sa->update(this->child_sa, this->proposal,
this->mode, integ_r, integ_i, encr_r, encr_i);
}
}
else
{
status = this->child_sa->add(this->child_sa, this->proposal,
this->mode, prf_plus);
if (this->keymat->derive_child_keys(this->keymat, this->proposal,
this->dh, this->other_nonce, this->my_nonce,
&encr_i, &integ_i, &encr_r, &integ_r))
{
status = this->child_sa->add(this->child_sa, this->proposal,
this->mode, integ_i, integ_r, encr_i, encr_r);
}
}
prf_plus->destroy(prf_plus);
/* TODO: invoke bus method with key mat */
chunk_clear(&integ_i);
chunk_clear(&integ_r);
chunk_clear(&encr_i);
chunk_clear(&encr_r);
if (status != SUCCESS)
{
@@ -494,7 +490,7 @@ static void process_payloads(private_child_create_t *this, message_t *message)
if (!this->initiator)
{
this->dh_group = ke_payload->get_dh_group_number(ke_payload);
this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
this->dh = this->keymat->create_dh(this->keymat, this->dh_group);
}
if (this->dh)
{
@@ -648,7 +644,7 @@ static status_t build_i(private_child_create_t *this, message_t *message)
if (this->dh_group != MODP_NONE)
{
this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
this->dh = this->keymat->create_dh(this->keymat, this->dh_group);
}
if (this->config->use_ipcomp(this->config)) {
@@ -1131,6 +1127,7 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config)
this->tsr = NULL;
this->dh = NULL;
this->dh_group = MODP_NONE;
this->keymat = ike_sa->get_keymat(ike_sa);
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
this->ipcomp = IPCOMP_NONE;
+2 -2
View File
@@ -415,7 +415,7 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
old_keymat = this->old_sa->get_keymat(this->old_sa);
}
if (!this->keymat->derive_keys(this->keymat, this->proposal, this->dh,
if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh,
this->other_nonce, this->my_nonce, id, old_keymat))
{
DBG1(DBG_IKE, "key derivation failed");
@@ -522,7 +522,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
old_keymat = this->old_sa->get_keymat(this->old_sa);
}
if (!this->keymat->derive_keys(this->keymat, this->proposal, this->dh,
if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh,
this->my_nonce, this->other_nonce, id, old_keymat))
{
DBG1(DBG_IKE, "key derivation failed");