TechnitiumSoftware/DnsServer · error · ArgumentException

The private key must be a Key Signing Key.

Error message

The private key must be a Key Signing Key.

What it means

Thrown by PrimaryZone.SignZone(kskPrivateKey, zskPrivateKey, ...) when the kskPrivateKey's KeyType is not DnssecPrivateKeyType.KeySigningKey. A KSK signs the DNSKEY RRset (and the DS chain), so passing a ZSK here would break the trust anchor. The guard raises ArgumentException with the 'kskPrivateKey' paramName before any signing work.

Source

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

                _dnsServer.LogManager.Write(ex);
            }
            finally
            {
                Timer dnssecTimer = _dnssecTimer;
                if (dnssecTimer is not null)
                {
                    lock (dnssecTimer)
                    {
                        dnssecTimer.Change(DNSSEC_TIMER_PERIODIC_INTERVAL, Timeout.Infinite);
                    }
                }
            }
        }

        public void SignZone(DnssecPrivateKey kskPrivateKey, DnssecPrivateKey zskPrivateKey, uint dnsKeyTtl, bool useNSec3, ushort iterations = 0, byte saltLength = 0)
        {
            if (kskPrivateKey.KeyType != DnssecPrivateKeyType.KeySigningKey)
                throw new ArgumentException("The private key must be a Key Signing Key.", nameof(kskPrivateKey));

            if (zskPrivateKey.KeyType != DnssecPrivateKeyType.ZoneSigningKey)
                throw new ArgumentException("The private key must be a Zone Signing Key.", nameof(zskPrivateKey));

            byte[] salt = null;

            if (useNSec3)
            {
                if (saltLength > 32)
                    throw new ArgumentOutOfRangeException(nameof(saltLength), "NSEC3 salt length valid range is 0-32");

                if (saltLength > 0)
                {
                    salt = new byte[saltLength];
                    RandomNumberGenerator.Fill(salt);
                }
                else
                {

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Pass a key whose KeyType == DnssecPrivateKeyType.KeySigningKey as the first argument.
  2. When generating keys, create exactly one KSK and one ZSK and label them.
  3. Validate both keys' roles before calling SignZone.

Example fix

// before
zone.SignZone(zsk1, zsk2, ttl, false);

// after
var ksk = keys.Single(k => k.KeyType == DnssecPrivateKeyType.KeySigningKey);
var zsk = keys.Single(k => k.KeyType == DnssecPrivateKeyType.ZoneSigningKey);
zone.SignZone(ksk, zsk, ttl, false);
Defensive patterns

Strategy: validation

Validate before calling

if (kskPrivateKey.KeyType != DnssecPrivateKeyType.KeySigningKey)
    throw new ArgumentException("A KeySigningKey is required.");
zone.SignZone(kskPrivateKey, zskPrivateKey, ttl, useNSec3);

Type guard

static bool IsKsk(DnssecPrivateKey k) => k.KeyType == DnssecPrivateKeyType.KeySigningKey;

Prevention

When it happens

Trigger: primaryZone.SignZone(aZsk, anotherZsk, ...) where the first argument's KeyType != KeySigningKey.

Common situations: Swapping the two key arguments; generating two ZSKs by mistake; loading keys from storage without checking their declared role.

Related errors


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