More Implementation of GSecretService session related code.

This commit is contained in:
Stef Walter 2011-09-25 08:22:36 +02:00 committed by Stef Walter
parent 3dfd7aa70f
commit b1b54f525d
26 changed files with 2519 additions and 264 deletions

3
.gitignore vendored
View File

@ -22,5 +22,8 @@ Makefile.in
Makefile.in.in Makefile.in.in
missing missing
stamp* stamp*
.settings
.project
.cproject
/po/POTFILES /po/POTFILES

View File

@ -0,0 +1 @@
NULL =

View File

@ -8,7 +8,7 @@ ORIGDIR=`pwd`
cd $srcdir cd $srcdir
PROJECT=gsecret PROJECT=gsecret
TEST_TYPE=-f TEST_TYPE=-f
FILE=library/gsecret-data.c FILE=library/gsecret-value.c
DIE=0 DIE=0

View 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_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]) AC_CONFIG_HEADERS([config.h])
dnl Other initialization dnl Other initialization
@ -70,10 +70,12 @@ fi
dnl ***************************** dnl *****************************
dnl *** done *** dnl *** done ***
dnl ***************************** dnl *****************************
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([
egg/Makefile Makefile
po/Makefile.in egg/Makefile
po/Makefile po/Makefile.in
library/Makefile po/Makefile
]) library/Makefile
library/tests/Makefile
])
AC_OUTPUT AC_OUTPUT

View File

@ -6,5 +6,7 @@ INCLUDES = \
-I$(top_srcdir) -I$(top_srcdir)
libegg_la_SOURCES = \ libegg_la_SOURCES = \
egg-dh.c egg-dh.h \
egg-hkdf.c egg-hkdf.h \
egg-secure-memory.c egg-secure-memory.h \ egg-secure-memory.c egg-secure-memory.h \
$(BUILT_SOURCES) $(BUILT_SOURCES)

353
egg/egg-dh.c Normal file
View File

@ -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;
}

50
egg/egg-dh.h Normal file
View File

@ -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_ */

109
egg/egg-hkdf.c Normal file
View File

@ -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;
}

39
egg/egg-hkdf.h Normal file
View File

@ -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_ */

View File

@ -97,20 +97,22 @@ typedef void* word_t;
typedef struct _Cell { typedef struct _Cell {
word_t *words; /* Pointer to secure memory */ word_t *words; /* Pointer to secure memory */
size_t n_words; /* Amount of secure memory in words */ size_t n_words; /* Amount of secure memory in words */
size_t allocated; /* Amount actually requested by app, in bytes, 0 if unused */ size_t requested; /* Amount actually requested by app, in bytes, 0 if unused */
struct _Cell *next; /* Next in unused memory ring, or NULL if used */ const char *tag; /* Tag which describes the allocation */
struct _Cell *prev; /* Previous in unused memory ring, or NULL if used */ struct _Cell *next; /* Next in memory ring */
struct _Cell *prev; /* Previous in memory ring */
} Cell; } Cell;
/* /*
* A block of secure memory. This structure is the header in that block. * A block of secure memory. This structure is the header in that block.
*/ */
typedef struct _Block { typedef struct _Block {
word_t *words; /* Actual memory hangs off here */ word_t *words; /* Actual memory hangs off here */
size_t n_words; /* Number of words in block */ size_t n_words; /* Number of words in block */
size_t used; /* Number of used allocations */ size_t n_used; /* Number of used allocations */
struct _Cell* unused; /* Ring of unused allocations */ struct _Cell* used_cells; /* Ring of used allocations */
struct _Block *next; /* Next block in list */ struct _Cell* unused_cells; /* Ring of unused allocations */
struct _Block *next; /* Next block in list */
} Block; } Block;
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
@ -263,6 +265,8 @@ pool_free (void* item)
unused_push (&pool->unused, item); unused_push (&pool->unused, item);
} }
#ifndef G_DISABLE_ASSERT
static int static int
pool_valid (void* item) pool_valid (void* item)
{ {
@ -282,6 +286,8 @@ pool_valid (void* item)
return 0; return 0;
} }
#endif /* G_DISABLE_ASSERT */
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* SEC ALLOCATION * SEC ALLOCATION
* *
@ -459,7 +465,9 @@ sec_neighbor_after (Block *block, Cell *cell)
} }
static void* static void*
sec_alloc (Block *block, size_t length) sec_alloc (Block *block,
const char *tag,
size_t length)
{ {
Cell *cell, *other; Cell *cell, *other;
size_t n_words; size_t n_words;
@ -467,8 +475,9 @@ sec_alloc (Block *block, size_t length)
ASSERT (block); ASSERT (block);
ASSERT (length); ASSERT (length);
ASSERT (tag);
if (!block->unused) if (!block->unused_cells)
return NULL; return NULL;
/* /*
@ -482,10 +491,10 @@ sec_alloc (Block *block, size_t length)
n_words = sec_size_to_words (length) + 2; n_words = sec_size_to_words (length) + 2;
/* Look for a cell of at least our required size */ /* Look for a cell of at least our required size */
cell = block->unused; cell = block->unused_cells;
while (cell->n_words < n_words) { while (cell->n_words < n_words) {
cell = cell->next; cell = cell->next;
if (cell == block->unused) { if (cell == block->unused_cells) {
cell = NULL; cell = NULL;
break; break;
} }
@ -493,8 +502,9 @@ sec_alloc (Block *block, size_t length)
if (!cell) if (!cell)
return NULL; return NULL;
ASSERT (cell->allocated == 0); ASSERT (cell->tag == NULL);
ASSERT (cell->requested == 0);
ASSERT (cell->prev); ASSERT (cell->prev);
ASSERT (cell->words); ASSERT (cell->words);
sec_check_guards (cell); sec_check_guards (cell);
@ -516,10 +526,12 @@ sec_alloc (Block *block, size_t length)
} }
if (cell->next) if (cell->next)
sec_remove_cell_ring (&block->unused, cell); sec_remove_cell_ring (&block->unused_cells, cell);
++block->used; ++block->n_used;
cell->allocated = length; cell->tag = tag;
cell->requested = length;
sec_insert_cell_ring (&block->used_cells, cell);
memory = sec_cell_to_memory (cell); memory = sec_cell_to_memory (cell);
#ifdef WITH_VALGRIND #ifdef WITH_VALGRIND
@ -555,16 +567,19 @@ sec_free (Block *block, void *memory)
#endif #endif
sec_check_guards (cell); sec_check_guards (cell);
sec_clear_memory (memory, 0, cell->allocated); sec_clear_memory (memory, 0, cell->requested);
sec_check_guards (cell); sec_check_guards (cell);
ASSERT (cell->next == NULL); ASSERT (cell->requested > 0);
ASSERT (cell->prev == NULL); ASSERT (cell->tag != NULL);
ASSERT (cell->allocated > 0);
/* Remove from the used cell ring */
sec_remove_cell_ring (&block->used_cells, cell);
/* Find previous unallocated neighbor, and merge if possible */ /* Find previous unallocated neighbor, and merge if possible */
other = sec_neighbor_before (block, cell); 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); ASSERT (other->next && other->prev);
other->n_words += cell->n_words; other->n_words += cell->n_words;
sec_write_guards (other); sec_write_guards (other);
@ -574,12 +589,13 @@ sec_free (Block *block, void *memory)
/* Find next unallocated neighbor, and merge if possible */ /* Find next unallocated neighbor, and merge if possible */
other = sec_neighbor_after (block, cell); 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); ASSERT (other->next && other->prev);
other->n_words += cell->n_words; other->n_words += cell->n_words;
other->words = cell->words; other->words = cell->words;
if (cell->next) if (cell->next)
sec_remove_cell_ring (&block->unused, cell); sec_remove_cell_ring (&block->unused_cells, cell);
sec_write_guards (other); sec_write_guards (other);
pool_free (cell); pool_free (cell);
cell = other; cell = other;
@ -587,25 +603,30 @@ sec_free (Block *block, void *memory)
/* Add to the unused list if not already there */ /* Add to the unused list if not already there */
if (!cell->next) if (!cell->next)
sec_insert_cell_ring (&block->unused, cell); sec_insert_cell_ring (&block->unused_cells, cell);
cell->allocated = 0; cell->tag = NULL;
--block->used; cell->requested = 0;
--block->n_used;
return NULL; return NULL;
} }
static void* 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; Cell *cell, *other;
word_t *word; word_t *word;
size_t n_words; size_t n_words;
size_t valid; size_t valid;
void *alloc; void *alloc;
/* Standard realloc behavior, should have been handled elsewhere */ /* Standard realloc behavior, should have been handled elsewhere */
ASSERT (memory != NULL); ASSERT (memory != NULL);
ASSERT (length > 0); ASSERT (length > 0);
ASSERT (tag != NULL);
/* Dig out where the meta should be */ /* Dig out where the meta should be */
word = memory; word = memory;
@ -621,13 +642,12 @@ sec_realloc (Block *block, void *memory, size_t length)
/* Validate that it's actually for real */ /* Validate that it's actually for real */
sec_check_guards (cell); sec_check_guards (cell);
ASSERT (cell->allocated > 0); ASSERT (cell->requested > 0);
ASSERT (cell->next == NULL); ASSERT (cell->tag != NULL);
ASSERT (cell->prev == NULL);
/* The amount of valid data */ /* The amount of valid data */
valid = cell->allocated; valid = cell->requested;
/* How many words we actually want */ /* How many words we actually want */
n_words = sec_size_to_words (length) + 2; 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) { if (n_words <= cell->n_words) {
/* TODO: No shrinking behavior yet */ /* TODO: No shrinking behavior yet */
cell->allocated = length; cell->requested = length;
alloc = sec_cell_to_memory (cell); alloc = sec_cell_to_memory (cell);
#ifdef WITH_VALGRIND #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 */ /* See if we have a neighbor who can give us some memory */
other = sec_neighbor_after (block, cell); other = sec_neighbor_after (block, cell);
if (!other || other->allocated != 0) if (!other || other->requested != 0)
break; break;
/* Eat the whole neighbor if not too big */ /* Eat the whole neighbor if not too big */
if (n_words - cell->n_words + WASTE >= other->n_words) { if (n_words - cell->n_words + WASTE >= other->n_words) {
cell->n_words += other->n_words; cell->n_words += other->n_words;
sec_write_guards (cell); sec_write_guards (cell);
sec_remove_cell_ring (&block->unused, other); sec_remove_cell_ring (&block->unused_cells, other);
pool_free (other); pool_free (other);
/* Steal from the neighbor */ /* Steal from the neighbor */
@ -679,18 +699,19 @@ sec_realloc (Block *block, void *memory, size_t length)
} }
if (cell->n_words >= n_words) { if (cell->n_words >= n_words) {
cell->allocated = length; cell->requested = length;
cell->tag = tag;
alloc = sec_cell_to_memory (cell); alloc = sec_cell_to_memory (cell);
#ifdef WITH_VALGRIND #ifdef WITH_VALGRIND
VALGRIND_MAKE_MEM_DEFINED (alloc, length); VALGRIND_MAKE_MEM_DEFINED (alloc, length);
#endif #endif
return sec_clear_memory (alloc, valid, length); return sec_clear_memory (alloc, valid, length);
} }
/* That didn't work, try alloc/free */ /* That didn't work, try alloc/free */
alloc = sec_alloc (block, length); alloc = sec_alloc (block, tag, length);
if (alloc) { if (alloc) {
memcpy (alloc, memory, valid); memcpy (alloc, memory, valid);
sec_free (block, memory); sec_free (block, memory);
@ -722,15 +743,14 @@ sec_allocated (Block *block, void *memory)
cell = *word; cell = *word;
sec_check_guards (cell); sec_check_guards (cell);
ASSERT (cell->next == NULL); ASSERT (cell->requested > 0);
ASSERT (cell->prev == NULL); ASSERT (cell->tag != NULL);
ASSERT (cell->allocated > 0);
#ifdef WITH_VALGRIND #ifdef WITH_VALGRIND
VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t)); VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
#endif #endif
return cell->allocated; return cell->requested;
} }
static void static void
@ -753,15 +773,19 @@ sec_validate (Block *block)
sec_check_guards (cell); sec_check_guards (cell);
/* Is it an allocated block? */ /* Is it an allocated block? */
if (cell->allocated > 0) { if (cell->requested > 0) {
ASSERT (cell->next == NULL); ASSERT (cell->tag != NULL);
ASSERT (cell->prev == NULL); ASSERT (cell->next != NULL);
ASSERT (cell->allocated <= (cell->n_words - 2) * sizeof (word_t)); 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 */ /* An unused block */
} else { } else {
ASSERT (cell->next); ASSERT (cell->tag == NULL);
ASSERT (cell->prev); ASSERT (cell->next != NULL);
ASSERT (cell->prev != NULL);
ASSERT (cell->next->prev == cell); ASSERT (cell->next->prev == cell);
ASSERT (cell->prev->next == cell); ASSERT (cell->prev->next == cell);
} }
@ -777,13 +801,15 @@ sec_validate (Block *block)
*/ */
static void* static void*
sec_acquire_pages (size_t *sz) sec_acquire_pages (size_t *sz,
const char *during_tag)
{ {
void *pages; void *pages;
unsigned long pgsize; unsigned long pgsize;
ASSERT (sz); ASSERT (sz);
ASSERT (*sz); ASSERT (*sz);
ASSERT (during_tag);
/* Make sure sz is a multiple of the page size */ /* Make sure sz is a multiple of the page size */
pgsize = getpagesize (); 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); pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (pages == MAP_FAILED) { if (pages == MAP_FAILED) {
if (lock_warning && egg_secure_warnings) if (lock_warning && egg_secure_warnings)
fprintf (stderr, "couldn't map %lu bytes of private memory: %s\n", fprintf (stderr, "couldn't map %lu bytes of memory (%s): %s\n",
(unsigned long)*sz, strerror (errno)); (unsigned long)*sz, during_tag, strerror (errno));
lock_warning = 0; lock_warning = 0;
return NULL; return NULL;
} }
if (mlock (pages, *sz) < 0) { if (mlock (pages, *sz) < 0) {
if (lock_warning && egg_secure_warnings && errno != EPERM) { if (lock_warning && egg_secure_warnings && errno != EPERM) {
fprintf (stderr, "couldn't lock %lu bytes of private memory: %s\n", fprintf (stderr, "couldn't lock %lu bytes of memory (%s): %s\n",
(unsigned long)*sz, strerror (errno)); (unsigned long)*sz, during_tag, strerror (errno));
lock_warning = 0; lock_warning = 0;
} }
munmap (pages, *sz); munmap (pages, *sz);
@ -850,11 +876,14 @@ sec_release_pages (void *pages, size_t sz)
static Block *all_blocks = NULL; static Block *all_blocks = NULL;
static Block* static Block*
sec_block_create (size_t size) sec_block_create (size_t size,
const char *during_tag)
{ {
Block *block; Block *block;
Cell *cell; Cell *cell;
ASSERT (during_tag);
#if FORCE_FALLBACK_MEMORY #if FORCE_FALLBACK_MEMORY
/* We can force all all memory to be malloced */ /* We can force all all memory to be malloced */
return NULL; return NULL;
@ -874,7 +903,7 @@ sec_block_create (size_t size)
if (size < DEFAULT_BLOCK_SIZE) if (size < DEFAULT_BLOCK_SIZE)
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); block->n_words = size / sizeof (word_t);
if (!block->words) { if (!block->words) {
pool_free (block); pool_free (block);
@ -889,10 +918,10 @@ sec_block_create (size_t size)
/* The first cell to allocate from */ /* The first cell to allocate from */
cell->words = block->words; cell->words = block->words;
cell->n_words = block->n_words; cell->n_words = block->n_words;
cell->allocated = 0; cell->requested = 0;
sec_write_guards (cell); sec_write_guards (cell);
sec_insert_cell_ring (&block->unused, cell); sec_insert_cell_ring (&block->unused_cells, cell);
block->next = all_blocks; block->next = all_blocks;
all_blocks = block; all_blocks = block;
@ -907,7 +936,7 @@ sec_block_destroy (Block *block)
ASSERT (block); ASSERT (block);
ASSERT (block->words); ASSERT (block->words);
ASSERT (block->used == 0); ASSERT (block->n_used == 0);
/* Remove from the list */ /* Remove from the list */
for (at = &all_blocks, bl = *at; bl; at = &bl->next, bl = *at) { 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 */ /* Must have been found */
ASSERT (bl == block); ASSERT (bl == block);
ASSERT (block->used_cells == NULL);
/* Release all the meta data cells */ /* Release all the meta data cells */
while (block->unused) { while (block->unused_cells) {
cell = block->unused; cell = block->unused_cells;
sec_remove_cell_ring (&block->unused, cell); sec_remove_cell_ring (&block->unused_cells, cell);
pool_free (cell); pool_free (cell);
} }
@ -938,17 +968,16 @@ sec_block_destroy (Block *block)
*/ */
void* void*
egg_secure_alloc (size_t length) egg_secure_alloc_full (const char *tag,
{ size_t length,
return egg_secure_alloc_full (length, GKR_SECURE_USE_FALLBACK); int flags)
}
void*
egg_secure_alloc_full (size_t length, int flags)
{ {
Block *block; Block *block;
void *memory = NULL; void *memory = NULL;
if (tag == NULL)
tag = "?";
if (length > 0xFFFFFFFF / 2) { if (length > 0xFFFFFFFF / 2) {
if (egg_secure_warnings) if (egg_secure_warnings)
fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", 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 (); DO_LOCK ();
for (block = all_blocks; block; block = block->next) { for (block = all_blocks; block; block = block->next) {
memory = sec_alloc (block, length); memory = sec_alloc (block, tag, length);
if (memory) if (memory)
break; break;
} }
/* None of the current blocks have space, allocate new */ /* None of the current blocks have space, allocate new */
if (!memory) { if (!memory) {
block = sec_block_create (length); block = sec_block_create (length, tag);
if (block) if (block)
memory = sec_alloc (block, length); memory = sec_alloc (block, tag, length);
} }
#ifdef WITH_VALGRIND #ifdef WITH_VALGRIND
@ -981,8 +1010,8 @@ egg_secure_alloc_full (size_t length, int flags)
#endif #endif
DO_UNLOCK (); DO_UNLOCK ();
if (!memory && (flags & GKR_SECURE_USE_FALLBACK)) { if (!memory && (flags & EGG_SECURE_USE_FALLBACK)) {
memory = egg_memory_fallback (NULL, length); memory = egg_memory_fallback (NULL, length);
if (memory) /* Our returned memory is always zeroed */ if (memory) /* Our returned memory is always zeroed */
memset (memory, 0, length); memset (memory, 0, length);
@ -995,19 +1024,19 @@ egg_secure_alloc_full (size_t length, int flags)
} }
void* void*
egg_secure_realloc (void *memory, size_t length) egg_secure_realloc_full (const char *tag,
{ void *memory,
return egg_secure_realloc_full (memory, length, GKR_SECURE_USE_FALLBACK); size_t length,
} int flags)
void*
egg_secure_realloc_full (void *memory, size_t length, int flags)
{ {
Block *block = NULL; Block *block = NULL;
size_t previous = 0; size_t previous = 0;
int donew = 0; int donew = 0;
void *alloc = NULL; void *alloc = NULL;
if (tag == NULL)
tag = "?";
if (length > 0xFFFFFFFF / 2) { if (length > 0xFFFFFFFF / 2) {
if (egg_secure_warnings) if (egg_secure_warnings)
fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", 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) if (memory == NULL)
return egg_secure_alloc_full (length, flags); return egg_secure_alloc_full (tag, length, flags);
if (!length) { if (!length) {
egg_secure_free_full (memory, flags); egg_secure_free_full (memory, flags);
return NULL; return NULL;
@ -1034,8 +1063,8 @@ egg_secure_realloc_full (void *memory, size_t length, int flags)
VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t)); VALGRIND_FREELIKE_BLOCK (memory, sizeof (word_t));
#endif #endif
alloc = sec_realloc (block, memory, length); alloc = sec_realloc (block, tag, memory, length);
#ifdef WITH_VALGRIND #ifdef WITH_VALGRIND
/* Now tell valgrind about either the new block or old one */ /* Now tell valgrind about either the new block or old one */
VALGRIND_MALLOCLIKE_BLOCK (alloc ? alloc : memory, VALGRIND_MALLOCLIKE_BLOCK (alloc ? alloc : memory,
@ -1050,13 +1079,13 @@ egg_secure_realloc_full (void *memory, size_t length, int flags)
if (block && !alloc) if (block && !alloc)
donew = 1; donew = 1;
if (block && block->used == 0) if (block && block->n_used == 0)
sec_block_destroy (block); sec_block_destroy (block);
DO_UNLOCK (); DO_UNLOCK ();
if (!block) { if (!block) {
if ((flags & GKR_SECURE_USE_FALLBACK)) { if ((flags & EGG_SECURE_USE_FALLBACK)) {
/* /*
* In this case we can't zero the returned memory, * In this case we can't zero the returned memory,
* because we don't know what the block size was. * 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; return NULL;
} }
} }
if (donew) { if (donew) {
alloc = egg_secure_alloc_full (length, flags); alloc = egg_secure_alloc_full (tag, length, flags);
if (alloc) { if (alloc) {
memcpy (alloc, memory, previous); memcpy (alloc, memory, previous);
egg_secure_free_full (memory, flags); egg_secure_free_full (memory, flags);
@ -1088,7 +1117,7 @@ egg_secure_realloc_full (void *memory, size_t length, int flags)
void void
egg_secure_free (void *memory) egg_secure_free (void *memory)
{ {
egg_secure_free_full (memory, GKR_SECURE_USE_FALLBACK); egg_secure_free_full (memory, EGG_SECURE_USE_FALLBACK);
} }
void void
@ -1115,14 +1144,14 @@ egg_secure_free_full (void *memory, int flags)
if (block != NULL) { if (block != NULL) {
sec_free (block, memory); sec_free (block, memory);
if (block->used == 0) if (block->n_used == 0)
sec_block_destroy (block); sec_block_destroy (block);
} }
DO_UNLOCK (); DO_UNLOCK ();
if (!block) { if (!block) {
if ((flags & GKR_SECURE_USE_FALLBACK)) { if ((flags & EGG_SECURE_USE_FALLBACK)) {
egg_memory_fallback (memory, 0); egg_memory_fallback (memory, 0);
} else { } else {
if (egg_secure_warnings) if (egg_secure_warnings)
@ -1164,35 +1193,87 @@ egg_secure_validate (void)
DO_UNLOCK (); 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; Block *block = NULL;
unsigned int total;
*count = 0;
DO_LOCK (); DO_LOCK ();
/* Find out where it belongs to */ for (block = all_blocks; block != NULL; block = block->next) {
for (block = all_blocks; block; block = block->next) { total = 0;
fprintf (stderr, "----------------------------------------------------\n");
fprintf (stderr, " BLOCK at: 0x%08lx len: %lu\n", (unsigned long)block, records = records_for_ring (block->unused_cells, records, count, &total);
(unsigned long)block->n_words * sizeof (word_t)); if (records == NULL)
fprintf (stderr, "\n"); 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 (); DO_UNLOCK ();
return records;
} }
char* char*
egg_secure_strdup (const char *str) egg_secure_strdup_full (const char *tag,
const char *str,
int options)
{ {
size_t len; size_t len;
char *res; char *res;
if (!str) if (!str)
return NULL; return NULL;
len = strlen (str) + 1; len = strlen (str) + 1;
res = (char*)egg_secure_alloc (len); res = (char *)egg_secure_alloc_full (tag, len, options);
strcpy (res, str); strcpy (res, str);
return res; return res;
} }
@ -1231,5 +1312,5 @@ egg_secure_strfree (char *str)
*/ */
egg_secure_strclear (str); egg_secure_strclear (str);
egg_secure_free_full (str, GKR_SECURE_USE_FALLBACK); egg_secure_free_full (str, EGG_SECURE_USE_FALLBACK);
} }

View File

@ -70,15 +70,22 @@ extern void* egg_memory_fallback (void *p, size_t length);
* Allocations return NULL on failure. * 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 (const char *tag, void *p, size_t length, int options);
void* egg_secure_realloc_full (void *p, size_t length, int fallback);
void egg_secure_free (void* p); 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_validate (void);
void egg_secure_dump_blocks (void); char* egg_secure_strdup_full (const char *tag, const char *str, int options);
char* egg_secure_strdup (const char *str);
void egg_secure_strclear (char *str); void egg_secure_strclear (char *str);
void egg_secure_strfree (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 */ #endif /* EGG_SECURE_MEMORY_H */

View File

@ -1,6 +1,6 @@
include $(top_srcdir)/Makefile.decl include $(top_srcdir)/Makefile.decl
NULL = SUBDIRS = . tests
module_flags = \ module_flags = \
-export_dynamic \ -export_dynamic \
@ -12,7 +12,11 @@ module_flags = \
lib_LTLIBRARIES = libgsecret.la lib_LTLIBRARIES = libgsecret.la
libgsecret_la_SOURCES = \ 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 = \ libgsecret_la_LIBADD = \
$(top_builddir)/egg/libegg.la \ $(top_builddir)/egg/libegg.la \

View File

@ -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___ */

View File

@ -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);
}
}

297
library/gsecret-item.c Normal file
View File

@ -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 */

120
library/gsecret-item.h Normal file
View File

@ -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___ */

42
library/gsecret-private.h Normal file
View File

@ -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___ */

57
library/gsecret-prompt.h Normal file
View File

@ -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___ */

691
library/gsecret-service.c Normal file
View File

@ -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;
}

192
library/gsecret-service.h Normal file
View File

@ -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___ */

30
library/gsecret-types.h Normal file
View File

@ -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___ */

32
library/gsecret-util.c Normal file
View File

@ -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);
}

122
library/gsecret-value.c Normal file
View File

@ -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);
}
}

View File

@ -10,36 +10,36 @@
* See the included COPYING file for more information. * See the included COPYING file for more information.
*/ */
#ifndef __GSECRET_DATA_H__ #ifndef __GSECRET_VALUE_H__
#define __GSECRET_DATA_H__ #define __GSECRET_VALUE_H__
#include <gio/gio.h> #include <gio/gio.h>
G_BEGIN_DECLS 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, gssize length,
const gchar *content_type); const gchar *content_type);
GSecretData* gsecret_data_new_full (gchar *secret, GSecretValue* gsecret_value_new_full (gchar *secret,
gssize length, gssize length,
const gchar *content_type, const gchar *content_type,
GDestroyNotify destroy); GDestroyNotify destroy);
const gchar* gsecret_data_get (GSecretData *data, const gchar* gsecret_value_get (GSecretValue *value,
gsize *length); 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 G_END_DECLS

27
library/tests/Makefile.am Normal file
View File

@ -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

View File

@ -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 ();
}