From 1f3cfad66456dd6f2e48f20b8eb0c51343449a1c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 11 Apr 2013 20:27:46 +0200 Subject: Add gcry_pubkey_get_sexp. * src/gcrypt.h.in (GCRY_PK_GET_PUBKEY): New. (GCRY_PK_GET_SECKEY): New. (gcry_pubkey_get_sexp): New. * src/visibility.c (gcry_pubkey_get_sexp): New. * src/visibility.h (gcry_pubkey_get_sexp): Mark visible. * src/libgcrypt.def, src/libgcrypt.vers: Add new function. * cipher/pubkey-internal.h: New. * cipher/Makefile.am (libcipher_la_SOURCES): Add new file. * cipher/ecc.c: Include pubkey-internal.h (_gcry_pk_ecc_get_sexp): New. * cipher/pubkey.c: Include pubkey-internal.h and context.h. (_gcry_pubkey_get_sexp): New. * src/context.c (_gcry_ctx_find_pointer): New. * src/cipher-proto.h: Add _gcry_pubkey_get_sexp. * tests/t-mpi-point.c (print_sexp): New. (context_param, basic_ec_math_simplified): Add tests for the new function. * configure.ac (NEED_GPG_ERROR_VERSION): Set to 1.11. (AH_BOTTOM) Add error codes from gpg-error 1.12 * src/g10lib.h (fips_not_operational): Use GPG_ERR_NOT_OPERATIONAL. * mpi/ec.c (_gcry_mpi_ec_get_mpi): Fix computation of Q. (_gcry_mpi_ec_get_point): Ditto. -- While checking the new code I figured that the auto-computation of Q must have led to a segv. It seems we had no test case for that. Signed-off-by: Werner Koch --- NEWS | 4 +- cipher/Makefile.am | 3 +- cipher/ecc.c | 74 +++++++++++++++++++++++++++++++++ cipher/pubkey-internal.h | 29 +++++++++++++ cipher/pubkey.c | 45 ++++++++++++++++++++ configure.ac | 16 +++++--- doc/gcrypt.texi | 44 ++++++++++++++++++++ mpi/ec.c | 10 ++++- src/cipher-proto.h | 6 +++ src/context.c | 19 +++++++++ src/context.h | 1 + src/g10lib.h | 2 +- src/gcrypt.h.in | 7 ++++ src/libgcrypt.def | 2 + src/libgcrypt.vers | 2 + src/visibility.c | 11 +++++ src/visibility.h | 1 + tests/t-mpi-point.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++- 18 files changed, 367 insertions(+), 13 deletions(-) create mode 100644 cipher/pubkey-internal.h diff --git a/NEWS b/NEWS index 926e531e..c4f89c17 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,8 @@ Noteworthy changes in version 1.6.0 (unreleased) ------------------------------------------------ * Removed the long deprecated gcry_ac interface. Thus Libgcrypt is - not anymore ABI compatible too previous versions. + not anymore ABI compatible to previous versions if they used the ac + interface. * Removed the module register subsystem. @@ -61,6 +62,7 @@ Noteworthy changes in version 1.6.0 (unreleased) GCRYMPI_FLAG_CONST NEW. GCRYPT_VERSION_NUMBER NEW. GCRY_KDF_SCRYPT NEW. + gcry_pubkey_get_sexp NEW. Noteworthy changes in version 1.5.0 (2011-06-29) diff --git a/cipher/Makefile.am b/cipher/Makefile.am index 51897949..396e5a2a 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -40,7 +40,8 @@ libcipher_la_LIBADD = $(GCRYPT_MODULES) libcipher_la_SOURCES = \ cipher.c cipher-internal.h \ cipher-cbc.c cipher-cfb.c cipher-ofb.c cipher-ctr.c cipher-aeswrap.c \ -pubkey.c md.c \ +pubkey.c pubkey-internal.h \ +md.c \ kdf.c kdf-internal.h \ hmac-tests.c \ bithelp.h \ diff --git a/cipher/ecc.c b/cipher/ecc.c index fbd8c6a3..34ed2c38 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -66,6 +66,7 @@ #include "cipher.h" #include "context.h" #include "ec-context.h" +#include "pubkey-internal.h" /* Definition of a curve. */ typedef struct @@ -1985,6 +1986,79 @@ _gcry_mpi_ec_new (gcry_ctx_t *r_ctx, } +/* This is the wroker function for gcry_pubkey_get_sexp for ECC + algorithms. Note that the caller has already stored NULL at + R_SEXP. */ +gpg_err_code_t +_gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec) +{ + gpg_err_code_t rc; + gcry_mpi_t mpi_G = NULL; + gcry_mpi_t mpi_Q = NULL; + + if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n) + return GPG_ERR_BAD_CRYPT_CTX; + + if (mode == GCRY_PK_GET_SECKEY && !ec->d) + return GPG_ERR_NO_SECKEY; + + /* Compute the public point if it is missing. */ + if (!ec->Q && ec->d) + { + ec->Q = gcry_mpi_point_new (0); + _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec); + } + + /* Encode G and Q. */ + mpi_G = _gcry_mpi_ec_ec2os (ec->G, ec); + if (!mpi_G) + { + rc = GPG_ERR_BROKEN_PUBKEY; + goto leave; + } + if (!ec->Q) + { + rc = GPG_ERR_BAD_CRYPT_CTX; + goto leave; + } + mpi_Q = _gcry_mpi_ec_ec2os (ec->Q, ec); + if (!mpi_Q) + { + rc = GPG_ERR_BROKEN_PUBKEY; + goto leave; + } + + /* Fixme: We should return a curve name instead of the parameters if + if know that they match a curve. */ + + if (ec->d && (!mode || mode == GCRY_PK_GET_SECKEY)) + { + /* Let's return a private key. */ + rc = gpg_err_code + (gcry_sexp_build + (r_sexp, NULL, + "(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))", + ec->p, ec->a, ec->b, mpi_G, ec->n, mpi_Q, ec->d)); + } + else if (ec->Q) + { + /* Let's return a public key. */ + rc = gpg_err_code + (gcry_sexp_build + (r_sexp, NULL, + "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))", + ec->p, ec->a, ec->b, mpi_G, ec->n, mpi_Q)); + } + else + rc = GPG_ERR_BAD_CRYPT_CTX; + + leave: + mpi_free (mpi_Q); + mpi_free (mpi_G); + return rc; +} + + /* Self-test section. diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h new file mode 100644 index 00000000..0ca17a50 --- /dev/null +++ b/cipher/pubkey-internal.h @@ -0,0 +1,29 @@ +/* pubkey-internal.h - Internal defs for pubkey.c + * Copyright (C) 2013 g10 code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser 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 . + */ + +#ifndef GCRY_PUBKEY_INTERNAL_H +#define GCRY_PUBKEY_INTERNAL_H + + +/*-- ecc.c --*/ +gpg_err_code_t _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, + mpi_ec_t ec); + + +#endif /*GCRY_PUBKEY_INTERNAL_H*/ diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 8b6356f8..00317b5b 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -1,6 +1,7 @@ /* pubkey.c - pubkey dispatcher * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005, * 2007, 2008, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * @@ -28,6 +29,8 @@ #include "mpi.h" #include "cipher.h" #include "ath.h" +#include "context.h" +#include "pubkey-internal.h" static gcry_err_code_t pubkey_decrypt (int algo, gcry_mpi_t *result, @@ -4068,6 +4071,48 @@ gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes) } +/* Return an S-expression representing the context CTX. Depending on + the state of that context, the S-expression may either be a public + key, a private key or any other object used with public key + operations. On success a new S-expression is stored at R_SEXP and + 0 is returned, on error NULL is store there and an error code is + returned. MODE is either 0 or one of the GCRY_PK_GET_xxx values. + + As of now it only support certain ECC operations because a context + object is right now only defined for ECC. Over time this function + will be extended to cover more algorithms. Note also that the name + of the function is gcry_pubkey_xxx and not gcry_pk_xxx. The idea + is that we will eventually provide variants of the existing + gcry_pk_xxx functions which will take a context parameter. */ +gcry_err_code_t +_gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp, int mode, gcry_ctx_t ctx) +{ + mpi_ec_t ec; + + if (!r_sexp) + return GPG_ERR_INV_VALUE; + *r_sexp = NULL; + switch (mode) + { + case 0: + case GCRY_PK_GET_PUBKEY: + case GCRY_PK_GET_SECKEY: + break; + default: + return GPG_ERR_INV_VALUE; + } + if (!ctx) + return GPG_ERR_NO_CRYPT_CTX; + + ec = _gcry_ctx_find_pointer (ctx, CONTEXT_TYPE_EC); + if (ec) + return _gcry_pk_ecc_get_sexp (r_sexp, mode, ec); + + return GPG_ERR_WRONG_CRYPT_CTX; +} + + + /* Explicitly initialize this module. */ gcry_err_code_t _gcry_pk_init (void) diff --git a/configure.ac b/configure.ac index c5973896..079951db 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # Configure.ac script for Libgcrypt # Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, # 2007, 2008, 2009, 2011 Free Software Foundation, Inc. -# Copyright (C) 2012 g10 Code GmbH +# Copyright (C) 2012, 2013 g10 Code GmbH # # This file is part of Libgcrypt. # @@ -65,7 +65,7 @@ LIBGCRYPT_LT_REVISION=0 # If the API is changed in an incompatible way: increment the next counter. LIBGCRYPT_CONFIG_API_VERSION=1 -NEED_GPG_ERROR_VERSION=1.8 +NEED_GPG_ERROR_VERSION=1.11 PACKAGE=$PACKAGE_NAME VERSION=$PACKAGE_VERSION @@ -105,10 +105,14 @@ AH_BOTTOM([ properly prefixed. */ #define CAMELLIA_EXT_SYM_PREFIX _gcry_ -/* This error code is only available with gpg-error 1.7. Thus - we define it here with the usual gcry prefix. */ -#define GCRY_GPG_ERR_NOT_OPERATIONAL 176 - +/* These error codes are used but not defined in the required + libgpg-error 1.11. Define them here. */ +#define GPG_ERR_NO_CRYPT_CTX 191 +#define GPG_ERR_WRONG_CRYPT_CTX 192 +#define GPG_ERR_BAD_CRYPT_CTX 193 +#define GPG_ERR_CRYPT_CTX_CONFLICT 194 +#define GPG_ERR_BROKEN_PUBKEY 195 +#define GPG_ERR_BROKEN_SECKEY 196 #endif /*_GCRYPT_CONFIG_H_INCLUDED*/ ]) diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 888a7408..5d9bd2fc 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -2722,6 +2722,50 @@ algorithm provides them. @end deftypefun @c end gcry_pk_genkey + +@noindent +Future versions of Libgcrypt will have extended versions of the public +key interfaced which will take an additional context to allow for +pre-computations, special operations, and other optimization. As a +first step a new function is introduced to help using the ECC +algorithms in new ways: + +@deftypefun gcry_error_t gcry_pubkey_get_sexp (@w{gcry_sexp_t *@var{r_sexp}}, @ + w{int @var{mode}}, @w{gcry_ctx_t @var{ctx}}) + +Return an S-expression representing the context @var{ctx}. Depending +on the state of that context, the S-expression may either be a public +key, a private key or any other object used with public key +operations. On success 0 is returned and a new S-expression is stored +at @var{r_sexp}; on error an error code is returned and NULL is stored +at @var{r_sexp}. @var{mode} must be one of: + +@table @code +@item 0 +Decide what to return depending on the context. For example if the +private key parameter is available a private key is returned, if not a +public key is returned. + +@item GCRY_PK_GET_PUBKEY +Return the public key even if the context has the private key +parameter. + +@item GCRY_PK_GET_SECKEY +Return the private key or the error @code{GPG_ERR_NO_SECKEY} if it is +not possible. +@end table + +As of now this function supports only certain ECC operations because a +context object is right now only defined for ECC. Over time this +function will be extended to cover more algorithms. + +@end deftypefun +@c end gcry_pubkey_get_sexp + + + + + @c ********************************************************** @c ******************* Hash Functions ********************* @c ********************************************************** diff --git a/mpi/ec.c b/mpi/ec.c index cd19c81a..c7367069 100644 --- a/mpi/ec.c +++ b/mpi/ec.c @@ -546,7 +546,10 @@ _gcry_mpi_ec_get_mpi (const char *name, gcry_ctx_t ctx, int copy) { /* If only the private key is given, compute the public key. */ if (!ec->Q && ec->d && ec->G && ec->p && ec->a) - _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec); + { + ec->Q = gcry_mpi_point_new (0); + _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec); + } if (ec->Q) return _gcry_mpi_ec_ec2os (ec->Q, ec); @@ -569,7 +572,10 @@ _gcry_mpi_ec_get_point (const char *name, gcry_ctx_t ctx, int copy) { /* If only the private key is given, compute the public key. */ if (!ec->Q && ec->d && ec->G && ec->p && ec->a) - _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec); + { + ec->Q = gcry_mpi_point_new (0); + _gcry_mpi_ec_mul_point (ec->Q, ec->d, ec->G, ec); + } if (ec->Q) return point_copy (ec->Q); diff --git a/src/cipher-proto.h b/src/cipher-proto.h index 347681ff..e2f913df 100644 --- a/src/cipher-proto.h +++ b/src/cipher-proto.h @@ -121,4 +121,10 @@ gcry_error_t _gcry_hmac_selftest (int algo, int extended, gcry_error_t _gcry_random_selftest (selftest_report_func_t report); + +/*-- pubkey.c --*/ +gcry_err_code_t _gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp, + int reserved, gcry_ctx_t ctx); + + #endif /*G10_CIPHER_PROTO_H*/ diff --git a/src/context.c b/src/context.c index 2c02c9c4..1b8090de 100644 --- a/src/context.c +++ b/src/context.c @@ -94,6 +94,25 @@ _gcry_ctx_get_pointer (gcry_ctx_t ctx, int type) return &ctx->u; } +/* Return a pointer to the private part of the context CTX. TYPE is + the requested context type. Using an explicit type allows to cross + check the type and eventually allows to store several private + contexts in one context object. In contrast to + _gcry_ctx_get_pointer, this function returns NULL if no context for + the given type was found. If CTX is NULL the function does not + abort but returns NULL. */ +void * +_gcry_ctx_find_pointer (gcry_ctx_t ctx, int type) +{ + if (!ctx) + return NULL; + if (memcmp (ctx->magic, CTX_MAGIC, CTX_MAGIC_LEN)) + log_fatal ("bad pointer %p passed to _gcry_ctx_get_pointer\n", ctx); + if (ctx->type != type) + return NULL; + return &ctx->u; +} + /* Release the generic context CTX. */ void diff --git a/src/context.h b/src/context.h index 72f14d48..875de243 100644 --- a/src/context.h +++ b/src/context.h @@ -26,6 +26,7 @@ gcry_ctx_t _gcry_ctx_alloc (int type, size_t length, void (*deinit)(void*)); void *_gcry_ctx_get_pointer (gcry_ctx_t ctx, int type); +void *_gcry_ctx_find_pointer (gcry_ctx_t ctx, int type); #endif /*GCRY_CONTEXT_H*/ diff --git a/src/g10lib.h b/src/g10lib.h index d1bcfa9a..23ea0960 100644 --- a/src/g10lib.h +++ b/src/g10lib.h @@ -394,7 +394,7 @@ void _gcry_fips_signal_error (const char *srcfile, int _gcry_fips_is_operational (void); #define fips_is_operational() (_gcry_global_is_operational ()) -#define fips_not_operational() (GCRY_GPG_ERR_NOT_OPERATIONAL) +#define fips_not_operational() (GPG_ERR_NOT_OPERATIONAL) int _gcry_fips_test_operational (void); int _gcry_fips_test_error_or_operational (void); diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 72fb6d33..85213ea4 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -944,6 +944,10 @@ enum gcry_pk_algos #define GCRY_PK_USAGE_AUTH 8 /* Good for authentication. */ #define GCRY_PK_USAGE_UNKN 128 /* Unknown usage flag. */ +/* Modes used with gcry_pubkey_get_sexp. */ +#define GCRY_PK_GET_PUBKEY 1 +#define GCRY_PK_GET_SECKEY 2 + /* Encrypt the DATA using the public key PKEY and store the result as a newly created S-expression at RESULT. */ gcry_error_t gcry_pk_encrypt (gcry_sexp_t *result, @@ -1007,6 +1011,9 @@ gcry_sexp_t gcry_pk_get_param (int algo, const char *name); #define gcry_pk_test_algo(a) \ gcry_pk_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL ) +/* Return an S-expression representing the context CTX. */ +gcry_error_t gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp, + int mode, gcry_ctx_t ctx); diff --git a/src/libgcrypt.def b/src/libgcrypt.def index 061c7e36..4da46232 100644 --- a/src/libgcrypt.def +++ b/src/libgcrypt.def @@ -232,3 +232,5 @@ EXPORTS gcry_mpi_ec_dup @209 gcry_mpi_ec_add @210 gcry_mpi_ec_mul @211 + + gcry_pubkey_get_sexp @212 diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers index 65959d36..29e46dbe 100644 --- a/src/libgcrypt.vers +++ b/src/libgcrypt.vers @@ -58,6 +58,8 @@ GCRYPT_1.6 { gcry_pk_testkey; gcry_pk_verify; gcry_pk_get_curve; gcry_pk_get_param; + gcry_pubkey_get_sexp; + gcry_kdf_derive; gcry_prime_check; gcry_prime_generate; diff --git a/src/visibility.c b/src/visibility.c index ed68b860..b503be66 100644 --- a/src/visibility.c +++ b/src/visibility.c @@ -861,6 +861,17 @@ gcry_pk_get_param (int algo, const char *name) return _gcry_pk_get_param (algo, name); } +gcry_error_t +gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp, int mode, gcry_ctx_t ctx) +{ + if (!fips_is_operational ()) + { + *r_sexp = NULL; + return gpg_error (fips_not_operational ()); + } + return gpg_error (_gcry_pubkey_get_sexp (r_sexp, mode, ctx)); +} + gcry_error_t gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags) { diff --git a/src/visibility.h b/src/visibility.h index 031537a1..1564e865 100644 --- a/src/visibility.h +++ b/src/visibility.h @@ -494,6 +494,7 @@ MARK_VISIBLE (gcry_pk_map_name) MARK_VISIBLE (gcry_pk_sign) MARK_VISIBLE (gcry_pk_testkey) MARK_VISIBLE (gcry_pk_verify) +MARK_VISIBLEX(gcry_pubkey_get_sexp) MARK_VISIBLE (gcry_kdf_derive) diff --git a/tests/t-mpi-point.c b/tests/t-mpi-point.c index a3b6c569..9f7360e2 100644 --- a/tests/t-mpi-point.c +++ b/tests/t-mpi-point.c @@ -216,6 +216,23 @@ print_point (const char *text, gcry_mpi_point_t a) } +static void +print_sexp (const char *prefix, gcry_sexp_t a) +{ + char *buf; + size_t size; + + if (prefix) + fputs (prefix, stderr); + size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); + buf = gcry_xmalloc (size); + + gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); + fprintf (stderr, "%.*s", (int)size, buf); + gcry_free (buf); +} + + static gcry_mpi_t hex2mpi (const char *string) { @@ -500,9 +517,34 @@ context_param (void) gpg_strerror (err)); else { + gcry_sexp_t sexp; + get_and_cmp_mpi ("q", sample_p256_q, "NIST P-256", ctx); get_and_cmp_point ("q", sample_p256_q_x, sample_p256_q_y, "NIST P-256", ctx); + + err = gcry_pubkey_get_sexp (&sexp, 0, ctx); + if (err) + fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err)); + else if (debug) + print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp); + gcry_sexp_release (sexp); + + err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx); + if (err) + fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n", + gpg_strerror (err)); + else if (debug) + print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp); + gcry_sexp_release (sexp); + + err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx); + if (gpg_err_code (err) != GPG_ERR_NO_SECKEY) + fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n", + gpg_strerror (err)); + gcry_sexp_release (sexp); + + gcry_ctx_release (ctx); } gcry_sexp_release (keyparam); @@ -537,7 +579,7 @@ basic_ec_math (void) gcry_mpi_t d; gcry_mpi_t x, y, z; - wherestr = "set_get_point"; + wherestr = "basic_ec_math"; show ("checking basic math functions for EC\n"); P = hex2mpi ("0xfffffffffffffffffffffffffffffffeffffffffffffffff"); @@ -600,8 +642,9 @@ basic_ec_math_simplified (void) gcry_mpi_point_t G, Q; gcry_mpi_t d; gcry_mpi_t x, y, z; + gcry_sexp_t sexp; - wherestr = "set_get_point"; + wherestr = "basic_ec_math_simplified"; show ("checking basic math functions for EC (variant)\n"); d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D"); @@ -644,6 +687,63 @@ basic_ec_math_simplified (void) gcry_mpi_release (z); gcry_mpi_release (y); gcry_mpi_release (x); + + /* Let us also check wheer we can update the context. */ + err = gcry_mpi_ec_set_point ("g", G, ctx); + if (err) + die ("gcry_mpi_ec_set_point(G) failed\n"); + err = gcry_mpi_ec_set_mpi ("d", d, ctx); + if (err) + die ("gcry_mpi_ec_set_mpi(d) failed\n"); + + /* FIXME: Below we need to check that the returned S-expression is + as requested. For now we use manual inspection using --debug. */ + + /* Does get_sexp return the private key? */ + err = gcry_pubkey_get_sexp (&sexp, 0, ctx); + if (err) + fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err)); + else if (verbose) + print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp); + gcry_sexp_release (sexp); + + /* Does get_sexp return the public key if requested? */ + err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx); + if (err) + fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n", gpg_strerror (err)); + else if (verbose) + print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp); + gcry_sexp_release (sexp); + + /* Does get_sexp return the public key if after d has been deleted? */ + err = gcry_mpi_ec_set_mpi ("d", NULL, ctx); + if (err) + die ("gcry_mpi_ec_set_mpi(d=NULL) failed\n"); + err = gcry_pubkey_get_sexp (&sexp, 0, ctx); + if (err) + fail ("gcry_pubkey_get_sexp(0 w/o d) failed: %s\n", gpg_strerror (err)); + else if (verbose) + print_sexp ("Result of gcry_pubkey_get_sexp (0 w/o d):\n", sexp); + gcry_sexp_release (sexp); + + /* Does get_sexp return an error after d has been deleted? */ + err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx); + if (gpg_err_code (err) != GPG_ERR_NO_SECKEY) + fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n", + gpg_strerror (err)); + gcry_sexp_release (sexp); + + /* Does get_sexp return an error after d and Q have been deleted? */ + err = gcry_mpi_ec_set_point ("q", NULL, ctx); + if (err) + die ("gcry_mpi_ec_set_point(q=NULL) failed\n"); + err = gcry_pubkey_get_sexp (&sexp, 0, ctx); + if (gpg_err_code (err) != GPG_ERR_BAD_CRYPT_CTX) + fail ("gcry_pubkey_get_sexp(0 w/o Q,d) returned wrong error: %s\n", + gpg_strerror (err)); + gcry_sexp_release (sexp); + + gcry_mpi_point_release (Q); gcry_mpi_release (d); gcry_mpi_point_release (G); -- cgit v1.2.1