moved CHILD_SA key derivation to keymat_t
passing key chunks to CHILD_SA, not the PRF
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user