From: Stef Walter Date: Fri, 10 Feb 2012 16:02:46 +0000 (+0100) Subject: gcr: Expose secure memory API X-Git-Tag: upstream/3.7.5~147 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a9e9199acaec4c0af75758cec82bd36612f431ef;p=platform%2Fupstream%2Fgcr.git 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 --- 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 @@ + 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
+gcr-secure-memory +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 +
+ +
gcr-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 #include #include +#include #include #include #include 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 +*/ + +#include "config.h" + +#include "gcr-secure-memory.h" + +#include "egg/egg-secure-memory.h" + +#include + +#include + +/** + * 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 +*/ + +#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) +#error "Only or can be included directly." +#endif + +#ifndef GCR_SECURE_MEMORY_H +#define GCR_SECURE_MEMORY_H + +#include + +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 +*/ + +#include "config.h" + +#include "gcr/gcr-secure-memory.h" + +#include + +#include +#include +#include + +#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 (); +}