1--TEST--
2openssl_error_string() tests
3--SKIPIF--
4<?php if (!extension_loaded("openssl")) print "skip"; ?>
5--FILE--
6<?php
7// helper function to check openssl errors
8function expect_openssl_errors($name, $expected_error_codes) {
9	$expected_errors = array_fill_keys($expected_error_codes, false);
10	while (($error_string = openssl_error_string()) !== false) {
11		if (strlen($error_string) > 14) {
12			$error_code = substr($error_string, 6, 8);
13			if (isset($expected_errors[$error_code])) {
14				$expected_errors[$error_code] = true;
15			}
16		}
17	}
18
19	$fail = false;
20	foreach ($expected_errors as $error_code => $error_code_found) {
21		if (!$error_code_found) {
22			$fail = true;
23			echo "$name: no error code $error_code\n";
24		}
25	}
26
27	if (!$fail) {
28		echo "$name: ok\n";
29	}
30}
31
32// helper for debugging errors
33function dump_openssl_errors($name) {
34	echo "\n$name\n";
35	while (($error_string = openssl_error_string()) !== false) {
36		var_dump($error_string);
37	}
38}
39
40// common output file
41$output_file =  __DIR__ . "/openssl_error_string_basic_output.tmp";
42// invalid file for read is something that does not exist in current directory
43$invalid_file_for_read = __DIR__ . "/invalid_file_for_read_operation.txt";
44// invalid file for is the test dir as writting file to existing dir should alway fail
45$invalid_file_for_write = __DIR__;
46// crt file
47$crt_file = "file://" . __DIR__ . "/cert.crt";
48// csr file
49$csr_file = "file://" . __DIR__ . "/cert.csr";
50// public key file
51$public_key_file = "file://" .__DIR__ . "/public.key";
52// private key file
53$private_key_file = "file://" .__DIR__ . "/private_rsa_1024.key";
54// private key file with password (password is 'php')
55$private_key_file_with_pass = "file://" .__DIR__ . "/private_rsa_2048_pass_php.key";
56
57// ENCRYPTION
58$data = "test";
59$method = "AES-128-ECB";
60$enc_key = str_repeat('x', 40);
61// error because password is longer then key length and
62// EVP_CIPHER_CTX_set_key_length fails for AES
63openssl_encrypt($data, $method, $enc_key);
64$enc_error = openssl_error_string();
65var_dump($enc_error);
66// make sure that error is cleared now
67var_dump(openssl_error_string());
68// internally OpenSSL ERR won't save more than 15 (16 - 1) errors so lets test it
69for ($i = 0; $i < 20; $i++) {
70	openssl_encrypt($data, $method, $enc_key);
71}
72$error_queue_size = 0;
73while (($enc_error_new = openssl_error_string()) !== false) {
74	if ($enc_error_new !== $enc_error) {
75		echo "The new encoding error doesn't match the expected one\n";
76	}
77	++$error_queue_size;
78}
79var_dump($error_queue_size);
80echo "\n";
81
82// PKEY
83echo "PKEY errors\n";
84// file for pkey (file:///) fails when opennig (BIO_new_file)
85@openssl_pkey_export_to_file("file://" . $invalid_file_for_read, $output_file);
86expect_openssl_errors('openssl_pkey_export_to_file opening', ['02001002', '2006D080']);
87// file or private pkey is not correct PEM - failing PEM_read_bio_PrivateKey
88@openssl_pkey_export_to_file($csr_file, $output_file);
89expect_openssl_errors('openssl_pkey_export_to_file pem', ['0906D06C']);
90// file to export cannot be written
91@openssl_pkey_export_to_file($private_key_file, $invalid_file_for_write);
92expect_openssl_errors('openssl_pkey_export_to_file write', ['2006D002']);
93// succesful export
94@openssl_pkey_export($private_key_file_with_pass, $out, 'wrong pwd');
95expect_openssl_errors('openssl_pkey_export', ['06065064', '0906A065']);
96// invalid x509 for getting public key
97@openssl_pkey_get_public($private_key_file);
98expect_openssl_errors('openssl_pkey_get_public', ['0906D06C']);
99// private encrypt with unknown padding
100@openssl_private_encrypt("data", $crypted, $private_key_file, 1000);
101expect_openssl_errors('openssl_private_encrypt', ['04066076']);
102// private decrypt with failed padding check
103@openssl_private_decrypt("data", $crypted, $private_key_file);
104expect_openssl_errors('openssl_private_decrypt', ['04065072']);
105// public encrypt and decrypt with failed padding check and padding
106@openssl_public_encrypt("data", $crypted, $public_key_file, 1000);
107@openssl_public_decrypt("data", $crypted, $public_key_file);
108expect_openssl_errors('openssl_private_(en|de)crypt padding', ['0906D06C', '04068076', '04067072']);
109
110// X509
111echo "X509 errors\n";
112// file for x509 (file:///) fails when opennig (BIO_new_file)
113@openssl_x509_export_to_file("file://" . $invalid_file_for_read, $output_file);
114expect_openssl_errors('openssl_x509_export_to_file open', ['02001002']);
115// file or str cert is not correct PEM - failing PEM_read_bio_X509 or PEM_ASN1_read_bio
116@openssl_x509_export_to_file($csr_file, $output_file);
117expect_openssl_errors('openssl_x509_export_to_file pem', ['0906D06C']);
118// file to export cannot be written
119@openssl_x509_export_to_file($crt_file, $invalid_file_for_write);
120expect_openssl_errors('openssl_x509_export_to_file write', ['2006D002']);
121// checking purpose fails because there is no such purpose 1000
122@openssl_x509_checkpurpose($crt_file, 1000);
123expect_openssl_errors('openssl_x509_checkpurpose purpose', ['0B086079']);
124
125// CSR
126echo "CSR errors\n";
127// file for csr (file:///) fails when opennig (BIO_new_file)
128@openssl_csr_get_subject("file://" . $invalid_file_for_read);
129expect_openssl_errors('openssl_csr_get_subject open', ['02001002', '2006D080']);
130// file or str csr is not correct PEM - failing PEM_read_bio_X509_REQ
131@openssl_csr_get_subject($crt_file);
132expect_openssl_errors('openssl_csr_get_subjec pem', ['0906D06C']);
133
134// other possible cuases that are difficult to catch:
135// - ASN1_STRING_to_UTF8 fails in add_assoc_name_entry
136// - invalid php_x509_request field (NULL) would cause error with CONF_get_string
137
138?>
139--CLEAN--
140<?php
141$output_file =  __DIR__ . "/openssl_error_string_basic_output.tmp";
142if (is_file($output_file)) {
143	unlink($output_file);
144}
145?>
146--EXPECT--
147string(89) "error:0607A082:digital envelope routines:EVP_CIPHER_CTX_set_key_length:invalid key length"
148bool(false)
149int(15)
150
151PKEY errors
152openssl_pkey_export_to_file opening: ok
153openssl_pkey_export_to_file pem: ok
154openssl_pkey_export_to_file write: ok
155openssl_pkey_export: ok
156openssl_pkey_get_public: ok
157openssl_private_encrypt: ok
158openssl_private_decrypt: ok
159openssl_private_(en|de)crypt padding: ok
160X509 errors
161openssl_x509_export_to_file open: ok
162openssl_x509_export_to_file pem: ok
163openssl_x509_export_to_file write: ok
164openssl_x509_checkpurpose purpose: ok
165CSR errors
166openssl_csr_get_subject open: ok
167openssl_csr_get_subjec pem: ok
168