5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
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.
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.
19 /* Implementation of the Message Payload used as channel messages and
23 #include "silcincludes.h"
24 #include "silcmessage.h"
26 /******************************************************************************
30 ******************************************************************************/
32 /* Calculates padding length for message payload */
33 #define SILC_MESSAGE_PAD(__payloadlen) (16 - ((__payloadlen) % 16))
35 /* Header length plus maximum padding length */
36 #define SILC_MESSAGE_HLEN 6 + 16
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)
46 /* Message Payload structure. Contents of this structure is parsed
48 struct SilcMessagePayloadStruct {
49 SilcMessageFlags flags;
57 /*SilcMessageSignedPayload sig;*/
60 /* Decrypts the Message Payload. The `data' is the actual Message Payload */
62 bool silc_message_payload_decrypt(unsigned char *data,
70 SilcUInt32 mac_len = 0, iv_len = 0;
71 unsigned char *mac, mac2[32];
73 mac_len = silc_hmac_len(hmac);
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);
80 if (data_len < mac_len)
85 mac = data + (data_len - mac_len);
87 /* Check the MAC of the message */
88 SILC_LOG_DEBUG(("Checking message MAC"));
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"));
96 SILC_LOG_DEBUG(("MAC is Ok"));
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)));
106 /* Parses Message Payload returning new payload structure. This also
107 decrypts it and checks the MAC. */
110 silc_message_payload_parse(unsigned char *payload,
111 SilcUInt32 payload_len,
112 bool private_message,
117 SilcBufferStruct buffer;
118 SilcMessagePayload newp;
120 SilcUInt32 mac_len = 0, iv_len = 0;
122 SILC_LOG_DEBUG(("Parsing Message Payload"));
124 silc_buffer_set(&buffer, payload, payload_len);
126 /* Decrypt the payload */
128 ret = silc_message_payload_decrypt(buffer.data, buffer.len,
129 private_message, static_key,
136 mac_len = silc_hmac_len(hmac);
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);
143 newp = silc_calloc(1, sizeof(*newp));
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,
152 SILC_STR_UI16_NSTRING_ALLOC(&newp->pad,
154 SILC_STR_UI_XNSTRING(&newp->iv, iv_len),
155 SILC_STR_UI_XNSTRING(&newp->mac, mac_len),
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"));
166 newp->iv_len = iv_len;
171 silc_message_payload_free(newp);
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. */
180 bool silc_message_payload_encrypt(unsigned char *data,
187 unsigned char mac[32];
189 SilcBufferStruct buf;
191 /* Encrypt payload of the packet. If the IV is added to packet do
193 silc_cipher_encrypt(cipher, data, data, data_len - iv_len,
194 iv_len ? iv : silc_cipher_get_iv(cipher));
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);
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);
209 /* Encodes Message Payload into a buffer and returns it. */
211 SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
212 const unsigned char *data,
215 bool private_message,
222 SilcUInt32 len, pad_len = 0, mac_len = 0, iv_len = 0;
223 unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
225 SILC_LOG_DEBUG(("Encoding Message Payload"));
230 /* For channel messages IV is always generated */
231 if (!private_message && !generate_iv)
235 if (cipher && generate_iv) {
236 iv_len = silc_cipher_get_block_len(cipher);
238 for (i = 0; i < iv_len; i++) iv[i] = silc_rng_get_byte_fast(rng);
240 for (i = 0; i < iv_len; i++) iv[i] = silc_rng_global_get_byte_fast();
245 mac_len = silc_hmac_len(hmac);
246 data_len = SILC_MESSAGE_DATALEN(data_len, mac_len + iv_len);
248 /* Calculate length of padding. IV is not included into the calculation
249 since it is not encrypted. */
251 pad_len = SILC_MESSAGE_PAD(len);
253 /* Allocate payload buffer */
254 len += pad_len + iv_len + mac_len;
255 buffer = silc_buffer_alloc(len);
259 /* Generate padding */
262 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_get_byte_fast(rng);
264 for (i = 0; i < pad_len; i++) pad[i] = silc_rng_global_get_byte_fast();
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),
279 memset(pad, 0, sizeof(pad));
281 /* Now encrypt the Message Payload */
283 if (!silc_message_payload_encrypt(buffer->data, buffer->len,
284 iv, iv_len, cipher, hmac)) {
285 silc_buffer_free(buffer);
289 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer) - buffer->len);
294 /* Free's Message Payload */
296 void silc_message_payload_free(SilcMessagePayload payload)
299 memset(payload->data, 0, payload->data_len);
300 silc_free(payload->data);
302 silc_free(payload->pad);
308 SilcMessageFlags silc_message_get_flags(SilcMessagePayload payload)
310 return payload->flags;
315 unsigned char *silc_message_get_data(SilcMessagePayload payload,
316 SilcUInt32 *data_len)
319 *data_len = payload->data_len;
320 return payload->data;
323 /* Return MAC. The caller knows the length of the MAC */
325 unsigned char *silc_message_get_mac(SilcMessagePayload payload)
330 /* Return IV. The caller knows the length of the IV */
332 unsigned char *silc_message_get_iv(SilcMessagePayload payload)
337 /******************************************************************************
339 SILC_MESSAGE_FLAG_SIGNED Payload
341 ******************************************************************************/
343 /* The SILC_MESSAGE_FLAG_SIGNED Payload */
344 struct SilcMessageSignedPayloadStruct {
348 unsigned char *pk_data;
349 unsigned char *sign_data;
352 /* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */
355 silc_message_signed_encode_data(const unsigned char *message_payload,
356 SilcUInt32 message_payload_len,
358 SilcUInt32 pk_len, SilcUInt32 pk_type)
362 sign = silc_buffer_alloc_size(message_payload_len + 4 + pk_len);
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),
374 silc_buffer_pull(sign, message_payload_len + 4);
375 silc_buffer_format(sign,
376 SILC_STR_UI_XNSTRING(pk, pk_len),
378 silc_buffer_push(sign, message_payload_len + 4);
384 /* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */
386 SilcMessageSignedPayload
387 silc_message_signed_payload_parse(const unsigned char *data,
390 SilcMessageSignedPayload sig;
391 SilcBufferStruct buffer;
394 SILC_LOG_DEBUG(("Parsing SILC_MESSAGE_FLAG_SIGNED Payload"));
396 silc_buffer_set(&buffer, (unsigned char *)data, data_len);
397 sig = silc_calloc(1, sizeof(*sig));
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),
406 if (ret == -1 || sig->pk_len > data_len - 4) {
407 silc_message_signed_payload_free(sig);
411 silc_buffer_pull(&buffer, 4);
412 ret = silc_buffer_unformat(&buffer,
413 SILC_STR_UI_XNSTRING_ALLOC(&sig->pk_data,
415 SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data,
419 silc_message_signed_payload_free(sig);
422 silc_buffer_push(&buffer, 4);
424 /* Signature must be provided */
425 if (sig->sign_len < 1) {
426 silc_message_signed_payload_free(sig);
433 /* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital
437 silc_message_signed_payload_encode(const unsigned char *message_payload,
438 SilcUInt32 message_payload_len,
439 SilcPublicKey public_key,
440 SilcPrivateKey private_key,
442 bool include_public_key)
444 SilcBuffer buffer, sign;
446 unsigned char auth_data[2048];
448 unsigned char *pk = NULL;
449 SilcUInt32 pk_len = 0;
452 if (!message_payload || !message_payload_len || !private_key || !hash)
454 if (include_public_key && !public_key)
457 if (include_public_key)
458 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
460 /* Now we support only SILC style public key */
461 pk_type = SILC_SKE_PK_TYPE_SILC;
463 /* Encode the data to be signed */
464 sign = silc_message_signed_encode_data(message_payload,
466 pk, pk_len, pk_type);
472 /* Sign the buffer */
474 /* Allocate PKCS object */
475 if (!silc_pkcs_alloc(private_key->name, &pkcs)) {
476 silc_buffer_clear(sign);
477 silc_buffer_free(sign);
481 silc_pkcs_private_key_set(pkcs, private_key);
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,
487 silc_buffer_clear(sign);
488 silc_buffer_free(sign);
489 silc_pkcs_free(pkcs);
494 /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
496 buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len);
498 silc_buffer_clear(sign);
499 silc_buffer_free(sign);
500 silc_pkcs_free(pkcs);
501 memset(auth_data, 0, sizeof(auth_data));
506 silc_buffer_format(sign,
507 SILC_STR_UI_SHORT(pk_len),
508 SILC_STR_UI_SHORT(pk_type),
512 silc_buffer_pull(sign, 4);
513 silc_buffer_format(sign,
514 SILC_STR_UI_XNSTRING(pk, pk_len),
516 silc_buffer_push(sign, 4);
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),
524 silc_buffer_push(sign, 4 + pk_len);
526 memset(auth_data, 0, sizeof(auth_data));
527 silc_pkcs_free(pkcs);
528 silc_buffer_clear(sign);
529 silc_buffer_free(sign);
535 /* Free the payload */
537 void silc_message_signed_payload_free(SilcMessageSignedPayload sig)
540 memset(sig->sign_data, 0, sig->sign_len);
541 silc_free(sig->sign_data);
542 silc_free(sig->pk_data);
547 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
549 int silc_message_signed_verify(SilcMessageSignedPayload sig,
550 SilcMessagePayload message,
551 SilcPublicKey remote_public_key,
554 int ret = SILC_AUTH_FAILED;
559 if (!sig || !remote_public_key || !hash)
562 /* Generate the signature verification data, the Message Payload */
563 tmp = silc_buffer_alloc_size(6 + message->data_len + message->pad_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),
573 sign = silc_message_signed_encode_data(tmp->data, tmp->len,
574 sig->pk_data, sig->pk_len,
576 silc_buffer_clear(tmp);
577 silc_buffer_free(tmp);
582 /* Allocate PKCS object */
583 if (!silc_pkcs_alloc(remote_public_key->name, &pkcs)) {
584 silc_buffer_clear(sign);
585 silc_buffer_free(sign);
588 silc_pkcs_public_key_set(pkcs, remote_public_key);
590 /* Verify the authentication data */
591 if (!silc_pkcs_verify_with_hash(pkcs, hash, sig->sign_data,
593 sign->data, sign->len)) {
595 silc_buffer_clear(sign);
596 silc_buffer_free(sign);
597 silc_pkcs_free(pkcs);
598 SILC_LOG_DEBUG(("Signature verification failed"));
604 silc_buffer_clear(sign);
605 silc_buffer_free(sign);
606 silc_pkcs_free(pkcs);
608 SILC_LOG_DEBUG(("Signature verification successful"));
613 /* Return the public key from the payload */
616 silc_message_signed_get_public_key(SilcMessageSignedPayload sig)
620 if (!sig->pk_data || !silc_pkcs_public_key_decode(sig->pk_data,