Support EAP-only authentication for mutual and key deriving EAP methods
[strongswan.git] / src / charon / sa / authenticators / pubkey_authenticator.c
index 15a79e2..f1dca27 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 Tobias Brunner
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2009 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
  *
  * 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 <string.h>
-
 #include "pubkey_authenticator.h"
 
 #include <daemon.h>
-#include <credentials/auth_info.h>
-
+#include <encoding/payloads/auth_payload.h>
 
 typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t;
 
@@ -31,122 +26,57 @@ typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t;
  * Private data of an pubkey_authenticator_t object.
  */
 struct private_pubkey_authenticator_t {
-       
+
        /**
         * Public authenticator_t interface.
         */
        pubkey_authenticator_t public;
-       
+
        /**
         * Assigned IKE_SA
         */
        ike_sa_t *ike_sa;
-};
 
-/**
- * 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);
+       /**
+        * nonce to include in AUTH calculation
+        */
+       chunk_t nonce;
 
-/**
- * Implementation of authenticator_t.verify.
- */
-static status_t verify(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
-                                          chunk_t my_nonce, auth_payload_t *auth_payload)
-{
-       public_key_t *public;
-       auth_method_t auth_method;
-       chunk_t auth_data, octets;
-       identification_t *other_id;
-       prf_t *prf;
-       auth_info_t *auth, *current_auth;
-       enumerator_t *enumerator;
-       key_type_t key_type = KEY_ECDSA;
-       signature_scheme_t scheme;
-       status_t status = FAILED;
-       
-       other_id = this->ike_sa->get_other_id(this->ike_sa);
-       auth_method = auth_payload->get_auth_method(auth_payload);
-       switch (auth_method)
-       {
-               case AUTH_RSA:
-                       /* We are currently fixed to SHA1 hashes.
-                        * TODO: allow other hash algorithms and note it in "auth" */
-                       key_type = KEY_RSA;
-                       scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
-                       break;
-               case AUTH_ECDSA_256:
-                       scheme = SIGN_ECDSA_256;
-                       break;
-               case AUTH_ECDSA_384:
-                       scheme = SIGN_ECDSA_384;
-                       break;
-               case AUTH_ECDSA_521:
-                       scheme = SIGN_ECDSA_521;
-                       break;
-               default:
-                       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);
-       
-       auth = this->ike_sa->get_other_auth(this->ike_sa);
-       enumerator = charon->credentials->create_public_enumerator(
-                                                               charon->credentials, key_type, other_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);
-                       status = SUCCESS;
-                       auth->merge(auth, current_auth);
-                       break;
-               }
-               else
-               {
-                       DBG1(DBG_IKE, "signature validation failed, looking for another key");
-               }
-       }
-       enumerator->destroy(enumerator);
-       chunk_free(&octets);
-       return status;
-}
+       /**
+        * IKE_SA_INIT message data to include in AUTH calculation
+        */
+       chunk_t ike_sa_init;
+};
 
 /**
- * Implementation of authenticator_t.build.
+ * Implementation of authenticator_t.build for builder
  */
-static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
-                                         chunk_t other_nonce, auth_payload_t **auth_payload)
+static status_t build(private_pubkey_authenticator_t *this, message_t *message)
 {
        chunk_t octets, auth_data;
        status_t status = FAILED;
        private_key_t *private;
-       identification_t *my_id;
-       prf_t *prf;
-       auth_info_t *auth;
+       identification_t *id;
+       auth_cfg_t *auth;
+       auth_payload_t *auth_payload;
        auth_method_t auth_method;
        signature_scheme_t scheme;
+       keymat_t *keymat;
 
-       my_id = this->ike_sa->get_my_id(this->ike_sa);
-       DBG1(DBG_IKE, "authentication of '%D' (myself) with public key", my_id);
-       
-       auth = this->ike_sa->get_my_auth(this->ike_sa);
+       id = this->ike_sa->get_my_id(this->ike_sa);
+       auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
        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 '%Y'", id);
                return NOT_FOUND;
        }
-       
+
        switch (private->get_type(private))
        {
                case KEY_RSA:
-                       /* we currently use always SHA1 for signatures, 
+                       /* we currently use always SHA1 for signatures,
                         * TODO: support other hashes depending on configuration/auth */
                        scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
                        auth_method = AUTH_RSA;
@@ -156,7 +86,7 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
                        switch (private->get_keysize(private))
                        {
                                case 32:
-                                       scheme = SIGN_ECDSA_256; 
+                                       scheme = SIGN_ECDSA_256;
                                        auth_method = AUTH_ECDSA_256;
                                        break;
                                case 48:
@@ -168,7 +98,8 @@ static status_t build(private_pubkey_authenticator_t *this, chunk_t ike_sa_init,
                                        auth_method = AUTH_ECDSA_521;
                                        break;
                                default:
-                                       DBG1(DBG_IKE, "ECDSA not supported by private key");
+                                       DBG1(DBG_IKE, "%d bit ECDSA private key size not supported",
+                                                       private->get_keysize(private));
                                        return status;
                        }
                        break;
@@ -177,32 +108,115 @@ 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, this->ike_sa_init,
+                                                                        this->nonce, id);
        if (private->sign(private, scheme, octets, &auth_data))
        {
-               auth_payload_t *payload = auth_payload_create();
-               payload->set_auth_method(payload, auth_method);
-               payload->set_data(payload, auth_data);
-               *auth_payload = payload;
+               auth_payload = auth_payload_create();
+               auth_payload->set_auth_method(auth_payload, auth_method);
+               auth_payload->set_data(auth_payload, auth_data);
                chunk_free(&auth_data);
+               message->add_payload(message, (payload_t*)auth_payload);
                status = SUCCESS;
-               DBG2(DBG_IKE, "successfully built %N with private key", auth_method_names, auth_method);
        }
-       else
+       DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id,
+                auth_method_names, auth_method,
+                (status == SUCCESS)? "successful":"failed");
+       chunk_free(&octets);
+       private->destroy(private);
+
+       return status;
+}
+
+/**
+ * Implementation of authenticator_t.process for verifier
+ */
+static status_t process(private_pubkey_authenticator_t *this, message_t *message)
+{
+       public_key_t *public;
+       auth_method_t auth_method;
+       auth_payload_t *auth_payload;
+       chunk_t auth_data, octets;
+       identification_t *id;
+       auth_cfg_t *auth, *current_auth;
+       enumerator_t *enumerator;
+       key_type_t key_type = KEY_ECDSA;
+       signature_scheme_t scheme;
+       status_t status = NOT_FOUND;
+       keymat_t *keymat;
+
+       auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
+       if (!auth_payload)
+       {
+               return FAILED;
+       }
+       auth_method = auth_payload->get_auth_method(auth_payload);
+       switch (auth_method)
+       {
+               case AUTH_RSA:
+                       /* We currently accept SHA1 signatures only
+                        * TODO: allow other hash algorithms and note it in "auth" */
+                       key_type = KEY_RSA;
+                       scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+                       break;
+               case AUTH_ECDSA_256:
+                       scheme = SIGN_ECDSA_256;
+                       break;
+               case AUTH_ECDSA_384:
+                       scheme = SIGN_ECDSA_384;
+                       break;
+               case AUTH_ECDSA_521:
+                       scheme = SIGN_ECDSA_521;
+                       break;
+               default:
+                       return INVALID_ARG;
+       }
+       auth_data = auth_payload->get_data(auth_payload);
+       id = this->ike_sa->get_other_id(this->ike_sa);
+       keymat = this->ike_sa->get_keymat(this->ike_sa);
+       octets = keymat->get_auth_octets(keymat, TRUE, this->ike_sa_init,
+                                                                        this->nonce, id);
+       auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
+       enumerator = charon->credentials->create_public_enumerator(
+                                                                               charon->credentials, key_type, id, auth);
+       while (enumerator->enumerate(enumerator, &public, &current_auth))
        {
-               DBG1(DBG_IKE, "building signature failed");
+               if (public->verify(public, scheme, octets, auth_data))
+               {
+                       DBG1(DBG_IKE, "authentication of '%Y' with %N successful",
+                                                  id, auth_method_names, auth_method);
+                       status = SUCCESS;
+                       auth->merge(auth, current_auth, FALSE);
+                       auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
+                       break;
+               }
+               else
+               {
+                       status = FAILED;
+                       DBG1(DBG_IKE, "signature validation failed, looking for another key");
+               }
        }
+       enumerator->destroy(enumerator);
        chunk_free(&octets);
-       private->destroy(private);
-       
+       if (status == NOT_FOUND)
+       {
+               DBG1(DBG_IKE, "no trusted %N public key found for '%Y'",
+                        key_type_names, key_type, id);
+       }
        return status;
 }
 
 /**
+ * Implementation of authenticator_t.process for builder
+ * Implementation of authenticator_t.build for verifier
+ */
+static status_t return_failed()
+{
+       return FAILED;
+}
+
+/**
  * Implementation of authenticator_t.destroy.
  */
 static void destroy(private_pubkey_authenticator_t *this)
@@ -213,17 +227,39 @@ static void destroy(private_pubkey_authenticator_t *this)
 /*
  * Described in header.
  */
-pubkey_authenticator_t *pubkey_authenticator_create(ike_sa_t *ike_sa)
+pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa,
+                                                                       chunk_t received_nonce, chunk_t sent_init)
 {
        private_pubkey_authenticator_t *this = malloc_thing(private_pubkey_authenticator_t);
-       
-       /* public functions */
-       this->public.authenticator_interface.verify = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t*))verify;
-       this->public.authenticator_interface.build = (status_t(*)(authenticator_t*,chunk_t,chunk_t,auth_payload_t**))build;
-       this->public.authenticator_interface.destroy = (void(*)(authenticator_t*))destroy;
-       
-       /* private data */
+
+       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;
-       
+       this->ike_sa_init = sent_init;
+       this->nonce = received_nonce;
+
+       return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa,
+                                                                       chunk_t sent_nonce, chunk_t received_init)
+{
+       private_pubkey_authenticator_t *this = malloc_thing(private_pubkey_authenticator_t);
+
+       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;
+       this->ike_sa_init = received_init;
+       this->nonce = sent_nonce;
+
        return &this->public;
 }