After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 793712 - segfault on a TLS connection without private key in g_tls_connection_set_certificate()
segfault on a TLS connection without private key in g_tls_connection_set_cert...
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: network
2.54.x
Other Linux
: Normal normal
: ---
Assigned To: Michael Catanzaro
gtkdev
Depends on:
Blocks:
 
 
Reported: 2018-02-22 09:02 UTC by Martin Pitt
Modified: 2018-03-05 02:40 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
reproducer (1.87 KB, text/x-csrc)
2018-02-22 09:02 UTC, Martin Pitt
  Details
Fix crash when setting client cert without private key (7.42 KB, patch)
2018-02-26 05:09 UTC, Michael Catanzaro
none Details | Review
Add a couple garbage certificate tests (8.36 KB, patch)
2018-02-26 05:10 UTC, Michael Catanzaro
none Details | Review
Fix crash when setting client cert without private key (7.42 KB, patch)
2018-02-26 19:30 UTC, Michael Catanzaro
none Details | Review
Use gnutls_certificate_set_retrieve_function2() (22.12 KB, patch)
2018-02-26 19:30 UTC, Michael Catanzaro
none Details | Review
Add a couple garbage certificate tests (8.36 KB, patch)
2018-02-26 19:31 UTC, Michael Catanzaro
none Details | Review
Fix crash when setting client cert without private key (7.42 KB, patch)
2018-02-26 19:34 UTC, Michael Catanzaro
none Details | Review
Use gnutls_certificate_set_retrieve_function2() (22.13 KB, patch)
2018-02-26 19:34 UTC, Michael Catanzaro
none Details | Review
Add a couple garbage certificate tests (8.36 KB, patch)
2018-02-26 19:34 UTC, Michael Catanzaro
none Details | Review
Fix crash when setting client cert without private key (7.42 KB, patch)
2018-02-26 19:35 UTC, Michael Catanzaro
none Details | Review
Use gnutls_certificate_set_retrieve_function2() (22.20 KB, patch)
2018-02-26 19:35 UTC, Michael Catanzaro
none Details | Review
Add a couple garbage certificate tests (8.36 KB, patch)
2018-02-26 19:36 UTC, Michael Catanzaro
none Details | Review
Fix crash when setting client cert without private key (7.61 KB, patch)
2018-02-26 19:44 UTC, Michael Catanzaro
committed Details | Review
Use gnutls_certificate_set_retrieve_function2() (22.17 KB, patch)
2018-02-26 19:44 UTC, Michael Catanzaro
committed Details | Review
Add a couple garbage certificate tests (8.36 KB, patch)
2018-02-26 19:44 UTC, Michael Catanzaro
committed Details | Review

Description Martin Pitt 2018-02-22 09:02:18 UTC
Created attachment 368745 [details]
reproducer

Normally, g_tls_connection_set_certificate() expects a public/private key pair; if /tmp/cert-and-key.pem has both the cert and the key, things work fine:

    GTlsCertificate *cert = g_tls_certificate_new_from_file ("/tmp/cert-and-key.pem", &error);
    g_tls_connection_set_certificate (G_TLS_CONNECTION (tls_con), cert);

But when the file only contains the certificate (and they key in a separate file), one gets a crash

    GTlsCertificate *cert = g_tls_certificate_new_from_file ("/tmp/cert.pem", &error);
    g_tls_connection_set_certificate (G_TLS_CONNECTION (tls_con), cert);

Starting program: /home/martin/src/test/a.out 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[New Thread 0x7ffff52ad700 (LWP 3065)]
** Message: successfully connected
[New Thread 0x7fffef17f700 (LWP 3066)]

Thread 3 "pool" received signal SIGSEGV, Segmentation fault.

Thread 140737204713216 (LWP 3066)

  • #0 gnutls_privkey_get_pk_algorithm
    at privkey.c line 125
  • #1 _gnutls_handshake_sign_crt_vrfy
    at tls-sig.c line 609
  • #2 _gnutls_gen_cert_client_crt_vrfy
    at cert.c line 1472
  • #3 _gnutls_send_client_certificate_verify
    at kx.c line 365
  • #4 handshake_client
    at handshake.c line 2936
  • #5 gnutls_handshake
    at handshake.c line 2626
  • #6 handshake_thread
    at gtlsconnection-gnutls.c line 1258
  • #7 g_task_thread_pool_thread
    at gtask.c line 1328
  • #8 g_thread_pool_thread_proxy
    at gthreadpool.c line 307
  • #9 g_thread_proxy
    at gthread.c line 784
  • #10 start_thread
    at pthread_create.c line 465
  • #11 clone
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S line 95


I'm attaching a full reproducer; it has the correct cert-and-key line commented out, and the incorrect "only cert" line is active. It expects /tmp/cert.pem, /tmp/cert-and-key.pem, and /tmp/ca.pem to exist, and hardcodes the server to connect to, so for running it you need to adjust this accordingly.

This should rather fail with a proper GError, not simply crash.
Comment 1 Philip Withnall 2018-02-22 10:08:48 UTC
Indeed. Since certificates could be provided by users, this should be resilient to malformed/garbage input files too. This needs fuzzing (and the bug you’ve already got a backtrace for needs fixing).
Comment 2 Michael Catanzaro 2018-02-26 05:09:57 UTC
Created attachment 368917 [details] [review]
Fix crash when setting client cert without private key

If, if g_tls_client_connection_gnutls_retrieve_function, we return to
GnuTLS a gnutls_retr2_st with positive ncerts but no key, GnuTLS will
crash. GnuTLS should probably become robust to this scenario, just as it
must be robust to any manner of invalid input here. But it makes sense
for us to handle it, as well. We must abort the handshake in this case.

A new test is added that triggers this crash. Thanks to Martin Pitt for
contributing a reproducer that formed the basis for this test.
Comment 3 Michael Catanzaro 2018-02-26 05:10:04 UTC
Created attachment 368918 [details] [review]
Add a couple garbage certificate tests

Ensure that creating a GTlsCertificate using a JPEG astronaut returns
NULL.

Also ensure that a GTlsDatabase containing only a JPEG astronaut does
not permit successful certificate verification.

More such tests are possible, but these are easy and a good start.
Comment 4 Martin Pitt 2018-02-26 06:50:13 UTC
Thanks Michael, patches look great. I like the idea of throwing space themed garbage at it :-)
Comment 5 Philip Withnall 2018-02-26 10:53:44 UTC
Review of attachment 368917 [details] [review]:

From a really quick look, I can’t see any obvious problems with this.
Comment 6 Philip Withnall 2018-02-26 10:57:24 UTC
Review of attachment 368918 [details] [review]:

A couple of nitpicks.

If you put together a quick program which loads a certificate file from argv[1], you could fuzz test it using afl with these commands:

CC=afl-gcc jhbuild make -ac
mkdir -p /tmp/fuzz/input /tmp/fuzz/output
# copy a few example valid certificates which are structurally different from each other into /tmp/fuzz/input
AFL_SKIP_CPUFREQ=1 afl-fuzz -m 100 -i /tmp/fuzz/input/ -o /tmp/fuzz/output/ -f /tmp/fuzz/in.pem -- my-test-program /tmp/fuzz/in.pem
# leave it running for quite a long time (a day or two)

::: tls/tests/certificate.c
@@ +234,3 @@
+
+  cert = g_tls_certificate_new_from_file (tls_test_file_path ("garbage.pem"), &error);
+  g_assert (cert == NULL);

g_assert_null (cert);

g_assert() will be optimised out if compiled with G_DISABLE_ASSERT. g_assert_null() won’t (and will give a more informative error message).

@@ +239,3 @@
+
+  cert = g_tls_certificate_new_from_pem ("I am not a very good certificate.", -1, &error);
+  g_assert (cert == NULL);

Same.

::: tls/tests/connection.c
@@ +2088,3 @@
+  test->database = g_tls_file_database_new (tls_test_file_path ("garbage.pem"), &error);
+  g_assert_no_error (error);
+  g_assert (test->database);

g_assert_nonnull (test->database);

@@ +2093,3 @@
+  test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
+  g_assert_no_error (error);
+  g_assert (test->client_connection);

g_assert_nonnull (test->client_connection);
Comment 7 Michael Catanzaro 2018-02-26 17:15:21 UTC
(In reply to Philip Withnall from comment #6)
> Review of attachment 368918 [details] [review] [review]:
> 
> A couple of nitpicks.
> 
> If you put together a quick program which loads a certificate file from
> argv[1], you could fuzz test it using afl with these commands:
> 
> CC=afl-gcc jhbuild make -ac
> mkdir -p /tmp/fuzz/input /tmp/fuzz/output
> # copy a few example valid certificates which are structurally different
> from each other into /tmp/fuzz/input
> AFL_SKIP_CPUFREQ=1 afl-fuzz -m 100 -i /tmp/fuzz/input/ -o /tmp/fuzz/output/
> -f /tmp/fuzz/in.pem -- my-test-program /tmp/fuzz/in.pem
> # leave it running for quite a long time (a day or two)

This would be good to do, yes. If anyone wants to attempt it. ;)

> ::: tls/tests/certificate.c
> @@ +234,3 @@
> +
> +  cert = g_tls_certificate_new_from_file (tls_test_file_path
> ("garbage.pem"), &error);
> +  g_assert (cert == NULL);
> 
> g_assert_null (cert);
> 
> g_assert() will be optimised out if compiled with G_DISABLE_ASSERT.
> g_assert_null() won’t (and will give a more informative error message).

True. Let me attach a follow-up patch to change the tests to g_assert_null() and g_assert_nonnull().
Comment 8 Michael Catanzaro 2018-02-26 19:16:39 UTC
Review of attachment 368917 [details] [review]:

::: tls/gnutls/gtlsconnection-gnutls.c
@@ -656,3 @@
 
-  st->cert_type = GNUTLS_CRT_X509;
-  st->ncerts = 0;

It's actually not right to delete this, since the return value (st) would then be unusable if g_tls_connection_get_certificate() returns null, and there would be no way to detect that using st.
Comment 9 Michael Catanzaro 2018-02-26 19:30:35 UTC
(In reply to Michael Catanzaro from comment #7)
> True. Let me attach a follow-up patch to change the tests to g_assert_null()
> and g_assert_nonnull().

Reported bug #793856.
Comment 10 Michael Catanzaro 2018-02-26 19:30:54 UTC
Created attachment 368960 [details] [review]
Fix crash when setting client cert without private key

If, if g_tls_client_connection_gnutls_retrieve_function, we return to
GnuTLS a gnutls_retr2_st with positive ncerts but no key, GnuTLS will
crash. GnuTLS should probably become robust to this scenario, just as it
must be robust to any manner of invalid input here. But it makes sense
for us to handle it, as well. We must abort the handshake in this case.

A new test is added that triggers this crash. Thanks to Martin Pitt for
contributing a reproducer that formed the basis for this test.
Comment 11 Michael Catanzaro 2018-02-26 19:30:58 UTC
Created attachment 368961 [details] [review]
Use gnutls_certificate_set_retrieve_function2()

The GnuTLS manual says this is significantly more efficient than using
gnutls_certificate_set_retrieve_function(). It certainly is a bit safer.
It's easy to forget to initialize a member of the gnutls_retr2_st, but
harder to forget about function parameters.
Comment 12 Michael Catanzaro 2018-02-26 19:31:03 UTC
Created attachment 368962 [details] [review]
Add a couple garbage certificate tests

Ensure that creating a GTlsCertificate using a JPEG astronaut returns
NULL.

Also ensure that a GTlsDatabase containing only a JPEG astronaut does
not permit successful certificate verification.

More such tests are possible, but these are easy and a good start.
Comment 13 Michael Catanzaro 2018-02-26 19:34:06 UTC
Created attachment 368963 [details] [review]
Fix crash when setting client cert without private key

If, if g_tls_client_connection_gnutls_retrieve_function, we return to
GnuTLS a gnutls_retr2_st with positive ncerts but no key, GnuTLS will
crash. GnuTLS should probably become robust to this scenario, just as it
must be robust to any manner of invalid input here. But it makes sense
for us to handle it, as well. We must abort the handshake in this case.

A new test is added that triggers this crash. Thanks to Martin Pitt for
contributing a reproducer that formed the basis for this test.
Comment 14 Michael Catanzaro 2018-02-26 19:34:12 UTC
Created attachment 368964 [details] [review]
Use gnutls_certificate_set_retrieve_function2()

The GnuTLS manual says this is significantly more efficient than using
gnutls_certificate_set_retrieve_function(). It certainly is a bit safer.
It's easy to forget to initialize a member of the gnutls_retr2_st, but
harder to forget about function parameters.
Comment 15 Michael Catanzaro 2018-02-26 19:34:19 UTC
Created attachment 368965 [details] [review]
Add a couple garbage certificate tests

Ensure that creating a GTlsCertificate using a JPEG astronaut returns
NULL.

Also ensure that a GTlsDatabase containing only a JPEG astronaut does
not permit successful certificate verification.

More such tests are possible, but these are easy and a good start.
Comment 16 Michael Catanzaro 2018-02-26 19:35:49 UTC
Created attachment 368966 [details] [review]
Fix crash when setting client cert without private key

If, if g_tls_client_connection_gnutls_retrieve_function, we return to
GnuTLS a gnutls_retr2_st with positive ncerts but no key, GnuTLS will
crash. GnuTLS should probably become robust to this scenario, just as it
must be robust to any manner of invalid input here. But it makes sense
for us to handle it, as well. We must abort the handshake in this case.

A new test is added that triggers this crash. Thanks to Martin Pitt for
contributing a reproducer that formed the basis for this test.
Comment 17 Michael Catanzaro 2018-02-26 19:35:55 UTC
Created attachment 368967 [details] [review]
Use gnutls_certificate_set_retrieve_function2()

The GnuTLS manual says this is significantly more efficient than using
gnutls_certificate_set_retrieve_function(). It certainly is a bit safer.
It's easy to forget to initialize a member of the gnutls_retr2_st, but
harder to forget about function parameters.
Comment 18 Michael Catanzaro 2018-02-26 19:36:02 UTC
Created attachment 368968 [details] [review]
Add a couple garbage certificate tests

Ensure that creating a GTlsCertificate using a JPEG astronaut returns
NULL.

Also ensure that a GTlsDatabase containing only a JPEG astronaut does
not permit successful certificate verification.

More such tests are possible, but these are easy and a good start.
Comment 19 Michael Catanzaro 2018-02-26 19:37:05 UTC
GitLab's killer feature will making it a lot less obvious when I need to resubmit a patch. ;)
Comment 20 Michael Catanzaro 2018-02-26 19:40:39 UTC
Review of attachment 368966 [details] [review]:

::: tls/gnutls/gtlsconnection-gnutls.c
@@ -656,3 @@
 
-  st->cert_type = GNUTLS_CRT_X509;
-  st->ncerts = 0;

I guess I did something wrong with git, because this is still here. OK, trying again....
Comment 21 Michael Catanzaro 2018-02-26 19:44:05 UTC
Created attachment 368969 [details] [review]
Fix crash when setting client cert without private key

If, if g_tls_client_connection_gnutls_retrieve_function, we return to
GnuTLS a gnutls_retr2_st with positive ncerts but no key, GnuTLS will
crash. GnuTLS should probably become robust to this scenario, just as it
must be robust to any manner of invalid input here. But it makes sense
for us to handle it, as well. We must abort the handshake in this case.

A new test is added that triggers this crash. Thanks to Martin Pitt for
contributing a reproducer that formed the basis for this test.
Comment 22 Michael Catanzaro 2018-02-26 19:44:12 UTC
Created attachment 368970 [details] [review]
Use gnutls_certificate_set_retrieve_function2()

The GnuTLS manual says this is significantly more efficient than using
gnutls_certificate_set_retrieve_function(). It certainly is a bit safer.
It's easy to forget to initialize a member of the gnutls_retr2_st, but
harder to forget about function parameters.
Comment 23 Michael Catanzaro 2018-02-26 19:44:18 UTC
Created attachment 368971 [details] [review]
Add a couple garbage certificate tests

Ensure that creating a GTlsCertificate using a JPEG astronaut returns
NULL.

Also ensure that a GTlsDatabase containing only a JPEG astronaut does
not permit successful certificate verification.

More such tests are possible, but these are easy and a good start.
Comment 24 Michael Catanzaro 2018-03-05 02:40:25 UTC
Attachment 368969 [details] pushed as 15531b5 - Fix crash when setting client cert without private key
Attachment 368970 [details] pushed as c158d7f - Use gnutls_certificate_set_retrieve_function2()
Attachment 368971 [details] pushed as 985277a - Add a couple garbage certificate tests