Skip to content

Instantly share code, notes, and snippets.

@dol
Created July 24, 2017 13:11
Show Gist options
  • Save dol/e9f3d682529ae7ee368f0e6862e16a87 to your computer and use it in GitHub Desktop.
Save dol/e9f3d682529ae7ee368f0e6862e16a87 to your computer and use it in GitHub Desktop.
Create CSR with subjectAlternativeName and check and copy them to a signed certificate
<?php
require_once __DIR__ . '/vendor/autoload.php';
use X509\CertificationRequest\CertificationRequest;
use X509\CertificationRequest\Attribute\ExtensionRequestValue;
use X509\Certificate\Extension\SubjectAlternativeNameExtension;
use X509\GeneralName\DNSName;
use CryptoUtil\PEM\PEM;
$keyConfig = [
'private_key_type' => OPENSSL_KEYTYPE_RSA,
'private_key_bits' => 2048,
];
$key = openssl_pkey_new($keyConfig);
$sanDomains = [
'mydomain.tld',
'seconddomain.tld',
];
$dn = [
'commonName' => reset($sanDomains),
];
$csrConfig = [
'config' => __DIR__ . '/openssl.cnf',
'req_extensions' => 'v3_req',
'digest_alg' => 'sha256',
];
$certConfig = [
'config' => __DIR__ . '/openssl.cnf',
'x509_extensions' => 'usr_cert',
'digest_alg' => 'sha256',
];
$addPrefix = function ($value) {
// Important: Sanatize domain value and check if a valid domain
return 'DNS:' . $value;
};
$sanDomainPrefixed = array_map($addPrefix, $sanDomains);
putenv('PHP_PASS_SUBJECTALTNAME=' . implode(',', $sanDomainPrefixed));
$csr = openssl_csr_new($dn, $key, $csrConfig);
if (false === $csr) {
while (($e = openssl_error_string()) !== false) {
echo $e . '\n';
}
return;
}
openssl_csr_export($csr, $csrout);
// !! Important !!
// Extract and validate SAN names before copy them.
$parsedCsr = CertificationRequest::fromPEM(
PEM::fromString($csrout)
);
$parsedCsrInfo = $parsedCsr->certificationRequestInfo();
$extractSanFromCsr = function ($parsedCsrInfo) {
$sanDomainsFromCsr = [];
if (!$parsedCsrInfo->hasAttributes()) {
return $sanDomainsFromCsr;
}
foreach ($parsedCsrInfo->attributes() as $attributes) {
foreach ($attributes as $attribute) {
if ($attribute instanceof ExtensionRequestValue) {
foreach ($attribute->extensions() as $extension) {
if ($extension instanceof SubjectAlternativeNameExtension) {
foreach ($extension->names() as $name) {
if ($name instanceof DNSName) {
$sanDomainsFromCsr[] = $name->name();
}
}
}
}
}
}
}
return $sanDomainsFromCsr;
};
$sanDomainFromCsr = $extractSanFromCsr($parsedCsrInfo);
// ! Check the CSR SAN domain list
// Code ...
//
$sanDomainFromCsrPrefixed = array_map($addPrefix, $sanDomains);
putenv('PHP_PASS_SUBJECTALTNAME_FROM_CSR=' . implode(',', $sanDomainFromCsrPrefixed));
$cert = openssl_csr_sign($csr, null, $key, 365, $certConfig);
openssl_x509_export($cert, $certout, false);
echo $certout;
{
"require": {
"sop/x509": "^0.4.2"
}
}
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"content-hash": "3340309492e69a0a80da8c1b5562649e",
"packages": [
{
"name": "fgrosse/phpasn1",
"version": "1.5.2",
"source": {
"type": "git",
"url": "https://github.com/fgrosse/PHPASN1.git",
"reference": "a18b162eca6aa70f8f15615f4ac8c852dffbc7dd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/a18b162eca6aa70f8f15615f4ac8c852dffbc7dd",
"reference": "a18b162eca6aa70f8f15615f4ac8c852dffbc7dd",
"shasum": ""
},
"require": {
"ext-gmp": "*",
"php": ">=5.6.0"
},
"require-dev": {
"phpunit/phpunit": "~4.5",
"satooshi/php-coveralls": "dev-master"
},
"suggest": {
"php-curl": "For loading OID information from the web if they have not bee defined statically"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.5.x-dev"
}
},
"autoload": {
"psr-4": {
"FG\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Friedrich Große",
"email": "[email protected]",
"homepage": "https://github.com/FGrosse",
"role": "Author"
},
{
"name": "All contributors",
"homepage": "https://github.com/FGrosse/PHPASN1/contributors"
}
],
"description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.",
"homepage": "https://github.com/FGrosse/PHPASN1",
"keywords": [
"DER",
"asn.1",
"asn1",
"ber",
"binary",
"decoding",
"encoding",
"x.509",
"x.690",
"x509",
"x690"
],
"time": "2016-10-29T15:46:46+00:00"
},
{
"name": "sop/asn1",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/sop/asn1.git",
"reference": "bf11b168876d51d3690897b99c3e24b8853446c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sop/asn1/zipball/bf11b168876d51d3690897b99c3e24b8853446c4",
"reference": "bf11b168876d51d3690897b99c3e24b8853446c4",
"shasum": ""
},
"require": {
"ext-gmp": "*",
"ext-mbstring": "*",
"php": ">=5.6.3"
},
"type": "library",
"autoload": {
"psr-4": {
"ASN1\\": "lib/ASN1/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Joni Eskelinen",
"email": "[email protected]",
"role": "Developer"
}
],
"description": "A PHP library for X.690 ASN.1 DER encoding and decoding.",
"homepage": "https://github.com/sop/asn1",
"keywords": [
"DER",
"asn.1",
"asn1",
"x.690",
"x690"
],
"time": "2016-06-22T05:28:53+00:00"
},
{
"name": "sop/crypto-util",
"version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/sop/crypto-util.git",
"reference": "ea7ead19175a81aaa7993046ffdaed1e200fb06f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sop/crypto-util/zipball/ea7ead19175a81aaa7993046ffdaed1e200fb06f",
"reference": "ea7ead19175a81aaa7993046ffdaed1e200fb06f",
"shasum": ""
},
"require": {
"ext-openssl": "*",
"php": ">=5.6.3",
"sop/asn1": "^2.0.0"
},
"type": "library",
"autoload": {
"psr-4": {
"CryptoUtil\\": "lib/CryptoUtil/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Joni Eskelinen",
"email": "[email protected]",
"role": "Developer"
}
],
"description": "A PHP library of various utilities for cryptographic applications.",
"homepage": "https://github.com/sop/crypto-util",
"keywords": [
"Private Key",
"asn.1",
"asn1",
"crypto",
"cryptography",
"ec",
"pbes1",
"pbes2",
"pbkdf1",
"pbkdf2",
"pem",
"public key",
"public-key",
"rsa",
"util"
],
"time": "2016-07-27T09:52:36+00:00"
},
{
"name": "sop/x501",
"version": "0.4.0",
"source": {
"type": "git",
"url": "https://github.com/sop/x501.git",
"reference": "51ff77ed58e19fd606fa7470c690dc44db69f73d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sop/x501/zipball/51ff77ed58e19fd606fa7470c690dc44db69f73d",
"reference": "51ff77ed58e19fd606fa7470c690dc44db69f73d",
"shasum": ""
},
"require": {
"ext-intl": "*",
"ext-mbstring": "*",
"php": ">=5.6.3",
"sop/asn1": "^2.0.0"
},
"type": "library",
"autoload": {
"psr-4": {
"X501\\": "lib/X501/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Joni Eskelinen",
"email": "[email protected]",
"role": "Developer"
}
],
"description": "A PHP library for X.501 ASN.1 types, X.520 attributes and DN parsing.",
"homepage": "https://github.com/sop/x501",
"keywords": [
"attribute",
"dn",
"ldap",
"rdn",
"x.501",
"x.520",
"x501",
"x520"
],
"time": "2016-07-26T06:57:42+00:00"
},
{
"name": "sop/x509",
"version": "0.4.2",
"source": {
"type": "git",
"url": "https://github.com/sop/x509.git",
"reference": "3d9bd4c0e2e658235295efdbf52719587b3d0d31"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sop/x509/zipball/3d9bd4c0e2e658235295efdbf52719587b3d0d31",
"reference": "3d9bd4c0e2e658235295efdbf52719587b3d0d31",
"shasum": ""
},
"require": {
"ext-gmp": "*",
"php": ">=5.6.3",
"sop/asn1": "^2.0.0",
"sop/crypto-util": "^1.10.0",
"sop/x501": "^0.4.0"
},
"type": "library",
"autoload": {
"psr-4": {
"X509\\": "lib/X509/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Joni Eskelinen",
"email": "[email protected]",
"role": "Developer"
}
],
"description": "A PHP library for X.509 public key certificates, attribute certificates, certification requests and certification path validation.",
"homepage": "https://github.com/sop/x509",
"keywords": [
"ac",
"attribute certificate",
"certificate",
"certification request",
"csr",
"x.509",
"x509"
],
"time": "2016-10-27T12:45:48+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": []
}
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = ${ENV::PHP_PASS_SUBJECTALTNAME}
[ usr_cert ]
basicConstraints=CA:FALSE
nsComment = "Generated Certificate by php unicorn"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
subjectAltName = ${ENV::PHP_PASS_SUBJECTALTNAME_FROM_CSR}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment