This source file includes following definitions.
- php_openssl_get_x509_list_id
- php_pkey_free
- php_x509_free
- php_csr_free
- php_openssl_open_base_dir_chk
- php_openssl_get_stream_from_ssl_handle
- php_openssl_get_ssl_stream_data_index
- STACK_OF
- add_assoc_asn1_string
- asn1_time_to_time_t
- php_openssl_config_check_syntax
- add_oid_section
- openssl_spki_cleanup
- php_openssl_parse_config
- php_openssl_dispose_config
- php_openssl_load_rand_file
- php_openssl_write_rand_file
- php_openssl_get_evp_md_from_algo
- php_openssl_get_evp_cipher_from_algo
- PHP_INI_BEGIN
- PHP_MINFO_FUNCTION
- PHP_MSHUTDOWN_FUNCTION
- PHP_FUNCTION
- php_openssl_x509_from_zval
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- php_openssl_x509_fingerprint
- PHP_FUNCTION
- PHP_FUNCTION
- openssl_x509v3_subjectAltName
- PHP_FUNCTION
- STACK_OF
- check_cert
- PHP_FUNCTION
- setup_verify
- PHP_FUNCTION
- PHP_FUNCTION
- php_sk_X509_free
- STACK_OF
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- php_openssl_make_REQ
- php_openssl_csr_from_zval
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- php_openssl_evp_from_zval
- php_openssl_generate_private_key
- php_openssl_is_private_key
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- openssl_add_method_or_alias
- openssl_add_method
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- php_openssl_validate_iv
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
- PHP_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "php.h"
30 #include "php_ini.h"
31 #include "php_openssl.h"
32
33
34 #include "ext/standard/file.h"
35 #include "ext/standard/info.h"
36 #include "ext/standard/php_fopen_wrappers.h"
37 #include "ext/standard/md5.h"
38 #include "ext/standard/base64.h"
39 #ifdef PHP_WIN32
40 # include "win32/winutil.h"
41 #endif
42
43
44 #include <openssl/evp.h>
45 #include <openssl/bn.h>
46 #include <openssl/rsa.h>
47 #include <openssl/dsa.h>
48 #include <openssl/dh.h>
49 #include <openssl/x509.h>
50 #include <openssl/x509v3.h>
51 #include <openssl/crypto.h>
52 #include <openssl/pem.h>
53 #include <openssl/err.h>
54 #include <openssl/conf.h>
55 #include <openssl/rand.h>
56 #include <openssl/ssl.h>
57 #include <openssl/pkcs12.h>
58
59
60 #include <time.h>
61
62 #if defined(NETWARE) || (defined(PHP_WIN32) && defined(_MSC_VER) && _MSC_VER >= 1900)
63 #define timezone _timezone
64 #endif
65
66 #define DEFAULT_KEY_LENGTH 512
67 #define MIN_KEY_LENGTH 384
68
69 #define OPENSSL_ALGO_SHA1 1
70 #define OPENSSL_ALGO_MD5 2
71 #define OPENSSL_ALGO_MD4 3
72 #ifdef HAVE_OPENSSL_MD2_H
73 #define OPENSSL_ALGO_MD2 4
74 #endif
75 #define OPENSSL_ALGO_DSS1 5
76 #if OPENSSL_VERSION_NUMBER >= 0x0090708fL
77 #define OPENSSL_ALGO_SHA224 6
78 #define OPENSSL_ALGO_SHA256 7
79 #define OPENSSL_ALGO_SHA384 8
80 #define OPENSSL_ALGO_SHA512 9
81 #define OPENSSL_ALGO_RMD160 10
82 #endif
83 #define DEBUG_SMIME 0
84
85 #if !defined(OPENSSL_NO_EC) && defined(EVP_PKEY_EC)
86 #define HAVE_EVP_PKEY_EC 1
87 #endif
88
89
90
91
92
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
120 PHP_FUNCTION(openssl_digest);
121 PHP_FUNCTION(openssl_encrypt);
122 PHP_FUNCTION(openssl_decrypt);
123 PHP_FUNCTION(openssl_cipher_iv_length);
124
125 PHP_FUNCTION(openssl_dh_compute_key);
126 PHP_FUNCTION(openssl_random_pseudo_bytes);
127
128
129 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 0, 2)
130 ZEND_ARG_INFO(0, x509)
131 ZEND_ARG_INFO(0, outfilename)
132 ZEND_ARG_INFO(0, notext)
133 ZEND_END_ARG_INFO()
134
135 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_export, 0, 0, 2)
136 ZEND_ARG_INFO(0, x509)
137 ZEND_ARG_INFO(1, out)
138 ZEND_ARG_INFO(0, notext)
139 ZEND_END_ARG_INFO()
140
141 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_fingerprint, 0, 0, 1)
142 ZEND_ARG_INFO(0, x509)
143 ZEND_ARG_INFO(0, method)
144 ZEND_ARG_INFO(0, raw_output)
145 ZEND_END_ARG_INFO()
146
147 ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_check_private_key, 0)
148 ZEND_ARG_INFO(0, cert)
149 ZEND_ARG_INFO(0, key)
150 ZEND_END_ARG_INFO()
151
152 ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_parse, 0)
153 ZEND_ARG_INFO(0, x509)
154 ZEND_ARG_INFO(0, shortname)
155 ZEND_END_ARG_INFO()
156
157 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_x509_checkpurpose, 0, 0, 3)
158 ZEND_ARG_INFO(0, x509cert)
159 ZEND_ARG_INFO(0, purpose)
160 ZEND_ARG_INFO(0, cainfo)
161 ZEND_ARG_INFO(0, untrustedfile)
162 ZEND_END_ARG_INFO()
163
164 ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_read, 0)
165 ZEND_ARG_INFO(0, cert)
166 ZEND_END_ARG_INFO()
167
168 ZEND_BEGIN_ARG_INFO(arginfo_openssl_x509_free, 0)
169 ZEND_ARG_INFO(0, x509)
170 ZEND_END_ARG_INFO()
171
172 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs12_export_to_file, 0, 0, 4)
173 ZEND_ARG_INFO(0, x509)
174 ZEND_ARG_INFO(0, filename)
175 ZEND_ARG_INFO(0, priv_key)
176 ZEND_ARG_INFO(0, pass)
177 ZEND_ARG_INFO(0, args)
178 ZEND_END_ARG_INFO()
179
180 ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_export, 0)
181 ZEND_ARG_INFO(0, x509)
182 ZEND_ARG_INFO(1, out)
183 ZEND_ARG_INFO(0, priv_key)
184 ZEND_ARG_INFO(0, pass)
185 ZEND_ARG_INFO(0, args)
186 ZEND_END_ARG_INFO()
187
188 ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkcs12_read, 0)
189 ZEND_ARG_INFO(0, PKCS12)
190 ZEND_ARG_INFO(1, certs)
191 ZEND_ARG_INFO(0, pass)
192 ZEND_END_ARG_INFO()
193
194 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export_to_file, 0, 0, 2)
195 ZEND_ARG_INFO(0, csr)
196 ZEND_ARG_INFO(0, outfilename)
197 ZEND_ARG_INFO(0, notext)
198 ZEND_END_ARG_INFO()
199
200 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_export, 0, 0, 2)
201 ZEND_ARG_INFO(0, csr)
202 ZEND_ARG_INFO(1, out)
203 ZEND_ARG_INFO(0, notext)
204 ZEND_END_ARG_INFO()
205
206 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_sign, 0, 0, 4)
207 ZEND_ARG_INFO(0, csr)
208 ZEND_ARG_INFO(0, x509)
209 ZEND_ARG_INFO(0, priv_key)
210 ZEND_ARG_INFO(0, days)
211 ZEND_ARG_INFO(0, config_args)
212 ZEND_ARG_INFO(0, serial)
213 ZEND_END_ARG_INFO()
214
215 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_csr_new, 0, 0, 2)
216 ZEND_ARG_INFO(0, dn)
217 ZEND_ARG_INFO(1, privkey)
218 ZEND_ARG_INFO(0, configargs)
219 ZEND_ARG_INFO(0, extraattribs)
220 ZEND_END_ARG_INFO()
221
222 ZEND_BEGIN_ARG_INFO(arginfo_openssl_csr_get_subject, 0)
223 ZEND_ARG_INFO(0, csr)
224 ZEND_END_ARG_INFO()
225
226 ZEND_BEGIN_ARG_INFO(arginfo_openssl_csr_get_public_key, 0)
227 ZEND_ARG_INFO(0, csr)
228 ZEND_END_ARG_INFO()
229
230 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_new, 0, 0, 0)
231 ZEND_ARG_INFO(0, configargs)
232 ZEND_END_ARG_INFO()
233
234 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export_to_file, 0, 0, 2)
235 ZEND_ARG_INFO(0, key)
236 ZEND_ARG_INFO(0, outfilename)
237 ZEND_ARG_INFO(0, passphrase)
238 ZEND_ARG_INFO(0, config_args)
239 ZEND_END_ARG_INFO()
240
241 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_export, 0, 0, 2)
242 ZEND_ARG_INFO(0, key)
243 ZEND_ARG_INFO(1, out)
244 ZEND_ARG_INFO(0, passphrase)
245 ZEND_ARG_INFO(0, config_args)
246 ZEND_END_ARG_INFO()
247
248 ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_public, 0)
249 ZEND_ARG_INFO(0, cert)
250 ZEND_END_ARG_INFO()
251
252 ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_free, 0)
253 ZEND_ARG_INFO(0, key)
254 ZEND_END_ARG_INFO()
255
256 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkey_get_private, 0, 0, 1)
257 ZEND_ARG_INFO(0, key)
258 ZEND_ARG_INFO(0, passphrase)
259 ZEND_END_ARG_INFO()
260
261 ZEND_BEGIN_ARG_INFO(arginfo_openssl_pkey_get_details, 0)
262 ZEND_ARG_INFO(0, key)
263 ZEND_END_ARG_INFO()
264
265 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
266 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pbkdf2, 0, 0, 4)
267 ZEND_ARG_INFO(0, password)
268 ZEND_ARG_INFO(0, salt)
269 ZEND_ARG_INFO(0, key_length)
270 ZEND_ARG_INFO(0, iterations)
271 ZEND_ARG_INFO(0, digest_algorithm)
272 ZEND_END_ARG_INFO()
273 #endif
274
275 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_verify, 0, 0, 2)
276 ZEND_ARG_INFO(0, filename)
277 ZEND_ARG_INFO(0, flags)
278 ZEND_ARG_INFO(0, signerscerts)
279 ZEND_ARG_INFO(0, cainfo)
280 ZEND_ARG_INFO(0, extracerts)
281 ZEND_ARG_INFO(0, content)
282 ZEND_END_ARG_INFO()
283
284 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_encrypt, 0, 0, 4)
285 ZEND_ARG_INFO(0, infile)
286 ZEND_ARG_INFO(0, outfile)
287 ZEND_ARG_INFO(0, recipcerts)
288 ZEND_ARG_INFO(0, headers)
289 ZEND_ARG_INFO(0, flags)
290 ZEND_ARG_INFO(0, cipher)
291 ZEND_END_ARG_INFO()
292
293 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_sign, 0, 0, 5)
294 ZEND_ARG_INFO(0, infile)
295 ZEND_ARG_INFO(0, outfile)
296 ZEND_ARG_INFO(0, signcert)
297 ZEND_ARG_INFO(0, signkey)
298 ZEND_ARG_INFO(0, headers)
299 ZEND_ARG_INFO(0, flags)
300 ZEND_ARG_INFO(0, extracertsfilename)
301 ZEND_END_ARG_INFO()
302
303 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_pkcs7_decrypt, 0, 0, 3)
304 ZEND_ARG_INFO(0, infilename)
305 ZEND_ARG_INFO(0, outfilename)
306 ZEND_ARG_INFO(0, recipcert)
307 ZEND_ARG_INFO(0, recipkey)
308 ZEND_END_ARG_INFO()
309
310 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_encrypt, 0, 0, 3)
311 ZEND_ARG_INFO(0, data)
312 ZEND_ARG_INFO(1, crypted)
313 ZEND_ARG_INFO(0, key)
314 ZEND_ARG_INFO(0, padding)
315 ZEND_END_ARG_INFO()
316
317 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_private_decrypt, 0, 0, 3)
318 ZEND_ARG_INFO(0, data)
319 ZEND_ARG_INFO(1, crypted)
320 ZEND_ARG_INFO(0, key)
321 ZEND_ARG_INFO(0, padding)
322 ZEND_END_ARG_INFO()
323
324 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_encrypt, 0, 0, 3)
325 ZEND_ARG_INFO(0, data)
326 ZEND_ARG_INFO(1, crypted)
327 ZEND_ARG_INFO(0, key)
328 ZEND_ARG_INFO(0, padding)
329 ZEND_END_ARG_INFO()
330
331 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_public_decrypt, 0, 0, 3)
332 ZEND_ARG_INFO(0, data)
333 ZEND_ARG_INFO(1, crypted)
334 ZEND_ARG_INFO(0, key)
335 ZEND_ARG_INFO(0, padding)
336 ZEND_END_ARG_INFO()
337
338 ZEND_BEGIN_ARG_INFO(arginfo_openssl_error_string, 0)
339 ZEND_END_ARG_INFO()
340
341 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_sign, 0, 0, 3)
342 ZEND_ARG_INFO(0, data)
343 ZEND_ARG_INFO(1, signature)
344 ZEND_ARG_INFO(0, key)
345 ZEND_ARG_INFO(0, method)
346 ZEND_END_ARG_INFO()
347
348 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_verify, 0, 0, 3)
349 ZEND_ARG_INFO(0, data)
350 ZEND_ARG_INFO(0, signature)
351 ZEND_ARG_INFO(0, key)
352 ZEND_ARG_INFO(0, method)
353 ZEND_END_ARG_INFO()
354
355 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_seal, 0, 0, 4)
356 ZEND_ARG_INFO(0, data)
357 ZEND_ARG_INFO(1, sealdata)
358 ZEND_ARG_INFO(1, ekeys)
359 ZEND_ARG_INFO(0, pubkeys)
360 ZEND_ARG_INFO(0, method)
361 ZEND_ARG_INFO(1, iv)
362 ZEND_END_ARG_INFO()
363
364 ZEND_BEGIN_ARG_INFO(arginfo_openssl_open, 0)
365 ZEND_ARG_INFO(0, data)
366 ZEND_ARG_INFO(1, opendata)
367 ZEND_ARG_INFO(0, ekey)
368 ZEND_ARG_INFO(0, privkey)
369 ZEND_ARG_INFO(0, iv)
370 ZEND_END_ARG_INFO()
371
372 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_md_methods, 0, 0, 0)
373 ZEND_ARG_INFO(0, aliases)
374 ZEND_END_ARG_INFO()
375
376 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_get_cipher_methods, 0, 0, 0)
377 ZEND_ARG_INFO(0, aliases)
378 ZEND_END_ARG_INFO()
379
380 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_digest, 0, 0, 2)
381 ZEND_ARG_INFO(0, data)
382 ZEND_ARG_INFO(0, method)
383 ZEND_ARG_INFO(0, raw_output)
384 ZEND_END_ARG_INFO()
385
386 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_encrypt, 0, 0, 3)
387 ZEND_ARG_INFO(0, data)
388 ZEND_ARG_INFO(0, method)
389 ZEND_ARG_INFO(0, password)
390 ZEND_ARG_INFO(0, options)
391 ZEND_ARG_INFO(0, iv)
392 ZEND_END_ARG_INFO()
393
394 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_decrypt, 0, 0, 3)
395 ZEND_ARG_INFO(0, data)
396 ZEND_ARG_INFO(0, method)
397 ZEND_ARG_INFO(0, password)
398 ZEND_ARG_INFO(0, options)
399 ZEND_ARG_INFO(0, iv)
400 ZEND_END_ARG_INFO()
401
402 ZEND_BEGIN_ARG_INFO(arginfo_openssl_cipher_iv_length, 0)
403 ZEND_ARG_INFO(0, method)
404 ZEND_END_ARG_INFO()
405
406 ZEND_BEGIN_ARG_INFO(arginfo_openssl_dh_compute_key, 0)
407 ZEND_ARG_INFO(0, pub_key)
408 ZEND_ARG_INFO(0, dh_key)
409 ZEND_END_ARG_INFO()
410
411 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_random_pseudo_bytes, 0, 0, 1)
412 ZEND_ARG_INFO(0, length)
413 ZEND_ARG_INFO(1, result_is_strong)
414 ZEND_END_ARG_INFO()
415
416 ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_spki_new, 0, 0, 2)
417 ZEND_ARG_INFO(0, privkey)
418 ZEND_ARG_INFO(0, challenge)
419 ZEND_ARG_INFO(0, algo)
420 ZEND_END_ARG_INFO()
421
422 ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_verify, 0)
423 ZEND_ARG_INFO(0, spki)
424 ZEND_END_ARG_INFO()
425
426 ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export, 0)
427 ZEND_ARG_INFO(0, spki)
428 ZEND_END_ARG_INFO()
429
430 ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export_challenge, 0)
431 ZEND_ARG_INFO(0, spki)
432 ZEND_END_ARG_INFO()
433
434 ZEND_BEGIN_ARG_INFO(arginfo_openssl_get_cert_locations, 0)
435 ZEND_END_ARG_INFO()
436
437
438
439
440 const zend_function_entry openssl_functions[] = {
441 PHP_FE(openssl_get_cert_locations, arginfo_openssl_get_cert_locations)
442
443
444 PHP_FE(openssl_spki_new, arginfo_openssl_spki_new)
445 PHP_FE(openssl_spki_verify, arginfo_openssl_spki_verify)
446 PHP_FE(openssl_spki_export, arginfo_openssl_spki_export)
447 PHP_FE(openssl_spki_export_challenge, arginfo_openssl_spki_export_challenge)
448
449
450 PHP_FE(openssl_pkey_free, arginfo_openssl_pkey_free)
451 PHP_FE(openssl_pkey_new, arginfo_openssl_pkey_new)
452 PHP_FE(openssl_pkey_export, arginfo_openssl_pkey_export)
453 PHP_FE(openssl_pkey_export_to_file, arginfo_openssl_pkey_export_to_file)
454 PHP_FE(openssl_pkey_get_private, arginfo_openssl_pkey_get_private)
455 PHP_FE(openssl_pkey_get_public, arginfo_openssl_pkey_get_public)
456 PHP_FE(openssl_pkey_get_details, arginfo_openssl_pkey_get_details)
457
458 PHP_FALIAS(openssl_free_key, openssl_pkey_free, arginfo_openssl_pkey_free)
459 PHP_FALIAS(openssl_get_privatekey, openssl_pkey_get_private, arginfo_openssl_pkey_get_private)
460 PHP_FALIAS(openssl_get_publickey, openssl_pkey_get_public, arginfo_openssl_pkey_get_public)
461
462
463 PHP_FE(openssl_x509_read, arginfo_openssl_x509_read)
464 PHP_FE(openssl_x509_free, arginfo_openssl_x509_free)
465 PHP_FE(openssl_x509_parse, arginfo_openssl_x509_parse)
466 PHP_FE(openssl_x509_checkpurpose, arginfo_openssl_x509_checkpurpose)
467 PHP_FE(openssl_x509_check_private_key, arginfo_openssl_x509_check_private_key)
468 PHP_FE(openssl_x509_export, arginfo_openssl_x509_export)
469 PHP_FE(openssl_x509_fingerprint, arginfo_openssl_x509_fingerprint)
470 PHP_FE(openssl_x509_export_to_file, arginfo_openssl_x509_export_to_file)
471
472
473 PHP_FE(openssl_pkcs12_export, arginfo_openssl_pkcs12_export)
474 PHP_FE(openssl_pkcs12_export_to_file, arginfo_openssl_pkcs12_export_to_file)
475 PHP_FE(openssl_pkcs12_read, arginfo_openssl_pkcs12_read)
476
477
478 PHP_FE(openssl_csr_new, arginfo_openssl_csr_new)
479 PHP_FE(openssl_csr_export, arginfo_openssl_csr_export)
480 PHP_FE(openssl_csr_export_to_file, arginfo_openssl_csr_export_to_file)
481 PHP_FE(openssl_csr_sign, arginfo_openssl_csr_sign)
482 PHP_FE(openssl_csr_get_subject, arginfo_openssl_csr_get_subject)
483 PHP_FE(openssl_csr_get_public_key, arginfo_openssl_csr_get_public_key)
484
485 PHP_FE(openssl_digest, arginfo_openssl_digest)
486 PHP_FE(openssl_encrypt, arginfo_openssl_encrypt)
487 PHP_FE(openssl_decrypt, arginfo_openssl_decrypt)
488 PHP_FE(openssl_cipher_iv_length, arginfo_openssl_cipher_iv_length)
489 PHP_FE(openssl_sign, arginfo_openssl_sign)
490 PHP_FE(openssl_verify, arginfo_openssl_verify)
491 PHP_FE(openssl_seal, arginfo_openssl_seal)
492 PHP_FE(openssl_open, arginfo_openssl_open)
493
494 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
495 PHP_FE(openssl_pbkdf2, arginfo_openssl_pbkdf2)
496 #endif
497
498
499 PHP_FE(openssl_pkcs7_verify, arginfo_openssl_pkcs7_verify)
500 PHP_FE(openssl_pkcs7_decrypt, arginfo_openssl_pkcs7_decrypt)
501 PHP_FE(openssl_pkcs7_sign, arginfo_openssl_pkcs7_sign)
502 PHP_FE(openssl_pkcs7_encrypt, arginfo_openssl_pkcs7_encrypt)
503
504 PHP_FE(openssl_private_encrypt, arginfo_openssl_private_encrypt)
505 PHP_FE(openssl_private_decrypt, arginfo_openssl_private_decrypt)
506 PHP_FE(openssl_public_encrypt, arginfo_openssl_public_encrypt)
507 PHP_FE(openssl_public_decrypt, arginfo_openssl_public_decrypt)
508
509 PHP_FE(openssl_get_md_methods, arginfo_openssl_get_md_methods)
510 PHP_FE(openssl_get_cipher_methods, arginfo_openssl_get_cipher_methods)
511
512 PHP_FE(openssl_dh_compute_key, arginfo_openssl_dh_compute_key)
513
514 PHP_FE(openssl_random_pseudo_bytes, arginfo_openssl_random_pseudo_bytes)
515 PHP_FE(openssl_error_string, arginfo_openssl_error_string)
516 PHP_FE_END
517 };
518
519
520
521
522 zend_module_entry openssl_module_entry = {
523 STANDARD_MODULE_HEADER,
524 "openssl",
525 openssl_functions,
526 PHP_MINIT(openssl),
527 PHP_MSHUTDOWN(openssl),
528 NULL,
529 NULL,
530 PHP_MINFO(openssl),
531 PHP_OPENSSL_VERSION,
532 STANDARD_MODULE_PROPERTIES
533 };
534
535
536 #ifdef COMPILE_DL_OPENSSL
537 ZEND_GET_MODULE(openssl)
538 #endif
539
540
541 #define PHP_OPENSSL_CHECK_NUMBER_CONVERSION(_cond, _name) \
542 do { \
543 if (_cond) { \
544 php_error_docref(NULL, E_WARNING, #_name" is too long"); \
545 RETURN_FALSE; \
546 } \
547 } while(0)
548
549 #define PHP_OPENSSL_CHECK_SIZE_T_TO_INT(_var, _name) \
550 PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_SIZE_T_INT_OVFL(_var), _name)
551
552 #define PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(_var, _name) \
553 PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_SIZE_T_UINT_OVFL(_var), _name)
554
555 #define PHP_OPENSSL_CHECK_LONG_TO_INT(_var, _name) \
556 PHP_OPENSSL_CHECK_NUMBER_CONVERSION(ZEND_LONG_EXCEEDS_INT(_var), _name)
557
558
559 static int le_key;
560 static int le_x509;
561 static int le_csr;
562 static int ssl_stream_data_index;
563
564 int php_openssl_get_x509_list_id(void)
565 {
566 return le_x509;
567 }
568
569
570
571 static void php_pkey_free(zend_resource *rsrc)
572 {
573 EVP_PKEY *pkey = (EVP_PKEY *)rsrc->ptr;
574
575 assert(pkey != NULL);
576
577 EVP_PKEY_free(pkey);
578 }
579
580 static void php_x509_free(zend_resource *rsrc)
581 {
582 X509 *x509 = (X509 *)rsrc->ptr;
583 X509_free(x509);
584 }
585
586 static void php_csr_free(zend_resource *rsrc)
587 {
588 X509_REQ * csr = (X509_REQ*)rsrc->ptr;
589 X509_REQ_free(csr);
590 }
591
592
593
594 inline static int php_openssl_open_base_dir_chk(char *filename)
595 {
596 if (php_check_open_basedir(filename)) {
597 return -1;
598 }
599
600 return 0;
601 }
602
603
604 php_stream* php_openssl_get_stream_from_ssl_handle(const SSL *ssl)
605 {
606 return (php_stream*)SSL_get_ex_data(ssl, ssl_stream_data_index);
607 }
608
609 int php_openssl_get_ssl_stream_data_index()
610 {
611 return ssl_stream_data_index;
612 }
613
614
615
616 static char default_ssl_conf_filename[MAXPATHLEN];
617
618 struct php_x509_request {
619 #if OPENSSL_VERSION_NUMBER >= 0x10000002L
620 LHASH_OF(CONF_VALUE) * global_config;
621 LHASH_OF(CONF_VALUE) * req_config;
622 #else
623 LHASH * global_config;
624 LHASH * req_config;
625 #endif
626 const EVP_MD * md_alg;
627 const EVP_MD * digest;
628 char * section_name,
629 * config_filename,
630 * digest_name,
631 * extensions_section,
632 * request_extensions_section;
633 int priv_key_bits;
634 int priv_key_type;
635
636 int priv_key_encrypt;
637
638 EVP_PKEY * priv_key;
639
640 const EVP_CIPHER * priv_key_encrypt_cipher;
641 };
642
643
644 static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval);
645 static EVP_PKEY * php_openssl_evp_from_zval(zval * val, int public_key, char * passphrase, int makeresource, zend_resource **resourceval);
646 static int php_openssl_is_private_key(EVP_PKEY* pkey);
647 static X509_STORE * setup_verify(zval * calist);
648 static STACK_OF(X509) * load_all_certs_from_file(char *certfile);
649 static X509_REQ * php_openssl_csr_from_zval(zval * val, int makeresource, zend_resource ** resourceval);
650 static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req);
651
652 static void add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname)
653 {
654 zval *data;
655 zval subitem, tmp;
656 int i;
657 char *sname;
658 int nid;
659 X509_NAME_ENTRY * ne;
660 ASN1_STRING * str = NULL;
661 ASN1_OBJECT * obj;
662
663 if (key != NULL) {
664 array_init(&subitem);
665 } else {
666 ZVAL_COPY_VALUE(&subitem, val);
667 }
668
669 for (i = 0; i < X509_NAME_entry_count(name); i++) {
670 unsigned char *to_add;
671 int to_add_len = 0;
672
673
674 ne = X509_NAME_get_entry(name, i);
675 obj = X509_NAME_ENTRY_get_object(ne);
676 nid = OBJ_obj2nid(obj);
677
678 if (shortname) {
679 sname = (char *) OBJ_nid2sn(nid);
680 } else {
681 sname = (char *) OBJ_nid2ln(nid);
682 }
683
684 str = X509_NAME_ENTRY_get_data(ne);
685 if (ASN1_STRING_type(str) != V_ASN1_UTF8STRING) {
686 to_add_len = ASN1_STRING_to_UTF8(&to_add, str);
687 } else {
688 to_add = ASN1_STRING_data(str);
689 to_add_len = ASN1_STRING_length(str);
690 }
691
692 if (to_add_len != -1) {
693 if ((data = zend_hash_str_find(Z_ARRVAL(subitem), sname, strlen(sname))) != NULL) {
694 if (Z_TYPE_P(data) == IS_ARRAY) {
695 add_next_index_stringl(data, (char *)to_add, to_add_len);
696 } else if (Z_TYPE_P(data) == IS_STRING) {
697 array_init(&tmp);
698 add_next_index_str(&tmp, zend_string_copy(Z_STR_P(data)));
699 add_next_index_stringl(&tmp, (char *)to_add, to_add_len);
700 zend_hash_str_update(Z_ARRVAL(subitem), sname, strlen(sname), &tmp);
701 }
702 } else {
703 add_assoc_stringl(&subitem, sname, (char *)to_add, to_add_len);
704 }
705 }
706 }
707 if (key != NULL) {
708 zend_hash_str_update(Z_ARRVAL_P(val), key, strlen(key), &subitem);
709 }
710 }
711
712
713 static void add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str)
714 {
715 add_assoc_stringl(val, key, (char *)str->data, str->length);
716 }
717
718
719 static time_t asn1_time_to_time_t(ASN1_UTCTIME * timestr)
720 {
721
722
723
724
725
726
727
728 time_t ret;
729 struct tm thetime;
730 char * strbuf;
731 char * thestr;
732 long gmadjust = 0;
733
734 if (ASN1_STRING_type(timestr) != V_ASN1_UTCTIME && ASN1_STRING_type(timestr) != V_ASN1_GENERALIZEDTIME) {
735 php_error_docref(NULL, E_WARNING, "illegal ASN1 data type for timestamp");
736 return (time_t)-1;
737 }
738
739 if (ASN1_STRING_length(timestr) != strlen((const char*)ASN1_STRING_data(timestr))) {
740 php_error_docref(NULL, E_WARNING, "illegal length in timestamp");
741 return (time_t)-1;
742 }
743
744 if (ASN1_STRING_length(timestr) < 13) {
745 php_error_docref(NULL, E_WARNING, "unable to parse time string %s correctly", timestr->data);
746 return (time_t)-1;
747 }
748
749 if (ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME && ASN1_STRING_length(timestr) < 15) {
750 php_error_docref(NULL, E_WARNING, "unable to parse time string %s correctly", timestr->data);
751 return (time_t)-1;
752 }
753
754 strbuf = estrdup((char *)ASN1_STRING_data(timestr));
755
756 memset(&thetime, 0, sizeof(thetime));
757
758
759
760 thestr = strbuf + ASN1_STRING_length(timestr) - 3;
761
762 thetime.tm_sec = atoi(thestr);
763 *thestr = '\0';
764 thestr -= 2;
765 thetime.tm_min = atoi(thestr);
766 *thestr = '\0';
767 thestr -= 2;
768 thetime.tm_hour = atoi(thestr);
769 *thestr = '\0';
770 thestr -= 2;
771 thetime.tm_mday = atoi(thestr);
772 *thestr = '\0';
773 thestr -= 2;
774 thetime.tm_mon = atoi(thestr)-1;
775
776 *thestr = '\0';
777 if( ASN1_STRING_type(timestr) == V_ASN1_UTCTIME ) {
778 thestr -= 2;
779 thetime.tm_year = atoi(thestr);
780
781 if (thetime.tm_year < 68) {
782 thetime.tm_year += 100;
783 }
784 } else if( ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME ) {
785 thestr -= 4;
786 thetime.tm_year = atoi(thestr) - 1900;
787 }
788
789
790 thetime.tm_isdst = -1;
791 ret = mktime(&thetime);
792
793 #if HAVE_TM_GMTOFF
794 gmadjust = thetime.tm_gmtoff;
795 #else
796
797
798
799
800
801 gmadjust = -(thetime.tm_isdst ? (long)timezone - 3600 : (long)timezone + 3600);
802 #endif
803 ret += gmadjust;
804
805 efree(strbuf);
806
807 return ret;
808 }
809
810
811 #if OPENSSL_VERSION_NUMBER >= 0x10000002L
812 static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH_OF(CONF_VALUE) * config)
813 #else
814 static inline int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, LHASH * config)
815 #endif
816 {
817 X509V3_CTX ctx;
818
819 X509V3_set_ctx_test(&ctx);
820 X509V3_set_conf_lhash(&ctx, config);
821 if (!X509V3_EXT_add_conf(config, &ctx, (char *)section, NULL)) {
822 php_error_docref(NULL, E_WARNING, "Error loading %s section %s of %s",
823 section_label,
824 section,
825 config_filename);
826 return FAILURE;
827 }
828 return SUCCESS;
829 }
830
831
832 static int add_oid_section(struct php_x509_request * req)
833 {
834 char * str;
835 STACK_OF(CONF_VALUE) * sktmp;
836 CONF_VALUE * cnf;
837 int i;
838
839 str = CONF_get_string(req->req_config, NULL, "oid_section");
840 if (str == NULL) {
841 return SUCCESS;
842 }
843 sktmp = CONF_get_section(req->req_config, str);
844 if (sktmp == NULL) {
845 php_error_docref(NULL, E_WARNING, "problem loading oid section %s", str);
846 return FAILURE;
847 }
848 for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
849 cnf = sk_CONF_VALUE_value(sktmp, i);
850 if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) {
851 php_error_docref(NULL, E_WARNING, "problem creating object %s=%s", cnf->name, cnf->value);
852 return FAILURE;
853 }
854 }
855 return SUCCESS;
856 }
857
858
859 #define PHP_SSL_REQ_INIT(req) memset(req, 0, sizeof(*req))
860 #define PHP_SSL_REQ_DISPOSE(req) php_openssl_dispose_config(req)
861 #define PHP_SSL_REQ_PARSE(req, zval) php_openssl_parse_config(req, zval)
862
863 #define PHP_SSL_CONFIG_SYNTAX_CHECK(var) if (req->var && php_openssl_config_check_syntax(#var, \
864 req->config_filename, req->var, req->req_config) == FAILURE) return FAILURE
865
866 #define SET_OPTIONAL_STRING_ARG(key, varname, defval) \
867 if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), key, sizeof(key)-1)) != NULL && Z_TYPE_P(item) == IS_STRING) \
868 varname = Z_STRVAL_P(item); \
869 else \
870 varname = defval
871
872 #define SET_OPTIONAL_LONG_ARG(key, varname, defval) \
873 if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), key, sizeof(key)-1)) != NULL && Z_TYPE_P(item) == IS_LONG) \
874 varname = (int)Z_LVAL_P(item); \
875 else \
876 varname = defval
877
878 static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo);
879
880
881 static int openssl_spki_cleanup(const char *src, char *dest)
882 {
883 int removed = 0;
884
885 while (*src) {
886 if (*src != '\n' && *src != '\r') {
887 *dest++ = *src;
888 } else {
889 ++removed;
890 }
891 ++src;
892 }
893 *dest = 0;
894 return removed;
895 }
896
897
898
899 static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args)
900 {
901 char * str;
902 zval * item;
903
904 SET_OPTIONAL_STRING_ARG("config", req->config_filename, default_ssl_conf_filename);
905 SET_OPTIONAL_STRING_ARG("config_section_name", req->section_name, "req");
906 req->global_config = CONF_load(NULL, default_ssl_conf_filename, NULL);
907 req->req_config = CONF_load(NULL, req->config_filename, NULL);
908
909 if (req->req_config == NULL) {
910 return FAILURE;
911 }
912
913
914 str = CONF_get_string(req->req_config, NULL, "oid_file");
915 if (str && !php_openssl_open_base_dir_chk(str)) {
916 BIO *oid_bio = BIO_new_file(str, "r");
917 if (oid_bio) {
918 OBJ_create_objects(oid_bio);
919 BIO_free(oid_bio);
920 }
921 }
922 if (add_oid_section(req) == FAILURE) {
923 return FAILURE;
924 }
925 SET_OPTIONAL_STRING_ARG("digest_alg", req->digest_name,
926 CONF_get_string(req->req_config, req->section_name, "default_md"));
927 SET_OPTIONAL_STRING_ARG("x509_extensions", req->extensions_section,
928 CONF_get_string(req->req_config, req->section_name, "x509_extensions"));
929 SET_OPTIONAL_STRING_ARG("req_extensions", req->request_extensions_section,
930 CONF_get_string(req->req_config, req->section_name, "req_extensions"));
931 SET_OPTIONAL_LONG_ARG("private_key_bits", req->priv_key_bits,
932 CONF_get_number(req->req_config, req->section_name, "default_bits"));
933
934 SET_OPTIONAL_LONG_ARG("private_key_type", req->priv_key_type, OPENSSL_KEYTYPE_DEFAULT);
935
936 if (optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key", sizeof("encrypt_key")-1)) != NULL) {
937 req->priv_key_encrypt = Z_TYPE_P(item) == IS_TRUE ? 1 : 0;
938 } else {
939 str = CONF_get_string(req->req_config, req->section_name, "encrypt_rsa_key");
940 if (str == NULL) {
941 str = CONF_get_string(req->req_config, req->section_name, "encrypt_key");
942 }
943 if (str && strcmp(str, "no") == 0) {
944 req->priv_key_encrypt = 0;
945 } else {
946 req->priv_key_encrypt = 1;
947 }
948 }
949
950 if (req->priv_key_encrypt && optional_args && (item = zend_hash_str_find(Z_ARRVAL_P(optional_args), "encrypt_key_cipher", sizeof("encrypt_key_cipher")-1)) != NULL
951 && Z_TYPE_P(item) == IS_LONG) {
952 zend_long cipher_algo = Z_LVAL_P(item);
953 const EVP_CIPHER* cipher = php_openssl_get_evp_cipher_from_algo(cipher_algo);
954 if (cipher == NULL) {
955 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm for private key.");
956 return FAILURE;
957 } else {
958 req->priv_key_encrypt_cipher = cipher;
959 }
960 } else {
961 req->priv_key_encrypt_cipher = NULL;
962 }
963
964
965
966
967 if (req->digest_name == NULL) {
968 req->digest_name = CONF_get_string(req->req_config, req->section_name, "default_md");
969 }
970 if (req->digest_name) {
971 req->digest = req->md_alg = EVP_get_digestbyname(req->digest_name);
972 }
973 if (req->md_alg == NULL) {
974 req->md_alg = req->digest = EVP_sha1();
975 }
976
977 PHP_SSL_CONFIG_SYNTAX_CHECK(extensions_section);
978
979
980 str = CONF_get_string(req->req_config, req->section_name, "string_mask");
981 if (str && !ASN1_STRING_set_default_mask_asc(str)) {
982 php_error_docref(NULL, E_WARNING, "Invalid global string mask setting %s", str);
983 return FAILURE;
984 }
985
986 PHP_SSL_CONFIG_SYNTAX_CHECK(request_extensions_section);
987
988 return SUCCESS;
989 }
990
991
992 static void php_openssl_dispose_config(struct php_x509_request * req)
993 {
994 if (req->priv_key) {
995 EVP_PKEY_free(req->priv_key);
996 req->priv_key = NULL;
997 }
998 if (req->global_config) {
999 CONF_free(req->global_config);
1000 req->global_config = NULL;
1001 }
1002 if (req->req_config) {
1003 CONF_free(req->req_config);
1004 req->req_config = NULL;
1005 }
1006 }
1007
1008
1009 static int php_openssl_load_rand_file(const char * file, int *egdsocket, int *seeded)
1010 {
1011 char buffer[MAXPATHLEN];
1012
1013 *egdsocket = 0;
1014 *seeded = 0;
1015
1016 if (file == NULL) {
1017 file = RAND_file_name(buffer, sizeof(buffer));
1018 #ifdef HAVE_RAND_EGD
1019 } else if (RAND_egd(file) > 0) {
1020
1021
1022 *egdsocket = 1;
1023 return SUCCESS;
1024 #endif
1025 }
1026 if (file == NULL || !RAND_load_file(file, -1)) {
1027 if (RAND_status() == 0) {
1028 php_error_docref(NULL, E_WARNING, "unable to load random state; not enough random data!");
1029 return FAILURE;
1030 }
1031 return FAILURE;
1032 }
1033 *seeded = 1;
1034 return SUCCESS;
1035 }
1036
1037
1038 static int php_openssl_write_rand_file(const char * file, int egdsocket, int seeded)
1039 {
1040 char buffer[MAXPATHLEN];
1041
1042
1043 if (egdsocket || !seeded) {
1044
1045
1046 return FAILURE;
1047 }
1048 if (file == NULL) {
1049 file = RAND_file_name(buffer, sizeof(buffer));
1050 }
1051 if (file == NULL || !RAND_write_file(file)) {
1052 php_error_docref(NULL, E_WARNING, "unable to write random state");
1053 return FAILURE;
1054 }
1055 return SUCCESS;
1056 }
1057
1058
1059 static EVP_MD * php_openssl_get_evp_md_from_algo(zend_long algo) {
1060 EVP_MD *mdtype;
1061
1062 switch (algo) {
1063 case OPENSSL_ALGO_SHA1:
1064 mdtype = (EVP_MD *) EVP_sha1();
1065 break;
1066 case OPENSSL_ALGO_MD5:
1067 mdtype = (EVP_MD *) EVP_md5();
1068 break;
1069 case OPENSSL_ALGO_MD4:
1070 mdtype = (EVP_MD *) EVP_md4();
1071 break;
1072 #ifdef HAVE_OPENSSL_MD2_H
1073 case OPENSSL_ALGO_MD2:
1074 mdtype = (EVP_MD *) EVP_md2();
1075 break;
1076 #endif
1077 case OPENSSL_ALGO_DSS1:
1078 mdtype = (EVP_MD *) EVP_dss1();
1079 break;
1080 #if OPENSSL_VERSION_NUMBER >= 0x0090708fL
1081 case OPENSSL_ALGO_SHA224:
1082 mdtype = (EVP_MD *) EVP_sha224();
1083 break;
1084 case OPENSSL_ALGO_SHA256:
1085 mdtype = (EVP_MD *) EVP_sha256();
1086 break;
1087 case OPENSSL_ALGO_SHA384:
1088 mdtype = (EVP_MD *) EVP_sha384();
1089 break;
1090 case OPENSSL_ALGO_SHA512:
1091 mdtype = (EVP_MD *) EVP_sha512();
1092 break;
1093 case OPENSSL_ALGO_RMD160:
1094 mdtype = (EVP_MD *) EVP_ripemd160();
1095 break;
1096 #endif
1097 default:
1098 return NULL;
1099 break;
1100 }
1101 return mdtype;
1102 }
1103
1104
1105 static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(zend_long algo) {
1106 switch (algo) {
1107 #ifndef OPENSSL_NO_RC2
1108 case PHP_OPENSSL_CIPHER_RC2_40:
1109 return EVP_rc2_40_cbc();
1110 break;
1111 case PHP_OPENSSL_CIPHER_RC2_64:
1112 return EVP_rc2_64_cbc();
1113 break;
1114 case PHP_OPENSSL_CIPHER_RC2_128:
1115 return EVP_rc2_cbc();
1116 break;
1117 #endif
1118
1119 #ifndef OPENSSL_NO_DES
1120 case PHP_OPENSSL_CIPHER_DES:
1121 return EVP_des_cbc();
1122 break;
1123 case PHP_OPENSSL_CIPHER_3DES:
1124 return EVP_des_ede3_cbc();
1125 break;
1126 #endif
1127
1128 #ifndef OPENSSL_NO_AES
1129 case PHP_OPENSSL_CIPHER_AES_128_CBC:
1130 return EVP_aes_128_cbc();
1131 break;
1132 case PHP_OPENSSL_CIPHER_AES_192_CBC:
1133 return EVP_aes_192_cbc();
1134 break;
1135 case PHP_OPENSSL_CIPHER_AES_256_CBC:
1136 return EVP_aes_256_cbc();
1137 break;
1138 #endif
1139
1140
1141 default:
1142 return NULL;
1143 break;
1144 }
1145 }
1146
1147
1148
1149 PHP_INI_BEGIN()
1150 PHP_INI_ENTRY("openssl.cafile", NULL, PHP_INI_PERDIR, NULL)
1151 PHP_INI_ENTRY("openssl.capath", NULL, PHP_INI_PERDIR, NULL)
1152 PHP_INI_END()
1153
1154
1155
1156
1157 PHP_MINIT_FUNCTION(openssl)
1158 {
1159 char * config_filename;
1160
1161 le_key = zend_register_list_destructors_ex(php_pkey_free, NULL, "OpenSSL key", module_number);
1162 le_x509 = zend_register_list_destructors_ex(php_x509_free, NULL, "OpenSSL X.509", module_number);
1163 le_csr = zend_register_list_destructors_ex(php_csr_free, NULL, "OpenSSL X.509 CSR", module_number);
1164
1165 SSL_library_init();
1166 OpenSSL_add_all_ciphers();
1167 OpenSSL_add_all_digests();
1168 OpenSSL_add_all_algorithms();
1169
1170 SSL_load_error_strings();
1171
1172
1173
1174 ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL);
1175
1176 REGISTER_STRING_CONSTANT("OPENSSL_VERSION_TEXT", OPENSSL_VERSION_TEXT, CONST_CS|CONST_PERSISTENT);
1177 REGISTER_LONG_CONSTANT("OPENSSL_VERSION_NUMBER", OPENSSL_VERSION_NUMBER, CONST_CS|CONST_PERSISTENT);
1178
1179
1180 REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_CLIENT", X509_PURPOSE_SSL_CLIENT, CONST_CS|CONST_PERSISTENT);
1181 REGISTER_LONG_CONSTANT("X509_PURPOSE_SSL_SERVER", X509_PURPOSE_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
1182 REGISTER_LONG_CONSTANT("X509_PURPOSE_NS_SSL_SERVER", X509_PURPOSE_NS_SSL_SERVER, CONST_CS|CONST_PERSISTENT);
1183 REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_SIGN", X509_PURPOSE_SMIME_SIGN, CONST_CS|CONST_PERSISTENT);
1184 REGISTER_LONG_CONSTANT("X509_PURPOSE_SMIME_ENCRYPT", X509_PURPOSE_SMIME_ENCRYPT, CONST_CS|CONST_PERSISTENT);
1185 REGISTER_LONG_CONSTANT("X509_PURPOSE_CRL_SIGN", X509_PURPOSE_CRL_SIGN, CONST_CS|CONST_PERSISTENT);
1186 #ifdef X509_PURPOSE_ANY
1187 REGISTER_LONG_CONSTANT("X509_PURPOSE_ANY", X509_PURPOSE_ANY, CONST_CS|CONST_PERSISTENT);
1188 #endif
1189
1190
1191 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA1", OPENSSL_ALGO_SHA1, CONST_CS|CONST_PERSISTENT);
1192 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD5", OPENSSL_ALGO_MD5, CONST_CS|CONST_PERSISTENT);
1193 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD4", OPENSSL_ALGO_MD4, CONST_CS|CONST_PERSISTENT);
1194 #ifdef HAVE_OPENSSL_MD2_H
1195 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_MD2", OPENSSL_ALGO_MD2, CONST_CS|CONST_PERSISTENT);
1196 #endif
1197 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_DSS1", OPENSSL_ALGO_DSS1, CONST_CS|CONST_PERSISTENT);
1198 #if OPENSSL_VERSION_NUMBER >= 0x0090708fL
1199 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA224", OPENSSL_ALGO_SHA224, CONST_CS|CONST_PERSISTENT);
1200 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA256", OPENSSL_ALGO_SHA256, CONST_CS|CONST_PERSISTENT);
1201 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA384", OPENSSL_ALGO_SHA384, CONST_CS|CONST_PERSISTENT);
1202 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_SHA512", OPENSSL_ALGO_SHA512, CONST_CS|CONST_PERSISTENT);
1203 REGISTER_LONG_CONSTANT("OPENSSL_ALGO_RMD160", OPENSSL_ALGO_RMD160, CONST_CS|CONST_PERSISTENT);
1204 #endif
1205
1206
1207 REGISTER_LONG_CONSTANT("PKCS7_DETACHED", PKCS7_DETACHED, CONST_CS|CONST_PERSISTENT);
1208 REGISTER_LONG_CONSTANT("PKCS7_TEXT", PKCS7_TEXT, CONST_CS|CONST_PERSISTENT);
1209 REGISTER_LONG_CONSTANT("PKCS7_NOINTERN", PKCS7_NOINTERN, CONST_CS|CONST_PERSISTENT);
1210 REGISTER_LONG_CONSTANT("PKCS7_NOVERIFY", PKCS7_NOVERIFY, CONST_CS|CONST_PERSISTENT);
1211 REGISTER_LONG_CONSTANT("PKCS7_NOCHAIN", PKCS7_NOCHAIN, CONST_CS|CONST_PERSISTENT);
1212 REGISTER_LONG_CONSTANT("PKCS7_NOCERTS", PKCS7_NOCERTS, CONST_CS|CONST_PERSISTENT);
1213 REGISTER_LONG_CONSTANT("PKCS7_NOATTR", PKCS7_NOATTR, CONST_CS|CONST_PERSISTENT);
1214 REGISTER_LONG_CONSTANT("PKCS7_BINARY", PKCS7_BINARY, CONST_CS|CONST_PERSISTENT);
1215 REGISTER_LONG_CONSTANT("PKCS7_NOSIGS", PKCS7_NOSIGS, CONST_CS|CONST_PERSISTENT);
1216
1217 REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_PADDING", RSA_PKCS1_PADDING, CONST_CS|CONST_PERSISTENT);
1218 REGISTER_LONG_CONSTANT("OPENSSL_SSLV23_PADDING", RSA_SSLV23_PADDING, CONST_CS|CONST_PERSISTENT);
1219 REGISTER_LONG_CONSTANT("OPENSSL_NO_PADDING", RSA_NO_PADDING, CONST_CS|CONST_PERSISTENT);
1220 REGISTER_LONG_CONSTANT("OPENSSL_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING, CONST_CS|CONST_PERSISTENT);
1221
1222
1223 REGISTER_STRING_CONSTANT("OPENSSL_DEFAULT_STREAM_CIPHERS", OPENSSL_DEFAULT_STREAM_CIPHERS, CONST_CS|CONST_PERSISTENT);
1224
1225
1226 #ifndef OPENSSL_NO_RC2
1227 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_40", PHP_OPENSSL_CIPHER_RC2_40, CONST_CS|CONST_PERSISTENT);
1228 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_128", PHP_OPENSSL_CIPHER_RC2_128, CONST_CS|CONST_PERSISTENT);
1229 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_RC2_64", PHP_OPENSSL_CIPHER_RC2_64, CONST_CS|CONST_PERSISTENT);
1230 #endif
1231 #ifndef OPENSSL_NO_DES
1232 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_DES", PHP_OPENSSL_CIPHER_DES, CONST_CS|CONST_PERSISTENT);
1233 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_3DES", PHP_OPENSSL_CIPHER_3DES, CONST_CS|CONST_PERSISTENT);
1234 #endif
1235 #ifndef OPENSSL_NO_AES
1236 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_128_CBC", PHP_OPENSSL_CIPHER_AES_128_CBC, CONST_CS|CONST_PERSISTENT);
1237 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_192_CBC", PHP_OPENSSL_CIPHER_AES_192_CBC, CONST_CS|CONST_PERSISTENT);
1238 REGISTER_LONG_CONSTANT("OPENSSL_CIPHER_AES_256_CBC", PHP_OPENSSL_CIPHER_AES_256_CBC, CONST_CS|CONST_PERSISTENT);
1239 #endif
1240
1241
1242 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_RSA", OPENSSL_KEYTYPE_RSA, CONST_CS|CONST_PERSISTENT);
1243 #ifndef NO_DSA
1244 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DSA", OPENSSL_KEYTYPE_DSA, CONST_CS|CONST_PERSISTENT);
1245 #endif
1246 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_DH", OPENSSL_KEYTYPE_DH, CONST_CS|CONST_PERSISTENT);
1247 #ifdef HAVE_EVP_PKEY_EC
1248 REGISTER_LONG_CONSTANT("OPENSSL_KEYTYPE_EC", OPENSSL_KEYTYPE_EC, CONST_CS|CONST_PERSISTENT);
1249 #endif
1250
1251 REGISTER_LONG_CONSTANT("OPENSSL_RAW_DATA", OPENSSL_RAW_DATA, CONST_CS|CONST_PERSISTENT);
1252 REGISTER_LONG_CONSTANT("OPENSSL_ZERO_PADDING", OPENSSL_ZERO_PADDING, CONST_CS|CONST_PERSISTENT);
1253
1254 #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
1255
1256 REGISTER_LONG_CONSTANT("OPENSSL_TLSEXT_SERVER_NAME", 1, CONST_CS|CONST_PERSISTENT);
1257 #endif
1258
1259
1260 config_filename = getenv("OPENSSL_CONF");
1261 if (config_filename == NULL) {
1262 config_filename = getenv("SSLEAY_CONF");
1263 }
1264
1265
1266 if (config_filename == NULL) {
1267 snprintf(default_ssl_conf_filename, sizeof(default_ssl_conf_filename), "%s/%s",
1268 X509_get_default_cert_area(),
1269 "openssl.cnf");
1270 } else {
1271 strlcpy(default_ssl_conf_filename, config_filename, sizeof(default_ssl_conf_filename));
1272 }
1273
1274 php_stream_xport_register("ssl", php_openssl_ssl_socket_factory);
1275 #ifndef OPENSSL_NO_SSL3
1276 php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory);
1277 #endif
1278 #ifndef OPENSSL_NO_SSL2
1279 php_stream_xport_register("sslv2", php_openssl_ssl_socket_factory);
1280 #endif
1281 php_stream_xport_register("tls", php_openssl_ssl_socket_factory);
1282 php_stream_xport_register("tlsv1.0", php_openssl_ssl_socket_factory);
1283 #if OPENSSL_VERSION_NUMBER >= 0x10001001L
1284 php_stream_xport_register("tlsv1.1", php_openssl_ssl_socket_factory);
1285 php_stream_xport_register("tlsv1.2", php_openssl_ssl_socket_factory);
1286 #endif
1287
1288
1289 php_stream_xport_register("tcp", php_openssl_ssl_socket_factory);
1290
1291 php_register_url_stream_wrapper("https", &php_stream_http_wrapper);
1292 php_register_url_stream_wrapper("ftps", &php_stream_ftp_wrapper);
1293
1294 REGISTER_INI_ENTRIES();
1295
1296 return SUCCESS;
1297 }
1298
1299
1300
1301
1302 PHP_MINFO_FUNCTION(openssl)
1303 {
1304 php_info_print_table_start();
1305 php_info_print_table_row(2, "OpenSSL support", "enabled");
1306 php_info_print_table_row(2, "OpenSSL Library Version", SSLeay_version(SSLEAY_VERSION));
1307 php_info_print_table_row(2, "OpenSSL Header Version", OPENSSL_VERSION_TEXT);
1308 php_info_print_table_row(2, "Openssl default config", default_ssl_conf_filename);
1309 php_info_print_table_end();
1310 DISPLAY_INI_ENTRIES();
1311 }
1312
1313
1314
1315
1316 PHP_MSHUTDOWN_FUNCTION(openssl)
1317 {
1318 EVP_cleanup();
1319
1320 #if OPENSSL_VERSION_NUMBER >= 0x00090805f
1321 ERR_free_strings();
1322 #endif
1323
1324 php_unregister_url_stream_wrapper("https");
1325 php_unregister_url_stream_wrapper("ftps");
1326
1327 php_stream_xport_unregister("ssl");
1328 #ifndef OPENSSL_NO_SSL2
1329 php_stream_xport_unregister("sslv2");
1330 #endif
1331 #ifndef OPENSSL_NO_SSL3
1332 php_stream_xport_unregister("sslv3");
1333 #endif
1334 php_stream_xport_unregister("tls");
1335 php_stream_xport_unregister("tlsv1.0");
1336 #if OPENSSL_VERSION_NUMBER >= 0x10001001L
1337 php_stream_xport_unregister("tlsv1.1");
1338 php_stream_xport_unregister("tlsv1.2");
1339 #endif
1340
1341
1342 php_stream_xport_register("tcp", php_stream_generic_socket_factory);
1343
1344 UNREGISTER_INI_ENTRIES();
1345
1346 return SUCCESS;
1347 }
1348
1349
1350
1351
1352
1353
1354 PHP_FUNCTION(openssl_get_cert_locations)
1355 {
1356 array_init(return_value);
1357
1358 add_assoc_string(return_value, "default_cert_file", (char *) X509_get_default_cert_file());
1359 add_assoc_string(return_value, "default_cert_file_env", (char *) X509_get_default_cert_file_env());
1360 add_assoc_string(return_value, "default_cert_dir", (char *) X509_get_default_cert_dir());
1361 add_assoc_string(return_value, "default_cert_dir_env", (char *) X509_get_default_cert_dir_env());
1362 add_assoc_string(return_value, "default_private_dir", (char *) X509_get_default_private_dir());
1363 add_assoc_string(return_value, "default_default_cert_area", (char *) X509_get_default_cert_area());
1364 add_assoc_string(return_value, "ini_cafile",
1365 zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0));
1366 add_assoc_string(return_value, "ini_capath",
1367 zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0));
1368 }
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381 static X509 * php_openssl_x509_from_zval(zval * val, int makeresource, zend_resource **resourceval)
1382 {
1383 X509 *cert = NULL;
1384
1385 if (resourceval) {
1386 *resourceval = NULL;
1387 }
1388 if (Z_TYPE_P(val) == IS_RESOURCE) {
1389
1390 void * what;
1391 zend_resource *res = Z_RES_P(val);
1392
1393 what = zend_fetch_resource(res, "OpenSSL X.509", le_x509);
1394 if (!what) {
1395 return NULL;
1396 }
1397
1398 if (resourceval) {
1399 *resourceval = res;
1400 Z_ADDREF_P(val);
1401 }
1402 return (X509*)what;
1403 }
1404
1405 if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) {
1406 return NULL;
1407 }
1408
1409
1410 convert_to_string_ex(val);
1411
1412 if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) {
1413
1414 BIO *in;
1415
1416 if (php_openssl_open_base_dir_chk(Z_STRVAL_P(val) + (sizeof("file://") - 1))) {
1417 return NULL;
1418 }
1419
1420 in = BIO_new_file(Z_STRVAL_P(val) + (sizeof("file://") - 1), "r");
1421 if (in == NULL) {
1422 return NULL;
1423 }
1424 cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
1425 BIO_free(in);
1426 } else {
1427 BIO *in;
1428
1429 in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val));
1430 if (in == NULL) {
1431 return NULL;
1432 }
1433 #ifdef TYPEDEF_D2I_OF
1434 cert = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
1435 #else
1436 cert = (X509 *) PEM_ASN1_read_bio((char *(*)())d2i_X509, PEM_STRING_X509, in, NULL, NULL, NULL);
1437 #endif
1438 BIO_free(in);
1439 }
1440
1441 if (cert && makeresource && resourceval) {
1442 *resourceval = zend_register_resource(cert, le_x509);
1443 }
1444 return cert;
1445 }
1446
1447
1448
1449
1450
1451 PHP_FUNCTION(openssl_x509_export_to_file)
1452 {
1453 X509 * cert;
1454 zval * zcert;
1455 zend_bool notext = 1;
1456 BIO * bio_out;
1457 zend_resource *certresource;
1458 char * filename;
1459 size_t filename_len;
1460
1461 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|b", &zcert, &filename, &filename_len, ¬ext) == FAILURE) {
1462 return;
1463 }
1464 RETVAL_FALSE;
1465
1466 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
1467 if (cert == NULL) {
1468 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1");
1469 return;
1470 }
1471
1472 if (php_openssl_open_base_dir_chk(filename)) {
1473 return;
1474 }
1475
1476 bio_out = BIO_new_file(filename, "w");
1477 if (bio_out) {
1478 if (!notext) {
1479 X509_print(bio_out, cert);
1480 }
1481 PEM_write_bio_X509(bio_out, cert);
1482
1483 RETVAL_TRUE;
1484 } else {
1485 php_error_docref(NULL, E_WARNING, "error opening file %s", filename);
1486 }
1487 if (certresource == NULL && cert) {
1488 X509_free(cert);
1489 }
1490 BIO_free(bio_out);
1491 }
1492
1493
1494
1495
1496
1497 PHP_FUNCTION(openssl_spki_new)
1498 {
1499 size_t challenge_len;
1500 char * challenge = NULL, * spkstr = NULL;
1501 zend_string * s = NULL;
1502 zend_resource *keyresource = NULL;
1503 const char *spkac = "SPKAC=";
1504 zend_long algo = OPENSSL_ALGO_MD5;
1505
1506 zval *method = NULL;
1507 zval * zpkey = NULL;
1508 EVP_PKEY * pkey = NULL;
1509 NETSCAPE_SPKI *spki=NULL;
1510 const EVP_MD *mdtype;
1511
1512 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|z", &zpkey, &challenge, &challenge_len, &method) == FAILURE) {
1513 return;
1514 }
1515 RETVAL_FALSE;
1516
1517 pkey = php_openssl_evp_from_zval(zpkey, 0, challenge, 1, &keyresource);
1518
1519 if (pkey == NULL) {
1520 php_error_docref(NULL, E_WARNING, "Unable to use supplied private key");
1521 goto cleanup;
1522 }
1523
1524 if (method != NULL) {
1525 if (Z_TYPE_P(method) == IS_LONG) {
1526 algo = Z_LVAL_P(method);
1527 } else {
1528 php_error_docref(NULL, E_WARNING, "Algorithm must be of supported type");
1529 goto cleanup;
1530 }
1531 }
1532 mdtype = php_openssl_get_evp_md_from_algo(algo);
1533
1534 if (!mdtype) {
1535 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
1536 goto cleanup;
1537 }
1538
1539 if ((spki = NETSCAPE_SPKI_new()) == NULL) {
1540 php_error_docref(NULL, E_WARNING, "Unable to create new SPKAC");
1541 goto cleanup;
1542 }
1543
1544 if (challenge) {
1545 if (!ASN1_STRING_set(spki->spkac->challenge, challenge, (int)challenge_len)) {
1546 php_error_docref(NULL, E_WARNING, "Unable to set challenge data");
1547 goto cleanup;
1548 }
1549 }
1550
1551 if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) {
1552 php_error_docref(NULL, E_WARNING, "Unable to embed public key");
1553 goto cleanup;
1554 }
1555
1556 if (!NETSCAPE_SPKI_sign(spki, pkey, mdtype)) {
1557 php_error_docref(NULL, E_WARNING, "Unable to sign with specified algorithm");
1558 goto cleanup;
1559 }
1560
1561 spkstr = NETSCAPE_SPKI_b64_encode(spki);
1562 if (!spkstr){
1563 php_error_docref(NULL, E_WARNING, "Unable to encode SPKAC");
1564 goto cleanup;
1565 }
1566
1567 s = zend_string_alloc(strlen(spkac) + strlen(spkstr), 0);
1568 sprintf(ZSTR_VAL(s), "%s%s", spkac, spkstr);
1569 ZSTR_LEN(s) = strlen(ZSTR_VAL(s));
1570
1571 RETVAL_STR(s);
1572 goto cleanup;
1573
1574 cleanup:
1575
1576 if (keyresource == NULL && spki != NULL) {
1577 NETSCAPE_SPKI_free(spki);
1578 }
1579 if (keyresource == NULL && pkey != NULL) {
1580 EVP_PKEY_free(pkey);
1581 }
1582 if (keyresource == NULL && spkstr != NULL) {
1583 efree(spkstr);
1584 }
1585
1586 if (s && ZSTR_LEN(s) <= 0) {
1587 RETVAL_FALSE;
1588 }
1589
1590 if (keyresource == NULL && s != NULL) {
1591 zend_string_release(s);
1592 }
1593 }
1594
1595
1596
1597
1598 PHP_FUNCTION(openssl_spki_verify)
1599 {
1600 size_t spkstr_len;
1601 int i = 0, spkstr_cleaned_len = 0;
1602 char *spkstr = NULL, * spkstr_cleaned = NULL;
1603
1604 EVP_PKEY *pkey = NULL;
1605 NETSCAPE_SPKI *spki = NULL;
1606
1607 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
1608 return;
1609 }
1610 RETVAL_FALSE;
1611
1612 if (spkstr == NULL) {
1613 php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC");
1614 goto cleanup;
1615 }
1616
1617 spkstr_cleaned = emalloc(spkstr_len + 1);
1618 spkstr_cleaned_len = (int)(spkstr_len - openssl_spki_cleanup(spkstr, spkstr_cleaned));
1619
1620 if (spkstr_cleaned_len == 0) {
1621 php_error_docref(NULL, E_WARNING, "Invalid SPKAC");
1622 goto cleanup;
1623 }
1624
1625 spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len);
1626 if (spki == NULL) {
1627 php_error_docref(NULL, E_WARNING, "Unable to decode supplied SPKAC");
1628 goto cleanup;
1629 }
1630
1631 pkey = X509_PUBKEY_get(spki->spkac->pubkey);
1632 if (pkey == NULL) {
1633 php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key");
1634 goto cleanup;
1635 }
1636
1637 i = NETSCAPE_SPKI_verify(spki, pkey);
1638 goto cleanup;
1639
1640 cleanup:
1641 if (spki != NULL) {
1642 NETSCAPE_SPKI_free(spki);
1643 }
1644 if (pkey != NULL) {
1645 EVP_PKEY_free(pkey);
1646 }
1647 if (spkstr_cleaned != NULL) {
1648 efree(spkstr_cleaned);
1649 }
1650
1651 if (i > 0) {
1652 RETVAL_TRUE;
1653 }
1654 }
1655
1656
1657
1658
1659 PHP_FUNCTION(openssl_spki_export)
1660 {
1661 size_t spkstr_len;
1662 char *spkstr = NULL, * spkstr_cleaned = NULL, * s = NULL;
1663 int spkstr_cleaned_len;
1664
1665 EVP_PKEY *pkey = NULL;
1666 NETSCAPE_SPKI *spki = NULL;
1667 BIO *out = NULL;
1668
1669 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
1670 return;
1671 }
1672 RETVAL_FALSE;
1673
1674 if (spkstr == NULL) {
1675 php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC");
1676 goto cleanup;
1677 }
1678
1679 spkstr_cleaned = emalloc(spkstr_len + 1);
1680 spkstr_cleaned_len = (int)(spkstr_len - openssl_spki_cleanup(spkstr, spkstr_cleaned));
1681
1682 if (spkstr_cleaned_len == 0) {
1683 php_error_docref(NULL, E_WARNING, "Invalid SPKAC");
1684 goto cleanup;
1685 }
1686
1687 spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len);
1688 if (spki == NULL) {
1689 php_error_docref(NULL, E_WARNING, "Unable to decode supplied SPKAC");
1690 goto cleanup;
1691 }
1692
1693 pkey = X509_PUBKEY_get(spki->spkac->pubkey);
1694 if (pkey == NULL) {
1695 php_error_docref(NULL, E_WARNING, "Unable to acquire signed public key");
1696 goto cleanup;
1697 }
1698
1699 out = BIO_new(BIO_s_mem());
1700 if (out && PEM_write_bio_PUBKEY(out, pkey)) {
1701 BUF_MEM *bio_buf;
1702
1703 BIO_get_mem_ptr(out, &bio_buf);
1704 RETVAL_STRINGL((char *)bio_buf->data, bio_buf->length);
1705 }
1706 goto cleanup;
1707
1708 cleanup:
1709
1710 if (spki != NULL) {
1711 NETSCAPE_SPKI_free(spki);
1712 }
1713 if (out != NULL) {
1714 BIO_free_all(out);
1715 }
1716 if (pkey != NULL) {
1717 EVP_PKEY_free(pkey);
1718 }
1719 if (spkstr_cleaned != NULL) {
1720 efree(spkstr_cleaned);
1721 }
1722 if (s != NULL) {
1723 efree(s);
1724 }
1725 }
1726
1727
1728
1729
1730 PHP_FUNCTION(openssl_spki_export_challenge)
1731 {
1732 size_t spkstr_len;
1733 char *spkstr = NULL, * spkstr_cleaned = NULL;
1734 int spkstr_cleaned_len;
1735
1736 NETSCAPE_SPKI *spki = NULL;
1737
1738 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &spkstr, &spkstr_len) == FAILURE) {
1739 return;
1740 }
1741 RETVAL_FALSE;
1742
1743 if (spkstr == NULL) {
1744 php_error_docref(NULL, E_WARNING, "Unable to use supplied SPKAC");
1745 goto cleanup;
1746 }
1747
1748 spkstr_cleaned = emalloc(spkstr_len + 1);
1749 spkstr_cleaned_len = (int)(spkstr_len - openssl_spki_cleanup(spkstr, spkstr_cleaned));
1750
1751 if (spkstr_cleaned_len == 0) {
1752 php_error_docref(NULL, E_WARNING, "Invalid SPKAC");
1753 goto cleanup;
1754 }
1755
1756 spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, spkstr_cleaned_len);
1757 if (spki == NULL) {
1758 php_error_docref(NULL, E_WARNING, "Unable to decode SPKAC");
1759 goto cleanup;
1760 }
1761
1762 RETVAL_STRING((char *) ASN1_STRING_data(spki->spkac->challenge));
1763 goto cleanup;
1764
1765 cleanup:
1766 if (spkstr_cleaned != NULL) {
1767 efree(spkstr_cleaned);
1768 }
1769 }
1770
1771
1772
1773
1774 PHP_FUNCTION(openssl_x509_export)
1775 {
1776 X509 * cert;
1777 zval * zcert, *zout;
1778 zend_bool notext = 1;
1779 BIO * bio_out;
1780 zend_resource *certresource;
1781
1782 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|b", &zcert, &zout, ¬ext) == FAILURE) {
1783 return;
1784 }
1785 RETVAL_FALSE;
1786
1787 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
1788 if (cert == NULL) {
1789 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1");
1790 return;
1791 }
1792
1793 bio_out = BIO_new(BIO_s_mem());
1794 if (!notext) {
1795 X509_print(bio_out, cert);
1796 }
1797 if (PEM_write_bio_X509(bio_out, cert)) {
1798 BUF_MEM *bio_buf;
1799
1800 zval_dtor(zout);
1801 BIO_get_mem_ptr(bio_out, &bio_buf);
1802 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length);
1803
1804 RETVAL_TRUE;
1805 }
1806
1807 if (certresource == NULL && cert) {
1808 X509_free(cert);
1809 }
1810 BIO_free(bio_out);
1811 }
1812
1813
1814 zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, zend_bool raw)
1815 {
1816 unsigned char md[EVP_MAX_MD_SIZE];
1817 const EVP_MD *mdtype;
1818 unsigned int n;
1819 zend_string *ret;
1820
1821 if (!(mdtype = EVP_get_digestbyname(method))) {
1822 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
1823 return NULL;
1824 } else if (!X509_digest(peer, mdtype, md, &n)) {
1825 php_error_docref(NULL, E_ERROR, "Could not generate signature");
1826 return NULL;
1827 }
1828
1829 if (raw) {
1830 ret = zend_string_init((char*)md, n, 0);
1831 } else {
1832 ret = zend_string_alloc(n * 2, 0);
1833 make_digest_ex(ZSTR_VAL(ret), md, n);
1834 ZSTR_VAL(ret)[n * 2] = '\0';
1835 }
1836
1837 return ret;
1838 }
1839
1840 PHP_FUNCTION(openssl_x509_fingerprint)
1841 {
1842 X509 *cert;
1843 zval *zcert;
1844 zend_resource *certresource;
1845 zend_bool raw_output = 0;
1846 char *method = "sha1";
1847 size_t method_len;
1848 zend_string *fingerprint;
1849
1850 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|sb", &zcert, &method, &method_len, &raw_output) == FAILURE) {
1851 return;
1852 }
1853
1854 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
1855 if (cert == NULL) {
1856 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1");
1857 RETURN_FALSE;
1858 }
1859
1860 fingerprint = php_openssl_x509_fingerprint(cert, method, raw_output);
1861 if (fingerprint) {
1862 RETVAL_STR(fingerprint);
1863 } else {
1864 RETVAL_FALSE;
1865 }
1866
1867 if (certresource == NULL && cert) {
1868 X509_free(cert);
1869 }
1870 }
1871
1872
1873
1874 PHP_FUNCTION(openssl_x509_check_private_key)
1875 {
1876 zval * zcert, *zkey;
1877 X509 * cert = NULL;
1878 EVP_PKEY * key = NULL;
1879 zend_resource *certresource = NULL, *keyresource = NULL;
1880
1881 RETVAL_FALSE;
1882
1883 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &zcert, &zkey) == FAILURE) {
1884 return;
1885 }
1886 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
1887 if (cert == NULL) {
1888 RETURN_FALSE;
1889 }
1890 key = php_openssl_evp_from_zval(zkey, 0, "", 1, &keyresource);
1891 if (key) {
1892 RETVAL_BOOL(X509_check_private_key(cert, key));
1893 }
1894
1895 if (keyresource == NULL && key) {
1896 EVP_PKEY_free(key);
1897 }
1898 if (certresource == NULL && cert) {
1899 X509_free(cert);
1900 }
1901 }
1902
1903
1904
1905
1906
1907
1908 static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension)
1909 {
1910 GENERAL_NAMES *names;
1911 const X509V3_EXT_METHOD *method = NULL;
1912 long i, length, num;
1913 const unsigned char *p;
1914
1915 method = X509V3_EXT_get(extension);
1916 if (method == NULL) {
1917 return -1;
1918 }
1919
1920 p = extension->value->data;
1921 length = extension->value->length;
1922 if (method->it) {
1923 names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, &p, length,
1924 ASN1_ITEM_ptr(method->it)));
1925 } else {
1926 names = (GENERAL_NAMES*) (method->d2i(NULL, &p, length));
1927 }
1928 if (names == NULL) {
1929 return -1;
1930 }
1931
1932 num = sk_GENERAL_NAME_num(names);
1933 for (i = 0; i < num; i++) {
1934 GENERAL_NAME *name;
1935 ASN1_STRING *as;
1936 name = sk_GENERAL_NAME_value(names, i);
1937 switch (name->type) {
1938 case GEN_EMAIL:
1939 BIO_puts(bio, "email:");
1940 as = name->d.rfc822Name;
1941 BIO_write(bio, ASN1_STRING_data(as),
1942 ASN1_STRING_length(as));
1943 break;
1944 case GEN_DNS:
1945 BIO_puts(bio, "DNS:");
1946 as = name->d.dNSName;
1947 BIO_write(bio, ASN1_STRING_data(as),
1948 ASN1_STRING_length(as));
1949 break;
1950 case GEN_URI:
1951 BIO_puts(bio, "URI:");
1952 as = name->d.uniformResourceIdentifier;
1953 BIO_write(bio, ASN1_STRING_data(as),
1954 ASN1_STRING_length(as));
1955 break;
1956 default:
1957
1958
1959
1960 GENERAL_NAME_print(bio, name);
1961 }
1962
1963 if (i < (num - 1)) {
1964 BIO_puts(bio, ", ");
1965 }
1966 }
1967 sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
1968
1969 return 0;
1970 }
1971
1972
1973
1974 PHP_FUNCTION(openssl_x509_parse)
1975 {
1976 zval * zcert;
1977 X509 * cert = NULL;
1978 zend_resource *certresource = NULL;
1979 int i, sig_nid;
1980 zend_bool useshortnames = 1;
1981 char * tmpstr;
1982 zval subitem;
1983 X509_EXTENSION *extension;
1984 char *extname;
1985 BIO *bio_out;
1986 BUF_MEM *bio_buf;
1987 char buf[256];
1988
1989 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcert, &useshortnames) == FAILURE) {
1990 return;
1991 }
1992 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
1993 if (cert == NULL) {
1994 RETURN_FALSE;
1995 }
1996 array_init(return_value);
1997
1998 if (cert->name) {
1999 add_assoc_string(return_value, "name", cert->name);
2000 }
2001
2002
2003 add_assoc_name_entry(return_value, "subject", X509_get_subject_name(cert), useshortnames);
2004
2005 {
2006 char buf[32];
2007 snprintf(buf, sizeof(buf), "%08lx", X509_subject_name_hash(cert));
2008 add_assoc_string(return_value, "hash", buf);
2009 }
2010
2011 add_assoc_name_entry(return_value, "issuer", X509_get_issuer_name(cert), useshortnames);
2012 add_assoc_long(return_value, "version", X509_get_version(cert));
2013
2014 add_assoc_string(return_value, "serialNumber", i2s_ASN1_INTEGER(NULL, X509_get_serialNumber(cert)));
2015
2016 add_assoc_asn1_string(return_value, "validFrom", X509_get_notBefore(cert));
2017 add_assoc_asn1_string(return_value, "validTo", X509_get_notAfter(cert));
2018
2019 add_assoc_long(return_value, "validFrom_time_t", asn1_time_to_time_t(X509_get_notBefore(cert)));
2020 add_assoc_long(return_value, "validTo_time_t", asn1_time_to_time_t(X509_get_notAfter(cert)));
2021
2022 tmpstr = (char *)X509_alias_get0(cert, NULL);
2023 if (tmpstr) {
2024 add_assoc_string(return_value, "alias", tmpstr);
2025 }
2026
2027 sig_nid = OBJ_obj2nid((cert)->sig_alg->algorithm);
2028 add_assoc_string(return_value, "signatureTypeSN", (char*)OBJ_nid2sn(sig_nid));
2029 add_assoc_string(return_value, "signatureTypeLN", (char*)OBJ_nid2ln(sig_nid));
2030 add_assoc_long(return_value, "signatureTypeNID", sig_nid);
2031 array_init(&subitem);
2032
2033
2034
2035 for (i = 0; i < X509_PURPOSE_get_count(); i++) {
2036 int id, purpset;
2037 char * pname;
2038 X509_PURPOSE * purp;
2039 zval subsub;
2040
2041 array_init(&subsub);
2042
2043 purp = X509_PURPOSE_get0(i);
2044 id = X509_PURPOSE_get_id(purp);
2045
2046 purpset = X509_check_purpose(cert, id, 0);
2047 add_index_bool(&subsub, 0, purpset);
2048
2049 purpset = X509_check_purpose(cert, id, 1);
2050 add_index_bool(&subsub, 1, purpset);
2051
2052 pname = useshortnames ? X509_PURPOSE_get0_sname(purp) : X509_PURPOSE_get0_name(purp);
2053 add_index_string(&subsub, 2, pname);
2054
2055
2056
2057 add_index_zval(&subitem, id, &subsub);
2058 }
2059 add_assoc_zval(return_value, "purposes", &subitem);
2060
2061 array_init(&subitem);
2062
2063
2064 for (i = 0; i < X509_get_ext_count(cert); i++) {
2065 int nid;
2066 extension = X509_get_ext(cert, i);
2067 nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension));
2068 if (nid != NID_undef) {
2069 extname = (char *)OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(extension)));
2070 } else {
2071 OBJ_obj2txt(buf, sizeof(buf)-1, X509_EXTENSION_get_object(extension), 1);
2072 extname = buf;
2073 }
2074 bio_out = BIO_new(BIO_s_mem());
2075 if (nid == NID_subject_alt_name) {
2076 if (openssl_x509v3_subjectAltName(bio_out, extension) == 0) {
2077 BIO_get_mem_ptr(bio_out, &bio_buf);
2078 add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length);
2079 } else {
2080 zval_dtor(return_value);
2081 if (certresource == NULL && cert) {
2082 X509_free(cert);
2083 }
2084 BIO_free(bio_out);
2085 RETURN_FALSE;
2086 }
2087 }
2088 else if (X509V3_EXT_print(bio_out, extension, 0, 0)) {
2089 BIO_get_mem_ptr(bio_out, &bio_buf);
2090 add_assoc_stringl(&subitem, extname, bio_buf->data, bio_buf->length);
2091 } else {
2092 add_assoc_asn1_string(&subitem, extname, X509_EXTENSION_get_data(extension));
2093 }
2094 BIO_free(bio_out);
2095 }
2096 add_assoc_zval(return_value, "extensions", &subitem);
2097
2098 if (certresource == NULL && cert) {
2099 X509_free(cert);
2100 }
2101 }
2102
2103
2104
2105 static STACK_OF(X509) * load_all_certs_from_file(char *certfile)
2106 {
2107 STACK_OF(X509_INFO) *sk=NULL;
2108 STACK_OF(X509) *stack=NULL, *ret=NULL;
2109 BIO *in=NULL;
2110 X509_INFO *xi;
2111
2112 if(!(stack = sk_X509_new_null())) {
2113 php_error_docref(NULL, E_ERROR, "memory allocation failure");
2114 goto end;
2115 }
2116
2117 if (php_openssl_open_base_dir_chk(certfile)) {
2118 sk_X509_free(stack);
2119 goto end;
2120 }
2121
2122 if(!(in=BIO_new_file(certfile, "r"))) {
2123 php_error_docref(NULL, E_WARNING, "error opening the file, %s", certfile);
2124 sk_X509_free(stack);
2125 goto end;
2126 }
2127
2128
2129 if(!(sk=PEM_X509_INFO_read_bio(in, NULL, NULL, NULL))) {
2130 php_error_docref(NULL, E_WARNING, "error reading the file, %s", certfile);
2131 sk_X509_free(stack);
2132 goto end;
2133 }
2134
2135
2136 while (sk_X509_INFO_num(sk)) {
2137 xi=sk_X509_INFO_shift(sk);
2138 if (xi->x509 != NULL) {
2139 sk_X509_push(stack,xi->x509);
2140 xi->x509=NULL;
2141 }
2142 X509_INFO_free(xi);
2143 }
2144 if(!sk_X509_num(stack)) {
2145 php_error_docref(NULL, E_WARNING, "no certificates in file, %s", certfile);
2146 sk_X509_free(stack);
2147 goto end;
2148 }
2149 ret=stack;
2150 end:
2151 BIO_free(in);
2152 sk_X509_INFO_free(sk);
2153
2154 return ret;
2155 }
2156
2157
2158
2159 static int check_cert(X509_STORE *ctx, X509 *x, STACK_OF(X509) *untrustedchain, int purpose)
2160 {
2161 int ret=0;
2162 X509_STORE_CTX *csc;
2163
2164 csc = X509_STORE_CTX_new();
2165 if (csc == NULL) {
2166 php_error_docref(NULL, E_ERROR, "memory allocation failure");
2167 return 0;
2168 }
2169 X509_STORE_CTX_init(csc, ctx, x, untrustedchain);
2170 if(purpose >= 0) {
2171 X509_STORE_CTX_set_purpose(csc, purpose);
2172 }
2173 ret = X509_verify_cert(csc);
2174 X509_STORE_CTX_free(csc);
2175
2176 return ret;
2177 }
2178
2179
2180
2181
2182 PHP_FUNCTION(openssl_x509_checkpurpose)
2183 {
2184 zval * zcert, * zcainfo = NULL;
2185 X509_STORE * cainfo = NULL;
2186 X509 * cert = NULL;
2187 zend_resource *certresource = NULL;
2188 STACK_OF(X509) * untrustedchain = NULL;
2189 zend_long purpose;
2190 char * untrusted = NULL;
2191 size_t untrusted_len = 0;
2192 int ret;
2193
2194 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl|a!s", &zcert, &purpose, &zcainfo, &untrusted, &untrusted_len) == FAILURE) {
2195 return;
2196 }
2197
2198 RETVAL_LONG(-1);
2199
2200 if (untrusted) {
2201 untrustedchain = load_all_certs_from_file(untrusted);
2202 if (untrustedchain == NULL) {
2203 goto clean_exit;
2204 }
2205 }
2206
2207 cainfo = setup_verify(zcainfo);
2208 if (cainfo == NULL) {
2209 goto clean_exit;
2210 }
2211 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
2212 if (cert == NULL) {
2213 goto clean_exit;
2214 }
2215
2216 ret = check_cert(cainfo, cert, untrustedchain, (int)purpose);
2217 if (ret != 0 && ret != 1) {
2218 RETVAL_LONG(ret);
2219 } else {
2220 RETVAL_BOOL(ret);
2221 }
2222
2223 clean_exit:
2224 if (certresource == NULL && cert) {
2225 X509_free(cert);
2226 }
2227 if (cainfo) {
2228 X509_STORE_free(cainfo);
2229 }
2230 if (untrustedchain) {
2231 sk_X509_pop_free(untrustedchain, X509_free);
2232 }
2233 }
2234
2235
2236
2237
2238
2239
2240 static X509_STORE * setup_verify(zval * calist)
2241 {
2242 X509_STORE *store;
2243 X509_LOOKUP * dir_lookup, * file_lookup;
2244 int ndirs = 0, nfiles = 0;
2245 zval * item;
2246 zend_stat_t sb;
2247
2248 store = X509_STORE_new();
2249
2250 if (store == NULL) {
2251 return NULL;
2252 }
2253
2254 if (calist && (Z_TYPE_P(calist) == IS_ARRAY)) {
2255 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(calist), item) {
2256 convert_to_string_ex(item);
2257
2258 if (VCWD_STAT(Z_STRVAL_P(item), &sb) == -1) {
2259 php_error_docref(NULL, E_WARNING, "unable to stat %s", Z_STRVAL_P(item));
2260 continue;
2261 }
2262
2263 if ((sb.st_mode & S_IFREG) == S_IFREG) {
2264 file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
2265 if (file_lookup == NULL || !X509_LOOKUP_load_file(file_lookup, Z_STRVAL_P(item), X509_FILETYPE_PEM)) {
2266 php_error_docref(NULL, E_WARNING, "error loading file %s", Z_STRVAL_P(item));
2267 } else {
2268 nfiles++;
2269 }
2270 file_lookup = NULL;
2271 } else {
2272 dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
2273 if (dir_lookup == NULL || !X509_LOOKUP_add_dir(dir_lookup, Z_STRVAL_P(item), X509_FILETYPE_PEM)) {
2274 php_error_docref(NULL, E_WARNING, "error loading directory %s", Z_STRVAL_P(item));
2275 } else {
2276 ndirs++;
2277 }
2278 dir_lookup = NULL;
2279 }
2280 } ZEND_HASH_FOREACH_END();
2281 }
2282 if (nfiles == 0) {
2283 file_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
2284 if (file_lookup) {
2285 X509_LOOKUP_load_file(file_lookup, NULL, X509_FILETYPE_DEFAULT);
2286 }
2287 }
2288 if (ndirs == 0) {
2289 dir_lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
2290 if (dir_lookup) {
2291 X509_LOOKUP_add_dir(dir_lookup, NULL, X509_FILETYPE_DEFAULT);
2292 }
2293 }
2294 return store;
2295 }
2296
2297
2298
2299
2300 PHP_FUNCTION(openssl_x509_read)
2301 {
2302 zval *cert;
2303 X509 *x509;
2304 zend_resource *res;
2305
2306 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &cert) == FAILURE) {
2307 return;
2308 }
2309 x509 = php_openssl_x509_from_zval(cert, 1, &res);
2310 ZVAL_RES(return_value, res);
2311
2312 if (x509 == NULL) {
2313 php_error_docref(NULL, E_WARNING, "supplied parameter cannot be coerced into an X509 certificate!");
2314 RETURN_FALSE;
2315 }
2316 }
2317
2318
2319
2320
2321 PHP_FUNCTION(openssl_x509_free)
2322 {
2323 zval *x509;
2324 X509 *cert;
2325
2326 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &x509) == FAILURE) {
2327 return;
2328 }
2329 if ((cert = (X509 *)zend_fetch_resource(Z_RES_P(x509), "OpenSSL X.509", le_x509)) == NULL) {
2330 RETURN_FALSE;
2331 }
2332 zend_list_close(Z_RES_P(x509));
2333 }
2334
2335
2336
2337
2338
2339 static void php_sk_X509_free(STACK_OF(X509) * sk)
2340 {
2341 for (;;) {
2342 X509* x = sk_X509_pop(sk);
2343 if (!x) break;
2344 X509_free(x);
2345 }
2346 sk_X509_free(sk);
2347 }
2348
2349
2350 static STACK_OF(X509) * php_array_to_X509_sk(zval * zcerts)
2351 {
2352 zval * zcertval;
2353 STACK_OF(X509) * sk = NULL;
2354 X509 * cert;
2355 zend_resource *certresource;
2356
2357 sk = sk_X509_new_null();
2358
2359
2360 if (Z_TYPE_P(zcerts) == IS_ARRAY) {
2361 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zcerts), zcertval) {
2362 cert = php_openssl_x509_from_zval(zcertval, 0, &certresource);
2363 if (cert == NULL) {
2364 goto clean_exit;
2365 }
2366
2367 if (certresource != NULL) {
2368 cert = X509_dup(cert);
2369
2370 if (cert == NULL) {
2371 goto clean_exit;
2372 }
2373
2374 }
2375 sk_X509_push(sk, cert);
2376 } ZEND_HASH_FOREACH_END();
2377 } else {
2378
2379 cert = php_openssl_x509_from_zval(zcerts, 0, &certresource);
2380
2381 if (cert == NULL) {
2382 goto clean_exit;
2383 }
2384
2385 if (certresource != NULL) {
2386 cert = X509_dup(cert);
2387 if (cert == NULL) {
2388 goto clean_exit;
2389 }
2390 }
2391 sk_X509_push(sk, cert);
2392 }
2393
2394 clean_exit:
2395 return sk;
2396 }
2397
2398
2399
2400
2401 PHP_FUNCTION(openssl_pkcs12_export_to_file)
2402 {
2403 X509 * cert = NULL;
2404 BIO * bio_out = NULL;
2405 PKCS12 * p12 = NULL;
2406 char * filename;
2407 char * friendly_name = NULL;
2408 size_t filename_len;
2409 char * pass;
2410 size_t pass_len;
2411 zval *zcert = NULL, *zpkey = NULL, *args = NULL;
2412 EVP_PKEY *priv_key = NULL;
2413 zend_resource *certresource, *keyresource;
2414 zval * item;
2415 STACK_OF(X509) *ca = NULL;
2416
2417 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zpzs|a", &zcert, &filename, &filename_len, &zpkey, &pass, &pass_len, &args) == FAILURE)
2418 return;
2419
2420 RETVAL_FALSE;
2421
2422 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
2423 if (cert == NULL) {
2424 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1");
2425 return;
2426 }
2427 priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource);
2428 if (priv_key == NULL) {
2429 php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3");
2430 goto cleanup;
2431 }
2432 if (cert && !X509_check_private_key(cert, priv_key)) {
2433 php_error_docref(NULL, E_WARNING, "private key does not correspond to cert");
2434 goto cleanup;
2435 }
2436 if (php_openssl_open_base_dir_chk(filename)) {
2437 goto cleanup;
2438 }
2439
2440
2441 if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name")-1)) != NULL && Z_TYPE_P(item) == IS_STRING)
2442 friendly_name = Z_STRVAL_P(item);
2443
2444
2445
2446
2447
2448 if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL)
2449 ca = php_array_to_X509_sk(item);
2450
2451
2452
2453
2454
2455 p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
2456
2457 bio_out = BIO_new_file(filename, "w");
2458 if (bio_out) {
2459
2460 i2d_PKCS12_bio(bio_out, p12);
2461
2462 RETVAL_TRUE;
2463 } else {
2464 php_error_docref(NULL, E_WARNING, "error opening file %s", filename);
2465 }
2466
2467 BIO_free(bio_out);
2468 PKCS12_free(p12);
2469 php_sk_X509_free(ca);
2470
2471 cleanup:
2472
2473 if (keyresource == NULL && priv_key) {
2474 EVP_PKEY_free(priv_key);
2475 }
2476 if (certresource == NULL && cert) {
2477 X509_free(cert);
2478 }
2479 }
2480
2481
2482
2483
2484 PHP_FUNCTION(openssl_pkcs12_export)
2485 {
2486 X509 * cert = NULL;
2487 BIO * bio_out;
2488 PKCS12 * p12 = NULL;
2489 zval * zcert = NULL, *zout = NULL, *zpkey, *args = NULL;
2490 EVP_PKEY *priv_key = NULL;
2491 zend_resource *certresource, *keyresource;
2492 char * pass;
2493 size_t pass_len;
2494 char * friendly_name = NULL;
2495 zval * item;
2496 STACK_OF(X509) *ca = NULL;
2497
2498 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/zs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE)
2499 return;
2500
2501 RETVAL_FALSE;
2502
2503 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
2504 if (cert == NULL) {
2505 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 1");
2506 return;
2507 }
2508 priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource);
2509 if (priv_key == NULL) {
2510 php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3");
2511 goto cleanup;
2512 }
2513 if (cert && !X509_check_private_key(cert, priv_key)) {
2514 php_error_docref(NULL, E_WARNING, "private key does not correspond to cert");
2515 goto cleanup;
2516 }
2517
2518
2519 if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "friendly_name", sizeof("friendly_name")-1)) != NULL && Z_TYPE_P(item) == IS_STRING)
2520 friendly_name = Z_STRVAL_P(item);
2521
2522 if (args && (item = zend_hash_str_find(Z_ARRVAL_P(args), "extracerts", sizeof("extracerts")-1)) != NULL)
2523 ca = php_array_to_X509_sk(item);
2524
2525
2526 p12 = PKCS12_create(pass, friendly_name, priv_key, cert, ca, 0, 0, 0, 0, 0);
2527
2528 bio_out = BIO_new(BIO_s_mem());
2529 if (i2d_PKCS12_bio(bio_out, p12)) {
2530 BUF_MEM *bio_buf;
2531
2532 zval_dtor(zout);
2533 BIO_get_mem_ptr(bio_out, &bio_buf);
2534 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length);
2535
2536 RETVAL_TRUE;
2537 }
2538
2539 BIO_free(bio_out);
2540 PKCS12_free(p12);
2541 php_sk_X509_free(ca);
2542
2543 cleanup:
2544
2545 if (keyresource == NULL && priv_key) {
2546 EVP_PKEY_free(priv_key);
2547 }
2548 if (certresource == NULL && cert) {
2549 X509_free(cert);
2550 }
2551 }
2552
2553
2554
2555
2556 PHP_FUNCTION(openssl_pkcs12_read)
2557 {
2558 zval *zout = NULL, zextracerts, zcert, zpkey;
2559 char *pass, *zp12;
2560 size_t pass_len, zp12_len;
2561 PKCS12 * p12 = NULL;
2562 EVP_PKEY * pkey = NULL;
2563 X509 * cert = NULL;
2564 STACK_OF(X509) * ca = NULL;
2565 BIO * bio_in = NULL;
2566 int i;
2567
2568 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/s", &zp12, &zp12_len, &zout, &pass, &pass_len) == FAILURE)
2569 return;
2570
2571 RETVAL_FALSE;
2572
2573 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(zp12_len, pkcs12);
2574
2575 bio_in = BIO_new(BIO_s_mem());
2576
2577 if(0 >= BIO_write(bio_in, zp12, (int)zp12_len))
2578 goto cleanup;
2579
2580 if(d2i_PKCS12_bio(bio_in, &p12)) {
2581 if(PKCS12_parse(p12, pass, &pkey, &cert, &ca)) {
2582 BIO * bio_out;
2583
2584 zval_dtor(zout);
2585 array_init(zout);
2586
2587 bio_out = BIO_new(BIO_s_mem());
2588 if (PEM_write_bio_X509(bio_out, cert)) {
2589 BUF_MEM *bio_buf;
2590 BIO_get_mem_ptr(bio_out, &bio_buf);
2591 ZVAL_STRINGL(&zcert, bio_buf->data, bio_buf->length);
2592 add_assoc_zval(zout, "cert", &zcert);
2593 }
2594 BIO_free(bio_out);
2595
2596 bio_out = BIO_new(BIO_s_mem());
2597 if (PEM_write_bio_PrivateKey(bio_out, pkey, NULL, NULL, 0, 0, NULL)) {
2598 BUF_MEM *bio_buf;
2599 BIO_get_mem_ptr(bio_out, &bio_buf);
2600 ZVAL_STRINGL(&zpkey, bio_buf->data, bio_buf->length);
2601 add_assoc_zval(zout, "pkey", &zpkey);
2602 }
2603 BIO_free(bio_out);
2604
2605 array_init(&zextracerts);
2606
2607 for (i=0;;i++) {
2608 zval zextracert;
2609 X509* aCA = sk_X509_pop(ca);
2610 if (!aCA) break;
2611
2612
2613 {
2614 int err = ERR_peek_error();
2615 if (err == OPENSSL_ERROR_X509_PRIVATE_KEY_VALUES_MISMATCH) {
2616 ERR_get_error();
2617 }
2618 }
2619
2620 bio_out = BIO_new(BIO_s_mem());
2621 if (PEM_write_bio_X509(bio_out, aCA)) {
2622 BUF_MEM *bio_buf;
2623 BIO_get_mem_ptr(bio_out, &bio_buf);
2624 ZVAL_STRINGL(&zextracert, bio_buf->data, bio_buf->length);
2625 add_index_zval(&zextracerts, i, &zextracert);
2626
2627 }
2628 BIO_free(bio_out);
2629
2630 X509_free(aCA);
2631 }
2632 if(ca) {
2633 sk_X509_free(ca);
2634 add_assoc_zval(zout, "extracerts", &zextracerts);
2635 } else {
2636 zval_dtor(&zextracerts);
2637 }
2638
2639 RETVAL_TRUE;
2640
2641 PKCS12_free(p12);
2642 }
2643 }
2644
2645 cleanup:
2646 if (bio_in) {
2647 BIO_free(bio_in);
2648 }
2649 if (pkey) {
2650 EVP_PKEY_free(pkey);
2651 }
2652 if (cert) {
2653 X509_free(cert);
2654 }
2655 }
2656
2657
2658
2659
2660
2661 static int php_openssl_make_REQ(struct php_x509_request * req, X509_REQ * csr, zval * dn, zval * attribs)
2662 {
2663 STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL;
2664 char * str, *dn_sect, *attr_sect;
2665
2666 dn_sect = CONF_get_string(req->req_config, req->section_name, "distinguished_name");
2667 if (dn_sect == NULL) {
2668 return FAILURE;
2669 }
2670 dn_sk = CONF_get_section(req->req_config, dn_sect);
2671 if (dn_sk == NULL) {
2672 return FAILURE;
2673 }
2674 attr_sect = CONF_get_string(req->req_config, req->section_name, "attributes");
2675 if (attr_sect == NULL) {
2676 attr_sk = NULL;
2677 } else {
2678 attr_sk = CONF_get_section(req->req_config, attr_sect);
2679 if (attr_sk == NULL) {
2680 return FAILURE;
2681 }
2682 }
2683
2684 if (X509_REQ_set_version(csr, 0L)) {
2685 int i, nid;
2686 char * type;
2687 CONF_VALUE * v;
2688 X509_NAME * subj;
2689 zval * item;
2690 zend_string * strindex = NULL;
2691
2692 subj = X509_REQ_get_subject_name(csr);
2693
2694 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(dn), strindex, item) {
2695 if (strindex) {
2696 int nid;
2697
2698 convert_to_string_ex(item);
2699
2700 nid = OBJ_txt2nid(ZSTR_VAL(strindex));
2701 if (nid != NID_undef) {
2702 if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8,
2703 (unsigned char*)Z_STRVAL_P(item), -1, -1, 0))
2704 {
2705 php_error_docref(NULL, E_WARNING,
2706 "dn: add_entry_by_NID %d -> %s (failed; check error"
2707 " queue and value of string_mask OpenSSL option "
2708 "if illegal characters are reported)",
2709 nid, Z_STRVAL_P(item));
2710 return FAILURE;
2711 }
2712 } else {
2713 php_error_docref(NULL, E_WARNING, "dn: %s is not a recognized name", ZSTR_VAL(strindex));
2714 }
2715 }
2716 } ZEND_HASH_FOREACH_END();
2717
2718
2719 for(i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) {
2720 int len;
2721 char buffer[200 + 1];
2722
2723 v = sk_CONF_VALUE_value(dn_sk, i);
2724 type = v->name;
2725
2726 len = (int)strlen(type);
2727 if (len < sizeof("_default")) {
2728 continue;
2729 }
2730 len -= sizeof("_default") - 1;
2731 if (strcmp("_default", type + len) != 0) {
2732 continue;
2733 }
2734 if (len > 200) {
2735 len = 200;
2736 }
2737 memcpy(buffer, type, len);
2738 buffer[len] = '\0';
2739 type = buffer;
2740
2741
2742
2743 for (str = type; *str; str++) {
2744 if (*str == ':' || *str == ',' || *str == '.') {
2745 str++;
2746 if (*str) {
2747 type = str;
2748 }
2749 break;
2750 }
2751 }
2752
2753 nid = OBJ_txt2nid(type);
2754 if (X509_NAME_get_index_by_NID(subj, nid, -1) >= 0) {
2755 continue;
2756 }
2757 if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_UTF8, (unsigned char*)v->value, -1, -1, 0)) {
2758 php_error_docref(NULL, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value);
2759 return FAILURE;
2760 }
2761 if (!X509_NAME_entry_count(subj)) {
2762 php_error_docref(NULL, E_WARNING, "no objects specified in config file");
2763 return FAILURE;
2764 }
2765 }
2766 if (attribs) {
2767 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(attribs), strindex, item) {
2768 int nid;
2769
2770 convert_to_string_ex(item);
2771
2772 nid = OBJ_txt2nid(ZSTR_VAL(strindex));
2773 if (nid != NID_undef) {
2774 if (!X509_NAME_add_entry_by_NID(subj, nid, MBSTRING_UTF8, (unsigned char*)Z_STRVAL_P(item), -1, -1, 0)) {
2775 php_error_docref(NULL, E_WARNING, "attribs: add_entry_by_NID %d -> %s (failed)", nid, Z_STRVAL_P(item));
2776 return FAILURE;
2777 }
2778 } else {
2779 php_error_docref(NULL, E_WARNING, "dn: %s is not a recognized name", ZSTR_VAL(strindex));
2780 }
2781 } ZEND_HASH_FOREACH_END();
2782 for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) {
2783 v = sk_CONF_VALUE_value(attr_sk, i);
2784
2785 nid = OBJ_txt2nid(v->name);
2786 if (X509_REQ_get_attr_by_NID(csr, nid, -1) >= 0) {
2787 continue;
2788 }
2789 if (!X509_REQ_add1_attr_by_txt(csr, v->name, MBSTRING_UTF8, (unsigned char*)v->value, -1)) {
2790 php_error_docref(NULL, E_WARNING,
2791 "add1_attr_by_txt %s -> %s (failed; check error queue "
2792 "and value of string_mask OpenSSL option if illegal "
2793 "characters are reported)",
2794 v->name, v->value);
2795 return FAILURE;
2796 }
2797 }
2798 }
2799 }
2800
2801 X509_REQ_set_pubkey(csr, req->priv_key);
2802 return SUCCESS;
2803 }
2804
2805
2806
2807 static X509_REQ * php_openssl_csr_from_zval(zval * val, int makeresource, zend_resource **resourceval)
2808 {
2809 X509_REQ * csr = NULL;
2810 char * filename = NULL;
2811 BIO * in;
2812
2813 if (resourceval) {
2814 *resourceval = NULL;
2815 }
2816 if (Z_TYPE_P(val) == IS_RESOURCE) {
2817 void * what;
2818 zend_resource *res = Z_RES_P(val);
2819
2820 what = zend_fetch_resource(res, "OpenSSL X.509 CSR", le_csr);
2821 if (what) {
2822 if (resourceval) {
2823 *resourceval = res;
2824 Z_ADDREF_P(val);
2825 }
2826 return (X509_REQ*)what;
2827 }
2828 return NULL;
2829 } else if (Z_TYPE_P(val) != IS_STRING) {
2830 return NULL;
2831 }
2832
2833 if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) {
2834 filename = Z_STRVAL_P(val) + (sizeof("file://") - 1);
2835 }
2836 if (filename) {
2837 if (php_openssl_open_base_dir_chk(filename)) {
2838 return NULL;
2839 }
2840 in = BIO_new_file(filename, "r");
2841 } else {
2842 in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val));
2843 }
2844 csr = PEM_read_bio_X509_REQ(in, NULL,NULL,NULL);
2845 BIO_free(in);
2846
2847 return csr;
2848 }
2849
2850
2851
2852
2853 PHP_FUNCTION(openssl_csr_export_to_file)
2854 {
2855 X509_REQ * csr;
2856 zval * zcsr = NULL;
2857 zend_bool notext = 1;
2858 char * filename = NULL;
2859 size_t filename_len;
2860 BIO * bio_out;
2861 zend_resource *csr_resource;
2862
2863 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rp|b", &zcsr, &filename, &filename_len, ¬ext) == FAILURE) {
2864 return;
2865 }
2866 RETVAL_FALSE;
2867
2868 csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource);
2869 if (csr == NULL) {
2870 php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1");
2871 return;
2872 }
2873
2874 if (php_openssl_open_base_dir_chk(filename)) {
2875 return;
2876 }
2877
2878 bio_out = BIO_new_file(filename, "w");
2879 if (bio_out) {
2880 if (!notext) {
2881 X509_REQ_print(bio_out, csr);
2882 }
2883 PEM_write_bio_X509_REQ(bio_out, csr);
2884 RETVAL_TRUE;
2885 } else {
2886 php_error_docref(NULL, E_WARNING, "error opening file %s", filename);
2887 }
2888
2889 if (csr_resource == NULL && csr) {
2890 X509_REQ_free(csr);
2891 }
2892 BIO_free(bio_out);
2893 }
2894
2895
2896
2897
2898 PHP_FUNCTION(openssl_csr_export)
2899 {
2900 X509_REQ * csr;
2901 zval * zcsr = NULL, *zout=NULL;
2902 zend_bool notext = 1;
2903 BIO * bio_out;
2904 zend_resource *csr_resource;
2905
2906 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|b", &zcsr, &zout, ¬ext) == FAILURE) {
2907 return;
2908 }
2909
2910 RETVAL_FALSE;
2911
2912 csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource);
2913 if (csr == NULL) {
2914 php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1");
2915 return;
2916 }
2917
2918
2919
2920 bio_out = BIO_new(BIO_s_mem());
2921 if (!notext) {
2922 X509_REQ_print(bio_out, csr);
2923 }
2924
2925 if (PEM_write_bio_X509_REQ(bio_out, csr)) {
2926 BUF_MEM *bio_buf;
2927
2928 BIO_get_mem_ptr(bio_out, &bio_buf);
2929 zval_dtor(zout);
2930 ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length);
2931
2932 RETVAL_TRUE;
2933 }
2934
2935 if (csr_resource == NULL && csr) {
2936 X509_REQ_free(csr);
2937 }
2938 BIO_free(bio_out);
2939 }
2940
2941
2942
2943
2944 PHP_FUNCTION(openssl_csr_sign)
2945 {
2946 zval * zcert = NULL, *zcsr, *zpkey, *args = NULL;
2947 zend_long num_days;
2948 zend_long serial = Z_L(0);
2949 X509 * cert = NULL, *new_cert = NULL;
2950 X509_REQ * csr;
2951 EVP_PKEY * key = NULL, *priv_key = NULL;
2952 zend_resource *csr_resource, *certresource = NULL, *keyresource = NULL;
2953 int i;
2954 struct php_x509_request req;
2955
2956 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz!zl|a!l", &zcsr, &zcert, &zpkey, &num_days, &args, &serial) == FAILURE)
2957 return;
2958
2959 RETVAL_FALSE;
2960 PHP_SSL_REQ_INIT(&req);
2961
2962 csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource);
2963 if (csr == NULL) {
2964 php_error_docref(NULL, E_WARNING, "cannot get CSR from parameter 1");
2965 return;
2966 }
2967 if (zcert) {
2968 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
2969 if (cert == NULL) {
2970 php_error_docref(NULL, E_WARNING, "cannot get cert from parameter 2");
2971 goto cleanup;
2972 }
2973 }
2974 priv_key = php_openssl_evp_from_zval(zpkey, 0, "", 1, &keyresource);
2975 if (priv_key == NULL) {
2976 php_error_docref(NULL, E_WARNING, "cannot get private key from parameter 3");
2977 goto cleanup;
2978 }
2979 if (cert && !X509_check_private_key(cert, priv_key)) {
2980 php_error_docref(NULL, E_WARNING, "private key does not correspond to signing cert");
2981 goto cleanup;
2982 }
2983
2984 if (PHP_SSL_REQ_PARSE(&req, args) == FAILURE) {
2985 goto cleanup;
2986 }
2987
2988 key = X509_REQ_get_pubkey(csr);
2989 if (key == NULL) {
2990 php_error_docref(NULL, E_WARNING, "error unpacking public key");
2991 goto cleanup;
2992 }
2993 i = X509_REQ_verify(csr, key);
2994
2995 if (i < 0) {
2996 php_error_docref(NULL, E_WARNING, "Signature verification problems");
2997 goto cleanup;
2998 }
2999 else if (i == 0) {
3000 php_error_docref(NULL, E_WARNING, "Signature did not match the certificate request");
3001 goto cleanup;
3002 }
3003
3004
3005
3006 new_cert = X509_new();
3007 if (new_cert == NULL) {
3008 php_error_docref(NULL, E_WARNING, "No memory");
3009 goto cleanup;
3010 }
3011
3012 if (!X509_set_version(new_cert, 2))
3013 goto cleanup;
3014
3015
3016 ASN1_INTEGER_set(X509_get_serialNumber(new_cert), (long)serial);
3017
3018 X509_set_subject_name(new_cert, X509_REQ_get_subject_name(csr));
3019
3020 if (cert == NULL) {
3021 cert = new_cert;
3022 }
3023 if (!X509_set_issuer_name(new_cert, X509_get_subject_name(cert))) {
3024 goto cleanup;
3025 }
3026 X509_gmtime_adj(X509_get_notBefore(new_cert), 0);
3027 X509_gmtime_adj(X509_get_notAfter(new_cert), 60*60*24*(long)num_days);
3028 i = X509_set_pubkey(new_cert, key);
3029 if (!i) {
3030 goto cleanup;
3031 }
3032 if (req.extensions_section) {
3033 X509V3_CTX ctx;
3034
3035 X509V3_set_ctx(&ctx, cert, new_cert, csr, NULL, 0);
3036 X509V3_set_conf_lhash(&ctx, req.req_config);
3037 if (!X509V3_EXT_add_conf(req.req_config, &ctx, req.extensions_section, new_cert)) {
3038 goto cleanup;
3039 }
3040 }
3041
3042
3043 if (!X509_sign(new_cert, priv_key, req.digest)) {
3044 php_error_docref(NULL, E_WARNING, "failed to sign it");
3045 goto cleanup;
3046 }
3047
3048
3049 ZVAL_RES(return_value, zend_register_resource(new_cert, le_x509));
3050 new_cert = NULL;
3051
3052 cleanup:
3053
3054 if (cert == new_cert) {
3055 cert = NULL;
3056 }
3057 PHP_SSL_REQ_DISPOSE(&req);
3058
3059 if (keyresource == NULL && priv_key) {
3060 EVP_PKEY_free(priv_key);
3061 }
3062 if (key) {
3063 EVP_PKEY_free(key);
3064 }
3065 if (csr_resource == NULL && csr) {
3066 X509_REQ_free(csr);
3067 }
3068 if (zcert && certresource == NULL && cert) {
3069 X509_free(cert);
3070 }
3071 if (new_cert) {
3072 X509_free(new_cert);
3073 }
3074 }
3075
3076
3077
3078
3079 PHP_FUNCTION(openssl_csr_new)
3080 {
3081 struct php_x509_request req;
3082 zval * args = NULL, * dn, *attribs = NULL;
3083 zval * out_pkey;
3084 X509_REQ * csr = NULL;
3085 int we_made_the_key = 1;
3086 zend_resource *key_resource;
3087
3088 if (zend_parse_parameters(ZEND_NUM_ARGS(), "az/|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) {
3089 return;
3090 }
3091 RETVAL_FALSE;
3092
3093 PHP_SSL_REQ_INIT(&req);
3094
3095 if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
3096
3097 if (Z_TYPE_P(out_pkey) != IS_NULL) {
3098 req.priv_key = php_openssl_evp_from_zval(out_pkey, 0, NULL, 0, &key_resource);
3099 if (req.priv_key != NULL) {
3100 we_made_the_key = 0;
3101 }
3102 }
3103 if (req.priv_key == NULL) {
3104 php_openssl_generate_private_key(&req);
3105 }
3106 if (req.priv_key == NULL) {
3107 php_error_docref(NULL, E_WARNING, "Unable to generate a private key");
3108 } else {
3109 csr = X509_REQ_new();
3110 if (csr) {
3111 if (php_openssl_make_REQ(&req, csr, dn, attribs) == SUCCESS) {
3112 X509V3_CTX ext_ctx;
3113
3114 X509V3_set_ctx(&ext_ctx, NULL, NULL, csr, NULL, 0);
3115 X509V3_set_conf_lhash(&ext_ctx, req.req_config);
3116
3117
3118 if (req.request_extensions_section && !X509V3_EXT_REQ_add_conf(req.req_config,
3119 &ext_ctx, req.request_extensions_section, csr))
3120 {
3121 php_error_docref(NULL, E_WARNING, "Error loading extension section %s", req.request_extensions_section);
3122 } else {
3123 RETVAL_TRUE;
3124
3125 if (X509_REQ_sign(csr, req.priv_key, req.digest)) {
3126 ZVAL_RES(return_value, zend_register_resource(csr, le_csr));
3127 csr = NULL;
3128 } else {
3129 php_error_docref(NULL, E_WARNING, "Error signing request");
3130 }
3131
3132 if (we_made_the_key) {
3133
3134 zval_dtor(out_pkey);
3135 ZVAL_RES(out_pkey, zend_register_resource(req.priv_key, le_key));
3136 req.priv_key = NULL;
3137 } else if (key_resource != NULL) {
3138 req.priv_key = NULL;
3139 }
3140 }
3141 }
3142 else {
3143 if (!we_made_the_key) {
3144
3145 req.priv_key = NULL;
3146 }
3147 }
3148 }
3149 }
3150 }
3151 if (csr) {
3152 X509_REQ_free(csr);
3153 }
3154 PHP_SSL_REQ_DISPOSE(&req);
3155 }
3156
3157
3158
3159
3160 PHP_FUNCTION(openssl_csr_get_subject)
3161 {
3162 zval * zcsr;
3163 zend_bool use_shortnames = 1;
3164 zend_resource *csr_resource;
3165 X509_NAME * subject;
3166 X509_REQ * csr;
3167
3168 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcsr, &use_shortnames) == FAILURE) {
3169 return;
3170 }
3171
3172 csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource);
3173
3174 if (csr == NULL) {
3175 RETURN_FALSE;
3176 }
3177
3178 subject = X509_REQ_get_subject_name(csr);
3179
3180 array_init(return_value);
3181 add_assoc_name_entry(return_value, NULL, subject, use_shortnames);
3182 return;
3183 }
3184
3185
3186
3187
3188 PHP_FUNCTION(openssl_csr_get_public_key)
3189 {
3190 zval * zcsr;
3191 zend_bool use_shortnames = 1;
3192 zend_resource *csr_resource;
3193
3194 X509_REQ * csr;
3195 EVP_PKEY *tpubkey;
3196
3197 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &zcsr, &use_shortnames) == FAILURE) {
3198 return;
3199 }
3200
3201 csr = php_openssl_csr_from_zval(zcsr, 0, &csr_resource);
3202
3203 if (csr == NULL) {
3204 RETURN_FALSE;
3205 }
3206
3207 tpubkey=X509_REQ_get_pubkey(csr);
3208 RETURN_RES(zend_register_resource(tpubkey, le_key));
3209 }
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229 static EVP_PKEY * php_openssl_evp_from_zval(zval * val, int public_key, char * passphrase, int makeresource, zend_resource **resourceval)
3230 {
3231 EVP_PKEY * key = NULL;
3232 X509 * cert = NULL;
3233 int free_cert = 0;
3234 zend_resource *cert_res = NULL;
3235 char * filename = NULL;
3236 zval tmp;
3237
3238 ZVAL_NULL(&tmp);
3239
3240 #define TMP_CLEAN \
3241 if (Z_TYPE(tmp) == IS_STRING) {\
3242 zval_dtor(&tmp); \
3243 } \
3244 return NULL;
3245
3246 if (resourceval) {
3247 *resourceval = NULL;
3248 }
3249 if (Z_TYPE_P(val) == IS_ARRAY) {
3250 zval * zphrase;
3251
3252
3253
3254 if ((zphrase = zend_hash_index_find(Z_ARRVAL_P(val), 1)) == NULL) {
3255 php_error_docref(NULL, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)");
3256 return NULL;
3257 }
3258
3259 if (Z_TYPE_P(zphrase) == IS_STRING) {
3260 passphrase = Z_STRVAL_P(zphrase);
3261 } else {
3262 ZVAL_COPY(&tmp, zphrase);
3263 convert_to_string(&tmp);
3264 passphrase = Z_STRVAL(tmp);
3265 }
3266
3267
3268 if ((val = zend_hash_index_find(Z_ARRVAL_P(val), 0)) == NULL) {
3269 php_error_docref(NULL, E_WARNING, "key array must be of the form array(0 => key, 1 => phrase)");
3270 TMP_CLEAN;
3271 }
3272 }
3273
3274 if (Z_TYPE_P(val) == IS_RESOURCE) {
3275 void * what;
3276 zend_resource * res = Z_RES_P(val);
3277
3278 what = zend_fetch_resource2(res, "OpenSSL X.509/key", le_x509, le_key);
3279 if (!what) {
3280 TMP_CLEAN;
3281 }
3282 if (resourceval) {
3283 *resourceval = res;
3284 Z_ADDREF_P(val);
3285 }
3286 if (res->type == le_x509) {
3287
3288 cert = (X509*)what;
3289 free_cert = 0;
3290 } else if (res->type == le_key) {
3291 int is_priv;
3292
3293 is_priv = php_openssl_is_private_key((EVP_PKEY*)what);
3294
3295
3296 if (!public_key && !is_priv) {
3297 php_error_docref(NULL, E_WARNING, "supplied key param is a public key");
3298 TMP_CLEAN;
3299 }
3300
3301 if (public_key && is_priv) {
3302 php_error_docref(NULL, E_WARNING, "Don't know how to get public key from this private key");
3303 TMP_CLEAN;
3304 } else {
3305 if (Z_TYPE(tmp) == IS_STRING) {
3306 zval_dtor(&tmp);
3307 }
3308
3309 return (EVP_PKEY*)what;
3310 }
3311 } else {
3312
3313 TMP_CLEAN;
3314 }
3315 } else {
3316
3317
3318
3319
3320 if (!(Z_TYPE_P(val) == IS_STRING || Z_TYPE_P(val) == IS_OBJECT)) {
3321 TMP_CLEAN;
3322 }
3323 convert_to_string_ex(val);
3324
3325 if (Z_STRLEN_P(val) > 7 && memcmp(Z_STRVAL_P(val), "file://", sizeof("file://") - 1) == 0) {
3326 filename = Z_STRVAL_P(val) + (sizeof("file://") - 1);
3327 }
3328
3329 if (public_key) {
3330 cert = php_openssl_x509_from_zval(val, 0, &cert_res);
3331 free_cert = (cert_res == NULL);
3332
3333 if (!cert) {
3334
3335 BIO* in;
3336 if (filename) {
3337 in = BIO_new_file(filename, "r");
3338 } else {
3339 in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val));
3340 }
3341 if (in == NULL) {
3342 TMP_CLEAN;
3343 }
3344 key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
3345 BIO_free(in);
3346 }
3347 } else {
3348
3349 BIO *in;
3350
3351 if (filename) {
3352 if (php_openssl_open_base_dir_chk(filename)) {
3353 TMP_CLEAN;
3354 }
3355 in = BIO_new_file(filename, "r");
3356 } else {
3357 in = BIO_new_mem_buf(Z_STRVAL_P(val), (int)Z_STRLEN_P(val));
3358 }
3359
3360 if (in == NULL) {
3361 TMP_CLEAN;
3362 }
3363 key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);
3364 BIO_free(in);
3365 }
3366 }
3367
3368 if (public_key && cert && key == NULL) {
3369
3370 key = (EVP_PKEY *) X509_get_pubkey(cert);
3371 }
3372
3373 if (free_cert && cert) {
3374 X509_free(cert);
3375 }
3376 if (key && makeresource && resourceval) {
3377 *resourceval = zend_register_resource(key, le_key);
3378 }
3379 if (Z_TYPE(tmp) == IS_STRING) {
3380 zval_dtor(&tmp);
3381 }
3382 return key;
3383 }
3384
3385
3386
3387 static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req)
3388 {
3389 char * randfile = NULL;
3390 int egdsocket, seeded;
3391 EVP_PKEY * return_val = NULL;
3392
3393 if (req->priv_key_bits < MIN_KEY_LENGTH) {
3394 php_error_docref(NULL, E_WARNING, "private key length is too short; it needs to be at least %d bits, not %d",
3395 MIN_KEY_LENGTH, req->priv_key_bits);
3396 return NULL;
3397 }
3398
3399 randfile = CONF_get_string(req->req_config, req->section_name, "RANDFILE");
3400 php_openssl_load_rand_file(randfile, &egdsocket, &seeded);
3401
3402 if ((req->priv_key = EVP_PKEY_new()) != NULL) {
3403 switch(req->priv_key_type) {
3404 case OPENSSL_KEYTYPE_RSA:
3405 {
3406 RSA* rsaparam;
3407 #if OPENSSL_VERSION_NUMBER < 0x10002000L
3408
3409 rsaparam = (RSA*)RSA_generate_key(req->priv_key_bits, RSA_F4, NULL, NULL);
3410 #else
3411 {
3412 BIGNUM *bne = (BIGNUM *)BN_new();
3413 if (BN_set_word(bne, RSA_F4) != 1) {
3414 BN_free(bne);
3415 php_error_docref(NULL, E_WARNING, "failed setting exponent");
3416 return NULL;
3417 }
3418 rsaparam = RSA_new();
3419 RSA_generate_key_ex(rsaparam, req->priv_key_bits, bne, NULL);
3420 BN_free(bne);
3421 }
3422 #endif
3423 if (rsaparam && EVP_PKEY_assign_RSA(req->priv_key, rsaparam)) {
3424 return_val = req->priv_key;
3425 }
3426 }
3427 break;
3428 #if !defined(NO_DSA)
3429 case OPENSSL_KEYTYPE_DSA:
3430 {
3431 DSA *dsaparam = NULL;
3432 #if OPENSSL_VERSION_NUMBER < 0x10002000L
3433 dsaparam = DSA_generate_parameters(req->priv_key_bits, NULL, 0, NULL, NULL, NULL, NULL);
3434 #else
3435 DSA_generate_parameters_ex(dsaparam, req->priv_key_bits, NULL, 0, NULL, NULL, NULL);
3436 #endif
3437 if (dsaparam) {
3438 DSA_set_method(dsaparam, DSA_get_default_method());
3439 if (DSA_generate_key(dsaparam)) {
3440 if (EVP_PKEY_assign_DSA(req->priv_key, dsaparam)) {
3441 return_val = req->priv_key;
3442 }
3443 } else {
3444 DSA_free(dsaparam);
3445 }
3446 }
3447 }
3448 break;
3449 #endif
3450 #if !defined(NO_DH)
3451 case OPENSSL_KEYTYPE_DH:
3452 {
3453 int codes = 0;
3454 DH *dhparam = NULL;
3455 #if OPENSSL_VERSION_NUMBER < 0x10002000L
3456 dhparam = DH_generate_parameters(req->priv_key_bits, 2, NULL, NULL);
3457 #else
3458 DH_generate_parameters_ex(dhparam, req->priv_key_bits, 2, NULL);
3459 #endif
3460 if (dhparam) {
3461 DH_set_method(dhparam, DH_get_default_method());
3462 if (DH_check(dhparam, &codes) && codes == 0 && DH_generate_key(dhparam)) {
3463 if (EVP_PKEY_assign_DH(req->priv_key, dhparam)) {
3464 return_val = req->priv_key;
3465 }
3466 } else {
3467 DH_free(dhparam);
3468 }
3469 }
3470 }
3471 break;
3472 #endif
3473 default:
3474 php_error_docref(NULL, E_WARNING, "Unsupported private key type");
3475 }
3476 }
3477
3478 php_openssl_write_rand_file(randfile, egdsocket, seeded);
3479
3480 if (return_val == NULL) {
3481 EVP_PKEY_free(req->priv_key);
3482 req->priv_key = NULL;
3483 return NULL;
3484 }
3485
3486 return return_val;
3487 }
3488
3489
3490
3491
3492 static int php_openssl_is_private_key(EVP_PKEY* pkey)
3493 {
3494 assert(pkey != NULL);
3495
3496 switch (pkey->type) {
3497 #ifndef NO_RSA
3498 case EVP_PKEY_RSA:
3499 case EVP_PKEY_RSA2:
3500 assert(pkey->pkey.rsa != NULL);
3501 if (pkey->pkey.rsa != NULL && (NULL == pkey->pkey.rsa->p || NULL == pkey->pkey.rsa->q)) {
3502 return 0;
3503 }
3504 break;
3505 #endif
3506 #ifndef NO_DSA
3507 case EVP_PKEY_DSA:
3508 case EVP_PKEY_DSA1:
3509 case EVP_PKEY_DSA2:
3510 case EVP_PKEY_DSA3:
3511 case EVP_PKEY_DSA4:
3512 assert(pkey->pkey.dsa != NULL);
3513
3514 if (NULL == pkey->pkey.dsa->p || NULL == pkey->pkey.dsa->q || NULL == pkey->pkey.dsa->priv_key){
3515 return 0;
3516 }
3517 break;
3518 #endif
3519 #ifndef NO_DH
3520 case EVP_PKEY_DH:
3521 assert(pkey->pkey.dh != NULL);
3522
3523 if (NULL == pkey->pkey.dh->p || NULL == pkey->pkey.dh->priv_key) {
3524 return 0;
3525 }
3526 break;
3527 #endif
3528 #ifdef HAVE_EVP_PKEY_EC
3529 case EVP_PKEY_EC:
3530 assert(pkey->pkey.ec != NULL);
3531
3532 if ( NULL == EC_KEY_get0_private_key(pkey->pkey.ec)) {
3533 return 0;
3534 }
3535 break;
3536 #endif
3537 default:
3538 php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
3539 break;
3540 }
3541 return 1;
3542 }
3543
3544
3545 #define OPENSSL_PKEY_GET_BN(_type, _name) do { \
3546 if (pkey->pkey._type->_name != NULL) { \
3547 int len = BN_num_bytes(pkey->pkey._type->_name); \
3548 zend_string *str = zend_string_alloc(len, 0); \
3549 BN_bn2bin(pkey->pkey._type->_name, (unsigned char*)ZSTR_VAL(str)); \
3550 ZSTR_VAL(str)[len] = 0; \
3551 add_assoc_str(&_type, #_name, str); \
3552 } \
3553 } while (0)
3554
3555 #define OPENSSL_PKEY_SET_BN(_ht, _type, _name) do { \
3556 zval *bn; \
3557 if ((bn = zend_hash_str_find(_ht, #_name, sizeof(#_name)-1)) != NULL && \
3558 Z_TYPE_P(bn) == IS_STRING) { \
3559 _type->_name = BN_bin2bn( \
3560 (unsigned char*)Z_STRVAL_P(bn), \
3561 (int)Z_STRLEN_P(bn), NULL); \
3562 } \
3563 } while (0);
3564
3565
3566
3567
3568 PHP_FUNCTION(openssl_pkey_new)
3569 {
3570 struct php_x509_request req;
3571 zval * args = NULL;
3572 zval *data;
3573
3574 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &args) == FAILURE) {
3575 return;
3576 }
3577 RETVAL_FALSE;
3578
3579 if (args && Z_TYPE_P(args) == IS_ARRAY) {
3580 EVP_PKEY *pkey;
3581
3582 if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "rsa", sizeof("rsa")-1)) != NULL &&
3583 Z_TYPE_P(data) == IS_ARRAY) {
3584 pkey = EVP_PKEY_new();
3585 if (pkey) {
3586 RSA *rsa = RSA_new();
3587 if (rsa) {
3588 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, n);
3589 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, e);
3590 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, d);
3591 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, p);
3592 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, q);
3593 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, dmp1);
3594 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, dmq1);
3595 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), rsa, iqmp);
3596 if (rsa->n && rsa->d) {
3597 if (EVP_PKEY_assign_RSA(pkey, rsa)) {
3598 RETURN_RES(zend_register_resource(pkey, le_key));
3599 }
3600 }
3601 RSA_free(rsa);
3602 }
3603 EVP_PKEY_free(pkey);
3604 }
3605 RETURN_FALSE;
3606 } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dsa", sizeof("dsa") - 1)) != NULL &&
3607 Z_TYPE_P(data) == IS_ARRAY) {
3608 pkey = EVP_PKEY_new();
3609 if (pkey) {
3610 DSA *dsa = DSA_new();
3611 if (dsa) {
3612 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dsa, p);
3613 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dsa, q);
3614 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dsa, g);
3615 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dsa, priv_key);
3616 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dsa, pub_key);
3617 if (dsa->p && dsa->q && dsa->g) {
3618 if (!dsa->priv_key && !dsa->pub_key) {
3619 DSA_generate_key(dsa);
3620 }
3621 if (EVP_PKEY_assign_DSA(pkey, dsa)) {
3622 RETURN_RES(zend_register_resource(pkey, le_key));
3623 }
3624 }
3625 DSA_free(dsa);
3626 }
3627 EVP_PKEY_free(pkey);
3628 }
3629 RETURN_FALSE;
3630 } else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dh", sizeof("dh") - 1)) != NULL &&
3631 Z_TYPE_P(data) == IS_ARRAY) {
3632 pkey = EVP_PKEY_new();
3633 if (pkey) {
3634 DH *dh = DH_new();
3635 if (dh) {
3636 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dh, p);
3637 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dh, g);
3638 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dh, priv_key);
3639 OPENSSL_PKEY_SET_BN(Z_ARRVAL_P(data), dh, pub_key);
3640 if (dh->p && dh->g &&
3641 (dh->pub_key || DH_generate_key(dh)) &&
3642 EVP_PKEY_assign_DH(pkey, dh)) {
3643 ZVAL_COPY_VALUE(return_value, zend_list_insert(pkey, le_key));
3644 return;
3645 }
3646 DH_free(dh);
3647 }
3648 EVP_PKEY_free(pkey);
3649 }
3650 RETURN_FALSE;
3651 }
3652 }
3653
3654 PHP_SSL_REQ_INIT(&req);
3655
3656 if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS)
3657 {
3658 if (php_openssl_generate_private_key(&req)) {
3659
3660 RETVAL_RES(zend_register_resource(req.priv_key, le_key));
3661
3662 req.priv_key = NULL;
3663 }
3664 }
3665 PHP_SSL_REQ_DISPOSE(&req);
3666 }
3667
3668
3669
3670
3671 PHP_FUNCTION(openssl_pkey_export_to_file)
3672 {
3673 struct php_x509_request req;
3674 zval * zpkey, * args = NULL;
3675 char * passphrase = NULL;
3676 size_t passphrase_len = 0;
3677 char * filename = NULL;
3678 size_t filename_len = 0;
3679 zend_resource *key_resource = NULL;
3680 int pem_write = 0;
3681 EVP_PKEY * key;
3682 BIO * bio_out = NULL;
3683 const EVP_CIPHER * cipher;
3684
3685 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zp|s!a!", &zpkey, &filename, &filename_len, &passphrase, &passphrase_len, &args) == FAILURE) {
3686 return;
3687 }
3688 RETVAL_FALSE;
3689
3690 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase);
3691
3692 key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource);
3693
3694 if (key == NULL) {
3695 php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1");
3696 RETURN_FALSE;
3697 }
3698
3699 if (php_openssl_open_base_dir_chk(filename)) {
3700 RETURN_FALSE;
3701 }
3702
3703 PHP_SSL_REQ_INIT(&req);
3704
3705 if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
3706 bio_out = BIO_new_file(filename, "w");
3707
3708 if (passphrase && req.priv_key_encrypt) {
3709 if (req.priv_key_encrypt_cipher) {
3710 cipher = req.priv_key_encrypt_cipher;
3711 } else {
3712 cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
3713 }
3714 } else {
3715 cipher = NULL;
3716 }
3717
3718 switch (EVP_PKEY_type(key->type)) {
3719 #ifdef HAVE_EVP_PKEY_EC
3720 case EVP_PKEY_EC:
3721 pem_write = PEM_write_bio_ECPrivateKey(bio_out, EVP_PKEY_get1_EC_KEY(key), cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
3722 break;
3723 #endif
3724 default:
3725 pem_write = PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
3726 break;
3727 }
3728
3729 if (pem_write) {
3730
3731
3732 RETVAL_TRUE;
3733 }
3734 }
3735 PHP_SSL_REQ_DISPOSE(&req);
3736
3737 if (key_resource == NULL && key) {
3738 EVP_PKEY_free(key);
3739 }
3740 if (bio_out) {
3741 BIO_free(bio_out);
3742 }
3743 }
3744
3745
3746
3747
3748 PHP_FUNCTION(openssl_pkey_export)
3749 {
3750 struct php_x509_request req;
3751 zval * zpkey, * args = NULL, *out;
3752 char * passphrase = NULL; size_t passphrase_len = 0;
3753 int pem_write = 0;
3754 zend_resource *key_resource = NULL;
3755 EVP_PKEY * key;
3756 BIO * bio_out = NULL;
3757 const EVP_CIPHER * cipher;
3758
3759 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) {
3760 return;
3761 }
3762 RETVAL_FALSE;
3763
3764 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(passphrase_len, passphrase);
3765
3766 key = php_openssl_evp_from_zval(zpkey, 0, passphrase, 0, &key_resource);
3767
3768 if (key == NULL) {
3769 php_error_docref(NULL, E_WARNING, "cannot get key from parameter 1");
3770 RETURN_FALSE;
3771 }
3772
3773 PHP_SSL_REQ_INIT(&req);
3774
3775 if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) {
3776 bio_out = BIO_new(BIO_s_mem());
3777
3778 if (passphrase && req.priv_key_encrypt) {
3779 if (req.priv_key_encrypt_cipher) {
3780 cipher = req.priv_key_encrypt_cipher;
3781 } else {
3782 cipher = (EVP_CIPHER *) EVP_des_ede3_cbc();
3783 }
3784 } else {
3785 cipher = NULL;
3786 }
3787
3788 switch (EVP_PKEY_type(key->type)) {
3789 #ifdef HAVE_EVP_PKEY_EC
3790 case EVP_PKEY_EC:
3791 pem_write = PEM_write_bio_ECPrivateKey(bio_out, EVP_PKEY_get1_EC_KEY(key), cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
3792 break;
3793 #endif
3794 default:
3795 pem_write = PEM_write_bio_PrivateKey(bio_out, key, cipher, (unsigned char *)passphrase, (int)passphrase_len, NULL, NULL);
3796 break;
3797 }
3798
3799 if (pem_write) {
3800
3801
3802
3803 char * bio_mem_ptr;
3804 long bio_mem_len;
3805 RETVAL_TRUE;
3806
3807 bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr);
3808 zval_dtor(out);
3809 ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len);
3810 }
3811 }
3812 PHP_SSL_REQ_DISPOSE(&req);
3813
3814 if (key_resource == NULL && key) {
3815 EVP_PKEY_free(key);
3816 }
3817 if (bio_out) {
3818 BIO_free(bio_out);
3819 }
3820 }
3821
3822
3823
3824
3825 PHP_FUNCTION(openssl_pkey_get_public)
3826 {
3827 zval *cert;
3828 EVP_PKEY *pkey;
3829 zend_resource *res;
3830
3831 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &cert) == FAILURE) {
3832 return;
3833 }
3834 pkey = php_openssl_evp_from_zval(cert, 1, NULL, 1, &res);
3835 if (pkey == NULL) {
3836 RETURN_FALSE;
3837 }
3838 ZVAL_RES(return_value, res);
3839 Z_ADDREF_P(return_value);
3840 }
3841
3842
3843
3844
3845 PHP_FUNCTION(openssl_pkey_free)
3846 {
3847 zval *key;
3848 EVP_PKEY *pkey;
3849
3850 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &key) == FAILURE) {
3851 return;
3852 }
3853 if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) {
3854 RETURN_FALSE;
3855 }
3856 zend_list_close(Z_RES_P(key));
3857 }
3858
3859
3860
3861
3862 PHP_FUNCTION(openssl_pkey_get_private)
3863 {
3864 zval *cert;
3865 EVP_PKEY *pkey;
3866 char * passphrase = "";
3867 size_t passphrase_len = sizeof("")-1;
3868 zend_resource *res;
3869
3870 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s", &cert, &passphrase, &passphrase_len) == FAILURE) {
3871 return;
3872 }
3873 pkey = php_openssl_evp_from_zval(cert, 0, passphrase, 1, &res);
3874
3875 if (pkey == NULL) {
3876 RETURN_FALSE;
3877 }
3878 ZVAL_RES(return_value, res);
3879 Z_ADDREF_P(return_value);
3880 }
3881
3882
3883
3884
3885
3886 PHP_FUNCTION(openssl_pkey_get_details)
3887 {
3888 zval *key;
3889 EVP_PKEY *pkey;
3890 BIO *out;
3891 unsigned int pbio_len;
3892 char *pbio;
3893 zend_long ktype;
3894
3895 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &key) == FAILURE) {
3896 return;
3897 }
3898 if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) {
3899 RETURN_FALSE;
3900 }
3901 out = BIO_new(BIO_s_mem());
3902 PEM_write_bio_PUBKEY(out, pkey);
3903 pbio_len = BIO_get_mem_data(out, &pbio);
3904
3905 array_init(return_value);
3906 add_assoc_long(return_value, "bits", EVP_PKEY_bits(pkey));
3907 add_assoc_stringl(return_value, "key", pbio, pbio_len);
3908
3909
3910
3911 switch (EVP_PKEY_type(pkey->type)) {
3912 case EVP_PKEY_RSA:
3913 case EVP_PKEY_RSA2:
3914 ktype = OPENSSL_KEYTYPE_RSA;
3915
3916 if (pkey->pkey.rsa != NULL) {
3917 zval rsa;
3918
3919 array_init(&rsa);
3920 OPENSSL_PKEY_GET_BN(rsa, n);
3921 OPENSSL_PKEY_GET_BN(rsa, e);
3922 OPENSSL_PKEY_GET_BN(rsa, d);
3923 OPENSSL_PKEY_GET_BN(rsa, p);
3924 OPENSSL_PKEY_GET_BN(rsa, q);
3925 OPENSSL_PKEY_GET_BN(rsa, dmp1);
3926 OPENSSL_PKEY_GET_BN(rsa, dmq1);
3927 OPENSSL_PKEY_GET_BN(rsa, iqmp);
3928 add_assoc_zval(return_value, "rsa", &rsa);
3929 }
3930
3931 break;
3932 case EVP_PKEY_DSA:
3933 case EVP_PKEY_DSA2:
3934 case EVP_PKEY_DSA3:
3935 case EVP_PKEY_DSA4:
3936 ktype = OPENSSL_KEYTYPE_DSA;
3937
3938 if (pkey->pkey.dsa != NULL) {
3939 zval dsa;
3940
3941 array_init(&dsa);
3942 OPENSSL_PKEY_GET_BN(dsa, p);
3943 OPENSSL_PKEY_GET_BN(dsa, q);
3944 OPENSSL_PKEY_GET_BN(dsa, g);
3945 OPENSSL_PKEY_GET_BN(dsa, priv_key);
3946 OPENSSL_PKEY_GET_BN(dsa, pub_key);
3947 add_assoc_zval(return_value, "dsa", &dsa);
3948 }
3949 break;
3950 case EVP_PKEY_DH:
3951
3952 ktype = OPENSSL_KEYTYPE_DH;
3953
3954 if (pkey->pkey.dh != NULL) {
3955 zval dh;
3956
3957 array_init(&dh);
3958 OPENSSL_PKEY_GET_BN(dh, p);
3959 OPENSSL_PKEY_GET_BN(dh, g);
3960 OPENSSL_PKEY_GET_BN(dh, priv_key);
3961 OPENSSL_PKEY_GET_BN(dh, pub_key);
3962 add_assoc_zval(return_value, "dh", &dh);
3963 }
3964
3965 break;
3966 #ifdef HAVE_EVP_PKEY_EC
3967 case EVP_PKEY_EC:
3968 ktype = OPENSSL_KEYTYPE_EC;
3969 if (pkey->pkey.ec != NULL) {
3970 zval ec;
3971 const EC_GROUP *ec_group;
3972 int nid;
3973 char *crv_sn;
3974 ASN1_OBJECT *obj;
3975
3976 char oir_buf[80];
3977
3978 ec_group = EC_KEY_get0_group(EVP_PKEY_get1_EC_KEY(pkey));
3979
3980
3981 nid = EC_GROUP_get_curve_name(ec_group);
3982 if (nid == NID_undef) {
3983 break;
3984 }
3985 array_init(&ec);
3986
3987
3988 crv_sn = (char*) OBJ_nid2sn(nid);
3989 if (crv_sn != NULL) {
3990 add_assoc_string(&ec, "curve_name", crv_sn);
3991 }
3992
3993 obj = OBJ_nid2obj(nid);
3994 if (obj != NULL) {
3995 int oir_len = OBJ_obj2txt(oir_buf, sizeof(oir_buf), obj, 1);
3996 add_assoc_stringl(&ec, "curve_oid", (char*)oir_buf, oir_len);
3997 ASN1_OBJECT_free(obj);
3998 }
3999
4000 add_assoc_zval(return_value, "ec", &ec);
4001 }
4002 break;
4003 #endif
4004 default:
4005 ktype = -1;
4006 break;
4007 }
4008 add_assoc_long(return_value, "type", ktype);
4009
4010 BIO_free(out);
4011 }
4012
4013
4014
4015
4016 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
4017
4018
4019
4020 PHP_FUNCTION(openssl_pbkdf2)
4021 {
4022 zend_long key_length = 0, iterations = 0;
4023 char *password;
4024 size_t password_len;
4025 char *salt;
4026 size_t salt_len;
4027 char *method;
4028 size_t method_len = 0;
4029 zend_string *out_buffer;
4030
4031 const EVP_MD *digest;
4032
4033 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssll|s",
4034 &password, &password_len,
4035 &salt, &salt_len,
4036 &key_length, &iterations,
4037 &method, &method_len) == FAILURE) {
4038 return;
4039 }
4040
4041 if (key_length <= 0) {
4042 RETURN_FALSE;
4043 }
4044
4045 if (method_len) {
4046 digest = EVP_get_digestbyname(method);
4047 } else {
4048 digest = EVP_sha1();
4049 }
4050
4051 if (!digest) {
4052 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
4053 RETURN_FALSE;
4054 }
4055
4056 PHP_OPENSSL_CHECK_LONG_TO_INT(key_length, key);
4057 PHP_OPENSSL_CHECK_LONG_TO_INT(iterations, iterations);
4058 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password);
4059 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(salt_len, salt);
4060
4061 out_buffer = zend_string_alloc(key_length, 0);
4062
4063 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) {
4064 ZSTR_VAL(out_buffer)[key_length] = 0;
4065 RETURN_NEW_STR(out_buffer);
4066 } else {
4067 zend_string_release(out_buffer);
4068 RETURN_FALSE;
4069 }
4070 }
4071
4072
4073 #endif
4074
4075
4076
4077
4078
4079 PHP_FUNCTION(openssl_pkcs7_verify)
4080 {
4081 X509_STORE * store = NULL;
4082 zval * cainfo = NULL;
4083 STACK_OF(X509) *signers= NULL;
4084 STACK_OF(X509) *others = NULL;
4085 PKCS7 * p7 = NULL;
4086 BIO * in = NULL, * datain = NULL, * dataout = NULL;
4087 zend_long flags = 0;
4088 char * filename;
4089 size_t filename_len;
4090 char * extracerts = NULL;
4091 size_t extracerts_len = 0;
4092 char * signersfilename = NULL;
4093 size_t signersfilename_len = 0;
4094 char * datafilename = NULL;
4095 size_t datafilename_len = 0;
4096
4097 RETVAL_LONG(-1);
4098
4099 if (zend_parse_parameters(ZEND_NUM_ARGS(), "pl|papp", &filename, &filename_len,
4100 &flags, &signersfilename, &signersfilename_len, &cainfo,
4101 &extracerts, &extracerts_len, &datafilename, &datafilename_len) == FAILURE) {
4102 return;
4103 }
4104
4105 if (extracerts) {
4106 others = load_all_certs_from_file(extracerts);
4107 if (others == NULL) {
4108 goto clean_exit;
4109 }
4110 }
4111
4112 flags = flags & ~PKCS7_DETACHED;
4113
4114 store = setup_verify(cainfo);
4115
4116 if (!store) {
4117 goto clean_exit;
4118 }
4119 if (php_openssl_open_base_dir_chk(filename)) {
4120 goto clean_exit;
4121 }
4122
4123 in = BIO_new_file(filename, (flags & PKCS7_BINARY) ? "rb" : "r");
4124 if (in == NULL) {
4125 goto clean_exit;
4126 }
4127 p7 = SMIME_read_PKCS7(in, &datain);
4128 if (p7 == NULL) {
4129 #if DEBUG_SMIME
4130 zend_printf("SMIME_read_PKCS7 failed\n");
4131 #endif
4132 goto clean_exit;
4133 }
4134
4135 if (datafilename) {
4136
4137 if (php_openssl_open_base_dir_chk(datafilename)) {
4138 goto clean_exit;
4139 }
4140
4141 dataout = BIO_new_file(datafilename, "w");
4142 if (dataout == NULL) {
4143 goto clean_exit;
4144 }
4145 }
4146 #if DEBUG_SMIME
4147 zend_printf("Calling PKCS7 verify\n");
4148 #endif
4149
4150 if (PKCS7_verify(p7, others, store, datain, dataout, (int)flags)) {
4151
4152 RETVAL_TRUE;
4153
4154 if (signersfilename) {
4155 BIO *certout;
4156
4157 if (php_openssl_open_base_dir_chk(signersfilename)) {
4158 goto clean_exit;
4159 }
4160
4161 certout = BIO_new_file(signersfilename, "w");
4162 if (certout) {
4163 int i;
4164 signers = PKCS7_get0_signers(p7, NULL, (int)flags);
4165
4166 for(i = 0; i < sk_X509_num(signers); i++) {
4167 PEM_write_bio_X509(certout, sk_X509_value(signers, i));
4168 }
4169 BIO_free(certout);
4170 sk_X509_free(signers);
4171 } else {
4172 php_error_docref(NULL, E_WARNING, "signature OK, but cannot open %s for writing", signersfilename);
4173 RETVAL_LONG(-1);
4174 }
4175 }
4176 goto clean_exit;
4177 } else {
4178 RETVAL_FALSE;
4179 }
4180 clean_exit:
4181 X509_STORE_free(store);
4182 BIO_free(datain);
4183 BIO_free(in);
4184 BIO_free(dataout);
4185 PKCS7_free(p7);
4186 sk_X509_free(others);
4187 }
4188
4189
4190
4191
4192 PHP_FUNCTION(openssl_pkcs7_encrypt)
4193 {
4194 zval * zrecipcerts, * zheaders = NULL;
4195 STACK_OF(X509) * recipcerts = NULL;
4196 BIO * infile = NULL, * outfile = NULL;
4197 zend_long flags = 0;
4198 PKCS7 * p7 = NULL;
4199 zval * zcertval;
4200 X509 * cert;
4201 const EVP_CIPHER *cipher = NULL;
4202 zend_long cipherid = PHP_OPENSSL_CIPHER_DEFAULT;
4203 zend_string * strindex;
4204 char * infilename = NULL;
4205 size_t infilename_len;
4206 char * outfilename = NULL;
4207 size_t outfilename_len;
4208
4209 RETVAL_FALSE;
4210
4211 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppza!|ll", &infilename, &infilename_len,
4212 &outfilename, &outfilename_len, &zrecipcerts, &zheaders, &flags, &cipherid) == FAILURE)
4213 return;
4214
4215
4216 if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
4217 return;
4218 }
4219
4220 infile = BIO_new_file(infilename, "r");
4221 if (infile == NULL) {
4222 goto clean_exit;
4223 }
4224
4225 outfile = BIO_new_file(outfilename, "w");
4226 if (outfile == NULL) {
4227 goto clean_exit;
4228 }
4229
4230 recipcerts = sk_X509_new_null();
4231
4232
4233 if (Z_TYPE_P(zrecipcerts) == IS_ARRAY) {
4234 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zrecipcerts), zcertval) {
4235 zend_resource *certresource;
4236
4237 cert = php_openssl_x509_from_zval(zcertval, 0, &certresource);
4238 if (cert == NULL) {
4239 goto clean_exit;
4240 }
4241
4242 if (certresource != NULL) {
4243
4244
4245 cert = X509_dup(cert);
4246 if (cert == NULL) {
4247 goto clean_exit;
4248 }
4249 }
4250 sk_X509_push(recipcerts, cert);
4251 } ZEND_HASH_FOREACH_END();
4252 } else {
4253
4254 zend_resource *certresource;
4255
4256 cert = php_openssl_x509_from_zval(zrecipcerts, 0, &certresource);
4257 if (cert == NULL) {
4258 goto clean_exit;
4259 }
4260
4261 if (certresource != NULL) {
4262
4263
4264 cert = X509_dup(cert);
4265 if (cert == NULL) {
4266 goto clean_exit;
4267 }
4268 }
4269 sk_X509_push(recipcerts, cert);
4270 }
4271
4272
4273 cipher = php_openssl_get_evp_cipher_from_algo(cipherid);
4274 if (cipher == NULL) {
4275
4276 php_error_docref(NULL, E_WARNING, "Failed to get cipher");
4277 goto clean_exit;
4278 }
4279
4280 p7 = PKCS7_encrypt(recipcerts, infile, (EVP_CIPHER*)cipher, (int)flags);
4281
4282 if (p7 == NULL) {
4283 goto clean_exit;
4284 }
4285
4286
4287 if (zheaders) {
4288 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, zcertval) {
4289 convert_to_string_ex(zcertval);
4290
4291 if (strindex) {
4292 BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(zcertval));
4293 } else {
4294 BIO_printf(outfile, "%s\n", Z_STRVAL_P(zcertval));
4295 }
4296 } ZEND_HASH_FOREACH_END();
4297 }
4298
4299 (void)BIO_reset(infile);
4300
4301
4302 SMIME_write_PKCS7(outfile, p7, infile, (int)flags);
4303
4304 RETVAL_TRUE;
4305
4306 clean_exit:
4307 PKCS7_free(p7);
4308 BIO_free(infile);
4309 BIO_free(outfile);
4310 if (recipcerts) {
4311 sk_X509_pop_free(recipcerts, X509_free);
4312 }
4313 }
4314
4315
4316
4317
4318
4319 PHP_FUNCTION(openssl_pkcs7_sign)
4320 {
4321 zval * zcert, * zprivkey, * zheaders;
4322 zval * hval;
4323 X509 * cert = NULL;
4324 EVP_PKEY * privkey = NULL;
4325 zend_long flags = PKCS7_DETACHED;
4326 PKCS7 * p7 = NULL;
4327 BIO * infile = NULL, * outfile = NULL;
4328 STACK_OF(X509) *others = NULL;
4329 zend_resource *certresource = NULL, *keyresource = NULL;
4330 zend_string * strindex;
4331 char * infilename;
4332 size_t infilename_len;
4333 char * outfilename;
4334 size_t outfilename_len;
4335 char * extracertsfilename = NULL;
4336 size_t extracertsfilename_len;
4337
4338 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppzza!|lp!",
4339 &infilename, &infilename_len, &outfilename, &outfilename_len,
4340 &zcert, &zprivkey, &zheaders, &flags, &extracertsfilename,
4341 &extracertsfilename_len) == FAILURE) {
4342 return;
4343 }
4344
4345 RETVAL_FALSE;
4346
4347 if (extracertsfilename) {
4348 others = load_all_certs_from_file(extracertsfilename);
4349 if (others == NULL) {
4350 goto clean_exit;
4351 }
4352 }
4353
4354 privkey = php_openssl_evp_from_zval(zprivkey, 0, "", 0, &keyresource);
4355 if (privkey == NULL) {
4356 php_error_docref(NULL, E_WARNING, "error getting private key");
4357 goto clean_exit;
4358 }
4359
4360 cert = php_openssl_x509_from_zval(zcert, 0, &certresource);
4361 if (cert == NULL) {
4362 php_error_docref(NULL, E_WARNING, "error getting cert");
4363 goto clean_exit;
4364 }
4365
4366 if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
4367 goto clean_exit;
4368 }
4369
4370 infile = BIO_new_file(infilename, "r");
4371 if (infile == NULL) {
4372 php_error_docref(NULL, E_WARNING, "error opening input file %s!", infilename);
4373 goto clean_exit;
4374 }
4375
4376 outfile = BIO_new_file(outfilename, "w");
4377 if (outfile == NULL) {
4378 php_error_docref(NULL, E_WARNING, "error opening output file %s!", outfilename);
4379 goto clean_exit;
4380 }
4381
4382 p7 = PKCS7_sign(cert, privkey, others, infile, (int)flags);
4383 if (p7 == NULL) {
4384 php_error_docref(NULL, E_WARNING, "error creating PKCS7 structure!");
4385 goto clean_exit;
4386 }
4387
4388 (void)BIO_reset(infile);
4389
4390
4391 if (zheaders) {
4392 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zheaders), strindex, hval) {
4393 convert_to_string_ex(hval);
4394
4395 if (strindex) {
4396 BIO_printf(outfile, "%s: %s\n", ZSTR_VAL(strindex), Z_STRVAL_P(hval));
4397 } else {
4398 BIO_printf(outfile, "%s\n", Z_STRVAL_P(hval));
4399 }
4400 } ZEND_HASH_FOREACH_END();
4401 }
4402
4403 SMIME_write_PKCS7(outfile, p7, infile, (int)flags);
4404
4405 RETVAL_TRUE;
4406
4407 clean_exit:
4408 PKCS7_free(p7);
4409 BIO_free(infile);
4410 BIO_free(outfile);
4411 if (others) {
4412 sk_X509_pop_free(others, X509_free);
4413 }
4414 if (privkey && keyresource == NULL) {
4415 EVP_PKEY_free(privkey);
4416 }
4417 if (cert && certresource == NULL) {
4418 X509_free(cert);
4419 }
4420 }
4421
4422
4423
4424
4425
4426 PHP_FUNCTION(openssl_pkcs7_decrypt)
4427 {
4428 zval * recipcert, * recipkey = NULL;
4429 X509 * cert = NULL;
4430 EVP_PKEY * key = NULL;
4431 zend_resource *certresval, *keyresval;
4432 BIO * in = NULL, * out = NULL, * datain = NULL;
4433 PKCS7 * p7 = NULL;
4434 char * infilename;
4435 size_t infilename_len;
4436 char * outfilename;
4437 size_t outfilename_len;
4438
4439 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppz|z", &infilename, &infilename_len,
4440 &outfilename, &outfilename_len, &recipcert, &recipkey) == FAILURE) {
4441 return;
4442 }
4443
4444 RETVAL_FALSE;
4445
4446 cert = php_openssl_x509_from_zval(recipcert, 0, &certresval);
4447 if (cert == NULL) {
4448 php_error_docref(NULL, E_WARNING, "unable to coerce parameter 3 to x509 cert");
4449 goto clean_exit;
4450 }
4451
4452 key = php_openssl_evp_from_zval(recipkey ? recipkey : recipcert, 0, "", 0, &keyresval);
4453 if (key == NULL) {
4454 php_error_docref(NULL, E_WARNING, "unable to get private key");
4455 goto clean_exit;
4456 }
4457
4458 if (php_openssl_open_base_dir_chk(infilename) || php_openssl_open_base_dir_chk(outfilename)) {
4459 goto clean_exit;
4460 }
4461
4462 in = BIO_new_file(infilename, "r");
4463 if (in == NULL) {
4464 goto clean_exit;
4465 }
4466 out = BIO_new_file(outfilename, "w");
4467 if (out == NULL) {
4468 goto clean_exit;
4469 }
4470
4471 p7 = SMIME_read_PKCS7(in, &datain);
4472
4473 if (p7 == NULL) {
4474 goto clean_exit;
4475 }
4476 if (PKCS7_decrypt(p7, key, cert, out, PKCS7_DETACHED)) {
4477 RETVAL_TRUE;
4478 }
4479 clean_exit:
4480 PKCS7_free(p7);
4481 BIO_free(datain);
4482 BIO_free(in);
4483 BIO_free(out);
4484 if (cert && certresval == NULL) {
4485 X509_free(cert);
4486 }
4487 if (key && keyresval == NULL) {
4488 EVP_PKEY_free(key);
4489 }
4490 }
4491
4492
4493
4494
4495
4496
4497 PHP_FUNCTION(openssl_private_encrypt)
4498 {
4499 zval *key, *crypted;
4500 EVP_PKEY *pkey;
4501 int cryptedlen;
4502 zend_string *cryptedbuf = NULL;
4503 int successful = 0;
4504 zend_resource *keyresource = NULL;
4505 char * data;
4506 size_t data_len;
4507 zend_long padding = RSA_PKCS1_PADDING;
4508
4509 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
4510 return;
4511 }
4512 RETVAL_FALSE;
4513
4514 pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource);
4515
4516 if (pkey == NULL) {
4517 php_error_docref(NULL, E_WARNING, "key param is not a valid private key");
4518 RETURN_FALSE;
4519 }
4520
4521 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
4522
4523 cryptedlen = EVP_PKEY_size(pkey);
4524 cryptedbuf = zend_string_alloc(cryptedlen, 0);
4525
4526 switch (pkey->type) {
4527 case EVP_PKEY_RSA:
4528 case EVP_PKEY_RSA2:
4529 successful = (RSA_private_encrypt((int)data_len,
4530 (unsigned char *)data,
4531 (unsigned char *)ZSTR_VAL(cryptedbuf),
4532 pkey->pkey.rsa,
4533 (int)padding) == cryptedlen);
4534 break;
4535 default:
4536 php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
4537 }
4538
4539 if (successful) {
4540 zval_dtor(crypted);
4541 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
4542 ZVAL_NEW_STR(crypted, cryptedbuf);
4543 cryptedbuf = NULL;
4544 RETVAL_TRUE;
4545 }
4546 if (cryptedbuf) {
4547 zend_string_release(cryptedbuf);
4548 }
4549 if (keyresource == NULL) {
4550 EVP_PKEY_free(pkey);
4551 }
4552 }
4553
4554
4555
4556
4557 PHP_FUNCTION(openssl_private_decrypt)
4558 {
4559 zval *key, *crypted;
4560 EVP_PKEY *pkey;
4561 int cryptedlen;
4562 zend_string *cryptedbuf = NULL;
4563 unsigned char *crypttemp;
4564 int successful = 0;
4565 zend_long padding = RSA_PKCS1_PADDING;
4566 zend_resource *keyresource = NULL;
4567 char * data;
4568 size_t data_len;
4569
4570 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
4571 return;
4572 }
4573 RETVAL_FALSE;
4574
4575 pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource);
4576 if (pkey == NULL) {
4577 php_error_docref(NULL, E_WARNING, "key parameter is not a valid private key");
4578 RETURN_FALSE;
4579 }
4580
4581 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
4582
4583 cryptedlen = EVP_PKEY_size(pkey);
4584 crypttemp = emalloc(cryptedlen + 1);
4585
4586 switch (pkey->type) {
4587 case EVP_PKEY_RSA:
4588 case EVP_PKEY_RSA2:
4589 cryptedlen = RSA_private_decrypt((int)data_len,
4590 (unsigned char *)data,
4591 crypttemp,
4592 pkey->pkey.rsa,
4593 (int)padding);
4594 if (cryptedlen != -1) {
4595 cryptedbuf = zend_string_alloc(cryptedlen, 0);
4596 memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen);
4597 successful = 1;
4598 }
4599 break;
4600 default:
4601 php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
4602 }
4603
4604 efree(crypttemp);
4605
4606 if (successful) {
4607 zval_dtor(crypted);
4608 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
4609 ZVAL_NEW_STR(crypted, cryptedbuf);
4610 cryptedbuf = NULL;
4611 RETVAL_TRUE;
4612 }
4613
4614 if (keyresource == NULL) {
4615 EVP_PKEY_free(pkey);
4616 }
4617 if (cryptedbuf) {
4618 zend_string_release(cryptedbuf);
4619 }
4620 }
4621
4622
4623
4624
4625 PHP_FUNCTION(openssl_public_encrypt)
4626 {
4627 zval *key, *crypted;
4628 EVP_PKEY *pkey;
4629 int cryptedlen;
4630 zend_string *cryptedbuf;
4631 int successful = 0;
4632 zend_resource *keyresource = NULL;
4633 zend_long padding = RSA_PKCS1_PADDING;
4634 char * data;
4635 size_t data_len;
4636
4637 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE)
4638 return;
4639 RETVAL_FALSE;
4640
4641 pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource);
4642 if (pkey == NULL) {
4643 php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key");
4644 RETURN_FALSE;
4645 }
4646
4647 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
4648
4649 cryptedlen = EVP_PKEY_size(pkey);
4650 cryptedbuf = zend_string_alloc(cryptedlen, 0);
4651
4652 switch (pkey->type) {
4653 case EVP_PKEY_RSA:
4654 case EVP_PKEY_RSA2:
4655 successful = (RSA_public_encrypt((int)data_len,
4656 (unsigned char *)data,
4657 (unsigned char *)ZSTR_VAL(cryptedbuf),
4658 pkey->pkey.rsa,
4659 (int)padding) == cryptedlen);
4660 break;
4661 default:
4662 php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
4663
4664 }
4665
4666 if (successful) {
4667 zval_dtor(crypted);
4668 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
4669 ZVAL_NEW_STR(crypted, cryptedbuf);
4670 cryptedbuf = NULL;
4671 RETVAL_TRUE;
4672 }
4673 if (keyresource == NULL) {
4674 EVP_PKEY_free(pkey);
4675 }
4676 if (cryptedbuf) {
4677 zend_string_release(cryptedbuf);
4678 }
4679 }
4680
4681
4682
4683
4684 PHP_FUNCTION(openssl_public_decrypt)
4685 {
4686 zval *key, *crypted;
4687 EVP_PKEY *pkey;
4688 int cryptedlen;
4689 zend_string *cryptedbuf = NULL;
4690 unsigned char *crypttemp;
4691 int successful = 0;
4692 zend_resource *keyresource = NULL;
4693 zend_long padding = RSA_PKCS1_PADDING;
4694 char * data;
4695 size_t data_len;
4696
4697 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) {
4698 return;
4699 }
4700 RETVAL_FALSE;
4701
4702 pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource);
4703 if (pkey == NULL) {
4704 php_error_docref(NULL, E_WARNING, "key parameter is not a valid public key");
4705 RETURN_FALSE;
4706 }
4707
4708 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
4709
4710 cryptedlen = EVP_PKEY_size(pkey);
4711 crypttemp = emalloc(cryptedlen + 1);
4712
4713 switch (pkey->type) {
4714 case EVP_PKEY_RSA:
4715 case EVP_PKEY_RSA2:
4716 cryptedlen = RSA_public_decrypt((int)data_len,
4717 (unsigned char *)data,
4718 crypttemp,
4719 pkey->pkey.rsa,
4720 (int)padding);
4721 if (cryptedlen != -1) {
4722 cryptedbuf = zend_string_alloc(cryptedlen, 0);
4723 memcpy(ZSTR_VAL(cryptedbuf), crypttemp, cryptedlen);
4724 successful = 1;
4725 }
4726 break;
4727
4728 default:
4729 php_error_docref(NULL, E_WARNING, "key type not supported in this PHP build!");
4730
4731 }
4732
4733 efree(crypttemp);
4734
4735 if (successful) {
4736 zval_dtor(crypted);
4737 ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0';
4738 ZVAL_NEW_STR(crypted, cryptedbuf);
4739 cryptedbuf = NULL;
4740 RETVAL_TRUE;
4741 }
4742
4743 if (cryptedbuf) {
4744 zend_string_release(cryptedbuf);
4745 }
4746 if (keyresource == NULL) {
4747 EVP_PKEY_free(pkey);
4748 }
4749 }
4750
4751
4752
4753
4754 PHP_FUNCTION(openssl_error_string)
4755 {
4756 char buf[512];
4757 unsigned long val;
4758
4759 if (zend_parse_parameters_none() == FAILURE) {
4760 return;
4761 }
4762
4763 val = ERR_get_error();
4764 if (val) {
4765 RETURN_STRING(ERR_error_string(val, buf));
4766 } else {
4767 RETURN_FALSE;
4768 }
4769 }
4770
4771
4772
4773
4774 PHP_FUNCTION(openssl_sign)
4775 {
4776 zval *key, *signature;
4777 EVP_PKEY *pkey;
4778 unsigned int siglen;
4779 zend_string *sigbuf;
4780 zend_resource *keyresource = NULL;
4781 char * data;
4782 size_t data_len;
4783 EVP_MD_CTX md_ctx;
4784 zval *method = NULL;
4785 zend_long signature_algo = OPENSSL_ALGO_SHA1;
4786 const EVP_MD *mdtype;
4787
4788 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|z", &data, &data_len, &signature, &key, &method) == FAILURE) {
4789 return;
4790 }
4791 pkey = php_openssl_evp_from_zval(key, 0, "", 0, &keyresource);
4792 if (pkey == NULL) {
4793 php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a private key");
4794 RETURN_FALSE;
4795 }
4796
4797 if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
4798 if (method != NULL) {
4799 signature_algo = Z_LVAL_P(method);
4800 }
4801 mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
4802 } else if (Z_TYPE_P(method) == IS_STRING) {
4803 mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
4804 } else {
4805 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
4806 RETURN_FALSE;
4807 }
4808 if (!mdtype) {
4809 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
4810 RETURN_FALSE;
4811 }
4812
4813 siglen = EVP_PKEY_size(pkey);
4814 sigbuf = zend_string_alloc(siglen, 0);
4815
4816 EVP_SignInit(&md_ctx, mdtype);
4817 EVP_SignUpdate(&md_ctx, data, data_len);
4818 if (EVP_SignFinal (&md_ctx, (unsigned char*)ZSTR_VAL(sigbuf), &siglen, pkey)) {
4819 zval_dtor(signature);
4820 ZSTR_VAL(sigbuf)[siglen] = '\0';
4821 ZSTR_LEN(sigbuf) = siglen;
4822 ZVAL_NEW_STR(signature, sigbuf);
4823 RETVAL_TRUE;
4824 } else {
4825 efree(sigbuf);
4826 RETVAL_FALSE;
4827 }
4828 EVP_MD_CTX_cleanup(&md_ctx);
4829 if (keyresource == NULL) {
4830 EVP_PKEY_free(pkey);
4831 }
4832 }
4833
4834
4835
4836
4837 PHP_FUNCTION(openssl_verify)
4838 {
4839 zval *key;
4840 EVP_PKEY *pkey;
4841 int err;
4842 EVP_MD_CTX md_ctx;
4843 const EVP_MD *mdtype;
4844 zend_resource *keyresource = NULL;
4845 char * data;
4846 size_t data_len;
4847 char * signature;
4848 size_t signature_len;
4849 zval *method = NULL;
4850 zend_long signature_algo = OPENSSL_ALGO_SHA1;
4851
4852 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssz|z", &data, &data_len, &signature, &signature_len, &key, &method) == FAILURE) {
4853 return;
4854 }
4855
4856 PHP_OPENSSL_CHECK_SIZE_T_TO_UINT(signature_len, signature);
4857
4858 if (method == NULL || Z_TYPE_P(method) == IS_LONG) {
4859 if (method != NULL) {
4860 signature_algo = Z_LVAL_P(method);
4861 }
4862 mdtype = php_openssl_get_evp_md_from_algo(signature_algo);
4863 } else if (Z_TYPE_P(method) == IS_STRING) {
4864 mdtype = EVP_get_digestbyname(Z_STRVAL_P(method));
4865 } else {
4866 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
4867 RETURN_FALSE;
4868 }
4869 if (!mdtype) {
4870 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
4871 RETURN_FALSE;
4872 }
4873
4874 pkey = php_openssl_evp_from_zval(key, 1, NULL, 0, &keyresource);
4875 if (pkey == NULL) {
4876 php_error_docref(NULL, E_WARNING, "supplied key param cannot be coerced into a public key");
4877 RETURN_FALSE;
4878 }
4879
4880 EVP_VerifyInit (&md_ctx, mdtype);
4881 EVP_VerifyUpdate (&md_ctx, data, data_len);
4882 err = EVP_VerifyFinal(&md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey);
4883 EVP_MD_CTX_cleanup(&md_ctx);
4884
4885 if (keyresource == NULL) {
4886 EVP_PKEY_free(pkey);
4887 }
4888 RETURN_LONG(err);
4889 }
4890
4891
4892
4893
4894 PHP_FUNCTION(openssl_seal)
4895 {
4896 zval *pubkeys, *pubkey, *sealdata, *ekeys, *iv = NULL;
4897 HashTable *pubkeysht;
4898 EVP_PKEY **pkeys;
4899 zend_resource ** key_resources;
4900 int i, len1, len2, *eksl, nkeys, iv_len;
4901 unsigned char iv_buf[EVP_MAX_IV_LENGTH + 1], *buf = NULL, **eks;
4902 char * data;
4903 size_t data_len;
4904 char *method =NULL;
4905 size_t method_len = 0;
4906 const EVP_CIPHER *cipher;
4907 EVP_CIPHER_CTX ctx;
4908
4909 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z/a/|sz/", &data, &data_len,
4910 &sealdata, &ekeys, &pubkeys, &method, &method_len, &iv) == FAILURE) {
4911 return;
4912 }
4913 pubkeysht = Z_ARRVAL_P(pubkeys);
4914 nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0;
4915 if (!nkeys) {
4916 php_error_docref(NULL, E_WARNING, "Fourth argument to openssl_seal() must be a non-empty array");
4917 RETURN_FALSE;
4918 }
4919
4920 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
4921
4922 if (method) {
4923 cipher = EVP_get_cipherbyname(method);
4924 if (!cipher) {
4925 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
4926 RETURN_FALSE;
4927 }
4928 } else {
4929 cipher = EVP_rc4();
4930 }
4931
4932 iv_len = EVP_CIPHER_iv_length(cipher);
4933 if (!iv && iv_len > 0) {
4934 php_error_docref(NULL, E_WARNING,
4935 "Cipher algorithm requires an IV to be supplied as a sixth parameter");
4936 RETURN_FALSE;
4937 }
4938
4939 pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0);
4940 eksl = safe_emalloc(nkeys, sizeof(*eksl), 0);
4941 eks = safe_emalloc(nkeys, sizeof(*eks), 0);
4942 memset(eks, 0, sizeof(*eks) * nkeys);
4943 key_resources = safe_emalloc(nkeys, sizeof(zend_resource*), 0);
4944 memset(key_resources, 0, sizeof(zend_resource*) * nkeys);
4945 memset(pkeys, 0, sizeof(*pkeys) * nkeys);
4946
4947
4948 i = 0;
4949 ZEND_HASH_FOREACH_VAL(pubkeysht, pubkey) {
4950 pkeys[i] = php_openssl_evp_from_zval(pubkey, 1, NULL, 0, &key_resources[i]);
4951 if (pkeys[i] == NULL) {
4952 php_error_docref(NULL, E_WARNING, "not a public key (%dth member of pubkeys)", i+1);
4953 RETVAL_FALSE;
4954 goto clean_exit;
4955 }
4956 eks[i] = emalloc(EVP_PKEY_size(pkeys[i]) + 1);
4957 i++;
4958 } ZEND_HASH_FOREACH_END();
4959
4960 if (!EVP_EncryptInit(&ctx,cipher,NULL,NULL)) {
4961 RETVAL_FALSE;
4962 EVP_CIPHER_CTX_cleanup(&ctx);
4963 goto clean_exit;
4964 }
4965
4966
4967 buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(&ctx));
4968 EVP_CIPHER_CTX_cleanup(&ctx);
4969
4970 if (!EVP_SealInit(&ctx, cipher, eks, eksl, &iv_buf[0], pkeys, nkeys) ||
4971 !EVP_SealUpdate(&ctx, buf, &len1, (unsigned char *)data, (int)data_len) ||
4972 !EVP_SealFinal(&ctx, buf + len1, &len2)) {
4973 RETVAL_FALSE;
4974 efree(buf);
4975 EVP_CIPHER_CTX_cleanup(&ctx);
4976 goto clean_exit;
4977 }
4978
4979 if (len1 + len2 > 0) {
4980 zval_dtor(sealdata);
4981 buf[len1 + len2] = '\0';
4982 ZVAL_NEW_STR(sealdata, zend_string_init((char*)buf, len1 + len2, 0));
4983 efree(buf);
4984
4985 zval_dtor(ekeys);
4986 array_init(ekeys);
4987 for (i=0; i<nkeys; i++) {
4988 eks[i][eksl[i]] = '\0';
4989 add_next_index_stringl(ekeys, (const char*)eks[i], eksl[i]);
4990 efree(eks[i]);
4991 eks[i] = NULL;
4992 }
4993
4994 if (iv) {
4995 zval_dtor(iv);
4996 iv_buf[iv_len] = '\0';
4997 ZVAL_NEW_STR(iv, zend_string_init((char*)iv_buf, iv_len, 0));
4998 }
4999 } else {
5000 efree(buf);
5001 }
5002 RETVAL_LONG(len1 + len2);
5003 EVP_CIPHER_CTX_cleanup(&ctx);
5004
5005 clean_exit:
5006 for (i=0; i<nkeys; i++) {
5007 if (key_resources[i] == NULL && pkeys[i] != NULL) {
5008 EVP_PKEY_free(pkeys[i]);
5009 }
5010 if (eks[i]) {
5011 efree(eks[i]);
5012 }
5013 }
5014 efree(eks);
5015 efree(eksl);
5016 efree(pkeys);
5017 efree(key_resources);
5018 }
5019
5020
5021
5022
5023 PHP_FUNCTION(openssl_open)
5024 {
5025 zval *privkey, *opendata;
5026 EVP_PKEY *pkey;
5027 int len1, len2, cipher_iv_len;
5028 unsigned char *buf, *iv_buf;
5029 zend_resource *keyresource = NULL;
5030 EVP_CIPHER_CTX ctx;
5031 char * data;
5032 size_t data_len;
5033 char * ekey;
5034 size_t ekey_len;
5035 char *method = NULL, *iv = NULL;
5036 size_t method_len = 0, iv_len = 0;
5037 const EVP_CIPHER *cipher;
5038
5039 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/sz|ss", &data, &data_len, &opendata,
5040 &ekey, &ekey_len, &privkey, &method, &method_len, &iv, &iv_len) == FAILURE) {
5041 return;
5042 }
5043
5044 pkey = php_openssl_evp_from_zval(privkey, 0, "", 0, &keyresource);
5045 if (pkey == NULL) {
5046 php_error_docref(NULL, E_WARNING, "unable to coerce parameter 4 into a private key");
5047 RETURN_FALSE;
5048 }
5049
5050 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(ekey_len, ekey);
5051 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
5052
5053 if (method) {
5054 cipher = EVP_get_cipherbyname(method);
5055 if (!cipher) {
5056 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm.");
5057 RETURN_FALSE;
5058 }
5059 } else {
5060 cipher = EVP_rc4();
5061 }
5062
5063 cipher_iv_len = EVP_CIPHER_iv_length(cipher);
5064 if (cipher_iv_len > 0) {
5065 if (!iv) {
5066 php_error_docref(NULL, E_WARNING,
5067 "Cipher algorithm requires an IV to be supplied as a sixth parameter");
5068 RETURN_FALSE;
5069 }
5070 if (cipher_iv_len != iv_len) {
5071 php_error_docref(NULL, E_WARNING, "IV length is invalid");
5072 RETURN_FALSE;
5073 }
5074 iv_buf = (unsigned char *)iv;
5075 } else {
5076 iv_buf = NULL;
5077 }
5078
5079 buf = emalloc(data_len + 1);
5080
5081 if (EVP_OpenInit(&ctx, cipher, (unsigned char *)ekey, (int)ekey_len, iv_buf, pkey) &&
5082 EVP_OpenUpdate(&ctx, buf, &len1, (unsigned char *)data, (int)data_len)) {
5083 if (!EVP_OpenFinal(&ctx, buf + len1, &len2) || (len1 + len2 == 0)) {
5084 efree(buf);
5085 RETVAL_FALSE;
5086 } else {
5087 zval_dtor(opendata);
5088 buf[len1 + len2] = '\0';
5089 ZVAL_NEW_STR(opendata, zend_string_init((char*)buf, len1 + len2, 0));
5090 efree(buf);
5091 RETVAL_TRUE;
5092 }
5093 } else {
5094 efree(buf);
5095 RETVAL_FALSE;
5096 }
5097 if (keyresource == NULL) {
5098 EVP_PKEY_free(pkey);
5099 }
5100 EVP_CIPHER_CTX_cleanup(&ctx);
5101 }
5102
5103
5104 static void openssl_add_method_or_alias(const OBJ_NAME *name, void *arg)
5105 {
5106 add_next_index_string((zval*)arg, (char*)name->name);
5107 }
5108
5109
5110 static void openssl_add_method(const OBJ_NAME *name, void *arg)
5111 {
5112 if (name->alias == 0) {
5113 add_next_index_string((zval*)arg, (char*)name->name);
5114 }
5115 }
5116
5117
5118
5119
5120 PHP_FUNCTION(openssl_get_md_methods)
5121 {
5122 zend_bool aliases = 0;
5123
5124 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &aliases) == FAILURE) {
5125 return;
5126 }
5127 array_init(return_value);
5128 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
5129 aliases ? openssl_add_method_or_alias: openssl_add_method,
5130 return_value);
5131 }
5132
5133
5134
5135
5136 PHP_FUNCTION(openssl_get_cipher_methods)
5137 {
5138 zend_bool aliases = 0;
5139
5140 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &aliases) == FAILURE) {
5141 return;
5142 }
5143 array_init(return_value);
5144 OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
5145 aliases ? openssl_add_method_or_alias: openssl_add_method,
5146 return_value);
5147 }
5148
5149
5150
5151
5152 PHP_FUNCTION(openssl_digest)
5153 {
5154 zend_bool raw_output = 0;
5155 char *data, *method;
5156 size_t data_len, method_len;
5157 const EVP_MD *mdtype;
5158 EVP_MD_CTX md_ctx;
5159 unsigned int siglen;
5160 zend_string *sigbuf;
5161
5162 if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|b", &data, &data_len, &method, &method_len, &raw_output) == FAILURE) {
5163 return;
5164 }
5165 mdtype = EVP_get_digestbyname(method);
5166 if (!mdtype) {
5167 php_error_docref(NULL, E_WARNING, "Unknown signature algorithm");
5168 RETURN_FALSE;
5169 }
5170
5171 siglen = EVP_MD_size(mdtype);
5172 sigbuf = zend_string_alloc(siglen, 0);
5173
5174 EVP_DigestInit(&md_ctx, mdtype);
5175 EVP_DigestUpdate(&md_ctx, (unsigned char *)data, data_len);
5176 if (EVP_DigestFinal (&md_ctx, (unsigned char *)ZSTR_VAL(sigbuf), &siglen)) {
5177 if (raw_output) {
5178 ZSTR_VAL(sigbuf)[siglen] = '\0';
5179 ZSTR_LEN(sigbuf) = siglen;
5180 RETVAL_STR(sigbuf);
5181 } else {
5182 int digest_str_len = siglen * 2;
5183 zend_string *digest_str = zend_string_alloc(digest_str_len, 0);
5184
5185 make_digest_ex(ZSTR_VAL(digest_str), (unsigned char*)ZSTR_VAL(sigbuf), siglen);
5186 ZSTR_VAL(digest_str)[digest_str_len] = '\0';
5187 zend_string_release(sigbuf);
5188 RETVAL_STR(digest_str);
5189 }
5190 } else {
5191 zend_string_release(sigbuf);
5192 RETVAL_FALSE;
5193 }
5194 }
5195
5196
5197 static zend_bool php_openssl_validate_iv(char **piv, size_t *piv_len, size_t iv_required_len)
5198 {
5199 char *iv_new;
5200
5201
5202 if (*piv_len == iv_required_len) {
5203 return 0;
5204 }
5205
5206 iv_new = ecalloc(1, iv_required_len + 1);
5207
5208 if (*piv_len == 0) {
5209
5210 *piv_len = iv_required_len;
5211 *piv = iv_new;
5212 return 1;
5213 }
5214
5215 if (*piv_len < iv_required_len) {
5216 php_error_docref(NULL, E_WARNING, "IV passed is only %zd bytes long, cipher expects an IV of precisely %zd bytes, padding with \\0", *piv_len, iv_required_len);
5217 memcpy(iv_new, *piv, *piv_len);
5218 *piv_len = iv_required_len;
5219 *piv = iv_new;
5220 return 1;
5221 }
5222
5223 php_error_docref(NULL, E_WARNING, "IV passed is %zd bytes long which is longer than the %zd expected by selected cipher, truncating", *piv_len, iv_required_len);
5224 memcpy(iv_new, *piv, iv_required_len);
5225 *piv_len = iv_required_len;
5226 *piv = iv_new;
5227 return 1;
5228
5229 }
5230
5231
5232
5233 PHP_FUNCTION(openssl_encrypt)
5234 {
5235 zend_long options = 0;
5236 char *data, *method, *password, *iv = "";
5237 size_t data_len, method_len, password_len, iv_len = 0, max_iv_len;
5238 const EVP_CIPHER *cipher_type;
5239 EVP_CIPHER_CTX cipher_ctx;
5240 int i=0, outlen, keylen;
5241 zend_string *outbuf;
5242 unsigned char *key;
5243 zend_bool free_iv;
5244
5245 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|ls", &data, &data_len, &method, &method_len, &password, &password_len, &options, &iv, &iv_len) == FAILURE) {
5246 return;
5247 }
5248 cipher_type = EVP_get_cipherbyname(method);
5249 if (!cipher_type) {
5250 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
5251 RETURN_FALSE;
5252 }
5253
5254 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
5255
5256 keylen = EVP_CIPHER_key_length(cipher_type);
5257 if (keylen > password_len) {
5258 key = emalloc(keylen);
5259 memset(key, 0, keylen);
5260 memcpy(key, password, password_len);
5261 } else {
5262 key = (unsigned char*)password;
5263 }
5264
5265 max_iv_len = EVP_CIPHER_iv_length(cipher_type);
5266 if (iv_len == 0 && max_iv_len > 0) {
5267 php_error_docref(NULL, E_WARNING, "Using an empty Initialization Vector (iv) is potentially insecure and not recommended");
5268 }
5269 free_iv = php_openssl_validate_iv(&iv, &iv_len, max_iv_len);
5270
5271 outlen = (int)data_len + EVP_CIPHER_block_size(cipher_type);
5272 outbuf = zend_string_alloc(outlen, 0);
5273
5274 EVP_EncryptInit(&cipher_ctx, cipher_type, NULL, NULL);
5275 if (password_len > keylen) {
5276 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password);
5277 EVP_CIPHER_CTX_set_key_length(&cipher_ctx, (int)password_len);
5278 }
5279 EVP_EncryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
5280 if (options & OPENSSL_ZERO_PADDING) {
5281 EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0);
5282 }
5283 if (data_len > 0) {
5284 EVP_EncryptUpdate(&cipher_ctx, (unsigned char*)ZSTR_VAL(outbuf), &i, (unsigned char *)data, (int)data_len);
5285 }
5286 outlen = i;
5287 if (EVP_EncryptFinal(&cipher_ctx, (unsigned char *)ZSTR_VAL(outbuf) + i, &i)) {
5288 outlen += i;
5289 if (options & OPENSSL_RAW_DATA) {
5290 ZSTR_VAL(outbuf)[outlen] = '\0';
5291 ZSTR_LEN(outbuf) = outlen;
5292 RETVAL_STR(outbuf);
5293 } else {
5294 zend_string *base64_str;
5295
5296 base64_str = php_base64_encode((unsigned char*)ZSTR_VAL(outbuf), outlen);
5297 zend_string_release(outbuf);
5298 RETVAL_STR(base64_str);
5299 }
5300 } else {
5301 zend_string_release(outbuf);
5302 RETVAL_FALSE;
5303 }
5304 if (key != (unsigned char*)password) {
5305 efree(key);
5306 }
5307 if (free_iv) {
5308 efree(iv);
5309 }
5310 EVP_CIPHER_CTX_cleanup(&cipher_ctx);
5311 }
5312
5313
5314
5315
5316 PHP_FUNCTION(openssl_decrypt)
5317 {
5318 zend_long options = 0;
5319 char *data, *method, *password, *iv = "";
5320 size_t data_len, method_len, password_len, iv_len = 0;
5321 const EVP_CIPHER *cipher_type;
5322 EVP_CIPHER_CTX cipher_ctx;
5323 int i, outlen, keylen;
5324 zend_string *outbuf;
5325 unsigned char *key;
5326 zend_string *base64_str = NULL;
5327 zend_bool free_iv;
5328
5329 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|ls", &data, &data_len, &method, &method_len, &password, &password_len, &options, &iv, &iv_len) == FAILURE) {
5330 return;
5331 }
5332
5333 if (!method_len) {
5334 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
5335 RETURN_FALSE;
5336 }
5337
5338 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data);
5339
5340 cipher_type = EVP_get_cipherbyname(method);
5341 if (!cipher_type) {
5342 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
5343 RETURN_FALSE;
5344 }
5345
5346 if (!(options & OPENSSL_RAW_DATA)) {
5347 base64_str = php_base64_decode((unsigned char*)data, (int)data_len);
5348 if (!base64_str) {
5349 php_error_docref(NULL, E_WARNING, "Failed to base64 decode the input");
5350 RETURN_FALSE;
5351 }
5352 data_len = ZSTR_LEN(base64_str);
5353 data = ZSTR_VAL(base64_str);
5354 }
5355
5356 keylen = EVP_CIPHER_key_length(cipher_type);
5357 if (keylen > password_len) {
5358 key = emalloc(keylen);
5359 memset(key, 0, keylen);
5360 memcpy(key, password, password_len);
5361 } else {
5362 key = (unsigned char*)password;
5363 }
5364
5365 free_iv = php_openssl_validate_iv(&iv, &iv_len, EVP_CIPHER_iv_length(cipher_type));
5366
5367 outlen = (int)data_len + EVP_CIPHER_block_size(cipher_type);
5368 outbuf = zend_string_alloc(outlen, 0);
5369
5370 EVP_DecryptInit(&cipher_ctx, cipher_type, NULL, NULL);
5371 if (password_len > keylen) {
5372 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(password_len, password);
5373 EVP_CIPHER_CTX_set_key_length(&cipher_ctx, (int)password_len);
5374 }
5375 EVP_DecryptInit_ex(&cipher_ctx, NULL, NULL, key, (unsigned char *)iv);
5376 if (options & OPENSSL_ZERO_PADDING) {
5377 EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0);
5378 }
5379 EVP_DecryptUpdate(&cipher_ctx, (unsigned char*)ZSTR_VAL(outbuf), &i, (unsigned char *)data, (int)data_len);
5380 outlen = i;
5381 if (EVP_DecryptFinal(&cipher_ctx, (unsigned char *)ZSTR_VAL(outbuf) + i, &i)) {
5382 outlen += i;
5383 ZSTR_VAL(outbuf)[outlen] = '\0';
5384 ZSTR_LEN(outbuf) = outlen;
5385 RETVAL_STR(outbuf);
5386 } else {
5387 zend_string_release(outbuf);
5388 RETVAL_FALSE;
5389 }
5390 if (key != (unsigned char*)password) {
5391 efree(key);
5392 }
5393 if (free_iv) {
5394 efree(iv);
5395 }
5396 if (base64_str) {
5397 zend_string_release(base64_str);
5398 }
5399 EVP_CIPHER_CTX_cleanup(&cipher_ctx);
5400 }
5401
5402
5403
5404 PHP_FUNCTION(openssl_cipher_iv_length)
5405 {
5406 char *method;
5407 size_t method_len;
5408 const EVP_CIPHER *cipher_type;
5409
5410 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &method, &method_len) == FAILURE) {
5411 return;
5412 }
5413
5414 if (!method_len) {
5415 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
5416 RETURN_FALSE;
5417 }
5418
5419 cipher_type = EVP_get_cipherbyname(method);
5420 if (!cipher_type) {
5421 php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm");
5422 RETURN_FALSE;
5423 }
5424
5425 RETURN_LONG(EVP_CIPHER_iv_length(cipher_type));
5426 }
5427
5428
5429
5430
5431
5432 PHP_FUNCTION(openssl_dh_compute_key)
5433 {
5434 zval *key;
5435 char *pub_str;
5436 size_t pub_len;
5437 EVP_PKEY *pkey;
5438 BIGNUM *pub;
5439 zend_string *data;
5440 int len;
5441
5442 if (zend_parse_parameters(ZEND_NUM_ARGS(), "sr", &pub_str, &pub_len, &key) == FAILURE) {
5443 return;
5444 }
5445 if ((pkey = (EVP_PKEY *)zend_fetch_resource(Z_RES_P(key), "OpenSSL key", le_key)) == NULL) {
5446 RETURN_FALSE;
5447 }
5448 if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH || !pkey->pkey.dh) {
5449 RETURN_FALSE;
5450 }
5451
5452 PHP_OPENSSL_CHECK_SIZE_T_TO_INT(pub_len, pub_key);
5453 pub = BN_bin2bn((unsigned char*)pub_str, (int)pub_len, NULL);
5454
5455 data = zend_string_alloc(DH_size(pkey->pkey.dh), 0);
5456 len = DH_compute_key((unsigned char*)ZSTR_VAL(data), pub, pkey->pkey.dh);
5457
5458 if (len >= 0) {
5459 ZSTR_LEN(data) = len;
5460 ZSTR_VAL(data)[len] = 0;
5461 RETVAL_STR(data);
5462 } else {
5463 zend_string_release(data);
5464 RETVAL_FALSE;
5465 }
5466
5467 BN_free(pub);
5468 }
5469
5470
5471
5472
5473 PHP_FUNCTION(openssl_random_pseudo_bytes)
5474 {
5475 zend_long buffer_length;
5476 zend_string *buffer = NULL;
5477 zval *zstrong_result_returned = NULL;
5478
5479 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z/", &buffer_length, &zstrong_result_returned) == FAILURE) {
5480 return;
5481 }
5482
5483 if (buffer_length <= 0) {
5484 RETURN_FALSE;
5485 }
5486
5487 if (zstrong_result_returned) {
5488 zval_dtor(zstrong_result_returned);
5489 ZVAL_FALSE(zstrong_result_returned);
5490 }
5491
5492 buffer = zend_string_alloc(buffer_length, 0);
5493
5494 #ifdef PHP_WIN32
5495
5496 if (php_win32_get_random_bytes((unsigned char*)buffer->val, (size_t) buffer_length) == FAILURE){
5497 zend_string_release(buffer);
5498 if (zstrong_result_returned) {
5499 ZVAL_FALSE(zstrong_result_returned);
5500 }
5501 RETURN_FALSE;
5502 }
5503 #else
5504
5505 PHP_OPENSSL_CHECK_LONG_TO_INT(buffer_length, length);
5506
5507 if (RAND_bytes((unsigned char*)ZSTR_VAL(buffer), (int)buffer_length) <= 0) {
5508 zend_string_release(buffer);
5509 if (zstrong_result_returned) {
5510 ZVAL_FALSE(zstrong_result_returned);
5511 }
5512 RETURN_FALSE;
5513 }
5514 #endif
5515
5516 ZSTR_VAL(buffer)[buffer_length] = 0;
5517 RETVAL_STR(buffer);
5518
5519 if (zstrong_result_returned) {
5520 ZVAL_BOOL(zstrong_result_returned, 1);
5521 }
5522 }
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533