¿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
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 –
@ 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
Genial, intentaré implementar usando este enfoque y regresar, gracias –