(Updated: four six typos fixed)
I)
From time to time I need a self-signed certificate. I use the java keytool utility to make one:
For a JKS (Java Key Store format):
keytool
-genkeypair
-keystore mihail.stoynov.jks
-storepass mihail.stoynov
-alias mihail.stoynov
-keypass mihail.stoynov
-keysize 2048
-keyalg RSA
-sigalg sha1withrsa
-dname "cn=Mihail Stoynov, ou=MyCompany Bulgaria, o=MyCompany, L=Sofia, S=Sofia, c=BG"
-validity 3650
-v
For a PKCS#12 keystore:
keytool
-genkeypair
-keystore mihail.stoynov.p12
-storetype pkcs12
-storepass mihail.stoynov
-alias mihail.stoynov
-keypass mihail.stoynov
-keysize 2048
-keyalg RSA
-sigalg sha1withrsa
-dname "cn=Mihail Stoynov, ou=MyCompany Bulgaria, o=MyCompany, L=Sofia, S=Sofia, c=BG"
-validity 3650
-v
When the public certificate is needed separately, one can be exported in a file (mihail.stoynov.cer) like this:
(from a JKS)
keytool
-exportcert
-keystore mihail.stoynov.jks
-storepass mihail.stoynov
-alias mihail.stoynov
-keypass mihail.stoynov
-file mihail.stoynov.cer
-v
(from a PKCS#12)
keytool
-exportcert
-keystore mihail.stoynov.p12
-storetype pkcs12
-storepass mihail.stoynov
-alias mihail.stoynov
-keypass mihail.stoynov
-file mihail.stoynov.cer
-v
NOTE: keep storepass and keypass the same for easy importing into browsers
II)
Sometimes self-signed certificates are not enough and a CA root certificate must be made in order to sign a group of certificates.
First a Certificate signing request (CSR) must be made:
(from a JKS)
keytool
-certreq
-keystore mihail.stoynov.jks
-storepass mihail.stoynov
-alias mihail.stoynov
-keypass mihail.stoynov
-v
>> mihail.stoynov.csr
(from a PKCS#12)
keytool
-certreq
-keystore mihail.stoynov.p12
-storetype pkcs12
-storepass mihail.stoynov
-alias mihail.stoynov
-keypass mihail.stoynov
-v
>> mihail.stoynov.csr
(the output is directed to a file: mihail.stoynov.cer)
The file looks something like that:
-----BEGIN NEW CERTIFICATE REQUEST-----
MIICtTCCAZ0CAQAwcDELMAkGA1UEBhMCQkcxDjAMBgNVBAgTBVNvZmlhMQ4wDAYDVQQHEwVTb2Zp
YTEQMA4GA1UEChMHTWF0ZXJuYTEWMBQGA1UECxMNTWF0ZXJuYSBTb2ZpYTEXMBUGA1UEAxMOTWlo
YWlsIFN0b3lub3YwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ7XpdyHuF9ApZodSn
GS9/TiUtXqryPDD0elzlP2QreSkfYv8IaXnB1Xy1ZVmda/d+P4TZ/aHvAhDwQPcei4KaoRzJWX9I
Yz9hi4cmKksjg8ufDZzXUuMwtbVlricc5vWg1HcSsQJ8vpLCBIelliDJOxc4skDcT23LGQttiv0b
23pjMthEe2tJVp37Tnwr29SLz0AGziVwzb5cfAXU4PzpiASr8vF2A0c2DObS7zM5Wp7jXWIe71P5
BZgIMcUUGlCdfLQRoA7URWN2Yx2qH8gyiNaIaZYZB6o2ib8rH3UmDl/ErKJgWQyS7sr4bANY9WpA
m7H2nXfGs+X88xSbA0JRAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEAIn81dCSpVbI7IDLO2L2p
MW1gnjvuRs9xm6M9rMV6Kwy0Nw05qL0H8tTsFaq4J7bLBXJeXmiREUbrtpbHxLUfjtaqs5q5Txxn
c7Cm5kj7t9PWeRTW0rbzRssgT+sHqUlMKMydB8E+gGEIMQdgwdurhjpD7aevOOeN5fvv9kV7Rszv
6nC8dixyrsiiWjLUGJRP7I9HrEAXKfk3JluSYKS/ZNhTIw5a7fKvhXbRPlN1lDSvdkJAtcaG/9dZ
3KlXL7ozL8sOQTjFxUhN6kS6QujJ1T7TlkWHu9/ivIAkuXBu8P/czyLyjf1JD9fnwGnxCO2FPmcX
9/2IpwG33mMpaAmXpA==
-----END NEW CERTIFICATE REQUEST-----
Did we forget something? Yes, there's no Root CA certificate. Let's make one:
(JKS)
keytool
-genkeypair
-keystore mycompany.root.ca.jks
-storepass "mycompany.root.ca"
-alias "mycompany.root.ca"
-keypass "mycompany.root.ca"
-keyalg RSA
-keysize 2048
-sigalg SHA1withRSA
-dname "cn=MyCompany Bulgaria, ou=Office No 5, o=MyCompany, L=Sofia, S=Sofia, c=BG"
-validity 3650
-v
(PKCS#12)
keytool
-genkeypair
-keystore mycompany.root.ca.p12
-storetype pkcs12
-storepass "mycompany.root.ca"
-alias "mycompany.root.ca"
-keypass "mycompany.root.ca"
-keyalg RSA
-keysize 2048
-sigalg SHA1withRSA
-dname "cn=MyCompany Bulgaria, ou=Office No 5, o=MyCompany, L=Sofia, S=Sofia, c=BG"
-validity 3650
-v
Problem No 1
Keytool cannot sign CSRs. Period.
Now what do we do?
I went to OpenSSL.
In order to sign with OpenSSL I needed the root certificate in the PEM format.
P12 (PKCS#12) -> PEM:
openssl
pkcs12
-in mycompany.root.ca.p12
-out mycompany.root.ca.pem
Sign the CSR with OpenSSL:
openssl
x509
-req
-in mihail.stoynov.csr
-CA mycompany.root.ca.pem
-out mihail.stoynov.signed.cer
-days 3650
-CAcreateserial
(I don't know what -CAcreateserial is but it works)
So now I have mihail.stoynov.signed.cer.
The last step is to import it to mihail.stoynov.p12 (or .jks) in order to override the self-signed certificate with the one signed by the MyCompany Root CA.
A Prerequisite step to that is to import mycompany.root.ca.cer into mihail.stoynov.p12 (or .jks) because every certificate in the chain must be contained in the certificate chain of mihail.stoynov.
Problem No 2
Importing mycompany.root.ca.cer into mihail.stoynov.p12 fails but importing it into mihail.stoynov.jks works?!
JKS:
keytool
-importcert
-keystore mihail.stoynov.jks
-storepass mihail.stoynov
-alias mycompany.root.ca
-keypass mycompany.root.ca
-file mycompany.root.ca.cer
-v
(this one works)
PKCS#12
keytool
-importcert
-keystore mihail.stoynov.p12
-storetype pkcs12
-storepass mihail.stoynov
-alias mycompany.root.ca
-keypass mycompany.root.ca
-file mycompany.root.ca.cer
-v
this one fails with:
Owner: CN=MyCompany Bulgaria, OU=Office No 5, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Issuer: CN=MyCompany Bulgaria, OU=Office No 5, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Serial number: 49b8c365
Valid from: Thu Mar 12 08:12:13 GMT+00:02 2009 until: Sun Mar 10 08:12:13 GMT+00:02 2019
Certificate fingerprints:
MD5: 1C:0C:82:0D:35:C8:1E:48:74:9F:13:43:C9:AE:D0:F7
SHA1: DB:BB:D7:DB:8C:33:AA:06:6D:CF:D2:5C:EB:64:01:D5:AD:AB:94:38
Signature algorithm name: SHA1withRSA
Version: 3
Trust this certificate? [no]: y
keytool error: java.security.KeyStoreException: TrustedCertEntry not supported
java.security.KeyStoreException: TrustedCertEntry not supported
at com.sun.net.ssl.internal.pkcs12.PKCS12KeyStore.engineSetCertificateEntry(PKCS12KeyStore.java:620)
at java.security.KeyStore.setCertificateEntry(KeyStore.java:941)
at sun.security.tools.KeyTool.addTrustedCert(KeyTool.java:1958)
at sun.security.tools.KeyTool.doCommands(KeyTool.java:818)
at sun.security.tools.KeyTool.run(KeyTool.java:172)
at sun.security.tools.KeyTool.main(KeyTool.java:166)
Actually P12 format does not permit trusted certificates. It is inteded to contain key/pairs only. So importing mycompany.root.ca.cer into mihail.stoynov.p12 failed.
I tried several things:
1) Importing mihail.stoynov.signed.cer directly into mihail.stoynov.p12:
keytool
-importcert
-keystore mihail.stoynov.p12
-storetype pkcs12
-storepass mihail.stoynov
-alias mihail.stoynov
-keypass mihail.stoynov
-file mihail.stoynov.signed.cer
-v
and the response was:
keytool error: java.lang.Exception: Failed to establish chain from reply
java.lang.Exception: Failed to establish chain from reply
at sun.security.tools.KeyTool.establishCertChain(KeyTool.java:2662)
at sun.security.tools.KeyTool.installReply(KeyTool.java:1870)
at sun.security.tools.KeyTool.doCommands(KeyTool.java:807)
at sun.security.tools.KeyTool.run(KeyTool.java:172)
at sun.security.tools.KeyTool.main(KeyTool.java:166)
2) Importing mycompany.root.ca.cer into cacerts:
keytool -importcert -trustcacerts -file mycompany.root.ca.cer
This again didn't fix the problem.
Solution to Problem No 2:
Transform P12 to JKS, import the root certificate and the signed certificate into JKS keystore, transform the modified JKS back to P12.
1) Transform P12 to JKS
keytool
-importkeystore
-srckeystore mihail.stoynov.p12
-destkeystore mihail.stoynov.jks
-srcstoretype pkcs12
-srcstorepass mihail.stoynov
-deststorepass mihail.stoynov
2) import the root certificate into the JKS keystore
keytool
-importcert
-keystore mihail.stoynov.jks
-storepass mihail.stoynov
-alias mycompany.root.ca
-keypass mycompany.root.ca
-file mycompany.root.ca.cer
-v
3) import signed certificate into JKS keystore
keytool
-importcert
-keystore mihail.stoynov.jks
-storepass mihail.stoynov
-alias mihail.stoynov
-keypass mihail.stoynov
-file mihail.stoynov.signed.cer
-v
4) transform the modified JKS back to P12
keytool
-importkeystore
-srckeystore mihail.stoynov.jks
-destkeystore mihail.stoynov.p12
-deststoretype pkcs12
-srcstorepass mihail.stoynov
-deststorepass mihail.stoynov
it said something like:
Entry for alias mihail.stoynov successfully imported.
Problem importing entry for alias mycompany.root.ca: java.security.KeyStoreException: TrustedCertEntry not supported.
Entry for alias mycompany.root.ca not imported.
Do you want to quit the import process? [no]: n
Import command completed: 1 entries successfully imported, 1 entries failed or cancelled
I clicked yes, and it worked.
Now let's see what's the difference between mihail.stoynov.jks and mihail.stoynov.p12:
JKS:
$ keytool -list -keystore mihail.stoynov.jks -storetype jks -storepass mihail.stoynov -v
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 2 entries
Alias name: mihail.stoynov
Creation date: Mar 12, 2009
Entry type: PrivateKeyEntry
Certificate chain length: 2
Certificate[1]:
Owner: CN=Mihail Stoynov, OU=MyCompany Sofia, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Issuer: CN=MyCompany Bulgaria, OU=Office No 5, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Serial number: f0e465bb77420e30
Valid from: Thu Mar 12 09:29:19 GMT+00:02 2009 until: Sun Mar 10 09:29:19 GMT+00:02 2019
Certificate fingerprints:
MD5: 40:9D:C2:DE:AE:11:1E:01:92:F9:C8:01:C5:92:69:CB
SHA1: D2:D0:03:5C:50:BC:F8:6C:EB:C0:36:B6:B0:8D:A8:3B:9E:B6:7B:B4
Signature algorithm name: SHA1withRSA
Version: 1
Certificate[2]:
Owner: CN=MyCompany Bulgaria, OU=Office No 5, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Issuer: CN=MyCompany Bulgaria, OU=Office No 5, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Serial number: 49b8c365
Valid from: Thu Mar 12 08:12:13 GMT+00:02 2009 until: Sun Mar 10 08:12:13 GMT+00:02 2019
Certificate fingerprints:
MD5: 1C:0C:82:0D:35:C8:1E:48:74:9F:13:43:C9:AE:D0:F7
SHA1: DB:BB:D7:DB:8C:33:AA:06:6D:CF:D2:5C:EB:64:01:D5:AD:AB:94:38
Signature algorithm name: SHA1withRSA
Version: 3
*******************************************
*******************************************
Alias name: mycompany.root.ca
Creation date: Mar 12, 2009
Entry type: trustedCertEntry
Owner: CN=MyCompany Bulgaria, OU=Office No 5, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Issuer: CN=MyCompany Bulgaria, OU=Office No 5, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Serial number: 49b8c365
Valid from: Thu Mar 12 08:12:13 GMT+00:02 2009 until: Sun Mar 10 08:12:13 GMT+00:02 2019
Certificate fingerprints:
MD5: 1C:0C:82:0D:35:C8:1E:48:74:9F:13:43:C9:AE:D0:F7
SHA1: DB:BB:D7:DB:8C:33:AA:06:6D:CF:D2:5C:EB:64:01:D5:AD:AB:94:38
Signature algorithm name: SHA1withRSA
Version: 3
*******************************************
*******************************************
P12 (PKCS#12)
$ keytool -list -keystore mihail.stoynov.p12 -storetype pkcs12 -storepass mihail.stoynov -v
Keystore type: PKCS12
Keystore provider: SunJSSE
Your keystore contains 1 entry
Alias name: mihail.stoynov
Creation date: Mar 12, 2009
Entry type: PrivateKeyEntry
Certificate chain length: 2
Certificate[1]:
Owner: CN=Mihail Stoynov, OU=MyCompany Sofia, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Issuer: CN=MyCompany Bulgaria, OU=Office No 5, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Serial number: f0e465bb77420e30
Valid from: Thu Mar 12 09:29:19 GMT+00:02 2009 until: Sun Mar 10 09:29:19 GMT+00:02 2019
Certificate fingerprints:
MD5: 40:9D:C2:DE:AE:11:1E:01:92:F9:C8:01:C5:92:69:CB
SHA1: D2:D0:03:5C:50:BC:F8:6C:EB:C0:36:B6:B0:8D:A8:3B:9E:B6:7B:B4
Signature algorithm name: SHA1withRSA
Version: 1
Certificate[2]:
Owner: CN=MyCompany Bulgaria, OU=Office No 5, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Issuer: CN=MyCompany Bulgaria, OU=Office No 5, O=MyCompany, L=Sofia, ST=Sofia, C=BG
Serial number: 49b8c365
Valid from: Thu Mar 12 08:12:13 GMT+00:02 2009 until: Sun Mar 10 08:12:13 GMT+00:02 2019
Certificate fingerprints:
MD5: 1C:0C:82:0D:35:C8:1E:48:74:9F:13:43:C9:AE:D0:F7
SHA1: DB:BB:D7:DB:8C:33:AA:06:6D:CF:D2:5C:EB:64:01:D5:AD:AB:94:38
Signature algorithm name: SHA1withRSA
Version: 3
*******************************************
*******************************************
Do you see the difference?
It's in italic - JKS format keeps an extra trusted certificate of MyCompany Root CA.
Anyway both mihail.stoynov.jks and mihail.stoynov.p12 work perfectly.
P.S.
Does someone know better solutions to Problem No 1 and Problem No 2?
Does someone know how to sign certificates but without the cumbersome CSR step?