passing chunks, not prf+, to kernel interface

gives us better control of keymat in CHILD_SA
This commit is contained in:
Martin Willi
2008-10-14 15:17:44 +00:00
parent c25c8dce60
commit e517b4b174
7 changed files with 263 additions and 210 deletions
+107 -18
View File
@@ -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;
+10 -10
View File
@@ -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)
{