add check for sufficiently recent version of libgnunetutil, remove now unnecessary crypto blinding logic
This commit is contained in:
parent
247d1ca3e5
commit
e1e9250ff7
@ -129,11 +129,16 @@ AC_CHECK_HEADERS([gnunet/platform.h gnunet/gnunet_util_lib.h],
|
|||||||
[AC_CHECK_LIB([gnunetutil], [GNUNET_SCHEDULER_run], libgnunetutil=1)],
|
[AC_CHECK_LIB([gnunetutil], [GNUNET_SCHEDULER_run], libgnunetutil=1)],
|
||||||
[], [#ifdef HAVE_GNUNET_PLATFORM_H
|
[], [#ifdef HAVE_GNUNET_PLATFORM_H
|
||||||
#include <gnunet/platform.h>
|
#include <gnunet/platform.h>
|
||||||
|
#endif
|
||||||
|
#include <gnunet/gnunet_common.h>
|
||||||
|
#if GNUNET_UTIL_VERSION < 0x00A0104
|
||||||
|
#fail libgnunetutil is too old
|
||||||
#endif])
|
#endif])
|
||||||
AS_IF([test $libgnunetutil != 1],
|
AS_IF([test $libgnunetutil != 1],
|
||||||
[AC_MSG_ERROR([[
|
[AC_MSG_ERROR([[
|
||||||
***
|
***
|
||||||
*** You need libgnunetutil to build this program.
|
*** You need libgnunetutil > 0.14.0 to build this program.
|
||||||
|
*** (Yes, ">", libgnunetutil 0.14.0 is NOT enough.)
|
||||||
*** This library is part of GNUnet, available at
|
*** This library is part of GNUnet, available at
|
||||||
*** https://gnunet.org
|
*** https://gnunet.org
|
||||||
*** ]])])
|
*** ]])])
|
||||||
|
@ -25,18 +25,6 @@
|
|||||||
#include "taler_util.h"
|
#include "taler_util.h"
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* Should we use the RSA blind signing implementation from libgnunetutil? The
|
|
||||||
* blinding only works correctly with a current version of libgnunetutil.
|
|
||||||
*
|
|
||||||
* Only applies to blinding and unblinding, but
|
|
||||||
* not to blind signing.
|
|
||||||
*
|
|
||||||
* FIXME: Can we define some macro for this in configure.ac
|
|
||||||
* to detect the version?
|
|
||||||
*/
|
|
||||||
#define USE_GNUNET_RSA_BLINDING 0
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called by libgcrypt on serious errors.
|
* Function called by libgcrypt on serious errors.
|
||||||
@ -312,280 +300,6 @@ TALER_refresh_get_commitment (struct TALER_RefreshCommitmentP *rc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if ! USE_GNUNET_RSA_BLINDING
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The private information of an RSA key pair.
|
|
||||||
*
|
|
||||||
* FIXME: This declaration is evil, as it defines
|
|
||||||
* an opaque struct that is "owned" by GNUnet.
|
|
||||||
*/
|
|
||||||
struct GNUNET_CRYPTO_RsaPrivateKey
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Libgcrypt S-expression for the RSA private key.
|
|
||||||
*/
|
|
||||||
gcry_sexp_t sexp;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The public information of an RSA key pair.
|
|
||||||
*
|
|
||||||
* FIXME: This declaration is evil, as it defines
|
|
||||||
* an opaque struct that is "owned" by GNUnet.
|
|
||||||
*/
|
|
||||||
struct GNUNET_CRYPTO_RsaPublicKey
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Libgcrypt S-expression for the RSA public key.
|
|
||||||
*/
|
|
||||||
gcry_sexp_t sexp;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief an RSA signature
|
|
||||||
*
|
|
||||||
* FIXME: This declaration is evil, as it defines
|
|
||||||
* an opaque struct that is "owned" by GNUnet.
|
|
||||||
*/
|
|
||||||
struct GNUNET_CRYPTO_RsaSignature
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Libgcrypt S-expression for the RSA signature.
|
|
||||||
*/
|
|
||||||
gcry_sexp_t sexp;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief RSA blinding key
|
|
||||||
*/
|
|
||||||
struct RsaBlindingKey
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Random value used for blinding.
|
|
||||||
*/
|
|
||||||
gcry_mpi_t r;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy a blinding key
|
|
||||||
*
|
|
||||||
* @param bkey the blinding key to destroy
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
rsa_blinding_key_free (struct RsaBlindingKey *bkey)
|
|
||||||
{
|
|
||||||
gcry_mpi_release (bkey->r);
|
|
||||||
GNUNET_free (bkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract values from an S-expression.
|
|
||||||
*
|
|
||||||
* @param array where to store the result(s)
|
|
||||||
* @param sexp S-expression to parse
|
|
||||||
* @param topname top-level name in the S-expression that is of interest
|
|
||||||
* @param elems names of the elements to extract
|
|
||||||
* @return 0 on success
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
key_from_sexp (gcry_mpi_t *array,
|
|
||||||
gcry_sexp_t sexp,
|
|
||||||
const char *topname,
|
|
||||||
const char *elems)
|
|
||||||
{
|
|
||||||
gcry_sexp_t list;
|
|
||||||
gcry_sexp_t l2;
|
|
||||||
const char *s;
|
|
||||||
unsigned int idx;
|
|
||||||
|
|
||||||
if (! (list = gcry_sexp_find_token (sexp, topname, 0)))
|
|
||||||
return 1;
|
|
||||||
l2 = gcry_sexp_cadr (list);
|
|
||||||
gcry_sexp_release (list);
|
|
||||||
list = l2;
|
|
||||||
if (! list)
|
|
||||||
return 2;
|
|
||||||
idx = 0;
|
|
||||||
for (s = elems; *s; s++, idx++)
|
|
||||||
{
|
|
||||||
if (! (l2 = gcry_sexp_find_token (list, s, 1)))
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < idx; i++)
|
|
||||||
{
|
|
||||||
gcry_free (array[i]);
|
|
||||||
array[i] = NULL;
|
|
||||||
}
|
|
||||||
gcry_sexp_release (list);
|
|
||||||
return 3; /* required parameter not found */
|
|
||||||
}
|
|
||||||
array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
|
|
||||||
gcry_sexp_release (l2);
|
|
||||||
if (! array[idx])
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < idx; i++)
|
|
||||||
{
|
|
||||||
gcry_free (array[i]);
|
|
||||||
array[i] = NULL;
|
|
||||||
}
|
|
||||||
gcry_sexp_release (list);
|
|
||||||
return 4; /* required parameter is invalid */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gcry_sexp_release (list);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for malicious RSA key.
|
|
||||||
*
|
|
||||||
* Assuming n is an RSA modulous and r is generated using a call to
|
|
||||||
* GNUNET_CRYPTO_kdf_mod_mpi, if gcd(r,n) != 1 then n must be a
|
|
||||||
* malicious RSA key designed to deanomize the user.
|
|
||||||
*
|
|
||||||
* @param r KDF result
|
|
||||||
* @param n RSA modulus
|
|
||||||
* @return True if gcd(r,n) = 1, False means RSA key is malicious
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
rsa_gcd_validate (gcry_mpi_t r, gcry_mpi_t n)
|
|
||||||
{
|
|
||||||
gcry_mpi_t g;
|
|
||||||
int t;
|
|
||||||
|
|
||||||
g = gcry_mpi_new (0);
|
|
||||||
t = gcry_mpi_gcd (g, r, n);
|
|
||||||
gcry_mpi_release (g);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes a full domain hash seeded by the given public key.
|
|
||||||
* This gives a measure of provable security to the Taler exchange
|
|
||||||
* against one-more forgery attacks. See:
|
|
||||||
* https://eprint.iacr.org/2001/002.pdf
|
|
||||||
* http://www.di.ens.fr/~pointche/Documents/Papers/2001_fcA.pdf
|
|
||||||
*
|
|
||||||
* @param hash initial hash of the message to sign
|
|
||||||
* @param pkey the public key of the signer
|
|
||||||
* @return MPI value set to the FDH, NULL if RSA key is malicious
|
|
||||||
*/
|
|
||||||
static gcry_mpi_t
|
|
||||||
rsa_full_domain_hash (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
|
|
||||||
const struct GNUNET_HashCode *hash)
|
|
||||||
{
|
|
||||||
gcry_mpi_t r, n;
|
|
||||||
void *xts;
|
|
||||||
size_t xts_len;
|
|
||||||
int ok;
|
|
||||||
|
|
||||||
/* Extract the composite n from the RSA public key */
|
|
||||||
GNUNET_assert (0 == key_from_sexp (&n, pkey->sexp, "rsa", "n"));
|
|
||||||
/* Assert that it at least looks like an RSA key */
|
|
||||||
GNUNET_assert (0 == gcry_mpi_get_flag (n, GCRYMPI_FLAG_OPAQUE));
|
|
||||||
|
|
||||||
/* We key with the public denomination key as a homage to RSA-PSS by *
|
|
||||||
* Mihir Bellare and Phillip Rogaway. Doing this lowers the degree *
|
|
||||||
* of the hypothetical polyomial-time attack on RSA-KTI created by a *
|
|
||||||
* polynomial-time one-more forgary attack. Yey seeding! */
|
|
||||||
xts_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, &xts);
|
|
||||||
|
|
||||||
GNUNET_CRYPTO_kdf_mod_mpi (&r,
|
|
||||||
n,
|
|
||||||
xts, xts_len,
|
|
||||||
hash, sizeof(*hash),
|
|
||||||
"RSA-FDA FTpsW!");
|
|
||||||
GNUNET_free (xts);
|
|
||||||
|
|
||||||
ok = rsa_gcd_validate (r, n);
|
|
||||||
gcry_mpi_release (n);
|
|
||||||
if (ok)
|
|
||||||
return r;
|
|
||||||
gcry_mpi_release (r);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a blinding key
|
|
||||||
*
|
|
||||||
* @param pkey the public key to blind for
|
|
||||||
* @param bks pre-secret to use to derive the blinding key
|
|
||||||
* @return the newly created blinding key, NULL if RSA key is malicious
|
|
||||||
*/
|
|
||||||
static struct RsaBlindingKey *
|
|
||||||
rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
|
|
||||||
const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks)
|
|
||||||
{
|
|
||||||
char *xts = "Blinding KDF extractor HMAC key"; /* Trusts bks' randomness more */
|
|
||||||
struct RsaBlindingKey *blind;
|
|
||||||
gcry_mpi_t n;
|
|
||||||
|
|
||||||
blind = GNUNET_new (struct RsaBlindingKey);
|
|
||||||
GNUNET_assert (NULL != blind);
|
|
||||||
|
|
||||||
/* Extract the composite n from the RSA public key */
|
|
||||||
GNUNET_assert (0 == key_from_sexp (&n, pkey->sexp, "rsa", "n"));
|
|
||||||
/* Assert that it at least looks like an RSA key */
|
|
||||||
GNUNET_assert (0 == gcry_mpi_get_flag (n, GCRYMPI_FLAG_OPAQUE));
|
|
||||||
|
|
||||||
GNUNET_CRYPTO_kdf_mod_mpi (&blind->r,
|
|
||||||
n,
|
|
||||||
xts, strlen (xts),
|
|
||||||
bks, sizeof(*bks),
|
|
||||||
"Blinding KDF");
|
|
||||||
if (0 == rsa_gcd_validate (blind->r, n))
|
|
||||||
{
|
|
||||||
GNUNET_free (blind);
|
|
||||||
blind = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
gcry_mpi_release (n);
|
|
||||||
return blind;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print an MPI to a newly created buffer
|
|
||||||
*
|
|
||||||
* @param v MPI to print.
|
|
||||||
* @param[out] buffer newly allocated buffer containing the result
|
|
||||||
* @return number of bytes stored in @a buffer
|
|
||||||
*/
|
|
||||||
static size_t
|
|
||||||
numeric_mpi_alloc_n_print (gcry_mpi_t v,
|
|
||||||
char **buffer)
|
|
||||||
{
|
|
||||||
size_t n;
|
|
||||||
char *b;
|
|
||||||
size_t rsize;
|
|
||||||
|
|
||||||
gcry_mpi_print (GCRYMPI_FMT_USG,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
&n,
|
|
||||||
v);
|
|
||||||
b = GNUNET_malloc (n);
|
|
||||||
GNUNET_assert (0 ==
|
|
||||||
gcry_mpi_print (GCRYMPI_FMT_USG,
|
|
||||||
(unsigned char *) b,
|
|
||||||
n,
|
|
||||||
&rsize,
|
|
||||||
v));
|
|
||||||
*buffer = b;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* ! USE_GNUNET_RSA_BLINDING */
|
|
||||||
|
|
||||||
|
|
||||||
enum GNUNET_GenericReturnValue
|
enum GNUNET_GenericReturnValue
|
||||||
TALER_rsa_blind (const struct GNUNET_HashCode *hash,
|
TALER_rsa_blind (const struct GNUNET_HashCode *hash,
|
||||||
const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks,
|
const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks,
|
||||||
@ -593,75 +307,11 @@ TALER_rsa_blind (const struct GNUNET_HashCode *hash,
|
|||||||
void **buf,
|
void **buf,
|
||||||
size_t *buf_size)
|
size_t *buf_size)
|
||||||
{
|
{
|
||||||
#if USE_GNUNET_RSA_BLINDING
|
|
||||||
return GNUNET_CRYPTO_rsa_blind (hash,
|
return GNUNET_CRYPTO_rsa_blind (hash,
|
||||||
bks,
|
bks,
|
||||||
pkey,
|
pkey,
|
||||||
buf,
|
buf,
|
||||||
buf_size);
|
buf_size);
|
||||||
#else
|
|
||||||
struct RsaBlindingKey *bkey;
|
|
||||||
gcry_mpi_t data;
|
|
||||||
gcry_mpi_t ne[2];
|
|
||||||
gcry_mpi_t r_e;
|
|
||||||
gcry_mpi_t data_r_e;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
GNUNET_assert (buf != NULL);
|
|
||||||
GNUNET_assert (buf_size != NULL);
|
|
||||||
ret = key_from_sexp (ne, pkey->sexp, "public-key", "ne");
|
|
||||||
if (0 != ret)
|
|
||||||
ret = key_from_sexp (ne, pkey->sexp, "rsa", "ne");
|
|
||||||
if (0 != ret)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
*buf = NULL;
|
|
||||||
*buf_size = 0;
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = rsa_full_domain_hash (pkey, hash);
|
|
||||||
if (NULL == data)
|
|
||||||
goto rsa_gcd_validate_failure;
|
|
||||||
|
|
||||||
bkey = rsa_blinding_key_derive (pkey, bks);
|
|
||||||
if (NULL == bkey)
|
|
||||||
{
|
|
||||||
gcry_mpi_release (data);
|
|
||||||
goto rsa_gcd_validate_failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
r_e = gcry_mpi_new (0);
|
|
||||||
gcry_mpi_powm (r_e,
|
|
||||||
bkey->r,
|
|
||||||
ne[1],
|
|
||||||
ne[0]);
|
|
||||||
data_r_e = gcry_mpi_new (0);
|
|
||||||
gcry_mpi_mulm (data_r_e,
|
|
||||||
data,
|
|
||||||
r_e,
|
|
||||||
ne[0]);
|
|
||||||
gcry_mpi_release (data);
|
|
||||||
gcry_mpi_release (ne[0]);
|
|
||||||
gcry_mpi_release (ne[1]);
|
|
||||||
gcry_mpi_release (r_e);
|
|
||||||
rsa_blinding_key_free (bkey);
|
|
||||||
|
|
||||||
*buf_size = numeric_mpi_alloc_n_print (data_r_e,
|
|
||||||
(char **) buf);
|
|
||||||
gcry_mpi_release (data_r_e);
|
|
||||||
|
|
||||||
return GNUNET_YES;
|
|
||||||
|
|
||||||
rsa_gcd_validate_failure:
|
|
||||||
/* We know the RSA key is malicious here, so warn the wallet. */
|
|
||||||
/* GNUNET_break_op (0); */
|
|
||||||
gcry_mpi_release (ne[0]);
|
|
||||||
gcry_mpi_release (ne[1]);
|
|
||||||
*buf = NULL;
|
|
||||||
*buf_size = 0;
|
|
||||||
return GNUNET_NO;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -670,82 +320,9 @@ TALER_rsa_unblind (const struct GNUNET_CRYPTO_RsaSignature *sig,
|
|||||||
const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks,
|
const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks,
|
||||||
struct GNUNET_CRYPTO_RsaPublicKey *pkey)
|
struct GNUNET_CRYPTO_RsaPublicKey *pkey)
|
||||||
{
|
{
|
||||||
#if USE_GNUNET_RSA_BLINDING
|
|
||||||
return GNUNET_CRYPTO_rsa_unblind (sig,
|
return GNUNET_CRYPTO_rsa_unblind (sig,
|
||||||
bks,
|
bks,
|
||||||
pkey);
|
pkey);
|
||||||
#else
|
|
||||||
struct RsaBlindingKey *bkey;
|
|
||||||
gcry_mpi_t n;
|
|
||||||
gcry_mpi_t s;
|
|
||||||
gcry_mpi_t r_inv;
|
|
||||||
gcry_mpi_t ubsig;
|
|
||||||
int ret;
|
|
||||||
struct GNUNET_CRYPTO_RsaSignature *sret;
|
|
||||||
|
|
||||||
ret = key_from_sexp (&n, pkey->sexp, "public-key", "n");
|
|
||||||
if (0 != ret)
|
|
||||||
ret = key_from_sexp (&n, pkey->sexp, "rsa", "n");
|
|
||||||
if (0 != ret)
|
|
||||||
{
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ret = key_from_sexp (&s, sig->sexp, "sig-val", "s");
|
|
||||||
if (0 != ret)
|
|
||||||
ret = key_from_sexp (&s, sig->sexp, "rsa", "s");
|
|
||||||
if (0 != ret)
|
|
||||||
{
|
|
||||||
gcry_mpi_release (n);
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bkey = rsa_blinding_key_derive (pkey, bks);
|
|
||||||
if (NULL == bkey)
|
|
||||||
{
|
|
||||||
/* RSA key is malicious since rsa_gcd_validate failed here.
|
|
||||||
* It should have failed during GNUNET_CRYPTO_rsa_blind too though,
|
|
||||||
* so the exchange is being malicious in an unfamilair way, maybe
|
|
||||||
* just trying to crash us. */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
gcry_mpi_release (n);
|
|
||||||
gcry_mpi_release (s);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
r_inv = gcry_mpi_new (0);
|
|
||||||
if (1 !=
|
|
||||||
gcry_mpi_invm (r_inv,
|
|
||||||
bkey->r,
|
|
||||||
n))
|
|
||||||
{
|
|
||||||
/* We cannot find r mod n, so gcd(r,n) != 1, which should get *
|
|
||||||
* caught above, but we handle it the same here. */
|
|
||||||
GNUNET_break_op (0);
|
|
||||||
gcry_mpi_release (r_inv);
|
|
||||||
rsa_blinding_key_free (bkey);
|
|
||||||
gcry_mpi_release (n);
|
|
||||||
gcry_mpi_release (s);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ubsig = gcry_mpi_new (0);
|
|
||||||
gcry_mpi_mulm (ubsig, s, r_inv, n);
|
|
||||||
gcry_mpi_release (n);
|
|
||||||
gcry_mpi_release (r_inv);
|
|
||||||
gcry_mpi_release (s);
|
|
||||||
rsa_blinding_key_free (bkey);
|
|
||||||
|
|
||||||
sret = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
|
|
||||||
GNUNET_assert (0 ==
|
|
||||||
gcry_sexp_build (&sret->sexp,
|
|
||||||
NULL,
|
|
||||||
"(sig-val (rsa (s %M)))",
|
|
||||||
ubsig));
|
|
||||||
gcry_mpi_release (ubsig);
|
|
||||||
return sret;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user