6
2.2. Socialist Millionaires' Protocol
8
3.1. OtrlMessageAppOps Callbacks
9
3.1.1. Max Message Size
11
3.2. Using Fragmentation
16
3.3.4. Control Flow and Errors
21
This file contains information about the changes between the 3.0.0 and
22
the 3.2.0 APIs for libotr. Note that, as a minor release, applications
23
compiled against 3.0.0 will continue to work with 3.2.0. This document
24
explains how to add the new functionality in 3.2.0.
28
This section describes the new features in OTR 3.2.0 along with a short
29
history or motivation for each.
31
2.1. Fragmentation [Added in 3.1.0]
33
Most IM networks supported by Pidgin have fixed maximum message sizes
34
(MMS) of approximately 1-3 kB. The longer messages in the initial key
35
exchange and the new socialist millionaires' protocol may exceed these
36
common MMS values. To allow these protocols to work properly even over
37
networks with low MMS values, support for fragmentation was added.
39
OTR version 3.0.0 added support for recombining message fragments to
40
recover the original message. Now that users may be assumed to be able to
41
handle message fragments, support for fragmenting and sending large
42
messages has been added to OTR 3.2.0.
44
2.2. Socialist Millionaires' Protocol [Added in 3.1.0, revised in 3.2.0]
46
In version 3.0.0, the only method available to authenticate a buddy was
47
fingerprint verification. However, many users who are unfamiliar with
48
cryptography do not understand what a fingerprint is or how it is useful.
49
Also, the verification itself relied on the user obtaining an authentic
50
copy of the other party's fingerprint somehow. The simplest way to do so
51
may be to relay the displayed hexadecimal values during a phone call,
52
but this is a large enough hassle that many users omit fingerprint
53
verification altogether.
55
To allow for a method of authentication that is both easier to understand
56
and easier to use, OTR version 3.2.0 includes the Socialist Millionaires'
57
Protocol (SMP). SMP runs as follows: each user inputs a secret string,
58
say "x" and "y". They then exchange a series of messages which reveal
59
the value of (x==y), but no additional information about the inputs.
60
This allows users to determine whether they hold the same secret
61
information with no danger of revealing that secret to an attacker.
63
To see how this is useful for authentication in OTR, assume that Alice
64
and Bob are chatting over OTR for the first time, though they know each
65
other well in real life. Alice may send Bob the following message:
66
"Let's make our shared secret the name of that restaurant we both like
69
Now Alice and Bob run SMP. If Alice is actually talking to Bob directly,
70
then they will both type in the same restaurant name and SMP will return
71
success (x==y). However, if an attacker is impersonating Bob or trying
72
to eavesdrop on the conversation, they will have no idea which restaurant
73
Alice has in mind, and will type in an incorrect value, causing SMP to
74
fail. Note that for security reasons, the values compared in the SMP
75
are actually hashes of several pieces of data, including both parties'
76
fingerprints, along with their respective secrets. The users, however,
77
are never exposed to this additional data.
79
Thus, SMP turns the problem of obtaining an authentic copy of a
80
fingerprint into the much simpler problem of obtaining any shared secret,
81
or simply of drawing on shared experiences to generate one.
83
For detailed information on how SMP works, see the paper by Boudot,
84
Schoenmakers and Traore titled "A Fair and Efficient Solution to the
85
Socialist Millionaires Problem" (2001), on which our solution is based.
87
3. Required Changes [Added in 3.1.0]
89
3.1. OtrlMessageAppOps Callbacks
91
Three new callbacks have been added to the end of OtrlMessageAppOps. If
92
the version number passed to otrl_init is less than 3.1.0 then libotr will
93
not call any of the new callbacks. As well, you may disable individual
94
callbacks by setting them to NULL. In either case, libotr will revert to
95
the standard behaviour of version 3.0.0.
97
3.1.1. Max Message Size
99
The first new callback has the following signature:
101
int (*max_message_size)(void *opdata, ConnContext *context);
103
This method is called whenever a message is about to be sent with
104
fragmentation enabled. The return value is checked against the size of
105
the message to be sent to determine whether fragmentation is necessary.
107
Although the maximum message size depends on a number of factors, we
108
found experimentally that the following rough values based solely on the
109
(pidgin) protocol name work well:
118
Setting max_message_size to NULL will disable the fragmentation of all
119
sent messages; returning 0 from this callback will disable fragmentation
120
of a particular message. The latter is useful, for example, for
121
protocols like XMPP (Jabber) that do not require fragmentation at all.
125
The other two new callbacks have the following signatures:
127
const char *(*account_name)(void *opdata, const char *account,
128
const char *protocol);
129
void (*account_name_free)(void *opdata, const char *account_name);
131
Normally, if an error message needs to be sent from Alice to Bob,
132
containing Alice's account name, the value of ConnContext->accountname
133
will be used. However, if this default name is unsuitable for your
134
application, you can use the above methods to provide replacement values
135
for displayed account names.
137
account_name is called when libotr requires a human-readable version of
138
an account name. account_name_free is called once the name has
139
been used, and the memory allocated by account_name (if any) must be
142
Setting account_name to NULL will cause libotr to use
143
ConnContext->accountname as the displayed name for an account.
145
3.2. Using Fragmentation [Added in 3.1.0]
147
To make use of fragmentation, first make sure that the max_message_size
148
callback described in 3.1.1. has been implemented. Then, whenever you
149
would normally send a message through your IM client, call
150
otrl_message_fragment_and_send instead:
152
gcry_error_t otrl_message_fragment_and_send(const OtrlMessageAppOps *ops,
153
void *opdata, ConnContext *context, const char *message,
154
OtrlFragmentPolicy fragPolicy, char **returnFragment);
156
Here, message is the original, encrypted, unfragmented message.
157
This method will break the message into fragments and send either all of
158
them or almost all of them according to the OtrlFragmentPolicy:
160
OTRL_FRAGMENT_SEND_ALL sends all fragments at once
161
OTRL_FRAGMENT_SEND_ALL_BUT_FIRST sends all but the first fragment
162
OTRL_FRAGMENT_SEND_ALL_BUT_LAST sends all but the last fragment
164
You may wish to use one of the latter two options if you still wish to
165
pass a message through your IM client. In this case, the unsent
166
fragment will be returned in returnFragment and should be sent as a
167
regular message. In order to reassemble the fragments, however, they
168
must be received in order, so at most one of the latter two options
169
will result in readable messages.
171
3.3. Using SMP [Added in 3.1.0, revised in 3.2.0]
173
Recall from section 2.2. above that SMP takes one input string from each
174
user and outputs either failure or success.
178
If you wish to initiate SMP for a user named Alice, you would use
179
otrl_message_initiate_smp.
181
void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
182
void *opdata, ConnContext *context, const unsigned char *secret,
185
Here, secret and secretlen describe the secret text as entered by Alice,
186
for example, ("kitten", 6). The other parameters are common to many
187
otrl_message functions. This method will cause a message to be sent
188
containing an appropriate OTRL_TLV_SMP1 (see below).
192
If you wish to continue SMP by supplying the secret for a second user
193
named Bob, you would use otrl_message_respond_smp:
195
void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
196
void *opdata, ConnContext *context, const unsigned char *secret,
199
The arguments for this method are the same as otrl_message_initiate_smp.
200
This method will send a message with an appropriate OTRL_TLV_SMP2
205
If you wish to abort SMP for any reason, including errors occuring
206
during the protocol, you should use otrl_message_abort_smp:
208
void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
209
void *opdata, ConnContext *context);
211
This method will cause the other user to abandon the current state of
212
SMP by sending an appropriate OTRL_TLV_SMP_ABORT (see below).
214
3.3.4. Control Flow and Errors
216
The protocol itself consists of 4 messages passed between the two users,
217
say Alice and Bob. These messages are identified through their TLVs:
219
OTRL_TLV_SMP1 The initial message, containing a commitment to
221
OTRL_TLV_SMP1Q Like OTRL_TLV_SMP1, but also containing a question
223
OTRL_TLV_SMP2 A response containing a commitment to Bob's secret
224
OTRL_TLV_SMP3 The next message in the chain, from Alice to Bob
225
OTRL_TLV_SMP4 The final message in the chain, from Bob to Alice
226
OTRL_TLV_SMP_ABORT Indicates an error has occurred. Will reset SMP state
228
To determine whether the protocol is proceeding correctly, additional
229
information has been added to ConnContext. You may access
230
context->smstate->nextExpected to find out which TLV should come next,
231
so you can compare this to what was actually received and take an
232
appropriate action. The value is of type NextExpectedSMP and could be
235
OTRL_SMP_EXPECT1 Next SMP TLV should be OTRL_TLV_SMP1
236
OTRL_SMP_EXPECT2 Next SMP TLV should be OTRL_TLV_SMP2
237
OTRL_SMP_EXPECT3 Next SMP TLV should be OTRL_TLV_SMP3
238
OTRL_SMP_EXPECT4 Next SMP TLV should be OTRL_TLV_SMP4
240
If at any point, an SMP TLV of an unexpected type is received, the
241
protocol should abort. Also, if the correct TLV type is received, then
242
the state should be updated accordingly. A typical control flow looks
245
OtrlTLV *tlvs = NULL;
247
[Initialize tlvs to the list of tlvs. This can be done
248
as part of otrl_message_receiving.]
250
ConnContext *context = [correct context];
251
NextExpectedSMP nextMsg = context->smstate->nextExpected;
253
if (context->smstate->sm_prog_state == OTRL_SMP_PROG_CHEATED) {
254
otrg_plugin_abort_smp(context);
255
otrg_dialog_update_smp(context, 0.0);
256
context->smstate->nextExpected = OTRL_SMP_EXPECT1;
257
context->smstate->sm_prog_state = OTRL_SMP_PROG_OK;
259
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
261
if (nextMsg != OTRL_SMP_EXPECT1)
264
char *question = (char *)tlv->data;
265
char *eoq = memchr(question, '\0', tlv->len);
267
[prompt the user with question, get the response,
272
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
274
if (nextMsg != OTRL_SMP_EXPECT1)
277
[get secret from user and continue SMP];
280
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
282
if (nextMsg != OTRL_SMP_EXPECT2)
285
// If we received TLV2, we will send TLV3 and expect TLV4
286
context->smstate->nextExpected = OTRL_SMP_EXPECT4;
289
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
291
if (nextMsg != OTRL_SMP_EXPECT3)
294
// If we received TLV3, we will send TLV4
295
// We will not expect more messages, so prepare for next SMP
296
context->smstate->nextExpected = OTRL_SMP_EXPECT1;
297
// Report result to user
300
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
302
if (nextMsg != OTRL_SMP_EXPECT4)
305
// We will not expect more messages, so prepare for next SMP
306
context->smstate->nextExpected = OTRL_SMP_EXPECT1;
307
// Report result to user
310
tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
312
// The message we are waiting for will not arrive, so reset
313
// and prepare for the next SMP
314
context->smstate->nextExpected = OTRL_SMP_EXPECT1;
318
To report the result to the user after receiving OTRL_TLV_SMP3 or
319
OTRL_TLV_SMP4, check whether context->active_fingerprint->trust is a
320
non-empty string. (That is, check that it's not NULL, and that its
321
first character is not '\0'.) If that is the case, then the SMP
322
completed successfully. Otherwise, the parties entered different secrets.
326
b64.h underwent a minor change in OTR 3.1.0. It was purely a
327
housekeeping change and should not require any changes to dependent code.
329
The arguments to otrl_base64_encode and otrl_base64_decode did not agree
330
in terms of which were of type char* and which were unsigned char*
331
instead. This has been corrected. The new method signatures are:
333
size_t otrl_base64_encode(char *base64data, const unsigned char *data,
335
size_t otrl_base64_decode(unsigned char *data, const char *base64data,