цепочка экспорта с openssl_pkcs12_export в PHP

Можно ли экспортировать сертификат и закрытый ключ в .pfx вместе с цепочкой сертификатов (корневой сертификат и/или промежуточный), используя PHP openssl_pkcs12_export()?

ОБНОВЛЕНИЕ: я просмотрел исходный код расширения php openssl и обнаружил, что openssl_pkcs12_export() поддерживает 2 аргумента, кроме тех, что указаны в документации, friendly_name и extracerts. Это из 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 /* }}} */

однако я не совсем уверен, как передать дополнительные сертификаты в качестве аргументов... какие-нибудь подсказки?

Дайте мне знать, если это легче читать без номеров строк


person Mathias R. Jessen    schedule 05.04.2012    source источник


Ответы (1)


Это ошибка, обнаруженная почти два месяца назад.

К счастью, он предоставляет образец исправления для документации:

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

Что такое $CAcert? Внутри он передается функции, которая берет массив и его в x509, и эта функция также определяет, является ли это массивом сертификатов или одиночным сертификатом. Каждый элемент должен быть ресурсом x509, если вы передаете массив, или $CAcert должен быть отдельным ресурсом, если вы не передаете массив. openssl_x509_read, скорее всего, вы хотите использовать здесь, так как он возвращает тип ресурса x509, ожидаемый в $CAcert.

Некоторые говорят, что обновление документации — одна из самых сложных частей PHP-проекта. Если вы не очень хорошо разбираетесь в C и хотите помочь PHP стать лучше, это хорошее место для начала.

person Incognito    schedule 08.04.2012
comment
Хорошо, спасибо. Какой тип переменной будет $CAcert в этом контексте? Просто строка или вывод из PEM, прочитанного с помощью openssl_x509_read() или что? Если можно, приведите пример - person Mathias R. Jessen; 08.04.2012
comment
@MathiasR.Jessen Внутри $CAcert передается lxr.php .net/opengrok/xref/PHP_5_4/ext/openssl/openssl.c#1741, и это определяет, является ли это массивом сертификатов или одним сертификатом, каждый элемент должен быть x509 Resource. Я не реализовал это раньше, но я очень подозреваю, что ваше предположение о openssl_x509_read верно, поскольку оно возвращает этот тип ресурса. - person Incognito; 08.04.2012
comment
Круто, попробую реализовать с помощью этого подхода и вернусь, спасибо - person Mathias R. Jessen; 08.04.2012