Beispiel #1
0
/* Log the certificate's name in "#SN/ISSUERDN" format along with
   TEXT. */
void
gpgsm_cert_log_name (const char *text, ksba_cert_t cert)
{
  log_info ("%s", text? text:"certificate" );
  if (cert)
    {
      ksba_sexp_t sn;
      char *p;

      p = ksba_cert_get_issuer (cert, 0);
      sn = ksba_cert_get_serial (cert);
      if (p && sn)
        {
          log_printf (" #");
          gpgsm_dump_serial (sn);
          log_printf ("/");
          gpgsm_dump_string (p);
        }
      else
        log_printf (" [invalid]");
      ksba_free (sn);
      xfree (p);
    }
  log_printf ("\n");
}
Beispiel #2
0
/* Create a key description for the CERT, this may be passed to the
   pinentry.  The caller must free the returned string.  NULL may be
   returned on error. */
char *
gpgsm_format_keydesc (ksba_cert_t cert)
{
  char *name, *subject, *buffer;
  ksba_isotime_t t;
  char created[20];
  char expires[20];
  char *sn;
  ksba_sexp_t sexp;
  char *orig_codeset;

  name = ksba_cert_get_subject (cert, 0);
  subject = name? gpgsm_format_name2 (name, 0) : NULL;
  ksba_free (name); name = NULL;

  sexp = ksba_cert_get_serial (cert);
  sn = sexp? gpgsm_format_serial (sexp) : NULL;
  ksba_free (sexp);

  ksba_cert_get_validity (cert, 0, t);
  if (*t)
    sprintf (created, "%.4s-%.2s-%.2s", t, t+4, t+6);
  else
    *created = 0;
  ksba_cert_get_validity (cert, 1, t);
  if (*t)
    sprintf (expires, "%.4s-%.2s-%.2s", t, t+4, t+6);
  else
    *expires = 0;

  orig_codeset = i18n_switchto_utf8 ();

  name = xtryasprintf (_("Please enter the passphrase to unlock the"
                         " secret key for the X.509 certificate:\n"
                         "\"%s\"\n"
                         "S/N %s, ID 0x%08lX,\n"
                         "created %s, expires %s.\n" ),
                       subject? subject:"?",
                       sn? sn: "?",
                       gpgsm_get_short_fingerprint (cert, NULL),
                       created, expires);

  i18n_switchback (orig_codeset);

  if (!name)
    {
      xfree (subject);
      xfree (sn);
      return NULL;
    }

  xfree (subject);
  xfree (sn);

  buffer = percent_plus_escape (name);
  xfree (name);
  return buffer;
}
Beispiel #3
0
/* For certain purposes we need a certificate id which has an upper
   limit of the size.  We use the hash of the issuer name and the
   serial number for this.  In most cases the serial number is not
   that large and the resulting string can be passed on an assuan
   command line.  Everything is hexencoded with the serialnumber
   delimited from the hash by a dot.

   The caller must free the string.
*/
char *
gpgsm_get_certid (ksba_cert_t cert)
{
  ksba_sexp_t serial;
  char *p;
  char *endp;
  unsigned char hash[20];
  unsigned long n;
  char *certid;
  int i;

  p = ksba_cert_get_issuer (cert, 0);
  if (!p)
    return NULL; /* Ooops: No issuer */
  gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
  xfree (p);

  serial = ksba_cert_get_serial (cert);
  if (!serial)
    return NULL; /* oops: no serial number */
  p = (char *)serial;
  if (*p != '(')
    {
      log_error ("Ooops: invalid serial number\n");
      xfree (serial);
      return NULL;
    }
  p++;
  n = strtoul (p, &endp, 10);
  p = endp;
  if (*p != ':')
    {
      log_error ("Ooops: invalid serial number (no colon)\n");
      xfree (serial);
      return NULL;
    }
  p++;

  certid = xtrymalloc ( 40 + 1 + n*2 + 1);
  if (!certid)
    {
      xfree (serial);
      return NULL; /* out of core */
    }

  for (i=0, endp = certid; i < 20; i++, endp += 2 )
    sprintf (endp, "%02X", hash[i]);
  *endp++ = '.';
  for (i=0; i < n; i++, endp += 2)
    sprintf (endp, "%02X", ((unsigned char*)p)[i]);
  *endp = 0;

  xfree (serial);
  return certid;
}
Beispiel #4
0
/* This simple dump function is mainly used for debugging purposes. */
void
gpgsm_dump_cert (const char *text, ksba_cert_t cert)
{
  ksba_sexp_t sexp;
  char *p;
  char *dn;
  ksba_isotime_t t;

  log_debug ("BEGIN Certificate '%s':\n", text? text:"");
  if (cert)
    {
      sexp = ksba_cert_get_serial (cert);
      log_debug ("     serial: ");
      gpgsm_dump_serial (sexp);
      ksba_free (sexp);
      log_printf ("\n");

      ksba_cert_get_validity (cert, 0, t);
      log_debug ("  notBefore: ");
      dump_isotime (t);
      log_printf ("\n");
      ksba_cert_get_validity (cert, 1, t);
      log_debug ("   notAfter: ");
      dump_isotime (t);
      log_printf ("\n");

      dn = ksba_cert_get_issuer (cert, 0);
      log_debug ("     issuer: ");
      gpgsm_dump_string (dn);
      ksba_free (dn);
      log_printf ("\n");

      dn = ksba_cert_get_subject (cert, 0);
      log_debug ("    subject: ");
      gpgsm_dump_string (dn);
      ksba_free (dn);
      log_printf ("\n");

      log_debug ("  hash algo: %s\n", ksba_cert_get_digest_algo (cert));

      p = gpgsm_get_fingerprint_string (cert, 0);
      log_debug ("  SHA1 Fingerprint: %s\n", p);
      xfree (p);
    }
  log_debug ("END Certificate\n");
}
Beispiel #5
0
/* Print some info about the certifciate CERT to FP or STREAM */
static void
print_short_info (ksba_cert_t cert, estream_t stream)
{
  char *p;
  ksba_sexp_t sexp;
  int idx;

  for (idx=0; (p = ksba_cert_get_issuer (cert, idx)); idx++)
    {
      es_fputs ((!idx
                 ?   "Issuer ...: "
                 : "\n   aka ...: "), stream);
      gpgsm_es_print_name (stream, p);
      xfree (p);
    }
  es_putc ('\n', stream);

  es_fputs ("Serial ...: ", stream);
  sexp = ksba_cert_get_serial (cert);
  if (sexp)
    {
      int len;
      const unsigned char *s = sexp;

      if (*s == '(')
        {
          s++;
          for (len=0; *s && *s != ':' && digitp (s); s++)
            len = len*10 + atoi_1 (s);
          if (*s == ':')
            es_write_hexstring (stream, s+1, len, 0, NULL);
        }
      xfree (sexp);
    }
  es_putc ('\n', stream);

  for (idx=0; (p = ksba_cert_get_subject (cert, idx)); idx++)
    {
      es_fputs ((!idx
                 ?   "Subject ..: "
                 : "\n    aka ..: "), stream);
      gpgsm_es_print_name (stream, p);
      xfree (p);
    }
  es_putc ('\n', stream);
}
Beispiel #6
0
/* Check whether CERT is a root certificate.  ISSUERDN and SUBJECTDN
   are the DNs already extracted by the caller from CERT.  Returns
   True if this is the case. */
static int
is_root_cert (ksba_cert_t cert, const char *issuerdn, const char *subjectdn)
{
  gpg_error_t err;
  int result = 0;
  ksba_sexp_t serialno;
  ksba_sexp_t ak_keyid;
  ksba_name_t ak_name;
  ksba_sexp_t ak_sn;
  const char *ak_name_str;
  ksba_sexp_t subj_keyid = NULL;

  if (!issuerdn || !subjectdn)
    return 0;  /* No.  */

  if (strcmp (issuerdn, subjectdn))
    return 0;  /* No.  */

  err = ksba_cert_get_auth_key_id (cert, &ak_keyid, &ak_name, &ak_sn);
  if (err)
    {
      if (gpg_err_code (err) == GPG_ERR_NO_DATA)
        return 1; /* Yes. Without a authorityKeyIdentifier this needs
                     to be the Root certifcate (our trust anchor).  */
      log_error ("error getting authorityKeyIdentifier: %s\n",
                 gpg_strerror (err));
      return 0; /* Well, it is broken anyway.  Return No. */
    }

  serialno = ksba_cert_get_serial (cert);
  if (!serialno)
    {
      log_error ("error getting serialno: %s\n", gpg_strerror (err));
      goto leave;
    }

  /* Check whether the auth name's matches the issuer name+sn.  If
     that is the case this is a root certificate.  */
  ak_name_str = ksba_name_enum (ak_name, 0);
  if (ak_name_str
      && !strcmp (ak_name_str, issuerdn)
      && !cmp_simple_canon_sexp (ak_sn, serialno))
    {
      result = 1;  /* Right, CERT is self-signed.  */
      goto leave;
    }

  /* Similar for the ak_keyid. */
  if (ak_keyid && !ksba_cert_get_subj_key_id (cert, NULL, &subj_keyid)
      && !cmp_simple_canon_sexp (ak_keyid, subj_keyid))
    {
      result = 1;  /* Right, CERT is self-signed.  */
      goto leave;
    }


 leave:
  ksba_free (subj_keyid);
  ksba_free (ak_keyid);
  ksba_name_release (ak_name);
  ksba_free (ak_sn);
  ksba_free (serialno);
  return result;
}
Beispiel #7
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;
}
Beispiel #8
0
/* Put the certificate CERT into the cache.  It is assumed that the
   cache is locked while this function is called. If FPR_BUFFER is not
   NULL the fingerprint of the certificate will be stored there.
   FPR_BUFFER neds to point to a buffer of at least 20 bytes. The
   fingerprint will be stored on success or when the function returns
   gpg_err_code(GPG_ERR_DUP_VALUE). */
static gpg_error_t
put_cert (ksba_cert_t cert, int is_loaded, int is_trusted, void *fpr_buffer)
{
  unsigned char help_fpr_buffer[20], *fpr;
  cert_item_t ci;

  fpr = fpr_buffer? fpr_buffer : &help_fpr_buffer;

  /* If we already reached the caching limit, drop a couple of certs
     from the cache.  Our dropping strategy is simple: We keep a
     static index counter and use this to start looking for
     certificates, then we drop 5 percent of the oldest certificates
     starting at that index.  For a large cache this is a fair way of
     removing items. An LRU strategy would be better of course.
     Because we append new entries to the head of the list and we want
     to remove old ones first, we need to do this from the tail.  The
     implementation is not very efficient but compared to the long
     time it takes to retrieve a certifciate from an external resource
     it seems to be reasonable. */
  if (!is_loaded && total_extra_certificates >= MAX_EXTRA_CACHED_CERTS)
    {
      static int idx;
      cert_item_t ci_mark;
      int i;
      unsigned int drop_count;

      drop_count = MAX_EXTRA_CACHED_CERTS / 20;
      if (drop_count < 2)
        drop_count = 2;

      log_info (_("dropping %u certificates from the cache\n"), drop_count);
      assert (idx < 256);
      for (i=idx; drop_count; i = ((i+1)%256))
        {
          ci_mark = NULL;
          for (ci = cert_cache[i]; ci; ci = ci->next)
            if (ci->cert && !ci->flags.loaded)
              ci_mark = ci;
          if (ci_mark)
            {
              clean_cache_slot (ci_mark);
              drop_count--;
              total_extra_certificates--;
            }
        }
      if (i==idx)
        idx++;
      else
        idx = i;
      idx %= 256;
    }

  cert_compute_fpr (cert, fpr);
  for (ci=cert_cache[*fpr]; ci; ci = ci->next)
    if (ci->cert && !memcmp (ci->fpr, fpr, 20))
      return gpg_error (GPG_ERR_DUP_VALUE);
  /* Try to reuse an existing entry.  */
  for (ci=cert_cache[*fpr]; ci; ci = ci->next)
    if (!ci->cert)
      break;
  if (!ci)
    { /* No: Create a new entry.  */
      ci = xtrycalloc (1, sizeof *ci);
      if (!ci)
        return gpg_error_from_errno (errno);
      ci->next = cert_cache[*fpr];
      cert_cache[*fpr] = ci;
    }
  else
    memset (&ci->flags, 0, sizeof ci->flags);

  ksba_cert_ref (cert);
  ci->cert = cert;
  memcpy (ci->fpr, fpr, 20);
  ci->sn = ksba_cert_get_serial (cert);
  ci->issuer_dn = ksba_cert_get_issuer (cert, 0);
  if (!ci->issuer_dn || !ci->sn)
    {
      clean_cache_slot (ci);
      return gpg_error (GPG_ERR_INV_CERT_OBJ);
    }
  ci->subject_dn = ksba_cert_get_subject (cert, 0);
  ci->flags.loaded  = !!is_loaded;
  ci->flags.trusted = !!is_trusted;

  if (is_loaded)
    total_loaded_certificates++;
  else
    total_extra_certificates++;

  return 0;
}