Removed signed payload encoding and parsing from public API,
authorPekka Riikonen <priikone@silcnet.org>
Sun, 5 Nov 2006 21:35:57 +0000 (21:35 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 5 Nov 2006 21:35:57 +0000 (21:35 +0000)
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
lib/silccore/silcmessage.h
lib/silccore/silcmessage_i.h [new file with mode: 0644]
lib/silccore/tests/test_silcmessage.c

index 6f6b1a9a3e037afda6a469a78e6186e401ff0244..c327e8ec5e787648bb81c47059f4a35bf17c6f96 100644 (file)
 /* 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;
index 186844f791adc3af7b8be3a4ff8191ca0703fe6e..09ca21aa8bc2bbff0dca4c71da69ef27f920257a 100644 (file)
  * 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
  *    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 (file)
index 0000000..30bee91
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+
+  silcmessage_i.h
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  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 */
index 47cdf2495309b99d644fff2b990d8428caeb848a..1f7d505229b8f0956bd3c9405801a82b392cd647 100644 (file)
@@ -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;