More Implementation of GSecretService session related code.
authorStef Walter <stefw@gnome.org>
Sun, 25 Sep 2011 06:22:36 +0000 (08:22 +0200)
committerStef Walter <stefw@collabora.co.uk>
Sun, 25 Sep 2011 06:22:36 +0000 (08:22 +0200)
26 files changed:
.gitignore
Makefile.decl
autogen.sh
configure.ac
egg/Makefile.am
egg/egg-dh.c [new file with mode: 0644]
egg/egg-dh.h [new file with mode: 0644]
egg/egg-hkdf.c [new file with mode: 0644]
egg/egg-hkdf.h [new file with mode: 0644]
egg/egg-secure-memory.c
egg/egg-secure-memory.h
library/Makefile.am
library/gsecret-collection.h [new file with mode: 0644]
library/gsecret-data.c [deleted file]
library/gsecret-item.c [new file with mode: 0644]
library/gsecret-item.h [new file with mode: 0644]
library/gsecret-private.h [new file with mode: 0644]
library/gsecret-prompt.h [new file with mode: 0644]
library/gsecret-service.c [new file with mode: 0644]
library/gsecret-service.h [new file with mode: 0644]
library/gsecret-types.h [new file with mode: 0644]
library/gsecret-util.c [new file with mode: 0644]
library/gsecret-value.c [new file with mode: 0644]
library/gsecret-value.h [moved from library/gsecret-data.h with 57% similarity]
library/tests/Makefile.am [new file with mode: 0644]
library/tests/test-initial.c [new file with mode: 0644]

index 9fbbe47..baaae47 100644 (file)
@@ -22,5 +22,8 @@ Makefile.in
 Makefile.in.in
 missing
 stamp*
+.settings
+.project
+.cproject
 
 /po/POTFILES
index e69de29..86f0b1c 100644 (file)
@@ -0,0 +1 @@
+NULL =
index 971b9a4..3773941 100755 (executable)
@@ -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
 
index f27984e..11a040a 100644 (file)
@@ -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
index 7c3993d..b70bf52 100644 (file)
@@ -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 (file)
index 0000000..85dec77
--- /dev/null
@@ -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 (file)
index 0000000..ee315e2
--- /dev/null
@@ -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 <glib.h>
+
+#include <gcrypt.h>
+
+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 (file)
index 0000000..a55ee5d
--- /dev/null
@@ -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 <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "egg-hkdf.h"
+#include "egg-secure-memory.h"
+
+#include <gcrypt.h>
+
+#include <string.h>
+
+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 (file)
index 0000000..430d331
--- /dev/null
@@ -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 <stefw@collabora.co.uk>
+ */
+
+#ifndef EGG_HKDF_H_
+#define EGG_HKDF_H_
+
+#include <glib.h>
+
+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_ */
index f699203..ab63d45 100644 (file)
@@ -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);
 }
index 85ce1f6..682811d 100644 (file)
@@ -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 */
index 416b85a..c7c79a4 100644 (file)
@@ -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 (file)
index 0000000..61f03a5
--- /dev/null
@@ -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 <gio/gio.h>
+
+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 (file)
index c17bb11..0000000
+++ /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 <string.h>
-
-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 (file)
index 0000000..3bed218
--- /dev/null
@@ -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 <glib/gi18n-lib.h>
+
+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 (file)
index 0000000..8ec1e00
--- /dev/null
@@ -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 <gio/gio.h>
+
+#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 (file)
index 0000000..e8f5bac
--- /dev/null
@@ -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 <gio/gio.h>
+
+#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 (file)
index 0000000..cb43339
--- /dev/null
@@ -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 <gio/gio.h>
+
+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 (file)
index 0000000..3c4beda
--- /dev/null
@@ -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 <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <gcrypt.h>
+
+#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 (file)
index 0000000..5a00df5
--- /dev/null
@@ -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 <gio/gio.h>
+
+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 (file)
index 0000000..eadfd87
--- /dev/null
@@ -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 <glib.h>
+
+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 (file)
index 0000000..fe1bb21
--- /dev/null
@@ -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 <string.h>
+
+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 (file)
index 0000000..a521ed3
--- /dev/null
@@ -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 <string.h>
+
+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);
+       }
+}
similarity index 57%
rename from library/gsecret-data.h
rename to library/gsecret-value.h
index 2ab9a4d..ebaa3d3 100644 (file)
  * 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 <gio/gio.h>
 
 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 (file)
index 0000000..4bce55f
--- /dev/null
@@ -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 (file)
index 0000000..2be82ca
--- /dev/null
@@ -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 <glib.h>
+
+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 ();
+}