/ext/openssl/openssl.c

http://github.com/infusion/PHP · C · 4921 lines · 3809 code · 704 blank · 408 comment · 1032 complexity · def9cf9a3ae9c4308d994129835e2aaa MD5 · raw file

Large files are truncated click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2011 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Stig Venaas <venaas@php.net> |
  16. | Wez Furlong <wez@thebrainroom.com> |
  17. | Sascha Kettler <kettler@gmx.net> |
  18. | Pierre-Alain Joye <pierre@php.net> |
  19. | Marc Delling <delling@silpion.de> (PKCS12 functions) |
  20. +----------------------------------------------------------------------+
  21. */
  22. /* $Id: openssl.c 308534 2011-02-21 12:47:38Z pajoye $ */
  23. #ifdef HAVE_CONFIG_H
  24. #include "config.h"
  25. #endif
  26. #include "php.h"
  27. #include "php_openssl.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. /* OpenSSL includes */
  35. #include <openssl/evp.h>
  36. #include <openssl/x509.h>
  37. #include <openssl/x509v3.h>
  38. #include <openssl/crypto.h>
  39. #include <openssl/pem.h>
  40. #include <openssl/err.h>
  41. #include <openssl/conf.h>
  42. #include <openssl/rand.h>
  43. #include <openssl/ssl.h>
  44. #include <openssl/pkcs12.h>
  45. /* Common */
  46. #include <time.h>
  47. #ifdef NETWARE
  48. #define timezone _timezone /* timezone is called _timezone in LibC */
  49. #endif
  50. #define DEFAULT_KEY_LENGTH 512
  51. #define MIN_KEY_LENGTH 384
  52. #define OPENSSL_ALGO_SHA1 1
  53. #define OPENSSL_ALGO_MD5 2
  54. #define OPENSSL_ALGO_MD4 3
  55. #ifdef HAVE_OPENSSL_MD2_H
  56. #define OPENSSL_ALGO_MD2 4
  57. #endif
  58. #define OPENSSL_ALGO_DSS1 5
  59. #define DEBUG_SMIME 0
  60. /* FIXME: Use the openssl constants instead of
  61. * enum. It is now impossible to match real values
  62. * against php constants. Also sorry to break the
  63. * enum principles here, BC...
  64. */
  65. enum php_openssl_key_type {
  66. OPENSSL_KEYTYPE_RSA,
  67. OPENSSL_KEYTYPE_DSA,
  68. OPENSSL_KEYTYPE_DH,
  69. OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA,
  70. #ifdef EVP_PKEY_EC
  71. OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH +1
  72. #endif
  73. };
  74. enum php_openssl_cipher_type {
  75. PHP_OPENSSL_CIPHER_RC2_40,
  76. PHP_OPENSSL_CIPHER_RC2_128,
  77. PHP_OPENSSL_CIPHER_RC2_64,
  78. PHP_OPENSSL_CIPHER_DES,
  79. PHP_OPENSSL_CIPHER_3DES,
  80. PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40
  81. };
  82. PHP_FUNCTION(openssl_get_md_methods);
  83. PHP_FUNCTION(openssl_get_cipher_methods);
  84. PHP_FUNCTION(openssl_digest);
  85. PHP_FUNCTION(openssl_encrypt);
  86. PHP_FUNCTION(openssl_decrypt);
  87. PHP_FUNCTION(openssl_cipher_iv_length);
  88. PHP_FUNCTION(openssl_dh_compute_key);
  89. PHP_FUNCTION(openssl_random_pseudo_bytes);
  90. /* {{{ arginfo */
  91. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 0, 2)
  92. ZEND_ARG_INFO(0, x509)
  93. ZEND_ARG_INFO(0, outfilename)
  94. ZEND_ARG_INFO(0, notext)
  95. ZEND_END_ARG_INFO()
  96. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export, 0, 0, 2)
  97. ZEND_ARG_INFO(0, x509)
  98. ZEND_ARG_INFO(1, out)
  99. ZEND_ARG_INFO(0, notext)
  100. ZEND_END_ARG_INFO()
  101. ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_check_private_key, 0)
  102. ZEND_ARG_INFO(0, cert)
  103. ZEND_ARG_INFO(0, key)
  104. ZEND_END_ARG_INFO()
  105. ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_parse, 0)
  106. ZEND_ARG_INFO(0, x509)
  107. ZEND_ARG_INFO(0, shortname)
  108. ZEND_END_ARG_INFO()
  109. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_checkpurpose, 0, 0, 3)
  110. ZEND_ARG_INFO(0, x509cert)
  111. ZEND_ARG_INFO(0, purpose)
  112. ZEND_ARG_INFO(0, cainfo) /* array */
  113. ZEND_ARG_INFO(0, untrustedfile)
  114. ZEND_END_ARG_INFO()
  115. ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_read, 0)
  116. ZEND_ARG_INFO(0, cert)
  117. ZEND_END_ARG_INFO()
  118. ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_free, 0)
  119. ZEND_ARG_INFO(0, x509)
  120. ZEND_END_ARG_INFO()
  121. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs12_export_to_file, 0, 0, 4)
  122. ZEND_ARG_INFO(0, x509)
  123. ZEND_ARG_INFO(0, filename)
  124. ZEND_ARG_INFO(0, priv_key)
  125. ZEND_ARG_INFO(0, pass)
  126. ZEND_ARG_INFO(0, args) /* array */
  127. ZEND_END_ARG_INFO()
  128. ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_export, 0)
  129. ZEND_ARG_INFO(0, x509)
  130. ZEND_ARG_INFO(1, out)
  131. ZEND_ARG_INFO(0, priv_key)
  132. ZEND_ARG_INFO(0, pass)
  133. ZEND_ARG_INFO(0, args) /* array */
  134. ZEND_END_ARG_INFO()
  135. ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_read, 0)
  136. ZEND_ARG_INFO(0, PKCS12)
  137. ZEND_ARG_INFO(1, certs) /* array */
  138. ZEND_ARG_INFO(0, pass)
  139. ZEND_END_ARG_INFO()
  140. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export_to_file, 0, 0, 2)
  141. ZEND_ARG_INFO(0, csr)
  142. ZEND_ARG_INFO(0, outfilename)
  143. ZEND_ARG_INFO(0, notext)
  144. ZEND_END_ARG_INFO()
  145. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export, 0, 0, 2)
  146. ZEND_ARG_INFO(0, csr)
  147. ZEND_ARG_INFO(1, out)
  148. ZEND_ARG_INFO(0, notext)
  149. ZEND_END_ARG_INFO()
  150. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_sign, 0, 0, 4)
  151. ZEND_ARG_INFO(0, csr)
  152. ZEND_ARG_INFO(0, x509)
  153. ZEND_ARG_INFO(0, priv_key)
  154. ZEND_ARG_INFO(0, days)
  155. ZEND_ARG_INFO(0, config_args) /* array */
  156. ZEND_ARG_INFO(0, serial)
  157. ZEND_END_ARG_INFO()
  158. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_new, 0, 0, 2)
  159. ZEND_ARG_INFO(0, dn) /* array */
  160. ZEND_ARG_INFO(1, privkey)
  161. ZEND_ARG_INFO(0, configargs)
  162. ZEND_ARG_INFO(0, extraattribs)
  163. ZEND_END_ARG_INFO()
  164. ZEND_BEGIN_ARG_INFO(arginfo_openssl_csr_get_subject, 0)
  165. ZEND_ARG_INFO(0, csr)
  166. ZEND_END_ARG_INFO()
  167. ZEND_BEGIN_ARG_INFO(arginfo_openssl_csr_get_public_key, 0)
  168. ZEND_ARG_INFO(0, csr)
  169. ZEND_END_ARG_INFO()
  170. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_new, 0, 0, 0)
  171. ZEND_ARG_INFO(0, configargs) /* array */
  172. ZEND_END_ARG_INFO()
  173. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export_to_file, 0, 0, 2)
  174. ZEND_ARG_INFO(0, key)
  175. ZEND_ARG_INFO(0, outfilename)
  176. ZEND_ARG_INFO(0, passphrase)
  177. ZEND_ARG_INFO(0, config_args) /* array */
  178. ZEND_END_ARG_INFO()
  179. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export, 0, 0, 2)
  180. ZEND_ARG_INFO(0, key)
  181. ZEND_ARG_INFO(1, out)
  182. ZEND_ARG_INFO(0, passphrase)
  183. ZEND_ARG_INFO(0, config_args) /* array */
  184. ZEND_END_ARG_INFO()
  185. ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_public, 0)
  186. ZEND_ARG_INFO(0, cert)
  187. ZEND_END_ARG_INFO()
  188. ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_free, 0)
  189. ZEND_ARG_INFO(0, key)
  190. ZEND_END_ARG_INFO()
  191. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_get_private, 0, 0, 1)
  192. ZEND_ARG_INFO(0, key)
  193. ZEND_ARG_INFO(0, passphrase)
  194. ZEND_END_ARG_INFO()
  195. ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_details, 0)
  196. ZEND_ARG_INFO(0, key)
  197. ZEND_END_ARG_INFO()
  198. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_verify, 0, 0, 2)
  199. ZEND_ARG_INFO(0, filename)
  200. ZEND_ARG_INFO(0, flags)
  201. ZEND_ARG_INFO(0, signerscerts)
  202. ZEND_ARG_INFO(0, cainfo) /* array */
  203. ZEND_ARG_INFO(0, extracerts)
  204. ZEND_ARG_INFO(0, content)
  205. ZEND_END_ARG_INFO()
  206. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_encrypt, 0, 0, 4)
  207. ZEND_ARG_INFO(0, infile)
  208. ZEND_ARG_INFO(0, outfile)
  209. ZEND_ARG_INFO(0, recipcerts)
  210. ZEND_ARG_INFO(0, headers) /* array */
  211. ZEND_ARG_INFO(0, flags)
  212. ZEND_ARG_INFO(0, cipher)
  213. ZEND_END_ARG_INFO()
  214. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_sign, 0, 0, 5)
  215. ZEND_ARG_INFO(0, infile)
  216. ZEND_ARG_INFO(0, outfile)
  217. ZEND_ARG_INFO(0, signcert)
  218. ZEND_ARG_INFO(0, signkey)
  219. ZEND_ARG_INFO(0, headers) /* array */
  220. ZEND_ARG_INFO(0, flags)
  221. ZEND_ARG_INFO(0, extracertsfilename)
  222. ZEND_END_ARG_INFO()
  223. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_decrypt, 0, 0, 3)
  224. ZEND_ARG_INFO(0, infilename)
  225. ZEND_ARG_INFO(0, outfilename)
  226. ZEND_ARG_INFO(0, recipcert)
  227. ZEND_ARG_INFO(0, recipkey)
  228. ZEND_END_ARG_INFO()
  229. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_encrypt, 0, 0, 3)
  230. ZEND_ARG_INFO(0, data)
  231. ZEND_ARG_INFO(1, crypted)
  232. ZEND_ARG_INFO(0, key)
  233. ZEND_ARG_INFO(0, padding)
  234. ZEND_END_ARG_INFO()
  235. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_decrypt, 0, 0, 3)
  236. ZEND_ARG_INFO(0, data)
  237. ZEND_ARG_INFO(1, crypted)
  238. ZEND_ARG_INFO(0, key)
  239. ZEND_ARG_INFO(0, padding)
  240. ZEND_END_ARG_INFO()
  241. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_encrypt, 0, 0, 3)
  242. ZEND_ARG_INFO(0, data)
  243. ZEND_ARG_INFO(1, crypted)
  244. ZEND_ARG_INFO(0, key)
  245. ZEND_ARG_INFO(0, padding)
  246. ZEND_END_ARG_INFO()
  247. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_decrypt, 0, 0, 3)
  248. ZEND_ARG_INFO(0, data)
  249. ZEND_ARG_INFO(1, crypted)
  250. ZEND_ARG_INFO(0, key)
  251. ZEND_ARG_INFO(0, padding)
  252. ZEND_END_ARG_INFO()
  253. ZEND_BEGIN_ARG_INFO(arginfo_openssl_error_string, 0)
  254. ZEND_END_ARG_INFO()
  255. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_sign, 0, 0, 3)
  256. ZEND_ARG_INFO(0, data)
  257. ZEND_ARG_INFO(1, signature)
  258. ZEND_ARG_INFO(0, key)
  259. ZEND_ARG_INFO(0, method)
  260. ZEND_END_ARG_INFO()
  261. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_verify, 0, 0, 3)
  262. ZEND_ARG_INFO(0, data)
  263. ZEND_ARG_INFO(0, signature)
  264. ZEND_ARG_INFO(0, key)
  265. ZEND_ARG_INFO(0, method)
  266. ZEND_END_ARG_INFO()
  267. ZEND_BEGIN_ARG_INFO(arginfo_openssl_seal, 0)
  268. ZEND_ARG_INFO(0, data)
  269. ZEND_ARG_INFO(1, sealdata)
  270. ZEND_ARG_INFO(1, ekeys) /* arary */
  271. ZEND_ARG_INFO(0, pubkeys) /* array */
  272. ZEND_END_ARG_INFO()
  273. ZEND_BEGIN_ARG_INFO(arginfo_openssl_open, 0)
  274. ZEND_ARG_INFO(0, data)
  275. ZEND_ARG_INFO(1, opendata)
  276. ZEND_ARG_INFO(0, ekey)
  277. ZEND_ARG_INFO(0, privkey)
  278. ZEND_END_ARG_INFO()
  279. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_md_methods, 0, 0, 0)
  280. ZEND_ARG_INFO(0, aliases)
  281. ZEND_END_ARG_INFO()
  282. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_cipher_methods, 0, 0, 0)
  283. ZEND_ARG_INFO(0, aliases)
  284. ZEND_END_ARG_INFO()
  285. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_digest, 0, 0, 2)
  286. ZEND_ARG_INFO(0, data)
  287. ZEND_ARG_INFO(0, method)
  288. ZEND_ARG_INFO(0, raw_output)
  289. ZEND_END_ARG_INFO()
  290. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_encrypt, 0, 0, 3)
  291. ZEND_ARG_INFO(0, data)
  292. ZEND_ARG_INFO(0, method)
  293. ZEND_ARG_INFO(0, password)
  294. ZEND_ARG_INFO(0, raw_output)
  295. ZEND_ARG_INFO(0, iv)
  296. ZEND_END_ARG_INFO()
  297. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_decrypt, 0, 0, 3)
  298. ZEND_ARG_INFO(0, data)
  299. ZEND_ARG_INFO(0, method)
  300. ZEND_ARG_INFO(0, password)
  301. ZEND_ARG_INFO(0, raw_input)
  302. ZEND_ARG_INFO(0, iv)
  303. ZEND_END_ARG_INFO()
  304. ZEND_BEGIN_ARG_INFO(arginfo_openssl_cipher_iv_length, 0)
  305. ZEND_ARG_INFO(0, method)
  306. ZEND_END_ARG_INFO()
  307. ZEND_BEGIN_ARG_INFO(arginfo_openssl_dh_compute_key, 0)
  308. ZEND_ARG_INFO(0, pub_key)
  309. ZEND_ARG_INFO(0, dh_key)
  310. ZEND_END_ARG_INFO()
  311. ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_random_pseudo_bytes, 0, 0, 1)
  312. ZEND_ARG_INFO(0, length)
  313. ZEND_ARG_INFO(1, result_is_strong)
  314. ZEND_END_ARG_INFO()
  315. /* }}} */
  316. /* {{{ openssl_functions[]
  317. */
  318. const zend_function_entry openssl_functions[] = {
  319. /* public/private key functions */
  320. PHP_FE(openssl_pkey_free, arginfo_openssl_pkey_free)
  321. PHP_FE(openssl_pkey_new, arginfo_openssl_pkey_new)
  322. PHP_FE(openssl_pkey_export, arginfo_openssl_pkey_export)
  323. PHP_FE(openssl_pkey_export_to_file, arginfo_openssl_pkey_export_to_file)
  324. PHP_FE(openssl_pkey_get_private, arginfo_openssl_pkey_get_private)
  325. PHP_FE(openssl_pkey_get_public, arginfo_openssl_pkey_get_public)
  326. PHP_FE(openssl_pkey_get_details, arginfo_openssl_pkey_get_details)
  327. PHP_FALIAS(openssl_free_key, openssl_pkey_free, arginfo_openssl_pkey_free)
  328. PHP_FALIAS(openssl_get_privatekey, openssl_pkey_get_private, arginfo_openssl_pkey_get_private)
  329. PHP_FALIAS(openssl_get_publickey, openssl_pkey_get_public, arginfo_openssl_pkey_get_public)
  330. /* x.509 cert funcs */
  331. PHP_FE(openssl_x509_read, arginfo_openssl_x509_read)
  332. PHP_FE(openssl_x509_free, arginfo_openssl_x509_free)
  333. PHP_FE(openssl_x509_parse, arginfo_openssl_x509_parse)
  334. PHP_FE(openssl_x509_checkpurpose, arginfo_openssl_x509_checkpurpose)
  335. PHP_FE(openssl_x509_check_private_key, arginfo_openssl_x509_check_private_key)
  336. PHP_FE(openssl_x509_export, arginfo_openssl_x509_export)
  337. PHP_FE(openssl_x509_export_to_file, arginfo_openssl_x509_export_to_file)
  338. /* PKCS12 funcs */
  339. PHP_FE(openssl_pkcs12_export, arginfo_openssl_pkcs12_export)
  340. PHP_FE(openssl_pkcs12_export_to_file, arginfo_openssl_pkcs12_export_to_file)
  341. PHP_FE(openssl_pkcs12_read, arginfo_openssl_pkcs12_read)
  342. /* CSR funcs */
  343. PHP_FE(openssl_csr_new, arginfo_openssl_csr_new)
  344. PHP_FE(openssl_csr_export, arginfo_openssl_csr_export)
  345. PHP_FE(openssl_csr_export_to_file, arginfo_openssl_csr_export_to_file)
  346. PHP_FE(openssl_csr_sign, arginfo_openssl_csr_sign)
  347. PHP_FE(openssl_csr_get_subject, arginfo_openssl_csr_get_subject)
  348. PHP_FE(openssl_csr_get_public_key, arginfo_openssl_csr_get_public_key)
  349. PHP_FE(openssl_digest, arginfo_openssl_digest)
  350. PHP_FE(openssl_encrypt, arginfo_openssl_encrypt)
  351. PHP_FE(openssl_decrypt, arginfo_openssl_decrypt)
  352. PHP_FE(openssl_cipher_iv_length, arginfo_openssl_cipher_iv_length)
  353. PHP_FE(openssl_sign, arginfo_openssl_sign)
  354. PHP_FE(openssl_verify, arginfo_openssl_verify)
  355. PHP_FE(openssl_seal, arginfo_openssl_seal)
  356. PHP_FE(openssl_open, arginfo_openssl_open)
  357. /* for S/MIME handling */
  358. PHP_FE(openssl_pkcs7_verify, arginfo_openssl_pkcs7_verify)
  359. PHP_FE(openssl_pkcs7_decrypt, arginfo_openssl_pkcs7_decrypt)
  360. PHP_FE(openssl_pkcs7_sign, arginfo_openssl_pkcs7_sign)
  361. PHP_FE(openssl_pkcs7_encrypt, arginfo_openssl_pkcs7_encrypt)
  362. PHP_FE(openssl_private_encrypt, arginfo_openssl_private_encrypt)
  363. PHP_FE(openssl_private_decrypt, arginfo_openssl_private_decrypt)
  364. PHP_FE(openssl_public_encrypt, arginfo_openssl_public_encrypt)
  365. PHP_FE(openssl_public_decrypt, arginfo_openssl_public_decrypt)
  366. PHP_FE(openssl_get_md_methods, arginfo_openssl_get_md_methods)
  367. PHP_FE(openssl_get_cipher_methods, arginfo_openssl_get_cipher_methods)
  368. PHP_FE(openssl_dh_compute_key, arginfo_openssl_dh_compute_key)
  369. PHP_FE(openssl_random_pseudo_bytes, arginfo_openssl_random_pseudo_bytes)
  370. PHP_FE(openssl_error_string, arginfo_openssl_error_string)
  371. {NULL, NULL, NULL}
  372. };
  373. /* }}} */
  374. /* {{{ openssl_module_entry
  375. */
  376. zend_module_entry openssl_module_entry = {
  377. STANDARD_MODULE_HEADER,
  378. "openssl",
  379. openssl_functions,
  380. PHP_MINIT(openssl),
  381. PHP_MSHUTDOWN(openssl),
  382. NULL,
  383. NULL,
  384. PHP_MINFO(openssl),
  385. NO_VERSION_YET,
  386. STANDARD_MODULE_PROPERTIES
  387. };
  388. /* }}} */
  389. #ifdef COMPILE_DL_OPENSSL
  390. ZEND_GET_MODULE(openssl)
  391. #endif
  392. static int le_key;
  393. static int le_x509;
  394. static int le_csr;
  395. static int ssl_stream_data_index;
  396. int php_openssl_get_x509_list_id(void) /* {{{ */
  397. {
  398. return le_x509;
  399. }
  400. /* }}} */
  401. /* {{{ resource destructors */
  402. static void php_pkey_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  403. {
  404. EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr;
  405. assert(pkey != NULL);
  406. EVP_PKEY_free(pkey);
  407. }
  408. static void php_x509_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  409. {
  410. X509 *x509 = (X509 *)rsrc->ptr;
  411. X509_free(x509);
  412. }
  413. static void php_csr_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  414. {
  415. X509_REQ * csr = (X509_REQ*)rsrc->ptr;
  416. X509_REQ_free(csr);
  417. }
  418. /* }}} */
  419. /* {{{ openssl safe_mode & open_basedir checks */
  420. inline static int php_openssl_safe_mode_chk(char *filename TSRMLS_DC)
  421. {
  422. if (php_check_open_basedir(filename TSRMLS_CC)) {
  423. return -1;
  424. }
  425. return 0;
  426. }
  427. /* }}} */
  428. /* openssl -> PHP "bridging" */
  429. /* true global; readonly after module startup */
  430. static char default_ssl_conf_filename[MAXPATHLEN];
  431. struct php_x509_request { /* {{{ */
  432. #if OPENSSL_VERSION_NUMBER >= 0x10000002L
  433. LHASH_OF(CONF_VALUE) * global_config; /* Global SSL config */
  434. LHASH_OF(CONF_VALUE) * req_config; /* SSL config for this request */
  435. #else
  436. LHASH * global_config; /* Global SSL config */
  437. LHASH * req_config; /* SSL config for this request */
  438. #endif
  439. const EVP_MD * md_alg;
  440. const EVP_MD * digest;
  441. char * section_name,
  442. * config_filename,
  443. * digest_name,
  444. * extensions_section,
  445. * request_extensions_section;
  446. int priv_key_bits;
  447. int priv_key_type;
  448. int priv_key_encrypt;
  449. EVP_PKEY * priv_key;
  450. };
  451. /* }}} */
  452. static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC);
  453. static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC);
  454. static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC);
  455. static X509_STORE * setup_verify(zval * calist TSRMLS_DC);
  456. static STACK_OF(X509) * load_all_certs_from_file(char *certfile);
  457. static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC);
  458. static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC);
  459. static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname TSRMLS_DC) /* {{{ */
  460. {
  461. zval *subitem, *subentries;
  462. int i, j = -1, last = -1, obj_cnt = 0;
  463. char *sname;
  464. int nid;
  465. X509_NAME_ENTRY * ne;
  466. ASN1_STRING * str = NULL;
  467. ASN1_OBJECT * obj;
  468. if (key != NULL) {
  469. MAKE_STD_ZVAL(subitem);
  470. array_init(subitem);
  471. } else {
  472. subitem = val;
  473. }
  474. for (i = 0; i < X509_NAME_entry_count(name); i++) {
  475. unsigned char *to_add;
  476. int to_add_len;
  477. ne = X509_NAME_get_entry(name, i);
  478. obj = X509_NAME_ENTRY_get_object(ne);
  479. nid = OBJ_obj2nid(obj);
  480. obj_cnt = 0;
  481. if (shortname) {
  482. sname = (char *) OBJ_nid2sn(nid);
  483. } else {
  484. sname = (char *) OBJ_nid2ln(nid);
  485. }
  486. MAKE_STD_ZVAL(subentries);
  487. array_init(subentries);
  488. last = -1;
  489. for (;;) {
  490. j = X509_NAME_get_index_by_OBJ(name, obj, last);
  491. if (j < 0) {
  492. if (last != -1) break;
  493. } else {
  494. obj_cnt++;
  495. ne = X509_NAME_get_entry(name, j);
  496. str = X509_NAME_ENTRY_get_data(ne);
  497. if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) {
  498. to_add_len = ASN1_STRING_to_UTF8(&to_add, str);
  499. if (to_add_len != -1) {
  500. add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1);
  501. }
  502. } else {
  503. to_add = ASN1_STRING_data(str);
  504. to_add_len = ASN1_STRING_length(str);
  505. add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1);
  506. }
  507. }
  508. last = j;
  509. }
  510. i = last;
  511. if (obj_cnt > 1) {
  512. add_assoc_zval_ex(subitem, sname, strlen(sname) + 1, subentries);
  513. } else {
  514. zval_dtor(subentries);
  515. FREE_ZVAL(subentries);
  516. if (obj_cnt && str && to_add_len > -1) {
  517. add_assoc_stringl(subitem, sname, (char *)to_add, to_add_len, 1);
  518. }
  519. }
  520. }
  521. if (key != NULL) {
  522. zend_hash_update(HASH_OF(val), key, strlen(key) + 1, (void *)&subitem, sizeof(subitem), NULL);
  523. }
  524. }
  525. /* }}} */
  526. static void add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) /* {{{ */
  527. {
  528. add_assoc_stringl(val, key, (char *)str->data, str->length, 1);
  529. }
  530. /* }}} */
  531. static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */
  532. {
  533. /*
  534. This is how the time string is formatted:
  535. snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
  536. ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
  537. */
  538. time_t ret;
  539. struct tm thetime;
  540. char * strbuf;
  541. char * thestr;
  542. long gmadjust = 0;
  543. if (timestr->length < 13) {
  544. php_error_docref(NULL TSRMLS_CC, E_WARNING, "extension author too lazy to parse %s correctly", timestr->data);
  545. return (time_t)-1;
  546. }
  547. strbuf = estrdup((char *)timestr->data);
  548. memset(&thetime, 0, sizeof(thetime));
  549. /* we work backwards so that we can use atoi more easily */
  550. thestr = strbuf + timestr->length - 3;
  551. thetime.tm_sec = atoi(thestr);
  552. *thestr = '\0';
  553. thestr -= 2;
  554. thetime.tm_min = atoi(thestr);
  555. *thestr = '\0';
  556. thestr -= 2;
  557. thetime.tm_hour = atoi(thestr);
  558. *thestr = '\0';
  559. thestr -= 2;
  560. thetime.tm_mday = atoi(thestr);
  561. *thestr = '\0';
  562. thestr -= 2;
  563. thetime.tm_mon = atoi(thestr)-1;
  564. *thestr = '\0';
  565. thestr -= 2;
  566. thetime.tm_year = atoi(thestr);
  567. if (thetime.tm_year < 68) {
  568. thetime.tm_year += 100;
  569. }
  570. thetime.tm_isdst = -1;
  571. ret = mktime(&thetime);
  572. #if HAVE_TM_GMTOFF
  573. gmadjust = thetime.tm_gmtoff;
  574. #else
  575. /*
  576. ** If correcting for daylight savings time, we set the adjustment to
  577. ** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and
  578. ** set the adjustment to the main timezone + 3600 seconds.
  579. */
  580. gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone + 3600);
  581. #endif
  582. ret += gmadjust;
  583. efree(strbuf);
  584. return ret;
  585. }
  586. /* }}} */
  587. #if OPENSSL_VERSION_NUMBER >= 0x10000002L
  588. static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH_OF(CONF_VALUE) * config TSRMLS_DC) /* {{{ */
  589. #else
  590. static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH * config TSRMLS_DC)
  591. #endif
  592. {
  593. X509V3_CTX ctx;
  594. X509V3_set_ctx_test(&ctx);
  595. X509V3_set_conf_lhash(&ctx, config);
  596. if (!X509V3_EXT_add_conf(config, &ctx, (char *)section, NULL)) {
  597. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading %s section %s of %s",
  598. section_label,
  599. section,
  600. config_filename);
  601. return FAILURE;
  602. }
  603. return SUCCESS;
  604. }
  605. /* }}} */
  606. static int add_oid_section(struct php_x509_request * req TSRMLS_DC) /* {{{ */
  607. {
  608. char * str;
  609. STACK_OF(CONF_VALUE) * sktmp;
  610. CONF_VALUE * cnf;
  611. int i;
  612. str = CONF_get_string(req->req_config, NULL, "oid_section");
  613. if (str == NULL) {
  614. return SUCCESS;
  615. }
  616. sktmp = CONF_get_section(req->req_config, str);
  617. if (sktmp == NULL) {
  618. php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem loading oid section %s", str);
  619. return FAILURE;
  620. }
  621. for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
  622. cnf = sk_CONF_VALUE_value(sktmp, i);
  623. if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
  624. php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value);
  625. return FAILURE;
  626. }
  627. }
  628. return SUCCESS;
  629. }
  630. /* }}} */
  631. #define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req))
  632. #define PHP_SSL_REQ_DISPOSE(req) php_openssl_dispose_config(req TSRMLS_CC)
  633. #define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval TSRMLS_CC)
  634. #define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \
  635. req->config_filename, req->var, req->req_config TSRMLS_CC) == FAILURE) return FAILURE
  636. #define SET_OPTIONAL_STRING_ARG(key, varname, defval) \
  637. if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS) \
  638. varname = Z_STRVAL_PP(item); \
  639. else \
  640. varname = defval
  641. #define SET_OPTIONAL_LONG_ARG(key, varname, defval) \
  642. if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS) \
  643. varname = Z_LVAL_PP(item); \
  644. else \
  645. varname = defval
  646. static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args TSRMLS_DC) /* {{{ */
  647. {
  648. char * str;
  649. zval ** item;
  650. SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename);
  651. SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req");
  652. req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL);
  653. req->req_config = CONF_load(NULL, req->config_filename, NULL);
  654. if (req->req_config == NULL) {
  655. return FAILURE;
  656. }
  657. /* read in the oids */
  658. str = CONF_get_string(req->req_config, NULL, "oid_file");
  659. if (str && !php_openssl_safe_mode_chk(str TSRMLS_CC)) {
  660. BIO *oid_bio = BIO_new_file(str, "r");
  661. if (oid_bio) {
  662. OBJ_create_objects(oid_bio);
  663. BIO_free(oid_bio);
  664. }
  665. }
  666. if (add_oid_section(req TSRMLS_CC) == FAILURE) {
  667. return FAILURE;
  668. }
  669. SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
  670. CONF_get_string(req->req_config, req->section_name, "default_md"));
  671. SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
  672. CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
  673. SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
  674. CONF_get_string(req->req_config, req->section_name, "req_extensions"));
  675. SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits,
  676. CONF_get_number(req->req_config, req->section_name, "default_bits"));
  677. SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT);
  678. if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key"), (void**)&item) == SUCCESS) {
  679. req->priv_key_encrypt = Z_BVAL_PP(item);
  680. } else {
  681. str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key");
  682. if (str == NULL) {
  683. str = CONF_get_string(req->req_config, req->section_name, "encrypt_key");
  684. }
  685. if (str && strcmp(str, "no") == 0) {
  686. req->priv_key_encrypt = 0;
  687. } else {
  688. req->priv_key_encrypt = 1;
  689. }
  690. }
  691. /* digest alg */
  692. if (req->digest_name == NULL) {
  693. req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md");
  694. }
  695. if (req->digest_name) {
  696. req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name);
  697. }
  698. if (req->md_alg == NULL) {
  699. req->md_alg = req->digest = EVP_md5();
  700. }
  701. PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
  702. /* set the string mask */
  703. str = CONF_get_string(req->req_config, req->section_name, "string_mask");
  704. if (str && !ASN1_STRING_set_default_mask_asc(str)) {
  705. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid global string mask setting %s", str);
  706. return FAILURE;
  707. }
  708. PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section);
  709. return SUCCESS;
  710. }
  711. /* }}} */
  712. static void php_openssl_dispose_config(struct php_x509_request * req TSRMLS_DC) /* {{{ */
  713. {
  714. if (req->priv_key) {
  715. EVP_PKEY_free(req->priv_key);
  716. req->priv_key = NULL;
  717. }
  718. if (req->global_config) {
  719. CONF_free(req->global_config);
  720. req->global_config = NULL;
  721. }
  722. if (req->req_config) {
  723. CONF_free(req->req_config);
  724. req->req_config = NULL;
  725. }
  726. }
  727. /* }}} */
  728. static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded) /* {{{ */
  729. {
  730. char buffer[MAXPATHLEN];
  731. TSRMLS_FETCH();
  732. *egdsocket = 0;
  733. *seeded = 0;
  734. if (file == NULL) {
  735. file = RAND_file_name(buffer, sizeof(buffer));
  736. } else if (RAND_egd(file) > 0) {
  737. /* if the given filename is an EGD socket, don't
  738. * write anything back to it */
  739. *egdsocket = 1;
  740. return SUCCESS;
  741. }
  742. if (file == NULL || !RAND_load_file(file, -1)) {
  743. if (RAND_status() == 0) {
  744. php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to load random state; not enough random data!");
  745. return FAILURE;
  746. }
  747. return FAILURE;
  748. }
  749. *seeded = 1;
  750. return SUCCESS;
  751. }
  752. /* }}} */
  753. static int php_openssl_write_rand_file(const char * file, int egdsocket, int seeded) /* {{{ */
  754. {
  755. char buffer[MAXPATHLEN];
  756. TSRMLS_FETCH();
  757. if (egdsocket || !seeded) {
  758. /* if we did not manage to read the seed file, we should not write
  759. * a low-entropy seed file back */
  760. return FAILURE;
  761. }
  762. if (file == NULL) {
  763. file = RAND_file_name(buffer, sizeof(buffer));
  764. }
  765. if (file == NULL || !RAND_write_file(file)) {
  766. php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to write random state");
  767. return FAILURE;
  768. }
  769. return SUCCESS;
  770. }
  771. /* }}} */
  772. static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {{{ */
  773. EVP_MD *mdtype;
  774. switch (algo) {
  775. case OPENSSL_ALGO_SHA1:
  776. mdtype = (EVP_MD *) EVP_sha1();
  777. break;
  778. case OPENSSL_ALGO_MD5:
  779. mdtype = (EVP_MD *) EVP_md5();
  780. break;
  781. case OPENSSL_ALGO_MD4:
  782. mdtype = (EVP_MD *) EVP_md4();
  783. break;
  784. #ifdef HAVE_OPENSSL_MD2_H
  785. case OPENSSL_ALGO_MD2:
  786. mdtype = (EVP_MD *) EVP_md2();
  787. break;
  788. #endif
  789. case OPENSSL_ALGO_DSS1:
  790. mdtype = (EVP_MD *) EVP_dss1();
  791. break;
  792. default:
  793. return NULL;
  794. break;
  795. }
  796. return mdtype;
  797. }
  798. /* }}} */
  799. static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo) { /* {{{ */
  800. switch (algo) {
  801. #ifndef OPENSSL_NO_RC2
  802. case PHP_OPENSSL_CIPHER_RC2_40:
  803. return EVP_rc2_40_cbc();
  804. break;
  805. case PHP_OPENSSL_CIPHER_RC2_64:
  806. return EVP_rc2_64_cbc();
  807. break;
  808. case PHP_OPENSSL_CIPHER_RC2_128:
  809. return EVP_rc2_cbc();
  810. break;
  811. #endif
  812. #ifndef OPENSSL_NO_DES
  813. case PHP_OPENSSL_CIPHER_DES:
  814. return EVP_des_cbc();
  815. break;
  816. case PHP_OPENSSL_CIPHER_3DES:
  817. return EVP_des_ede3_cbc();
  818. break;
  819. #endif
  820. default:
  821. return NULL;
  822. break;
  823. }
  824. }
  825. /* }}} */
  826. /* {{{ PHP_MINIT_FUNCTION
  827. */
  828. PHP_MINIT_FUNCTION(openssl)
  829. {
  830. char * config_filename;
  831. le_key = zend_register_list_destructors_ex(php_pkey_free, NULL, "OpenSSL key", module_number);
  832. le_x509 = zend_register_list_destructors_ex(php_x509_free, NULL, "OpenSSL X.509", module_number);
  833. le_csr = zend_register_list_destructors_ex(php_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
  834. SSL_library_init();
  835. OpenSSL_add_all_ciphers();
  836. OpenSSL_add_all_digests();
  837. OpenSSL_add_all_algorithms();
  838. ERR_load_ERR_strings();
  839. ERR_load_crypto_strings();
  840. ERR_load_EVP_strings();
  841. /* register a resource id number with openSSL so that we can map SSL -> stream structures in
  842. * openSSL callbacks */
  843. ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);
  844. REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT);
  845. REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT);
  846. /* purposes for cert purpose checking */
  847. REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT);
  848. REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
  849. REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
  850. REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT);
  851. REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT);
  852. REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT);
  853. #ifdef X509_PURPOSE_ANY
  854. REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT);
  855. #endif
  856. /* signature algorithm constants */
  857. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT);
  858. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT);
  859. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD4", OPENSSL_ALGO_MD4, CONST_CS|CONST_PERSISTENT);
  860. #ifdef HAVE_OPENSSL_MD2_H
  861. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_CS|CONST_PERSISTENT);
  862. #endif
  863. REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT);
  864. /* flags for S/MIME */
  865. REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT);
  866. REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT);
  867. REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT);
  868. REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT);
  869. REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT);
  870. REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT);
  871. REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT);
  872. REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
  873. REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
  874. REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
  875. REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
  876. REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
  877. REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
  878. /* Ciphers */
  879. #ifndef OPENSSL_NO_RC2
  880. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
  881. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT);
  882. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT);
  883. #endif
  884. #ifndef OPENSSL_NO_DES
  885. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT);
  886. REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT);
  887. #endif
  888. /* Values for key types */
  889. REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT);
  890. #ifndef NO_DSA
  891. REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT);
  892. #endif
  893. REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT);
  894. #ifdef EVP_PKEY_EC
  895. REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT);
  896. #endif
  897. #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
  898. /* SNI support included in OpenSSL >= 0.9.8j */
  899. REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT);
  900. #endif
  901. /* Determine default SSL configuration file */
  902. config_filename = getenv("OPENSSL_CONF");
  903. if (config_filename == NULL) {
  904. config_filename = getenv("SSLEAY_CONF");
  905. }
  906. /* default to 'openssl.cnf' if no environment variable is set */
  907. if (config_filename == NULL) {
  908. snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename), "%s/%s",
  909. X509_get_default_cert_area(),
  910. "openssl.cnf");
  911. } else {
  912. strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename));
  913. }
  914. php_stream_xport_register("ssl", php_openssl_ssl_socket_factory TSRMLS_CC);
  915. php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory TSRMLS_CC);
  916. php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory TSRMLS_CC);
  917. php_stream_xport_register("tls", php_openssl_ssl_socket_factory TSRMLS_CC);
  918. /* override the default tcp socket provider */
  919. php_stream_xport_register("tcp", php_openssl_ssl_socket_factory TSRMLS_CC);
  920. php_register_url_stream_wrapper("https", &php_stream_http_wrapper TSRMLS_CC);
  921. php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper TSRMLS_CC);
  922. return SUCCESS;
  923. }
  924. /* }}} */
  925. /* {{{ PHP_MINFO_FUNCTION
  926. */
  927. PHP_MINFO_FUNCTION(openssl)
  928. {
  929. php_info_print_table_start();
  930. php_info_print_table_row(2, "OpenSSL support", "enabled");
  931. php_info_print_table_row(2, "OpenSSL Library Version", SSLeay_version(SSLEAY_VERSION));
  932. php_info_print_table_row(2, "OpenSSL Header Version", OPENSSL_VERSION_TEXT);
  933. php_info_print_table_end();
  934. }
  935. /* }}} */
  936. /* {{{ PHP_MSHUTDOWN_FUNCTION
  937. */
  938. PHP_MSHUTDOWN_FUNCTION(openssl)
  939. {
  940. EVP_cleanup();
  941. php_unregister_url_stream_wrapper("https" TSRMLS_CC);
  942. php_unregister_url_stream_wrapper("ftps" TSRMLS_CC);
  943. php_stream_xport_unregister("ssl" TSRMLS_CC);
  944. php_stream_xport_unregister("sslv2" TSRMLS_CC);
  945. php_stream_xport_unregister("sslv3" TSRMLS_CC);
  946. php_stream_xport_unregister("tls" TSRMLS_CC);
  947. /* reinstate the default tcp handler */
  948. php_stream_xport_register("tcp", php_stream_generic_socket_factory TSRMLS_CC);
  949. return SUCCESS;
  950. }
  951. /* }}} */
  952. /* {{{ x509 cert functions */
  953. /* {{{ php_openssl_x509_from_zval
  954. Given a zval, coerce it into an X509 object.
  955. The zval can be:
  956. . X509 resource created using openssl_read_x509()
  957. . if it starts with file:// then it will be interpreted as the path to that cert
  958. . it will be interpreted as the cert data
  959. If you supply makeresource, the result will be registered as an x509 resource and
  960. it's value returned in makeresource.
  961. */
  962. static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC)
  963. {
  964. X509 *cert = NULL;
  965. if (resourceval) {
  966. *resourceval = -1;
  967. }
  968. if (Z_TYPE_PP(val) == IS_RESOURCE) {
  969. /* is it an x509 resource ? */
  970. void * what;
  971. int type;
  972. what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509", &type, 1, le_x509);
  973. if (!what) {
  974. return NULL;
  975. }
  976. /* this is so callers can decide if they should free the X509 */
  977. if (resourceval) {
  978. *resourceval = Z_LVAL_PP(val);
  979. }
  980. if (type == le_x509) {
  981. return (X509*)what;
  982. }
  983. /* other types could be used here - eg: file pointers and read in the data from them */
  984. return NULL;
  985. }
  986. if (!(Z_TYPE_PP(val) == IS_STRING || Z_TYPE_PP(val) == IS_OBJECT)) {
  987. return NULL;
  988. }
  989. /* force it to be a string and check if it refers to a file */
  990. convert_to_string_ex(val);
  991. if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) {
  992. /* read cert from the named file */
  993. BIO *in;
  994. if (php_openssl_safe_mode_chk(Z_STRVAL_PP(val) + (sizeof("file://") - 1) TSRMLS_CC)) {
  995. return NULL;
  996. }
  997. in = BIO_new_file(Z_STRVAL_PP(val) + (sizeof("file://") - 1), "r");
  998. if (in == NULL) {
  999. return NULL;
  1000. }
  1001. cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
  1002. BIO_free(in);
  1003. } else {
  1004. BIO *in;
  1005. in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
  1006. if (in == NULL) {
  1007. return NULL;
  1008. }
  1009. #ifdef TYPEDEF_D2I_OF
  1010. cert = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
  1011. #else
  1012. cert = (X509 *) PEM_ASN1_read_bio((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
  1013. #endif
  1014. BIO_free(in);
  1015. }
  1016. if (cert && makeresource && resourceval) {
  1017. *resourceval = zend_list_insert(cert, le_x509);
  1018. }
  1019. return cert;
  1020. }
  1021. /* }}} */
  1022. /* {{{ proto bool openssl_x509_export_to_file(mixed x509, string outfilename [, bool notext = true])
  1023. Exports a CERT to file or a var */
  1024. PHP_FUNCTION(openssl_x509_export_to_file)
  1025. {
  1026. X509 * cert;
  1027. zval ** zcert;
  1028. zend_bool notext = 1;
  1029. BIO * bio_out;
  1030. long certresource;
  1031. char * filename;
  1032. int filename_len;
  1033. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs|b", &zcert, &filename, &filename_len, &notext) == FAILURE) {
  1034. return;
  1035. }
  1036. RETVAL_FALSE;
  1037. cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
  1038. if (cert == NULL) {
  1039. php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
  1040. return;
  1041. }
  1042. if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
  1043. return;
  1044. }
  1045. bio_out = BIO_new_file(filename, "w");
  1046. if (bio_out) {
  1047. if (!notext) {
  1048. X509_print(bio_out, cert);
  1049. }
  1050. PEM_write_bio_X509(bio_out, cert);
  1051. RETVAL_TRUE;
  1052. } else {
  1053. php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename);
  1054. }
  1055. if (certresource == -1 && cert) {
  1056. X509_free(cert);
  1057. }
  1058. BIO_free(bio_out);
  1059. }
  1060. /* }}} */
  1061. /* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true])
  1062. Exports a CERT to file or a var */
  1063. PHP_FUNCTION(openssl_x509_export)
  1064. {
  1065. X509 * cert;
  1066. zval ** zcert, *zout;
  1067. zend_bool notext = 1;
  1068. BIO * bio_out;
  1069. long certresource;
  1070. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zz|b", &zcert, &zout, &notext) == FAILURE) {
  1071. return;
  1072. }
  1073. RETVAL_FALSE;
  1074. cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
  1075. if (cert == NULL) {
  1076. php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
  1077. return;
  1078. }
  1079. bio_out = BIO_new(BIO_s_mem());
  1080. if (!notext) {
  1081. X509_print(bio_out, cert);
  1082. }
  1083. if (PEM_write_bio_X509(bio_out, cert)) {
  1084. BUF_MEM *bio_buf;
  1085. zval_dtor(zout);
  1086. BIO_get_mem_ptr(bio_out, &bio_buf);
  1087. ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
  1088. RETVAL_TRUE;
  1089. }
  1090. if (certresource == -1 && cert) {
  1091. X509_free(cert);
  1092. }
  1093. BIO_free(bio_out);
  1094. }
  1095. /* }}} */
  1096. /* {{{ proto bool openssl_x509_check_private_key(mixed cert, mixed key)
  1097. Checks if a private key corresponds to a CERT */
  1098. PHP_FUNCTION(openssl_x509_check_private_key)
  1099. {
  1100. zval ** zcert, **zkey;
  1101. X509 * cert = NULL;
  1102. EVP_PKEY * key = NULL;
  1103. long certresource = -1, keyresource = -1;
  1104. RETVAL_FALSE;
  1105. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &zcert, &zkey) == FAILURE) {
  1106. return;
  1107. }
  1108. cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
  1109. if (cert == NULL) {
  1110. RETURN_FALSE;
  1111. }
  1112. key = php_openssl_evp_from_zval(zkey, 0, "", 1, &keyresource TSRMLS_CC);
  1113. if (key) {
  1114. RETVAL_BOOL(X509_check_private_key(cert, key));
  1115. }
  1116. if (keyresource == -1 && key) {
  1117. EVP_PKEY_free(key);
  1118. }
  1119. if (certresource == -1 && cert) {
  1120. X509_free(cert);
  1121. }
  1122. }
  1123. /* }}} */
  1124. /* {{{ proto array openssl_x509_parse(mixed x509 [, bool shortnames=true])
  1125. Returns an array of the fields/values of the CERT */
  1126. PHP_FUNCTION(openssl_x509_parse)
  1127. {
  1128. zval ** zcert;
  1129. X509 * cert = NULL;
  1130. long certresource = -1;
  1131. int i;
  1132. zend_bool useshortnames = 1;
  1133. char * tmpstr;
  1134. zval * subitem;
  1135. X509_EXTENSION *extension;
  1136. char *extname;
  1137. BIO *bio_out;
  1138. BUF_MEM *bio_buf;
  1139. char buf[256];
  1140. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcert, &useshortnames) == FAILURE) {
  1141. return;
  1142. }
  1143. cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
  1144. if (cert == NULL) {
  1145. RETURN_FALSE;
  1146. }
  1147. array_init(return_value);
  1148. if (cert->name) {
  1149. add_assoc_string(return_value, "name", cert->name, 1);
  1150. }
  1151. /* add_assoc_bool(return_value, "valid", cert->valid); */
  1152. add_assoc_name_entry(return_value, "subject", X509_get_subject_name(cert), useshortnames TSRMLS_CC);
  1153. /* hash as used in CA directories to lookup cert by subject name */
  1154. {
  1155. char buf[32];
  1156. snprintf(buf, sizeof(buf), "%08lx", X509_subject_name_hash(cert));
  1157. add_assoc_string(return_value, "hash", buf, 1);
  1158. }
  1159. add_assoc_name_entry(return_value, "issuer", X509_get_issuer_name(cert), useshortnames TSRMLS_CC);
  1160. add_assoc_long(return_value, "version", X509_get_version(cert));
  1161. add_assoc_string(return_value, "serialNumber", i2s_ASN1_INTEGER(NULL, X509_get_serialNumber(cert)), 1);
  1162. add_assoc_asn1_string(return_value, "validFrom", X509_get_notBefore(cert));
  1163. add_assoc_asn1_string(return_value, "validTo", X509_get_notAfter(cert));
  1164. add_assoc_long(return_value, "validFrom_time_t", asn1_time_to_time_t(X509_get_notBefore(cert) TSRMLS_CC));
  1165. add_assoc_long(return_value, "validTo_time_t", asn1_time_to_time_t(X509_get_notAfter(cert) TSRMLS_CC));
  1166. tmpstr = (char *)X509_alias_get0(cert, NULL);
  1167. if (tmpstr) {
  1168. add_assoc_string(return_value, "alias", tmpstr, 1);
  1169. }
  1170. /*
  1171. add_assoc_long(return_value, "signaturetypeLONG", X509_get_signature_type(cert));
  1172. add_assoc_string(return_value, "signaturetype", OBJ_nid2sn(X509_get_signature_type(cert)), 1);
  1173. add_assoc_string(return_value, "signaturetypeLN", OBJ_nid2ln(X509_get_signature_type(cert)), 1);
  1174. */
  1175. MAKE_STD_ZVAL(subitem);
  1176. array_init(subitem);
  1177. /* NOTE: the purposes are added as integer keys - the keys match up to the X509_PURPOSE_SSL_XXX defines
  1178. in x509v3.h */
  1179. for (i = 0; i < X509_PURPOSE_get_count(); i++) {
  1180. int id, purpset;
  1181. char * pname;
  1182. X509_PURPOSE * purp;
  1183. zval * subsub;
  1184. MAKE_STD_ZVAL(subsub);
  1185. array_init(subsub);
  1186. purp = X509_PURPOSE_get0(i);
  1187. id = X509_PURPOSE_get_id(purp);
  1188. purpset = X509_check_purpose(cert, id, 0);
  1189. add_index_bool(subsub, 0, purpset);
  1190. purpset = X509_check_purpose(cert, id, 1);
  1191. add_index_bool(subsub, 1, purpset);
  1192. pname = useshortnames ? X509_PURPOSE_get0_sname(purp) : X509_PURPOSE_get0_name(purp);
  1193. add_index_string(subsub, 2, pname, 1);
  1194. /* NOTE: if purpset > 1 then it's a warning - we should mention it ? */
  1195. add_index_zval(subitem, id, subsub);
  1196. }
  1197. add_assoc_zval(return_value, "purposes", subitem);
  1198. MAKE_STD_ZVAL(subitem);
  1199. array_init(subitem);
  1200. for (i = 0; i < X509_get_ext_count(cert); i++) {
  1201. extension = X509_get_ext(cert, i);
  1202. if (OBJ_obj2nid(X509_EXTENSION_get_object(extension)) != NID_undef) {
  1203. extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension)));
  1204. } else {
  1205. OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1);
  1206. extname = buf;
  1207. }
  1208. bio_out = BIO_new(BIO_s_mem());
  1209. if (X509V3_EXT_print(bio_out, extension, 0, 0)) {
  1210. BIO_get_mem_ptr(bio_out, &bio_buf);
  1211. add_assoc_stringl(subitem, extname, bio_buf->data, bio_buf->length, 1);
  1212. } else {
  1213. add_assoc_asn1_string(subitem, extname, X509_EXTENSION_get_data(extension));
  1214. }
  1215. BIO_free(bio_out);
  1216. }
  1217. add_assoc_zval(return_value, "extensions", subitem);
  1218. if (certresource == -1 && cert) {
  1219. X509_free(cert);
  1220. }
  1221. }
  1222. /* }}} */
  1223. /* {{{ load_all_certs_from_file */
  1224. static STACK_OF(X509) * load_all_certs_from_file(char *certfile)
  1225. {
  1226. STACK_OF(X509_INFO) *sk=NULL;
  1227. STACK_OF(X509) *stack=NULL, *ret=NULL;
  1228. BIO *in=NULL;
  1229. X509_INFO *xi;
  1230. TSRMLS_FETCH();
  1231. if(!(stack = sk_X509_new_null())) {
  1232. php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure");
  1233. goto end;
  1234. }
  1235. if (php_openssl_safe_mode_chk(certfile TSRMLS_CC)) {
  1236. sk_X509_free(stack);
  1237. goto end;
  1238. }
  1239. if(!(in=BIO_new_file(certfile, "r"))) {
  1240. php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening the file, %s", certfile);
  1241. sk_X509_free(stack);
  1242. goto end;
  1243. }
  1244. /* This loads from a file, a stack of x509/crl/pkey sets */
  1245. if(!(sk=PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) {
  1246. php_error_docref(NULL TSRMLS_CC, E_WARNING, "error reading the file, %s", certfile);
  1247. sk_X509_free(stack);
  1248. goto end;
  1249. }
  1250. /* scan over it and pull out the certs */
  1251. while (sk_X509_INFO_num(sk)) {
  1252. xi=sk_X509_INFO_shift(sk);
  1253. if (xi->x509 != NULL) {
  1254. sk_X509_push(stack,xi->x509);
  1255. xi->x509=NULL;
  1256. }
  1257. X509_INFO_free(xi);
  1258. }
  1259. if(!sk_X509_num(stack)) {
  1260. php_error_docref(NULL TSRMLS_CC, E_WARNING, "no certificates in file, %s", certfile);
  1261. sk_X509_free(stack);
  1262. goto end;
  1263. }
  1264. ret=stack;
  1265. end:
  1266. BIO_free(in);
  1267. sk_X509_INFO_free(sk);
  1268. return ret;
  1269. }
  1270. /* }}} */
  1271. /* {{{ check_cert */
  1272. static int check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedchain, int purpose)
  1273. {
  1274. int ret=0;
  1275. X509_STORE_CTX *csc;
  1276. TSRMLS_FETCH();
  1277. csc = X509_STORE_CTX_new();
  1278. if (csc == NULL) {
  1279. php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure");
  1280. return 0;
  1281. }
  1282. X509_STORE_CTX_init(csc, ctx, x, untrustedchain);
  1283. if(purpose >= 0) {
  1284. X509_STORE_CTX_set_purpose(csc, purpose);
  1285. }
  1286. ret = X509_verify_cert(csc);
  1287. X509_STORE_CTX_free(csc);
  1288. return ret;
  1289. }
  1290. /* }}} */
  1291. /* {{{ proto int openssl_x509_checkpurpose(mixed x509cert, int purpose, array cainfo [, string untrustedfile])
  1292. Checks the CERT to see if it can be used for the purpose in purpose. cainfo holds information about trusted CAs */
  1293. PHP_FUNCTION(openssl_x509_checkpurpose)
  1294. {
  1295. zval ** zcert, * zcainfo = NULL;
  1296. X509_STORE * cainfo = NULL;
  1297. X509 * cert = NULL;
  1298. long certresource = -1;
  1299. STACK_OF(X509) * untrustedchain = NULL;
  1300. long purpose;
  1301. char * untrusted = NULL;
  1302. int untrusted_len = 0, ret;
  1303. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|a!s", &zcert, &purpose, &zcainfo, &untrusted, &untrusted_len) == FAILURE) {
  1304. return;
  1305. }
  1306. RETVAL_LONG(-1);
  1307. if (untrusted) {
  1308. untrustedchain = load_all_certs_from_file(untrusted);
  1309. if (untrustedchain == NULL) {
  1310. goto clean_exit;
  1311. }
  1312. }
  1313. cainfo = setup_verify(zcainfo TSRMLS_CC);
  1314. if (cainfo == NULL) {
  1315. goto clean_exit;
  1316. }
  1317. cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
  1318. if (cert == NULL) {
  1319. goto clean_exit;
  1320. }
  1321. ret = check_cert(cainfo, cert, untrustedchain, purpose);
  1322. if (ret != 0 && ret != 1) {
  1323. RETVAL_LONG(ret);
  1324. } else {
  1325. RETVAL_BOOL(ret);
  1326. }
  1327. clean_exit:
  1328. if (certresource == 1 && cert) {
  1329. X509_free(cert);
  1330. }
  1331. if (cainfo) {
  1332. X509_STORE_free(cainfo);
  1333. }
  1334. if (untrustedchain) {
  1335. sk_X509_pop_free(untrustedchain, X509_free);
  1336. }
  1337. }
  1338. /* }}} */
  1339. /* {{{ setup_verify
  1340. * calist is an array containing file and directory names. create a
  1341. * certificate store and add those certs to it for use in verification.
  1342. */
  1343. static X509_STORE * setup_verify(zval * calist TSRMLS_DC)
  1344. {
  1345. X509_STORE *store;
  1346. X509_LOOKUP * dir_lookup, * file_lookup;
  1347. HashPosition pos;
  1348. int ndirs = 0, nfiles = 0;
  1349. store = X509_STORE_new();
  1350. if (store == NULL) {
  1351. return NULL;
  1352. }
  1353. if (calist && (Z_TYPE_P(calist) == IS_ARRAY)) {
  1354. zend_hash_internal_pointer_reset_ex(HASH_OF(calist), &pos);
  1355. for (;; zend_hash_move_forward_ex(HASH_OF(calist), &pos)) {
  1356. zval ** item;
  1357. struct stat sb;
  1358. if (zend_hash_get_current_data_ex(HASH_OF(calist), (void**)&item, &pos) == FAILURE) {
  1359. break;
  1360. }
  1361. convert_to_string_ex(item);
  1362. if (VCWD_STAT(Z_STRVAL_PP(item), &sb) == -1) {
  1363. php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to stat %s", Z_STRVAL_PP(item));
  1364. continue;
  1365. }
  1366. if ((sb.st_mode & S_IFREG) == S_IFREG) {
  1367. file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
  1368. if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) {
  1369. php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading file %s", Z_STRVAL_PP(item));
  1370. } else {
  1371. nfiles++;
  1372. }
  1373. file_lookup = NULL;
  1374. } else {
  1375. dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
  1376. if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) {
  1377. php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading directory %s", Z_STRVAL_PP(item));
  1378. } else {
  1379. ndirs++;
  1380. }
  1381. dir_lookup = NULL;
  1382. }
  1383. }
  1384. }
  1385. if (nfiles == 0) {
  1386. file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
  1387. if (file_lookup) {
  1388. X509_LOOKUP_load_file(file_lookup, NULL, X509_FILETYPE_DEFAULT);
  1389. }
  1390. }
  1391. if (ndirs == 0) {
  1392. dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
  1393. if (dir_lookup) {
  1394. X509_LOOKUP_add_dir(dir_lookup, NULL, X509_FILETYPE_DEFAULT);
  1395. }
  1396. }
  1397. return store;
  1398. }
  1399. /* }}} */
  1400. /* {{{ proto resource openssl_x509_read(mixed cert)
  1401. Reads X.509 certificates */
  1402. PHP_FUNCTION(openssl_x509_read)
  1403. {
  1404. zval **cert;
  1405. X509 *x509;
  1406. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &cert) == FAILURE) {
  1407. return;
  1408. }
  1409. Z_TYPE_P(return_value) = IS_RESOURCE;
  1410. x509 = php_openssl_x509_from_zval(cert, 1, &Z_LVAL_P(return_value) TSRMLS_CC);
  1411. if (x509 == NULL) {
  1412. php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied parameter cannot be coerced into an X509 certificate!");
  1413. RETURN_FALSE;
  1414. }
  1415. }
  1416. /* }}} */
  1417. /* {{{ proto void openssl_x509_free(resource x509)
  1418. Frees X.509 certificates */
  1419. PHP_FUNCTION(openssl_x509_free)
  1420. {
  1421. zval *x509;
  1422. X509 *cert;
  1423. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &x509) == FAILURE) {
  1424. return;
  1425. }
  1426. ZEND_FETCH_RESOURCE(cert, X509 *, &x509, -1, "OpenSSL X.509", le_x509);
  1427. zend_list_delete(Z_LVAL_P(x509));
  1428. }
  1429. /* }}} */
  1430. /* }}} */
  1431. /* Pop all X509 from Stack and free them, free the…