summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/crypto-backend.h17
-rw-r--r--lib/gnutls_errors.c2
-rw-r--r--lib/gnutls_pk.c35
-rw-r--r--lib/gnutls_pk.h3
-rw-r--r--lib/includes/gnutls/gnutls.h.in1
-rw-r--r--lib/includes/gnutls/x509.h1
-rw-r--r--lib/libgnutls.map1
-rw-r--r--lib/nettle/pk.c203
-rw-r--r--lib/x509/privkey.c28
-rw-r--r--src/certtool.c9
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/keygen.c102
12 files changed, 355 insertions, 49 deletions
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index 389e025c67..ed89deb39d 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -255,6 +255,21 @@
#define ECC_Y 7
#define ECC_K 8
+#define DSA_P 0
+#define DSA_Q 1
+#define DSA_G 2
+#define DSA_Y 3
+#define DSA_X 4
+
+#define RSA_MODULUS 0
+#define RSA_PUB 1
+#define RSA_PRIV 2
+#define RSA_PRIME1 3
+#define RSA_PRIME2 4
+#define RSA_COEF 5
+#define RSA_E1 6
+#define RSA_E2 7
+
/**
* gnutls_direction_t:
* @GNUTLS_IMPORT: Import direction.
@@ -286,6 +301,8 @@
int (*verify) (gnutls_pk_algorithm_t, const gnutls_datum_t * data,
const gnutls_datum_t * signature,
const gnutls_pk_params_st * pub);
+ int (*verify_params) (gnutls_pk_algorithm_t,
+ const gnutls_pk_params_st * pub);
int (*generate) (gnutls_pk_algorithm_t, unsigned int nbits,
gnutls_pk_params_st *);
/* this function should convert params to ones suitable
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
index 0084a88da8..b978d1d247 100644
--- a/lib/gnutls_errors.c
+++ b/lib/gnutls_errors.c
@@ -176,6 +176,8 @@ static const gnutls_error_entry error_algorithms[] = {
ERROR_ENTRY (N_("The cookie was bad."), GNUTLS_E_BAD_COOKIE, 1),
ERROR_ENTRY (N_("An illegal parameter has been received."),
GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 1),
+ ERROR_ENTRY (N_("An illegal parameter was found."),
+ GNUTLS_E_ILLEGAL_PARAMETER, 1),
ERROR_ENTRY (N_("Error while reading file."), GNUTLS_E_FILE_ERROR, 1),
ERROR_ENTRY (N_("ASN1 parser: Element was not found."),
diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c
index e80c38092a..59eb9478c5 100644
--- a/lib/gnutls_pk.c
+++ b/lib/gnutls_pk.c
@@ -489,41 +489,6 @@ gnutls_pk_params_release (gnutls_pk_params_st * p)
}
int
-_gnutls_calc_rsa_exp (gnutls_pk_params_st* params)
-{
- bigint_t tmp = _gnutls_mpi_alloc_like (params->params[0]);
-
- if (params->params_nr < RSA_PRIVATE_PARAMS - 2)
- {
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
- }
-
- if (tmp == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- /* [6] = d % p-1, [7] = d % q-1 */
- _gnutls_mpi_sub_ui (tmp, params->params[3], 1);
- params->params[6] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp);
-
- _gnutls_mpi_sub_ui (tmp, params->params[4], 1);
- params->params[7] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp);
-
- _gnutls_mpi_release (&tmp);
-
- if (params->params[7] == NULL || params->params[6] == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- return 0;
-}
-
-int
_gnutls_pk_get_hash_algorithm (gnutls_pk_algorithm_t pk,
gnutls_pk_params_st* params,
gnutls_digest_algorithm_t * dig,
diff --git a/lib/gnutls_pk.h b/lib/gnutls_pk.h
index 6c192da471..26a91acc30 100644
--- a/lib/gnutls_pk.h
+++ b/lib/gnutls_pk.h
@@ -30,6 +30,7 @@ extern gnutls_crypto_pk_st _gnutls_pk_ops;
#define _gnutls_pk_decrypt( algo, ciphertext, plaintext, params) _gnutls_pk_ops.decrypt( algo, ciphertext, plaintext, params)
#define _gnutls_pk_sign( algo, sig, data, params) _gnutls_pk_ops.sign( algo, sig, data, params)
#define _gnutls_pk_verify( algo, data, sig, params) _gnutls_pk_ops.verify( algo, data, sig, params)
+#define _gnutls_pk_verify_params( algo, params) _gnutls_pk_ops.verify_params( algo, params)
#define _gnutls_pk_derive( algo, out, pub, priv) _gnutls_pk_ops.derive( algo, out, pub, priv)
#define _gnutls_pk_generate( algo, bits, priv) _gnutls_pk_ops.generate( algo, bits, priv)
@@ -65,8 +66,6 @@ int
_gnutls_decode_ber_rs (const gnutls_datum_t * sig_value, bigint_t * r,
bigint_t * s);
-int _gnutls_calc_rsa_exp (gnutls_pk_params_st*);
-
int _gnutls_pk_get_hash_algorithm (gnutls_pk_algorithm_t pk,
gnutls_pk_params_st*,
gnutls_digest_algorithm_t * dig,
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 77dd47ef08..f6395e203e 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -1793,6 +1793,7 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session);
#define GNUTLS_E_ECC_UNSUPPORTED_CURVE -322
#define GNUTLS_E_PKCS11_REQUESTED_OBJECT_NOT_AVAILBLE -323
#define GNUTLS_E_CERTIFICATE_LIST_UNSORTED -324
+#define GNUTLS_E_ILLEGAL_PARAMETER -325
#define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 55fdd317c9..2ade033d95 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -735,6 +735,7 @@ extern "C"
int gnutls_x509_privkey_generate (gnutls_x509_privkey_t key,
gnutls_pk_algorithm_t algo,
unsigned int bits, unsigned int flags);
+ int gnutls_x509_privkey_verify_params (gnutls_x509_privkey_t key);
int gnutls_x509_privkey_export (gnutls_x509_privkey_t key,
gnutls_x509_crt_fmt_t format,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 813a3cda8e..807c94ec6c 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -724,6 +724,7 @@ GNUTLS_3_0_0 {
gnutls_srp_3072_group_prime;
gnutls_srp_4096_group_generator;
gnutls_srp_4096_group_prime;
+ gnutls_x509_privkey_verify_params;
} GNUTLS_2_12;
GNUTLS_PRIVATE {
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index c56288ed17..5221aa66f0 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -136,7 +136,7 @@ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo, gnutls_datum_t * o
out->data = NULL;
if (is_supported_curve(curve) == 0)
- return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
_ecc_params_to_pubkey(pub, &ecc_pub);
_ecc_params_to_privkey(priv, &ecc_priv);
@@ -792,7 +792,7 @@ rsa_fail:
st = _gnutls_ecc_curve_get_params(level);
if (st == NULL)
- return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
tls_ecc_set.size = st->size;
tls_ecc_set.prime = st->prime;
@@ -855,6 +855,194 @@ fail:
return ret;
}
+static int
+wrap_nettle_pk_verify_params (gnutls_pk_algorithm_t algo,
+ const gnutls_pk_params_st * params)
+{
+ int ret;
+
+ switch (algo)
+ {
+ case GNUTLS_PK_RSA:
+ {
+ bigint_t t1 = NULL, t2 = NULL;
+
+ if (params->params_nr != RSA_PRIVATE_PARAMS)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ t1 = _gnutls_mpi_new (256);
+ if (t1 == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ _gnutls_mpi_mulm (t1, params->params[RSA_PRIME1], params->params[RSA_PRIME2], params->params[RSA_MODULUS]);
+ if (_gnutls_mpi_cmp_ui(t1, 0) != 0)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+ goto rsa_cleanup;
+ }
+
+ mpz_invert (TOMPZ(t1), TOMPZ (params->params[RSA_PRIME2]), TOMPZ (params->params[RSA_PRIME1]));
+ if (_gnutls_mpi_cmp(t1, params->params[RSA_COEF]) != 0)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+ goto rsa_cleanup;
+ }
+
+ /* [RSA_PRIME1] = d % p-1, [RSA_PRIME2] = d % q-1 */
+ _gnutls_mpi_sub_ui (t1, params->params[RSA_PRIME1], 1);
+ t2 = _gnutls_mpi_mod (params->params[RSA_PRIV], t1);
+ if (t2 == NULL)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto rsa_cleanup;
+ }
+
+ if (_gnutls_mpi_cmp(params->params[RSA_E1], t2) != 0)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+ goto rsa_cleanup;
+ }
+
+ _gnutls_mpi_sub_ui (t1, params->params[RSA_PRIME2], 1);
+ _gnutls_mpi_release(&t2);
+
+ t2 = _gnutls_mpi_mod (params->params[RSA_PRIV], t1);
+ if (t2 == NULL)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ goto rsa_cleanup;
+ }
+
+ if (_gnutls_mpi_cmp(params->params[RSA_E2], t2) != 0)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+ goto rsa_cleanup;
+ }
+
+ ret = 0;
+
+rsa_cleanup:
+ _gnutls_mpi_release(&t1);
+ _gnutls_mpi_release(&t2);
+ }
+
+ break;
+ case GNUTLS_PK_DSA:
+ {
+ bigint_t t1 = NULL;
+
+ if (params->params_nr != DSA_PRIVATE_PARAMS)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ t1 = _gnutls_mpi_new (256);
+ if (t1 == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ _gnutls_mpi_powm (t1, params->params[DSA_G], params->params[DSA_X], params->params[DSA_P]);
+
+ if (_gnutls_mpi_cmp(t1, params->params[DSA_Y]) != 0)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+ goto dsa_cleanup;
+ }
+
+ ret = 0;
+
+dsa_cleanup:
+ _gnutls_mpi_release(&t1);
+ }
+
+ break;
+ case GNUTLS_PK_ECC:
+ {
+ int curve = params->flags;
+ ecc_key ecc_priv;
+ ecc_point *R;
+ ecc_point zero;
+
+ if (params->params_nr != ECC_PRIVATE_PARAMS)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ if (is_supported_curve(curve) == 0)
+ return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+
+ _ecc_params_to_privkey(params, &ecc_priv);
+ R = ecc_new_point();
+
+ /* verify that x,y lie on the curve */
+ ret = ecc_projective_check_point(&ecc_priv.pubkey, TOMPZ(params->params[ECC_B]), params->params[ECC_PRIME]);
+ if (ret != 0)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+ goto ecc_cleanup;
+ }
+
+ memcpy(&zero.x, ecc_priv.Gx, sizeof(mpz_t));
+ memcpy(&zero.y, ecc_priv.Gy, sizeof(mpz_t));
+ memcpy(&zero.z, ecc_priv.pubkey.z, sizeof(mpz_t)); /* z = 1 */
+
+ /* verify that k*(Gx,Gy)=(x,y) */
+ ret = ecc_mulmod(ecc_priv.k, &zero, R, TOMPZ(params->params[ECC_A]), TOMPZ(params->params[ECC_PRIME]), 1);
+ if (ret != 0)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+ goto ecc_cleanup;
+ }
+
+ if (mpz_cmp(ecc_priv.pubkey.x, R->x) != 0 || mpz_cmp(ecc_priv.pubkey.y, R->y) != 0)
+ {
+ ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
+ goto ecc_cleanup;
+ }
+
+ ret = 0;
+
+ecc_cleanup:
+ _ecc_params_clear(&ecc_priv);
+ ecc_del_point(R);
+ }
+ break;
+ default:
+ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
+
+ return ret;
+}
+
+static int calc_rsa_exp (gnutls_pk_params_st* params)
+{
+ bigint_t tmp = _gnutls_mpi_alloc_like (params->params[0]);
+
+ if (params->params_nr < RSA_PRIVATE_PARAMS - 2)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INTERNAL_ERROR;
+ }
+
+ if (tmp == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ /* [6] = d % p-1, [7] = d % q-1 */
+ _gnutls_mpi_sub_ui (tmp, params->params[3], 1);
+ params->params[6] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp);
+
+ _gnutls_mpi_sub_ui (tmp, params->params[4], 1);
+ params->params[7] = _gnutls_mpi_mod (params->params[2] /*d */ , tmp);
+
+ _gnutls_mpi_release (&tmp);
+
+ if (params->params[7] == NULL || params->params[6] == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ return 0;
+}
+
static int
wrap_nettle_pk_fixup (gnutls_pk_algorithm_t algo,
@@ -870,14 +1058,14 @@ wrap_nettle_pk_fixup (gnutls_pk_algorithm_t algo,
* old but it seemed some of the shipped example private
* keys were as old.
*/
- mpz_invert (TOMPZ (params->params[5]),
- TOMPZ (params->params[4]), TOMPZ (params->params[3]));
+ mpz_invert (TOMPZ (params->params[RSA_COEF]),
+ TOMPZ (params->params[RSA_PRIME2]), TOMPZ (params->params[RSA_PRIME1]));
/* calculate exp1 [6] and exp2 [7] */
- _gnutls_mpi_release (&params->params[6]);
- _gnutls_mpi_release (&params->params[7]);
+ _gnutls_mpi_release (&params->params[RSA_E1]);
+ _gnutls_mpi_release (&params->params[RSA_E2]);
- result = _gnutls_calc_rsa_exp (params);
+ result = calc_rsa_exp (params);
if (result < 0)
{
gnutls_assert ();
@@ -896,6 +1084,7 @@ gnutls_crypto_pk_st _gnutls_pk_ops = {
.decrypt = _wrap_nettle_pk_decrypt,
.sign = _wrap_nettle_pk_sign,
.verify = _wrap_nettle_pk_verify,
+ .verify_params = wrap_nettle_pk_verify_params,
.generate = wrap_nettle_pk_generate_params,
.pk_fixup_private_params = wrap_nettle_pk_fixup,
.derive = _wrap_nettle_pk_derive,
diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c
index 75e59bd497..8e42dd4c17 100644
--- a/lib/x509/privkey.c
+++ b/lib/x509/privkey.c
@@ -1306,12 +1306,10 @@ gnutls_x509_privkey_export_dsa_raw (gnutls_x509_privkey_t key,
return 0;
}
-
-
/**
* gnutls_x509_privkey_generate:
* @key: should contain a #gnutls_x509_privkey_t structure
- * @algo: is one of RSA or DSA.
+ * @algo: is one of the algorithms in #gnutls_pk_algorithm_t.
* @bits: the size of the modulus
* @flags: unused for now. Must be 0.
*
@@ -1366,6 +1364,30 @@ cleanup:
}
/**
+ * gnutls_x509_privkey_verify_params:
+ * @key: should contain a #gnutls_x509_privkey_t structure
+ *
+ * This function will verify the private key parameters.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_x509_privkey_verify_params (gnutls_x509_privkey_t key)
+{
+ int ret;
+
+ ret = _gnutls_pk_verify_params (key->pk_algorithm, &key->params);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
* gnutls_x509_privkey_get_key_id:
* @key: Holds the key
* @flags: should be 0 for now
diff --git a/src/certtool.c b/src/certtool.c
index d60f5eb7c4..1988aff0a4 100644
--- a/src/certtool.c
+++ b/src/certtool.c
@@ -222,6 +222,10 @@ generate_private_key_int (void)
if (ret < 0)
error (EXIT_FAILURE, 0, "privkey_generate: %s", gnutls_strerror (ret));
+ ret = gnutls_x509_privkey_verify_params (key);
+ if (ret < 0)
+ error (EXIT_FAILURE, 0, "privkey_verify_params: %s", gnutls_strerror (ret));
+
return key;
}
@@ -1737,9 +1741,12 @@ privkey_info (void)
if (ret < 0)
error (EXIT_FAILURE, 0, "import error: %s", gnutls_strerror (ret));
-
privkey_info_int (key);
+ ret = gnutls_x509_privkey_verify_params (key);
+ if (ret < 0)
+ fprintf (outfile, "\n** Private key parameters validation failed **\n\n");
+
if (info.fix_key != 0)
{
ret = gnutls_x509_privkey_fix (key);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 13b8f7c87e..00d17be95d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -64,7 +64,7 @@ ctests = mini-deflate simple gc set_pkcs12_cred certder certuniqueid \
crq_apis init_roundtrip pkcs12_s2k_pem dn2 mini-eagain \
nul-in-x509-names x509_altname pkcs12_encode mini-x509 \
mini-x509-rehandshake rng-fork mini-eagain-dtls cipher-test \
- x509cert x509cert-tl infoaccess #gendh
+ x509cert x509cert-tl infoaccess keygen #gendh
#gendh is out because it is too slow in valgrind
if ENABLE_OPENSSL
diff --git a/tests/keygen.c b/tests/keygen.c
new file mode 100644
index 0000000000..aa6365ed2f
--- /dev/null
+++ b/tests/keygen.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ *
+ * Author: David Marín Carreño
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GnuTLS; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/abstract.h>
+
+#include "utils.h"
+
+static void
+tls_log_func (int level, const char *str)
+{
+ fprintf (stderr, "%s |<%d>| %s", "crq_key_id", level, str);
+}
+
+void
+doit (void)
+{
+ gnutls_x509_privkey_t pkey;
+ int ret, algorithm, i;
+
+ ret = gnutls_global_init ();
+ if (ret < 0)
+ fail ("gnutls_global_init: %d\n", ret);
+
+ gnutls_global_set_log_function (tls_log_func);
+ if (debug)
+ gnutls_global_set_log_level (4711);
+
+ for (i = 0; i < 2; i++)
+ {
+ for (algorithm = GNUTLS_PK_RSA; algorithm <= GNUTLS_PK_ECC;
+ algorithm++)
+ {
+ if (algorithm == GNUTLS_PK_DH)
+ continue;
+
+ ret = gnutls_x509_privkey_init (&pkey);
+ if (ret < 0)
+ {
+ fail ("gnutls_x509_privkey_init: %d\n", ret);
+ }
+
+ ret =
+ gnutls_x509_privkey_generate (pkey, algorithm,
+ gnutls_sec_param_to_pk_bits
+ (algorithm,
+ GNUTLS_SEC_PARAM_NORMAL),
+ 0);
+ if (ret < 0)
+ {
+ fail ("gnutls_x509_privkey_generate (%s): %s (%d)\n",
+ gnutls_pk_algorithm_get_name (algorithm),
+ gnutls_strerror (ret), ret);
+ }
+ else if (debug)
+ {
+ success ("Key[%s] generation ok: %d\n",
+ gnutls_pk_algorithm_get_name (algorithm),
+ ret);
+ }
+
+ ret = gnutls_x509_privkey_verify_params (pkey);
+ if (ret < 0)
+ {
+ fail ("gnutls_x509_privkey_generate (%s): %s (%d)\n",
+ gnutls_pk_algorithm_get_name (algorithm),
+ gnutls_strerror (ret), ret);
+ }
+
+ gnutls_x509_privkey_deinit (pkey);
+ }
+ }
+
+ gnutls_global_deinit ();
+}