експортна верига с openssl_pkcs12_export в PHP

Възможно ли е да експортирате сертификат и частен ключ към .pfx заедно с веригата сертификати (основен сертификат и/или междинен), като използвате 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