1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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 :
23 : /* $Id: openssl.c 290191 2009-11-03 21:26:39Z guenter $ */
24 :
25 : #ifdef HAVE_CONFIG_H
26 : #include "config.h"
27 : #endif
28 :
29 : #include "php.h"
30 : #include "php_openssl.h"
31 :
32 : /* PHP Includes */
33 : #include "ext/standard/file.h"
34 : #include "ext/standard/info.h"
35 : #include "ext/standard/php_fopen_wrappers.h"
36 : #include "ext/standard/md5.h"
37 : #include "ext/standard/base64.h"
38 :
39 : /* OpenSSL includes */
40 : #include <openssl/evp.h>
41 : #include <openssl/x509.h>
42 : #include <openssl/x509v3.h>
43 : #include <openssl/crypto.h>
44 : #include <openssl/pem.h>
45 : #include <openssl/err.h>
46 : #include <openssl/conf.h>
47 : #include <openssl/rand.h>
48 : #include <openssl/ssl.h>
49 : #include <openssl/pkcs12.h>
50 :
51 : /* Common */
52 : #include <time.h>
53 :
54 : #ifdef NETWARE
55 : #define timezone _timezone /* timezone is called _timezone in LibC */
56 : #endif
57 :
58 : #define DEFAULT_KEY_LENGTH 512
59 : #define MIN_KEY_LENGTH 384
60 :
61 : #define OPENSSL_ALGO_SHA1 1
62 : #define OPENSSL_ALGO_MD5 2
63 : #define OPENSSL_ALGO_MD4 3
64 : #define OPENSSL_ALGO_MD2 4
65 : #define OPENSSL_ALGO_DSS1 5
66 :
67 : #define DEBUG_SMIME 0
68 :
69 : /* FIXME: Use the openssl constants instead of
70 : * enum. It is now impossible to match real values
71 : * against php constants. Also sorry to break the
72 : * enum principles here, BC...
73 : */
74 : enum php_openssl_key_type {
75 : OPENSSL_KEYTYPE_RSA,
76 : OPENSSL_KEYTYPE_DSA,
77 : OPENSSL_KEYTYPE_DH,
78 : OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA,
79 : #ifdef EVP_PKEY_EC
80 : OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH +1
81 : #endif
82 : };
83 :
84 : enum php_openssl_cipher_type {
85 : PHP_OPENSSL_CIPHER_RC2_40,
86 : PHP_OPENSSL_CIPHER_RC2_128,
87 : PHP_OPENSSL_CIPHER_RC2_64,
88 : PHP_OPENSSL_CIPHER_DES,
89 : PHP_OPENSSL_CIPHER_3DES,
90 :
91 : PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40
92 : };
93 :
94 : PHP_FUNCTION(openssl_get_md_methods);
95 : PHP_FUNCTION(openssl_get_cipher_methods);
96 :
97 : PHP_FUNCTION(openssl_digest);
98 : PHP_FUNCTION(openssl_encrypt);
99 : PHP_FUNCTION(openssl_decrypt);
100 :
101 : PHP_FUNCTION(openssl_dh_compute_key);
102 : PHP_FUNCTION(openssl_random_pseudo_bytes);
103 :
104 : /* {{{ arginfo */
105 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 0, 2)
106 : ZEND_ARG_INFO(0, x509)
107 : ZEND_ARG_INFO(0, outfilename)
108 : ZEND_ARG_INFO(0, notext)
109 : ZEND_END_ARG_INFO()
110 :
111 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export, 0, 0, 2)
112 : ZEND_ARG_INFO(0, x509)
113 : ZEND_ARG_INFO(1, out)
114 : ZEND_ARG_INFO(0, notext)
115 : ZEND_END_ARG_INFO()
116 :
117 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_check_private_key, 0)
118 : ZEND_ARG_INFO(0, cert)
119 : ZEND_ARG_INFO(0, key)
120 : ZEND_END_ARG_INFO()
121 :
122 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_parse, 0)
123 : ZEND_ARG_INFO(0, x509)
124 : ZEND_ARG_INFO(0, shortname)
125 : ZEND_END_ARG_INFO()
126 :
127 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_checkpurpose, 0, 0, 3)
128 : ZEND_ARG_INFO(0, x509cert)
129 : ZEND_ARG_INFO(0, purpose)
130 : ZEND_ARG_INFO(0, cainfo) /* array */
131 : ZEND_ARG_INFO(0, untrustedfile)
132 : ZEND_END_ARG_INFO()
133 :
134 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_read, 0)
135 : ZEND_ARG_INFO(0, cert)
136 : ZEND_END_ARG_INFO()
137 :
138 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_free, 0)
139 : ZEND_ARG_INFO(0, x509)
140 : ZEND_END_ARG_INFO()
141 :
142 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs12_export_to_file, 0, 0, 4)
143 : ZEND_ARG_INFO(0, x509)
144 : ZEND_ARG_INFO(0, filename)
145 : ZEND_ARG_INFO(0, priv_key)
146 : ZEND_ARG_INFO(0, pass)
147 : ZEND_ARG_INFO(0, args) /* array */
148 : ZEND_END_ARG_INFO()
149 :
150 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_export, 0)
151 : ZEND_ARG_INFO(0, x509)
152 : ZEND_ARG_INFO(1, out)
153 : ZEND_ARG_INFO(0, priv_key)
154 : ZEND_ARG_INFO(0, pass)
155 : ZEND_ARG_INFO(0, args) /* array */
156 : ZEND_END_ARG_INFO()
157 :
158 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_read, 0)
159 : ZEND_ARG_INFO(0, PKCS12)
160 : ZEND_ARG_INFO(1, certs) /* array */
161 : ZEND_ARG_INFO(0, pass)
162 : ZEND_END_ARG_INFO()
163 :
164 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export_to_file, 0, 0, 2)
165 : ZEND_ARG_INFO(0, csr)
166 : ZEND_ARG_INFO(0, outfilename)
167 : ZEND_ARG_INFO(0, notext)
168 : ZEND_END_ARG_INFO()
169 :
170 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export, 0, 0, 2)
171 : ZEND_ARG_INFO(0, csr)
172 : ZEND_ARG_INFO(1, out)
173 : ZEND_ARG_INFO(0, notext)
174 : ZEND_END_ARG_INFO()
175 :
176 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_sign, 0, 0, 4)
177 : ZEND_ARG_INFO(0, csr)
178 : ZEND_ARG_INFO(0, x509)
179 : ZEND_ARG_INFO(0, priv_key)
180 : ZEND_ARG_INFO(0, days)
181 : ZEND_ARG_INFO(0, config_args) /* array */
182 : ZEND_ARG_INFO(0, serial)
183 : ZEND_END_ARG_INFO()
184 :
185 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_new, 0, 0, 2)
186 : ZEND_ARG_INFO(0, dn) /* array */
187 : ZEND_ARG_INFO(1, privkey)
188 : ZEND_ARG_INFO(0, configargs)
189 : ZEND_ARG_INFO(0, extraattribs)
190 : ZEND_END_ARG_INFO()
191 :
192 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_csr_get_subject, 0)
193 : ZEND_ARG_INFO(0, csr)
194 : ZEND_END_ARG_INFO()
195 :
196 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_csr_get_public_key, 0)
197 : ZEND_ARG_INFO(0, csr)
198 : ZEND_END_ARG_INFO()
199 :
200 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_new, 0, 0, 0)
201 : ZEND_ARG_INFO(0, configargs) /* array */
202 : ZEND_END_ARG_INFO()
203 :
204 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export_to_file, 0, 0, 2)
205 : ZEND_ARG_INFO(0, key)
206 : ZEND_ARG_INFO(0, outfilename)
207 : ZEND_ARG_INFO(0, passphrase)
208 : ZEND_ARG_INFO(0, config_args) /* array */
209 : ZEND_END_ARG_INFO()
210 :
211 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export, 0, 0, 2)
212 : ZEND_ARG_INFO(0, key)
213 : ZEND_ARG_INFO(1, out)
214 : ZEND_ARG_INFO(0, passphrase)
215 : ZEND_ARG_INFO(0, config_args) /* array */
216 : ZEND_END_ARG_INFO()
217 :
218 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_public, 0)
219 : ZEND_ARG_INFO(0, cert)
220 : ZEND_END_ARG_INFO()
221 :
222 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_free, 0)
223 : ZEND_ARG_INFO(0, key)
224 : ZEND_END_ARG_INFO()
225 :
226 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_get_private, 0, 0, 1)
227 : ZEND_ARG_INFO(0, key)
228 : ZEND_ARG_INFO(0, passphrase)
229 : ZEND_END_ARG_INFO()
230 :
231 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_details, 0)
232 : ZEND_ARG_INFO(0, key)
233 : ZEND_END_ARG_INFO()
234 :
235 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_verify, 0, 0, 2)
236 : ZEND_ARG_INFO(0, filename)
237 : ZEND_ARG_INFO(0, flags)
238 : ZEND_ARG_INFO(0, signerscerts)
239 : ZEND_ARG_INFO(0, cainfo) /* array */
240 : ZEND_ARG_INFO(0, extracerts)
241 : ZEND_ARG_INFO(0, content)
242 : ZEND_END_ARG_INFO()
243 :
244 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_encrypt, 0, 0, 4)
245 : ZEND_ARG_INFO(0, infile)
246 : ZEND_ARG_INFO(0, outfile)
247 : ZEND_ARG_INFO(0, recipcerts)
248 : ZEND_ARG_INFO(0, headers) /* array */
249 : ZEND_ARG_INFO(0, flags)
250 : ZEND_ARG_INFO(0, cipher)
251 : ZEND_END_ARG_INFO()
252 :
253 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_sign, 0, 0, 5)
254 : ZEND_ARG_INFO(0, infile)
255 : ZEND_ARG_INFO(0, outfile)
256 : ZEND_ARG_INFO(0, signcert)
257 : ZEND_ARG_INFO(0, signkey)
258 : ZEND_ARG_INFO(0, headers) /* array */
259 : ZEND_ARG_INFO(0, flags)
260 : ZEND_ARG_INFO(0, extracertsfilename)
261 : ZEND_END_ARG_INFO()
262 :
263 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_decrypt, 0, 0, 3)
264 : ZEND_ARG_INFO(0, infilename)
265 : ZEND_ARG_INFO(0, outfilename)
266 : ZEND_ARG_INFO(0, recipcert)
267 : ZEND_ARG_INFO(0, recipkey)
268 : ZEND_END_ARG_INFO()
269 :
270 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_encrypt, 0, 0, 3)
271 : ZEND_ARG_INFO(0, data)
272 : ZEND_ARG_INFO(1, crypted)
273 : ZEND_ARG_INFO(0, key)
274 : ZEND_ARG_INFO(0, padding)
275 : ZEND_END_ARG_INFO()
276 :
277 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_decrypt, 0, 0, 3)
278 : ZEND_ARG_INFO(0, data)
279 : ZEND_ARG_INFO(1, crypted)
280 : ZEND_ARG_INFO(0, key)
281 : ZEND_ARG_INFO(0, padding)
282 : ZEND_END_ARG_INFO()
283 :
284 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_encrypt, 0, 0, 3)
285 : ZEND_ARG_INFO(0, data)
286 : ZEND_ARG_INFO(1, crypted)
287 : ZEND_ARG_INFO(0, key)
288 : ZEND_ARG_INFO(0, padding)
289 : ZEND_END_ARG_INFO()
290 :
291 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_decrypt, 0, 0, 3)
292 : ZEND_ARG_INFO(0, data)
293 : ZEND_ARG_INFO(1, crypted)
294 : ZEND_ARG_INFO(0, key)
295 : ZEND_ARG_INFO(0, padding)
296 : ZEND_END_ARG_INFO()
297 :
298 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_error_string, 0)
299 : ZEND_END_ARG_INFO()
300 :
301 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_sign, 0, 0, 3)
302 : ZEND_ARG_INFO(0, data)
303 : ZEND_ARG_INFO(1, signature)
304 : ZEND_ARG_INFO(0, key)
305 : ZEND_ARG_INFO(0, method)
306 : ZEND_END_ARG_INFO()
307 :
308 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_verify, 0, 0, 3)
309 : ZEND_ARG_INFO(0, data)
310 : ZEND_ARG_INFO(0, signature)
311 : ZEND_ARG_INFO(0, key)
312 : ZEND_ARG_INFO(0, method)
313 : ZEND_END_ARG_INFO()
314 :
315 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_seal, 0)
316 : ZEND_ARG_INFO(0, data)
317 : ZEND_ARG_INFO(1, sealdata)
318 : ZEND_ARG_INFO(1, ekeys) /* arary */
319 : ZEND_ARG_INFO(0, pubkeys) /* array */
320 : ZEND_END_ARG_INFO()
321 :
322 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_open, 0)
323 : ZEND_ARG_INFO(0, data)
324 : ZEND_ARG_INFO(1, opendata)
325 : ZEND_ARG_INFO(0, ekey)
326 : ZEND_ARG_INFO(0, privkey)
327 : ZEND_END_ARG_INFO()
328 :
329 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_md_methods, 0, 0, 0)
330 : ZEND_ARG_INFO(0, aliases)
331 : ZEND_END_ARG_INFO()
332 :
333 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_cipher_methods, 0, 0, 0)
334 : ZEND_ARG_INFO(0, aliases)
335 : ZEND_END_ARG_INFO()
336 :
337 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_digest, 0, 0, 2)
338 : ZEND_ARG_INFO(0, data)
339 : ZEND_ARG_INFO(0, method)
340 : ZEND_ARG_INFO(0, raw_output)
341 : ZEND_END_ARG_INFO()
342 :
343 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_encrypt, 0, 0, 3)
344 : ZEND_ARG_INFO(0, data)
345 : ZEND_ARG_INFO(0, method)
346 : ZEND_ARG_INFO(0, password)
347 : ZEND_ARG_INFO(0, raw_output)
348 : ZEND_END_ARG_INFO()
349 :
350 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_decrypt, 0, 0, 3)
351 : ZEND_ARG_INFO(0, data)
352 : ZEND_ARG_INFO(0, method)
353 : ZEND_ARG_INFO(0, password)
354 : ZEND_ARG_INFO(0, raw_input)
355 : ZEND_END_ARG_INFO()
356 :
357 : ZEND_BEGIN_ARG_INFO(arginfo_openssl_dh_compute_key, 0)
358 : ZEND_ARG_INFO(0, pub_key)
359 : ZEND_ARG_INFO(0, dh_key)
360 : ZEND_END_ARG_INFO()
361 :
362 : ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_random_pseudo_bytes, 0, 0, 1)
363 : ZEND_ARG_INFO(0, length)
364 : ZEND_ARG_INFO(1, result_is_strong)
365 : ZEND_END_ARG_INFO()
366 : /* }}} */
367 :
368 : /* {{{ openssl_functions[]
369 : */
370 : const zend_function_entry openssl_functions[] = {
371 : /* public/private key functions */
372 : PHP_FE(openssl_pkey_free, arginfo_openssl_pkey_free)
373 : PHP_FE(openssl_pkey_new, arginfo_openssl_pkey_new)
374 : PHP_FE(openssl_pkey_export, arginfo_openssl_pkey_export)
375 : PHP_FE(openssl_pkey_export_to_file, arginfo_openssl_pkey_export_to_file)
376 : PHP_FE(openssl_pkey_get_private, arginfo_openssl_pkey_get_private)
377 : PHP_FE(openssl_pkey_get_public, arginfo_openssl_pkey_get_public)
378 : PHP_FE(openssl_pkey_get_details, arginfo_openssl_pkey_get_details)
379 :
380 : PHP_FALIAS(openssl_free_key, openssl_pkey_free, NULL)
381 : PHP_FALIAS(openssl_get_privatekey, openssl_pkey_get_private, NULL)
382 : PHP_FALIAS(openssl_get_publickey, openssl_pkey_get_public, NULL)
383 :
384 : /* x.509 cert funcs */
385 : PHP_FE(openssl_x509_read, arginfo_openssl_x509_read)
386 : PHP_FE(openssl_x509_free, arginfo_openssl_x509_free)
387 : PHP_FE(openssl_x509_parse, arginfo_openssl_x509_parse)
388 : PHP_FE(openssl_x509_checkpurpose, arginfo_openssl_x509_checkpurpose)
389 : PHP_FE(openssl_x509_check_private_key, arginfo_openssl_x509_check_private_key)
390 : PHP_FE(openssl_x509_export, arginfo_openssl_x509_export)
391 : PHP_FE(openssl_x509_export_to_file, arginfo_openssl_x509_export_to_file)
392 :
393 : /* PKCS12 funcs */
394 : PHP_FE(openssl_pkcs12_export, arginfo_openssl_pkcs12_export)
395 : PHP_FE(openssl_pkcs12_export_to_file, arginfo_openssl_pkcs12_export_to_file)
396 : PHP_FE(openssl_pkcs12_read, arginfo_openssl_pkcs12_read)
397 :
398 : /* CSR funcs */
399 : PHP_FE(openssl_csr_new, arginfo_openssl_csr_new)
400 : PHP_FE(openssl_csr_export, arginfo_openssl_csr_export)
401 : PHP_FE(openssl_csr_export_to_file, arginfo_openssl_csr_export_to_file)
402 : PHP_FE(openssl_csr_sign, arginfo_openssl_csr_sign)
403 : PHP_FE(openssl_csr_get_subject, arginfo_openssl_csr_get_subject)
404 : PHP_FE(openssl_csr_get_public_key, arginfo_openssl_csr_get_public_key)
405 :
406 : PHP_FE(openssl_digest, arginfo_openssl_digest)
407 : PHP_FE(openssl_encrypt, arginfo_openssl_encrypt)
408 : PHP_FE(openssl_decrypt, arginfo_openssl_decrypt)
409 : PHP_FE(openssl_sign, arginfo_openssl_sign)
410 : PHP_FE(openssl_verify, arginfo_openssl_verify)
411 : PHP_FE(openssl_seal, arginfo_openssl_seal)
412 : PHP_FE(openssl_open, arginfo_openssl_open)
413 :
414 : /* for S/MIME handling */
415 : PHP_FE(openssl_pkcs7_verify, arginfo_openssl_pkcs7_verify)
416 : PHP_FE(openssl_pkcs7_decrypt, arginfo_openssl_pkcs7_decrypt)
417 : PHP_FE(openssl_pkcs7_sign, arginfo_openssl_pkcs7_sign)
418 : PHP_FE(openssl_pkcs7_encrypt, arginfo_openssl_pkcs7_encrypt)
419 :
420 : PHP_FE(openssl_private_encrypt, arginfo_openssl_private_encrypt)
421 : PHP_FE(openssl_private_decrypt, arginfo_openssl_private_decrypt)
422 : PHP_FE(openssl_public_encrypt, arginfo_openssl_public_encrypt)
423 : PHP_FE(openssl_public_decrypt, arginfo_openssl_public_decrypt)
424 :
425 : PHP_FE(openssl_get_md_methods, arginfo_openssl_get_md_methods)
426 : PHP_FE(openssl_get_cipher_methods, arginfo_openssl_get_cipher_methods)
427 :
428 : PHP_FE(openssl_dh_compute_key, arginfo_openssl_dh_compute_key)
429 :
430 : PHP_FE(openssl_random_pseudo_bytes, arginfo_openssl_random_pseudo_bytes)
431 : PHP_FE(openssl_error_string, arginfo_openssl_error_string)
432 : {NULL, NULL, NULL}
433 : };
434 : /* }}} */
435 :
436 : /* {{{ openssl_module_entry
437 : */
438 : zend_module_entry openssl_module_entry = {
439 : STANDARD_MODULE_HEADER,
440 : "openssl",
441 : openssl_functions,
442 : PHP_MINIT(openssl),
443 : PHP_MSHUTDOWN(openssl),
444 : NULL,
445 : NULL,
446 : PHP_MINFO(openssl),
447 : NO_VERSION_YET,
448 : STANDARD_MODULE_PROPERTIES
449 : };
450 : /* }}} */
451 :
452 : #ifdef COMPILE_DL_OPENSSL
453 : ZEND_GET_MODULE(openssl)
454 : #endif
455 :
456 : static int le_key;
457 : static int le_x509;
458 : static int le_csr;
459 : static int ssl_stream_data_index;
460 :
461 : int php_openssl_get_x509_list_id(void) /* {{{ */
462 0 : {
463 0 : return le_x509;
464 : }
465 : /* }}} */
466 :
467 : /* {{{ resource destructors */
468 : static void php_pkey_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
469 21 : {
470 21 : EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr;
471 :
472 : assert(pkey != NULL);
473 :
474 21 : EVP_PKEY_free(pkey);
475 21 : }
476 :
477 : static void php_x509_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
478 9 : {
479 9 : X509 *x509 = (X509 *)rsrc->ptr;
480 9 : X509_free(x509);
481 9 : }
482 :
483 : static void php_csr_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
484 4 : {
485 4 : X509_REQ * csr = (X509_REQ*)rsrc->ptr;
486 4 : X509_REQ_free(csr);
487 4 : }
488 : /* }}} */
489 :
490 : /* {{{ openssl safe_mode & open_basedir checks */
491 : inline static int php_openssl_safe_mode_chk(char *filename TSRMLS_DC)
492 124 : {
493 124 : if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
494 0 : return -1;
495 : }
496 124 : if (php_check_open_basedir(filename TSRMLS_CC)) {
497 0 : return -1;
498 : }
499 :
500 124 : return 0;
501 : }
502 : /* }}} */
503 :
504 : /* openssl -> PHP "bridging" */
505 : /* true global; readonly after module startup */
506 : static char default_ssl_conf_filename[MAXPATHLEN];
507 :
508 : struct php_x509_request { /* {{{ */
509 : #if OPENSSL_VERSION_NUMBER >= 0x10000002L
510 : LHASH_OF(CONF_VALUE) * global_config; /* Global SSL config */
511 : LHASH_OF(CONF_VALUE) * req_config; /* SSL config for this request */
512 : #else
513 : LHASH * global_config; /* Global SSL config */
514 : LHASH * req_config; /* SSL config for this request */
515 : #endif
516 : const EVP_MD * md_alg;
517 : const EVP_MD * digest;
518 : char * section_name,
519 : * config_filename,
520 : * digest_name,
521 : * extensions_section,
522 : * request_extensions_section;
523 : int priv_key_bits;
524 : int priv_key_type;
525 :
526 : int priv_key_encrypt;
527 :
528 : EVP_PKEY * priv_key;
529 : };
530 : /* }}} */
531 :
532 : static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC);
533 : static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC);
534 : static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC);
535 : static X509_STORE * setup_verify(zval * calist TSRMLS_DC);
536 : static STACK_OF(X509) * load_all_certs_from_file(char *certfile);
537 : static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC);
538 : static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC);
539 :
540 : static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname TSRMLS_DC) /* {{{ */
541 13 : {
542 : zval *subitem, *subentries;
543 13 : int i, j = -1, last = -1, obj_cnt = 0;
544 : char *sname;
545 : int nid;
546 : X509_NAME_ENTRY * ne;
547 13 : ASN1_STRING * str = NULL;
548 : ASN1_OBJECT * obj;
549 :
550 13 : if (key != NULL) {
551 12 : MAKE_STD_ZVAL(subitem);
552 12 : array_init(subitem);
553 : } else {
554 1 : subitem = val;
555 : }
556 :
557 87 : for (i = 0; i < X509_NAME_entry_count(name); i++) {
558 : unsigned char *to_add;
559 : int to_add_len;
560 :
561 :
562 74 : ne = X509_NAME_get_entry(name, i);
563 74 : obj = X509_NAME_ENTRY_get_object(ne);
564 74 : nid = OBJ_obj2nid(obj);
565 74 : obj_cnt = 0;
566 :
567 74 : if (shortname) {
568 64 : sname = (char *) OBJ_nid2sn(nid);
569 : } else {
570 10 : sname = (char *) OBJ_nid2ln(nid);
571 : }
572 :
573 74 : MAKE_STD_ZVAL(subentries);
574 74 : array_init(subentries);
575 :
576 74 : last = -1;
577 : for (;;) {
578 150 : j = X509_NAME_get_index_by_OBJ(name, obj, last);
579 150 : if (j < 0) {
580 74 : if (last != -1) break;
581 : } else {
582 76 : obj_cnt++;
583 76 : ne = X509_NAME_get_entry(name, j);
584 76 : str = X509_NAME_ENTRY_get_data(ne);
585 76 : if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) {
586 76 : to_add_len = ASN1_STRING_to_UTF8(&to_add, str);
587 76 : if (to_add_len != -1) {
588 74 : add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1);
589 : }
590 : } else {
591 0 : to_add = ASN1_STRING_data(str);
592 0 : to_add_len = ASN1_STRING_length(str);
593 0 : add_next_index_stringl(subentries, (char *)to_add, to_add_len, 1);
594 : }
595 : }
596 76 : last = j;
597 76 : }
598 74 : i = last;
599 :
600 74 : if (obj_cnt > 1) {
601 2 : add_assoc_zval_ex(subitem, sname, strlen(sname) + 1, subentries);
602 : } else {
603 72 : zval_dtor(subentries);
604 72 : FREE_ZVAL(subentries);
605 72 : if (obj_cnt && str && to_add_len > -1) {
606 70 : add_assoc_stringl(subitem, sname, (char *)to_add, to_add_len, 1);
607 : }
608 : }
609 : }
610 13 : if (key != NULL) {
611 12 : zend_hash_update(HASH_OF(val), key, strlen(key) + 1, (void *)&subitem, sizeof(subitem), NULL);
612 : }
613 13 : }
614 : /* }}} */
615 :
616 : static void add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) /* {{{ */
617 14 : {
618 14 : add_assoc_stringl(val, key, (char *)str->data, str->length, 1);
619 14 : }
620 : /* }}} */
621 :
622 : static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr TSRMLS_DC) /* {{{ */
623 12 : {
624 : /*
625 : This is how the time string is formatted:
626 :
627 : snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
628 : ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
629 : */
630 :
631 : time_t ret;
632 : struct tm thetime;
633 : char * strbuf;
634 : char * thestr;
635 12 : long gmadjust = 0;
636 :
637 12 : if (timestr->length < 13) {
638 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "extension author too lazy to parse %s correctly", timestr->data);
639 0 : return (time_t)-1;
640 : }
641 :
642 12 : strbuf = estrdup((char *)timestr->data);
643 :
644 12 : memset(&thetime, 0, sizeof(thetime));
645 :
646 : /* we work backwards so that we can use atoi more easily */
647 :
648 12 : thestr = strbuf + timestr->length - 3;
649 :
650 12 : thetime.tm_sec = atoi(thestr);
651 12 : *thestr = '\0';
652 12 : thestr -= 2;
653 12 : thetime.tm_min = atoi(thestr);
654 12 : *thestr = '\0';
655 12 : thestr -= 2;
656 12 : thetime.tm_hour = atoi(thestr);
657 12 : *thestr = '\0';
658 12 : thestr -= 2;
659 12 : thetime.tm_mday = atoi(thestr);
660 12 : *thestr = '\0';
661 12 : thestr -= 2;
662 12 : thetime.tm_mon = atoi(thestr)-1;
663 12 : *thestr = '\0';
664 12 : thestr -= 2;
665 12 : thetime.tm_year = atoi(thestr);
666 :
667 12 : if (thetime.tm_year < 68) {
668 12 : thetime.tm_year += 100;
669 : }
670 :
671 12 : thetime.tm_isdst = -1;
672 12 : ret = mktime(&thetime);
673 :
674 : #if HAVE_TM_GMTOFF
675 12 : gmadjust = thetime.tm_gmtoff;
676 : #else
677 : /*
678 : ** If correcting for daylight savings time, we set the adjustment to
679 : ** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and
680 : ** set the adjustment to the main timezone + 3600 seconds.
681 : */
682 : gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone + 3600);
683 : #endif
684 12 : ret += gmadjust;
685 :
686 12 : efree(strbuf);
687 :
688 12 : return ret;
689 : }
690 : /* }}} */
691 :
692 : #if OPENSSL_VERSION_NUMBER >= 0x10000002L
693 : 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) /* {{{ */
694 : #else
695 : static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH * config TSRMLS_DC) /* {{{ */
696 : #endif
697 24 : {
698 : X509V3_CTX ctx;
699 :
700 24 : X509V3_set_ctx_test(&ctx);
701 24 : X509V3_set_conf_lhash(&ctx, config);
702 24 : if (!X509V3_EXT_add_conf(config, &ctx, (char *)section, NULL)) {
703 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading %s section %s of %s",
704 : section_label,
705 : section,
706 : config_filename);
707 0 : return FAILURE;
708 : }
709 24 : return SUCCESS;
710 : }
711 : /* }}} */
712 :
713 : static int add_oid_section(struct php_x509_request * req TSRMLS_DC) /* {{{ */
714 22 : {
715 : char * str;
716 : STACK_OF(CONF_VALUE) * sktmp;
717 : CONF_VALUE * cnf;
718 : int i;
719 :
720 22 : str = CONF_get_string(req->req_config, NULL, "oid_section");
721 22 : if (str == NULL) {
722 22 : return SUCCESS;
723 : }
724 0 : sktmp = CONF_get_section(req->req_config, str);
725 0 : if (sktmp == NULL) {
726 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem loading oid section %s", str);
727 0 : return FAILURE;
728 : }
729 0 : for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
730 0 : cnf = sk_CONF_VALUE_value(sktmp, i);
731 0 : if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
732 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value);
733 0 : return FAILURE;
734 : }
735 : }
736 0 : return SUCCESS;
737 : }
738 : /* }}} */
739 :
740 : #define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req))
741 : #define PHP_SSL_REQ_DISPOSE(req) php_openssl_dispose_config(req TSRMLS_CC)
742 : #define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval TSRMLS_CC)
743 :
744 : #define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \
745 : req->config_filename, req->var, req->req_config TSRMLS_CC) == FAILURE) return FAILURE
746 :
747 : #define SET_OPTIONAL_STRING_ARG(key, varname, defval) \
748 : if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS) \
749 : varname = Z_STRVAL_PP(item); \
750 : else \
751 : varname = defval
752 :
753 : #define SET_OPTIONAL_LONG_ARG(key, varname, defval) \
754 : if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), key, sizeof(key), (void**)&item) == SUCCESS) \
755 : varname = Z_LVAL_PP(item); \
756 : else \
757 : varname = defval
758 :
759 : static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args TSRMLS_DC) /* {{{ */
760 22 : {
761 : char * str;
762 : zval ** item;
763 :
764 22 : SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename);
765 22 : SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req");
766 22 : req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL);
767 22 : req->req_config = CONF_load(NULL, req->config_filename, NULL);
768 :
769 22 : if (req->req_config == NULL) {
770 0 : return FAILURE;
771 : }
772 :
773 : /* read in the oids */
774 22 : str = CONF_get_string(req->req_config, NULL, "oid_file");
775 22 : if (str && !php_openssl_safe_mode_chk(str TSRMLS_CC)) {
776 0 : BIO *oid_bio = BIO_new_file(str, "r");
777 0 : if (oid_bio) {
778 0 : OBJ_create_objects(oid_bio);
779 0 : BIO_free(oid_bio);
780 : }
781 : }
782 22 : if (add_oid_section(req TSRMLS_CC) == FAILURE) {
783 0 : return FAILURE;
784 : }
785 22 : SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
786 : CONF_get_string(req->req_config, req->section_name, "default_md"));
787 22 : SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
788 : CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
789 22 : SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
790 : CONF_get_string(req->req_config, req->section_name, "req_extensions"));
791 22 : SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits,
792 : CONF_get_number(req->req_config, req->section_name, "default_bits"));
793 :
794 22 : SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT);
795 :
796 25 : if (optional_args && zend_hash_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key"), (void**)&item) == SUCCESS) {
797 3 : req->priv_key_encrypt = Z_BVAL_PP(item);
798 : } else {
799 19 : str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key");
800 19 : if (str == NULL) {
801 19 : str = CONF_get_string(req->req_config, req->section_name, "encrypt_key");
802 : }
803 19 : if (str && strcmp(str, "no") == 0) {
804 0 : req->priv_key_encrypt = 0;
805 : } else {
806 19 : req->priv_key_encrypt = 1;
807 : }
808 : }
809 :
810 : /* digest alg */
811 22 : if (req->digest_name == NULL) {
812 0 : req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md");
813 : }
814 22 : if (req->digest_name) {
815 22 : req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name);
816 : }
817 22 : if (req->md_alg == NULL) {
818 0 : req->md_alg = req->digest = EVP_md5();
819 : }
820 :
821 22 : PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
822 :
823 : /* set the string mask */
824 22 : str = CONF_get_string(req->req_config, req->section_name, "string_mask");
825 22 : if (str && !ASN1_STRING_set_default_mask_asc(str)) {
826 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid global string mask setting %s", str);
827 0 : return FAILURE;
828 : }
829 :
830 22 : PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section);
831 :
832 22 : return SUCCESS;
833 : }
834 : /* }}} */
835 :
836 : static void php_openssl_dispose_config(struct php_x509_request * req TSRMLS_DC) /* {{{ */
837 26 : {
838 26 : if (req->priv_key) {
839 1 : EVP_PKEY_free(req->priv_key);
840 1 : req->priv_key = NULL;
841 : }
842 26 : if (req->global_config) {
843 22 : CONF_free(req->global_config);
844 22 : req->global_config = NULL;
845 : }
846 26 : if (req->req_config) {
847 22 : CONF_free(req->req_config);
848 22 : req->req_config = NULL;
849 : }
850 26 : }
851 : /* }}} */
852 :
853 : static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded) /* {{{ */
854 10 : {
855 : char buffer[MAXPATHLEN];
856 :
857 : TSRMLS_FETCH();
858 :
859 10 : *egdsocket = 0;
860 10 : *seeded = 0;
861 :
862 : #ifdef WINDOWS
863 : RAND_screen();
864 : #endif
865 10 : if (file == NULL) {
866 0 : file = RAND_file_name(buffer, sizeof(buffer));
867 10 : } else if (RAND_egd(file) > 0) {
868 : /* if the given filename is an EGD socket, don't
869 : * write anything back to it */
870 0 : *egdsocket = 1;
871 0 : return SUCCESS;
872 : }
873 10 : if (file == NULL || !RAND_load_file(file, -1)) {
874 10 : if (RAND_status() == 0) {
875 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to load random state; not enough random data!");
876 0 : return FAILURE;
877 : }
878 10 : return FAILURE;
879 : }
880 0 : *seeded = 1;
881 0 : return SUCCESS;
882 : }
883 : /* }}} */
884 :
885 : static int php_openssl_write_rand_file(const char * file, int egdsocket, int seeded) /* {{{ */
886 10 : {
887 : char buffer[MAXPATHLEN];
888 :
889 : TSRMLS_FETCH();
890 :
891 10 : if (egdsocket || !seeded) {
892 : /* if we did not manage to read the seed file, we should not write
893 : * a low-entropy seed file back */
894 10 : return FAILURE;
895 : }
896 0 : if (file == NULL) {
897 0 : file = RAND_file_name(buffer, sizeof(buffer));
898 : }
899 0 : if (file == NULL || !RAND_write_file(file)) {
900 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to write random state");
901 0 : return FAILURE;
902 : }
903 0 : return SUCCESS;
904 : }
905 : /* }}} */
906 :
907 14 : static EVP_MD * php_openssl_get_evp_md_from_algo(long algo) { /* {{{ */
908 : EVP_MD *mdtype;
909 :
910 14 : switch (algo) {
911 : case OPENSSL_ALGO_SHA1:
912 7 : mdtype = (EVP_MD *) EVP_sha1();
913 7 : break;
914 : case OPENSSL_ALGO_MD5:
915 5 : mdtype = (EVP_MD *) EVP_md5();
916 5 : break;
917 : case OPENSSL_ALGO_MD4:
918 0 : mdtype = (EVP_MD *) EVP_md4();
919 0 : break;
920 : case OPENSSL_ALGO_MD2:
921 0 : mdtype = (EVP_MD *) EVP_md2();
922 0 : break;
923 : case OPENSSL_ALGO_DSS1:
924 2 : mdtype = (EVP_MD *) EVP_dss1();
925 2 : break;
926 : default:
927 0 : return NULL;
928 : break;
929 : }
930 14 : return mdtype;
931 : }
932 : /* }}} */
933 :
934 5 : static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo) { /* {{{ */
935 5 : switch (algo) {
936 : #ifndef OPENSSL_NO_RC2
937 : case PHP_OPENSSL_CIPHER_RC2_40:
938 5 : return EVP_rc2_40_cbc();
939 : break;
940 : case PHP_OPENSSL_CIPHER_RC2_64:
941 0 : return EVP_rc2_64_cbc();
942 : break;
943 : case PHP_OPENSSL_CIPHER_RC2_128:
944 0 : return EVP_rc2_cbc();
945 : break;
946 : #endif
947 :
948 : #ifndef OPENSSL_NO_DES
949 : case PHP_OPENSSL_CIPHER_DES:
950 0 : return EVP_des_cbc();
951 : break;
952 : case PHP_OPENSSL_CIPHER_3DES:
953 0 : return EVP_des_ede3_cbc();
954 : break;
955 : #endif
956 : default:
957 0 : return NULL;
958 : break;
959 : }
960 : }
961 : /* }}} */
962 :
963 : /* {{{ PHP_MINIT_FUNCTION
964 : */
965 : PHP_MINIT_FUNCTION(openssl)
966 17633 : {
967 : char * config_filename;
968 :
969 17633 : le_key = zend_register_list_destructors_ex(php_pkey_free, NULL, "OpenSSL key", module_number);
970 17633 : le_x509 = zend_register_list_destructors_ex(php_x509_free, NULL, "OpenSSL X.509", module_number);
971 17633 : le_csr = zend_register_list_destructors_ex(php_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
972 :
973 17633 : SSL_library_init();
974 17633 : OpenSSL_add_all_ciphers();
975 17633 : OpenSSL_add_all_digests();
976 17633 : OpenSSL_add_all_algorithms();
977 :
978 17633 : ERR_load_ERR_strings();
979 17633 : ERR_load_crypto_strings();
980 17633 : ERR_load_EVP_strings();
981 :
982 : /* register a resource id number with openSSL so that we can map SSL -> stream structures in
983 : * openSSL callbacks */
984 17633 : ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);
985 :
986 17633 : REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT);
987 17633 : REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT);
988 :
989 : /* purposes for cert purpose checking */
990 17633 : REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT);
991 17633 : REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
992 17633 : REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
993 17633 : REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT);
994 17633 : REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT);
995 17633 : REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT);
996 : #ifdef X509_PURPOSE_ANY
997 17633 : REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT);
998 : #endif
999 :
1000 : /* signature algorithm constants */
1001 17633 : REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT);
1002 17633 : REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT);
1003 17633 : REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD4", OPENSSL_ALGO_MD4, CONST_CS|CONST_PERSISTENT);
1004 17633 : REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_CS|CONST_PERSISTENT);
1005 17633 : REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT);
1006 :
1007 : /* flags for S/MIME */
1008 17633 : REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT);
1009 17633 : REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT);
1010 17633 : REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT);
1011 17633 : REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT);
1012 17633 : REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT);
1013 17633 : REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT);
1014 17633 : REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT);
1015 17633 : REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
1016 17633 : REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
1017 :
1018 17633 : REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
1019 17633 : REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
1020 17633 : REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
1021 17633 : REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
1022 :
1023 : /* Ciphers */
1024 : #ifndef OPENSSL_NO_RC2
1025 17633 : REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
1026 17633 : REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT);
1027 17633 : REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT);
1028 : #endif
1029 : #ifndef OPENSSL_NO_DES
1030 17633 : REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT);
1031 17633 : REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT);
1032 : #endif
1033 :
1034 : /* Values for key types */
1035 17633 : REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT);
1036 : #ifndef NO_DSA
1037 17633 : REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT);
1038 : #endif
1039 17633 : REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT);
1040 : #ifdef EVP_PKEY_EC
1041 17633 : REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT);
1042 : #endif
1043 :
1044 : /* Determine default SSL configuration file */
1045 17633 : config_filename = getenv("OPENSSL_CONF");
1046 17633 : if (config_filename == NULL) {
1047 17633 : config_filename = getenv("SSLEAY_CONF");
1048 : }
1049 :
1050 : /* default to 'openssl.cnf' if no environment variable is set */
1051 17633 : if (config_filename == NULL) {
1052 17633 : snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename), "%s/%s",
1053 : X509_get_default_cert_area(),
1054 : "openssl.cnf");
1055 : } else {
1056 0 : strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename));
1057 : }
1058 :
1059 17633 : php_stream_xport_register("ssl", php_openssl_ssl_socket_factory TSRMLS_CC);
1060 17633 : php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory TSRMLS_CC);
1061 17633 : php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory TSRMLS_CC);
1062 17633 : php_stream_xport_register("tls", php_openssl_ssl_socket_factory TSRMLS_CC);
1063 :
1064 : /* override the default tcp socket provider */
1065 17633 : php_stream_xport_register("tcp", php_openssl_ssl_socket_factory TSRMLS_CC);
1066 :
1067 17633 : php_register_url_stream_wrapper("https", &php_stream_http_wrapper TSRMLS_CC);
1068 17633 : php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper TSRMLS_CC);
1069 :
1070 17633 : return SUCCESS;
1071 : }
1072 : /* }}} */
1073 :
1074 : /* {{{ PHP_MINFO_FUNCTION
1075 : */
1076 : PHP_MINFO_FUNCTION(openssl)
1077 42 : {
1078 42 : php_info_print_table_start();
1079 42 : php_info_print_table_row(2, "OpenSSL support", "enabled");
1080 42 : php_info_print_table_row(2, "OpenSSL Library Version", SSLeay_version(SSLEAY_VERSION));
1081 42 : php_info_print_table_row(2, "OpenSSL Header Version", OPENSSL_VERSION_TEXT);
1082 42 : php_info_print_table_end();
1083 42 : }
1084 : /* }}} */
1085 :
1086 : /* {{{ PHP_MSHUTDOWN_FUNCTION
1087 : */
1088 : PHP_MSHUTDOWN_FUNCTION(openssl)
1089 17665 : {
1090 17665 : EVP_cleanup();
1091 :
1092 17665 : php_unregister_url_stream_wrapper("https" TSRMLS_CC);
1093 17665 : php_unregister_url_stream_wrapper("ftps" TSRMLS_CC);
1094 :
1095 17665 : php_stream_xport_unregister("ssl" TSRMLS_CC);
1096 17665 : php_stream_xport_unregister("sslv2" TSRMLS_CC);
1097 17665 : php_stream_xport_unregister("sslv3" TSRMLS_CC);
1098 17665 : php_stream_xport_unregister("tls" TSRMLS_CC);
1099 :
1100 : /* reinstate the default tcp handler */
1101 17665 : php_stream_xport_register("tcp", php_stream_generic_socket_factory TSRMLS_CC);
1102 :
1103 17665 : return SUCCESS;
1104 : }
1105 : /* }}} */
1106 :
1107 : /* {{{ x509 cert functions */
1108 :
1109 : /* {{{ php_openssl_x509_from_zval
1110 : Given a zval, coerce it into an X509 object.
1111 : The zval can be:
1112 : . X509 resource created using openssl_read_x509()
1113 : . if it starts with file:// then it will be interpreted as the path to that cert
1114 : . it will be interpreted as the cert data
1115 : If you supply makeresource, the result will be registered as an x509 resource and
1116 : it's value returned in makeresource.
1117 : */
1118 : static X509 * php_openssl_x509_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC)
1119 96 : {
1120 96 : X509 *cert = NULL;
1121 :
1122 96 : if (resourceval) {
1123 96 : *resourceval = -1;
1124 : }
1125 96 : if (Z_TYPE_PP(val) == IS_RESOURCE) {
1126 : /* is it an x509 resource ? */
1127 : void * what;
1128 : int type;
1129 :
1130 4 : what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509", &type, 1, le_x509);
1131 4 : if (!what) {
1132 0 : return NULL;
1133 : }
1134 : /* this is so callers can decide if they should free the X509 */
1135 4 : if (resourceval) {
1136 4 : *resourceval = Z_LVAL_PP(val);
1137 : }
1138 4 : if (type == le_x509) {
1139 4 : return (X509*)what;
1140 : }
1141 : /* other types could be used here - eg: file pointers and read in the data from them */
1142 :
1143 0 : return NULL;
1144 : }
1145 :
1146 92 : if (!(Z_TYPE_PP(val) == IS_STRING || Z_TYPE_PP(val) == IS_OBJECT)) {
1147 11 : return NULL;
1148 : }
1149 :
1150 : /* force it to be a string and check if it refers to a file */
1151 81 : convert_to_string_ex(val);
1152 :
1153 127 : if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) {
1154 : /* read cert from the named file */
1155 : BIO *in;
1156 :
1157 47 : if (php_openssl_safe_mode_chk(Z_STRVAL_PP(val) + (sizeof("file://") - 1) TSRMLS_CC)) {
1158 0 : return NULL;
1159 : }
1160 :
1161 47 : in = BIO_new_file(Z_STRVAL_PP(val) + (sizeof("file://") - 1), "r");
1162 47 : if (in == NULL) {
1163 0 : return NULL;
1164 : }
1165 47 : cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
1166 47 : BIO_free(in);
1167 : } else {
1168 : BIO *in;
1169 :
1170 33 : in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
1171 33 : if (in == NULL) {
1172 0 : return NULL;
1173 : }
1174 : #ifdef TYPEDEF_D2I_OF
1175 33 : cert = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
1176 : #else
1177 : cert = (X509 *) PEM_ASN1_read_bio((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
1178 : #endif
1179 33 : BIO_free(in);
1180 : }
1181 :
1182 80 : if (cert && makeresource && resourceval) {
1183 4 : *resourceval = zend_list_insert(cert, le_x509);
1184 : }
1185 80 : return cert;
1186 : }
1187 :
1188 : /* }}} */
1189 :
1190 : /* {{{ proto bool openssl_x509_export_to_file(mixed x509, string outfilename [, bool notext = true])
1191 : Exports a CERT to file or a var */
1192 : PHP_FUNCTION(openssl_x509_export_to_file)
1193 5 : {
1194 : X509 * cert;
1195 : zval ** zcert;
1196 5 : zend_bool notext = 1;
1197 : BIO * bio_out;
1198 : long certresource;
1199 : char * filename;
1200 : int filename_len;
1201 :
1202 5 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs|b", &zcert, &filename, &filename_len, ¬ext) == FAILURE) {
1203 0 : return;
1204 : }
1205 5 : RETVAL_FALSE;
1206 :
1207 5 : cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
1208 5 : if (cert == NULL) {
1209 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
1210 2 : return;
1211 : }
1212 :
1213 3 : if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
1214 0 : return;
1215 : }
1216 :
1217 3 : bio_out = BIO_new_file(filename, "w");
1218 3 : if (bio_out) {
1219 3 : if (!notext) {
1220 0 : X509_print(bio_out, cert);
1221 : }
1222 3 : PEM_write_bio_X509(bio_out, cert);
1223 :
1224 3 : RETVAL_TRUE;
1225 : } else {
1226 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename);
1227 : }
1228 3 : if (certresource == -1 && cert) {
1229 2 : X509_free(cert);
1230 : }
1231 3 : BIO_free(bio_out);
1232 : }
1233 : /* }}} */
1234 :
1235 : /* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true])
1236 : Exports a CERT to file or a var */
1237 : PHP_FUNCTION(openssl_x509_export)
1238 6 : {
1239 : X509 * cert;
1240 : zval ** zcert, *zout;
1241 6 : zend_bool notext = 1;
1242 : BIO * bio_out;
1243 : long certresource;
1244 :
1245 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zz|b", &zcert, &zout, ¬ext) == FAILURE) {
1246 0 : return;
1247 : }
1248 6 : RETVAL_FALSE;
1249 :
1250 6 : cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
1251 6 : if (cert == NULL) {
1252 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
1253 2 : return;
1254 : }
1255 :
1256 4 : bio_out = BIO_new(BIO_s_mem());
1257 4 : if (!notext) {
1258 1 : X509_print(bio_out, cert);
1259 : }
1260 4 : if (PEM_write_bio_X509(bio_out, cert)) {
1261 : BUF_MEM *bio_buf;
1262 :
1263 4 : zval_dtor(zout);
1264 4 : BIO_get_mem_ptr(bio_out, &bio_buf);
1265 4 : ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
1266 :
1267 4 : RETVAL_TRUE;
1268 : }
1269 :
1270 4 : if (certresource == -1 && cert) {
1271 2 : X509_free(cert);
1272 : }
1273 4 : BIO_free(bio_out);
1274 : }
1275 : /* }}} */
1276 :
1277 : /* {{{ proto bool openssl_x509_check_private_key(mixed cert, mixed key)
1278 : Checks if a private key corresponds to a CERT */
1279 : PHP_FUNCTION(openssl_x509_check_private_key)
1280 5 : {
1281 : zval ** zcert, **zkey;
1282 5 : X509 * cert = NULL;
1283 5 : EVP_PKEY * key = NULL;
1284 5 : long certresource = -1, keyresource = -1;
1285 :
1286 5 : RETVAL_FALSE;
1287 :
1288 5 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &zcert, &zkey) == FAILURE) {
1289 0 : return;
1290 : }
1291 5 : cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
1292 5 : if (cert == NULL) {
1293 2 : RETURN_FALSE;
1294 : }
1295 3 : key = php_openssl_evp_from_zval(zkey, 0, "", 1, &keyresource TSRMLS_CC);
1296 3 : if (key) {
1297 2 : RETVAL_BOOL(X509_check_private_key(cert, key));
1298 : }
1299 :
1300 3 : if (keyresource == -1 && key) {
1301 0 : EVP_PKEY_free(key);
1302 : }
1303 3 : if (certresource == -1 && cert) {
1304 3 : X509_free(cert);
1305 : }
1306 : }
1307 : /* }}} */
1308 :
1309 : /* {{{ proto array openssl_x509_parse(mixed x509 [, bool shortnames=true])
1310 : Returns an array of the fields/values of the CERT */
1311 : PHP_FUNCTION(openssl_x509_parse)
1312 12 : {
1313 : zval ** zcert;
1314 12 : X509 * cert = NULL;
1315 12 : long certresource = -1;
1316 : int i;
1317 12 : zend_bool useshortnames = 1;
1318 : char * tmpstr;
1319 : zval * subitem;
1320 : X509_EXTENSION *extension;
1321 : char *extname;
1322 : BIO *bio_out;
1323 : BUF_MEM *bio_buf;
1324 : char buf[256];
1325 :
1326 12 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcert, &useshortnames) == FAILURE) {
1327 1 : return;
1328 : }
1329 11 : cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
1330 10 : if (cert == NULL) {
1331 4 : RETURN_FALSE;
1332 : }
1333 6 : array_init(return_value);
1334 :
1335 6 : if (cert->name) {
1336 6 : add_assoc_string(return_value, "name", cert->name, 1);
1337 : }
1338 : /* add_assoc_bool(return_value, "valid", cert->valid); */
1339 :
1340 6 : add_assoc_name_entry(return_value, "subject", X509_get_subject_name(cert), useshortnames TSRMLS_CC);
1341 : /* hash as used in CA directories to lookup cert by subject name */
1342 : {
1343 : char buf[32];
1344 6 : snprintf(buf, sizeof(buf), "%08lx", X509_subject_name_hash(cert));
1345 6 : add_assoc_string(return_value, "hash", buf, 1);
1346 : }
1347 :
1348 6 : add_assoc_name_entry(return_value, "issuer", X509_get_issuer_name(cert), useshortnames TSRMLS_CC);
1349 6 : add_assoc_long(return_value, "version", X509_get_version(cert));
1350 :
1351 6 : add_assoc_string(return_value, "serialNumber", i2s_ASN1_INTEGER(NULL, X509_get_serialNumber(cert)), 1);
1352 :
1353 6 : add_assoc_asn1_string(return_value, "validFrom", X509_get_notBefore(cert));
1354 6 : add_assoc_asn1_string(return_value, "validTo", X509_get_notAfter(cert));
1355 :
1356 6 : add_assoc_long(return_value, "validFrom_time_t", asn1_time_to_time_t(X509_get_notBefore(cert) TSRMLS_CC));
1357 6 : add_assoc_long(return_value, "validTo_time_t", asn1_time_to_time_t(X509_get_notAfter(cert) TSRMLS_CC));
1358 :
1359 6 : tmpstr = (char *)X509_alias_get0(cert, NULL);
1360 6 : if (tmpstr) {
1361 0 : add_assoc_string(return_value, "alias", tmpstr, 1);
1362 : }
1363 : /*
1364 : add_assoc_long(return_value, "signaturetypeLONG", X509_get_signature_type(cert));
1365 : add_assoc_string(return_value, "signaturetype", OBJ_nid2sn(X509_get_signature_type(cert)), 1);
1366 : add_assoc_string(return_value, "signaturetypeLN", OBJ_nid2ln(X509_get_signature_type(cert)), 1);
1367 : */
1368 6 : MAKE_STD_ZVAL(subitem);
1369 6 : array_init(subitem);
1370 :
1371 : /* NOTE: the purposes are added as integer keys - the keys match up to the X509_PURPOSE_SSL_XXX defines
1372 : in x509v3.h */
1373 54 : for (i = 0; i < X509_PURPOSE_get_count(); i++) {
1374 : int id, purpset;
1375 : char * pname;
1376 : X509_PURPOSE * purp;
1377 : zval * subsub;
1378 :
1379 48 : MAKE_STD_ZVAL(subsub);
1380 48 : array_init(subsub);
1381 :
1382 48 : purp = X509_PURPOSE_get0(i);
1383 48 : id = X509_PURPOSE_get_id(purp);
1384 :
1385 48 : purpset = X509_check_purpose(cert, id, 0);
1386 48 : add_index_bool(subsub, 0, purpset);
1387 :
1388 48 : purpset = X509_check_purpose(cert, id, 1);
1389 48 : add_index_bool(subsub, 1, purpset);
1390 :
1391 48 : pname = useshortnames ? X509_PURPOSE_get0_sname(purp) : X509_PURPOSE_get0_name(purp);
1392 48 : add_index_string(subsub, 2, pname, 1);
1393 :
1394 : /* NOTE: if purpset > 1 then it's a warning - we should mention it ? */
1395 :
1396 48 : add_index_zval(subitem, id, subsub);
1397 : }
1398 6 : add_assoc_zval(return_value, "purposes", subitem);
1399 :
1400 6 : MAKE_STD_ZVAL(subitem);
1401 6 : array_init(subitem);
1402 :
1403 :
1404 35 : for (i = 0; i < X509_get_ext_count(cert); i++) {
1405 29 : extension = X509_get_ext(cert, i);
1406 29 : if (OBJ_obj2nid(X509_EXTENSION_get_object(extension)) != NID_undef) {
1407 27 : extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension)));
1408 : } else {
1409 2 : OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1);
1410 2 : extname = buf;
1411 : }
1412 29 : bio_out = BIO_new(BIO_s_mem());
1413 29 : if (X509V3_EXT_print(bio_out, extension, 0, 0)) {
1414 27 : BIO_get_mem_ptr(bio_out, &bio_buf);
1415 27 : add_assoc_stringl(subitem, extname, bio_buf->data, bio_buf->length, 1);
1416 : } else {
1417 2 : add_assoc_asn1_string(subitem, extname, X509_EXTENSION_get_data(extension));
1418 : }
1419 29 : BIO_free(bio_out);
1420 : }
1421 6 : add_assoc_zval(return_value, "extensions", subitem);
1422 :
1423 6 : if (certresource == -1 && cert) {
1424 6 : X509_free(cert);
1425 : }
1426 : }
1427 : /* }}} */
1428 :
1429 : /* {{{ load_all_certs_from_file */
1430 : static STACK_OF(X509) * load_all_certs_from_file(char *certfile)
1431 0 : {
1432 0 : STACK_OF(X509_INFO) *sk=NULL;
1433 0 : STACK_OF(X509) *stack=NULL, *ret=NULL;
1434 0 : BIO *in=NULL;
1435 : X509_INFO *xi;
1436 : TSRMLS_FETCH();
1437 :
1438 0 : if(!(stack = sk_X509_new_null())) {
1439 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure");
1440 0 : goto end;
1441 : }
1442 :
1443 0 : if (php_openssl_safe_mode_chk(certfile TSRMLS_CC)) {
1444 0 : sk_X509_free(stack);
1445 0 : goto end;
1446 : }
1447 :
1448 0 : if(!(in=BIO_new_file(certfile, "r"))) {
1449 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening the file, %s", certfile);
1450 0 : sk_X509_free(stack);
1451 0 : goto end;
1452 : }
1453 :
1454 : /* This loads from a file, a stack of x509/crl/pkey sets */
1455 0 : if(!(sk=PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) {
1456 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error reading the file, %s", certfile);
1457 0 : sk_X509_free(stack);
1458 0 : goto end;
1459 : }
1460 :
1461 : /* scan over it and pull out the certs */
1462 0 : while (sk_X509_INFO_num(sk)) {
1463 0 : xi=sk_X509_INFO_shift(sk);
1464 0 : if (xi->x509 != NULL) {
1465 0 : sk_X509_push(stack,xi->x509);
1466 0 : xi->x509=NULL;
1467 : }
1468 0 : X509_INFO_free(xi);
1469 : }
1470 0 : if(!sk_X509_num(stack)) {
1471 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "no certificates in file, %s", certfile);
1472 0 : sk_X509_free(stack);
1473 0 : goto end;
1474 : }
1475 0 : ret=stack;
1476 0 : end:
1477 0 : BIO_free(in);
1478 0 : sk_X509_INFO_free(sk);
1479 :
1480 0 : return ret;
1481 : }
1482 : /* }}} */
1483 :
1484 : /* {{{ check_cert */
1485 : static int check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedchain, int purpose)
1486 0 : {
1487 0 : int ret=0;
1488 : X509_STORE_CTX *csc;
1489 : TSRMLS_FETCH();
1490 :
1491 0 : csc = X509_STORE_CTX_new();
1492 0 : if (csc == NULL) {
1493 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "memory allocation failure");
1494 0 : return 0;
1495 : }
1496 0 : X509_STORE_CTX_init(csc, ctx, x, untrustedchain);
1497 0 : if(purpose >= 0) {
1498 0 : X509_STORE_CTX_set_purpose(csc, purpose);
1499 : }
1500 0 : ret = X509_verify_cert(csc);
1501 0 : X509_STORE_CTX_free(csc);
1502 :
1503 0 : return ret;
1504 : }
1505 : /* }}} */
1506 :
1507 : /* {{{ proto int openssl_x509_checkpurpose(mixed x509cert, int purpose, array cainfo [, string untrustedfile])
1508 : Checks the CERT to see if it can be used for the purpose in purpose. cainfo holds information about trusted CAs */
1509 : PHP_FUNCTION(openssl_x509_checkpurpose)
1510 0 : {
1511 0 : zval ** zcert, * zcainfo = NULL;
1512 0 : X509_STORE * cainfo = NULL;
1513 0 : X509 * cert = NULL;
1514 0 : long certresource = -1;
1515 0 : STACK_OF(X509) * untrustedchain = NULL;
1516 : long purpose;
1517 0 : char * untrusted = NULL;
1518 0 : int untrusted_len = 0, ret;
1519 :
1520 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|a!s", &zcert, &purpose, &zcainfo, &untrusted, &untrusted_len) == FAILURE) {
1521 0 : return;
1522 : }
1523 :
1524 0 : RETVAL_LONG(-1);
1525 :
1526 0 : if (untrusted) {
1527 0 : untrustedchain = load_all_certs_from_file(untrusted);
1528 0 : if (untrustedchain == NULL) {
1529 0 : goto clean_exit;
1530 : }
1531 : }
1532 :
1533 0 : cainfo = setup_verify(zcainfo TSRMLS_CC);
1534 0 : if (cainfo == NULL) {
1535 0 : goto clean_exit;
1536 : }
1537 0 : cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
1538 0 : if (cert == NULL) {
1539 0 : goto clean_exit;
1540 : }
1541 :
1542 0 : ret = check_cert(cainfo, cert, untrustedchain, purpose);
1543 0 : if (ret != 0 && ret != 1) {
1544 0 : RETVAL_LONG(ret);
1545 : } else {
1546 0 : RETVAL_BOOL(ret);
1547 : }
1548 :
1549 0 : clean_exit:
1550 0 : if (certresource == 1 && cert) {
1551 0 : X509_free(cert);
1552 : }
1553 0 : if (cainfo) {
1554 0 : X509_STORE_free(cainfo);
1555 : }
1556 0 : if (untrustedchain) {
1557 0 : sk_X509_pop_free(untrustedchain, X509_free);
1558 : }
1559 : }
1560 : /* }}} */
1561 :
1562 : /* {{{ setup_verify
1563 : * calist is an array containing file and directory names. create a
1564 : * certificate store and add those certs to it for use in verification.
1565 : */
1566 : static X509_STORE * setup_verify(zval * calist TSRMLS_DC)
1567 0 : {
1568 : X509_STORE *store;
1569 : X509_LOOKUP * dir_lookup, * file_lookup;
1570 : HashPosition pos;
1571 0 : int ndirs = 0, nfiles = 0;
1572 :
1573 0 : store = X509_STORE_new();
1574 :
1575 0 : if (store == NULL) {
1576 0 : return NULL;
1577 : }
1578 :
1579 0 : if (calist && (Z_TYPE_P(calist) == IS_ARRAY)) {
1580 0 : zend_hash_internal_pointer_reset_ex(HASH_OF(calist), &pos);
1581 0 : for (;; zend_hash_move_forward_ex(HASH_OF(calist), &pos)) {
1582 : zval ** item;
1583 : struct stat sb;
1584 :
1585 0 : if (zend_hash_get_current_data_ex(HASH_OF(calist), (void**)&item, &pos) == FAILURE) {
1586 0 : break;
1587 : }
1588 0 : convert_to_string_ex(item);
1589 :
1590 0 : if (VCWD_STAT(Z_STRVAL_PP(item), &sb) == -1) {
1591 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to stat %s", Z_STRVAL_PP(item));
1592 0 : continue;
1593 : }
1594 :
1595 0 : if ((sb.st_mode & S_IFREG) == S_IFREG) {
1596 0 : file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
1597 0 : if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) {
1598 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading file %s", Z_STRVAL_PP(item));
1599 : } else {
1600 0 : nfiles++;
1601 : }
1602 0 : file_lookup = NULL;
1603 : } else {
1604 0 : dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
1605 0 : if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_PP(item), X509_FILETYPE_PEM)) {
1606 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error loading directory %s", Z_STRVAL_PP(item));
1607 : } else {
1608 0 : ndirs++;
1609 : }
1610 0 : dir_lookup = NULL;
1611 : }
1612 0 : }
1613 : }
1614 0 : if (nfiles == 0) {
1615 0 : file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
1616 0 : if (file_lookup) {
1617 0 : X509_LOOKUP_load_file(file_lookup, NULL, X509_FILETYPE_DEFAULT);
1618 : }
1619 : }
1620 0 : if (ndirs == 0) {
1621 0 : dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
1622 0 : if (dir_lookup) {
1623 0 : X509_LOOKUP_add_dir(dir_lookup, NULL, X509_FILETYPE_DEFAULT);
1624 : }
1625 : }
1626 0 : return store;
1627 : }
1628 : /* }}} */
1629 :
1630 : /* {{{ proto resource openssl_x509_read(mixed cert)
1631 : Reads X.509 certificates */
1632 : PHP_FUNCTION(openssl_x509_read)
1633 8 : {
1634 : zval **cert;
1635 : X509 *x509;
1636 :
1637 8 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &cert) == FAILURE) {
1638 0 : return;
1639 : }
1640 8 : Z_TYPE_P(return_value) = IS_RESOURCE;
1641 8 : x509 = php_openssl_x509_from_zval(cert, 1, &Z_LVAL_P(return_value) TSRMLS_CC);
1642 :
1643 8 : if (x509 == NULL) {
1644 3 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied parameter cannot be coerced into an X509 certificate!");
1645 3 : RETURN_FALSE;
1646 : }
1647 : }
1648 : /* }}} */
1649 :
1650 : /* {{{ proto void openssl_x509_free(resource x509)
1651 : Frees X.509 certificates */
1652 : PHP_FUNCTION(openssl_x509_free)
1653 6 : {
1654 : zval *x509;
1655 : X509 *cert;
1656 :
1657 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &x509) == FAILURE) {
1658 3 : return;
1659 : }
1660 3 : ZEND_FETCH_RESOURCE(cert, X509 *, &x509, -1, "OpenSSL X.509", le_x509);
1661 3 : zend_list_delete(Z_LVAL_P(x509));
1662 : }
1663 : /* }}} */
1664 :
1665 : /* }}} */
1666 :
1667 : /* Pop all X509 from Stack and free them, free the stack afterwards */
1668 : static void php_sk_X509_free(STACK_OF(X509) * sk) /* {{{ */
1669 0 : {
1670 : for (;;) {
1671 0 : X509* x = sk_X509_pop(sk);
1672 0 : if (!x) break;
1673 0 : X509_free(x);
1674 0 : }
1675 0 : sk_X509_free(sk);
1676 0 : }
1677 : /* }}} */
1678 :
1679 : static STACK_OF(X509) * php_array_to_X509_sk(zval ** zcerts TSRMLS_DC) /* {{{ */
1680 0 : {
1681 : HashPosition hpos;
1682 : zval ** zcertval;
1683 0 : STACK_OF(X509) * sk = NULL;
1684 : X509 * cert;
1685 : long certresource;
1686 :
1687 0 : sk = sk_X509_new_null();
1688 :
1689 : /* get certs */
1690 0 : if (Z_TYPE_PP(zcerts) == IS_ARRAY) {
1691 0 : zend_hash_internal_pointer_reset_ex(HASH_OF(*zcerts), &hpos);
1692 0 : while(zend_hash_get_current_data_ex(HASH_OF(*zcerts), (void**)&zcertval, &hpos) == SUCCESS) {
1693 :
1694 0 : cert = php_openssl_x509_from_zval(zcertval, 0, &certresource TSRMLS_CC);
1695 0 : if (cert == NULL) {
1696 0 : goto clean_exit;
1697 : }
1698 :
1699 0 : if (certresource != -1) {
1700 0 : cert = X509_dup(cert);
1701 :
1702 0 : if (cert == NULL) {
1703 0 : goto clean_exit;
1704 : }
1705 :
1706 : }
1707 0 : sk_X509_push(sk, cert);
1708 :
1709 0 : zend_hash_move_forward_ex(HASH_OF(*zcerts), &hpos);
1710 : }
1711 : } else {
1712 : /* a single certificate */
1713 0 : cert = php_openssl_x509_from_zval(zcerts, 0, &certresource TSRMLS_CC);
1714 :
1715 0 : if (cert == NULL) {
1716 0 : goto clean_exit;
1717 : }
1718 :
1719 0 : if (certresource != -1) {
1720 0 : cert = X509_dup(cert);
1721 0 : if (cert == NULL) {
1722 0 : goto clean_exit;
1723 : }
1724 : }
1725 0 : sk_X509_push(sk, cert);
1726 : }
1727 :
1728 0 : clean_exit:
1729 0 : return sk;
1730 : }
1731 : /* }}} */
1732 :
1733 : /* {{{ proto bool openssl_pkcs12_export_to_file(mixed x509, string filename, mixed priv_key, string pass[, array args])
1734 : Creates and exports a PKCS to file */
1735 : PHP_FUNCTION(openssl_pkcs12_export_to_file)
1736 0 : {
1737 0 : X509 * cert = NULL;
1738 0 : BIO * bio_out = NULL;
1739 0 : PKCS12 * p12 = NULL;
1740 : char * filename;
1741 0 : char * friendly_name = NULL;
1742 : int filename_len;
1743 : char * pass;
1744 : int pass_len;
1745 0 : zval **zcert = NULL, *zpkey = NULL, *args = NULL;
1746 0 : EVP_PKEY *priv_key = NULL;
1747 : long certresource, keyresource;
1748 : zval ** item;
1749 0 : STACK_OF(X509) *ca = NULL;
1750 :
1751 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zszs|a", &zcert, &filename, &filename_len, &zpkey, &pass, &pass_len, &args) == FAILURE)
1752 0 : return;
1753 :
1754 0 : RETVAL_FALSE;
1755 :
1756 0 : cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
1757 0 : if (cert == NULL) {
1758 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
1759 0 : return;
1760 : }
1761 0 : priv_key = php_openssl_evp_from_zval(&zpkey, 0, "", 1, &keyresource TSRMLS_CC);
1762 0 : if (priv_key == NULL) {
1763 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3");
1764 0 : goto cleanup;
1765 : }
1766 0 : if (cert && !X509_check_private_key(cert, priv_key)) {
1767 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to cert");
1768 0 : goto cleanup;
1769 : }
1770 0 : if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
1771 0 : goto cleanup;
1772 : }
1773 :
1774 : /* parse extra config from args array, promote this to an extra function */
1775 0 : if (args && zend_hash_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name"), (void**)&item) == SUCCESS)
1776 0 : friendly_name = Z_STRVAL_PP(item);
1777 : /* certpbe (default RC2-40)
1778 : keypbe (default 3DES)
1779 : friendly_caname
1780 : */
1781 :
1782 0 : if (args && zend_hash_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts"), (void**)&item) == SUCCESS)
1783 0 : ca = php_array_to_X509_sk(item TSRMLS_CC);
1784 : /* end parse extra config */
1785 :
1786 : /*PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca,
1787 : int nid_key, int nid_cert, int iter, int mac_iter, int keytype);*/
1788 :
1789 0 : p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
1790 :
1791 0 : bio_out = BIO_new_file(filename, "w");
1792 0 : if (bio_out) {
1793 :
1794 0 : i2d_PKCS12_bio(bio_out, p12);
1795 :
1796 0 : RETVAL_TRUE;
1797 : } else {
1798 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename);
1799 : }
1800 :
1801 0 : BIO_free(bio_out);
1802 0 : PKCS12_free(p12);
1803 0 : php_sk_X509_free(ca);
1804 :
1805 0 : cleanup:
1806 :
1807 0 : if (keyresource == -1 && priv_key) {
1808 0 : EVP_PKEY_free(priv_key);
1809 : }
1810 0 : if (certresource == -1 && cert) {
1811 0 : X509_free(cert);
1812 : }
1813 : }
1814 : /* }}} */
1815 :
1816 : /* {{{ proto bool openssl_pkcs12_export(mixed x509, string &out, mixed priv_key, string pass[, array args])
1817 : Creates and exports a PKCS12 to a var */
1818 : PHP_FUNCTION(openssl_pkcs12_export)
1819 0 : {
1820 0 : X509 * cert = NULL;
1821 : BIO * bio_out;
1822 0 : PKCS12 * p12 = NULL;
1823 0 : zval * zcert = NULL, *zout = NULL, *zpkey, *args = NULL;
1824 0 : EVP_PKEY *priv_key = NULL;
1825 : long certresource, keyresource;
1826 : char * pass;
1827 : int pass_len;
1828 0 : char * friendly_name = NULL;
1829 : zval ** item;
1830 0 : STACK_OF(X509) *ca = NULL;
1831 :
1832 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zzzs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE)
1833 0 : return;
1834 :
1835 0 : RETVAL_FALSE;
1836 :
1837 0 : cert = php_openssl_x509_from_zval(&zcert, 0, &certresource TSRMLS_CC);
1838 0 : if (cert == NULL) {
1839 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 1");
1840 0 : return;
1841 : }
1842 0 : priv_key = php_openssl_evp_from_zval(&zpkey, 0, "", 1, &keyresource TSRMLS_CC);
1843 0 : if (priv_key == NULL) {
1844 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3");
1845 0 : goto cleanup;
1846 : }
1847 0 : if (cert && !X509_check_private_key(cert, priv_key)) {
1848 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to cert");
1849 0 : goto cleanup;
1850 : }
1851 :
1852 : /* parse extra config from args array, promote this to an extra function */
1853 0 : if (args && zend_hash_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name"), (void**)&item) == SUCCESS)
1854 0 : friendly_name = Z_STRVAL_PP(item);
1855 :
1856 0 : if (args && zend_hash_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts"), (void**)&item) == SUCCESS)
1857 0 : ca = php_array_to_X509_sk(item TSRMLS_CC);
1858 : /* end parse extra config */
1859 :
1860 0 : p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
1861 :
1862 0 : bio_out = BIO_new(BIO_s_mem());
1863 0 : if (i2d_PKCS12_bio(bio_out, p12)) {
1864 : BUF_MEM *bio_buf;
1865 :
1866 0 : zval_dtor(zout);
1867 0 : BIO_get_mem_ptr(bio_out, &bio_buf);
1868 0 : ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
1869 :
1870 0 : RETVAL_TRUE;
1871 : }
1872 :
1873 0 : BIO_free(bio_out);
1874 0 : PKCS12_free(p12);
1875 0 : php_sk_X509_free(ca);
1876 :
1877 0 : cleanup:
1878 :
1879 0 : if (keyresource == -1 && priv_key) {
1880 0 : EVP_PKEY_free(priv_key);
1881 : }
1882 0 : if (certresource == -1 && cert) {
1883 0 : X509_free(cert);
1884 : }
1885 : }
1886 : /* }}} */
1887 :
1888 : /* {{{ proto bool openssl_pkcs12_read(string PKCS12, array &certs, string pass)
1889 : Parses a PKCS12 to an array */
1890 : PHP_FUNCTION(openssl_pkcs12_read)
1891 1 : {
1892 1 : zval *zout = NULL, *zextracerts, *zcert, *zpkey;
1893 : char *pass, *zp12;
1894 : int pass_len, zp12_len;
1895 1 : PKCS12 * p12 = NULL;
1896 1 : EVP_PKEY * pkey = NULL;
1897 1 : X509 * cert = NULL;
1898 1 : STACK_OF(X509) * ca = NULL;
1899 1 : BIO * bio_in = NULL;
1900 : int i;
1901 :
1902 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szs", &zp12, &zp12_len, &zout, &pass, &pass_len) == FAILURE)
1903 0 : return;
1904 :
1905 1 : RETVAL_FALSE;
1906 :
1907 1 : bio_in = BIO_new(BIO_s_mem());
1908 :
1909 1 : if(!BIO_write(bio_in, zp12, zp12_len))
1910 0 : goto cleanup;
1911 :
1912 1 : if(d2i_PKCS12_bio(bio_in, &p12)) {
1913 0 : if(PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
1914 : BIO * bio_out;
1915 :
1916 0 : zval_dtor(zout);
1917 0 : array_init(zout);
1918 :
1919 0 : bio_out = BIO_new(BIO_s_mem());
1920 0 : if (PEM_write_bio_X509(bio_out, cert)) {
1921 : BUF_MEM *bio_buf;
1922 0 : BIO_get_mem_ptr(bio_out, &bio_buf);
1923 0 : MAKE_STD_ZVAL(zcert);
1924 0 : ZVAL_STRINGL(zcert, bio_buf->data, bio_buf->length, 1);
1925 0 : add_assoc_zval(zout, "cert", zcert);
1926 : }
1927 0 : BIO_free(bio_out);
1928 :
1929 0 : bio_out = BIO_new(BIO_s_mem());
1930 0 : if (PEM_write_bio_PrivateKey(bio_out, pkey, NULL, NULL, 0, 0, NULL)) {
1931 : BUF_MEM *bio_buf;
1932 0 : BIO_get_mem_ptr(bio_out, &bio_buf);
1933 0 : MAKE_STD_ZVAL(zpkey);
1934 0 : ZVAL_STRINGL(zpkey, bio_buf->data, bio_buf->length, 1);
1935 0 : add_assoc_zval(zout, "pkey", zpkey);
1936 : }
1937 0 : BIO_free(bio_out);
1938 :
1939 0 : MAKE_STD_ZVAL(zextracerts);
1940 0 : array_init(zextracerts);
1941 :
1942 0 : for (i=0;;i++) {
1943 : zval * zextracert;
1944 0 : X509* aCA = sk_X509_pop(ca);
1945 0 : if (!aCA) break;
1946 :
1947 0 : bio_out = BIO_new(BIO_s_mem());
1948 0 : if (PEM_write_bio_X509(bio_out, aCA)) {
1949 : BUF_MEM *bio_buf;
1950 0 : BIO_get_mem_ptr(bio_out, &bio_buf);
1951 0 : MAKE_STD_ZVAL(zextracert);
1952 0 : ZVAL_STRINGL(zextracert, bio_buf->data, bio_buf->length, 1);
1953 0 : add_index_zval(zextracerts, i, zextracert);
1954 :
1955 : }
1956 0 : BIO_free(bio_out);
1957 :
1958 0 : X509_free(aCA);
1959 0 : }
1960 0 : if(ca) {
1961 0 : sk_X509_free(ca);
1962 0 : add_assoc_zval(zout, "extracerts", zextracerts);
1963 : } else {
1964 0 : zval_dtor(zextracerts);
1965 : }
1966 :
1967 0 : RETVAL_TRUE;
1968 :
1969 0 : PKCS12_free(p12);
1970 : }
1971 : }
1972 :
1973 1 : cleanup:
1974 1 : if (bio_in) {
1975 1 : BIO_free(bio_in);
1976 : }
1977 1 : if (pkey) {
1978 0 : EVP_PKEY_free(pkey);
1979 : }
1980 1 : if (cert) {
1981 0 : X509_free(cert);
1982 : }
1983 : }
1984 : /* }}} */
1985 :
1986 : /* {{{ x509 CSR functions */
1987 :
1988 : /* {{{ php_openssl_make_REQ */
1989 : static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, zval * dn, zval * attribs TSRMLS_DC)
1990 5 : {
1991 5 : STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL;
1992 : char * str, *dn_sect, *attr_sect;
1993 :
1994 5 : dn_sect = CONF_get_string(req->req_config, req->section_name, "distinguished_name");
1995 5 : if (dn_sect == NULL) {
1996 0 : return FAILURE;
1997 : }
1998 5 : dn_sk = CONF_get_section(req->req_config, dn_sect);
1999 5 : if (dn_sk == NULL) {
2000 0 : return FAILURE;
2001 : }
2002 5 : attr_sect = CONF_get_string(req->req_config, req->section_name, "attributes");
2003 5 : if (attr_sect == NULL) {
2004 0 : attr_sk = NULL;
2005 : } else {
2006 5 : attr_sk = CONF_get_section(req->req_config, attr_sect);
2007 5 : if (attr_sk == NULL) {
2008 0 : return FAILURE;
2009 : }
2010 : }
2011 : /* setup the version number: version 1 */
2012 5 : if (X509_REQ_set_version(csr, 0L)) {
2013 : int i, nid;
2014 : char * type;
2015 : CONF_VALUE * v;
2016 : X509_NAME * subj;
2017 : HashPosition hpos;
2018 : zval ** item;
2019 :
2020 5 : subj = X509_REQ_get_subject_name(csr);
2021 : /* apply values from the dn hash */
2022 5 : zend_hash_internal_pointer_reset_ex(HASH_OF(dn), &hpos);
2023 27 : while(zend_hash_get_current_data_ex(HASH_OF(dn), (void**)&item, &hpos) == SUCCESS) {
2024 17 : char * strindex = NULL;
2025 17 : uint strindexlen = 0;
2026 : ulong intindex;
2027 :
2028 17 : zend_hash_get_current_key_ex(HASH_OF(dn), &strindex, &strindexlen, &intindex, 0, &hpos);
2029 :
2030 17 : convert_to_string_ex(item);
2031 :
2032 17 : if (strindex) {
2033 : int nid;
2034 :
2035 15 : nid = OBJ_txt2nid(strindex);
2036 15 : if (nid != NID_undef) {
2037 15 : if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC,
2038 : (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0))
2039 : {
2040 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_PP(item));
2041 0 : return FAILURE;
2042 : }
2043 : } else {
2044 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: %s is not a recognized name", strindex);
2045 : }
2046 : }
2047 17 : zend_hash_move_forward_ex(HASH_OF(dn), &hpos);
2048 : }
2049 :
2050 : /* Finally apply defaults from config file */
2051 80 : for(i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) {
2052 : int len;
2053 : char buffer[200 + 1]; /*200 + \0 !*/
2054 :
2055 75 : v = sk_CONF_VALUE_value(dn_sk, i);
2056 75 : type = v->name;
2057 :
2058 75 : len = strlen(type);
2059 75 : if (len < sizeof("_default")) {
2060 0 : continue;
2061 : }
2062 75 : len -= sizeof("_default") - 1;
2063 75 : if (strcmp("_default", type + len) != 0) {
2064 55 : continue;
2065 : }
2066 20 : if (len > 200) {
2067 0 : len = 200;
2068 : }
2069 20 : memcpy(buffer, type, len);
2070 20 : buffer[len] = '\0';
2071 20 : type = buffer;
2072 :
2073 : /* Skip past any leading X. X: X, etc to allow for multiple
2074 : * instances */
2075 235 : for (str = type; *str; str++) {
2076 220 : if (*str == ':' || *str == ',' || *str == '.') {
2077 5 : str++;
2078 5 : if (*str) {
2079 5 : type = str;
2080 : }
2081 5 : break;
2082 : }
2083 : }
2084 : /* if it is already set, skip this */
2085 20 : nid = OBJ_txt2nid(type);
2086 20 : if (X509_NAME_get_index_by_NID(subj, nid, -1) >= 0) {
2087 10 : continue;
2088 : }
2089 10 : if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_ASC, (unsigned char*)v->value, -1, -1, 0)) {
2090 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value);
2091 0 : return FAILURE;
2092 : }
2093 10 : if (!X509_NAME_entry_count(subj)) {
2094 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "no objects specified in config file");
2095 0 : return FAILURE;
2096 : }
2097 : }
2098 5 : if (attribs) {
2099 1 : zend_hash_internal_pointer_reset_ex(HASH_OF(attribs), &hpos);
2100 2 : while(zend_hash_get_current_data_ex(HASH_OF(attribs), (void**)&item, &hpos) == SUCCESS) {
2101 : char * strindex; uint strindexlen;
2102 : ulong intindex;
2103 :
2104 0 : zend_hash_get_current_key_ex(HASH_OF(attribs), &strindex, &strindexlen, &intindex, 0, &hpos);
2105 0 : convert_to_string_ex(item);
2106 :
2107 0 : if (strindex) {
2108 : int nid;
2109 :
2110 0 : nid = OBJ_txt2nid(strindex);
2111 0 : if (nid != NID_undef) {
2112 0 : if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_ASC, (unsigned char*)Z_STRVAL_PP(item), -1, -1, 0)) {
2113 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_PP(item));
2114 0 : return FAILURE;
2115 : }
2116 : } else {
2117 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "dn: %s is not a recognized name", strindex);
2118 : }
2119 : }
2120 0 : zend_hash_move_forward_ex(HASH_OF(attribs), &hpos);
2121 : }
2122 2 : for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) {
2123 2 : v = sk_CONF_VALUE_value(attr_sk, i);
2124 : /* if it is already set, skip this */
2125 2 : nid = OBJ_txt2nid(v->name);
2126 2 : if (X509_REQ_get_attr_by_NID(csr, nid, -1) >= 0) {
2127 0 : continue;
2128 : }
2129 2 : if (!X509_REQ_add1_attr_by_txt(csr, v->name, MBSTRING_ASC, (unsigned char*)v->value, -1)) {
2130 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "add1_attr_by_txt %s -> %s (failed)", v->name, v->value);
2131 1 : return FAILURE;
2132 : }
2133 : }
2134 : }
2135 : }
2136 :
2137 4 : X509_REQ_set_pubkey(csr, req->priv_key);
2138 4 : return SUCCESS;
2139 : }
2140 : /* }}} */
2141 :
2142 : /* {{{ php_openssl_csr_from_zval */
2143 : static X509_REQ * php_openssl_csr_from_zval(zval ** val, int makeresource, long * resourceval TSRMLS_DC)
2144 16 : {
2145 16 : X509_REQ * csr = NULL;
2146 16 : char * filename = NULL;
2147 : BIO * in;
2148 :
2149 16 : if (resourceval) {
2150 16 : *resourceval = -1;
2151 : }
2152 16 : if (Z_TYPE_PP(val) == IS_RESOURCE) {
2153 : void * what;
2154 : int type;
2155 :
2156 13 : what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509 CSR", &type, 1, le_csr);
2157 13 : if (what) {
2158 12 : if (resourceval) {
2159 12 : *resourceval = Z_LVAL_PP(val);
2160 : }
2161 12 : return (X509_REQ*)what;
2162 : }
2163 1 : return NULL;
2164 3 : } else if (Z_TYPE_PP(val) != IS_STRING) {
2165 1 : return NULL;
2166 : }
2167 :
2168 2 : if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) {
2169 0 : filename = Z_STRVAL_PP(val) + (sizeof("file://") - 1);
2170 : }
2171 2 : if (filename) {
2172 0 : if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
2173 0 : return NULL;
2174 : }
2175 0 : in = BIO_new_file(filename, "r");
2176 : } else {
2177 2 : in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
2178 : }
2179 2 : csr = PEM_read_bio_X509_REQ(in, NULL,NULL,NULL);
2180 2 : BIO_free(in);
2181 :
2182 2 : return csr;
2183 : }
2184 : /* }}} */
2185 :
2186 : /* {{{ proto bool openssl_csr_export_to_file(resource csr, string outfilename [, bool notext=true])
2187 : Exports a CSR to file */
2188 : PHP_FUNCTION(openssl_csr_export_to_file)
2189 0 : {
2190 : X509_REQ * csr;
2191 0 : zval * zcsr = NULL;
2192 0 : zend_bool notext = 1;
2193 0 : char * filename = NULL; int filename_len;
2194 : BIO * bio_out;
2195 : long csr_resource;
2196 :
2197 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|b", &zcsr, &filename, &filename_len, ¬ext) == FAILURE) {
2198 0 : return;
2199 : }
2200 0 : RETVAL_FALSE;
2201 :
2202 0 : csr = php_openssl_csr_from_zval(&zcsr, 0, &csr_resource TSRMLS_CC);
2203 0 : if (csr == NULL) {
2204 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1");
2205 0 : return;
2206 : }
2207 :
2208 0 : if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
2209 0 : return;
2210 : }
2211 :
2212 0 : bio_out = BIO_new_file(filename, "w");
2213 0 : if (bio_out) {
2214 0 : if (!notext) {
2215 0 : X509_REQ_print(bio_out, csr);
2216 : }
2217 0 : PEM_write_bio_X509_REQ(bio_out, csr);
2218 0 : RETVAL_TRUE;
2219 : } else {
2220 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening file %s", filename);
2221 : }
2222 :
2223 0 : if (csr_resource == -1 && csr) {
2224 0 : X509_REQ_free(csr);
2225 : }
2226 0 : BIO_free(bio_out);
2227 : }
2228 : /* }}} */
2229 :
2230 : /* {{{ proto bool openssl_csr_export(resource csr, string &out [, bool notext=true])
2231 : Exports a CSR to file or a var */
2232 : PHP_FUNCTION(openssl_csr_export)
2233 6 : {
2234 : X509_REQ * csr;
2235 6 : zval * zcsr = NULL, *zout=NULL;
2236 6 : zend_bool notext = 1;
2237 : BIO * bio_out;
2238 :
2239 : long csr_resource;
2240 :
2241 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|b", &zcsr, &zout, ¬ext) == FAILURE) {
2242 2 : return;
2243 : }
2244 4 : RETVAL_FALSE;
2245 :
2246 4 : csr = php_openssl_csr_from_zval(&zcsr, 0, &csr_resource TSRMLS_CC);
2247 4 : if (csr == NULL) {
2248 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1");
2249 1 : return;
2250 : }
2251 :
2252 : /* export to a var */
2253 :
2254 3 : bio_out = BIO_new(BIO_s_mem());
2255 3 : if (!notext) {
2256 2 : X509_REQ_print(bio_out, csr);
2257 : }
2258 :
2259 3 : if (PEM_write_bio_X509_REQ(bio_out, csr)) {
2260 : BUF_MEM *bio_buf;
2261 :
2262 3 : BIO_get_mem_ptr(bio_out, &bio_buf);
2263 3 : zval_dtor(zout);
2264 3 : ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length, 1);
2265 :
2266 3 : RETVAL_TRUE;
2267 : }
2268 :
2269 3 : if (csr_resource == -1 && csr) {
2270 0 : X509_REQ_free(csr);
2271 : }
2272 3 : BIO_free(bio_out);
2273 : }
2274 : /* }}} */
2275 :
2276 : /* {{{ proto resource openssl_csr_sign(mixed csr, mixed x509, mixed priv_key, long days [, array config_args [, long serial]])
2277 : Signs a cert with another CERT */
2278 : PHP_FUNCTION(openssl_csr_sign)
2279 14 : {
2280 14 : zval ** zcert = NULL, **zcsr, **zpkey, *args = NULL;
2281 : long num_days;
2282 14 : long serial = 0L;
2283 14 : X509 * cert = NULL, *new_cert = NULL;
2284 : X509_REQ * csr;
2285 14 : EVP_PKEY * key = NULL, *priv_key = NULL;
2286 14 : long csr_resource, certresource = 0, keyresource = -1;
2287 : int i;
2288 : struct php_x509_request req;
2289 :
2290 14 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ!Zl|a!l", &zcsr, &zcert, &zpkey, &num_days, &args, &serial) == FAILURE)
2291 3 : return;
2292 :
2293 11 : RETVAL_FALSE;
2294 11 : PHP_SSL_REQ_INIT(&req);
2295 :
2296 11 : csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC);
2297 11 : if (csr == NULL) {
2298 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get CSR from parameter 1");
2299 2 : return;
2300 : }
2301 9 : if (zcert) {
2302 3 : cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
2303 3 : if (cert == NULL) {
2304 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get cert from parameter 2");
2305 2 : goto cleanup;
2306 : }
2307 : }
2308 7 : priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource TSRMLS_CC);
2309 7 : if (priv_key == NULL) {
2310 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get private key from parameter 3");
2311 2 : goto cleanup;
2312 : }
2313 5 : if (cert && !X509_check_private_key(cert, priv_key)) {
2314 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key does not correspond to signing cert");
2315 0 : goto cleanup;
2316 : }
2317 :
2318 5 : if (PHP_SSL_REQ_PARSE(&req, args) == FAILURE) {
2319 0 : goto cleanup;
2320 : }
2321 : /* Check that the request matches the signature */
2322 5 : key = X509_REQ_get_pubkey(csr);
2323 5 : if (key == NULL) {
2324 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error unpacking public key");
2325 0 : goto cleanup;
2326 : }
2327 5 : i = X509_REQ_verify(csr, key);
2328 :
2329 5 : if (i < 0) {
2330 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Signature verification problems");
2331 0 : goto cleanup;
2332 : }
2333 5 : else if (i == 0) {
2334 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Signature did not match the certificate request");
2335 0 : goto cleanup;
2336 : }
2337 :
2338 : /* Now we can get on with it */
2339 :
2340 5 : new_cert = X509_new();
2341 5 : if (new_cert == NULL) {
2342 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "No memory");
2343 0 : goto cleanup;
2344 : }
2345 : /* Version 3 cert */
2346 5 : if (!X509_set_version(new_cert, 2))
2347 0 : goto cleanup;
2348 :
2349 5 : ASN1_INTEGER_set(X509_get_serialNumber(new_cert), serial);
2350 :
2351 5 : X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr));
2352 :
2353 5 : if (cert == NULL) {
2354 4 : cert = new_cert;
2355 : }
2356 5 : if (!X509_set_issuer_name(new_cert, X509_get_subject_name(cert))) {
2357 0 : goto cleanup;
2358 : }
2359 5 : X509_gmtime_adj(X509_get_notBefore(new_cert), 0);
2360 5 : X509_gmtime_adj(X509_get_notAfter(new_cert), (long)60*60*24*num_days);
2361 5 : i = X509_set_pubkey(new_cert, key);
2362 5 : if (!i) {
2363 0 : goto cleanup;
2364 : }
2365 5 : if (req.extensions_section) {
2366 : X509V3_CTX ctx;
2367 :
2368 5 : X509V3_set_ctx(&ctx, cert, new_cert, csr, NULL, 0);
2369 5 : X509V3_set_conf_lhash(&ctx, req.req_config);
2370 5 : if (!X509V3_EXT_add_conf(req.req_config, &ctx, req.extensions_section, new_cert)) {
2371 0 : goto cleanup;
2372 : }
2373 : }
2374 :
2375 : /* Now sign it */
2376 5 : if (!X509_sign(new_cert, priv_key, req.digest)) {
2377 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to sign it");
2378 0 : goto cleanup;
2379 : }
2380 :
2381 : /* Succeeded; lets return the cert */
2382 5 : RETVAL_RESOURCE(zend_list_insert(new_cert, le_x509));
2383 5 : new_cert = NULL;
2384 :
2385 9 : cleanup:
2386 :
2387 9 : if (cert == new_cert) {
2388 4 : cert = NULL;
2389 : }
2390 9 : PHP_SSL_REQ_DISPOSE(&req);
2391 :
2392 9 : if (keyresource == -1 && priv_key) {
2393 0 : EVP_PKEY_free(priv_key);
2394 : }
2395 9 : if (key) {
2396 5 : EVP_PKEY_free(key);
2397 : }
2398 9 : if (csr_resource == -1 && csr) {
2399 0 : X509_REQ_free(csr);
2400 : }
2401 9 : if (certresource == -1 && cert) {
2402 1 : X509_free(cert);
2403 : }
2404 9 : if (new_cert) {
2405 0 : X509_free(new_cert);
2406 : }
2407 : }
2408 : /* }}} */
2409 :
2410 : /* {{{ proto bool openssl_csr_new(array dn, resource &privkey [, array configargs [, array extraattribs]])
2411 : Generates a privkey and CSR */
2412 : PHP_FUNCTION(openssl_csr_new)
2413 7 : {
2414 : struct php_x509_request req;
2415 7 : zval * args = NULL, * dn, *attribs = NULL;
2416 : zval * out_pkey;
2417 7 : X509_REQ * csr = NULL;
2418 7 : int we_made_the_key = 1;
2419 : long key_resource;
2420 :
2421 7 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) {
2422 2 : return;
2423 : }
2424 5 : RETVAL_FALSE;
2425 :
2426 5 : PHP_SSL_REQ_INIT(&req);
2427 :
2428 5 : if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
2429 : /* Generate or use a private key */
2430 5 : if (Z_TYPE_P(out_pkey) != IS_NULL) {
2431 5 : req.priv_key = php_openssl_evp_from_zval(&out_pkey, 0, NULL, 0, &key_resource TSRMLS_CC);
2432 5 : if (req.priv_key != NULL) {
2433 3 : we_made_the_key = 0;
2434 : }
2435 : }
2436 5 : if (req.priv_key == NULL) {
2437 2 : php_openssl_generate_private_key(&req TSRMLS_CC);
2438 : }
2439 5 : if (req.priv_key == NULL) {
2440 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to generate a private key");
2441 : } else {
2442 5 : csr = X509_REQ_new();
2443 5 : if (csr) {
2444 5 : if (php_openssl_make_REQ(&req, csr, dn, attribs TSRMLS_CC) == SUCCESS) {
2445 : X509V3_CTX ext_ctx;
2446 :
2447 4 : X509V3_set_ctx(&ext_ctx, NULL, NULL, csr, NULL, 0);
2448 4 : X509V3_set_conf_lhash(&ext_ctx, req.req_config);
2449 :
2450 : /* Add extensions */
2451 4 : if (req.request_extensions_section && !X509V3_EXT_REQ_add_conf(req.req_config,
2452 : &ext_ctx, req.request_extensions_section, csr))
2453 : {
2454 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error loading extension section %s", req.request_extensions_section);
2455 : } else {
2456 4 : RETVAL_TRUE;
2457 :
2458 4 : if (X509_REQ_sign(csr, req.priv_key, req.digest)) {
2459 4 : RETVAL_RESOURCE(zend_list_insert(csr, le_csr));
2460 4 : csr = NULL;
2461 : } else {
2462 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error signing request");
2463 : }
2464 :
2465 4 : if (we_made_the_key) {
2466 : /* and a resource for the private key */
2467 1 : zval_dtor(out_pkey);
2468 1 : ZVAL_RESOURCE(out_pkey, zend_list_insert(req.priv_key, le_key));
2469 1 : req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */
2470 3 : } else if (key_resource != -1) {
2471 3 : req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */
2472 : }
2473 : }
2474 : }
2475 : else {
2476 1 : if (!we_made_the_key) {
2477 : /* if we have not made the key we are not supposed to zap it by calling dispose! */
2478 0 : req.priv_key = NULL;
2479 : }
2480 : }
2481 : }
2482 : }
2483 : }
2484 5 : if (csr) {
2485 1 : X509_REQ_free(csr);
2486 : }
2487 5 : PHP_SSL_REQ_DISPOSE(&req);
2488 : }
2489 : /* }}} */
2490 :
2491 : /* {{{ proto mixed openssl_csr_get_subject(mixed csr)
2492 : Returns the subject of a CERT or FALSE on error */
2493 : PHP_FUNCTION(openssl_csr_get_subject)
2494 1 : {
2495 : zval ** zcsr;
2496 1 : zend_bool use_shortnames = 1;
2497 : long csr_resource;
2498 : X509_NAME * subject;
2499 : X509_REQ * csr;
2500 :
2501 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcsr, &use_shortnames) == FAILURE) {
2502 0 : return;
2503 : }
2504 :
2505 1 : csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC);
2506 :
2507 1 : if (csr == NULL) {
2508 0 : RETURN_FALSE;
2509 : }
2510 :
2511 1 : subject = X509_REQ_get_subject_name(csr);
2512 :
2513 1 : array_init(return_value);
2514 1 : add_assoc_name_entry(return_value, NULL, subject, use_shortnames TSRMLS_CC);
2515 1 : return;
2516 : }
2517 : /* }}} */
2518 :
2519 : /* {{{ proto mixed openssl_csr_get_public_key(mixed csr)
2520 : Returns the subject of a CERT or FALSE on error */
2521 : PHP_FUNCTION(openssl_csr_get_public_key)
2522 0 : {
2523 : zval ** zcsr;
2524 0 : zend_bool use_shortnames = 1;
2525 : long csr_resource;
2526 :
2527 : X509_REQ * csr;
2528 : EVP_PKEY *tpubkey;
2529 :
2530 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|b", &zcsr, &use_shortnames) == FAILURE) {
2531 0 : return;
2532 : }
2533 :
2534 0 : csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource TSRMLS_CC);
2535 :
2536 0 : if (csr == NULL) {
2537 0 : RETURN_FALSE;
2538 : }
2539 :
2540 0 : tpubkey=X509_REQ_get_pubkey(csr);
2541 0 : RETVAL_RESOURCE(zend_list_insert(tpubkey, le_key));
2542 0 : return;
2543 : }
2544 : /* }}} */
2545 :
2546 : /* }}} */
2547 :
2548 : /* {{{ EVP Public/Private key functions */
2549 :
2550 : /* {{{ php_openssl_evp_from_zval
2551 : Given a zval, coerce it into a EVP_PKEY object.
2552 : It can be:
2553 : 1. private key resource from openssl_get_privatekey()
2554 : 2. X509 resource -> public key will be extracted from it
2555 : 3. if it starts with file:// interpreted as path to key file
2556 : 4. interpreted as the data from the cert/key file and interpreted in same way as openssl_get_privatekey()
2557 : 5. an array(0 => [items 2..4], 1 => passphrase)
2558 : 6. if val is a string (possibly starting with file:///) and it is not an X509 certificate, then interpret as public key
2559 : NOTE: If you are requesting a private key but have not specified a passphrase, you should use an
2560 : empty string rather than NULL for the passphrase - NULL causes a passphrase prompt to be emitted in
2561 : the Apache error log!
2562 : */
2563 : static EVP_PKEY * php_openssl_evp_from_zval(zval ** val, int public_key, char * passphrase, int makeresource, long * resourceval TSRMLS_DC)
2564 99 : {
2565 99 : EVP_PKEY * key = NULL;
2566 99 : X509 * cert = NULL;
2567 99 : int free_cert = 0;
2568 99 : long cert_res = -1;
2569 99 : char * filename = NULL;
2570 : zval tmp;
2571 :
2572 99 : Z_TYPE(tmp) = IS_NULL;
2573 :
2574 : #define TMP_CLEAN \
2575 : if (Z_TYPE(tmp) == IS_STRING) {\
2576 : zval_dtor(&tmp); \
2577 : } \
2578 : return NULL;
2579 :
2580 99 : if (resourceval) {
2581 99 : *resourceval = -1;
2582 : }
2583 99 : if (Z_TYPE_PP(val) == IS_ARRAY) {
2584 : zval ** zphrase;
2585 :
2586 : /* get passphrase */
2587 :
2588 9 : if (zend_hash_index_find(HASH_OF(*val), 1, (void **)&zphrase) == FAILURE) {
2589 5 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)");
2590 5 : return NULL;
2591 : }
2592 :
2593 4 : if (Z_TYPE_PP(zphrase) == IS_STRING) {
2594 3 : passphrase = Z_STRVAL_PP(zphrase);
2595 : } else {
2596 1 : tmp = **zphrase;
2597 1 : zval_copy_ctor(&tmp);
2598 1 : convert_to_string(&tmp);
2599 1 : passphrase = Z_STRVAL(tmp);
2600 : }
2601 :
2602 : /* now set val to be the key param and continue */
2603 4 : if (zend_hash_index_find(HASH_OF(*val), 0, (void **)&val) == FAILURE) {
2604 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)");
2605 0 : TMP_CLEAN;
2606 : }
2607 : }
2608 :
2609 94 : if (Z_TYPE_PP(val) == IS_RESOURCE) {
2610 : void * what;
2611 : int type;
2612 :
2613 16 : what = zend_fetch_resource(val TSRMLS_CC, -1, "OpenSSL X.509/key", &type, 2, le_x509, le_key);
2614 16 : if (!what) {
2615 0 : TMP_CLEAN;
2616 : }
2617 16 : if (resourceval) {
2618 16 : *resourceval = Z_LVAL_PP(val);
2619 : }
2620 16 : if (type == le_x509) {
2621 : /* extract key from cert, depending on public_key param */
2622 0 : cert = (X509*)what;
2623 0 : free_cert = 0;
2624 16 : } else if (type == le_key) {
2625 : int is_priv;
2626 :
2627 16 : is_priv = php_openssl_is_private_key((EVP_PKEY*)what TSRMLS_CC);
2628 :
2629 : /* check whether it is actually a private key if requested */
2630 16 : if (!public_key && !is_priv) {
2631 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param is a public key");
2632 0 : TMP_CLEAN;
2633 : }
2634 :
2635 16 : if (public_key && is_priv) {
2636 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Don't know how to get public key from this private key");
2637 1 : TMP_CLEAN;
2638 : } else {
2639 15 : if (Z_TYPE(tmp) == IS_STRING) {
2640 0 : zval_dtor(&tmp);
2641 : }
2642 : /* got the key - return it */
2643 15 : return (EVP_PKEY*)what;
2644 : }
2645 : } else {
2646 : /* other types could be used here - eg: file pointers and read in the data from them */
2647 0 : TMP_CLEAN;
2648 : }
2649 : } else {
2650 : /* force it to be a string and check if it refers to a file */
2651 : /* passing non string values leaks, object uses toString, it returns NULL
2652 : * See bug38255.phpt
2653 : */
2654 78 : if (!(Z_TYPE_PP(val) == IS_STRING || Z_TYPE_PP(val) == IS_OBJECT)) {
2655 5 : TMP_CLEAN;
2656 : }
2657 73 : convert_to_string_ex(val);
2658 :
2659 73 : if (Z_STRLEN_PP(val) > 7 && memcmp(Z_STRVAL_PP(val), "file://", sizeof("file://") - 1) == 0) {
2660 51 : filename = Z_STRVAL_PP(val) + (sizeof("file://") - 1);
2661 : }
2662 : /* it's an X509 file/cert of some kind, and we need to extract the data from that */
2663 73 : if (public_key) {
2664 27 : cert = php_openssl_x509_from_zval(val, 0, &cert_res TSRMLS_CC);
2665 27 : free_cert = (cert_res == -1);
2666 : /* actual extraction done later */
2667 27 : if (!cert) {
2668 : /* not a X509 certificate, try to retrieve public key */
2669 : BIO* in;
2670 26 : if (filename) {
2671 20 : in = BIO_new_file(filename, "r");
2672 : } else {
2673 6 : in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
2674 : }
2675 26 : if (in == NULL) {
2676 0 : TMP_CLEAN;
2677 : }
2678 26 : key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
2679 26 : BIO_free(in);
2680 : }
2681 : } else {
2682 : /* we want the private key */
2683 : BIO *in;
2684 :
2685 46 : if (filename) {
2686 31 : if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
2687 0 : TMP_CLEAN;
2688 : }
2689 31 : in = BIO_new_file(filename, "r");
2690 : } else {
2691 15 : in = BIO_new_mem_buf(Z_STRVAL_PP(val), Z_STRLEN_PP(val));
2692 : }
2693 :
2694 46 : if (in == NULL) {
2695 0 : TMP_CLEAN;
2696 : }
2697 46 : key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);
2698 46 : BIO_free(in);
2699 : }
2700 : }
2701 :
2702 73 : if (public_key && cert && key == NULL) {
2703 : /* extract public key from X509 cert */
2704 1 : key = (EVP_PKEY *) X509_get_pubkey(cert);
2705 : }
2706 :
2707 73 : if (free_cert && cert) {
2708 1 : X509_free(cert);
2709 : }
2710 73 : if (key && makeresource && resourceval) {
2711 12 : *resourceval = ZEND_REGISTER_RESOURCE(NULL, key, le_key);
2712 : }
2713 73 : if (Z_TYPE(tmp) == IS_STRING) {
2714 0 : zval_dtor(&tmp);
2715 : }
2716 73 : return key;
2717 : }
2718 : /* }}} */
2719 :
2720 : /* {{{ php_openssl_generate_private_key */
2721 : static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req TSRMLS_DC)
2722 10 : {
2723 10 : char * randfile = NULL;
2724 : int egdsocket, seeded;
2725 10 : EVP_PKEY * return_val = NULL;
2726 :
2727 10 : if (req->priv_key_bits < MIN_KEY_LENGTH) {
2728 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "private key length is too short; it needs to be at least %d bits, not %d",
2729 : MIN_KEY_LENGTH, req->priv_key_bits);
2730 0 : return NULL;
2731 : }
2732 :
2733 10 : randfile = CONF_get_string(req->req_config, req->section_name, "RANDFILE");
2734 10 : php_openssl_load_rand_file(randfile, &egdsocket, &seeded);
2735 :
2736 10 : if ((req->priv_key = EVP_PKEY_new()) != NULL) {
2737 10 : switch(req->priv_key_type) {
2738 : case OPENSSL_KEYTYPE_RSA:
2739 10 : if (EVP_PKEY_assign_RSA(req->priv_key, RSA_generate_key(req->priv_key_bits, 0x10001, NULL, NULL))) {
2740 10 : return_val = req->priv_key;
2741 : }
2742 10 : break;
2743 : #if !defined(NO_DSA) && defined(HAVE_DSA_DEFAULT_METHOD)
2744 : case OPENSSL_KEYTYPE_DSA:
2745 : {
2746 0 : DSA *dsapar = DSA_generate_parameters(req->priv_key_bits, NULL, 0, NULL, NULL, NULL, NULL);
2747 0 : if (dsapar) {
2748 0 : DSA_set_method(dsapar, DSA_get_default_method());
2749 0 : if (DSA_generate_key(dsapar)) {
2750 0 : if (EVP_PKEY_assign_DSA(req->priv_key, dsapar)) {
2751 0 : return_val = req->priv_key;
2752 : }
2753 : } else {
2754 0 : DSA_free(dsapar);
2755 : }
2756 : }
2757 : }
2758 0 : break;
2759 : #endif
2760 : #if !defined(NO_DH)
2761 : case OPENSSL_KEYTYPE_DH:
2762 : {
2763 0 : DH *dhpar = DH_generate_parameters(req->priv_key_bits, 2, NULL, NULL);
2764 0 : int codes = 0;
2765 :
2766 0 : if (dhpar) {
2767 0 : DH_set_method(dhpar, DH_get_default_method());
2768 0 : if (DH_check(dhpar, &codes) && codes == 0 && DH_generate_key(dhpar)) {
2769 0 : if (EVP_PKEY_assign_DH(req->priv_key, dhpar)) {
2770 0 : return_val = req->priv_key;
2771 : }
2772 : } else {
2773 0 : DH_free(dhpar);
2774 : }
2775 : }
2776 : }
2777 0 : break;
2778 : #endif
2779 : default:
2780 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unsupported private key type");
2781 : }
2782 : }
2783 :
2784 10 : php_openssl_write_rand_file(randfile, egdsocket, seeded);
2785 :
2786 10 : if (return_val == NULL) {
2787 0 : EVP_PKEY_free(req->priv_key);
2788 0 : req->priv_key = NULL;
2789 0 : return NULL;
2790 : }
2791 :
2792 10 : return return_val;
2793 : }
2794 : /* }}} */
2795 :
2796 : /* {{{ php_openssl_is_private_key
2797 : Check whether the supplied key is a private key by checking if the secret prime factors are set */
2798 : static int php_openssl_is_private_key(EVP_PKEY* pkey TSRMLS_DC)
2799 16 : {
2800 : assert(pkey != NULL);
2801 :
2802 16 : switch (pkey->type) {
2803 : #ifndef NO_RSA
2804 : case EVP_PKEY_RSA:
2805 : case EVP_PKEY_RSA2:
2806 : assert(pkey->pkey.rsa != NULL);
2807 14 : if (pkey->pkey.rsa != NULL && (NULL == pkey->pkey.rsa->p || NULL == pkey->pkey.rsa->q)) {
2808 1 : return 0;
2809 : }
2810 13 : break;
2811 : #endif
2812 : #ifndef NO_DSA
2813 : case EVP_PKEY_DSA:
2814 : case EVP_PKEY_DSA1:
2815 : case EVP_PKEY_DSA2:
2816 : case EVP_PKEY_DSA3:
2817 : case EVP_PKEY_DSA4:
2818 : assert(pkey->pkey.dsa != NULL);
2819 :
2820 2 : if (NULL == pkey->pkey.dsa->p || NULL == pkey->pkey.dsa->q || NULL == pkey->pkey.dsa->priv_key){
2821 1 : return 0;
2822 : }
2823 1 : break;
2824 : #endif
2825 : #ifndef NO_DH
2826 : case EVP_PKEY_DH:
2827 : assert(pkey->pkey.dh != NULL);
2828 :
2829 0 : if (NULL == pkey->pkey.dh->p || NULL == pkey->pkey.dh->priv_key) {
2830 0 : return 0;
2831 : }
2832 0 : break;
2833 : #endif
2834 : default:
2835 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
2836 : break;
2837 : }
2838 14 : return 1;
2839 : }
2840 : /* }}} */
2841 :
2842 : #define OPENSSL_PKEY_GET_BN(_type, _name) do { \
2843 : if (pkey->pkey._type->_name != NULL) { \
2844 : int len = BN_num_bytes(pkey->pkey._type->_name); \
2845 : char *str = emalloc(len + 1); \
2846 : BN_bn2bin(pkey->pkey._type->_name, (unsigned char*)str); \
2847 : str[len] = 0; \
2848 : add_assoc_stringl(_type, #_name, str, len, 0); \
2849 : } \
2850 : } while (0)
2851 :
2852 : #define OPENSSL_PKEY_SET_BN(_ht, _type, _name) do { \
2853 : zval **bn; \
2854 : if (zend_hash_find(_ht, #_name, sizeof(#_name), (void**)&bn) == SUCCESS && \
2855 : Z_TYPE_PP(bn) == IS_STRING) { \
2856 : _type->_name = BN_bin2bn( \
2857 : (unsigned char*)Z_STRVAL_PP(bn), \
2858 : Z_STRLEN_PP(bn), NULL); \
2859 : } \
2860 : } while (0);
2861 :
2862 :
2863 : /* {{{ proto resource openssl_pkey_new([array configargs])
2864 : Generates a new private key */
2865 : PHP_FUNCTION(openssl_pkey_new)
2866 11 : {
2867 : struct php_x509_request req;
2868 11 : zval * args = NULL;
2869 : zval **data;
2870 :
2871 11 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &args) == FAILURE) {
2872 0 : return;
2873 : }
2874 11 : RETVAL_FALSE;
2875 :
2876 11 : if (args && Z_TYPE_P(args) == IS_ARRAY) {
2877 : EVP_PKEY *pkey;
2878 :
2879 3 : if (zend_hash_find(Z_ARRVAL_P(args), "rsa", sizeof("rsa"), (void**)&data) == SUCCESS &&
2880 : Z_TYPE_PP(data) == IS_ARRAY) {
2881 1 : pkey = EVP_PKEY_new();
2882 1 : if (pkey) {
2883 1 : RSA *rsa = RSA_new();
2884 1 : if (rsa) {
2885 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, n);
2886 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, e);
2887 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, d);
2888 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, p);
2889 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, q);
2890 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, dmp1);
2891 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, dmq1);
2892 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), rsa, iqmp);
2893 1 : if (rsa->n && rsa->d) {
2894 0 : if (EVP_PKEY_assign_RSA(pkey, rsa)) {
2895 0 : RETURN_RESOURCE(zend_list_insert(pkey, le_key));
2896 : }
2897 : }
2898 1 : RSA_free(rsa);
2899 : }
2900 1 : EVP_PKEY_free(pkey);
2901 : }
2902 1 : RETURN_FALSE;
2903 2 : } else if (zend_hash_find(Z_ARRVAL_P(args), "dsa", sizeof("dsa"), (void**)&data) == SUCCESS &&
2904 : Z_TYPE_PP(data) == IS_ARRAY) {
2905 1 : pkey = EVP_PKEY_new();
2906 1 : if (pkey) {
2907 1 : DSA *dsa = DSA_new();
2908 1 : if (dsa) {
2909 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, p);
2910 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, q);
2911 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, g);
2912 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, priv_key);
2913 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dsa, pub_key);
2914 1 : if (dsa->p && dsa->q && dsa->g) {
2915 0 : if (!dsa->priv_key && !dsa->pub_key) {
2916 0 : DSA_generate_key(dsa);
2917 : }
2918 0 : if (EVP_PKEY_assign_DSA(pkey, dsa)) {
2919 0 : RETURN_RESOURCE(zend_list_insert(pkey, le_key));
2920 : }
2921 : }
2922 1 : DSA_free(dsa);
2923 : }
2924 1 : EVP_PKEY_free(pkey);
2925 : }
2926 1 : RETURN_FALSE;
2927 1 : } else if (zend_hash_find(Z_ARRVAL_P(args), "dh", sizeof("dh"), (void**)&data) == SUCCESS &&
2928 : Z_TYPE_PP(data) == IS_ARRAY) {
2929 1 : pkey = EVP_PKEY_new();
2930 1 : if (pkey) {
2931 1 : DH *dh = DH_new();
2932 1 : if (dh) {
2933 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, p);
2934 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, g);
2935 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, priv_key);
2936 1 : OPENSSL_PKEY_SET_BN(Z_ARRVAL_PP(data), dh, pub_key);
2937 1 : if (dh->p && dh->g) {
2938 0 : if (!dh->pub_key) {
2939 0 : DH_generate_key(dh);
2940 : }
2941 0 : if (EVP_PKEY_assign_DH(pkey, dh)) {
2942 0 : RETURN_RESOURCE(zend_list_insert(pkey, le_key));
2943 : }
2944 : }
2945 1 : DH_free(dh);
2946 : }
2947 1 : EVP_PKEY_free(pkey);
2948 : }
2949 1 : RETURN_FALSE;
2950 : }
2951 : }
2952 :
2953 8 : PHP_SSL_REQ_INIT(&req);
2954 :
2955 8 : if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS)
2956 : {
2957 8 : if (php_openssl_generate_private_key(&req TSRMLS_CC)) {
2958 : /* pass back a key resource */
2959 8 : RETVAL_RESOURCE(zend_list_insert(req.priv_key, le_key));
2960 : /* make sure the cleanup code doesn't zap it! */
2961 8 : req.priv_key = NULL;
2962 : }
2963 : }
2964 8 : PHP_SSL_REQ_DISPOSE(&req);
2965 : }
2966 : /* }}} */
2967 :
2968 : /* {{{ proto bool openssl_pkey_export_to_file(mixed key, string outfilename [, string passphrase, array config_args)
2969 : Gets an exportable representation of a key into a file */
2970 : PHP_FUNCTION(openssl_pkey_export_to_file)
2971 1 : {
2972 : struct php_x509_request req;
2973 1 : zval ** zpkey, * args = NULL;
2974 1 : char * passphrase = NULL; int passphrase_len = 0;
2975 1 : char * filename = NULL; int filename_len = 0;
2976 1 : long key_resource = -1;
2977 : EVP_PKEY * key;
2978 1 : BIO * bio_out = NULL;
2979 : const EVP_CIPHER * cipher;
2980 :
2981 1 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) {
2982 0 : return;
2983 : }
2984 1 : RETVAL_FALSE;
2985 :
2986 1 : key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC);
2987 :
2988 1 : if (key == NULL) {
2989 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1");
2990 0 : RETURN_FALSE;
2991 : }
2992 :
2993 1 : if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
2994 0 : RETURN_FALSE;
2995 : }
2996 :
2997 1 : PHP_SSL_REQ_INIT(&req);
2998 :
2999 1 : if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
3000 1 : bio_out = BIO_new_file(filename, "w");
3001 :
3002 2 : if (passphrase && req.priv_key_encrypt) {
3003 1 : cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
3004 : } else {
3005 0 : cipher = NULL;
3006 : }
3007 1 : if (PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)) {
3008 : /* Success!
3009 : * If returning the output as a string, do so now */
3010 1 : RETVAL_TRUE;
3011 : }
3012 : }
3013 1 : PHP_SSL_REQ_DISPOSE(&req);
3014 :
3015 1 : if (key_resource == -1 && key) {
3016 0 : EVP_PKEY_free(key);
3017 : }
3018 1 : if (bio_out) {
3019 1 : BIO_free(bio_out);
3020 : }
3021 : }
3022 : /* }}} */
3023 :
3024 : /* {{{ proto bool openssl_pkey_export(mixed key, &mixed out [, string passphrase [, array config_args]])
3025 : Gets an exportable representation of a key into a string or file */
3026 : PHP_FUNCTION(openssl_pkey_export)
3027 3 : {
3028 : struct php_x509_request req;
3029 3 : zval ** zpkey, * args = NULL, *out;
3030 3 : char * passphrase = NULL; int passphrase_len = 0;
3031 3 : long key_resource = -1;
3032 : EVP_PKEY * key;
3033 3 : BIO * bio_out = NULL;
3034 : const EVP_CIPHER * cipher;
3035 :
3036 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zz|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) {
3037 0 : return;
3038 : }
3039 3 : RETVAL_FALSE;
3040 :
3041 3 : key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource TSRMLS_CC);
3042 :
3043 3 : if (key == NULL) {
3044 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot get key from parameter 1");
3045 0 : RETURN_FALSE;
3046 : }
3047 :
3048 3 : PHP_SSL_REQ_INIT(&req);
3049 :
3050 3 : if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
3051 3 : bio_out = BIO_new(BIO_s_mem());
3052 :
3053 3 : if (passphrase && req.priv_key_encrypt) {
3054 0 : cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
3055 : } else {
3056 3 : cipher = NULL;
3057 : }
3058 3 : if (PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, passphrase_len, NULL, NULL)) {
3059 : /* Success!
3060 : * If returning the output as a string, do so now */
3061 :
3062 : char * bio_mem_ptr;
3063 : long bio_mem_len;
3064 3 : RETVAL_TRUE;
3065 :
3066 3 : bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr);
3067 3 : zval_dtor(out);
3068 3 : ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len, 1);
3069 : }
3070 : }
3071 3 : PHP_SSL_REQ_DISPOSE(&req);
3072 :
3073 3 : if (key_resource == -1 && key) {
3074 0 : EVP_PKEY_free(key);
3075 : }
3076 3 : if (bio_out) {
3077 3 : BIO_free(bio_out);
3078 : }
3079 : }
3080 : /* }}} */
3081 :
3082 : /* {{{ proto int openssl_pkey_get_public(mixed cert)
3083 : Gets public key from X.509 certificate */
3084 : PHP_FUNCTION(openssl_pkey_get_public)
3085 3 : {
3086 : zval **cert;
3087 : EVP_PKEY *pkey;
3088 :
3089 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &cert) == FAILURE) {
3090 0 : return;
3091 : }
3092 3 : Z_TYPE_P(return_value) = IS_RESOURCE;
3093 3 : pkey = php_openssl_evp_from_zval(cert, 1, NULL, 1, &Z_LVAL_P(return_value) TSRMLS_CC);
3094 :
3095 3 : if (pkey == NULL) {
3096 1 : RETURN_FALSE;
3097 : }
3098 : }
3099 : /* }}} */
3100 :
3101 : /* {{{ proto void openssl_pkey_free(int key)
3102 : Frees a key */
3103 : PHP_FUNCTION(openssl_pkey_free)
3104 3 : {
3105 : zval *key;
3106 : EVP_PKEY *pkey;
3107 :
3108 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &key) == FAILURE) {
3109 0 : return;
3110 : }
3111 3 : ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
3112 3 : zend_list_delete(Z_LVAL_P(key));
3113 : }
3114 : /* }}} */
3115 :
3116 : /* {{{ proto int openssl_pkey_get_private(string key [, string passphrase])
3117 : Gets private keys */
3118 : PHP_FUNCTION(openssl_pkey_get_private)
3119 7 : {
3120 : zval **cert;
3121 : EVP_PKEY *pkey;
3122 7 : char * passphrase = "";
3123 7 : int passphrase_len = sizeof("")-1;
3124 :
3125 7 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|s", &cert, &passphrase, &passphrase_len) == FAILURE) {
3126 0 : return;
3127 : }
3128 7 : Z_TYPE_P(return_value) = IS_RESOURCE;
3129 7 : pkey = php_openssl_evp_from_zval(cert, 0, passphrase, 1, &Z_LVAL_P(return_value) TSRMLS_CC);
3130 :
3131 7 : if (pkey == NULL) {
3132 0 : RETURN_FALSE;
3133 : }
3134 : }
3135 :
3136 : /* }}} */
3137 :
3138 : /* {{{ proto resource openssl_pkey_get_details(resource key)
3139 : returns an array with the key details (bits, pkey, type)*/
3140 : PHP_FUNCTION(openssl_pkey_get_details)
3141 4 : {
3142 : zval *key;
3143 : EVP_PKEY *pkey;
3144 : BIO *out;
3145 : unsigned int pbio_len;
3146 : char *pbio;
3147 : long ktype;
3148 :
3149 4 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &key) == FAILURE) {
3150 3 : return;
3151 : }
3152 1 : ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
3153 1 : if (!pkey) {
3154 0 : RETURN_FALSE;
3155 : }
3156 1 : out = BIO_new(BIO_s_mem());
3157 1 : PEM_write_bio_PUBKEY(out, pkey);
3158 1 : pbio_len = BIO_get_mem_data(out, &pbio);
3159 :
3160 1 : array_init(return_value);
3161 1 : add_assoc_long(return_value, "bits", EVP_PKEY_bits(pkey));
3162 1 : add_assoc_stringl(return_value, "key", pbio, pbio_len, 1);
3163 : /*TODO: Use the real values once the openssl constants are used
3164 : * See the enum at the top of this file
3165 : */
3166 1 : switch (EVP_PKEY_type(pkey->type)) {
3167 : case EVP_PKEY_RSA:
3168 : case EVP_PKEY_RSA2:
3169 1 : ktype = OPENSSL_KEYTYPE_RSA;
3170 :
3171 1 : if (pkey->pkey.rsa != NULL) {
3172 : zval *rsa;
3173 :
3174 1 : ALLOC_INIT_ZVAL(rsa);
3175 1 : array_init(rsa);
3176 1 : OPENSSL_PKEY_GET_BN(rsa, n);
3177 1 : OPENSSL_PKEY_GET_BN(rsa, e);
3178 1 : OPENSSL_PKEY_GET_BN(rsa, d);
3179 1 : OPENSSL_PKEY_GET_BN(rsa, p);
3180 1 : OPENSSL_PKEY_GET_BN(rsa, q);
3181 1 : OPENSSL_PKEY_GET_BN(rsa, dmp1);
3182 1 : OPENSSL_PKEY_GET_BN(rsa, dmq1);
3183 1 : OPENSSL_PKEY_GET_BN(rsa, iqmp);
3184 1 : add_assoc_zval(return_value, "rsa", rsa);
3185 : }
3186 :
3187 1 : break;
3188 : case EVP_PKEY_DSA:
3189 : case EVP_PKEY_DSA2:
3190 : case EVP_PKEY_DSA3:
3191 : case EVP_PKEY_DSA4:
3192 0 : ktype = OPENSSL_KEYTYPE_DSA;
3193 :
3194 0 : if (pkey->pkey.dsa != NULL) {
3195 : zval *dsa;
3196 :
3197 0 : ALLOC_INIT_ZVAL(dsa);
3198 0 : array_init(dsa);
3199 0 : OPENSSL_PKEY_GET_BN(dsa, p);
3200 0 : OPENSSL_PKEY_GET_BN(dsa, q);
3201 0 : OPENSSL_PKEY_GET_BN(dsa, g);
3202 0 : OPENSSL_PKEY_GET_BN(dsa, priv_key);
3203 0 : OPENSSL_PKEY_GET_BN(dsa, pub_key);
3204 0 : add_assoc_zval(return_value, "dsa", dsa);
3205 : }
3206 0 : break;
3207 : case EVP_PKEY_DH:
3208 :
3209 0 : ktype = OPENSSL_KEYTYPE_DH;
3210 :
3211 0 : if (pkey->pkey.dh != NULL) {
3212 : zval *dh;
3213 :
3214 0 : ALLOC_INIT_ZVAL(dh);
3215 0 : array_init(dh);
3216 0 : OPENSSL_PKEY_GET_BN(dh, p);
3217 0 : OPENSSL_PKEY_GET_BN(dh, g);
3218 0 : OPENSSL_PKEY_GET_BN(dh, priv_key);
3219 0 : OPENSSL_PKEY_GET_BN(dh, pub_key);
3220 0 : add_assoc_zval(return_value, "dh", dh);
3221 : }
3222 :
3223 0 : break;
3224 : #ifdef EVP_PKEY_EC
3225 : case EVP_PKEY_EC:
3226 0 : ktype = OPENSSL_KEYTYPE_EC;
3227 0 : break;
3228 : #endif
3229 : default:
3230 0 : ktype = -1;
3231 : break;
3232 : }
3233 1 : add_assoc_long(return_value, "type", ktype);
3234 :
3235 1 : BIO_free(out);
3236 : }
3237 : /* }}} */
3238 :
3239 : /* }}} */
3240 :
3241 : /* {{{ PKCS7 S/MIME functions */
3242 :
3243 : /* {{{ proto bool openssl_pkcs7_verify(string filename, long flags [, string signerscerts [, array cainfo [, string extracerts [, string content]]]])
3244 : Verifys that the data block is intact, the signer is who they say they are, and returns the CERTs of the signers */
3245 : PHP_FUNCTION(openssl_pkcs7_verify)
3246 0 : {
3247 0 : X509_STORE * store = NULL;
3248 0 : zval * cainfo = NULL;
3249 0 : STACK_OF(X509) *signers= NULL;
3250 0 : STACK_OF(X509) *others = NULL;
3251 0 : PKCS7 * p7 = NULL;
3252 0 : BIO * in = NULL, * datain = NULL, * dataout = NULL;
3253 0 : long flags = 0;
3254 : char * filename; int filename_len;
3255 0 : char * extracerts = NULL; int extracerts_len = 0;
3256 0 : char * signersfilename = NULL; int signersfilename_len = 0;
3257 0 : char * datafilename = NULL; int datafilename_len = 0;
3258 :
3259 0 : RETVAL_LONG(-1);
3260 :
3261 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|sass", &filename, &filename_len,
3262 : &flags, &signersfilename, &signersfilename_len, &cainfo,
3263 : &extracerts, &extracerts_len, &datafilename, &datafilename_len) == FAILURE) {
3264 0 : return;
3265 : }
3266 :
3267 0 : if (extracerts) {
3268 0 : others = load_all_certs_from_file(extracerts);
3269 0 : if (others == NULL) {
3270 0 : goto clean_exit;
3271 : }
3272 : }
3273 :
3274 0 : flags = flags & ~PKCS7_DETACHED;
3275 :
3276 0 : store = setup_verify(cainfo TSRMLS_CC);
3277 :
3278 0 : if (!store) {
3279 0 : goto clean_exit;
3280 : }
3281 0 : if (php_openssl_safe_mode_chk(filename TSRMLS_CC)) {
3282 0 : goto clean_exit;
3283 : }
3284 :
3285 0 : in = BIO_new_file(filename, (flags & PKCS7_BINARY) ? "rb" : "r");
3286 0 : if (in == NULL) {
3287 0 : goto clean_exit;
3288 : }
3289 0 : p7 = SMIME_read_PKCS7(in, &datain);
3290 0 : if (p7 == NULL) {
3291 : #if DEBUG_SMIME
3292 : zend_printf("SMIME_read_PKCS7 failed\n");
3293 : #endif
3294 0 : goto clean_exit;
3295 : }
3296 :
3297 0 : if (datafilename) {
3298 :
3299 0 : if (php_openssl_safe_mode_chk(datafilename TSRMLS_CC)) {
3300 0 : goto clean_exit;
3301 : }
3302 :
3303 0 : dataout = BIO_new_file(datafilename, "w");
3304 0 : if (dataout == NULL) {
3305 0 : goto clean_exit;
3306 : }
3307 : }
3308 : #if DEBUG_SMIME
3309 : zend_printf("Calling PKCS7 verify\n");
3310 : #endif
3311 :
3312 0 : if (PKCS7_verify(p7, others, store, datain, dataout, flags)) {
3313 :
3314 0 : RETVAL_TRUE;
3315 :
3316 0 : if (signersfilename) {
3317 : BIO *certout;
3318 :
3319 0 : if (php_openssl_safe_mode_chk(signersfilename TSRMLS_CC)) {
3320 0 : goto clean_exit;
3321 : }
3322 :
3323 0 : certout = BIO_new_file(signersfilename, "w");
3324 0 : if (certout) {
3325 : int i;
3326 0 : signers = PKCS7_get0_signers(p7, NULL, flags);
3327 :
3328 0 : for(i = 0; i < sk_X509_num(signers); i++) {
3329 0 : PEM_write_bio_X509(certout, sk_X509_value(signers, i));
3330 : }
3331 0 : BIO_free(certout);
3332 0 : sk_X509_free(signers);
3333 : } else {
3334 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename);
3335 0 : RETVAL_LONG(-1);
3336 : }
3337 : }
3338 0 : goto clean_exit;
3339 : } else {
3340 0 : RETVAL_FALSE;
3341 : }
3342 0 : clean_exit:
3343 0 : X509_STORE_free(store);
3344 0 : BIO_free(datain);
3345 0 : BIO_free(in);
3346 0 : BIO_free(dataout);
3347 0 : PKCS7_free(p7);
3348 0 : sk_X509_free(others);
3349 : }
3350 : /* }}} */
3351 :
3352 : /* {{{ proto bool openssl_pkcs7_encrypt(string infile, string outfile, mixed recipcerts, array headers [, long flags [, long cipher]])
3353 : Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */
3354 : PHP_FUNCTION(openssl_pkcs7_encrypt)
3355 12 : {
3356 12 : zval ** zrecipcerts, * zheaders = NULL;
3357 12 : STACK_OF(X509) * recipcerts = NULL;
3358 12 : BIO * infile = NULL, * outfile = NULL;
3359 12 : long flags = 0;
3360 12 : PKCS7 * p7 = NULL;
3361 : HashPosition hpos;
3362 : zval ** zcertval;
3363 : X509 * cert;
3364 12 : const EVP_CIPHER *cipher = NULL;
3365 12 : long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
3366 : uint strindexlen;
3367 : ulong intindex;
3368 : char * strindex;
3369 12 : char * infilename = NULL; int infilename_len;
3370 12 : char * outfilename = NULL; int outfilename_len;
3371 :
3372 12 : RETVAL_FALSE;
3373 :
3374 12 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZa!|ll", &infilename, &infilename_len,
3375 : &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE)
3376 2 : return;
3377 :
3378 :
3379 10 : if (php_openssl_safe_mode_chk(infilename TSRMLS_CC) || php_openssl_safe_mode_chk(outfilename TSRMLS_CC)) {
3380 0 : return;
3381 : }
3382 :
3383 10 : infile = BIO_new_file(infilename, "r");
3384 10 : if (infile == NULL) {
3385 2 : goto clean_exit;
3386 : }
3387 :
3388 8 : outfile = BIO_new_file(outfilename, "w");
3389 8 : if (outfile == NULL) {
3390 1 : goto clean_exit;
3391 : }
3392 :
3393 7 : recipcerts = sk_X509_new_null();
3394 :
3395 : /* get certs */
3396 7 : if (Z_TYPE_PP(zrecipcerts) == IS_ARRAY) {
3397 1 : zend_hash_internal_pointer_reset_ex(HASH_OF(*zrecipcerts), &hpos);
3398 4 : while(zend_hash_get_current_data_ex(HASH_OF(*zrecipcerts), (void**)&zcertval, &hpos) == SUCCESS) {
3399 : long certresource;
3400 :
3401 2 : cert = php_openssl_x509_from_zval(zcertval, 0, &certresource TSRMLS_CC);
3402 2 : if (cert == NULL) {
3403 0 : goto clean_exit;
3404 : }
3405 :
3406 2 : if (certresource != -1) {
3407 : /* we shouldn't free this particular cert, as it is a resource.
3408 : make a copy and push that on the stack instead */
3409 0 : cert = X509_dup(cert);
3410 0 : if (cert == NULL) {
3411 0 : goto clean_exit;
3412 : }
3413 : }
3414 2 : sk_X509_push(recipcerts, cert);
3415 :
3416 2 : zend_hash_move_forward_ex(HASH_OF(*zrecipcerts), &hpos);
3417 : }
3418 : } else {
3419 : /* a single certificate */
3420 : long certresource;
3421 :
3422 6 : cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource TSRMLS_CC);
3423 6 : if (cert == NULL) {
3424 2 : goto clean_exit;
3425 : }
3426 :
3427 4 : if (certresource != -1) {
3428 : /* we shouldn't free this particular cert, as it is a resource.
3429 : make a copy and push that on the stack instead */
3430 0 : cert = X509_dup(cert);
3431 0 : if (cert == NULL) {
3432 0 : goto clean_exit;
3433 : }
3434 : }
3435 4 : sk_X509_push(recipcerts, cert);
3436 : }
3437 :
3438 : /* sanity check the cipher */
3439 5 : cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
3440 5 : if (cipher == NULL) {
3441 : /* shouldn't happen */
3442 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to get cipher");
3443 0 : goto clean_exit;
3444 : }
3445 :
3446 5 : p7 = PKCS7_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, flags);
3447 :
3448 5 : if (p7 == NULL) {
3449 0 : goto clean_exit;
3450 : }
3451 :
3452 : /* tack on extra headers */
3453 5 : if (zheaders) {
3454 5 : zend_hash_internal_pointer_reset_ex(HASH_OF(zheaders), &hpos);
3455 18 : while(zend_hash_get_current_data_ex(HASH_OF(zheaders), (void**)&zcertval, &hpos) == SUCCESS) {
3456 8 : strindex = NULL;
3457 8 : zend_hash_get_current_key_ex(HASH_OF(zheaders), &strindex, &strindexlen, &intindex, 0, &hpos);
3458 :
3459 8 : convert_to_string_ex(zcertval);
3460 :
3461 8 : if (strindex) {
3462 2 : BIO_printf(outfile, "%s: %s\n", strindex, Z_STRVAL_PP(zcertval));
3463 : } else {
3464 6 : BIO_printf(outfile, "%s\n", Z_STRVAL_PP(zcertval));
3465 : }
3466 :
3467 8 : zend_hash_move_forward_ex(HASH_OF(zheaders), &hpos);
3468 : }
3469 : }
3470 :
3471 5 : (void)BIO_reset(infile);
3472 :
3473 : /* write the encrypted data */
3474 5 : SMIME_write_PKCS7(outfile, p7, infile, flags);
3475 :
3476 5 : RETVAL_TRUE;
3477 :
3478 10 : clean_exit:
3479 10 : PKCS7_free(p7);
3480 10 : BIO_free(infile);
3481 10 : BIO_free(outfile);
3482 10 : if (recipcerts) {
3483 7 : sk_X509_pop_free(recipcerts, X509_free);
3484 : }
3485 : }
3486 : /* }}} */
3487 :
3488 : /* {{{ proto bool openssl_pkcs7_sign(string infile, string outfile, mixed signcert, mixed signkey, array headers [, long flags [, string extracertsfilename]])
3489 : Signs the MIME message in the file named infile with signcert/signkey and output the result to file name outfile. headers lists plain text headers to exclude from the signed portion of the message, and should include to, from and subject as a minimum */
3490 :
3491 : PHP_FUNCTION(openssl_pkcs7_sign)
3492 11 : {
3493 : zval ** zcert, ** zprivkey, * zheaders;
3494 : zval ** hval;
3495 11 : X509 * cert = NULL;
3496 11 : EVP_PKEY * privkey = NULL;
3497 11 : long flags = PKCS7_DETACHED;
3498 11 : PKCS7 * p7 = NULL;
3499 11 : BIO * infile = NULL, * outfile = NULL;
3500 11 : STACK_OF(X509) *others = NULL;
3501 11 : long certresource = -1, keyresource = -1;
3502 : ulong intindex;
3503 : uint strindexlen;
3504 : HashPosition hpos;
3505 : char * strindex;
3506 : char * infilename; int infilename_len;
3507 : char * outfilename; int outfilename_len;
3508 11 : char * extracertsfilename = NULL; int extracertsfilename_len;
3509 :
3510 11 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZZa!|ls",
3511 : &infilename, &infilename_len, &outfilename, &outfilename_len,
3512 : &zcert, &zprivkey, &zheaders, &flags, &extracertsfilename,
3513 : &extracertsfilename_len) == FAILURE) {
3514 2 : return;
3515 : }
3516 :
3517 9 : RETVAL_FALSE;
3518 :
3519 9 : if (extracertsfilename) {
3520 0 : others = load_all_certs_from_file(extracertsfilename);
3521 0 : if (others == NULL) {
3522 0 : goto clean_exit;
3523 : }
3524 : }
3525 :
3526 9 : privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, &keyresource TSRMLS_CC);
3527 9 : if (privkey == NULL) {
3528 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting private key");
3529 1 : goto clean_exit;
3530 : }
3531 :
3532 8 : cert = php_openssl_x509_from_zval(zcert, 0, &certresource TSRMLS_CC);
3533 8 : if (cert == NULL) {
3534 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error getting cert");
3535 2 : goto clean_exit;
3536 : }
3537 :
3538 6 : if (php_openssl_safe_mode_chk(infilename TSRMLS_CC) || php_openssl_safe_mode_chk(outfilename TSRMLS_CC)) {
3539 : goto clean_exit;
3540 : }
3541 :
3542 6 : infile = BIO_new_file(infilename, "r");
3543 6 : if (infile == NULL) {
3544 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening input file %s!", infilename);
3545 2 : goto clean_exit;
3546 : }
3547 :
3548 4 : outfile = BIO_new_file(outfilename, "w");
3549 4 : if (outfile == NULL) {
3550 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error opening output file %s!", outfilename);
3551 1 : goto clean_exit;
3552 : }
3553 :
3554 3 : p7 = PKCS7_sign(cert, privkey, others, infile, flags);
3555 3 : if (p7 == NULL) {
3556 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "error creating PKCS7 structure!");
3557 0 : goto clean_exit;
3558 : }
3559 :
3560 3 : (void)BIO_reset(infile);
3561 :
3562 : /* tack on extra headers */
3563 3 : if (zheaders) {
3564 3 : zend_hash_internal_pointer_reset_ex(HASH_OF(zheaders), &hpos);
3565 10 : while(zend_hash_get_current_data_ex(HASH_OF(zheaders), (void**)&hval, &hpos) == SUCCESS) {
3566 4 : strindex = NULL;
3567 4 : zend_hash_get_current_key_ex(HASH_OF(zheaders), &strindex, &strindexlen, &intindex, 0, &hpos);
3568 :
3569 4 : convert_to_string_ex(hval);
3570 :
3571 4 : if (strindex) {
3572 2 : BIO_printf(outfile, "%s: %s\n", strindex, Z_STRVAL_PP(hval));
3573 : } else {
3574 2 : BIO_printf(outfile, "%s\n", Z_STRVAL_PP(hval));
3575 : }
3576 4 : zend_hash_move_forward_ex(HASH_OF(zheaders), &hpos);
3577 : }
3578 : }
3579 : /* write the signed data */
3580 3 : SMIME_write_PKCS7(outfile, p7, infile, flags);
3581 :
3582 3 : RETVAL_TRUE;
3583 :
3584 9 : clean_exit:
3585 9 : PKCS7_free(p7);
3586 9 : BIO_free(infile);
3587 9 : BIO_free(outfile);
3588 9 : if (others) {
3589 0 : sk_X509_pop_free(others, X509_free);
3590 : }
3591 9 : if (privkey && keyresource == -1) {
3592 8 : EVP_PKEY_free(privkey);
3593 : }
3594 9 : if (cert && certresource == -1) {
3595 6 : X509_free(cert);
3596 : }
3597 : }
3598 : /* }}} */
3599 :
3600 : /* {{{ proto bool openssl_pkcs7_decrypt(string infilename, string outfilename, mixed recipcert [, mixed recipkey])
3601 : Decrypts the S/MIME message in the file name infilename and output the results to the file name outfilename. recipcert is a CERT for one of the recipients. recipkey specifies the private key matching recipcert, if recipcert does not include the key */
3602 :
3603 : PHP_FUNCTION(openssl_pkcs7_decrypt)
3604 15 : {
3605 15 : zval ** recipcert, ** recipkey = NULL;
3606 15 : X509 * cert = NULL;
3607 15 : EVP_PKEY * key = NULL;
3608 : long certresval, keyresval;
3609 15 : BIO * in = NULL, * out = NULL, * datain = NULL;
3610 15 : PKCS7 * p7 = NULL;
3611 : char * infilename; int infilename_len;
3612 : char * outfilename; int outfilename_len;
3613 :
3614 15 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|Z", &infilename, &infilename_len,
3615 : &outfilename, &outfilename_len, &recipcert, &recipkey) == FAILURE) {
3616 0 : return;
3617 : }
3618 :
3619 15 : RETVAL_FALSE;
3620 :
3621 15 : cert = php_openssl_x509_from_zval(recipcert, 0, &certresval TSRMLS_CC);
3622 15 : if (cert == NULL) {
3623 8 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 3 to x509 cert");
3624 8 : goto clean_exit;
3625 : }
3626 :
3627 7 : key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, &keyresval TSRMLS_CC);
3628 7 : if (key == NULL) {
3629 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to get private key");
3630 2 : goto clean_exit;
3631 : }
3632 :
3633 5 : if (php_openssl_safe_mode_chk(infilename TSRMLS_CC) || php_openssl_safe_mode_chk(outfilename TSRMLS_CC)) {
3634 : goto clean_exit;
3635 : }
3636 :
3637 5 : in = BIO_new_file(infilename, "r");
3638 5 : if (in == NULL) {
3639 2 : goto clean_exit;
3640 : }
3641 3 : out = BIO_new_file(outfilename, "w");
3642 3 : if (out == NULL) {
3643 1 : goto clean_exit;
3644 : }
3645 :
3646 2 : p7 = SMIME_read_PKCS7(in, &datain);
3647 :
3648 2 : if (p7 == NULL) {
3649 0 : goto clean_exit;
3650 : }
3651 2 : if (PKCS7_decrypt(p7, key, cert, out, PKCS7_DETACHED)) {
3652 2 : RETVAL_TRUE;
3653 : }
3654 15 : clean_exit:
3655 15 : PKCS7_free(p7);
3656 15 : BIO_free(datain);
3657 15 : BIO_free(in);
3658 15 : BIO_free(out);
3659 15 : if (cert && certresval == -1) {
3660 7 : X509_free(cert);
3661 : }
3662 15 : if (key && keyresval == -1) {
3663 5 : EVP_PKEY_free(key);
3664 : }
3665 : }
3666 : /* }}} */
3667 :
3668 : /* }}} */
3669 :
3670 : /* {{{ proto bool openssl_private_encrypt(string data, string &crypted, mixed key [, int padding])
3671 : Encrypts data with private key */
3672 : PHP_FUNCTION(openssl_private_encrypt)
3673 6 : {
3674 : zval **key, *crypted;
3675 : EVP_PKEY *pkey;
3676 : int cryptedlen;
3677 6 : unsigned char *cryptedbuf = NULL;
3678 6 : int successful = 0;
3679 6 : long keyresource = -1;
3680 : char * data;
3681 : int data_len;
3682 6 : long padding = RSA_PKCS1_PADDING;
3683 :
3684 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
3685 0 : return;
3686 : }
3687 6 : RETVAL_FALSE;
3688 :
3689 6 : pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
3690 :
3691 6 : if (pkey == NULL) {
3692 3 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key param is not a valid private key");
3693 3 : RETURN_FALSE;
3694 : }
3695 :
3696 3 : cryptedlen = EVP_PKEY_size(pkey);
3697 3 : cryptedbuf = emalloc(cryptedlen + 1);
3698 :
3699 3 : switch (pkey->type) {
3700 : case EVP_PKEY_RSA:
3701 : case EVP_PKEY_RSA2:
3702 3 : successful = (RSA_private_encrypt(data_len,
3703 : (unsigned char *)data,
3704 : cryptedbuf,
3705 : pkey->pkey.rsa,
3706 : padding) == cryptedlen);
3707 3 : break;
3708 : default:
3709 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
3710 : }
3711 :
3712 3 : if (successful) {
3713 3 : zval_dtor(crypted);
3714 3 : cryptedbuf[cryptedlen] = '\0';
3715 3 : ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
3716 3 : cryptedbuf = NULL;
3717 3 : RETVAL_TRUE;
3718 : }
3719 3 : if (cryptedbuf) {
3720 0 : efree(cryptedbuf);
3721 : }
3722 3 : if (keyresource == -1) {
3723 3 : EVP_PKEY_free(pkey);
3724 : }
3725 : }
3726 : /* }}} */
3727 :
3728 : /* {{{ proto bool openssl_private_decrypt(string data, string &decrypted, mixed key [, int padding])
3729 : Decrypts data with private key */
3730 : PHP_FUNCTION(openssl_private_decrypt)
3731 6 : {
3732 : zval **key, *crypted;
3733 : EVP_PKEY *pkey;
3734 : int cryptedlen;
3735 6 : unsigned char *cryptedbuf = NULL;
3736 : unsigned char *crypttemp;
3737 6 : int successful = 0;
3738 6 : long padding = RSA_PKCS1_PADDING;
3739 6 : long keyresource = -1;
3740 : char * data;
3741 : int data_len;
3742 :
3743 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
3744 0 : return;
3745 : }
3746 6 : RETVAL_FALSE;
3747 :
3748 6 : pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
3749 6 : if (pkey == NULL) {
3750 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid private key");
3751 2 : RETURN_FALSE;
3752 : }
3753 :
3754 4 : cryptedlen = EVP_PKEY_size(pkey);
3755 4 : crypttemp = emalloc(cryptedlen + 1);
3756 :
3757 4 : switch (pkey->type) {
3758 : case EVP_PKEY_RSA:
3759 : case EVP_PKEY_RSA2:
3760 4 : cryptedlen = RSA_private_decrypt(data_len,
3761 : (unsigned char *)data,
3762 : crypttemp,
3763 : pkey->pkey.rsa,
3764 : padding);
3765 4 : if (cryptedlen != -1) {
3766 3 : cryptedbuf = emalloc(cryptedlen + 1);
3767 3 : memcpy(cryptedbuf, crypttemp, cryptedlen);
3768 3 : successful = 1;
3769 : }
3770 4 : break;
3771 : default:
3772 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
3773 : }
3774 :
3775 4 : efree(crypttemp);
3776 :
3777 4 : if (successful) {
3778 3 : zval_dtor(crypted);
3779 3 : cryptedbuf[cryptedlen] = '\0';
3780 3 : ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
3781 3 : cryptedbuf = NULL;
3782 3 : RETVAL_TRUE;
3783 : }
3784 :
3785 4 : if (keyresource == -1) {
3786 4 : EVP_PKEY_free(pkey);
3787 : }
3788 4 : if (cryptedbuf) {
3789 0 : efree(cryptedbuf);
3790 : }
3791 : }
3792 : /* }}} */
3793 :
3794 : /* {{{ proto bool openssl_public_encrypt(string data, string &crypted, mixed key [, int padding])
3795 : Encrypts data with public key */
3796 : PHP_FUNCTION(openssl_public_encrypt)
3797 6 : {
3798 : zval **key, *crypted;
3799 : EVP_PKEY *pkey;
3800 : int cryptedlen;
3801 : unsigned char *cryptedbuf;
3802 6 : int successful = 0;
3803 6 : long keyresource = -1;
3804 6 : long padding = RSA_PKCS1_PADDING;
3805 : char * data;
3806 : int data_len;
3807 :
3808 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE)
3809 0 : return;
3810 :
3811 6 : RETVAL_FALSE;
3812 :
3813 6 : pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
3814 6 : if (pkey == NULL) {
3815 3 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key");
3816 3 : RETURN_FALSE;
3817 : }
3818 :
3819 3 : cryptedlen = EVP_PKEY_size(pkey);
3820 3 : cryptedbuf = emalloc(cryptedlen + 1);
3821 :
3822 3 : switch (pkey->type) {
3823 : case EVP_PKEY_RSA:
3824 : case EVP_PKEY_RSA2:
3825 3 : successful = (RSA_public_encrypt(data_len,
3826 : (unsigned char *)data,
3827 : cryptedbuf,
3828 : pkey->pkey.rsa,
3829 : padding) == cryptedlen);
3830 3 : break;
3831 : default:
3832 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
3833 :
3834 : }
3835 :
3836 3 : if (successful) {
3837 3 : zval_dtor(crypted);
3838 3 : cryptedbuf[cryptedlen] = '\0';
3839 3 : ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
3840 3 : cryptedbuf = NULL;
3841 3 : RETVAL_TRUE;
3842 : }
3843 3 : if (keyresource == -1) {
3844 3 : EVP_PKEY_free(pkey);
3845 : }
3846 3 : if (cryptedbuf) {
3847 0 : efree(cryptedbuf);
3848 : }
3849 : }
3850 : /* }}} */
3851 :
3852 : /* {{{ proto bool openssl_public_decrypt(string data, string &crypted, resource key [, int padding])
3853 : Decrypts data with public key */
3854 : PHP_FUNCTION(openssl_public_decrypt)
3855 7 : {
3856 : zval **key, *crypted;
3857 : EVP_PKEY *pkey;
3858 : int cryptedlen;
3859 7 : unsigned char *cryptedbuf = NULL;
3860 : unsigned char *crypttemp;
3861 7 : int successful = 0;
3862 7 : long keyresource = -1;
3863 7 : long padding = RSA_PKCS1_PADDING;
3864 : char * data;
3865 : int data_len;
3866 :
3867 7 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
3868 0 : return;
3869 : }
3870 7 : RETVAL_FALSE;
3871 :
3872 7 : pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
3873 7 : if (pkey == NULL) {
3874 3 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key parameter is not a valid public key");
3875 3 : RETURN_FALSE;
3876 : }
3877 :
3878 4 : cryptedlen = EVP_PKEY_size(pkey);
3879 4 : crypttemp = emalloc(cryptedlen + 1);
3880 :
3881 4 : switch (pkey->type) {
3882 : case EVP_PKEY_RSA:
3883 : case EVP_PKEY_RSA2:
3884 4 : cryptedlen = RSA_public_decrypt(data_len,
3885 : (unsigned char *)data,
3886 : crypttemp,
3887 : pkey->pkey.rsa,
3888 : padding);
3889 4 : if (cryptedlen != -1) {
3890 3 : cryptedbuf = emalloc(cryptedlen + 1);
3891 3 : memcpy(cryptedbuf, crypttemp, cryptedlen);
3892 3 : successful = 1;
3893 : }
3894 4 : break;
3895 :
3896 : default:
3897 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "key type not supported in this PHP build!");
3898 :
3899 : }
3900 :
3901 4 : efree(crypttemp);
3902 :
3903 4 : if (successful) {
3904 3 : zval_dtor(crypted);
3905 3 : cryptedbuf[cryptedlen] = '\0';
3906 3 : ZVAL_STRINGL(crypted, (char *)cryptedbuf, cryptedlen, 0);
3907 3 : cryptedbuf = NULL;
3908 3 : RETVAL_TRUE;
3909 : }
3910 :
3911 4 : if (cryptedbuf) {
3912 0 : efree(cryptedbuf);
3913 : }
3914 4 : if (keyresource == -1) {
3915 4 : EVP_PKEY_free(pkey);
3916 : }
3917 : }
3918 : /* }}} */
3919 :
3920 : /* {{{ proto mixed openssl_error_string(void)
3921 : Returns a description of the last error, and alters the index of the error messages. Returns false when the are no more messages */
3922 : PHP_FUNCTION(openssl_error_string)
3923 0 : {
3924 : char buf[512];
3925 : unsigned long val;
3926 :
3927 0 : if (zend_parse_parameters_none() == FAILURE) {
3928 0 : return;
3929 : }
3930 :
3931 0 : val = ERR_get_error();
3932 0 : if (val) {
3933 0 : RETURN_STRING(ERR_error_string(val, buf), 1);
3934 : } else {
3935 0 : RETURN_FALSE;
3936 : }
3937 : }
3938 : /* }}} */
3939 :
3940 : /* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, mixed method])
3941 : Signs data */
3942 : PHP_FUNCTION(openssl_sign)
3943 6 : {
3944 : zval **key, *signature;
3945 : EVP_PKEY *pkey;
3946 : int siglen;
3947 : unsigned char *sigbuf;
3948 6 : long keyresource = -1;
3949 : char * data;
3950 : int data_len;
3951 : EVP_MD_CTX md_ctx;
3952 6 : zval *method = NULL;
3953 6 : long signature_algo = OPENSSL_ALGO_SHA1;
3954 : const EVP_MD *mdtype;
3955 :
3956 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szZ|z", &data, &data_len, &signature, &key, &method) == FAILURE) {
3957 1 : return;
3958 : }
3959 5 : pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource TSRMLS_CC);
3960 5 : if (pkey == NULL) {
3961 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param cannot be coerced into a private key");
3962 1 : RETURN_FALSE;
3963 : }
3964 :
3965 8 : if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
3966 4 : if (method != NULL) {
3967 2 : signature_algo = Z_LVAL_P(method);
3968 : }
3969 4 : mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
3970 0 : } else if (Z_TYPE_P(method) == IS_STRING) {
3971 0 : mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
3972 : } else {
3973 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
3974 0 : RETURN_FALSE;
3975 : }
3976 4 : if (!mdtype) {
3977 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
3978 0 : RETURN_FALSE;
3979 : }
3980 :
3981 4 : siglen = EVP_PKEY_size(pkey);
3982 4 : sigbuf = emalloc(siglen + 1);
3983 :
3984 4 : EVP_SignInit(&md_ctx, mdtype);
3985 4 : EVP_SignUpdate(&md_ctx, data, data_len);
3986 4 : if (EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, pkey)) {
3987 4 : zval_dtor(signature);
3988 4 : sigbuf[siglen] = '\0';
3989 4 : ZVAL_STRINGL(signature, (char *)sigbuf, siglen, 0);
3990 4 : RETVAL_TRUE;
3991 : } else {
3992 0 : efree(sigbuf);
3993 0 : RETVAL_FALSE;
3994 : }
3995 4 : EVP_MD_CTX_cleanup(&md_ctx);
3996 4 : if (keyresource == -1) {
3997 2 : EVP_PKEY_free(pkey);
3998 : }
3999 : }
4000 : /* }}} */
4001 :
4002 : /* {{{ proto int openssl_verify(string data, string signature, mixed key[, mixed method])
4003 : Verifys data */
4004 : PHP_FUNCTION(openssl_verify)
4005 15 : {
4006 : zval **key;
4007 : EVP_PKEY *pkey;
4008 : int err;
4009 : EVP_MD_CTX md_ctx;
4010 : const EVP_MD *mdtype;
4011 15 : long keyresource = -1;
4012 : char * data; int data_len;
4013 : char * signature; int signature_len;
4014 15 : zval *method = NULL;
4015 15 : long signature_algo = OPENSSL_ALGO_SHA1;
4016 :
4017 15 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssZ|z", &data, &data_len, &signature, &signature_len, &key, &method) == FAILURE) {
4018 5 : return;
4019 : }
4020 :
4021 20 : if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
4022 10 : if (method != NULL) {
4023 5 : signature_algo = Z_LVAL_P(method);
4024 : }
4025 10 : mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
4026 0 : } else if (Z_TYPE_P(method) == IS_STRING) {
4027 0 : mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
4028 : } else {
4029 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
4030 0 : RETURN_FALSE;
4031 : }
4032 10 : if (!mdtype) {
4033 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
4034 0 : RETURN_FALSE;
4035 : }
4036 :
4037 10 : pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource TSRMLS_CC);
4038 10 : if (pkey == NULL) {
4039 5 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "supplied key param cannot be coerced into a public key");
4040 5 : RETURN_FALSE;
4041 : }
4042 :
4043 5 : EVP_VerifyInit (&md_ctx, mdtype);
4044 5 : EVP_VerifyUpdate (&md_ctx, data, data_len);
4045 5 : err = EVP_VerifyFinal (&md_ctx, (unsigned char *)signature, signature_len, pkey);
4046 5 : EVP_MD_CTX_cleanup(&md_ctx);
4047 :
4048 5 : if (keyresource == -1) {
4049 3 : EVP_PKEY_free(pkey);
4050 : }
4051 5 : RETURN_LONG(err);
4052 : }
4053 : /* }}} */
4054 :
4055 : /* {{{ proto int openssl_seal(string data, &string sealdata, &array ekeys, array pubkeys)
4056 : Seals data */
4057 : PHP_FUNCTION(openssl_seal)
4058 11 : {
4059 : zval *pubkeys, **pubkey, *sealdata, *ekeys;
4060 : HashTable *pubkeysht;
4061 : HashPosition pos;
4062 : EVP_PKEY **pkeys;
4063 : long * key_resources; /* so we know what to cleanup */
4064 : int i, len1, len2, *eksl, nkeys;
4065 11 : unsigned char *buf = NULL, **eks;
4066 : char * data; int data_len;
4067 11 : char *method =NULL;
4068 11 : int method_len = 0;
4069 : const EVP_CIPHER *cipher;
4070 : EVP_CIPHER_CTX ctx;
4071 :
4072 11 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szza/|s", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len) == FAILURE) {
4073 3 : return;
4074 : }
4075 :
4076 8 : pubkeysht = HASH_OF(pubkeys);
4077 8 : nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0;
4078 8 : if (!nkeys) {
4079 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Fourth argument to openssl_seal() must be a non-empty array");
4080 2 : RETURN_FALSE;
4081 : }
4082 :
4083 6 : if (method) {
4084 0 : cipher = EVP_get_cipherbyname(method);
4085 0 : if (!cipher) {
4086 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
4087 0 : RETURN_FALSE;
4088 : }
4089 : } else {
4090 6 : cipher = EVP_rc4();
4091 : }
4092 :
4093 6 : pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
4094 6 : eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
4095 6 : eks = safe_emalloc(nkeys, sizeof(*eks), 0);
4096 6 : memset(eks, 0, sizeof(*eks) * nkeys);
4097 6 : key_resources = safe_emalloc(nkeys, sizeof(long), 0);
4098 6 : memset(key_resources, 0, sizeof(*key_resources) * nkeys);
4099 :
4100 : /* get the public keys we are using to seal this data */
4101 6 : zend_hash_internal_pointer_reset_ex(pubkeysht, &pos);
4102 6 : i = 0;
4103 19 : while (zend_hash_get_current_data_ex(pubkeysht, (void **) &pubkey,
4104 : &pos) == SUCCESS) {
4105 10 : pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, &key_resources[i] TSRMLS_CC);
4106 10 : if (pkeys[i] == NULL) {
4107 3 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "not a public key (%dth member of pubkeys)", i+1);
4108 3 : RETVAL_FALSE;
4109 3 : goto clean_exit;
4110 : }
4111 7 : eks[i] = emalloc(EVP_PKEY_size(pkeys[i]) + 1);
4112 7 : zend_hash_move_forward_ex(pubkeysht, &pos);
4113 7 : i++;
4114 : }
4115 :
4116 3 : if (!EVP_EncryptInit(&ctx,cipher,NULL,NULL)) {
4117 0 : RETVAL_FALSE;
4118 0 : goto clean_exit;
4119 : }
4120 :
4121 : #if 0
4122 : /* Need this if allow ciphers that require initialization vector */
4123 : ivlen = EVP_CIPHER_CTX_iv_length(&ctx);
4124 : iv = ivlen ? emalloc(ivlen + 1) : NULL;
4125 : #endif
4126 : /* allocate one byte extra to make room for \0 */
4127 3 : buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(&ctx));
4128 :
4129 3 : if (!EVP_SealInit(&ctx, cipher, eks, eksl, NULL, pkeys, nkeys) || !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
4130 0 : RETVAL_FALSE;
4131 0 : efree(buf);
4132 0 : goto clean_exit;
4133 : }
4134 :
4135 3 : EVP_SealFinal(&ctx, buf + len1, &len2);
4136 :
4137 3 : if (len1 + len2 > 0) {
4138 3 : zval_dtor(sealdata);
4139 3 : buf[len1 + len2] = '\0';
4140 3 : buf = erealloc(buf, len1 + len2 + 1);
4141 3 : ZVAL_STRINGL(sealdata, (char *)buf, len1 + len2, 0);
4142 :
4143 3 : zval_dtor(ekeys);
4144 3 : array_init(ekeys);
4145 9 : for (i=0; i<nkeys; i++) {
4146 6 : eks[i][eksl[i]] = '\0';
4147 6 : add_next_index_stringl(ekeys, erealloc(eks[i], eksl[i] + 1), eksl[i], 0);
4148 6 : eks[i] = NULL;
4149 : }
4150 : #if 0
4151 : /* If allow ciphers that need IV, we need this */
4152 : zval_dtor(*ivec);
4153 : if (ivlen) {
4154 : iv[ivlen] = '\0';
4155 : ZVAL_STRINGL(*ivec, erealloc(iv, ivlen + 1), ivlen, 0);
4156 : } else {
4157 : ZVAL_EMPTY_STRING(*ivec);
4158 : }
4159 : #endif
4160 : } else {
4161 0 : efree(buf);
4162 : }
4163 3 : RETVAL_LONG(len1 + len2);
4164 :
4165 6 : clean_exit:
4166 16 : for (i=0; i<nkeys; i++) {
4167 10 : if (key_resources[i] == -1) {
4168 10 : EVP_PKEY_free(pkeys[i]);
4169 : }
4170 10 : if (eks[i]) {
4171 1 : efree(eks[i]);
4172 : }
4173 : }
4174 6 : efree(eks);
4175 6 : efree(eksl);
4176 6 : efree(pkeys);
4177 6 : efree(key_resources);
4178 : }
4179 : /* }}} */
4180 :
4181 : /* {{{ proto bool openssl_open(string data, &string opendata, string ekey, mixed privkey)
4182 : Opens data */
4183 : PHP_FUNCTION(openssl_open)
4184 4 : {
4185 : zval **privkey, *opendata;
4186 : EVP_PKEY *pkey;
4187 : int len1, len2;
4188 : unsigned char *buf;
4189 4 : long keyresource = -1;
4190 : EVP_CIPHER_CTX ctx;
4191 : char * data; int data_len;
4192 : char * ekey; int ekey_len;
4193 4 : char *method =NULL;
4194 4 : int method_len = 0;
4195 : const EVP_CIPHER *cipher;
4196 :
4197 4 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szsZ|s", &data, &data_len, &opendata, &ekey, &ekey_len, &privkey, &method, &method_len) == FAILURE) {
4198 0 : return;
4199 : }
4200 :
4201 4 : pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, &keyresource TSRMLS_CC);
4202 4 : if (pkey == NULL) {
4203 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to coerce parameter 4 into a private key");
4204 1 : RETURN_FALSE;
4205 : }
4206 :
4207 3 : if (method) {
4208 0 : cipher = EVP_get_cipherbyname(method);
4209 0 : if (!cipher) {
4210 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm.");
4211 0 : RETURN_FALSE;
4212 : }
4213 : } else {
4214 3 : cipher = EVP_rc4();
4215 : }
4216 :
4217 3 : buf = emalloc(data_len + 1);
4218 :
4219 3 : if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, ekey_len, NULL, pkey) && EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, data_len)) {
4220 2 : if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) {
4221 0 : efree(buf);
4222 0 : if (keyresource == -1) {
4223 0 : EVP_PKEY_free(pkey);
4224 : }
4225 0 : RETURN_FALSE;
4226 : }
4227 : } else {
4228 1 : efree(buf);
4229 1 : if (keyresource == -1) {
4230 1 : EVP_PKEY_free(pkey);
4231 : }
4232 1 : RETURN_FALSE;
4233 : }
4234 2 : if (keyresource == -1) {
4235 2 : EVP_PKEY_free(pkey);
4236 : }
4237 2 : zval_dtor(opendata);
4238 2 : buf[len1 + len2] = '\0';
4239 2 : ZVAL_STRINGL(opendata, erealloc(buf, len1 + len2 + 1), len1 + len2, 0);
4240 2 : RETURN_TRUE;
4241 : }
4242 : /* }}} */
4243 :
4244 : /* SSL verification functions */
4245 :
4246 : #define GET_VER_OPT(name) (stream->context && SUCCESS == php_stream_context_get_option(stream->context, "ssl", name, &val))
4247 : #define GET_VER_OPT_STRING(name, str) if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_PP(val); }
4248 :
4249 : static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */
4250 0 : {
4251 : php_stream *stream;
4252 : SSL *ssl;
4253 : X509 *err_cert;
4254 : int err, depth, ret;
4255 : zval **val;
4256 :
4257 0 : ret = preverify_ok;
4258 :
4259 : /* determine the status for the current cert */
4260 0 : err_cert = X509_STORE_CTX_get_current_cert(ctx);
4261 0 : err = X509_STORE_CTX_get_error(ctx);
4262 0 : depth = X509_STORE_CTX_get_error_depth(ctx);
4263 :
4264 : /* conjure the stream & context to use */
4265 0 : ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
4266 0 : stream = (php_stream*)SSL_get_ex_data(ssl, ssl_stream_data_index);
4267 :
4268 : /* if allow_self_signed is set, make sure that verification succeeds */
4269 0 : if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GET_VER_OPT("allow_self_signed") && zval_is_true(*val)) {
4270 0 : ret = 1;
4271 : }
4272 :
4273 : /* check the depth */
4274 0 : if (GET_VER_OPT("verify_depth")) {
4275 0 : convert_to_long_ex(val);
4276 :
4277 0 : if (depth > Z_LVAL_PP(val)) {
4278 0 : ret = 0;
4279 0 : X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG);
4280 : }
4281 : }
4282 :
4283 0 : return ret;
4284 :
4285 : }
4286 : /* }}} */
4287 :
4288 : int php_openssl_apply_verification_policy(SSL *ssl, X509 *peer, php_stream *stream TSRMLS_DC) /* {{{ */
4289 5 : {
4290 5 : zval **val = NULL;
4291 5 : char *cnmatch = NULL;
4292 : X509_NAME *name;
4293 : char buf[1024];
4294 : int err;
4295 :
4296 : /* verification is turned off */
4297 5 : if (!(GET_VER_OPT("verify_peer") && zval_is_true(*val))) {
4298 5 : return SUCCESS;
4299 : }
4300 :
4301 0 : if (peer == NULL) {
4302 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not get peer certificate");
4303 0 : return FAILURE;
4304 : }
4305 :
4306 0 : err = SSL_get_verify_result(ssl);
4307 0 : switch (err) {
4308 : case X509_V_OK:
4309 : /* fine */
4310 0 : break;
4311 : case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
4312 0 : if (GET_VER_OPT("allow_self_signed") && zval_is_true(*val)) {
4313 : /* allowed */
4314 0 : break;
4315 : }
4316 : /* not allowed, so fall through */
4317 : default:
4318 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not verify peer: code:%d %s", err, X509_verify_cert_error_string(err));
4319 0 : return FAILURE;
4320 : }
4321 :
4322 : /* if the cert passed the usual checks, apply our own local policies now */
4323 :
4324 0 : name = X509_get_subject_name(peer);
4325 :
4326 : /* Does the common name match ? (used primarily for https://) */
4327 0 : GET_VER_OPT_STRING("CN_match", cnmatch);
4328 0 : if (cnmatch) {
4329 0 : int match = 0;
4330 0 : int name_len = X509_NAME_get_text_by_NID(name, NID_commonName, buf, sizeof(buf));
4331 :
4332 0 : if (name_len == -1) {
4333 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate peer certificate CN");
4334 0 : return FAILURE;
4335 0 : } else if (name_len != strlen(buf)) {
4336 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' is malformed", name_len, buf);
4337 0 : return FAILURE;
4338 : }
4339 :
4340 0 : match = strcmp(cnmatch, buf) == 0;
4341 0 : if (!match && strlen(buf) > 3 && buf[0] == '*' && buf[1] == '.') {
4342 : /* Try wildcard */
4343 :
4344 0 : if (strchr(buf+2, '.')) {
4345 0 : char *tmp = strstr(cnmatch, buf+1);
4346 :
4347 0 : match = tmp && strcmp(tmp, buf+2) && tmp == strchr(cnmatch, '.');
4348 : }
4349 : }
4350 :
4351 0 : if (!match) {
4352 : /* didn't match */
4353 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' did not match expected CN=`%s'", name_len, buf, cnmatch);
4354 0 : return FAILURE;
4355 : }
4356 : }
4357 :
4358 0 : return SUCCESS;
4359 : }
4360 : /* }}} */
4361 :
4362 : static int passwd_callback(char *buf, int num, int verify, void *data) /* {{{ */
4363 1 : {
4364 1 : php_stream *stream = (php_stream *)data;
4365 1 : zval **val = NULL;
4366 1 : char *passphrase = NULL;
4367 : /* TODO: could expand this to make a callback into PHP user-space */
4368 :
4369 1 : GET_VER_OPT_STRING("passphrase", passphrase);
4370 :
4371 1 : if (passphrase) {
4372 1 : if (Z_STRLEN_PP(val) < num - 1) {
4373 1 : memcpy(buf, Z_STRVAL_PP(val), Z_STRLEN_PP(val)+1);
4374 1 : return Z_STRLEN_PP(val);
4375 : }
4376 : }
4377 0 : return 0;
4378 : }
4379 : /* }}} */
4380 :
4381 : SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{ */
4382 5 : {
4383 5 : zval **val = NULL;
4384 5 : char *cafile = NULL;
4385 5 : char *capath = NULL;
4386 5 : char *certfile = NULL;
4387 5 : char *cipherlist = NULL;
4388 5 : int ok = 1;
4389 :
4390 5 : ERR_clear_error();
4391 :
4392 : /* look at context options in the stream and set appropriate verification flags */
4393 5 : if (GET_VER_OPT("verify_peer") && zval_is_true(*val)) {
4394 :
4395 : /* turn on verification callback */
4396 0 : SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
4397 :
4398 : /* CA stuff */
4399 0 : GET_VER_OPT_STRING("cafile", cafile);
4400 0 : GET_VER_OPT_STRING("capath", capath);
4401 :
4402 0 : if (cafile || capath) {
4403 0 : if (!SSL_CTX_load_verify_locations(ctx, cafile, capath)) {
4404 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set verify locations `%s' `%s'", cafile, capath);
4405 0 : return NULL;
4406 : }
4407 : }
4408 :
4409 0 : if (GET_VER_OPT("verify_depth")) {
4410 0 : convert_to_long_ex(val);
4411 0 : SSL_CTX_set_verify_depth(ctx, Z_LVAL_PP(val));
4412 : }
4413 : } else {
4414 5 : SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
4415 : }
4416 :
4417 : /* callback for the passphrase (for localcert) */
4418 5 : if (GET_VER_OPT("passphrase")) {
4419 1 : SSL_CTX_set_default_passwd_cb_userdata(ctx, stream);
4420 1 : SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
4421 : }
4422 :
4423 5 : GET_VER_OPT_STRING("ciphers", cipherlist);
4424 5 : if (!cipherlist) {
4425 5 : cipherlist = "DEFAULT";
4426 : }
4427 5 : SSL_CTX_set_cipher_list(ctx, cipherlist);
4428 :
4429 5 : GET_VER_OPT_STRING("local_cert", certfile);
4430 5 : if (certfile) {
4431 3 : X509 *cert = NULL;
4432 3 : EVP_PKEY *key = NULL;
4433 : SSL *tmpssl;
4434 : char resolved_path_buff[MAXPATHLEN];
4435 :
4436 3 : if (VCWD_REALPATH(certfile, resolved_path_buff)) {
4437 : /* a certificate to use for authentication */
4438 3 : if (SSL_CTX_use_certificate_chain_file(ctx, resolved_path_buff) != 1) {
4439 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set local cert chain file `%s'; Check that your cafile/capath settings include details of your certificate and its issuer", certfile);
4440 0 : return NULL;
4441 : }
4442 :
4443 3 : if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) {
4444 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff);
4445 0 : return NULL;
4446 : }
4447 :
4448 3 : tmpssl = SSL_new(ctx);
4449 3 : cert = SSL_get_certificate(tmpssl);
4450 :
4451 3 : if (cert) {
4452 3 : key = X509_get_pubkey(cert);
4453 3 : EVP_PKEY_copy_parameters(key, SSL_get_privatekey(tmpssl));
4454 3 : EVP_PKEY_free(key);
4455 : }
4456 3 : SSL_free(tmpssl);
4457 :
4458 3 : if (!SSL_CTX_check_private_key(ctx)) {
4459 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Private key does not match certificate!");
4460 : }
4461 : }
4462 : }
4463 5 : if (ok) {
4464 5 : SSL *ssl = SSL_new(ctx);
4465 :
4466 5 : if (ssl) {
4467 : /* map SSL => stream */
4468 5 : SSL_set_ex_data(ssl, ssl_stream_data_index, stream);
4469 : }
4470 5 : return ssl;
4471 : }
4472 :
4473 0 : return NULL;
4474 : }
4475 : /* }}} */
4476 :
4477 : static void openssl_add_method_or_alias(const OBJ_NAME *name, void *arg) /* {{{ */
4478 0 : {
4479 0 : add_next_index_string((zval*)arg, (char*)name->name, 1);
4480 0 : }
4481 : /* }}} */
4482 :
4483 : static void openssl_add_method(const OBJ_NAME *name, void *arg) /* {{{ */
4484 0 : {
4485 0 : if (name->alias == 0) {
4486 0 : add_next_index_string((zval*)arg, (char*)name->name, 1);
4487 : }
4488 0 : }
4489 : /* }}} */
4490 :
4491 : /* {{{ proto array openssl_get_md_methods([bool aliases = false])
4492 : Return array of available digest methods */
4493 : PHP_FUNCTION(openssl_get_md_methods)
4494 0 : {
4495 0 : zend_bool aliases = 0;
4496 :
4497 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == FAILURE) {
4498 0 : return;
4499 : }
4500 0 : array_init(return_value);
4501 0 : OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
4502 : aliases ? openssl_add_method_or_alias: openssl_add_method,
4503 : return_value);
4504 : }
4505 : /* }}} */
4506 :
4507 : /* {{{ proto array openssl_get_cipher_methods([bool aliases = false])
4508 : Return array of available cipher methods */
4509 : PHP_FUNCTION(openssl_get_cipher_methods)
4510 0 : {
4511 0 : zend_bool aliases = 0;
4512 :
4513 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &aliases) == FAILURE) {
4514 0 : return;
4515 : }
4516 0 : array_init(return_value);
4517 0 : OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
4518 : aliases ? openssl_add_method_or_alias: openssl_add_method,
4519 : return_value);
4520 : }
4521 : /* }}} */
4522 :
4523 : /* {{{ proto string openssl_digest(string data, string method [, bool raw_output=false])
4524 : Computes digest hash value for given data using given method, returns raw or binhex encoded string */
4525 : PHP_FUNCTION(openssl_digest)
4526 2 : {
4527 2 : zend_bool raw_output = 0;
4528 : char *data, *method;
4529 : int data_len, method_len;
4530 : const EVP_MD *mdtype;
4531 : EVP_MD_CTX md_ctx;
4532 : int siglen;
4533 : unsigned char *sigbuf;
4534 :
4535 2 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &data, &data_len, &method, &method_len, &raw_output) == FAILURE) {
4536 0 : return;
4537 : }
4538 2 : mdtype = EVP_get_digestbyname(method);
4539 2 : if (!mdtype) {
4540 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm");
4541 0 : RETURN_FALSE;
4542 : }
4543 :
4544 2 : siglen = EVP_MD_size(mdtype);
4545 2 : sigbuf = emalloc(siglen + 1);
4546 :
4547 2 : EVP_DigestInit(&md_ctx, mdtype);
4548 2 : EVP_DigestUpdate(&md_ctx, (unsigned char *)data, data_len);
4549 2 : if (EVP_DigestFinal (&md_ctx, (unsigned char *)sigbuf, (unsigned int *)&siglen)) {
4550 2 : if (raw_output) {
4551 0 : sigbuf[siglen] = '\0';
4552 0 : RETVAL_STRINGL((char *)sigbuf, siglen, 0);
4553 : } else {
4554 2 : int digest_str_len = siglen * 2;
4555 2 : char *digest_str = emalloc(digest_str_len + 1);
4556 :
4557 2 : make_digest_ex(digest_str, sigbuf, siglen);
4558 2 : efree(sigbuf);
4559 2 : RETVAL_STRINGL(digest_str, digest_str_len, 0);
4560 : }
4561 : } else {
4562 0 : efree(sigbuf);
4563 0 : RETVAL_FALSE;
4564 : }
4565 : }
4566 : /* }}} */
4567 :
4568 : /* {{{ proto string openssl_encrypt(string data, string method, string password [, bool raw_output=false])
4569 : Encrypts given data with given method and key, returns raw or base64 encoded string */
4570 : PHP_FUNCTION(openssl_encrypt)
4571 10 : {
4572 10 : zend_bool raw_output = 0;
4573 : char *data, *method, *password;
4574 : int data_len, method_len, password_len;
4575 : const EVP_CIPHER *cipher_type;
4576 : EVP_CIPHER_CTX cipher_ctx;
4577 : int i, outlen, keylen, ivlen;
4578 : unsigned char *outbuf, *key, *iv;
4579 :
4580 10 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &data, &data_len, &method, &method_len, &password, &password_len, &raw_output) == FAILURE) {
4581 6 : return;
4582 : }
4583 4 : cipher_type = EVP_get_cipherbyname(method);
4584 4 : if (!cipher_type) {
4585 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
4586 1 : RETURN_FALSE;
4587 : }
4588 :
4589 3 : keylen = EVP_CIPHER_key_length(cipher_type);
4590 3 : if (keylen > password_len) {
4591 3 : key = emalloc(keylen);
4592 3 : memset(key, 0, keylen);
4593 3 : memcpy(key, password, password_len);
4594 : } else {
4595 0 : key = (unsigned char*)password;
4596 : }
4597 :
4598 3 : ivlen = EVP_CIPHER_iv_length(cipher_type);
4599 3 : iv = emalloc(ivlen);
4600 3 : memset(iv, 0, ivlen);
4601 :
4602 3 : outlen = data_len + EVP_CIPHER_block_size(cipher_type);
4603 3 : outbuf = emalloc(outlen + 1);
4604 :
4605 3 : EVP_EncryptInit(&cipher_ctx, cipher_type, key, iv);
4606 3 : EVP_EncryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
4607 3 : outlen = i;
4608 3 : if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
4609 3 : outlen += i;
4610 3 : if (raw_output) {
4611 1 : outbuf[outlen] = '\0';
4612 1 : RETVAL_STRINGL((char *)outbuf, outlen, 0);
4613 : } else {
4614 : int base64_str_len;
4615 : char *base64_str;
4616 :
4617 2 : base64_str = (char*)php_base64_encode(outbuf, outlen, &base64_str_len);
4618 2 : efree(outbuf);
4619 2 : RETVAL_STRINGL(base64_str, base64_str_len, 0);
4620 : }
4621 : } else {
4622 0 : efree(outbuf);
4623 0 : RETVAL_FALSE;
4624 : }
4625 3 : if (key != (unsigned char*)password) {
4626 3 : efree(key);
4627 : }
4628 3 : efree(iv);
4629 : }
4630 : /* }}} */
4631 :
4632 : /* {{{ proto string openssl_decrypt(string data, string method, string password [, bool raw_input=false])
4633 : Takes raw or base64 encoded string and dectupt it using given method and key */
4634 : PHP_FUNCTION(openssl_decrypt)
4635 11 : {
4636 11 : zend_bool raw_input = 0;
4637 : char *data, *method, *password;
4638 : int data_len, method_len, password_len;
4639 : const EVP_CIPHER *cipher_type;
4640 : EVP_CIPHER_CTX cipher_ctx;
4641 : int i, outlen, keylen, ivlen;
4642 : unsigned char *outbuf, *key, *iv;
4643 : int base64_str_len;
4644 11 : char *base64_str = NULL;
4645 :
4646 11 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &data, &data_len, &method, &method_len, &password, &password_len, &raw_input) == FAILURE) {
4647 3 : return;
4648 : }
4649 :
4650 8 : if (!method_len) {
4651 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
4652 0 : RETURN_FALSE;
4653 : }
4654 :
4655 8 : cipher_type = EVP_get_cipherbyname(method);
4656 8 : if (!cipher_type) {
4657 4 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown cipher algorithm");
4658 4 : RETURN_FALSE;
4659 : }
4660 :
4661 4 : if (!raw_input) {
4662 3 : base64_str = (char*)php_base64_decode((unsigned char*)data, data_len, &base64_str_len);
4663 3 : data_len = base64_str_len;
4664 3 : data = base64_str;
4665 : }
4666 :
4667 4 : keylen = EVP_CIPHER_key_length(cipher_type);
4668 4 : if (keylen > password_len) {
4669 4 : key = emalloc(keylen);
4670 4 : memset(key, 0, keylen);
4671 4 : memcpy(key, password, password_len);
4672 : } else {
4673 0 : key = (unsigned char*)password;
4674 : }
4675 :
4676 4 : ivlen = EVP_CIPHER_iv_length(cipher_type);
4677 4 : iv = emalloc(ivlen);
4678 4 : memset(iv, 0, ivlen);
4679 :
4680 4 : outlen = data_len + EVP_CIPHER_block_size(cipher_type);
4681 4 : outbuf = emalloc(outlen + 1);
4682 :
4683 4 : EVP_DecryptInit(&cipher_ctx, cipher_type, key, iv);
4684 4 : EVP_DecryptUpdate(&cipher_ctx, outbuf, &i, (unsigned char *)data, data_len);
4685 4 : outlen = i;
4686 4 : if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)outbuf + i, &i)) {
4687 2 : outlen += i;
4688 2 : outbuf[outlen] = '\0';
4689 2 : RETVAL_STRINGL((char *)outbuf, outlen, 0);
4690 : } else {
4691 2 : efree(outbuf);
4692 2 : RETVAL_FALSE;
4693 : }
4694 4 : if (key != (unsigned char*)password) {
4695 4 : efree(key);
4696 : }
4697 4 : efree(iv);
4698 4 : if (base64_str) {
4699 3 : efree(base64_str);
4700 : }
4701 : }
4702 : /* }}} */
4703 :
4704 : /* {{{ proto string openssl_dh_compute_key(string pub_key, resource dh_key)
4705 : Computes shared sicret for public value of remote DH key and local DH key */
4706 : PHP_FUNCTION(openssl_dh_compute_key)
4707 0 : {
4708 : zval *key;
4709 : char *pub_str;
4710 : int pub_len;
4711 : EVP_PKEY *pkey;
4712 : BIGNUM *pub;
4713 : char *data;
4714 : int len;
4715 :
4716 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr", &pub_str, &pub_len, &key) == FAILURE) {
4717 0 : return;
4718 : }
4719 0 : ZEND_FETCH_RESOURCE(pkey, EVP_PKEY *, &key, -1, "OpenSSL key", le_key);
4720 0 : if (!pkey || EVP_PKEY_type(pkey->type) != EVP_PKEY_DH || !pkey->pkey.dh) {
4721 0 : RETURN_FALSE;
4722 : }
4723 :
4724 0 : pub = BN_bin2bn((unsigned char*)pub_str, pub_len, NULL);
4725 :
4726 0 : data = emalloc(DH_size(pkey->pkey.dh) + 1);
4727 0 : len = DH_compute_key((unsigned char*)data, pub, pkey->pkey.dh);
4728 :
4729 0 : if (len >= 0) {
4730 0 : data[len] = 0;
4731 0 : RETVAL_STRINGL(data, len, 0);
4732 : } else {
4733 0 : efree(data);
4734 0 : RETVAL_FALSE;
4735 : }
4736 :
4737 0 : BN_free(pub);
4738 : }
4739 : /* }}} */
4740 :
4741 : /* {{{ proto string openssl_random_pseudo_bytes(integer length [, &bool returned_strong_result])
4742 : Returns a string of the length specified filled with random pseudo bytes */
4743 : PHP_FUNCTION(openssl_random_pseudo_bytes)
4744 10 : {
4745 : long buffer_length;
4746 10 : unsigned char *buffer = NULL;
4747 10 : zval *zstrong_result_returned = NULL;
4748 10 : int strong_result = 0;
4749 :
4750 10 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|z", &buffer_length, &zstrong_result_returned) == FAILURE) {
4751 0 : return;
4752 : }
4753 :
4754 10 : if (buffer_length <= 0) {
4755 1 : RETURN_FALSE;
4756 : }
4757 :
4758 9 : if (zstrong_result_returned) {
4759 9 : zval_dtor(zstrong_result_returned);
4760 9 : ZVAL_BOOL(zstrong_result_returned, 0);
4761 : }
4762 :
4763 9 : buffer = emalloc(buffer_length);
4764 :
4765 9 : if (!buffer) {
4766 0 : RETURN_FALSE;
4767 : }
4768 :
4769 : #ifdef WINDOWS
4770 : RAND_screen();
4771 : #endif
4772 :
4773 9 : if ((strong_result = RAND_pseudo_bytes(buffer, buffer_length)) < 0) {
4774 0 : RETVAL_FALSE;
4775 : } else {
4776 9 : RETVAL_STRINGL((char *)buffer, buffer_length, 1);
4777 :
4778 9 : if (zstrong_result_returned) {
4779 9 : ZVAL_BOOL(zstrong_result_returned, strong_result);
4780 : }
4781 :
4782 : }
4783 9 : efree(buffer);
4784 : }
4785 : /* }}} */
4786 :
4787 : /*
4788 : * Local variables:
4789 : * tab-width: 8
4790 : * c-basic-offset: 8
4791 : * End:
4792 : * vim600: sw=4 ts=4 fdm=marker
4793 : * vim<600: sw=4 ts=4
4794 : */
|