{"record":{"id":"a41da2c21b96554c","repo":"TechnitiumSoftware/DnsServer","slug":"web-service-tls-certificate-file-must-contain-a-ce","errorCode":null,"errorMessage":"Web Service TLS certificate file must contain a certificate with private key.","messagePattern":"Web Service TLS certificate file must contain a certificate with private key\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/DnsWebService.cs","lineNumber":2710,"sourceCode":"\n                default:\n                    throw new ArgumentException(\"Web Service TLS certificate file must be PKCS #12 formatted with .pfx or .p12 extension: \" + tlsCertificatePath);\n            }\n\n            X509Certificate2Collection certificateCollection = X509CertificateLoader.LoadPkcs12CollectionFromFile(tlsCertificatePath, tlsCertificatePassword, X509KeyStorageFlags.PersistKeySet);\n            X509Certificate2 serverCertificate = null;\n\n            foreach (X509Certificate2 certificate in certificateCollection)\n            {\n                if (certificate.HasPrivateKey)\n                {\n                    serverCertificate = certificate;\n                    break;\n                }\n            }\n\n            if (serverCertificate is null)\n                throw new ArgumentException(\"Web Service TLS certificate file must contain a certificate with private key.\");\n\n            List<SslApplicationProtocol> applicationProtocols = new List<SslApplicationProtocol>();\n\n            if (_webServiceEnableHttp3)\n                applicationProtocols.Add(new SslApplicationProtocol(\"h3\"));\n\n            if (IsHttp2Supported())\n                applicationProtocols.Add(new SslApplicationProtocol(\"h2\"));\n\n            applicationProtocols.Add(new SslApplicationProtocol(\"http/1.1\"));\n\n            _webServiceSslServerAuthenticationOptions = new SslServerAuthenticationOptions\n            {\n                ApplicationProtocols = applicationProtocols,\n                ServerCertificateContext = SslStreamCertificateContext.Create(serverCertificate, certificateCollection, false)\n            };\n\n            _webServiceCertificateLastModifiedOn = fileInfo.LastWriteTimeUtc;","sourceCodeStart":2692,"sourceCodeEnd":2728,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/DnsWebService.cs#L2692-L2728","documentation":"ArgumentException thrown by LoadWebServiceTlsCertificate when none of the certificates in the loaded PKCS #12 collection has a private key. The loader scans the collection for a cert with HasPrivateKey; without one the server cannot present a TLS endpoint, so it aborts.","triggerScenarios":"Supplying a .pfx/.p12 that contains only public certificates (e.g. a CA chain) and no end-entity certificate with its private key, or a bundle where the private key was not exported.","commonSituations":"Exported the PFX without checking 'include private key'; exported only the chain; password-protected bundle opened but key absent; cert renewed and only public part re-bundled.","solutions":["Re-export the PFX including the private key (mark key as exportable) from the source store/CA.","Verify with openssl: 'openssl pkcs12 -in cert.pfx -info -noout' should list a private key.","Re-issue/renew the certificate with an exportable private key if the key is non-exportable."],"exampleFix":"# re-export including the private key\nopenssl pkcs12 -export -in server.crt -inkey server.key -out server.pfx\n# verify a private key is present\nopenssl pkcs12 -in server.pfx -info -noout -passin pass:****","handlingStrategy":"validation","validationCode":"using var coll = new X509Certificate2Collection();\ncoll.Import(webServiceTlsCertificatePath, password, X509KeyStorageFlags.DefaultKeySet);\nbool hasPrivate = coll.Cast<X509Certificate2>().Any(c => c.HasPrivateKey);\nif (!hasPrivate)\n    throw new ArgumentException(\"PFX must contain a certificate with a private key.\");","typeGuard":"static bool PfxHasPrivateKey(string path, string password)\n{\n    var coll = new X509Certificate2Collection();\n    coll.Import(path, password, X509KeyStorageFlags.DefaultKeySet);\n    return coll.Cast<X509Certificate2>().Any(c => c.HasPrivateKey);\n}","tryCatchPattern":"null","preventionTips":["When exporting PFX, tick 'include private key' and 'mark key as exportable'.","Validate the PFX with openssl before deploying.","Renew/re-export certificates with an exportable private key."],"tags":["dns-server","technitium","tls","certificate","private-key","pkcs12","csharp"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}