1 /*
2  *  Off-the-Record Messaging library
3  *  Copyright (C) 2004-2016  Ian Goldberg, David Goulet, Rob Smits,
4  *                           Chris Alexander, Willy Lew, Lisa Du,
5  *                           Nikita Borisov
6  *                           <otr@cypherpunks.ca>
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of version 2.1 of the GNU Lesser General
10  *  Public License as published by the Free Software Foundation.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /* OTR Protocol implementation.  This file should be independent of
23  * gaim, so that it can be used to make other clients. */
24 
25 /* system headers */
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <assert.h>
29 
30 /* libgcrypt headers */
31 #include <gcrypt.h>
32 
33 /* libotr headers */
34 #include "b64.h"
35 #include "privkey.h"
36 #include "proto.h"
37 #include "mem.h"
38 #include "version.h"
39 #include "tlv.h"
40 #include "serial.h"
41 
42 #if OTRL_DEBUGGING
43 extern const char *OTRL_DEBUGGING_DEBUGSTR;
44 #endif
45 
46 /* For now, we need to know the API version the client is using so that
47  * we don't use any UI callbacks it hasn't set. */
48 unsigned int otrl_api_version = 0;
49 
50 /* Initialize the OTR library.  Pass the version of the API you are
51  * using. */
otrl_init(unsigned int ver_major,unsigned int ver_minor,unsigned int ver_sub)52 gcry_error_t otrl_init(unsigned int ver_major, unsigned int ver_minor,
53 	unsigned int ver_sub)
54 {
55     unsigned int api_version;
56 
57     /* The major versions have to match, and you can't be using a newer
58      * minor version than we expect. */
59     if (ver_major != OTRL_VERSION_MAJOR || ver_minor > OTRL_VERSION_MINOR) {
60 	fprintf(stderr, "Expected libotr API version %u.%u.%u incompatible "
61 		"with actual version %u.%u.%u.  Aborting.\n",
62 		ver_major, ver_minor, ver_sub,
63 		OTRL_VERSION_MAJOR, OTRL_VERSION_MINOR, OTRL_VERSION_SUB);
64 	return gcry_error(GPG_ERR_INV_VALUE);
65     }
66 
67     /* Set the API version.  If we get called multiple times for some
68      * reason, take the smallest value. */
69     api_version = (ver_major << 16) | (ver_minor << 8) | (ver_sub);
70     if (otrl_api_version == 0 || otrl_api_version > api_version) {
71 	otrl_api_version = api_version;
72     }
73 
74     /* Initialize the memory module */
75     otrl_mem_init();
76 
77     /* Initialize the DH module */
78     otrl_dh_init();
79 
80     /* Initialize the SM module */
81     otrl_sm_init();
82 
83 #if OTRL_DEBUGGING
84     /* Inform the user that debugging is available */
85     fprintf(stderr, "\nlibotr debugging is available.  Type %s in a message\n"
86 	    "  to see debug info.\n\n", OTRL_DEBUGGING_DEBUGSTR);
87 #endif
88 
89     return gcry_error(GPG_ERR_NO_ERROR);
90 }
91 
92 /* Return a pointer to a static string containing the version number of
93  * the OTR library. */
otrl_version(void)94 const char *otrl_version(void)
95 {
96     return OTRL_VERSION;
97 }
98 
99 /* Store some MAC keys to be revealed later */
reveal_macs(ConnContext * context,DH_sesskeys * sess1,DH_sesskeys * sess2)100 static gcry_error_t reveal_macs(ConnContext *context,
101 	DH_sesskeys *sess1, DH_sesskeys *sess2)
102 {
103     unsigned int numnew = sess1->rcvmacused + sess1->sendmacused +
104 	sess2->rcvmacused + sess2->sendmacused;
105     unsigned int newnumsaved;
106     unsigned char *newmacs;
107 
108     /* Is there anything to do? */
109     if (numnew == 0) return gcry_error(GPG_ERR_NO_ERROR);
110 
111     newnumsaved = context->context_priv->numsavedkeys + numnew;
112     newmacs = realloc(context->context_priv->saved_mac_keys,
113 	    newnumsaved * 20);
114     if (!newmacs) {
115 	return gcry_error(GPG_ERR_ENOMEM);
116     }
117     if (sess1->rcvmacused) {
118 	memmove(newmacs + context->context_priv->numsavedkeys * 20,
119 		sess1->rcvmackey, 20);
120 	context->context_priv->numsavedkeys++;
121     }
122     if (sess1->sendmacused) {
123 	memmove(newmacs + context->context_priv->numsavedkeys * 20,
124 		sess1->sendmackey, 20);
125 	context->context_priv->numsavedkeys++;
126     }
127     if (sess2->rcvmacused) {
128 	memmove(newmacs + context->context_priv->numsavedkeys * 20,
129 		sess2->rcvmackey, 20);
130 	context->context_priv->numsavedkeys++;
131     }
132     if (sess2->sendmacused) {
133 	memmove(newmacs + context->context_priv->numsavedkeys * 20,
134 		sess2->sendmackey, 20);
135 	context->context_priv->numsavedkeys++;
136     }
137     context->context_priv->saved_mac_keys = newmacs;
138 
139     return gcry_error(GPG_ERR_NO_ERROR);
140 }
141 
142 /* Make a new DH key for us, and rotate old old ones.  Be sure to keep
143  * the sesskeys array in sync. */
rotate_dh_keys(ConnContext * context)144 static gcry_error_t rotate_dh_keys(ConnContext *context)
145 {
146     gcry_error_t err;
147 
148     /* Rotate the keypair */
149     otrl_dh_keypair_free(&(context->context_priv->our_old_dh_key));
150     memmove(&(context->context_priv->our_old_dh_key),
151 	    &(context->context_priv->our_dh_key),
152 	    sizeof(DH_keypair));
153 
154     /* Rotate the session keys */
155     err = reveal_macs(context, &(context->context_priv->sesskeys[1][0]),
156 	    &(context->context_priv->sesskeys[1][1]));
157     if (err) return err;
158     otrl_dh_session_free(&(context->context_priv->sesskeys[1][0]));
159     otrl_dh_session_free(&(context->context_priv->sesskeys[1][1]));
160     memmove(&(context->context_priv->sesskeys[1][0]),
161 	    &(context->context_priv->sesskeys[0][0]),
162 	    sizeof(DH_sesskeys));
163     memmove(&(context->context_priv->sesskeys[1][1]),
164 	    &(context->context_priv->sesskeys[0][1]),
165 	    sizeof(DH_sesskeys));
166 
167     /* Create a new DH key */
168     otrl_dh_gen_keypair(DH1536_GROUP_ID, &(context->context_priv->our_dh_key));
169     context->context_priv->our_keyid++;
170 
171     /* Make the session keys */
172     if (context->context_priv->their_y) {
173 	err = otrl_dh_session(&(context->context_priv->sesskeys[0][0]),
174 		&(context->context_priv->our_dh_key),
175 		context->context_priv->their_y);
176 	if (err) return err;
177     } else {
178 	otrl_dh_session_blank(&(context->context_priv->sesskeys[0][0]));
179     }
180     if (context->context_priv->their_old_y) {
181 	err = otrl_dh_session(&(context->context_priv->sesskeys[0][1]),
182 		&(context->context_priv->our_dh_key),
183 		context->context_priv->their_old_y);
184 	if (err) return err;
185     } else {
186 	otrl_dh_session_blank(&(context->context_priv->sesskeys[0][1]));
187     }
188     return gcry_error(GPG_ERR_NO_ERROR);
189 }
190 
191 /* Rotate in a new DH public key for our correspondent.  Be sure to keep
192  * the sesskeys array in sync. */
rotate_y_keys(ConnContext * context,gcry_mpi_t new_y)193 static gcry_error_t rotate_y_keys(ConnContext *context, gcry_mpi_t new_y)
194 {
195     gcry_error_t err;
196 
197     /* Rotate the public key */
198     gcry_mpi_release(context->context_priv->their_old_y);
199     context->context_priv->their_old_y = context->context_priv->their_y;
200 
201     /* Rotate the session keys */
202     err = reveal_macs(context, &(context->context_priv->sesskeys[0][1]),
203 	    &(context->context_priv->sesskeys[1][1]));
204     if (err) return err;
205     otrl_dh_session_free(&(context->context_priv->sesskeys[0][1]));
206     otrl_dh_session_free(&(context->context_priv->sesskeys[1][1]));
207     memmove(&(context->context_priv->sesskeys[0][1]),
208 	    &(context->context_priv->sesskeys[0][0]),
209 	    sizeof(DH_sesskeys));
210     memmove(&(context->context_priv->sesskeys[1][1]),
211 	    &(context->context_priv->sesskeys[1][0]),
212 	    sizeof(DH_sesskeys));
213 
214     /* Copy in the new public key */
215     context->context_priv->their_y = gcry_mpi_copy(new_y);
216     context->context_priv->their_keyid++;
217 
218     /* Make the session keys */
219     err = otrl_dh_session(&(context->context_priv->sesskeys[0][0]),
220 	    &(context->context_priv->our_dh_key),
221 	    context->context_priv->their_y);
222     if (err) return err;
223     err = otrl_dh_session(&(context->context_priv->sesskeys[1][0]),
224 	    &(context->context_priv->our_old_dh_key),
225 	    context->context_priv->their_y);
226     if (err) return err;
227 
228     return gcry_error(GPG_ERR_NO_ERROR);
229 }
230 
231 /* Return a pointer to a newly-allocated OTR query message, customized
232  * with our name.  The caller should free() the result when he's done
233  * with it. */
otrl_proto_default_query_msg(const char * ourname,OtrlPolicy policy)234 char *otrl_proto_default_query_msg(const char *ourname, OtrlPolicy policy)
235 {
236     char *msg;
237     int v1_supported, v2_supported, v3_supported;
238     char *version_tag;
239     char *bufp;
240     /* Don't use g_strdup_printf here, because someone (not us) is going
241      * to free() the *message pointer, not g_free() it.  We can't
242      * require that they g_free() it, because this pointer will probably
243      * get passed to the main IM application for processing (and
244      * free()ing). */
245     const char *format = "?OTR%s\n<b>%s</b> has requested an "
246 	    "<a href=\"https://otr.cypherpunks.ca/\">Off-the-Record "
247 	    "private conversation</a>.  However, you do not have a plugin "
248 	    "to support that.\nSee <a href=\"https://otr.cypherpunks.ca/\">"
249 	    "https://otr.cypherpunks.ca/</a> for more information.";
250 
251     /* Figure out the version tag */
252     v1_supported = (policy & OTRL_POLICY_ALLOW_V1);
253     v2_supported = (policy & OTRL_POLICY_ALLOW_V2);
254     v3_supported = (policy & OTRL_POLICY_ALLOW_V3);
255     version_tag = malloc(8);
256     bufp = version_tag;
257     if (v1_supported) {
258 	*bufp = '?';
259 	bufp++;
260     }
261     if (v2_supported || v3_supported) {
262 	*bufp = 'v';
263 	bufp++;
264 	if (v2_supported) {
265 	    *bufp = '2';
266 	    bufp++;
267 	}
268 	if (v3_supported) {
269 	    *bufp = '3';
270 	    bufp++;
271 	}
272 	*bufp = '?';
273 	bufp++;
274     }
275     *bufp = '\0';
276 
277     /* Remove two "%s", add '\0' */
278     msg = malloc(strlen(format) + strlen(version_tag) + strlen(ourname) - 3);
279     if (!msg) {
280 	free(version_tag);
281 	return NULL;
282     }
283     sprintf(msg, format, version_tag, ourname);
284     free(version_tag);
285     return msg;
286 }
287 
288 /* Return the best version of OTR support by both sides, given an OTR
289  * Query Message and the local policy. */
otrl_proto_query_bestversion(const char * otrquerymsg,OtrlPolicy policy)290 unsigned int otrl_proto_query_bestversion(const char *otrquerymsg,
291 	OtrlPolicy policy)
292 {
293     char *otrtag;
294     unsigned int query_versions = 0;
295 
296 
297     otrtag = strstr(otrquerymsg, "?OTR");
298     if (!otrtag) {
299 	return 0;
300     }
301     otrtag += 4;
302 
303     if (*otrtag == '?') {
304 	query_versions = (1<<0);
305 	++otrtag;
306     }
307     if (*otrtag == 'v') {
308 	for(++otrtag; *otrtag && *otrtag != '?'; ++otrtag) {
309 	    switch(*otrtag) {
310 		case '2':
311 		    query_versions |= (1<<1);
312 		    break;
313 		case '3':
314 		    query_versions |= (1<<2);
315 		    break;
316 	    }
317 	}
318     }
319 
320     if ((policy & OTRL_POLICY_ALLOW_V3) && (query_versions & (1<<2))) {
321 	return 3;
322     }
323     if ((policy & OTRL_POLICY_ALLOW_V2) && (query_versions & (1<<1))) {
324 	return 2;
325     }
326     if ((policy & OTRL_POLICY_ALLOW_V1) && (query_versions & (1<<0))) {
327 	return 1;
328     }
329     return 0;
330 }
331 
332 /* Locate any whitespace tag in this message, and return the best
333  * version of OTR support on both sides.  Set *starttagp and *endtagp to
334  * the start and end of the located tag, so that it can be snipped out. */
otrl_proto_whitespace_bestversion(const char * msg,const char ** starttagp,const char ** endtagp,OtrlPolicy policy)335 unsigned int otrl_proto_whitespace_bestversion(const char *msg,
336 	const char **starttagp, const char **endtagp, OtrlPolicy policy)
337 {
338     const char *starttag, *endtag;
339     unsigned int query_versions = 0;
340 
341     *starttagp = NULL;
342     *endtagp = NULL;
343 
344     starttag = strstr(msg, OTRL_MESSAGE_TAG_BASE);
345     if (!starttag) return 0;
346 
347     endtag = starttag + strlen(OTRL_MESSAGE_TAG_BASE);
348 
349     /* Look for groups of 8 spaces and/or tabs */
350     while(1) {
351 	int i;
352 	int allwhite = 1;
353 	for(i=0;i<8;++i) {
354 	    if (endtag[i] != ' ' && endtag[i] != '\t') {
355 		allwhite = 0;
356 		break;
357 	    }
358 	}
359 	if (allwhite) {
360 	    if (!strncmp(endtag, OTRL_MESSAGE_TAG_V1, 8)) {
361 		query_versions |= (1<<0);
362 	    }
363 	    if (!strncmp(endtag, OTRL_MESSAGE_TAG_V2, 8)) {
364 		query_versions |= (1<<1);
365 	    }
366 	    if (!strncmp(endtag, OTRL_MESSAGE_TAG_V3, 8)) {
367 		query_versions |= (1<<2);
368 	    }
369 	    endtag += 8;
370 	} else {
371 	    break;
372 	}
373     }
374 
375     *starttagp = starttag;
376     *endtagp = endtag;
377 
378     if ((policy & OTRL_POLICY_ALLOW_V3) && (query_versions & (1<<2))) {
379 	return 3;
380     }
381     if ((policy & OTRL_POLICY_ALLOW_V2) && (query_versions & (1<<1))) {
382 	return 2;
383     }
384     if ((policy & OTRL_POLICY_ALLOW_V1) && (query_versions & (1<<0))) {
385 	return 1;
386     }
387     return 0;
388 }
389 
390 /* Find the message type. */
otrl_proto_message_type(const char * message)391 OtrlMessageType otrl_proto_message_type(const char *message)
392 {
393     char *otrtag;
394 
395     otrtag = strstr(message, "?OTR");
396 
397     if (!otrtag) {
398 	if (strstr(message, OTRL_MESSAGE_TAG_BASE)) {
399 	    return OTRL_MSGTYPE_TAGGEDPLAINTEXT;
400 	} else {
401 	    return OTRL_MSGTYPE_NOTOTR;
402 	}
403     }
404 
405     if (!strncmp(otrtag, "?OTR:AAM", 8) || !strncmp(otrtag, "?OTR:AAI", 8)) {
406 	switch(*(otrtag + 8)) {
407 	    case 'C': return OTRL_MSGTYPE_DH_COMMIT;
408 	    case 'K': return OTRL_MSGTYPE_DH_KEY;
409 	    case 'R': return OTRL_MSGTYPE_REVEALSIG;
410 	    case 'S': return OTRL_MSGTYPE_SIGNATURE;
411 	    case 'D': return OTRL_MSGTYPE_DATA;
412 	}
413     } else {
414 	if (!strncmp(otrtag, "?OTR?", 5)) return OTRL_MSGTYPE_QUERY;
415 	if (!strncmp(otrtag, "?OTRv", 5)) return OTRL_MSGTYPE_QUERY;
416 	if (!strncmp(otrtag, "?OTR:AAEK", 9)) return OTRL_MSGTYPE_V1_KEYEXCH;
417 	if (!strncmp(otrtag, "?OTR:AAED", 9)) return OTRL_MSGTYPE_DATA;
418 	if (!strncmp(otrtag, "?OTR Error:", 11)) return OTRL_MSGTYPE_ERROR;
419     }
420     return OTRL_MSGTYPE_UNKNOWN;
421 }
422 
423 /* Find the message version. */
otrl_proto_message_version(const char * message)424 int otrl_proto_message_version(const char *message)
425 {
426     char *otrtag;
427 
428     otrtag = strstr(message, "?OTR");
429 
430     if (!otrtag) {
431 	return 0;
432     }
433 
434     if (!strncmp(otrtag, "?OTR:AAM", 8))
435 	return 3;
436     if (!strncmp(otrtag, "?OTR:AAI", 8))
437 	return 2;
438     if (!strncmp(otrtag, "?OTR:AAE", 8))
439 	return 1;
440 
441     return 0;
442 }
443 
444 /* Find the instance tags in this message */
otrl_proto_instance(const char * otrmsg,unsigned int * instance_from,unsigned int * instance_to)445 gcry_error_t otrl_proto_instance(const char *otrmsg,
446 	unsigned int *instance_from, unsigned int *instance_to)
447 {
448     gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
449 
450     const char *otrtag = otrmsg;
451     unsigned char *bufp = NULL;
452     unsigned char *bufp_head = NULL;
453     size_t lenp;
454 
455     if (!otrtag || strncmp(otrtag, "?OTR:AAM", 8)) {
456 	goto invval;
457     }
458 
459     if (strlen(otrtag) < 21 ) goto invval;
460 
461     /* Decode and extract instance tag */
462     bufp = malloc(OTRL_B64_MAX_DECODED_SIZE(12));
463     bufp_head = bufp;
464     lenp = otrl_base64_decode(bufp, otrtag+9, 12);
465     read_int(*instance_from);
466     read_int(*instance_to);
467     free(bufp_head);
468     return gcry_error(GPG_ERR_NO_ERROR);
469 invval:
470     free(bufp_head);
471     err = gcry_error(GPG_ERR_INV_VALUE);
472     return err;
473 }
474 
475 /* Create an OTR Data message.  Pass the plaintext as msg, and an
476  * optional chain of TLVs.  A newly-allocated string will be returned in
477  * *encmessagep. Put the current extra symmetric key into extrakey
478  * (if non-NULL). */
otrl_proto_create_data(char ** encmessagep,ConnContext * context,const char * msg,const OtrlTLV * tlvs,unsigned char flags,unsigned char * extrakey)479 gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
480 	const char *msg, const OtrlTLV *tlvs, unsigned char flags,
481 	unsigned char *extrakey)
482 {
483     size_t justmsglen = strlen(msg);
484     size_t msglen = justmsglen + 1 + otrl_tlv_seriallen(tlvs);
485     size_t buflen;
486     size_t pubkeylen;
487     unsigned char *buf = NULL;
488     unsigned char *bufp;
489     size_t lenp;
490     DH_sesskeys *sess = &(context->context_priv->sesskeys[1][0]);
491     gcry_error_t err;
492     size_t reveallen = 20 * context->context_priv->numsavedkeys;
493     char *base64buf = NULL;
494     unsigned char *msgbuf = NULL;
495     enum gcry_mpi_format format = GCRYMPI_FMT_USG;
496     char *msgdup;
497     int version = context->protocol_version;
498 
499     *encmessagep = NULL;
500 
501     /* Make sure we're actually supposed to be able to encrypt */
502     if (context->msgstate != OTRL_MSGSTATE_ENCRYPTED ||
503 	    context->context_priv->their_keyid == 0) {
504 	return gcry_error(GPG_ERR_CONFLICT);
505     }
506 
507     /* We need to copy the incoming msg, since it might be an alias for
508      * context->lastmessage, which we'll be freeing soon. */
509     msgdup = gcry_malloc_secure(justmsglen + 1);
510     if (msgdup == NULL) {
511 	return gcry_error(GPG_ERR_ENOMEM);
512     }
513     strcpy(msgdup, msg);
514 
515     /* Header, msg flags, send keyid, recv keyid, counter, msg len, msg
516      * len of revealed mac keys, revealed mac keys, MAC */
517     buflen = OTRL_HEADER_LEN + (version == 3 ? 8 : 0)
518 	+ (version == 2 || version == 3 ? 1 : 0) + 4 + 4
519 	+ 8 + 4 + msglen + 4 + reveallen + 20;
520     gcry_mpi_print(format, NULL, 0, &pubkeylen,
521 	    context->context_priv->our_dh_key.pub);
522     buflen += pubkeylen + 4;
523     buf = malloc(buflen);
524     msgbuf = gcry_malloc_secure(msglen);
525     if (buf == NULL || msgbuf == NULL) {
526 	free(buf);
527 	gcry_free(msgbuf);
528 	gcry_free(msgdup);
529 	return gcry_error(GPG_ERR_ENOMEM);
530     }
531     memmove(msgbuf, msgdup, justmsglen);
532     msgbuf[justmsglen] = '\0';
533     otrl_tlv_serialize(msgbuf + justmsglen + 1, tlvs);
534     bufp = buf;
535     lenp = buflen;
536     if (version == 1) {
537 	memmove(bufp, "\x00\x01\x03", 3);  /* header */
538     } else if (version == 2) {
539 	memmove(bufp, "\x00\x02\x03", 3);  /* header */
540     } else {
541 	memmove(bufp, "\x00\x03\x03", 3);  /* header */
542     }
543 
544     debug_data("Header", bufp, 3);
545     bufp += 3; lenp -= 3;
546 
547     if (version == 3) {
548 	/* v3 instance tags */
549 	write_int(context->our_instance);
550 	debug_int("Sender instag", bufp-4);
551 	write_int(context->their_instance);
552 	debug_int("Recipient instag", bufp-4);
553     }
554 
555     if (version == 2 || version == 3) {
556 	bufp[0] = flags;
557 	bufp += 1; lenp -= 1;
558     }
559 
560     write_int(context->context_priv->our_keyid-1); /* sender keyid */
561     debug_int("Sender keyid", bufp-4);
562     write_int(context->context_priv->their_keyid); /* recipient keyid */
563     debug_int("Recipient keyid", bufp-4);
564 
565     write_mpi(context->context_priv->our_dh_key.pub, pubkeylen, "Y");  /* Y */
566 
567     otrl_dh_incctr(sess->sendctr);
568     memmove(bufp, sess->sendctr, 8);      /* Counter (top 8 bytes only) */
569     debug_data("Counter", bufp, 8);
570     bufp += 8; lenp -= 8;
571 
572     write_int(msglen);                        /* length of encrypted data */
573     debug_int("Msg len", bufp-4);
574 
575     err = gcry_cipher_reset(sess->sendenc);
576     if (err) goto err;
577     err = gcry_cipher_setctr(sess->sendenc, sess->sendctr, 16);
578     if (err) goto err;
579     err = gcry_cipher_encrypt(sess->sendenc, bufp, msglen, msgbuf, msglen);
580     if (err) goto err;                              /* encrypted data */
581     debug_data("Enc data", bufp, msglen);
582     bufp += msglen;
583     lenp -= msglen;
584 
585     gcry_md_reset(sess->sendmac);
586     gcry_md_write(sess->sendmac, buf, bufp-buf);
587     memmove(bufp, gcry_md_read(sess->sendmac, GCRY_MD_SHA1), 20);
588     debug_data("MAC", bufp, 20);
589     bufp += 20;                                         /* MAC */
590     lenp -= 20;
591 
592     write_int(reveallen);                     /* length of revealed MAC keys */
593     debug_int("Revealed MAC length", bufp-4);
594 
595     if (reveallen > 0) {
596 	memmove(bufp, context->context_priv->saved_mac_keys, reveallen);
597 	debug_data("Revealed MAC data", bufp, reveallen);
598 	bufp += reveallen; lenp -= reveallen;
599 	free(context->context_priv->saved_mac_keys);
600 	context->context_priv->saved_mac_keys = NULL;
601 	context->context_priv->numsavedkeys = 0;
602     }
603 
604     assert(lenp == 0);
605 
606     /* Make the base64-encoding. */
607     base64buf = otrl_base64_otr_encode(buf, buflen);
608     if (base64buf == NULL) {
609 	err = gcry_error(GPG_ERR_ENOMEM);
610 	goto err;
611     }
612 
613     free(buf);
614     gcry_free(msgbuf);
615     *encmessagep = base64buf;
616     gcry_free(context->context_priv->lastmessage);
617     context->context_priv->lastmessage = NULL;
618     context->context_priv->may_retransmit = 0;
619     if (msglen > 0) {
620 	context->context_priv->lastmessage = gcry_malloc_secure(justmsglen + 1);
621 	if (context->context_priv->lastmessage) {
622 	    strcpy(context->context_priv->lastmessage, msgdup);
623 	}
624     }
625     gcry_free(msgdup);
626 
627     /* Save a copy of the current extra key */
628     if (extrakey) {
629 	memmove(extrakey, sess->extrakey, OTRL_EXTRAKEY_BYTES);
630     }
631 
632     return gcry_error(GPG_ERR_NO_ERROR);
633 err:
634     free(buf);
635     gcry_free(msgbuf);
636     gcry_free(msgdup);
637     *encmessagep = NULL;
638     return err;
639 }
640 
641 /* Extract the flags from an otherwise unreadable Data Message. */
otrl_proto_data_read_flags(const char * datamsg,unsigned char * flagsp)642 gcry_error_t otrl_proto_data_read_flags(const char *datamsg,
643 	unsigned char *flagsp)
644 {
645     char *otrtag, *endtag;
646     unsigned char *rawmsg = NULL;
647     unsigned char *bufp;
648     size_t msglen, rawlen, lenp;
649     unsigned char version;
650 
651     if (flagsp) *flagsp = 0;
652     otrtag = strstr(datamsg, "?OTR:");
653     if (!otrtag) {
654 	goto invval;
655     }
656     endtag = strchr(otrtag, '.');
657     if (endtag) {
658 	msglen = endtag-otrtag;
659     } else {
660 	msglen = strlen(otrtag);
661     }
662 
663     /* Skip over the "?OTR:" */
664     otrtag += 5;
665     msglen -= 5;
666 
667     /* Base64-decode the message */
668     rawlen = OTRL_B64_MAX_DECODED_SIZE(msglen);   /* maximum possible */
669     rawmsg = malloc(rawlen);
670     if (!rawmsg && rawlen > 0) {
671 	return gcry_error(GPG_ERR_ENOMEM);
672     }
673     rawlen = otrl_base64_decode(rawmsg, otrtag, msglen);  /* actual size */
674 
675     bufp = rawmsg;
676     lenp = rawlen;
677 
678     require_len(3);
679     version = bufp[1];
680     skip_header('\x03');
681 
682     if (version == 3) {
683 	require_len(8);
684 	bufp += 8; lenp -= 8;
685     }
686 
687     if (version == 2 || version == 3) {
688 	require_len(1);
689 	if (flagsp) *flagsp = bufp[0];
690 	bufp += 1; lenp -= 1;
691     }
692 
693     free(rawmsg);
694     return gcry_error(GPG_ERR_NO_ERROR);
695 
696 invval:
697     free(rawmsg);
698     return gcry_error(GPG_ERR_INV_VALUE);
699 }
700 
701 /* Accept an OTR Data Message in datamsg.  Decrypt it and put the
702  * plaintext into *plaintextp, and any TLVs into tlvsp.  Put any
703  * received flags into *flagsp (if non-NULL).  Put the current extra
704  * symmetric key into extrakey (if non-NULL). */
otrl_proto_accept_data(char ** plaintextp,OtrlTLV ** tlvsp,ConnContext * context,const char * datamsg,unsigned char * flagsp,unsigned char * extrakey)705 gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp,
706 	ConnContext *context, const char *datamsg, unsigned char *flagsp,
707 	unsigned char *extrakey)
708 {
709     char *otrtag, *endtag;
710     gcry_error_t err;
711     unsigned char *rawmsg = NULL;
712     size_t msglen, rawlen, lenp;
713     unsigned char *macstart, *macend;
714     unsigned char *bufp;
715     unsigned int sender_keyid, recipient_keyid;
716     gcry_mpi_t sender_next_y = NULL;
717     unsigned char ctr[8];
718     size_t datalen, reveallen;
719     unsigned char *data = NULL;
720     unsigned char *nul = NULL;
721     unsigned char givenmac[20];
722     DH_sesskeys *sess;
723     unsigned char version;
724 
725     *plaintextp = NULL;
726     *tlvsp = NULL;
727     if (flagsp) *flagsp = 0;
728     otrtag = strstr(datamsg, "?OTR:");
729     if (!otrtag) {
730 	goto invval;
731     }
732     endtag = strchr(otrtag, '.');
733     if (endtag) {
734 	msglen = endtag-otrtag;
735     } else {
736 	msglen = strlen(otrtag);
737     }
738 
739     /* Skip over the "?OTR:" */
740     otrtag += 5;
741     msglen -= 5;
742 
743     /* Base64-decode the message */
744     rawlen = OTRL_B64_MAX_DECODED_SIZE(msglen);   /* maximum possible */
745     rawmsg = malloc(rawlen);
746     if (!rawmsg && rawlen > 0) {
747 	err = gcry_error(GPG_ERR_ENOMEM);
748 	goto err;
749     }
750     rawlen = otrl_base64_decode(rawmsg, otrtag, msglen);  /* actual size */
751 
752     bufp = rawmsg;
753     lenp = rawlen;
754 
755     macstart = bufp;
756     require_len(3);
757     version = bufp[1];
758 
759     skip_header('\x03');
760 
761     if (version == 3) {
762 	require_len(8);
763 	bufp += 8; lenp -= 8;
764     }
765 
766     if (version == 2 || version == 3) {
767 	require_len(1);
768 	if (flagsp) *flagsp = bufp[0];
769 	bufp += 1; lenp -= 1;
770     }
771 
772     read_int(sender_keyid);
773     read_int(recipient_keyid);
774     read_mpi(sender_next_y);
775     require_len(8);
776     memmove(ctr, bufp, 8);
777     bufp += 8; lenp -= 8;
778     read_int(datalen);
779     require_len(datalen);
780     data = malloc(datalen+1);
781     if (!data) {
782 	err = gcry_error(GPG_ERR_ENOMEM);
783 	goto err;
784     }
785     memmove(data, bufp, datalen);
786     data[datalen] = '\0';
787     bufp += datalen; lenp -= datalen;
788     macend = bufp;
789     require_len(20);
790     memmove(givenmac, bufp, 20);
791     bufp += 20; lenp -= 20;
792     read_int(reveallen);
793     require_len(reveallen);
794     /* Just skip over the revealed MAC keys, which we don't need.  They
795      * were published for deniability of transcripts. */
796     bufp += reveallen; lenp -= reveallen;
797 
798     /* That should be everything */
799     if (lenp != 0) goto invval;
800 
801     /* We don't take any action on this message (especially rotating
802      * keys) until we've verified the MAC on this message.  To that end,
803      * we need to know which keys this message is claiming to use. */
804     if (context->context_priv->their_keyid == 0 ||
805 	    (sender_keyid != context->context_priv->their_keyid &&
806 		sender_keyid != context->context_priv->their_keyid - 1) ||
807 	    (recipient_keyid != context->context_priv->our_keyid &&
808 	     recipient_keyid != context->context_priv->our_keyid - 1) ||
809 	    sender_keyid == 0 || recipient_keyid == 0) {
810 	goto conflict;
811     }
812 
813     if (sender_keyid == context->context_priv->their_keyid - 1 &&
814 	    context->context_priv->their_old_y == NULL) {
815 	goto conflict;
816     }
817 
818     /* These are the session keys this message is claiming to use. */
819     sess = &(context->context_priv->sesskeys
820 	    [context->context_priv->our_keyid - recipient_keyid]
821 	    [context->context_priv->their_keyid - sender_keyid]);
822 
823     gcry_md_reset(sess->rcvmac);
824     gcry_md_write(sess->rcvmac, macstart, macend-macstart);
825     if (otrl_mem_differ(givenmac, gcry_md_read(sess->rcvmac, GCRY_MD_SHA1),
826 	    20)) {
827 	/* The MACs didn't match! */
828 	goto conflict;
829     }
830     sess->rcvmacused = 1;
831 
832     /* Check to see that the counter is increasing; i.e. that this isn't
833      * a replay. */
834     if (otrl_dh_cmpctr(ctr, sess->rcvctr) <= 0) {
835 	goto conflict;
836     }
837 
838     /* Decrypt the message */
839     memmove(sess->rcvctr, ctr, 8);
840     err = gcry_cipher_reset(sess->rcvenc);
841     if (err) goto err;
842     err = gcry_cipher_setctr(sess->rcvenc, sess->rcvctr, 16);
843     if (err) goto err;
844     err = gcry_cipher_decrypt(sess->rcvenc, data, datalen, NULL, 0);
845     if (err) goto err;
846 
847     /* Save a copy of the current extra key */
848     if (extrakey) {
849 	memmove(extrakey, sess->extrakey, OTRL_EXTRAKEY_BYTES);
850     }
851 
852     /* See if either set of keys needs rotating */
853 
854     if (recipient_keyid == context->context_priv->our_keyid) {
855 	/* They're using our most recent key, so generate a new one */
856 	err = rotate_dh_keys(context);
857 	if (err) goto err;
858     }
859 
860     if (sender_keyid == context->context_priv->their_keyid) {
861 	/* They've sent us a new public key */
862 	err = rotate_y_keys(context, sender_next_y);
863 	if (err) goto err;
864     }
865 
866     gcry_mpi_release(sender_next_y);
867     *plaintextp = (char *)data;
868 
869     /* See if there are TLVs */
870     nul = data;
871     while (nul < data+datalen && *nul) ++nul;
872     /* If we stopped before the end, skip the NUL we stopped at */
873     if (nul < data+datalen) ++nul;
874     *tlvsp = otrl_tlv_parse(nul, (data+datalen)-nul);
875 
876     free(rawmsg);
877     return gcry_error(GPG_ERR_NO_ERROR);
878 
879 invval:
880     err = gcry_error(GPG_ERR_INV_VALUE);
881     goto err;
882 conflict:
883     err = gcry_error(GPG_ERR_CONFLICT);
884     goto err;
885 err:
886     gcry_mpi_release(sender_next_y);
887     free(data);
888     free(rawmsg);
889     return err;
890 }
891 
892 /* Accumulate a potential fragment into the current context. */
otrl_proto_fragment_accumulate(char ** unfragmessagep,ConnContext * context,const char * msg)893 OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep,
894 	ConnContext *context, const char *msg)
895 {
896     OtrlFragmentResult res = OTRL_FRAGMENT_INCOMPLETE;
897     const char *tag;
898     unsigned short n = 0, k = 0;
899     int start = 0, end = 0;
900 
901     tag = strstr(msg, "?OTR|");
902     if (tag) {
903 	sscanf(tag, "?OTR|%*x|%*x,%hu,%hu,%n%*[^,],%n", &k, &n, &start, &end);
904     } else if ((tag = strstr(msg, "?OTR,")) != NULL) {
905 	sscanf(tag, "?OTR,%hu,%hu,%n%*[^,],%n", &k, &n, &start, &end);
906     } else {
907 	/* Unfragmented message, so discard any fragment we may have */
908 	free(context->context_priv->fragment);
909 	context->context_priv->fragment = NULL;
910 	context->context_priv->fragment_len = 0;
911 	context->context_priv->fragment_n = 0;
912 	context->context_priv->fragment_k = 0;
913 	res = OTRL_FRAGMENT_UNFRAGMENTED;
914 	return res;
915     }
916 
917     if (k > 0 && n > 0 && k <= n && start > 0 && end > 0 && start < end) {
918 	if (k == 1) {
919 	    size_t fraglen = end - start - 1;
920 	    size_t newsize = fraglen + 1;
921 	    free(context->context_priv->fragment);
922 	    context->context_priv->fragment = NULL;
923 	    if (newsize >= 1) {  /* Check for overflow */
924 		context->context_priv->fragment = malloc(newsize);
925 	    }
926 	    if (context->context_priv->fragment) {
927 		memmove(context->context_priv->fragment, tag + start, fraglen);
928 		context->context_priv->fragment_len = fraglen;
929 		context->context_priv->fragment[
930 			context->context_priv->fragment_len] = '\0';
931 		context->context_priv->fragment_n = n;
932 		context->context_priv->fragment_k = k;
933 	    } else {
934 		context->context_priv->fragment_len = 0;
935 		context->context_priv->fragment_n = 0;
936 		context->context_priv->fragment_k = 0;
937 	    }
938 	} else if (n == context->context_priv->fragment_n &&
939 		k == context->context_priv->fragment_k + 1) {
940 	    size_t fraglen = end - start - 1;
941 	    char *newfrag = NULL;
942 	    size_t newsize = context->context_priv->fragment_len + fraglen + 1;
943 	    /* Check for overflow */
944 	    if (newsize > context->context_priv->fragment_len) {
945 		newfrag = realloc(context->context_priv->fragment, newsize);
946 	    }
947 	    if (newfrag) {
948 		context->context_priv->fragment = newfrag;
949 		memmove(context->context_priv->fragment +
950 			context->context_priv->fragment_len,
951 			tag + start, fraglen);
952 		context->context_priv->fragment_len += fraglen;
953 		context->context_priv->fragment[
954 			context->context_priv->fragment_len] = '\0';
955 		context->context_priv->fragment_k = k;
956 	    } else {
957 		free(context->context_priv->fragment);
958 		context->context_priv->fragment = NULL;
959 		context->context_priv->fragment_len = 0;
960 		context->context_priv->fragment_n = 0;
961 		context->context_priv->fragment_k = 0;
962 	    }
963 	} else {
964 	    free(context->context_priv->fragment);
965 	    context->context_priv->fragment = NULL;
966 	    context->context_priv->fragment_len = 0;
967 	    context->context_priv->fragment_n = 0;
968 	    context->context_priv->fragment_k = 0;
969 	}
970     }
971 
972     if (context->context_priv->fragment_n > 0 &&
973 	    context->context_priv->fragment_n ==
974 	    context->context_priv->fragment_k) {
975 	/* We've got a complete message */
976 	*unfragmessagep = context->context_priv->fragment;
977 	context->context_priv->fragment = NULL;
978 	context->context_priv->fragment_len = 0;
979 	context->context_priv->fragment_n = 0;
980 	context->context_priv->fragment_k = 0;
981 	res = OTRL_FRAGMENT_COMPLETE;
982     }
983 
984     return res;
985 }
986 
987 /* Create a fragmented message. */
otrl_proto_fragment_create(int mms,int fragment_count,char *** fragments,ConnContext * context,const char * message)988 gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count,
989 	char ***fragments, ConnContext *context, const char *message)
990 {
991     char *fragdata;
992     size_t fragdatalen = 0;
993     int curfrag = 0;
994     size_t index = 0;
995     size_t msglen = strlen(message);
996     /* Should vary by number of msgs */
997     int headerlen = context->protocol_version == 3 ? 37 : 19;
998 
999     char **fragmentarray;
1000 
1001     if (fragment_count < 1 || fragment_count > 65535) {
1002 	return gcry_error(GPG_ERR_INV_VALUE);
1003     }
1004 
1005     fragmentarray = malloc(fragment_count * sizeof(char*));
1006     if(!fragmentarray) return gcry_error(GPG_ERR_ENOMEM);
1007 
1008     /*
1009      * Find the next message fragment and store it in the array.
1010      */
1011     for(curfrag = 1; curfrag <= fragment_count; curfrag++) {
1012 	int i;
1013 	char *fragmentmsg;
1014 
1015 	if (msglen - index < (size_t)(mms - headerlen)) {
1016 	    fragdatalen = msglen - index;
1017 	} else {
1018 	    fragdatalen = mms - headerlen;
1019 	}
1020 
1021 	fragdata = malloc(fragdatalen + 1);
1022 	if(!fragdata) {
1023 		for (i=0; i<curfrag-1; free(fragmentarray[i++])) {}
1024 		free(fragmentarray);
1025 		return gcry_error(GPG_ERR_ENOMEM);
1026 	}
1027 	strncpy(fragdata, message, fragdatalen);
1028 	fragdata[fragdatalen] = 0;
1029 
1030 	fragmentmsg = malloc(fragdatalen+headerlen+1);
1031 	if(!fragmentmsg) {
1032 	    for (i=0; i<curfrag-1; free(fragmentarray[i++])) {}
1033 	    free(fragmentarray);
1034 	    free(fragdata);
1035 	    return gcry_error(GPG_ERR_ENOMEM);
1036 	}
1037 
1038 	/*
1039 	 * Create the actual fragment and store it in the array
1040 	 */
1041 	if (context->auth.protocol_version != 3) {
1042 	    snprintf(fragmentmsg, fragdatalen + headerlen,
1043 		    "?OTR,%05hu,%05hu,%s,", (unsigned short)curfrag,
1044 			    (unsigned short)fragment_count, fragdata);
1045 	} else {
1046 	    /* V3 messages require instance tags in the header */
1047 	    snprintf(fragmentmsg, fragdatalen + headerlen,
1048 		    "?OTR|%08x|%08x,%05hu,%05hu,%s,",
1049 		    context->our_instance, context->their_instance,
1050 		    (unsigned short)curfrag, (unsigned short)fragment_count,
1051 		    fragdata);
1052 	}
1053 	fragmentmsg[fragdatalen + headerlen] = 0;
1054 
1055 	fragmentarray[curfrag-1] = fragmentmsg;
1056 
1057 	free(fragdata);
1058 	index += fragdatalen;
1059 	message += fragdatalen;
1060     }
1061 
1062     *fragments = fragmentarray;
1063     return gcry_error(GPG_ERR_NO_ERROR);
1064 }
1065 
1066 /* Free a string array containing fragment messages. */
otrl_proto_fragment_free(char *** fragments,unsigned short arraylen)1067 void otrl_proto_fragment_free(char ***fragments, unsigned short arraylen)
1068 {
1069     int i;
1070     char **fragmentarray = *fragments;
1071     if(fragmentarray) {
1072 	for(i = 0; i < arraylen; i++)
1073 	{
1074 	    if(fragmentarray[i]) {
1075 		free(fragmentarray[i]);
1076 	    }
1077 	}
1078 	free(fragmentarray);
1079     }
1080 }
1081 
1082