2

Where SAN means: Subject Alternative Name.

I feel I have a basic misunderstanding in which certificate the SAN stuff shall go: ca or server or both or what?

It might be 3 Years or more in the past, where chrome / chromium browsers required the occurrence of the SAN extension in certificates. While fierfox still accepts hostname / domain name as a usual common name (CN), chromium doesn't.

Recent chromium versions are verifying the CN by the SAN extension and moreover don't take care of the CN.

So far so good. I'd like to refer to a google's statement: scroll to

Error: "Subject Alternative Name Missing" or NET::ERR_CERT_COMMON_NAME_INVALID or "Your connection is not private"

In here they state

... using a valid, trusted server certificate

Am I right to assume that it's not the Root CA certificate which I can import to chromium via the Settings > Manage certificates > Authorities Tab?

Such Root CA certificate which I am importing to firefox (where it is recognized correctly) is generated like this:

openssl req -new -x509 -days 365 -extensions v3_ca -keyout mosq_ca.key -out mosq_ca.crt -subj "/C=CA/ST=BC/L=your-city/O=ca.your-domain.com/OU=ca/CN=your-hostname/emailAddress=your@email.com"

Within the Root CA certificate I generate a server certificate (used on mosquitto) like this:

Private key

openssl genrsa -out mosq_serv.key 2048

Server certificate signing request

openssl req -new -key mosq_serv.key -out mosq_serv.csr -subj "/C=your-country/ST=your-state/L=your-city/O=server.your-domain.com/OU=server/CN=your-hostname/emailAddress=your@email.com"

Self CA signed server certificate

openssl x509 -req -in mosq_serv.csr -CA mosq_ca.crt -CAkey mosq_ca.key -CAcreateserial -out mosq_serv.crt -days 365

  • private key
  • Root CA certificate
  • Self CA signed server certificate

Those three are provided to mosquitto config and it works for most browsers, when importing the Root CA certificate as an Authority, except for chrome / chromium. And I guess it is due to the statement mentioned above.

I was able to put the SAN into the Root CA certificate via openssl's -config option. That didn't help against the NET::ERR_CERT_COMMON_NAME_INVALID.

The config san.cfg is this:

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

[req_distinguished_name]
C = <myC>
ST = <myST>
L = <myL>
O = <myO>
OU = <myOU>
CN = <myCN>
emailAddress = <myemailAddress>

[v3_req]
basicConstraints = CA:true
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
#basicConstraints = critical,CA:TRUE
#subjectKeyIdentifier = hash
#authorityKeyIdentifier = keyid:always,issuer:always
#keyUsage = keyEncipherment, dataEncipherment
#extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.0 = <myCN>

Then issue Root CA certificate

openssl req -new -x509 -days 365 -extensions 'v3_req' -keyout mq_srv_ca.key -out mq_srv_ca.crt -config san.cfg

I was not able to gain a SAN for the Self CA signed server certificate since I don't know how to apply with -config. And I am not sure whether it needs to be done. When reading the statement from google exactly, one might think it should be done.

If so, how to do this? And how to provide the result to chrome / chromium?

Btw. I am using Paho's js utility for browser testing

woodz
  • 131
  • 1
  • 6
  • 5
    I'm not really sure what you are asking. But I get the basic idea that you assume that a CA must have a SAN too. This is not the case, not even with Chrome. This can be easily verified by visiting some common site and checking the certificate chain: __you'll find SAN in the server certificate (leaf) but typically not in the intermediate or root CA certificates__. – Steffen Ullrich Jun 19 '20 at 05:23
  • That helps to do a step forward, and yes, I mixed multiple questions into my post that made it hard to read. You answered one of them, many thanks – woodz Jun 19 '20 at 09:29
  • (1) For example one site you might possibly be able to access is stackexchange, where you can see the leaf cert has SAN with over a dozen names, but the CAs (LetsEncrypt and either IdenTrust or ISRG) do not have SAN. (2) for using openssl to create leaf cert with SAN see https://security.stackexchange.com/questions/190905/ https://security.stackexchange.com/questions/150078/ https://security.stackexchange.com/questions/74345/ – dave_thompson_085 Jun 20 '20 at 06:49
  • "Recent chromium versions" - this has been a requirement in Chrome for at least 2 years. – symcbean Jul 14 '20 at 22:47

2 Answers2

0

I managed things to fit together; it's true, the CA certificate does not need to have a SAN in, as the server certificate which gets signed by the CA is the candidate in which to include the SAN.

  • I am answering all my own questions from my original post, which hopefully helps to unravel my somewhat mixed and twisted question-style:
    1. In which certificate does the SAN go?
      Into the srv.crt
    2. Am I right to assume it's not the Root CA certificate which I can import into Chromium via Settings > Manage certificates > Authorities Tab?
      No, it's indeed the Root CA certificate; SAN will be provided by srv.crt during server requests, with the CA only guaranteeing trust to the endpoint being requested.
    3. When reading the statement from google exactly, one might think it should be done. If so, how to do this?
      The process is shown below
    4. How to provide the result to Chromium?
      The same way as before (in the original question)

This solves my issue (<...>: anonymous placeholder):

  1. Generate Root CA certificate and key (no SAN included):
    openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt -subj "/C=<C>/ST=<ST>/L=<L>/O=<O>OU=<OU>/CN=$(hostname)/emailAddress=<emailAddress>"
    
  2. Generate server-side private key:
    openssl genrsa -out srv.key 2048
    
  3. Generate signing request for server certificate (SAN included, openssl.cnf unchanged):
    openssl req -new -sha256 -key srv.key -subj "/C=<C>/ST=<ST>/L=<L>/O=<O>/OU=<OU>/CN=$(hostname)/emailAddress=<emailAddress>" -reqexts SAN -extensions SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:$(hostname)")) -out srv.csr
    
  4. Generate signed server certificate (SAN included, openssl.cnf unchanged):
    openssl x509 -req -days 365 -CA ca.crt -CAkey ca.key -CAcreateserial -extensions SAN -extfile <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:$(hostname)")) -in srv.csr -out srv.crt
    


By placing ca.crt, srv.crt, and srv.key on the server, and importing ca.crt into Chromium, TLS requests now work like a charm on any desktop browser, but not in browsers on Android, which is my next question.

JW0914
  • 115
  • 5
woodz
  • 131
  • 1
  • 6
  • `openssl x509 -req` completely ignores any extensions in CSR, so the work done in your step 3 to put SAN in CSR is wasted. OTOH `openssl ca` _can_ use CSR extensions, though not by default, so if you used that _and_ configured `copy_extensions`, putting SAN _only_ in CSR (step 3) and _not_ the signing operation (a different step 4) is sufficient. Multiple existing Qs have these correct. – dave_thompson_085 Jul 14 '20 at 00:52
  • @dave_thompson_085: would you mind to put me to an appropriate resource? Coud you provide some cmd-line samples? Telling me of waste but not providing useful stuff.. What would you think it sounds to me? – woodz Jul 14 '20 at 09:59
  • @ woodz Your reverted edit is using the incorrect markdown... please see the formatting bar or the help section on how to properly use markdown, as headings are for headings, not numbered lists. Using the incorrect markdown means that someone has to take the time out to edit it, and with such a pervasive amount of incorrect markdown, it's a time-consuming edit, so please use the correct markdown. – JW0914 Jul 14 '20 at 12:18
  • @woodz Just an FYI, if you used the `v3_req` profile in your question, as is, to generate your server cert, it's malformed and missing the requisite KUs and EKUs, and even if the `keyUsage` is uncommented, `dataEncipherment` is not a valid KU for a server cert _(it should be `digitalSignature, keyEncipherment, keyAgreement` [[reference](https://superuser.com/a/1248085/529800)])_. It would also not be a secure cert to use due to being issued with `basicConstraints = CA:TRUE`, making the server cert a CA _(a massive security risk - it should be `CA:FALSE`)_. – JW0914 Jul 14 '20 at 13:21
0

I have a basic misunderstanding within which certificate the SAN goes: CA, server, or both?

  • The SAN profile can be used within any certificate and is the correct way to issue certs, as a cert's CN should not contain the HN/FQDN/IP for security reasons (covered in the RFC).
    • CA and ICA SAN and V3 profiles:
      Certain OSes require the main CA to use a SAN (e.g. Sophos UTM must have the local hostname set in DNS.1 and the localhost IP set in IP.1)
      [ alt_ca ]
      DNS.1                     = Router.1
      IP.1                      = 127.0.0.1
      
      [ v3_ca ]
      basicConstraints          = critical, CA:TRUE
      subjectKeyIdentifier      = hash
      authorityKeyIdentifier    = keyid:always, issuer:always
      subjectAltName            = @alt_ca
      keyUsage                  = critical, cRLSign, digitalSignature, keyCertSign
      
      [ alt_ica ]
      DNS.1                     = Router.2
      IP.1                      = 127.0.0.1
      
      [ v3_ica ]
      basicConstraints          = critical, CA:TRUE, pathlen:0
      subjectKeyIdentifier      = hash
      authorityKeyIdentifier    = keyid:always, issuer:always
      subjectAltName            = @alt_ica
      keyUsage                  = critical, cRLSign, digitalSignature, keyCertSign
      
    • Server SAN and V3 profiles:
      All webservers capable of being accessed through SSH must have the localhost IP [127.0.0.1] specified in their SAN, else accessing the webserver over SSH from the machine they're running on will result in browser trust errors
      [ alt_server ]
      IP.1                      = 192.168.2.13
      IP.2                      = 192.168.2.130
      IP.3                      = 127.0.0.1
      DNS.1                     = server.lan
      DNS.2                     = your-fqdn.com
      
      [ v3_server ]
      basicConstraints          = critical, CA:FALSE
      subjectKeyIdentifier      = hash
      authorityKeyIdentifier    = keyid:always, issuer:always
      keyUsage                  = critical, nonRepudiation, digitalSignature, keyEncipherment, keyAgreement
      extendedKeyUsage          = critical, serverAuth
      subjectAltName            = @alt_server
      
    • VPN Client and Code Signing SAN and V3 profiles:
      [ alt_vpn_user ]
      email.1                   = user@email.com
      DNS.1                     = VPN-Client1-Device1
      DNS.2                     = VPN-Client1-Device2
      
      [ v3_vpn_user ]
      basicConstraints          = critical,CA:FALSE
      subjectKeyIdentifier      = hash
      authorityKeyIdentifier    = keyid:always, issuer:always
      keyUsage                  = critical, nonRepudiation, digitalSignature, keyEncipherment
      extendedKeyUsage          = critical, clientAuth
      subjectAltName            = @alt_vpn_user
      
      [ alt_codesign ]
      email.1                   = user@email.com
      
      [ v3_codesign ]
      basicConstraints          = critical, CA:FALSE
      subjectKeyIdentifier      = hash
      authorityKeyIdentifier    = keyid:always, issuer:always
      keyUsage                  = critical, nonRepudiation, digitalSignature
      extendedKeyUsage          = critical, codeSigning, msCodeInd, msCodeCom, msCTLSign, timeStamping
      subjectAltName            = @alt_codesign
      

...Chromium browsers required the occurrence of the SAN in certificates, verifying the CN by the SAN, whereas Firefox still accepts HN/DN for the CN.

Error: "Subject Alternative Name Missing" or NET::ERR_CERT_COMMON_NAME_INVALID or "Your connection is not private"
  • Two decades ago, the RFC noted the CN should not contain the HN/FQDN/IP for security reasons; instead, these should be contained within the SAN.

    While the RFC didn't mandate this, it did provide an example of how this could be exploited; until recently, browsers and VPNs chose to ignore this (Chromium ~3yrs ago; OpenVPN ~2yrs ago), even then, it's discombobulated across browsers.

...Am I right to assume that it's not the Root CA certificate which I can import to chromium via the Settings > Manage certificates > Authorities Tab?

  • This depends on the OS:
    • On Windows, the user must have Admin privileges to import a root CA into the Trusted Root Certification Authorities store due to the security implications of this store.
    • Whereas Android is different than all other OSes, with it being impossible unless the device is rooted due the /system partition (or it's A/B variants) being read-only, making it impossible to import any cert into the system store without root permissions.

      For a rooted device:
      If /system/etc/security/cacerts.bks exists on the device, refer to CAcert wiki, then continue
      • Method 1:
        1. Add certificate to Android Keychain:
          • SettingsSecurityInstall from Storage
            SettingsSecurityEncryptionInstall
        2. Move certificate from userland to system trusted:
          1. Android <5.0:
            Move new file from /data/misc/keychain/cacertsadded/ to /system/etc/security/cacerts/
          2. Android >5.0:
            Move new file from /data/misc/user/0/cacerts-added/ to /system/etc/security/cacerts/
      • Method 2:
        1. Save certificate with .pem extension:
          # Garnish subject of certificate (similar to 0b112a89):
            openssl x509 -inform PEM -subject_hash -in 0b112a89.0
          
          # Save certificate as text:
            openssl x509 -inform PEM -text -in 0b112a89.0 > 0b112a89.0.txt
          
        2. Swap PEM section and text: -----BEGIN CERTIFICATE----- must be at top of file
        3. Rename file, replacing with subject [0b112a89.0] from 2.1
        4. Copy file to /system/etc/security/cacerts/ and set permissions:
           chmod 644 0b112a89.0
          
        5. Certificate should be listed under:
          SettingsSecurityTrusted CredentialsSystem
          SettingsSecurityEncryptionTrusted CredentialsSystem
          1. If it's still under User, disable/re-enable certificate in Settings, which creates a file in /data/misc/keychain/cacertsadded/
          2. Move that file to /system/etc/security/cacerts/ and delete original file

...I was not able to gain a SAN for the self-signed CA server certificate since I don't know how to apply it with -config and am unsure whether it needs to be done.

  • Rather than address this and the last half of the question directly, making this a much longer answer, please use the custom openssl.cnf I built, which has all commands and info required beginning on Line 430, along with this answer for further reference.
    1. Generate CA:
      # Request/Generate:
        openssl req -x509 -new -sha512 -days 3650 -newkey rsa:4096 -keyout 'CA.key.pem' -out 'CA.crt.pem' -config '.\openssl.cnf' -extensions v3_ca
      
      # Generate CRL:
        openssl ca -gencrl -keyfile 'CA.key.pem' -cert 'CA.crt.pem' -out 'CA.crl.pem' -config '.\openssl.cnf'
      
      # Convert CRL to DER:
        openssl crl -inform PEM -in 'CA.crl.pem' -outform DER -out 'CA.crl'
      
    2. Generate ICA:
      # Same commands as CA, using v3_ica and ICA in lieu of CA for naming, plus:
      
      # Sign ICA with CA:
        openssl x509 -req -sha512 -days 3650 -in 'ICA.csr' -CA 'CA.crt.pem' -CAkey 'CA.key' -CAserial '.\serial' -out 'ICA.crt.pem' -extfile '.\openssl.cnf' -extensions v3_ica
      
      # Create Concatenated CA - Intermediate CA Certificate Chain:
        # Windows:
          Cmd /c Type '.\ICA.crt.pem' '.\CA.crt.pem' > '.\CA-ICA-chain.crt.pem'
      
        # All others:
          cat './ICA.crt.pem' './CA.crt.pem' > './CA-ICA-chain.crt.pem'
      
    3. Generate Server/Client certs:
      # Request:
        openssl req -out 'server.csr' -new -days 3650 -sha512 -newkey rsa:2048 -keyout 'server.key.pem' -config '.\openssl.cnf' -extensions v3_server
      
      # Sign:
        openssl x509 -req -sha512 -days 3650 -in 'server.csr' -CA 'CA-ICA-chain.crt.pem' -CAkey 'ICA.key.pem' -CAserial '.\serial' -out 'server.crt.pem' -extfile '.\openssl.cnf' -extensions v3_server
      
      # Export:
        openssl pkcs12 -export -out 'server.p12' -inkey 'server.key.pem' -in 'server.crt.pem' -certfile 'CA-ICA-chain.crt.pem'
      
      • Server certs need to be created with -nodes appended to the command if encrypt_key = yes is set in the openssl.cnf (all keys, except a server's, should be encrypted)

Something you may want to look into for Android is using Let's Encrypt, which received their root CA registration on most OSes in the last couple of years, with the regeneration of a signed cert upon expiration able to be executed via a simple script.

JW0914
  • 115
  • 5
  • this answer does not provide additional useful stuff to that before – woodz Jul 14 '20 at 12:02
  • @woodz ??? I'm unsure how you've come to that conclusion... please re-read and review the actual commands. SANs are used, V3 and SAN profiles for 5 different certificates were provided, efficient commands that create and sign certs in two steps are shown, a prebuilt `openssl.cnf` was linked to that contains all the information and commands required to do what you want to do, etc. I laid out the correct way to do what you're trying to do, it's up to you whether you wish to use the information provided to you. – JW0914 Jul 14 '20 at 12:07
  • I am already OK, I've solved the issue by answering – woodz Jul 14 '20 at 12:08