TechnitiumSoftware/DnsServer · error · DnsServerException

Failed to sign record set: {extendedDnsErrorCode}

Error message

Failed to sign record set: {extendedDnsErrorCode}

What it means

Thrown by DnssecPrivateKey.SignRRSet after DnsRRSIGRecordData.TryGetRRSetHash returns false. The hash step (RFC 4034 §3.1.8) builds the canonical RRset wire image to sign, and TryGetRRSetHash validates that image before hashing. When it fails it reports an EDnsExtendedDnsErrorCode describing exactly what was inconsistent (e.g. mixed record names/types/classes, or an RRSIG field that does not match the RRset). The message stringifies that code so the operator can see why canonicalization broke.

Source

Thrown at DnsServerCore/Dns/Dnssec/DnssecPrivateKey.cs:353

        }

        protected abstract byte[] SignHash(byte[] hash);

        protected abstract void ReadPrivateKeyFrom(BinaryReader bR);

        protected abstract void WritePrivateKeyTo(BinaryWriter bW);

        #endregion

        #region internal

        internal DnsResourceRecord SignRRSet(string signersName, IReadOnlyList<DnsResourceRecord> records, uint signatureInceptionOffset, uint signatureValidityPeriod)
        {
            DnsResourceRecord firstRecord = records[0];
            DnsRRSIGRecordData unsignedRRSigRecord = new DnsRRSIGRecordData(firstRecord.Type, _algorithm, DnsRRSIGRecordData.GetLabelCount(firstRecord.Name), firstRecord.OriginalTtlValue, Convert.ToUInt32((DateTime.UtcNow.AddSeconds(signatureValidityPeriod) - DateTime.UnixEpoch).TotalSeconds % uint.MaxValue), Convert.ToUInt32((DateTime.UtcNow.AddSeconds(-signatureInceptionOffset) - DateTime.UnixEpoch).TotalSeconds % uint.MaxValue), DnsKey.ComputedKeyTag, signersName, null);

            if (!DnsRRSIGRecordData.TryGetRRSetHash(unsignedRRSigRecord, records, out byte[] hash, out EDnsExtendedDnsErrorCode extendedDnsErrorCode))
                throw new DnsServerException("Failed to sign record set: " + extendedDnsErrorCode.ToString());

            byte[] signature = SignHash(hash);

            DnsRRSIGRecordData signedRRSigRecord = new DnsRRSIGRecordData(unsignedRRSigRecord.TypeCovered, unsignedRRSigRecord.Algorithm, unsignedRRSigRecord.Labels, unsignedRRSigRecord.OriginalTtl, unsignedRRSigRecord.SignatureExpiration, unsignedRRSigRecord.SignatureInception, unsignedRRSigRecord.KeyTag, unsignedRRSigRecord.SignersName, signature);
            return new DnsResourceRecord(firstRecord.Name, DnsResourceRecordType.RRSIG, firstRecord.Class, firstRecord.OriginalTtlValue, signedRRSigRecord);
        }

        internal void SetState(DnssecPrivateKeyState state, uint stateTransitionInTtl = 0)
        {
            if (_state >= state)
                return; //ignore; state cannot be updated to lower value

            _state = state;
            _stateChangedOn = DateTime.UtcNow;

            if (stateTransitionInTtl > 0)
                _stateTransitionBy = _stateChangedOn.AddSeconds(stateTransitionInTtl);
            else

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Inspect the extendedDnsErrorCode in the message: it names the precise canonicalization rule that failed (name/type/class mismatch). Fix the RRset so every record shares one name, one type, one class.
  2. Verify the records list is non-empty and homogeneous before calling SignRRSet; filter out RRSIG/CNAME/NSEC entries that do not belong to the RRset being signed.
  3. Check that the DnsKey key tag, algorithm, and signersName on the signing key match what the RRset expects.
  4. If the error appears during automatic zone signing, open the zone in the web console, find the offending record set (the zone log names it), correct or delete it, and re-trigger signing.

Example fix

// before
var rrsig = key.SignRRSet(zoneName, allRecords, -300, 30 * 86400); // allRecords mixes A + AAAA + CNAME

// after
var aRecords = allRecords.Where(r => r.Type == DnsResourceRecordType.A)
                          .Where(r => r.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
                          .ToList();
if (aRecords.Count > 0)
    var rrsig = key.SignRRSet(zoneName, aRecords, -300, 30 * 86400);
Defensive patterns

Strategy: validation

Validate before calling

// Validate an RRset is canonical before signing.
static bool IsValidRrsetForSigning(IReadOnlyList<DnsResourceRecord> records)
{
    if (records is null || records.Count == 0) return false;
    string name = records[0].Name;
    var type = records[0].Type;
    var cls = records[0].Class;
    for (int i = 1; i < records.Count; i++)
    {
        if (!records[i].Name.Equals(name, StringComparison.OrdinalIgnoreCase)) return false;
        if (records[i].Type != type) return false;
        if (records[i].Class != cls) return false;
        // RRSIG/CNAME/NSEC must not be in the RRset being signed
        if (records[i].Type == DnsResourceRecordType.RRSIG ||
            records[i].Type == DnsResourceRecordType.CNAME ||
            records[i].Type == DnsResourceRecordType.NSEC) return false;
    }
    return true;
}

Try / catch

// Catch only around the signing call; log extendedDnsErrorCode and skip the RRset.
try
{
    var rrsig = key.SignRRSet(signer, rrset, inceptionOffset, validity);
}
catch (DnsServerException ex) when (ex.Message.StartsWith("Failed to sign record set:"))
{
    _log.Error($"Skipped signing RRset {rrset[0].Name} {rrset[0].Type}: {ex.Message}");
}

Prevention

When it happens

Trigger: Calling SignRRSet(signersName, records, ...) with a records list whose members do not form a valid RRset: more than one name, more than one type, mismatched class, CNAME/RRSIG/NSEC records mixed in, an empty list (records[0] already IndexOutOfRange before this), or an unsignedRRSigRecord whose TypeCovered/KeyTag/SignersName disagree with the records. It can also fire if the underlying ManagedDns canonicalization rejects the input.

Common situations: A zone signing pass encounters corrupt or hand-edited authoritative records; a custom App that assembles an RRset to sign groups unrelated records together; a downgrade then upgrade cycle left records whose canonical form changed; DNSSEC signing a zone with CNAME chains mistakenly placed in one RRset.

Related errors


AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13). Data as JSON: /api/errors/8aa942f79e6988d7. Report an issue: GitHub.