Merge branch 'STABLE-BRANCH-2-2' into master
[gnupg.git] / sm / keylist.c
index 42c533a..ea2a220 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 
 #include "keydb.h"
 #include "../kbx/keybox.h" /* for KEYBOX_FLAG_* */
-#include "i18n.h"
-#include "tlv.h"
+#include "../common/i18n.h"
+#include "../common/tlv.h"
+#include "../common/compliance.h"
+#include "../common/pkscreening.h"
 
 struct list_external_parm_s
 {
@@ -79,7 +81,7 @@ struct
 
 
 /* Do not print this extension in the list of extensions.  This is set
-   for oids which are already available via ksba fucntions. */
+   for oids which are already available via ksba functions. */
 #define OID_FLAG_SKIP 1
 /* The extension is a simple UTF8String and should be printed.  */
 #define OID_FLAG_UTF8 2
@@ -237,6 +239,38 @@ print_key_data (ksba_cert_t cert, estream_t fp)
 #endif
 }
 
+
+/* Various public key screenings.  (Right now just ROCA).  With
+ * COLON_MODE set the output is formatted for use in the compliance
+ * field of a colon listing.  */
+static void
+print_pk_screening (ksba_cert_t cert, int colon_mode, estream_t fp)
+{
+  gpg_error_t err;
+  gcry_mpi_t modulus;
+
+  modulus = gpgsm_get_rsa_modulus (cert);
+  if (modulus)
+    {
+      err = screen_key_for_roca (modulus);
+      if (!err)
+        ;
+      else if (gpg_err_code (err) == GPG_ERR_TRUE)
+        {
+          if (colon_mode)
+            es_fprintf (fp, colon_mode > 1? " %d":"%d", 6001);
+          else
+            es_fprintf (fp, "    screening: ROCA vulnerability detected\n");
+        }
+      else if (!colon_mode)
+        es_fprintf (fp, "    screening: [ROCA check failed: %s]\n",
+                    gpg_strerror (err));
+      gcry_mpi_release (modulus);
+    }
+
+}
+
+
 static void
 print_capabilities (ksba_cert_t cert, estream_t fp)
 {
@@ -288,8 +322,6 @@ print_capabilities (ksba_cert_t cert, estream_t fp)
     es_putc ('S', fp);
   if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN))
     es_putc ('C', fp);
-
-  es_putc (':', fp);
 }
 
 
@@ -346,6 +378,23 @@ email_kludge (const char *name)
 }
 
 
+/* 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,
+                        estream_t fp)
+{
+  int any = 0;
+
+  if (gnupg_pk_is_compliant (CO_DE_VS, algo, NULL, nbits, NULL))
+    {
+      es_fputs (gnupg_status_compliance_flag (CO_DE_VS), fp);
+      any++;
+    }
+
+  if (opt.with_key_screening)
+    print_pk_screening (cert, 1+any, fp);
+}
 
 
 /* List one certificate in colon mode */
@@ -457,7 +506,6 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
   algo = gpgsm_get_key_algo_info (cert, &nbits);
   es_fprintf (fp, ":%u:%d:%s:", nbits, algo, fpr+24);
 
-  /* We assume --fixed-list-mode for gpgsm */
   ksba_cert_get_validity (cert, 0, t);
   print_time (t, fp);
   es_putc (':', fp);
@@ -495,24 +543,33 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
   es_putc (':', fp);
   /* Field 12, capabilities: */
   print_capabilities (cert, fp);
+  es_putc (':', fp);
   /* Field 13, not used: */
   es_putc (':', fp);
-  if (have_secret)
+  /* Field 14, not used: */
+  es_putc (':', fp);
+  if (have_secret || ctrl->with_secret)
     {
       char *cardsn;
 
       p = gpgsm_get_keygrip_hexstring (cert);
-      if (!gpgsm_agent_keyinfo (ctrl, p, &cardsn) && cardsn)
+      if (!gpgsm_agent_keyinfo (ctrl, p, &cardsn)
+          && (cardsn || ctrl->with_secret))
         {
-          /* Field 14, not used: */
-          es_putc (':', fp);
-          /* Field 15:  Token serial number.  */
-          es_fputs (cardsn, fp);
-          es_putc (':', fp);
+          /* Field 15:  Token serial number or secret key indicator.  */
+          if (cardsn)
+            es_fputs (cardsn, fp);
+          else if (ctrl->with_secret)
+            es_putc ('+', fp);
         }
       xfree (cardsn);
       xfree (p);
     }
+  es_putc (':', fp);  /* End of field 15. */
+  es_putc (':', fp);  /* End of field 16. */
+  es_putc (':', fp);  /* End of field 17. */
+  print_compliance_flags (cert, algo, nbits, fp);
+  es_putc (':', fp);  /* End of field 18. */
   es_putc ('\n', fp);
 
   /* FPR record */
@@ -525,16 +582,16 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
   xfree (fpr); fpr = NULL; chain_id = NULL;
   xfree (chain_id_buffer); chain_id_buffer = NULL;
 
-  if (opt.with_key_data)
+  /* Always print the keygrip.  */
+  if ( (p = gpgsm_get_keygrip_hexstring (cert)))
     {
-      if ( (p = gpgsm_get_keygrip_hexstring (cert)))
-        {
-          es_fprintf (fp, "grp:::::::::%s:\n", p);
-          xfree (p);
-        }
-      print_key_data (cert, fp);
+      es_fprintf (fp, "grp:::::::::%s:\n", p);
+      xfree (p);
     }
 
+  if (opt.with_key_data)
+    print_key_data (cert, fp);
+
   kludge_uid = NULL;
   for (idx=0; (p = ksba_cert_get_subject (cert,idx)); idx++)
     {
@@ -1238,6 +1295,9 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret,
         }
     }
 
+  if (opt.with_key_screening)
+    print_pk_screening (cert, 0, fp);
+
   if (have_secret)
     {
       char *cardsn;
@@ -1277,7 +1337,7 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret,
 }
 
 
-/* Same as standard mode mode list all certifying certs too. */
+/* Same as standard mode list all certifying certs too. */
 static void
 list_cert_chain (ctrl_t ctrl, KEYDB_HANDLE hd,
                  ksba_cert_t cert, int raw_mode,
@@ -1326,7 +1386,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
   int have_secret;
   int want_ephemeral = ctrl->with_ephemeral_keys;
 
-  hd = keydb_new (0);
+  hd = keydb_new ();
   if (!hd)
     {
       log_error ("keydb_new failed\n");
@@ -1359,7 +1419,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
           rc = classify_user_id (sl->d, desc+ndesc, 0);
           if (rc)
             {
-              log_error ("key `%s' not found: %s\n",
+              log_error ("key '%s' not found: %s\n",
                          sl->d, gpg_strerror (rc));
               rc = 0;
             }
@@ -1398,7 +1458,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
 
   /* Suppress duplicates at least when they follow each other.  */
   lastresname = NULL;
-  while (!(rc = keydb_search (hd, desc, ndesc)))
+  while (!(rc = keydb_search (ctrl, hd, desc, ndesc)))
     {
       unsigned int validity;
 
@@ -1459,8 +1519,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
             }
         }
 
-      if (!mode
-          || ((mode & 1) && !have_secret)
+      if (!mode          || ((mode & 1) && !have_secret)
           || ((mode & 2) && have_secret)  )
         {
           if (ctrl->with_colons)
@@ -1504,7 +1563,7 @@ list_external_cb (void *cb_value, ksba_cert_t cert)
 {
   struct list_external_parm_s *parm = cb_value;
 
-  if (keydb_store_cert (cert, 1, NULL))
+  if (keydb_store_cert (parm->ctrl, cert, 1, NULL))
     log_error ("error storing certificate as ephemeral\n");
 
   if (parm->print_header)