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