|
|
c2d1e6 |
diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c
|
|
|
c2d1e6 |
index 00a0080..336c4da 100644
|
|
|
c2d1e6 |
--- a/lib/dns/dnssec.c
|
|
|
c2d1e6 |
+++ b/lib/dns/dnssec.c
|
|
|
c2d1e6 |
@@ -982,6 +982,8 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
|
|
|
c2d1e6 |
mctx = msg->mctx;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
msg->verify_attempted = 1;
|
|
|
c2d1e6 |
+ msg->verified_sig = 0;
|
|
|
c2d1e6 |
+ msg->sig0status = dns_tsigerror_badsig;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
if (is_response(msg)) {
|
|
|
c2d1e6 |
if (msg->query.base == NULL)
|
|
|
c2d1e6 |
@@ -1076,6 +1078,7 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
msg->verified_sig = 1;
|
|
|
c2d1e6 |
+ msg->sig0status = dns_rcode_noerror;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
dst_context_destroy(&ctx;;
|
|
|
c2d1e6 |
dns_rdata_freestruct(&sig);
|
|
|
c2d1e6 |
diff --git a/lib/dns/message.c b/lib/dns/message.c
|
|
|
c2d1e6 |
index 1417067..0621175 100644
|
|
|
c2d1e6 |
--- a/lib/dns/message.c
|
|
|
c2d1e6 |
+++ b/lib/dns/message.c
|
|
|
c2d1e6 |
@@ -3052,12 +3052,19 @@ dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
result = dns_rdata_tostruct(&rdata, &tsig, NULL);
|
|
|
c2d1e6 |
INSIST(result == ISC_R_SUCCESS);
|
|
|
c2d1e6 |
- if (msg->tsigstatus != dns_rcode_noerror)
|
|
|
c2d1e6 |
+ if (msg->verified_sig &&
|
|
|
c2d1e6 |
+ msg->tsigstatus == dns_rcode_noerror &&
|
|
|
c2d1e6 |
+ tsig.error == dns_rcode_noerror)
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
+ result = ISC_R_SUCCESS;
|
|
|
c2d1e6 |
+ } else if ((!msg->verified_sig) ||
|
|
|
c2d1e6 |
+ (msg->tsigstatus != dns_rcode_noerror))
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
result = DNS_R_TSIGVERIFYFAILURE;
|
|
|
c2d1e6 |
- else if (tsig.error != dns_rcode_noerror)
|
|
|
c2d1e6 |
+ } else {
|
|
|
c2d1e6 |
+ INSIST(tsig.error != dns_rcode_noerror);
|
|
|
c2d1e6 |
result = DNS_R_TSIGERRORSET;
|
|
|
c2d1e6 |
- else
|
|
|
c2d1e6 |
- result = ISC_R_SUCCESS;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
dns_rdata_freestruct(&tsig);
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
if (msg->tsigkey == NULL) {
|
|
|
c2d1e6 |
diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c
|
|
|
c2d1e6 |
index 3239bff..7b91d1e 100644
|
|
|
c2d1e6 |
--- a/lib/dns/tsig.c
|
|
|
c2d1e6 |
+++ b/lib/dns/tsig.c
|
|
|
c2d1e6 |
@@ -941,11 +941,20 @@ dns_tsig_sign(dns_message_t *msg) {
|
|
|
c2d1e6 |
isc_buffer_putuint48(&otherbuf, tsig.timesigned);
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
- if (key->key != NULL && tsig.error != dns_tsigerror_badsig) {
|
|
|
c2d1e6 |
+ if ((key->key != NULL) &&
|
|
|
c2d1e6 |
+ (tsig.error != dns_tsigerror_badsig) &&
|
|
|
c2d1e6 |
+ (tsig.error != dns_tsigerror_badkey))
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
unsigned char header[DNS_MESSAGE_HEADERLEN];
|
|
|
c2d1e6 |
isc_buffer_t headerbuf;
|
|
|
c2d1e6 |
isc_uint16_t digestbits;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
+ /*
|
|
|
c2d1e6 |
+ * If it is a response, we assume that the request MAC
|
|
|
c2d1e6 |
+ * has validated at this point. This is why we include a
|
|
|
c2d1e6 |
+ * MAC length > 0 in the reply.
|
|
|
c2d1e6 |
+ */
|
|
|
c2d1e6 |
+
|
|
|
c2d1e6 |
ret = dst_context_create3(key->key, mctx,
|
|
|
c2d1e6 |
DNS_LOGCATEGORY_DNSSEC,
|
|
|
c2d1e6 |
ISC_TRUE, &ctx;;
|
|
|
c2d1e6 |
@@ -953,7 +962,7 @@ dns_tsig_sign(dns_message_t *msg) {
|
|
|
c2d1e6 |
return (ret);
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
/*
|
|
|
c2d1e6 |
- * If this is a response, digest the query signature.
|
|
|
c2d1e6 |
+ * If this is a response, digest the request's MAC.
|
|
|
c2d1e6 |
*/
|
|
|
c2d1e6 |
if (response) {
|
|
|
c2d1e6 |
dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
|
|
|
c2d1e6 |
@@ -1083,6 +1092,17 @@ dns_tsig_sign(dns_message_t *msg) {
|
|
|
c2d1e6 |
dst_context_destroy(&ctx;;
|
|
|
c2d1e6 |
digestbits = dst_key_getbits(key->key);
|
|
|
c2d1e6 |
if (digestbits != 0) {
|
|
|
c2d1e6 |
+ /*
|
|
|
c2d1e6 |
+ * XXXRAY: Is this correct? What is the
|
|
|
c2d1e6 |
+ * expected behavior when digestbits is not an
|
|
|
c2d1e6 |
+ * integral multiple of 8? It looks like bytes
|
|
|
c2d1e6 |
+ * should either be (digestbits/8) or
|
|
|
c2d1e6 |
+ * (digestbits+7)/8.
|
|
|
c2d1e6 |
+ *
|
|
|
c2d1e6 |
+ * In any case, for current algorithms,
|
|
|
c2d1e6 |
+ * digestbits are an integral multiple of 8, so
|
|
|
c2d1e6 |
+ * it has the same effect as (digestbits/8).
|
|
|
c2d1e6 |
+ */
|
|
|
c2d1e6 |
unsigned int bytes = (digestbits + 1) / 8;
|
|
|
c2d1e6 |
if (response && bytes < querytsig.siglen)
|
|
|
c2d1e6 |
bytes = querytsig.siglen;
|
|
|
c2d1e6 |
@@ -1196,6 +1216,8 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
|
|
|
c2d1e6 |
REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
msg->verify_attempted = 1;
|
|
|
c2d1e6 |
+ msg->verified_sig = 0;
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_tsigerror_badsig;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
if (msg->tcp_continuation) {
|
|
|
c2d1e6 |
if (tsigkey == NULL || msg->querytsig == NULL)
|
|
|
c2d1e6 |
@@ -1294,19 +1316,6 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
|
|
|
c2d1e6 |
key = tsigkey->key;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
/*
|
|
|
c2d1e6 |
- * Is the time ok?
|
|
|
c2d1e6 |
- */
|
|
|
c2d1e6 |
- if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
|
|
|
c2d1e6 |
- msg->tsigstatus = dns_tsigerror_badtime;
|
|
|
c2d1e6 |
- tsig_log(msg->tsigkey, 2, "signature has expired");
|
|
|
c2d1e6 |
- return (DNS_R_CLOCKSKEW);
|
|
|
c2d1e6 |
- } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) {
|
|
|
c2d1e6 |
- msg->tsigstatus = dns_tsigerror_badtime;
|
|
|
c2d1e6 |
- tsig_log(msg->tsigkey, 2, "signature is in the future");
|
|
|
c2d1e6 |
- return (DNS_R_CLOCKSKEW);
|
|
|
c2d1e6 |
- }
|
|
|
c2d1e6 |
-
|
|
|
c2d1e6 |
- /*
|
|
|
c2d1e6 |
* Check digest length.
|
|
|
c2d1e6 |
*/
|
|
|
c2d1e6 |
alg = dst_key_alg(key);
|
|
|
c2d1e6 |
@@ -1315,31 +1324,19 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
|
|
|
c2d1e6 |
return (ret);
|
|
|
c2d1e6 |
if (alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 ||
|
|
|
c2d1e6 |
alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
|
|
|
c2d1e6 |
- alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) {
|
|
|
c2d1e6 |
- isc_uint16_t digestbits = dst_key_getbits(key);
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512)
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
if (tsig.siglen > siglen) {
|
|
|
c2d1e6 |
- tsig_log(msg->tsigkey, 2, "signature length to big");
|
|
|
c2d1e6 |
+ tsig_log(msg->tsigkey, 2, "signature length too big");
|
|
|
c2d1e6 |
return (DNS_R_FORMERR);
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
if (tsig.siglen > 0 &&
|
|
|
c2d1e6 |
- (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) {
|
|
|
c2d1e6 |
+ (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2)))
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
"signature length below minimum");
|
|
|
c2d1e6 |
return (DNS_R_FORMERR);
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
- if (tsig.siglen > 0 && digestbits != 0 &&
|
|
|
c2d1e6 |
- tsig.siglen < ((digestbits + 1) / 8)) {
|
|
|
c2d1e6 |
- msg->tsigstatus = dns_tsigerror_badtrunc;
|
|
|
c2d1e6 |
- tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
- "truncated signature length too small");
|
|
|
c2d1e6 |
- return (DNS_R_TSIGVERIFYFAILURE);
|
|
|
c2d1e6 |
- }
|
|
|
c2d1e6 |
- if (tsig.siglen > 0 && digestbits == 0 &&
|
|
|
c2d1e6 |
- tsig.siglen < siglen) {
|
|
|
c2d1e6 |
- msg->tsigstatus = dns_tsigerror_badtrunc;
|
|
|
c2d1e6 |
- tsig_log(msg->tsigkey, 2, "signature length too small");
|
|
|
c2d1e6 |
- return (DNS_R_TSIGVERIFYFAILURE);
|
|
|
c2d1e6 |
- }
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
if (tsig.siglen > 0) {
|
|
|
c2d1e6 |
@@ -1451,34 +1448,92 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
ret = dst_context_verify(ctx, &sig_r);
|
|
|
c2d1e6 |
if (ret == DST_R_VERIFYFAILURE) {
|
|
|
c2d1e6 |
- msg->tsigstatus = dns_tsigerror_badsig;
|
|
|
c2d1e6 |
ret = DNS_R_TSIGVERIFYFAILURE;
|
|
|
c2d1e6 |
tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
"signature failed to verify(1)");
|
|
|
c2d1e6 |
goto cleanup_context;
|
|
|
c2d1e6 |
- } else if (ret != ISC_R_SUCCESS)
|
|
|
c2d1e6 |
+ } else if (ret != ISC_R_SUCCESS) {
|
|
|
c2d1e6 |
goto cleanup_context;
|
|
|
c2d1e6 |
-
|
|
|
c2d1e6 |
- dst_context_destroy(&ctx;;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
} else if (tsig.error != dns_tsigerror_badsig &&
|
|
|
c2d1e6 |
tsig.error != dns_tsigerror_badkey) {
|
|
|
c2d1e6 |
- msg->tsigstatus = dns_tsigerror_badsig;
|
|
|
c2d1e6 |
tsig_log(msg->tsigkey, 2, "signature was empty");
|
|
|
c2d1e6 |
return (DNS_R_TSIGVERIFYFAILURE);
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
- msg->tsigstatus = dns_rcode_noerror;
|
|
|
c2d1e6 |
+ /*
|
|
|
c2d1e6 |
+ * Here at this point, the MAC has been verified. Even if any of
|
|
|
c2d1e6 |
+ * the following code returns a TSIG error, the reply will be
|
|
|
c2d1e6 |
+ * signed and WILL always include the request MAC in the digest
|
|
|
c2d1e6 |
+ * computation.
|
|
|
c2d1e6 |
+ */
|
|
|
c2d1e6 |
+
|
|
|
c2d1e6 |
+ /*
|
|
|
c2d1e6 |
+ * Is the time ok?
|
|
|
c2d1e6 |
+ */
|
|
|
c2d1e6 |
+ if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_tsigerror_badtime;
|
|
|
c2d1e6 |
+ tsig_log(msg->tsigkey, 2, "signature has expired");
|
|
|
c2d1e6 |
+ ret = DNS_R_CLOCKSKEW;
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
+ } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) {
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_tsigerror_badtime;
|
|
|
c2d1e6 |
+ tsig_log(msg->tsigkey, 2, "signature is in the future");
|
|
|
c2d1e6 |
+ ret = DNS_R_CLOCKSKEW;
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
+
|
|
|
c2d1e6 |
+ if (
|
|
|
c2d1e6 |
+#ifndef PK11_MD5_DISABLE
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACMD5 ||
|
|
|
c2d1e6 |
+#endif
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA1 ||
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512)
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
+ isc_uint16_t digestbits = dst_key_getbits(key);
|
|
|
c2d1e6 |
+
|
|
|
c2d1e6 |
+ /*
|
|
|
c2d1e6 |
+ * XXXRAY: Is this correct? What is the expected
|
|
|
c2d1e6 |
+ * behavior when digestbits is not an integral multiple
|
|
|
c2d1e6 |
+ * of 8? It looks like bytes should either be
|
|
|
c2d1e6 |
+ * (digestbits/8) or (digestbits+7)/8.
|
|
|
c2d1e6 |
+ *
|
|
|
c2d1e6 |
+ * In any case, for current algorithms, digestbits are
|
|
|
c2d1e6 |
+ * an integral multiple of 8, so it has the same effect
|
|
|
c2d1e6 |
+ * as (digestbits/8).
|
|
|
c2d1e6 |
+ */
|
|
|
c2d1e6 |
+ if (tsig.siglen > 0 && digestbits != 0 &&
|
|
|
c2d1e6 |
+ tsig.siglen < ((digestbits + 1) / 8))
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_tsigerror_badtrunc;
|
|
|
c2d1e6 |
+ tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
+ "truncated signature length too small");
|
|
|
c2d1e6 |
+ ret = DNS_R_TSIGVERIFYFAILURE;
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
+ if (tsig.siglen > 0 && digestbits == 0 &&
|
|
|
c2d1e6 |
+ tsig.siglen < siglen)
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_tsigerror_badtrunc;
|
|
|
c2d1e6 |
+ tsig_log(msg->tsigkey, 2, "signature length too small");
|
|
|
c2d1e6 |
+ ret = DNS_R_TSIGVERIFYFAILURE;
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
if (tsig.error != dns_rcode_noerror) {
|
|
|
c2d1e6 |
+ msg->tsigstatus = tsig.error;
|
|
|
c2d1e6 |
if (tsig.error == dns_tsigerror_badtime)
|
|
|
c2d1e6 |
- return (DNS_R_CLOCKSKEW);
|
|
|
c2d1e6 |
+ ret = DNS_R_CLOCKSKEW;
|
|
|
c2d1e6 |
else
|
|
|
c2d1e6 |
- return (DNS_R_TSIGERRORSET);
|
|
|
c2d1e6 |
+ ret = DNS_R_TSIGERRORSET;
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_rcode_noerror;
|
|
|
c2d1e6 |
msg->verified_sig = 1;
|
|
|
c2d1e6 |
-
|
|
|
c2d1e6 |
- return (ISC_R_SUCCESS);
|
|
|
c2d1e6 |
+ ret = ISC_R_SUCCESS;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
cleanup_context:
|
|
|
c2d1e6 |
if (ctx != NULL)
|
|
|
c2d1e6 |
@@ -1503,6 +1558,8 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
|
|
|
c2d1e6 |
isc_uint16_t addcount, id;
|
|
|
c2d1e6 |
isc_boolean_t has_tsig = ISC_FALSE;
|
|
|
c2d1e6 |
isc_mem_t *mctx;
|
|
|
c2d1e6 |
+ unsigned int siglen;
|
|
|
c2d1e6 |
+ unsigned int alg;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
REQUIRE(source != NULL);
|
|
|
c2d1e6 |
REQUIRE(msg != NULL);
|
|
|
c2d1e6 |
@@ -1510,12 +1567,16 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
|
|
|
c2d1e6 |
REQUIRE(msg->tcp_continuation == 1);
|
|
|
c2d1e6 |
REQUIRE(msg->querytsig != NULL);
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
+ msg->verified_sig = 0;
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_tsigerror_badsig;
|
|
|
c2d1e6 |
+
|
|
|
c2d1e6 |
if (!is_response(msg))
|
|
|
c2d1e6 |
return (DNS_R_EXPECTEDRESPONSE);
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
mctx = msg->mctx;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
tsigkey = dns_message_gettsigkey(msg);
|
|
|
c2d1e6 |
+ key = tsigkey->key;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
/*
|
|
|
c2d1e6 |
* Extract and parse the previous TSIG
|
|
|
c2d1e6 |
@@ -1548,7 +1609,8 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
|
|
|
c2d1e6 |
* Do the key name and algorithm match that of the query?
|
|
|
c2d1e6 |
*/
|
|
|
c2d1e6 |
if (!dns_name_equal(keyname, &tsigkey->name) ||
|
|
|
c2d1e6 |
- !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) {
|
|
|
c2d1e6 |
+ !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
msg->tsigstatus = dns_tsigerror_badkey;
|
|
|
c2d1e6 |
ret = DNS_R_TSIGVERIFYFAILURE;
|
|
|
c2d1e6 |
tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
@@ -1557,27 +1619,40 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
/*
|
|
|
c2d1e6 |
- * Is the time ok?
|
|
|
c2d1e6 |
+ * Check digest length.
|
|
|
c2d1e6 |
*/
|
|
|
c2d1e6 |
- isc_stdtime_get(&now;;
|
|
|
c2d1e6 |
-
|
|
|
c2d1e6 |
- if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
|
|
|
c2d1e6 |
- msg->tsigstatus = dns_tsigerror_badtime;
|
|
|
c2d1e6 |
- tsig_log(msg->tsigkey, 2, "signature has expired");
|
|
|
c2d1e6 |
- ret = DNS_R_CLOCKSKEW;
|
|
|
c2d1e6 |
- goto cleanup_querystruct;
|
|
|
c2d1e6 |
- } else if (now + msg->timeadjust <
|
|
|
c2d1e6 |
- tsig.timesigned - tsig.fudge) {
|
|
|
c2d1e6 |
- msg->tsigstatus = dns_tsigerror_badtime;
|
|
|
c2d1e6 |
- tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
- "signature is in the future");
|
|
|
c2d1e6 |
- ret = DNS_R_CLOCKSKEW;
|
|
|
c2d1e6 |
+ alg = dst_key_alg(key);
|
|
|
c2d1e6 |
+ ret = dst_key_sigsize(key, &siglen);
|
|
|
c2d1e6 |
+ if (ret != ISC_R_SUCCESS)
|
|
|
c2d1e6 |
goto cleanup_querystruct;
|
|
|
c2d1e6 |
+ if (
|
|
|
c2d1e6 |
+#ifndef PK11_MD5_DISABLE
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACMD5 ||
|
|
|
c2d1e6 |
+#endif
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA1 ||
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA224 ||
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA256 ||
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA384 ||
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA512)
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
+ if (tsig.siglen > siglen) {
|
|
|
c2d1e6 |
+ tsig_log(tsigkey, 2,
|
|
|
c2d1e6 |
+ "signature length too big");
|
|
|
c2d1e6 |
+ ret = DNS_R_FORMERR;
|
|
|
c2d1e6 |
+ goto cleanup_querystruct;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
+ if (tsig.siglen > 0 &&
|
|
|
c2d1e6 |
+ (tsig.siglen < 10 ||
|
|
|
c2d1e6 |
+ tsig.siglen < ((siglen + 1) / 2)))
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
+ tsig_log(tsigkey, 2,
|
|
|
c2d1e6 |
+ "signature length below minimum");
|
|
|
c2d1e6 |
+ ret = DNS_R_FORMERR;
|
|
|
c2d1e6 |
+ goto cleanup_querystruct;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
- key = tsigkey->key;
|
|
|
c2d1e6 |
-
|
|
|
c2d1e6 |
if (msg->tsigctx == NULL) {
|
|
|
c2d1e6 |
ret = dst_context_create3(key, mctx,
|
|
|
c2d1e6 |
DNS_LOGCATEGORY_DNSSEC,
|
|
|
c2d1e6 |
@@ -1670,10 +1745,12 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
|
|
|
c2d1e6 |
sig_r.length = tsig.siglen;
|
|
|
c2d1e6 |
if (tsig.siglen == 0) {
|
|
|
c2d1e6 |
if (tsig.error != dns_rcode_noerror) {
|
|
|
c2d1e6 |
- if (tsig.error == dns_tsigerror_badtime)
|
|
|
c2d1e6 |
+ msg->tsigstatus = tsig.error;
|
|
|
c2d1e6 |
+ if (tsig.error == dns_tsigerror_badtime) {
|
|
|
c2d1e6 |
ret = DNS_R_CLOCKSKEW;
|
|
|
c2d1e6 |
- else
|
|
|
c2d1e6 |
+ } else {
|
|
|
c2d1e6 |
ret = DNS_R_TSIGERRORSET;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
} else {
|
|
|
c2d1e6 |
tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
"signature is empty");
|
|
|
c2d1e6 |
@@ -1684,29 +1761,111 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
ret = dst_context_verify(msg->tsigctx, &sig_r);
|
|
|
c2d1e6 |
if (ret == DST_R_VERIFYFAILURE) {
|
|
|
c2d1e6 |
- msg->tsigstatus = dns_tsigerror_badsig;
|
|
|
c2d1e6 |
tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
"signature failed to verify(2)");
|
|
|
c2d1e6 |
ret = DNS_R_TSIGVERIFYFAILURE;
|
|
|
c2d1e6 |
goto cleanup_context;
|
|
|
c2d1e6 |
+ } else if (ret != ISC_R_SUCCESS) {
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
- else if (ret != ISC_R_SUCCESS)
|
|
|
c2d1e6 |
+
|
|
|
c2d1e6 |
+ /*
|
|
|
c2d1e6 |
+ * Here at this point, the MAC has been verified. Even
|
|
|
c2d1e6 |
+ * if any of the following code returns a TSIG error,
|
|
|
c2d1e6 |
+ * the reply will be signed and WILL always include the
|
|
|
c2d1e6 |
+ * request MAC in the digest computation.
|
|
|
c2d1e6 |
+ */
|
|
|
c2d1e6 |
+
|
|
|
c2d1e6 |
+ /*
|
|
|
c2d1e6 |
+ * Is the time ok?
|
|
|
c2d1e6 |
+ */
|
|
|
c2d1e6 |
+ isc_stdtime_get(&now;;
|
|
|
c2d1e6 |
+
|
|
|
c2d1e6 |
+ if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_tsigerror_badtime;
|
|
|
c2d1e6 |
+ tsig_log(msg->tsigkey, 2, "signature has expired");
|
|
|
c2d1e6 |
+ ret = DNS_R_CLOCKSKEW;
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
+ } else if (now + msg->timeadjust <
|
|
|
c2d1e6 |
+ tsig.timesigned - tsig.fudge)
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_tsigerror_badtime;
|
|
|
c2d1e6 |
+ tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
+ "signature is in the future");
|
|
|
c2d1e6 |
+ ret = DNS_R_CLOCKSKEW;
|
|
|
c2d1e6 |
goto cleanup_context;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
- dst_context_destroy(&msg->tsigctx);
|
|
|
c2d1e6 |
+ alg = dst_key_alg(key);
|
|
|
c2d1e6 |
+ ret = dst_key_sigsize(key, &siglen);
|
|
|
c2d1e6 |
+ if (ret != ISC_R_SUCCESS)
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
+ if (
|
|
|
c2d1e6 |
+#ifndef PK11_MD5_DISABLE
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACMD5 ||
|
|
|
c2d1e6 |
+#endif
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA1 ||
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA224 ||
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA256 ||
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA384 ||
|
|
|
c2d1e6 |
+ alg == DST_ALG_HMACSHA512)
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
+ isc_uint16_t digestbits = dst_key_getbits(key);
|
|
|
c2d1e6 |
+
|
|
|
c2d1e6 |
+ /*
|
|
|
c2d1e6 |
+ * XXXRAY: Is this correct? What is the
|
|
|
c2d1e6 |
+ * expected behavior when digestbits is not an
|
|
|
c2d1e6 |
+ * integral multiple of 8? It looks like bytes
|
|
|
c2d1e6 |
+ * should either be (digestbits/8) or
|
|
|
c2d1e6 |
+ * (digestbits+7)/8.
|
|
|
c2d1e6 |
+ *
|
|
|
c2d1e6 |
+ * In any case, for current algorithms,
|
|
|
c2d1e6 |
+ * digestbits are an integral multiple of 8, so
|
|
|
c2d1e6 |
+ * it has the same effect as (digestbits/8).
|
|
|
c2d1e6 |
+ */
|
|
|
c2d1e6 |
+ if (tsig.siglen > 0 && digestbits != 0 &&
|
|
|
c2d1e6 |
+ tsig.siglen < ((digestbits + 1) / 8))
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_tsigerror_badtrunc;
|
|
|
c2d1e6 |
+ tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
+ "truncated signature length "
|
|
|
c2d1e6 |
+ "too small");
|
|
|
c2d1e6 |
+ ret = DNS_R_TSIGVERIFYFAILURE;
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
+ if (tsig.siglen > 0 && digestbits == 0 &&
|
|
|
c2d1e6 |
+ tsig.siglen < siglen)
|
|
|
c2d1e6 |
+ {
|
|
|
c2d1e6 |
+ msg->tsigstatus = dns_tsigerror_badtrunc;
|
|
|
c2d1e6 |
+ tsig_log(msg->tsigkey, 2,
|
|
|
c2d1e6 |
+ "signature length too small");
|
|
|
c2d1e6 |
+ ret = DNS_R_TSIGVERIFYFAILURE;
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
+
|
|
|
c2d1e6 |
+ if (tsig.error != dns_rcode_noerror) {
|
|
|
c2d1e6 |
+ msg->tsigstatus = tsig.error;
|
|
|
c2d1e6 |
+ if (tsig.error == dns_tsigerror_badtime)
|
|
|
c2d1e6 |
+ ret = DNS_R_CLOCKSKEW;
|
|
|
c2d1e6 |
+ else
|
|
|
c2d1e6 |
+ ret = DNS_R_TSIGERRORSET;
|
|
|
c2d1e6 |
+ goto cleanup_context;
|
|
|
c2d1e6 |
+ }
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
msg->tsigstatus = dns_rcode_noerror;
|
|
|
c2d1e6 |
- return (ISC_R_SUCCESS);
|
|
|
c2d1e6 |
+ msg->verified_sig = 1;
|
|
|
c2d1e6 |
+ ret = ISC_R_SUCCESS;
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
cleanup_context:
|
|
|
c2d1e6 |
- dst_context_destroy(&msg->tsigctx);
|
|
|
c2d1e6 |
+ if (msg->tsigctx != NULL)
|
|
|
c2d1e6 |
+ dst_context_destroy(&msg->tsigctx);
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
cleanup_querystruct:
|
|
|
c2d1e6 |
dns_rdata_freestruct(&querytsig);
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
return (ret);
|
|
|
c2d1e6 |
-
|
|
|
c2d1e6 |
}
|
|
|
c2d1e6 |
|
|
|
c2d1e6 |
isc_result_t
|