2012-04-05 6 views
5

È possibile esportare un certificato e una chiave privata in un file .pfx lungo il certificato con catena di certificati (certificato radice e/o intermedio), utilizzando il codice PHP openssl_pkcs12_export()?con openssl_pkcs12_export in PHP

UPDATE: Ho preso uno sguardo alla fonte per l'estensione openssl php, e ha scoperto che openssl_pkcs12_export() supporta 2 args diverse da quelle riportate nella documentazione, friendly_name e extracerts. Questo è da ext/openssl/openssl.c, controllare le linee 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 /* }}} */ 

tuttavia, io non sono molto sicuro come passare i certificati supplementari come argomenti ... qualche indizio?

fatemi sapere se è più facile leggibile senza i numeri di riga

risposta

5

Questo è a bug that has been brought up quasi due mesi fa.

Fortunatamente egli fornisce una patch di esempio per la documentazione:

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

Che cosa è $CAcert? Internamente viene passato a una funzione che è takes an array and turns it into a x509 e che rileva anche se si tratta di una matrice di certificati o di un singolo certificato. Ogni elemento dovrebbe essere una risorsa x509 se stai passando un array, o $ CAcert dovrebbe essere una singola risorsa se non stai passando un array. openssl_x509_read è probabilmente ciò che si desidera utilizzare qui in quanto restituisce il tipo di risorsa x509 previsto in $CAcert.

Alcuni dicono che tenere aggiornati i documenti è una delle parti più difficili del progetto PHP. Se non sei eccezionale con C e vuoi aiutare PHP a migliorare, è un buon punto di partenza.

+0

Bello, grazie. Quale tipo di variabile sarebbe $ CAcert essere in questo contesto? Solo una stringa o l'output di un PEM letto con openssl_x509_read() o cosa? Si prega di fornire un esempio se è possibile –

+0

@ MathiasR.Jessen Internamente '$ CAcert' viene passato a http://lxr.php.net/opengrok/xref/PHP_5_4/ext/openssl/openssl.c#1741 e questo rileva se è un array di certs o un singolo cert, ogni elemento dovrebbe essere un 'x509 Resource'. Non l'ho ancora implementato, ma sospetto molto che la tua ipotesi di 'openssl_x509_read' sia corretta in quanto restituisce quel tipo di risorsa. – Incognito

+1

Cool, proverò a implementare usando questo approccio e tornerò, grazie –