Example #1
0
/* See card.c for interface description.  Frankly we don't do any real
   enumeration but just check whether the well know files are
   available.  */
static int
dinsig_enum_keypairs (CARD card, int idx,
                      unsigned char *keygrip, char **keyid)
{
  int rc;
  unsigned char *buf;
  size_t buflen;
  ksba_cert_t cert;

  /* fixme: We should locate the application via the EF(DIR) and not
     assume a Netkey card */
  if (!idx)
    rc = dinsig_read_cert (card, "DINSIG-DF01.C000", &buf, &buflen);
  else if (idx == 1)
    rc = dinsig_read_cert (card, "DINSIG-DF01.C200", &buf, &buflen);
  else
    rc = -1;
  if (rc)
    return rc;

  rc = ksba_cert_new (&cert);
  if (rc)
    {
      xfree (buf);
      return rc;
    }

  rc = ksba_cert_init_from_mem (cert, buf, buflen);
  xfree (buf);
  if (rc)
    {
      log_error ("failed to parse the certificate at idx %d: %s\n",
                 idx, gpg_strerror (rc));
      ksba_cert_release (cert);
      return rc;
    }
  if (card_help_get_keygrip (cert, keygrip))
    {
      log_error ("failed to calculate the keygrip at index %d\n", idx);
      ksba_cert_release (cert);
      return gpg_error (GPG_ERR_CARD);
    }
  ksba_cert_release (cert);

  /* return the iD */
  if (keyid)
    {
      *keyid = xtrymalloc (17);
      if (!*keyid)
        return gpg_error (gpg_err_code_from_errno (errno));
      if (!idx)
        strcpy (*keyid, "DINSIG-DF01.C000");
      else
        strcpy (*keyid, "DINSIG-DF01.C200");
    }

  return 0;
}
Example #2
0
static gpg_error_t
cmd_passwd (assuan_context_t ctx, char *line)
{
  ctrl_t ctrl = assuan_get_pointer (ctx);
  gpg_error_t err;
  ksba_cert_t cert = NULL;
  char *grip = NULL;

  line = skip_options (line);

  err = gpgsm_find_cert (line, NULL, &cert);
  if (err)
    ;
  else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
    err = gpg_error (GPG_ERR_INTERNAL);
  else
    {
      char *desc = gpgsm_format_keydesc (cert);
      err = gpgsm_agent_passwd (ctrl, grip, desc);
      xfree (desc);
    }

  xfree (grip);
  ksba_cert_release (cert);

  return err;
}
Example #3
0
/* Helper to store the DER encoded certificate CERTDATA of length
   CERTDATALEN.  */
static void
store_cert_cb (void *opaque,
               const unsigned char *certdata, size_t certdatalen)
{
  struct store_cert_parm_s *parm = opaque;
  gpg_error_t err;
  ksba_cert_t cert;

  err = ksba_cert_new (&cert);
  if (err)
    {
      if (!parm->err)
        parm->err = err;
      return;
    }

  err = ksba_cert_init_from_mem (cert, certdata, certdatalen);
  if (err)
    {
      log_error ("failed to parse a certificate: %s\n", gpg_strerror (err));
      if (!parm->err)
        parm->err = err;
    }
  else
    check_and_store (parm->ctrl, parm->stats, cert, 0);
  ksba_cert_release (cert);
}
Example #4
0
static gpg_error_t
my_http_tls_verify_cb (void *opaque,
                       http_t http,
                       http_session_t session,
                       unsigned int http_flags,
                       void *tls_context)
{
  gpg_error_t err;
  int idx;
  ksba_cert_t cert;
  ksba_cert_t hostcert = NULL;

  (void)opaque;
  (void)http;
  (void)session;
  (void)http_flags;

  /* Get the peer's certs fron ntbtls.  */
  for (idx = 0;
       (cert = ntbtls_x509_get_peer_cert (tls_context, idx)); idx++)
    {
      if (!idx)
        {
          log_info ("Received host certificate\n");
          hostcert = cert;
        }
      else
        {

          log_info ("Received additional certificate\n");
          ksba_cert_release (cert);
        }
    }
  if (!idx)
    {
      err  = gpg_error (GPG_ERR_MISSING_CERT);
      goto leave;
    }

  err = 0;

 leave:
  ksba_cert_release (hostcert);
  log_info ("my_http_tls_verify_cb returns: %s\n", gpg_strerror (err));
  return err;
}
Example #5
0
/*
  Return the last found cert.  Caller must free it.
 */
int
keybox_get_cert (KEYBOX_HANDLE hd, ksba_cert_t *r_cert)
{
  const unsigned char *buffer;
  size_t length;
  size_t cert_off, cert_len;
  ksba_reader_t reader = NULL;
  ksba_cert_t cert = NULL;
  int rc;

  if (!hd)
    return gpg_error (GPG_ERR_INV_VALUE);
  if (!hd->found.blob)
    return gpg_error (GPG_ERR_NOTHING_FOUND);

  if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
    return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);

  buffer = _keybox_get_blob_image (hd->found.blob, &length);
  if (length < 40)
    return gpg_error (GPG_ERR_TOO_SHORT);
  cert_off = get32 (buffer+8);
  cert_len = get32 (buffer+12);
  if (cert_off+cert_len > length)
    return gpg_error (GPG_ERR_TOO_SHORT);

  rc = ksba_reader_new (&reader);
  if (rc)
    return rc;
  rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
  if (rc)
    {
      ksba_reader_release (reader);
      /* fixme: need to map the error codes */
      return gpg_error (GPG_ERR_GENERAL);
    }

  rc = ksba_cert_new (&cert);
  if (rc)
    {
      ksba_reader_release (reader);
      return rc;
    }

  rc = ksba_cert_read_der (cert, reader);
  if (rc)
    {
      ksba_cert_release (cert);
      ksba_reader_release (reader);
      /* fixme: need to map the error codes */
      return gpg_error (GPG_ERR_GENERAL);
    }

  *r_cert = cert;
  ksba_reader_release (reader);
  return 0;
}
Example #6
0
/* Create a request for the DER encoded certificate in the file
   CERT_FNAME and its issuer's certificate in the file
   ISSUER_CERT_FNAME. */
void
one_request (const char *cert_fname, const char *issuer_cert_fname)
{
  gpg_error_t err;
  ksba_cert_t cert = get_one_cert (cert_fname);
  ksba_cert_t issuer_cert = get_one_cert (issuer_cert_fname);
  ksba_ocsp_t ocsp;
  unsigned char *request;
  size_t requestlen;

  err = ksba_ocsp_new (&ocsp);
  fail_if_err (err);
  
  err = ksba_ocsp_add_target (ocsp, cert, issuer_cert);
  fail_if_err (err);
  ksba_cert_release (cert);
  ksba_cert_release (issuer_cert);

  if (!no_nonce)
    ksba_ocsp_set_nonce (ocsp, "ABCDEFGHIJKLMNOP", 16);

  err = ksba_ocsp_build_request (ocsp, &request, &requestlen);
  fail_if_err (err);
  ksba_ocsp_release (ocsp);

  printf ("OCSP request of length %u created\n", (unsigned int)requestlen);
  {

    FILE *fp = fopen ("a.req", "wb");
    if (!fp)
      fail ("can't create output file `a.req'");
    if (fwrite (request, requestlen, 1, fp) != 1)
      fail ("can't write output");
    fclose (fp);
  }
  
  xfree (request);
}
Example #7
0
/* Return a certificate from the Directory Manager's cache.  This
   function only returns one certificate which must be specified using
   the fingerprint FPR and will be stored at R_CERT.  On error NULL is
   stored at R_CERT and an error code returned.  Note that the caller
   must provide the locked dirmngr context CTX. */
static gpg_error_t
get_cached_cert (assuan_context_t ctx,
                 const unsigned char *fpr, ksba_cert_t *r_cert)
{
  gpg_error_t err;
  char line[ASSUAN_LINELENGTH];
  char hexfpr[2*20+1];
  struct membuf mb;
  char *buf;
  size_t buflen;
  ksba_cert_t cert;

  *r_cert = NULL;

  bin2hex (fpr, 20, hexfpr);
  snprintf (line, DIM(line)-1, "LOOKUP --signle --cache-only 0x%s", hexfpr);

  init_membuf (&mb, 4096);
  err = assuan_transact (ctx, line, get_cached_cert_data_cb, &mb,
                         NULL, NULL, NULL, NULL);
  buf = get_membuf (&mb, &buflen);
  if (err)
    {
      xfree (buf);
      return err;
    }
  if (!buf)
    return gpg_error (GPG_ERR_ENOMEM);

  err = ksba_cert_new (&cert);
  if (err)
    {
      xfree (buf);
      return err;
    }
  err = ksba_cert_init_from_mem (cert, buf, buflen);
  xfree (buf);
  if (err)
    {
      log_error ("failed to parse a certificate: %s\n", gpg_strerror (err));
      ksba_cert_release (cert);
      return err;
    }

  *r_cert = cert;
  return 0;
}
Example #8
0
/* Handle inquiries from the dirmngr COMMAND. */
static gpg_error_t
run_command_inq_cb (void *opaque, const char *line)
{
  struct run_command_parm_s *parm = opaque;
  int rc = 0;

  if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
    { /* send the given certificate */
      int err;
      ksba_cert_t cert;
      const unsigned char *der;
      size_t derlen;

      line += 8;
      if (!*line)
        return gpg_error (GPG_ERR_ASS_PARAMETER);

      err = gpgsm_find_cert (line, NULL, &cert);
      if (err)
        {
          log_error ("certificate not found: %s\n", gpg_strerror (err));
          rc = gpg_error (GPG_ERR_NOT_FOUND);
        }
      else
        {
          der = ksba_cert_get_image (cert, &derlen);
          if (!der)
            rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
          else
            rc = assuan_send_data (parm->ctx, der, derlen);
          ksba_cert_release (cert);
        }
    }
  else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
    { /* Simply show the message given in the argument. */
      line += 9;
      log_info ("dirmngr: %s\n", line);
    }
  else
    {
      log_error ("unsupported inquiry `%s'\n", line);
      rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
    }

  return rc; 
}
Example #9
0
/* Lookup helpers*/
static gpg_error_t
lookup_cb (void *opaque, const void *buffer, size_t length)
{
  struct lookup_parm_s *parm = opaque;
  size_t len;
  char *buf;
  ksba_cert_t cert;
  int rc;

  if (parm->error)
    return 0;

  if (buffer)
    {
      put_membuf (&parm->data, buffer, length);
      return 0;
    }
  /* END encountered - process what we have */
  buf = get_membuf (&parm->data, &len);
  if (!buf)
    {
      parm->error = gpg_error (GPG_ERR_ENOMEM);
      return 0;
    }

  rc = ksba_cert_new (&cert);
  if (rc)
    {
      parm->error = rc;
      return 0;
    }
  rc = ksba_cert_init_from_mem (cert, buf, len);
  if (rc)
    {
      log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
    }
  else
    {
      parm->cb (parm->cb_value, cert);
    }

  ksba_cert_release (cert);
  init_membuf (&parm->data, 4096);
  return 0;
}
Example #10
0
/* Cleanup one slot.  This releases all resourses but keeps the actual
   slot in the cache marked for reuse. */
static void
clean_cache_slot (cert_item_t ci)
{
  ksba_cert_t cert;

  if (!ci->cert)
    return; /* Already cleaned.  */

  ksba_free (ci->sn);
  ci->sn = NULL;
  ksba_free (ci->issuer_dn);
  ci->issuer_dn = NULL;
  ksba_free (ci->subject_dn);
  ci->subject_dn = NULL;
  cert = ci->cert;
  ci->cert = NULL;

  ksba_cert_release (cert);
}
Example #11
0
/* Export a certificate and its private key. */
void
gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream)
{
  gpg_error_t err = 0;
  KEYDB_HANDLE hd;
  KEYDB_SEARCH_DESC *desc = NULL;
  Base64Context b64writer = NULL;
  ksba_writer_t writer;
  ksba_cert_t cert = NULL;
  const unsigned char *image;
  size_t imagelen;
  char *keygrip = NULL;
  char *prompt;
  void *data;
  size_t datalen;


  hd = keydb_new (0);
  if (!hd)
    {
      log_error ("keydb_new failed\n");
      goto leave;
    }

  desc = xtrycalloc (1, sizeof *desc);
  if (!desc)
    {
      log_error ("allocating memory for export failed: %s\n",
                 gpg_strerror (out_of_core ()));
      goto leave;
    }

  err = classify_user_id (name, desc, 0);
  if (err)
    {
      log_error ("key '%s' not found: %s\n",
                 name, gpg_strerror (err));
      goto leave;
    }

  /* Lookup the certificate and make sure that it is unique. */
  err = keydb_search (hd, desc, 1);
  if (!err)
    {
      err = keydb_get_cert (hd, &cert);
      if (err)
        {
          log_error ("keydb_get_cert failed: %s\n", gpg_strerror (err));
          goto leave;
        }

    next_ambiguous:
      err = keydb_search (hd, desc, 1);
      if (!err)
        {
          ksba_cert_t cert2 = NULL;

          if (!keydb_get_cert (hd, &cert2))
            {
              if (gpgsm_certs_identical_p (cert, cert2))
                {
                  ksba_cert_release (cert2);
                  goto next_ambiguous;
                }
              ksba_cert_release (cert2);
            }
          err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
        }
      else if (err == -1 || gpg_err_code (err) == GPG_ERR_EOF)
        err = 0;
      if (err)
        {
          log_error ("key '%s' not found: %s\n",
                     name, gpg_strerror (err));
          goto leave;
        }
    }

  keygrip = gpgsm_get_keygrip_hexstring (cert);
  if (!keygrip || gpgsm_agent_havekey (ctrl, keygrip))
    {
      /* Note, that the !keygrip case indicates a bad certificate. */
      err = gpg_error (GPG_ERR_NO_SECKEY);
      log_error ("can't export key '%s': %s\n", name, gpg_strerror (err));
      goto leave;
    }

  image = ksba_cert_get_image (cert, &imagelen);
  if (!image)
    {
      log_error ("ksba_cert_get_image failed\n");
      goto leave;
    }

  if (ctrl->create_pem)
    {
      print_short_info (cert, stream);
      es_putc ('\n', stream);
    }

  if (opt.p12_charset && ctrl->create_pem)
    {
      es_fprintf (stream, "The passphrase is %s encoded.\n\n",
                  opt.p12_charset);
    }

  ctrl->pem_name = "PKCS12";
  err = gpgsm_create_writer (&b64writer, ctrl, stream, &writer);
  if (err)
    {
      log_error ("can't create writer: %s\n", gpg_strerror (err));
      goto leave;
    }

  prompt = gpgsm_format_keydesc (cert);
  err = export_p12 (ctrl, image, imagelen, prompt, keygrip, &data, &datalen);
  xfree (prompt);
  if (err)
    goto leave;
  err = ksba_writer_write (writer, data, datalen);
  xfree (data);
  if (err)
    {
      log_error ("write failed: %s\n", gpg_strerror (err));
      goto leave;
    }

  if (ctrl->create_pem)
    {
      /* We want one certificate per PEM block */
      err = gpgsm_finish_writer (b64writer);
      if (err)
        {
          log_error ("write failed: %s\n", gpg_strerror (err));
          goto leave;
        }
      gpgsm_destroy_writer (b64writer);
      b64writer = NULL;
    }

  ksba_cert_release (cert);
  cert = NULL;

 leave:
  gpgsm_destroy_writer (b64writer);
  ksba_cert_release (cert);
  xfree (desc);
  keydb_release (hd);
}
Example #12
0
/* Return the certificate matching ISSUER_DN and SERIALNO; if it is
   not already in the cache, try to find it from other resources.  */
ksba_cert_t
find_cert_bysn (ctrl_t ctrl, const char *issuer_dn, ksba_sexp_t serialno)
{
  gpg_error_t err;
  ksba_cert_t cert;
  cert_fetch_context_t context = NULL;
  char *hexsn, *buf;

  /* First check whether it has already been cached.  */
  cert = get_cert_bysn (issuer_dn, serialno);
  if (cert)
    return cert;

  /* Ask back to the service requester to return the certificate.
     This is because we can assume that he already used the
     certificate while checking for the CRL. */
  hexsn = serial_hex (serialno);
  if (!hexsn)
    {
      log_error ("serial_hex() failed\n");
      return NULL;
    }
  buf = xtrymalloc (1 + strlen (hexsn) + 1 + strlen (issuer_dn) + 1);
  if (!buf)
    {
      log_error ("can't allocate enough memory: %s\n", strerror (errno));
      xfree (hexsn);
      return NULL;
    }
  strcpy (stpcpy (stpcpy (stpcpy (buf, "#"), hexsn),"/"), issuer_dn);
  xfree (hexsn);
  cert = get_cert_local (ctrl, buf);
  xfree (buf);
  if (cert)
    {
      cache_cert (cert);
      return cert; /* Done. */
    }

  if (DBG_LOOKUP)
    log_debug ("find_cert_bysn: certificate not returned by caller"
               " - doing lookup\n");

  /* Retrieve the certificate from external resources. */
  while (!cert)
    {
      ksba_sexp_t sn;
      char *issdn;

      if (!context)
        {
          err = ca_cert_fetch (ctrl, &context, issuer_dn);
          if (err)
            {
              log_error (_("error fetching certificate by S/N: %s\n"),
                         gpg_strerror (err));
              break;
            }
        }

      err = fetch_next_ksba_cert (context, &cert);
      if (err)
        {
          log_error (_("error fetching certificate by S/N: %s\n"),
                     gpg_strerror (err) );
          break;
        }

      issdn = ksba_cert_get_issuer (cert, 0);
      if (strcmp (issuer_dn, issdn))
        {
          log_debug ("find_cert_bysn: Ooops: issuer DN does not match\n");
          ksba_cert_release (cert);
          cert = NULL;
          ksba_free (issdn);
          break;
        }

      sn = ksba_cert_get_serial (cert);

      if (DBG_LOOKUP)
        {
          log_debug ("   considering certificate (#");
          dump_serial (sn);
          log_printf ("/");
          dump_string (issdn);
          log_printf (")\n");
        }

      if (!compare_serialno (serialno, sn))
        {
          ksba_free (sn);
          ksba_free (issdn);
          cache_cert (cert);
          if (DBG_LOOKUP)
            log_debug ("   found\n");
          break; /* Ready.  */
        }

      ksba_free (sn);
      ksba_free (issdn);
      ksba_cert_release (cert);
      cert = NULL;
    }

  end_cert_fetch (context);
  return cert;
}
Example #13
0
/* Given PATTERN, which is a string as used by GnuPG to specify a
   certificate, return all matching certificates by calling the
   supplied function RETFNC.  */
gpg_error_t
get_certs_bypattern (const char *pattern,
                     gpg_error_t (*retfnc)(void*,ksba_cert_t),
                     void *retfnc_data)
{
  gpg_error_t err = GPG_ERR_BUG;
  enum pattern_class class;
  size_t offset, sn_offset;
  const char *hexserialno;
  ksba_sexp_t serialno = NULL;
  ksba_cert_t cert = NULL;
  unsigned int seq;

  if (!pattern || !retfnc)
    return gpg_error (GPG_ERR_INV_ARG);

  class = classify_pattern (pattern, &offset, &sn_offset);
  hexserialno = pattern + sn_offset;
  pattern += offset;
  switch (class)
    {
    case PATTERN_UNKNOWN:
      err = gpg_error (GPG_ERR_INV_NAME);
      break;

    case PATTERN_FINGERPRINT20:
      cert = get_cert_byhexfpr (pattern);
      err = cert? 0 : gpg_error (GPG_ERR_NOT_FOUND);
      break;

    case PATTERN_SERIALNO_ISSUER:
      serialno = hexsn_to_sexp (hexserialno);
      if (!serialno)
        err = gpg_error_from_syserror ();
      else
        {
          cert = get_cert_bysn (pattern, serialno);
          err = cert? 0 : gpg_error (GPG_ERR_NOT_FOUND);
        }
      break;

    case PATTERN_ISSUER:
      for (seq=0,err=0; !err && (cert = get_cert_byissuer (pattern, seq)); seq++)
        {
          err = retfnc (retfnc_data, cert);
          ksba_cert_release (cert);
          cert = NULL;
        }
      if (!err && !seq)
        err = gpg_error (GPG_ERR_NOT_FOUND);
      break;

    case PATTERN_SUBJECT:
      for (seq=0,err=0; !err && (cert = get_cert_bysubject (pattern, seq));seq++)
        {
          err = retfnc (retfnc_data, cert);
          ksba_cert_release (cert);
          cert = NULL;
        }
      if (!err && !seq)
        err = gpg_error (GPG_ERR_NOT_FOUND);
      break;

    case PATTERN_EMAIL:
    case PATTERN_EMAIL_SUBSTR:
    case PATTERN_FINGERPRINT16:
    case PATTERN_SHORT_KEYID:
    case PATTERN_LONG_KEYID:
    case PATTERN_SUBSTR:
    case PATTERN_SERIALNO:
      /* Not supported.  */
      err = gpg_error (GPG_ERR_INV_NAME);
    }


  if (!err && cert)
    err = retfnc (retfnc_data, cert);
  ksba_cert_release (cert);
  xfree (serialno);
  return err;
}
Example #14
0
/* Load certificates from the directory DIRNAME.  All certificates
   matching the pattern "*.crt" or "*.der"  are loaded.  We assume that
   certificates are DER encoded and not PEM encapsulated. The cache
   should be in a locked state when calling this function.  */
static gpg_error_t
load_certs_from_dir (const char *dirname, int are_trusted)
{
  gpg_error_t err;
  DIR *dir;
  struct dirent *ep;
  char *p;
  size_t n;
  estream_t fp;
  ksba_reader_t reader;
  ksba_cert_t cert;
  char *fname = NULL;

  dir = opendir (dirname);
  if (!dir)
    {
      if (opt.system_daemon)
        log_info (_("can't access directory '%s': %s\n"),
                  dirname, strerror (errno));
      return 0; /* We do not consider this a severe error.  */
    }

  while ( (ep=readdir (dir)) )
    {
      p = ep->d_name;
      if (*p == '.' || !*p)
        continue; /* Skip any hidden files and invalid entries.  */
      n = strlen (p);
      if ( n < 5 || (strcmp (p+n-4,".crt") && strcmp (p+n-4,".der")))
        continue; /* Not the desired "*.crt" or "*.der" pattern.  */

      xfree (fname);
      fname = make_filename (dirname, p, NULL);
      fp = es_fopen (fname, "rb");
      if (!fp)
        {
          log_error (_("can't open '%s': %s\n"),
                     fname, strerror (errno));
          continue;
        }

      err = create_estream_ksba_reader (&reader, fp);
      if (err)
        {
          es_fclose (fp);
          continue;
        }

      err = ksba_cert_new (&cert);
      if (!err)
        err = ksba_cert_read_der (cert, reader);
      ksba_reader_release (reader);
      es_fclose (fp);
      if (err)
        {
          log_error (_("can't parse certificate '%s': %s\n"),
                     fname, gpg_strerror (err));
          ksba_cert_release (cert);
          continue;
        }

      err = put_cert (cert, 1, are_trusted, NULL);
      if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
        log_info (_("certificate '%s' already cached\n"), fname);
      else if (!err)
        {
          if (are_trusted)
            log_info (_("trusted certificate '%s' loaded\n"), fname);
          else
            log_info (_("certificate '%s' loaded\n"), fname);
          if (opt.verbose)
            {
              p = get_fingerprint_hexstring_colon (cert);
              log_info (_("  SHA1 fingerprint = %s\n"), p);
              xfree (p);

              cert_log_name (_("   issuer ="), cert);
              cert_log_subject (_("  subject ="), cert);
            }
        }
      else
        log_error (_("error loading certificate '%s': %s\n"),
                     fname, gpg_strerror (err));
      ksba_cert_release (cert);
    }

  xfree (fname);
  closedir (dir);
  return 0;
}
Example #15
0
/* Return true if the key in BLOB matches the 20 bytes keygrip GRIP.
   We don't have the keygrips as meta data, thus we need to parse the
   certificate. Fixme: We might want to return proper error codes
   instead of failing a search for invalid certificates etc.  */
static int
blob_x509_has_grip (KEYBOXBLOB blob, const unsigned char *grip)
{
  int rc;
  const unsigned char *buffer;
  size_t length;
  size_t cert_off, cert_len;
  ksba_reader_t reader = NULL;
  ksba_cert_t cert = NULL;
  ksba_sexp_t p = NULL;
  gcry_sexp_t s_pkey;
  unsigned char array[20];
  unsigned char *rcp;
  size_t n;

  buffer = _keybox_get_blob_image (blob, &length);
  if (length < 40)
    return 0; /* Too short. */
  cert_off = get32 (buffer+8);
  cert_len = get32 (buffer+12);
  if (cert_off+cert_len > length)
    return 0; /* Too short.  */

  rc = ksba_reader_new (&reader);
  if (rc)
    return 0; /* Problem with ksba. */
  rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
  if (rc)
    goto failed;
  rc = ksba_cert_new (&cert);
  if (rc)
    goto failed;
  rc = ksba_cert_read_der (cert, reader);
  if (rc)
    goto failed;
  p = ksba_cert_get_public_key (cert);
  if (!p)
    goto failed;
  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
  if (!n)
    goto failed;
  rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n);
  if (rc)
    {
      gcry_sexp_release (s_pkey);
      goto failed;
    }
  rcp = gcry_pk_get_keygrip (s_pkey, array);
  gcry_sexp_release (s_pkey);
  if (!rcp)
    goto failed; /* Can't calculate keygrip. */

  xfree (p);
  ksba_cert_release (cert);
  ksba_reader_release (reader);
  return !memcmp (array, grip, 20);
 failed:
  xfree (p);
  ksba_cert_release (cert);
  ksba_reader_release (reader);
  return 0;
}
Example #16
0
/* Export all certificates or just those given in NAMES.  The output
   is written to STREAM.  */
void
gpgsm_export (ctrl_t ctrl, strlist_t names, estream_t stream)
{
  KEYDB_HANDLE hd = NULL;
  KEYDB_SEARCH_DESC *desc = NULL;
  int ndesc;
  Base64Context b64writer = NULL;
  ksba_writer_t writer;
  strlist_t sl;
  ksba_cert_t cert = NULL;
  int rc=0;
  int count = 0;
  int i;
  duptable_t *dtable;


  dtable = create_duptable ();
  if (!dtable)
    {
      log_error ("creating duplicates table failed: %s\n", strerror (errno));
      goto leave;
    }

  hd = keydb_new (0);
  if (!hd)
    {
      log_error ("keydb_new failed\n");
      goto leave;
    }

  if (!names)
    ndesc = 1;
  else
    {
      for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++)
        ;
    }

  desc = xtrycalloc (ndesc, sizeof *desc);
  if (!ndesc)
    {
      log_error ("allocating memory for export failed: %s\n",
                 gpg_strerror (out_of_core ()));
      goto leave;
    }

  if (!names)
    desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
  else
    {
      for (ndesc=0, sl=names; sl; sl = sl->next)
        {
          rc = classify_user_id (sl->d, desc+ndesc, 0);
          if (rc)
            {
              log_error ("key '%s' not found: %s\n",
                         sl->d, gpg_strerror (rc));
              rc = 0;
            }
          else
            ndesc++;
        }
    }

  /* If all specifications are done by fingerprint or keygrip, we
     switch to ephemeral mode so that _all_ currently available and
     matching certificates are exported.  */
  if (names && ndesc)
    {
      for (i=0; (i < ndesc
                 && (desc[i].mode == KEYDB_SEARCH_MODE_FPR
                     || desc[i].mode == KEYDB_SEARCH_MODE_FPR20
                     || desc[i].mode == KEYDB_SEARCH_MODE_FPR16
                     || desc[i].mode == KEYDB_SEARCH_MODE_KEYGRIP)); i++)
        ;
      if (i == ndesc)
        keydb_set_ephemeral (hd, 1);
    }

  while (!(rc = keydb_search (hd, desc, ndesc)))
    {
      unsigned char fpr[20];
      int exists;

      if (!names)
        desc[0].mode = KEYDB_SEARCH_MODE_NEXT;

      rc = keydb_get_cert (hd, &cert);
      if (rc)
        {
          log_error ("keydb_get_cert failed: %s\n", gpg_strerror (rc));
          goto leave;
        }

      gpgsm_get_fingerprint (cert, 0, fpr, NULL);
      rc = insert_duptable (dtable, fpr, &exists);
      if (rc)
        {
          log_error ("inserting into duplicates table failed: %s\n",
                     gpg_strerror (rc));
          goto leave;
        }

      if (!exists && count && !ctrl->create_pem)
        {
          log_info ("exporting more than one certificate "
                    "is not possible in binary mode\n");
          log_info ("ignoring other certificates\n");
          break;
        }

      if (!exists)
        {
          const unsigned char *image;
          size_t imagelen;

          image = ksba_cert_get_image (cert, &imagelen);
          if (!image)
            {
              log_error ("ksba_cert_get_image failed\n");
              goto leave;
            }


          if (ctrl->create_pem)
            {
              if (count)
                es_putc ('\n', stream);
              print_short_info (cert, stream);
              es_putc ('\n', stream);
            }
          count++;

          if (!b64writer)
            {
              ctrl->pem_name = "CERTIFICATE";
              rc = gpgsm_create_writer (&b64writer, ctrl, stream, &writer);
              if (rc)
                {
                  log_error ("can't create writer: %s\n", gpg_strerror (rc));
                  goto leave;
                }
            }

          rc = ksba_writer_write (writer, image, imagelen);
          if (rc)
            {
              log_error ("write error: %s\n", gpg_strerror (rc));
              goto leave;
            }

          if (ctrl->create_pem)
            {
              /* We want one certificate per PEM block */
              rc = gpgsm_finish_writer (b64writer);
              if (rc)
                {
                  log_error ("write failed: %s\n", gpg_strerror (rc));
                  goto leave;
                }
              gpgsm_destroy_writer (b64writer);
              b64writer = NULL;
            }
        }

      ksba_cert_release (cert);
      cert = NULL;
    }
  if (rc && rc != -1)
    log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
  else if (b64writer)
    {
      rc = gpgsm_finish_writer (b64writer);
      if (rc)
        {
          log_error ("write failed: %s\n", gpg_strerror (rc));
          goto leave;
        }
    }

 leave:
  gpgsm_destroy_writer (b64writer);
  ksba_cert_release (cert);
  xfree (desc);
  keydb_release (hd);
  destroy_duptable (dtable);
}
Example #17
0
/* Re-import certifciates.  IN_FD is a list of linefeed delimited
   fingerprints t re-import.  The actual re-import is done by clearing
   the ephemeral flag.  */
static int
reimport_one (ctrl_t ctrl, struct stats_s *stats, int in_fd)
{
  gpg_error_t err = 0;
  estream_t fp = NULL;
  char line[100];  /* Sufficient for a fingerprint.  */
  KEYDB_HANDLE kh;
  KEYDB_SEARCH_DESC desc;
  ksba_cert_t cert = NULL;
  unsigned int flags;

  kh = keydb_new (0);
  if (!kh)
    {
      err = gpg_error (GPG_ERR_ENOMEM);;
      log_error (_("failed to allocate keyDB handle\n"));
      goto leave;
    }
  keydb_set_ephemeral (kh, 1);
   
  fp = es_fdopen_nc (in_fd, "r");
  if (!fp)
    {
      err = gpg_error_from_syserror ();
      log_error ("es_fdopen(%d) failed: %s\n", in_fd, gpg_strerror (err));
      goto leave;
    }

  while (es_fgets (line, DIM(line)-1, fp) )
    {
      if (*line && line[strlen(line)-1] != '\n')
        {
          err = gpg_error (GPG_ERR_LINE_TOO_LONG);
          goto leave;
	}
      trim_spaces (line);
      if (!*line)
        continue;
    
      stats->count++;

      err = keydb_classify_name (line, &desc);
      if (err)
        {
          print_import_problem (ctrl, NULL, 0);
          stats->not_imported++;
          continue;
        }

      keydb_search_reset (kh);
      err = keydb_search (kh, &desc, 1);
      if (err)
        {
          print_import_problem (ctrl, NULL, 0);
          stats->not_imported++;
          continue;
        }

      ksba_cert_release (cert);
      cert = NULL;
      err = keydb_get_cert (kh, &cert);
      if (err)
        {
          log_error ("keydb_get_cert() failed: %s\n", gpg_strerror (err));
          print_import_problem (ctrl, NULL, 1);
          stats->not_imported++;
          continue;
        }

      err = keydb_get_flags (kh, KEYBOX_FLAG_BLOB, 0, &flags);
      if (err)
        {
          log_error (_("error getting stored flags: %s\n"), gpg_strerror (err));
          print_imported_status (ctrl, cert, 0);
          stats->not_imported++;
          continue;
        }
      if ( !(flags & KEYBOX_FLAG_BLOB_EPHEMERAL) )
        {
          print_imported_status (ctrl, cert, 0);
          stats->unchanged++;
          continue;
        }

      err = keydb_set_cert_flags (cert, 1, KEYBOX_FLAG_BLOB, 0,
                                  KEYBOX_FLAG_BLOB_EPHEMERAL, 0);
      if (err)
        {
          log_error ("clearing ephemeral flag failed: %s\n",
                     gpg_strerror (err)); 
          print_import_problem (ctrl, cert, 0);
          stats->not_imported++;
          continue;
        }

      print_imported_status (ctrl, cert, 1);
      stats->imported++;
    }
  err = 0;
  if (es_ferror (fp))
    {
      err = gpg_error_from_syserror ();
      log_error ("error reading fd %d: %s\n", in_fd, gpg_strerror (err));
      goto leave;
    }

 leave:
  ksba_cert_release (cert);
  keydb_release (kh);
  es_fclose (fp);
  return err;
}
Example #18
0
File: ocsp.c Project: FMayzek/gnupg
/* Check whether the certificate either given by fingerprint CERT_FPR
   or directly through the CERT object is valid by running an OCSP
   transaction.  With FORCE_DEFAULT_RESPONDER set only the configured
   default responder is used. */
gpg_error_t
ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
              int force_default_responder)
{
  gpg_error_t err;
  ksba_ocsp_t ocsp = NULL;
  ksba_cert_t issuer_cert = NULL;
  ksba_sexp_t sigval = NULL;
  gcry_sexp_t s_sig = NULL;
  ksba_isotime_t current_time;
  ksba_isotime_t this_update, next_update, revocation_time, produced_at;
  ksba_isotime_t tmp_time;
  ksba_status_t status;
  ksba_crl_reason_t reason;
  char *url_buffer = NULL;
  const char *url;
  gcry_md_hd_t md = NULL;
  int i, idx;
  char *oid;
  ksba_name_t name;
  fingerprint_list_t default_signer = NULL;

  /* Get the certificate.  */
  if (cert)
    {
      ksba_cert_ref (cert);

      err = find_issuing_cert (ctrl, cert, &issuer_cert);
      if (err)
        {
          log_error (_("issuer certificate not found: %s\n"),
                     gpg_strerror (err));
          goto leave;
        }
    }
  else
    {
      cert = get_cert_local (ctrl, cert_fpr);
      if (!cert)
        {
          log_error (_("caller did not return the target certificate\n"));
          err = gpg_error (GPG_ERR_GENERAL);
          goto leave;
        }
      issuer_cert = get_issuing_cert_local (ctrl, NULL);
      if (!issuer_cert)
        {
          log_error (_("caller did not return the issuing certificate\n"));
          err = gpg_error (GPG_ERR_GENERAL);
          goto leave;
        }
    }

  /* Create an OCSP instance.  */
  err = ksba_ocsp_new (&ocsp);
  if (err)
    {
      log_error (_("failed to allocate OCSP context: %s\n"),
                 gpg_strerror (err));
      goto leave;
    }



  /* 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.
   */
  url = NULL;
  for (idx=0; !url && !opt.ignore_ocsp_service_url && !force_default_responder
         && !(err=ksba_cert_get_authority_info_access (cert, idx,
                                                       &oid, &name)); idx++)
    {
      if ( !strcmp (oid, oidstr_ocsp) )
        {
          for (i=0; !url && ksba_name_enum (name, i); i++)
            {
              char *p = ksba_name_get_uri (name, i);
              if (p && (!ascii_strncasecmp (p, "http:", 5)
                        || !ascii_strncasecmp (p, "https:", 6)))
                url = url_buffer = p;
              else
                xfree (p);
            }
        }
      ksba_name_release (name);
      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)
        {
          log_info (_("no default OCSP responder defined\n"));
          err = gpg_error (GPG_ERR_CONFIGURATION);
          goto leave;
        }
      if (!opt.ocsp_signer)
        {
          log_info (_("no default OCSP signer defined\n"));
          err = gpg_error (GPG_ERR_CONFIGURATION);
          goto leave;
        }
      url = opt.ocsp_responder;
      default_signer = opt.ocsp_signer;
      if (opt.verbose)
        log_info (_("using default OCSP responder '%s'\n"), url);
    }
  else
    {
      if (opt.verbose)
        log_info (_("using OCSP responder '%s'\n"), url);
    }

  /* Ask the OCSP responder. */
  err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
  if (err)
    {
      log_error (_("failed to establish a hashing context for OCSP: %s\n"),
                 gpg_strerror (err));
      goto leave;
    }
  err = do_ocsp_request (ctrl, ocsp, md, url, cert, issuer_cert);
  if (err)
    goto leave;

  /* 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)
    {
      err = gpg_error (GPG_ERR_INV_OBJ);
      goto leave;
    }
  if ( (err = canon_sexp_to_gcry (sigval, &s_sig)) )
    goto leave;
  xfree (sigval);
  sigval = NULL;
  err = check_signature (ctrl, ocsp, s_sig, md, default_signer);
  if (err)
    goto leave;

  /* We only support one certificate per request.  Check that the
     answer matches the right certificate. */
  err = ksba_ocsp_get_status (ocsp, cert,
                              &status, this_update, next_update,
                              revocation_time, &reason);
  if (err)
    {
      log_error (_("error getting OCSP status for target certificate: %s\n"),
                 gpg_strerror (err));
      goto leave;
    }

  /* In case the certificate has been revoked, we better invalidate
     our cached validation status. */
  if (status == KSBA_STATUS_REVOKED)
    {
      time_t validated_at = 0; /* That is: No cached validation available. */
      err = ksba_cert_set_user_data (cert, "validated_at",
                                     &validated_at, sizeof (validated_at));
      if (err)
        {
          log_error ("set_user_data(validated_at) failed: %s\n",
                     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"),
                status == KSBA_STATUS_GOOD? _("good"):
                status == KSBA_STATUS_REVOKED? _("revoked"):
                status == KSBA_STATUS_UNKNOWN? _("unknown"):
                status == KSBA_STATUS_NONE? _("none"): "?",
                this_update, next_update);
      if (status == KSBA_STATUS_REVOKED)
        log_info (_("certificate has been revoked at: %s due to: %s\n"),
                  revocation_time,
                  reason == KSBA_CRLREASON_UNSPECIFIED?   "unspecified":
                  reason == KSBA_CRLREASON_KEY_COMPROMISE? "key compromise":
                  reason == KSBA_CRLREASON_CA_COMPROMISE?   "CA compromise":
                  reason == KSBA_CRLREASON_AFFILIATION_CHANGED?
                                                      "affiliation changed":
                  reason == KSBA_CRLREASON_SUPERSEDED?   "superseeded":
                  reason == KSBA_CRLREASON_CESSATION_OF_OPERATION?
                                                  "cessation of operation":
                  reason == KSBA_CRLREASON_CERTIFICATE_HOLD?
                                                  "certificate on hold":
                  reason == KSBA_CRLREASON_REMOVE_FROM_CRL?
                                                  "removed from CRL":
                  reason == KSBA_CRLREASON_PRIVILEGE_WITHDRAWN?
                                                  "privilege withdrawn":
                  reason == KSBA_CRLREASON_AA_COMPROMISE? "AA compromise":
                  reason == KSBA_CRLREASON_OTHER?   "other":"?");

    }


  if (status == KSBA_STATUS_REVOKED)
    err = gpg_error (GPG_ERR_CERT_REVOKED);
  else if (status == KSBA_STATUS_UNKNOWN)
    err = gpg_error (GPG_ERR_NO_DATA);
  else if (status != KSBA_STATUS_GOOD)
    err = gpg_error (GPG_ERR_GENERAL);

  /* Allow for some clock skew. */
  gnupg_get_isotime (current_time);
  add_seconds_to_isotime (current_time, opt.ocsp_max_clock_skew);

  if (strcmp (this_update, current_time) > 0 )
    {
      log_error (_("OCSP responder returned a status in the future\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 THIS_UPDATE is not too far back in the past. */
  gnupg_copy_time (tmp_time, this_update);
  add_seconds_to_isotime (tmp_time,
                          opt.ocsp_max_period+opt.ocsp_max_clock_skew);
  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",
                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). */
  if (*next_update)
    {
      gnupg_copy_time (tmp_time, next_update);
      add_seconds_to_isotime (tmp_time,
                              opt.ocsp_current_period+opt.ocsp_max_clock_skew);
      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",
                    current_time, next_update);
          if (!err)
            err = gpg_error (GPG_ERR_TIME_CONFLICT);
        }
    }


 leave:
  gcry_md_close (md);
  gcry_sexp_release (s_sig);
  xfree (sigval);
  ksba_cert_release (issuer_cert);
  ksba_cert_release (cert);
  ksba_ocsp_release (ocsp);
  xfree (url_buffer);
  return err;
}
Example #19
0
/* Delete a certificate or an secret key from a key database. */
static int
delete_one (ctrl_t ctrl, const char *username)
{
  int rc = 0;
  KEYDB_SEARCH_DESC desc;
  KEYDB_HANDLE kh = NULL;
  ksba_cert_t cert = NULL;
  int duplicates = 0;
  int is_ephem = 0;
  
  rc = keydb_classify_name (username, &desc);
  if (rc)
    {
      log_error (_("certificate `%s' not found: %s\n"),
                 username, gpg_strerror (rc));
      gpgsm_status2 (ctrl, STATUS_DELETE_PROBLEM, "1", NULL);
      goto leave;
    }

  kh = keydb_new (0);
  if (!kh)
    {
      log_error ("keydb_new failed\n");
      goto leave;
    }

  /* If the key is specified in a unique way, include ephemeral keys
     in the search.  */
  if ( desc.mode == KEYDB_SEARCH_MODE_FPR
       || desc.mode == KEYDB_SEARCH_MODE_FPR20
       || desc.mode == KEYDB_SEARCH_MODE_FPR16
       || desc.mode == KEYDB_SEARCH_MODE_KEYGRIP )
    {
      is_ephem = 1;
      keydb_set_ephemeral (kh, 1);
    }

  rc = keydb_search (kh, &desc, 1);
  if (!rc)
    rc = keydb_get_cert (kh, &cert);
  if (!rc && !is_ephem)
    {
      unsigned char fpr[20];

      gpgsm_get_fingerprint (cert, 0, fpr, NULL);

    next_ambigious:
      rc = keydb_search (kh, &desc, 1);
      if (rc == -1)
        rc = 0;
      else if (!rc)
        {
          ksba_cert_t cert2 = NULL;
          unsigned char fpr2[20];

          /* We ignore all duplicated certificates which might have
             been inserted due to program bugs. */
          if (!keydb_get_cert (kh, &cert2))
            {
              gpgsm_get_fingerprint (cert2, 0, fpr2, NULL);
              ksba_cert_release (cert2);
              if (!memcmp (fpr, fpr2, 20))
                {
                  duplicates++;
                  goto next_ambigious;
                }
            }
          rc = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
        }
    }
  if (rc)
    {
      if (rc == -1)
        rc = gpg_error (GPG_ERR_NO_PUBKEY);
      log_error (_("certificate `%s' not found: %s\n"),
                 username, gpg_strerror (rc));
      gpgsm_status2 (ctrl, STATUS_DELETE_PROBLEM, "3", NULL);
      goto leave;
    }

  /* We need to search again to get back to the right position. */
  rc = keydb_lock (kh);
  if (rc)
    {
      log_error (_("error locking keybox: %s\n"), gpg_strerror (rc));
      goto leave;
    }
                   
  do 
    {
      keydb_search_reset (kh);
      rc = keydb_search (kh, &desc, 1);
      if (rc)
        {
          log_error ("problem re-searching certificate: %s\n",
                     gpg_strerror (rc));
          goto leave;
        }
      
      rc = keydb_delete (kh, duplicates ? 0 : 1);
      if (rc) 
        goto leave;
      if (opt.verbose)
        {
          if (duplicates)
            log_info (_("duplicated certificate `%s' deleted\n"), username);
          else
            log_info (_("certificate `%s' deleted\n"), username);
        }
    }
  while (duplicates--);

 leave:
  keydb_release (kh);
  ksba_cert_release (cert);
  return rc;
}
Example #20
0
File: ocsp.c Project: FMayzek/gnupg
/* Check the signature of an OCSP repsonse.  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
   used and thus the certificate is one of those identified by
   the fingerprints. */
static gpg_error_t
check_signature (ctrl_t ctrl,
                 ksba_ocsp_t ocsp, gcry_sexp_t s_sig, gcry_md_hd_t md,
                 fingerprint_list_t signer_fpr_list)
{
  gpg_error_t err;
  int algo, cert_idx;
  gcry_sexp_t s_hash;
  ksba_cert_t cert;

  /* Create a suitable S-expression with the hash value of our response. */
  gcry_md_final (md);
  algo = gcry_md_get_algo (md);
  if (algo != GCRY_MD_SHA1 )
    {
      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))",
                         gcry_md_get_algo_dlen (algo),
                         gcry_md_read (md, algo));
  if (err)
    {
      log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err));
      return err;
    }

  /* Get rid of old OCSP specific certificate references. */
  release_ctrl_ocsp_certs (ctrl);

  if (signer_fpr_list && !signer_fpr_list->next)
    {
      /* There is exactly one signer fingerprint given. Thus we use
         the default OCSP responder's certificate and instantly know
         the certificate to use.  */
      cert = get_cert_byhexfpr (signer_fpr_list->hexfpr);
      if (!cert)
        cert = get_cert_local (ctrl, signer_fpr_list->hexfpr);
      if (cert)
        {
          err = check_signature_core (ctrl, cert, s_sig, s_hash,
                                      signer_fpr_list);
          ksba_cert_release (cert);
          cert = NULL;
          if (!err)
            {
              gcry_sexp_release (s_hash);
              return 0; /* Successfully verified the signature. */
            }
        }
    }
  else
    {
      char *name;
      ksba_sexp_t keyid;

      /* Put all certificates included in the response into the cache
         and setup a list of those certificate which will later be
         preferred used when locating certificates.  */
      for (cert_idx=0; (cert = ksba_ocsp_get_cert (ocsp, cert_idx));
           cert_idx++)
        {
          cert_ref_t cref;

          cref = xtrymalloc (sizeof *cref);
          if (!cref)
            log_error (_("allocating list item failed: %s\n"),
                       gcry_strerror (err));
          else if (!cache_cert_silent (cert, &cref->fpr))
            {
              cref->next = ctrl->ocsp_certs;
              ctrl->ocsp_certs = cref;
            }
          else
            xfree (cref);
        }

      /* Get the certificate by means of the responder ID. */
      err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid);
      if (err)
        {
          log_error (_("error getting responder ID: %s\n"),
                     gcry_strerror (err));
          return err;
        }
      cert = find_cert_bysubject (ctrl, name, keyid);
      if (!cert)
        {
          log_error ("responder certificate ");
          if (name)
            log_printf ("'/%s' ", name);
          if (keyid)
            {
              log_printf ("{");
              dump_serial (keyid);
              log_printf ("} ");
            }
          log_printf ("not found\n");
        }
      ksba_free (name);
      ksba_free (keyid);

      if (cert)
        {
          err = check_signature_core (ctrl, cert, s_sig, s_hash,
                                      signer_fpr_list);
          ksba_cert_release (cert);
          if (!err)
            {
              gcry_sexp_release (s_hash);
              return 0; /* Successfully verified the signature. */
            }
        }
    }

  gcry_sexp_release (s_hash);
  log_error (_("no suitable certificate found to verify the OCSP response\n"));
  return gpg_error (GPG_ERR_NO_PUBKEY);
}
Example #21
0
/* Fetch the next certificate. Return 0 on success, GPG_ERR_EOF if no
   (more) certificates are available or any other error
   code. GPG_ERR_TRUNCATED may be returned to indicate that the result
   has been truncated. */
gpg_error_t
fetch_next_cert_ldap (cert_fetch_context_t context,
                      unsigned char **value, size_t *valuelen)
{
  gpg_error_t err;
  unsigned char hdr[5];
  char *p, *pend;
  unsigned long n;
  int okay = 0;
  /* int is_cms = 0; */

  *value = NULL;
  *valuelen = 0;

  err = 0;
  while (!err)
    {
      err = read_buffer (context->reader, hdr, 5);
      if (err)
        break;
      n = buf32_to_ulong (hdr+1);
      if (*hdr == 'V' && okay)
        {
#if 0  /* That code is not yet ready.  */

          if (is_cms)
            {
              /* The certificate needs to be parsed from CMS data. */
              ksba_cms_t cms;
              ksba_stop_reason_t stopreason;
              int i;

              err = ksba_cms_new (&cms);
              if (err)
                goto leave;
              err = ksba_cms_set_reader_writer (cms, context->reader, NULL);
              if (err)
                {
                  log_error ("ksba_cms_set_reader_writer failed: %s\n",
                             gpg_strerror (err));
                  goto leave;
                }

              do
                {
                  err = ksba_cms_parse (cms, &stopreason);
                  if (err)
                    {
                      log_error ("ksba_cms_parse failed: %s\n",
                                 gpg_strerror (err));
                      goto leave;
                    }

                  if (stopreason == KSBA_SR_BEGIN_DATA)
                    log_error ("userSMIMECertificate is not "
                               "a certs-only message\n");
                }
              while (stopreason != KSBA_SR_READY);

              for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
                {
                  check_and_store (ctrl, stats, cert, 0);
                  ksba_cert_release (cert);
                  cert = NULL;
                }
              if (!i)
                log_error ("no certificate found\n");
              else
                any = 1;
            }
          else
#endif
            {
              *value = xtrymalloc (n);
              if (!*value)
                return gpg_error_from_errno (errno);
              *valuelen = n;
              err = read_buffer (context->reader, *value, n);
              break; /* Ready or error.  */
            }
        }
      else if (!n && *hdr == 'A')
        okay = 0;
      else if (n)
        {
          if (n > context->tmpbufsize)
            {
              xfree (context->tmpbuf);
              context->tmpbufsize = 0;
              context->tmpbuf = xtrymalloc (n+1);
              if (!context->tmpbuf)
                return gpg_error_from_errno (errno);
              context->tmpbufsize = n;
            }
          err = read_buffer (context->reader, context->tmpbuf, n);
          if (err)
            break;
          if (*hdr == 'A')
            {
              p = context->tmpbuf;
              p[n] = 0; /*(we allocated one extra byte for this.)*/
              /* fixme: is_cms = 0; */
              if ( (pend = strchr (p, ';')) )
                *pend = 0; /* Strip off the extension. */
              if (!ascii_strcasecmp (p, USERCERTIFICATE))
                {
                  if (DBG_LOOKUP)
                    log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
                               USERCERTIFICATE);
                  okay = 1;
                }
              else if (!ascii_strcasecmp (p, CACERTIFICATE))
                {
                  if (DBG_LOOKUP)
                    log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
                               CACERTIFICATE);
                  okay = 1;
                }
              else if (!ascii_strcasecmp (p, X509CACERT))
                {
                  if (DBG_LOOKUP)
                    log_debug ("fetch_next_cert_ldap: got attribute '%s'\n",
                               CACERTIFICATE);
                  okay = 1;
                }
/*               else if (!ascii_strcasecmp (p, USERSMIMECERTIFICATE)) */
/*                 { */
/*                   if (DBG_LOOKUP) */
/*                     log_debug ("fetch_next_cert_ldap: got attribute '%s'\n", */
/*                                USERSMIMECERTIFICATE); */
/*                   okay = 1; */
/*                   is_cms = 1; */
/*                 } */
              else
                {
                  if (DBG_LOOKUP)
                    log_debug ("fetch_next_cert_ldap: got attribute '%s'"
                               " -  ignored\n", p);
                  okay = 0;
                }
            }
          else if (*hdr == 'E')
            {
              p = context->tmpbuf;
              p[n] = 0; /*(we allocated one extra byte for this.)*/
              if (!strcmp (p, "truncated"))
                {
                  context->truncated = 1;
                  log_info (_("ldap_search hit the size limit of"
                              " the server\n"));
                }
            }
        }
    }

  if (err)
    {
      xfree (*value);
      *value = NULL;
      *valuelen = 0;
      if (gpg_err_code (err) == GPG_ERR_EOF && context->truncated)
        {
          context->truncated = 0; /* So that the next call would return EOF. */
          err = gpg_error (GPG_ERR_TRUNCATED);
        }
    }

  return err;
}
Example #22
0
void 
one_response (const char *cert_fname, const char *issuer_cert_fname,
              char *response_fname)
{
  gpg_error_t err;
  ksba_ocsp_t ocsp;
  unsigned char *request, *response;
  size_t requestlen, responselen;
  ksba_cert_t cert = get_one_cert (cert_fname);
  ksba_cert_t issuer_cert = get_one_cert (issuer_cert_fname);
  ksba_ocsp_response_status_t response_status;
  const char *t;

  err = ksba_ocsp_new (&ocsp);
  fail_if_err (err);

  /* We need to build a request, so that the context is properly
     prepared for the response. */
  err = ksba_ocsp_add_target (ocsp, cert, issuer_cert);
  fail_if_err (err);
  ksba_cert_release (issuer_cert);

  if (!no_nonce)
    ksba_ocsp_set_nonce (ocsp, "ABCDEFGHIJKLMNOP", 16);

  err = ksba_ocsp_build_request (ocsp, &request, &requestlen);
  fail_if_err (err);
  xfree (request);

  /* Now for the response. */
  response = read_file (response_fname, &responselen);
  if (!response)
    fail ("file error");

  err = ksba_ocsp_parse_response (ocsp, response, responselen,
                                  &response_status);
  fail_if_err (err);
  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_NONE:         t = "no status"; break;
    default: fail ("impossible response_status"); break;
    }
  printf ("response status ..: %s\n", t);

  if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS
      || response_status == KSBA_OCSP_RSPSTATUS_REPLAYED)
    {
      ksba_status_t status;
      ksba_crl_reason_t reason;
      ksba_isotime_t this_update, next_update, revocation_time, produced_at;
      ksba_sexp_t sigval;
      char *name;
      ksba_sexp_t keyid;

      err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid);
      fail_if_err (err);
      printf ("responder id .....: ");
      if (name)
        printf ("`%s'", name);
      else
        print_sexp (keyid);
      putchar ('\n');
      ksba_free (name);
      ksba_free (keyid);

      sigval = ksba_ocsp_get_sig_val (ocsp, produced_at);
      printf ("signature value ..: ");
      print_sexp (sigval);
      printf ("\nproduced at ......: ");
      print_time (produced_at);
      putchar ('\n');
      err = ksba_ocsp_get_status (ocsp, cert,
                                  &status, this_update, next_update,
                                  revocation_time, &reason);
      fail_if_err (err);
      printf ("certificate status: %s\n",
              status == KSBA_STATUS_GOOD? "good":
              status == KSBA_STATUS_REVOKED? "revoked":
              status == KSBA_STATUS_UNKNOWN? "unknown":
              status == KSBA_STATUS_NONE? "none": "?");
      if (status == KSBA_STATUS_REVOKED)
        {
          printf ("revocation time ..: ");
          print_time (revocation_time);
          printf ("\nrevocation reason : %s\n",
                  reason == KSBA_CRLREASON_UNSPECIFIED?   "unspecified":        
                  reason == KSBA_CRLREASON_KEY_COMPROMISE? "key compromise":
                  reason == KSBA_CRLREASON_CA_COMPROMISE?   "CA compromise":
                  reason == KSBA_CRLREASON_AFFILIATION_CHANGED?
                                                       "affiliation changed":
                  reason == KSBA_CRLREASON_SUPERSEDED?   "superseeded":
                  reason == KSBA_CRLREASON_CESSATION_OF_OPERATION?
                                                      "cessation of operation": 
                  reason == KSBA_CRLREASON_CERTIFICATE_HOLD?
                                                      "certificate on hold":   
                  reason == KSBA_CRLREASON_REMOVE_FROM_CRL? "removed from CRL":
                  reason == KSBA_CRLREASON_PRIVILEGE_WITHDRAWN?
                                                       "privilege withdrawn":
                  reason == KSBA_CRLREASON_AA_COMPROMISE? "AA compromise":
                  reason == KSBA_CRLREASON_OTHER?   "other":"?");
        }
      printf ("this update ......: ");
      print_time (this_update);
      printf ("\nnext update ......: ");
      print_time (next_update);
      putchar ('\n');
      {
        int cert_idx;
        ksba_cert_t acert;

        for (cert_idx=0; (acert = ksba_ocsp_get_cert (ocsp, cert_idx));
             cert_idx++)
          ksba_cert_release (acert);
        printf ("extra certificates: %d\n", cert_idx );
      }

      {
        int idx, crit;
        const char *oid;
        const unsigned char *der;
        size_t derlen;
        
        for (idx=0; !(err=ksba_ocsp_get_extension (ocsp, NULL, idx,
                                                   &oid, &crit,
                                                   &der, &derlen)); idx++)
          {
            const char *s = get_oid_desc (oid);
            printf ("%sresp-extn ..%s: %s%s%s%s  (",
                    crit? "crit. ":"", 
                    crit?"":"......", 
                    s?"(":"", s?s:"", s?") ":"", oid);
            print_hex (der, derlen);
            putchar (')');
            putchar ('\n');
          }
        if (err && gpg_err_code (err) != GPG_ERR_EOF)
          fail_if_err (err);

        for (idx=0; !(err=ksba_ocsp_get_extension (ocsp, cert, idx,
                                                   &oid, &crit,
                                                   &der, &derlen)); idx++)
          {
            const char *s = get_oid_desc (oid);
            printf ("%ssngl-extn ..%s: %s%s%s%s  (",
                    crit? "crit. ":"", 
                    crit?"":"......", 
                    s?"(":"", s?s:"", s?") ":"", oid);
            print_hex (der, derlen);
            putchar (')');
            putchar ('\n');
          }
        if (err && gpg_err_code (err) != GPG_ERR_EOF)
          fail_if_err (err);
      }
    }
  

  ksba_cert_release (cert);
  ksba_ocsp_release (ocsp);
  xfree (response);
}
Example #23
0
/* Handle a SENDCERT inquiry. */
static gpg_error_t
inq_certificate (void *opaque, const char *line)
{
  struct inq_certificate_parm_s *parm = opaque;
  int rc;
  const unsigned char *der;
  size_t derlen;
  int issuer_mode = 0;
  ksba_sexp_t ski = NULL;

  if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
    {
      line += 8;
    }
  else if (!strncmp (line, "SENDCERT_SKI", 12) && (line[12]==' ' || !line[12]))
    {
      size_t n;

      /* Send a certificate where a sourceKeyIdentifier is included. */
      line += 12;
      while (*line == ' ')
        line++;
      ski = make_simple_sexp_from_hexstr (line, &n);
      line += n;
      while (*line == ' ')
        line++;
    }
  else if (!strncmp (line, "SENDISSUERCERT", 14)
           && (line[14] == ' ' || !line[14]))
    {
      line += 14;
      issuer_mode = 1;
    }
  else if (!strncmp (line, "ISTRUSTED", 9) && (line[9]==' ' || !line[9]))
    {
      /* The server is asking us whether the certificate is a trusted
         root certificate.  */
      const char *s;
      size_t n;
      char fpr[41];
      struct rootca_flags_s rootca_flags;

      line += 9;
      while (*line == ' ')
        line++;

      for (s=line,n=0; hexdigitp (s); s++, n++)
        ;
      if (*s || n != 40)
        return gpg_error (GPG_ERR_ASS_PARAMETER);
      for (s=line, n=0; n < 40; s++, n++)
        fpr[n] = (*s >= 'a')? (*s & 0xdf): *s;
      fpr[n] = 0;
      
      if (!gpgsm_agent_istrusted (parm->ctrl, NULL, fpr, &rootca_flags))
        rc = assuan_send_data (parm->ctx, "1", 1);
      else
        rc = 0;
      return rc;
    }
  else
    {
      log_error ("unsupported inquiry `%s'\n", line);
      return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
    }

  if (!*line)
    { /* Send the current certificate. */
      der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
                                 &derlen);
      if (!der)
        rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
      else
        rc = assuan_send_data (parm->ctx, der, derlen);
    }
  else if (issuer_mode)
    {
      log_error ("sending specific issuer certificate back "
                 "is not yet implemented\n");
      rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
    }
  else 
    { /* Send the given certificate. */
      int err;
      ksba_cert_t cert;


      err = gpgsm_find_cert (line, ski, &cert);
      if (err)
        {
          log_error ("certificate not found: %s\n", gpg_strerror (err));
          rc = gpg_error (GPG_ERR_NOT_FOUND);
        }
      else
        {
          der = ksba_cert_get_image (cert, &derlen);
          if (!der)
            rc = gpg_error (GPG_ERR_INV_CERT_OBJ);
          else
            rc = assuan_send_data (parm->ctx, der, derlen);
          ksba_cert_release (cert);
        }
    }

  xfree (ski);
  return rc; 
}
Example #24
0
/* Return the certificate matching SUBJECT_DN and (if not NULL)
   KEYID. If it is not already in the cache, try to find it from other
   resources.  Note, that the external search does not work for user
   certificates because the LDAP lookup is on the caCertificate
   attribute. For our purposes this is just fine.  */
ksba_cert_t
find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid)
{
  gpg_error_t err;
  int seq;
  ksba_cert_t cert = NULL;
  cert_fetch_context_t context = NULL;
  ksba_sexp_t subj;

  /* If we have certificates from an OCSP request we first try to use
     them.  This is because these certificates will really be the
     required ones and thus even in the case that they can't be
     uniquely located by the following code we can use them.  This is
     for example required by Telesec certificates where a keyId is
     used but the issuer certificate comes without a subject keyId! */
  if (ctrl->ocsp_certs && subject_dn)
    {
      cert_item_t ci;
      cert_ref_t cr;
      int i;

      /* For efficiency reasons we won't use get_cert_bysubject here. */
      acquire_cache_read_lock ();
      for (i=0; i < 256; i++)
        for (ci=cert_cache[i]; ci; ci = ci->next)
          if (ci->cert && ci->subject_dn
              && !strcmp (ci->subject_dn, subject_dn))
            for (cr=ctrl->ocsp_certs; cr; cr = cr->next)
              if (!memcmp (ci->fpr, cr->fpr, 20))
                {
                  ksba_cert_ref (ci->cert);
                  release_cache_lock ();
                  return ci->cert; /* We use this certificate. */
                }
      release_cache_lock ();
      if (DBG_LOOKUP)
        log_debug ("find_cert_bysubject: certificate not in ocsp_certs\n");
    }


  /* First we check whether the certificate is cached.  */
  for (seq=0; (cert = get_cert_bysubject (subject_dn, seq)); seq++)
    {
      if (!keyid)
        break; /* No keyid requested, so return the first one found. */
      if (!ksba_cert_get_subj_key_id (cert, NULL, &subj)
          && !cmp_simple_canon_sexp (keyid, subj))
        {
          xfree (subj);
          break; /* Found matching cert. */
        }
      xfree (subj);
      ksba_cert_release (cert);
    }
  if (cert)
    return cert; /* Done.  */

  if (DBG_LOOKUP)
    log_debug ("find_cert_bysubject: certificate not in cache\n");

  /* Ask back to the service requester to return the certificate.
     This is because we can assume that he already used the
     certificate while checking for the CRL. */
  if (keyid)
    cert = get_cert_local_ski (ctrl, subject_dn, keyid);
  else
    {
      /* In contrast to get_cert_local_ski, get_cert_local uses any
         passed pattern, so we need to make sure that an exact subject
         search is done. */
      char *buf;

      buf = xtrymalloc (1 + strlen (subject_dn) + 1);
      if (!buf)
        {
          log_error ("can't allocate enough memory: %s\n", strerror (errno));
          return NULL;
        }
      strcpy (stpcpy (buf, "/"), subject_dn);
      cert = get_cert_local (ctrl, buf);
      xfree (buf);
    }
  if (cert)
    {
      cache_cert (cert);
      return cert; /* Done. */
    }

  if (DBG_LOOKUP)
    log_debug ("find_cert_bysubject: certificate not returned by caller"
               " - doing lookup\n");

  /* Locate the certificate using external resources. */
  while (!cert)
    {
      char *subjdn;

      if (!context)
        {
          err = ca_cert_fetch (ctrl, &context, subject_dn);
          if (err)
            {
              log_error (_("error fetching certificate by subject: %s\n"),
                         gpg_strerror (err));
              break;
            }
        }

      err = fetch_next_ksba_cert (context, &cert);
      if (err)
        {
          log_error (_("error fetching certificate by subject: %s\n"),
                     gpg_strerror (err) );
          break;
        }

      subjdn = ksba_cert_get_subject (cert, 0);
      if (strcmp (subject_dn, subjdn))
        {
          log_info ("find_cert_bysubject: subject DN does not match\n");
          ksba_cert_release (cert);
          cert = NULL;
          ksba_free (subjdn);
          continue;
        }


      if (DBG_LOOKUP)
        {
          log_debug ("   considering certificate (/");
          dump_string (subjdn);
          log_printf (")\n");
        }
      ksba_free (subjdn);

      /* If no key ID has been provided, we return the first match.  */
      if (!keyid)
        {
          cache_cert (cert);
          if (DBG_LOOKUP)
            log_debug ("   found\n");
          break; /* Ready.  */
        }

      /* With the key ID given we need to compare it.  */
      if (!ksba_cert_get_subj_key_id (cert, NULL, &subj))
        {
          if (!cmp_simple_canon_sexp (keyid, subj))
            {
              ksba_free (subj);
              cache_cert (cert);
              if (DBG_LOOKUP)
                log_debug ("   found\n");
              break; /* Ready.  */
            }
        }

      ksba_free (subj);
      ksba_cert_release (cert);
      cert = NULL;
    }

  end_cert_fetch (context);
  return cert;
}
Example #25
0
/* Call the directory manager to check whether the certificate is valid
   Returns 0 for valid or usually one of the errors:

  GPG_ERR_CERTIFICATE_REVOKED
  GPG_ERR_NO_CRL_KNOWN
  GPG_ERR_CRL_TOO_OLD

  Values for USE_OCSP:
     0 = Do CRL check.
     1 = Do an OCSP check.
     2 = Do an OCSP check using only the default responder.
 */
int
gpgsm_dirmngr_isvalid (ctrl_t ctrl,
                       ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
{
  static int did_options;
  int rc;
  char *certid;
  char line[ASSUAN_LINELENGTH];
  struct inq_certificate_parm_s parm;
  struct isvalid_status_parm_s stparm;

  rc = start_dirmngr (ctrl);
  if (rc)
    return rc;

  if (use_ocsp)
    {
      certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
    }
  else
    {
      certid = gpgsm_get_certid (cert);
      if (!certid)
        {
          log_error ("error getting the certificate ID\n");
	  release_dirmngr (ctrl);
          return gpg_error (GPG_ERR_GENERAL);
        }
    }

  if (opt.verbose > 1)
    {
      char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
      log_info ("asking dirmngr about %s%s\n", fpr,
                use_ocsp? " (using OCSP)":"");
      xfree (fpr);
    }

  parm.ctx = dirmngr_ctx;
  parm.ctrl = ctrl;
  parm.cert = cert;
  parm.issuer_cert = issuer_cert;

  stparm.ctrl = ctrl;
  stparm.seen = 0;
  memset (stparm.fpr, 0, 20);

  /* FIXME: If --disable-crl-checks has been set, we should pass an
     option to dirmngr, so that no fallback CRL check is done after an
     ocsp check.  It is not a problem right now as dirmngr does not
     fallback to CRL checking.  */

  /* It is sufficient to send the options only once because we have
     one connection per process only. */
  if (!did_options)
    {
      if (opt.force_crl_refresh)
        assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
                         NULL, NULL, NULL, NULL, NULL, NULL);
      did_options = 1;
    }
  snprintf (line, DIM(line)-1, "ISVALID%s %s", 
            use_ocsp == 2? " --only-ocsp --force-default-responder":"",
            certid);
  line[DIM(line)-1] = 0;
  xfree (certid);

  rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
                        inq_certificate, &parm,
                        isvalid_status_cb, &stparm);
  if (opt.verbose > 1)
    log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
  rc = rc;

  if (!rc && stparm.seen)
    {
      /* Need to also check the certificate validity. */
      if (stparm.seen != 1)
        {
          log_error ("communication problem with dirmngr detected\n");
          rc = gpg_error (GPG_ERR_INV_CRL);
        }
      else
        {
          KEYDB_HANDLE kh;
          ksba_cert_t rspcert = NULL;

          /* Fixme: First try to get the certificate from the
             dirmngr's cache - it should be there. */
          kh = keydb_new (0);
          if (!kh)
            rc = gpg_error (GPG_ERR_ENOMEM);
          if (!rc)
            rc = keydb_search_fpr (kh, stparm.fpr);
          if (!rc)
            rc = keydb_get_cert (kh, &rspcert);
          if (rc)
            {
              log_error ("unable to find the certificate used "
                         "by the dirmngr: %s\n", gpg_strerror (rc));
              rc = gpg_error (GPG_ERR_INV_CRL);
            }
          keydb_release (kh);

          if (!rc)
            {
              rc = gpgsm_cert_use_ocsp_p (rspcert);
              if (rc)
                rc = gpg_error (GPG_ERR_INV_CRL);
              else
                {
                  /* Note the no_dirmngr flag: This avoids checking
                     this certificate over and over again. */
                  rc = gpgsm_validate_chain (ctrl, rspcert, "", NULL, 0, NULL, 
                                             VALIDATE_FLAG_NO_DIRMNGR, NULL);
                  if (rc)
                    {
                      log_error ("invalid certificate used for CRL/OCSP: %s\n",
                                 gpg_strerror (rc));
                      rc = gpg_error (GPG_ERR_INV_CRL);
                    }
                }
            }
          ksba_cert_release (rspcert);
        }
    }
  release_dirmngr (ctrl);
  return rc;
}
Example #26
0
/* Given the certificate CERT locate the issuer for this certificate
   and return it at R_CERT.  Returns 0 on success or
   GPG_ERR_NOT_FOUND.  */
gpg_error_t
find_issuing_cert (ctrl_t ctrl, ksba_cert_t cert, ksba_cert_t *r_cert)
{
  gpg_error_t err;
  char *issuer_dn;
  ksba_cert_t issuer_cert = NULL;
  ksba_name_t authid;
  ksba_sexp_t authidno;
  ksba_sexp_t keyid;

  *r_cert = NULL;

  issuer_dn = ksba_cert_get_issuer (cert, 0);
  if (!issuer_dn)
    {
      log_error (_("no issuer found in certificate\n"));
      err = gpg_error (GPG_ERR_BAD_CERT);
      goto leave;
    }

  /* First we need to check whether we can return that certificate
     using the authorithyKeyIdentifier.  */
  err = ksba_cert_get_auth_key_id (cert, &keyid, &authid, &authidno);
  if (err)
    {
      log_info (_("error getting authorityKeyIdentifier: %s\n"),
                gpg_strerror (err));
    }
  else
    {
      const char *s = ksba_name_enum (authid, 0);
      if (s && *authidno)
        {
          issuer_cert = find_cert_bysn (ctrl, s, authidno);
        }
      if (!issuer_cert && keyid)
        {
          /* Not found by issuer+s/n.  Now that we have an AKI
             keyIdentifier look for a certificate with a matching
             SKI. */
          issuer_cert = find_cert_bysubject (ctrl, issuer_dn, keyid);
        }
      /* Print a note so that the user does not feel too helpless when
         an issuer certificate was found and gpgsm prints BAD
         signature because it is not the correct one. */
      if (!issuer_cert)
        {
          log_info ("issuer certificate ");
          if (keyid)
            {
              log_printf ("{");
              dump_serial (keyid);
              log_printf ("} ");
            }
          if (authidno)
            {
              log_printf ("(#");
              dump_serial (authidno);
              log_printf ("/");
              dump_string (s);
              log_printf (") ");
            }
          log_printf ("not found using authorityKeyIdentifier\n");
        }
      ksba_name_release (authid);
      xfree (authidno);
      xfree (keyid);
    }

  /* If this did not work, try just with the issuer's name and assume
     that there is only one such certificate.  We only look into our
     cache then. */
  if (err || !issuer_cert)
    {
      issuer_cert = get_cert_bysubject (issuer_dn, 0);
      if (issuer_cert)
        err = 0;
    }

 leave:
  if (!err && !issuer_cert)
    err = gpg_error (GPG_ERR_NOT_FOUND);

  xfree (issuer_dn);

  if (err)
    ksba_cert_release (issuer_cert);
  else
    *r_cert = issuer_cert;

  return err;
}
Example #27
0
static void
check_and_store (ctrl_t ctrl, struct stats_s *stats,
                 ksba_cert_t cert, int depth)
{
  int rc;

  if (stats)
    stats->count++;
  if ( depth >= 50 )
    {
      log_error (_("certificate chain too long\n"));
      if (stats)
        stats->not_imported++;
      print_import_problem (ctrl, cert, 3);
      return;
    }

  /* Some basic checks, but don't care about missing certificates;
     this is so that we are able to import entire certificate chains
     w/o requiring a special order (i.e. root-CA first).  This used
     to be different but because gpgsm_verify even imports
     certificates without any checks, it doesn't matter much and the
     code gets much cleaner.  A housekeeping function to remove
     certificates w/o an anchor would be nice, though. 
     
     Optionally we do a full validation in addition to the basic test.
  */
  rc = gpgsm_basic_cert_check (ctrl, cert);
  if (!rc && ctrl->with_validation)
    rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL);
  if (!rc || (!ctrl->with_validation
              && (gpg_err_code (rc) == GPG_ERR_MISSING_CERT
                  || gpg_err_code (rc) == GPG_ERR_MISSING_ISSUER_CERT)))
    {
      int existed;

      if (!keydb_store_cert (cert, 0, &existed))
        {
          ksba_cert_t next = NULL;

          if (!existed)
            {
              print_imported_status (ctrl, cert, 1);
              if (stats)
                stats->imported++;
            }
          else
            {
              print_imported_status (ctrl, cert, 0);
              if (stats)
                stats->unchanged++;
            }
            
          if (opt.verbose > 1 && existed)
            {
              if (depth)
                log_info ("issuer certificate already in DB\n");
              else
                log_info ("certificate already in DB\n");
            }
          else if (opt.verbose && !existed)
            {
              if (depth)
                log_info ("issuer certificate imported\n");
              else
                log_info ("certificate imported\n");
            }

          /* Now lets walk up the chain and import all certificates up
             the chain.  This is required in case we already stored
             parent certificates in the ephemeral keybox.  Do not
             update the statistics, though. */
          if (!gpgsm_walk_cert_chain (ctrl, cert, &next))
            {
              check_and_store (ctrl, NULL, next, depth+1);
              ksba_cert_release (next);
            }
        }
      else
        {
          log_error (_("error storing certificate\n"));
          if (stats)
            stats->not_imported++;
          print_import_problem (ctrl, cert, 4);
        }
    }
  else
    {
      log_error (_("basic certificate checks failed - not imported\n"));
      if (stats)
        stats->not_imported++;
      /* We keep the test for GPG_ERR_MISSING_CERT only in case
         GPG_ERR_MISSING_CERT has been used instead of the newer
         GPG_ERR_MISSING_ISSUER_CERT.  */
      print_import_problem 
        (ctrl, cert,
         gpg_err_code (rc) == GPG_ERR_MISSING_ISSUER_CERT? 2 :
         gpg_err_code (rc) == GPG_ERR_MISSING_CERT? 2 :
         gpg_err_code (rc) == GPG_ERR_BAD_CERT?     1 : 0);
    }
}
Example #28
0
static int
import_one (ctrl_t ctrl, struct stats_s *stats, int in_fd)
{
  int rc;
  Base64Context b64reader = NULL;
  ksba_reader_t reader;
  ksba_cert_t cert = NULL;
  ksba_cms_t cms = NULL;
  estream_t fp = NULL;
  ksba_content_type_t ct;
  int any = 0;

  fp = es_fdopen_nc (in_fd, "rb");
  if (!fp)
    {
      rc = gpg_error_from_syserror ();
      log_error ("fdopen() failed: %s\n", strerror (errno));
      goto leave;
    }

  rc = gpgsm_create_reader (&b64reader, ctrl, fp, 1, &reader);
  if (rc)
    {
      log_error ("can't create reader: %s\n", gpg_strerror (rc));
      goto leave;
    }


  /* We need to loop here to handle multiple PEM objects in one
     file. */
  do
    {
      ksba_cms_release (cms); cms = NULL;
      ksba_cert_release (cert); cert = NULL;

      ct = ksba_cms_identify (reader);
      if (ct == KSBA_CT_SIGNED_DATA)
        { /* This is probably a signed-only message - import the certs */
          ksba_stop_reason_t stopreason;
          int i;

          rc = ksba_cms_new (&cms);
          if (rc)
            goto leave;

          rc = ksba_cms_set_reader_writer (cms, reader, NULL);
          if (rc)
            {
              log_error ("ksba_cms_set_reader_writer failed: %s\n",
                         gpg_strerror (rc));
              goto leave;
            }

          do
            {
              rc = ksba_cms_parse (cms, &stopreason);
              if (rc)
                {
                  log_error ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
                  goto leave;
                }

              if (stopreason == KSBA_SR_BEGIN_DATA)
                log_info ("not a certs-only message\n");
            }
          while (stopreason != KSBA_SR_READY);

          for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
            {
              check_and_store (ctrl, stats, cert, 0);
              ksba_cert_release (cert);
              cert = NULL;
            }
          if (!i)
            log_error ("no certificate found\n");
          else
            any = 1;
        }
      else if (ct == KSBA_CT_PKCS12)
        {
          /* This seems to be a pkcs12 message. */
          rc = parse_p12 (ctrl, reader, stats);
          if (!rc)
            any = 1;
        }
      else if (ct == KSBA_CT_NONE)
        { /* Failed to identify this message - assume a certificate */

          rc = ksba_cert_new (&cert);
          if (rc)
            goto leave;

          rc = ksba_cert_read_der (cert, reader);
          if (rc)
            goto leave;

          check_and_store (ctrl, stats, cert, 0);
          any = 1;
        }
      else
        {
          log_error ("can't extract certificates from input\n");
          rc = gpg_error (GPG_ERR_NO_DATA);
        }

      ksba_reader_clear (reader, NULL, NULL);
    }
  while (!gpgsm_reader_eof_seen (b64reader));

 leave:
  if (any && gpg_err_code (rc) == GPG_ERR_EOF)
    rc = 0;
  ksba_cms_release (cms);
  ksba_cert_release (cert);
  gpgsm_destroy_reader (b64reader);
  es_fclose (fp);
  return rc;
}
Example #29
0
/* Validate the certificate CHAIN up to the trust anchor. Optionally
   return the closest expiration time in R_EXPTIME (this is useful for
   caching issues).  MODE is one of the VALIDATE_MODE_* constants.

   If R_TRUST_ANCHOR is not NULL and the validation would fail only
   because the root certificate is not trusted, the hexified
   fingerprint of that root certificate is stored at R_TRUST_ANCHOR
   and success is returned.  The caller needs to free the value at
   R_TRUST_ANCHOR; in all other cases NULL is stored there.  */
gpg_error_t
validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
                     int mode, char **r_trust_anchor)
{
  gpg_error_t err = 0;
  int depth, maxdepth;
  char *issuer = NULL;
  char *subject = NULL;
  ksba_cert_t subject_cert = NULL, issuer_cert = NULL;
  ksba_isotime_t current_time;
  ksba_isotime_t exptime;
  int any_expired = 0;
  int any_no_policy_match = 0;
  chain_item_t chain;


  if (r_exptime)
    *r_exptime = 0;
  *exptime = 0;

  if (r_trust_anchor)
    *r_trust_anchor = NULL;

  if (!opt.system_daemon)
    {
      /* For backward compatibility we only do this in daemon mode.  */
      log_info (_("running in compatibility mode - "
                  "certificate chain not checked!\n"));
      return 0; /* Okay. */
    }

  if (DBG_X509)
    dump_cert ("subject", cert);

  /* May the target certificate be used for this purpose?  */
  switch (mode)
    {
    case VALIDATE_MODE_OCSP:
      err = cert_use_ocsp_p (cert);
      break;
    case VALIDATE_MODE_CRL:
    case VALIDATE_MODE_CRL_RECURSIVE:
      err = cert_use_crl_p (cert);
      break;
    default:
      err = 0;
      break;
    }
  if (err)
    return err;

  /* If we already validated the certificate not too long ago, we can
     avoid the excessive computations and lookups unless the caller
     asked for the expiration time.  */
  if (!r_exptime)
    {
      size_t buflen;
      time_t validated_at;

      err = ksba_cert_get_user_data (cert, "validated_at",
                                     &validated_at, sizeof (validated_at),
                                     &buflen);
      if (err || buflen != sizeof (validated_at) || !validated_at)
        err = 0; /* Not available or other error. */
      else
        {
          /* If the validation is not older than 30 minutes we are ready. */
          if (validated_at < gnupg_get_time () + (30*60))
            {
              if (opt.verbose)
                log_info ("certificate is good (cached)\n");
              /* Note, that we can't jump to leave here as this would
                 falsely updated the validation timestamp.  */
              return 0;
            }
        }
    }

  /* Get the current time. */
  gnupg_get_isotime (current_time);

  /* We walk up the chain until we find a trust anchor. */
  subject_cert = cert;
  maxdepth = 10;
  chain = NULL;
  depth = 0;
  for (;;)
    {
      /* Get the subject and issuer name from the current
         certificate.  */
      ksba_free (issuer);
      ksba_free (subject);
      issuer = ksba_cert_get_issuer (subject_cert, 0);
      subject = ksba_cert_get_subject (subject_cert, 0);

      if (!issuer)
        {
          log_error (_("no issuer found in certificate\n"));
          err = gpg_error (GPG_ERR_BAD_CERT);
          goto leave;
        }

      /* Handle the notBefore and notAfter timestamps.  */
      {
        ksba_isotime_t not_before, not_after;

        err = ksba_cert_get_validity (subject_cert, 0, not_before);
        if (!err)
          err = ksba_cert_get_validity (subject_cert, 1, not_after);
        if (err)
          {
            log_error (_("certificate with invalid validity: %s"),
                       gpg_strerror (err));
            err = gpg_error (GPG_ERR_BAD_CERT);
            goto leave;
          }

        /* Keep track of the nearest expiration time in EXPTIME.  */
        if (*not_after)
          {
            if (!*exptime)
              gnupg_copy_time (exptime, not_after);
            else if (strcmp (not_after, exptime) < 0 )
              gnupg_copy_time (exptime, not_after);
          }

        /* Check whether the certificate is already valid.  */
        if (*not_before && strcmp (current_time, not_before) < 0 )
          {
            log_error (_("certificate not yet valid"));
            log_info ("(valid from ");
            dump_isotime (not_before);
            log_printf (")\n");
            err = gpg_error (GPG_ERR_CERT_TOO_YOUNG);
            goto leave;
          }

        /* Now check whether the certificate has expired.  */
        if (*not_after && strcmp (current_time, not_after) > 0 )
          {
            log_error (_("certificate has expired"));
            log_info ("(expired at ");
            dump_isotime (not_after);
            log_printf (")\n");
            any_expired = 1;
          }
      }

      /* Do we have any critical extensions in the certificate we
         can't handle? */
      err = unknown_criticals (subject_cert);
      if (err)
        goto leave; /* yes. */

      /* Check that given policies are allowed.  */
      err = check_cert_policy (subject_cert);
      if (gpg_err_code (err) == GPG_ERR_NO_POLICY_MATCH)
        {
          any_no_policy_match = 1;
          err = 0;
        }
      else if (err)
        goto leave;

      /* Is this a self-signed certificate? */
      if (is_root_cert ( subject_cert, issuer, subject))
        {
          /* Yes, this is our trust anchor.  */
          if (check_cert_sig (subject_cert, subject_cert) )
            {
              log_error (_("selfsigned certificate has a BAD signature"));
              err = gpg_error (depth? GPG_ERR_BAD_CERT_CHAIN
                                    : GPG_ERR_BAD_CERT);
              goto leave;
            }

          /* Is this certificate allowed to act as a CA.  */
          err = allowed_ca (subject_cert, NULL);
          if (err)
            goto leave;  /* No. */

          err = is_trusted_cert (subject_cert);
          if (!err)
            ; /* Yes we trust this cert.  */
          else if (gpg_err_code (err) == GPG_ERR_NOT_TRUSTED)
            {
              char *fpr;

              log_error (_("root certificate is not marked trusted"));
              fpr = get_fingerprint_hexstring (subject_cert);
              log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
              dump_cert ("issuer", subject_cert);
              if (r_trust_anchor)
                {
                  /* Caller wants to do another trustiness check.  */
                  *r_trust_anchor = fpr;
                  err = 0;
                }
              else
                xfree (fpr);
            }
          else
            {
              log_error (_("checking trustworthiness of "
                           "root certificate failed: %s\n"),
                         gpg_strerror (err));
            }
          if (err)
            goto leave;

          /* Prepend the certificate to our list.  */
          {
            chain_item_t ci;

            ci = xtrycalloc (1, sizeof *ci);
            if (!ci)
              {
                err = gpg_error_from_errno (errno);
                goto leave;
              }
            ksba_cert_ref (subject_cert);
            ci->cert = subject_cert;
            cert_compute_fpr (subject_cert, ci->fpr);
            ci->next = chain;
            chain = ci;
          }

          if (opt.verbose)
            {
              if (r_trust_anchor && *r_trust_anchor)
                log_info ("root certificate is good but not trusted\n");
              else
                log_info ("root certificate is good and trusted\n");
            }

          break;  /* Okay: a self-signed certicate is an end-point. */
        }

      /* To avoid loops, we use an arbitrary limit on the length of
         the chain. */
      depth++;
      if (depth > maxdepth)
        {
          log_error (_("certificate chain too long\n"));
          err = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
          goto leave;
        }

      /* Find the next cert up the tree. */
      ksba_cert_release (issuer_cert); issuer_cert = NULL;
      err = find_issuing_cert (ctrl, subject_cert, &issuer_cert);
      if (err)
        {
          if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
            {
              log_error (_("issuer certificate not found"));
              log_info ("issuer certificate: #/");
              dump_string (issuer);
              log_printf ("\n");
            }
          else
            log_error (_("issuer certificate not found: %s\n"),
                         gpg_strerror (err));
          /* Use a better understandable error code.  */
          err = gpg_error (GPG_ERR_MISSING_ISSUER_CERT);
          goto leave;
        }

/*     try_another_cert: */
      if (DBG_X509)
        {
          log_debug ("got issuer's certificate:\n");
          dump_cert ("issuer", issuer_cert);
        }

      /* Now check the signature of the certificate.  Well, we
         should delay this until later so that faked certificates
         can't be turned into a DoS easily.  */
      err = check_cert_sig (issuer_cert, subject_cert);
      if (err)
        {
          log_error (_("certificate has a BAD signature"));
#if 0
          if (gpg_err_code (err) == GPG_ERR_BAD_SIGNATURE)
            {
              /* We now try to find other issuer certificates which
                 might have been used.  This is required because some
                 CAs are reusing the issuer and subject DN for new
                 root certificates without using a  authorityKeyIdentifier. */
              rc = find_up (kh, subject_cert, issuer, 1);
              if (!rc)
                {
                  ksba_cert_t tmp_cert;

                  rc = keydb_get_cert (kh, &tmp_cert);
                  if (rc || !compare_certs (issuer_cert, tmp_cert))
                    {
                      /* The find next did not work or returned an
                         identical certificate.  We better stop here
                         to avoid infinite checks. */
                      rc = gpg_error (GPG_ERR_BAD_SIGNATURE);
                      ksba_cert_release (tmp_cert);
                    }
                  else
                    {
                      do_list (0, lm, fp, _("found another possible matching "
                                            "CA certificate - trying again"));
                      ksba_cert_release (issuer_cert);
                      issuer_cert = tmp_cert;
                      goto try_another_cert;
                    }
                }
            }
#endif
          /* We give a more descriptive error code than the one
             returned from the signature checking. */
          err = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
          goto leave;
        }

      /* Check that the length of the chain is not longer than allowed
         by the CA.  */
      {
        int chainlen;

        err = allowed_ca (issuer_cert, &chainlen);
        if (err)
          goto leave;
        if (chainlen >= 0 && (depth - 1) > chainlen)
          {
            log_error (_("certificate chain longer than allowed by CA (%d)"),
                       chainlen);
            err = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
            goto leave;
          }
      }

      /* May that certificate be used for certification? */
      err = cert_use_cert_p (issuer_cert);
      if (err)
        goto leave;  /* No.  */

      /* Prepend the certificate to our list.  */
      {
        chain_item_t ci;

        ci = xtrycalloc (1, sizeof *ci);
        if (!ci)
          {
            err = gpg_error_from_errno (errno);
            goto leave;
          }
        ksba_cert_ref (subject_cert);
        ci->cert = subject_cert;
        cert_compute_fpr (subject_cert, ci->fpr);
        ci->next = chain;
        chain = ci;
      }

      if (opt.verbose)
        log_info (_("certificate is good\n"));

      /* Now to the next level up.  */
      subject_cert = issuer_cert;
      issuer_cert = NULL;
    }

  if (!err)
    { /* If we encountered an error somewhere during the checks, set
         the error code to the most critical one */
      if (any_expired)
        err = gpg_error (GPG_ERR_CERT_EXPIRED);
      else if (any_no_policy_match)
        err = gpg_error (GPG_ERR_NO_POLICY_MATCH);
    }

  if (!err && opt.verbose)
    {
      chain_item_t citem;

      log_info (_("certificate chain is good\n"));
      for (citem = chain; citem; citem = citem->next)
        cert_log_name ("  certificate", citem->cert);
    }

  if (!err && mode != VALIDATE_MODE_CRL)
    { /* Now that everything is fine, walk the chain and check each
         certificate for revocations.

         1. item in the chain  - The root certificate.
         2. item               - the CA below the root
         last item             - the target certificate.

         Now for each certificate in the chain check whether it has
         been included in a CRL and thus be revoked.  We don't do OCSP
         here because this does not seem to make much sense.  This
         might become a recursive process and we should better cache
         our validity results to avoid double work.  Far worse a
         catch-22 may happen for an improper setup hierarchy and we
         need a way to break up such a deadlock. */
      err = check_revocations (ctrl, chain);
    }

  if (!err && opt.verbose)
    {
      if (r_trust_anchor && *r_trust_anchor)
        log_info ("target certificate may be valid\n");
      else
        log_info ("target certificate is valid\n");
    }
  else if (err && opt.verbose)
    log_info ("target certificate is NOT valid\n");


 leave:
  if (!err && !(r_trust_anchor && *r_trust_anchor))
    {
      /* With no error we can update the validation cache.  We do this
         for all certificates in the chain.  Note that we can't use
         the cache if the caller requested to check the trustiness of
         the root certificate himself.  Adding such a feature would
         require us to also store the fingerprint of root
         certificate.  */
      chain_item_t citem;
      time_t validated_at = gnupg_get_time ();

      for (citem = chain; citem; citem = citem->next)
        {
          err = ksba_cert_set_user_data (citem->cert, "validated_at",
                                         &validated_at, sizeof (validated_at));
          if (err)
            {
              log_error ("set_user_data(validated_at) failed: %s\n",
                         gpg_strerror (err));
              err = 0;
            }
        }
    }

  if (r_exptime)
    gnupg_copy_time (r_exptime, exptime);
  ksba_free (issuer);
  ksba_free (subject);
  ksba_cert_release (issuer_cert);
  if (subject_cert != cert)
    ksba_cert_release (subject_cert);
  while (chain)
    {
      chain_item_t ci_next = chain->next;
      if (chain->cert)
        ksba_cert_release (chain->cert);
      xfree (chain);
      chain = ci_next;
    }
  if (err && r_trust_anchor && *r_trust_anchor)
    {
      xfree (*r_trust_anchor);
      *r_trust_anchor = NULL;
    }
  return err;
}
Example #30
0
static int
import_one (ctrl_t ctrl, struct stats_s *stats, int in_fd)
{
  int rc;
  Base64Context b64reader = NULL;
  ksba_reader_t reader;
  ksba_cert_t cert = NULL;
  ksba_cms_t cms = NULL;
  FILE *fp = NULL;
  ksba_content_type_t ct;
  int any = 0;

  fp = fdopen ( dup (in_fd), "rb");
  if (!fp)
    {
      rc = gpg_error (gpg_err_code_from_errno (errno));
      log_error ("fdopen() failed: %s\n", strerror (errno));
      goto leave;
    }

  rc = gpgsm_create_reader (&b64reader, ctrl, fp, 1, &reader);
  if (rc)
    {
      log_error ("can't create reader: %s\n", gpg_strerror (rc));
      goto leave;
    }
  
  
  /* We need to loop here to handle multiple PEM objects in one
     file. */
  do
    {
      ksba_cms_release (cms); cms = NULL;
      ksba_cert_release (cert); cert = NULL;
      
      ct = ksba_cms_identify (reader);
      if (ct == KSBA_CT_SIGNED_DATA)
        { /* This is probably a signed-only message - import the certs */
          ksba_stop_reason_t stopreason;
          int i;
          
          rc = ksba_cms_new (&cms);
          if (rc)
            goto leave;
          
          rc = ksba_cms_set_reader_writer (cms, reader, NULL);
          if (rc)
            {
              log_error ("ksba_cms_set_reader_writer failed: %s\n",
                         gpg_strerror (rc));
              goto leave;
            }

          do 
            {
              rc = ksba_cms_parse (cms, &stopreason);
              if (rc)
                {
                  log_error ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
                  goto leave;
                }

              if (stopreason == KSBA_SR_BEGIN_DATA)
                log_info ("not a certs-only message\n");
            }
          while (stopreason != KSBA_SR_READY);   
      
          for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
            {
              check_and_store (ctrl, stats, cert, 0);
              ksba_cert_release (cert); 
              cert = NULL;
            }
          if (!i)
            log_error ("no certificate found\n");
          else
            any = 1;
        }
      else if (ct == KSBA_CT_PKCS12)
        { /* This seems to be a pkcs12 message.  We use an external
             tool to parse the message and to store the private keys.
             We need to use a another reader here to parse the
             certificate we included in the p12 file; then we continue
             to look for other pkcs12 files (works only if they are in
             PEM format. */
          FILE *certfp;
          Base64Context b64p12rdr;
          ksba_reader_t p12rdr;
          
          rc = parse_p12 (ctrl, reader, &certfp, stats);
          if (!rc)
            {
              any = 1;
              
              rewind (certfp);
              rc = gpgsm_create_reader (&b64p12rdr, ctrl, certfp, 1, &p12rdr);
              if (rc)
                {
                  log_error ("can't create reader: %s\n", gpg_strerror (rc));
                  fclose (certfp);
                  goto leave;
                }

              do
                {
                  ksba_cert_release (cert); cert = NULL;
                  rc = ksba_cert_new (&cert);
                  if (!rc)
                    {
                      rc = ksba_cert_read_der (cert, p12rdr);
                      if (!rc)
                        check_and_store (ctrl, stats, cert, 0);
                    }
                  ksba_reader_clear (p12rdr, NULL, NULL);
                }
              while (!rc && !gpgsm_reader_eof_seen (b64p12rdr));

              if (gpg_err_code (rc) == GPG_ERR_EOF)
                rc = 0;
              gpgsm_destroy_reader (b64p12rdr);
              fclose (certfp);
              if (rc)
                goto leave;
            }
        }
      else if (ct == KSBA_CT_NONE)
        { /* Failed to identify this message - assume a certificate */

          rc = ksba_cert_new (&cert);
          if (rc)
            goto leave;

          rc = ksba_cert_read_der (cert, reader);
          if (rc)
            goto leave;

          check_and_store (ctrl, stats, cert, 0);
          any = 1;
        }
      else
        {
          log_error ("can't extract certificates from input\n");
          rc = gpg_error (GPG_ERR_NO_DATA);
        }
      
      ksba_reader_clear (reader, NULL, NULL);
    }
  while (!gpgsm_reader_eof_seen (b64reader));

 leave:
  if (any && gpg_err_code (rc) == GPG_ERR_EOF)
    rc = 0;
  ksba_cms_release (cms);
  ksba_cert_release (cert);
  gpgsm_destroy_reader (b64reader);
  if (fp)
    fclose (fp);
  return rc;
}