https.createServer error: SSL_CTX_use_certificate: ca md too weak - node.js

I am trying to implement peer certificate validation in node.js with express.
In the production i receive error: EE certificate key too weak.
How can i change it to support the weak key?
I don't want to ignore it in the code level, because if i am doing that it does not check the CA at all.
In the development server, if i remove the matching CA certificate i receive UNABLE_TO_VERIFY_LEAF_SIGNATURE, while in the production server i receive "EE certificate key too weak" - it does not check it at all.
In the development server it is working correctly, but in the production server i receive the error.
I cannot change the certificate on the client devices, so i must support the weak key.
https.createServer({
key: getFile(config.get("ssl_certificate.key")),
cert: getFile(config.get("ssl_certificate.cert")),
ca: [
getCACertFile('ca-crt.pem'), //some certificates
],
requestCert: true,
rejectUnauthorized: false
},app)
In req.socket.authorizationError, i expect to receive null.
In the development server i receive null, but in the production server i receive "EE certificate key too weak"
stderrs:
error: failed to start server: Error: error:140AB18E:SSL routines:SSL_CTX_use_certificate:ca md too weak
at Object.createSecureContext (_tls_common.js:135:17)
at Server (_tls_wrap.js:873:27)
at new Server (https.js:62:14)
at Object.createServer (https.js:85:10)

Node v10.0.0 Release News
Dependencies
V8 has been updated to 6.6. [9daebb48d6]
OpenSSL has been updated to 1.1.0h. [66cb29e646]
If you are using Node.js>=10.0.0, it will raise the exception if certs are encrypted by sha1 or md5.
Generate new certs encrypted by sha256 will fix the question on Server.
But in your case, since the certs has been used for devices to connect to server, you can simply use Node.js<10.0.0 (eg:v8.x) to start the server.
Besides, suggest to use nvm to control versions of Node.js.
nvm use v8.x.x
node server.js

Two aspects of your typical SSL cert immediately jump to one's mind: RSA key length, and the hash algorithm. The recipe to accept the cert might differ based on which one is weak.
Check the cert properties, under Siganture Algorithm. Is it sha1RSA by any chance? If so, search for enabling SHA1 support.
Check the public key. How many bits in it? Is it less than 1024? Then search for minimum RSA key length setting.

Related

Using a Self-Signed CA Certificate for WebSocket (ws) in Node JS

I need to use the ws client in Node JS to connect to a separate WebSocket server.
I am able to connect using a sample program in my Chrome since I installed my Self-Signed Root CA in the Trusted Root Certification Authorities Store on my machine.
I know that Node JS uses a hard coded list of Root CAs (stupid), but I was hoping there was some way I could import my own.
I tried:
using the CLI option mentioned in the Node JS documentation
export NODE_EXTRA_CA_CERTS=C:\\Users\\IT1\\Documents\\security\\rootCA.pem
using the ssl-root-cas library suggested in many forum posts, but I think it may not be applicable here because it doesn't change the https for the ws client that I'm using. (I THINK, I'm spitballing at this point)
using the ca, cert, and key options available for the WebSocket constructor.
// Using just ca
var test = new WebSocket(uri, {
ca: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.pem")
});
// Using cert and key
var test = new WebSocket(uri, {
cert: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.crt"),
key: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.key")
});
// Using ca, cert and key
var test = new WebSocket(uri, {
ca: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.pem"),
cert: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.crt"),
key: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.key")
});
And NO MATTER WHAT, I always get the following error message:
events.js:200
throw er; // Unhandled 'error' event
^
Error: unable to verify the first certificate
at TLSSocket.onConnectSecure (_tls_wrap.js:1321:34)
at TLSSocket.emit (events.js:223:5)
at TLSSocket._finishInit (_tls_wrap.js:794:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:608:12)
Emitted 'error' event on WebSocket instance at:
at ClientRequest.<anonymous> (C:\Users\IT1\source\repos\WebSocketTest\WebSocketTest\node_modules\ws\lib\websocket.js:554:15)
at ClientRequest.emit (events.js:223:5)
at TLSSocket.socketErrorListener (_http_client.js:406:9)
at TLSSocket.emit (events.js:223:5)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:81:21) {
code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
}
Also, I cannot use rejectUnauthorized: true. I need it to be authorized, so please don't suggest that as a solution.
Please help, I'm really scratching my head on this one.
After almost a day or two of scratching my head, I decided to verify the certificates in OpenSSL. It turned out that the certificate was using a different encryption algorithm (SHA 256 vs. DES3 or something like that). The reason that it worked fine in the browser is because I already installed a different certificate for that domain earlier.
Moral of the story:
ALWAYS test your SSL certificates with OpenSSL before trying to use them in your code. OpenSSL will always present a LOT more information about why your certificate isn't working than NodeJS, Java or any runtime environment.
Remove all certificates for a domain from your trusted root store before testing a Root Certificate.
I was following tutorials online about generating a Self-Signed Root CA in Windows, and the tutorials I found did not offer a lot of information about what I was doing, more so "this is how you do it". This is where I went wrong because I was following a couple of tutorials and combining the info to find a solution. This meant I generated a root certificate and private key using one tutorial and then signed other certificates using another tutorial (which specified a different algorithm, but did NOT explain that the algorithms must match for the root CA and the signed certificate).
It helps to have a decent understanding of how SSL and Root Certificates work before diving into making a Self-Signed root CA. Not from a technical perspective, but from the perspective of why there are Root CAs, how they're used in the real world, and how it applies to your application as a developer. I found this article extremely helpful.

Decryption of openssl packets with static certificates

I am working on an ethical hacking project to monitor all the encrypted packets through OpenSSL.
I do have both the public and private keys (cert files). My application code snippet for regular packet decryption is as follows:
SSL_library_init();
ctx = InitCTX();
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
ShowCerts(ssl); /* get any certs */
SSL_write(ssl,acClientRequest, strlen(acClientRequest)); /* encrypt & send message */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
SSL_free(ssl); /* release connection state */
SSL_read basically gets the certificate at the time of handshaking and utilizes it for decrypting the data. Is there any way to provide the same certificate offline for decryption of data.
Any help/pointers would be highly appreciable.
Generally TLS is gravitating to ephemeral key exchange, DHE or ECDHE. With ephemeral key exchange the session key (pre-master secret and master secret) are calculated using key agreement with temporary Diffie Hellman keys rather than the RSA or ECDSA key pair that is part of the certificate. So often you cannot do this.
You can however explicitly select one of the older RSA_ ciphersuites. In this case the pre-master secret is encrypted on the client side using the server's public key. The private key of the server can then decrypt this pre-master secret, calculate the session keys using the PRF (HMAC based key derivation) and then verify / decrypt all the packets.
It should be possible to do this using Wireshark, yes.
Note that TLS 1.3 will not support the RSA_ ciphersuites anymore. You would have to capture a public key of the client and private key of the server, the public key of the server and a private key of the client, or indeed the session keys directly to decrypt the traffic. Actually, that was one of the common complaints for TLS 1.3; that decrypting the traffic afterwards is not possible. That's however by design; the NSA cannot do this either.

How to protect data protection key files with a certificate on Asp.Net Core 2 on debian/linux

I'm trying to configuring data protection and to use the certificate to protect key files. Here is the MS documentation Configuring data protection
Here is what I'm trying to do:
services
.AddDataProtection()
.SetApplicationName("test server")
.PersistKeysToFileSystem("/home/www-data/config")
.ProtectKeysWithCertificate(
new X509Certificate2("/home/www-data/config/"keyprotection.pfx);
When I launch the application I get the following error on startup:
info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[58]
Creating key {71e2c23f-448b-49c9-984f-3c8d7227c904} with
creation date 2017-08-29 18:53:51Z, activation date 2017-08-29 18:53:51Z, and expiration date 2017-11-27 18:53:51Z.
info: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[39]
Writing data to file '/home/www-data/config/key-71e2c23f-448b-49c9-984f-3c8d7227c904.xml'.
fail: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[24]
An exception occurred while processing the key element '<key id="71e2c23f-448b-49c9-984f-3c8d7227c904" version="1" />'.
System.Security.Cryptography.CryptographicException: Unable to retrieve the decryption key.
at System.Security.Cryptography.Xml.EncryptedXml.GetDecryptionKey(EncryptedData encryptedData, String symmetricAlgorithmUri)
at System.Security.Cryptography.Xml.EncryptedXml.DecryptDocument()
at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.Decrypt(XElement encryptedElement)
at Microsoft.AspNetCore.DataProtection.XmlEncryption.XmlEncryptionExtensions.DecryptElement(XElement element, IActivator activator)
at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement)
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[12]
Key {71e2c23f-448b-49c9-984f-3c8d7227c904} is ineligible to be the default key because its CreateEncryptor method failed.
System.Security.Cryptography.CryptographicException: Unable to retrieve the decryption key.
at System.Security.Cryptography.Xml.EncryptedXml.GetDecryptionKey(EncryptedData encryptedData, String symmetricAlgorithmUri)
at System.Security.Cryptography.Xml.EncryptedXml.DecryptDocument()
at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.Decrypt(XElement encryptedElement)
at Microsoft.AspNetCore.DataProtection.XmlEncryption.XmlEncryptionExtensions.DecryptElement(XElement element, IActivator activator)
at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement)
at Microsoft.AspNetCore.DataProtection.KeyManagement.DeferredKey.<>c__DisplayClass1_0.<GetLazyDescriptorDelegate>b__0()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyBase.get_Descriptor()
at Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.CngGcmAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey key)
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyBase.CreateEncryptor()
at Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver.CanCreateAuthenticatedEncryptor(IKey key)
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver[12]
Key {71e2c23f-448b-49c9-984f-3c8d7227c904} is ineligible to be the default key because its CreateEncryptor method failed.
System.Security.Cryptography.CryptographicException: Unable to retrieve the decryption key.
at System.Security.Cryptography.Xml.EncryptedXml.GetDecryptionKey(EncryptedData encryptedData, String symmetricAlgorithmUri)
at System.Security.Cryptography.Xml.EncryptedXml.DecryptDocument()
at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.Decrypt(XElement encryptedElement)
at Microsoft.AspNetCore.DataProtection.XmlEncryption.XmlEncryptionExtensions.DecryptElement(XElement element, IActivator activator)
at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement)
at Microsoft.AspNetCore.DataProtection.KeyManagement.DeferredKey.<>c__DisplayClass1_0.<GetLazyDescriptorDelegate>b__0()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
--- End of stack trace from previous location where exception was thrown ---
So the key is created and well encrypted. But it seems that somehow it doesn't know how to decrypt it as it says in the error:
System.Security.Cryptography.CryptographicException:
Unable to retrieve the decryption key.
If I understand it correctly, it uses the certificate I provided to encrypt the key. But it looks like it doesn't use the same cert for the decryption for some reason (It looks like it tries to retreive it from somewhere else [store?]).
What is going wrong ?
I also tried to put the cert into CA store as described here:
Create a Self-Signed Certificate and trust it on Ubuntu Linux
Then I tried to find them back from the code like this:
var cert = new CertificateResolver().ResolveCertificate(CertThumbprint);
But it didn't work (it cannot find it).
I also tried tried to find them using the following approach:
var store = new X509Store(StoreName.CertificateAuthority,
StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var collection = store.Certificates.Find(
X509FindType.FindByThumbprint,
CertThumbprint, false);
store.Close();
var x509Cert = collection.Count > 0 ? collection[0] : null;
But it didn't work neither.
So what is the right way ?
For reasons known only to Microsoft, the ProtectKeysWithCertificate overrides that accept actual certificates (PFX files or X509Certificate2 objects) are only able to encrypt DPAPI data. Decryption only works if the same certificate is stored in the machine's certificate store, which makes those overrides relatively pointless.
Why? Who knows. It isn't particularly useful information, but it's vaguely dismissed here as a "limitation of the underlying framework".
In this related discussion (which was just closed without any Microsoft assistance or engagement at all), a user shares custom persistence classes which aren't affected this mysterious "limitation." GitHub repo linked below, I know this is an old question, but maybe it'll help someone else.
https://github.com/tillig/DataProtection
Update: This will be fixed in the upcoming Core 2.1.0 release:
https://github.com/aspnet/Home/issues/2759#issuecomment-367157751

SSL handshake error when connecting by websocket using encrypted connection

I use Tyrus webSocket implementation to connect to the server from my JavaFX application. When I try to establish connection over SSL I get this error: javax.net.ssl.SSLException: SSL handshake error has occurred - more data needed for validating the certificate
I tried to use a dummy certificate and host verification as described in Disable Certificate Validation in Java SSL Connections but to no avail.
There is also not much information on Tyrus documentation.
I simply don't know what to do!
P.S. For what it's worth I managed to get around this issue by using Grizzly client
//final WebSocketContainer container = ContainerProvider.getWebSocketContainer();
final ClientManager client = ClientManager.createClient();
URI uri = URI.create(this.uri + "?" + System.currentTimeMillis());
session = client.connectToServer(this, uri);
It sounds like you need to install a certificate chain. I believe you can import the signing certificate using keytool -import. Have you setup the certificate store?

boost asio with ECDSA certificate issue

I am implementing SSL server using boost::asio.
The context initialization is shown in below code
boost::asio::ssl::context_base::method SSL_version =
static_cast<boost::asio::ssl::context_base::method>(param_values[ID_PROTOCOL_VERSION].int32_value);
// load certificate files
boost::shared_ptr<boost::asio::ssl::context> context_ = boost::shared_ptr<boost::asio::ssl::context>(
new boost::asio::ssl::context(SSL_version));
p_ctx = boost::static_pointer_cast<void>(context_);
context_->set_options(boost::asio::ssl::context::default_workarounds);
context_->use_certificate_chain_file(cert_chain_file);
context_->use_certificate_file(cert_file, boost::asio::ssl::context::pem);
context_->use_private_key_file(cert_file, boost::asio::ssl::context::pem);
context_->set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);
context_->set_verify_callback(boost::bind(&verify_certificate_cb, _1, _2));
if (param_values[ID_CIPHER_LIST].int32_value != 0)
{
std::string cipher_list = "";
generate_cipher_list(param_values[ID_CIPHER_LIST].int32_value, cipher_list);
MA5G_logger::log(PRIORITY_INFO, "Supported cipher list %s", cipher_list.c_str());
SSL_CTX_set_cipher_list((reinterpret_cast<boost::asio::ssl::context*>(p_ctx.get()))->native_handle(),
cipher_list.c_str());
}
in the cipher_list, I am supporting below list
AES128-SHA:AES256-SHA:AES128-SHA256:AES256-SHA256:AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA
With ECDSA certificates if I use cipher_list given above then client can not connect to the server and gives error "No shared cipher". But if I do not give cipher_list then the client can successfully connect to the server. The same cipher list works fine with RSA certificates.
The same ECDSA certificates work fine if I use openssl s_server with -cipher option to provide supported cipher_list
Can anyone help with this issue?
No sorry buddy I found the answer after lot of research.
The problem is with the cipher list and not with the code / certificate.
The same certificate uses ECDHE-ECDSA-AES256-SHA cipher with openssl client-server while used ECDH-ECDSA-AES256-SHA cipher for boost asio SSL client-server.
Anyways thanks #rkyser for your help!
I found this buried in the FAQ of the openssl-1.0.1 source code:
Why can't I make an SSL connection to a server using a DSA certificate?
Typically you'll see a message saying there are no shared ciphers when
the same setup works fine with an RSA certificate. There are two
possible causes. The client may not support connections to DSA servers
most web browsers (including Netscape and MSIE) only support
connections to servers supporting RSA cipher suites. The other cause
is that a set of DH parameters has not been supplied to the server. DH
parameters can be created with the dhparam(1) command and loaded using
the SSL_CTX_set_tmp_dh() for example: check the source to s_server in
apps/s_server.c for an example.
So based on this, make sure you are setting your DH parameters using SSL_CTX_set_tmp_dh().

Resources