2012-04-05 13 views
5

¿Es posible exportar un certificado y una clave privada a .pfx junto con con la cadena de certificados (root cert y/o intermedio), usando PHP openssl_pkcs12_export()?cadena de exportación con openssl_pkcs12_export en PHP

ACTUALIZACIÓN: he echado un vistazo a la fuente para la extensión openssl php, y encontró que openssl_pkcs12_export() soportes 2 argumentos distintos a los de la documentación, friendly_name y extracerts. Esto es de ext/openssl/openssl.c, echa un vistazo a las líneas 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 /* }}} */ 

Sin embargo, no estoy muy seguro de cómo pasar los certificados adicionales como argumentos ... alguna pista?

Avísame si es más fácil leer sin los números de línea

Respuesta

5

Ésta es a bug that has been brought up hace casi dos meses.

Afortunadamente se proporciona un programa de muestreo de la documentación:

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

¿Cuál es $CAcert? Internamente se pasa a una función que takes an array and turns it into a x509 y esa función también detecta si se trata de una matriz de cert o un solo certificado. Cada elemento debe ser un Recurso x509 si está pasando una matriz, o $ CAcert debe ser un único recurso si no está pasando una matriz. openssl_x509_read es probable que lo que desea utilizar aquí, ya que devuelve el tipo de recurso x509 que se espera en $CAcert.

Algunas personas dicen que mantener los documentos actualizados es una de las partes más difíciles del proyecto PHP. Si no eres bueno con C y quieres ayudar a PHP a mejorar, ese es un buen lugar para comenzar.

+0

Agradable, gracias. ¿Qué tipo de variable sería $ CAcert en este contexto? ¿Solo una cadena o el resultado de una lectura de PEM con openssl_x509_read() o qué? Proporcione un ejemplo si puede –

+0

@ MathiasR.Jessen Internamente '$ CAcert' se pasa a http://lxr.php.net/opengrok/xref/PHP_5_4/ext/openssl/openssl.c#1741 y esto detecta si se trata de una serie de certs o un solo cert, cada elemento debe ser un 'x509 Resource'. No he implementado esto antes, pero sospecho que su suposición de 'openssl_x509_read' es correcta ya que devuelve ese tipo de recurso. – Incognito

+1

Genial, intentaré implementar usando este enfoque y regresar, gracias –