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.
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.
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
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 openssl@1.1
).
Note that if you have set the config attribute "req_extensions" at section "[req]" in openssl.cfg, it will ignore the command-line parameter
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
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
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 environment variable before invoking openssl:
export 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.
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
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
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.
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")
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.
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.
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
My solution to this problem was to create and reference a temporary cnf file by appending my command-line-collected subjectAltName information.
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
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:
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
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
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: 'info@example.com' # 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'
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
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
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}
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.
{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
{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 ~
distinguished_name = req_distinguished_name
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.
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.)
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.
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 = .
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
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: