summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-05-30 15:39:52 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-06-07 13:04:02 +0200
commit60c32fd85e3f944a31ba93a368e0dda27ee397c8 (patch)
treed5286f9bf404d2972e8f85f4f535918fb6a15763
parent57f45e13eef3629e7384730284dbbc6fef46977e (diff)
downloadgnutls-60c32fd85e3f944a31ba93a368e0dda27ee397c8.tar.gz
abstract API: introduced new signing functions
That is, the gnutls_privkey_sign_data2() and gnutls_privkey_sign_hash2(). The new functions perform signing with input the signature algorithm instead of the hash algorithm; that allows to use algorithms where the hash algorithm is not used, or the public key algorithm may be different than the key's. Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/algorithms.h15
-rw-r--r--lib/algorithms/sign.c30
-rw-r--r--lib/includes/gnutls/abstract.h13
-rw-r--r--lib/libgnutls.map2
-rw-r--r--lib/privkey.c130
5 files changed, 166 insertions, 24 deletions
diff --git a/lib/algorithms.h b/lib/algorithms.h
index b666668cf0..3d8c95e910 100644
--- a/lib/algorithms.h
+++ b/lib/algorithms.h
@@ -292,6 +292,21 @@ enum encipher_type _gnutls_kx_encipher_type(gnutls_kx_algorithm_t
algorithm);
/* Functions for sign algorithms. */
+
+struct gnutls_sign_entry_st {
+ const char *name;
+ const char *oid;
+ gnutls_sign_algorithm_t id;
+ gnutls_pk_algorithm_t pk;
+ gnutls_digest_algorithm_t hash;
+ /* See RFC 5246 HashAlgorithm and SignatureAlgorithm
+ for values to use in aid struct. */
+ const sign_algorithm_st aid;
+};
+typedef struct gnutls_sign_entry_st gnutls_sign_entry_st;
+
+const gnutls_sign_entry_st *_gnutls_sign_to_entry(gnutls_sign_algorithm_t sign);
+
gnutls_pk_algorithm_t _gnutls_x509_sign_to_pk(gnutls_sign_algorithm_t
sign);
const char *_gnutls_x509_sign_to_oid(gnutls_pk_algorithm_t,
diff --git a/lib/algorithms/sign.c b/lib/algorithms/sign.c
index 1c19cc86fb..b64221bcfb 100644
--- a/lib/algorithms/sign.c
+++ b/lib/algorithms/sign.c
@@ -28,17 +28,6 @@
/* signature algorithms;
*/
-struct gnutls_sign_entry {
- const char *name;
- const char *oid;
- gnutls_sign_algorithm_t id;
- gnutls_pk_algorithm_t pk;
- gnutls_digest_algorithm_t mac;
- /* See RFC 5246 HashAlgorithm and SignatureAlgorithm
- for values to use in aid struct. */
- const sign_algorithm_st aid;
-};
-typedef struct gnutls_sign_entry gnutls_sign_entry;
#define TLS_SIGN_AID_UNKNOWN {255, 255}
static const sign_algorithm_st unknown_tls_aid = TLS_SIGN_AID_UNKNOWN;
@@ -46,7 +35,7 @@ static const sign_algorithm_st unknown_tls_aid = TLS_SIGN_AID_UNKNOWN;
/* Signature algorithms may be listed twice with a different PK algorithm,
* e.g., RSA-PSS-SHA256 can be generated by GNUTLS_PK_RSA or GNUTLS_PK_RSA_PSS.
*/
-static const gnutls_sign_entry sign_algorithms[] = {
+static const gnutls_sign_entry_st sign_algorithms[] = {
{"RSA-SHA1", SIG_RSA_SHA1_OID, GNUTLS_SIGN_RSA_SHA1, GNUTLS_PK_RSA,
GNUTLS_DIG_SHA1, {2, 1}},
{"RSA-SHA1", ISO_SIG_RSA_SHA1_OID, GNUTLS_SIGN_RSA_SHA1,
@@ -146,7 +135,7 @@ static const gnutls_sign_entry sign_algorithms[] = {
#define GNUTLS_SIGN_LOOP(b) \
do { \
- const gnutls_sign_entry *p; \
+ const gnutls_sign_entry_st *p; \
for(p = sign_algorithms; p->name != NULL; p++) { b ; } \
} while (0)
@@ -185,7 +174,7 @@ int gnutls_sign_is_secure(gnutls_sign_algorithm_t algorithm)
gnutls_digest_algorithm_t dig = GNUTLS_DIG_UNKNOWN;
/* avoid prefix */
- GNUTLS_SIGN_ALG_LOOP(dig = p->mac);
+ GNUTLS_SIGN_ALG_LOOP(dig = p->hash);
if (dig != GNUTLS_DIG_UNKNOWN)
return _gnutls_digest_is_secure(hash_to_entry(dig));
@@ -289,7 +278,7 @@ gnutls_pk_to_sign(gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash)
gnutls_sign_algorithm_t ret = 0;
GNUTLS_SIGN_LOOP(
- if (pk == p->pk && hash == p->mac) {
+ if (pk == p->pk && hash == p->hash) {
ret = p->id;
break;
}
@@ -336,7 +325,7 @@ gnutls_sign_get_hash_algorithm(gnutls_sign_algorithm_t sign)
{
gnutls_digest_algorithm_t ret = GNUTLS_DIG_UNKNOWN;
- GNUTLS_SIGN_ALG_LOOP(ret = p->mac);
+ GNUTLS_SIGN_ALG_LOOP(ret = p->hash);
return ret;
}
@@ -422,3 +411,12 @@ const sign_algorithm_st *_gnutls_sign_to_tls_aid(gnutls_sign_algorithm_t
return ret;
}
+
+const gnutls_sign_entry_st *_gnutls_sign_to_entry(gnutls_sign_algorithm_t sign)
+{
+ const gnutls_sign_entry_st *ret = NULL;
+
+ GNUTLS_SIGN_ALG_LOOP(ret = p);
+
+ return ret;
+}
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
index 5acc6bc555..94bb9b9042 100644
--- a/lib/includes/gnutls/abstract.h
+++ b/lib/includes/gnutls/abstract.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2015-2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -404,6 +405,12 @@ int gnutls_privkey_sign_data(gnutls_privkey_t signer,
const gnutls_datum_t * data,
gnutls_datum_t * signature);
+int gnutls_privkey_sign_data2(gnutls_privkey_t signer,
+ gnutls_sign_algorithm_t algo,
+ unsigned int flags,
+ const gnutls_datum_t * data,
+ gnutls_datum_t * signature);
+
#define gnutls_privkey_sign_raw_data(key, flags, data, sig) \
gnutls_privkey_sign_hash ( key, 0, GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA, data, sig)
@@ -413,6 +420,12 @@ int gnutls_privkey_sign_hash(gnutls_privkey_t signer,
const gnutls_datum_t * hash_data,
gnutls_datum_t * signature);
+int gnutls_privkey_sign_hash2(gnutls_privkey_t signer,
+ gnutls_sign_algorithm_t algo,
+ unsigned int flags,
+ const gnutls_datum_t * hash_data,
+ gnutls_datum_t * signature);
+
int gnutls_privkey_decrypt_data(gnutls_privkey_t key,
unsigned int flags,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 672c55bdc1..d32f482e95 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1156,6 +1156,8 @@ GNUTLS_3_4
gnutls_x509_crq_set_pk_algorithm;
gnutls_x509_privkey_get_pk_algorithm3;
gnutls_sign_supports_pk_algorithm;
+ gnutls_privkey_sign_hash2;
+ gnutls_privkey_sign_data2;
local:
*;
};
diff --git a/lib/privkey.c b/lib/privkey.c
index d114160011..1c61bfe317 100644
--- a/lib/privkey.c
+++ b/lib/privkey.c
@@ -2,6 +2,7 @@
* GnuTLS PKCS#11 support
* Copyright (C) 2010-2014 Free Software Foundation, Inc.
* Copyright (C) 2012-2015 Nikos Mavrogiannopoulos
+ * Copyright (C) 2016-2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -42,7 +43,7 @@ static int
privkey_sign_hash(gnutls_privkey_t signer,
const gnutls_datum_t * hash_data,
gnutls_datum_t * signature,
- gnutls_x509_spki_st * params);
+ gnutls_x509_spki_st * params, unsigned flags);
static int
_gnutls_privkey_sign_raw_data(gnutls_privkey_t key,
@@ -1227,6 +1228,117 @@ gnutls_privkey_sign_data(gnutls_privkey_t signer,
return privkey_sign_data(signer, data, signature, &params);
}
+/**
+ * gnutls_privkey_sign_data2:
+ * @signer: Holds the key
+ * @algo: The signature algorithm used
+ * @flags: Zero or one of %gnutls_privkey_flags_t
+ * @data: holds the data to be signed
+ * @signature: will contain the signature allocated with gnutls_malloc()
+ *
+ * This function will sign the given data using the specified signature
+ * algorithm. This function is an enhancement of gnutls_privkey_sign_data(),
+ * as it allows utilizing a alternative signature algorithm where possible
+ * (e.g, use an RSA key with RSA-PSS).
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.6.0
+ **/
+int
+gnutls_privkey_sign_data2(gnutls_privkey_t signer,
+ gnutls_sign_algorithm_t algo,
+ unsigned int flags,
+ const gnutls_datum_t * data,
+ gnutls_datum_t * signature)
+{
+ int ret;
+ gnutls_x509_spki_st params;
+ const gnutls_sign_entry_st *e;
+
+ if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ e = _gnutls_sign_to_entry(algo);
+ if (e == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret = _gnutls_privkey_get_sign_params(signer, &params);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = _gnutls_privkey_update_sign_params(signer, e->pk, e->hash,
+ flags, &params);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return privkey_sign_data(signer, data, signature, &params);
+}
+
+/**
+ * gnutls_privkey_sign_hash2:
+ * @signer: Holds the signer's key
+ * @algo: The signature algorithm used
+ * @flags: Zero or one of %gnutls_privkey_flags_t
+ * @hash_data: holds the data to be signed
+ * @signature: will contain newly allocated signature
+ *
+ * This function will sign the given hashed data using a signature algorithm
+ * supported by the private key. Signature algorithms are always used
+ * together with a hash functions. Different hash functions may be
+ * used for the RSA algorithm, but only SHA-XXX for the DSA keys.
+ *
+ * You may use gnutls_pubkey_get_preferred_hash_algorithm() to determine
+ * the hash algorithm.
+ *
+ * The flags may be %GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA or %GNUTLS_PRIVKEY_SIGN_FLAG_RSA_PSS.
+ * In the former case this function will ignore @hash_algo and perform a raw PKCS1 signature,
+ * and in the latter an RSA-PSS signature will be generated.
+ *
+ * Note that, not all algorithm support signing already signed data. When
+ * signing with Ed25519, gnutls_privkey_sign_data() should be used.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.6.0
+ **/
+int
+gnutls_privkey_sign_hash2(gnutls_privkey_t signer,
+ gnutls_sign_algorithm_t algo,
+ unsigned int flags,
+ const gnutls_datum_t * hash_data,
+ gnutls_datum_t * signature)
+{
+ int ret;
+ gnutls_x509_spki_st params;
+ const gnutls_sign_entry_st *e;
+
+ e = _gnutls_sign_to_entry(algo);
+ if (e == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ ret = _gnutls_privkey_get_sign_params(signer, &params);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = _gnutls_privkey_update_sign_params(signer, e->pk, e->hash,
+ flags, &params);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return privkey_sign_hash(signer, hash_data, signature, &params, flags);
+}
+
int
privkey_sign_data(gnutls_privkey_t signer,
const gnutls_datum_t * data,
@@ -1267,6 +1379,7 @@ privkey_sign_data(gnutls_privkey_t signer,
return ret;
}
+
/**
* gnutls_privkey_sign_hash:
* @signer: Holds the signer's key
@@ -1314,23 +1427,24 @@ gnutls_privkey_sign_hash(gnutls_privkey_t signer,
return ret;
}
- if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA)
- return _gnutls_privkey_sign_raw_data(signer,
- hash_data, signature,
- &params);
-
- return privkey_sign_hash(signer, hash_data, signature, &params);
+ return privkey_sign_hash(signer, hash_data, signature, &params, flags);
}
static int
privkey_sign_hash(gnutls_privkey_t signer,
const gnutls_datum_t * hash_data,
gnutls_datum_t * signature,
- gnutls_x509_spki_st * params)
+ gnutls_x509_spki_st * params,
+ unsigned flags)
{
int ret;
gnutls_datum_t digest;
+ if (flags & GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA)
+ return _gnutls_privkey_sign_raw_data(signer,
+ hash_data, signature,
+ params);
+
digest.data = gnutls_malloc(hash_data->size);
if (digest.data == NULL) {
gnutls_assert();