322
188
/* Return a pointer to a newly-allocated OTR query message, customized
323
189
* with our name. The caller should free() the result when he's done
325
char *otrl_proto_default_query_msg(const char *ourname)
191
char *otrl_proto_default_query_msg(const char *ourname, OtrlPolicy policy)
194
int v1_supported, v2_supported;
195
const char *version_tag;
328
196
/* Don't use g_strdup_printf here, because someone (not us) is going
329
197
* to free() the *message pointer, not g_free() it. We can't
330
198
* require that they g_free() it, because this pointer will probably
331
199
* get passed to the main IM application for processing (and
333
const char *format = "?OTR?\n<b>%s</b> has requested an "
201
const char *format = "?OTR%s\n<b>%s</b> has requested an "
334
202
"<a href=\"http://www.cypherpunks.ca/otr/\">Off-the-Record "
335
203
"private conversation</a>. However, you do not have a plugin "
336
204
"to support that.\nSee <a href=\"http://www.cypherpunks.ca/otr/\">"
337
205
"http://www.cypherpunks.ca/otr/</a> for more information.";
339
/* Remove "%s", add '\0' */
340
msg = malloc(strlen(format) + strlen(ourname) - 1);
207
/* Figure out the version tag */
208
v1_supported = (policy & OTRL_POLICY_ALLOW_V1);
209
v2_supported = (policy & OTRL_POLICY_ALLOW_V2);
212
version_tag = "?v2?";
224
/* Remove two "%s", add '\0' */
225
msg = malloc(strlen(format) + strlen(version_tag) + strlen(ourname) - 3);
341
226
if (!msg) return NULL;
342
sprintf(msg, format, ourname);
227
sprintf(msg, format, version_tag, ourname);
231
/* Return the best version of OTR support by both sides, given an OTR
232
* Query Message and the local policy. */
233
unsigned int otrl_proto_query_bestversion(const char *querymsg,
237
unsigned int query_versions = 0;
239
otrtag = strstr(querymsg, "?OTR");
241
if (*otrtag == '?') {
242
query_versions = (1<<0);
245
if (*otrtag == 'v') {
246
for(++otrtag; *otrtag && *otrtag != '?'; ++otrtag) {
249
query_versions |= (1<<1);
255
if ((policy & OTRL_POLICY_ALLOW_V2) && (query_versions & (1<<1))) {
258
if ((policy & OTRL_POLICY_ALLOW_V1) && (query_versions & (1<<0))) {
264
/* Locate any whitespace tag in this message, and return the best
265
* version of OTR support on both sides. Set *starttagp and *endtagp to
266
* the start and end of the located tag, so that it can be snipped out. */
267
unsigned int otrl_proto_whitespace_bestversion(const char *msg,
268
const char **starttagp, const char **endtagp, OtrlPolicy policy)
270
const char *starttag, *endtag;
271
unsigned int query_versions = 0;
276
starttag = strstr(msg, OTRL_MESSAGE_TAG_BASE);
277
if (!starttag) return 0;
279
endtag = starttag + strlen(OTRL_MESSAGE_TAG_BASE);
281
/* Look for groups of 8 spaces and/or tabs */
286
if (endtag[i] != ' ' && endtag[i] != '\t') {
292
if (!strncmp(endtag, OTRL_MESSAGE_TAG_V1, 8)) {
293
query_versions |= (1<<0);
295
if (!strncmp(endtag, OTRL_MESSAGE_TAG_V2, 8)) {
296
query_versions |= (1<<1);
304
*starttagp = starttag;
307
if ((policy & OTRL_POLICY_ALLOW_V2) && (query_versions & (1<<1))) {
310
if ((policy & OTRL_POLICY_ALLOW_V1) && (query_versions & (1<<0))) {
346
316
/* Return the Message type of the given message. */
347
OTRMessageType otrl_proto_message_type(const char *message)
317
OtrlMessageType otrl_proto_message_type(const char *message)
351
321
otrtag = strstr(message, "?OTR");
354
if (strstr(message, OTR_MESSAGE_TAG)) {
355
return OTR_TAGGEDPLAINTEXT;
324
if (strstr(message, OTRL_MESSAGE_TAG_BASE)) {
325
return OTRL_MSGTYPE_TAGGEDPLAINTEXT;
361
if (!strncmp(otrtag, "?OTR?", 5)) return OTR_QUERY;
362
if (!strncmp(otrtag, "?OTR:AAEK", 9)) return OTR_KEYEXCH;
363
if (!strncmp(otrtag, "?OTR:AAED", 9)) return OTR_DATA;
364
if (!strncmp(otrtag, "?OTR Error:", 11)) return OTR_ERROR;
369
/* Create a Key Exchange message for our correspondent. If we need a
370
* private key and don't have one, create_privkey will be called. Use
371
* the privkeys from the given OtrlUserState. */
372
gcry_error_t otrl_proto_create_key_exchange(OtrlUserState us,
373
char **messagep, ConnContext *context, unsigned char is_reply,
374
void (*create_privkey)(void *create_privkey_data,
375
const char *accountname, const char *protocol),
376
void *create_privkey_data)
379
gcry_sexp_t dsas, rs, ss;
380
gcry_sexp_t sigs, hashs;
381
size_t nr, ns, buflen, lenp;
382
unsigned char *buf, *bufp;
383
enum gcry_mpi_format format = GCRYMPI_FMT_USG;
384
unsigned char digest[20];
385
gcry_mpi_t digestmpi;
390
otrl_privkey_find(us, context->accountname, context->protocol);
394
if (privkey == NULL) {
395
/* We've got no private key! */
396
if (create_privkey) {
397
create_privkey(create_privkey_data, context->accountname,
400
otrl_privkey_find(us, context->accountname, context->protocol);
403
if (privkey == NULL) {
404
/* We've still got no private key! */
405
return gcry_error(GPG_ERR_UNUSABLE_SECKEY);
408
/* Make sure we have two keys */
409
while (context->our_keyid < 2) {
410
rotate_dh_keys(context);
413
buflen = 3 + 1 + privkey->pubkey_datalen + 4 + 40;
414
/* header, is_reply, pubkey, keyid, sig */
415
gcry_mpi_print(format, NULL, 0, &pubkeylen, context->our_old_dh_key.pub);
416
buflen += pubkeylen + 4;
417
buf = malloc(buflen);
419
return gcry_error(GPG_ERR_ENOMEM);
423
memmove(bufp, "\x00\x01\x0a", 3); /* header */
424
debug_data("Header", bufp, 3);
425
bufp += 3; lenp -= 3;
427
*bufp = is_reply; /* is_reply */
428
debug_data("Reply", bufp, 1);
429
bufp += 1; lenp -= 1;
432
memmove(bufp, privkey->pubkey_data, privkey->pubkey_datalen);
433
debug_data("DSA key", bufp, privkey->pubkey_datalen);
434
bufp += privkey->pubkey_datalen; lenp -= privkey->pubkey_datalen;
437
write_int(context->our_keyid - 1);
438
debug_int("Keyid", bufp - 4);
441
write_mpi(context->our_old_dh_key.pub, pubkeylen, "Pubkey");
443
/* Get a hash of the data to be signed */
444
gcry_md_hash_buffer(GCRY_MD_SHA1, digest, buf, bufp-buf);
445
gcry_mpi_scan(&digestmpi, GCRYMPI_FMT_USG, digest, 20, NULL);
447
/* Calculate the sig */
448
gcry_sexp_build(&hashs, NULL, "(%m)", digestmpi);
449
gcry_mpi_release(digestmpi);
450
gcry_pk_sign(&sigs, hashs, privkey->privkey);
451
gcry_sexp_release(hashs);
452
dsas = gcry_sexp_find_token(sigs, "dsa", 0);
453
gcry_sexp_release(sigs);
454
rs = gcry_sexp_find_token(dsas, "r", 0);
455
ss = gcry_sexp_find_token(dsas, "s", 0);
456
gcry_sexp_release(dsas);
457
r = gcry_sexp_nth_mpi(rs, 1, GCRYMPI_FMT_USG);
458
gcry_sexp_release(rs);
459
s = gcry_sexp_nth_mpi(ss, 1, GCRYMPI_FMT_USG);
460
gcry_sexp_release(ss);
461
gcry_mpi_print(format, NULL, 0, &nr, r);
462
gcry_mpi_print(format, NULL, 0, &ns, s);
464
gcry_mpi_print(format, bufp+(20-nr), lenp, NULL, r);
465
debug_data("R", bufp, 20);
466
bufp += 20; lenp -= 20;
467
gcry_mpi_print(format, bufp+(20-ns), lenp, NULL, s);
468
debug_data("S", bufp, 20);
469
bufp += 20; lenp -= 20;
476
/* Make the base64-encoding. */
477
base64len = ((buflen + 2) / 3) * 4;
478
base64buf = malloc(5 + base64len + 1 + 1);
479
assert(base64buf != NULL);
480
memmove(base64buf, "?OTR:", 5);
481
otrl_base64_encode(base64buf+5, buf, buflen);
482
base64buf[5 + base64len] = '.';
483
base64buf[5 + base64len + 1] = '\0';
487
*messagep = base64buf;
489
return gcry_error(GPG_ERR_NO_ERROR);
492
/* Deallocate an OTRKeyExchangeMsg returned from proto_parse_key_exchange */
493
void otrl_proto_free_key_exchange(OTRKeyExchangeMsg kem)
496
gcry_sexp_release(kem->digest_sexp);
497
gcry_sexp_release(kem->dsa_pubkey);
498
gcry_mpi_release(kem->dh_pubkey);
499
gcry_sexp_release(kem->dsa_sig);
503
/* Parse a purported Key Exchange message. Possible error code portions
504
* of the return value:
505
* GPG_ERR_NO_ERROR: Success
506
* GPG_ERR_ENOMEM: Out of memory condition
507
* GPG_ERR_INV_VALUE: The message was not a well-formed Key Exchange
509
* GPG_ERR_BAD_SIGNATURE: The signature on the message didn't verify
511
gcry_error_t otrl_proto_parse_key_exchange(OTRKeyExchangeMsg *kemp,
514
char *otrtag, *endtag;
515
unsigned char *rawmsg, *bufp;
516
size_t msglen, rawlen, lenp;
517
gcry_mpi_t p,q,g,e,r,s;
518
unsigned char hash_of_msg[20];
520
const unsigned char *fingerprintstart, *fingerprintend;
521
const unsigned char *signaturestart, *signatureend;
522
OTRKeyExchangeMsg kem = calloc(1, sizeof(struct s_OTRKeyExchangeMsg));
526
return gcry_error(GPG_ERR_ENOMEM);
529
otrtag = strstr(msg, "?OTR:");
532
otrl_proto_free_key_exchange(kem);
533
return gcry_error(GPG_ERR_INV_VALUE);
535
endtag = strchr(otrtag, '.');
537
msglen = endtag-otrtag;
539
msglen = strlen(otrtag);
542
/* Base64-decode the message */
543
rawlen = ((msglen-5) / 4) * 3; /* maximum possible */
544
rawmsg = malloc(rawlen);
545
if (!rawmsg && rawlen > 0) {
547
otrl_proto_free_key_exchange(kem);
548
return gcry_error(GPG_ERR_ENOMEM);
550
rawlen = otrl_base64_decode(rawmsg, otrtag+5, msglen-5); /* actual size */
555
signaturestart = bufp;
558
if (memcmp(bufp, "\x00\x01\x0a", 3)) {
562
bufp += 3; lenp -= 3;
565
kem->is_reply = *bufp;
566
if (kem->is_reply != 0 && kem->is_reply != 1) {
567
/* Malformed is_reply field */
570
bufp += 1; lenp -= 1;
572
fingerprintstart = bufp;
573
/* Read the DSA public key and calculate its fingerprint. */
578
fingerprintend = bufp;
579
gcry_md_hash_buffer(GCRY_MD_SHA1, kem->key_fingerprint,
580
fingerprintstart, fingerprintend-fingerprintstart);
582
/* Create the pubkey S-expression. */
583
gcry_sexp_build(&(kem->dsa_pubkey), NULL,
584
"(public-key (dsa (p %m)(q %m)(g %m)(y %m)))",
591
/* Read the key id */
592
read_int(kem->keyid);
593
if (kem->keyid == 0) {
594
/* Not a legal value */
598
/* Read the DH public key */
599
read_mpi(kem->dh_pubkey);
601
/* Hash the message so we can check the signature */
603
gcry_md_hash_buffer(GCRY_MD_SHA1, hash_of_msg,
604
signaturestart, signatureend-signaturestart);
605
/* Turn the hash into an mpi, then into a sexp */
606
gcry_mpi_scan(&hashmpi, GCRYMPI_FMT_USG, hash_of_msg, 20, NULL);
607
gcry_sexp_build(&(kem->digest_sexp), NULL, "(%m)", hashmpi);
608
gcry_mpi_release(hashmpi);
610
/* Read the signature */
612
gcry_mpi_scan(&r, GCRYMPI_FMT_USG, bufp, 20, NULL);
613
gcry_mpi_scan(&s, GCRYMPI_FMT_USG, bufp+20, 20, NULL);
615
gcry_sexp_build(&(kem->dsa_sig), NULL, "(sig-val (dsa (r %m)(s %m)))",
620
/* That should be everything */
621
if (lenp != 0) goto invval;
623
/* Verify the signature */
624
if (gcry_pk_verify(kem->dsa_sig, kem->digest_sexp, kem->dsa_pubkey)) {
626
otrl_proto_free_key_exchange(kem);
629
return gcry_error(GPG_ERR_BAD_SIGNATURE);
634
return gcry_error(GPG_ERR_NO_ERROR);
636
otrl_proto_free_key_exchange(kem);
639
return gcry_error(GPG_ERR_INV_VALUE);
642
/* Deal with a Key Exchange Message once it's been received and passed
643
* all the validity and UI ("accept this fingerprint?") tests.
644
* context/fprint is the ConnContext and Fingerprint to which it
645
* belongs. Use the given OtrlUserState to look up any necessary
646
* private keys. It is the caller's responsibility to
647
* otrl_proto_free_key_exchange(kem) when we're done. If *messagep gets
648
* set to non-NULL by this function, then it's a message that needs to
649
* get sent to the correspondent. If we need a private key and don't
650
* have one, create_privkey will be called. */
651
gcry_error_t otrl_proto_accept_key_exchange(OtrlUserState us,
652
ConnContext *context, Fingerprint *fprint, OTRKeyExchangeMsg kem,
654
void (*create_privkey)(void *create_privkey_data,
655
const char *accountname, const char *protocol),
656
void *create_privkey_data)
659
char *savedmessage = context->lastmessage;
660
int savedmay_retransmit = context->may_retransmit;
661
time_t savedtime = context->lastsent;
662
ConnectionState state = context->state;
664
context->lastmessage = NULL;
668
if (kem->is_reply == 0) {
669
/* Send a Key Exchange message to the correspondent */
670
err = otrl_proto_create_key_exchange(us, messagep, context, 1,
671
create_privkey, create_privkey_data);
674
if (context->their_keyid > 0 &&
675
(kem->keyid == context->their_keyid &&
676
!gcry_mpi_cmp(kem->dh_pubkey, context->their_y))
677
|| (kem->keyid == (context->their_keyid - 1) &&
678
!gcry_mpi_cmp(kem->dh_pubkey, context->their_old_y))) {
679
/* We've already seen this key of theirs, so all is
683
/* It's an entirely different session; our correspondent has
684
* gone away and come back. */
685
otrl_context_force_setup(context);
688
case CONN_UNCONNECTED:
690
if (state == CONN_UNCONNECTED ||
691
(state == CONN_SETUP && kem->is_reply == 0)) {
692
/* Send a Key Exchange message to the correspondent */
693
err = otrl_proto_create_key_exchange(us, messagep, context, 1,
694
create_privkey, create_privkey_data);
697
context->their_keyid = kem->keyid;
698
gcry_mpi_release(context->their_y);
699
context->their_y = gcry_mpi_copy(kem->dh_pubkey);
700
err = otrl_dh_session(&(context->sesskeys[0][0]),
701
&(context->our_dh_key), context->their_y);
703
err = otrl_dh_session(&(context->sesskeys[1][0]),
704
&(context->our_old_dh_key), context->their_y);
706
context->state = CONN_CONNECTED;
707
context->active_fingerprint = fprint;
708
context->generation++;
709
context->lastmessage = savedmessage;
710
context->may_retransmit = savedmay_retransmit;
711
context->lastsent = savedtime;
715
return gcry_error(GPG_ERR_NO_ERROR);
327
return OTRL_MSGTYPE_NOTOTR;
331
if (!strncmp(otrtag, "?OTR?", 5)) return OTRL_MSGTYPE_QUERY;
332
if (!strncmp(otrtag, "?OTRv", 5)) return OTRL_MSGTYPE_QUERY;
333
if (!strncmp(otrtag, "?OTR:AAIC", 9)) return OTRL_MSGTYPE_DH_COMMIT;
334
if (!strncmp(otrtag, "?OTR:AAIK", 9)) return OTRL_MSGTYPE_DH_KEY;
335
if (!strncmp(otrtag, "?OTR:AAIR", 9)) return OTRL_MSGTYPE_REVEALSIG;
336
if (!strncmp(otrtag, "?OTR:AAIS", 9)) return OTRL_MSGTYPE_SIGNATURE;
337
if (!strncmp(otrtag, "?OTR:AAEK", 9)) return OTRL_MSGTYPE_V1_KEYEXCH;
338
if (!strncmp(otrtag, "?OTR:AAED", 9)) return OTRL_MSGTYPE_DATA;
339
if (!strncmp(otrtag, "?OTR:AAID", 9)) return OTRL_MSGTYPE_DATA;
340
if (!strncmp(otrtag, "?OTR Error:", 11)) return OTRL_MSGTYPE_ERROR;
342
return OTRL_MSGTYPE_UNKNOWN;
718
345
/* Create an OTR Data message. Pass the plaintext as msg, and an
719
346
* optional chain of TLVs. A newly-allocated string will be returned in
720
347
* *encmessagep. */
721
348
gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
722
const char *msg, OtrlTLV *tlvs)
349
const char *msg, const OtrlTLV *tlvs, unsigned char flags)
724
351
size_t justmsglen = strlen(msg);
725
352
size_t msglen = justmsglen + 1 + otrl_tlv_seriallen(tlvs);