TechnitiumSoftware/DnsServer · error · ArgumentException

DNS Server TLS certificate file must contain a certificate w

Error message

DNS Server TLS certificate file must contain a certificate with private key.

What it means

Thrown by LoadDnsTlsCertificate after loading the PKCS #12 collection when no certificate in the bundle has a private key. The server iterates the collection looking for HasPrivateKey; TLS servers must present a cert with its private key, so a keyless bundle is unusable.

Source

Thrown at DnsServerCore/Dns/DnsServer.cs:1589

                default:
                    throw new ArgumentException("DNS Server TLS certificate file must be PKCS #12 formatted with .pfx or .p12 extension: " + tlsCertificatePath);
            }

            X509Certificate2Collection certificateCollection = X509CertificateLoader.LoadPkcs12CollectionFromFile(tlsCertificatePath, tlsCertificatePassword, X509KeyStorageFlags.PersistKeySet);
            X509Certificate2 serverCertificate = null;

            foreach (X509Certificate2 certificate in certificateCollection)
            {
                if (certificate.HasPrivateKey)
                {
                    serverCertificate = certificate;
                    break;
                }
            }

            if (serverCertificate is null)
                throw new ArgumentException("DNS Server TLS certificate file must contain a certificate with private key.");

            SslStreamCertificateContext certificateContext = SslStreamCertificateContext.Create(serverCertificate, certificateCollection, false);

            _dotSslServerAuthenticationOptions = new SslServerAuthenticationOptions()
            {
                ServerCertificateContext = certificateContext
            };

            _doqSslServerAuthenticationOptions = new SslServerAuthenticationOptions()
            {
                ApplicationProtocols = _doqApplicationProtocols,
                ServerCertificateContext = certificateContext
            };

            List<SslApplicationProtocol> applicationProtocols = new List<SslApplicationProtocol>();

            if (_enableDnsOverHttp3)
                applicationProtocols.Add(new SslApplicationProtocol("h3"));

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Re-export the .pfx and explicitly include the private key (Windows: 'Yes, export the private key').
  2. Rebuild with openssl including -inkey: openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out cert.pfx.
  3. Confirm privkey.pem corresponds to the certificate's public key (modulus match) before bundling.
  4. If the key lives in an HSM/KMS, use a tool that exports a key-bearing pfx, or supply a different bundle.

Example fix

# before: openssl pkcs12 -export -in cert.pem -out cert.pfx   (no -inkey)

# after
openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out cert.pfx -password pass:secret
Defensive patterns

Strategy: validation

Validate before calling

bool PfxHasPrivateKey(string path, string pass)
{
    using var col = new X509Certificate2Collection();
    col.Import(path, pass, X509KeyStorageFlags.DefaultKeySet);
    return col.OfType<X509Certificate2>().Any(c => c.HasPrivateKey);
}

Type guard

static bool CertBundleContainsPrivateKey(string pfxPath, string password)
{
    var col = new X509Certificate2Collection();
    col.Import(pfxPath, password ?? string.Empty, X509KeyStorageFlags.DefaultKeySet);
    try { return col.Cast<X509Certificate2>().Any(c => c.HasPrivateKey); }
    finally { foreach (var c in col) c.Dispose(); }
}

Try / catch

try { server.SetDnsTlsCertificate(path, pass, throwException: true); }
catch (ArgumentException ex) when (ex.Message.Contains("private key")) { log.Error("Re-export the .pfx including the private key"); }

Prevention

When it happens

Trigger: The .pfx contains only the leaf certificate or a CA chain but not the end-entity private key (common when exporting without 'include private key'), or the key was stripped for security during distribution.

Common situations: Exporting from Windows cert store without checking 'Yes, export the private key'; generating a CA bundle instead of an end-entity bundle; using a public cert downloaded from the CA website rather than the one created with the CSR.

Understand the failure class

Related errors


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