moved key derivation and management into keymat object
authorMartin Willi <martin@strongswan.org>
Tue, 28 Oct 2008 16:07:06 +0000 (16:07 -0000)
committerMartin Willi <martin@strongswan.org>
Tue, 28 Oct 2008 16:07:06 +0000 (16:07 -0000)
allows secured implementation of key management (e.g. in kernel or HW)
only IKE keys for now

13 files changed:
src/charon/Makefile.am
src/charon/plugins/stroke/stroke_list.c
src/charon/sa/authenticators/eap_authenticator.c
src/charon/sa/authenticators/psk_authenticator.c
src/charon/sa/authenticators/pubkey_authenticator.c
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa.h
src/charon/sa/keymat.c [new file with mode: 0644]
src/charon/sa/keymat.h [new file with mode: 0644]
src/charon/sa/tasks/child_create.c
src/charon/sa/tasks/ike_init.c
src/charon/sa/tasks/ike_reauth.c
src/charon/sa/tasks/ike_rekey.c

index 04cebb6..b14abc5 100644 (file)
@@ -74,6 +74,7 @@ sa/ike_sa.c sa/ike_sa.h \
 sa/ike_sa_id.c sa/ike_sa_id.h \
 sa/ike_sa_manager.c sa/ike_sa_manager.h \
 sa/task_manager.c sa/task_manager.h \
+sa/keymat.c sa/keymat.h \
 sa/tasks/child_create.c sa/tasks/child_create.h \
 sa/tasks/child_delete.c sa/tasks/child_delete.h \
 sa/tasks/child_rekey.c sa/tasks/child_rekey.h \
index 555239f..b4963a7 100644 (file)
@@ -79,14 +79,18 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
        
        if (all)
        {
-               proposal_t *ike_proposal = ike_sa->get_proposal(ike_sa);
-
+               keymat_t *keymat;
+               proposal_t *ike_proposal;
+               
+               keymat = ike_sa->get_keymat(ike_sa);
+               ike_proposal = keymat->get_proposal(keymat);
+               
                fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s",
                                ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
                                id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "",
                                id->get_responder_spi(id), id->is_initiator(id) ? "" : "*");
-       
-
+               
+               
                if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED)
                {
                        u_int32_t rekey, reauth, now;
@@ -112,7 +116,7 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
                        }
                }
                fprintf(out, "\n");
-
+               
                if (ike_proposal)
                {
                        char buf[BUF_LEN];
@@ -121,7 +125,7 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all)
                        fprintf(out, "%12s[%d]: IKE proposal: %s\n",
                                        ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
                                        buf+4);
-               }               
+               }
        }
 }
 
index 04204cb..70d56f0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Martin Willi
+ * Copyright (C) 2006-2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -70,36 +70,24 @@ struct private_eap_authenticator_t {
         */
        u_int32_t vendor;
 };
-
-/**
- * reuse shared key signature function from PSK authenticator
- */
-extern chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
-                                                                                 chunk_t secret, identification_t *id,
-                                                                                 chunk_t skp, prf_t *prf);
 /**
  * Implementation of authenticator_t.verify.
  */
 static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init,
                                           chunk_t my_nonce, auth_payload_t *auth_payload)
 {
-       chunk_t auth_data, recv_auth_data, secret;
-       identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa);
+       chunk_t auth_data, recv_auth_data;
+       identification_t *other_id;
+       keymat_t *keymat;
        
-       if (this->msk.len)
-       {       /* use MSK if EAP method established one... */
-               secret = this->msk;
-       }
-       else
-       {       /* ... or use SKp if not */
-               secret = this->ike_sa->get_skp_verify(this->ike_sa);
-       }
-       auth_data = build_shared_key_signature(ike_sa_init, my_nonce, secret,
-                                               other_id, this->ike_sa->get_skp_verify(this->ike_sa),
-                                               this->ike_sa->get_prf(this->ike_sa));
+       other_id = this->ike_sa->get_other_id(this->ike_sa);
+       keymat = this->ike_sa->get_keymat(this->ike_sa);
+       
+       auth_data = keymat->get_psk_sig(keymat, TRUE, ike_sa_init, my_nonce,
+                                                                       this->msk, other_id);
        
        recv_auth_data = auth_payload->get_data(auth_payload);
-       if (!chunk_equals(auth_data, recv_auth_data))
+       if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data))
        {
                DBG1(DBG_IKE, "verification of AUTH payload created from EAP MSK failed");
                chunk_free(&auth_data);
@@ -118,23 +106,18 @@ static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init,
 static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init,
                                          chunk_t other_nonce, auth_payload_t **auth_payload)
 {
-       chunk_t auth_data, secret;
-       identification_t *my_id = this->ike_sa->get_my_id(this->ike_sa);
+       identification_t *my_id;
+       chunk_t auth_data;
+       keymat_t *keymat;
+       
+       my_id = this->ike_sa->get_my_id(this->ike_sa);
+       keymat = this->ike_sa->get_keymat(this->ike_sa);
        
        DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
                 my_id, auth_class_names, AUTH_CLASS_EAP);
-
-       if (this->msk.len)
-       {       /* use MSK if EAP method established one... */
-               secret = this->msk;
-       }
-       else
-       {       /* ... or use SKp if not */
-               secret = this->ike_sa->get_skp_build(this->ike_sa);
-       }
-       auth_data = build_shared_key_signature(ike_sa_init, other_nonce, secret,
-                                                       my_id, this->ike_sa->get_skp_build(this->ike_sa),
-                                                       this->ike_sa->get_prf(this->ike_sa));
+       
+       auth_data = keymat->get_psk_sig(keymat, FALSE, ike_sa_init, other_nonce,
+                                                                       this->msk, my_id);
        
        *auth_payload = auth_payload_create();
        (*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK);
index 9094077..a3c84c4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
 #include <daemon.h>
 #include <credentials/auth_info.h>
 
-/**
- * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
- */
-#define IKEV2_KEY_PAD "Key Pad for IKEv2"
-#define IKEV2_KEY_PAD_LENGTH 17
-
 
 typedef struct private_psk_authenticator_t private_psk_authenticator_t;
 
@@ -49,55 +43,6 @@ struct private_psk_authenticator_t {
 };
 
 /**
- * Builds the octets to be signed as described in section 2.15 of RFC 4306
- */
-chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
-                                                identification_t *id, prf_t *prf)
-{
-       u_int8_t id_header_buf[] = {0x00, 0x00, 0x00, 0x00};
-       chunk_t id_header = chunk_from_buf(id_header_buf);
-       chunk_t id_with_header, id_prfd, id_encoding;
-       
-       id_header_buf[0] = id->get_type(id);
-       id_encoding = id->get_encoding(id);
-       
-       id_with_header = chunk_cat("cc", id_header, id_encoding);
-       prf->allocate_bytes(prf, id_with_header, &id_prfd);
-       chunk_free(&id_with_header);
-       
-       return chunk_cat("ccm", ike_sa_init, nonce, id_prfd);
-}
-
-/**
- * Creates the AUTH data using auth method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
- */
-chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
-                                                                  chunk_t secret, identification_t *id,
-                                                                  chunk_t skp, prf_t *prf)
-{
-       chunk_t key_pad, key, auth_data, octets;
-       
-       prf->set_key(prf, skp);
-       octets = build_tbs_octets(ike_sa_init, nonce, id, prf);
-       /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
-       key_pad.ptr = IKEV2_KEY_PAD;
-       key_pad.len = IKEV2_KEY_PAD_LENGTH;
-       prf->set_key(prf, secret);
-       prf->allocate_bytes(prf, key_pad, &key);
-       prf->set_key(prf, key);
-       prf->allocate_bytes(prf, octets, &auth_data);
-       DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets);
-       DBG3(DBG_IKE, "secret %B", &secret);
-       DBG3(DBG_IKE, "keypad %B", &key_pad);
-       DBG3(DBG_IKE, "prf(secret, keypad) %B", &key);
-       DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", &auth_data);
-       chunk_free(&octets);
-       chunk_free(&key);
-       
-       return auth_data;
-}
-
-/**
  * Implementation of authenticator_t.verify.
  */
 static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
@@ -105,25 +50,25 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
 {
        chunk_t auth_data, recv_auth_data;
        identification_t *my_id, *other_id;
-       shared_key_t *shared_key;
+       shared_key_t *key;
        enumerator_t *enumerator;
        bool authenticated = FALSE;
        int keys_found = 0;
+       keymat_t *keymat;
        
+       keymat = this->ike_sa->get_keymat(this->ike_sa);
+       recv_auth_data = auth_payload->get_data(auth_payload);
        my_id = this->ike_sa->get_my_id(this->ike_sa);
        other_id = this->ike_sa->get_other_id(this->ike_sa);
        enumerator = charon->credentials->create_shared_enumerator(
                                                        charon->credentials, SHARED_IKE, my_id, other_id);
-       while (!authenticated && enumerator->enumerate(enumerator, &shared_key, NULL, NULL))
+       while (!authenticated && enumerator->enumerate(enumerator, &key, NULL, NULL))
        {
                keys_found++;
-               auth_data = build_shared_key_signature(ike_sa_init, my_nonce,
-                                                                       shared_key->get_key(shared_key), other_id,
-                                                                       this->ike_sa->get_skp_verify(this->ike_sa),
-                                                                       this->ike_sa->get_prf(this->ike_sa));
-               recv_auth_data = auth_payload->get_data(auth_payload);
-               if (auth_data.len == recv_auth_data.len &&
-                       memeq(auth_data.ptr, recv_auth_data.ptr, auth_data.len))
+               
+               auth_data = keymat->get_psk_sig(keymat, TRUE, ike_sa_init, my_nonce,
+                                                                               key->get_key(key), other_id);
+               if (auth_data.len && chunk_equals(auth_data, recv_auth_data))
                {
                        DBG1(DBG_IKE, "authentication of '%D' with %N successful",
                                 other_id, auth_method_names, AUTH_PSK);
@@ -153,26 +98,26 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
 static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init,
                                          chunk_t other_nonce, auth_payload_t **auth_payload)
 {
-       shared_key_t *shared_key;
-       chunk_t auth_data;
        identification_t *my_id, *other_id;
+       shared_key_t *key;
+       chunk_t auth_data;
+       keymat_t *keymat;
        
+       keymat = this->ike_sa->get_keymat(this->ike_sa);
        my_id = this->ike_sa->get_my_id(this->ike_sa);
        other_id = this->ike_sa->get_other_id(this->ike_sa);
        DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
                 my_id, auth_method_names, AUTH_PSK);
-       shared_key = charon->credentials->get_shared(charon->credentials, SHARED_IKE,
-                                                                                                my_id, other_id);
-       if (shared_key == NULL)
+       key = charon->credentials->get_shared(charon->credentials, SHARED_IKE,
+                                                                                 my_id, other_id);
+       if (key == NULL)
        {
                DBG1(DBG_IKE, "no shared key found for '%D' - '%D'", my_id, other_id);
                return NOT_FOUND;
        }
-       auth_data = build_shared_key_signature(ike_sa_init, other_nonce,
-                                                                       shared_key->get_key(shared_key), my_id,
-                                                                       this->ike_sa->get_skp_build(this->ike_sa),
-                                                                       this->ike_sa->get_prf(this->ike_sa));
-       shared_key->destroy(shared_key);
+       auth_data = keymat->get_psk_sig(keymat, FALSE, ike_sa_init, other_nonce,
+                                                                       key->get_key(key), my_id);
+       key->destroy(key);
        DBG2(DBG_IKE, "successfully created shared key MAC");
        *auth_payload = auth_payload_create();
        (*auth_payload)->set_auth_method(*auth_payload, AUTH_PSK);
index 46e0be4..49a4283 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Tobias Brunner
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
@@ -44,12 +44,6 @@ struct private_pubkey_authenticator_t {
 };
 
 /**
- * Function implemented in psk_authenticator.c
- */
-extern chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
-                                                               identification_t *id, prf_t *prf);
-
-/**
  * Implementation of authenticator_t.verify.
  */
 static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
@@ -58,15 +52,15 @@ static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init
        public_key_t *public;
        auth_method_t auth_method;
        chunk_t auth_data, octets;
-       identification_t *other_id;
-       prf_t *prf;
+       identification_t *id;
        auth_info_t *auth, *current_auth;
        enumerator_t *enumerator;
        key_type_t key_type = KEY_ECDSA;
        signature_scheme_t scheme;
        status_t status = FAILED;
+       keymat_t *keymat;
        
-       other_id = this->ike_sa->get_other_id(this->ike_sa);
+       id = this->ike_sa->get_other_id(this->ike_sa);
        auth_method = auth_payload->get_auth_method(auth_payload);
        switch (auth_method)
        {
@@ -89,19 +83,17 @@ static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init
                        return INVALID_ARG;
        }
        auth_data = auth_payload->get_data(auth_payload);
-       prf = this->ike_sa->get_prf(this->ike_sa);
-       prf->set_key(prf, this->ike_sa->get_skp_verify(this->ike_sa));
-       octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, prf);
-       
+       keymat = this->ike_sa->get_keymat(this->ike_sa);
+       octets = keymat->get_auth_octets(keymat, TRUE, ike_sa_init, my_nonce, id);
        auth = this->ike_sa->get_other_auth(this->ike_sa);
        enumerator = charon->credentials->create_public_enumerator(
-                                                               charon->credentials, key_type, other_id, auth);
+                                                                               charon->credentials, key_type, id, auth);
        while (enumerator->enumerate(enumerator, &public, &current_auth))
        {
                if (public->verify(public, scheme, octets, auth_data))
                {
                        DBG1(DBG_IKE, "authentication of '%D' with %N successful",
-                                                  other_id, auth_method_names, auth_method);
+                                                  id, auth_method_names, auth_method);
                        status = SUCCESS;
                        auth->merge(auth, current_auth);
                        break;
@@ -125,19 +117,19 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
        chunk_t octets, auth_data;
        status_t status = FAILED;
        private_key_t *private;
-       identification_t *my_id;
-       prf_t *prf;
+       identification_t *id;
        auth_info_t *auth;
        auth_method_t auth_method;
        signature_scheme_t scheme;
+       keymat_t *keymat;
 
-       my_id = this->ike_sa->get_my_id(this->ike_sa);
+       id = this->ike_sa->get_my_id(this->ike_sa);
        auth = this->ike_sa->get_my_auth(this->ike_sa);
        private = charon->credentials->get_private(charon->credentials, KEY_ANY,
-                                                                                          my_id, auth);
+                                                                                          id, auth);
        if (private == NULL)
        {
-               DBG1(DBG_IKE, "no private key found for '%D'", my_id);
+               DBG1(DBG_IKE, "no private key found for '%D'", id);
                return NOT_FOUND;
        }
        
@@ -176,9 +168,8 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
                                        key_type_names, private->get_type(private));
                        return status;
        }
-       prf = this->ike_sa->get_prf(this->ike_sa);
-       prf->set_key(prf, this->ike_sa->get_skp_build(this->ike_sa));
-       octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, prf);
+       keymat = this->ike_sa->get_keymat(this->ike_sa);
+       octets = keymat->get_auth_octets(keymat, FALSE, ike_sa_init, other_nonce, id);
        
        if (private->sign(private, scheme, octets, &auth_data))
        {
@@ -189,9 +180,9 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
                chunk_free(&auth_data);
                status = SUCCESS;
        }
-       DBG1(DBG_IKE, "authentication of '%D' (myself) with %N %s", my_id,
-                       auth_method_names, auth_method,
-                       (status == SUCCESS)? "successful":"failed");
+       DBG1(DBG_IKE, "authentication of '%D' (myself) with %N %s", id,
+                auth_method_names, auth_method, 
+                (status == SUCCESS)? "successful":"failed");
        chunk_free(&octets);
        private->destroy(private);
        
index d4ee4bb..5f02157 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2006-2008 Tobias Brunner
  * Copyright (C) 2006 Daniel Roethlisberger
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
@@ -191,49 +191,9 @@ struct private_ike_sa_t {
        linked_list_t *child_sas;
        
        /**
-        * Selected IKE proposal
+        * keymat of this IKE_SA
         */
-       proposal_t *selected_proposal;
-       
-       /**
-        * crypter for inbound traffic
-        */
-       crypter_t *crypter_in;
-       
-       /**
-        * crypter for outbound traffic
-        */
-       crypter_t *crypter_out;
-       
-       /**
-        * Signer for inbound traffic
-        */
-       signer_t *signer_in;
-       
-       /**
-        * Signer for outbound traffic
-        */
-       signer_t *signer_out;
-       
-       /**
-        * Multi purpose prf, set key, use it, forget it
-        */
-       prf_t *prf;
-       
-       /**
-        * Prf function for derivating keymat child SAs
-        */
-       prf_t *child_prf;
-       
-       /**
-        * Key to build outging authentication data (SKp)
-        */
-       chunk_t skp_build;
-
-       /**
-        * Key to verify incoming authentication data (SKp)
-        */
-       chunk_t skp_verify;
+       keymat_t *keymat;
        
        /**
         * Virtual IP on local host, if any
@@ -743,6 +703,14 @@ static void reset(private_ike_sa_t *this)
 }
 
 /**
+ * Implementation of ike_sa_t.get_keymat
+ */
+static keymat_t* get_keymat(private_ike_sa_t *this)
+{
+       return this->keymat;
+}
+
+/**
  * Implementation of ike_sa_t.set_virtual_ip
  */
 static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
@@ -912,7 +880,9 @@ static status_t generate_message(private_ike_sa_t *this, message_t *message,
 {
        this->stats[STAT_OUTBOUND] = time(NULL);
        message->set_ike_sa_id(message, this->ike_sa_id);
-       return message->generate(message, this->crypter_out, this->signer_out, packet);
+       return message->generate(message,
+                               this->keymat->get_crypter(this->keymat, FALSE),
+                               this->keymat->get_signer(this->keymat, FALSE), packet);
 }
 
 /**
@@ -1335,7 +1305,9 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
        
        is_request = message->get_request(message);
        
-       status = message->parse_body(message, this->crypter_in, this->signer_in);
+       status = message->parse_body(message,
+                                                                this->keymat->get_crypter(this->keymat, TRUE),
+                                                                this->keymat->get_signer(this->keymat, TRUE));
        if (status != SUCCESS)
        {
                
@@ -1473,38 +1445,6 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
 }
 
 /**
- * Implementation of ike_sa_t.get_prf.
- */
-static prf_t *get_prf(private_ike_sa_t *this)
-{
-       return this->prf;
-}
-
-/**
- * Implementation of ike_sa_t.get_prf.
- */
-static prf_t *get_child_prf(private_ike_sa_t *this)
-{
-       return this->child_prf;
-}
-
-/**
- * Implementation of ike_sa_t.get_skp_bild
- */
-static chunk_t get_skp_build(private_ike_sa_t *this)
-{
-       return this->skp_build;
-}
-
-/**
- * Implementation of ike_sa_t.get_skp_verify
- */
-static chunk_t get_skp_verify(private_ike_sa_t *this)
-{
-       return this->skp_verify;
-}
-
-/**
  * Implementation of ike_sa_t.get_id.
  */
 static ike_sa_id_t* get_id(private_ike_sa_t *this)
@@ -1564,224 +1504,6 @@ static void set_eap_identity(private_ike_sa_t *this, identification_t *id)
 }
 
 /**
- * Implementation of ike_sa_t.derive_keys.
- */
-static status_t derive_keys(private_ike_sa_t *this,
-                                                       proposal_t *proposal, chunk_t secret,
-                                                       chunk_t nonce_i, chunk_t nonce_r,
-                                                       bool initiator, prf_t *child_prf, prf_t *old_prf)
-{
-       prf_plus_t *prf_plus;
-       chunk_t skeyseed, key, full_nonce, fixed_nonce, prf_plus_seed;
-       u_int16_t alg, key_size;
-       crypter_t *crypter_i, *crypter_r;
-       signer_t *signer_i, *signer_r;
-       u_int8_t spi_i_buf[sizeof(u_int64_t)], spi_r_buf[sizeof(u_int64_t)];
-       chunk_t spi_i = chunk_from_buf(spi_i_buf);
-       chunk_t spi_r = chunk_from_buf(spi_r_buf);
-       
-       /* Create SAs general purpose PRF first, we may use it here */
-       if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
-       {
-               DBG1(DBG_IKE, "no %N selected",
-                        transform_type_names, PSEUDO_RANDOM_FUNCTION);
-               return FAILED;
-       }
-       this->prf = lib->crypto->create_prf(lib->crypto, alg);
-       if (this->prf == NULL)
-       {
-               DBG1(DBG_IKE, "%N %N not supported!",
-                        transform_type_names, PSEUDO_RANDOM_FUNCTION,
-                        pseudo_random_function_names, alg);
-               return FAILED;
-       }
-       DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
-       /* full nonce is used as seed for PRF+ ... */
-       full_nonce = chunk_cat("cc", nonce_i, nonce_r);
-       /* but the PRF may need a fixed key which only uses the first bytes of
-        * the nonces. */
-       switch (alg)
-       {
-               case PRF_AES128_XCBC:
-                       /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does
-                        * not and therefore fixed key semantics apply to XCBC for key
-                        * derivation. */
-                       nonce_i.len = min(nonce_i.len, this->prf->get_key_size(this->prf)/2);
-                       nonce_r.len = min(nonce_r.len, this->prf->get_key_size(this->prf)/2);
-                       break;
-               default:
-                       /* all other algorithms use variable key length, full nonce */
-                       break;
-       }
-       fixed_nonce = chunk_cat("cc", nonce_i, nonce_r);
-       *((u_int64_t*)spi_i.ptr) = this->ike_sa_id->get_initiator_spi(this->ike_sa_id);
-       *((u_int64_t*)spi_r.ptr) = this->ike_sa_id->get_responder_spi(this->ike_sa_id);
-       prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r);
-       
-       /* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr) 
-        *
-        * if we are rekeying, SKEYSEED is built on another way
-        */
-       if (child_prf == NULL) /* not rekeying */
-       {
-               /* SKEYSEED = prf(Ni | Nr, g^ir) */
-               this->prf->set_key(this->prf, fixed_nonce);
-               this->prf->allocate_bytes(this->prf, secret, &skeyseed);
-               DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
-               this->prf->set_key(this->prf, skeyseed);
-               chunk_clear(&skeyseed);
-               chunk_clear(&secret);
-               prf_plus = prf_plus_create(this->prf, prf_plus_seed);
-       }
-       else
-       {
-               /* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr) 
-                * use OLD SAs PRF functions for both prf_plus and prf */
-               secret = chunk_cat("mc", secret, full_nonce);
-               child_prf->allocate_bytes(child_prf, secret, &skeyseed);
-               DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
-               old_prf->set_key(old_prf, skeyseed);
-               chunk_clear(&skeyseed);
-               chunk_clear(&secret);
-               prf_plus = prf_plus_create(old_prf, prf_plus_seed);
-       }
-       chunk_free(&full_nonce);
-       chunk_free(&fixed_nonce);
-       chunk_clear(&prf_plus_seed);
-       
-       /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */
-       
-       /* SK_d is used for generating CHILD_SA key mat => child_prf */
-       proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL);
-       this->child_prf = lib->crypto->create_prf(lib->crypto, alg);
-       key_size = this->child_prf->get_key_size(this->child_prf);
-       prf_plus->allocate_bytes(prf_plus, key_size, &key);
-       DBG4(DBG_IKE, "Sk_d secret %B", &key);
-       this->child_prf->set_key(this->child_prf, key);
-       chunk_clear(&key);
-       
-       /* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */
-       if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
-       {
-               DBG1(DBG_IKE, "no %N selected",
-                        transform_type_names, INTEGRITY_ALGORITHM);
-               return FAILED;
-       }
-       signer_i = lib->crypto->create_signer(lib->crypto, alg);
-       signer_r = lib->crypto->create_signer(lib->crypto, alg);
-       if (signer_i == NULL || signer_r == NULL)
-       {
-               DBG1(DBG_IKE, "%N %N not supported!",
-                        transform_type_names, INTEGRITY_ALGORITHM,
-                        integrity_algorithm_names ,alg);
-               prf_plus->destroy(prf_plus);
-               return FAILED;
-       }
-       key_size = signer_i->get_key_size(signer_i);
-       
-       prf_plus->allocate_bytes(prf_plus, key_size, &key);
-       DBG4(DBG_IKE, "Sk_ai secret %B", &key);
-       signer_i->set_key(signer_i, key);
-       chunk_clear(&key);
-       
-       prf_plus->allocate_bytes(prf_plus, key_size, &key);
-       DBG4(DBG_IKE, "Sk_ar secret %B", &key);
-       signer_r->set_key(signer_r, key);
-       chunk_clear(&key);
-       
-       if (initiator)
-       {
-               this->signer_in = signer_r;
-               this->signer_out = signer_i;
-       }
-       else
-       {
-               this->signer_in = signer_i;
-               this->signer_out = signer_r;
-       }
-       
-       /* SK_ei/SK_er used for encryption => crypter_in/crypter_out */
-       if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size))
-       {
-               DBG1(DBG_IKE, "no %N selected",
-                        transform_type_names, ENCRYPTION_ALGORITHM);
-               prf_plus->destroy(prf_plus);
-               return FAILED;
-       }
-       crypter_i = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
-       crypter_r = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
-       if (crypter_i == NULL || crypter_r == NULL)
-       {
-               DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
-                        transform_type_names, ENCRYPTION_ALGORITHM,
-                        encryption_algorithm_names, alg, key_size);
-               prf_plus->destroy(prf_plus);
-               return FAILED;
-       }
-       key_size = crypter_i->get_key_size(crypter_i);
-       
-       prf_plus->allocate_bytes(prf_plus, key_size, &key);
-       DBG4(DBG_IKE, "Sk_ei secret %B", &key);
-       crypter_i->set_key(crypter_i, key);
-       chunk_clear(&key);
-       
-       prf_plus->allocate_bytes(prf_plus, key_size, &key);
-       DBG4(DBG_IKE, "Sk_er secret %B", &key);
-       crypter_r->set_key(crypter_r, key);
-       chunk_clear(&key);
-       
-       if (initiator)
-       {
-               this->crypter_in = crypter_r;
-               this->crypter_out = crypter_i;
-       }
-       else
-       {
-               this->crypter_in = crypter_i;
-               this->crypter_out = crypter_r;
-       }
-       
-       /* SK_pi/SK_pr used for authentication => stored for later */   
-       key_size = this->prf->get_key_size(this->prf);
-       prf_plus->allocate_bytes(prf_plus, key_size, &key);
-       DBG4(DBG_IKE, "Sk_pi secret %B", &key);
-       if (initiator)
-       {
-               this->skp_build = key;
-       }
-       else
-       {
-               this->skp_verify = key;
-       }
-       prf_plus->allocate_bytes(prf_plus, key_size, &key);
-       DBG4(DBG_IKE, "Sk_pr secret %B", &key);
-       if (initiator)
-       {
-               this->skp_verify = key;
-       }
-       else
-       {
-               this->skp_build = key;
-       }
-       
-       /* all done, prf_plus not needed anymore */
-       prf_plus->destroy(prf_plus);
-       
-       /* save selected proposal */
-       this->selected_proposal = proposal->clone(proposal);
-       
-       return SUCCESS;
-}
-
-/**
- * Implementation of ike_sa_t.get_proposal.
- */
-static proposal_t* get_proposal(private_ike_sa_t *this)
-{
-       return this->selected_proposal;
-}
-
-/**
  * Implementation of ike_sa_t.add_child_sa.
  */
 static void add_child_sa(private_ike_sa_t *this, child_sa_t *child_sa)
@@ -2452,16 +2174,7 @@ static void destroy(private_ike_sa_t *this)
        charon->bus->set_sa(charon->bus, NULL);
        
        this->task_manager->destroy(this->task_manager);
-       
-       DESTROY_IF(this->crypter_in);
-       DESTROY_IF(this->crypter_out);
-       DESTROY_IF(this->signer_in);
-       DESTROY_IF(this->signer_out);
-       DESTROY_IF(this->prf);
-       DESTROY_IF(this->child_prf);
-       chunk_free(&this->skp_verify);
-       chunk_free(&this->skp_build);
-       DESTROY_IF(this->selected_proposal);
+       this->keymat->destroy(this->keymat);
        
        if (this->my_virtual_ip)
        {
@@ -2561,12 +2274,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->public.destroy = (void (*)(ike_sa_t*))destroy;
        this->public.send_dpd = (status_t (*)(ike_sa_t*)) send_dpd;
        this->public.send_keepalive = (void (*)(ike_sa_t*)) send_keepalive;
-       this->public.get_prf = (prf_t* (*)(ike_sa_t*)) get_prf;
-       this->public.get_child_prf = (prf_t* (*)(ike_sa_t *)) get_child_prf;
-       this->public.get_skp_verify = (chunk_t (*)(ike_sa_t *)) get_skp_verify;
-       this->public.get_skp_build = (chunk_t (*)(ike_sa_t *)) get_skp_build;
-       this->public.derive_keys = (status_t (*)(ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys;
-       this->public.get_proposal = (proposal_t* (*)(ike_sa_t*)) get_proposal;
+       this->public.get_keymat = (keymat_t*(*)(ike_sa_t*))get_keymat;
        this->public.add_child_sa = (void (*)(ike_sa_t*,child_sa_t*)) add_child_sa;
        this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa;
        this->public.create_child_sa_iterator = (iterator_t* (*)(ike_sa_t*)) create_child_sa_iterator;
@@ -2607,15 +2315,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
        this->eap_identity = NULL;
        this->extensions = 0;
        this->conditions = 0;
-       this->selected_proposal = NULL;
-       this->crypter_in = NULL;
-       this->crypter_out = NULL;
-       this->signer_in = NULL;
-       this->signer_out = NULL;
-       this->prf = NULL;
-       this->skp_verify = chunk_empty;
-       this->skp_build = chunk_empty;
-       this->child_prf = NULL;
+       this->keymat = keymat_create(ike_sa_id->is_initiator(ike_sa_id));
        this->state = IKE_CREATED;
        this->keepalive_interval = lib->settings->get_time(lib->settings,
                                                                        "charon.keep_alive", KEEPALIVE_INTERVAL);
index a438e41..354f026 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2006-2008 Tobias Brunner
  * Copyright (C) 2006 Daniel Roethlisberger
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
@@ -38,9 +38,7 @@ typedef struct ike_sa_t ike_sa_t;
 #include <sa/ike_sa_id.h>
 #include <sa/child_sa.h>
 #include <sa/tasks/task.h>
-#include <crypto/prfs/prf.h>
-#include <crypto/crypters/crypter.h>
-#include <crypto/signers/signer.h>
+#include <sa/keymat.h>
 #include <config/peer_cfg.h>
 #include <config/ike_cfg.h>
 #include <credentials/auth_info.h>
@@ -714,62 +712,13 @@ struct ike_sa_t {
         * was sent.
         */
        void (*send_keepalive) (ike_sa_t *this);
-
-       /**
-        * Derive all keys and create the transforms for IKE communication.
-        *
-        * Keys are derived using the diffie hellman secret, nonces and internal
-        * stored SPIs.
-        * Key derivation differs when an IKE_SA is set up to replace an
-        * existing IKE_SA (rekeying). The SK_d key from the old IKE_SA
-        * is included in the derivation process.
-        *
-        * @param proposal              proposal which contains algorithms to use
-        * @param secret                secret derived from DH exchange, gets freed
-        * @param nonce_i               initiators nonce
-        * @param nonce_r               responders nonce
-        * @param initiator             TRUE if initiator, FALSE otherwise
-        * @param child_prf             PRF with SK_d key when rekeying, NULL otherwise
-        * @param old_prf               general purpose PRF of old SA when rekeying
-        */
-       status_t (*derive_keys)(ike_sa_t *this, proposal_t* proposal, chunk_t secret,
-                                                       chunk_t nonce_i, chunk_t nonce_r,
-                                                       bool initiator, prf_t *child_prf, prf_t *old_prf);
        
        /**
-        * Get the selected IKE proposal
+        * Get the keying material of this IKE_SA.
         *
-        * @return                              selected IKE proposal
-        */
-       proposal_t* (*get_proposal)(ike_sa_t *this);                                    
-
-       /**
-        * Get a multi purpose prf for the negotiated PRF function.
-        * 
-        * @return                              pointer to prf_t object
-        */
-       prf_t *(*get_prf) (ike_sa_t *this);
-       
-       /**
-        * Get the prf-object, which is used to derive keys for child SAs.
-        * 
-        * @return                              pointer to prf_t object
-        */
-       prf_t *(*get_child_prf) (ike_sa_t *this);
-       
-       /**
-        * Get the key to build outgoing authentication data.
-        * 
-        * @return                              pointer to prf_t object
-        */
-       chunk_t (*get_skp_build) (ike_sa_t *this);
-       
-       /**
-        * Get the key to verify incoming authentication data.
-        * 
-        * @return                              pointer to prf_t object
+        * @return                              per IKE_SA keymat instance
         */
-       chunk_t (*get_skp_verify) (ike_sa_t *this);
+       keymat_t* (*get_keymat)(ike_sa_t *this);
        
        /**
         * Associates a child SA to this IKE SA
diff --git a/src/charon/sa/keymat.c b/src/charon/sa/keymat.c
new file mode 100644 (file)
index 0000000..4af33dd
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * $Id$
+ */
+
+#include "keymat.h"
+
+#include <daemon.h>
+#include <crypto/prf_plus.h>
+
+typedef struct private_keymat_t private_keymat_t;
+
+/**
+ * Private data of an keymat_t object.
+ */
+struct private_keymat_t {
+       
+       /**
+        * Public keymat_t interface.
+        */
+       keymat_t public;
+       
+       /**
+        * IKE_SA Role, initiator or responder
+        */
+       bool initiator;
+       
+       /**
+        * diffie hellman key exchange
+        */
+       diffie_hellman_t *dh;
+       
+       /**
+        * inbound signer (verify)
+        */
+       signer_t *signer_in;
+       
+       /**
+        * outbound signer (sign)
+        */
+       signer_t *signer_out;
+       
+       /**
+        * inbound crypter (decrypt)
+        */
+       crypter_t *crypter_in;
+       
+       /**
+        * outbound crypter (encrypt)
+        */
+       crypter_t *crypter_out;
+       
+       /**
+        * General purpose PRF
+        */
+       prf_t *prf;
+       
+       /**
+        * PRF for CHILD_SA keymat
+        */
+       prf_t *child_prf;
+       
+       /**
+        * Key to build outging authentication data (SKp)
+        */
+       chunk_t skp_build;
+
+       /**
+        * Key to verify incoming authentication data (SKp)
+        */
+       chunk_t skp_verify;
+       
+       /**
+        * Negotiated IKE proposal
+        */
+       proposal_t *proposal;
+};
+
+/**
+ * Implementation of keymat_t.set_dh_group
+ */
+static bool set_dh_group(private_keymat_t *this, diffie_hellman_group_t group)
+{
+       DESTROY_IF(this->dh);
+       this->dh = lib->crypto->create_dh(lib->crypto, group);
+       return this->dh != NULL;
+}
+
+/**
+ * Implementation of keymat_t.get_dh
+ */
+static diffie_hellman_t* get_dh(private_keymat_t *this)
+{
+       return this->dh;
+}
+
+/**
+ * Implementation of keymat_t.derive_keys
+ */
+static bool derive_keys(private_keymat_t *this, proposal_t *proposal,
+                                               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;
+       crypter_t *crypter_i, *crypter_r;
+       signer_t *signer_i, *signer_r;
+       prf_plus_t *prf_plus;
+       u_int16_t alg, key_size;
+       
+       spi_i = chunk_alloca(sizeof(u_int64_t));
+       spi_r = chunk_alloca(sizeof(u_int64_t));
+       
+       if (!this->dh || this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
+       {
+               return FALSE;
+       }
+       
+       /* Create SAs general purpose PRF first, we may use it here */
+       if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
+       {
+               DBG1(DBG_IKE, "no %N selected",
+                        transform_type_names, PSEUDO_RANDOM_FUNCTION);
+               return FALSE;
+       }
+       this->prf = lib->crypto->create_prf(lib->crypto, alg);
+       if (this->prf == NULL)
+       {
+               DBG1(DBG_IKE, "%N %N not supported!",
+                        transform_type_names, PSEUDO_RANDOM_FUNCTION,
+                        pseudo_random_function_names, alg);
+               return FALSE;
+       }
+       DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
+       /* full nonce is used as seed for PRF+ ... */
+       full_nonce = chunk_cat("cc", nonce_i, nonce_r);
+       /* but the PRF may need a fixed key which only uses the first bytes of
+        * the nonces. */
+       switch (alg)
+       {
+               case PRF_AES128_XCBC:
+                       /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does
+                        * not and therefore fixed key semantics apply to XCBC for key
+                        * derivation. */
+                       nonce_i.len = min(nonce_i.len, this->prf->get_key_size(this->prf)/2);
+                       nonce_r.len = min(nonce_r.len, this->prf->get_key_size(this->prf)/2);
+                       break;
+               default:
+                       /* all other algorithms use variable key length, full nonce */
+                       break;
+       }
+       fixed_nonce = chunk_cat("cc", nonce_i, nonce_r);
+       *((u_int64_t*)spi_i.ptr) = id->get_initiator_spi(id);
+       *((u_int64_t*)spi_r.ptr) = id->get_responder_spi(id);
+       prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r);
+       
+       /* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr) 
+        *
+        * if we are rekeying, SKEYSEED is built on another way
+        */
+       if (rekey == NULL) /* not rekeying */
+       {
+               /* SKEYSEED = prf(Ni | Nr, g^ir) */
+               this->prf->set_key(this->prf, fixed_nonce);
+               this->prf->allocate_bytes(this->prf, secret, &skeyseed);
+               DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
+               this->prf->set_key(this->prf, skeyseed);
+               chunk_clear(&skeyseed);
+               chunk_clear(&secret);
+               prf_plus = prf_plus_create(this->prf, prf_plus_seed);
+       }
+       else
+       {
+               /* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr) 
+                * use OLD SAs PRF functions for both prf_plus and prf */
+               secret = chunk_cat("mc", secret, full_nonce);
+               rekey->child_prf->allocate_bytes(rekey->child_prf, secret, &skeyseed);
+               DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
+               rekey->prf->set_key(rekey->prf, skeyseed);
+               chunk_clear(&skeyseed);
+               chunk_clear(&secret);
+               prf_plus = prf_plus_create(rekey->prf, prf_plus_seed);
+       }
+       chunk_free(&full_nonce);
+       chunk_free(&fixed_nonce);
+       chunk_clear(&prf_plus_seed);
+       
+       /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */
+       
+       /* SK_d is used for generating CHILD_SA key mat => child_prf */
+       proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL);
+       this->child_prf = lib->crypto->create_prf(lib->crypto, alg);
+       key_size = this->child_prf->get_key_size(this->child_prf);
+       prf_plus->allocate_bytes(prf_plus, key_size, &key);
+       DBG4(DBG_IKE, "Sk_d secret %B", &key);
+       this->child_prf->set_key(this->child_prf, key);
+       chunk_clear(&key);
+       
+       /* SK_ai/SK_ar used for integrity protection => signer_in/signer_out */
+       if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
+       {
+               DBG1(DBG_IKE, "no %N selected",
+                        transform_type_names, INTEGRITY_ALGORITHM);
+               return FALSE;
+       }
+       signer_i = lib->crypto->create_signer(lib->crypto, alg);
+       signer_r = lib->crypto->create_signer(lib->crypto, alg);
+       if (signer_i == NULL || signer_r == NULL)
+       {
+               DBG1(DBG_IKE, "%N %N not supported!",
+                        transform_type_names, INTEGRITY_ALGORITHM,
+                        integrity_algorithm_names ,alg);
+               prf_plus->destroy(prf_plus);
+               return FALSE;
+       }
+       key_size = signer_i->get_key_size(signer_i);
+       
+       prf_plus->allocate_bytes(prf_plus, key_size, &key);
+       DBG4(DBG_IKE, "Sk_ai secret %B", &key);
+       signer_i->set_key(signer_i, key);
+       chunk_clear(&key);
+       
+       prf_plus->allocate_bytes(prf_plus, key_size, &key);
+       DBG4(DBG_IKE, "Sk_ar secret %B", &key);
+       signer_r->set_key(signer_r, key);
+       chunk_clear(&key);
+       
+       if (this->initiator)
+       {
+               this->signer_in = signer_r;
+               this->signer_out = signer_i;
+       }
+       else
+       {
+               this->signer_in = signer_i;
+               this->signer_out = signer_r;
+       }
+       
+       /* SK_ei/SK_er used for encryption => crypter_in/crypter_out */
+       if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size))
+       {
+               DBG1(DBG_IKE, "no %N selected",
+                        transform_type_names, ENCRYPTION_ALGORITHM);
+               prf_plus->destroy(prf_plus);
+               return FALSE;
+       }
+       crypter_i = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
+       crypter_r = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
+       if (crypter_i == NULL || crypter_r == NULL)
+       {
+               DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
+                        transform_type_names, ENCRYPTION_ALGORITHM,
+                        encryption_algorithm_names, alg, key_size);
+               prf_plus->destroy(prf_plus);
+               return FALSE;
+       }
+       key_size = crypter_i->get_key_size(crypter_i);
+       
+       prf_plus->allocate_bytes(prf_plus, key_size, &key);
+       DBG4(DBG_IKE, "Sk_ei secret %B", &key);
+       crypter_i->set_key(crypter_i, key);
+       chunk_clear(&key);
+       
+       prf_plus->allocate_bytes(prf_plus, key_size, &key);
+       DBG4(DBG_IKE, "Sk_er secret %B", &key);
+       crypter_r->set_key(crypter_r, key);
+       chunk_clear(&key);
+       
+       if (this->initiator)
+       {
+               this->crypter_in = crypter_r;
+               this->crypter_out = crypter_i;
+       }
+       else
+       {
+               this->crypter_in = crypter_i;
+               this->crypter_out = crypter_r;
+       }
+       
+       /* SK_pi/SK_pr used for authentication => stored for later */   
+       key_size = this->prf->get_key_size(this->prf);
+       prf_plus->allocate_bytes(prf_plus, key_size, &key);
+       DBG4(DBG_IKE, "Sk_pi secret %B", &key);
+       if (this->initiator)
+       {
+               this->skp_build = key;
+       }
+       else
+       {
+               this->skp_verify = key;
+       }
+       prf_plus->allocate_bytes(prf_plus, key_size, &key);
+       DBG4(DBG_IKE, "Sk_pr secret %B", &key);
+       if (this->initiator)
+       {
+               this->skp_verify = key;
+       }
+       else
+       {
+               this->skp_build = key;
+       }
+       
+       /* all done, prf_plus not needed anymore */
+       prf_plus->destroy(prf_plus);
+       
+       /* save selected proposal */
+       this->proposal = proposal->clone(proposal);
+       
+       return TRUE;
+}
+
+/**
+ * Implementation of keymat_t.get_proposal
+ */
+static proposal_t* get_proposal(private_keymat_t *this)
+{
+       return this->proposal;
+}
+
+/**
+ * Implementation of keymat_t.get_signer
+ */
+static signer_t* get_signer(private_keymat_t *this, bool in)
+{
+       return in ? this->signer_in : this->signer_out;
+}
+
+/**
+ * Implementation of keymat_t.get_crypter
+ */
+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
+ */
+static chunk_t get_auth_octets(private_keymat_t *this, bool verify,
+                                                          chunk_t ike_sa_init, chunk_t nonce,
+                                                          identification_t *id)
+{
+       chunk_t chunk, idx, octets;
+       chunk_t skp;
+       
+       skp = verify ? this->skp_verify : this->skp_build;
+       
+       chunk = chunk_alloca(4);
+       memset(chunk.ptr, 0, chunk.len);
+       chunk.ptr[0] = id->get_type(id);
+       idx = chunk_cata("cc", chunk, id->get_encoding(id));
+       
+       DBG3(DBG_IKE, "IDx' %B", &idx);
+       DBG3(DBG_IKE, "SK_p %B", &skp);
+       this->prf->set_key(this->prf, skp);
+       this->prf->allocate_bytes(this->prf, idx, &chunk);
+       
+       octets = chunk_cat("ccm", ike_sa_init, nonce, chunk);
+       DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets);
+       return octets;
+}
+
+/**
+ * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
+ */
+#define IKEV2_KEY_PAD "Key Pad for IKEv2"
+#define IKEV2_KEY_PAD_LENGTH 17
+
+/**
+ * Implementation of keymat_t.get_psk_sig
+ */
+static chunk_t get_psk_sig(private_keymat_t *this, bool verify, 
+                                                  chunk_t ike_sa_init, chunk_t nonce, chunk_t secret,
+                                                  identification_t *id)
+{
+       chunk_t key_pad, key, sig, octets;
+       
+       if (!secret.len)
+       {       /* EAP uses SK_p if no MSK has been established */
+               secret = verify ? this->skp_verify : this->skp_build;
+       }
+       octets = get_auth_octets(this, verify, ike_sa_init, nonce, id);
+       /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
+       key_pad = chunk_create(IKEV2_KEY_PAD, IKEV2_KEY_PAD_LENGTH);
+       this->prf->set_key(this->prf, secret);
+       this->prf->allocate_bytes(this->prf, key_pad, &key);
+       this->prf->set_key(this->prf, key);
+       this->prf->allocate_bytes(this->prf, octets, &sig);
+       DBG4(DBG_IKE, "secret %B", &secret);
+       DBG4(DBG_IKE, "prf(secret, keypad) %B", &key);
+       DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", &sig);
+       chunk_free(&octets);
+       chunk_free(&key);
+       
+       return sig;
+}
+
+/**
+ * Implementation of keymat_t.destroy.
+ */
+static void destroy(private_keymat_t *this)
+{
+       DESTROY_IF(this->dh);
+       DESTROY_IF(this->signer_in);
+       DESTROY_IF(this->signer_out);
+       DESTROY_IF(this->crypter_in);
+       DESTROY_IF(this->crypter_out);
+       DESTROY_IF(this->prf);
+       DESTROY_IF(this->child_prf);
+       DESTROY_IF(this->proposal);
+       chunk_clear(&this->skp_verify);
+       chunk_clear(&this->skp_build);
+       free(this);
+}
+
+/**
+ * See header
+ */
+keymat_t *keymat_create(bool initiator)
+{
+       private_keymat_t *this = malloc_thing(private_keymat_t);
+       
+       this->public.set_dh_group = (bool(*)(keymat_t*, diffie_hellman_group_t group))set_dh_group;
+       this->public.get_dh = (diffie_hellman_t*(*)(keymat_t*))get_dh;
+       this->public.derive_keys = (bool(*)(keymat_t*, proposal_t *proposal, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, keymat_t *rekey))derive_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;
+       
+       this->initiator = initiator;
+       
+       this->dh = NULL;
+       this->signer_in = NULL;
+       this->signer_out = NULL;
+       this->crypter_in = NULL;
+       this->crypter_out = NULL;
+       this->prf = NULL;
+       this->child_prf = NULL;
+       this->proposal = NULL;
+       this->skp_verify = chunk_empty;
+       this->skp_build = chunk_empty;
+       
+       return &this->public;
+}
+
diff --git a/src/charon/sa/keymat.h b/src/charon/sa/keymat.h
new file mode 100644 (file)
index 0000000..c41c022
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup keymat keymat
+ * @{ @ingroup sa
+ */
+
+#ifndef KEYMAT_H_
+#define KEYMAT_H_
+
+#include <library.h>
+#include <utils/identification.h>
+#include <crypto/prfs/prf.h>
+#include <crypto/crypters/crypter.h>
+#include <crypto/signers/signer.h>
+#include <config/proposal.h>
+#include <sa/ike_sa_id.h>
+
+typedef struct keymat_t keymat_t;
+
+/**
+ * Derivation an management of sensitive keying material.
+ */
+struct keymat_t {
+
+       /**
+        * Set the diffie hellman group to use.
+        *
+        * @param group         diffie hellman group to use
+        * @return                      TRUE if group supported
+        */
+       bool (*set_dh_group)(keymat_t *this, diffie_hellman_group_t group);
+       
+       /**
+        * Get the diffie hellman key agreement interface.
+        *
+        * Call set_dh_group() before acquiring this interface.
+        *
+        * @return                      key agreement interface
+        */
+       diffie_hellman_t* (*get_dh)(keymat_t *this);
+       
+       /**
+        * Derive keys from the shared secret.
+        *
+        * @param proposal      selected algorithms
+        * @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, chunk_t nonce_i,
+                                               chunk_t nonce_r, ike_sa_id_t *id, keymat_t *rekey);
+       /**
+        * Get a signer to sign/verify IKE messages.
+        *
+        * @param in            TRUE for inbound (verify), FALSE for outbound (sign)
+        * @return                      signer
+        */
+       signer_t* (*get_signer)(keymat_t *this, bool in);
+       
+       /*
+        * Get a crypter to en-/decrypt IKE messages.
+        *
+        * @param in            TRUE for inbound (decrypt), FALSE for outbound (encrypt)
+        * @return                      crypter
+        */
+       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().
+        *
+        * @return                      selected proposal
+        */
+       proposal_t* (*get_proposal)(keymat_t *this);
+       
+       /**
+        * Generate octets to use for authentication procedure (RFC4306 2.15).
+        *
+        * This method creates the plain octets and is usually signed by a private
+        * key. PSK and EAP authentication include a secret into the data, use
+        * the get_psk_sig() method instead.
+        *
+        * @param verify                TRUE to create for verfification, FALSE to sign
+        * @param ike_sa_init   encoded ike_sa_init message
+        * @param nonce                 nonce value
+        * @param id                    identity
+        * @return                              authentication octets
+        */
+       chunk_t (*get_auth_octets)(keymat_t *this, bool verify, chunk_t ike_sa_init,
+                                                          chunk_t nonce, identification_t *id);
+       /**
+        * Build the shared secret signature used for PSK and EAP authentication.
+        *
+        * This method wraps the get_auth_octets() method and additionally
+        * includes the secret into the signature. If no secret is given, SK_p is
+        * used as secret (used for EAP methods without MSK).
+        *
+        * @param verify                TRUE to create for verfification, FALSE to sign
+        * @param ike_sa_init   encoded ike_sa_init message
+        * @param nonce                 nonce value
+        * @param secret                optional secret to include into signature
+        * @param id                    identity
+        * @return                              signature octets
+        */
+       chunk_t (*get_psk_sig)(keymat_t *this, bool verify, chunk_t ike_sa_init,
+                                                  chunk_t nonce, chunk_t secret, identification_t *id);
+       /**
+        * Destroy a keymat_t.
+        */
+       void (*destroy)(keymat_t *this);
+};
+
+/**
+ * Create a keymat instance.
+ *
+ * @param initiator            TRUE if we are the initiator
+ * @return                             keymat instance
+ */
+keymat_t *keymat_create(bool initiator);
+
+#endif /* KEYMAT_ @}*/
index bf447d6..8f2329c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Tobias Brunner
- * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
@@ -196,6 +196,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
        chunk_t nonce_i, nonce_r, secret, seed;
        linked_list_t *my_ts, *other_ts;
        host_t *me, *other, *other_vip, *my_vip;
+       keymat_t *keymat;
        
        if (this->proposals == NULL)
        {
@@ -351,7 +352,8 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
                return NOT_FOUND;
        }
        
-       prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
+       keymat = this->ike_sa->get_keymat(this->ike_sa);
+       prf_plus = prf_plus_create(keymat->get_child_prf(keymat), seed);
        if (this->initiator)
        {
                status = this->child_sa->update(this->child_sa, this->proposal,
index c109bff..bc7d2dd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Tobias Brunner
- * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
@@ -64,11 +64,16 @@ struct private_ike_init_t {
        diffie_hellman_group_t dh_group;
        
        /**
-        * Diffie hellman object used to generate public DH value.
+        * diffie hellman key exchange
         */
        diffie_hellman_t *dh;
        
        /**
+        * Keymat derivation (from IKE_SA)
+        */
+       keymat_t *keymat;
+       
+       /**
         * nonce chosen by us
         */
        chunk_t my_nonce;
@@ -192,7 +197,10 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
                                this->dh_group = ke_payload->get_dh_group_number(ke_payload);
                                if (!this->initiator)
                                {
-                                       this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
+                                       if (this->keymat->set_dh_group(this->keymat, this->dh_group))
+                                       {
+                                               this->dh = this->keymat->get_dh(this->keymat);
+                                       }
                                }
                                if (this->dh)
                                {
@@ -241,18 +249,18 @@ static status_t build_i(private_ike_init_t *this, message_t *message)
                DBG1(DBG_IKE, "giving up after %d retries", MAX_RETRIES);
                return FAILED;
        }
-
+       
        /* if the DH group is set via use_dh_group(), we already have a DH object */
        if (!this->dh)
        {
                this->dh_group = this->config->get_dh_group(this->config);
-               this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
-               if (this->dh == NULL)
+               if (!this->keymat->set_dh_group(this->keymat, this->dh_group))
                {
                        DBG1(DBG_IKE, "configured DH group %N not supported",
                                diffie_hellman_group_names, this->dh_group);
                        return FAILED;
                }
+               this->dh = this->keymat->get_dh(this->keymat);
        }
        
        /* generate nonce only when we are trying the first time */
@@ -368,9 +376,9 @@ static status_t process_r(private_ike_init_t *this, message_t *message)
  */
 static status_t build_r(private_ike_init_t *this, message_t *message)
 {
-       chunk_t secret;
-       status_t status;
-
+       keymat_t *old_keymat = NULL;
+       ike_sa_id_t *id;
+       
        /* check if we have everything we need */
        if (this->proposal == NULL ||
                this->other_nonce.len == 0 || this->my_nonce.len == 0)
@@ -381,8 +389,7 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
        }
        
        if (this->dh == NULL ||
-               !this->proposal->has_dh_group(this->proposal, this->dh_group) ||
-               this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
+               !this->proposal->has_dh_group(this->proposal, this->dh_group))
        {
                u_int16_t group;
                
@@ -404,30 +411,14 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
                return FAILED;
        }
        
+       id = this->ike_sa->get_id(this->ike_sa);
        if (this->old_sa)
-       {
-               ike_sa_id_t *id;
-               prf_t *prf, *child_prf;
-                               
-               /* Apply SPI if we are rekeying */
-               id = this->ike_sa->get_id(this->ike_sa);
+       {       /* rekeying: Apply SPI, include keymat from old SA in key derivation */
                id->set_initiator_spi(id, this->proposal->get_spi(this->proposal));
-       
-               /* setup crypto keys for the rekeyed SA */
-               prf = this->old_sa->get_prf(this->old_sa);
-               child_prf = this->old_sa->get_child_prf(this->old_sa);
-               status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, 
-                                                                                  this->other_nonce, this->my_nonce,
-                                                                                  FALSE, child_prf, prf);
+               old_keymat = this->old_sa->get_keymat(this->old_sa);
        }
-       else
-       {
-               /* setup crypto keys */
-               status =  this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, 
-                                                                                   this->other_nonce, this->my_nonce,
-                                                                                   FALSE, NULL, NULL);
-       }
-       if (status != SUCCESS)
+       if (!this->keymat->derive_keys(this->keymat, this->proposal, this->other_nonce,
+                                                                  this->my_nonce, id, old_keymat))
        {
                DBG1(DBG_IKE, "key derivation failed");
                message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
@@ -443,8 +434,8 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
  */
 static status_t process_i(private_ike_init_t *this, message_t *message)
 {
-       chunk_t secret;
-       status_t status;
+       keymat_t *old_keymat = NULL;
+       ike_sa_id_t *id;
        iterator_t *iterator;
        payload_t *payload;
 
@@ -521,42 +512,25 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
        }
        
        if (this->dh == NULL ||
-               !this->proposal->has_dh_group(this->proposal, this->dh_group) ||
-               this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
+               !this->proposal->has_dh_group(this->proposal, this->dh_group))
        {
                DBG1(DBG_IKE, "peer DH group selection invalid");
                return FAILED;
        }
        
-       /* Apply SPI if we are rekeying */
+       id = this->ike_sa->get_id(this->ike_sa);
        if (this->old_sa)
-       {
-               ike_sa_id_t *id;
-               prf_t *prf, *child_prf;
-               
-               id = this->ike_sa->get_id(this->ike_sa);
+       {       /* rekeying: Apply SPI, include keymat from old SA in key derivation */
                id->set_responder_spi(id, this->proposal->get_spi(this->proposal));
-               
-               /* setup crypto keys for the rekeyed SA */
-               prf = this->old_sa->get_prf(this->old_sa);
-               child_prf = this->old_sa->get_child_prf(this->old_sa);
-               status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, 
-                                                                                   this->my_nonce, this->other_nonce,
-                                                                                   TRUE, child_prf, prf);
-       }
-       else
-       {
-               /* setup crypto keys for a new SA */
-               status = this->ike_sa->derive_keys(this->ike_sa, this->proposal, secret, 
-                                                                                  this->my_nonce, this->other_nonce,
-                                                                                  TRUE, NULL, NULL);
+               old_keymat = this->old_sa->get_keymat(this->old_sa);
        }
-       if (status != SUCCESS)
+       if (!this->keymat->derive_keys(this->keymat, this->proposal, this->my_nonce,
+                                                                  this->other_nonce, id, old_keymat))
        {
                DBG1(DBG_IKE, "key derivation failed");
                return FAILED;
        }
-
+       
        return SUCCESS;
 }
 
@@ -590,12 +564,12 @@ static chunk_t get_lower_nonce(private_ike_init_t *this)
 static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
 {
        DESTROY_IF(this->proposal);
-       DESTROY_IF(this->dh);
        chunk_free(&this->other_nonce);
        
        this->ike_sa = ike_sa;
        this->proposal = NULL;
-       this->dh = lib->crypto->create_dh(lib->crypto, this->dh_group);
+       this->keymat->set_dh_group(this->keymat, this->dh_group);
+       this->dh = this->keymat->get_dh(this->keymat);
 }
 
 /**
@@ -604,7 +578,6 @@ static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
 static void destroy(private_ike_init_t *this)
 {
        DESTROY_IF(this->proposal);
-       DESTROY_IF(this->dh);
        chunk_free(&this->my_nonce);
        chunk_free(&this->other_nonce);
        chunk_free(&this->cookie);
@@ -637,6 +610,7 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
        this->initiator = initiator;
        this->dh_group = MODP_NONE;
        this->dh = NULL;
+       this->keymat = ike_sa->get_keymat(ike_sa);
        this->my_nonce = chunk_empty;
        this->other_nonce = chunk_empty;
        this->cookie = chunk_empty;
index c6d74dc..d16a0b8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2007 Martin Willi
+ * Copyright (C) 2006-2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
index 2dc444e..242f209 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *