I have set up a test C# Https Listener using a self-signed certificate (followed advice in Httplistener with https support ).
The service (runs as a windows service under Local System) and initially (after startup) works well. After a certain period of time (~1.5 hours) calls to https endpoint stop working with Edge/IE complaining:
Can’t connect securely to this page This might be because the site uses outdated or unsafe TLS security settings. If this keeps happening, try contacting the website’s owner.
Chrome complains as follows:
This site can’t be reached The connection was reset. ERR_CONNECTION_RESET
When this happens, checking the certificate store shows that certificates (in Root and My stores) are still present.
Checking the
netsh http show sslcert
Also shows that the registration of the certificate to the port is still in place.
Re-starting the application (re-creating, re-installing and re-bindin certificate to port on which C# http(s) listener listens) helps, but until the next hiccup which may happen in some time (~1.5..2 hours?).
I know that the listener thread is still alive as requests on an unsecure port still work.
Something happens in the meantime and I can't figure out what...
Code:
All starts with a generation of a self-signed certificate:
// create DN for subject and issuer
var dn = new CX500DistinguishedName();
dn.Encode("CN=localhost");
// create a new private key for the certificate
var privateKey = new CX509PrivateKey
{
ProviderName = "Microsoft Base Cryptographic Provider v1.0",
MachineContext = false,
Length = 2048,
KeySpec = X509KeySpec.XCN_AT_SIGNATURE,
KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_SIGNING_FLAG,
FriendlyName = "Application Testing Key",
ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG
};
privateKey.Create();
var hashobj = new CObjectId();
hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID,
ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY,
AlgorithmFlags.AlgorithmFlagsNone, "SHA256");
// Create the self signing request
var certificateRequest = new CX509CertificateRequestCertificate();
certificateRequest.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextUser, privateKey, String.Empty);
certificateRequest.Subject = dn;
certificateRequest.Issuer = dn; // the issuer and the subject are the same
certificateRequest.NotBefore = DateTime.UtcNow.AddDays(-1);
certificateRequest.NotAfter = DateTime.UtcNow.AddYears(10);
certificateRequest.HashAlgorithm = hashobj;
// Set up the Subject Alternative Names extension.
var nameslist = new CAlternativeNames();
var alternativeName = new CAlternativeName();
alternativeName.InitializeFromString(AlternativeNameType.XCN_CERT_ALT_NAME_DNS_NAME, "localhost");
nameslist.Add(alternativeName);
var subjectAlternativeNamesExtension = new CX509ExtensionAlternativeNames();
subjectAlternativeNamesExtension.InitializeEncode(nameslist);
certificateRequest.X509Extensions.Add((CX509Extension)subjectAlternativeNamesExtension);
var skiExtension = new CX509ExtensionSubjectKeyIdentifier();
skiExtension.InitializeEncode(EncodingType.XCN_CRYPT_STRING_BASE64, Convert.ToBase64String(StringToByteArray(certSKI)));
certificateRequest.X509Extensions.Add((CX509Extension)skiExtension);
certificateRequest.Encode();
// Do the final enrollment process
var enroll = new CX509Enrollment();
enroll.InitializeFromRequest(certificateRequest); // load the certificate
enroll.CertificateFriendlyName = "Application Testing Cert";
var csr = enroll.CreateRequest(); // Output the request in base64
var pwd = Guid.NewGuid().ToString();
enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate, csr, EncodingType.XCN_CRYPT_STRING_BASE64, pwd); // and install it back as the response
var base64encoded = enroll.CreatePFX(pwd, PFXExportOptions.PFXExportChainWithRoot);
// instantiate the target class with the PKCS#12 data
return new X509Certificate2(Convert.FromBase64String(base64encoded), pwd);
Followed by adding a newly-generated certificate to localhost Root and Private store:
InstallCertificateToCertStore(cert, new X509Store(StoreName.Root, StoreLocation.LocalMachine));
InstallCertificateToCertStore(cert, new X509Store(StoreName.My, StoreLocation.LocalMachine));
Followed by registering a newly created and installed cert to a port on which Http Listener listens:
netsh.exe http add sslcert ipport=0.0.0.0:{port} certhash={certThumbprint} appid={appid_guid}