[gcr] gcr: Expose secure memory API



commit a9e9199acaec4c0af75758cec82bd36612f431ef
Author: Stef Walter <stefw gnome org>
Date:   Fri Feb 10 17:02:46 2012 +0100

    gcr: Expose secure memory API
    
     * Add gcr_secure_memory_new() and gcr_secure_memory_free()
       and friends.
     * Exposed so that we can implement secure entry widget in
       gnome-shell

 docs/reference/gcr/gcr-docs.sgml    |    1 +
 docs/reference/gcr/gcr-sections.txt |   13 ++
 gcr/Makefile.am                     |    2 +
 gcr/gcr-base.h                      |    1 +
 gcr/gcr-base.symbols                |    9 ++
 gcr/gcr-secure-memory.c             |  247 +++++++++++++++++++++++++++++++++++
 gcr/gcr-secure-memory.h             |   59 +++++++++
 gcr/tests/Makefile.am               |    1 +
 gcr/tests/test-secure-memory.c      |  149 +++++++++++++++++++++
 9 files changed, 482 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gcr/gcr-docs.sgml b/docs/reference/gcr/gcr-docs.sgml
index 9ba537d..8756344 100644
--- a/docs/reference/gcr/gcr-docs.sgml
+++ b/docs/reference/gcr/gcr-docs.sgml
@@ -68,6 +68,7 @@
 		<xi:include href="xml/gcr-library.xml"/>
 		<xi:include href="xml/gcr-fingerprint.xml"/>
 		<xi:include href="xml/gcr-secret-exchange.xml"/>
+		<xi:include href="xml/gcr-secure-memory.xml"/>
 		<xi:include href="xml/gcr-secure-entry-buffer.xml"/>
 	</part>
 
diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt
index 6b7f4c0..de8b840 100644
--- a/docs/reference/gcr/gcr-sections.txt
+++ b/docs/reference/gcr/gcr-sections.txt
@@ -663,6 +663,19 @@ GcrSecureEntryBufferPrivate
 </SECTION>
 
 <SECTION>
+<FILE>gcr-secure-memory</FILE>
+gcr_secure_memory_new
+gcr_secure_memory_alloc
+gcr_secure_memory_try_alloc
+gcr_secure_memory_realloc
+gcr_secure_memory_try_realloc
+gcr_secure_memory_strdup
+gcr_secure_memory_strfree
+gcr_secure_memory_free
+gcr_secure_memory_is_secure
+</SECTION>
+
+<SECTION>
 <FILE>gcr-private</FILE>
 <SUBSECTION Private>
 GCR_GNUPG_COLLECTION
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index adda387..7f7528c 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -32,6 +32,7 @@ HEADER_BASE_FILES = \
 	gcr-pkcs11-certificate.h \
 	gcr-prompt.h \
 	gcr-secret-exchange.h \
+	gcr-secure-memory.h \
 	gcr-simple-certificate.h \
 	gcr-system-prompt.h \
 	gcr-system-prompter.h \
@@ -139,6 +140,7 @@ libgcr_base_ GCR_MAJOR@_la_SOURCES = \
 	gcr-prompt.c gcr-prompt.h \
 	gcr-record.c gcr-record.h \
 	gcr-secret-exchange.c gcr-secret-exchange.h \
+	gcr-secure-memory.c gcr-secure-memory.h \
 	gcr-simple-certificate.c gcr-simple-certificate.h \
 	gcr-simple-collection.c gcr-simple-collection.h \
 	gcr-single-collection.c gcr-single-collection.h \
diff --git a/gcr/gcr-base.h b/gcr/gcr-base.h
index c52a747..ddaa6f3 100644
--- a/gcr/gcr-base.h
+++ b/gcr/gcr-base.h
@@ -48,6 +48,7 @@
 #include <gcr/gcr-pkcs11-certificate.h>
 #include <gcr/gcr-prompt.h>
 #include <gcr/gcr-secret-exchange.h>
+#include <gcr/gcr-secure-memory.h>
 #include <gcr/gcr-simple-certificate.h>
 #include <gcr/gcr-simple-collection.h>
 #include <gcr/gcr-system-prompt.h>
diff --git a/gcr/gcr-base.symbols b/gcr/gcr-base.symbols
index efb4f27..69908c4 100644
--- a/gcr/gcr-base.symbols
+++ b/gcr/gcr-base.symbols
@@ -191,6 +191,15 @@ gcr_secret_exchange_get_type
 gcr_secret_exchange_new
 gcr_secret_exchange_receive
 gcr_secret_exchange_send
+gcr_secure_memory_alloc
+gcr_secure_memory_free
+gcr_secure_memory_is_secure
+gcr_secure_memory_new
+gcr_secure_memory_realloc
+gcr_secure_memory_strdup
+gcr_secure_memory_strfree
+gcr_secure_memory_try_alloc
+gcr_secure_memory_try_realloc
 gcr_simple_certificate_get_type
 gcr_simple_certificate_new
 gcr_simple_certificate_new_static
diff --git a/gcr/gcr-secure-memory.c b/gcr/gcr-secure-memory.c
new file mode 100644
index 0000000..7a1e99d
--- /dev/null
+++ b/gcr/gcr-secure-memory.c
@@ -0,0 +1,247 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gcr-secure-memory.c - library for allocating memory that is non-pageable
+
+   Copyright (C) 2007 Stefan Walter
+   Copyright (C) 2012 Red Hat Inc.
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stefw gnome org>
+*/
+
+#include "config.h"
+
+#include "gcr-secure-memory.h"
+
+#include "egg/egg-secure-memory.h"
+
+#include <glib.h>
+
+#include <string.h>
+
+/**
+ * SECTION:gcr-secure-memory
+ * @title: Non-pageable Memory
+ * @short_description: Secure non-pageable memory
+ *
+ * Normal allocated memory can be paged to disk at the whim of the operating
+ * system. This can be a problem for sensitive information like passwords, keys
+ * and secrets.
+ *
+ * The Gcr library holds passwords and keys in non-pageable, or locked memory.
+ * This is only possible if the OS contains support for it.
+ *
+ * These functions allow applications to use secure memory to hold passwords
+ * and other sensitive information.
+ */
+
+/**
+ * gcr_secure_memory_new: (skip)
+ * @type: C type of the objects to allocate
+ * @n_objects: number of objects to allocate
+ *
+ * Allocate objects in non-pageable memory.
+ *
+ * Returns: (transfer full): the new block of memory
+ **/
+
+/**
+ * gcr_secure_memory_alloc: (skip)
+ * @size: The new desired size of the memory block.
+ *
+ * Allocate a block of non-pageable memory.
+ *
+ * If non-pageable memory cannot be allocated then normal memory will be
+ * returned.
+ *
+ * Return value: (transfer full): new memory block which should be freed
+ * with gcr_secure_memory_free()
+ **/
+gpointer
+gcr_secure_memory_alloc (gsize size)
+{
+	gpointer memory;
+
+	/* Try to allocate secure memory */
+	memory = egg_secure_alloc_full ("gcr-secure-memory", size,
+	                                EGG_SECURE_USE_FALLBACK);
+
+	/* Our fallback will always allocate */
+	g_assert (memory != NULL);
+
+	return memory;
+}
+
+/**
+ * gcr_secure_memory_try_alloc: (skip)
+ * @size: new desired size of the memory block
+ *
+ * Allocate a block of non-pageable memory.
+ *
+ * If non-pageable memory cannot be allocated, then %NULL is returned.
+ *
+ * Return value: (transfer full): new block, or %NULL if memory cannot be
+ * allocated; memory block should be freed with gcr_secure_memory_free()
+ */
+gpointer
+gcr_secure_memory_try_alloc (gsize size)
+{
+	return egg_secure_alloc_full ("gcr-secure-memory", size, 0);
+}
+
+/**
+ * gcr_secure_memory_realloc: (skip)
+ * @memory: (allow-none): pointer to reallocate or %NULL to allocate a new block
+ * @size: new desired size of the memory block, or 0 to free the memory
+ *
+ * Reallocate a block of non-pageable memory.
+ *
+ * Glib memory is also reallocated correctly. If called with a null pointer,
+ * then a new block of memory is allocated. If called with a zero size,
+ * then the block of memory is freed.
+ *
+ * If non-pageable memory cannot be allocated then normal memory will be
+ * returned.
+ *
+ * Return value: (transfer full): new block, or %NULL if the block was
+ * freed; memory block should be freed with gcr_secure_memory_free()
+ */
+gpointer
+gcr_secure_memory_realloc (gpointer memory,
+                           gsize size)
+{
+	gpointer new_memory;
+
+	if (!memory) {
+		return gcr_secure_memory_alloc (size);
+	} else if (!size) {
+		 gcr_secure_memory_free (memory);
+		 return NULL;
+	} else if (!egg_secure_check (memory)) {
+		return g_realloc (memory, size);
+	}
+
+	/* First try and ask secure memory to reallocate */
+	new_memory = egg_secure_realloc_full ("gcr-secure-memory", memory,
+	                                      size, EGG_SECURE_USE_FALLBACK);
+
+	g_assert (new_memory != NULL);
+
+	return new_memory;
+}
+
+/**
+ * gcr_secure_memory_try_realloc: (skip)
+ * @memory: (allow-none): pointer to reallocate or %NULL to allocate a new block
+ * @size: new desired size of the memory block
+ *
+ * Reallocate a block of non-pageable memory.
+ *
+ * Glib memory is also reallocated correctly when passed to this function.
+ * If called with a null pointer, then a new block of memory is allocated.
+ * If called with a zero size, then the block of memory is freed.
+ *
+ * If memory cannot be allocated, %NULL is returned and the original block
+ * of memory remains intact.
+ *
+ * Return value: (transfer full): the new block, or %NULL if memory cannot be
+ * allocated; the memory block should be freed with gcr_secure_memory_free()
+ */
+gpointer
+gcr_secure_memory_try_realloc (gpointer memory,
+                               gsize size)
+{
+	gpointer new_memory;
+
+	if (!memory) {
+		return gcr_secure_memory_try_alloc (size);
+	} else if (!size) {
+		 gcr_secure_memory_free (memory);
+		 return NULL;
+	} else if (!egg_secure_check (memory)) {
+		return g_try_realloc (memory, size);
+	}
+
+	/* First try and ask secure memory to reallocate */
+	new_memory = egg_secure_realloc_full ("gcr-secure-memory", memory,
+	                                      size, 0);
+
+	g_assert (new_memory != NULL);
+
+	return new_memory;
+}
+
+/**
+ * gcr_secure_memory_free: (skip)
+ * @memory: (allow-none): pointer to the beginning of the block of memory to free
+ *
+ * Free a block of non-pageable memory.
+ *
+ * Glib memory is also freed correctly when passed to this function. If called
+ * with a %NULL pointer then no action is taken.
+ */
+void
+gcr_secure_memory_free (gpointer memory)
+{
+	if (!memory)
+		return;
+	egg_secure_free_full (memory, EGG_SECURE_USE_FALLBACK);
+}
+
+/**
+ * gcr_secure_memory_is_secure: (skip)
+ * @memory: pointer to check
+ *
+ * Check if a pointer is in non-pageable memory allocated by.
+ *
+ * Returns: whether the memory is secure non-pageable memory allocated by the
+ *          Gcr library or not
+ */
+gboolean
+gcr_secure_memory_is_secure (gpointer memory)
+{
+	return egg_secure_check (memory) ? TRUE : FALSE;
+}
+
+/**
+ * gcr_secure_memory_strdup: (skip)
+ * @string: (allow-none): null terminated string to copy
+ *
+ * Copy a string into non-pageable memory. If the input string is %NULL, then
+ * %NULL will be returned.
+ *
+ * Returns: copied string, should be freed with gcr_secure_memory_free()
+ */
+gchar *
+gcr_secure_memory_strdup (const gchar* string)
+{
+	return egg_secure_strdup_full ("gcr-secure-memory", string,
+	                               EGG_SECURE_USE_FALLBACK);
+}
+
+/**
+ * gcr_secure_memory_strfree: (skip)
+ * @string: (allow-none): null terminated string to fere
+ *
+ * Free a string, whether securely allocated using these functions or not.
+ * This will also clear out the contents of the string so they do not
+ * remain in memory.
+ */
+void
+gcr_secure_memory_strfree (gchar *string)
+{
+	egg_secure_strfree (string);
+}
diff --git a/gcr/gcr-secure-memory.h b/gcr/gcr-secure-memory.h
new file mode 100644
index 0000000..f41f972
--- /dev/null
+++ b/gcr/gcr-secure-memory.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gcr-secure-memory.h - library for allocating memory that is non-pageable
+
+   Copyright (C) 2007 Stefan Walter
+   Copyright (C) 2012 Red Hat Inc.
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stefw gnome org>
+*/
+
+#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly."
+#endif
+
+#ifndef GCR_SECURE_MEMORY_H
+#define GCR_SECURE_MEMORY_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define   gcr_secure_memory_new(type, n_objects) \
+          ((type *)(gcr_secure_memory_alloc (sizeof (type) * (n_objects))))
+
+gpointer  gcr_secure_memory_alloc          (gsize size);
+
+gpointer  gcr_secure_memory_try_alloc      (gsize size);
+
+gpointer  gcr_secure_memory_realloc        (gpointer memory,
+                                            gsize size);
+
+gpointer  gcr_secure_memory_try_realloc    (gpointer memory,
+                                            gulong size);
+
+void      gcr_secure_memory_free           (gpointer memory);
+
+gboolean  gcr_secure_memory_is_secure      (gpointer memory);
+
+gchar *   gcr_secure_memory_strdup         (const gchar *string);
+
+void      gcr_secure_memory_strfree        (gchar *string);
+
+G_END_DECLS
+
+#endif /* GCR_SECURE_MEMORY_H */
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index 1a8d6cd..2f87b54 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -31,6 +31,7 @@ TEST_PROGS = \
 	test-pkcs11-certificate \
 	test-openpgp \
 	test-openssh \
+	test-secure-memory \
 	test-trust \
 	test-parser \
 	test-record \
diff --git a/gcr/tests/test-secure-memory.c b/gcr/tests/test-secure-memory.c
new file mode 100644
index 0000000..12fa35a
--- /dev/null
+++ b/gcr/tests/test-secure-memory.c
@@ -0,0 +1,149 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-memory.c: Test memory allocation functionality
+
+   Copyright (C) 2007 Stefan Walter
+   Copyright (C) 2012 Red Hat Inc.
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stefw gnome org>
+*/
+
+#include "config.h"
+
+#include "gcr/gcr-secure-memory.h"
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define IS_ZERO -1
+
+static int
+find_non_zero (gpointer mem, gsize len)
+{
+	guchar *b, *e;
+	gsize sz = 0;
+	for (b = (guchar*)mem, e = ((guchar*)mem) + len; b != e; ++b, ++sz) {
+		if (*b != 0x00)
+			return (int)sz;
+	}
+
+	return -1;
+}
+
+static void
+test_alloc_free (void)
+{
+	gpointer p;
+	gboolean ret;
+
+	p = gcr_secure_memory_alloc (512);
+	g_assert (p != NULL);
+	g_assert_cmpint (IS_ZERO, ==, find_non_zero (p, 512));
+
+	memset (p, 0x67, 512);
+
+	ret = gcr_secure_memory_is_secure (p);
+	g_assert (ret == TRUE);
+
+	gcr_secure_memory_free (p);
+}
+
+static void
+test_alloc_two (void)
+{
+	gpointer p, p2;
+	gboolean ret;
+
+	p2 = gcr_secure_memory_alloc (4);
+	g_assert(p2 != NULL);
+	g_assert_cmpint (IS_ZERO, ==, find_non_zero (p2, 4));
+
+	memset (p2, 0x67, 4);
+
+	p = gcr_secure_memory_alloc (16200);
+	g_assert (p != NULL);
+	g_assert_cmpint (IS_ZERO, ==, find_non_zero (p, 16200));
+
+	memset (p, 0x67, 16200);
+
+	ret = gcr_secure_memory_is_secure (p);
+	g_assert (ret == TRUE);
+
+	gcr_secure_memory_free (p2);
+	gcr_secure_memory_free (p);
+}
+
+static void
+test_realloc (void)
+{
+	gchar *str = "a test string to see if realloc works properly";
+	gpointer p, p2;
+	gsize len;
+
+	len = strlen (str) + 1;
+
+	p = gcr_secure_memory_realloc (NULL, len);
+	g_assert (p != NULL);
+	g_assert_cmpint (IS_ZERO, ==, find_non_zero (p, len));
+
+	strcpy ((gchar*)p, str);
+
+	p2 = gcr_secure_memory_realloc (p, 512);
+	g_assert (p2 != NULL);
+
+	/* "strings not equal after realloc" */
+	g_assert_cmpstr (p2, ==, str);
+
+	p = gcr_secure_memory_realloc (p2, 0);
+	/* "should have freed memory" */
+	g_assert (p == NULL);
+}
+
+static void
+test_realloc_across (void)
+{
+	gpointer p, p2;
+
+	/* Tiny allocation */
+	p = gcr_secure_memory_realloc (NULL, 1088);
+	g_assert (p != NULL);
+	g_assert_cmpint (IS_ZERO, ==, find_non_zero (p, 1088));
+
+	/* Reallocate to a large one, will have to have changed blocks */
+	p2 = gcr_secure_memory_realloc (p, 16200);
+	g_assert (p2 != NULL);
+	g_assert_cmpint (IS_ZERO, ==, find_non_zero (p2, 16200));
+
+	gcr_secure_memory_free (p2);
+}
+
+int
+main (int argc, char **argv)
+{
+	g_test_init (&argc, &argv, NULL);
+	g_set_prgname ("test-memory");
+
+	g_test_add_func ("/memory/alloc-free", test_alloc_free);
+	g_test_add_func ("/memory/alloc-two", test_alloc_two);
+	g_test_add_func ("/memory/realloc", test_realloc);
+	g_test_add_func ("/memory/realloc-across", test_realloc_across);
+
+	return g_test_run ();
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]