/************************** Types and definitions ***************************/
-/* Key agreement context */
+/* Key agreement context, used by responder */
struct SilcClientKeyAgreementStruct {
SilcClient client; /* Client */
SilcClientConnection conn; /* Server connection */
SilcKeyAgreementCallback completion; /* Key agreement completion */
void *context; /* User context */
-
- /* Responder */
- SilcNetListener listener; /* TCP listener */
- SilcStream stream; /* Remote connection (TCP or UDP) */
-
- /* Initiator */
- SilcClientConnection client_conn; /* Connection to remote client */
+ SilcClientConnectionParams params; /* Connection parameters */
+ SilcPublicKey public_key; /* Responder public key */
+ SilcPrivateKey private_key; /* Responder private key */
+ SilcNetListener tcp_listener; /* TCP listener */
+ SilcPacketStream udp_listener; /* UDP listener */
+ SilcPacketStream stream; /* Remote connection (TCP or UDP) */
+ SilcAsyncOperation op; /* SKE operation */
+ SilcSKE ske; /* SKE */
};
/************************ Static utility functions **************************/
-/* TCP network listener callback. Accepts new key agreement connection */
+/* Destroyes key agreement session */
-static void silc_client_tcp_accept(SilcNetStatus status,
- SilcStream stream,
- void *context)
+static void silc_client_keyagr_free(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
{
- SilcClientEntry client_entry = context;
- SilcClientKeyAgreement ke = client_entry->ke;
+ SilcClientKeyAgreement ke = client_entry->internal.ke;
+
+ silc_schedule_task_del_by_context(conn->internal->schedule, client_entry);
+
+ if (ke->op)
+ silc_async_abort(ke->op, NULL, NULL);
+ if (ke->ske)
+ silc_ske_free(ke->ske);
+ if (ke->tcp_listener)
+ silc_net_close_listener(ke->tcp_listener);
+ silc_packet_stream_destroy(ke->stream);
+ silc_packet_stream_destroy(ke->udp_listener);
- ke->stream = stream;
- silc_client_process_key_agreement(ke->client, ke->conn, ke);
+ client_entry->internal.ke = NULL;
+ client_entry->internal.prv_resp = FALSE;
+ silc_client_unref_client(client, conn, client_entry);
+
+ silc_free(ke);
}
-/* UDP network callback. All UDP packets are read from here. */
+/* Key agreement timeout callback */
-static void silc_client_udp_accept(SilcStream stream,
- SilcStreamStatus status,
- void *context)
+SILC_TASK_CALLBACK(silc_client_keyagr_timeout)
{
+ SilcClientEntry client_entry = context;
+ SilcClientKeyAgreement ke = client_entry->internal.ke;
-}
+ SILC_LOG_DEBUG(("Key agreement %p timeout", ke));
+ ke->completion(ke->client, ke->conn, client_entry,
+ SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
+
+ silc_client_keyagr_free(ke->client, ke->conn, client_entry);
+}
-/* Packet sending function used by the SKE in the key agreement process. */
+/* Client resolving callback. Continues with the key agreement processing */
-static void silc_client_key_agreement_send_packet(SilcSKE ske,
- SilcBuffer packet,
- SilcPacketType type,
- void *context)
+static void silc_client_keyagr_resolved(SilcClient client,
+ SilcClientConnection conn,
+ SilcStatus status,
+ SilcDList clients,
+ void *context)
{
- SilcProtocol protocol = (SilcProtocol)context;
- SilcClientKEInternalContext *ctx =
- (SilcClientKEInternalContext *)protocol->context;
- void *tmp;
-
- /* Send the packet immediately. We will assure that the packet is not
- encrypted by setting the socket's user_data pointer to NULL. The
- silc_client_packet_send would take the keys (wrong keys that is,
- because user_data is the current SilcClientConnection) from it and
- we cannot allow that. The packets are never encrypted when doing SKE
- with another client. */
- tmp = ske->sock->user_data;
- ske->sock->user_data = NULL;
- silc_client_packet_send(ctx->client, ske->sock, type, NULL, 0, NULL, NULL,
- packet->data, packet->len, TRUE);
- ske->sock->user_data = tmp;
+ /* If no client found, ignore the packet, a silent error */
+ if (!clients)
+ silc_fsm_next(context, silc_client_key_agreement_error);
+
+ /* Continue processing the packet */
+ SILC_FSM_CALL_CONTINUE(context);
}
-/* Timeout callback that is called to close the connection and free the
- socket connection data. */
+/* Called after application has verified remote host's public key. Responder
+ function. */
-SILC_TASK_CALLBACK(silc_client_key_agreement_close)
+static void silc_client_keyagr_verify_key_cb(SilcBool success, void *context)
{
- SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
+ VerifyKeyContext verify = context;
- silc_schedule_unset_listen_fd(ke->client->schedule, ke->sock->sock);
- silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
- silc_net_close_connection(ke->sock->sock);
- silc_net_close_connection(ke->fd);
- silc_socket_free(ke->sock);
- silc_free(ke);
+ /* Call the completion callback back to the SKE */
+ verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK :
+ SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
+ verify->completion_context);
+
+ silc_free(verify);
}
-/* This callback is called after the key agreement protocol has been
- performed. This calls the final completion callback for the application. */
+/* Verify remote host's public key. Responder function. */
-SILC_TASK_CALLBACK(silc_client_key_agreement_final)
+static void silc_client_keyagr_verify_key(SilcSKE ske,
+ SilcPublicKey public_key,
+ void *context,
+ SilcSKEVerifyCbCompletion completion,
+ void *completion_context)
{
- SilcProtocol protocol = (SilcProtocol)context;
- SilcClientKEInternalContext *ctx =
- (SilcClientKEInternalContext *)protocol->context;
- SilcClient client = (SilcClient)ctx->client;
- SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
- protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
- /* Error occured during protocol */
- ke->client_entry->ke = NULL;
- ke->completion(ke->client, ke->conn, ke->client_entry,
- SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
- silc_ske_free_key_material(ctx->keymat);
- goto out;
+ SilcClientEntry client_entry = context;
+ SilcClientKeyAgreement ke = client_entry->internal.ke;
+ SilcClientConnection conn = ke->conn;
+ SilcClient client = conn->client;
+ VerifyKeyContext verify;
+
+ /* If we provided repository for SKE and we got here the key was not
+ found from the repository. */
+ if (ke->params.repository && !ke->params.verify_notfound) {
+ completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
+ completion_context);
+ return;
}
- /* Pass the negotiated key material to the application. The application
- is responsible of freeing the key material. */
- ke->client_entry->ke = NULL;
- ke->completion(ke->client, ke->conn, ke->client_entry,
- SILC_KEY_AGREEMENT_OK, ctx->keymat, ke->context);
-
- out:
- silc_protocol_free(protocol);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
- silc_schedule_task_del_by_fd(client->schedule, ke->fd);
- silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
- silc_net_close_connection(ke->fd);
- if (ke->timeout)
- silc_schedule_task_del(client->schedule, ke->timeout);
- silc_client_del_socket(ke->client, ke->sock);
-
- silc_schedule_task_add(client->schedule, 0,
- silc_client_key_agreement_close,
- (void *)ke, 0, 1,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
-
- silc_free(ctx);
+ SILC_LOG_DEBUG(("Verify remote public key"));
+
+ verify = silc_calloc(1, sizeof(*verify));
+ if (!verify) {
+ completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
+ completion_context);
+ return;
+ }
+ verify->ske = ske;
+ verify->completion = completion;
+ verify->completion_context = completion_context;
+
+ /* Verify public key in application */
+ client->internal->ops->verify_public_key(client, conn,
+ SILC_CONN_CLIENT, public_key,
+ silc_client_keyagr_verify_key_cb,
+ verify);
}
-/* Key agreement callback that is called when remote end has initiated
- the key agreement protocol. This accepts the incoming TCP/IP connection
- for the key agreement protocol. */
+/* Key exchange protocol completion callback. Responder function. */
-SILC_TASK_CALLBACK(silc_client_process_key_agreement)
+static void silc_client_keyagr_completion(SilcSKE ske,
+ SilcSKEStatus status,
+ SilcSKESecurityProperties prop,
+ SilcSKEKeyMaterial keymat,
+ SilcSKERekeyMaterial rekey,
+ void *context)
{
- SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
- SilcClient client = ke->client;
+ SilcClientEntry client_entry = context;
+ SilcClientKeyAgreement ke = client_entry->internal.ke;
SilcClientConnection conn = ke->conn;
- SilcSocketConnection newsocket;
- SilcClientKEInternalContext *proto_ctx;
- int sock;
-
- SILC_LOG_DEBUG(("Start"));
-
- sock = silc_net_accept_connection(ke->fd);
- if (sock < 0) {
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Could not accept key agreement connection: ",
- strerror(errno));
- ke->client_entry->ke = NULL;
- ke->completion(ke->client, ke->conn, ke->client_entry,
- SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
- silc_schedule_task_del_by_fd(client->schedule, ke->fd);
- silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
- silc_net_close_connection(ke->fd);
- if (ke->timeout)
- silc_schedule_task_del(client->schedule, ke->timeout);
- silc_free(ke);
+ SilcClient client = conn->client;
+
+ if (status != SILC_SKE_STATUS_OK) {
+ /* Key exchange failed */
+ ke->completion(client, conn, client_entry,
+ status == SILC_SKE_STATUS_TIMEOUT ?
+ SILC_KEY_AGREEMENT_TIMEOUT :
+ SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
+ silc_client_keyagr_free(client, conn, client_entry);
+ return;
+ }
+
+ /* Returns the negotiated key material to application. Key agreement
+ was successful. */
+ ke->completion(client, conn, client_entry, SILC_KEY_AGREEMENT_OK,
+ keymat, ke->context);
+
+ silc_client_keyagr_free(client, conn, client_entry);
+}
+
+/* Starts key agreement as responder. */
+
+static void silc_client_process_key_agreement(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ SilcClientKeyAgreement ke = client_entry->internal.ke;
+ SilcSKEParamsStruct params;
+
+ SILC_LOG_DEBUG(("Processing key agrement %p session", ke));
+
+ /* Allocate SKE */
+ ke->ske = silc_ske_alloc(client->rng, conn->internal->schedule,
+ ke->params.repository, ke->public_key,
+ ke->private_key, client_entry);
+ if (!ke->ske) {
+ ke->completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
+ NULL, ke->context);
+ silc_client_keyagr_free(client, conn, client_entry);
return;
}
- /* Set socket options */
- silc_net_set_socket_nonblock(sock);
- silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-
- /* Create socket for this connection (it is of type UNKNOWN since this
- really is not a real SILC connection. It is only for the key
- agreement protocol). */
- silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &newsocket);
- ke->sock = newsocket;
-
- /* Perform name and address lookups for the remote host. */
- silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
- if (!newsocket->hostname && !newsocket->ip) {
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Could not resolve the remote IP or hostname");
- ke->client_entry->ke = NULL;
- ke->completion(ke->client, ke->conn, ke->client_entry,
- SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
- silc_schedule_task_del_by_fd(client->schedule, ke->fd);
- silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
- silc_net_close_connection(ke->fd);
- if (ke->timeout)
- silc_schedule_task_del(client->schedule, ke->timeout);
- silc_free(ke);
+ /* Set SKE parameters */
+ params.version = client->internal->silc_client_version;
+ params.flags = SILC_SKE_SP_FLAG_MUTUAL;
+ if (ke->params.udp) {
+ params.flags |= SILC_SKE_SP_FLAG_IV_INCLUDED;
+ params.session_port = ke->params.local_port;
+ }
+
+ silc_ske_set_callbacks(ke->ske, silc_client_keyagr_verify_key,
+ silc_client_keyagr_completion, client_entry);
+
+ /* Start key exchange as responder */
+ ke->op = silc_ske_responder(ke->ske, ke->stream, ¶ms);
+ if (!ke->op) {
+ ke->completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
+ NULL, ke->context);
+ silc_client_keyagr_free(client, conn, client_entry);
+ }
+}
+
+/* TCP network listener callback. Accepts new key agreement connection.
+ Responder function. */
+
+static void silc_client_tcp_accept(SilcNetStatus status,
+ SilcStream stream,
+ void *context)
+{
+ SilcClientEntry client_entry = context;
+ SilcClientKeyAgreement ke = client_entry->internal.ke;
+
+ /* Create packet stream */
+ ke->stream = silc_packet_stream_create(ke->client->internal->packet_engine,
+ ke->conn->internal->schedule, stream);
+ if (!ke->stream) {
+ silc_stream_destroy(stream);
return;
}
- if (!newsocket->hostname)
- newsocket->hostname = strdup(newsocket->ip);
- newsocket->port = silc_net_get_remote_port(sock);
- silc_client_add_socket(client, newsocket);
-
- /* Allocate internal context for key exchange protocol. This is
- sent as context for the protocol. */
- proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
- proto_ctx->client = client;
- proto_ctx->sock = silc_socket_dup(newsocket);
- proto_ctx->rng = client->rng;
- proto_ctx->responder = TRUE;
- proto_ctx->context = context;
- proto_ctx->send_packet = silc_client_key_agreement_send_packet;
- proto_ctx->verify = silc_client_protocol_ke_verify_key;
- ke->proto_ctx = proto_ctx;
-
- /* Prepare the connection for key exchange protocol. We allocate the
- protocol but will not start it yet. The connector will be the
- initiator of the protocol thus we will wait for initiation from
- there before we start the protocol. */
- silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
- &newsocket->protocol, proto_ctx,
- silc_client_key_agreement_final);
-
- /* Register the connection for network input and output. This sets
- that scheduler will listen for incoming packets for this connection
- and sets that outgoing packets may be sent to this connection as well.
- However, this doesn't set the scheduler for outgoing traffic, it
- will be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
- later when outgoing data is available. */
- context = (void *)client;
- SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
+
+ /* Process session */
+ silc_client_process_key_agreement(ke->client, ke->conn, client_entry);
}
-/* Timeout occured during key agreement. This means that the key agreement
- protocol was not completed in the specified timeout. We will call the
- completion callback. */
+/* UDP network listener callback. Accepts new key agreement session.
+ Responder function. */
-SILC_TASK_CALLBACK(silc_client_key_agreement_timeout)
+static SilcBool silc_client_udp_accept(SilcPacketEngine engine,
+ SilcPacketStream stream,
+ SilcPacket packet,
+ void *callback_context,
+ void *stream_context)
{
- SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
+ SilcClientEntry client_entry = callback_context;
+ SilcClientKeyAgreement ke = client_entry->internal.ke;
+ SilcUInt16 port;
+ const char *ip;
+
+ /* We want only key exchange packet. Eat other packets so that default
+ packet callback doesn't get them. */
+ if (packet->type != SILC_PACKET_KEY_EXCHANGE) {
+ silc_packet_free(packet);
+ return TRUE;
+ }
- ke->client_entry->ke = NULL;
- ke->completion(ke->client, ke->conn, ke->client_entry,
- SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
+ /* Create packet stream for this remote UDP session */
+ if (!silc_packet_get_sender(packet, &ip, &port)) {
+ silc_packet_free(packet);
+ return TRUE;
+ }
+ ke->stream = silc_packet_stream_add_remote(stream, ip, port, packet);
+ if (!ke->stream) {
+ silc_packet_free(packet);
+ return TRUE;
+ }
+
+ /* Process session */
+ silc_client_process_key_agreement(ke->client, ke->conn, client_entry);
+ return TRUE;
+}
- if (ke->sock) {
- silc_client_del_socket(ke->client, ke->sock);
- silc_socket_free(ke->sock);
+/* Client connect completion callback. Initiator function. */
+
+static void silc_client_keyagr_perform_cb(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientConnectionStatus status,
+ SilcStatus error,
+ const char *message,
+ void *context)
+{
+ SilcClientEntry client_entry = context;
+ SilcClientKeyAgreement ke = client_entry->internal.ke;
+ SilcSKEKeyMaterial keymat;
+
+ ke->op = NULL;
+
+ switch (status) {
+ case SILC_CLIENT_CONN_SUCCESS:
+ SILC_LOG_DEBUG(("Key agreement %p successful", ke));
+
+ keymat = silc_ske_get_key_material(conn->internal->ske);
+ ke->completion(ke->client, ke->conn, client_entry, SILC_KEY_AGREEMENT_OK,
+ keymat, ke->context);
+ break;
+
+ case SILC_CLIENT_CONN_ERROR_TIMEOUT:
+ SILC_LOG_DEBUG(("Key agreement %p timeout", ke));
+ ke->completion(ke->client, ke->conn, client_entry,
+ SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
+ break;
+
+ default:
+ SILC_LOG_DEBUG(("Key agreement %p error %d", ke, status));
+ ke->completion(ke->client, ke->conn, client_entry,
+ SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
+ break;
}
- if (ke->proto_ctx && ke->proto_ctx->ske)
- silc_ske_free(ke->proto_ctx->ske);
- ke->client_entry->ke = NULL;
- if (ke->fd)
- silc_schedule_task_del_by_fd(ke->client->schedule, ke->fd);
- silc_schedule_unset_listen_fd(ke->client->schedule, ke->fd);
- silc_net_close_connection(ke->fd);
- silc_free(ke);
+
+ /* Close the created connection */
+ if (conn)
+ silc_client_close_connection(ke->client, conn);
+
+ silc_client_keyagr_free(ke->client, ke->conn, client_entry);
}
+/* Packet stream callbacks */
+static SilcPacketCallbacks silc_client_keyagr_stream_cb =
+{
+ silc_client_udp_accept, NULL, NULL
+};
+
/*************************** Key Agreement API ******************************/
/* Sends key agreement packet to remote client. If IP addresses are provided
void silc_client_send_key_agreement(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry,
- const char *local_ip,
- const char *bind_ip,
- int port,
- SilcUInt32 timeout_secs,
- SilcBool udp,
+ SilcClientConnectionParams *params,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
SilcKeyAgreementCallback completion,
void *context)
{
SilcClientKeyAgreement ke = NULL;
- SilcAsyncOperation op;
SilcBuffer buffer;
- SilcUInt16 ports = NULL;
+ SilcUInt16 port = 0, protocol = 0;
+ char *local_ip = NULL;
+ SilcStream stream;
+
+ SILC_LOG_DEBUG(("Sending key agreement"));
if (!client_entry)
return;
- if (client_entry->internal->ke) {
+ if (client_entry->internal.ke) {
completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ALREADY_STARTED,
NULL, context);
return;
}
/* If local IP is provided, create listener */
- if (local_ip || bind_ip) {
+ if (params && (params->local_ip || params->bind_ip)) {
ke = silc_calloc(1, sizeof(*ke));
if (!ke) {
completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
}
/* Create network listener */
- if (udp) {
+ if (params->udp) {
/* UDP listener */
- ke->stream =
- silc_net_udp_connect(bind_ip ? bind_ip : local_ip, port, NULL, 0,
- client_entry);
- if (!ke->stream) {
+ stream = silc_net_udp_connect(params->bind_ip ? params->bind_ip :
+ params->local_ip, params->local_port,
+ NULL, 0, conn->internal->schedule);
+ ke->udp_listener =
+ silc_packet_stream_create(client->internal->packet_engine,
+ conn->internal->schedule, stream);
+ if (!ke->udp_listener) {
client->internal->ops->say(
client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Cannot create UDP listener on %s on port %d: %s",
- bind_ip ? bind_ip : local_ip, port, strerror(errno));
+ params->bind_ip ? params->bind_ip :
+ params->local_ip, params->local_port, strerror(errno));
completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
NULL, context);
+ if (stream)
+ silc_stream_destroy(stream);
silc_free(ke);
return;
}
- silc_stream_set_notifier(ke->stream, conn->schedule,
- silc_client_udp_accept, client_entry);
+ silc_packet_stream_link(ke->udp_listener,
+ &silc_client_keyagr_stream_cb,
+ client_entry, 1000000,
+ SILC_PACKET_ANY, -1);
+
+ port = params->local_port;
+ if (!port) {
+ /* Get listener port */
+ int sock;
+ silc_socket_stream_get_info(stream, &sock, NULL, NULL, NULL);
+ port = silc_net_get_local_port(sock);
+ }
} else {
/* TCP listener */
- ke->listener =
- silc_net_tcp_create_listener(bind_ip ? &bind_ip :
- &local_ip, 1, port, FALSE,
- FALSE, conn->internal->schedule,
+ ke->tcp_listener =
+ silc_net_tcp_create_listener(params->bind_ip ?
+ (const char **)¶ms->bind_ip :
+ (const char **)¶ms->local_ip,
+ 1, params->local_port, FALSE, FALSE,
+ conn->internal->schedule,
silc_client_tcp_accept,
client_entry);
- if (!ke->listener) {
+ if (!ke->tcp_listener) {
client->internal->ops->say(
client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Cannot create listener on %s on port %d: %s",
- bind_ip ? bind_ip : local_ip, port, strerror(errno));
+ params->bind_ip ? params->bind_ip :
+ params->local_ip, params->local_port, strerror(errno));
completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
NULL, context);
silc_free(ke);
return;
}
+
+ port = params->local_port;
+ if (!port) {
+ /* Get listener port */
+ SilcUInt16 *ports;
+ ports = silc_net_listener_get_port(ke->tcp_listener, NULL);
+ port = ports[0];
+ silc_free(ports);
+ }
}
+ local_ip = params->local_ip;
+ protocol = params->udp;
+
ke->client = client;
ke->conn = conn;
ke->completion = completion;
ke->context = context;
+ ke->params = *params;
+ ke->public_key = public_key;
+ ke->private_key = private_key;
+ silc_client_ref_client(client, conn, client_entry);
+ client_entry->internal.ke = ke;
+ client_entry->internal.prv_resp = TRUE;
}
- /* Add key agreement timeout task */
- silc_schedule_task_add_timeout(conn->internal->schedule,
- silc_client_key_agreement_timeout,
- client_entry, timeout_secs, 0);
-
/* Encode the key agreement payload */
- if (ke && ke->listener)
- ports = silc_net_listener_get_port(ke->listener, NULL);
- buffer = silc_key_agreement_payload_encode(local_ip, (port ? port :
- ports ? ports[0] : 0));
+ buffer = silc_key_agreement_payload_encode(local_ip, protocol, port);
if (!buffer) {
- if (ke) {
- if (ke->listener)
- silc_net_close_listener(ke->listener);
- silc_free(ke);
- }
completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
NULL, context);
+ silc_client_keyagr_free(client, conn, client_entry);
return;
}
- silc_free(ports);
-
- if (ke) {
- silc_client_ref_client(client, conn, client_entry);
- client_entry->internal.ke = ke;
- }
/* Send the key agreement packet to the client */
- silc_packet_send(conn->stream, SILC_PACKET_KEY_AGREEMENT, 0,
- silc_buffer_data(buffer), silc_buffer_len(data));
-
- silc_buffer_free(buffer);
-}
-
-/* Callback that is called after connection has been created. This actually
- starts the key agreement protocol. This is initiator function. */
-
-SILC_TASK_CALLBACK(silc_client_perform_key_agreement_start)
-{
- SilcClientInternalConnectContext *ctx =
- (SilcClientInternalConnectContext *)context;
- SilcClient client = ctx->client;
- SilcClientConnection conn = ctx->conn;
- SilcClientKeyAgreement ke = (SilcClientKeyAgreement)ctx->context;
- int opt, opt_len = sizeof(opt);
-
- SILC_LOG_DEBUG(("Start"));
-
- /* Check the socket status as it might be in error */
- silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
- if (opt != 0) {
- if (ctx->tries < 2) {
- /* Connection failed but lets try again */
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to client %s: %s",
- ctx->host, strerror(opt));
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Connecting to port %d of client %s resumed",
- ctx->port, ctx->host);
-
- /* Unregister old connection try */
- silc_schedule_unset_listen_fd(client->schedule, fd);
- silc_net_close_connection(fd);
- silc_schedule_task_del(client->schedule, ctx->task);
-
- /* Try again */
- silc_client_connect_to_client_internal(ctx);
- ctx->tries++;
- } else {
- /* Connection failed and we won't try anymore */
- client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to client %s: %s",
- ctx->host, strerror(opt));
- silc_schedule_unset_listen_fd(client->schedule, fd);
- silc_net_close_connection(fd);
- silc_schedule_task_del(client->schedule, ctx->task);
- silc_free(ctx->host);
- silc_free(ctx);
-
- /* Call the completion callback */
- ke->completion(ke->client, ke->conn, ke->client_entry,
- SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
- silc_free(ke);
- }
+ if (!silc_packet_send_ext(conn->stream, SILC_PACKET_KEY_AGREEMENT, 0,
+ 0, NULL, SILC_ID_CLIENT, &client_entry->id,
+ silc_buffer_datalen(buffer), NULL, NULL)) {
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
+ NULL, context);
+ silc_client_keyagr_free(client, conn, client_entry);
+ silc_buffer_free(buffer);
return;
}
- silc_schedule_unset_listen_fd(client->schedule, fd);
- silc_schedule_task_del(client->schedule, ctx->task);
-
- ke->fd = fd;
+ /* Add key agreement timeout task */
+ if (params && params->timeout_secs)
+ silc_schedule_task_add_timeout(conn->internal->schedule,
+ silc_client_keyagr_timeout,
+ client_entry, params->timeout_secs, 0);
- /* Now actually perform the key agreement protocol */
- silc_client_perform_key_agreement_fd(ke->client, ke->conn,
- ke->client_entry, ke->fd, ctx->host,
- ke->completion, ke->context);
- silc_free(ke);
- silc_free(ctx->host);
- silc_free(ctx);
+ silc_buffer_free(buffer);
}
-/* Performs the actual key agreement protocol. Application may use this
- to initiate the key agreement protocol. This can be called for example
- after the application has received the `key_agreement' client operation,
- and did not return TRUE from it.
-
- The `hostname' is the remote hostname (or IP address) and the `port'
- is the remote port. The `completion' callback with the `context' will
- be called after the key agreement protocol.
-
- NOTE: If the application returns TRUE in the `key_agreement' client
- operation the library will automatically start the key agreement. In this
- case the application must not call this function. However, application
- may choose to just ignore the `key_agreement' client operation (and
- merely just print information about it on the screen) and call this
- function when the user whishes to do so (by, for example, giving some
- specific command). Thus, the API provides both, automatic and manual
- initiation of the key agreement. Calling this function is the manual
- initiation and returning TRUE in the `key_agreement' client operation
- is the automatic initiation. */
+/* Perform key agreement protocol as initiator. Conneects to remote host. */
void silc_client_perform_key_agreement(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry,
- char *hostname,
- int port,
+ SilcClientConnectionParams *params,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
+ char *hostname, int port,
SilcKeyAgreementCallback completion,
void *context)
{
SilcClientKeyAgreement ke;
- SILC_LOG_DEBUG(("Start"));
-
- if (!client_entry)
- return;
+ SILC_LOG_DEBUG(("Performing key agreement"));
- if (!hostname || !port) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
+ if (!client_entry || !hostname || !port) {
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
NULL, context);
return;
}
}
ke = silc_calloc(1, sizeof(*ke));
+ if (!ke) {
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
+ NULL, context);
+ return;
+ }
ke->client = client;
ke->conn = conn;
- ke->client_entry = client_entry;
ke->completion = completion;
ke->context = context;
-
- /* Connect to the remote client */
- ke->fd = silc_client_connect_to_client(client, conn, port, hostname, ke);
- if (ke->fd < 0) {
- completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
+ silc_client_ref_client(client, conn, client_entry);
+ client_entry->internal.ke = ke;
+
+ if (params)
+ params->no_authentication = TRUE;
+
+ /* Connect to the remote client. Performs key exchange automatically. */
+ if (!silc_client_connect_to_client(client, params, public_key,
+ private_key, hostname, port,
+ silc_client_keyagr_perform_cb,
+ client_entry)) {
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
NULL, context);
- silc_free(ke);
+ silc_client_keyagr_free(client, conn, client_entry);
return;
}
}
-/* Same as above but application has created already the connection to
- the remote host. The `sock' is the socket to the remote connection.
- Application can use this function if it does not want the client library
- to create the connection. */
-
-void silc_client_perform_key_agreement_fd(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- int sock,
- char *hostname,
- SilcKeyAgreementCallback completion,
- void *context)
+/* Same as above but caller has created connection. */
+
+void
+silc_client_perform_key_agreement_stream(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ SilcClientConnectionParams *params,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
+ SilcStream stream,
+ SilcKeyAgreementCallback completion,
+ void *context)
{
SilcClientKeyAgreement ke;
- SilcClientKEInternalContext *proto_ctx;
- SilcProtocol protocol;
- SILC_LOG_DEBUG(("Start"));
+ SILC_LOG_DEBUG(("Performing key agreement"));
- if (!client_entry)
+ if (!client_entry || !stream) {
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
+ NULL, context);
return;
+ }
if (client_entry == conn->local_entry) {
completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
}
ke = silc_calloc(1, sizeof(*ke));
+ if (!ke) {
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
+ NULL, context);
+ return;
+ }
ke->client = client;
ke->conn = conn;
- ke->client_entry = client_entry;
- ke->fd = sock;
ke->completion = completion;
ke->context = context;
-
- /* Allocate new socket connection object */
- silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &ke->sock);
- silc_client_add_socket(client, ke->sock);
- ke->sock->hostname = strdup(hostname);
- ke->sock->port = silc_net_get_remote_port(sock);
-
- /* Allocate internal context for key exchange protocol. This is
- sent as context for the protocol. */
- proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
- proto_ctx->client = client;
- proto_ctx->sock = silc_socket_dup(ke->sock);
- proto_ctx->rng = client->rng;
- proto_ctx->responder = FALSE;
- proto_ctx->context = ke;
- proto_ctx->send_packet = silc_client_key_agreement_send_packet;
- proto_ctx->verify = silc_client_protocol_ke_verify_key;
- ke->proto_ctx = proto_ctx;
-
- /* Perform key exchange protocol. */
- silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
- &protocol, (void *)proto_ctx,
- silc_client_key_agreement_final);
- ke->sock->protocol = protocol;
-
- /* Register the connection for network input and output. This sets
- that scheduler will listen for incoming packets for this connection
- and sets that outgoing packets may be sent to this connection as well.
- However, this doesn't set the scheduler for outgoing traffic, it will
- be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
- later when outgoing data is available. */
- context = (void *)client;
- SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
-
- /* Execute the protocol */
- silc_protocol_execute(protocol, client->schedule, 0, 0);
+ silc_client_ref_client(client, conn, client_entry);
+ client_entry->internal.ke = ke;
+
+ if (params)
+ params->no_authentication = TRUE;
+
+ /* Perform key exchange protocol */
+ if (!silc_client_key_exchange(client, params, public_key,
+ private_key, stream, SILC_CONN_CLIENT,
+ silc_client_keyagr_perform_cb,
+ client_entry)) {
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
+ NULL, context);
+ silc_client_keyagr_free(client, conn, client_entry);
+ return;
+ }
}
/* This function can be called to unbind the hostname and the port for
SilcClientConnection conn,
SilcClientEntry client_entry)
{
- if (!client_entry)
+ SilcClientKeyAgreement ke;
+
+ if (!client_entry || !client_entry->internal.ke)
return;
- if (client_entry->ke) {
- SilcClientKeyAgreement ke;
+ ke = client_entry->internal.ke;
- if (client_entry->ke->sock) {
- silc_client_del_socket(client_entry->ke->client, client_entry->ke->sock);
- silc_socket_free(client_entry->ke->sock);
- }
- silc_schedule_task_del_by_fd(client->schedule, client_entry->ke->fd);
- if (client_entry->ke->timeout)
- silc_schedule_task_del(client->schedule,
- client_entry->ke->timeout);
- ke = client_entry->ke;
- client_entry->ke = NULL;
- ke->completion(client, conn, client_entry,
- SILC_KEY_AGREEMENT_ABORTED, NULL, ke->context);
- silc_free(ke);
- }
+ SILC_LOG_DEBUG(("Abort key agreement %p"));
+
+ ke->completion(client, conn, client_entry,
+ SILC_KEY_AGREEMENT_ABORTED, NULL, ke->context);
+
+ silc_client_keyagr_free(client, conn, client_entry);
}
-/* Callback function that is called after we've resolved the client
- information who sent us the key agreement packet from the server.
- We actually call the key_agreement client operation now. */
+/* Key agreement packet received */
-static void
-silc_client_key_agreement_resolve_cb(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry *clients,
- SilcUInt32 clients_count,
- void *context)
+SILC_FSM_STATE(silc_client_key_agreement)
{
- SilcPacketContext *packet = (SilcPacketContext *)context;
+ SilcClientConnection conn = fsm_context;
+ SilcClient client = conn->client;
+ SilcPacket packet = state_context;
+ SilcClientID remote_id;
+ SilcClientEntry remote_client;
SilcKeyAgreementPayload payload;
- int ret;
- SilcKeyAgreementCallback completion;
- void *completion_context;
- if (!clients)
- goto out;
+ if (packet->src_id_type != SILC_ID_CLIENT) {
+ /** Invalid packet */
+ silc_fsm_next(fsm, silc_client_key_agreement_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
+ &remote_id, sizeof(remote_id))) {
+ /** Invalid source ID */
+ silc_fsm_next(fsm, silc_client_key_agreement_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /* Check whether we know this client already */
+ remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
+ if (!remote_client || !remote_client->nickname[0]) {
+ /** Resolve client info */
+ silc_client_unref_client(client, conn, remote_client);
+ SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
+ client, conn, &remote_id, NULL,
+ silc_client_keyagr_resolved, fsm));
+ /* NOT REACHED */
+ }
/* Parse the key agreement payload */
- payload = silc_key_agreement_payload_parse(packet->buffer->data,
- packet->buffer->len);
- if (!payload)
- goto out;
-
- /* Call the key_agreement client operation */
- ret = client->internal->ops->key_agreement(
- client, conn, clients[0],
- silc_key_agreement_get_hostname(payload),
- silc_key_agreement_get_port(payload),
- &completion, &completion_context);
+ payload = silc_key_agreement_payload_parse(silc_buffer_data(&packet->buffer),
+ silc_buffer_len(&packet->buffer));
+ if (!payload) {
+ /** Malformed Payload */
+ SILC_LOG_DEBUG(("Malformed key agreement payload"));
+ silc_fsm_next(fsm, silc_client_key_agreement_error);
+ return SILC_FSM_CONTINUE;
+ }
+
+ /* If remote did not provide connection endpoint, we will assume that we
+ will provide it and will be responder. */
+ if (!silc_key_agreement_get_hostname(payload))
+ remote_client->internal.prv_resp = TRUE;
+ else
+ remote_client->internal.prv_resp = FALSE;
- /* If the user returned TRUE then we'll start the key agreement right
- here and right now. */
- if (ret == TRUE)
- silc_client_perform_key_agreement(client, conn, clients[0],
- silc_key_agreement_get_hostname(payload),
- silc_key_agreement_get_port(payload),
- completion, completion_context);
+ /* Notify application for key agreement request */
+ client->internal->ops->key_agreement(
+ client, conn, remote_client,
+ silc_key_agreement_get_hostname(payload),
+ silc_key_agreement_get_protocol(payload),
+ silc_key_agreement_get_port(payload));
silc_key_agreement_payload_free(payload);
- out:
- silc_packet_context_free(packet);
+ silc_packet_free(packet);
+ return SILC_FSM_FINISH;
}
-/* Received Key Agreement packet from remote client. Process the packet
- and resolve the client information from the server before actually
- letting the application know that we've received this packet. Then
- call the key_agreement client operation and let the user decide
- whether we perform the key agreement protocol now or not. */
+/* Key agreement packet processing error */
-void silc_client_key_agreement(SilcClient client,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
+SILC_FSM_STATE(silc_client_key_agreement_error)
{
- SilcClientID *remote_id;
-
- if (packet->src_id_type != SILC_ID_CLIENT)
- return;
-
- remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
- SILC_ID_CLIENT);
- if (!remote_id)
- return;
-
- silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
- NULL,
- silc_client_key_agreement_resolve_cb,
- silc_packet_context_dup(packet));
- silc_free(remote_id);
+ SilcPacket packet = state_context;
+ silc_packet_free(packet);
+ return SILC_FSM_FINISH;
}
SilcClientConnection conn,
SilcClientEntry client_entry,
SilcKeyAgreementStatus status,
- SilcSKEKeyMaterial *key,
+ SilcSKEKeyMaterial key,
void *context);
/****s* silcclient/SilcClientAPI/SilcPrivateMessageKeys
SilcClientEntry client_entry; /* The remote client entry */
char *cipher; /* The cipher name */
unsigned char *key; /* The original key, If the appliation
- provided it. This is NULL if the
- library generated the key or if
+ provided it. This is NULL if
the SKE key material was used. */
SilcUInt32 key_len; /* The key length */
} *SilcPrivateMessageKeys;
void (*ask_passphrase)(SilcClient client, SilcClientConnection conn,
SilcAskPassphrase completion, void *context);
- /* Asks whether the user would like to perform the key agreement protocol.
- This is called after we have received an key agreement packet or an
- reply to our key agreement packet. This returns TRUE if the user wants
- the library to perform the key agreement protocol and FALSE if it is not
- desired (application may start it later by calling the function
- silc_client_perform_key_agreement). If TRUE is returned also the
- `completion' and `context' arguments must be set by the application. */
- SilcBool (*key_agreement)(SilcClient client, SilcClientConnection conn,
- SilcClientEntry client_entry,
- const char *hostname, SilcUInt16 port,
- SilcKeyAgreementCallback *completion,
- void **context);
+ /* Called to indicate that incoming key agreement request has been
+ received. If the application wants to perform key agreement it may
+ call silc_client_perform_key_agreement to initiate key agreementn or
+ silc_client_send_key_agreement to provide connection point to the
+ remote client in case the `hostname' is NULL. If key agreement is
+ not desired this request can be ignored. The `protocol' is either
+ value 0 for TCP or value 1 for UDP. */
+ void (*key_agreement)(SilcClient client, SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ const char *hostname, SilcUInt16 protocol,
+ SilcUInt16 port);
/* Notifies application that file transfer protocol session is being
requested by the remote client indicated by the `client_entry' from
/* Called when the client library is up and running. After this callback
is called the application may start using the client library APIs. */
void (*running)(SilcClient client, void *application);
+
} SilcClientOperations;
/***/
*
* Client connection parameters. This can be filled by the application
* and given as argument to silc_client_connect_to_server,
- * silc_client_connect_to_client or silc_client_key_exchange.
+ * silc_client_connect_to_client, silc_client_key_exchange or
+ * silc_client_send_key_agreement.
*
* SOURCE
*/
void *auth;
SilcUInt32 auth_len;
- /* If this boolean is set to TRUE then the client's connection to the
- remote host will use UDP instead of TCP. The `local_ip' specifies
- the local IP address used with the UDP connection, and it must be
- non-NULL. If the `local_port' is non-zero it will be used as local
- port with the UDP connection. The remote host will also send packets
- to the specified address and port. */
+ /* If this boolean is set to TRUE then the connection will use UDP instead
+ of TCP. If UDP is set the also the next `local_ip' and `local_port'
+ must be set. */
SilcBool udp;
+
+ /* The `local_ip' specifies the local IP address used with the connection.
+ It must be non-NULL if `udp' boolean is TRUE. If the `local_port' is
+ non-zero it will be used as local port with UDP connection. The remote
+ host will also send packets to the specified address and port. If the
+ `bind_ip' is non-NULL a listener is bound to that address instead of
+ `local_ip'. */
char *local_ip;
+ char *bind_ip;
int local_port;
/* If this boolean is set to TRUE then the key exchange is done with
unsigned char *detach_data;
SilcUInt32 detach_data_len;
+ /* Connection timeout. If non-zero, the connection will timeout unless
+ the SILC connection is completed in the specified amount of time. */
+ SilcUInt32 timeout_secs;
} SilcClientConnectionParams;
/***/
* const char *cipher,
* const char *hmac,
* unsigned char *key,
- * SilcUInt32 key_len,
- * SilcBool generate_key,
- * SilcBool responder);
+ * SilcUInt32 key_len);
*
* DESCRIPTION
*
- * Adds private message key to the client library. The key will be used to
- * encrypt all private message between the client and the remote client
- * indicated by the `client_entry'. If the `key' is NULL and the boolean
- * value `generate_key' is TRUE the library will generate random key.
- * The `key' maybe for example pre-shared-key, passphrase or similar.
- * The `cipher' and `hmac' MAY be provided but SHOULD be NULL to assure
- * that the requirements of the SILC protocol are met. The API, however,
- * allows to allocate any cipher and HMAC.
+ * Adds a static private message key to the client library. The key
+ * will be used to encrypt all private message between the client and
+ * the remote client indicated by the `client_entry'. The `key' can
+ * be for example a pre-shared-key, passphrase or similar shared secret
+ * string. The `cipher' and `hmac' MAY be provided but SHOULD be NULL
+ * to assure that the requirements of the SILC protocol are met. The
+ * API, however, allows to allocate any cipher and HMAC.
*
- * If `responder' is TRUE then the sending and receiving keys will be
- * set according the client being the receiver of the private key. If
- * FALSE the client is being the sender (or negotiator) of the private
- * key.
+ * If the private message key is added to client without first receiving
+ * a request for it from the remote `client_entry' this function will
+ * send the request to `client_entry'. Note that, the actual key is
+ * not sent to the network.
*
* It is not necessary to set key for normal private message usage. If the
* key is not set then the private messages are encrypted using normal
- * session keys. Setting the private key, however, increases the security.
+ * session keys. Setting the private key, however, increases the security.
*
* Returns FALSE if the key is already set for the `client_entry', TRUE
* otherwise.
const char *cipher,
const char *hmac,
unsigned char *key,
- SilcUInt32 key_len,
- SilcBool generate_key,
- SilcBool responder);
+ SilcUInt32 key_len);
/****f* silcclient/SilcClientAPI/silc_client_add_private_message_key_ske
*
* DESCRIPTION
*
* Same as silc_client_add_private_message_key but takes the key material
- * from the SKE key material structure. This structure is received if
+ * from the SKE key material structure. This structure is received if
* the application uses the silc_client_send_key_agreement to negotiate
- * the key material. The `cipher' and `hmac' SHOULD be provided as it is
+ * the key material. The `cipher' and `hmac' SHOULD be provided as it is
* negotiated also in the SKE protocol.
*
***/
SilcClientEntry client_entry,
const char *cipher,
const char *hmac,
- SilcSKEKeyMaterial key,
- SilcBool responder);
+ SilcSKEKeyMaterial key);
/****f* silcclient/SilcClientAPI/silc_client_del_private_message_key
*
SilcClientConnection conn,
SilcUInt32 *key_count);
-/****f* silcclient/SilcClientAPI/silc_client_send_private_message_key_request
- *
- * SYNOPSIS
- *
- * SilcBool
- * silc_client_send_private_message_key_request(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientEntry client_entry);
- *
- * DESCRIPTION
- *
- * This function can be used to send an private message key indicator
- * request to the remote client indicated by 'client_entry'. This can
- * be used when setting a static or pre-shared private message key.
- * The sender of this packet is the initiator and must set the 'responder'
- * argument in silc_client_add_private_message_key function to FALSE.
- * The receiver of this indicator request must set it to TRUE, if the
- * receiver decides to set a private message key. By using this
- * function applications may automate initiator/responder setting in
- * private message key functions, without asking from user which one is
- * the initiator and which one is responder.
- *
- * NOTES
- *
- * The sender of this packet must set the private message key for
- * 'client_entry' before calling this function. The 'responder'
- * argument MUST be set to FALSE when setting the key.
- *
- ***/
-SilcBool
-silc_client_send_private_message_key_request(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry);
-
/****f* silcclient/SilcClientAPI/silc_client_free_private_message_keys
*
* SYNOPSIS
SilcChannelPrivateKey key);
-/* Key Agreement routines (client_keyagr.c) */
+/* Key Agreement routines */
/****f* silcclient/SilcClientAPI/silc_client_send_key_agreement
*
* void silc_client_send_key_agreement(SilcClient client,
* SilcClientConnection conn,
* SilcClientEntry client_entry,
- * char *hostname,
- * int port,
- * SilcUInt32 timeout_secs,
+ * SilcClientConnectionParams *params,
+ * SilcPublicKey public_key,
+ * SilcPrivateKey private_key,
* SilcKeyAgreementCallback completion,
* void *context);
*
* DESCRIPTION
*
* Sends key agreement request to the remote client indicated by the
- * `client_entry'. If the caller provides the `hostname' and the `port'
- * arguments then the library will bind the client to that hostname and
- * that port for the key agreement protocol. It also sends the `hostname'
- * and the `port' in the key agreement packet to the remote client. This
- * would indicate that the remote client may initiate the key agreement
- * protocol to the `hostname' on the `port'. If port is zero then the
- * bound port is undefined (the operating system defines it).
- *
- * If the `hostname' and `port' is not provided then empty key agreement
- * packet is sent to the remote client. The remote client may reply with
- * the same packet including its hostname and port. If the library receives
- * the reply from the remote client the `key_agreement' client operation
- * callback will be called to verify whether the user wants to perform the
- * key agreement or not.
- *
- * NOTES
- *
- * NOTE: If the application provided the `hostname' and the `port' and the
- * remote side initiates the key agreement protocol it is not verified
- * from the user anymore whether the protocol should be executed or not.
- * By setting the `hostname' and `port' the user gives permission to
- * perform the protocol (we are responder in this case).
- *
- * NOTE: If the remote side decides not to initiate the key agreement
- * or decides not to reply with the key agreement packet then we cannot
- * perform the key agreement at all. If the key agreement protocol is
- * performed the `completion' callback with the `context' will be called.
- * If remote side decides to ignore the request the `completion' will be
- * called after the specified timeout, `timeout_secs'.
- *
- * NOTE: If the `hostname' and the `port' was not provided the `completion'
- * will not be called at all since this does nothing more than sending
- * a packet to the remote host.
- *
- * NOTE: There can be only one active key agreement for one client entry.
- * Before setting new one, the old one must be finished (it is finished
- * after calling the completion callback) or the function
- * silc_client_abort_key_agreement must be called.
+ * `client_entry'.
+ *
+ * If `params' is non-NULL and it has the `local_ip' and `local_port' set
+ * the caller will provide the connection endpoint for the key agreement
+ * connection. The `bind_ip' can be used to bind to that IP instead of
+ * `local_ip'. If the `udp' is set to TRUE the connection will be UDP
+ * instead of TCP. Caller may also set the `repository', `verify_notfound'
+ * and `timeout_secs' fields in `params'. Other fields are ignored.
+ * If `params' is NULL, then the `client_entry' is expected to provide
+ * the connection endpoint for us. It is recommended the `timeout_secs'
+ * is specified in case the remote client does not reply anything to
+ * the request.
+ *
+ * The `public_key' and `private_key' is our identity in the key agreement.
+ *
+ * In case we do not provide the connection endpoint, we will receive
+ * the `key_agreement' client operation when the remote send its own
+ * key agreement request packet. We may then there start the key
+ * agreement with silc_client_perform_key_agreement. If we provided the
+ * the connection endpoint, the client operation will not be called.
+ *
+ * There can be only one active key agreement for `client_entry'. Old
+ * key agreement may be aborted by calling silc_client_abort_key_agreement.
*
***/
void silc_client_send_key_agreement(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry,
- const char *hostname,
- const char *bindhost,
- int port,
- SilcUInt32 timeout_secs,
+ SilcClientConnectionParams *params,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
SilcKeyAgreementCallback completion,
void *context);
* silc_client_perform_key_agreement(SilcClient client,
* SilcClientConnection conn,
* SilcClientEntry client_entry,
- * char *hostname,
- * int port,
+ * SilcClientConnectionParams *params,
+ * SilcPublicKey public_key,
+ * SilcPrivateKey private_key,
+ * char *hostname, int port,
* SilcKeyAgreementCallback completion,
* void *context);
*
* DESCRIPTION
*
- * Performs the actual key agreement protocol. Application may use this
- * to initiate the key agreement protocol. This can be called for example
- * after the application has received the `key_agreement' client operation,
- * and did not return TRUE from it.
+ * Performs the key agreement protocol. Application may use this to
+ * initiate the key agreement protocol. Usually this is called after
+ * receiving the `key_agreement' client operation.
*
* The `hostname' is the remote hostname (or IP address) and the `port'
- * is the remote port. The `completion' callback with the `context' will
+ * is the remote port. The `completion' callback with the `context' will
* be called after the key agreement protocol.
*
- * NOTES
- *
- * NOTE: If the application returns TRUE in the `key_agreement' client
- * operation the library will automatically start the key agreement. In this
- * case the application must not call this function. However, application
- * may choose to just ignore the `key_agreement' client operation (and
- * merely just print information about it on the screen) and call this
- * function when the user whishes to do so (by, for example, giving some
- * specific command). Thus, the API provides both, automatic and manual
- * initiation of the key agreement. Calling this function is the manual
- * initiation and returning TRUE in the `key_agreement' client operation
- * is the automatic initiation.
+ * The `params' is connection parameters and it may be used to define
+ * the key agreement connection related parameters. It may be NULL.
*
***/
void silc_client_perform_key_agreement(SilcClient client,
SilcClientConnection conn,
SilcClientEntry client_entry,
- char *hostname,
- int port,
+ SilcClientConnectionParams *params,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
+ char *hostname, int port,
SilcKeyAgreementCallback completion,
void *context);
-/****f* silcclient/SilcClientAPI/silc_client_perform_key_agreement_fd
+/****f* silcclient/SilcClientAPI/silc_client_perform_key_agreement_stream
*
* SYNOPSIS
*
* void
- * silc_client_perform_key_agreement_fd(SilcClient client,
- * SilcClientConnection conn,
- * SilcClientEntry client_entry,
- * int sock,
- * char *hostname,
- * SilcKeyAgreementCallback completion,
- * void *context);
+ * silc_client_perform_key_agreement_stream(
+ * SilcClient client,
+ * SilcClientConnection conn,
+ * SilcClientEntry client_entry,
+ * SilcClientConnectionParams *params,
+ * SilcPublicKey public_key,
+ * SilcPrivateKey private_key,
+ * SilcStream stream,
+ * SilcKeyAgreementCallback completion,
+ * void *context);
*
* DESCRIPTION
*
- * Same as above but application has created already the connection to
- * the remote host. The `sock' is the socket to the remote connection.
- * Application can use this function if it does not want the client library
- * to create the connection.
+ * Same as silc_client_perform_key_agreement but the caller has created
+ * the connection. The `stream' is the created connection.
*
***/
-void silc_client_perform_key_agreement_fd(SilcClient client,
- SilcClientConnection conn,
- SilcClientEntry client_entry,
- int sock,
- char *hostname,
- SilcKeyAgreementCallback completion,
- void *context);
+void
+silc_client_perform_key_agreement_stream(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry,
+ SilcClientConnectionParams *params,
+ SilcPublicKey public_key,
+ SilcPrivateKey private_key,
+ SilcStream stream,
+ SilcKeyAgreementCallback completion,
+ void *context);
/****f* silcclient/SilcClientAPI/silc_client_abort_key_agreement
*