Create x509 certificate with openssl/makecert tool - security

I'm creating a x509 certificate using makecert with the following parameters:
makecert -r -pe -n "CN=Client" -ss MyApp
I want to use this certificate to encrypt and decrypt data with RSA algoritm.
I look to generated certificate in windows certificate store and everything seems ok (It has a private key, public key is a RSA key with 1024 bits and so on..)
Now i use this C# code to encrypt data:
X509Store store = new X509Store("MyApp", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectName, "Client", false);
X509Certificate2 _x509 = certs[0];
using (RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)_x509.PublicKey.Key)
{
byte[] dataToEncrypt = Encoding.UTF8.GetBytes("hello");
_encryptedData = rsa.Encrypt(dataToEncrypt, true);
}
When executing the Encrypt method, i receive a CryptographicException with message "Bad key".
I think the code is fine. Probably i'm not creating the certificate properly.
Any comments?
Thanks
---------------- EDIT --------------
If anyone know how to create the certificate using OpenSsl, its also a valid answer for me.

To allow the key to be used for encryption, you should use the -sky-option. Per default ´makecert` uses the AT_SIGNATURE key specification, which will not work with encryption/decryption. Instead have it use the AT_KEYEXCHANGE specification by issuing the following command:
makecert -r -pe -n "CN=Client" -ss MyApp -sky Exchange
(Remember to delete the previous key or use another container-name).

This was another page I stumbled across when I was trying to find examples of makcert usage with x509 certificates and rsa using c#, and unfortunately it only provided part of the solution. I put all the bits together in a blog entry that people might be interested in, and it can be found here:
http://nick-howard.blogspot.com/2011/05/makecert-x509-certificates-and-rsa.html

Related

HTTPS in Nodejs - error:06065064 digital envelope routines evp_decryptfinal_ex bad decrypt

We tried to install our Hapis (Nodejs Version 14) Web service on our customer's server. It ran under HTTP for months, but when we went to enable HTTPS with the appropriate paths to the cert and key it fails when the service starts up with:
error:06065064:digital envelope routines:EVP_Decryptfinal_ex:bad decrypt
Their certificate and key are generated using the Venafi online portal. It gave them a crt and key. The crt uses a Signature algorithm: sha256RSA, Signature hash algorithm of sha256, and Thumbprint algorith: sha1.
Also, the private key is a RSA PRIVATE KEY with Proc-Type: 4,ENCRYPTED and DEK-Info: DES-EDE3-CBC.
I am not sure what is going on, because HTTPS works fine on our development servers.
Is the problem in HapiJS?
Is the problem with the certificate or key themselves?
Is there an Node option I need to be passing in when creating the service?
Please help.
The specified error 06065064:digital envelope routines:EVP_Decryptfinal_ex:bad decrypt occurs in an SSL/TLS connection using OpenSSL (which is what nodejs modules like tls and https actually use) when the privatekey is encrypted (with a passphrase) and the correct passphrase is not provided to decrypt it. The described file format, beginning with a line -----BEGIN RSA PRIVATE KEY----- followed by lines Proc-Type: and DEK-Info: is indeed one of the encrypted formats used by OpenSSL. Specifically this is the encrypted 'traditional' or 'legacy' format; the PKSC8 format added about 2000 but still considered new(!) uses -----BEGIN ENCRYPTED PRIVATE KEY----- and no 822-style headers, only base64 (of the encrypted structure defined by PKCS8); see ursinely-verbose https://security.stackexchange.com/questions/39279/stronger-encryption-for-ssh-keys/#52564 about OpenSSH's use of OpenSSL, which is basically the same as nodejs's use.
The tls module and others that build on it including https ultimately read the key(s) and cert(s) using tls.createSecureContext which accepts in options a member passphrase, or if you need to use multiple keys (and certs) you can provide a passphrase for each key as described in the linked doc.
Alternatively you can avoid the need for a passphrase by converting the key to an unencrypted file, if acceptable under applicable security policies and regulations. (Good policies may prohibit this, but they usually also prohibit getting the privatekey from or providing it to any other system, especially one 'online' somewhere, and your customer is doing the latter.) To retain traditional format do
openssl rsa -in oldfile -out newfile
# and give the passphrase when prompted, or see the man page about -passin
or you can use the 'new' PKCS8 format with
openssl pkey -in oldfile -out newfile
# technically only in release 1.0.0 up, but pretty much everyone is there now
#
# or in all versions back to about 2000
openssl pkcs8 -topk8 -nocrypt -in oldfile -out newfile
For me this error occured after pulling some old code that was workign to a fresh system, I was using too current of a node Version, I downgraded from 17 to 16 and that solved my problem.
Tried checking the github issues related to the TLS, handshake and versions. But couldn't find any.
The final fix was the one suggested by #Greggory Wiley.
Installed nvm - downgraded the node and npm versions. Recomplied the code. And it worked.
In my case I was exporting a certificate from windows to linux inside a docker using openSSL and facing this error.
The problem was in the versions of OpenSLL, when I was converting .pfx file to .crt and .key I was using 3.0.x version on windows, and on linux I had 1.1.1 installed. After I did the same using the same version of OpenSLL on windows it worked.
I had the same issue, I would say that the accepted answer is good expect it does not provide an example where the passphrase is used.
Here's code that worked in my case for express.js
const server = https
.createServer(
{
key: fs.readFileSync("./root/ca/cakey.pem"),
cert: fs.readFileSync("./root/ca/cacert.pem"),
passphrase: "abcdefg",
},
app
)
.listen(PORT, () => {
console.log(`Secure server listening on port:${PORT}`);
});

Public encryption in crypto on node 0.12

I need to encrypt (and decrypt) a string with a public key previously generated in nodejs (i'm using version 0.12) with crypto module, but i'm unable to do it.
For first i generated the keys in this way:
var diffHell = crypto.createDiffieHellman(60);
diffHell.generateKeys('base64');
var publicKey = diffHell.getPublicKey('base64'); //or whatever 'hex','binary'
var privateKey = diffHell.getPrivateKey('base64'); //or whatever 'hex','binary'
Then i tried to encrypt a string using the generated public key:
crypto.publicEncrypt({key: publicKey}, new Buffer(textToEncrypt));
Running this snippet, node throw this error:
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
at Error (native)
at Object.exports.publicEncrypt (crypto.js:362:18)
[...]
Reading it, I understand that the key must be in PEM format, but i can't find in the documentation how to tranform a public key in PEM.
So, How i can do that? Someone has done this yet?
Diffie-Hellman (Key Exchange) is an algorithm and protocol to derive a shared secret based on modular arithmetic. It is not a public-key cipher in the same way as RSA is. You cannot use Diffie-Hellman for crypto.publicEncrypt().
Node.js' Crypto module doesn't provide a way to generate a public-private RSA key pair, so you either need to use OpenSSL through child_process or use one of the many modules which provide this sort of thing (e.g. ursa).
You do not need to uses ursa for key generation. Instead you can generate keys with openssl then store the generated PEM keys on your server and try to load them in your script

How to extract the private key from a PKCS#12 file for further use with nodeJS OAuth

I have a p12 file containing the private key to be used to sign my OAuth requests. But, the OAuth NodeJS lib (ciaranj/node-oauth) doesn't take this format as input.
I tried many OpenSsl options (PKCS#8 or traditional PEM format) to extract my private key from the PKCS#12 keystore, but I can't get the OAuth header signature to get accepted.
What OpenSsl options shall I use to create a PEM file usable as follows:
var privateKey = fs.readFileSync("privateKey.pem").toString('ascii');
var oauth= new OAuth(null, null, consumerKey, privateKey, "1.0", null, "RSA-SHA1");
I'm not an OpenSsl expert so any hint would be very welcomed.
PS: Alternatively, as the OAuth lib uses the sign API of NodeJS crypto, if you know a way to use a PKCS#12 file for signing, this could save me.
After many attempts, I found a solution. So, I thought I'd share the commands here if it can be useful for someone else:
This extract the private key from the PKCS#12 file:
openssl pkcs12 -in myKeystore.p12 -nocerts -out privateKeyPkcs8.pem
But the outcome is PKCS#8 encoded which isn't what NodeJS crypto package expects. So, I had to run the following command to get the traditional PEM encoding:
openssl pkcs8 -in privateKeyPkcs8.pem -out privateKey.pem

Openssl decryption using a public key

I need to decrypt a file which is encrypted using a private key. I have a public key which I can use to decrypt this file. How can I do this. I did:
openssl rsautl -in file -inkey key.pem
But this is not working. This shows the error as:
unable to load Private Key
3074128072:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:696:Expecting: ANY PRIVATE KEY
Public keys cannot be used to decrypt, they can only be used to encrypt and to verify the encryption signature.
Contrary to everyone, you can in fact decrypt using a Public Key, only however, if your data was encrypted with the appropriate Private Key.
As to how you go about decrypting it, from what I can see the openssl utility doesn't ship with this functionality. It seems you would have to use something that utilises the OpenSSL C API (https://www.openssl.org/docs/man1.0.2/crypto/RSA_public_decrypt.html).
Either use the C API directly or something like PHP's bindings to OpenSSL.
Openssl CLI can achieve "decrypting with the public key" via the rsautl subcommand like so:
openssl rsautl -verify -inkey public_key.pem -pubin -in data.sig -raw -hexdump
Note: here, "decrypt" is loosly defined as modular exponentiation, and the API used is actually the -verify algorithm. Warning that rolling your own crypto is not advised, and misusing RSA is easy to do to create a broken security system.

Conversion from cert file to pfx file

Is it possible to convert a cert file to a pfx file? I tried importing my cerf file into IE, but it is never shown under the "personal" tab, thus I cannot export there.
I am looking for if there is alternatives available.
FYI, the cerf file is created by using "keytool" and then doing an export to a cert file.
This article describes two ways of creating a .pfx file from a .cer file:
Maxime Lamure: Create your own .pfx file for ClickOnce
Create your public & private Keys (You will be prompt to define the private key’s password):
makecert.exe -sv MyKey.pvk -n "CN=.NET Ready!!!" MyKey.cer
Create your PFX file from the public and private key
pvk2pfx.exe -pvk MyKey.pvk -spc MyKey.cer -pfx MyPFX.pfx -po toto
Programmaticaly you could do so in C# by writing the byte array directly to a file:
byte[] certificateData = certificate.Export(X509ContentType.Pfx, "YourPassword");
File.WriteAllBytes(#"C:\YourCert.pfx", certificateData);
And generally (if you're using IE 8) you might want to have a look at this answer on SO:
How to make IE8 trust a self-signed certificate in 20 irritating steps
Hope that helps you.

Resources