Unified Channel Message Payload and Private Message Payload
[silc.git] / lib / silccore / silcmessage.c
1 /*
2
3   silcmessage.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 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$ */
22
23 #include "silcincludes.h"
24 #include "silcmessage.h"
25
26 /******************************************************************************
27
28                                Message Payload
29
30 ******************************************************************************/
31
32 /* Calculates padding length for message payload */
33 #define SILC_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16))
34
35 /* Header length plus maximum padding length */
36 #define SILC_MESSAGE_HLEN 6 + 16
37
38 /* Returns the data length that fits to the packet.  If data length is too
39    big it will be truncated to fit to the payload. */
40 #define SILC_MESSAGE_DATALEN(data_len, header_len)              \
41   ((data_len + SILC_MESSAGE_HLEN + header_len) >                \
42    SILC_PACKET_MAX_LEN ?                                        \
43    data_len - ((data_len + SILC_MESSAGE_HLEN + header_len) -    \
44                SILC_PACKET_MAX_LEN) : data_len)
45
46 /* Message Payload structure. Contents of this structure is parsed
47    from SILC packets. */
48 struct SilcMessagePayloadStruct {
49   SilcMessageFlags flags;
50   SilcUInt16 data_len;
51   SilcUInt16 pad_len;
52   SilcUInt16 iv_len;
53   unsigned char *data;
54   unsigned char *pad;
55   unsigned char *iv;
56   unsigned char *mac;
57   /*SilcMessageSignedPayload sig;*/
58 };
59
60 /* Decrypts the Message Payload. The `data' is the actual Message Payload */
61
62 bool silc_message_payload_decrypt(unsigned char *data,
63                                   size_t data_len,
64                                   bool private_message,
65                                   bool static_key,
66                                   SilcCipher cipher,
67                                   SilcHmac hmac,
68                                   bool check_mac)
69 {
70   SilcUInt32 mac_len = 0, iv_len = 0;
71   unsigned char *mac, mac2[32];
72
73   mac_len = silc_hmac_len(hmac);
74
75   /* IV is present for channel messages and private messages when static
76      key (pre-shared key) is used. */
77   if (!private_message || (private_message && static_key))
78     iv_len = silc_cipher_get_block_len(cipher);
79
80   if (data_len < mac_len)
81     return FALSE;
82
83   if (check_mac) {
84     /* Take the MAC */
85     mac = data + (data_len - mac_len);
86
87     /* Check the MAC of the message */
88     SILC_LOG_DEBUG(("Checking message MAC"));
89     silc_hmac_init(hmac);
90     silc_hmac_update(hmac, data, data_len - mac_len);
91     silc_hmac_final(hmac, mac2, &mac_len);
92     if (memcmp(mac, mac2, mac_len)) {
93       SILC_LOG_DEBUG(("Message MAC does not match"));
94       return FALSE;
95     }
96     SILC_LOG_DEBUG(("MAC is Ok"));
97   }
98
99   /* Decrypt the message */
100   silc_cipher_decrypt(cipher, data, data, data_len - iv_len - mac_len,
101                       (iv_len ? data + (data_len - iv_len - mac_len) :
102                        silc_cipher_get_iv(cipher)));
103   return TRUE;
104 }
105
106 /* Parses Message Payload returning new payload structure.  This also
107    decrypts it and checks the MAC. */
108
109 SilcMessagePayload 
110 silc_message_payload_parse(unsigned char *payload,
111                            SilcUInt32 payload_len,
112                            bool private_message,
113                            bool static_key,
114                            SilcCipher cipher,
115                            SilcHmac hmac)
116 {
117   SilcBufferStruct buffer;
118   SilcMessagePayload newp;
119   int ret;
120   SilcUInt32 mac_len = 0, iv_len = 0;
121
122   SILC_LOG_DEBUG(("Parsing Message Payload"));
123
124   silc_buffer_set(&buffer, payload, payload_len);
125
126   /* Decrypt the payload */
127   if (cipher) {
128     ret = silc_message_payload_decrypt(buffer.data, buffer.len,
129                                        private_message, static_key,
130                                        cipher, hmac, TRUE);
131     if (ret == FALSE)
132       return NULL;
133   }
134
135   if (hmac)
136     mac_len = silc_hmac_len(hmac);
137
138   /* IV is present for channel messages and private messages when static
139      key (pre-shared key) is used. */
140   if (cipher && (!private_message || (private_message && static_key)))
141     iv_len = silc_cipher_get_block_len(cipher);
142
143   newp = silc_calloc(1, sizeof(*newp));
144   if (!newp)
145     return NULL;
146
147   /* Parse the Message Payload. */
148   ret = silc_buffer_unformat(&buffer,
149                              SILC_STR_UI_SHORT(&newp->flags),
150                              SILC_STR_UI16_NSTRING_ALLOC(&newp->data, 
151                                                          &newp->data_len),
152                              SILC_STR_UI16_NSTRING_ALLOC(&newp->pad, 
153                                                          &newp->pad_len),
154                              SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
155                              SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
156                              SILC_STR_END);
157   if (ret == -1)
158     goto err;
159
160   if ((newp->data_len > buffer.len - 6 - mac_len - iv_len) ||
161       (newp->pad_len + newp->data_len > buffer.len - 6 - mac_len - iv_len)) {
162     SILC_LOG_ERROR(("Incorrect Message Payload in packet"));
163     goto err;
164   }
165
166   newp->iv_len = iv_len;
167
168   return newp;
169
170  err:
171   silc_message_payload_free(newp);
172   return NULL;
173 }
174
175 /* This function is used to encrypt the Messsage Payload which is
176    the `data' and `data_len'.  This is used internally by the Message
177    Payload encoding routines but application may call this too if needed. 
178    The `data_len' is the data lenght which is used to create MAC out of. */
179
180 bool silc_message_payload_encrypt(unsigned char *data,
181                                   SilcUInt32 data_len,
182                                   unsigned char *iv,
183                                   SilcUInt32 iv_len,
184                                   SilcCipher cipher,
185                                   SilcHmac hmac)
186 {
187   unsigned char mac[32];
188   SilcUInt32 mac_len;
189   SilcBufferStruct buf;
190
191   /* Encrypt payload of the packet. If the IV is added to packet do
192      not encrypt that. */
193   silc_cipher_encrypt(cipher, data, data, data_len - iv_len,
194                       iv_len ? iv : silc_cipher_get_iv(cipher));
195
196   /* Compute the MAC of the encrypted message data */
197   silc_hmac_init(hmac);
198   silc_hmac_update(hmac, data, data_len);
199   silc_hmac_final(hmac, mac, &mac_len);
200
201   /* Put rest of the data to the payload */
202   silc_buffer_set(&buf, data, data_len + mac_len);
203   silc_buffer_pull(&buf, data_len);
204   silc_buffer_put(&buf, mac, mac_len);
205
206   return TRUE;
207 }
208
209 /* Encodes Message Payload into a buffer and returns it. */
210
211 SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
212                                        const unsigned char *data,
213                                        SilcUInt32 data_len,
214                                        bool generate_iv,
215                                        bool private_message,
216                                        SilcCipher cipher,
217                                        SilcHmac hmac,
218                                        SilcRng rng)
219 {
220   int i;
221   SilcBuffer buffer;
222   SilcUInt32 len, pad_len = 0, mac_len = 0, iv_len = 0;
223   unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
224
225   SILC_LOG_DEBUG(("Encoding Message Payload"));
226
227   if (!data_len)
228     return NULL;
229
230   /* For channel messages IV is always generated */
231   if (!private_message && !generate_iv)
232     generate_iv = TRUE;
233
234   /* Generate IV */
235   if (cipher && generate_iv) {
236     iv_len = silc_cipher_get_block_len(cipher);
237     if (rng) {
238       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng);
239     } else {
240       for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast();
241     }
242   }
243
244   if (hmac)
245     mac_len = silc_hmac_len(hmac);
246   data_len = SILC_MESSAGE_DATALEN(data_len, mac_len + iv_len);
247
248   /* Calculate length of padding. IV is not included into the calculation
249      since it is not encrypted. */
250   len = 6 + data_len;
251   pad_len = SILC_MESSAGE_PAD(len);
252
253   /* Allocate payload buffer */
254   len += pad_len + iv_len + mac_len;
255   buffer = silc_buffer_alloc(len);
256   if (!buffer)
257     return NULL;
258
259   /* Generate padding */
260   if (cipher) {
261     if (rng) {
262       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
263     } else {
264       for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
265     }
266   }
267
268   /* Encode the Message Payload */
269   silc_buffer_pull_tail(buffer, 6 + data_len + pad_len + iv_len);
270   silc_buffer_format(buffer, 
271                      SILC_STR_UI_SHORT(flags),
272                      SILC_STR_UI_SHORT(data_len),
273                      SILC_STR_UI_XNSTRING(data, data_len),
274                      SILC_STR_UI_SHORT(pad_len),
275                      SILC_STR_UI_XNSTRING(pad, pad_len),
276                      SILC_STR_UI_XNSTRING(iv, iv_len),
277                      SILC_STR_END);
278
279   memset(pad, 0, sizeof(pad));
280
281   /* Now encrypt the Message Payload */
282   if (cipher) {
283     if (!silc_message_payload_encrypt(buffer->data, buffer->len,
284                                       iv, iv_len, cipher, hmac)) {
285       silc_buffer_free(buffer);
286       return NULL;
287     }
288   }
289   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
290
291   return buffer;
292 }
293
294 /* Free's Message Payload */
295
296 void silc_message_payload_free(SilcMessagePayload payload)
297 {
298   if (payload->data) {
299     memset(payload->data, 0, payload->data_len);
300     silc_free(payload->data);
301   }
302   silc_free(payload->pad);
303   silc_free(payload);
304 }
305
306 /* Return flags */
307
308 SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload)
309 {
310   return payload->flags;
311 }
312
313 /* Return data */
314
315 unsigned char *silc_message_get_data(SilcMessagePayload payload,
316                                      SilcUInt32 *data_len)
317 {
318   if (data_len)
319     *data_len = payload->data_len;
320   return payload->data;
321 }
322
323 /* Return MAC. The caller knows the length of the MAC */
324
325 unsigned char *silc_message_get_mac(SilcMessagePayload payload)
326 {
327   return payload->mac;
328 }
329
330 /* Return IV. The caller knows the length of the IV */
331
332 unsigned char *silc_message_get_iv(SilcMessagePayload payload)
333 {
334   return payload->iv;
335 }
336
337 /******************************************************************************
338
339                      SILC_MESSAGE_FLAG_SIGNED Payload
340
341 ******************************************************************************/
342
343 /* The SILC_MESSAGE_FLAG_SIGNED Payload */
344 struct SilcMessageSignedPayloadStruct {
345   SilcUInt16 pk_len;
346   SilcUInt16 pk_type;
347   SilcUInt16 sign_len;
348   unsigned char *pk_data;
349   unsigned char *sign_data;
350 };
351
352 /* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */
353
354 static SilcBuffer
355 silc_message_signed_encode_data(const unsigned char *message_payload,
356                                 SilcUInt32 message_payload_len,
357                                 unsigned char *pk,
358                                 SilcUInt32 pk_len, SilcUInt32 pk_type)
359 {
360   SilcBuffer sign;
361
362   sign = silc_buffer_alloc_size(message_payload_len + 4 + pk_len);
363   if (!sign)
364     return NULL;
365
366   silc_buffer_format(sign,
367                      SILC_STR_UI_XNSTRING(message_payload,
368                                           message_payload_len),
369                      SILC_STR_UI_SHORT(pk_len),
370                      SILC_STR_UI_SHORT(pk_type),
371                      SILC_STR_END);
372
373   if (pk && pk_len) {
374     silc_buffer_pull(sign, message_payload_len + 4);
375     silc_buffer_format(sign,
376                        SILC_STR_UI_XNSTRING(pk, pk_len),
377                        SILC_STR_END);
378     silc_buffer_push(sign, message_payload_len + 4);
379   }
380
381   return sign;
382 }
383
384 /* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */
385
386 SilcMessageSignedPayload
387 silc_message_signed_payload_parse(const unsigned char *data,
388                                   SilcUInt32 data_len)
389 {
390   SilcMessageSignedPayload sig;
391   SilcBufferStruct buffer;
392   int ret;
393
394   SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload"));
395
396   silc_buffer_set(&buffer, (unsigned char *)data, data_len);
397   sig = silc_calloc(1, sizeof(*sig));
398   if (!sig)
399     return NULL;
400
401   /* Parse the payload */
402   ret = silc_buffer_unformat(&buffer,
403                              SILC_STR_UI_SHORT(&sig->pk_len),
404                              SILC_STR_UI_SHORT(&sig->pk_type),
405                              SILC_STR_END);
406   if (ret == -1 || sig->pk_len > data_len - 4) {
407     silc_message_signed_payload_free(sig);
408     return NULL;
409   }
410
411   silc_buffer_pull(&buffer, 4);
412   ret = silc_buffer_unformat(&buffer,
413                              SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data,
414                                                         sig->pk_len),
415                              SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data,
416                                                          &sig->sign_len),
417                              SILC_STR_END);
418   if (ret == -1) {
419     silc_message_signed_payload_free(sig);
420     return NULL;
421   }
422   silc_buffer_push(&buffer, 4);
423
424   /* Signature must be provided */
425   if (sig->sign_len < 1)  {
426     silc_message_signed_payload_free(sig);
427     return NULL;
428   }
429
430   return sig;
431 }
432
433 /* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital
434    signature. */
435
436 SilcBuffer
437 silc_message_signed_payload_encode(const unsigned char *message_payload,
438                                    SilcUInt32 message_payload_len,
439                                    SilcPublicKey public_key,
440                                    SilcPrivateKey private_key,
441                                    SilcHash hash,
442                                    bool include_public_key)
443 {
444   SilcBuffer buffer, sign;
445   SilcPKCS pkcs;
446   unsigned char auth_data[2048];
447   SilcUInt32 auth_len;
448   unsigned char *pk = NULL;
449   SilcUInt32 pk_len = 0;
450   SilcUInt16 pk_type;
451
452   if (!message_payload || !message_payload_len || !private_key || !hash)
453     return NULL;
454   if (include_public_key && !public_key)
455     return NULL;
456
457   if (include_public_key)
458     pk = silc_pkcs_public_key_encode(public_key, &pk_len);
459
460   /* Now we support only SILC style public key */
461   pk_type = SILC_SKE_PK_TYPE_SILC;
462
463   /* Encode the data to be signed */
464   sign = silc_message_signed_encode_data(message_payload,
465                                          message_payload_len,
466                                          pk, pk_len, pk_type);
467   if (!sign) {
468     silc_free(pk);
469     return NULL;
470   }
471
472   /* Sign the buffer */
473
474   /* Allocate PKCS object */
475   if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
476     silc_buffer_clear(sign);
477     silc_buffer_free(sign);
478     silc_free(pk);
479     return NULL;
480   }
481   silc_pkcs_private_key_set(pkcs, private_key);
482
483   /* Compute the hash and the signature. */
484   if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
485       !silc_pkcs_sign_with_hash(pkcs, hash, sign->data, sign->len, auth_data,
486                                 &auth_len)) {
487     silc_buffer_clear(sign);
488     silc_buffer_free(sign);
489     silc_pkcs_free(pkcs);
490     silc_free(pk);
491     return NULL;
492   }
493
494   /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
495
496   buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len);
497   if (!buffer) {
498     silc_buffer_clear(sign);
499     silc_buffer_free(sign);
500     silc_pkcs_free(pkcs);
501     memset(auth_data, 0, sizeof(auth_data));
502     silc_free(pk);
503     return NULL;
504   }
505
506   silc_buffer_format(sign,
507                      SILC_STR_UI_SHORT(pk_len),
508                      SILC_STR_UI_SHORT(pk_type),
509                      SILC_STR_END);
510
511   if (pk_len && pk) {
512     silc_buffer_pull(sign, 4);
513     silc_buffer_format(sign,
514                        SILC_STR_UI_XNSTRING(pk, pk_len),
515                        SILC_STR_END);
516     silc_buffer_push(sign, 4);
517   }
518
519   silc_buffer_pull(sign, 4 + pk_len);
520   silc_buffer_format(sign,
521                      SILC_STR_UI_SHORT(auth_len),
522                      SILC_STR_UI_XNSTRING(auth_data, auth_len),
523                      SILC_STR_END);
524   silc_buffer_push(sign, 4 + pk_len);
525
526   memset(auth_data, 0, sizeof(auth_data));
527   silc_pkcs_free(pkcs);
528   silc_buffer_clear(sign);
529   silc_buffer_free(sign);
530   silc_free(pk);
531
532   return buffer;
533 }
534
535 /* Free the payload */
536
537 void silc_message_signed_payload_free(SilcMessageSignedPayload sig)
538 {
539   if (sig) {
540     memset(sig->sign_data, 0, sig->sign_len);
541     silc_free(sig->sign_data);
542     silc_free(sig->pk_data);
543     silc_free(sig);
544   }
545 }
546
547 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
548
549 int silc_message_signed_verify(SilcMessageSignedPayload sig,
550                                SilcMessagePayload message,
551                                SilcPublicKey remote_public_key,
552                                SilcHash hash)
553 {
554   int ret = SILC_AUTH_FAILED;
555   SilcBuffer sign;
556   SilcPKCS pkcs;
557   SilcBuffer tmp;
558   
559   if (!sig || !remote_public_key || !hash)
560     return ret;
561
562   /* Generate the signature verification data, the Message Payload */
563   tmp = silc_buffer_alloc_size(6 + message->data_len + message->pad_len +
564                                message->iv_len);
565   silc_buffer_format(tmp,
566                      SILC_STR_UI_SHORT(message->flags),
567                      SILC_STR_UI_SHORT(message->data_len),
568                      SILC_STR_UI_XNSTRING(message->data, message->data_len),
569                      SILC_STR_UI_SHORT(message->pad_len),
570                      SILC_STR_UI_XNSTRING(message->pad, message->pad_len),
571                      SILC_STR_UI_XNSTRING(message->iv, message->iv_len),
572                      SILC_STR_END);
573   sign = silc_message_signed_encode_data(tmp->data, tmp->len,
574                                          sig->pk_data, sig->pk_len,
575                                          sig->pk_type);
576   silc_buffer_clear(tmp);
577   silc_buffer_free(tmp);
578   
579   if (!sign)
580     return ret;
581   
582   /* Allocate PKCS object */
583   if (!silc_pkcs_alloc(remote_public_key->name, &pkcs)) {
584     silc_buffer_clear(sign);
585     silc_buffer_free(sign);
586     return ret;
587   }
588   silc_pkcs_public_key_set(pkcs, remote_public_key);
589
590   /* Verify the authentication data */
591   if (!silc_pkcs_verify_with_hash(pkcs, hash, sig->sign_data,
592                                   sig->sign_len,
593                                   sign->data, sign->len)) {
594
595     silc_buffer_clear(sign);
596     silc_buffer_free(sign);
597     silc_pkcs_free(pkcs);
598     SILC_LOG_DEBUG(("Signature verification failed"));
599     return ret;
600   }
601
602   ret = SILC_AUTH_OK;
603
604   silc_buffer_clear(sign);
605   silc_buffer_free(sign);
606   silc_pkcs_free(pkcs);
607
608   SILC_LOG_DEBUG(("Signature verification successful"));
609
610   return ret;
611 }
612
613 /* Return the public key from the payload */
614
615 SilcPublicKey
616 silc_message_signed_get_public_key(SilcMessageSignedPayload sig)
617 {
618   SilcPublicKey pk;
619
620   if (!sig->pk_data || !silc_pkcs_public_key_decode(sig->pk_data,
621                                                     sig->pk_len, &pk))
622     return NULL;
623
624   return pk;
625 }