コード例 #1
0
ファイル: dns.c プロジェクト: ht13/openssh-portable
/*
 * Verify the given hostname, address and host key using DNS.
 * Returns 0 if lookup succeeds, -1 otherwise
 */
int
verify_host_key_dns(const char *hostname, struct sockaddr *address,
                    struct sshkey *hostkey, int *flags)
{
    u_int counter;
    int result;
    struct rrsetinfo *fingerprints = NULL;

    u_int8_t hostkey_algorithm;
    u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED;
    u_char *hostkey_digest;
    size_t hostkey_digest_len;

    u_int8_t dnskey_algorithm;
    u_int8_t dnskey_digest_type;
    u_char *dnskey_digest;
    size_t dnskey_digest_len;

    *flags = 0;

    debug3("verify_host_key_dns");
    if (hostkey == NULL)
        fatal("No key to look up!");

    if (is_numeric_hostname(hostname)) {
        debug("skipped DNS lookup for numerical hostname");
        return -1;
    }

    result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
                            DNS_RDATATYPE_SSHFP, 0, &fingerprints);
    if (result) {
        verbose("DNS lookup error: %s", dns_result_totext(result));
        return -1;
    }

    if (fingerprints->rri_flags & RRSET_VALIDATED) {
        *flags |= DNS_VERIFY_SECURE;
        debug("found %d secure fingerprints in DNS",
              fingerprints->rri_nrdatas);
    } else {
        debug("found %d insecure fingerprints in DNS",
              fingerprints->rri_nrdatas);
    }

    /* Initialize default host key parameters */
    if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
                      &hostkey_digest, &hostkey_digest_len, hostkey)) {
        error("Error calculating host key fingerprint.");
        freerrset(fingerprints);
        return -1;
    }

    if (fingerprints->rri_nrdatas)
        *flags |= DNS_VERIFY_FOUND;

    for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) {
        /*
         * Extract the key from the answer. Ignore any badly
         * formatted fingerprints.
         */
        if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type,
                            &dnskey_digest, &dnskey_digest_len,
                            fingerprints->rri_rdatas[counter].rdi_data,
                            fingerprints->rri_rdatas[counter].rdi_length)) {
            verbose("Error parsing fingerprint from DNS.");
            continue;
        }

        if (hostkey_digest_type != dnskey_digest_type) {
            hostkey_digest_type = dnskey_digest_type;
            free(hostkey_digest);

            /* Initialize host key parameters */
            if (!dns_read_key(&hostkey_algorithm,
                              &hostkey_digest_type, &hostkey_digest,
                              &hostkey_digest_len, hostkey)) {
                error("Error calculating key fingerprint.");
                freerrset(fingerprints);
                return -1;
            }
        }

        /* Check if the current key is the same as the given key */
        if (hostkey_algorithm == dnskey_algorithm &&
                hostkey_digest_type == dnskey_digest_type) {
            if (hostkey_digest_len == dnskey_digest_len &&
                    timingsafe_bcmp(hostkey_digest, dnskey_digest,
                                    hostkey_digest_len) == 0)
                *flags |= DNS_VERIFY_MATCH;
        }
        free(dnskey_digest);
    }

    free(hostkey_digest); /* from sshkey_fingerprint_raw() */
    freerrset(fingerprints);

    if (*flags & DNS_VERIFY_FOUND)
        if (*flags & DNS_VERIFY_MATCH)
            debug("matching host key fingerprint found in DNS");
        else
            debug("mismatching host key fingerprint found in DNS");
    else
        debug("no host key fingerprint found in DNS");

    return 0;
}
コード例 #2
0
ファイル: dns.c プロジェクト: sokoow/openssh
/*
 * Verify the given hostname, address and host key using DNS.
 * Returns 0 if lookup succeeds, -1 otherwise
 */
int
verify_host_key_dns(const char *hostname, struct sockaddr *address,
    struct sshkey *hostkey, int *flags)
{
	u_int counter;
	int result;
	unsigned int rrset_flags = 0;
	struct rrsetinfo *fingerprints = NULL;

	u_int8_t hostkey_algorithm;
	u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED;
	u_char *hostkey_digest;
	size_t hostkey_digest_len;

	u_int8_t dnskey_algorithm;
	u_int8_t dnskey_digest_type;
	u_char *dnskey_digest;
	size_t dnskey_digest_len;

	*flags = 0;

	debug3("verify_host_key_dns");
	if (hostkey == NULL)
		fatal("No key to look up!");

	if (is_numeric_hostname(hostname)) {
		debug("skipped DNS lookup for numerical hostname");
		return -1;
	}

	/*
	 * Original getrrsetbyname function, found on OpenBSD for example,
	 * doesn't accept any flag and prerequisite for obtaining AD bit in
	 * DNS response is set by "options edns0" in resolv.conf.
	 *
	 * Our version is more clever and use RRSET_FORCE_EDNS0 flag.
	 */
#ifndef HAVE_GETRRSETBYNAME
	rrset_flags |= RRSET_FORCE_EDNS0;
#endif
	result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
	    DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints);

	if (result) {
		verbose("DNS lookup error: %s", dns_result_totext(result));
		return -1;
	}

	if (fingerprints->rri_flags & RRSET_VALIDATED) {
		*flags |= DNS_VERIFY_SECURE;
		debug("found %d secure fingerprints in DNS",
		    fingerprints->rri_nrdatas);
	} else {
		debug("found %d insecure fingerprints in DNS",
		    fingerprints->rri_nrdatas);
	}

	/* Initialize default host key parameters */
	if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
	    &hostkey_digest, &hostkey_digest_len, hostkey)) {
		error("Error calculating host key fingerprint.");
		freerrset(fingerprints);
		return -1;
	}

	if (fingerprints->rri_nrdatas)
		*flags |= DNS_VERIFY_FOUND;

	for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) {
		/*
		 * Extract the key from the answer. Ignore any badly
		 * formatted fingerprints.
		 */
		if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type,
		    &dnskey_digest, &dnskey_digest_len,
		    fingerprints->rri_rdatas[counter].rdi_data,
		    fingerprints->rri_rdatas[counter].rdi_length)) {
			verbose("Error parsing fingerprint from DNS.");
			continue;
		}

		if (hostkey_digest_type != dnskey_digest_type) {
			hostkey_digest_type = dnskey_digest_type;
			free(hostkey_digest);

			/* Initialize host key parameters */
			if (!dns_read_key(&hostkey_algorithm,
			    &hostkey_digest_type, &hostkey_digest,
			    &hostkey_digest_len, hostkey)) {
				error("Error calculating key fingerprint.");
				freerrset(fingerprints);
				return -1;
			}
		}

		/* Check if the current key is the same as the given key */
		if (hostkey_algorithm == dnskey_algorithm &&
		    hostkey_digest_type == dnskey_digest_type) {
			if (hostkey_digest_len == dnskey_digest_len &&
			    timingsafe_bcmp(hostkey_digest, dnskey_digest,
			    hostkey_digest_len) == 0)
				*flags |= DNS_VERIFY_MATCH;
		}
		free(dnskey_digest);
	}

	free(hostkey_digest); /* from sshkey_fingerprint_raw() */
	freerrset(fingerprints);

	if (*flags & DNS_VERIFY_FOUND)
		if (*flags & DNS_VERIFY_MATCH)
			debug("matching host key fingerprint found in DNS");
		else
			debug("mismatching host key fingerprint found in DNS");
	else
		debug("no host key fingerprint found in DNS");

	return 0;
}