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