Commit 36b73df4 authored by Dan Winship's avatar Dan Winship
Browse files

nss: add an NSS-based GTlsBackend [wip]

parent 0f24c52c
......@@ -36,9 +36,10 @@ proxy/libproxy/org.gtk.GLib.PACRunner.service
proxy/tests/gnome
proxy/tests/libproxy
/tls/tests/certificate
/tls/tests/file-database
/tls/tests/connection
/tls/tests/certificate-*
/tls/tests/connection-*
/tls/tests/file-database-*
/tls/tests/pkcs11
/tls/tests/pkcs11-array
/tls/tests/pkcs11-pin
......
......@@ -23,6 +23,13 @@ endif
if HAVE_GNUTLS
SUBDIRS += tls/gnutls
endif
if HAVE_NSS
SUBDIRS += tls/nss
endif
if HAVE_TLS
SUBDIRS += tls/tests
endif
......
......@@ -156,6 +156,30 @@ AM_CONDITIONAL(HAVE_PKCS11, [test "x$with_pkcs11" = "xyes"])
AC_SUBST(PKCS11_CFLAGS)
AC_SUBST(PKCS11_LIBS)
dnl **********************
dnl *** Checks for NSS ***
dnl **********************
AC_ARG_WITH(nss,
[AC_HELP_STRING([--with-nss],
[support for NSS @<:@default=check@:>@])],
[],
[with_nss=check])
AS_IF([test "$with_nss" != "no"],
[PKG_CHECK_MODULES(NSS, [nss],
[with_nss=yes
tls_support="nss $tls_support"],
[AS_IF([test "x$with_nss" = "xyes"],
[AC_MSG_FAILURE("$NSS_PKG_ERRORS")])])])
AM_CONDITIONAL(HAVE_NSS, [test "$with_nss" = "yes"])
AC_SUBST(NSS_CFLAGS)
AC_SUBST(NSS_LIBS)
dnl ***********************************
dnl *** Do we have any TLS backend? ***
dnl ***********************************
AM_CONDITIONAL(HAVE_TLS, [test "$with_gnutls" = "yes" -o "$with_nss" = "yes"])
dnl ************************************
dnl *** Enable lcov coverage reports ***
dnl ************************************
......@@ -243,6 +267,7 @@ AC_CONFIG_FILES([Makefile
tls/base/Makefile
tls/gnutls/Makefile
tls/pkcs11/Makefile
tls/nss/Makefile
tls/tests/Makefile
])
AC_OUTPUT
......@@ -250,7 +275,7 @@ AC_OUTPUT
echo ""
echo " Proxy support: ${proxy_support:-no}"
echo " TLS support: ${tls_support:-no}"
if test "$tls_support" != "no"; then
if test "$with_gnutls" = "yes"; then
echo " PKCS#11 Support: $pkcs11_support"
echo " TLS CA file: ${with_ca_certificates:-(none)}"
if test -n "$with_ca_certificates"; then
......
......@@ -4,5 +4,8 @@ tls/gnutls/gtlscertificate-gnutls.c
tls/gnutls/gtlsclientconnection-gnutls.c
tls/gnutls/gtlsconnection-gnutls.c
tls/gnutls/gtlsserverconnection-gnutls.c
tls/nss/gtlscertificate-nss.c
tls/nss/gtlsconnection-nss.c
tls/nss/gtlsfiledatabase-nss.c
tls/pkcs11/gpkcs11pin.c
tls/pkcs11/gpkcs11slot.c
include $(top_srcdir)/Makefile.decl
giomodule_LTLIBRARIES = libgionss.la
libgionss_la_SOURCES = \
nss-module.c \
gtlsbackend-nss.c \
gtlsbackend-nss.h \
gtlscertificate-nss.c \
gtlscertificate-nss.h \
gtlsclientconnection-nss.c \
gtlsclientconnection-nss.h \
gtlsconnection-nss.c \
gtlsconnection-nss.h \
gtlsdatabase-nss.c \
gtlsdatabase-nss.h \
gtlsfiledatabase-nss.c \
gtlsfiledatabase-nss.h \
gtlsprfiledesc-nss.c \
gtlsprfiledesc-nss.h \
gtlsserverconnection-nss.c \
gtlsserverconnection-nss.h \
$(NULL)
INCLUDES += \
-I$(top_srcdir)/tls/base \
$(NSS_CFLAGS)
libgionss_la_LDFLAGS = $(module_flags)
libgionss_la_LIBADD = \
../base/libtlsbase.la \
$(GLIB_LIBS) \
$(NSS_LIBS) \
$(NULL)
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2011 Red Hat, Inc
*
* 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 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, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "glib.h"
#include <errno.h>
#include <nss.h>
#include <keyhi.h>
#include <pk11pub.h>
#include <secmod.h>
#include <ssl.h>
#include "gtlsbackend-nss.h"
#include "gtlscertificate-nss.h"
#include "gtlsclientconnection-nss.h"
#include "gtlsfiledatabase-nss.h"
#include "gtlsserverconnection-nss.h"
GTlsDatabaseNss *g_tls_backend_nss_default_database;
CERTCertDBHandle *g_tls_backend_nss_certdbhandle;
PK11SlotInfo *g_tls_backend_nss_pem_slot;
struct _GTlsBackendNssPrivate
{
NSSInitContext *context;
};
static void g_tls_backend_nss_interface_init (GTlsBackendInterface *iface);
G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendNss, g_tls_backend_nss, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
g_tls_backend_nss_interface_init);)
static void
g_tls_backend_nss_init (GTlsBackendNss *backend)
{
static volatile gsize inited;
int i;
backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, G_TYPE_TLS_BACKEND_NSS, GTlsBackendNssPrivate);
backend->priv->context = NSS_InitContext ("sql:/etc/pki/nssdb", "", "",
SECMOD_DB, NULL, 0);
/* FIXME? */
NSS_SetDomesticPolicy ();
if (g_once_init_enter (&inited))
{
SECMODModule *pem_module;
g_tls_backend_nss_certdbhandle = CERT_GetDefaultCertDB ();
g_tls_backend_nss_default_database = g_object_new (G_TYPE_TLS_DATABASE_NSS, NULL);
pem_module = SECMOD_LoadUserModule ("library=libnsspem.so name=PEM",
NULL, PR_FALSE);
g_assert (pem_module != NULL);
/* Find an open slot in the PEM loader; slot 0 is reserved for
* CA certificates.
*/
for (i = 1; i <= 8; i++)
{
char *slot_name = g_strdup_printf ("PEM Token #%d", i);
PK11SlotInfo *slot = PK11_FindSlotByName (slot_name);
SECKEYPublicKeyList *pubkeys;
if (!slot)
continue;
pubkeys = PK11_ListPublicKeysInSlot (slot, NULL);
if (!pubkeys)
{
g_tls_backend_nss_pem_slot = slot;
break;
}
SECKEY_DestroyPublicKeyList (pubkeys);
PK11_FreeSlot (slot);
}
g_assert (g_tls_backend_nss_pem_slot != NULL);
g_once_init_leave (&inited, TRUE);
}
}
static void
g_tls_backend_nss_finalize (GObject *object)
{
GTlsBackendNss *backend = G_TLS_BACKEND_NSS (object);
if (backend->priv->context)
NSS_ShutdownContext (backend->priv->context);
G_OBJECT_CLASS (g_tls_backend_nss_parent_class)->finalize (object);
}
static void
g_tls_backend_nss_class_init (GTlsBackendNssClass *backend_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (backend_class);
g_type_class_add_private (backend_class, sizeof (GTlsBackendNssPrivate));
gobject_class->finalize = g_tls_backend_nss_finalize;
}
static void
g_tls_backend_nss_class_finalize (GTlsBackendNssClass *backend_class)
{
}
static GTlsDatabase *
g_tls_backend_nss_get_default_database (GTlsBackend *backend)
{
return g_object_ref (g_tls_backend_nss_default_database);
}
static void
g_tls_backend_nss_interface_init (GTlsBackendInterface *iface)
{
iface->get_certificate_type = g_tls_certificate_nss_get_type;
iface->get_client_connection_type = g_tls_client_connection_nss_get_type;
iface->get_server_connection_type = g_tls_server_connection_nss_get_type;
iface->get_file_database_type = g_tls_file_database_nss_get_type;
iface->get_default_database = g_tls_backend_nss_get_default_database;
}
void
g_tls_backend_nss_register (GIOModule *module)
{
g_tls_backend_nss_register_type (G_TYPE_MODULE (module));
g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
g_tls_backend_nss_get_type(),
"nss",
0);
}
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2011 Red Hat, Inc.
*
* This program 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 of the licence or (at
* your option) any later version.
*
* See the included COPYING file for more information.
*/
#ifndef __G_TLS_BACKEND_NSS_H__
#define __G_TLS_BACKEND_NSS_H__
#include <gio/gio.h>
#include "gtlsdatabase-nss.h"
G_BEGIN_DECLS
#define G_TYPE_TLS_BACKEND_NSS (g_tls_backend_nss_get_type ())
#define G_TLS_BACKEND_NSS(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_BACKEND_NSS, GTlsBackendNss))
#define G_TLS_BACKEND_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_BACKEND_NSS, GTlsBackendNssClass))
#define G_IS_TLS_BACKEND_NSS(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_BACKEND_NSS))
#define G_IS_TLS_BACKEND_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_BACKEND_NSS))
#define G_TLS_BACKEND_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_BACKEND_NSS, GTlsBackendNssClass))
typedef struct _GTlsBackendNss GTlsBackendNss;
typedef struct _GTlsBackendNssClass GTlsBackendNssClass;
typedef struct _GTlsBackendNssPrivate GTlsBackendNssPrivate;
struct _GTlsBackendNssClass
{
GObjectClass parent_class;
};
struct _GTlsBackendNss
{
GObject parent_instance;
GTlsBackendNssPrivate *priv;
};
GType g_tls_backend_nss_get_type (void) G_GNUC_CONST;
void g_tls_backend_nss_register (GIOModule *module);
extern GTlsDatabaseNss *g_tls_backend_nss_default_database;
extern CERTCertDBHandle *g_tls_backend_nss_certdbhandle;
extern PK11SlotInfo *g_tls_backend_nss_pem_slot;
G_END_DECLS
#endif /* __G_TLS_BACKEND_NSS_H___ */
This diff is collapsed.
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2011 Red Hat, Inc
*
* This program 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 of the licence or (at
* your option) any later version.
*
* See the included COPYING file for more information.
*/
#ifndef __G_TLS_CERTIFICATE_NSS_H__
#define __G_TLS_CERTIFICATE_NSS_H__
#include <gio/gio.h>
#include <cert.h>
G_BEGIN_DECLS
#define G_TYPE_TLS_CERTIFICATE_NSS (g_tls_certificate_nss_get_type ())
#define G_TLS_CERTIFICATE_NSS(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_CERTIFICATE_NSS, GTlsCertificateNss))
#define G_TLS_CERTIFICATE_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_CERTIFICATE_NSS, GTlsCertificateNssClass))
#define G_IS_TLS_CERTIFICATE_NSS(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_CERTIFICATE_NSS))
#define G_IS_TLS_CERTIFICATE_NSS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_CERTIFICATE_NSS))
#define G_TLS_CERTIFICATE_NSS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_CERTIFICATE_NSS, GTlsCertificateNssClass))
typedef struct _GTlsCertificateNssPrivate GTlsCertificateNssPrivate;
typedef struct _GTlsCertificateNssClass GTlsCertificateNssClass;
typedef struct _GTlsCertificateNss GTlsCertificateNss;
struct _GTlsCertificateNssClass
{
GTlsCertificateClass parent_class;
};
struct _GTlsCertificateNss
{
GTlsCertificate parent_instance;
GTlsCertificateNssPrivate *priv;
};
GType g_tls_certificate_nss_get_type (void) G_GNUC_CONST;
GTlsCertificateNss *g_tls_certificate_nss_new_for_cert (CERTCertificate *cert);
CERTCertificate *g_tls_certificate_nss_get_cert (GTlsCertificateNss *nss);
SECKEYPrivateKey *g_tls_certificate_nss_get_key (GTlsCertificateNss *nss);
GTlsCertificateFlags g_tls_certificate_nss_verify_full (GTlsCertificate *chain,
GTlsDatabase *database,
GTlsCertificate *trusted_ca,
const gchar *purpose,
GSocketConnectable *identity,
GTlsInteraction *interaction,
GTlsDatabaseVerifyFlags flags,
GCancellable *cancellable,
GError **error);
G_END_DECLS
#endif /* __G_TLS_CERTIFICATE_NSS_H___ */
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2011 Red Hat, Inc
*
* 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 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, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <glib.h>
#include "gtlsclientconnection-nss.h"
#include "gtlscertificate-nss.h"
#include <key.h>
#include <glib/gi18n-lib.h>
enum
{
PROP_0,
PROP_VALIDATION_FLAGS,
PROP_SERVER_IDENTITY,
PROP_USE_SSL3,
PROP_ACCEPTED_CAS
};
SECStatus g_tls_client_connection_nss_certificate_requested (void *arg,
PRFileDesc *fd,
CERTDistNames *caNames,
CERTCertificate **pRetCert,
SECKEYPrivateKey **pRetKey);
static void g_tls_client_connection_nss_client_connection_interface_init (GTlsClientConnectionInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GTlsClientConnectionNss, g_tls_client_connection_nss, G_TYPE_TLS_CONNECTION_NSS,
G_IMPLEMENT_INTERFACE (G_TYPE_TLS_CLIENT_CONNECTION,
g_tls_client_connection_nss_client_connection_interface_init));
struct _GTlsClientConnectionNssPrivate
{
GTlsCertificateFlags validation_flags;
GSocketConnectable *server_identity;
gboolean use_ssl3;
GList *accepted_cas;
};
static void
g_tls_client_connection_nss_init (GTlsClientConnectionNss *nss)
{
GTlsConnectionNss *conn_nss = G_TLS_CONNECTION_NSS (nss);
nss->priv = G_TYPE_INSTANCE_GET_PRIVATE (nss, G_TYPE_TLS_CLIENT_CONNECTION_NSS, GTlsClientConnectionNssPrivate);
SSL_ResetHandshake (conn_nss->prfd, PR_FALSE);
SSL_GetClientAuthDataHook (conn_nss->prfd, g_tls_client_connection_nss_certificate_requested, nss);
}
static void
g_tls_client_connection_nss_finalize (GObject *object)
{
GTlsClientConnectionNss *nss = G_TLS_CLIENT_CONNECTION_NSS (object);
if (nss->priv->server_identity)
g_object_unref (nss->priv->server_identity);
if (nss->priv->accepted_cas)
g_list_free_full (nss->priv->accepted_cas, (GDestroyNotify)g_byte_array_unref);
G_OBJECT_CLASS (g_tls_client_connection_nss_parent_class)->finalize (object);
}
static void
g_tls_client_connection_nss_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GTlsClientConnectionNss *nss = G_TLS_CLIENT_CONNECTION_NSS (object);
GList *accepted_cas, *iter;
switch (prop_id)
{
case PROP_VALIDATION_FLAGS:
g_value_set_flags (value, nss->priv->validation_flags);
break;
case PROP_SERVER_IDENTITY:
g_value_set_object (value, nss->priv->server_identity);
break;
case PROP_USE_SSL3:
g_value_set_boolean (value, nss->priv->use_ssl3);
break;
case PROP_ACCEPTED_CAS:
accepted_cas = NULL;
for (iter = nss->priv->accepted_cas; iter; iter = iter->next)
accepted_cas = g_list_prepend (accepted_cas, g_byte_array_ref (iter->data));
g_value_set_pointer (value, accepted_cas);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
g_tls_client_connection_nss_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GTlsClientConnectionNss *nss = G_TLS_CLIENT_CONNECTION_NSS (object);
GTlsConnectionNss *conn_nss = G_TLS_CONNECTION_NSS (object);
const char *identity_host;
switch (prop_id)
{
case PROP_VALIDATION_FLAGS:
nss->priv->validation_flags = g_value_get_flags (value);
break;
case PROP_SERVER_IDENTITY:
if (nss->priv->server_identity)
g_object_unref (nss->priv->server_identity);
nss->priv->server_identity = g_value_dup_object (value);
if (G_IS_NETWORK_ADDRESS (nss->priv->server_identity))
identity_host = g_network_address_get_hostname (G_NETWORK_ADDRESS (nss->priv->server_identity));
else if (G_IS_NETWORK_SERVICE (nss->priv->server_identity))
identity_host = g_network_service_get_domain (G_NETWORK_SERVICE (nss->priv->server_identity));
else
identity_host = NULL;
if (identity_host)
{
SSL_SetURL (conn_nss->prfd, identity_host);
SSL_SetSockPeerID (conn_nss->prfd, identity_host);
}
break;
case PROP_USE_SSL3:
nss->priv->use_ssl3 = g_value_get_boolean (value);
SSL_OptionSet (conn_nss->prfd, SSL_ENABLE_TLS, !nss->priv->use_ssl3);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
g_tls_client_connection_nss_class_init (GTlsClientConnectionNssClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (GTlsClientConnectionNssPrivate));
gobject_class->get_property = g_tls_client_connection_nss_get_property;
gobject_class->set_property = g_tls_client_connection_nss_set_property;
gobject_class->finalize = g_tls_client_connection_nss_finalize;
g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity");
g_object_class_override_property (gobject_class, PROP_USE_SSL3, "use-ssl3");
g_object_class_override_property (gobject_class, PROP_ACCEPTED_CAS, "accepted-cas");
}
static void
g_tls_client_connection_nss_client_connection_interface_init (GTlsClientConnectionInterface *iface)
{
}
SECStatus
g_tls_client_connection_nss_certificate_requested (void *arg,
PRFileDesc *fd,
CERTDistNames *caNames,
CERTCertificate **pRetCert,
SECKEYPrivateKey **pRetKey)
{
GTlsClientConnectionNss *nss = arg;
GTlsConnectionBase *tls = arg;
GTlsCertificateNss *gcert;
GByteArray *name;
GList *cas = NULL;
int i;
tls->certificate_requested = TRUE;
for (i = 0; i < caNames->nnames; i++)
{
name = g_byte_array_new ();
g_byte_array_append (name, caNames->names[i].data, caNames->names[i].len);
cas = g_list_prepend (cas, name);
}
nss->priv->accepted_cas = cas;
g_object_notify (G_OBJECT (nss), "accepted-cas");
if (!tls->certificate)
return SECFailure;
gcert = G_TLS_CERTIFICATE_NSS (tls->certificate);
*pRetCert = CERT_DupCertificate (g_tls_certificate_nss_get_cert (gcert));
*pRetKey = SECKEY_CopyPrivateKey (g_tls_certificate_nss_get_key (gcert));
return SECSuccess;
}
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2011 Red Hat, Inc.
*
* This program 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 of the licence or (at