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