if (!ctx)
return -ENOMEM;
+ /* If the signature algorithm is supported by systemd-resolved but disabled by host policy,
+ * also return -EOPNOTSUPP. */
if (EVP_DigestInit_ex(ctx, md_algorithm, NULL) <= 0)
- return -EIO;
+ return -EOPNOTSUPP;
if (EVP_DigestUpdate(ctx, sig_data, sig_size) <= 0)
return -EIO;
DNS_ANSWER_FOREACH_FLAGS(dnskey, flags, validated_dnskeys) {
DnssecResult one_result;
- if ((flags & DNS_ANSWER_AUTHENTICATED) == 0)
- continue;
-
/* Is this a DNSKEY RR that matches they key of our RRSIG? */
r = dnssec_rrsig_match_dnskey(rrsig, dnskey, false);
if (r < 0)
if (r == 0)
continue;
+ if ((flags & DNS_ANSWER_AUTHENTICATED) == 0) {
+ /* An unauthenticated DNSKEY in validated_dnskeys is a key we are not able to
+ * authenticate, but might still be valid. Record this as an unsupported
+ * algorithm so we can still at least report an insecure answer. */
+ found_unsupported_algorithm = true;
+ continue;
+ }
+
/* Take the time here, if it isn't set yet, so
* that we do all validations with the same
* time. */
return -ENOMEM;
if (EVP_DigestInit_ex(ctx, algorithm, NULL) <= 0)
- return -EIO;
+ return -EOPNOTSUPP;
r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true);
if (r < 0)
for (unsigned k = 0; k < nsec3->nsec3.iterations; k++) {
if (EVP_DigestInit_ex(ctx, algorithm, NULL) <= 0)
- return -EIO;
+ return -EOPNOTSUPP;
if (EVP_DigestUpdate(ctx, result, hash_size) <= 0)
return -EIO;
if (EVP_DigestUpdate(ctx, nsec3->nsec3.salt, nsec3->nsec3.salt_size) <= 0)
if (DNS_TRANSACTION_IS_LIVE(dt->state))
continue;
+ /* Some of the validated keys may not be authenticated, but are still useful to report
+ * insecure answers when the domain is signed only by unsupported algorithms. */
+ r = dns_answer_extend(&t->validated_keys, dt->validated_keys);
+ if (r < 0)
+ return r;
+
if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED))
continue;
/* https://datatracker.ietf.org/doc/html/rfc6840#section-5.2 */
if (result == DNSSEC_UNSUPPORTED_ALGORITHM) {
+ if (rr->key->type == DNS_TYPE_DNSKEY) {
+ /* This is a DNSKEY we cannot authenticate, but it might still be the best
+ * offer from the resolver. Add it to the validated keys in case it's the
+ * best we can find, but do not mark it as authenticated.
+ */
+
+ r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, 0, NULL);
+ if (r < 0)
+ return r;
+
+ /* Some of the DNSKEYs we just added might already have been revoked,
+ * remove them again in that case. */
+ r = dns_transaction_invalidate_revoked_keys(t);
+ if (r < 0)
+ return r;
+ }
+
r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0, NULL);
if (r < 0)
return r;