3 February 2014

As part of my slow-moving efforts within my company to get WinRM enabled across the enterprise (14,000 computers…) I’ve had to do a bit of testing to make sure I can properly secure it.  Much of that testing is around setting the execution level and making sure nothing outside of what I or my team has signed is able to be executed.  To do that, I needed to be able to make my own, self-signed certs to test what it would be like with scripts coming from outside.  Naturally, I chose OpenSSL  I don’t have access to create Microsoft certs with our company tools and I don’t want to bug (or wait on) someone else to make them for me when I need them.  I’m not patient like that.  So, in typical geek fashion I set out to figure out how to do it on my own.

First I’ll start of by saying that 99% of what you find on the internet on how to do it will not work on Windows.  Those instructions will work beautifully on Linux but if the instructions only tell you to make modifications to the config file, then those instructions are not for you.  I went through several different sites giving values to set inside the config but it never worked.  Every cert I ended up with was not valid for code signing!  I ended up spending time going through the official OpenSSL documention and figuring out the method I ended up with.  It’s not hard, it just uses a method most don’t know about or haven’t had a need to use.  You’ll have to make changes to your main config file, create a supplemental one, and I throw in a batch file to automate it.  I am using OpenSSL 1.0.1e that was released on 11 Feb 2013 on a Windows 7 machine.

Make sure the v3_req section in your openssl.cfg matches the one below:

[ v3_req  ] 

# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = digitalSignature
extendedKeyUsage = codeSigning, msCodeInd, msCodeCom
nsCertType = client, email, objsign

You can take away the email under nsCertType but there isn’t a reason to.  You can also add any additional types you may want this cert to do, just don’t take anything away that has Code, Signature or obj references in them.

You then want to create a NEW .cfg file and put the exact same properties as above (without the [ v3_req ] header).  You can call it anything you want, just save it somewhere logical.  I keep mine in the OpenSSL directory with the openssl.cfg.

Below is the batch script I wrote to automate the process of creating a new self-signed CA and a code signing cert.

REM Switch to the directory where openssl.exe is
CD C:\OpenSSL-Win32\bin
REM Create the key for the Certificate Authority.  2048 is the bit encryptiong, you can set it whatever you want
openssl genrsa -out C:\YOURPATH\ca.key 2048
REM Next create the certificate and self-sign it (what the -new and -x509 do).  Note, I'm explicitly telling it the main config path.  You have to.
openssl req -config C:\OpenSSL-Win32\bin\openssl.cfg -new -x509 -days 1826 -key C:\YOURPATH\ca.key -out C:\YOURPATH\ca.crt
REM Now I'm creating the private key that will be for the actual code signing cert
openssl genrsa -out C:\YOURPATH\codesign.key 2048
REM Creating the request for a certificate here.  Note the -reqexts you need to tell it to pull that section from the main config or it wont do it.
openssl req -config C:\OpenSSL-Win32\bin\openssl.cfg -new -key C:\YOURPATH\codesign.key -reqexts v3_req -out C:\YOURPATH\codesign.csr
REM Signing the code signing cert with the certificate authority I created.  Note the -extfile this is where you point to the new .cfg you made.
openssl x509 -req -days 1826 -in C:\YOURPATH\codesign.csr -CA C:\YOURPATH\ca.crt -CAkey C:\YOURPATH\ca.key -extfile C:\OpenSSL-Win32\bin\v3.cfg -set_serial 01 -out C:\YOURPATH\codesign.crt
REM Now I"m expoorting my key and crt into a PKCS12 (.pfx file) so that I can import it onto the machine that I'm going to use it to sign on.
openssl pkcs12 -export -out C:\YOURPATH\codesign.pfx -inkey C:\YOURPATH\codesign.key -in C:\YOURPATH\codesign.crt

I know some of it looks redundant, and it is, but I found it all to be necessary to get it to work.  I suspect it’s a bug with the Windows version of SSL since it should read it all from the openssl.cfg file.  It does on Linux.  I may have missed a specific scenario of testing config information in places, and maybe you can leave it out in one place, but this isn’t a long or complicated process so I see no reason to go back and fully verify.

I don’t go into detail on all of the parameters that are used.  I don’t understand enough to do that (although I’m pretty sure I have it figured out) and I am by no means an expert on encryption or SSL.  I hope this all works for you.  If anyone has any website they recommend that gives a great, clear, and thorough explanation of how encryption (or specifically SSL) works I would really appreciate you linking it in the comments!

A few more notes:

  • Don’t forget to import this to use it!
  • If you want full trust, import the CA you created too.
  • This works for signing powershell scripts, it’s the reason why I figured it out
  • Secure your cert with a password.  It’s listed as an optional parameter when generating the crt but do it.  When you import it into your certificate store, mark it as non-exportable and keep your key, crt, and pfx files in a secure location!

4 Responses to “Creating OpenSSL Code Signing Certs on Windows”

  • Desmond Whitt
    August 19th, 2014 at 1:53 pm     

    Here is the missing piece to getting the config file to work on windows:
    set OPENSSL_CONF=C:\Apache2\conf\openssl.cnf

  • thegeek
    August 21st, 2014 at 11:53 am     

    Thanks! I wonder why that isn’t written anywhere… or maybe I just missed it.

  • Thom
    November 12th, 2014 at 4:50 am     

    Thankyou for the post it was helpful!

  • thegeek
    November 12th, 2014 at 7:05 am     

    You’re welcome!

You must be logged in to post a comment.