tests/dane
tests/dane-strcodes
tests/dh-compute
+tests/dh-compute2
tests/dh-params
tests/dhepskself
tests/dhex509self
tests/eagain
tests/eagain-auto-auth
tests/ecdh-compute
+tests/ecdh-compute2
tests/empty_retrieve_function
tests/fallback-scsv
tests/finished
tests/priority-mix
tests/priority-set
tests/priority-set2
+tests/privkey-derive
tests/privkey-keygen
tests/privkey-verify-broken
tests/protocol-set-allowlist
Copyright (C) 2013-2019 Nikos Mavrogiannopoulos
See the end for copying conditions.
+* Version 3.8.2 (unreleased)
+
+** libgnutls: Add API functions to perform ECDH and DH key agreement
+ The functionality has been there for a long time though they were
+ not available as part of the public API. This enables applications
+ to implement custom protocols leveraging non-interactive key
+ agreement with ECDH and DH.
+
+** API and ABI modifications:
+gnutls_pubkey_import_dh_raw: New function
+gnutls_privkey_import_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
+GNUTLS_KEYGEN_DH: New enum member of gnutls_keygen_types_t
+
* Version 3.8.1 (released 2023-08-03)
** libgnutls: ClientHello extensions are randomized by default
[suppress_function]
name = gnutls_x509_privkey_import_dh_raw
+
+[suppress_function]
+name = gnutls_privkey_derive_secret
gnutls_privkey_decrypt_data2@GNUTLS_3_6_5
gnutls_privkey_decrypt_data@GNUTLS_3_4
gnutls_privkey_deinit@GNUTLS_3_4
+gnutls_privkey_derive_secret@GNUTLS_3_8_2
gnutls_privkey_export_dh_raw@GNUTLS_3_8_2
gnutls_privkey_export_dsa_raw2@GNUTLS_3_6_0
gnutls_privkey_export_dsa_raw@GNUTLS_3_4
FUNCS += functions/gnutls_privkey_decrypt_data2.short
FUNCS += functions/gnutls_privkey_deinit
FUNCS += functions/gnutls_privkey_deinit.short
+FUNCS += functions/gnutls_privkey_derive_secret
+FUNCS += functions/gnutls_privkey_derive_secret.short
FUNCS += functions/gnutls_privkey_export_dh_raw
FUNCS += functions/gnutls_privkey_export_dh_raw.short
FUNCS += functions/gnutls_privkey_export_dsa_raw
APIMANS += gnutls_privkey_decrypt_data.3
APIMANS += gnutls_privkey_decrypt_data2.3
APIMANS += gnutls_privkey_deinit.3
+APIMANS += gnutls_privkey_derive_secret.3
APIMANS += gnutls_privkey_export_dh_raw.3
APIMANS += gnutls_privkey_export_dsa_raw.3
APIMANS += gnutls_privkey_export_dsa_raw2.3
gnutls_gost_paramset_t *paramset,
gnutls_datum_t *x, gnutls_datum_t *y,
gnutls_datum_t *k, unsigned flags);
+int gnutls_privkey_derive_secret(gnutls_privkey_t privkey,
+ gnutls_pubkey_t pubkey,
+ const gnutls_datum_t *nonce,
+ gnutls_datum_t *secret, unsigned int flags);
int gnutls_x509_crt_privkey_sign(gnutls_x509_crt_t crt,
gnutls_x509_crt_t issuer,
gnutls_privkey_import_dh_raw;
gnutls_privkey_export_dh_raw;
gnutls_x509_privkey_import_dh_raw;
+ gnutls_privkey_derive_secret;
local:
*;
} GNUTLS_3_8_1;
return 1;
}
+
+/**
+ * gnutls_privkey_derive_secret:
+ * @privkey: a private key of type #gnutls_privkey_t
+ * @pubkey: a public key of type #gnutls_pubkey_t
+ * @nonce: an optional nonce value
+ * @secret: where shared secret will be stored
+ * @flags: must be zero
+ *
+ * This function will calculate a shared secret from our @privkey and
+ * peer's @pubkey. The result will be stored in @secret, whose data
+ * member should be freed after use using gnutls_free(). @privkey and
+ * @pubkey must be backed by the X.509 keys.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.8.2
+ **/
+int gnutls_privkey_derive_secret(gnutls_privkey_t privkey,
+ gnutls_pubkey_t pubkey,
+ const gnutls_datum_t *nonce,
+ gnutls_datum_t *secret, unsigned int flags)
+{
+ if (unlikely(privkey == NULL || privkey->type != GNUTLS_PRIVKEY_X509)) {
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
+
+ if (unlikely(pubkey == NULL ||
+ pubkey->params.algo != privkey->pk_algorithm)) {
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
+
+ return _gnutls_pk_derive_nonce(privkey->pk_algorithm, secret,
+ &privkey->key.x509->params,
+ &pubkey->params, nonce);
+}
x509cert-dntypes id-on-xmppAddr tls13-compat-mode ciphersuite-name \
x509-upnconstraint xts-key-check cipher-padding pkcs7-verify-double-free \
fips-rsa-sizes tls12-rehandshake-ticket pathbuf tls-force-ems \
- psk-importer
+ psk-importer privkey-derive dh-compute2 ecdh-compute2
ctests += tls-channel-binding
* along with GnuTLS. If not, see <https://www.gnu.org/licenses/>.
*/
-/* This program tests functionality of DH exchanges */
+/* This program tests functionality of DH exchanges, with legacy,
+ * FIPS-only API
+ */
#ifdef HAVE_CONFIG_H
#include <config.h>
--- /dev/null
+/*
+ * Copyright (C) 2019-2023 Red Hat, Inc.
+ *
+ * Author: Simo Sorce, Daiki Ueno
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+/* This program tests functionality of DH exchanges, with public API */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gnutls/gnutls.h>
+#include <gnutls/abstract.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include "utils.h"
+
+static void params(gnutls_dh_params_t *dh_params, const gnutls_datum_t *p,
+ const gnutls_datum_t *q, const gnutls_datum_t *g)
+{
+ int ret;
+
+ ret = gnutls_dh_params_init(dh_params);
+ if (ret != 0)
+ fail("error\n");
+
+ ret = gnutls_dh_params_import_raw3(*dh_params, p, q, g);
+ if (ret != 0)
+ fail("error\n");
+}
+
+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_keygen_data_st data;
+
+ ret = gnutls_privkey_init(&privkey);
+ if (ret != 0)
+ fail("error\n");
+
+ data.type = GNUTLS_KEYGEN_DH;
+ data.data = (unsigned char *)dh_params;
+ ret = gnutls_privkey_generate2(privkey, GNUTLS_PK_DH, 0, 0, &data, 1);
+ 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));
+
+ gnutls_privkey_deinit(privkey);
+}
+
+static void compute_key(const char *name, const gnutls_dh_params_t dh_params,
+ const gnutls_datum_t *priv_key,
+ const gnutls_datum_t *pub_key,
+ const gnutls_datum_t *peer_key, int expect_error,
+ gnutls_datum_t *result, bool expect_success)
+{
+ gnutls_datum_t Z = { 0 };
+ bool success;
+ 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");
+
+ 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_pubkey_init(&pubkey);
+ if (ret != 0)
+ fail("error\n");
+
+ ret = gnutls_pubkey_import_dh_raw(pubkey, &prime, NULL, &generator,
+ pub_key);
+ if (ret != 0)
+ fail("error\n");
+
+ ret = gnutls_privkey_derive_secret(privkey, pubkey, NULL, &Z, 0);
+ if (ret != 0)
+ fail("error\n");
+
+ if (result) {
+ success = (Z.size != result->size &&
+ memcmp(Z.data, result->data, Z.size));
+ if (success != expect_success)
+ 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);
+}
+
+struct dh_test_data {
+ const char *name;
+ const gnutls_datum_t prime;
+ const gnutls_datum_t q;
+ const gnutls_datum_t generator;
+ const gnutls_datum_t peer_key;
+ int expected_error;
+ gnutls_fips140_operation_state_t fips_state_genkey;
+ gnutls_fips140_operation_state_t fips_state_compute_key;
+};
+
+void doit(void)
+{
+ struct dh_test_data test_data[] = {
+ {
+ "Legal Input",
+ gnutls_ffdhe_2048_group_prime,
+ gnutls_ffdhe_2048_group_q,
+ gnutls_ffdhe_2048_group_generator,
+ { (void *)"\x02", 1 },
+ 0,
+ GNUTLS_FIPS140_OP_APPROVED,
+ GNUTLS_FIPS140_OP_APPROVED,
+ },
+ { NULL }
+ };
+
+ for (int i = 0; test_data[i].name != NULL; i++) {
+ gnutls_datum_t priv_key, pub_key;
+ gnutls_dh_params_t dh_params;
+ gnutls_fips140_context_t fips_context;
+ int ret;
+
+ if (gnutls_fips140_mode_enabled()) {
+ ret = gnutls_fips140_context_init(&fips_context);
+ if (ret < 0) {
+ fail("Cannot initialize FIPS context\n");
+ }
+ }
+
+ fips_push_context(fips_context);
+ params(&dh_params, &test_data[i].prime, &test_data[i].q,
+ &test_data[i].generator);
+ fips_pop_context(fips_context, GNUTLS_FIPS140_OP_INITIAL);
+
+ success("%s genkey\n", test_data[i].name);
+
+ fips_push_context(fips_context);
+ genkey(dh_params, &priv_key, &pub_key);
+ fips_pop_context(fips_context, test_data[i].fips_state_genkey);
+
+ success("%s compute_key\n", test_data[i].name);
+
+ fips_push_context(fips_context);
+ compute_key(test_data[i].name, dh_params, &priv_key, &pub_key,
+ &test_data[i].peer_key, test_data[i].expected_error,
+ NULL, 0);
+ fips_pop_context(fips_context,
+ test_data[i].fips_state_compute_key);
+
+ gnutls_dh_params_deinit(dh_params);
+ gnutls_free(priv_key.data);
+ gnutls_free(pub_key.data);
+
+ if (gnutls_fips140_mode_enabled()) {
+ gnutls_fips140_context_deinit(fips_context);
+ }
+ }
+
+ success("all ok\n");
+}
* along with GnuTLS. If not, see <https://www.gnu.org/licenses/>.
*/
-/* This program tests functionality of DH exchanges */
+/* This program tests functionality of ECDH exchanges, with legacy,
+ * FIPS-only API
+ */
#ifdef HAVE_CONFIG_H
#include <config.h>
--- /dev/null
+/*
+ * Copyright (C) 2019-2023 Red Hat, Inc.
+ *
+ * Author: Simo Sorce, Daiki Ueno
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+/* This program tests functionality of ECDH exchanges, using public API */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gnutls/gnutls.h>
+#include <gnutls/abstract.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include "utils.h"
+
+static void genkey(gnutls_ecc_curve_t curve, gnutls_datum_t *x,
+ gnutls_datum_t *y, gnutls_datum_t *key)
+{
+ int ret;
+ gnutls_privkey_t privkey;
+
+ ret = gnutls_privkey_init(&privkey);
+ if (ret != 0)
+ fail("error\n");
+
+ ret = gnutls_privkey_generate(privkey, GNUTLS_PK_EC,
+ GNUTLS_CURVE_TO_BITS(curve), 0);
+ if (ret != 0)
+ fail("error\n");
+
+ ret = gnutls_privkey_export_ecc_raw(privkey, NULL, x, y, key);
+ if (ret != 0)
+ fail("error\n");
+
+ gnutls_privkey_deinit(privkey);
+}
+
+static void compute_key(gnutls_ecc_curve_t curve, const gnutls_datum_t *x,
+ const gnutls_datum_t *y, const gnutls_datum_t *key,
+ const gnutls_datum_t *peer_x,
+ const gnutls_datum_t *peer_y, int expect_error,
+ gnutls_datum_t *result, bool expect_success)
+{
+ gnutls_datum_t Z = { 0 };
+ bool success;
+ int ret;
+ gnutls_privkey_t privkey;
+ gnutls_pubkey_t pubkey;
+
+ ret = gnutls_privkey_init(&privkey);
+ if (ret != 0)
+ fail("error\n");
+
+ ret = gnutls_privkey_import_ecc_raw(privkey, curve, x, y, key);
+ if (ret != 0)
+ fail("error\n");
+
+ ret = gnutls_pubkey_init(&pubkey);
+ if (ret != 0)
+ fail("error\n");
+
+ ret = gnutls_pubkey_import_ecc_raw(pubkey, curve, x, y);
+ if (ret != 0)
+ fail("error\n");
+
+ ret = gnutls_privkey_derive_secret(privkey, pubkey, NULL, &Z, 0);
+ if (ret != 0)
+ fail("error\n");
+
+ if (result) {
+ success = (Z.size != result->size &&
+ memcmp(Z.data, result->data, Z.size));
+ if (success != expect_success)
+ fail("error\n");
+ }
+ gnutls_free(Z.data);
+
+ gnutls_privkey_deinit(privkey);
+ gnutls_pubkey_deinit(pubkey);
+}
+
+struct dh_test_data {
+ gnutls_ecc_curve_t curve;
+ const gnutls_datum_t x;
+ const gnutls_datum_t y;
+ const gnutls_datum_t key;
+ const gnutls_datum_t peer_x;
+ const gnutls_datum_t peer_y;
+ int expected_error;
+};
+
+void doit(void)
+{
+ struct dh_test_data test_data[] = {
+ {
+ /* From CAVS tests */
+ GNUTLS_ECC_CURVE_SECP521R1,
+ { (void *)"\xac\xbe\x4a\xd4\xf6\x73\x44\x0a"
+ "\xfc\x31\xf0\xb0\x3d\x28\xd4\xd5"
+ "\x14\xbe\x7b\xdd\x7a\x31\xb0\x32"
+ "\xec\x27\x27\x17\xa5\x7d\xc2\x6c"
+ "\xc4\xc9\x56\x29\xdb\x2d\x8c\x05"
+ "\x86\x2b\xe6\x15\xc6\x06\x28\xa3"
+ "\x24\xf2\x01\x7f\x98\xbd\xf9\x11"
+ "\xcc\xf8\x83\x5e\x43\x9e\xb2\xc1"
+ "\x88",
+ 65 },
+ { (void *)"\xd6\x9b\x29\xa2\x37\x82\x36\x92"
+ "\xe8\xdb\x90\xa3\x25\x68\x67\x6c"
+ "\x92\xff\x3d\x23\x85\xe2\xfd\x13"
+ "\x16\x12\x72\xb3\x4b\x55\x88\x72"
+ "\xb0\x35\xab\xb5\x10\x89\x52\x5f"
+ "\x42\x9f\x53\x02\x60\x80\xc3\xd5"
+ "\x36\x6e\xe9\xdd\x28\xae\xd2\x38"
+ "\xab\xbe\x68\x6a\x54\x3e\x19\xf2"
+ "\x77",
+ 65 },
+ { (void *)"\xd7\xdd\x17\x7c\xb9\x7f\x19\x09"
+ "\xbe\x56\x79\xba\x38\x7b\xee\x64"
+ "\xf7\xb4\x08\x4a\x4f\xaa\x6c\x31"
+ "\x8b\x82\xe9\xf2\xf7\x50\xc5\xc1"
+ "\x82\x26\x20\xd4\x88\x25\x0b\xf6"
+ "\xb4\x14\xea\x9b\x2c\x07\x93\x50"
+ "\xb9\xad\x78\x0a\x5e\xc6\xa6\xf8"
+ "\xb2\x9f\xa1\xc4\x76\xce\x1d\xa9"
+ "\xf5",
+ 65 },
+ { (void *)"\x01\x41\xbe\x1a\xfa\x21\x99\xc9"
+ "\xb2\x2d\xaa\x0a\xff\x90\xb2\x67"
+ "\x18\xa2\x67\x04\x7e\xae\x28\x40"
+ "\xe8\xbc\xa0\xbd\x0c\x75\x41\x51"
+ "\xf1\xa0\x4d\xcf\x09\xa5\x4f\x1e"
+ "\x13\x5e\xa0\xdd\x13\xed\x86\x74"
+ "\x05\xc0\xcb\x6d\xac\x14\x6a\x24"
+ "\xb8\xdc\xf3\x78\xed\xed\x5d\xcd"
+ "\x57\x5b",
+ 66 },
+ { (void *)"\x19\x52\xbd\x5d\xe6\x26\x40\xc3"
+ "\xfc\x8c\xc1\x55\xe2\x9c\x71\x14"
+ "\x5e\xdc\x62\x1c\x3a\x94\x4e\x55"
+ "\x56\x75\xf7\x45\x6e\xa4\x9e\x94"
+ "\xb8\xfe\xda\xd4\xac\x7d\x76\xc5"
+ "\xb4\x65\xed\xb4\x49\x34\x71\x14"
+ "\xdb\x8f\x10\x90\xa3\x05\x02\xdc"
+ "\x86\x92\x6c\xbe\x9b\x57\x32\xe3"
+ "\x2c",
+ 65 },
+ 0,
+ },
+ { 0 }
+ };
+
+ for (int i = 0; test_data[i].curve != 0; i++) {
+ gnutls_datum_t x, y, key;
+
+ if (test_data[i].key.data == NULL) {
+ genkey(test_data[i].curve, &x, &y, &key);
+ } else {
+ x = test_data[i].x;
+ y = test_data[i].y;
+ key = test_data[i].key;
+ }
+
+ compute_key(test_data[i].curve, &x, &y, &key,
+ &test_data[i].peer_x, &test_data[i].peer_y,
+ test_data[i].expected_error, NULL, 0);
+
+ if (test_data[i].key.data == NULL) {
+ gnutls_free(x.data);
+ gnutls_free(y.data);
+ gnutls_free(key.data);
+ }
+ }
+
+ success("all ok\n");
+}
--- /dev/null
+/*
+ * Copyright (C) 2023 Red Hat, Inc.
+ *
+ * Author: Daiki Ueno
+ *
+ * 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 Lesser General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
+ */
+
+#include "config.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/abstract.h>
+#include <stdint.h>
+
+#include "utils.h"
+
+/* Test vector from RFC7748, section 6.2 */
+static uint8_t alice_priv[] = {
+ 0x9a, 0x8f, 0x49, 0x25, 0xd1, 0x51, 0x9f, 0x57, 0x75, 0xcf, 0x46, 0xb0,
+ 0x4b, 0x58, 0x00, 0xd4, 0xee, 0x9e, 0xe8, 0xba, 0xe8, 0xbc, 0x55, 0x65,
+ 0xd4, 0x98, 0xc2, 0x8d, 0xd9, 0xc9, 0xba, 0xf5, 0x74, 0xa9, 0x41, 0x97,
+ 0x44, 0x89, 0x73, 0x91, 0x00, 0x63, 0x82, 0xa6, 0xf1, 0x27, 0xab, 0x1d,
+ 0x9a, 0xc2, 0xd8, 0xc0, 0xa5, 0x98, 0x72, 0x6b,
+};
+static uint8_t alice_pub[] = {
+ 0x9b, 0x08, 0xf7, 0xcc, 0x31, 0xb7, 0xe3, 0xe6, 0x7d, 0x22, 0xd5, 0xae,
+ 0xa1, 0x21, 0x07, 0x4a, 0x27, 0x3b, 0xd2, 0xb8, 0x3d, 0xe0, 0x9c, 0x63,
+ 0xfa, 0xa7, 0x3d, 0x2c, 0x22, 0xc5, 0xd9, 0xbb, 0xc8, 0x36, 0x64, 0x72,
+ 0x41, 0xd9, 0x53, 0xd4, 0x0c, 0x5b, 0x12, 0xda, 0x88, 0x12, 0x0d, 0x53,
+ 0x17, 0x7f, 0x80, 0xe5, 0x32, 0xc4, 0x1f, 0xa0,
+};
+#if 0
+static uint8_t bob_priv[] = {
+ 0x1c, 0x30, 0x6a, 0x7a, 0xc2, 0xa0, 0xe2, 0xe0, 0x99, 0x0b, 0x29, 0x44, 0x70, 0xcb, 0xa3, 0x39, 0xe6, 0x45, 0x37, 0x72, 0xb0, 0x75, 0x81, 0x1d, 0x8f, 0xad, 0x0d, 0x1d,
+ 0x69, 0x27, 0xc1, 0x20, 0xbb, 0x5e, 0xe8, 0x97, 0x2b, 0x0d, 0x3e, 0x21, 0x37, 0x4c, 0x9c, 0x92, 0x1b, 0x09, 0xd1, 0xb0, 0x36, 0x6f, 0x10, 0xb6, 0x51, 0x73, 0x99, 0x2d,
+};
+#endif
+static uint8_t bob_pub[] = {
+ 0x3e, 0xb7, 0xa8, 0x29, 0xb0, 0xcd, 0x20, 0xf5, 0xbc, 0xfc, 0x0b, 0x59,
+ 0x9b, 0x6f, 0xec, 0xcf, 0x6d, 0xa4, 0x62, 0x71, 0x07, 0xbd, 0xb0, 0xd4,
+ 0xf3, 0x45, 0xb4, 0x30, 0x27, 0xd8, 0xb9, 0x72, 0xfc, 0x3e, 0x34, 0xfb,
+ 0x42, 0x32, 0xa1, 0x3c, 0xa7, 0x06, 0xdc, 0xb5, 0x7a, 0xec, 0x3d, 0xae,
+ 0x07, 0xbd, 0xc1, 0xc6, 0x7b, 0xf3, 0x36, 0x09,
+};
+static uint8_t secret_expected[] = {
+ 0x07, 0xff, 0xf4, 0x18, 0x1a, 0xc6, 0xcc, 0x95, 0xec, 0x1c, 0x16, 0xa9,
+ 0x4a, 0x0f, 0x74, 0xd1, 0x2d, 0xa2, 0x32, 0xce, 0x40, 0xa7, 0x75, 0x52,
+ 0x28, 0x1d, 0x28, 0x2b, 0xb6, 0x0c, 0x0b, 0x56, 0xfd, 0x24, 0x64, 0xc3,
+ 0x35, 0x54, 0x39, 0x36, 0x52, 0x1c, 0x24, 0x40, 0x30, 0x85, 0xd5, 0x9a,
+ 0x44, 0x9a, 0x50, 0x37, 0x51, 0x4a, 0x87, 0x9d,
+};
+
+void doit(void)
+{
+ gnutls_privkey_t privkey;
+ gnutls_pubkey_t pubkey;
+ gnutls_datum_t x, y, k;
+ gnutls_datum_t secret = { NULL, 0 };
+ int ret;
+
+ ret = gnutls_privkey_init(&privkey);
+ if (ret < 0) {
+ fail("unable to init privkey: %s\n", gnutls_strerror(ret));
+ }
+ x.data = alice_pub;
+ x.size = sizeof(alice_pub);
+ k.data = alice_priv;
+ k.size = sizeof(alice_priv);
+ ret = gnutls_privkey_import_ecc_raw(privkey, GNUTLS_ECC_CURVE_X448, &x,
+ NULL, &k);
+ if (ret < 0) {
+ fail("unable to import privkey: %s\n", gnutls_strerror(ret));
+ }
+
+ ret = gnutls_pubkey_init(&pubkey);
+ if (ret < 0) {
+ fail("unable to init pubkey: %s\n", gnutls_strerror(ret));
+ }
+ y.data = bob_pub;
+ y.size = sizeof(bob_pub);
+ ret = gnutls_pubkey_import_ecc_raw(pubkey, GNUTLS_ECC_CURVE_X448, &y,
+ NULL);
+ if (ret < 0) {
+ fail("unable to import pubkey: %s\n", gnutls_strerror(ret));
+ }
+
+ ret = gnutls_privkey_derive_secret(privkey, pubkey, NULL, &secret, 0);
+ if (ret < 0) {
+ fail("unable to derive secret: %s\n", gnutls_strerror(ret));
+ }
+
+ if (secret.size != sizeof(secret_expected) ||
+ gnutls_memcmp(secret.data, secret_expected, secret.size)) {
+ fail("derived secret is incorrect\n");
+ }
+
+ gnutls_pubkey_deinit(pubkey);
+ gnutls_privkey_deinit(privkey);
+ gnutls_free(secret.data);
+}