Create CSR with SANs on php

Posted under others On By xpk

Ever tried generating CSR with SANs? It is tedious work. It involves populating an openssl config file with the additional domain names. Put it on a webapp, it does not eliminate the work, but only require minimal coding once.

SANs certificate is an extension to X.509, which allows additional domain names to be added to a certificate. As people starts to put more and more domains in a certificate, the work to generate a CSR becomes cumbersome. Maybe the future version of openssl will simplify the process. Until then, the domain names need to be put in a config file for openssl to read.

Building a webapp, or more like a couple of php pages make life easier. First, check that the openssl extension is enabled on php. Then here comes the php code.

Generate a RSA key, export the private key to a string variable

$keypair = openssl_pkey_new(array('private_key_bits' => 2048));
openssl_pkey_export($keypair, $privKey);

Create a form, get the usual inputs

$dn = array(
    "countryName" => $_POST["country"],
    "stateOrProvinceName" => $_POST["state"],
    "localityName" => $_POST["city"],
    "organizationName" => $_POST["orgname"],
    "commonName" => $_POST["cn"],
    "emailAddress" => $_POST["email"]

Use a textarea to gather the SANs, then put it in an array

	$sansRaw = $_POST["sans"];
	$sansArr = explode("\n", $sansRaw);
	$sansArr = array_filter($sansArr, 'trim');

Write that to a temp openssl config file

$sslConfig = file_get_contents("/data/sites/x/csr/ssl-template.cnf");
	$counter = 1;

	foreach ($sansArr as $line) {
		$fqdn = tidyFqdn($line);
		$sslConfig = $sslConfig . "\nDNS." . $counter . "=" . $fqdn;

	$sslConfigFile = "/data/sites/x/csr/tmp/ssl.cnf-" . rand();

	file_put_contents($sslConfigFile, $sslConfig);

The template config looks like this

[ req ]
distinguished_name    = req_distinguished_name

[ req_distinguished_name ]
countryName            = Country Name (2 letter code)
stateOrProvinceName        = State or Province Name (full name)
stateOrProvinceName_default    = Some-State
localityName            = Locality Name (eg, city)
0.organizationName        = Organization Name (eg, company)
organizationalUnitName        = Organizational Unit Name (eg, section)
commonName            = Common Name (e.g. server FQDN or YOUR name)
emailAddress            = Email Address

[ v3_req ]
subjectAltName = @req_sans

[ req_sans ]

Create a config array and generate the CSR

	$csrConfig = array(
	    "digest_alg" => "sha256",
	    "req_extensions" => "v3_req",
   	    "config" => $sslConfigFile

	$csrRes = openssl_csr_new($dn, $privKey, $csrConfig);
        openssl_csr_export($csrRes, $csr);

The CSR is now in the $csr variable. The private key that goes with it is in $privKey.

 570 total views,  2 views today

Leave a comment

Your email address will not be published. Required fields are marked *