static int
blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
                   int fproff, int fprlen)
{
  const unsigned char *buffer;
  size_t length;
  size_t pos, off;
  size_t nkeys, keyinfolen;
  int idx;

  buffer = _keybox_get_blob_image (blob, &length);
  if (length < 40)
    return 0; /* blob too short */

  /*keys*/
  nkeys = get16 (buffer + 16);
  keyinfolen = get16 (buffer + 18 );
  if (keyinfolen < 28)
    return 0; /* invalid blob */
  pos = 20;
  if (pos + keyinfolen*nkeys > length)
    return 0; /* out of bounds */

  for (idx=0; idx < nkeys; idx++)
    {
      off = pos + idx*keyinfolen;
      if (!memcmp (buffer + off + fproff, fpr, fprlen))
        return 1; /* found */
    }
  return 0; /* not found */
}
static int
blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
{
  const unsigned char *buffer;
  size_t length;
  size_t pos, off;
  size_t nkeys, keyinfolen;
  size_t nserial;

  buffer = _keybox_get_blob_image (blob, &length);
  if (length < 40)
    return 0; /* blob too short */

  /*keys*/
  nkeys = get16 (buffer + 16);
  keyinfolen = get16 (buffer + 18 );
  if (keyinfolen < 28)
    return 0; /* invalid blob */
  pos = 20 + keyinfolen*nkeys;
  if (pos+2 > length)
    return 0; /* out of bounds */

  /*serial*/
  nserial = get16 (buffer+pos);
  off = pos + 2;
  if (off+nserial > length)
    return 0; /* out of bounds */

  return nserial == snlen && !memcmp (buffer+off, sn, snlen);
}
/*
  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;
}
static inline unsigned int
blob_get_blob_flags (KEYBOXBLOB blob)
{
  const unsigned char *buffer;
  size_t length;

  buffer = _keybox_get_blob_image (blob, &length);
  if (length < 8)
    return 0; /* oops */

  return get16 (buffer + 6);
}
static inline int
blob_get_type (KEYBOXBLOB blob)
{
  const unsigned char *buffer;
  size_t length;

  buffer = _keybox_get_blob_image (blob, &length);
  if (length < 32)
    return -1; /* blob too short */

  return buffer[4];
}
/* Return the flags named WHAT at the address of VALUE. IDX is used
   only for certain flags and should be 0 if not required. */
int
keybox_get_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int *value)
{
  const unsigned char *buffer;
  size_t length;
  gpg_err_code_t ec;

  (void)idx; /* Not yet used.  */

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

  buffer = _keybox_get_blob_image (hd->found.blob, &length);
  ec = get_flag_from_image (buffer, length, what, value);
  return ec? gpg_error (ec):0;
}
Exemple #7
0
/* Compute the SHA-1 checksum of the rawdata in BLOB and put it into
   DIGEST. */
static int
hash_blob_rawdata (KEYBOXBLOB blob, unsigned char *digest)
{
  const unsigned char *buffer;
  size_t n, length;
  int type;
  ulong rawdata_off, rawdata_len;

  buffer = _keybox_get_blob_image (blob, &length);

  if (length < 32)
    return -1;
  n = get32 (buffer);
  if (n < length)
    length = n;  /* Blob larger than length in header - ignore the rest. */

  type = buffer[4];
  switch (type)
    {
    case KEYBOX_BLOBTYPE_PGP:
    case KEYBOX_BLOBTYPE_X509:
      break;

    case KEYBOX_BLOBTYPE_EMPTY:
    case KEYBOX_BLOBTYPE_HEADER:
    default:
      memset (digest, 0, 20);
      return 0;
    }

  if (length < 40)
    return -1;

  rawdata_off = get32 (buffer + 8);
  rawdata_len = get32 (buffer + 12);

  if (rawdata_off > length || rawdata_len > length
      || rawdata_off+rawdata_off > length)
    return -1; /* Out of bounds.  */

  gcry_md_hash_buffer (GCRY_MD_SHA1, digest, buffer+rawdata_off, rawdata_len);
  return 0;
}
Exemple #8
0
static int
update_stats (KEYBOXBLOB blob, struct file_stats_s *s)
{
  const unsigned char *buffer;
  size_t length;
  int type;
  unsigned long n;

  buffer = _keybox_get_blob_image (blob, &length);
  if (length < 32)
    {
      s->too_short_blobs++;
      return -1;
    }

  n = get32( buffer );
  if (n > length)
    s->too_large_blobs++;
  else
    length = n;  /* ignore the rest */

  s->total_blob_count++;
  type = buffer[4];
  switch (type)
    {
    case KEYBOX_BLOBTYPE_EMPTY:
      s->empty_blob_count++;
      return 0;
    case KEYBOX_BLOBTYPE_HEADER:
      s->header_blob_count++;
      return 0;
    case KEYBOX_BLOBTYPE_PGP:
      s->pgp_blob_count++;
      break;
    case KEYBOX_BLOBTYPE_X509:
      s->x509_blob_count++;
      break;
    default:
      s->unknown_blob_count++;
      return 0;
    }

  if (length < 40)
    {
      s->too_short_blobs++;
      return -1;
    }

  n = get16 (buffer + 6);
  if (n)
    {
      if ((n & 1))
        s->secret_flagged++;
      if ((n & 2))
        s->ephemeral_flagged++;
    }
  else
    s->non_flagged++;

  return 0;
}
Exemple #9
0
/* Dump one block to FP */
int
_keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
{
  const byte *buffer;
  size_t length;
  int type, i;
  ulong n, nkeys, keyinfolen;
  ulong nuids, uidinfolen;
  ulong nsigs, siginfolen;
  ulong rawdata_off, rawdata_len;
  ulong nserial;
  ulong unhashed;
  const byte *p;

  buffer = _keybox_get_blob_image (blob, &length);

  if (length < 32)
    {
      fprintf (fp, "[blob too short]\n");
      return -1;
    }

  n = get32( buffer );
  if (n > length)
    fprintf (fp, "[blob larger than length - output truncated]\n");
  else
    length = n;  /* ignore the rest */

  fprintf (fp, "Length: %lu\n", n );
  type = buffer[4];
  switch (type)
    {
    case KEYBOX_BLOBTYPE_EMPTY:
      fprintf (fp, "Type:   Empty\n");
      return 0;

    case KEYBOX_BLOBTYPE_HEADER:
      fprintf (fp, "Type:   Header\n");
      return dump_header_blob (buffer, length, fp);
    case KEYBOX_BLOBTYPE_PGP:
      fprintf (fp, "Type:   OpenPGP\n");
      break;
    case KEYBOX_BLOBTYPE_X509:
      fprintf (fp, "Type:   X.509\n");
      break;
    default:
      fprintf (fp, "Type:   %d\n", type);
      fprintf (fp, "[can't dump this blob type]\n");
      return 0;
    }
  fprintf (fp, "Version: %d\n", buffer[5]);

  if (length < 40)
    {
      fprintf (fp, "[blob too short]\n");
      return -1;
    }

  n = get16 (buffer + 6);
  fprintf( fp, "Blob-Flags: %04lX", n);
  if (n)
    {
      int any = 0;

      fputs (" (", fp);
      if ((n & 1))
        {
          fputs ("secret", fp);
          any++;
        }
      if ((n & 2))
        {
          if (any)
            putc (',', fp);
          fputs ("ephemeral", fp);
          any++;
        }
      putc (')', fp);
    }
  putc ('\n', fp);

  rawdata_off = get32 (buffer + 8);
  rawdata_len = get32 (buffer + 12);

  fprintf( fp, "Data-Offset: %lu\n", rawdata_off );
  fprintf( fp, "Data-Length: %lu\n", rawdata_len );
  if (rawdata_off > length || rawdata_len > length
      || rawdata_off+rawdata_len > length
      || rawdata_len + 4 > length
      || rawdata_off+rawdata_len + 4 > length)
    fprintf (fp, "[Error: raw data larger than blob]\n");
  unhashed = length - rawdata_off - rawdata_len;
  fprintf (fp, "Unhashed: %lu\n", unhashed);

  nkeys = get16 (buffer + 16);
  fprintf (fp, "Key-Count: %lu\n", nkeys );
  if (!nkeys)
    fprintf (fp, "[Error: no keys]\n");
  if (nkeys > 1 && type == KEYBOX_BLOBTYPE_X509)
    fprintf (fp, "[Error: only one key allowed for X509]\n");

  keyinfolen = get16 (buffer + 18 );
  fprintf (fp, "Key-Info-Length: %lu\n", keyinfolen);
  /* fixme: check bounds */
  p = buffer + 20;
  for (n=0; n < nkeys; n++, p += keyinfolen)
    {
      ulong kidoff, kflags;

      fprintf (fp, "Key-Fpr[%lu]: ", n );
      for (i=0; i < 20; i++ )
        fprintf (fp, "%02X", p[i]);
      kidoff = get32 (p + 20);
      fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff );
      fprintf (fp, "Key-Kid[%lu]: ", n );
      /* fixme: check bounds */
      for (i=0; i < 8; i++ )
        fprintf (fp, "%02X", buffer[kidoff+i] );
      kflags = get16 (p + 24 );
      fprintf( fp, "\nKey-Flags[%lu]: %04lX\n", n, kflags);
    }

  /* serial number */
  fputs ("Serial-No: ", fp);
  nserial = get16 (p);
  p += 2;
  if (!nserial)
    fputs ("none", fp);
  else
    {
      for (; nserial; nserial--, p++)
        fprintf (fp, "%02X", *p);
    }
  putc ('\n', fp);

  /* user IDs */
  nuids = get16 (p);
  fprintf (fp, "Uid-Count: %lu\n", nuids );
  uidinfolen = get16  (p + 2);
  fprintf (fp, "Uid-Info-Length: %lu\n", uidinfolen);
  /* fixme: check bounds */
  p += 4;
  for (n=0; n < nuids; n++, p += uidinfolen)
    {
      ulong uidoff, uidlen, uflags;

      uidoff = get32( p );
      uidlen = get32( p+4 );
      if (type == KEYBOX_BLOBTYPE_X509 && !n)
        {
          fprintf (fp, "Issuer-Off: %lu\n", uidoff );
          fprintf (fp, "Issuer-Len: %lu\n", uidlen );
          fprintf (fp, "Issuer: \"");
        }
      else if (type == KEYBOX_BLOBTYPE_X509 && n == 1)
        {
          fprintf (fp, "Subject-Off: %lu\n", uidoff );
          fprintf (fp, "Subject-Len: %lu\n", uidlen );
          fprintf (fp, "Subject: \"");
        }
      else
        {
          fprintf (fp, "Uid-Off[%lu]: %lu\n", n, uidoff );
          fprintf (fp, "Uid-Len[%lu]: %lu\n", n, uidlen );
          fprintf (fp, "Uid[%lu]: \"", n );
        }
      print_string (fp, buffer+uidoff, uidlen, '\"');
      fputs ("\"\n", fp);
      uflags = get16 (p + 8);
      if (type == KEYBOX_BLOBTYPE_X509 && !n)
        {
          fprintf (fp, "Issuer-Flags: %04lX\n", uflags );
          fprintf (fp, "Issuer-Validity: %d\n", p[10] );
        }
      else if (type == KEYBOX_BLOBTYPE_X509 && n == 1)
        {
          fprintf (fp, "Subject-Flags: %04lX\n", uflags );
          fprintf (fp, "Subject-Validity: %d\n", p[10] );
        }
      else
        {
          fprintf (fp, "Uid-Flags[%lu]: %04lX\n", n, uflags );
          fprintf (fp, "Uid-Validity[%lu]: %d\n", n, p[10] );
        }
    }

  nsigs = get16 (p);
  fprintf (fp, "Sig-Count: %lu\n", nsigs );
  siginfolen = get16 (p + 2);
  fprintf (fp, "Sig-Info-Length: %lu\n", siginfolen );
  /* fixme: check bounds  */
  p += 4;
  {
    int in_range = 0;
    ulong first = 0;

    for (n=0; n < nsigs; n++, p += siginfolen)
      {
        ulong sflags;

        sflags = get32 (p);
        if (!in_range && !sflags)
          {
            in_range = 1;
            first = n;
            continue;
          }
        if (in_range && !sflags)
          continue;
        if (in_range)
          {
            fprintf (fp, "Sig-Expire[%lu-%lu]: [not checked]\n", first, n-1);
            in_range = 0;
          }

        fprintf (fp, "Sig-Expire[%lu]: ", n );
        if (!sflags)
          fputs ("[not checked]", fp);
        else if (sflags == 1 )
          fputs ("[missing key]", fp);
        else if (sflags == 2 )
          fputs ("[bad signature]", fp);
        else if (sflags < 0x10000000)
          fprintf (fp, "[bad flag %0lx]", sflags);
        else if (sflags == (ulong)(-1))
          fputs ("[good - does not expire]", fp );
        else
          fprintf (fp, "[good - expires at %lu]", sflags);
        putc ('\n', fp );
      }
    if (in_range)
      {
        fprintf (fp, "Sig-Expire[%lu-%lu]: [not checked]\n", first, n-1);
        in_range = 0;
      }
  }
  fprintf (fp, "Ownertrust: %d\n", p[0] );
  fprintf (fp, "All-Validity: %d\n", p[1] );
  p += 4;
  n = get32 (p); p += 4;
  fprintf (fp, "Recheck-After: %lu\n", n );
  n = get32 (p ); p += 4;
  fprintf( fp, "Latest-Timestamp: %lu\n", n );
  n = get32 (p ); p += 4;
  fprintf (fp, "Created-At: %lu\n", n );
  n = get32 (p ); p += 4;
  fprintf (fp, "Reserved-Space: %lu\n", n );

  if (n >= 4 && unhashed >= 24)
    {
      n = get32 ( buffer + length - unhashed);
      fprintf (fp, "Storage-Flags: %08lx\n", n );
    }
  print_checksum (buffer, length, unhashed, fp);
  return 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;
}
/* compare all email addresses of the subject.  With SUBSTR given as
   True a substring search is done in the mail address */
static int
blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
{
  const unsigned char *buffer;
  size_t length;
  size_t pos, off, len;
  size_t nkeys, keyinfolen;
  size_t nuids, uidinfolen;
  size_t nserial;
  int idx;

  /* fixme: this code is common to blob_cmp_mail */
  buffer = _keybox_get_blob_image (blob, &length);
  if (length < 40)
    return 0; /* blob too short */

  /*keys*/
  nkeys = get16 (buffer + 16);
  keyinfolen = get16 (buffer + 18 );
  if (keyinfolen < 28)
    return 0; /* invalid blob */
  pos = 20 + keyinfolen*nkeys;
  if (pos+2 > length)
    return 0; /* out of bounds */

  /*serial*/
  nserial = get16 (buffer+pos);
  pos += 2 + nserial;
  if (pos+4 > length)
    return 0; /* out of bounds */

  /* user ids*/
  nuids = get16 (buffer + pos);  pos += 2;
  uidinfolen = get16 (buffer + pos);  pos += 2;
  if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
    return 0; /* invalid blob */
  if (pos + uidinfolen*nuids > length)
    return 0; /* out of bounds */

  if (namelen < 1)
    return 0;

  for (idx=1 ;idx < nuids; idx++)
    {
      size_t mypos = pos;

      mypos += idx*uidinfolen;
      off = get32 (buffer+mypos);
      len = get32 (buffer+mypos+4);
      if (off+len > length)
        return 0; /* error: better stop here out of bounds */
      if (len < 2 || buffer[off] != '<')
        continue; /* empty name or trailing 0 not stored */
      len--; /* one back */
      if ( len < 3 || buffer[off+len] != '>')
        continue; /* not a proper email address */
      len--;
      if (substr)
        {
          if (ascii_memcasemem (buffer+off+1, len, name, namelen))
            return 1; /* found */
        }
      else
        {
          if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len))
            return 1; /* found */
        }
    }
  return 0; /* not found */
}
static int
blob_cmp_name (KEYBOXBLOB blob, int idx,
               const char *name, size_t namelen, int substr)
{
  const unsigned char *buffer;
  size_t length;
  size_t pos, off, len;
  size_t nkeys, keyinfolen;
  size_t nuids, uidinfolen;
  size_t nserial;

  buffer = _keybox_get_blob_image (blob, &length);
  if (length < 40)
    return 0; /* blob too short */

  /*keys*/
  nkeys = get16 (buffer + 16);
  keyinfolen = get16 (buffer + 18 );
  if (keyinfolen < 28)
    return 0; /* invalid blob */
  pos = 20 + keyinfolen*nkeys;
  if (pos+2 > length)
    return 0; /* out of bounds */

  /*serial*/
  nserial = get16 (buffer+pos);
  pos += 2 + nserial;
  if (pos+4 > length)
    return 0; /* out of bounds */

  /* user ids*/
  nuids = get16 (buffer + pos);  pos += 2;
  uidinfolen = get16 (buffer + pos);  pos += 2;
  if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
    return 0; /* invalid blob */
  if (pos + uidinfolen*nuids > length)
    return 0; /* out of bounds */

  if (idx < 0)
    { /* compare all names starting with that (negated) index */
      idx = -idx;

      for ( ;idx < nuids; idx++)
        {
          size_t mypos = pos;

          mypos += idx*uidinfolen;
          off = get32 (buffer+mypos);
          len = get32 (buffer+mypos+4);
          if (off+len > length)
            return 0; /* error: better stop here out of bounds */
          if (len < 1)
            continue; /* empty name */
          if (substr)
            {
              if (ascii_memcasemem (buffer+off, len, name, namelen))
                return 1; /* found */
            }
          else
            {
              if (len == namelen && !memcmp (buffer+off, name, len))
                return 1; /* found */
            }
        }
      return 0; /* not found */
    }
  else
    {
      if (idx > nuids)
        return 0; /* no user ID with that idx */
      pos += idx*uidinfolen;
      off = get32 (buffer+pos);
      len = get32 (buffer+pos+4);
      if (off+len > length)
        return 0; /* out of bounds */
      if (len < 1)
        return 0; /* empty name */

      if (substr)
        {
          return !!ascii_memcasemem (buffer+off, len, name, namelen);
        }
      else
        {
          return len == namelen && !memcmp (buffer+off, name, len);
        }
    }
}