summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2021-09-08 20:15:26 +0900
committerNIIBE Yutaka <gniibe@fsij.org>2021-09-08 20:15:26 +0900
commit1486a05e7853feb87d12d4f61df6dd3ad4afe2e8 (patch)
tree4b53eee9eede91e095dee5ea902df249c4a36c05
parent196c4d7e396d0d0e918d3ad483a04bf6ffae4885 (diff)
downloadlibgcrypt-1486a05e7853feb87d12d4f61df6dd3ad4afe2e8.tar.gz
experiment: Implement RSA X9.31 signature.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
-rw-r--r--cipher/pkey-internal.h10
-rw-r--r--cipher/pkey-rsa.c343
-rw-r--r--cipher/pkey.c26
3 files changed, 368 insertions, 11 deletions
diff --git a/cipher/pkey-internal.h b/cipher/pkey-internal.h
index 685d6be0..ec5f370e 100644
--- a/cipher/pkey-internal.h
+++ b/cipher/pkey-internal.h
@@ -58,6 +58,16 @@ 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[]);
+
struct pkey_ecc {
int curve;
diff --git a/cipher/pkey-rsa.c b/cipher/pkey-rsa.c
index 29744f15..1389f265 100644
--- a/cipher/pkey-rsa.c
+++ b/cipher/pkey-rsa.c
@@ -1,4 +1,4 @@
-/* pkey-rsa.c - PKEY API implementation for RSA PSS/15/931
+/* pkey-rsa.c - PKEY API implementation for RSA PSS/15/931
* Copyright (C) 2021 g10 Code GmbH
*
* This file is part of Libgcrypt.
@@ -111,7 +111,27 @@ _gcry_pkey_rsapss_sign (gcry_pkey_hd_t h,
s_tmp = sexp_find_token (s_tmp2, "s", 0);
if (s_tmp)
{
- out[0] = sexp_nth_buffer (s_tmp, 1, &out_len[0]);
+ const char *p;
+ size_t n;
+
+ out_len[0] = h->rsa.n_len;
+ out[0] = xtrymalloc (h->rsa.n_len);
+ if (! out[0])
+ {
+ err = gpg_error_from_syserror ();
+ sexp_release (s_tmp);
+ sexp_release (s_tmp2);
+ return err;
+ }
+
+ p = sexp_nth_data (s_tmp, 1, &n);
+ if (n == h->rsa.n_len)
+ memcpy (out[0], p, h->rsa.n_len);
+ else
+ {
+ memset (out[0], 0, h->rsa.n_len - n);
+ memcpy (out[0] + h->rsa.n_len - n, p, n);
+ }
sexp_release (s_tmp);
}
}
@@ -280,7 +300,27 @@ _gcry_pkey_rsa15_sign (gcry_pkey_hd_t h,
s_tmp = sexp_find_token (s_tmp2, "s", 0);
if (s_tmp)
{
- out[0] = sexp_nth_buffer (s_tmp, 1, &out_len[0]);
+ const char *p;
+ size_t n;
+
+ out_len[0] = h->rsa.n_len;
+ out[0] = xtrymalloc (h->rsa.n_len);
+ if (! out[0])
+ {
+ err = gpg_error_from_syserror ();
+ sexp_release (s_tmp);
+ sexp_release (s_tmp2);
+ return err;
+ }
+
+ p = sexp_nth_data (s_tmp, 1, &n);
+ if (n == h->rsa.n_len)
+ memcpy (out[0], p, h->rsa.n_len);
+ else
+ {
+ memset (out[0], 0, h->rsa.n_len - n);
+ memcpy (out[0] + h->rsa.n_len - n, p, n);
+ }
sexp_release (s_tmp);
}
}
@@ -365,3 +405,300 @@ _gcry_pkey_rsa15_verify (gcry_pkey_hd_t h,
return err;
}
+
+
+
+static void
+x931_encode_sig (gcry_pkey_hd_t h, unsigned char md_number,
+ unsigned char *frame,
+ const unsigned char *input, size_t input_len)
+{
+ size_t hashlen;
+ size_t len_ps;
+
+ hashlen = _gcry_md_get_algo_dlen (h->rsa.md_algo);
+
+ len_ps = h->rsa.n_len - hashlen - 4;
+ frame[0] = 0x6b;
+ memset (frame+1, 0xbb, len_ps);
+ frame[1+len_ps] = 0xba;
+ _gcry_md_hash_buffer (h->rsa.md_algo, &frame[len_ps+2], input, input_len);
+ frame[h->rsa.n_len - 2] = md_number;
+ frame[h->rsa.n_len - 1] = 0xcc;
+}
+
+static int
+bn_sub (unsigned char *res,
+ const unsigned char *a, const unsigned char *b, size_t n)
+{
+ int i;
+ unsigned char borrow = 0;
+
+ for (i = 0; i < (int)n; i++)
+ {
+ res[n-i-1] = a[n-i-1] - b[n-i-1] - borrow;
+ if ((int)a[n-i-1] < (int)b[n-i-1] + borrow)
+ borrow = 1;
+ else
+ borrow = 0;
+ }
+
+ return borrow;
+}
+
+static int
+bn_cmp (const unsigned char *a, const unsigned char *b, size_t n)
+{
+ int i;
+ unsigned char borrow = 0;
+
+ for (i = 0; i < (int)n; i++)
+ {
+ if ((int)a[n-i-1] < (int)b[n-i-1] + borrow)
+ borrow = 1;
+ else
+ borrow = 0;
+ }
+
+ return borrow;
+}
+
+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 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;
+ unsigned char md_number;
+ unsigned char *frame;
+
+ if (num_in != 1)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ if (num_out != 1)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ switch (h->rsa.md_algo)
+ {
+ case GCRY_MD_SHA224:
+ md_number = 0x38;
+ break;
+ case GCRY_MD_SHA256:
+ md_number = 0x34;
+ break;
+ case GCRY_MD_SHA384:
+ md_number = 0x36;
+ break;
+ case GCRY_MD_SHA512:
+ md_number = 0x35;
+ break;
+ default:
+ return gpg_error (GPG_ERR_INV_ARG);
+ }
+
+ if (!(frame = xtrymalloc (h->rsa.n_len)))
+ return gpg_error_from_syserror ();
+
+ x931_encode_sig (h, md_number, frame, in[0], in_len[0]);
+
+ err = sexp_build (&s_sk, NULL,
+ "(private-key (rsa (n %b)(e %b)(d %b)))",
+ (int)h->rsa.n_len, h->rsa.n,
+ (int)h->rsa.e_len, h->rsa.e,
+ (int)h->rsa.d_len, h->rsa.d);
+ if (err)
+ {
+ xfree (frame);
+ return err;
+ }
+
+ err = sexp_build (&s_msg, NULL,
+ "(data"
+ " (flags raw)"
+ " (value %b))",
+ (int)h->rsa.n_len, frame);
+ if (err)
+ {
+ xfree (frame);
+ 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)
+ {
+ xfree (frame);
+ return err;
+ }
+
+ out[0] = 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, "rsa", 0);
+ if (s_tmp)
+ {
+ sexp_release (s_tmp2);
+ s_tmp2 = s_tmp;
+ s_tmp = sexp_find_token (s_tmp2, "s", 0);
+ if (s_tmp)
+ {
+ const char *p;
+ size_t n;
+
+ out_len[0] = h->rsa.n_len;
+ out[0] = xtrymalloc (h->rsa.n_len);
+ if (! out[0])
+ {
+ err = gpg_error_from_syserror ();
+ xfree (frame);
+ sexp_release (s_tmp);
+ sexp_release (s_tmp2);
+ return err;
+ }
+
+ p = sexp_nth_data (s_tmp, 1, &n);
+ if (n == h->rsa.n_len)
+ memcpy (out[0], p, h->rsa.n_len);
+ else
+ {
+ memset (out[0], 0, h->rsa.n_len - n);
+ memcpy (out[0] + h->rsa.n_len - n, p, n);
+ }
+ sexp_release (s_tmp);
+ }
+ }
+ }
+ sexp_release (s_tmp2);
+
+ if (out[0] == NULL)
+ err = gpg_error (GPG_ERR_BAD_SIGNATURE);
+ else
+ {
+ /* X9.31 signature scheme is tricky; It selects minimum one. */
+ if (!bn_sub (frame, h->rsa.n, out[0], h->rsa.n_len)
+ && bn_cmp (frame, out[0], h->rsa.n_len))
+ memcpy (out[0], frame, h->rsa.n_len);
+ }
+
+ sexp_release (s_sig);
+ xfree (frame);
+
+ return err;
+}
+
+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 err = 0;
+ gcry_sexp_t s_pk = NULL;
+ gcry_sexp_t s_msg= NULL;
+ gcry_sexp_t s_sig= NULL;
+ unsigned char md_number;
+ unsigned char *frame;
+
+ if (num_in != 2)
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ switch (h->rsa.md_algo)
+ {
+ case GCRY_MD_SHA224:
+ md_number = 0x38;
+ break;
+ case GCRY_MD_SHA256:
+ md_number = 0x34;
+ break;
+ case GCRY_MD_SHA384:
+ md_number = 0x36;
+ break;
+ case GCRY_MD_SHA512:
+ md_number = 0x35;
+ break;
+ default:
+ return gpg_error (GPG_ERR_INV_ARG);
+ }
+
+ if (!(frame = xtrymalloc (h->rsa.n_len)))
+ return gpg_error_from_syserror ();
+
+ x931_encode_sig (h, md_number, frame, in[0], in_len[0]);
+
+ err = sexp_build (&s_pk, NULL,
+ "(public-key (rsa (n %b)(e %b)))",
+ (int)h->rsa.n_len, h->rsa.n,
+ (int)h->rsa.e_len, h->rsa.e);
+ if (err)
+ {
+ xfree (frame);
+ return err;
+ }
+
+ err = sexp_build (&s_msg, NULL,
+ "(data"
+ " (flags raw)"
+ " (value %b))",
+ (int)h->rsa.n_len, frame);
+ xfree (frame);
+ if (err)
+ {
+ sexp_release (s_pk);
+ return err;
+ }
+
+ err = sexp_build (&s_sig, NULL,
+ "(sig-val(rsa(s %b)))",
+ (int)in_len[1], in[1]);
+ if (err)
+ {
+ sexp_release (s_msg);
+ sexp_release (s_pk);
+ return err;
+ }
+
+ err = _gcry_pk_verify (s_sig, s_msg, s_pk);
+
+ if (err)
+ {
+ unsigned char *alt;
+
+ /* Try another. */
+ sexp_release (s_sig);
+
+ if (!(alt = xtrymalloc (h->rsa.n_len)))
+ {
+ sexp_release (s_msg);
+ sexp_release (s_pk);
+ return gpg_error_from_syserror ();
+ }
+
+ bn_sub (alt, h->rsa.n, in[1], h->rsa.n_len);
+ err = sexp_build (&s_sig, NULL,
+ "(sig-val(rsa(s %b)))",
+ (int)in_len[1], alt);
+ 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.c b/cipher/pkey.c
index 1ef0034a..9a0d12fa 100644
--- a/cipher/pkey.c
+++ b/cipher/pkey.c
@@ -1,4 +1,4 @@
-/* pkey.c - pubric key cryptography API
+/* pkey.c - Pubric key cryptography API
* Copyright (C) 2021 g10 Code GmbH
*
* This file is part of Libgcrypt.
@@ -50,7 +50,7 @@ _gcry_pkey_vopen (gcry_pkey_hd_t *h_p, int algo, unsigned int flags,
return err;
if (!(h = xtrycalloc (1, sizeof (struct gcry_pkey_handle))))
- return gpg_err_code_from_syserror ();
+ return gpg_error_from_syserror ();
h->algo = algo;
h->flags = flags;
@@ -102,7 +102,7 @@ _gcry_pkey_vopen (gcry_pkey_hd_t *h_p, int algo, unsigned int flags,
h->ecc.pk = xtrymalloc (h->ecc.pk_len);
if (!h->ecc.pk)
{
- err = gpg_err_code_from_syserror ();
+ err = gpg_error_from_syserror ();
xfree (h);
return err;
}
@@ -116,7 +116,7 @@ _gcry_pkey_vopen (gcry_pkey_hd_t *h_p, int algo, unsigned int flags,
h->ecc.sk = xtrymalloc_secure (h->ecc.sk_len);
if (!h->ecc.sk)
{
- err = gpg_err_code_from_syserror ();
+ err = gpg_error_from_syserror ();
xfree (h->ecc.pk);
xfree (h);
return err;
@@ -138,7 +138,7 @@ _gcry_pkey_vopen (gcry_pkey_hd_t *h_p, int algo, unsigned int flags,
else if (scheme == GCRY_PKEY_RSA_15)
;
else if (scheme == GCRY_PKEY_RSA_931)
- err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ ;
else
err = gpg_error (GPG_ERR_INV_ARG);
if (err)
@@ -182,7 +182,7 @@ _gcry_pkey_vopen (gcry_pkey_hd_t *h_p, int algo, unsigned int flags,
h->rsa.n = xtrymalloc (h->rsa.n_len);
if (!h->rsa.n)
{
- err = gpg_err_code_from_syserror ();
+ err = gpg_error_from_syserror ();
xfree (h);
return err;
}
@@ -196,7 +196,7 @@ _gcry_pkey_vopen (gcry_pkey_hd_t *h_p, int algo, unsigned int flags,
h->rsa.e = xtrymalloc (h->rsa.e_len);
if (!h->rsa.e)
{
- err = gpg_err_code_from_syserror ();
+ err = gpg_error_from_syserror ();
xfree (h);
return err;
}
@@ -210,7 +210,7 @@ _gcry_pkey_vopen (gcry_pkey_hd_t *h_p, int algo, unsigned int flags,
h->rsa.d = xtrymalloc (h->rsa.d_len);
if (!h->rsa.d)
{
- err = gpg_err_code_from_syserror ();
+ err = gpg_error_from_syserror ();
xfree (h);
return err;
}
@@ -311,6 +311,16 @@ _gcry_pkey_op (gcry_pkey_hd_t h, int cmd,
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);
}