- jakob@cvs.openbsd.org 2003/11/12 16:39:58
[dns.c dns.h readconf.c ssh_config.5 sshconnect.c] update SSHFP validation. ok markus@
This commit is contained in:
parent
c1f2792bd0
commit
150b55745b
|
@ -31,6 +31,9 @@
|
||||||
- dtucker@cvs.openbsd.org 2003/11/12 10:12:15
|
- dtucker@cvs.openbsd.org 2003/11/12 10:12:15
|
||||||
[scp.c]
|
[scp.c]
|
||||||
When called with -q, pass -q to ssh; suppresses SSH2 banner. ok markus@
|
When called with -q, pass -q to ssh; suppresses SSH2 banner. ok markus@
|
||||||
|
- jakob@cvs.openbsd.org 2003/11/12 16:39:58
|
||||||
|
[dns.c dns.h readconf.c ssh_config.5 sshconnect.c]
|
||||||
|
update SSHFP validation. ok markus@
|
||||||
|
|
||||||
20031115
|
20031115
|
||||||
- (dtucker) [regress/agent-ptrace.sh] Test for GDB output from Solaris and
|
- (dtucker) [regress/agent-ptrace.sh] Test for GDB output from Solaris and
|
||||||
|
@ -1451,4 +1454,4 @@
|
||||||
- Fix sshd BindAddress and -b options for systems using fake-getaddrinfo.
|
- Fix sshd BindAddress and -b options for systems using fake-getaddrinfo.
|
||||||
Report from murple@murple.net, diagnosis from dtucker@zip.com.au
|
Report from murple@murple.net, diagnosis from dtucker@zip.com.au
|
||||||
|
|
||||||
$Id: ChangeLog,v 1.3105 2003/11/17 10:19:05 djm Exp $
|
$Id: ChangeLog,v 1.3106 2003/11/17 10:19:29 djm Exp $
|
||||||
|
|
68
dns.c
68
dns.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: dns.c,v 1.7 2003/10/14 19:42:10 jakob Exp $ */
|
/* $OpenBSD: dns.c,v 1.8 2003/11/12 16:39:58 jakob Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
|
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
#include "uuencode.h"
|
#include "uuencode.h"
|
||||||
|
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
RCSID("$OpenBSD: dns.c,v 1.7 2003/10/14 19:42:10 jakob Exp $");
|
RCSID("$OpenBSD: dns.c,v 1.8 2003/11/12 16:39:58 jakob Exp $");
|
||||||
|
|
||||||
#ifndef LWRES
|
#ifndef LWRES
|
||||||
static const char *errset_text[] = {
|
static const char *errset_text[] = {
|
||||||
|
@ -83,7 +83,7 @@ dns_result_totext(unsigned int error)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
|
dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
|
||||||
u_char **digest, u_int *digest_len, Key *key)
|
u_char **digest, u_int *digest_len, const Key *key)
|
||||||
{
|
{
|
||||||
int success = 0;
|
int success = 0;
|
||||||
|
|
||||||
|
@ -145,16 +145,15 @@ dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify the given hostname, address and host key using DNS.
|
* Verify the given hostname, address and host key using DNS.
|
||||||
* Returns 0 if key verifies or -1 if key does NOT verify
|
* Returns 0 if lookup succeeds, -1 otherwise
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
verify_host_key_dns(const char *hostname, struct sockaddr *address,
|
verify_host_key_dns(const char *hostname, struct sockaddr *address,
|
||||||
Key *hostkey)
|
const Key *hostkey, int *flags)
|
||||||
{
|
{
|
||||||
int counter;
|
int counter;
|
||||||
int result;
|
int result;
|
||||||
struct rrsetinfo *fingerprints = NULL;
|
struct rrsetinfo *fingerprints = NULL;
|
||||||
int failures = 0;
|
|
||||||
|
|
||||||
u_int8_t hostkey_algorithm;
|
u_int8_t hostkey_algorithm;
|
||||||
u_int8_t hostkey_digest_type;
|
u_int8_t hostkey_digest_type;
|
||||||
|
@ -166,6 +165,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
|
||||||
u_char *dnskey_digest;
|
u_char *dnskey_digest;
|
||||||
u_int dnskey_digest_len;
|
u_int dnskey_digest_len;
|
||||||
|
|
||||||
|
*flags = 0;
|
||||||
|
|
||||||
debug3("verify_hostkey_dns");
|
debug3("verify_hostkey_dns");
|
||||||
if (hostkey == NULL)
|
if (hostkey == NULL)
|
||||||
|
@ -175,28 +175,29 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
|
||||||
DNS_RDATATYPE_SSHFP, 0, &fingerprints);
|
DNS_RDATATYPE_SSHFP, 0, &fingerprints);
|
||||||
if (result) {
|
if (result) {
|
||||||
verbose("DNS lookup error: %s", dns_result_totext(result));
|
verbose("DNS lookup error: %s", dns_result_totext(result));
|
||||||
return DNS_VERIFY_ERROR;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DNSSEC
|
if (fingerprints->rri_flags & RRSET_VALIDATED) {
|
||||||
/* Only accept validated answers */
|
*flags |= DNS_VERIFY_SECURE;
|
||||||
if (!fingerprints->rri_flags & RRSET_VALIDATED) {
|
debug("found %d secure fingerprints in DNS",
|
||||||
error("Ignored unvalidated fingerprint from DNS.");
|
fingerprints->rri_nrdatas);
|
||||||
freerrset(fingerprints);
|
} else {
|
||||||
return DNS_VERIFY_ERROR;
|
debug("found %d insecure fingerprints in DNS",
|
||||||
|
fingerprints->rri_nrdatas);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
debug("found %d fingerprints in DNS", fingerprints->rri_nrdatas);
|
|
||||||
|
|
||||||
/* Initialize host key parameters */
|
/* Initialize host key parameters */
|
||||||
if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
|
if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
|
||||||
&hostkey_digest, &hostkey_digest_len, hostkey)) {
|
&hostkey_digest, &hostkey_digest_len, hostkey)) {
|
||||||
error("Error calculating host key fingerprint.");
|
error("Error calculating host key fingerprint.");
|
||||||
freerrset(fingerprints);
|
freerrset(fingerprints);
|
||||||
return DNS_VERIFY_ERROR;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fingerprints->rri_nrdatas)
|
||||||
|
*flags |= DNS_VERIFY_FOUND;
|
||||||
|
|
||||||
for (counter = 0 ; counter < fingerprints->rri_nrdatas ; counter++) {
|
for (counter = 0 ; counter < fingerprints->rri_nrdatas ; counter++) {
|
||||||
/*
|
/*
|
||||||
* Extract the key from the answer. Ignore any badly
|
* Extract the key from the answer. Ignore any badly
|
||||||
|
@ -218,35 +219,22 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
|
||||||
memcmp(hostkey_digest, dnskey_digest,
|
memcmp(hostkey_digest, dnskey_digest,
|
||||||
hostkey_digest_len) == 0) {
|
hostkey_digest_len) == 0) {
|
||||||
|
|
||||||
/* Matching algoritm and digest. */
|
*flags |= DNS_VERIFY_MATCH;
|
||||||
freerrset(fingerprints);
|
|
||||||
debug("matching host key fingerprint found in DNS");
|
|
||||||
return DNS_VERIFY_OK;
|
|
||||||
} else {
|
|
||||||
/* Correct algorithm but bad digest */
|
|
||||||
debug("verify_hostkey_dns: failed");
|
|
||||||
failures++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
freerrset(fingerprints);
|
freerrset(fingerprints);
|
||||||
|
|
||||||
if (failures) {
|
if (*flags & DNS_VERIFY_FOUND)
|
||||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
if (*flags & DNS_VERIFY_MATCH)
|
||||||
error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
|
debug("matching host key fingerprint found in DNS");
|
||||||
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
|
else
|
||||||
error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
|
debug("mismatching host key fingerprint found in DNS");
|
||||||
error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
|
else
|
||||||
error("It is also possible that the %s host key has just been changed.",
|
debug("no host key fingerprint found in DNS");
|
||||||
key_type(hostkey));
|
|
||||||
error("Please contact your system administrator.");
|
|
||||||
return DNS_VERIFY_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug("fingerprints found in DNS, but none of them matched");
|
return 0;
|
||||||
|
|
||||||
return DNS_VERIFY_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -254,7 +242,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
|
||||||
* Export the fingerprint of a key as a DNS resource record
|
* Export the fingerprint of a key as a DNS resource record
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
|
export_dns_rr(const char *hostname, const Key *key, FILE *f, int generic)
|
||||||
{
|
{
|
||||||
u_int8_t rdata_pubkey_algorithm = 0;
|
u_int8_t rdata_pubkey_algorithm = 0;
|
||||||
u_int8_t rdata_digest_type = SSHFP_HASH_SHA1;
|
u_int8_t rdata_digest_type = SSHFP_HASH_SHA1;
|
||||||
|
|
13
dns.h
13
dns.h
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: dns.h,v 1.4 2003/10/14 19:42:10 jakob Exp $ */
|
/* $OpenBSD: dns.h,v 1.5 2003/11/12 16:39:58 jakob Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
|
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
|
||||||
|
@ -45,11 +45,12 @@ enum sshfp_hashes {
|
||||||
#define DNS_RDATACLASS_IN 1
|
#define DNS_RDATACLASS_IN 1
|
||||||
#define DNS_RDATATYPE_SSHFP 44
|
#define DNS_RDATATYPE_SSHFP 44
|
||||||
|
|
||||||
#define DNS_VERIFY_FAILED -1
|
#define DNS_VERIFY_FOUND 0x00000001
|
||||||
#define DNS_VERIFY_OK 0
|
#define DNS_VERIFY_MATCH 0x00000002
|
||||||
#define DNS_VERIFY_ERROR 1
|
#define DNS_VERIFY_SECURE 0x00000004
|
||||||
|
|
||||||
int verify_host_key_dns(const char *, struct sockaddr *, Key *);
|
|
||||||
int export_dns_rr(const char *, Key *, FILE *, int);
|
int verify_host_key_dns(const char *, struct sockaddr *, const Key *, int *);
|
||||||
|
int export_dns_rr(const char *, const Key *, FILE *, int);
|
||||||
|
|
||||||
#endif /* DNS_H */
|
#endif /* DNS_H */
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: readconf.c,v 1.124 2003/10/14 19:42:10 jakob Exp $");
|
RCSID("$OpenBSD: readconf.c,v 1.125 2003/11/12 16:39:58 jakob Exp $");
|
||||||
|
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
@ -401,10 +401,11 @@ parse_flag:
|
||||||
|
|
||||||
case oVerifyHostKeyDNS:
|
case oVerifyHostKeyDNS:
|
||||||
intptr = &options->verify_host_key_dns;
|
intptr = &options->verify_host_key_dns;
|
||||||
goto parse_flag;
|
goto parse_yesnoask;
|
||||||
|
|
||||||
case oStrictHostKeyChecking:
|
case oStrictHostKeyChecking:
|
||||||
intptr = &options->strict_host_key_checking;
|
intptr = &options->strict_host_key_checking;
|
||||||
|
parse_yesnoask:
|
||||||
arg = strdelim(&s);
|
arg = strdelim(&s);
|
||||||
if (!arg || *arg == '\0')
|
if (!arg || *arg == '\0')
|
||||||
fatal("%.200s line %d: Missing yes/no/ask argument.",
|
fatal("%.200s line %d: Missing yes/no/ask argument.",
|
||||||
|
|
19
ssh_config.5
19
ssh_config.5
|
@ -34,7 +34,7 @@
|
||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\" $OpenBSD: ssh_config.5,v 1.23 2003/10/12 13:12:13 jmc Exp $
|
.\" $OpenBSD: ssh_config.5,v 1.24 2003/11/12 16:39:58 jakob Exp $
|
||||||
.Dd September 25, 1999
|
.Dd September 25, 1999
|
||||||
.Dt SSH_CONFIG 5
|
.Dt SSH_CONFIG 5
|
||||||
.Os
|
.Os
|
||||||
|
@ -642,6 +642,23 @@ host key database instead of
|
||||||
.It Cm VerifyHostKeyDNS
|
.It Cm VerifyHostKeyDNS
|
||||||
Specifies whether to verify the remote key using DNS and SSHFP resource
|
Specifies whether to verify the remote key using DNS and SSHFP resource
|
||||||
records.
|
records.
|
||||||
|
If this option is set to
|
||||||
|
.Dq yes ,
|
||||||
|
the client will implicitly trust keys that matches a secure fingerprint
|
||||||
|
from DNS.
|
||||||
|
Insecure fingerprints will be handled as if this option was set to
|
||||||
|
.Dq ask .
|
||||||
|
If this option is set to
|
||||||
|
.Dq ask ,
|
||||||
|
information on fingerprint match will be displayed, but the user will still
|
||||||
|
need to confirm new host keys according to the
|
||||||
|
.Cm StrictHostKeyChecking
|
||||||
|
option.
|
||||||
|
The argument must be
|
||||||
|
.Dq yes ,
|
||||||
|
.Dq no
|
||||||
|
or
|
||||||
|
.Dq ask .
|
||||||
The default is
|
The default is
|
||||||
.Dq no .
|
.Dq no .
|
||||||
Note that this option applies to protocol version 2 only.
|
Note that this option applies to protocol version 2 only.
|
||||||
|
|
40
sshconnect.c
40
sshconnect.c
|
@ -13,7 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
RCSID("$OpenBSD: sshconnect.c,v 1.152 2003/11/10 16:23:41 jakob Exp $");
|
RCSID("$OpenBSD: sshconnect.c,v 1.153 2003/11/12 16:39:58 jakob Exp $");
|
||||||
|
|
||||||
#include <openssl/bn.h>
|
#include <openssl/bn.h>
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ RCSID("$OpenBSD: sshconnect.c,v 1.152 2003/11/10 16:23:41 jakob Exp $");
|
||||||
char *client_version_string = NULL;
|
char *client_version_string = NULL;
|
||||||
char *server_version_string = NULL;
|
char *server_version_string = NULL;
|
||||||
|
|
||||||
int verified_host_key_dns = 0;
|
int matching_host_key_dns = 0;
|
||||||
|
|
||||||
/* import */
|
/* import */
|
||||||
extern Options options;
|
extern Options options;
|
||||||
|
@ -728,7 +728,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key,
|
||||||
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
|
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
|
||||||
msg2[0] = '\0';
|
msg2[0] = '\0';
|
||||||
if (options.verify_host_key_dns) {
|
if (options.verify_host_key_dns) {
|
||||||
if (verified_host_key_dns)
|
if (matching_host_key_dns)
|
||||||
snprintf(msg2, sizeof(msg2),
|
snprintf(msg2, sizeof(msg2),
|
||||||
"Matching host key fingerprint"
|
"Matching host key fingerprint"
|
||||||
" found in DNS.\n");
|
" found in DNS.\n");
|
||||||
|
@ -892,23 +892,25 @@ int
|
||||||
verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
|
verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
if (options.verify_host_key_dns) {
|
if (options.verify_host_key_dns &&
|
||||||
switch(verify_host_key_dns(host, hostaddr, host_key)) {
|
verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
|
||||||
case DNS_VERIFY_OK:
|
|
||||||
#ifdef DNSSEC
|
if (flags & DNS_VERIFY_FOUND) {
|
||||||
return 0;
|
|
||||||
#else
|
if (options.verify_host_key_dns == 1 &&
|
||||||
verified_host_key_dns = 1;
|
flags & DNS_VERIFY_MATCH &&
|
||||||
break;
|
flags & DNS_VERIFY_SECURE)
|
||||||
#endif
|
return 0;
|
||||||
case DNS_VERIFY_FAILED:
|
|
||||||
return -1;
|
if (flags & DNS_VERIFY_MATCH) {
|
||||||
case DNS_VERIFY_ERROR:
|
matching_host_key_dns = 1;
|
||||||
break;
|
} else {
|
||||||
default:
|
warn_changed_key(host_key);
|
||||||
debug3("bad return value from verify_host_key_dns");
|
error("Update the SSHFP RR in DNS with the new "
|
||||||
break;
|
"host key to get rid of this message.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue