• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • openssl_csr_new()

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

    生成一个 CSR

    说明

    openssl_csr_new(array $dn,resource &$privkey[,array $configargs[,array $extraattribs]]): mixed

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

    Note:必须安装有效的openssl.cnf以保证此函数正确运行。参考有关安装的说明以获得更多信息。

    参数

    $dn

    在证书中使用的专有名称或主题字段。

    $privkey

    $privkey应该被设置为由openssl_pkey_new()函数预先生成(或者以其他方式从openssl_pkey函数集中获得)的私钥。该密钥的相应公共部分将用于签署CSR.

    $configargs

    默认的,是通过你系统里的openssl.conf配置来初始化请求;您可以通过设置$configargsconfig_section_section项来指定配置文件部分。您还可以通过将config键的值设置为您想要使用的文件路径来指定另一个openssl配置文件。如果在$configargs中存在下列键,它们的行为就像在openssl.conf中一样。如下表所示:

    配置覆盖
    $configargstype等同于openssl.conf描述
    digest_algstringdefault_md摘要算法或签名哈希算法,通常是openssl_get_md_methods()之一。
    x509_extensionsstringx509_extensions选择在创建x509证书时应该使用哪些扩展
    req_extensionsstringreq_extensions创建CSR时,选择使用哪个扩展
    private_key_bitsintegerdefault_bits指定应该使用多少位来生成私钥
    private_key_typeintegernone选择在创建CSR时应该使用哪些扩展。可选值有OPENSSL_KEYTYPE_DSA,OPENSSL_KEYTYPE_DH,OPENSSL_KEYTYPE_RSAOPENSSL_KEYTYPE_EC.默认值是OPENSSL_KEYTYPE_RSA.
    encrypt_keybooleanencrypt_key是否应该对导出的密钥(带有密码短语)进行加密?
    encrypt_key_cipherintegernonecipher constants常量之一。
    curve_namestringnone要求PHP7.1+,openssl_get_curve_names()之一。
    configstringN/A自定义 openssl.conf 文件的路径。
    $extraattribs

    $extraattribs用于为CSR指定额外的配置选项。$dn$extraattribs都是关联数组它们的键被转换成OIDs,并应用到请求的相关部分。

    返回值

    成功,返回CSR 或者在失败时返回FALSE.

    范例

    创建一个自签名的证书

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

    在PHP 7.1+版本中创建一个自签名的ECC证书

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

    参见

    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
        );
    ?>
    
    In the PHP example above it uses "UK" as the country name which is incorrect, the country name must be "GB"
    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.
    For those of you using Debian-based systems, the openssl configuration file is at: /etc/ssl/openssl.cnf
    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
    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, [...])
    How in openssl_csr_new usign [, array configargs [, array extraattribs]] 
    because I am have add this extension to certificate
    /********************
    basicConstraints = critical,CA:TRUE,pathlen:0
    nsCertType = sslCA,emailCA,objCA
    **********************************/
    Rafal
    Is there some way to change the distinguished name using this function? I have tried adding overrides to the dn to configargs and extraattribs but this did not have an impact on the certificate.
    Example: A CSR is submitted and I want to change only the commonName (CN) before signing the certificate.