diff options
Diffstat (limited to 'src/testcurl/https/tls_daemon_options_test.c')
-rw-r--r-- | src/testcurl/https/tls_daemon_options_test.c | 370 |
1 files changed, 27 insertions, 343 deletions
diff --git a/src/testcurl/https/tls_daemon_options_test.c b/src/testcurl/https/tls_daemon_options_test.c index b388f24d..7b56f334 100644 --- a/src/testcurl/https/tls_daemon_options_test.c +++ b/src/testcurl/https/tls_daemon_options_test.c | |||
@@ -26,360 +26,46 @@ | |||
26 | 26 | ||
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "microhttpd.h" | 28 | #include "microhttpd.h" |
29 | |||
30 | #include <sys/stat.h> | 29 | #include <sys/stat.h> |
31 | #include <limits.h> | 30 | #include <limits.h> |
32 | #include "gnutls.h" | 31 | #include "gnutls.h" |
33 | #include <curl/curl.h> | ||
34 | |||
35 | #define DEBUG_CURL_VERBOSE 0 | ||
36 | #define PAGE_NOT_FOUND "<html><head><title>File not found</title></head><body>File not found</body></html>" | ||
37 | 32 | ||
38 | #define MHD_E_MEM "Error: memory error\n" | 33 | #include "tls_test_common.h" |
39 | #define MHD_E_SERVER_INIT "Error: failed to start server\n" | ||
40 | #define MHD_E_TEST_FILE_CREAT "Error: failed to setup test file\n" | ||
41 | #define MHD_E_CERT_FILE_CREAT "Error: failed to setup test certificate\n" | ||
42 | #define MHD_E_KEY_FILE_CREAT "Error: failed to setup test certificate\n" | ||
43 | 34 | ||
44 | #include "tls_test_keys.h" | 35 | extern const char srv_key_pem[]; |
45 | 36 | extern const char srv_self_signed_cert_pem[]; | |
46 | const char *test_file_name = "https_test_file"; | ||
47 | const char test_file_data[] = "Hello World\n"; | ||
48 | 37 | ||
49 | int curl_check_version (const char *req_version, ...); | 38 | int curl_check_version (const char *req_version, ...); |
50 | 39 | ||
51 | struct CBC | ||
52 | { | ||
53 | char *buf; | ||
54 | size_t pos; | ||
55 | size_t size; | ||
56 | }; | ||
57 | |||
58 | struct https_test_data | ||
59 | { | ||
60 | FILE *test_fd; | ||
61 | char *cipher_suite; | ||
62 | int proto_version; | ||
63 | }; | ||
64 | |||
65 | struct CipherDef | ||
66 | { | ||
67 | int options[2]; | ||
68 | char *curlname; | ||
69 | }; | ||
70 | |||
71 | static size_t | ||
72 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | ||
73 | { | ||
74 | struct CBC *cbc = ctx; | ||
75 | |||
76 | if (cbc->pos + size * nmemb > cbc->size) | ||
77 | return 0; /* overflow */ | ||
78 | memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); | ||
79 | cbc->pos += size * nmemb; | ||
80 | return size * nmemb; | ||
81 | } | ||
82 | |||
83 | static int | ||
84 | file_reader (void *cls, size_t pos, char *buf, int max) | ||
85 | { | ||
86 | FILE *file = cls; | ||
87 | fseek (file, pos, SEEK_SET); | ||
88 | return fread (buf, 1, max, file); | ||
89 | } | ||
90 | |||
91 | /* HTTP access handler call back */ | ||
92 | static int | ||
93 | http_ahc (void *cls, struct MHD_Connection *connection, | ||
94 | const char *url, const char *method, const char *upload_data, | ||
95 | const char *version, unsigned int *upload_data_size, void **ptr) | ||
96 | { | ||
97 | static int aptr; | ||
98 | struct MHD_Response *response; | ||
99 | int ret; | ||
100 | FILE *file; | ||
101 | struct stat buf; | ||
102 | |||
103 | if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) | ||
104 | return MHD_NO; /* unexpected method */ | ||
105 | if (&aptr != *ptr) | ||
106 | { | ||
107 | /* do never respond on first call */ | ||
108 | *ptr = &aptr; | ||
109 | return MHD_YES; | ||
110 | } | ||
111 | *ptr = NULL; /* reset when done */ | ||
112 | |||
113 | file = fopen (url, "r"); | ||
114 | if (file == NULL) | ||
115 | { | ||
116 | response = MHD_create_response_from_data (strlen (PAGE_NOT_FOUND), | ||
117 | (void *) PAGE_NOT_FOUND, | ||
118 | MHD_NO, MHD_NO); | ||
119 | ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response); | ||
120 | MHD_destroy_response (response); | ||
121 | } | ||
122 | else | ||
123 | { | ||
124 | stat (url, &buf); | ||
125 | response = MHD_create_response_from_callback (buf.st_size, 32 * 1024, /* 32k PAGE_NOT_FOUND size */ | ||
126 | &file_reader, file, | ||
127 | (MHD_ContentReaderFreeCallback) | ||
128 | & fclose); | ||
129 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
130 | MHD_destroy_response (response); | ||
131 | } | ||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | |||
136 | |||
137 | /** | 40 | /** |
138 | * test HTTPS transfer | 41 | * test server refuses to negotiate connections with unsupported protocol versions |
139 | * @param test_fd: file to attempt transfering | 42 | * |
140 | */ | 43 | */ |
44 | /* TODO rm test_fd */ | ||
141 | static int | 45 | static int |
142 | test_https_transfer (FILE * test_fd, char *cipher_suite, int proto_version) | 46 | test_unmatching_ssl_version (FILE * test_fd, char *cipher_suite, |
47 | int curl_req_ssl_version) | ||
143 | { | 48 | { |
144 | CURL *c; | ||
145 | CURLcode errornum; | ||
146 | struct CBC cbc; | 49 | struct CBC cbc; |
147 | char *doc_path; | 50 | if (NULL == (cbc.buf = malloc (sizeof (char) * 256))) |
148 | size_t doc_path_len; | ||
149 | char url[255]; | ||
150 | struct stat statb; | ||
151 | |||
152 | stat (test_file_name, &statb); | ||
153 | |||
154 | int len = statb.st_size; | ||
155 | |||
156 | /* used to memcmp local copy & deamon supplied copy */ | ||
157 | unsigned char *mem_test_file_local; | ||
158 | |||
159 | /* setup test file path, url */ | ||
160 | doc_path_len = PATH_MAX > 4096 ? 4096 : PATH_MAX; | ||
161 | if (NULL == (doc_path = malloc (doc_path_len))) | ||
162 | { | ||
163 | fprintf (stderr, MHD_E_MEM); | ||
164 | return -1; | ||
165 | } | ||
166 | if (getcwd (doc_path, doc_path_len) == NULL) | ||
167 | { | ||
168 | fprintf (stderr, "Error: failed to get working directory. %s\n", | ||
169 | strerror (errno)); | ||
170 | free (doc_path); | ||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | if (NULL == (mem_test_file_local = malloc (len))) | ||
175 | { | ||
176 | fprintf (stderr, MHD_E_MEM); | ||
177 | free (doc_path); | ||
178 | return -1; | ||
179 | } | ||
180 | |||
181 | fseek (test_fd, 0, SEEK_SET); | ||
182 | if (fread (mem_test_file_local, sizeof (char), len, test_fd) != len) | ||
183 | { | 51 | { |
184 | fprintf (stderr, "Error: failed to read test file. %s\n", | 52 | fprintf (stderr, "Error: failed to read test file. %s\n", |
185 | strerror (errno)); | 53 | strerror (errno)); |
186 | free (mem_test_file_local); | ||
187 | free (doc_path); | ||
188 | return -1; | ||
189 | } | ||
190 | |||
191 | if (NULL == (cbc.buf = malloc (sizeof (char) * len))) | ||
192 | { | ||
193 | fprintf (stderr, MHD_E_MEM); | ||
194 | free (mem_test_file_local); | ||
195 | free (doc_path); | ||
196 | return -1; | 54 | return -1; |
197 | } | 55 | } |
198 | cbc.size = len; | 56 | cbc.size = 256; |
199 | cbc.pos = 0; | 57 | cbc.pos = 0; |
200 | 58 | ||
201 | /* construct url - this might use doc_path */ | 59 | char url[255]; |
202 | sprintf (url, "%s%s/%s", "https://localhost:42433", | 60 | if (gen_test_file_url (url, DEAMON_TEST_PORT)) |
203 | doc_path, test_file_name); | ||
204 | |||
205 | c = curl_easy_init (); | ||
206 | #if DEBUG_CURL_VERBOSE | ||
207 | curl_easy_setopt (c, CURLOPT_VERBOSE, 1); | ||
208 | #endif | ||
209 | curl_easy_setopt (c, CURLOPT_URL, url); | ||
210 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
211 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 60L); | ||
212 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 60L); | ||
213 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
214 | curl_easy_setopt (c, CURLOPT_FILE, &cbc); | ||
215 | |||
216 | /* TLS options */ | ||
217 | curl_easy_setopt (c, CURLOPT_SSLVERSION, proto_version); | ||
218 | curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, cipher_suite); | ||
219 | |||
220 | /* currently skip any peer authentication */ | ||
221 | curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0); | ||
222 | curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); | ||
223 | |||
224 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
225 | |||
226 | /* NOTE: use of CONNECTTIMEOUT without also | ||
227 | setting NOSIGNAL results in really weird | ||
228 | crashes on my system! */ | ||
229 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
230 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
231 | { | ||
232 | fprintf (stderr, "curl_easy_perform failed: `%s'\n", | ||
233 | curl_easy_strerror (errornum)); | ||
234 | curl_easy_cleanup (c); | ||
235 | free (cbc.buf); | ||
236 | free (mem_test_file_local); | ||
237 | free (doc_path); | ||
238 | return errornum; | ||
239 | } | ||
240 | |||
241 | curl_easy_cleanup (c); | ||
242 | |||
243 | if (memcmp (cbc.buf, mem_test_file_local, len) != 0) | ||
244 | { | ||
245 | fprintf (stderr, "Error: local file & received file differ.\n"); | ||
246 | free (cbc.buf); | ||
247 | free (mem_test_file_local); | ||
248 | free (doc_path); | ||
249 | return -1; | ||
250 | } | ||
251 | |||
252 | free (mem_test_file_local); | ||
253 | free (cbc.buf); | ||
254 | free (doc_path); | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static FILE * | ||
259 | setupTestFile () | ||
260 | { | ||
261 | FILE *test_fd; | ||
262 | |||
263 | if (NULL == (test_fd = fopen (test_file_name, "w+"))) | ||
264 | { | ||
265 | fprintf (stderr, "Error: failed to open `%s': %s\n", | ||
266 | test_file_name, strerror (errno)); | ||
267 | return NULL; | ||
268 | } | ||
269 | if (fwrite (test_file_data, sizeof (char), strlen (test_file_data), test_fd) | ||
270 | != strlen (test_file_data)) | ||
271 | { | ||
272 | fprintf (stderr, "Error: failed to write `%s. %s'\n", | ||
273 | test_file_name, strerror (errno)); | ||
274 | fclose (test_fd); | ||
275 | return NULL; | ||
276 | } | ||
277 | if (fflush (test_fd)) | ||
278 | { | ||
279 | fprintf (stderr, "Error: failed to flush test file stream. %s\n", | ||
280 | strerror (errno)); | ||
281 | fclose (test_fd); | ||
282 | return NULL; | ||
283 | } | ||
284 | |||
285 | return test_fd; | ||
286 | } | ||
287 | |||
288 | static int | ||
289 | setup (struct MHD_Daemon **d, int daemon_flags, va_list arg_list) | ||
290 | { | ||
291 | *d = MHD_start_daemon_va (daemon_flags, 42433, | ||
292 | NULL, NULL, &http_ahc, NULL, arg_list); | ||
293 | |||
294 | if (*d == NULL) | ||
295 | { | ||
296 | fprintf (stderr, MHD_E_SERVER_INIT); | ||
297 | return -1; | ||
298 | } | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static void | ||
304 | teardown (struct MHD_Daemon *d) | ||
305 | { | ||
306 | MHD_stop_daemon (d); | ||
307 | } | ||
308 | |||
309 | /* TODO test_wrap: change sig to (setup_func, test, va_list test_arg) & move to test_util.c */ | ||
310 | static int | ||
311 | test_wrap (char *test_name, int | ||
312 | (*test_function) (FILE * test_fd, char *cipher_suite, | ||
313 | int proto_version), FILE * test_fd, | ||
314 | int daemon_flags, char *cipher_suite, int proto_version, ...) | ||
315 | { | ||
316 | int ret; | ||
317 | va_list arg_list; | ||
318 | struct MHD_Daemon *d; | ||
319 | |||
320 | va_start (arg_list, proto_version); | ||
321 | if (setup (&d, daemon_flags, arg_list) != 0) | ||
322 | { | 61 | { |
323 | va_end (arg_list); | ||
324 | return -1; | 62 | return -1; |
325 | } | 63 | } |
326 | 64 | ||
327 | fprintf (stdout, "running test: %s ", test_name); | 65 | /* assert daemon *rejected* request */ |
328 | ret = test_function (test_fd, cipher_suite, proto_version); | 66 | if (CURLE_OK == |
329 | 67 | send_curl_req (url, &cbc, cipher_suite, curl_req_ssl_version)) | |
330 | if (ret == 0) | ||
331 | { | ||
332 | fprintf (stdout, "[pass]\n"); | ||
333 | } | ||
334 | else | ||
335 | { | 68 | { |
336 | fprintf (stdout, "[fail]\n"); | ||
337 | } | ||
338 | |||
339 | teardown (d); | ||
340 | va_end (arg_list); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * test server refuses to negotiate connections with unsupported protocol versions | ||
346 | * | ||
347 | */ | ||
348 | static int | ||
349 | test_protocol_version (FILE * test_fd, char *cipher_suite, | ||
350 | int curl_proto_version) | ||
351 | { | ||
352 | CURL *c; | ||
353 | CURLcode errornum; | ||
354 | |||
355 | c = curl_easy_init (); | ||
356 | #if DEBUG_CURL_VERBOSE | ||
357 | curl_easy_setopt (c, CURLOPT_VERBOSE, 1); | ||
358 | #endif | ||
359 | curl_easy_setopt (c, CURLOPT_URL, "https://localhost:42433/"); | ||
360 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
361 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 3L); | ||
362 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 3L); | ||
363 | |||
364 | /* TLS options */ | ||
365 | curl_easy_setopt (c, CURLOPT_SSLVERSION, curl_proto_version); | ||
366 | curl_easy_setopt (c, CURLOPT_SSL_CIPHER_LIST, cipher_suite); | ||
367 | |||
368 | curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0); | ||
369 | curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0); | ||
370 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
371 | |||
372 | /* NOTE: use of CONNECTTIMEOUT without also | ||
373 | setting NOSIGNAL results in really weird | ||
374 | crashes on my system! */ | ||
375 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
376 | |||
377 | /* assert daemon rejected request */ | ||
378 | if (CURLE_OK == (errornum = curl_easy_perform (c))) | ||
379 | { | ||
380 | fprintf (stderr, "curl_easy_perform failed: `%s'\n", | ||
381 | curl_easy_strerror (errornum)); | ||
382 | curl_easy_cleanup (c); | ||
383 | return -1; | 69 | return -1; |
384 | } | 70 | } |
385 | 71 | ||
@@ -403,7 +89,7 @@ main (int argc, char *const *argv) | |||
403 | return -1; | 89 | return -1; |
404 | } | 90 | } |
405 | 91 | ||
406 | if ((test_fd = setupTestFile ()) == NULL) | 92 | if ((test_fd = setup_test_file ()) == NULL) |
407 | { | 93 | { |
408 | fprintf (stderr, MHD_E_TEST_FILE_CREAT); | 94 | fprintf (stderr, MHD_E_TEST_FILE_CREAT); |
409 | return -1; | 95 | return -1; |
@@ -411,8 +97,9 @@ main (int argc, char *const *argv) | |||
411 | 97 | ||
412 | if (0 != curl_global_init (CURL_GLOBAL_ALL)) | 98 | if (0 != curl_global_init (CURL_GLOBAL_ALL)) |
413 | { | 99 | { |
414 | fprintf (stderr, "Error: %s\n", strerror (errno)); | ||
415 | fclose (test_fd); | 100 | fclose (test_fd); |
101 | remove (TEST_FILE_NAME); | ||
102 | fprintf (stderr, "Error: %s\n", strerror (errno)); | ||
416 | return -1; | 103 | return -1; |
417 | } | 104 | } |
418 | 105 | ||
@@ -422,12 +109,12 @@ main (int argc, char *const *argv) | |||
422 | MHD_GNUTLS_PROTOCOL_TLS1_0, 0 | 109 | MHD_GNUTLS_PROTOCOL_TLS1_0, 0 |
423 | }; | 110 | }; |
424 | 111 | ||
425 | struct CipherDef ciphers[] = | 112 | struct CipherDef ciphers[] = { |
426 | { {{MHD_GNUTLS_CIPHER_ARCFOUR_128, 0}, "RC4-SHA"}, | 113 | {{MHD_GNUTLS_CIPHER_AES_128_CBC, 0}, "AES128-SHA"}, |
427 | {{MHD_GNUTLS_CIPHER_3DES_CBC, 0}, "3DES-SHA"}, | 114 | {{MHD_GNUTLS_CIPHER_ARCFOUR_128, 0}, "RC4-SHA"}, |
428 | {{MHD_GNUTLS_CIPHER_AES_128_CBC, 0}, "AES128-SHA"}, | 115 | {{MHD_GNUTLS_CIPHER_3DES_CBC, 0}, "3DES-SHA"}, |
429 | {{MHD_GNUTLS_CIPHER_AES_256_CBC, 0}, "AES256-SHA"}, | 116 | {{MHD_GNUTLS_CIPHER_AES_256_CBC, 0}, "AES256-SHA"}, |
430 | {{0, 0}, NULL} | 117 | {{0, 0}, NULL} |
431 | }; | 118 | }; |
432 | 119 | ||
433 | fprintf (stderr, "SHA/TLS tests:\n"); | 120 | fprintf (stderr, "SHA/TLS tests:\n"); |
@@ -466,18 +153,15 @@ main (int argc, char *const *argv) | |||
466 | } | 153 | } |
467 | 154 | ||
468 | errorCount += | 155 | errorCount += |
469 | test_wrap ("protocol_version", &test_protocol_version, test_fd, | 156 | test_wrap ("unmatching SSL version", &test_unmatching_ssl_version, |
470 | daemon_flags, "AES256-SHA", CURL_SSLVERSION_TLSv1, | 157 | test_fd, daemon_flags, "AES256-SHA", CURL_SSLVERSION_TLSv1, |
471 | MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, | 158 | MHD_OPTION_HTTPS_MEM_KEY, srv_key_pem, |
472 | MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, | 159 | MHD_OPTION_HTTPS_MEM_CERT, srv_self_signed_cert_pem, |
473 | MHD_OPTION_PROTOCOL_VERSION, p_ssl3, MHD_OPTION_END); | 160 | MHD_OPTION_PROTOCOL_VERSION, p_ssl3, MHD_OPTION_END); |
474 | if (errorCount != 0) | ||
475 | fprintf (stderr, "Failed test: %s.\n", argv[0]); | ||
476 | 161 | ||
477 | curl_global_cleanup (); | 162 | curl_global_cleanup (); |
478 | fclose (test_fd); | 163 | fclose (test_fd); |
479 | 164 | remove (TEST_FILE_NAME); | |
480 | remove (test_file_name); | ||
481 | 165 | ||
482 | return errorCount != 0; | 166 | return errorCount != 0; |
483 | } | 167 | } |