Commit 4804febd authored by Simo Sorce's avatar Simo Sorce
Browse files

Constant time/cache PKCS#1 RSA decryption



This patch tries to make the code have the same time and memory access
aptterns across all branches of the decryption function so that timining
or cache side channels are minimized or neutralized.

To do so it uses a new nettle rsa decryption function that is
side-channel silent.
Signed-off-by: Simo Sorce's avatarSimo Sorce <simo@redhat.com>
parent ed3bddda
Pipeline #38563590 passed with stage
in 113 minutes and 3 seconds
......@@ -41,6 +41,15 @@ See the end for copying conditions.
** certtool: Add parameter --no-text that prevents certtool from outputting
text before PEM-encoded private key, public key, certificate, CRL or CSR.
** libgnutls: Change RSA decryption to use a new side-channel silent function.
This addresses a security issue where memory access patterns as well as timing
on the underlying Nettle rsa-decrypt function could lead to new Bleichenbacher
attacks. Side-channel resistant code is slower due to the need to mask
access and timings. When used in TLS the new functions cause RSA based
handshakes to be between 13% and 28% slower on average (Numbers are indicative,
the tests where performed on a relatively modern Intel CPU, results vary
depending on the CPU and architecture used).
** API and ABI modifications:
GNUTLS_AUTO_REAUTH: Added
GNUTLS_CIPHER_AES_128_CFB8: Added
......@@ -57,6 +66,7 @@ gnutls_anti_replay_init: Added
gnutls_anti_replay_deinit: Added
gnutls_anti_replay_set_window: Added
gnutls_anti_replay_enable: Added
gnutls_privkey_decrypt_data2: Added
* Version 3.6.4 (released 2018-09-24)
......
......@@ -553,6 +553,15 @@ if test "$enable_non_suiteb" = "yes";then
fi
AM_CONDITIONAL(ENABLE_NON_SUITEB_CURVES, test "$enable_non_suiteb" = "yes")
# We MUST require a Nettle version that has rsa_sec_decrypt now.
save_LIBS=$LIBS
LIBS="$LIBS $HOGWEED_LIBS"
AC_CHECK_FUNCS(nettle_rsa_sec_decrypt,
[],
[AC_MSG_ERROR([Nettle lacks the required rsa_sec_decrypt function])]
)
LIBS=$save_LIBS
# Check if nettle has CFB8 support
save_LIBS=$LIBS
LIBS="$LIBS $NETTLE_LIBS"
......
......@@ -1579,6 +1579,8 @@ FUNCS += functions/gnutls_priority_string_list
FUNCS += functions/gnutls_priority_string_list.short
FUNCS += functions/gnutls_privkey_decrypt_data
FUNCS += functions/gnutls_privkey_decrypt_data.short
FUNCS += functions/gnutls_privkey_decrypt_data2
FUNCS += functions/gnutls_privkey_decrypt_data2.short
FUNCS += functions/gnutls_privkey_deinit
FUNCS += functions/gnutls_privkey_deinit.short
FUNCS += functions/gnutls_privkey_export_dsa_raw
......
......@@ -591,6 +591,7 @@ APIMANS += gnutls_priority_set_direct.3
APIMANS += gnutls_priority_sign_list.3
APIMANS += gnutls_priority_string_list.3
APIMANS += gnutls_privkey_decrypt_data.3
APIMANS += gnutls_privkey_decrypt_data2.3
APIMANS += gnutls_privkey_deinit.3
APIMANS += gnutls_privkey_export_dsa_raw.3
APIMANS += gnutls_privkey_export_dsa_raw2.3
......
......@@ -39,6 +39,7 @@ struct gnutls_privkey_st {
gnutls_privkey_sign_data_func sign_data_func;
gnutls_privkey_sign_hash_func sign_hash_func;
gnutls_privkey_decrypt_func decrypt_func;
gnutls_privkey_decrypt_func2 decrypt_func2;
gnutls_privkey_deinit_func deinit_func;
gnutls_privkey_info_func info_func;
void *userdata;
......
......@@ -155,12 +155,13 @@ static int
proc_rsa_client_kx(gnutls_session_t session, uint8_t * data,
size_t _data_size)
{
gnutls_datum_t plaintext = {NULL, 0};
const char attack_error[] = "auth_rsa: Possible PKCS #1 attack\n";
gnutls_datum_t ciphertext;
int ret, dsize;
int use_rnd_key = 0;
ssize_t data_size = _data_size;
gnutls_datum_t rndkey = {NULL, 0};
volatile uint8_t ver_maj, ver_min;
volatile uint8_t check_ver_min;
volatile uint32_t ok;
#ifdef ENABLE_SSL3
if (get_num_version(session) == GNUTLS_SSL3) {
......@@ -184,75 +185,73 @@ proc_rsa_client_kx(gnutls_session_t session, uint8_t * data,
ciphertext.size = dsize;
}
rndkey.size = GNUTLS_MASTER_SIZE;
rndkey.data = gnutls_malloc(rndkey.size);
if (rndkey.data == NULL) {
ver_maj = _gnutls_get_adv_version_major(session);
ver_min = _gnutls_get_adv_version_minor(session);
check_ver_min = (session->internals.allow_wrong_pms == 0);
session->key.key.data = gnutls_malloc(GNUTLS_MASTER_SIZE);
if (session->key.key.data == NULL) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
session->key.key.size = GNUTLS_MASTER_SIZE;
/* we do not need strong random numbers here.
*/
ret = gnutls_rnd(GNUTLS_RND_NONCE, rndkey.data,
rndkey.size);
/* Fallback value when decryption fails. Needs to be unpredictable. */
ret = gnutls_rnd(GNUTLS_RND_NONCE, session->key.key.data,
GNUTLS_MASTER_SIZE);
if (ret < 0) {
gnutls_free(session->key.key.data);
session->key.key.data = NULL;
session->key.key.size = 0;
gnutls_assert();
goto cleanup;
return ret;
}
ret =
gnutls_privkey_decrypt_data(session->internals.selected_key, 0,
&ciphertext, &plaintext);
if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE) {
/* In case decryption fails then don't inform
* the peer. Just use a random key. (in order to avoid
* attack against pkcs-1 formating).
*/
_gnutls_debug_log("auth_rsa: Possible PKCS #1 format attack\n");
if (ret >= 0) {
gnutls_free(plaintext.data);
plaintext.data = NULL;
}
use_rnd_key = 1;
} else {
/* If the secret was properly formatted, then
* check the version number.
*/
if (_gnutls_get_adv_version_major(session) !=
plaintext.data[0]
|| (session->internals.allow_wrong_pms == 0
&& _gnutls_get_adv_version_minor(session) !=
plaintext.data[1])) {
/* No error is returned here, if the version number check
* fails. We proceed normally.
* That is to defend against the attack described in the paper
* "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima,
* Ondej Pokorny and Tomas Rosa.
*/
_gnutls_debug_log("auth_rsa: Possible PKCS #1 version check format attack\n");
}
}
gnutls_privkey_decrypt_data2(session->internals.selected_key,
0, &ciphertext, session->key.key.data,
session->key.key.size);
/* After this point, any conditional on failure that cause differences
* in execution may create a timing or cache access pattern side
* channel that can be used as an oracle, so tread very carefully */
/* Error handling logic:
* In case decryption fails then don't inform the peer. Just use the
* random key previously generated. (in order to avoid attack against
* pkcs-1 formating).
*
* If we get version mismatches no error is returned either. We
* proceed normally. This is to defend against the attack described
* in the paper "Attacking RSA-based sessions in SSL/TLS" by
* Vlastimil Klima, Ondej Pokorny and Tomas Rosa.
*/
if (use_rnd_key != 0) {
session->key.key.data = rndkey.data;
session->key.key.size = rndkey.size;
rndkey.data = NULL;
/* ok is 0 in case of error and 1 in case of success. */
/* if ret < 0 */
ok = CONSTCHECK_EQUAL(ret, 0);
/* session->key.key.data[0] must equal ver_maj */
ok &= CONSTCHECK_EQUAL(session->key.key.data[0], ver_maj);
/* if check_ver_min then session->key.key.data[1] must equal ver_min */
ok &= CONSTCHECK_NOT_EQUAL(check_ver_min, 0) &
CONSTCHECK_EQUAL(session->key.key.data[1], ver_min);
if (ok) {
/* call logging function unconditionally so all branches are
* indistinguishable for timing and cache access when debug
* logging is disabled */
_gnutls_no_log("%s", attack_error);
} else {
session->key.key.data = plaintext.data;
session->key.key.size = plaintext.size;
_gnutls_debug_log("%s", attack_error);
}
/* This is here to avoid the version check attack
* discussed above.
*/
session->key.key.data[0] = _gnutls_get_adv_version_major(session);
session->key.key.data[1] = _gnutls_get_adv_version_minor(session);
session->key.key.data[0] = ver_maj;
session->key.key.data[1] = ver_min;
ret = 0;
cleanup:
gnutls_free(rndkey.data);
return ret;
return 0;
}
......
......@@ -344,10 +344,15 @@ typedef struct gnutls_crypto_pk {
int (*encrypt) (gnutls_pk_algorithm_t, gnutls_datum_t * ciphertext,
const gnutls_datum_t * plaintext,
const gnutls_pk_params_st * pub);
int (*decrypt) (gnutls_pk_algorithm_t, gnutls_datum_t * plaintext,
int (*decrypt) (gnutls_pk_algorithm_t,
gnutls_datum_t * plaintext,
const gnutls_datum_t * ciphertext,
const gnutls_pk_params_st * priv);
int (*decrypt2) (gnutls_pk_algorithm_t,
const gnutls_datum_t * ciphertext,
unsigned char * plaintext,
size_t paintext_size,
const gnutls_pk_params_st * priv);
int (*sign) (gnutls_pk_algorithm_t, gnutls_datum_t * signature,
const gnutls_datum_t * data,
const gnutls_pk_params_st *priv,
......
......@@ -116,6 +116,7 @@ static int test_rsa_enc(gnutls_pk_algorithm_t pk,
gnutls_datum_t raw_rsa_key = { (void*)rsa_key2048, sizeof(rsa_key2048)-1 };
gnutls_privkey_t key;
gnutls_pubkey_t pub = NULL;
unsigned char plaintext2[sizeof(DATASTR) - 1];
ret = gnutls_privkey_init(&key);
if (ret < 0)
......@@ -165,6 +166,18 @@ static int test_rsa_enc(gnutls_pk_algorithm_t pk,
goto cleanup;
}
ret = gnutls_privkey_decrypt_data2(key, 0, &enc, plaintext2,
signed_data.size);
if (ret < 0) {
gnutls_assert();
goto cleanup;
}
if (memcmp(plaintext2, signed_data.data, signed_data.size) != 0) {
ret = GNUTLS_E_SELF_TEST_ERROR;
gnutls_assert();
goto cleanup;
}
ret = 0;
cleanup:
if (pub != NULL)
......
......@@ -108,6 +108,7 @@ void _gnutls_mpi_log(const char *prefix, bigint_t a);
#define _gnutls_write_log(...) LEVEL(11, __VA_ARGS__)
#define _gnutls_io_log(...) LEVEL(12, __VA_ARGS__)
#define _gnutls_buffers_log(...) LEVEL(13, __VA_ARGS__)
#define _gnutls_no_log(...) LEVEL(INT_MAX, __VA_ARGS__)
#else
#define _gnutls_debug_log _gnutls_null_log
#define _gnutls_assert_log _gnutls_null_log
......@@ -119,6 +120,7 @@ void _gnutls_mpi_log(const char *prefix, bigint_t a);
#define _gnutls_dtls_log _gnutls_null_log
#define _gnutls_read_log _gnutls_null_log
#define _gnutls_write_log _gnutls_null_log
#define _gnutls_no_log _gnutle_null_log
void _gnutls_null_log(void *, ...);
......
......@@ -1564,4 +1564,8 @@ inline static bool _gnutls_has_negotiate_ctypes(gnutls_session_t session)
return session->internals.flags & GNUTLS_ENABLE_CERT_TYPE_NEG;
}
/* Macros to aide constant time/mem checks */
#define CONSTCHECK_NOT_EQUAL(a, b) ((-((uint32_t)(a) ^ (uint32_t)(b))) >> 31)
#define CONSTCHECK_EQUAL(a, b) (1U - CONSTCHECK_NOT_EQUAL(a, b))
#endif /* GNUTLS_INT_H */
......@@ -75,6 +75,12 @@ typedef int (*gnutls_privkey_decrypt_func) (gnutls_privkey_t key,
const gnutls_datum_t *ciphertext,
gnutls_datum_t * plaintext);
typedef int (*gnutls_privkey_decrypt_func2) (gnutls_privkey_t key,
void *userdata,
const gnutls_datum_t *ciphertext,
unsigned char * plaintext,
size_t plaintext_size);
/* to be called to sign pre-hashed data. The input will be
* the output of the hash (such as SHA256) corresponding to
* the signature algorithm. The algorithm GNUTLS_SIGN_RSA_RAW
......@@ -542,12 +548,17 @@ int gnutls_privkey_sign_hash2(gnutls_privkey_t signer,
const gnutls_datum_t * hash_data,
gnutls_datum_t * signature);
int gnutls_privkey_decrypt_data(gnutls_privkey_t key,
unsigned int flags,
const gnutls_datum_t * ciphertext,
gnutls_datum_t * plaintext);
int gnutls_privkey_decrypt_data2(gnutls_privkey_t key,
unsigned int flags,
const gnutls_datum_t * ciphertext,
unsigned char * plaintext,
size_t plaintext_size);
int
gnutls_privkey_export_rsa_raw(gnutls_privkey_t key,
gnutls_datum_t * m, gnutls_datum_t * e,
......
......@@ -1261,6 +1261,7 @@ GNUTLS_3_6_5
gnutls_anti_replay_deinit;
gnutls_anti_replay_set_window;
gnutls_anti_replay_enable;
gnutls_privkey_decrypt_data2;
} GNUTLS_3_6_4;
GNUTLS_FIPS140_3_4 {
......
......@@ -529,6 +529,57 @@ _wrap_nettle_pk_decrypt(gnutls_pk_algorithm_t algo,
return ret;
}
/* Note: we do not allocate in this function to avoid asymettric
* unallocation (which creates a side channel) in case of failure
* */
static int
_wrap_nettle_pk_decrypt2(gnutls_pk_algorithm_t algo,
const gnutls_datum_t * ciphertext,
unsigned char * plaintext,
size_t plaintext_size,
const gnutls_pk_params_st * pk_params)
{
struct rsa_private_key priv;
struct rsa_public_key pub;
bigint_t c;
uint32_t is_err;
int ret;
if (algo != GNUTLS_PK_RSA || plaintext == NULL) {
gnutls_assert();
return GNUTLS_E_INTERNAL_ERROR;
}
_rsa_params_to_privkey(pk_params, &priv);
ret = _rsa_params_to_pubkey(pk_params, &pub);
if (ret < 0)
return gnutls_assert_val(ret);
if (ciphertext->size != pub.size)
return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
if (_gnutls_mpi_init_scan_nz(&c, ciphertext->data,
ciphertext->size) != 0) {
return gnutls_assert_val (GNUTLS_E_MPI_SCAN_FAILED);
}
ret = rsa_sec_decrypt(&pub, &priv, NULL, rnd_nonce_func,
plaintext_size, plaintext, TOMPZ(c));
/* after this point, any conditional on failure that cause differences
* in execution may create a timing or cache access pattern side
* channel that can be used as an oracle, so thread very carefully */
_gnutls_mpi_release(&c);
/* Here HAVE_LIB_ERROR() should be fine as it doesn't have
* branches in it and returns a bool */
is_err = HAVE_LIB_ERROR();
/* if is_err != 0 */
is_err = CONSTCHECK_NOT_EQUAL(is_err, 0);
/* or ret == 0 */
is_err |= CONSTCHECK_EQUAL(ret, 0);
/* then return GNUTLS_E_DECRYPTION_FAILED */
return (int)((is_err * UINT_MAX) & GNUTLS_E_DECRYPTION_FAILED);
}
#define CHECK_INVALID_RSA_PSS_PARAMS(dig_size, salt_size, pub_size, err) \
if (unlikely(dig_size + salt_size + 2 > pub_size)) \
return gnutls_assert_val(err)
......@@ -2780,6 +2831,7 @@ int crypto_pk_prio = INT_MAX;
gnutls_crypto_pk_st _gnutls_pk_ops = {
.encrypt = _wrap_nettle_pk_encrypt,
.decrypt = _wrap_nettle_pk_decrypt,
.decrypt2 = _wrap_nettle_pk_decrypt2,
.sign = _wrap_nettle_pk_sign,
.verify = _wrap_nettle_pk_verify,
.verify_priv_params = wrap_nettle_pk_verify_priv_params,
......
......@@ -28,6 +28,7 @@ extern gnutls_crypto_pk_st _gnutls_pk_ops;
#define _gnutls_pk_encrypt( algo, ciphertext, plaintext, params) _gnutls_pk_ops.encrypt( algo, ciphertext, plaintext, params)
#define _gnutls_pk_decrypt( algo, ciphertext, plaintext, params) _gnutls_pk_ops.decrypt( algo, ciphertext, plaintext, params)
#define _gnutls_pk_decrypt2( algo, ciphertext, plaintext, size, params) _gnutls_pk_ops.decrypt2( algo, ciphertext, plaintext, size, params)
#define _gnutls_pk_sign( algo, sig, data, params, sign_params) _gnutls_pk_ops.sign( algo, sig, data, params, sign_params)
#define _gnutls_pk_verify( algo, data, sig, params, sign_params) _gnutls_pk_ops.verify( algo, data, sig, params, sign_params)
#define _gnutls_pk_verify_priv_params( algo, params) _gnutls_pk_ops.verify_priv_params( algo, params)
......
......@@ -218,6 +218,13 @@ _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
const gnutls_datum_t * ciphertext,
gnutls_datum_t * plaintext);
int
_gnutls_pkcs11_privkey_decrypt_data2(gnutls_pkcs11_privkey_t key,
unsigned int flags,
const gnutls_datum_t * ciphertext,
unsigned char * plaintext,
size_t plaintext_size);
int
_pkcs11_privkey_get_pubkey (gnutls_pkcs11_privkey_t pkey, gnutls_pubkey_t *pub, unsigned flags);
......
......@@ -715,6 +715,121 @@ _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
return ret;
}
/*-
* _gnutls_pkcs11_privkey_decrypt_data2:
* @key: Holds the key
* @flags: should be 0 for now
* @ciphertext: holds the data to be signed
* @plaintext: a preallocated buffer that will be filled with the plaintext
* @plaintext_size: size of the plaintext
*
* This function will decrypt the given data using the public key algorithm
* supported by the private key.
* Unlike with _gnutls_pkcs11_privkey_decrypt_data the plaintext size is known
* and provided by the caller, if the plaintext size differs from the requested
* one, the operation fails and the provided buffer is left unchanged.
* NOTE: plaintext_size must be exactly the size of the payload in the
* ciphertext, otherwise an error is returned and the plaintext buffer is left
* unchanged.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
-*/
int
_gnutls_pkcs11_privkey_decrypt_data2(gnutls_pkcs11_privkey_t key,
unsigned int flags,
const gnutls_datum_t * ciphertext,
unsigned char * plaintext,
size_t plaintext_size)
{
ck_rv_t rv;
int ret;
struct ck_mechanism mech;
unsigned long siglen = ciphertext->size;
unsigned req_login = 0;
unsigned login_flags = SESSION_LOGIN|SESSION_CONTEXT_SPECIFIC;
unsigned char *buffer;
volatile unsigned char value;
unsigned char mask;
PKCS11_CHECK_INIT_PRIVKEY(key);
if (key->pk_algorithm != GNUTLS_PK_RSA)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
mech.mechanism = CKM_RSA_PKCS;
mech.parameter = NULL;
mech.parameter_len = 0;
ret = gnutls_mutex_lock(&key->mutex);
if (ret != 0)
return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);
buffer = gnutls_malloc(siglen);
if (!buffer) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
/* Initialize signing operation; using the private key discovered
* earlier. */
REPEAT_ON_INVALID_HANDLE(
rv = pkcs11_decrypt_init(key->sinfo.module, key->sinfo.pks,
&mech, key->ref)
);
if (rv != CKR_OK) {
gnutls_assert();
ret = pkcs11_rv_to_err(rv);
goto cleanup;
}
retry_login:
if (key->reauth || req_login) {
if (req_login)
login_flags = SESSION_FORCE_LOGIN|SESSION_LOGIN;
ret =
pkcs11_login(&key->sinfo, &key->pin,
key->uinfo, login_flags);
if (ret < 0) {
gnutls_assert();
_gnutls_debug_log("PKCS #11 login failed, trying operation anyway\n");
/* let's try the operation anyway */
}
}
ret = 0;
siglen = ciphertext->size;
rv = pkcs11_decrypt(key->sinfo.module, key->sinfo.pks,
ciphertext->data, ciphertext->size,
buffer, &siglen);
if (unlikely(rv == CKR_USER_NOT_LOGGED_IN && req_login == 0)) {
req_login = 1;
goto retry_login;
}
/* NOTE: These branches are not side-channel silent */
if (rv != CKR_OK) {
gnutls_assert();
ret = pkcs11_rv_to_err(rv);
} else if (siglen != plaintext_size) {
gnutls_assert();
ret = GNUTLS_E_INVALID_REQUEST;
}
/* conditionally copy buffer in a side-channel silent way */
/* on success mask is 0xFF, on failure it is 0 */
mask = ((uint32_t)ret >> 31) - 1U;
for (size_t i = 0; i < plaintext_size; i++) {
value = (buffer[i] & mask) + (plaintext[i] & ~mask);
plaintext[i] = value;
}
cleanup:
gnutls_mutex_unlock(&key->mutex);
gnutls_free(buffer);
return ret;
}
/**
* gnutls_pkcs11_privkey_export_url:
* @key: Holds the PKCS 11 key
......
......@@ -1554,6 +1554,82 @@ gnutls_privkey_decrypt_data(gnutls_privkey_t key,
}
}
/**
* gnutls_privkey_decrypt_data2:
* @key: Holds the key
* @flags: zero for now
* @ciphertext: holds the data to be decrypted
* @plaintext: a preallocated buffer that will be filled with the plaintext
* @plaintext_size: in/out size of the plaintext
*
* This function will decrypt the given data using the algorithm
* supported by the private key. Unlike with gnutls_privkey_decrypt_data()
* this function operates in constant time and constant memory access.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
*
* Since: 3.6.5
**/
int
gnutls_privkey_decrypt_data2(gnutls_privkey_t key,
unsigned int flags,
const gnutls_datum_t * ciphertext,
unsigned char * plaintext,
size_t plaintext_size)
{
/* Note: except for the backwards compatibility function, no
* conditional code should be called after the decryption
* function call, to avoid creating oracle attacks based
* on cache/timing side channels */
/* backwards compatibility */
if (key->type == GNUTLS_PRIVKEY_EXT &&
key->key.ext.decrypt_func2 == NULL &&
key->key.ext.decrypt_func != NULL) {
gnutls_datum_t plain;
int ret;
ret = key->key.ext.decrypt_func(key,
key->key.ext.userdata,
ciphertext,
&plain);
if (plain.size != plaintext_size) {
ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
} else {
memcpy(plaintext, plain.data, plain.size);
}
gnutls_free(plain.data);
return ret;
}
switch (key->type) {
case GNUTLS_PRIVKEY_X509:
return _gnutls_pk_decrypt2(key->pk_algorithm, ciphertext,
plaintext, plaintext_size,
&key->key.x509->params);
#ifdef ENABLE_PKCS11
case GNUTLS_PRIVKEY_PKCS11:
return _gnutls_pkcs11_privkey_decrypt_data2(key->key.pkcs11,
flags,
ciphertext,
plaintext,
plaintext_size);
#endif
case GNUTLS_PRIVKEY_EXT:
if (key->key.ext.decrypt_func2 == NULL)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);