1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2
3 #include "test-utils.h"
4 #include "soup-message-private.h"
5 #include "soup-server-message-private.h"
6
7 #if HAVE_GNUTLS
8 #include <gnutls/gnutls.h>
9 #include <gnutls/pkcs11.h>
10 #endif
11
12 GUri *uri;
13
14 typedef struct {
15 const char *name;
16 gboolean strict;
17 gboolean with_ca_list;
18 guint expected_status;
19 } StrictnessTest;
20
21 static const StrictnessTest strictness_tests[] = {
22 { "/ssl/strictness/strict/with-ca",
23 TRUE, TRUE, SOUP_STATUS_OK },
24 { "/ssl/strictness/strict/without-ca",
25 TRUE, FALSE, SOUP_STATUS_NONE },
26 { "/ssl/strictness/non-strict/with-ca",
27 FALSE, TRUE, SOUP_STATUS_OK },
28 { "/ssl/strictness/non-strict/without-ca",
29 FALSE, FALSE, SOUP_STATUS_OK },
30 };
31
32 static gboolean
accept_certificate(SoupMessage * msg,GTlsCertificate * certificate,GTlsCertificateFlags errors)33 accept_certificate (SoupMessage *msg,
34 GTlsCertificate *certificate,
35 GTlsCertificateFlags errors)
36 {
37 return TRUE;
38 }
39
40 static void
do_strictness_test(gconstpointer data)41 do_strictness_test (gconstpointer data)
42 {
43 const StrictnessTest *test = data;
44 SoupSession *session;
45 SoupMessage *msg;
46 GBytes *body;
47 GTlsCertificateFlags flags = 0;
48 GError *error = NULL;
49
50 SOUP_TEST_SKIP_IF_NO_TLS;
51
52 session = soup_test_session_new (NULL);
53 if (!test->with_ca_list) {
54 GTlsDatabase *tlsdb;
55
56 tlsdb = g_tls_backend_get_default_database (g_tls_backend_get_default ());
57 soup_session_set_tls_database (session, tlsdb);
58 g_object_unref (tlsdb);
59 }
60
61 msg = soup_message_new_from_uri ("GET", uri);
62 if (!test->strict) {
63 g_signal_connect (msg, "accept-certificate",
64 G_CALLBACK (accept_certificate), NULL);
65 }
66 body = soup_session_send_and_read (session, msg, NULL, &error);
67 soup_test_assert_message_status (msg, test->expected_status);
68 if (test->expected_status != SOUP_STATUS_OK)
69 g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
70
71 g_test_bug ("690176");
72 g_assert_nonnull (soup_message_get_tls_peer_certificate (msg));
73 flags = soup_message_get_tls_peer_certificate_errors (msg);
74
75 if (test->expected_status == SOUP_STATUS_OK) {
76 g_assert_cmpuint (soup_message_get_tls_protocol_version (msg), ==, G_TLS_PROTOCOL_VERSION_TLS_1_3);
77 g_assert_cmpstr (soup_message_get_tls_ciphersuite_name (msg), ==, "TLS_AES-256-GCM_SHA384");
78 } else {
79 g_assert_cmpuint (soup_message_get_tls_protocol_version (msg), ==, G_TLS_PROTOCOL_VERSION_UNKNOWN);
80 g_assert_null (soup_message_get_tls_ciphersuite_name (msg));
81 }
82
83 g_test_bug ("665182");
84 if (test->with_ca_list && !error)
85 g_assert_cmpuint (flags, ==, 0);
86 else
87 g_assert_cmpuint (flags, !=, 0);
88
89 if (soup_message_get_status (msg) == SOUP_STATUS_NONE &&
90 test->expected_status != SOUP_STATUS_NONE)
91 debug_printf (1, " tls error flags: 0x%x\n", flags);
92
93 g_clear_pointer (&body, g_bytes_unref);
94 g_clear_error (&error);
95 g_object_unref (msg);
96
97 soup_test_session_abort_unref (session);
98 }
99
100 /* GTlsInteraction subclass for do_interaction_test */
101 typedef GTlsInteraction TestTlsInteraction;
102 typedef GTlsInteractionClass TestTlsInteractionClass;
103
104 GType test_tls_interaction_get_type (void);
105
106 G_DEFINE_TYPE (TestTlsInteraction, test_tls_interaction, G_TYPE_TLS_INTERACTION);
107
108 static void
test_tls_interaction_init(TestTlsInteraction * interaction)109 test_tls_interaction_init (TestTlsInteraction *interaction)
110 {
111
112 }
113
114 static GTlsInteractionResult
test_tls_interaction_request_certificate(GTlsInteraction * interaction,GTlsConnection * connection,GTlsCertificateRequestFlags flags,GCancellable * cancellable,GError ** error)115 test_tls_interaction_request_certificate (GTlsInteraction *interaction,
116 GTlsConnection *connection,
117 GTlsCertificateRequestFlags flags,
118 GCancellable *cancellable,
119 GError **error)
120 {
121 GTlsCertificate *cert;
122
123 cert = g_object_get_data (G_OBJECT (interaction), "certificate");
124 g_tls_connection_set_certificate (connection, cert);
125
126 return G_TLS_INTERACTION_HANDLED;
127 }
128
129 static void
test_tls_interaction_class_init(TestTlsInteractionClass * klass)130 test_tls_interaction_class_init (TestTlsInteractionClass *klass)
131 {
132 GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass);
133
134 interaction_class->request_certificate = test_tls_interaction_request_certificate;
135 }
136
137
138 static gboolean
accept_client_certificate(SoupServerMessage * msg,GTlsCertificate * client_cert,GTlsCertificateFlags errors)139 accept_client_certificate (SoupServerMessage *msg,
140 GTlsCertificate *client_cert,
141 GTlsCertificateFlags errors)
142 {
143 return errors == 0;
144 }
145
146 static void
server_request_started(SoupServer * server,SoupServerMessage * msg)147 server_request_started (SoupServer *server,
148 SoupServerMessage *msg)
149 {
150 g_signal_connect (msg, "accept-certificate",
151 G_CALLBACK (accept_client_certificate),
152 NULL);
153 }
154
155 static void
do_tls_interaction_test(gconstpointer data)156 do_tls_interaction_test (gconstpointer data)
157 {
158 SoupServer *server = (SoupServer *)data;
159 SoupSession *session;
160 SoupMessage *msg;
161 GBytes *body;
162 GTlsDatabase *tls_db;
163 GTlsCertificate *certificate;
164 GTlsInteraction *interaction;
165 GError *error = NULL;
166
167 SOUP_TEST_SKIP_IF_NO_TLS;
168
169 session = soup_test_session_new (NULL);
170 tls_db = soup_session_get_tls_database (session);
171 g_object_set (server, "tls-database", tls_db, "tls-auth-mode", G_TLS_AUTHENTICATION_REQUIRED, NULL);
172
173 g_signal_connect (server, "request-started",
174 G_CALLBACK (server_request_started),
175 session);
176
177 /* Without a GTlsInteraction */
178 msg = soup_message_new_from_uri ("GET", uri);
179 body = soup_test_session_async_send (session, msg, NULL, &error);
180 /* Sometimes glib-networking fails to report the error as certificate required
181 * and we end up with connection reset by peer because the server closes the connection
182 */
183 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
184 g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
185 g_clear_error (&error);
186 g_bytes_unref (body);
187 g_object_unref (msg);
188
189 interaction = g_object_new (test_tls_interaction_get_type (), NULL);
190 /* Yes, we use the same certificate for the client as for the server. Shrug */
191 g_object_get (server, "tls-certificate", &certificate, NULL);
192 g_object_set_data_full (G_OBJECT (interaction),
193 "certificate",
194 g_object_ref (certificate),
195 g_object_unref);
196 soup_session_set_tls_interaction (session, interaction);
197 g_object_unref (interaction);
198
199 /* With a GTlsInteraction */
200 msg = soup_message_new_from_uri ("GET", uri);
201 body = soup_test_session_async_send (session, msg, NULL, &error);
202 g_assert_no_error (error);
203 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
204 g_assert_nonnull (soup_message_get_tls_peer_certificate (msg));
205 g_bytes_unref (body);
206 g_object_unref (msg);
207
208 g_object_set (server, "tls-database", NULL, "tls-auth-mode", G_TLS_AUTHENTICATION_NONE, NULL);
209 g_signal_handlers_disconnect_by_data (server, session);
210
211 soup_test_session_abort_unref (session);
212 g_object_unref (certificate);
213 }
214
215 static gboolean
request_certificate_cb(SoupMessage * msg,GTlsClientConnection * conn,GTlsCertificate * certificate)216 request_certificate_cb (SoupMessage *msg,
217 GTlsClientConnection *conn,
218 GTlsCertificate *certificate)
219 {
220 soup_message_set_tls_client_certificate (msg, certificate);
221
222 return TRUE;
223 }
224
225 static gboolean
request_certificate_password_cb(SoupMessage * msg,GTlsPassword * tls_password,const guchar * password)226 request_certificate_password_cb (SoupMessage *msg,
227 GTlsPassword *tls_password,
228 const guchar *password)
229 {
230 g_tls_password_set_value (tls_password, password, -1);
231 soup_message_tls_client_certificate_password_request_complete (msg);
232
233 return TRUE;
234 }
235
236 typedef struct {
237 SoupMessage *msg;
238 GTlsCertificate *certificate;
239 GTlsPassword *tls_password;
240 const guchar *password;
241 } SetCertificateAsyncData;
242
243 static void
set_certificate_async_data_free(SetCertificateAsyncData * data)244 set_certificate_async_data_free (SetCertificateAsyncData *data)
245 {
246 g_clear_object (&data->tls_password);
247 g_free (data);
248 }
249
250 static gboolean
set_certificate_idle_cb(SetCertificateAsyncData * data)251 set_certificate_idle_cb (SetCertificateAsyncData *data)
252 {
253 soup_message_set_tls_client_certificate (data->msg, data->certificate);
254
255 return FALSE;
256 }
257
258 static gboolean
request_certificate_async_cb(SoupMessage * msg,GTlsClientConnection * conn,GTlsCertificate * certificate)259 request_certificate_async_cb (SoupMessage *msg,
260 GTlsClientConnection *conn,
261 GTlsCertificate *certificate)
262 {
263 SetCertificateAsyncData *data;
264
265 data = g_new0 (SetCertificateAsyncData, 1);
266 data->msg = msg;
267 data->certificate = certificate;
268 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
269 (GSourceFunc)set_certificate_idle_cb,
270 data,
271 (GDestroyNotify)set_certificate_async_data_free);
272
273 return TRUE;
274 }
275
276 static gboolean
set_certificate_password_idle_cb(SetCertificateAsyncData * data)277 set_certificate_password_idle_cb (SetCertificateAsyncData *data)
278 {
279 g_tls_password_set_value (data->tls_password, data->password, -1);
280 soup_message_tls_client_certificate_password_request_complete (data->msg);
281
282 return FALSE;
283 }
284
285 static gboolean
request_certificate_password_async_cb(SoupMessage * msg,GTlsPassword * password,const guchar * pin)286 request_certificate_password_async_cb (SoupMessage *msg,
287 GTlsPassword *password,
288 const guchar *pin)
289 {
290 SetCertificateAsyncData *data;
291
292 data = g_new (SetCertificateAsyncData, 1);
293 data->msg = msg;
294 data->tls_password = g_object_ref (password);
295 data->password = pin;
296 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
297 (GSourceFunc)set_certificate_password_idle_cb,
298 data,
299 (GDestroyNotify)set_certificate_async_data_free);
300
301 return TRUE;
302 }
303
304 static void
do_tls_interaction_msg_test(gconstpointer data)305 do_tls_interaction_msg_test (gconstpointer data)
306 {
307 SoupServer *server = (SoupServer *)data;
308 SoupSession *session;
309 SoupMessage *msg;
310 GBytes *body;
311 GTlsDatabase *tls_db;
312 GTlsCertificate *certificate, *wrong_certificate;
313 GError *error = NULL;
314
315 SOUP_TEST_SKIP_IF_NO_TLS;
316
317 session = soup_test_session_new (NULL);
318 tls_db = soup_session_get_tls_database (session);
319 g_object_set (server, "tls-database", tls_db, "tls-auth-mode", G_TLS_AUTHENTICATION_REQUIRED, NULL);
320
321 g_signal_connect (server, "request-started",
322 G_CALLBACK (server_request_started),
323 session);
324
325 /* Not handling request-certificate signal */
326 msg = soup_message_new_from_uri ("GET", uri);
327 body = soup_test_session_async_send (session, msg, NULL, &error);
328 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
329 g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
330 g_clear_error (&error);
331 g_bytes_unref (body);
332 g_object_unref (msg);
333
334 /* Handling the request-certificate signal synchronously */
335 g_object_get (server, "tls-certificate", &certificate, NULL);
336 g_assert_nonnull (certificate);
337 msg = soup_message_new_from_uri ("GET", uri);
338 g_signal_connect (msg, "request-certificate",
339 G_CALLBACK (request_certificate_cb),
340 certificate);
341 body = soup_test_session_async_send (session, msg, NULL, &error);
342 g_assert_no_error (error);
343 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
344 g_clear_error (&error);
345 g_bytes_unref (body);
346 g_object_unref (msg);
347
348 /* Next load doesn't emit request-certificate because the connection is reused */
349 msg = soup_message_new_from_uri ("GET", uri);
350 body = soup_test_session_async_send (session, msg, NULL, &error);
351 g_assert_no_error (error);
352 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
353 g_clear_error (&error);
354 g_bytes_unref (body);
355 g_object_unref (msg);
356
357 /* It fails for a new connection */
358 msg = soup_message_new_from_uri ("GET", uri);
359 soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
360 body = soup_test_session_async_send (session, msg, NULL, &error);
361 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
362 g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
363 g_clear_error (&error);
364 g_bytes_unref (body);
365 g_object_unref (msg);
366
367 /* Using the wrong certificate fails */
368 wrong_certificate = g_tls_certificate_new_from_files (
369 g_test_get_filename (G_TEST_DIST, "test-cert-2.pem", NULL),
370 g_test_get_filename (G_TEST_DIST, "test-key-2.pem", NULL),
371 NULL
372 );
373 g_assert_nonnull (wrong_certificate);
374 msg = soup_message_new_from_uri ("GET", uri);
375 soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
376 g_signal_connect (msg, "request-certificate",
377 G_CALLBACK (request_certificate_cb),
378 wrong_certificate);
379 body = soup_test_session_async_send (session, msg, NULL, &error);
380 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
381 g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
382 g_assert_null (body);
383 g_clear_error (&error);
384 g_object_unref (msg);
385
386 /* Passing NULL certificate fails */
387 msg = soup_message_new_from_uri ("GET", uri);
388 soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
389 g_signal_connect (msg, "request-certificate",
390 G_CALLBACK (request_certificate_cb),
391 NULL);
392 body = soup_test_session_async_send (session, msg, NULL, &error);
393 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
394 g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
395 g_clear_error (&error);
396 g_bytes_unref (body);
397 g_object_unref (msg);
398
399 /* request-certificate is not emitted if the certificate is set before the load */
400 msg = soup_message_new_from_uri ("GET", uri);
401 soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
402 soup_message_set_tls_client_certificate (msg, certificate);
403 body = soup_test_session_async_send (session, msg, NULL, &error);
404 g_assert_no_error (error);
405 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
406 g_clear_error (&error);
407 g_bytes_unref (body);
408 g_object_unref (msg);
409
410 /* Handling the request-certificate signal asynchronously */
411 msg = soup_message_new_from_uri ("GET", uri);
412 soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
413 g_signal_connect (msg, "request-certificate",
414 G_CALLBACK (request_certificate_async_cb),
415 certificate);
416 body = soup_test_session_async_send (session, msg, NULL, &error);
417 g_assert_no_error (error);
418 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
419 g_clear_error (&error);
420 g_bytes_unref (body);
421 g_object_unref (msg);
422
423 /* Using the wrong certificate fails */
424 msg = soup_message_new_from_uri ("GET", uri);
425 soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
426 g_signal_connect (msg, "request-certificate",
427 G_CALLBACK (request_certificate_async_cb),
428 wrong_certificate);
429 body = soup_test_session_async_send (session, msg, NULL, &error);
430 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
431 g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
432 g_assert_null (body);
433 g_clear_error (&error);
434 g_object_unref (msg);
435
436 /* Passing NULL certificate fails */
437 msg = soup_message_new_from_uri ("GET", uri);
438 soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
439 g_signal_connect (msg, "request-certificate",
440 G_CALLBACK (request_certificate_async_cb),
441 NULL);
442 body = soup_test_session_async_send (session, msg, NULL, &error);
443 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_CLOSED))
444 g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
445 g_assert_null (body);
446 g_clear_error (&error);
447 g_object_unref (msg);
448
449 /* Currently on the gnutls backend supports pkcs#11 */
450 if (g_strcmp0 (g_type_name (G_TYPE_FROM_INSTANCE (g_tls_backend_get_default ())), "GTlsBackendGnutls") == 0) {
451 g_test_message ("Running PKCS#11 tests");
452
453 /* Using PKCS#11 works, and asks for a PIN */
454 GTlsCertificate *pkcs11_certificate = g_tls_certificate_new_from_pkcs11_uris (
455 "pkcs11:model=mock;serial=1;token=Mock%20Certificate;id=%4D%6F%63%6B%20%43%65%72%74%69%66%69%63%61%74%65;object=Mock%20Certificate;type=cert",
456 "pkcs11:model=mock;serial=1;token=Mock%20Certificate;id=%4D%6F%63%6B%20%50%72%69%76%61%74%65%20%4B%65%79;object=Mock%20Private%20Key;type=private",
457 &error
458 );
459 g_assert_no_error (error);
460 g_assert_nonnull (pkcs11_certificate);
461 g_assert_true (G_IS_TLS_CERTIFICATE (pkcs11_certificate));
462 msg = soup_message_new_from_uri ("GET", uri);
463 soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
464 g_signal_connect (msg, "request-certificate",
465 G_CALLBACK (request_certificate_cb),
466 pkcs11_certificate);
467 g_signal_connect (msg, "request-certificate-password",
468 G_CALLBACK (request_certificate_password_cb),
469 "ABC123");
470 body = soup_test_session_async_send (session, msg, NULL, &error);
471 g_assert_no_error (error);
472 g_clear_error (&error);
473 g_bytes_unref (body);
474 g_object_unref (msg);
475
476 #if GLIB_CHECK_VERSION (2, 69, 1)
477 /* glib-networking issue fixed by https://gitlab.gnome.org/GNOME/glib-networking/-/commit/362fb43a5a4816f0706569ac57e645f20eac34ca */
478 /* It should safely fail when the PIN is unhandled */
479 msg = soup_message_new_from_uri ("GET", uri);
480 soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
481 g_signal_connect (msg, "request-certificate",
482 G_CALLBACK (request_certificate_cb),
483 pkcs11_certificate);
484 body = soup_test_session_async_send (session, msg, NULL, &error);
485 g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
486 g_clear_error (&error);
487 g_bytes_unref (body);
488 g_object_unref (msg);
489 #endif
490
491 /* Handling the request-certificate-password signal asynchronously */
492 msg = soup_message_new_from_uri ("GET", uri);
493 soup_message_add_flags (msg, SOUP_MESSAGE_NEW_CONNECTION);
494 g_signal_connect (msg, "request-certificate",
495 G_CALLBACK (request_certificate_async_cb),
496 pkcs11_certificate);
497 g_signal_connect (msg, "request-certificate-password",
498 G_CALLBACK (request_certificate_password_async_cb),
499 "ABC123");
500 body = soup_test_session_async_send (session, msg, NULL, &error);
501 g_assert_no_error (error);
502 g_clear_error (&error);
503 g_bytes_unref (body);
504 g_object_unref (msg);
505
506 g_object_unref (pkcs11_certificate);
507 }
508
509 g_object_set (server, "tls-database", NULL, "tls-auth-mode", G_TLS_AUTHENTICATION_NONE, NULL);
510 g_signal_handlers_disconnect_by_data (server, session);
511
512 soup_test_session_abort_unref (session);
513 g_object_unref (certificate);
514 g_object_unref (wrong_certificate);
515 }
516
517 static gboolean
preconnect_request_certificate(SoupMessage * msg,GTlsClientConnection * conn,gboolean * called)518 preconnect_request_certificate (SoupMessage *msg,
519 GTlsClientConnection *conn,
520 gboolean *called)
521 {
522 *called = TRUE;
523
524 return FALSE;
525 }
526
527 static gboolean
preconnect_request_certificate_password(SoupMessage * msg,GTlsPassword * password,gboolean * called)528 preconnect_request_certificate_password (SoupMessage *msg,
529 GTlsPassword *password,
530 gboolean *called)
531 {
532 *called = TRUE;
533
534 return FALSE;
535 }
536
537 static void
preconnect_finished_cb(SoupSession * session,GAsyncResult * result,gboolean * preconnect_finished)538 preconnect_finished_cb (SoupSession *session,
539 GAsyncResult *result,
540 gboolean *preconnect_finished)
541 {
542 g_assert_true (soup_session_preconnect_finish (session, result, NULL));
543 *preconnect_finished = TRUE;
544 }
545
546 static void
do_tls_interaction_preconnect_test(gconstpointer data)547 do_tls_interaction_preconnect_test (gconstpointer data)
548 {
549 SoupServer *server = (SoupServer *)data;
550 SoupSession *session;
551 SoupMessage *preconnect_msg;
552 SoupMessage *msg;
553 GBytes *body;
554 GTlsDatabase *tls_db;
555 GTlsCertificate *certificate;
556 GError *error = NULL;
557 gboolean preconnect_request_cert_called = FALSE;
558 gboolean preconnect_request_cert_pass_called = FALSE;
559 gboolean preconnect_finished = FALSE;
560
561 SOUP_TEST_SKIP_IF_NO_TLS;
562
563 session = soup_test_session_new (NULL);
564 tls_db = soup_session_get_tls_database (session);
565 g_object_set (server, "tls-database", tls_db, "tls-auth-mode", G_TLS_AUTHENTICATION_REQUIRED, NULL);
566 g_object_get (server, "tls-certificate", &certificate, NULL);
567 g_signal_connect (server, "request-started",
568 G_CALLBACK (server_request_started),
569 session);
570
571 /* Start a preconnect until it get blocked on tls interaction */
572 preconnect_msg = soup_message_new_from_uri ("HEAD", uri);
573 g_signal_connect (preconnect_msg, "request-certificate",
574 G_CALLBACK (preconnect_request_certificate),
575 &preconnect_request_cert_called);
576 soup_session_preconnect_async (session, preconnect_msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
577 while (!soup_message_has_pending_tls_cert_request (preconnect_msg))
578 g_main_context_iteration (NULL, TRUE);
579
580 /* New message should steal the preconnect connection */
581 msg = soup_message_new_from_uri ("GET", uri);
582 g_signal_connect (msg, "request-certificate",
583 G_CALLBACK (request_certificate_cb),
584 certificate);
585 body = soup_test_session_async_send (session, msg, NULL, &error);
586 g_assert_no_error (error);
587 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
588 g_assert_false (preconnect_request_cert_called);
589 g_clear_error (&error);
590 g_bytes_unref (body);
591 g_object_unref (msg);
592 g_object_unref (preconnect_msg);
593
594 soup_session_abort (session);
595
596 /* Preconnect finishes if we set the certificate before */
597 preconnect_msg = soup_message_new_from_uri ("HEAD", uri);
598 g_signal_connect (preconnect_msg, "request-certificate",
599 G_CALLBACK (preconnect_request_certificate),
600 &preconnect_request_cert_called);
601 soup_message_set_tls_client_certificate (preconnect_msg, certificate);
602 soup_session_preconnect_async (session, preconnect_msg, G_PRIORITY_DEFAULT, NULL,
603 (GAsyncReadyCallback)preconnect_finished_cb,
604 &preconnect_finished);
605 while (!preconnect_finished)
606 g_main_context_iteration (NULL, TRUE);
607 g_assert_false (preconnect_request_cert_called);
608 g_object_unref (preconnect_msg);
609 /* New request will use the idle connection without having to provide a certificate */
610 msg = soup_message_new_from_uri ("GET", uri);
611 body = soup_test_session_async_send (session, msg, NULL, &error);
612 g_assert_no_error (error);
613 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
614 g_clear_error (&error);
615 g_bytes_unref (body);
616 g_object_unref (msg);
617
618 soup_session_abort (session);
619
620 /* request-certificate signal is not emitted either if the message stealing the
621 * preconnect connection has a certificate set.
622 */
623 preconnect_msg = soup_message_new_from_uri ("HEAD", uri);
624 g_signal_connect (preconnect_msg, "request-certificate",
625 G_CALLBACK (preconnect_request_certificate),
626 &preconnect_request_cert_called);
627 soup_session_preconnect_async (session, preconnect_msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
628 while (!soup_message_has_pending_tls_cert_request (preconnect_msg))
629 g_main_context_iteration (NULL, TRUE);
630
631 /* New message should steal the preconnect connection */
632 msg = soup_message_new_from_uri ("GET", uri);
633 soup_message_set_tls_client_certificate (msg, certificate);
634 body = soup_test_session_async_send (session, msg, NULL, &error);
635 g_assert_no_error (error);
636 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
637 g_assert_false (preconnect_request_cert_called);
638 g_clear_error (&error);
639 g_bytes_unref (body);
640 g_object_unref (msg);
641 g_object_unref (preconnect_msg);
642
643 soup_session_abort (session);
644
645 /* Currently on the gnutls backend supports pkcs#11 */
646 if (g_strcmp0 (g_type_name (G_TYPE_FROM_INSTANCE (g_tls_backend_get_default ())), "GTlsBackendGnutls") == 0) {
647 GTlsCertificate *pkcs11_certificate;
648
649 pkcs11_certificate = g_tls_certificate_new_from_pkcs11_uris (
650 "pkcs11:model=mock;serial=1;token=Mock%20Certificate;id=%4D%6F%63%6B%20%43%65%72%74%69%66%69%63%61%74%65;object=Mock%20Certificate;type=cert",
651 "pkcs11:model=mock;serial=1;token=Mock%20Certificate;id=%4D%6F%63%6B%20%50%72%69%76%61%74%65%20%4B%65%79;object=Mock%20Private%20Key;type=private",
652 &error
653 );
654 g_assert_no_error (error);
655
656 preconnect_msg = soup_message_new_from_uri ("HEAD", uri);
657 g_signal_connect (preconnect_msg, "request-certificate-password",
658 G_CALLBACK (preconnect_request_certificate_password),
659 &preconnect_request_cert_pass_called);
660 soup_message_set_tls_client_certificate (preconnect_msg, pkcs11_certificate);
661 soup_session_preconnect_async (session, preconnect_msg, G_PRIORITY_DEFAULT, NULL, NULL, NULL);
662 while (!soup_message_has_pending_tls_cert_pass_request (preconnect_msg))
663 g_main_context_iteration (NULL, TRUE);
664
665 /* New message should steal the preconnect connection */
666 msg = soup_message_new_from_uri ("GET", uri);
667 g_signal_connect (msg, "request-certificate-password",
668 G_CALLBACK (request_certificate_password_cb),
669 "ABC123");
670 body = soup_test_session_async_send (session, msg, NULL, &error);
671 g_assert_no_error (error);
672 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
673 g_assert_false (preconnect_request_cert_pass_called);
674 g_clear_error (&error);
675 g_bytes_unref (body);
676 g_object_unref (msg);
677 g_object_unref (preconnect_msg);
678
679 g_object_unref (pkcs11_certificate);
680 }
681
682 g_object_set (server, "tls-database", NULL, "tls-auth-mode", G_TLS_AUTHENTICATION_NONE, NULL);
683 g_signal_handlers_disconnect_by_data (server, session);
684
685 soup_test_session_abort_unref (session);
686 g_object_unref (certificate);
687 }
688
689 static void
server_handler(SoupServer * server,SoupServerMessage * msg,const char * path,GHashTable * query,gpointer user_data)690 server_handler (SoupServer *server,
691 SoupServerMessage *msg,
692 const char *path,
693 GHashTable *query,
694 gpointer user_data)
695 {
696 soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
697 soup_server_message_set_response (msg, "text/plain",
698 SOUP_MEMORY_STATIC,
699 "ok\r\n", 4);
700 }
701
702 int
main(int argc,char ** argv)703 main (int argc, char **argv)
704 {
705 SoupServer *server = NULL;
706 int i, ret;
707
708 test_init (argc, argv, NULL);
709
710 #if HAVE_GNUTLS
711 char *module_path = soup_test_build_filename_abs (G_TEST_BUILT, "mock-pkcs11.so", NULL);
712 g_assert_true (g_file_test (module_path, G_FILE_TEST_EXISTS));
713
714 g_assert (gnutls_pkcs11_init (GNUTLS_PKCS11_FLAG_MANUAL, NULL) == GNUTLS_E_SUCCESS);
715 g_assert (gnutls_pkcs11_add_provider (module_path, NULL) == GNUTLS_E_SUCCESS);
716 g_free (module_path);
717 #endif
718
719 if (tls_available) {
720 server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
721 soup_server_add_handler (server, NULL, server_handler, NULL, NULL);
722 uri = soup_test_server_get_uri (server, "https", "127.0.0.1");
723 } else
724 uri = NULL;
725
726 g_test_add_data_func ("/ssl/tls-interaction", server, do_tls_interaction_test);
727 g_test_add_data_func ("/ssl/tls-interaction-msg", server, do_tls_interaction_msg_test);
728 g_test_add_data_func ("/ssl/tls-interaction/preconnect", server, do_tls_interaction_preconnect_test);
729
730 for (i = 0; i < G_N_ELEMENTS (strictness_tests); i++) {
731 g_test_add_data_func (strictness_tests[i].name,
732 &strictness_tests[i],
733 do_strictness_test);
734 }
735
736 ret = g_test_run ();
737
738 if (tls_available) {
739 g_uri_unref (uri);
740 soup_test_server_quit_unref (server);
741 }
742
743 test_cleanup ();
744 return ret;
745 }
746