{"record":{"id":"c1000563aa3f3b31","repo":"TechnitiumSoftware/DnsServer","slug":"nsec3-salt-length-valid-range-is-0-32","errorCode":null,"errorMessage":"NSEC3 salt length valid range is 0-32","messagePattern":"NSEC3 salt length valid range is 0-32","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/Zones/PrimaryZone.cs","lineNumber":458,"sourceCode":"                    }\n                }\n            }\n        }\n\n        public void SignZone(DnssecPrivateKey kskPrivateKey, DnssecPrivateKey zskPrivateKey, uint dnsKeyTtl, bool useNSec3, ushort iterations = 0, byte saltLength = 0)\n        {\n            if (kskPrivateKey.KeyType != DnssecPrivateKeyType.KeySigningKey)\n                throw new ArgumentException(\"The private key must be a Key Signing Key.\", nameof(kskPrivateKey));\n\n            if (zskPrivateKey.KeyType != DnssecPrivateKeyType.ZoneSigningKey)\n                throw new ArgumentException(\"The private key must be a Zone Signing Key.\", nameof(zskPrivateKey));\n\n            byte[] salt = null;\n\n            if (useNSec3)\n            {\n                if (saltLength > 32)\n                    throw new ArgumentOutOfRangeException(nameof(saltLength), \"NSEC3 salt length valid range is 0-32\");\n\n                if (saltLength > 0)\n                {\n                    salt = new byte[saltLength];\n                    RandomNumberGenerator.Fill(salt);\n                }\n                else\n                {\n                    salt = [];\n                }\n            }\n\n            SignZone([kskPrivateKey, zskPrivateKey], dnsKeyTtl, useNSec3, iterations, salt);\n        }\n\n        public void SignZone(IReadOnlyCollection<DnssecPrivateKey> dnssecPrivateKeys, uint dnsKeyTtl, bool useNSec3, ushort iterations = 0, byte[] salt = null)\n        {\n            //do validations","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/Zones/PrimaryZone.cs#L440-L476","documentation":"Thrown by the (ksk,zsk) overload of PrimaryZone.SignZone when useNSec3 is true and saltLength > 32. RFC 5151 NSEC3 salt is bounded; the guard raises ArgumentOutOfRangeException(nameof(saltLength)) before allocating the salt buffer.","triggerScenarios":"zone.SignZone(ksk, zsk, ttl, useNSec3: true, saltLength: 64).","commonSituations":"Hardcoding an oversized salt; copying salt-length from a hash config meant for a different algorithm.","solutions":["Pass saltLength in the valid 0-32 range (0 means no salt).","Prefer a small salt (e.g., 8 bytes) — larger salts add resolver cost without security benefit.","Validate saltLength against the 0-32 bound before calling."],"exampleFix":"// before\nzone.SignZone(ksk, zsk, ttl, true, iterations: 0, saltLength: 64);\n\n// after\nint saltLength = Math.Clamp(requestedSalt, 0, 32);\nzone.SignZone(ksk, zsk, ttl, true, iterations: 0, saltLength: saltLength);","handlingStrategy":"validation","validationCode":"if (saltLength > 32) throw new ArgumentOutOfRangeException(nameof(saltLength));\nzone.SignZone(ksk, zsk, ttl, useNSec3: true, iterations, saltLength);","typeGuard":"static bool IsValidNsec3SaltLength(int len) => len >= 0 && len <= 32;","tryCatchPattern":null,"preventionTips":["Keep NSEC3 salt length within 0-32 bytes.","Prefer a small salt (0-8 bytes); larger salts add resolver cost.","Clamp the requested length before calling SignZone."],"tags":["csharp","dns","dnssec","nsec3","validation","technitium-dns"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}