From 4a36adaa64311a42eb78d9e52390df489454cafb Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 3 Jul 2020 15:47:55 +0200 Subject: [PATCH] sm: Exclude rsaPSS from de-vs compliance mode. * common/compliance.h (PK_ALGO_FLAG_RSAPSS): New. * common/compliance.c (gnupg_pk_is_compliant): Add arg alog_flags and test rsaPSS. Adjust all callers. * common/util.c (pubkey_algo_to_string): New. (gnupg_pk_is_allowed): Ditto. * sm/misc.c (gpgsm_ksba_cms_get_sig_val): New wrapper function. (gpgsm_get_hash_algo_from_sigval): New. * sm/certcheck.c (gpgsm_check_cms_signature): Change type of sigval arg. Add arg pkalgoflags. Use the PK_ALGO_FLAG_RSAPSS. * sm/verify.c (gpgsm_verify): Use the new wrapper and new fucntion to also get the algo flags. Pass algo flags along. Change some of the info output to be more like current master. -- Signed-off-by: Werner Koch This backport from master commit 969abcf40cdfc65f3ee859c5e62889e1a8ccde91 also includes some changes taken from commit a759fa963a42e0652134130029217270b6d5d00b (sm: Improve readability of the data verification output.) Signed-off-by: Werner Koch --- common/compliance.c | 12 ++++- common/compliance.h | 8 ++- common/sexputil.c | 17 +++++++ common/util.h | 1 + g10/encrypt.c | 6 +-- g10/keylist.c | 2 +- g10/mainproc.c | 8 +-- g10/pubkey-enc.c | 4 +- g10/sig-check.c | 2 +- g10/sign.c | 3 +- sm/certcheck.c | 73 ++++++++------------------ sm/decrypt.c | 4 +- sm/encrypt.c | 5 +- sm/fingerprint.c | 35 +++++++++++++ sm/gpgsm.h | 10 +++- sm/keylist.c | 5 +- sm/misc.c | 90 ++++++++++++++++++++++++++++++++ sm/sign.c | 2 +- sm/verify.c | 121 +++++++++++++++++++++++++++----------------- 19 files changed, 286 insertions(+), 122 deletions(-) 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; }