For those of you using Debian-based systems, the openssl configuration file is at: /etc/ssl/openssl.cnf
(PHP 4 >= 4.2.0, PHP 5, PHP 7, PHP 8)
openssl_csr_new — Generates a CSR
$distinguished_names
,&$private_key
,$options
= null
,$extra_attributes
= null
openssl_csr_new() generates a new CSR (Certificate Signing Request)
based on the information provided by distinguished_names
.
Nota: É preciso ter um arquivo openssl.cnf válido instalado para que esta função funcione corretamente. Veja as notas na seção de instalação para obter mais informações.
distinguished_names
The Distinguished Name or subject fields to be used in the certificate.
private_key
private_key
should be set to a private key that was
previously generated by openssl_pkey_new() (or
otherwise obtained from the other openssl_pkey family of functions).
The corresponding public portion of the key will be used to sign the
CSR.
options
By default, the information in your system openssl.conf
is used to initialize the request; you can specify a configuration file
section by setting the config_section_section
key of
options
. You can also specify an alternative
openssl configuration file by setting the value of the
config
key to the path of the file you want to use.
The following keys, if present in options
behave as their equivalents in the openssl.conf
, as
listed in the table below.
options key |
type | openssl.conf equivalent |
description |
---|---|---|---|
digest_alg | string | default_md | Digest method or signature hash, usually one of openssl_get_md_methods() |
x509_extensions | string | x509_extensions | Selects which extensions should be used when creating an x509 certificate |
req_extensions | string | req_extensions | Selects which extensions should be used when creating a CSR |
private_key_bits | int | default_bits | Specifies how many bits should be used to generate a private key |
private_key_type | int | none | Specifies the type of private key to create. This can be one
of OPENSSL_KEYTYPE_DSA ,
OPENSSL_KEYTYPE_DH ,
OPENSSL_KEYTYPE_RSA or
OPENSSL_KEYTYPE_EC .
The default value is OPENSSL_KEYTYPE_RSA .
|
encrypt_key | bool | encrypt_key | Should an exported key (with passphrase) be encrypted? |
encrypt_key_cipher | int | none | One of cipher constants. |
curve_name | string | none | One of openssl_get_curve_names(). |
config | string | N/A | Path to your own alternative openssl.conf file. |
extra_attributes
extra_attributes
is used to specify additional
configuration options for the CSR. Both distinguished_names
and
extra_attributes
are associative arrays whose keys are
converted to OIDs and applied to the relevant part of the request.
Returns the CSR ou false
em caso de falha.
Versão | Descrição |
---|---|
8.0.0 |
On success, this function returns an OpenSSLCertificateSigningRequest instance now;
previously, a resource of type OpenSSL X.509 CSR was returned.
|
8.0.0 |
private_key accepts an OpenSSLAsymmetricKey instance now;
previously, a resource of type OpenSSL key was accepted.
|
7.1.0 |
options now also supports curve_name .
|
Exemplo #1 Creating a self-signed certificate
<?php
// for SSL server certificates the commonName is the domain name to be secured
// for S/MIME email certificates the commonName is the owner of the email address
// location and identification fields refer to the owner of domain or email subject to be secured
$dn = array(
"countryName" => "GB",
"stateOrProvinceName" => "Somerset",
"localityName" => "Glastonbury",
"organizationName" => "The Brain Room Limited",
"organizationalUnitName" => "PHP Documentation Team",
"commonName" => "Wez Furlong",
"emailAddress" => "wez@example.com"
);
// Generate a new private (and public) key pair
$privkey = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));
// Generate a certificate signing request
$csr = openssl_csr_new($dn, $privkey, array('digest_alg' => 'sha256'));
// Generate a self-signed cert, valid for 365 days
$x509 = openssl_csr_sign($csr, null, $privkey, $days=365, array('digest_alg' => 'sha256'));
// Save your private key, CSR and self-signed cert for later use
openssl_csr_export($csr, $csrout) and var_dump($csrout);
openssl_x509_export($x509, $certout) and var_dump($certout);
openssl_pkey_export($privkey, $pkeyout, "mypassword") and var_dump($pkeyout);
// Show any errors that occurred here
while (($e = openssl_error_string()) !== false) {
echo $e . "\n";
}
?>
Exemplo #2 Creating a self-signed ECC certificate (as of PHP 7.1.0)
<?php
$subject = array(
"commonName" => "docs.php.net",
);
// Generate a new private (and public) key pair
$private_key = openssl_pkey_new(array(
"private_key_type" => OPENSSL_KEYTYPE_EC,
"curve_name" => 'prime256v1',
));
// Generate a certificate signing request
$csr = openssl_csr_new($subject, $private_key, array('digest_alg' => 'sha384'));
// Generate self-signed EC cert
$x509 = openssl_csr_sign($csr, null, $private_key, $days=365, array('digest_alg' => 'sha384'));
openssl_x509_export_to_file($x509, 'ecc-cert.pem');
openssl_pkey_export_to_file($private_key, 'ecc-private.key');
?>
For those of you using Debian-based systems, the openssl configuration file is at: /etc/ssl/openssl.cnf
Not sure whether the "bug" (undocumented behavior) I encountered is common to other people, but this comment might save hours of painful debug:
If you can't generate a new private key using openssl_pkey_new() or openssl_csr_new(), your script hangs during the call of these functions and in case you specified a "private_key_bits" parameter, ensure that you cast the variable to an int. Took me ages to notice that.
<?php
$SSLcnf = array('config' => '/usr/local/nessy2/share/ssl/openssl.cnf',
'encrypt_key' => true,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
'digest_alg' => 'sha1',
'x509_extensions' => 'v3_ca',
'private_key_bits' => $someVariable // ---> bad
'private_key_bits' => (int)$someVariable // ---> good
'private_key_bits' => 512 // ---> obviously good
);
?>
When in doubt, read the source code to PHP!
$configargs is fairly opaque as to what is going on behind the scenes. That is, until you actually look at php_openssl_parse_config() in '/ext/openssl/openssl.c':
SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
CONF_get_string(req->req_config, req->section_name, "default_md"));
SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
CONF_get_string(req->req_config, req->section_name, "req_extensions"));
SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits,
CONF_get_number(req->req_config, req->section_name, "default_bits"));
SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT);
Here we can see that SET_OPTIONAL_STRING_ARG() is called for most inputs but for 'private_key_bits' SET_OPTIONAL_LONG_ARG() is called. Both calls are C macros that expand to code that enforces the expected input type. The generated code ignores the input without warning/notice if an unexpected type is used and just uses the default from the configuration file. This is why using a string with 'private_key_bits' will result in unexpected behavior.
Further inspection of the earlier initialization in the same function:
SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename);
SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req");
req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL);
req->req_config = CONF_load(NULL, req->config_filename, NULL);
if (req->req_config == NULL) {
return FAILURE;
}
And elsewhere in another function:
/* default to 'openssl.cnf' if no environment variable is set */
if (config_filename == NULL) {
snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename), "%s/%s",
X509_get_default_cert_area(),
"openssl.cnf");
} else {
strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename));
}
Reveals that 'config' in $configargs is an override for any default setting elsewhere. This actually negates the comment in the documentation that says "Note: You need to have a valid openssl.cnf installed for this function to operate correctly. See the notes under the installation section for more information." A more correct sentence would be "Note: You need to either have a valid openssl.cnf set up or use $configargs to point at a valid openssl.cnf file for this function to operate correctly."
All of that goes to show that looking at the PHP source code is the only real way to figure out what is actually happening. Doing so saves time and effort.
In the PHP example above it uses "UK" as the country name which is incorrect, the country name must be "GB"
To set the "basicConstraints" to "critical,CA:TRUE", you have to define configargs, but in the openssl_csr_sign() function !
That's my example of code to sign a "child" certificate :
$CAcrt = "file://ca.crt";
$CAkey = array("file://ca.key", "myPassWord");
$clientKeys = openssl_pkey_new();
$dn = array(
"countryName" => "FR",
"stateOrProvinceName" => "Finistere",
"localityName" => "Plouzane",
"organizationName" => "Ecole Nationale d'Ingenieurs de Brest",
"organizationalUnitName" => "Enib Students",
"commonName" => "www.enib.fr",
"emailAddress" => "ilovessl@php.net"
);
$csr = openssl_csr_new($dn, $clientPrivKey);
$configArgs = array("x509_extensions" => "v3_req");
$cert = openssl_csr_sign($csr, $CAcrt, $CAkey, 100, $configArgs);
openssl_x509_export_to_file($cert, "childCert.crt");
Then if you want to add some more options, you can edit the "/etc/ssl/openssl.cnf" ssl config' file (debian path), and add these after the [ v3_req ] tag.
There appears to be no openssl_csr_free function.
At least not here.
If it's in the source, one might be able to just call it.
If it's not in the source, it probably should be.
If you get the error:
error:0D11A086:asn1 encoding routines:ASN1_mbstring_copy:string too short
then look at your key:value pairs in the $dn (distinguished name) array.
If you have one value (like "organizationalUnitName" = "") set to an empty string, it will throw the above error.
Fix the error by either eliminating that array element from $dn completely, or using a space " " instead of an empty string.
I am using PHP-4.3.11.
The type of configargs--private_key_bits is a INTEGER, not a string.
An example of configration:
<?php
$config = array(
"digest_alg" => "sha1",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_DSA,
"encrypt_key" => false
);
?>
As you probably guessed from the example, the documentation is misinforming. openssl_csr_new returns a CSR resource or FALSE on failure.
mixed openssl_csr_new (assoc_array dn, resource_privkey, [...])
One command to create modern certificate request with 4 SAN subdomain.
According to RFC you can change CN (common name) and subjectAltName. When cert validated searching in CN and subjectAltName.
openssl req -new -nodes -config <( cat <<-EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = re
distinguished_name = dn
[ dn ]
CN = my.tld
C = country
ST = state
L = location
O = ORGANISATION
[ re ]
subjectAltName = DNS.1: www.my.tld, DNS.2: www2.my.tld, DNS.3: www3.my.tld, DNS.4: www4.my.tld
EOF
) -keyout secret.key -out req.csr