1--TEST--
2CURLOPT_SSL* basic client auth tests
3--EXTENSIONS--
4curl
5--SKIPIF--
6<?php
7if (!function_exists("proc_open")) die("skip no proc_open");
8exec('openssl version', $out, $code);
9if ($code > 0) die("skip couldn't locate openssl binary");
10if (PHP_OS_FAMILY === 'Windows') die('skip not for Windows');
11$curl_version = curl_version();
12if ($curl_version['version_number'] < 0x074700) {
13    die("skip: blob options not supported for curl < 7.71.0");
14}
15?>
16--FILE--
17<?php
18
19function check_error(CurlHandle $ch) {
20    if (curl_errno($ch) !== 0) {
21        echo "CURL ERROR: " . curl_errno($ch) . "\n";
22    }
23}
24
25function check_response($response, $clientCertSubject) {
26    if (strpos($response, $clientCertSubject) === false) {
27        echo "client cert subject not in response\n";
28    } else {
29        echo "client cert subject in response\n";
30    }
31}
32
33$clientCertSubject = "Subject: C=US, ST=TX, L=Clientlocation, O=Clientcompany, CN=clientname/emailAddress=test@example.com";
34
35// load server cert
36$serverCertPath = __DIR__ . DIRECTORY_SEPARATOR . 'curl_setopt_ssl_servercert.pem';
37$serverCert = file_get_contents($serverCertPath);
38
39// load server key
40$serverKeyPath = __DIR__ . DIRECTORY_SEPARATOR . 'curl_setopt_ssl_serverkey.pem';
41$serverKey = file_get_contents($serverKeyPath);
42
43// load client cert
44$clientCertPath = __DIR__ . DIRECTORY_SEPARATOR . 'curl_setopt_ssl_clientcert.pem';
45$clientCert = file_get_contents($clientCertPath);
46
47// load client key
48$clientKeyPath = __DIR__ . DIRECTORY_SEPARATOR . 'curl_setopt_ssl_clientkey.pem';
49$clientKey = file_get_contents($clientKeyPath);
50
51if ($serverCert === false
52    || $serverKey === false
53    || $clientCert === false
54    || $clientKey === false
55) {
56    die('failed to load test certs and keys for files');
57}
58
59$port = 14430;
60
61// set up local server
62$cmd = "openssl s_server -key $serverKeyPath -cert $serverCertPath -accept $port -www -CAfile $clientCertPath -verify_return_error -Verify 1";
63$process = proc_open($cmd, [["pipe", "r"], ["pipe", "w"], ["pipe", "w"]], $pipes);
64
65if ($process === false) {
66    die('failed to start server');
67}
68try {
69    // Give the server time to start
70    sleep(1);
71
72    echo "case 1: client cert and key from string\n";
73    $ch = curl_init("https://127.0.0.1:$port/");
74    var_dump(curl_setopt($ch, CURLOPT_SSLCERT_BLOB, $clientCert));
75    var_dump(curl_setopt($ch, CURLOPT_SSLKEY_BLOB, $clientKey));
76    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false));
77    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false));
78    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
79
80    $response = curl_exec($ch);
81    check_response($response, $clientCertSubject);
82    check_error($ch);
83    curl_close($ch);
84
85    echo "\n";
86    echo "case 2: empty client cert and key from string\n";
87    $ch = curl_init("https://127.0.0.1:$port/");
88    var_dump(curl_setopt($ch, CURLOPT_SSLCERT_BLOB, ''));
89    var_dump(curl_setopt($ch, CURLOPT_SSLKEY_BLOB, $clientKey));
90    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false));
91    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false));
92    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
93
94    $response = curl_exec($ch);
95    check_response($response, $clientCertSubject);
96    check_error($ch);
97    curl_close($ch);
98
99    echo "\n";
100    echo "case 3: client cert and empty key from string\n";
101    $ch = curl_init("https://127.0.0.1:$port/");
102    var_dump(curl_setopt($ch, CURLOPT_SSLCERT_BLOB, $clientCert));
103    var_dump(curl_setopt($ch, CURLOPT_SSLKEY_BLOB, ''));
104    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false));
105    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false));
106    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
107
108    $response = curl_exec($ch);
109    check_response($response, $clientCertSubject);
110    check_error($ch);
111    curl_close($ch);
112
113    echo "\n";
114    echo "case 4: client cert and key from file\n";
115    $ch = curl_init("https://127.0.0.1:$port/");
116    var_dump(curl_setopt($ch, CURLOPT_SSLCERT, $clientCertPath));
117    var_dump(curl_setopt($ch, CURLOPT_SSLKEY, $clientKeyPath));
118    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false));
119    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false));
120    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
121
122    $response = curl_exec($ch);
123    check_response($response, $clientCertSubject);
124    check_error($ch);
125    curl_close($ch);
126
127    echo "\n";
128    echo "case 5: issuer cert from file\n";
129    $ch = curl_init("https://127.0.0.1:$port/");
130    var_dump(curl_setopt($ch, CURLOPT_CAINFO, $serverCertPath));
131    var_dump(curl_setopt($ch, CURLOPT_ISSUERCERT, $serverCertPath));
132    var_dump(curl_setopt($ch, CURLOPT_SSLCERT, $clientCertPath));
133    var_dump(curl_setopt($ch, CURLOPT_SSLKEY, $clientKeyPath));
134    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true));
135    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false));
136    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
137
138    $response = curl_exec($ch);
139    check_response($response, $clientCertSubject);
140    check_error($ch);
141    curl_close($ch);
142
143    echo "\n";
144    echo "case 6: issuer cert from string\n";
145    $ch = curl_init("https://127.0.0.1:$port/");
146    var_dump(curl_setopt($ch, CURLOPT_CAINFO, $serverCertPath));
147    var_dump(curl_setopt($ch, CURLOPT_ISSUERCERT_BLOB, $serverCert));
148    var_dump(curl_setopt($ch, CURLOPT_SSLCERT, $clientCertPath));
149    var_dump(curl_setopt($ch, CURLOPT_SSLKEY, $clientKeyPath));
150    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true));
151    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false));
152    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
153
154    $response = curl_exec($ch);
155    check_response($response, $clientCertSubject);
156    check_error($ch);
157    curl_close($ch);
158
159    echo "\n";
160    echo "case 7: empty issuer cert from string\n";
161    $ch = curl_init("https://127.0.0.1:$port/");
162    var_dump(curl_setopt($ch, CURLOPT_CAINFO, $serverCertPath));
163    var_dump(curl_setopt($ch, CURLOPT_ISSUERCERT_BLOB, ''));
164    var_dump(curl_setopt($ch, CURLOPT_SSLCERT, $clientCertPath));
165    var_dump(curl_setopt($ch, CURLOPT_SSLKEY, $clientKeyPath));
166    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true));
167    var_dump(curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false));
168    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
169
170    $response = curl_exec($ch);
171    check_response($response, $clientCertSubject);
172    check_error($ch);
173    curl_close($ch);
174
175} finally {
176    // clean up server process
177    proc_terminate($process);
178    proc_close($process);
179}
180
181?>
182--EXPECT--
183case 1: client cert and key from string
184bool(true)
185bool(true)
186bool(true)
187bool(true)
188client cert subject in response
189
190case 2: empty client cert and key from string
191bool(true)
192bool(true)
193bool(true)
194bool(true)
195client cert subject not in response
196CURL ERROR: 58
197
198case 3: client cert and empty key from string
199bool(true)
200bool(true)
201bool(true)
202bool(true)
203client cert subject not in response
204CURL ERROR: 58
205
206case 4: client cert and key from file
207bool(true)
208bool(true)
209bool(true)
210bool(true)
211client cert subject in response
212
213case 5: issuer cert from file
214bool(true)
215bool(true)
216bool(true)
217bool(true)
218bool(true)
219bool(true)
220client cert subject in response
221
222case 6: issuer cert from string
223bool(true)
224bool(true)
225bool(true)
226bool(true)
227bool(true)
228bool(true)
229client cert subject in response
230
231case 7: empty issuer cert from string
232bool(true)
233bool(true)
234bool(true)
235bool(true)
236bool(true)
237bool(true)
238client cert subject not in response
239CURL ERROR: 83