~ubuntu-branches/ubuntu/trusty/libotr2/trusty

« back to all changes in this revision

Viewing changes to src/auth.c

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2012-11-05 01:06:26 UTC
  • Revision ID: package-import@ubuntu.com-20121105010626-4m3hldpaz3jfr3wb
Tags: upstream-3.2.1
ImportĀ upstreamĀ versionĀ 3.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Off-the-Record Messaging library
 
3
 *  Copyright (C) 2004-2008  Ian Goldberg, Chris Alexander, Nikita Borisov
 
4
 *                           <otr@cypherpunks.ca>
 
5
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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
 
18
 */
 
19
 
 
20
/* system headers */
 
21
#include <stdlib.h>
 
22
#include <string.h>
 
23
#include <assert.h>
 
24
 
 
25
/* libotr headers */
 
26
#include "b64.h"
 
27
#include "privkey.h"
 
28
#include "auth.h"
 
29
#include "serial.h"
 
30
 
 
31
/*
 
32
 * Initialize the fields of an OtrlAuthInfo (already allocated).
 
33
 */
 
34
void otrl_auth_new(OtrlAuthInfo *auth)
 
35
{
 
36
    auth->authstate = OTRL_AUTHSTATE_NONE;
 
37
    otrl_dh_keypair_init(&(auth->our_dh));
 
38
    auth->our_keyid = 0;
 
39
    auth->encgx = NULL;
 
40
    auth->encgx_len = 0;
 
41
    memset(auth->r, 0, 16);
 
42
    memset(auth->hashgx, 0, 32);
 
43
    auth->their_pub = NULL;
 
44
    auth->their_keyid = 0;
 
45
    auth->enc_c = NULL;
 
46
    auth->enc_cp = NULL;
 
47
    auth->mac_m1 = NULL;
 
48
    auth->mac_m1p = NULL;
 
49
    auth->mac_m2 = NULL;
 
50
    auth->mac_m2p = NULL;
 
51
    memset(auth->their_fingerprint, 0, 20);
 
52
    auth->initiated = 0;
 
53
    auth->protocol_version = 0;
 
54
    memset(auth->secure_session_id, 0, 20);
 
55
    auth->secure_session_id_len = 0;
 
56
    auth->lastauthmsg = NULL;
 
57
}
 
58
 
 
59
/*
 
60
 * Clear the fields of an OtrlAuthInfo (but leave it allocated).
 
61
 */
 
62
void otrl_auth_clear(OtrlAuthInfo *auth)
 
63
{
 
64
    auth->authstate = OTRL_AUTHSTATE_NONE;
 
65
    otrl_dh_keypair_free(&(auth->our_dh));
 
66
    auth->our_keyid = 0;
 
67
    free(auth->encgx);
 
68
    auth->encgx = NULL;
 
69
    auth->encgx_len = 0;
 
70
    memset(auth->r, 0, 16);
 
71
    memset(auth->hashgx, 0, 32);
 
72
    gcry_mpi_release(auth->their_pub);
 
73
    auth->their_pub = NULL;
 
74
    auth->their_keyid = 0;
 
75
    gcry_cipher_close(auth->enc_c);
 
76
    gcry_cipher_close(auth->enc_cp);
 
77
    gcry_md_close(auth->mac_m1);
 
78
    gcry_md_close(auth->mac_m1p);
 
79
    gcry_md_close(auth->mac_m2);
 
80
    gcry_md_close(auth->mac_m2p);
 
81
    auth->enc_c = NULL;
 
82
    auth->enc_cp = NULL;
 
83
    auth->mac_m1 = NULL;
 
84
    auth->mac_m1p = NULL;
 
85
    auth->mac_m2 = NULL;
 
86
    auth->mac_m2p = NULL;
 
87
    memset(auth->their_fingerprint, 0, 20);
 
88
    auth->initiated = 0;
 
89
    auth->protocol_version = 0;
 
90
    memset(auth->secure_session_id, 0, 20);
 
91
    auth->secure_session_id_len = 0;
 
92
    free(auth->lastauthmsg);
 
93
    auth->lastauthmsg = NULL;
 
94
}
 
95
 
 
96
/*
 
97
 * Start a fresh AKE (version 2) using the given OtrlAuthInfo.  Generate
 
98
 * a fresh DH keypair to use.  If no error is returned, the message to
 
99
 * transmit will be contained in auth->lastauthmsg.
 
100
 */
 
101
gcry_error_t otrl_auth_start_v2(OtrlAuthInfo *auth)
 
102
{
 
103
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
104
    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
 
105
    size_t npub;
 
106
    gcry_cipher_hd_t enc = NULL;
 
107
    unsigned char ctr[16];
 
108
    unsigned char *buf, *bufp;
 
109
    size_t buflen, lenp;
 
110
 
 
111
    /* Clear out this OtrlAuthInfo and start over */
 
112
    otrl_auth_clear(auth);
 
113
    auth->initiated = 1;
 
114
 
 
115
    otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
 
116
    auth->our_keyid = 1;
 
117
 
 
118
    /* Pick an encryption key */
 
119
    gcry_randomize(auth->r, 16, GCRY_STRONG_RANDOM);
 
120
 
 
121
    /* Allocate space for the encrypted g^x */
 
122
    gcry_mpi_print(format, NULL, 0, &npub, auth->our_dh.pub);
 
123
    auth->encgx = malloc(4+npub);
 
124
    if (auth->encgx == NULL) goto memerr;
 
125
    auth->encgx_len = 4+npub;
 
126
    bufp = auth->encgx;
 
127
    lenp = auth->encgx_len;
 
128
    write_mpi(auth->our_dh.pub, npub, "g^x");
 
129
    assert(lenp == 0);
 
130
 
 
131
    /* Hash g^x */
 
132
    gcry_md_hash_buffer(GCRY_MD_SHA256, auth->hashgx, auth->encgx,
 
133
            auth->encgx_len);
 
134
 
 
135
    /* Encrypt g^x using the key r */
 
136
    err = gcry_cipher_open(&enc, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR,
 
137
            GCRY_CIPHER_SECURE);
 
138
    if (err) goto err;
 
139
 
 
140
    err = gcry_cipher_setkey(enc, auth->r, 16);
 
141
    if (err) goto err;
 
142
 
 
143
    memset(ctr, 0, 16);
 
144
    err = gcry_cipher_setctr(enc, ctr, 16);
 
145
    if (err) goto err;
 
146
 
 
147
    err = gcry_cipher_encrypt(enc, auth->encgx, auth->encgx_len, NULL, 0);
 
148
    if (err) goto err;
 
149
 
 
150
    gcry_cipher_close(enc);
 
151
    enc = NULL;
 
152
 
 
153
    /* Now serialize the message */
 
154
    lenp = 3 + 4 + auth->encgx_len + 4 + 32;
 
155
    bufp = malloc(lenp);
 
156
    if (bufp == NULL) goto memerr;
 
157
    buf = bufp;
 
158
    buflen = lenp;
 
159
 
 
160
    memmove(bufp, "\x00\x02\x02", 3); /* header */
 
161
    debug_data("Header", bufp, 3);
 
162
    bufp += 3; lenp -= 3;
 
163
 
 
164
    /* Encrypted g^x */
 
165
    write_int(auth->encgx_len);
 
166
    debug_int("Enc gx len", bufp-4);
 
167
    memmove(bufp, auth->encgx, auth->encgx_len);
 
168
    debug_data("Enc gx", bufp, auth->encgx_len);
 
169
    bufp += auth->encgx_len; lenp -= auth->encgx_len;
 
170
 
 
171
    /* Hashed g^x */
 
172
    write_int(32);
 
173
    debug_int("hashgx len", bufp-4);
 
174
    memmove(bufp, auth->hashgx, 32);
 
175
    debug_data("hashgx", bufp, 32);
 
176
    bufp += 32; lenp -= 32;
 
177
 
 
178
    assert(lenp == 0);
 
179
 
 
180
    auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
 
181
    free(buf);
 
182
    if (auth->lastauthmsg == NULL) goto memerr;
 
183
    auth->authstate = OTRL_AUTHSTATE_AWAITING_DHKEY;
 
184
 
 
185
    return err;
 
186
 
 
187
memerr:
 
188
    err = gcry_error(GPG_ERR_ENOMEM);
 
189
err:
 
190
    otrl_auth_clear(auth);
 
191
    gcry_cipher_close(enc);
 
192
    return err;
 
193
}
 
194
 
 
195
/*
 
196
 * Create a D-H Key Message using the our_dh value in the given auth,
 
197
 * and store it in auth->lastauthmsg.
 
198
 */
 
199
static gcry_error_t create_key_message(OtrlAuthInfo *auth)
 
200
{
 
201
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
202
    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
 
203
    unsigned char *buf, *bufp;
 
204
    size_t buflen, lenp;
 
205
    size_t npub;
 
206
 
 
207
    gcry_mpi_print(format, NULL, 0, &npub, auth->our_dh.pub);
 
208
    buflen = 3 + 4 + npub;
 
209
    buf = malloc(buflen);
 
210
    if (buf == NULL) goto memerr;
 
211
    bufp = buf;
 
212
    lenp = buflen;
 
213
 
 
214
    memmove(bufp, "\x00\x02\x0a", 3); /* header */
 
215
    debug_data("Header", bufp, 3);
 
216
    bufp += 3; lenp -= 3;
 
217
 
 
218
    /* g^y */
 
219
    write_mpi(auth->our_dh.pub, npub, "g^y");
 
220
 
 
221
    assert(lenp == 0);
 
222
 
 
223
    free(auth->lastauthmsg);
 
224
    auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
 
225
    free(buf);
 
226
    if (auth->lastauthmsg == NULL) goto memerr;
 
227
 
 
228
    return err;
 
229
 
 
230
memerr:
 
231
    err = gcry_error(GPG_ERR_ENOMEM);
 
232
    return err;
 
233
}
 
234
 
 
235
/*
 
236
 * Handle an incoming D-H Commit Message.  If no error is returned, the
 
237
 * message to send will be left in auth->lastauthmsg.  Generate a fresh
 
238
 * keypair to use.
 
239
 */
 
240
gcry_error_t otrl_auth_handle_commit(OtrlAuthInfo *auth,
 
241
        const char *commitmsg)
 
242
{
 
243
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
244
    unsigned char *buf = NULL, *bufp = NULL, *encbuf = NULL;
 
245
    unsigned char hashbuf[32];
 
246
    size_t buflen, lenp, enclen, hashlen;
 
247
    int res;
 
248
 
 
249
    res = otrl_base64_otr_decode(commitmsg, &buf, &buflen);
 
250
    if (res == -1) goto memerr;
 
251
    if (res == -2) goto invval;
 
252
 
 
253
    bufp = buf;
 
254
    lenp = buflen;
 
255
 
 
256
    /* Header */
 
257
    require_len(3);
 
258
    if (memcmp(bufp, "\x00\x02\x02", 3)) goto invval;
 
259
    bufp += 3; lenp -= 3;
 
260
 
 
261
    /* Encrypted g^x */
 
262
    read_int(enclen);
 
263
    require_len(enclen);
 
264
    encbuf = malloc(enclen);
 
265
    if (encbuf == NULL && enclen > 0) goto memerr;
 
266
    memmove(encbuf, bufp, enclen);
 
267
    bufp += enclen; lenp -= enclen;
 
268
 
 
269
    /* Hashed g^x */
 
270
    read_int(hashlen);
 
271
    if (hashlen != 32) goto invval;
 
272
    require_len(32);
 
273
    memmove(hashbuf, bufp, 32);
 
274
    bufp += 32; lenp -= 32;
 
275
 
 
276
    if (lenp != 0) goto invval;
 
277
    free(buf);
 
278
    buf = NULL;
 
279
 
 
280
    switch(auth->authstate) {
 
281
        case OTRL_AUTHSTATE_NONE:
 
282
        case OTRL_AUTHSTATE_AWAITING_SIG:
 
283
        case OTRL_AUTHSTATE_V1_SETUP:
 
284
 
 
285
            /* Store the incoming information */
 
286
            otrl_auth_clear(auth);
 
287
            otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
 
288
            auth->our_keyid = 1;
 
289
            auth->encgx = encbuf;
 
290
            encbuf = NULL;
 
291
            auth->encgx_len = enclen;
 
292
            memmove(auth->hashgx, hashbuf, 32);
 
293
 
 
294
            /* Create a D-H Key Message */
 
295
            err = create_key_message(auth);
 
296
            if (err) goto err;
 
297
            auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG;
 
298
 
 
299
            break;
 
300
 
 
301
        case OTRL_AUTHSTATE_AWAITING_DHKEY:
 
302
            /* We sent a D-H Commit Message, and we also received one
 
303
             * back.  Compare the hashgx values to see which one wins. */
 
304
            if (memcmp(auth->hashgx, hashbuf, 32) > 0) {
 
305
                /* Ours wins.  Ignore the message we received, and just
 
306
                 * resend the same D-H Commit message again. */
 
307
                free(encbuf);
 
308
                encbuf = NULL;
 
309
            } else {
 
310
                /* Ours loses.  Use the incoming parameters instead. */
 
311
                otrl_auth_clear(auth);
 
312
                otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
 
313
                auth->our_keyid = 1;
 
314
                auth->encgx = encbuf;
 
315
                encbuf = NULL;
 
316
                auth->encgx_len = enclen;
 
317
                memmove(auth->hashgx, hashbuf, 32);
 
318
 
 
319
                /* Create a D-H Key Message */
 
320
                err = create_key_message(auth);
 
321
                if (err) goto err;
 
322
                auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG;
 
323
            }
 
324
            break;
 
325
        case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
 
326
            /* Use the incoming parameters, but just retransmit the old
 
327
             * D-H Key Message. */
 
328
            free(auth->encgx);
 
329
            auth->encgx = encbuf;
 
330
            encbuf = NULL;
 
331
            auth->encgx_len = enclen;
 
332
            memmove(auth->hashgx, hashbuf, 32);
 
333
            break;
 
334
    }
 
335
 
 
336
    return err;
 
337
 
 
338
invval:
 
339
    err = gcry_error(GPG_ERR_INV_VALUE);
 
340
    goto err;
 
341
memerr:
 
342
    err = gcry_error(GPG_ERR_ENOMEM);
 
343
err:
 
344
    free(buf);
 
345
    free(encbuf);
 
346
    return err;
 
347
}
 
348
 
 
349
/*
 
350
 * Calculate the encrypted part of the Reveal Signature and Signature
 
351
 * Messages, given a MAC key, an encryption key, two DH public keys, an
 
352
 * authentication public key (contained in an OtrlPrivKey structure),
 
353
 * and a keyid.  If no error is returned, *authbufp will point to the
 
354
 * result, and *authlenp will point to its length.
 
355
 */
 
356
static gcry_error_t calculate_pubkey_auth(unsigned char **authbufp,
 
357
        size_t *authlenp, gcry_md_hd_t mackey, gcry_cipher_hd_t enckey,
 
358
        gcry_mpi_t our_dh_pub, gcry_mpi_t their_dh_pub,
 
359
        OtrlPrivKey *privkey, unsigned int keyid)
 
360
{
 
361
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
362
    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
 
363
    size_t ourpublen, theirpublen, totallen, lenp;
 
364
    unsigned char *buf = NULL, *bufp = NULL;
 
365
    unsigned char macbuf[32];
 
366
    unsigned char *sigbuf = NULL;
 
367
    size_t siglen;
 
368
 
 
369
    /* How big are the DH public keys? */
 
370
    gcry_mpi_print(format, NULL, 0, &ourpublen, our_dh_pub);
 
371
    gcry_mpi_print(format, NULL, 0, &theirpublen, their_dh_pub);
 
372
 
 
373
    /* How big is the total structure to be MAC'd? */
 
374
    totallen = 4 + ourpublen + 4 + theirpublen + 2 + privkey->pubkey_datalen
 
375
        + 4;
 
376
    buf = malloc(totallen);
 
377
    if (buf == NULL) goto memerr;
 
378
 
 
379
    bufp = buf;
 
380
    lenp = totallen;
 
381
 
 
382
    /* Write the data to be MAC'd */
 
383
    write_mpi(our_dh_pub, ourpublen, "Our DH pubkey");
 
384
    write_mpi(their_dh_pub, theirpublen, "Their DH pubkey");
 
385
    bufp[0] = ((privkey->pubkey_type) >> 16) & 0xff;
 
386
    bufp[1] = (privkey->pubkey_type) & 0xff;
 
387
    bufp += 2; lenp -= 2;
 
388
    memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen);
 
389
    debug_data("Pubkey", bufp, privkey->pubkey_datalen);
 
390
    bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen;
 
391
    write_int(keyid);
 
392
    debug_int("Keyid", bufp-4);
 
393
 
 
394
    assert(lenp == 0);
 
395
 
 
396
    /* Do the MAC */
 
397
    gcry_md_reset(mackey);
 
398
    gcry_md_write(mackey, buf, totallen);
 
399
    memmove(macbuf, gcry_md_read(mackey, GCRY_MD_SHA256), 32);
 
400
 
 
401
    free(buf);
 
402
    buf = NULL;
 
403
 
 
404
    /* Sign the MAC */
 
405
    err = otrl_privkey_sign(&sigbuf, &siglen, privkey, macbuf, 32);
 
406
    if (err) goto err;
 
407
 
 
408
    /* Calculate the total size of the structure to be encrypted */
 
409
    totallen = 2 + privkey->pubkey_datalen + 4 + siglen;
 
410
    buf = malloc(totallen);
 
411
    if (buf == NULL) goto memerr;
 
412
    bufp = buf;
 
413
    lenp = totallen;
 
414
 
 
415
    /* Write the data to be encrypted */
 
416
    bufp[0] = ((privkey->pubkey_type) >> 16) & 0xff;
 
417
    bufp[1] = (privkey->pubkey_type) & 0xff;
 
418
    bufp += 2; lenp -= 2;
 
419
    memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen);
 
420
    debug_data("Pubkey", bufp, privkey->pubkey_datalen);
 
421
    bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen;
 
422
    write_int(keyid);
 
423
    debug_int("Keyid", bufp-4);
 
424
    memmove(bufp, sigbuf, siglen);
 
425
    debug_data("Signature", bufp, siglen);
 
426
    bufp += siglen; lenp -= siglen;
 
427
    free(sigbuf);
 
428
    sigbuf = NULL;
 
429
 
 
430
    assert(lenp == 0);
 
431
 
 
432
    /* Now do the encryption */
 
433
    err = gcry_cipher_encrypt(enckey, buf, totallen, NULL, 0);
 
434
    if (err) goto err;
 
435
 
 
436
    *authbufp = buf;
 
437
    buf = NULL;
 
438
    *authlenp = totallen;
 
439
 
 
440
    return err;
 
441
memerr:
 
442
    err = gcry_error(GPG_ERR_ENOMEM);
 
443
err:
 
444
    free(buf);
 
445
    free(sigbuf);
 
446
    return err;
 
447
}
 
448
 
 
449
/*
 
450
 * Decrypt the authenticator in the Reveal Signature and Signature
 
451
 * Messages, given a MAC key, and encryption key, and two DH public
 
452
 * keys.  The fingerprint of the received public key will get put into
 
453
 * fingerprintbufp, and the received keyid will get put in *keyidp.
 
454
 * The encrypted data pointed to by authbuf will be decrypted in place.
 
455
 */
 
456
static gcry_error_t check_pubkey_auth(unsigned char fingerprintbufp[20],
 
457
        unsigned int *keyidp, unsigned char *authbuf, size_t authlen,
 
458
        gcry_md_hd_t mackey, gcry_cipher_hd_t enckey,
 
459
        gcry_mpi_t our_dh_pub, gcry_mpi_t their_dh_pub)
 
460
{
 
461
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
462
    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
 
463
    size_t ourpublen, theirpublen, totallen, lenp;
 
464
    unsigned char *buf = NULL, *bufp = NULL;
 
465
    unsigned char macbuf[32];
 
466
    unsigned short pubkey_type;
 
467
    gcry_mpi_t p,q,g,y;
 
468
    gcry_sexp_t pubs = NULL;
 
469
    unsigned int received_keyid;
 
470
    unsigned char *fingerprintstart, *fingerprintend, *sigbuf;
 
471
    size_t siglen;
 
472
 
 
473
    /* Start by decrypting it */
 
474
    err = gcry_cipher_decrypt(enckey, authbuf, authlen, NULL, 0);
 
475
    if (err) goto err;
 
476
 
 
477
    bufp = authbuf;
 
478
    lenp = authlen;
 
479
 
 
480
    /* Get the public key and calculate its fingerprint */
 
481
    require_len(2);
 
482
    pubkey_type = (bufp[0] << 8) + bufp[1];
 
483
    bufp += 2; lenp -= 2;
 
484
    if (pubkey_type != OTRL_PUBKEY_TYPE_DSA) goto invval;
 
485
    fingerprintstart = bufp;
 
486
    read_mpi(p);
 
487
    read_mpi(q);
 
488
    read_mpi(g);
 
489
    read_mpi(y);
 
490
    fingerprintend = bufp;
 
491
    gcry_md_hash_buffer(GCRY_MD_SHA1, fingerprintbufp,
 
492
            fingerprintstart, fingerprintend-fingerprintstart);
 
493
    gcry_sexp_build(&pubs, NULL,
 
494
        "(public-key (dsa (p %m)(q %m)(g %m)(y %m)))", p, q, g, y);
 
495
    gcry_mpi_release(p);
 
496
    gcry_mpi_release(q);
 
497
    gcry_mpi_release(g);
 
498
    gcry_mpi_release(y);
 
499
 
 
500
    /* Get the keyid */
 
501
    read_int(received_keyid);
 
502
    if (received_keyid == 0) goto invval;
 
503
 
 
504
    /* Get the signature */
 
505
    sigbuf = bufp;
 
506
    siglen = lenp;
 
507
 
 
508
    /* How big are the DH public keys? */
 
509
    gcry_mpi_print(format, NULL, 0, &ourpublen, our_dh_pub);
 
510
    gcry_mpi_print(format, NULL, 0, &theirpublen, their_dh_pub);
 
511
 
 
512
    /* Now calculate the message to be MAC'd. */
 
513
    totallen = 4 + ourpublen + 4 + theirpublen + 2 +
 
514
        (fingerprintend - fingerprintstart) + 4;
 
515
    buf = malloc(totallen);
 
516
    if (buf == NULL) goto memerr;
 
517
 
 
518
    bufp = buf;
 
519
    lenp = totallen;
 
520
 
 
521
    write_mpi(their_dh_pub, theirpublen, "Their DH pubkey");
 
522
    write_mpi(our_dh_pub, ourpublen, "Our DH pubkey");
 
523
    bufp[0] = (pubkey_type >> 16) & 0xff;
 
524
    bufp[1] = pubkey_type & 0xff;
 
525
    bufp += 2; lenp -= 2;
 
526
    memmove(bufp, fingerprintstart, fingerprintend - fingerprintstart);
 
527
    debug_data("Pubkey", bufp, fingerprintend - fingerprintstart);
 
528
    bufp += fingerprintend - fingerprintstart;
 
529
    lenp -= fingerprintend - fingerprintstart;
 
530
    write_int(received_keyid);
 
531
    debug_int("Keyid", bufp-4);
 
532
 
 
533
    assert(lenp == 0);
 
534
 
 
535
    /* Do the MAC */
 
536
    gcry_md_reset(mackey);
 
537
    gcry_md_write(mackey, buf, totallen);
 
538
    memmove(macbuf, gcry_md_read(mackey, GCRY_MD_SHA256), 32);
 
539
 
 
540
    free(buf);
 
541
    buf = NULL;
 
542
 
 
543
    /* Verify the signature on the MAC */
 
544
    err = otrl_privkey_verify(sigbuf, siglen, pubkey_type, pubs, macbuf, 32);
 
545
    if (err) goto err;
 
546
    gcry_sexp_release(pubs);
 
547
    pubs = NULL;
 
548
 
 
549
    /* Everything checked out */
 
550
    *keyidp = received_keyid;
 
551
 
 
552
    return err;
 
553
invval:
 
554
    err = gcry_error(GPG_ERR_INV_VALUE);
 
555
    goto err;
 
556
memerr:
 
557
    err = gcry_error(GPG_ERR_ENOMEM);
 
558
err:
 
559
    free(buf);
 
560
    gcry_sexp_release(pubs);
 
561
    return err;
 
562
}
 
563
 
 
564
/*
 
565
 * Create a Reveal Signature Message using the values in the given auth,
 
566
 * and store it in auth->lastauthmsg.  Use the given privkey to sign the
 
567
 * message.
 
568
 */
 
569
static gcry_error_t create_revealsig_message(OtrlAuthInfo *auth,
 
570
        OtrlPrivKey *privkey)
 
571
{
 
572
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
573
    unsigned char *buf = NULL, *bufp, *startmac;
 
574
    size_t buflen, lenp;
 
575
 
 
576
    unsigned char *authbuf = NULL;
 
577
    size_t authlen;
 
578
 
 
579
    /* Get the encrypted authenticator */
 
580
    err = calculate_pubkey_auth(&authbuf, &authlen, auth->mac_m1, auth->enc_c,
 
581
            auth->our_dh.pub, auth->their_pub, privkey, auth->our_keyid);
 
582
    if (err) goto err;
 
583
 
 
584
    buflen = 3 + 4 + 16 + 4 + authlen + 20;
 
585
    buf = malloc(buflen);
 
586
    if (buf == NULL) goto memerr;
 
587
 
 
588
    bufp = buf;
 
589
    lenp = buflen;
 
590
 
 
591
    memmove(bufp, "\x00\x02\x11", 3); /* header */
 
592
    debug_data("Header", bufp, 3);
 
593
    bufp += 3; lenp -= 3;
 
594
 
 
595
    /* r */
 
596
    write_int(16);
 
597
    memmove(bufp, auth->r, 16);
 
598
    debug_data("r", bufp, 16);
 
599
    bufp += 16; lenp -= 16;
 
600
 
 
601
    /* Encrypted authenticator */
 
602
    startmac = bufp;
 
603
    write_int(authlen);
 
604
    memmove(bufp, authbuf, authlen);
 
605
    debug_data("auth", bufp, authlen);
 
606
    bufp += authlen; lenp -= authlen;
 
607
    free(authbuf);
 
608
    authbuf = NULL;
 
609
 
 
610
    /* MAC it, but only take the first 20 bytes */
 
611
    gcry_md_reset(auth->mac_m2);
 
612
    gcry_md_write(auth->mac_m2, startmac, bufp - startmac);
 
613
    memmove(bufp, gcry_md_read(auth->mac_m2, GCRY_MD_SHA256), 20);
 
614
    debug_data("MAC", bufp, 20);
 
615
    bufp += 20; lenp -= 20;
 
616
 
 
617
    assert(lenp == 0);
 
618
 
 
619
    free(auth->lastauthmsg);
 
620
    auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
 
621
    if (auth->lastauthmsg == NULL) goto memerr;
 
622
    free(buf);
 
623
    buf = NULL;
 
624
 
 
625
    return err;
 
626
 
 
627
memerr:
 
628
    err = gcry_error(GPG_ERR_ENOMEM);
 
629
err:
 
630
    free(buf);
 
631
    free(authbuf);
 
632
    return err;
 
633
}
 
634
 
 
635
/*
 
636
 * Create a Signature Message using the values in the given auth, and
 
637
 * store it in auth->lastauthmsg.  Use the given privkey to sign the
 
638
 * message.
 
639
 */
 
640
static gcry_error_t create_signature_message(OtrlAuthInfo *auth,
 
641
        OtrlPrivKey *privkey)
 
642
{
 
643
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
644
    unsigned char *buf = NULL, *bufp, *startmac;
 
645
    size_t buflen, lenp;
 
646
 
 
647
    unsigned char *authbuf = NULL;
 
648
    size_t authlen;
 
649
 
 
650
    /* Get the encrypted authenticator */
 
651
    err = calculate_pubkey_auth(&authbuf, &authlen, auth->mac_m1p,
 
652
            auth->enc_cp, auth->our_dh.pub, auth->their_pub, privkey,
 
653
            auth->our_keyid);
 
654
    if (err) goto err;
 
655
 
 
656
    buflen = 3 + 4 + authlen + 20;
 
657
    buf = malloc(buflen);
 
658
    if (buf == NULL) goto memerr;
 
659
 
 
660
    bufp = buf;
 
661
    lenp = buflen;
 
662
 
 
663
    memmove(bufp, "\x00\x02\x12", 3); /* header */
 
664
    debug_data("Header", bufp, 3);
 
665
    bufp += 3; lenp -= 3;
 
666
 
 
667
    /* Encrypted authenticator */
 
668
    startmac = bufp;
 
669
    write_int(authlen);
 
670
    memmove(bufp, authbuf, authlen);
 
671
    debug_data("auth", bufp, authlen);
 
672
    bufp += authlen; lenp -= authlen;
 
673
    free(authbuf);
 
674
    authbuf = NULL;
 
675
 
 
676
    /* MAC it, but only take the first 20 bytes */
 
677
    gcry_md_reset(auth->mac_m2p);
 
678
    gcry_md_write(auth->mac_m2p, startmac, bufp - startmac);
 
679
    memmove(bufp, gcry_md_read(auth->mac_m2p, GCRY_MD_SHA256), 20);
 
680
    debug_data("MAC", bufp, 20);
 
681
    bufp += 20; lenp -= 20;
 
682
 
 
683
    assert(lenp == 0);
 
684
 
 
685
    free(auth->lastauthmsg);
 
686
    auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
 
687
    if (auth->lastauthmsg == NULL) goto memerr;
 
688
    free(buf);
 
689
    buf = NULL;
 
690
 
 
691
    return err;
 
692
 
 
693
memerr:
 
694
    err = gcry_error(GPG_ERR_ENOMEM);
 
695
err:
 
696
    free(buf);
 
697
    free(authbuf);
 
698
    return err;
 
699
}
 
700
 
 
701
/*
 
702
 * Handle an incoming D-H Key Message.  If no error is returned, and
 
703
 * *havemsgp is 1, the message to sent will be left in auth->lastauthmsg.
 
704
 * Use the given private authentication key to sign messages.
 
705
 */
 
706
gcry_error_t otrl_auth_handle_key(OtrlAuthInfo *auth, const char *keymsg,
 
707
        int *havemsgp, OtrlPrivKey *privkey)
 
708
{
 
709
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
710
    unsigned char *buf = NULL, *bufp = NULL;
 
711
    size_t buflen, lenp;
 
712
    gcry_mpi_t incoming_pub = NULL;
 
713
    int res;
 
714
 
 
715
    *havemsgp = 0;
 
716
 
 
717
    res = otrl_base64_otr_decode(keymsg, &buf, &buflen);
 
718
    if (res == -1) goto memerr;
 
719
    if (res == -2) goto invval;
 
720
 
 
721
    bufp = buf;
 
722
    lenp = buflen;
 
723
 
 
724
    /* Header */
 
725
    if (memcmp(bufp, "\x00\x02\x0a", 3)) goto invval;
 
726
    bufp += 3; lenp -= 3;
 
727
 
 
728
    /* g^y */
 
729
    read_mpi(incoming_pub);
 
730
 
 
731
    if (lenp != 0) goto invval;
 
732
    free(buf);
 
733
    buf = NULL;
 
734
 
 
735
    switch(auth->authstate) {
 
736
        case OTRL_AUTHSTATE_AWAITING_DHKEY:
 
737
            /* Store the incoming public key */
 
738
            gcry_mpi_release(auth->their_pub);
 
739
            auth->their_pub = incoming_pub;
 
740
            incoming_pub = NULL;
 
741
 
 
742
            /* Compute the encryption and MAC keys */
 
743
            err = otrl_dh_compute_v2_auth_keys(&(auth->our_dh),
 
744
                    auth->their_pub, auth->secure_session_id,
 
745
                    &(auth->secure_session_id_len),
 
746
                    &(auth->enc_c), &(auth->enc_cp),
 
747
                    &(auth->mac_m1), &(auth->mac_m1p),
 
748
                    &(auth->mac_m2), &(auth->mac_m2p));
 
749
            if (err) goto err;
 
750
 
 
751
            /* Create the Reveal Signature Message */
 
752
            err = create_revealsig_message(auth, privkey);
 
753
            if (err) goto err;
 
754
            *havemsgp = 1;
 
755
            auth->authstate = OTRL_AUTHSTATE_AWAITING_SIG;
 
756
 
 
757
            break;
 
758
 
 
759
        case OTRL_AUTHSTATE_AWAITING_SIG:
 
760
            if (gcry_mpi_cmp(incoming_pub, auth->their_pub) == 0) {
 
761
                /* Retransmit the Reveal Signature Message */
 
762
                *havemsgp = 1;
 
763
            } else {
 
764
                /* Ignore this message */
 
765
                *havemsgp = 0;
 
766
            }
 
767
            break;
 
768
        case OTRL_AUTHSTATE_NONE:
 
769
        case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
 
770
        case OTRL_AUTHSTATE_V1_SETUP:
 
771
            /* Ignore this message */
 
772
            *havemsgp = 0;
 
773
            break;
 
774
    }
 
775
 
 
776
    gcry_mpi_release(incoming_pub);
 
777
    return err;
 
778
 
 
779
invval:
 
780
    err = gcry_error(GPG_ERR_INV_VALUE);
 
781
    goto err;
 
782
memerr:
 
783
    err = gcry_error(GPG_ERR_ENOMEM);
 
784
err:
 
785
    free(buf);
 
786
    gcry_mpi_release(incoming_pub);
 
787
    return err;
 
788
}
 
789
 
 
790
/*
 
791
 * Handle an incoming Reveal Signature Message.  If no error is
 
792
 * returned, and *havemsgp is 1, the message to be sent will be left in
 
793
 * auth->lastauthmsg.  Use the given private authentication key to sign
 
794
 * messages.  Call the auth_succeeded callback if authentication is
 
795
 * successful.
 
796
 */
 
797
gcry_error_t otrl_auth_handle_revealsig(OtrlAuthInfo *auth,
 
798
        const char *revealmsg, int *havemsgp, OtrlPrivKey *privkey,
 
799
        gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata),
 
800
        void *asdata)
 
801
{
 
802
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
803
    unsigned char *buf = NULL, *bufp = NULL, *gxbuf = NULL;
 
804
    unsigned char *authstart, *authend, *macstart;
 
805
    size_t buflen, lenp, rlen, authlen;
 
806
    gcry_cipher_hd_t enc = NULL;
 
807
    gcry_mpi_t incoming_pub = NULL;
 
808
    unsigned char ctr[16], hashbuf[32];
 
809
    int res;
 
810
 
 
811
    *havemsgp = 0;
 
812
 
 
813
    res = otrl_base64_otr_decode(revealmsg, &buf, &buflen);
 
814
    if (res == -1) goto memerr;
 
815
    if (res == -2) goto invval;
 
816
 
 
817
    bufp = buf;
 
818
    lenp = buflen;
 
819
 
 
820
    /* Header */
 
821
    if (memcmp(bufp, "\x00\x02\x11", 3)) goto invval;
 
822
    bufp += 3; lenp -= 3;
 
823
 
 
824
    /* r */
 
825
    read_int(rlen);
 
826
    if (rlen != 16) goto invval;
 
827
    require_len(rlen);
 
828
    memmove(auth->r, bufp, rlen);
 
829
    bufp += rlen; lenp -= rlen;
 
830
 
 
831
    /* auth */
 
832
    authstart = bufp;
 
833
    read_int(authlen);
 
834
    require_len(authlen);
 
835
    bufp += authlen; lenp -= authlen;
 
836
    authend = bufp;
 
837
 
 
838
    /* MAC */
 
839
    require_len(20);
 
840
    macstart = bufp;
 
841
    bufp += 20; lenp -= 20;
 
842
 
 
843
    if (lenp != 0) goto invval;
 
844
 
 
845
    switch(auth->authstate) {
 
846
        case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
 
847
            gxbuf = malloc(auth->encgx_len);
 
848
            if (auth->encgx_len && gxbuf == NULL) goto memerr;
 
849
 
 
850
            /* Use r to decrypt the value of g^x we received earlier */
 
851
            err = gcry_cipher_open(&enc, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR,
 
852
                    GCRY_CIPHER_SECURE);
 
853
            if (err) goto err;
 
854
 
 
855
            err = gcry_cipher_setkey(enc, auth->r, 16);
 
856
            if (err) goto err;
 
857
 
 
858
            memset(ctr, 0, 16);
 
859
            err = gcry_cipher_setctr(enc, ctr, 16);
 
860
            if (err) goto err;
 
861
 
 
862
            err = gcry_cipher_decrypt(enc, gxbuf, auth->encgx_len,
 
863
                    auth->encgx, auth->encgx_len);
 
864
            if (err) goto err;
 
865
 
 
866
            gcry_cipher_close(enc);
 
867
            enc = NULL;
 
868
 
 
869
            /* Check the hash */
 
870
            gcry_md_hash_buffer(GCRY_MD_SHA256, hashbuf, gxbuf,
 
871
                    auth->encgx_len);
 
872
            if (memcmp(hashbuf, auth->hashgx, 32)) goto decfail;
 
873
 
 
874
            /* Extract g^x */
 
875
            bufp = gxbuf;
 
876
            lenp = auth->encgx_len;
 
877
 
 
878
            read_mpi(incoming_pub);
 
879
            free(gxbuf);
 
880
            gxbuf = NULL;
 
881
 
 
882
            if (lenp != 0) goto invval;
 
883
 
 
884
            gcry_mpi_release(auth->their_pub);
 
885
            auth->their_pub = incoming_pub;
 
886
            incoming_pub = NULL;
 
887
 
 
888
            /* Compute the encryption and MAC keys */
 
889
            err = otrl_dh_compute_v2_auth_keys(&(auth->our_dh),
 
890
                    auth->their_pub, auth->secure_session_id,
 
891
                    &(auth->secure_session_id_len),
 
892
                    &(auth->enc_c), &(auth->enc_cp),
 
893
                    &(auth->mac_m1), &(auth->mac_m1p),
 
894
                    &(auth->mac_m2), &(auth->mac_m2p));
 
895
            if (err) goto err;
 
896
 
 
897
            /* Check the MAC */
 
898
            gcry_md_reset(auth->mac_m2);
 
899
            gcry_md_write(auth->mac_m2, authstart, authend - authstart);
 
900
            if (memcmp(macstart,
 
901
                        gcry_md_read(auth->mac_m2, GCRY_MD_SHA256),
 
902
                        20)) goto invval;
 
903
 
 
904
            /* Check the auth */
 
905
            err = check_pubkey_auth(auth->their_fingerprint,
 
906
                    &(auth->their_keyid), authstart + 4,
 
907
                    authend - authstart - 4, auth->mac_m1, auth->enc_c,
 
908
                    auth->our_dh.pub, auth->their_pub);
 
909
            if (err) goto err;
 
910
 
 
911
            authstart = NULL;
 
912
            authend = NULL;
 
913
            macstart = NULL;
 
914
            free(buf);
 
915
            buf = NULL;
 
916
 
 
917
            /* Create the Signature Message */
 
918
            err = create_signature_message(auth, privkey);
 
919
            if (err) goto err;
 
920
 
 
921
            /* No error?  Then we've completed our end of the
 
922
             * authentication. */
 
923
            auth->protocol_version = 2;
 
924
            auth->session_id_half = OTRL_SESSIONID_SECOND_HALF_BOLD;
 
925
            if (auth_succeeded) err = auth_succeeded(auth, asdata);
 
926
            *havemsgp = 1;
 
927
            auth->our_keyid = 0;
 
928
            auth->authstate = OTRL_AUTHSTATE_NONE;
 
929
 
 
930
            break;
 
931
        case OTRL_AUTHSTATE_NONE:
 
932
        case OTRL_AUTHSTATE_AWAITING_DHKEY:
 
933
        case OTRL_AUTHSTATE_AWAITING_SIG:
 
934
        case OTRL_AUTHSTATE_V1_SETUP:
 
935
            /* Ignore this message */
 
936
            *havemsgp = 0;
 
937
            free(buf);
 
938
            buf = NULL;
 
939
            break;
 
940
    }
 
941
 
 
942
    return err;
 
943
 
 
944
decfail:
 
945
    err = gcry_error(GPG_ERR_NO_ERROR);
 
946
    goto err;
 
947
invval:
 
948
    err = gcry_error(GPG_ERR_INV_VALUE);
 
949
    goto err;
 
950
memerr:
 
951
    err = gcry_error(GPG_ERR_ENOMEM);
 
952
err:
 
953
    free(buf);
 
954
    free(gxbuf);
 
955
    gcry_cipher_close(enc);
 
956
    gcry_mpi_release(incoming_pub);
 
957
    return err;
 
958
}
 
959
 
 
960
/*
 
961
 * Handle an incoming Signature Message.  If no error is returned, and
 
962
 * *havemsgp is 1, the message to be sent will be left in
 
963
 * auth->lastauthmsg.  Call the auth_succeeded callback if
 
964
 * authentication is successful.
 
965
 */
 
966
gcry_error_t otrl_auth_handle_signature(OtrlAuthInfo *auth,
 
967
        const char *sigmsg, int *havemsgp,
 
968
        gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata),
 
969
        void *asdata)
 
970
{
 
971
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
972
    unsigned char *buf = NULL, *bufp = NULL;
 
973
    unsigned char *authstart, *authend, *macstart;
 
974
    size_t buflen, lenp, authlen;
 
975
    int res;
 
976
 
 
977
    *havemsgp = 0;
 
978
 
 
979
    res = otrl_base64_otr_decode(sigmsg, &buf, &buflen);
 
980
    if (res == -1) goto memerr;
 
981
    if (res == -2) goto invval;
 
982
 
 
983
    bufp = buf;
 
984
    lenp = buflen;
 
985
 
 
986
    /* Header */
 
987
    if (memcmp(bufp, "\x00\x02\x12", 3)) goto invval;
 
988
    bufp += 3; lenp -= 3;
 
989
 
 
990
    /* auth */
 
991
    authstart = bufp;
 
992
    read_int(authlen);
 
993
    require_len(authlen);
 
994
    bufp += authlen; lenp -= authlen;
 
995
    authend = bufp;
 
996
 
 
997
    /* MAC */
 
998
    require_len(20);
 
999
    macstart = bufp;
 
1000
    bufp += 20; lenp -= 20;
 
1001
 
 
1002
    if (lenp != 0) goto invval;
 
1003
 
 
1004
    switch(auth->authstate) {
 
1005
        case OTRL_AUTHSTATE_AWAITING_SIG:
 
1006
            /* Check the MAC */
 
1007
            gcry_md_reset(auth->mac_m2p);
 
1008
            gcry_md_write(auth->mac_m2p, authstart, authend - authstart);
 
1009
            if (memcmp(macstart,
 
1010
                        gcry_md_read(auth->mac_m2p, GCRY_MD_SHA256),
 
1011
                        20)) goto invval;
 
1012
 
 
1013
            /* Check the auth */
 
1014
            err = check_pubkey_auth(auth->their_fingerprint,
 
1015
                    &(auth->their_keyid), authstart + 4,
 
1016
                    authend - authstart - 4, auth->mac_m1p, auth->enc_cp,
 
1017
                    auth->our_dh.pub, auth->their_pub);
 
1018
            if (err) goto err;
 
1019
 
 
1020
            authstart = NULL;
 
1021
            authend = NULL;
 
1022
            macstart = NULL;
 
1023
            free(buf);
 
1024
            buf = NULL;
 
1025
 
 
1026
            /* No error?  Then we've completed our end of the
 
1027
             * authentication. */
 
1028
            auth->protocol_version = 2;
 
1029
            auth->session_id_half = OTRL_SESSIONID_FIRST_HALF_BOLD;
 
1030
            if (auth_succeeded) err = auth_succeeded(auth, asdata);
 
1031
            free(auth->lastauthmsg);
 
1032
            auth->lastauthmsg = NULL;
 
1033
            *havemsgp = 1;
 
1034
            auth->our_keyid = 0;
 
1035
            auth->authstate = OTRL_AUTHSTATE_NONE;
 
1036
 
 
1037
            break;
 
1038
        case OTRL_AUTHSTATE_NONE:
 
1039
        case OTRL_AUTHSTATE_AWAITING_DHKEY:
 
1040
        case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
 
1041
        case OTRL_AUTHSTATE_V1_SETUP:
 
1042
            /* Ignore this message */
 
1043
            *havemsgp = 0;
 
1044
            break;
 
1045
    }
 
1046
 
 
1047
    return err;
 
1048
 
 
1049
invval:
 
1050
    err = gcry_error(GPG_ERR_INV_VALUE);
 
1051
    goto err;
 
1052
memerr:
 
1053
    err = gcry_error(GPG_ERR_ENOMEM);
 
1054
err:
 
1055
    free(buf);
 
1056
    return err;
 
1057
}
 
1058
 
 
1059
/* Version 1 routines, for compatibility */
 
1060
 
 
1061
/*
 
1062
 * Create a verion 1 Key Exchange Message using the values in the given
 
1063
 * auth, and store it in auth->lastauthmsg.  Set the Reply field to the
 
1064
 * given value, and use the given privkey to sign the message.
 
1065
 */
 
1066
static gcry_error_t create_v1_key_exchange_message(OtrlAuthInfo *auth,
 
1067
        unsigned char reply, OtrlPrivKey *privkey)
 
1068
{
 
1069
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
1070
    const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
 
1071
    unsigned char *buf = NULL, *bufp = NULL, *sigbuf = NULL;
 
1072
    size_t lenp, ourpublen, totallen, siglen;
 
1073
    unsigned char hashbuf[20];
 
1074
 
 
1075
    if (privkey->pubkey_type != OTRL_PUBKEY_TYPE_DSA) {
 
1076
        return gpg_error(GPG_ERR_INV_VALUE);
 
1077
    }
 
1078
 
 
1079
    /* How big is the DH public key? */
 
1080
    gcry_mpi_print(format, NULL, 0, &ourpublen, auth->our_dh.pub);
 
1081
 
 
1082
    totallen = 3 + 1 + privkey->pubkey_datalen + 4 + 4 + ourpublen + 40;
 
1083
    buf = malloc(totallen);
 
1084
    if (buf == NULL) goto memerr;
 
1085
 
 
1086
    bufp = buf;
 
1087
    lenp = totallen;
 
1088
 
 
1089
    memmove(bufp, "\x00\x01\x0a", 3); /* header */
 
1090
    debug_data("Header", bufp, 3);
 
1091
    bufp += 3; lenp -= 3;
 
1092
 
 
1093
    bufp[0] = reply;
 
1094
    debug_data("Reply", bufp, 1);
 
1095
    bufp += 1; lenp -= 1;
 
1096
 
 
1097
    memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen);
 
1098
    debug_data("Pubkey", bufp, privkey->pubkey_datalen);
 
1099
    bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen;
 
1100
 
 
1101
    write_int(auth->our_keyid);
 
1102
    debug_int("Keyid", bufp-4);
 
1103
 
 
1104
    write_mpi(auth->our_dh.pub, ourpublen, "D-H y");
 
1105
 
 
1106
    /* Hash all the data written so far, and sign the hash */
 
1107
    gcry_md_hash_buffer(GCRY_MD_SHA1, hashbuf, buf, bufp - buf);
 
1108
 
 
1109
    err = otrl_privkey_sign(&sigbuf, &siglen, privkey, hashbuf, 20);
 
1110
    if (err) goto err;
 
1111
 
 
1112
    if (siglen != 40) goto invval;
 
1113
    memmove(bufp, sigbuf, 40);
 
1114
    debug_data("Signature", bufp, 40);
 
1115
    bufp += 40; lenp -= 40;
 
1116
    free(sigbuf);
 
1117
    sigbuf = NULL;
 
1118
 
 
1119
    assert(lenp == 0);
 
1120
 
 
1121
    free(auth->lastauthmsg);
 
1122
    auth->lastauthmsg = otrl_base64_otr_encode(buf, totallen);
 
1123
    if (auth->lastauthmsg == NULL) goto memerr;
 
1124
    free(buf);
 
1125
    buf = NULL;
 
1126
 
 
1127
    return err;
 
1128
 
 
1129
invval:
 
1130
    err = gcry_error(GPG_ERR_INV_VALUE);
 
1131
    goto err;
 
1132
memerr:
 
1133
    err = gcry_error(GPG_ERR_ENOMEM);
 
1134
err:
 
1135
    free(buf);
 
1136
    free(sigbuf);
 
1137
    return err;
 
1138
}
 
1139
 
 
1140
/*
 
1141
 * Start a fresh AKE (version 1) using the given OtrlAuthInfo.  If
 
1142
 * our_dh is NULL, generate a fresh DH keypair to use.  Otherwise, use a
 
1143
 * copy of the one passed (with the given keyid).  Use the given private
 
1144
 * key to sign the message.  If no error is returned, the message to
 
1145
 * transmit will be contained in auth->lastauthmsg.
 
1146
 */
 
1147
gcry_error_t otrl_auth_start_v1(OtrlAuthInfo *auth, DH_keypair *our_dh,
 
1148
        unsigned int our_keyid, OtrlPrivKey *privkey)
 
1149
{
 
1150
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
1151
 
 
1152
    /* Clear out this OtrlAuthInfo and start over */
 
1153
    otrl_auth_clear(auth);
 
1154
    auth->initiated = 1;
 
1155
 
 
1156
    /* Import the given DH keypair, or else create a fresh one */
 
1157
    if (our_dh) {
 
1158
        otrl_dh_keypair_copy(&(auth->our_dh), our_dh);
 
1159
        auth->our_keyid = our_keyid;
 
1160
    } else {
 
1161
        otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
 
1162
        auth->our_keyid = 1;
 
1163
    }
 
1164
 
 
1165
    err = create_v1_key_exchange_message(auth, 0, privkey);
 
1166
    if (!err) {
 
1167
        auth->authstate = OTRL_AUTHSTATE_V1_SETUP;
 
1168
    }
 
1169
 
 
1170
    return err;
 
1171
}
 
1172
 
 
1173
/*
 
1174
 * Handle an incoming v1 Key Exchange Message.  If no error is returned,
 
1175
 * and *havemsgp is 1, the message to be sent will be left in
 
1176
 * auth->lastauthmsg.  Use the given private authentication key to sign
 
1177
 * messages.  Call the auth_secceeded callback if authentication is
 
1178
 * successful.  If non-NULL, use a copy of the given D-H keypair, with
 
1179
 * the given keyid.
 
1180
 */
 
1181
gcry_error_t otrl_auth_handle_v1_key_exchange(OtrlAuthInfo *auth,
 
1182
        const char *keyexchmsg, int *havemsgp, OtrlPrivKey *privkey,
 
1183
        DH_keypair *our_dh, unsigned int our_keyid,
 
1184
        gcry_error_t (*auth_succeeded)(const OtrlAuthInfo *auth, void *asdata),
 
1185
        void *asdata)
 
1186
{
 
1187
    gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
 
1188
    unsigned char *buf = NULL, *bufp = NULL;
 
1189
    unsigned char *fingerprintstart, *fingerprintend;
 
1190
    unsigned char fingerprintbuf[20], hashbuf[20];
 
1191
    gcry_mpi_t p, q, g, y, received_pub = NULL;
 
1192
    gcry_sexp_t pubs = NULL;
 
1193
    size_t buflen, lenp;
 
1194
    unsigned char received_reply;
 
1195
    unsigned int received_keyid;
 
1196
    int res;
 
1197
 
 
1198
    *havemsgp = 0;
 
1199
 
 
1200
    res = otrl_base64_otr_decode(keyexchmsg, &buf, &buflen);
 
1201
    if (res == -1) goto memerr;
 
1202
    if (res == -2) goto invval;
 
1203
 
 
1204
    bufp = buf;
 
1205
    lenp = buflen;
 
1206
 
 
1207
    /* Header */
 
1208
    require_len(3);
 
1209
    if (memcmp(bufp, "\x00\x01\x0a", 3)) goto invval;
 
1210
    bufp += 3; lenp -= 3;
 
1211
 
 
1212
    /* Reply */
 
1213
    require_len(1);
 
1214
    received_reply = bufp[0];
 
1215
    bufp += 1; lenp -= 1;
 
1216
 
 
1217
    /* Public Key */
 
1218
    fingerprintstart = bufp;
 
1219
    read_mpi(p);
 
1220
    read_mpi(q);
 
1221
    read_mpi(g);
 
1222
    read_mpi(y);
 
1223
    fingerprintend = bufp;
 
1224
    gcry_md_hash_buffer(GCRY_MD_SHA1, fingerprintbuf,
 
1225
            fingerprintstart, fingerprintend-fingerprintstart);
 
1226
    gcry_sexp_build(&pubs, NULL,
 
1227
        "(public-key (dsa (p %m)(q %m)(g %m)(y %m)))", p, q, g, y);
 
1228
    gcry_mpi_release(p);
 
1229
    gcry_mpi_release(q);
 
1230
    gcry_mpi_release(g);
 
1231
    gcry_mpi_release(y);
 
1232
 
 
1233
    /* keyid */
 
1234
    read_int(received_keyid);
 
1235
    if (received_keyid == 0) goto invval;
 
1236
 
 
1237
    /* D-H pubkey */
 
1238
    read_mpi(received_pub);
 
1239
 
 
1240
    /* Verify the signature */
 
1241
    if (lenp != 40) goto invval;
 
1242
    gcry_md_hash_buffer(GCRY_MD_SHA1, hashbuf, buf, bufp - buf);
 
1243
    err = otrl_privkey_verify(bufp, lenp, OTRL_PUBKEY_TYPE_DSA,
 
1244
            pubs, hashbuf, 20);
 
1245
    if (err) goto err;
 
1246
    gcry_sexp_release(pubs);
 
1247
    pubs = NULL;
 
1248
    free(buf);
 
1249
    buf = NULL;
 
1250
    
 
1251
    if (auth->authstate != OTRL_AUTHSTATE_V1_SETUP && received_reply == 0x01) {
 
1252
        /* They're replying to something we never sent.  We must be
 
1253
         * logged in more than once; ignore the message. */
 
1254
        err = gpg_error(GPG_ERR_NO_ERROR);
 
1255
        goto err;
 
1256
    }
 
1257
 
 
1258
    if (auth->authstate != OTRL_AUTHSTATE_V1_SETUP) {
 
1259
        /* Clear the auth and start over */
 
1260
        otrl_auth_clear(auth);
 
1261
    }
 
1262
 
 
1263
    /* Everything checked out */
 
1264
    auth->their_keyid = received_keyid;
 
1265
    gcry_mpi_release(auth->their_pub);
 
1266
    auth->their_pub = received_pub;
 
1267
    received_pub = NULL;
 
1268
    memmove(auth->their_fingerprint, fingerprintbuf, 20);
 
1269
 
 
1270
    if (received_reply == 0x01) {
 
1271
        /* Don't send a reply to this. */
 
1272
        *havemsgp = 0;
 
1273
    } else {
 
1274
        /* Import the given DH keypair, or else create a fresh one */
 
1275
        if (our_dh) {
 
1276
            otrl_dh_keypair_copy(&(auth->our_dh), our_dh);
 
1277
            auth->our_keyid = our_keyid;
 
1278
        } else if (auth->our_keyid == 0) {
 
1279
            otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
 
1280
            auth->our_keyid = 1;
 
1281
        }
 
1282
 
 
1283
        /* Reply with our own Key Exchange Message */
 
1284
        err = create_v1_key_exchange_message(auth, 1, privkey);
 
1285
        if (err) goto err;
 
1286
        *havemsgp = 1;
 
1287
    }
 
1288
 
 
1289
    /* Compute the session id */
 
1290
    err = otrl_dh_compute_v1_session_id(&(auth->our_dh),
 
1291
            auth->their_pub, auth->secure_session_id,
 
1292
            &(auth->secure_session_id_len),
 
1293
            &(auth->session_id_half));
 
1294
    if (err) goto err;
 
1295
 
 
1296
    /* We've completed our end of the authentication */
 
1297
    auth->protocol_version = 1;
 
1298
    if (auth_succeeded) err = auth_succeeded(auth, asdata);
 
1299
    auth->our_keyid = 0;
 
1300
    auth->authstate = OTRL_AUTHSTATE_NONE;
 
1301
 
 
1302
    return err;
 
1303
 
 
1304
invval:
 
1305
    err = gcry_error(GPG_ERR_INV_VALUE);
 
1306
    goto err;
 
1307
memerr:
 
1308
    err = gcry_error(GPG_ERR_ENOMEM);
 
1309
err:
 
1310
    free(buf);
 
1311
    gcry_sexp_release(pubs);
 
1312
    gcry_mpi_release(received_pub);
 
1313
    return err;
 
1314
}
 
1315
 
 
1316
#ifdef OTRL_TESTING_AUTH
 
1317
#include "mem.h"
 
1318
#include "privkey.h"
 
1319
 
 
1320
#define CHECK_ERR if (err) { printf("Error: %s\n", gcry_strerror(err)); return 1; }
 
1321
 
 
1322
static gcry_error_t starting(const OtrlAuthInfo *auth, void *asdata)
 
1323
{
 
1324
    char *name = asdata;
 
1325
 
 
1326
    fprintf(stderr, "\nStarting ENCRYPTED mode for %s (v%d).\n", name, auth->protocol_version);
 
1327
 
 
1328
    fprintf(stderr, "\nour_dh (%d):", auth->our_keyid);
 
1329
    gcry_mpi_dump(auth->our_dh.pub);
 
1330
    fprintf(stderr, "\ntheir_pub (%d):", auth->their_keyid);
 
1331
    gcry_mpi_dump(auth->their_pub);
 
1332
 
 
1333
    debug_data("\nTheir fingerprint", auth->their_fingerprint, 20);
 
1334
    debug_data("\nSecure session id", auth->secure_session_id,
 
1335
            auth->secure_session_id_len);
 
1336
    fprintf(stderr, "Sessionid half: %d\n\n", auth->session_id_half);
 
1337
 
 
1338
    return gpg_error(GPG_ERR_NO_ERROR);
 
1339
}
 
1340
 
 
1341
int main(int argc, char **argv)
 
1342
{
 
1343
    OtrlAuthInfo alice, bob;
 
1344
    gcry_error_t err;
 
1345
    int havemsg;
 
1346
    OtrlUserState us;
 
1347
    OtrlPrivKey *alicepriv, *bobpriv;
 
1348
 
 
1349
    otrl_mem_init();
 
1350
    otrl_dh_init();
 
1351
    otrl_auth_new(&alice);
 
1352
    otrl_auth_new(&bob);
 
1353
 
 
1354
    us = otrl_userstate_create();
 
1355
    otrl_privkey_read(us, "/home/iang/.gaim/otr.private_key");
 
1356
    alicepriv = otrl_privkey_find(us, "oneeyedian", "prpl-oscar");
 
1357
    bobpriv = otrl_privkey_find(us, "otr4ian", "prpl-oscar");
 
1358
 
 
1359
    printf("\n\n  ***** V2 *****\n\n");
 
1360
 
 
1361
    err = otrl_auth_start_v2(&bob, NULL, 0);
 
1362
    CHECK_ERR
 
1363
    printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
 
1364
    err = otrl_auth_handle_commit(&alice, bob.lastauthmsg, NULL, 0);
 
1365
    CHECK_ERR
 
1366
    printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg);
 
1367
    err = otrl_auth_handle_key(&bob, alice.lastauthmsg, &havemsg, bobpriv);
 
1368
    CHECK_ERR
 
1369
    if (havemsg) {
 
1370
        printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
 
1371
    } else {
 
1372
        printf("\nIGNORE\n\n");
 
1373
    }
 
1374
    err = otrl_auth_handle_revealsig(&alice, bob.lastauthmsg, &havemsg,
 
1375
            alicepriv, starting, "Alice");
 
1376
    CHECK_ERR
 
1377
    if (havemsg) {
 
1378
        printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg);
 
1379
    } else {
 
1380
        printf("\nIGNORE\n\n");
 
1381
    }
 
1382
    err = otrl_auth_handle_signature(&bob, alice.lastauthmsg, &havemsg,
 
1383
            starting, "Bob");
 
1384
    CHECK_ERR
 
1385
 
 
1386
    printf("\n\n  ***** V1 *****\n\n");
 
1387
 
 
1388
    err = otrl_auth_start_v1(&bob, NULL, 0, bobpriv);
 
1389
    CHECK_ERR
 
1390
    printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
 
1391
    err = otrl_auth_handle_v1_key_exchange(&alice, bob.lastauthmsg,
 
1392
            &havemsg, alicepriv, NULL, 0, starting, "Alice");
 
1393
    CHECK_ERR
 
1394
    if (havemsg) {
 
1395
        printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg);
 
1396
    } else {
 
1397
        printf("\nIGNORE\n\n");
 
1398
    }
 
1399
    err = otrl_auth_handle_v1_key_exchange(&bob, alice.lastauthmsg,
 
1400
            &havemsg, bobpriv, NULL, 0, starting, "Bob");
 
1401
    CHECK_ERR
 
1402
    if (havemsg) {
 
1403
        printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
 
1404
    } else {
 
1405
        printf("\nIGNORE\n\n");
 
1406
    }
 
1407
 
 
1408
    otrl_userstate_free(us);
 
1409
    otrl_auth_clear(&alice);
 
1410
    otrl_auth_clear(&bob);
 
1411
    return 0;
 
1412
}
 
1413
#endif