Implemented IKEv1 attribute encoding in SA payload
authorMartin Willi <martin@revosec.ch>
Thu, 24 Nov 2011 14:25:22 +0000 (15:25 +0100)
committerMartin Willi <martin@revosec.ch>
Tue, 20 Mar 2012 16:30:53 +0000 (17:30 +0100)
src/libcharon/encoding/payloads/proposal_substructure.c
src/libcharon/encoding/payloads/proposal_substructure.h
src/libcharon/encoding/payloads/sa_payload.c
src/libcharon/encoding/payloads/transform_attribute.c
src/libcharon/encoding/payloads/transform_attribute.h

index 11d684f..ca19ba7 100644 (file)
@@ -754,6 +754,157 @@ METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*,
        return this->transforms->create_enumerator(this->transforms);
 }
 
+/**
+ * Get an attribute from a selected transform
+ */
+static u_int64_t get_attr_tfrm(transform_substructure_t *transform,
+                                                          transform_attribute_type_t type)
+{
+       enumerator_t *enumerator;
+       transform_attribute_t *attr;
+       u_int64_t value = 0;
+
+       enumerator = transform->create_attribute_enumerator(transform);
+       while (enumerator->enumerate(enumerator, &attr))
+       {
+               if (attr->get_attribute_type(attr) == type)
+               {
+                       value = attr->get_value(attr);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       return value;
+}
+
+
+/**
+ * Get an attribute from any transform, 0 if not found
+ */
+static u_int64_t get_attr(private_proposal_substructure_t *this,
+                               transform_attribute_type_t type, transform_substructure_t **sel)
+{
+       transform_substructure_t *transform;
+       enumerator_t *enumerator;
+       u_int64_t value = 0;
+
+       enumerator = this->transforms->create_enumerator(this->transforms);
+       while (enumerator->enumerate(enumerator, &transform))
+       {
+               value = get_attr_tfrm(transform, type);
+               if (value)
+               {
+                       if (sel)
+                       {
+                               *sel = transform;
+                       }
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       return value;
+}
+
+METHOD(proposal_substructure_t, get_lifetime, u_int32_t,
+       private_proposal_substructure_t *this)
+{
+       transform_substructure_t *transform;
+       transform_attribute_type_t type;
+
+       switch (this->protocol_id)
+       {
+               case PROTO_IKE:
+                       type = get_attr(this, TATTR_PH1_LIFE_TYPE, &transform);
+                       if (type == IKEV1_LIFE_TYPE_SECONDS)
+                       {
+                               return get_attr_tfrm(transform, TATTR_PH1_LIFE_DURATION);
+                       }
+                       break;
+               case PROTO_ESP:
+                       type = get_attr(this, TATTR_PH2_SA_LIFE_TYPE, &transform);
+                       if (type == IKEV1_LIFE_TYPE_SECONDS)
+                       {
+                               return get_attr_tfrm(transform, TATTR_PH2_SA_LIFE_DURATION);
+                       }
+                       else if (type != IKEV1_LIFE_TYPE_KILOBYTES)
+                       {       /* default to 8 hours, RFC 2407 */
+                               return 28800;
+                       }
+                       break;
+               default:
+                       break;
+       }
+       return 0;
+}
+
+METHOD(proposal_substructure_t, get_lifebytes, u_int64_t,
+       private_proposal_substructure_t *this)
+{
+       transform_substructure_t *transform;
+       transform_attribute_type_t type;
+
+       switch (this->protocol_id)
+       {
+               case PROTO_IKE:
+                       type = get_attr(this, TATTR_PH1_LIFE_TYPE, &transform);
+                       if (type == IKEV1_LIFE_TYPE_KILOBYTES)
+                       {
+                               return get_attr_tfrm(transform, TATTR_PH1_LIFE_DURATION);
+                       }
+                       break;
+               case PROTO_ESP:
+                       type = get_attr(this, TATTR_PH2_SA_LIFE_TYPE, &transform);
+                       if (type == IKEV1_LIFE_TYPE_KILOBYTES)
+                       {
+                               return get_attr_tfrm(transform, TATTR_PH1_LIFE_DURATION);
+                       }
+                       break;
+               default:
+                       break;
+       }
+       return 0;
+
+}
+
+METHOD(proposal_substructure_t, get_auth_method, auth_method_t,
+       private_proposal_substructure_t *this)
+{
+       switch (get_attr(this, TATTR_PH1_AUTH_METHOD, NULL))
+       {
+               case IKEV1_AUTH_PSK:
+                       return AUTH_PSK;
+               case IKEV1_AUTH_RSA_SIG:
+                       return AUTH_RSA;
+               case IKEV1_AUTH_DSS_SIG:
+                       return AUTH_DSS;
+               default:
+                       /* TODO-IKEv1: XAUTH, ECDSA sigs */
+                       return AUTH_NONE;
+       }
+}
+
+METHOD(proposal_substructure_t, get_encap_mode, ipsec_mode_t,
+       private_proposal_substructure_t *this, bool *udp)
+{
+       *udp = FALSE;
+       switch (get_attr(this, TATTR_PH2_ENCAP_MODE, NULL))
+       {
+               case IKEV1_ENCAP_TRANSPORT:
+                       return MODE_TRANSPORT;
+               case IKEV1_ENCAP_TUNNEL:
+                       return MODE_TRANSPORT;
+               case IKEV1_ENCAP_UDP_TRANSPORT:
+                       *udp = TRUE;
+                       return MODE_TRANSPORT;
+               case IKEV1_ENCAP_UDP_TUNNEL:
+                       *udp = TRUE;
+                       return MODE_TUNNEL;
+               default:
+                       /* default to TUNNEL, RFC 2407 says implementation specific */
+                       return MODE_TUNNEL;
+       }
+}
+
 METHOD2(payload_t, proposal_substructure_t, destroy, void,
        private_proposal_substructure_t *this)
 {
@@ -791,6 +942,10 @@ proposal_substructure_t *proposal_substructure_create(payload_type_t type)
                        .create_substructure_enumerator = _create_substructure_enumerator,
                        .set_spi = _set_spi,
                        .get_spi = _get_spi,
+                       .get_lifetime = _get_lifetime,
+                       .get_lifebytes = _get_lifebytes,
+                       .get_auth_method = _get_auth_method,
+                       .get_encap_mode = _get_encap_mode,
                        .destroy = _destroy,
                },
                .next_payload = NO_PAYLOAD,
index de06f91..03b26e1 100644 (file)
@@ -112,6 +112,35 @@ struct proposal_substructure_t {
        enumerator_t* (*create_substructure_enumerator)(proposal_substructure_t *this);
 
        /**
+        * Get the (shortest) lifetime of a proposal (IKEv1 only).
+        *
+        * @return                                      lifetime, in seconds
+        */
+       u_int32_t (*get_lifetime)(proposal_substructure_t *this);
+
+       /**
+        * Get the (shortest) life duration of a proposal (IKEv1 only).
+        *
+        * @return                                      life duration, in bytes
+        */
+       u_int64_t (*get_lifebytes)(proposal_substructure_t *this);
+
+       /**
+        * Get the first authentication method from the proposal (IKEv1 only).
+        *
+        * @return                                      auth method, or AUTH_NONE
+        */
+       auth_method_t (*get_auth_method)(proposal_substructure_t *this);
+
+       /**
+        * Get the (first) encapsulation mode from a proposal (IKEv1 only).
+        *
+        * @param udp                           set to TRUE if UDP encapsulation used
+        * @return                                      ipsec encapsulation mode
+        */
+       ipsec_mode_t (*get_encap_mode)(proposal_substructure_t *this, bool *udp);
+
+       /**
         * Destroys an proposal_substructure_t object.
         */
        void (*destroy) (proposal_substructure_t *this);
index 5f739c9..254916c 100644 (file)
@@ -339,26 +339,69 @@ METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*,
 METHOD(sa_payload_t, get_lifetime, u_int32_t,
        private_sa_payload_t *this)
 {
-       return 0;
+       proposal_substructure_t *substruct;
+       enumerator_t *enumerator;
+       u_int32_t lifetime = 0;
+
+       enumerator = this->proposals->create_enumerator(this->proposals);
+       if (enumerator->enumerate(enumerator, &substruct))
+       {
+               lifetime = substruct->get_lifetime(substruct);
+       }
+       enumerator->destroy(enumerator);
+
+       return lifetime;
 }
 
 METHOD(sa_payload_t, get_lifebytes, u_int64_t,
        private_sa_payload_t *this)
 {
-       return 0;
+       proposal_substructure_t *substruct;
+       enumerator_t *enumerator;
+       u_int64_t lifebytes = 0;
+
+       enumerator = this->proposals->create_enumerator(this->proposals);
+       if (enumerator->enumerate(enumerator, &substruct))
+       {
+               lifebytes = substruct->get_lifebytes(substruct);
+       }
+       enumerator->destroy(enumerator);
+
+       return lifebytes;
 }
 
 METHOD(sa_payload_t, get_auth_method, auth_method_t,
        private_sa_payload_t *this)
 {
-       return AUTH_NONE;
+       proposal_substructure_t *substruct;
+       enumerator_t *enumerator;
+       auth_method_t method = AUTH_NONE;
+
+       enumerator = this->proposals->create_enumerator(this->proposals);
+       if (enumerator->enumerate(enumerator, &substruct))
+       {
+               method = substruct->get_auth_method(substruct);
+       }
+       enumerator->destroy(enumerator);
+
+       return method;
 }
 
 METHOD(sa_payload_t, get_encap_mode, ipsec_mode_t,
        private_sa_payload_t *this, bool *udp)
 {
-       *udp = FALSE;
-       return MODE_NONE;
+       proposal_substructure_t *substruct;
+       enumerator_t *enumerator;
+       ipsec_mode_t mode = MODE_NONE;
+
+       enumerator = this->proposals->create_enumerator(this->proposals);
+       if (enumerator->enumerate(enumerator, &substruct))
+       {
+               mode = substruct->get_encap_mode(substruct, udp);
+       }
+       enumerator->destroy(enumerator);
+
+       return mode;
 }
 
 METHOD2(payload_t, sa_payload_t, destroy, void,
index 7e8a9c7..0be3931 100644 (file)
@@ -209,10 +209,22 @@ METHOD(transform_attribute_t, get_value_chunk, chunk_t,
        return this->attribute_value;
 }
 
-METHOD(transform_attribute_t, get_value, u_int16_t,
+METHOD(transform_attribute_t, get_value, u_int64_t,
        private_transform_attribute_t *this)
 {
-       return this->attribute_length_or_value;
+       u_int64_t value = 0;
+
+       if (this->attribute_format)
+       {
+               return this->attribute_length_or_value;
+       }
+       if (this->attribute_value.len > sizeof(value))
+       {
+               return UINT64_MAX;
+       }
+       memcpy(((char*)&value) + sizeof(value) - this->attribute_value.len,
+                  this->attribute_value.ptr, this->attribute_value.len);
+       return be64toh(value);
 }
 
 METHOD(transform_attribute_t, set_attribute_type, void,
index 52e5d84..7eed40b 100644 (file)
@@ -109,7 +109,7 @@ struct transform_attribute_t {
         *
         * @return              value
         */
-       u_int16_t (*get_value) (transform_attribute_t *this);
+       u_int64_t (*get_value) (transform_attribute_t *this);
 
        /**
         * Sets the value of the attribute.