SilcBuffer silc_public_key_payload_encode(SilcPublicKey public_key) { SilcBuffer buffer; unsigned char *pk; SilcUInt32 pk_len; SilcPKCSType type; if (!public_key) return NULL; type = silc_pkcs_get_type(public_key); pk = silc_pkcs_public_key_encode(public_key, &pk_len); if (!pk) return NULL; buffer = silc_buffer_alloc_size(4 + pk_len); if (!buffer) { silc_free(pk); return NULL; } if (silc_buffer_format(buffer, SILC_STR_UI_SHORT(pk_len), SILC_STR_UI_SHORT(type), SILC_STR_DATA(pk, pk_len), SILC_STR_END) < 0) { silc_buffer_free(buffer); silc_free(pk); return NULL; } silc_free(pk); return buffer; }
SilcPrivateKey silc_acc_private_key(SilcAccelerator acc, SilcPrivateKey private_key) { SilcPrivateKey privkey; SilcAcceleratorPrivateKey acc_privkey; const SilcPKCSAlgorithm *alg; int i; if (!acc || !private_key) return NULL; SILC_LOG_DEBUG(("Accelerate private key %p with accelerator %s", private_key, acc->name)); if (!acc->pkcs) { SILC_LOG_ERROR(("Accelerator '%s' does not support private key " "acceleration", acc->name)); return NULL; } if (silc_acc_get_private_key(NULL, private_key)) { SILC_LOG_DEBUG(("Private key %p is already accelerated", private_key)); return NULL; } /* Check that accelerator supports this private key algorithm */ alg = silc_pkcs_get_algorithm(private_key); if (!alg) return NULL; for (i = 0; acc->pkcs[i].name; i++) { if ((!strcmp(acc->pkcs[i].name, alg->name) && !strcmp(acc->pkcs[i].scheme, alg->scheme)) || !strcmp(acc->pkcs[i].name, "any")) { alg = NULL; break; } } if (alg) { SILC_LOG_DEBUG(("Accelerator %s does not support %s/%s acceleration", acc->name, alg->name, alg->scheme)); return NULL; } privkey = silc_calloc(1, sizeof(*privkey)); if (!privkey) return NULL; /* Allocate PKCS operations */ privkey->pkcs = silc_calloc(1, sizeof(*privkey->pkcs)); if (!privkey->pkcs) { silc_free(privkey); return NULL; } *privkey->pkcs = silc_acc_pkcs; privkey->pkcs->type = silc_pkcs_get_type(private_key); privkey->alg = silc_pkcs_get_algorithm(private_key); /* Allocate accelerator public key */ acc_privkey = silc_calloc(1, sizeof(*acc_privkey)); if (!acc_privkey) { silc_free(privkey->pkcs); silc_free(privkey); return NULL; } acc_privkey->magic = SILC_ACC_KEY_MAGIC; acc_privkey->accelerated = private_key; acc_privkey->acc = acc; acc_privkey->pkcs_index = i; /* Accelerate the public key. Returns accelerator context. The import_public_key operation is used to accelerate the key. */ if (!acc->pkcs[i].import_private_key(&acc->pkcs[i], private_key, 0, &acc_privkey->context)) { SILC_LOG_ERROR(("Error accelerating private key with accelerator '%s'", acc->name)); silc_free(acc_privkey); silc_free(privkey->pkcs); silc_free(privkey); return NULL; } privkey->private_key = acc_privkey; SILC_LOG_DEBUG(("New accelerated private key %p", privkey)); return privkey; }
void silcpurple_show_public_key(SilcPurple sg, const char *name, SilcPublicKey public_key, GCallback callback, void *context) { SilcPublicKeyIdentifier ident; SilcSILCPublicKey silc_pubkey; char *fingerprint, *babbleprint; unsigned char *pk; SilcUInt32 pk_len, key_len = 0; GString *s; /* We support showing only SILC public keys for now */ if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) return; silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key); ident = &silc_pubkey->identifier; key_len = silc_pkcs_public_key_get_len(public_key); pk = silc_pkcs_public_key_encode(public_key, &pk_len); if (!pk) return; fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); if (!fingerprint || !babbleprint) return; s = g_string_new(""); if (ident->realname) /* Hint for translators: Please check the tabulator width here and in the next strings (short strings: 2 tabs, longer strings 1 tab, sum: 3 tabs or 24 characters) */ g_string_append_printf(s, _("Real Name: \t%s\n"), ident->realname); if (ident->username) g_string_append_printf(s, _("User Name: \t%s\n"), ident->username); if (ident->email) g_string_append_printf(s, _("Email: \t\t%s\n"), ident->email); if (ident->host) g_string_append_printf(s, _("Host Name: \t%s\n"), ident->host); if (ident->org) g_string_append_printf(s, _("Organization: \t%s\n"), ident->org); if (ident->country) g_string_append_printf(s, _("Country: \t%s\n"), ident->country); g_string_append_printf(s, _("Algorithm: \t%s\n"), silc_pubkey->pkcs->name); g_string_append_printf(s, _("Key Length: \t%d bits\n"), (int)key_len); if (ident->version) g_string_append_printf(s, _("Version: \t%s\n"), ident->version); g_string_append_printf(s, "\n"); g_string_append_printf(s, _("Public Key Fingerprint:\n%s\n\n"), fingerprint); g_string_append_printf(s, _("Public Key Babbleprint:\n%s"), babbleprint); purple_request_action(sg->gc, _("Public Key Information"), _("Public Key Information"), s->str, 0, purple_connection_get_account(sg->gc), NULL, NULL, context, 1, _("Close"), callback); g_string_free(s, TRUE); silc_free(fingerprint); silc_free(babbleprint); silc_free(pk); }
void silcpurple_verify_public_key(SilcClient client, SilcClientConnection conn, const char *name, SilcConnectionType conn_type, SilcPublicKey public_key, SilcVerifyPublicKey completion, void *context) { PurpleConnection *gc = client->application; int i; char file[256], filename[256], filename2[256], *ipf, *hostf = NULL; char *fingerprint, *babbleprint; struct passwd *pw; struct stat st; char *entity = ((conn_type == SILC_CONN_SERVER || conn_type == SILC_CONN_ROUTER) ? "server" : "client"); PublicKeyVerify verify; const char *ip, *hostname; SilcUInt16 port; unsigned char *pk; SilcUInt32 pk_len; if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) { purple_notify_error(gc, _("Verify Public Key"), _("Unsupported public key type"), NULL); if (completion) completion(FALSE, context); return; } pw = getpwuid(getuid()); if (!pw) { if (completion) completion(FALSE, context); return; } memset(filename, 0, sizeof(filename)); memset(filename2, 0, sizeof(filename2)); memset(file, 0, sizeof(file)); silc_socket_stream_get_info(silc_packet_stream_get_stream(conn->stream), NULL, &hostname, &ip, &port); pk = silc_pkcs_public_key_encode(public_key, &pk_len); if (!pk) { if (completion) completion(FALSE, context); return; } if (conn_type == SILC_CONN_SERVER || conn_type == SILC_CONN_ROUTER) { if (!name) { g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, ip, port); g_snprintf(filename, sizeof(filename) - 1, "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", silcpurple_silcdir(), entity, file); g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, hostname, port); g_snprintf(filename2, sizeof(filename2) - 1, "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", silcpurple_silcdir(), entity, file); ipf = filename; hostf = filename2; } else { g_snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, name, port); g_snprintf(filename, sizeof(filename) - 1, "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", silcpurple_silcdir(), entity, file); ipf = filename; } } 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] = '_'; g_snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint); g_snprintf(filename, sizeof(filename) - 1, "%s" G_DIR_SEPARATOR_S "%skeys" G_DIR_SEPARATOR_S "%s", silcpurple_silcdir(), entity, file); silc_free(fingerprint); ipf = filename; } verify = silc_calloc(1, sizeof(*verify)); if (!verify) return; verify->client = client; verify->conn = conn; verify->filename = g_strdup(ipf); verify->entity = g_strdup(entity); verify->entity_name = (conn_type != SILC_CONN_CLIENT ? (name ? g_strdup(name) : g_strdup(hostname)) : NULL); verify->public_key = silc_pkcs_public_key_copy(public_key); verify->completion = completion; verify->context = context; fingerprint = verify->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); babbleprint = verify->babbleprint = silc_hash_babbleprint(NULL, pk, pk_len); /* Check whether this key already exists */ if (g_stat(ipf, &st) < 0 && (!hostf || g_stat(hostf, &st) < 0)) { /* Key does not exist, ask user to verify the key and save it */ silcpurple_verify_ask(name ? name : entity, fingerprint, babbleprint, verify); return; } else { /* The key already exists, verify it. */ SilcPublicKey public_key; unsigned char *encpk; SilcUInt32 encpk_len; /* Load the key file, try for both IP filename and hostname filename */ if (!silc_pkcs_load_public_key(ipf, &public_key) && (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key)))) { silcpurple_verify_ask(name ? name : entity, fingerprint, babbleprint, verify); return; } /* Encode the key data */ encpk = silc_pkcs_public_key_encode(public_key, &encpk_len); if (!encpk) { silcpurple_verify_ask(name ? name : entity, fingerprint, babbleprint, verify); return; } /* Compare the keys */ if (memcmp(encpk, pk, encpk_len)) { /* Ask user to verify the key and save it */ verify->changed = TRUE; silcpurple_verify_ask(name ? name : entity, fingerprint, babbleprint, verify); return; } /* Local copy matched */ if (completion) completion(TRUE, context); g_free(verify->filename); g_free(verify->entity); g_free(verify->entity_name); silc_free(verify->fingerprint); silc_free(verify->babbleprint); silc_pkcs_public_key_free(verify->public_key); silc_free(verify); } }