diff options
author | Ben Lindstrom <mouring@eviladmin.org> | 2001-04-04 01:56:17 +0000 |
---|---|---|
committer | Ben Lindstrom <mouring@eviladmin.org> | 2001-04-04 01:56:17 +0000 |
commit | 20d7c7b02c92c28007dba8b08e617a415146d1df (patch) | |
tree | 8b5258b1065f6ad079d7410c3a29562903f128bb /sshd.c | |
parent | 86ebcb6cf55ea296a7921d157afdc03c07102933 (diff) |
- markus@cvs.openbsd.org 2001/04/03 19:53:29
[dh.c dh.h kex.c kex.h sshconnect2.c sshd.c]
move kex to kex*.c, used dispatch_set() callbacks for kex. should
make rekeying easier.
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 359 |
1 files changed, 10 insertions, 349 deletions
@@ -40,7 +40,7 @@ | |||
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include "includes.h" | 42 | #include "includes.h" |
43 | RCSID("$OpenBSD: sshd.c,v 1.185 2001/03/29 23:42:01 djm Exp $"); | 43 | RCSID("$OpenBSD: sshd.c,v 1.186 2001/04/03 19:53:29 markus Exp $"); |
44 | 44 | ||
45 | #include <openssl/dh.h> | 45 | #include <openssl/dh.h> |
46 | #include <openssl/bn.h> | 46 | #include <openssl/bn.h> |
@@ -70,6 +70,7 @@ RCSID("$OpenBSD: sshd.c,v 1.185 2001/03/29 23:42:01 djm Exp $"); | |||
70 | #include "canohost.h" | 70 | #include "canohost.h" |
71 | #include "auth.h" | 71 | #include "auth.h" |
72 | #include "misc.h" | 72 | #include "misc.h" |
73 | #include "dispatch.h" | ||
73 | 74 | ||
74 | #ifdef LIBWRAP | 75 | #ifdef LIBWRAP |
75 | #include <tcpd.h> | 76 | #include <tcpd.h> |
@@ -1407,14 +1408,7 @@ do_ssh1_kex(void) | |||
1407 | void | 1408 | void |
1408 | do_ssh2_kex(void) | 1409 | do_ssh2_kex(void) |
1409 | { | 1410 | { |
1410 | Buffer *server_kexinit; | ||
1411 | Buffer *client_kexinit; | ||
1412 | int payload_len; | ||
1413 | int i; | ||
1414 | Kex *kex; | 1411 | Kex *kex; |
1415 | char *cprop[PROPOSAL_MAX]; | ||
1416 | |||
1417 | /* KEXINIT */ | ||
1418 | 1412 | ||
1419 | if (options.ciphers != NULL) { | 1413 | if (options.ciphers != NULL) { |
1420 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = | 1414 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
@@ -1431,36 +1425,14 @@ do_ssh2_kex(void) | |||
1431 | } | 1425 | } |
1432 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); | 1426 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); |
1433 | 1427 | ||
1434 | server_kexinit = kex_init(myproposal); | 1428 | kex = kex_start(myproposal); |
1435 | client_kexinit = xmalloc(sizeof(*client_kexinit)); | 1429 | kex->server = 1; |
1436 | buffer_init(client_kexinit); | 1430 | kex->client_version_string=client_version_string; |
1437 | 1431 | kex->server_version_string=server_version_string; | |
1438 | /* algorithm negotiation */ | 1432 | kex->load_host_key=&get_hostkey_by_type; |
1439 | kex_exchange_kexinit(server_kexinit, client_kexinit, cprop); | ||
1440 | kex = kex_choose_conf(cprop, myproposal, 1); | ||
1441 | for (i = 0; i < PROPOSAL_MAX; i++) | ||
1442 | xfree(cprop[i]); | ||
1443 | |||
1444 | switch (kex->kex_type) { | ||
1445 | case DH_GRP1_SHA1: | ||
1446 | ssh_dh1_server(kex, client_kexinit, server_kexinit); | ||
1447 | break; | ||
1448 | case DH_GEX_SHA1: | ||
1449 | ssh_dhgex_server(kex, client_kexinit, server_kexinit); | ||
1450 | break; | ||
1451 | default: | ||
1452 | fatal("Unsupported key exchange %d", kex->kex_type); | ||
1453 | } | ||
1454 | |||
1455 | debug("send SSH2_MSG_NEWKEYS."); | ||
1456 | packet_start(SSH2_MSG_NEWKEYS); | ||
1457 | packet_send(); | ||
1458 | packet_write_wait(); | ||
1459 | debug("done: send SSH2_MSG_NEWKEYS."); | ||
1460 | 1433 | ||
1461 | debug("Wait SSH2_MSG_NEWKEYS."); | 1434 | /* start key exchange */ |
1462 | packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS); | 1435 | dispatch_run(DISPATCH_BLOCK, &kex->newkeys, kex); |
1463 | debug("GOT SSH2_MSG_NEWKEYS."); | ||
1464 | 1436 | ||
1465 | #ifdef DEBUG_KEXDH | 1437 | #ifdef DEBUG_KEXDH |
1466 | /* send 1st encrypted/maced/compressed message */ | 1438 | /* send 1st encrypted/maced/compressed message */ |
@@ -1469,316 +1441,5 @@ do_ssh2_kex(void) | |||
1469 | packet_send(); | 1441 | packet_send(); |
1470 | packet_write_wait(); | 1442 | packet_write_wait(); |
1471 | #endif | 1443 | #endif |
1472 | 1444 | debug("KEX done"); | |
1473 | debug("done: KEX2."); | ||
1474 | } | ||
1475 | |||
1476 | /* | ||
1477 | * SSH2 key exchange | ||
1478 | */ | ||
1479 | |||
1480 | /* diffie-hellman-group1-sha1 */ | ||
1481 | |||
1482 | void | ||
1483 | ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) | ||
1484 | { | ||
1485 | #ifdef DEBUG_KEXDH | ||
1486 | int i; | ||
1487 | #endif | ||
1488 | int payload_len, dlen; | ||
1489 | int slen; | ||
1490 | u_char *signature = NULL; | ||
1491 | u_char *server_host_key_blob = NULL; | ||
1492 | u_int sbloblen; | ||
1493 | u_int klen, kout; | ||
1494 | u_char *kbuf; | ||
1495 | u_char *hash; | ||
1496 | BIGNUM *shared_secret = 0; | ||
1497 | DH *dh; | ||
1498 | BIGNUM *dh_client_pub = 0; | ||
1499 | Key *hostkey; | ||
1500 | |||
1501 | hostkey = get_hostkey_by_type(kex->hostkey_type); | ||
1502 | if (hostkey == NULL) | ||
1503 | fatal("Unsupported hostkey type %d", kex->hostkey_type); | ||
1504 | |||
1505 | /* KEXDH */ | ||
1506 | /* generate DH key */ | ||
1507 | dh = dh_new_group1(); /* XXX depends on 'kex' */ | ||
1508 | dh_gen_key(dh, kex->we_need * 8); | ||
1509 | |||
1510 | debug("Wait SSH2_MSG_KEXDH_INIT."); | ||
1511 | packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT); | ||
1512 | |||
1513 | /* key, cert */ | ||
1514 | dh_client_pub = BN_new(); | ||
1515 | if (dh_client_pub == NULL) | ||
1516 | fatal("dh_client_pub == NULL"); | ||
1517 | packet_get_bignum2(dh_client_pub, &dlen); | ||
1518 | |||
1519 | #ifdef DEBUG_KEXDH | ||
1520 | fprintf(stderr, "\ndh_client_pub= "); | ||
1521 | BN_print_fp(stderr, dh_client_pub); | ||
1522 | fprintf(stderr, "\n"); | ||
1523 | debug("bits %d", BN_num_bits(dh_client_pub)); | ||
1524 | #endif | ||
1525 | |||
1526 | #ifdef DEBUG_KEXDH | ||
1527 | fprintf(stderr, "\np= "); | ||
1528 | BN_print_fp(stderr, dh->p); | ||
1529 | fprintf(stderr, "\ng= "); | ||
1530 | bn_print(dh->g); | ||
1531 | fprintf(stderr, "\npub= "); | ||
1532 | BN_print_fp(stderr, dh->pub_key); | ||
1533 | fprintf(stderr, "\n"); | ||
1534 | DHparams_print_fp(stderr, dh); | ||
1535 | #endif | ||
1536 | if (!dh_pub_is_valid(dh, dh_client_pub)) | ||
1537 | packet_disconnect("bad client public DH value"); | ||
1538 | |||
1539 | klen = DH_size(dh); | ||
1540 | kbuf = xmalloc(klen); | ||
1541 | kout = DH_compute_key(kbuf, dh_client_pub, dh); | ||
1542 | |||
1543 | #ifdef DEBUG_KEXDH | ||
1544 | debug("shared secret: len %d/%d", klen, kout); | ||
1545 | fprintf(stderr, "shared secret == "); | ||
1546 | for (i = 0; i< kout; i++) | ||
1547 | fprintf(stderr, "%02x", (kbuf[i])&0xff); | ||
1548 | fprintf(stderr, "\n"); | ||
1549 | #endif | ||
1550 | shared_secret = BN_new(); | ||
1551 | |||
1552 | BN_bin2bn(kbuf, kout, shared_secret); | ||
1553 | memset(kbuf, 0, klen); | ||
1554 | xfree(kbuf); | ||
1555 | |||
1556 | /* XXX precompute? */ | ||
1557 | key_to_blob(hostkey, &server_host_key_blob, &sbloblen); | ||
1558 | |||
1559 | /* calc H */ /* XXX depends on 'kex' */ | ||
1560 | hash = kex_hash( | ||
1561 | client_version_string, | ||
1562 | server_version_string, | ||
1563 | buffer_ptr(client_kexinit), buffer_len(client_kexinit), | ||
1564 | buffer_ptr(server_kexinit), buffer_len(server_kexinit), | ||
1565 | (char *)server_host_key_blob, sbloblen, | ||
1566 | dh_client_pub, | ||
1567 | dh->pub_key, | ||
1568 | shared_secret | ||
1569 | ); | ||
1570 | buffer_free(client_kexinit); | ||
1571 | buffer_free(server_kexinit); | ||
1572 | xfree(client_kexinit); | ||
1573 | xfree(server_kexinit); | ||
1574 | BN_free(dh_client_pub); | ||
1575 | #ifdef DEBUG_KEXDH | ||
1576 | fprintf(stderr, "hash == "); | ||
1577 | for (i = 0; i< 20; i++) | ||
1578 | fprintf(stderr, "%02x", (hash[i])&0xff); | ||
1579 | fprintf(stderr, "\n"); | ||
1580 | #endif | ||
1581 | /* save session id := H */ | ||
1582 | /* XXX hashlen depends on KEX */ | ||
1583 | session_id2_len = 20; | ||
1584 | session_id2 = xmalloc(session_id2_len); | ||
1585 | memcpy(session_id2, hash, session_id2_len); | ||
1586 | |||
1587 | /* sign H */ | ||
1588 | /* XXX hashlen depends on KEX */ | ||
1589 | key_sign(hostkey, &signature, &slen, hash, 20); | ||
1590 | |||
1591 | destroy_sensitive_data(); | ||
1592 | |||
1593 | /* send server hostkey, DH pubkey 'f' and singed H */ | ||
1594 | packet_start(SSH2_MSG_KEXDH_REPLY); | ||
1595 | packet_put_string((char *)server_host_key_blob, sbloblen); | ||
1596 | packet_put_bignum2(dh->pub_key); /* f */ | ||
1597 | packet_put_string((char *)signature, slen); | ||
1598 | packet_send(); | ||
1599 | xfree(signature); | ||
1600 | xfree(server_host_key_blob); | ||
1601 | packet_write_wait(); | ||
1602 | |||
1603 | kex_derive_keys(kex, hash, shared_secret); | ||
1604 | BN_clear_free(shared_secret); | ||
1605 | packet_set_kex(kex); | ||
1606 | |||
1607 | /* have keys, free DH */ | ||
1608 | DH_free(dh); | ||
1609 | } | ||
1610 | |||
1611 | /* diffie-hellman-group-exchange-sha1 */ | ||
1612 | |||
1613 | void | ||
1614 | ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) | ||
1615 | { | ||
1616 | #ifdef DEBUG_KEXDH | ||
1617 | int i; | ||
1618 | #endif | ||
1619 | int payload_len, dlen; | ||
1620 | int slen, nbits, type, min, max; | ||
1621 | u_char *signature = NULL; | ||
1622 | u_char *server_host_key_blob = NULL; | ||
1623 | u_int sbloblen; | ||
1624 | u_int klen, kout; | ||
1625 | u_char *kbuf; | ||
1626 | u_char *hash; | ||
1627 | BIGNUM *shared_secret = 0; | ||
1628 | DH *dh; | ||
1629 | BIGNUM *dh_client_pub = 0; | ||
1630 | Key *hostkey; | ||
1631 | |||
1632 | hostkey = get_hostkey_by_type(kex->hostkey_type); | ||
1633 | if (hostkey == NULL) | ||
1634 | fatal("Unsupported hostkey type %d", kex->hostkey_type); | ||
1635 | |||
1636 | /* KEXDHGEX */ | ||
1637 | debug("Wait SSH2_MSG_KEX_DH_GEX_REQUEST."); | ||
1638 | type = packet_read(&payload_len); | ||
1639 | if (type != SSH2_MSG_KEX_DH_GEX_REQUEST_OLD && | ||
1640 | type != SSH2_MSG_KEX_DH_GEX_REQUEST) | ||
1641 | packet_disconnect("Protocol error: expected type %d or %d, got %d", | ||
1642 | SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, | ||
1643 | SSH2_MSG_KEX_DH_GEX_REQUEST, | ||
1644 | type); | ||
1645 | if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) { | ||
1646 | nbits = packet_get_int(); | ||
1647 | min = DH_GRP_MIN; | ||
1648 | max = DH_GRP_MAX; | ||
1649 | } else { | ||
1650 | min = packet_get_int(); | ||
1651 | nbits = packet_get_int(); | ||
1652 | max = packet_get_int(); | ||
1653 | |||
1654 | min = MAX(DH_GRP_MIN, min); | ||
1655 | max = MIN(DH_GRP_MAX, max); | ||
1656 | } | ||
1657 | |||
1658 | if (max < min || nbits < min || max < nbits) | ||
1659 | fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", | ||
1660 | min, nbits, max); | ||
1661 | |||
1662 | dh = choose_dh(min, nbits, max); | ||
1663 | if (dh == NULL) | ||
1664 | packet_disconnect("Protocol error: no matching DH grp found"); | ||
1665 | |||
1666 | debug("Sending SSH2_MSG_KEX_DH_GEX_GROUP."); | ||
1667 | packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); | ||
1668 | packet_put_bignum2(dh->p); | ||
1669 | packet_put_bignum2(dh->g); | ||
1670 | packet_send(); | ||
1671 | packet_write_wait(); | ||
1672 | |||
1673 | /* Compute our exchange value in parallel with the client */ | ||
1674 | |||
1675 | dh_gen_key(dh, kex->we_need * 8); | ||
1676 | |||
1677 | debug("Wait SSH2_MSG_KEX_DH_GEX_INIT."); | ||
1678 | packet_read_expect(&payload_len, SSH2_MSG_KEX_DH_GEX_INIT); | ||
1679 | |||
1680 | /* key, cert */ | ||
1681 | dh_client_pub = BN_new(); | ||
1682 | if (dh_client_pub == NULL) | ||
1683 | fatal("dh_client_pub == NULL"); | ||
1684 | packet_get_bignum2(dh_client_pub, &dlen); | ||
1685 | |||
1686 | #ifdef DEBUG_KEXDH | ||
1687 | fprintf(stderr, "\ndh_client_pub= "); | ||
1688 | BN_print_fp(stderr, dh_client_pub); | ||
1689 | fprintf(stderr, "\n"); | ||
1690 | debug("bits %d", BN_num_bits(dh_client_pub)); | ||
1691 | #endif | ||
1692 | |||
1693 | #ifdef DEBUG_KEXDH | ||
1694 | fprintf(stderr, "\np= "); | ||
1695 | BN_print_fp(stderr, dh->p); | ||
1696 | fprintf(stderr, "\ng= "); | ||
1697 | bn_print(dh->g); | ||
1698 | fprintf(stderr, "\npub= "); | ||
1699 | BN_print_fp(stderr, dh->pub_key); | ||
1700 | fprintf(stderr, "\n"); | ||
1701 | DHparams_print_fp(stderr, dh); | ||
1702 | #endif | ||
1703 | if (!dh_pub_is_valid(dh, dh_client_pub)) | ||
1704 | packet_disconnect("bad client public DH value"); | ||
1705 | |||
1706 | klen = DH_size(dh); | ||
1707 | kbuf = xmalloc(klen); | ||
1708 | kout = DH_compute_key(kbuf, dh_client_pub, dh); | ||
1709 | |||
1710 | #ifdef DEBUG_KEXDH | ||
1711 | debug("shared secret: len %d/%d", klen, kout); | ||
1712 | fprintf(stderr, "shared secret == "); | ||
1713 | for (i = 0; i< kout; i++) | ||
1714 | fprintf(stderr, "%02x", (kbuf[i])&0xff); | ||
1715 | fprintf(stderr, "\n"); | ||
1716 | #endif | ||
1717 | shared_secret = BN_new(); | ||
1718 | |||
1719 | BN_bin2bn(kbuf, kout, shared_secret); | ||
1720 | memset(kbuf, 0, klen); | ||
1721 | xfree(kbuf); | ||
1722 | |||
1723 | /* XXX precompute? */ | ||
1724 | key_to_blob(hostkey, &server_host_key_blob, &sbloblen); | ||
1725 | |||
1726 | if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) { | ||
1727 | /* These values are not included in the hash */ | ||
1728 | min = -1; | ||
1729 | max = -1; | ||
1730 | } | ||
1731 | |||
1732 | /* calc H */ /* XXX depends on 'kex' */ | ||
1733 | hash = kex_hash_gex( | ||
1734 | client_version_string, | ||
1735 | server_version_string, | ||
1736 | buffer_ptr(client_kexinit), buffer_len(client_kexinit), | ||
1737 | buffer_ptr(server_kexinit), buffer_len(server_kexinit), | ||
1738 | (char *)server_host_key_blob, sbloblen, | ||
1739 | min, nbits, max, | ||
1740 | dh->p, dh->g, | ||
1741 | dh_client_pub, | ||
1742 | dh->pub_key, | ||
1743 | shared_secret | ||
1744 | ); | ||
1745 | buffer_free(client_kexinit); | ||
1746 | buffer_free(server_kexinit); | ||
1747 | xfree(client_kexinit); | ||
1748 | xfree(server_kexinit); | ||
1749 | BN_free(dh_client_pub); | ||
1750 | #ifdef DEBUG_KEXDH | ||
1751 | fprintf(stderr, "hash == "); | ||
1752 | for (i = 0; i< 20; i++) | ||
1753 | fprintf(stderr, "%02x", (hash[i])&0xff); | ||
1754 | fprintf(stderr, "\n"); | ||
1755 | #endif | ||
1756 | /* save session id := H */ | ||
1757 | /* XXX hashlen depends on KEX */ | ||
1758 | session_id2_len = 20; | ||
1759 | session_id2 = xmalloc(session_id2_len); | ||
1760 | memcpy(session_id2, hash, session_id2_len); | ||
1761 | |||
1762 | /* sign H */ | ||
1763 | /* XXX hashlen depends on KEX */ | ||
1764 | key_sign(hostkey, &signature, &slen, hash, 20); | ||
1765 | |||
1766 | destroy_sensitive_data(); | ||
1767 | |||
1768 | /* send server hostkey, DH pubkey 'f' and singed H */ | ||
1769 | packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); | ||
1770 | packet_put_string((char *)server_host_key_blob, sbloblen); | ||
1771 | packet_put_bignum2(dh->pub_key); /* f */ | ||
1772 | packet_put_string((char *)signature, slen); | ||
1773 | packet_send(); | ||
1774 | xfree(signature); | ||
1775 | xfree(server_host_key_blob); | ||
1776 | packet_write_wait(); | ||
1777 | |||
1778 | kex_derive_keys(kex, hash, shared_secret); | ||
1779 | BN_clear_free(shared_secret); | ||
1780 | packet_set_kex(kex); | ||
1781 | |||
1782 | /* have keys, free DH */ | ||
1783 | DH_free(dh); | ||
1784 | } | 1445 | } |