comparison common-kex.c @ 26:0969767bca0d

snapshot of stuff
author Matt Johnston <matt@ucc.asn.au>
date Mon, 26 Jul 2004 02:44:20 +0000
parents c1e5d9195402
children f789045062e6
comparison
equal deleted inserted replaced
25:e4b6e2d569b2 26:0969767bca0d
191 /* sent/recv'd MSG_NEWKEYS */ 191 /* sent/recv'd MSG_NEWKEYS */
192 ses.kexstate.recvnewkeys = 0; 192 ses.kexstate.recvnewkeys = 0;
193 ses.kexstate.sentnewkeys = 0; 193 ses.kexstate.sentnewkeys = 0;
194 194
195 /* first_packet_follows */ 195 /* first_packet_follows */
196 /* TODO - currently not handled */
197 ses.kexstate.firstfollows = 0; 196 ses.kexstate.firstfollows = 0;
198 197
199 ses.kexstate.datatrans = 0; 198 ses.kexstate.datatrans = 0;
200 ses.kexstate.datarecv = 0; 199 ses.kexstate.datarecv = 0;
201 200
400 TRACE(("continue recv_msg_kexinit: sent kexinit")); 399 TRACE(("continue recv_msg_kexinit: sent kexinit"));
401 } 400 }
402 401
403 402
404 if (IS_DROPBEAR_CLIENT) { 403 if (IS_DROPBEAR_CLIENT) {
405 404 #ifdef DROPBEAR_CLIENT
406 /* read the peer's choice of algos */ 405
407 cli_read_kex(); 406 /* read the peer's choice of algos */
408 407 read_kex_algos(cli_buf_match_algo);
409 /* V_C, the client's version string (CR and NL excluded) */ 408
409 /* V_C, the client's version string (CR and NL excluded) */
410 buf_putstring(ses.kexhashbuf, 410 buf_putstring(ses.kexhashbuf,
411 (unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT)); 411 (unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT));
412 /* V_S, the server's version string (CR and NL excluded) */ 412 /* V_S, the server's version string (CR and NL excluded) */
413 buf_putstring(ses.kexhashbuf, 413 buf_putstring(ses.kexhashbuf,
414 ses.remoteident, strlen((char*)ses.remoteident)); 414 ses.remoteident, strlen((char*)ses.remoteident));
415 415
416 /* I_C, the payload of the client's SSH_MSG_KEXINIT */ 416 /* I_C, the payload of the client's SSH_MSG_KEXINIT */
417 buf_putstring(ses.kexhashbuf, 417 buf_putstring(ses.kexhashbuf,
418 buf_getptr(ses.transkexinit, ses.transkexinit->len), 418 buf_getptr(ses.transkexinit, ses.transkexinit->len),
419 ses.transkexinit->len); 419 ses.transkexinit->len);
420 /* I_S, the payload of the server's SSH_MSG_KEXINIT */ 420 /* I_S, the payload of the server's SSH_MSG_KEXINIT */
421 buf_setpos(ses.payload, 0); 421 buf_setpos(ses.payload, 0);
422 buf_putstring(ses.kexhashbuf, 422 buf_putstring(ses.kexhashbuf,
423 buf_getptr(ses.payload, ses.payload->len), 423 buf_getptr(ses.payload, ses.payload->len),
424 ses.payload->len); 424 ses.payload->len);
425 425
426 cli_ses.state = KEXINIT_RCVD;
427 #endif
426 } else { 428 } else {
427 429 /* SERVER */
428 /* read the peer's choice of algos */ 430 #ifdef DROPBEAR_SERVER
429 svr_read_kex(); 431
430 /* V_C, the client's version string (CR and NL excluded) */ 432 /* read the peer's choice of algos */
433 read_kex_algos(svr_buf_match_algo);
434 /* V_C, the client's version string (CR and NL excluded) */
431 buf_putstring(ses.kexhashbuf, 435 buf_putstring(ses.kexhashbuf,
432 ses.remoteident, strlen((char*)ses.remoteident)); 436 ses.remoteident, strlen((char*)ses.remoteident));
433 /* V_S, the server's version string (CR and NL excluded) */ 437 /* V_S, the server's version string (CR and NL excluded) */
434 buf_putstring(ses.kexhashbuf, 438 buf_putstring(ses.kexhashbuf,
435 (unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT)); 439 (unsigned char*)LOCAL_IDENT, strlen(LOCAL_IDENT));
436 440
437 /* I_C, the payload of the client's SSH_MSG_KEXINIT */ 441 /* I_C, the payload of the client's SSH_MSG_KEXINIT */
438 buf_setpos(ses.payload, 0); 442 buf_setpos(ses.payload, 0);
439 buf_putstring(ses.kexhashbuf, 443 buf_putstring(ses.kexhashbuf,
440 buf_getptr(ses.payload, ses.payload->len), 444 buf_getptr(ses.payload, ses.payload->len),
441 ses.payload->len); 445 ses.payload->len);
442 /* I_S, the payload of the server's SSH_MSG_KEXINIT */ 446 /* I_S, the payload of the server's SSH_MSG_KEXINIT */
443 buf_putstring(ses.kexhashbuf, 447 buf_putstring(ses.kexhashbuf,
444 buf_getptr(ses.transkexinit, ses.transkexinit->len), 448 buf_getptr(ses.transkexinit, ses.transkexinit->len),
445 ses.transkexinit->len); 449 ses.transkexinit->len);
450 ses.requirenext = SSH_MSG_KEXDH_INIT;
451 #endif
446 } 452 }
447 453
448 buf_free(ses.transkexinit); 454 buf_free(ses.transkexinit);
449 ses.transkexinit = NULL; 455 ses.transkexinit = NULL;
450 /* the rest of ses.kexhashbuf will be done after DH exchange */ 456 /* the rest of ses.kexhashbuf will be done after DH exchange */
451 457
452 ses.kexstate.recvkexinit = 1; 458 ses.kexstate.recvkexinit = 1;
453 ses.requirenext = SSH_MSG_KEXDH_INIT;
454 // ses.expecting = 0; // client matt 459 // ses.expecting = 0; // client matt
455 460
456 TRACE(("leave recv_msg_kexinit")); 461 TRACE(("leave recv_msg_kexinit"));
457 } 462 }
458 463
464 /* Initialises and generate one side of the diffie-hellman key exchange values.
465 * See the ietf-secsh-transport draft, section 6, for details */
466 void gen_kexdh_vals(mp_int *dh_pub, mp_int *dh_priv) {
467
468 mp_int dh_p, dh_q, dh_g;
469 unsigned char randbuf[DH_P_LEN];
470 int dh_q_len;
471
472 TRACE(("enter send_msg_kexdh_reply"));
473
474 m_mp_init_multi(&dh_g, &dh_p, &dh_q, dh_priv, dh_pub, NULL);
475
476 /* read the prime and generator*/
477 if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
478 != MP_OKAY) {
479 dropbear_exit("Diffie-Hellman error");
480 }
481
482 if (mp_set_int(&dh_g, DH_G_VAL) != MP_OKAY) {
483 dropbear_exit("Diffie-Hellman error");
484 }
485
486 /* calculate q = (p-1)/2 */
487 /* dh_priv is just a temp var here */
488 if (mp_sub_d(&dh_p, 1, dh_priv) != MP_OKAY) {
489 dropbear_exit("Diffie-Hellman error");
490 }
491 if (mp_div_2(dh_priv, &dh_q) != MP_OKAY) {
492 dropbear_exit("Diffie-Hellman error");
493 }
494
495 dh_q_len = mp_unsigned_bin_size(&dh_q);
496
497 /* calculate our random value dh_y */
498 do {
499 assert((unsigned int)dh_q_len <= sizeof(randbuf));
500 genrandom(randbuf, dh_q_len);
501 if (mp_read_unsigned_bin(dh_priv, randbuf, dh_q_len) != MP_OKAY) {
502 dropbear_exit("Diffie-Hellman error");
503 }
504 } while (mp_cmp(dh_priv, &dh_q) == MP_GT || mp_cmp_d(dh_priv, 0) != MP_GT);
505
506 /* f = g^y mod p */
507 if (mp_exptmod(&dh_g, dh_priv, &dh_p, dh_pub) != MP_OKAY) {
508 dropbear_exit("Diffie-Hellman error");
509 }
510 mp_clear_multi(&dh_g, &dh_p, &dh_q, NULL);
511 }
512
513 /* This function is fairly common between client/server, with some substitution
514 * of dh_e/dh_f etc. Hence these arguments:
515 * dh_pub_us is 'e' for the client, 'f' for the server. dh_pub_them is
516 * vice-versa. dh_priv is the x/y value corresponding to dh_pub_us */
517 void kexdh_comb_key(mp_int *dh_pub_us, mp_int *dh_priv, mp_int *dh_pub_them,
518 sign_key *hostkey) {
519
520 mp_int dh_p;
521 mp_int *dh_e = NULL, *dh_f = NULL;
522 hash_state hs;
523
524 /* read the prime and generator*/
525 mp_init(&dh_p);
526 if (mp_read_unsigned_bin(&dh_p, (unsigned char*)dh_p_val, DH_P_LEN)
527 != MP_OKAY) {
528 dropbear_exit("Diffie-Hellman error");
529 }
530
531 /* Check that dh_pub_them (dh_e or dh_f) is in the range [1, p-1] */
532 if (mp_cmp(dh_pub_them, &dh_p) != MP_LT
533 || mp_cmp_d(dh_pub_them, 0) != MP_GT) {
534 dropbear_exit("Diffie-Hellman error");
535 }
536
537 /* K = e^y mod p = f^x mod p */
538 ses.dh_K = (mp_int*)m_malloc(sizeof(mp_int));
539 m_mp_init(ses.dh_K);
540 if (mp_exptmod(dh_pub_them, dh_priv, &dh_p, ses.dh_K) != MP_OKAY) {
541 dropbear_exit("Diffie-Hellman error");
542 }
543
544 /* clear no longer needed vars */
545 mp_clear_multi(&dh_p, NULL);
546
547 /* From here on, the code needs to work with the _same_ vars on each side,
548 * not vice-versaing for client/server */
549 if (IS_DROPBEAR_CLIENT) {
550 dh_e = dh_pub_us;
551 dh_f = dh_pub_them;
552 } else {
553 dh_e = dh_pub_them;
554 dh_f = dh_pub_us;
555 }
556
557 /* Create the remainder of the hash buffer, to generate the exchange hash */
558 /* K_S, the host key */
559 buf_put_pub_key(ses.kexhashbuf, hostkey, ses.newkeys->algo_hostkey);
560 /* e, exchange value sent by the client */
561 buf_putmpint(ses.kexhashbuf, dh_e);
562 /* f, exchange value sent by the server */
563 buf_putmpint(ses.kexhashbuf, dh_f);
564 /* K, the shared secret */
565 buf_putmpint(ses.kexhashbuf, ses.dh_K);
566
567 /* calculate the hash H to sign */
568 sha1_init(&hs);
569 buf_setpos(ses.kexhashbuf, 0);
570 sha1_process(&hs, buf_getptr(ses.kexhashbuf, ses.kexhashbuf->len),
571 ses.kexhashbuf->len);
572 sha1_done(&hs, ses.hash);
573 buf_free(ses.kexhashbuf);
574 ses.kexhashbuf = NULL;
575
576 /* first time around, we set the session_id to H */
577 if (ses.session_id == NULL) {
578 /* create the session_id, this never needs freeing */
579 ses.session_id = (unsigned char*)m_malloc(SHA1_HASH_SIZE);
580 memcpy(ses.session_id, ses.hash, SHA1_HASH_SIZE);
581 }
582 }
583
584 /* read the other side's algo list. buf_match_algo is a callback to match
585 * algos for the client or server. */
586 void read_kex_algos(
587 algo_type*(buf_match_algo)(buffer*buf, algo_type localalgos[],
588 int *goodguess)) {
589
590 algo_type * algo;
591 char * erralgo = NULL;
592
593 int goodguess = 0;
594 int allgood = 1; /* we AND this with each goodguess and see if its still
595 true after */
596
597 buf_incrpos(ses.payload, 16); /* start after the cookie */
598
599 ses.newkeys = (struct key_context*)m_malloc(sizeof(struct key_context));
600
601 /* kex_algorithms */
602 algo = buf_match_algo(ses.payload, sshkex, &goodguess);
603 allgood &= goodguess;
604 if (algo == NULL) {
605 erralgo = "kex";
606 goto error;
607 }
608 ses.newkeys->algo_kex = algo->val;
609
610 /* server_host_key_algorithms */
611 algo = buf_match_algo(ses.payload, sshhostkey, &goodguess);
612 allgood &= goodguess;
613 if (algo == NULL) {
614 erralgo = "hostkey";
615 goto error;
616 }
617 ses.newkeys->algo_hostkey = algo->val;
618
619 /* encryption_algorithms_client_to_server */
620 algo = buf_match_algo(ses.payload, sshciphers, &goodguess);
621 if (algo == NULL) {
622 erralgo = "enc c->s";
623 goto error;
624 }
625 ses.newkeys->recv_algo_crypt = (struct dropbear_cipher*)algo->data;
626
627 /* encryption_algorithms_server_to_client */
628 algo = buf_match_algo(ses.payload, sshciphers, &goodguess);
629 if (algo == NULL) {
630 erralgo = "enc s->c";
631 goto error;
632 }
633 ses.newkeys->trans_algo_crypt = (struct dropbear_cipher*)algo->data;
634
635 /* mac_algorithms_client_to_server */
636 algo = buf_match_algo(ses.payload, sshhashes, &goodguess);
637 if (algo == NULL) {
638 erralgo = "mac c->s";
639 goto error;
640 }
641 ses.newkeys->recv_algo_mac = (struct dropbear_hash*)algo->data;
642
643 /* mac_algorithms_server_to_client */
644 algo = buf_match_algo(ses.payload, sshhashes, &goodguess);
645 if (algo == NULL) {
646 erralgo = "mac s->c";
647 goto error;
648 }
649 ses.newkeys->trans_algo_mac = (struct dropbear_hash*)algo->data;
650
651 /* compression_algorithms_client_to_server */
652 algo = buf_match_algo(ses.payload, sshcompress, &goodguess);
653 if (algo == NULL) {
654 erralgo = "comp c->s";
655 goto error;
656 }
657 ses.newkeys->recv_algo_comp = algo->val;
658
659 /* compression_algorithms_server_to_client */
660 algo = buf_match_algo(ses.payload, sshcompress, &goodguess);
661 if (algo == NULL) {
662 erralgo = "comp s->c";
663 goto error;
664 }
665 ses.newkeys->trans_algo_comp = algo->val;
666
667 /* languages_client_to_server */
668 buf_eatstring(ses.payload);
669
670 /* languages_server_to_client */
671 buf_eatstring(ses.payload);
672
673 /* first_kex_packet_follows */
674 if (buf_getbyte(ses.payload)) {
675 ses.kexstate.firstfollows = 1;
676 /* if the guess wasn't good, we ignore the packet sent */
677 if (!allgood) {
678 ses.ignorenext = 1;
679 }
680 }
681
682 /* reserved for future extensions */
683 buf_getint(ses.payload);
684 return;
685
686 error:
687 dropbear_exit("no matching algo %s", erralgo);
688 }