diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2021-09-08 20:15:26 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2021-09-08 20:15:26 +0900 |
commit | 1486a05e7853feb87d12d4f61df6dd3ad4afe2e8 (patch) | |
tree | 4b53eee9eede91e095dee5ea902df249c4a36c05 | |
parent | 196c4d7e396d0d0e918d3ad483a04bf6ffae4885 (diff) | |
download | libgcrypt-1486a05e7853feb87d12d4f61df6dd3ad4afe2e8.tar.gz |
experiment: Implement RSA X9.31 signature.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
-rw-r--r-- | cipher/pkey-internal.h | 10 | ||||
-rw-r--r-- | cipher/pkey-rsa.c | 343 | ||||
-rw-r--r-- | cipher/pkey.c | 26 |
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); } |