diff --git a/common/compliance.c b/common/compliance.c
index 49aada144..7dbbbd399 100644
--- a/common/compliance.c
+++ b/common/compliance.c
@@ -96,6 +96,7 @@ gnupg_initialize_compliance (int gnupg_module_name)
* both are compatible from the point of view of this function. */
int
gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
+ unsigned int algo_flags,
gcry_mpi_t key[], unsigned int keylength,
const char *curvename)
{
@@ -148,6 +149,10 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
result = (keylength == 2048
|| keylength == 3072
|| keylength == 4096);
+ /* rsaPSS was not part of the evaluation and thus we don't
+ * claim compliance. */
+ if ((algo_flags & PK_ALGO_FLAG_RSAPSS))
+ result = 0;
break;
case is_dsa:
@@ -197,7 +202,8 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
* they produce, and liberal in what they accept. */
int
gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
- enum pk_use_case use, int algo, gcry_mpi_t key[],
+ enum pk_use_case use, int algo,
+ unsigned int algo_flags, gcry_mpi_t key[],
unsigned int keylength, const char *curvename)
{
int result = 0;
@@ -228,6 +234,10 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
default:
log_assert (!"reached");
}
+ /* rsaPSS was not part of the evaluation and thus we don't
+ * claim compliance. */
+ if ((algo_flags & PK_ALGO_FLAG_RSAPSS))
+ result = 0;
break;
case PUBKEY_ALGO_DSA:
diff --git a/common/compliance.h b/common/compliance.h
index 2076e79cb..21bd230c2 100644
--- a/common/compliance.h
+++ b/common/compliance.h
@@ -48,11 +48,17 @@ enum pk_use_case
PK_USE_SIGNING, PK_USE_VERIFICATION,
};
+/* Flags to distinguish public key algorithm variants. */
+#define PK_ALGO_FLAG_RSAPSS 1 /* Use rsaPSS padding. */
+
+
int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
+ unsigned int algo_flags,
gcry_mpi_t key[], unsigned int keylength,
const char *curvename);
int gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
- enum pk_use_case use, int algo, gcry_mpi_t key[],
+ enum pk_use_case use, int algo,
+ unsigned int algo_flags, gcry_mpi_t key[],
unsigned int keylength, const char *curvename);
int gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance,
cipher_algo_t cipher,
diff --git a/common/sexputil.c b/common/sexputil.c
index 1633022ce..9a79c0573 100644
--- a/common/sexputil.c
+++ b/common/sexputil.c
@@ -642,6 +642,23 @@ pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid)
}
+/* Map a pubkey algo id from gcrypt to a string. This is the same as
+ * gcry_pk_algo_name but makes sure that the ECC algo identifiers are
+ * not all mapped to "ECC". */
+const char *
+pubkey_algo_to_string (int algo)
+{
+ if (algo == GCRY_PK_ECDSA)
+ return "ECDSA";
+ else if (algo == GCRY_PK_ECDH)
+ return "ECDH";
+ else if (algo == GCRY_PK_EDDSA)
+ return "EdDSA";
+ else
+ return gcry_pk_algo_name (algo);
+}
+
+
/* Map a hash algo id from gcrypt to a string. This is the same as
* gcry_md_algo_name but the returned string is lower case, as
* expected by libksba and it avoids some overhead. */
diff --git a/common/util.h b/common/util.h
index 5002039d6..fd8a7dc81 100644
--- a/common/util.h
+++ b/common/util.h
@@ -221,6 +221,7 @@ int get_pk_algo_from_key (gcry_sexp_t key);
int get_pk_algo_from_canon_sexp (const unsigned char *keydata,
size_t keydatalen);
char *pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid);
+const char *pubkey_algo_to_string (int algo);
const char *hash_algo_to_string (int algo);
/*-- convert.c --*/
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 55c67cac4..75bef8b74 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -619,15 +619,15 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
PKT_public_key *pk = pkr->pk;
unsigned int nbits = nbits_from_pk (pk);
- if (!gnupg_pk_is_compliant (opt.compliance,
- pk->pubkey_algo, pk->pkey, nbits, NULL))
+ if (!gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, 0,
+ pk->pkey, nbits, NULL))
log_info (_("WARNING: key %s is not suitable for encryption"
" in %s mode\n"),
keystr_from_pk (pk),
gnupg_compliance_option_string (opt.compliance));
if (compliant
- && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
+ && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey,
nbits, NULL))
compliant = 0;
}
diff --git a/g10/keylist.c b/g10/keylist.c
index 8ff40850b..5b0f7ba5c 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -1340,7 +1340,7 @@ print_compliance_flags (PKT_public_key *pk,
es_fputs (gnupg_status_compliance_flag (CO_GNUPG), es_stdout);
any++;
}
- if (gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
+ if (gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey,
keylength, curvename))
{
es_fprintf (es_stdout, any ? " %s" : "%s",
diff --git a/g10/mainproc.c b/g10/mainproc.c
index a67efd676..79ff21198 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -739,8 +739,8 @@ proc_encrypted (CTX c, PACKET *pkt)
memset (pk, 0, sizeof *pk);
pk->pubkey_algo = i->pubkey_algo;
if (get_pubkey (c->ctrl, pk, i->kid) != 0
- || ! gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
- nbits_from_pk (pk), NULL))
+ || ! gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0,
+ pk->pkey, nbits_from_pk (pk), NULL))
compliant = 0;
release_public_key_parts (pk);
}
@@ -2429,7 +2429,7 @@ check_sig_and_print (CTX c, kbnode_t node)
/* Print compliance warning for Good signatures. */
if (!rc && pk && !opt.quiet
- && !gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo,
+ && !gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, 0,
pk->pkey, nbits_from_pk (pk), NULL))
{
log_info (_("WARNING: This key is not suitable for signing"
@@ -2513,7 +2513,7 @@ check_sig_and_print (CTX c, kbnode_t node)
/* Compute compliance with CO_DE_VS. */
if (pk && is_status_enabled ()
- && gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
+ && gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey,
nbits_from_pk (pk), NULL)
&& gnupg_digest_is_compliant (CO_DE_VS, sig->digest_algo))
write_status_strings (STATUS_VERIFICATION_COMPLIANCE_MODE,
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 7c02f02a3..30a4bc099 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -92,7 +92,7 @@ get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
{
/* Check compliance. */
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
- sk->pubkey_algo,
+ sk->pubkey_algo, 0,
sk->pkey, nbits_from_pk (sk), NULL))
{
log_info (_("key %s is not suitable for decryption"
@@ -133,7 +133,7 @@ get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
/* Check compliance. */
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
- sk->pubkey_algo,
+ sk->pubkey_algo, 0,
sk->pkey, nbits_from_pk (sk), NULL))
{
log_info (_("key %s is not suitable for decryption"
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 44e7871ee..e71e662c2 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -164,7 +164,7 @@ check_signature2 (ctrl_t ctrl,
else if (get_pubkey_for_sig (ctrl, pk, sig, forced_pk))
rc = gpg_error (GPG_ERR_NO_PUBKEY);
else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
- pk->pubkey_algo, pk->pkey,
+ pk->pubkey_algo, 0, pk->pkey,
nbits_from_pk (pk),
NULL))
{
diff --git a/g10/sign.c b/g10/sign.c
index 6e9f68ec0..a71ceda21 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -395,7 +395,8 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
goto leave;
}
- if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pksk->pubkey_algo,
+ if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING,
+ pksk->pubkey_algo, 0,
pksk->pkey, nbits_from_pk (pksk), NULL))
{
log_error (_("key %s may not be used for signing in %s mode\n"),
diff --git a/sm/certcheck.c b/sm/certcheck.c
index 14f78dbe6..12b3ec927 100644
--- a/sm/certcheck.c
+++ b/sm/certcheck.c
@@ -492,69 +492,40 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
int
-gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
- gcry_md_hd_t md, int mdalgo, int *r_pkalgo)
+gpgsm_check_cms_signature (ksba_cert_t cert, gcry_sexp_t s_sig,
+ gcry_md_hd_t md, int mdalgo,
+ unsigned int pkalgoflags, int *r_pkalgo)
{
int rc;
ksba_sexp_t p;
- gcry_sexp_t s_sig, s_hash, s_pkey, l1;
+ gcry_sexp_t s_hash, s_pkey;
size_t n;
- const char *s;
- int i;
int pkalgo;
int use_pss;
unsigned int saltlen = 0;
-
if (r_pkalgo)
*r_pkalgo = 0;
- n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
- if (!n)
+ /* Check whether rsaPSS is needed. This information is indicated in
+ * the SIG-VAL and already provided to us by the caller so that we
+ * do not need to parse this out. */
+ use_pss = !!(pkalgoflags & PK_ALGO_FLAG_RSAPSS);
+ if (use_pss)
{
- log_error ("libksba did not return a proper S-Exp\n");
- return gpg_error (GPG_ERR_BUG);
- }
- rc = gcry_sexp_sscan (&s_sig, NULL, (char*)sigval, n);
- if (rc)
- {
- log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
- return rc;
- }
+ int algo;
- /* 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)
+ rc = extract_pss_params (s_sig, &algo, &saltlen);
+ if (rc)
{
- 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);
- }
+ 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);
}
}
@@ -564,7 +535,6 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
{
log_error ("libksba did not return a proper S-Exp\n");
ksba_free (p);
- gcry_sexp_release (s_sig);
return gpg_error (GPG_ERR_BUG);
}
if (DBG_CRYPTO)
@@ -575,7 +545,6 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
if (rc)
{
log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc));
- gcry_sexp_release (s_sig);
return rc;
}
@@ -605,7 +574,6 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
if (rc)
{
- gcry_sexp_release (s_sig);
gcry_sexp_release (s_pkey);
return rc;
}
@@ -618,7 +586,6 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
if (DBG_X509)
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);
return rc;
diff --git a/sm/decrypt.c b/sm/decrypt.c
index 904a40235..90eba888d 100644
--- a/sm/decrypt.c
+++ b/sm/decrypt.c
@@ -483,7 +483,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
/* Check compliance. */
if (!gnupg_pk_is_allowed (opt.compliance,
PK_USE_DECRYPTION,
- pk_algo, NULL, nbits, NULL))
+ pk_algo, 0, NULL, nbits, NULL))
{
char kidstr[10+1];
@@ -501,7 +501,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
/* Check that all certs are compliant with CO_DE_VS. */
is_de_vs =
(is_de_vs
- && gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL,
+ && gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL,
nbits, NULL));
}
diff --git a/sm/encrypt.c b/sm/encrypt.c
index 6213a6604..f03097c84 100644
--- a/sm/encrypt.c
+++ b/sm/encrypt.c
@@ -480,7 +480,8 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp)
/* Check compliance. */
pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
- if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, NULL, nbits, NULL))
+ if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, 0,
+ NULL, nbits, NULL))
{
char kidstr[10+1];
@@ -495,7 +496,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp)
/* Fixme: When adding ECC we need to provide the curvename and
* the key to gnupg_pk_is_compliant. */
if (compliant
- && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL))
+ && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL, nbits, NULL))
compliant = 0;
rc = encrypt_dek (dek, cl->cert, &encval);
diff --git a/sm/fingerprint.c b/sm/fingerprint.c
index 3a57b7ba5..2e01cf1c0 100644
--- a/sm/fingerprint.c
+++ b/sm/fingerprint.c
@@ -277,6 +277,41 @@ gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
}
+/* This is a wrapper around pubkey_algo_string which takes a KSBA
+ * certificate instead of a Gcrypt public key. Note that this
+ * function may return NULL on error. */
+char *
+gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid)
+{
+ gpg_error_t err;
+ gcry_sexp_t s_pkey;
+ ksba_sexp_t p;
+ size_t n;
+ enum gcry_pk_algos algoid;
+ char *algostr;
+
+ p = ksba_cert_get_public_key (cert);
+ if (!p)
+ return NULL;
+ n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+ if (!n)
+ {
+ xfree (p);
+ return NULL;
+ }
+ err = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n);
+ xfree (p);
+ if (err)
+ return NULL;
+
+ algostr = pubkey_algo_string (s_pkey, r_algoid? &algoid : NULL);
+ if (algostr && r_algoid)
+ *r_algoid = algoid;
+
+ gcry_sexp_release (s_pkey);
+ return algostr;
+}
+
/* For certain purposes we need a certificate id which has an upper
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 268c2d054..d1283440d 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -264,6 +264,7 @@ unsigned long gpgsm_get_short_fingerprint (ksba_cert_t cert,
unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array);
char *gpgsm_get_keygrip_hexstring (ksba_cert_t cert);
int gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits);
+char *gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid);
char *gpgsm_get_certid (ksba_cert_t cert);
@@ -295,8 +296,10 @@ char *gpgsm_format_keydesc (ksba_cert_t cert);
/*-- certcheck.c --*/
int gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert);
-int gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval,
- gcry_md_hd_t md, int hash_algo, int *r_pkalgo);
+int gpgsm_check_cms_signature (ksba_cert_t cert, gcry_sexp_t sigval,
+ gcry_md_hd_t md,
+ int hash_algo, unsigned int pkalgoflags,
+ int *r_pkalgo);
/* fixme: move create functions to another file */
int gpgsm_create_cms_signature (ctrl_t ctrl,
ksba_cert_t cert, gcry_md_hd_t md, int mdalgo,
@@ -438,6 +441,9 @@ gpg_error_t transform_sigval (const unsigned char *sigval, size_t sigvallen,
int mdalgo,
unsigned char **r_newsigval,
size_t *r_newsigvallen);
+gcry_sexp_t gpgsm_ksba_cms_get_sig_val (ksba_cms_t cms, int idx);
+int gpgsm_get_hash_algo_from_sigval (gcry_sexp_t sigval,
+ unsigned int *r_pkalgo_flags);
diff --git a/sm/keylist.c b/sm/keylist.c
index 7961b66fd..8c7fafc28 100644
--- a/sm/keylist.c
+++ b/sm/keylist.c
@@ -361,7 +361,10 @@ print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits,
{
int hashalgo;
- if (gnupg_pk_is_compliant (CO_DE_VS, algo, NULL, nbits, NULL))
+ /* Note that we do not need to test for PK_ALGO_FLAG_RSAPSS because
+ * that is not a property of the key but one of the created
+ * signature. */
+ if (gnupg_pk_is_compliant (CO_DE_VS, algo, 0, NULL, nbits, NULL))
{
hashalgo = gcry_md_map_name (ksba_cert_get_digest_algo (cert));
if (gnupg_digest_is_compliant (CO_DE_VS, hashalgo))
diff --git a/sm/misc.c b/sm/misc.c
index 6d047763b..66d928c6b 100644
--- a/sm/misc.c
+++ b/sm/misc.c
@@ -216,3 +216,93 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
return err;
}
+
+
+/* Wrapper around ksba_cms_get_sig_val to return a gcrypt object
+ * instaed of ksba's canonical s-expression. On errror NULL is return
+ * and in some cases an error message is printed. */
+gcry_sexp_t
+gpgsm_ksba_cms_get_sig_val (ksba_cms_t cms, int idx)
+{
+ gpg_error_t err;
+ ksba_sexp_t sigval;
+ gcry_sexp_t s_sigval;
+ size_t n;
+
+ sigval = ksba_cms_get_sig_val (cms, idx);
+ if (!sigval)
+ return NULL;
+ n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
+ if (!n)
+ {
+ log_error ("%s: libksba did not return a proper S-Exp\n", __func__);
+ ksba_free (sigval);
+ return NULL;
+ }
+ err = gcry_sexp_sscan (&s_sigval, NULL, (char*)sigval, n);
+ ksba_free (sigval);
+ if (err)
+ {
+ log_error ("%s: gcry_sexp_scan failed: %s\n",
+ __func__, gpg_strerror (err));
+ s_sigval = NULL;
+ }
+
+ return s_sigval;
+}
+
+
+/* Return the hash algorithm from the S-expression SIGVAL. Returns 0
+ * if the hash algorithm is not encoded in SIGVAL or it is not
+ * supported by libgcrypt. It further stores flag values for the
+ * public key algorithm at R_PKALGO_FLAGS; the only flag we currently
+ * support is PK_ALGO_FLAG_RSAPSS. */
+int
+gpgsm_get_hash_algo_from_sigval (gcry_sexp_t sigval_arg,
+ unsigned int *r_pkalgo_flags)
+{
+ gcry_sexp_t sigval, l1;
+ size_t n;
+ const char *s;
+ char *string;
+ int hashalgo;
+ int i;
+
+ *r_pkalgo_flags = 0;
+
+ sigval = gcry_sexp_find_token (sigval_arg, "sig-val", 0);
+ if (!sigval)
+ return 0; /* Not a sig-val. */
+
+ /* First check whether this is a rsaPSS signature and return that as
+ * additional info. */
+ l1 = gcry_sexp_find_token (sigval, "flags", 0);
+ if (l1)
+ {
+ /* Note that the flag parser assumes that the list of flags
+ * contains only strings and in particular not a sub-list. This
+ * is always the case for the current libksba. */
+ for (i=1; (s = gcry_sexp_nth_data (l1, i, &n)); i++)
+ if (n == 3 && !memcmp (s, "pss", 3))
+ {
+ *r_pkalgo_flags |= PK_ALGO_FLAG_RSAPSS;
+ break;
+ }
+ gcry_sexp_release (l1);
+ }
+
+ l1 = gcry_sexp_find_token (sigval, "hash", 0);
+ if (!l1)
+ {
+ gcry_sexp_release (sigval);
+ return 0; /* hash algorithm not given in sigval. */
+ }
+ string = gcry_sexp_nth_string (l1, 1);
+ gcry_sexp_release (sigval);
+ if (!string)
+ return 0; /* hash algorithm has no value. */
+ hashalgo = gcry_md_map_name (string);
+ gcry_free (string);
+
+ return hashalgo;
+}
diff --git a/sm/sign.c b/sm/sign.c
index fd6ebe00c..dd7612f27 100644
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -486,7 +486,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
unsigned int nbits;
int pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
- if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo,
+ if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0,
NULL, nbits, NULL))
{
char kidstr[10+1];
diff --git a/sm/verify.c b/sm/verify.c
index 6d2f11055..0fa365fb7 100644
--- a/sm/verify.c
+++ b/sm/verify.c
@@ -1,6 +1,8 @@
/* verify.c - Verify a messages signature
* Copyright (C) 2001, 2002, 2003, 2007,
* 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2001-2019 Werner Koch
+ * Copyright (C) 2015-2020 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -16,6 +18,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
+ * SPDX-License-Identifier: GPL-3.0-or-later
*/
#include
@@ -286,7 +289,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
for (signer=0; ; signer++)
{
char *issuer = NULL;
- ksba_sexp_t sigval = NULL;
+ gcry_sexp_t sigval = NULL;
ksba_isotime_t sigtime, keyexptime;
ksba_sexp_t serial;
char *msgdigest = NULL;
@@ -294,7 +297,11 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
char *ctattr;
int sigval_hash_algo;
int info_pkalgo;
- unsigned int verifyflags;
+ unsigned int nbits;
+ int pkalgo;
+ char *pkalgostr = NULL;
+ char *pkfpr = NULL;
+ unsigned int pkalgoflags, verifyflags;
rc = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
if (!signer && gpg_err_code (rc) == GPG_ERR_NO_DATA
@@ -400,20 +407,19 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
rc = 0;
- sigval = ksba_cms_get_sig_val (cms, signer);
+ sigval = gpgsm_ksba_cms_get_sig_val (cms, signer);
if (!sigval)
{
log_error ("no signature value available\n");
audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
goto next_signer;
}
- sigval_hash_algo = hash_algo_from_sigval (sigval);
+
+ sigval_hash_algo = gpgsm_get_hash_algo_from_sigval (sigval, &pkalgoflags);
if (DBG_X509)
{
- log_debug ("signer %d - signature available (sigval hash=%d)",
- signer, sigval_hash_algo);
- /*log_printhex(sigval, gcry_sexp_canon_len (sigval, 0, NULL, NULL),*/
- /* "sigval "); */
+ log_debug ("signer %d - signature available (sigval hash=%d pkaf=%u)",
+ signer, sigval_hash_algo, pkalgoflags);
}
if (!sigval_hash_algo)
sigval_hash_algo = algo; /* Fallback used e.g. with old libksba. */
@@ -450,49 +456,68 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
goto next_signer;
}
- /* Check compliance. */
- {
- unsigned int nbits;
- int pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
-
- if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
- pk_algo, NULL, nbits, NULL))
- {
- char kidstr[10+1];
-
- snprintf (kidstr, sizeof kidstr, "0x%08lX",
- gpgsm_get_short_fingerprint (cert, NULL));
- log_error (_("key %s may not be used for signing in %s mode\n"),
- kidstr,
- gnupg_compliance_option_string (opt.compliance));
- goto next_signer;
- }
-
- if (! gnupg_digest_is_allowed (opt.compliance, 0, sigval_hash_algo))
- {
- log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
- gcry_md_algo_name (sigval_hash_algo),
- gnupg_compliance_option_string (opt.compliance));
- goto next_signer;
- }
-
- /* Check compliance with CO_DE_VS. */
- if (gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL)
- && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo))
- gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE,
- gnupg_status_compliance_flag (CO_DE_VS));
- }
+ pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
+ pkalgostr = gpgsm_pubkey_algo_string (cert, NULL);
+ pkalgo = gpgsm_get_key_algo_info (cert, &nbits);
log_info (_("Signature made "));
if (*sigtime)
- dump_isotime (sigtime);
+ {
+ /* We take the freedom as noted in RFC3339 to use a space
+ * instead of the "T" delimiter between date and time. We
+ * also append a separate UTC instead of a "Z" or "+00:00"
+ * suffix because that makes it clear to everyone what kind
+ * of time this is. */
+ dump_isotime (sigtime);
+ log_printf (" UTC");
+ }
else
log_printf (_("[date not given]"));
- log_printf (_(" using certificate ID 0x%08lX\n"),
- gpgsm_get_short_fingerprint (cert, NULL));
+ log_info (_(" using %s key %s\n"), pkalgostr, pkfpr);
+ if (opt.verbose)
+ {
+ log_info (_("algorithm:"));
+ log_printf (" %s + %s",
+ pubkey_algo_to_string (pkalgo),
+ gcry_md_algo_name (sigval_hash_algo));
+ if (algo != sigval_hash_algo)
+ log_printf (" (%s)", gcry_md_algo_name (algo));
+ log_printf ("\n");
+ }
audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
+ /* Check compliance. */
+ if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
+ pkalgo, pkalgoflags, NULL, nbits, NULL))
+ {
+ char kidstr[10+1];
+
+ snprintf (kidstr, sizeof kidstr, "0x%08lX",
+ gpgsm_get_short_fingerprint (cert, NULL));
+ log_error (_("key %s may not be used for signing in %s mode\n"),
+ kidstr,
+ gnupg_compliance_option_string (opt.compliance));
+ goto next_signer;
+ }
+
+ if (!gnupg_digest_is_allowed (opt.compliance, 0, sigval_hash_algo))
+ {
+ log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
+ gcry_md_algo_name (sigval_hash_algo),
+ gnupg_compliance_option_string (opt.compliance));
+ goto next_signer;
+ }
+
+ /* Check compliance with CO_DE_VS. */
+ if (gnupg_pk_is_compliant (CO_DE_VS, pkalgo, pkalgoflags,
+ NULL, nbits, NULL)
+ && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo))
+ gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE,
+ gnupg_status_compliance_flag (CO_DE_VS));
+
+
+ /* Now we can check the signature. */
if (msgdigest)
{ /* Signed attributes are available. */
gcry_md_hd_t md;
@@ -545,14 +570,14 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
goto next_signer;
}
- rc = gpgsm_check_cms_signature (cert, sigval, md,
- sigval_hash_algo, &info_pkalgo);
+ rc = gpgsm_check_cms_signature (cert, sigval, md, sigval_hash_algo,
+ pkalgoflags, &info_pkalgo);
gcry_md_close (md);
}
else
{
rc = gpgsm_check_cms_signature (cert, sigval, data_md,
- algo, &info_pkalgo);
+ algo, pkalgoflags, &info_pkalgo);
}
if (rc)
@@ -669,8 +694,10 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
rc = 0;
xfree (issuer);
xfree (serial);
- xfree (sigval);
+ gcry_sexp_release (sigval);
xfree (msgdigest);
+ xfree (pkalgostr);
+ xfree (pkfpr);
ksba_cert_release (cert);
cert = NULL;
}