Commit b1b54f52 authored by Stef Walter's avatar Stef Walter Committed by Stef Walter
Browse files

More Implementation of GSecretService session related code.

parent 3dfd7aa7
......@@ -22,5 +22,8 @@ Makefile.in
Makefile.in.in
missing
stamp*
.settings
.project
.cproject
/po/POTFILES
......@@ -8,7 +8,7 @@ ORIGDIR=`pwd`
cd $srcdir
PROJECT=gsecret
TEST_TYPE=-f
FILE=library/gsecret-data.c
FILE=library/gsecret-value.c
DIE=0
......
......@@ -3,7 +3,7 @@ AC_CONFIG_MACRO_DIR([m4])
AC_INIT([gsecret],[0.1],[http://bugzilla.gnome.org/enter_bug.cgi?product=gsecret])
AC_CONFIG_SRCDIR([library/gsecret-data.c])
AC_CONFIG_SRCDIR([library/gsecret-value.c])
AC_CONFIG_HEADERS([config.h])
dnl Other initialization
......@@ -70,10 +70,12 @@ fi
dnl *****************************
dnl *** done ***
dnl *****************************
AC_CONFIG_FILES([Makefile
egg/Makefile
po/Makefile.in
po/Makefile
library/Makefile
])
AC_CONFIG_FILES([
Makefile
egg/Makefile
po/Makefile.in
po/Makefile
library/Makefile
library/tests/Makefile
])
AC_OUTPUT
......@@ -6,5 +6,7 @@ INCLUDES = \
-I$(top_srcdir)
libegg_la_SOURCES = \
egg-dh.c egg-dh.h \
egg-hkdf.c egg-hkdf.h \
egg-secure-memory.c egg-secure-memory.h \
$(BUILT_SOURCES)
This diff is collapsed.
/*
* 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_ */
/*
* 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;
}
/*
* 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_ */
......@@ -97,20 +97,22 @@ typedef void* word_t;
typedef struct _Cell {
word_t *words; /* Pointer to secure memory */
size_t n_words; /* Amount of secure memory in words */
size_t allocated; /* Amount actually requested by app, in bytes, 0 if unused */
struct _Cell *next; /* Next in unused memory ring, or NULL if used */
struct _Cell *prev; /* Previous in unused memory ring, or NULL if used */
size_t requested; /* Amount actually requested by app, in bytes, 0 if unused */
const char *tag; /* Tag which describes the allocation */
struct _Cell *next; /* Next in memory ring */
struct _Cell *prev; /* Previous in memory ring */
} Cell;
/*
* A block of secure memory. This structure is the header in that block.
*/
typedef struct _Block {
word_t *words; /* Actual memory hangs off here */
size_t n_words; /* Number of words in block */
size_t used; /* Number of used allocations */
struct _Cell* unused; /* Ring of unused allocations */
struct _Block *next; /* Next block in list */
word_t *words; /* Actual memory hangs off here */
size_t n_words; /* Number of words in block */
size_t n_used; /* Number of used allocations */
struct _Cell* used_cells; /* Ring of used allocations */
struct _Cell* unused_cells; /* Ring of unused allocations */
struct _Block *next; /* Next block in list */
} Block;
/* -----------------------------------------------------------------------------
......@@ -263,6 +265,8 @@ pool_free (void* item)
unused_push (&pool->unused, item);
}
#ifndef G_DISABLE_ASSERT
static int
pool_valid (void* item)
{
......@@ -282,6 +286,8 @@ pool_valid (void* item)
return 0;
}
#endif /* G_DISABLE_ASSERT */
/* -----------------------------------------------------------------------------
* SEC ALLOCATION
*
......@@ -459,7 +465,9 @@ sec_neighbor_after (Block *block, Cell *cell)
}
static void*
sec_alloc (Block *block, size_t length)
sec_alloc (Block *block,
const char *tag,
size_t length)
{
Cell *cell, *other;
size_t n_words;
......@@ -467,8 +475,9 @@ sec_alloc (Block *block, size_t length)
ASSERT (block);
ASSERT (length);
ASSERT (tag);
if (!block->unused)
if (!block->unused_cells)
return NULL;
/*
......@@ -482,10 +491,10 @@ sec_alloc (Block *block, size_t length)
n_words = sec_size_to_words (length) + 2;
/* Look for a cell of at least our required size */
cell = block->unused;
cell = block->unused_cells;
while (cell->n_words < n_words) {
cell = cell->next;
if (cell == block->unused) {
if (cell == block->unused_cells) {
cell = NULL;
break;
}
......@@ -493,8 +502,9 @@ sec_alloc (Block *block, size_t length)
if (!cell)
return NULL;
ASSERT (cell->allocated == 0);
ASSERT (cell->tag == NULL);
ASSERT (cell->requested == 0);
ASSERT (cell->prev);
ASSERT (cell->words);
sec_check_guards (cell);
......@@ -516,10 +526,12 @@ sec_alloc (Block *block, size_t length)
}
if (cell->next)
sec_remove_cell_ring (&block->unused, cell);
++block->used;
cell->allocated = length;
sec_remove_cell_ring (&block->unused_cells, cell);
++block->n_used;
cell->tag = tag;
cell->requested = length;
sec_insert_cell_ring (&block->used_cells, cell);
memory = sec_cell_to_memory (cell);
#ifdef WITH_VALGRIND
......@@ -555,16 +567,19 @@ sec_free (Block *block, void *memory)
#endif
sec_check_guards (cell);
sec_clear_memory (memory, 0, cell->allocated);
sec_clear_memory (memory, 0, cell->requested);
sec_check_guards (cell);
ASSERT (cell->next == NULL);
ASSERT (cell->prev == NULL);
ASSERT (cell->allocated > 0);
ASSERT (cell->requested > 0);
ASSERT (cell->tag != NULL);
/* Remove from the used cell ring */
sec_remove_cell_ring (&block->used_cells, cell);
/* Find previous unallocated neighbor, and merge if possible */
other = sec_neighbor_before (block, cell);
if (other && other->allocated == 0) {
if (other && other->requested == 0) {
ASSERT (other->tag == NULL);
ASSERT (other->next && other->prev);
other->n_words += cell->n_words;
sec_write_guards (other);
......@@ -574,12 +589,13 @@ sec_free (Block *block, void *memory)
/* Find next unallocated neighbor, and merge if possible */
other = sec_neighbor_after (block, cell);
if (other && other->allocated == 0) {
if (other && other->requested == 0) {
ASSERT (other->tag == NULL);
ASSERT (other->next && other->prev);
other->n_words += cell->n_words;
other->words = cell->words;
if (cell->next)
sec_remove_cell_ring (&block->unused, cell);
sec_remove_cell_ring (&block->unused_cells, cell);
sec_write_guards (other);
pool_free (cell);
cell = other;
......@@ -587,25 +603,30 @@ sec_free (Block *block, void *memory)
/* Add to the unused list if not already there */
if (!cell->next)
sec_insert_cell_ring (&block->unused, cell);
cell->allocated = 0;
--block->used;
sec_insert_cell_ring (&block->unused_cells, cell);
cell->tag = NULL;
cell->requested = 0;
--block->n_used;
return NULL;
}
static void*
sec_realloc (Block *block, void *memory, size_t length)
sec_realloc (Block *block,
const char *tag,
void *memory,
size_t length)
{
Cell *cell, *other;
word_t *word;
size_t n_words;
size_t valid;
void *alloc;
/* Standard realloc behavior, should have been handled elsewhere */
ASSERT (memory != NULL);
ASSERT (length > 0);
ASSERT (tag != NULL);
/* Dig out where the meta should be */
word = memory;
......@@ -621,13 +642,12 @@ sec_realloc (Block *block, void *memory, size_t length)
/* Validate that it's actually for real */
sec_check_guards (cell);
ASSERT (cell->allocated > 0);
ASSERT (cell->next == NULL);
ASSERT (cell->prev == NULL);
ASSERT (cell->requested > 0);
ASSERT (cell->tag != NULL);
/* The amount of valid data */
valid = cell->allocated;
valid = cell->requested;
/* How many words we actually want */
n_words = sec_size_to_words (length) + 2;
......@@ -635,7 +655,7 @@ sec_realloc (Block *block, void *memory, size_t length)
if (n_words <= cell->n_words) {
/* TODO: No shrinking behavior yet */
cell->allocated = length;
cell->requested = length;
alloc = sec_cell_to_memory (cell);
#ifdef WITH_VALGRIND
......@@ -658,14 +678,14 @@ sec_realloc (Block *block, void *memory, size_t length)
/* See if we have a neighbor who can give us some memory */
other = sec_neighbor_after (block, cell);
if (!other || other->allocated != 0)
if (!other || other->requested != 0)
break;
/* Eat the whole neighbor if not too big */
if (n_words - cell->n_words + WASTE >= other->n_words) {
cell->n_words += other->n_words;
sec_write_guards (cell);
sec_remove_cell_ring (&block->unused, other);
sec_remove_cell_ring (&block->unused_cells, other);
pool_free (other);
/* Steal from the neighbor */
......@@ -679,18 +699,19 @@ sec_realloc (Block *block, void *memory, size_t length)
}
if (cell->n_words >= n_words) {
cell->allocated = length;
cell->requested = length;
cell->tag = tag;
alloc = sec_cell_to_memory (cell);
#ifdef WITH_VALGRIND
VALGRIND_MAKE_MEM_DEFINED (alloc, length);
#endif
return sec_clear_memory (alloc, valid, length);
}
/* That didn't work, try alloc/free */
alloc = sec_alloc (block, length);
alloc = sec_alloc (block, tag, length);
if (alloc) {
memcpy (alloc, memory, valid);
sec_free (block, memory);
......@@ -722,15 +743,14 @@ sec_allocated (Block *block, void *memory)
cell = *word;
sec_check_guards (cell);
ASSERT (cell->next == NULL);
ASSERT (cell->prev == NULL);
ASSERT (cell->allocated > 0);
ASSERT (cell->requested > 0);
ASSERT (cell->tag != NULL);
#ifdef WITH_VALGRIND
VALGRIND_MAKE_MEM_NOACCESS (word, sizeof (word_t));
#endif
return cell->allocated;
return cell->requested;
}
static void
......@@ -753,15 +773,19 @@ sec_validate (Block *block)
sec_check_guards (cell);
/* Is it an allocated block? */
if (cell->allocated > 0) {
ASSERT (cell->next == NULL);
ASSERT (cell->prev == NULL);
ASSERT (cell->allocated <= (cell->n_words - 2) * sizeof (word_t));
if (cell->requested > 0) {
ASSERT (cell->tag != NULL);
ASSERT (cell->next != NULL);
ASSERT (cell->prev != NULL);
ASSERT (cell->next->prev == cell);
ASSERT (cell->prev->next == cell);
ASSERT (cell->requested <= (cell->n_words - 2) * sizeof (word_t));
/* An unused block */
} else {
ASSERT (cell->next);
ASSERT (cell->prev);
ASSERT (cell->tag == NULL);
ASSERT (cell->next != NULL);
ASSERT (cell->prev != NULL);
ASSERT (cell->next->prev == cell);
ASSERT (cell->prev->next == cell);
}
......@@ -777,13 +801,15 @@ sec_validate (Block *block)
*/
static void*
sec_acquire_pages (size_t *sz)
sec_acquire_pages (size_t *sz,
const char *during_tag)
{
void *pages;
unsigned long pgsize;
ASSERT (sz);
ASSERT (*sz);
ASSERT (during_tag);
/* Make sure sz is a multiple of the page size */
pgsize = getpagesize ();
......@@ -793,16 +819,16 @@ sec_acquire_pages (size_t *sz)
pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
if (pages == MAP_FAILED) {
if (lock_warning && egg_secure_warnings)
fprintf (stderr, "couldn't map %lu bytes of private memory: %s\n",
(unsigned long)*sz, strerror (errno));
fprintf (stderr, "couldn't map %lu bytes of memory (%s): %s\n",
(unsigned long)*sz, during_tag, strerror (errno));
lock_warning = 0;
return NULL;
}
if (mlock (pages, *sz) < 0) {
if (lock_warning && egg_secure_warnings && errno != EPERM) {
fprintf (stderr, "couldn't lock %lu bytes of private memory: %s\n",
(unsigned long)*sz, strerror (errno));
fprintf (stderr, "couldn't lock %lu bytes of memory (%s): %s\n",
(unsigned long)*sz, during_tag, strerror (errno));
lock_warning = 0;
}
munmap (pages, *sz);
......@@ -850,11 +876,14 @@ sec_release_pages (void *pages, size_t sz)
static Block *all_blocks = NULL;
static Block*
sec_block_create (size_t size)
sec_block_create (size_t size,
const char *during_tag)
{
Block *block;
Cell *cell;
ASSERT (during_tag);
#if FORCE_FALLBACK_MEMORY
/* We can force all all memory to be malloced */
return NULL;
......@@ -874,7 +903,7 @@ sec_block_create (size_t size)
if (size < DEFAULT_BLOCK_SIZE)
size = DEFAULT_BLOCK_SIZE;
block->words = sec_acquire_pages (&size);
block->words = sec_acquire_pages (&size, during_tag);
block->n_words = size / sizeof (word_t);
if (!block->words) {
pool_free (block);
......@@ -889,10 +918,10 @@ sec_block_create (size_t size)
/* The first cell to allocate from */
cell->words = block->words;
cell->n_words = block->n_words;
cell->allocated = 0;
cell->requested = 0;
sec_write_guards (cell);
sec_insert_cell_ring (&block->unused, cell);
sec_insert_cell_ring (&block->unused_cells, cell);
block->next = all_blocks;