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; }