Extend sa_payload for IKEv1 support
authorMartin Willi <martin@revosec.ch>
Wed, 16 Nov 2011 08:29:38 +0000 (09:29 +0100)
committerMartin Willi <martin@revosec.ch>
Tue, 20 Mar 2012 16:30:40 +0000 (17:30 +0100)
src/conftest/hooks/custom_proposal.c
src/conftest/hooks/pretend_auth.c
src/conftest/hooks/set_proposal_number.c
src/libcharon/encoding/parser.c
src/libcharon/encoding/payloads/encodings.h
src/libcharon/encoding/payloads/payload.c
src/libcharon/encoding/payloads/payload.h
src/libcharon/encoding/payloads/sa_payload.c
src/libcharon/encoding/payloads/sa_payload.h
src/libcharon/sa/tasks/child_create.c
src/libcharon/sa/tasks/ike_init.c

index e4acd84..9522335 100644 (file)
@@ -145,7 +145,8 @@ METHOD(listener_t, message, bool,
                                                                                   proposal->get_protocol(proposal),
                                                                                   proposal->get_spi(proposal));
                                DBG1(DBG_CFG, "injecting custom proposal: %#P", new_props);
-                               new = sa_payload_create_from_proposal_list(new_props);
+                               new = sa_payload_create_from_proposal_list(
+                                                                                       SECURITY_ASSOCIATION, new_props);
                                message->add_payload(message, (payload_t*)new);
                                new_props->destroy_offset(new_props, offsetof(proposal_t, destroy));
                        }
index 4b7168c..dd6ab99 100644 (file)
@@ -294,7 +294,8 @@ static void process_auth_response(private_pretend_auth_t *this,
        if (this->proposal)
        {
                message->add_payload(message, (payload_t*)
-                                       sa_payload_create_from_proposal(this->proposal));
+                                       sa_payload_create_from_proposal(SECURITY_ASSOCIATION,
+                                                                                                       this->proposal));
        }
        if (this->tsi)
        {
index a59d96b..32b0155 100644 (file)
@@ -121,7 +121,7 @@ METHOD(listener_t, message, bool,
                        }
                        enumerator->destroy(enumerator);
                }
-               sa = sa_payload_create_from_proposal_list(updated);
+               sa = sa_payload_create_from_proposal_list(SECURITY_ASSOCIATION, updated);
                list->destroy_offset(list, offsetof(proposal_t, destroy));
                updated->destroy_offset(updated, offsetof(proposal_t, destroy));
                message->add_payload(message, (payload_t*)sa);
index 6309a5c..09b5216 100644 (file)
@@ -496,6 +496,18 @@ METHOD(parser_t, parse_payload, status_t,
                                }
                                break;
                        }
+                       case PROPOSALS_V1:
+                       {
+                               if (payload_length < SA_PAYLOAD_V1_HEADER_LENGTH ||
+                                       !parse_list(this, rule_number, output + rule->offset,
+                                                               PROPOSAL_SUBSTRUCTURE_V1,
+                                                               payload_length - SA_PAYLOAD_V1_HEADER_LENGTH))
+                               {
+                                       pld->destroy(pld);
+                                       return PARSE_ERROR;
+                               }
+                               break;
+                       }
                        case TRANSFORMS:
                        {
                                if (payload_length <
index 52af4a9..80df979 100644 (file)
@@ -220,6 +220,11 @@ enum encoding_type_t {
        PROPOSALS,
 
        /**
+        * Same as PROPOSALS, but for IKEv1 in a SECURITY_ASSOCIATION_V1
+        */
+       PROPOSALS_V1,
+
+       /**
         * Representating one or more transform substructures.
         *
         * The offset points to a linked_list_t pointer.
index 78451c5..14617b4 100644 (file)
@@ -156,7 +156,8 @@ payload_t *payload_create(payload_type_t type)
                case HEADER:
                        return (payload_t*)ike_header_create();
                case SECURITY_ASSOCIATION:
-                       return (payload_t*)sa_payload_create();
+               case SECURITY_ASSOCIATION_V1:
+                       return (payload_t*)sa_payload_create(type);
                case PROPOSAL_SUBSTRUCTURE:
                        return (payload_t*)proposal_substructure_create();
                case TRANSFORM_SUBSTRUCTURE:
index 021383a..ff1ae73 100644 (file)
@@ -29,6 +29,10 @@ typedef struct payload_t payload_t;
 #include <library.h>
 #include <encoding/payloads/encodings.h>
 
+/**
+ * Domain of interpretation used by IPsec/IKEv1
+ */
+#define IKEV1_DOI_IPSEC 1
 
 /**
  * Payload-Types of an IKE message.
@@ -243,6 +247,14 @@ enum payload_type_t {
         * used internally to handle a transform attribute like a payload.
         */
        CONFIGURATION_ATTRIBUTE = 261,
+
+       /**
+        * PROPOSAL_SUBSTRUCTURE has a value of PRIVATE USE space.
+        *
+        * This payload type is not sent over wire and just
+        * used internally to handle a proposal substructure like a payload.
+        */
+       PROPOSAL_SUBSTRUCTURE_V1 = 262,
 };
 
 /**
index 89464ac..af30126 100644 (file)
@@ -22,6 +22,8 @@
 #include <utils/linked_list.h>
 #include <daemon.h>
 
+/* IKEv1 situation */
+#define SIT_IDENTITY_ONLY 1
 
 typedef struct private_sa_payload_t private_sa_payload_t;
 
@@ -48,7 +50,7 @@ struct private_sa_payload_t {
        /**
         * Reserved bits
         */
-       bool reserved[7];
+       bool reserved[8];
 
        /**
         * Length of this payload.
@@ -58,21 +60,75 @@ struct private_sa_payload_t {
        /**
         * Proposals in this payload are stored in a linked_list_t.
         */
-       linked_list_t * proposals;
+       linked_list_t *proposals;
+
+       /**
+        * Type of this payload, V1 or V2
+        */
+       payload_type_t type;
+
+       /**
+        * IKEv1 DOI
+        */
+       u_int32_t doi;
+
+       /**
+        * IKEv1 situation
+        */
+       u_int32_t situation;
 };
 
 /**
- * Encoding rules to parse or generate a IKEv2-SA Payload
- *
- * The defined offsets are the positions in a object of type
- * private_sa_payload_t.
+ * Encoding rules for IKEv1 SA payload
  */
-encoding_rule_t sa_payload_encodings[] = {
+static encoding_rule_t encodings_v1[] = {
+       /* 1 Byte next payload type, stored in the field next_payload */
+       { U_INT_8,                      offsetof(private_sa_payload_t, next_payload)    },
+       /* 8 reserved bits */
+       { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[0])                     },
+       { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[1])                     },
+       { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[2])                     },
+       { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[3])                     },
+       { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[4])                     },
+       { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[5])                     },
+       { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[6])                     },
+       { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[7])                     },
+       /* Length of the whole SA payload*/
+       { PAYLOAD_LENGTH,       offsetof(private_sa_payload_t, payload_length)  },
+       /* DOI*/
+       { U_INT_32,                     offsetof(private_sa_payload_t, doi)                             },
+       /* Situation*/
+       { U_INT_32,                     offsetof(private_sa_payload_t, situation)               },
+       /* Proposals are stored in a proposal substructure,
+          offset points to a linked_list_t pointer */
+       { PROPOSALS_V1,         offsetof(private_sa_payload_t, proposals)               },
+};
+
+/*
+                           1                   2                   3
+       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      ! Next Payload  !    RESERVED   !         Payload Length        !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      !                           DOI                                 !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      !                           Situation                           !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      !                                                               !
+      ~                          <Proposals>                          ~
+      !                                                               !
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Encoding rules for IKEv2 SA payload
+ */
+static encoding_rule_t encodings_v2[] = {
        /* 1 Byte next payload type, stored in the field next_payload */
        { U_INT_8,                      offsetof(private_sa_payload_t, next_payload)            },
        /* the critical bit */
        { FLAG,                         offsetof(private_sa_payload_t, critical)                        },
-       /* 7 Bit reserved bits, nowhere stored */
+       /* 7 Bit reserved bits */
        { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[0])                     },
        { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[1])                     },
        { RESERVED_BIT,         offsetof(private_sa_payload_t, reserved[2])                     },
@@ -144,14 +200,22 @@ METHOD(payload_t, verify, status_t,
 METHOD(payload_t, get_encoding_rules, void,
        private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
 {
-       *rules = sa_payload_encodings;
-       *rule_count = countof(sa_payload_encodings);
+       if (this->type == SECURITY_ASSOCIATION_V1)
+       {
+               *rules = encodings_v1;
+               *rule_count = countof(encodings_v1);
+       }
+       else
+       {
+               *rules = encodings_v2;
+               *rule_count = countof(encodings_v2);
+       }
 }
 
 METHOD(payload_t, get_type, payload_type_t,
        private_sa_payload_t *this)
 {
-       return SECURITY_ASSOCIATION;
+       return this->type;
 }
 
 METHOD(payload_t, get_next_type, payload_type_t,
@@ -175,6 +239,11 @@ static void compute_length(private_sa_payload_t *this)
        payload_t *current;
        size_t length = SA_PAYLOAD_HEADER_LENGTH;
 
+       if (this->type == SECURITY_ASSOCIATION_V1)
+       {
+               length = SA_PAYLOAD_V1_HEADER_LENGTH;
+       }
+
        enumerator = this->proposals->create_enumerator(this->proposals);
        while (enumerator->enumerate(enumerator, (void **)&current))
        {
@@ -270,14 +339,14 @@ METHOD2(payload_t, sa_payload_t, destroy, void,
        private_sa_payload_t *this)
 {
        this->proposals->destroy_offset(this->proposals,
-                                                                       offsetof(proposal_substructure_t, destroy));
+                                                                       offsetof(payload_t, destroy));
        free(this);
 }
 
 /*
  * Described in header.
  */
-sa_payload_t *sa_payload_create()
+sa_payload_t *sa_payload_create(payload_type_t type)
 {
        private_sa_payload_t *this;
 
@@ -298,41 +367,49 @@ sa_payload_t *sa_payload_create()
                        .destroy = _destroy,
                },
                .next_payload = NO_PAYLOAD,
-               .payload_length = SA_PAYLOAD_HEADER_LENGTH,
                .proposals = linked_list_create(),
+               .type = type,
+               /* for IKEv1 only */
+               .doi = IKEV1_DOI_IPSEC,
+               .situation = SIT_IDENTITY_ONLY,
        );
+
+       compute_length(this);
+
        return &this->public;
 }
 
 /*
  * Described in header.
  */
-sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals)
+sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type,
+                                                                                                  linked_list_t *proposals)
 {
-       private_sa_payload_t *this;
+       sa_payload_t *this;
        enumerator_t *enumerator;
        proposal_t *proposal;
 
-       this = (private_sa_payload_t*)sa_payload_create();
+       this = sa_payload_create(type);
        enumerator = proposals->create_enumerator(proposals);
        while (enumerator->enumerate(enumerator, &proposal))
        {
-               add_proposal(this, proposal);
+               this->add_proposal(this, proposal);
        }
        enumerator->destroy(enumerator);
 
-       return &this->public;
+       return this;
 }
 
 /*
  * Described in header.
  */
-sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal)
+sa_payload_t *sa_payload_create_from_proposal(payload_type_t type,
+                                                                                         proposal_t *proposal)
 {
-       private_sa_payload_t *this;
+       sa_payload_t *this;
 
-       this = (private_sa_payload_t*)sa_payload_create();
-       add_proposal(this, proposal);
+       this = sa_payload_create(type);
+       this->add_proposal(this, proposal);
 
-       return &this->public;
+       return this;
 }
index cc8c481..11fc774 100644 (file)
@@ -30,12 +30,17 @@ typedef struct sa_payload_t sa_payload_t;
 #include <utils/linked_list.h>
 
 /**
- * SA_PAYLOAD length in bytes without any proposal substructure.
+ * SECURITY_ASSOCIATION length in bytes without any proposal substructure.
  */
 #define SA_PAYLOAD_HEADER_LENGTH 4
 
 /**
- * Class representing an IKEv2-SA Payload.
+ * SECURITY_ASSOCIATION_V1 length in bytes without any proposal substructure.
+ */
+#define SA_PAYLOAD_V1_HEADER_LENGTH 12
+
+/**
+ * Class representing an IKEv1 or IKEv2 SA Payload.
  *
  * The SA Payload format is described in RFC section 3.3.
  */
@@ -76,17 +81,20 @@ struct sa_payload_t {
 /**
  * Creates an empty sa_payload_t object
  *
+ * @param type                         SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1
  * @return                                     created sa_payload_t object
  */
-sa_payload_t *sa_payload_create(void);
+sa_payload_t *sa_payload_create(payload_type_t type);
 
 /**
  * Creates a sa_payload_t object from a list of proposals.
  *
+ * @param type                         SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1
  * @param proposals                    list of proposals to build the payload from
  * @return                                     sa_payload_t object
  */
-sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals);
+sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type,
+                                                                                                  linked_list_t *proposals);
 
 /**
  * Creates a sa_payload_t object from a single proposal.
@@ -94,9 +102,11 @@ sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals);
  * This is only for convenience. Use sa_payload_create_from_proposal_list
  * if you want to add more than one proposal.
  *
+ * @param type                         SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1
  * @param proposal                     proposal from which the payload should be built.
  * @return                                     sa_payload_t object
  */
-sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal);
+sa_payload_t *sa_payload_create_from_proposal(payload_type_t type,
+                                                                                         proposal_t *proposal);
 
 #endif /** SA_PAYLOAD_H_ @}*/
index 67c29d3..fdc5b52 100644 (file)
@@ -526,11 +526,13 @@ static void build_payloads(private_child_create_t *this, message_t *message)
        /* add SA payload */
        if (this->initiator)
        {
-               sa_payload = sa_payload_create_from_proposal_list(this->proposals);
+               sa_payload = sa_payload_create_from_proposal_list(SECURITY_ASSOCIATION,
+                                                                                                                 this->proposals);
        }
        else
        {
-               sa_payload = sa_payload_create_from_proposal(this->proposal);
+               sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION,
+                                                                                                        this->proposal);
        }
        message->add_payload(message, (payload_t*)sa_payload);
 
index b8e66c7..911e0c2 100644 (file)
@@ -132,7 +132,8 @@ static void build_payloads(private_ike_init_t *this, message_t *message)
                        enumerator->destroy(enumerator);
                }
 
-               sa_payload = sa_payload_create_from_proposal_list(proposal_list);
+               sa_payload = sa_payload_create_from_proposal_list(SECURITY_ASSOCIATION,
+                                                                                                                 proposal_list);
                proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy));
        }
        else
@@ -142,7 +143,8 @@ static void build_payloads(private_ike_init_t *this, message_t *message)
                        /* include SPI of new IKE_SA when we are rekeying */
                        this->proposal->set_spi(this->proposal, id->get_responder_spi(id));
                }
-               sa_payload = sa_payload_create_from_proposal(this->proposal);
+               sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION,
+                                                                                                        this->proposal);
        }
        message->add_payload(message, (payload_t*)sa_payload);