/* silcmessage.c Author: Pekka Riikonen Copyright (C) 1997 - 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ /* Implementation of the Message Payload used as channel messages and private messages. */ /* $Id$ */ #include "silc.h" #include "silcmessage.h" /*************************** Types and definitions **************************/ /* Calculates padding length for message payload */ #define SILC_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16)) /* Header length plus maximum padding length */ #define SILC_MESSAGE_HLEN 6 + 16 /* Maximum message length */ #define SILC_MESSAGE_MAX_LEN SILC_PACKET_MAX_LEN - SILC_MESSAGE_HLEN - 16 /* Payload encoding context */ typedef struct { SilcBuffer buffer; SilcBuffer sign; SilcStack stack; SilcMessagePayloadEncoded encoded; void *context; SilcMessageFlags flags; SilcPublicKey public_key; SilcPrivateKey private_key; SilcRng rng; SilcHash hash; SilcCipher cipher; SilcHmac hmac; unsigned char *iv; unsigned char *pk; SilcUInt16 pk_len; SilcUInt16 iv_len; SilcUInt16 payload_len; SilcID sid; SilcID rid; } SilcMessageEncode; /************************* Static utility functions *************************/ static void silc_message_payload_encode_final(SilcBuffer buffer, SilcMessageFlags flags, SilcCipher cipher, SilcHmac hmac, unsigned char *iv, SilcUInt32 iv_len, SilcUInt32 payload_len, SilcID *sender_id, SilcID *receiver_id, SilcStack stack, SilcBuffer signature, SilcMessagePayloadEncoded encoded, void *context); /* Returns the data length that fits to the packet. If data length is too big it will be truncated to fit to the payload. */ static inline SilcUInt32 silc_message_payload_datalen(SilcUInt32 data_len, SilcUInt32 header_len, SilcUInt32 flags, SilcPublicKey public_key, SilcPrivateKey private_key) { SilcUInt32 pklen = (flags & SILC_MESSAGE_FLAG_SIGNED && public_key ? silc_pkcs_public_key_get_len(public_key) : 0); SilcUInt32 prlen = (flags & SILC_MESSAGE_FLAG_SIGNED ? silc_pkcs_private_key_get_len(private_key) / 8 : 0); SilcUInt32 dlen = data_len + SILC_MESSAGE_HLEN + header_len + pklen + prlen; if (silc_unlikely(dlen > SILC_MESSAGE_MAX_LEN)) data_len -= (dlen - SILC_MESSAGE_MAX_LEN); return data_len; } /* Free signed payload */ static void silc_message_signed_payload_free(SilcMessageSignedPayload sig) { if (sig->sign_data) { memset(sig->sign_data, 0, sig->sign_len); silc_free(sig->sign_data); } silc_free(sig->pk_data); } /* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */ static SilcBool silc_message_signed_payload_parse(const unsigned char *data, SilcUInt32 data_len, SilcMessageSignedPayload sig) { SilcBufferStruct buffer; int ret; SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload")); SILC_LOG_HEXDUMP(("sig payload"), (unsigned char *)data, data_len); silc_buffer_set(&buffer, (unsigned char *)data, data_len); /* Parse the payload */ ret = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&sig->pk_len), SILC_STR_UI_SHORT(&sig->pk_type), SILC_STR_END); if (ret == -1 || sig->pk_len > data_len - 4) { SILC_LOG_DEBUG(("Malformed public key in SILC_MESSAGE_FLAG_SIGNED " "Payload")); return FALSE; } silc_buffer_pull(&buffer, 4); ret = silc_buffer_unformat(&buffer, SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data, sig->pk_len), SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data, &sig->sign_len), SILC_STR_END); if (ret == -1 || sig->sign_len > silc_buffer_len(&buffer) - sig->pk_len - 2) { silc_message_signed_payload_free(sig); SILC_LOG_DEBUG(("Malformed SILC_MESSAGE_FLAG_SIGNED Payload")); return FALSE; } silc_buffer_push(&buffer, 4); /* Signature must be provided */ if (sig->sign_len < 1) { SILC_LOG_DEBUG(("Malformed signature in SILC_MESSAGE_SIGNED_PAYLOAD " "Payload")); silc_message_signed_payload_free(sig); return FALSE; } return TRUE; } /* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */ static SilcBuffer silc_message_signed_encode_data(SilcStack stack, const unsigned char *message_payload, SilcUInt32 message_payload_len, unsigned char *pk, SilcUInt32 pk_len, SilcUInt32 pk_type) { SilcBuffer sign; sign = silc_buffer_salloc_size(stack, message_payload_len + 4 + pk_len); if (!sign) return NULL; silc_buffer_sformat(stack, sign, SILC_STR_DATA(message_payload, message_payload_len), SILC_STR_UI_SHORT(pk_len), SILC_STR_UI_SHORT(pk_type), SILC_STR_END); if (pk && pk_len) { silc_buffer_pull(sign, message_payload_len + 4); silc_buffer_sformat(stack, sign, SILC_STR_UI_XNSTRING(pk, pk_len), SILC_STR_END); silc_buffer_push(sign, message_payload_len + 4); } return sign; } /* Signature callback */ void silc_message_signed_payload_encode_cb(SilcBool success, const unsigned char *signature, SilcUInt32 signature_len, void *context) { SilcMessageEncode *e = context; SilcPKCSType pk_type; SilcStack stack = e->stack; SilcBuffer buffer, payload; SilcMessageFlags flags; SilcCipher cipher; SilcHmac hmac; unsigned char *iv; SilcUInt32 iv_len, payload_len; SilcID *sid, *rid; SilcMessagePayloadEncoded encoded; void *encoded_context; if (!success) { e->encoded(NULL, e->context); silc_buffer_sfree(stack, e->sign); silc_sfree(stack, e->pk); silc_sfree(stack, e); silc_stack_free(stack); return; } pk_type = silc_pkcs_get_type(e->private_key); /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */ buffer = silc_buffer_salloc_size(stack, 4 + e->pk_len + 2 + signature_len); if (!buffer) { e->encoded(NULL, e->context); silc_buffer_sfree(stack, e->sign); silc_sfree(stack, e->pk); silc_sfree(stack, e); silc_stack_free(stack); return; } silc_buffer_sformat(stack, buffer, SILC_STR_UI_SHORT(e->pk_len), SILC_STR_UI_SHORT(pk_type), SILC_STR_END); if (e->pk_len && e->pk) { silc_buffer_pull(buffer, 4); silc_buffer_sformat(stack, buffer, SILC_STR_DATA(e->pk, e->pk_len), SILC_STR_END); silc_buffer_push(buffer, 4); } silc_buffer_pull(buffer, 4 + e->pk_len); silc_buffer_sformat(stack, buffer, SILC_STR_UI_SHORT(signature_len), SILC_STR_DATA(signature, signature_len), SILC_STR_END); silc_buffer_push(buffer, 4 + e->pk_len); SILC_LOG_HEXDUMP(("SIG payload"), buffer->data, silc_buffer_len(buffer)); payload = e->buffer; flags = e->flags; cipher = e->cipher; hmac = e->hmac; iv = e->iv; iv_len = e->iv_len; payload_len = e->payload_len; sid = &e->sid; rid = &e->rid; encoded = e->encoded; encoded_context = e->context; silc_sfree(stack, e->pk); silc_buffer_sfree(stack, e->sign); silc_sfree(stack, e); /* Finalize message payload encoding */ silc_message_payload_encode_final(payload, flags, cipher, hmac, iv, iv_len, payload_len, sid, rid, stack, buffer, encoded, encoded_context); } /* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital signature. */ static SilcAsyncOperation silc_message_signed_payload_encode(SilcBuffer payload, SilcMessageEncode *e) { SilcAsyncOperation op; SilcBuffer sign; unsigned char *pk = NULL; SilcUInt32 pk_len = 0; SilcUInt16 pk_type; SilcStack stack = e->stack; SilcRng rng = e->rng; SilcHash hash = e->hash; SilcPublicKey public_key = e->public_key; SilcPrivateKey private_key = e->private_key; unsigned char *message_payload; SilcUInt16 message_payload_len; message_payload = payload->head; message_payload_len = silc_buffer_headlen(payload); if (!message_payload || !message_payload_len || !private_key || !hash) { e->encoded(NULL, e->context); silc_sfree(stack, e); silc_stack_free(stack); return NULL; } if (public_key) { e->pk = pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len); if (!pk) { e->encoded(NULL, e->context); silc_sfree(stack, e); silc_stack_free(stack); return NULL; } e->pk_len = pk_len; } pk_type = silc_pkcs_get_type(private_key); /* Encode the data to be signed */ e->sign = sign = silc_message_signed_encode_data(stack, message_payload, message_payload_len, pk, pk_len, pk_type); if (!sign) { e->encoded(NULL, e->context); silc_sfree(stack, pk); silc_sfree(stack, e); silc_stack_free(stack); return NULL; } /* Compute signature */ op = silc_pkcs_sign_async(private_key, sign->data, silc_buffer_len(sign), TRUE, hash, rng, silc_message_signed_payload_encode_cb, e); return op; } /***************************** Payload parsing ******************************/ /* Decrypts the Message Payload. The `data' is the actual Message Payload. */ SilcBool silc_message_payload_decrypt(unsigned char *data, size_t data_len, SilcBool private_message, SilcBool static_key, SilcCipher cipher, SilcHmac hmac, unsigned char *sender_id, SilcUInt32 sender_id_len, unsigned char *receiver_id, SilcUInt32 receiver_id_len, SilcBool check_mac) { SilcUInt32 mac_len, iv_len = 0, block_len; SilcUInt16 len, totlen; unsigned char mac[32], *ivp; mac_len = silc_hmac_len(hmac); block_len = silc_cipher_get_block_len(cipher); /* IV is present for all channel messages, and private messages when static key (pre-shared key) is used. */ if (!private_message || (private_message && static_key)) iv_len = block_len; if (silc_unlikely(data_len < (mac_len + iv_len + block_len))) return FALSE; if (silc_likely(check_mac)) { /* Check the MAC of the message */ SILC_LOG_DEBUG(("Checking message MAC")); silc_hmac_init(hmac); silc_hmac_update(hmac, data, data_len - mac_len); silc_hmac_update(hmac, sender_id, sender_id_len); silc_hmac_update(hmac, receiver_id, receiver_id_len); silc_hmac_final(hmac, mac, &mac_len); if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) { /* Check for old style (version 1.2) message MAC. Remove this check at some point. */ silc_hmac_init(hmac); silc_hmac_update(hmac, data, data_len - mac_len); silc_hmac_final(hmac, mac, &mac_len); if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) { SILC_LOG_DEBUG(("Message MAC does not match")); return FALSE; } } SILC_LOG_DEBUG(("MAC is Ok")); } /* Decrypt first only one block to get the header and then rest of the data. This is done because there might be unencrypted data at the end and we don't know the encrypted length yet. */ /* Get pointer to the IV */ ivp = (iv_len ? data + (data_len - iv_len - mac_len) : silc_cipher_get_iv(cipher)); /* Decrypt block */ if (silc_unlikely(!silc_cipher_decrypt(cipher, data, data, block_len, ivp))) { SILC_ASSERT(FALSE); return FALSE; } /* Get the payload length and decrypt rest */ totlen = 2; SILC_GET16_MSB(len, data + totlen); totlen += 2 + len; if (silc_unlikely(totlen + iv_len + mac_len + 2 > data_len)) return FALSE; totlen += 2; if (totlen >= block_len) if (silc_unlikely(!silc_cipher_decrypt(cipher, data + block_len, data + block_len, (totlen - block_len) + SILC_MESSAGE_PAD(totlen), ivp))) { SILC_ASSERT(FALSE); return FALSE; } return TRUE; } /* Parses Message Payload returning new payload structure. This also decrypts it and checks the MAC. */ SilcMessagePayload silc_message_payload_parse(unsigned char *payload, SilcUInt32 payload_len, SilcBool private_message, SilcBool static_key, SilcCipher cipher, SilcHmac hmac, unsigned char *sender_id, SilcUInt32 sender_id_len, unsigned char *receiver_id, SilcUInt32 receiver_id_len, SilcStack stack, SilcBool no_allocation, SilcMessagePayload message) { SilcBufferStruct buffer; SilcMessagePayload newp = NULL; int ret; SilcUInt32 mac_len = 0, iv_len = 0; SILC_LOG_DEBUG(("Parsing Message Payload")); silc_buffer_set(&buffer, payload, payload_len); /* Decrypt the payload */ if (silc_likely(cipher)) { ret = silc_message_payload_decrypt(buffer.data, silc_buffer_len(&buffer), private_message, static_key, cipher, hmac, sender_id, sender_id_len, receiver_id, receiver_id_len, TRUE); if (silc_unlikely(ret == FALSE)) return NULL; } if (silc_likely(hmac)) mac_len = silc_hmac_len(hmac); /* IV is present for all channel messages, and private messages when static key (pre-shared key) is used. */ if (cipher && (!private_message || (private_message && static_key))) iv_len = silc_cipher_get_block_len(cipher); if (!message) { newp = message = silc_calloc(1, sizeof(*newp)); if (silc_unlikely(!newp)) return NULL; } memset(message, 0, sizeof(*message)); message->allocated = (stack || no_allocation ? FALSE : TRUE); /* Parse the Message Payload. */ if (!no_allocation) ret = silc_buffer_sunformat(stack, &buffer, SILC_STR_UI_SHORT(&message->flags), SILC_STR_UI16_NSTRING_ALLOC(&message->data, &message->data_len), SILC_STR_UI16_NSTRING_ALLOC(&message->pad, &message->pad_len), SILC_STR_END); else ret = silc_buffer_unformat(&buffer, SILC_STR_UI_SHORT(&message->flags), SILC_STR_UI16_NSTRING(&message->data, &message->data_len), SILC_STR_UI16_NSTRING(&message->pad, &message->pad_len), SILC_STR_END); if (silc_unlikely(ret == -1)) goto err; if (silc_unlikely((message->data_len > silc_buffer_len(&buffer) - 6 - mac_len - iv_len) || (message->pad_len + message->data_len > silc_buffer_len(&buffer) - 6 - mac_len - iv_len))) { SILC_LOG_ERROR(("Incorrect Message Payload in packet")); goto err; } /* Parse Signed Message Payload if provided */ if (message->flags & SILC_MESSAGE_FLAG_SIGNED && message->data_len + message->pad_len + 6 + mac_len + iv_len < silc_buffer_len(&buffer)) { if (!silc_message_signed_payload_parse(buffer.data + 6 + message->data_len + message->pad_len, silc_buffer_len(&buffer) - iv_len - mac_len - 6 - message->data_len - message->pad_len, &message->sig)) goto err; } /* Parse MAC from the payload */ if (mac_len) message->mac = buffer.data + (silc_buffer_len(&buffer) - mac_len); return newp; err: if (newp) silc_message_payload_free(newp); return NULL; } /***************************** Payload encoding *****************************/ /* This function is used to encrypt the Messsage Payload which is the `data' and `data_len'. This is used internally by the Message Payload encoding routines but application may call this too if needed. The `true_len' is the data length which is used to create MAC out of. */ SilcBool silc_message_payload_encrypt(unsigned char *data, SilcUInt32 data_len, SilcUInt32 true_len, unsigned char *iv, SilcID *sender_id, SilcID *receiver_id, SilcCipher cipher, SilcHmac hmac) { unsigned char sid[32], rid[32]; SilcUInt32 sid_len = 0, rid_len = 0; /* Encrypt payload of the packet */ if (silc_unlikely(!silc_cipher_encrypt(cipher, data, data, data_len, iv))) return FALSE; /* Encode IDs */ silc_id_id2str(&sender_id->u.client_id, SILC_ID_CLIENT, sid, sizeof(sid), &sid_len); if (receiver_id->type == SILC_ID_CLIENT) silc_id_id2str(&receiver_id->u.client_id, SILC_ID_CLIENT, rid, sizeof(rid), &rid_len); else if (receiver_id->type == SILC_ID_CHANNEL) silc_id_id2str(&receiver_id->u.channel_id, SILC_ID_CHANNEL, rid, sizeof(rid), &rid_len); /* Compute the MAC of the encrypted message data */ silc_hmac_init(hmac); silc_hmac_update(hmac, data, true_len); silc_hmac_update(hmac, sid, sid_len); silc_hmac_update(hmac, rid, rid_len); silc_hmac_final(hmac, data + true_len, NULL); return TRUE; } /* Encrypt message payload */ static int silc_message_payload_encode_encrypt(SilcStack stack, SilcBuffer buffer, void *value, void *context) { SilcMessageEncode *e = context; SilcUInt32 mac_len; if (!e->cipher || !e->hmac) return 0; mac_len = silc_hmac_len(e->hmac); if (silc_unlikely(!silc_buffer_enlarge(buffer, mac_len))) return -1; if (silc_unlikely(!silc_message_payload_encrypt(buffer->head, e->payload_len, silc_buffer_headlen(buffer), e->iv, &e->sid, &e->rid, e->cipher, e->hmac))) return -1; return mac_len; } /* Finalize message payload encoding */ static void silc_message_payload_encode_final(SilcBuffer buffer, SilcMessageFlags flags, SilcCipher cipher, SilcHmac hmac, unsigned char *iv, SilcUInt32 iv_len, SilcUInt32 payload_len, SilcID *sender_id, SilcID *receiver_id, SilcStack stack, SilcBuffer signature, SilcMessagePayloadEncoded encoded, void *context) { SilcMessageEncode e; e.flags = flags; e.cipher = cipher; e.hmac = hmac; e.sid = *sender_id; e.rid = *receiver_id; e.iv = iv; e.payload_len = payload_len; /* Encrypt */ if (silc_buffer_format(buffer, SILC_STR_DATA(signature ? silc_buffer_data(signature) : NULL, signature ? silc_buffer_len(signature) : 0), SILC_STR_DATA(iv, iv_len), SILC_STR_FUNC(silc_message_payload_encode_encrypt, NULL, &e), SILC_STR_END) < 0) { silc_buffer_sfree(stack, buffer); encoded(NULL, context); return; } /* Deliver message payload */ silc_buffer_start(buffer); encoded(buffer, context); silc_buffer_sfree(stack, buffer); silc_buffer_sfree(stack, signature); silc_stack_free(stack); } /* Encodes Message Payload into a buffer and returns it. */ SilcAsyncOperation silc_message_payload_encode(SilcMessageFlags flags, const unsigned char *data, SilcUInt32 data_len, SilcBool generate_iv, SilcBool private_message, SilcCipher cipher, SilcHmac hmac, SilcRng rng, SilcPublicKey public_key, SilcPrivateKey private_key, SilcHash hash, SilcID *sender_id, SilcID *receiver_id, SilcStack stack, SilcMessagePayloadEncoded encoded, void *context) { SilcUInt32 pad_len = 0, mac_len = 0, iv_len = 0; unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE]; SilcBuffer buffer; int i; SILC_LOG_DEBUG(("Encoding Message Payload")); if (silc_unlikely(!data_len)) { encoded(NULL, context); return NULL; } if (silc_unlikely(!private_message && (!cipher || !hmac))) { encoded(NULL, context); return NULL; } stack = silc_stack_alloc(0, stack ? stack : silc_crypto_stack()); buffer = silc_buffer_salloc(stack, 0); if (silc_unlikely(!buffer)) { encoded(NULL, context); silc_stack_free(stack); return NULL; } /* For channel messages IV is always generated */ if (!private_message && !generate_iv) generate_iv = TRUE; /* Generate IV */ if (cipher && generate_iv) { iv_len = silc_cipher_get_block_len(cipher); if (rng) { for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng); } else { for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast(); } } if (hmac) mac_len = silc_hmac_len(hmac); data_len = silc_message_payload_datalen(data_len, mac_len + iv_len, flags, public_key, private_key); /* Calculate length of padding. IV is not included into the calculation since it is not encrypted. */ pad_len = SILC_MESSAGE_PAD(6 + data_len); /* Generate padding */ if (cipher) { if (rng) { for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng); } else { for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast(); } } /* Encode the Message Payload */ if (silc_buffer_format(buffer, SILC_STR_ADVANCE, SILC_STR_UI_SHORT(flags), SILC_STR_UI_SHORT(data_len), SILC_STR_DATA(data, data_len), SILC_STR_UI_SHORT(pad_len), SILC_STR_DATA(pad, pad_len), SILC_STR_END) < 0) { silc_buffer_sfree(stack, buffer); encoded(NULL, context); silc_stack_free(stack); return NULL; } if (flags & SILC_MESSAGE_FLAG_SIGNED) { SilcMessageEncode *e = silc_scalloc(stack, 1, sizeof(*e)); if (!e) { silc_buffer_sfree(stack, buffer); encoded(NULL, context); silc_stack_free(stack); return NULL; } e->stack = stack; e->buffer = buffer; e->flags = flags; e->public_key = public_key; e->private_key = private_key; e->rng = rng; e->hash = hash; e->cipher = cipher; e->hmac = hmac; e->sid = *sender_id; e->rid = *receiver_id; e->iv = iv_len ? iv : NULL; e->iv_len = iv_len; e->payload_len = 6 + data_len + pad_len; e->encoded = encoded; e->context = context; /* Compute signature */ return silc_message_signed_payload_encode(buffer, e); } /* Finalize */ silc_message_payload_encode_final(buffer, flags, cipher, hmac, iv_len ? iv : NULL, iv_len, 6 + data_len + pad_len, sender_id, receiver_id, stack, NULL, encoded, context); return NULL; } /* Free's Message Payload */ void silc_message_payload_free(SilcMessagePayload payload) { silc_message_signed_payload_free(&payload->sig); if (payload->data) { memset(payload->data, 0, payload->data_len); if (payload->allocated) silc_free(payload->data); } if (payload->allocated) { silc_free(payload->pad); silc_free(payload); } } /* Return flags */ SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload) { return payload->flags; } /* Return data */ unsigned char *silc_message_get_data(SilcMessagePayload payload, SilcUInt32 *data_len) { if (data_len) *data_len = payload->data_len; return payload->data; } /* Return MAC. The caller knows the length of the MAC */ unsigned char *silc_message_get_mac(SilcMessagePayload payload) { return payload->mac; } /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */ SilcAsyncOperation silc_message_signed_verify(SilcMessagePayload message, SilcPublicKey remote_public_key, SilcHash hash, SilcAuthResultCb result, void *context) { SilcAsyncOperation op; SilcBuffer sign, tmp; SilcStack stack = NULL; SilcMessageSignedPayload sig = &message->sig; if (!(message->flags & SILC_MESSAGE_FLAG_SIGNED) || !sig->sign_len || !remote_public_key || !hash) { result(FALSE, context); return NULL; } if (silc_crypto_stack()) stack = silc_stack_alloc(0, silc_crypto_stack()); /* Generate the signature verification data, the Message Payload */ tmp = silc_buffer_salloc_size(stack, 6 + message->data_len + message->pad_len); silc_buffer_sformat(stack, tmp, SILC_STR_UI_SHORT(message->flags), SILC_STR_UI_SHORT(message->data_len), SILC_STR_DATA(message->data, message->data_len), SILC_STR_UI_SHORT(message->pad_len), SILC_STR_DATA(message->pad, message->pad_len), SILC_STR_END); sign = silc_message_signed_encode_data(stack, tmp->data, silc_buffer_len(tmp), sig->pk_data, sig->pk_len, sig->pk_type); silc_buffer_clear(tmp); silc_buffer_sfree(stack, tmp); if (!sign) { result(FALSE, context); silc_stack_free(stack); return NULL; } /* Verify the authentication data */ op = silc_pkcs_verify_async(remote_public_key, sig->sign_data, sig->sign_len, silc_buffer_data(sign), silc_buffer_len(sign), TRUE, hash, result, context); silc_buffer_clear(sign); silc_buffer_sfree(stack, sign); silc_stack_free(stack); return op; } /* Return the public key from the payload */ SilcPublicKey silc_message_signed_get_public_key(SilcMessagePayload payload, const unsigned char **pk_data, SilcUInt32 *pk_data_len) { SilcPublicKey pk; SilcMessageSignedPayload sig = &payload->sig; if (!sig->pk_data) return NULL; if (!silc_pkcs_public_key_alloc(sig->pk_type, sig->pk_data, sig->pk_len, &pk)) return NULL; if (pk_data) *pk_data = sig->pk_data; if (pk_data_len) *pk_data_len = sig->pk_len; return pk; }