how to create a certificate

we will show step by step on how to create a CA certificate and use that CA certificate to create a server certificate.

you need to understand "public key infrastructure (PKI)" and then "digital certificate (cert)" in order to understand this writing.

During TLS hand shaking, a client ( thinking firefox ) needs to verify a cert from a server, e.g., "https://gmail.com". The cert might be signed by Certificate Authority A, whose cert might be signed by Certificate Authority B, and C, and D. This so called "CA chain" needs to be maintained carefully and updated periodically to avoid rejecting authorized cert. It is a big burden for clients.

on one firefox installation on linux, it maintains 173 CA certificates:

ls -lt /usr/share/ca-certificates/mozilla/ | wc -l

173

When both TLS communication end points are owned by a single entity, and the server only allows certain clients to connect, the server becomes a "closed server", as compared to all "open servers" on internet, which allow any clients to connect.

Since obtaining a server cert cost money and time ( though on-demand cert is available ), for "closed server" scenario, we can home cook a cert for server to use, since we own client as well, we can easily fool client to accept the home cooked server cert.

here are the steps to do so. ( I should not take the credit as I found below link is the most explicit instructions on the internet and I am just adding extra comments on each step )

https://github.com/codequest-eu/grpc-demo/commit/30f4520d3c06f6f1cc2e4f3ffb88e752ffee09ea

step 1: Generate a CA private key. This create a file that contains a private key as well as a public key. Note this file should be "owner read only". You publish your public key via a cert file, not key file.

openssl genrsa -des3 -out ca.key 4096

step 2: Generate a CA certificate. This is a root cert and we will use it to sign another cert to be used on our server. Very important: you must be careful of choosing "organization name and common name". Those names, along with country code, etc., are called "Issuer". CA cert is used to issue a cert to a server.

openssl req -new -x509 -days 365 -key ca.key -out ca.crt

step 3: Generate a server private key ( it contains a public key as well ). This is a private key that server will use during TLS handshaking to agree on a symmetric key. Refer here for TLS basics

openssl genrsa -des3 -out server.key 4096

step 4: Generate server signing request. This is a request to generate a cert. Very important: you must use different organization name and common name from what you used when generated CA cert. those pieces together are called "subject". If "issuer" is the same as "subject", X509 requires to declare the cert as self-signed. We are not generated a self-signed server cert. We are generating a server cert that is signed by a CA cert ( This CA cert is generated by us as well )please ignore "challenge password" when prompted.

openssl req -new -key server.key -out server.csr

step 5: generate a server certificate signed by the CA cert generated earlier.

openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

step 6: Remove passphrase from the server key. We need this in order to use the private key in our code.

openssl rsa -in server.key -out server.key

Now, we got a server cert that we can verify using the CA cert. Both certs are generated by us. However, the CA cert is self-signed, but server cert is signed by our CA cert.

step 7: very the server cert is acceptable.

openssl verify -CAfile ca.crt server.crt

step 8: copy "ca.crt" to the location where client code requires. If client code using openssl, the location should be "/etc/ssl/certs". If client code is a different implementation of x509, you need to check programming manual.

step 9: copy "server.crt" and "server.key" to the location where server code requires. If server code is using openssl, the location should be "/etc/ssl/certs". If server code is a different implementation of x509, you need to check programming manual.

For golang programming, because golang implements its own TLS and x509, it requires to load the certs directly into your code. Below is code example on both client side ( loading ca.crt ) and server side ( loading server.crt and server.key ):

https://github.com/grpc/grpc-go/tree/master/examples/route_guide

Note that there are server private key and server cert and CA cert under folder "testdata". I looked into the key and certs, and it appears that the key and certs were generated by following exactly the above steps.

final notes:

1. ".crt" file suffix is the same as ".pem" file suffix. From x509 point of view, they are alias of each other and the former appears more popular on windows system and the latter appears more popular on Linux likes.

2. be care of when prompt for input during above steps. at least chose a unique organization name for each and every different cert, otherwise the server cert might become self-signed, and might be rejected by clients.

3. you can follow same steps above to generate a client cert if your TLS requires two factor authentication, this is rare.

4. your private key file should be "owner read-only", even it contains public key as well. Nobody else should be able to read it.

5. refer openssl manual to combine some steps above into one step. E.g.,

openssl req -new -out server.csr -out server.csr -newkey rsa:4096 -keyout server.key

openssl req -new -x509 -days 365 -newkey rsa:4096 -keyout ca.key -out ca.crt

following is a screen dump of above steps:

bottom5@ubuntu:~/1$ openssl genrsa -des3 -out ca.key 4096

Generating RSA private key, 4096 bit long modulus

.........................................................................................................................................................................................++

...........++

e is 65537 (0x10001)

Enter pass phrase for ca.key:

Verifying - Enter pass phrase for ca.key:

bottom5@ubuntu: ~/1

bottom5@ubuntu:~/1$ openssl req -new -x509 -days 365 -key ca.key -out ca.crt

Enter pass phrase for ca.key:

You are about to be asked to enter information that will be incorporated

into your certificate request.

What you are about to enter is what is called a Distinguished Name or a DN.

There are quite a few fields but you can leave some blank

For some fields there will be a default value,

If you enter '.', the field will be left blank.

-----

Country Name (2 letter code) [AU]:

State or Province Name (full name) [Some-State]:

Locality Name (eg, city) []:

Organization Name (eg, company) [Internet Widgits Pty Ltd]:

Organizational Unit Name (eg, section) []:ca

Common Name (e.g. server FQDN or YOUR name) []:ca

Email Address []:ca.com

bottom5@ubuntu: ~/1

bottom5@ubuntu:~/1$ openssl genrsa -des3 -out server.key 4096

Generating RSA private key, 4096 bit long modulus

......................................................................................................++

............................................................................++

e is 65537 (0x10001)

Enter pass phrase for server.key:

Verifying - Enter pass phrase for server.key:

bottom5@ubuntu: ~/1

bottom5@ubuntu:~/1$ openssl req -new -key server.key -out server.csr

Enter pass phrase for server.key:

You are about to be asked to enter information that will be incorporated

into your certificate request.

What you are about to enter is what is called a Distinguished Name or a DN.

There are quite a few fields but you can leave some blank

For some fields there will be a default value,

If you enter '.', the field will be left blank.

-----

Country Name (2 letter code) [AU]:

State or Province Name (full name) [Some-State]:

Locality Name (eg, city) []:

Organization Name (eg, company) [Internet Widgits Pty Ltd]:server

Organizational Unit Name (eg, section) []:server

Common Name (e.g. server FQDN or YOUR name) []:server

Email Address []:server.com

Please enter the following 'extra' attributes

to be sent with your certificate request

A challenge password []:123

An optional company name []:

bottom5@ubuntu: ~/1

bottom5@ubuntu:~/1$ openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey

ca.key -set_serial 01 -out server.crt

Signature ok

subject=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/OU=server/CN=server/emailAddress=server.com

Getting CA Private Key

Enter pass phrase for ca.key:

bottom5@ubuntu: ~/1

bottom5@ubuntu:~/1$ openssl rsa -in server.key -out server.key

Enter pass phrase for server.key:

writing RSA key

bottom5@ubuntu: ~/1

bottom5@ubuntu:~/1$ ls -t

total 20

-rw-rw-r-- 1 bottom5 bottom5 3243 Jun 8 19:12 server.key

-rw-rw-r-- 1 bottom5 bottom5 1944 Jun 8 19:12 server.crt

-rw-rw-r-- 1 bottom5 bottom51736 Jun 8 19:11 server.csr

-rw-rw-r-- 1 bottom5 bottom5 2053 Jun 8 19:10 ca.crt

-rw-rw-r-- 1 bottom5 bottom5 3311 Jun 8 19:10 ca.key

bottom5@ubuntu:~/1$ openssl verify -CAfile ca.crt server.crt

server.crt: OK

bottom5@ubuntu:~/1$

Note that "server.key" and "ca.key" can be read by others, this is wrong. It should be "owner read-only".

"chmod 0600 *.key" will fix it.