openssl_csr_new

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

openssl_csr_new生成证书签名请求 (CSR)

描述

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

openssl_csr_new() 根据 distinguished_names 提供的信息生成一个新的证书签名请求 (CSR)。

注意: 该函数需要一个有效的 openssl.cnf 文件才能正常工作。有关详细信息,请参阅 安装部分 中的说明。

参数

distinguished_names

证书中要使用的识别名称或主体字段。

private_key

private_key 应设置为之前由 openssl_pkey_new() 生成的私钥(或从其他 openssl_pkey 函数族中获取)。该私钥的公钥部分将用于签署 CSR。

options

默认情况下,系统 openssl.conf 中的信息将用于初始化请求;可以通过设置 optionsconfig_section_section 键来指定一个配置文件部分。还可以通过设置 config 键的值为要使用的文件的路径来指定一个备用的 openssl 配置文件。如果 options 中存在以下键,则它们的行为与 openssl.conf 中的等效项相同,如下表所示。

配置覆盖
options 类型 openssl.conf 等效项 描述
digest_alg 字符串 default_md 摘要方法或签名哈希,通常是 openssl_get_md_methods() 中的某个值
x509_extensions 字符串 x509_extensions 选择在创建 x509 证书时应使用哪些扩展
req_extensions 字符串 req_extensions 选择在创建 CSR 时应使用哪些扩展
private_key_bits 整数 default_bits 指定生成私钥时应使用的位数
private_key_type 整数 指定要创建的私钥类型。可以是 OPENSSL_KEYTYPE_DSAOPENSSL_KEYTYPE_DHOPENSSL_KEYTYPE_RSAOPENSSL_KEYTYPE_EC。默认值为 OPENSSL_KEYTYPE_RSA
encrypt_key 布尔值 encrypt_key 是否应加密导出的密钥(使用密码)?
encrypt_key_cipher 整数 一个 密码常量
curve_name 字符串 openssl_get_curve_names() 中的某个值。
config 字符串 N/A 您自己的备用 openssl.conf 文件的路径。

extra_attributes

extra_attributes 用于指定 CSR 的其他配置选项。distinguished_namesextra_attributes 都是关联数组,它们的键将转换为 OID 并应用于请求的相关部分。

返回值

返回 CSR,如果失败则返回 false

变更日志

版本 描述
8.0.0 成功时,此函数现在返回一个 OpenSSLCertificateSigningRequest 实例;以前返回的是类型为 OpenSSL X.509 CSR资源
8.0.0 private_key 现在接受一个 OpenSSLAsymmetricKey 实例;以前接受的是类型为 OpenSSL key资源
7.1.0 options 现在也支持 curve_name

示例

示例 #1 创建自签名证书

<?php
// 对于 SSL 服务器证书,commonName 是要保护的域名
// 对于 S/MIME 邮件证书,commonName 是邮件地址的拥有者
// 位置和标识字段是指要保护的域名或邮件主题的拥有者
$dn = array(
"countryName" => "GB",
"stateOrProvinceName" => "Somerset",
"localityName" => "Glastonbury",
"organizationName" => "The Brain Room Limited",
"organizationalUnitName" => "PHP Documentation Team",
"commonName" => "Wez Furlong",
"emailAddress" => "[email protected]"
);

// 生成新的私钥(和公钥)对
$privkey = openssl_pkey_new(array(
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
));

// 生成证书签名请求
$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 = 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 个注释

12
The_Lost_One
14 年前
不确定我遇到的“错误”(未记录的行为)是否对其他人也一样,但这则注释可能节省您数小时的痛苦调试时间
如果您无法使用 openssl_pkey_new() 或 openssl_csr_new() 生成新的私钥,您的脚本会在调用这些函数时挂起,并且如果您指定了“private_key_bits”参数,请确保将变量强制转换为 int 类型。我花了很长时间才注意到这一点。

<?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 // ---> 错误
'private_key_bits' => (int)$someVariable // ---> 正确
'private_key_bits' => 512 // ---> 显然正确
);
?>
6
james at kirk dot com
9 年前
如有疑问,请阅读 PHP 源代码!

$configargs 在幕后发生了什么方面相当不透明。也就是说,直到您真正查看“/ext/openssl/openssl.c”中的 php_openssl_parse_config()。

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);

这里我们可以看到,对于大多数输入,SET_OPTIONAL_STRING_ARG() 被调用,但对于“private_key_bits”,SET_OPTIONAL_LONG_ARG() 被调用。这两个调用都是扩展为强制执行预期输入类型的 C 宏。如果使用意外类型,生成的代码会忽略输入,不会发出警告/通知,而只使用配置文件中的默认值。这就是为什么使用字符串“private_key_bits”会导致意外行为的原因。

进一步检查同一函数中更早的初始化

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;
}

在另一个函数中的其他地方

/* 如果没有设置环境变量,则默认为“openssl.cnf” */
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));
}

这表明 $configargs 中的“config”会覆盖其他地方的任何默认设置。这实际上否定了文档中关于“注意:您需要安装有效的 openssl.cnf 才能使此函数正常运行。有关详细信息,请参阅安装部分中的注释”的评论。更准确的句子应该是“注意:您需要设置有效的 openssl.cnf 或使用 $configargs 指向有效的 openssl.cnf 文件才能使此函数正常运行”。

所有这些都表明,查看 PHP 源代码是真正了解实际发生情况的唯一方法。这样做可以节省时间和精力。
3
匿名
9 年前
对于使用基于 Debian 的系统的用户,openssl 配置文件位于:/etc/ssl/openssl.cnf
2
main ATT jokester DOTT fr
15 年前
要将“basicConstraints”设置为“critical,CA:TRUE”,您必须定义 configargs,但在 openssl_csr_sign() 函数中!

以下是我对签署“子”证书的代码示例

$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",
"组织单位名称" => "Enib 学生",
"通用名称" => "www.enib.fr",
"电子邮件地址" => "[email protected]"
);
$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");

然后,如果您想添加更多选项,您可以编辑"/etc/ssl/openssl.cnf" ssl 配置文件(debian 路径),并在 [v3_req] 标签后添加这些选项。
1
Richard Lynch
11 年前
似乎没有 openssl_csr_free 函数。

至少在这里没有。

如果它在源代码中,你可能可以直接调用它。

如果它不在源代码中,它可能应该存在。
2
alex at nodex dot co dot uk
9 年前
在上面的 PHP 示例中,它使用 "UK" 作为国家名称,这是不正确的,国家名称必须是 "GB"
0
匿名
19 年前
如果您收到以下错误

error:0D11A086:asn1 encoding routines:ASN1_mbstring_copy:string too short

请查看 $dn(可分辨名称)数组中的键值对。

如果一个值(例如 "organizationalUnitName" = "")被设置为空字符串,它将抛出上述错误。

通过从 $dn 中完全删除该数组元素,或使用空格 " " 代替空字符串来修复该错误。
0
robertliu AT wiscore DOT com
19 年前
我使用的是 PHP-4.3.11。
configargs--private_key_bits 的类型是 INTEGER,而不是字符串。
配置示例
<?php
$config
= array(
"digest_alg" => "sha1",
"private_key_bits" => 2048,
"private_key_type" => OPENSSL_KEYTYPE_DSA,
"encrypt_key" => false
);
?>
-1
dankybastard at hotmail
19 年前
正如您可能从示例中猜到的那样,文档中存在误导。openssl_csr_new 返回 CSR 资源或在失败时返回 FALSE。

mixed openssl_csr_new (assoc_array dn, resource_privkey, [...])
-3
@operator
7 年前
一条命令即可创建包含 4 个 SAN 子域的现代证书请求。
根据 RFC,您可以更改 CN(通用名称)和 subjectAltName。 当证书验证时,将在 CN 和 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