mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
no convert to der for DSA signatures
signature test. git-svn-id: file:///svn/unbound/trunk@564 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
134db23ea8
commit
de6d807e3d
4 changed files with 150 additions and 117 deletions
|
|
@ -3,6 +3,9 @@
|
||||||
- added RSA and DSA test keys, public and private pairs, 512 bits.
|
- added RSA and DSA test keys, public and private pairs, 512 bits.
|
||||||
- default configuration is with validation enabled.
|
- default configuration is with validation enabled.
|
||||||
Only a trust-anchor needs to be configured for DNSSEC to work.
|
Only a trust-anchor needs to be configured for DNSSEC to work.
|
||||||
|
- do not convert to DER for DSA signature verification.
|
||||||
|
- validator replay test file, for a DS to DNSKEY DSA key prime and
|
||||||
|
positive response.
|
||||||
|
|
||||||
28 August 2007: Wouter
|
28 August 2007: Wouter
|
||||||
- removed double use for udp buffers, that could fail,
|
- removed double use for udp buffers, that could fail,
|
||||||
|
|
|
||||||
121
testdata/val_positive.rpl
vendored
Normal file
121
testdata/val_positive.rpl
vendored
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
; config options
|
||||||
|
; The island of trust is at example.com
|
||||||
|
server:
|
||||||
|
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
|
||||||
|
val-override-date: "20070916134226"
|
||||||
|
|
||||||
|
stub-zone:
|
||||||
|
name: "."
|
||||||
|
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
|
||||||
|
CONFIG_END
|
||||||
|
|
||||||
|
SCENARIO_BEGIN Test validator with positive response
|
||||||
|
|
||||||
|
; K.ROOT-SERVERS.NET.
|
||||||
|
RANGE_BEGIN 0 100
|
||||||
|
ADDRESS 193.0.14.129
|
||||||
|
ENTRY_BEGIN
|
||||||
|
MATCH opcode qtype qname
|
||||||
|
ADJUST copy_id
|
||||||
|
REPLY QR NOERROR
|
||||||
|
SECTION QUESTION
|
||||||
|
. IN NS
|
||||||
|
SECTION ANSWER
|
||||||
|
. IN NS K.ROOT-SERVERS.NET.
|
||||||
|
SECTION ADDITIONAL
|
||||||
|
K.ROOT-SERVERS.NET. IN A 193.0.14.129
|
||||||
|
ENTRY_END
|
||||||
|
|
||||||
|
ENTRY_BEGIN
|
||||||
|
MATCH opcode qtype qname
|
||||||
|
ADJUST copy_id
|
||||||
|
REPLY QR NOERROR
|
||||||
|
SECTION QUESTION
|
||||||
|
www.example.com. IN A
|
||||||
|
SECTION AUTHORITY
|
||||||
|
com. IN NS a.gtld-servers.net.
|
||||||
|
SECTION ADDITIONAL
|
||||||
|
a.gtld-servers.net. IN A 192.5.6.30
|
||||||
|
ENTRY_END
|
||||||
|
RANGE_END
|
||||||
|
|
||||||
|
; a.gtld-servers.net.
|
||||||
|
RANGE_BEGIN 0 100
|
||||||
|
ADDRESS 192.5.6.30
|
||||||
|
ENTRY_BEGIN
|
||||||
|
MATCH opcode qtype qname
|
||||||
|
ADJUST copy_id
|
||||||
|
REPLY QR NOERROR
|
||||||
|
SECTION QUESTION
|
||||||
|
www.example.com. IN A
|
||||||
|
SECTION AUTHORITY
|
||||||
|
example.com. IN NS ns.example.com.
|
||||||
|
SECTION ADDITIONAL
|
||||||
|
ns.example.com. IN A 1.2.3.4
|
||||||
|
ENTRY_END
|
||||||
|
RANGE_END
|
||||||
|
|
||||||
|
; ns.example.com.
|
||||||
|
RANGE_BEGIN 0 100
|
||||||
|
ADDRESS 1.2.3.4
|
||||||
|
|
||||||
|
; response to DNSKEY priming query
|
||||||
|
ENTRY_BEGIN
|
||||||
|
MATCH opcode qtype qname
|
||||||
|
ADJUST copy_id
|
||||||
|
REPLY QR NOERROR
|
||||||
|
SECTION QUESTION
|
||||||
|
example.com. IN DNSKEY
|
||||||
|
SECTION ANSWER
|
||||||
|
example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
|
||||||
|
example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
|
||||||
|
SECTION AUTHORITY
|
||||||
|
example.com. IN NS ns.example.com.
|
||||||
|
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
|
||||||
|
SECTION ADDITIONAL
|
||||||
|
ns.example.com. IN A 1.2.3.4
|
||||||
|
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
|
||||||
|
ENTRY_END
|
||||||
|
|
||||||
|
; response to query of interest
|
||||||
|
ENTRY_BEGIN
|
||||||
|
MATCH opcode qtype qname
|
||||||
|
ADJUST copy_id
|
||||||
|
REPLY QR NOERROR
|
||||||
|
SECTION QUESTION
|
||||||
|
www.example.com. IN A
|
||||||
|
SECTION ANSWER
|
||||||
|
www.example.com. IN A 10.20.30.40
|
||||||
|
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
|
||||||
|
SECTION AUTHORITY
|
||||||
|
example.com. IN NS ns.example.com.
|
||||||
|
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
|
||||||
|
SECTION ADDITIONAL
|
||||||
|
ns.example.com. IN A 1.2.3.4
|
||||||
|
www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
|
||||||
|
ENTRY_END
|
||||||
|
RANGE_END
|
||||||
|
|
||||||
|
STEP 1 QUERY
|
||||||
|
ENTRY_BEGIN
|
||||||
|
REPLY RD
|
||||||
|
SECTION QUESTION
|
||||||
|
www.example.com. IN A
|
||||||
|
ENTRY_END
|
||||||
|
|
||||||
|
; recursion happens here.
|
||||||
|
STEP 10 CHECK_ANSWER
|
||||||
|
ENTRY_BEGIN
|
||||||
|
MATCH all
|
||||||
|
REPLY QR RD RA AD NOERROR
|
||||||
|
SECTION QUESTION
|
||||||
|
www.example.com. IN A
|
||||||
|
SECTION ANSWER
|
||||||
|
www.example.com. IN A 10.20.30.40
|
||||||
|
SECTION AUTHORITY
|
||||||
|
example.com. IN NS ns.example.com.
|
||||||
|
SECTION ADDITIONAL
|
||||||
|
ns.example.com. IN A 1.2.3.4
|
||||||
|
ENTRY_END
|
||||||
|
|
||||||
|
SCENARIO_END
|
||||||
|
|
@ -312,7 +312,10 @@ ds_create_dnskey_digest(struct module_env* env,
|
||||||
ldns_buffer_limit(b), (unsigned char*)digest);
|
ldns_buffer_limit(b), (unsigned char*)digest);
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
default: break;
|
default:
|
||||||
|
verbose(VERB_DETAIL, "unknown DS digest algorithm %d",
|
||||||
|
(int) ds_get_digest_algo(ds_rrset, ds_idx));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -326,21 +329,33 @@ int ds_digest_match_dnskey(struct module_env* env,
|
||||||
uint8_t* digest; /* generated digest */
|
uint8_t* digest; /* generated digest */
|
||||||
size_t digestlen = ds_digest_size_algo(ds_rrset, ds_idx);
|
size_t digestlen = ds_digest_size_algo(ds_rrset, ds_idx);
|
||||||
|
|
||||||
if(digestlen == 0)
|
if(digestlen == 0) {
|
||||||
|
verbose(VERB_DETAIL, "DS fail: not supported, or DS RR "
|
||||||
|
"format error");
|
||||||
return 0; /* not supported, or DS RR format error */
|
return 0; /* not supported, or DS RR format error */
|
||||||
|
}
|
||||||
/* check digest length in DS with length from hash function */
|
/* check digest length in DS with length from hash function */
|
||||||
ds_get_sigdata(ds_rrset, ds_idx, &ds, &dslen);
|
ds_get_sigdata(ds_rrset, ds_idx, &ds, &dslen);
|
||||||
if(!ds || dslen != digestlen)
|
if(!ds || dslen != digestlen) {
|
||||||
|
verbose(VERB_DETAIL, "DS fail: DS RR algo and digest do not "
|
||||||
|
"match each other");
|
||||||
return 0; /* DS algorithm and digest do not match */
|
return 0; /* DS algorithm and digest do not match */
|
||||||
|
}
|
||||||
|
|
||||||
digest = region_alloc(env->scratch, digestlen);
|
digest = region_alloc(env->scratch, digestlen);
|
||||||
if(!digest)
|
if(!digest) {
|
||||||
|
verbose(VERB_DETAIL, "DS fail: out of memory");
|
||||||
return 0; /* mem error */
|
return 0; /* mem error */
|
||||||
|
}
|
||||||
if(!ds_create_dnskey_digest(env, dnskey_rrset, dnskey_idx, ds_rrset,
|
if(!ds_create_dnskey_digest(env, dnskey_rrset, dnskey_idx, ds_rrset,
|
||||||
ds_idx, digest))
|
ds_idx, digest)) {
|
||||||
|
verbose(VERB_DETAIL, "DS fail: could not calc key digest");
|
||||||
return 0; /* digest algo failed */
|
return 0; /* digest algo failed */
|
||||||
if(memcmp(digest, ds, dslen) != 0)
|
}
|
||||||
|
if(memcmp(digest, ds, dslen) != 0) {
|
||||||
|
verbose(VERB_DETAIL, "DS fail: digest is different");
|
||||||
return 0; /* digest different */
|
return 0; /* digest different */
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1164,91 +1179,6 @@ log_crypto_error(const char* str, unsigned long e)
|
||||||
log_err("%s crypto %s", str, buf);
|
log_err("%s crypto %s", str, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert DSA RRsig sigblock to a DSA_SIG structure.
|
|
||||||
* @param sig: sigblock field of RRSIG
|
|
||||||
* @param siglen: length of sig.
|
|
||||||
* @return DSA_SIG or NULL
|
|
||||||
*/
|
|
||||||
static DSA_SIG*
|
|
||||||
dsa_rrsig_to_dsa_sig(unsigned char* sig, unsigned int siglen)
|
|
||||||
{
|
|
||||||
uint8_t t;
|
|
||||||
BIGNUM *R, *S;
|
|
||||||
DSA_SIG *dsasig;
|
|
||||||
|
|
||||||
/* extract the R and S field from the sig buffer */
|
|
||||||
if(siglen < 1 + SHA_DIGEST_LENGTH*2) {
|
|
||||||
verbose(VERB_DETAIL, "verify: short DSA RRSIG");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
t = sig[0];
|
|
||||||
R = BN_new();
|
|
||||||
if(!R) {
|
|
||||||
log_err("verify: alloc failure");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
S = BN_new();
|
|
||||||
if(!S) {
|
|
||||||
BN_free(R);
|
|
||||||
log_err("verify: alloc failure");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if(!BN_bin2bn(sig + 1, SHA_DIGEST_LENGTH, R)) {
|
|
||||||
log_err("verify: bignum failure");
|
|
||||||
BN_free(R);
|
|
||||||
BN_free(S);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if(!BN_bin2bn(sig + 21, SHA_DIGEST_LENGTH, S)) {
|
|
||||||
log_err("verify: bignum failure");
|
|
||||||
BN_free(R);
|
|
||||||
BN_free(S);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dsasig = DSA_SIG_new();
|
|
||||||
if(!dsasig) {
|
|
||||||
log_err("verify: alloc failure");
|
|
||||||
BN_free(R);
|
|
||||||
BN_free(S);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
dsasig->r = R;
|
|
||||||
dsasig->s = S;
|
|
||||||
return dsasig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert DSA signature to a DER signature.
|
|
||||||
* @param sig: signature, used to read, then replaced with malloced
|
|
||||||
* DER signature on success.
|
|
||||||
* @param siglen: read to get input len, then updated to new length.
|
|
||||||
* @return false on (alloc) error.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
dsa_convert_to_der(unsigned char** sig, unsigned int* siglen)
|
|
||||||
{
|
|
||||||
DSA_SIG* dsasig;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
dsasig = dsa_rrsig_to_dsa_sig(*sig, *siglen);
|
|
||||||
if(!dsasig) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*sig = NULL; /* needs libcrypto >= 0.9.7 */
|
|
||||||
res = i2d_DSA_SIG(dsasig, sig);
|
|
||||||
if(res < 0) {
|
|
||||||
log_crypto_error("verify: bad dsa sig ",
|
|
||||||
ERR_get_error());
|
|
||||||
DSA_SIG_free(dsasig);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
DSA_SIG_free(dsasig);
|
|
||||||
*siglen = (unsigned int)res;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup key and digest for verification. Adjust sig if necessary.
|
* Setup key and digest for verification. Adjust sig if necessary.
|
||||||
*
|
*
|
||||||
|
|
@ -1257,14 +1187,11 @@ dsa_convert_to_der(unsigned char** sig, unsigned int* siglen)
|
||||||
* @param digest_type: digest type to use
|
* @param digest_type: digest type to use
|
||||||
* @param key: key to setup for.
|
* @param key: key to setup for.
|
||||||
* @param keylen: length of key.
|
* @param keylen: length of key.
|
||||||
* @param sig: sig to update if necessary.
|
|
||||||
* @param siglen: length of sig.
|
|
||||||
* @return false on failure.
|
* @return false on failure.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
setup_key_digest(int algo, EVP_PKEY* evp_key, const EVP_MD** digest_type,
|
setup_key_digest(int algo, EVP_PKEY* evp_key, const EVP_MD** digest_type,
|
||||||
unsigned char* key, size_t keylen,
|
unsigned char* key, size_t keylen)
|
||||||
unsigned char** sig, unsigned int* siglen)
|
|
||||||
{
|
{
|
||||||
switch(algo) {
|
switch(algo) {
|
||||||
case LDNS_DSA:
|
case LDNS_DSA:
|
||||||
|
|
@ -1272,8 +1199,6 @@ setup_key_digest(int algo, EVP_PKEY* evp_key, const EVP_MD** digest_type,
|
||||||
EVP_PKEY_assign_DSA(evp_key,
|
EVP_PKEY_assign_DSA(evp_key,
|
||||||
ldns_key_buf2dsa_raw(key, keylen));
|
ldns_key_buf2dsa_raw(key, keylen));
|
||||||
*digest_type = EVP_dss1();
|
*digest_type = EVP_dss1();
|
||||||
if(!dsa_convert_to_der(sig, siglen))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case LDNS_RSASHA1:
|
case LDNS_RSASHA1:
|
||||||
|
|
@ -1297,23 +1222,6 @@ setup_key_digest(int algo, EVP_PKEY* evp_key, const EVP_MD** digest_type,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Desetup what setup_key_digest setup.
|
|
||||||
* @param algo: key algorithm
|
|
||||||
* @param sig: signature.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
desetup_key_digest(int algo, unsigned char* sig)
|
|
||||||
{
|
|
||||||
switch(algo) {
|
|
||||||
case LDNS_DSA:
|
|
||||||
case LDNS_DSA_NSEC3:
|
|
||||||
/* free converted signature */
|
|
||||||
free(sig);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check a canonical sig+rrset and signature against a dnskey
|
* Check a canonical sig+rrset and signature against a dnskey
|
||||||
* @param buf: buffer with data to verify, the first rrsig part and the
|
* @param buf: buffer with data to verify, the first rrsig part and the
|
||||||
|
|
@ -1339,8 +1247,8 @@ verify_canonrrset(ldns_buffer* buf, int algo, unsigned char* sigblock,
|
||||||
return sec_status_unchecked;
|
return sec_status_unchecked;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!setup_key_digest(algo, evp_key, &digest_type, key, keylen,
|
if(!setup_key_digest(algo, evp_key, &digest_type, key, keylen)) {
|
||||||
&sigblock, &sigblock_len)) {
|
verbose(VERB_DETAIL, "verify: failed to setup key");
|
||||||
EVP_PKEY_free(evp_key);
|
EVP_PKEY_free(evp_key);
|
||||||
return sec_status_bogus;
|
return sec_status_bogus;
|
||||||
}
|
}
|
||||||
|
|
@ -1353,7 +1261,6 @@ verify_canonrrset(ldns_buffer* buf, int algo, unsigned char* sigblock,
|
||||||
res = EVP_VerifyFinal(&ctx, sigblock, sigblock_len, evp_key);
|
res = EVP_VerifyFinal(&ctx, sigblock, sigblock_len, evp_key);
|
||||||
EVP_MD_CTX_cleanup(&ctx);
|
EVP_MD_CTX_cleanup(&ctx);
|
||||||
EVP_PKEY_free(evp_key);
|
EVP_PKEY_free(evp_key);
|
||||||
desetup_key_digest(algo, sigblock);
|
|
||||||
|
|
||||||
if(res == 1) {
|
if(res == 1) {
|
||||||
return sec_status_secure;
|
return sec_status_secure;
|
||||||
|
|
|
||||||
|
|
@ -365,8 +365,10 @@ verify_dnskeys_with_ds_rr(struct module_env* env, struct val_env* ve,
|
||||||
* same DS hash algorithm. */
|
* same DS hash algorithm. */
|
||||||
if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset,
|
if(!ds_digest_match_dnskey(env, dnskey_rrset, i, ds_rrset,
|
||||||
ds_idx)) {
|
ds_idx)) {
|
||||||
|
verbose(VERB_ALGO, "DS match attempt failed");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
verbose(VERB_ALGO, "DS match digest ok, trying signature");
|
||||||
|
|
||||||
/* Otherwise, we have a match! Make sure that the DNSKEY
|
/* Otherwise, we have a match! Make sure that the DNSKEY
|
||||||
* verifies *with this key* */
|
* verifies *with this key* */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue