Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Self Signed Certificate with Custom Root CA

Create Root CA (Done once)

Create Root Key

Attention: this is the key used to sign the certificate requests, anyone holding this can sign certificates on your behalf. So keep it in a safe place!

openssl genrsa -des3 -out rootCA.key 4096

If you want a non password protected key just remove the -des3 option

Create and self sign the Root Certificate

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt

Here we used our root key to create the root certificate that needs to be distributed in all the computers that have to trust us.

Create a certificate (Done for each server)

This procedure needs to be followed for each server/appliance that needs a trusted certificate from our CA

Create the certificate key

openssl genrsa -out mydomain.com.key 2048

Create the signing (csr)

The certificate signing request is where you specify the details for the certificate you want to generate. This request will be processed by the owner of the Root key (you in this case since you create it earlier) to generate the certificate.

Important: Please mind that while creating the signign request is important to specify the Common Name providing the IP address or domain name for the service, otherwise the certificate cannot be verified.

I will describe here two ways to gener

Method A (Interactive)

If you generate the csr in this way, openssl will ask you questions about the certificate to generate like the organization details and the Common Name (CN) that is the web address you are creating the certificate for, e.g mydomain.com.

openssl req -new -key mydomain.com.key -out mydomain.com.csr

Method B (One Liner)

This method generates the same output as Method A but it's suitable for use in your automation :) .

openssl req -new -sha256 -key mydomain.com.key -subj "/C=US/ST=CA/O=MyOrg, Inc./CN=mydomain.com" -out mydomain.com.csr

If you need to pass additional config you can use the -config parameter, here for example I want to add alternative names to my certificate.

openssl req -new -sha256 \
    -key mydomain.com.key \
    -subj "/C=US/ST=CA/O=MyOrg, Inc./CN=mydomain.com" \
    -reqexts SAN \
    -config <(cat /etc/ssl/openssl.cnf \
        <(printf "\n[SAN]\nsubjectAltName=DNS:mydomain.com,DNS:www.mydomain.com")) \
    -out mydomain.com.csr

Verify the csr's content

openssl req -in mydomain.com.csr -noout -text

Generate the certificate using the mydomain csr and key along with the CA Root key

openssl x509 -req -in mydomain.com.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out mydomain.com.crt -days 500 -sha256

Verify the certificate's content

openssl x509 -in mydomain.com.crt -text -noout
@dthrash

This comment has been minimized.

Copy link

@dthrash dthrash commented Mar 1, 2018

How does the private key fit in here? Doesn't the pem file need to be generated too?

@fxpires

This comment has been minimized.

Copy link

@fxpires fxpires commented Mar 6, 2018

The files with ".key" extension are the private keys.

@qfan

This comment has been minimized.

Copy link

@qfan qfan commented Apr 23, 2018

Is there a way to inform openssl to ask for the SAN (Subject Alternative Name) when generating the CSR?

@kalloa

This comment has been minimized.

Copy link

@kalloa kalloa commented May 12, 2018

@qfan You can use -config option to pass SAN to openssl
openssl req -new -key mydomain.com.key -out mydomain.com.csr -config certificate.conf
this is an example of certificate.conf

[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[dn]
C = HU
ST = Budapest
L = Budapest
O = ACME
OU = ACME Inc
emailAddress = kalloa@example.com
CN = example.com
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com

@jkpaye

This comment has been minimized.

Copy link

@jkpaye jkpaye commented May 31, 2018

Suggest you change the encryption from triple des to something stronger.

@scipilot

This comment has been minimized.

Copy link

@scipilot scipilot commented Jun 11, 2018

@qfan You will also need to pass the same config to the x509 command when you use the CSR, with -extfile certificate.conf -extensions req_ext. Took me a while to figure out.

@Fermec28

This comment has been minimized.

Copy link

@Fermec28 Fermec28 commented Jun 25, 2018

can I Generate the certificate using the third-domain csr and key along with the CA mydomain key ?
Root
mydomain
third-domain

@vs4vijay

This comment has been minimized.

Copy link

@vs4vijay vs4vijay commented Oct 10, 2018

Whats the difference between these two lines:

openssl x509 -req -in localhost.csr -CA root-CA.crt -CAkey root-CA.pem -CAcreateserial -out localhost.crt -days 365 -sha256

AND

openssl x509 -req -in localhost.csr -signkey root-CA.pem -out localhost.crt -days 365 -sha256

Are these commands are same? I have checked the output from these... Output were different but I guess both are used for signing CSR with Root CA... but whats the difference?

@choas75

This comment has been minimized.

Copy link

@choas75 choas75 commented Oct 25, 2018

@qfan You will also need to pass the same config to the x509 command when you use the CSR, with -extfile certificate.conf -extensions req_ext. Took me a while to figure out.

This is actually a very important comment. If forgotten the subjectAltName with the IP address will be missing!
Thanks scipilot!

@anand-k-p

This comment has been minimized.

Copy link

@anand-k-p anand-k-p commented Nov 2, 2018

@fntlnz - thank you very, very much for this Gist, it has enabled me to FINALLY get past a major hurdle with app development on Android Google Chrome!!!

I wanted to ask if you could perhaps update the gist to reflect the addition of "Subject Alternative Name" as the Common Name has become (according to some SO answers I've seen) a non-authoritative representation of the domain name and, apparently, will be phased out in some time. It has become important (and modern Firefox and Chrome at least demand it) that certificates be generated specifying DNS entries representing the domain name using the subjectAltName config setting. Source: https://stackoverflow.com/a/49087278.

Having learned this, I can say that almost all the steps in this Gist work for Google Chrome but, without some adjustments, Chrome keeps displaying an SSL Invalid message (and more importantly, in chromeless web apps, displaying an HTTPS Error warning bar at the top). In order to pass all the checks so that Chrome doesn't show this warning bar in chromeless apps, you need to specify the subjectAltName values for your domain(s), e.g. example.com and www.example.com.

Using the technique mentioned by @scipilot is what cleared all this up. @scipilot's comment was in response to @qfan's question:

@qfan You will also need to pass the same config to the x509 command when you use the CSR, with -extfile certificate.conf -extensions req_ext. Took me a while to figure out.

@scipilot - thank you SO MUCH for returning and sharing this information (as @choas75 already mentioned).

@fntlnz, I'd like to suggest that you modify your instructions for the section:

If you need to pass additional config you can use the -config parameter, here for example I want to add alternative names to my certificate.

To include the instructions provided by @scipilot. I feel it will save A LOT of people A LOT of head scratching!

Thanks everyone! 😄 👍

@nuvitu

This comment has been minimized.

Copy link

@nuvitu nuvitu commented Nov 22, 2018

After did all steps, When I put .cer file to ios, it is shown that Not verified (Unverified profile - The authenticity of "xxx" cannot be verified.) => So I can install it, but after installed, it is still not verified.

Could you please tell me why ?

@ramumanavalan

This comment has been minimized.

Copy link

@ramumanavalan ramumanavalan commented Jan 19, 2019

openssl x509 -req -extfile <(printf "subjectAltName=example.com,DNS:*.example.com") -days 365 -in domain.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out domain.crt

@xenogenesi

This comment has been minimized.

Copy link

@xenogenesi xenogenesi commented Jan 31, 2019

Thanks for this gist, I created a Makefile from it, tested on linux only (see this gist)

@alexgrud

This comment has been minimized.

Copy link

@alexgrud alexgrud commented Jul 19, 2019

Thanks a lot for this post!

@pitometsyurii

This comment has been minimized.

Copy link

@pitometsyurii pitometsyurii commented Jul 26, 2019

Thanks.

@abdkaviani

This comment has been minimized.

Copy link

@abdkaviani abdkaviani commented Aug 25, 2019

Hi

I'm looking for the way that use SSL in my local network (Apache & Windows server with IP adress like 192.168.10.10) and I don't like that browser display "your connection is not secure" or it works after "Add Exception" option.
I read many articles & I couldn't solve this problem.
I want a real secure ssl in my localhost
Can you help me?
Thanks a lot

@gaochundong

This comment has been minimized.

Copy link

@gaochundong gaochundong commented Aug 30, 2019

Thanks.

@bkrahmer

This comment has been minimized.

Copy link

@bkrahmer bkrahmer commented Sep 4, 2019

I'm looking for the way that use SSL in my local network (Apache & Windows
server with IP adress like 192.168.10.10) and I don't like that browser display
"your connection is not secure" or it works after "Add Exception" option.
I read many articles & I couldn't solve this problem.
I want a real secure ssl in my localhost

@abdkaviani: This article is about creating a self-signed certificate. If you want to avoid the security warnings, the certificate has to have a chain all the way back to a trusted authority. You'll have to use one of the commercial services to get a certificate like that.

@garydmx29

This comment has been minimized.

Copy link

@garydmx29 garydmx29 commented Sep 16, 2019

Does the root key and subsequent steps have to be done on the server hosting/using the SSL setup?

@yo1995

This comment has been minimized.

Copy link

@yo1995 yo1995 commented Sep 22, 2019

The commands I used for adding SAN to the request and certificate are

$ openssl req -new -sha256 \
    -key SERVER.key \
    -subj "/C=US/ST=North Carolina/O=ORG/OU=ORG_UNIT/CN=YOUR_DOMAIN_NAME" \
    -reqexts SAN \
    -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:YOUR_DOMAIN_NAME")) \
    -out SERVER.csr

and for signing

$ openssl x509 -req -extfile <(printf "subjectAltName=DNS:YOUR_DOMAIN_NAME") -days 120 -in SERVER.csr -CA rootCA.crt -CAkey root_rsa.key -CAcreateserial -out SERVER.crt -sha256

based on the discussions above.

It finally results in a secure connection with Chrome.
Picture1

Hope it helps people who come here for classes or server SSL setup! 😄

@fhajji

This comment has been minimized.

Copy link

@fhajji fhajji commented Oct 1, 2019

Thanks, that was very helpful.

Unfortunately, RSA keys are rather slow to process. It would be better to generate Elliptic Curve keys for the servers, and have them signed by the root CA. It looks like Let's Encrypt would do this already:

https://dev.to/benjaminblack/obtaining-an-elliptic-curve-dsa-certificate-with-lets-encrypt-51bc

It may be even better, it the root CA would use Elliptic Curve keys to sign any certificate that is thrown at it... but would certificates signed (by the root CA) with an EC key be accepted by the majority of TLS clients out there?

@itsnuwan

This comment has been minimized.

Copy link

@itsnuwan itsnuwan commented Oct 23, 2019

The commands I used for adding SAN to the request and certificate are

$ openssl req -new -sha256 \
    -key SERVER.key \
    -subj "/C=US/ST=North Carolina/O=ORG/OU=ORG_UNIT/CN=YOUR_DOMAIN_NAME" \
    -reqexts SAN \
    -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:YOUR_DOMAIN_NAME")) \
    -out SERVER.csr

and for signing

$ openssl x509 -req -extfile <(printf "subjectAltName=DNS:YOUR_DOMAIN_NAME") -days 120 -in SERVER.csr -CA rootCA.crt -CAkey root_rsa.key -CAcreateserial -out SERVER.crt -sha256

based on the discussions above.

It finally results in a secure connection with Chrome.
Picture1

Hope it helps people who come here for classes or server SSL setup!

this works.thanks.saved lot of time

@pistacchio

This comment has been minimized.

Copy link

@pistacchio pistacchio commented Nov 28, 2019

I followed all the steps and configured nginx to use the generated certificate:

    ssl_certificate         /root/mydomain.com.crt;
    ssl_certificate_key     /root/mydomain.com.key;
    ssl_client_certificate  /root/rootCA.crt;

    ssl_verify_client on;
    ssl_verify_depth 2;

however, when trying it with curl it doens't work: curl --cacert rootCA.crt https://localhost:9090

Any idea?

@boypt

This comment has been minimized.

Copy link

@boypt boypt commented Dec 2, 2019

some may require the certificate contain extendedKeyUsage=serverAuth, the sign command needs some more attributes:

openssl x509 -req \
        -extfile <(printf "[v3_req]\nextendedKeyUsage=serverAuth\nsubjectAltName=DNS:*.mydomain.best,DNS:*.mydomian.xxx") \
        -extensions v3_req \
        -days 365 -in mydomain.com.csr -CA rootCA.crt -CAkey rootCA.key \
        -CAcreateserial -out mydomain.com.csr -sha256
@boypt

This comment has been minimized.

Copy link

@boypt boypt commented Dec 2, 2019

Apple require all TLS server certificates issued after July 1, 2019 "contain an ExtendedKeyUsage (EKU) extension containing the id-kp-serverAuth OID."

https://support.apple.com/en-us/HT210176

@ganeshkamath89

This comment has been minimized.

Copy link

@ganeshkamath89 ganeshkamath89 commented Dec 12, 2019

How to pass subjectAltName parameter on windows?

@boumanb

This comment has been minimized.

Copy link

@boumanb boumanb commented Dec 23, 2019

Thanks! 😄

@chainhead

This comment has been minimized.

Copy link

@chainhead chainhead commented Dec 28, 2019

Thanks for the gist!

I couldn't get the instructions in this gist working on a Mac. When using the generated certificate elsewhere, I would get this error message - Error getting keypair for CA issuer: certificate is not a CA. After some research, I found that,

It turns out that on MacOS the default OpenSSL config does not include the configuration for v3_ca certificate generation.

For more details, see Error getting keypair for CA issuer: certificate is not a CA.

I have extracted the relevant portion and pasted here.

##  - Create new root CA key and certificate
openssl genrsa -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -subj "/CN=rootCA.crt" \ 
-reqexts v3_req -extensions v3_ca \ 
-out rootCA.crt -config crt.conf

The crt.conf is defined as follows. Note the [ v3_ca ] section and basicConstraints = critical,CA:TRUE.

[ v3_ca ]
basicConstraints = critical,CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = org
@faizafaiza02

This comment has been minimized.

Copy link

@faizafaiza02 faizafaiza02 commented Feb 22, 2020

Hi,
I am trying the above steps to generate a certificate for PWA(Ionic/Angular) intranet sites in IIS(Windows). There is no specific domain. So I tried using the Computer name instead of domain.com but for some reason the certificate doesn't get recognized in the IIS. Can someone please help in making the below steps run in Windows PowerShell:

Method 2 Create the signing (csr)
$ openssl req -new -sha256
-key SERVER.key
-subj "/C=US/ST=North Carolina/O=ORG/OU=ORG_UNIT/CN=YOUR_DOMAIN_NAME"
-reqexts SAN
-config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:YOUR_DOMAIN_NAME"))
-out SERVER.csr

Method 2 Generate the certificate using the mydomain csr and key along with the CA Root key
$ openssl x509 -req -extfile <(printf "subjectAltName=DNS:YOUR_DOMAIN_NAME") -days 120 -in SERVER.csr -CA rootCA.crt -CAkey root_rsa.key -CAcreateserial -out SERVER.crt -sha256

@q2dg

This comment has been minimized.

Copy link

@q2dg q2dg commented Mar 31, 2020

Whats the difference between these two lines:

openssl x509 -req -in localhost.csr -CA root-CA.crt -CAkey root-CA.pem -CAcreateserial -out localhost.crt -days 365 -sha256

AND

openssl x509 -req -in localhost.csr -signkey root-CA.pem -out localhost.crt -days 365 -sha256

Are these commands are same? I have checked the output from these... Output were different but I guess both are used for signing CSR with Root CA... but whats the difference?

I've spent hours searching for a response to this exactly same question but finally I've given up :_/

@trevor403

This comment has been minimized.

Copy link

@trevor403 trevor403 commented Mar 31, 2020

thank you this was super helpful!

@faktorqm

This comment has been minimized.

Copy link

@faktorqm faktorqm commented Apr 23, 2020

Thanks a lot for all! I was able to make it "secure" on Chrome.

@chrismacp

This comment has been minimized.

Copy link

@chrismacp chrismacp commented May 6, 2020

The commands I used for adding SAN to the request and certificate are

$ openssl req -new -sha256 \
    -key SERVER.key \
    -subj "/C=US/ST=North Carolina/O=ORG/OU=ORG_UNIT/CN=YOUR_DOMAIN_NAME" \
    -reqexts SAN \
    -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:YOUR_DOMAIN_NAME")) \
    -out SERVER.csr

and for signing

$ openssl x509 -req -extfile <(printf "subjectAltName=DNS:YOUR_DOMAIN_NAME") -days 120 -in SERVER.csr -CA rootCA.crt -CAkey root_rsa.key -CAcreateserial -out SERVER.crt -sha256

based on the discussions above.

It finally results in a secure connection with Chrome.
Picture1

Hope it helps people who come here for classes or server SSL setup! 😄

Thanks, the initial instructions didn't work properly, the SAN was missing from the final signed certificate.

@notariuss

This comment has been minimized.

Copy link

@notariuss notariuss commented May 24, 2020

I followed your guide but cannot verify created certificate with root CA

openssl verify -CAfile rootCA.crt mydomain.com.crt
C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
error 18 at 0 depth lookup: self signed certificate
error mydomain.com.crt: verification failed

@perseon

This comment has been minimized.

Copy link

@perseon perseon commented Jun 2, 2020

I had to amend the last command because on ubuntu the certificate was missing the SAN section.
what i did was to create ans supply a config file
openssl x509 -req -in 192.168.10.100.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out 192.168.10.100.crt -days 3650 -sha256 -extfile certificate.conf -extensions req_ext

and the config file contains:

[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[dn]
C = RO
ST = Bucharest
L = Bucharest
O = ACME, INC
OU = OU
emailAddress = some@email.com
CN = address.local
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = address.local
IP.1 = 192.168.10.100

@AlexeyNovikov

This comment has been minimized.

Copy link

@AlexeyNovikov AlexeyNovikov commented Jul 4, 2020

A small note. If you want to use this in your local network you have to add IP addresses your server runs on as well as localhost to subjectAltName, e.g.:

[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = development.personal #real domain
DNS.2 = localhost
IP.1 = 127.0.0.1 # ip for localhost
IP.2 = 192.168.10.10 # local network address
IP.3 = 94.181.174.85 # external address

@ykfq

This comment has been minimized.

Copy link

@ykfq ykfq commented Jul 16, 2020

openssl genrsa -out apiserver.key 2048
openssl req -new -key apiserver.key -out apiserver.csr -subj "/CN=kube-apiserver"
openssl x509 -req -in apiserver.csr -CA /etc/kubernetes/ssl/ca.crt -CAkey /etc/kubernetes/ssl/ca.key \
             -CAcreateserial -out apiserver.crt -days 3650 -extensions SAN \
             -extfile <(printf "[SAN]\nsubjectAltName=DNS:localhost,DNS:kubernetes,DNS:kubernetes.default,DNS:kubernetes.default.svc,DNS:kubernetes.default.svc.cluster.local,DNS:lb-apiserver.kubernetes.local,IP:127.0.0.1,IP:192.168.10.21,IP:192.168.10.21")
@edbshubham

This comment has been minimized.

Copy link

@edbshubham edbshubham commented Sep 6, 2020

The security team is just providing the rootCA.crt but not rootCA.key, is their any way to sign the server level certificate using the only rootCA.crt?

@xB-2048

This comment has been minimized.

Copy link

@xB-2048 xB-2048 commented Sep 21, 2020

@edbshubham Usually security teams won't share rootCA private key. Please send the CSR to your security team and ask them to sign it In response you should receive the signed cert and the rootCA.crt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.