From 14383ff052ff5013ba40b6d53b91a1525b5ae2d8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 12 May 2025 17:36:28 +0200 Subject: [PATCH] gpgsm: Make use of the de-vs flag in the trustlist.txt. * sm/gpgsm.h (COMPAT_DE_VS_TRUSTLIST): New. * sm/gpgsm.c (compatibility_flags): Add flag "de-vs-trustlist" * sm/call-agent.c (istrusted_status_cb): Apply the compatibility flag. * sm/certchain.c (do_validate_chain): Handle the "de-vs" flag similar to the "qualified" flag. * sm/keylist.c (cert_has_de_vs_flag): New. (print_compliance_flags): Print compliance string only if the flag is set or if the compatibiliy flag is set. -- In de-vs compliance mode we now look at the de-vs flag from the trustlist.txt and print a certificate as VS-NfD compliant only if this flag is set. Obviously this now requires that --with-validation has been used. To revert to the old behaviour a new compatibility flag can be set. The advantage of this new behaviour is that also non-compliant certificates can be entered into the trustlist.txt and such certs can be used with the usual warning that the cert is not VS-NfD compliant. --- sm/call-agent.c | 4 ++++ sm/certchain.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++-- sm/gpgsm.c | 1 + sm/gpgsm.h | 2 ++ sm/keylist.c | 26 ++++++++++++++++---- 5 files changed, 90 insertions(+), 6 deletions(-) diff --git a/sm/call-agent.c b/sm/call-agent.c index 4ad7059a5..75ae3f677 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -967,6 +967,10 @@ istrusted_status_cb (void *opaque, const char *line) return gpg_error_from_syserror (); strcpy (ci->fpr, s); memset (&ci->flags, 0, sizeof ci->flags); + + if ((opt.compat_flags & COMPAT_DE_VS_TRUSTLIST)) + parm->flags.de_vs = 1; + ci->next = parm->cache; parm->cache = ci; } diff --git a/sm/certchain.c b/sm/certchain.c index 334af8d2d..69a68b40f 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -1572,6 +1572,9 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg, int is_qualified = -1; /* Indicates whether the certificate stems from a qualified root certificate. -1 = unknown, 0 = no, 1 = yes. */ + int is_de_vs = -1; /* Indicates whether the certificate stems + from a de_vs compliant root certificate. + -1 = unknown, 0 = no, 1 = yes. */ chain_item_t chain = NULL; /* A list of all certificates in the chain. */ @@ -1743,8 +1746,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg, /* Set the flag for qualified signatures. This flag is - deduced from a list of root certificates allowed for - qualified signatures. */ + * deduced from a list of root certificates allowed for + * qualified signatures or flags from the trustlist.txt. */ if (is_qualified == -1 && !(flags & VALIDATE_FLAG_STEED)) { gpg_error_t err; @@ -1790,6 +1793,40 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg, } } + /* Set a flag for de_vs compliant certificates. This flag + * is deduced from trustlist.txt flags de_vs. */ + if (is_de_vs == -1 && !(flags & VALIDATE_FLAG_STEED)) + { + gpg_error_t err; + size_t buflen; + char buf[1]; + + if (!ksba_cert_get_user_data (cert, "is_de_vs", + &buf, sizeof (buf), + &buflen) && buflen) + { + /* We already checked this for this certificate, + * thus we simply take it from the user data. */ + is_de_vs = !!*buf; + } + else + { + /* We check by looking at the root ca flag. */ + is_de_vs = !!rootca_flags->de_vs; + if (is_de_vs != -1 ) + { + /* Cache the result but don't care too much + * about an error. */ + buf[0] = !!is_de_vs; + err = ksba_cert_set_user_data (subject_cert, + "is_de_vs", buf, 1); + if (err) + log_error ("set_user_data(is_de_vs) failed: %s\n", + gpg_strerror (err)); + } + } + } + /* Act on the check for a trusted root certificates. */ rc = istrusted_rc; @@ -2177,6 +2214,28 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg, } } + /* The same as above for the de-vs flag. */ + if (is_de_vs != -1 && !(flags & VALIDATE_FLAG_STEED)) + { + gpg_error_t err; + chain_item_t ci; + char buf[1]; + + buf[0] = !!is_de_vs; + + for (ci = chain; ci; ci = ci->next) + { + err = ksba_cert_set_user_data (ci->cert, "is_de_vs", buf, 1); + if (err) + { + log_error ("set_user_data(is_der_vs) failed: %s\n", + gpg_strerror (err)); + if (!rc) + rc = err; + } + } + } + /* If auditing has been enabled, record what is in the chain. */ if (ctrl->audit) { diff --git a/sm/gpgsm.c b/sm/gpgsm.c index ea37a4a4c..db900b93a 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -471,6 +471,7 @@ static struct compatibility_flags_s compatibility_flags [] = { COMPAT_ALLOW_KA_TO_ENCR, "allow-ka-to-encr" }, { COMPAT_NO_CHAIN_CACHE, "no-chain-cache" }, { COMPAT_NO_KEYINFO_CACHE, "no-keyinfo-cache" }, + { COMPAT_DE_VS_TRUSTLIST, "de-vs-trustlist" }, { 0, NULL } }; diff --git a/sm/gpgsm.h b/sm/gpgsm.h index f239f21b6..c81e36347 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -188,6 +188,8 @@ struct #define COMPAT_NO_CHAIN_CACHE 2 /* Ditto. But here to disable the keyinfo and istrusted cache. */ #define COMPAT_NO_KEYINFO_CACHE 4 +/* Assume that all trustlist.txt entries have the de-vs flag set. */ +#define COMPAT_DE_VS_TRUSTLIST 8 /* Forward declaration for an object defined in server.c */ struct server_local_s; diff --git a/sm/keylist.c b/sm/keylist.c index 4e2d99920..c2f201c8e 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -371,20 +371,38 @@ email_kludge (const char *name) } +/* Check whether the certificate has the de_vs flag set. */ +static int +cert_has_de_vs_flag (ksba_cert_t cert) +{ + gpg_error_t err; + size_t buflen; + char buffer[1]; + + if ((opt.compat_flags & COMPAT_DE_VS_TRUSTLIST)) + return 1; + + err = ksba_cert_get_user_data (cert, "is_de_vs", + &buffer, sizeof (buffer), &buflen); + if (!err && buflen && *buffer) + return 1; + + return 0; +} + /* Print the compliance flags to field 18. ALGO is the gcrypt algo * number. NBITS is the length of the key in bits. */ static void print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits, const char *curvename, estream_t fp) { - int hashalgo; - /* 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, curvename)) + if (cert_has_de_vs_flag (cert) + && gnupg_pk_is_compliant (CO_DE_VS, algo, 0, NULL, nbits, curvename)) { - hashalgo = gcry_md_map_name (ksba_cert_get_digest_algo (cert)); + int hashalgo = gcry_md_map_name (ksba_cert_get_digest_algo (cert)); if (gnupg_digest_is_compliant (CO_DE_VS, hashalgo)) { es_fputs (gnupg_status_compliance_flag (CO_DE_VS), fp);