1 /*
2  *  Off-the-Record Messaging library
3  *  Copyright (C) 2004-2014  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 /* system headers */
23 #include <stdlib.h>
24 #include <assert.h>
25 
26 /* libgcrypt headers */
27 #include <gcrypt.h>
28 
29 /* libotr headers */
30 #include "context.h"
31 #include "instag.h"
32 
33 #if OTRL_DEBUGGING
34 #include <stdio.h>
35 
36 void otrl_auth_dump(FILE *f, const OtrlAuthInfo *auth);
37 void otrl_sm_dump(FILE *f, const OtrlSMState *sm);
38 
39 /* Dump the contents of a context to the FILE *f. */
otrl_context_dump(FILE * f,const ConnContext * context)40 void otrl_context_dump(FILE *f, const ConnContext *context)
41 {
42     const Fingerprint *fing;
43 
44     fprintf(f, "Context %p:\n\n", context);
45 
46     fprintf(f, "  Username: %s\n", context->username);
47     fprintf(f, "  Accountname: %s\n", context->accountname);
48     fprintf(f, "  Protocol: %s\n\n", context->protocol);
49     fprintf(f, "  Master context: %p%s\n", context->m_context,
50 	    context->m_context == context ? " IS MASTER" : "");
51     fprintf(f, "  Recent recv child: %p\n", context->recent_rcvd_child);
52     fprintf(f, "  Recent sent child: %p\n", context->recent_sent_child);
53     fprintf(f, "  Recent child: %p\n\n", context->recent_child);
54     fprintf(f, "  Our instance:   %08x\n", context->our_instance);
55     fprintf(f, "  Their instance: %08x\n\n", context->their_instance);
56     fprintf(f, "  Msgstate: %d (%s)\n\n", context->msgstate,
57 	context->msgstate == OTRL_MSGSTATE_PLAINTEXT ? "PLAINTEXT" :
58 	context->msgstate == OTRL_MSGSTATE_ENCRYPTED ? "ENCRYPTED" :
59 	context->msgstate == OTRL_MSGSTATE_FINISHED ? "FINISHED" :
60 	"INVALID");
61     otrl_auth_dump(f, &context->auth);
62     fprintf(f, "\n  Fingerprints:\n");
63     for (fing = context->fingerprint_root.next; fing; fing = fing->next) {
64 	fprintf(f, "    %p ", fing);
65 	if (fing->fingerprint == NULL) {
66 	    fprintf(f, "(null)");
67 	} else {
68 	    int i;
69 	    for (i=0;i<20;++i) {
70 		fprintf(f, "%02x", fing->fingerprint[i]);
71 	    }
72 	}
73 	fprintf(f, " %p", fing->context);
74 	if (fing->trust && fing->trust[0]) {
75 	    fprintf(f, " %s", fing->trust);
76 	}
77 	fprintf(f, "\n");
78     }
79     fprintf(f, "\n  Active fingerprint: %p\n\n", context->active_fingerprint);
80     fprintf(f, "  Protocol version: %d\n", context->protocol_version);
81     fprintf(f, "  OTR offer: %d (%s)\n\n", context->otr_offer,
82 	context->otr_offer == OFFER_NOT ? "NOT" :
83 	context->otr_offer == OFFER_SENT ? "SENT" :
84 	context->otr_offer == OFFER_REJECTED ? "REJECTED" :
85 	context->otr_offer == OFFER_ACCEPTED ? "ACCEPTED" :
86 	"INVALID");
87 
88     fprintf(f, "  Application data: %p\n", context->app_data);
89     if (context->smstate == NULL) {
90 	fprintf(f, "  SM state: NULL\n");
91     } else {
92 	otrl_sm_dump(f, context->smstate);
93     }
94     fprintf(f, "\n");
95 }
96 
97 /* Dump the master context of this context, and all of its children. */
otrl_context_siblings_dump(FILE * f,const ConnContext * context)98 void otrl_context_siblings_dump(FILE *f, const ConnContext *context)
99 {
100     const ConnContext *citer;
101     for (citer = context->m_context;
102 	    citer && citer->m_context == context->m_context;
103 	    citer = citer->next) {
104 	if (citer == context) {
105 	    fprintf(f, "*** ");
106 	}
107 	otrl_context_dump(f, citer);
108     }
109 }
110 
111 /* Dump all contexts. */
otrl_context_all_dump(FILE * f,OtrlUserState us)112 void otrl_context_all_dump(FILE *f, OtrlUserState us)
113 {
114     const ConnContext *citer;
115     unsigned int ctxnum = 1;
116     for (citer = us->context_root; citer; citer = citer->next, ++ctxnum) {
117 	fprintf(f, "%u. ", ctxnum);
118 	otrl_context_dump(f, citer);
119     }
120 }
121 #endif
122 
123 /* Create a new connection context. */
new_context(const char * user,const char * accountname,const char * protocol)124 static ConnContext * new_context(const char * user, const char * accountname,
125 	const char * protocol)
126 {
127     ConnContext * context;
128     OtrlSMState *smstate;
129 
130     context = malloc(sizeof(ConnContext));
131     assert(context != NULL);
132 
133     context->username = strdup(user);
134     context->accountname = strdup(accountname);
135     context->protocol = strdup(protocol);
136 
137     context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
138     otrl_auth_new(context);
139 
140     smstate = malloc(sizeof(OtrlSMState));
141     assert(smstate != NULL);
142     otrl_sm_state_new(smstate);
143     context->smstate = smstate;
144 
145     context->our_instance = 0;
146     context->their_instance = OTRL_INSTAG_MASTER;
147     context->fingerprint_root.fingerprint = NULL;
148     context->fingerprint_root.context = context;
149     context->fingerprint_root.next = NULL;
150     context->fingerprint_root.tous = NULL;
151     context->active_fingerprint = NULL;
152     memset(context->sessionid, 0, 20);
153     context->sessionid_len = 0;
154     context->protocol_version = 0;
155     context->otr_offer = OFFER_NOT;
156     context->app_data = NULL;
157     context->app_data_free = NULL;
158     context->context_priv = otrl_context_priv_new();
159     assert(context->context_priv != NULL);
160     context->next = NULL;
161     context->m_context = context;
162     context->recent_rcvd_child = NULL;
163     context->recent_sent_child = NULL;
164     context->recent_child = NULL;
165 
166     return context;
167 }
168 
otrl_context_find_recent_instance(ConnContext * context,otrl_instag_t recent_instag)169 ConnContext * otrl_context_find_recent_instance(ConnContext * context,
170 	otrl_instag_t recent_instag) {
171     ConnContext * m_context;
172 
173     if (!context) return NULL;
174 
175     m_context = context->m_context;
176 
177     if (!m_context) return NULL;
178 
179     switch(recent_instag) {
180 	case OTRL_INSTAG_RECENT:
181 	    return m_context->recent_child;
182 	case OTRL_INSTAG_RECENT_RECEIVED:
183 	    return m_context->recent_rcvd_child;
184 	case OTRL_INSTAG_RECENT_SENT:
185 	    return m_context->recent_sent_child;
186 	default:
187 	    return NULL;
188     }
189 }
190 
191 /* Find the instance of this context that has the best security level,
192    and for which we have most recently received a message from. Note that most
193    recent in this case is limited to a one-second resolution. */
otrl_context_find_recent_secure_instance(ConnContext * context)194 ConnContext * otrl_context_find_recent_secure_instance(ConnContext * context)
195 {
196     ConnContext *curp; /* for iteration */
197     ConnContext *m_context; /* master */
198     ConnContext *cresult = context;  /* best so far */
199 
200     if (!context) {
201 	return cresult;
202     }
203 
204     m_context = context->m_context;
205 
206     for (curp = m_context; curp && curp->m_context == m_context;
207 	    curp = curp->next) {
208 	int msgstate_improved = 0; /* 0 == same, 1 == improved   */
209 	int trust_improved = 0;    /* (will immediately 'continue' if worse
210 				    * than) */
211 
212 	if (cresult->msgstate == curp->msgstate) {
213 	    msgstate_improved = 0;
214 	} else if (curp->msgstate == OTRL_MSGSTATE_ENCRYPTED ||
215 		(cresult->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
216 		curp->msgstate == OTRL_MSGSTATE_FINISHED)) {
217 	    msgstate_improved = 1;
218 	} else {
219 	    continue;
220 	}
221 
222 
223 	if (otrl_context_is_fingerprint_trusted(cresult->active_fingerprint) ==
224 		otrl_context_is_fingerprint_trusted(curp->active_fingerprint)) {
225 
226 	    trust_improved = 0;
227 	} else if
228 		(otrl_context_is_fingerprint_trusted(curp->active_fingerprint)){
229 
230 	    trust_improved = 1;
231 	} else {
232 	    continue;
233 	}
234 
235 	if (msgstate_improved || trust_improved ||
236 		(!msgstate_improved && !trust_improved &&
237 		curp->context_priv->lastrecv >=
238 		cresult->context_priv->lastrecv)) {
239 	    cresult = curp;
240 	}
241     }
242 
243     return cresult;
244 }
245 
246 /* Look up a connection context by name/account/protocol/instag from the given
247  * OtrlUserState.  If add_if_missing is true, allocate and return a new
248  * context if one does not currently exist.  In that event, call
249  * add_app_data(data, context) so that app_data and app_data_free can be
250  * filled in by the application, and set *addedp to 1.
251  * In the 'their_instance' field note that you can also specify a 'meta-
252  * instance' value such as OTRL_INSTAG_MASTER, OTRL_INSTAG_RECENT,
253  * OTRL_INSTAG_RECENT_RECEIVED and OTRL_INSTAG_RECENT_SENT. */
otrl_context_find(OtrlUserState us,const char * user,const char * accountname,const char * protocol,otrl_instag_t their_instance,int add_if_missing,int * addedp,void (* add_app_data)(void * data,ConnContext * context),void * data)254 ConnContext * otrl_context_find(OtrlUserState us, const char *user,
255 	const char *accountname, const char *protocol,
256 	otrl_instag_t their_instance, int add_if_missing, int *addedp,
257 	void (*add_app_data)(void *data, ConnContext *context), void *data)
258 {
259     ConnContext ** curp;
260     int usercmp = 1, acctcmp = 1, protocmp = 1;
261     if (addedp) *addedp = 0;
262     if (!user || !accountname || !protocol) return NULL;
263 
264     for (curp = &(us->context_root); *curp; curp = &((*curp)->next)) {
265 	if ((usercmp = strcmp((*curp)->username, user)) > 0 ||
266 		(usercmp == 0 &&
267 		(acctcmp = strcmp((*curp)->accountname, accountname)) > 0) ||
268 		(usercmp == 0 && acctcmp == 0 &&
269 		(protocmp = strcmp((*curp)->protocol, protocol)) > 0) ||
270 		(usercmp == 0 && acctcmp == 0 && protocmp == 0
271 		&& (their_instance < OTRL_MIN_VALID_INSTAG ||
272 		    ((*curp)->their_instance >= their_instance))))
273 	    /* We're at the right place in the list.  We've either found
274 	     * it, or gone too far. */
275 	    break;
276     }
277 
278     if (usercmp == 0 && acctcmp == 0 && protocmp == 0 && *curp &&
279 	    (their_instance < OTRL_MIN_VALID_INSTAG ||
280 	    (their_instance == (*curp)->their_instance))) {
281 	/* Found one! */
282 	if (their_instance >= OTRL_MIN_VALID_INSTAG ||
283 		their_instance == OTRL_INSTAG_MASTER) {
284 	    return *curp;
285 	}
286 
287 	/* We need to go back and check more values in the context */
288 	switch(their_instance) {
289 	    case OTRL_INSTAG_BEST:
290 		return otrl_context_find_recent_secure_instance(*curp);
291 	    case OTRL_INSTAG_RECENT:
292 	    case OTRL_INSTAG_RECENT_RECEIVED:
293 	    case OTRL_INSTAG_RECENT_SENT:
294 		return otrl_context_find_recent_instance(*curp, their_instance);
295 	    default:
296 		return NULL;
297 	}
298     }
299 
300     if (add_if_missing) {
301 	ConnContext *newctx;
302 	OtrlInsTag *our_instag = (OtrlInsTag *)otrl_instag_find(us, accountname,
303 		protocol);
304 
305 	if (addedp) *addedp = 1;
306 	newctx = new_context(user, accountname, protocol);
307 	newctx->next = *curp;
308 	if (*curp) {
309 	    (*curp)->tous = &(newctx->next);
310 	}
311 	*curp = newctx;
312 	newctx->tous = curp;
313 	if (add_app_data) {
314 	    add_app_data(data, *curp);
315 	}
316 
317 	/* Initialize specified instance tags */
318 	if (our_instag) {
319 	    newctx->our_instance = our_instag->instag;
320 	}
321 
322 	if (their_instance >= OTRL_MIN_VALID_INSTAG ||
323 		their_instance == OTRL_INSTAG_MASTER) {
324 	    newctx->their_instance = their_instance;
325 	}
326 
327 	if (their_instance >= OTRL_MIN_VALID_INSTAG) {
328 	    newctx->m_context = otrl_context_find(us, user, accountname,
329 		protocol, OTRL_INSTAG_MASTER, 1, NULL, add_app_data, data);
330 	}
331 
332 	if (their_instance == OTRL_INSTAG_MASTER) {
333 	    /* if we're adding a master, there are no children, so the most
334 	     * recent context is the one we add. */
335 	    newctx->recent_child = newctx;
336 	    newctx->recent_rcvd_child = newctx;
337 	    newctx->recent_sent_child = newctx;
338 	}
339 
340 	return *curp;
341     }
342     return NULL;
343 }
344 
345 /* Return true iff the given fingerprint is marked as trusted. */
otrl_context_is_fingerprint_trusted(Fingerprint * fprint)346 int otrl_context_is_fingerprint_trusted(Fingerprint *fprint) {
347     return fprint && fprint->trust && fprint->trust[0] != '\0';
348 }
349 
350 /* This method gets called after sending or receiving a message, to
351  * update the master context's "recent context" pointers. */
otrl_context_update_recent_child(ConnContext * context,unsigned int sent_msg)352 void otrl_context_update_recent_child(ConnContext *context,
353 	unsigned int sent_msg) {
354     ConnContext *m_context = context->m_context;
355 
356     if (sent_msg) {
357 	m_context->recent_sent_child = context;
358     } else {
359 	m_context->recent_rcvd_child = context;
360     }
361 
362     m_context->recent_child = context;
363 
364 }
365 
366 /* Find a fingerprint in a given context, perhaps adding it if not
367  * present. */
otrl_context_find_fingerprint(ConnContext * context,unsigned char fingerprint[20],int add_if_missing,int * addedp)368 Fingerprint *otrl_context_find_fingerprint(ConnContext *context,
369 	unsigned char fingerprint[20], int add_if_missing, int *addedp)
370 {
371     Fingerprint *f;
372     if (addedp) *addedp = 0;
373 
374     if (!context || !context->m_context) return NULL;
375 
376     context = context->m_context;
377 
378     f = context->fingerprint_root.next;
379     while(f) {
380 	if (!memcmp(f->fingerprint, fingerprint, 20)) return f;
381 	f = f->next;
382     }
383 
384     /* Didn't find it. */
385     if (add_if_missing) {
386 	if (addedp) *addedp = 1;
387 	f = malloc(sizeof(*f));
388 	assert(f != NULL);
389 	f->fingerprint = malloc(20);
390 	assert(f->fingerprint != NULL);
391 	memmove(f->fingerprint, fingerprint, 20);
392 	f->context = context;
393 	f->trust = NULL;
394 	f->next = context->fingerprint_root.next;
395 	if (f->next) {
396 	    f->next->tous = &(f->next);
397 	}
398 	context->fingerprint_root.next = f;
399 	f->tous = &(context->fingerprint_root.next);
400 	return f;
401     }
402     return NULL;
403 }
404 
405 /* Set the trust level for a given fingerprint */
otrl_context_set_trust(Fingerprint * fprint,const char * trust)406 void otrl_context_set_trust(Fingerprint *fprint, const char *trust)
407 {
408     if (fprint == NULL) return;
409 
410     free(fprint->trust);
411     fprint->trust = trust ? strdup(trust) : NULL;
412 }
413 
414 /* Force a context into the OTRL_MSGSTATE_FINISHED state. */
otrl_context_force_finished(ConnContext * context)415 void otrl_context_force_finished(ConnContext *context)
416 {
417     context->msgstate = OTRL_MSGSTATE_FINISHED;
418     otrl_auth_clear(&(context->auth));
419     context->active_fingerprint = NULL;
420     memset(context->sessionid, 0, 20);
421     context->sessionid_len = 0;
422     context->protocol_version = 0;
423     otrl_sm_state_free(context->smstate);
424     otrl_context_priv_force_finished(context->context_priv);
425 }
426 
427 /* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */
otrl_context_force_plaintext(ConnContext * context)428 void otrl_context_force_plaintext(ConnContext *context)
429 {
430     /* First clean up everything we'd need to do for the FINISHED state */
431     otrl_context_force_finished(context);
432 
433     /* And just set the state properly */
434     context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
435 }
436 
437 /* Forget a fingerprint (so long as it's not the active one.  If it's a
438  * fingerprint_root, forget the whole context (as long as
439  * and_maybe_context is set, and it's PLAINTEXT).  Also, if it's not
440  * the fingerprint_root, but it's the only fingerprint, and we're
441  * PLAINTEXT, forget the whole context if and_maybe_context is set. */
otrl_context_forget_fingerprint(Fingerprint * fprint,int and_maybe_context)442 void otrl_context_forget_fingerprint(Fingerprint *fprint,
443 	int and_maybe_context)
444 {
445     ConnContext *context = fprint->context;
446     if (fprint == &(context->fingerprint_root)) {
447 	if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
448 		and_maybe_context) {
449 	    otrl_context_forget(context);
450 	}
451     } else {
452 	if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT ||
453 		context->active_fingerprint != fprint) {
454 
455 	    free(fprint->fingerprint);
456 	    free(fprint->trust);
457 	    *(fprint->tous) = fprint->next;
458 	    if (fprint->next) {
459 		fprint->next->tous = fprint->tous;
460 	    }
461 	    free(fprint);
462 	    if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
463 		    context->fingerprint_root.next == NULL &&
464 		    and_maybe_context) {
465 		/* We just deleted the only fingerprint.  Forget the
466 		 * whole thing. */
467 		otrl_context_forget(context);
468 	    }
469 	}
470     }
471 }
472 
473 /* Forget a whole context, so long as it's PLAINTEXT. If a context has child
474  * instances, don't remove this instance unless children are also all in
475  * PLAINTEXT state. In this case, the children will also be removed.
476  * Returns 0 on success, 1 on failure. */
otrl_context_forget(ConnContext * context)477 int otrl_context_forget(ConnContext *context)
478 {
479     if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT) return 1;
480 
481     if (context->their_instance == OTRL_INSTAG_MASTER) {
482 	ConnContext *c_iter;
483 
484 	for (c_iter = context; c_iter &&
485 		c_iter->m_context == context->m_context;
486 		c_iter = c_iter->next) {
487 	    if (c_iter->msgstate != OTRL_MSGSTATE_PLAINTEXT) return 1;
488 	}
489 
490 	c_iter = context->next;
491 	while (c_iter && c_iter->m_context == context->m_context) {
492 	    if (!otrl_context_forget(c_iter)) {
493 		c_iter = context->next;
494 	    } else {
495 		return 1;
496 	    }
497 	}
498 
499     }
500 
501     /* Just to be safe, force to plaintext.  This also frees any
502      * extraneous data lying around. */
503     otrl_context_force_plaintext(context);
504 
505     /* First free all the Fingerprints */
506     while(context->fingerprint_root.next) {
507 	otrl_context_forget_fingerprint(context->fingerprint_root.next, 0);
508     }
509     /* Now free all the dynamic info here */
510     free(context->username);
511     free(context->accountname);
512     free(context->protocol);
513     free(context->smstate);
514     context->username = NULL;
515     context->accountname = NULL;
516     context->protocol = NULL;
517     context->smstate = NULL;
518 
519     /* Free the application data, if it exists */
520     if (context->app_data && context->app_data_free) {
521 	(context->app_data_free)(context->app_data);
522 	context->app_data = NULL;
523     }
524 
525     /* Fix the list linkages */
526     *(context->tous) = context->next;
527     if (context->next) {
528 	context->next->tous = context->tous;
529     }
530 
531     free(context);
532     return 0;
533 }
534 
535 /* Forget all the contexts in a given OtrlUserState. */
otrl_context_forget_all(OtrlUserState us)536 void otrl_context_forget_all(OtrlUserState us)
537 {
538     ConnContext *c_iter;
539 
540     for (c_iter = us->context_root; c_iter; c_iter = c_iter->next) {
541 	otrl_context_force_plaintext(c_iter);
542     }
543 
544     while (us->context_root) {
545 	otrl_context_forget(us->context_root);
546     }
547 }
548