I recently run into needing a pair of *.pem
and *.jks
self-signed certificates for local TLS verification. After some reading I put together this guide for generating either and converting it to the other.
You can use two approaches:
Note: This guide is based on documentation for an open source library I built recently called IBeam. It is a wrapper working with IBKR Client Portal Web API Gateway. For that reason all example URLs below point to localhost:5000/v1/api/one/user
. Modify this URL to whatever routes your server supports.
Generating Certificates
You can generate your own self-signed certificate in two ways:
-
Using Keytool to generate
cacert.jks
-
Using OpenSSL to generate
cacert.pem
Either way you chose, you will then need to convert one certificate into the other. Therefore, you will need both Keytool and OpenSSL to generate your certificates.
Note that you can't generate cacert.jks
and cacert.pem
independently. You must generate only one certificate first using either method and then convert it into the other format.
Using Keytool
Generate JKS
Keytool is a Java tool shipped with Java Runtime Environment (JRE). It can be found in JRE_ROOT/bin/keytool
.
-
To generate the
cacert.jks
run:
keytool -genkey -keyalg RSA -alias selfsigned \ -keystore cacert.jks -storepass YOUR_CERTIFICATE_PASSWORD \ -validity 730 -keysize 2048
Note the YOUR_CERTIFICATE_PASSWORD field. Replace it which certificate password you want to use. You will need to use this same password in later steps.
Optionally, you may want to add additional option to provide Subject Alternative Names (SAN) in order for the certificate to accept requests from your client hosts. For instance, if the server is to be communicated with from two client machines, one with IP address of
10.148.0.0
and one with DNS ofmy-client.machine.com
, your keytool command line should include:
-ext SAN=ip:10.147.0.0,dns:my-client.machine.com
-
Upon running command from Step 1, you will be asked the following questions which you may chose to ignore:
- What is your first and last name?
- What is the name of your organizational unit?
- What is the name of your organization?
- What is the name of your City or Locality?
- What is the name of your State or Province?
- What is the two-letter country code for this unit?
-
Eventually, Keytool will ask for your confirmation, along the lines of:
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
Type
yes
to continue if the information is correct. Finally, Keytool will ask you for the key password. You may simply hit return to use the same password as specified in the
-storepass
flag in Step 1. DO NOT provide a different password than YOUR_CERTIFICATE_PASSWORD specified above.You should now have the
cacert.jks
file generated in your current directory.
Convert JKS to PEM
To convert a cacert.jks
to cacert.pem
file you need to:
-
Convert
cacert.jks
tocacert.p12
using Keytool:
keytool -importkeystore -srckeystore cacert.jks \ -destkeystore cacert.p12 -srcstoretype jks -deststoretype pkcs12
You will be asked for a new password for
cacert.p12
, as well as for the original password ofcacert.jks
. Ensure you use the same password as when generating thecacert.jks
. -
Convert
cacert.p12
tocacert.pem
using OpenSSL:
openssl pkcs12 -in cacert.p12 -out cacert.pem
Again, you will be asked for a new password for
cacert.pem
, as well as for the original password ofcacert.p12
. Ensure you use the same password as when generating thecacert.jks
andcacert.p12
. You should now have the
cacert.pem
file generated in your current directory.
You should now have cacert.jks
, cacert.p12
and cacert.pem
. You will only need the .jks
and .pem
files. You may delete the redundant cacert.p12
file.
Using OpenSSL
Generate PEM
-
To generate a
cacert.pem
using OpenSSL run:
openssl req -x509 -days 730 -newkey rsa:2048 \ -keyout key.pem -out cert.pem
Optionally, you may want to add additional option to provide Subject Alternative Names (SAN) in order for the certificate to accept requests from your client hosts. To do so, you must create a
san.cnf
used as a configuration file for openssl, and add the following to the openssl command line:
-config san.cnf
Your
san.cnf
can take multiple forms, yet to support SAN it requires the subjectAltName field. Have a look at this template san.cnf file that you can use as a basis to specify your SANs.For instance, if the server is to be communicated with from two client machines, one with IP address of
10.148.0.0
and one with DNS ofmy-client.machine.com
, yoursan.cnf
should contain:
[alt_names] IP.1 = 10.148.0.0 DNS.1 = my-client.machine.com
You will be asked for a password. You will need to use this same password in later steps.
You should now have
key.pem
andcert.pem
files in your current directory.-
Combine
key.pem
andcert.pem
to createcacert.pem
:
cat key.pem cert.pem > cacert.pem
You can also merge these two files manually if you prefer.
You should now have
cacert.pem
,key.pem
andcert.pem
. You will only need thecacert.pem
file. You may delete the redundantkey.pem
andcert.pem
files.
PEM to JKS
To convert a cacert.pem
to cacert.jks
file you need to:
-
Convert
cacert.pem
tocacert.p12
using OpenSSL:
openssl pkcs12 -export -in cacert.pem -out cacert.p12
You will be asked for a new password for
cacert.p12
, as well as for the original password ofcacert.pem
. Ensure you use the same password as when generating thecacert.pem
. -
Convert
cacert.p12
tocacert.jks
using Keytool:
keytool -importkeystore -srckeystore cacert.p12 \ -srcstoretype pkcs12 -destkeystore cacert.jks
Again, you will be asked for a new password for
cacert.jks
, as well as for the original password ofcacert.p12
. Ensure you use the same password as when generating thecacert.pem
andcacert.p12
. You should now have the
cacert.jks
file generated in your current directory.
You should now have cacert.pem
, cacert.p12
and cacert.jks
. You will only need the .jks
and .pem
files. You may delete the redundant cacert.p12
file.
Use your certificate
cURL
cURL accepts --cacert
flag that can be used to pass the certificate. See cURL documentation for more.
curl -X GET "https://localhost:5000/v1/api/one/user" \
--cacert cacert.pem
Python urllib3
Python urllib3 library allows you to specify a SSL context through which you can specify the location of your certificate.
context = ssl.create_default_context()
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
context.load_verify_locations('cacert.pem')
urllib.request.urlopen("https://localhost:5000/v1/api/one/user",
context=context)
Python requests
Python requests library allows you to set the verify
parameter to specify the location of your certificate.
requests.get("https://localhost:5000/v1/api/one/user",
verify='cacert.pem')
Ignoring the TLS verification
For debugging and development, you may chose to ignore the TLS verification. This section describes ways of doing so in cURL
, Python's urllib3
and requests
libraries.
cURL
cURL accepts --insecure
or -k
flags that can be used to ignore verifying certificates. See [cURL documentation][curl-k] for more.
curl -X GET "https://localhost:5000/v1/api/one/user" -k
Python urllib3
Python urllib3 library allows you to specify an empty SSL context, which effectively will ignore verifying the certificates.
empty_context = ssl.SSLContext()
urllib.request.urlopen("https://localhost:5000/v1/api/one/user",
context=empty_context)
Python requests
Python requests library allows you to set the verify
parameter to False
when making requests, which effectively will ignore verifying the certificates.
requests.get("https://localhost:5000/v1/api/one/user",
verify=False)
Hope you guys find this guide useful 👋
Final word: It's a whole another conversation whether it is a good idea to create self-signed certificates and where do they belong. This guide is merely showing you how to create a pair of certificates. It is recommended to verify whether self-signed certificates would be the right choice for your use case.
Top comments (0)