2012-04-05 33 views
5

使用PHP的openssl_pkcs12_export()可以使用證書鏈(根證書和/或中間)將證書和私鑰導出到.pfx 沿在PHP中使用openssl_pkcs12_export導出鏈

UPDATE: 我已經採取了看看源的PHP OpenSSL的擴展,並發現openssl_pkcs12_export()支持比文檔,friendly_nameextracerts在那些其他2個ARGS。這是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 /* }}} */ 

不過,我不太清楚如何通過其他證書作爲參數...任何線索?

讓我知道,如果它更容易讀取,而不行號

回答

5

這是a bug that has been brought up近兩個月前。

值得慶幸的是,他提供的文檔樣本補丁:

$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?它在內部傳遞給一個函數takes an array and turns it into a x509,該函數還檢測它是否是一個證書數組或證書。如果您傳遞數組,則每個元素都應該是x509資源;如果不傳遞數組,則$ CAcert應該是單個資源。 openssl_x509_read可能是您想要在此處使用的,因爲它返回了$CAcert中預期的x509資源類型。

有人說保持文檔更新是PHP項目中最難的部分之一。如果你對C不太好,並希望幫助PHP變得更好,那麼這是一個很好的開始。

+0

不錯,謝謝。在這種情況下,$ CAcert會有哪些變量類型?只是一個字符串或PEM的輸出讀取openssl_x509_read()或什麼?請提供一個例子,如果你可以 – 2012-04-08 13:09:08

+0

@ MathiasR.Jessen內部'$ CAcert'被傳遞到http://lxr.php.net/opengrok/xref/PHP_5_4/ext/openssl/openssl.c#1741,這檢測它是否是一組證書或一個證書,每個元素應該是'x509資源'。我之前沒有實現過,但是我高度懷疑你對'openssl_x509_read'的假設是正確的,因爲它返回了這個資源類型。 – Incognito 2012-04-08 13:33:15

+1

酷,我會嘗試使用這種方法來實現並回來,謝謝 – 2012-04-08 13:42:33