void val_log_rrsig_rdata(const val_context_t * ctx, int level, const char *prefix, val_rrsig_rdata_t * rdata) { char ctime_buf1[1028], ctime_buf2[1028]; char buf[1028]; struct timeval tv_sig1, tv_sig2; if (rdata) { if (!prefix) prefix = ""; memset(&tv_sig1, 0, sizeof(tv_sig1)); memset(&tv_sig2, 0, sizeof(tv_sig2)); tv_sig1.tv_sec = rdata->sig_expr; tv_sig2.tv_sec = rdata->sig_incp; GET_TIME_BUF((const time_t *)(&tv_sig1.tv_sec), ctime_buf1); GET_TIME_BUF((const time_t *)(&tv_sig2.tv_sec), ctime_buf2); val_log(ctx, level, "%s Type=%d Algo=%d[%s] Labels=%d OrgTTL=%d " "SigExp=%s SigIncp=%s KeyTag=%d[0x %04x] Signer=%s Sig=%s", prefix, rdata->algorithm, get_algorithm_string(rdata->algorithm), rdata->labels, rdata->orig_ttl, ctime_buf1, ctime_buf2, rdata->key_tag, rdata->key_tag, rdata->signer_name, get_base64_string(rdata->signature, rdata->signature_len, buf, 1024)); } }
void val_log_assertion_pfx(const val_context_t * ctx, int level, const char *prefix, const char * name_pr, struct val_authentication_chain *next_as) { char name_buf[INET6_ADDRSTRLEN + 1]; const char *serv_pr; int tag = 0; int class_h; int type_h; struct val_rr_rec *data; struct sockaddr *serv; val_astatus_t status; struct val_rr_rec *curkey; #undef VAL_LOG_SIG #ifdef VAL_LOG_SIG struct val_rr_rec *sig; struct val_rr_rec *cursig; #endif if (next_as == NULL) return; class_h = next_as->val_ac_rrset->val_rrset_class; type_h = next_as->val_ac_rrset->val_rrset_type; data = next_as->val_ac_rrset->val_rrset_data; #ifdef VAL_LOG_SIG sig = next_as->val_ac_rrset->val_rrset_sig; #endif serv = next_as->val_ac_rrset->val_rrset_server; status = next_as->val_ac_status; if (NULL == prefix) prefix = ""; if (serv) serv_pr = ((serv_pr = val_get_ns_string(serv, name_buf, sizeof(name_buf))) == NULL) ? "VAL_CACHE" : serv_pr; else serv_pr = "NULL"; if (type_h == ns_t_dnskey) { for (curkey = data; curkey; curkey = curkey->rr_next) { if ((curkey->rr_status == VAL_AC_VERIFIED_LINK) || (curkey->rr_status == VAL_AC_TRUST_POINT) || (curkey->rr_status == VAL_AC_UNKNOWN_ALGORITHM_LINK)) { /* * Extract the key tag */ val_dnskey_rdata_t dnskey; if (VAL_NO_ERROR != val_parse_dnskey_rdata(curkey->rr_rdata, curkey->rr_rdata_length, &dnskey)) { val_log(ctx, LOG_INFO, "val_log_assertion_pfx(): Cannot parse DNSKEY data"); } else { tag = dnskey.key_tag; if (dnskey.public_key) FREE(dnskey.public_key); } break; } } } if (tag != 0) { val_log(ctx, level, "%sname=%s class=%s type=%s[tag=%d] from-server=%s " "status=%s:%d", prefix, name_pr, p_class(class_h), p_type(type_h), tag, serv_pr, p_ac_status(status), status); } else { val_log(ctx, level, "%sname=%s class=%s type=%s from-server=%s status=%s:%d", prefix, name_pr, p_class(class_h), p_type(type_h), serv_pr, p_ac_status(status), status); } #ifdef VAL_LOG_SIG for (cursig = sig; cursig; cursig = cursig->rr_next) { char incpTime[1028]; char exprTime[1028]; struct timeval tv_sig; val_rrsig_rdata_t rrsig; val_parse_rrsig_rdata(cursig->rr_rdata, cursig->rr_rdata_length, &rrsig); memset(&tv_sig, 0, sizeof(tv_sig)); tv_sig.tv_sec = rrsig.sig_incp; GET_TIME_BUF((const time_t *)(&tv_sig.tv_sec), incpTime); memset(&tv_sig, 0, sizeof(tv_sig)); tv_sig.tv_sec = rrsig.sig_expr; GET_TIME_BUF((const time_t *)(&tv_sig.tv_sec), exprTime); val_log(ctx, level, "%s ->tag=%d status=%s sig-incep=%s sig-expr=%s", prefix, rrsig.key_tag, p_ac_status(cursig->rr_status), incpTime, exprTime); } #endif #ifdef VAL_LOG_SIG struct val_rr_rec *rr; struct val_rr_rec *sig = next_as->val_ac_rrset->val_rrset_sig; for (rr = data; rr; rr = rr->rr_next) { val_log(ctx, level, " data_status=%s:%d", p_ac_status(rr->rr_status), rr->rr_status); } for (rr = sig; rr; rr = rr->rr_next) { val_log(ctx, level, " sig_status=%s:%d", p_ac_status(rr->rr_status), rr->rr_status); } #endif }
/* * Verify a signature, given the data and the dnskey */ static int val_sigverify(val_context_t * ctx, int is_a_wildcard, const u_char *data, size_t data_len, const val_dnskey_rdata_t * dnskey, const val_rrsig_rdata_t * rrsig, val_astatus_t * dnskey_status, val_astatus_t * sig_status, int clock_skew) { struct timeval tv; struct timeval tv_sig; /** Inputs to this function have already been NULL-checked **/ /* * Check if the dnskey is a zone key */ if ((dnskey->flags & ZONE_KEY_FLAG) == 0) { val_log(ctx, LOG_INFO, "val_sigverify(): DNSKEY with tag=%d is not a zone key", dnskey->key_tag); *dnskey_status = VAL_AC_INVALID_KEY; return 0; } /* * Check dnskey protocol value */ if (dnskey->protocol != 3) { val_log(ctx, LOG_INFO, "val_sigverify(): Invalid protocol field in DNSKEY with tag=%d: %d", dnskey->protocol, dnskey->key_tag); *dnskey_status = VAL_AC_UNKNOWN_DNSKEY_PROTOCOL; return 0; } /* * Match dnskey and rrsig algorithms */ if (dnskey->algorithm != rrsig->algorithm) { val_log(ctx, LOG_INFO, "val_sigverify(): Algorithm mismatch between DNSKEY (%d) and RRSIG (%d) records.", dnskey->algorithm, rrsig->algorithm); *sig_status = VAL_AC_RRSIG_ALGORITHM_MISMATCH; return 0; } if (clock_skew >= 0) { /* * Check signature inception and expiration times */ gettimeofday(&tv, NULL); if (tv.tv_sec < rrsig->sig_incp) { if (tv.tv_sec < rrsig->sig_incp - clock_skew) { char currTime[1028]; char incpTime[1028]; memset(&tv_sig, 0, sizeof(tv_sig)); tv_sig.tv_sec = rrsig->sig_incp; GET_TIME_BUF((const time_t *)(&tv.tv_sec), currTime); GET_TIME_BUF((const time_t *)(&tv_sig.tv_sec), incpTime); val_log(ctx, LOG_INFO, "val_sigverify(): Signature not yet valid. Current time (%s) is less than signature inception time (%s).", currTime, incpTime); *sig_status = VAL_AC_RRSIG_NOTYETACTIVE; return 0; } else { val_log(ctx, LOG_DEBUG, "val_sigverify(): Signature not yet valid, but within acceptable skew."); } } if (tv.tv_sec > rrsig->sig_expr) { if (tv.tv_sec > rrsig->sig_expr + clock_skew) { char currTime[1028]; char exprTime[1028]; memset(&tv_sig, 0, sizeof(tv_sig)); tv_sig.tv_sec = rrsig->sig_expr; memset(currTime, 0, sizeof(currTime)); memset(exprTime, 0, sizeof(exprTime)); GET_TIME_BUF((const time_t *)(&tv.tv_sec), currTime); GET_TIME_BUF((const time_t *)(&tv_sig.tv_sec), exprTime); val_log(ctx, LOG_INFO, "val_sigverify(): Signature expired. Current time (%s) is greater than signature expiration time (%s).", currTime, exprTime); *sig_status = VAL_AC_RRSIG_EXPIRED; return 0; } else { val_log(ctx, LOG_DEBUG, "val_sigverify(): Signature expired, but within acceptable skew."); } } } else { val_log(ctx, LOG_DEBUG, "val_sigverify(): Not checking inception and expiration times on signatures."); } switch (rrsig->algorithm) { case ALG_RSAMD5: rsamd5_sigverify(ctx, data, data_len, dnskey, rrsig, dnskey_status, sig_status); break; #ifdef LIBVAL_NSEC3 case ALG_NSEC3_DSASHA1: #endif case ALG_DSASHA1: dsasha1_sigverify(ctx, data, data_len, dnskey, rrsig, dnskey_status, sig_status); break; #ifdef LIBVAL_NSEC3 case ALG_NSEC3_RSASHA1: #endif case ALG_RSASHA1: #ifdef HAVE_SHA_2 case ALG_RSASHA256: case ALG_RSASHA512: #endif rsasha_sigverify(ctx, data, data_len, dnskey, rrsig, dnskey_status, sig_status); break; #if defined(HAVE_SHA_2) && defined(HAVE_OPENSSL_ECDSA_H) case ALG_ECDSAP256SHA256: case ALG_ECDSAP384SHA384: ecdsa_sigverify(ctx, data, data_len, dnskey, rrsig, dnskey_status, sig_status); break; #endif default: val_log(ctx, LOG_INFO, "val_sigverify(): Unsupported algorithm %d.", rrsig->algorithm); *sig_status = VAL_AC_ALGORITHM_NOT_SUPPORTED; *dnskey_status = VAL_AC_ALGORITHM_NOT_SUPPORTED; break; } if (*sig_status == VAL_AC_RRSIG_VERIFIED) { if (is_a_wildcard) { val_log(ctx, LOG_DEBUG, "val_sigverify(): Verified RRSIG is for a wildcard"); if (clock_skew > 0) *sig_status = VAL_AC_WCARD_VERIFIED_SKEW; else *sig_status = VAL_AC_WCARD_VERIFIED; } else { if (clock_skew > 0) *sig_status = VAL_AC_RRSIG_VERIFIED_SKEW; } return 1; } return 0; }