Support GnuTLS as an alternative crypto backend

This turns the `-Dgcrypt` build time option into a more generic
`-Dcrypto` option, which enables user to choose which cryptographic
library to link with.  It currently supports libgcrypt (`libgcrypt`)
and GnuTLS (`gnutls`); for the latter, GnuTLS 3.8.2 is the minimum
required version.

Signed-off-by: Daiki Ueno <dueno@src.gnome.org>
This commit is contained in:
Daiki Ueno 2023-09-10 11:42:06 +09:00
parent 0f49b34fa2
commit 28486191b2
18 changed files with 1064 additions and 320 deletions

261
egg/egg-dh-gnutls.c Normal file
View File

@ -0,0 +1,261 @@
/*
* libsecret
*
* Copyright (C) 2023 Daiki Ueno
*
* 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.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 Public License for more details.
*
* You should have received copies of the GNU General Public License and
* the GNU Lesser General Public License along with this program. If
* not, see http://www.gnu.org/licenses/.
*
* Author: Daiki Ueno
*/
#include "config.h"
#include "egg-dh.h"
/* Enabling this is a complete security compromise */
#define DEBUG_DH_SECRET 0
#include <gnutls/gnutls.h>
#include <gnutls/abstract.h>
struct egg_dh_params {
gnutls_dh_params_t inner;
guint bits;
};
struct egg_dh_pubkey {
gnutls_pubkey_t inner;
};
struct egg_dh_privkey {
gnutls_privkey_t inner;
};
egg_dh_params *
egg_dh_default_params (const gchar *name)
{
const egg_dh_group *group;
egg_dh_params *params;
g_return_val_if_fail (name, NULL);
for (group = egg_dh_groups; group->name; ++group) {
if (g_str_equal (group->name, name)) {
gnutls_dh_params_t inner;
gnutls_datum_t prime, generator;
int ret;
ret = gnutls_dh_params_init (&inner);
if (ret < 0)
return NULL;
prime.data = (void *)group->prime;
prime.size = group->n_prime;
generator.data = (void *)group->base;
generator.size = group->n_base;
ret = gnutls_dh_params_import_raw (inner,
&prime,
&generator);
if (ret < 0) {
gnutls_dh_params_deinit (inner);
return NULL;
}
params = g_new (struct egg_dh_params, 1);
if (!params) {
gnutls_dh_params_deinit (inner);
return NULL;
}
params->inner = g_steal_pointer (&inner);
params->bits = group->bits;
return params;
}
}
return NULL;
}
gboolean
egg_dh_gen_pair (egg_dh_params *params, guint bits,
egg_dh_pubkey **pub, egg_dh_privkey **priv)
{
gnutls_pubkey_t pub_inner = NULL;
gnutls_privkey_t priv_inner = NULL;
egg_dh_pubkey *pub_outer = NULL;
egg_dh_privkey *priv_outer = NULL;
gnutls_keygen_data_st data;
gboolean ok = FALSE;
int ret;
g_return_val_if_fail (params, FALSE);
g_return_val_if_fail (pub, FALSE);
g_return_val_if_fail (priv, FALSE);
if (bits == 0)
bits = params->bits;
else if (bits > params->bits)
g_return_val_if_reached (FALSE);
ret = gnutls_privkey_init (&priv_inner);
if (ret < 0)
goto out;
data.type = GNUTLS_KEYGEN_DH;
data.data = (void *)params->inner;
ret = gnutls_privkey_generate2 (priv_inner, GNUTLS_PK_DH, bits, 0,
&data, 1);
if (ret < 0)
goto out;
ret = gnutls_pubkey_init (&pub_inner);
if (ret < 0)
goto out;
ret = gnutls_pubkey_import_privkey (pub_inner, priv_inner, 0, 0);
if (ret < 0)
goto out;
pub_outer = g_new0 (struct egg_dh_pubkey, 1);
if (!pub_outer)
goto out;
pub_outer->inner = g_steal_pointer (&pub_inner);
priv_outer = g_new0 (struct egg_dh_privkey, 1);
if (!priv_outer)
goto out;
priv_outer->inner = g_steal_pointer (&priv_inner);
*pub = g_steal_pointer (&pub_outer);
*priv = g_steal_pointer (&priv_outer);
ok = TRUE;
out:
if (priv_inner)
gnutls_privkey_deinit (priv_inner);
if (pub_inner)
gnutls_pubkey_deinit (pub_inner);
egg_dh_privkey_free (priv_outer);
egg_dh_pubkey_free (pub_outer);
return ok;
}
GBytes *
egg_dh_gen_secret (egg_dh_pubkey *peer, egg_dh_privkey *priv,
egg_dh_params *params)
{
int ret;
gnutls_datum_t k;
#if DEBUG_DH_SECRET
gnutls_datum_t h;
#endif
g_return_val_if_fail (peer, NULL);
g_return_val_if_fail (priv, NULL);
g_return_val_if_fail (params, NULL);
ret = gnutls_privkey_derive_secret (priv->inner, peer->inner,
NULL, &k, 0);
if (ret < 0)
return NULL;
#if DEBUG_DH_SECRET
ret = gnutls_hex_encode2 (&k, &h);
g_assert (ret >= 0);
g_printerr ("DH SECRET: %s\n", h.data);
gnutls_free (h.data);
#endif
return g_bytes_new_with_free_func (k.data, k.size,
(GDestroyNotify)gnutls_free,
k.data);
}
void
egg_dh_params_free (egg_dh_params *params)
{
gnutls_dh_params_deinit (params->inner);
g_free (params);
}
void
egg_dh_pubkey_free (egg_dh_pubkey *pubkey)
{
if (!pubkey)
return;
if (pubkey->inner)
gnutls_pubkey_deinit (pubkey->inner);
g_free (pubkey);
}
void
egg_dh_privkey_free (egg_dh_privkey *privkey)
{
if (!privkey)
return;
if (privkey->inner)
gnutls_privkey_deinit (privkey->inner);
g_free (privkey);
}
GBytes *
egg_dh_pubkey_export (const egg_dh_pubkey *pubkey)
{
gnutls_datum_t data;
int ret;
ret = gnutls_pubkey_export_dh_raw (pubkey->inner, NULL, &data, 0);
if (ret < 0)
return NULL;
return g_bytes_new_with_free_func (data.data, data.size,
(GDestroyNotify)gnutls_free,
data.data);
}
egg_dh_pubkey *
egg_dh_pubkey_new_from_bytes (const egg_dh_params *params, GBytes *bytes)
{
egg_dh_pubkey *pub;
gnutls_pubkey_t inner;
gnutls_datum_t data;
int ret;
ret = gnutls_pubkey_init (&inner);
if (ret < 0)
return NULL;
data.data = (void *)g_bytes_get_data (bytes, NULL);
data.size = g_bytes_get_size (bytes);
ret = gnutls_pubkey_import_dh_raw (inner, params->inner, &data);
if (ret < 0) {
gnutls_pubkey_deinit (inner);
return NULL;
}
pub = g_new (struct egg_dh_pubkey, 1);
if (!pub) {
gnutls_pubkey_deinit (inner);
return NULL;
}
pub->inner = g_steal_pointer (&inner);
return pub;
}

278
egg/egg-dh-libgcrypt.c Normal file
View File

@ -0,0 +1,278 @@
/*
* 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 Public 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 Public License for more details.
*
* You should have received copies of the GNU General Public License and
* the GNU Lesser General Public License along with this program. If
* not, see http://www.gnu.org/licenses/.
*
* Author: Stef Walter <stefw@thewalter.net>
*/
#include "config.h"
#include "egg-dh.h"
#include <gcrypt.h>
#include "egg-secure-memory.h"
/* Enabling this is a complete security compromise */
#define DEBUG_DH_SECRET 0
EGG_SECURE_DECLARE (dh);
struct egg_dh_params {
gcry_mpi_t prime;
gcry_mpi_t base;
};
struct egg_dh_pubkey {
gcry_mpi_t inner;
};
struct egg_dh_privkey {
gcry_mpi_t inner;
};
egg_dh_params *
egg_dh_default_params (const gchar *name)
{
const egg_dh_group *group;
gcry_error_t gcry;
gcry_mpi_t prime = NULL, base = NULL;
egg_dh_params *params = NULL;
g_return_val_if_fail (name, NULL);
for (group = egg_dh_groups; group->name; ++group)
if (g_str_equal (group->name, name))
break;
if (!group->name)
return NULL;
gcry = gcry_mpi_scan (&prime, GCRYMPI_FMT_USG,
group->prime, group->n_prime, NULL);
g_return_val_if_fail (gcry == 0, NULL);
g_return_val_if_fail (gcry_mpi_get_nbits (prime) == group->bits, NULL);
gcry = gcry_mpi_scan (&base, GCRYMPI_FMT_USG,
group->base, group->n_base, NULL);
g_return_val_if_fail (gcry == 0, NULL);
params = g_new (struct egg_dh_params, 1);
if (!params)
goto error;
params->prime = g_steal_pointer (&prime);
params->base = g_steal_pointer (&base);
error:
gcry_mpi_release (prime);
gcry_mpi_release (base);
return params;
}
gboolean
egg_dh_gen_pair (egg_dh_params *params, guint bits,
egg_dh_pubkey **pub, egg_dh_privkey **priv)
{
guint pbits;
gcry_mpi_t pub_inner = NULL, priv_inner = NULL;
g_return_val_if_fail (params, FALSE);
g_return_val_if_fail (pub, FALSE);
g_return_val_if_fail (priv, FALSE);
*pub = NULL;
*priv = NULL;
pbits = gcry_mpi_get_nbits (params->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_inner = gcry_mpi_snew (bits);
g_return_val_if_fail (priv_inner, FALSE);
while (gcry_mpi_cmp_ui (priv_inner, 0) == 0)
gcry_mpi_randomize (priv_inner, bits, GCRY_STRONG_RANDOM);
/* Secret key value must be less than half of p */
if (gcry_mpi_get_nbits (priv_inner) > bits)
gcry_mpi_clear_highbit (priv_inner, bits);
if (gcry_mpi_get_nbits (priv_inner) > pbits - 1)
gcry_mpi_clear_highbit (priv_inner, pbits - 1);
g_assert (gcry_mpi_cmp (params->prime, priv_inner) > 0);
pub_inner = gcry_mpi_new (gcry_mpi_get_nbits (priv_inner));
if (!pub_inner)
goto error;
gcry_mpi_powm (pub_inner, params->base, priv_inner, params->prime);
*priv = g_new0 (struct egg_dh_privkey, 1);
if (!*priv)
goto error;
(*priv)->inner = g_steal_pointer (&priv_inner);
*pub = g_new0 (struct egg_dh_pubkey, 1);
if (!*pub)
goto error;
(*pub)->inner = g_steal_pointer (&pub_inner);
return TRUE;
error:
egg_dh_privkey_free (*priv);
egg_dh_pubkey_free (*pub);
gcry_mpi_release (priv_inner);
gcry_mpi_release (pub_inner);
g_return_val_if_reached (FALSE);
}
GBytes *
egg_dh_gen_secret (egg_dh_pubkey *peer, egg_dh_privkey *priv,
egg_dh_params *params)
{
gcry_error_t gcry;
guchar *value;
gsize n_prime;
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 (params, NULL);
bits = gcry_mpi_get_nbits (params->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->inner, priv->inner, params->prime);
/* Write out the secret */
gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_prime, params->prime);
g_return_val_if_fail (gcry == 0, NULL);
value = egg_secure_alloc (n_prime);
if (!value)
return NULL;
gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value, n_prime, &n_value, k);
g_return_val_if_fail (gcry == 0, NULL);
/* Pad the secret with zero bytes to match length of prime in bytes. */
if (n_value < n_prime) {
memmove (value + (n_prime - n_value), value, n_value);
memset (value, 0, (n_prime - n_value));
}
#if DEBUG_DH_SECRET
g_printerr ("DH SECRET: ");
gcry_mpi_dump (k);
#endif
gcry_mpi_release (k);
#if DEBUG_DH_SECRET
gcry_mpi_scan (&k, GCRYMPI_FMT_USG, value, n_prime, NULL);
g_printerr ("RAW SECRET: ");
gcry_mpi_dump (k);
gcry_mpi_release (k);
#endif
return g_bytes_new_with_free_func (value, n_prime,
(GDestroyNotify)egg_secure_free,
value);
}
void
egg_dh_params_free (egg_dh_params *params)
{
if (!params)
return;
gcry_mpi_release (params->prime);
gcry_mpi_release (params->base);
g_free (params);
}
void
egg_dh_pubkey_free (egg_dh_pubkey *pubkey)
{
if (!pubkey)
return;
if (pubkey->inner)
gcry_mpi_release (pubkey->inner);
g_free (pubkey);
}
void
egg_dh_privkey_free (egg_dh_privkey *privkey)
{
if (!privkey)
return;
if (privkey->inner)
gcry_mpi_release (privkey->inner);
g_free (privkey);
}
GBytes *
egg_dh_pubkey_export (const egg_dh_pubkey *pubkey)
{
gcry_error_t gcry;
unsigned char *buffer;
size_t n_buffer;
gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer,
pubkey->inner);
g_return_val_if_fail (gcry == 0, NULL);
return g_bytes_new_with_free_func (buffer, n_buffer,
gcry_free, buffer);
}
egg_dh_pubkey *
egg_dh_pubkey_new_from_bytes (const egg_dh_params *params,
GBytes *bytes)
{
gcry_error_t gcry;
gcry_mpi_t inner;
egg_dh_pubkey *pub;
gcry = gcry_mpi_scan (&inner, GCRYMPI_FMT_USG,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes),
NULL);
if (gcry != 0)
return NULL;
pub = g_new (struct egg_dh_pubkey, 1);
if (!pub) {
gcry_mpi_release (inner);
return NULL;
}
pub->inner = inner;
return pub;
}

View File

@ -13,10 +13,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received copies of the GNU General Public License and
* License along with this program; if not, write to the Free Software * the GNU Lesser General Public License along with this program. If
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * not, see http://www.gnu.org/licenses/.
* MA 02110-1301 USA
* *
* Author: Stef Walter <stefw@thewalter.net> * Author: Stef Walter <stefw@thewalter.net>
*/ */
@ -24,23 +23,6 @@
#include "config.h" #include "config.h"
#include "egg-dh.h" #include "egg-dh.h"
#include "egg-secure-memory.h"
#include <gcrypt.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[] = { 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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
@ -173,7 +155,7 @@ static const guchar dh_group_8192_prime[] = {
0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
}; };
static const DHGroup dh_groups[] = { const egg_dh_group egg_dh_groups[] = {
{ {
"ietf-ike-grp-modp-768", 768, "ietf-ike-grp-modp-768", 768,
dh_group_768_prime, G_N_ELEMENTS (dh_group_768_prime), dh_group_768_prime, G_N_ELEMENTS (dh_group_768_prime),
@ -214,24 +196,11 @@ static const DHGroup dh_groups[] = {
} }
}; };
struct egg_dh_params {
gcry_mpi_t prime;
gcry_mpi_t base;
};
struct egg_dh_pubkey {
gcry_mpi_t inner;
};
struct egg_dh_privkey {
gcry_mpi_t inner;
};
gboolean gboolean
egg_dh_default_params_raw (const gchar *name, gconstpointer *prime, egg_dh_default_params_raw (const gchar *name, gconstpointer *prime,
gsize *n_prime, gconstpointer *base, gsize *n_base) gsize *n_prime, gconstpointer *base, gsize *n_base)
{ {
const DHGroup *group; const egg_dh_group *group;
g_return_val_if_fail (name, FALSE); g_return_val_if_fail (name, FALSE);
g_return_val_if_fail (prime, FALSE); g_return_val_if_fail (prime, FALSE);
@ -239,7 +208,7 @@ egg_dh_default_params_raw (const gchar *name, gconstpointer *prime,
g_return_val_if_fail (base, FALSE); g_return_val_if_fail (base, FALSE);
g_return_val_if_fail (n_base, FALSE); g_return_val_if_fail (n_base, FALSE);
for (group = dh_groups; group->name; ++group) { for (group = egg_dh_groups; group->name; ++group) {
if (g_str_equal (group->name, name)) { if (g_str_equal (group->name, name)) {
*prime = group->prime; *prime = group->prime;
*n_prime = group->n_prime; *n_prime = group->n_prime;
@ -251,232 +220,3 @@ egg_dh_default_params_raw (const gchar *name, gconstpointer *prime,
return FALSE; return FALSE;
} }
egg_dh_params *
egg_dh_default_params (const gchar *name)
{
const DHGroup *group;
gcry_error_t gcry;
gcry_mpi_t prime = NULL, base = NULL;
egg_dh_params *params = NULL;
g_return_val_if_fail (name, NULL);
for (group = dh_groups; group->name; ++group)
if (g_str_equal (group->name, name))
break;
if (!group->name)
return NULL;
gcry = gcry_mpi_scan (&prime, GCRYMPI_FMT_USG,
group->prime, group->n_prime, NULL);
g_return_val_if_fail (gcry == 0, NULL);
if (G_UNLIKELY (gcry_mpi_get_nbits (prime) != group->bits))
goto error;
gcry = gcry_mpi_scan (&base, GCRYMPI_FMT_USG,
group->base, group->n_base, NULL);
if (gcry != 0)
goto error;
params = g_new (struct egg_dh_params, 1);
if (!params)
goto error;
params->prime = g_steal_pointer (&prime);
params->base = g_steal_pointer (&base);
error:
gcry_mpi_release (prime);
gcry_mpi_release (base);
return params;
}
gboolean
egg_dh_gen_pair (egg_dh_params *params, guint bits,
egg_dh_pubkey **pub, egg_dh_privkey **priv)
{
guint pbits;
gcry_mpi_t pub_inner = NULL, priv_inner = NULL;
g_return_val_if_fail (params, FALSE);
g_return_val_if_fail (pub, FALSE);
g_return_val_if_fail (priv, FALSE);
*pub = NULL;
*priv = NULL;
pbits = gcry_mpi_get_nbits (params->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_inner = gcry_mpi_snew (bits);
g_return_val_if_fail (priv_inner, FALSE);
while (gcry_mpi_cmp_ui (priv_inner, 0) == 0)
gcry_mpi_randomize (priv_inner, bits, GCRY_STRONG_RANDOM);
/* Secret key value must be less than half of p */
if (gcry_mpi_get_nbits (priv_inner) > bits)
gcry_mpi_clear_highbit (priv_inner, bits);
if (gcry_mpi_get_nbits (priv_inner) > pbits - 1)
gcry_mpi_clear_highbit (priv_inner, pbits - 1);
g_assert (gcry_mpi_cmp (params->prime, priv_inner) > 0);
pub_inner = gcry_mpi_new (gcry_mpi_get_nbits (priv_inner));
if (!pub_inner)
goto error;
gcry_mpi_powm (pub_inner, params->base, priv_inner, params->prime);
*priv = g_new0 (struct egg_dh_privkey, 1);
if (!*priv)
goto error;
(*priv)->inner = g_steal_pointer (&priv_inner);
*pub = g_new0 (struct egg_dh_pubkey, 1);
if (!*pub)
goto error;
(*pub)->inner = g_steal_pointer (&pub_inner);
return TRUE;
error:
egg_dh_privkey_free (*priv);
egg_dh_pubkey_free (*pub);
gcry_mpi_release (priv_inner);
gcry_mpi_release (pub_inner);
g_return_val_if_reached (FALSE);
}
GBytes *
egg_dh_gen_secret (egg_dh_pubkey *peer, egg_dh_privkey *priv,
egg_dh_params *params)
{
gcry_error_t gcry;
guchar *value;
gsize n_prime;
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 (params, NULL);
bits = gcry_mpi_get_nbits (params->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->inner, priv->inner, params->prime);
/* Write out the secret */
gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_prime, params->prime);
g_return_val_if_fail (gcry == 0, NULL);
value = egg_secure_alloc (n_prime);
gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value, n_prime, &n_value, k);
g_return_val_if_fail (gcry == 0, NULL);
/* Pad the secret with zero bytes to match length of prime in bytes. */
if (n_value < n_prime) {
memmove (value + (n_prime - n_value), value, n_value);
memset (value, 0, (n_prime - n_value));
}
#if DEBUG_DH_SECRET
g_printerr ("DH SECRET: ");
gcry_mpi_dump (k);
#endif
gcry_mpi_release (k);
#if DEBUG_DH_SECRET
gcry_mpi_scan (&k, GCRYMPI_FMT_USG, value, n_prime, NULL);
g_printerr ("RAW SECRET: ");
gcry_mpi_dump (k);
gcry_mpi_release (k);
#endif
return g_bytes_new_with_free_func (value, n_prime,
(GDestroyNotify)egg_secure_free,
value);
}
void
egg_dh_params_free (egg_dh_params *params)
{
if (!params)
return;
gcry_mpi_release (params->prime);
gcry_mpi_release (params->base);
g_free (params);
}
void
egg_dh_pubkey_free (egg_dh_pubkey *pubkey)
{
if (!pubkey)
return;
if (pubkey->inner)
gcry_mpi_release (pubkey->inner);
g_free (pubkey);
}
void
egg_dh_privkey_free (egg_dh_privkey *privkey)
{
if (!privkey)
return;
if (privkey->inner)
gcry_mpi_release (privkey->inner);
g_free (privkey);
}
GBytes *
egg_dh_pubkey_export (const egg_dh_pubkey *pubkey)
{
gcry_error_t gcry;
unsigned char *buffer;
size_t n_buffer;
gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer,
pubkey->inner);
g_return_val_if_fail (gcry == 0, NULL);
return g_bytes_new_with_free_func (buffer, n_buffer,
gcry_free, buffer);
}
egg_dh_pubkey *
egg_dh_pubkey_new_from_bytes (const egg_dh_params *params,
GBytes *bytes)
{
gcry_error_t gcry;
gcry_mpi_t inner;
egg_dh_pubkey *pub;
gcry = gcry_mpi_scan (&inner, GCRYMPI_FMT_USG,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes),
NULL);
g_return_val_if_fail (gcry == 0, NULL);
pub = g_new (struct egg_dh_pubkey, 1);
if (!pub) {
gcry_mpi_release (inner);
g_return_val_if_reached (NULL);
}
pub->inner = inner;
return pub;
}

View File

@ -30,6 +30,17 @@ typedef struct egg_dh_params egg_dh_params;
typedef struct egg_dh_pubkey egg_dh_pubkey; typedef struct egg_dh_pubkey egg_dh_pubkey;
typedef struct egg_dh_privkey egg_dh_privkey; typedef struct egg_dh_privkey egg_dh_privkey;
typedef struct egg_dh_group {
const gchar *name;
guint bits;
const guchar *prime;
gsize n_prime;
const guchar base[1];
gsize n_base;
} egg_dh_group;
extern const egg_dh_group egg_dh_groups[];
egg_dh_params *egg_dh_default_params (const gchar *name); egg_dh_params *egg_dh_default_params (const gchar *name);
gboolean egg_dh_default_params_raw (const gchar *name, gboolean egg_dh_default_params_raw (const gchar *name,

110
egg/egg-hkdf-gnutls.c Normal file
View File

@ -0,0 +1,110 @@
/*
* libsecret
*
* Copyright (C) 2023 Daiki Ueno
*
* 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.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 Public License for more details.
*
* You should have received copies of the GNU General Public License and
* the GNU Lesser General Public License along with this program. If
* not, see http://www.gnu.org/licenses/.
*
* Author: Daiki Ueno
*/
#include "config.h"
#include "egg-hkdf.h"
#include "egg-secure-memory.h"
#include <gnutls/crypto.h>
EGG_SECURE_DECLARE (hkdf);
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)
{
static const struct {
gchar *name;
gnutls_mac_algorithm_t algo;
} hash_algos[] = {
{ "sha1", GNUTLS_MAC_SHA1 },
{ "sha256", GNUTLS_MAC_SHA256 },
{ NULL, }
};
gnutls_mac_algorithm_t algo = GNUTLS_MAC_UNKNOWN;
gnutls_datum_t input_datum, salt_datum, info_datum;
gpointer alloc = NULL;
gpointer buffer = NULL;
guint hash_len;
gsize i;
int ret;
gboolean result = TRUE;
for (i = 0; hash_algos[i].name; i++) {
if (g_str_equal (hash_algos[i].name, hash_algo)) {
algo = hash_algos[i].algo;
break;
}
}
g_return_val_if_fail (algo != GNUTLS_MAC_UNKNOWN, FALSE);
hash_len = gnutls_hmac_get_len (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 */
buffer = egg_secure_alloc (hash_len);
g_return_val_if_fail (buffer, FALSE);
/* Salt defaults to hash_len zeros */
if (!salt) {
alloc = g_malloc0 (hash_len);
if (!alloc) {
result = FALSE;
goto out;
}
salt = alloc;
n_salt = hash_len;
}
/* Step 1: Extract */
input_datum.data = (void *)input;
input_datum.size = n_input;
salt_datum.data = (void *)salt;
salt_datum.size = n_salt;
ret = gnutls_hkdf_extract (algo, &input_datum, &salt_datum, buffer);
if (ret < 0) {
result = FALSE;
goto out;
}
/* Step 2: Expand */
input_datum.data = buffer;
input_datum.size = hash_len;
info_datum.data = (void *)info;
info_datum.size = n_info;
ret = gnutls_hkdf_expand (algo, &input_datum, &info_datum,
output, n_output);
if (ret < 0) {
result = FALSE;
goto out;
}
out:
g_free (alloc);
egg_secure_free (buffer);
return result;
}

View File

@ -13,10 +13,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received copies of the GNU General Public License and
* License along with this program; if not, write to the Free Software * the GNU Lesser General Public License along with this program. If
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * not, see http://www.gnu.org/licenses/.
* MA 02110-1301 USA
* *
* Author: Stef Walter <stefw@collabora.co.uk> * Author: Stef Walter <stefw@collabora.co.uk>
*/ */
@ -24,10 +23,8 @@
#include "config.h" #include "config.h"
#include "egg-hkdf.h" #include "egg-hkdf.h"
#include "egg-secure-memory.h"
#include <gcrypt.h> #include <gcrypt.h>
#include <string.h> #include <string.h>
gboolean gboolean

156
egg/egg-keyring1-gnutls.c Normal file
View File

@ -0,0 +1,156 @@
/* libsecret - GLib wrapper for Secret Service
*
* Copyright 2019 Red Hat, Inc.
*
* 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.1 of the licence or (at
* your option) any later version.
*
* See the included COPYING file for more information.
*
* Author: Daiki Ueno
*/
#include "config.h"
#include "egg-keyring1.h"
#include "egg/egg-secure-memory.h"
EGG_SECURE_DECLARE (egg_keyring1);
#include <gnutls/crypto.h>
#define PBKDF2_HASH_ALGO GNUTLS_MAC_SHA256
#define MAC_ALGO GNUTLS_MAC_SHA256
#define CIPHER_ALGO GNUTLS_CIPHER_AES_128_CBC
void
egg_keyring1_create_nonce (guint8 *nonce,
gsize nonce_size)
{
(void)gnutls_rnd (GNUTLS_RND_NONCE, nonce, nonce_size);
}
GBytes *
egg_keyring1_derive_key (const char *password,
gsize n_password,
GBytes *salt,
guint32 iteration_count)
{
gnutls_datum_t password_datum, salt_datum;
guint8 *buffer;
int ret;
password_datum.data = (void *)password;
password_datum.size = n_password;
salt_datum.data = (void *)g_bytes_get_data (salt, NULL);
salt_datum.size = g_bytes_get_size (salt);
buffer = egg_secure_alloc (KEY_SIZE);
g_return_val_if_fail (buffer, NULL);
ret = gnutls_pbkdf2 (PBKDF2_HASH_ALGO, &password_datum, &salt_datum,
iteration_count,
buffer, KEY_SIZE);
if (ret < 0) {
egg_secure_free (buffer);
return NULL;
}
return g_bytes_new_with_free_func (buffer,
KEY_SIZE,
egg_secure_free,
buffer);
}
gboolean
egg_keyring1_calculate_mac (GBytes *key,
const guint8 *value,
gsize n_value,
guint8 *buffer)
{
return gnutls_hmac_fast (MAC_ALGO,
g_bytes_get_data (key, NULL),
g_bytes_get_size (key),
value, n_value,
buffer) >= 0;
}
gboolean
egg_keyring1_verify_mac (GBytes *key,
const guint8 *value,
gsize n_value,
const guint8 *data)
{
guint8 buffer[MAC_SIZE];
guint8 status = 0;
gsize i;
if (!egg_keyring1_calculate_mac (key, value, n_value, buffer)) {
return FALSE;
}
for (i = 0; i < MAC_SIZE; i++) {
status |= data[i] ^ buffer[i];
}
return status == 0;
}
gboolean
egg_keyring1_decrypt (GBytes *key,
guint8 *data,
gsize n_data)
{
gnutls_cipher_hd_t hd = NULL;
int ret;
gsize n_secret;
gnutls_datum_t key_datum, iv_datum;
key_datum.data = (void *)g_bytes_get_data (key, &n_secret);
key_datum.size = n_secret;
iv_datum.data = data + n_data;
iv_datum.size = IV_SIZE;
ret = gnutls_cipher_init (&hd, CIPHER_ALGO, &key_datum, &iv_datum);
if (ret < 0) {
return FALSE;
}
ret = gnutls_cipher_decrypt2 (hd, data, n_data, data, n_data);
if (ret < 0) {
gnutls_cipher_deinit (hd);
return FALSE;
}
gnutls_cipher_deinit (hd);
return TRUE;
}
gboolean
egg_keyring1_encrypt (GBytes *key,
guint8 *data,
gsize n_data)
{
gnutls_cipher_hd_t hd = NULL;
int ret;
gsize n_secret;
gnutls_datum_t key_datum, iv_datum;
key_datum.data = (void *)g_bytes_get_data (key, &n_secret);
key_datum.size = n_secret;
iv_datum.data = data + n_data;
iv_datum.size = IV_SIZE;
egg_keyring1_create_nonce (iv_datum.data, iv_datum.size);
ret = gnutls_cipher_init (&hd, CIPHER_ALGO, &key_datum, &iv_datum);
g_return_val_if_fail (ret >= 0, FALSE);
ret = gnutls_cipher_encrypt2 (hd, data, n_data, data, n_data);
gnutls_cipher_deinit (hd);
return ret < 0 ? FALSE : TRUE;
}

View File

@ -8,15 +8,27 @@ libegg_deps = [
glib_deps, glib_deps,
] ]
if get_option('gcrypt') if with_crypto
libegg_sources += [ libegg_sources += [
'egg-dh.c', 'egg-dh.c',
'egg-hkdf.c',
'egg-keyring1.c',
'egg-libgcrypt.c',
] ]
libegg_deps += gcrypt_dep if with_gcrypt
libegg_sources += [
'egg-dh-libgcrypt.c',
'egg-hkdf-libgcrypt.c',
'egg-keyring1-libgcrypt.c',
'egg-libgcrypt.c',
]
elif with_gnutls
libegg_sources += [
'egg-dh-gnutls.c',
'egg-hkdf-gnutls.c',
'egg-keyring1-gnutls.c',
]
endif
libegg_deps += crypto_deps
endif endif
if get_option('tpm2') if get_option('tpm2')
@ -39,7 +51,7 @@ test_names = [
'test-secmem', 'test-secmem',
] ]
if get_option('gcrypt') if with_crypto
test_names += [ test_names += [
'test-dh', 'test-dh',
'test-hkdf', 'test-hkdf',

View File

@ -33,7 +33,6 @@
#include <string.h> #include <string.h>
#include <glib.h> #include <glib.h>
#include <gcrypt.h>
EGG_SECURE_DEFINE_GLIB_GLOBALS (); EGG_SECURE_DEFINE_GLIB_GLOBALS ();
@ -107,10 +106,8 @@ static void
check_dh_default (const gchar *name, guint bits) check_dh_default (const gchar *name, guint bits)
{ {
gboolean ret; gboolean ret;
gcry_mpi_t check;
gconstpointer prime, base; gconstpointer prime, base;
gsize n_prime, n_base; gsize n_prime, n_base;
gcry_error_t gcry;
ret = egg_dh_default_params_raw (name, &prime, &n_prime, &base, &n_base); ret = egg_dh_default_params_raw (name, &prime, &n_prime, &base, &n_base);
g_assert_true (ret); g_assert_true (ret);
@ -118,14 +115,6 @@ check_dh_default (const gchar *name, guint bits)
egg_assert_cmpsize (n_prime, >, 0); egg_assert_cmpsize (n_prime, >, 0);
g_assert_nonnull (base); g_assert_nonnull (base);
egg_assert_cmpsize (n_base, >, 0); egg_assert_cmpsize (n_base, >, 0);
gcry = gcry_mpi_scan (&check, GCRYMPI_FMT_USG, prime, n_prime, NULL);
g_assert_true (gcry == 0);
gcry_mpi_release (check);
gcry = gcry_mpi_scan (&check, GCRYMPI_FMT_USG, base, n_base, NULL);
g_assert_true (gcry == 0);
gcry_mpi_release (check);
} }
static void static void

View File

@ -36,7 +36,7 @@ libsecret_headers = [
'secret-value.h', 'secret-value.h',
] ]
if get_option('gcrypt') if with_crypto
libsecret_sources += [ libsecret_sources += [
'secret-file-backend.c', 'secret-file-backend.c',
'secret-file-collection.c', 'secret-file-collection.c',
@ -76,8 +76,8 @@ libsecret_dependencies = [
glib_deps, glib_deps,
] ]
if get_option('gcrypt') if with_crypto
libsecret_dependencies += gcrypt_dep libsecret_dependencies += crypto_deps
endif endif
libsecret_cflags = [ libsecret_cflags = [
@ -231,7 +231,7 @@ test_names = [
'test-collection', 'test-collection',
] ]
if get_option('gcrypt') if with_crypto
test_names += [ test_names += [
'test-file-collection', 'test-file-collection',
] ]

View File

@ -16,7 +16,7 @@
#include "secret-backend.h" #include "secret-backend.h"
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
#include "secret-file-backend.h" #include "secret-file-backend.h"
#endif #endif
@ -148,11 +148,11 @@ backend_get_impl_type (void)
GIOExtensionPoint *ep; GIOExtensionPoint *ep;
g_type_ensure (secret_service_get_type ()); g_type_ensure (secret_service_get_type ());
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
g_type_ensure (secret_file_backend_get_type ()); g_type_ensure (secret_file_backend_get_type ());
#endif #endif
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
if ((g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS) || g_getenv ("SNAP_NAME") != NULL) && if ((g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS) || g_getenv ("SNAP_NAME") != NULL) &&
_secret_file_backend_check_portal_version ()) _secret_file_backend_check_portal_version ())
extension_name = "file"; extension_name = "file";

View File

@ -17,11 +17,14 @@
#include "secret-file-collection.h" #include "secret-file-collection.h"
#include "egg/egg-keyring1.h" #include "egg/egg-keyring1.h"
#include "egg/egg-libgcrypt.h"
#include "egg/egg-secure-memory.h" #include "egg/egg-secure-memory.h"
EGG_SECURE_DECLARE (secret_file_collection); EGG_SECURE_DECLARE (secret_file_collection);
#ifdef WITH_GCRYPT
#include "egg/egg-libgcrypt.h"
#endif
#define KEYRING_FILE_HEADER "GnomeKeyring\n\r\0\n" #define KEYRING_FILE_HEADER "GnomeKeyring\n\r\0\n"
#define KEYRING_FILE_HEADER_LEN 16 #define KEYRING_FILE_HEADER_LEN 16
@ -143,8 +146,9 @@ secret_file_collection_class_init (SecretFileCollectionClass *klass)
g_param_spec_boxed ("password", "password", "Password", g_param_spec_boxed ("password", "password", "Password",
SECRET_TYPE_VALUE, SECRET_TYPE_VALUE,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
#ifdef WITH_GCRYPT
egg_libgcrypt_initialize (); egg_libgcrypt_initialize ();
#endif
} }
static gboolean static gboolean

View File

@ -17,13 +17,20 @@
#include "secret-private.h" #include "secret-private.h"
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
#include "egg/egg-dh.h" #include "egg/egg-dh.h"
#include "egg/egg-hkdf.h" #include "egg/egg-hkdf.h"
#endif
#ifdef WITH_GCRYPT
#include "egg/egg-libgcrypt.h" #include "egg/egg-libgcrypt.h"
#include <gcrypt.h> #include <gcrypt.h>
#endif #endif
#ifdef WITH_GNUTLS
#include <gnutls/crypto.h>
#endif
#include "egg/egg-hex.h" #include "egg/egg-hex.h"
#include "egg/egg-secure-memory.h" #include "egg/egg-secure-memory.h"
@ -37,7 +44,7 @@ EGG_SECURE_DECLARE (secret_session);
struct _SecretSession { struct _SecretSession {
gchar *path; gchar *path;
const gchar *algorithms; const gchar *algorithms;
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
egg_dh_params *params; egg_dh_params *params;
egg_dh_privkey *privat; egg_dh_privkey *privat;
egg_dh_pubkey *publi; egg_dh_pubkey *publi;
@ -55,7 +62,7 @@ _secret_session_free (gpointer data)
return; return;
g_free (session->path); g_free (session->path);
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
egg_dh_pubkey_free (session->publi); egg_dh_pubkey_free (session->publi);
egg_dh_privkey_free (session->privat); egg_dh_privkey_free (session->privat);
egg_dh_params_free (session->params); egg_dh_params_free (session->params);
@ -64,7 +71,7 @@ _secret_session_free (gpointer data)
g_free (session); g_free (session);
} }
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
static GVariant * static GVariant *
request_open_session_aes (SecretSession *session) request_open_session_aes (SecretSession *session)
@ -76,7 +83,9 @@ request_open_session_aes (SecretSession *session)
g_assert (session->privat == NULL); g_assert (session->privat == NULL);
g_assert (session->publi == NULL); g_assert (session->publi == NULL);
#ifdef WITH_GCRYPT
egg_libgcrypt_initialize (); egg_libgcrypt_initialize ();
#endif
/* Initialize our local parameters and values */ /* Initialize our local parameters and values */
session->params = egg_dh_default_params ("ietf-ike-grp-modp-1024"); session->params = egg_dh_default_params ("ietf-ike-grp-modp-1024");
@ -168,7 +177,7 @@ response_open_session_aes (SecretSession *session,
return TRUE; return TRUE;
} }
#endif /* WITH_GCRYPT */ #endif /* WITH_CRYPTO */
static GVariant * static GVariant *
request_open_session_plain (SecretSession *session) request_open_session_plain (SecretSession *session)
@ -251,7 +260,7 @@ on_service_open_session_plain (GObject *source,
g_object_unref (task); g_object_unref (task);
} }
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
static void static void
on_service_open_session_aes (GObject *source, on_service_open_session_aes (GObject *source,
@ -300,7 +309,7 @@ on_service_open_session_aes (GObject *source,
g_object_unref (task); g_object_unref (task);
} }
#endif /* WITH_GCRYPT */ #endif /* WITH_CRYPTO */
void void
@ -319,7 +328,7 @@ _secret_session_open (SecretService *service,
g_task_set_task_data (task, closure, open_session_closure_free); g_task_set_task_data (task, closure, open_session_closure_free);
g_dbus_proxy_call (G_DBUS_PROXY (service), "OpenSession", g_dbus_proxy_call (G_DBUS_PROXY (service), "OpenSession",
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
request_open_session_aes (closure->session), request_open_session_aes (closure->session),
G_DBUS_CALL_FLAGS_NONE, -1, G_DBUS_CALL_FLAGS_NONE, -1,
cancellable, on_service_open_session_aes, cancellable, on_service_open_session_aes,
@ -345,7 +354,7 @@ _secret_session_open_finish (GAsyncResult *result,
return TRUE; return TRUE;
} }
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
static gboolean static gboolean
pkcs7_unpad_bytes_in_place (guchar *padded, pkcs7_unpad_bytes_in_place (guchar *padded,
@ -377,6 +386,8 @@ pkcs7_unpad_bytes_in_place (guchar *padded,
return TRUE; return TRUE;
} }
#ifdef WITH_GCRYPT
static SecretValue * static SecretValue *
service_decode_aes_secret (SecretSession *session, service_decode_aes_secret (SecretSession *session,
gconstpointer param, gconstpointer param,
@ -447,6 +458,85 @@ service_decode_aes_secret (SecretSession *session,
#endif /* WITH_GCRYPT */ #endif /* WITH_GCRYPT */
#ifdef WITH_GNUTLS
static SecretValue *
service_decode_aes_secret (SecretSession *session,
gconstpointer param,
gsize n_param,
gconstpointer value,
gsize n_value,
const gchar *content_type)
{
gnutls_cipher_hd_t cih;
gnutls_datum_t iv, key;
gsize n_padded;
int ret;
guchar *padded;
if (n_param != 16) {
g_info ("received an encrypted secret structure with invalid parameter");
return NULL;
}
if (n_value == 0 || n_value % 16 != 0) {
g_info ("received an encrypted secret structure with bad secret length");
return NULL;
}
#if 0
g_printerr (" lib iv: %s\n", egg_hex_encode (param, n_param));
#endif
#if 0
g_printerr (" lib key: %s\n", egg_hex_encode (session->key, session->n_key));
#endif
iv.data = (void *)param;
iv.size = n_param;
key.data = session->key;
key.size = session->n_key;
ret = gnutls_cipher_init (&cih, GNUTLS_CIPHER_AES_128_CBC, &key, &iv);
if (ret != 0) {
g_warning ("couldn't create AES cipher: %s", gnutls_strerror (ret));
return NULL;
}
/* Copy the memory buffer */
n_padded = n_value;
padded = egg_secure_alloc (n_padded);
if (!padded) {
gnutls_cipher_deinit (cih);
return NULL;
}
memcpy (padded, value, n_padded);
/* Perform the decryption */
ret = gnutls_cipher_decrypt2 (cih, padded, n_padded, padded, n_padded);
if (ret < 0) {
egg_secure_clear (padded, n_padded);
egg_secure_free (padded);
gnutls_cipher_deinit (cih);
return NULL;
}
gnutls_cipher_deinit (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_info ("received an invalid or unencryptable secret");
return FALSE;
}
return secret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free);
}
#endif /* WITH_GNUTLS */
#endif /* WITH_CRYPTO */
static SecretValue * static SecretValue *
service_decode_plain_secret (SecretSession *session, service_decode_plain_secret (SecretSession *session,
gconstpointer param, gconstpointer param,
@ -496,7 +586,7 @@ _secret_session_decode_secret (SecretSession *session,
value = g_variant_get_fixed_array (vvalue, &n_value, sizeof (guchar)); value = g_variant_get_fixed_array (vvalue, &n_value, sizeof (guchar));
g_variant_get_child (encoded, 3, "s", &content_type); g_variant_get_child (encoded, 3, "s", &content_type);
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
if (session->key != NULL) if (session->key != NULL)
result = service_decode_aes_secret (session, param, n_param, result = service_decode_aes_secret (session, param, n_param,
value, n_value, content_type); value, n_value, content_type);
@ -513,7 +603,7 @@ _secret_session_decode_secret (SecretSession *session,
return result; return result;
} }
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
static guchar* static guchar*
pkcs7_pad_bytes_in_secure_memory (gconstpointer secret, pkcs7_pad_bytes_in_secure_memory (gconstpointer secret,
@ -535,6 +625,8 @@ pkcs7_pad_bytes_in_secure_memory (gconstpointer secret,
return padded; return padded;
} }
#ifdef WITH_GCRYPT
static gboolean static gboolean
service_encode_aes_secret (SecretSession *session, service_encode_aes_secret (SecretSession *session,
SecretValue *value, SecretValue *value,
@ -594,6 +686,72 @@ service_encode_aes_secret (SecretSession *session,
#endif /* WITH_GCRYPT */ #endif /* WITH_GCRYPT */
#ifdef WITH_GNUTLS
static gboolean
service_encode_aes_secret (SecretSession *session,
SecretValue *value,
GVariantBuilder *builder)
{
gnutls_cipher_hd_t cih = NULL;
guchar *padded;
gsize n_padded;
int ret;
gnutls_datum_t iv, key;
gpointer iv_data;
gconstpointer secret;
gsize n_secret;
GVariant *child;
g_variant_builder_add (builder, "o", session->path);
secret = secret_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_data = g_malloc0 (16);
iv.data = iv_data;
iv.size = 16;
ret = gnutls_rnd (GNUTLS_RND_NONCE, iv.data, iv.size);
g_return_val_if_fail (ret >= 0, FALSE);
/* Setup the key */
key.data = session->key;
key.size = session->n_key;
/* Create the cipher */
ret = gnutls_cipher_init (&cih, GNUTLS_CIPHER_AES_128_CBC, &key, &iv);
if (ret < 0) {
g_warning ("couldn't create AES cipher: %s", gnutls_strerror (ret));
return FALSE;
}
/* Perform the encryption */
ret = gnutls_cipher_encrypt2 (cih, padded, n_padded, padded, n_padded);
if (ret < 0) {
gnutls_cipher_deinit (cih);
return FALSE;
}
gnutls_cipher_deinit (cih);
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), iv_data, 16, TRUE, g_free, iv_data);
g_variant_builder_add_value (builder, 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_builder_add (builder, "s", secret_value_get_content_type (value));
return TRUE;
}
#endif /* WITH_GNUTLS */
#endif /* WITH_CRYPTO */
static gboolean static gboolean
service_encode_plain_secret (SecretSession *session, service_encode_plain_secret (SecretSession *session,
SecretValue *value, SecretValue *value,
@ -633,7 +791,7 @@ _secret_session_encode_secret (SecretSession *session,
type = g_variant_type_new ("(oayays)"); type = g_variant_type_new ("(oayays)");
builder = g_variant_builder_new (type); builder = g_variant_builder_new (type);
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
if (session->key) if (session->key)
ret = service_encode_aes_secret (session, value, builder); ret = service_encode_aes_secret (session, value, builder);
else else

View File

@ -29,7 +29,7 @@
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef WITH_GCRYPT #ifdef WITH_CRYPTO
#define SESSION_ALGO "dh-ietf1024-sha256-aes128-cbc-pkcs7" #define SESSION_ALGO "dh-ietf1024-sha256-aes128-cbc-pkcs7"
#else #else
#define SESSION_ALGO "plain" #define SESSION_ALGO "plain"

View File

@ -30,11 +30,37 @@ glib_deps = [
dependency('gio-unix-2.0', version: '>=' + min_glib_version), dependency('gio-unix-2.0', version: '>=' + min_glib_version),
] ]
with_gcrypt = false
with_gnutls = false
with_crypto = false
crypto_deps = []
if get_option('crypto') == 'libgcrypt'
min_libgcrypt_version = '1.2.2' min_libgcrypt_version = '1.2.2'
gcrypt_dep = dependency('libgcrypt', gcrypt_dep = dependency(
'libgcrypt',
version: '>=' + min_libgcrypt_version, version: '>=' + min_libgcrypt_version,
required: get_option('gcrypt'), required: false,
) )
if gcrypt_dep.found()
with_gcrypt = true
with_crypto = true
crypto_deps += gcrypt_dep
endif
elif get_option('crypto') == 'gnutls'
min_gnutls_version = '3.8.2'
gnutls_dep = dependency(
'gnutls',
version: '>=' + min_gnutls_version,
required: false,
)
if gnutls_dep.found()
with_gnutls = true
with_crypto = true
crypto_deps += gnutls_dep
endif
endif
min_tss2_version = '3.0.3' min_tss2_version = '3.0.3'
tss2_esys = dependency('tss2-esys', version: '>=' + min_tss2_version, required: get_option('tpm2')) tss2_esys = dependency('tss2-esys', version: '>=' + min_tss2_version, required: get_option('tpm2'))
@ -58,9 +84,11 @@ conf.set_quoted('LOCALEDIR', libsecret_prefix / get_option('localedir'))
conf.set_quoted('PACKAGE_NAME', meson.project_name()) conf.set_quoted('PACKAGE_NAME', meson.project_name())
conf.set_quoted('PACKAGE_STRING', meson.project_name()) conf.set_quoted('PACKAGE_STRING', meson.project_name())
conf.set_quoted('PACKAGE_VERSION', meson.project_version()) conf.set_quoted('PACKAGE_VERSION', meson.project_version())
conf.set('WITH_GCRYPT', get_option('gcrypt')) conf.set('WITH_GCRYPT', with_gcrypt)
conf.set('WITH_GNUTLS', with_gnutls)
conf.set('WITH_CRYPTO', with_crypto)
conf.set('WITH_TPM', get_option('tpm2')) conf.set('WITH_TPM', get_option('tpm2'))
if get_option('gcrypt') if with_gcrypt
conf.set_quoted('LIBGCRYPT_VERSION', min_libgcrypt_version) conf.set_quoted('LIBGCRYPT_VERSION', min_libgcrypt_version)
endif endif
if get_option('tpm2') if get_option('tpm2')

View File

@ -1,5 +1,5 @@
option('manpage', type: 'boolean', value: true, description: 'Build man pages') option('manpage', type: 'boolean', value: true, description: 'Build man pages')
option('gcrypt', type: 'boolean', value: true, description: 'With gcrypt and transport encryption') option('crypto', type: 'combo', choices: ['libgcrypt', 'gnutls', 'disabled'], value: 'libgcrypt', description: 'Backend library to implement transport encryption')
option('debugging', type: 'boolean', value: false, description: 'Turn debugging on/off') option('debugging', type: 'boolean', value: false, description: 'Turn debugging on/off')
option('vapi', type: 'boolean', value: true, description: 'Create VAPI file.') option('vapi', type: 'boolean', value: true, description: 'Create VAPI file.')
option('gtk_doc', type: 'boolean', value: true, description: 'Build reference documentation using gi-docgen') option('gtk_doc', type: 'boolean', value: true, description: 'Build reference documentation using gi-docgen')

View File

@ -10,7 +10,7 @@ secret_tool = executable('secret-tool',
install: true, install: true,
) )
if get_option('gcrypt') and host_machine.system() != 'windows' if with_crypto and host_machine.system() != 'windows'
test('test-secret-tool.sh', test('test-secret-tool.sh',
find_program('test-secret-tool.sh'), find_program('test-secret-tool.sh'),
env: test_env, env: test_env,