How to create a self-signed SSL certificate with subject alternate names (SAN) for IIS websites
Does anyone know how to create a self-signed SSL certificate for use with IIS (7) that has subject alternative names (SAN)s? I need the certificate to be able to validate the hostname AND the IP address like this:
- CN=MyServerName
- IP SAN: 192.168.2.2
Some things i've been looking at:
Windows SDK: makecert.exe (doesn't support SANs)
Windows API CertEnroll (Server 2008): using PowerShell script (I've been able to get this to work with IIS, however when I export the certificate into a Java keystore (must have) I get an error keytool error: 'java.lang.Exception: Input not an X.509 certificate’)
Here's an example of a PowerShell script using CertEnroll: http://blogs.technet.com/b/vishalagarwal/archive/2009/08/22/generating-a-certificate-self-signed-using-powershell-and-certenroll-interfaces.aspx
- OpenSSL: I haven't looked into this yet...
It would be great if I can get my PowerShell script to create a certificate that Java recognizes using the CertEnroll API, but anything that works at this point i'll be happy hearing about.
I found a way to do this using OpenSSL. I was hoping to use CertEnroll but since it gave me interoperability problems with Java I'm just going to use OpenSSL.
Here is how I created a cert for IIS with subject alternative names using OpenSSL.
First create a OpenSSL config text file:
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = US
ST = VA
L = SomeCity
O = MyCompany
OU = MyDivision
CN = ANDY
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = andy
DNS.2 = 192.168.2.12
IP.1 = 192.168.2.12
IP.2 = 192.167.20.1
Then run the following OpenSSL commands:
openssl.exe req -x509 -nodes -days 730 -newkey rsa:2048 -keyout C:\cert.pem -out C:\cert.pem -config C:\PathToConfigFileAbove.txt
openssl.exe pkcs12 -export -out C:\cert.pfx -in C:\cert.pem -name "My Cert" -passout pass:mypassword
This will create you a cert in a PFX file which can be imported to IIS. I automated this with powershell like so:
# Get the certificate from the PFX file.
$pfxcert = new-object system.security.cryptography.x509certificates.x509certificate2
$pfxcert.Import(
"C:\cert.pfx",
"mypassword",
[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet -bor `
[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
)
# Add the certificate to the windows stores.
Get-Item -Path cert:\LocalMachine\My, cert:\LocalMachine\root | ForEach-Object {
$store = $_
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
$store.Add($pfxcert)
$store.Close()
}
Add-PSSnapin -Name WebAdministration # IIS 7 Powershell module.
Push-Location -Path IIS:\SslBindings
# Create new IIS SSL bindings.
Get-Item -Path "cert:\LocalMachine\My\$($pfxcert.Thumbprint)" | New-Item "0.0.0.0!443"
The java key tool is picky about what it'll allow to import. The certificate that you've built via powershell should work, though, with a little massaging.
What format is the certificate in now? If you've done an export from a windows certificate store, it's probably .pfx; you'll want to convert to a PEM-encoded x509 certificate:
openssl pkcs12 -in /path/to/certbundle.pfx -out /public/key/path/certificate.crt -nokeys
openssl pkcs12 -in /path/to/certbundle.pfx -out /private/key/path/certificate.key -nocerts -nodes
From there, you'll want to check the actual contents of the file - these Windows certificates include a "Bag Attributes" section above the -----BEGIN CERTIFICATE-----
section, which the keytool parser likes to choke on - feel free to strip that out so that the files look just like this, with no other content:
/public/key/path/certificate.crt
-----BEGIN CERTIFICATE-----
MIIAAAA........
-----END CERTIFICATE-----
/private/key/path/certificate.key
-----BEGIN RSA PRIVATE KEY-----
MIIAAAA........
-----END RSA PRIVATE KEY-----
These certificate files should be a lot more amenable to import by the java keytool.
I thought SAN wasn't supported using makecert either, but then I found this blog
It seems that you can get similar functionality to using SAN by using multiple common names. e.g. makecert -n "CN=CertName;CN=pseudoSAN"
or in your example "CN=Andy;CN=192.168.2.12"