Created SILC Client Libary by moving stuff from silc/ directory.
[silc.git] / lib / silcclient / protocol.c
similarity index 75%
rename from apps/silc/protocol.c
rename to lib/silcclient/protocol.c
index ba89d9dcf80a4fb47ddd4d9b24a98aeee608d0f3..d0b8064c1093adc736e96f4cd8dbd5f3bd179f79 100644 (file)
 /*
  * Client side of the protocols.
  */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
-#include "clientincludes.h"
+#include "clientlibincludes.h"
 
 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
-SILC_TASK_CALLBACK(silc_client_protocol_channel_auth);
 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
 
-/* SILC client protocol list */
-const SilcProtocolObject silc_protocol_list[] =
-{
-  { SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
-    silc_client_protocol_connection_auth },
-  { SILC_PROTOCOL_CLIENT_CHANNEL_AUTH, 
-    silc_client_protocol_channel_auth },
-  { SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
-    silc_client_protocol_key_exchange },
-
-  { SILC_PROTOCOL_CLIENT_NONE, NULL },
-};
+extern char *silc_version_string;
 
 /*
  * Key Exhange protocol functions
  */
 
+/* Function that is called when SKE protocol sends packets to network. */
+
 static void silc_client_protocol_ke_send_packet(SilcSKE ske,
                                                SilcBuffer packet,
                                                SilcPacketType type,
@@ -68,20 +51,15 @@ static void silc_client_protocol_ke_send_packet(SilcSKE ske,
 
 }
 
-static void silc_client_protocol_ke_phase1_cb(SilcSKE ske,
-                                             void *context)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
-    (SilcClientKEInternalContext *)protocol->context;
-  SilcClient client = (SilcClient)ctx->client;
-
-  SILC_LOG_DEBUG(("Start"));
-
-}
+/* Callback that is called when we have received KE2 payload from
+   responder. We try to verify the public key now. */
 
-static void silc_client_protocol_ke_finish_cb(SilcSKE ske,
-                                             void *context)
+static SilcSKEStatus 
+silc_client_protocol_ke_verify_key(SilcSKE ske,
+                                  unsigned char *pk_data,
+                                  unsigned int pk_len,
+                                  SilcSKEPKType pk_type,
+                                  void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
   SilcClientKEInternalContext *ctx = 
@@ -90,6 +68,12 @@ static void silc_client_protocol_ke_finish_cb(SilcSKE ske,
 
   SILC_LOG_DEBUG(("Start"));
 
+  /* Verify server key from user. */
+  if (!client->ops->verify_server_key(client, ctx->sock->user_data, 
+                                     pk_data, pk_len, pk_type))
+    return SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+
+  return SILC_SKE_STATUS_OK;
 }
 
 /* Sets the negotiated key material into use for particular connection. */
@@ -101,42 +85,38 @@ static void silc_client_protocol_ke_set_keys(SilcSKE ske,
                                             SilcPKCS pkcs,
                                             SilcHash hash)
 {
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
   SilcHash nhash;
 
   SILC_LOG_DEBUG(("Setting new keys into use"));
 
   /* Allocate cipher to be used in the communication */
-  silc_cipher_alloc(cipher->cipher->name, &win->send_key);
-  silc_cipher_alloc(cipher->cipher->name, &win->receive_key);
+  silc_cipher_alloc(cipher->cipher->name, &conn->send_key);
+  silc_cipher_alloc(cipher->cipher->name, &conn->receive_key);
 
-  win->send_key->cipher->set_key(win->send_key->context, 
+  conn->send_key->cipher->set_key(conn->send_key->context, 
                                 keymat->send_enc_key, 
                                 keymat->enc_key_len);
-  win->send_key->set_iv(win->send_key, keymat->send_iv);
-  win->receive_key->cipher->set_key(win->receive_key->context, 
+  conn->send_key->set_iv(conn->send_key, keymat->send_iv);
+  conn->receive_key->cipher->set_key(conn->receive_key->context, 
                                    keymat->receive_enc_key, 
                                    keymat->enc_key_len);
-  win->receive_key->set_iv(win->receive_key, keymat->receive_iv);
+  conn->receive_key->set_iv(conn->receive_key, keymat->receive_iv);
 
   /* Allocate PKCS to be used */
 #if 0
   /* XXX Do we ever need to allocate PKCS for the connection??
      If yes, we need to change KE protocol to get the initiators
      public key. */
-  silc_pkcs_alloc(pkcs->pkcs->name, &win->public_Key);
-  silc_pkcs_set_public_key(win->public_key, ske->ke2_payload->pk_data, 
+  silc_pkcs_alloc(pkcs->pkcs->name, &conn->public_Key);
+  silc_pkcs_set_public_key(conn->public_key, ske->ke2_payload->pk_data, 
                           ske->ke2_payload->pk_len);
 #endif
 
   /* Save HMAC key to be used in the communication. */
   silc_hash_alloc(hash->hash->name, &nhash);
-  silc_hmac_alloc(nhash, &win->hmac);
-  win->hmac_key_len = keymat->hmac_key_len;
-  win->hmac_key = silc_calloc(win->hmac_key_len,
-                                   sizeof(unsigned char));
-  memcpy(win->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
-
+  silc_hmac_alloc(nhash, &conn->hmac);
+  silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
 }
 
 /* Performs key exchange protocol. This is used for both initiator
@@ -148,6 +128,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
   SilcClientKEInternalContext *ctx = 
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
+  SilcClientConnection conn = ctx->sock->user_data;
   SilcSKEStatus status;
 
   SILC_LOG_DEBUG(("Start"));
@@ -183,7 +164,8 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
        SilcSKEStartPayload *start_payload;
 
        /* Assemble security properties. */
-       silc_ske_assemble_security_properties(ske, &start_payload);
+       silc_ske_assemble_security_properties(ske, silc_version_string,
+                                             &start_payload);
 
        /* Start the key exchange by sending our security properties
           to the remote end. */
@@ -223,11 +205,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
           paylaod reply we just got from the responder. The callback
           function will receive the processed payload where we will
           save it. */
-       status = 
-         silc_ske_initiator_phase_1(ctx->ske,
-                                    ctx->packet,
-                                    silc_client_protocol_ke_phase1_cb,
-                                    context);
+       status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet, NULL, NULL);
       }
 
       switch(status) {
@@ -259,6 +237,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
           Key Exhange 1 Payload to the responder. */
        status = 
          silc_ske_initiator_phase_2(ctx->ske,
+                                    client->public_key,
                                     silc_client_protocol_ke_send_packet,
                                     context);
       }
@@ -278,6 +257,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
        * Finish protocol
        */
       if (ctx->responder == TRUE) {
+       status = 0;
 #if 0
        status = 
          silc_ske_responder_phase_2(ctx->ske, 
@@ -288,16 +268,25 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       } else {
        /* Finish the protocol. This verifies the Key Exchange 2 payload
           sent by responder. */
-       status = 
-         silc_ske_initiator_finish(ctx->ske,
-                                   ctx->packet,
-                                   silc_client_protocol_ke_finish_cb,
-                                   context);
+       status = silc_ske_initiator_finish(ctx->ske, ctx->packet,
+                                          silc_client_protocol_ke_verify_key,
+                                          context, NULL, NULL);
       }
 
-      switch(status) {
-      default:
-       break;
+      if (status != SILC_SKE_STATUS_OK) {
+
+        if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
+          client->ops->say(client, conn, 
+                          "Received unsupported server %s public key",
+                          ctx->sock->hostname);
+        } else {
+          client->ops->say(client, conn,
+                          "Error during key exchange protocol with server %s",
+                          ctx->sock->hostname);
+        }
+       protocol->state = SILC_PROTOCOL_STATE_ERROR;
+       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+       return;
       }
       
       /* Send Ok to the other end. We will end the protocol as server
@@ -335,7 +324,10 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
   case SILC_PROTOCOL_STATE_ERROR:
     
     /* On error the final callback is always called. */
-    /*    protocol->final_callback(pptr, context);*/
+    if (protocol->final_callback)
+      protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
     break;
   case SILC_PROTOCOL_STATE_UNKNOWN:
     break;
@@ -352,6 +344,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
   SilcClientConnAuthInternalContext *ctx = 
     (SilcClientConnAuthInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
+  SilcClientConnection conn = ctx->sock->user_data;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -383,16 +376,15 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
          break;
        }
 
-       silc_say(client, "Password authentication required by server %s",
-                ctx->sock->hostname);
-       auth_data = silc_client_ask_passphrase(client);
+       client->ops->say(client, conn, 
+                        "Password authentication required by server %s",
+                        ctx->sock->hostname);
+       auth_data = client->ops->ask_passphrase(client, conn);
        auth_data_len = strlen(auth_data);
        break;
 
       case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
-#if 0
-
-#endif
+       /* XXX */
        break;
       }
 
@@ -459,6 +451,22 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
   }
 }
 
-SILC_TASK_CALLBACK(silc_client_protocol_channel_auth)
+/* Registers protocols used in client */
+
+void silc_client_protocols_register(void)
+{
+  silc_protocol_register(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
+                        silc_client_protocol_connection_auth);
+  silc_protocol_register(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+                        silc_client_protocol_key_exchange);
+}
+
+/* Unregisters protocols */
+
+void silc_client_protocols_unregister(void)
 {
+  silc_protocol_unregister(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
+                          silc_client_protocol_connection_auth);
+  silc_protocol_unregister(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+                          silc_client_protocol_key_exchange);
 }