Example #1
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 #2
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;
}
Example #3
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 #4
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 #5
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;
}