From b1b54f525d4c3f2db6bff59952323d2424850597 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sun, 25 Sep 2011 08:22:36 +0200 Subject: [PATCH] More Implementation of GSecretService session related code. --- .gitignore | 3 + Makefile.decl | 1 + autogen.sh | 2 +- configure.ac | 16 +- egg/Makefile.am | 2 + egg/egg-dh.c | 353 ++++++++++++++ egg/egg-dh.h | 50 ++ egg/egg-hkdf.c | 109 +++++ egg/egg-hkdf.h | 39 ++ egg/egg-secure-memory.c | 313 ++++++++----- egg/egg-secure-memory.h | 31 +- library/Makefile.am | 8 +- library/gsecret-collection.h | 67 +++ library/gsecret-data.c | 118 ----- library/gsecret-item.c | 297 ++++++++++++ library/gsecret-item.h | 120 +++++ library/gsecret-private.h | 42 ++ library/gsecret-prompt.h | 57 +++ library/gsecret-service.c | 691 ++++++++++++++++++++++++++++ library/gsecret-service.h | 192 ++++++++ library/gsecret-types.h | 30 ++ library/gsecret-util.c | 32 ++ library/gsecret-value.c | 122 +++++ library/{gsecret-data.h => gsecret-value.h} | 22 +- library/tests/Makefile.am | 27 ++ library/tests/test-initial.c | 39 ++ 26 files changed, 2519 insertions(+), 264 deletions(-) create mode 100644 egg/egg-dh.c create mode 100644 egg/egg-dh.h create mode 100644 egg/egg-hkdf.c create mode 100644 egg/egg-hkdf.h create mode 100644 library/gsecret-collection.h delete mode 100644 library/gsecret-data.c create mode 100644 library/gsecret-item.c create mode 100644 library/gsecret-item.h create mode 100644 library/gsecret-private.h create mode 100644 library/gsecret-prompt.h create mode 100644 library/gsecret-service.c create mode 100644 library/gsecret-service.h create mode 100644 library/gsecret-types.h create mode 100644 library/gsecret-util.c create mode 100644 library/gsecret-value.c rename library/{gsecret-data.h => gsecret-value.h} (57%) create mode 100644 library/tests/Makefile.am create mode 100644 library/tests/test-initial.c diff --git a/.gitignore b/.gitignore index 9fbbe47..baaae47 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,8 @@ Makefile.in Makefile.in.in missing stamp* +.settings +.project +.cproject /po/POTFILES diff --git a/Makefile.decl b/Makefile.decl index e69de29..86f0b1c 100644 --- a/Makefile.decl +++ b/Makefile.decl @@ -0,0 +1 @@ +NULL = diff --git a/autogen.sh b/autogen.sh index 971b9a4..3773941 100755 --- a/autogen.sh +++ b/autogen.sh @@ -8,7 +8,7 @@ ORIGDIR=`pwd` cd $srcdir PROJECT=gsecret TEST_TYPE=-f -FILE=library/gsecret-data.c +FILE=library/gsecret-value.c DIE=0 diff --git a/configure.ac b/configure.ac index f27984e..11a040a 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_CONFIG_MACRO_DIR([m4]) AC_INIT([gsecret],[0.1],[http://bugzilla.gnome.org/enter_bug.cgi?product=gsecret]) -AC_CONFIG_SRCDIR([library/gsecret-data.c]) +AC_CONFIG_SRCDIR([library/gsecret-value.c]) AC_CONFIG_HEADERS([config.h]) dnl Other initialization @@ -70,10 +70,12 @@ fi dnl ***************************** dnl *** done *** dnl ***************************** -AC_CONFIG_FILES([Makefile - egg/Makefile - po/Makefile.in - po/Makefile - library/Makefile - ]) +AC_CONFIG_FILES([ + Makefile + egg/Makefile + po/Makefile.in + po/Makefile + library/Makefile + library/tests/Makefile +]) AC_OUTPUT diff --git a/egg/Makefile.am b/egg/Makefile.am index 7c3993d..b70bf52 100644 --- a/egg/Makefile.am +++ b/egg/Makefile.am @@ -6,5 +6,7 @@ INCLUDES = \ -I$(top_srcdir) libegg_la_SOURCES = \ + egg-dh.c egg-dh.h \ + egg-hkdf.c egg-hkdf.h \ egg-secure-memory.c egg-secure-memory.h \ $(BUILT_SOURCES) diff --git a/egg/egg-dh.c b/egg/egg-dh.c new file mode 100644 index 0000000..85dec77 --- /dev/null +++ b/egg/egg-dh.c @@ -0,0 +1,353 @@ +/* + * gnome-keyring + * + * Copyright (C) 2009 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program 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 License for more details. + * + * You should have received a copy of the GNU Lesser General + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "egg-dh.h" +#include "egg-secure-memory.h" + +/* Enabling this is a complete security compromise */ +#define DEBUG_DH_SECRET 0 + +EGG_SECURE_DECLARE (dh); + +typedef struct _DHGroup { + const gchar *name; + guint bits; + const guchar *prime; + gsize n_prime; + const guchar base[1]; + gsize n_base; +} DHGroup; + +static const guchar dh_group_768_prime[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const guchar dh_group_1024_prime[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const guchar dh_group_1536_prime[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const guchar dh_group_2048_prime[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const guchar dh_group_3072_prime[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const guchar dh_group_4096_prime[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const guchar dh_group_8192_prime[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, + 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, + 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, + 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, + 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, + 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, + 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, + 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, + 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, + 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, + 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, + 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, + 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, + 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, + 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, + 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, + 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, + 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, + 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, + 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, + 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, + 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59, 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4, + 0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, 0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA, 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00, + 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED, 0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66, 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68, + 0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, 0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D, 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9, + 0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07, 0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7, 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B, + 0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, 0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8, 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, + 0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6, 0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D, 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36, + 0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, 0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D, 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1, + 0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, 0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68, 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92, + 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, 0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B, 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47, + 0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA, 0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF, 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71, + 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const DHGroup dh_groups[] = { + { + "ietf-ike-grp-modp-768", 768, + dh_group_768_prime, G_N_ELEMENTS (dh_group_768_prime), + { 0x02 }, 1 + }, + { + "ietf-ike-grp-modp-1024", 1024, + dh_group_1024_prime, G_N_ELEMENTS (dh_group_1024_prime), + { 0x02 }, 1 + }, + { + "ietf-ike-grp-modp-1536", 1536, + dh_group_1536_prime, G_N_ELEMENTS (dh_group_1536_prime), + { 0x02 }, 1 + }, + { + "ietf-ike-grp-modp-2048", 2048, + dh_group_2048_prime, G_N_ELEMENTS (dh_group_2048_prime), + { 0x02 }, 1 + }, + { + "ietf-ike-grp-modp-3072", 3072, + dh_group_3072_prime, G_N_ELEMENTS (dh_group_3072_prime), + { 0x02 }, 1 + }, + { + "ietf-ike-grp-modp-4096", 4096, + dh_group_4096_prime, G_N_ELEMENTS (dh_group_4096_prime), + { 0x02 }, 1 + }, + { + "ietf-ike-grp-modp-8192", 8192, + dh_group_8192_prime, G_N_ELEMENTS (dh_group_8192_prime), + { 0x02 }, 1 + }, + { + NULL + } +}; + +gboolean +egg_dh_default_params_raw (const gchar *name, gconstpointer *prime, + gsize *n_prime, gconstpointer *base, gsize *n_base) +{ + const DHGroup *group; + + g_return_val_if_fail (name, FALSE); + g_return_val_if_fail (prime, FALSE); + g_return_val_if_fail (n_prime, FALSE); + g_return_val_if_fail (base, FALSE); + g_return_val_if_fail (n_base, FALSE); + + for (group = dh_groups; group->name; ++group) { + if (g_str_equal (group->name, name)) { + *prime = group->prime; + *n_prime = group->n_prime; + *base = group->base; + *n_base = group->n_base; + return TRUE; + } + } + + return FALSE; +} + +gboolean +egg_dh_default_params (const gchar *name, gcry_mpi_t *prime, gcry_mpi_t *base) +{ + const DHGroup *group; + gcry_error_t gcry; + + g_return_val_if_fail (name, FALSE); + + for (group = dh_groups; group->name; ++group) { + if (g_str_equal (group->name, name)) { + if (prime) { + gcry = gcry_mpi_scan (prime, GCRYMPI_FMT_USG, group->prime, group->n_prime, NULL); + g_return_val_if_fail (gcry == 0, FALSE); + g_return_val_if_fail (gcry_mpi_get_nbits (*prime) == group->bits, FALSE); + } + if (base) { + gcry = gcry_mpi_scan (base, GCRYMPI_FMT_USG, group->base, group->n_base, NULL); + g_return_val_if_fail (gcry == 0, FALSE); + } + return TRUE; + } + } + + return FALSE; +} + +gboolean +egg_dh_gen_pair (gcry_mpi_t prime, gcry_mpi_t base, guint bits, + gcry_mpi_t *pub, gcry_mpi_t *priv) +{ + guint pbits; + + g_return_val_if_fail (prime, FALSE); + g_return_val_if_fail (base, FALSE); + g_return_val_if_fail (pub, FALSE); + g_return_val_if_fail (priv, FALSE); + + pbits = gcry_mpi_get_nbits (prime); + g_return_val_if_fail (pbits > 1, FALSE); + + if (bits == 0) { + bits = pbits; + } else if (bits > pbits) { + g_return_val_if_reached (FALSE); + } + + /* + * Generate a strong random number of bits, and not zero. + * gcry_mpi_randomize bumps up to the next byte. Since we + * need to have a value less than half of prime, we make sure + * we bump down. + */ + *priv = gcry_mpi_snew (bits); + g_return_val_if_fail (*priv, FALSE); + while (gcry_mpi_cmp_ui (*priv, 0) == 0) + gcry_mpi_randomize (*priv, bits, GCRY_STRONG_RANDOM); + + /* Secret key value must be less than half of p */ + if (gcry_mpi_get_nbits (*priv) > bits) + gcry_mpi_clear_highbit (*priv, bits); + if (gcry_mpi_get_nbits (*priv) > pbits - 1) + gcry_mpi_clear_highbit (*priv, pbits - 1); + g_assert (gcry_mpi_cmp (prime, *priv) > 0); + + *pub = gcry_mpi_new (gcry_mpi_get_nbits (*priv)); + g_return_val_if_fail (*pub, FALSE); + gcry_mpi_powm (*pub, base, *priv, prime); + + return TRUE; +} + +gpointer +egg_dh_gen_secret (gcry_mpi_t peer, gcry_mpi_t priv, + gcry_mpi_t prime, gsize *bytes) +{ + gcry_error_t gcry; + guchar *value; + gsize n_value; + gcry_mpi_t k; + gint bits; + + g_return_val_if_fail (peer, NULL); + g_return_val_if_fail (priv, NULL); + g_return_val_if_fail (prime, NULL); + + bits = gcry_mpi_get_nbits (prime); + g_return_val_if_fail (bits >= 0, NULL); + + k = gcry_mpi_snew (bits); + g_return_val_if_fail (k, NULL); + gcry_mpi_powm (k, peer, priv, prime); + + /* Write out the secret */ + gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_value, k); + g_return_val_if_fail (gcry == 0, NULL); + value = egg_secure_alloc (n_value); + gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value, n_value, &n_value, k); + g_return_val_if_fail (gcry == 0, NULL); + +#if DEBUG_DH_SECRET + g_printerr ("DH SECRET: "); + gcry_mpi_dump (k); + gcry_mpi_release (k); +#endif + + *bytes = n_value; + +#if DEBUG_DH_SECRET + gcry_mpi_scan (&k, GCRYMPI_FMT_USG, value, bytes, NULL); + g_printerr ("RAW SECRET: "); + gcry_mpi_dump (k); + gcry_mpi_release (k); +#endif + + return value; +} diff --git a/egg/egg-dh.h b/egg/egg-dh.h new file mode 100644 index 0000000..ee315e2 --- /dev/null +++ b/egg/egg-dh.h @@ -0,0 +1,50 @@ +/* + * gnome-keyring + * + * Copyright (C) 2009 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program 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 License for more details. + * + * You should have received a copy of the GNU Lesser General + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef EGG_DH_H_ +#define EGG_DH_H_ + +#include + +#include + +gboolean egg_dh_default_params (const gchar *name, + gcry_mpi_t *prime, + gcry_mpi_t *base); + +gboolean egg_dh_default_params_raw (const gchar *name, + gconstpointer *prime, + gsize *n_prime, + gconstpointer *base, + gsize *n_base); + +gboolean egg_dh_gen_pair (gcry_mpi_t prime, + gcry_mpi_t base, + guint bits, + gcry_mpi_t *pub, + gcry_mpi_t *priv); + +gpointer egg_dh_gen_secret (gcry_mpi_t peer, + gcry_mpi_t priv, + gcry_mpi_t prime, + gsize *bytes); + +#endif /* EGG_DH_H_ */ diff --git a/egg/egg-hkdf.c b/egg/egg-hkdf.c new file mode 100644 index 0000000..a55ee5d --- /dev/null +++ b/egg/egg-hkdf.c @@ -0,0 +1,109 @@ +/* + * gnome-keyring + * + * Copyright (C) 2011 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program 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 License for more details. + * + * You should have received a copy of the GNU Lesser General + * License along with this program; 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 "egg-hkdf.h" +#include "egg-secure-memory.h" + +#include + +#include + +gboolean +egg_hkdf_perform (const gchar *hash_algo, gconstpointer input, gsize n_input, + gconstpointer salt, gsize n_salt, gconstpointer info, + gsize n_info, gpointer output, gsize n_output) +{ + gpointer alloc = NULL; + gpointer buffer = NULL; + gcry_md_hd_t md1, md2; + guint hash_len; + guchar i; + gint flags, algo; + gsize step, n_buffer; + guchar *at; + gcry_error_t gcry; + + algo = gcry_md_map_name (hash_algo); + g_return_val_if_fail (algo != 0, FALSE); + + hash_len = gcry_md_get_algo_dlen (algo); + g_return_val_if_fail (hash_len != 0, FALSE); + g_return_val_if_fail (n_output <= 255 * hash_len, FALSE); + + /* Buffer we need to for intermediate stuff */ + if (gcry_is_secure (input)) { + flags = GCRY_MD_FLAG_SECURE; + buffer = gcry_malloc_secure (hash_len); + } else { + flags = 0; + buffer = gcry_malloc (hash_len); + } + + g_return_val_if_fail (buffer, FALSE); + n_buffer = 0; + + /* Salt defaults to hash_len zeros */ + if (!salt) { + salt = alloc = g_malloc0 (hash_len); + n_salt = hash_len; + } + + /* Step 1: Extract */ + gcry = gcry_md_open (&md1, algo, GCRY_MD_FLAG_HMAC | flags); + g_return_val_if_fail (gcry == 0, FALSE); + gcry = gcry_md_setkey (md1, salt, n_salt); + g_return_val_if_fail (gcry == 0, FALSE); + gcry_md_write (md1, input, n_input); + + /* Step 2: Expand */ + gcry = gcry_md_open (&md2, algo, GCRY_MD_FLAG_HMAC | flags); + g_return_val_if_fail (gcry == 0, FALSE); + gcry = gcry_md_setkey (md2, gcry_md_read (md1, algo), hash_len); + g_return_val_if_fail (gcry == 0, FALSE); + gcry_md_close (md1); + + at = output; + for (i = 1; i < 256; ++i) { + gcry_md_reset (md2); + gcry_md_write (md2, buffer, n_buffer); + gcry_md_write (md2, info, n_info); + gcry_md_write (md2, &i, 1); + + n_buffer = hash_len; + memcpy (buffer, gcry_md_read (md2, algo), n_buffer); + + step = MIN (n_buffer, n_output); + memcpy (at, buffer, step); + n_output -= step; + at += step; + + if (!n_output) + break; + } + + g_free (alloc); + gcry_free (buffer); + return TRUE; +} diff --git a/egg/egg-hkdf.h b/egg/egg-hkdf.h new file mode 100644 index 0000000..430d331 --- /dev/null +++ b/egg/egg-hkdf.h @@ -0,0 +1,39 @@ +/* + * gnome-keyring + * + * Copyright (C) 2011 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program 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 License for more details. + * + * You should have received a copy of the GNU Lesser General + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Author: Stef Walter + */ + +#ifndef EGG_HKDF_H_ +#define EGG_HKDF_H_ + +#include + +gboolean egg_hkdf_perform (const gchar *hash_algo, + gconstpointer input, + gsize n_input, + gconstpointer salt, + gsize n_salt, + gconstpointer info, + gsize n_info, + gpointer output, + gsize n_output); + +#endif /* EGG_HKDF_H_ */ diff --git a/egg/egg-secure-memory.c b/egg/egg-secure-memory.c index f699203..ab63d45 100644 --- a/egg/egg-secure-memory.c +++ b/egg/egg-secure-memory.c @@ -97,20 +97,22 @@ typedef void* word_t; typedef struct _Cell { word_t *words; /* Pointer to secure memory */ size_t n_words; /* Amount of secure memory in words */ - size_t allocated; /* Amount actually requested by app, in bytes, 0 if unused */ - struct _Cell *next; /* Next in unused memory ring, or NULL if used */ - struct _Cell *prev; /* Previous in unused memory ring, or NULL if used */ + size_t requested; /* Amount actually requested by app, in bytes, 0 if unused */ + const char *tag; /* Tag which describes the allocation */ + struct _Cell *next; /* Next in memory ring */ + struct _Cell *prev; /* Previous in memory ring */ } Cell; /* * A block of secure memory. This structure is the header in that block. */ typedef struct _Block { - word_t *words; /* Actual memory hangs off here */ - size_t n_words; /* Number of words in block */ - size_t used; /* Number of used allocations */ - struct _Cell* unused; /* Ring of unused allocations */ - struct _Block *next; /* Next block in list */ + word_t *words; /* Actual memory hangs off here */ + size_t n_words; /* Number of words in block */ + size_t n_used; /* Number of used allocations */ + struct _Cell* used_cells; /* Ring of used allocations */ + struct _Cell* unused_cells; /* Ring of unused allocations */ + struct _Block *next; /* Next block in list */ } Block; /* ----------------------------------------------------------------------------- @@ -263,6 +265,8 @@ pool_free (void* item) unused_push (&pool->unused, item); } +#ifndef G_DISABLE_ASSERT + static int pool_valid (void* item) { @@ -282,6 +286,8 @@ pool_valid (void* item) return 0; } +#endif /* G_DISABLE_ASSERT */ + /* ----------------------------------------------------------------------------- * SEC ALLOCATION * @@ -459,7 +465,9 @@ sec_neighbor_after (Block *block, Cell *cell) } static void* -sec_alloc (Block *block, size_t length) +sec_alloc (Block *block, + const char *tag, + size_t length) { Cell *cell, *other; size_t n_words; @@ -467,8 +475,9 @@ sec_alloc (Block *block, size_t length) ASSERT (block); ASSERT (length); + ASSERT (tag); - if (!block->unused) + if (!block->unused_cells) return NULL; /* @@ -482,10 +491,10 @@ sec_alloc (Block *block, size_t length) n_words = sec_size_to_words (length) + 2; /* Look for a cell of at least our required size */ - cell = block->unused; + cell = block->unused_cells; while (cell->n_words < n_words) { cell = cell->next; - if (cell == block->unused) { + if (cell == block->unused_cells) { cell = NULL; break; } @@ -493,8 +502,9 @@ sec_alloc (Block *block, size_t length) if (!cell) return NULL; - - ASSERT (cell->allocated == 0); + + ASSERT (cell->tag == NULL); + ASSERT (cell->requested == 0); ASSERT (cell->prev); ASSERT (cell->words); sec_check_guards (cell); @@ -516,10 +526,12 @@ sec_alloc (Block *block, size_t length) } if (cell->next) - sec_remove_cell_ring (&block->unused, cell); - - ++block->used; - cell->allocated = length; + sec_remove_cell_ring (&block->unused_cells, cell); + + ++block->n_used; + cell->tag = tag; + cell->requested = length; + sec_insert_cell_ring (&block->used_cells, cell); memory = sec_cell_to_memory (cell); #ifdef WITH_VALGRIND @@ -555,16 +567,19 @@ sec_free (Block *block, void *memory) #endif sec_check_guards (cell); - sec_clear_memory (memory, 0, cell->allocated); + sec_clear_memory (memory, 0, cell->requested); sec_check_guards (cell); - ASSERT (cell->next == NULL); - ASSERT (cell->prev == NULL); - ASSERT (cell->allocated > 0); + ASSERT (cell->requested > 0); + ASSERT (cell->tag != NULL); + + /* Remove from the used cell ring */ + sec_remove_cell_ring (&block->used_cells, cell); /* Find previous unallocated neighbor, and merge if possible */ other = sec_neighbor_before (block, cell); - if (other && other->allocated == 0) { + if (other && other->requested == 0) { + ASSERT (other->tag == NULL); ASSERT (other->next && other->prev); other->n_words += cell->n_words; sec_write_guards (other); @@ -574,12 +589,13 @@ sec_free (Block *block, void *memory) /* Find next unallocated neighbor, and merge if possible */ other = sec_neighbor_after (block, cell); - if (other && other->allocated == 0) { + if (other && other->requested == 0) { + ASSERT (other->tag == NULL); ASSERT (other->next && other->prev); other->n_words += cell->n_words; other->words = cell->words; if (cell->next) - sec_remove_cell_ring (&block->unused, cell); + sec_remove_cell_ring (&block->unused_cells, cell); sec_write_guards (other); pool_free (cell); cell = other; @@ -587,25 +603,30 @@ sec_free (Block *block, void *memory) /* Add to the unused list if not already there */ if (!cell->next) - sec_insert_cell_ring (&block->unused, cell); - - cell->allocated = 0; - --block->used; + sec_insert_cell_ring (&block->unused_cells, cell); + + cell->tag = NULL; + cell->requested = 0; + --block->n_used; return NULL; } static void* -sec_realloc (Block *block, void *memory, size_t length) +sec_realloc (Block *block, + const char *tag, + void *memory, + size_t length) { Cell *cell, *other; word_t *word; size_t n_words; size_t valid; void *alloc; - + /* Standard realloc behavior, should have been handled elsewhere */ ASSERT (memory != NULL); ASSERT (length > 0); + ASSERT (tag != NULL); /* Dig out where the meta should be */ word = memory; @@ -621,13 +642,12 @@ sec_realloc (Block *block, void *memory, size_t length) /* Validate that it's actually for real */ sec_check_guards (cell); - ASSERT (cell->allocated > 0); - ASSERT (cell->next == NULL); - ASSERT (cell->prev == NULL); - + ASSERT (cell->requested > 0); + ASSERT (cell->tag != NULL); + /* The amount of valid data */ - valid = cell->allocated; - + valid = cell->requested; + /* How many words we actually want */ n_words = sec_size_to_words (length) + 2; @@ -635,7 +655,7 @@ sec_realloc (Block *block, void *memory, size_t length) if (n_words <= cell->n_words) { /* TODO: No shrinking behavior yet */ - cell->allocated = length; + cell->requested = length; alloc = sec_cell_to_memory (cell); #ifdef WITH_VALGRIND @@ -658,14 +678,14 @@ sec_realloc (Block *block, void *memory, size_t length) /* See if we have a neighbor who can give us some memory */ other = sec_neighbor_after (block, cell); - if (!other || other->allocated != 0) + if (!other || other->requested != 0) break; /* Eat the whole neighbor if not too big */ if (n_words - cell->n_words + WASTE >= other->n_words) { cell->n_words += other->n_words; sec_write_guards (cell); - sec_remove_cell_ring (&block->unused, other); + sec_remove_cell_ring (&block->unused_cells, other); pool_free (other); /* Steal from the neighbor */ @@ -679,18 +699,19 @@ sec_realloc (Block *block, void *memory, size_t length) } if (cell->n_words >= n_words) { - cell->allocated = length; + cell->requested = length; + cell->tag = tag; alloc = sec_cell_to_memory (cell); - + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_DEFINED (alloc, length); #endif return sec_clear_memory (alloc, valid, length); } - + /* That didn't work, try alloc/free */ - alloc = sec_alloc (block, length); + alloc = sec_alloc (block, tag, length); if (alloc) { memcpy (alloc, memory, valid); sec_free (block, memory); @@ -722,15 +743,14 @@ sec_allocated (Block *block, void *memory) cell = *word; sec_check_guards (cell); - ASSERT (cell->next == NULL); - ASSERT (cell->prev == NULL); - ASSERT (cell->allocated > 0); - + ASSERT (cell->requested > 0); + ASSERT (cell->tag != NULL); + #ifdef WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t)); #endif - - return cell->allocated; + + return cell->requested; } static void @@ -753,15 +773,19 @@ sec_validate (Block *block) sec_check_guards (cell); /* Is it an allocated block? */ - if (cell->allocated > 0) { - ASSERT (cell->next == NULL); - ASSERT (cell->prev == NULL); - ASSERT (cell->allocated <= (cell->n_words - 2) * sizeof (word_t)); + if (cell->requested > 0) { + ASSERT (cell->tag != NULL); + ASSERT (cell->next != NULL); + ASSERT (cell->prev != NULL); + ASSERT (cell->next->prev == cell); + ASSERT (cell->prev->next == cell); + ASSERT (cell->requested <= (cell->n_words - 2) * sizeof (word_t)); /* An unused block */ } else { - ASSERT (cell->next); - ASSERT (cell->prev); + ASSERT (cell->tag == NULL); + ASSERT (cell->next != NULL); + ASSERT (cell->prev != NULL); ASSERT (cell->next->prev == cell); ASSERT (cell->prev->next == cell); } @@ -777,13 +801,15 @@ sec_validate (Block *block) */ static void* -sec_acquire_pages (size_t *sz) +sec_acquire_pages (size_t *sz, + const char *during_tag) { void *pages; unsigned long pgsize; ASSERT (sz); ASSERT (*sz); + ASSERT (during_tag); /* Make sure sz is a multiple of the page size */ pgsize = getpagesize (); @@ -793,16 +819,16 @@ sec_acquire_pages (size_t *sz) pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (pages == MAP_FAILED) { if (lock_warning && egg_secure_warnings) - fprintf (stderr, "couldn't map %lu bytes of private memory: %s\n", - (unsigned long)*sz, strerror (errno)); + fprintf (stderr, "couldn't map %lu bytes of memory (%s): %s\n", + (unsigned long)*sz, during_tag, strerror (errno)); lock_warning = 0; return NULL; } if (mlock (pages, *sz) < 0) { if (lock_warning && egg_secure_warnings && errno != EPERM) { - fprintf (stderr, "couldn't lock %lu bytes of private memory: %s\n", - (unsigned long)*sz, strerror (errno)); + fprintf (stderr, "couldn't lock %lu bytes of memory (%s): %s\n", + (unsigned long)*sz, during_tag, strerror (errno)); lock_warning = 0; } munmap (pages, *sz); @@ -850,11 +876,14 @@ sec_release_pages (void *pages, size_t sz) static Block *all_blocks = NULL; static Block* -sec_block_create (size_t size) +sec_block_create (size_t size, + const char *during_tag) { Block *block; Cell *cell; + ASSERT (during_tag); + #if FORCE_FALLBACK_MEMORY /* We can force all all memory to be malloced */ return NULL; @@ -874,7 +903,7 @@ sec_block_create (size_t size) if (size < DEFAULT_BLOCK_SIZE) size = DEFAULT_BLOCK_SIZE; - block->words = sec_acquire_pages (&size); + block->words = sec_acquire_pages (&size, during_tag); block->n_words = size / sizeof (word_t); if (!block->words) { pool_free (block); @@ -889,10 +918,10 @@ sec_block_create (size_t size) /* The first cell to allocate from */ cell->words = block->words; cell->n_words = block->n_words; - cell->allocated = 0; + cell->requested = 0; sec_write_guards (cell); - sec_insert_cell_ring (&block->unused, cell); - + sec_insert_cell_ring (&block->unused_cells, cell); + block->next = all_blocks; all_blocks = block; @@ -907,7 +936,7 @@ sec_block_destroy (Block *block) ASSERT (block); ASSERT (block->words); - ASSERT (block->used == 0); + ASSERT (block->n_used == 0); /* Remove from the list */ for (at = &all_blocks, bl = *at; bl; at = &bl->next, bl = *at) { @@ -919,11 +948,12 @@ sec_block_destroy (Block *block) /* Must have been found */ ASSERT (bl == block); + ASSERT (block->used_cells == NULL); /* Release all the meta data cells */ - while (block->unused) { - cell = block->unused; - sec_remove_cell_ring (&block->unused, cell); + while (block->unused_cells) { + cell = block->unused_cells; + sec_remove_cell_ring (&block->unused_cells, cell); pool_free (cell); } @@ -938,17 +968,16 @@ sec_block_destroy (Block *block) */ void* -egg_secure_alloc (size_t length) -{ - return egg_secure_alloc_full (length, GKR_SECURE_USE_FALLBACK); -} - -void* -egg_secure_alloc_full (size_t length, int flags) +egg_secure_alloc_full (const char *tag, + size_t length, + int flags) { Block *block; void *memory = NULL; - + + if (tag == NULL) + tag = "?"; + if (length > 0xFFFFFFFF / 2) { if (egg_secure_warnings) fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", @@ -963,16 +992,16 @@ egg_secure_alloc_full (size_t length, int flags) DO_LOCK (); for (block = all_blocks; block; block = block->next) { - memory = sec_alloc (block, length); + memory = sec_alloc (block, tag, length); if (memory) break; } /* None of the current blocks have space, allocate new */ if (!memory) { - block = sec_block_create (length); + block = sec_block_create (length, tag); if (block) - memory = sec_alloc (block, length); + memory = sec_alloc (block, tag, length); } #ifdef WITH_VALGRIND @@ -981,8 +1010,8 @@ egg_secure_alloc_full (size_t length, int flags) #endif DO_UNLOCK (); - - if (!memory && (flags & GKR_SECURE_USE_FALLBACK)) { + + if (!memory && (flags & EGG_SECURE_USE_FALLBACK)) { memory = egg_memory_fallback (NULL, length); if (memory) /* Our returned memory is always zeroed */ memset (memory, 0, length); @@ -995,19 +1024,19 @@ egg_secure_alloc_full (size_t length, int flags) } void* -egg_secure_realloc (void *memory, size_t length) -{ - return egg_secure_realloc_full (memory, length, GKR_SECURE_USE_FALLBACK); -} - -void* -egg_secure_realloc_full (void *memory, size_t length, int flags) +egg_secure_realloc_full (const char *tag, + void *memory, + size_t length, + int flags) { Block *block = NULL; size_t previous = 0; int donew = 0; void *alloc = NULL; - + + if (tag == NULL) + tag = "?"; + if (length > 0xFFFFFFFF / 2) { if (egg_secure_warnings) fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", @@ -1016,7 +1045,7 @@ egg_secure_realloc_full (void *memory, size_t length, int flags) } if (memory == NULL) - return egg_secure_alloc_full (length, flags); + return egg_secure_alloc_full (tag, length, flags); if (!length) { egg_secure_free_full (memory, flags); return NULL; @@ -1034,8 +1063,8 @@ egg_secure_realloc_full (void *memory, size_t length, int flags) VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t)); #endif - alloc = sec_realloc (block, memory, length); - + alloc = sec_realloc (block, tag, memory, length); + #ifdef WITH_VALGRIND /* Now tell valgrind about either the new block or old one */ VALGRIND_MALLOCLIKE_BLOCK (alloc ? alloc : memory, @@ -1050,13 +1079,13 @@ egg_secure_realloc_full (void *memory, size_t length, int flags) if (block && !alloc) donew = 1; - if (block && block->used == 0) + if (block && block->n_used == 0) sec_block_destroy (block); DO_UNLOCK (); if (!block) { - if ((flags & GKR_SECURE_USE_FALLBACK)) { + if ((flags & EGG_SECURE_USE_FALLBACK)) { /* * In this case we can't zero the returned memory, * because we don't know what the block size was. @@ -1070,9 +1099,9 @@ egg_secure_realloc_full (void *memory, size_t length, int flags) return NULL; } } - + if (donew) { - alloc = egg_secure_alloc_full (length, flags); + alloc = egg_secure_alloc_full (tag, length, flags); if (alloc) { memcpy (alloc, memory, previous); egg_secure_free_full (memory, flags); @@ -1088,7 +1117,7 @@ egg_secure_realloc_full (void *memory, size_t length, int flags) void egg_secure_free (void *memory) { - egg_secure_free_full (memory, GKR_SECURE_USE_FALLBACK); + egg_secure_free_full (memory, EGG_SECURE_USE_FALLBACK); } void @@ -1115,14 +1144,14 @@ egg_secure_free_full (void *memory, int flags) if (block != NULL) { sec_free (block, memory); - if (block->used == 0) + if (block->n_used == 0) sec_block_destroy (block); } DO_UNLOCK (); if (!block) { - if ((flags & GKR_SECURE_USE_FALLBACK)) { + if ((flags & EGG_SECURE_USE_FALLBACK)) { egg_memory_fallback (memory, 0); } else { if (egg_secure_warnings) @@ -1164,35 +1193,87 @@ egg_secure_validate (void) DO_UNLOCK (); } -void -egg_secure_dump_blocks (void) + +static egg_secure_rec * +records_for_ring (Cell *cell_ring, + egg_secure_rec *records, + unsigned int *count, + unsigned int *total) +{ + egg_secure_rec *new_rec; + unsigned int allocated = *count; + Cell *cell; + + cell = cell_ring; + do { + if (*count >= allocated) { + new_rec = realloc (records, sizeof (egg_secure_rec) * (allocated + 32)); + if (new_rec == NULL) { + *count = 0; + free (records); + return NULL; + } else { + records = new_rec; + allocated += 32; + } + } + + if (cell != NULL) { + records[*count].request_length = cell->requested; + records[*count].block_length = cell->n_words * sizeof (word_t); + records[*count].tag = cell->tag; + (*count)++; + (*total) += cell->n_words; + cell = cell->next; + } + } while (cell != NULL && cell != cell_ring); + + return records; +} + +egg_secure_rec * +egg_secure_records (unsigned int *count) { + egg_secure_rec *records = NULL; Block *block = NULL; + unsigned int total; + + *count = 0; DO_LOCK (); - - /* Find out where it belongs to */ - for (block = all_blocks; block; block = block->next) { - fprintf (stderr, "----------------------------------------------------\n"); - fprintf (stderr, " BLOCK at: 0x%08lx len: %lu\n", (unsigned long)block, - (unsigned long)block->n_words * sizeof (word_t)); - fprintf (stderr, "\n"); + + for (block = all_blocks; block != NULL; block = block->next) { + total = 0; + + records = records_for_ring (block->unused_cells, records, count, &total); + if (records == NULL) + break; + records = records_for_ring (block->used_cells, records, count, &total); + if (records == NULL) + break; + + /* Make sure this actualy accounts for all memory */ + ASSERT (total == block->n_words); } - + DO_UNLOCK (); + + return records; } char* -egg_secure_strdup (const char *str) +egg_secure_strdup_full (const char *tag, + const char *str, + int options) { size_t len; char *res; - + if (!str) return NULL; - + len = strlen (str) + 1; - res = (char*)egg_secure_alloc (len); + res = (char *)egg_secure_alloc_full (tag, len, options); strcpy (res, str); return res; } @@ -1231,5 +1312,5 @@ egg_secure_strfree (char *str) */ egg_secure_strclear (str); - egg_secure_free_full (str, GKR_SECURE_USE_FALLBACK); + egg_secure_free_full (str, EGG_SECURE_USE_FALLBACK); } diff --git a/egg/egg-secure-memory.h b/egg/egg-secure-memory.h index 85ce1f6..682811d 100644 --- a/egg/egg-secure-memory.h +++ b/egg/egg-secure-memory.h @@ -70,15 +70,22 @@ extern void* egg_memory_fallback (void *p, size_t length); * Allocations return NULL on failure. */ -#define GKR_SECURE_USE_FALLBACK 0x0001 +#define EGG_SECURE_USE_FALLBACK 0x0001 -void* egg_secure_alloc (size_t length); +#define EGG_SECURE_DECLARE(tag) \ + static inline void* egg_secure_alloc (size_t length) { \ + return egg_secure_alloc_full (G_STRINGIFY (tag), length, EGG_SECURE_USE_FALLBACK); \ + } \ + static inline void* egg_secure_realloc (void *p, size_t length) { \ + return egg_secure_realloc_full (G_STRINGIFY (tag), p, length, EGG_SECURE_USE_FALLBACK); \ + } \ + static inline void* egg_secure_strdup (const char *str) { \ + return egg_secure_strdup_full (G_STRINGIFY (tag), str, EGG_SECURE_USE_FALLBACK); \ + } -void* egg_secure_alloc_full (size_t length, int flags); +void* egg_secure_alloc_full (const char *tag, size_t length, int options); -void* egg_secure_realloc (void *p, size_t length); - -void* egg_secure_realloc_full (void *p, size_t length, int fallback); +void* egg_secure_realloc_full (const char *tag, void *p, size_t length, int options); void egg_secure_free (void* p); @@ -90,12 +97,18 @@ int egg_secure_check (const void* p); void egg_secure_validate (void); -void egg_secure_dump_blocks (void); - -char* egg_secure_strdup (const char *str); +char* egg_secure_strdup_full (const char *tag, const char *str, int options); void egg_secure_strclear (char *str); void egg_secure_strfree (char *str); +typedef struct { + const char *tag; + size_t request_length; + size_t block_length; +} egg_secure_rec; + +egg_secure_rec * egg_secure_records (unsigned int *count); + #endif /* EGG_SECURE_MEMORY_H */ diff --git a/library/Makefile.am b/library/Makefile.am index 416b85a..c7c79a4 100644 --- a/library/Makefile.am +++ b/library/Makefile.am @@ -1,6 +1,6 @@ include $(top_srcdir)/Makefile.decl -NULL = +SUBDIRS = . tests module_flags = \ -export_dynamic \ @@ -12,7 +12,11 @@ module_flags = \ lib_LTLIBRARIES = libgsecret.la libgsecret_la_SOURCES = \ - gsecret-data.h gsecret-data.c + gsecret-value.h gsecret-value.c \ + gsecret-item.h gsecret-item.c \ + gsecret-service.h gsecret-service.c \ + gsecret-util.c \ + $(NULL) libgsecret_la_LIBADD = \ $(top_builddir)/egg/libegg.la \ diff --git a/library/gsecret-collection.h b/library/gsecret-collection.h new file mode 100644 index 0000000..61f03a5 --- /dev/null +++ b/library/gsecret-collection.h @@ -0,0 +1,67 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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 __GSECRET_SERVICE_H__ +#define __GSECRET_SERVICE_H__ + +#include + +G_BEGIN_DECLS + +#define GSECRET_TYPE_SERVICE (gsecret_service_get_type ()) +#define GSECRET_SERVICE(inst) (GSECRET_TYPE_CHECK_INSTANCE_CAST ((inst), GSECRET_TYPE_SERVICE, GSecretService)) +#define GSECRET_SERVICE_CLASS(class) (GSECRET_TYPE_CHECK_CLASS_CAST ((class), GSECRET_TYPE_SERVICE, GSecretServiceClass)) +#define GSECRET_IS_SERVICE(inst) (GSECRET_TYPE_CHECK_INSTANCE_TYPE ((inst), GSECRET_TYPE_SERVICE)) +#define GSECRET_IS_SERVICE_CLASS(class) (GSECRET_TYPE_CHECK_CLASS_TYPE ((class), GSECRET_TYPE_SERVICE)) +#define GSECRET_SERVICE_GET_CLASS(inst) (GSECRET_TYPE_INSTANCE_GET_CLASS ((inst), GSECRET_TYPE_SERVICE, GSecretServiceClass)) + +typedef struct _GSecretService GSecretService; +typedef struct _GSecretServiceClass GSecretServiceClass; +typedef struct _GSecretServicePrivate GSecretServicePrivate; + +struct _GSecretServiceClass { + GDBusProxyClass parent_class; + + GType collection_type; + GType item_type; + + padding; +}; + +struct _GSecretService { + GDBusProxy parent_instance; + GSecretServicePrivate *pv; +}; + +GType gsecret_service_get_type (void) G_GNUC_CONST; + +GSecretService* gsecret_collection_xxx_new (void); + +GSecretCollection* gsecret_collection_instance (GDBusConnection *connection, + const gchar *object_path); + + gsecret_collection_delete + gsecret_collection_search + + GSecretItem* gsecret_collection_create_item (xxxx); + + + gsecret_collection_get_items + gsecret_collection_get_label + gsecret_collection_set_label + gsecret_collection_get_locked + gsecret_collection_get_created + gsecret_collection_get_modified + +G_END_DECLS + +#endif /* __G_SERVICE_H___ */ diff --git a/library/gsecret-data.c b/library/gsecret-data.c deleted file mode 100644 index c17bb11..0000000 --- a/library/gsecret-data.c +++ /dev/null @@ -1,118 +0,0 @@ -/* GSecret - GLib wrapper for Secret Service - * - * Copyright 2011 Collabora Ltd. - * - * 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. - */ - -#include "config.h" - -#include "gsecret-data.h" - -#include "egg/egg-secure-memory.h" - -#include - -struct _GSecretData { - gint refs; - gpointer secret; - gsize length; - GDestroyNotify destroy; - gchar *content_type; -}; - -GType -gsecret_data_get_type (void) -{ - static gsize initialized = 0; - static GType type = 0; - - if (g_once_init_enter (&initialized)) { - type = g_boxed_type_register_static ("GSecretData", - (GBoxedCopyFunc)gsecret_data_ref, - (GBoxedFreeFunc)gsecret_data_unref); - g_once_init_leave (&initialized, 1); - } - - return type; -} - -GSecretData* -gsecret_data_new (const gchar *secret, gssize length, const gchar *content_type) -{ - gchar *copy; - - g_return_val_if_fail (!secret && length, NULL); - g_return_val_if_fail (content_type, NULL); - - if (length < 0) - length = strlen (secret); - - copy = egg_secure_alloc (length + 1); - memcpy (copy, secret, length); - copy[length] = 0; - return gsecret_data_new_full (copy, length, content_type, egg_secure_free); -} - -GSecretData* -gsecret_data_new_full (gchar *secret, gssize length, - const gchar *content_type, GDestroyNotify destroy) -{ - GSecretData *data; - - g_return_val_if_fail (!secret && length, NULL); - g_return_val_if_fail (content_type, NULL); - - if (length < 0) - length = strlen (secret); - - data = g_slice_new0 (GSecretData); - data->content_type = strdup (content_type); - data->destroy = destroy; - data->length = length; - data->secret = secret; - - return data; -} - -const gchar* -gsecret_data_get (GSecretData *data, gsize *length) -{ - g_return_val_if_fail (data, NULL); - if (length) - *length = data->length; - return data->secret; -} - -const gchar* -gsecret_data_get_content_type (GSecretData *data) -{ - g_return_val_if_fail (data, NULL); - return data->content_type; -} - -GSecretData* -gsecret_data_ref (GSecretData *data) -{ - g_return_val_if_fail (data, NULL); - g_atomic_int_inc (&data->refs); - return data; -} - -void -gsecret_data_unref (GSecretData *data) -{ - g_return_if_fail (data); - - if (g_atomic_int_dec_and_test (&data->refs)) { - g_free (data->content_type); - if (data->destroy) - (data->destroy) (data->secret); - g_slice_free (GSecretData, data); - } -} diff --git a/library/gsecret-item.c b/library/gsecret-item.c new file mode 100644 index 0000000..3bed218 --- /dev/null +++ b/library/gsecret-item.c @@ -0,0 +1,297 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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. + */ + +#include "config.h" + +#include "gsecret-item.h" +#include "gsecret-private.h" +#include "gsecret-service.h" +#include "gsecret-types.h" +#include "gsecret-value.h" + +#include + +struct _GSecretItemPrivate { + GSecretService *service; +}; + +G_DEFINE_TYPE (GSecretItem, gsecret_item, G_TYPE_DBUS_PROXY); + +static void +gsecret_item_init (GSecretItem *self) +{ + self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GSECRET_TYPE_ITEM, GSecretItemPrivate); +} + +static void +gsecret_item_class_init (GSecretItemClass *klass) +{ + +} + +static void +on_item_delete_ready (GObject *source, GAsyncResult *result, gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + GError *error = NULL; + GVariant *ret; + + ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), + result, &error); + if (ret == NULL) + g_simple_async_result_take_error (res, error); + else + g_variant_unref (ret); + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +void +gsecret_item_delete (GSecretItem *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data) +{ + const gchar *object_path; + gchar *collection_path; + GSimpleAsyncResult *res; + + g_return_if_fail (GSECRET_IS_ITEM (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + res = g_simple_async_result_new (G_OBJECT (self), callback, + user_data, gsecret_item_delete); + + object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self)); + collection_path = _gsecret_util_parent_path (object_path); + + g_dbus_connection_call (g_dbus_proxy_get_connection (G_DBUS_PROXY (self)), + g_dbus_proxy_get_name (G_DBUS_PROXY (self)), + collection_path, GSECRET_COLLECTION_INTERFACE, + "Delete", NULL, NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, + cancellable, on_item_delete_ready, res); + + g_free (collection_path); +} + +gboolean +gsecret_item_delete_finish (GSecretItem *self, GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (GSECRET_IS_ITEM (self), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail (g_simple_async_result_is_valid (result, + G_OBJECT (self), gsecret_item_delete), FALSE); + + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), + error)) + return FALSE; + + return TRUE; +} + +gboolean +gsecret_item_delete_sync (GSecretItem *self, GCancellable *cancellable, + GError **error) +{ + const gchar *object_path; + gchar *collection_path; + GVariant *ret; + + g_return_val_if_fail (GSECRET_IS_ITEM (self), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + object_path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (self)); + collection_path = _gsecret_util_parent_path (object_path); + + ret = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (self)), + g_dbus_proxy_get_name (G_DBUS_PROXY (self)), + collection_path, GSECRET_COLLECTION_INTERFACE, + "Delete", NULL, NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, + cancellable, error); + + g_free (collection_path); + + if (ret != NULL) { + g_variant_unref (ret); + return TRUE; + } + + return FALSE; +} + +static void +on_item_get_secret_ready (GObject *source, GAsyncResult *result, gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + GSecretItem *self = GSECRET_ITEM (g_async_result_get_source_object (user_data)); + GError *error = NULL; + GSecretValue *value; + GVariant *ret; + + ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error); + if (error == NULL) { + value = _gsecret_service_decode_secret (self->pv->service, ret); + if (value == NULL) { + g_set_error (&error, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL, + _("Received invalid secret from the secret storage")); + } + g_object_unref (ret); + } + + if (error != NULL) + g_simple_async_result_take_error (res, error); + else + g_simple_async_result_set_op_res_gpointer (res, value, + gsecret_value_unref); + + g_simple_async_result_complete (res); + g_object_unref (res); +} + +static void +on_service_ensure_session (GObject *source, GAsyncResult *result, gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + GSecretItem *self = GSECRET_ITEM (g_async_result_get_source_object (user_data)); + GError *error = NULL; + const gchar *session_path; + + session_path = gsecret_service_ensure_session_finish (self->pv->service, + result, &error); + if (error != NULL) { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + + } else { + g_assert (session_path != NULL && session_path[0] != '\0'); + g_dbus_proxy_call (G_DBUS_PROXY (self), "GetSecret", + g_variant_new ("o", session_path), + G_DBUS_CALL_FLAGS_NONE, -1, + _gsecret_async_result_get_cancellable (res), + on_item_get_secret_ready, g_object_ref (res)); + } + + g_object_unref (res); +} + +void +gsecret_item_get_secret (GSecretItem *self, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data) +{ + GSimpleAsyncResult *res; + + g_return_if_fail (GSECRET_IS_ITEM (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = g_simple_async_result_new (G_OBJECT (self), callback, + user_data, gsecret_item_get_secret); + + gsecret_service_ensure_session (self->pv->service, cancellable, + on_service_ensure_session, + g_object_ref (res)); + + g_object_unref (res); +} + +GSecretValue* +gsecret_item_get_secret_finish (GSecretItem *self, GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *res; + + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + gsecret_item_get_secret), NULL); + + res = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (res, error)) + return NULL; + + return gsecret_value_ref (g_simple_async_result_get_op_res_gpointer (res)); +} + +GSecretValue* +gsecret_item_get_secret_sync (GSecretItem *self, + GCancellable *cancellable, + GError **error) +{ + const gchar *session_path; + GSecretValue *value; + GVariant *ret; + + session_path = gsecret_service_ensure_session_sync (self->pv->service, + cancellable, error); + if (session_path != NULL) + return NULL; + + g_assert (session_path != NULL && session_path[0] != '\0'); + ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (self), "GetSecret", + g_variant_new ("o", session_path), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, error); + + if (ret != NULL) { + value = _gsecret_service_decode_secret (self->pv->service, ret); + if (value == NULL) { + g_set_error (error, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL, + _("Received invalid secret from the secret storage")); + } + } + + g_object_unref (ret); + return value; +} + +#ifdef UNIMPLEMENTED + +GHashTable* gsecret_item_get_attributes (GSecretItem *self); + +void gsecret_item_set_attributes (GSecretItem *self, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gsecret_item_set_attributes_finish (GSecretItem *self, + GAsyncResult *result, + GError **error); + +void gsecret_item_set_attributes_sync (GSecretItem *self, + GHashTable *attributes, + GCancellable *cancellable, + GError **error); + +const gchar* gsecret_item_get_label (GSecretItem *self); + +void gsecret_item_set_label (GSecretItem *self, + const gchar *label, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gsecret_item_set_label_finish (GSecretItem *self, + GAsyncResult *result, + GError **error); + +void gsecret_item_set_label_sync (GSecretItem *self, + const gchar *label, + GCancellable *cancellable, + GError **error); + +gboolean gsecret_item_get_locked (GSecretItem *self); + +guint64 gsecret_item_get_created (GSecretItem *self); + +guint64 gsecret_item_get_modified (GSecretItem *self); + +#endif /* UNIMPLEMENTED */ diff --git a/library/gsecret-item.h b/library/gsecret-item.h new file mode 100644 index 0000000..8ec1e00 --- /dev/null +++ b/library/gsecret-item.h @@ -0,0 +1,120 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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 __GSECRET_ITEM_H__ +#define __GSECRET_ITEM_H__ + +#include + +#include "gsecret-item.h" +#include "gsecret-value.h" + +G_BEGIN_DECLS + +#define GSECRET_TYPE_ITEM (gsecret_item_get_type ()) +#define GSECRET_ITEM(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), GSECRET_TYPE_ITEM, GSecretItem)) +#define GSECRET_ITEM_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), GSECRET_TYPE_ITEM, GSecretItemClass)) +#define GSECRET_IS_ITEM(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), GSECRET_TYPE_ITEM)) +#define GSECRET_IS_ITEM_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), GSECRET_TYPE_ITEM)) +#define GSECRET_ITEM_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), GSECRET_TYPE_ITEM, GSecretItemClass)) + +typedef struct _GSecretItem GSecretItem; +typedef struct _GSecretItemClass GSecretItemClass; +typedef struct _GSecretItemPrivate GSecretItemPrivate; + +struct _GSecretItemClass { + GDBusProxyClass parent_class; +}; + +struct _GSecretItem { + GDBusProxy parent_instance; + GSecretItemPrivate *pv; +}; + +GType gsecret_item_get_type (void) G_GNUC_CONST; + +GSecretItem* gsecret_item_instance (GDBusConnection *connection, + const gchar *object_path); + +void gsecret_item_delete (GSecretItem *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gsecret_item_delete_finish (GSecretItem *self, + GAsyncResult *result, + GError **error); + +gboolean gsecret_item_delete_sync (GSecretItem *self, + GCancellable *cancellable, + GError **error); + +void gsecret_item_get_secret (GSecretItem *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GSecretValue * gsecret_item_get_secret_finish (GSecretItem *self, + GAsyncResult *result, + GError **error); + +GSecretValue * gsecret_item_get_secret_sync (GSecretItem *self, + GCancellable *cancellable, + GError **error); + +#if 0 + +GHashTable* gsecret_item_get_attributes (GSecretItem *self); + +void gsecret_item_set_attributes (GSecretItem *self, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gsecret_item_set_attributes_finish (GSecretItem *self, + GAsyncResult *result, + GError **error); + +void gsecret_item_set_attributes_sync (GSecretItem *self, + GHashTable *attributes, + GCancellable *cancellable, + GError **error); + +const gchar* gsecret_item_get_label (GSecretItem *self); + +void gsecret_item_set_label (GSecretItem *self, + const gchar *label, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gsecret_item_set_label_finish (GSecretItem *self, + GAsyncResult *result, + GError **error); + +void gsecret_item_set_label_sync (GSecretItem *self, + const gchar *label, + GCancellable *cancellable, + GError **error); + +gboolean gsecret_item_get_locked (GSecretItem *self); + +guint64 gsecret_item_get_created (GSecretItem *self); + +guint64 gsecret_item_get_modified (GSecretItem *self); + +#endif + +G_END_DECLS + +#endif /* __G_ITEM_H___ */ diff --git a/library/gsecret-private.h b/library/gsecret-private.h new file mode 100644 index 0000000..e8f5bac --- /dev/null +++ b/library/gsecret-private.h @@ -0,0 +1,42 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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 __GSECRET_PRIVATE_H__ +#define __GSECRET_PRIVATE_H__ + +#include + +#include "gsecret-service.h" +#include "gsecret-value.h" + +G_BEGIN_DECLS + +#define GSECRET_COLLECTION_INTERFACE "org.freedesktop.Secret.Collection" + +gchar * _gsecret_util_parent_path (const gchar *path); + +GVariant * _gsecret_service_encode_secret (GSecretService *self, + GSecretValue *value); + +GSecretValue * _gsecret_service_decode_secret (GSecretService *service, + GVariant *encoded); + +GCancellable * _gsecret_async_result_get_cancellable (GSimpleAsyncResult *result); + +void _gsecret_async_result_set_cancellable (GSimpleAsyncResult *result, + GCancellable *cancellable); + +gboolean _gsecret_async_result_propagate_cancelled (GSimpleAsyncResult *result); + +G_END_DECLS + +#endif /* __G_SERVICE_H___ */ diff --git a/library/gsecret-prompt.h b/library/gsecret-prompt.h new file mode 100644 index 0000000..cb43339 --- /dev/null +++ b/library/gsecret-prompt.h @@ -0,0 +1,57 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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 __GSECRET_PROMPT_H__ +#define __GSECRET_PROMPT_H__ + +#include + +G_BEGIN_DECLS + +#define GSECRET_TYPE_PROMPT (gsecret_prompt_get_type ()) +#define GSECRET_PROMPT(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), GSECRET_TYPE_PROMPT, GSecretPrompt)) +#define GSECRET_PROMPT_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), GSECRET_TYPE_PROMPT, GSecretPromptClass)) +#define GSECRET_IS_PROMPT(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), GSECRET_TYPE_PROMPT)) +#define GSECRET_IS_PROMPT_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), GSECRET_TYPE_PROMPT)) +#define GSECRET_PROMPT_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), GSECRET_TYPE_PROMPT, GSecretPromptClass)) + +typedef struct _GSecretPrompt GSecretPrompt; +typedef struct _GSecretPromptClass GSecretPromptClass; +typedef struct _GSecretPromptPrivate GSecretPromptPrivate; + +struct _GSecretPromptClass { + GDBusProxyClass parent_class; + padding; +}; + +struct _GSecretPrompt { + GDBusProxy parent_instance; + GSecretPromptPrivate *pv; +}; + +GType gsecret_service_get_type (void) G_GNUC_CONST; + +GSecretService* gsecret_collection_xxx_new (void); + +GSecretPrompt* gsecret_prompt_instance (GDBusConnection *connection, + const gchar *object_path, + GError **error); + +GSecretPrompt* gsecret_prompt_instance_sync (GDBusConnection *connection, + const gchar *object_path); + + gsecret_prompt_perform + gsecret_prompt_dismiss + +G_END_DECLS + +#endif /* __G_SERVICE_H___ */ diff --git a/library/gsecret-service.c b/library/gsecret-service.c new file mode 100644 index 0000000..3c4beda --- /dev/null +++ b/library/gsecret-service.c @@ -0,0 +1,691 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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. + */ + +#include "config.h" + +#include "gsecret-private.h" +#include "gsecret-service.h" +#include "gsecret-types.h" +#include "gsecret-value.h" + +#include +#include + +#include + +#include "egg/egg-dh.h" +#include "egg/egg-hkdf.h" +#include "egg/egg-secure-memory.h" + +EGG_SECURE_GLIB_DEFINITIONS (); + +EGG_SECURE_DECLARE (secret_service); + +typedef struct { + gchar *path; + gcry_mpi_t prime; + gcry_mpi_t privat; + gcry_mpi_t publi; + gpointer key; + gsize n_key; +} GSecretSession; + +struct _GSecretServicePrivate { + gpointer session; +}; + +static void +gsecret_session_free (gpointer data) +{ + GSecretSession *session = data; + + if (session == NULL) + return; + + g_free (session->path); + gcry_mpi_release (session->publi); + gcry_mpi_release (session->privat); + gcry_mpi_release (session->prime); + egg_secure_free (session->key); + g_free (session); +} + +static GVariant * +request_open_session_aes (GSecretSession *session) +{ + gcry_error_t gcry; + gcry_mpi_t base; + unsigned char *buffer; + size_t n_buffer; + GVariant *argument; + + g_assert (session->prime == NULL); + g_assert (session->privat == NULL); + g_assert (session->publi == NULL); + + /* Initialize our local parameters and values */ + if (!egg_dh_default_params ("ietf-ike-grp-modp-1024", + &session->prime, &base)) + g_return_val_if_reached (NULL); + if (!egg_dh_gen_pair (session->prime, base, 0, + &session->publi, &session->privat)) + g_return_val_if_reached (NULL); + gcry_mpi_release (base); + + gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer, session->publi); + g_return_val_if_fail (gcry == 0, NULL); + argument = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), + buffer, n_buffer, TRUE, + gcry_free, buffer); + + return g_variant_new ("sv", "dh-ietf1024-sha256-aes128-cbc-pkcs7", argument); +} + +static gboolean +response_open_session_aes (GSecretSession *session, + GVariant *response) +{ + gconstpointer buffer; + GVariant *argument; + gsize n_buffer; + gcry_mpi_t peer; + gcry_error_t gcry; + gpointer ikm; + gsize n_ikm; + + if (G_VARIANT_TYPE ("vo") != g_variant_get_type (response)) { + g_warning ("invalid OpenSession() response from daemon with signature: %s", + g_variant_get_type_string (response)); + return FALSE; + } + + g_assert (session->path == NULL); + g_variant_get (response, "vo", &argument, &session->path); + + buffer = g_variant_get_fixed_array (argument, &n_buffer, sizeof (guchar)); + gcry = gcry_mpi_scan (&peer, GCRYMPI_FMT_USG, buffer, n_buffer, NULL); + g_return_val_if_fail (gcry == 0, FALSE); + g_variant_unref (argument); + + ikm = egg_dh_gen_secret (peer, session->privat, session->prime, &n_ikm); + gcry_mpi_release (peer); + + if (ikm == NULL) { + g_warning ("couldn't negotiate a valid AES session key"); + g_free (session->path); + session->path = NULL; + return FALSE; + } + + session->n_key = 16; + session->key = egg_secure_alloc (session->n_key); + if (!egg_hkdf_perform ("sha256", ikm, n_ikm, NULL, 0, NULL, 0, + session->key, session->n_key)) + g_return_val_if_reached (FALSE); + egg_secure_free (ikm); + + return TRUE; +} + +static GVariant * +request_open_session_plain (GSecretSession *session) +{ + GVariant *argument = g_variant_new_string (""); + return g_variant_new ("sv", "plain", argument); +} + +static gboolean +response_open_session_plain (GSecretSession *session, + GVariant *response) +{ + GVariant *argument; + + if (G_VARIANT_TYPE ("vo") != g_variant_get_type (response)) { + g_warning ("invalid OpenSession() response from daemon with signature: %s", + g_variant_get_type_string (response)); + return FALSE; + } + + g_assert (session->path == NULL); + g_variant_get (response, "vo", &argument, &session->path); + g_variant_unref (argument); + + g_assert (session->key == NULL); + g_assert (session->n_key == 0); + + return TRUE; +} + +typedef struct { + GCancellable *cancellable; + GSecretSession *session; +} OpenSessionClosure; + +static void +open_session_closure_free (gpointer data) +{ + OpenSessionClosure *closure = data; + g_assert (closure); + g_clear_object (&closure->cancellable); + gsecret_session_free (closure->session); + g_free (closure); +} + +static void +on_service_open_session_plain (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + OpenSessionClosure *closure = g_simple_async_result_get_op_res_gpointer (res); + GSecretService *self = GSECRET_SERVICE (source); + GError *error = NULL; + GVariant *response; + + response = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, &error); + + /* A successful response, decode it */ + if (response != NULL) { + if (response_open_session_plain (closure->session, response)) { + + /* Set value atomically, in case of race condition */ + if (g_atomic_pointer_compare_and_exchange (&(self->pv->session), + NULL, closure->session)) + closure->session = NULL; /* Service takes ownership */ + + } else { + g_simple_async_result_set_error (res, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL, + _("Couldn't communicate with the secret storage")); + } + + g_simple_async_result_complete (res); + g_variant_unref (response); + + } else { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + } + + g_object_unref (res); +} + +static void +on_service_open_session_aes (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); + OpenSessionClosure * closure = g_simple_async_result_get_op_res_gpointer (res); + GSecretService *self = GSECRET_SERVICE (source); + GError *error = NULL; + GVariant *response; + + response = g_dbus_proxy_call_finish (G_DBUS_PROXY (self), result, &error); + + /* A successful response, decode it */ + if (response != NULL) { + if (response_open_session_aes (closure->session, response)) { + + /* Set value atomically, in case of race condition */ + if (!g_atomic_pointer_compare_and_exchange (&(self->pv->session), + NULL, closure->session)) + closure->session = NULL; /* Service takes ownership */ + + } else { + g_simple_async_result_set_error (res, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL, + _("Couldn't communicate with the secret storage")); + } + + g_simple_async_result_complete (res); + g_variant_unref (response); + + } else { + /* AES session not supported, request a plain session */ + if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED)) { + g_dbus_proxy_call (G_DBUS_PROXY (source), "OpenSession", + request_open_session_plain (closure->session), + G_DBUS_CALL_FLAGS_NONE, -1, + closure->cancellable, on_service_open_session_plain, + g_object_ref (res)); + g_error_free (error); + + /* Other errors result in a failure */ + } else { + g_simple_async_result_take_error (res, error); + g_simple_async_result_complete (res); + } + } + + g_object_unref (res); +} + +void +gsecret_service_ensure_session (GSecretService *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + OpenSessionClosure *closure; + + g_return_if_fail (GSECRET_IS_SERVICE (self)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + gsecret_service_ensure_session); + + /* If we have no session, then request an AES session */ + if (g_atomic_pointer_get (&self->pv->session) == NULL) { + + closure = g_new (OpenSessionClosure, 1); + closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable; + closure->session = g_new (GSecretSession, 1); + g_simple_async_result_set_op_res_gpointer (res, closure, open_session_closure_free); + + g_dbus_proxy_call (G_DBUS_PROXY (self), "OpenSession", + request_open_session_aes (closure->session), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, on_service_open_session_aes, + g_object_ref (res)); + + /* Already have a session */ + } else { + g_simple_async_result_complete_in_idle (res); + } + + g_object_unref (res); +} + +const gchar * +gsecret_service_ensure_session_finish (GSecretService *self, + GAsyncResult *result, + GError **error) +{ + GSecretSession *session; + + g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + gsecret_service_ensure_session), NULL); + + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return NULL; + + /* The session we have should never change once created */ + session = g_atomic_pointer_get (&self->pv->session); + g_assert (session != NULL); + return session->path; +} + +const gchar * +gsecret_service_ensure_session_sync (GSecretService *self, + GCancellable *cancellable, + GError **error) +{ + GVariant *response; + GSecretSession *session; + GError *lerror = NULL; + gboolean complete = FALSE; + + g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* The session we have should never change once created */ + session = g_atomic_pointer_get (&self->pv->session); + if (session != NULL) + return session->path; + + session = g_new0 (GSecretSession, 1); + response = g_dbus_proxy_call_sync (G_DBUS_PROXY (self), "OpenSession", + request_open_session_aes (session), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, &lerror); + + if (response != NULL) { + complete = response_open_session_aes (session, response); + g_variant_unref (response); + + /* AES session not supported, request a plain session */ + } else if (g_error_matches (lerror, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED)) { + g_clear_error (&lerror); + + response = g_dbus_proxy_call_sync (G_DBUS_PROXY (self), "OpenSession", + request_open_session_plain (session), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, &lerror); + + if (response != NULL) { + complete = response_open_session_plain (session, response); + g_variant_unref (response); + } + } + + if (lerror == NULL && !complete) { + g_set_error (&lerror, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL, + _("Couldn't communicate with the secret storage")); + } + + if (lerror != NULL) { + gsecret_session_free (session); + g_propagate_error (error, lerror); + return NULL; + } + + /* Set value atomically, in case of race condition */ + if (!g_atomic_pointer_compare_and_exchange (&(self->pv->session), + NULL, session)) + gsecret_session_free (session); + + /* The session we have should never change once created */ + session = g_atomic_pointer_get (&self->pv->session); + g_assert (session != NULL); + return session->path; +} + +static gboolean +pkcs7_unpad_bytes_in_place (guchar *padded, + gsize *n_padded) +{ + gsize n_pad, i; + + if (*n_padded == 0) + return FALSE; + + n_pad = padded[*n_padded - 1]; + + /* Validate the padding */ + if (n_pad == 0 || n_pad > 16) + return FALSE; + if (n_pad > *n_padded) + return FALSE; + for (i = *n_padded - n_pad; i < *n_padded; ++i) { + if (padded[i] != n_pad) + return FALSE; + } + + /* The last bit of data */ + *n_padded -= n_pad; + + /* Null teriminate as a courtesy */ + padded[*n_padded] = 0; + + return TRUE; +} + +static GSecretValue * +service_decode_aes_secret (GSecretSession *session, + gconstpointer param, + gsize n_param, + gconstpointer value, + gsize n_value, + const gchar *content_type) +{ + gcry_cipher_hd_t cih; + gsize n_padded; + gcry_error_t gcry; + guchar *padded; + gsize pos; + + if (n_param != 16) { + g_message ("received an encrypted secret structure with invalid parameter"); + return NULL; + } + + if (n_value == 0 || n_value % 16 != 0) { + g_message ("received an encrypted secret structure with bad secret length"); + return NULL; + } + + gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0); + if (gcry != 0) { + g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry)); + return NULL; + } + + gcry = gcry_cipher_setiv (cih, param, n_param); + g_return_val_if_fail (gcry == 0, NULL); + + gcry = gcry_cipher_setkey (cih, session->key, session->n_key); + g_return_val_if_fail (gcry == 0, NULL); + + /* Copy the memory buffer */ + n_padded = n_value; + padded = egg_secure_alloc (n_padded); + memcpy (padded, value, n_padded); + + /* Perform the decryption */ + for (pos = 0; pos < n_padded; pos += 16) { + gcry = gcry_cipher_decrypt (cih, (guchar*)padded + pos, 16, NULL, 0); + g_return_val_if_fail (gcry == 0, FALSE); + } + + gcry_cipher_close (cih); + + /* Unpad the resulting value */ + if (!pkcs7_unpad_bytes_in_place (padded, &n_padded)) { + egg_secure_clear (padded, n_padded); + egg_secure_free (padded); + g_message ("received an invalid, unencryptable, or non-utf8 secret"); + return FALSE; + } + + return gsecret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free); +} + +static GSecretValue * +service_decode_plain_secret (GSecretSession *session, + gconstpointer param, + gsize n_param, + gconstpointer value, + gsize n_value, + const gchar *content_type) +{ + if (n_param != 0) { + g_message ("received a plain secret structure with invalid parameter"); + return NULL; + } + + return gsecret_value_new (value, n_value, content_type); +} + +GSecretValue * +_gsecret_service_decode_secret (GSecretService *self, + GVariant *encoded) +{ + GSecretSession *session; + GSecretValue *result; + gconstpointer param; + gconstpointer value; + gchar *session_path; + gchar *content_type; + gsize n_param; + gsize n_value; + GVariant *vparam; + GVariant *vvalue; + + g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (encoded, NULL); + + session = g_atomic_pointer_get (&self->pv->session); + g_return_val_if_fail (session != NULL, NULL); + g_assert (session->path != NULL); + + /* Parsing (oayays) */ + g_variant_get_child (encoded, 0, "o", &session_path); + + if (session_path == NULL || !g_str_equal (session_path, session->path)) { + g_message ("received a secret encoded with wrong session: %s != %s", + session_path, session->path); + g_free (session_path); + return NULL; + } + + vparam = g_variant_get_child_value (encoded, 1); + param = g_variant_get_fixed_array (vparam, &n_param, sizeof (guchar)); + vvalue = g_variant_get_child_value (encoded, 2); + value = g_variant_get_fixed_array (vvalue, &n_value, sizeof (guchar)); + g_variant_get_child (encoded, 3, "s", &content_type); + + if (session->key != NULL) { + result = service_decode_aes_secret (session, param, n_param, + value, n_value, content_type); + } else { + result = service_decode_plain_secret (session, param, n_param, + value, n_value, content_type); + } + + g_variant_unref (vparam); + g_variant_unref (vvalue); + g_free (content_type); + g_free (session_path); + + return result; +} + +static guchar* +pkcs7_pad_bytes_in_secure_memory (gconstpointer secret, + gsize length, + gsize *n_padded) +{ + gsize n_pad; + guchar *padded; + + /* Pad the secret */ + *n_padded = ((length + 16) / 16) * 16; + g_assert (length < *n_padded); + g_assert (*n_padded > 0); + n_pad = *n_padded - length; + g_assert (n_pad > 0 && n_pad <= 16); + padded = egg_secure_alloc (*n_padded); + memcpy (padded, secret, length); + memset (padded + length, n_pad, n_pad); + return padded; +} + +static gboolean +service_encode_aes_secret (GSecretSession *session, + GSecretValue *value, + GVariantBuilder *builder) +{ + gcry_cipher_hd_t cih; + guchar *padded; + gsize n_padded, pos; + gcry_error_t gcry; + gpointer iv; + gconstpointer secret; + gsize n_secret; + GVariant *child; + + g_variant_builder_add (builder, "o", session->path); + + /* Create the cipher */ + gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0); + if (gcry != 0) { + g_warning ("couldn't create AES cipher: %s", gcry_strerror (gcry)); + return FALSE; + } + + secret = gsecret_value_get (value, &n_secret); + + /* Perform the encoding here */ + padded = pkcs7_pad_bytes_in_secure_memory (secret, n_secret, &n_padded); + g_assert (padded != NULL); + + /* Setup the IV */ + iv = g_malloc0 (16); + gcry_create_nonce (iv, 16); + gcry = gcry_cipher_setiv (cih, iv, 16); + g_return_val_if_fail (gcry == 0, FALSE); + + /* Setup the key */ + gcry = gcry_cipher_setkey (cih, session->key, session->n_key); + g_return_val_if_fail (gcry == 0, FALSE); + + /* Perform the encryption */ + for (pos = 0; pos < n_padded; pos += 16) { + gcry = gcry_cipher_encrypt (cih, (guchar*)padded + pos, 16, NULL, 0); + g_return_val_if_fail (gcry == 0, FALSE); + } + + gcry_cipher_close (cih); + + child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), iv, 16, TRUE, g_free, iv); + g_variant_builder_add_value (builder, child); + g_variant_unref (child); + + child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), padded, n_padded, TRUE, egg_secure_free, padded); + g_variant_builder_add_value (builder, child); + g_variant_unref (child); + + g_variant_builder_add (builder, "s", gsecret_value_get_content_type (value)); + return TRUE; +} + +static gboolean +service_encode_plain_secret (GSecretSession *session, + GSecretValue *value, + GVariantBuilder *builder) +{ + gconstpointer secret; + gsize n_secret; + GVariant *child; + + g_variant_builder_add (builder, "o", session->path); + + secret = gsecret_value_get (value, &n_secret); + + child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), "", 0, TRUE, NULL, NULL); + g_variant_builder_add_value (builder, child); + g_variant_unref (child); + + child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), secret, n_secret, TRUE, + gsecret_value_unref, gsecret_value_ref (value)); + g_variant_builder_add_value (builder, child); + g_variant_unref (child); + + g_variant_builder_add (builder, "s", gsecret_value_get_content_type (value)); + return TRUE; +} + +GVariant * +_gsecret_service_encode_secret (GSecretService *self, + GSecretValue *value) +{ + GVariantBuilder *builder; + GSecretSession *session; + GVariant *result = NULL; + GVariantType *type; + gboolean ret; + + g_return_val_if_fail (GSECRET_IS_SERVICE (self), NULL); + g_return_val_if_fail (value, NULL); + + session = g_atomic_pointer_get (&self->pv->session); + g_return_val_if_fail (session != NULL, NULL); + g_assert (session->path != NULL); + + type = g_variant_type_new ("(oayays)"); + builder = g_variant_builder_new (type); + + if (session->key) + ret = service_encode_aes_secret (session, value, builder); + else + ret = service_encode_plain_secret (session, value, builder); + if (ret) + result = g_variant_builder_end (builder); + + g_variant_builder_unref (builder); + g_variant_type_free (type); + return result; +} diff --git a/library/gsecret-service.h b/library/gsecret-service.h new file mode 100644 index 0000000..5a00df5 --- /dev/null +++ b/library/gsecret-service.h @@ -0,0 +1,192 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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 __GSECRET_SERVICE_H__ +#define __GSECRET_SERVICE_H__ + +#include + +G_BEGIN_DECLS + +#define GSECRET_TYPE_SERVICE (gsecret_service_get_type ()) +#define GSECRET_SERVICE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), GSECRET_TYPE_SERVICE, GSecretService)) +#define GSECRET_SERVICE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), GSECRET_TYPE_SERVICE, GSecretServiceClass)) +#define GSECRET_IS_SERVICE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), GSECRET_TYPE_SERVICE)) +#define GSECRET_IS_SERVICE_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), GSECRET_TYPE_SERVICE)) +#define GSECRET_SERVICE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), GSECRET_TYPE_SERVICE, GSecretServiceClass)) + +typedef struct _GSecretService GSecretService; +typedef struct _GSecretServiceClass GSecretServiceClass; +typedef struct _GSecretServicePrivate GSecretServicePrivate; + +struct _GSecretServiceClass { + GDBusProxyClass parent_class; + + GType collection_type; + GType item_type; + +#if 0 + padding; +#endif +}; + +struct _GSecretService { + GDBusProxy parent_instance; + GSecretServicePrivate *pv; +}; + +GType gsecret_service_get_type (void) G_GNUC_CONST; + +#if 0 +void gsecret_service_get (GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GSecretService* gsecret_service_get_finish (GAsyncResult *result, + GError **error); + +GSecretService* gsecret_service_get_sync (GAsyncResult *result, + GError **error); + +void gsecret_service_instance (GDBusConnection *connection, + const gchar *object_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GSecretService * gsecret_service_instance_finish (GAsyncResult *result, + GError **error); + +GSecretService * gsecret_service_instance_sync (GDBusConnection *connection, + const gchar *object_path, + GCancellable *cancellable, + GError **error); +#endif + +void gsecret_service_ensure_session (GSecretService *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +const gchar * gsecret_service_ensure_session_finish (GSecretService *self, + GAsyncResult *result, + GError **error); + +const gchar * gsecret_service_ensure_session_sync (GSecretService *self, + GCancellable *cancellable, + GError **error); + +#if 0 +void gsecret_service_search (GSecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gsecret_service_search_finish (GSecretService *self, + GAsyncResult *result, + GList **unlocked, + GList **locked, + GError **error); + +gboolean gsecret_service_search_sync (GSecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + GList **unlocked, + GList **locked, + GError **error); + +void gsecret_service_search_for_paths (GSecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gsecret_service_search_for_paths_finish (GSecretService *self, + GAsyncResult *result, + gchar ***unlocked, + gchar ***locked, + GError **error); + +gboolean gsecret_service_search_for_paths_sync (GSecretService *self, + GHashTable *attributes, + GCancellable *cancellable, + gchar ***unlocked, + gchar ***locked, + GError **error); + +void gsecret_service_lock (GSecretService *self, + GList *objects, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gsecret_service_lock_finish (GSecretService *self, + GAsyncResult *result, + GList **locked, + GSecretPrompt *prompt, + GError **error); + +void gsecret_service_lock_sync (GSecretService *self, + GList *objects, + GCancellable *cancellable, + GList **locked, + GSecretPrompt *prompt, + GError **error); + +void gsecret_service_unlock (GSecretService *self, + GList *objects, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gsecret_service_ + GList **unlocked, + GSecretPrompt *prompt, + GError **error); + +gboolean gsecret_service_unlock (GSecretService *self, + GList *objects, + GList **unlocked, + GSecretPrompt *prompt, + GError **error); + +gboolean gsecret_service_unlock_for_paths (GSecretService *self, + GList *objects, + GList **unlocked, + GSecretPrompt *prompt, + GError **error); + +GHashTable* gsecret_service_get_secrets (GList *items, + GError **error); + +GHashTable* gsecret_service_get_secrets_for_paths (GList *items, + GError **error); + +gsecret_collection_create_collection + +GList* gsecret_service_get_collections + +GSecretCollection* gsecret_service_read_alias (GSecretService *self, + const gchar *alias, + GError **error); + +GSecretCollection* gsecret_service_set_alias (GSecretService *self, + const gchar *alias, + GSecretCollection *collection, + GError **error); + +#endif + +G_END_DECLS + +#endif /* __G_SERVICE_H___ */ diff --git a/library/gsecret-types.h b/library/gsecret-types.h new file mode 100644 index 0000000..eadfd87 --- /dev/null +++ b/library/gsecret-types.h @@ -0,0 +1,30 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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 __GSECRET_TYPES_H__ +#define __GSECRET_TYPES_H__ + +#include + +G_BEGIN_DECLS + +#define GSECRET_ERROR (gsecret_error_get_quark ()) + +GQuark gsecret_error_get_quark (void) G_GNUC_CONST; + +typedef enum { + GSECRET_ERROR_PROTOCOL = 1, +} GSecretError; + +G_END_DECLS + +#endif /* __G_SERVICE_H___ */ diff --git a/library/gsecret-util.c b/library/gsecret-util.c new file mode 100644 index 0000000..fe1bb21 --- /dev/null +++ b/library/gsecret-util.c @@ -0,0 +1,32 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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. + */ + +#include "config.h" + +#include "gsecret-private.h" + +#include + +gchar * +_gsecret_util_parent_path (const gchar *path) +{ + const gchar *pos; + + g_return_val_if_fail (path != NULL, NULL); + + pos = strrchr (path, '/'); + g_return_val_if_fail (pos != NULL, NULL); + g_return_val_if_fail (pos != path, NULL); + + pos--; + return g_strndup (path, pos - path); +} diff --git a/library/gsecret-value.c b/library/gsecret-value.c new file mode 100644 index 0000000..a521ed3 --- /dev/null +++ b/library/gsecret-value.c @@ -0,0 +1,122 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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. + */ + +#include "config.h" + +#include "gsecret-value.h" + +#include "egg/egg-secure-memory.h" + +#include + +EGG_SECURE_DECLARE (gsecret_value); + +struct _GSecretValue { + gint refs; + gpointer secret; + gsize length; + GDestroyNotify destroy; + gchar *content_type; +}; + +GType +gsecret_value_get_type (void) +{ + static gsize initialized = 0; + static GType type = 0; + + if (g_once_init_enter (&initialized)) { + type = g_boxed_type_register_static ("GSecretValue", + (GBoxedCopyFunc)gsecret_value_ref, + (GBoxedFreeFunc)gsecret_value_unref); + g_once_init_leave (&initialized, 1); + } + + return type; +} + +GSecretValue* +gsecret_value_new (const gchar *secret, gssize length, const gchar *content_type) +{ + gchar *copy; + + g_return_val_if_fail (!secret && length, NULL); + g_return_val_if_fail (content_type, NULL); + + if (length < 0) + length = strlen (secret); + + copy = egg_secure_alloc (length + 1); + memcpy (copy, secret, length); + copy[length] = 0; + return gsecret_value_new_full (copy, length, content_type, egg_secure_free); +} + +GSecretValue* +gsecret_value_new_full (gchar *secret, gssize length, + const gchar *content_type, GDestroyNotify destroy) +{ + GSecretValue *value; + + g_return_val_if_fail (!secret && length, NULL); + g_return_val_if_fail (content_type, NULL); + + if (length < 0) + length = strlen (secret); + + value = g_slice_new0 (GSecretValue); + value->content_type = strdup (content_type); + value->destroy = destroy; + value->length = length; + value->secret = secret; + + return value; +} + +const gchar* +gsecret_value_get (GSecretValue *value, gsize *length) +{ + g_return_val_if_fail (value, NULL); + if (length) + *length = value->length; + return value->secret; +} + +const gchar* +gsecret_value_get_content_type (GSecretValue *value) +{ + g_return_val_if_fail (value, NULL); + return value->content_type; +} + +GSecretValue* +gsecret_value_ref (GSecretValue *value) +{ + g_return_val_if_fail (value, NULL); + g_atomic_int_inc (&value->refs); + return value; +} + +void +gsecret_value_unref (gpointer value) +{ + GSecretValue *val = value; + + g_return_if_fail (value); + + if (g_atomic_int_dec_and_test (&val->refs)) { + g_free (val->content_type); + if (val->destroy) + (val->destroy) (val->secret); + g_slice_free (GSecretValue, val); + } +} diff --git a/library/gsecret-data.h b/library/gsecret-value.h similarity index 57% rename from library/gsecret-data.h rename to library/gsecret-value.h index 2ab9a4d..ebaa3d3 100644 --- a/library/gsecret-data.h +++ b/library/gsecret-value.h @@ -10,36 +10,36 @@ * See the included COPYING file for more information. */ -#ifndef __GSECRET_DATA_H__ -#define __GSECRET_DATA_H__ +#ifndef __GSECRET_VALUE_H__ +#define __GSECRET_VALUE_H__ #include G_BEGIN_DECLS -#define GSECRET_TYPE_DATA (gsecret_service_get_type ()) +#define GSECRET_TYPE_VALUE (gsecret_service_get_type ()) -typedef struct _GSecretData GSecretData; +typedef struct _GSecretValue GSecretValue; -GType gsecret_data_get_type (void) G_GNUC_CONST; +GType gsecret_value_get_type (void) G_GNUC_CONST; -GSecretData* gsecret_data_new (const gchar *secret, +GSecretValue* gsecret_value_new (const gchar *secret, gssize length, const gchar *content_type); -GSecretData* gsecret_data_new_full (gchar *secret, +GSecretValue* gsecret_value_new_full (gchar *secret, gssize length, const gchar *content_type, GDestroyNotify destroy); -const gchar* gsecret_data_get (GSecretData *data, +const gchar* gsecret_value_get (GSecretValue *value, gsize *length); -const gchar* gsecret_data_get_content_type (GSecretData *data); +const gchar* gsecret_value_get_content_type (GSecretValue *value); -GSecretData* gsecret_data_ref (GSecretData *data); +GSecretValue* gsecret_value_ref (GSecretValue *value); -void gsecret_data_unref (GSecretData *data); +void gsecret_value_unref (gpointer value); G_END_DECLS diff --git a/library/tests/Makefile.am b/library/tests/Makefile.am new file mode 100644 index 0000000..4bce55f --- /dev/null +++ b/library/tests/Makefile.am @@ -0,0 +1,27 @@ +include $(top_srcdir)/Makefile.decl + +INCLUDES = \ + -I$(top_srcdir)/library \ + $(NULL) + +LDADD = \ + $(top_builddir)/egg/libegg.la \ + $(top_builddir)/library/libgsecret.la \ + $(NULL) + +TEST_PROGS = \ + test-initial \ + $(NULL) + +check_PROGRAMS = \ + $(TEST_PROGS) + +noinst_PROGRAMS = \ + $(NULL) + +test: $(TEST_PROGS) + gtester -k --verbose $(TEST_PROGS) + +all-local: $(check_PROGRAMS) + +check-local: test \ No newline at end of file diff --git a/library/tests/test-initial.c b/library/tests/test-initial.c new file mode 100644 index 0000000..2be82ca --- /dev/null +++ b/library/tests/test-initial.c @@ -0,0 +1,39 @@ +/* GSecret - GLib wrapper for Secret Service + * + * Copyright 2011 Collabora Ltd. + * + * 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. + */ + + +#include "config.h" + +#include "gsecret-item.h" +#include "gsecret-service.h" + +#include + +static void +test_initial (void) +{ + GType type; + + type = gsecret_service_get_type (); + type += gsecret_item_get_type (); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_set_prgname ("test-other"); + + g_test_add_func ("/initial", test_initial); + + return g_test_run (); +} -- 2.7.4