Generated SSL certificate doesn't work in Personal > Certificates, only if it's also in Trusted Root Certificate Authorities > Certificates

I'm trying to install an SSL certificate automatically with certutil, and I've done this successfully with the following command:

certutil -addstore -user -f "My" "$CERT_FILE_CERT"

Looking at the certificates in certmgr, the installed certificate appears under Personal > Certificates as expected. This doesn't seem to be sufficient for my browsers (Chrome, Edge) to validate the certificate when it is used to serve a page from one of the hostnames mentioned in the SAN list.

In order to successfully validate the certificate and accept that it's legitimate, I also have to install the certificate to Trusted Root Certification Authorities. Is there a way I can change the configuration file I use with OpenSSL so that only the Personal > Certificates entry is required? Or do I always need to install the certificate in two places?

For context, I'm aiming to streamline the process of setting up the local development environment in my company as much as possible. One thing we require is that the local services be served over HTTPS (one service is an identity service, and "Sign in with Google" doesn't work if your redirect URL isn't secure).

I've used OpenSSL with the following configuration to generate a certificate:

[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no

[req_distinguished_name]
C = JP
ST = Shizuoka
L = Hamamatsu
O = COMPANY
OU = Development
CN = localhost

[v3_req]
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
IP.1 = 127.0.0.1
DNS.1 = localhost
DNS.2 = host.docker.internal

And the following commands:

openssl ecparam -genkey -name prime256v1 | openssl ec -aes256 -out $CERT_FILE_KEY -passout "pass:$CERT_PWD"

openssl req -new -x509 -nodes -days 3650 -key $CERT_FILE_KEY -out $CERT_FILE_CERT -passin "pass:$CERT_PWD" -passout "pass:$CERT_PWD" -config cert-input.conf

openssl pkcs12 -export -out $CERT_FILE_PFX -inkey $CERT_FILE_KEY -in $CERT_FILE_CERT -passin "pass:$CERT_PWD" -passout "pass:$CERT_PWD" -name "Local Dev"

This has resulted in the following certificate:

-----BEGIN CERTIFICATE-----
MIICODCCAd6gAwIBAgIUNrzhFtF68r7gVL5isCrZNUoOzS4wCgYIKoZIzj0EAwIw
cDELMAkGA1UEBhMCSlAxETAPBgNVBAgMCFNoaXp1b2thMRIwEAYDVQQHDAlIYW1h
bWF0c3UxEDAOBgNVBAoMB0NPTVBBTlkxFDASBgNVBAsMC0RldmVsb3BtZW50MRIw
EAYDVQQDDAlsb2NhbGhvc3QwHhcNMjEwODI2MDMyMjMyWhcNMzEwODI0MDMyMjMy
WjBwMQswCQYDVQQGEwJKUDERMA8GA1UECAwIU2hpenVva2ExEjAQBgNVBAcMCUhh
bWFtYXRzdTEQMA4GA1UECgwHQ09NUEFOWTEUMBIGA1UECwwLRGV2ZWxvcG1lbnQx
EjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJRO
TwcPcq2ZI8y6vDqiKaxJ1IGcIsVup1xpBdgGOTpKMQ5IZWyIttFEXjBVytSPJXJx
4NXiryNnWdMEPNdu7JujVjBUMAsGA1UdDwQEAwIF4DATBgNVHSUEDDAKBggrBgEF
BQcDATAwBgNVHREEKTAnhwR/AAABgglsb2NhbGhvc3SCFGhvc3QuZG9ja2VyLmlu
dGVybmFsMAoGCCqGSM49BAMCA0gAMEUCIQDC6qzBjPB8Wj/G7a4x8O8ccX3Gqs5O
W2vwk78A/dDaJAIgdsBlg8kc1MNPuHHXEfp1PvOFAR0DWEilUPJDgbQw6eA=
-----END CERTIFICATE-----

Solution 1:

That's working as it should. The Trusted Root Certificate Authorities store is where you place certificates (root ones) which you trust. If they're not in there your relying-party doesn't know that you've chosen to trust them.

The Personal store is where you place subscriber (also known as end-entity) certificates. These are certificates which services use to present to relying-parties. You only need the certificate here if you have a Windows application which is a server/service - e.g. IIS.

As your SAN is for localhost then you will need to ensure that whatever service is running on that machine has access to the certificate and private key. If it's not a Windows native application, or an application which can access the Windows certificate store, then you will need to configure the certificate and private key on that service as per its documentation; not place it in the Personal store. As this works when you add the certificate to the Trusted Root Certificate Authorities store, this suggests you may have done that already.

You would probably be better to create a CA key and certificate (basicConstraints = CA) and have that in the Trusted Root Certificate Authorities store. Then use that to sign a end-entity certificate for use by your application.