From 25fc6127772a2cefdebd1a11600365d1647c8a04 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 5 Nov 2006 21:35:57 +0000 Subject: [PATCH] Removed signed payload encoding and parsing from public API, it's now done internally only. Added support for pre-allocated SilcMessagePayload in parsing to make parsing without memory allocations. Added SilcStack support also. --- lib/silccore/silcmessage.c | 541 +++++++++++++------------- lib/silccore/silcmessage.h | 174 ++------- lib/silccore/silcmessage_i.h | 49 +++ lib/silccore/tests/test_silcmessage.c | 97 +++-- 4 files changed, 433 insertions(+), 428 deletions(-) create mode 100644 lib/silccore/silcmessage_i.h diff --git a/lib/silccore/silcmessage.c b/lib/silccore/silcmessage.c index 6f6b1a9a..c327e8ec 100644 --- a/lib/silccore/silcmessage.c +++ b/lib/silccore/silcmessage.c @@ -31,26 +31,8 @@ /* Header length plus maximum padding length */ #define SILC_MESSAGE_HLEN 6 + 16 -/* Returns the data length that fits to the packet. If data length is too - big it will be truncated to fit to the payload. */ -#define SILC_MESSAGE_DATALEN(data_len, header_len) \ - ((data_len + SILC_MESSAGE_HLEN + header_len) > \ - SILC_PACKET_MAX_LEN ? \ - data_len - ((data_len + SILC_MESSAGE_HLEN + header_len) - \ - SILC_PACKET_MAX_LEN) : data_len) - -/* Message Payload structure. Contents of this structure is parsed - from SILC packets. */ -struct SilcMessagePayloadStruct { - SilcMessageFlags flags; - SilcUInt16 data_len; - SilcUInt16 pad_len; - SilcUInt16 iv_len; - unsigned char *data; - unsigned char *pad; - unsigned char *mac; - SilcMessageSignedPayload sig; -}; +/* Maximum message length */ +#define SILC_MESSAGE_MAX_LEN SILC_PACKET_MAX_LEN - SILC_MESSAGE_HLEN - 16 /* Payload encoding context */ typedef struct { @@ -65,7 +47,217 @@ typedef struct { } SilcMessageEncode; -/****************************** Payload parsing *****************************/ +/************************* Static utility functions *************************/ + +/* 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 (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(const unsigned char *message_payload, + SilcUInt32 message_payload_len, + unsigned char *pk, + SilcUInt32 pk_len, SilcUInt32 pk_type) +{ + SilcBuffer sign; + + sign = silc_buffer_alloc_size(message_payload_len + 4 + pk_len); + if (!sign) + return NULL; + + silc_buffer_format(sign, + SILC_STR_UI_XNSTRING(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_format(sign, + SILC_STR_UI_XNSTRING(pk, pk_len), + SILC_STR_END); + silc_buffer_push(sign, message_payload_len + 4); + } + + return sign; +} + +/* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital + signature. */ + +static SilcBuffer +silc_message_signed_payload_encode(const unsigned char *message_payload, + SilcUInt32 message_payload_len, + SilcPublicKey public_key, + SilcPrivateKey private_key, + SilcHash hash) +{ + SilcBuffer buffer, sign; + unsigned char auth_data[2048 + 1]; + SilcUInt32 auth_len; + unsigned char *pk = NULL; + SilcUInt32 pk_len = 0; + SilcUInt16 pk_type; + + if (!message_payload || !message_payload_len || !private_key || !hash) + return NULL; + + if (public_key) { + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + if (!pk) + return NULL; + } + pk_type = silc_pkcs_get_type(public_key); + + /* Encode the data to be signed */ + sign = silc_message_signed_encode_data(message_payload, + message_payload_len, + pk, pk_len, pk_type); + if (!sign) { + silc_free(pk); + return NULL; + } + + /* Sign the buffer */ + + /* Compute the hash and the signature. */ + if (!silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign), + auth_data, sizeof(auth_data) - 1, &auth_len, hash)) { + SILC_LOG_ERROR(("Could not compute signature")); + silc_buffer_clear(sign); + silc_buffer_free(sign); + silc_free(pk); + return NULL; + } + + /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */ + + buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len); + if (!buffer) { + silc_buffer_clear(sign); + silc_buffer_free(sign); + memset(auth_data, 0, sizeof(auth_data)); + silc_free(pk); + return NULL; + } + + silc_buffer_format(buffer, + SILC_STR_UI_SHORT(pk_len), + SILC_STR_UI_SHORT(pk_type), + SILC_STR_END); + + if (pk_len && pk) { + silc_buffer_pull(buffer, 4); + silc_buffer_format(buffer, + SILC_STR_UI_XNSTRING(pk, pk_len), + SILC_STR_END); + silc_buffer_push(buffer, 4); + } + + silc_buffer_pull(buffer, 4 + pk_len); + silc_buffer_format(buffer, + SILC_STR_UI_SHORT(auth_len), + SILC_STR_UI_XNSTRING(auth_data, auth_len), + SILC_STR_END); + silc_buffer_push(buffer, 4 + pk_len); + + SILC_LOG_HEXDUMP(("sig payload"), buffer->data, silc_buffer_len(buffer)); + + memset(auth_data, 0, sizeof(auth_data)); + silc_buffer_clear(sign); + silc_buffer_free(sign); + silc_free(pk); + + return buffer; +} + + +/***************************** Payload parsing ******************************/ /* Decrypts the Message Payload. The `data' is the actual Message Payload. */ @@ -142,10 +334,13 @@ silc_message_payload_parse(unsigned char *payload, SilcBool private_message, SilcBool static_key, SilcCipher cipher, - SilcHmac hmac) + SilcHmac hmac, + SilcStack stack, + SilcBool no_allocation, + SilcMessagePayload message) { SilcBufferStruct buffer; - SilcMessagePayload newp; + SilcMessagePayload newp = NULL; int ret; SilcUInt32 mac_len = 0, iv_len = 0; @@ -170,48 +365,65 @@ silc_message_payload_parse(unsigned char *payload, if (cipher && (!private_message || (private_message && static_key))) iv_len = silc_cipher_get_block_len(cipher); - newp = silc_calloc(1, sizeof(*newp)); - if (!newp) - return NULL; + if (!message) { + newp = message = silc_calloc(1, sizeof(*newp)); + if (!newp) + return NULL; + } + memset(message, 0, sizeof(*message)); + message->allocated = (stack || no_allocation ? FALSE : TRUE); /* Parse the Message Payload. */ - ret = silc_buffer_unformat(&buffer, - SILC_STR_UI_SHORT(&newp->flags), - SILC_STR_UI16_NSTRING_ALLOC(&newp->data, - &newp->data_len), - SILC_STR_UI16_NSTRING_ALLOC(&newp->pad, - &newp->pad_len), - SILC_STR_END); + 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 (ret == -1) goto err; - if ((newp->data_len > silc_buffer_len(&buffer) - 6 - mac_len - iv_len) || - (newp->pad_len + newp->data_len > silc_buffer_len(&buffer) - + if ((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 (newp->flags & SILC_MESSAGE_FLAG_SIGNED && - newp->data_len + newp->pad_len + 6 + mac_len + + if (message->flags & SILC_MESSAGE_FLAG_SIGNED && + message->data_len + message->pad_len + 6 + mac_len + iv_len < silc_buffer_len(&buffer)) { - newp->sig = - silc_message_signed_payload_parse(buffer.data + 6 + newp->data_len + - newp->pad_len, - silc_buffer_len(&buffer) - - iv_len - mac_len - 6 - newp->data_len - - newp->pad_len); + 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) - newp->mac = buffer.data + (silc_buffer_len(&buffer) - mac_len); + message->mac = buffer.data + (silc_buffer_len(&buffer) - mac_len); return newp; err: - silc_message_payload_free(newp); + if (newp) + silc_message_payload_free(newp); return NULL; } @@ -349,7 +561,8 @@ SilcBuffer silc_message_payload_encode(SilcMessageFlags flags, if (hmac) mac_len = silc_hmac_len(hmac); - data_len = SILC_MESSAGE_DATALEN(data_len, mac_len + iv_len); + 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. */ @@ -399,12 +612,14 @@ void silc_message_payload_free(SilcMessagePayload payload) { if (payload->data) { memset(payload->data, 0, payload->data_len); - silc_free(payload->data); + if (payload->allocated) + silc_free(payload->data); + } + if (payload->allocated) { + silc_free(payload->pad); + silc_free(payload); } - if (payload->sig) - silc_message_signed_payload_free(payload->sig); - silc_free(payload->pad); - silc_free(payload); + silc_message_signed_payload_free(&payload->sig); } /* Return flags */ @@ -431,225 +646,18 @@ unsigned char *silc_message_get_mac(SilcMessagePayload payload) return payload->mac; } -/* Return signature of the message */ - -SilcMessageSignedPayload -silc_message_get_signature(SilcMessagePayload payload) -{ - return payload->sig; -} - - -/************************ Message Signature Payload *************************/ - -/* The SILC_MESSAGE_FLAG_SIGNED Payload */ -struct SilcMessageSignedPayloadStruct { - SilcUInt16 pk_len; - SilcUInt16 pk_type; - SilcUInt16 sign_len; - unsigned char *pk_data; - unsigned char *sign_data; -}; - -/* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */ - -static SilcBuffer -silc_message_signed_encode_data(const unsigned char *message_payload, - SilcUInt32 message_payload_len, - unsigned char *pk, - SilcUInt32 pk_len, SilcUInt32 pk_type) -{ - SilcBuffer sign; - - sign = silc_buffer_alloc_size(message_payload_len + 4 + pk_len); - if (!sign) - return NULL; - - silc_buffer_format(sign, - SILC_STR_UI_XNSTRING(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_format(sign, - SILC_STR_UI_XNSTRING(pk, pk_len), - SILC_STR_END); - silc_buffer_push(sign, message_payload_len + 4); - } - - return sign; -} - -/* Parses the SILC_MESSAGE_FLAG_SIGNED Payload */ - -SilcMessageSignedPayload -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); - sig = silc_calloc(1, sizeof(*sig)); - if (!sig) - return NULL; - - /* 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_message_signed_payload_free(sig); - SILC_LOG_DEBUG(("Malformed public key in SILC_MESSAGE_FLAG_SIGNED " - "Payload")); - return NULL; - } - - 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 NULL; - } - 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 NULL; - } - - return sig; -} - -/* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital - signature. */ - -SilcBuffer -silc_message_signed_payload_encode(const unsigned char *message_payload, - SilcUInt32 message_payload_len, - SilcPublicKey public_key, - SilcPrivateKey private_key, - SilcHash hash) -{ - SilcBuffer buffer, sign; - unsigned char auth_data[2048 + 1]; - SilcUInt32 auth_len; - unsigned char *pk = NULL; - SilcUInt32 pk_len = 0; - SilcUInt16 pk_type; - - if (!message_payload || !message_payload_len || !private_key || !hash) - return NULL; - - if (public_key) { - pk = silc_pkcs_public_key_encode(public_key, &pk_len); - if (!pk) - return NULL; - } - pk_type = silc_pkcs_get_type(public_key); - - /* Encode the data to be signed */ - sign = silc_message_signed_encode_data(message_payload, - message_payload_len, - pk, pk_len, pk_type); - if (!sign) { - silc_free(pk); - return NULL; - } - - /* Sign the buffer */ - - /* Compute the hash and the signature. */ - if (!silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign), - auth_data, sizeof(auth_data) - 1, &auth_len, hash)) { - SILC_LOG_ERROR(("Could not compute signature")); - silc_buffer_clear(sign); - silc_buffer_free(sign); - silc_free(pk); - return NULL; - } - - /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */ - - buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len); - if (!buffer) { - silc_buffer_clear(sign); - silc_buffer_free(sign); - memset(auth_data, 0, sizeof(auth_data)); - silc_free(pk); - return NULL; - } - - silc_buffer_format(buffer, - SILC_STR_UI_SHORT(pk_len), - SILC_STR_UI_SHORT(pk_type), - SILC_STR_END); - - if (pk_len && pk) { - silc_buffer_pull(buffer, 4); - silc_buffer_format(buffer, - SILC_STR_UI_XNSTRING(pk, pk_len), - SILC_STR_END); - silc_buffer_push(buffer, 4); - } - - silc_buffer_pull(buffer, 4 + pk_len); - silc_buffer_format(buffer, - SILC_STR_UI_SHORT(auth_len), - SILC_STR_UI_XNSTRING(auth_data, auth_len), - SILC_STR_END); - silc_buffer_push(buffer, 4 + pk_len); - - SILC_LOG_HEXDUMP(("sig payload"), buffer->data, silc_buffer_len(buffer)); - - memset(auth_data, 0, sizeof(auth_data)); - silc_buffer_clear(sign); - silc_buffer_free(sign); - silc_free(pk); - - return buffer; -} - -/* Free the payload */ - -void silc_message_signed_payload_free(SilcMessageSignedPayload sig) -{ - memset(sig->sign_data, 0, sig->sign_len); - silc_free(sig->sign_data); - silc_free(sig->pk_data); - silc_free(sig); -} - /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */ -int silc_message_signed_verify(SilcMessageSignedPayload sig, - SilcMessagePayload message, +int silc_message_signed_verify(SilcMessagePayload message, SilcPublicKey remote_public_key, SilcHash hash) { int ret = SILC_AUTH_FAILED; SilcBuffer sign, tmp; + SilcMessageSignedPayload sig = &message->sig; - if (!sig || !remote_public_key || !hash) + if (!(message->flags & SILC_MESSAGE_FLAG_SIGNED) || + !sig->sign_len || !remote_public_key || !hash) return ret; /* Generate the signature verification data, the Message Payload */ @@ -671,10 +679,8 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig, return ret; /* Verify the authentication data */ - if (!silc_pkcs_verify(remote_public_key, sig->sign_data, - sig->sign_len, - sign->data, silc_buffer_len(sign), hash)) { - + if (!silc_pkcs_verify(remote_public_key, sig->sign_data, sig->sign_len, + silc_buffer_data(sign), silc_buffer_len(sign), hash)) { silc_buffer_clear(sign); silc_buffer_free(sign); SILC_LOG_DEBUG(("Signature verification failed")); @@ -694,11 +700,12 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig, /* Return the public key from the payload */ SilcPublicKey -silc_message_signed_get_public_key(SilcMessageSignedPayload sig, +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; diff --git a/lib/silccore/silcmessage.h b/lib/silccore/silcmessage.h index 186844f7..09ca21aa 100644 --- a/lib/silccore/silcmessage.h +++ b/lib/silccore/silcmessage.h @@ -22,12 +22,10 @@ * DESCRIPTION * * This interface includes the implementation of the Message Payload that - * is used to send private messages and channel messages. - * - * This interface defines also the SILC_MESSAGE_FLAG_SIGNED Payload, - * which defines how channel messages and private messages can be digitally - * signed. This interface provides the payload parsing, encoding, - * signature computing and signature verification routines. + * is used to send private messages and channel messages. The interface + * is also able to automatically provide digital signature in the messages + * if it is requested. Message digital signatures may also be verified with + * this interface. * ***/ @@ -38,7 +36,8 @@ * * NAME * - * typedef struct SilcMessagePayloadStruct *SilcMessagePayload; + * typedef struct SilcMessagePayloadObject + * *SilcMessagePayload, SilcMessagePayloadStruct; * * * DESCRIPTION @@ -49,26 +48,8 @@ * silc_message_payload_free function. * ***/ -typedef struct SilcMessagePayloadStruct *SilcMessagePayload; - -/****s* silccore/SilcMessageAPI/SilcMessageSignedPayload - * - * NAME - * - * typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload; - * - * - * DESCRIPTION - * - * This context represents the SILC_MESSAGE_FLAG_SIGNED Payload which - * is used with channel messages and private messages to indicate that - * the message is digitally signed. This payload may include the - * message sender's public key and it includes the digital signature. - * This payload MUST NOT be used in any other context except with - * channel and private message sending and reception. - * - ***/ -typedef struct SilcMessageSignedPayloadStruct *SilcMessageSignedPayload; +typedef struct SilcMessagePayloadObject + *SilcMessagePayload, SilcMessagePayloadStruct; /****d* silccore/SilcMessageAPI/SilcMessageFlags * @@ -149,7 +130,10 @@ SilcBool silc_message_payload_decrypt(unsigned char *data, * SilcBool private_message, * SilcBool static_key, * SilcCipher cipher, - * SilcHmac hmac); + * SilcHmac hmac, + * SilcStack stack, + * SilcBool no_allocation, + * SilcMessagePayload message); * * DESCRIPTION * @@ -167,6 +151,14 @@ SilcBool silc_message_payload_decrypt(unsigned char *data, * then this assumes that the packet was decrypted with session keys * (no private message key) and this merely decodes the payload. * + * If the `message' is non-NULL then that pre-allocated context is + * used in parsing. Same context is returned. Otherwise new context + * is allocated and returned. If the `stack' is non-NULL then memory + * is allocated from that stack. If `no_allocation' is TRUE then the + * `message' must be provided and data is merely parsed and referenced + * from `payload' and will become invalid when `payload' invalidates. + * If `no_allocation' is TRUE the routine does not do any allocations. + * ***/ SilcMessagePayload silc_message_payload_parse(unsigned char *payload, @@ -174,7 +166,10 @@ silc_message_payload_parse(unsigned char *payload, SilcBool private_message, SilcBool static_key, SilcCipher cipher, - SilcHmac hmac); + SilcHmac hmac, + SilcStack stack, + SilcBool no_allocation, + SilcMessagePayload message); /****f* silccore/SilcMessageAPI/silc_message_payload_encrypt * @@ -330,116 +325,23 @@ unsigned char *silc_message_get_data(SilcMessagePayload payload, ***/ unsigned char *silc_message_get_mac(SilcMessagePayload payload); -/****f* silccore/SilcMessageAPI/silc_message_get_signature - * - * SYNOPSIS - * - * SilcMessageSignedPayload - * silc_message_get_signature(SilcMessagePayload payload); - * - * DESCRIPTION - * - * Returns the pointer to the signature of the message if the - * SILC_MESSAGE_FLAG_SIGNED was set. If the flag is set and this - * function returns NULL then error had occurred and the signature - * could not be retrieved from the message. - * - * The caller SHOULD verify the signature by calling the - * silc_message_signed_verify function. Caller must not free the - * returned payload pointer. - * - ***/ -SilcMessageSignedPayload -silc_message_get_signature(SilcMessagePayload payload); - -/****f* silccore/SilcMessageAPI/silc_message_signed_payload_parse - * - * SYNOPSIS - * - * SilcMessageSignedPayload - * silc_message_signed_payload_parse(const unsigned char *data, - * SilcUInt32 data_len); - * - * DESCRIPTION - * - * Parses the SilcMessageSignedPayload Payload from the `data' of - * length of `data_len' bytes. The `data' must be payload without - * the actual message payload. Returns the parsed payload or NULL - * on error. Caller must free the returned payload. Application - * usually does not need to call this since the function - * silc_message_payload_parse calls this automatically for signed - * messages. - * - ***/ -SilcMessageSignedPayload -silc_message_signed_payload_parse(const unsigned char *data, - SilcUInt32 data_len); - -/****f* silccore/SilcMessageAPI/silc_message_signed_payload_encode - * - * SYNOPSIS - * - * SilcBuffer - * silc_message_signed_payload_encode(const unsigned char *message_payload, - * SilcUInt32 message_payload_len, - * SilcPublicKey public_key, - * SilcPrivateKey private_key, - * SilcHash hash); - * - * DESCRIPTION - * - * Encodes the SilcMessageSignedPayload Payload and computes the - * digital signature. The `message_payload' is the message data that - * is used in the signature computation. The encoding of the buffer - * is specified in the SILC protocol. If `public_key' is provided - * then the public key included in the payload. The `private_key' - * is used to produce the signature. This function returns the encoded - * payload with the signature or NULL on error. Caller must free the - * returned buffer. The `hash' SHOULD be SHA-1 hash function. - * - * Application usually does not need to call this since the function - * silc_message_payload_encode calls this automatically if the caller - * wants to sign the message. - * - ***/ -SilcBuffer -silc_message_signed_payload_encode(const unsigned char *message_payload, - SilcUInt32 message_payload_len, - SilcPublicKey public_key, - SilcPrivateKey private_key, - SilcHash hash); - -/****f* silccore/SilcMessageAPI/silc_message_signed_payload_free - * - * SYNOPSIS - * - * void silc_message_signed_payload_free(SilcMessageSignedPayload sig); - * - * DESCRIPTION - * - * Frees the SilcMessageSignedPayload Payload. - * - ***/ -void silc_message_signed_payload_free(SilcMessageSignedPayload sig); - /****f* silccore/SilcMessageAPI/silc_message_signed_verify * * SYNOPSIS * - * int silc_message_signed_verify(SilcMessageSignedPayload sig, - * SilcMessagePayload message, + * int silc_message_signed_verify(SilcMessagePayload message, * SilcPublicKey remote_public_key, * SilcHash hash); * * DESCRIPTION * - * This routine can be used to verify the signature found in - * SilcMessageSignedPayload Payload. This returns SILC_AUTH_OK if the - * signature verification was successful. + * This routine can be used to verify the digital signature from the + * message indicated by `message'. The signature is present only if + * the SILC_MESSAGE_FLAG_SIGNED is set in the message flags. This + * returns SILC_AUTH_OK if the signature verification was successful. * ***/ -int silc_message_signed_verify(SilcMessageSignedPayload sig, - SilcMessagePayload message, +int silc_message_signed_verify(SilcMessagePayload message, SilcPublicKey remote_public_key, SilcHash hash); @@ -448,22 +350,24 @@ int silc_message_signed_verify(SilcMessageSignedPayload sig, * SYNOPSIS * * SilcPublicKey - * silc_message_signed_get_public_key(SilcMessageSignedPayload sig, + * silc_message_signed_get_public_key(SilcMessagePayload payload, * const unsigned char **pk_data, * SilcUInt32 *pk_data_len); * * DESCRIPTION * - * Returns the decoded SilcPublicKey from the SilcMessageSignedPayload - * Payload or NULL if it does not include public key. The caller must - * free the returned public key pointer. This also returns the raw - * public key (before decoding) into `pk_data' and `pk_data_len' if - * they are provided. The caller must not free these pointers. + * Returns the decoded SilcPublicKey from the message payload or NULL + * if it does not include public key. The caller must free the returned + * public key pointer. This also returns the raw public key (before + * decoding) into `pk_data' and `pk_data_len' if they are provided. The + * caller must not free these pointers. * ***/ SilcPublicKey -silc_message_signed_get_public_key(SilcMessageSignedPayload sig, +silc_message_signed_get_public_key(SilcMessagePayload payload, const unsigned char **pk_data, SilcUInt32 *pk_data_len); +#include "silcmessage_i.h" + #endif /* SILCMESSAGE_H */ diff --git a/lib/silccore/silcmessage_i.h b/lib/silccore/silcmessage_i.h new file mode 100644 index 00000000..30bee91b --- /dev/null +++ b/lib/silccore/silcmessage_i.h @@ -0,0 +1,49 @@ +/* + + silcmessage_i.h + + Author: Pekka Riikonen + + Copyright (C) 2006 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. + +*/ + +#ifndef SILCMESSAGE_I_H +#define SILCMESSAGE_I_H + +#ifndef SILCMESSAGE_I_H +#error "Do not include this header directly" +#endif + +/* The SILC_MESSAGE_FLAG_SIGNED Payload */ +typedef struct SilcMessageSignedPayloadStruct { + unsigned char *pk_data; + unsigned char *sign_data; + SilcUInt16 pk_len; + SilcUInt16 pk_type; + SilcUInt16 sign_len; +} *SilcMessageSignedPayload; + +/* Message Payload structure. */ +struct SilcMessagePayloadObject { + unsigned char *data; + unsigned char *pad; + unsigned char *mac; + struct SilcMessageSignedPayloadStruct sig; + SilcMessageFlags flags; + SilcUInt16 data_len; + SilcUInt16 pad_len; + SilcUInt16 iv_len; + unsigned int allocated : 1; +}; + +#endif /* SILCMESSAGE_I_H */ diff --git a/lib/silccore/tests/test_silcmessage.c b/lib/silccore/tests/test_silcmessage.c index 47cdf249..1f7d5052 100644 --- a/lib/silccore/tests/test_silcmessage.c +++ b/lib/silccore/tests/test_silcmessage.c @@ -16,11 +16,10 @@ int main(int argc, char **argv) SilcMessagePayload message; SilcBuffer buf; const char *msg = "FOOBAR MESSAGE"; - unsigned char *data, tmp[1023]; + unsigned char *data, tmp[1023], *tmp2; SilcUInt32 data_len; SilcUInt16 flags; int i, n; - SilcMessageSignedPayload sig; if (argc > 1 && !strcmp(argv[1], "-d")) { silc_log_debug(TRUE); @@ -78,7 +77,7 @@ int main(int argc, char **argv) SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, TRUE, - key, hmac); + key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); @@ -111,7 +110,7 @@ int main(int argc, char **argv) SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, TRUE, - key, hmac); + key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); @@ -144,7 +143,7 @@ int main(int argc, char **argv) SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, TRUE, - key, hmac); + key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); @@ -179,7 +178,7 @@ int main(int argc, char **argv) SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, TRUE, - key, hmac); + key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); @@ -216,7 +215,7 @@ int main(int argc, char **argv) SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, TRUE, - key, hmac); + key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); @@ -235,17 +234,13 @@ int main(int argc, char **argv) goto err; SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message), silc_hmac_len(hmac)); - SILC_LOG_DEBUG(("Get signature")); - sig = silc_message_get_signature(message); - if (!sig) - goto err; SILC_LOG_DEBUG(("Verifying signature")); - if (silc_message_signed_verify(sig, message, public_key, hash) != + if (silc_message_signed_verify(message, public_key, hash) != SILC_AUTH_OK) goto err; SILC_LOG_DEBUG(("Signature Ok")); SILC_LOG_DEBUG(("Get public key")); - pk2 = silc_message_signed_get_public_key(sig, NULL, NULL); + pk2 = silc_message_signed_get_public_key(message, NULL, NULL); if (!pk2) goto err; SILC_LOG_DEBUG(("Verify public key")); @@ -273,7 +268,7 @@ int main(int argc, char **argv) SILC_LOG_DEBUG(("Parsing channel messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), FALSE, TRUE, - key, hmac); + key, hmac, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); @@ -292,17 +287,13 @@ int main(int argc, char **argv) goto err; SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message), silc_hmac_len(hmac)); - SILC_LOG_DEBUG(("Get signature")); - sig = silc_message_get_signature(message); - if (!sig) - goto err; SILC_LOG_DEBUG(("Verifying signature")); - if (silc_message_signed_verify(sig, message, public_key, hash) != + if (silc_message_signed_verify(message, public_key, hash) != SILC_AUTH_OK) goto err; SILC_LOG_DEBUG(("Signature Ok")); SILC_LOG_DEBUG(("Get public key")); - pk2 = silc_message_signed_get_public_key(sig, NULL, NULL); + pk2 = silc_message_signed_get_public_key(message, NULL, NULL); if (!pk2) goto err; SILC_LOG_DEBUG(("Verify public key")); @@ -330,7 +321,7 @@ int main(int argc, char **argv) SILC_LOG_DEBUG(("Parsing private messsage (static key)")); message = silc_message_payload_parse(silc_buffer_data(buf), silc_buffer_len(buf), TRUE, FALSE, - NULL, NULL); + NULL, NULL, NULL, FALSE, NULL); if (!message) goto err; flags = silc_message_get_flags(message); @@ -347,17 +338,70 @@ int main(int argc, char **argv) SILC_LOG_HEXDUMP(("Data"), data, data_len); if (data_len != sizeof(tmp) / 2 || memcmp(data, tmp, sizeof(tmp) / 2)) goto err; - SILC_LOG_DEBUG(("Get signature")); - sig = silc_message_get_signature(message); - if (!sig) + SILC_LOG_DEBUG(("Verifying signature")); + if (silc_message_signed_verify(message, public_key, hash) != + SILC_AUTH_OK) + goto err; + SILC_LOG_DEBUG(("Signature Ok")); + SILC_LOG_DEBUG(("Get public key")); + pk2 = silc_message_signed_get_public_key(message, NULL, NULL); + if (!pk2) + goto err; + SILC_LOG_DEBUG(("Verify public key")); + if (!silc_pkcs_public_key_compare(public_key, pk2)) + goto err; + SILC_LOG_DEBUG(("Public key Ok")); + silc_pkcs_public_key_free(pk2); + silc_message_payload_free(message); + + /* Digitally signed channel message (LARGE) */ + n = 65550; + tmp2 = silc_malloc(n); + if (!tmp2) + goto err; + SILC_LOG_DEBUG(("Encoding channel message len %d (static key) SIGNED LARGE", + n)); + buf = silc_message_payload_encode(SILC_MESSAGE_FLAG_ACTION | + SILC_MESSAGE_FLAG_UTF8 | + SILC_MESSAGE_FLAG_ACK | + SILC_MESSAGE_FLAG_SIGNED, + tmp2, n, TRUE, FALSE, + key, hmac, rng, + public_key, private_key, hash, buf); + if (!buf) + goto err; + SILC_LOG_DEBUG(("Message length: %d", silc_buffer_len(buf))); + if (silc_buffer_len(buf) > SILC_PACKET_MAX_LEN) + goto err; + SILC_LOG_DEBUG(("Parsing channel messsage (static key)")); + message = silc_message_payload_parse(silc_buffer_data(buf), + silc_buffer_len(buf), FALSE, TRUE, + key, hmac, NULL, FALSE, NULL); + if (!message) + goto err; + flags = silc_message_get_flags(message); + SILC_LOG_DEBUG(("Flags: %x", flags)); + if (!(flags & SILC_MESSAGE_FLAG_ACTION)) + goto err; + if (!(flags & SILC_MESSAGE_FLAG_UTF8)) + goto err; + if (!(flags & SILC_MESSAGE_FLAG_ACK)) goto err; + if (!(flags & SILC_MESSAGE_FLAG_SIGNED)) + goto err; + data = silc_message_get_data(message, &data_len); + SILC_LOG_DEBUG(("Data len: %d", data_len)); + if (silc_buffer_len(buf) > SILC_PACKET_MAX_LEN) + goto err; + SILC_LOG_HEXDUMP(("MAC"), silc_message_get_mac(message), + silc_hmac_len(hmac)); SILC_LOG_DEBUG(("Verifying signature")); - if (silc_message_signed_verify(sig, message, public_key, hash) != + if (silc_message_signed_verify(message, public_key, hash) != SILC_AUTH_OK) goto err; SILC_LOG_DEBUG(("Signature Ok")); SILC_LOG_DEBUG(("Get public key")); - pk2 = silc_message_signed_get_public_key(sig, NULL, NULL); + pk2 = silc_message_signed_get_public_key(message, NULL, NULL); if (!pk2) goto err; SILC_LOG_DEBUG(("Verify public key")); @@ -366,6 +410,7 @@ int main(int argc, char **argv) SILC_LOG_DEBUG(("Public key Ok")); silc_pkcs_public_key_free(pk2); silc_message_payload_free(message); + silc_free(tmp2); success = TRUE; -- 2.24.0