Skip to content

Instantly share code, notes, and snippets.

@evandrocoan
Created January 5, 2022 13:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save evandrocoan/14531fa0d795fc8ed89b877eeec51665 to your computer and use it in GitHub Desktop.
Save evandrocoan/14531fa0d795fc8ed89b877eeec51665 to your computer and use it in GitHub Desktop.
Generated an ssl private/public SSL certificate
#!/bin/bash
set -x
set -eu -o pipefail
function printerror
{
set +x
printf '\n'
printf 'Usage\n'
printf ' %s "key name" "key password" "servidor ip" "server name (i.e., $HOSTNAME)"\n' "$0"
printf '\n'
exit 0
}
# Parameters
# $1 = certificate name
# $2 = certificate name CA
# $3 = password
if [[ -z "${1+x}" ]];
then
printerror;
fi
certnamefile="${1}"
certnamecafile="${certnamefile}"
if [[ -z "${2+x}" ]];
then
printerror;
fi
password="${2}"
if [[ -z "${3+x}" ]];
then
printerror;
fi
serverip="${3}"
if [[ -z "${4+x}" ]];
then
printerror;
fi
servername="${4}"
# Generate a new key
openssl genrsa -out "$certnamefile".key -aes128 -passout pass:"$password" 2048
# Generate a certificate requisition
openssl req -new -key "$certnamefile".key -out "$certnamefile".csr -config <(printf '[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
[req_distinguished_name]
C = BR
ST = Some State
L = SomeCity
O = CityOrg
OU = CityState
CN = localname
emailAddress = localname@localname.com')
# Generate a signed certificate through the certificate requisition
openssl x509 -req -days 99999 -in "$certnamefile".csr -signkey "$certnamecafile".key -out "$certnamefile".crt \
-extfile <(printf "basicConstraints = CA:TRUE
subjectAltName = @alt_names
[alt_names]
IP.1 = 127.0.0.1
IP.2 = 127.0.0.2
IP.3 = 127.0.0.3
IP.4 = 192.168.0.1
IP.5 = 192.168.0.2
IP.6 = 192.168.0.3
IP.7 = ${serverip}
IP.8 = 192.168.0.9
IP.9 = 169.254.217.244
DNS.1 = ${serverip}
DNS.2 = 10.254.254.240
DNS.3 = $servername
DNS.4 = localhost
DNS.5 = hostname
DNS.6 = localhost.localdomain
DNS.7 = dev.local
DNS.8 = 192.168.0.9
DNS.9 = 169.254.217.244
")
# See the generated certificate
openssl x509 -text -noout -in $certnamefile.crt
# Check is signature
openssl verify -CAfile $certnamecafile.crt $certnamefile.crt
# Creates a certifying unit
cat $certnamefile.crt $certnamefile.key > $certnamefile.pem
exit 0
# https://stackoverflow.com/questions/50788043/how-to-trust-self-signed-localhost-certificates-on-linux-chrome-and-firefox
'
# TLDR
1. Create the file `generate.sh`
#!/usr/bin/env bash
find . \( -name "$1.*" -o -name "*.srl" \) -type f -delete
cp /usr/lib/ssl/openssl.cnf $1.cnf
python <(
cat << "END"
import sys
from ConfigParser import ConfigParser
from StringIO import StringIO
domain = sys.argv[1]
config = ConfigParser()
config.optionxform = lambda option: option
name = "{}.cnf".format(domain)
with open(name, "rb") as stream:
config.readfp(StringIO("[top]\n" + stream.read()))
config.set(" v3_ca ", "subjectKeyIdentifier", "hash")
config.set(" v3_ca ", "authorityKeyIdentifier", "keyid:always,issuer")
config.set(" v3_ca ", "basicConstraints", "critical, CA:TRUE, pathlen:3")
config.set(" v3_ca ", "keyUsage", "critical, cRLSign, keyCertSign")
config.set(" v3_ca ", "nsCertType", "sslCA, emailCA")
config.set(" v3_req ", "basicConstraints", "CA:FALSE")
config.set(" v3_req ", "keyUsage", "nonRepudiation, digitalSignature, keyEncipherment")
config.set(" v3_req ", "subjectAltName", "@alt_names")
config.remove_option(" v3_req ", "extendedKeyUsage")
config.add_section(" alt_names ")
config.set(" alt_names ", "DNS.1", domain)
config.set(" alt_names ", "DNS.2", "*.{}".format(domain))
config.set(" req ", "req_extensions", "v3_req")
with open(name, "wb") as stream:
config.write(stream)
END
) $1
tail -n +2 $1.cnf > $1.cnf.tmp && mv $1.cnf.tmp $1.cnf
echo "$1\n" | openssl genrsa -aes256 -out $1.ca.key 2048
chmod 400 $1.ca.key
openssl req -new -x509 -subj "/CN=$1" -extensions v3_ca -days 3650 -key $1.ca.key -sha256 -out $1.ca.crt -config $1.cnf
openssl genrsa -out $1.key 2048
openssl req -subj "/CN=$1" -extensions v3_req -sha256 -new -key $1.key -out $1.csr
openssl x509 -req -extensions v3_req -days 3650 -sha256 -in $1.csr -CA $1.ca.crt -CAkey $1.ca.key -CAcreateserial -out $1.crt -extfile $1.cnf
openssl x509 -in $1.crt -text -noout
2. Call `./generate.sh example.com`
> Requires Python 2
----------
> All credits go to [this excellent article][3] by Fabian Lee.
# Create a trusted CA and SAN certificate using OpenSSL
1. Customize openssl.cnf
2. Create CA certificate
3. Create Server certificate with SAN signed by CA
## Prerequisite
As a prerequisite, ensure the SSL packages are installed:
$ sudo apt install libssl1.0.0 -y
## Customized openssl.cnf
The first step is to grab the `openssl.cnf` template available on your system. On Ubuntu this can be found at `/usr/lib/ssl/openssl.cnf`. You may find this in `/System/Library/OpenSSL/` on MacOS, and `/etc/pki/tls` on Redhat variants.
export prefix="mydomain"
cp /usr/lib/ssl/openssl.cnf $prefix.cnf
`$prefix.cnf` needs be modified with the specific information about the cert we are going to generate.
Under the `[ v3_ca ]` section, add the following values. For the CA, this signifies we are creating a CA that will be used for key signing.
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical, CA:TRUE, pathlen:3
keyUsage = critical, cRLSign, keyCertSign
nsCertType = sslCA, emailCA
Then under the `[ v3_req ]` section, set the following along with all the valid alternative names for this certificate.
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
#extendedKeyUsage=serverAuth
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = mydomain.com
DNS.2 = *.dydomain.com
Also uncomment the following line under the `[ req ]` section so that certificate requests are created with v3 extensions.
req_extensions = v3_req
When we generate each type of key, we specify which extension section we want to use, which is why we can share `$prefix.cnf` for creating both the CA as well as the SAN certificate.
## Create CA Certificate
Now we will start using OpenSSL to create the necessary keys and certificates. First generate the private/public RSA key pair:
openssl genrsa -aes256 -out ca.key.pem 2048
chmod 400 ca.key.pem
This encodes the key file using an passphrase based on AES256.
Then we need to create the self-signed root CA certificate.
openssl req -new -x509 -subj "/CN=myca" -extensions v3_ca -days 3650 -key ca.key.pem -sha256 -out ca.pem -config $prefix.cnf
You can verify this root CA certificate using:
openssl x509 -in ca.pem -text -noout
This will show the root CA certificate, and the `Issuer` and `Subject` will be the same since this is self-signed. This is flagged as `CA:TRUE` meaning it will be recognized as a root CA certificate; meaning browsers and OS will allow it to be imported into their trusted root certificate store.
Issuer: CN=myca
...
Subject: CN=myca
...
X509v3 Basic Constraints:
critical CA:TRUE, pathlen:3
X509v3 Key Usage:
critical Certificate Sign, CRL Sign
Netscape Cert Type:
SSL CA, S/MIME CA
## Create Server certificate signed by CA
With the root CA now created, we switch over to the server certificate. First generate the private/public RSA key pair:
openssl genrsa -out $prefix.key.pem 2048
We didn’t put a passphrase on this key simply because the CA is more valuable target and we can always regenerate the server cert, but feel free to take this extra precaution.
Then create the server cert signing request:
openssl req -subj "/CN=$prefix" -extensions v3_req -sha256 -new -key $prefix.key.pem -out $prefix.csr
Then generate the server certificate using the: server signing request, the CA signing key, and CA cert.
openssl x509 -req -extensions v3_req -days 3650 -sha256 -in $prefix.csr -CA ca.pem -CAkey ca.key.pem -CAcreateserial -out $prefix.crt -extfile $prefix.cnf
The `$prefix.key.pem` is the server private key and `$prefix.crt` is the server certificate. Verify the certificate:
openssl x509 -in $prefix.crt -text -noout
This will show the certificate, and the `Issuer` will be the CA name, while the Subject is the prefix. This is not set to be a CA, and the `Subject Alternative Name` field contains the URLs that will be considered valid by browsers.
Issuer:
CN=myca
...
Subject:
CN=mydomain
...
X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment
X509v3 Subject Alternative Name:
DNS:mydomain.com, DNS:*.mydomain.com
## Browser Evaluation
When you first point Chrome or Firefox at the site with your SAN cert with CA signing, it will throw the same type of exceptions as a self-signed SAN cert. This is because the root CA cert is not known as a trusted source for signed certificates.
### Chrome
#### **Linux**
On Linux, Chrome manages its own certificate store and again you should import `ca.pem` into the `Authorities`. This should now make the security icon turn green.
[![enter image description here][1]][1]
#### **Windows**
In Chrome settings (`chrome://settings`), search for `certificates` and click on `Manage Certificates`. On Windows this will open the Windows certificate manager and you should import the `ca.pem` file at the `Trusted Root Certification Authorities` tab. This is equivalent to adding it through `mmc.exe`, in the `local user` trusted root store (not the computer level).
#### **Firefox**
In Firefox Options `about:preferences`, search for `certificates` and click `View Certificates`. Go to the `Authorities` tab and import `ca.pem`. Check the box to have it trust websites, and now the lock icon should turn green when you visit the page.
[![enter image description here][2]][2]
[1]: https://i.stack.imgur.com/geaeq.png
[2]: https://i.stack.imgur.com/JtaTa.png
[3]: https://fabianlee.org/2018/02/17/ubuntu-creating-a-trusted-ca-and-san-certificate-using-openssl-on-ubuntu/
'
# https://stackoverflow.com/questions/52373778/neterr-cert-common-name-invalid-using-nettys-websocket
'
ERR_CERT_COMMON_NAME_INVALID, this happens when the domain name inside the certificate file is differend from the domain name the client is trying to connect to, can you post both domain names?
'
# https://serverfault.com/questions/880804/can-not-get-rid-of-neterr-cert-common-name-invalid-error-in-chrome-with-self
'
[Chrome 58+ no longer matches the Common Name (`CN`) in certs.](https://groups.google.com/a/chromium.org/forum/#!topic/security-dev/IGT2fLJrAeo)
Now it uses Subject Alternative Names (`SAN`) instead.
`SAN` must contain proper `DNS` or `IP` entry.
- When DNS is used, it should be a resolvable FQDN name.
- When an IP address is used, it should be explicitely specified as
such within the `SAN` chain.
That said, this should work :
openssl req \
-newkey rsa:2048 \
-x509 \
-nodes \
-keyout file.key \
-new \
-out file.crt \
-subj /CN=Hostname \
-reqexts SAN \
-extensions SAN \
-config <(cat /etc/ssl/openssl.cnf \
<(printf "[SAN]\nsubjectAltName=DNS:hostname,IP:192.168.0.1")) \
-sha256 \
-days 3650
Specifically, this is due to tools.ietf.org/html/rfc6125#section-5.7.3.1 which states "For TLS authentication with X.509 certificates, an identity from the DNS namespace MUST be checked against each subjectAltName extension of type dNSName present in the certificate. If no such extension is present, then the identity MUST be compared to the (most specific) Common Name in the Subject field of the certificate." So, if any SAN exists then the CN is not checked.
Life saver. For anyone trying this out on Windows, Cygwin comes with a copy of openssl.cnf here: .\cygwin\etc\defaults\etc\pki\tls\ Also, I had to change my CN=hostname and DNS:hostname lines to be localhost instead of hostname
'
# https://stackoverflow.com/questions/66558788/how-to-create-a-self-signed-ssl-certificate-for-ip-address-that-pass-chrome-requ
'
1. Prepare config files for creating certificates non-interactivelly (without prompts)
`CA.cnf` →
```
[ req ]
prompt = no
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
C = US
ST = Localzone
L = localhost
O = Certificate Authority Local Center
OU = Develop
CN = develop.localhost.localdomain
emailAddress = root@localhost.localdomain
```
`localhost.cnf` →
```
[req]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
countryName = US
stateOrProvinceName = Localzone
localityName = Localhost
organizationName = Self-signed certificate
commonName = localhost.localdomain
[req_ext]
subjectAltName = @alt_names
[v3_req]
subjectAltName = @alt_names
[alt_names]
IP.1 = 127.0.0.1
IP.2 = 127.0.0.2
IP.3 = 127.0.0.3
IP.4 = 192.168.0.1
IP.5 = 192.168.0.2
IP.6 = 192.168.0.3
DNS.1 = localhost
DNS.2 = localhost.localdomain
DNS.3 = dev.local
```
2. Generate a CA private key and Certificate (valid for 5 years)
```
openssl req -nodes -new -x509 -keyout CA_key.pem -out CA_cert.pem -days 1825 -config CA.cnf
```
3. Generate web server secret key and CSR
```
openssl req -sha256 -nodes -newkey rsa:2048 -keyout localhost_key.pem -out localhost.csr -config localhost.cnf
```
4. Create self-signed certificate ([valid 1 year][1])
```
openssl x509 -req -days 398 -in localhost.csr -CA CA_cert.pem -CAkey CA_key.pem -CAcreateserial -out localhost_cert.pem -extensions req_ext -extfile localhost.cnf
```
5. Profit
Output files will be:
- `CA.cnf` → OpenSSL CA config file. May be deleted after certificate creation process.
- `CA_cert.pem` → [Certificate Authority] certificate. This certificate must be added to the browser local authority storage to make trust all certificates that created with using this CA.
- `CA_cert.srl` → Random serial number. May be deleted after certificate creation process.
- `CA_key.pem` → Must be used when creating new [localhost] certificate. May be deleted after certificate creation process (if you do not plan reuse it and CA_cert.pem).
- `localhost.cnf` → OpenSSL SSL certificate config file. May be deleted after certificate creation process.
- `localhost.csr` → Certificate Signing Request. May be deleted after certificate creation process.
- `localhost_cert.pem` → SSL certificate. Must be installed at WEB server.
- `localhost_key.pem` → Secret key. Must be installed at WEB server.
SSL Certificate alternative names can be checked by
```
openssl x509 -noout -text -in localhost_cert.pem | grep "X509v3 Subject Alternative Name" -A 1
```
[1]: https://www.certisur.com/en/google-chrome-limits-the-validity-of-ssl-certificates-to-one-year/
'
# https://www.ibm.com/docs/en/ztpf/1.1.0.15?topic=gssccr-configuration-file-generating-self-signed-certificates-certificate-requests
'
[req]
days = daystocertify
serial = serialnumber
#The following three values can be anything; they just need to
#match a section name in the file.
distinguished_name = req_distinguished_name
req_extensions = v3_req
x509_extensions = v3_ca
[req_distinguished_name]
countryName = country
stateOrProvinceName = stateorprov
localityName = locality
organizationName = organization
organizationalUnitName = organizationalunit
commonName = commonname
emailAddress = emailaddress
[v3_req]
basicConstraints = CA:trueorfalse
keyUsage = keyusage
[v3_ca]
subjectKeyIdentifier = subjectkeyidentifier
authorityKeyIdentifier = authoritykeyidentifier
basicConstraints = basicconstraints
keyUsage = keyusage
subjectAltName = subjectaltname
issuerAltName = issueraltname
[req]
defines the sections in the certificate, along with the days and serial fields. This field is required, and must be exactly [req]. You can specify the following fields in this section:
days=daystocertify
specifies the number of days to certify a self-signed certificate, where daystocertify is an integer from 1–36500. If alphanumeric characters are specified, the number up to the first non-digit is accepted. (For example, 22FE is accepted as 22.) This field is required for both self-signed certificates and certificate requests, but has significance only for self-signed certificates.
serial=serialnumber
specifies the serial number to use when creating a self-signed certificate, where serialnumber is an integer value from 0–9999 or hexadecimal value from 0x0–0x270F. If alphanumeric characters are specified for the integer value, the number up to the first non-digit is accepted. (For example, 22FE is accepted as 22.) This field is optional. The default value is 0.
distinguished_name=req_distinguished_name
specifies the section that defines the information needed to generate a self-signed certificate or certificate request, where req_distinguished_name is the name of the section. At least one field must be specified in this section. See the following [req_distinguished_name] description for information about the fields that it can contain. This field is required for both self-signed certificates and certificate requests.
req_extensions=v3_req
specifies the section that defines extensions to add to a certificate request, where v3_req is the name of the section. See the following [v3_req] description for information about the fields that the section can contain. This field is optional.
x509_extensions=v3_ca
specifies the section that defines extensions to add to a self-signed certificate, where v3_ca is the name of the section. See the following [v3_ca] description for information about the fields that the section can contain. This field is optional.
[req_distinguished_name]
This is the value you specified on distinguished_name. You can specify more than one value for a field using the following syntax:
0.emailAddress=moe@curlyshouse
1.emailAddress=moe@larryshouse
2.emailAddress=moe@moeshouse
You can specify the following fields in this section:
countryName=country
specifies the two-character country name in ISO 3166 format.
stateOrProvinceName=stateorprov
specifies the state or province name, where stateorprov is 1–128 characters.
localityName=locality
specifies the locality name, where locality is 1–128 characters.
organizationName=organization
specifies the organization name, where organization is 1–64 characters.
organizationalUnitName=organizationalunit
specifies the organizational unit name, where organizationalunit is 1–64 characters.
commonName=commonname
specifies the common name, where commonname is 1–64 characters.
emailAddress=emailaddress
specifies the email address, where emailaddress is 1–64 characters.
[v3_req]
This is the value you specified on req_extensions. This section is optional. You can specify the following fields in this section:
basicConstraints=CA:trueorfalse
indicates whether a certificate is a certificate authority (CA), where trueorfalse is either TRUE or FALSE.
keyUsage=keyusage
specifies permitted key usages, where keyusage is a comma-separated list of any of the following:
digitalSignature
nonRepudiation
keyEncipherment
dataEncipherment
keyAgreement
keyCertSign
cRLSign
encipherOnly
decipherOnly.
[v3_ca]
This is the value you specified on x509_extensions. This section is optional. You can specify the following fields in this section:
subjectKeyIdentifier=subjectkeyidentifier
specifies how to identify the public key being certified. The only value supported for subjectkeyidentifier is hash. This field is required if x509_extensions is specified.
authorityKeyIdentifier=authoritykeyidentifier
specifies how to identify the public key being used to verify the signature on this certificate, and enables keys used by the same CA to be distinguished, where authoritykeyidentifier is one of the following:
keyid
indicates that the subject key identifier is copied from the parent certificate.
keyid:always
indicates that the subject key identifier is copied from the parent certificate and an error is returned if the copy fails.
issuer
indicates that the issuer and serial number is copied from the issuer certificate if the keyid option fails or is not specified.
issuer:always
indicates that the issuer and serial number is always copied from the issuer certificate.
basicConstraints=CA:trueorfalse
see basicConstraints description in the [v3_req] section.
keyUsage=keyusage
see keyUsage description in the [v3_req] section.
subjectAltName=subjectaltname
allows you to specify the following literal values in the configuration file:
email:email
specifies an email address. If copy is specified, all email addresses contained in the certificate are included.
URI:uri
specifies a uniform resource indicator.
DNS:dns
specifies a Domain Name System (DNS).
RID:rid
specifies a registered ID.
IP:IP
specifies an IP address in Internet Protocol version 4 (IPv4) format.
@dirname
specifies a section that contains a list of fields, where dirname is the section name and must be defined later in the configuration file (by placing it between square brackets).
issuerAltName=issueraltname
allows you to specify all literal values from subjectAltName except email:copy, including the following:
issuer:copy
all subject alternative name values from the issuer certificate are included.
#
#Creating a self-signed certificate
#
####################################################################
[req]
days = 180
serial = 1
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
[req_distinguished_name]
countryName = US
stateOrProvinceName = NY
localityName = POK
organizationName = IBM
organizationalUnitName = TPF
commonName = SSL_SERVER
0.emailAddress = moe@curlyshouse.org
1.emailAddress = moe@larryshouse.org
2.emailAddress = moe@moeshouse.org
[ v3_ca ]
# The extentions to add to a self-signed cert
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:TRUE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign
subjectAltName = DNS:moe.ibm.com, DNS:larry.ibm.com, email:curly@moe.org
issuerAltName = issuer:copy
#
#Creating a certificate request
#
####################################################################
[req]
days = 180
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
countryName = US
stateOrProvinceName = NY
localityName = POK
organizationName = IBM
organizationalUnitName = TPF
commonName = SSL_SERVER
0.emailAddress = moe@curlyshouse.org
1.emailAddress = moe@larryshouse.org
2.emailAddress = moe@moeshouse.org
[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign
'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment