aboutsummaryrefslogtreecommitdiffstats
path: root/sm/certcheck.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2020-04-14 13:46:04 +0000
committerWerner Koch <[email protected]>2020-04-14 13:46:04 +0000
commit6c28d9343ea6df9cda1b69e77751a9e958eb3d70 (patch)
treeca46091a945e5b681289815f56193549f0ab3b75 /sm/certcheck.c
parentdirmngr: Support rsaPSS also in the general validate module. (diff)
downloadgnupg-6c28d9343ea6df9cda1b69e77751a9e958eb3d70.tar.gz
gnupg-6c28d9343ea6df9cda1b69e77751a9e958eb3d70.zip
sm: Support rsaPSS verification also for CMS signatures.
* sm/certcheck.c (gpgsm_check_cert_sig): Factor PSS parsing out to ... (extract_pss_params): new. (gpgsm_check_cms_signature): Implement PSS. -- GnuPG-bug-id: 4538
Diffstat (limited to 'sm/certcheck.c')
-rw-r--r--sm/certcheck.c148
1 files changed, 110 insertions, 38 deletions
diff --git a/sm/certcheck.c b/sm/certcheck.c
index effab9ab9..68185332e 100644
--- a/sm/certcheck.c
+++ b/sm/certcheck.c
@@ -270,6 +270,41 @@ uint_from_buffer (const void *buffer, size_t buflen)
}
+/* Extract the hash algorithm and the salt length from the sigval. */
+static gpg_error_t
+extract_pss_params (gcry_sexp_t s_sig, int *r_algo, unsigned int *r_saltlen)
+{
+ gpg_error_t err;
+ gcry_buffer_t ioarray[2] = { {0}, {0} };
+
+ err = gcry_sexp_extract_param (s_sig, "sig-val",
+ "&'hash-algo''salt-length'",
+ ioarray+0, ioarray+1, NULL);
+ if (err)
+ {
+ log_error ("extracting params from PSS failed: %s\n", gpg_strerror (err));
+ return err;
+ }
+
+ *r_algo = hash_algo_from_buffer (ioarray[0].data, ioarray[0].len);
+ *r_saltlen = uint_from_buffer (ioarray[1].data, ioarray[1].len);
+ xfree (ioarray[0].data);
+ xfree (ioarray[1].data);
+ if (*r_saltlen < 20)
+ {
+ log_error ("length of PSS salt too short\n");
+ gcry_sexp_release (s_sig);
+ return gpg_error (GPG_ERR_DIGEST_ALGO);
+ }
+ if (!*r_algo)
+ {
+ return gpg_error (GPG_ERR_DIGEST_ALGO);
+ }
+ /* log_debug ("PSS hash=%d saltlen=%u\n", *r_algo, *r_saltlen); */
+ return 0;
+}
+
+
/* Check the signature on CERT using the ISSUER-CERT. This function
does only test the cryptographic signature and nothing else. It is
assumed that the ISSUER_CERT is valid. */
@@ -320,35 +355,12 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
if (use_pss)
{
- /* Extract the hash algorithm and the salt length from the sigval. */
- gcry_buffer_t ioarray[2] = { {0}, {0} };
-
- rc = gcry_sexp_extract_param (s_sig, "sig-val",
- "&'hash-algo''salt-length'",
- ioarray+0, ioarray+1, NULL);
+ rc = extract_pss_params (s_sig, &algo, &saltlen);
if (rc)
{
gcry_sexp_release (s_sig);
- log_error ("extracting params from PSS failed: %s\n",
- gpg_strerror (rc));
return rc;
}
- algo = hash_algo_from_buffer (ioarray[0].data, ioarray[0].len);
- saltlen = uint_from_buffer (ioarray[1].data, ioarray[1].len);
- xfree (ioarray[0].data);
- xfree (ioarray[1].data);
- if (saltlen < 20)
- {
- log_error ("length of PSS salt too short\n");
- gcry_sexp_release (s_sig);
- return gpg_error (GPG_ERR_DIGEST_ALGO);
- }
- if (!algo)
- {
- gcry_sexp_release (s_sig);
- return gpg_error (GPG_ERR_DIGEST_ALGO);
- }
- /* log_debug ("PSS hash=%d saltlen=%u\n", algo, saltlen); */
}
@@ -409,7 +421,7 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
}
else
{
- /* RSA or DAS: Prepare the hash for verification. */
+ /* RSA or DSA: Prepare the hash for verification. */
gcry_mpi_t frame;
rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
@@ -447,10 +459,14 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
{
int rc;
ksba_sexp_t p;
- gcry_mpi_t frame;
- gcry_sexp_t s_sig, s_hash, s_pkey;
+ gcry_sexp_t s_sig, s_hash, s_pkey, l1;
size_t n;
+ const char *s;
+ int i;
int pkalgo;
+ int use_pss;
+ unsigned int saltlen = 0;
+
if (r_pkalgo)
*r_pkalgo = 0;
@@ -468,6 +484,42 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
return rc;
}
+ /* Check whether rsaPSS is needed. This is indicated in the SIG-VAL
+ * using a flag. Only if we found that flag, we extract the PSS
+ * parameters for SIG-VAL. */
+ use_pss = 0;
+ l1 = gcry_sexp_find_token (s_sig, "flags", 0);
+ if (l1)
+ {
+ /* Note that the flag parser assumes that the list of flags
+ * contains only strings and in particular not sublist. This is
+ * always the case or current libksba. */
+ for (i=1; (s = gcry_sexp_nth_data (l1, i, &n)); i++)
+ if (n == 3 && !memcmp (s, "pss", 3))
+ {
+ use_pss = 1;
+ break;
+ }
+ gcry_sexp_release (l1);
+ if (use_pss)
+ {
+ int algo;
+
+ rc = extract_pss_params (s_sig, &algo, &saltlen);
+ if (rc)
+ {
+ gcry_sexp_release (s_sig);
+ return rc;
+ }
+ if (algo != mdalgo)
+ {
+ log_error ("PSS hash algo mismatch (%d/%d)\n", mdalgo, algo);
+ gcry_sexp_release (s_sig);
+ return gpg_error (GPG_ERR_DIGEST_ALGO);
+ }
+ }
+ }
+
p = ksba_cert_get_public_key (cert);
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
if (!n)
@@ -492,22 +544,42 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
pkalgo = pk_algo_from_sexp (s_pkey);
if (r_pkalgo)
*r_pkalgo = pkalgo;
- rc = do_encode_md (md, mdalgo, pkalgo,
- gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
- if (rc)
+
+ if (use_pss)
{
- gcry_sexp_release (s_sig);
- gcry_sexp_release (s_pkey);
- return rc;
+ rc = gcry_sexp_build (&s_hash, NULL,
+ "(data (flags pss)"
+ "(hash %s %b)"
+ "(salt-length %u))",
+ hash_algo_to_string (mdalgo),
+ (int)gcry_md_get_algo_dlen (mdalgo),
+ gcry_md_read (md, mdalgo),
+ saltlen);
+ if (rc)
+ BUG ();
+ }
+ else
+ {
+ /* RSA or DSA: Prepare the hash for verification. */
+ gcry_mpi_t frame;
+
+ rc = do_encode_md (md, mdalgo, pkalgo,
+ gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
+ if (rc)
+ {
+ gcry_sexp_release (s_sig);
+ gcry_sexp_release (s_pkey);
+ return rc;
+ }
+ /* put hash into the S-Exp s_hash */
+ if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
+ BUG ();
+ gcry_mpi_release (frame);
}
- /* put hash into the S-Exp s_hash */
- if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
- BUG ();
- gcry_mpi_release (frame);
rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
if (DBG_X509)
- log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
+ log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc));
gcry_sexp_release (s_sig);
gcry_sexp_release (s_hash);
gcry_sexp_release (s_pkey);