The SILC Project

source navigation ]
identifier search ]
freetext search ]
file search ]

silc/lib/silccore/silcmessage.c

  1 /*
  2 
  3   silcmessage.c
  4 
  5   Author: Pekka Riikonen <priikone@silcnet.org>
  6 
  7   Copyright (C) 1997 - 2007 Pekka Riikonen
  8 
  9   This program is free software; you can redistribute it and/or modify
 10   it under the terms of the GNU General Public License as published by
 11   the Free Software Foundation; version 2 of the License.
 12 
 13   This program is distributed in the hope that it will be useful,
 14   but WITHOUT ANY WARRANTY; without even the implied warranty of
 15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16   GNU General Public License for more details.
 17 
 18 */
 19 /* Implementation of the Message Payload used as channel messages and
 20    private messages. */
 21 /* $Id: silcmessage.c,v 1.30 2007/07/21 17:18:20 priikone Exp $ */
 22 
 23 #include "silc.h"
 24 #include "silcmessage.h"
 25 
 26 /*************************** Types and definitions **************************/
 27 
 28 /* Calculates padding length for message payload */
 29 #define SILC_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16))
 30 
 31 /* Header length plus maximum padding length */
 32 #define SILC_MESSAGE_HLEN 6 + 16
 33 
 34 /* Maximum message length */
 35 #define SILC_MESSAGE_MAX_LEN SILC_PACKET_MAX_LEN - SILC_MESSAGE_HLEN - 16
 36 
 37 /* Payload encoding context */
 38 typedef struct {
 39   SilcBuffer buffer;
 40   SilcBuffer sign;
 41   SilcStack stack;
 42   SilcMessagePayloadEncoded encoded;
 43   void *context;
 44   SilcMessageFlags flags;
 45   SilcPublicKey public_key;
 46   SilcPrivateKey private_key;
 47   SilcRng rng;
 48   SilcHash hash;
 49   SilcCipher cipher;
 50   SilcHmac hmac;
 51   unsigned char *iv;
 52   unsigned char *pk;
 53   SilcUInt16 pk_len;
 54   SilcUInt16 iv_len;
 55   SilcUInt16 payload_len;
 56   SilcID sid;
 57   SilcID rid;
 58 } SilcMessageEncode;
 59 
 60 
 61 /************************* Static utility functions *************************/
 62 
 63 static void
 64 silc_message_payload_encode_final(SilcBuffer buffer,
 65                                   SilcMessageFlags flags,
 66                                   SilcCipher cipher,
 67                                   SilcHmac hmac,
 68                                   unsigned char *iv,
 69                                   SilcUInt32 iv_len,
 70                                   SilcUInt32 payload_len,
 71                                   SilcID *sender_id,
 72                                   SilcID *receiver_id,
 73                                   SilcStack stack,
 74                                   SilcBuffer signature,
 75                                   SilcMessagePayloadEncoded encoded,
 76                                   void *context);
 77 
 78 /* Returns the data length that fits to the packet.  If data length is too
 79    big it will be truncated to fit to the payload. */
 80 
 81 static inline
 82 SilcUInt32 silc_message_payload_datalen(SilcUInt32 data_len,
 83                                         SilcUInt32 header_len,
 84                                         SilcUInt32 flags,
 85                                         SilcPublicKey public_key,
 86                                         SilcPrivateKey private_key)
 87 {
 88   SilcUInt32 pklen = (flags & SILC_MESSAGE_FLAG_SIGNED && public_key ?
 89                       silc_pkcs_public_key_get_len(public_key) : 0);
 90   SilcUInt32 prlen = (flags & SILC_MESSAGE_FLAG_SIGNED ?
 91                       silc_pkcs_private_key_get_len(private_key) / 8 : 0);
 92   SilcUInt32 dlen = data_len + SILC_MESSAGE_HLEN + header_len + pklen + prlen;
 93 
 94   if (silc_unlikely(dlen > SILC_MESSAGE_MAX_LEN))
 95     data_len -= (dlen - SILC_MESSAGE_MAX_LEN);
 96 
 97   return data_len;
 98 }
 99 
100 /* Free signed payload */
101 
102 static void silc_message_signed_payload_free(SilcMessageSignedPayload sig)
103 {
104   if (sig->sign_data) {
105     memset(sig->sign_data, 0, sig->sign_len);
106     silc_free(sig->sign_data);
107   }
108   silc_free(sig->pk_data);
109 }
110 
111 /* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */
112 
113 static SilcBool
114 silc_message_signed_payload_parse(const unsigned char *data,
115                                   SilcUInt32 data_len,
116                                   SilcMessageSignedPayload sig)
117 {
118   SilcBufferStruct buffer;
119   int ret;
120 
121   SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload"));
122 
123   SILC_LOG_HEXDUMP(("sig payload"), (unsigned char *)data, data_len);
124 
125   silc_buffer_set(&buffer, (unsigned char *)data, data_len);
126 
127   /* Parse the payload */
128   ret = silc_buffer_unformat(&buffer,
129                              SILC_STR_UI_SHORT(&sig->pk_len),
130                              SILC_STR_UI_SHORT(&sig->pk_type),
131                              SILC_STR_END);
132   if (ret == -1 || sig->pk_len > data_len - 4) {
133     SILC_LOG_DEBUG(("Malformed public key in SILC_MESSAGE_FLAG_SIGNED "
134                     "Payload"));
135     return FALSE;
136   }
137 
138   silc_buffer_pull(&buffer, 4);
139   ret = silc_buffer_unformat(&buffer,
140                              SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data,
141                                                         sig->pk_len),
142                              SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data,
143                                                          &sig->sign_len),
144                              SILC_STR_END);
145   if (ret == -1 || sig->sign_len > silc_buffer_len(&buffer) -
146       sig->pk_len - 2) {
147     silc_message_signed_payload_free(sig);
148     SILC_LOG_DEBUG(("Malformed SILC_MESSAGE_FLAG_SIGNED Payload"));
149     return FALSE;
150   }
151   silc_buffer_push(&buffer, 4);
152 
153   /* Signature must be provided */
154   if (sig->sign_len < 1)  {
155     SILC_LOG_DEBUG(("Malformed signature in SILC_MESSAGE_SIGNED_PAYLOAD "
156                     "Payload"));
157     silc_message_signed_payload_free(sig);
158     return FALSE;
159   }
160 
161   return TRUE;
162 }
163 
164 /* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */
165 
166 static SilcBuffer
167 silc_message_signed_encode_data(SilcStack stack,
168                                 const unsigned char *message_payload,
169                                 SilcUInt32 message_payload_len,
170                                 unsigned char *pk,
171                                 SilcUInt32 pk_len, SilcUInt32 pk_type)
172 {
173   SilcBuffer sign;
174 
175   sign = silc_buffer_salloc_size(stack, message_payload_len + 4 + pk_len);
176   if (!sign)
177     return NULL;
178 
179   silc_buffer_sformat(stack, sign,
180                       SILC_STR_DATA(message_payload, message_payload_len),
181                       SILC_STR_UI_SHORT(pk_len),
182                       SILC_STR_UI_SHORT(pk_type),
183                       SILC_STR_END);
184 
185   if (pk && pk_len) {
186     silc_buffer_pull(sign, message_payload_len + 4);
187     silc_buffer_sformat(stack, sign,
188                         SILC_STR_UI_XNSTRING(pk, pk_len),
189                         SILC_STR_END);
190     silc_buffer_push(sign, message_payload_len + 4);
191   }
192 
193   return sign;
194 }
195 
196 /* Signature callback */
197 
198 void silc_message_signed_payload_encode_cb(SilcBool success,
199                                            const unsigned char *signature,
200                                            SilcUInt32 signature_len,
201                                            void *context)
202 {
203   SilcMessageEncode *e = context;
204   SilcPKCSType pk_type;
205   SilcStack stack = e->stack;
206   SilcBuffer buffer, payload;
207   SilcMessageFlags flags;
208   SilcCipher cipher;
209   SilcHmac hmac;
210   unsigned char *iv;
211   SilcUInt32 iv_len, payload_len;
212   SilcID *sid, *rid;
213   SilcMessagePayloadEncoded encoded;
214   void *encoded_context;
215 
216   if (!success) {
217     e->encoded(NULL, e->context);
218     silc_buffer_sfree(stack, e->sign);
219     silc_sfree(stack, e->pk);
220     silc_sfree(stack, e);
221     silc_stack_free(stack);
222     return;
223   }
224 
225   pk_type = silc_pkcs_get_type(e->private_key);
226 
227   /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
228   buffer = silc_buffer_salloc_size(stack, 4 + e->pk_len + 2 + signature_len);
229   if (!buffer) {
230     e->encoded(NULL, e->context);
231     silc_buffer_sfree(stack, e->sign);
232     silc_sfree(stack, e->pk);
233     silc_sfree(stack, e);
234     silc_stack_free(stack);
235     return;
236   }
237 
238   silc_buffer_sformat(stack, buffer,
239                       SILC_STR_UI_SHORT(e->pk_len),
240                       SILC_STR_UI_SHORT(pk_type),
241                       SILC_STR_END);
242 
243   if (e->pk_len && e->pk) {
244     silc_buffer_pull(buffer, 4);
245     silc_buffer_sformat(stack, buffer,
246                         SILC_STR_DATA(e->pk, e->pk_len),
247                         SILC_STR_END);
248     silc_buffer_push(buffer, 4);
249   }
250 
251   silc_buffer_pull(buffer, 4 + e->pk_len);
252   silc_buffer_sformat(stack, buffer,
253                       SILC_STR_UI_SHORT(signature_len),
254                       SILC_STR_DATA(signature, signature_len),
255                       SILC_STR_END);
256   silc_buffer_push(buffer, 4 + e->pk_len);
257 
258   SILC_LOG_HEXDUMP(("SIG payload"), buffer->data, silc_buffer_len(buffer));
259 
260   payload = e->buffer;
261   flags = e->flags;
262   cipher = e->cipher;
263   hmac = e->hmac;
264   iv = e->iv;
265   iv_len = e->iv_len;
266   payload_len = e->payload_len;
267   sid = &e->sid;
268   rid = &e->rid;
269   encoded = e->encoded;
270   encoded_context = e->context;
271 
272   silc_sfree(stack, e->pk);
273   silc_buffer_sfree(stack, e->sign);
274   silc_sfree(stack, e);
275 
276   /* Finalize message payload encoding */
277   silc_message_payload_encode_final(payload, flags, cipher, hmac,
278                                     iv, iv_len, payload_len,
279                                     sid, rid, stack, buffer,
280                                     encoded, encoded_context);
281 }
282 
283 /* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital
284    signature. */
285 
286 static SilcAsyncOperation
287 silc_message_signed_payload_encode(SilcBuffer payload,
288                                    SilcMessageEncode *e)
289 {
290   SilcAsyncOperation op;
291   SilcBuffer sign;
292   unsigned char *pk = NULL;
293   SilcUInt32 pk_len = 0;
294   SilcUInt16 pk_type;
295   SilcStack stack = e->stack;
296   SilcRng rng = e->rng;
297   SilcHash hash = e->hash;
298   SilcPublicKey public_key = e->public_key;
299   SilcPrivateKey private_key = e->private_key;
300   unsigned char *message_payload;
301   SilcUInt16 message_payload_len;
302 
303   message_payload = payload->head;
304   message_payload_len = silc_buffer_headlen(payload);
305 
306   if (!message_payload || !message_payload_len || !private_key || !hash) {
307     e->encoded(NULL, e->context);
308     silc_sfree(stack, e);
309     silc_stack_free(stack);
310     return NULL;
311   }
312 
313   if (public_key) {
314     e->pk = pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len);
315     if (!pk) {
316       e->encoded(NULL, e->context);
317       silc_sfree(stack, e);
318       silc_stack_free(stack);
319       return NULL;
320     }
321     e->pk_len = pk_len;
322   }
323   pk_type = silc_pkcs_get_type(private_key);
324 
325   /* Encode the data to be signed */
326   e->sign = sign = silc_message_signed_encode_data(stack, message_payload,
327                                                    message_payload_len,
328                                                    pk, pk_len, pk_type);
329   if (!sign) {
330     e->encoded(NULL, e->context);
331     silc_sfree(stack, pk);
332     silc_sfree(stack, e);
333     silc_stack_free(stack);
334     return NULL;
335   }
336 
337   /* Compute signature */
338   op = silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign),
339                       TRUE, hash, rng,
340                       silc_message_signed_payload_encode_cb, e);
341 
342   return op;
343 }
344 
345 /***************************** Payload parsing ******************************/
346 
347 /* Decrypts the Message Payload. The `data' is the actual Message Payload. */
348 
349 SilcBool silc_message_payload_decrypt(unsigned char *data,
350                                       size_t data_len,
351                                       SilcBool private_message,
352                                       SilcBool static_key,
353                                       SilcCipher cipher,
354                                       SilcHmac hmac,
355                                       unsigned char *sender_id,
356                                       SilcUInt32 sender_id_len,
357                                       unsigned char *receiver_id,
358                                       SilcUInt32 receiver_id_len,
359                                       SilcBool check_mac)
360 {
361   SilcUInt32 mac_len, iv_len = 0, block_len;
362   SilcUInt16 len, totlen;
363   unsigned char mac[32], *ivp;
364 
365   mac_len = silc_hmac_len(hmac);
366   block_len = silc_cipher_get_block_len(cipher);
367 
368   /* IV is present for all channel messages, and private messages when
369      static key (pre-shared key) is used. */
370   if (!private_message || (private_message && static_key))
371     iv_len = block_len;
372 
373   if (silc_unlikely(data_len < (mac_len + iv_len + block_len)))
374     return FALSE;
375 
376   if (silc_likely(check_mac)) {
377     /* Check the MAC of the message */
378     SILC_LOG_DEBUG(("Checking message MAC"));
379     silc_hmac_init(hmac);
380     silc_hmac_update(hmac, data, data_len - mac_len);
381     silc_hmac_update(hmac, sender_id, sender_id_len);
382     silc_hmac_update(hmac, receiver_id, receiver_id_len);
383     silc_hmac_final(hmac, mac, &mac_len);
384     if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
385       /* Check for old style (version 1.2) message MAC.  Remove this check
386          at some point. */
387       silc_hmac_init(hmac);
388       silc_hmac_update(hmac, data, data_len - mac_len);
389       silc_hmac_final(hmac, mac, &mac_len);
390       if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
391         SILC_LOG_DEBUG(("Message MAC does not match"));
392         return FALSE;
393       }
394     }
395     SILC_LOG_DEBUG(("MAC is Ok"));
396   }
397 
398   /* Decrypt first only one block to get the header and then rest of
399      the data.  This is done because there might be unencrypted data at
400      the end and we don't know the encrypted length yet. */
401 
402   /* Get pointer to the IV */
403   ivp = (iv_len ? data + (data_len - iv_len - mac_len) :
404          silc_cipher_get_iv(cipher));
405 
406   /* Decrypt block */
407   if (silc_unlikely(!silc_cipher_decrypt(cipher, data, data, block_len,
408                                          ivp))) {
409     SILC_ASSERT(FALSE);
410     return FALSE;
411   }
412 
413   /* Get the payload length and decrypt rest */
414   totlen = 2;
415   SILC_GET16_MSB(len, data + totlen);
416   totlen += 2 + len;
417   if (silc_unlikely(totlen + iv_len + mac_len + 2 > data_len))
418     return FALSE;
419   totlen += 2;
420   if (totlen >= block_len)
421     if (silc_unlikely(!silc_cipher_decrypt(cipher, data + block_len,
422                                            data + block_len,
423                                            (totlen - block_len) +
424                                            SILC_MESSAGE_PAD(totlen), ivp))) {
425       SILC_ASSERT(FALSE);
426       return FALSE;
427     }
428 
429   return TRUE;
430 }
431 
432 /* Parses Message Payload returning new payload structure.  This also
433    decrypts it and checks the MAC. */
434 
435 SilcMessagePayload
436 silc_message_payload_parse(unsigned char *payload,
437                            SilcUInt32 payload_len,
438                            SilcBool private_message,
439                            SilcBool static_key,
440                            SilcCipher cipher,
441                            SilcHmac hmac,
442                            unsigned char *sender_id,
443                            SilcUInt32 sender_id_len,
444                            unsigned char *receiver_id,
445                            SilcUInt32 receiver_id_len,
446                            SilcStack stack,
447                            SilcBool no_allocation,
448                            SilcMessagePayload message)
449 {
450   SilcBufferStruct buffer;
451   SilcMessagePayload newp = NULL;
452   int ret;
453   SilcUInt32 mac_len = 0, iv_len = 0;
454 
455   SILC_LOG_DEBUG(("Parsing Message Payload"));
456 
457   silc_buffer_set(&buffer, payload, payload_len);
458 
459   /* Decrypt the payload */
460   if (silc_likely(cipher)) {
461     ret = silc_message_payload_decrypt(buffer.data, silc_buffer_len(&buffer),
462                                        private_message, static_key,
463                                        cipher, hmac, sender_id,
464                                        sender_id_len, receiver_id,
465                                        receiver_id_len, TRUE);
466     if (silc_unlikely(ret == FALSE))
467       return NULL;
468   }
469 
470   if (silc_likely(hmac))
471     mac_len = silc_hmac_len(hmac);
472 
473   /* IV is present for all channel messages, and private messages when
474      static key (pre-shared key) is used. */
475   if (cipher && (!private_message || (private_message && static_key)))
476     iv_len = silc_cipher_get_block_len(cipher);
477 
478   if (!message) {
479     newp = message = silc_calloc(1, sizeof(*newp));
480     if (silc_unlikely(!newp))
481       return NULL;
482   }
483   memset(message, 0, sizeof(*message));
484   message->allocated = (stack || no_allocation ? FALSE : TRUE);
485 
486   /* Parse the Message Payload. */
487   if (!no_allocation)
488     ret = silc_buffer_sunformat(stack, &buffer,
489                           SILC_STR_UI_SHORT(&message->flags),
490                           SILC_STR_UI16_NSTRING_ALLOC(&message->data,
491                                                       &message->data_len),
492                           SILC_STR_UI16_NSTRING_ALLOC(&message->pad,
493                                                       &message->pad_len),
494                           SILC_STR_END);
495   else
496     ret = silc_buffer_unformat(&buffer,
497                                SILC_STR_UI_SHORT(&message->flags),
498                                SILC_STR_UI16_NSTRING(&message->data,
499                                                      &message->data_len),
500                                SILC_STR_UI16_NSTRING(&message->pad,
501                                                      &message->pad_len),
502                                SILC_STR_END);
503   if (silc_unlikely(ret == -1))
504     goto err;
505 
506   if (silc_unlikely((message->data_len > silc_buffer_len(&buffer) -
507                      6 - mac_len - iv_len) ||
508                     (message->pad_len + message->data_len >
509                      silc_buffer_len(&buffer) - 6 - mac_len - iv_len))) {
510     SILC_LOG_ERROR(("Incorrect Message Payload in packet"));
511     goto err;
512   }
513 
514   /* Parse Signed Message Payload if provided */
515   if (message->flags & SILC_MESSAGE_FLAG_SIGNED &&
516       message->data_len + message->pad_len + 6 + mac_len +
517       iv_len < silc_buffer_len(&buffer)) {
518     if (!silc_message_signed_payload_parse(buffer.data + 6 +
519                                            message->data_len +
520                                            message->pad_len,
521                                            silc_buffer_len(&buffer) -
522                                            iv_len - mac_len - 6 -
523                                            message->data_len -
524                                            message->pad_len,
525                                            &message->sig))
526       goto err;
527   }
528 
529   /* Parse MAC from the payload */
530   if (mac_len)
531     message->mac = buffer.data + (silc_buffer_len(&buffer) - mac_len);
532 
533   return newp;
534 
535  err:
536   if (newp)
537     silc_message_payload_free(newp);
538   return NULL;
539 }
540 
541 
542 /***************************** Payload encoding *****************************/
543 
544 /* This function is used to encrypt the Messsage Payload which is
545    the `data' and `data_len'.  This is used internally by the Message
546    Payload encoding routines but application may call this too if needed.
547    The `true_len' is the data length which is used to create MAC out of. */
548 
549 SilcBool silc_message_payload_encrypt(unsigned char *data,
550                                       SilcUInt32 data_len,
551                                       SilcUInt32 true_len,
552                                       unsigned char *iv,
553                                       SilcID *sender_id,
554                                       SilcID *receiver_id,
555                                       SilcCipher cipher,
556                                       SilcHmac hmac)
557 {
558   unsigned char sid[32], rid[32];
559   SilcUInt32 sid_len = 0, rid_len = 0;
560 
561   /* Encrypt payload of the packet */
562   if (silc_unlikely(!silc_cipher_encrypt(cipher, data, data, data_len, iv)))
563     return FALSE;
564 
565   /* Encode IDs */
566   silc_id_id2str(&sender_id->u.client_id, SILC_ID_CLIENT, sid, sizeof(sid),
567                  &sid_len);
568   if (receiver_id->type == SILC_ID_CLIENT)
569     silc_id_id2str(&receiver_id->u.client_id, SILC_ID_CLIENT, rid,
570                    sizeof(rid), &rid_len);
571   else if (receiver_id->type == SILC_ID_CHANNEL)
572     silc_id_id2str(&receiver_id->u.channel_id, SILC_ID_CHANNEL, rid,
573                    sizeof(rid), &rid_len);
574 
575   /* Compute the MAC of the encrypted message data */
576   silc_hmac_init(hmac);
577   silc_hmac_update(hmac, data, true_len);
578   silc_hmac_update(hmac, sid, sid_len);
579   silc_hmac_update(hmac, rid, rid_len);
580   silc_hmac_final(hmac, data + true_len, NULL);
581 
582   return TRUE;
583 }
584 
585 /* Encrypt message payload */
586 
587 static int silc_message_payload_encode_encrypt(SilcStack stack,
588                                                SilcBuffer buffer,
589                                                void *value, void *context)
590 {
591   SilcMessageEncode *e = context;
592   SilcUInt32 mac_len;
593 
594   if (!e->cipher || !e->hmac)
595     return 0;
596 
597   mac_len = silc_hmac_len(e->hmac);
598   if (silc_unlikely(!silc_buffer_enlarge(buffer, mac_len)))
599     return -1;
600 
601   if (silc_unlikely(!silc_message_payload_encrypt(buffer->head,
602                                                   e->payload_len,
603                                                   silc_buffer_headlen(buffer),
604                                                   e->iv, &e->sid, &e->rid,
605                                                   e->cipher, e->hmac)))
606     return -1;
607 
608   return mac_len;
609 }
610 
611 /* Finalize message payload encoding */
612 
613 static void
614 silc_message_payload_encode_final(SilcBuffer buffer,
615                                   SilcMessageFlags flags,
616                                   SilcCipher cipher,
617                                   SilcHmac hmac,
618                                   unsigned char *iv,
619                                   SilcUInt32 iv_len,
620                                   SilcUInt32 payload_len,
621                                   SilcID *sender_id,
622                                   SilcID *receiver_id,
623                                   SilcStack stack,
624                                   SilcBuffer signature,
625                                   SilcMessagePayloadEncoded encoded,
626                                   void *context)
627 {
628   SilcMessageEncode e;
629 
630   e.flags = flags;
631   e.cipher = cipher;
632   e.hmac = hmac;
633   e.sid = *sender_id;
634   e.rid = *receiver_id;
635   e.iv = iv;
636   e.payload_len = payload_len;
637 
638   /* Encrypt */
639   if (silc_buffer_format(buffer,
640                          SILC_STR_DATA(signature ?
641                                        silc_buffer_data(signature) : NULL,
642                                        signature ?
643                                        silc_buffer_len(signature) : 0),
644                          SILC_STR_DATA(iv, iv_len),
645                          SILC_STR_FUNC(silc_message_payload_encode_encrypt,
646                                        NULL, &e),
647                          SILC_STR_END) < 0) {
648     silc_buffer_sfree(stack, buffer);
649     encoded(NULL, context);
650     return;
651   }
652 
653   /* Deliver message payload */
654   silc_buffer_start(buffer);
655   encoded(buffer, context);
656 
657   silc_buffer_sfree(stack, buffer);
658   silc_buffer_sfree(stack, signature);
659   silc_stack_free(stack);
660 }
661 
662 /* Encodes Message Payload into a buffer and returns it. */
663 
664 SilcAsyncOperation
665 silc_message_payload_encode(SilcMessageFlags flags,
666                             const unsigned char *data,
667                             SilcUInt32 data_len,
668                             SilcBool generate_iv,
669                             SilcBool private_message,
670                             SilcCipher cipher,
671                             SilcHmac hmac,
672                             SilcRng rng,
673                             SilcPublicKey public_key,
674                             SilcPrivateKey private_key,
675                             SilcHash hash,
676                             SilcID *sender_id,
677                             SilcID *receiver_id,
678                             SilcStack stack,
679                             SilcMessagePayloadEncoded encoded,
680                             void *context)
681 {
682   SilcUInt32 pad_len = 0, mac_len = 0, iv_len = 0;
683   unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
684   SilcBuffer buffer;
685   int i;
686 
687   SILC_LOG_DEBUG(("Encoding Message Payload"));
688 
689   if (silc_unlikely(!data_len)) {
690     encoded(NULL, context);
691     return NULL;
692   }
693   if (silc_unlikely(!private_message && (!cipher || !hmac))) {
694     encoded(NULL, context);
695     return NULL;
696   }
697 
698   stack = silc_stack_alloc(0, stack ? stack : silc_crypto_stack());
699 
700   buffer = silc_buffer_salloc(stack, 0);
701   if (silc_unlikely(!buffer)) {
702     encoded(NULL, context);
703     silc_stack_free(stack);
704     return NULL;
705   }
706 
707   /* For channel messages IV is always generated */
708   if (!private_message && !generate_iv)
709     generate_iv = TRUE;
710 
711   /* Generate IV */
712   if (cipher && generate_iv) {
713     iv_len = silc_cipher_get_block_len(cipher);
714     if (rng) {
715       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng);
716     } else {
717       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast();
718     }
719   }
720 
721   if (hmac)
722     mac_len = silc_hmac_len(hmac);
723   data_len = silc_message_payload_datalen(data_len, mac_len + iv_len, flags,
724                                           public_key, private_key);
725 
726   /* Calculate length of padding. IV is not included into the calculation
727      since it is not encrypted. */
728   pad_len = SILC_MESSAGE_PAD(6 + data_len);
729 
730   /* Generate padding */
731   if (cipher) {
732     if (rng) {
733       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
734     } else {
735       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
736     }
737   }
738 
739   /* Encode the Message Payload */
740   if (silc_buffer_format(buffer,
741                          SILC_STR_ADVANCE,
742                          SILC_STR_UI_SHORT(flags),
743                          SILC_STR_UI_SHORT(data_len),
744                          SILC_STR_DATA(data, data_len),
745                          SILC_STR_UI_SHORT(pad_len),
746                          SILC_STR_DATA(pad, pad_len),
747                          SILC_STR_END) < 0) {
748     silc_buffer_sfree(stack, buffer);
749     encoded(NULL, context);
750     silc_stack_free(stack);
751     return NULL;
752   }
753 
754   if (flags & SILC_MESSAGE_FLAG_SIGNED) {
755     SilcMessageEncode *e = silc_scalloc(stack, 1, sizeof(*e));
756     if (!e) {
757       silc_buffer_sfree(stack, buffer);
758       encoded(NULL, context);
759       silc_stack_free(stack);
760       return NULL;
761     }
762 
763     e->stack = stack;
764     e->buffer = buffer;
765     e->flags = flags;
766     e->public_key = public_key;
767     e->private_key = private_key;
768     e->rng = rng;
769     e->hash = hash;
770     e->cipher = cipher;
771     e->hmac = hmac;
772     e->sid = *sender_id;
773     e->rid = *receiver_id;
774     e->iv = iv_len ? iv : NULL;
775     e->iv_len = iv_len;
776     e->payload_len = 6 + data_len + pad_len;
777     e->encoded = encoded;
778     e->context = context;
779 
780     /* Compute signature */
781     return silc_message_signed_payload_encode(buffer, e);
782   }
783 
784   /* Finalize */
785   silc_message_payload_encode_final(buffer, flags, cipher, hmac,
786                                     iv_len ? iv : NULL, iv_len,
787                                     6 + data_len + pad_len,
788                                     sender_id, receiver_id, stack, NULL,
789                                     encoded, context);
790   return NULL;
791 }
792 
793 /* Free's Message Payload */
794 
795 void silc_message_payload_free(SilcMessagePayload payload)
796 {
797   silc_message_signed_payload_free(&payload->sig);
798   if (payload->data) {
799     memset(payload->data, 0, payload->data_len);
800     if (payload->allocated)
801       silc_free(payload->data);
802   }
803   if (payload->allocated) {
804     silc_free(payload->pad);
805     silc_free(payload);
806   }
807 }
808 
809 /* Return flags */
810 
811 SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload)
812 {
813   return payload->flags;
814 }
815 
816 /* Return data */
817 
818 unsigned char *silc_message_get_data(SilcMessagePayload payload,
819                                      SilcUInt32 *data_len)
820 {
821   if (data_len)
822     *data_len = payload->data_len;
823   return payload->data;
824 }
825 
826 /* Return MAC. The caller knows the length of the MAC */
827 
828 unsigned char *silc_message_get_mac(SilcMessagePayload payload)
829 {
830   return payload->mac;
831 }
832 
833 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
834 
835 SilcAsyncOperation
836 silc_message_signed_verify(SilcMessagePayload message,
837                            SilcPublicKey remote_public_key,
838                            SilcHash hash,
839                            SilcAuthResultCb result,
840                            void *context)
841 {
842   SilcAsyncOperation op;
843   SilcBuffer sign, tmp;
844   SilcStack stack = NULL;
845   SilcMessageSignedPayload sig = &message->sig;
846 
847   if (!(message->flags & SILC_MESSAGE_FLAG_SIGNED) ||
848       !sig->sign_len || !remote_public_key || !hash) {
849     result(FALSE, context);
850     return NULL;
851   }
852 
853   if (silc_crypto_stack())
854     stack = silc_stack_alloc(0, silc_crypto_stack());
855 
856   /* Generate the signature verification data, the Message Payload */
857   tmp = silc_buffer_salloc_size(stack,
858                                 6 + message->data_len + message->pad_len);
859   silc_buffer_sformat(stack, tmp,
860                       SILC_STR_UI_SHORT(message->flags),
861                       SILC_STR_UI_SHORT(message->data_len),
862                       SILC_STR_DATA(message->data, message->data_len),
863                       SILC_STR_UI_SHORT(message->pad_len),
864                       SILC_STR_DATA(message->pad, message->pad_len),
865                       SILC_STR_END);
866   sign = silc_message_signed_encode_data(stack, tmp->data, silc_buffer_len(tmp),
867                                          sig->pk_data, sig->pk_len,
868                                          sig->pk_type);
869   silc_buffer_clear(tmp);
870   silc_buffer_sfree(stack, tmp);
871 
872   if (!sign) {
873     result(FALSE, context);
874     silc_stack_free(stack);
875     return NULL;
876   }
877 
878   /* Verify the authentication data */
879   op = silc_pkcs_verify(remote_public_key, sig->sign_data, sig->sign_len,
880                         silc_buffer_data(sign), silc_buffer_len(sign),
881                         hash, result, context);
882 
883   silc_buffer_clear(sign);
884   silc_buffer_sfree(stack, sign);
885   silc_stack_free(stack);
886 
887   return op;
888 }
889 
890 /* Return the public key from the payload */
891 
892 SilcPublicKey
893 silc_message_signed_get_public_key(SilcMessagePayload payload,
894                                    const unsigned char **pk_data,
895                                    SilcUInt32 *pk_data_len)
896 {
897   SilcPublicKey pk;
898   SilcMessageSignedPayload sig = &payload->sig;
899 
900   if (!sig->pk_data)
901     return NULL;
902 
903   if (!silc_pkcs_public_key_alloc(sig->pk_type, sig->pk_data,
904                                   sig->pk_len, &pk))
905     return NULL;
906 
907   if (pk_data)
908     *pk_data = sig->pk_data;
909   if (pk_data_len)
910     *pk_data_len = sig->pk_len;
911 
912   return pk;
913 }
914 

This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse