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
32
* Initialize the fields of an OtrlAuthInfo (already allocated).
34
void otrl_auth_new(OtrlAuthInfo *auth)
36
auth->authstate = OTRL_AUTHSTATE_NONE;
37
otrl_dh_keypair_init(&(auth->our_dh));
41
memset(auth->r, 0, 16);
42
memset(auth->hashgx, 0, 32);
43
auth->their_pub = NULL;
44
auth->their_keyid = 0;
51
memset(auth->their_fingerprint, 0, 20);
53
auth->protocol_version = 0;
54
memset(auth->secure_session_id, 0, 20);
55
auth->secure_session_id_len = 0;
56
auth->lastauthmsg = NULL;
60
* Clear the fields of an OtrlAuthInfo (but leave it allocated).
62
void otrl_auth_clear(OtrlAuthInfo *auth)
64
auth->authstate = OTRL_AUTHSTATE_NONE;
65
otrl_dh_keypair_free(&(auth->our_dh));
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);
87
memset(auth->their_fingerprint, 0, 20);
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;
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.
101
gcry_error_t otrl_auth_start_v2(OtrlAuthInfo *auth)
103
gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
104
const enum gcry_mpi_format format = GCRYMPI_FMT_USG;
106
gcry_cipher_hd_t enc = NULL;
107
unsigned char ctr[16];
108
unsigned char *buf, *bufp;
111
/* Clear out this OtrlAuthInfo and start over */
112
otrl_auth_clear(auth);
115
otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
118
/* Pick an encryption key */
119
gcry_randomize(auth->r, 16, GCRY_STRONG_RANDOM);
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;
127
lenp = auth->encgx_len;
128
write_mpi(auth->our_dh.pub, npub, "g^x");
132
gcry_md_hash_buffer(GCRY_MD_SHA256, auth->hashgx, auth->encgx,
135
/* Encrypt g^x using the key r */
136
err = gcry_cipher_open(&enc, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR,
140
err = gcry_cipher_setkey(enc, auth->r, 16);
144
err = gcry_cipher_setctr(enc, ctr, 16);
147
err = gcry_cipher_encrypt(enc, auth->encgx, auth->encgx_len, NULL, 0);
150
gcry_cipher_close(enc);
153
/* Now serialize the message */
154
lenp = 3 + 4 + auth->encgx_len + 4 + 32;
156
if (bufp == NULL) goto memerr;
160
memmove(bufp, "\x00\x02\x02", 3); /* header */
161
debug_data("Header", bufp, 3);
162
bufp += 3; lenp -= 3;
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;
173
debug_int("hashgx len", bufp-4);
174
memmove(bufp, auth->hashgx, 32);
175
debug_data("hashgx", bufp, 32);
176
bufp += 32; lenp -= 32;
180
auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
182
if (auth->lastauthmsg == NULL) goto memerr;
183
auth->authstate = OTRL_AUTHSTATE_AWAITING_DHKEY;
188
err = gcry_error(GPG_ERR_ENOMEM);
190
otrl_auth_clear(auth);
191
gcry_cipher_close(enc);
196
* Create a D-H Key Message using the our_dh value in the given auth,
197
* and store it in auth->lastauthmsg.
199
static gcry_error_t create_key_message(OtrlAuthInfo *auth)
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;
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;
214
memmove(bufp, "\x00\x02\x0a", 3); /* header */
215
debug_data("Header", bufp, 3);
216
bufp += 3; lenp -= 3;
219
write_mpi(auth->our_dh.pub, npub, "g^y");
223
free(auth->lastauthmsg);
224
auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
226
if (auth->lastauthmsg == NULL) goto memerr;
231
err = gcry_error(GPG_ERR_ENOMEM);
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
240
gcry_error_t otrl_auth_handle_commit(OtrlAuthInfo *auth,
241
const char *commitmsg)
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;
249
res = otrl_base64_otr_decode(commitmsg, &buf, &buflen);
250
if (res == -1) goto memerr;
251
if (res == -2) goto invval;
258
if (memcmp(bufp, "\x00\x02\x02", 3)) goto invval;
259
bufp += 3; lenp -= 3;
264
encbuf = malloc(enclen);
265
if (encbuf == NULL && enclen > 0) goto memerr;
266
memmove(encbuf, bufp, enclen);
267
bufp += enclen; lenp -= enclen;
271
if (hashlen != 32) goto invval;
273
memmove(hashbuf, bufp, 32);
274
bufp += 32; lenp -= 32;
276
if (lenp != 0) goto invval;
280
switch(auth->authstate) {
281
case OTRL_AUTHSTATE_NONE:
282
case OTRL_AUTHSTATE_AWAITING_SIG:
283
case OTRL_AUTHSTATE_V1_SETUP:
285
/* Store the incoming information */
286
otrl_auth_clear(auth);
287
otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
289
auth->encgx = encbuf;
291
auth->encgx_len = enclen;
292
memmove(auth->hashgx, hashbuf, 32);
294
/* Create a D-H Key Message */
295
err = create_key_message(auth);
297
auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG;
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. */
310
/* Ours loses. Use the incoming parameters instead. */
311
otrl_auth_clear(auth);
312
otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
314
auth->encgx = encbuf;
316
auth->encgx_len = enclen;
317
memmove(auth->hashgx, hashbuf, 32);
319
/* Create a D-H Key Message */
320
err = create_key_message(auth);
322
auth->authstate = OTRL_AUTHSTATE_AWAITING_REVEALSIG;
325
case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
326
/* Use the incoming parameters, but just retransmit the old
327
* D-H Key Message. */
329
auth->encgx = encbuf;
331
auth->encgx_len = enclen;
332
memmove(auth->hashgx, hashbuf, 32);
339
err = gcry_error(GPG_ERR_INV_VALUE);
342
err = gcry_error(GPG_ERR_ENOMEM);
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.
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)
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;
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);
373
/* How big is the total structure to be MAC'd? */
374
totallen = 4 + ourpublen + 4 + theirpublen + 2 + privkey->pubkey_datalen
376
buf = malloc(totallen);
377
if (buf == NULL) goto memerr;
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;
392
debug_int("Keyid", bufp-4);
397
gcry_md_reset(mackey);
398
gcry_md_write(mackey, buf, totallen);
399
memmove(macbuf, gcry_md_read(mackey, GCRY_MD_SHA256), 32);
405
err = otrl_privkey_sign(&sigbuf, &siglen, privkey, macbuf, 32);
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;
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;
423
debug_int("Keyid", bufp-4);
424
memmove(bufp, sigbuf, siglen);
425
debug_data("Signature", bufp, siglen);
426
bufp += siglen; lenp -= siglen;
432
/* Now do the encryption */
433
err = gcry_cipher_encrypt(enckey, buf, totallen, NULL, 0);
438
*authlenp = totallen;
442
err = gcry_error(GPG_ERR_ENOMEM);
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.
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)
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;
468
gcry_sexp_t pubs = NULL;
469
unsigned int received_keyid;
470
unsigned char *fingerprintstart, *fingerprintend, *sigbuf;
473
/* Start by decrypting it */
474
err = gcry_cipher_decrypt(enckey, authbuf, authlen, NULL, 0);
480
/* Get the public key and calculate its fingerprint */
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;
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);
501
read_int(received_keyid);
502
if (received_keyid == 0) goto invval;
504
/* Get the signature */
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);
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;
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);
536
gcry_md_reset(mackey);
537
gcry_md_write(mackey, buf, totallen);
538
memmove(macbuf, gcry_md_read(mackey, GCRY_MD_SHA256), 32);
543
/* Verify the signature on the MAC */
544
err = otrl_privkey_verify(sigbuf, siglen, pubkey_type, pubs, macbuf, 32);
546
gcry_sexp_release(pubs);
549
/* Everything checked out */
550
*keyidp = received_keyid;
554
err = gcry_error(GPG_ERR_INV_VALUE);
557
err = gcry_error(GPG_ERR_ENOMEM);
560
gcry_sexp_release(pubs);
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
569
static gcry_error_t create_revealsig_message(OtrlAuthInfo *auth,
570
OtrlPrivKey *privkey)
572
gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
573
unsigned char *buf = NULL, *bufp, *startmac;
576
unsigned char *authbuf = NULL;
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);
584
buflen = 3 + 4 + 16 + 4 + authlen + 20;
585
buf = malloc(buflen);
586
if (buf == NULL) goto memerr;
591
memmove(bufp, "\x00\x02\x11", 3); /* header */
592
debug_data("Header", bufp, 3);
593
bufp += 3; lenp -= 3;
597
memmove(bufp, auth->r, 16);
598
debug_data("r", bufp, 16);
599
bufp += 16; lenp -= 16;
601
/* Encrypted authenticator */
604
memmove(bufp, authbuf, authlen);
605
debug_data("auth", bufp, authlen);
606
bufp += authlen; lenp -= authlen;
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;
619
free(auth->lastauthmsg);
620
auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
621
if (auth->lastauthmsg == NULL) goto memerr;
628
err = gcry_error(GPG_ERR_ENOMEM);
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
640
static gcry_error_t create_signature_message(OtrlAuthInfo *auth,
641
OtrlPrivKey *privkey)
643
gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
644
unsigned char *buf = NULL, *bufp, *startmac;
647
unsigned char *authbuf = NULL;
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,
656
buflen = 3 + 4 + authlen + 20;
657
buf = malloc(buflen);
658
if (buf == NULL) goto memerr;
663
memmove(bufp, "\x00\x02\x12", 3); /* header */
664
debug_data("Header", bufp, 3);
665
bufp += 3; lenp -= 3;
667
/* Encrypted authenticator */
670
memmove(bufp, authbuf, authlen);
671
debug_data("auth", bufp, authlen);
672
bufp += authlen; lenp -= authlen;
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;
685
free(auth->lastauthmsg);
686
auth->lastauthmsg = otrl_base64_otr_encode(buf, buflen);
687
if (auth->lastauthmsg == NULL) goto memerr;
694
err = gcry_error(GPG_ERR_ENOMEM);
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.
706
gcry_error_t otrl_auth_handle_key(OtrlAuthInfo *auth, const char *keymsg,
707
int *havemsgp, OtrlPrivKey *privkey)
709
gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
710
unsigned char *buf = NULL, *bufp = NULL;
712
gcry_mpi_t incoming_pub = NULL;
717
res = otrl_base64_otr_decode(keymsg, &buf, &buflen);
718
if (res == -1) goto memerr;
719
if (res == -2) goto invval;
725
if (memcmp(bufp, "\x00\x02\x0a", 3)) goto invval;
726
bufp += 3; lenp -= 3;
729
read_mpi(incoming_pub);
731
if (lenp != 0) goto invval;
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;
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));
751
/* Create the Reveal Signature Message */
752
err = create_revealsig_message(auth, privkey);
755
auth->authstate = OTRL_AUTHSTATE_AWAITING_SIG;
759
case OTRL_AUTHSTATE_AWAITING_SIG:
760
if (gcry_mpi_cmp(incoming_pub, auth->their_pub) == 0) {
761
/* Retransmit the Reveal Signature Message */
764
/* Ignore this message */
768
case OTRL_AUTHSTATE_NONE:
769
case OTRL_AUTHSTATE_AWAITING_REVEALSIG:
770
case OTRL_AUTHSTATE_V1_SETUP:
771
/* Ignore this message */
776
gcry_mpi_release(incoming_pub);
780
err = gcry_error(GPG_ERR_INV_VALUE);
783
err = gcry_error(GPG_ERR_ENOMEM);
786
gcry_mpi_release(incoming_pub);
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
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),
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];
813
res = otrl_base64_otr_decode(revealmsg, &buf, &buflen);
814
if (res == -1) goto memerr;
815
if (res == -2) goto invval;
821
if (memcmp(bufp, "\x00\x02\x11", 3)) goto invval;
822
bufp += 3; lenp -= 3;
826
if (rlen != 16) goto invval;
828
memmove(auth->r, bufp, rlen);
829
bufp += rlen; lenp -= rlen;
834
require_len(authlen);
835
bufp += authlen; lenp -= authlen;
841
bufp += 20; lenp -= 20;
843
if (lenp != 0) goto invval;
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;
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,
855
err = gcry_cipher_setkey(enc, auth->r, 16);
859
err = gcry_cipher_setctr(enc, ctr, 16);
862
err = gcry_cipher_decrypt(enc, gxbuf, auth->encgx_len,
863
auth->encgx, auth->encgx_len);
866
gcry_cipher_close(enc);
870
gcry_md_hash_buffer(GCRY_MD_SHA256, hashbuf, gxbuf,
872
if (memcmp(hashbuf, auth->hashgx, 32)) goto decfail;
876
lenp = auth->encgx_len;
878
read_mpi(incoming_pub);
882
if (lenp != 0) goto invval;
884
gcry_mpi_release(auth->their_pub);
885
auth->their_pub = incoming_pub;
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));
898
gcry_md_reset(auth->mac_m2);
899
gcry_md_write(auth->mac_m2, authstart, authend - authstart);
901
gcry_md_read(auth->mac_m2, GCRY_MD_SHA256),
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);
917
/* Create the Signature Message */
918
err = create_signature_message(auth, privkey);
921
/* No error? Then we've completed our end of the
923
auth->protocol_version = 2;
924
auth->session_id_half = OTRL_SESSIONID_SECOND_HALF_BOLD;
925
if (auth_succeeded) err = auth_succeeded(auth, asdata);
928
auth->authstate = OTRL_AUTHSTATE_NONE;
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 */
945
err = gcry_error(GPG_ERR_NO_ERROR);
948
err = gcry_error(GPG_ERR_INV_VALUE);
951
err = gcry_error(GPG_ERR_ENOMEM);
955
gcry_cipher_close(enc);
956
gcry_mpi_release(incoming_pub);
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.
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),
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;
979
res = otrl_base64_otr_decode(sigmsg, &buf, &buflen);
980
if (res == -1) goto memerr;
981
if (res == -2) goto invval;
987
if (memcmp(bufp, "\x00\x02\x12", 3)) goto invval;
988
bufp += 3; lenp -= 3;
993
require_len(authlen);
994
bufp += authlen; lenp -= authlen;
1000
bufp += 20; lenp -= 20;
1002
if (lenp != 0) goto invval;
1004
switch(auth->authstate) {
1005
case OTRL_AUTHSTATE_AWAITING_SIG:
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),
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);
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;
1034
auth->our_keyid = 0;
1035
auth->authstate = OTRL_AUTHSTATE_NONE;
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 */
1050
err = gcry_error(GPG_ERR_INV_VALUE);
1053
err = gcry_error(GPG_ERR_ENOMEM);
1059
/* Version 1 routines, for compatibility */
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.
1066
static gcry_error_t create_v1_key_exchange_message(OtrlAuthInfo *auth,
1067
unsigned char reply, OtrlPrivKey *privkey)
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];
1075
if (privkey->pubkey_type != OTRL_PUBKEY_TYPE_DSA) {
1076
return gpg_error(GPG_ERR_INV_VALUE);
1079
/* How big is the DH public key? */
1080
gcry_mpi_print(format, NULL, 0, &ourpublen, auth->our_dh.pub);
1082
totallen = 3 + 1 + privkey->pubkey_datalen + 4 + 4 + ourpublen + 40;
1083
buf = malloc(totallen);
1084
if (buf == NULL) goto memerr;
1089
memmove(bufp, "\x00\x01\x0a", 3); /* header */
1090
debug_data("Header", bufp, 3);
1091
bufp += 3; lenp -= 3;
1094
debug_data("Reply", bufp, 1);
1095
bufp += 1; lenp -= 1;
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;
1101
write_int(auth->our_keyid);
1102
debug_int("Keyid", bufp-4);
1104
write_mpi(auth->our_dh.pub, ourpublen, "D-H y");
1106
/* Hash all the data written so far, and sign the hash */
1107
gcry_md_hash_buffer(GCRY_MD_SHA1, hashbuf, buf, bufp - buf);
1109
err = otrl_privkey_sign(&sigbuf, &siglen, privkey, hashbuf, 20);
1112
if (siglen != 40) goto invval;
1113
memmove(bufp, sigbuf, 40);
1114
debug_data("Signature", bufp, 40);
1115
bufp += 40; lenp -= 40;
1121
free(auth->lastauthmsg);
1122
auth->lastauthmsg = otrl_base64_otr_encode(buf, totallen);
1123
if (auth->lastauthmsg == NULL) goto memerr;
1130
err = gcry_error(GPG_ERR_INV_VALUE);
1133
err = gcry_error(GPG_ERR_ENOMEM);
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.
1147
gcry_error_t otrl_auth_start_v1(OtrlAuthInfo *auth, DH_keypair *our_dh,
1148
unsigned int our_keyid, OtrlPrivKey *privkey)
1150
gcry_error_t err = gcry_error(GPG_ERR_NO_ERROR);
1152
/* Clear out this OtrlAuthInfo and start over */
1153
otrl_auth_clear(auth);
1154
auth->initiated = 1;
1156
/* Import the given DH keypair, or else create a fresh one */
1158
otrl_dh_keypair_copy(&(auth->our_dh), our_dh);
1159
auth->our_keyid = our_keyid;
1161
otrl_dh_gen_keypair(DH1536_GROUP_ID, &(auth->our_dh));
1162
auth->our_keyid = 1;
1165
err = create_v1_key_exchange_message(auth, 0, privkey);
1167
auth->authstate = OTRL_AUTHSTATE_V1_SETUP;
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
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),
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;
1200
res = otrl_base64_otr_decode(keyexchmsg, &buf, &buflen);
1201
if (res == -1) goto memerr;
1202
if (res == -2) goto invval;
1209
if (memcmp(bufp, "\x00\x01\x0a", 3)) goto invval;
1210
bufp += 3; lenp -= 3;
1214
received_reply = bufp[0];
1215
bufp += 1; lenp -= 1;
1218
fingerprintstart = bufp;
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);
1234
read_int(received_keyid);
1235
if (received_keyid == 0) goto invval;
1238
read_mpi(received_pub);
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,
1246
gcry_sexp_release(pubs);
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);
1258
if (auth->authstate != OTRL_AUTHSTATE_V1_SETUP) {
1259
/* Clear the auth and start over */
1260
otrl_auth_clear(auth);
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);
1270
if (received_reply == 0x01) {
1271
/* Don't send a reply to this. */
1274
/* Import the given DH keypair, or else create a fresh one */
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;
1283
/* Reply with our own Key Exchange Message */
1284
err = create_v1_key_exchange_message(auth, 1, privkey);
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));
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;
1305
err = gcry_error(GPG_ERR_INV_VALUE);
1308
err = gcry_error(GPG_ERR_ENOMEM);
1311
gcry_sexp_release(pubs);
1312
gcry_mpi_release(received_pub);
1316
#ifdef OTRL_TESTING_AUTH
1318
#include "privkey.h"
1320
#define CHECK_ERR if (err) { printf("Error: %s\n", gcry_strerror(err)); return 1; }
1322
static gcry_error_t starting(const OtrlAuthInfo *auth, void *asdata)
1324
char *name = asdata;
1326
fprintf(stderr, "\nStarting ENCRYPTED mode for %s (v%d).\n", name, auth->protocol_version);
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);
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);
1338
return gpg_error(GPG_ERR_NO_ERROR);
1341
int main(int argc, char **argv)
1343
OtrlAuthInfo alice, bob;
1347
OtrlPrivKey *alicepriv, *bobpriv;
1351
otrl_auth_new(&alice);
1352
otrl_auth_new(&bob);
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");
1359
printf("\n\n ***** V2 *****\n\n");
1361
err = otrl_auth_start_v2(&bob, NULL, 0);
1363
printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
1364
err = otrl_auth_handle_commit(&alice, bob.lastauthmsg, NULL, 0);
1366
printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg);
1367
err = otrl_auth_handle_key(&bob, alice.lastauthmsg, &havemsg, bobpriv);
1370
printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
1372
printf("\nIGNORE\n\n");
1374
err = otrl_auth_handle_revealsig(&alice, bob.lastauthmsg, &havemsg,
1375
alicepriv, starting, "Alice");
1378
printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg);
1380
printf("\nIGNORE\n\n");
1382
err = otrl_auth_handle_signature(&bob, alice.lastauthmsg, &havemsg,
1386
printf("\n\n ***** V1 *****\n\n");
1388
err = otrl_auth_start_v1(&bob, NULL, 0, bobpriv);
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");
1395
printf("\nAlice: %d\n%s\n\n", strlen(alice.lastauthmsg), alice.lastauthmsg);
1397
printf("\nIGNORE\n\n");
1399
err = otrl_auth_handle_v1_key_exchange(&bob, alice.lastauthmsg,
1400
&havemsg, bobpriv, NULL, 0, starting, "Bob");
1403
printf("\nBob: %d\n%s\n\n", strlen(bob.lastauthmsg), bob.lastauthmsg);
1405
printf("\nIGNORE\n\n");
1408
otrl_userstate_free(us);
1409
otrl_auth_clear(&alice);
1410
otrl_auth_clear(&bob);