使用PHP中的openssl_pkcs12_export导出链

Mat*_*sen 5 php c openssl pfx pkcs#12

是否可以使用PHP 将证书和私钥与证书链(根证书和/或中间证)一起导出到.pfx openssl_pkcs12_export()

更新:我已经看了php openssl扩展的源代码,发现它openssl_pkcs12_export()支持2个args而不是文档中的那些,friendly_nameextracerts.这是来自ext/openssl/openssl.c,查看1914-1920行(PHP-5.4.0):

1878 /* {{{ proto bool openssl_pkcs12_export(mixed x509, string &out, mixed priv_key, string pass[, array args])
1879    Creates and exports a PKCS12 to a var */
1880 PHP_FUNCTION(openssl_pkcs12_export)
1881 {
1882         X509 * cert = NULL;                                                                                                                                                
1883         BIO * bio_out;
1884         PKCS12 * p12 = NULL;
1885         zval * zcert = NULL, *zout = NULL, *zpkey, *args = NULL;
1886         EVP_PKEY *priv_key = NULL;
1887         long certresource, keyresource;
1888         char * pass;
1889         int pass_len;
1890         char * friendly_name = NULL;
1891         zval ** item;
1892         STACK_OF(X509) *ca = NULL;
1893 
1894         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zzzs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE)
1895                 return;
1896 
1897         RETVAL_FALSE;
1898 
1899         cert = php_openssl_x509_from_zval(&zcert, 0, &certresource TSRMLS_CC);
1900         if (cert == NULL) {
1901                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
1902                 return;
1903         }
1904         priv_key = php_openssl_evp_from_zval(&zpkey, 0, "", 1, &keyresource TSRMLS_CC);
1905         if (priv_key == NULL) {
1906                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3");
1907                 goto cleanup;
1908         }
1909         if (cert && !X509_check_private_key(cert, priv_key)) {
1910                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to cert");
1911                 goto cleanup;
1912         }
1913 
1914         /* parse extra config from args array, promote this to an extra function */
1915         if (args && zend_hash_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name"), (void**)&item) == SUCCESS)
1916                 friendly_name = Z_STRVAL_PP(item);
1917 
1918         if (args && zend_hash_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts"), (void**)&item) == SUCCESS)
1919                 ca = php_array_to_X509_sk(item TSRMLS_CC);
1920         /* end parse extra config */
1921 
1922         p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
1923 
1924         bio_out = BIO_new(BIO_s_mem());
1925         if (i2d_PKCS12_bio(bio_out, p12))  {
1926                 BUF_MEM *bio_buf;
1927 
1928                 zval_dtor(zout);
1929                 BIO_get_mem_ptr(bio_out, &bio_buf);
1930                 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
1931 
1932                 RETVAL_TRUE;
1933         }
1934 
1935         BIO_free(bio_out);
1936         PKCS12_free(p12);
1937         php_sk_X509_free(ca);
1938 
1939 cleanup:
1940 
1941         if (keyresource == -1 && priv_key) {
1942                 EVP_PKEY_free(priv_key);
1943         }
1944         if (certresource == -1 && cert) {
1945                 X509_free(cert);
1946         }
1947 }
1948 /* }}} */
Run Code Online (Sandbox Code Playgroud)

但是,我不太确定如何将附加证书作为参数传递......任何线索?

如果没有行号,它是否更容易阅读,请告诉我

Inc*_*ito 5

这是近两个月前提出的一个错误.

值得庆幸的是,他为文档提供了一个示例补丁:

$args = array(
               'extracerts' => $CAcert,
               'friendly_name' => 'My signed cert by CA certificate'
              );
openssl_pkcs12_export($signed_csr, $cerificate_out, $private_key_resource, $passphrase, $args);
Run Code Online (Sandbox Code Playgroud)

什么是$CAcert?在内部,它被传递给一个函数,该函数接受一个数组并将其转换为x509,该函数还检测它是一个证书数组还是一个证书.如果要传递数组,则每个元素应为x509资源;如果未传递数组,则$ CAcert应为单个资源.openssl_x509_read很可能你想在这里使用它,因为它返回了预期的x509资源类型$CAcert.

有人说保持文档更新是PHP项目中最难的部分之一.如果你对C不好,并希望帮助PHP变得更好,那么这是一个好的开始.