+Tue Sep 4 12:39:17 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
+
+ * Changed the get_auth_methdod client operation to be asynchronous.
+ It can be async if the application resolves the authentication
+ method from the server during the negotiation. Added new
+ SilcGetAuthMeth completion callback that the application will
+ call after resolving the authentication method.
+
+ Added function silc_client_request_authentication_method that
+ the application can use to resolve the authentication method
+ from the server. Added also SilcConnectionAuthRequest callback
+ that the library will call after the server has replied. The
+ application can call this function if it does not know the
+ current authentication method.
+
+ Affected files are lib/silcclient/client.c and
+ lib/silcclient/silcapi.h.
+
+ * The Irssi SILC client now automatically resolves the authentication
+ method incase any configuration information is not present (and
+ currently there never is). The affected file is
+ irssi/src/silc/core/client_ops.c.
+
+ * Fixed public key authentication from the client library.
+ Affected file lib/silcclient/protocol.c. Changed also the
+ protocol specification about the public key authentication in
+ the connection authentication protocol. The actual data to be
+ signed is now computed with a hash function before signing.
+
+ * Fixed the public key authentication from the server as well.
+ Affected file silcd/protocol.c.
+
+ * Removed the mlock()'s from the memory allocation routines.
+ Affected file lib/silcutil/silcmemory.c. The ./configure does
+ not check anymore for the mlock(). Affected file is
+ configure.in.pre.
+
Mon Sep 3 20:09:59 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
* Fixed the lib/silcmath/mpi/mpi.h to always use 32-bit data
* Do not check for threads at all on BSD systems. Affected
file configure.in.pre.
+ * Removed -n and -h options from the Irssi SILC Client since
+ they are not used in silc.
+
+ * Fixed the prime generation to assure that the first digit
+ of the generated random number is not zero since our conversion
+ routines does not like number strings that starts with zero
+ digit. If zero digit is seen the random number is regenerated.
+ This caused some corrupted RSA keys when the zero first digit
+ was met. Affected file lib/silcmath/silcprimegen.c.
+
Sun Sep 2 17:17:24 EEST 2001 Pekka Riikonen <priikone@silcnet.org>
* Fixed WIN32 configuration in the ./configure script.
TODO/bugs in Irssi SILC client
==============================
- o If the configuration for a server connection does not exist then
- resolve the authentication method always from the server. Otherwise
- password and/or public key auth with server does not work since it
- now assumes that config exists or NONE is used.
-
- o -n and -c options does not work.
-
- o Switching servers while on channel is supposed to crash the client?
-
o Add local command to switch the channel's private key when channel has
several private keys. Currently sending channel messages with many
keys is not possible because changing the key is not possible by the
o Some ./prepare problems with latest autoconf and automake.
- o Remove the mlock() stuff from the lib/silcutil/silcmemory.c, they
- are redundant.
-
o Compression routines are missing. The protocol supports packet
compression thus it must be implemented. SILC Comp API must be
defined. zlib package is already included into the lib dir (in CVS,
{ "password", 'w', POPT_ARG_STRING, &autocon_password, 0, "Autoconnect password", "SERVER" },
{ "port", 'p', POPT_ARG_INT, &autocon_port, 0, "Autoconnect port", "PORT" },
{ "noconnect", '!', POPT_ARG_NONE, &no_autoconnect, 0, "Disable autoconnecting", NULL },
+ /*
{ "nick", 'n', POPT_ARG_STRING, &cmdline_nick, 0, "Specify nick to use", NULL },
{ "hostname", 'h', POPT_ARG_STRING, &cmdline_hostname, 0, "Specify host name to use", NULL },
+ */
{ NULL, '\0', 0, NULL }
};
}
void silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
- SilcAskPassphrase completion, void *context)
+ SilcAskPassphrase completion, void *context)
{
AskPassphrase p = silc_calloc(1, sizeof(*p));
p->completion = completion;
"Passphrase: ", ENTRY_REDIRECT_FLAG_HIDDEN, p);
}
+typedef struct {
+ SilcGetAuthMeth completion;
+ void *context;
+} *InternalGetAuthMethod;
+
+/* Callback called when we've received the authentication method information
+ from the server after we've requested it. This will get the authentication
+ data from the user if needed. */
+
+static void silc_get_auth_method_callback(SilcClient client,
+ SilcClientConnection conn,
+ SilcAuthMethod auth_meth,
+ void *context)
+{
+ InternalGetAuthMethod internal = (InternalGetAuthMethod)context;
+
+ switch (auth_meth) {
+ case SILC_AUTH_NONE:
+ /* No authentication required. */
+ (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+ break;
+ case SILC_AUTH_PASSWORD:
+ /* Do not ask the passphrase from user, the library will ask it if
+ we do not provide it here. */
+ (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+ break;
+ case SILC_AUTH_PUBLIC_KEY:
+ /* Do not get the authentication data now, the library will generate
+ it using our default key, if we do not provide it here. */
+ /* XXX In the future when we support multiple local keys and multiple
+ local certificates we will need to ask from user which one to use. */
+ (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+ break;
+ }
+
+ silc_free(internal);
+}
+
/* Find authentication method and authentication data by hostname and
port. The hostname may be IP address as well. The found authentication
method and authentication data is returned to `auth_meth', `auth_data'
and `auth_data_len'. The function returns TRUE if authentication method
is found and FALSE if not. `conn' may be NULL. */
-int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
- char *hostname, uint16 port,
- SilcProtocolAuthMeth *auth_meth,
- unsigned char **auth_data,
- uint32 *auth_data_len)
+void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
+ char *hostname, uint16 port,
+ SilcGetAuthMeth completion, void *context)
{
- bool ret = TRUE;
- SILC_SERVER_REC *server = conn ? conn->context : NULL;
+ InternalGetAuthMethod internal;
/* XXX must resolve from configuration whether this connection has
any specific authentication data */
- *auth_meth = SILC_AUTH_NONE;
- *auth_data = NULL;
- *auth_data_len = 0;
-
- if (ret == FALSE) {
- printformat_module("fe-common/silc", server, NULL,
- MSGLEVEL_MODES, SILCTXT_AUTH_METH_UNRESOLVED);
- }
+ /* If we do not have this connection configured by the user in a
+ configuration file then resolve the authentication method from the
+ server for this session. */
+ internal = silc_calloc(1, sizeof(*internal));
+ internal->completion = completion;
+ internal->context = context;
- return ret;
+ silc_client_request_authentication_method(client, conn,
+ silc_get_auth_method_callback,
+ internal);
}
/* Notifies application that failure packet was received. This is called
SilcSocketType conn_type, unsigned char *pk,
uint32 pk_len, SilcSKEPKType pk_type,
SilcVerifyPublicKey completion, void *context);
-int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
- char *hostname, uint16 port,
- SilcProtocolAuthMeth *auth_meth,
- unsigned char **auth_data,
- uint32 *auth_data_len);
+void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
+ char *hostname, uint16 port,
+ SilcGetAuthMeth completion, void *context);
void silc_failure(SilcClient client, SilcClientConnection conn,
SilcProtocol protocol, void *failure);
int silc_key_agreement(SilcClient client, SilcClientConnection conn,
SILC_PKCS_FILE_BIN) == FALSE)
return FALSE;
+ silc_pkcs_alloc(client->public_key->name, &client->pkcs);
+ silc_pkcs_public_key_set(client->pkcs, client->public_key);
+ silc_pkcs_private_key_set(client->pkcs, client->private_key);
+
return TRUE;
}
actually be received at anytime but usually it is used only during
the connection authentication phase. Now, protocol says that this packet
can come from client or server, however, we support only this coming
- from client and expect that server's always knows what authentication
+ from client and expect that server always knows what authentication
method to use. */
void silc_server_connection_auth_request(SilcServer server,
{
SilcServerConfigSectionClientConnection *client = NULL;
uint16 conn_type;
- int ret;
+ int ret, port;
SilcAuthMethod auth_meth;
SILC_LOG_DEBUG(("Start"));
/* Get the authentication method for the client */
auth_meth = SILC_AUTH_NONE;
+ port = server->sockets[server->sock]->port; /* Listenning port */
client = silc_server_config_find_client_conn(server->config,
sock->ip,
- sock->port);
+ port);
if (!client)
client = silc_server_config_find_client_conn(server->config,
sock->hostname,
- sock->port);
+ port);
if (client)
auth_meth = client->auth_meth;
SILC_STR_END);
/* Verify signature */
- if (silc_pkcs_verify(pkcs, sign, sign_len, auth->data, auth->len)) {
+ if (silc_pkcs_verify_with_hash(pkcs, ske->prop->hash, sign, sign_len,
+ auth->data, auth->len)) {
silc_pkcs_free(pkcs);
silc_buffer_free(auth);
return TRUE;
static int
silc_server_get_public_key_auth(SilcServer server,
- SilcPublicKey pub_key,
unsigned char *auth_data,
uint32 *auth_data_len,
SilcSKE ske)
SilcPKCS pkcs;
SilcBuffer auth;
- if (!pub_key)
- return FALSE;
-
- silc_pkcs_alloc(pub_key->name, &pkcs);
- if (!silc_pkcs_public_key_set(pkcs, pub_key)) {
- silc_pkcs_free(pkcs);
- return FALSE;
- }
+ pkcs = server->pkcs;
/* Make the authentication data. Protocol says it is HASH plus
KE Start Payload. */
ske->start_payload_copy->len),
SILC_STR_END);
- if (silc_pkcs_sign(pkcs, auth->data, auth->len, auth_data, auth_data_len)) {
- silc_pkcs_free(pkcs);
+ if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data,
+ auth->len, auth_data, auth_data_len)) {
silc_buffer_free(auth);
return TRUE;
}
- silc_pkcs_free(pkcs);
silc_buffer_free(auth);
return FALSE;
}
unsigned char sign[1024];
/* Public key authentication */
- silc_server_get_public_key_auth(server, ctx->auth_data,
- sign, &auth_data_len,
+ silc_server_get_public_key_auth(server, sign, &auth_data_len,
ctx->ske);
auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
memcpy(auth_data, sign, auth_data_len);
if (ctx->packet->type != SILC_PACKET_REKEY_DONE) {
/* Error in protocol */
protocol->state = SILC_PROTOCOL_STATE_ERROR;
- silc_protocol_execute(protocol, server->schedule, 0, 0);
+ silc_protocol_execute(protocol, server->schedule, 0, 300000);
return;
}
if (server->rng)
silc_rng_free(server->rng);
+ if (server->pkcs)
+ silc_pkcs_free(server->pkcs);
+
#ifdef SILC_SIM
while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
silc_dlist_del(server->sim, sim);
SilcServerID *id;
SilcServerEntry id_entry;
SilcIDListPurge purge;
+ SilcServerConfigSectionListenPort *listen;
SILC_LOG_DEBUG(("Initializing server"));
assert(server);
/* Initialize none cipher */
silc_cipher_alloc("none", &server->none_cipher);
- /* Create a listening server. Note that our server can listen on
- multiple ports. All listeners are created here and now. */
- /* XXX Still check this whether to use server_info or listen_port. */
+ /* Allocate PKCS context for local public and private keys */
+ silc_pkcs_alloc(server->public_key->name, &server->pkcs);
+ silc_pkcs_public_key_set(server->pkcs, server->public_key);
+ silc_pkcs_private_key_set(server->pkcs, server->private_key);
+
+ /* Create a listening server. Note that our server can listen on multiple
+ ports. All listeners are created here and now. */
sock_count = 0;
- while(server->config->listen_port) {
+ listen = server->config->listen_port;
+ while(listen) {
int tmp;
tmp = silc_net_create_server(server->config->listen_port->port,
- server->config->listen_port->host);
+ server->config->listen_port->listener_ip);
if (tmp < 0)
goto err0;
sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
sock[sock_count] = tmp;
- server->config->listen_port = server->config->listen_port->next;
sock_count++;
+ listen = listen->next;
}
/* Initialize ID caches */
sconn->remote_host, sconn->remote_port));
/* Connect to remote host */
- sock = silc_net_create_connection(sconn->remote_port,
+ sock = silc_net_create_connection(server->config->listen_port->local_ip,
+ sconn->remote_port,
sconn->remote_host);
if (sock < 0) {
SILC_LOG_ERROR(("Could not connect to router"));
SILC_SERVER_CONFIG_LIST_ALLOC(config->listen_port);
- /* Get host */
- ret = silc_config_get_token(line, &config->listen_port->host);
+ /* Get local IP */
+ ret = silc_config_get_token(line, &config->listen_port->local_ip);
if (ret < 0)
break;
- /* Get remote IP */
- ret = silc_config_get_token(line, &config->listen_port->remote_ip);
+ /* Get listener IP */
+ ret = silc_config_get_token(line, &config->listen_port->listener_ip);
if (ret < 0)
break;
/* Holds all the ports the server is listenning on */
typedef struct SilcServerConfigSectionListenPortStruct {
- char *host;
- char *remote_ip;
+ char *local_ip;
+ char *listener_ip;
uint16 port;
struct SilcServerConfigSectionListenPortStruct *next;
struct SilcServerConfigSectionListenPortStruct *prev;
/* Holds server's execution identity, or the user and group which
to change from root when server starts */
typedef struct {
- char *user;
- char *group;
+ char *user;
+ char *group;
} SilcServerConfigSectionIdentity;
/* Holds all the configured log files. */
AC_CHECK_FUNCS(select listen bind shutdown close connect)
AC_CHECK_FUNCS(fcntl setsockopt)
AC_CHECK_FUNCS(getopt_long time)
-AC_CHECK_FUNCS(mlock munlock)
AC_CHECK_FUNCS(chmod stat fstat getenv putenv strerror ctime gettimeofday)
AC_CHECK_FUNCS(getpid getgid getsid getpgid getpgrp getuid)
AC_CHECK_FUNCS(strchr strstr strcpy strncpy memcpy memset memmove)
Authentication for more information.
If authentication method is public key authentication the authentication
-data is signature of the hash value HASH plus Key Exchange Start Payload,
-established by the SILC Key Exchange protocol. This signature MUST then
-be verified by the server. See the section 3.2.2 Public Key
-Authentication for more information.
+data is a signature of the hash value of hash HASH plus Key Exchange
+Start Payload, established by the SILC Key Exchange protocol. This
+signature MUST then be verified by the server. See the section 3.2.2
+Public Key Authentication for more information.
The connecting client of this protocol MUST wait after successful execution
of this protocol for the SILC_PACKET_NEW_ID packet where it will receive
The signature is computed using the private key of the sender by signing
the HASH value provided by the SKE protocol previously, and the Key
Exchange Start Payload from SKE protocol that was sent to the server.
-The server MUST verify the data, thus it must keep the HASH and the
-Key Exchange Start Payload saved during SKE and authentication protocols.
+These are concatenated and hash function is used to compute a hash value
+which is then signed.
+
+ auth_hash = hash(HASH | Key Exchange Start Payload);
+ signature = sign(auth_hash);
+
+The hash() function used to compute the value is the hash function negotiated
+in the SKE protocol. The server MUST verify the data, thus it must keep
+the HASH and the Key Exchange Start Payload saved during SKE and
+authentication protocols.
If the verified signature matches the sent signature, the authentication
were successful and SILC_PACKET_SUCCESS is sent. If it failed the protocol
#
# Listenning ports.
#
-# Format: <local IP/UNIX socket path>:<remote IP>:<port>
+# Format: <local IP>:<Listener IP>:<port>
#
[ListenPort]
10.2.1.6:10.2.1.6:706
static void silc_client_packet_parse_type(SilcClient client,
SilcSocketConnection sock,
SilcPacketContext *packet);
+void silc_client_resolve_auth_method(bool success,
+ SilcProtocolAuthMeth auth_meth,
+ const unsigned char *auth_data,
+ uint32 auth_data_len, void *context);
/* Allocates new client object. This has to be done before client may
work. After calling this one must call silc_client_init to initialize
if (!new_client->params->rekey_secs)
new_client->params->rekey_secs = 3600;
+ if (!new_client->params->connauth_request_secs)
+ new_client->params->connauth_request_secs = 2;
+
return new_client;
}
/* XXX In the future we should give up this non-blocking connect all
together and use threads instead. */
/* Create connection to server asynchronously */
- sock = silc_net_create_connection_async(ctx->port, ctx->host);
+ sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
if (sock < 0)
return -1;
proto_ctx->dest_id_type = ctx->dest_id_type;
proto_ctx->dest_id = ctx->dest_id;
- /* Resolve the authentication method to be used in this connection */
- if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
- sock->port, &proto_ctx->auth_meth,
- &proto_ctx->auth_data,
- &proto_ctx->auth_data_len))
- proto_ctx->auth_meth = SILC_AUTH_NONE;
-
/* Free old protocol as it is finished now */
silc_protocol_free(protocol);
if (ctx->packet)
silc_free(ctx);
sock->protocol = NULL;
+ /* Resolve the authentication method to be used in this connection. The
+ completion callback is called after the application has resolved
+ the authentication method. */
+ client->ops->get_auth_method(client, sock->user_data, sock->hostname,
+ sock->port, silc_client_resolve_auth_method,
+ proto_ctx);
+}
+
+/* Authentication method resolving callback. Application calls this function
+ after we've called the client->ops->get_auth_method client operation
+ to resolve the authentication method. We will continue the executiong
+ of the protocol in this function. */
+
+void silc_client_resolve_auth_method(bool success,
+ SilcProtocolAuthMeth auth_meth,
+ const unsigned char *auth_data,
+ uint32 auth_data_len, void *context)
+{
+ SilcClientConnAuthInternalContext *proto_ctx =
+ (SilcClientConnAuthInternalContext *)context;
+ SilcClient client = (SilcClient)proto_ctx->client;
+
+ if (!success)
+ auth_meth = SILC_AUTH_NONE;
+
+ proto_ctx->auth_meth = auth_meth;
+
+ if (auth_data && auth_data_len) {
+ proto_ctx->auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
+ memcpy(proto_ctx->auth_data, auth_data, auth_data_len);
+ proto_ctx->auth_data_len = auth_data_len;
+ }
+
/* Allocate the authenteication protocol and execute it. */
silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
- &sock->protocol, (void *)proto_ctx,
+ &proto_ctx->sock->protocol, (void *)proto_ctx,
silc_client_connect_to_server_final);
/* Execute the protocol */
- silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
+ silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
}
/* Finalizes the connection to the remote SILC server. This is called
conn->rekey->timeout = client->params->rekey_secs;
conn->rekey->context = (void *)client;
silc_schedule_task_add(client->schedule, conn->sock->sock,
- silc_client_rekey_callback,
- (void *)conn->sock, conn->rekey->timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ silc_client_rekey_callback,
+ (void *)conn->sock, conn->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
silc_protocol_free(protocol);
if (ctx->auth_data)
/* Parse the packet */
silc_schedule_task_add(client->schedule, parser_context->sock->sock,
- silc_client_packet_parse_real,
- (void *)parser_context, 0, 1,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_client_packet_parse_real,
+ (void *)parser_context, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
/* Parses the packet type and calls what ever routines the packet type
}
break;
+ case SILC_PACKET_CONNECTION_AUTH_REQUEST:
+ /*
+ * Reveived reply to our connection authentication method request
+ * packet. This is used to resolve the authentication method for the
+ * current session from the server if the client does not know it.
+ */
+ silc_client_connection_auth_request(client, sock, packet);
+ break;
+
default:
SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
break;
/* Re-register re-key timeout */
silc_schedule_task_add(client->schedule, sock->sock,
- silc_client_rekey_callback,
- context, conn->rekey->timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ silc_client_rekey_callback,
+ context, conn->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
/* The final callback for the REKEY protocol. This will actually take the
silc_socket_free(ctx->sock);
silc_free(ctx);
}
+
+/* Processes incoming connection authentication method request packet.
+ It is a reply to our previously sent request. The packet can be used
+ to resolve the authentication method for the current session if the
+ client does not know it beforehand. */
+
+void silc_client_connection_auth_request(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ uint16 conn_type, auth_meth;
+ int ret;
+
+ /* If we haven't send our request then ignore this one. */
+ if (!conn->connauth)
+ return;
+
+ /* Parse the payload */
+ ret = silc_buffer_unformat(packet->buffer,
+ SILC_STR_UI_SHORT(&conn_type),
+ SILC_STR_UI_SHORT(&auth_meth),
+ SILC_STR_END);
+ if (ret == -1)
+ auth_meth = SILC_AUTH_NONE;
+
+ /* Call the request callback to notify application for received
+ authentication method information. */
+ if (conn->connauth->callback)
+ (*conn->connauth->callback)(client, conn, auth_meth,
+ conn->connauth->context);
+
+ silc_schedule_task_del(client->schedule, conn->connauth->timeout);
+
+ silc_free(conn->connauth);
+ conn->connauth = NULL;
+}
+
+/* Timeout task callback called if the server does not reply to our
+ connection authentication method request in the specified time interval. */
+
+SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
+{
+ SilcClientConnection conn = (SilcClientConnection)context;
+ SilcClient client = conn->client;
+
+ if (!conn->connauth)
+ return;
+
+ /* Call the request callback to notify application */
+ if (conn->connauth->callback)
+ (*conn->connauth->callback)(client, conn, SILC_AUTH_NONE,
+ conn->connauth->context);
+
+ silc_free(conn->connauth);
+ conn->connauth = NULL;
+}
+
+/* This function can be used to request the current authentication method
+ from the server. This may be called when connecting to the server
+ and the client library requests the authentication data from the
+ application. If the application does not know the current authentication
+ method it can request it from the server using this function.
+ The `callback' with `context' will be called after the server has
+ replied back with the current authentication method. */
+
+void
+silc_client_request_authentication_method(SilcClient client,
+ SilcClientConnection conn,
+ SilcConnectionAuthRequest callback,
+ void *context)
+{
+ SilcClientConnAuthRequest connauth;
+ SilcBuffer packet;
+
+ connauth = silc_calloc(1, sizeof(*connauth));
+ connauth->callback = callback;
+ connauth->context = context;
+
+ if (conn->connauth)
+ silc_free(conn->connauth);
+
+ conn->connauth = connauth;
+
+ /* Assemble the request packet and send it to the server */
+ packet = silc_buffer_alloc(4);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
+ SILC_STR_UI_SHORT(SILC_AUTH_NONE),
+ SILC_STR_END);
+ silc_client_packet_send(client, conn->sock,
+ SILC_PACKET_CONNECTION_AUTH_REQUEST,
+ NULL, 0, NULL, NULL,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+
+ /* Register a timeout in case server does not reply anything back. */
+ connauth->timeout =
+ silc_schedule_task_add(client->schedule, conn->sock->sock,
+ silc_client_request_authentication_method_timeout,
+ conn, client->params->connauth_request_secs, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+}
void *context;
} *SilcClientRekey;
+/* Context to hold the connection authentication request callbacks that
+ will be called when the server has replied back to our request about
+ current authentication method in the session. */
+typedef struct {
+ SilcConnectionAuthRequest callback;
+ void *context;
+ SilcTask timeout;
+} *SilcClientConnAuthRequest;
+
/* Connection structure used in client to associate all the important
connection specific data to this structure. */
struct SilcClientConnectionStruct {
/* Re-key context */
SilcClientRekey rekey;
+ /* Authentication request context. */
+ SilcClientConnAuthRequest connauth;
+
/* Pointer back to the SilcClient. This object is passed to the application
and the actual client object is accesible through this pointer. */
SilcClient client;
void silc_client_private_message(SilcClient client,
SilcSocketConnection sock,
SilcPacketContext *packet);
+void silc_client_connection_auth_request(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet);
#endif
int sock;
/* Create connection to server asynchronously */
- sock = silc_net_create_connection_async(ctx->port, ctx->host);
+ sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
if (sock < 0)
return -1;
static int
silc_client_get_public_key_auth(SilcClient client,
- char *filepath,
+ SilcClientConnection conn,
unsigned char *auth_data,
uint32 *auth_data_len,
SilcSKE ske)
int len;
SilcPKCS pkcs;
SilcBuffer auth;
- SilcPublicKey pub_key;
- if (!silc_pkcs_load_public_key(filepath,&pub_key, SILC_PKCS_FILE_PEM))
- if (!silc_pkcs_load_public_key(filepath, &pub_key, SILC_PKCS_FILE_BIN))
- return FALSE;
-
- silc_pkcs_alloc(pub_key->name, &pkcs);
- if (!silc_pkcs_public_key_set(pkcs, pub_key)) {
- silc_pkcs_free(pkcs);
- silc_pkcs_public_key_free(pub_key);
- return FALSE;
- }
+ /* Use our default key */
+ pkcs = client->pkcs;
/* Make the authentication data. Protocol says it is HASH plus
KE Start Payload. */
ske->start_payload_copy->len),
SILC_STR_END);
- if (silc_pkcs_sign(pkcs, auth->data, auth->len, auth_data, auth_data_len)) {
- silc_pkcs_free(pkcs);
+ if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data,
+ auth->len, auth_data, auth_data_len)) {
silc_buffer_free(auth);
- silc_pkcs_public_key_free(pub_key);
return TRUE;
}
- silc_pkcs_free(pkcs);
silc_buffer_free(auth);
- silc_pkcs_public_key_free(pub_key);
return FALSE;
}
SILC_PACKET_CONNECTION_AUTH,
NULL, 0, NULL, NULL,
packet->data, packet->len, TRUE);
-
- if (auth_data) {
- memset(auth_data, 0, auth_data_len);
- silc_free(auth_data);
- }
silc_buffer_free(packet);
/* Next state is end of protocol */
*/
unsigned char *auth_data = NULL;
uint32 auth_data_len = 0;
+ unsigned char sign[1024];
switch(ctx->auth_meth) {
case SILC_AUTH_NONE:
break;
case SILC_AUTH_PUBLIC_KEY:
- {
- unsigned char sign[1024];
-
+ if (!ctx->auth_data) {
/* Public key authentication */
- silc_client_get_public_key_auth(client, ctx->auth_data,
- sign, &auth_data_len,
+ silc_client_get_public_key_auth(client, conn, sign, &auth_data_len,
ctx->ske);
- auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
- memcpy(auth_data, sign, auth_data_len);
- break;
+ auth_data = sign;
+ } else {
+ auth_data = ctx->auth_data;
+ auth_data_len = ctx->auth_data_len;
}
+
+ break;
}
silc_client_conn_auth_continue(auth_data,
***/
typedef void (*SilcVerifyPublicKey)(bool success, void *context);
+/****f* silcclient/SilcClientAPI/SilcGetAuthMeth
+ *
+ * SYNOPSIS
+ *
+ * typedef void (*SilcGetAuthMeth)(bool success,
+ * SilcProtocolAuthMeth auth_meth,
+ * const unsigned char *auth_data,
+ * uint32 auth_data_len, void *context);
+ *
+ * DESCRIPTION
+ *
+ * Authentication method resolving callback. This is called by the
+ * application to return the resolved authentication method. The client
+ * library has called the get_auth_method client operation and given
+ * this function pointer as argument. The `success' will indicate whether
+ * the authentication method could be resolved. The `auth_meth' is the
+ * resolved authentication method. The `auth_data' and the `auth_data_len'
+ * are the resolved authentication data. The `context' is the libary's
+ * context sent to the get_auth_method client operation.
+ *
+ ***/
+typedef void (*SilcGetAuthMeth)(bool success,
+ SilcProtocolAuthMeth auth_meth,
+ const unsigned char *auth_data,
+ uint32 auth_data_len, void *context);
+
/****d* silcclient/SilcClientAPI/SilcClientMessageType
*
* NAME
void (*disconnect)(SilcClient client, SilcClientConnection conn);
/* Find authentication method and authentication data by hostname and
- port. The hostname may be IP address as well. The found authentication
- method and authentication data is returned to `auth_meth', `auth_data'
- and `auth_data_len'. The function returns TRUE if authentication method
- is found and FALSE if not. `conn' may be NULL. */
- int (*get_auth_method)(SilcClient client, SilcClientConnection conn,
- char *hostname, uint16 port,
- SilcProtocolAuthMeth *auth_meth,
- unsigned char **auth_data,
- uint32 *auth_data_len);
+ port. The hostname may be IP address as well. When the authentication
+ method has been resolved the `completion' callback with the found
+ authentication method and authentication data is called. The `conn'
+ may be NULL. */
+ void (*get_auth_method)(SilcClient client, SilcClientConnection conn,
+ char *hostname, uint16 port,
+ SilcGetAuthMeth completion, void *context);
/* Verifies received public key. The `conn_type' indicates which entity
(server, client etc.) has sent the public key. If user decides to trust
/* Rekey timeout in seconds. The client will perform rekey in this
time interval. If set to zero, the default value will be used. */
unsigned int rekey_secs;
+
+ /* Connection authentication method request timeout. If server does not
+ reply back the current authentication method when we've requested it
+ in this time interval we'll assume the reply will not come at all.
+ If set to zero, the default value (2 seconds) will be used. */
+ unsigned int connauth_request_secs;
} SilcClientParams;
/***/
SilcClientConnection conn,
char *message);
+
+/****f* silcclient/SilcClientAPI/SilcConnectionAuthRequest
+ *
+ * SYNOPSIS
+ *
+ * typedef void (*SilcConnectionAuthRequest)(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcAuthMethod auth_meth,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * Connection authentication method request callback. This is called
+ * by the client library after it has received the authentication method
+ * that the application requested by calling the function
+ * silc_client_request_authentication_method.
+ *
+ ***/
+typedef void (*SilcConnectionAuthRequest)(SilcClient client,
+ SilcClientConnection conn,
+ SilcAuthMethod auth_meth,
+ void *context);
+
+/****f* silcclient/SilcClientAPI/silc_client_request_authentication_method
+ *
+ * SYNOPSIS
+ *
+ * void
+ * silc_client_request_authentication_method(SilcClient client,
+ * SilcClientConnection conn,
+ * SilcConnectionAuthRequest
+ * callback,
+ * void *context);
+ *
+ * DESCRIPTION
+ *
+ * This function can be used to request the current authentication method
+ * from the server. This may be called when connecting to the server
+ * and the client library requests the authentication data from the
+ * application. If the application does not know the current authentication
+ * method it can request it from the server using this function.
+ * The `callback' with `context' will be called after the server has
+ * replied back with the current authentication method.
+ *
+ ***/
+void
+silc_client_request_authentication_method(SilcClient client,
+ SilcClientConnection conn,
+ SilcConnectionAuthRequest callback,
+ void *context);
+
#endif
{
uint32 prime_bits = keylen / 2;
SilcMPInt p, q;
+ bool found = FALSE;
printf("Generating RSA Public and Private keys, might take a while...\n");
silc_mp_init(&q);
/* Find p and q */
- retry_primes:
- printf("Finding p: ");
- silc_math_gen_prime(&p, prime_bits, TRUE);
-
- printf("\nFinding q: ");
- silc_math_gen_prime(&q, prime_bits, TRUE);
-
- if ((silc_mp_cmp(&p, &q)) == 0) {
- printf("\nFound equal primes, not good, retrying...\n");
- goto retry_primes;
+ while (!found) {
+ printf("Finding p: ");
+ silc_math_gen_prime(&p, prime_bits, TRUE);
+
+ printf("\nFinding q: ");
+ silc_math_gen_prime(&q, prime_bits, TRUE);
+
+ if ((silc_mp_cmp(&p, &q)) == 0)
+ printf("\nFound equal primes, not good, retrying...\n");
+ else
+ found = TRUE;
}
/* If p is smaller than q, switch them */
/* Set the primes */
silc_mp_set(&key->p, p);
silc_mp_set(&key->q, q);
-
+
/* Compute modulus, n = p * q */
silc_mp_mul(&key->n, &key->p, &key->q);
bool silc_math_gen_prime(SilcMPInt *prime, uint32 bits, bool verbose)
{
- unsigned char *numbuf;
+ unsigned char *numbuf = NULL;
uint32 i, b, k;
uint32 *spmods;
SilcMPInt r, base, tmp, tmp2, oprime;
SILC_LOG_DEBUG(("Generating new prime"));
- /* Get random number */
- numbuf = silc_rng_global_get_rn_string((bits / 8));
- if (!numbuf)
- return FALSE;
+ /* Get random number and assure that the first digit is not zero since
+ our conversion routines does not like the first digit being zero. */
+ do {
+ if (numbuf) {
+ memset(numbuf, 0, (bits / 8));
+ silc_free(numbuf);
+ }
+ numbuf = silc_rng_global_get_rn_string((bits / 8));
+ if (!numbuf)
+ return FALSE;
+ } while (numbuf[0] == '0');
/* Convert into MP and set the size */
- silc_mp_set_str(prime, numbuf, 16);
+ silc_mp_set_str(prime, numbuf, 16);
silc_mp_mod_2exp(prime, prime, bits);
/* Empty buffer */
void *silc_malloc(size_t size)
{
void *addr;
-#ifdef HAVE_MLOCK
addr = malloc(size);
assert(addr != NULL);
- mlock(addr, size);
return addr;
-#else
- addr = malloc(size);
- assert(addr != NULL);
- return addr;
-#endif
}
void *silc_calloc(size_t items, size_t size)
{
void *addr;
-#ifdef HAVE_MLOCK
addr = calloc(items, size);
assert(addr != NULL);
- mlock(addr, size);
return addr;
-#else
- addr = calloc(items, size);
- assert(addr != NULL);
- return addr;
-#endif
}
void *silc_realloc(void *ptr, size_t size)
{
void *addr;
-#ifdef HAVE_MLOCK
- addr = realloc(ptr, size);
- assert(addr != NULL);
- mlock(addr, size);
- return addr;
-#else
addr = realloc(ptr, size);
assert(addr != NULL);
return addr;
-#endif
}
void silc_free(void *ptr)
*
* SYNOPSIS
*
- * int silc_net_create_connection(int port, char *host);
+ * int silc_net_create_connection(const char *local_ip, int port,
+ * const char *host);
*
* DESCRIPTION
*
* Creates a connection (TCP/IP) to a remote host. Returns the connection
* socket or -1 on error. This blocks the process while trying to create
- * the connection.
+ * the connection. If the `local_ip' is not NULL then this will bind
+ * the `local_ip' address to a port before creating the connection. If
+ * it is NULL then this will directly create the connection.
*
***/
-int silc_net_create_connection(int port, char *host);
+int silc_net_create_connection(const char *localhost, int port,
+ const char *host);
/****f* silcutil/SilcNetAPI/silc_net_create_connection_async
*
* SYNOPSIS
*
- * int silc_net_create_connection_async(int port, char *host);
+ * int silc_net_create_connection_async(const char *local_ip, int port,
+ * const char *host);
*
* DESCRIPTION
*
* Creates a connection (TCP/IP) to a remote host. Returns the connection
* socket or -1 on error. This creates non-blocking socket hence the
* connection returns directly. To get the result of the connect() one
- * must select() the socket and read the result after it's ready.
+ * must select() the socket and read the result after it's ready. If the
+ * `local_ip' is not NULL then this will bind the `local_ip' address to
+ * a port before creating the connection. If it is NULL then this will
+ * directly create the connection.
*
***/
-int silc_net_create_connection_async(int port, char *host);
+int silc_net_create_connection_async(const char *local_ip, int port,
+ const char *host);
/****f* silcutil/SilcNetAPI/silc_net_close_connection
*
SILC_LOG_DEBUG(("Creating a new server listener"));
/* Create the socket */
- sock = socket(PF_INET, SOCK_STREAM, 0);
+ sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
return -1;
/* Set the socket information for bind() */
memset(&server, 0, sizeof(server));
- server.sin_family = PF_INET;
+ server.sin_family = AF_INET;
if (port)
server.sin_port = htons(port);
socket or -1 on error. This blocks the process while trying to create
the connection. */
-int silc_net_create_connection(int port, char *host)
+int silc_net_create_connection(const char *local_ip, int port,
+ const char *host)
{
int sock, rval;
struct hostent *dest;
/* Set socket information */
memset(&desthost, 0, sizeof(desthost));
desthost.sin_port = htons(port);
- desthost.sin_family = PF_INET;
+ desthost.sin_family = AF_INET;
memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
/* Create the connection socket */
- sock = socket(PF_INET, SOCK_STREAM, 0);
+ sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
return -1;
}
+ /* Bind to the local address if provided */
+ if (local_ip) {
+ struct sockaddr_in local;
+ int local_len = sizeof(local.sin_addr);
+
+ /* Set the socket information for bind() */
+ memset(&local, 0, sizeof(local));
+ local.sin_family = AF_INET;
+
+ /* Convert IP address to network byte order */
+ silc_net_addr2bin(local_ip, (unsigned char *)&local.sin_addr.s_addr,
+ local_len);
+
+ /* Bind the local socket */
+ rval = bind(sock, (struct sockaddr *)&local, sizeof(local));
+ if (rval < 0) {
+ SILC_LOG_ERROR(("Cannot connect to remote host: "
+ "cannot bind socket: %s", strerror(errno)));
+ return -1;
+ }
+ }
+
/* Connect to the host */
rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost));
if (rval < 0) {
connection returns directly. To get the result of the connect() one
must select() the socket and read the result after it's ready. */
-int silc_net_create_connection_async(int port, char *host)
+int silc_net_create_connection_async(const char *local_ip, int port,
+ const char *host)
{
int sock, rval;
struct hostent *dest;
/* Set socket information */
memset(&desthost, 0, sizeof(desthost));
desthost.sin_port = htons(port);
- desthost.sin_family = PF_INET;
+ desthost.sin_family = AF_INET;
memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
/* Create the connection socket */
- sock = socket(PF_INET, SOCK_STREAM, 0);
+ sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno)));
return -1;
}
+ /* Bind to the local address if provided */
+ if (local_ip) {
+ struct sockaddr_in local;
+ int local_len = sizeof(local.sin_addr);
+
+ /* Set the socket information for bind() */
+ memset(&local, 0, sizeof(local));
+ local.sin_family = AF_INET;
+
+ /* Convert IP address to network byte order */
+ silc_net_addr2bin(local_ip, (unsigned char *)&local.sin_addr.s_addr,
+ local_len);
+
+ /* Bind the local socket */
+ rval = bind(sock, (struct sockaddr *)&local, sizeof(local));
+ if (rval < 0) {
+ SILC_LOG_ERROR(("Cannot connect to remote host: "
+ "cannot bind socket: %s", strerror(errno)));
+ return -1;
+ }
+ }
+
/* Set the socket to non-blocking mode */
silc_net_set_socket_nonblock(sock);
socket or -1 on error. This blocks the process while trying to create
the connection. */
-int silc_net_create_connection(int port, char *host)
+int silc_net_create_connection(const char *local_ip, int port,
+ const char *host)
{
SOCKET sock;
int rval, err;
connection returns directly. To get the result of the connect() one
must select() the socket and read the result after it's ready. */
-int silc_net_create_connection_async(int port, char *host)
+int silc_net_create_connection_async(const char *local_ip, int port,
+ const char *host)
{
SOCKET sock;
int rval, err;
#
# prepare
#
-# Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+# Author: Pekka Riikonen <priikone@silcnet.org>
#
# Copyright (C) 2000 - 2001 Pekka Riikonen
#
dist_version=$version
fi
-echo "Preparing $distribution distribution version $version"
+echo "Preparing $distribution distribution version $version (package $dist_version)"
#
# Go though the subdirs and create the Makefile.ams from the