gpgsm: Add new validation model "steed".
authorWerner Koch <wk@gnupg.org>
Wed, 7 Dec 2011 15:15:15 +0000 (16:15 +0100)
committerWerner Koch <wk@gnupg.org>
Wed, 7 Dec 2011 15:15:15 +0000 (16:15 +0100)
* sm/gpgsm.h (VALIDATE_FLAG_STEED): New.
* sm/gpgsm.c (gpgsm_parse_validation_model): Add model "steed".
* sm/server.c (option_handler): Allow validation model "steed".
* sm/certlist.c (gpgsm_cert_has_well_known_private_key): New.
* sm/certchain.c (do_validate_chain): Handle the
well-known-private-key attribute.  Support the "steed" model.
(gpgsm_validate_chain): Ditto.
* sm/verify.c (gpgsm_verify): Return "steed" in the trust status line.
* sm/keylist.c (list_cert_colon): Print the new 'w' flag.
--

This is the first part of changes to implement the STEED proposal as
described at http://g10code.com/steed.html .  The idea for X.509 is
not to use plain self-signed certificates but certificates signed by a
dummy CA (i.e. one for which the private key is known).  Having a
single CA as an indication for the use of STEED might help other X.509
implementations to implement STEED.

doc/DETAILS
doc/gpgsm.texi
sm/certchain.c
sm/certlist.c
sm/gpgsm.c
sm/gpgsm.h
sm/keylist.c
sm/server.c
sm/verify.c

index 2e6874e..ddf7438 100644 (file)
@@ -58,6 +58,10 @@ record; gpg2 does this by default and the option is a dummy.
                u = The key is ultimately valid.  This often means
                    that the secret key is available, but any key may
                    be marked as ultimately valid.
+                w = The key has a well known private part.
+                s = The key has special validity.  This means that it
+                    might be self-signed and expected to be used in
+                    the STEED sytem.
 
             If the validity information is given for a UID or UAT
             record, it describes the validity calculated based on this
@@ -347,6 +351,7 @@ more arguments in future versions.
            "pgp"   for the standard PGP WoT.
           "shell" for the standard X.509 model.
           "chain" for the chain model.
+           "steed" for the STEED model.
 
         Note that we use the term "TRUST_" in the status names for
         historic reasons; we now speak of validity.
index 8e25baf..bdb0378 100644 (file)
@@ -451,10 +451,11 @@ address and the time when you verified the signature.
 @item --validation-model @var{name}
 @opindex validation-model
 This option changes the default validation model.  The only possible
-values are "shell" (which is the default) and "chain" which forces the
-use of the chain model.  The chain model is also used if an option in
-the @file{trustlist.txt} or an attribute of the certificate requests it.
-However the standard model (shell) is in that case always tried first.
+values are "shell" (which is the default), "chain" which forces the
+use of the chain model and "steed" for a new simplified model.  The
+chain model is also used if an option in the @file{trustlist.txt} or
+an attribute of the certificate requests it.  However the standard
+model (shell) is in that case always tried first.
 
 @item --ignore-cert-extension @var{oid}
 @opindex ignore-cert-extension
index 1a26325..54c7a57 100644 (file)
@@ -1,6 +1,6 @@
 /* certchain.c - certificate chain validation
  * Copyright (C) 2001, 2002, 2003, 2004, 2005,
- *               2006, 2007, 2008 Free Software Foundation, Inc.
+ *               2006, 2007, 2008, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -1193,6 +1193,7 @@ ask_marktrusted (ctrl_t ctrl, ksba_cert_t cert, int listmode)
 
    VALIDATE_FLAG_NO_DIRMNGR  - Do not do any dirmngr isvalid checks.
    VALIDATE_FLAG_CHAIN_MODEL - Check according to chain model.
+   VALIDATE_FLAG_STEED       - Check according to the STEED model.
 */
 static int
 do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
@@ -1305,13 +1306,21 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
              We used to do this only later but changed it to call the
              check right here so that we can access special flags
              associated with that specific root certificate.  */
-          istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert, NULL,
-                                                rootca_flags);
+          if (gpgsm_cert_has_well_known_private_key (subject_cert))
+            {
+              memset (rootca_flags, 0, sizeof *rootca_flags);
+              istrusted_rc = ((flags & VALIDATE_FLAG_STEED)
+                              ? 0 : gpg_error (GPG_ERR_NOT_TRUSTED));
+            }
+          else
+            istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert, NULL,
+                                                  rootca_flags);
           audit_log_cert (ctrl->audit, AUDIT_ROOT_TRUSTED,
                           subject_cert, istrusted_rc);
           /* If the chain model extended attribute is used, make sure
              that our chain model flag is set. */
-          if (has_validation_model_chain (subject_cert, listmode, listfp))
+          if (!(flags & VALIDATE_FLAG_STEED)
+              && has_validation_model_chain (subject_cert, listmode, listfp))
             rootca_flags->chain_model = 1;
         }
 
@@ -1383,7 +1392,7 @@ 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. */
-          if (is_qualified == -1)
+          if (is_qualified == -1 && !(flags & VALIDATE_FLAG_STEED))
             {
               gpg_error_t err;
               size_t buflen;
@@ -1437,8 +1446,11 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
                  expired it does not make much sense to ask the user
                  whether we wants to trust the root certificate.  We
                  should do this only if the certificate under question
-                 will then be usable.  */
+                 will then be usable.  If the certificate has a well
+                 known private key asking the user does not make any
+                 sense.  */
               if ( !any_expired
+                   && !gpgsm_cert_has_well_known_private_key (subject_cert)
                    && (!listmode || !already_asked_marktrusted (subject_cert))
                    && ask_marktrusted (ctrl, subject_cert, listmode) )
                 rc = 0;
@@ -1455,6 +1467,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
           /* Check for revocations etc. */
           if ((flags & VALIDATE_FLAG_NO_DIRMNGR))
             ;
+          else if ((flags & VALIDATE_FLAG_STEED))
+            ; /* Fixme: check revocations via DNS.  */
           else if (opt.no_trusted_cert_crl_check || rootca_flags->relax)
             ;
           else
@@ -1586,8 +1600,16 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
                performance reasons. */
             if (is_root)
               {
-                istrusted_rc = gpgsm_agent_istrusted (ctrl, issuer_cert, NULL,
-                                                      rootca_flags);
+                if (gpgsm_cert_has_well_known_private_key (issuer_cert))
+                  {
+                    memset (rootca_flags, 0, sizeof *rootca_flags);
+                    istrusted_rc = ((flags & VALIDATE_FLAG_STEED)
+                                    ? 0 : gpg_error (GPG_ERR_NOT_TRUSTED));
+                  }
+                else
+                  istrusted_rc = gpgsm_agent_istrusted
+                    (ctrl, issuer_cert, NULL, rootca_flags);
+
                 if (!istrusted_rc && rootca_flags->relax)
                   {
                     /* Ignore the error due to the relax flag.  */
@@ -1627,6 +1649,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
          be fixed. */
       if ((flags & VALIDATE_FLAG_NO_DIRMNGR))
         rc = 0;
+      else if ((flags & VALIDATE_FLAG_STEED))
+        rc = 0; /* Fixme: XXX */
       else if (is_root && (opt.no_trusted_cert_crl_check
                            || (!istrusted_rc && rootca_flags->relax)))
         rc = 0;
@@ -1722,7 +1746,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
      capability of the certificate under question, store the result as
      user data in all certificates of the chain.  We do this even if the
      validation itself failed.  */
-  if (is_qualified != -1)
+  if (is_qualified != -1 && !(flags & VALIDATE_FLAG_STEED))
     {
       gpg_error_t err;
       chain_item_t ci;
@@ -1780,8 +1804,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
    do_validate_chain.  This function is a wrapper to handle a root
    certificate with the chain_model flag set.  If RETFLAGS is not
    NULL, flags indicating now the verification was done are stored
-   there.  The only defined flag for RETFLAGS is
-   VALIDATE_FLAG_CHAIN_MODEL.
+   there.  The only defined vits for RETFLAGS are
+   VALIDATE_FLAG_CHAIN_MODEL and VALIDATE_FLAG_STEED.
 
    If you are verifying a signature you should set CHECKTIME to the
    creation time of the signature.  If your are verifying a
@@ -1801,16 +1825,27 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
   if (!retflags)
     retflags = &dummy_retflags;
 
+  /* If the session requested a certain validation mode make sure the
+     corresponding flags are set.  */
   if (ctrl->validation_model == 1)
     flags |= VALIDATE_FLAG_CHAIN_MODEL;
+  else if (ctrl->validation_model == 2)
+    flags |= VALIDATE_FLAG_STEED;
 
+  /* If the chain model was forced, set this immediately into
+     RETFLAGS.  */
   *retflags = (flags & VALIDATE_FLAG_CHAIN_MODEL);
+
   memset (&rootca_flags, 0, sizeof rootca_flags);
 
   rc = do_validate_chain (ctrl, cert, checktime,
                           r_exptime, listmode, listfp, flags,
                           &rootca_flags);
-  if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED
+  if (!rc && (flags & VALIDATE_FLAG_STEED))
+    {
+      *retflags |= VALIDATE_FLAG_STEED;
+    }
+  else if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED
       && !(flags & VALIDATE_FLAG_CHAIN_MODEL)
       && (rootca_flags.valid && rootca_flags.chain_model))
     {
@@ -1824,6 +1859,8 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
 
   if (opt.verbose)
     do_list (0, listmode, listfp, _("validation model used: %s"),
+             (*retflags & VALIDATE_FLAG_STEED)?
+             "steed" :
              (*retflags & VALIDATE_FLAG_CHAIN_MODEL)?
              _("chain"):_("shell"));
 
index 0e90319..241364a 100644 (file)
@@ -1,6 +1,6 @@
 /* certlist.c - build list of certificates
  * Copyright (C) 2001, 2003, 2004, 2005, 2007,
- *               2008 Free Software Foundation, Inc.
+ *               2008, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -210,6 +210,21 @@ gpgsm_cert_use_ocsp_p (ksba_cert_t cert)
 }
 
 
+/* Return true if CERT has the well known private key extension.  */
+int
+gpgsm_cert_has_well_known_private_key (ksba_cert_t cert)
+{
+  int idx;
+  const char *oid;
+
+  for (idx=0; !ksba_cert_get_extension (cert, idx,
+                                        &oid, NULL, NULL, NULL);idx++)
+    if (!strcmp (oid, "1.3.6.1.4.1.11591.2.2.2") )
+      return 1; /* Yes.  */
+  return 0; /* No.  */
+}
+
+
 static int
 same_subject_issuer (const char *subject, const char *issuer, ksba_cert_t cert)
 {
index dc9f2e0..7164f42 100644 (file)
@@ -2004,6 +2004,8 @@ gpgsm_parse_validation_model (const char *model)
     return 0;
   else if ( !ascii_strcasecmp (model, "chain") )
     return 1;
+  else if ( !ascii_strcasecmp (model, "steed") )
+    return 2;
   else
     return -1;
 }
index 31cd951..6c68af7 100644 (file)
@@ -195,7 +195,9 @@ struct server_control_s
                          certificates up the chain (0 = none, 1 = only
                          signer) */
   int use_ocsp;       /* Set to true if OCSP should be used. */
-  int validation_model; /* Set to 1 for the chain model.  */
+  int validation_model; /* 0 := standard model (shell),
+                           1 := chain model,
+                           2 := STEED model. */
 };
 
 
@@ -307,7 +309,7 @@ int gpgsm_create_cms_signature (ctrl_t ctrl,
 /* Flags used with  gpgsm_validate_chain.  */
 #define VALIDATE_FLAG_NO_DIRMNGR  1
 #define VALIDATE_FLAG_CHAIN_MODEL 2
-
+#define VALIDATE_FLAG_STEED       4
 
 int gpgsm_walk_cert_chain (ctrl_t ctrl,
                            ksba_cert_t start, ksba_cert_t *r_next);
@@ -326,6 +328,7 @@ int gpgsm_cert_use_verify_p (ksba_cert_t cert);
 int gpgsm_cert_use_decrypt_p (ksba_cert_t cert);
 int gpgsm_cert_use_cert_p (ksba_cert_t cert);
 int gpgsm_cert_use_ocsp_p (ksba_cert_t cert);
+int gpgsm_cert_has_well_known_private_key (ksba_cert_t cert);
 int gpgsm_certs_identical_p (ksba_cert_t cert_a, ksba_cert_t cert_b);
 int gpgsm_add_cert_to_certlist (ctrl_t ctrl, ksba_cert_t cert,
                                 certlist_t *listaddr, int is_encrypt_to);
index a502360..42c533a 100644 (file)
@@ -1,6 +1,6 @@
 /* keylist.c - Print certificates in various formats.
- * Copyright (C) 1998, 1999, 2000, 2001, 2003,
- *               2004, 2005, 2008, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2008, 2009,
+ *               2010, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -421,7 +421,12 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
           && *not_after && strcmp (current_time, not_after) > 0 )
         *truststring = 'e';
       else if (valerr)
-        *truststring = 'i';
+        {
+          if (gpgsm_cert_has_well_known_private_key (cert))
+            *truststring = 'w';  /* Well, this is dummy CA.  */
+          else
+            *truststring = 'i';
+        }
       else if (ctrl->with_validation && !is_root)
         *truststring = 'f';
     }
@@ -433,12 +438,17 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
     {
       struct rootca_flags_s dummy_flags;
 
-      rc = gpgsm_agent_istrusted (ctrl, cert, NULL, &dummy_flags);
-      if (!rc)
-        *truststring = 'u';  /* Yes, we trust this one (ultimately). */
-      else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
-        *truststring = 'n';  /* No, we do not trust this one. */
-      /* (in case of an error we can't tell anything.) */
+      if (gpgsm_cert_has_well_known_private_key (cert))
+        *truststring = 'w';  /* Well, this is dummy CA.  */
+      else
+        {
+          rc = gpgsm_agent_istrusted (ctrl, cert, NULL, &dummy_flags);
+          if (!rc)
+            *truststring = 'u';  /* Yes, we trust this one (ultimately). */
+          else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
+            *truststring = 'n';  /* No, we do not trust this one. */
+          /* (in case of an error we can't tell anything.) */
+        }
     }
 
   if (*truststring)
index 19c4a16..385eb53 100644 (file)
@@ -277,7 +277,7 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
   else if (!strcmp (key, "validation-model"))
     {
       int i = gpgsm_parse_validation_model (value);
-      if ( i >= 0 && i <= 1 )
+      if ( i >= 0 && i <= 2 )
         ctrl->validation_model = i;
       else
         err = gpg_error (GPG_ERR_ASS_PARAMETER);
index c77eb57..1173f66 100644 (file)
@@ -624,6 +624,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
       }
 
       gpgsm_status (ctrl, STATUS_TRUST_FULLY,
+                    (verifyflags & VALIDATE_FLAG_STEED)?
+                    "0 steed":
                     (verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
                     "0 chain": "0 shell");