+ 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)
+{
+ char *data, *ptr;
+ int i = 0, j = 0, len = strlen(escaped_data);
+
+ data = silc_calloc(len, sizeof(char));
+
+ while (i < len) {
+ ptr = memchr(escaped_data + i, 1, len - i);
+ if (ptr) {
+ int inc = (ptr - escaped_data) - i;
+ memcpy(data + j, escaped_data + i, inc);
+ j += inc;
+ i += inc + 2;
+ data[j++] = *(ptr + 1) - 1;
+ } else {
+ memcpy(data + j, escaped_data + i, len - i);
+ j += (len - i);
+ break;
+ }
+ }
+
+ *length = j;
+ return data;
+}
+
+char * silc_escape_data(const char *data, SilcUInt32 len)
+{
+ char *escaped_data, *ptr, *ptr0, *ptr1;
+ int i = 0, j = 0;
+
+ escaped_data = silc_calloc(2 * len, sizeof(char));
+
+ while (i < len) {
+ ptr0 = memchr(data + i, 0, len - i);
+ ptr1 = memchr(data + i, 1, len - i);
+
+ ptr = (ptr0 < ptr1 ? (ptr0 ? ptr0 : ptr1) : (ptr1 ? ptr1 : ptr0));
+
+ if (ptr) {
+ int inc = (ptr - data) - i;
+ if (inc)
+ memcpy(escaped_data + j, data + i, inc);
+ j += inc;
+ i += inc;
+ escaped_data[j++] = 1;
+ escaped_data[j++] = *(data + i++) + 1;
+ } else {
+ memcpy(escaped_data + j, data + i, len - i);
+ j += (len - i);
+ break;
+ }
+ }