Support EAP-only authentication for mutual and key deriving EAP methods
authorMartin Willi <martin@strongswan.org>
Thu, 7 Jan 2010 14:51:30 +0000 (15:51 +0100)
committerMartin Willi <martin@strongswan.org>
Thu, 7 Jan 2010 14:51:30 +0000 (15:51 +0100)
src/charon/sa/authenticators/authenticator.h
src/charon/sa/authenticators/eap_authenticator.c
src/charon/sa/authenticators/psk_authenticator.c
src/charon/sa/authenticators/pubkey_authenticator.c
src/charon/sa/tasks/ike_auth.c

index 299b9e6..fff91ed 100644 (file)
@@ -128,6 +128,16 @@ struct authenticator_t {
        status_t (*build)(authenticator_t *this, message_t *message);
 
        /**
+        * Check if the authenticator is capable of mutual authentication.
+        *
+        * Some authenticator authenticate both peers, e.g. EAP. To support
+        * mutual authentication with only a single authenticator (EAP-only
+        * authentication), it must be mutual. This method is invoked in ike_auth
+        * to check if the given authenticator is capable of doing so.
+        */
+       bool (*is_mutual)(authenticator_t *this);
+
+       /**
         * Destroy authenticator instance.
         */
        void (*destroy) (authenticator_t *this);
index 922a95f..1691105 100644 (file)
@@ -73,6 +73,11 @@ struct private_eap_authenticator_t {
        bool eap_complete;
 
        /**
+        * Set if we require mutual EAP due EAP-only authentication
+        */
+       bool require_mutual;
+
+       /**
         * authentication payload verified successfully
         */
        bool auth_complete;
@@ -526,6 +531,15 @@ static status_t process_client(private_eap_authenticator_t *this,
                {
                        return FAILED;
                }
+               if (this->require_mutual && !this->method->is_mutual(this->method))
+               {       /* we require mutual authentication due to EAP-only */
+                       u_int32_t vendor;
+
+                       DBG1(DBG_IKE, "EAP-only authentication requires a mutual and "
+                                "MSK deriving EAP method, but %N is not",
+                                eap_type_names, this->method->get_type(this->method, &vendor));
+                       return FAILED;
+               }
                return SUCCESS;
        }
 
@@ -608,6 +622,16 @@ static status_t build_client(private_eap_authenticator_t *this,
 }
 
 /**
+ * Implementation of authenticator_t.is_mutual.
+ */
+static bool is_mutual(private_eap_authenticator_t *this)
+{
+       /* we don't know yet, but insist on it after EAP is complete */
+       this->require_mutual = TRUE;
+       return TRUE;
+}
+
+/**
  * Implementation of authenticator_t.destroy.
  */
 static void destroy(private_eap_authenticator_t *this)
@@ -630,6 +654,7 @@ eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa,
 
        this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build_client;
        this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process_client;
+       this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))is_mutual;
        this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
 
        this->ike_sa = ike_sa;
@@ -643,6 +668,7 @@ eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa,
        this->eap_complete = FALSE;
        this->auth_complete = FALSE;
        this->eap_identity = NULL;
+       this->require_mutual = FALSE;
 
        return &this->public;
 }
@@ -658,6 +684,7 @@ eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa,
 
        this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *messageh))build_server;
        this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process_server;
+       this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))is_mutual;
        this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
 
        this->ike_sa = ike_sa;
@@ -671,6 +698,7 @@ eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa,
        this->eap_complete = FALSE;
        this->auth_complete = FALSE;
        this->eap_identity = NULL;
+       this->require_mutual = FALSE;
 
        return &this->public;
 }
index 83a4b22..67197d6 100644 (file)
@@ -169,6 +169,7 @@ psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa,
 
        this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build;
        this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))return_failed;
+       this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))return_false;
        this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
 
        this->ike_sa = ike_sa;
@@ -188,6 +189,7 @@ psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa,
 
        this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *messageh))return_failed;
        this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process;
+       this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))return_false;
        this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
 
        this->ike_sa = ike_sa;
index 7e558db..f1dca27 100644 (file)
@@ -234,6 +234,7 @@ pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa,
 
        this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build;
        this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))return_failed;
+       this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))return_false;
        this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
 
        this->ike_sa = ike_sa;
@@ -253,6 +254,7 @@ pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa,
 
        this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))return_failed;
        this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process;
+       this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))return_false;
        this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy;
 
        this->ike_sa = ike_sa;
index 0e81d2b..fb79cb2 100644 (file)
@@ -650,15 +650,31 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
                id_payload = id_payload_create_from_identification(ID_RESPONDER, id);
                message->add_payload(message, (payload_t*)id_payload);
 
-               /* build authentication data */
-               this->my_auth = authenticator_create_builder(this->ike_sa, cfg,
-                                                       this->other_nonce, this->my_nonce,
-                                                       this->other_packet->get_data(this->other_packet),
-                                                       this->my_packet->get_data(this->my_packet));
-               if (!this->my_auth)
+               if ((uintptr_t)cfg->get(cfg, AUTH_RULE_AUTH_CLASS) == AUTH_CLASS_EAP)
+               {       /* EAP-only authentication */
+                       if (!this->ike_sa->supports_extension(this->ike_sa,
+                                                                                                 EXT_EAP_ONLY_AUTHENTICATION))
+                       {
+                               DBG1(DBG_IKE, "configured EAP-only authentication, but peer "
+                                        "does not support it");
+                               message->add_notify(message, TRUE, AUTHENTICATION_FAILED,
+                                                                       chunk_empty);
+                               return FAILED;
+                       }
+               }
+               else
                {
-                       message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
-                       return FAILED;
+                       /* build authentication data */
+                       this->my_auth = authenticator_create_builder(this->ike_sa, cfg,
+                                                               this->other_nonce, this->my_nonce,
+                                                               this->other_packet->get_data(this->other_packet),
+                                                               this->my_packet->get_data(this->my_packet));
+                       if (!this->my_auth)
+                       {
+                               message->add_notify(message, TRUE, AUTHENTICATION_FAILED,
+                                                                       chunk_empty);
+                               return FAILED;
+                       }
                }
        }
 
@@ -837,13 +853,6 @@ static status_t process_i(private_ike_auth_t *this, message_t *message)
                        id_payload_t *id_payload;
                        identification_t *id;
 
-                       /* responder is not allowed to do EAP */
-                       if (!message->get_payload(message, AUTHENTICATION))
-                       {
-                               DBG1(DBG_IKE, "AUTH payload missing");
-                               return FAILED;
-                       }
-
                        /* handle IDr payload */
                        id_payload = (id_payload_t*)message->get_payload(message,
                                                                                                                         ID_RESPONDER);
@@ -857,31 +866,45 @@ static status_t process_i(private_ike_auth_t *this, message_t *message)
                        cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
                        cfg->add(cfg, AUTH_RULE_IDENTITY, id->clone(id));
 
-                       /* verify authentication data */
-                       this->other_auth = authenticator_create_verifier(this->ike_sa,
-                                                       message, this->other_nonce, this->my_nonce,
-                                                       this->other_packet->get_data(this->other_packet),
-                                                       this->my_packet->get_data(this->my_packet));
-                       if (!this->other_auth)
+                       if (message->get_payload(message, AUTHENTICATION))
                        {
-                               return FAILED;
+                               /* verify authentication data */
+                               this->other_auth = authenticator_create_verifier(this->ike_sa,
+                                                               message, this->other_nonce, this->my_nonce,
+                                                               this->other_packet->get_data(this->other_packet),
+                                                               this->my_packet->get_data(this->my_packet));
+                               if (!this->other_auth)
+                               {
+                                       return FAILED;
+                               }
+                       }
+                       else
+                       {       /* responder omited AUTH payload, indicating EAP-only */
+                               if (!this->my_auth ||
+                                       !this->my_auth->is_mutual(this->my_auth))
+                               {
+                                       return FAILED;
+                               }
                        }
                }
-               switch (this->other_auth->process(this->other_auth, message))
+               if (this->other_auth)
                {
-                       case SUCCESS:
-                               break;
-                       case NEED_MORE:
-                               return NEED_MORE;
-                       default:
-                               return FAILED;
+                       switch (this->other_auth->process(this->other_auth, message))
+                       {
+                               case SUCCESS:
+                                       break;
+                               case NEED_MORE:
+                                       return NEED_MORE;
+                               default:
+                                       return FAILED;
+                       }
+                       this->other_auth->destroy(this->other_auth);
+                       this->other_auth = NULL;
                }
                /* store authentication information, reset authenticator */
                cfg = auth_cfg_create();
                cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE);
                this->ike_sa->add_auth_cfg(this->ike_sa, FALSE, cfg);
-               this->other_auth->destroy(this->other_auth);
-               this->other_auth = NULL;
 
                /* another auth round done, invoke authorize hook */
                if (!charon->bus->authorize(charon->bus, FALSE))