2
* Off-the-Record Messaging library
3
* Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of version 2.1 of the GNU Lesser General
8
* Public License as published by the Free Software Foundation.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
/* libgcrypt headers */
30
/* Create a new connection context. */
31
static ConnContext * new_context(const char * user, const char * accountname,
32
const char * protocol)
34
ConnContext * context;
36
context = malloc(sizeof(*context));
37
assert(context != NULL);
38
context->username = strdup(user);
39
context->accountname = strdup(accountname);
40
context->protocol = strdup(protocol);
41
context->fragment = NULL;
42
context->fragment_len = 0;
43
context->fragment_n = 0;
44
context->fragment_k = 0;
45
context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
46
otrl_auth_new(&(context->auth));
48
smstate = malloc(sizeof(OtrlSMState));
49
assert(smstate != NULL);
50
otrl_sm_state_new(smstate);
51
context->smstate = smstate;
53
context->fingerprint_root.fingerprint = NULL;
54
context->fingerprint_root.context = context;
55
context->fingerprint_root.next = NULL;
56
context->fingerprint_root.tous = NULL;
57
context->active_fingerprint = NULL;
58
context->their_keyid = 0;
59
context->their_y = NULL;
60
context->their_old_y = NULL;
61
context->our_keyid = 0;
62
context->our_dh_key.groupid = 0;
63
context->our_dh_key.priv = NULL;
64
context->our_dh_key.pub = NULL;
65
context->our_old_dh_key.groupid = 0;
66
context->our_old_dh_key.priv = NULL;
67
context->our_old_dh_key.pub = NULL;
68
otrl_dh_session_blank(&(context->sesskeys[0][0]));
69
otrl_dh_session_blank(&(context->sesskeys[0][1]));
70
otrl_dh_session_blank(&(context->sesskeys[1][0]));
71
otrl_dh_session_blank(&(context->sesskeys[1][1]));
72
memset(context->sessionid, 0, 20);
73
context->sessionid_len = 0;
74
context->protocol_version = 0;
75
context->numsavedkeys = 0;
76
context->preshared_secret = NULL;
77
context->preshared_secret_len = 0;
78
context->saved_mac_keys = NULL;
79
context->generation = 0;
80
context->lastsent = 0;
81
context->lastmessage = NULL;
82
context->may_retransmit = 0;
83
context->otr_offer = OFFER_NOT;
84
context->app_data = NULL;
85
context->app_data_free = NULL;
90
/* Look up a connection context by name/account/protocol from the given
91
* OtrlUserState. If add_if_missing is true, allocate and return a new
92
* context if one does not currently exist. In that event, call
93
* add_app_data(data, context) so that app_data and app_data_free can be
94
* filled in by the application, and set *addedp to 1. */
95
ConnContext * otrl_context_find(OtrlUserState us, const char *user,
96
const char *accountname, const char *protocol, int add_if_missing,
98
void (*add_app_data)(void *data, ConnContext *context), void *data)
101
int usercmp = 1, acctcmp = 1, protocmp = 1;
102
if (addedp) *addedp = 0;
103
if (!user || !accountname || !protocol) return NULL;
104
for (curp = &(us->context_root); *curp; curp = &((*curp)->next)) {
105
if ((usercmp = strcmp((*curp)->username, user)) > 0 ||
107
(acctcmp = strcmp((*curp)->accountname, accountname)) > 0) ||
108
(usercmp == 0 && acctcmp == 0 &&
109
(protocmp = strcmp((*curp)->protocol, protocol)) >= 0))
110
/* We're at the right place in the list. We've either found
111
* it, or gone too far. */
114
if (usercmp == 0 && acctcmp == 0 && protocmp == 0) {
118
if (add_if_missing) {
120
if (addedp) *addedp = 1;
121
newctx = new_context(user, accountname, protocol);
122
newctx->next = *curp;
124
(*curp)->tous = &(newctx->next);
129
add_app_data(data, *curp);
136
/* Find a fingerprint in a given context, perhaps adding it if not
138
Fingerprint *otrl_context_find_fingerprint(ConnContext *context,
139
unsigned char fingerprint[20], int add_if_missing, int *addedp)
141
Fingerprint *f = context->fingerprint_root.next;
142
if (addedp) *addedp = 0;
144
if (!memcmp(f->fingerprint, fingerprint, 20)) return f;
147
/* Didn't find it. */
148
if (add_if_missing) {
149
if (addedp) *addedp = 1;
150
f = malloc(sizeof(*f));
152
f->fingerprint = malloc(20);
153
assert(f->fingerprint != NULL);
154
memmove(f->fingerprint, fingerprint, 20);
155
f->context = context;
157
f->next = context->fingerprint_root.next;
159
f->next->tous = &(f->next);
161
context->fingerprint_root.next = f;
162
f->tous = &(context->fingerprint_root.next);
168
/* Set the trust level for a given fingerprint */
169
void otrl_context_set_trust(Fingerprint *fprint, const char *trust)
171
if (fprint == NULL) return;
174
fprint->trust = trust ? strdup(trust) : NULL;
177
/* Set the preshared secret for a given fingerprint. Note that this
178
* currently only stores the secret in the ConnContext structure, but
179
* doesn't yet do anything with it. */
180
void otrl_context_set_preshared_secret(ConnContext *context,
181
const unsigned char *secret, size_t secret_len)
183
free(context->preshared_secret);
184
context->preshared_secret = NULL;
185
context->preshared_secret_len = 0;
188
context->preshared_secret = malloc(secret_len);
189
if (context->preshared_secret) {
190
memmove(context->preshared_secret, secret, secret_len);
191
context->preshared_secret_len = secret_len;
196
/* Force a context into the OTRL_MSGSTATE_FINISHED state. */
197
void otrl_context_force_finished(ConnContext *context)
199
context->msgstate = OTRL_MSGSTATE_FINISHED;
200
otrl_auth_clear(&(context->auth));
201
free(context->fragment);
202
context->fragment = NULL;
203
context->fragment_len = 0;
204
context->fragment_n = 0;
205
context->fragment_k = 0;
206
context->active_fingerprint = NULL;
207
context->their_keyid = 0;
208
gcry_mpi_release(context->their_y);
209
context->their_y = NULL;
210
gcry_mpi_release(context->their_old_y);
211
context->their_old_y = NULL;
212
context->our_keyid = 0;
213
otrl_dh_keypair_free(&(context->our_dh_key));
214
otrl_dh_keypair_free(&(context->our_old_dh_key));
215
otrl_dh_session_free(&(context->sesskeys[0][0]));
216
otrl_dh_session_free(&(context->sesskeys[0][1]));
217
otrl_dh_session_free(&(context->sesskeys[1][0]));
218
otrl_dh_session_free(&(context->sesskeys[1][1]));
219
memset(context->sessionid, 0, 20);
220
context->sessionid_len = 0;
221
free(context->preshared_secret);
222
context->preshared_secret = NULL;
223
context->preshared_secret_len = 0;
224
context->protocol_version = 0;
225
context->numsavedkeys = 0;
226
free(context->saved_mac_keys);
227
context->saved_mac_keys = NULL;
228
gcry_free(context->lastmessage);
229
context->lastmessage = NULL;
230
context->may_retransmit = 0;
231
otrl_sm_state_free(context->smstate);
234
/* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */
235
void otrl_context_force_plaintext(ConnContext *context)
237
/* First clean up everything we'd need to do for the FINISHED state */
238
otrl_context_force_finished(context);
240
/* And just set the state properly */
241
context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
244
/* Forget a fingerprint (so long as it's not the active one. If it's a
245
* fingerprint_root, forget the whole context (as long as
246
* and_maybe_context is set, and it's PLAINTEXT). Also, if it's not
247
* the fingerprint_root, but it's the only fingerprint, and we're
248
* PLAINTEXT, forget the whole context if and_maybe_context is set. */
249
void otrl_context_forget_fingerprint(Fingerprint *fprint,
250
int and_maybe_context)
252
ConnContext *context = fprint->context;
253
if (fprint == &(context->fingerprint_root)) {
254
if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
256
otrl_context_forget(context);
259
if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT ||
260
context->active_fingerprint != fprint) {
261
free(fprint->fingerprint);
263
*(fprint->tous) = fprint->next;
265
fprint->next->tous = fprint->tous;
268
if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT &&
269
context->fingerprint_root.next == NULL &&
271
/* We just deleted the only fingerprint. Forget the
273
otrl_context_forget(context);
279
/* Forget a whole context, so long as it's PLAINTEXT. */
280
void otrl_context_forget(ConnContext *context)
282
if (context->msgstate != OTRL_MSGSTATE_PLAINTEXT) return;
284
/* Just to be safe, force to plaintext. This also frees any
285
* extraneous data lying around. */
286
otrl_context_force_plaintext(context);
288
/* First free all the Fingerprints */
289
while(context->fingerprint_root.next) {
290
otrl_context_forget_fingerprint(context->fingerprint_root.next, 0);
292
/* Now free all the dynamic info here */
293
free(context->username);
294
free(context->accountname);
295
free(context->protocol);
296
free(context->smstate);
297
context->username = NULL;
298
context->accountname = NULL;
299
context->protocol = NULL;
300
context->smstate = NULL;
302
/* Free the application data, if it exists */
303
if (context->app_data && context->app_data_free) {
304
(context->app_data_free)(context->app_data);
305
context->app_data = NULL;
308
/* Fix the list linkages */
309
*(context->tous) = context->next;
311
context->next->tous = context->tous;
317
/* Forget all the contexts in a given OtrlUserState. */
318
void otrl_context_forget_all(OtrlUserState us)
320
while (us->context_root) {
321
otrl_context_force_plaintext(us->context_root);
322
otrl_context_forget(us->context_root);