I created a self-signed Root CA certificate, then created an IA certificate signed with Root CA, and finally created a server certificate signed with IA certificate.
These are the commands that I use:
@ECHO OFF
ECHO Create Root CA Private key...
openssl ecparam -name secp384r1 -genkey -out "SSL-Bundle/Root-CA.key"
ECHO Create Root CA Private key successfully!
ECHO Create Root CA CSR...
openssl req -new -sha256 -key "SSL-Bundle/Root-CA.key" -config "SSL-Bundle/config_root_ca.cnf" -out "SSL-Bundle/Root-CA.csr"
ECHO Create Root CA CSR successfully!
ECHO Create Root CA...
REM Install Root CA into Trusted Root Certification Authorities store and Third-Party Root Certification Authorities store
certutil -f -addstore AuthRoot "SSL-Bundle/Root-CA.crt"
ECHO Create Root CA successfully!
ECHO Create Intermediate CA Private key...
openssl ecparam -name secp384r1 -genkey -out "SSL-Bundle/Intermediate-CA.key"
ECHO Create Intermediate CA Private key successfully!
ECHO Create Intermediate CA CSR...
openssl req -new -sha256 -key "SSL-Bundle/Intermediate-CA.key" -config "SSL-Bundle/config_intermediate_ca.cnf" -out "SSL-Bundle/Intermediate-CA.csr"
ECHO Create Intermediate CA CSR successfully!
ECHO Sign Intermediate CA CSR with Root CA...
openssl ca -config "SSL-Bundle/config_intermediate_ca.cnf" -in "SSL-Bundle/Intermediate-CA.csr" -out "SSL-Bundle/Intermediate-CA.crt"
REM Install Intermediate CA into Intermediate Certification Authorities store
certutil -f -addstore CA "SSL-Bundle/Intermediate-CA.crt"
ECHO Sign Intermediate CA CSR with Root CA successfully!
ECHO Create Server Private key...
openssl ecparam -name prime256v1 -genkey -out "SSL-Bundle/Certificates/server.key"
ECHO Create Server Private key successfully!
ECHO Create Server CSR...
openssl req -new -sha256 -key "SSL-Bundle/Certificates/server.key" -config "SSL-Bundle/config_server_ssl.cnf" -out "SSL-Bundle/Certificates/server.csr"
ECHO Create Server CSR successfully!
ECHO Sign Server CSR with Intermediate CA...
openssl ca -config "SSL-Bundle/config_server_ssl.cnf" -in "SSL-Bundle/Certificates/server.csr" -out "SSL-Bundle/Certificates/server.crt"
ECHO Sign Server CSR with Intermediate CA successfully!
These are the configuration files that I use:
config_root_ca.cnf:
[ req ]
prompt=no
string_mask=default
distinguished_name=req_distinguished_name
default_bits=2048
[ req_distinguished_name ]
countryName=VN
stateOrProvinceName=
localityName=
organizationName=Localhost Inc.
organizationalUnitName=Localhost Co., Ltd.
commonName=Root CA ECC
emailAddress=
we use 'ca' as the default section because we're usign the ca command
[ ca ]
default_ca=root_ca
[ root_ca ]
a text file containing the next serial number to use in hex. Mandatory.
This file must be present and contain a valid serial number.
serial=SSL-Bundle/Root-CA.srl
the text database file to use. Mandatory. This file must be present though
initially it will be empty.
database=SSL-Bundle/Root-CA.txt
specifies the directory where new certificates will be placed. Mandatory.
new_certs_dir=SSL-Bundle/Certificates
the file containing the CA certificate. Mandatory
certificate=SSL-Bundle/Root-CA.crt
the file contaning the CA private key. Mandatory
private_key=SSL-Bundle/Root-CA.key
the message digest algorithm. Remember to not use MD5
default_md=sha384
for how many days will the signed certificate be valid
default_days=397
the start date to certify a certificate for
default_startdate=19700101000000Z
either this option or default_days
default_enddate=21060207062815Z
a section with a set of variables corresponding to DN fields
policy=root_ca_policy
Extensions added while singing with the openssl ca command
x509_extensions=x509_ext
MOST IMPORTANT PART OF THIS CONFIG
copy_extensions=copy
[ root_ca_policy ]
if the value is "match" then the field value must match the same field in the
CA certificate. If the value is "supplied" then it must be present.
Optional means it may be present. Any fields not mentioned are silently
deleted.
countryName=match
stateOrProvinceName=optional
localityName=optional
organizationName=supplied
organizationalUnitName=supplied
commonName=supplied
emailAddress=optional
[ x509_ext ]
basicConstraints=critical,CA:TRUE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
keyUsage=critical,digitalSignature,cRLSign,keyCertSign
config_intermediate_ca.cnf:
[ req ]
prompt=no
string_mask=default
distinguished_name=req_distinguished_name
default_bits=2048
[ req_distinguished_name ]
countryName=VN
stateOrProvinceName=
localityName=
organizationName=Localhost Inc.
organizationalUnitName=Localhost Pte. Ltd.
commonName=Intermediate CA ECC
emailAddress=
we use 'ca' as the default section because we're usign the ca command
[ ca ]
default_ca=intermediate_ca
[ intermediate_ca ]
a text file containing the next serial number to use in hex. Mandatory.
This file must be present and contain a valid serial number.
serial=SSL-Bundle/Root-CA.srl
the text database file to use. Mandatory. This file must be present though
initially it will be empty.
database=SSL-Bundle/Root-CA.txt
specifies the directory where new certificates will be placed. Mandatory.
new_certs_dir=SSL-Bundle/Certificates
the file containing the CA certificate. Mandatory
certificate=SSL-Bundle/Root-CA.crt
the file contaning the CA private key. Mandatory
private_key=SSL-Bundle/Root-CA.key
the message digest algorithm. Remember to not use MD5
default_md=sha384
for how many days will the signed certificate be valid
default_days=397
the start date to certify a certificate for
default_startdate=19700101000000Z
either this option or default_days
default_enddate=20791231235959Z
a section with a set of variables corresponding to DN fields
policy=intermediate_ca_policy
Extensions added while singing with the openssl ca command
x509_extensions=x509_ext
MOST IMPORTANT PART OF THIS CONFIG
copy_extensions=copy
[ intermediate_ca_policy ]
if the value is "match" then the field value must match the same field in the
CA certificate. If the value is "supplied" then it must be present.
Optional means it may be present. Any fields not mentioned are silently
deleted.
countryName=match
stateOrProvinceName=optional
localityName=optional
organizationName=supplied
organizationalUnitName=supplied
commonName=supplied
emailAddress=optional
[ x509_ext ]
basicConstraints=critical,CA:TRUE,pathlen:0
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
keyUsage=critical,digitalSignature,keyCertSign,cRLSign
extendedKeyUsage=serverAuth,clientAuth
config_server_ssl.cnf:
[ req ]
prompt=no
string_mask=default
distinguished_name=req_distinguished_name
default_bits=2048
[ req_distinguished_name ]
countryName=VN
stateOrProvinceName=
localityName=
organizationName=Localhost Inc.
organizationalUnitName=Localhost LLC
commonName=Localhost ECC
emailAddress=
we use 'ca' as the default section because we're usign the ca command
[ ca ]
default_ca=server_ca
[ server_ca ]
a text file containing the next serial number to use in hex. Mandatory.
This file must be present and contain a valid serial number.
serial=SSL-Bundle/Intermediate-CA.srl
the text database file to use. Mandatory. This file must be present though
initially it will be empty.
database=SSL-Bundle/Intermediate-CA.txt
specifies the directory where new certificates will be placed. Mandatory.
new_certs_dir=SSL-Bundle/Certificates
the file containing the CA certificate. Mandatory
certificate=SSL-Bundle/Intermediate-CA.crt
the file contaning the CA private key. Mandatory
private_key=SSL-Bundle/Intermediate-CA.key
the message digest algorithm. Remember to not use MD5
default_md=sha256
for how many days will the signed certificate be valid
default_days=397
the start date to certify a certificate for
default_startdate=19700101000000Z
either this option or default_days
default_enddate=20380319031407Z
a section with a set of variables corresponding to DN fields
policy=ia_ca_policy
Extensions added while singing with the openssl ca command
x509_extensions=x509_ext
MOST IMPORTANT PART OF THIS CONFIG
copy_extensions=copy
[ ia_ca_policy ]
if the value is "match" then the field value must match the same field in the
CA certificate. If the value is "supplied" then it must be present.
Optional means it may be present. Any fields not mentioned are silently
deleted.
countryName=match
stateOrProvinceName=optional
localityName=optional
organizationName=supplied
organizationalUnitName=supplied
commonName=supplied
emailAddress=optional
[ x509_ext ]
basicConstraints=critical,CA:false
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
keyUsage=critical,digitalSignature
extendedKeyUsage=serverAuth
subjectAltName=@alternate_names
[ alternate_names ]
DNS.1=localhost
DNS.2=*.localhost
IP.1=127.0.0.1
The Root CA certificate has been installed into the Trusted Root Certification Authorities store and Third-Party Root Certification Authorities store. The IA certificate has been installed into the Intermediate Certification Authorities store. I checked through certmgr.msc, all was installed correctly, and when I opened those certificates, the Root CA, IA, and server all returned the correct certificate path and the certificate status was This certificate is OK.
When I open: Chrome Settings > Privacy and security > Security > Manage Certificates. At the Intermediate Certification Authorities tab there is a self-signed IA certificate, and at the Trusted Root Certification Authorities tab there is also a self-signed Root CA above.
Then I configured Apache:
Listen 443
<VirtualHost _default_:80>
DocumentRoot "/WWW"
<Directory "/WWW">
Options -Indexes +FollowSymLinks +ExecCGI
AllowOverride All
Order allow,deny
Allow from all
Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:443>
DocumentRoot "/WWW"
ServerName localhost
ServerAlias www.localhost
<Directory "/WWW">
Options FollowSymLinks ExecCGI
AllowOverride All
Order allow,deny
Allow from all
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile /Apache/conf/ssl/server.crt
SSLCertificateKeyFile /Apache/conf/ssl/server.key
SSLCertificateChainFile /Apache/conf/ssl/Root-CA.crt
</VirtualHost>
But when I try to access https://localhost on Google Chrome, I still get the error NET::ERR_CERT_AUTHORITY_INVALID and at the address bar gave a red warning Not Secure.
I want to know what am I missing? How to make Google Chrome also trust my self-signed certificate (i.e. there will be no more warnings and the address bar will also change to green Secure)?
UPDATE: Below is the output of openssl x509 -noout -text -in <cert.crt> as requested by @garethTheRed.
openssl x509 -noout -text -in Root-CA.crt:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: ecdsa-with-SHA384
Issuer: C = VN, O = Localhost Inc., OU = "Localhost Co., Ltd.", CN = Localhost ECC P384 Root CA
Validity
Not Before: Jan 1 00:00:00 1970 GMT
Not After : Feb 7 06:28:15 2106 GMT
Subject: C = VN, O = Localhost Inc., OU = "Localhost Co., Ltd.", CN = Localhost ECC P384 Root CA
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
04:9f:a9:ed:b2:46:dd:2d:78:42:5f:cc:41:8b:6a:
26:82:f9:8d:5f:52:a5:ea:7c:1f:e7:73:a2:43:0c:
d2:69:a9:ba:b1:06:53:f8:2f:6f:94:95:59:09:4b:
6e:fd:51:72:54:7e:11:7a:88:cf:4b:49:99:d9:f5:
92:c1:19:b0:10:6f:c7:f5:e0:36:c9:5d:32:01:18:
d1:52:26:fb:57:d8:3c:4e:15:ba:b0:7c:80:00:bb:
0e:d9:bc:26:1b:1b:d5
ASN1 OID: secp384r1
NIST CURVE: P-384
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
74:49:7D:71:7E:A0:31:28:6E:EC:46:BA:D4:99:72:41:78:B5:11:6A
X509v3 Authority Key Identifier:
keyid:74:49:7D:71:7E:A0:31:28:6E:EC:46:BA:D4:99:72:41:78:B5:11:6A
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
Signature Algorithm: ecdsa-with-SHA384
30:66:02:31:00:fa:2d:4a:35:4b:21:83:14:dc:13:8b:5a:e5:
a8:da:d2:1a:86:fc:59:47:07:da:c4:2a:fd:ff:07:cc:96:4e:
f2:d2:0d:da:80:d8:e7:e7:c6:cb:0c:b6:87:c6:f5:20:95:02:
31:00:e2:32:d8:09:af:ef:a8:1e:03:4c:d2:e9:6f:92:bf:82:
c7:52:8e:43:33:da:38:c9:a4:42:37:b9:cc:db:48:d9:ae:3e:
55:43:4d:df:d5:35:f3:b0:0e:42:87:9f:b0:1a
openssl x509 -noout -text -in Intermediate-CA.crt:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: ecdsa-with-SHA384
Issuer: C = VN, O = Localhost Inc., OU = "Localhost Co., Ltd.", CN = Localhost ECC P384 Root CA
Validity
Not Before: Jan 1 00:00:00 1970 GMT
Not After : Dec 31 23:59:59 2079 GMT
Subject: C = VN, O = Localhost Inc., OU = Localhost Pte. Ltd., CN = Localhost ECC P384 Intermediate CA
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (384 bit)
pub:
04:07:c4:b3:2c:2f:33:cb:76:d2:19:f1:21:04:02:
5d:92:14:06:dc:87:c6:3d:af:c8:27:18:8d:9e:10:
e5:11:43:47:28:24:e5:be:b6:cf:12:8e:80:59:c8:
d7:82:c9:88:9b:bb:06:fa:0b:46:44:a2:39:6c:23:
5c:b0:a8:80:91:d9:6d:9a:4c:ae:e8:9d:69:73:b6:
60:81:e0:e9:69:e2:8a:44:41:dc:a3:f3:e5:ae:7e:
02:00:f4:41:74:22:7c
ASN1 OID: secp384r1
NIST CURVE: P-384
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Subject Key Identifier:
F3:38:E4:E6:B9:1E:EC:12:E5:80:96:00:94:A9:76:06:D1:C9:B4:89
X509v3 Authority Key Identifier:
keyid:74:49:7D:71:7E:A0:31:28:6E:EC:46:BA:D4:99:72:41:78:B5:11:6A
DirName:/C=VN/O=Localhost Inc./OU=Localhost Co., Ltd./CN=Localhost ECC P384 Root CA
serial:00
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: ecdsa-with-SHA384
30:65:02:30:68:3f:e8:2f:45:3f:fb:f9:65:62:fc:f5:3a:d0:
b3:3e:21:9a:76:c3:b3:cc:8c:2c:77:69:48:ed:2e:85:0d:5f:
35:8d:9b:ca:de:bb:32:d5:8b:c3:39:53:2a:c8:61:82:02:31:
00:f2:cb:ed:ba:ba:68:19:73:f0:53:7c:10:63:3f:b8:20:4f:
f2:19:b9:86:7b:bd:c9:b3:7d:2e:c5:34:62:e2:1f:4f:b0:24:
9c:b3:ae:fd:f5:54:3a:08:e3:dd:f9:50:fe
openssl x509 -noout -text -in Server.crt:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = VN, O = Localhost Inc., OU = Localhost Pte. Ltd., CN = Localhost ECC P384 Intermediate CA
Validity
Not Before: Jan 1 00:00:00 1970 GMT
Not After : Mar 19 03:14:07 2038 GMT
Subject: C = VN, O = Localhost Inc., OU = Localhost LLC, CN = Localhost ECC P256
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:b6:8f:91:37:73:9d:a7:31:ee:6e:d6:74:e2:15:
d4:af:78:cc:d5:21:1f:0a:52:be:66:af:36:01:c4:
d3:b1:7e:c7:99:e9:cd:0d:41:9b:e6:28:cf:26:8c:
f9:44:2f:c9:ee:6d:e5:f5:d3:00:82:7b:19:95:3e:
89:5b:ef:a2:ac
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
32:19:D3:18:FA:46:0C:A6:2B:1F:CF:A1:04:8D:99:6F:C5:03:54:AD
X509v3 Authority Key Identifier:
keyid:F3:38:E4:E6:B9:1E:EC:12:E5:80:96:00:94:A9:76:06:D1:C9:B4:89
X509v3 Key Usage: critical
Digital Signature
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Subject Alternative Name:
DNS:localhost, DNS:*.localhost, IP Address:127.0.0.1
Signature Algorithm: ecdsa-with-SHA256
30:64:02:30:4d:43:cc:3d:4e:7a:8d:78:ec:bb:01:64:60:93:
26:96:7c:07:55:9c:66:ae:4f:13:c9:1f:d3:01:ff:ae:10:da:
a1:ca:5b:d7:9d:f5:8f:81:89:0d:56:32:7b:53:58:ad:02:30:
78:7e:06:56:f6:fc:93:67:ba:53:f4:cb:22:1d:15:86:62:63:
9a:2e:fa:14:bd:8b:2c:01:a3:6b:8c:20:94:61:a9:e0:cc:a4:
8f:c9:a8:a5:88:59:72:b1:35:5d:e2:e6

