Extract multiple keys from one .p12 file using OpenSSL ruby - ruby

I am wondering how to extract keys from an Apple .p12 file. From my limited understanding, a .p12 file is a combination of X504 certificates and private keys.
I am seeing that every .p12 file I run into has a X504 certificate and at least one key, and in some situations two keys. This is due to the fact that every .p12 has an Apple developer key, and some have an extra key (possibly an Apple root authorization key). I am considering only those .p12 files with two keys as valid. My goal here is to differentiate between those .p12 files that have one key and those that have two.
So far I have used OpenSSL to be able to inspect X504 files and the keys of any .p12. For example I have this code that does the inspections for all .p12 files in a directory:
Dir.glob('*.p12').each do |p|
file = File.read(p)
p12 = OpenSSL::PKCS12.new(file, "")
# note that this new certificate is in an X509 format
cert = p12.certificate
puts p12.inspect()
puts cert.inspect()
end
This is my output:
#<OpenSSL::PKCS12:0x007fcf33018920>
#<OpenSSL::X509::Certificate subject=/UID=FFBMT4K5/CN=iPhone Distribution: A.H. Belo Management Services, Inc./OU=FFBMT4K5/O=FFBMT4K5/C=US, issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority, serial=36597980220620, not_before=2012-01-11 16:30:22 UTC, not_after=2013-01-10 16:30:22 UTC>
Now my problem is getting keys. If I do something like this:
puts p12.key
I get a long string on encrypted data like this:
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA4Pet7CZrPr4x/SKjMwy5avXmcguzQlix/vBq+qq7aKQhctKr
d5HE7wk4jWbDGj7Rf9ckeFFMktTTbKYmnKCywCct/uJmgavFl1+t45DIQL2V1JMU
JSXvtjDXoKFweKQgdiha5mBNL70+ivqxMzJJw19E+MhFoZ6tFOgQ5gPLcDLR5WTU
ezxH9RbXGWbq+CMBjJ+lw8/Ako7IOm+d95ZTM6u333qp0dsn+1/I/zGeWE1gJXIl
8mIkvrp7+BDTvXHYALADwXnXijqvd/bANfetsDQ+gxRnc06dFt114JUuptcXGwbg
//ykDzNYhuibQD1Z65KfTB/ntQ1aE5FtHEXirwIDAQABAoIBACNCrt/0pZqP9QXY
B/xYYjeBkz0M2GvtuvhadmoTmIwuLY/xtS5oipVsvJBtKudSMUP4VJ8HHxlkgj7l
S+gAyAOWIH9yvN5WLgIr3PVuG/UJwhIve1jXOVs1DJcAtsAx+WSLrrOtJGv3HXZr
FJsRpr4YkJbtzPwoArjkJsHmllxfT2zeQPMJy+RQ/qlHUqsude/ahC0I3RiW3SgB
EKTNM1vGTEkox8bUUhHqNY3ERlihFpZC2wSkroETDY3RkSjuPkNy7uT/b66a/qjj
qaIA0YLhNOYGdN2llJN5GJjYYVKakpiipqcHCFrV1+JtbFB2tKhqAvK6fjCZcSFF
fW58owECgYEA/g8FvAPcejPR3O8E1ydNWChhd9UZQUeQNCET+lY3Dxwklk+u1140
yw/u2hUoNdJLfev1HtlYruglD9jW/LGoLaPodQfcHcaCSfdJa1mmKfSieApOe15+
ijO3WpZK/MJUTteGVMW/B/QnxPBGtsDo6q2v2YxA7fOhzmImn5hgxlsCgYEA4q/A
DBKe1WDZPUyG3R/Cfl5AEqEHly6VkCPFF+uYFZzep/SN/ez34r7fmcfl0RL7H9kn
Q4WBaCMbCgG9dErORW99usoBsjys5pojstNJDZwACUg9rPnV/+uUqMyocjeN0Vrl
2Vg0dC8HH1hLZPLkp+MAy2nNzmnnHcTKiTqsDT0CgYEApVzfzaXxvvS1t4k37Fbf
h+8YqefhfVT4LoYNO9ccFVCrG88XrYTa9gUT4Yz91DJiAr8vl/m+OHJPlUX9gRKd
tb9HEc2g3xyTN1OmzSHX/t0FVv7WYIR79rZ8tJC4lFZki8DK5aikk6e+rvf5/wAH
WqDcocwhgwAeJHhMTXrgGpsCgYBGYqWx2fJBdNHfK6zQafUdAazJXACcW5WK7OBc
vgU56Lxl0BRqnLKXUAbjm+Lq2Qbqa6W6XHDC4euaXtHxkuybOLQEVIbUTeytqXye
IOaU+DQ2rZyg4e4liYNeKjW/SSqar6ugobefv55piCPY02ZWDrEHd/G0PsPJRXpR
w8r6TQKBgFMoEZKywokRIbMCUHHRR3TVeizBMhbNUUmOiRhzsHZPJ2V63PNp3L1c
0NsRo62mbekXDRH8J0C8fLG4R64Y7+rHBQo0tBpgYepPU0NCrsojF7brtYYb3VqI
baVEPRhIy2tJylDad6M36DeOCIhvXalh8GaV/HhEr4lxykth+mGH
-----END RSA PRIVATE KEY-----
My question is how can I determine whether this certificate has more than one key, and also how I can inspect the keys for information. If what I am asking or my understanding of this issue is fundamentally flawed, please let me know. This is my first time being exposed to certificates and any information will be greatly helpful. Any points in the right direction will be appreciated, thanks in advance.
EDIT:
Using OpenSSL I can view the two shrouded keybags of a .p12. Example:
openssl pkcs12 -in some_p12.p12 -info -noout
output:
Enter Import Password:
MAC Iteration 1
MAC verified OK
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 2048
Certificate bag
Certificate bag
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
So I'm looking for a couple things. Generally speaking, what exactly are these keybags? And also, how can I inspect them/determine how many I have per .p12 file using Ruby. Thanks.

I'm quite late for this one but it also interested me. I've tested creating a p12 file using two of my digital certificates (one expiring in 2023 and the other one in 2027) and this is was the openssl output:
$ openssl pkcs12 -in some_p12.p12 -info -noout
Enter Import Password:
MAC Iteration 1
MAC verified OK
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 2048
Certificate bag
Certificate bag
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048*
When parsing it in ruby using OpenSSL::PKCS12 I noticed one of the certificates could be read from the in ca_certs array and the other from the certificate method:
p12 = OpenSSL::PKCS12.new(file, "1234")
p12.certificate # => The latest one with the further expiry date (2027)
p12.key # => The private key from the certificate
p12.ca_certs # => Array, with the other certificate (expiring in 2023)
p12.ca_certs.count #=> 1
I could read the private key from the certificate using key as usual, however I could not find a way to read the key corresponding the certificate from ca_certs

A .p12 contains only 1 private key, and contains 1 or more public keys. The public keys are the ones that make the chain of trust.
.p12 is a binary format. To convert it and extract to individual certificates, look for example here. The link contains all the openssl commands you need.

Related

How do you generate your RSA Private and Public keys for VodaPay Mini-Programs Authentication?

I am currently developing a mini-program for Vodapay and I need to generate the RSA key pairs to be able to sign my requests to the Vodapay backend.
Is there a recommended method or suggested tools I should use in order to generate my public-private key-pair for my VodaPay mini-program?
I managed to figure this out, the keys need to be generated through open SSL and they need to be stored as a .pem file
The bash commands required to get the keys are as follows, it will create the keys
Create RSA 2048 Keysopenssl genrsa -out rsa_2048_key.pem 2048
Export Public Keyopenssl rsa -in rsa_2048_key.pem -out rsa_public_key.pem -pubout
Export Private Key with PKCS#8 Encodeopenssl pkcs8 -topk8 -in rsa_2048_key.pem -out rsa_private_key.pem -nocrypt

Convert key and certificate

I am using Mac OS X. I have the following files
key.rtf
cert.rtf
These files are PEM encoded and contain the key and the certificate in text form (-----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY-----).
How can I:
decrypt the private key with the passphrase I used to encrypt it and get it back in text form?
get both files in PEM format as text (!) back?
The PEM encoding makes problems - if the files are stored as .key, .cert or anything like this, it works properly. But I need the text.
Thanks!
It is possible with this command: openssl rsa -in cert.pem -out server.key (I converted the files to a cert.pem file before).

Unable to load Private Key

I am new to SSL/OpenSSL and I'm working on Windows 7. I'm trying to configure HTTPS for my ElasticBeanstalk environment following these instructions.
I'm at Step 2 in "Create a Private Key". After I issue the command to generate the key pair:
openssl genrsa 2048 > privatekey.pem
I get:
Generating RSA private key, 2048 bit long modulus
........................................+++
...............................+++
unable to write 'random state'
e is 65537 (0x10001)
However, it does write a key to my directory. But after the second command:
openssl req -new -key privatekey.pem -out csr.pem
I get:
unable to load Private Key
6312:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:647:Expecting: ANY PRIVATE KEY
I've tried Googling this a bit, but none of the solutions I've found seem to be relevant for me. I checked the generated key and it looks like
-----BEGIN RSA PRIVATE KEY-----
{lots of characters}
-----END RSA PRIVATE KEY-----
What am I doing incorrectly?
unable to load Private Key
6312:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:647:Expecting: ANY PRIVATE KEY
I ran your commands on OS X, and I could not reproduce the results.
I did use the -config option because I have an "OpenSSL server config template" that makes it easy to generate CSRs and self signed certificates:
$ mkdir test
$ cd test
$ openssl req -new -key privatekey.pem -out csr.pem -config example-com.conf
The configuration file is named example-com.conf, and you can find it at How do I edit a self signed certificate created using openssl xampp?. Edit it to suit your taste (in particular, the DNS names).
If interested, here's the OpenSSL man pages on the req sub-command.
I checked the generated key and it looks like
-----BEGIN RSA PRIVATE KEY----- {lots of characters}
-----END RSA PRIVATE KEY-----
You can validate the key you just created with:
$ openssl rsa -in privatekey.pem -inform PEM -text -noout
Private-Key: (2048 bit)
modulus:
00:b0:91:ce:57:28:0f:5c:3a:c3:29:d7:23:6a:71:
ca:64:49:fc:24:ea:69:a3:09:d6:49:94:17:b9:09:
65:fa:5a:10:47:a4:9b:b8:cd:6d:32:74:19:8d:5c:
79:92:f0:a6:43:9c:75:a3:7b:ef:c4:c3:d9:c2:db:
b9:bd:ec:14:a8:b1:52:73:8f:56:c8:5c:16:08:56:
ff:c2:2b:35:3c:0a:0f:34:d0:91:c1:54:7e:72:e8:
97:bf:ea:46:69:5f:e4:21:8d:7a:f5:a5:6b:6a:e8:
00:56:bc:02:f6:b4:ae:6e:89:a6:50:aa:5b:2f:d8:
7d:99:04:61:51:76:b3:5e:9e:30:52:99:54:26:e2:
3a:54:ec:78:34:e6:9a:b7:c2:58:5c:51:3d:39:52:
d4:6e:0c:6e:a1:a0:a5:f1:4d:5a:f5:0b:1a:6e:dc:
f3:bb:0d:d0:53:51:b0:1a:04:ee:86:35:d5:f3:8b:
0d:bc:19:61:6c:0c:b2:7b:a9:7c:47:97:01:bb:a2:
6a:74:d9:19:e9:df:60:07:d4:95:4c:83:f8:3b:84:
c2:b8:3d:b9:a7:34:0a:9b:a3:c6:70:cc:ef:de:f4:
64:88:f1:56:d3:2a:fd:5a:82:88:96:66:93:6c:a0:
b8:ec:e4:4c:e8:76:5c:9c:fc:c4:60:72:b6:9a:3f:
98:a3
publicExponent: 65537 (0x10001)
privateExponent:
00:87:ab:f1:65:ac:e5:68:93:ca:64:3a:e7:fe:a1:
62:c7:7e:c5:dc:c3:b5:d9:cd:f4:36:e3:30:fb:40:
0a:78:bc:7d:67:df:46:bc:50:34:88:a1:07:05:44:
ba:31:ba:f1:b6:5f:e1:50:76:29:bd:02:54:2f:d2:
cf:bc:ec:4a:cf:78:39:07:8c:6b:3d:56:ec:a3:09:
de:49:9f:13:af:87:77:39:b8:cd:56:45:0b:48:56:
0a:4c:2f:c2:5c:b3:8e:c2:6d:48:be:b9:95:79:36:
bd:13:e8:31:4a:c9:78:82:7d:08:2b:51:4a:f1:cf:
a2:6a:52:20:49:0d:31:34:10:88:02:d7:a7:07:70:
32:b5:f5:8c:cc:d4:b2:8d:b9:aa:bb:33:82:1a:74:
bd:4d:4f:e9:e0:cc:f2:27:fb:98:34:2c:77:56:6f:
88:3a:66:32:5d:7d:57:c6:5b:63:39:fa:32:04:9d:
e3:cc:a5:b6:44:91:fd:7d:d1:b6:2d:16:47:59:81:
3d:cf:d9:a7:58:2a:d6:61:5d:c6:69:3b:7a:70:50:
4f:80:f4:d9:fb:c8:7d:5e:44:9e:ac:c8:e6:aa:49:
c3:d6:df:6b:03:68:25:a3:2b:89:8f:9a:35:3a:58:
7d:71:b4:08:d9:04:7b:b9:96:17:f3:a5:19:c5:07:
4e:c1
prime1:
00:d7:d0:d8:8c:b5:86:ed:0e:06:70:c9:54:00:25:
d7:8c:e4:65:51:1b:c5:ba:33:c2:02:1a:dc:80:a6:
ae:8e:1e:e8:c0:b7:04:11:5a:e3:98:52:8f:4a:7a:
43:b8:e8:1b:c8:d6:d3:b2:dc:70:59:a5:ca:83:bb:
35:f1:6c:f5:cb:d0:f4:04:5e:aa:7c:d0:ec:d7:4a:
d5:1c:7c:e2:67:e4:e8:17:95:9b:4e:2b:a0:26:74:
61:d0:a0:15:27:18:e5:84:b5:54:ef:be:82:35:7e:
78:e0:49:6b:4e:ae:93:53:a0:81:a3:8e:de:d3:e5:
dc:c5:ba:03:36:14:47:97:03
prime2:
00:d1:72:3b:f5:34:b1:11:78:b2:79:f4:3e:d7:be:
bf:cc:b3:09:ea:24:a4:cc:7f:64:73:96:d2:48:9e:
55:bc:79:23:c2:d9:80:81:7d:a4:a5:4b:43:33:8e:
62:04:ec:8d:22:d7:43:5e:41:b6:4d:e9:b0:cc:70:
63:17:70:93:88:81:f5:84:a6:3f:2b:98:33:a3:69:
53:11:c7:95:8c:30:ea:e8:58:c7:77:10:b4:a8:f5:
bf:5e:cf:e1:99:bb:b3:4e:57:d2:4c:f7:73:de:8a:
98:8e:7c:26:37:6c:e4:77:c6:d2:ed:5d:53:a7:15:
c3:9c:67:61:d3:24:9a:f5:e1
exponent1:
00:83:34:59:e2:b9:9d:8c:d2:e1:01:82:b4:89:de:
77:bc:15:42:af:5b:c6:0a:dc:da:8e:f3:0b:a9:3f:
2c:92:04:a2:96:3e:ed:bf:2b:55:80:ce:78:84:db:
ed:fe:25:46:77:04:7b:f1:9a:68:c7:67:ae:c6:05:
73:d7:11:da:21:0e:28:bb:db:5d:a4:c2:53:aa:d3:
b8:da:37:e6:61:29:5e:1c:b0:7c:99:ba:96:03:aa:
ef:a8:a9:1a:13:09:e4:c7:98:82:49:ba:b5:68:96:
3a:20:89:22:2e:d4:9d:86:d2:e6:dd:ab:c7:36:65:
e1:a1:67:e3:f9:e5:bc:5c:47
exponent2:
00:81:6d:b9:55:8f:09:39:05:c0:2d:12:dd:5e:cf:
56:91:35:b6:93:c5:af:3d:5c:20:04:3a:18:9a:9d:
95:d7:d1:78:62:e9:ab:ba:d9:9c:cc:34:95:43:9f:
e2:3c:ae:bd:8c:e1:3f:95:58:c0:42:a7:7e:04:e8:
12:a4:22:82:59:22:0e:49:b9:be:61:bf:3d:71:e7:
1d:59:68:5f:a6:f1:77:c8:bb:4c:0f:ec:f7:e7:4d:
6d:c4:36:6c:70:67:08:a8:0a:27:40:3e:ce:90:a0:
4f:24:05:de:4b:f3:f3:bf:7c:d3:4d:b1:95:87:34:
30:dc:4f:1a:a9:b2:fe:3b:a1
coefficient:
6d:51:b3:6e:87:8d:aa:f0:55:c4:22:21:62:a9:ea:
24:b3:b7:91:40:f5:78:5d:f1:40:45:7e:0d:a2:a3:
54:46:ba:42:33:b6:cd:57:a1:85:bc:3d:ba:1c:eb:
87:33:a9:e9:63:1e:7c:2c:89:98:b9:0f:4b:e8:c4:
79:bd:00:6a:f5:3e:ea:63:f1:9e:aa:47:35:5a:22:
fc:4e:e3:61:7e:eb:dc:a6:c0:2c:d5:fd:22:9f:01:
59:32:15:db:41:99:b7:a8:c1:eb:1e:42:c7:1b:c7:
c8:56:86:a8:34:fe:1c:48:b6:6e:f1:c1:5c:96:bf:
9d:fa:e5:4c:d0:2a:d9:09
unable to write 'random state'
This is a well known problem. OpenSSL uses a default configuration file. You can locate the configuration file with correct location of openssl.cnf file.
The default configuration file includes these lines:
$ cat /usr/local/ssl/macosx-x64/openssl.cnf
...
HOME = .
RANDFILE = $ENV::HOME/.rnd
...
To save the random file, you should point HOME and RANDFILE to a valid location. On Windows, you type set HOME=... and set RANDFILE=... in the command prompt. Or better, change it in the OpenSSL configuration file you use.
Also see How to fix “unable to write 'random state' ” in openssl and How do I make OpenSSL write the RANDFILE on Windows Vista?.
I'm trying to configure HTTPS for my ElasticBeanstalk environment following these instructions.
The instructions are wrong in the image below. Do not place a DNS name in the Common Name (CN).
Placing a DNS name in the Common Name is deprecated by both the IETF (the folks who publish RFCs) and the CA/B Forums (the cartel where browsers and CAs collude). You should pay articular attention to what the CA/B recommends because Browsers and CAs come up with those rules, and the browsers follow them (and they don't follow the RFCs). For reference, see RFC 5280, RFC 6125 and the CA/B Baseline Requirements.
Instead, place DNS names in the Subject Alternate Name (SAN). Both the IETF and CA/B specifies it.
The custom OpenSSL configuration file handles this for you. You just have to change the DNS names listed under the section [ alternate_names ]. For example, here's a set of names set up for the domain example.com. Notice there is no DNS name in the CN:
[ subject ]
...
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Example Company
[ alternate_names ]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = mail.example.com
DNS.4 = ftp.example.com
Can you check if you have appropriate permissions when you run both the commands? Maybe try doing the same using a user with Admin Rights.
Also make sure the created file privatekey.pem has appropriate permissions before executing the command below (Use chmod if necessary)
openssl req -new -key privatekey.pem -out csr.pem
Submitting this as answer as I don't have enough reputation to comment.
I believe the root of the problem is the error
unable to write 'random state'
e is 65537 (0x10001)
Searching StackOverflow found these results. I would stress that you run the openssl program as sudo or directly as root to avoid any possible permissions issues.
The fix in Windows:
https://stackoverflow.com/a/12522479/3765769
In Linux:
https://stackoverflow.com/a/94458/3765769

Heroku No valid, non-passphrase-protected keys given error

I have this files:
AddTrustExternalCARoot.crt
STAR_mydomain_com.crt
TrustedSecureCertificateAuthority5.crt
USERTrustRSAAddTrustCA.crt
domain.key
domain.key is passphrase protected and it was generated during creation of CSR files (files that were required to get .crt files from certificate provider. I tried:
heroku certs:update certs/STAR_mydomain_com.crt certs/domain.key
But I get following error:
! No valid, non-passphrase-protected keys given.
How I can generate valid crt/key for heroku? (I tried all other crt files with domain key but they are not valid domain certificates.
domain.key was generated with following command:
openssl genrsa -des3 -out domain.key 2048
Here's how to remove a passphrase from a private key:
openssl rsa -in certs/domain.key -out certs/domain-nopassphrase.key
You'll need to enter the current passphrase on the private key. If prompted for a passphrase on the new key, do not enter one (just press enter).
You can then update your SSL endpoint using your cert + this new key:
heroku certs:update certs/*.crt certs/domain-nopassphrase.key

OpenSSL not enough data

I've generated a self signed certificate using Adobe X, and exported a pfx file (for my private key) along with a .cer file (for the certificate).
I then try to collect the certificate, along with the key, but for some reason, OpenSSL is giving the error
OpenSSL::X509::CertificateError: not enough data
Here is my code
require 'openssl'
CERTFILE = "test.cer"
RSAKEYFILE = "test.pfx"
# Open certificate files
cert = OpenSSL::X509::Certificate.new(File.read CERTFILE)
key = OpenSSL::PKey::RSA.new(File.read RSAKEYFILE )
My certificate was generated using Adobe X reader, and is a self-signed certificate. It is working fine to sign pdf documents...
What might i do to make this work?
Apparently OpenSSL has some problems reading directly from .cer files, and for the key, we should use only the private_key, and the pfx has both the privatekey and the cert.
So, i installed openSsl locally, and first converted my .cer certificate to .pem with the following command :
C:\OpenSSL-Win32\bin>openssl x509 -inform der -in "c:\mydir\test.cer" -out "C:\mydir\certificate.pem"
and then extracted my privatekey from the pfx file (based on this site) :
C:\OpenSSL-Win32\bin>openssl pkcs12 -in "c:\mydir\test.pfx" -nocerts -out "c:\mydir\test_pk.pem"
just make sure you have your pfx pwd and select a passphrase when you extract the privatekey.
Here is the final code :
require 'openssl'
CERTFILE = "certificate.pem"
RSAKEYFILE = "test_pk.pem"
passphrase = "your chosen passphrase for the private key"
key4pem=File.read RSAKEYFILE
# Open certificate files
cert = OpenSSL::X509::Certificate.new(File.read CERTFILE)
key = OpenSSL::PKey::RSA.new key4pem, passphrase
And voilá :-), we have successfully mapped into memory both our certificate and privatekey, and can put it to uses like the answer here
While trying to create an OpenSSL::X509::Certificate object from '.cer', I found this error:
OpenSSL::X509::CertificateError (not enough data)
I checked that file was actually a DER-encoded certificate which is in binary format. In that case, we should read the file contents by File.binread.
To check if the file is PEM or DER encoded? We can use the following code:
require "open3"
require "openssl"
def pem_cert?(file)
details, status = Open3.capture2e("file", file)
return false unless status.success?
details.rpartition(":").last.strip == "PEM certificate"
end
contents = if pem_cert?(cer_file_path)
File.read(cer_file_path)
else
File.binread(cer_file_path)
end
OpenSSL::X509::Certificate.new(contents)
This is a pure ruby way, without any shell interaction.

Resources