When I use openssl
's command line to generate an RSA-2048 keypair, and then construct two Certificate Signing Requests (CSRs) for identical domain names using identical private keys, I get identical output.
$ openssl genrsa -f4 -out rsa.key | head -1
Generating RSA private key, 2048 bit long modulus
$ openssl req -new -sha256 -key rsa.key -out rsa1.csr -subj "/CN=example.com"
$ openssl req -new -sha256 -key rsa.key -out rsa2.csr -subj "/CN=example.com"
$ diff rsa1.csr rsa2.csr
But, when I generate an elliptic curve (P-256) keypair, and make two CSRs for identical domain names using identical private keys, I get two different outputs!
$ openssl ecparam -genkey -name prime256v1 -noout -out p256.key
$ openssl req -new -sha256 -key p256.key -out ec1.csr -subj "/CN=example.com"
$ openssl req -new -sha256 -key p256.key -out ec2.csr -subj "/CN=example.com"
$ diff -U999 ec1.csr ec2.csr
--- ec1.csr 2019-08-14 12:20:55.000000000 -0400
+++ ec2.csr 2019-08-14 12:20:59.000000000 -0400
@@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE REQUEST-----
-MIHRMHgCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggq
+MIHPMHgCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggq
hkjOPQMBBwNCAASKkrbzoJCjHgvI95U1ZYPG5AQUtN+ImrutI2KNAne/BvktGaHW
-ep2CEc5bliuYzxeC68cUG0MBmDrLZbRwaMS7oAAwCgYIKoZIzj0EAwIDSQAwRgIh
-AO1VziY7sHIKNFvCQnm+g7fguFSPoopHw+Jh3CKpjTKYAiEAmvlilKQkiN134T07
-LCDWfF/IlGeWv6nv1VhgsD3SEBU=
+ep2CEc5bliuYzxeC68cUG0MBmDrLZbRwaMS7oAAwCgYIKoZIzj0EAwIDRwAwRAIg
+AxHKjgwyXbeMqWK8XF/F6KztweW/tpY1U55pXyHeKgECID9jgdAQp7FetjbRGY7A
+GY0Y37x8XY5O3o5rEZSnsA1C
-----END CERTIFICATE REQUEST-----
It's not a one-time thing. I generate 1000 CSRs using this P-256 key, I get 1000 different outputs. I generate 1000 CSRs using this RSA-2048 key, I get 1000 identical outputs.
$ for i in `seq 1 1000`; do openssl req -new -sha256 -key p256.key -out ec$i.csr -subj "/CN=example.com"; done
real 0m8.147s
user 0m5.972s
sys 0m1.810s
$ md5sum ec*.csr | cut -f 1 -d ' ' | sort | uniq | wc -l
1000
$ time for i in `seq 1 1000`; do openssl req -new -sha256 -key rsa.key -out rsa$i.csr -subj "/CN=example.com"; done
real 0m43.940s
user 0m41.386s
sys 0m2.049s
$ md5sum rsa*.csr | cut -f 1 -d ' ' | sort | uniq | wc -l
1
What on earth is going on here? Is there any way to force OpenSSL to generate reproducible output? Is there any reason I wouldn't want OpenSSL to generate reproducible output?
Is there any reason I would want OpenSSL to generate reproducible output when using RSA keys, but not when using EC keys?
I should add that I used https://certlogik.com/decoder/ to look at the CSRs being generated, and they look exactly the same except for the BIT STRING
at the end, which I assume is supposed to be the SHA-256 signature?
I also see the same nondeterminism happening with P-384 keys:
$ openssl ecparam -genkey -name secp384r1 -noout -out p384.key
$ openssl req -new -sha256 -key p384.key -out ec1.csr -subj "/CN=example.com"
$ openssl req -new -sha256 -key p384.key -out ec2.csr -subj "/CN=example.com"
$ cmp ec1.csr ec2.csr
ec1.csr ec2.csr differ: char 275, line 5