moved CHILD_SA key derivation to keymat_t
authorMartin Willi <martin@strongswan.org>
Wed, 29 Oct 2008 16:06:16 +0000 (16:06 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 29 Oct 2008 16:06:16 +0000 (16:06 -0000)
passing key chunks to CHILD_SA, not the PRF

src/charon/plugins/stroke/stroke_list.c
src/charon/sa/child_sa.c
src/charon/sa/child_sa.h
src/charon/sa/keymat.c
src/charon/sa/keymat.h
src/charon/sa/tasks/child_create.c
src/charon/sa/tasks/ike_init.c

index b4963a7..eb15e24 100644 (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)
-                       {
-                               encr_alg = child_sa->get_encryption(child_sa, TRUE, &encr_key);
-                       
-                               switch (encr_alg)
+                       proposal = child_sa->get_proposal(child_sa);
+                       if (proposal)
+                       {
+                               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 ");
                        
index 4bc2c2c..1cc2ad0 100644 (file)
@@ -47,64 +47,65 @@ 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;
        
        /**
-        * Allocated SPI for a ESP proposal candidates
+        * address of remote
         */
-       u_int32_t alloc_esp_spi;
+       host_t *other_addr;
        
        /**
-        * Allocated SPI for a AH proposal candidates
+        * our actually used SPI, 0 if unused
         */
-       u_int32_t alloc_ah_spi;
+       u_int32_t my_spi;
        
        /**
-        * Protocol used to protect this SA, ESP|AH
+        * others used SPI, 0 if unused
         */
-       protocol_id_t protocol;
+       u_int32_t other_spi;
        
        /**
-        * Separate list for local traffic selectors
+        * our Compression Parameter Index (CPI) used, 0 if unused
         */
-       linked_list_t *my_ts;
+       u_int16_t my_cpi;
        
        /**
-        * Separate list for remote traffic selectors
+        * others Compression Parameter Index (CPI) used, 0 if unused
         */
-       linked_list_t *other_ts;
+       u_int16_t other_cpi;
        
        /**
-        * reqid used for this child_sa
+        * List for local traffic selectors
         */
-       u_int32_t reqid;
+       linked_list_t *my_ts;
+       
+       /**
+        * List for remote traffic selectors
+        */
+       linked_list_t *other_ts;
        
        /**
-        * encryption algorithm used for this SA
+        * Allocated SPI for a ESP proposal candidates
         */
-       u_int16_t enc_alg;
+       u_int32_t alloc_esp_spi;
        
        /**
-        * Encryption key data, inbound and outbound
+        * Allocated SPI for a AH proposal candidates
         */
-       chunk_t enc_key[2];
+       u_int32_t alloc_ah_spi;
        
        /**
-        * integrity protection algorithm used for this SA
+        * Protocol used to protect this SA, ESP|AH
         */
-       u_int16_t int_alg;
+       protocol_id_t protocol;
        
        /**
-        * integrity key data, inbound and outbound
+        * reqid used for this child_sa
         */
-       chunk_t int_key[2];
+       u_int32_t reqid;
        
        /**
         * absolute time when rekeying is scheduled
@@ -142,65 +143,18 @@ 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;
 }
 
 /**
@@ -248,6 +194,14 @@ protocol_id_t get_protocol(private_child_sa_t *this)
 }
 
 /**
+ * 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
  */
 static bool has_encap(private_child_sa_t *this)
@@ -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;
-       
-       /* backup outbound spi, as alloc overwrites it */
-       outbound_spi = proposal->get_spi(proposal);
+       this->proposal = proposal->clone(proposal);
+       this->protocol = proposal->get_protocol(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);
        
index d76e23a..3e13814 100644 (file)
@@ -169,24 +169,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.
         *
         * @param hard          TRUE for hard lifetime, FALSE for soft (rekey) lifetime
@@ -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.
         *
index cc75a20..08bf55c 100644 (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;
@@ -308,6 +361,99 @@ static bool derive_keys(private_keymat_t *this, proposal_t *proposal,
 }
 
 /**
+ * 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
  */
 static proposal_t* get_proposal(private_keymat_t *this)
@@ -332,14 +478,6 @@ static crypter_t* get_crypter(private_keymat_t *this, bool in)
 }
 
 /**
- * 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
  */
 static chunk_t get_auth_octets(private_keymat_t *this, bool verify,
@@ -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;
index d23486d..835ad45 100644 (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
         */
index 8f2329c..0f1a47b 100644 (file)
@@ -97,6 +97,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)
         */
        ipsec_mode_t mode;
@@ -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;
index bbeda15..522d1d7 100644 (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");