diff --git a/cipher/pkey-rsa.c b/cipher/pkey-rsa.c
index 1c9b3c48..44e0cd66 100644
--- a/cipher/pkey-rsa.c
+++ b/cipher/pkey-rsa.c
@@ -1,672 +1,692 @@
/* 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)
+ if (num_in != 1 && 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;
case GCRY_MD_SHA512_224:
md_name = "sha512-224";
break;
case GCRY_MD_SHA512_256:
md_name = "sha512-256";
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 (num_in == 1)
+ err = sexp_build (&s_msg, NULL,
+ "(data"
+ " (flags pss)"
+ " (hash-algo %s)"
+ " (value %b)"
+ " (salt-length %d))",
+ md_name,
+ (int)in_len[0], in[0], 0);
+ else
+ 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)
{
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)
+ if (num_in != 2 && 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;
case GCRY_MD_SHA512_224:
md_name = "sha512-224";
break;
case GCRY_MD_SHA512_256:
md_name = "sha512-256";
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 (num_in == 2)
+ err = sexp_build (&s_msg, NULL,
+ "(data"
+ " (flags pss)"
+ " (hash-algo %s)"
+ " (value %b)"
+ " (salt-length %d))",
+ md_name,
+ (int)in_len[0], in[0], 0);
+ else
+ 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]);
+ (int)in_len[num_in-1], in[num_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;
}
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;
case GCRY_MD_SHA512_224:
md_name = "sha512-224";
break;
case GCRY_MD_SHA512_256:
md_name = "sha512-256";
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)
{
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;
case GCRY_MD_SHA512_224:
md_name = "sha512-224";
break;
case GCRY_MD_SHA512_256:
md_name = "sha512-256";
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 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)
{
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 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;
}
diff --git a/tests/t-rsa-pss.c b/tests/t-rsa-pss.c
index e72f10e2..2a00a715 100644
--- a/tests/t-rsa-pss.c
+++ b/tests/t-rsa-pss.c
@@ -1,456 +1,463 @@
/* t-rsa-pss.c - Check the RSA-PSS 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-rsa-pss"
#include "t-common.h"
#define N_TESTS 120
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);
}
/* 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 *n, const char *e, const char *d,
const char *sha_alg, const char *msg, const char *s, const char *salt_val)
{
gpg_error_t err;
int i;
char *p;
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_string = NULL;
const unsigned char *in[3];
size_t in_len[3];
unsigned char *out[1] = { NULL };
size_t out_len[1] = { 0 };
unsigned int flags = 0;
int md_algo;
+ int num_in;
if (verbose > 1)
info ("Running test %s\n", sha_alg);
if (!strcmp (sha_alg, "SHA224"))
md_algo = GCRY_MD_SHA224;
else if (!strcmp (sha_alg, "SHA256"))
md_algo = GCRY_MD_SHA256;
else if (!strcmp (sha_alg, "SHA384"))
md_algo = GCRY_MD_SHA384;
else if (!strcmp (sha_alg, "SHA512"))
md_algo = GCRY_MD_SHA512;
else if (!strcmp (sha_alg, "SHA512224"))
md_algo = GCRY_MD_SHA512_224;
else if (!strcmp (sha_alg, "SHA512256"))
md_algo = GCRY_MD_SHA512_256;
else
{
fail ("error for test, %s: %s",
"d", "invalid hex string");
goto leave;
}
if (!(buffer = hex2buffer (n, &buflen)))
{
fail ("error parsing for test, %s: %s",
"n", "invalid hex string");
goto leave;
}
if (!(buffer2 = hex2buffer (e, &buflen2)))
{
fail ("error parsing for test, %s: %s",
"e", "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_RSA, flags, GCRY_PKEY_RSA_PSS, 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_RSA, flags, GCRY_PKEY_RSA_PSS, 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 (salt_val, &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, 1, out, out_len);
+ /* SaltVal = 00 means no salt. */
+ if (buflen2 == 1 && ((char *)buffer2)[0] == 0)
+ num_in = 1;
+ else
+ num_in = 2;
+
+ err = gcry_pkey_op (h0, GCRY_PKEY_OP_SIGN, num_in, in, in_len, 1, out, out_len);
if (err)
fail ("gcry_pkey_op failed: %s", gpg_strerror (err));
sig_string = xmalloc (2*out_len[0]+1);
p = sig_string;
*p = 0;
for (i=0; i < out_len[0]; i++, p += 2)
snprintf (p, 3, "%02x", out[0][i]);
if (strcmp (sig_string, s))
{
fail ("gcry_pkey_op failed: %s",
"wrong value returned");
info (" expected: '%s'", s);
info (" got: '%s'", sig_string);
}
if (!no_verify)
{
- in[2] = out[0];
- in_len[2] = out_len[0];
+ in[num_in] = out[0];
+ in_len[num_in] = out_len[0];
if ((err = gcry_pkey_op (h1, GCRY_PKEY_OP_VERIFY,
- 3, in, in_len, 0, NULL, 0)))
+ num_in+1, 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 (sig_string);
gcry_pkey_close (h0);
gcry_pkey_close (h1);
}
static void
check_rsa_pss (const char *fname)
{
FILE *fp;
int lineno, ntests;
char *line;
char *n, *e, *d;
char *sha_alg, *msg, *s, *salt_val;
info ("Checking RSASSA-PSS.\n");
fp = fopen (fname, "r");
if (!fp)
die ("error opening '%s': %s\n", fname, strerror (errno));
n = e = d = NULL;
sha_alg = msg = s = salt_val = NULL;
lineno = ntests = 0;
while ((line = read_textline (fp, &lineno)))
{
if (!strncmp (line, "[mod", 4))
/* Skip the annotation for modulus. */
;
else if (!strncmp (line, "n =", 3))
copy_data (&n, line, lineno);
else if (!strncmp (line, "e =", 3))
copy_data (&e, line, lineno);
else if (!strncmp (line, "d =", 3))
copy_data (&d, line, lineno);
else if (!strncmp (line, "SHAAlg =", 8))
copy_data (&sha_alg, line, lineno);
else if (!strncmp (line, "Msg =", 5))
copy_data (&msg, line, lineno);
else if (!strncmp (line, "S =", 3))
copy_data (&s, line, lineno);
else if (!strncmp (line, "SaltVal =", 9))
copy_data (&salt_val, line, lineno);
else
fail ("unknown tag at input line %d", lineno);
xfree (line);
if (n && e && d && sha_alg && msg && s && salt_val)
{
one_test (n, e, d, sha_alg, msg, s, salt_val);
ntests++;
if (!(ntests % 256))
show_note ("%d of %d tests done\n", ntests, N_TESTS);
xfree (sha_alg); sha_alg = NULL;
xfree (msg); msg = NULL;
xfree (s); s = NULL;
xfree (salt_val); salt_val = NULL;
}
}
xfree (n);
xfree (e);
xfree (d);
xfree (sha_alg);
xfree (msg);
xfree (s);
xfree (salt_val);
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-rsa-pss.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_rsa_pss (fname);
stop_timer ();
xfree (fname);
info ("All tests completed in %s. Errors: %d\n",
elapsed_time (1), error_count);
return !!error_count;
}