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 — Erzeugt einen CSR
$distinguished_names
,&$private_key
,$options
= null
,$extra_attributes
= null
openssl_csr_new() erzeugt einen neuen
CSR (Certificate Signing Request,
Zertifikats-Signierungsanfrage) basierend auf den Informationen, die mit
dem Parameter distinguished_names
angegeben werden.
Hinweis: Die ordnungsgemäße Ausführung dieser Funktion setzt die Installation einer gültigen openssl.cnf-Datei voraus. Mehr Information hierzu sind im Abschnitt Installation zu finden.
distinguished_names
Der Distinguished Name oder die Subjekt-Felder, die im Zertifikat verwendet werden sollen.
private_key
Der private_key
muss ein privater Schlüssel
sein, der vorher mit openssl_pkey_new() (oder einer
anderen Funktion aus der openssl_pkey-Familie) erzeugt wurde. Der
entsprechende öffentliche Teil des Schlüssels wird verwendet, um den
CSR zu signieren.
options
In der Standardeinstellung werden die Informationen für die Anfrage aus
der openssl.conf
ihres Systems verwendet. Sie können
einen Konfigurationsabsschnitt mit dem Schlüssel
config_section_section
des Arrays
options
setzen. Außerdem haben Sie die
Möglichkeit, eine alternative OpenSSL-Konfigurationsdatei anzugeben,
indem Sie den Wert des Schlüssels config
auf den
Pfad zu der Datei setzen, die Sie verwenden möchten. Die unten in der
Tabelle aufgeführten Schlüssel, soweit in
options
vorhanden, verhalten sich genau gleich
wie die entsprechenden Werte in der openssl.conf
options -Schlüssel |
Typ | openssl.conf -Entsprechung |
Beschreibung |
---|---|---|---|
digest_alg | string | default_md | Digest-Methode oder Signaturhash, üblicherweise eins von openssl_get_md_methods(). |
x509_extensions | string | x509_extensions | Bestimmt, welche Erweiterung verwendet werden soll, wenn ein x509-Zertifikat erzeugt werden soll. |
req_extensions | string | req_extensions | Bestimmt welche Erweiterung verwendet werden soll, wenn eine Zertifikats-Signierungsanfrage (CSR) erzeugt werden soll. |
private_key_bits | int | default_bits | Bestimmt wieviele Bits verwendet werden sollen, um einen privaten Schlüssel zu erzeugen. |
private_key_type | int | keine |
Bestimmt den Typ des privaten Schlüssels, der erzeugt werden soll.
Der Typ kann einer der folgenden sein:
OPENSSL_KEYTYPE_DSA ,
OPENSSL_KEYTYPE_DH ,
OPENSSL_KEYTYPE_RSA oder
OPENSSL_KEYTYPE_EC . Der Standardwert ist
OPENSSL_KEYTYPE_RSA .
|
encrypt_key | bool | encrypt_key | Soll ein exportierter Schlüssel (mit Passphrase) verschlüsselt werden? |
encrypt_key_cipher | int | keine | Eine der Ziffer-Konstanten. |
curve_name | string | none | Einer der openssl_get_curve_names(). |
config | string | N/A | Pfad zur eigenen alternativen openssl.conf-Datei. |
extra_attributes
extra_attributes
kann verwendet werden, um
zusätzliche Konfigurationsoptionen für den CSR
anzugeben. Sowohl distinguished_names
als auch
extra_attributes
sind assoziative Arrays, deren
Schlüssel zu OIDs konvertiert und auf den relevanten Teil der Anfrage
angewendet werden.
Gibt den CSR zurück. Bei einem Fehler wird false
zurückgegeben.
Version | Beschreibung |
---|---|
8.0.0 |
Bei Erfolg gibt diese Funktion nun eine
OpenSSLCertificateSigningRequest-Instanz zurück;
vorher wurde eine Ressource vom Typ OpenSSL X.509
CSR zurückgegeben.
|
8.0.0 |
private_key akzeptiert nun eine
OpenSSLAsymmetricKey-Instanz; vorher wurde eine
Ressource vom Typ OpenSSL-Schlüssel akzeptiert.
|
7.1.0 |
options unterstützt nun auch
curve_name .
|
Beispiel #1 Erzeugen eines selbstsignierten Zertifikats
<?php
// bei SSL-Zertifikate ist der commonName der zu sichernde Domain-Name
// bei S/MIME-Zertifikate ist der commonName der Eigentümer der E-Mail-Adresse
// die Felder location und identification beziehen sich auf den Eigentümer der
// zu sichernden Domain oder des E-Mail-Eigentümers
$dn = array(
"countryName" => "GB",
"stateOrProvinceName" => "Somerset",
"localityName" => "Glastonbury",
"organizationName" => "The Brain Room Limited",
"organizationalUnitName" => "PHP Documentation Team",
"commonName" => "Wez Furlong",
"emailAddress" => "wez@example.com"
);
// Erzeugen eines neuen privaten (und öffentlichen) Schlüsselpaars
$privkey = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));
// Erzeugen einer Zertifikats-Signierungsanfrage
$csr = openssl_csr_new($dn, $privkey, array('digest_alg' => 'sha256'));
// Erzeugen eines selbstsignierten Zertifikats, das für die Dauer von 365 Tagen
// gültig ist.
$x509 = openssl_csr_sign($csr, null, $privkey, $days=365, array('digest_alg' => 'sha256'));
// Sichern des privaten Schlüssels, des CSR und des selbstsignierten
// Zertifikats für die spätere Verwendung
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);
// Anzeigen aller aufgetretenen Fehler
while (($e = openssl_error_string()) !== false) {
echo $e . "\n";
}
?>
Beispiel #2 Erzeugen eines selbstsignierten ECC-Zertifikats (von PHP 7.1.0 an)
<?php
$subject = array(
"commonName" => "docs.php.net",
);
// Erzeugen eines neuen privaten (und öffentlichen) Schlüsselpaars
$private_key = openssl_pkey_new(array(
"private_key_type" => OPENSSL_KEYTYPE_EC,
"curve_name" => 'prime256v1',
));
// Erzeugen einer Zertifikats-Signierungsanfrage
$csr = openssl_csr_new($subject, $private_key, array('digest_alg' => 'sha384'));
// Erzeugen eines selbstsignierten EC-Zertifikats
$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.
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.
In the PHP example above it uses "UK" as the country name which is incorrect, the country name must be "GB"
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