Beispiel #1
0
/* Read the prefix of the keyblob and do some basic parsing.  On
   success returns an open estream file at R_FP and the length of the
   header at R_HEADERLEN.  */
static gpg_error_t
read_keyblob_prefix (const char *filename, estream_t *r_fp, size_t *r_headerlen)
{
  gpg_error_t err;
  estream_t fp;
  unsigned char packet[32];

  *r_fp = NULL;

  fp = es_fopen (filename, "rb");
  if (!fp)
    {
      err = gpg_error_from_syserror ();
      log_error ("error reading '%s': %s\n", filename, gpg_strerror (err));
      return err;
    }

  /* Read the header.  It is defined as 32 bytes thus we read it in one go.  */
  if (es_fread (packet, 32, 1, fp) != 1)
    {
      err = gpg_error_from_syserror ();
      log_error ("error reading the header of '%s': %s\n",
                 filename, gpg_strerror (err));
      es_fclose (fp);
      return err;
    }

  err = parse_header (filename, packet, 32, r_headerlen);
  if (err)
    es_fclose (fp);
  else
    *r_fp = fp;

  return err;
}
Beispiel #2
0
/* Read the keyblob at FILENAME.  The caller should have acquired a
   lockfile and checked that the file exists.  */
static gpg_error_t
read_keyblob (const char *filename,
              void **r_enckeyblob, size_t *r_enckeybloblen)
{
  gpg_error_t err;
  estream_t fp = NULL;
  size_t headerlen = 0;
  size_t msglen;
  void *msg = NULL;

  *r_enckeyblob = NULL;
  *r_enckeybloblen = 0;

  err = read_keyblob_prefix (filename, &fp, &headerlen);
  if (err)
    goto leave;

  if (opt.verbose)
    log_info ("header length of '%s' is %zu\n", filename, headerlen);

  /* Read everything including the padding.  We should eventually do a
     regular OpenPGP parsing to detect the padding packet and pass
     only the actual used OpenPGP data to the engine.  This is in
     particular required when supporting CMS which will be
     encapsulated in an OpenPGP packet.  */
  assert (headerlen >= 32);
  msglen = headerlen - 32;
  if (!msglen)
    {
      err = gpg_error (GPG_ERR_NO_DATA);
      goto leave;
    }
  msg = xtrymalloc (msglen);
  if (!msglen)
    {
      err = gpg_error_from_syserror ();
      goto leave;
    }
  if (es_fread (msg, msglen, 1, fp) != 1)
    {
      err = gpg_error_from_syserror ();
      log_error ("error reading keyblob of '%s': %s\n",
                 filename, gpg_strerror (err));
      goto leave;
    }

  *r_enckeyblob = msg;
  msg = NULL;
  *r_enckeybloblen = msglen;

 leave:
  xfree (msg);
  es_fclose (fp);

  return err;
}
Beispiel #3
0
/* A KSBA reader callback to read from an estream.  */
static int
my_estream_ksba_reader_cb (void *cb_value, char *buffer, size_t count,
                           size_t *r_nread)
{
  estream_t fp = cb_value;

  if (!fp)
    return gpg_error (GPG_ERR_INV_VALUE);

  if (!buffer && !count && !r_nread)
    {
      es_rewind (fp);
      return 0;
    }

  *r_nread = es_fread (buffer, 1, count, fp);
  if (!*r_nread)
    return -1; /* EOF or error.  */
  return 0; /* Success.  */
}
Beispiel #4
0
/* Read the next record from STREAM.  RECORD is a buffer provided by
   the caller and must be at leadt of size RECORDSIZE.  The function
   return 0 on success and and error code on failure; a diagnostic
   printed as well.  Note that there is no need for an EOF indicator
   because a tarball has an explicit EOF record. */
gpg_error_t
read_record (estream_t stream, void *record)
{
    gpg_error_t err;
    size_t nread;

    nread = es_fread (record, 1, RECORDSIZE, stream);
    if (nread != RECORDSIZE)
    {
        err = gpg_error_from_syserror ();
        if (es_ferror (stream))
            log_error ("error reading '%s': %s\n",
                       es_fname_get (stream), gpg_strerror (err));
        else
            log_error ("error reading '%s': premature EOF "
                       "(size of last record: %zu)\n",
                       es_fname_get (stream), nread);
    }
    else
        err = 0;

    return err;
}
Beispiel #5
0
/* Read the key identified by GRIP from the private key directory and
   return it as an gcrypt S-expression object in RESULT.  On failure
   returns an error code and stores NULL at RESULT. */
static gpg_error_t
read_key_file (const unsigned char *grip, gcry_sexp_t *result)
{
  int rc;
  char *fname;
  estream_t fp;
  struct stat st;
  unsigned char *buf;
  size_t buflen, erroff;
  gcry_sexp_t s_skey;
  char hexgrip[40+4+1];

  *result = NULL;

  bin2hex (grip, 20, hexgrip);
  strcpy (hexgrip+40, ".key");

  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
  fp = es_fopen (fname, "rb");
  if (!fp)
    {
      rc = gpg_error_from_syserror ();
      if (gpg_err_code (rc) != GPG_ERR_ENOENT)
        log_error ("can't open '%s': %s\n", fname, strerror (errno));
      xfree (fname);
      return rc;
    }

  if (fstat (es_fileno (fp), &st))
    {
      rc = gpg_error_from_syserror ();
      log_error ("can't stat '%s': %s\n", fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      return rc;
    }

  buflen = st.st_size;
  buf = xtrymalloc (buflen+1);
  if (!buf)
    {
      rc = gpg_error_from_syserror ();
      log_error ("error allocating %zu bytes for '%s': %s\n",
                 buflen, fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      xfree (buf);
      return rc;

    }

  if (es_fread (buf, buflen, 1, fp) != 1)
    {
      rc = gpg_error_from_syserror ();
      log_error ("error reading %zu bytes from '%s': %s\n",
                 buflen, fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      xfree (buf);
      return rc;
    }

  /* Convert the file into a gcrypt S-expression object.  */
  rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
  xfree (fname);
  es_fclose (fp);
  xfree (buf);
  if (rc)
    {
      log_error ("failed to build S-Exp (off=%u): %s\n",
                 (unsigned int)erroff, gpg_strerror (rc));
      return rc;
    }
  *result = s_skey;
  return 0;
}
Beispiel #6
0
/* Read from FP and return a newly allocated buffer in R_BUFFER with the
   entire data read from FP. */
static gpg_error_t
read_response (estream_t fp, unsigned char **r_buffer, size_t *r_buflen)
{
  gpg_error_t err;
  unsigned char *buffer;
  size_t bufsize, nbytes;

  *r_buffer = NULL;
  *r_buflen = 0;

  bufsize = 4096;
  buffer = xtrymalloc (bufsize);
  if (!buffer)
    return gpg_error_from_errno (errno);

  nbytes = 0;
  for (;;)
    {
      unsigned char *tmp;
      size_t nread = 0;

      assert (nbytes < bufsize);
      nread = es_fread (buffer+nbytes, 1, bufsize-nbytes, fp);
      if (nread < bufsize-nbytes && es_ferror (fp))
        {
          err = gpg_error_from_errno (errno);
          log_error (_("error reading from responder: %s\n"),
                     strerror (errno));
          xfree (buffer);
          return err;
        }
      if ( !(nread == bufsize-nbytes && !es_feof (fp)))
        { /* Response succesfully received. */
          nbytes += nread;
          *r_buffer = buffer;
          *r_buflen = nbytes;
          return 0;
        }

      nbytes += nread;

      /* Need to enlarge the buffer. */
      if (bufsize >= MAX_RESPONSE_SIZE)
        {
          log_error (_("response from server too large; limit is %d bytes\n"),
                     MAX_RESPONSE_SIZE);
          xfree (buffer);
          return gpg_error (GPG_ERR_TOO_LARGE);
        }

      bufsize += 4096;
      tmp = xtryrealloc (buffer, bufsize);
      if (!tmp)
        {
          err = gpg_error_from_errno (errno);
          xfree (buffer);
          return err;
        }
      buffer = tmp;
    }
}
Beispiel #7
0
/* Read the key identified by GRIP from the private key directory and
   return it as an gcrypt S-expression object in RESULT.  On failure
   returns an error code and stores NULL at RESULT. */
static gpg_error_t
read_key_file (const unsigned char *grip, gcry_sexp_t *result)
{
  int rc;
  char *fname;
  estream_t fp;
  struct stat st;
  unsigned char *buf;
  size_t buflen, erroff;
  gcry_sexp_t s_skey;
  char hexgrip[40+4+1];
  char first;

  *result = NULL;

  bin2hex (grip, 20, hexgrip);
  strcpy (hexgrip+40, ".key");

  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
  fp = es_fopen (fname, "rb");
  if (!fp)
    {
      rc = gpg_error_from_syserror ();
      if (gpg_err_code (rc) != GPG_ERR_ENOENT)
        log_error ("can't open '%s': %s\n", fname, strerror (errno));
      xfree (fname);
      return rc;
    }

  if (es_fread (&first, 1, 1, fp) != 1)
    {
      rc = gpg_error_from_syserror ();
      log_error ("error reading first byte from '%s': %s\n",
                 fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      return rc;
    }

  rc = es_fseek (fp, 0, SEEK_SET);
  if (rc)
    {
      log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      return rc;
    }

  if (first != '(')
    {
      /* Key is in extended format.  */
      pkc_t pk;
      int line;

      rc = pkc_parse (&pk, &line, fp);
      es_fclose (fp);

      if (rc)
        log_error ("error parsing '%s' line %d: %s\n",
                   fname, line, gpg_strerror (rc));
      else
        {
          rc = pkc_get_private_key (pk, result);
          pkc_release (pk);
          if (rc)
            log_error ("error getting private key from '%s': %s\n",
                       fname, gpg_strerror (rc));
        }

      xfree (fname);
      return rc;
    }

  if (fstat (es_fileno (fp), &st))
    {
      rc = gpg_error_from_syserror ();
      log_error ("can't stat '%s': %s\n", fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      return rc;
    }

  buflen = st.st_size;
  buf = xtrymalloc (buflen+1);
  if (!buf)
    {
      rc = gpg_error_from_syserror ();
      log_error ("error allocating %zu bytes for '%s': %s\n",
                 buflen, fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      xfree (buf);
      return rc;

    }

  if (es_fread (buf, buflen, 1, fp) != 1)
    {
      rc = gpg_error_from_syserror ();
      log_error ("error reading %zu bytes from '%s': %s\n",
                 buflen, fname, strerror (errno));
      xfree (fname);
      es_fclose (fp);
      xfree (buf);
      return rc;
    }

  /* Convert the file into a gcrypt S-expression object.  */
  rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
  xfree (fname);
  es_fclose (fp);
  xfree (buf);
  if (rc)
    {
      log_error ("failed to build S-Exp (off=%u): %s\n",
                 (unsigned int)erroff, gpg_strerror (rc));
      return rc;
    }
  *result = s_skey;
  return 0;
}
Beispiel #8
0
/* Write an S-expression formatted key to our key storage.  With FORCE
   passed as true an existing key with the given GRIP will get
   overwritten.  */
int
agent_write_private_key (const unsigned char *grip,
                         const void *buffer, size_t length, int force)
{
  char *fname;
  estream_t fp;
  char hexgrip[40+4+1];

  bin2hex (grip, 20, hexgrip);
  strcpy (hexgrip+40, ".key");

  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);

  /* FIXME: Write to a temp file first so that write failures during
     key updates won't lead to a key loss.  */

  if (!force && !access (fname, F_OK))
    {
      log_error ("secret key file '%s' already exists\n", fname);
      xfree (fname);
      return gpg_error (GPG_ERR_EEXIST);
    }

  fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
  if (!fp)
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
      xfree (fname);
      return tmperr;
    }

  /* See if an existing key is in extended format.  */
  if (force)
    {
      gpg_error_t rc;
      char first;

      if (es_fread (&first, 1, 1, fp) != 1)
        {
          rc = gpg_error_from_syserror ();
          log_error ("error reading first byte from '%s': %s\n",
                     fname, strerror (errno));
          xfree (fname);
          es_fclose (fp);
          return rc;
        }

      rc = es_fseek (fp, 0, SEEK_SET);
      if (rc)
        {
          log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
          xfree (fname);
          es_fclose (fp);
          return rc;
        }

      if (first != '(')
        {
          /* Key is in extended format.  */
          return write_extended_private_key (fname, fp, buffer, length);
        }
    }

  if (es_fwrite (buffer, length, 1, fp) != 1)
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error writing '%s': %s\n", fname, gpg_strerror (tmperr));
      es_fclose (fp);
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }

  /* When force is given, the file might have to be truncated.  */
  if (force && ftruncate (es_fileno (fp), es_ftello (fp)))
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error truncating '%s': %s\n", fname, gpg_strerror (tmperr));
      es_fclose (fp);
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }

  if (es_fclose (fp))
    {
      gpg_error_t tmperr = gpg_error_from_syserror ();
      log_error ("error closing '%s': %s\n", fname, gpg_strerror (tmperr));
      gnupg_remove (fname);
      xfree (fname);
      return tmperr;
    }
  bump_key_eventcounter ();
  xfree (fname);
  return 0;
}