glib/gio/tests/tls-certificate.c
Michael Catanzaro d58e5de9e9 Revert "gtlscertificate: Add support for PKCS #11 backed certificates"
This reverts commit b6d8efbebc.

This GLib API is good, but the implentation is not ready, so there's no
reason to commit to the API in GLib 2.64. We can reland again when the
implementation is ready.

There are three problems: (a) The glib-networking implementation normally
works, but the test has been broken for a long time. I'm not comfortable
with adding a major new feature without a working test. This is
glib-networking#104. (b) The WebKit implementation never landed. There
is a working patch, but it hasn't been accepted upstream yet. This API
isn't needed in GLib until WebKit is ready to start using it.
https://bugs.webkit.org/show_bug.cgi?id=200805. (c) Similarly, even if
the WebKit API was ready, that itself isn't useful until an application
is ready to start using it, and the Epiphany level work never happened.

Let's try again for GLib 2.66. Reverting this commit now just means we
gain another six months before committing to the API forever. No reason
to keep this in GLib 2.64 when nothing is using it yet.
2020-01-30 04:19:22 -06:00

480 lines
16 KiB
C

/* GLib testing framework examples and tests
*
* Copyright (C) 2011 Collabora Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
*/
#include "config.h"
#include <gio/gio.h>
#include "gtesttlsbackend.h"
typedef struct
{
gchar *cert_pems[3];
gchar *cert_crlf_pem;
gchar *key_pem;
gchar *key_crlf_pem;
gchar *key8_pem;
} Reference;
static void
pem_parser (const Reference *ref)
{
GTlsCertificate *cert;
gchar *pem;
gsize pem_len = 0;
gchar *parsed_cert_pem = NULL;
const gchar *parsed_key_pem = NULL;
GError *error = NULL;
/* Check PEM parsing in certificate, private key order. */
g_file_get_contents (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert-key.pem", NULL), &pem, &pem_len, &error);
g_assert_no_error (error);
g_assert_nonnull (pem);
g_assert_cmpuint (pem_len, >=, 10);
cert = g_tls_certificate_new_from_pem (pem, -1, &error);
g_assert_no_error (error);
g_assert_nonnull (cert);
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
parsed_key_pem = g_test_tls_connection_get_private_key_pem (cert);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_pems[0]);
g_free (parsed_cert_pem);
parsed_cert_pem = NULL;
g_assert_cmpstr (parsed_key_pem, ==, ref->key_pem);
parsed_key_pem = NULL;
g_object_unref (cert);
/* Make sure length is respected and parser detect invalid PEM
* when cert is truncated. */
cert = g_tls_certificate_new_from_pem (pem, 10, &error);
g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
g_clear_error (&error);
/* Make sure length is respected and parser detect invalid PEM
* when cert exists but key is truncated. */
cert = g_tls_certificate_new_from_pem (pem, pem_len - 10, &error);
g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
g_clear_error (&error);
g_free (pem);
/* Check PEM parsing in private key, certificate order */
g_file_get_contents (g_test_get_filename (G_TEST_DIST, "cert-tests", "key-cert.pem", NULL), &pem, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (pem);
cert = g_tls_certificate_new_from_pem (pem, -1, &error);
g_assert_no_error (error);
g_assert_nonnull (cert);
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
parsed_key_pem = g_test_tls_connection_get_private_key_pem (cert);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_pems[0]);
g_free (parsed_cert_pem);
parsed_cert_pem = NULL;
g_assert_cmpstr (parsed_key_pem, ==, ref->key_pem);
parsed_key_pem = NULL;
g_free (pem);
g_object_unref (cert);
/* Check certificate only PEM */
g_file_get_contents (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert1.pem", NULL), &pem, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (pem);
cert = g_tls_certificate_new_from_pem (pem, -1, &error);
g_assert_no_error (error);
g_assert_nonnull (cert);
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
parsed_key_pem = g_test_tls_connection_get_private_key_pem (cert);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_pems[0]);
g_free (parsed_cert_pem);
parsed_cert_pem = NULL;
g_assert_null (parsed_key_pem);
g_free (pem);
g_object_unref (cert);
/* Check error with private key only PEM */
g_file_get_contents (g_test_get_filename (G_TEST_DIST, "cert-tests", "key.pem", NULL), &pem, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (pem);
cert = g_tls_certificate_new_from_pem (pem, -1, &error);
g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
g_clear_error (&error);
g_assert_null (cert);
g_free (pem);
}
static void
pem_parser_handles_chain (const Reference *ref)
{
GTlsCertificate *cert;
GTlsCertificate *issuer;
GTlsCertificate *original_cert;
gchar *pem;
gchar *parsed_cert_pem = NULL;
const gchar *parsed_key_pem = NULL;
GError *error = NULL;
/* Check that a chain with exactly three certificates is returned */
g_file_get_contents (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert-list.pem", NULL), &pem, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (pem);
cert = original_cert = g_tls_certificate_new_from_pem (pem, -1, &error);
g_free (pem);
g_assert_no_error (error);
g_assert_nonnull (cert);
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_pems[0]);
g_clear_pointer (&parsed_cert_pem, g_free);
/* Make sure the private key was parsed */
parsed_key_pem = g_test_tls_connection_get_private_key_pem (cert);
g_assert_cmpstr (parsed_key_pem, ==, ref->key_pem);
parsed_key_pem = NULL;
/* Now test the second cert */
issuer = g_tls_certificate_get_issuer (cert);
g_assert_nonnull (issuer);
cert = issuer;
issuer = g_tls_certificate_get_issuer (cert);
g_assert_nonnull (issuer);
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_pems[1]);
g_clear_pointer (&parsed_cert_pem, g_free);
/* Only the first cert should have a private key */
parsed_key_pem = g_test_tls_connection_get_private_key_pem (cert);
g_assert_null (parsed_key_pem);
/* Now test the final cert */
cert = issuer;
issuer = g_tls_certificate_get_issuer (cert);
g_assert_null (issuer);
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_pems[2]);
g_clear_pointer (&parsed_cert_pem, g_free);
parsed_key_pem = g_test_tls_connection_get_private_key_pem (cert);
g_assert_null (parsed_key_pem);
g_object_unref (original_cert);
}
static void
from_file (const Reference *ref)
{
GTlsCertificate *cert;
gchar *parsed_cert_pem = NULL;
const gchar *parsed_key_pem = NULL;
GError *error = NULL;
cert = g_tls_certificate_new_from_file (g_test_get_filename (G_TEST_DIST, "cert-tests", "key-cert.pem", NULL),
&error);
g_assert_no_error (error);
g_assert_nonnull (cert);
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
parsed_key_pem = g_test_tls_connection_get_private_key_pem (cert);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_pems[0]);
g_free (parsed_cert_pem);
parsed_cert_pem = NULL;
g_assert_cmpstr (parsed_key_pem, ==, ref->key_pem);
parsed_key_pem = NULL;
g_object_unref (cert);
}
static void
from_files (const Reference *ref)
{
GTlsCertificate *cert;
gchar *parsed_cert_pem = NULL;
const gchar *parsed_key_pem = NULL;
GError *error = NULL;
cert = g_tls_certificate_new_from_files (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert1.pem", NULL),
g_test_get_filename (G_TEST_DIST, "cert-tests", "key.pem", NULL),
&error);
g_assert_no_error (error);
g_assert_nonnull (cert);
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
parsed_key_pem = g_test_tls_connection_get_private_key_pem (cert);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_pems[0]);
g_free (parsed_cert_pem);
parsed_cert_pem = NULL;
g_assert_cmpstr (parsed_key_pem, ==, ref->key_pem);
parsed_key_pem = NULL;
g_object_unref (cert);
/* Missing private key */
cert = g_tls_certificate_new_from_files (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert1.pem", NULL),
g_test_get_filename (G_TEST_DIST, "cert-tests", "cert2.pem", NULL),
&error);
g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
g_clear_error (&error);
g_assert_null (cert);
/* Missing header private key */
cert = g_tls_certificate_new_from_files (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert1.pem", NULL),
g_test_get_filename (G_TEST_DIST, "cert-tests", "key_missing-header.pem", NULL),
&error);
g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
g_clear_error (&error);
g_assert_null (cert);
/* Missing footer private key */
cert = g_tls_certificate_new_from_files (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert1.pem", NULL),
g_test_get_filename (G_TEST_DIST, "cert-tests", "key_missing-footer.pem", NULL),
&error);
g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
g_clear_error (&error);
g_assert_null (cert);
/* Missing certificate */
cert = g_tls_certificate_new_from_files (g_test_get_filename (G_TEST_DIST, "cert-tests", "key.pem", NULL),
g_test_get_filename (G_TEST_DIST, "cert-tests", "key.pem", NULL),
&error);
g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
g_clear_error (&error);
g_assert_null (cert);
/* Using this method twice with a file containing both private key and
* certificate as a way to inforce private key presence is a fair use
*/
cert = g_tls_certificate_new_from_files (g_test_get_filename (G_TEST_DIST, "cert-tests", "key-cert.pem", NULL),
g_test_get_filename (G_TEST_DIST, "cert-tests", "key-cert.pem", NULL),
&error);
g_assert_no_error (error);
g_assert_nonnull (cert);
g_object_unref (cert);
}
static void
from_files_crlf (const Reference *ref)
{
GTlsCertificate *cert;
gchar *parsed_cert_pem = NULL;
const gchar *parsed_key_pem = NULL;
GError *error = NULL;
cert = g_tls_certificate_new_from_files (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert-crlf.pem", NULL),
g_test_get_filename (G_TEST_DIST, "cert-tests", "key-crlf.pem", NULL),
&error);
g_assert_no_error (error);
g_assert_nonnull (cert);
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
parsed_key_pem = g_test_tls_connection_get_private_key_pem (cert);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_crlf_pem);
g_free (parsed_cert_pem);
parsed_cert_pem = NULL;
g_assert_cmpstr (parsed_key_pem, ==, ref->key_crlf_pem);
parsed_key_pem = NULL;
g_object_unref (cert);
}
static void
from_files_pkcs8 (const Reference *ref)
{
GTlsCertificate *cert;
gchar *parsed_cert_pem = NULL;
const gchar *parsed_key_pem = NULL;
GError *error = NULL;
cert = g_tls_certificate_new_from_files (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert1.pem", NULL),
g_test_get_filename (G_TEST_DIST, "cert-tests", "key8.pem", NULL),
&error);
g_assert_no_error (error);
g_assert_nonnull (cert);
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
parsed_key_pem = g_test_tls_connection_get_private_key_pem (cert);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_pems[0]);
g_free (parsed_cert_pem);
parsed_cert_pem = NULL;
g_assert_cmpstr (parsed_key_pem, ==, ref->key8_pem);
parsed_key_pem = NULL;
g_object_unref (cert);
}
static void
from_files_pkcs8enc (const Reference *ref)
{
GTlsCertificate *cert;
GError *error = NULL;
/* Mare sure an error is returned for encrypted key */
cert = g_tls_certificate_new_from_files (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert1.pem", NULL),
g_test_get_filename (G_TEST_DIST, "cert-tests", "key8enc.pem", NULL),
&error);
g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
g_clear_error (&error);
g_assert_null (cert);
}
static void
list_from_file (const Reference *ref)
{
GList *list, *l;
GError *error = NULL;
int i;
list = g_tls_certificate_list_new_from_file (g_test_get_filename (G_TEST_DIST, "cert-tests", "cert-list.pem", NULL),
&error);
g_assert_no_error (error);
g_assert_cmpint (g_list_length (list), ==, 3);
l = list;
for (i = 0; i < 3; i++)
{
GTlsCertificate *cert = l->data;
gchar *parsed_cert_pem = NULL;
g_object_get (cert,
"certificate-pem", &parsed_cert_pem,
NULL);
g_assert_cmpstr (parsed_cert_pem, ==, ref->cert_pems[i]);
g_free (parsed_cert_pem);
l = g_list_next (l);
}
g_list_free_full (list, g_object_unref);
/* Empty list is not an error */
list = g_tls_certificate_list_new_from_file (g_test_get_filename (G_TEST_DIST, "cert-tests", "nothing.pem", NULL),
&error);
g_assert_no_error (error);
g_assert_cmpint (g_list_length (list), ==, 0);
}
int
main (int argc,
char *argv[])
{
int rtv;
Reference ref;
GError *error = NULL;
gchar *path;
g_test_init (&argc, &argv, NULL);
_g_test_tls_backend_get_type ();
/* Load reference PEM */
path = g_test_build_filename (G_TEST_DIST, "cert-tests", "cert1.pem", NULL);
g_file_get_contents (path, &ref.cert_pems[0], NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (ref.cert_pems[0]);
g_free (path);
path = g_test_build_filename (G_TEST_DIST, "cert-tests", "cert2.pem", NULL);
g_file_get_contents (path, &ref.cert_pems[1], NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (ref.cert_pems[1]);
g_free (path);
path = g_test_build_filename (G_TEST_DIST, "cert-tests", "cert3.pem", NULL);
g_file_get_contents (path, &ref.cert_pems[2], NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (ref.cert_pems[2]);
g_free (path);
path = g_test_build_filename (G_TEST_DIST, "cert-tests", "cert-crlf.pem", NULL);
g_file_get_contents (path, &ref.cert_crlf_pem, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (ref.cert_crlf_pem);
g_free (path);
path = g_test_build_filename (G_TEST_DIST, "cert-tests", "key.pem", NULL);
g_file_get_contents (path, &ref.key_pem, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (ref.key_pem);
g_free (path);
path = g_test_build_filename (G_TEST_DIST, "cert-tests", "key-crlf.pem", NULL);
g_file_get_contents (path, &ref.key_crlf_pem, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (ref.key_crlf_pem);
g_free (path);
path = g_test_build_filename (G_TEST_DIST, "cert-tests", "key8.pem", NULL);
g_file_get_contents (path, &ref.key8_pem, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (ref.key8_pem);
g_free (path);
g_test_add_data_func ("/tls-certificate/pem-parser",
&ref, (GTestDataFunc)pem_parser);
g_test_add_data_func ("/tls-certificate/pem-parser-handles-chain",
&ref, (GTestDataFunc)pem_parser_handles_chain);
g_test_add_data_func ("/tls-certificate/from_file",
&ref, (GTestDataFunc)from_file);
g_test_add_data_func ("/tls-certificate/from_files",
&ref, (GTestDataFunc)from_files);
g_test_add_data_func ("/tls-certificate/from_files_crlf",
&ref, (GTestDataFunc)from_files_crlf);
g_test_add_data_func ("/tls-certificate/from_files_pkcs8",
&ref, (GTestDataFunc)from_files_pkcs8);
g_test_add_data_func ("/tls-certificate/from_files_pkcs8enc",
&ref, (GTestDataFunc)from_files_pkcs8enc);
g_test_add_data_func ("/tls-certificate/list_from_file",
&ref, (GTestDataFunc)list_from_file);
rtv = g_test_run();
g_free (ref.cert_pems[0]);
g_free (ref.cert_pems[1]);
g_free (ref.cert_pems[2]);
g_free (ref.cert_crlf_pem);
g_free (ref.key_pem);
g_free (ref.key_crlf_pem);
g_free (ref.key8_pem);
return rtv;
}