summaryrefslogtreecommitdiff
path: root/cipher/pkey-ecc-nist.c
diff options
context:
space:
mode:
Diffstat (limited to 'cipher/pkey-ecc-nist.c')
-rw-r--r--cipher/pkey-ecc-nist.c220
1 files changed, 220 insertions, 0 deletions
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 <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#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;
+}