Self-signed certificates are useful for testing as well as some limited real-world use-cases. The instructions below cover commands necessary to create self-signed certificates using keytool.
keytool, being included with Java JDK installations, is more likely to be available on Windows if OpenJDK or Oracle JDK is installed, however Linux/Unix/OSX users will also typically have the more robust openssl program readily available to them. For instructions on how to create certificates using openssl, you can follow these instructions instead.
Note: To be clear, OpenSSL is also available for Windows however it is rarely found already installed on systems.
Whenever cryptography is involved, you can expect to a deluge of terminology about complex concepts. Fully fleshing out these concepts is beyond the scope of this piece, but it would be beneficial to roughly summarize some of the terms as they apply to the operations used further down:
- Keystore or Truststore - Container file designed to hold cryptographic materials such as keys, certificates, etc.
- PFX - Effectively an alternate name for PKCS12 files. PFX is usually found within Microsoft contexts as PFX was initially a Microsoft format before it eventually became re-defined by RFC 7292 as PKCS12.
- Key Pair - A public key and its corresponding private key together are commonly referred to as a "key pair".
- Private Key - The secret key of a key pair that should be availble only to the owner or owner programs/processes
- Public Key - The public key of a key pair that is made available to one or more external parties to encrypt data that can (well...should) only be decrypted by someone with access to the corresponding secret key.
- Certificate - A file format (typically X.509) that includes a key (commonly a public key) along with other relevant information such as expiration, issuer, etc.
A Quick Note On Approach
Several best practices are intentionally not followed in the commands below in order to emphasize the overall mechanics. Things like the keystore password being 'password', private key password not being set, and passwords included on the command line should not be followed outside an educational exercise context.
As mentioned above, keytool is provided with Java JDK installations. It is capable of generating the necessary self-signed certificate materials however is otherwise fairly limited in its capabilities. For example as of the time of this writing there is no way to export a private key into its own dedicated file using keytool, only to another keystore container file.
Another item to note is that prior to Java 9 the default keystore container format for keytool was JKS, which is a Java-specific format which limits its use by other software and tools. The examples below instruct keytool to use the more widely supported PKCS12 container format instead.
Keytool primarily deals with keystores, so the approach followed below is to simultaneously generate a new keypair and store it in a new keystore, then afterwards export the public certificate to its own file.
Create PKCS12 keystore container
keytool \ -genkeypair \ -ext san=dns:localhost \ -storetype PKCS12 \ -keystore server.p12 \ -storepass password \ -alias myalias \ -keyalg RSA \ -keysize 4096 \ -dname "C=,S=,L=,O=,OU=,CN=localhost"
Export the certificate
keytool \ -exportcert \ -rfc \ -keystore server.p12 \ -storepass password \ -alias myalias \ -file server.public.crt
(Optional) Examine the keystore
keytool \ -list \ -v \ -storetype PKCS12 \ -storepass password \ -keystore server.p12
Testing with OpenSSL
Even if you've created your certificate with keytool, you can use openssl to quickly test it.
Note: As keytool does not have a built-in ability to export private keys, prior to testing you'll need to export the private key from the p12 container using openssl:
openssl pkcs12 \
-in server.p12 \
-passin pass:password | openssl rsa -outform PEM -out server.private.key
Starting the test server
The following commands will start the TLS/SSL server bound to TCP port 4430 and instruct it to respond to a simple HTTP GET requests.
openssl s_server \ -key server.private.key \ -cert server.public.crt \ -accept 4430 \ -no_dhe \ -www
Testing client-side with web browser
Browse to https://localhost:4430 in a browser (you may have to click past warnings). You should see info text provided by test server (ciphers supported, ciphers in common with client, etc)
Testing client-side on the command line
- In a separate teminal window or tab, run:
openssl s_client -connect localhost:4430
- Followed by:
GET / HTTP 1.0
- Then the Enter key
You should see the same HTML used to generate the page for the browser test.