summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2014-11-13 12:06:32 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2014-11-13 12:11:05 +0100
commit88289f4402d1f3b2063c007fb7029996bd97b987 (patch)
tree0994bbbf876e8cb210c876e450871a2b08313041
parent305103b65f5b476daa0e84539128550de552281d (diff)
downloadgnutls-88289f4402d1f3b2063c007fb7029996bd97b987.tar.gz
added the notion of preferred sign algorithm in a private key
This can be set for keys imported with gnutls_privkey_import_ext3() with the info callback. It is only considered for client side keys in TLS sessions.
-rw-r--r--lib/abstract_int.h6
-rw-r--r--lib/gnutls_privkey.c39
-rw-r--r--lib/gnutls_sig.c13
-rw-r--r--lib/includes/gnutls/abstract.h11
4 files changed, 54 insertions, 15 deletions
diff --git a/lib/abstract_int.h b/lib/abstract_int.h
index fc78f1cad9..273585a778 100644
--- a/lib/abstract_int.h
+++ b/lib/abstract_int.h
@@ -41,12 +41,13 @@ struct gnutls_privkey_st {
gnutls_privkey_sign_func sign_func;
gnutls_privkey_decrypt_func decrypt_func;
gnutls_privkey_deinit_func deinit_func;
- gnutls_privkey_pk_func pk_func;
+ gnutls_privkey_info_func info_func;
void *userdata;
} ext;
} key;
unsigned int flags;
+ gnutls_sign_algorithm_t preferred_sign_algo;
struct pin_info_st pin;
};
@@ -111,4 +112,7 @@ const mac_entry_st *_gnutls_dsa_q_to_hash(gnutls_pk_algorithm_t algo,
int
_gnutls_privkey_get_mpis(gnutls_privkey_t key, gnutls_pk_params_st * params);
+gnutls_sign_algorithm_t
+_gnutls_privkey_get_preferred_sign_algo(gnutls_privkey_t key);
+
#endif
diff --git a/lib/gnutls_privkey.c b/lib/gnutls_privkey.c
index 054ac629d4..ab419ae544 100644
--- a/lib/gnutls_privkey.c
+++ b/lib/gnutls_privkey.c
@@ -89,8 +89,8 @@ int gnutls_privkey_get_pk_algorithm(gnutls_privkey_t key, unsigned int *bits)
case GNUTLS_PRIVKEY_EXT:
if (bits)
*bits = 0;
- if (key->key.ext.pk_func)
- return key->key.ext.pk_func(key, key->key.ext.userdata);
+ if (key->key.ext.info_func)
+ return key->key.ext.info_func(key, GNUTLS_PRIVKEY_INFO_PK_ALGO, key->key.ext.userdata);
else
return key->pk_algorithm;
default:
@@ -558,12 +558,11 @@ gnutls_privkey_import_ext2(gnutls_privkey_t pkey,
/**
* gnutls_privkey_import_ext3:
* @pkey: The private key
- * @pk: The public key algorithm, when @pk_func isn't provided
* @userdata: private data to be provided to the callbacks
* @sign_fn: callback for signature operations
* @decrypt_fn: callback for decryption operations
* @deinit_fn: a deinitialization function
- * @pk_fn: returns the public key algorithm (may be %NULL; if set @pk will be ignored)
+ * @info_fn: returns info about the public key algorithm (should not be %NULL)
* @flags: Flags for the import
*
* This function will associate the given callbacks with the
@@ -576,6 +575,9 @@ gnutls_privkey_import_ext2(gnutls_privkey_t pkey,
* will be provided, and the signing function is expected to do the PKCS #1
* 1.5 padding and the exponentiation.
*
+ * The @info_fn must provide information on %GNUTLS_PRIVKEY_INFO_PK_ALGO and
+ * %GNUTLS_PRIVKEY_INFO_PK_ALGO, and should return -1 on unknown flags.
+ *
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
*
@@ -588,7 +590,7 @@ gnutls_privkey_import_ext3(gnutls_privkey_t pkey,
gnutls_privkey_sign_func sign_fn,
gnutls_privkey_decrypt_func decrypt_fn,
gnutls_privkey_deinit_func deinit_fn,
- gnutls_privkey_pk_func pk_fn,
+ gnutls_privkey_info_func info_fn,
unsigned int flags)
{
int ret;
@@ -602,13 +604,15 @@ gnutls_privkey_import_ext3(gnutls_privkey_t pkey,
if (sign_fn == NULL && decrypt_fn == NULL)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ if (info_fn == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
pkey->key.ext.sign_func = sign_fn;
pkey->key.ext.decrypt_func = decrypt_fn;
pkey->key.ext.deinit_func = deinit_fn;
- pkey->key.ext.pk_func = pk_fn;
+ pkey->key.ext.info_func = info_fn;
pkey->key.ext.userdata = userdata;
pkey->type = GNUTLS_PRIVKEY_EXT;
- pkey->pk_algorithm = pk;
pkey->flags = flags;
/* Ensure gnutls_privkey_deinit() calls the deinit_func */
@@ -1337,3 +1341,24 @@ int gnutls_privkey_verify_params(gnutls_privkey_t key)
return 0;
}
+/*-
+ * _gnutls_privkey_get_preferred_sign_algo:
+ * @key: should contain a #gnutls_privkey_t structure
+ *
+ * This function returns the preferred signature algorithm for this
+ * private key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.4.0
+ -*/
+gnutls_sign_algorithm_t
+_gnutls_privkey_get_preferred_sign_algo(gnutls_privkey_t key)
+{
+ if (key->type == GNUTLS_PRIVKEY_EXT) {
+ if (key->key.ext.info_func)
+ return key->key.ext.info_func(key, GNUTLS_PRIVKEY_INFO_SIGN_ALGO, key->key.ext.userdata);
+ }
+ return key->preferred_sign_algo;
+}
diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c
index 5c5f4f3b30..97f463d33d 100644
--- a/lib/gnutls_sig.c
+++ b/lib/gnutls_sig.c
@@ -570,10 +570,15 @@ _gnutls_handshake_sign_crt_vrfy12(gnutls_session_t session,
gnutls_sign_algorithm_t sign_algo;
const mac_entry_st *me;
- sign_algo = _gnutls_session_get_sign_algo(session, cert);
- if (sign_algo == GNUTLS_SIGN_UNKNOWN) {
- gnutls_assert();
- return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
+ sign_algo = _gnutls_privkey_get_preferred_sign_algo(pkey);
+ if (sign_algo == GNUTLS_SIGN_UNKNOWN ||
+ _gnutls_session_sign_algo_enabled(session, sign_algo) < 0) {
+
+ sign_algo = _gnutls_session_get_sign_algo(session, cert);
+ if (sign_algo == GNUTLS_SIGN_UNKNOWN) {
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
+ }
}
gnutls_sign_algorithm_set_client(session, sign_algo);
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
index d3a33e3362..0c5353e124 100644
--- a/lib/includes/gnutls/abstract.h
+++ b/lib/includes/gnutls/abstract.h
@@ -68,8 +68,13 @@ typedef int (*gnutls_privkey_decrypt_func) (gnutls_privkey_t key,
typedef void (*gnutls_privkey_deinit_func) (gnutls_privkey_t key,
void *userdata);
-/* returns the public key algorithm associated with userdata */
-typedef gnutls_pk_algorithm_t (*gnutls_privkey_pk_func) (gnutls_privkey_t key, void *userdata);
+/* Should return the public key algorithm (gnutls_pk_algorithm_t) */
+#define GNUTLS_PRIVKEY_INFO_PK_ALGO 1
+
+/* Should return the preferred signature algorithm (gnutls_sign_algorithm_t) or 0. */
+#define GNUTLS_PRIVKEY_INFO_SIGN_ALGO (1<<1)
+/* returns information on the public key associated with userdata */
+typedef int (*gnutls_privkey_info_func) (gnutls_privkey_t key, unsigned int flags, void *userdata);
int gnutls_pubkey_init(gnutls_pubkey_t * key);
void gnutls_pubkey_deinit(gnutls_pubkey_t key);
@@ -354,7 +359,7 @@ gnutls_privkey_import_ext3(gnutls_privkey_t pkey,
gnutls_privkey_sign_func sign_func,
gnutls_privkey_decrypt_func decrypt_func,
gnutls_privkey_deinit_func deinit_func,
- gnutls_privkey_pk_func pk_func,
+ gnutls_privkey_info_func info_func,
unsigned int flags);
int gnutls_privkey_import_dsa_raw(gnutls_privkey_t key,