diff options
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 117 |
1 files changed, 104 insertions, 13 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.372 2010/01/29 00:20:41 djm Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.373 2010/02/26 20:29:54 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -205,6 +205,7 @@ struct { | |||
205 | Key *server_key; /* ephemeral server key */ | 205 | Key *server_key; /* ephemeral server key */ |
206 | Key *ssh1_host_key; /* ssh1 host key */ | 206 | Key *ssh1_host_key; /* ssh1 host key */ |
207 | Key **host_keys; /* all private host keys */ | 207 | Key **host_keys; /* all private host keys */ |
208 | Key **host_certificates; /* all public host certificates */ | ||
208 | int have_ssh1_key; | 209 | int have_ssh1_key; |
209 | int have_ssh2_key; | 210 | int have_ssh2_key; |
210 | u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; | 211 | u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; |
@@ -545,6 +546,10 @@ destroy_sensitive_data(void) | |||
545 | key_free(sensitive_data.host_keys[i]); | 546 | key_free(sensitive_data.host_keys[i]); |
546 | sensitive_data.host_keys[i] = NULL; | 547 | sensitive_data.host_keys[i] = NULL; |
547 | } | 548 | } |
549 | if (sensitive_data.host_certificates[i]) { | ||
550 | key_free(sensitive_data.host_certificates[i]); | ||
551 | sensitive_data.host_certificates[i] = NULL; | ||
552 | } | ||
548 | } | 553 | } |
549 | sensitive_data.ssh1_host_key = NULL; | 554 | sensitive_data.ssh1_host_key = NULL; |
550 | memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); | 555 | memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); |
@@ -571,6 +576,7 @@ demote_sensitive_data(void) | |||
571 | if (tmp->type == KEY_RSA1) | 576 | if (tmp->type == KEY_RSA1) |
572 | sensitive_data.ssh1_host_key = tmp; | 577 | sensitive_data.ssh1_host_key = tmp; |
573 | } | 578 | } |
579 | /* Certs do not need demotion */ | ||
574 | } | 580 | } |
575 | 581 | ||
576 | /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ | 582 | /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ |
@@ -717,10 +723,11 @@ list_hostkey_types(void) | |||
717 | const char *p; | 723 | const char *p; |
718 | char *ret; | 724 | char *ret; |
719 | int i; | 725 | int i; |
726 | Key *key; | ||
720 | 727 | ||
721 | buffer_init(&b); | 728 | buffer_init(&b); |
722 | for (i = 0; i < options.num_host_key_files; i++) { | 729 | for (i = 0; i < options.num_host_key_files; i++) { |
723 | Key *key = sensitive_data.host_keys[i]; | 730 | key = sensitive_data.host_keys[i]; |
724 | if (key == NULL) | 731 | if (key == NULL) |
725 | continue; | 732 | continue; |
726 | switch (key->type) { | 733 | switch (key->type) { |
@@ -732,6 +739,19 @@ list_hostkey_types(void) | |||
732 | buffer_append(&b, p, strlen(p)); | 739 | buffer_append(&b, p, strlen(p)); |
733 | break; | 740 | break; |
734 | } | 741 | } |
742 | /* If the private key has a cert peer, then list that too */ | ||
743 | key = sensitive_data.host_certificates[i]; | ||
744 | if (key == NULL) | ||
745 | continue; | ||
746 | switch (key->type) { | ||
747 | case KEY_RSA_CERT: | ||
748 | case KEY_DSA_CERT: | ||
749 | if (buffer_len(&b) > 0) | ||
750 | buffer_append(&b, ",", 1); | ||
751 | p = key_ssh_name(key); | ||
752 | buffer_append(&b, p, strlen(p)); | ||
753 | break; | ||
754 | } | ||
735 | } | 755 | } |
736 | buffer_append(&b, "\0", 1); | 756 | buffer_append(&b, "\0", 1); |
737 | ret = xstrdup(buffer_ptr(&b)); | 757 | ret = xstrdup(buffer_ptr(&b)); |
@@ -740,20 +760,37 @@ list_hostkey_types(void) | |||
740 | return ret; | 760 | return ret; |
741 | } | 761 | } |
742 | 762 | ||
743 | Key * | 763 | static Key * |
744 | get_hostkey_by_type(int type) | 764 | get_hostkey_by_type(int type, int need_private) |
745 | { | 765 | { |
746 | int i; | 766 | int i; |
767 | Key *key; | ||
747 | 768 | ||
748 | for (i = 0; i < options.num_host_key_files; i++) { | 769 | for (i = 0; i < options.num_host_key_files; i++) { |
749 | Key *key = sensitive_data.host_keys[i]; | 770 | if (type == KEY_RSA_CERT || type == KEY_DSA_CERT) |
771 | key = sensitive_data.host_certificates[i]; | ||
772 | else | ||
773 | key = sensitive_data.host_keys[i]; | ||
750 | if (key != NULL && key->type == type) | 774 | if (key != NULL && key->type == type) |
751 | return key; | 775 | return need_private ? |
776 | sensitive_data.host_keys[i] : key; | ||
752 | } | 777 | } |
753 | return NULL; | 778 | return NULL; |
754 | } | 779 | } |
755 | 780 | ||
756 | Key * | 781 | Key * |
782 | get_hostkey_public_by_type(int type) | ||
783 | { | ||
784 | return get_hostkey_by_type(type, 0); | ||
785 | } | ||
786 | |||
787 | Key * | ||
788 | get_hostkey_private_by_type(int type) | ||
789 | { | ||
790 | return get_hostkey_by_type(type, 1); | ||
791 | } | ||
792 | |||
793 | Key * | ||
757 | get_hostkey_by_index(int ind) | 794 | get_hostkey_by_index(int ind) |
758 | { | 795 | { |
759 | if (ind < 0 || ind >= options.num_host_key_files) | 796 | if (ind < 0 || ind >= options.num_host_key_files) |
@@ -767,8 +804,13 @@ get_hostkey_index(Key *key) | |||
767 | int i; | 804 | int i; |
768 | 805 | ||
769 | for (i = 0; i < options.num_host_key_files; i++) { | 806 | for (i = 0; i < options.num_host_key_files; i++) { |
770 | if (key == sensitive_data.host_keys[i]) | 807 | if (key_is_cert(key)) { |
771 | return (i); | 808 | if (key == sensitive_data.host_certificates[i]) |
809 | return (i); | ||
810 | } else { | ||
811 | if (key == sensitive_data.host_keys[i]) | ||
812 | return (i); | ||
813 | } | ||
772 | } | 814 | } |
773 | return (-1); | 815 | return (-1); |
774 | } | 816 | } |
@@ -807,9 +849,9 @@ usage(void) | |||
807 | fprintf(stderr, "%s, %s\n", | 849 | fprintf(stderr, "%s, %s\n", |
808 | SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); | 850 | SSH_RELEASE, SSLeay_version(SSLEAY_VERSION)); |
809 | fprintf(stderr, | 851 | fprintf(stderr, |
810 | "usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-f config_file]\n" | 852 | "usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n" |
811 | " [-g login_grace_time] [-h host_key_file] [-k key_gen_time]\n" | 853 | " [-f config_file] [-g login_grace_time] [-h host_key_file]\n" |
812 | " [-o option] [-p port] [-u len]\n" | 854 | " [-k key_gen_time] [-o option] [-p port] [-u len]\n" |
813 | ); | 855 | ); |
814 | exit(1); | 856 | exit(1); |
815 | } | 857 | } |
@@ -1236,7 +1278,7 @@ main(int ac, char **av) | |||
1236 | { | 1278 | { |
1237 | extern char *optarg; | 1279 | extern char *optarg; |
1238 | extern int optind; | 1280 | extern int optind; |
1239 | int opt, i, on = 1; | 1281 | int opt, i, j, on = 1; |
1240 | int sock_in = -1, sock_out = -1, newsock = -1; | 1282 | int sock_in = -1, sock_out = -1, newsock = -1; |
1241 | const char *remote_ip; | 1283 | const char *remote_ip; |
1242 | char *test_user = NULL, *test_host = NULL, *test_addr = NULL; | 1284 | char *test_user = NULL, *test_host = NULL, *test_addr = NULL; |
@@ -1289,6 +1331,14 @@ main(int ac, char **av) | |||
1289 | case 'f': | 1331 | case 'f': |
1290 | config_file_name = optarg; | 1332 | config_file_name = optarg; |
1291 | break; | 1333 | break; |
1334 | case 'c': | ||
1335 | if (options.num_host_cert_files >= MAX_HOSTCERTS) { | ||
1336 | fprintf(stderr, "too many host certificates.\n"); | ||
1337 | exit(1); | ||
1338 | } | ||
1339 | options.host_cert_files[options.num_host_cert_files++] = | ||
1340 | derelativise_path(optarg); | ||
1341 | break; | ||
1292 | case 'd': | 1342 | case 'd': |
1293 | if (debug_flag == 0) { | 1343 | if (debug_flag == 0) { |
1294 | debug_flag = 1; | 1344 | debug_flag = 1; |
@@ -1536,6 +1586,46 @@ main(int ac, char **av) | |||
1536 | exit(1); | 1586 | exit(1); |
1537 | } | 1587 | } |
1538 | 1588 | ||
1589 | /* | ||
1590 | * Load certificates. They are stored in an array at identical | ||
1591 | * indices to the public keys that they relate to. | ||
1592 | */ | ||
1593 | sensitive_data.host_certificates = xcalloc(options.num_host_key_files, | ||
1594 | sizeof(Key *)); | ||
1595 | for (i = 0; i < options.num_host_key_files; i++) | ||
1596 | sensitive_data.host_certificates[i] = NULL; | ||
1597 | |||
1598 | for (i = 0; i < options.num_host_cert_files; i++) { | ||
1599 | key = key_load_public(options.host_cert_files[i], NULL); | ||
1600 | if (key == NULL) { | ||
1601 | error("Could not load host certificate: %s", | ||
1602 | options.host_cert_files[i]); | ||
1603 | continue; | ||
1604 | } | ||
1605 | if (!key_is_cert(key)) { | ||
1606 | error("Certificate file is not a certificate: %s", | ||
1607 | options.host_cert_files[i]); | ||
1608 | key_free(key); | ||
1609 | continue; | ||
1610 | } | ||
1611 | /* Find matching private key */ | ||
1612 | for (j = 0; j < options.num_host_key_files; j++) { | ||
1613 | if (key_equal_public(key, | ||
1614 | sensitive_data.host_keys[j])) { | ||
1615 | sensitive_data.host_certificates[j] = key; | ||
1616 | break; | ||
1617 | } | ||
1618 | } | ||
1619 | if (j >= options.num_host_key_files) { | ||
1620 | error("No matching private key for certificate: %s", | ||
1621 | options.host_cert_files[i]); | ||
1622 | key_free(key); | ||
1623 | continue; | ||
1624 | } | ||
1625 | sensitive_data.host_certificates[j] = key; | ||
1626 | debug("host certificate: #%d type %d %s", j, key->type, | ||
1627 | key_type(key)); | ||
1628 | } | ||
1539 | /* Check certain values for sanity. */ | 1629 | /* Check certain values for sanity. */ |
1540 | if (options.protocol & SSH_PROTO_1) { | 1630 | if (options.protocol & SSH_PROTO_1) { |
1541 | if (options.server_key_bits < 512 || | 1631 | if (options.server_key_bits < 512 || |
@@ -2205,7 +2295,8 @@ do_ssh2_kex(void) | |||
2205 | kex->server = 1; | 2295 | kex->server = 1; |
2206 | kex->client_version_string=client_version_string; | 2296 | kex->client_version_string=client_version_string; |
2207 | kex->server_version_string=server_version_string; | 2297 | kex->server_version_string=server_version_string; |
2208 | kex->load_host_key=&get_hostkey_by_type; | 2298 | kex->load_host_public_key=&get_hostkey_public_by_type; |
2299 | kex->load_host_private_key=&get_hostkey_private_by_type; | ||
2209 | kex->host_key_index=&get_hostkey_index; | 2300 | kex->host_key_index=&get_hostkey_index; |
2210 | 2301 | ||
2211 | xxx_kex = kex; | 2302 | xxx_kex = kex; |