diff --git a/cipher/pkey-rsa.c b/cipher/pkey-rsa.c
index 1389f265..320e43fc 100644
--- a/cipher/pkey-rsa.c
+++ b/cipher/pkey-rsa.c
@@ -1,704 +1,648 @@
/* pkey-rsa.c - PKEY API implementation for RSA PSS/15/931
* 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_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 err = 0;
gcry_sexp_t s_sk = NULL;
gcry_sexp_t s_msg= NULL;
gcry_sexp_t s_sig= NULL;
const char *md_name;
gcry_sexp_t s_tmp, s_tmp2;
if (num_in != 2)
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_name = "sha224";
break;
case GCRY_MD_SHA256:
md_name = "sha256";
break;
case GCRY_MD_SHA384:
md_name = "sha384";
break;
case GCRY_MD_SHA512:
md_name = "sha512";
break;
default:
return gpg_error (GPG_ERR_INV_ARG);
}
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)
return err;
err = sexp_build (&s_msg, NULL,
"(data"
" (flags pss)"
" (hash-algo %s)"
" (value %b)"
" (salt-length %d)"
" (random-override %b))",
md_name,
(int)in_len[0], in[0],
(int)in_len[1],
(int)in_len[1], in[1]);
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] = 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 ();
- 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);
- }
+ out[0] = sexp_nth_buffer (s_tmp, 1, &out_len[0]);
sexp_release (s_tmp);
}
}
}
sexp_release (s_tmp2);
if (out[0] == NULL)
err = gpg_error (GPG_ERR_BAD_SIGNATURE);
sexp_release (s_sig);
return err;
}
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 err = 0;
gcry_sexp_t s_pk = NULL;
const char *md_name;
gcry_sexp_t s_msg= NULL;
gcry_sexp_t s_sig= NULL;
if (num_in != 3)
return gpg_error (GPG_ERR_INV_ARG);
switch (h->rsa.md_algo)
{
case GCRY_MD_SHA224:
md_name = "sha224";
break;
case GCRY_MD_SHA256:
md_name = "sha256";
break;
case GCRY_MD_SHA384:
md_name = "sha384";
break;
case GCRY_MD_SHA512:
md_name = "sha512";
break;
default:
return gpg_error (GPG_ERR_INV_ARG);
}
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)
return err;
err = sexp_build (&s_msg, NULL,
"(data"
" (flags pss)"
" (hash-algo %s)"
" (value %b)"
" (salt-length %d)"
" (random-override %b))",
md_name,
(int)in_len[0], in[0],
(int)in_len[1],
(int)in_len[1], in[1]);
if (err)
{
sexp_release (s_pk);
return err;
}
err = sexp_build (&s_sig, NULL,
"(sig-val(rsa(s %b)))",
(int)in_len[2], in[2]);
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;
}
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 err = 0;
gcry_sexp_t s_sk = NULL;
gcry_sexp_t s_msg= NULL;
gcry_sexp_t s_sig= NULL;
const char *md_name;
gcry_sexp_t s_tmp, s_tmp2;
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_name = "sha224";
break;
case GCRY_MD_SHA256:
md_name = "sha256";
break;
case GCRY_MD_SHA384:
md_name = "sha384";
break;
case GCRY_MD_SHA512:
md_name = "sha512";
break;
default:
return gpg_error (GPG_ERR_INV_ARG);
}
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)
return err;
err = sexp_build (&s_msg, NULL,
"(data"
" (flags pkcs1 prehash)"
" (hash-algo %s)"
" (value %b))",
md_name,
(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] = 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 ();
- 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);
- }
+ out[0] = sexp_nth_buffer (s_tmp, 1, &out_len[0]);
sexp_release (s_tmp);
}
}
}
sexp_release (s_tmp2);
if (out[0] == NULL)
err = gpg_error (GPG_ERR_BAD_SIGNATURE);
sexp_release (s_sig);
return err;
}
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 err = 0;
gcry_sexp_t s_pk = NULL;
const char *md_name;
gcry_sexp_t s_msg= NULL;
gcry_sexp_t s_sig= NULL;
if (num_in != 2)
return gpg_error (GPG_ERR_INV_ARG);
switch (h->rsa.md_algo)
{
case GCRY_MD_SHA224:
md_name = "sha224";
break;
case GCRY_MD_SHA256:
md_name = "sha256";
break;
case GCRY_MD_SHA384:
md_name = "sha384";
break;
case GCRY_MD_SHA512:
md_name = "sha512";
break;
default:
return gpg_error (GPG_ERR_INV_ARG);
}
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)
return err;
err = sexp_build (&s_msg, NULL,
"(data"
" (flags pkcs1 prehash)"
" (hash-algo %s)"
" (value %b))",
md_name,
(int)in_len[0], in[0]);
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);
sexp_release (s_sig);
sexp_release (s_msg);
sexp_release (s_pk);
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)"
+ " (flags raw fixedlen)"
" (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);
- }
+ out[0] = sexp_nth_buffer (s_tmp, 1, &out_len[0]);
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)"
+ " (flags raw fixedlen)"
" (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;
}
+ /* We check two possible signature;
+ * This allows invalid signature (by another value).
+ * We should support X9.31 signature scheme in lower level.
+ */
+
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;
}