+ 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;
+}