IKEv1: Added basic support for INFORMATIONAL exchange types, and for NOTIFY_V1 messag...
authorClavister OpenSource <opensource@clavister.com>
Fri, 2 Dec 2011 15:22:42 +0000 (16:22 +0100)
committerClavister OpenSource <opensource@clavister.com>
Tue, 20 Mar 2012 16:31:11 +0000 (17:31 +0100)
src/libcharon/encoding/message.c
src/libcharon/encoding/payloads/notify_payload.c
src/libcharon/sa/task_manager_v1.c
src/libcharon/sa/tasks/quick_mode.c

index b63264b..0a808ac 100644 (file)
@@ -574,6 +574,7 @@ static payload_order_t aggressive_r_order[] = {
  */
 static payload_rule_t informational_i_rules_v1[] = {
 /*     payload type                            min     max                                             encr    suff */
+       {NOTIFY_V1,                                     0,      MAX_NOTIFY_PAYLOADS,    FALSE,  FALSE},
        {NOTIFY_V1,                                     0,      MAX_NOTIFY_PAYLOADS,    TRUE,   FALSE},
        {DELETE_V1,                                     0,      MAX_DELETE_PAYLOADS,    TRUE,   FALSE},
        {VENDOR_ID_V1,                          0,      MAX_VID_PAYLOADS,               TRUE,   FALSE},
@@ -1946,22 +1947,25 @@ METHOD(message_t, parse_body, status_t,
                {
                        hash_payload_t *hash_payload;
                        chunk_t other_hash;
-                       if (this->first_payload != HASH_V1)
+                       if ((this->first_payload != HASH_V1) && (this->public.get_exchange_type(&this->public) != INFORMATIONAL_V1))
                        {
                                DBG1(DBG_ENC, "expected HASH payload as first payload");
                                chunk_free(&hash);
                                return VERIFY_ERROR;
                        }
-                       hash_payload = (hash_payload_t*)get_payload(this, HASH_V1);
-                       other_hash = hash_payload->get_hash(hash_payload);
-                       if (!chunk_equals(hash, other_hash))
+                       if (this->first_payload == HASH_V1)
                        {
-                               DBG1(DBG_ENC, "our hash does not match received %B",
-                                        &other_hash);
-                               chunk_free(&hash);
-                               return FAILED;
+                               hash_payload = (hash_payload_t*)get_payload(this, HASH_V1);
+                               other_hash = hash_payload->get_hash(hash_payload);
+                               if (!chunk_equals(hash, other_hash))
+                               {
+                                       DBG1(DBG_ENC, "our hash does not match received %B",
+                                                &other_hash);
+                                       chunk_free(&hash);
+                                       return FAILED;
+                               }
+                               DBG2(DBG_ENC, "verified IKEv1 message with hash %B", &hash);
                        }
-                       DBG2(DBG_ENC, "verified IKEv1 message with hash %B", &hash);
                        chunk_free(&hash);
                }
        }
index a5ffb06..a72a0f3 100644 (file)
@@ -413,7 +413,7 @@ METHOD(payload_t, verify, status_t,
                case INVALID_MAJOR_VERSION:
                case NO_PROPOSAL_CHOSEN:
                {
-                       if (this->notify_data.len != 0)
+                       if ((this->notify_data.len != 0) && (this->type == NOTIFY))
                        {
                                bad_length = TRUE;
                        }
index a2b1725..86b25e4 100644 (file)
@@ -489,6 +489,8 @@ static status_t process_request(private_task_manager_t *this,
        enumerator_t *enumerator;
        task_t *task = NULL;
        bool send_response = FALSE;
+       payload_t *payload;
+       notify_payload_t *notify;
 
        if (this->passive_tasks->get_count(this->passive_tasks) == 0)
        {       /* create tasks depending on request type, if not already some queued */
@@ -511,8 +513,44 @@ static status_t process_request(private_task_manager_t *this,
                                this->passive_tasks->insert_last(this->passive_tasks, task);
                                break;
                        case INFORMATIONAL_V1:
-                               /* TODO-IKEv1: informational */
-                               return FAILED;
+                               enumerator = message->create_payload_enumerator(message);
+                               while (enumerator->enumerate(enumerator, &payload))
+                               {
+                                       switch (payload->get_type(payload))
+                                       {
+                                               case NOTIFY_V1:
+                                               {
+                                                       notify = (notify_payload_t*)payload;
+                                                       switch (notify->get_notify_type(notify))
+                                                       {
+                                                               /* TODO-IKEv1: Add notification types here as needed */
+                                                               case INITIAL_CONTACT_IKEV1:
+                                                                       break;
+                                                               default:
+                                                                       if(notify->get_notify_type(notify) < 16384)
+                                                                       {
+                                                                               DBG1(DBG_IKE, "Received %N error notification.", notify_type_names, notify->get_notify_type(notify));
+                                                                               return FAILED;
+                                                                       }
+                                                                       break;
+                                                       }
+                                                       break;
+                                               }
+                                               case DELETE_V1:
+                                               {
+                                                       /* TODO-IKEv1: Delete payload handling. */
+                                                       break;
+                                               }
+                                               default:
+                                                       break;
+                                       }
+                                       if (task)
+                                       {
+                                               break;
+                                       }
+                               }
+                               enumerator->destroy(enumerator);
+                               break;
                        case TRANSACTION:
                                task = (task_t *)xauth_request_create(this->ike_sa, FALSE);
                                this->passive_tasks->insert_last(this->passive_tasks, task);
index 472aad8..10e0c22 100644 (file)
@@ -22,6 +22,7 @@
 #include <encoding/payloads/sa_payload.h>
 #include <encoding/payloads/nonce_payload.h>
 #include <encoding/payloads/id_payload.h>
+#include <encoding/payloads/payload.h>
 
 typedef struct private_quick_mode_t private_quick_mode_t;
 
@@ -548,9 +549,24 @@ METHOD(task_t, build_i, status_t,
        }
 }
 
+status_t process_notify(notify_payload_t *notify)
+{
+       if(notify->get_notify_type(notify) < 16384)
+       {
+               DBG1(DBG_IKE, "Received %N error notification.", notify_type_names, notify->get_notify_type(notify));
+               return FAILED;
+       }
+       DBG1(DBG_IKE, "Received %N notification.", notify_type_names, notify->get_notify_type(notify));
+       return SUCCESS;
+}
+
 METHOD(task_t, process_r, status_t,
        private_quick_mode_t *this, message_t *message)
 {
+       enumerator_t *enumerator;
+       payload_t *payload;
+       status_t status;
+
        switch (this->state)
        {
                case QM_INIT:
@@ -625,6 +641,19 @@ METHOD(task_t, process_r, status_t,
                }
                case QM_NEGOTIATED:
                {
+                       enumerator = message->create_payload_enumerator(message);
+                       while(enumerator->enumerate(enumerator, &payload))
+                       {
+                               if(payload->get_type(payload) == NOTIFY_V1)
+                               {
+                                       status = process_notify((notify_payload_t *)payload);
+                                       if(status != SUCCESS)
+                                       {
+                                               return status;
+                                       }
+                               }
+                       }
+                       enumerator->destroy(enumerator);
                        if (!install(this))
                        {
                                return FAILED;