+/* try to verify a message using locally stored public key data */
+int verify_message_signature(SilcClientEntry sender,
+ SilcMessageSignedPayload sig,
+ SilcMessagePayload message)
+{
+ SilcPublicKey pk;
+ char file[256], filename[256];
+ char *fingerprint, *fingerprint2;
+ unsigned char *pk_data;
+ SilcUInt32 pk_datalen;
+ struct stat st;
+ int ret = SILC_MSG_SIGNED_VERIFIED, i;
+
+ if (sig == NULL)
+ return SILC_MSG_SIGNED_UNKNOWN;
+
+ /* get public key from the signature payload and compare it with the
+ one stored in the client entry */
+ pk = silc_message_signed_get_public_key(sig, &pk_data, &pk_datalen);
+
+ if (pk != NULL) {
+ fingerprint = silc_hash_fingerprint(NULL, pk_data, pk_datalen);
+
+ if (sender->fingerprint) {
+ fingerprint2 = silc_fingerprint(sender->fingerprint,
+ sender->fingerprint_len);
+ if (strcmp(fingerprint, fingerprint2)) {
+ /* since the public key differs from the senders public key, the
+ verification _failed_ */
+ silc_pkcs_public_key_free(pk);
+ silc_free(fingerprint);
+ ret = SILC_MSG_SIGNED_UNKNOWN;
+ }
+ silc_free(fingerprint2);
+ }
+ } else if (sender->fingerprint)
+ fingerprint = silc_fingerprint(sender->fingerprint,
+ sender->fingerprint_len);
+ else
+ /* no idea, who or what signed that message ... */
+ return SILC_MSG_SIGNED_UNKNOWN;
+
+ /* search our local client key cache */
+ for (i = 0; i < strlen(fingerprint); i++)
+ if (fingerprint[i] == ' ')
+ fingerprint[i] = '_';
+
+ snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
+ snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
+ get_irssi_dir(), file);
+ silc_free(fingerprint);
+
+ if (stat(filename, &st) < 0)
+ /* we don't have the public key cached ... use the one from the sig */
+ ret = SILC_MSG_SIGNED_UNKNOWN;
+ else {
+ SilcPublicKey cached_pk=NULL;
+
+ /* try to load the file */
+ if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
+ !silc_pkcs_load_public_key(filename, &cached_pk,
+ SILC_PKCS_FILE_BIN)) {
+ printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+ SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
+ if (pk == NULL)
+ return SILC_MSG_SIGNED_UNKNOWN;
+ else
+ ret = SILC_MSG_SIGNED_UNKNOWN;
+ }
+
+ if (cached_pk) {
+ if (pk)
+ silc_pkcs_public_key_free(pk);
+ pk = cached_pk;
+ }
+ }
+
+ /* the public key is now in pk, our "level of trust" in ret */
+ if ((pk) && silc_message_signed_verify(sig, message, pk,
+ silc_client->sha1hash)!= SILC_AUTH_OK)
+ ret = SILC_MSG_SIGNED_FAILED;
+
+ if (pk)
+ silc_pkcs_public_key_free(pk);
+
+ return ret;
+}
+
+char * silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
+{
+ SilcUInt32 ctr, dest=0;
+ char *data;
+
+ data = silc_calloc(strlen(escaped_data), sizeof(char));
+
+ for (ctr = 0; ctr < strlen(escaped_data); ctr++)
+ if (escaped_data[ctr] == 1)
+ data[dest++] = escaped_data[++ctr] - 1;
+ else
+ data[dest++] = escaped_data[ctr];
+
+ *length = dest;
+ return data;
+}
+
+char * silc_escape_data(const char *data, SilcUInt32 len)
+{
+ char *escaped_data;
+ SilcUInt32 ctr, zeros=0;
+
+ for (ctr = 0; ctr < len; ctr++)
+ if (data[ctr] == 0 || data[ctr] == 1)
+ zeros++;
+
+ escaped_data = silc_calloc(zeros + len, sizeof(char));
+
+ zeros=0;
+ for (ctr = 0; ctr < len; ctr++)
+ switch (data[ctr]) {
+ case 0:
+ escaped_data[zeros++] = 1;
+ escaped_data[zeros++] = 1;
+ break;
+
+ case 1:
+ escaped_data[zeros++] = 1;
+ escaped_data[zeros++] = 2;
+ break;
+
+ default:
+ escaped_data[zeros++] = data[ctr];
+ }
+
+ return escaped_data;
+}
+
+void silc_emit_mime_sig(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
+ const char *data, SilcUInt32 data_len,
+ const char *encoding, const char *type, const char *nick)
+{
+ char *escaped_data;
+
+ escaped_data = silc_escape_data(data, data_len);
+
+ signal_emit("mime", 6, server, channel, escaped_data, encoding, type, nick);
+
+ silc_free(escaped_data);
+}
+
+
+/* Message for a channel. The `sender' is the nickname of the sender