PHP 8.4.0 RC4 available for testing

openssl_csr_new

(PHP 4 >= 4.2.0, PHP 5, PHP 7, PHP 8)

openssl_csr_newГенерирует CSR

Описание

openssl_csr_new(
    array $distinguished_names,
    #[\SensitiveParameter] ?OpenSSLAsymmetricKey &$private_key,
    ?array $options = null,
    ?array $extra_attributes = null
): OpenSSLCertificateSigningRequest|bool

Функция openssl_csr_new() создаёт новый CSR на основе информации, которую задали в параметре distinguished_names.

Замечание: Для корректной работы этой функции должен существовать правильный openssl.cnf. Для более подробной информации смотрите замечания под разделом установки.

Список параметров

distinguished_names

Уникальное имя (Distinguished Name) или поля субъекта для сертификата.

private_key

Для параметра private_key требуется установить закрытый ключ, который сгенерировала функция openssl_pkey_new() (или который вернула любая другая функция семейства openssl_pkey) или null. Если значение переменной null, то создаётся новый закрытый ключ на основе предоставленного параметра options и присваивается предоставленной переменной. Соответствующую открытую часть ключа функция использует, чтобы подписать CSR.

options

По умолчанию для инициализации запроса используется информация из системного файла openssl.conf. Можно указать секцию конфигурационного файла путём задания ключа config_section_section в параметре options. Можно также задать альтернативный файл конфигурации OpenSSL путём задания ключа config значением пути до него. Соответствие ключей, которые указали в параметре options, ключам из файла openssl.conf дают следующие параграфы описания.

Переопределение конфигурации
Ключ options Тип Соответствие в openssl.conf Описание
digest_alg string default_md Один из методов openssl_get_md_methods()
x509_extensions string x509_extensions Определяет, какое расширение должно использоваться, чтобы создать сертификат x509
req_extensions string req_extensions Определяет, какое расширение должно использоваться для создания CSR
private_key_bits int default_bits Задаёт, сколько бит должно использоваться для генерации закрытого ключа
private_key_type int none Задаёт тип создаваемого закрытого ключа. Одна из констант: OPENSSL_KEYTYPE_DSA, OPENSSL_KEYTYPE_DH, OPENSSL_KEYTYPE_RSA или OPENSSL_KEYTYPE_EC. По умолчанию OPENSSL_KEYTYPE_RSA.
encrypt_key bool encrypt_key Должен ли шифроваться (паролем) экспортируемый ключ?
encrypt_key_cipher int none Одна из констант шифров.
curve_name string none Одно из openssl_get_curve_names().
config string N/A Путь до альтернативного файла конфигурации openssl.conf.

extra_attributes

Параметр extra_attributes используется для указания дополнительных опций для CSR. И distinguished_names, и extra_attributes являются ассоциативными массивами, ключи которых преобразуются в OI-ы и применяются к соответствующим частям запроса.

Возвращаемые значения

Функция возвращает CSR в случае успешного выполнения, true, в случае успешного создания CSR, но при возникновении ошибки подписания или false, если возникла ошибка.

Список изменений

Версия Описание
8.0.0 csr теперь принимает экземпляр OpenSSLCertificateSigningRequest; ранее принимался ресурс (resource) типа OpenSSL X.509 CSR.
8.0.0 private_key теперь принимает экземпляр OpenSSLAsymmetricKey; ранее принимался ресурс (resource) типа OpenSSL key.
7.1.0 Параметр options теперь поддерживает curve_name.

Примеры

Пример #1 Создание самоподписанного сертификата

<?php
// для сервера сертификации SSL, commonName является доменным именем
// для сертификатов S/MIME, commonName является владельцем расположения адреса email
// и поля идентификации относятся к владельцу домена или электронной почты,
// подлежащим защите
$dn = array(
"countryName" => "GB",
"stateOrProvinceName" => "Somerset",
"localityName" => "Glastonbury",
"organizationName" => "The Brain Room Limited",
"organizationalUnitName" => "PHP Documentation Team",
"commonName" => "Wez Furlong",
"emailAddress" => "wez@example.com"
);

// Создание пары закрытый/открытый ключ
$privkey = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));

// Создание CSR
$csr = openssl_csr_new($dn, $privkey, array('digest_alg' => 'sha256'));

// Создание самоподписанного сертификата со сроком жизни 365 дней
$x509 = openssl_csr_sign($csr, null, $privkey, $days=365, array('digest_alg' => 'sha256'));

// Сохранение закрытого ключа, CSR и самоподписанного сертификата
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);

// Покажем возникшие ошибки, если они были
while (($e = openssl_error_string()) !== false) {
echo
$e . "\n";
}
?>

Пример #2 Создание самоподписанного ECC сертификата (начиная с PHP 7.1.0)

<?php
$subject
= array(
"commonName" => "docs.php.net",
);

// Создание пары закрытый/открытый ключ
$private_key = openssl_pkey_new(array(
"private_key_type" => OPENSSL_KEYTYPE_EC,
"curve_name" => 'prime256v1',
));

// Создание CSR
$csr = openssl_csr_new($subject, $private_key, array('digest_alg' => 'sha384'));

// Создание самоподписанного EC сертификата
$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');
?>

Смотрите также

  • openssl_csr_sign() - Подписывает CSR через другой сертификат (или им же) и создаёт сертификат

Добавить

Примечания пользователей 10 notes

up
12
The_Lost_One
15 years ago
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
);
?>
up
6
james at kirk dot com
9 years ago
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.
up
3
Anonymous
9 years ago
For those of you using Debian-based systems, the openssl configuration file is at: /etc/ssl/openssl.cnf
up
2
main ATT jokester DOTT fr
16 years ago
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.
up
1
Richard Lynch
11 years ago
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.
up
2
alex at nodex dot co dot uk
9 years ago
In the PHP example above it uses "UK" as the country name which is incorrect, the country name must be "GB"
up
0
Anonymous
19 years ago
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.
up
0
robertliu AT wiscore DOT com
19 years ago
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
);
?>
up
-1
dankybastard at hotmail
19 years ago
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, [...])
up
-3
@operator
7 years ago
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
To Top