updates.
[silc.git] / lib / silcclient / protocol.c
index 8460ad8fccd0df61fb4f5c315c8086d459cc7eda..da7bc07fb352423627398550db7c670bd609cb86 100644 (file)
@@ -97,10 +97,10 @@ void silc_client_protocol_ke_verify_key(SilcSKE ske,
   verify->completion_context = completion_context;
 
   /* Verify public key from user. */
-  client->ops->verify_public_key(client, ctx->sock->user_data, 
-                                ctx->sock->type,
-                                pk_data, pk_len, pk_type,
-                                silc_client_verify_key_cb, verify);
+  client->internal->ops->verify_public_key(client, ctx->sock->user_data, 
+                                          ctx->sock->type,
+                                          pk_data, pk_len, pk_type,
+                                          silc_client_verify_key_cb, verify);
 }
 
 /* Sets the negotiated key material into use for particular connection. */
@@ -112,7 +112,8 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske,
                                      SilcPKCS pkcs,
                                      SilcHash hash,
                                      SilcHmac hmac,
-                                     SilcSKEDiffieHellmanGroup group)
+                                     SilcSKEDiffieHellmanGroup group,
+                                     bool is_responder)
 {
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
 
@@ -121,34 +122,43 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske,
   /* Allocate cipher to be used in the communication */
   silc_cipher_alloc(cipher->cipher->name, &conn->send_key);
   silc_cipher_alloc(cipher->cipher->name, &conn->receive_key);
-
-  conn->send_key->cipher->set_key(conn->send_key->context, 
-                                keymat->send_enc_key, 
-                                keymat->enc_key_len);
-  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);
-  conn->receive_key->set_iv(conn->receive_key, keymat->receive_iv);
+  silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_send);
+  silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, &conn->hmac_receive);
+
+  if (is_responder == TRUE) {
+    silc_cipher_set_key(conn->send_key, keymat->receive_enc_key, 
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(conn->send_key, keymat->receive_iv);
+    silc_cipher_set_key(conn->receive_key, keymat->send_enc_key, 
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(conn->receive_key, keymat->send_iv);
+    silc_hmac_set_key(conn->hmac_send, keymat->receive_hmac_key, 
+                     keymat->hmac_key_len);
+    silc_hmac_set_key(conn->hmac_receive, keymat->send_hmac_key, 
+                     keymat->hmac_key_len);
+  } else {
+    silc_cipher_set_key(conn->send_key, keymat->send_enc_key, 
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(conn->send_key, keymat->send_iv);
+    silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, 
+                       keymat->enc_key_len);
+    silc_cipher_set_iv(conn->receive_key, keymat->receive_iv);
+    silc_hmac_set_key(conn->hmac_send, keymat->send_hmac_key, 
+                     keymat->hmac_key_len);
+    silc_hmac_set_key(conn->hmac_receive, keymat->receive_hmac_key, 
+                     keymat->hmac_key_len);
+  }
 
   /* Rekey stuff */
   conn->rekey = silc_calloc(1, sizeof(*conn->rekey));
-  conn->rekey->send_enc_key = 
-    silc_calloc(keymat->enc_key_len / 8,
-               sizeof(*conn->rekey->send_enc_key));
-  memcpy(conn->rekey->send_enc_key, 
-        keymat->send_enc_key, keymat->enc_key_len / 8);
+  conn->rekey->send_enc_key = silc_memdup(keymat->send_enc_key, 
+                                         keymat->enc_key_len / 8);
   conn->rekey->enc_key_len = keymat->enc_key_len / 8;
 
   if (ske->start_payload->flags & SILC_SKE_SP_FLAG_PFS)
     conn->rekey->pfs = TRUE;
   conn->rekey->ske_group = silc_ske_group_get_number(group);
 
-  /* Save HMAC key to be used in the communication. */
-  silc_hmac_alloc(hmac->hmac->name, NULL, &conn->hmac_send);
-  silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, keymat->hmac_key_len);
-  conn->hmac_receive = conn->hmac_send;
-
   /* Save the HASH function */
   silc_hash_alloc(hash->hash->name, &conn->hash);
 }
@@ -184,7 +194,7 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
   if (cp)
     build = atoi(cp + 1);
 
-  cp = client->silc_client_version + 9;
+  cp = client->internal->silc_client_version + 9;
   if (!cp)
     status = SILC_SKE_STATUS_BAD_VERSION;
 
@@ -200,12 +210,15 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
 
   if (maj != maj2)
     status = SILC_SKE_STATUS_BAD_VERSION;
-  if (min < min2)
-    status = SILC_SKE_STATUS_BAD_VERSION;
+
+  /* XXX backward support for 0.6.1 */
+  if (maj == 0 && min == 6 && build < 2)
+    ske->backward_version = 1;
 
   if (status != SILC_SKE_STATUS_OK)
-    client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
-                    "We don't support server version `%s'", version);
+    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+                              "We don't support server version `%s'", 
+                              version);
 
   return status;
 }
@@ -229,20 +242,9 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
   SILC_LOG_DEBUG(("Start"));
 
   if (ske->status != SILC_SKE_STATUS_OK) {
-    if (ske->status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
-      client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
-                      "Received unsupported server %s public key",
-                      ctx->sock->hostname);
-    } else if (ske->status == SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED) {
-      client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
-                      "Remote host did not send its public key, even though "
-                      "it must send it");
-    } else {
-      client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
-                      "Error during key exchange protocol with server %s",
-                      ctx->sock->hostname);
-    }
-    
+    /* Call failure client operation */
+    client->internal->ops->failure(client, conn, protocol, 
+                                  (void *)ske->status);
     protocol->state = SILC_PROTOCOL_STATE_ERROR;
     silc_protocol_execute(protocol, client->schedule, 0, 0);
     return;
@@ -294,10 +296,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       SilcSKE ske;
 
       /* Allocate Key Exchange object */
-      ske = silc_ske_alloc();
-      ctx->ske = ske;
-      ske->rng = client->rng;
-      ske->user_data = (void *)client;
+      ctx->ske = ske = silc_ske_alloc(client->rng, client);
 
       silc_ske_set_callbacks(ske, ctx->send_packet, NULL,
                             ctx->verify,
@@ -308,16 +307,18 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       if (ctx->responder == TRUE) {
        /* Start the key exchange by processing the received security
           properties packet from initiator. */
-       status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
-                                         client->silc_client_version,
-                                         ctx->packet->buffer, TRUE);
+       status = 
+         silc_ske_responder_start(ske, ctx->rng, ctx->sock,
+                                  client->internal->silc_client_version,
+                                  ctx->packet->buffer, TRUE);
       } else {
        SilcSKEStartPayload *start_payload;
 
        /* Assemble security properties. */
-       silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_NONE, 
-                                             client->silc_client_version,
-                                             &start_payload);
+       silc_ske_assemble_security_properties(
+                                 ske, SILC_SKE_SP_FLAG_MUTUAL, 
+                                 client->internal->silc_client_version,
+                                 &start_payload);
 
        /* Start the key exchange by sending our security properties
           to the remote end. */
@@ -353,9 +354,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
        */
       if (ctx->responder == TRUE) {
        /* Sends the selected security properties to the initiator. */
-       status = 
-         silc_ske_responder_phase_1(ctx->ske, 
-                                    ctx->ske->start_payload);
+       status = silc_ske_responder_phase_1(ctx->ske);
       } else {
        /* Call Phase-1 function. This processes the Key Exchange Start
           paylaod reply we just got from the responder. The callback
@@ -398,7 +397,8 @@ 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,
-                                           client->private_key);
+                                           client->private_key,
+                                           SILC_SKE_PK_TYPE_SILC);
        protocol->state++;
       }
 
@@ -446,11 +446,13 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
 
       if (status != SILC_SKE_STATUS_OK) {
         if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
-          client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
-                          "Received unsupported server %s public key",
-                          ctx->sock->hostname);
+          client->internal->ops->say(
+                            client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
+                            "Received unsupported server %s public key",
+                            ctx->sock->hostname);
         } else {
-          client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+          client->internal->ops->say(
+                          client, conn, SILC_CLIENT_MESSAGE_AUDIT,
                           "Error during key exchange protocol with server %s",
                           ctx->sock->hostname);
         }
@@ -650,12 +652,13 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
          break;
        }
 
-       client->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
-                        "Password authentication required by server %s",
-                        ctx->sock->hostname);
-       client->ops->ask_passphrase(client, conn,
-                                   silc_client_conn_auth_continue,
-                                   protocol);
+       client->internal->ops->say(
+                       client, conn, SILC_CLIENT_MESSAGE_INFO,
+                       "Password authentication required by server %s",
+                       ctx->sock->hostname);
+       client->internal->ops->ask_passphrase(client, conn,
+                                             silc_client_conn_auth_continue,
+                                             protocol);
        return;
        break;
 
@@ -750,41 +753,37 @@ silc_client_protocol_rekey_validate(SilcClient client,
       silc_cipher_set_key(conn->send_key, keymat->receive_enc_key, 
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->send_key, keymat->receive_iv);
+      silc_hmac_set_key(conn->hmac_send, keymat->receive_hmac_key, 
+                       keymat->hmac_key_len);
     } else {
       silc_cipher_set_key(conn->receive_key, keymat->send_enc_key, 
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->receive_key, keymat->send_iv);
+      silc_hmac_set_key(conn->hmac_receive, keymat->send_hmac_key, 
+                       keymat->hmac_key_len);
     }
   } else {
     if (send) {
       silc_cipher_set_key(conn->send_key, keymat->send_enc_key, 
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->send_key, keymat->send_iv);
+      silc_hmac_set_key(conn->hmac_send, keymat->send_hmac_key, 
+                       keymat->hmac_key_len);
     } else {
       silc_cipher_set_key(conn->receive_key, keymat->receive_enc_key, 
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->receive_key, keymat->receive_iv);
+      silc_hmac_set_key(conn->hmac_receive, keymat->receive_hmac_key, 
+                       keymat->hmac_key_len);
     }
   }
 
-  if (send) {
-    silc_hmac_alloc(conn->hmac_receive->hmac->name, NULL, &conn->hmac_send);
-    silc_hmac_set_key(conn->hmac_send, keymat->hmac_key, 
-                     keymat->hmac_key_len);
-  } else {
-    silc_hmac_free(conn->hmac_receive);
-    conn->hmac_receive = conn->hmac_send;
-  }
-
   /* Save the current sending encryption key */
   if (!send) {
     memset(conn->rekey->send_enc_key, 0, conn->rekey->enc_key_len);
     silc_free(conn->rekey->send_enc_key);
-    conn->rekey->send_enc_key = 
-      silc_calloc(keymat->enc_key_len / 8,
-                 sizeof(*conn->rekey->send_enc_key));
-    memcpy(conn->rekey->send_enc_key, keymat->send_enc_key, 
-          keymat->enc_key_len / 8);
+    conn->rekey->send_enc_key = silc_memdup(keymat->send_enc_key,
+                                           keymat->enc_key_len / 8);
     conn->rekey->enc_key_len = keymat->enc_key_len / 8;
   }
 }
@@ -913,10 +912,9 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
            silc_protocol_execute(protocol, client->schedule, 0, 300000);
          }
 
-         ctx->ske = silc_ske_alloc();
-         ctx->ske->rng = client->rng;
+         ctx->ske = silc_ske_alloc(client->rng, client);
          ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
-         silc_ske_get_group_by_number(conn->rekey->ske_group,
+         silc_ske_group_get_by_number(conn->rekey->ske_group,
                                       &ctx->ske->prop->group);
 
          silc_ske_set_callbacks(ctx->ske, 
@@ -970,10 +968,9 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
           * Use Perfect Forward Secrecy, ie. negotiate the key material
           * using the SKE protocol.
           */
-         ctx->ske = silc_ske_alloc();
-         ctx->ske->rng = client->rng;
+         ctx->ske = silc_ske_alloc(client->rng, client);
          ctx->ske->prop = silc_calloc(1, sizeof(*ctx->ske->prop));
-         silc_ske_get_group_by_number(conn->rekey->ske_group,
+         silc_ske_group_get_by_number(conn->rekey->ske_group,
                                       &ctx->ske->prop->group);
 
          silc_ske_set_callbacks(ctx->ske, 
@@ -981,7 +978,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
                                 NULL,  NULL, NULL, silc_ske_check_version,
                                 context);
       
-         status =  silc_ske_initiator_phase_2(ctx->ske, NULL, NULL);
+         status =  silc_ske_initiator_phase_2(ctx->ske, NULL, NULL, 0);
          if (status != SILC_SKE_STATUS_OK) {
            SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
                              status));