diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 8b647d94..29ee30c1 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -1,271 +1,271 @@
# Makefile for cipher modules
# Copyright (C) 1998, 1999, 2000, 2001, 2002,
# 2003, 2009 Free Software Foundation, Inc.
#
# 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 .
# Process this file with automake to produce Makefile.in
# Need to include ../src in addition to top_srcdir because gcrypt.h is
# a built header.
AM_CPPFLAGS = -I../src -I$(top_srcdir)/src -I../mpi -I$(top_srcdir)/mpi
AM_CFLAGS = $(GPG_ERROR_CFLAGS)
AM_CCASFLAGS = $(NOEXECSTACK_FLAGS)
EXTRA_DIST = gost-s-box.c
CLEANFILES = gost-s-box
DISTCLEANFILES = gost-sb.h
noinst_LTLIBRARIES = libcipher.la
GCRYPT_MODULES = @GCRYPT_CIPHERS@ @GCRYPT_PUBKEY_CIPHERS@ \
@GCRYPT_DIGESTS@ @GCRYPT_KDFS@
libcipher_la_DEPENDENCIES = $(GCRYPT_MODULES)
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 \
cipher-ccm.c \
cipher-cmac.c \
cipher-gcm.c \
cipher-poly1305.c \
cipher-ocb.c \
cipher-xts.c \
cipher-eax.c \
cipher-siv.c \
cipher-gcm-siv.c \
cipher-selftest.c cipher-selftest.h \
pubkey.c pubkey-internal.h pubkey-util.c \
pkey.c pkey-internal.h \
- pkey-ed25519.c pkey-ed448.c pkey-rsa.c pkey-dsa.c \
+ pkey-ed25519.c pkey-ed448.c pkey-rsa.c pkey-dsa.c pkey-ecc-nist.c \
md.c \
mac.c mac-internal.h \
mac-hmac.c mac-cmac.c mac-gmac.c mac-poly1305.c \
poly1305.c poly1305-internal.h \
poly1305-s390x.S \
kdf.c kdf-internal.h \
bithelp.h \
bufhelp.h \
primegen.c \
hash-common.c hash-common.h \
dsa-common.c rsa-common.c \
sha1.h
EXTRA_libcipher_la_SOURCES = \
asm-common-aarch64.h \
asm-common-amd64.h \
asm-common-s390x.h \
asm-inline-s390x.h \
asm-poly1305-aarch64.h \
asm-poly1305-amd64.h \
asm-poly1305-s390x.h \
arcfour.c arcfour-amd64.S \
blowfish.c blowfish-amd64.S blowfish-arm.S \
cast5.c cast5-amd64.S cast5-arm.S \
chacha20.c chacha20-amd64-ssse3.S chacha20-amd64-avx2.S \
chacha20-armv7-neon.S chacha20-aarch64.S \
chacha20-ppc.c chacha20-s390x.S \
cipher-gcm-ppc.c cipher-gcm-intel-pclmul.c cipher-gcm-armv7-neon.S \
cipher-gcm-armv8-aarch32-ce.S cipher-gcm-armv8-aarch64-ce.S \
crc.c crc-intel-pclmul.c crc-armv8-ce.c \
crc-armv8-aarch64-ce.S \
crc-ppc.c \
des.c des-amd64.S \
dsa.c \
elgamal.c \
ecc.c ecc-curves.c ecc-misc.c ecc-common.h \
ecc-ecdh.c ecc-ecdsa.c ecc-eddsa.c ecc-gost.c ecc-sm2.c \
idea.c \
gost28147.c gost.h \
gostr3411-94.c \
md4.c \
md5.c \
rijndael.c rijndael-internal.h rijndael-tables.h \
rijndael-aesni.c rijndael-padlock.c \
rijndael-amd64.S rijndael-arm.S \
rijndael-ssse3-amd64.c rijndael-ssse3-amd64-asm.S \
rijndael-vaes.c rijndael-vaes-avx2-amd64.S \
rijndael-armv8-ce.c rijndael-armv8-aarch32-ce.S \
rijndael-armv8-aarch64-ce.S rijndael-aarch64.S \
rijndael-ppc.c rijndael-ppc9le.c \
rijndael-ppc-common.h rijndael-ppc-functions.h \
rijndael-s390x.c \
rmd160.c \
rsa.c \
salsa20.c salsa20-amd64.S salsa20-armv7-neon.S \
scrypt.c \
seed.c \
serpent.c serpent-sse2-amd64.S \
sm4.c sm4-aesni-avx-amd64.S sm4-aesni-avx2-amd64.S \
serpent-avx2-amd64.S serpent-armv7-neon.S \
sha1.c sha1-ssse3-amd64.S sha1-avx-amd64.S sha1-avx-bmi2-amd64.S \
sha1-avx2-bmi2-amd64.S sha1-armv7-neon.S sha1-armv8-aarch32-ce.S \
sha1-armv8-aarch64-ce.S sha1-intel-shaext.c \
sha256.c sha256-ssse3-amd64.S sha256-avx-amd64.S \
sha256-avx2-bmi2-amd64.S \
sha256-armv8-aarch32-ce.S sha256-armv8-aarch64-ce.S \
sha256-intel-shaext.c sha256-ppc.c \
sha512.c sha512-ssse3-amd64.S sha512-avx-amd64.S \
sha512-avx2-bmi2-amd64.S \
sha512-armv7-neon.S sha512-arm.S \
sha512-ppc.c sha512-ssse3-i386.c \
sm3.c \
keccak.c keccak_permute_32.h keccak_permute_64.h keccak-armv7-neon.S \
stribog.c \
tiger.c \
whirlpool.c whirlpool-sse2-amd64.S \
twofish.c twofish-amd64.S twofish-arm.S twofish-aarch64.S \
twofish-avx2-amd64.S \
rfc2268.c \
camellia.c camellia.h camellia-glue.c camellia-aesni-avx-amd64.S \
camellia-aesni-avx2-amd64.h camellia-vaes-avx2-amd64.S \
camellia-aesni-avx2-amd64.S camellia-arm.S camellia-aarch64.S \
blake2.c \
blake2b-amd64-avx2.S blake2s-amd64-avx.S
gost28147.lo: gost-sb.h
gost-sb.h: gost-s-box
./gost-s-box $@
gost-s-box: gost-s-box.c
$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) \
$(CPPFLAGS_FOR_BUILD)-o $@ $(srcdir)/gost-s-box.c
if ENABLE_O_FLAG_MUNGING
o_flag_munging = sed -e 's/-O\([2-9sg][2-9sg]*\)/-O1/' -e 's/-Ofast/-O1/g'
else
o_flag_munging = cat
endif
# We need to lower the optimization for this module.
tiger.o: $(srcdir)/tiger.c Makefile
`echo $(COMPILE) -c $< | $(o_flag_munging) `
tiger.lo: $(srcdir)/tiger.c Makefile
`echo $(LTCOMPILE) -c $< | $(o_flag_munging) `
# We need to disable instrumentation for these modules as they use cc as
# thin assembly front-end and do not tolerate in-between function calls
# inserted by compiler as those functions may clobber the XMM registers.
if ENABLE_INSTRUMENTATION_MUNGING
instrumentation_munging = sed \
-e 's/-fsanitize[=,\-][=,a-z,A-Z,0-9,\,,\-]*//g' \
-e 's/-fprofile[=,\-][=,a-z,A-Z,0-9,\,,\-]*//g' \
-e 's/-fcoverage[=,\-][=,a-z,A-Z,0-9,\,,\-]*//g'
else
instrumentation_munging = cat
endif
rijndael-aesni.o: $(srcdir)/rijndael-aesni.c Makefile
`echo $(COMPILE) -c $< | $(instrumentation_munging) `
rijndael-aesni.lo: $(srcdir)/rijndael-aesni.c Makefile
`echo $(LTCOMPILE) -c $< | $(instrumentation_munging) `
rijndael-ssse3-amd64.o: $(srcdir)/rijndael-ssse3-amd64.c Makefile
`echo $(COMPILE) -c $< | $(instrumentation_munging) `
rijndael-ssse3-amd64.lo: $(srcdir)/rijndael-ssse3-amd64.c Makefile
`echo $(LTCOMPILE) -c $< | $(instrumentation_munging) `
cipher-gcm-intel-pclmul.o: $(srcdir)/cipher-gcm-intel-pclmul.c Makefile
`echo $(COMPILE) -c $< | $(instrumentation_munging) `
cipher-gcm-intel-pclmul.lo: $(srcdir)/cipher-gcm-intel-pclmul.c Makefile
`echo $(LTCOMPILE) -c $< | $(instrumentation_munging) `
sha1-intel-shaext.o: $(srcdir)/sha1-intel-shaext.c Makefile
`echo $(COMPILE) -c $< | $(instrumentation_munging) `
sha1-intel-shaext.lo: $(srcdir)/sha1-intel-shaext.c Makefile
`echo $(LTCOMPILE) -c $< | $(instrumentation_munging) `
sha256-intel-shaext.o: $(srcdir)/sha256-intel-shaext.c Makefile
`echo $(COMPILE) -c $< | $(instrumentation_munging) `
sha256-intel-shaext.lo: $(srcdir)/sha256-intel-shaext.c Makefile
`echo $(LTCOMPILE) -c $< | $(instrumentation_munging) `
sha256-ssse3-i386.o: $(srcdir)/sha256-ssse3-i386.c Makefile
`echo $(COMPILE) -c $< | $(instrumentation_munging) `
sha256-ssse3-i386.lo: $(srcdir)/sha256-ssse3-i386.c Makefile
`echo $(LTCOMPILE) -c $< | $(instrumentation_munging) `
crc-intel-pclmul.o: $(srcdir)/crc-intel-pclmul.c Makefile
`echo $(COMPILE) -c $< | $(instrumentation_munging) `
crc-intel-pclmul.lo: $(srcdir)/crc-intel-pclmul.c Makefile
`echo $(LTCOMPILE) -c $< | $(instrumentation_munging) `
if ENABLE_PPC_VCRYPTO_EXTRA_CFLAGS
ppc_vcrypto_cflags = -maltivec -mvsx -mcrypto
else
ppc_vcrypto_cflags =
endif
rijndael-ppc.o: $(srcdir)/rijndael-ppc.c Makefile
`echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
rijndael-ppc.lo: $(srcdir)/rijndael-ppc.c Makefile
`echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
rijndael-ppc9le.o: $(srcdir)/rijndael-ppc9le.c Makefile
`echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
rijndael-ppc9le.lo: $(srcdir)/rijndael-ppc9le.c Makefile
`echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
sha256-ppc.o: $(srcdir)/sha256-ppc.c Makefile
`echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
sha256-ppc.lo: $(srcdir)/sha256-ppc.c Makefile
`echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
sha512-ppc.o: $(srcdir)/sha512-ppc.c Makefile
`echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
sha512-ppc.lo: $(srcdir)/sha512-ppc.c Makefile
`echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
chacha20-ppc.o: $(srcdir)/chacha20-ppc.c Makefile
`echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
chacha20-ppc.lo: $(srcdir)/chacha20-ppc.c Makefile
`echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
crc-ppc.o: $(srcdir)/crc-ppc.c Makefile
`echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
crc-ppc.lo: $(srcdir)/crc-ppc.c Makefile
`echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
cipher-gcm-ppc.o: $(srcdir)/cipher-gcm-ppc.c Makefile
`echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
cipher-gcm-ppc.lo: $(srcdir)/cipher-gcm-ppc.c Makefile
`echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) `
diff --git a/cipher/pkey-ecc-nist.c b/cipher/pkey-ecc-nist.c
new file mode 100644
index 00000000..9011a15e
--- /dev/null
+++ b/cipher/pkey-ecc-nist.c
@@ -0,0 +1,220 @@
+/* pkey-ecc-nist.c - PKEY API implementation for NIST Curves
+ * Copyright (C) 2021 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 .
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "g10lib.h"
+#include "gcrypt-int.h"
+#include "pkey-internal.h"
+
+static const char *
+get_curve_name (int curve)
+{
+ switch (curve)
+ {
+ case GCRY_PKEY_CURVE_NIST_P224:
+ return "nistp224";
+ case GCRY_PKEY_CURVE_NIST_P256:
+ return "nistp256";
+ case GCRY_PKEY_CURVE_NIST_P384:
+ return "nistp384";
+ case GCRY_PKEY_CURVE_NIST_P521:
+ return "nistp521";
+ default:
+ return "unknown";
+ }
+}
+
+gcry_error_t
+_gcry_pkey_nist_sign (gcry_pkey_hd_t h,
+ int num_in, const unsigned char *const in[],
+ const size_t in_len[],
+ int num_out, unsigned char *out[], size_t out_len[])
+{
+ gcry_error_t err = 0;
+ gcry_sexp_t s_sk = NULL;
+ gcry_sexp_t s_msg= NULL;
+ gcry_sexp_t s_sig= NULL;
+ gcry_sexp_t s_tmp, s_tmp2;
+ const char *curve;
+ const char *md_name;
+
+ if (num_in != 2) /* For now, k should be specified by the caller. */
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ if (num_out != 2)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ curve = get_curve_name (h->ecc.curve);
+ if (h->ecc.pk)
+ err = sexp_build (&s_sk, NULL,
+ "(private-key"
+ " (ecc"
+ " (curve %s)"
+ " (q %b)"
+ " (d %b)))", curve,
+ (int)h->ecc.pk_len, h->ecc.pk,
+ (int)h->ecc.sk_len, h->ecc.sk);
+ else
+ err = sexp_build (&s_sk, NULL,
+ "(private-key"
+ " (ecc"
+ " (curve %s)"
+ " (d %b)))", curve,
+ (int)h->ecc.sk_len, h->ecc.sk);
+ if (err)
+ return err;
+
+ md_name = _gcry_md_algo_name (h->ecc.md_algo);
+
+ if ((h->flags & GCRY_PKEY_FLAG_PREHASH))
+ err = sexp_build (&s_msg, NULL,
+ "(data"
+ " (flags prehash)"
+ " (label %b)"
+ " (hash-algo %s)"
+ " (value %b))",
+ (int)in_len[1], in[1],
+ md_name, (int)in_len[0], in[0]);
+ else
+ err = sexp_build (&s_msg, NULL,
+ "(data "
+ " (label %b)"
+ " (value %b))", (int)in_len[1], in[1],
+ (int)in_len[0], in[0]);
+ if (err)
+ {
+ sexp_release (s_sk);
+ return err;
+ }
+
+ err = _gcry_pk_sign (&s_sig, s_msg, s_sk);
+ sexp_release (s_sk);
+ sexp_release (s_msg);
+ if (err)
+ return err;
+
+ out[0] = out[1] = NULL;
+ s_tmp2 = NULL;
+ s_tmp = sexp_find_token (s_sig, "sig-val", 0);
+ if (s_tmp)
+ {
+ s_tmp2 = s_tmp;
+ s_tmp = sexp_find_token (s_tmp2, "ecdsa", 0);
+ if (s_tmp)
+ {
+ sexp_release (s_tmp2);
+ s_tmp2 = s_tmp;
+ s_tmp = sexp_find_token (s_tmp2, "r", 0);
+ if (s_tmp)
+ {
+ out[0] = sexp_nth_buffer (s_tmp, 1, &out_len[0]);
+ sexp_release (s_tmp);
+ }
+ s_tmp = sexp_find_token (s_tmp2, "s", 0);
+ if (s_tmp)
+ {
+ out[1] = sexp_nth_buffer (s_tmp, 1, &out_len[1]);
+ sexp_release (s_tmp);
+ }
+ }
+ }
+ sexp_release (s_tmp2);
+
+ if (out[0] == NULL || out[1] == NULL)
+ err = gpg_error (GPG_ERR_BAD_SIGNATURE);
+
+ sexp_release (s_sig);
+
+ return err;
+}
+
+gcry_error_t
+_gcry_pkey_nist_verify (gcry_pkey_hd_t h,
+ int num_in, const unsigned char *const in[],
+ const size_t in_len[])
+{
+ gcry_error_t err = 0;
+ gcry_sexp_t s_pk = NULL;
+ gcry_sexp_t s_msg= NULL;
+ gcry_sexp_t s_sig= NULL;
+ const char *curve;
+ const char *md_name;
+
+ if (num_in != 4) /* For now, k should be specified by the caller. */
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ curve = get_curve_name (h->ecc.curve);
+ err = sexp_build (&s_pk, NULL,
+ "(public-key"
+ " (ecc"
+ " (curve %s)"
+ " (q %b)))", curve,
+ (int)h->ecc.pk_len, h->ecc.pk);
+ if (err)
+ return err;
+
+ md_name = _gcry_md_algo_name (h->ecc.md_algo);
+
+ if ((h->flags & GCRY_PKEY_FLAG_PREHASH))
+ err = sexp_build (&s_msg, NULL,
+ "(data"
+ " (flags prehash)"
+ " (label %b)"
+ " (hash-algo %s)"
+ " (value %b))",
+ (int)in_len[1], in[1],
+ md_name, (int)in_len[0], in[0]);
+ else
+ err = sexp_build (&s_msg, NULL,
+ "(data "
+ " (label %b)"
+ " (value %b))", (int)in_len[1], in[1],
+ (int)in_len[0], in[0]);
+ if (err)
+ {
+ sexp_release (s_pk);
+ return err;
+ }
+
+ err = sexp_build (&s_sig, NULL,
+ "(sig-val(ecdsa(r %b)(s %b)))",
+ (int)in_len[2], in[2],
+ (int)in_len[3], in[3]);
+ if (err)
+ {
+ sexp_release (s_msg);
+ sexp_release (s_pk);
+ return err;
+ }
+
+ err = _gcry_pk_verify (s_sig, s_msg, s_pk);
+
+ sexp_release (s_sig);
+ sexp_release (s_msg);
+ sexp_release (s_pk);
+
+ return err;
+}
diff --git a/cipher/pkey-internal.h b/cipher/pkey-internal.h
index 2f67ff67..d81fb72c 100644
--- a/cipher/pkey-internal.h
+++ b/cipher/pkey-internal.h
@@ -1,134 +1,145 @@
/* pkey-internal.h - Internal defs for pkey.c
* Copyright (C) 2021 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 .
* SPDX-License-Identifier: LGPL-2.1+
*/
gcry_error_t _gcry_pkey_ed25519_sign (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[],
int num_out, unsigned char *out[],
size_t out_len[]);
gcry_error_t _gcry_pkey_ed25519_verify (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[]);
gcry_error_t _gcry_pkey_ed448_sign (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[],
int num_out, unsigned char *out[],
size_t out_len[]);
gcry_error_t _gcry_pkey_ed448_verify (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[]);
gcry_error_t _gcry_pkey_rsapss_sign (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[],
int num_out, unsigned char *out[],
size_t out_len[]);
gcry_error_t _gcry_pkey_rsapss_verify (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[]);
gcry_error_t _gcry_pkey_rsa15_sign (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[],
int num_out, unsigned char *out[],
size_t out_len[]);
gcry_error_t _gcry_pkey_rsa15_verify (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[]);
gcry_error_t _gcry_pkey_rsa931_sign (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[],
int num_out, unsigned char *out[],
size_t out_len[]);
gcry_error_t _gcry_pkey_rsa931_verify (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[]);
gcry_error_t _gcry_pkey_dsa_sign (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[],
int num_out, unsigned char *out[],
size_t out_len[]);
gcry_error_t _gcry_pkey_dsa_verify (gcry_pkey_hd_t h,
int num_in, const unsigned char *const in[],
const size_t in_len[]);
+gcry_error_t _gcry_pkey_nist_sign (gcry_pkey_hd_t h,
+ int num_in, const unsigned char *const in[],
+ const size_t in_len[],
+ int num_out, unsigned char *out[],
+ size_t out_len[]);
+
+gcry_error_t _gcry_pkey_nist_verify (gcry_pkey_hd_t h, int num_in,
+ const unsigned char *const in[],
+ const size_t in_len[]);
+
+
struct pkey_ecc {
int curve;
+ int md_algo; /* Only used for NIST cuves. */
unsigned char *pk;
size_t pk_len;
unsigned char *sk;
size_t sk_len;
};
struct pkey_rsa {
int scheme;
-
int md_algo;
unsigned char *n;
size_t n_len;
unsigned char *e;
size_t e_len;
unsigned char *d;
size_t d_len;
};
struct pkey_dsa {
int md_algo;
unsigned char *p;
size_t p_len;
unsigned char *q;
size_t q_len;
unsigned char *g;
size_t g_len;
unsigned char *x; /* Private key. */
size_t x_len;
unsigned char *y; /* Public key. */
size_t y_len;
};
struct gcry_pkey_handle {
int algo;
unsigned int flags;
union {
struct pkey_ecc ecc;
struct pkey_rsa rsa;
struct pkey_dsa dsa;
};
};
diff --git a/cipher/pkey.c b/cipher/pkey.c
index 93e56e67..3fc69b2e 100644
--- a/cipher/pkey.c
+++ b/cipher/pkey.c
@@ -1,467 +1,508 @@
/* pkey.c - Pubric key cryptography API
* Copyright (C) 2021 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 .
* SPDX-License-Identifier: LGPL-2.1+
*/
#include
#include
#include
#include
#include
#include
#include "g10lib.h"
#include "gcrypt-int.h"
#include "pkey-internal.h"
gcry_error_t
_gcry_pkey_vopen (gcry_pkey_hd_t *h_p, int algo, unsigned int flags,
va_list arg_ptr)
{
gcry_error_t err = 0;
gcry_pkey_hd_t h;
if (algo == GCRY_PKEY_ECC || algo == GCRY_PKEY_RSA || algo == GCRY_PKEY_DSA)
;
else if (algo == GCRY_PKEY_ELG)
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
else
err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
if (err)
return err;
if (!(h = xtrycalloc (1, sizeof (struct gcry_pkey_handle))))
return gpg_error_from_syserror ();
h->algo = algo;
h->flags = flags;
if (algo == GCRY_PKEY_ECC)
{
int curve;
unsigned char *pk;
unsigned char *sk;
curve = va_arg (arg_ptr, int);
- if (curve == GCRY_PKEY_CURVE_ED25519)
- ;
- else if (curve == GCRY_PKEY_CURVE_ED448)
- ;
+ if (curve == GCRY_PKEY_CURVE_ED25519 || curve == GCRY_PKEY_CURVE_ED448)
+ h->ecc.md_algo = 0;
+ else if (curve == GCRY_PKEY_CURVE_NIST_P224
+ || curve == GCRY_PKEY_CURVE_NIST_P256
+ || curve == GCRY_PKEY_CURVE_NIST_P384
+ || curve == GCRY_PKEY_CURVE_NIST_P521)
+ h->ecc.md_algo = va_arg (arg_ptr, int);
else
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
if (err)
{
xfree (h);
return err;
}
h->ecc.curve = curve;
- pk = va_arg (arg_ptr, unsigned char *);
- h->ecc.pk_len = va_arg (arg_ptr, size_t);
+ if (h->ecc.md_algo)
+ { /* NIST curves */
+ unsigned char *x, *y;
+ size_t x_len, y_len;
+
+ x = va_arg (arg_ptr, unsigned char *);
+ x_len = va_arg (arg_ptr, size_t);
+ y = va_arg (arg_ptr, unsigned char *);
+ y_len = va_arg (arg_ptr, size_t);
+
+ if (x && y)
+ {
+ h->ecc.pk_len = 1 + x_len + y_len;
+ h->ecc.pk = xtrymalloc (h->ecc.pk_len);
+ if (!h->ecc.pk)
+ {
+ err = gpg_error_from_syserror ();
+ xfree (h);
+ return err;
+ }
+
+ h->ecc.pk[0] = 0x04;
+ memcpy (h->ecc.pk+1, x, x_len);
+ memcpy (h->ecc.pk+1+x_len, y, y_len);
+ }
+ else
+ h->ecc.pk = NULL;
+ }
+ else
+ { /* Modern curves */
+ pk = va_arg (arg_ptr, unsigned char *);
+ h->ecc.pk_len = va_arg (arg_ptr, size_t);
+
+ if (pk)
+ {
+ h->ecc.pk = xtrymalloc (h->ecc.pk_len);
+ if (!h->ecc.pk)
+ {
+ err = gpg_error_from_syserror ();
+ xfree (h);
+ return err;
+ }
+ memcpy (h->ecc.pk, pk, h->ecc.pk_len);
+ }
+ else
+ h->ecc.pk = NULL;
+ }
+
if (!(flags & GCRY_PKEY_FLAG_SECRET))
{
h->ecc.sk = sk = NULL;
h->ecc.sk_len = 0;
}
else
{
sk = va_arg (arg_ptr, unsigned char *);
h->ecc.sk_len = va_arg (arg_ptr, size_t);
}
- if (err)
- {
- xfree (h);
- return err;
- }
-
- if (pk)
- {
- h->ecc.pk = xtrymalloc (h->ecc.pk_len);
- if (!h->ecc.pk)
- {
- err = gpg_error_from_syserror ();
- xfree (h);
- return err;
- }
- memcpy (h->ecc.pk, pk, h->ecc.pk_len);
- }
- else
- h->ecc.pk = NULL;
-
if (sk)
{
h->ecc.sk = xtrymalloc_secure (h->ecc.sk_len);
if (!h->ecc.sk)
{
err = gpg_error_from_syserror ();
xfree (h->ecc.pk);
xfree (h);
return err;
}
memcpy (h->ecc.sk, sk, h->ecc.sk_len);
}
}
else if (algo == GCRY_PKEY_RSA)
{
int scheme;
int md_algo;
unsigned char *n;
unsigned char *e;
unsigned char *d;
scheme = va_arg (arg_ptr, int);
if (scheme == GCRY_PKEY_RSA_PSS)
;
else if (scheme == GCRY_PKEY_RSA_15)
;
else if (scheme == GCRY_PKEY_RSA_931)
;
else
err = gpg_error (GPG_ERR_INV_ARG);
if (err)
{
xfree (h);
return err;
}
h->rsa.scheme = scheme;
md_algo = va_arg (arg_ptr, int);
h->rsa.md_algo = md_algo;
n = va_arg (arg_ptr, unsigned char *);
h->rsa.n_len = va_arg (arg_ptr, size_t);
e = va_arg (arg_ptr, unsigned char *);
h->rsa.e_len = va_arg (arg_ptr, size_t);
if (!(flags & GCRY_PKEY_FLAG_SECRET))
{
h->rsa.d = d = NULL;
h->rsa.d_len = 0;
}
else
{
d = va_arg (arg_ptr, unsigned char *);
h->rsa.d_len = va_arg (arg_ptr, size_t);
}
if (err)
{
xfree (h);
return err;
}
if (n)
{
h->rsa.n = xtrymalloc (h->rsa.n_len);
if (!h->rsa.n)
{
err = gpg_error_from_syserror ();
xfree (h);
return err;
}
memcpy (h->rsa.n, n, h->rsa.n_len);
}
else
h->rsa.n = NULL;
if (e)
{
h->rsa.e = xtrymalloc (h->rsa.e_len);
if (!h->rsa.e)
{
err = gpg_error_from_syserror ();
xfree (h);
return err;
}
memcpy (h->rsa.e, e, h->rsa.e_len);
}
else
h->rsa.e = NULL;
if (d)
{
h->rsa.d = xtrymalloc (h->rsa.d_len);
if (!h->rsa.d)
{
err = gpg_error_from_syserror ();
xfree (h);
return err;
}
memcpy (h->rsa.d, d, h->rsa.d_len);
}
}
else if (algo == GCRY_PKEY_DSA)
{
int md_algo;
unsigned char *p;
unsigned char *q;
unsigned char *g;
unsigned char *x;
unsigned char *y;
md_algo = va_arg (arg_ptr, int);
h->dsa.md_algo = md_algo;
p = va_arg (arg_ptr, unsigned char *);
h->dsa.p_len = va_arg (arg_ptr, size_t);
q = va_arg (arg_ptr, unsigned char *);
h->dsa.q_len = va_arg (arg_ptr, size_t);
g = va_arg (arg_ptr, unsigned char *);
h->dsa.g_len = va_arg (arg_ptr, size_t);
y = va_arg (arg_ptr, unsigned char *);
h->dsa.y_len = va_arg (arg_ptr, size_t);
if (!(flags & GCRY_PKEY_FLAG_SECRET))
{
h->dsa.x = x = NULL;
h->dsa.x_len = 0;
}
else
{
x = va_arg (arg_ptr, unsigned char *);
h->dsa.x_len = va_arg (arg_ptr, size_t);
}
if (err)
{
xfree (h);
return err;
}
if (p)
{
h->dsa.p = xtrymalloc (h->dsa.p_len);
if (!h->dsa.p)
{
err = gpg_error_from_syserror ();
xfree (h);
return err;
}
memcpy (h->dsa.p, p, h->dsa.p_len);
}
else
h->dsa.p = NULL;
if (q)
{
h->dsa.q = xtrymalloc (h->dsa.q_len);
if (!h->dsa.q)
{
err = gpg_error_from_syserror ();
xfree (h);
return err;
}
memcpy (h->dsa.q, q, h->dsa.q_len);
}
else
h->dsa.q = NULL;
if (g)
{
h->dsa.g = xtrymalloc (h->dsa.g_len);
if (!h->dsa.g)
{
err = gpg_error_from_syserror ();
xfree (h);
return err;
}
memcpy (h->dsa.g, g, h->dsa.g_len);
}
else
h->dsa.g = NULL;
if (y)
{
h->dsa.y = xtrymalloc (h->dsa.y_len);
if (!h->dsa.y)
{
err = gpg_error_from_syserror ();
xfree (h);
return err;
}
memcpy (h->dsa.y, y, h->dsa.y_len);
}
else
h->dsa.y = NULL;
if (x)
{
h->dsa.x = xtrymalloc (h->dsa.x_len);
if (!h->dsa.x)
{
err = gpg_error_from_syserror ();
xfree (h);
return err;
}
memcpy (h->dsa.x, x, h->dsa.x_len);
}
}
*h_p = h;
return err;
}
gcry_error_t
_gcry_pkey_ctl (gcry_pkey_hd_t h, int cmd, void *buffer, size_t buflen)
{
gcry_error_t err = 0;
(void)h; (void)cmd; (void)buffer; (void)buflen;
/* FIXME: Not yet implemented anything. */
return err;
}
/* For now, it uses SEXP implementation, because the purpose is
to test the API (but not the implementation).
Will be rewritten soon.
Currently, it's like:
[ gcry_pkey_op API (with binary data) ]
|
[ gcry_pk_ API (with SEXP) ]
|
[ lower level public key implementations (with SEXP) ]
It will be like:
[ gcry_pk_ API with SEXP ] [ gcry_pkey_op API with binary data ]
| |
[ lower level public key implementations ]
That is, lower level public key implementations won't have any
(direct) handling of SEXP.
*/
gcry_error_t
_gcry_pkey_op (gcry_pkey_hd_t h, int cmd,
int num_in, const unsigned char *const in[],
const size_t in_len[],
int num_out, unsigned char *out[], size_t out_len[])
{
gcry_error_t err = 0;
if (h->algo == GCRY_PKEY_ECC)
{
- /* Just for Ed25519 and Ed448 for now. Will support more... */
if (h->ecc.curve == GCRY_PKEY_CURVE_ED25519)
{
if (cmd == GCRY_PKEY_OP_SIGN)
err = _gcry_pkey_ed25519_sign (h, num_in, in, in_len,
num_out, out, out_len);
else if (cmd == GCRY_PKEY_OP_VERIFY)
err = _gcry_pkey_ed25519_verify (h, num_in, in, in_len);
else
err = gpg_error (GPG_ERR_INV_OP);
}
else if (h->ecc.curve == GCRY_PKEY_CURVE_ED448)
{
if (cmd == GCRY_PKEY_OP_SIGN)
err = _gcry_pkey_ed448_sign (h, num_in, in, in_len,
num_out, out, out_len);
else if (cmd == GCRY_PKEY_OP_VERIFY)
err = _gcry_pkey_ed448_verify (h, num_in, in, in_len);
else
err = gpg_error (GPG_ERR_INV_OP);
}
+ else if (h->ecc.curve == GCRY_PKEY_CURVE_NIST_P224
+ || h->ecc.curve == GCRY_PKEY_CURVE_NIST_P256
+ || h->ecc.curve == GCRY_PKEY_CURVE_NIST_P384
+ || h->ecc.curve == GCRY_PKEY_CURVE_NIST_P521)
+ {
+ if (cmd == GCRY_PKEY_OP_SIGN)
+ err = _gcry_pkey_nist_sign (h, num_in, in, in_len,
+ num_out, out, out_len);
+ else if (cmd == GCRY_PKEY_OP_VERIFY)
+ err = _gcry_pkey_nist_verify (h, num_in, in, in_len);
+ else
+ err = gpg_error (GPG_ERR_INV_OP);
+ }
else
err = gpg_error (GPG_ERR_INV_OP);
}
else if (h->algo == GCRY_PKEY_RSA)
{
if (h->rsa.scheme == GCRY_PKEY_RSA_PSS)
{
if (cmd == GCRY_PKEY_OP_SIGN)
err = _gcry_pkey_rsapss_sign (h, num_in, in, in_len,
num_out, out, out_len);
else if (cmd == GCRY_PKEY_OP_VERIFY)
err = _gcry_pkey_rsapss_verify (h, num_in, in, in_len);
else
err = gpg_error (GPG_ERR_INV_OP);
}
else if (h->rsa.scheme == GCRY_PKEY_RSA_15)
{
if (cmd == GCRY_PKEY_OP_SIGN)
err = _gcry_pkey_rsa15_sign (h, num_in, in, in_len,
num_out, out, out_len);
else if (cmd == GCRY_PKEY_OP_VERIFY)
err = _gcry_pkey_rsa15_verify (h, num_in, in, in_len);
else
err = gpg_error (GPG_ERR_INV_OP);
}
else if (h->rsa.scheme == GCRY_PKEY_RSA_931)
{
if (cmd == GCRY_PKEY_OP_SIGN)
err = _gcry_pkey_rsa931_sign (h, num_in, in, in_len,
num_out, out, out_len);
else if (cmd == GCRY_PKEY_OP_VERIFY)
err = _gcry_pkey_rsa931_verify (h, num_in, in, in_len);
else
err = gpg_error (GPG_ERR_INV_OP);
}
else
err = gpg_error (GPG_ERR_INV_OP);
}
else if (h->algo == GCRY_PKEY_DSA)
{
if (cmd == GCRY_PKEY_OP_SIGN)
err = _gcry_pkey_dsa_sign (h, num_in, in, in_len,
num_out, out, out_len);
else if (cmd == GCRY_PKEY_OP_VERIFY)
err = _gcry_pkey_dsa_verify (h, num_in, in, in_len);
else
err = gpg_error (GPG_ERR_INV_OP);
}
else
err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
return err;
}
void
_gcry_pkey_close (gcry_pkey_hd_t h)
{
if (h)
{
if (h->algo == GCRY_PKEY_ECC)
{
xfree (h->ecc.pk);
xfree (h->ecc.sk);
}
else if (h->algo == GCRY_PKEY_RSA)
{
xfree (h->rsa.n);
xfree (h->rsa.e);
xfree (h->rsa.d);
}
else if (h->algo == GCRY_PKEY_DSA)
{
xfree (h->dsa.p);
xfree (h->dsa.q);
xfree (h->dsa.g);
xfree (h->dsa.x);
xfree (h->dsa.y);
}
xfree (h);
}
}
diff --git a/tests/t-ecdsa.c b/tests/t-ecdsa.c
index fb7f2741..18876273 100644
--- a/tests/t-ecdsa.c
+++ b/tests/t-ecdsa.c
@@ -1,533 +1,533 @@
/* t-ecdsa.c - Check the ECDSA crypto
* Copyright (C) 2021 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 .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include "stopwatch.h"
#define PGM "t-ecdsa"
#include "t-common.h"
#define N_TESTS 320
static int no_verify;
static int custom_data_file;
static int in_fips_mode = 0;
static void
show_note (const char *format, ...)
{
va_list arg_ptr;
if (!verbose && getenv ("srcdir"))
fputs (" ", stderr); /* To align above "PASS: ". */
else
fprintf (stderr, "%s: ", PGM);
va_start (arg_ptr, format);
vfprintf (stderr, format, arg_ptr);
if (*format && format[strlen(format)-1] != '\n')
putc ('\n', stderr);
va_end (arg_ptr);
}
/* Prepend FNAME with the srcdir environment variable's value and
* return an allocated filename. */
char *
prepend_srcdir (const char *fname)
{
static const char *srcdir;
char *result;
if (!srcdir && !(srcdir = getenv ("srcdir")))
srcdir = ".";
result = xmalloc (strlen (srcdir) + 1 + strlen (fname) + 1);
strcpy (result, srcdir);
strcat (result, "/");
strcat (result, fname);
return result;
}
/* Read next line but skip over empty and comment lines. Caller must
xfree the result. */
static char *
read_textline (FILE *fp, int *lineno)
{
char line[4096];
char *p;
do
{
if (!fgets (line, sizeof line, fp))
{
if (feof (fp))
return NULL;
die ("error reading input line: %s\n", strerror (errno));
}
++*lineno;
p = strchr (line, '\n');
if (!p)
die ("input line %d not terminated or too long\n", *lineno);
*p = 0;
for (p--;p > line && my_isascii (*p) && isspace (*p); p--)
*p = 0;
}
while (!*line || *line == '#');
/* if (debug) */
/* info ("read line: '%s'\n", line); */
return xstrdup (line);
}
/*
* The input line is like:
*
* [P-224,SHA-224]
*
*/
static void
parse_annotation (char **buffer, char **buffer2, const char *line, int lineno)
{
const char *s;
xfree (*buffer);
*buffer = NULL;
xfree (*buffer2);
*buffer2 = NULL;
s = strchr (line, '-');
if (!s)
{
fail ("syntax error at input line %d", lineno);
return;
}
*buffer = xstrdup (s-1);
(*buffer)[5] = 0; /* Remove ','. */
s = strchr (s+1, ',');
if (!s)
{
fail ("syntax error at input line %d", lineno);
return;
}
*buffer2 = xstrdup (s+1);
(*buffer2)[strlen (*buffer2) - 1] = 0; /* Remove ']'. */
}
/* Copy the data after the tag to BUFFER. BUFFER will be allocated as
needed. */
static void
copy_data (char **buffer, const char *line, int lineno)
{
const char *s;
xfree (*buffer);
*buffer = NULL;
s = strchr (line, '=');
if (!s)
{
fail ("syntax error at input line %d", lineno);
return;
}
for (s++; my_isascii (*s) && isspace (*s); s++)
;
*buffer = xstrdup (s);
}
/* Convert STRING consisting of hex characters into its binary
representation and return it as an allocated buffer. The valid
length of the buffer is returned at R_LENGTH. The string is
delimited by end of string. The function returns NULL on
error. */
static void *
hex2buffer (const char *string, size_t *r_length)
{
const char *s;
unsigned char *buffer;
size_t length;
buffer = xmalloc (strlen(string)/2+1);
length = 0;
for (s=string; *s; s +=2 )
{
if (!hexdigitp (s) || !hexdigitp (s+1))
return NULL; /* Invalid hex digits. */
((unsigned char*)buffer)[length++] = xtoi_2 (s);
}
*r_length = length;
return buffer;
}
static void
one_test (const char *curvename, const char *sha_alg,
const char *x, const char *y, const char *d,
const char *msg, const char *k,
const char *r, const char *s)
{
gpg_error_t err;
int i;
char *p0;
void *buffer = NULL;
void *buffer2 = NULL;
void *buffer3 = NULL;
size_t buflen, buflen2, buflen3;
gcry_pkey_hd_t h0 = NULL;
gcry_pkey_hd_t h1 = NULL;
char *sig_r_string = NULL;
char *sig_s_string = NULL;
const unsigned char *in[4];
size_t in_len[4];
unsigned char *out[2] = { NULL, NULL };
size_t out_len[2] = { 0, 0 };
- unsigned int flags = 0;
+ unsigned int flags = GCRY_PKEY_FLAG_PREHASH;
int curve;
int md_algo;
if (verbose > 1)
info ("Running test %s\n", sha_alg);
if (!strcmp (curvename, "P-224"))
curve = GCRY_PKEY_CURVE_NIST_P224;
else if (!strcmp (curvename, "P-256"))
curve = GCRY_PKEY_CURVE_NIST_P256;
else if (!strcmp (curvename, "P-384"))
curve = GCRY_PKEY_CURVE_NIST_P384;
else if (!strcmp (curvename, "P-521"))
curve = GCRY_PKEY_CURVE_NIST_P521;
else
{
fail ("error for test, %s: %s: %s",
"ECC curve", "invalid", curvename);
goto leave;
}
if (!strcmp (sha_alg, "SHA-224"))
md_algo = GCRY_MD_SHA224;
else if (!strcmp (sha_alg, "SHA-256"))
md_algo = GCRY_MD_SHA256;
else if (!strcmp (sha_alg, "SHA-384"))
md_algo = GCRY_MD_SHA384;
else if (!strcmp (sha_alg, "SHA-512"))
md_algo = GCRY_MD_SHA512;
else if (!strcmp (sha_alg, "SHA-512224"))
md_algo = GCRY_MD_SHA512_224;
else if (!strcmp (sha_alg, "SHA-512256"))
md_algo = GCRY_MD_SHA512_256;
else
{
fail ("error for test, %s: %s: %s",
"SHA algo", "invalid", sha_alg);
goto leave;
}
if (!(buffer = hex2buffer (x, &buflen)))
{
fail ("error parsing for test, %s: %s",
"Qx", "invalid hex string");
goto leave;
}
if (!(buffer2 = hex2buffer (y, &buflen2)))
{
fail ("error parsing for test, %s: %s",
"Qy", "invalid hex string");
goto leave;
}
if (!(buffer3 = hex2buffer (d, &buflen3)))
{
fail ("error parsing for test, %s: %s",
"d", "invalid hex string");
goto leave;
}
flags |= GCRY_PKEY_FLAG_SECRET;
err = gcry_pkey_open (&h0, GCRY_PKEY_ECC, flags, curve, md_algo,
buffer, buflen, buffer2, buflen2, buffer3, buflen3);
if (err)
{
fail ("error opening PKEY for test, %s: %s",
"sk", gpg_strerror (err));
goto leave;
}
flags &= ~GCRY_PKEY_FLAG_SECRET;
err = gcry_pkey_open (&h1, GCRY_PKEY_ECC, flags, curve, md_algo,
buffer, buflen, buffer2, buflen2);
if (err)
{
fail ("error opening PKEY for test, %s: %s",
"pk", gpg_strerror (err));
goto leave;
}
xfree (buffer);
xfree (buffer2);
xfree (buffer3);
buffer = buffer2 = buffer3 = NULL;
if (!(buffer = hex2buffer (msg, &buflen)))
{
fail ("error parsing for test, %s: %s",
"msg", "invalid hex string");
goto leave;
}
in[0] = buffer;
in_len[0] = buflen;
if (!(buffer2 = hex2buffer (k, &buflen2)))
{
fail ("error parsing for test, %s: %s",
"salt_val", "invalid hex string");
goto leave;
}
in[1] = buffer2;
in_len[1] = buflen2;
err = gcry_pkey_op (h0, GCRY_PKEY_OP_SIGN, 2, in, in_len, 2, out, out_len);
if (err)
fail ("gcry_pkey_op failed: %s", gpg_strerror (err));
sig_r_string = xmalloc (2*out_len[0]+1);
p0 = sig_r_string;
*p0 = 0;
for (i=0; i < out_len[0]; i++, p0 += 2)
snprintf (p0, 3, "%02x", out[0][i]);
sig_s_string = xmalloc (2*out_len[1]+1);
p0 = sig_s_string;
*p0 = 0;
for (i=0; i < out_len[0]; i++, p0 += 2)
snprintf (p0, 3, "%02x", out[1][i]);
if (strcmp (sig_r_string, r) || strcmp (sig_s_string, s))
{
fail ("gcry_pkey_op failed: %s",
"wrong value returned");
info (" expected: '%s'", r);
info (" got: '%s'", sig_r_string);
info (" expected: '%s'", s);
info (" got: '%s'", sig_s_string);
}
if (!no_verify)
{
in[2] = out[0];
in_len[2] = out_len[0];
in[3] = out[1];
in_len[3] = out_len[1];
if ((err = gcry_pkey_op (h1, GCRY_PKEY_OP_VERIFY,
4, in, in_len, 0, NULL, 0)))
fail ("GCRY_PKEY_OP_VERIFY failed for test: %s",
gpg_strerror (err));
}
leave:
xfree (buffer);
xfree (buffer2);
xfree (buffer3);
xfree (out[0]);
xfree (out[1]);
xfree (sig_r_string);
xfree (sig_s_string);
gcry_pkey_close (h0);
gcry_pkey_close (h1);
}
static void
check_ecdsa (const char *fname)
{
FILE *fp;
int lineno, ntests;
char *line;
char *curve, *sha_alg;
char *x, *y;
char *d;
char *msg, *k, *r, *s;
info ("Checking ECDSA.\n");
fp = fopen (fname, "r");
if (!fp)
die ("error opening '%s': %s\n", fname, strerror (errno));
curve = NULL;
sha_alg = NULL;
x = y = d = NULL;
msg = k = r = s = NULL;
lineno = ntests = 0;
while ((line = read_textline (fp, &lineno)))
{
if (!strncmp (line, "[", 1))
parse_annotation (&curve, &sha_alg, line, lineno);
else if (!strncmp (line, "Msg =", 5))
copy_data (&msg, line, lineno);
else if (!strncmp (line, "d =", 3))
copy_data (&d, line, lineno);
else if (!strncmp (line, "Qx =", 4))
copy_data (&x, line, lineno);
else if (!strncmp (line, "Qy =", 4))
copy_data (&y, line, lineno);
else if (!strncmp (line, "k =", 3))
copy_data (&k, line, lineno);
else if (!strncmp (line, "R =", 3))
copy_data (&r, line, lineno);
else if (!strncmp (line, "S =", 3))
copy_data (&s, line, lineno);
else
fail ("unknown tag at input line %d", lineno);
xfree (line);
if (curve && sha_alg && x && y && d && msg && k && r && s)
{
one_test (curve, sha_alg, x, y, d, msg, k, r, s);
ntests++;
if (!(ntests % 256))
show_note ("%d of %d tests done\n", ntests, N_TESTS);
xfree (msg); msg = NULL;
xfree (x); x = NULL;
xfree (y); y = NULL;
xfree (d); d = NULL;
xfree (k); k = NULL;
xfree (r); r = NULL;
xfree (s); s = NULL;
}
}
xfree (curve);
xfree (sha_alg);
xfree (x);
xfree (y);
xfree (d);
xfree (msg);
xfree (k);
xfree (r);
xfree (s);
if (ntests != N_TESTS && !custom_data_file)
fail ("did %d tests but expected %d", ntests, N_TESTS);
else if ((ntests % 256))
show_note ("%d tests done\n", ntests);
fclose (fp);
}
int
main (int argc, char **argv)
{
int last_argc = -1;
char *fname = NULL;
if (argc)
{ argc--; argv++; }
while (argc && last_argc != argc )
{
last_argc = argc;
if (!strcmp (*argv, "--"))
{
argc--; argv++;
break;
}
else if (!strcmp (*argv, "--help"))
{
fputs ("usage: " PGM " [options]\n"
"Options:\n"
" --verbose print timings etc.\n"
" --debug flyswatter\n"
" --no-verify skip the verify test\n"
" --data FNAME take test data from file FNAME\n",
stdout);
exit (0);
}
else if (!strcmp (*argv, "--verbose"))
{
verbose++;
argc--; argv++;
}
else if (!strcmp (*argv, "--debug"))
{
verbose += 2;
debug++;
argc--; argv++;
}
else if (!strcmp (*argv, "--no-verify"))
{
no_verify = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--data"))
{
argc--; argv++;
if (argc)
{
xfree (fname);
fname = xstrdup (*argv);
argc--; argv++;
}
}
else if (!strncmp (*argv, "--", 2))
die ("unknown option '%s'", *argv);
}
if (!fname)
fname = prepend_srcdir ("t-ecdsa.inp");
else
custom_data_file = 1;
xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0));
if (!gcry_check_version (GCRYPT_VERSION))
die ("version mismatch\n");
if (debug)
xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u , 0));
xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0));
xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0));
if (gcry_fips_mode_active ())
in_fips_mode = 1;
start_timer ();
check_ecdsa (fname);
stop_timer ();
xfree (fname);
info ("All tests completed in %s. Errors: %d\n",
elapsed_time (1), error_count);
return !!error_count;
}