WebSocket Self-Signed Security Certificate Certificate

A goal is a web application that communicates with a C # application that is installed on a user's PC. The client application is the websocket server, and the browser is the websocket client.

In the end, the websocket client in the user browser is constantly created using Angular, and the application runs on the computer and performs some actions.

Used C # WebSocket-Sharp library. The websocket client is plain javascript.

Obviously, this connection only happens locally, so the client connects to localhost. Since the website is protected via HTTPS, websocket must also be protected. To do this, the C # application creates a certificate at startup (this is just for testing purposes).

The connection does not work because the certificate is not trusted. All server checks for the client are disabled, but the connection will not be established.

This is the part where the server is created.

_server = new WebSocketServer($"wss://localhost:4649") { SslConfiguration = { ServerCertificate = Utils.Certificate.CreateSelfSignedCert(), ClientCertificateRequired = false, CheckCertificateRevocation = false, ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true } }; _server.AddWebSocketService<CommandsBehaviour>("/commands"); _server.AddWebSocketService<NotificationsBehaviour>("/notifications"); _server.Start(); 

Here's how to create a certificate using BouncyCastle

 private static AsymmetricKeyParameter CreatePrivateKey(string subjectName = "CN=root") { const int keyStrength = 2048; // Generating Random Numbers var randomGenerator = new CryptoApiRandomGenerator(); var random = new SecureRandom(randomGenerator); // The Certificate Generator var certificateGenerator = new X509V3CertificateGenerator(); // Serial Number var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random); certificateGenerator.SetSerialNumber(serialNumber); // Issuer and Subject Name var subjectDn = new X509Name(subjectName); var issuerDn = subjectDn; certificateGenerator.SetIssuerDN(issuerDn); certificateGenerator.SetSubjectDN(subjectDn); // Valid For var notBefore = DateTime.UtcNow.Date; var notAfter = notBefore.AddYears(70); certificateGenerator.SetNotBefore(notBefore); certificateGenerator.SetNotAfter(notAfter); // Subject Public Key var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); var keyPairGenerator = new RsaKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); var subjectKeyPair = keyPairGenerator.GenerateKeyPair(); return subjectKeyPair.Private; } public static X509Certificate2 CreateSelfSignedCert(string subjectName = "CN=localhost", string issuerName = "CN=root") { const int keyStrength = 2048; var issuerPrivKey = CreatePrivateKey(); // Generating Random Numbers var randomGenerator = new CryptoApiRandomGenerator(); var random = new SecureRandom(randomGenerator); ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerPrivKey, random); // The Certificate Generator var certificateGenerator = new X509V3CertificateGenerator(); certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName, false, new GeneralNames(new GeneralName[] { new GeneralName(GeneralName.DnsName, "localhost"), new GeneralName(GeneralName.DnsName, "127.0.0.1") })); certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage((new ArrayList() { new DerObjectIdentifier("1.3.6.1.5.5.7.3.1") }))); // Serial Number var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); certificateGenerator.SetSerialNumber(serialNumber); // Signature Algorithm //const string signatureAlgorithm = "SHA512WITHRSA"; //certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm); // Issuer and Subject Name var subjectDn = new X509Name(subjectName); var issuerDn = new X509Name(issuerName); certificateGenerator.SetIssuerDN(issuerDn); certificateGenerator.SetSubjectDN(subjectDn); // Valid For var notBefore = DateTime.UtcNow.Date; var notAfter = notBefore.AddYears(70); certificateGenerator.SetNotBefore(notBefore); certificateGenerator.SetNotAfter(notAfter); // Subject Public Key var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); var keyPairGenerator = new RsaKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); var subjectKeyPair = keyPairGenerator.GenerateKeyPair(); certificateGenerator.SetPublicKey(subjectKeyPair.Public); // self sign certificate var certificate = certificateGenerator.Generate(signatureFactory); // corresponding private key var info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private); // merge into X509Certificate2 var x509 = new X509Certificate2(certificate.GetEncoded()); var seq = (Asn1Sequence)Asn1Object.FromByteArray(info.ParsePrivateKey().GetDerEncoded()); if (seq.Count != 9) { throw new PemException("malformed sequence in RSA private key"); } var rsa = RsaPrivateKeyStructure.GetInstance(seq); //new RsaPrivateKeyStructure(seq); var rsaparams = new RsaPrivateCrtKeyParameters( rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient); x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams); return x509; } 

This behavior is logical, although strange, since certificate verification should not be performed locally. Is there any way around this problem? I already thought about installing the issuer certificate with trusted certificates, but this is not the best solution.

+7
c # websocket
source share
2 answers

Have you tried any answers to this question ?

To summarize, there seem to be a few options you could try:

  • Launch Chrome with the specified argument --ignore-certificate-errors .

  • Start the HTTP server on the same port that takes the same self-signed certificate, looks at it and accepts the certificate, after which you can use the WebSocket connection.

  • Set the configuration parameter in Firefox network.websocket.allowInsecureFromHTTPS to true , then use ws:// rather than the wss:// address.

If all this is for testing, and you have the ability to control it, I think one or more of them should work. If you need your standard end user to be able to do this, I think you will need a different solution. As you find, it does not matter if you configured the server not to care about the certificate, the client must ultimately decide whether he wants to accept the certificate or he will not accept the connection.

+4
source share
The answers

@Kdawg are true.

You have no hope that client browsers accept an insecure connection with only server-side configuration. All behavior when accepting an unsigned (or self-signed) certificate is on the client side.

I would like to add, in addition to @Kdawg, the answer that on Windows networks the most common practice for private organizations is:

  • Designate Windows Server to act as a certification authority

  • Add a public certificate authority root certificate to Windows hosts (or a GPO ) or manually

  • Sign a custom certificate with a Windows CA server

It sounds excruciating, and it is.

If I were you, I would go for the creation of a standard publicly signed certificate and start SSL until it is completed.

See Enable encryption for free SSL certificates for your domain.

+4
source share

All Articles