+static bool
+silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
+ SilcSocketType conn_type, unsigned char *pk,
+ SilcUInt32 pk_len, SilcSKEPKType pk_type)
+{
+ int i;
+ char file[256], filename[256], *fingerprint;
+ struct passwd *pw;
+ struct stat st;
+ char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
+ conn_type == SILC_SOCKET_TYPE_ROUTER) ?
+ "server" : "client");
+
+ if (pk_type != SILC_SKE_PK_TYPE_SILC) {
+ silc_say(client, conn, "We don't support %s public key type %d",
+ entity, pk_type);
+ return FALSE;
+ }
+
+ pw = getpwuid(getuid());
+ if (!pw)
+ return FALSE;
+
+ memset(filename, 0, sizeof(filename));
+ memset(file, 0, sizeof(file));
+
+ if (conn_type == SILC_SOCKET_TYPE_SERVER ||
+ conn_type == SILC_SOCKET_TYPE_ROUTER) {
+ snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
+ conn->sock->hostname, conn->sock->port);
+ snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
+ pw->pw_dir, entity, file);
+ } else {
+ /* Replace all whitespaces with `_'. */
+ fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+ for (i = 0; i < strlen(fingerprint); i++)
+ if (fingerprint[i] == ' ')
+ fingerprint[i] = '_';
+
+ snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
+ snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s",
+ pw->pw_dir, entity, file);
+ silc_free(fingerprint);
+ }
+
+ /* Take fingerprint of the public key */
+ fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+
+ /* Check whether this key already exists */
+ if (stat(filename, &st) < 0) {
+
+ silc_say(client, conn, "Received %s public key", entity);
+ silc_say(client, conn, "Fingerprint for the %s key is", entity);
+ silc_say(client, conn, "%s", fingerprint);
+
+ /* Ask user to verify the key and save it */
+ if (silc_client_ask_yes_no(client,
+ "Would you like to accept the key (y/n)? "))
+ {
+ /* Save the key for future checking */
+ silc_pkcs_save_public_key_data(filename, pk, pk_len,
+ SILC_PKCS_FILE_PEM);
+ silc_free(fingerprint);
+ return TRUE;
+ }
+ } else {
+ /* The key already exists, verify it. */
+ SilcPublicKey public_key;
+ unsigned char *encpk;
+ SilcUInt32 encpk_len;
+
+ /* Load the key file */
+ if (!silc_pkcs_load_public_key(filename, &public_key,
+ SILC_PKCS_FILE_PEM))
+ if (!silc_pkcs_load_public_key(filename, &public_key,
+ SILC_PKCS_FILE_BIN)) {
+ silc_say(client, conn, "Received %s public key", entity);
+ silc_say(client, conn, "Fingerprint for the %s key is", entity);
+ silc_say(client, conn, "%s", fingerprint);
+ silc_say(client, conn, "Could not load your local copy of the %s key",
+ entity);
+ if (silc_client_ask_yes_no(client,
+ "Would you like to accept the key anyway (y/n)? "))
+ {
+ /* Save the key for future checking */
+ unlink(filename);
+ silc_pkcs_save_public_key_data(filename, pk, pk_len,
+ SILC_PKCS_FILE_PEM);
+ silc_free(fingerprint);
+ return TRUE;
+ }
+
+ silc_free(fingerprint);
+ return FALSE;
+ }
+
+ /* Encode the key data */
+ encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
+ if (!encpk) {
+ silc_say(client, conn, "Received %s public key", entity);
+ silc_say(client, conn, "Fingerprint for the %s key is", entity);
+ silc_say(client, conn, "%s", fingerprint);
+ silc_say(client, conn, "Your local copy of the %s key is malformed",
+ entity);
+ if (silc_client_ask_yes_no(client,
+ "Would you like to accept the key anyway (y/n)? "))
+ {
+ /* Save the key for future checking */
+ unlink(filename);
+ silc_pkcs_save_public_key_data(filename, pk, pk_len,
+ SILC_PKCS_FILE_PEM);
+ silc_free(fingerprint);
+ return TRUE;
+ }
+
+ silc_free(fingerprint);
+ return FALSE;
+ }
+
+ if (memcmp(encpk, pk, encpk_len)) {
+ silc_say(client, conn, "Received %s public key", entity);
+ silc_say(client, conn, "Fingerprint for the %s key is", entity);
+ silc_say(client, conn, "%s", fingerprint);
+ silc_say(client, conn, "%s key does not match with your local copy",
+ entity);
+ silc_say(client, conn,
+ "It is possible that the key has expired or changed");
+ silc_say(client, conn, "It is also possible that some one is performing "
+ "man-in-the-middle attack");
+
+ /* Ask user to verify the key and save it */
+ if (silc_client_ask_yes_no(client,
+ "Would you like to accept the key anyway (y/n)? "))
+ {
+ /* Save the key for future checking */
+ unlink(filename);
+ silc_pkcs_save_public_key_data(filename, pk, pk_len,
+ SILC_PKCS_FILE_PEM);
+ silc_free(fingerprint);
+ return TRUE;
+ }
+
+ silc_say(client, conn, "Will not accept the %s key", entity);
+ silc_free(fingerprint);
+ return FALSE;
+ }
+
+ /* Local copy matched */
+ silc_free(fingerprint);
+ return TRUE;
+ }
+
+ silc_say(client, conn, "Will not accept the %s key", entity);
+ silc_free(fingerprint);
+ return FALSE;
+}
+
+void silc_say(SilcClient client, SilcClientConnection conn,
+ char *msg, ...)
+{
+ va_list vp;
+ char message[2048];
+ SilcClientInternal app = (SilcClientInternal)client->application;
+
+ memset(message, 0, sizeof(message));
+ strncat(message, "\n*** ", 5);
+
+ va_start(vp, msg);
+ vsprintf(message + 5, msg, vp);
+ va_end(vp);
+
+ /* Print the message */
+ silc_print_to_window(app->screen->output_win[0], message);
+}
+