DEV Community

Miro
Miro

Posted on

2 1

Quickly create a self signed certificate for a custom domain

I often find myself needing a simple self signed certificate that is either for a wildcard domain or that cover multiple domain names. And then, even when I have openssl somewhere the questions are "do I have the config file?", "do I really need to fill in all those distinguished name values?", "where do I put additional domains", etc.

So to make my life simpler I made a small batch script that takes domain names as arguments, creates configuration file and instructs openssl to create a self signed certificate for those domains.

Example usage

Requesting certificates like:

E:\Temp> self-signed-cert mydomain.local *.mydomain.local

will generate one certificate with 2 domain names (mydomain.local and *.mydomain.local) and will produce the following files:

  1. mydomain.local.conf - configuration file for openssl
  2. mydomain.local.key - private key
  3. mydomain.local.crt - certificate
  4. mydomain.local.pfx - a pkcs#12 file with both certificate and private key

Content of the generated mydomain.local.conf file:

[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = req_distinguished_name
x509_extensions = v3_req

[req_distinguished_name]
CN = mydomain.local

[v3_req]
subjectAltName = @san

[san]
DNS.1 = mydomain.local
DNS.2 = *.mydomain.local

And the generated certificate looks like this:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            fc:55:a1:88:a5:68:67:0c
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = mydomain.local
        Validity
            Not Before: Apr 13 12:12:57 2020 GMT
            Not After : Apr 11 12:12:57 2030 GMT
        Subject: CN = mydomain.local
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:cb:d9:5c:bb:df:23:1e:69:5d:b2:45:06:d8:1f:
                    d9:d1:4a:37:07:ab:c7:86:77:e0:2f:88:36:dc:f4:
                                      <...>
                    7d:70:b6:23:aa:9a:bc:57:83:c9:f8:13:3f:9f:b4:
                    01:54:71
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:mydomain.local, DNS:*.mydomain.local
    Signature Algorithm: sha256WithRSAEncryption
         b0:7b:4c:2c:f6:5e:40:2b:9d:9d:71:b1:d3:f8:0b:44:84:50:
         d1:ea:b0:91:fb:61:7d:d8:f8:d9:ca:5d:c8:b2:bf:d4:5d:75:
                               <...>
         5c:73:66:d1:52:10:11:2b:68:85:da:8a:16:3d:82:4f:0c:c5:
         50:a5:85:81:4f:06:27:33

Batch file explained

if [%1]==[] (
  echo Usage: %0 ^<domain_name^> [additional_domain] [additional_domain] ...
  exit /b 1
)

Just making sure that there is at least one argument

if [%2]==[] (set addsan=) else (set addsan=1)

Checking if it is a single domain name or multiple domain name

set fn=%~1
if [%fn:~0,2%] == [*.] set fn=_wildcard.%fn:~2%

Setting a file name for configuration and certificates. If the (first) domain name in the list is a wildcard domain, replace the asterisk character with "wildcard" word. Otherwise just take the domain name. So requesting a *.mydomain.local certificates will generate wildcard.mydomain.local files, while requesting web1.mydomain.local certificate will generate web1.mydomain.local files.

%~1 - removing surrounding quotes around first argument. E.g. if the first argument is "something with spaces", the %~1 will remove the quotes.
%fn:~0,2% - substring, first two characters of the fn variable
%fn:~2% - substring, everything after 2nd character

echo [req]>%fn%.conf
echo default_bits = 2048>>%fn%.conf
echo prompt = no>>%fn%.conf
echo default_md = sha256>>%fn%.conf
echo distinguished_name = req_distinguished_name>>%fn%.conf
if [%addsan%] == [1] echo x509_extensions = v3_req>>%fn%.conf
echo.>>%fn%.conf
echo [req_distinguished_name]>>%fn%.conf
echo CN = %~1>>%fn%.conf
echo.>>%fn%.conf

Making the openssl configuration, named %fn%.conf.

if not [%addsan%] == [1] goto :makecert

Skip additional configuration if there is only one domain

echo [v3_req]>>%fn%.conf
echo subjectAltName = @san>>%fn%.conf
echo.>>%fn%.conf
echo [san]>>%fn%.conf
set /a sanid = 0

Additional configuration sections for multiple domain names.

:sanloop
set /a sanid+=1
echo DNS.%sanid% = %~1>>%fn%.conf
shift
if [%~1]==[] goto :makecert
goto :sanloop

Looping through the arguments.
set /a sanid+=1 - increment counter so that each DNS entry has it's own number
shift - shift arguments so that %2 becomes %1, %3 becomes %2, etc
if [%~1]==[] goto :makecert - once there are no more arguments, break the loop

:makecert
openssl req -new -x509 -nodes -days 3650 -sha256 -newkey rsa:4096 -keyout %fn%.key -out %fn%.crt -config %fn%.conf

openssl pkcs12 -export -out %fn%.pfx -inkey %fn%.key -in %fn%.crt -name %friendly% -passout pass:

Finally, the openssl call. Frist create a new self signed certificate which is valid for 10 years, and then export it to pkcs#12 pfx file with an empty password.

Make sure that openssl is somewhere in PATH.

self-signed-cert.cmd

@echo off
setlocal
if [%1]==[] (
echo Usage: %0 ^<domain_name^> [additional_domain] [additional_domain] ...
exit /b 1
)
set friendly=%1
if [%2]==[] (set addsan=) else (set addsan=1)
rem ***** If domain is wildcard substitute asterisk character with a _wildcard text for the file name
set fn=%~1
if [%fn:~0,2%] == [*.] set fn=_wildcard.%fn:~2%
rem ***** Write openssl configuration file
echo [req]>%fn%.conf
echo default_bits = 2048>>%fn%.conf
echo prompt = no>>%fn%.conf
echo default_md = sha256>>%fn%.conf
echo distinguished_name = req_distinguished_name>>%fn%.conf
if [%addsan%] == [1] echo x509_extensions = v3_req>>%fn%.conf
echo.>>%fn%.conf
echo [req_distinguished_name]>>%fn%.conf
echo CN = %~1>>%fn%.conf
echo.>>%fn%.conf
if not [%addsan%] == [1] goto :makecert
rem ***** Write san related sections
echo [v3_req]>>%fn%.conf
echo subjectAltName = @san>>%fn%.conf
echo.>>%fn%.conf
echo [san]>>%fn%.conf
set /a sanid = 0
rem ***** Loop through SAN names
:sanloop
set /a sanid+=1
echo DNS.%sanid% = %~1>>%fn%.conf
shift
if [%~1]==[] goto :makecert
goto :sanloop
:makecert
openssl req -new -x509 -nodes -days 3650 -sha256 -newkey rsa:4096 -keyout %fn%.key -out %fn%.crt -config %fn%.conf
openssl pkcs12 -export -out %fn%.pfx -inkey %fn%.key -in %fn%.crt -name %friendly% -passout pass:

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more