示例#1
0
/**
 * Check a canonical sig+rrset and signature against a dnskey
 * @param buf: buffer with data to verify, the first rrsig part and the
 *	canonicalized rrset.
 * @param algo: DNSKEY algorithm.
 * @param sigblock: signature rdata field from RRSIG
 * @param sigblock_len: length of sigblock data.
 * @param key: public key data from DNSKEY RR.
 * @param keylen: length of keydata.
 * @param reason: bogus reason in more detail.
 * @return secure if verification succeeded, bogus on crypto failure,
 *	unchecked on format errors and alloc failures.
 */
enum sec_status
verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, 
	unsigned int sigblock_len, unsigned char* key, unsigned int keylen,
	char** reason)
{
	const EVP_MD *digest_type;
	EVP_MD_CTX* ctx;
	int res, dofree = 0, docrypto_free = 0;
	EVP_PKEY *evp_key = NULL;

#ifndef USE_DSA
	if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) &&(fake_dsa||fake_sha1))
		return sec_status_secure;
#endif
#ifndef USE_SHA1
	if(fake_sha1 && (algo == LDNS_DSA || algo == LDNS_DSA_NSEC3 || algo == LDNS_RSASHA1 || algo == LDNS_RSASHA1_NSEC3))
		return sec_status_secure;
#endif
	
	if(!setup_key_digest(algo, &evp_key, &digest_type, key, keylen)) {
		verbose(VERB_QUERY, "verify: failed to setup key");
		*reason = "use of key for crypto failed";
		EVP_PKEY_free(evp_key);
		return sec_status_bogus;
	}
#ifdef USE_DSA
	/* if it is a DSA signature in bind format, convert to DER format */
	if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) && 
		sigblock_len == 1+2*SHA_DIGEST_LENGTH) {
		if(!setup_dsa_sig(&sigblock, &sigblock_len)) {
			verbose(VERB_QUERY, "verify: failed to setup DSA sig");
			*reason = "use of key for DSA crypto failed";
			EVP_PKEY_free(evp_key);
			return sec_status_bogus;
		}
		docrypto_free = 1;
	}
#endif
#if defined(USE_ECDSA) && defined(USE_DSA)
	else 
#endif
#ifdef USE_ECDSA
	if(algo == LDNS_ECDSAP256SHA256 || algo == LDNS_ECDSAP384SHA384) {
		/* EVP uses ASN prefix on sig, which is not in the wire data */
		if(!setup_ecdsa_sig(&sigblock, &sigblock_len)) {
			verbose(VERB_QUERY, "verify: failed to setup ECDSA sig");
			*reason = "use of signature for ECDSA crypto failed";
			EVP_PKEY_free(evp_key);
			return sec_status_bogus;
		}
		dofree = 1;
	}
#endif /* USE_ECDSA */

	/* do the signature cryptography work */
#ifdef HAVE_EVP_MD_CTX_NEW
	ctx = EVP_MD_CTX_new();
#else
	ctx = (EVP_MD_CTX*)malloc(sizeof(*ctx));
	if(ctx) EVP_MD_CTX_init(ctx);
#endif
	if(!ctx) {
		log_err("EVP_MD_CTX_new: malloc failure");
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		else if(docrypto_free) OPENSSL_free(sigblock);
		return sec_status_unchecked;
	}
#ifndef HAVE_EVP_DIGESTVERIFY
	if(EVP_DigestInit(ctx, digest_type) == 0) {
		verbose(VERB_QUERY, "verify: EVP_DigestInit failed");
#ifdef HAVE_EVP_MD_CTX_NEW
		EVP_MD_CTX_destroy(ctx);
#else
		EVP_MD_CTX_cleanup(ctx);
		free(ctx);
#endif
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		else if(docrypto_free) OPENSSL_free(sigblock);
		return sec_status_unchecked;
	}
	if(EVP_DigestUpdate(ctx, (unsigned char*)sldns_buffer_begin(buf), 
		(unsigned int)sldns_buffer_limit(buf)) == 0) {
		verbose(VERB_QUERY, "verify: EVP_DigestUpdate failed");
#ifdef HAVE_EVP_MD_CTX_NEW
		EVP_MD_CTX_destroy(ctx);
#else
		EVP_MD_CTX_cleanup(ctx);
		free(ctx);
#endif
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		else if(docrypto_free) OPENSSL_free(sigblock);
		return sec_status_unchecked;
	}

	res = EVP_VerifyFinal(ctx, sigblock, sigblock_len, evp_key);
#else /* HAVE_EVP_DIGESTVERIFY */
	if(EVP_DigestVerifyInit(ctx, NULL, digest_type, NULL, evp_key) == 0) {
		verbose(VERB_QUERY, "verify: EVP_DigestVerifyInit failed");
#ifdef HAVE_EVP_MD_CTX_NEW
		EVP_MD_CTX_destroy(ctx);
#else
		EVP_MD_CTX_cleanup(ctx);
		free(ctx);
#endif
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		else if(docrypto_free) OPENSSL_free(sigblock);
		return sec_status_unchecked;
	}
	res = EVP_DigestVerify(ctx, sigblock, sigblock_len,
		(unsigned char*)sldns_buffer_begin(buf),
		sldns_buffer_limit(buf));
#endif
#ifdef HAVE_EVP_MD_CTX_NEW
	EVP_MD_CTX_destroy(ctx);
#else
	EVP_MD_CTX_cleanup(ctx);
	free(ctx);
#endif
	EVP_PKEY_free(evp_key);

	if(dofree) free(sigblock);
	else if(docrypto_free) OPENSSL_free(sigblock);

	if(res == 1) {
		return sec_status_secure;
	} else if(res == 0) {
		verbose(VERB_QUERY, "verify: signature mismatch");
		*reason = "signature crypto failed";
		return sec_status_bogus;
	}

	log_crypto_error("verify:", ERR_get_error());
	return sec_status_unchecked;
}
示例#2
0
/**
 * Check a canonical sig+rrset and signature against a dnskey
 * @param buf: buffer with data to verify, the first rrsig part and the
 *	canonicalized rrset.
 * @param algo: DNSKEY algorithm.
 * @param sigblock: signature rdata field from RRSIG
 * @param sigblock_len: length of sigblock data.
 * @param key: public key data from DNSKEY RR.
 * @param keylen: length of keydata.
 * @param reason: bogus reason in more detail.
 * @return secure if verification succeeded, bogus on crypto failure,
 *	unchecked on format errors and alloc failures.
 */
enum sec_status
verify_canonrrset(ldns_buffer* buf, int algo, unsigned char* sigblock, 
	unsigned int sigblock_len, unsigned char* key, unsigned int keylen,
	char** reason)
{
	const EVP_MD *digest_type;
	EVP_MD_CTX ctx;
	int res, dofree = 0;
	EVP_PKEY *evp_key = NULL;
	
	if(!setup_key_digest(algo, &evp_key, &digest_type, key, keylen)) {
		verbose(VERB_QUERY, "verify: failed to setup key");
		*reason = "use of key for crypto failed";
		EVP_PKEY_free(evp_key);
		return sec_status_bogus;
	}
	/* if it is a DSA signature in bind format, convert to DER format */
	if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) && 
		sigblock_len == 1+2*SHA_DIGEST_LENGTH) {
		if(!setup_dsa_sig(&sigblock, &sigblock_len)) {
			verbose(VERB_QUERY, "verify: failed to setup DSA sig");
			*reason = "use of key for DSA crypto failed";
			EVP_PKEY_free(evp_key);
			return sec_status_bogus;
		}
		dofree = 1;
	}
#ifdef USE_ECDSA
	else if(algo == LDNS_ECDSAP256SHA256 || algo == LDNS_ECDSAP384SHA384) {
		/* EVP uses ASN prefix on sig, which is not in the wire data */
		if(!setup_ecdsa_sig(&sigblock, &sigblock_len)) {
			verbose(VERB_QUERY, "verify: failed to setup ECDSA sig");
			*reason = "use of signature for ECDSA crypto failed";
			EVP_PKEY_free(evp_key);
			return sec_status_bogus;
		}
		dofree = 1;
	}
#endif /* USE_ECDSA */

	/* do the signature cryptography work */
	EVP_MD_CTX_init(&ctx);
	if(EVP_VerifyInit(&ctx, digest_type) == 0) {
		verbose(VERB_QUERY, "verify: EVP_VerifyInit failed");
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		return sec_status_unchecked;
	}
	if(EVP_VerifyUpdate(&ctx, (unsigned char*)ldns_buffer_begin(buf), 
		(unsigned int)ldns_buffer_limit(buf)) == 0) {
		verbose(VERB_QUERY, "verify: EVP_VerifyUpdate failed");
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		return sec_status_unchecked;
	}

	res = EVP_VerifyFinal(&ctx, sigblock, sigblock_len, evp_key);
	if(EVP_MD_CTX_cleanup(&ctx) == 0) {
		verbose(VERB_QUERY, "verify: EVP_MD_CTX_cleanup failed");
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		return sec_status_unchecked;
	}
	EVP_PKEY_free(evp_key);

	if(dofree)
		free(sigblock);

	if(res == 1) {
		return sec_status_secure;
	} else if(res == 0) {
		verbose(VERB_QUERY, "verify: signature mismatch");
		*reason = "signature crypto failed";
		return sec_status_bogus;
	}

	log_crypto_error("verify:", ERR_get_error());
	return sec_status_unchecked;
}