TechnitiumSoftware/DnsServer · error · ArgumentException

The private keys must contain at least one Zone Signing Key.

Error message

The private keys must contain at least one Zone Signing Key.

What it means

Companion to error 516: thrown by the collection overload PrimaryZone.SignZone when no key in dnssecPrivateKeys has KeyType == ZoneSigningKey. Without a ZSK the non-DNSKEY RRsets cannot be signed, so the guard raises ArgumentException(nameof(dnssecPrivateKeys)) right after the KSK check.

Source

Thrown at DnsServerCore/Dns/Zones/PrimaryZone.cs:510

            foreach (DnssecPrivateKey dnssecPrivateKey in dnssecPrivateKeys)
            {
                switch (dnssecPrivateKey.KeyType)
                {
                    case DnssecPrivateKeyType.KeySigningKey:
                        foundKsk = true;
                        break;

                    case DnssecPrivateKeyType.ZoneSigningKey:
                        foundZsk = true;
                        break;
                }
            }

            if (!foundKsk)
                throw new ArgumentException("The private keys must contain at least one Key Signing Key.", nameof(dnssecPrivateKeys));

            if (!foundZsk)
                throw new ArgumentException("The private keys must contain at least one Zone Signing Key.", nameof(dnssecPrivateKeys));

            //load dnssec private keys
            _dnssecPrivateKeys = new Dictionary<ushort, DnssecPrivateKey>(dnssecPrivateKeys.Count);

            foreach (DnssecPrivateKey dnssecPrivateKey in dnssecPrivateKeys)
                _dnssecPrivateKeys.Add(dnssecPrivateKey.KeyTag, dnssecPrivateKey);

            //start zone signing
            List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();
            List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();

            try
            {
                IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetApexZoneWithSubDomainZones(_name);

                //find max record ttl in zone
                uint maxRecordTtl = 0;

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Include at least one ZoneSigningKey in the collection.
  2. Validate both roles are present before signing.
  3. Use the (ksk, zsk) overload for the common single-KSK/single-ZSK case.

Example fix

// before
zone.SignZone(new[] { ksk }, ttl, false);

// after
zone.SignZone(new[] { ksk, zsk }, ttl, false);
Defensive patterns

Strategy: validation

Validate before calling

if (!dnssecPrivateKeys.Any(k => k.KeyType == DnssecPrivateKeyType.ZoneSigningKey))
    throw new ArgumentException("At least one ZSK required.");
zone.SignZone(dnssecPrivateKeys, ttl, useNSec3);

Type guard

static bool HasZsk(IEnumerable<DnssecPrivateKey> ks) => ks.Any(k => k.KeyType == DnssecPrivateKeyType.ZoneSigningKey);

Prevention

When it happens

Trigger: zone.SignZone(kskOnlyList, ...) — a collection with only KeySigningKey entries.

Common situations: Creating one KSK and forgetting the ZSK; key-roll scripts that provision only the trust anchor.

Related errors


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