tupdates
[silc.git] / apps / silcd / protocol.c
index a7a1b707d7d1a39000626dbf555ac8f20a52cd2d..7e6b1631e3f96593e726a8b9e33c6bdb216013e7 100644 (file)
@@ -283,7 +283,7 @@ int silc_server_protocol_ke_set_keys(SilcServer server,
         keymat->send_enc_key, keymat->enc_key_len / 8);
   idata->rekey->enc_key_len = keymat->enc_key_len / 8;
 
-  if (ske->start_payload->flags & SILC_SKE_SP_FLAG_PFS)
+  if (ske->prop->flags & SILC_SKE_SP_FLAG_PFS)
     idata->rekey->pfs = TRUE;
   idata->rekey->ske_group = silc_ske_group_get_number(group);
 
@@ -471,12 +471,12 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
           properties packet from initiator. */
        status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
                                          silc_version_string,
-                                         ctx->packet->buffer, TRUE);
+                                         ctx->packet->buffer, ctx->flags);
       } else {
        SilcSKEStartPayload *start_payload;
 
        /* Assemble security properties. */
-       silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_MUTUAL
+       silc_ske_assemble_security_properties(ske, ctx->flags
                                              silc_version_string,
                                              &start_payload);
 
@@ -783,7 +783,7 @@ silc_server_public_key_authentication(SilcServer server,
 
 static int
 silc_server_get_public_key_auth(SilcServer server,
-                               unsigned char *auth_data,
+                               unsigned char **auth_data,
                                uint32 *auth_data_len,
                                SilcSKE ske)
 {
@@ -804,16 +804,63 @@ silc_server_get_public_key_auth(SilcServer server,
                                          ske->start_payload_copy->len),
                     SILC_STR_END);
 
+  *auth_data = silc_calloc(silc_pkcs_get_key_len(pkcs), sizeof(**auth_data));
   if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data, 
-                              auth->len, auth_data, auth_data_len)) {
+                              auth->len, *auth_data, auth_data_len)) {
     silc_buffer_free(auth);
     return TRUE;
   }
 
+  silc_free(*auth_data);
   silc_buffer_free(auth);
   return FALSE;
 }
 
+/* Function that actually performs the authentication to the remote. This
+   supports both passphrase and public key authentication. */
+
+static bool 
+silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx,
+                              char *local_passphrase,
+                              void *local_publickey,
+                              unsigned char *remote_auth,
+                              uint32 remote_auth_len)
+{
+  SilcServer server = (SilcServer)ctx->server;
+  SilcSKE ske = ctx->ske;
+  bool result = FALSE;
+
+  /* If we don't have authentication data set at all we do not require
+     authentication at all */
+  if (!local_passphrase && !local_publickey) {
+    SILC_LOG_DEBUG(("No authentication required"));
+    return TRUE;
+  }
+
+  /* If both passphrase and public key is provided then we'll try both of
+     them and see which one of them authenticates.  If only one of them is
+     set, then try only that. */
+
+  /* Try first passphrase (as it is faster to check) */
+  if (local_passphrase) {
+    SILC_LOG_DEBUG(("Password authentication"));
+    result = silc_server_password_authentication(server, local_passphrase,
+                                                remote_auth);
+  }
+
+  /* Try public key authenetication */
+  if (!result && local_publickey) {
+    SILC_LOG_DEBUG(("Public key authentication"));
+    result = silc_server_public_key_authentication(server, 
+                                                  local_publickey,
+                                                  remote_auth,
+                                                  remote_auth_len, 
+                                                  ske);
+  }
+
+  return result;
+}
+
 /* Performs connection authentication protocol. If responder, we 
    authenticate the remote data received. If initiator, we will send
    authentication data to the remote end. */
@@ -906,52 +953,19 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
 
        /* Remote end is client */
        if (conn_type == SILC_SOCKET_TYPE_CLIENT) {
-         SilcServerConfigSectionClient *client = ctx->cconfig;
+         SilcServerConfigClient *client = ctx->cconfig;
          
          if (client) {
-           switch(client->auth_meth) {
-           case SILC_AUTH_NONE:
-             /* No authentication required */
-             SILC_LOG_DEBUG(("No authentication required"));
-             break;
-             
-           case SILC_AUTH_PASSWORD:
-             /* Password authentication */
-             SILC_LOG_DEBUG(("Password authentication"));
-             ret = silc_server_password_authentication(server, auth_data,
-                                                       client->auth_data);
-
-             if (ret)
-               break;
-
+           ret = silc_server_get_authentication(ctx, client->passphrase,
+                                                client->publickey,
+                                                auth_data, payload_len);
+           if (!ret) {
              /* Authentication failed */
              SILC_LOG_ERROR(("Authentication failed"));
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
-             return;
-             break;
-             
-           case SILC_AUTH_PUBLIC_KEY:
-             /* Public key authentication */
-             SILC_LOG_DEBUG(("Public key authentication"));
-             ret = silc_server_public_key_authentication(server, 
-                                                         client->auth_data,
-                                                         auth_data,
-                                                         payload_len, 
-                                                         ctx->ske);
-
-             if (ret)
-               break;
-
-             SILC_LOG_ERROR(("Authentication failed"));
-             SILC_LOG_DEBUG(("Authentication failed"));
-             silc_free(auth_data);
-             protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
+             silc_protocol_execute(protocol, server->schedule, 0, 300000);
              return;
            }
          } else {
@@ -968,52 +982,19 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        
        /* Remote end is server */
        if (conn_type == SILC_SOCKET_TYPE_SERVER) {
-         SilcServerConfigSectionServer *serv = ctx->sconfig;
+         SilcServerConfigServer *serv = ctx->sconfig;
          
          if (serv) {
-           switch(serv->auth_meth) {
-           case SILC_AUTH_NONE:
-             /* No authentication required */
-             SILC_LOG_DEBUG(("No authentication required"));
-             break;
-             
-           case SILC_AUTH_PASSWORD:
-             /* Password authentication */
-             SILC_LOG_DEBUG(("Password authentication"));
-             ret = silc_server_password_authentication(server, auth_data,
-                                                       serv->auth_data);
-
-             if (ret)
-               break;
-             
+           ret = silc_server_get_authentication(ctx, serv->passphrase,
+                                                serv->publickey,
+                                                auth_data, payload_len);
+           if (!ret) {
              /* Authentication failed */
              SILC_LOG_ERROR(("Authentication failed"));
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
-             return;
-             break;
-
-           case SILC_AUTH_PUBLIC_KEY:
-             /* Public key authentication */
-             SILC_LOG_DEBUG(("Public key authentication"));
-             ret = silc_server_public_key_authentication(server, 
-                                                         serv->auth_data,
-                                                         auth_data,
-                                                         payload_len, 
-                                                         ctx->ske);
-                                                         
-             if (ret)
-               break;
-
-             SILC_LOG_ERROR(("Authentication failed"));
-             SILC_LOG_DEBUG(("Authentication failed"));
-             silc_free(auth_data);
-             protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
+             silc_protocol_execute(protocol, server->schedule, 0, 300000);
              return;
            }
          } else {
@@ -1030,52 +1011,19 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        
        /* Remote end is router */
        if (conn_type == SILC_SOCKET_TYPE_ROUTER) {
-         SilcServerConfigSectionRouter *serv = ctx->rconfig;
+         SilcServerConfigRouter *serv = ctx->rconfig;
 
          if (serv) {
-           switch(serv->auth_meth) {
-           case SILC_AUTH_NONE:
-             /* No authentication required */
-             SILC_LOG_DEBUG(("No authentication required"));
-             break;
-             
-           case SILC_AUTH_PASSWORD:
-             /* Password authentication */
-             SILC_LOG_DEBUG(("Password authentication"));
-             ret = silc_server_password_authentication(server, auth_data,
-                                                       serv->auth_data);
-
-             if (ret)
-               break;
-             
+           ret = silc_server_get_authentication(ctx, serv->passphrase,
+                                                serv->publickey,
+                                                auth_data, payload_len);
+           if (!ret) {
              /* Authentication failed */
              SILC_LOG_ERROR(("Authentication failed"));
              SILC_LOG_DEBUG(("Authentication failed"));
              silc_free(auth_data);
              protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
-             return;
-             break;
-             
-           case SILC_AUTH_PUBLIC_KEY:
-             /* Public key authentication */
-             SILC_LOG_DEBUG(("Public key authentication"));
-             ret = silc_server_public_key_authentication(server, 
-                                                         serv->auth_data,
-                                                         auth_data,
-                                                         payload_len, 
-                                                         ctx->ske);
-                                                         
-             if (ret)
-               break;
-             
-             SILC_LOG_ERROR(("Authentication failed"));
-             SILC_LOG_DEBUG(("Authentication failed"));
-             silc_free(auth_data);
-             protocol->state = SILC_PROTOCOL_STATE_ERROR;
-             silc_protocol_execute(protocol, server->schedule, 
-                                   0, 300000);
+             silc_protocol_execute(protocol, server->schedule, 0, 300000);
              return;
            }
          } else {
@@ -1127,13 +1075,9 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
          
        case SILC_AUTH_PUBLIC_KEY:
          {
-           unsigned char sign[1024];
-
            /* Public key authentication */
-           silc_server_get_public_key_auth(server, sign, &auth_data_len,
+           silc_server_get_public_key_auth(server, &auth_data, &auth_data_len,
                                            ctx->ske);
-           auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
-           memcpy(auth_data, sign, auth_data_len);
            break;
          }
        }