]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
abstract: add gnutls_pubkey_export_dh_raw
authorDaiki Ueno <ueno@gnu.org>
Sun, 10 Sep 2023 11:19:13 +0000 (20:19 +0900)
committerDaiki Ueno <ueno@gnu.org>
Tue, 12 Sep 2023 05:43:55 +0000 (14:43 +0900)
This adds gnutls_pubkey_export_dh_raw, a public key counterpart of
gnutls_privkey_export_dh_raw.  This also replaces the P, Q, G
parameters with gnutls_dh_params_t in the function signatures to avoid
unnecessary serialization of bignums.

Signed-off-by: Daiki Ueno <ueno@gnu.org>
13 files changed:
NEWS
devel/libgnutls.abignore
devel/symbols.last
doc/Makefile.am
doc/manpages/Makefile.am
lib/includes/gnutls/abstract.h
lib/includes/gnutls/x509.h
lib/libgnutls.map
lib/privkey.c
lib/privkey_raw.c
lib/pubkey.c
lib/x509/privkey.c
tests/dh-compute2.c

diff --git a/NEWS b/NEWS
index 4fa162c894a2d138af3b9602385590236e56da35..2e6486ab7d37d230f6b6eca0af0d34060b1b4476 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,7 @@ See the end for copying conditions.
 ** API and ABI modifications:
 gnutls_pubkey_import_dh_raw: New function
 gnutls_privkey_import_dh_raw: New function
+gnutls_pubkey_export_dh_raw: New function
 gnutls_privkey_export_dh_raw: New function
 gnutls_x509_privkey_import_dh_raw: New function
 gnutls_privkey_derive_secret: New function
index c67292f5055c615a264c7c1ac894ede751f2e991..d22aec8496595709b5ba20e8a6fa79af56cd02eb 100644 (file)
@@ -76,6 +76,9 @@ name = gnutls_pubkey_import_dh_raw
 [suppress_function]
 name = gnutls_privkey_import_dh_raw
 
+[suppress_function]
+name = gnutls_pubkey_export_dh_raw
+
 [suppress_function]
 name = gnutls_privkey_export_dh_raw
 
index 5be2afd345bb9fc0faae87214b6b597388f4a24e..5972178b9daa2985f8540d0cf6857b3131cda699 100644 (file)
@@ -708,6 +708,7 @@ gnutls_pubkey_deinit@GNUTLS_3_4
 gnutls_pubkey_encrypt_data@GNUTLS_3_4
 gnutls_pubkey_export2@GNUTLS_3_4
 gnutls_pubkey_export@GNUTLS_3_4
+gnutls_pubkey_export_dh_raw@GNUTLS_3_8_2
 gnutls_pubkey_export_dsa_raw2@GNUTLS_3_6_0
 gnutls_pubkey_export_dsa_raw@GNUTLS_3_4
 gnutls_pubkey_export_ecc_raw2@GNUTLS_3_6_0
index d4d0beb41500ec7ffb711ab888ccd153aaf3aab4..90fab522fe824e2ad1c9944165ecef498ff5a16a 100644 (file)
@@ -1824,6 +1824,8 @@ FUNCS += functions/gnutls_pubkey_export
 FUNCS += functions/gnutls_pubkey_export.short
 FUNCS += functions/gnutls_pubkey_export2
 FUNCS += functions/gnutls_pubkey_export2.short
+FUNCS += functions/gnutls_pubkey_export_dh_raw
+FUNCS += functions/gnutls_pubkey_export_dh_raw.short
 FUNCS += functions/gnutls_pubkey_export_dsa_raw
 FUNCS += functions/gnutls_pubkey_export_dsa_raw.short
 FUNCS += functions/gnutls_pubkey_export_dsa_raw2
index 6d7f4bcea19bd1046bdfd068bc478656afb80f26..ca3336abaa56388150849d461dbeab664139598b 100644 (file)
@@ -758,6 +758,7 @@ APIMANS += gnutls_pubkey_deinit.3
 APIMANS += gnutls_pubkey_encrypt_data.3
 APIMANS += gnutls_pubkey_export.3
 APIMANS += gnutls_pubkey_export2.3
+APIMANS += gnutls_pubkey_export_dh_raw.3
 APIMANS += gnutls_pubkey_export_dsa_raw.3
 APIMANS += gnutls_pubkey_export_dsa_raw2.3
 APIMANS += gnutls_pubkey_export_ecc_raw.3
index 9e033a6e569596f1067fe141f72a5be96b375878..6916f305a22b0407023224019ec272bb03b74852 100644 (file)
@@ -190,6 +190,9 @@ int gnutls_pubkey_export_dsa_raw2(gnutls_pubkey_t key, gnutls_datum_t *p,
                                  gnutls_datum_t *q, gnutls_datum_t *g,
                                  gnutls_datum_t *y, unsigned flags);
 
+int gnutls_pubkey_export_dh_raw(gnutls_pubkey_t key, gnutls_dh_params_t params,
+                               gnutls_datum_t *y, unsigned flags);
+
 int gnutls_pubkey_export_ecc_raw2(gnutls_pubkey_t key,
                                  gnutls_ecc_curve_t *curve, gnutls_datum_t *x,
                                  gnutls_datum_t *y, unsigned flags);
@@ -238,9 +241,8 @@ int gnutls_pubkey_import_dsa_raw(gnutls_pubkey_t key, const gnutls_datum_t *p,
                                 const gnutls_datum_t *q,
                                 const gnutls_datum_t *g,
                                 const gnutls_datum_t *y);
-int gnutls_pubkey_import_dh_raw(gnutls_pubkey_t key, const gnutls_datum_t *p,
-                               const gnutls_datum_t *q,
-                               const gnutls_datum_t *g,
+int gnutls_pubkey_import_dh_raw(gnutls_pubkey_t key,
+                               const gnutls_dh_params_t params,
                                const gnutls_datum_t *y);
 int gnutls_pubkey_import_rsa_raw(gnutls_pubkey_t key, const gnutls_datum_t *m,
                                 const gnutls_datum_t *e);
@@ -441,9 +443,8 @@ int gnutls_privkey_import_dsa_raw(gnutls_privkey_t key, const gnutls_datum_t *p,
                                  const gnutls_datum_t *y,
                                  const gnutls_datum_t *x);
 
-int gnutls_privkey_import_dh_raw(gnutls_privkey_t key, const gnutls_datum_t *p,
-                                const gnutls_datum_t *q,
-                                const gnutls_datum_t *g,
+int gnutls_privkey_import_dh_raw(gnutls_privkey_t key,
+                                const gnutls_dh_params_t params,
                                 const gnutls_datum_t *y,
                                 const gnutls_datum_t *x);
 
@@ -521,10 +522,9 @@ int gnutls_privkey_export_dsa_raw2(gnutls_privkey_t key, gnutls_datum_t *p,
                                   gnutls_datum_t *y, gnutls_datum_t *x,
                                   unsigned flags);
 
-int gnutls_privkey_export_dh_raw(gnutls_privkey_t key, gnutls_datum_t *p,
-                                gnutls_datum_t *q, gnutls_datum_t *g,
-                                gnutls_datum_t *y, gnutls_datum_t *x,
-                                unsigned int flags);
+int gnutls_privkey_export_dh_raw(gnutls_privkey_t key,
+                                gnutls_dh_params_t params, gnutls_datum_t *y,
+                                gnutls_datum_t *x, unsigned int flags);
 
 int gnutls_privkey_export_ecc_raw(gnutls_privkey_t key,
                                  gnutls_ecc_curve_t *curve, gnutls_datum_t *x,
index 61ae85b609ee0dc12f1d413879be5c528d26810c..44661553bc616df07ec186d05b611fbab8bf5b03 100644 (file)
@@ -1119,9 +1119,7 @@ int gnutls_x509_privkey_import_dsa_raw(gnutls_x509_privkey_t key,
                                       const gnutls_datum_t *y,
                                       const gnutls_datum_t *x);
 int gnutls_x509_privkey_import_dh_raw(gnutls_x509_privkey_t key,
-                                     const gnutls_datum_t *p,
-                                     const gnutls_datum_t *q,
-                                     const gnutls_datum_t *g,
+                                     const gnutls_dh_params_t params,
                                      const gnutls_datum_t *y,
                                      const gnutls_datum_t *x);
 
index 6a1df9f8e0c8fa2c487687500bc3d95d6c84c4c1..87907f812858644f92f04cea2c41f910c4cdb8ec 100644 (file)
@@ -1424,6 +1424,7 @@ GNUTLS_3_8_2
  global:
        gnutls_pubkey_import_dh_raw;
        gnutls_privkey_import_dh_raw;
+       gnutls_pubkey_export_dh_raw;
        gnutls_privkey_export_dh_raw;
        gnutls_x509_privkey_import_dh_raw;
        gnutls_privkey_derive_secret;
index 3514e515144302a040419f9467f278cc68fd6a64..1d4cd0e52eb0ba58efb5950c1536913b9d37cbcb 100644 (file)
@@ -571,7 +571,7 @@ int gnutls_privkey_import_pkcs11(gnutls_privkey_t pkey,
  * @key: A key of type #gnutls_pubkey_t
  * @url: A PKCS 11 url
  *
- * This function will import a PKCS 11 private key to a #gnutls_private_key_t
+ * This function will import a PKCS 11 private key to a #gnutls_privkey_t
  * type.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
index 3b6b8fd908dc2dbadc595ff11c5515a78e345447..28e6e67327807ab2a2ab0579cf7e1c3db35d7207 100644 (file)
@@ -181,29 +181,51 @@ int gnutls_privkey_export_dsa_raw2(gnutls_privkey_t key, gnutls_datum_t *p,
 
 /**
  * gnutls_privkey_export_dh_raw:
- * @key: Holds the public key
- * @p: will hold the p
- * @q: will hold the q
- * @g: will hold the g
- * @y: will hold the y
+ * @key: Holds the private key
+ * @params: will hold the Diffie-Hellman parameters (optional), must be initialized
+ * @y: will hold the y (optional)
  * @x: will hold the x
  * @flags: flags from %gnutls_abstract_export_flags_t
  *
- * This function will export the Diffie-Hellman private key's
- * parameters found in the given structure. The new parameters will be
- * allocated using gnutls_malloc() and will be stored in the
+ * This function will export the Diffie-Hellman private key parameter
+ * found in the given %gnutls_privkey_t structure. The new parameter
+ * will be allocated using gnutls_malloc() and will be stored in the
  * appropriate datum.
  *
+ * To retrieve other parameters common in both public key and private
+ * key, use gnutls_dh_params_export_raw().
+ *
  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
  *
  * Since: 3.8.2
  **/
-int gnutls_privkey_export_dh_raw(gnutls_privkey_t key, gnutls_datum_t *p,
-                                gnutls_datum_t *q, gnutls_datum_t *g,
-                                gnutls_datum_t *y, gnutls_datum_t *x,
-                                unsigned int flags)
+int gnutls_privkey_export_dh_raw(gnutls_privkey_t key,
+                                gnutls_dh_params_t params, gnutls_datum_t *y,
+                                gnutls_datum_t *x, unsigned int flags)
 {
-       return gnutls_privkey_export_dsa_raw2(key, p, q, g, y, x, flags);
+       if (params) {
+               gnutls_pk_params_st pk_params;
+               int ret;
+
+               gnutls_pk_params_init(&pk_params);
+
+               ret = _gnutls_privkey_get_mpis(key, &pk_params);
+               if (ret < 0)
+                       return gnutls_assert_val(ret);
+
+               params->params[0] = _gnutls_mpi_copy(pk_params.params[DH_P]);
+               params->params[1] = _gnutls_mpi_copy(pk_params.params[DH_G]);
+               if (pk_params.params[DH_Q]) {
+                       params->params[2] =
+                               _gnutls_mpi_copy(pk_params.params[DH_Q]);
+               }
+               params->q_bits = pk_params.qbits;
+
+               gnutls_pk_params_release(&pk_params);
+       }
+
+       return gnutls_privkey_export_dsa_raw2(key, NULL, NULL, NULL, y, x,
+                                             flags);
 }
 
 /**
@@ -434,9 +456,7 @@ error:
 /**
  * gnutls_privkey_import_dh_raw:
  * @key: The structure to store the parsed key
- * @p: holds the p
- * @q: holds the q (optional)
- * @g: holds the g
+ * @params: holds the %gnutls_dh_params_t
  * @y: holds the y (optional)
  * @x: holds the x
  *
@@ -449,9 +469,8 @@ error:
  *
  * Since: 3.8.2
  **/
-int gnutls_privkey_import_dh_raw(gnutls_privkey_t key, const gnutls_datum_t *p,
-                                const gnutls_datum_t *q,
-                                const gnutls_datum_t *g,
+int gnutls_privkey_import_dh_raw(gnutls_privkey_t key,
+                                const gnutls_dh_params_t params,
                                 const gnutls_datum_t *y,
                                 const gnutls_datum_t *x)
 {
@@ -462,7 +481,7 @@ int gnutls_privkey_import_dh_raw(gnutls_privkey_t key, const gnutls_datum_t *p,
        if (ret < 0)
                return gnutls_assert_val(ret);
 
-       ret = gnutls_x509_privkey_import_dh_raw(xkey, p, q, g, y, x);
+       ret = gnutls_x509_privkey_import_dh_raw(xkey, params, y, x);
        if (ret < 0) {
                gnutls_assert();
                goto error;
index 71ba2272dcb1319ad5c77ac89975d2419fcdc049..8ed79d3577517c34dbe990fc2468ca7d9207787c 100644 (file)
@@ -1073,6 +1073,65 @@ int gnutls_pubkey_export_dsa_raw2(gnutls_pubkey_t key, gnutls_datum_t *p,
        return 0;
 }
 
+/**
+ * gnutls_pubkey_export_dh_raw:
+ * @key: Holds the public key
+ * @params: will hold the Diffie-Hellman parameter (optional), must be initialized
+ * @y: will hold the y
+ * @flags: flags from %gnutls_abstract_export_flags_t
+ *
+ * This function will export the Diffie-Hellman public key parameter
+ * found in the given public key.  The new parameter will be allocated
+ * using gnutls_malloc() and will be stored in the appropriate datum.
+ *
+ * To retrieve other parameters common in both public key and private
+ * key, use gnutls_dh_params_export_raw().
+ *
+ * This function allows for %NULL parameters since 3.4.1.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
+ *
+ * Since: 3.8.2
+ **/
+int gnutls_pubkey_export_dh_raw(gnutls_pubkey_t key, gnutls_dh_params_t params,
+                               gnutls_datum_t *y, unsigned flags)
+{
+       int ret;
+       mpi_dprint_func dprint = _gnutls_mpi_dprint_lz;
+
+       if (flags & GNUTLS_EXPORT_FLAG_NO_LZ) {
+               dprint = _gnutls_mpi_dprint;
+       }
+
+       if (key == NULL) {
+               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+       }
+
+       if (key->params.algo != GNUTLS_PK_DH) {
+               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+       }
+
+       if (params) {
+               params->params[0] = _gnutls_mpi_copy(key->params.params[DH_P]);
+               params->params[1] = _gnutls_mpi_copy(key->params.params[DH_G]);
+               if (key->params.params[DH_Q]) {
+                       params->params[2] =
+                               _gnutls_mpi_copy(key->params.params[DH_Q]);
+               }
+               params->q_bits = key->params.qbits;
+       }
+
+       /* Y */
+       if (y) {
+               ret = dprint(key->params.params[DH_Y], y);
+               if (ret < 0) {
+                       return gnutls_assert_val(ret);
+               }
+       }
+
+       return 0;
+}
+
 /**
  * gnutls_pubkey_export_ecc_raw:
  * @key: Holds the public key
@@ -1948,9 +2007,7 @@ cleanup:
 /**
  * gnutls_pubkey_import_dh_raw:
  * @key: The structure to store the parsed key
- * @p: holds the p
- * @q: holds the q (optional)
- * @g: holds the g
+ * @params: holds the %gnutls_dh_params_t
  * @y: holds the y
  *
  * This function will convert the given Diffie-Hellman raw parameters
@@ -1962,42 +2019,25 @@ cleanup:
  *
  * Since: 3.8.2
  **/
-int gnutls_pubkey_import_dh_raw(gnutls_pubkey_t key, const gnutls_datum_t *p,
-                               const gnutls_datum_t *q,
-                               const gnutls_datum_t *g,
+int gnutls_pubkey_import_dh_raw(gnutls_pubkey_t key,
+                               const gnutls_dh_params_t params,
                                const gnutls_datum_t *y)
 {
        int ret;
 
-       if (unlikely(key == NULL || p == NULL || g == NULL || y == NULL)) {
+       if (unlikely(key == NULL || params == NULL || y == NULL)) {
                return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
        }
 
        gnutls_pk_params_release(&key->params);
        gnutls_pk_params_init(&key->params);
 
-       if (_gnutls_mpi_init_scan_nz(&key->params.params[DH_P], p->data,
-                                    p->size)) {
-               gnutls_assert();
-               ret = GNUTLS_E_MPI_SCAN_FAILED;
-               goto cleanup;
-       }
-
-       if (q) {
-               if (_gnutls_mpi_init_scan_nz(&key->params.params[DH_Q], q->data,
-                                            q->size)) {
-                       gnutls_assert();
-                       ret = GNUTLS_E_MPI_SCAN_FAILED;
-                       goto cleanup;
-               }
-       }
-
-       if (_gnutls_mpi_init_scan_nz(&key->params.params[DH_G], g->data,
-                                    g->size)) {
-               gnutls_assert();
-               ret = GNUTLS_E_MPI_SCAN_FAILED;
-               goto cleanup;
+       key->params.params[DH_P] = _gnutls_mpi_copy(params->params[0]);
+       key->params.params[DH_G] = _gnutls_mpi_copy(params->params[1]);
+       if (params->params[2]) {
+               key->params.params[DH_Q] = _gnutls_mpi_copy(params->params[2]);
        }
+       key->params.qbits = params->q_bits;
 
        if (_gnutls_mpi_init_scan_nz(&key->params.params[DH_Y], y->data,
                                     y->size)) {
index 3ee15971aa8ef1c5897fafc8db684109995d4339..df7c3f0806d9a1df14ec1abadf8774f79f091384 100644 (file)
@@ -1074,9 +1074,7 @@ cleanup:
 /**
  * gnutls_x509_privkey_import_dh_raw:
  * @key: The data to store the parsed key
- * @p: holds the p
- * @q: holds the q (optional)
- * @g: holds the g
+ * @params: holds the %gnutls_dh_params_t
  * @y: holds the y (optional)
  * @x: holds the x
  *
@@ -1088,42 +1086,24 @@ cleanup:
  *   negative error value.
  **/
 int gnutls_x509_privkey_import_dh_raw(gnutls_x509_privkey_t key,
-                                     const gnutls_datum_t *p,
-                                     const gnutls_datum_t *q,
-                                     const gnutls_datum_t *g,
+                                     const gnutls_dh_params_t params,
                                      const gnutls_datum_t *y,
                                      const gnutls_datum_t *x)
 {
        int ret;
 
-       if (unlikely(key == NULL || p == NULL || g == NULL || x == NULL)) {
+       if (unlikely(key == NULL || params == NULL || x == NULL)) {
                return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
        }
 
        gnutls_pk_params_init(&key->params);
 
-       if (_gnutls_mpi_init_scan_nz(&key->params.params[DH_P], p->data,
-                                    p->size)) {
-               gnutls_assert();
-               ret = GNUTLS_E_MPI_SCAN_FAILED;
-               goto cleanup;
-       }
-
-       if (q) {
-               if (_gnutls_mpi_init_scan_nz(&key->params.params[DH_Q], q->data,
-                                            q->size)) {
-                       gnutls_assert();
-                       ret = GNUTLS_E_MPI_SCAN_FAILED;
-                       goto cleanup;
-               }
-       }
-
-       if (_gnutls_mpi_init_scan_nz(&key->params.params[DH_G], g->data,
-                                    g->size)) {
-               gnutls_assert();
-               ret = GNUTLS_E_MPI_SCAN_FAILED;
-               goto cleanup;
+       key->params.params[DH_P] = _gnutls_mpi_copy(params->params[0]);
+       key->params.params[DH_G] = _gnutls_mpi_copy(params->params[1]);
+       if (params->params[2]) {
+               key->params.params[DH_Q] = _gnutls_mpi_copy(params->params[2]);
        }
+       key->params.qbits = params->q_bits;
 
        if (y) {
                if (_gnutls_mpi_init_scan_nz(&key->params.params[DH_Y], y->data,
@@ -1941,6 +1921,7 @@ int gnutls_x509_privkey_generate2(gnutls_x509_privkey_t key,
                        _gnutls_mpi_copy(dh_params->params[1]);
                /* X and Y will be added by _gnutls_pk_generate_keys */
                key->params.params_nr = 3;
+               key->params.qbits = dh_params->q_bits;
        } else {
                ret = _gnutls_pk_generate_params(algo, bits, &key->params);
                if (ret < 0) {
index 94463e185fd813301efe1979022f344b0fc95a3b..cf16fe8560419c4d675319700569768e5ca8a730 100644 (file)
@@ -46,16 +46,50 @@ static void params(gnutls_dh_params_t *dh_params, const gnutls_datum_t *p,
                fail("error\n");
 }
 
+static bool dh_params_equal(const gnutls_dh_params_t a,
+                           const gnutls_dh_params_t b)
+{
+       gnutls_datum_t prime1, generator1;
+       unsigned int bits1;
+       gnutls_datum_t prime2, generator2;
+       unsigned int bits2;
+       int ret;
+       bool ok;
+
+       ret = gnutls_dh_params_export_raw(a, &prime1, &generator1, &bits1);
+       assert(ret >= 0);
+       ret = gnutls_dh_params_export_raw(b, &prime2, &generator2, &bits2);
+       assert(ret >= 0);
+
+       ok = prime1.size == prime2.size &&
+            !memcmp(prime1.data, prime2.data, prime1.size) &&
+            generator1.size == generator2.size &&
+            !memcmp(generator1.data, generator2.data, generator1.size) &&
+            bits1 == bits2;
+
+       gnutls_free(prime1.data);
+       gnutls_free(prime2.data);
+       gnutls_free(generator1.data);
+       gnutls_free(generator2.data);
+
+       return ok;
+}
+
 static void genkey(const gnutls_dh_params_t dh_params, gnutls_datum_t *priv_key,
                   gnutls_datum_t *pub_key)
 {
        int ret;
        gnutls_privkey_t privkey;
+       gnutls_pubkey_t pubkey;
        gnutls_keygen_data_st data;
+       gnutls_dh_params_t dh_params_exported;
+       gnutls_datum_t tmp;
 
        ret = gnutls_privkey_init(&privkey);
-       if (ret != 0)
-               fail("error\n");
+       assert(ret >= 0);
+
+       ret = gnutls_pubkey_init(&pubkey);
+       assert(ret >= 0);
 
        data.type = GNUTLS_KEYGEN_DH;
        data.data = (unsigned char *)dh_params;
@@ -63,12 +97,59 @@ static void genkey(const gnutls_dh_params_t dh_params, gnutls_datum_t *priv_key,
        if (ret != 0)
                fail("error\n");
 
-       ret = gnutls_privkey_export_dh_raw(privkey, NULL, NULL, NULL, pub_key,
-                                          priv_key, 0);
-       if (ret != 0)
-               fail("error: %s\n", gnutls_strerror(ret));
+       ret = gnutls_pubkey_import_privkey(pubkey, privkey, 0, 0);
+       assert(ret >= 0);
+
+       /* Retrieve only private key */
+       ret = gnutls_privkey_export_dh_raw(privkey, NULL, NULL, &tmp, 0);
+       if (ret != 0) {
+               fail("unable to export private key: %s\n",
+                    gnutls_strerror(ret));
+       }
+       gnutls_free(tmp.data);
+
+       /* Retrieve DH params and private key */
+       ret = gnutls_dh_params_init(&dh_params_exported);
+       assert(ret >= 0);
+
+       ret = gnutls_privkey_export_dh_raw(privkey, dh_params_exported, NULL,
+                                          &tmp, 0);
+       if (ret != 0) {
+               fail("unable to export private key: %s\n",
+                    gnutls_strerror(ret));
+       }
+       *priv_key = tmp;
+
+       if (!dh_params_equal(dh_params_exported, dh_params)) {
+               fail("error\n");
+       }
+
+       gnutls_dh_params_deinit(dh_params_exported);
 
+       /* Retrieve only public key */
+       ret = gnutls_pubkey_export_dh_raw(pubkey, NULL, &tmp, 0);
+       if (ret != 0) {
+               fail("unable to export public key: %s\n", gnutls_strerror(ret));
+       }
+       gnutls_free(tmp.data);
+
+       /* Retrieve DH params and public key */
+       ret = gnutls_dh_params_init(&dh_params_exported);
+       assert(ret >= 0);
+
+       ret = gnutls_pubkey_export_dh_raw(pubkey, dh_params_exported, &tmp, 0);
+       if (ret != 0) {
+               fail("unable to export public key: %s\n", gnutls_strerror(ret));
+       }
+       *pub_key = tmp;
+
+       if (!dh_params_equal(dh_params_exported, dh_params)) {
+               fail("error\n");
+       }
+
+       gnutls_dh_params_deinit(dh_params_exported);
        gnutls_privkey_deinit(privkey);
+       gnutls_pubkey_deinit(pubkey);
 }
 
 static void compute_key(const char *name, const gnutls_dh_params_t dh_params,
@@ -82,34 +163,23 @@ static void compute_key(const char *name, const gnutls_dh_params_t dh_params,
        int ret;
        gnutls_privkey_t privkey;
        gnutls_pubkey_t pubkey;
-       gnutls_datum_t prime, generator;
-       unsigned int bits;
 
        ret = gnutls_privkey_init(&privkey);
-       if (ret != 0)
-               fail("error\n");
+       assert(ret >= 0);
 
-       ret = gnutls_dh_params_export_raw(dh_params, &prime, &generator, &bits);
-       if (ret != 0)
-               fail("error\n");
-
-       ret = gnutls_privkey_import_dh_raw(privkey, &prime, NULL, &generator,
-                                          NULL, priv_key);
-       if (ret != 0)
-               fail("error\n");
+       ret = gnutls_privkey_import_dh_raw(privkey, dh_params, NULL, priv_key);
+       assert(ret >= 0);
 
        ret = gnutls_pubkey_init(&pubkey);
-       if (ret != 0)
-               fail("error\n");
+       assert(ret >= 0);
 
-       ret = gnutls_pubkey_import_dh_raw(pubkey, &prime, NULL, &generator,
-                                         pub_key);
-       if (ret != 0)
-               fail("error\n");
+       ret = gnutls_pubkey_import_dh_raw(pubkey, dh_params, pub_key);
+       assert(ret >= 0);
 
        ret = gnutls_privkey_derive_secret(privkey, pubkey, NULL, &Z, 0);
-       if (ret != 0)
-               fail("error\n");
+       if (ret != 0) {
+               fail("unable to derive secret: %s\n", gnutls_strerror(ret));
+       }
 
        if (result) {
                success = (Z.size != result->size &&
@@ -118,8 +188,6 @@ static void compute_key(const char *name, const gnutls_dh_params_t dh_params,
                        fail("%s: failed to match result\n", name);
        }
        gnutls_free(Z.data);
-       gnutls_free(prime.data);
-       gnutls_free(generator.data);
        gnutls_privkey_deinit(privkey);
        gnutls_pubkey_deinit(pubkey);
 }