|
|
|
@ -25,10 +25,13 @@ |
|
|
|
|
#include <stdio.h> |
|
|
|
|
#include <stdlib.h> |
|
|
|
|
#include <string.h> |
|
|
|
|
#include <assert.h> |
|
|
|
|
|
|
|
|
|
#include <gcrypt.h> |
|
|
|
|
#include <libgfshare.h> |
|
|
|
|
|
|
|
|
|
#include <xmem.h> |
|
|
|
|
|
|
|
|
|
#include "util.h" |
|
|
|
|
|
|
|
|
|
/** @file secret.c
|
|
|
|
@ -108,24 +111,23 @@ gfsec_fill_rand(unsigned char *buffer, unsigned int len) |
|
|
|
|
/**
|
|
|
|
|
* Initializes a new share object. |
|
|
|
|
* |
|
|
|
|
* @return The share object, or NULL if memory could not be allocated. |
|
|
|
|
* @return The share object. |
|
|
|
|
*/ |
|
|
|
|
gfsec_share_t * |
|
|
|
|
gfsec_share_new(void) |
|
|
|
|
{ |
|
|
|
|
gfsec_share_t *s = NULL; |
|
|
|
|
gfsec_share_t *s; |
|
|
|
|
|
|
|
|
|
if ( (s = malloc(sizeof(gfsec_share_t))) ) { |
|
|
|
|
s->number = GFSEC_SHARE_NUMBER_AUTOASSIGN; |
|
|
|
|
s = xmalloc(sizeof(gfsec_share_t)); |
|
|
|
|
s->number = GFSEC_SHARE_NUMBER_AUTOASSIGN; |
|
|
|
|
|
|
|
|
|
s->scheme = GFSEC_SCHEME_FILE; |
|
|
|
|
s->authority = NULL; |
|
|
|
|
s->path = NULL; |
|
|
|
|
s->scheme = GFSEC_SCHEME_FILE; |
|
|
|
|
s->authority = NULL; |
|
|
|
|
s->path = NULL; |
|
|
|
|
|
|
|
|
|
s->len = 0; |
|
|
|
|
s->data = NULL; |
|
|
|
|
s->hash = NULL; |
|
|
|
|
} |
|
|
|
|
s->len = 0; |
|
|
|
|
s->data = NULL; |
|
|
|
|
s->hash = NULL; |
|
|
|
|
|
|
|
|
|
return s; |
|
|
|
|
} |
|
|
|
@ -147,10 +149,8 @@ gfsec_share_new(void) |
|
|
|
|
* @param path The path part of the URI (may be NULL); |
|
|
|
|
* @param hash A buffer containing a SHA-256 hash of the |
|
|
|
|
* share's data (may be NULL). |
|
|
|
|
* |
|
|
|
|
* @return 0 if successful, or one of the GFSEC_ERR_* error codes. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
void |
|
|
|
|
gfsec_share_set_info(gfsec_share_t *share, |
|
|
|
|
unsigned char number, |
|
|
|
|
gfsec_scheme_t scheme, |
|
|
|
@ -158,21 +158,18 @@ gfsec_share_set_info(gfsec_share_t *share, |
|
|
|
|
const char *path, |
|
|
|
|
const unsigned char *hash) |
|
|
|
|
{ |
|
|
|
|
if ( ! share ) |
|
|
|
|
return GFSEC_ERR_INVALID_CALL; |
|
|
|
|
assert(share != NULL); |
|
|
|
|
|
|
|
|
|
share->number = number; |
|
|
|
|
|
|
|
|
|
share->scheme = scheme; |
|
|
|
|
if ( authority && ! (share->authority = strdup(authority)) ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
if ( path && ! (share->path = strdup(path)) ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
if ( authority ) |
|
|
|
|
share->authority = xstrdup(authority); |
|
|
|
|
if ( path ) |
|
|
|
|
share->path = xstrdup(path); |
|
|
|
|
|
|
|
|
|
if ( hash ) |
|
|
|
|
memcpy(share->hash, hash, 32); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -187,7 +184,8 @@ gfsec_share_set_info(gfsec_share_t *share, |
|
|
|
|
* freed when the gfsec_share_free function is called; |
|
|
|
|
* @param len The size of the data buffer. |
|
|
|
|
* |
|
|
|
|
* @return 0 if successfull, or one of the GFSEC_ERR_* error codes. |
|
|
|
|
* @return 0 if successfull, or GFSEC_ERR_INVALID_SHARE is the |
|
|
|
|
* data does not match the share's expected hash. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_share_set_data(gfsec_share_t *share, |
|
|
|
@ -196,8 +194,8 @@ gfsec_share_set_data(gfsec_share_t *share, |
|
|
|
|
{ |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
if ( ! share || ! data ) |
|
|
|
|
return GFSEC_ERR_INVALID_CALL; |
|
|
|
|
assert(share != NULL); |
|
|
|
|
assert(data != NULL); |
|
|
|
|
|
|
|
|
|
share->data = data; |
|
|
|
|
share->len = len; |
|
|
|
@ -224,8 +222,7 @@ gfsec_share_set_data(gfsec_share_t *share, |
|
|
|
|
* @param buffer The buffer to write the URI into. |
|
|
|
|
* @param len The size of the buffer. |
|
|
|
|
* |
|
|
|
|
* @return The number of characters written into the buffer, |
|
|
|
|
* or GFSEC_ERR_INVALID_CALL if an invalid poitner was passed. |
|
|
|
|
* @return The number of characters written into the buffer. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_share_get_uri(gfsec_share_t *share, |
|
|
|
@ -235,8 +232,8 @@ gfsec_share_get_uri(gfsec_share_t *share, |
|
|
|
|
static char *schemes[] = { "file://", "uuid://", "label://", "mtp://" }; |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
if ( ! share || ! buffer ) |
|
|
|
|
return GFSEC_ERR_INVALID_CALL; |
|
|
|
|
assert(share != NULL); |
|
|
|
|
assert(buffer != NULL); |
|
|
|
|
|
|
|
|
|
ret = snprintf(buffer, len, "%s%s%s", |
|
|
|
|
schemes[share->scheme], |
|
|
|
@ -254,8 +251,7 @@ gfsec_share_get_uri(gfsec_share_t *share, |
|
|
|
|
void |
|
|
|
|
gfsec_share_free(gfsec_share_t *share) |
|
|
|
|
{ |
|
|
|
|
if ( ! share ) |
|
|
|
|
return; |
|
|
|
|
assert(share != NULL); |
|
|
|
|
|
|
|
|
|
if ( share->authority ) |
|
|
|
|
free(share->authority); |
|
|
|
@ -273,28 +269,27 @@ gfsec_share_free(gfsec_share_t *share) |
|
|
|
|
/**
|
|
|
|
|
* Initializes a new secret object. |
|
|
|
|
* |
|
|
|
|
* @return The secret object, or NULL if memory could not be allocated. |
|
|
|
|
* @return The secret object. |
|
|
|
|
*/ |
|
|
|
|
gfsec_secret_t * |
|
|
|
|
gfsec_secret_new(void) |
|
|
|
|
{ |
|
|
|
|
gfsec_secret_t *s = NULL; |
|
|
|
|
gfsec_secret_t *s; |
|
|
|
|
|
|
|
|
|
if ( (s = malloc(sizeof(*s))) ) { |
|
|
|
|
s->filename = NULL; |
|
|
|
|
s = xmalloc(sizeof(*s)); |
|
|
|
|
s->filename = NULL; |
|
|
|
|
|
|
|
|
|
s->data = NULL; |
|
|
|
|
s->len = 0; |
|
|
|
|
s->data = NULL; |
|
|
|
|
s->len = 0; |
|
|
|
|
|
|
|
|
|
s->n_shares = 0; |
|
|
|
|
s->max_shares = 0; |
|
|
|
|
s->threshold = 0; |
|
|
|
|
s->n_shares = 0; |
|
|
|
|
s->max_shares = 0; |
|
|
|
|
s->threshold = 0; |
|
|
|
|
|
|
|
|
|
s->shares = NULL; |
|
|
|
|
s->full_share = NULL; |
|
|
|
|
s->shares = NULL; |
|
|
|
|
s->full_share = NULL; |
|
|
|
|
|
|
|
|
|
s->can_combine = 0; |
|
|
|
|
} |
|
|
|
|
s->can_combine = 0; |
|
|
|
|
|
|
|
|
|
return s; |
|
|
|
|
} |
|
|
|
@ -305,17 +300,17 @@ gfsec_secret_new(void) |
|
|
|
|
* @param secret The secret object. |
|
|
|
|
* @param filename The location of the file to read the secret from. |
|
|
|
|
* |
|
|
|
|
* @return 0 if successful, or one of the GFSEC_ERR_* error codes. |
|
|
|
|
* @return 0 if successful, or one of the GFSEC_ERR_SYSTEM_ERROR if |
|
|
|
|
* an I/O error occured. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_secret_set_secret_file(gfsec_secret_t *secret, |
|
|
|
|
const char *filename) |
|
|
|
|
{ |
|
|
|
|
if ( ! secret || ! filename ) |
|
|
|
|
return GFSEC_ERR_INVALID_CALL; |
|
|
|
|
assert(secret != NULL); |
|
|
|
|
assert(filename != NULL); |
|
|
|
|
|
|
|
|
|
if ( ! (secret->filename = strdup(filename)) ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
secret->filename = xstrdup(filename); |
|
|
|
|
|
|
|
|
|
if ( ! (secret->data = read_file(filename, &(secret->len), |
|
|
|
|
GFSEC_SECRET_MAX_SIZE)) ) |
|
|
|
@ -330,22 +325,17 @@ gfsec_secret_set_secret_file(gfsec_secret_t *secret, |
|
|
|
|
* @param secret The secret object. |
|
|
|
|
* @param share The share to add. |
|
|
|
|
* |
|
|
|
|
* @return |
|
|
|
|
* - 0 if successful; |
|
|
|
|
* - GFSEC_ERR_INVALID_CALL if improperly called; |
|
|
|
|
* - GFSEC_ERR_TOO_MANY_SHARES if the secret object already has the |
|
|
|
|
* maximal number of shares allowed; |
|
|
|
|
* - GFSEC_ERR_SYSTEM_ERROR if a memory allocation error occurs. |
|
|
|
|
* @return 0 if successful, or GFSEC_ERR_TOO_MANY_SHARES if the |
|
|
|
|
* secret object already has the maximal number of shares allowed. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_secret_add_share(gfsec_secret_t *secret, gfsec_share_t *share) |
|
|
|
|
{ |
|
|
|
|
if ( ! secret || ! share ) |
|
|
|
|
return GFSEC_ERR_INVALID_CALL; |
|
|
|
|
assert(secret != NULL); |
|
|
|
|
assert(share != NULL); |
|
|
|
|
|
|
|
|
|
if ( secret->n_shares >= secret->max_shares ) { |
|
|
|
|
size_t new_max; |
|
|
|
|
void *tmp; |
|
|
|
|
|
|
|
|
|
new_max = secret->max_shares + 10; |
|
|
|
|
if ( new_max > 255 ) { |
|
|
|
@ -354,11 +344,7 @@ gfsec_secret_add_share(gfsec_secret_t *secret, gfsec_share_t *share) |
|
|
|
|
return GFSEC_ERR_TOO_MANY_SHARES; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tmp = realloc(secret->shares, new_max * sizeof(gfsec_share_t *)); |
|
|
|
|
if ( ! tmp ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
|
|
|
|
|
secret->shares = tmp; |
|
|
|
|
secret->shares = xrealloc(secret->shares, new_max * sizeof(gfsec_share_t *)); |
|
|
|
|
secret->max_shares = new_max; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -378,9 +364,7 @@ gfsec_secret_add_share(gfsec_secret_t *secret, gfsec_share_t *share) |
|
|
|
|
|
|
|
|
|
share->number = nr; |
|
|
|
|
|
|
|
|
|
if ( asprintf(&tmp, "%s.%03d", share->path, nr) == -1 ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
|
|
|
|
|
xasprintf(&tmp, "%s.%03d", share->path, nr); |
|
|
|
|
free(share->path); |
|
|
|
|
share->path = tmp; |
|
|
|
|
} |
|
|
|
@ -399,7 +383,6 @@ gfsec_secret_add_share(gfsec_secret_t *secret, gfsec_share_t *share) |
|
|
|
|
* |
|
|
|
|
* @return |
|
|
|
|
* - 0 if the secret can be reconstituted; |
|
|
|
|
* - GFSEC_ERR_INVALID_CALL if improperly called (secret is NULL); |
|
|
|
|
* - GFSEC_ERR_INVALID_LENGTH if not all shares have the same length; |
|
|
|
|
* - GFSEC_ERR_NOT_ENOUGH_SHARES if not enough shares are available. |
|
|
|
|
*/ |
|
|
|
@ -409,8 +392,7 @@ gfsec_secret_can_combine(gfsec_secret_t *secret) |
|
|
|
|
unsigned u, avail_shares; |
|
|
|
|
gfsec_share_t *share; |
|
|
|
|
|
|
|
|
|
if ( ! secret ) |
|
|
|
|
return GFSEC_ERR_INVALID_CALL; |
|
|
|
|
assert(secret != NULL); |
|
|
|
|
|
|
|
|
|
for ( u = 0, avail_shares = 0; u < secret->n_shares; u++ ) { |
|
|
|
|
share = secret->shares[u]; |
|
|
|
@ -445,11 +427,11 @@ gfsec_secret_can_combine(gfsec_secret_t *secret) |
|
|
|
|
* |
|
|
|
|
* @return |
|
|
|
|
* - 0 if successful; |
|
|
|
|
* - GFSEC_ERR_INVALID_CALL if called improperly (secret is NULL, |
|
|
|
|
* or gfsec_secret_can_recombine has not been called previously, |
|
|
|
|
* - GFSEC_ERR_INVALID_CALL if called improperly (either |
|
|
|
|
* gfsec_secret_can_recombine has not been called previously, |
|
|
|
|
* or it has been called but has found the secret could not be |
|
|
|
|
* reconstituted); |
|
|
|
|
* - GFSEC_ERR_SYSTEM_ERROR if a memory allocation error occurs. |
|
|
|
|
* - GFSEC_ERR_SYSTEM_ERROR if an error occured in Libgfshare. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_secret_combine(gfsec_secret_t *secret) |
|
|
|
@ -457,14 +439,12 @@ gfsec_secret_combine(gfsec_secret_t *secret) |
|
|
|
|
gfsec_share_t *share; |
|
|
|
|
unsigned u; |
|
|
|
|
|
|
|
|
|
if ( ! secret ) |
|
|
|
|
return GFSEC_ERR_INVALID_CALL; |
|
|
|
|
assert(secret != NULL); |
|
|
|
|
|
|
|
|
|
if ( ! secret->can_combine ) |
|
|
|
|
return GFSEC_ERR_INVALID_CALL; |
|
|
|
|
|
|
|
|
|
if ( ! (secret->data = malloc(secret->len)) ) |
|
|
|
|
return GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
secret->data = xmalloc(secret->len); |
|
|
|
|
|
|
|
|
|
if ( gfshare_fill_rand == NULL ) |
|
|
|
|
gfshare_fill_rand = gfsec_fill_rand; |
|
|
|
@ -522,10 +502,10 @@ gfsec_secret_get_partial_share_count(gfsec_secret_t *secret) |
|
|
|
|
* |
|
|
|
|
* @return |
|
|
|
|
* - 0 if successful; |
|
|
|
|
* - GFSEC_ERR_INVALID_CALL if called improperly; |
|
|
|
|
* - GFSEC_ERR_NOT_ENOUGH_SHARES if the secret object does not define |
|
|
|
|
* enough shares to satisfy the desired threshold; |
|
|
|
|
* - GFSEC_ERR_SYSTEM_ERROR if a memory allocation error occurs. |
|
|
|
|
* - GFSEC_ERR_SYSTEM_ERROR if an error occured in Libgfshare or |
|
|
|
|
* Libgcrypt. |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
gfsec_secret_split(gfsec_secret_t *secret, unsigned char threshold) |
|
|
|
@ -537,8 +517,7 @@ gfsec_secret_split(gfsec_secret_t *secret, unsigned char threshold) |
|
|
|
|
unsigned u, v, n; |
|
|
|
|
int rc; |
|
|
|
|
|
|
|
|
|
if ( ! secret ) |
|
|
|
|
return GFSEC_ERR_INVALID_CALL; |
|
|
|
|
assert(secret != NULL); |
|
|
|
|
|
|
|
|
|
n = gfsec_secret_get_partial_share_count(secret); |
|
|
|
|
if ( threshold >= n ) |
|
|
|
@ -549,22 +528,19 @@ gfsec_secret_split(gfsec_secret_t *secret, unsigned char threshold) |
|
|
|
|
if ( gfshare_fill_rand == NULL ) |
|
|
|
|
gfshare_fill_rand = gfsec_fill_rand; |
|
|
|
|
|
|
|
|
|
for ( u = v = rc = 0; u < secret->n_shares && rc == 0; u++ ) { |
|
|
|
|
for ( u = v = rc = 0; u < secret->n_shares; u++ ) { |
|
|
|
|
share = secret->shares[u]; |
|
|
|
|
|
|
|
|
|
if ( ! gfsec_share_is_full(share) ) |
|
|
|
|
sharenrs[v++] = share->number; |
|
|
|
|
|
|
|
|
|
if ( ! (share->data = malloc(secret->len)) ) |
|
|
|
|
rc = GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
if ( ! (share->hash = malloc(32)) ) |
|
|
|
|
rc = GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
share->data = xmalloc(secret->len); |
|
|
|
|
share->hash = xmalloc(32); |
|
|
|
|
|
|
|
|
|
share->len = secret->len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ( rc == 0 && ! (ctx = gfshare_ctx_init_enc(sharenrs, n, threshold, |
|
|
|
|
secret->len)) ) |
|
|
|
|
if ( ! (ctx = gfshare_ctx_init_enc(sharenrs, n, threshold, secret->len)) ) |
|
|
|
|
rc = GFSEC_ERR_SYSTEM_ERROR; |
|
|
|
|
|
|
|
|
|
if ( rc == 0 && gcry_md_open(&md, GCRY_MD_SHA256, 0) != 0 ) |
|
|
|
@ -619,8 +595,7 @@ gfsec_secret_free(gfsec_secret_t *secret) |
|
|
|
|
{ |
|
|
|
|
unsigned u; |
|
|
|
|
|
|
|
|
|
if ( ! secret ) |
|
|
|
|
return; |
|
|
|
|
assert(secret != NULL); |
|
|
|
|
|
|
|
|
|
if ( secret->filename ) |
|
|
|
|
free(secret->filename); |
|
|
|
|