sm: Fix certificate creation with key on card.
[gnupg.git] / dirmngr / ocsp.c
index ec727f0..79c252d 100644 (file)
@@ -30,7 +30,6 @@
 #include "validate.h"
 #include "certcache.h"
 #include "ocsp.h"
-#include "estream.h"
 
 /* The maximum size we allow as a response from an OCSP reponder. */
 #define MAX_RESPONSE_SIZE 65536
 static const char oidstr_ocsp[] = "1.3.6.1.5.5.7.48.1";
 
 
-/* Telesec attribute used to implement a positive confirmation. 
+/* Telesec attribute used to implement a positive confirmation.
 
    CertHash ::= SEQUENCE {
       HashAlgorithm    AlgorithmIdentifier,
       certificateHash OCTET STRING }
  */
-static const char oidstr_certHash[] = "1.3.36.8.3.13";
+/* static const char oidstr_certHash[] = "1.3.36.8.3.13"; */
 
 
 
@@ -84,7 +83,7 @@ read_response (estream_t fp, unsigned char **r_buffer, size_t *r_buflen)
           return err;
         }
       if ( !(nread == bufsize-nbytes && !es_feof (fp)))
-        { /* Response succesfully received. */
+        { /* Response successfully received. */
           nbytes += nread;
           *r_buffer = buffer;
           *r_buflen = nbytes;
@@ -117,7 +116,7 @@ read_response (estream_t fp, unsigned char **r_buffer, size_t *r_buflen)
 
 /* Construct an OCSP request, send it to the configured OCSP responder
    and parse the response. On success the OCSP context may be used to
-   further process the reponse. */
+   further process the response. */
 static gpg_error_t
 do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
                  const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert)
@@ -133,6 +132,14 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
 
   (void)ctrl;
 
+  if (dirmngr_use_tor ())
+    {
+      /* For now we do not allow OCSP via Tor due to possible privacy
+         concerns.  Needs further research.  */
+      log_error (_("OCSP request not possible due to Tor mode\n"));
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
+
   if (opt.disable_http)
     {
       log_error (_("OCSP request not possible due to disabled HTTP\n"));
@@ -165,25 +172,28 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
     }
 
  once_more:
-  err = http_open (&http, HTTP_REQ_POST, url, NULL,
-                   (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0),
-                   opt.http_proxy, NULL, NULL, NULL);
+  err = http_open (ctrl, &http, HTTP_REQ_POST, url, NULL, NULL,
+                   ((opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)
+                    | (dirmngr_use_tor ()? HTTP_FLAG_FORCE_TOR:0)
+                    | (opt.disable_ipv4? HTTP_FLAG_IGNORE_IPv4 : 0)
+                    | (opt.disable_ipv6? HTTP_FLAG_IGNORE_IPv6 : 0)),
+                   ctrl->http_proxy, NULL, NULL, NULL);
   if (err)
     {
-      log_error (_("error connecting to `%s': %s\n"), url, gpg_strerror (err));
+      log_error (_("error connecting to '%s': %s\n"), url, gpg_strerror (err));
       xfree (free_this);
       return err;
     }
 
   es_fprintf (http_get_write_ptr (http),
              "Content-Type: application/ocsp-request\r\n"
-             "Content-Length: %lu\r\n", 
+             "Content-Length: %lu\r\n",
              (unsigned long)requestlen );
   http_start_data (http);
   if (es_fwrite (request, requestlen, 1, http_get_write_ptr (http)) != 1)
     {
       err = gpg_error_from_errno (errno);
-      log_error ("error sending request to `%s': %s\n", url, strerror (errno));
+      log_error ("error sending request to '%s': %s\n", url, strerror (errno));
       http_close (http, 0);
       xfree (request);
       xfree (free_this);
@@ -196,7 +206,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
   if (err || http_get_status_code (http) != 200)
     {
       if (err)
-        log_error (_("error reading HTTP response for `%s': %s\n"),
+        log_error (_("error reading HTTP response for '%s': %s\n"),
                    url, gpg_strerror (err));
       else
         {
@@ -206,8 +216,8 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
             case 302:
               {
                 const char *s = http_get_header (http, "Location");
-                
-                log_info (_("URL `%s' redirected to `%s' (%u)\n"),
+
+                log_info (_("URL '%s' redirected to '%s' (%u)\n"),
                           url, s?s:"[none]", http_get_status_code (http));
                 if (s && *s && redirects_left-- )
                   {
@@ -229,7 +239,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
               break;
 
             default:
-              log_error (_("error accessing `%s': http status %u\n"),
+              log_error (_("error accessing '%s': http status %u\n"),
                          url, http_get_status_code (http));
               err = gpg_error (GPG_ERR_NO_DATA);
               break;
@@ -244,7 +254,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
   http_close (http, 0);
   if (err)
     {
-      log_error (_("error reading HTTP response for `%s': %s\n"),
+      log_error (_("error reading HTTP response for '%s': %s\n"),
                  url, gpg_strerror (err));
       xfree (free_this);
       return err;
@@ -254,7 +264,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
                                   &response_status);
   if (err)
     {
-      log_error (_("error parsing OCSP response for `%s': %s\n"),
+      log_error (_("error parsing OCSP response for '%s': %s\n"),
                  url, gpg_strerror (err));
       xfree (response);
       xfree (free_this);
@@ -264,30 +274,30 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
   switch (response_status)
     {
     case KSBA_OCSP_RSPSTATUS_SUCCESS:      t = "success"; break;
-    case KSBA_OCSP_RSPSTATUS_MALFORMED:    t = "malformed"; break;  
-    case KSBA_OCSP_RSPSTATUS_INTERNAL:     t = "internal error"; break;  
-    case KSBA_OCSP_RSPSTATUS_TRYLATER:     t = "try later"; break;      
-    case KSBA_OCSP_RSPSTATUS_SIGREQUIRED:  t = "must sign request"; break;  
-    case KSBA_OCSP_RSPSTATUS_UNAUTHORIZED: t = "unauthorized"; break;  
-    case KSBA_OCSP_RSPSTATUS_REPLAYED:     t = "replay detected"; break;  
-    case KSBA_OCSP_RSPSTATUS_OTHER:        t = "other (unknown)"; break;  
+    case KSBA_OCSP_RSPSTATUS_MALFORMED:    t = "malformed"; break;
+    case KSBA_OCSP_RSPSTATUS_INTERNAL:     t = "internal error"; break;
+    case KSBA_OCSP_RSPSTATUS_TRYLATER:     t = "try later"; break;
+    case KSBA_OCSP_RSPSTATUS_SIGREQUIRED:  t = "must sign request"; break;
+    case KSBA_OCSP_RSPSTATUS_UNAUTHORIZED: t = "unauthorized"; break;
+    case KSBA_OCSP_RSPSTATUS_REPLAYED:     t = "replay detected"; break;
+    case KSBA_OCSP_RSPSTATUS_OTHER:        t = "other (unknown)"; break;
     case KSBA_OCSP_RSPSTATUS_NONE:         t = "no status"; break;
     default:                               t = "[unknown status]"; break;
     }
   if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS)
     {
       if (opt.verbose)
-        log_info (_("OCSP responder at `%s' status: %s\n"), url, t);
+        log_info (_("OCSP responder at '%s' status: %s\n"), url, t);
 
       err = ksba_ocsp_hash_response (ocsp, response, responselen,
-                                     HASH_FNC, md);  
+                                     HASH_FNC, md);
       if (err)
-        log_error (_("hashing the OCSP response for `%s' failed: %s\n"),
+        log_error (_("hashing the OCSP response for '%s' failed: %s\n"),
                    url, gpg_strerror (err));
     }
   else
     {
-      log_error (_("OCSP responder at `%s' status: %s\n"), url, t);
+      log_error (_("OCSP responder at '%s' status: %s\n"), url, t);
       err = gpg_error (GPG_ERR_GENERAL);
     }
 
@@ -301,7 +311,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
    SIGNER_FPR_LIST is not NULL we simply check that CERT matches one
    of the fingerprints in this list. */
 static gpg_error_t
-validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert, 
+validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert,
                          fingerprint_list_t signer_fpr_list)
 {
   gpg_error_t err;
@@ -310,7 +320,7 @@ validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert,
   if (signer_fpr_list)
     {
       fpr = get_fingerprint_hexstring (cert);
-      for (; signer_fpr_list && strcmp (signer_fpr_list->hexfpr, fpr); 
+      for (; signer_fpr_list && strcmp (signer_fpr_list->hexfpr, fpr);
            signer_fpr_list = signer_fpr_list->next)
         ;
       if (signer_fpr_list)
@@ -322,10 +332,6 @@ validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert,
         }
       xfree (fpr);
     }
-  else if (opt.system_daemon)
-    {
-      err = validate_cert_chain (ctrl, cert, NULL, VALIDATE_MODE_OCSP, NULL);
-    }
   else
     {
       /* We avoid duplicating the entire certificate validation code
@@ -337,7 +343,7 @@ validate_responder_cert (ctrl_t ctrl, ksba_cert_t cert,
 
          Note, that in theory we could simply ask the client via an
          inquire to validate a certificate but this might involve
-         calling DirMngr again recursivly - we can't do that as of now
+         calling DirMngr again recursively - we can't do that as of now
          (neither DirMngr nor gpgsm have the ability for concurrent
          access to DirMngr.   */
 
@@ -385,7 +391,7 @@ check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
 }
 
 
-/* Check the signature of an OCSP repsonse.  OCSP is the context,
+/* Check the signature of an OCSP response.  OCSP is the context,
    S_SIG the signature value and MD the handle of the hash we used for
    the response.  This function automagically finds the correct public
    key.  If SIGNER_FPR_LIST is not NULL, the default OCSP reponder has been
@@ -409,10 +415,10 @@ check_signature (ctrl_t ctrl,
       log_error (_("only SHA-1 is supported for OCSP responses\n"));
       return gpg_error (GPG_ERR_DIGEST_ALGO);
     }
-  err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash sha1 %b))", 
+  err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash sha1 %b))",
                          gcry_md_get_algo_dlen (algo),
                          gcry_md_read (md, algo));
-  if (err) 
+  if (err)
     {
       log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err));
       return err;
@@ -481,7 +487,7 @@ check_signature (ctrl_t ctrl,
         {
           log_error ("responder certificate ");
           if (name)
-            log_printf ("`/%s' ", name);
+            log_printf ("'/%s' ", name);
           if (keyid)
             {
               log_printf ("{");
@@ -546,7 +552,7 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
       err = find_issuing_cert (ctrl, cert, &issuer_cert);
       if (err)
         {
-          log_error (_("issuer certificate not found: %s\n"), 
+          log_error (_("issuer certificate not found: %s\n"),
                      gpg_strerror (err));
           goto leave;
         }
@@ -580,7 +586,7 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
 
 
 
-  /* Figure out the OCSP responder to use. 
+  /* Figure out the OCSP responder to use.
      1. Try to get the reponder from the certificate.
         We do only take http and https style URIs into account.
      2. If this fails use the default responder, if any.
@@ -606,10 +612,10 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
       ksba_free (oid);
     }
   if (err && gpg_err_code (err) != GPG_ERR_EOF)
-    { 
+    {
       log_error (_("can't get authorityInfoAccess: %s\n"), gpg_strerror (err));
       goto leave;
-    } 
+    }
   if (!url)
     {
       if (!opt.ocsp_responder || !*opt.ocsp_responder)
@@ -627,12 +633,12 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
       url = opt.ocsp_responder;
       default_signer = opt.ocsp_signer;
       if (opt.verbose)
-        log_info (_("using default OCSP responder `%s'\n"), url);
+        log_info (_("using default OCSP responder '%s'\n"), url);
     }
   else
     {
       if (opt.verbose)
-        log_info (_("using OCSP responder `%s'\n"), url);
+        log_info (_("using OCSP responder '%s'\n"), url);
     }
 
   /* Ask the OCSP responder. */
@@ -647,6 +653,33 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
   if (err)
     goto leave;
 
+  /* It is sometimes useful to know the responder ID. */
+  if (opt.verbose)
+    {
+      char *resp_name;
+      ksba_sexp_t resp_keyid;
+
+      err = ksba_ocsp_get_responder_id (ocsp, &resp_name, &resp_keyid);
+      if (err)
+        log_info (_("error getting responder ID: %s\n"), gpg_strerror (err));
+      else
+        {
+          log_info ("responder id: ");
+          if (resp_name)
+            log_printf ("'/%s' ", resp_name);
+          if (resp_keyid)
+            {
+              log_printf ("{");
+              dump_serial (resp_keyid);
+              log_printf ("} ");
+            }
+          log_printf ("\n");
+        }
+      ksba_free (resp_name);
+      ksba_free (resp_keyid);
+      err = 0;
+    }
+
   /* We got a useful answer, check that the answer has a valid signature. */
   sigval = ksba_ocsp_get_sig_val (ocsp, produced_at);
   if (!sigval || !*produced_at)
@@ -684,14 +717,14 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
       if (err)
         {
           log_error ("set_user_data(validated_at) failed: %s\n",
-                     gpg_strerror (err)); 
+                     gpg_strerror (err));
           err = 0; /* The certificate is anyway revoked, and that is a
                       more important message than the failure of our
                       cache. */
         }
     }
 
-  
+
   if (opt.verbose)
     {
       log_info (_("certificate status is: %s  (this=%s  next=%s)\n"),
@@ -708,11 +741,11 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
                   reason == KSBA_CRLREASON_CA_COMPROMISE?   "CA compromise":
                   reason == KSBA_CRLREASON_AFFILIATION_CHANGED?
                                                       "affiliation changed":
-                  reason == KSBA_CRLREASON_SUPERSEDED?   "superseeded":
+                  reason == KSBA_CRLREASON_SUPERSEDED?   "superseded":
                   reason == KSBA_CRLREASON_CESSATION_OF_OPERATION?
-                                                  "cessation of operation": 
+                                                  "cessation of operation":
                   reason == KSBA_CRLREASON_CERTIFICATE_HOLD?
-                                                  "certificate on hold":   
+                                                  "certificate on hold":
                   reason == KSBA_CRLREASON_REMOVE_FROM_CRL?
                                                   "removed from CRL":
                   reason == KSBA_CRLREASON_PRIVILEGE_WITHDRAWN?
@@ -749,13 +782,13 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
   if (!*tmp_time || strcmp (tmp_time, current_time) < 0 )
     {
       log_error (_("OCSP responder returned a non-current status\n"));
-      log_info ("used now: %s  this_update: %s\n", 
+      log_info ("used now: %s  this_update: %s\n",
                 current_time, this_update);
       if (!err)
         err = gpg_error (GPG_ERR_TIME_CONFLICT);
     }
 
-  /* Check that we are not beyound NEXT_UPDATE  (plus some extra time). */
+  /* Check that we are not beyond NEXT_UPDATE  (plus some extra time). */
   if (*next_update)
     {
       gnupg_copy_time (tmp_time, next_update);
@@ -764,7 +797,7 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
       if (!*tmp_time && strcmp (tmp_time, current_time) < 0 )
         {
           log_error (_("OCSP responder returned an too old status\n"));
-          log_info ("used now: %s  next_update: %s\n", 
+          log_info ("used now: %s  next_update: %s\n",
                     current_time, next_update);
           if (!err)
             err = gpg_error (GPG_ERR_TIME_CONFLICT);