Wednesday, October 16, 2013

Creating Wildcard self-signed certificates with openssl with subjectAltName (SAN - Subject Alternate Name)

For the past few hours I have been trying to create a self-signed certificate for all the sub-domains for my staging setup using wildcard subdomain.

There are a lot of guides and tutorials on the internet out there which explain the process of creating a self-signed certificate using openssl with a good amount details. Further there are also certain guides to create a self-signed cert for wildcard domain. It's fairly easy. You just specify that your Common Name (CN) a.k.a FQDN is *.yourdomain.com while creating the certificate signing request (CSR).

This will take care of all of your sub-domains under yourdomain.com (like www.yourdomain.com or mail.yourdomain.com), however your top level bare domain (yourdomain.com) itself is not covered under this certificate. When you use a certificate generated by specifying *.yourdomain.com the browsers will throw up an error when you hit your server with the top level domain name https://yourdomain.com/.

To address this X.509 certificate standard allows for a type of extension named subjectAltName (http://en.wikipedia.org/wiki/SubjectAltName). Using this you can specify that there are a few other domain names for which this certificate is valid.

This requires specifying the use of this extension while generating the certificate request AND while signing the certificate. To do this you will have to add a few things to your openssl configuration file (typically /etc/ssl/openssl.cnf on a Ubuntu like machine). Alternatively you can copy the config file to another location, add these extension stuff there and then specify the new config file for all your openssl commands. The commands shown below assume the default config file at /etc/ssl/openssl.cnf was updated with extension details.

Here is one blog post which details the updates needed for the openssl config file. http://grevi.ch/blog/ssl-certificate-request-with-subject-alternative-names-san. It also has commands for generating the private key, converting the key to a format which does not ask for password (a.k.a unencrypted key), generating the certificate request (CSR) and finally signing the certificate. The steps mentioned there until the generation of certificate request are correct. It is the last step of signing the certificate that is missing one small piece of information because of which the extension mentioned above (subjectAltName) doesn't get added to the final certificate, despite they being present in the certificate request.

After a lot of searching on the internet, copy pasting the commands exactly, trying my luck at IRC (irc.freenode.net#openssl) the answer finally appeared to me in the man pages (duh..! RTFM dude..!!).  The man page for x509 (man x509) command of openssl has this little entry :

-extfile filename
           file containing certificate extensions to use. If not specified then no extensions are added to the certificate.

So turns out that just specifying the extensions in the openssl config file is not sufficient, but you must also specify the same file as the file containing the extensions to be included in the command line using the above -extfile option.

With that added, you will get a self-signed certificate for your wildcard subdomain which is also valid for your top level bare domain.

Changes made to /etc/ssl/openssl.cnf

Uncomment the req_extensions = v3_req
req_extensions = v3_req # The extensions to add to a certificate request


Add subjectAltName to v3_req section

[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

Finally add the alternate names for which you want this certificate to be valid. It would be your toplevel bare domain

[alt_names]
DNS.1 = yourdomain.com

This last section [alt_names] will not be present in the file. You can add it right after the [ v3_req ] section.

Once config update is done, create your certificate.
Here are the commands that I used to create such a certificate :

Create a private key :
openssl genrsa -des3 -out ssl/staging/yourdomain.com.key 2048

This will ask you for a password. Key in a simple one and remember it.

Convert the private key to an unencrypted format

openssl rsa -in ssl/staging/yourdomain.com.key -out ssl/staging/yourdomain.com.key.rsa

This will ask you for a password. Key in the same thing that you used in the previous step.

Create the certificate signing request

openssl req -new -key ssl/staging/yourdomain.com.key.rsa -out ssl/staging/yourdomain.com.csr

This will ask you for a bunch of fields. Enter *.yourdomain.com when it asks for Common Name (or FQDN). The fields after that can be left blank by just hitting return (Enter) key.

Sign the certificate with extensions

openssl x509 -req -extensions v3_req -days 365 -in ssl/staging/yourdomain.com.csr -signkey ssl/staging/yourdomain.com.key.rsa -out ssl/staging/yourdomain.com.crt -extfile /etc/ssl/openssl.cnf

Note that here we specify the openssl config file as the file file containing extensions as that is where we have defined it. Probably we can put the extensions in a separate file too, but I haven't tried that. (Homework?! :P)

Thats it. Now you have a self-signed wildcard subdomain certificate which is valid for your top level domain too.

Despite this the first time you hit your SSL enabled website with the above generated certificate your browser will show the standard "Invalid Certificate - Untrusted" page. It is because your certificate is self-signed. You can view the errors in the "Technical Details" section.

15 comments:

  1. "... You just specify that your Common Name (CN) a.k.a FQDN is *.yourdomain.com ..." - wrong. CN is deprecated for DNS names. Use the SAN.

    ReplyDelete
  2. > "... You just specify that your Common Name (CN) a.k.a FQDN is *.yourdomain.com ..." - wrong. CN is deprecated for DNS names. Use the SAN.

    Yeah browser (chrome in my case) seems to prefer SAN over the wildcard CN when both are present. Fixed with wildcard SAN (though they say it's against the RFC):

    [alt_names]
    DNS.1 = yourdomain.com
    DNS.2 = *.yourdomain.com

    ReplyDelete
  3. Perfect! Thank you for this posting! -extfile option is exactly what I was looking for! I was stuck at this point too, but just typed a few lines in Google and your blog saved my day! Otherwise I would also have to tediously, monotonically, and boringly read through all the MAN pages and stuff.. Thank you for sharing!

    ReplyDelete
  4. Thank you for this! It was driving me nuts trying to figure out why the OpenSSL provided CA.pl script wasn't including extensions when signing. They don't have this switch in their own file!

    Can anyone here explain to me a way to sign with the extensions included in the request rather than resupplying them? For example, if I receive a request from someone and I want to sign it, why should I have to have their openssl.cnf extensions? Shouldn't I be able to decide whether to sign it as requested rather than having to provide the extensions myself?

    ReplyDelete
    Replies
    1. anakha000 you signed it using scr provided. Then provided scr has the key that has been generated before. It works successively. In other words you do not put the cart before the horse in order to ride it, first you put the horse and then the cart, not vice versa :-)

      Delete
  5. I'm not understanding what you're saying. I'm guessing you mean CSR not SCR? It's not really a question of putting the cart before the horse.

    I'm asking if you are the CA and you receive a CSR to sign, shouldn't there be something embedded in the request that includes the extensions rather than the person sending the CSR having to send extensions in a config file separately? Unless I'm misunderstanding something, shouldn't the CA's function just be to sign off on the request and not to have to obtain extensions in addition to the request it's signing?

    I don't think you've answered my question, but thanks I guess?

    ReplyDelete
  6. I believe you don't have to edit /etc/ssl/openssl.cnf (putting altnames there seems silly; req_extensions = v3_req is set by default isn't it?), just make an alt.txt containing

    [v3_req]
    subjectAltName = @alt_names
    [alt_names]
    DNS.1 = domain1
    DNS.2 = domain2
    etc

    and supply it to -extfile

    ReplyDelete
  7. Now comes the hard part:
    Signing your CSR with altNames with your self signed root certificate while keeping the alt names.
    Please tell me that you know how to accomplish this!

    ReplyDelete
    Replies
    1. Just found the answer for myself:
      Instead of using the "-signkey device.key" option for self signing you just use the "-CA, -CAkey, -CAserial" options to sign with your root CA

      But also make sure to use the Extensions like described above with "-extensions v3_req -extfile openssl.cnf"

      Delete
  8. I know that people say there are always vulnerabilities, but what if there weren't. Or to be much more realistic; hard to find. What do hackers do then? If there is nothing for them to exploit how can they gain access to what ever it is that they are targeting? Is finding vulnerabilities then exploiting them the only way?

    For the record, I have no interest in unethical hacking. I just want to find other ways to protect my website and programs.
    cdn services

    ReplyDelete
  9. I am really very agree with your qualities it is very helpful for look like home. Thanks so much for info and keep it up.
    mac design software

    ReplyDelete
  10. I visited your blog for the first time and just been your fan. I Will be back often to check up on new stuff you post!
    Buy VPN With Bitcoin

    ReplyDelete
  11. Post is very informative,It helped me with great information so I really believe you will do much better in the future.
    Owncloud Privacy Services

    ReplyDelete
  12. Many thanks to this Information . It will help me very much. My Clients expext that they can find
    a SSL Certificate at our Website. Not all, but with international Clients, you have to thing international

    ReplyDelete
  13. Thanks for this post. I found that I had to put both mydomain.com and *.mydomain.com in the alt_names section. Regardless of what I specified as the CN, I'd still get an error about the cert was only valid for one name until I added both to the alt_names section.

    ReplyDelete