305

Is it possible to provide a subjectAltName-Extension to the openssl req module directly on the command line?

I know it's possible via a openssl.cnf file, but that's not really elegant for batch-creation of CSRs.

4
  • I just developed a web based tool that will generate this command automatically based on form input and display the output. kernelmanic.com/… Commented Oct 27, 2015 at 17:29
  • It isn't clear from what you have included how the output of your tool applies to the Question. Also, can you explain how your tool works (in case the link goes dead)?
    – schroeder
    Commented Oct 27, 2015 at 18:18
  • Peter(editor): 'OpenSSL' is the name of the project and its output as a whole, but 'openssl' all-lower is the name of the command-line 'utility' program relevant to this Q. Commented Dec 29, 2018 at 12:28
  • As of 2019 this answer should be the accepted one: security.stackexchange.com/a/183973/143034
    – wedi
    Commented Jun 19, 2020 at 17:14

18 Answers 18

234

As of OpenSSL 1.1.1, providing subjectAltName directly on command line becomes much easier, with the introduction of the -addext flag to openssl req (via this commit).

The commit adds an example to the openssl req man page:

Example of giving the most common attributes (subject and extensions)
on the command line:

 openssl req -new -subj "/C=GB/CN=foo" \
                  -addext "subjectAltName = DNS:foo.co.uk" \
                  -addext "certificatePolicies = 1.2.3.4" \
                  -newkey rsa:2048 -keyout key.pem -out req.pem

The commit message itself is also helpful to understand what's happening:

 Add 'openssl req' option to specify extension values on command line

The idea is to be able to add extension value lines directly on the
command line instead of through the config file, for example:

    openssl req -new -extension 'subjectAltName = DNS:dom.ain, DNS:oth.er' \
                     -extension 'certificatePolicies = 1.2.3.4'

This has been merged into the master branch of the openssl command on Github, and as of April 18 2018 can be installed via a git pull + compile (or via Homebrew if on OS X: brew install --devel [email protected]).

Note that if you have set the config attribute "req_extensions" at section "[req]" in openssl.cfg, it will ignore the command-line parameter

5
  • 21
    The -addext is convenient for creating signing requests, but the SAN still has to be added when the csr is signed, correct? Openssl doesn't have the equivalent flag on the x509 command, necessitating the use of a file.
    – end-user
    Commented Feb 21, 2019 at 18:52
  • 3
    @end-user: if you issue the cert (which is not signing the CSR) with openssl x509 -req -CA/CAkey yes. If you isse with openssl ca it can be configured with copy_extensions to put the extensions from the CSR in the cert. Commented Oct 11, 2019 at 0:53
  • 4
    (necroed elsewhere) if you specify -addext and also have req_extensions in config, it doesn't ignore either; instead it creates TWO attribute items with OID pkcs9.14, which clearly doesn't make sense, though AFAICS rfc2986 doesn't prohibit it (as rfc5280 does for extensions in certs). openssl req -text only displays the first, and since attributes is a SET and the tbs is DER-encoded, which set of extensions is first is determined in an arcane way that might as well be random. Other things using the CSR, like openssl ca with copy_extensions, are also likely to be confused. Commented Sep 18, 2020 at 1:25
  • To make sure the extensions added to the CSR using -addext are really added to the signed certificate you have to enable copy_extensions = copy in /etc/ssl/openssl.cnf
    – hfmanson
    Commented Apr 25, 2023 at 7:28
  • 4
    adding openssl x509 ... -copy_extensions copy made this solution working for me
    – reto
    Commented Sep 27, 2023 at 11:29
159

Based on link from DarkLighting, here's the command I came up with using nested subshells.

openssl req -new -sha256 \
    -key domain.key \
    -subj "/C=US/ST=CA/O=Acme, Inc./CN=example.com" \
    -reqexts SAN \
    -config <(cat /etc/ssl/openssl.cnf \
        <(printf "\n[SAN]\nsubjectAltName=DNS:example.com,DNS:www.example.com")) \
    -out domain.csr

All one line:

openssl req -new -sha256 -key domain.key -subj "/C=US/ST=CA/O=Acme, Inc./CN=example.com" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:example.com,DNS:www.example.com")) -out domain.csr

Example use:

user@hostname:~$ openssl req -new -sha256 -key domain.key -subj "/C=US/ST=CA/O=Acme, Inc./CN=example.com" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:example.com,DNS:www.example.com\n")) -out domain.csr
user@hostname:~$ openssl req -in domain.csr -text -noout
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=US, ST=CA, O=Acme, Inc., CN=example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:a8:05:50:86:49:98:c8:05:01:e9:50:18:7f:2f:
                    b4:89:09:29:d1:c1:58:d8:14:bb:58:1d:25:50:11:
                    bb:43:d8:28:03:a5:de:59:49:bb:d2:f7:d3:79:5c:
                    c6:99:2c:98:ff:99:23:8c:df:96:7c:ea:4b:62:2a:
                    a4:c2:84:f5:5d:62:7f:7d:c4:7c:e2:c3:db:e6:58:
                    03:c2:26:9d:02:da:bb:84:d9:11:82:fe:38:12:9b:
                    c7:b6:ff:b2:40:30:38:b1:44:d8:47:1d:43:4a:29:
                    58:6b:49:ec:33:d7:dc:a7:1b:90:05:3a:f5:e6:16:
                    98:08:5d:2d:7e:b4:ea:a2:a4:b1:84:89:f7:f1:c4:
                    67:a6:a1:06:70:dd:4e:6b:0c:f8:b5:9b:bc:3f:06:
                    ee:90:d6:86:29:52:d3:af:f6:d4:2f:c6:cf:4b:5a:
                    b8:cd:01:74:6d:5c:25:a8:02:1c:7c:e8:66:3d:46:
                    07:b1:9d:ef:cc:eb:90:b6:bf:7b:33:e0:5f:b2:9b:
                    e8:b4:12:67:2f:8d:0d:9b:54:9d:95:6e:09:83:cb:
                    f3:5b:1f:31:8e:3b:ca:4e:08:e0:40:c0:60:40:72:
                    dd:0d:3e:99:ec:7c:ac:c4:3c:ba:85:9d:d9:d9:6b:
                    02:2e:bf:a8:a3:02:1d:eb:c8:58:e3:04:b3:a5:f1:
                    67:37
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Subject Alternative Name: 
                DNS:example.com, DNS:www.example.com
    Signature Algorithm: sha256WithRSAEncryption
         a2:1d:1a:e8:56:43:e7:e5:c7:c1:04:c1:6a:eb:d5:70:92:78:
         06:c1:96:fa:60:e2:5f:3c:95:ee:75:ed:70:52:c1:f0:a7:54:
         d2:9f:4a:2f:52:0f:d4:27:d8:13:73:1f:21:be:34:3f:0a:9c:
         f1:2a:5c:98:d4:28:b8:9c:78:44:e8:ea:70:f3:11:6b:26:c3:
         d6:29:b3:25:a0:81:ea:a2:55:31:f2:63:c8:60:6d:68:e3:ab:
         24:c9:46:33:92:8f:f2:a7:72:43:c6:aa:bd:8d:e9:6f:64:64:
         9e:fe:30:48:3f:06:2e:58:7c:b5:ef:b1:4d:c3:84:cc:02:a5:
         58:c3:3f:d8:ed:98:c7:54:b9:5e:50:44:5e:be:99:c2:e4:03:
         81:4b:1f:47:9a:b0:4d:74:7b:10:29:2f:84:fd:d1:70:88:2e:
         ea:f3:42:b7:06:94:4a:06:f6:92:10:4c:ce:de:65:89:2d:0a:
         f1:0f:79:90:02:a4:b9:6d:b8:39:db:de:6e:34:61:4f:21:36:
         a0:b5:73:2b:2b:c6:7e:2f:f2:e5:1e:51:9f:85:c8:17:9c:1a:
         b6:59:b0:41:a7:06:c8:5b:f4:88:92:c9:34:71:9d:73:f0:2e:
         31:ae:ed:ab:35:0e:b4:8a:9a:72:7c:6f:7a:3e:5d:66:49:26:
         26:99:e1:69
7
  • 3
    If your config is missing a [ SAN ] section, the -reqexts SAN section will result in the error message 'Error Loading request extension section SAN'. Incase anybody else runs into that. Commented Sep 4, 2016 at 6:37
  • 15
    I also had to set -extensions SAN to get this to work. Full 1-liner: openssl req -new -sha256 -key domain.key -subj "/C=US/ST=CA/O=Acme, Inc./CN=example.com" -reqexts SAN -extensions SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:example.com,DNS:www.example.com")) -out domain.csr Commented Apr 7, 2017 at 5:35
  • 1
    For a self-signed cert I needed x509_extensions = SAN in config file, for CSR -reqexts seems to work... Commented Aug 1, 2017 at 11:18
  • 2
    @GertvandenBerg For self-signed (meaning openssl req -x509) you can specify on the command line -extensions SAN and it works as well.
    – kubanczyk
    Commented Aug 26, 2017 at 20:23
  • 3
    This oneliner only works in BASH (bash) not Bourne shell (sh), probably because of the sub-shell syntax.
    – Devy
    Commented Nov 13, 2018 at 18:37
68

This is my solution to finally generate a working self signed cert, based on the answers above(The accepted answer don't work for me):

openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 365 -key ca.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=Acme Root CA" -out ca.crt

openssl req -newkey rsa:2048 -nodes -keyout server.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=*.example.com" -out server.csr
openssl x509 -req -extfile <(printf "subjectAltName=DNS:example.com,DNS:www.example.com") -days 365 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt

openssl x509 -in server.crt -text -noout:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            ef:ca:cb:c7:3e:5c:25:85
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=CN, ST=GD, L=SZ, O=Acme, Inc., CN=Acme Root CA
        Validity
            Not Before: May 15 14:42:17 2017 GMT
            Not After : May 15 14:42:17 2018 GMT
        Subject: C=CN, ST=GD, L=SZ, O=Acme, Inc., CN=*.example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:f0:19:32:51:9c:13:ec:dc:d4:52:30:d9:39:4a:
                    f5:9b:53:60:48:10:2d:c1:c0:48:ac:75:a3:2a:d2:
                    6c:62:f1:ed:39:46:7e:e7:e7:03:34:7a:c2:53:b7:
                    42:5a:f2:47:ff:34:68:b1:c9:28:3c:1c:eb:57:af:
                    90:87:53:85:3c:0f:6c:85:62:a1:02:94:b6:5f:3e:
                    e2:d1:bc:48:20:81:46:fe:25:b4:06:cd:b8:04:c4:
                    f5:81:f6:29:55:66:98:95:2f:db:75:39:82:7f:32:
                    5b:18:d9:9d:69:d0:f4:6b:0b:a2:92:83:b2:02:1b:
                    6c:d9:1e:f9:c4:f4:72:a6:76:e7:03:14:d6:29:2b:
                    be:e7:96:3e:42:3a:12:16:8b:51:11:22:7d:c1:d9:
                    47:ab:cd:93:36:27:d3:ad:af:85:0b:c4:d1:75:6e:
                    c1:a8:ed:f8:0f:4a:c8:79:21:4c:02:7f:27:70:00:
                    60:ed:68:8f:97:e0:0e:63:86:9f:12:07:78:aa:bf:
                    b1:bb:d1:30:ff:e6:7e:5c:cd:48:3b:31:fd:ab:54:
                    b4:af:dd:95:49:a6:17:0b:23:98:5f:3d:98:f2:eb:
                    8c:e4:aa:6e:44:2e:2d:5e:d5:91:a3:3a:61:18:3b:
                    56:29:47:86:1f:1d:d7:7c:6b:29:e7:ae:28:ec:3c:
                    e3:b1
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:example.com, DNS:www.example.com
    Signature Algorithm: sha1WithRSAEncryption
        56:d2:5b:d0:6a:d9:1d:0b:d4:2d:b3:99:cf:5f:92:e6:9f:4d:
        ea:b7:22:57:0b:85:e1:f7:4b:b1:13:c1:45:f7:7c:06:34:bd:
        0c:4b:e8:45:01:84:58:8a:7a:0d:7b:08:90:a0:91:7c:f1:f7:
        ef:de:3b:94:be:44:4b:71:c5:40:6f:3c:35:3e:61:79:b1:46:
        d9:81:31:bf:11:15:6a:b2:53:b9:a3:d7:81:cd:2d:f5:3e:20:
        dc:06:1c:a0:74:16:9f:d4:53:5d:f2:3a:23:1c:43:2d:ce:8b:
        68:d3:35:f3:36:8a:05:13:34:a7:42:75:6e:df:a2:b5:95:77:
        71:99:ae:be:4a:6c:ae:14:b4:d1:e4:f7:b4:39:b0:30:04:57:
        8a:d8:21:c5:1c:50:f3:86:38:ec:eb:0c:a6:f6:94:f3:f4:af:
        ec:1b:d1:79:ad:16:45:bc:c9:10:2a:a8:2d:b8:cf:7d:8a:aa:
        b4:b5:74:e0:d4:53:82:b5:71:b8:bb:2f:d2:12:51:87:ab:f1:
        b6:dd:1c:24:b1:8b:36:05:83:29:ca:58:ba:6b:f0:83:cc:27:
        86:43:00:da:73:a0:d5:36:31:bb:e7:e5:1b:2f:c0:42:55:7b:
        b4:2e:57:4f:88:b4:cd:0d:d0:bf:a8:87:76:a1:1b:bc:e4:fc:
        31:ba:ee:04

Repro step for "The accepted answer don't work for me" (On OSX 10.12.4, with system openssl):

bash-3.2$ openssl genrsa -out domain.key 2048
Generating RSA private key, 2048 bit long modulus
.........................................................................................+++
....................................+++
e is 65537 (0x10001)
bash-3.2$ openssl req -new -sha256 -key domain.key -subj "/C=US/ST=CA/O=Acme, Inc./CN=example.com" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:example.com,DNS:www.example.com")) -out domain.csr
bash-3.2$ openssl req -in domain.csr -text -noout
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=US, ST=CA, O=Acme, Inc., CN=example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:cd:a5:97:b2:1a:83:c6:1d:0e:78:1a:6f:ca:4c:
                    e6:e3:64:94:41:b8:fb:f3:4a:4c:56:8c:33:36:c1:
                    5d:10:25:f5:86:f5:14:c6:17:22:53:34:7b:16:52:
                    ea:f2:ac:bf:0d:09:7d:55:c8:16:ce:0e:f9:98:20:
                    aa:11:4e:bb:4d:75:b1:ed:1b:ca:37:82:f1:15:71:
                    56:ad:c0:be:40:b4:ef:f2:e6:a5:a2:3b:e3:a8:0c:
                    8b:38:3d:d5:41:1a:e8:92:f6:78:52:9f:35:c2:98:
                    a6:58:87:64:e6:d3:7e:a0:00:8c:d0:16:13:80:e9:
                    ee:81:aa:40:c7:1d:9d:fc:52:9a:50:7d:50:e6:ca:
                    20:38:89:12:7d:99:a0:68:ae:45:64:03:e0:00:3c:
                    30:b7:94:87:ab:de:51:90:73:6b:bc:48:c4:e8:47:
                    2d:0e:5a:d0:fb:b4:1b:cb:76:7b:05:70:1a:a8:03:
                    bc:35:38:70:b5:ca:07:43:d3:9d:66:8c:32:32:74:
                    7e:6f:61:e8:de:80:de:d9:fd:fc:27:d8:bb:fa:8c:
                    f9:94:42:c4:b8:e0:bb:24:8b:1f:71:5b:18:99:ca:
                    ac:42:3b:ed:d7:4d:5f:dc:79:8c:6c:fe:d1:df:44:
                    05:5f:1a:a7:bd:e8:1c:85:0c:70:fb:4e:29:62:a0:
                    e9:71
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Subject Alternative Name:
                DNS:example.com, DNS:www.example.com
    Signature Algorithm: sha256WithRSAEncryption
        47:f3:82:ae:78:f2:19:76:05:e3:97:30:00:16:c5:9c:89:94:
        ef:b0:51:b0:cf:4a:93:81:7d:ee:94:25:9a:0a:9e:1f:7f:e0:
        d8:72:55:75:2d:ac:c3:f9:3a:74:b6:1f:1b:c3:f1:68:d4:66:
        72:89:ed:53:7b:09:da:35:eb:40:63:e6:6a:0f:9a:4f:6e:25:
        9f:63:df:bb:d6:00:77:c2:e7:d6:96:0c:50:58:01:c9:d1:ff:
        df:de:fb:19:fb:72:38:48:25:5d:b7:56:fb:eb:d7:41:f5:f6:
        d7:f7:4b:c7:07:4f:59:b4:b8:c3:d8:bf:c9:2c:07:5a:c3:0a:
        51:f8:02:4f:dc:de:2d:88:49:b7:6d:de:67:04:d0:78:6e:0f:
        96:d8:06:e4:73:4f:fb:ce:29:0f:1e:3a:1a:6e:3c:a5:f3:f1:
        68:3d:22:85:34:fa:f0:ad:f6:75:61:02:81:f1:c4:e3:69:2b:
        80:3d:05:39:c6:9d:72:66:2a:50:93:6c:79:5d:d0:33:42:cf:
        a6:68:6a:16:d7:dc:61:b4:c3:4e:01:ac:68:7c:77:29:d4:fe:
        0d:9d:34:0a:3e:73:02:27:12:a4:08:9c:b9:2e:3e:c8:3f:1d:
        91:33:3b:71:8f:24:6b:66:f5:c3:8a:d7:7b:fe:2d:7f:b4:6d:
        96:cf:52:74
bash-3.2$ openssl x509 -req -in domain.csr -signkey domain.key -out domain.crt
Signature ok
subject=/C=US/ST=CA/O=Acme, Inc./CN=example.com
Getting Private key
bash-3.2$ openssl x509 -in domain.crt -text -noout
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            de:c5:cf:28:1f:33:6c:53
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=US, ST=CA, O=Acme, Inc., CN=example.com
        Validity
            Not Before: May 15 15:30:07 2017 GMT
            Not After : Jun 14 15:30:07 2017 GMT
        Subject: C=US, ST=CA, O=Acme, Inc., CN=example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:cd:a5:97:b2:1a:83:c6:1d:0e:78:1a:6f:ca:4c:
                    e6:e3:64:94:41:b8:fb:f3:4a:4c:56:8c:33:36:c1:
                    5d:10:25:f5:86:f5:14:c6:17:22:53:34:7b:16:52:
                    ea:f2:ac:bf:0d:09:7d:55:c8:16:ce:0e:f9:98:20:
                    aa:11:4e:bb:4d:75:b1:ed:1b:ca:37:82:f1:15:71:
                    56:ad:c0:be:40:b4:ef:f2:e6:a5:a2:3b:e3:a8:0c:
                    8b:38:3d:d5:41:1a:e8:92:f6:78:52:9f:35:c2:98:
                    a6:58:87:64:e6:d3:7e:a0:00:8c:d0:16:13:80:e9:
                    ee:81:aa:40:c7:1d:9d:fc:52:9a:50:7d:50:e6:ca:
                    20:38:89:12:7d:99:a0:68:ae:45:64:03:e0:00:3c:
                    30:b7:94:87:ab:de:51:90:73:6b:bc:48:c4:e8:47:
                    2d:0e:5a:d0:fb:b4:1b:cb:76:7b:05:70:1a:a8:03:
                    bc:35:38:70:b5:ca:07:43:d3:9d:66:8c:32:32:74:
                    7e:6f:61:e8:de:80:de:d9:fd:fc:27:d8:bb:fa:8c:
                    f9:94:42:c4:b8:e0:bb:24:8b:1f:71:5b:18:99:ca:
                    ac:42:3b:ed:d7:4d:5f:dc:79:8c:6c:fe:d1:df:44:
                    05:5f:1a:a7:bd:e8:1c:85:0c:70:fb:4e:29:62:a0:
                    e9:71
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha1WithRSAEncryption
        02:71:7f:a5:8e:aa:7d:4b:0a:9d:54:8c:25:cb:b3:66:a3:22:
        c5:61:73:0c:c4:da:3b:ce:e8:4b:ec:ee:45:83:ca:db:e0:25:
        9b:a6:a3:c0:c9:7c:d9:76:a2:8c:38:38:b1:77:c7:84:33:03:
        b7:9a:cb:ff:bf:83:bc:7b:d8:4c:7e:c4:b3:8f:c5:23:22:75:
        67:d3:d6:5e:0e:bd:ef:0b:0f:6a:8d:f0:d3:20:8f:5a:cf:37:
        94:b7:8a:d9:b3:0e:99:31:4f:77:6f:89:33:c5:93:99:2e:8b:
        61:ad:84:17:af:b5:8e:1e:f0:4a:af:b1:90:c3:09:3a:d6:16:
        4b:1b:c4:6b:2e:22:7e:b1:7d:9b:3c:a9:3b:06:20:e2:37:14:
        8b:0d:da:c6:4b:e3:6e:83:9c:df:20:67:2e:d0:33:68:05:17:
        01:d5:5a:6f:51:b3:50:d7:73:10:73:c8:be:3b:de:e6:bd:28:
        60:6f:19:75:0c:05:16:37:4d:50:df:f4:bb:41:f0:65:ba:6f:
        7f:5c:56:27:ae:0e:18:0a:df:7e:d2:7b:93:db:40:d2:bb:e0:
        dc:b8:57:c7:08:07:37:e4:db:d4:09:b6:13:d7:22:e2:ef:6d:
        60:fa:3e:7c:f4:1f:0b:bf:26:f4:08:d0:39:cf:51:dd:bf:b1:
        0e:ee:46:d1
bash-3.2$ openssl version
OpenSSL 0.9.8zh 14 Jan 2016
12
  • 3
    Why is it your solution? Can you talk us through it?
    – schroeder
    Commented May 15, 2017 at 15:09
  • 3
    How is this different from the accepted answer?
    – schroeder
    Commented May 15, 2017 at 15:10
  • 1
    Ok, but why does it work for you? What part replaces the accepted answer and makes it work? Right now, it's just a wall of code.
    – schroeder
    Commented May 15, 2017 at 15:25
  • 6
    The question was about creating a CSR (presumably for submission to a real CA) and the accepted answer does that. Your answer creates a self-signed cert with SAN but not a CSR with SAN, so it doesn't answer the question here although it does answer security.stackexchange.com/questions/150078/… Commented May 16, 2017 at 5:27
  • 4
    The main difference in this answer compared to the accepted one (which only deals with how to generate a CSR with subjectAltName) is that in this answer two certificates are generated. A Root CA certificate and a domain certificate. The Root CA acts as the issuer of the domain certificate.
    – marekful
    Commented Dec 3, 2018 at 15:53
51

My solution was to pass subjectAltName via an environment variable.

First have this added to openssl.conf:

[ san_env ]
subjectAltName=${ENV::SAN}

Then set the SAN environment variable when invoking openssl:

SAN="DNS:value1,DNS:value2" openssl req -extensions san_env -subj "/CN=value1" ...

Note: the -extensions san_env parameter needs to be present when signing the CSR as well as when generating it. Therefore, for CA-signed CSRs add -extensions san_env to the openssl ca command as well.

4
  • 1
    I get this error message Error Loading extension section san_env Commented Dec 22, 2016 at 14:05
  • 1
    That's probably because the SAN environment variable was not set or was empty.
    – rustyx
    Commented Dec 22, 2016 at 15:21
  • I don't think this works on macOS. I tried it with the export and with the variable inlined like Anton suggests. I end up with 4696151660:error:0EFFF068:configuration file routines:CRYPTO_internal:variable has no value:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.260.1/libressl-2.6/crypto/conf/conf_def.c:563:line 122
    – bmauter
    Commented May 15, 2020 at 19:06
  • Creating a new config section and passing -extensions to the command line didn't work for me. I just replaced subjectAltName=email:copy with subjectAltName=${ENV::SAN} in the existing sections and it worked. So -extensions was useless for me
    – Bemipefe
    Commented Oct 7, 2022 at 12:23
30

As of 2023, with OpenSSL ≥ 1.1.1, the following command demonstrates how to generate a self-signed certificate with SAN for example.com and example.net:

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
  -keyout example.key -out example.crt -subj '/CN=example.com' \
  -addext 'subjectAltName=DNS:example.com,DNS:example.net'

Here we are using the -addext option.

If you are stuck to OpenSSL ≤ 1.1.0, e.g. on Debian ≤ 9 or CentOS ≤ 7, you can apply instead a tiny hack via -extensions and -config. The following command is portable in the sense that we don't have to mess around with (or even know about) the location of the openssl.cnf file:

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
  -keyout example.key -out example.crt -subj '/CN=example.com' \
  -extensions san \
  -config <(echo '[req]'; echo 'distinguished_name=req';
            echo '[san]'; echo 'subjectAltName=DNS:example.com,DNS:example.net')

The trick here is to include a minimal [req] section that is good enough for OpenSSL to get along without its main openssl.cnf file.

Either way, don't forget to verify the contents of the generated certificate:

openssl x509 -noout -text -in example.crt

See also: https://stackoverflow.com/a/41366949/19163 and https://unix.stackexchange.com/a/333325/20407

3
  • 2
    Well done, thanks for your multiple useful answers re: OpenSSL. This is really the only updated answer on this page in particular. Commented May 24, 2021 at 8:46
  • What is -addext? - my openssl (v1.1) doesn't know this option and it's not listed on the man page...
    – Marc
    Commented Sep 22, 2021 at 18:35
  • 1
    @Marc Please have a look at the OpenSSL manual of OpenSSL version 1.1.1, which clearly explains the -addext option: openssl.org/docs/man1.1.1/man1/openssl-req.html
    – vog
    Commented Sep 23, 2021 at 21:32
13

So I had a heck of a time getting this working right, and putting at all in Ansible. As Ansible's command module doesn't allow file-redirects (<(...)), I had to use a small .cnf file as a template, but it's all working now. Here's what I did to make it work:

The san.cnf template (generated for each CSR/CRT pair):

[req]
distinguished_name = req_distinguished_name
req_extensions     = v3_req
x509_extensions    = v3_req

[req_distinguished_name]
commonName       = {{ common_name }}
emailAddress     = {{ ssl_certs_email }}
organizationName = {{ ssl_certs_organization }}
localityName     = {{ ssl_certs_locality }}
countryName      = {{ ssl_certs_country }}

[v3_req]
# The extentions to add to a self-signed cert
subjectKeyIdentifier = hash
basicConstraints     = critical,CA:false
subjectAltName       = DNS:{{ common_name }}
keyUsage             = critical,digitalSignature,keyEncipherment

Some Variables

These Ansible variables used in the following commands, but you can substitute as needed in your scripts:

ssl_certs_fields: "/C={{ssl_certs_country}}/ST={{ssl_certs_state}}/L={{ssl_certs_locality}}/O={{ssl_certs_organization}}/CN={{common_name}}/emailAddress={{ssl_certs_email}}"
ssl_certs_local_privkey_path:       The path to the Private Key
ssl_certs_local_csr_path:           The path to the CSR
ssl_certs_local_path:               The local dir for this PKI file set
ssl_certs_local_decrypt_cakey_path: A temporarily decrypted copy of the CA 

key ssl_certs_local_caserial_path: The CA's serial numbering file ssl_certs_local_cert_path: The final generated certificate file.

The CSR Generation Command

openssl req -new -sha256 -subj "{{ ssl_certs_fields }}" 
-key "{{ ssl_certs_local_privkey_path }}"
-out "{{ ssl_certs_local_csr_path }}" 
-config "{{ssl_certs_local_path}}/san.cnf"

Self-Signing the CSR to create the Certificate

  openssl x509 -req -days {{ ssl_certs_days }}
  -sha256
  -extfile "{{ssl_certs_local_path}}/san.cnf"
  -extensions v3_req
  -in "{{ ssl_certs_local_csr_path }}"
  -CA "{{ ssl_certs_local_ca_path }}"
  -CAkey "{{ ssl_certs_local_decrypt_cakey_path }}"
  -CAcreateserial
  -CAserial "{{ ssl_certs_local_caserial_path }}"
  -out "{{ ssl_certs_local_cert_path }}"

To Verify the Result

openssl x509 -noout -text -in {{ ssl_certs_local_cert_path }}

That should include a section that appears as follows:

        X509v3 extensions:
        X509v3 Subject Key Identifier:
            3B:6E:E9:9F:B2:30:08:21:1C:C7:0D:4C:21:7A:B4:92:40:B6:71:98
        X509v3 Basic Constraints: critical
            CA:FALSE
        X509v3 Subject Alternative Name:
            DNS:foo.bar.com
2
  • For complex stuff like this, the shell Ansible module should be used instead of command. It is not really elegant either way - but thank you for your template workaround, this certainly works too.
    – AdamKalisz
    Commented May 22, 2020 at 19:47
  • I have provided a solution using the Ansible shell module down bellow. If only it was easier to generate CSRs in a sane way (or had openssl at least have a better user interface)...
    – AdamKalisz
    Commented Jul 6, 2020 at 20:40
8

The 2nd post in this link says that it not possible to do that only from command line, but the 4th post in the same link provides a workaround using bash's ability of referencing data as if it was in a file.

Taking a further look into it, someone mentioned the reqexts parameter used to make additions to certificate request. This blog uses bash's env as an approach to this.

But i'm just trying to help. Haven't tested any of this myself.

1
  • Thanks. I went with the solution using bash's command substitution ability. This way everything is contained in a single script. Commented Dec 9, 2014 at 10:18
3

Tested for RHEL7 (creating a self-signed certificate with a SAN)

openssl req -x509 -nodes -newkey rsa:2048 -days 3650 -sha256 -keyout test.key -out test.cert -reqexts SAN -extensions SAN -subj '/CN=test.example.com' -config <(cat /etc/pki/tls/openssl.cnf; printf "[SAN]\nsubjectAltName=DNS:test.example.com,DNS:test2.example.com")
3

I wanted a one line command to create a CSR - worked perfectly with no conf files, but didn't generate a SubjAltName entry. This version is what I was using Using read -p to request FQDN I wanted this to work with a SAN entry as well - so here's a working solution.

There is a dependency on the version of openssl, needs to be at least 1.1.1. because you need -addext.

read -p "FQDN ?" CN; openssl req -new -key yourkeyfile.key -subj /C=GB/ST=county/L=city/O=company/OU=yourorg/CN=$CN -addext "subjectAltName = DNS:$CN" -out./$CN.csr

No messing with conf files this way.

2

My solution to this problem was to create and reference a temporary cnf file by appending my command-line-collected subjectAltName information.

2

I needed to do this for creating self-signed certs for local testing, but also wanted to be able to pass multiple parameters for extensions, not just SAN. I discovered that doing multiple -extfile commands, just seemed to overwrite each other, and only the last -extfile value ended up in cert.

The solution was just to add more variables to the printf:

openssl x509 -req -sha256 \
    -extfile <(printf "extendedKeyUsage=serverAuth\nsubjectAltName=DNS:example.com") \
    -days 820 -in server.csr -signkey key.pem -out cert.pem

That works fine, but our workflow was already generated certs by storing the command in a package.json file, and then running npm run newcert. Attempting to add \n to the printf just broke the command. The solution for this was to switch to using a lot of echos, along with explicitly defining an extension name.

  • Note: For running these as an npm script, you'll have to escape the double quotes, and line continuations can't be used.
openssl req -newkey rsa:2048 -sha256 -nodes -keyout key.pem \
    -subj "/C=CN/ST=GD/L=SZ/O=Example/CN=example.com" -out server.csr

openssl x509 -req -sha256 -extensions v3_ca \
    -extfile <(echo "[v3_ca]"; echo "extendedKeyUsage=serverAuth"; echo "subjectAltName=DNS:example.com") \
    -days 820 -in server.csr -signkey key.pem -out cert.pem

Running openssl x509 -noout -text -in cert.pem shows it worked:

     X509v3 extensions:
            X509v3 Extended Key Usage:
                TLS Web Server Authentication
            X509v3 Subject Alternative Name:
                DNS:example.com
1

The question has been answered, but I still struggled with getting this into an elegant and useful form to automate CSR generation. The one liner is nice so I incorporated it into a routine that allows the subject alternative names as command arguments rather than values in a file also the flexibility to SAN or not to SAN. Try it with one argument then with many.

#!/bin/bash

#san_cert.sh

# defaults =====================================================================
DOM=domain.com
O=My\ Company,\ LLC
L=Seattle
ST=Washington
C=US
OU=Operations
EMAIL=certalert

#basic checks and strings ======================================================
if [ -z "$1" ];then
    echo usage: $0 name1 optionalname optionalname ...
    echo example: san_cert.sh www web w3 exch mail
    exit
else
    CN=$1
    SUBJ="/C=$C/ST=$ST/L=$L/O=$O/OU=$OU/CN=$CN.$DOM/emailAddress=$EMAIL.$DOM"
fi

#clearing old files
rm $CN.$DOM.ssl_csr $CN.$DOM.ssl_key

#create private key ============================================================
openssl genrsa -out $CN.$DOM.ssl_key 2048


if [ $# -gt 1 ];then #test for arg count
    #build SAN string ==================
    A=($@)
    I=1
    while [ $I -lt ${#A[@]} ]
    do
        SAN="DNS:${A[I]}.$DOM$CMA${SAN}"
        CMA=","
        I=$[$I+1]
    done
    SAN="\n[SAN]\nsubjectAltName=${SAN}"
    #===================================

    #create SAN certificate signing request ====================================
    openssl req -new -sha256 \
    -subj "$SUBJ" \
    -key   $CN.$DOM.ssl_key \
    -out   $CN.$DOM.ssl_csr \
    -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "$SAN"))
else
    #create Single certificate signing request =================================
    openssl req -new -sha256 \
    -subj "$SUBJ" \
    -key   $CN.$DOM.ssl_key \
    -out   $CN.$DOM.ssl_csr
fi

#verification ==================================================================
openssl req -text -noout -verify -in $CN.$DOM.ssl_csr
1

This has been answered, but if anyone's still looking for a no-prompt, cli-only method to create a self-signed root cert (without CAs or CSRs) and don't mind using Java keytool, here's an alternative:

Generate a PKCS12 keystore with keytool

keytool -genkeypair \
 -keyalg RSA \
 -keysize 3072 \
 -alias titan \
 -dname "CN=titan,OU=Engineering,O=Titan Corp.,C=US" \
 -ext BC:c=ca:false \
 -ext EKU:c=serverAuth \
 -ext "SAN:c=DNS:titan,IP:192.168.1.7" \
 -validity 3650 \
 -keystore server.p12 \
 -storepass s3cr3t \
 -keypass s3cr3t \
 -storetype pkcs12

Export Certificate and Key with openssl

openssl pkcs12 -in server.p12 -nodes -out cert.pem -passin pass:s3cr3t
openssl pkcs12 -in server.p12 -nodes -nocerts -out key.pem -passin pass:s3cr3t
0

As an addition to the answer by @Excalibur (btw. thank you for your work!)

I find this form a bit more suited for Ansible. It sidesteps the problems of the official module openssl_csr that is somewhat difficult to work with due to library dependency and version problems.

The following is an adaptation of a part of the script generation by @Excalibur. You don't need to create a file. This particular playbook outputs the certificate to stdin which you can show with (ansible-playbook -vvvv <playbook.yml>) or dump to a variable and output using the debug module.

The domain.key needs to be in the same directory as the playbook.

---
- name: Test CSR generation
  hosts: localhost

  vars:
  - country: 'US'                     # C
  - state: 'NJ'                       # ST
  - locality: 'Trenton'               # L
  - organization: 'ACME'              # O
  - organization_unit: 'IT'           # OU
  - common_name: 'host.example.com'
  - email_address: '[email protected]' # emailAddress
  - add_subj_alt_name: 'IP:192.0.2.0' # without common_name, e.g. IP:2001:db8::1

  tasks:
  - name: Generate CSR
    shell: |
      STR="/C={{ country }}/
        ST={{ state }}/
        L={{ locality }}/
        O={{ organization }}/
        OU={{ organization_unit }}/
        CN={{ common_name }}/
        emailAddress={{ email_address }}"
      openssl req -new -sha256 -key domain.key -subj "$STR" \
      -reqexts v3_req -extensions v3_req -config \
      <(cat <<<'
      [req]
      distinguished_name = req_distinguished_name
      req_extensions     = v3_req
      x509_extensions    = v3_req
      
      [req_distinguished_name]
      countryName                         = {{ country }}
      stateOrProvinceNamecountryName      = {{ state }}
      localityName                        = {{ locality }}
      organizationName                    = {{ organization }}
      organizationalUnitName              = {{ organization_unit }}
      commonName                          = {{ common_name }}
      emailAddress                        = {{ email_address }}
      
      [v3_req]
      # The extentions to add to a self-signed cert
      subjectKeyIdentifier = hash
      basicConstraints     = critical,CA:false
      subjectAltName       = DNS:{{ common_name }},{{ add_subj_alt_name }}
      keyUsage             = critical,digitalSignature,keyEncipherment') -noout -text
    args:
      executable: '/bin/bash'
0

extfile for IP SANs when signing CSR to CRT https://www.golinuxcloud.com/openssl-create-client-server-certificate/

openssl x509 -req -in server.csr -CA selfca.crt -CAkey selfca.key -CAcreateserial --extensions v3_req -extfile server.req -out server.crt
1
  • Why extfile? How is this answer different from all the other answers that mention extfile? If the answer is in the link, please include the relevant parts of the link in your answer here.
    – schroeder
    Commented Jul 8, 2020 at 8:54
0

Simple answer is: you need two separate sections for requesting and signing certificates.

In signing section, REMOVE subjectAltName specification altogether.

Then it'll pass from the request.

[ x509_server ]

basicConstraints = critical, CA:FALSE
keyUsage = critical, digitalSignature, keyAgreement, dataEncipherment
extendedKeyUsage = serverAuth, emailProtection, clientAuth

subjectKeyIdentifier = ${x509_base::subjectKeyIdentifier}
#subjectAltName = ${x509_base::subjectAltName}

authorityKeyIdentifier = ${x509_base::authorityKeyIdentifier}
issuerAltName = ${x509_base::issuerAltName}

authorityInfoAccess = ${x509_base::authorityInfoAccess}
crlDistributionPoints = ${x509_base::crlDistributionPoints}


[ x509_server_req ]

basicConstraints = ${x509_server::basicConstraints}
keyUsage = ${x509_server::keyUsage}
extendedKeyUsage = ${x509_server::extendedKeyUsage}

subjectKeyIdentifier = ${x509_server::subjectKeyIdentifier}
subjectAltName = ${x509_base::subjectAltName}
0

Create a copy of the default openssl.cnf file and add the line below in the [req] section:

[ req ]
default_bits        = 2048
default_keyfile     = privkey.pem
distinguished_name  = req_distinguished_name
attributes      = req_attributes
**req_extensions     = req_ext**
x509_extensions = v3_ca # The extentions to add to the self signed cert

Then, add the content below under the req_extensions section:

#req_extensions = v3_req # The extensions to add to a certificate request
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
DNS.1   = x.x.com
DNS.2   = x.x.com 
DNS.2   = x.x.com

Once the custom config file is created, explicitly specify this config file while creating a CSR:

req -newkey rsa:2048 -keyout test.key -out test.csr -config openssl_custom.cnf

Link to my working modified openssl config file:

https://drive.google.com/file/d/1LB26NdW13d4WggbaYwQXR7wnXd_pXed3/view?usp=sharing

0

Shout out to Thiyagarajen's solution

[Background] Was trying to generate CSR with adding in SAN

After few experiments, here's what I did after reading all useful solutions here and various sources.

If the OpenSSL configuration file is defined well, then we could use -config myopenssl.cnf without the need of -reqexts param.

First, you would need to create an OpenSSL configuration file {your_name}.cnf.

For example, nano myopenssl.cnf

Below is a template OpenSSL configuration file

[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
C = US
ST = VA
L = SomeCity
O = MyCompany
OU = MyDivision
CN = www.company.com
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = www.company.com
DNS.2 = company.com
DNS.3 = www.company.net
DNS.4 = company.net
IP.1 = 127.0.0.1
IP.2 = 127.0.0.2

Once you have configured well your {your_name}.cnf, let's proceed to generate the CSR

// Generate Certificate Signing Request(CSR) using existing key without creating a new key

openssl req -new -key myworker.key -out myworker.csr -config myopenssl.cnf

// Generate CSR with "new" RSA 2048 key

-nodes is no DES

openssl req -new -newkey rsa:2048 -nodes -out myworker.csr -keyout myworker.key -sha256 -config myopenssl.cnf

Based on my current understanding, I will try my best to explain the above configuration. Please correct me if I'm wrong ~

Under [req] section,

  1. distinguished_name = req_distinguished_name
    First, we need to understand what distinguished name is?
    Distinguished Name (DN) is a set of values entered during enrollment and the creation of a Certificate Signing Request (CSR) such as:
    • C= Country (2 character country code such as US)
    • ST = State (must be spelled out completely such as New York or California)
    • L = Locality/City
    • O = Organization (legal company name)
    • OU = Organizational Unit (division or department of company but this is an optional field)
    • CN = Common Name (the fully qualified domain name such as www.digicert.com)


So, distinguished_name = req_distinguished_name will point the OpenSSL to find the set of values under [req_distinguished_name] section and there's no need for us to use -subj param.

  1. req_extensions = v3_req
    Will point to [v3_req] section, whereby you could define any of the extension attributes you wish to add, in our case is just the subjectAltName. So, we could take out the keyUsage and extendedKeyUsage attributes. So, there's no need to use -reqexts anymore to point to the SAN section when you define "req_extensions = v3_req" and at which you subjectAltName resides in this [v3_req] section!(When generating a CSR, like this, 'req' could use the commandline option -reqexts or straight from the defined configuration file entry req_extensions.)

  2. prompt = no
    Will not prompt you to enter the Distinguised name like usual, instead it will used the one configured inside this cnf file [req_distinguished_name] section.

Under [req_distinguished_name]

From the OpenSSL commandline return message,

What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.

However, from my testing, it seem like could not leave country (C) with '.', else will hit error like: 140027926083488:error:0D07A098:asn1 encoding routines:ASN1_mbstring_ncopy:string too short:a_mbstr.c:151:minsize=2

Below is a sample snippet of leaving blank for the distinguished name.

[req_distinguished_name]
C = MY
ST = .
L = .
O = .
OU = .
CN = .

Under [v3_req]

We could either define subjectAltName in just one line like the upvoted solutions given in this thread or we could point subjectAltName to a "section" we created as shown in the template OpenSSL configuration file shown above.

Either
subjectAltName=DNS:example.com,DNS:www.example.com,IP:10.0.0.1,IP:10.0.0.2

Or

[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
IP.1 = 10.0.0.1
IP.2 = 10.0.0.2

Under [alt_names]

IP address must be in range of 0.0.0.0 - 255.255.255.255

For example, when defining IP.1 = ip1, the returned error message would be like: 139870375749536:error:220A4076:X509 V3 routines:a2i_GENERAL_NAME:bad ip address:v3_alt.c:476:value=ip1

For example, when defining IP.1 = 128.56.256.43, (invalid IP addr), the returned error message would be like: 140205462144928:error:220A4076:X509 V3 routines:a2i_GENERAL_NAME:bad ip address:v3_alt.c:476:value=128.56.256.43

Reference:

  1. https://support.citrix.com/article/CTX227983/how-to-create-a-csr-and-key-file-for-a-san-certificate-with-multiple-subject-alternate-names

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .