PageRenderTime 65ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 2ms

/ext/openssl/openssl.c

http://github.com/php/php-src
C | 6595 lines | 5257 code | 868 blank | 470 comment | 1492 complexity | fc00f3cc45b888f17bb7d4e0a60efcd8 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Stig Venaas <venaas@php.net> |
  14. | Wez Furlong <wez@thebrainroom.com> |
  15. | Sascha Kettler <kettler@gmx.net> |
  16. | Pierre-Alain Joye <pierre@php.net> |
  17. | Marc Delling <delling@silpion.de> (PKCS12 functions) |
  18. | Jakub Zelenka <bukka@php.net> |
  19. +----------------------------------------------------------------------+
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include "config.h"
  23. #endif
  24. #include "php.h"
  25. #include "php_ini.h"
  26. #include "php_openssl.h"
  27. #include "zend_exceptions.h"
  28. /* PHP Includes */
  29. #include "ext/standard/file.h"
  30. #include "ext/standard/info.h"
  31. #include "ext/standard/php_fopen_wrappers.h"
  32. #include "ext/standard/md5.h"
  33. #include "ext/standard/base64.h"
  34. #ifdef PHP_WIN32
  35. # include "win32/winutil.h"
  36. #endif
  37. /* OpenSSL includes */
  38. #include <openssl/evp.h>
  39. #include <openssl/bn.h>
  40. #include <openssl/rsa.h>
  41. #include <openssl/dsa.h>
  42. #include <openssl/dh.h>
  43. #include <openssl/x509.h>
  44. #include <openssl/x509v3.h>
  45. #include <openssl/crypto.h>
  46. #include <openssl/pem.h>
  47. #include <openssl/err.h>
  48. #include <openssl/conf.h>
  49. #include <openssl/rand.h>
  50. #include <openssl/ssl.h>
  51. #include <openssl/pkcs12.h>
  52. /* Common */
  53. #include <time.h>
  54. #if (defined(PHP_WIN32) && defined(_MSC_VER) && _MSC_VER >= 1900)
  55. #define timezone _timezone /* timezone is called _timezone in LibC */
  56. #endif
  57. #define MIN_KEY_LENGTH 384
  58. #define OPENSSL_ALGO_SHA1 1
  59. #define OPENSSL_ALGO_MD5 2
  60. #define OPENSSL_ALGO_MD4 3
  61. #ifdef HAVE_OPENSSL_MD2_H
  62. #define OPENSSL_ALGO_MD2 4
  63. #endif
  64. #if PHP_OPENSSL_API_VERSION < 0x10100
  65. #define OPENSSL_ALGO_DSS1 5
  66. #endif
  67. #define OPENSSL_ALGO_SHA224 6
  68. #define OPENSSL_ALGO_SHA256 7
  69. #define OPENSSL_ALGO_SHA384 8
  70. #define OPENSSL_ALGO_SHA512 9
  71. #define OPENSSL_ALGO_RMD160 10
  72. #define DEBUG_SMIME 0
  73. #if !defined(OPENSSL_NO_EC) && defined(EVP_PKEY_EC)
  74. #define HAVE_EVP_PKEY_EC 1
  75. #endif
  76. #include "openssl_arginfo.h"
  77. ZEND_DECLARE_MODULE_GLOBALS(openssl)
  78. /* FIXME: Use the openssl constants instead of
  79. * enum. It is now impossible to match real values
  80. * against php constants. Also sorry to break the
  81. * enum principles here, BC...
  82. */
  83. enum php_openssl_key_type {
  84. OPENSSL_KEYTYPE_RSA,
  85. OPENSSL_KEYTYPE_DSA,
  86. OPENSSL_KEYTYPE_DH,
  87. OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA,
  88. #ifdef HAVE_EVP_PKEY_EC
  89. OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH +1
  90. #endif
  91. };
  92. enum php_openssl_cipher_type {
  93. PHP_OPENSSL_CIPHER_RC2_40,
  94. PHP_OPENSSL_CIPHER_RC2_128,
  95. PHP_OPENSSL_CIPHER_RC2_64,
  96. PHP_OPENSSL_CIPHER_DES,
  97. PHP_OPENSSL_CIPHER_3DES,
  98. PHP_OPENSSL_CIPHER_AES_128_CBC,
  99. PHP_OPENSSL_CIPHER_AES_192_CBC,
  100. PHP_OPENSSL_CIPHER_AES_256_CBC,
  101. PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40
  102. };
  103. /* {{{ openssl_module_entry
  104. */
  105. zend_module_entry openssl_module_entry = {
  106. STANDARD_MODULE_HEADER,
  107. "openssl",
  108. ext_functions,
  109. PHP_MINIT(openssl),
  110. PHP_MSHUTDOWN(openssl),
  111. NULL,
  112. NULL,
  113. PHP_MINFO(openssl),
  114. PHP_OPENSSL_VERSION,
  115. PHP_MODULE_GLOBALS(openssl),
  116. PHP_GINIT(openssl),
  117. PHP_GSHUTDOWN(openssl),
  118. NULL,
  119. STANDARD_MODULE_PROPERTIES_EX
  120. };
  121. /* }}} */
  122. #ifdef COMPILE_DL_OPENSSL
  123. ZEND_GET_MODULE(openssl)
  124. #endif
  125. /* {{{ OpenSSL compatibility functions and macros */
  126. #if PHP_OPENSSL_API_VERSION < 0x10100
  127. #define EVP_PKEY_get0_RSA(_pkey) _pkey->pkey.rsa
  128. #define EVP_PKEY_get0_DH(_pkey) _pkey->pkey.dh
  129. #define EVP_PKEY_get0_DSA(_pkey) _pkey->pkey.dsa
  130. #define EVP_PKEY_get0_EC_KEY(_pkey) _pkey->pkey.ec
  131. static int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
  132. {
  133. r->n = n;
  134. r->e = e;
  135. r->d = d;
  136. return 1;
  137. }
  138. static int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
  139. {
  140. r->p = p;
  141. r->q = q;
  142. return 1;
  143. }
  144. static int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
  145. {
  146. r->dmp1 = dmp1;
  147. r->dmq1 = dmq1;
  148. r->iqmp = iqmp;
  149. return 1;
  150. }
  151. static void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
  152. {
  153. *n = r->n;
  154. *e = r->e;
  155. *d = r->d;
  156. }
  157. static void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
  158. {
  159. *p = r->p;
  160. *q = r->q;
  161. }
  162. static void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp)
  163. {
  164. *dmp1 = r->dmp1;
  165. *dmq1 = r->dmq1;
  166. *iqmp = r->iqmp;
  167. }
  168. static void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
  169. {
  170. *p = dh->p;
  171. *q = dh->q;
  172. *g = dh->g;
  173. }
  174. static int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
  175. {
  176. dh->p = p;
  177. dh->q = q;
  178. dh->g = g;
  179. return 1;
  180. }
  181. static void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
  182. {
  183. *pub_key = dh->pub_key;
  184. *priv_key = dh->priv_key;
  185. }
  186. static int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
  187. {
  188. dh->pub_key = pub_key;
  189. dh->priv_key = priv_key;
  190. return 1;
  191. }
  192. static void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
  193. {
  194. *p = d->p;
  195. *q = d->q;
  196. *g = d->g;
  197. }
  198. int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
  199. {
  200. d->p = p;
  201. d->q = q;
  202. d->g = g;
  203. return 1;
  204. }
  205. static void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
  206. {
  207. *pub_key = d->pub_key;
  208. *priv_key = d->priv_key;
  209. }
  210. int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
  211. {
  212. d->pub_key = pub_key;
  213. d->priv_key = priv_key;
  214. return 1;
  215. }
  216. static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1)
  217. {
  218. return M_ASN1_STRING_data(asn1);
  219. }
  220. #if PHP_OPENSSL_API_VERSION < 0x10002
  221. static int X509_get_signature_nid(const X509 *x)
  222. {
  223. return OBJ_obj2nid(x->sig_alg->algorithm);
  224. }
  225. #endif
  226. #define OpenSSL_version SSLeay_version
  227. #define OPENSSL_VERSION SSLEAY_VERSION
  228. #define X509_getm_notBefore X509_get_notBefore
  229. #define X509_getm_notAfter X509_get_notAfter
  230. #define EVP_CIPHER_CTX_reset EVP_CIPHER_CTX_cleanup
  231. #endif
  232. /* }}} */
  233. /* number conversion flags checks */
  234. #define PHP_OPENSSL_CHECK_NUMBER_CONVERSION(_cond, _name) \
  235. do { \
  236. if (_cond) { \
  237. php_error_docref(NULL, E_WARNING, #_name" is too long"); \
  238. RETURN_FALSE; \
  239. } \
  240. } while(0)
  241. /* number conversion flags checks */
  242. #define PHP_OPENSSL_CHECK_NUMBER_CONVERSION_NORET(_cond, _name) \
  243. do { \
  244. if (_cond) { \
  245. php_error_docref(NULL, E_WARNING, #_name" is too long"); \
  246. return NULL; \
  247. } \
  248. } while(0)
  249. /* check if size_t can be safely casted to int */
  250. #define PHP_OPENSSL_CHECK_SIZE_T_TO_INT(_var, _name) \
  251. PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_SIZE_T_INT_OVFL(_var), _name)
  252. /* check if size_t can be safely casted to int */
  253. #define PHP_OPENSSL_CHECK_SIZE_T_TO_INT_NORET(_var, _name) \
  254. PHP_OPENSSL_CHECK_NUMBER_CONVERSION_NORET(ZEND_SIZE_T_INT_OVFL(_var), _name)
  255. /* check if size_t can be safely casted to unsigned int */
  256. #define PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(_var, _name) \
  257. PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_SIZE_T_UINT_OVFL(_var), _name)
  258. /* check if long can be safely casted to int */
  259. #define PHP_OPENSSL_CHECK_LONG_TO_INT(_var, _name) \
  260. PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_LONG_EXCEEDS_INT(_var), _name)
  261. /* check if long can be safely casted to int */
  262. #define PHP_OPENSSL_CHECK_LONG_TO_INT_NORET(_var, _name) \
  263. PHP_OPENSSL_CHECK_NUMBER_CONVERSION_NORET(ZEND_LONG_EXCEEDS_INT(_var), _name)
  264. /* {{{ php_openssl_store_errors */
  265. void php_openssl_store_errors()
  266. {
  267. struct php_openssl_errors *errors;
  268. int error_code = ERR_get_error();
  269. if (!error_code) {
  270. return;
  271. }
  272. if (!OPENSSL_G(errors)) {
  273. OPENSSL_G(errors) = pecalloc(1, sizeof(struct php_openssl_errors), 1);
  274. }
  275. errors = OPENSSL_G(errors);
  276. do {
  277. errors->top = (errors->top + 1) % ERR_NUM_ERRORS;
  278. if (errors->top == errors->bottom) {
  279. errors->bottom = (errors->bottom + 1) % ERR_NUM_ERRORS;
  280. }
  281. errors->buffer[errors->top] = error_code;
  282. } while ((error_code = ERR_get_error()));
  283. }
  284. /* }}} */
  285. static int le_key;
  286. static int le_x509;
  287. static int le_csr;
  288. static int ssl_stream_data_index;
  289. int php_openssl_get_x509_list_id(void) /* {{{ */
  290. {
  291. return le_x509;
  292. }
  293. /* }}} */
  294. /* {{{ resource destructors */
  295. static void php_openssl_pkey_free(zend_resource *rsrc)
  296. {
  297. EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr;
  298. assert(pkey != NULL);
  299. EVP_PKEY_free(pkey);
  300. }
  301. static void php_openssl_x509_free(zend_resource *rsrc)
  302. {
  303. X509 *x509 = (X509 *)rsrc->ptr;
  304. X509_free(x509);
  305. }
  306. static void php_openssl_csr_free(zend_resource *rsrc)
  307. {
  308. X509_REQ * csr = (X509_REQ*)rsrc->ptr;
  309. X509_REQ_free(csr);
  310. }
  311. /* }}} */
  312. /* {{{ openssl open_basedir check */
  313. inline static int php_openssl_open_base_dir_chk(char *filename)
  314. {
  315. if (php_check_open_basedir(filename)) {
  316. return -1;
  317. }
  318. return 0;
  319. }
  320. /* }}} */
  321. php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl)
  322. {
  323. return (php_stream*)SSL_get_ex_data(ssl, ssl_stream_data_index);
  324. }
  325. int php_openssl_get_ssl_stream_data_index()
  326. {
  327. return ssl_stream_data_index;
  328. }
  329. /* openssl -> PHP "bridging" */
  330. /* true global; readonly after module startup */
  331. static char default_ssl_conf_filename[MAXPATHLEN];
  332. struct php_x509_request { /* {{{ */
  333. LHASH_OF(CONF_VALUE) * global_config; /* Global SSL config */
  334. LHASH_OF(CONF_VALUE) * req_config; /* SSL config for this request */
  335. const EVP_MD * md_alg;
  336. const EVP_MD * digest;
  337. char * section_name,
  338. * config_filename,
  339. * digest_name,
  340. * extensions_section,
  341. * request_extensions_section;
  342. int priv_key_bits;
  343. int priv_key_type;
  344. int priv_key_encrypt;
  345. #ifdef HAVE_EVP_PKEY_EC
  346. int curve_name;
  347. #endif
  348. EVP_PKEY * priv_key;
  349. const EVP_CIPHER * priv_key_encrypt_cipher;
  350. };
  351. /* }}} */
  352. static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval);
  353. static EVP_PKEY * php_openssl_evp_from_zval(
  354. zval * val, int public_key, char *passphrase, size_t passphrase_len,
  355. int makeresource, zend_resource **resourceval);
  356. static int php_openssl_is_private_key(EVP_PKEY* pkey);
  357. static X509_STORE * php_openssl_setup_verify(zval * calist);
  358. static STACK_OF(X509) * php_openssl_load_all_certs_from_file(char *certfile);
  359. static X509_REQ * php_openssl_csr_from_zval(zval * val, int makeresource, zend_resource ** resourceval);
  360. static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req);
  361. static void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname) /* {{{ */
  362. {
  363. zval *data;
  364. zval subitem, tmp;
  365. int i;
  366. char *sname;
  367. int nid;
  368. X509_NAME_ENTRY * ne;
  369. ASN1_STRING * str = NULL;
  370. ASN1_OBJECT * obj;
  371. if (key != NULL) {
  372. array_init(&subitem);
  373. } else {
  374. ZVAL_COPY_VALUE(&subitem, val);
  375. }
  376. for (i = 0; i < X509_NAME_entry_count(name); i++) {
  377. const unsigned char *to_add = NULL;
  378. int to_add_len = 0;
  379. unsigned char *to_add_buf = NULL;
  380. ne = X509_NAME_get_entry(name, i);
  381. obj = X509_NAME_ENTRY_get_object(ne);
  382. nid = OBJ_obj2nid(obj);
  383. if (shortname) {
  384. sname = (char *) OBJ_nid2sn(nid);
  385. } else {
  386. sname = (char *) OBJ_nid2ln(nid);
  387. }
  388. str = X509_NAME_ENTRY_get_data(ne);
  389. if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) {
  390. /* ASN1_STRING_to_UTF8(3): The converted data is copied into a newly allocated buffer */
  391. to_add_len = ASN1_STRING_to_UTF8(&to_add_buf, str);
  392. to_add = to_add_buf;
  393. } else {
  394. /* ASN1_STRING_get0_data(3): Since this is an internal pointer it should not be freed or modified in any way */
  395. to_add = ASN1_STRING_get0_data(str);
  396. to_add_len = ASN1_STRING_length(str);
  397. }
  398. if (to_add_len != -1) {
  399. if ((data = zend_hash_str_find(Z_ARRVAL(subitem), sname, strlen(sname))) != NULL) {
  400. if (Z_TYPE_P(data) == IS_ARRAY) {
  401. add_next_index_stringl(data, (const char *)to_add, to_add_len);
  402. } else if (Z_TYPE_P(data) == IS_STRING) {
  403. array_init(&tmp);
  404. add_next_index_str(&tmp, zend_string_copy(Z_STR_P(data)));
  405. add_next_index_stringl(&tmp, (const char *)to_add, to_add_len);
  406. zend_hash_str_update(Z_ARRVAL(subitem), sname, strlen(sname), &tmp);
  407. }
  408. } else {
  409. /* it might be better to expand it and pass zval from ZVAL_STRING
  410. * to zend_symtable_str_update so we do not silently drop const
  411. * but we need a test to cover this part first */
  412. add_assoc_stringl(&subitem, sname, (char *)to_add, to_add_len);
  413. }
  414. } else {
  415. php_openssl_store_errors();
  416. }
  417. if (to_add_buf != NULL) {
  418. OPENSSL_free(to_add_buf);
  419. }
  420. }
  421. if (key != NULL) {
  422. zend_hash_str_update(Z_ARRVAL_P(val), key, strlen(key), &subitem);
  423. }
  424. }
  425. /* }}} */
  426. static void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) /* {{{ */
  427. {
  428. add_assoc_stringl(val, key, (char *)str->data, str->length);
  429. }
  430. /* }}} */
  431. static time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr) /* {{{ */
  432. {
  433. /*
  434. This is how the time string is formatted:
  435. snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
  436. ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
  437. */
  438. time_t ret;
  439. struct tm thetime;
  440. char * strbuf;
  441. char * thestr;
  442. long gmadjust = 0;
  443. size_t timestr_len;
  444. if (ASN1_STRING_type(timestr) != V_ASN1_UTCTIME && ASN1_STRING_type(timestr) != V_ASN1_GENERALIZEDTIME) {
  445. php_error_docref(NULL, E_WARNING, "Illegal ASN1 data type for timestamp");
  446. return (time_t)-1;
  447. }
  448. timestr_len = (size_t)ASN1_STRING_length(timestr);
  449. if (timestr_len != strlen((const char *)ASN1_STRING_get0_data(timestr))) {
  450. php_error_docref(NULL, E_WARNING, "Illegal length in timestamp");
  451. return (time_t)-1;
  452. }
  453. if (timestr_len < 13 && timestr_len != 11) {
  454. php_error_docref(NULL, E_WARNING, "Unable to parse time string %s correctly", timestr->data);
  455. return (time_t)-1;
  456. }
  457. if (ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME && timestr_len < 15) {
  458. php_error_docref(NULL, E_WARNING, "Unable to parse time string %s correctly", timestr->data);
  459. return (time_t)-1;
  460. }
  461. strbuf = estrdup((const char *)ASN1_STRING_get0_data(timestr));
  462. memset(&thetime, 0, sizeof(thetime));
  463. /* we work backwards so that we can use atoi more easily */
  464. thestr = strbuf + timestr_len - 3;
  465. if (timestr_len == 11) {
  466. thetime.tm_sec = 0;
  467. } else {
  468. thetime.tm_sec = atoi(thestr);
  469. *thestr = '\0';
  470. thestr -= 2;
  471. }
  472. thetime.tm_min = atoi(thestr);
  473. *thestr = '\0';
  474. thestr -= 2;
  475. thetime.tm_hour = atoi(thestr);
  476. *thestr = '\0';
  477. thestr -= 2;
  478. thetime.tm_mday = atoi(thestr);
  479. *thestr = '\0';
  480. thestr -= 2;
  481. thetime.tm_mon = atoi(thestr)-1;
  482. *thestr = '\0';
  483. if( ASN1_STRING_type(timestr) == V_ASN1_UTCTIME ) {
  484. thestr -= 2;
  485. thetime.tm_year = atoi(thestr);
  486. if (thetime.tm_year < 68) {
  487. thetime.tm_year += 100;
  488. }
  489. } else if( ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME ) {
  490. thestr -= 4;
  491. thetime.tm_year = atoi(thestr) - 1900;
  492. }
  493. thetime.tm_isdst = -1;
  494. ret = mktime(&thetime);
  495. #if HAVE_STRUCT_TM_TM_GMTOFF
  496. gmadjust = thetime.tm_gmtoff;
  497. #else
  498. /*
  499. ** If correcting for daylight savings time, we set the adjustment to
  500. ** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and
  501. ** set the adjustment to the main timezone + 3600 seconds.
  502. */
  503. gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone);
  504. #endif
  505. ret += gmadjust;
  506. efree(strbuf);
  507. return ret;
  508. }
  509. /* }}} */
  510. static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH_OF(CONF_VALUE) * config) /* {{{ */
  511. {
  512. X509V3_CTX ctx;
  513. X509V3_set_ctx_test(&ctx);
  514. X509V3_set_conf_lhash(&ctx, config);
  515. if (!X509V3_EXT_add_conf(config, &ctx, (char *)section, NULL)) {
  516. php_openssl_store_errors();
  517. php_error_docref(NULL, E_WARNING, "Error loading %s section %s of %s",
  518. section_label,
  519. section,
  520. config_filename);
  521. return FAILURE;
  522. }
  523. return SUCCESS;
  524. }
  525. /* }}} */
  526. static int php_openssl_add_oid_section(struct php_x509_request * req) /* {{{ */
  527. {
  528. char * str;
  529. STACK_OF(CONF_VALUE) * sktmp;
  530. CONF_VALUE * cnf;
  531. int i;
  532. str = CONF_get_string(req->req_config, NULL, "oid_section");
  533. if (str == NULL) {
  534. php_openssl_store_errors();
  535. return SUCCESS;
  536. }
  537. sktmp = CONF_get_section(req->req_config, str);
  538. if (sktmp == NULL) {
  539. php_openssl_store_errors();
  540. php_error_docref(NULL, E_WARNING, "Problem loading oid section %s", str);
  541. return FAILURE;
  542. }
  543. for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
  544. cnf = sk_CONF_VALUE_value(sktmp, i);
  545. if (OBJ_sn2nid(cnf->name) == NID_undef && OBJ_ln2nid(cnf->name) == NID_undef &&
  546. OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
  547. php_openssl_store_errors();
  548. php_error_docref(NULL, E_WARNING, "Problem creating object %s=%s", cnf->name, cnf->value);
  549. return FAILURE;
  550. }
  551. }
  552. return SUCCESS;
  553. }
  554. /* }}} */
  555. #define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req))
  556. #define PHP_SSL_REQ_DISPOSE(req) php_openssl_dispose_config(req)
  557. #define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval)
  558. #define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \
  559. req->config_filename, req->var, req->req_config) == FAILURE) return FAILURE
  560. #define SET_OPTIONAL_STRING_ARG(key, varname, defval) \
  561. do { \
  562. if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), key, sizeof(key)-1)) != NULL && Z_TYPE_P(item) == IS_STRING) { \
  563. varname = Z_STRVAL_P(item); \
  564. } else { \
  565. varname = defval; \
  566. if (varname == NULL) { \
  567. php_openssl_store_errors(); \
  568. } \
  569. } \
  570. } while(0)
  571. #define SET_OPTIONAL_LONG_ARG(key, varname, defval) \
  572. if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), key, sizeof(key)-1)) != NULL && Z_TYPE_P(item) == IS_LONG) \
  573. varname = (int)Z_LVAL_P(item); \
  574. else \
  575. varname = defval
  576. static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo);
  577. /* {{{ strip line endings from spkac */
  578. static int php_openssl_spki_cleanup(const char *src, char *dest)
  579. {
  580. int removed = 0;
  581. while (*src) {
  582. if (*src != '\n' && *src != '\r') {
  583. *dest++ = *src;
  584. } else {
  585. ++removed;
  586. }
  587. ++src;
  588. }
  589. *dest = 0;
  590. return removed;
  591. }
  592. /* }}} */
  593. static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args) /* {{{ */
  594. {
  595. char * str;
  596. zval * item;
  597. SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename);
  598. SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req");
  599. req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL);
  600. if (req->global_config == NULL) {
  601. php_openssl_store_errors();
  602. }
  603. req->req_config = CONF_load(NULL, req->config_filename, NULL);
  604. if (req->req_config == NULL) {
  605. php_openssl_store_errors();
  606. return FAILURE;
  607. }
  608. /* read in the oids */
  609. str = CONF_get_string(req->req_config, NULL, "oid_file");
  610. if (str == NULL) {
  611. php_openssl_store_errors();
  612. } else if (!php_openssl_open_base_dir_chk(str)) {
  613. BIO *oid_bio = BIO_new_file(str, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
  614. if (oid_bio) {
  615. OBJ_create_objects(oid_bio);
  616. BIO_free(oid_bio);
  617. php_openssl_store_errors();
  618. }
  619. }
  620. if (php_openssl_add_oid_section(req) == FAILURE) {
  621. return FAILURE;
  622. }
  623. SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
  624. CONF_get_string(req->req_config, req->section_name, "default_md"));
  625. SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
  626. CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
  627. SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
  628. CONF_get_string(req->req_config, req->section_name, "req_extensions"));
  629. SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits,
  630. CONF_get_number(req->req_config, req->section_name, "default_bits"));
  631. SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT);
  632. if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key")-1)) != NULL) {
  633. req->priv_key_encrypt = Z_TYPE_P(item) == IS_TRUE ? 1 : 0;
  634. } else {
  635. str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key");
  636. if (str == NULL) {
  637. str = CONF_get_string(req->req_config, req->section_name, "encrypt_key");
  638. /* it is sure that there are some errors as str was NULL for encrypt_rsa_key */
  639. php_openssl_store_errors();
  640. }
  641. if (str != NULL && strcmp(str, "no") == 0) {
  642. req->priv_key_encrypt = 0;
  643. } else {
  644. req->priv_key_encrypt = 1;
  645. }
  646. }
  647. if (req->priv_key_encrypt &&
  648. optional_args &&
  649. (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key_cipher", sizeof("encrypt_key_cipher")-1)) != NULL &&
  650. Z_TYPE_P(item) == IS_LONG
  651. ) {
  652. zend_long cipher_algo = Z_LVAL_P(item);
  653. const EVP_CIPHER* cipher = php_openssl_get_evp_cipher_from_algo(cipher_algo);
  654. if (cipher == NULL) {
  655. php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm for private key.");
  656. return FAILURE;
  657. } else {
  658. req->priv_key_encrypt_cipher = cipher;
  659. }
  660. } else {
  661. req->priv_key_encrypt_cipher = NULL;
  662. }
  663. /* digest alg */
  664. if (req->digest_name == NULL) {
  665. req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md");
  666. }
  667. if (req->digest_name != NULL) {
  668. req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name);
  669. } else {
  670. php_openssl_store_errors();
  671. }
  672. if (req->md_alg == NULL) {
  673. req->md_alg = req->digest = EVP_sha1();
  674. php_openssl_store_errors();
  675. }
  676. PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
  677. #ifdef HAVE_EVP_PKEY_EC
  678. /* set the ec group curve name */
  679. req->curve_name = NID_undef;
  680. if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "curve_name", sizeof("curve_name")-1)) != NULL
  681. && Z_TYPE_P(item) == IS_STRING) {
  682. req->curve_name = OBJ_sn2nid(Z_STRVAL_P(item));
  683. if (req->curve_name == NID_undef) {
  684. php_error_docref(NULL, E_WARNING, "Unknown elliptic curve (short) name %s", Z_STRVAL_P(item));
  685. return FAILURE;
  686. }
  687. }
  688. #endif
  689. /* set the string mask */
  690. str = CONF_get_string(req->req_config, req->section_name, "string_mask");
  691. if (str == NULL) {
  692. php_openssl_store_errors();
  693. } else if (!ASN1_STRING_set_default_mask_asc(str)) {
  694. php_error_docref(NULL, E_WARNING, "Invalid global string mask setting %s", str);
  695. return FAILURE;
  696. }
  697. PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section);
  698. return SUCCESS;
  699. }
  700. /* }}} */
  701. static void php_openssl_dispose_config(struct php_x509_request * req) /* {{{ */
  702. {
  703. if (req->priv_key) {
  704. EVP_PKEY_free(req->priv_key);
  705. req->priv_key = NULL;
  706. }
  707. if (req->global_config) {
  708. CONF_free(req->global_config);
  709. req->global_config = NULL;
  710. }
  711. if (req->req_config) {
  712. CONF_free(req->req_config);
  713. req->req_config = NULL;
  714. }
  715. }
  716. /* }}} */
  717. #if defined(PHP_WIN32) || PHP_OPENSSL_API_VERSION >= 0x10100
  718. #define PHP_OPENSSL_RAND_ADD_TIME() ((void) 0)
  719. #else
  720. #define PHP_OPENSSL_RAND_ADD_TIME() php_openssl_rand_add_timeval()
  721. static inline void php_openssl_rand_add_timeval() /* {{{ */
  722. {
  723. struct timeval tv;
  724. gettimeofday(&tv, NULL);
  725. RAND_add(&tv, sizeof(tv), 0.0);
  726. }
  727. /* }}} */
  728. #endif
  729. static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded) /* {{{ */
  730. {
  731. char buffer[MAXPATHLEN];
  732. *egdsocket = 0;
  733. *seeded = 0;
  734. if (file == NULL) {
  735. file = RAND_file_name(buffer, sizeof(buffer));
  736. #ifdef HAVE_RAND_EGD
  737. } else if (RAND_egd(file) > 0) {
  738. /* if the given filename is an EGD socket, don't
  739. * write anything back to it */
  740. *egdsocket = 1;
  741. return SUCCESS;
  742. #endif
  743. }
  744. if (file == NULL || !RAND_load_file(file, -1)) {
  745. if (RAND_status() == 0) {
  746. php_openssl_store_errors();
  747. php_error_docref(NULL, E_WARNING, "Unable to load random state; not enough random data!");
  748. return FAILURE;
  749. }
  750. return FAILURE;
  751. }
  752. *seeded = 1;
  753. return SUCCESS;
  754. }
  755. /* }}} */
  756. static int php_openssl_write_rand_file(const char * file, int egdsocket, int seeded) /* {{{ */
  757. {
  758. char buffer[MAXPATHLEN];
  759. if (egdsocket || !seeded) {
  760. /* if we did not manage to read the seed file, we should not write
  761. * a low-entropy seed file back */
  762. return FAILURE;
  763. }
  764. if (file == NULL) {
  765. file = RAND_file_name(buffer, sizeof(buffer));
  766. }
  767. PHP_OPENSSL_RAND_ADD_TIME();
  768. if (file == NULL || !RAND_write_file(file)) {
  769. php_openssl_store_errors();
  770. php_error_docref(NULL, E_WARNING, "Unable to write random state");
  771. return FAILURE;
  772. }
  773. return SUCCESS;
  774. }
  775. /* }}} */
  776. static EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo) { /* {{{ */
  777. EVP_MD *mdtype;
  778. switch (algo) {
  779. case OPENSSL_ALGO_SHA1:
  780. mdtype = (EVP_MD *) EVP_sha1();
  781. break;
  782. case OPENSSL_ALGO_MD5:
  783. mdtype = (EVP_MD *) EVP_md5();
  784. break;
  785. case OPENSSL_ALGO_MD4:
  786. mdtype = (EVP_MD *) EVP_md4();
  787. break;
  788. #ifdef HAVE_OPENSSL_MD2_H
  789. case OPENSSL_ALGO_MD2:
  790. mdtype = (EVP_MD *) EVP_md2();
  791. break;
  792. #endif
  793. #if PHP_OPENSSL_API_VERSION < 0x10100
  794. case OPENSSL_ALGO_DSS1:
  795. mdtype = (EVP_MD *) EVP_dss1();
  796. break;
  797. #endif
  798. case OPENSSL_ALGO_SHA224:
  799. mdtype = (EVP_MD *) EVP_sha224();
  800. break;
  801. case OPENSSL_ALGO_SHA256:
  802. mdtype = (EVP_MD *) EVP_sha256();
  803. break;
  804. case OPENSSL_ALGO_SHA384:
  805. mdtype = (EVP_MD *) EVP_sha384();
  806. break;
  807. case OPENSSL_ALGO_SHA512:
  808. mdtype = (EVP_MD *) EVP_sha512();
  809. break;
  810. case OPENSSL_ALGO_RMD160:
  811. mdtype = (EVP_MD *) EVP_ripemd160();
  812. break;
  813. default:
  814. return NULL;
  815. break;
  816. }
  817. return mdtype;
  818. }
  819. /* }}} */
  820. static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo) { /* {{{ */
  821. switch (algo) {
  822. #ifndef OPENSSL_NO_RC2
  823. case PHP_OPENSSL_CIPHER_RC2_40:
  824. return EVP_rc2_40_cbc();
  825. break;
  826. case PHP_OPENSSL_CIPHER_RC2_64:
  827. return EVP_rc2_64_cbc();
  828. break;
  829. case PHP_OPENSSL_CIPHER_RC2_128:
  830. return EVP_rc2_cbc();
  831. break;
  832. #endif
  833. #ifndef OPENSSL_NO_DES
  834. case PHP_OPENSSL_CIPHER_DES:
  835. return EVP_des_cbc();
  836. break;
  837. case PHP_OPENSSL_CIPHER_3DES:
  838. return EVP_des_ede3_cbc();
  839. break;
  840. #endif
  841. #ifndef OPENSSL_NO_AES
  842. case PHP_OPENSSL_CIPHER_AES_128_CBC:
  843. return EVP_aes_128_cbc();
  844. break;
  845. case PHP_OPENSSL_CIPHER_AES_192_CBC:
  846. return EVP_aes_192_cbc();
  847. break;
  848. case PHP_OPENSSL_CIPHER_AES_256_CBC:
  849. return EVP_aes_256_cbc();
  850. break;
  851. #endif
  852. default:
  853. return NULL;
  854. break;
  855. }
  856. }
  857. /* }}} */
  858. /* {{{ INI Settings */
  859. PHP_INI_BEGIN()
  860. PHP_INI_ENTRY("openssl.cafile", NULL, PHP_INI_PERDIR, NULL)
  861. PHP_INI_ENTRY("openssl.capath", NULL, PHP_INI_PERDIR, NULL)
  862. PHP_INI_END()
  863. /* }}} */
  864. /* {{{ PHP_MINIT_FUNCTION
  865. */
  866. PHP_MINIT_FUNCTION(openssl)
  867. {
  868. char * config_filename;
  869. le_key = zend_register_list_destructors_ex(php_openssl_pkey_free, NULL, "OpenSSL key", module_number);
  870. le_x509 = zend_register_list_destructors_ex(php_openssl_x509_free, NULL, "OpenSSL X.509", module_number);
  871. le_csr = zend_register_list_destructors_ex(php_openssl_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
  872. #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
  873. OPENSSL_config(NULL);
  874. SSL_library_init();
  875. OpenSSL_add_all_ciphers();
  876. OpenSSL_add_all_digests();
  877. OpenSSL_add_all_algorithms();
  878. #if !defined(OPENSSL_NO_AES) && defined(EVP_CIPH_CCM_MODE) && OPENSSL_VERSION_NUMBER < 0x100020000
  879. EVP_add_cipher(EVP_aes_128_ccm());
  880. EVP_add_cipher(EVP_aes_192_ccm());
  881. EVP_add_cipher(EVP_aes_256_ccm());
  882. #endif
  883. SSL_load_error_strings();
  884. #else
  885. OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
  886. #endif
  887. /* register a resource id number with OpenSSL so that we can map SSL -> stream structures in
  888. * OpenSSL callbacks */
  889. ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);
  890. REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT);
  891. REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT);
  892. /* purposes for cert purpose checking */
  893. REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT);
  894. REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
  895. REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
  896. REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT);
  897. REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT);
  898. REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT);
  899. #ifdef X509_PURPOSE_ANY
  900. REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT);
  901. #endif
  902. /* signature algorithm constants */
  903. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT);
  904. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT);
  905. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD4", OPENSSL_ALGO_MD4, CONST_CS|CONST_PERSISTENT);
  906. #ifdef HAVE_OPENSSL_MD2_H
  907. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_CS|CONST_PERSISTENT);
  908. #endif
  909. #if PHP_OPENSSL_API_VERSION < 0x10100
  910. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT);
  911. #endif
  912. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA224", OPENSSL_ALGO_SHA224, CONST_CS|CONST_PERSISTENT);
  913. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA256", OPENSSL_ALGO_SHA256, CONST_CS|CONST_PERSISTENT);
  914. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA384", OPENSSL_ALGO_SHA384, CONST_CS|CONST_PERSISTENT);
  915. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA512", OPENSSL_ALGO_SHA512, CONST_CS|CONST_PERSISTENT);
  916. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_RMD160", OPENSSL_ALGO_RMD160, CONST_CS|CONST_PERSISTENT);
  917. /* flags for S/MIME */
  918. REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT);
  919. REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT);
  920. REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT);
  921. REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT);
  922. REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT);
  923. REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT);
  924. REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT);
  925. REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
  926. REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
  927. REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
  928. REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
  929. REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
  930. REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
  931. /* Informational stream wrapper constants */
  932. REGISTER_STRING_CONSTANT("OPENSSL_DEFAULT_STREAM_CIPHERS", OPENSSL_DEFAULT_STREAM_CIPHERS, CONST_CS|CONST_PERSISTENT);
  933. /* Ciphers */
  934. #ifndef OPENSSL_NO_RC2
  935. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
  936. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT);
  937. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT);
  938. #endif
  939. #ifndef OPENSSL_NO_DES
  940. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT);
  941. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT);
  942. #endif
  943. #ifndef OPENSSL_NO_AES
  944. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_128_CBC", PHP_OPENSSL_CIPHER_AES_128_CBC, CONST_CS|CONST_PERSISTENT);
  945. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_192_CBC", PHP_OPENSSL_CIPHER_AES_192_CBC, CONST_CS|CONST_PERSISTENT);
  946. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_256_CBC", PHP_OPENSSL_CIPHER_AES_256_CBC, CONST_CS|CONST_PERSISTENT);
  947. #endif
  948. /* Values for key types */
  949. REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT);
  950. #ifndef NO_DSA
  951. REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT);
  952. #endif
  953. REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT);
  954. #ifdef HAVE_EVP_PKEY_EC
  955. REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT);
  956. #endif
  957. REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_CS|CONST_PERSISTENT);
  958. REGISTER_LONG_CONSTANT("OPENSSL_ZERO_PADDING", OPENSSL_ZERO_PADDING, CONST_CS|CONST_PERSISTENT);
  959. REGISTER_LONG_CONSTANT("OPENSSL_DONT_ZERO_PAD_KEY", OPENSSL_DONT_ZERO_PAD_KEY, CONST_CS|CONST_PERSISTENT);
  960. #ifndef OPENSSL_NO_TLSEXT
  961. /* SNI support included */
  962. REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT);
  963. #endif
  964. /* Determine default SSL configuration file */
  965. config_filename = getenv("OPENSSL_CONF");
  966. if (config_filename == NULL) {
  967. config_filename = getenv("SSLEAY_CONF");
  968. }
  969. /* default to 'openssl.cnf' if no environment variable is set */
  970. if (config_filename == NULL) {
  971. snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename), "%s/%s",
  972. X509_get_default_cert_area(),
  973. "openssl.cnf");
  974. } else {
  975. strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename));
  976. }
  977. php_stream_xport_register("ssl", php_openssl_ssl_socket_factory);
  978. #ifndef OPENSSL_NO_SSL3
  979. php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory);
  980. #endif
  981. php_stream_xport_register("tls", php_openssl_ssl_socket_factory);
  982. php_stream_xport_register("tlsv1.0", php_openssl_ssl_socket_factory);
  983. php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory);
  984. php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory);
  985. #if OPENSSL_VERSION_NUMBER >= 0x10101000
  986. php_stream_xport_register("tlsv1.3", php_openssl_ssl_socket_factory);
  987. #endif
  988. /* override the default tcp socket provider */
  989. php_stream_xport_register("tcp", php_openssl_ssl_socket_factory);
  990. php_register_url_stream_wrapper("https", &php_stream_http_wrapper);
  991. php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper);
  992. REGISTER_INI_ENTRIES();
  993. return SUCCESS;
  994. }
  995. /* }}} */
  996. /* {{{ PHP_GINIT_FUNCTION
  997. */
  998. PHP_GINIT_FUNCTION(openssl)
  999. {
  1000. #if defined(COMPILE_DL_OPENSSL) && defined(ZTS)
  1001. ZEND_TSRMLS_CACHE_UPDATE();
  1002. #endif
  1003. openssl_globals->errors = NULL;
  1004. }
  1005. /* }}} */
  1006. /* {{{ PHP_GSHUTDOWN_FUNCTION
  1007. */
  1008. PHP_GSHUTDOWN_FUNCTION(openssl)
  1009. {
  1010. if (openssl_globals->errors) {
  1011. pefree(openssl_globals->errors, 1);
  1012. }
  1013. }
  1014. /* }}} */
  1015. /* {{{ PHP_MINFO_FUNCTION
  1016. */
  1017. PHP_MINFO_FUNCTION(openssl)
  1018. {
  1019. php_info_print_table_start();
  1020. php_info_print_table_row(2, "OpenSSL support", "enabled");
  1021. php_info_print_table_row(2, "OpenSSL Library Version", OpenSSL_version(OPENSSL_VERSION));
  1022. php_info_print_table_row(2, "OpenSSL Header Version", OPENSSL_VERSION_TEXT);
  1023. php_info_print_table_row(2, "Openssl default config", default_ssl_conf_filename);
  1024. php_info_print_table_end();
  1025. DISPLAY_INI_ENTRIES();
  1026. }
  1027. /* }}} */
  1028. /* {{{ PHP_MSHUTDOWN_FUNCTION
  1029. */
  1030. PHP_MSHUTDOWN_FUNCTION(openssl)
  1031. {
  1032. #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
  1033. EVP_cleanup();
  1034. /* prevent accessing locking callback from unloaded extension */
  1035. CRYPTO_set_locking_callback(NULL);
  1036. /* free allocated error strings */
  1037. ERR_free_strings();
  1038. CONF_modules_free();
  1039. #endif
  1040. php_unregister_url_stream_wrapper("https");
  1041. php_unregister_url_stream_wrapper("ftps");
  1042. php_stream_xport_unregister("ssl");
  1043. #ifndef OPENSSL_NO_SSL3
  1044. php_stream_xport_unregister("sslv3");
  1045. #endif
  1046. php_stream_xport_unregister("tls");
  1047. php_stream_xport_unregister("tlsv1.0");
  1048. php_stream_xport_unregister("tlsv1.1");
  1049. php_stream_xport_unregister("tlsv1.2");
  1050. #if OPENSSL_VERSION_NUMBER >= 0x10101000
  1051. php_stream_xport_unregister("tlsv1.3");
  1052. #endif
  1053. /* reinstate the default tcp handler */
  1054. php_stream_xport_register("tcp", php_stream_generic_socket_factory);
  1055. UNREGISTER_INI_ENTRIES();
  1056. return SUCCESS;
  1057. }
  1058. /* }}} */
  1059. /* {{{ x509 cert functions */
  1060. /* {{{ proto array openssl_get_cert_locations(void)
  1061. Retrieve an array mapping available certificate locations */
  1062. PHP_FUNCTION(openssl_get_cert_locations)
  1063. {
  1064. if (zend_parse_parameters_none() == FAILURE) {
  1065. RETURN_THROWS();
  1066. }
  1067. array_init(return_value);
  1068. add_assoc_string(return_value, "default_cert_file", (char *) X509_get_default_cert_file());
  1069. add_assoc_string(return_value, "default_cert_file_env", (char *) X509_get_default_cert_file_env());
  1070. add_assoc_string(return_value, "default_cert_dir", (char *) X509_get_default_cert_dir());
  1071. add_assoc_string(return_value, "default_cert_dir_env", (char *) X509_get_default_cert_dir_env());
  1072. add_assoc_string(return_value, "default_private_dir", (char *) X509_get_default_private_dir());
  1073. add_assoc_string(return_value, "default_default_cert_area", (char *) X509_get_default_cert_area());
  1074. add_assoc_string(return_value, "ini_cafile",
  1075. zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0));
  1076. add_assoc_string(return_value, "ini_capath",
  1077. zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0));
  1078. }
  1079. /* }}} */
  1080. /* {{{ php_openssl_x509_from_zval
  1081. Given a zval, coerce it into an X509 object.
  1082. The zval can be:
  1083. . X509 resource created using openssl_read_x509()
  1084. . if it starts with file:// then it will be interpreted as the path to that cert
  1085. . it will be interpreted as the cert data
  1086. If you supply makeresource, the result will be registered as an x509 resource and
  1087. it's value returned in makeresource.
  1088. */
  1089. static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval)
  1090. {
  1091. X509 *cert = NULL;
  1092. BIO *in;
  1093. if (resourceval) {
  1094. *resourceval = NULL;
  1095. }
  1096. if (Z_TYPE_P(val) == IS_RESOURCE) {
  1097. /* is it an x509 resource ? */
  1098. void * what;
  1099. zend_resource *res = Z_RES_P(val);
  1100. what = zend_fetch_resource(res, "OpenSSL X.509", le_x509);
  1101. if (!what) {
  1102. return NULL;
  1103. }
  1104. if (resourceval) {
  1105. *resourceval = res;
  1106. if (makeresource) {
  1107. Z_ADDREF_P(val);
  1108. }
  1109. }
  1110. return (X509*)what;
  1111. }
  1112. if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) {
  1113. return NULL;
  1114. }
  1115. /* force it to be a string and check if it refers to a file */
  1116. if (!try_convert_to_string(val)) {
  1117. return NULL;
  1118. }
  1119. if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) {
  1120. if (php_openssl_open_base_dir_chk(Z_STRVAL_P(val) + (sizeof("file://") - 1))) {
  1121. return NULL;
  1122. }
  1123. in = BIO_new_file(Z_STRVAL_P(val) + (sizeof("file://") - 1), PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
  1124. if (in == NULL) {
  1125. php_openssl_store_errors();
  1126. return NULL;
  1127. }
  1128. cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
  1129. } else {
  1130. in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val));
  1131. if (in == NULL) {
  1132. php_openssl_store_errors();
  1133. return NULL;
  1134. }
  1135. #ifdef TYPEDEF_D2I_OF
  1136. cert = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
  1137. #else
  1138. cert = (X509 *) PEM_ASN1_read_bio((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
  1139. #endif
  1140. }
  1141. if (!BIO_free(in)) {
  1142. php_openssl_store_errors();
  1143. }
  1144. if (cert == NULL) {
  1145. php_openssl_store_errors();
  1146. return NULL;
  1147. }
  1148. if (makeresource && resourceval) {
  1149. *resourceval = zend_register_resource(cert, le_x509);
  1150. }
  1151. return cert;
  1152. }
  1153. /* }}} */
  1154. /* {{{ proto bool openssl_x509_export_to_file(mixed x509, string outfilename [, bool notext = true])
  1155. Exports a CERT to file or a var */
  1156. PHP_FUNCTION(openssl_x509_export_to_file)
  1157. {
  1158. X509 * cert;
  1159. zval * zcert;
  1160. zend_bool notext = 1;
  1161. BIO * bio_out;
  1162. char * filename;
  1163. size_t filename_len;
  1164. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|b", &zcert, &filename, &filename_len, &notext) == FAILURE) {
  1165. RETURN_THROWS();
  1166. }
  1167. RETVAL_FALSE;
  1168. cert = php_openssl_x509_from_zval(zcert, 0, NULL);
  1169. if (cert == NULL) {
  1170. php_error_docref(NULL, E_WARNING, "Cannot get cert from parameter 1");
  1171. return;
  1172. }
  1173. if (php_openssl_open_base_dir_chk(filename)) {
  1174. return;
  1175. }
  1176. bio_out = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
  1177. if (bio_out) {
  1178. if (!notext && !X509_print(bio_out, cert)) {
  1179. php_openssl_store_errors();
  1180. }
  1181. if (!PEM_write_bio_X509(bio_out, cert)) {
  1182. php_openssl_store_errors();
  1183. }
  1184. RETVAL_TRUE;
  1185. } else {
  1186. php_openssl_store_errors();
  1187. php_error_docref(NULL, E_WARNING, "Error opening file %s", filename);
  1188. }
  1189. if (Z_TYPE_P(zcert) != IS_RESOURCE) {
  1190. X509_free(cert);
  1191. }
  1192. if (!BIO_free(bio_out)) {
  1193. php_openssl_store_errors();
  1194. }
  1195. }
  1196. /* }}} */
  1197. /* {{{ proto string openssl_spki_new(mixed zpkey, string challenge [, mixed method])
  1198. Creates new private key (or uses existing) and creates a new spki cert
  1199. outputting results to var */
  1200. PHP_FUNCTION(openssl_spki_new)
  1201. {
  1202. size_t challenge_len;
  1203. char * challenge = NULL, * spkstr = NULL;
  1204. zend_string * s = NULL;
  1205. zend_resource *keyresource = NULL;
  1206. const char *spkac = "SPKAC=";
  1207. zend_long algo = OPENSSL_ALGO_MD5;
  1208. zval * zpkey = NULL;
  1209. EVP_PKEY * pkey = NULL;
  1210. NETSCAPE_SPKI *spki=NULL;
  1211. const EVP_MD *mdtype;
  1212. if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|l", &zpkey, &challenge, &challenge_len, &algo) == FAILURE) {
  1213. RETURN_THROWS();
  1214. }
  1215. RETVAL_FALSE;
  1216. PHP_OPENSSL_CHECK_SIZE_T_TO_INT(challenge_len, challenge);
  1217. pkey = php_openssl_evp_from_zval(zpkey, 0, challenge, challenge_len, 1, &keyresource);
  1218. if (pkey == NULL) {
  1219. if (!EG(exception)) {
  1220. php_error_docref(NULL, E_WARNING, "Unable to use supplied private key");
  1221. }
  1222. goto cleanup;
  1223. }
  1224. mdtype = php_openssl_get_evp_md_from_algo(algo);
  1225. if (!mdtype) {
  1226. php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
  1227. goto cleanup;
  1228. }
  1229. if ((spki = NETSCAPE_SPKI_new()) == NULL) {
  1230. php_openssl_store_errors();
  1231. php_error_docref(NULL, E_WARNING, "Unable to create new SPKAC");
  1232. goto cleanup;
  1233. }
  1234. if (challenge) {
  1235. if (!ASN1_STRING_set(spki->spkac->challenge, challenge, (int)challenge_len)) {
  1236. php_openssl_store_errors();
  1237. php_error_docref(NULL, E_WARNING, "Unable to set challenge data");
  1238. goto cleanup;
  1239. }
  1240. }
  1241. if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) {
  1242. php_openssl_store_errors();
  1243. php_error_docref(NULL, E_WARNING, "Unable to embed public key");
  1244. goto cleanup;
  1245. }
  1246. if (!NETSCAPE_SPKI_sign(spki, pkey, mdtype)) {
  1247. php_openssl_store_errors();
  1248. php_error_docref(NULL, E_WARNING, "Unable to sign with specified algorithm");
  1249. goto cleanup;
  1250. }
  1251. spkstr = NETSCAPE_SPKI_b64_encode(spki);
  1252. if (!spkstr){
  1253. php_openssl_store_errors();
  1254. php_error_docref(NULL, E_WARNING, "Unable to encode SPKAC");
  1255. goto cleanup;
  1256. }
  1257. s = zend_string_alloc(strlen(spkac) + strlen(spkstr), 0);
  1258. sprintf(ZSTR_VAL(s), "%s%s", spkac, spkstr);
  1259. ZSTR_LEN(s) = strlen(ZSTR_VAL(s));
  1260. OPENSSL_free(spkstr);
  1261. RETVAL_STR(s);
  1262. goto cleanup;
  1263. cleanup:
  1264. if (spki != NULL) {
  1265. NETSCAPE_SPKI_free(spki);
  1266. }
  1267. if (keyresource == NULL && pkey != NULL) {
  1268. EVP_PKEY_free(pkey);
  1269. }
  1270. if (s && ZSTR_LEN(s) <= 0) {
  1271. RETVAL_FALSE;
  1272. }
  1273. if (keyresource == NULL && s != NULL) {
  1274. zend_string_release_ex(s, 0);
  1275. }
  1276. }
  1277. /* }}} */
  1278. /* {{{ proto bool openssl_spki_verify(string spki)
  1279. Verifies spki returns boolean */
  1280. PHP_FUNCTION(openssl_spki_verify)
  1281. {
  1282. size_t spkstr_len;
  1283. int i = 0, spkstr_cleaned_len = 0;
  1284. char *spkstr, * spkstr_cleaned = NULL;
  1285. EVP_PKEY *pkey = NULL;
  1286. NETSCAPE_SPKI *spki = NULL;
  1287. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
  1288. RETURN_THROWS();
  1289. }
  1290. RETVAL_FALSE;
  1291. spkstr_cleaned = emalloc(spkstr_len + 1);
  1292. spkstr_cleaned_len = (int)(spkstr_len - php_openssl_spki_cleanup(spkstr, spkstr_cleaned));
  1293. if (spkstr_cleaned_len == 0) {
  1294. php_error_docref(NULL, E_WARNING, "Invalid SPKAC");
  1295. goto cleanup;
  1296. }
  1297. spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len);
  1298. if (spki == NULL) {
  1299. php_openssl_store_errors();
  1300. php_error_docref(NULL, E_WARNING, "Unable to decode supplied SPKAC");
  1301. goto cleanup;
  1302. }
  1303. pkey = X509_PUBKEY_get(spki->spkac->pubkey);
  1304. if (pkey == NULL) {
  1305. php_openssl_store_errors();
  1306. php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key");
  1307. goto cleanup;
  1308. }
  1309. i = NETSCAPE_SPKI_verify(spki, pkey);
  1310. goto cleanup;
  1311. cleanup:
  1312. if (spki != NULL) {
  1313. NETSCAPE_SPKI_free(spki);
  1314. }
  1315. if (pkey != NULL) {
  1316. EVP_PKEY_free(pkey);
  1317. }
  1318. if (spkstr_cleaned != NULL) {
  1319. efree(spkstr_cleaned);
  1320. }
  1321. if (i > 0) {
  1322. RETVAL_TRUE;
  1323. } else {
  1324. php_openssl_store_errors();
  1325. }
  1326. }
  1327. /* }}} */
  1328. /* {{{ proto string openssl_spki_export(string spki)
  1329. Exports public key from existing spki to var */
  1330. PHP_FUNCTION(openssl_spki_export)
  1331. {
  1332. size_t spkstr_len;
  1333. char *spkstr, * spkstr_cleaned = NULL, * s = NULL;
  1334. int spkstr_cleaned_len;
  1335. EVP_PKEY *pkey = NULL;
  1336. NETSCAPE_SPKI *spki = NULL;
  1337. BIO *out = NULL;
  1338. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
  1339. RETURN_THROWS();
  1340. }
  1341. RETVAL_FALSE;
  1342. spkstr_cleaned = emalloc(spkstr_len + 1);
  1343. spkstr_cleaned_len = (int)(spkstr_len - php_openssl_spki_cleanup(spkstr, spkstr_cleaned));
  1344. if (spkstr_cleaned_len == 0) {
  1345. php_error_docref(NULL, E_WARNING, "Invalid SPKAC");
  1346. goto cleanup;
  1347. }
  1348. spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len);
  1349. if (spki == NULL) {
  1350. php_openssl_store_errors();
  1351. php_error_docref(NULL, E_WARNING, "Unable to decode supplied SPKAC");
  1352. goto cleanup;
  1353. }
  1354. pkey = X509_PUBKEY_get(spki->spkac->pubkey);
  1355. if (pkey == NULL) {
  1356. php_openssl_store_errors();
  1357. php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key");
  1358. goto cleanup;
  1359. }
  1360. out = BIO_new(BIO_s_mem());
  1361. if (out && PEM_write_bio_PUBKEY(out, pkey)) {
  1362. BUF_MEM *bio_buf;
  1363. BIO_get_mem_ptr(out, &bio_buf);
  1364. RETVAL_STRINGL((char *)bio_buf->data, bio_buf->length);
  1365. } else {
  1366. php_openssl_store_errors();
  1367. }
  1368. goto cleanup;
  1369. cleanup:
  1370. if (spki != NULL) {
  1371. NETSCAPE_SPKI_free(spki);
  1372. }
  1373. if (out != NULL) {
  1374. BIO_free_all(out);
  1375. }
  1376. if (pkey != NULL) {
  1377. EVP_PKEY_free(pkey);
  1378. }
  1379. if (spkstr_cleaned != NULL) {
  1380. efree(spkstr_cleaned);
  1381. }
  1382. if (s != NULL) {
  1383. efree(s);
  1384. }
  1385. }
  1386. /* }}} */
  1387. /* {{{ proto string openssl_spki_export_challenge(string spki)
  1388. Exports spkac challenge from existing spki to var */
  1389. PHP_FUNCTION(openssl_spki_export_challenge)
  1390. {
  1391. size_t spkstr_len;
  1392. char *spkstr, * spkstr_cleaned = NULL;
  1393. int spkstr_cleaned_len;
  1394. NETSCAPE_SPKI *spki = NULL;
  1395. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
  1396. RETURN_THROWS();
  1397. }
  1398. RETVAL_FALSE;
  1399. spkstr_cleaned = emalloc(spkstr_len + 1);
  1400. spkstr_cleaned_len = (int)(spkstr_len - php_openssl_spki_cleanup(spkstr, spkstr_cleaned));
  1401. if (spkstr_cleaned_len == 0) {
  1402. php_error_docref(NULL, E_WARNING, "Invalid SPKAC");
  1403. goto cleanup;
  1404. }
  1405. spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len);
  1406. if (spki == NULL) {
  1407. php_openssl_store_errors();
  1408. php_error_docref(NULL, E_WARNING, "Unable to decode SPKAC");
  1409. goto cleanup;
  1410. }
  1411. RETVAL_STRING((const char *)ASN1_STRING_get0_data(spki->spkac->challenge));
  1412. goto cleanup;
  1413. cleanup:
  1414. if (spkstr_cleaned != NULL) {
  1415. efree(spkstr_cleaned);
  1416. }
  1417. if (spki) {
  1418. NETSCAPE_SPKI_free(spki);
  1419. }
  1420. }
  1421. /* }}} */
  1422. /* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true])
  1423. Exports a CERT to file or a var */
  1424. PHP_FUNCTION(openssl_x509_export)
  1425. {
  1426. X509 * cert;
  1427. zval * zcert, *zout;
  1428. zend_bool notext = 1;
  1429. BIO * bio_out;
  1430. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|b", &zcert, &zout, &notext) == FAILURE) {
  1431. RETURN_THROWS();
  1432. }
  1433. RETVAL_FALSE;
  1434. cert = php_openssl_x509_from_zval(zcert, 0, NULL);
  1435. if (cert == NULL) {
  1436. php_error_docref(NULL, E_WARNING, "Cannot get cert from parameter 1");
  1437. return;
  1438. }
  1439. bio_out = BIO_new(BIO_s_mem());
  1440. if (!bio_out) {
  1441. php_openssl_store_errors();
  1442. goto cleanup;
  1443. }
  1444. if (!notext && !X509_print(bio_out, cert)) {
  1445. php_openssl_store_errors();
  1446. }
  1447. if (PEM_write_bio_X509(bio_out, cert)) {
  1448. BUF_MEM *bio_buf;
  1449. BIO_get_mem_ptr(bio_out, &bio_buf);
  1450. ZEND_TRY_ASSIGN_REF_STRINGL(zout, bio_buf->data, bio_buf->length);
  1451. RETVAL_TRUE;
  1452. } else {
  1453. php_openssl_store_errors();
  1454. }
  1455. BIO_free(bio_out);
  1456. cleanup:
  1457. if (Z_TYPE_P(zcert) != IS_RESOURCE) {
  1458. X509_free(cert);
  1459. }
  1460. }
  1461. /* }}} */
  1462. zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw)
  1463. {
  1464. unsigned char md[EVP_MAX_MD_SIZE];
  1465. const EVP_MD *mdtype;
  1466. unsigned int n;
  1467. zend_string *ret;
  1468. if (!(mdtype = EVP_get_digestbyname(method))) {
  1469. php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
  1470. return NULL;
  1471. } else if (!X509_digest(peer, mdtype, md, &n)) {
  1472. php_openssl_store_errors();
  1473. php_error_docref(NULL, E_ERROR, "Could not generate signature");
  1474. return NULL;
  1475. }
  1476. if (raw) {
  1477. ret = zend_string_init((char*)md, n, 0);
  1478. } else {
  1479. ret = zend_string_alloc(n * 2, 0);
  1480. make_digest_ex(ZSTR_VAL(ret), md, n);
  1481. ZSTR_VAL(ret)[n * 2] = '\0';
  1482. }
  1483. return ret;
  1484. }
  1485. PHP_FUNCTION(openssl_x509_fingerprint)
  1486. {
  1487. X509 *cert;
  1488. zval *zcert;
  1489. zend_bool raw_output = 0;
  1490. char *method = "sha1";
  1491. size_t method_len;
  1492. zend_string *fingerprint;
  1493. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|sb", &zcert, &method, &method_len, &raw_output) == FAILURE) {
  1494. RETURN_THROWS();
  1495. }
  1496. cert = php_openssl_x509_from_zval(zcert, 0, NULL);
  1497. if (cert == NULL) {
  1498. php_error_docref(NULL, E_WARNING, "Cannot get cert from parameter 1");
  1499. RETURN_FALSE;
  1500. }
  1501. fingerprint = php_openssl_x509_fingerprint(cert, method, raw_output);
  1502. if (fingerprint) {
  1503. RETVAL_STR(fingerprint);
  1504. } else {
  1505. RETVAL_FALSE;
  1506. }
  1507. if (Z_TYPE_P(zcert) != IS_RESOURCE) {
  1508. X509_free(cert);
  1509. }
  1510. }
  1511. /* {{{ proto bool openssl_x509_check_private_key(mixed cert, mixed key)
  1512. Checks if a private key corresponds to a CERT */
  1513. PHP_FUNCTION(openssl_x509_check_private_key)
  1514. {
  1515. zval * zcert, *zkey;
  1516. X509 * cert = NULL;
  1517. EVP_PKEY * key = NULL;
  1518. zend_resource *keyresource = NULL;
  1519. RETVAL_FALSE;
  1520. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zcert, &zkey) == FAILURE) {
  1521. RETURN_THROWS();
  1522. }
  1523. cert = php

Large files files are truncated, but you can click here to view the full file