1

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

1 Answers1

0

Okay, I've identified the problem and found a solution. The command line and configuration file I used generated the certificates in question without any problem. The error was determined to be due to a feature called Chrome Root Store and Certificate Verifier. This feature was added since Chrome 105:

We expect the transition to the Chrome Root Store and Chrome Certificate Verifier to be seamless for most users.

As the transition occurs, a small population of users may notice that a small number of websites that successfully loaded in earlier versions of Chrome now present a “Your connection is not private” warning. When a website’s certificate does not validate to a certificate included in the Chrome Root Store or a user’s local settings, users will see detailed error language that includes “ERR_CERT_AUTHORITY_INVALID.”

Although also according to this article, a certificate added to the Trusted Root Certification Authorities store will also be trusted by Chrome Certificate Verifier, but since it is not in the Chrome Root Store it will give the same warning as the certificate not trusted.

I tried on older versions (Chrome 49 - Chrome Root Store and Certificate Verifier feature is not available, uses platform root store and verifier) these certificates work fine:Test self-signed certificate on Chrome 49

And according to the article Testing the Chrome Root Store and Certificate Verifier, the only workaround is to disable Chrome Root Store and Certificate Verifier. Here is how to do it (on Chrome >= 105):

  1. Disable the Chrome Root Store & Certificate Verifier by starting Chrome with the following flag: --disable-features=ChromeRootStoreUsed

  2. Disable the Chrome Root Store and Certificate Verifier by going to chrome://flags, searching for the flag Chrome Root Store (chrome://flags/#chrome-root-store-enabled), and set it to Disabled. This will then require Chrome to restart.

And here is the result (I tested on Chrome 109): Test self-signed certificate on Chrome 109

Note: The Root Store and Certificate Verifier feature is available on all browsers using Chromium, including Microsoft Edge. This feature is called Microsoft Root Store on Microsoft Edge.