diff options
author | djm@openbsd.org <djm@openbsd.org> | 2014-12-04 02:24:32 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2014-12-05 09:29:47 +1100 |
commit | 5e39a49930d885aac9c76af3129332b6e772cd75 (patch) | |
tree | 0d3613d35ba5478ff9f7889cc1912a70ee3b2e32 | |
parent | 74de254bb92c684cf53461da97f52d5ba34ded80 (diff) |
upstream commit
add RevokedHostKeys option for the client
Allow textfile or KRL-based revocation of hostkeys.
-rw-r--r-- | auth.c | 62 | ||||
-rw-r--r-- | auth2-pubkey.c | 6 | ||||
-rw-r--r-- | authfile.c | 58 | ||||
-rw-r--r-- | authfile.h | 5 | ||||
-rw-r--r-- | readconf.c | 12 | ||||
-rw-r--r-- | readconf.h | 4 | ||||
-rw-r--r-- | ssh_config.5 | 14 | ||||
-rw-r--r-- | sshconnect.c | 64 |
8 files changed, 155 insertions, 70 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.c,v 1.106 2014/07/15 15:54:14 millert Exp $ */ | 1 | /* $OpenBSD: auth.c,v 1.107 2014/12/04 02:24:32 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -71,7 +71,8 @@ | |||
71 | #endif | 71 | #endif |
72 | #include "authfile.h" | 72 | #include "authfile.h" |
73 | #include "monitor_wrap.h" | 73 | #include "monitor_wrap.h" |
74 | #include "krl.h" | 74 | #include "authfile.h" |
75 | #include "ssherr.h" | ||
75 | #include "compat.h" | 76 | #include "compat.h" |
76 | 77 | ||
77 | /* import */ | 78 | /* import */ |
@@ -673,43 +674,38 @@ getpwnamallow(const char *user) | |||
673 | int | 674 | int |
674 | auth_key_is_revoked(Key *key) | 675 | auth_key_is_revoked(Key *key) |
675 | { | 676 | { |
676 | #ifdef WITH_OPENSSL | 677 | char *fp = NULL; |
677 | char *key_fp; | 678 | int r; |
678 | 679 | ||
679 | if (options.revoked_keys_file == NULL) | 680 | if (options.revoked_keys_file == NULL) |
680 | return 0; | 681 | return 0; |
681 | switch (ssh_krl_file_contains_key(options.revoked_keys_file, key)) { | 682 | if ((fp = sshkey_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX)) == NULL) { |
682 | case 0: | 683 | r = SSH_ERR_ALLOC_FAIL; |
683 | return 0; /* Not revoked */ | 684 | error("%s: fingerprint key: %s", __func__, ssh_err(r)); |
684 | case -2: | 685 | goto out; |
685 | break; /* Not a KRL */ | ||
686 | default: | ||
687 | goto revoked; | ||
688 | } | 686 | } |
689 | #endif | 687 | |
690 | debug3("%s: treating %s as a key list", __func__, | 688 | r = sshkey_check_revoked(key, options.revoked_keys_file); |
691 | options.revoked_keys_file); | 689 | switch (r) { |
692 | switch (key_in_file(key, options.revoked_keys_file, 0)) { | ||
693 | case 0: | 690 | case 0: |
694 | /* key not revoked */ | 691 | break; /* not revoked */ |
695 | return 0; | 692 | case SSH_ERR_KEY_REVOKED: |
696 | case -1: | 693 | error("Authentication key %s %s revoked by file %s", |
697 | /* Error opening revoked_keys_file: refuse all keys */ | 694 | sshkey_type(key), fp, options.revoked_keys_file); |
698 | error("Revoked keys file is unreadable: refusing public key " | 695 | goto out; |
699 | "authentication"); | 696 | default: |
700 | return 1; | 697 | error("Error checking authentication key %s %s in " |
701 | #ifdef WITH_OPENSSL | 698 | "revoked keys file %s: %s", sshkey_type(key), fp, |
702 | case 1: | 699 | options.revoked_keys_file, ssh_err(r)); |
703 | revoked: | 700 | goto out; |
704 | /* Key revoked */ | ||
705 | key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); | ||
706 | error("WARNING: authentication attempt with a revoked " | ||
707 | "%s key %s ", key_type(key), key_fp); | ||
708 | free(key_fp); | ||
709 | return 1; | ||
710 | #endif | ||
711 | } | 701 | } |
712 | fatal("key_in_file returned junk"); | 702 | |
703 | /* Success */ | ||
704 | r = 0; | ||
705 | |||
706 | out: | ||
707 | free(fp); | ||
708 | return r == 0 ? 0 : 1; | ||
713 | } | 709 | } |
714 | 710 | ||
715 | void | 711 | void |
diff --git a/auth2-pubkey.c b/auth2-pubkey.c index f3ca96592..0a3c1deee 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-pubkey.c,v 1.41 2014/07/15 15:54:14 millert Exp $ */ | 1 | /* $OpenBSD: auth2-pubkey.c,v 1.42 2014/12/04 02:24:32 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -434,8 +434,8 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | |||
434 | ca_fp = key_fingerprint(key->cert->signature_key, | 434 | ca_fp = key_fingerprint(key->cert->signature_key, |
435 | SSH_FP_MD5, SSH_FP_HEX); | 435 | SSH_FP_MD5, SSH_FP_HEX); |
436 | 436 | ||
437 | if (key_in_file(key->cert->signature_key, | 437 | if (sshkey_in_file(key->cert->signature_key, |
438 | options.trusted_user_ca_keys, 1) != 1) { | 438 | options.trusted_user_ca_keys, 1, 0) != 0) { |
439 | debug2("%s: CA %s %s is not listed in %s", __func__, | 439 | debug2("%s: CA %s %s is not listed in %s", __func__, |
440 | key_type(key->cert->signature_key), ca_fp, | 440 | key_type(key->cert->signature_key), ca_fp, |
441 | options.trusted_user_ca_keys); | 441 | options.trusted_user_ca_keys); |
diff --git a/authfile.c b/authfile.c index e93d86738..95877e159 100644 --- a/authfile.c +++ b/authfile.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: authfile.c,v 1.107 2014/06/24 01:13:21 djm Exp $ */ | 1 | /* $OpenBSD: authfile.c,v 1.108 2014/12/04 02:24:32 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -48,6 +48,7 @@ | |||
48 | #include "atomicio.h" | 48 | #include "atomicio.h" |
49 | #include "sshbuf.h" | 49 | #include "sshbuf.h" |
50 | #include "ssherr.h" | 50 | #include "ssherr.h" |
51 | #include "krl.h" | ||
51 | 52 | ||
52 | #define MAX_KEY_FILE_SIZE (1024 * 1024) | 53 | #define MAX_KEY_FILE_SIZE (1024 * 1024) |
53 | 54 | ||
@@ -494,11 +495,14 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase, | |||
494 | /* | 495 | /* |
495 | * Returns success if the specified "key" is listed in the file "filename", | 496 | * Returns success if the specified "key" is listed in the file "filename", |
496 | * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error. | 497 | * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error. |
497 | * If strict_type is set then the key type must match exactly, | 498 | * If "strict_type" is set then the key type must match exactly, |
498 | * otherwise a comparison that ignores certficiate data is performed. | 499 | * otherwise a comparison that ignores certficiate data is performed. |
500 | * If "check_ca" is set and "key" is a certificate, then its CA key is | ||
501 | * also checked and sshkey_in_file() will return success if either is found. | ||
499 | */ | 502 | */ |
500 | int | 503 | int |
501 | sshkey_in_file(struct sshkey *key, const char *filename, int strict_type) | 504 | sshkey_in_file(struct sshkey *key, const char *filename, int strict_type, |
505 | int check_ca) | ||
502 | { | 506 | { |
503 | FILE *f; | 507 | FILE *f; |
504 | char line[SSH_MAX_PUBKEY_BYTES]; | 508 | char line[SSH_MAX_PUBKEY_BYTES]; |
@@ -509,12 +513,8 @@ sshkey_in_file(struct sshkey *key, const char *filename, int strict_type) | |||
509 | int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) = | 513 | int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) = |
510 | strict_type ? sshkey_equal : sshkey_equal_public; | 514 | strict_type ? sshkey_equal : sshkey_equal_public; |
511 | 515 | ||
512 | if ((f = fopen(filename, "r")) == NULL) { | 516 | if ((f = fopen(filename, "r")) == NULL) |
513 | if (errno == ENOENT) | 517 | return SSH_ERR_SYSTEM_ERROR; |
514 | return SSH_ERR_KEY_NOT_FOUND; | ||
515 | else | ||
516 | return SSH_ERR_SYSTEM_ERROR; | ||
517 | } | ||
518 | 518 | ||
519 | while (read_keyfile_line(f, filename, line, sizeof(line), | 519 | while (read_keyfile_line(f, filename, line, sizeof(line), |
520 | &linenum) != -1) { | 520 | &linenum) != -1) { |
@@ -538,7 +538,9 @@ sshkey_in_file(struct sshkey *key, const char *filename, int strict_type) | |||
538 | } | 538 | } |
539 | if ((r = sshkey_read(pub, &cp)) != 0) | 539 | if ((r = sshkey_read(pub, &cp)) != 0) |
540 | goto out; | 540 | goto out; |
541 | if (sshkey_compare(key, pub)) { | 541 | if (sshkey_compare(key, pub) || |
542 | (check_ca && sshkey_is_cert(key) && | ||
543 | sshkey_compare(key->cert->signature_key, pub))) { | ||
542 | r = 0; | 544 | r = 0; |
543 | goto out; | 545 | goto out; |
544 | } | 546 | } |
@@ -553,3 +555,39 @@ sshkey_in_file(struct sshkey *key, const char *filename, int strict_type) | |||
553 | return r; | 555 | return r; |
554 | } | 556 | } |
555 | 557 | ||
558 | /* | ||
559 | * Checks whether the specified key is revoked, returning 0 if not, | ||
560 | * SSH_ERR_KEY_REVOKED if it is or another error code if something | ||
561 | * unexpected happened. | ||
562 | * This will check both the key and, if it is a certificate, its CA key too. | ||
563 | * "revoked_keys_file" may be a KRL or a one-per-line list of public keys. | ||
564 | */ | ||
565 | int | ||
566 | sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file) | ||
567 | { | ||
568 | int r; | ||
569 | |||
570 | #ifdef WITH_OPENSSL | ||
571 | r = ssh_krl_file_contains_key(revoked_keys_file, key); | ||
572 | /* If this was not a KRL to begin with then continue below */ | ||
573 | if (r != SSH_ERR_KRL_BAD_MAGIC) | ||
574 | return r; | ||
575 | #endif | ||
576 | |||
577 | /* | ||
578 | * If the file is not a KRL or we can't handle KRLs then attempt to | ||
579 | * parse the file as a flat list of keys. | ||
580 | */ | ||
581 | switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) { | ||
582 | case 0: | ||
583 | /* Key found => revoked */ | ||
584 | return SSH_ERR_KEY_REVOKED; | ||
585 | case SSH_ERR_KEY_NOT_FOUND: | ||
586 | /* Key not found => not revoked */ | ||
587 | return 0; | ||
588 | default: | ||
589 | /* Some other error occurred */ | ||
590 | return r; | ||
591 | } | ||
592 | } | ||
593 | |||
diff --git a/authfile.h b/authfile.h index 03bc3958c..645404e61 100644 --- a/authfile.h +++ b/authfile.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: authfile.h,v 1.19 2014/07/03 23:18:35 djm Exp $ */ | 1 | /* $OpenBSD: authfile.h,v 1.20 2014/12/04 02:24:32 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. |
@@ -42,6 +42,7 @@ int sshkey_load_private_type(int, const char *, const char *, | |||
42 | struct sshkey **, char **, int *); | 42 | struct sshkey **, char **, int *); |
43 | int sshkey_load_private_pem(int, int, const char *, struct sshkey **, char **); | 43 | int sshkey_load_private_pem(int, int, const char *, struct sshkey **, char **); |
44 | int sshkey_perm_ok(int, const char *); | 44 | int sshkey_perm_ok(int, const char *); |
45 | int sshkey_in_file(struct sshkey *, const char *, int); | 45 | int sshkey_in_file(struct sshkey *, const char *, int, int); |
46 | int sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file); | ||
46 | 47 | ||
47 | #endif | 48 | #endif |
diff --git a/readconf.c b/readconf.c index 922c57454..e0386935f 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.c,v 1.222 2014/10/24 02:01:20 lteo Exp $ */ | 1 | /* $OpenBSD: readconf.c,v 1.223 2014/12/04 02:24:32 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 |
@@ -154,7 +154,7 @@ typedef enum { | |||
154 | oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, | 154 | oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, |
155 | oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, | 155 | oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, |
156 | oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, | 156 | oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, |
157 | oStreamLocalBindMask, oStreamLocalBindUnlink, | 157 | oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, |
158 | oIgnoredUnknownOption, oDeprecated, oUnsupported | 158 | oIgnoredUnknownOption, oDeprecated, oUnsupported |
159 | } OpCodes; | 159 | } OpCodes; |
160 | 160 | ||
@@ -269,6 +269,7 @@ static struct { | |||
269 | { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, | 269 | { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, |
270 | { "streamlocalbindmask", oStreamLocalBindMask }, | 270 | { "streamlocalbindmask", oStreamLocalBindMask }, |
271 | { "streamlocalbindunlink", oStreamLocalBindUnlink }, | 271 | { "streamlocalbindunlink", oStreamLocalBindUnlink }, |
272 | { "revokedhostkeys", oRevokedHostKeys }, | ||
272 | { "ignoreunknown", oIgnoreUnknown }, | 273 | { "ignoreunknown", oIgnoreUnknown }, |
273 | 274 | ||
274 | { NULL, oBadOption } | 275 | { NULL, oBadOption } |
@@ -1455,6 +1456,10 @@ parse_int: | |||
1455 | intptr = &options->fwd_opts.streamlocal_bind_unlink; | 1456 | intptr = &options->fwd_opts.streamlocal_bind_unlink; |
1456 | goto parse_flag; | 1457 | goto parse_flag; |
1457 | 1458 | ||
1459 | case oRevokedHostKeys: | ||
1460 | charptr = &options->revoked_host_keys; | ||
1461 | goto parse_string; | ||
1462 | |||
1458 | case oDeprecated: | 1463 | case oDeprecated: |
1459 | debug("%s line %d: Deprecated option \"%s\"", | 1464 | debug("%s line %d: Deprecated option \"%s\"", |
1460 | filename, linenum, keyword); | 1465 | filename, linenum, keyword); |
@@ -1631,6 +1636,7 @@ initialize_options(Options * options) | |||
1631 | options->canonicalize_max_dots = -1; | 1636 | options->canonicalize_max_dots = -1; |
1632 | options->canonicalize_fallback_local = -1; | 1637 | options->canonicalize_fallback_local = -1; |
1633 | options->canonicalize_hostname = -1; | 1638 | options->canonicalize_hostname = -1; |
1639 | options->revoked_host_keys = NULL; | ||
1634 | } | 1640 | } |
1635 | 1641 | ||
1636 | /* | 1642 | /* |
@@ -1818,6 +1824,7 @@ fill_default_options(Options * options) | |||
1818 | CLEAR_ON_NONE(options->local_command); | 1824 | CLEAR_ON_NONE(options->local_command); |
1819 | CLEAR_ON_NONE(options->proxy_command); | 1825 | CLEAR_ON_NONE(options->proxy_command); |
1820 | CLEAR_ON_NONE(options->control_path); | 1826 | CLEAR_ON_NONE(options->control_path); |
1827 | CLEAR_ON_NONE(options->revoked_host_keys); | ||
1821 | /* options->user will be set in the main program if appropriate */ | 1828 | /* options->user will be set in the main program if appropriate */ |
1822 | /* options->hostname will be set in the main program if appropriate */ | 1829 | /* options->hostname will be set in the main program if appropriate */ |
1823 | /* options->host_key_alias should not be set by default */ | 1830 | /* options->host_key_alias should not be set by default */ |
@@ -2251,6 +2258,7 @@ dump_client_config(Options *o, const char *host) | |||
2251 | dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); | 2258 | dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); |
2252 | dump_cfg_string(oProxyCommand, o->proxy_command); | 2259 | dump_cfg_string(oProxyCommand, o->proxy_command); |
2253 | dump_cfg_string(oXAuthLocation, o->xauth_location); | 2260 | dump_cfg_string(oXAuthLocation, o->xauth_location); |
2261 | dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); | ||
2254 | 2262 | ||
2255 | dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards); | 2263 | dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards); |
2256 | dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards); | 2264 | dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards); |
diff --git a/readconf.h b/readconf.h index 7b58d01f3..49858bff3 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.h,v 1.103 2014/10/08 22:20:25 djm Exp $ */ | 1 | /* $OpenBSD: readconf.h,v 1.104 2014/12/04 02:24:32 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -144,6 +144,8 @@ typedef struct { | |||
144 | int num_permitted_cnames; | 144 | int num_permitted_cnames; |
145 | struct allowed_cname permitted_cnames[MAX_CANON_DOMAINS]; | 145 | struct allowed_cname permitted_cnames[MAX_CANON_DOMAINS]; |
146 | 146 | ||
147 | char *revoked_host_keys; | ||
148 | |||
147 | char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ | 149 | char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ |
148 | } Options; | 150 | } Options; |
149 | 151 | ||
diff --git a/ssh_config.5 b/ssh_config.5 index d8f980b68..f0a4b293a 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: ssh_config.5,v 1.195 2014/11/10 22:25:49 djm Exp $ | 36 | .\" $OpenBSD: ssh_config.5,v 1.196 2014/12/04 02:24:32 djm Exp $ |
37 | .Dd $Mdocdate: November 10 2014 $ | 37 | .Dd $Mdocdate: December 4 2014 $ |
38 | .Dt SSH_CONFIG 5 | 38 | .Dt SSH_CONFIG 5 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -1253,6 +1253,16 @@ and | |||
1253 | .Fl T | 1253 | .Fl T |
1254 | flags for | 1254 | flags for |
1255 | .Xr ssh 1 . | 1255 | .Xr ssh 1 . |
1256 | .It Cm RevokedHostKeys | ||
1257 | Specifies revoked host public keys. | ||
1258 | Keys listed in this file will be refused for host authentication. | ||
1259 | Note that if this file does not exist or is not readable, | ||
1260 | then host authentication will be refused for all hosts. | ||
1261 | Keys may be specified as a text file, listing one public key per line, or as | ||
1262 | an OpenSSH Key Revocation List (KRL) as generated by | ||
1263 | .Xr ssh-keygen 1 . | ||
1264 | For more information on KRLs, see the KEY REVOCATION LISTS section in | ||
1265 | .Xr ssh-keygen 1 . | ||
1256 | .It Cm RhostsRSAAuthentication | 1266 | .It Cm RhostsRSAAuthentication |
1257 | Specifies whether to try rhosts based authentication with RSA host | 1267 | Specifies whether to try rhosts based authentication with RSA host |
1258 | authentication. | 1268 | authentication. |
diff --git a/sshconnect.c b/sshconnect.c index ac09eae67..f9a59372c 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect.c,v 1.251 2014/07/15 15:54:14 millert Exp $ */ | 1 | /* $OpenBSD: sshconnect.c,v 1.252 2014/12/04 02:24:32 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 |
@@ -62,6 +62,8 @@ | |||
62 | #include "monitor_fdpass.h" | 62 | #include "monitor_fdpass.h" |
63 | #include "ssh2.h" | 63 | #include "ssh2.h" |
64 | #include "version.h" | 64 | #include "version.h" |
65 | #include "authfile.h" | ||
66 | #include "ssherr.h" | ||
65 | 67 | ||
66 | char *client_version_string = NULL; | 68 | char *client_version_string = NULL; |
67 | char *server_version_string = NULL; | 69 | char *server_version_string = NULL; |
@@ -1219,16 +1221,44 @@ int | |||
1219 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | 1221 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) |
1220 | { | 1222 | { |
1221 | int r = -1, flags = 0; | 1223 | int r = -1, flags = 0; |
1222 | char *fp; | 1224 | char *fp = NULL; |
1223 | Key *plain = NULL; | 1225 | struct sshkey *plain = NULL; |
1226 | |||
1227 | if ((fp = sshkey_fingerprint(host_key, | ||
1228 | SSH_FP_MD5, SSH_FP_HEX)) == NULL) { | ||
1229 | error("%s: fingerprint host key: %s", __func__, ssh_err(r)); | ||
1230 | r = -1; | ||
1231 | goto out; | ||
1232 | } | ||
1224 | 1233 | ||
1225 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 1234 | debug("Server host key: %s %s", sshkey_type(host_key), fp); |
1226 | debug("Server host key: %s %s", key_type(host_key), fp); | ||
1227 | free(fp); | ||
1228 | 1235 | ||
1229 | if (key_equal(previous_host_key, host_key)) { | 1236 | if (sshkey_equal(previous_host_key, host_key)) { |
1230 | debug("%s: server host key matches cached key", __func__); | 1237 | debug2("%s: server host key %s %s matches cached key", |
1231 | return 0; | 1238 | __func__, sshkey_type(host_key), fp); |
1239 | r = 0; | ||
1240 | goto out; | ||
1241 | } | ||
1242 | |||
1243 | /* Check in RevokedHostKeys file if specified */ | ||
1244 | if (options.revoked_host_keys != NULL) { | ||
1245 | r = sshkey_check_revoked(host_key, options.revoked_host_keys); | ||
1246 | switch (r) { | ||
1247 | case 0: | ||
1248 | break; /* not revoked */ | ||
1249 | case SSH_ERR_KEY_REVOKED: | ||
1250 | error("Host key %s %s revoked by file %s", | ||
1251 | sshkey_type(host_key), fp, | ||
1252 | options.revoked_host_keys); | ||
1253 | r = -1; | ||
1254 | goto out; | ||
1255 | default: | ||
1256 | error("Error checking host key %s %s in " | ||
1257 | "revoked keys file %s: %s", sshkey_type(host_key), | ||
1258 | fp, options.revoked_host_keys, ssh_err(r)); | ||
1259 | r = -1; | ||
1260 | goto out; | ||
1261 | } | ||
1232 | } | 1262 | } |
1233 | 1263 | ||
1234 | if (options.verify_host_key_dns) { | 1264 | if (options.verify_host_key_dns) { |
@@ -1236,17 +1266,17 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1236 | * XXX certs are not yet supported for DNS, so downgrade | 1266 | * XXX certs are not yet supported for DNS, so downgrade |
1237 | * them and try the plain key. | 1267 | * them and try the plain key. |
1238 | */ | 1268 | */ |
1239 | plain = key_from_private(host_key); | 1269 | if ((r = sshkey_from_private(host_key, &plain)) != 0) |
1240 | if (key_is_cert(plain)) | 1270 | goto out; |
1241 | key_drop_cert(plain); | 1271 | if (sshkey_is_cert(plain)) |
1272 | sshkey_drop_cert(plain); | ||
1242 | if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { | 1273 | if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { |
1243 | if (flags & DNS_VERIFY_FOUND) { | 1274 | if (flags & DNS_VERIFY_FOUND) { |
1244 | if (options.verify_host_key_dns == 1 && | 1275 | if (options.verify_host_key_dns == 1 && |
1245 | flags & DNS_VERIFY_MATCH && | 1276 | flags & DNS_VERIFY_MATCH && |
1246 | flags & DNS_VERIFY_SECURE) { | 1277 | flags & DNS_VERIFY_SECURE) { |
1247 | key_free(plain); | ||
1248 | r = 0; | 1278 | r = 0; |
1249 | goto done; | 1279 | goto out; |
1250 | } | 1280 | } |
1251 | if (flags & DNS_VERIFY_MATCH) { | 1281 | if (flags & DNS_VERIFY_MATCH) { |
1252 | matching_host_key_dns = 1; | 1282 | matching_host_key_dns = 1; |
@@ -1258,14 +1288,14 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1258 | } | 1288 | } |
1259 | } | 1289 | } |
1260 | } | 1290 | } |
1261 | key_free(plain); | ||
1262 | } | 1291 | } |
1263 | |||
1264 | r = check_host_key(host, hostaddr, options.port, host_key, RDRW, | 1292 | r = check_host_key(host, hostaddr, options.port, host_key, RDRW, |
1265 | options.user_hostfiles, options.num_user_hostfiles, | 1293 | options.user_hostfiles, options.num_user_hostfiles, |
1266 | options.system_hostfiles, options.num_system_hostfiles); | 1294 | options.system_hostfiles, options.num_system_hostfiles); |
1267 | 1295 | ||
1268 | done: | 1296 | out: |
1297 | sshkey_free(plain); | ||
1298 | free(fp); | ||
1269 | if (r == 0 && host_key != NULL) { | 1299 | if (r == 0 && host_key != NULL) { |
1270 | key_free(previous_host_key); | 1300 | key_free(previous_host_key); |
1271 | previous_host_key = key_from_private(host_key); | 1301 | previous_host_key = key_from_private(host_key); |