1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 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 | Jakub Zelenka <bukka@php.net> |
21 +----------------------------------------------------------------------+
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "php.h"
29 #include "php_ini.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 #ifdef PHP_WIN32
39 # include "win32/winutil.h"
40 #endif
41
42 /* OpenSSL includes */
43 #include <openssl/evp.h>
44 #include <openssl/bn.h>
45 #include <openssl/rsa.h>
46 #include <openssl/dsa.h>
47 #include <openssl/dh.h>
48 #include <openssl/x509.h>
49 #include <openssl/x509v3.h>
50 #include <openssl/crypto.h>
51 #include <openssl/pem.h>
52 #include <openssl/err.h>
53 #include <openssl/conf.h>
54 #include <openssl/rand.h>
55 #include <openssl/ssl.h>
56 #include <openssl/pkcs12.h>
57
58 /* Common */
59 #include <time.h>
60
61 #if (defined(PHP_WIN32) && defined(_MSC_VER) && _MSC_VER >= 1900)
62 #define timezone _timezone /* timezone is called _timezone in LibC */
63 #endif
64
65 #define MIN_KEY_LENGTH 384
66
67 #define OPENSSL_ALGO_SHA1 1
68 #define OPENSSL_ALGO_MD5 2
69 #define OPENSSL_ALGO_MD4 3
70 #ifdef HAVE_OPENSSL_MD2_H
71 #define OPENSSL_ALGO_MD2 4
72 #endif
73 #if PHP_OPENSSL_API_VERSION < 0x10100
74 #define OPENSSL_ALGO_DSS1 5
75 #endif
76 #define OPENSSL_ALGO_SHA224 6
77 #define OPENSSL_ALGO_SHA256 7
78 #define OPENSSL_ALGO_SHA384 8
79 #define OPENSSL_ALGO_SHA512 9
80 #define OPENSSL_ALGO_RMD160 10
81 #define DEBUG_SMIME 0
82
83 #if !defined(OPENSSL_NO_EC) && defined(EVP_PKEY_EC)
84 #define HAVE_EVP_PKEY_EC 1
85 #endif
86
87 ZEND_DECLARE_MODULE_GLOBALS(openssl)
88
89 /* FIXME: Use the openssl constants instead of
90 * enum. It is now impossible to match real values
91 * against php constants. Also sorry to break the
92 * enum principles here, BC...
93 */
94 enum php_openssl_key_type {
95 OPENSSL_KEYTYPE_RSA,
96 OPENSSL_KEYTYPE_DSA,
97 OPENSSL_KEYTYPE_DH,
98 OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA,
99 #ifdef HAVE_EVP_PKEY_EC
100 OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH +1
101 #endif
102 };
103
104 enum php_openssl_cipher_type {
105 PHP_OPENSSL_CIPHER_RC2_40,
106 PHP_OPENSSL_CIPHER_RC2_128,
107 PHP_OPENSSL_CIPHER_RC2_64,
108 PHP_OPENSSL_CIPHER_DES,
109 PHP_OPENSSL_CIPHER_3DES,
110 PHP_OPENSSL_CIPHER_AES_128_CBC,
111 PHP_OPENSSL_CIPHER_AES_192_CBC,
112 PHP_OPENSSL_CIPHER_AES_256_CBC,
113
114 PHP_OPENSSL_CIPHER_DEFAULT = PHP_OPENSSL_CIPHER_RC2_40
115 };
116
117 PHP_FUNCTION(openssl_get_md_methods);
118 PHP_FUNCTION(openssl_get_cipher_methods);
119 #ifdef HAVE_EVP_PKEY_EC
120 PHP_FUNCTION(openssl_get_curve_names);
121 #endif
122
123 PHP_FUNCTION(openssl_digest);
124 PHP_FUNCTION(openssl_encrypt);
125 PHP_FUNCTION(openssl_decrypt);
126 PHP_FUNCTION(openssl_cipher_iv_length);
127
128 PHP_FUNCTION(openssl_dh_compute_key);
129 PHP_FUNCTION(openssl_pkey_derive);
130 PHP_FUNCTION(openssl_random_pseudo_bytes);
131
132 /* {{{ arginfo */
133 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 0, 2)
134 ZEND_ARG_INFO(0, x509)
135 ZEND_ARG_INFO(0, outfilename)
136 ZEND_ARG_INFO(0, notext)
137 ZEND_END_ARG_INFO()
138
139 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export, 0, 0, 2)
140 ZEND_ARG_INFO(0, x509)
141 ZEND_ARG_INFO(1, out)
142 ZEND_ARG_INFO(0, notext)
143 ZEND_END_ARG_INFO()
144
145 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_fingerprint, 0, 0, 1)
146 ZEND_ARG_INFO(0, x509)
147 ZEND_ARG_INFO(0, method)
148 ZEND_ARG_INFO(0, raw_output)
149 ZEND_END_ARG_INFO()
150
151 ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_check_private_key, 0)
152 ZEND_ARG_INFO(0, cert)
153 ZEND_ARG_INFO(0, key)
154 ZEND_END_ARG_INFO()
155
156 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_parse, 0, 0, 1)
157 ZEND_ARG_INFO(0, x509)
158 ZEND_ARG_INFO(0, shortname)
159 ZEND_END_ARG_INFO()
160
161 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_checkpurpose, 0, 0, 2)
162 ZEND_ARG_INFO(0, x509cert)
163 ZEND_ARG_INFO(0, purpose)
164 ZEND_ARG_INFO(0, cainfo) /* array */
165 ZEND_ARG_INFO(0, untrustedfile)
166 ZEND_END_ARG_INFO()
167
168 ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_read, 0)
169 ZEND_ARG_INFO(0, cert)
170 ZEND_END_ARG_INFO()
171
172 ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_free, 0)
173 ZEND_ARG_INFO(0, x509)
174 ZEND_END_ARG_INFO()
175
176 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs12_export_to_file, 0, 0, 4)
177 ZEND_ARG_INFO(0, x509)
178 ZEND_ARG_INFO(0, filename)
179 ZEND_ARG_INFO(0, priv_key)
180 ZEND_ARG_INFO(0, pass)
181 ZEND_ARG_INFO(0, args) /* array */
182 ZEND_END_ARG_INFO()
183
184 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs12_export, 0, 0, 4)
185 ZEND_ARG_INFO(0, x509)
186 ZEND_ARG_INFO(1, out)
187 ZEND_ARG_INFO(0, priv_key)
188 ZEND_ARG_INFO(0, pass)
189 ZEND_ARG_INFO(0, args) /* array */
190 ZEND_END_ARG_INFO()
191
192 ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_read, 0)
193 ZEND_ARG_INFO(0, PKCS12)
194 ZEND_ARG_INFO(1, certs) /* array */
195 ZEND_ARG_INFO(0, pass)
196 ZEND_END_ARG_INFO()
197
198 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export_to_file, 0, 0, 2)
199 ZEND_ARG_INFO(0, csr)
200 ZEND_ARG_INFO(0, outfilename)
201 ZEND_ARG_INFO(0, notext)
202 ZEND_END_ARG_INFO()
203
204 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export, 0, 0, 2)
205 ZEND_ARG_INFO(0, csr)
206 ZEND_ARG_INFO(1, out)
207 ZEND_ARG_INFO(0, notext)
208 ZEND_END_ARG_INFO()
209
210 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_sign, 0, 0, 4)
211 ZEND_ARG_INFO(0, csr)
212 ZEND_ARG_INFO(0, x509)
213 ZEND_ARG_INFO(0, priv_key)
214 ZEND_ARG_INFO(0, days)
215 ZEND_ARG_INFO(0, config_args) /* array */
216 ZEND_ARG_INFO(0, serial)
217 ZEND_END_ARG_INFO()
218
219 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_new, 0, 0, 2)
220 ZEND_ARG_INFO(0, dn) /* array */
221 ZEND_ARG_INFO(1, privkey)
222 ZEND_ARG_INFO(0, configargs)
223 ZEND_ARG_INFO(0, extraattribs)
224 ZEND_END_ARG_INFO()
225
226 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_get_subject, 0, 0, 1)
227 ZEND_ARG_INFO(0, csr)
228 ZEND_ARG_INFO(0, use_shortnames)
229 ZEND_END_ARG_INFO()
230
231 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_get_public_key, 0, 0, 1)
232 ZEND_ARG_INFO(0, csr)
233 ZEND_ARG_INFO(0, use_shortnames)
234 ZEND_END_ARG_INFO()
235
236 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_new, 0, 0, 0)
237 ZEND_ARG_INFO(0, configargs) /* array */
238 ZEND_END_ARG_INFO()
239
240 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export_to_file, 0, 0, 2)
241 ZEND_ARG_INFO(0, key)
242 ZEND_ARG_INFO(0, outfilename)
243 ZEND_ARG_INFO(0, passphrase)
244 ZEND_ARG_INFO(0, config_args) /* array */
245 ZEND_END_ARG_INFO()
246
247 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export, 0, 0, 2)
248 ZEND_ARG_INFO(0, key)
249 ZEND_ARG_INFO(1, out)
250 ZEND_ARG_INFO(0, passphrase)
251 ZEND_ARG_INFO(0, config_args) /* array */
252 ZEND_END_ARG_INFO()
253
254 ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_public, 0)
255 ZEND_ARG_INFO(0, cert)
256 ZEND_END_ARG_INFO()
257
258 ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_free, 0)
259 ZEND_ARG_INFO(0, key)
260 ZEND_END_ARG_INFO()
261
262 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_get_private, 0, 0, 1)
263 ZEND_ARG_INFO(0, key)
264 ZEND_ARG_INFO(0, passphrase)
265 ZEND_END_ARG_INFO()
266
267 ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_details, 0)
268 ZEND_ARG_INFO(0, key)
269 ZEND_END_ARG_INFO()
270
271 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pbkdf2, 0, 0, 4)
272 ZEND_ARG_INFO(0, password)
273 ZEND_ARG_INFO(0, salt)
274 ZEND_ARG_INFO(0, key_length)
275 ZEND_ARG_INFO(0, iterations)
276 ZEND_ARG_INFO(0, digest_algorithm)
277 ZEND_END_ARG_INFO()
278
279 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_verify, 0, 0, 2)
280 ZEND_ARG_INFO(0, filename)
281 ZEND_ARG_INFO(0, flags)
282 ZEND_ARG_INFO(0, signerscerts)
283 ZEND_ARG_INFO(0, cainfo) /* array */
284 ZEND_ARG_INFO(0, extracerts)
285 ZEND_ARG_INFO(0, content)
286 ZEND_ARG_INFO(0, pk7)
287 ZEND_END_ARG_INFO()
288
289 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_encrypt, 0, 0, 4)
290 ZEND_ARG_INFO(0, infile)
291 ZEND_ARG_INFO(0, outfile)
292 ZEND_ARG_INFO(0, recipcerts)
293 ZEND_ARG_INFO(0, headers) /* array */
294 ZEND_ARG_INFO(0, flags)
295 ZEND_ARG_INFO(0, cipher)
296 ZEND_END_ARG_INFO()
297
298 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_sign, 0, 0, 5)
299 ZEND_ARG_INFO(0, infile)
300 ZEND_ARG_INFO(0, outfile)
301 ZEND_ARG_INFO(0, signcert)
302 ZEND_ARG_INFO(0, signkey)
303 ZEND_ARG_INFO(0, headers) /* array */
304 ZEND_ARG_INFO(0, flags)
305 ZEND_ARG_INFO(0, extracertsfilename)
306 ZEND_END_ARG_INFO()
307
308 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_decrypt, 0, 0, 3)
309 ZEND_ARG_INFO(0, infilename)
310 ZEND_ARG_INFO(0, outfilename)
311 ZEND_ARG_INFO(0, recipcert)
312 ZEND_ARG_INFO(0, recipkey)
313 ZEND_END_ARG_INFO()
314
315 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_read, 0, 0, 2)
316 ZEND_ARG_INFO(0, infilename)
317 ZEND_ARG_INFO(1, certs)
318 ZEND_END_ARG_INFO()
319
320 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_encrypt, 0, 0, 3)
321 ZEND_ARG_INFO(0, data)
322 ZEND_ARG_INFO(1, crypted)
323 ZEND_ARG_INFO(0, key)
324 ZEND_ARG_INFO(0, padding)
325 ZEND_END_ARG_INFO()
326
327 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_decrypt, 0, 0, 3)
328 ZEND_ARG_INFO(0, data)
329 ZEND_ARG_INFO(1, crypted)
330 ZEND_ARG_INFO(0, key)
331 ZEND_ARG_INFO(0, padding)
332 ZEND_END_ARG_INFO()
333
334 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_encrypt, 0, 0, 3)
335 ZEND_ARG_INFO(0, data)
336 ZEND_ARG_INFO(1, crypted)
337 ZEND_ARG_INFO(0, key)
338 ZEND_ARG_INFO(0, padding)
339 ZEND_END_ARG_INFO()
340
341 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_decrypt, 0, 0, 3)
342 ZEND_ARG_INFO(0, data)
343 ZEND_ARG_INFO(1, crypted)
344 ZEND_ARG_INFO(0, key)
345 ZEND_ARG_INFO(0, padding)
346 ZEND_END_ARG_INFO()
347
348 ZEND_BEGIN_ARG_INFO(arginfo_openssl_error_string, 0)
349 ZEND_END_ARG_INFO()
350
351 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_sign, 0, 0, 3)
352 ZEND_ARG_INFO(0, data)
353 ZEND_ARG_INFO(1, signature)
354 ZEND_ARG_INFO(0, key)
355 ZEND_ARG_INFO(0, method)
356 ZEND_END_ARG_INFO()
357
358 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_verify, 0, 0, 3)
359 ZEND_ARG_INFO(0, data)
360 ZEND_ARG_INFO(0, signature)
361 ZEND_ARG_INFO(0, key)
362 ZEND_ARG_INFO(0, method)
363 ZEND_END_ARG_INFO()
364
365 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_seal, 0, 0, 4)
366 ZEND_ARG_INFO(0, data)
367 ZEND_ARG_INFO(1, sealdata)
368 ZEND_ARG_INFO(1, ekeys) /* array */
369 ZEND_ARG_INFO(0, pubkeys) /* array */
370 ZEND_ARG_INFO(0, method)
371 ZEND_ARG_INFO(1, iv)
372 ZEND_END_ARG_INFO()
373
374 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_open, 0, 0, 4)
375 ZEND_ARG_INFO(0, data)
376 ZEND_ARG_INFO(1, opendata)
377 ZEND_ARG_INFO(0, ekey)
378 ZEND_ARG_INFO(0, privkey)
379 ZEND_ARG_INFO(0, method)
380 ZEND_ARG_INFO(0, iv)
381 ZEND_END_ARG_INFO()
382
383 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_md_methods, 0, 0, 0)
384 ZEND_ARG_INFO(0, aliases)
385 ZEND_END_ARG_INFO()
386
387 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_cipher_methods, 0, 0, 0)
388 ZEND_ARG_INFO(0, aliases)
389 ZEND_END_ARG_INFO()
390
391 #ifdef HAVE_EVP_PKEY_EC
392 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_curve_names, 0, 0, 0)
393 ZEND_END_ARG_INFO()
394 #endif
395
396 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_digest, 0, 0, 2)
397 ZEND_ARG_INFO(0, data)
398 ZEND_ARG_INFO(0, method)
399 ZEND_ARG_INFO(0, raw_output)
400 ZEND_END_ARG_INFO()
401
402 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_encrypt, 0, 0, 3)
403 ZEND_ARG_INFO(0, data)
404 ZEND_ARG_INFO(0, method)
405 ZEND_ARG_INFO(0, password)
406 ZEND_ARG_INFO(0, options)
407 ZEND_ARG_INFO(0, iv)
408 ZEND_ARG_INFO(1, tag)
409 ZEND_ARG_INFO(0, aad)
410 ZEND_ARG_INFO(0, tag_length)
411 ZEND_END_ARG_INFO()
412
413 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_decrypt, 0, 0, 3)
414 ZEND_ARG_INFO(0, data)
415 ZEND_ARG_INFO(0, method)
416 ZEND_ARG_INFO(0, password)
417 ZEND_ARG_INFO(0, options)
418 ZEND_ARG_INFO(0, iv)
419 ZEND_ARG_INFO(0, tag)
420 ZEND_ARG_INFO(0, aad)
421 ZEND_END_ARG_INFO()
422
423 ZEND_BEGIN_ARG_INFO(arginfo_openssl_cipher_iv_length, 0)
424 ZEND_ARG_INFO(0, method)
425 ZEND_END_ARG_INFO()
426
427 ZEND_BEGIN_ARG_INFO(arginfo_openssl_dh_compute_key, 0)
428 ZEND_ARG_INFO(0, pub_key)
429 ZEND_ARG_INFO(0, dh_key)
430 ZEND_END_ARG_INFO()
431
432 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_derive, 0, 0, 2)
433 ZEND_ARG_INFO(0, peer_pub_key)
434 ZEND_ARG_INFO(0, priv_key)
435 ZEND_ARG_INFO(0, keylen)
436 ZEND_END_ARG_INFO()
437
438 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_random_pseudo_bytes, 0, 0, 1)
439 ZEND_ARG_INFO(0, length)
440 ZEND_ARG_INFO(1, result_is_strong)
441 ZEND_END_ARG_INFO()
442
443 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_spki_new, 0, 0, 2)
444 ZEND_ARG_INFO(0, privkey)
445 ZEND_ARG_INFO(0, challenge)
446 ZEND_ARG_INFO(0, algo)
447 ZEND_END_ARG_INFO()
448
449 ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_verify, 0)
450 ZEND_ARG_INFO(0, spki)
451 ZEND_END_ARG_INFO()
452
453 ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export, 0)
454 ZEND_ARG_INFO(0, spki)
455 ZEND_END_ARG_INFO()
456
457 ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export_challenge, 0)
458 ZEND_ARG_INFO(0, spki)
459 ZEND_END_ARG_INFO()
460
461 ZEND_BEGIN_ARG_INFO(arginfo_openssl_get_cert_locations, 0)
462 ZEND_END_ARG_INFO()
463 /* }}} */
464
465 /* {{{ openssl_functions[]
466 */
467 static const zend_function_entry openssl_functions[] = {
468 PHP_FE(openssl_get_cert_locations, arginfo_openssl_get_cert_locations)
469
470 /* spki functions */
471 PHP_FE(openssl_spki_new, arginfo_openssl_spki_new)
472 PHP_FE(openssl_spki_verify, arginfo_openssl_spki_verify)
473 PHP_FE(openssl_spki_export, arginfo_openssl_spki_export)
474 PHP_FE(openssl_spki_export_challenge, arginfo_openssl_spki_export_challenge)
475
476 /* public/private key functions */
477 PHP_FE(openssl_pkey_free, arginfo_openssl_pkey_free)
478 PHP_FE(openssl_pkey_new, arginfo_openssl_pkey_new)
479 PHP_FE(openssl_pkey_export, arginfo_openssl_pkey_export)
480 PHP_FE(openssl_pkey_export_to_file, arginfo_openssl_pkey_export_to_file)
481 PHP_FE(openssl_pkey_get_private, arginfo_openssl_pkey_get_private)
482 PHP_FE(openssl_pkey_get_public, arginfo_openssl_pkey_get_public)
483 PHP_FE(openssl_pkey_get_details, arginfo_openssl_pkey_get_details)
484
485 PHP_FALIAS(openssl_free_key, openssl_pkey_free, arginfo_openssl_pkey_free)
486 PHP_FALIAS(openssl_get_privatekey, openssl_pkey_get_private, arginfo_openssl_pkey_get_private)
487 PHP_FALIAS(openssl_get_publickey, openssl_pkey_get_public, arginfo_openssl_pkey_get_public)
488
489 /* x.509 cert funcs */
490 PHP_FE(openssl_x509_read, arginfo_openssl_x509_read)
491 PHP_FE(openssl_x509_free, arginfo_openssl_x509_free)
492 PHP_FE(openssl_x509_parse, arginfo_openssl_x509_parse)
493 PHP_FE(openssl_x509_checkpurpose, arginfo_openssl_x509_checkpurpose)
494 PHP_FE(openssl_x509_check_private_key, arginfo_openssl_x509_check_private_key)
495 PHP_FE(openssl_x509_export, arginfo_openssl_x509_export)
496 PHP_FE(openssl_x509_fingerprint, arginfo_openssl_x509_fingerprint)
497 PHP_FE(openssl_x509_export_to_file, arginfo_openssl_x509_export_to_file)
498
499 /* PKCS12 funcs */
500 PHP_FE(openssl_pkcs12_export, arginfo_openssl_pkcs12_export)
501 PHP_FE(openssl_pkcs12_export_to_file, arginfo_openssl_pkcs12_export_to_file)
502 PHP_FE(openssl_pkcs12_read, arginfo_openssl_pkcs12_read)
503
504 /* CSR funcs */
505 PHP_FE(openssl_csr_new, arginfo_openssl_csr_new)
506 PHP_FE(openssl_csr_export, arginfo_openssl_csr_export)
507 PHP_FE(openssl_csr_export_to_file, arginfo_openssl_csr_export_to_file)
508 PHP_FE(openssl_csr_sign, arginfo_openssl_csr_sign)
509 PHP_FE(openssl_csr_get_subject, arginfo_openssl_csr_get_subject)
510 PHP_FE(openssl_csr_get_public_key, arginfo_openssl_csr_get_public_key)
511
512 PHP_FE(openssl_digest, arginfo_openssl_digest)
513 PHP_FE(openssl_encrypt, arginfo_openssl_encrypt)
514 PHP_FE(openssl_decrypt, arginfo_openssl_decrypt)
515 PHP_FE(openssl_cipher_iv_length, arginfo_openssl_cipher_iv_length)
516 PHP_FE(openssl_sign, arginfo_openssl_sign)
517 PHP_FE(openssl_verify, arginfo_openssl_verify)
518 PHP_FE(openssl_seal, arginfo_openssl_seal)
519 PHP_FE(openssl_open, arginfo_openssl_open)
520
521 PHP_FE(openssl_pbkdf2, arginfo_openssl_pbkdf2)
522
523 /* for S/MIME handling */
524 PHP_FE(openssl_pkcs7_verify, arginfo_openssl_pkcs7_verify)
525 PHP_FE(openssl_pkcs7_decrypt, arginfo_openssl_pkcs7_decrypt)
526 PHP_FE(openssl_pkcs7_sign, arginfo_openssl_pkcs7_sign)
527 PHP_FE(openssl_pkcs7_encrypt, arginfo_openssl_pkcs7_encrypt)
528 PHP_FE(openssl_pkcs7_read, arginfo_openssl_pkcs7_read)
529
530 PHP_FE(openssl_private_encrypt, arginfo_openssl_private_encrypt)
531 PHP_FE(openssl_private_decrypt, arginfo_openssl_private_decrypt)
532 PHP_FE(openssl_public_encrypt, arginfo_openssl_public_encrypt)
533 PHP_FE(openssl_public_decrypt, arginfo_openssl_public_decrypt)
534
535 PHP_FE(openssl_get_md_methods, arginfo_openssl_get_md_methods)
536 PHP_FE(openssl_get_cipher_methods, arginfo_openssl_get_cipher_methods)
537 #ifdef HAVE_EVP_PKEY_EC
538 PHP_FE(openssl_get_curve_names, arginfo_openssl_get_curve_names)
539 #endif
540
541 PHP_FE(openssl_dh_compute_key, arginfo_openssl_dh_compute_key)
542 PHP_FE(openssl_pkey_derive, arginfo_openssl_pkey_derive)
543
544 PHP_FE(openssl_random_pseudo_bytes, arginfo_openssl_random_pseudo_bytes)
545 PHP_FE(openssl_error_string, arginfo_openssl_error_string)
546 PHP_FE_END
547 };
548 /* }}} */
549
550 /* {{{ openssl_module_entry
551 */
552 zend_module_entry openssl_module_entry = {
553 STANDARD_MODULE_HEADER,
554 "openssl",
555 openssl_functions,
556 PHP_MINIT(openssl),
557 PHP_MSHUTDOWN(openssl),
558 NULL,
559 NULL,
560 PHP_MINFO(openssl),
561 PHP_OPENSSL_VERSION,
562 PHP_MODULE_GLOBALS(openssl),
563 PHP_GINIT(openssl),
564 PHP_GSHUTDOWN(openssl),
565 NULL,
566 STANDARD_MODULE_PROPERTIES_EX
567 };
568 /* }}} */
569
570 #ifdef COMPILE_DL_OPENSSL
ZEND_GET_MODULE(openssl)571 ZEND_GET_MODULE(openssl)
572 #endif
573
574 /* {{{ OpenSSL compatibility functions and macros */
575 #if PHP_OPENSSL_API_VERSION < 0x10100
576 #define EVP_PKEY_get0_RSA(_pkey) _pkey->pkey.rsa
577 #define EVP_PKEY_get0_DH(_pkey) _pkey->pkey.dh
578 #define EVP_PKEY_get0_DSA(_pkey) _pkey->pkey.dsa
579 #define EVP_PKEY_get0_EC_KEY(_pkey) _pkey->pkey.ec
580
581 static int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
582 {
583 r->n = n;
584 r->e = e;
585 r->d = d;
586
587 return 1;
588 }
589
RSA_set0_factors(RSA * r,BIGNUM * p,BIGNUM * q)590 static int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
591 {
592 r->p = p;
593 r->q = q;
594
595 return 1;
596 }
597
RSA_set0_crt_params(RSA * r,BIGNUM * dmp1,BIGNUM * dmq1,BIGNUM * iqmp)598 static int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
599 {
600 r->dmp1 = dmp1;
601 r->dmq1 = dmq1;
602 r->iqmp = iqmp;
603
604 return 1;
605 }
606
RSA_get0_key(const RSA * r,const BIGNUM ** n,const BIGNUM ** e,const BIGNUM ** d)607 static void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
608 {
609 *n = r->n;
610 *e = r->e;
611 *d = r->d;
612 }
613
RSA_get0_factors(const RSA * r,const BIGNUM ** p,const BIGNUM ** q)614 static void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
615 {
616 *p = r->p;
617 *q = r->q;
618 }
619
RSA_get0_crt_params(const RSA * r,const BIGNUM ** dmp1,const BIGNUM ** dmq1,const BIGNUM ** iqmp)620 static void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp)
621 {
622 *dmp1 = r->dmp1;
623 *dmq1 = r->dmq1;
624 *iqmp = r->iqmp;
625 }
626
DH_get0_pqg(const DH * dh,const BIGNUM ** p,const BIGNUM ** q,const BIGNUM ** g)627 static void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
628 {
629 *p = dh->p;
630 *q = dh->q;
631 *g = dh->g;
632 }
633
DH_set0_pqg(DH * dh,BIGNUM * p,BIGNUM * q,BIGNUM * g)634 static int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
635 {
636 dh->p = p;
637 dh->q = q;
638 dh->g = g;
639
640 return 1;
641 }
642
DH_get0_key(const DH * dh,const BIGNUM ** pub_key,const BIGNUM ** priv_key)643 static void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
644 {
645 *pub_key = dh->pub_key;
646 *priv_key = dh->priv_key;
647 }
648
DH_set0_key(DH * dh,BIGNUM * pub_key,BIGNUM * priv_key)649 static int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
650 {
651 dh->pub_key = pub_key;
652 dh->priv_key = priv_key;
653
654 return 1;
655 }
656
DSA_get0_pqg(const DSA * d,const BIGNUM ** p,const BIGNUM ** q,const BIGNUM ** g)657 static void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
658 {
659 *p = d->p;
660 *q = d->q;
661 *g = d->g;
662 }
663
DSA_set0_pqg(DSA * d,BIGNUM * p,BIGNUM * q,BIGNUM * g)664 int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
665 {
666 d->p = p;
667 d->q = q;
668 d->g = g;
669
670 return 1;
671 }
672
DSA_get0_key(const DSA * d,const BIGNUM ** pub_key,const BIGNUM ** priv_key)673 static void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
674 {
675 *pub_key = d->pub_key;
676 *priv_key = d->priv_key;
677 }
678
DSA_set0_key(DSA * d,BIGNUM * pub_key,BIGNUM * priv_key)679 int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
680 {
681 d->pub_key = pub_key;
682 d->priv_key = priv_key;
683
684 return 1;
685 }
686
ASN1_STRING_get0_data(const ASN1_STRING * asn1)687 static const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1)
688 {
689 return M_ASN1_STRING_data(asn1);
690 }
691
692 #if PHP_OPENSSL_API_VERSION < 0x10002
693
X509_get_signature_nid(const X509 * x)694 static int X509_get_signature_nid(const X509 *x)
695 {
696 return OBJ_obj2nid(x->sig_alg->algorithm);
697 }
698
699 #endif
700
701 #endif
702 /* }}} */
703
704 /* number conversion flags checks */
705 #define PHP_OPENSSL_CHECK_NUMBER_CONVERSION(_cond, _name) \
706 do { \
707 if (_cond) { \
708 php_error_docref(NULL, E_WARNING, #_name" is too long"); \
709 RETURN_FALSE; \
710 } \
711 } while(0)
712 /* check if size_t can be safely casted to int */
713 #define PHP_OPENSSL_CHECK_SIZE_T_TO_INT(_var, _name) \
714 PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_SIZE_T_INT_OVFL(_var), _name)
715 /* check if size_t can be safely casted to unsigned int */
716 #define PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(_var, _name) \
717 PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_SIZE_T_UINT_OVFL(_var), _name)
718 /* check if long can be safely casted to int */
719 #define PHP_OPENSSL_CHECK_LONG_TO_INT(_var, _name) \
720 PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_LONG_EXCEEDS_INT(_var), _name)
721
722 /* {{{ php_openssl_store_errors */
php_openssl_store_errors()723 void php_openssl_store_errors()
724 {
725 struct php_openssl_errors *errors;
726 int error_code = ERR_get_error();
727
728 if (!error_code) {
729 return;
730 }
731
732 if (!OPENSSL_G(errors)) {
733 OPENSSL_G(errors) = pecalloc(1, sizeof(struct php_openssl_errors), 1);
734 }
735
736 errors = OPENSSL_G(errors);
737
738 do {
739 errors->top = (errors->top + 1) % ERR_NUM_ERRORS;
740 if (errors->top == errors->bottom) {
741 errors->bottom = (errors->bottom + 1) % ERR_NUM_ERRORS;
742 }
743 errors->buffer[errors->top] = error_code;
744 } while ((error_code = ERR_get_error()));
745
746 }
747 /* }}} */
748
749 static int le_key;
750 static int le_x509;
751 static int le_csr;
752 static int ssl_stream_data_index;
753
php_openssl_get_x509_list_id(void)754 int php_openssl_get_x509_list_id(void) /* {{{ */
755 {
756 return le_x509;
757 }
758 /* }}} */
759
760 /* {{{ resource destructors */
php_openssl_pkey_free(zend_resource * rsrc)761 static void php_openssl_pkey_free(zend_resource *rsrc)
762 {
763 EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr;
764
765 assert(pkey != NULL);
766
767 EVP_PKEY_free(pkey);
768 }
769
php_openssl_x509_free(zend_resource * rsrc)770 static void php_openssl_x509_free(zend_resource *rsrc)
771 {
772 X509 *x509 = (X509 *)rsrc->ptr;
773 X509_free(x509);
774 }
775
php_openssl_csr_free(zend_resource * rsrc)776 static void php_openssl_csr_free(zend_resource *rsrc)
777 {
778 X509_REQ * csr = (X509_REQ*)rsrc->ptr;
779 X509_REQ_free(csr);
780 }
781 /* }}} */
782
783 /* {{{ openssl open_basedir check */
php_openssl_open_base_dir_chk(char * filename)784 inline static int php_openssl_open_base_dir_chk(char *filename)
785 {
786 if (php_check_open_basedir(filename)) {
787 return -1;
788 }
789
790 return 0;
791 }
792 /* }}} */
793
php_openssl_get_stream_from_ssl_handle(const SSL * ssl)794 php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl)
795 {
796 return (php_stream*)SSL_get_ex_data(ssl, ssl_stream_data_index);
797 }
798
php_openssl_get_ssl_stream_data_index()799 int php_openssl_get_ssl_stream_data_index()
800 {
801 return ssl_stream_data_index;
802 }
803
804 /* openssl -> PHP "bridging" */
805 /* true global; readonly after module startup */
806 static char default_ssl_conf_filename[MAXPATHLEN];
807
808 struct php_x509_request { /* {{{ */
809 LHASH_OF(CONF_VALUE) * global_config; /* Global SSL config */
810 LHASH_OF(CONF_VALUE) * req_config; /* SSL config for this request */
811 const EVP_MD * md_alg;
812 const EVP_MD * digest;
813 char * section_name,
814 * config_filename,
815 * digest_name,
816 * extensions_section,
817 * request_extensions_section;
818 int priv_key_bits;
819 int priv_key_type;
820
821 int priv_key_encrypt;
822
823 #ifdef HAVE_EVP_PKEY_EC
824 int curve_name;
825 #endif
826
827 EVP_PKEY * priv_key;
828
829 const EVP_CIPHER * priv_key_encrypt_cipher;
830 };
831 /* }}} */
832
833 static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval);
834 static EVP_PKEY * php_openssl_evp_from_zval(
835 zval * val, int public_key, char *passphrase, size_t passphrase_len,
836 int makeresource, zend_resource **resourceval);
837 static int php_openssl_is_private_key(EVP_PKEY* pkey);
838 static X509_STORE * php_openssl_setup_verify(zval * calist);
839 static STACK_OF(X509) * php_openssl_load_all_certs_from_file(char *certfile);
840 static X509_REQ * php_openssl_csr_from_zval(zval * val, int makeresource, zend_resource ** resourceval);
841 static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req);
842
php_openssl_add_assoc_name_entry(zval * val,char * key,X509_NAME * name,int shortname)843 static void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname) /* {{{ */
844 {
845 zval *data;
846 zval subitem, tmp;
847 int i;
848 char *sname;
849 int nid;
850 X509_NAME_ENTRY * ne;
851 ASN1_STRING * str = NULL;
852 ASN1_OBJECT * obj;
853
854 if (key != NULL) {
855 array_init(&subitem);
856 } else {
857 ZVAL_COPY_VALUE(&subitem, val);
858 }
859
860 for (i = 0; i < X509_NAME_entry_count(name); i++) {
861 const unsigned char *to_add = NULL;
862 int to_add_len = 0;
863 unsigned char *to_add_buf = NULL;
864
865 ne = X509_NAME_get_entry(name, i);
866 obj = X509_NAME_ENTRY_get_object(ne);
867 nid = OBJ_obj2nid(obj);
868
869 if (shortname) {
870 sname = (char *) OBJ_nid2sn(nid);
871 } else {
872 sname = (char *) OBJ_nid2ln(nid);
873 }
874
875 str = X509_NAME_ENTRY_get_data(ne);
876 if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) {
877 /* ASN1_STRING_to_UTF8(3): The converted data is copied into a newly allocated buffer */
878 to_add_len = ASN1_STRING_to_UTF8(&to_add_buf, str);
879 to_add = to_add_buf;
880 } else {
881 /* ASN1_STRING_get0_data(3): Since this is an internal pointer it should not be freed or modified in any way */
882 to_add = ASN1_STRING_get0_data(str);
883 to_add_len = ASN1_STRING_length(str);
884 }
885
886 if (to_add_len != -1) {
887 if ((data = zend_hash_str_find(Z_ARRVAL(subitem), sname, strlen(sname))) != NULL) {
888 if (Z_TYPE_P(data) == IS_ARRAY) {
889 add_next_index_stringl(data, (const char *)to_add, to_add_len);
890 } else if (Z_TYPE_P(data) == IS_STRING) {
891 array_init(&tmp);
892 add_next_index_str(&tmp, zend_string_copy(Z_STR_P(data)));
893 add_next_index_stringl(&tmp, (const char *)to_add, to_add_len);
894 zend_hash_str_update(Z_ARRVAL(subitem), sname, strlen(sname), &tmp);
895 }
896 } else {
897 /* it might be better to expand it and pass zval from ZVAL_STRING
898 * to zend_symtable_str_update so we do not silently drop const
899 * but we need a test to cover this part first */
900 add_assoc_stringl(&subitem, sname, (char *)to_add, to_add_len);
901 }
902 } else {
903 php_openssl_store_errors();
904 }
905
906 if (to_add_buf != NULL) {
907 OPENSSL_free(to_add_buf);
908 }
909 }
910
911 if (key != NULL) {
912 zend_hash_str_update(Z_ARRVAL_P(val), key, strlen(key), &subitem);
913 }
914 }
915 /* }}} */
916
php_openssl_add_assoc_asn1_string(zval * val,char * key,ASN1_STRING * str)917 static void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) /* {{{ */
918 {
919 add_assoc_stringl(val, key, (char *)str->data, str->length);
920 }
921 /* }}} */
922
php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr)923 static time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr) /* {{{ */
924 {
925 /*
926 This is how the time string is formatted:
927
928 snprintf(p, sizeof(p), "%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
929 ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
930 */
931
932 time_t ret;
933 struct tm thetime;
934 char * strbuf;
935 char * thestr;
936 long gmadjust = 0;
937 size_t timestr_len;
938
939 if (ASN1_STRING_type(timestr) != V_ASN1_UTCTIME && ASN1_STRING_type(timestr) != V_ASN1_GENERALIZEDTIME) {
940 php_error_docref(NULL, E_WARNING, "illegal ASN1 data type for timestamp");
941 return (time_t)-1;
942 }
943
944 timestr_len = (size_t)ASN1_STRING_length(timestr);
945
946 if (timestr_len != strlen((const char *)ASN1_STRING_get0_data(timestr))) {
947 php_error_docref(NULL, E_WARNING, "illegal length in timestamp");
948 return (time_t)-1;
949 }
950
951 if (timestr_len < 13 && timestr_len != 11) {
952 php_error_docref(NULL, E_WARNING, "unable to parse time string %s correctly", timestr->data);
953 return (time_t)-1;
954 }
955
956 if (ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME && timestr_len < 15) {
957 php_error_docref(NULL, E_WARNING, "unable to parse time string %s correctly", timestr->data);
958 return (time_t)-1;
959 }
960
961 strbuf = estrdup((const char *)ASN1_STRING_get0_data(timestr));
962
963 memset(&thetime, 0, sizeof(thetime));
964
965 /* we work backwards so that we can use atoi more easily */
966
967 thestr = strbuf + timestr_len - 3;
968
969 if (timestr_len == 11) {
970 thetime.tm_sec = 0;
971 } else {
972 thetime.tm_sec = atoi(thestr);
973 *thestr = '\0';
974 thestr -= 2;
975 }
976 thetime.tm_min = atoi(thestr);
977 *thestr = '\0';
978 thestr -= 2;
979 thetime.tm_hour = atoi(thestr);
980 *thestr = '\0';
981 thestr -= 2;
982 thetime.tm_mday = atoi(thestr);
983 *thestr = '\0';
984 thestr -= 2;
985 thetime.tm_mon = atoi(thestr)-1;
986
987 *thestr = '\0';
988 if( ASN1_STRING_type(timestr) == V_ASN1_UTCTIME ) {
989 thestr -= 2;
990 thetime.tm_year = atoi(thestr);
991
992 if (thetime.tm_year < 68) {
993 thetime.tm_year += 100;
994 }
995 } else if( ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME ) {
996 thestr -= 4;
997 thetime.tm_year = atoi(thestr) - 1900;
998 }
999
1000
1001 thetime.tm_isdst = -1;
1002 ret = mktime(&thetime);
1003
1004 #if HAVE_TM_GMTOFF
1005 gmadjust = thetime.tm_gmtoff;
1006 #else
1007 /*
1008 ** If correcting for daylight savings time, we set the adjustment to
1009 ** the value of timezone - 3600 seconds. Otherwise, we need to overcorrect and
1010 ** set the adjustment to the main timezone + 3600 seconds.
1011 */
1012 gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone);
1013 #endif
1014 ret += gmadjust;
1015
1016 efree(strbuf);
1017
1018 return ret;
1019 }
1020 /* }}} */
1021
php_openssl_config_check_syntax(const char * section_label,const char * config_filename,const char * section,LHASH_OF (CONF_VALUE)* config)1022 static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH_OF(CONF_VALUE) * config) /* {{{ */
1023 {
1024 X509V3_CTX ctx;
1025
1026 X509V3_set_ctx_test(&ctx);
1027 X509V3_set_conf_lhash(&ctx, config);
1028 if (!X509V3_EXT_add_conf(config, &ctx, (char *)section, NULL)) {
1029 php_openssl_store_errors();
1030 php_error_docref(NULL, E_WARNING, "Error loading %s section %s of %s",
1031 section_label,
1032 section,
1033 config_filename);
1034 return FAILURE;
1035 }
1036 return SUCCESS;
1037 }
1038 /* }}} */
1039
php_openssl_add_oid_section(struct php_x509_request * req)1040 static int php_openssl_add_oid_section(struct php_x509_request * req) /* {{{ */
1041 {
1042 char * str;
1043 STACK_OF(CONF_VALUE) * sktmp;
1044 CONF_VALUE * cnf;
1045 int i;
1046
1047 str = CONF_get_string(req->req_config, NULL, "oid_section");
1048 if (str == NULL) {
1049 php_openssl_store_errors();
1050 return SUCCESS;
1051 }
1052 sktmp = CONF_get_section(req->req_config, str);
1053 if (sktmp == NULL) {
1054 php_openssl_store_errors();
1055 php_error_docref(NULL, E_WARNING, "problem loading oid section %s", str);
1056 return FAILURE;
1057 }
1058 for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
1059 cnf = sk_CONF_VALUE_value(sktmp, i);
1060 if (OBJ_sn2nid(cnf->name) == NID_undef && OBJ_ln2nid(cnf->name) == NID_undef &&
1061 OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
1062 php_openssl_store_errors();
1063 php_error_docref(NULL, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value);
1064 return FAILURE;
1065 }
1066 }
1067 return SUCCESS;
1068 }
1069 /* }}} */
1070
1071 #define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req))
1072 #define PHP_SSL_REQ_DISPOSE(req) php_openssl_dispose_config(req)
1073 #define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval)
1074
1075 #define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \
1076 req->config_filename, req->var, req->req_config) == FAILURE) return FAILURE
1077
1078 #define SET_OPTIONAL_STRING_ARG(key, varname, defval) \
1079 do { \
1080 if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), key, sizeof(key)-1)) != NULL && Z_TYPE_P(item) == IS_STRING) { \
1081 varname = Z_STRVAL_P(item); \
1082 } else { \
1083 varname = defval; \
1084 if (varname == NULL) { \
1085 php_openssl_store_errors(); \
1086 } \
1087 } \
1088 } while(0)
1089
1090 #define SET_OPTIONAL_LONG_ARG(key, varname, defval) \
1091 if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), key, sizeof(key)-1)) != NULL && Z_TYPE_P(item) == IS_LONG) \
1092 varname = (int)Z_LVAL_P(item); \
1093 else \
1094 varname = defval
1095
1096 static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo);
1097
1098 /* {{{ strip line endings from spkac */
php_openssl_spki_cleanup(const char * src,char * dest)1099 static int php_openssl_spki_cleanup(const char *src, char *dest)
1100 {
1101 int removed = 0;
1102
1103 while (*src) {
1104 if (*src != '\n' && *src != '\r') {
1105 *dest++ = *src;
1106 } else {
1107 ++removed;
1108 }
1109 ++src;
1110 }
1111 *dest = 0;
1112 return removed;
1113 }
1114 /* }}} */
1115
php_openssl_parse_config(struct php_x509_request * req,zval * optional_args)1116 static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args) /* {{{ */
1117 {
1118 char * str;
1119 zval * item;
1120
1121 SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename);
1122 SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req");
1123 req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL);
1124 if (req->global_config == NULL) {
1125 php_openssl_store_errors();
1126 }
1127 req->req_config = CONF_load(NULL, req->config_filename, NULL);
1128 if (req->req_config == NULL) {
1129 php_openssl_store_errors();
1130 return FAILURE;
1131 }
1132
1133 /* read in the oids */
1134 str = CONF_get_string(req->req_config, NULL, "oid_file");
1135 if (str == NULL) {
1136 php_openssl_store_errors();
1137 } else if (!php_openssl_open_base_dir_chk(str)) {
1138 BIO *oid_bio = BIO_new_file(str, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
1139 if (oid_bio) {
1140 OBJ_create_objects(oid_bio);
1141 BIO_free(oid_bio);
1142 php_openssl_store_errors();
1143 }
1144 }
1145 if (php_openssl_add_oid_section(req) == FAILURE) {
1146 return FAILURE;
1147 }
1148 SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
1149 CONF_get_string(req->req_config, req->section_name, "default_md"));
1150 SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
1151 CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
1152 SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
1153 CONF_get_string(req->req_config, req->section_name, "req_extensions"));
1154 SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits,
1155 CONF_get_number(req->req_config, req->section_name, "default_bits"));
1156
1157 SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT);
1158
1159 if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key")-1)) != NULL) {
1160 req->priv_key_encrypt = Z_TYPE_P(item) == IS_TRUE ? 1 : 0;
1161 } else {
1162 str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key");
1163 if (str == NULL) {
1164 str = CONF_get_string(req->req_config, req->section_name, "encrypt_key");
1165 /* it is sure that there are some errrors as str was NULL for encrypt_rsa_key */
1166 php_openssl_store_errors();
1167 }
1168 if (str != NULL && strcmp(str, "no") == 0) {
1169 req->priv_key_encrypt = 0;
1170 } else {
1171 req->priv_key_encrypt = 1;
1172 }
1173 }
1174
1175 if (req->priv_key_encrypt &&
1176 optional_args &&
1177 (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key_cipher", sizeof("encrypt_key_cipher")-1)) != NULL &&
1178 Z_TYPE_P(item) == IS_LONG
1179 ) {
1180 zend_long cipher_algo = Z_LVAL_P(item);
1181 const EVP_CIPHER* cipher = php_openssl_get_evp_cipher_from_algo(cipher_algo);
1182 if (cipher == NULL) {
1183 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm for private key.");
1184 return FAILURE;
1185 } else {
1186 req->priv_key_encrypt_cipher = cipher;
1187 }
1188 } else {
1189 req->priv_key_encrypt_cipher = NULL;
1190 }
1191
1192 /* digest alg */
1193 if (req->digest_name == NULL) {
1194 req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md");
1195 }
1196 if (req->digest_name != NULL) {
1197 req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name);
1198 } else {
1199 php_openssl_store_errors();
1200 }
1201 if (req->md_alg == NULL) {
1202 req->md_alg = req->digest = EVP_sha1();
1203 php_openssl_store_errors();
1204 }
1205
1206 PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
1207 #ifdef HAVE_EVP_PKEY_EC
1208 /* set the ec group curve name */
1209 req->curve_name = NID_undef;
1210 if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "curve_name", sizeof("curve_name")-1)) != NULL
1211 && Z_TYPE_P(item) == IS_STRING) {
1212 req->curve_name = OBJ_sn2nid(Z_STRVAL_P(item));
1213 if (req->curve_name == NID_undef) {
1214 php_error_docref(NULL, E_WARNING, "Unknown elliptic curve (short) name %s", Z_STRVAL_P(item));
1215 return FAILURE;
1216 }
1217 }
1218 #endif
1219
1220 /* set the string mask */
1221 str = CONF_get_string(req->req_config, req->section_name, "string_mask");
1222 if (str == NULL) {
1223 php_openssl_store_errors();
1224 } else if (!ASN1_STRING_set_default_mask_asc(str)) {
1225 php_error_docref(NULL, E_WARNING, "Invalid global string mask setting %s", str);
1226 return FAILURE;
1227 }
1228
1229 PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section);
1230
1231 return SUCCESS;
1232 }
1233 /* }}} */
1234
php_openssl_dispose_config(struct php_x509_request * req)1235 static void php_openssl_dispose_config(struct php_x509_request * req) /* {{{ */
1236 {
1237 if (req->priv_key) {
1238 EVP_PKEY_free(req->priv_key);
1239 req->priv_key = NULL;
1240 }
1241 if (req->global_config) {
1242 CONF_free(req->global_config);
1243 req->global_config = NULL;
1244 }
1245 if (req->req_config) {
1246 CONF_free(req->req_config);
1247 req->req_config = NULL;
1248 }
1249 }
1250 /* }}} */
1251
1252 #if defined(PHP_WIN32) || PHP_OPENSSL_API_VERSION >= 0x10100
1253 #define PHP_OPENSSL_RAND_ADD_TIME() ((void) 0)
1254 #else
1255 #define PHP_OPENSSL_RAND_ADD_TIME() php_openssl_rand_add_timeval()
1256
php_openssl_rand_add_timeval()1257 static inline void php_openssl_rand_add_timeval() /* {{{ */
1258 {
1259 struct timeval tv;
1260
1261 gettimeofday(&tv, NULL);
1262 RAND_add(&tv, sizeof(tv), 0.0);
1263 }
1264 /* }}} */
1265
1266 #endif
1267
php_openssl_load_rand_file(const char * file,int * egdsocket,int * seeded)1268 static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded) /* {{{ */
1269 {
1270 char buffer[MAXPATHLEN];
1271
1272 *egdsocket = 0;
1273 *seeded = 0;
1274
1275 if (file == NULL) {
1276 file = RAND_file_name(buffer, sizeof(buffer));
1277 #ifdef HAVE_RAND_EGD
1278 } else if (RAND_egd(file) > 0) {
1279 /* if the given filename is an EGD socket, don't
1280 * write anything back to it */
1281 *egdsocket = 1;
1282 return SUCCESS;
1283 #endif
1284 }
1285 if (file == NULL || !RAND_load_file(file, -1)) {
1286 if (RAND_status() == 0) {
1287 php_openssl_store_errors();
1288 php_error_docref(NULL, E_WARNING, "unable to load random state; not enough random data!");
1289 return FAILURE;
1290 }
1291 return FAILURE;
1292 }
1293 *seeded = 1;
1294 return SUCCESS;
1295 }
1296 /* }}} */
1297
php_openssl_write_rand_file(const char * file,int egdsocket,int seeded)1298 static int php_openssl_write_rand_file(const char * file, int egdsocket, int seeded) /* {{{ */
1299 {
1300 char buffer[MAXPATHLEN];
1301
1302
1303 if (egdsocket || !seeded) {
1304 /* if we did not manage to read the seed file, we should not write
1305 * a low-entropy seed file back */
1306 return FAILURE;
1307 }
1308 if (file == NULL) {
1309 file = RAND_file_name(buffer, sizeof(buffer));
1310 }
1311 PHP_OPENSSL_RAND_ADD_TIME();
1312 if (file == NULL || !RAND_write_file(file)) {
1313 php_openssl_store_errors();
1314 php_error_docref(NULL, E_WARNING, "unable to write random state");
1315 return FAILURE;
1316 }
1317 return SUCCESS;
1318 }
1319 /* }}} */
1320
php_openssl_get_evp_md_from_algo(zend_long algo)1321 static EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo) { /* {{{ */
1322 EVP_MD *mdtype;
1323
1324 switch (algo) {
1325 case OPENSSL_ALGO_SHA1:
1326 mdtype = (EVP_MD *) EVP_sha1();
1327 break;
1328 case OPENSSL_ALGO_MD5:
1329 mdtype = (EVP_MD *) EVP_md5();
1330 break;
1331 case OPENSSL_ALGO_MD4:
1332 mdtype = (EVP_MD *) EVP_md4();
1333 break;
1334 #ifdef HAVE_OPENSSL_MD2_H
1335 case OPENSSL_ALGO_MD2:
1336 mdtype = (EVP_MD *) EVP_md2();
1337 break;
1338 #endif
1339 #if PHP_OPENSSL_API_VERSION < 0x10100
1340 case OPENSSL_ALGO_DSS1:
1341 mdtype = (EVP_MD *) EVP_dss1();
1342 break;
1343 #endif
1344 case OPENSSL_ALGO_SHA224:
1345 mdtype = (EVP_MD *) EVP_sha224();
1346 break;
1347 case OPENSSL_ALGO_SHA256:
1348 mdtype = (EVP_MD *) EVP_sha256();
1349 break;
1350 case OPENSSL_ALGO_SHA384:
1351 mdtype = (EVP_MD *) EVP_sha384();
1352 break;
1353 case OPENSSL_ALGO_SHA512:
1354 mdtype = (EVP_MD *) EVP_sha512();
1355 break;
1356 case OPENSSL_ALGO_RMD160:
1357 mdtype = (EVP_MD *) EVP_ripemd160();
1358 break;
1359 default:
1360 return NULL;
1361 break;
1362 }
1363 return mdtype;
1364 }
1365 /* }}} */
1366
php_openssl_get_evp_cipher_from_algo(zend_long algo)1367 static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo) { /* {{{ */
1368 switch (algo) {
1369 #ifndef OPENSSL_NO_RC2
1370 case PHP_OPENSSL_CIPHER_RC2_40:
1371 return EVP_rc2_40_cbc();
1372 break;
1373 case PHP_OPENSSL_CIPHER_RC2_64:
1374 return EVP_rc2_64_cbc();
1375 break;
1376 case PHP_OPENSSL_CIPHER_RC2_128:
1377 return EVP_rc2_cbc();
1378 break;
1379 #endif
1380
1381 #ifndef OPENSSL_NO_DES
1382 case PHP_OPENSSL_CIPHER_DES:
1383 return EVP_des_cbc();
1384 break;
1385 case PHP_OPENSSL_CIPHER_3DES:
1386 return EVP_des_ede3_cbc();
1387 break;
1388 #endif
1389
1390 #ifndef OPENSSL_NO_AES
1391 case PHP_OPENSSL_CIPHER_AES_128_CBC:
1392 return EVP_aes_128_cbc();
1393 break;
1394 case PHP_OPENSSL_CIPHER_AES_192_CBC:
1395 return EVP_aes_192_cbc();
1396 break;
1397 case PHP_OPENSSL_CIPHER_AES_256_CBC:
1398 return EVP_aes_256_cbc();
1399 break;
1400 #endif
1401
1402
1403 default:
1404 return NULL;
1405 break;
1406 }
1407 }
1408 /* }}} */
1409
1410 /* {{{ INI Settings */
1411 PHP_INI_BEGIN()
1412 PHP_INI_ENTRY("openssl.cafile", NULL, PHP_INI_PERDIR, NULL)
1413 PHP_INI_ENTRY("openssl.capath", NULL, PHP_INI_PERDIR, NULL)
PHP_INI_END()1414 PHP_INI_END()
1415 /* }}} */
1416
1417 /* {{{ PHP_MINIT_FUNCTION
1418 */
1419 PHP_MINIT_FUNCTION(openssl)
1420 {
1421 char * config_filename;
1422
1423 le_key = zend_register_list_destructors_ex(php_openssl_pkey_free, NULL, "OpenSSL key", module_number);
1424 le_x509 = zend_register_list_destructors_ex(php_openssl_x509_free, NULL, "OpenSSL X.509", module_number);
1425 le_csr = zend_register_list_destructors_ex(php_openssl_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
1426
1427 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
1428 OPENSSL_config(NULL);
1429 SSL_library_init();
1430 OpenSSL_add_all_ciphers();
1431 OpenSSL_add_all_digests();
1432 OpenSSL_add_all_algorithms();
1433
1434 #if !defined(OPENSSL_NO_AES) && defined(EVP_CIPH_CCM_MODE) && OPENSSL_VERSION_NUMBER < 0x100020000
1435 EVP_add_cipher(EVP_aes_128_ccm());
1436 EVP_add_cipher(EVP_aes_192_ccm());
1437 EVP_add_cipher(EVP_aes_256_ccm());
1438 #endif
1439
1440 SSL_load_error_strings();
1441 #else
1442 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
1443 #endif
1444
1445 /* register a resource id number with OpenSSL so that we can map SSL -> stream structures in
1446 * OpenSSL callbacks */
1447 ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);
1448
1449 REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT);
1450 REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT);
1451
1452 /* purposes for cert purpose checking */
1453 REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT);
1454 REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
1455 REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
1456 REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT);
1457 REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT);
1458 REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT);
1459 #ifdef X509_PURPOSE_ANY
1460 REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT);
1461 #endif
1462
1463 /* signature algorithm constants */
1464 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT);
1465 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT);
1466 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD4", OPENSSL_ALGO_MD4, CONST_CS|CONST_PERSISTENT);
1467 #ifdef HAVE_OPENSSL_MD2_H
1468 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_CS|CONST_PERSISTENT);
1469 #endif
1470 #if PHP_OPENSSL_API_VERSION < 0x10100
1471 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT);
1472 #endif
1473 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA224", OPENSSL_ALGO_SHA224, CONST_CS|CONST_PERSISTENT);
1474 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA256", OPENSSL_ALGO_SHA256, CONST_CS|CONST_PERSISTENT);
1475 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA384", OPENSSL_ALGO_SHA384, CONST_CS|CONST_PERSISTENT);
1476 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA512", OPENSSL_ALGO_SHA512, CONST_CS|CONST_PERSISTENT);
1477 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_RMD160", OPENSSL_ALGO_RMD160, CONST_CS|CONST_PERSISTENT);
1478
1479 /* flags for S/MIME */
1480 REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT);
1481 REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT);
1482 REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT);
1483 REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT);
1484 REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT);
1485 REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT);
1486 REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT);
1487 REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
1488 REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
1489
1490 REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
1491 REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
1492 REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
1493 REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
1494
1495 /* Informational stream wrapper constants */
1496 REGISTER_STRING_CONSTANT("OPENSSL_DEFAULT_STREAM_CIPHERS", OPENSSL_DEFAULT_STREAM_CIPHERS, CONST_CS|CONST_PERSISTENT);
1497
1498 /* Ciphers */
1499 #ifndef OPENSSL_NO_RC2
1500 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
1501 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT);
1502 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT);
1503 #endif
1504 #ifndef OPENSSL_NO_DES
1505 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT);
1506 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT);
1507 #endif
1508 #ifndef OPENSSL_NO_AES
1509 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_128_CBC", PHP_OPENSSL_CIPHER_AES_128_CBC, CONST_CS|CONST_PERSISTENT);
1510 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_192_CBC", PHP_OPENSSL_CIPHER_AES_192_CBC, CONST_CS|CONST_PERSISTENT);
1511 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_256_CBC", PHP_OPENSSL_CIPHER_AES_256_CBC, CONST_CS|CONST_PERSISTENT);
1512 #endif
1513
1514 /* Values for key types */
1515 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT);
1516 #ifndef NO_DSA
1517 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT);
1518 #endif
1519 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT);
1520 #ifdef HAVE_EVP_PKEY_EC
1521 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT);
1522 #endif
1523
1524 REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_CS|CONST_PERSISTENT);
1525 REGISTER_LONG_CONSTANT("OPENSSL_ZERO_PADDING", OPENSSL_ZERO_PADDING, CONST_CS|CONST_PERSISTENT);
1526 REGISTER_LONG_CONSTANT("OPENSSL_DONT_ZERO_PAD_KEY", OPENSSL_DONT_ZERO_PAD_KEY, CONST_CS|CONST_PERSISTENT);
1527
1528 #ifndef OPENSSL_NO_TLSEXT
1529 /* SNI support included */
1530 REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT);
1531 #endif
1532
1533 /* Determine default SSL configuration file */
1534 config_filename = getenv("OPENSSL_CONF");
1535 if (config_filename == NULL) {
1536 config_filename = getenv("SSLEAY_CONF");
1537 }
1538
1539 /* default to 'openssl.cnf' if no environment variable is set */
1540 if (config_filename == NULL) {
1541 snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename), "%s/%s",
1542 X509_get_default_cert_area(),
1543 "openssl.cnf");
1544 } else {
1545 strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename));
1546 }
1547
1548 php_stream_xport_register("ssl", php_openssl_ssl_socket_factory);
1549 #ifndef OPENSSL_NO_SSL3
1550 php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory);
1551 #endif
1552 php_stream_xport_register("tls", php_openssl_ssl_socket_factory);
1553 php_stream_xport_register("tlsv1.0", php_openssl_ssl_socket_factory);
1554 php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory);
1555 php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory);
1556
1557 /* override the default tcp socket provider */
1558 php_stream_xport_register("tcp", php_openssl_ssl_socket_factory);
1559
1560 php_register_url_stream_wrapper("https", &php_stream_http_wrapper);
1561 php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper);
1562
1563 REGISTER_INI_ENTRIES();
1564
1565 return SUCCESS;
1566 }
1567 /* }}} */
1568
1569 /* {{{ PHP_GINIT_FUNCTION
1570 */
PHP_GINIT_FUNCTION(openssl)1571 PHP_GINIT_FUNCTION(openssl)
1572 {
1573 #if defined(COMPILE_DL_OPENSSL) && defined(ZTS)
1574 ZEND_TSRMLS_CACHE_UPDATE();
1575 #endif
1576 openssl_globals->errors = NULL;
1577 }
1578 /* }}} */
1579
1580 /* {{{ PHP_GSHUTDOWN_FUNCTION
1581 */
PHP_GSHUTDOWN_FUNCTION(openssl)1582 PHP_GSHUTDOWN_FUNCTION(openssl)
1583 {
1584 if (openssl_globals->errors) {
1585 pefree(openssl_globals->errors, 1);
1586 }
1587 }
1588 /* }}} */
1589
1590 /* {{{ PHP_MINFO_FUNCTION
1591 */
PHP_MINFO_FUNCTION(openssl)1592 PHP_MINFO_FUNCTION(openssl)
1593 {
1594 php_info_print_table_start();
1595 php_info_print_table_row(2, "OpenSSL support", "enabled");
1596 php_info_print_table_row(2, "OpenSSL Library Version", SSLeay_version(SSLEAY_VERSION));
1597 php_info_print_table_row(2, "OpenSSL Header Version", OPENSSL_VERSION_TEXT);
1598 php_info_print_table_row(2, "Openssl default config", default_ssl_conf_filename);
1599 php_info_print_table_end();
1600 DISPLAY_INI_ENTRIES();
1601 }
1602 /* }}} */
1603
1604 /* {{{ PHP_MSHUTDOWN_FUNCTION
1605 */
PHP_MSHUTDOWN_FUNCTION(openssl)1606 PHP_MSHUTDOWN_FUNCTION(openssl)
1607 {
1608 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
1609 EVP_cleanup();
1610
1611 /* prevent accessing locking callback from unloaded extension */
1612 CRYPTO_set_locking_callback(NULL);
1613 /* free allocated error strings */
1614 ERR_free_strings();
1615 CONF_modules_free();
1616 #endif
1617
1618 php_unregister_url_stream_wrapper("https");
1619 php_unregister_url_stream_wrapper("ftps");
1620
1621 php_stream_xport_unregister("ssl");
1622 #ifndef OPENSSL_NO_SSL3
1623 php_stream_xport_unregister("sslv3");
1624 #endif
1625 php_stream_xport_unregister("tls");
1626 php_stream_xport_unregister("tlsv1.0");
1627 php_stream_xport_unregister("tlsv1.1");
1628 php_stream_xport_unregister("tlsv1.2");
1629
1630 /* reinstate the default tcp handler */
1631 php_stream_xport_register("tcp", php_stream_generic_socket_factory);
1632
1633 UNREGISTER_INI_ENTRIES();
1634
1635 return SUCCESS;
1636 }
1637 /* }}} */
1638
1639 /* {{{ x509 cert functions */
1640
1641 /* {{{ proto array openssl_get_cert_locations(void)
1642 Retrieve an array mapping available certificate locations */
PHP_FUNCTION(openssl_get_cert_locations)1643 PHP_FUNCTION(openssl_get_cert_locations)
1644 {
1645 array_init(return_value);
1646
1647 add_assoc_string(return_value, "default_cert_file", (char *) X509_get_default_cert_file());
1648 add_assoc_string(return_value, "default_cert_file_env", (char *) X509_get_default_cert_file_env());
1649 add_assoc_string(return_value, "default_cert_dir", (char *) X509_get_default_cert_dir());
1650 add_assoc_string(return_value, "default_cert_dir_env", (char *) X509_get_default_cert_dir_env());
1651 add_assoc_string(return_value, "default_private_dir", (char *) X509_get_default_private_dir());
1652 add_assoc_string(return_value, "default_default_cert_area", (char *) X509_get_default_cert_area());
1653 add_assoc_string(return_value, "ini_cafile",
1654 zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0));
1655 add_assoc_string(return_value, "ini_capath",
1656 zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0));
1657 }
1658 /* }}} */
1659
1660
1661 /* {{{ php_openssl_x509_from_zval
1662 Given a zval, coerce it into an X509 object.
1663 The zval can be:
1664 . X509 resource created using openssl_read_x509()
1665 . if it starts with file:// then it will be interpreted as the path to that cert
1666 . it will be interpreted as the cert data
1667 If you supply makeresource, the result will be registered as an x509 resource and
1668 it's value returned in makeresource.
1669 */
php_openssl_x509_from_zval(zval * val,int makeresource,zend_resource ** resourceval)1670 static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval)
1671 {
1672 X509 *cert = NULL;
1673 BIO *in;
1674
1675 if (resourceval) {
1676 *resourceval = NULL;
1677 }
1678 if (Z_TYPE_P(val) == IS_RESOURCE) {
1679 /* is it an x509 resource ? */
1680 void * what;
1681 zend_resource *res = Z_RES_P(val);
1682
1683 what = zend_fetch_resource(res, "OpenSSL X.509", le_x509);
1684 if (!what) {
1685 return NULL;
1686 }
1687 if (resourceval) {
1688 *resourceval = res;
1689 if (makeresource) {
1690 Z_ADDREF_P(val);
1691 }
1692 }
1693 return (X509*)what;
1694 }
1695
1696 if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) {
1697 return NULL;
1698 }
1699
1700 /* force it to be a string and check if it refers to a file */
1701 convert_to_string_ex(val);
1702
1703 if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) {
1704
1705 if (php_openssl_open_base_dir_chk(Z_STRVAL_P(val) + (sizeof("file://") - 1))) {
1706 return NULL;
1707 }
1708
1709 in = BIO_new_file(Z_STRVAL_P(val) + (sizeof("file://") - 1), PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
1710 if (in == NULL) {
1711 php_openssl_store_errors();
1712 return NULL;
1713 }
1714 cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
1715
1716 } else {
1717
1718 in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val));
1719 if (in == NULL) {
1720 php_openssl_store_errors();
1721 return NULL;
1722 }
1723 #ifdef TYPEDEF_D2I_OF
1724 cert = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
1725 #else
1726 cert = (X509 *) PEM_ASN1_read_bio((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
1727 #endif
1728 }
1729
1730 if (!BIO_free(in)) {
1731 php_openssl_store_errors();
1732 }
1733
1734 if (cert == NULL) {
1735 php_openssl_store_errors();
1736 return NULL;
1737 }
1738
1739 if (makeresource && resourceval) {
1740 *resourceval = zend_register_resource(cert, le_x509);
1741 }
1742 return cert;
1743 }
1744
1745 /* }}} */
1746
1747 /* {{{ proto bool openssl_x509_export_to_file(mixed x509, string outfilename [, bool notext = true])
1748 Exports a CERT to file or a var */
PHP_FUNCTION(openssl_x509_export_to_file)1749 PHP_FUNCTION(openssl_x509_export_to_file)
1750 {
1751 X509 * cert;
1752 zval * zcert;
1753 zend_bool notext = 1;
1754 BIO * bio_out;
1755 char * filename;
1756 size_t filename_len;
1757
1758 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|b", &zcert, &filename, &filename_len, ¬ext) == FAILURE) {
1759 return;
1760 }
1761 RETVAL_FALSE;
1762
1763 cert = php_openssl_x509_from_zval(zcert, 0, NULL);
1764 if (cert == NULL) {
1765 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1");
1766 return;
1767 }
1768
1769 if (php_openssl_open_base_dir_chk(filename)) {
1770 return;
1771 }
1772
1773 bio_out = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
1774 if (bio_out) {
1775 if (!notext && !X509_print(bio_out, cert)) {
1776 php_openssl_store_errors();
1777 }
1778 if (!PEM_write_bio_X509(bio_out, cert)) {
1779 php_openssl_store_errors();
1780 }
1781
1782 RETVAL_TRUE;
1783 } else {
1784 php_openssl_store_errors();
1785 php_error_docref(NULL, E_WARNING, "error opening file %s", filename);
1786 }
1787 if (Z_TYPE_P(zcert) != IS_RESOURCE) {
1788 X509_free(cert);
1789 }
1790
1791 if (!BIO_free(bio_out)) {
1792 php_openssl_store_errors();
1793 }
1794 }
1795 /* }}} */
1796
1797 /* {{{ proto string openssl_spki_new(mixed zpkey, string challenge [, mixed method])
1798 Creates new private key (or uses existing) and creates a new spki cert
1799 outputting results to var */
PHP_FUNCTION(openssl_spki_new)1800 PHP_FUNCTION(openssl_spki_new)
1801 {
1802 size_t challenge_len;
1803 char * challenge = NULL, * spkstr = NULL;
1804 zend_string * s = NULL;
1805 zend_resource *keyresource = NULL;
1806 const char *spkac = "SPKAC=";
1807 zend_long algo = OPENSSL_ALGO_MD5;
1808
1809 zval *method = NULL;
1810 zval * zpkey = NULL;
1811 EVP_PKEY * pkey = NULL;
1812 NETSCAPE_SPKI *spki=NULL;
1813 const EVP_MD *mdtype;
1814
1815 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|z", &zpkey, &challenge, &challenge_len, &method) == FAILURE) {
1816 return;
1817 }
1818 RETVAL_FALSE;
1819
1820 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(challenge_len, challenge);
1821 pkey = php_openssl_evp_from_zval(zpkey, 0, challenge, challenge_len, 1, &keyresource);
1822
1823 if (pkey == NULL) {
1824 php_error_docref(NULL, E_WARNING, "Unable to use supplied private key");
1825 goto cleanup;
1826 }
1827
1828 if (method != NULL) {
1829 if (Z_TYPE_P(method) == IS_LONG) {
1830 algo = Z_LVAL_P(method);
1831 } else {
1832 php_error_docref(NULL, E_WARNING, "Algorithm must be of supported type");
1833 goto cleanup;
1834 }
1835 }
1836 mdtype = php_openssl_get_evp_md_from_algo(algo);
1837
1838 if (!mdtype) {
1839 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
1840 goto cleanup;
1841 }
1842
1843 if ((spki = NETSCAPE_SPKI_new()) == NULL) {
1844 php_openssl_store_errors();
1845 php_error_docref(NULL, E_WARNING, "Unable to create new SPKAC");
1846 goto cleanup;
1847 }
1848
1849 if (challenge) {
1850 if (!ASN1_STRING_set(spki->spkac->challenge, challenge, (int)challenge_len)) {
1851 php_openssl_store_errors();
1852 php_error_docref(NULL, E_WARNING, "Unable to set challenge data");
1853 goto cleanup;
1854 }
1855 }
1856
1857 if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) {
1858 php_openssl_store_errors();
1859 php_error_docref(NULL, E_WARNING, "Unable to embed public key");
1860 goto cleanup;
1861 }
1862
1863 if (!NETSCAPE_SPKI_sign(spki, pkey, mdtype)) {
1864 php_openssl_store_errors();
1865 php_error_docref(NULL, E_WARNING, "Unable to sign with specified algorithm");
1866 goto cleanup;
1867 }
1868
1869 spkstr = NETSCAPE_SPKI_b64_encode(spki);
1870 if (!spkstr){
1871 php_openssl_store_errors();
1872 php_error_docref(NULL, E_WARNING, "Unable to encode SPKAC");
1873 goto cleanup;
1874 }
1875
1876 s = zend_string_alloc(strlen(spkac) + strlen(spkstr), 0);
1877 sprintf(ZSTR_VAL(s), "%s%s", spkac, spkstr);
1878 ZSTR_LEN(s) = strlen(ZSTR_VAL(s));
1879 OPENSSL_free(spkstr);
1880
1881 RETVAL_STR(s);
1882 goto cleanup;
1883
1884 cleanup:
1885
1886 if (spki != NULL) {
1887 NETSCAPE_SPKI_free(spki);
1888 }
1889 if (keyresource == NULL && pkey != NULL) {
1890 EVP_PKEY_free(pkey);
1891 }
1892
1893 if (s && ZSTR_LEN(s) <= 0) {
1894 RETVAL_FALSE;
1895 }
1896
1897 if (keyresource == NULL && s != NULL) {
1898 zend_string_release_ex(s, 0);
1899 }
1900 }
1901 /* }}} */
1902
1903 /* {{{ proto bool openssl_spki_verify(string spki)
1904 Verifies spki returns boolean */
PHP_FUNCTION(openssl_spki_verify)1905 PHP_FUNCTION(openssl_spki_verify)
1906 {
1907 size_t spkstr_len;
1908 int i = 0, spkstr_cleaned_len = 0;
1909 char *spkstr = NULL, * spkstr_cleaned = NULL;
1910
1911 EVP_PKEY *pkey = NULL;
1912 NETSCAPE_SPKI *spki = NULL;
1913
1914 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
1915 return;
1916 }
1917 RETVAL_FALSE;
1918
1919 if (spkstr == NULL) {
1920 php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC");
1921 goto cleanup;
1922 }
1923
1924 spkstr_cleaned = emalloc(spkstr_len + 1);
1925 spkstr_cleaned_len = (int)(spkstr_len - php_openssl_spki_cleanup(spkstr, spkstr_cleaned));
1926
1927 if (spkstr_cleaned_len == 0) {
1928 php_error_docref(NULL, E_WARNING, "Invalid SPKAC");
1929 goto cleanup;
1930 }
1931
1932 spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len);
1933 if (spki == NULL) {
1934 php_openssl_store_errors();
1935 php_error_docref(NULL, E_WARNING, "Unable to decode supplied SPKAC");
1936 goto cleanup;
1937 }
1938
1939 pkey = X509_PUBKEY_get(spki->spkac->pubkey);
1940 if (pkey == NULL) {
1941 php_openssl_store_errors();
1942 php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key");
1943 goto cleanup;
1944 }
1945
1946 i = NETSCAPE_SPKI_verify(spki, pkey);
1947 goto cleanup;
1948
1949 cleanup:
1950 if (spki != NULL) {
1951 NETSCAPE_SPKI_free(spki);
1952 }
1953 if (pkey != NULL) {
1954 EVP_PKEY_free(pkey);
1955 }
1956 if (spkstr_cleaned != NULL) {
1957 efree(spkstr_cleaned);
1958 }
1959
1960 if (i > 0) {
1961 RETVAL_TRUE;
1962 } else {
1963 php_openssl_store_errors();
1964 }
1965 }
1966 /* }}} */
1967
1968 /* {{{ proto string openssl_spki_export(string spki)
1969 Exports public key from existing spki to var */
PHP_FUNCTION(openssl_spki_export)1970 PHP_FUNCTION(openssl_spki_export)
1971 {
1972 size_t spkstr_len;
1973 char *spkstr = NULL, * spkstr_cleaned = NULL, * s = NULL;
1974 int spkstr_cleaned_len;
1975
1976 EVP_PKEY *pkey = NULL;
1977 NETSCAPE_SPKI *spki = NULL;
1978 BIO *out = NULL;
1979
1980 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
1981 return;
1982 }
1983 RETVAL_FALSE;
1984
1985 if (spkstr == NULL) {
1986 php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC");
1987 goto cleanup;
1988 }
1989
1990 spkstr_cleaned = emalloc(spkstr_len + 1);
1991 spkstr_cleaned_len = (int)(spkstr_len - php_openssl_spki_cleanup(spkstr, spkstr_cleaned));
1992
1993 if (spkstr_cleaned_len == 0) {
1994 php_error_docref(NULL, E_WARNING, "Invalid SPKAC");
1995 goto cleanup;
1996 }
1997
1998 spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len);
1999 if (spki == NULL) {
2000 php_openssl_store_errors();
2001 php_error_docref(NULL, E_WARNING, "Unable to decode supplied SPKAC");
2002 goto cleanup;
2003 }
2004
2005 pkey = X509_PUBKEY_get(spki->spkac->pubkey);
2006 if (pkey == NULL) {
2007 php_openssl_store_errors();
2008 php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key");
2009 goto cleanup;
2010 }
2011
2012 out = BIO_new(BIO_s_mem());
2013 if (out && PEM_write_bio_PUBKEY(out, pkey)) {
2014 BUF_MEM *bio_buf;
2015
2016 BIO_get_mem_ptr(out, &bio_buf);
2017 RETVAL_STRINGL((char *)bio_buf->data, bio_buf->length);
2018 } else {
2019 php_openssl_store_errors();
2020 }
2021 goto cleanup;
2022
2023 cleanup:
2024
2025 if (spki != NULL) {
2026 NETSCAPE_SPKI_free(spki);
2027 }
2028 if (out != NULL) {
2029 BIO_free_all(out);
2030 }
2031 if (pkey != NULL) {
2032 EVP_PKEY_free(pkey);
2033 }
2034 if (spkstr_cleaned != NULL) {
2035 efree(spkstr_cleaned);
2036 }
2037 if (s != NULL) {
2038 efree(s);
2039 }
2040 }
2041 /* }}} */
2042
2043 /* {{{ proto string openssl_spki_export_challenge(string spki)
2044 Exports spkac challenge from existing spki to var */
PHP_FUNCTION(openssl_spki_export_challenge)2045 PHP_FUNCTION(openssl_spki_export_challenge)
2046 {
2047 size_t spkstr_len;
2048 char *spkstr = NULL, * spkstr_cleaned = NULL;
2049 int spkstr_cleaned_len;
2050
2051 NETSCAPE_SPKI *spki = NULL;
2052
2053 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
2054 return;
2055 }
2056 RETVAL_FALSE;
2057
2058 if (spkstr == NULL) {
2059 php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC");
2060 goto cleanup;
2061 }
2062
2063 spkstr_cleaned = emalloc(spkstr_len + 1);
2064 spkstr_cleaned_len = (int)(spkstr_len - php_openssl_spki_cleanup(spkstr, spkstr_cleaned));
2065
2066 if (spkstr_cleaned_len == 0) {
2067 php_error_docref(NULL, E_WARNING, "Invalid SPKAC");
2068 goto cleanup;
2069 }
2070
2071 spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len);
2072 if (spki == NULL) {
2073 php_openssl_store_errors();
2074 php_error_docref(NULL, E_WARNING, "Unable to decode SPKAC");
2075 goto cleanup;
2076 }
2077
2078 RETVAL_STRING((const char *)ASN1_STRING_get0_data(spki->spkac->challenge));
2079 goto cleanup;
2080
2081 cleanup:
2082 if (spkstr_cleaned != NULL) {
2083 efree(spkstr_cleaned);
2084 }
2085 if (spki) {
2086 NETSCAPE_SPKI_free(spki);
2087 }
2088 }
2089 /* }}} */
2090
2091 /* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true])
2092 Exports a CERT to file or a var */
PHP_FUNCTION(openssl_x509_export)2093 PHP_FUNCTION(openssl_x509_export)
2094 {
2095 X509 * cert;
2096 zval * zcert, *zout;
2097 zend_bool notext = 1;
2098 BIO * bio_out;
2099
2100 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|b", &zcert, &zout, ¬ext) == FAILURE) {
2101 return;
2102 }
2103 RETVAL_FALSE;
2104
2105 cert = php_openssl_x509_from_zval(zcert, 0, NULL);
2106 if (cert == NULL) {
2107 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1");
2108 return;
2109 }
2110
2111 bio_out = BIO_new(BIO_s_mem());
2112 if (!bio_out) {
2113 php_openssl_store_errors();
2114 goto cleanup;
2115 }
2116 if (!notext && !X509_print(bio_out, cert)) {
2117 php_openssl_store_errors();
2118 }
2119 if (PEM_write_bio_X509(bio_out, cert)) {
2120 BUF_MEM *bio_buf;
2121
2122 zval_ptr_dtor(zout);
2123 BIO_get_mem_ptr(bio_out, &bio_buf);
2124 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length);
2125
2126 RETVAL_TRUE;
2127 } else {
2128 php_openssl_store_errors();
2129 }
2130
2131 BIO_free(bio_out);
2132
2133 cleanup:
2134 if (Z_TYPE_P(zcert) != IS_RESOURCE) {
2135 X509_free(cert);
2136 }
2137 }
2138 /* }}} */
2139
php_openssl_x509_fingerprint(X509 * peer,const char * method,zend_bool raw)2140 zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw)
2141 {
2142 unsigned char md[EVP_MAX_MD_SIZE];
2143 const EVP_MD *mdtype;
2144 unsigned int n;
2145 zend_string *ret;
2146
2147 if (!(mdtype = EVP_get_digestbyname(method))) {
2148 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
2149 return NULL;
2150 } else if (!X509_digest(peer, mdtype, md, &n)) {
2151 php_openssl_store_errors();
2152 php_error_docref(NULL, E_ERROR, "Could not generate signature");
2153 return NULL;
2154 }
2155
2156 if (raw) {
2157 ret = zend_string_init((char*)md, n, 0);
2158 } else {
2159 ret = zend_string_alloc(n * 2, 0);
2160 make_digest_ex(ZSTR_VAL(ret), md, n);
2161 ZSTR_VAL(ret)[n * 2] = '\0';
2162 }
2163
2164 return ret;
2165 }
2166
PHP_FUNCTION(openssl_x509_fingerprint)2167 PHP_FUNCTION(openssl_x509_fingerprint)
2168 {
2169 X509 *cert;
2170 zval *zcert;
2171 zend_bool raw_output = 0;
2172 char *method = "sha1";
2173 size_t method_len;
2174 zend_string *fingerprint;
2175
2176 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|sb", &zcert, &method, &method_len, &raw_output) == FAILURE) {
2177 return;
2178 }
2179
2180 cert = php_openssl_x509_from_zval(zcert, 0, NULL);
2181 if (cert == NULL) {
2182 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1");
2183 RETURN_FALSE;
2184 }
2185
2186 fingerprint = php_openssl_x509_fingerprint(cert, method, raw_output);
2187 if (fingerprint) {
2188 RETVAL_STR(fingerprint);
2189 } else {
2190 RETVAL_FALSE;
2191 }
2192
2193 if (Z_TYPE_P(zcert) != IS_RESOURCE) {
2194 X509_free(cert);
2195 }
2196 }
2197
2198 /* {{{ proto bool openssl_x509_check_private_key(mixed cert, mixed key)
2199 Checks if a private key corresponds to a CERT */
PHP_FUNCTION(openssl_x509_check_private_key)2200 PHP_FUNCTION(openssl_x509_check_private_key)
2201 {
2202 zval * zcert, *zkey;
2203 X509 * cert = NULL;
2204 EVP_PKEY * key = NULL;
2205 zend_resource *keyresource = NULL;
2206
2207 RETVAL_FALSE;
2208
2209 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zcert, &zkey) == FAILURE) {
2210 return;
2211 }
2212 cert = php_openssl_x509_from_zval(zcert, 0, NULL);
2213 if (cert == NULL) {
2214 RETURN_FALSE;
2215 }
2216 key = php_openssl_evp_from_zval(zkey, 0, "", 0, 1, &keyresource);
2217 if (key) {
2218 RETVAL_BOOL(X509_check_private_key(cert, key));
2219 }
2220
2221 if (keyresource == NULL && key) {
2222 EVP_PKEY_free(key);
2223 }
2224 if (Z_TYPE_P(zcert) != IS_RESOURCE) {
2225 X509_free(cert);
2226 }
2227 }
2228 /* }}} */
2229
2230 /* Special handling of subjectAltName, see CVE-2013-4073
2231 * Christian Heimes
2232 */
2233
openssl_x509v3_subjectAltName(BIO * bio,X509_EXTENSION * extension)2234 static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension)
2235 {
2236 GENERAL_NAMES *names;
2237 const X509V3_EXT_METHOD *method = NULL;
2238 ASN1_OCTET_STRING *extension_data;
2239 long i, length, num;
2240 const unsigned char *p;
2241
2242 method = X509V3_EXT_get(extension);
2243 if (method == NULL) {
2244 return -1;
2245 }
2246
2247 extension_data = X509_EXTENSION_get_data(extension);
2248 p = extension_data->data;
2249 length = extension_data->length;
2250 if (method->it) {
2251 names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, &p, length,
2252 ASN1_ITEM_ptr(method->it)));
2253 } else {
2254 names = (GENERAL_NAMES*) (method->d2i(NULL, &p, length));
2255 }
2256 if (names == NULL) {
2257 php_openssl_store_errors();
2258 return -1;
2259 }
2260
2261 num = sk_GENERAL_NAME_num(names);
2262 for (i = 0; i < num; i++) {
2263 GENERAL_NAME *name;
2264 ASN1_STRING *as;
2265 name = sk_GENERAL_NAME_value(names, i);
2266 switch (name->type) {
2267 case GEN_EMAIL:
2268 BIO_puts(bio, "email:");
2269 as = name->d.rfc822Name;
2270 BIO_write(bio, ASN1_STRING_get0_data(as),
2271 ASN1_STRING_length(as));
2272 break;
2273 case GEN_DNS:
2274 BIO_puts(bio, "DNS:");
2275 as = name->d.dNSName;
2276 BIO_write(bio, ASN1_STRING_get0_data(as),
2277 ASN1_STRING_length(as));
2278 break;
2279 case GEN_URI:
2280 BIO_puts(bio, "URI:");
2281 as = name->d.uniformResourceIdentifier;
2282 BIO_write(bio, ASN1_STRING_get0_data(as),
2283 ASN1_STRING_length(as));
2284 break;
2285 default:
2286 /* use builtin print for GEN_OTHERNAME, GEN_X400,
2287 * GEN_EDIPARTY, GEN_DIRNAME, GEN_IPADD and GEN_RID
2288 */
2289 GENERAL_NAME_print(bio, name);
2290 }
2291 /* trailing ', ' except for last element */
2292 if (i < (num - 1)) {
2293 BIO_puts(bio, ", ");
2294 }
2295 }
2296 sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
2297
2298 return 0;
2299 }
2300
2301 /* {{{ proto array openssl_x509_parse(mixed x509 [, bool shortnames=true])
2302 Returns an array of the fields/values of the CERT */
PHP_FUNCTION(openssl_x509_parse)2303 PHP_FUNCTION(openssl_x509_parse)
2304 {
2305 zval * zcert;
2306 X509 * cert = NULL;
2307 int i, sig_nid;
2308 zend_bool useshortnames = 1;
2309 char * tmpstr;
2310 zval subitem;
2311 X509_EXTENSION *extension;
2312 X509_NAME *subject_name;
2313 char *cert_name;
2314 char *extname;
2315 BIO *bio_out;
2316 BUF_MEM *bio_buf;
2317 ASN1_INTEGER *asn1_serial;
2318 BIGNUM *bn_serial;
2319 char *str_serial;
2320 char *hex_serial;
2321 char buf[256];
2322
2323 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcert, &useshortnames) == FAILURE) {
2324 return;
2325 }
2326 cert = php_openssl_x509_from_zval(zcert, 0, NULL);
2327 if (cert == NULL) {
2328 RETURN_FALSE;
2329 }
2330 array_init(return_value);
2331
2332 subject_name = X509_get_subject_name(cert);
2333 cert_name = X509_NAME_oneline(subject_name, NULL, 0);
2334 add_assoc_string(return_value, "name", cert_name);
2335 OPENSSL_free(cert_name);
2336
2337 php_openssl_add_assoc_name_entry(return_value, "subject", subject_name, useshortnames);
2338 /* hash as used in CA directories to lookup cert by subject name */
2339 {
2340 char buf[32];
2341 snprintf(buf, sizeof(buf), "%08lx", X509_subject_name_hash(cert));
2342 add_assoc_string(return_value, "hash", buf);
2343 }
2344
2345 php_openssl_add_assoc_name_entry(return_value, "issuer", X509_get_issuer_name(cert), useshortnames);
2346 add_assoc_long(return_value, "version", X509_get_version(cert));
2347
2348 asn1_serial = X509_get_serialNumber(cert);
2349
2350 bn_serial = ASN1_INTEGER_to_BN(asn1_serial, NULL);
2351 /* Can return NULL on error or memory allocation failure */
2352 if (!bn_serial) {
2353 php_openssl_store_errors();
2354 RETURN_FALSE;
2355 }
2356
2357 hex_serial = BN_bn2hex(bn_serial);
2358 BN_free(bn_serial);
2359 /* Can return NULL on error or memory allocation failure */
2360 if (!hex_serial) {
2361 php_openssl_store_errors();
2362 RETURN_FALSE;
2363 }
2364
2365 str_serial = i2s_ASN1_INTEGER(NULL, asn1_serial);
2366 add_assoc_string(return_value, "serialNumber", str_serial);
2367 OPENSSL_free(str_serial);
2368
2369 /* Return the hex representation of the serial number, as defined by OpenSSL */
2370 add_assoc_string(return_value, "serialNumberHex", hex_serial);
2371 OPENSSL_free(hex_serial);
2372
2373 php_openssl_add_assoc_asn1_string(return_value, "validFrom", X509_get_notBefore(cert));
2374 php_openssl_add_assoc_asn1_string(return_value, "validTo", X509_get_notAfter(cert));
2375
2376 add_assoc_long(return_value, "validFrom_time_t", php_openssl_asn1_time_to_time_t(X509_get_notBefore(cert)));
2377 add_assoc_long(return_value, "validTo_time_t", php_openssl_asn1_time_to_time_t(X509_get_notAfter(cert)));
2378
2379 tmpstr = (char *)X509_alias_get0(cert, NULL);
2380 if (tmpstr) {
2381 add_assoc_string(return_value, "alias", tmpstr);
2382 }
2383
2384 sig_nid = X509_get_signature_nid(cert);
2385 add_assoc_string(return_value, "signatureTypeSN", (char*)OBJ_nid2sn(sig_nid));
2386 add_assoc_string(return_value, "signatureTypeLN", (char*)OBJ_nid2ln(sig_nid));
2387 add_assoc_long(return_value, "signatureTypeNID", sig_nid);
2388 array_init(&subitem);
2389
2390 /* NOTE: the purposes are added as integer keys - the keys match up to the X509_PURPOSE_SSL_XXX defines
2391 in x509v3.h */
2392 for (i = 0; i < X509_PURPOSE_get_count(); i++) {
2393 int id, purpset;
2394 char * pname;
2395 X509_PURPOSE * purp;
2396 zval subsub;
2397
2398 array_init(&subsub);
2399
2400 purp = X509_PURPOSE_get0(i);
2401 id = X509_PURPOSE_get_id(purp);
2402
2403 purpset = X509_check_purpose(cert, id, 0);
2404 add_index_bool(&subsub, 0, purpset);
2405
2406 purpset = X509_check_purpose(cert, id, 1);
2407 add_index_bool(&subsub, 1, purpset);
2408
2409 pname = useshortnames ? X509_PURPOSE_get0_sname(purp) : X509_PURPOSE_get0_name(purp);
2410 add_index_string(&subsub, 2, pname);
2411
2412 /* NOTE: if purpset > 1 then it's a warning - we should mention it ? */
2413
2414 add_index_zval(&subitem, id, &subsub);
2415 }
2416 add_assoc_zval(return_value, "purposes", &subitem);
2417
2418 array_init(&subitem);
2419
2420
2421 for (i = 0; i < X509_get_ext_count(cert); i++) {
2422 int nid;
2423 extension = X509_get_ext(cert, i);
2424 nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension));
2425 if (nid != NID_undef) {
2426 extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension)));
2427 } else {
2428 OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1);
2429 extname = buf;
2430 }
2431 bio_out = BIO_new(BIO_s_mem());
2432 if (bio_out == NULL) {
2433 php_openssl_store_errors();
2434 RETURN_FALSE;
2435 }
2436 if (nid == NID_subject_alt_name) {
2437 if (openssl_x509v3_subjectAltName(bio_out, extension) == 0) {
2438 BIO_get_mem_ptr(bio_out, &bio_buf);
2439 add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length);
2440 } else {
2441 zend_array_destroy(Z_ARR_P(return_value));
2442 BIO_free(bio_out);
2443 if (Z_TYPE_P(zcert) != IS_RESOURCE) {
2444 X509_free(cert);
2445 }
2446 RETURN_FALSE;
2447 }
2448 }
2449 else if (X509V3_EXT_print(bio_out, extension, 0, 0)) {
2450 BIO_get_mem_ptr(bio_out, &bio_buf);
2451 add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length);
2452 } else {
2453 php_openssl_add_assoc_asn1_string(&subitem, extname, X509_EXTENSION_get_data(extension));
2454 }
2455 BIO_free(bio_out);
2456 }
2457 add_assoc_zval(return_value, "extensions", &subitem);
2458 if (Z_TYPE_P(zcert) != IS_RESOURCE) {
2459 X509_free(cert);
2460 }
2461 }
2462 /* }}} */
2463
2464 /* {{{ php_openssl_load_all_certs_from_file */
STACK_OF(X509)2465 static STACK_OF(X509) *php_openssl_load_all_certs_from_file(char *certfile)
2466 {
2467 STACK_OF(X509_INFO) *sk=NULL;
2468 STACK_OF(X509) *stack=NULL, *ret=NULL;
2469 BIO *in=NULL;
2470 X509_INFO *xi;
2471
2472 if(!(stack = sk_X509_new_null())) {
2473 php_openssl_store_errors();
2474 php_error_docref(NULL, E_ERROR, "memory allocation failure");
2475 goto end;
2476 }
2477
2478 if (php_openssl_open_base_dir_chk(certfile)) {
2479 sk_X509_free(stack);
2480 goto end;
2481 }
2482
2483 if (!(in=BIO_new_file(certfile, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY)))) {
2484 php_openssl_store_errors();
2485 php_error_docref(NULL, E_WARNING, "error opening the file, %s", certfile);
2486 sk_X509_free(stack);
2487 goto end;
2488 }
2489
2490 /* This loads from a file, a stack of x509/crl/pkey sets */
2491 if (!(sk=PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) {
2492 php_openssl_store_errors();
2493 php_error_docref(NULL, E_WARNING, "error reading the file, %s", certfile);
2494 sk_X509_free(stack);
2495 goto end;
2496 }
2497
2498 /* scan over it and pull out the certs */
2499 while (sk_X509_INFO_num(sk)) {
2500 xi=sk_X509_INFO_shift(sk);
2501 if (xi->x509 != NULL) {
2502 sk_X509_push(stack,xi->x509);
2503 xi->x509=NULL;
2504 }
2505 X509_INFO_free(xi);
2506 }
2507 if (!sk_X509_num(stack)) {
2508 php_error_docref(NULL, E_WARNING, "no certificates in file, %s", certfile);
2509 sk_X509_free(stack);
2510 goto end;
2511 }
2512 ret = stack;
2513 end:
2514 BIO_free(in);
2515 sk_X509_INFO_free(sk);
2516
2517 return ret;
2518 }
2519 /* }}} */
2520
2521 /* {{{ check_cert */
check_cert(X509_STORE * ctx,X509 * x,STACK_OF (X509)* untrustedchain,int purpose)2522 static int check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedchain, int purpose)
2523 {
2524 int ret=0;
2525 X509_STORE_CTX *csc;
2526
2527 csc = X509_STORE_CTX_new();
2528 if (csc == NULL) {
2529 php_openssl_store_errors();
2530 php_error_docref(NULL, E_ERROR, "memory allocation failure");
2531 return 0;
2532 }
2533 if (!X509_STORE_CTX_init(csc, ctx, x, untrustedchain)) {
2534 php_openssl_store_errors();
2535 php_error_docref(NULL, E_WARNING, "cert store initialization failed");
2536 return 0;
2537 }
2538 if (purpose >= 0 && !X509_STORE_CTX_set_purpose(csc, purpose)) {
2539 php_openssl_store_errors();
2540 }
2541 ret = X509_verify_cert(csc);
2542 if (ret < 0) {
2543 php_openssl_store_errors();
2544 }
2545 X509_STORE_CTX_free(csc);
2546
2547 return ret;
2548 }
2549 /* }}} */
2550
2551 /* {{{ proto int openssl_x509_checkpurpose(mixed x509cert, int purpose, array cainfo [, string untrustedfile])
2552 Checks the CERT to see if it can be used for the purpose in purpose. cainfo holds information about trusted CAs */
PHP_FUNCTION(openssl_x509_checkpurpose)2553 PHP_FUNCTION(openssl_x509_checkpurpose)
2554 {
2555 zval * zcert, * zcainfo = NULL;
2556 X509_STORE * cainfo = NULL;
2557 X509 * cert = NULL;
2558 STACK_OF(X509) * untrustedchain = NULL;
2559 zend_long purpose;
2560 char * untrusted = NULL;
2561 size_t untrusted_len = 0;
2562 int ret;
2563
2564 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl|a!s", &zcert, &purpose, &zcainfo, &untrusted, &untrusted_len) == FAILURE) {
2565 return;
2566 }
2567
2568 RETVAL_LONG(-1);
2569
2570 if (untrusted) {
2571 untrustedchain = php_openssl_load_all_certs_from_file(untrusted);
2572 if (untrustedchain == NULL) {
2573 goto clean_exit;
2574 }
2575 }
2576
2577 cainfo = php_openssl_setup_verify(zcainfo);
2578 if (cainfo == NULL) {
2579 goto clean_exit;
2580 }
2581 cert = php_openssl_x509_from_zval(zcert, 0, NULL);
2582 if (cert == NULL) {
2583 goto clean_exit;
2584 }
2585
2586 ret = check_cert(cainfo, cert, untrustedchain, (int)purpose);
2587 if (ret != 0 && ret != 1) {
2588 RETVAL_LONG(ret);
2589 } else {
2590 RETVAL_BOOL(ret);
2591 }
2592 if (Z_TYPE_P(zcert) != IS_RESOURCE) {
2593 X509_free(cert);
2594 }
2595 clean_exit:
2596 if (cainfo) {
2597 X509_STORE_free(cainfo);
2598 }
2599 if (untrustedchain) {
2600 sk_X509_pop_free(untrustedchain, X509_free);
2601 }
2602 }
2603 /* }}} */
2604
2605 /* {{{ php_openssl_setup_verify
2606 * calist is an array containing file and directory names. create a
2607 * certificate store and add those certs to it for use in verification.
2608 */
php_openssl_setup_verify(zval * calist)2609 static X509_STORE *php_openssl_setup_verify(zval *calist)
2610 {
2611 X509_STORE *store;
2612 X509_LOOKUP * dir_lookup, * file_lookup;
2613 int ndirs = 0, nfiles = 0;
2614 zval * item;
2615 zend_stat_t sb;
2616
2617 store = X509_STORE_new();
2618
2619 if (store == NULL) {
2620 php_openssl_store_errors();
2621 return NULL;
2622 }
2623
2624 if (calist && (Z_TYPE_P(calist) == IS_ARRAY)) {
2625 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(calist), item) {
2626 convert_to_string_ex(item);
2627
2628 if (VCWD_STAT(Z_STRVAL_P(item), &sb) == -1) {
2629 php_error_docref(NULL, E_WARNING, "unable to stat %s", Z_STRVAL_P(item));
2630 continue;
2631 }
2632
2633 if ((sb.st_mode & S_IFREG) == S_IFREG) {
2634 file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
2635 if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_P(item), X509_FILETYPE_PEM)) {
2636 php_openssl_store_errors();
2637 php_error_docref(NULL, E_WARNING, "error loading file %s", Z_STRVAL_P(item));
2638 } else {
2639 nfiles++;
2640 }
2641 file_lookup = NULL;
2642 } else {
2643 dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
2644 if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_P(item), X509_FILETYPE_PEM)) {
2645 php_openssl_store_errors();
2646 php_error_docref(NULL, E_WARNING, "error loading directory %s", Z_STRVAL_P(item));
2647 } else {
2648 ndirs++;
2649 }
2650 dir_lookup = NULL;
2651 }
2652 } ZEND_HASH_FOREACH_END();
2653 }
2654 if (nfiles == 0) {
2655 file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
2656 if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, NULL, X509_FILETYPE_DEFAULT)) {
2657 php_openssl_store_errors();
2658 }
2659 }
2660 if (ndirs == 0) {
2661 dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
2662 if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, NULL, X509_FILETYPE_DEFAULT)) {
2663 php_openssl_store_errors();
2664 }
2665 }
2666 return store;
2667 }
2668 /* }}} */
2669
2670 /* {{{ proto resource openssl_x509_read(mixed cert)
2671 Reads X.509 certificates */
PHP_FUNCTION(openssl_x509_read)2672 PHP_FUNCTION(openssl_x509_read)
2673 {
2674 zval *cert;
2675 X509 *x509;
2676 zend_resource *res;
2677
2678 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &cert) == FAILURE) {
2679 return;
2680 }
2681 x509 = php_openssl_x509_from_zval(cert, 1, &res);
2682 ZVAL_RES(return_value, res);
2683
2684 if (x509 == NULL) {
2685 php_error_docref(NULL, E_WARNING, "supplied parameter cannot be coerced into an X509 certificate!");
2686 RETURN_FALSE;
2687 }
2688 }
2689 /* }}} */
2690
2691 /* {{{ proto void openssl_x509_free(resource x509)
2692 Frees X.509 certificates */
PHP_FUNCTION(openssl_x509_free)2693 PHP_FUNCTION(openssl_x509_free)
2694 {
2695 zval *x509;
2696 X509 *cert;
2697
2698 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &x509) == FAILURE) {
2699 return;
2700 }
2701 if ((cert = (X509 *)zend_fetch_resource(Z_RES_P(x509), "OpenSSL X.509", le_x509)) == NULL) {
2702 RETURN_FALSE;
2703 }
2704 zend_list_close(Z_RES_P(x509));
2705 }
2706 /* }}} */
2707
2708 /* }}} */
2709
2710 /* Pop all X509 from Stack and free them, free the stack afterwards */
php_sk_X509_free(STACK_OF (X509)* sk)2711 static void php_sk_X509_free(STACK_OF(X509) * sk) /* {{{ */
2712 {
2713 for (;;) {
2714 X509* x = sk_X509_pop(sk);
2715 if (!x) break;
2716 X509_free(x);
2717 }
2718 sk_X509_free(sk);
2719 }
2720 /* }}} */
2721
STACK_OF(X509)2722 static STACK_OF(X509) * php_array_to_X509_sk(zval * zcerts) /* {{{ */
2723 {
2724 zval * zcertval;
2725 STACK_OF(X509) * sk = NULL;
2726 X509 * cert;
2727 zend_resource *certresource;
2728
2729 sk = sk_X509_new_null();
2730
2731 /* get certs */
2732 if (Z_TYPE_P(zcerts) == IS_ARRAY) {
2733 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zcerts), zcertval) {
2734 cert = php_openssl_x509_from_zval(zcertval, 0, &certresource);
2735 if (cert == NULL) {
2736 goto clean_exit;
2737 }
2738
2739 if (certresource != NULL) {
2740 cert = X509_dup(cert);
2741
2742 if (cert == NULL) {
2743 php_openssl_store_errors();
2744 goto clean_exit;
2745 }
2746
2747 }
2748 sk_X509_push(sk, cert);
2749 } ZEND_HASH_FOREACH_END();
2750 } else {
2751 /* a single certificate */
2752 cert = php_openssl_x509_from_zval(zcerts, 0, &certresource);
2753
2754 if (cert == NULL) {
2755 goto clean_exit;
2756 }
2757
2758 if (certresource != NULL) {
2759 cert = X509_dup(cert);
2760 if (cert == NULL) {
2761 php_openssl_store_errors();
2762 goto clean_exit;
2763 }
2764 }
2765 sk_X509_push(sk, cert);
2766 }
2767
2768 clean_exit:
2769 return sk;
2770 }
2771 /* }}} */
2772
2773 /* {{{ proto bool openssl_pkcs12_export_to_file(mixed x509, string filename, mixed priv_key, string pass[, array args])
2774 Creates and exports a PKCS to file */
PHP_FUNCTION(openssl_pkcs12_export_to_file)2775 PHP_FUNCTION(openssl_pkcs12_export_to_file)
2776 {
2777 X509 * cert = NULL;
2778 BIO * bio_out = NULL;
2779 PKCS12 * p12 = NULL;
2780 char * filename;
2781 char * friendly_name = NULL;
2782 size_t filename_len;
2783 char * pass;
2784 size_t pass_len;
2785 zval *zcert = NULL, *zpkey = NULL, *args = NULL;
2786 EVP_PKEY *priv_key = NULL;
2787 zend_resource *keyresource;
2788 zval * item;
2789 STACK_OF(X509) *ca = NULL;
2790
2791 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zpzs|a", &zcert, &filename, &filename_len, &zpkey, &pass, &pass_len, &args) == FAILURE)
2792 return;
2793
2794 RETVAL_FALSE;
2795
2796 cert = php_openssl_x509_from_zval(zcert, 0, NULL);
2797 if (cert == NULL) {
2798 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1");
2799 return;
2800 }
2801 priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 0, 1, &keyresource);
2802 if (priv_key == NULL) {
2803 php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3");
2804 goto cleanup;
2805 }
2806 if (!X509_check_private_key(cert, priv_key)) {
2807 php_openssl_store_errors();
2808 php_error_docref(NULL, E_WARNING, "private key does not correspond to cert");
2809 goto cleanup;
2810 }
2811 if (php_openssl_open_base_dir_chk(filename)) {
2812 goto cleanup;
2813 }
2814
2815 /* parse extra config from args array, promote this to an extra function */
2816 if (args &&
2817 (item = zend_hash_str_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name")-1)) != NULL &&
2818 Z_TYPE_P(item) == IS_STRING
2819 ) {
2820 friendly_name = Z_STRVAL_P(item);
2821 }
2822 /* certpbe (default RC2-40)
2823 keypbe (default 3DES)
2824 friendly_caname
2825 */
2826
2827 if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL) {
2828 ca = php_array_to_X509_sk(item);
2829 }
2830 /* end parse extra config */
2831
2832 /*PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert, STACK_OF(X509) *ca,
2833 int nid_key, int nid_cert, int iter, int mac_iter, int keytype);*/
2834
2835 p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
2836 if (p12 != NULL) {
2837 bio_out = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
2838 if (bio_out != NULL) {
2839
2840 i2d_PKCS12_bio(bio_out, p12);
2841 BIO_free(bio_out);
2842
2843 RETVAL_TRUE;
2844 } else {
2845 php_openssl_store_errors();
2846 php_error_docref(NULL, E_WARNING, "error opening file %s", filename);
2847 }
2848
2849 PKCS12_free(p12);
2850 } else {
2851 php_openssl_store_errors();
2852 }
2853
2854 php_sk_X509_free(ca);
2855
2856 cleanup:
2857
2858 if (keyresource == NULL && priv_key) {
2859 EVP_PKEY_free(priv_key);
2860 }
2861
2862 if (Z_TYPE_P(zcert) != IS_RESOURCE) {
2863 X509_free(cert);
2864 }
2865 }
2866 /* }}} */
2867
2868 /* {{{ proto bool openssl_pkcs12_export(mixed x509, string &out, mixed priv_key, string pass[, array args])
2869 Creates and exports a PKCS12 to a var */
PHP_FUNCTION(openssl_pkcs12_export)2870 PHP_FUNCTION(openssl_pkcs12_export)
2871 {
2872 X509 * cert = NULL;
2873 BIO * bio_out;
2874 PKCS12 * p12 = NULL;
2875 zval * zcert = NULL, *zout = NULL, *zpkey, *args = NULL;
2876 EVP_PKEY *priv_key = NULL;
2877 zend_resource *keyresource;
2878 char * pass;
2879 size_t pass_len;
2880 char * friendly_name = NULL;
2881 zval * item;
2882 STACK_OF(X509) *ca = NULL;
2883
2884 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/zs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE)
2885 return;
2886
2887 RETVAL_FALSE;
2888
2889 cert = php_openssl_x509_from_zval(zcert, 0, NULL);
2890 if (cert == NULL) {
2891 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1");
2892 return;
2893 }
2894 priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 0, 1, &keyresource);
2895 if (priv_key == NULL) {
2896 php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3");
2897 goto cleanup;
2898 }
2899 if (!X509_check_private_key(cert, priv_key)) {
2900 php_error_docref(NULL, E_WARNING, "private key does not correspond to cert");
2901 goto cleanup;
2902 }
2903
2904 /* parse extra config from args array, promote this to an extra function */
2905 if (args &&
2906 (item = zend_hash_str_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name")-1)) != NULL &&
2907 Z_TYPE_P(item) == IS_STRING
2908 ) {
2909 friendly_name = Z_STRVAL_P(item);
2910 }
2911
2912 if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL) {
2913 ca = php_array_to_X509_sk(item);
2914 }
2915 /* end parse extra config */
2916
2917 p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
2918
2919 if (p12 != NULL) {
2920 bio_out = BIO_new(BIO_s_mem());
2921 if (i2d_PKCS12_bio(bio_out, p12)) {
2922 BUF_MEM *bio_buf;
2923
2924 zval_ptr_dtor(zout);
2925 BIO_get_mem_ptr(bio_out, &bio_buf);
2926 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length);
2927
2928 RETVAL_TRUE;
2929 } else {
2930 php_openssl_store_errors();
2931 }
2932
2933 BIO_free(bio_out);
2934 PKCS12_free(p12);
2935 } else {
2936 php_openssl_store_errors();
2937 }
2938 php_sk_X509_free(ca);
2939
2940 cleanup:
2941
2942 if (keyresource == NULL && priv_key) {
2943 EVP_PKEY_free(priv_key);
2944 }
2945 if (Z_TYPE_P(zcert) != IS_RESOURCE) {
2946 X509_free(cert);
2947 }
2948 }
2949 /* }}} */
2950
2951 /* {{{ proto bool openssl_pkcs12_read(string PKCS12, array &certs, string pass)
2952 Parses a PKCS12 to an array */
PHP_FUNCTION(openssl_pkcs12_read)2953 PHP_FUNCTION(openssl_pkcs12_read)
2954 {
2955 zval *zout = NULL, zextracerts, zcert, zpkey;
2956 char *pass, *zp12;
2957 size_t pass_len, zp12_len;
2958 PKCS12 * p12 = NULL;
2959 EVP_PKEY * pkey = NULL;
2960 X509 * cert = NULL;
2961 STACK_OF(X509) * ca = NULL;
2962 BIO * bio_in = NULL;
2963 int i;
2964
2965 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/s", &zp12, &zp12_len, &zout, &pass, &pass_len) == FAILURE)
2966 return;
2967
2968 RETVAL_FALSE;
2969
2970 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(zp12_len, pkcs12);
2971
2972 bio_in = BIO_new(BIO_s_mem());
2973
2974 if (0 >= BIO_write(bio_in, zp12, (int)zp12_len)) {
2975 php_openssl_store_errors();
2976 goto cleanup;
2977 }
2978
2979 if (d2i_PKCS12_bio(bio_in, &p12) && PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
2980 BIO * bio_out;
2981 int cert_num;
2982
2983 zval_ptr_dtor(zout);
2984 array_init(zout);
2985
2986 if (cert) {
2987 bio_out = BIO_new(BIO_s_mem());
2988 if (PEM_write_bio_X509(bio_out, cert)) {
2989 BUF_MEM *bio_buf;
2990 BIO_get_mem_ptr(bio_out, &bio_buf);
2991 ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
2992 add_assoc_zval(zout, "cert", &zcert);
2993 } else {
2994 php_openssl_store_errors();
2995 }
2996 BIO_free(bio_out);
2997 }
2998
2999 if (pkey) {
3000 bio_out = BIO_new(BIO_s_mem());
3001 if (PEM_write_bio_PrivateKey(bio_out, pkey, NULL, NULL, 0, 0, NULL)) {
3002 BUF_MEM *bio_buf;
3003 BIO_get_mem_ptr(bio_out, &bio_buf);
3004 ZVAL_STRINGL(&zpkey, bio_buf->data, bio_buf->length);
3005 add_assoc_zval(zout, "pkey", &zpkey);
3006 } else {
3007 php_openssl_store_errors();
3008 }
3009 BIO_free(bio_out);
3010 }
3011
3012 cert_num = sk_X509_num(ca);
3013 if (ca && cert_num) {
3014 array_init(&zextracerts);
3015
3016 for (i = 0; i < cert_num; i++) {
3017 zval zextracert;
3018 X509* aCA = sk_X509_pop(ca);
3019 if (!aCA) break;
3020
3021 bio_out = BIO_new(BIO_s_mem());
3022 if (PEM_write_bio_X509(bio_out, aCA)) {
3023 BUF_MEM *bio_buf;
3024 BIO_get_mem_ptr(bio_out, &bio_buf);
3025 ZVAL_STRINGL(&zextracert, bio_buf->data, bio_buf->length);
3026 add_index_zval(&zextracerts, i, &zextracert);
3027 }
3028
3029 X509_free(aCA);
3030 BIO_free(bio_out);
3031 }
3032
3033 sk_X509_free(ca);
3034 add_assoc_zval(zout, "extracerts", &zextracerts);
3035 }
3036
3037 RETVAL_TRUE;
3038 } else {
3039 php_openssl_store_errors();
3040 }
3041
3042 cleanup:
3043 if (bio_in) {
3044 BIO_free(bio_in);
3045 }
3046 if (pkey) {
3047 EVP_PKEY_free(pkey);
3048 }
3049 if (cert) {
3050 X509_free(cert);
3051 }
3052 if (p12) {
3053 PKCS12_free(p12);
3054 }
3055 }
3056 /* }}} */
3057
3058 /* {{{ x509 CSR functions */
3059
3060 /* {{{ php_openssl_make_REQ */
php_openssl_make_REQ(struct php_x509_request * req,X509_REQ * csr,zval * dn,zval * attribs)3061 static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, zval * dn, zval * attribs)
3062 {
3063 STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL;
3064 char * str, *dn_sect, *attr_sect;
3065
3066 dn_sect = CONF_get_string(req->req_config, req->section_name, "distinguished_name");
3067 if (dn_sect == NULL) {
3068 php_openssl_store_errors();
3069 return FAILURE;
3070 }
3071 dn_sk = CONF_get_section(req->req_config, dn_sect);
3072 if (dn_sk == NULL) {
3073 php_openssl_store_errors();
3074 return FAILURE;
3075 }
3076 attr_sect = CONF_get_string(req->req_config, req->section_name, "attributes");
3077 if (attr_sect == NULL) {
3078 php_openssl_store_errors();
3079 attr_sk = NULL;
3080 } else {
3081 attr_sk = CONF_get_section(req->req_config, attr_sect);
3082 if (attr_sk == NULL) {
3083 php_openssl_store_errors();
3084 return FAILURE;
3085 }
3086 }
3087 /* setup the version number: version 1 */
3088 if (X509_REQ_set_version(csr, 0L)) {
3089 int i, nid;
3090 char * type;
3091 CONF_VALUE * v;
3092 X509_NAME * subj;
3093 zval * item;
3094 zend_string * strindex = NULL;
3095
3096 subj = X509_REQ_get_subject_name(csr);
3097 /* apply values from the dn hash */
3098 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(dn), strindex, item) {
3099 if (strindex) {
3100 int nid;
3101
3102 convert_to_string_ex(item);
3103
3104 nid = OBJ_txt2nid(ZSTR_VAL(strindex));
3105 if (nid != NID_undef) {
3106 if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8,
3107 (unsigned char*)Z_STRVAL_P(item), -1, -1, 0))
3108 {
3109 php_openssl_store_errors();
3110 php_error_docref(NULL, E_WARNING,
3111 "dn: add_entry_by_NID %d -> %s (failed; check error"
3112 " queue and value of string_mask OpenSSL option "
3113 "if illegal characters are reported)",
3114 nid, Z_STRVAL_P(item));
3115 return FAILURE;
3116 }
3117 } else {
3118 php_error_docref(NULL, E_WARNING, "dn: %s is not a recognized name", ZSTR_VAL(strindex));
3119 }
3120 }
3121 } ZEND_HASH_FOREACH_END();
3122
3123 /* Finally apply defaults from config file */
3124 for(i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) {
3125 size_t len;
3126 char buffer[200 + 1]; /*200 + \0 !*/
3127
3128 v = sk_CONF_VALUE_value(dn_sk, i);
3129 type = v->name;
3130
3131 len = strlen(type);
3132 if (len < sizeof("_default")) {
3133 continue;
3134 }
3135 len -= sizeof("_default") - 1;
3136 if (strcmp("_default", type + len) != 0) {
3137 continue;
3138 }
3139 if (len > 200) {
3140 len = 200;
3141 }
3142 memcpy(buffer, type, len);
3143 buffer[len] = '\0';
3144 type = buffer;
3145
3146 /* Skip past any leading X. X: X, etc to allow for multiple
3147 * instances */
3148 for (str = type; *str; str++) {
3149 if (*str == ':' || *str == ',' || *str == '.') {
3150 str++;
3151 if (*str) {
3152 type = str;
3153 }
3154 break;
3155 }
3156 }
3157 /* if it is already set, skip this */
3158 nid = OBJ_txt2nid(type);
3159 if (X509_NAME_get_index_by_NID(subj, nid, -1) >= 0) {
3160 continue;
3161 }
3162 if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_UTF8, (unsigned char*)v->value, -1, -1, 0)) {
3163 php_openssl_store_errors();
3164 php_error_docref(NULL, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value);
3165 return FAILURE;
3166 }
3167 if (!X509_NAME_entry_count(subj)) {
3168 php_error_docref(NULL, E_WARNING, "no objects specified in config file");
3169 return FAILURE;
3170 }
3171 }
3172 if (attribs) {
3173 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(attribs), strindex, item) {
3174 int nid;
3175
3176 if (NULL == strindex) {
3177 php_error_docref(NULL, E_WARNING, "dn: numeric fild names are not supported");
3178 continue;
3179 }
3180
3181 convert_to_string_ex(item);
3182
3183 nid = OBJ_txt2nid(ZSTR_VAL(strindex));
3184 if (nid != NID_undef) {
3185 if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, (unsigned char*)Z_STRVAL_P(item), -1, -1, 0)) {
3186 php_openssl_store_errors();
3187 php_error_docref(NULL, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_P(item));
3188 return FAILURE;
3189 }
3190 } else {
3191 php_error_docref(NULL, E_WARNING, "dn: %s is not a recognized name", ZSTR_VAL(strindex));
3192 }
3193 } ZEND_HASH_FOREACH_END();
3194 for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) {
3195 v = sk_CONF_VALUE_value(attr_sk, i);
3196 /* if it is already set, skip this */
3197 nid = OBJ_txt2nid(v->name);
3198 if (X509_REQ_get_attr_by_NID(csr, nid, -1) >= 0) {
3199 continue;
3200 }
3201 if (!X509_REQ_add1_attr_by_txt(csr, v->name, MBSTRING_UTF8, (unsigned char*)v->value, -1)) {
3202 php_openssl_store_errors();
3203 php_error_docref(NULL, E_WARNING,
3204 "add1_attr_by_txt %s -> %s (failed; check error queue "
3205 "and value of string_mask OpenSSL option if illegal "
3206 "characters are reported)",
3207 v->name, v->value);
3208 return FAILURE;
3209 }
3210 }
3211 }
3212 } else {
3213 php_openssl_store_errors();
3214 }
3215
3216 if (!X509_REQ_set_pubkey(csr, req->priv_key)) {
3217 php_openssl_store_errors();
3218 }
3219 return SUCCESS;
3220 }
3221 /* }}} */
3222
3223 /* {{{ php_openssl_csr_from_zval */
php_openssl_csr_from_zval(zval * val,int makeresource,zend_resource ** resourceval)3224 static X509_REQ * php_openssl_csr_from_zval(zval * val, int makeresource, zend_resource **resourceval)
3225 {
3226 X509_REQ * csr = NULL;
3227 char * filename = NULL;
3228 BIO * in;
3229
3230 if (resourceval) {
3231 *resourceval = NULL;
3232 }
3233 if (Z_TYPE_P(val) == IS_RESOURCE) {
3234 void * what;
3235 zend_resource *res = Z_RES_P(val);
3236
3237 what = zend_fetch_resource(res, "OpenSSL X.509 CSR", le_csr);
3238 if (what) {
3239 if (resourceval) {
3240 *resourceval = res;
3241 if (makeresource) {
3242 Z_ADDREF_P(val);
3243 }
3244 }
3245 return (X509_REQ*)what;
3246 }
3247 return NULL;
3248 } else if (Z_TYPE_P(val) != IS_STRING) {
3249 return NULL;
3250 }
3251
3252 if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) {
3253 filename = Z_STRVAL_P(val) + (sizeof("file://") - 1);
3254 }
3255 if (filename) {
3256 if (php_openssl_open_base_dir_chk(filename)) {
3257 return NULL;
3258 }
3259 in = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
3260 } else {
3261 in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val));
3262 }
3263
3264 if (in == NULL) {
3265 php_openssl_store_errors();
3266 return NULL;
3267 }
3268
3269 csr = PEM_read_bio_X509_REQ(in, NULL,NULL,NULL);
3270 if (csr == NULL) {
3271 php_openssl_store_errors();
3272 }
3273
3274 BIO_free(in);
3275
3276 return csr;
3277 }
3278 /* }}} */
3279
3280 /* {{{ proto bool openssl_csr_export_to_file(resource csr, string outfilename [, bool notext=true])
3281 Exports a CSR to file */
PHP_FUNCTION(openssl_csr_export_to_file)3282 PHP_FUNCTION(openssl_csr_export_to_file)
3283 {
3284 X509_REQ * csr;
3285 zval * zcsr = NULL;
3286 zend_bool notext = 1;
3287 char * filename = NULL;
3288 size_t filename_len;
3289 BIO * bio_out;
3290 zend_resource *csr_resource;
3291
3292 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rp|b", &zcsr, &filename, &filename_len, ¬ext) == FAILURE) {
3293 return;
3294 }
3295 RETVAL_FALSE;
3296
3297 csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource);
3298 if (csr == NULL) {
3299 php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1");
3300 return;
3301 }
3302
3303 if (php_openssl_open_base_dir_chk(filename)) {
3304 return;
3305 }
3306
3307 bio_out = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
3308 if (bio_out != NULL) {
3309 if (!notext && !X509_REQ_print(bio_out, csr)) {
3310 php_openssl_store_errors();
3311 }
3312 if (!PEM_write_bio_X509_REQ(bio_out, csr)) {
3313 php_error_docref(NULL, E_WARNING, "error writing PEM to file %s", filename);
3314 php_openssl_store_errors();
3315 } else {
3316 RETVAL_TRUE;
3317 }
3318 BIO_free(bio_out);
3319 } else {
3320 php_openssl_store_errors();
3321 php_error_docref(NULL, E_WARNING, "error opening file %s", filename);
3322 }
3323
3324 if (csr_resource == NULL && csr != NULL) {
3325 X509_REQ_free(csr);
3326 }
3327 }
3328 /* }}} */
3329
3330 /* {{{ proto bool openssl_csr_export(resource csr, string &out [, bool notext=true])
3331 Exports a CSR to file or a var */
PHP_FUNCTION(openssl_csr_export)3332 PHP_FUNCTION(openssl_csr_export)
3333 {
3334 X509_REQ * csr;
3335 zval * zcsr = NULL, *zout=NULL;
3336 zend_bool notext = 1;
3337 BIO * bio_out;
3338 zend_resource *csr_resource;
3339
3340 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|b", &zcsr, &zout, ¬ext) == FAILURE) {
3341 return;
3342 }
3343
3344 RETVAL_FALSE;
3345
3346 csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource);
3347 if (csr == NULL) {
3348 php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1");
3349 return;
3350 }
3351
3352 /* export to a var */
3353
3354 bio_out = BIO_new(BIO_s_mem());
3355 if (!notext && !X509_REQ_print(bio_out, csr)) {
3356 php_openssl_store_errors();
3357 }
3358
3359 if (PEM_write_bio_X509_REQ(bio_out, csr)) {
3360 BUF_MEM *bio_buf;
3361
3362 BIO_get_mem_ptr(bio_out, &bio_buf);
3363 zval_ptr_dtor(zout);
3364 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length);
3365
3366 RETVAL_TRUE;
3367 } else {
3368 php_openssl_store_errors();
3369 }
3370
3371 if (csr_resource == NULL && csr) {
3372 X509_REQ_free(csr);
3373 }
3374 BIO_free(bio_out);
3375 }
3376 /* }}} */
3377
3378 /* {{{ proto resource openssl_csr_sign(mixed csr, mixed x509, mixed priv_key, int days [, array config_args [, int serial]])
3379 Signs a cert with another CERT */
PHP_FUNCTION(openssl_csr_sign)3380 PHP_FUNCTION(openssl_csr_sign)
3381 {
3382 zval * zcert = NULL, *zcsr, *zpkey, *args = NULL;
3383 zend_long num_days;
3384 zend_long serial = Z_L(0);
3385 X509 * cert = NULL, *new_cert = NULL;
3386 X509_REQ * csr;
3387 EVP_PKEY * key = NULL, *priv_key = NULL;
3388 zend_resource *csr_resource, *certresource = NULL, *keyresource = NULL;
3389 int i;
3390 struct php_x509_request req;
3391
3392 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz!zl|a!l", &zcsr, &zcert, &zpkey, &num_days, &args, &serial) == FAILURE)
3393 return;
3394
3395 RETVAL_FALSE;
3396 PHP_SSL_REQ_INIT(&req);
3397
3398 csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource);
3399 if (csr == NULL) {
3400 php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1");
3401 return;
3402 }
3403 if (zcert) {
3404 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
3405 if (cert == NULL) {
3406 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 2");
3407 goto cleanup;
3408 }
3409 }
3410 priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 0, 1, &keyresource);
3411 if (priv_key == NULL) {
3412 php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3");
3413 goto cleanup;
3414 }
3415 if (cert && !X509_check_private_key(cert, priv_key)) {
3416 php_openssl_store_errors();
3417 php_error_docref(NULL, E_WARNING, "private key does not correspond to signing cert");
3418 goto cleanup;
3419 }
3420
3421 if (PHP_SSL_REQ_PARSE(&req, args) == FAILURE) {
3422 goto cleanup;
3423 }
3424 /* Check that the request matches the signature */
3425 key = X509_REQ_get_pubkey(csr);
3426 if (key == NULL) {
3427 php_openssl_store_errors();
3428 php_error_docref(NULL, E_WARNING, "error unpacking public key");
3429 goto cleanup;
3430 }
3431 i = X509_REQ_verify(csr, key);
3432
3433 if (i < 0) {
3434 php_openssl_store_errors();
3435 php_error_docref(NULL, E_WARNING, "Signature verification problems");
3436 goto cleanup;
3437 }
3438 else if (i == 0) {
3439 php_error_docref(NULL, E_WARNING, "Signature did not match the certificate request");
3440 goto cleanup;
3441 }
3442
3443 /* Now we can get on with it */
3444
3445 new_cert = X509_new();
3446 if (new_cert == NULL) {
3447 php_openssl_store_errors();
3448 php_error_docref(NULL, E_WARNING, "No memory");
3449 goto cleanup;
3450 }
3451 /* Version 3 cert */
3452 if (!X509_set_version(new_cert, 2)) {
3453 goto cleanup;
3454 }
3455
3456
3457 ASN1_INTEGER_set(X509_get_serialNumber(new_cert), (long)serial);
3458
3459 X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr));
3460
3461 if (cert == NULL) {
3462 cert = new_cert;
3463 }
3464 if (!X509_set_issuer_name(new_cert, X509_get_subject_name(cert))) {
3465 php_openssl_store_errors();
3466 goto cleanup;
3467 }
3468 X509_gmtime_adj(X509_get_notBefore(new_cert), 0);
3469 X509_gmtime_adj(X509_get_notAfter(new_cert), 60*60*24*(long)num_days);
3470 i = X509_set_pubkey(new_cert, key);
3471 if (!i) {
3472 php_openssl_store_errors();
3473 goto cleanup;
3474 }
3475 if (req.extensions_section) {
3476 X509V3_CTX ctx;
3477
3478 X509V3_set_ctx(&ctx, cert, new_cert, csr, NULL, 0);
3479 X509V3_set_conf_lhash(&ctx, req.req_config);
3480 if (!X509V3_EXT_add_conf(req.req_config, &ctx, req.extensions_section, new_cert)) {
3481 php_openssl_store_errors();
3482 goto cleanup;
3483 }
3484 }
3485
3486 /* Now sign it */
3487 if (!X509_sign(new_cert, priv_key, req.digest)) {
3488 php_openssl_store_errors();
3489 php_error_docref(NULL, E_WARNING, "failed to sign it");
3490 goto cleanup;
3491 }
3492
3493 /* Succeeded; lets return the cert */
3494 ZVAL_RES(return_value, zend_register_resource(new_cert, le_x509));
3495 new_cert = NULL;
3496
3497 cleanup:
3498
3499 if (cert == new_cert) {
3500 cert = NULL;
3501 }
3502 PHP_SSL_REQ_DISPOSE(&req);
3503
3504 if (keyresource == NULL && priv_key) {
3505 EVP_PKEY_free(priv_key);
3506 }
3507 if (key) {
3508 EVP_PKEY_free(key);
3509 }
3510 if (csr_resource == NULL && csr) {
3511 X509_REQ_free(csr);
3512 }
3513 if (zcert && certresource == NULL && cert) {
3514 X509_free(cert);
3515 }
3516 if (new_cert) {
3517 X509_free(new_cert);
3518 }
3519 }
3520 /* }}} */
3521
3522 /* {{{ proto bool openssl_csr_new(array dn, resource &privkey [, array configargs [, array extraattribs]])
3523 Generates a privkey and CSR */
PHP_FUNCTION(openssl_csr_new)3524 PHP_FUNCTION(openssl_csr_new)
3525 {
3526 struct php_x509_request req;
3527 zval * args = NULL, * dn, *attribs = NULL;
3528 zval * out_pkey;
3529 X509_REQ * csr = NULL;
3530 int we_made_the_key = 1;
3531 zend_resource *key_resource;
3532
3533 if (zend_parse_parameters(ZEND_NUM_ARGS(), "az/|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) {
3534 return;
3535 }
3536 RETVAL_FALSE;
3537
3538 PHP_SSL_REQ_INIT(&req);
3539
3540 if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
3541 /* Generate or use a private key */
3542 if (Z_TYPE_P(out_pkey) != IS_NULL) {
3543 req.priv_key = php_openssl_evp_from_zval(out_pkey, 0, NULL, 0, 0, &key_resource);
3544 if (req.priv_key != NULL) {
3545 we_made_the_key = 0;
3546 }
3547 }
3548 if (req.priv_key == NULL) {
3549 php_openssl_generate_private_key(&req);
3550 }
3551 if (req.priv_key == NULL) {
3552 php_error_docref(NULL, E_WARNING, "Unable to generate a private key");
3553 } else {
3554 csr = X509_REQ_new();
3555 if (csr) {
3556 if (php_openssl_make_REQ(&req, csr, dn, attribs) == SUCCESS) {
3557 X509V3_CTX ext_ctx;
3558
3559 X509V3_set_ctx(&ext_ctx, NULL, NULL, csr, NULL, 0);
3560 X509V3_set_conf_lhash(&ext_ctx, req.req_config);
3561
3562 /* Add extensions */
3563 if (req.request_extensions_section && !X509V3_EXT_REQ_add_conf(req.req_config,
3564 &ext_ctx, req.request_extensions_section, csr))
3565 {
3566 php_openssl_store_errors();
3567 php_error_docref(NULL, E_WARNING, "Error loading extension section %s", req.request_extensions_section);
3568 } else {
3569 RETVAL_TRUE;
3570
3571 if (X509_REQ_sign(csr, req.priv_key, req.digest)) {
3572 ZVAL_RES(return_value, zend_register_resource(csr, le_csr));
3573 csr = NULL;
3574 } else {
3575 php_openssl_store_errors();
3576 php_error_docref(NULL, E_WARNING, "Error signing request");
3577 }
3578
3579 if (we_made_the_key) {
3580 /* and a resource for the private key */
3581 zval_ptr_dtor(out_pkey);
3582 ZVAL_RES(out_pkey, zend_register_resource(req.priv_key, le_key));
3583 req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */
3584 } else if (key_resource != NULL) {
3585 req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */
3586 }
3587 }
3588 }
3589 else {
3590 if (!we_made_the_key) {
3591 /* if we have not made the key we are not supposed to zap it by calling dispose! */
3592 req.priv_key = NULL;
3593 }
3594 }
3595 } else {
3596 php_openssl_store_errors();
3597 }
3598
3599 }
3600 }
3601 if (csr) {
3602 X509_REQ_free(csr);
3603 }
3604 PHP_SSL_REQ_DISPOSE(&req);
3605 }
3606 /* }}} */
3607
3608 /* {{{ proto mixed openssl_csr_get_subject(mixed csr)
3609 Returns the subject of a CERT or FALSE on error */
PHP_FUNCTION(openssl_csr_get_subject)3610 PHP_FUNCTION(openssl_csr_get_subject)
3611 {
3612 zval * zcsr;
3613 zend_bool use_shortnames = 1;
3614 zend_resource *csr_resource;
3615 X509_NAME * subject;
3616 X509_REQ * csr;
3617
3618 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcsr, &use_shortnames) == FAILURE) {
3619 return;
3620 }
3621
3622 csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource);
3623
3624 if (csr == NULL) {
3625 RETURN_FALSE;
3626 }
3627
3628 subject = X509_REQ_get_subject_name(csr);
3629
3630 array_init(return_value);
3631 php_openssl_add_assoc_name_entry(return_value, NULL, subject, use_shortnames);
3632
3633 if (!csr_resource) {
3634 X509_REQ_free(csr);
3635 }
3636 }
3637 /* }}} */
3638
3639 /* {{{ proto mixed openssl_csr_get_public_key(mixed csr)
3640 Returns the subject of a CERT or FALSE on error */
PHP_FUNCTION(openssl_csr_get_public_key)3641 PHP_FUNCTION(openssl_csr_get_public_key)
3642 {
3643 zval * zcsr;
3644 zend_bool use_shortnames = 1;
3645 zend_resource *csr_resource;
3646
3647 X509_REQ *orig_csr, *csr;
3648 EVP_PKEY *tpubkey;
3649
3650 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcsr, &use_shortnames) == FAILURE) {
3651 return;
3652 }
3653
3654 orig_csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource);
3655
3656 if (orig_csr == NULL) {
3657 RETURN_FALSE;
3658 }
3659
3660 #if PHP_OPENSSL_API_VERSION >= 0x10100
3661 /* Due to changes in OpenSSL 1.1 related to locking when decoding CSR,
3662 * the pub key is not changed after assigning. It means if we pass
3663 * a private key, it will be returned including the private part.
3664 * If we duplicate it, then we get just the public part which is
3665 * the same behavior as for OpenSSL 1.0 */
3666 csr = X509_REQ_dup(orig_csr);
3667 #else
3668 csr = orig_csr;
3669 #endif
3670
3671 /* Retrieve the public key from the CSR */
3672 tpubkey = X509_REQ_get_pubkey(csr);
3673
3674 if (csr != orig_csr) {
3675 /* We need to free the duplicated CSR */
3676 X509_REQ_free(csr);
3677 }
3678
3679 if (!csr_resource) {
3680 /* We also need to free the original CSR if it was freshly created */
3681 X509_REQ_free(orig_csr);
3682 }
3683
3684 if (tpubkey == NULL) {
3685 php_openssl_store_errors();
3686 RETURN_FALSE;
3687 }
3688
3689 RETURN_RES(zend_register_resource(tpubkey, le_key));
3690 }
3691 /* }}} */
3692
3693 /* }}} */
3694
3695 /* {{{ EVP Public/Private key functions */
3696
3697 struct php_openssl_pem_password {
3698 char *key;
3699 int len;
3700 };
3701
3702 /* {{{ php_openssl_pem_password_cb */
php_openssl_pem_password_cb(char * buf,int size,int rwflag,void * userdata)3703 static int php_openssl_pem_password_cb(char *buf, int size, int rwflag, void *userdata)
3704 {
3705 struct php_openssl_pem_password *password = userdata;
3706
3707 if (password == NULL || password->key == NULL) {
3708 return -1;
3709 }
3710
3711 size = (password->len > size) ? size : password->len;
3712 memcpy(buf, password->key, size);
3713
3714 return size;
3715 }
3716 /* }}} */
3717
3718 /* {{{ php_openssl_evp_from_zval
3719 Given a zval, coerce it into a EVP_PKEY object.
3720 It can be:
3721 1. private key resource from openssl_get_privatekey()
3722 2. X509 resource -> public key will be extracted from it
3723 3. if it starts with file:// interpreted as path to key file
3724 4. interpreted as the data from the cert/key file and interpreted in same way as openssl_get_privatekey()
3725 5. an array(0 => [items 2..4], 1 => passphrase)
3726 6. if val is a string (possibly starting with file:///) and it is not an X509 certificate, then interpret as public key
3727 NOTE: If you are requesting a private key but have not specified a passphrase, you should use an
3728 empty string rather than NULL for the passphrase - NULL causes a passphrase prompt to be emitted in
3729 the Apache error log!
3730 */
php_openssl_evp_from_zval(zval * val,int public_key,char * passphrase,size_t passphrase_len,int makeresource,zend_resource ** resourceval)3731 static EVP_PKEY * php_openssl_evp_from_zval(
3732 zval * val, int public_key, char *passphrase, size_t passphrase_len,
3733 int makeresource, zend_resource **resourceval)
3734 {
3735 EVP_PKEY * key = NULL;
3736 X509 * cert = NULL;
3737 int free_cert = 0;
3738 zend_resource *cert_res = NULL;
3739 char * filename = NULL;
3740 zval tmp;
3741
3742 ZVAL_NULL(&tmp);
3743
3744 #define TMP_CLEAN \
3745 if (Z_TYPE(tmp) == IS_STRING) {\
3746 zval_ptr_dtor_str(&tmp); \
3747 } \
3748 return NULL;
3749
3750 if (resourceval) {
3751 *resourceval = NULL;
3752 }
3753 if (Z_TYPE_P(val) == IS_ARRAY) {
3754 zval * zphrase;
3755
3756 /* get passphrase */
3757
3758 if ((zphrase = zend_hash_index_find(Z_ARRVAL_P(val), 1)) == NULL) {
3759 php_error_docref(NULL, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)");
3760 return NULL;
3761 }
3762
3763 if (Z_TYPE_P(zphrase) == IS_STRING) {
3764 passphrase = Z_STRVAL_P(zphrase);
3765 passphrase_len = Z_STRLEN_P(zphrase);
3766 } else {
3767 ZVAL_COPY(&tmp, zphrase);
3768 convert_to_string(&tmp);
3769 passphrase = Z_STRVAL(tmp);
3770 passphrase_len = Z_STRLEN(tmp);
3771 }
3772
3773 /* now set val to be the key param and continue */
3774 if ((val = zend_hash_index_find(Z_ARRVAL_P(val), 0)) == NULL) {
3775 php_error_docref(NULL, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)");
3776 TMP_CLEAN;
3777 }
3778 }
3779
3780 if (Z_TYPE_P(val) == IS_RESOURCE) {
3781 void * what;
3782 zend_resource * res = Z_RES_P(val);
3783
3784 what = zend_fetch_resource2(res, "OpenSSL X.509/key", le_x509, le_key);
3785 if (!what) {
3786 TMP_CLEAN;
3787 }
3788 if (resourceval) {
3789 *resourceval = res;
3790 Z_ADDREF_P(val);
3791 }
3792 if (res->type == le_x509) {
3793 /* extract key from cert, depending on public_key param */
3794 cert = (X509*)what;
3795 free_cert = 0;
3796 } else if (res->type == le_key) {
3797 int is_priv;
3798
3799 is_priv = php_openssl_is_private_key((EVP_PKEY*)what);
3800
3801 /* check whether it is actually a private key if requested */
3802 if (!public_key && !is_priv) {
3803 php_error_docref(NULL, E_WARNING, "supplied key param is a public key");
3804 TMP_CLEAN;
3805 }
3806
3807 if (public_key && is_priv) {
3808 php_error_docref(NULL, E_WARNING, "Don't know how to get public key from this private key");
3809 TMP_CLEAN;
3810 } else {
3811 if (Z_TYPE(tmp) == IS_STRING) {
3812 zval_ptr_dtor_str(&tmp);
3813 }
3814 /* got the key - return it */
3815 return (EVP_PKEY*)what;
3816 }
3817 } else {
3818 /* other types could be used here - eg: file pointers and read in the data from them */
3819 TMP_CLEAN;
3820 }
3821 } else {
3822 /* force it to be a string and check if it refers to a file */
3823 /* passing non string values leaks, object uses toString, it returns NULL
3824 * See bug38255.phpt
3825 */
3826 if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) {
3827 TMP_CLEAN;
3828 }
3829 convert_to_string_ex(val);
3830
3831 if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) {
3832 filename = Z_STRVAL_P(val) + (sizeof("file://") - 1);
3833 if (php_openssl_open_base_dir_chk(filename)) {
3834 TMP_CLEAN;
3835 }
3836 }
3837 /* it's an X509 file/cert of some kind, and we need to extract the data from that */
3838 if (public_key) {
3839 cert = php_openssl_x509_from_zval(val, 0, &cert_res);
3840 free_cert = (cert_res == NULL);
3841 /* actual extraction done later */
3842 if (!cert) {
3843 /* not a X509 certificate, try to retrieve public key */
3844 BIO* in;
3845 if (filename) {
3846 in = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
3847 } else {
3848 in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val));
3849 }
3850 if (in == NULL) {
3851 php_openssl_store_errors();
3852 TMP_CLEAN;
3853 }
3854 key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
3855 BIO_free(in);
3856 }
3857 } else {
3858 /* we want the private key */
3859 BIO *in;
3860
3861 if (filename) {
3862 in = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
3863 } else {
3864 in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val));
3865 }
3866
3867 if (in == NULL) {
3868 TMP_CLEAN;
3869 }
3870 if (passphrase == NULL) {
3871 key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
3872 } else {
3873 struct php_openssl_pem_password password;
3874 password.key = passphrase;
3875 password.len = passphrase_len;
3876 key = PEM_read_bio_PrivateKey(in, NULL, php_openssl_pem_password_cb, &password);
3877 }
3878 BIO_free(in);
3879 }
3880 }
3881
3882 if (key == NULL) {
3883 php_openssl_store_errors();
3884
3885 if (public_key && cert) {
3886 /* extract public key from X509 cert */
3887 key = (EVP_PKEY *) X509_get_pubkey(cert);
3888 if (key == NULL) {
3889 php_openssl_store_errors();
3890 }
3891 }
3892 }
3893
3894 if (free_cert && cert) {
3895 X509_free(cert);
3896 }
3897 if (key && makeresource && resourceval) {
3898 *resourceval = zend_register_resource(key, le_key);
3899 }
3900 if (Z_TYPE(tmp) == IS_STRING) {
3901 zval_ptr_dtor_str(&tmp);
3902 }
3903 return key;
3904 }
3905 /* }}} */
3906
3907 /* {{{ php_openssl_generate_private_key */
php_openssl_generate_private_key(struct php_x509_request * req)3908 static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req)
3909 {
3910 char * randfile = NULL;
3911 int egdsocket, seeded;
3912 EVP_PKEY * return_val = NULL;
3913
3914 if (req->priv_key_bits < MIN_KEY_LENGTH) {
3915 php_error_docref(NULL, E_WARNING, "private key length is too short; it needs to be at least %d bits, not %d",
3916 MIN_KEY_LENGTH, req->priv_key_bits);
3917 return NULL;
3918 }
3919
3920 randfile = CONF_get_string(req->req_config, req->section_name, "RANDFILE");
3921 if (randfile == NULL) {
3922 php_openssl_store_errors();
3923 }
3924 php_openssl_load_rand_file(randfile, &egdsocket, &seeded);
3925
3926 if ((req->priv_key = EVP_PKEY_new()) != NULL) {
3927 switch(req->priv_key_type) {
3928 case OPENSSL_KEYTYPE_RSA:
3929 {
3930 RSA* rsaparam;
3931 #if OPENSSL_VERSION_NUMBER < 0x10002000L
3932 /* OpenSSL 1.0.2 deprecates RSA_generate_key */
3933 PHP_OPENSSL_RAND_ADD_TIME();
3934 rsaparam = (RSA*)RSA_generate_key(req->priv_key_bits, RSA_F4, NULL, NULL);
3935 #else
3936 {
3937 BIGNUM *bne = (BIGNUM *)BN_new();
3938 if (BN_set_word(bne, RSA_F4) != 1) {
3939 BN_free(bne);
3940 php_error_docref(NULL, E_WARNING, "failed setting exponent");
3941 return NULL;
3942 }
3943 rsaparam = RSA_new();
3944 PHP_OPENSSL_RAND_ADD_TIME();
3945 if (rsaparam == NULL || !RSA_generate_key_ex(rsaparam, req->priv_key_bits, bne, NULL)) {
3946 php_openssl_store_errors();
3947 }
3948 BN_free(bne);
3949 }
3950 #endif
3951 if (rsaparam && EVP_PKEY_assign_RSA(req->priv_key, rsaparam)) {
3952 return_val = req->priv_key;
3953 } else {
3954 php_openssl_store_errors();
3955 }
3956 }
3957 break;
3958 #if !defined(NO_DSA)
3959 case OPENSSL_KEYTYPE_DSA:
3960 PHP_OPENSSL_RAND_ADD_TIME();
3961 {
3962 DSA *dsaparam = DSA_new();
3963 if (dsaparam && DSA_generate_parameters_ex(dsaparam, req->priv_key_bits, NULL, 0, NULL, NULL, NULL)) {
3964 DSA_set_method(dsaparam, DSA_get_default_method());
3965 if (DSA_generate_key(dsaparam)) {
3966 if (EVP_PKEY_assign_DSA(req->priv_key, dsaparam)) {
3967 return_val = req->priv_key;
3968 } else {
3969 php_openssl_store_errors();
3970 }
3971 } else {
3972 php_openssl_store_errors();
3973 DSA_free(dsaparam);
3974 }
3975 } else {
3976 php_openssl_store_errors();
3977 }
3978 }
3979 break;
3980 #endif
3981 #if !defined(NO_DH)
3982 case OPENSSL_KEYTYPE_DH:
3983 PHP_OPENSSL_RAND_ADD_TIME();
3984 {
3985 int codes = 0;
3986 DH *dhparam = DH_new();
3987 if (dhparam && DH_generate_parameters_ex(dhparam, req->priv_key_bits, 2, NULL)) {
3988 DH_set_method(dhparam, DH_get_default_method());
3989 if (DH_check(dhparam, &codes) && codes == 0 && DH_generate_key(dhparam)) {
3990 if (EVP_PKEY_assign_DH(req->priv_key, dhparam)) {
3991 return_val = req->priv_key;
3992 } else {
3993 php_openssl_store_errors();
3994 }
3995 } else {
3996 php_openssl_store_errors();
3997 DH_free(dhparam);
3998 }
3999 } else {
4000 php_openssl_store_errors();
4001 }
4002 }
4003 break;
4004 #endif
4005 #ifdef HAVE_EVP_PKEY_EC
4006 case OPENSSL_KEYTYPE_EC:
4007 {
4008 EC_KEY *eckey;
4009 if (req->curve_name == NID_undef) {
4010 php_error_docref(NULL, E_WARNING, "Missing configuration value: 'curve_name' not set");
4011 return NULL;
4012 }
4013 eckey = EC_KEY_new_by_curve_name(req->curve_name);
4014 if (eckey) {
4015 EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
4016 if (EC_KEY_generate_key(eckey) &&
4017 EVP_PKEY_assign_EC_KEY(req->priv_key, eckey)) {
4018 return_val = req->priv_key;
4019 } else {
4020 EC_KEY_free(eckey);
4021 }
4022 }
4023 }
4024 break;
4025 #endif
4026 default:
4027 php_error_docref(NULL, E_WARNING, "Unsupported private key type");
4028 }
4029 } else {
4030 php_openssl_store_errors();
4031 }
4032
4033 php_openssl_write_rand_file(randfile, egdsocket, seeded);
4034
4035 if (return_val == NULL) {
4036 EVP_PKEY_free(req->priv_key);
4037 req->priv_key = NULL;
4038 return NULL;
4039 }
4040
4041 return return_val;
4042 }
4043 /* }}} */
4044
4045 /* {{{ php_openssl_is_private_key
4046 Check whether the supplied key is a private key by checking if the secret prime factors are set */
php_openssl_is_private_key(EVP_PKEY * pkey)4047 static int php_openssl_is_private_key(EVP_PKEY* pkey)
4048 {
4049 assert(pkey != NULL);
4050
4051 switch (EVP_PKEY_id(pkey)) {
4052 case EVP_PKEY_RSA:
4053 case EVP_PKEY_RSA2:
4054 {
4055 RSA *rsa = EVP_PKEY_get0_RSA(pkey);
4056 if (rsa != NULL) {
4057 const BIGNUM *p, *q;
4058
4059 RSA_get0_factors(rsa, &p, &q);
4060 if (p == NULL || q == NULL) {
4061 return 0;
4062 }
4063 }
4064 }
4065 break;
4066 case EVP_PKEY_DSA:
4067 case EVP_PKEY_DSA1:
4068 case EVP_PKEY_DSA2:
4069 case EVP_PKEY_DSA3:
4070 case EVP_PKEY_DSA4:
4071 {
4072 DSA *dsa = EVP_PKEY_get0_DSA(pkey);
4073 if (dsa != NULL) {
4074 const BIGNUM *p, *q, *g, *pub_key, *priv_key;
4075
4076 DSA_get0_pqg(dsa, &p, &q, &g);
4077 if (p == NULL || q == NULL) {
4078 return 0;
4079 }
4080
4081 DSA_get0_key(dsa, &pub_key, &priv_key);
4082 if (priv_key == NULL) {
4083 return 0;
4084 }
4085 }
4086 }
4087 break;
4088 case EVP_PKEY_DH:
4089 {
4090 DH *dh = EVP_PKEY_get0_DH(pkey);
4091 if (dh != NULL) {
4092 const BIGNUM *p, *q, *g, *pub_key, *priv_key;
4093
4094 DH_get0_pqg(dh, &p, &q, &g);
4095 if (p == NULL) {
4096 return 0;
4097 }
4098
4099 DH_get0_key(dh, &pub_key, &priv_key);
4100 if (priv_key == NULL) {
4101 return 0;
4102 }
4103 }
4104 }
4105 break;
4106 #ifdef HAVE_EVP_PKEY_EC
4107 case EVP_PKEY_EC:
4108 {
4109 EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
4110 if (ec != NULL && NULL == EC_KEY_get0_private_key(ec)) {
4111 return 0;
4112 }
4113 }
4114 break;
4115 #endif
4116 default:
4117 php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
4118 break;
4119 }
4120 return 1;
4121 }
4122 /* }}} */
4123
4124 #define OPENSSL_GET_BN(_array, _bn, _name) do { \
4125 if (_bn != NULL) { \
4126 int len = BN_num_bytes(_bn); \
4127 zend_string *str = zend_string_alloc(len, 0); \
4128 BN_bn2bin(_bn, (unsigned char*)ZSTR_VAL(str)); \
4129 ZSTR_VAL(str)[len] = 0; \
4130 add_assoc_str(&_array, #_name, str); \
4131 } \
4132 } while (0);
4133
4134 #define OPENSSL_PKEY_GET_BN(_type, _name) OPENSSL_GET_BN(_type, _name, _name)
4135
4136 #define OPENSSL_PKEY_SET_BN(_data, _name) do { \
4137 zval *bn; \
4138 if ((bn = zend_hash_str_find(Z_ARRVAL_P(_data), #_name, sizeof(#_name)-1)) != NULL && \
4139 Z_TYPE_P(bn) == IS_STRING) { \
4140 _name = BN_bin2bn( \
4141 (unsigned char*)Z_STRVAL_P(bn), \
4142 (int)Z_STRLEN_P(bn), NULL); \
4143 } else { \
4144 _name = NULL; \
4145 } \
4146 } while (0);
4147
4148 /* {{{ php_openssl_pkey_init_rsa */
php_openssl_pkey_init_and_assign_rsa(EVP_PKEY * pkey,RSA * rsa,zval * data)4149 static zend_bool php_openssl_pkey_init_and_assign_rsa(EVP_PKEY *pkey, RSA *rsa, zval *data)
4150 {
4151 BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
4152
4153 OPENSSL_PKEY_SET_BN(data, n);
4154 OPENSSL_PKEY_SET_BN(data, e);
4155 OPENSSL_PKEY_SET_BN(data, d);
4156 if (!n || !d || !RSA_set0_key(rsa, n, e, d)) {
4157 return 0;
4158 }
4159
4160 OPENSSL_PKEY_SET_BN(data, p);
4161 OPENSSL_PKEY_SET_BN(data, q);
4162 if ((p || q) && !RSA_set0_factors(rsa, p, q)) {
4163 return 0;
4164 }
4165
4166 OPENSSL_PKEY_SET_BN(data, dmp1);
4167 OPENSSL_PKEY_SET_BN(data, dmq1);
4168 OPENSSL_PKEY_SET_BN(data, iqmp);
4169 if ((dmp1 || dmq1 || iqmp) && !RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp)) {
4170 return 0;
4171 }
4172
4173 if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
4174 php_openssl_store_errors();
4175 return 0;
4176 }
4177
4178 return 1;
4179 }
4180
4181 /* {{{ php_openssl_pkey_init_dsa */
php_openssl_pkey_init_dsa(DSA * dsa,zval * data)4182 static zend_bool php_openssl_pkey_init_dsa(DSA *dsa, zval *data)
4183 {
4184 BIGNUM *p, *q, *g, *priv_key, *pub_key;
4185 const BIGNUM *priv_key_const, *pub_key_const;
4186
4187 OPENSSL_PKEY_SET_BN(data, p);
4188 OPENSSL_PKEY_SET_BN(data, q);
4189 OPENSSL_PKEY_SET_BN(data, g);
4190 if (!p || !q || !g || !DSA_set0_pqg(dsa, p, q, g)) {
4191 return 0;
4192 }
4193
4194 OPENSSL_PKEY_SET_BN(data, pub_key);
4195 OPENSSL_PKEY_SET_BN(data, priv_key);
4196 if (pub_key) {
4197 return DSA_set0_key(dsa, pub_key, priv_key);
4198 }
4199
4200 /* generate key */
4201 PHP_OPENSSL_RAND_ADD_TIME();
4202 if (!DSA_generate_key(dsa)) {
4203 php_openssl_store_errors();
4204 return 0;
4205 }
4206
4207 /* if BN_mod_exp return -1, then DSA_generate_key succeed for failed key
4208 * so we need to double check that public key is created */
4209 DSA_get0_key(dsa, &pub_key_const, &priv_key_const);
4210 if (!pub_key_const || BN_is_zero(pub_key_const)) {
4211 return 0;
4212 }
4213 /* all good */
4214 return 1;
4215 }
4216 /* }}} */
4217
4218 /* {{{ php_openssl_dh_pub_from_priv */
php_openssl_dh_pub_from_priv(BIGNUM * priv_key,BIGNUM * g,BIGNUM * p)4219 static BIGNUM *php_openssl_dh_pub_from_priv(BIGNUM *priv_key, BIGNUM *g, BIGNUM *p)
4220 {
4221 BIGNUM *pub_key, *priv_key_const_time;
4222 BN_CTX *ctx;
4223
4224 pub_key = BN_new();
4225 if (pub_key == NULL) {
4226 php_openssl_store_errors();
4227 return NULL;
4228 }
4229
4230 priv_key_const_time = BN_new();
4231 if (priv_key_const_time == NULL) {
4232 BN_free(pub_key);
4233 php_openssl_store_errors();
4234 return NULL;
4235 }
4236 ctx = BN_CTX_new();
4237 if (ctx == NULL) {
4238 BN_free(pub_key);
4239 BN_free(priv_key_const_time);
4240 php_openssl_store_errors();
4241 return NULL;
4242 }
4243
4244 BN_with_flags(priv_key_const_time, priv_key, BN_FLG_CONSTTIME);
4245
4246 if (!BN_mod_exp_mont(pub_key, g, priv_key_const_time, p, ctx, NULL)) {
4247 BN_free(pub_key);
4248 php_openssl_store_errors();
4249 pub_key = NULL;
4250 }
4251
4252 BN_free(priv_key_const_time);
4253 BN_CTX_free(ctx);
4254
4255 return pub_key;
4256 }
4257 /* }}} */
4258
4259 /* {{{ php_openssl_pkey_init_dh */
php_openssl_pkey_init_dh(DH * dh,zval * data)4260 static zend_bool php_openssl_pkey_init_dh(DH *dh, zval *data)
4261 {
4262 BIGNUM *p, *q, *g, *priv_key, *pub_key;
4263
4264 OPENSSL_PKEY_SET_BN(data, p);
4265 OPENSSL_PKEY_SET_BN(data, q);
4266 OPENSSL_PKEY_SET_BN(data, g);
4267 if (!p || !g || !DH_set0_pqg(dh, p, q, g)) {
4268 return 0;
4269 }
4270
4271 OPENSSL_PKEY_SET_BN(data, priv_key);
4272 OPENSSL_PKEY_SET_BN(data, pub_key);
4273 if (pub_key) {
4274 return DH_set0_key(dh, pub_key, priv_key);
4275 }
4276 if (priv_key) {
4277 pub_key = php_openssl_dh_pub_from_priv(priv_key, g, p);
4278 if (pub_key == NULL) {
4279 return 0;
4280 }
4281 return DH_set0_key(dh, pub_key, priv_key);
4282 }
4283
4284 /* generate key */
4285 PHP_OPENSSL_RAND_ADD_TIME();
4286 if (!DH_generate_key(dh)) {
4287 php_openssl_store_errors();
4288 return 0;
4289 }
4290 /* all good */
4291 return 1;
4292 }
4293 /* }}} */
4294
4295 /* {{{ proto resource openssl_pkey_new([array configargs])
4296 Generates a new private key */
PHP_FUNCTION(openssl_pkey_new)4297 PHP_FUNCTION(openssl_pkey_new)
4298 {
4299 struct php_x509_request req;
4300 zval * args = NULL;
4301 zval *data;
4302
4303 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &args) == FAILURE) {
4304 return;
4305 }
4306 RETVAL_FALSE;
4307
4308 if (args && Z_TYPE_P(args) == IS_ARRAY) {
4309 EVP_PKEY *pkey;
4310
4311 if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "rsa", sizeof("rsa")-1)) != NULL &&
4312 Z_TYPE_P(data) == IS_ARRAY) {
4313 pkey = EVP_PKEY_new();
4314 if (pkey) {
4315 RSA *rsa = RSA_new();
4316 if (rsa) {
4317 if (php_openssl_pkey_init_and_assign_rsa(pkey, rsa, data)) {
4318 RETURN_RES(zend_register_resource(pkey, le_key));
4319 }
4320 RSA_free(rsa);
4321 } else {
4322 php_openssl_store_errors();
4323 }
4324 EVP_PKEY_free(pkey);
4325 } else {
4326 php_openssl_store_errors();
4327 }
4328 RETURN_FALSE;
4329 } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dsa", sizeof("dsa") - 1)) != NULL &&
4330 Z_TYPE_P(data) == IS_ARRAY) {
4331 pkey = EVP_PKEY_new();
4332 if (pkey) {
4333 DSA *dsa = DSA_new();
4334 if (dsa) {
4335 if (php_openssl_pkey_init_dsa(dsa, data)) {
4336 if (EVP_PKEY_assign_DSA(pkey, dsa)) {
4337 RETURN_RES(zend_register_resource(pkey, le_key));
4338 } else {
4339 php_openssl_store_errors();
4340 }
4341 }
4342 DSA_free(dsa);
4343 } else {
4344 php_openssl_store_errors();
4345 }
4346 EVP_PKEY_free(pkey);
4347 } else {
4348 php_openssl_store_errors();
4349 }
4350 RETURN_FALSE;
4351 } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dh", sizeof("dh") - 1)) != NULL &&
4352 Z_TYPE_P(data) == IS_ARRAY) {
4353 pkey = EVP_PKEY_new();
4354 if (pkey) {
4355 DH *dh = DH_new();
4356 if (dh) {
4357 if (php_openssl_pkey_init_dh(dh, data)) {
4358 if (EVP_PKEY_assign_DH(pkey, dh)) {
4359 ZVAL_COPY_VALUE(return_value, zend_list_insert(pkey, le_key));
4360 return;
4361 } else {
4362 php_openssl_store_errors();
4363 }
4364 }
4365 DH_free(dh);
4366 } else {
4367 php_openssl_store_errors();
4368 }
4369 EVP_PKEY_free(pkey);
4370 } else {
4371 php_openssl_store_errors();
4372 }
4373 RETURN_FALSE;
4374 #ifdef HAVE_EVP_PKEY_EC
4375 } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "ec", sizeof("ec") - 1)) != NULL &&
4376 Z_TYPE_P(data) == IS_ARRAY) {
4377 EC_KEY *eckey = NULL;
4378 EC_GROUP *group = NULL;
4379 EC_POINT *pnt = NULL;
4380 BIGNUM *d = NULL;
4381 pkey = EVP_PKEY_new();
4382 if (pkey) {
4383 eckey = EC_KEY_new();
4384 if (eckey) {
4385 EC_GROUP *group = NULL;
4386 zval *bn;
4387 zval *x;
4388 zval *y;
4389
4390 if ((bn = zend_hash_str_find(Z_ARRVAL_P(data), "curve_name", sizeof("curve_name") - 1)) != NULL &&
4391 Z_TYPE_P(bn) == IS_STRING) {
4392 int nid = OBJ_sn2nid(Z_STRVAL_P(bn));
4393 if (nid != NID_undef) {
4394 group = EC_GROUP_new_by_curve_name(nid);
4395 if (!group) {
4396 php_openssl_store_errors();
4397 goto clean_exit;
4398 }
4399 EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
4400 EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
4401 if (!EC_KEY_set_group(eckey, group)) {
4402 php_openssl_store_errors();
4403 goto clean_exit;
4404 }
4405 }
4406 }
4407
4408 if (group == NULL) {
4409 php_error_docref(NULL, E_WARNING, "Unknown curve_name");
4410 goto clean_exit;
4411 }
4412
4413 // The public key 'pnt' can be calculated from 'd' or is defined by 'x' and 'y'
4414 if ((bn = zend_hash_str_find(Z_ARRVAL_P(data), "d", sizeof("d") - 1)) != NULL &&
4415 Z_TYPE_P(bn) == IS_STRING) {
4416 d = BN_bin2bn((unsigned char*) Z_STRVAL_P(bn), Z_STRLEN_P(bn), NULL);
4417 if (!EC_KEY_set_private_key(eckey, d)) {
4418 php_openssl_store_errors();
4419 goto clean_exit;
4420 }
4421 // Calculate the public key by multiplying the Point Q with the public key
4422 // P = d * Q
4423 pnt = EC_POINT_new(group);
4424 if (!pnt || !EC_POINT_mul(group, pnt, d, NULL, NULL, NULL)) {
4425 php_openssl_store_errors();
4426 goto clean_exit;
4427 }
4428
4429 BN_free(d);
4430 } else if ((x = zend_hash_str_find(Z_ARRVAL_P(data), "x", sizeof("x") - 1)) != NULL &&
4431 Z_TYPE_P(x) == IS_STRING &&
4432 (y = zend_hash_str_find(Z_ARRVAL_P(data), "y", sizeof("y") - 1)) != NULL &&
4433 Z_TYPE_P(y) == IS_STRING) {
4434 pnt = EC_POINT_new(group);
4435 if (pnt == NULL) {
4436 php_openssl_store_errors();
4437 goto clean_exit;
4438 }
4439 if (!EC_POINT_set_affine_coordinates_GFp(
4440 group, pnt, BN_bin2bn((unsigned char*) Z_STRVAL_P(x), Z_STRLEN_P(x), NULL),
4441 BN_bin2bn((unsigned char*) Z_STRVAL_P(y), Z_STRLEN_P(y), NULL), NULL)) {
4442 php_openssl_store_errors();
4443 goto clean_exit;
4444 }
4445 }
4446
4447 if (pnt != NULL) {
4448 if (!EC_KEY_set_public_key(eckey, pnt)) {
4449 php_openssl_store_errors();
4450 goto clean_exit;
4451 }
4452 EC_POINT_free(pnt);
4453 pnt = NULL;
4454 }
4455
4456 if (!EC_KEY_check_key(eckey)) {
4457 PHP_OPENSSL_RAND_ADD_TIME();
4458 EC_KEY_generate_key(eckey);
4459 php_openssl_store_errors();
4460 }
4461 if (EC_KEY_check_key(eckey) && EVP_PKEY_assign_EC_KEY(pkey, eckey)) {
4462 EC_GROUP_free(group);
4463 RETURN_RES(zend_register_resource(pkey, le_key));
4464 } else {
4465 php_openssl_store_errors();
4466 }
4467 } else {
4468 php_openssl_store_errors();
4469 }
4470 } else {
4471 php_openssl_store_errors();
4472 }
4473 clean_exit:
4474 if (d != NULL) {
4475 BN_free(d);
4476 }
4477 if (pnt != NULL) {
4478 EC_POINT_free(pnt);
4479 }
4480 if (group != NULL) {
4481 EC_GROUP_free(group);
4482 }
4483 if (eckey != NULL) {
4484 EC_KEY_free(eckey);
4485 }
4486 if (pkey != NULL) {
4487 EVP_PKEY_free(pkey);
4488 }
4489 RETURN_FALSE;
4490 #endif
4491 }
4492 }
4493
4494 PHP_SSL_REQ_INIT(&req);
4495
4496 if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
4497 if (php_openssl_generate_private_key(&req)) {
4498 /* pass back a key resource */
4499 RETVAL_RES(zend_register_resource(req.priv_key, le_key));
4500 /* make sure the cleanup code doesn't zap it! */
4501 req.priv_key = NULL;
4502 }
4503 }
4504 PHP_SSL_REQ_DISPOSE(&req);
4505 }
4506 /* }}} */
4507
4508 /* {{{ proto bool openssl_pkey_export_to_file(mixed key, string outfilename [, string passphrase, array config_args)
4509 Gets an exportable representation of a key into a file */
PHP_FUNCTION(openssl_pkey_export_to_file)4510 PHP_FUNCTION(openssl_pkey_export_to_file)
4511 {
4512 struct php_x509_request req;
4513 zval * zpkey, * args = NULL;
4514 char * passphrase = NULL;
4515 size_t passphrase_len = 0;
4516 char * filename = NULL;
4517 size_t filename_len = 0;
4518 zend_resource *key_resource = NULL;
4519 int pem_write = 0;
4520 EVP_PKEY * key;
4521 BIO * bio_out = NULL;
4522 const EVP_CIPHER * cipher;
4523
4524 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) {
4525 return;
4526 }
4527 RETVAL_FALSE;
4528
4529 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase);
4530 key = php_openssl_evp_from_zval(zpkey, 0, passphrase, passphrase_len, 0, &key_resource);
4531
4532 if (key == NULL) {
4533 php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1");
4534 RETURN_FALSE;
4535 }
4536
4537 if (php_openssl_open_base_dir_chk(filename)) {
4538 RETURN_FALSE;
4539 }
4540
4541 PHP_SSL_REQ_INIT(&req);
4542
4543 if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
4544 bio_out = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
4545 if (bio_out == NULL) {
4546 php_openssl_store_errors();
4547 goto clean_exit;
4548 }
4549
4550 if (passphrase && req.priv_key_encrypt) {
4551 if (req.priv_key_encrypt_cipher) {
4552 cipher = req.priv_key_encrypt_cipher;
4553 } else {
4554 cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
4555 }
4556 } else {
4557 cipher = NULL;
4558 }
4559
4560 switch (EVP_PKEY_base_id(key)) {
4561 #ifdef HAVE_EVP_PKEY_EC
4562 case EVP_PKEY_EC:
4563 pem_write = PEM_write_bio_ECPrivateKey(
4564 bio_out, EVP_PKEY_get0_EC_KEY(key), cipher,
4565 (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
4566 break;
4567 #endif
4568 default:
4569 pem_write = PEM_write_bio_PrivateKey(
4570 bio_out, key, cipher,
4571 (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
4572 break;
4573 }
4574
4575 if (pem_write) {
4576 /* Success!
4577 * If returning the output as a string, do so now */
4578 RETVAL_TRUE;
4579 } else {
4580 php_openssl_store_errors();
4581 }
4582 }
4583
4584 clean_exit:
4585 PHP_SSL_REQ_DISPOSE(&req);
4586
4587 if (key_resource == NULL && key) {
4588 EVP_PKEY_free(key);
4589 }
4590 if (bio_out) {
4591 BIO_free(bio_out);
4592 }
4593 }
4594 /* }}} */
4595
4596 /* {{{ proto bool openssl_pkey_export(mixed key, &mixed out [, string passphrase [, array config_args]])
4597 Gets an exportable representation of a key into a string or file */
PHP_FUNCTION(openssl_pkey_export)4598 PHP_FUNCTION(openssl_pkey_export)
4599 {
4600 struct php_x509_request req;
4601 zval * zpkey, * args = NULL, *out;
4602 char * passphrase = NULL; size_t passphrase_len = 0;
4603 int pem_write = 0;
4604 zend_resource *key_resource = NULL;
4605 EVP_PKEY * key;
4606 BIO * bio_out = NULL;
4607 const EVP_CIPHER * cipher;
4608
4609 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) {
4610 return;
4611 }
4612 RETVAL_FALSE;
4613
4614 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase);
4615 key = php_openssl_evp_from_zval(zpkey, 0, passphrase, passphrase_len, 0, &key_resource);
4616
4617 if (key == NULL) {
4618 php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1");
4619 RETURN_FALSE;
4620 }
4621
4622 PHP_SSL_REQ_INIT(&req);
4623
4624 if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
4625 bio_out = BIO_new(BIO_s_mem());
4626
4627 if (passphrase && req.priv_key_encrypt) {
4628 if (req.priv_key_encrypt_cipher) {
4629 cipher = req.priv_key_encrypt_cipher;
4630 } else {
4631 cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
4632 }
4633 } else {
4634 cipher = NULL;
4635 }
4636
4637 switch (EVP_PKEY_base_id(key)) {
4638 #ifdef HAVE_EVP_PKEY_EC
4639 case EVP_PKEY_EC:
4640 pem_write = PEM_write_bio_ECPrivateKey(
4641 bio_out, EVP_PKEY_get0_EC_KEY(key), cipher,
4642 (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
4643 break;
4644 #endif
4645 default:
4646 pem_write = PEM_write_bio_PrivateKey(
4647 bio_out, key, cipher,
4648 (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
4649 break;
4650 }
4651
4652 if (pem_write) {
4653 /* Success!
4654 * If returning the output as a string, do so now */
4655
4656 char * bio_mem_ptr;
4657 long bio_mem_len;
4658 RETVAL_TRUE;
4659
4660 bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr);
4661 zval_ptr_dtor(out);
4662 ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len);
4663 } else {
4664 php_openssl_store_errors();
4665 }
4666 }
4667 PHP_SSL_REQ_DISPOSE(&req);
4668
4669 if (key_resource == NULL && key) {
4670 EVP_PKEY_free(key);
4671 }
4672 if (bio_out) {
4673 BIO_free(bio_out);
4674 }
4675 }
4676 /* }}} */
4677
4678 /* {{{ proto int openssl_pkey_get_public(mixed cert)
4679 Gets public key from X.509 certificate */
PHP_FUNCTION(openssl_pkey_get_public)4680 PHP_FUNCTION(openssl_pkey_get_public)
4681 {
4682 zval *cert;
4683 EVP_PKEY *pkey;
4684 zend_resource *res;
4685
4686 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &cert) == FAILURE) {
4687 return;
4688 }
4689 pkey = php_openssl_evp_from_zval(cert, 1, NULL, 0, 1, &res);
4690 if (pkey == NULL) {
4691 RETURN_FALSE;
4692 }
4693 ZVAL_RES(return_value, res);
4694 }
4695 /* }}} */
4696
4697 /* {{{ proto void openssl_pkey_free(int key)
4698 Frees a key */
PHP_FUNCTION(openssl_pkey_free)4699 PHP_FUNCTION(openssl_pkey_free)
4700 {
4701 zval *key;
4702 EVP_PKEY *pkey;
4703
4704 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &key) == FAILURE) {
4705 return;
4706 }
4707 if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) {
4708 RETURN_FALSE;
4709 }
4710 zend_list_close(Z_RES_P(key));
4711 }
4712 /* }}} */
4713
4714 /* {{{ proto int openssl_pkey_get_private(string key [, string passphrase])
4715 Gets private keys */
PHP_FUNCTION(openssl_pkey_get_private)4716 PHP_FUNCTION(openssl_pkey_get_private)
4717 {
4718 zval *cert;
4719 EVP_PKEY *pkey;
4720 char * passphrase = "";
4721 size_t passphrase_len = sizeof("")-1;
4722 zend_resource *res;
4723
4724 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s", &cert, &passphrase, &passphrase_len) == FAILURE) {
4725 return;
4726 }
4727
4728 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase);
4729 pkey = php_openssl_evp_from_zval(cert, 0, passphrase, passphrase_len, 1, &res);
4730
4731 if (pkey == NULL) {
4732 RETURN_FALSE;
4733 }
4734 ZVAL_RES(return_value, res);
4735 }
4736
4737 /* }}} */
4738
4739 /* {{{ proto resource openssl_pkey_get_details(resource key)
4740 returns an array with the key details (bits, pkey, type)*/
PHP_FUNCTION(openssl_pkey_get_details)4741 PHP_FUNCTION(openssl_pkey_get_details)
4742 {
4743 zval *key;
4744 EVP_PKEY *pkey;
4745 BIO *out;
4746 unsigned int pbio_len;
4747 char *pbio;
4748 zend_long ktype;
4749
4750 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &key) == FAILURE) {
4751 return;
4752 }
4753 if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) {
4754 RETURN_FALSE;
4755 }
4756 out = BIO_new(BIO_s_mem());
4757 if (!PEM_write_bio_PUBKEY(out, pkey)) {
4758 BIO_free(out);
4759 php_openssl_store_errors();
4760 RETURN_FALSE;
4761 }
4762 pbio_len = BIO_get_mem_data(out, &pbio);
4763
4764 array_init(return_value);
4765 add_assoc_long(return_value, "bits", EVP_PKEY_bits(pkey));
4766 add_assoc_stringl(return_value, "key", pbio, pbio_len);
4767 /*TODO: Use the real values once the openssl constants are used
4768 * See the enum at the top of this file
4769 */
4770 switch (EVP_PKEY_base_id(pkey)) {
4771 case EVP_PKEY_RSA:
4772 case EVP_PKEY_RSA2:
4773 {
4774 RSA *rsa = EVP_PKEY_get0_RSA(pkey);
4775 ktype = OPENSSL_KEYTYPE_RSA;
4776
4777 if (rsa != NULL) {
4778 zval z_rsa;
4779 const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
4780
4781 RSA_get0_key(rsa, &n, &e, &d);
4782 RSA_get0_factors(rsa, &p, &q);
4783 RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
4784
4785 array_init(&z_rsa);
4786 OPENSSL_PKEY_GET_BN(z_rsa, n);
4787 OPENSSL_PKEY_GET_BN(z_rsa, e);
4788 OPENSSL_PKEY_GET_BN(z_rsa, d);
4789 OPENSSL_PKEY_GET_BN(z_rsa, p);
4790 OPENSSL_PKEY_GET_BN(z_rsa, q);
4791 OPENSSL_PKEY_GET_BN(z_rsa, dmp1);
4792 OPENSSL_PKEY_GET_BN(z_rsa, dmq1);
4793 OPENSSL_PKEY_GET_BN(z_rsa, iqmp);
4794 add_assoc_zval(return_value, "rsa", &z_rsa);
4795 }
4796 }
4797 break;
4798 case EVP_PKEY_DSA:
4799 case EVP_PKEY_DSA2:
4800 case EVP_PKEY_DSA3:
4801 case EVP_PKEY_DSA4:
4802 {
4803 DSA *dsa = EVP_PKEY_get0_DSA(pkey);
4804 ktype = OPENSSL_KEYTYPE_DSA;
4805
4806 if (dsa != NULL) {
4807 zval z_dsa;
4808 const BIGNUM *p, *q, *g, *priv_key, *pub_key;
4809
4810 DSA_get0_pqg(dsa, &p, &q, &g);
4811 DSA_get0_key(dsa, &pub_key, &priv_key);
4812
4813 array_init(&z_dsa);
4814 OPENSSL_PKEY_GET_BN(z_dsa, p);
4815 OPENSSL_PKEY_GET_BN(z_dsa, q);
4816 OPENSSL_PKEY_GET_BN(z_dsa, g);
4817 OPENSSL_PKEY_GET_BN(z_dsa, priv_key);
4818 OPENSSL_PKEY_GET_BN(z_dsa, pub_key);
4819 add_assoc_zval(return_value, "dsa", &z_dsa);
4820 }
4821 }
4822 break;
4823 case EVP_PKEY_DH:
4824 {
4825 DH *dh = EVP_PKEY_get0_DH(pkey);
4826 ktype = OPENSSL_KEYTYPE_DH;
4827
4828 if (dh != NULL) {
4829 zval z_dh;
4830 const BIGNUM *p, *q, *g, *priv_key, *pub_key;
4831
4832 DH_get0_pqg(dh, &p, &q, &g);
4833 DH_get0_key(dh, &pub_key, &priv_key);
4834
4835 array_init(&z_dh);
4836 OPENSSL_PKEY_GET_BN(z_dh, p);
4837 OPENSSL_PKEY_GET_BN(z_dh, g);
4838 OPENSSL_PKEY_GET_BN(z_dh, priv_key);
4839 OPENSSL_PKEY_GET_BN(z_dh, pub_key);
4840 add_assoc_zval(return_value, "dh", &z_dh);
4841 }
4842 }
4843 break;
4844 #ifdef HAVE_EVP_PKEY_EC
4845 case EVP_PKEY_EC:
4846 ktype = OPENSSL_KEYTYPE_EC;
4847 if (EVP_PKEY_get0_EC_KEY(pkey) != NULL) {
4848 zval ec;
4849 const EC_GROUP *ec_group;
4850 const EC_POINT *pub;
4851 int nid;
4852 char *crv_sn;
4853 ASN1_OBJECT *obj;
4854 // openssl recommends a buffer length of 80
4855 char oir_buf[80];
4856 const EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey);
4857 BIGNUM *x = BN_new();
4858 BIGNUM *y = BN_new();
4859 const BIGNUM *d;
4860
4861 ec_group = EC_KEY_get0_group(ec_key);
4862
4863 // Curve nid (numerical identifier) used for ASN1 mapping
4864 nid = EC_GROUP_get_curve_name(ec_group);
4865 if (nid == NID_undef) {
4866 break;
4867 }
4868 array_init(&ec);
4869
4870 // Short object name
4871 crv_sn = (char*) OBJ_nid2sn(nid);
4872 if (crv_sn != NULL) {
4873 add_assoc_string(&ec, "curve_name", crv_sn);
4874 }
4875
4876 obj = OBJ_nid2obj(nid);
4877 if (obj != NULL) {
4878 int oir_len = OBJ_obj2txt(oir_buf, sizeof(oir_buf), obj, 1);
4879 add_assoc_stringl(&ec, "curve_oid", (char*) oir_buf, oir_len);
4880 ASN1_OBJECT_free(obj);
4881 }
4882
4883 pub = EC_KEY_get0_public_key(ec_key);
4884
4885 if (EC_POINT_get_affine_coordinates_GFp(ec_group, pub, x, y, NULL)) {
4886 OPENSSL_GET_BN(ec, x, x);
4887 OPENSSL_GET_BN(ec, y, y);
4888 } else {
4889 php_openssl_store_errors();
4890 }
4891
4892 if ((d = EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(pkey))) != NULL) {
4893 OPENSSL_GET_BN(ec, d, d);
4894 }
4895
4896 add_assoc_zval(return_value, "ec", &ec);
4897
4898 BN_free(x);
4899 BN_free(y);
4900 }
4901 break;
4902 #endif
4903 default:
4904 ktype = -1;
4905 break;
4906 }
4907 add_assoc_long(return_value, "type", ktype);
4908
4909 BIO_free(out);
4910 }
4911 /* }}} */
4912
4913 /* {{{ proto string openssl_dh_compute_key(string pub_key, resource dh_key)
4914 Computes shared secret for public value of remote DH key and local DH key */
PHP_FUNCTION(openssl_dh_compute_key)4915 PHP_FUNCTION(openssl_dh_compute_key)
4916 {
4917 zval *key;
4918 char *pub_str;
4919 size_t pub_len;
4920 DH *dh;
4921 EVP_PKEY *pkey;
4922 BIGNUM *pub;
4923 zend_string *data;
4924 int len;
4925
4926 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sr", &pub_str, &pub_len, &key) == FAILURE) {
4927 return;
4928 }
4929 if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) {
4930 RETURN_FALSE;
4931 }
4932 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) {
4933 RETURN_FALSE;
4934 }
4935 dh = EVP_PKEY_get0_DH(pkey);
4936 if (dh == NULL) {
4937 RETURN_FALSE;
4938 }
4939
4940 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(pub_len, pub_key);
4941 pub = BN_bin2bn((unsigned char*)pub_str, (int)pub_len, NULL);
4942
4943 data = zend_string_alloc(DH_size(dh), 0);
4944 len = DH_compute_key((unsigned char*)ZSTR_VAL(data), pub, dh);
4945
4946 if (len >= 0) {
4947 ZSTR_LEN(data) = len;
4948 ZSTR_VAL(data)[len] = 0;
4949 RETVAL_NEW_STR(data);
4950 } else {
4951 php_openssl_store_errors();
4952 zend_string_release_ex(data, 0);
4953 RETVAL_FALSE;
4954 }
4955
4956 BN_free(pub);
4957 }
4958 /* }}} */
4959
4960 /* {{{ proto string openssl_pkey_derive(peer_pub_key, priv_key, int keylen=NULL)
4961 Computes shared secret for public value of remote and local DH or ECDH key */
PHP_FUNCTION(openssl_pkey_derive)4962 PHP_FUNCTION(openssl_pkey_derive)
4963 {
4964 zval *priv_key;
4965 zval *peer_pub_key;
4966 EVP_PKEY *pkey;
4967 EVP_PKEY *peer_key;
4968 size_t key_size;
4969 zend_long key_len = 0;
4970 zend_string *result;
4971
4972 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &peer_pub_key, &priv_key, &key_len) == FAILURE) {
4973 RETURN_FALSE;
4974 }
4975 if (key_len < 0) {
4976 php_error_docref(NULL, E_WARNING, "keylen < 0, assuming NULL");
4977 }
4978 key_size = key_len;
4979 if ((pkey = php_openssl_evp_from_zval(priv_key, 0, "", 0, 0, NULL)) == NULL
4980 || (peer_key = php_openssl_evp_from_zval(peer_pub_key, 1, NULL, 0, 0, NULL)) == NULL) {
4981 RETURN_FALSE;
4982 }
4983 EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
4984 if (!ctx) {
4985 RETURN_FALSE;
4986 }
4987 if (EVP_PKEY_derive_init(ctx) > 0
4988 && EVP_PKEY_derive_set_peer(ctx, peer_key) > 0
4989 && (key_size > 0 || EVP_PKEY_derive(ctx, NULL, &key_size) > 0)
4990 && (result = zend_string_alloc(key_size, 0)) != NULL) {
4991 if (EVP_PKEY_derive(ctx, (unsigned char*)ZSTR_VAL(result), &key_size) > 0) {
4992 ZSTR_LEN(result) = key_size;
4993 ZSTR_VAL(result)[key_size] = 0;
4994 RETVAL_NEW_STR(result);
4995 } else {
4996 php_openssl_store_errors();
4997 zend_string_release_ex(result, 0);
4998 RETVAL_FALSE;
4999 }
5000 } else {
5001 RETVAL_FALSE;
5002 }
5003 EVP_PKEY_CTX_free(ctx);
5004 }
5005 /* }}} */
5006
5007
5008 /* {{{ proto string openssl_pbkdf2(string password, string salt, int key_length, int iterations [, string digest_method = "sha1"])
5009 Generates a PKCS5 v2 PBKDF2 string, defaults to sha1 */
PHP_FUNCTION(openssl_pbkdf2)5010 PHP_FUNCTION(openssl_pbkdf2)
5011 {
5012 zend_long key_length = 0, iterations = 0;
5013 char *password;
5014 size_t password_len;
5015 char *salt;
5016 size_t salt_len;
5017 char *method;
5018 size_t method_len = 0;
5019 zend_string *out_buffer;
5020
5021 const EVP_MD *digest;
5022
5023 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssll|s",
5024 &password, &password_len,
5025 &salt, &salt_len,
5026 &key_length, &iterations,
5027 &method, &method_len) == FAILURE) {
5028 return;
5029 }
5030
5031 if (key_length <= 0) {
5032 RETURN_FALSE;
5033 }
5034
5035 if (method_len) {
5036 digest = EVP_get_digestbyname(method);
5037 } else {
5038 digest = EVP_sha1();
5039 }
5040
5041 if (!digest) {
5042 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
5043 RETURN_FALSE;
5044 }
5045
5046 PHP_OPENSSL_CHECK_LONG_TO_INT(key_length, key);
5047 PHP_OPENSSL_CHECK_LONG_TO_INT(iterations, iterations);
5048 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password);
5049 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(salt_len, salt);
5050
5051 out_buffer = zend_string_alloc(key_length, 0);
5052
5053 if (PKCS5_PBKDF2_HMAC(password, (int)password_len, (unsigned char *)salt, (int)salt_len, (int)iterations, digest, (int)key_length, (unsigned char*)ZSTR_VAL(out_buffer)) == 1) {
5054 ZSTR_VAL(out_buffer)[key_length] = 0;
5055 RETURN_NEW_STR(out_buffer);
5056 } else {
5057 php_openssl_store_errors();
5058 zend_string_release_ex(out_buffer, 0);
5059 RETURN_FALSE;
5060 }
5061 }
5062 /* }}} */
5063
5064 /* {{{ PKCS7 S/MIME functions */
5065
5066 /* {{{ proto bool openssl_pkcs7_verify(string filename, int flags [, string signerscerts [, array cainfo [, string extracerts [, string content [, string pk7]]]]])
5067 Verifys that the data block is intact, the signer is who they say they are, and returns the CERTs of the signers */
PHP_FUNCTION(openssl_pkcs7_verify)5068 PHP_FUNCTION(openssl_pkcs7_verify)
5069 {
5070 X509_STORE * store = NULL;
5071 zval * cainfo = NULL;
5072 STACK_OF(X509) *signers= NULL;
5073 STACK_OF(X509) *others = NULL;
5074 PKCS7 * p7 = NULL;
5075 BIO * in = NULL, * datain = NULL, * dataout = NULL, * p7bout = NULL;
5076 zend_long flags = 0;
5077 char * filename;
5078 size_t filename_len;
5079 char * extracerts = NULL;
5080 size_t extracerts_len = 0;
5081 char * signersfilename = NULL;
5082 size_t signersfilename_len = 0;
5083 char * datafilename = NULL;
5084 size_t datafilename_len = 0;
5085 char * p7bfilename = NULL;
5086 size_t p7bfilename_len = 0;
5087
5088 RETVAL_LONG(-1);
5089
5090 if (zend_parse_parameters(ZEND_NUM_ARGS(), "pl|pappp", &filename, &filename_len,
5091 &flags, &signersfilename, &signersfilename_len, &cainfo,
5092 &extracerts, &extracerts_len, &datafilename, &datafilename_len, &p7bfilename, &p7bfilename_len) == FAILURE) {
5093 return;
5094 }
5095
5096 if (extracerts) {
5097 others = php_openssl_load_all_certs_from_file(extracerts);
5098 if (others == NULL) {
5099 goto clean_exit;
5100 }
5101 }
5102
5103 flags = flags & ~PKCS7_DETACHED;
5104
5105 store = php_openssl_setup_verify(cainfo);
5106
5107 if (!store) {
5108 goto clean_exit;
5109 }
5110 if (php_openssl_open_base_dir_chk(filename)) {
5111 goto clean_exit;
5112 }
5113
5114 in = BIO_new_file(filename, PHP_OPENSSL_BIO_MODE_R(flags));
5115 if (in == NULL) {
5116 php_openssl_store_errors();
5117 goto clean_exit;
5118 }
5119 p7 = SMIME_read_PKCS7(in, &datain);
5120 if (p7 == NULL) {
5121 #if DEBUG_SMIME
5122 zend_printf("SMIME_read_PKCS7 failed\n");
5123 #endif
5124 php_openssl_store_errors();
5125 goto clean_exit;
5126 }
5127
5128 if (datafilename) {
5129
5130 if (php_openssl_open_base_dir_chk(datafilename)) {
5131 goto clean_exit;
5132 }
5133
5134 dataout = BIO_new_file(datafilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
5135 if (dataout == NULL) {
5136 php_openssl_store_errors();
5137 goto clean_exit;
5138 }
5139 }
5140
5141 if (p7bfilename) {
5142
5143 if (php_openssl_open_base_dir_chk(p7bfilename)) {
5144 goto clean_exit;
5145 }
5146
5147 p7bout = BIO_new_file(p7bfilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
5148 if (p7bout == NULL) {
5149 php_openssl_store_errors();
5150 goto clean_exit;
5151 }
5152 }
5153 #if DEBUG_SMIME
5154 zend_printf("Calling PKCS7 verify\n");
5155 #endif
5156
5157 if (PKCS7_verify(p7, others, store, datain, dataout, (int)flags)) {
5158
5159 RETVAL_TRUE;
5160
5161 if (signersfilename) {
5162 BIO *certout;
5163
5164 if (php_openssl_open_base_dir_chk(signersfilename)) {
5165 goto clean_exit;
5166 }
5167
5168 certout = BIO_new_file(signersfilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
5169 if (certout) {
5170 int i;
5171 signers = PKCS7_get0_signers(p7, NULL, (int)flags);
5172 if (signers != NULL) {
5173
5174 for (i = 0; i < sk_X509_num(signers); i++) {
5175 if (!PEM_write_bio_X509(certout, sk_X509_value(signers, i))) {
5176 php_openssl_store_errors();
5177 RETVAL_LONG(-1);
5178 php_error_docref(NULL, E_WARNING, "failed to write signer %d", i);
5179 }
5180 }
5181
5182 sk_X509_free(signers);
5183 } else {
5184 RETVAL_LONG(-1);
5185 php_openssl_store_errors();
5186 }
5187
5188 BIO_free(certout);
5189 } else {
5190 php_openssl_store_errors();
5191 php_error_docref(NULL, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename);
5192 RETVAL_LONG(-1);
5193 }
5194
5195 if (p7bout) {
5196 PEM_write_bio_PKCS7(p7bout, p7);
5197 }
5198 }
5199 } else {
5200 php_openssl_store_errors();
5201 RETVAL_FALSE;
5202 }
5203 clean_exit:
5204 if (p7bout) {
5205 BIO_free(p7bout);
5206 }
5207 X509_STORE_free(store);
5208 BIO_free(datain);
5209 BIO_free(in);
5210 BIO_free(dataout);
5211 PKCS7_free(p7);
5212 sk_X509_pop_free(others, X509_free);
5213 }
5214 /* }}} */
5215
5216 /* {{{ proto bool openssl_pkcs7_encrypt(string infile, string outfile, mixed recipcerts, array headers [, int flags [, int cipher]])
5217 Encrypts the message in the file named infile with the certificates in recipcerts and output the result to the file named outfile */
PHP_FUNCTION(openssl_pkcs7_encrypt)5218 PHP_FUNCTION(openssl_pkcs7_encrypt)
5219 {
5220 zval * zrecipcerts, * zheaders = NULL;
5221 STACK_OF(X509) * recipcerts = NULL;
5222 BIO * infile = NULL, * outfile = NULL;
5223 zend_long flags = 0;
5224 PKCS7 * p7 = NULL;
5225 zval * zcertval;
5226 X509 * cert;
5227 const EVP_CIPHER *cipher = NULL;
5228 zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
5229 zend_string * strindex;
5230 char * infilename = NULL;
5231 size_t infilename_len;
5232 char * outfilename = NULL;
5233 size_t outfilename_len;
5234
5235 RETVAL_FALSE;
5236
5237 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|ll", &infilename, &infilename_len,
5238 &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE)
5239 return;
5240
5241
5242 if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
5243 return;
5244 }
5245
5246 infile = BIO_new_file(infilename, PHP_OPENSSL_BIO_MODE_R(flags));
5247 if (infile == NULL) {
5248 php_openssl_store_errors();
5249 goto clean_exit;
5250 }
5251
5252 outfile = BIO_new_file(outfilename, PHP_OPENSSL_BIO_MODE_W(flags));
5253 if (outfile == NULL) {
5254 php_openssl_store_errors();
5255 goto clean_exit;
5256 }
5257
5258 recipcerts = sk_X509_new_null();
5259
5260 /* get certs */
5261 if (Z_TYPE_P(zrecipcerts) == IS_ARRAY) {
5262 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zrecipcerts), zcertval) {
5263 zend_resource *certresource;
5264
5265 cert = php_openssl_x509_from_zval(zcertval, 0, &certresource);
5266 if (cert == NULL) {
5267 goto clean_exit;
5268 }
5269
5270 if (certresource != NULL) {
5271 /* we shouldn't free this particular cert, as it is a resource.
5272 make a copy and push that on the stack instead */
5273 cert = X509_dup(cert);
5274 if (cert == NULL) {
5275 php_openssl_store_errors();
5276 goto clean_exit;
5277 }
5278 }
5279 sk_X509_push(recipcerts, cert);
5280 } ZEND_HASH_FOREACH_END();
5281 } else {
5282 /* a single certificate */
5283 zend_resource *certresource;
5284
5285 cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource);
5286 if (cert == NULL) {
5287 goto clean_exit;
5288 }
5289
5290 if (certresource != NULL) {
5291 /* we shouldn't free this particular cert, as it is a resource.
5292 make a copy and push that on the stack instead */
5293 cert = X509_dup(cert);
5294 if (cert == NULL) {
5295 php_openssl_store_errors();
5296 goto clean_exit;
5297 }
5298 }
5299 sk_X509_push(recipcerts, cert);
5300 }
5301
5302 /* sanity check the cipher */
5303 cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
5304 if (cipher == NULL) {
5305 /* shouldn't happen */
5306 php_error_docref(NULL, E_WARNING, "Failed to get cipher");
5307 goto clean_exit;
5308 }
5309
5310 p7 = PKCS7_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, (int)flags);
5311
5312 if (p7 == NULL) {
5313 php_openssl_store_errors();
5314 goto clean_exit;
5315 }
5316
5317 /* tack on extra headers */
5318 if (zheaders) {
5319 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, zcertval) {
5320 convert_to_string_ex(zcertval);
5321
5322 if (strindex) {
5323 BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(zcertval));
5324 } else {
5325 BIO_printf(outfile, "%s\n", Z_STRVAL_P(zcertval));
5326 }
5327 } ZEND_HASH_FOREACH_END();
5328 }
5329
5330 (void)BIO_reset(infile);
5331
5332 /* write the encrypted data */
5333 if (!SMIME_write_PKCS7(outfile, p7, infile, (int)flags)) {
5334 php_openssl_store_errors();
5335 goto clean_exit;
5336 }
5337
5338 RETVAL_TRUE;
5339
5340 clean_exit:
5341 PKCS7_free(p7);
5342 BIO_free(infile);
5343 BIO_free(outfile);
5344 if (recipcerts) {
5345 sk_X509_pop_free(recipcerts, X509_free);
5346 }
5347 }
5348 /* }}} */
5349
5350 /* {{{ proto bool openssl_pkcs7_read(string P7B, array &certs)
5351 Exports the PKCS7 file to an array of PEM certificates */
PHP_FUNCTION(openssl_pkcs7_read)5352 PHP_FUNCTION(openssl_pkcs7_read)
5353 {
5354 zval * zout = NULL, zcert;
5355 char *p7b;
5356 size_t p7b_len;
5357 STACK_OF(X509) *certs = NULL;
5358 STACK_OF(X509_CRL) *crls = NULL;
5359 BIO * bio_in = NULL, * bio_out = NULL;
5360 PKCS7 * p7 = NULL;
5361 int i;
5362
5363 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/", &p7b, &p7b_len,
5364 &zout) == FAILURE) {
5365 return;
5366 }
5367
5368 RETVAL_FALSE;
5369
5370 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(p7b_len, p7b);
5371
5372 bio_in = BIO_new(BIO_s_mem());
5373 if (bio_in == NULL) {
5374 goto clean_exit;
5375 }
5376
5377 if (0 >= BIO_write(bio_in, p7b, (int)p7b_len)) {
5378 php_openssl_store_errors();
5379 goto clean_exit;
5380 }
5381
5382 p7 = PEM_read_bio_PKCS7(bio_in, NULL, NULL, NULL);
5383 if (p7 == NULL) {
5384 php_openssl_store_errors();
5385 goto clean_exit;
5386 }
5387
5388 switch (OBJ_obj2nid(p7->type)) {
5389 case NID_pkcs7_signed:
5390 if (p7->d.sign != NULL) {
5391 certs = p7->d.sign->cert;
5392 crls = p7->d.sign->crl;
5393 }
5394 break;
5395 case NID_pkcs7_signedAndEnveloped:
5396 if (p7->d.signed_and_enveloped != NULL) {
5397 certs = p7->d.signed_and_enveloped->cert;
5398 crls = p7->d.signed_and_enveloped->crl;
5399 }
5400 break;
5401 default:
5402 break;
5403 }
5404
5405 zval_ptr_dtor(zout);
5406 array_init(zout);
5407
5408 if (certs != NULL) {
5409 for (i = 0; i < sk_X509_num(certs); i++) {
5410 X509* ca = sk_X509_value(certs, i);
5411
5412 bio_out = BIO_new(BIO_s_mem());
5413 if (bio_out && PEM_write_bio_X509(bio_out, ca)) {
5414 BUF_MEM *bio_buf;
5415 BIO_get_mem_ptr(bio_out, &bio_buf);
5416 ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
5417 add_index_zval(zout, i, &zcert);
5418 BIO_free(bio_out);
5419 }
5420 }
5421 }
5422
5423 if (crls != NULL) {
5424 for (i = 0; i < sk_X509_CRL_num(crls); i++) {
5425 X509_CRL* crl = sk_X509_CRL_value(crls, i);
5426
5427 bio_out = BIO_new(BIO_s_mem());
5428 if (bio_out && PEM_write_bio_X509_CRL(bio_out, crl)) {
5429 BUF_MEM *bio_buf;
5430 BIO_get_mem_ptr(bio_out, &bio_buf);
5431 ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
5432 add_index_zval(zout, i, &zcert);
5433 BIO_free(bio_out);
5434 }
5435 }
5436 }
5437
5438 RETVAL_TRUE;
5439
5440 clean_exit:
5441 if (bio_in != NULL) {
5442 BIO_free(bio_in);
5443 }
5444
5445 if (p7 != NULL) {
5446 PKCS7_free(p7);
5447 }
5448 }
5449 /* }}} */
5450
5451 /* {{{ proto bool openssl_pkcs7_sign(string infile, string outfile, mixed signcert, mixed signkey, array headers [, int flags [, string extracertsfilename]])
5452 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 */
5453
PHP_FUNCTION(openssl_pkcs7_sign)5454 PHP_FUNCTION(openssl_pkcs7_sign)
5455 {
5456 zval * zcert, * zprivkey, * zheaders;
5457 zval * hval;
5458 X509 * cert = NULL;
5459 EVP_PKEY * privkey = NULL;
5460 zend_long flags = PKCS7_DETACHED;
5461 PKCS7 * p7 = NULL;
5462 BIO * infile = NULL, * outfile = NULL;
5463 STACK_OF(X509) *others = NULL;
5464 zend_resource *certresource = NULL, *keyresource = NULL;
5465 zend_string * strindex;
5466 char * infilename;
5467 size_t infilename_len;
5468 char * outfilename;
5469 size_t outfilename_len;
5470 char * extracertsfilename = NULL;
5471 size_t extracertsfilename_len;
5472
5473 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppzza!|lp!",
5474 &infilename, &infilename_len, &outfilename, &outfilename_len,
5475 &zcert, &zprivkey, &zheaders, &flags, &extracertsfilename,
5476 &extracertsfilename_len) == FAILURE) {
5477 return;
5478 }
5479
5480 RETVAL_FALSE;
5481
5482 if (extracertsfilename) {
5483 others = php_openssl_load_all_certs_from_file(extracertsfilename);
5484 if (others == NULL) {
5485 goto clean_exit;
5486 }
5487 }
5488
5489 privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, 0, &keyresource);
5490 if (privkey == NULL) {
5491 php_error_docref(NULL, E_WARNING, "error getting private key");
5492 goto clean_exit;
5493 }
5494
5495 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
5496 if (cert == NULL) {
5497 php_error_docref(NULL, E_WARNING, "error getting cert");
5498 goto clean_exit;
5499 }
5500
5501 if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
5502 goto clean_exit;
5503 }
5504
5505 infile = BIO_new_file(infilename, PHP_OPENSSL_BIO_MODE_R(flags));
5506 if (infile == NULL) {
5507 php_openssl_store_errors();
5508 php_error_docref(NULL, E_WARNING, "error opening input file %s!", infilename);
5509 goto clean_exit;
5510 }
5511
5512 outfile = BIO_new_file(outfilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
5513 if (outfile == NULL) {
5514 php_openssl_store_errors();
5515 php_error_docref(NULL, E_WARNING, "error opening output file %s!", outfilename);
5516 goto clean_exit;
5517 }
5518
5519 p7 = PKCS7_sign(cert, privkey, others, infile, (int)flags);
5520 if (p7 == NULL) {
5521 php_openssl_store_errors();
5522 php_error_docref(NULL, E_WARNING, "error creating PKCS7 structure!");
5523 goto clean_exit;
5524 }
5525
5526 (void)BIO_reset(infile);
5527
5528 /* tack on extra headers */
5529 if (zheaders) {
5530 int ret;
5531
5532 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, hval) {
5533 convert_to_string_ex(hval);
5534
5535 if (strindex) {
5536 ret = BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(hval));
5537 } else {
5538 ret = BIO_printf(outfile, "%s\n", Z_STRVAL_P(hval));
5539 }
5540 if (ret < 0) {
5541 php_openssl_store_errors();
5542 }
5543 } ZEND_HASH_FOREACH_END();
5544 }
5545 /* write the signed data */
5546 if (!SMIME_write_PKCS7(outfile, p7, infile, (int)flags)) {
5547 php_openssl_store_errors();
5548 goto clean_exit;
5549 }
5550
5551 RETVAL_TRUE;
5552
5553 clean_exit:
5554 PKCS7_free(p7);
5555 BIO_free(infile);
5556 BIO_free(outfile);
5557 if (others) {
5558 sk_X509_pop_free(others, X509_free);
5559 }
5560 if (privkey && keyresource == NULL) {
5561 EVP_PKEY_free(privkey);
5562 }
5563 if (cert && certresource == NULL) {
5564 X509_free(cert);
5565 }
5566 }
5567 /* }}} */
5568
5569 /* {{{ proto bool openssl_pkcs7_decrypt(string infilename, string outfilename, mixed recipcert [, mixed recipkey])
5570 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 */
5571
PHP_FUNCTION(openssl_pkcs7_decrypt)5572 PHP_FUNCTION(openssl_pkcs7_decrypt)
5573 {
5574 zval * recipcert, * recipkey = NULL;
5575 X509 * cert = NULL;
5576 EVP_PKEY * key = NULL;
5577 zend_resource *certresval, *keyresval;
5578 BIO * in = NULL, * out = NULL, * datain = NULL;
5579 PKCS7 * p7 = NULL;
5580 char * infilename;
5581 size_t infilename_len;
5582 char * outfilename;
5583 size_t outfilename_len;
5584
5585 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppz|z", &infilename, &infilename_len,
5586 &outfilename, &outfilename_len, &recipcert, &recipkey) == FAILURE) {
5587 return;
5588 }
5589
5590 RETVAL_FALSE;
5591
5592 cert = php_openssl_x509_from_zval(recipcert, 0, &certresval);
5593 if (cert == NULL) {
5594 php_error_docref(NULL, E_WARNING, "unable to coerce parameter 3 to x509 cert");
5595 goto clean_exit;
5596 }
5597
5598 key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, 0, &keyresval);
5599 if (key == NULL) {
5600 php_error_docref(NULL, E_WARNING, "unable to get private key");
5601 goto clean_exit;
5602 }
5603
5604 if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
5605 goto clean_exit;
5606 }
5607
5608 in = BIO_new_file(infilename, PHP_OPENSSL_BIO_MODE_R(PKCS7_BINARY));
5609 if (in == NULL) {
5610 php_openssl_store_errors();
5611 goto clean_exit;
5612 }
5613 out = BIO_new_file(outfilename, PHP_OPENSSL_BIO_MODE_W(PKCS7_BINARY));
5614 if (out == NULL) {
5615 php_openssl_store_errors();
5616 goto clean_exit;
5617 }
5618
5619 p7 = SMIME_read_PKCS7(in, &datain);
5620
5621 if (p7 == NULL) {
5622 php_openssl_store_errors();
5623 goto clean_exit;
5624 }
5625 if (PKCS7_decrypt(p7, key, cert, out, PKCS7_DETACHED)) {
5626 RETVAL_TRUE;
5627 } else {
5628 php_openssl_store_errors();
5629 }
5630 clean_exit:
5631 PKCS7_free(p7);
5632 BIO_free(datain);
5633 BIO_free(in);
5634 BIO_free(out);
5635 if (cert && certresval == NULL) {
5636 X509_free(cert);
5637 }
5638 if (key && keyresval == NULL) {
5639 EVP_PKEY_free(key);
5640 }
5641 }
5642 /* }}} */
5643
5644 /* }}} */
5645
5646 /* {{{ proto bool openssl_private_encrypt(string data, string &crypted, mixed key [, int padding])
5647 Encrypts data with private key */
PHP_FUNCTION(openssl_private_encrypt)5648 PHP_FUNCTION(openssl_private_encrypt)
5649 {
5650 zval *key, *crypted;
5651 EVP_PKEY *pkey;
5652 int cryptedlen;
5653 zend_string *cryptedbuf = NULL;
5654 int successful = 0;
5655 zend_resource *keyresource = NULL;
5656 char * data;
5657 size_t data_len;
5658 zend_long padding = RSA_PKCS1_PADDING;
5659
5660 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
5661 return;
5662 }
5663 RETVAL_FALSE;
5664
5665 pkey = php_openssl_evp_from_zval(key, 0, "", 0, 0, &keyresource);
5666
5667 if (pkey == NULL) {
5668 php_error_docref(NULL, E_WARNING, "key param is not a valid private key");
5669 RETURN_FALSE;
5670 }
5671
5672 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
5673
5674 cryptedlen = EVP_PKEY_size(pkey);
5675 cryptedbuf = zend_string_alloc(cryptedlen, 0);
5676
5677 switch (EVP_PKEY_id(pkey)) {
5678 case EVP_PKEY_RSA:
5679 case EVP_PKEY_RSA2:
5680 successful = (RSA_private_encrypt((int)data_len,
5681 (unsigned char *)data,
5682 (unsigned char *)ZSTR_VAL(cryptedbuf),
5683 EVP_PKEY_get0_RSA(pkey),
5684 (int)padding) == cryptedlen);
5685 break;
5686 default:
5687 php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
5688 }
5689
5690 if (successful) {
5691 zval_ptr_dtor(crypted);
5692 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
5693 ZVAL_NEW_STR(crypted, cryptedbuf);
5694 cryptedbuf = NULL;
5695 RETVAL_TRUE;
5696 } else {
5697 php_openssl_store_errors();
5698 }
5699 if (cryptedbuf) {
5700 zend_string_release_ex(cryptedbuf, 0);
5701 }
5702 if (keyresource == NULL) {
5703 EVP_PKEY_free(pkey);
5704 }
5705 }
5706 /* }}} */
5707
5708 /* {{{ proto bool openssl_private_decrypt(string data, string &decrypted, mixed key [, int padding])
5709 Decrypts data with private key */
PHP_FUNCTION(openssl_private_decrypt)5710 PHP_FUNCTION(openssl_private_decrypt)
5711 {
5712 zval *key, *crypted;
5713 EVP_PKEY *pkey;
5714 int cryptedlen;
5715 zend_string *cryptedbuf = NULL;
5716 unsigned char *crypttemp;
5717 int successful = 0;
5718 zend_long padding = RSA_PKCS1_PADDING;
5719 zend_resource *keyresource = NULL;
5720 char * data;
5721 size_t data_len;
5722
5723 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
5724 return;
5725 }
5726 RETVAL_FALSE;
5727
5728 pkey = php_openssl_evp_from_zval(key, 0, "", 0, 0, &keyresource);
5729 if (pkey == NULL) {
5730 php_error_docref(NULL, E_WARNING, "key parameter is not a valid private key");
5731 RETURN_FALSE;
5732 }
5733
5734 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
5735
5736 cryptedlen = EVP_PKEY_size(pkey);
5737 crypttemp = emalloc(cryptedlen + 1);
5738
5739 switch (EVP_PKEY_id(pkey)) {
5740 case EVP_PKEY_RSA:
5741 case EVP_PKEY_RSA2:
5742 cryptedlen = RSA_private_decrypt((int)data_len,
5743 (unsigned char *)data,
5744 crypttemp,
5745 EVP_PKEY_get0_RSA(pkey),
5746 (int)padding);
5747 if (cryptedlen != -1) {
5748 cryptedbuf = zend_string_alloc(cryptedlen, 0);
5749 memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen);
5750 successful = 1;
5751 }
5752 break;
5753 default:
5754 php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
5755 }
5756
5757 efree(crypttemp);
5758
5759 if (successful) {
5760 zval_ptr_dtor(crypted);
5761 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
5762 ZVAL_NEW_STR(crypted, cryptedbuf);
5763 cryptedbuf = NULL;
5764 RETVAL_TRUE;
5765 } else {
5766 php_openssl_store_errors();
5767 }
5768
5769 if (keyresource == NULL) {
5770 EVP_PKEY_free(pkey);
5771 }
5772 if (cryptedbuf) {
5773 zend_string_release_ex(cryptedbuf, 0);
5774 }
5775 }
5776 /* }}} */
5777
5778 /* {{{ proto bool openssl_public_encrypt(string data, string &crypted, mixed key [, int padding])
5779 Encrypts data with public key */
PHP_FUNCTION(openssl_public_encrypt)5780 PHP_FUNCTION(openssl_public_encrypt)
5781 {
5782 zval *key, *crypted;
5783 EVP_PKEY *pkey;
5784 int cryptedlen;
5785 zend_string *cryptedbuf;
5786 int successful = 0;
5787 zend_resource *keyresource = NULL;
5788 zend_long padding = RSA_PKCS1_PADDING;
5789 char * data;
5790 size_t data_len;
5791
5792 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE)
5793 return;
5794 RETVAL_FALSE;
5795
5796 pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, 0, &keyresource);
5797 if (pkey == NULL) {
5798 php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key");
5799 RETURN_FALSE;
5800 }
5801
5802 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
5803
5804 cryptedlen = EVP_PKEY_size(pkey);
5805 cryptedbuf = zend_string_alloc(cryptedlen, 0);
5806
5807 switch (EVP_PKEY_id(pkey)) {
5808 case EVP_PKEY_RSA:
5809 case EVP_PKEY_RSA2:
5810 successful = (RSA_public_encrypt((int)data_len,
5811 (unsigned char *)data,
5812 (unsigned char *)ZSTR_VAL(cryptedbuf),
5813 EVP_PKEY_get0_RSA(pkey),
5814 (int)padding) == cryptedlen);
5815 break;
5816 default:
5817 php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
5818
5819 }
5820
5821 if (successful) {
5822 zval_ptr_dtor(crypted);
5823 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
5824 ZVAL_NEW_STR(crypted, cryptedbuf);
5825 cryptedbuf = NULL;
5826 RETVAL_TRUE;
5827 } else {
5828 php_openssl_store_errors();
5829 }
5830 if (keyresource == NULL) {
5831 EVP_PKEY_free(pkey);
5832 }
5833 if (cryptedbuf) {
5834 zend_string_release_ex(cryptedbuf, 0);
5835 }
5836 }
5837 /* }}} */
5838
5839 /* {{{ proto bool openssl_public_decrypt(string data, string &crypted, resource key [, int padding])
5840 Decrypts data with public key */
PHP_FUNCTION(openssl_public_decrypt)5841 PHP_FUNCTION(openssl_public_decrypt)
5842 {
5843 zval *key, *crypted;
5844 EVP_PKEY *pkey;
5845 int cryptedlen;
5846 zend_string *cryptedbuf = NULL;
5847 unsigned char *crypttemp;
5848 int successful = 0;
5849 zend_resource *keyresource = NULL;
5850 zend_long padding = RSA_PKCS1_PADDING;
5851 char * data;
5852 size_t data_len;
5853
5854 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
5855 return;
5856 }
5857 RETVAL_FALSE;
5858
5859 pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, 0, &keyresource);
5860 if (pkey == NULL) {
5861 php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key");
5862 RETURN_FALSE;
5863 }
5864
5865 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
5866
5867 cryptedlen = EVP_PKEY_size(pkey);
5868 crypttemp = emalloc(cryptedlen + 1);
5869
5870 switch (EVP_PKEY_id(pkey)) {
5871 case EVP_PKEY_RSA:
5872 case EVP_PKEY_RSA2:
5873 cryptedlen = RSA_public_decrypt((int)data_len,
5874 (unsigned char *)data,
5875 crypttemp,
5876 EVP_PKEY_get0_RSA(pkey),
5877 (int)padding);
5878 if (cryptedlen != -1) {
5879 cryptedbuf = zend_string_alloc(cryptedlen, 0);
5880 memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen);
5881 successful = 1;
5882 }
5883 break;
5884
5885 default:
5886 php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
5887
5888 }
5889
5890 efree(crypttemp);
5891
5892 if (successful) {
5893 zval_ptr_dtor(crypted);
5894 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
5895 ZVAL_NEW_STR(crypted, cryptedbuf);
5896 cryptedbuf = NULL;
5897 RETVAL_TRUE;
5898 } else {
5899 php_openssl_store_errors();
5900 }
5901
5902 if (cryptedbuf) {
5903 zend_string_release_ex(cryptedbuf, 0);
5904 }
5905 if (keyresource == NULL) {
5906 EVP_PKEY_free(pkey);
5907 }
5908 }
5909 /* }}} */
5910
5911 /* {{{ proto mixed openssl_error_string(void)
5912 Returns a description of the last error, and alters the index of the error messages. Returns false when the are no more messages */
PHP_FUNCTION(openssl_error_string)5913 PHP_FUNCTION(openssl_error_string)
5914 {
5915 char buf[256];
5916 unsigned long val;
5917
5918 if (zend_parse_parameters_none() == FAILURE) {
5919 return;
5920 }
5921
5922 php_openssl_store_errors();
5923
5924 if (OPENSSL_G(errors) == NULL || OPENSSL_G(errors)->top == OPENSSL_G(errors)->bottom) {
5925 RETURN_FALSE;
5926 }
5927
5928 OPENSSL_G(errors)->bottom = (OPENSSL_G(errors)->bottom + 1) % ERR_NUM_ERRORS;
5929 val = OPENSSL_G(errors)->buffer[OPENSSL_G(errors)->bottom];
5930
5931 if (val) {
5932 ERR_error_string_n(val, buf, 256);
5933 RETURN_STRING(buf);
5934 } else {
5935 RETURN_FALSE;
5936 }
5937 }
5938 /* }}} */
5939
5940 /* {{{ proto bool openssl_sign(string data, &string signature, mixed key[, mixed method])
5941 Signs data */
PHP_FUNCTION(openssl_sign)5942 PHP_FUNCTION(openssl_sign)
5943 {
5944 zval *key, *signature;
5945 EVP_PKEY *pkey;
5946 unsigned int siglen;
5947 zend_string *sigbuf;
5948 zend_resource *keyresource = NULL;
5949 char * data;
5950 size_t data_len;
5951 EVP_MD_CTX *md_ctx;
5952 zval *method = NULL;
5953 zend_long signature_algo = OPENSSL_ALGO_SHA1;
5954 const EVP_MD *mdtype;
5955
5956 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|z", &data, &data_len, &signature, &key, &method) == FAILURE) {
5957 return;
5958 }
5959 pkey = php_openssl_evp_from_zval(key, 0, "", 0, 0, &keyresource);
5960 if (pkey == NULL) {
5961 php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a private key");
5962 RETURN_FALSE;
5963 }
5964
5965 if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
5966 if (method != NULL) {
5967 signature_algo = Z_LVAL_P(method);
5968 }
5969 mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
5970 } else if (Z_TYPE_P(method) == IS_STRING) {
5971 mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
5972 } else {
5973 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
5974 RETURN_FALSE;
5975 }
5976 if (!mdtype) {
5977 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
5978 RETURN_FALSE;
5979 }
5980
5981 siglen = EVP_PKEY_size(pkey);
5982 sigbuf = zend_string_alloc(siglen, 0);
5983
5984 md_ctx = EVP_MD_CTX_create();
5985 if (md_ctx != NULL &&
5986 EVP_SignInit(md_ctx, mdtype) &&
5987 EVP_SignUpdate(md_ctx, data, data_len) &&
5988 EVP_SignFinal(md_ctx, (unsigned char*)ZSTR_VAL(sigbuf), &siglen, pkey)) {
5989 zval_ptr_dtor(signature);
5990 ZSTR_VAL(sigbuf)[siglen] = '\0';
5991 ZSTR_LEN(sigbuf) = siglen;
5992 ZVAL_NEW_STR(signature, sigbuf);
5993 RETVAL_TRUE;
5994 } else {
5995 php_openssl_store_errors();
5996 efree(sigbuf);
5997 RETVAL_FALSE;
5998 }
5999 EVP_MD_CTX_destroy(md_ctx);
6000 if (keyresource == NULL) {
6001 EVP_PKEY_free(pkey);
6002 }
6003 }
6004 /* }}} */
6005
6006 /* {{{ proto int openssl_verify(string data, string signature, mixed key[, mixed method])
6007 Verifys data */
PHP_FUNCTION(openssl_verify)6008 PHP_FUNCTION(openssl_verify)
6009 {
6010 zval *key;
6011 EVP_PKEY *pkey;
6012 int err = 0;
6013 EVP_MD_CTX *md_ctx;
6014 const EVP_MD *mdtype;
6015 zend_resource *keyresource = NULL;
6016 char * data;
6017 size_t data_len;
6018 char * signature;
6019 size_t signature_len;
6020 zval *method = NULL;
6021 zend_long signature_algo = OPENSSL_ALGO_SHA1;
6022
6023 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssz|z", &data, &data_len, &signature, &signature_len, &key, &method) == FAILURE) {
6024 return;
6025 }
6026
6027 PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(signature_len, signature);
6028
6029 if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
6030 if (method != NULL) {
6031 signature_algo = Z_LVAL_P(method);
6032 }
6033 mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
6034 } else if (Z_TYPE_P(method) == IS_STRING) {
6035 mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
6036 } else {
6037 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
6038 RETURN_FALSE;
6039 }
6040 if (!mdtype) {
6041 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
6042 RETURN_FALSE;
6043 }
6044
6045 pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, 0, &keyresource);
6046 if (pkey == NULL) {
6047 php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a public key");
6048 RETURN_FALSE;
6049 }
6050
6051 md_ctx = EVP_MD_CTX_create();
6052 if (md_ctx == NULL ||
6053 !EVP_VerifyInit (md_ctx, mdtype) ||
6054 !EVP_VerifyUpdate (md_ctx, data, data_len) ||
6055 (err = EVP_VerifyFinal(md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey)) < 0) {
6056 php_openssl_store_errors();
6057 }
6058 EVP_MD_CTX_destroy(md_ctx);
6059
6060 if (keyresource == NULL) {
6061 EVP_PKEY_free(pkey);
6062 }
6063 RETURN_LONG(err);
6064 }
6065 /* }}} */
6066
6067 /* {{{ proto int openssl_seal(string data, &string sealdata, &array ekeys, array pubkeys [, string method [, &string iv]]))
6068 Seals data */
PHP_FUNCTION(openssl_seal)6069 PHP_FUNCTION(openssl_seal)
6070 {
6071 zval *pubkeys, *pubkey, *sealdata, *ekeys, *iv = NULL;
6072 HashTable *pubkeysht;
6073 EVP_PKEY **pkeys;
6074 zend_resource ** key_resources; /* so we know what to cleanup */
6075 int i, len1, len2, *eksl, nkeys, iv_len;
6076 unsigned char iv_buf[EVP_MAX_IV_LENGTH + 1], *buf = NULL, **eks;
6077 char * data;
6078 size_t data_len;
6079 char *method =NULL;
6080 size_t method_len = 0;
6081 const EVP_CIPHER *cipher;
6082 EVP_CIPHER_CTX *ctx;
6083
6084 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z/a|sz/", &data, &data_len,
6085 &sealdata, &ekeys, &pubkeys, &method, &method_len, &iv) == FAILURE) {
6086 return;
6087 }
6088 pubkeysht = Z_ARRVAL_P(pubkeys);
6089 nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0;
6090 if (!nkeys) {
6091 php_error_docref(NULL, E_WARNING, "Fourth argument to openssl_seal() must be a non-empty array");
6092 RETURN_FALSE;
6093 }
6094
6095 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
6096
6097 if (method) {
6098 cipher = EVP_get_cipherbyname(method);
6099 if (!cipher) {
6100 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
6101 RETURN_FALSE;
6102 }
6103 } else {
6104 cipher = EVP_rc4();
6105 }
6106
6107 iv_len = EVP_CIPHER_iv_length(cipher);
6108 if (!iv && iv_len > 0) {
6109 php_error_docref(NULL, E_WARNING,
6110 "Cipher algorithm requires an IV to be supplied as a sixth parameter");
6111 RETURN_FALSE;
6112 }
6113
6114 pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
6115 eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
6116 eks = safe_emalloc(nkeys, sizeof(*eks), 0);
6117 memset(eks, 0, sizeof(*eks) * nkeys);
6118 key_resources = safe_emalloc(nkeys, sizeof(zend_resource*), 0);
6119 memset(key_resources, 0, sizeof(zend_resource*) * nkeys);
6120 memset(pkeys, 0, sizeof(*pkeys) * nkeys);
6121
6122 /* get the public keys we are using to seal this data */
6123 i = 0;
6124 ZEND_HASH_FOREACH_VAL(pubkeysht, pubkey) {
6125 pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, 0, &key_resources[i]);
6126 if (pkeys[i] == NULL) {
6127 php_error_docref(NULL, E_WARNING, "not a public key (%dth member of pubkeys)", i+1);
6128 RETVAL_FALSE;
6129 goto clean_exit;
6130 }
6131 eks[i] = emalloc(EVP_PKEY_size(pkeys[i]) + 1);
6132 i++;
6133 } ZEND_HASH_FOREACH_END();
6134
6135 ctx = EVP_CIPHER_CTX_new();
6136 if (ctx == NULL || !EVP_EncryptInit(ctx,cipher,NULL,NULL)) {
6137 EVP_CIPHER_CTX_free(ctx);
6138 php_openssl_store_errors();
6139 RETVAL_FALSE;
6140 goto clean_exit;
6141 }
6142
6143 /* allocate one byte extra to make room for \0 */
6144 buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(ctx));
6145 EVP_CIPHER_CTX_cleanup(ctx);
6146
6147 if (EVP_SealInit(ctx, cipher, eks, eksl, &iv_buf[0], pkeys, nkeys) <= 0 ||
6148 !EVP_SealUpdate(ctx, buf, &len1, (unsigned char *)data, (int)data_len) ||
6149 !EVP_SealFinal(ctx, buf + len1, &len2)) {
6150 efree(buf);
6151 EVP_CIPHER_CTX_free(ctx);
6152 php_openssl_store_errors();
6153 RETVAL_FALSE;
6154 goto clean_exit;
6155 }
6156
6157 if (len1 + len2 > 0) {
6158 zval_ptr_dtor(sealdata);
6159 ZVAL_NEW_STR(sealdata, zend_string_init((char*)buf, len1 + len2, 0));
6160 efree(buf);
6161
6162 zval_ptr_dtor(ekeys);
6163 array_init(ekeys);
6164 for (i=0; i<nkeys; i++) {
6165 eks[i][eksl[i]] = '\0';
6166 add_next_index_stringl(ekeys, (const char*)eks[i], eksl[i]);
6167 efree(eks[i]);
6168 eks[i] = NULL;
6169 }
6170
6171 if (iv) {
6172 zval_ptr_dtor(iv);
6173 iv_buf[iv_len] = '\0';
6174 ZVAL_NEW_STR(iv, zend_string_init((char*)iv_buf, iv_len, 0));
6175 }
6176 } else {
6177 efree(buf);
6178 }
6179 RETVAL_LONG(len1 + len2);
6180 EVP_CIPHER_CTX_free(ctx);
6181
6182 clean_exit:
6183 for (i=0; i<nkeys; i++) {
6184 if (key_resources[i] == NULL && pkeys[i] != NULL) {
6185 EVP_PKEY_free(pkeys[i]);
6186 }
6187 if (eks[i]) {
6188 efree(eks[i]);
6189 }
6190 }
6191 efree(eks);
6192 efree(eksl);
6193 efree(pkeys);
6194 efree(key_resources);
6195 }
6196 /* }}} */
6197
6198 /* {{{ proto bool openssl_open(string data, &string opendata, string ekey, mixed privkey [, string method [, string iv]])
6199 Opens data */
PHP_FUNCTION(openssl_open)6200 PHP_FUNCTION(openssl_open)
6201 {
6202 zval *privkey, *opendata;
6203 EVP_PKEY *pkey;
6204 int len1, len2, cipher_iv_len;
6205 unsigned char *buf, *iv_buf;
6206 zend_resource *keyresource = NULL;
6207 EVP_CIPHER_CTX *ctx;
6208 char * data;
6209 size_t data_len;
6210 char * ekey;
6211 size_t ekey_len;
6212 char *method = NULL, *iv = NULL;
6213 size_t method_len = 0, iv_len = 0;
6214 const EVP_CIPHER *cipher;
6215
6216 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/sz|ss", &data, &data_len, &opendata,
6217 &ekey, &ekey_len, &privkey, &method, &method_len, &iv, &iv_len) == FAILURE) {
6218 return;
6219 }
6220
6221 pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, 0, &keyresource);
6222 if (pkey == NULL) {
6223 php_error_docref(NULL, E_WARNING, "unable to coerce parameter 4 into a private key");
6224 RETURN_FALSE;
6225 }
6226
6227 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(ekey_len, ekey);
6228 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
6229
6230 if (method) {
6231 cipher = EVP_get_cipherbyname(method);
6232 if (!cipher) {
6233 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
6234 RETURN_FALSE;
6235 }
6236 } else {
6237 cipher = EVP_rc4();
6238 }
6239
6240 cipher_iv_len = EVP_CIPHER_iv_length(cipher);
6241 if (cipher_iv_len > 0) {
6242 if (!iv) {
6243 php_error_docref(NULL, E_WARNING,
6244 "Cipher algorithm requires an IV to be supplied as a sixth parameter");
6245 RETURN_FALSE;
6246 }
6247 if ((size_t)cipher_iv_len != iv_len) {
6248 php_error_docref(NULL, E_WARNING, "IV length is invalid");
6249 RETURN_FALSE;
6250 }
6251 iv_buf = (unsigned char *)iv;
6252 } else {
6253 iv_buf = NULL;
6254 }
6255
6256 buf = emalloc(data_len + 1);
6257
6258 ctx = EVP_CIPHER_CTX_new();
6259 if (ctx != NULL && EVP_OpenInit(ctx, cipher, (unsigned char *)ekey, (int)ekey_len, iv_buf, pkey) &&
6260 EVP_OpenUpdate(ctx, buf, &len1, (unsigned char *)data, (int)data_len) &&
6261 EVP_OpenFinal(ctx, buf + len1, &len2) && (len1 + len2 > 0)) {
6262 zval_ptr_dtor(opendata);
6263 buf[len1 + len2] = '\0';
6264 ZVAL_NEW_STR(opendata, zend_string_init((char*)buf, len1 + len2, 0));
6265 RETVAL_TRUE;
6266 } else {
6267 php_openssl_store_errors();
6268 RETVAL_FALSE;
6269 }
6270
6271 efree(buf);
6272 if (keyresource == NULL) {
6273 EVP_PKEY_free(pkey);
6274 }
6275 EVP_CIPHER_CTX_free(ctx);
6276 }
6277 /* }}} */
6278
php_openssl_add_method_or_alias(const OBJ_NAME * name,void * arg)6279 static void php_openssl_add_method_or_alias(const OBJ_NAME *name, void *arg) /* {{{ */
6280 {
6281 add_next_index_string((zval*)arg, (char*)name->name);
6282 }
6283 /* }}} */
6284
php_openssl_add_method(const OBJ_NAME * name,void * arg)6285 static void php_openssl_add_method(const OBJ_NAME *name, void *arg) /* {{{ */
6286 {
6287 if (name->alias == 0) {
6288 add_next_index_string((zval*)arg, (char*)name->name);
6289 }
6290 }
6291 /* }}} */
6292
6293 /* {{{ proto array openssl_get_md_methods([bool aliases = false])
6294 Return array of available digest methods */
PHP_FUNCTION(openssl_get_md_methods)6295 PHP_FUNCTION(openssl_get_md_methods)
6296 {
6297 zend_bool aliases = 0;
6298
6299 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &aliases) == FAILURE) {
6300 return;
6301 }
6302 array_init(return_value);
6303 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
6304 aliases ? php_openssl_add_method_or_alias: php_openssl_add_method,
6305 return_value);
6306 }
6307 /* }}} */
6308
6309 /* {{{ proto array openssl_get_cipher_methods([bool aliases = false])
6310 Return array of available cipher methods */
PHP_FUNCTION(openssl_get_cipher_methods)6311 PHP_FUNCTION(openssl_get_cipher_methods)
6312 {
6313 zend_bool aliases = 0;
6314
6315 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &aliases) == FAILURE) {
6316 return;
6317 }
6318 array_init(return_value);
6319 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
6320 aliases ? php_openssl_add_method_or_alias: php_openssl_add_method,
6321 return_value);
6322 }
6323 /* }}} */
6324
6325 /* {{{ proto array openssl_get_curve_names()
6326 Return array of available elliptic curves */
6327 #ifdef HAVE_EVP_PKEY_EC
PHP_FUNCTION(openssl_get_curve_names)6328 PHP_FUNCTION(openssl_get_curve_names)
6329 {
6330 EC_builtin_curve *curves = NULL;
6331 const char *sname;
6332 size_t i;
6333 size_t len = EC_get_builtin_curves(NULL, 0);
6334
6335 curves = emalloc(sizeof(EC_builtin_curve) * len);
6336 if (!EC_get_builtin_curves(curves, len)) {
6337 RETURN_FALSE;
6338 }
6339
6340 array_init(return_value);
6341 for (i = 0; i < len; i++) {
6342 sname = OBJ_nid2sn(curves[i].nid);
6343 if (sname != NULL) {
6344 add_next_index_string(return_value, sname);
6345 }
6346 }
6347 efree(curves);
6348 }
6349 #endif
6350 /* }}} */
6351
6352 /* {{{ proto string openssl_digest(string data, string method [, bool raw_output=false])
6353 Computes digest hash value for given data using given method, returns raw or binhex encoded string */
PHP_FUNCTION(openssl_digest)6354 PHP_FUNCTION(openssl_digest)
6355 {
6356 zend_bool raw_output = 0;
6357 char *data, *method;
6358 size_t data_len, method_len;
6359 const EVP_MD *mdtype;
6360 EVP_MD_CTX *md_ctx;
6361 unsigned int siglen;
6362 zend_string *sigbuf;
6363
6364 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|b", &data, &data_len, &method, &method_len, &raw_output) == FAILURE) {
6365 return;
6366 }
6367 mdtype = EVP_get_digestbyname(method);
6368 if (!mdtype) {
6369 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
6370 RETURN_FALSE;
6371 }
6372
6373 siglen = EVP_MD_size(mdtype);
6374 sigbuf = zend_string_alloc(siglen, 0);
6375
6376 md_ctx = EVP_MD_CTX_create();
6377 if (EVP_DigestInit(md_ctx, mdtype) &&
6378 EVP_DigestUpdate(md_ctx, (unsigned char *)data, data_len) &&
6379 EVP_DigestFinal (md_ctx, (unsigned char *)ZSTR_VAL(sigbuf), &siglen)) {
6380 if (raw_output) {
6381 ZSTR_VAL(sigbuf)[siglen] = '\0';
6382 ZSTR_LEN(sigbuf) = siglen;
6383 RETVAL_STR(sigbuf);
6384 } else {
6385 int digest_str_len = siglen * 2;
6386 zend_string *digest_str = zend_string_alloc(digest_str_len, 0);
6387
6388 make_digest_ex(ZSTR_VAL(digest_str), (unsigned char*)ZSTR_VAL(sigbuf), siglen);
6389 ZSTR_VAL(digest_str)[digest_str_len] = '\0';
6390 zend_string_release_ex(sigbuf, 0);
6391 RETVAL_NEW_STR(digest_str);
6392 }
6393 } else {
6394 php_openssl_store_errors();
6395 zend_string_release_ex(sigbuf, 0);
6396 RETVAL_FALSE;
6397 }
6398
6399 EVP_MD_CTX_destroy(md_ctx);
6400 }
6401 /* }}} */
6402
6403 /* Cipher mode info */
6404 struct php_openssl_cipher_mode {
6405 zend_bool is_aead;
6406 zend_bool is_single_run_aead;
6407 int aead_get_tag_flag;
6408 int aead_set_tag_flag;
6409 int aead_ivlen_flag;
6410 };
6411
php_openssl_load_cipher_mode(struct php_openssl_cipher_mode * mode,const EVP_CIPHER * cipher_type)6412 static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EVP_CIPHER *cipher_type) /* {{{ */
6413 {
6414 switch (EVP_CIPHER_mode(cipher_type)) {
6415 #ifdef EVP_CIPH_GCM_MODE
6416 case EVP_CIPH_GCM_MODE:
6417 mode->is_aead = 1;
6418 mode->is_single_run_aead = 0;
6419 mode->aead_get_tag_flag = EVP_CTRL_GCM_GET_TAG;
6420 mode->aead_set_tag_flag = EVP_CTRL_GCM_SET_TAG;
6421 mode->aead_ivlen_flag = EVP_CTRL_GCM_SET_IVLEN;
6422 break;
6423 #endif
6424 #ifdef EVP_CIPH_CCM_MODE
6425 case EVP_CIPH_CCM_MODE:
6426 mode->is_aead = 1;
6427 mode->is_single_run_aead = 1;
6428 mode->aead_get_tag_flag = EVP_CTRL_CCM_GET_TAG;
6429 mode->aead_set_tag_flag = EVP_CTRL_CCM_SET_TAG;
6430 mode->aead_ivlen_flag = EVP_CTRL_CCM_SET_IVLEN;
6431 break;
6432 #endif
6433 default:
6434 memset(mode, 0, sizeof(struct php_openssl_cipher_mode));
6435 }
6436 }
6437 /* }}} */
6438
php_openssl_validate_iv(char ** piv,size_t * piv_len,size_t iv_required_len,zend_bool * free_iv,EVP_CIPHER_CTX * cipher_ctx,struct php_openssl_cipher_mode * mode)6439 static int php_openssl_validate_iv(char **piv, size_t *piv_len, size_t iv_required_len,
6440 zend_bool *free_iv, EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode) /* {{{ */
6441 {
6442 char *iv_new;
6443
6444 if (mode->is_aead) {
6445 if (EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_ivlen_flag, *piv_len, NULL) != 1) {
6446 php_error_docref(NULL, E_WARNING, "Setting of IV length for AEAD mode failed");
6447 return FAILURE;
6448 }
6449 return SUCCESS;
6450 }
6451
6452 /* Best case scenario, user behaved */
6453 if (*piv_len == iv_required_len) {
6454 return SUCCESS;
6455 }
6456
6457 iv_new = ecalloc(1, iv_required_len + 1);
6458
6459 if (*piv_len == 0) {
6460 /* BC behavior */
6461 *piv_len = iv_required_len;
6462 *piv = iv_new;
6463 *free_iv = 1;
6464 return SUCCESS;
6465
6466 }
6467
6468 if (*piv_len < iv_required_len) {
6469 php_error_docref(NULL, E_WARNING,
6470 "IV passed is only %zd bytes long, cipher expects an IV of precisely %zd bytes, padding with \\0",
6471 *piv_len, iv_required_len);
6472 memcpy(iv_new, *piv, *piv_len);
6473 *piv_len = iv_required_len;
6474 *piv = iv_new;
6475 *free_iv = 1;
6476 return SUCCESS;
6477 }
6478
6479 php_error_docref(NULL, E_WARNING,
6480 "IV passed is %zd bytes long which is longer than the %zd expected by selected cipher, truncating",
6481 *piv_len, iv_required_len);
6482 memcpy(iv_new, *piv, iv_required_len);
6483 *piv_len = iv_required_len;
6484 *piv = iv_new;
6485 *free_iv = 1;
6486 return SUCCESS;
6487
6488 }
6489 /* }}} */
6490
php_openssl_cipher_init(const EVP_CIPHER * cipher_type,EVP_CIPHER_CTX * cipher_ctx,struct php_openssl_cipher_mode * mode,char ** ppassword,size_t * ppassword_len,zend_bool * free_password,char ** piv,size_t * piv_len,zend_bool * free_iv,char * tag,int tag_len,zend_long options,int enc)6491 static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type,
6492 EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode,
6493 char **ppassword, size_t *ppassword_len, zend_bool *free_password,
6494 char **piv, size_t *piv_len, zend_bool *free_iv,
6495 char *tag, int tag_len, zend_long options, int enc) /* {{{ */
6496 {
6497 unsigned char *key;
6498 int key_len, password_len;
6499 size_t max_iv_len;
6500
6501 *free_password = 0;
6502
6503 max_iv_len = EVP_CIPHER_iv_length(cipher_type);
6504 if (enc && *piv_len == 0 && max_iv_len > 0 && !mode->is_aead) {
6505 php_error_docref(NULL, E_WARNING,
6506 "Using an empty Initialization Vector (iv) is potentially insecure and not recommended");
6507 }
6508
6509 if (!EVP_CipherInit_ex(cipher_ctx, cipher_type, NULL, NULL, NULL, enc)) {
6510 php_openssl_store_errors();
6511 return FAILURE;
6512 }
6513 if (php_openssl_validate_iv(piv, piv_len, max_iv_len, free_iv, cipher_ctx, mode) == FAILURE) {
6514 return FAILURE;
6515 }
6516 if (mode->is_single_run_aead && enc) {
6517 if (!EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, NULL)) {
6518 php_error_docref(NULL, E_WARNING, "Setting tag length for AEAD cipher failed");
6519 return FAILURE;
6520 }
6521 } else if (!enc && tag && tag_len > 0) {
6522 if (!mode->is_aead) {
6523 php_error_docref(NULL, E_WARNING, "The tag cannot be used because the cipher method does not support AEAD");
6524 } else if (!EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, (unsigned char *) tag)) {
6525 php_error_docref(NULL, E_WARNING, "Setting tag for AEAD cipher decryption failed");
6526 return FAILURE;
6527 }
6528 }
6529 /* check and set key */
6530 password_len = (int) *ppassword_len;
6531 key_len = EVP_CIPHER_key_length(cipher_type);
6532 if (key_len > password_len) {
6533 if ((OPENSSL_DONT_ZERO_PAD_KEY & options) && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) {
6534 php_openssl_store_errors();
6535 php_error_docref(NULL, E_WARNING, "Key length cannot be set for the cipher method");
6536 return FAILURE;
6537 }
6538 key = emalloc(key_len);
6539 memset(key, 0, key_len);
6540 memcpy(key, *ppassword, password_len);
6541 *ppassword = (char *) key;
6542 *ppassword_len = key_len;
6543 *free_password = 1;
6544 } else {
6545 if (password_len > key_len && !EVP_CIPHER_CTX_set_key_length(cipher_ctx, password_len)) {
6546 php_openssl_store_errors();
6547 }
6548 key = (unsigned char*)*ppassword;
6549 }
6550
6551 if (!EVP_CipherInit_ex(cipher_ctx, NULL, NULL, key, (unsigned char *)*piv, enc)) {
6552 php_openssl_store_errors();
6553 return FAILURE;
6554 }
6555 if (options & OPENSSL_ZERO_PADDING) {
6556 EVP_CIPHER_CTX_set_padding(cipher_ctx, 0);
6557 }
6558
6559 return SUCCESS;
6560 }
6561 /* }}} */
6562
php_openssl_cipher_update(const EVP_CIPHER * cipher_type,EVP_CIPHER_CTX * cipher_ctx,struct php_openssl_cipher_mode * mode,zend_string ** poutbuf,int * poutlen,char * data,size_t data_len,char * aad,size_t aad_len,int enc)6563 static int php_openssl_cipher_update(const EVP_CIPHER *cipher_type,
6564 EVP_CIPHER_CTX *cipher_ctx, struct php_openssl_cipher_mode *mode,
6565 zend_string **poutbuf, int *poutlen, char *data, size_t data_len,
6566 char *aad, size_t aad_len, int enc) /* {{{ */
6567 {
6568 int i = 0;
6569
6570 if (mode->is_single_run_aead && !EVP_CipherUpdate(cipher_ctx, NULL, &i, NULL, (int)data_len)) {
6571 php_openssl_store_errors();
6572 php_error_docref(NULL, E_WARNING, "Setting of data length failed");
6573 return FAILURE;
6574 }
6575
6576 if (mode->is_aead && !EVP_CipherUpdate(cipher_ctx, NULL, &i, (unsigned char *)aad, (int)aad_len)) {
6577 php_openssl_store_errors();
6578 php_error_docref(NULL, E_WARNING, "Setting of additional application data failed");
6579 return FAILURE;
6580 }
6581
6582 *poutbuf = zend_string_alloc((int)data_len + EVP_CIPHER_block_size(cipher_type), 0);
6583
6584 if (!EVP_CipherUpdate(cipher_ctx, (unsigned char*)ZSTR_VAL(*poutbuf),
6585 &i, (unsigned char *)data, (int)data_len)) {
6586 /* we don't show warning when we fail but if we ever do, then it should look like this:
6587 if (mode->is_single_run_aead && !enc) {
6588 php_error_docref(NULL, E_WARNING, "Tag verifycation failed");
6589 } else {
6590 php_error_docref(NULL, E_WARNING, enc ? "Encryption failed" : "Decryption failed");
6591 }
6592 */
6593 php_openssl_store_errors();
6594 zend_string_release_ex(*poutbuf, 0);
6595 return FAILURE;
6596 }
6597
6598 *poutlen = i;
6599
6600 return SUCCESS;
6601 }
6602 /* }}} */
6603
6604 /* {{{ proto string openssl_encrypt(string data, string method, string password [, int options=0 [, string $iv=''[, string &$tag = ''[, string $aad = ''[, int $tag_length = 16]]]]])
6605 Encrypts given data with given method and key, returns raw or base64 encoded string */
PHP_FUNCTION(openssl_encrypt)6606 PHP_FUNCTION(openssl_encrypt)
6607 {
6608 zend_long options = 0, tag_len = 16;
6609 char *data, *method, *password, *iv = "", *aad = "";
6610 size_t data_len, method_len, password_len, iv_len = 0, aad_len = 0;
6611 zval *tag = NULL;
6612 const EVP_CIPHER *cipher_type;
6613 EVP_CIPHER_CTX *cipher_ctx;
6614 struct php_openssl_cipher_mode mode;
6615 int i=0, outlen;
6616 zend_string *outbuf;
6617 zend_bool free_iv = 0, free_password = 0;
6618
6619 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|lsz/sl", &data, &data_len, &method, &method_len,
6620 &password, &password_len, &options, &iv, &iv_len, &tag, &aad, &aad_len, &tag_len) == FAILURE) {
6621 return;
6622 }
6623
6624 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
6625 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password);
6626 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(aad_len, aad);
6627 PHP_OPENSSL_CHECK_LONG_TO_INT(tag_len, tag_len);
6628
6629 cipher_type = EVP_get_cipherbyname(method);
6630 if (!cipher_type) {
6631 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
6632 RETURN_FALSE;
6633 }
6634
6635 cipher_ctx = EVP_CIPHER_CTX_new();
6636 if (!cipher_ctx) {
6637 php_error_docref(NULL, E_WARNING, "Failed to create cipher context");
6638 RETURN_FALSE;
6639 }
6640 php_openssl_load_cipher_mode(&mode, cipher_type);
6641
6642 if (php_openssl_cipher_init(cipher_type, cipher_ctx, &mode,
6643 &password, &password_len, &free_password,
6644 &iv, &iv_len, &free_iv, NULL, tag_len, options, 1) == FAILURE ||
6645 php_openssl_cipher_update(cipher_type, cipher_ctx, &mode, &outbuf, &outlen,
6646 data, data_len, aad, aad_len, 1) == FAILURE) {
6647 RETVAL_FALSE;
6648 } else if (EVP_EncryptFinal(cipher_ctx, (unsigned char *)ZSTR_VAL(outbuf) + outlen, &i)) {
6649 outlen += i;
6650 if (options & OPENSSL_RAW_DATA) {
6651 ZSTR_VAL(outbuf)[outlen] = '\0';
6652 ZSTR_LEN(outbuf) = outlen;
6653 RETVAL_STR(outbuf);
6654 } else {
6655 zend_string *base64_str;
6656
6657 base64_str = php_base64_encode((unsigned char*)ZSTR_VAL(outbuf), outlen);
6658 zend_string_release_ex(outbuf, 0);
6659 outbuf = base64_str;
6660 RETVAL_STR(base64_str);
6661 }
6662 if (mode.is_aead && tag) {
6663 zend_string *tag_str = zend_string_alloc(tag_len, 0);
6664
6665 if (EVP_CIPHER_CTX_ctrl(cipher_ctx, mode.aead_get_tag_flag, tag_len, ZSTR_VAL(tag_str)) == 1) {
6666 zval_ptr_dtor(tag);
6667 ZSTR_VAL(tag_str)[tag_len] = '\0';
6668 ZSTR_LEN(tag_str) = tag_len;
6669 ZVAL_NEW_STR(tag, tag_str);
6670 } else {
6671 php_error_docref(NULL, E_WARNING, "Retrieving verification tag failed");
6672 zend_string_release_ex(tag_str, 0);
6673 zend_string_release_ex(outbuf, 0);
6674 RETVAL_FALSE;
6675 }
6676 } else if (tag) {
6677 zval_ptr_dtor(tag);
6678 ZVAL_NULL(tag);
6679 php_error_docref(NULL, E_WARNING,
6680 "The authenticated tag cannot be provided for cipher that doesn not support AEAD");
6681 } else if (mode.is_aead) {
6682 php_error_docref(NULL, E_WARNING, "A tag should be provided when using AEAD mode");
6683 zend_string_release_ex(outbuf, 0);
6684 RETVAL_FALSE;
6685 }
6686 } else {
6687 php_openssl_store_errors();
6688 zend_string_release_ex(outbuf, 0);
6689 RETVAL_FALSE;
6690 }
6691
6692 if (free_password) {
6693 efree(password);
6694 }
6695 if (free_iv) {
6696 efree(iv);
6697 }
6698 EVP_CIPHER_CTX_cleanup(cipher_ctx);
6699 EVP_CIPHER_CTX_free(cipher_ctx);
6700 }
6701 /* }}} */
6702
6703 /* {{{ proto string openssl_decrypt(string data, string method, string password [, int options=0 [, string $iv = ''[, string $tag = ''[, string $aad = '']]]])
6704 Takes raw or base64 encoded string and decrypts it using given method and key */
PHP_FUNCTION(openssl_decrypt)6705 PHP_FUNCTION(openssl_decrypt)
6706 {
6707 zend_long options = 0;
6708 char *data, *method, *password, *iv = "", *tag = NULL, *aad = "";
6709 size_t data_len, method_len, password_len, iv_len = 0, tag_len = 0, aad_len = 0;
6710 const EVP_CIPHER *cipher_type;
6711 EVP_CIPHER_CTX *cipher_ctx;
6712 struct php_openssl_cipher_mode mode;
6713 int i = 0, outlen;
6714 zend_string *outbuf;
6715 zend_string *base64_str = NULL;
6716 zend_bool free_iv = 0, free_password = 0;
6717
6718 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|lsss", &data, &data_len, &method, &method_len,
6719 &password, &password_len, &options, &iv, &iv_len, &tag, &tag_len, &aad, &aad_len) == FAILURE) {
6720 return;
6721 }
6722
6723 if (!method_len) {
6724 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
6725 RETURN_FALSE;
6726 }
6727
6728 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
6729 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password);
6730 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(aad_len, aad);
6731 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(tag_len, tag);
6732
6733 cipher_type = EVP_get_cipherbyname(method);
6734 if (!cipher_type) {
6735 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
6736 RETURN_FALSE;
6737 }
6738
6739 cipher_ctx = EVP_CIPHER_CTX_new();
6740 if (!cipher_ctx) {
6741 php_error_docref(NULL, E_WARNING, "Failed to create cipher context");
6742 RETURN_FALSE;
6743 }
6744
6745 php_openssl_load_cipher_mode(&mode, cipher_type);
6746
6747 if (!(options & OPENSSL_RAW_DATA)) {
6748 base64_str = php_base64_decode((unsigned char*)data, data_len);
6749 if (!base64_str) {
6750 php_error_docref(NULL, E_WARNING, "Failed to base64 decode the input");
6751 EVP_CIPHER_CTX_free(cipher_ctx);
6752 RETURN_FALSE;
6753 }
6754 data_len = ZSTR_LEN(base64_str);
6755 data = ZSTR_VAL(base64_str);
6756 }
6757
6758 if (php_openssl_cipher_init(cipher_type, cipher_ctx, &mode,
6759 &password, &password_len, &free_password,
6760 &iv, &iv_len, &free_iv, tag, tag_len, options, 0) == FAILURE ||
6761 php_openssl_cipher_update(cipher_type, cipher_ctx, &mode, &outbuf, &outlen,
6762 data, data_len, aad, aad_len, 0) == FAILURE) {
6763 RETVAL_FALSE;
6764 } else if (mode.is_single_run_aead ||
6765 EVP_DecryptFinal(cipher_ctx, (unsigned char *)ZSTR_VAL(outbuf) + outlen, &i)) {
6766 outlen += i;
6767 ZSTR_VAL(outbuf)[outlen] = '\0';
6768 ZSTR_LEN(outbuf) = outlen;
6769 RETVAL_STR(outbuf);
6770 } else {
6771 php_openssl_store_errors();
6772 zend_string_release_ex(outbuf, 0);
6773 RETVAL_FALSE;
6774 }
6775
6776 if (free_password) {
6777 efree(password);
6778 }
6779 if (free_iv) {
6780 efree(iv);
6781 }
6782 if (base64_str) {
6783 zend_string_release_ex(base64_str, 0);
6784 }
6785 EVP_CIPHER_CTX_cleanup(cipher_ctx);
6786 EVP_CIPHER_CTX_free(cipher_ctx);
6787 }
6788 /* }}} */
6789
6790 /* {{{ proto int openssl_cipher_iv_length(string $method) */
PHP_FUNCTION(openssl_cipher_iv_length)6791 PHP_FUNCTION(openssl_cipher_iv_length)
6792 {
6793 char *method;
6794 size_t method_len;
6795 const EVP_CIPHER *cipher_type;
6796
6797 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &method, &method_len) == FAILURE) {
6798 return;
6799 }
6800
6801 if (!method_len) {
6802 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
6803 RETURN_FALSE;
6804 }
6805
6806 cipher_type = EVP_get_cipherbyname(method);
6807 if (!cipher_type) {
6808 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
6809 RETURN_FALSE;
6810 }
6811
6812 RETURN_LONG(EVP_CIPHER_iv_length(cipher_type));
6813 }
6814 /* }}} */
6815
6816
6817 /* {{{ proto string openssl_random_pseudo_bytes(int length [, &bool returned_strong_result])
6818 Returns a string of the length specified filled with random pseudo bytes */
PHP_FUNCTION(openssl_random_pseudo_bytes)6819 PHP_FUNCTION(openssl_random_pseudo_bytes)
6820 {
6821 zend_long buffer_length;
6822 zend_string *buffer = NULL;
6823 zval *zstrong_result_returned = NULL;
6824
6825 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z/", &buffer_length, &zstrong_result_returned) == FAILURE) {
6826 return;
6827 }
6828
6829 if (zstrong_result_returned) {
6830 zval_ptr_dtor(zstrong_result_returned);
6831 ZVAL_FALSE(zstrong_result_returned);
6832 }
6833
6834 if (buffer_length <= 0
6835 #ifndef PHP_WIN32
6836 || ZEND_LONG_INT_OVFL(buffer_length)
6837 #endif
6838 ) {
6839 RETURN_FALSE;
6840 }
6841 buffer = zend_string_alloc(buffer_length, 0);
6842
6843 #ifdef PHP_WIN32
6844 /* random/urandom equivalent on Windows */
6845 if (php_win32_get_random_bytes((unsigned char*)buffer->val, (size_t) buffer_length) == FAILURE){
6846 zend_string_release_ex(buffer, 0);
6847 if (zstrong_result_returned) {
6848 ZVAL_FALSE(zstrong_result_returned);
6849 }
6850 RETURN_FALSE;
6851 }
6852 #else
6853
6854 PHP_OPENSSL_CHECK_LONG_TO_INT(buffer_length, length);
6855 PHP_OPENSSL_RAND_ADD_TIME();
6856 /* FIXME loop if requested size > INT_MAX */
6857 if (RAND_bytes((unsigned char*)ZSTR_VAL(buffer), (int)buffer_length) <= 0) {
6858 zend_string_release_ex(buffer, 0);
6859 if (zstrong_result_returned) {
6860 ZVAL_FALSE(zstrong_result_returned);
6861 }
6862 RETURN_FALSE;
6863 } else {
6864 php_openssl_store_errors();
6865 }
6866 #endif
6867
6868 ZSTR_VAL(buffer)[buffer_length] = 0;
6869 RETVAL_NEW_STR(buffer);
6870
6871 if (zstrong_result_returned) {
6872 ZVAL_BOOL(zstrong_result_returned, 1);
6873 }
6874 }
6875 /* }}} */
6876
6877 /*
6878 * Local variables:
6879 * tab-width: 8
6880 * c-basic-offset: 8
6881 * End:
6882 * vim600: sw=4 ts=4 fdm=marker
6883 * vim<600: sw=4 ts=4
6884 */
6885