[Pkg-privacy-commits] [libotr] 12/225: * Protocol: Added section describing fragments.

Ximin Luo infinity0 at moszumanska.debian.org
Sat Aug 22 12:44:44 UTC 2015


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch master
in repository libotr.

commit 67b9ce49aeb9d2cb6f8680dd40fb795dd9ca1ed7
Author: cypherpunk <cypherpunk>
Date:   Thu Aug 4 16:39:48 2005 +0000

    	* Protocol: Added section describing fragments.
    
    	* src/proto.h:
    	* src/proto.c (otrl_proto_fragment_accumulate):
    	* src/context.h:
    	* src/context.c (new_context, otrl_context_force_setup): Keep
    	track of fragments in the ConnContext structure.
    
    	* src/message.c (otrl_message_receiving): Handle fragments in
    	received messages.
---
 ChangeLog     |  13 ++++++++
 Protocol      | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/context.c |   9 ++++++
 src/context.h |  10 ++++++
 src/message.c |  24 ++++++++++++++
 src/proto.c   |  82 ++++++++++++++++++++++++++++++++++++++++++++++
 src/proto.h   |  10 ++++++
 7 files changed, 250 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 877811f..54ce80f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2005-08-04
+
+	* Protocol: Added section describing fragments.
+
+	* src/proto.h:
+	* src/proto.c (otrl_proto_fragment_accumulate): 
+	* src/context.h:
+	* src/context.c (new_context, otrl_context_force_setup): Keep
+	track of fragments in the ConnContext structure.
+
+	* src/message.c (otrl_message_receiving): Handle fragments in
+	received messages.
+
 2005-07-29
 
 	* src/message.h:
diff --git a/Protocol b/Protocol
index 7f4416e..7f1ba97 100644
--- a/Protocol
+++ b/Protocol
@@ -521,3 +521,105 @@ can modify an OTR message and still have it appear valid.  But since we
 don't reveal the MAC keys until their corresponding pubkeys are being
 discarded, there is no danger of us accepting a message as valid which
 uses a MAC key which has already been revealed.
+
+Fragments
+---------
+
+[Remember when reading this section that the network model assumes
+in-order delivery, but that some messages may not get delivered at all
+(for example, if the user disconnects).  And, of course, there's the
+possibility of an active attacker, who is allowed to perform a Denial of
+Service attack, but not to learn contents of messages.]
+
+Transmitting Fragments:
+
+    If you have information about the maximum size of message you are
+    able to send (the different IM networks have different limits), you
+    can fragment an OTR message as follows:
+
+    - Start with the OTR message as you would normally transmit it.  For
+      example, an OTR Data Message would start with "?OTR:AAED" and end
+      with ".".
+    - Break it up into sufficiently small pieces.  Let the number of
+      pieces be (n), and the pieces be piece[1],piece[2],...,piece[n].
+    - Transmit (n) messages with the following (printf-like) structure
+      (as k runs from 1 to n inclusive):
+
+	  "?OTR,%hu,%hu,%s," , k , n , piece[k]
+
+    - Note that k and n are unsigned short ints (2 bytes), and each has
+      a maximum value of 65535.  Also, each piece[k] must be non-empty.
+
+Receiving Fragments:
+
+    If you receive a message containing "?OTR," (note that you'll need
+    to check for this _before_ checking for any of the other "?OTR:"
+    markers):
+
+    - Parse it as the printf statement above into k, n, and piece.
+    - Let (K,N) be your currently stored fragment number, and F be your
+      currently stored fragment.  [If you have no currently stored
+      fragment, then K = N = 0 and F = "".]
+
+    - If k == 0 or n == 0 or k > n, discard this (illegal) fragment.
+
+    - If k == 1:
+      - Forget any stored fragment you may have
+      - Store (piece) as F.
+      - Store (k,n) as (K,N).
+
+    - If n == N and k == K+1:
+      - Append (piece) to F.
+      - Store (k,n) as (K,N).
+
+    - Otherwise:
+      - Forget any stored fragment you may have
+      - Store "" as F.
+      - Store (0,0) as (K,N).
+
+    After this, if N > 0 and K == N, treat F as the received message.
+
+    If you receive an unfragmented message, forget any stored fragment
+    you may have, store "" as F and store (0,0) as (K,N).
+
+Example:
+
+    Here is an OTR Key Exchange Message we would like to transmit over a
+    network with an unreasonably small maximum message size:
+
+	?OTR:AAEKAQAAAICGmmRMlmuq4gY7Ro0GiYAJKWwVZyITNyifFP9VRIVgyxxGxwV
+	bFjoGMhO9XE0xFisuO6M27DPkX7hCtIXZM2glDszmTklQO5hJPu0g/RgDZ84q0ee
+	Q5AvexW3Hmp/VHUPTpZfJPep/Ctiqn0oE2y/2yRPyYQjpZCL440sM5i7B1wAAABT
+	zzL9WbuaxOK8rfrtaw4Lx/iLxeQAAAIAWaGpchsVOV1D6xK5cS5QNANelTvyVHre
+	XPSRjU0NFKIHrNDiFwa8lXcIBH/E8MHoQDzw+J2AuU6MuICPT8GMJYBcSZq0OM7x
+	gmfNlt1viUXxJXbYRpD82ki7QsMA1I7aQo/OqMryKlW5W8UqEjVcCsTOjEyQphLY
+	ENG6St9+ivgAAAIBgUjzleG1+VYCXZszTj+x5gNNidVVNKI+MG5elHMcsg2Guef3
+	DBYEsor6YGeqJLAfhk28Tg7tktMQwGN5GXR1ZNkwkoFIOyVRq3lfabfHtsTp+Hkx
+	5e8OrhTZ1G+ScDeqYbbTtUj631LhXUoyp+7pllVtpyLgqk5z9JYu6Kw0ZkQAAAAE
+	AAADASZH/uq17EVRo6dBZIL12x9JLx4gpEjgovfNLoORa6E+sMMuG7Z+zfLQVodX
+	H5shi/dvPzwbVrA/Iw72XHSYtld8lK/FLtjsI5mzancvRAEs1ZDBoBJRLW1X54eF
+	HpN/peDi6fBbdXyGahWYyF9MCJxDFCRqAHvEMZbfdyEtkXbFUZM2lJM2SJJG9zGZ
+	LCvd2/gF/VOgMlvdus+8TFW0k7cBhAgm/rb+EUeovkWXy2BiVpInXKCCH+M6EVpU
+	YNG7BPtH44ABwUw6Y5n5sSb6dtout34NGz+dspXMajffkZxFOAcabRwKIpw==.
+
+    We could fragment this message into (for example) three pieces:
+
+	?OTR,1,3,?OTR:AAEKAQAAAICGmmRMlmuq4gY7Ro0GiYAJKWwVZyITNyifFP9VRI
+	VgyxxGxwVbFjoGMhO9XE0xFisuO6M27DPkX7hCtIXZM2glDszmTklQO5hJPu0g/R
+	gDZ84q0eeQ5AvexW3Hmp/VHUPTpZfJPep/Ctiqn0oE2y/2yRPyYQjpZCL440sM5i
+	7B1wAAABTzzL9WbuaxOK8rfrtaw4Lx/iLxeQAAAIAWaGpchsVOV1D6xK5cS5QNAN
+	elTvyVHreXPSRjU0NFKIHrNDiFwa8lXcIBH/E8MHoQDzw+J2AuU6MuICPT8GMJYB
+	cSZq0OM7xgmfNlt1viUXxJXbYRpD82ki7QsMA1I7aQo/OqMryKlW5W8UqEjVcCsT
+	OjEyQphLY,
+
+	?OTR,2,3,ENG6St9+ivgAAAIBgUjzleG1+VYCXZszTj+x5gNNidVVNKI+MG5elHM
+	csg2Guef3DBYEsor6YGeqJLAfhk28Tg7tktMQwGN5GXR1ZNkwkoFIOyVRq3lfabf
+	HtsTp+Hkx5e8OrhTZ1G+ScDeqYbbTtUj631LhXUoyp+7pllVtpyLgqk5z9JYu6Kw
+	0ZkQAAAAEAAADASZH/uq17EVRo6dBZIL12x9JLx4gpEjgovfNLoORa6E+sMMuG7Z
+	+zfLQVodXH5shi/dvPzwbVrA/Iw72XHSYtld8lK/FLtjsI5mzancvRAEs1ZDBoBJ
+	RLW1X54eFHpN/peDi6fBbdXyGahWYyF9MCJxDFCRqAHvEMZbfdyEtkXbFUZM2lJM
+	2SJJG9zGZ,
+
+	?OTR,3,3,LCvd2/gF/VOgMlvdus+8TFW0k7cBhAgm/rb+EUeovkWXy2BiVpInXKC
+	CH+M6EVpUYNG7BPtH44ABwUw6Y5n5sSb6dtout34NGz+dspXMajffkZxFOAcabRw
+	KIpw==.,
diff --git a/src/context.c b/src/context.c
index bdcd1b7..6d53210 100644
--- a/src/context.c
+++ b/src/context.c
@@ -41,6 +41,10 @@ static ConnContext * new_context(const char * user, const char * accountname,
     context->username = strdup(user);
     context->accountname = strdup(accountname);
     context->protocol = strdup(protocol);
+    context->fragment = NULL;
+    context->fragment_len = 0;
+    context->fragment_n = 0;
+    context->fragment_k = 0;
     context->state = CONN_UNCONNECTED;
     context->fingerprint_root.fingerprint = NULL;
     context->fingerprint_root.context = context;
@@ -188,6 +192,11 @@ void otrl_context_set_preshared_secret(ConnContext *context,
 void otrl_context_force_setup(ConnContext *context)
 {
     context->state = CONN_SETUP;
+    free(context->fragment);
+    context->fragment = NULL;
+    context->fragment_len = 0;
+    context->fragment_n = 0;
+    context->fragment_k = 0;
     context->active_fingerprint = NULL;
     context->their_keyid = 0;
     gcry_mpi_release(context->their_y);
diff --git a/src/context.h b/src/context.h
index aca4a7b..fbe095a 100644
--- a/src/context.h
+++ b/src/context.h
@@ -45,6 +45,16 @@ typedef struct context {
     char * accountname;                /* The username is relative to
 					  this account... */
     char * protocol;                   /* ... and this protocol */
+
+    char *fragment;                    /* The part of the fragmented message
+					  we've seen so far */
+    size_t fragment_len;               /* The length of fragment */
+    unsigned short fragment_n;         /* The total number of fragments
+					  in this message */
+    unsigned short fragment_k;         /* The highest fragment number
+					  we've seen so far for this
+					  message */
+
     ConnectionState state;             /* The state of our connection to this
 					  user */
     Fingerprint fingerprint_root;      /* The root of a linked list of
diff --git a/src/message.c b/src/message.c
index c36994a..8c6ec92 100644
--- a/src/message.c
+++ b/src/message.c
@@ -376,6 +376,8 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
     ConnectionState state;
     OtrlPolicy policy = OTRL_POLICY_DEFAULT;
     int ignore_message = -1;
+    int fragment_assembled = 0;
+    char *unfragmessage = NULL;
 
     if (!accountname || !protocol || !sender || !message || !newmessagep)
         return 0;
@@ -402,6 +404,22 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
         return 0;
     }
 
+    /* See if we have a fragment */
+    switch(otrl_proto_fragment_accumulate(&unfragmessage, context, message)) {
+	case OTRL_FRAGMENT_UNFRAGMENTED:
+	    /* Do nothing */
+	    break;
+	case OTRL_FRAGMENT_INCOMPLETE:
+	    /* We've accumulated this fragment, but we don't have a
+	     * complete message yet */
+	    return 1;
+	case OTRL_FRAGMENT_COMPLETE:
+	    /* We've got a new complete message, in unfragmessage. */
+	    fragment_assembled = 1;
+	    message = unfragmessage;
+	    break;
+    }
+
     /* What type of message is it?  Note that this just checks the
      * header; it's not necessarily a _valid_ message of this type. */
     msgtype = otrl_proto_message_type(message);
@@ -895,6 +913,12 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
 	    break;
     }
 
+    /* If we reassembled a fragmented message, we need to free the
+     * allocated memory now. */
+    if (fragment_assembled) {
+	free(unfragmessage);
+    }
+
     if (ignore_message == -1) ignore_message = 0;
     return ignore_message;
 }
diff --git a/src/proto.c b/src/proto.c
index 9998071..2ecd24b 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -1030,3 +1030,85 @@ err:
     free(rawmsg);
     return err;
 }
+
+/* Accumulate a potential fragment into the current context. */
+OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep,
+	ConnContext *context, const char *msg)
+{
+    OtrlFragmentResult res = OTRL_FRAGMENT_INCOMPLETE;
+    const char *tag;
+
+    tag = strstr(msg, "?OTR,");
+    if (tag) {
+	unsigned short n = 0, k = 0;
+	int start = 0, end = 0;
+
+	sscanf(tag, "?OTR,%hu,%hu,%n%*[^,],%n", &k, &n, &start, &end);
+	if (k > 0 && n > 0 && k <= n && start > 0 && end > 0 && start < end) {
+	    if (k == 1) {
+		int fraglen = end - start - 1;
+		free(context->fragment);
+		context->fragment = malloc(fraglen + 1);
+		if (fraglen + 1 > fraglen && context->fragment) {
+		    memmove(context->fragment, tag + start, fraglen);
+		    context->fragment_len = fraglen;
+		    context->fragment[context->fragment_len] = '\0';
+		    context->fragment_n = n;
+		    context->fragment_k = k;
+		} else {
+		    free(context->fragment);
+		    context->fragment = NULL;
+		    context->fragment_len = 0;
+		    context->fragment_n = 0;
+		    context->fragment_k = 0;
+		}
+	    } else if (n == context->fragment_n &&
+		    k == context->fragment_k + 1) {
+		int fraglen = end - start - 1;
+		char *newfrag = realloc(context->fragment,
+			context->fragment_len + fraglen + 1);
+		if (context->fragment_len + fraglen + 1 > fraglen && newfrag) {
+		    context->fragment = newfrag;
+		    memmove(context->fragment + context->fragment_len,
+			    tag + start, fraglen);
+		    context->fragment_len += fraglen;
+		    context->fragment[context->fragment_len] = '\0';
+		    context->fragment_k = k;
+		} else {
+		    free(context->fragment);
+		    context->fragment = NULL;
+		    context->fragment_len = 0;
+		    context->fragment_n = 0;
+		    context->fragment_k = 0;
+		}
+	    } else {
+		free(context->fragment);
+		context->fragment = NULL;
+		context->fragment_len = 0;
+		context->fragment_n = 0;
+		context->fragment_k = 0;
+	    }
+	}
+
+	if (context->fragment_n > 0 &&
+		context->fragment_n == context->fragment_k) {
+	    /* We've got a complete message */
+	    *unfragmessagep = context->fragment;
+	    context->fragment = NULL;
+	    context->fragment_len = 0;
+	    context->fragment_n = 0;
+	    context->fragment_k = 0;
+	    res = OTRL_FRAGMENT_COMPLETE;
+	}
+    } else {
+	/* Unfragmented message, so discard anyy fragment we may have */
+	free(context->fragment);
+	context->fragment = NULL;
+	context->fragment_len = 0;
+	context->fragment_n = 0;
+	context->fragment_k = 0;
+	res = OTRL_FRAGMENT_UNFRAGMENTED;
+    }
+
+    return res;
+}
diff --git a/src/proto.h b/src/proto.h
index de98242..86f5fba 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -40,6 +40,12 @@ typedef enum {
     OTR_UNKNOWN
 } OTRMessageType;
 
+typedef enum {
+    OTRL_FRAGMENT_UNFRAGMENTED,
+    OTRL_FRAGMENT_INCOMPLETE,
+    OTRL_FRAGMENT_COMPLETE
+} OtrlFragmentResult;
+
 typedef struct s_OTRKeyExchangeMsg {
     gcry_sexp_t digest_sexp;              /* SHA-1 hash of the raw message,
 					     except for the DSA sig; used
@@ -130,4 +136,8 @@ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
 gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp,
 	ConnContext *context, const char *datamsg);
 
+/* Accumulate a potential fragment into the current context. */
+OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep,
+	ConnContext *context, const char *msg);
+
 #endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/libotr.git



More information about the Pkg-privacy-commits mailing list