/*
* Server side of the protocols.
*/
-/*
- * $Id$
- * $Log$
- * Revision 1.2 2000/07/05 06:13:04 priikone
- * Support for SILC style public keys added.
- *
- * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
- * Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
#include "serverincludes.h"
#include "server_internal.h"
SILC_TASK_CALLBACK(silc_server_protocol_connection_auth);
-SILC_TASK_CALLBACK(silc_server_protocol_channel_auth);
SILC_TASK_CALLBACK(silc_server_protocol_key_exchange);
-/* SILC client protocol list */
-const SilcProtocolObject silc_protocol_list[] =
-{
- { SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
- silc_server_protocol_connection_auth },
- { SILC_PROTOCOL_SERVER_CHANNEL_AUTH,
- silc_server_protocol_channel_auth },
- { SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
- silc_server_protocol_key_exchange },
-
- { SILC_PROTOCOL_SERVER_NONE, NULL },
-};
+extern char *silc_version_string;
/*
* Key Exhange protocol functions
SilcHash hash,
int is_responder)
{
- SilcIDListUnknown *conn_data;
+ SilcUnknownEntry conn_data;
SilcHash nhash;
SILC_LOG_DEBUG(("Setting new key into use"));
If yes, we need to change KE protocol to get the initiators
public key. */
silc_pkcs_alloc(pkcs->pkcs->name, &conn_data->pkcs);
+ conn_data->public_key = silc_pkcs_public_key_alloc(XXX);
silc_pkcs_set_public_key(conn_data->pkcs, 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, &conn_data->hmac);
- conn_data->hmac_key_len = keymat->hmac_key_len;
- conn_data->hmac_key = silc_calloc(conn_data->hmac_key_len,
- sizeof(unsigned char));
- memcpy(conn_data->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
+ silc_hmac_set_key(conn_data->hmac, keymat->hmac_key, keymat->hmac_key_len);
sock->user_data = (void *)conn_data;
}
+/* XXX TODO */
+
+SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
+ unsigned int len)
+{
+ return SILC_SKE_STATUS_OK;
+}
+
/* Performs key exchange protocol. This is used for both initiator
and responder key exchange. This is performed always when accepting
new connection to the server. This may be called recursively. */
/* Allocate Key Exchange object */
ske = silc_ske_alloc();
ctx->ske = ske;
+ ske->rng = server->rng;
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,
+ silc_version_string,
ctx->packet, NULL, NULL);
} else {
SilcSKEStartPayload *start_payload;
/* Assemble security properties. */
- silc_ske_assemble_security_properties(ske, &start_payload);
+ silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_NONE,
+ silc_version_string,
+ &start_payload);
/* Start the key exchange by sending our security properties
to the remote end. */
Key Exhange 1 Payload to the responder. */
status =
silc_ske_initiator_phase_2(ctx->ske,
+ server->public_key,
silc_server_protocol_ke_send_packet,
context);
}
* Finish protocol
*/
if (ctx->responder == TRUE) {
- unsigned char *pk, *prv;
- unsigned int pk_len, prv_len;
-
- /* Get our public key to be sent to the initiator */
- pk = silc_pkcs_get_public_key(server->public_key, &pk_len);
-
- /* Get out private key to sign some data. */
- prv = silc_pkcs_get_private_key(server->public_key, &prv_len);
-
/* This creates the key exchange material and sends our
public parts to the initiator inside Key Exchange 2 Payload. */
status =
silc_ske_responder_finish(ctx->ske,
- pk, pk_len, prv, prv_len,
+ server->public_key, server->private_key,
SILC_SKE_PK_TYPE_SILC,
silc_server_protocol_ke_send_packet,
context);
-
- memset(pk, 0, pk_len);
- memset(prv, 0, prv_len);
- silc_free(pk);
- silc_free(prv);
} else {
/* Finish the protocol. This verifies the Key Exchange 2 payload
sent by responder. */
status =
silc_ske_initiator_finish(ctx->ske,
- ctx->packet, NULL, NULL);
+ ctx->packet, NULL, NULL, NULL, NULL);
}
if (status != SILC_SKE_STATUS_OK) {
protocol->state = SILC_PROTOCOL_STATE_END;
}
break;
+
case SILC_PROTOCOL_STATE_END:
{
/*
silc_protocol_free(protocol);
}
break;
+
case SILC_PROTOCOL_STATE_ERROR:
/*
* Error occured
*/
+ /* Send abort notification */
+ silc_ske_abort(ctx->ske, ctx->ske->status,
+ silc_server_protocol_ke_send_packet,
+ context);
+
/* Unregister the timeout task since the protocol has ended.
This was the timeout task to be executed if the protocol is
not completed fast enough. */
else
silc_protocol_free(protocol);
break;
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /*
+ * We have received failure from remote
+ */
+
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ break;
+
case SILC_PROTOCOL_STATE_UNKNOWN:
break;
}
* Connection Authentication protocol functions
*/
+/* XXX move these to somehwere else */
+
+int silc_server_password_authentication(SilcServer server, char *auth1,
+ char *auth2)
+{
+ if (!auth1 || !auth2)
+ return FALSE;
+
+ if (!memcmp(auth1, auth2, strlen(auth1)))
+ return TRUE;
+
+ return FALSE;
+}
+
+int silc_server_public_key_authentication(SilcServer server,
+ char *pkfile,
+ unsigned char *sign,
+ unsigned int sign_len,
+ SilcSKE ske)
+{
+ SilcPublicKey pub_key;
+ SilcPKCS pkcs;
+ int len;
+ SilcBuffer auth;
+
+ if (!pkfile || !sign)
+ return FALSE;
+
+ /* Load public key from file */
+ if (!silc_pkcs_load_public_key(pkfile, &pub_key, SILC_PKCS_FILE_PEM))
+ if (!silc_pkcs_load_public_key(pkfile, &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);
+ 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);
+
+ /* Verify signature */
+ if (pkcs->pkcs->verify(pkcs->context, sign, sign_len,
+ auth->data, auth->len))
+ {
+ silc_pkcs_free(pkcs);
+ silc_pkcs_public_key_free(pub_key);
+ silc_buffer_free(auth);
+ return TRUE;
+ }
+
+ silc_pkcs_free(pkcs);
+ silc_pkcs_public_key_free(pub_key);
+ silc_buffer_free(auth);
+ return FALSE;
+}
+
/* Performs connection authentication protocol. If responder, we
authenticate the remote data received. If initiator, we will send
authentication data to the remote end. */
/*
* We are receiving party
*/
+ int ret;
unsigned short payload_len;
unsigned short conn_type;
unsigned char *auth_data;
+ SILC_LOG_INFO(("Performing authentication protocol for %s",
+ ctx->sock->hostname ? ctx->sock->hostname :
+ ctx->sock->ip));
+
/* Parse the received authentication data packet. The received
payload is Connection Auth Payload. */
silc_buffer_unformat(ctx->packet,
case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
/* Password authentication */
SILC_LOG_DEBUG(("Password authentication"));
- if (auth_data) {
- if (!memcmp(client->auth_data, auth_data, strlen(auth_data))) {
- memset(auth_data, 0, payload_len);
- silc_free(auth_data);
- auth_data = NULL;
- break;
- }
+ ret = silc_server_password_authentication(server, auth_data,
+ client->auth_data);
+
+ if (ret) {
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ break;
}
/* Authentication failed */
case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
/* Public key authentication */
SILC_LOG_DEBUG(("Public key authentication"));
- if (auth_data) {
- SilcIDListUnknown *conn_data;
- SilcPublicKey pub_key;
- SilcPKCS pkcs;
-
- conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
-
- /* Load public key from file */
- if (silc_pkcs_load_public_key(client->auth_data,
- &pub_key) == FALSE) {
-
- /* Authentication failed */
- SILC_LOG_ERROR(("Authentication failed "
- "- could not read public key file"));
- memset(auth_data, 0, payload_len);
- silc_free(auth_data);
- auth_data = NULL;
- protocol->state = SILC_PROTOCOL_STATE_ERROR;
- protocol->execute(server->timeout_queue, 0,
- protocol, fd, 0, 300000);
- return;
- }
-
- silc_pkcs_alloc(pub_key->name, &pkcs);
-
- /* Verify hash value HASH from KE protocol */
- if (pkcs->pkcs->verify(pkcs->context,
- auth_data, payload_len,
- ctx->ske->hash,
- ctx->ske->hash_len)
- == TRUE) {
- silc_pkcs_free(pkcs);
- silc_pkcs_public_key_free(pub_key);
- break;
- }
+ ret = silc_server_public_key_authentication(server,
+ client->auth_data,
+ auth_data,
+ payload_len,
+ ctx->ske);
+
+ if (ret) {
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ break;
}
SILC_LOG_ERROR(("Authentication failed"));
case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
/* Password authentication */
SILC_LOG_DEBUG(("Password authentication"));
- if (auth_data) {
- if (!memcmp(serv->auth_data, auth_data, strlen(auth_data))) {
- memset(auth_data, 0, payload_len);
- silc_free(auth_data);
- auth_data = NULL;
- break;
- }
+ ret = silc_server_password_authentication(server, auth_data,
+ serv->auth_data);
+
+ if (ret) {
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ break;
}
/* Authentication failed */
case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
/* Public key authentication */
SILC_LOG_DEBUG(("Public key authentication"));
- if (auth_data) {
- SilcIDListUnknown *conn_data;
- SilcPublicKey pub_key;
- SilcPKCS pkcs;
-
- conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
-
- /* Load public key from file */
- if (silc_pkcs_load_public_key(serv->auth_data,
- &pub_key) == FALSE) {
-
- /* Authentication failed */
- SILC_LOG_ERROR(("Authentication failed "
- "- could not read public key file"));
- memset(auth_data, 0, payload_len);
- silc_free(auth_data);
- auth_data = NULL;
- protocol->state = SILC_PROTOCOL_STATE_ERROR;
- protocol->execute(server->timeout_queue, 0,
- protocol, fd, 0, 300000);
- return;
- }
-
- silc_pkcs_alloc(pub_key->name, &pkcs);
-
- /* Verify hash value HASH from KE protocol */
- if (pkcs->pkcs->verify(pkcs->context,
- auth_data, payload_len,
- ctx->ske->hash,
- ctx->ske->hash_len)
- == TRUE) {
- silc_pkcs_free(pkcs);
- silc_pkcs_public_key_free(pub_key);
- break;
- }
+ ret = silc_server_public_key_authentication(server,
+ serv->auth_data,
+ auth_data,
+ payload_len,
+ ctx->ske);
+
+ if (ret) {
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ break;
}
SILC_LOG_ERROR(("Authentication failed"));
case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
/* Password authentication */
SILC_LOG_DEBUG(("Password authentication"));
- if (auth_data) {
- if (!memcmp(serv->auth_data, auth_data, strlen(auth_data))) {
- memset(auth_data, 0, payload_len);
- silc_free(auth_data);
- auth_data = NULL;
- break;
- }
+ ret = silc_server_password_authentication(server, auth_data,
+ serv->auth_data);
+
+ if (ret) {
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ break;
}
/* Authentication failed */
case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
/* Public key authentication */
SILC_LOG_DEBUG(("Public key authentication"));
- if (auth_data) {
- SilcIDListUnknown *conn_data;
- SilcPublicKey pub_key;
- SilcPKCS pkcs;
-
- conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
-
- /* Load public key from file */
- if (silc_pkcs_load_public_key(serv->auth_data,
- &pub_key) == FALSE) {
-
- /* Authentication failed */
- SILC_LOG_ERROR(("Authentication failed "
- "- could not read public key file"));
- memset(auth_data, 0, payload_len);
- silc_free(auth_data);
- auth_data = NULL;
- protocol->state = SILC_PROTOCOL_STATE_ERROR;
- protocol->execute(server->timeout_queue, 0,
- protocol, fd, 0, 300000);
- return;
- }
-
- silc_pkcs_alloc(pub_key->name, &pkcs);
-
- /* Verify hash value HASH from KE protocol */
- if (pkcs->pkcs->verify(pkcs->context,
- auth_data, payload_len,
- ctx->ske->hash,
- ctx->ske->hash_len)
- == TRUE) {
- silc_pkcs_public_key_free(pub_key);
- silc_pkcs_free(pkcs);
- break;
- }
+ ret = silc_server_public_key_authentication(server,
+ serv->auth_data,
+ auth_data,
+ payload_len,
+ ctx->ske);
+
+ if (ret) {
+ memset(auth_data, 0, payload_len);
+ silc_free(auth_data);
+ auth_data = NULL;
+ break;
}
SILC_LOG_ERROR(("Authentication failed"));
/*
* End protocol
*/
+ unsigned char ok[4];
- /* Succesfully authenticated */
- silc_server_packet_send(server, ctx->sock, SILC_PACKET_SUCCESS,
- 0, NULL, 0, TRUE);
+ SILC_PUT32_MSB(SILC_CONN_AUTH_OK, ok);
+
+ /* Authentication failed */
+ silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
+ 0, ok, 4, TRUE);
/* Unregister the timeout task since the protocol has ended.
This was the timeout task to be executed if the protocol is
case SILC_PROTOCOL_STATE_ERROR:
{
/*
- * Error
+ * Error. Send notify to remote.
*/
+ unsigned char error[4];
+
+ SILC_PUT32_MSB(SILC_CONN_AUTH_FAILED, error);
/* Authentication failed */
silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
- 0, NULL, 0, TRUE);
+ 0, error, 4, TRUE);
/* Unregister the timeout task since the protocol has ended.
This was the timeout task to be executed if the protocol is
silc_protocol_free(protocol);
}
break;
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /*
+ * We have received failure from remote
+ */
+
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ break;
+
case SILC_PROTOCOL_STATE_UNKNOWN:
break;
}
}
-SILC_TASK_CALLBACK(silc_server_protocol_channel_auth)
+/* Registers protocols used in server. */
+
+void silc_server_protocols_register(void)
+{
+ silc_protocol_register(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
+ silc_server_protocol_connection_auth);
+ silc_protocol_register(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+ silc_server_protocol_key_exchange);
+}
+
+/* Unregisters protocols */
+
+void silc_server_protocols_unregister(void)
{
+ silc_protocol_unregister(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
+ silc_server_protocol_connection_auth);
+ silc_protocol_unregister(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+ silc_server_protocol_key_exchange);
}