Example #1
0
int
main (int argc, char *argv[])
{
  FILE *fp;
  int save_errno;
  gpg_err_code_t ec;

  fp = fopen ("/does-not-exist/110761/nowhere.foo", "r");
  if (fp)
    {
      fclose (fp);
      fp = fopen ("  no this file does not exists foo 4711", "r");
    }
  if (fp)
    {
      fprintf (stderr, "unable to run test\n");
      return 1;
    }
  save_errno = errno;

  ec = gpg_err_code_from_syserror ();
  if (ec != GPG_ERR_ENOENT)
    {
      fprintf (stderr, "fopen failed with bad code: %d\n", save_errno);
      return 1;
    }

  if (ec != gpg_err_code_from_errno (save_errno))
    {
      fprintf (stderr, "oops at %d\n",__LINE__);
      return 1;
    }

  gpg_err_set_errno (0);

  ec = gpg_err_code_from_syserror ();
  if (ec != GPG_ERR_MISSING_ERRNO)
    {
      fprintf (stderr, "oops at %d\n",__LINE__);
      return 1;
    }

  if ( gpg_err_code_from_errno (0) )
    {
      fprintf (stderr, "oops at %d\n",__LINE__);
      return 1;
    }


  return 0;
}
Example #2
0
gcry_err_code_t
_gcry_malloc (size_t n, unsigned int flags, void **mem)
{
  gcry_err_code_t err = 0;
  void *m;

  if ((flags & GCRY_ALLOC_FLAG_SECURE) && !no_secure_memory)
    {
      if (alloc_secure_func)
	m = (*alloc_secure_func) (n);
      else
	m = _gcry_private_malloc_secure (n);
    }
  else
    {
      if (alloc_func)
	m = (*alloc_func) (n);
      else
	m = _gcry_private_malloc (n);
    }

  if (!m)
    {
      if (!errno)
        errno = ENOMEM;
      err = gpg_err_code_from_errno (errno);
    }
  else
    *mem = m;

  return err;
}
Example #3
0
/* Note: Use this function only if no other thread holds or waits for
   this lock.  */
gpg_err_code_t
gpgrt_lock_destroy (gpgrt_lock_t *lockhd)
{
  _gpgrt_lock_t *lock = get_lock_object (lockhd);
  int rc;

#if USE_POSIX_THREADS
  if (use_pthread_p())
    {
      rc = pthread_mutex_destroy (&lock->u.mtx);
      if (rc)
        rc = gpg_err_code_from_errno (rc);
      else
        {
          /* Re-init the mutex so that it can be re-used.  */
          gpgrt_lock_t tmp = GPGRT_LOCK_INITIALIZER;
          memcpy (lockhd, &tmp, sizeof tmp);
        }
    }
  else
    rc = 0; /* Threads are not used.  */
#else /* Unknown thread system.  */
  rc = GPG_ERR_NOT_IMPLEMENTED;
#endif /* Unknown thread system.  */

  return rc;
}
Example #4
0
gpg_err_code_t
gpgrt_lock_init (gpgrt_lock_t *lockhd)
{
  _gpgrt_lock_t *lock = (_gpgrt_lock_t*)lockhd;
  int rc;

  /* If VERS is zero we assume that no static initialization has been
     done, so we setup our ABI version right here.  The caller might
     have called us to test whether lock support is at all available. */
  if (!lock->vers)
    {
      if (sizeof (gpgrt_lock_t) < sizeof (_gpgrt_lock_t))
        abort ();
      lock->vers = LOCK_ABI_VERSION;
    }
  else /* Run the usual check.  */
    lock = get_lock_object (lockhd);

#if USE_POSIX_THREADS
  if (use_pthread_p())
    {
      rc = pthread_mutex_init (&lock->u.mtx, NULL);
      if (rc)
        rc = gpg_err_code_from_errno (rc);
    }
  else
    rc = 0; /* Threads are not used.  */
#else /* Unknown thread system.  */
  rc = GPG_ERR_NOT_IMPLEMENTED;
#endif /* Unknown thread system.  */

  return rc;
}
Example #5
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;
}
/* See exechelp.h for the description.  */
gpg_error_t
gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
{
    gpg_err_code_t ec;
    int i, status;

    if (r_exitcode)
        *r_exitcode = -1;

    if (pid == (pid_t)(-1))
        return gpg_error (GPG_ERR_INV_VALUE);

#ifdef USE_NPTH
    i = npth_waitpid (pid, &status, hang? 0:WNOHANG);
#else
    while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1)
            && errno == EINTR);
#endif

    if (i == (pid_t)(-1))
    {
        ec = gpg_err_code_from_errno (errno);
        log_error (_("waiting for process %d to terminate failed: %s\n"),
                   (int)pid, strerror (errno));
    }
    else if (!i)
    {
        ec = GPG_ERR_TIMEOUT; /* Still running.  */
    }
    else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
    {
        log_error (_("error running '%s': probably not installed\n"), pgmname);
        ec = GPG_ERR_CONFIGURATION;
    }
    else if (WIFEXITED (status) && WEXITSTATUS (status))
    {
        if (!r_exitcode)
            log_error (_("error running '%s': exit status %d\n"), pgmname,
                       WEXITSTATUS (status));
        else
            *r_exitcode = WEXITSTATUS (status);
        ec = GPG_ERR_GENERAL;
    }
    else if (!WIFEXITED (status))
    {
        log_error (_("error running '%s': terminated\n"), pgmname);
        ec = GPG_ERR_GENERAL;
    }
    else
    {
        if (r_exitcode)
            *r_exitcode = 0;
        ec = 0;
    }

    return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
}
Example #7
0
void *
gcry_xmalloc( size_t n )
{
    void *p;

    while ( !(p = gcry_malloc( n )) ) {
	if( !outofcore_handler
	    || !outofcore_handler( outofcore_handler_value, n, 0 ) ) {
	    _gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
	}
    }
    return p;
}
Example #8
0
/* Explicitly initialize this module.  */
gcry_err_code_t
_gcry_cipher_init (void)
{
  gcry_err_code_t err;

  err = ath_mutex_init (&ciphers_registered_lock);
  if (err)
    return gpg_err_code_from_errno (err);

  REGISTER_DEFAULT_CIPHERS;

  return err;
}
Example #9
0
void *
gcry_xrealloc( void *a, size_t n )
{
    void *p;

    while ( !(p = gcry_realloc( a, n )) ) {
	if( !outofcore_handler
	    || !outofcore_handler( outofcore_handler_value, n, 
                                   gcry_is_secure(a)? 3:2 ) ) {
	    _gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
	}
    }
    return p;
}
Example #10
0
void *
gcry_xmalloc_secure( size_t n )
{
    void *p;

    while ( !(p = gcry_malloc_secure( n )) ) {
	if( !outofcore_handler
	    || !outofcore_handler( outofcore_handler_value, n, 1 ) ) {
	    _gcry_fatal_error(gpg_err_code_from_errno (errno),
			     _("out of core in secure memory"));
	}
    }
    return p;
}
Example #11
0
void *
gcry_xcalloc_secure( size_t n, size_t m )
{
  size_t nbytes;
  void *p;

  nbytes = n * m; 
  if (m && nbytes / m != n) 
    {
      errno = ENOMEM;
      _gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
    }

  p = gcry_xmalloc_secure ( nbytes );
  memset ( p, 0, nbytes );
  return p;
}
Example #12
0
char *
gcry_xstrdup (const char *string)
{
  char *p;

  while ( !(p = gcry_strdup (string)) ) 
    {
      size_t n = strlen (string);
      int is_sec = !!gcry_is_secure (string);

      if (!outofcore_handler
          || !outofcore_handler (outofcore_handler_value, n, is_sec) ) 
        {
          _gcry_fatal_error (gpg_err_code_from_errno (errno),
                             is_sec? _("out of core in secure memory"):NULL);
	}
    }

  return p;
}
Example #13
0
gpg_err_code_t
gpgrt_lock_unlock (gpgrt_lock_t *lockhd)
{
  _gpgrt_lock_t *lock = get_lock_object (lockhd);
  int rc;

#if USE_POSIX_THREADS
  if (use_pthread_p())
    {
      rc = pthread_mutex_unlock (&lock->u.mtx);
      if (rc)
        rc = gpg_err_code_from_errno (rc);
    }
  else
    rc = 0; /* Threads are not used.  */
#else /* Unknown thread system.  */
  rc = GPG_ERR_NOT_IMPLEMENTED;
#endif /* Unknown thread system.  */

  return rc;
}
Example #14
0
/* Add a module specification to the list ENTRIES.  The new module has
   it's use-counter set to one.  */
gcry_err_code_t
_gcry_module_add (gcry_module_t *entries, unsigned int mod_id,
		  void *spec, void *extraspec, gcry_module_t *module)
{
  gcry_err_code_t err = 0;
  gcry_module_t entry;

  if (! mod_id)
    err = _gcry_module_id_new (*entries, &mod_id);

  if (! err)
    {
      entry = gcry_malloc (sizeof (struct gcry_module));
      if (! entry)
	err = gpg_err_code_from_errno (errno);
    }

  if (! err)
    {
      /* Fill new module entry.  */
      entry->flags = 0;
      entry->counter = 1;
      entry->spec = spec;
      entry->extraspec = extraspec;
      entry->mod_id = mod_id;

      /* Link it into the list.  */
      entry->next = *entries;
      entry->prevp = entries;
      if (*entries)
	(*entries)->prevp = &entry->next;
      *entries = entry;

      /* And give it to the caller.  */
      if (module)
	*module = entry;
    }
  return err;
}
Example #15
0
static int
find_iccsn (const unsigned char *buffer, size_t length, char **serial)
{
  size_t n;
  const unsigned char *s;
  char *p;

  s = find_simple_tlv (buffer, length, 0x5A, &n);
  if (!s)
    return gpg_error (GPG_ERR_CARD);
  length -= s - buffer;
  if (n > length)
    {
      /* Oops, it does not fit into the buffer.  This is an invalid
         encoding (or the buffer is too short.  However, I have some
         test cards with such an invalid encoding and therefore I use
         this ugly workaround to return something I can further
         experiment with. */
      if (n == 0x0D && length+1 == n)
        {
          log_debug ("enabling BMI testcard workaround\n");
          n--;
        }
      else
        return gpg_error (GPG_ERR_CARD); /* Bad encoding; does
					    not fit into buffer. */
    }
  if (!n)
    return gpg_error (GPG_ERR_CARD); /* Well, that is too short. */

  *serial = p = xtrymalloc (2*n+1);
  if (!*serial)
    return gpg_error (gpg_err_code_from_errno (errno));
  for (; n; n--, p += 2, s++)
    sprintf (p, "%02X", *s);
  *p = 0;
  return 0;
}
Example #16
0
static gpg_err_code_t
make_space ( struct make_space_ctx *c, size_t n )
{
  size_t used = c->pos - c->sexp->d;

  if ( used + n + sizeof(DATALEN) + 1 >= c->allocated )
    {
      gcry_sexp_t newsexp;
      byte *newhead;
      size_t newsize;

      newsize = c->allocated + 2*(n+sizeof(DATALEN)+1);
      if (newsize <= c->allocated)
        return GPG_ERR_TOO_LARGE;
      newsexp = gcry_realloc ( c->sexp, sizeof *newsexp + newsize - 1);
      if (!newsexp)
        return gpg_err_code_from_errno (errno);
      c->allocated = newsize;
      newhead = newsexp->d;
      c->pos = newhead + used;
      c->sexp = newsexp;
    }
  return 0;
}
Example #17
0
/* Try to connect to the agent via socket or fork it off and work by
   pipes.  Handle the server's initial greeting */
static int
start_dirmngr_ext (ctrl_t ctrl, assuan_context_t *ctx_r)
{
  int rc;
  char *infostr, *p;
  assuan_context_t ctx = NULL;
  int try_default = 0;

  if (opt.disable_dirmngr)
    return gpg_error (GPG_ERR_NO_DIRMNGR);

  if (*ctx_r)
    return 0;

  /* Note: if you change this to multiple connections, you also need
     to take care of the implicit option sending caching. */

#ifdef HAVE_W32_SYSTEM
  infostr = NULL;
  opt.prefer_system_dirmngr = 1;
#else
  infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
#endif /*HAVE_W32_SYSTEM*/
  if (infostr && !*infostr)
    infostr = NULL;
  else if (infostr)
    infostr = xstrdup (infostr);

  if (opt.prefer_system_dirmngr && !force_pipe_server && !infostr)
    {
      infostr = xstrdup (dirmngr_socket_name ());
      try_default = 1;
    }

  rc = assuan_new (&ctx);
  if (rc)
    {
      log_error ("can't allocate assuan context: %s\n", gpg_strerror (rc));
      return rc;
    }

  if (!infostr)
    {
      const char *pgmname;
      const char *argv[3];
      int no_close_list[3];
      int i;

      if (!opt.dirmngr_program || !*opt.dirmngr_program)
        opt.dirmngr_program = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
      if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
        pgmname = opt.dirmngr_program;
      else
        pgmname++;

      if (opt.verbose)
        log_info (_("no running dirmngr - starting `%s'\n"),
                  opt.dirmngr_program);
      
      if (fflush (NULL))
        {
          gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
          log_error ("error flushing pending output: %s\n", strerror (errno));
          return tmperr;
        }

      argv[0] = pgmname;
      argv[1] = "--server";
      argv[2] = NULL;

      i=0;
      if (log_get_fd () != -1)
        no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
      no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
      no_close_list[i] = -1;

      /* connect to the agent and perform initial handshaking */
      rc = assuan_pipe_connect (ctx, opt.dirmngr_program, argv,
                                no_close_list, NULL, NULL, 0);
    }
  else
    {
      int prot;
      int pid;

      if (!try_default)
        {
          if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
            {
              log_error (_("malformed DIRMNGR_INFO environment variable\n"));
              xfree (infostr);
              force_pipe_server = 1;
              return start_dirmngr_ext (ctrl, ctx_r);
            }
          *p++ = 0;
          pid = atoi (p);
          while (*p && *p != PATHSEP_C)
            p++;
          prot = *p? atoi (p+1) : 0;
          if (prot != 1)
            {
              log_error (_("dirmngr protocol version %d is not supported\n"),
                         prot);
              xfree (infostr);
              force_pipe_server = 1;
              return start_dirmngr_ext (ctrl, ctx_r);
            }
        }
      else
        pid = -1;

      rc = assuan_socket_connect (ctx, infostr, pid, 0);
#ifdef HAVE_W32_SYSTEM
      if (rc)
        log_debug ("connecting dirmngr at `%s' failed\n", infostr);
#endif

      xfree (infostr);
#ifndef HAVE_W32_SYSTEM
      if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
        {
          log_info (_("can't connect to the dirmngr - trying fall back\n"));
          force_pipe_server = 1;
          return start_dirmngr_ext (ctrl, ctx_r);
        }
#endif /*!HAVE_W32_SYSTEM*/
    }

  prepare_dirmngr (ctrl, ctx, rc);

  if (rc)
    {
      assuan_release (ctx);
      log_error ("can't connect to the dirmngr: %s\n", gpg_strerror (rc));
      return gpg_error (GPG_ERR_NO_DIRMNGR);
    }
  *ctx_r = ctx;

  if (DBG_ASSUAN)
    log_debug ("connection to dirmngr established\n");
  return 0;
}
Example #18
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;
  FILE *fp;
  char hexgrip[40+4+1];
  int fd;

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

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

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

  /* In FORCE mode we would like to create FNAME but only if it does
     not already exist.  We cannot make this guarantee just using
     POSIX (GNU provides the "x" opentype for fopen, however, this is
     not portable).  Thus, we use the more flexible open function and
     then use fdopen to obtain a stream. */
  fd = open (fname, force? (O_CREAT | O_TRUNC | O_WRONLY | O_BINARY)
                         : (O_CREAT | O_EXCL | O_WRONLY | O_BINARY),
             S_IRUSR | S_IWUSR
#ifndef HAVE_W32_SYSTEM
                 | S_IRGRP
#endif
                 );
  if (fd < 0)
    fp = NULL;
  else
    {
      fp = fdopen (fd, "wb");
      if (!fp)
        {
          int save_e = errno;
          close (fd);
          errno = save_e;
        }
    }

  if (!fp)
    {
      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
      log_error ("can't create `%s': %s\n", fname, strerror (errno));
      xfree (fname);
      return tmperr;
    }

  if (fwrite (buffer, length, 1, fp) != 1)
    {
      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
      log_error ("error writing `%s': %s\n", fname, strerror (errno));
      fclose (fp);
      remove (fname);
      xfree (fname);
      return tmperr;
    }
  if ( fclose (fp) )
    {
      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
      log_error ("error closing `%s': %s\n", fname, strerror (errno));
      remove (fname);
      xfree (fname);
      return tmperr;
    }
  bump_key_eventcounter ();
  xfree (fname);
  return 0;
}
Example #19
0
/* See exechelp.h for a description.  */
gpg_error_t
gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
                      int hang, int *r_exitcodes)
{
  gpg_err_code_t ec = 0;
  size_t i, left;

  for (i = 0; i < count; i++)
    {
      if (r_exitcodes)
        r_exitcodes[i] = -1;

      if (pids[i] == (pid_t)(-1))
        return my_error (GPG_ERR_INV_VALUE);
    }

  left = count;
  while (left > 0)
    {
      pid_t pid;
      int status;

#ifdef USE_NPTH
      pid = npth_waitpid (-1, &status, hang ? 0 : WNOHANG);
#else
      while ((pid = waitpid (-1, &status, hang ? 0 : WNOHANG)) == (pid_t)(-1)
             && errno == EINTR);
#endif

      if (pid == (pid_t)(-1))
        {
          ec = gpg_err_code_from_errno (errno);
          log_error (_("waiting for processes to terminate failed: %s\n"),
                     strerror (errno));
          break;
        }
      else if (!pid)
        {
          ec = GPG_ERR_TIMEOUT; /* Still running.  */
          break;
        }
      else
        {
          for (i = 0; i < count; i++)
            if (pid == pids[i])
              break;

          if (i == count)
            /* No match, ignore this pid.  */
            continue;

          /* Process PIDS[i] died.  */
          left -= 1;

          if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
            {
              log_error (_("error running '%s': probably not installed\n"),
                         pgmnames[i]);
              ec = GPG_ERR_CONFIGURATION;
            }
          else if (WIFEXITED (status) && WEXITSTATUS (status))
            {
              if (!r_exitcodes)
                log_error (_("error running '%s': exit status %d\n"),
                           pgmnames[i], WEXITSTATUS (status));
              else
                r_exitcodes[i] = WEXITSTATUS (status);
              ec = GPG_ERR_GENERAL;
            }
          else if (!WIFEXITED (status))
            {
              log_error (_("error running '%s': terminated\n"), pgmnames[i]);
              ec = GPG_ERR_GENERAL;
            }
          else
            {
              if (r_exitcodes)
                r_exitcodes[i] = 0;
            }
        }
    }

  return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
}
Example #20
0
static GPGRT_INLINE gpg_error_t
my_error_from_errno (int e)
{
  return gpg_err_make (default_errsource, gpg_err_code_from_errno (e));
}
Example #21
0
/****************
 * Scan the provided buffer and return the S expression in our internal
 * format.  Returns a newly allocated expression.  If erroff is not NULL and
 * a parsing error has occurred, the offset into buffer will be returned.
 * If ARGFLAG is true, the function supports some printf like
 * expressions.
 *  These are:
 *	%m - MPI
 *	%s - string (no autoswitch to secure allocation)
 *	%d - integer stored as string (no autoswitch to secure allocation)
 *      %b - memory buffer; this takes _two_ arguments: an integer with the
 *           length of the buffer and a pointer to the buffer.
 *      %S - Copy an gcry_sexp_t here.  The S-expression needs to be a
 *           regular one, starting with a parenthesis.
 *           (no autoswitch to secure allocation)
 *  all other format elements are currently not defined and return an error.
 *  this includes the "%%" sequence becauce the percent sign is not an
 *  allowed character.
 * FIXME: We should find a way to store the secure-MPIs not in the string
 * but as reference to somewhere - this can help us to save huge amounts
 * of secure memory.  The problem is, that if only one element is secure, all
 * other elements are automagicaly copied to secure memory too, so the most
 * common operation gcry_sexp_cdr_mpi() will always return a secure MPI
 * regardless whether it is needed or not.
 */
static gcry_error_t
vsexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
	     const char *buffer, size_t length, int argflag,
	     void **arg_list, va_list arg_ptr)
{
  gcry_err_code_t err = 0;
  static const char tokenchars[] =
    "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "0123456789-./_:*+=";
  const char *p;
  size_t n;
  const char *digptr = NULL;
  const char *quoted = NULL;
  const char *tokenp = NULL;
  const char *hexfmt = NULL;
  const char *base64 = NULL;
  const char *disphint = NULL;
  const char *percent = NULL;
  int hexcount = 0;
  int quoted_esc = 0;
  int datalen = 0;
  size_t dummy_erroff;
  struct make_space_ctx c;
  int arg_counter = 0;
  int level = 0;

  if (!erroff)
    erroff = &dummy_erroff;

  /* Depending on whether ARG_LIST is non-zero or not, this macro gives
     us the next argument, either from the variable argument list as
     specified by ARG_PTR or from the argument array ARG_LIST.  */
#define ARG_NEXT(storage, type)                          \
  do                                                     \
    {                                                    \
      if (!arg_list)                                     \
	storage = va_arg (arg_ptr, type);                \
      else                                               \
	storage = *((type *) (arg_list[arg_counter++])); \
    }                                                    \
  while (0)

  /* The MAKE_SPACE macro is used before each store operation to
     ensure that the buffer is large enough.  It requires a global
     context named C and jumps out to the label LEAVE on error! It
     also sets ERROFF using the variables BUFFER and P.  */
#define MAKE_SPACE(n)  do {                                                \
                            gpg_err_code_t _ms_err = make_space (&c, (n)); \
                            if (_ms_err)                                   \
                              {                                            \
                                err = _ms_err;                             \
                                *erroff = p - buffer;                      \
                                goto leave;                                \
                              }                                            \
                       } while (0)

  /* The STORE_LEN macro is used to store the length N at buffer P. */
#define STORE_LEN(p,n) do {						   \
			    DATALEN ashort = (n);			   \
			    memcpy ( (p), &ashort, sizeof(ashort) );	   \
			    (p) += sizeof (ashort);			   \
			} while (0)

  /* We assume that the internal representation takes less memory than
     the provided one.  However, we add space for one extra datalen so
     that the code which does the ST_CLOSE can use MAKE_SPACE */
  c.allocated = length + sizeof(DATALEN);
  if (buffer && length && gcry_is_secure (buffer))
    c.sexp = gcry_malloc_secure (sizeof *c.sexp + c.allocated - 1);
  else
    c.sexp = gcry_malloc (sizeof *c.sexp + c.allocated - 1);
  if (!c.sexp)
    {
      err = gpg_err_code_from_errno (errno);
      *erroff = 0;
      goto leave;
    }
  c.pos = c.sexp->d;

  for (p = buffer, n = length; n; p++, n--)
    {
      if (tokenp && !hexfmt)
	{
	  if (strchr (tokenchars, *p))
	    continue;
	  else
	    {
	      datalen = p - tokenp;
	      MAKE_SPACE (datalen);
	      *c.pos++ = ST_DATA;
	      STORE_LEN (c.pos, datalen);
	      memcpy (c.pos, tokenp, datalen);
	      c.pos += datalen;
	      tokenp = NULL;
	    }
	}

      if (quoted)
	{
	  if (quoted_esc)
	    {
	      switch (*p)
		{
		case 'b': case 't': case 'v': case 'n': case 'f':
		case 'r': case '"': case '\'': case '\\':
		  quoted_esc = 0;
		  break;

		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7':
		  if (!((n > 2)
                        && (p[1] >= '0') && (p[1] <= '7')
                        && (p[2] >= '0') && (p[2] <= '7')))
		    {
		      *erroff = p - buffer;
		      /* Invalid octal value.  */
		      err = GPG_ERR_SEXP_BAD_QUOTATION;
                      goto leave;
		    }
		  p += 2;
		  n -= 2;
		  quoted_esc = 0;
		  break;

		case 'x':
		  if (!((n > 2) && hexdigitp (p+1) && hexdigitp (p+2)))
		    {
		      *erroff = p - buffer;
		      /* Invalid hex value.  */
		      err = GPG_ERR_SEXP_BAD_QUOTATION;
                      goto leave;
		    }
		  p += 2;
		  n -= 2;
		  quoted_esc = 0;
		  break;

		case '\r':
		  /* ignore CR[,LF] */
		  if (n && (p[1] == '\n'))
		    {
		      p++;
		      n--;
		    }
		  quoted_esc = 0;
		  break;

		case '\n':
		  /* ignore LF[,CR] */
		  if (n && (p[1] == '\r'))
		    {
		      p++;
		      n--;
		    }
		  quoted_esc = 0;
		  break;

		default:
		  *erroff = p - buffer;
		  /* Invalid quoted string escape.  */
		  err = GPG_ERR_SEXP_BAD_QUOTATION;
                  goto leave;
		}
	    }
	  else if (*p == '\\')
	    quoted_esc = 1;
	  else if (*p == '\"')
	    {
	      /* Keep it easy - we know that the unquoted string will
		 never be larger. */
	      unsigned char *save;
	      size_t len;

	      quoted++; /* Skip leading quote.  */
	      MAKE_SPACE (p - quoted);
	      *c.pos++ = ST_DATA;
	      save = c.pos;
	      STORE_LEN (c.pos, 0); /* Will be fixed up later.  */
	      len = unquote_string (quoted, p - quoted, c.pos);
	      c.pos += len;
	      STORE_LEN (save, len);
	      quoted = NULL;
	    }
	}
      else if (hexfmt)
	{
	  if (isxdigit (*p))
	    hexcount++;
	  else if (*p == '#')
	    {
	      if ((hexcount & 1))
		{
		  *erroff = p - buffer;
		  err = GPG_ERR_SEXP_ODD_HEX_NUMBERS;
                  goto leave;
		}

	      datalen = hexcount / 2;
	      MAKE_SPACE (datalen);
	      *c.pos++ = ST_DATA;
	      STORE_LEN (c.pos, datalen);
	      for (hexfmt++; hexfmt < p; hexfmt++)
		{
                  int tmpc;

		  if (whitespacep (hexfmt))
		    continue;
		  tmpc = hextonibble (*(const unsigned char*)hexfmt);
                  for (hexfmt++; hexfmt < p && whitespacep (hexfmt); hexfmt++)
		    ;
                  if (hexfmt < p)
                    {
                      tmpc *= 16;
                      tmpc += hextonibble (*(const unsigned char*)hexfmt);
                    }
                  *c.pos++ = tmpc;
		}
	      hexfmt = NULL;
	    }
	  else if (!whitespacep (p))
	    {
	      *erroff = p - buffer;
	      err = GPG_ERR_SEXP_BAD_HEX_CHAR;
              goto leave;
	    }
	}
      else if (base64)
	{
	  if (*p == '|')
	    base64 = NULL;
	}
      else if (digptr)
	{
	  if (digitp (p))
	    ;
	  else if (*p == ':')
	    {
	      datalen = atoi (digptr); /* FIXME: check for overflow.  */
	      digptr = NULL;
	      if (datalen > n - 1)
		{
		  *erroff = p - buffer;
		  /* Buffer too short.  */
		  err = GPG_ERR_SEXP_STRING_TOO_LONG;
                  goto leave;
		}
	      /* Make a new list entry.  */
	      MAKE_SPACE (datalen);
	      *c.pos++ = ST_DATA;
	      STORE_LEN (c.pos, datalen);
	      memcpy (c.pos, p + 1, datalen);
	      c.pos += datalen;
	      n -= datalen;
	      p += datalen;
	    }
	  else if (*p == '\"')
	    {
	      digptr = NULL; /* We ignore the optional length.  */
	      quoted = p;
	      quoted_esc = 0;
	    }
	  else if (*p == '#')
	    {
	      digptr = NULL; /* We ignore the optional length.  */
	      hexfmt = p;
	      hexcount = 0;
	    }
	  else if (*p == '|')
	    {
	      digptr = NULL; /* We ignore the optional length.  */
	      base64 = p;
	    }
	  else
	    {
	      *erroff = p - buffer;
	      err = GPG_ERR_SEXP_INV_LEN_SPEC;
              goto leave;
	    }
	}
      else if (percent)
	{
	  if (*p == 'm' || *p == 'M')
	    {
	      /* Insert an MPI.  */
	      gcry_mpi_t m;
	      size_t nm = 0;
              int mpifmt = *p == 'm'? GCRYMPI_FMT_STD: GCRYMPI_FMT_USG;

	      ARG_NEXT (m, gcry_mpi_t);

              if (gcry_mpi_get_flag (m, GCRYMPI_FLAG_OPAQUE))
                {
                  void *mp;
                  unsigned int nbits;

                  mp = gcry_mpi_get_opaque (m, &nbits);
                  nm = (nbits+7)/8;
                  if (mp && nm)
                    {
                      MAKE_SPACE (nm);
                      if (!gcry_is_secure (c.sexp->d)
                          && gcry_mpi_get_flag (m, GCRYMPI_FLAG_SECURE))
                        {
                          /* We have to switch to secure allocation.  */
                          gcry_sexp_t newsexp;
                          byte *newhead;

                          newsexp = gcry_malloc_secure (sizeof *newsexp
                                                        + c.allocated - 1);
                          if (!newsexp)
                            {
                              err = gpg_err_code_from_errno (errno);
                              goto leave;
                            }
                          newhead = newsexp->d;
                          memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d));
                          c.pos = newhead + (c.pos - c.sexp->d);
                          gcry_free (c.sexp);
                          c.sexp = newsexp;
                        }

                      *c.pos++ = ST_DATA;
                      STORE_LEN (c.pos, nm);
                      memcpy (c.pos, mp, nm);
                      c.pos += nm;
                    }
                }
              else
                {
                  if (gcry_mpi_print (mpifmt, NULL, 0, &nm, m))
                    BUG ();

                  MAKE_SPACE (nm);
                  if (!gcry_is_secure (c.sexp->d)
                      && gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE))
                    {
                      /* We have to switch to secure allocation.  */
                      gcry_sexp_t newsexp;
                      byte *newhead;

                      newsexp = gcry_malloc_secure (sizeof *newsexp
                                                    + c.allocated - 1);
                      if (!newsexp)
                        {
                          err = gpg_err_code_from_errno (errno);
                          goto leave;
                        }
                      newhead = newsexp->d;
                      memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d));
                      c.pos = newhead + (c.pos - c.sexp->d);
                      gcry_free (c.sexp);
                      c.sexp = newsexp;
                    }

                  *c.pos++ = ST_DATA;
                  STORE_LEN (c.pos, nm);
                  if (gcry_mpi_print (mpifmt, c.pos, nm, &nm, m))
                    BUG ();
                  c.pos += nm;
                }
	    }
	  else if (*p == 's')
	    {
	      /* Insert an string.  */
	      const char *astr;
	      size_t alen;

	      ARG_NEXT (astr, const char *);
	      alen = strlen (astr);

	      MAKE_SPACE (alen);
	      *c.pos++ = ST_DATA;
	      STORE_LEN (c.pos, alen);
	      memcpy (c.pos, astr, alen);
	      c.pos += alen;
	    }
	  else if (*p == 'b')
	    {
	      /* Insert a memory buffer.  */
	      const char *astr;
	      int alen;

	      ARG_NEXT (alen, int);
	      ARG_NEXT (astr, const char *);

	      MAKE_SPACE (alen);
	      if (alen
                  && !gcry_is_secure (c.sexp->d)
		  && gcry_is_secure (astr))
              {
		  /* We have to switch to secure allocation.  */
		  gcry_sexp_t newsexp;
		  byte *newhead;

		  newsexp = gcry_malloc_secure (sizeof *newsexp
                                                + c.allocated - 1);
                  if (!newsexp)
                    {
                      err = gpg_err_code_from_errno (errno);
                      goto leave;
                    }
		  newhead = newsexp->d;
		  memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d));
		  c.pos = newhead + (c.pos - c.sexp->d);
		  gcry_free (c.sexp);
		  c.sexp = newsexp;
		}

	      *c.pos++ = ST_DATA;
	      STORE_LEN (c.pos, alen);
	      memcpy (c.pos, astr, alen);
	      c.pos += alen;
	    }
	  else if (*p == 'd')
	    {
	      /* Insert an integer as string.  */
	      int aint;
	      size_t alen;
	      char buf[35];

	      ARG_NEXT (aint, int);
	      sprintf (buf, "%d", aint);
	      alen = strlen (buf);
	      MAKE_SPACE (alen);
	      *c.pos++ = ST_DATA;
	      STORE_LEN (c.pos, alen);
	      memcpy (c.pos, buf, alen);
	      c.pos += alen;
	    }
	  else if (*p == 'u')
	    {
	      /* Insert an unsigned integer as string.  */
	      unsigned int aint;
	      size_t alen;
	      char buf[35];

	      ARG_NEXT (aint, unsigned int);
	      sprintf (buf, "%u", aint);
	      alen = strlen (buf);
	      MAKE_SPACE (alen);
	      *c.pos++ = ST_DATA;
	      STORE_LEN (c.pos, alen);
	      memcpy (c.pos, buf, alen);
	      c.pos += alen;
	    }
	  else if (*p == 'S')
	    {
	      /* Insert a gcry_sexp_t.  */
	      gcry_sexp_t asexp;
	      size_t alen, aoff;

	      ARG_NEXT (asexp, gcry_sexp_t);
              alen = get_internal_buffer (asexp, &aoff);
              if (alen)
                {
                  MAKE_SPACE (alen);
                  memcpy (c.pos, asexp->d + aoff, alen);
                  c.pos += alen;
                }
	    }
	  else
	    {
	      *erroff = p - buffer;
	      /* Invalid format specifier.  */
	      err = GPG_ERR_SEXP_INV_LEN_SPEC;
              goto leave;
	    }
	  percent = NULL;
	}
      else if (*p == '(')
	{
	  if (disphint)
	    {
	      *erroff = p - buffer;
	      /* Open display hint.  */
	      err = GPG_ERR_SEXP_UNMATCHED_DH;
              goto leave;
	    }
	  MAKE_SPACE (0);
	  *c.pos++ = ST_OPEN;
	  level++;
	}
      else if (*p == ')')
	{
	  /* Walk up.  */
	  if (disphint)
	    {
	      *erroff = p - buffer;
	      /* Open display hint.  */
	      err = GPG_ERR_SEXP_UNMATCHED_DH;
              goto leave;
	    }
	  MAKE_SPACE (0);
	  *c.pos++ = ST_CLOSE;
	  level--;
	}
      else if (*p == '\"')
	{
	  quoted = p;
	  quoted_esc = 0;
	}
      else if (*p == '#')
	{
	  hexfmt = p;
	  hexcount = 0;
	}
      else if (*p == '|')
	base64 = p;
      else if (*p == '[')
	{
	  if (disphint)
	    {
	      *erroff = p - buffer;
	      /* Open display hint.  */
	      err = GPG_ERR_SEXP_NESTED_DH;
              goto leave;
	    }
	  disphint = p;
	}
      else if (*p == ']')
	{
	  if (!disphint)
	    {
	      *erroff = p - buffer;
	      /* Open display hint.  */
	      err = GPG_ERR_SEXP_UNMATCHED_DH;
              goto leave;
	    }
	  disphint = NULL;
	}
      else if (digitp (p))
	{
	  if (*p == '0')
	    {
	      /* A length may not begin with zero.  */
	      *erroff = p - buffer;
	      err = GPG_ERR_SEXP_ZERO_PREFIX;
              goto leave;
	    }
	  digptr = p;
	}
      else if (strchr (tokenchars, *p))
	tokenp = p;
      else if (whitespacep (p))
	;
      else if (*p == '{')
	{
	  /* fixme: handle rescanning: we can do this by saving our
	     current state and start over at p+1 -- Hmmm. At this
	     point here we are in a well defined state, so we don't
	     need to save it.  Great.  */
	  *erroff = p - buffer;
	  err = GPG_ERR_SEXP_UNEXPECTED_PUNC;
          goto leave;
	}
      else if (strchr ("&\\", *p))
	{
	  /* Reserved punctuation.  */
	  *erroff = p - buffer;
	  err = GPG_ERR_SEXP_UNEXPECTED_PUNC;
          goto leave;
	}
      else if (argflag && (*p == '%'))
	percent = p;
      else
	{
	  /* Bad or unavailable.  */
	  *erroff = p - buffer;
	  err = GPG_ERR_SEXP_BAD_CHARACTER;
          goto leave;
	}
    }
  MAKE_SPACE (0);
  *c.pos++ = ST_STOP;

  if (level && !err)
    err = GPG_ERR_SEXP_UNMATCHED_PAREN;

 leave:
  if (err)
    {
      /* Error -> deallocate.  */
      if (c.sexp)
        {
          /* Extra paranoid wipe on error. */
          if (gcry_is_secure (c.sexp))
            wipememory (c.sexp, sizeof (struct gcry_sexp) + c.allocated - 1);
          gcry_free (c.sexp);
        }
      /* This might be expected by existing code...  */
      *retsexp = NULL;
    }
  else
    *retsexp = normalize (c.sexp);

  return gcry_error (err);
#undef MAKE_SPACE
#undef STORE_LEN
}
Example #22
0
/*
 * Register a resource (which currently may only be a keybox file).
 * The first keybox which is added by this function is created if it
 * does not exist.  If AUTO_CREATED is not NULL it will be set to true
 * if the function has created a a new keybox.
 */
int
keydb_add_resource (const char *url, int force, int secret, int *auto_created)
{
  static int any_secret, any_public;
  const char *resname = url;
  char *filename = NULL;
  int rc = 0;
  FILE *fp;
  KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;

  if (auto_created)
    *auto_created = 0;

  /* Do we have an URL?
     gnupg-kbx:filename := this is a plain keybox
     filename := See what is is, but create as plain keybox.
  */
  if (strlen (resname) > 10)
    {
      if (!strncmp (resname, "gnupg-kbx:", 10) )
        {
          rt = KEYDB_RESOURCE_TYPE_KEYBOX;
          resname += 10;
	}
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
      else if (strchr (resname, ':'))
        {
          log_error ("invalid key resource URL `%s'\n", url );
          rc = gpg_error (GPG_ERR_GENERAL);
          goto leave;
	}
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
    }

  if (*resname != DIRSEP_C )
    { /* do tilde expansion etc */
      if (strchr(resname, DIRSEP_C) )
        filename = make_filename (resname, NULL);
      else
        filename = make_filename (opt.homedir, resname, NULL);
    }
  else
    filename = xstrdup (resname);

  if (!force)
    force = secret? !any_secret : !any_public;

  /* see whether we can determine the filetype */
  if (rt == KEYDB_RESOURCE_TYPE_NONE)
    {
      FILE *fp2 = fopen( filename, "rb" );

      if (fp2) {
        u32 magic;

        /* FIXME: check for the keybox magic */
        if (fread( &magic, 4, 1, fp2) == 1 )
          {
            if (magic == 0x13579ace || magic == 0xce9a5713)
              ; /* GDBM magic - no more support */
            else
              rt = KEYDB_RESOURCE_TYPE_KEYBOX;
          }
        else /* maybe empty: assume ring */
          rt = KEYDB_RESOURCE_TYPE_KEYBOX;
        fclose (fp2);
      }
      else /* no file yet: create ring */
        rt = KEYDB_RESOURCE_TYPE_KEYBOX;
    }

  switch (rt)
    {
    case KEYDB_RESOURCE_TYPE_NONE:
      log_error ("unknown type of key resource `%s'\n", url );
      rc = gpg_error (GPG_ERR_GENERAL);
      goto leave;

    case KEYDB_RESOURCE_TYPE_KEYBOX:
      fp = fopen (filename, "rb");
      if (!fp && !force)
        {
          rc = gpg_error (gpg_err_code_from_errno (errno));
          goto leave;
        }

      if (!fp)
        { /* no file */
#if 0 /* no autocreate of the homedirectory yet */
          {
            char *last_slash_in_filename;

            last_slash_in_filename = strrchr (filename, DIRSEP_C);
            *last_slash_in_filename = 0;
            if (access (filename, F_OK))
              { /* on the first time we try to create the default
                   homedir and in this case the process will be
                   terminated, so that on the next invocation can
                   read the options file in on startup */
                try_make_homedir (filename);
                rc = gpg_error (GPG_ERR_FILE_OPEN_ERROR);
                *last_slash_in_filename = DIRSEP_C;
                goto leave;
              }
            *last_slash_in_filename = DIRSEP_C;
          }
#endif
          fp = fopen (filename, "w");
          if (!fp)
            {
              rc = gpg_error (gpg_err_code_from_errno (errno));
              log_error (_("error creating keybox `%s': %s\n"),
                         filename, strerror(errno));
              if (errno == ENOENT)
                log_info (_("you may want to start the gpg-agent first\n"));
              goto leave;
	    }

          if (!opt.quiet)
            log_info (_("keybox `%s' created\n"), filename);
          if (auto_created)
            *auto_created = 1;
	}
	fclose (fp);
	fp = NULL;
        /* now register the file */
        {

          void *token = keybox_register_file (filename, secret);
          if (!token)
            ; /* already registered - ignore it */
          else if (used_resources >= MAX_KEYDB_RESOURCES)
            rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
          else
            {
              all_resources[used_resources].type = rt;
              all_resources[used_resources].u.kr = NULL; /* Not used here */
              all_resources[used_resources].token = token;
              all_resources[used_resources].secret = secret;

              all_resources[used_resources].lockhandle
                = create_dotlock (filename);
              if (!all_resources[used_resources].lockhandle)
                log_fatal ( _("can't create lock for `%s'\n"), filename);

              /* Do a compress run if needed and the file is not locked. */
              if (!make_dotlock (all_resources[used_resources].lockhandle, 0))
                {
                  KEYBOX_HANDLE kbxhd = keybox_new (token, secret);

                  if (kbxhd)
                    {
                      keybox_compress (kbxhd);
                      keybox_release (kbxhd);
                    }
                  release_dotlock (all_resources[used_resources].lockhandle);
                }

              used_resources++;
            }
        }


	break;
    default:
      log_error ("resource type of `%s' not supported\n", url);
      rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
      goto leave;
    }

  /* fixme: check directory permissions and print a warning */

 leave:
  if (rc)
    log_error ("keyblock resource `%s': %s\n", filename, gpg_strerror(rc));
  else if (secret)
    any_secret = 1;
  else
    any_public = 1;
  xfree (filename);
  return rc;
}
Example #23
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 #24
0
File: error.c Project: gpg/gsti
/* Retrieve the system error for the error code CODE.  This returns 0
   if CODE is not a system error code.  */
int
gsti_err_code_to_errno (gsti_err_code_t code)
{
  return gpg_err_code_from_errno (code);
}
Example #25
0
/* See card.c for interface description */
static int
dinsig_read_cert (CARD card, const char *certidstr,
                  unsigned char **cert, size_t *ncert)
{
  int rc;
  struct sc_path path;
  struct sc_file *file;
  unsigned char *buf;
  int buflen;

  if (!strcmp (certidstr, "DINSIG-DF01.C000"))
    sc_format_path ("3F00DF01C000", &path);
  else if (!strcmp (certidstr, "DINSIG-DF01.C200"))
    sc_format_path ("3F00DF01C200", &path);
  else
    return gpg_error (GPG_ERR_INV_ID);

  rc = sc_select_file (card->scard, &path, &file);
  if (rc)
    {
      log_error ("sc_select_file failed: %s\n", sc_strerror (rc));
      return map_sc_err (rc);
    }
  if (file->type != SC_FILE_TYPE_WORKING_EF
      || file->ef_structure != SC_FILE_EF_TRANSPARENT)
    {
      log_error ("wrong type or structure of certificate EF\n");
      sc_file_free (file);
      return gpg_error (GPG_ERR_CARD);
    }
  if (file->size < 20) /* check against a somewhat arbitrary length */
    {
      log_error ("certificate EF too short\n");
      sc_file_free (file);
      return gpg_error (GPG_ERR_CARD);
    }
  buf = xtrymalloc (file->size);
  if (!buf)
    {
      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
      sc_file_free (file);
      return tmperr;
    }

  rc = sc_read_binary (card->scard, 0, buf, file->size, 0);
  if (rc >= 0 && rc != file->size)
    {
      log_error ("short read on certificate EF\n");
      sc_file_free (file);
      xfree (buf);
      return gpg_error (GPG_ERR_CARD);
    }
  sc_file_free (file);
  if (rc < 0)
    {
      log_error ("error reading certificate EF: %s\n", sc_strerror (rc));
      xfree (buf);
      return map_sc_err (rc);
    }
  buflen = rc;

  /* The object is not a plain certificate but wrapped into id-at
     userCertificate - fixme: we should check the specs and decided
     whether libksba should support it */
  if (buflen > 9 && buf[0] == 0x30 && buf[4] == 6 && buf[5] == 3
      && buf[6] == 0x55 && buf[7] == 4 && buf[8] == 0x24)
    {
      /* We have to strip the padding.  Although this is a good idea
         anyway, we have to do it due to a KSBA problem; KSBA does not
         work correct when the buffer is larger than the ASN.1
         structure and the certificates here are padded with FF.  So
         as a workaround we look at the outer structure to get the
         size of the entire thing and adjust the buflen.  We can only
         do this when there is a 2 byte length field */
      size_t seqlen;
      if (buf[1] == 0x82)
        {
          seqlen = ((buf[2] << 8) | buf[3]) + 4;
          if (seqlen < buflen)
            buflen = seqlen;
        }
      memmove (buf, buf+9, buflen-9);
      buflen -= 9;
    }

  *cert = buf;
  *ncert = buflen;
  return 0;
}
Example #26
0
/* Return an error value with the system error ERR.  */
gcry_err_code_t
gcry_error_from_errno (int err)
{
  return gcry_error (gpg_err_code_from_errno (err));
}
Example #27
0
/* Retrieve the system error for the error code CODE.  This returns 0
   if CODE is not a system error code.  */
int
gcry_err_code_to_errno (gcry_err_code_t code)
{
  return gpg_err_code_from_errno (code);
}
Example #28
0
/****************
 * We do not need to use the strongest RNG because we gain no extra
 * security from it - The prime number is public and we could also
 * offer the factors for those who are willing to check that it is
 * indeed a strong prime.  With ALL_FACTORS set to true all afcors of
 * prime-1 are returned in FACTORS.
 *
 * mode 0: Standard
 *	1: Make sure that at least one factor is of size qbits.
 */
static gcry_err_code_t
prime_generate_internal (int mode,
			 gcry_mpi_t *prime_generated, unsigned int pbits,
			 unsigned int qbits, gcry_mpi_t g,
			 gcry_mpi_t **ret_factors,
			 gcry_random_level_t randomlevel, unsigned int flags,
                         int all_factors,
                         gcry_prime_check_func_t cb_func, void *cb_arg)
{
  gcry_err_code_t err = 0;
  gcry_mpi_t *factors_new = NULL; /* Factors to return to the
				     caller.  */
  gcry_mpi_t *factors = NULL;	/* Current factors.  */
  gcry_mpi_t *pool = NULL;	/* Pool of primes.  */
  unsigned char *perms = NULL;	/* Permutations of POOL.  */
  gcry_mpi_t q_factor = NULL;	/* Used if QBITS is non-zero.  */
  unsigned int fbits = 0;	/* Length of prime factors.  */
  unsigned int n = 0;		/* Number of factors.  */
  unsigned int m = 0;		/* Number of primes in pool.  */
  gcry_mpi_t q = NULL;		/* First prime factor.  */
  gcry_mpi_t prime = NULL;	/* Prime candidate.  */
  unsigned int nprime = 0;	/* Bits of PRIME.  */
  unsigned int req_qbits;       /* The original QBITS value.  */
  gcry_mpi_t val_2;             /* For check_prime().  */
  unsigned int is_secret = (flags & GCRY_PRIME_FLAG_SECRET);
  unsigned int count1 = 0, count2 = 0;
  unsigned int i = 0, j = 0;

  if (pbits < 48)
    return GPG_ERR_INV_ARG;

  /* If QBITS is not given, assume a reasonable value. */
  if (!qbits)
    qbits = pbits / 3;

  req_qbits = qbits;

  /* Find number of needed prime factors.  */
  for (n = 1; (pbits - qbits - 1) / n  >= qbits; n++)
    ;
  n--;

  val_2 = mpi_alloc_set_ui (2);

  if ((! n) || ((mode == 1) && (n < 2)))
    {
      err = GPG_ERR_INV_ARG;
      goto leave;
    }

  if (mode == 1)
    {
      n--;
      fbits = (pbits - 2 * req_qbits -1) / n;
      qbits =  pbits - req_qbits - n * fbits;
    }
  else
    {
      fbits = (pbits - req_qbits -1) / n;
      qbits = pbits - n * fbits;
    }
  
  if (DBG_CIPHER)
    log_debug ("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n",
               pbits, req_qbits, qbits, fbits, n);

  prime = gcry_mpi_new (pbits);

  /* Generate first prime factor.  */
  q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL);
  
  if (mode == 1)
    q_factor = gen_prime (req_qbits, is_secret, randomlevel, NULL, NULL);
  
  /* Allocate an array to hold the factors + 2 for later usage.  */
  factors = gcry_calloc (n + 2, sizeof (*factors));
  if (!factors)
    {
      err = gpg_err_code_from_errno (errno);
      goto leave;
    }
      
  /* Make a pool of 3n+5 primes (this is an arbitrary value).  */
  m = n * 3 + 5;
  if (mode == 1) /* Need some more (for e.g. DSA).  */
    m += 5;
  if (m < 25)
    m = 25;
  pool = gcry_calloc (m , sizeof (*pool));
  if (! pool)
    {
      err = gpg_err_code_from_errno (errno);
      goto leave;
    }

  /* Permutate over the pool of primes.  */
  do
    {
    next_try:
      if (! perms)
        {
          /* Allocate new primes.  */
          for(i = 0; i < m; i++)
            {
              mpi_free (pool[i]);
              pool[i] = NULL;
            }

          /* Init m_out_of_n().  */
          perms = gcry_calloc (1, m);
          if (! perms)
            {
              err = gpg_err_code_from_errno (errno);
              goto leave;
            }
          for(i = 0; i < n; i++)
            {
              perms[i] = 1;
              pool[i] = gen_prime (fbits, is_secret,
                                   randomlevel, NULL, NULL);
              factors[i] = pool[i];
            }
        }
      else
        {
          m_out_of_n ((char*)perms, n, m);
          for (i = j = 0; (i < m) && (j < n); i++)
            if (perms[i])
              {
                if(! pool[i])
                  pool[i] = gen_prime (fbits, 0, 1, NULL, NULL);
                factors[j++] = pool[i];
              }
          if (i == n)
            {
              gcry_free (perms);
              perms = NULL;
              progress ('!');
              goto next_try;	/* Allocate new primes.  */
            }
        }

	/* Generate next prime candidate:
	   p = 2 * q [ * q_factor] * factor_0 * factor_1 * ... * factor_n + 1. 
        */
	mpi_set (prime, q);
	mpi_mul_ui (prime, prime, 2);
	if (mode == 1)
	  mpi_mul (prime, prime, q_factor);
	for(i = 0; i < n; i++)
	  mpi_mul (prime, prime, factors[i]);
	mpi_add_ui (prime, prime, 1);
	nprime = mpi_get_nbits (prime);

	if (nprime < pbits)
	  {
	    if (++count1 > 20)
	      {
		count1 = 0;
		qbits++;
		progress('>');
		mpi_free (q);
		q = gen_prime (qbits, 0, 0, NULL, NULL);
		goto next_try;
	      }
	  }
	else
	  count1 = 0;
        
	if (nprime > pbits)
	  {
	    if (++count2 > 20)
	      {
		count2 = 0;
		qbits--;
		progress('<');
		mpi_free (q);
		q = gen_prime (qbits, 0, 0, NULL, NULL);
		goto next_try;
	      }
	  }
	else
	  count2 = 0;
    }
  while (! ((nprime == pbits) && check_prime (prime, val_2, cb_func, cb_arg)));

  if (DBG_CIPHER)
    {
      progress ('\n');
      log_mpidump ("prime    : ", prime);
      log_mpidump ("factor  q: ", q);
      if (mode == 1)
        log_mpidump ("factor q0: ", q_factor);
      for (i = 0; i < n; i++)
        log_mpidump ("factor pi: ", factors[i]);
      log_debug ("bit sizes: prime=%u, q=%u",
                 mpi_get_nbits (prime), mpi_get_nbits (q));
      if (mode == 1)
        log_debug (", q0=%u", mpi_get_nbits (q_factor));
      for (i = 0; i < n; i++)
        log_debug (", p%d=%u", i, mpi_get_nbits (factors[i]));
      progress('\n');
    }

  if (ret_factors)
    {
      /* Caller wants the factors.  */
      factors_new = gcry_calloc (n + 4, sizeof (*factors_new));
      if (! factors_new)
        {
          err = gpg_err_code_from_errno (errno);
          goto leave;
        }

      if (all_factors)
        {
          i = 0;
          factors_new[i++] = gcry_mpi_set_ui (NULL, 2);
          factors_new[i++] = mpi_copy (q);
          if (mode == 1)
            factors_new[i++] = mpi_copy (q_factor);
          for(j=0; j < n; j++)
            factors_new[i++] = mpi_copy (factors[j]);
        }
      else
        {
          i = 0;
          if (mode == 1)
            {
              factors_new[i++] = mpi_copy (q_factor);
              for (; i <= n; i++)
                factors_new[i] = mpi_copy (factors[i]);
            }
          else
            for (; i < n; i++ )
              factors_new[i] = mpi_copy (factors[i]);
        }
    }
  
  if (g)
    {
      /* Create a generator (start with 3).  */
      gcry_mpi_t tmp = mpi_alloc (mpi_get_nlimbs (prime));
      gcry_mpi_t b = mpi_alloc (mpi_get_nlimbs (prime));
      gcry_mpi_t pmin1 = mpi_alloc (mpi_get_nlimbs (prime));
      
      if (mode == 1)
        err = GPG_ERR_NOT_IMPLEMENTED;
      else
        {
          factors[n] = q;
          factors[n + 1] = mpi_alloc_set_ui (2);
          mpi_sub_ui (pmin1, prime, 1);
          mpi_set_ui (g, 2);
          do
            {
              mpi_add_ui (g, g, 1);
              if (DBG_CIPHER)
                {
                  log_debug ("checking g:");
                  gcry_mpi_dump (g);
                  log_printf ("\n");
                }
              else
                progress('^');
              for (i = 0; i < n + 2; i++)
                {
                  mpi_fdiv_q (tmp, pmin1, factors[i]);
                  /* No mpi_pow(), but it is okay to use this with mod
                     prime.  */
                  gcry_mpi_powm (b, g, tmp, prime);
                  if (! mpi_cmp_ui (b, 1))
                    break;
                }
              if (DBG_CIPHER)
                progress('\n');
            } 
          while (i < n + 2);

          mpi_free (factors[n+1]);
          mpi_free (tmp);
          mpi_free (b);
          mpi_free (pmin1);
        }
    }
  
  if (! DBG_CIPHER)
    progress ('\n');


 leave:
  if (pool)
    {
      for(i = 0; i < m; i++)
	mpi_free (pool[i]);
      gcry_free (pool);
    }
  if (factors)
    gcry_free (factors);  /* Factors are shallow copies.  */
  if (perms)
    gcry_free (perms);

  mpi_free (val_2);
  mpi_free (q);
  mpi_free (q_factor);

  if (! err)
    {
      *prime_generated = prime;
      if (ret_factors)
	*ret_factors = factors_new;
    }
  else
    {
      if (factors_new)
	{
	  for (i = 0; factors_new[i]; i++)
	    mpi_free (factors_new[i]);
	  gcry_free (factors_new);
	}
      mpi_free (prime);
    }

  return err;
}
Example #29
0
/* Perform an encrypt operation.  

   Encrypt the data received on DATA-FD and write it to OUT_FP.  The
   recipients are take from the certificate given in recplist; if this
   is NULL it will be encrypted for a default recipient */
int
gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp)
{
  int rc = 0;
  Base64Context b64writer = NULL;
  gpg_error_t err;
  ksba_writer_t writer;
  ksba_reader_t reader = NULL;
  ksba_cms_t cms = NULL;
  ksba_stop_reason_t stopreason;
  KEYDB_HANDLE kh = NULL;
  struct encrypt_cb_parm_s encparm;
  DEK dek = NULL;
  int recpno;
  FILE *data_fp = NULL;
  certlist_t cl;
  int count;

  memset (&encparm, 0, sizeof encparm);

  audit_set_type (ctrl->audit, AUDIT_TYPE_ENCRYPT);

  /* Check that the certificate list is not empty and that at least
     one certificate is not flagged as encrypt_to; i.e. is a real
     recipient. */
  for (cl = recplist; cl; cl = cl->next)
    if (!cl->is_encrypt_to)
      break;
  if (!cl)
    {
      log_error(_("no valid recipients given\n"));
      gpgsm_status (ctrl, STATUS_NO_RECP, "0");
      audit_log_i (ctrl->audit, AUDIT_GOT_RECIPIENTS, 0);
      rc = gpg_error (GPG_ERR_NO_PUBKEY);
      goto leave;
    }

  for (count = 0, cl = recplist; cl; cl = cl->next)
    count++;
  audit_log_i (ctrl->audit, AUDIT_GOT_RECIPIENTS, count);

  kh = keydb_new (0);
  if (!kh)
    {
      log_error (_("failed to allocated keyDB handle\n"));
      rc = gpg_error (GPG_ERR_GENERAL);
      goto leave;
    }

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

  err = ksba_reader_new (&reader);
  if (err)
      rc = err;
  if (!rc)
    rc = ksba_reader_set_cb (reader, encrypt_cb, &encparm);
  if (rc)
      goto leave;

  encparm.fp = data_fp;

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

  err = ksba_cms_new (&cms);
  if (err)
    {
      rc = err;
      goto leave;
    }

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

  audit_log (ctrl->audit, AUDIT_GOT_DATA);

  /* We are going to create enveloped data with uninterpreted data as
     inner content */
  err = ksba_cms_set_content_type (cms, 0, KSBA_CT_ENVELOPED_DATA);
  if (!err)
    err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA);
  if (err)
    {
      log_debug ("ksba_cms_set_content_type failed: %s\n",
                 gpg_strerror (err));
      rc = err;
      goto leave;
    }

  /* Create a session key */
  dek = xtrycalloc_secure (1, sizeof *dek); 
  if (!dek)
    rc = out_of_core ();
  else
  {
    dek->algoid = opt.def_cipher_algoid;
    rc = init_dek (dek);
  }
  if (rc)
    {
      log_error ("failed to create the session key: %s\n",
                 gpg_strerror (rc));
      goto leave;
    }

  err = ksba_cms_set_content_enc_algo (cms, dek->algoid, dek->iv, dek->ivlen);
  if (err)
    {
      log_error ("ksba_cms_set_content_enc_algo failed: %s\n",
                 gpg_strerror (err));
      rc = err;
      goto leave;
    }

  encparm.dek = dek;
  /* Use a ~8k (AES) or ~4k (3DES) buffer */
  encparm.bufsize = 500 * dek->ivlen;
  encparm.buffer = xtrymalloc (encparm.bufsize);
  if (!encparm.buffer)
    {
      rc = out_of_core ();
      goto leave;
    }
  
  audit_log_s (ctrl->audit, AUDIT_SESSION_KEY, dek->algoid);

  /* Gather certificates of recipients, encrypt the session key for
     each and store them in the CMS object */
  for (recpno = 0, cl = recplist; cl; recpno++, cl = cl->next)
    {
      unsigned char *encval;
      
      rc = encrypt_dek (dek, cl->cert, &encval);
      if (rc)
        {
          audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, rc);
          log_error ("encryption failed for recipient no. %d: %s\n",
                     recpno, gpg_strerror (rc));
          goto leave;
        }
      
      err = ksba_cms_add_recipient (cms, cl->cert);
      if (err)
        {
          audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err);
          log_error ("ksba_cms_add_recipient failed: %s\n",
                     gpg_strerror (err));
          rc = err;
          xfree (encval);
          goto leave;
        }
      
      err = ksba_cms_set_enc_val (cms, recpno, encval);
      xfree (encval);
      audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err);
      if (err)
        {
          log_error ("ksba_cms_set_enc_val failed: %s\n",
                     gpg_strerror (err));
          rc = err;
          goto leave;
        }
    }

  /* Main control loop for encryption. */
  recpno = 0;
  do 
    {
      err = ksba_cms_build (cms, &stopreason);
      if (err)
        {
          log_debug ("ksba_cms_build failed: %s\n", gpg_strerror (err));
          rc = err;
          goto leave;
        }
    }
  while (stopreason != KSBA_SR_READY);   

  if (encparm.readerror)
    {
      log_error ("error reading input: %s\n", strerror (encparm.readerror));
      rc = gpg_error (gpg_err_code_from_errno (encparm.readerror));
      goto leave;
    }


  rc = gpgsm_finish_writer (b64writer);
  if (rc) 
    {
      log_error ("write failed: %s\n", gpg_strerror (rc));
      goto leave;
    }
  audit_log (ctrl->audit, AUDIT_ENCRYPTION_DONE);
  log_info ("encrypted data created\n");

 leave:
  ksba_cms_release (cms);
  gpgsm_destroy_writer (b64writer);
  ksba_reader_release (reader);
  keydb_release (kh); 
  xfree (dek);
  if (data_fp)
    fclose (data_fp);
  xfree (encparm.buffer);
  return rc;
}
Example #30
0
/* Retrieve the error code for the system error ERR.  This returns
   GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report
   this).  */
gcry_err_code_t
gcry_err_code_from_errno (int err)
{
  return gpg_err_code_from_errno (err);
}