updates. New data types.
[silc.git] / lib / silcclient / protocol.c
index 5040a3014da88186d47b24c2db588a95b49e0b7d..5255b67abf6d04d9906a84c31803600ffd86b97a 100644 (file)
@@ -57,7 +57,7 @@ void silc_client_protocol_ke_send_packet(SilcSKE ske,
 
 SilcSKEStatus silc_client_protocol_ke_verify_key(SilcSKE ske,
                                                 unsigned char *pk_data,
-                                                unsigned int pk_len,
+                                                uint32 pk_len,
                                                 SilcSKEPKType pk_type,
                                                 void *context)
 {
@@ -68,8 +68,9 @@ SilcSKEStatus silc_client_protocol_ke_verify_key(SilcSKE ske,
 
   SILC_LOG_DEBUG(("Start"));
 
-  /* Verify server key from user. */
-  if (!client->ops->verify_server_key(client, ctx->sock->user_data, 
+  /* Verify public key from user. */
+  if (!client->ops->verify_public_key(client, ctx->sock->user_data, 
+                                     ctx->sock->type,
                                      pk_data, pk_len, pk_type))
     return SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
 
@@ -116,12 +117,15 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske,
   /* Save HMAC key to be used in the communication. */
   silc_hmac_alloc(hmac->hmac->name, NULL, &conn->hmac);
   silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
+
+  /* Save the HASH function */
+  silc_hash_alloc(hash->hash->name, &conn->hash);
 }
 
 /* Checks the version string of the server. */
 
 SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
-                                    unsigned int len)
+                                    uint32 len)
 {
   SilcClientConnection conn = (SilcClientConnection)ske->sock->user_data;
   SilcClient client = (SilcClient)ske->user_data;
@@ -182,7 +186,8 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
           properties packet from initiator. */
        status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
                                          silc_version_string,
-                                         ctx->packet->buffer, NULL, NULL);
+                                         ctx->packet->buffer, TRUE,
+                                         NULL, NULL);
       } else {
        SilcSKEStartPayload *start_payload;
 
@@ -264,16 +269,16 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
           the initiator. This also creates our parts of the Diffie
           Hellman algorithm. */
        status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer, 
-                                           NULL, NULL);
+                                           ctx->verify, context, NULL, NULL);
       } else {
        /* Call the Phase-2 function. This creates Diffie Hellman
           key exchange parameters and sends our public part inside
           Key Exhange 1 Payload to the responder. */
-       status = 
-         silc_ske_initiator_phase_2(ctx->ske,
-                                    client->public_key,
-                                    ctx->send_packet,
-                                    context);
+       status = silc_ske_initiator_phase_2(ctx->ske,
+                                           client->public_key,
+                                           client->private_key,
+                                           ctx->send_packet,
+                                           context);
       }
 
       if (status != SILC_SKE_STATUS_OK) {
@@ -423,6 +428,53 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
  * Connection Authentication protocol functions
  */
 
+static int
+silc_client_get_public_key_auth(SilcClient client,
+                               char *filepath,
+                               unsigned char *auth_data,
+                               uint32 *auth_data_len,
+                               SilcSKE ske)
+{
+  int len;
+  SilcPKCS pkcs;
+  SilcBuffer auth;
+  SilcPublicKey pub_key;
+
+  if (!silc_pkcs_load_public_key(filepath,&pub_key, SILC_PKCS_FILE_PEM))
+    if (!silc_pkcs_load_public_key(filepath, &pub_key, SILC_PKCS_FILE_BIN))
+      return FALSE;
+
+  silc_pkcs_alloc(pub_key->name, &pkcs);
+  if (!silc_pkcs_public_key_set(pkcs, pub_key)) {
+    silc_pkcs_free(pkcs);
+    silc_pkcs_public_key_free(pub_key);
+    return FALSE;
+  }
+
+  /* Make the authentication data. Protocol says it is HASH plus
+     KE Start Payload. */
+  len = ske->hash_len + ske->start_payload_copy->len;
+  auth = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(auth, len);
+  silc_buffer_format(auth,
+                    SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
+                    SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+                                         ske->start_payload_copy->len),
+                    SILC_STR_END);
+
+  if (silc_pkcs_sign(pkcs, auth->data, auth->len, auth_data, auth_data_len)) {
+    silc_pkcs_free(pkcs);
+    silc_buffer_free(auth);
+    silc_pkcs_public_key_free(pub_key);
+    return TRUE;
+  }
+
+  silc_pkcs_free(pkcs);
+  silc_buffer_free(auth);
+  silc_pkcs_public_key_free(pub_key);
+  return FALSE;
+}
+
 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 {
   SilcProtocol protocol = (SilcProtocol)context;
@@ -446,7 +498,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
       SilcBuffer packet;
       int payload_len = 0;
       unsigned char *auth_data = NULL;
-      unsigned int auth_data_len = 0;
+      uint32 auth_data_len = 0;
 
       switch(ctx->auth_meth) {
       case SILC_AUTH_NONE:
@@ -469,8 +521,17 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
        break;
 
       case SILC_AUTH_PUBLIC_KEY:
-       /* XXX */
-       break;
+       {
+         unsigned char sign[1024];
+
+         /* Public key authentication */
+         silc_client_get_public_key_auth(client, ctx->auth_data,
+                                         sign, &auth_data_len, 
+                                         ctx->ske);
+         auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
+         memcpy(auth_data, sign, auth_data_len);
+         break;
+       }
       }
 
       payload_len = 4 + auth_data_len;