Beispiel #1
0
/****************
 * Note:  It was a bad idea to use the number of limbs to allocate
 *	  because on a alpha the limbs are large but we normally need
 *	  integers of n bits - So we should chnage this to bits (or bytes).
 *
 *	  But mpi_alloc is used in a lot of places :-)
 */
gcry_mpi_t
_gcry_mpi_alloc( unsigned nlimbs )
{
    gcry_mpi_t a;

    a = gcry_xmalloc( sizeof *a );
    a->d = nlimbs? mpi_alloc_limb_space( nlimbs, 0 ) : NULL;
    a->alloced = nlimbs;
    a->nlimbs = 0;
    a->sign = 0;
    a->flags = 0;
    return a;
}
Beispiel #2
0
mpi_ptr_t
_gcry_mpi_alloc_limb_space( unsigned int nlimbs, int secure )
{
    mpi_ptr_t p;
    size_t len;

    len = (nlimbs ? nlimbs : 1) * sizeof (mpi_limb_t);
    p = secure ? gcry_xmalloc_secure (len) : gcry_xmalloc (len);
    if (! nlimbs)
      *p = 0;

    return p;
}
Beispiel #3
0
static void
print_sexp (const char *prefix, gcry_sexp_t a)
{
  char *buf;
  size_t size;

  if (prefix)
    fputs (prefix, stderr);
  size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
  buf = gcry_xmalloc (size);

  gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
  fprintf (stderr, "%.*s", (int)size, buf);
  gcry_free (buf);
}
Beispiel #4
0
void *
gcry_xcalloc( 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 ( nbytes );
  memset ( p, 0, nbytes );
  return p;
}
Beispiel #5
0
/* Convert STRING consisting of hex characters into its binary
   representation and return it as an allocated buffer. The valid
   length of the buffer is returned at R_LENGTH.  The string is
   delimited by end of string.  The function returns NULL on
   error.  */
static void *
data_from_hex (const char *string, size_t *r_length)
{
  const char *s;
  unsigned char *buffer;
  size_t length;

  buffer = gcry_xmalloc (strlen(string)/2+1);
  length = 0;
  for (s=string; *s; s +=2 )
    {
      if (!hexdigitp (s) || !hexdigitp (s+1))
        die ("error parsing hex string `%s'\n", string);
      ((unsigned char*)buffer)[length++] = xtoi_2 (s);
    }
  *r_length = length;
  return buffer;
}
Beispiel #6
0
void
gcry_mpi_randomize( gcry_mpi_t w,
		    unsigned int nbits, enum gcry_random_level level )
{
  unsigned char *p;
  size_t nbytes = (nbits+7)/8;
  
  if (level == GCRY_WEAK_RANDOM)
    {
      p = mpi_is_secure(w) ? gcry_xmalloc_secure (nbytes)
                           : gcry_xmalloc (nbytes);
      gcry_create_nonce (p, nbytes);
    }
  else
    {
      p = mpi_is_secure(w) ? gcry_random_bytes_secure (nbytes, level)
                           : gcry_random_bytes (nbytes, level);
    }
  _gcry_mpi_set_buffer( w, p, nbytes, 0 );
  gcry_free (p);
}
Beispiel #7
0
/*********************************************
 **************  interface  ******************
 *********************************************/
static gcry_mpi_t
ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p)
{
  gpg_error_t err;
  int pbytes = (mpi_get_nbits (p)+7)/8;
  size_t n;
  unsigned char *buf, *ptr;
  gcry_mpi_t result;

  buf = gcry_xmalloc ( 1 + 2*pbytes );
  *buf = 04; /* Uncompressed point.  */
  ptr = buf+1;
  err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x);
  if (err)
    log_fatal ("mpi_print failed: %s\n", gpg_strerror (err));
  if (n < pbytes)
    {
      memmove (ptr+(pbytes-n), ptr, n);
      memset (ptr, 0, (pbytes-n));
    }
  ptr += pbytes;
  err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y);
  if (err)
    log_fatal ("mpi_print failed: %s\n", gpg_strerror (err));
  if (n < pbytes)
    {
      memmove (ptr+(pbytes-n), ptr, n);
      memset (ptr, 0, (pbytes-n));
    }
  
  err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, buf, 1+2*pbytes, NULL);
  if (err)
    log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err));
  gcry_free (buf);

  mpi_free (x);
  mpi_free (y);

  return result;
}
Beispiel #8
0
static int
gather_faked( void (*add)(const void*, size_t, int), int requester,
              size_t length, int level )
{
    static int initialized=0;
    size_t n;
    char *buffer, *p;

    if( !initialized ) {
        log_info(_("WARNING: using insecure random number generator!!\n"));
        /* we can't use tty_printf here - do we need this function at
          all - does it really make sense or canit be viewed as a potential
          security problem ? wk 17.11.99 */
#if 0
        tty_printf(_("The random number generator is only a kludge to let\n"
                     "it run - it is in no way a strong RNG!\n\n"
                     "DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
#endif
        initialized=1;
#ifdef HAVE_RAND
        srand( time(NULL)*getpid());
#else
        srandom( time(NULL)*getpid());
#endif
    }

    p = buffer = gcry_xmalloc( length );
    n = length;
#ifdef HAVE_RAND
    while( n-- )
        *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
#else
    while( n-- )
        *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
#endif
    add_randomness( buffer, length, requester );
    gcry_free(buffer);
    return 0; /* okay */
}
Beispiel #9
0
void
test_sexp ( int argc, char **argv )
{
    int rc, nbits;
    gcry_sexp_t sexp;
    gcry_mpi_t key[3];
    size_t n;
    char *buf;

    if ( gcry_mpi_scan( &key[0], GCRYMPI_FMT_HEX, elg_testkey1.p, NULL ) )
	BUG();
    if ( gcry_mpi_scan( &key[1], GCRYMPI_FMT_HEX, elg_testkey1.g, NULL ) )
	BUG();
    if ( gcry_mpi_scan( &key[2], GCRYMPI_FMT_HEX, elg_testkey1.y, NULL ) )
	BUG();

    /* get nbits from a key */
    rc = gcry_sexp_build ( &sexp, NULL,
			   "(public-key(elg(p%m)(g%m)(y%m)))",
				  key[0], key[1], key[2] );
    fputs ( "DUMP of PK:\n", stderr );
    gcry_sexp_dump ( sexp );
    {  gcry_sexp_t x;
       x = gcry_sexp_cdr ( sexp );
       fputs ( "DUMP of CDR:\n", stderr );
       gcry_sexp_dump ( x );
       gcry_sexp_release ( x );
    }
    nbits = gcry_pk_get_nbits( sexp );
    printf ( "elg_testkey1 - nbits=%d\n", nbits );
    n = gcry_sexp_sprint ( sexp, 0, NULL, 0 );
    buf = gcry_xmalloc ( n );
    n = gcry_sexp_sprint ( sexp, 0, buf, n );
    printf ( "sprint length=%u\n", (unsigned int)n );
    gcry_free ( buf );
    gcry_sexp_release( sexp );
}
Beispiel #10
0
static void
back_and_forth_one (int testno, const char *buffer, size_t length)
{
  gcry_error_t rc;
  gcry_sexp_t se, se1;
  size_t n, n1;
  char *p1;

  rc = gcry_sexp_new (&se, buffer, length, 1);
  if (rc)
    {
      fail ("baf %d: gcry_sexp_new failed: %s\n", testno, gpg_strerror (rc));
      return;
    }
  n1 = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, NULL, 0);
  if (!n1)
    {
      fail ("baf %d: get required length for canon failed\n", testno);
      return;
    }
  p1 = gcry_xmalloc (n1);
  n = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, p1, n1);
  if (n1 != n+1) /* sprints adds an extra 0 but dies not return it */
    {
      fail ("baf %d: length mismatch for canon\n", testno);
      return;
    }
  rc = gcry_sexp_create (&se1, p1, n, 0, gcry_free);
  if (rc)
    {
      fail ("baf %d: gcry_sexp_create failed: %s\n",
            testno, gpg_strerror (rc));
      return;
    }
  gcry_sexp_release (se1);

  /* Again but with memory checking. */
  p1 = gcry_xmalloc (n1+2);
  *p1 = '\x55';
  p1[n1+1] = '\xaa';
  n = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, p1+1, n1);
  if (n1 != n+1) /* sprints adds an extra 0 but does not return it */
    {
      fail ("baf %d: length mismatch for canon\n", testno);
      return;
    }
  if (*p1 != '\x55' || p1[n1+1] != '\xaa')
    fail ("baf %d: memory corrupted (1)\n", testno);
  rc = gcry_sexp_create (&se1, p1+1, n, 0, NULL);
  if (rc)
    {
      fail ("baf %d: gcry_sexp_create failed: %s\n",
            testno, gpg_strerror (rc));
      return;
    }
  if (*p1 != '\x55' || p1[n1+1] != '\xaa')
    fail ("baf %d: memory corrupted (2)\n", testno);
  gcry_sexp_release (se1);
  if (*p1 != '\x55' || p1[n1+1] != '\xaa')
    fail ("baf %d: memory corrupted (3)\n", testno);
  gcry_free (p1);

  /* FIXME: we need a lot more tests */

  gcry_sexp_release (se);
}
Beispiel #11
0
static gcry_mpi_t
gen_prime (unsigned int nbits, int secret, int randomlevel, 
           int (*extra_check)(void *, gcry_mpi_t), void *extra_check_arg)
{
  gcry_mpi_t prime, ptest, pminus1, val_2, val_3, result;
  int i;
  unsigned int x, step;
  unsigned int count1, count2;
  int *mods;
  
/*   if (  DBG_CIPHER ) */
/*     log_debug ("generate a prime of %u bits ", nbits ); */

  if (nbits < 16)
    log_fatal ("can't generate a prime with less than %d bits\n", 16);

  mods = gcry_xmalloc( no_of_small_prime_numbers * sizeof *mods );
  /* Make nbits fit into gcry_mpi_t implementation. */
  val_2  = mpi_alloc_set_ui( 2 );
  val_3 = mpi_alloc_set_ui( 3);
  prime  = secret? gcry_mpi_snew ( nbits ): gcry_mpi_new ( nbits );
  result = mpi_alloc_like( prime );
  pminus1= mpi_alloc_like( prime );
  ptest  = mpi_alloc_like( prime );
  count1 = count2 = 0;
  for (;;)
    {  /* try forvever */
      int dotcount=0;
      
      /* generate a random number */
      gcry_mpi_randomize( prime, nbits, randomlevel );
      
      /* Set high order bit to 1, set low order bit to 1.  If we are
         generating a secret prime we are most probably doing that
         for RSA, to make sure that the modulus does have the
         requested key size we set the 2 high order bits. */
      mpi_set_highbit (prime, nbits-1);
      if (secret)
        mpi_set_bit (prime, nbits-2);
      mpi_set_bit(prime, 0);
      
      /* Calculate all remainders. */
      for (i=0; (x = small_prime_numbers[i]); i++ )
        mods[i] = mpi_fdiv_r_ui(NULL, prime, x);
      
      /* Now try some primes starting with prime. */
      for(step=0; step < 20000; step += 2 ) 
        {
          /* Check against all the small primes we have in mods. */
          count1++;
          for (i=0; (x = small_prime_numbers[i]); i++ ) 
            {
              while ( mods[i] + step >= x )
                mods[i] -= x;
              if ( !(mods[i] + step) )
                break;
	    }
          if ( x )
            continue;   /* Found a multiple of an already known prime. */
          
          mpi_add_ui( ptest, prime, step );

          /* Do a fast Fermat test now. */
          count2++;
          mpi_sub_ui( pminus1, ptest, 1);
          gcry_mpi_powm( result, val_2, pminus1, ptest );
          if ( !mpi_cmp_ui( result, 1 ) )
            { 
              /* Not composite, perform stronger tests */
              if (is_prime(ptest, 5, &count2 ))
                {
                  if (!mpi_test_bit( ptest, nbits-1-secret ))
                    {
                      progress('\n');
                      log_debug ("overflow in prime generation\n");
                      break; /* Stop loop, continue with a new prime. */
                    }

                  if (extra_check && extra_check (extra_check_arg, ptest))
                    { 
                      /* The extra check told us that this prime is
                         not of the caller's taste. */
                      progress ('/');
                    }
                  else
                    { 
                      /* Got it. */
                      mpi_free(val_2);
                      mpi_free(val_3);
                      mpi_free(result);
                      mpi_free(pminus1);
                      mpi_free(prime);
                      gcry_free(mods);
                      return ptest; 
                    }
                }
	    }
          if (++dotcount == 10 )
            {
              progress('.');
              dotcount = 0;
	    }
	}
      progress(':'); /* restart with a new random value */
    }
}
Beispiel #12
0
static void
back_and_forth_one (int testno, const char *buffer, size_t length)
{
  gcry_error_t rc;
  gcry_sexp_t se, se1;
  unsigned char *canon;
  size_t canonlen;  /* Including the hidden nul suffix.  */
  size_t n, n1;
  char *p1;

  rc = gcry_sexp_new (&se, buffer, length, 1);
  if (rc)
    {
      fail ("baf %d: gcry_sexp_new failed: %s\n", testno, gpg_strerror (rc));
      return;
    }
  n1 = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, NULL, 0);
  if (!n1)
    {
      fail ("baf %d: get required length for canon failed\n", testno);
      return;
    }
  p1 = gcry_xmalloc (n1);
  n = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, p1, n1);
  if (n1 != n+1) /* sprints adds an extra 0 but does not return it. */
    {
      fail ("baf %d: length mismatch for canon\n", testno);
      return;
    }
  canonlen = n1;
  canon = gcry_malloc (canonlen);
  memcpy (canon, p1, canonlen);
  rc = gcry_sexp_create (&se1, p1, n, 0, gcry_free);
  if (rc)
    {
      fail ("baf %d: gcry_sexp_create failed: %s\n",
            testno, gpg_strerror (rc));
      return;
    }
  gcry_sexp_release (se1);

  /* Again but with memory checking. */
  p1 = gcry_xmalloc (n1+2);
  *p1 = '\x55';
  p1[n1+1] = '\xaa';
  n = gcry_sexp_sprint (se, GCRYSEXP_FMT_CANON, p1+1, n1);
  if (n1 != n+1) /* sprints adds an extra 0 but does not return it */
    {
      fail ("baf %d: length mismatch for canon\n", testno);
      return;
    }
  if (*p1 != '\x55' || p1[n1+1] != '\xaa')
    fail ("baf %d: memory corrupted (1)\n", testno);
  rc = gcry_sexp_create (&se1, p1+1, n, 0, NULL);
  if (rc)
    {
      fail ("baf %d: gcry_sexp_create failed: %s\n",
            testno, gpg_strerror (rc));
      return;
    }
  if (*p1 != '\x55' || p1[n1+1] != '\xaa')
    fail ("baf %d: memory corrupted (2)\n", testno);
  gcry_sexp_release (se1);
  if (*p1 != '\x55' || p1[n1+1] != '\xaa')
    fail ("baf %d: memory corrupted (3)\n", testno);
  gcry_free (p1);

  /* Check converting to advanced format.  */
  n1 = gcry_sexp_sprint (se, GCRYSEXP_FMT_ADVANCED, NULL, 0);
  if (!n1)
    {
      fail ("baf %d: get required length for advanced failed\n", testno);
      return;
    }
  p1 = gcry_xmalloc (n1);
  n = gcry_sexp_sprint (se, GCRYSEXP_FMT_ADVANCED, p1, n1);
  if (n1 != n+1) /* sprints adds an extra 0 but does not return it */
    {
      fail ("baf %d: length mismatch for advanced\n", testno);
      return;
    }
  rc = gcry_sexp_create (&se1, p1, n, 0, gcry_free);
  if (rc)
    {
      fail ("baf %d: gcry_sexp_create failed: %s\n",
            testno, gpg_strerror (rc));
      return;
    }
  if (compare_to_canon (se1, canon, canonlen))
    {
      fail ("baf %d: converting to advanced failed: %s\n",
            testno, gpg_strerror (rc));
      return;
    }
  gcry_sexp_release (se1);


  /* FIXME: we need a lot more tests */

  gcry_sexp_release (se);
  xfree (canon);
}
Beispiel #13
0
/****************
 * Extract the CAR of the given list
 */
gcry_sexp_t
gcry_sexp_nth( const gcry_sexp_t list, int number )
{
    const byte *p;
    DATALEN n;
    gcry_sexp_t newlist;
    byte *d;
    int level = 0;

    if ( !list || list->d[0] != ST_OPEN )
	return NULL;
    p = list->d;

    while ( number > 0 ) {
	p++;
	if ( *p == ST_DATA ) {
	    memcpy ( &n, ++p, sizeof n );
	    p += sizeof n + n;
	    p--;
	    if ( !level )
		number--;
	}
	else if ( *p == ST_OPEN ) {
	    level++;
	}
	else if ( *p == ST_CLOSE ) {
	    level--;
	    if ( !level )
		number--;
	}
	else if ( *p == ST_STOP ) {
	    return NULL;
	}
    }
    p++;

    if ( *p == ST_DATA ) {
	memcpy ( &n, p, sizeof n ); p += sizeof n;
	newlist = gcry_xmalloc ( sizeof *newlist + n + 1 );
	d = newlist->d;
	memcpy ( d, p, n ); d += n;
	*d++ = ST_STOP;
    }
    else if ( *p == ST_OPEN ) {
	const byte *head = p;

	level = 1;
	do {
	    p++;
	    if ( *p == ST_DATA ) {
		memcpy ( &n, ++p, sizeof n );
		p += sizeof n + n;
		p--;
	    }
	    else if ( *p == ST_OPEN ) {
		level++;
	    }
	    else if ( *p == ST_CLOSE ) {
		level--;
	    }
	    else if ( *p == ST_STOP ) {
		BUG ();
	    }
	} while ( level );
	n = p + 1 - head;

	newlist = gcry_xmalloc ( sizeof *newlist + n );
	d = newlist->d;
	memcpy ( d, head, n ); d += n;
	*d++ = ST_STOP;
    }
    else
	newlist = NULL;

    return normalize (newlist);
}
Beispiel #14
0
/****************
 * Get the CDR
 */
gcry_sexp_t
gcry_sexp_cdr( const gcry_sexp_t list )
{
    const byte *p;
    const byte *head;
    DATALEN n;
    gcry_sexp_t newlist;
    byte *d;
    int level = 0;
    int skip = 1;

    if ( !list || list->d[0] != ST_OPEN )
	return NULL;
    p = list->d;

    while ( skip > 0 ) {
	p++;
	if ( *p == ST_DATA ) {
	    memcpy ( &n, ++p, sizeof n );
	    p += sizeof n + n;
	    p--;
	    if ( !level )
		skip--;
	}
	else if ( *p == ST_OPEN ) {
	    level++;
	}
	else if ( *p == ST_CLOSE ) {
	    level--;
	    if ( !level )
		skip--;
	}
	else if ( *p == ST_STOP ) {
	    return NULL;
	}
    }
    p++;

    head = p;
    level = 0;
    do {
	if ( *p == ST_DATA ) {
	    memcpy ( &n, ++p, sizeof n );
	    p += sizeof n + n;
	    p--;
	}
	else if ( *p == ST_OPEN ) {
	    level++;
	}
	else if ( *p == ST_CLOSE ) {
	    level--;
	}
	else if ( *p == ST_STOP ) {
	    return NULL;
	}
	p++;
    } while ( level );
    n = p - head;

    newlist = gcry_xmalloc ( sizeof *newlist + n + 2 );
    d = newlist->d;
    *d++ = ST_OPEN;
    memcpy ( d, head, n ); d += n;
    *d++ = ST_CLOSE;
    *d++ = ST_STOP;

    return normalize (newlist);
}
Beispiel #15
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 occured, 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.
 *  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
sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
	    const char *buffer, size_t length, int argflag,
	    va_list arg_ptr, void **arg_list)
{
  gcry_err_code_t err = GPG_ERR_NO_ERROR;
  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;

  /* FIXME: invent better error codes (?).  */

  if (! erroff)
    erroff = &dummy_erroff;

  /* Depending on wether 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)

#define MAKE_SPACE(n)  do { make_space ( &c, (n) ); } while (0)
#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_xmalloc_secure (sizeof *c.sexp + c.allocated - 1);
  else
    c.sexp = gcry_xmalloc (sizeof *c.sexp + c.allocated - 1);
  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;
		      //return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
		    }
		  p += 2;
		  n -= 2;
		  quoted_esc = 0;
		  break;
		  
		case 'x':
		  if (! ((n > 2) && isxdigit(p[1]) && isxdigit(p[2])))
		    {
		      *erroff = p - buffer;
		      /* Invalid hex value.  */
		      err = GPG_ERR_SEXP_BAD_QUOTATION;
		      //return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
		    }
		  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;
		}
	    }
	  else if (*p == '\\')
	    quoted_esc = 1;
	  else if (*p == '\"')
	    {
	      /* Keep it easy - we know that the unquoted string will
		 never be larger. */
	      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;
		}

	      datalen = hexcount / 2;
	      MAKE_SPACE (datalen);
	      *c.pos++ = ST_DATA;
	      STORE_LEN (c.pos, datalen);
	      for (hexfmt++; hexfmt < p; hexfmt++)
		{
		  if (isspace (*hexfmt))
		    continue;
		  *c.pos++ = hextobyte (hexfmt);
		  hexfmt++;
		}
	      hexfmt = NULL;
	    }
	  else if (! isspace (*p))
	    {
	      *erroff = p - buffer;
	      err = GPG_ERR_SEXP_BAD_HEX_CHAR;
	    }
	}
      else if (base64)
	{
	  if (*p == '|')
	    base64 = NULL;
	}
      else if (digptr)
	{
	  if (isdigit (*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;
		}
	      /* 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;
	    }
	}
      else if (percent)
	{
	  if (*p == 'm')
	    {
	      /* Insert an MPI.  */
	      gcry_mpi_t m;
	      size_t nm = 0;

	      ARG_NEXT (m, gcry_mpi_t);
	      
	      if (gcry_mpi_print (GCRYMPI_FMT_STD, 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_xmalloc_secure (sizeof *newsexp
						 + c.allocated - 1);
		  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 (GCRYMPI_FMT_STD, 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_xmalloc_secure (sizeof *newsexp
 						 + c.allocated - 1);
		  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[20];
	      
	      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
	    {
	      *erroff = p - buffer;
	      /* Invalid format specifier.  */
	      err = GPG_ERR_SEXP_INV_LEN_SPEC;
	    }
	  percent = NULL;
	}
      else if (*p == '(')
	{
	  if (disphint)
	    {
	      *erroff = p - buffer;
	      /* Open display hint.  */
	      err = GPG_ERR_SEXP_UNMATCHED_DH;
	    }
	  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;
	    }
	  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;
	    }
	  disphint = p;
	}
      else if (*p == ']')
	{
	  if (! disphint)
	    {
	      *erroff = p - buffer;
	      /* Open display hint.  */
	      err = GPG_ERR_SEXP_UNMATCHED_DH;
	    }
	  disphint = NULL;
	}
      else if (isdigit (*p))
	{
	  if (*p == '0')
	    {
	      /* A length may not begin with zero.  */
	      *erroff = p - buffer;
	      err = GPG_ERR_SEXP_ZERO_PREFIX;
	    }
	  digptr = p;
	}
      else if (strchr (tokenchars, *p))
	tokenp = p;
      else if (isspace (*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;
	}
      else if (strchr ("&\\", *p))
	{
	  /* Reserved punctuation.  */
	  *erroff = p - buffer;
	  err = GPG_ERR_SEXP_UNEXPECTED_PUNC;
	}
      else if (argflag && (*p == '%'))
	percent = p;
      else
	{
	  /* Bad or unavailable.  */
	  *erroff = p - buffer;
	  err = GPG_ERR_SEXP_BAD_CHARACTER;
	}
    }
  MAKE_SPACE (0);
  *c.pos++ = ST_STOP;

  if (level)
    err = GPG_ERR_SEXP_UNMATCHED_PAREN;

  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
}
Beispiel #16
0
/* Fallback method using the registry to poll the statistics.  */
static void
registry_poll (void (*add)(const void*, size_t, enum random_origins),
               enum random_origins requester)
{
  static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
  int iterations;
  DWORD dwSize, status;
  PERF_DATA_BLOCK *pPerfData;

  /* Get information from the system performance counters.  This can take a
     few seconds to do.  In some environments the call to RegQueryValueEx()
     can produce an access violation at some random time in the future, in
     some cases adding a short delay after the following code block makes
     the problem go away.  This problem is extremely difficult to
     reproduce, I haven't been able to get it to occur despite running it
     on a number of machines.  MS knowledge base article Q178887 covers
     this type of problem, it's typically caused by an external driver or
     other program that adds its own values under the
     HKEY_PERFORMANCE_DATA key.  The NT kernel, via Advapi32.dll, calls the
     required external module to map in the data inside an SEH try/except
     block, so problems in the module's collect function don't pop up until
     after it has finished, so the fault appears to occur in Advapi32.dll.
     There may be problems in the NT kernel as well though, a low-level
     memory checker indicated that ExpandEnvironmentStrings() in
     Kernel32.dll, called an interminable number of calls down inside
     RegQueryValueEx(), was overwriting memory (it wrote twice the
     allocated size of a buffer to a buffer allocated by the NT kernel).
     OTOH this could be coming from the external module calling back into
     the kernel, which eventually causes the problem described above.

     Possibly as an extension of the problem that the krnlWaitSemaphore()
     call above works around, running two instances of cryptlib (e.g. two
     applications that use it) under NT4 can result in one of them hanging
     in the RegQueryValueEx() call.  This happens only under NT4 and is
     hard to reproduce in any consistent manner.

     One workaround that helps a bit is to read the registry as a remote
     (rather than local) registry, it's possible that the use of a network
     RPC call isolates the calling app from the problem in that whatever
     service handles the RPC is taking the hit and not affecting the
     calling app.  Since this would require another round of extensive
     testing to verify and the NT native API call is working fine, we'll
     stick with the native API call for now.

     Some versions of NT4 had a problem where the amount of data returned
     was mis-reported and would never settle down, because of this the code
     below includes a safety-catch that bails out after 10 attempts have
     been made, this results in no data being returned but at does ensure
     that the thread will terminate.

     In addition to these problems the code in RegQueryValueEx() that
     estimates the amount of memory required to return the performance
     counter information isn't very accurate (it's much worse than the
     "slightly-inaccurate" level that the MS docs warn about, it's usually
     wildly off) since it always returns a worst-case estimate which is
     usually nowhere near the actual amount required.  For example it may
     report that 128K of memory is required, but only return 64K of data.

     Even worse than the registry-based performance counters is the
     performance data helper (PDH) shim that tries to make the counters
     look like the old Win16 API (which is also used by Win95).  Under NT
     this can consume tens of MB of memory and huge amounts of CPU time
     while it gathers its data, and even running once can still consume
     about 1/2MB of memory */
  if (getenv ("GNUPG_RNDW32_NOPERF"))
    {
      static int shown;

      if (!shown)
        {
          shown = 1;
          log_info ("note: get performance data has been disabled\n");
        }
    }
  else
    {
      pPerfData = gcry_xmalloc (cbPerfData);
      for (iterations=0; iterations < 10; iterations++)
        {
          dwSize = cbPerfData;
          if ( debug_me )
            log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );

          status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
                                    NULL, (LPBYTE) pPerfData, &dwSize);
          if (status == ERROR_SUCCESS)
            {
              if (!memcmp (pPerfData->Signature, L"PERF", 8))
                (*add) ( pPerfData, dwSize, requester );
              else
                log_debug ("rndw32: no PERF signature\n");
              break;
            }
          else if (status == ERROR_MORE_DATA)
            {
              cbPerfData += PERFORMANCE_BUFFER_STEP;
              pPerfData = gcry_xrealloc (pPerfData, cbPerfData);
            }
          else
            {
              static int been_here;

              /* Silence the error message.  In particular under Wine (as
                 of 2008) we would get swamped with such diagnotiscs.  One
                 such diagnotiscs should be enough.  */
              if (been_here != status)
                {
                  been_here = status;
                  log_debug ("rndw32: get performance data problem: ec=%ld\n",
                             status);
                }
              break;
            }
        }
      gcry_free (pPerfData);
    }

  /* Although this isn't documented in the Win32 API docs, it's necessary
     to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
     implicitly opened on the first call to RegQueryValueEx()).  If this
     isn't done then any system components which provide performance data
     can't be removed or changed while the handle remains active.  */
  RegCloseKey (HKEY_PERFORMANCE_DATA);
}
Beispiel #17
0
static void
slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester )
{
    static int is_initialized = 0;
    static NETSTATISTICSGET pNetStatisticsGet = NULL;
    static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
    static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
    static int is_workstation = 1;

    static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
    PERF_DATA_BLOCK *pPerfData;
    HANDLE hDevice, hNetAPI32 = NULL;
    DWORD dwSize, status;
    int nDrive;

    if ( !is_initialized ) {
	HKEY hKey;

	if ( debug_me )
	    log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" );
	/* Find out whether this is an NT server or workstation if necessary */
	if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
			  "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
			  0, KEY_READ, &hKey) == ERROR_SUCCESS) {
	    BYTE szValue[32];
	    dwSize = sizeof (szValue);

	    if ( debug_me )
		log_debug ("rndw32#slow_gatherer_nt: check product options\n" );
	    status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
				      szValue, &dwSize);
	    if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) {
		/* Note: There are (at least) three cases for ProductType:
		 * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
		 * NT Server acting as a Domain Controller */
		is_workstation = 0;
		if ( debug_me )
		    log_debug ("rndw32: this is a NT server\n");
	    }
	    RegCloseKey (hKey);
	}

	/* Initialize the NetAPI32 function pointers if necessary */
	if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) {
	    if ( debug_me )
		log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" );
	    pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
						       "NetStatisticsGet");
	    pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
						       "NetApiBufferSize");
	    pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
						       "NetApiBufferFree");

	    if ( !pNetStatisticsGet
		 || !pNetApiBufferSize || !pNetApiBufferFree ) {
		FreeLibrary (hNetAPI32);
		hNetAPI32 = NULL;
		log_debug ("rndw32: No NETAPI found\n" );
	    }
	}

	is_initialized = 1;
    }

    /* Get network statistics.	Note: Both NT Workstation and NT Server by
     * default will be running both the workstation and server services.  The
     * heuristic below is probably useful though on the assumption that the
     * majority of the network traffic will be via the appropriate service.
     * In any case the network statistics return almost no randomness */
    {	LPBYTE lpBuffer;
	if (hNetAPI32 && !pNetStatisticsGet (NULL,
			   is_workstation ? L"LanmanWorkstation" :
			   L"LanmanServer", 0, 0, &lpBuffer) ) {
	    if ( debug_me )
		log_debug ("rndw32#slow_gatherer_nt: get netstats\n" );
	    pNetApiBufferSize (lpBuffer, &dwSize);
	    (*add) ( lpBuffer, dwSize,requester );
	    pNetApiBufferFree (lpBuffer);
	}
    }

    /* Get disk I/O statistics for all the hard drives */
    for (nDrive = 0;; nDrive++) {
        char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT];
	char szDevice[50];

	/* Check whether we can access this device */
	sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive);
	hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
			      NULL, OPEN_EXISTING, 0, NULL);
	if (hDevice == INVALID_HANDLE_VALUE)
	    break;

	/* Note: This only works if you have turned on the disk performance
	 * counters with 'diskperf -y'.  These counters are off by default */
	if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
			     diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT,
			     &dwSize, NULL))
	{
	    if ( debug_me )
		log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n",
								  nDrive );
	    (*add) (diskPerformance, dwSize, requester );
	}
	else {
	    log_info ("NOTE: you should run 'diskperf -y' "
		      "to enable the disk statistics\n");
	}
	CloseHandle (hDevice);
    }

#if 0 /* we don't need this in GnuPG  */
    /* Wait for any async keyset driver binding to complete.  You may be
     * wondering what this call is doing here... the reason it's necessary is
     * because RegQueryValueEx() will hang indefinitely if the async driver
     * bind is in progress.  The problem occurs in the dynamic loading and
     * linking of driver DLL's, which work as follows:
     *
     * hDriver = LoadLibrary( DRIVERNAME );
     * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 );
     * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 );
     *
     * If RegQueryValueEx() is called while the GetProcAddress()'s are in
     * progress, it will hang indefinitely.  This is probably due to some
     * synchronisation problem in the NT kernel where the GetProcAddress()
     * calls affect something like a module reference count or function
     * reference count while RegQueryValueEx() is trying to take a snapshot
     * of the statistics, which include the reference counts.  Because of
     * this, we have to wait until any async driver bind has completed
     * before we can call RegQueryValueEx() */
    waitSemaphore (SEMAPHORE_DRIVERBIND);
#endif

    /* Get information from the system performance counters.  This can take
     * a few seconds to do.  In some environments the call to
     * RegQueryValueEx() can produce an access violation at some random time
     * in the future, adding a short delay after the following code block
     * makes the problem go away.  This problem is extremely difficult to
     * reproduce, I haven't been able to get it to occur despite running it
     * on a number of machines.  The best explanation for the problem is that
     * on the machine where it did occur, it was caused by an external driver
     * or other program which adds its own values under the
     * HKEY_PERFORMANCE_DATA key.  The NT kernel calls the required external
     * modules to map in the data, if there's a synchronisation problem the
     * external module would write its data at an inappropriate moment,
     * causing the access violation.  A low-level memory checker indicated
     * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an
     * interminable number of calls down inside RegQueryValueEx(), was
     * overwriting memory (it wrote twice the allocated size of a buffer to a
     * buffer allocated by the NT kernel).  This may be what's causing the
     * problem, but since it's in the kernel there isn't much which can be
     * done.
     *
     * In addition to these problems the code in RegQueryValueEx() which
     * estimates the amount of memory required to return the performance
     * counter information isn't very accurate, since it always returns a
     * worst-case estimate which is usually nowhere near the actual amount
     * required.  For example it may report that 128K of memory is required,
     * but only return 64K of data */
    {	pPerfData =  gcry_xmalloc (cbPerfData);
	for (;;) {
	    dwSize = cbPerfData;
	    if ( debug_me )
		log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );
	    status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
				      NULL, (LPBYTE) pPerfData, &dwSize);
	    if (status == ERROR_SUCCESS) {
		if (!memcmp (pPerfData->Signature, L"PERF", 8)) {
		    (*add) ( pPerfData, dwSize, requester );
		}
		else
		    log_debug ( "rndw32: no PERF signature\n");
		break;
	    }
	    else if (status == ERROR_MORE_DATA) {
		cbPerfData += PERFORMANCE_BUFFER_STEP;
		pPerfData = gcry_realloc (pPerfData, cbPerfData);
	    }
	    else {
		log_debug ( "rndw32: get performance data problem\n");
		break;
	    }
	}
	gcry_free (pPerfData);
    }
    /* Although this isn't documented in the Win32 API docs, it's necessary
       to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
       implicitly opened on the first call to RegQueryValueEx()).  If this
       isn't done then any system components which provide performance data
       can't be removed or changed while the handle remains active */
    RegCloseKey (HKEY_PERFORMANCE_DATA);
}
Beispiel #18
0
static void
slow_gatherer ( void (*add)(const void*, size_t, enum random_origins),
                enum random_origins requester )
{
  static int is_initialized = 0;
  static int is_workstation = 1;
  HANDLE hDevice;
  DWORD dwType, dwSize, dwResult;
  ULONG ulSize;
  int drive_no, status;
  int no_results = 0;
  void *buffer;

  if ( !is_initialized )
    {
      HKEY hKey;

      if ( debug_me )
        log_debug ("rndw32#slow_gatherer: init toolkit\n" );
      /* Find out whether this is an NT server or workstation if necessary */
      if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
                        "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
                        0, KEY_READ, &hKey) == ERROR_SUCCESS)
        {
          BYTE szValue[32 + 8];
          dwSize = 32;

          if ( debug_me )
            log_debug ("rndw32#slow_gatherer: check product options\n" );

          status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
                                    szValue, &dwSize);
          if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT"))
            {
              /* Note: There are (at least) three cases for ProductType:
                 WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
                 NT Server acting as a Domain Controller.  */
              is_workstation = 0;
              if ( debug_me )
                log_debug ("rndw32: this is a NT server\n");
            }
          RegCloseKey (hKey);
        }

      /* The following are fixed for the lifetime of the process so we
         only add them once */
      /* readPnPData ();  - we have not implemented that.  */

      /* Initialize the NetAPI32 function pointers if necessary */
      hNetAPI32 = LoadLibrary ("NETAPI32.DLL");
      if (hNetAPI32)
        {
          if (debug_me)
            log_debug ("rndw32#slow_gatherer: netapi32 loaded\n" );
          pNetStatisticsGet = (NETSTATISTICSGET)
            GetProcAddress (hNetAPI32, "NetStatisticsGet");
          pNetApiBufferSize = (NETAPIBUFFERSIZE)
            GetProcAddress (hNetAPI32, "NetApiBufferSize");
          pNetApiBufferFree = (NETAPIBUFFERFREE)
            GetProcAddress (hNetAPI32, "NetApiBufferFree");

          if (!pNetStatisticsGet || !pNetApiBufferSize || !pNetApiBufferFree)
            {
              FreeLibrary (hNetAPI32);
              hNetAPI32 = NULL;
              log_debug ("rndw32: No NETAPI found\n" );
            }
        }

      /* Initialize the NT kernel native API function pointers if necessary */
      hNTAPI = GetModuleHandle ("NTDll.dll");
      if (hNTAPI)
        {
          /* Get a pointer to the NT native information query functions */
          pNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)
            GetProcAddress (hNTAPI, "NtQuerySystemInformation");
          pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)
            GetProcAddress (hNTAPI, "NtQueryInformationProcess");
          pNtPowerInformation = (NTPOWERINFORMATION)
            GetProcAddress(hNTAPI, "NtPowerInformation");

          if (!pNtQuerySystemInformation || !pNtQueryInformationProcess)
            hNTAPI = NULL;
        }


      is_initialized = 1;
    }

  read_system_rng ( add, requester );
  read_mbm_data ( add, requester );

  /* Get network statistics.    Note: Both NT Workstation and NT Server by
     default will be running both the workstation and server services.  The
     heuristic below is probably useful though on the assumption that the
     majority of the network traffic will be via the appropriate service.
     In any case the network statistics return almost no randomness.  */
  {
    LPBYTE lpBuffer;

    if (hNetAPI32
        && !pNetStatisticsGet (NULL,
                               is_workstation ? L"LanmanWorkstation" :
                               L"LanmanServer", 0, 0, &lpBuffer))
      {
        if ( debug_me )
          log_debug ("rndw32#slow_gatherer: get netstats\n" );
        pNetApiBufferSize (lpBuffer, &dwSize);
        (*add) ( lpBuffer, dwSize, requester );
        pNetApiBufferFree (lpBuffer);
      }
  }

  /* Get disk I/O statistics for all the hard drives.  100 is an
     arbitrary failsafe limit.  */
  for (drive_no = 0; drive_no < 100 ; drive_no++)
    {
      char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT + 8];
      char szDevice[50];

      /* Check whether we can access this device.  */
      snprintf (szDevice, sizeof szDevice, "\\\\.\\PhysicalDrive%d",
                drive_no);
      hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
                            NULL, OPEN_EXISTING, 0, NULL);
      if (hDevice == INVALID_HANDLE_VALUE)
        break; /* No more drives.  */

      /* Note: This only works if you have turned on the disk performance
         counters with 'diskperf -y'.  These counters are off by default. */
      dwSize = sizeof diskPerformance;
      if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
                           diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT,
                           &dwSize, NULL))
        {
          if ( debug_me )
            log_debug ("rndw32#slow_gatherer: iostat drive %d\n",
                       drive_no);
          (*add) (diskPerformance, dwSize, requester);
        }
      else
        {
          log_info ("NOTE: you should run 'diskperf -y' "
                    "to enable the disk statistics\n");
        }
      CloseHandle (hDevice);
    }

  /* In theory we should be using the Win32 performance query API to obtain
     unpredictable data from the system, however this is so unreliable (see
     the multiple sets of comments in registryPoll()) that it's too risky
     to rely on it except as a fallback in emergencies.  Instead, we rely
     mostly on the NT native API function NtQuerySystemInformation(), which
     has the dual advantages that it doesn't have as many (known) problems
     as the Win32 equivalent and that it doesn't access the data indirectly
     via pseudo-registry keys, which means that it's much faster.  Note
     that the Win32 equivalent actually works almost all of the time, the
     problem is that on one or two systems it can fail in strange ways that
     are never the same and can't be reproduced on any other system, which
     is why we use the native API here.  Microsoft officially documented
     this function in early 2003, so it'll be fairly safe to use.  */
  if ( !hNTAPI )
    {
      registry_poll (add, requester);
      return;
    }


  /* Scan the first 64 possible information types (we don't bother with
     increasing the buffer size as we do with the Win32 version of the
     performance data read, we may miss a few classes but it's no big deal).
     This scan typically yields around 20 pieces of data, there's nothing
     in the range 65...128 so chances are there won't be anything above
     there either.  */
  buffer = gcry_xmalloc (PERFORMANCE_BUFFER_SIZE);
  for (dwType = 0; dwType < 64; dwType++)
    {
      switch (dwType)
        {
          /* ID 17 = SystemObjectInformation hangs on some win2k systems.  */
        case 17:
          if (system_is_w2000)
            continue;
          break;

          /* Some information types are write-only (the IDs are shared with
             a set-information call), we skip these.  */
        case 26: case 27: case 38: case 46: case 47: case 48: case 52:
          continue;

          /* ID 53 = SystemSessionProcessInformation reads input from the
             output buffer, which has to contain a session ID and pointer
             to the actual buffer in which to store the session information.
             Because this isn't a standard query, we skip this.  */
        case  53:
          continue;
        }

      /* Query the info for this ID.  Some results (for example for
         ID = 6, SystemCallCounts) are only available in checked builds
         of the kernel.  A smaller subcless of results require that
         certain system config flags be set, for example
         SystemObjectInformation requires that the
         FLG_MAINTAIN_OBJECT_TYPELIST be set in NtGlobalFlags.  To avoid
         having to special-case all of these, we try reading each one and
         only use those for which we get a success status.  */
      dwResult = pNtQuerySystemInformation (dwType, buffer,
                                            PERFORMANCE_BUFFER_SIZE - 2048,
                                            &ulSize);
      if (dwResult != ERROR_SUCCESS)
        continue;

      /* Some calls (e.g. ID = 23, SystemProcessorStatistics, and ID = 24,
         SystemDpcInformation) incorrectly return a length of zero, so we
         manually adjust the length to the correct value.  */
      if ( !ulSize )
        {
          if (dwType == 23)
            ulSize = 6 * sizeof (ULONG);
          else if (dwType == 24)
            ulSize = 5 * sizeof (ULONG);
        }

      /* If we got some data back, add it to the entropy pool.  */
      if (ulSize > 0 && ulSize <= PERFORMANCE_BUFFER_SIZE - 2048)
        {
          if (debug_me)
            log_debug ("rndw32#slow_gatherer: %lu bytes from sysinfo %ld\n",
                       ulSize, dwType);
          (*add) (buffer, ulSize, requester);
          no_results++;
        }
    }

  /* Now we would do the same for the process information.  This
     call would rather ugly in that it requires an exact length
     match for the data returned, failing with a
     STATUS_INFO_LENGTH_MISMATCH error code (0xC0000004) if the
     length isn't an exact match.  It requires a compiler to handle
     complex nested structs, alignment issues, and so on, and
     without the headers in which the entries are declared it's
     almost impossible to do.  Thus we don't.  */


  /* Finally, do the same for the system power status information.  There
     are only a limited number of useful information types available so we
     restrict ourselves to the useful types.  In addition since this
     function doesn't return length information, we have to hardcode in
     length data.  */
  if (pNtPowerInformation)
    {
      static const struct { int type; int size; } powerInfo[] = {
        { 0, 128 },     /* SystemPowerPolicyAc */
        { 1, 128 },     /* SystemPowerPolicyDc */
        { 4, 64 },      /* SystemPowerCapabilities */
        { 5, 48 },      /* SystemBatteryState */
        { 11, 48 },     /* ProcessorInformation */
        { 12, 24 },     /* SystemPowerInformation */
        { -1, -1 }
      };
      int i;

      /* The 100 is a failsafe limit.  */
      for (i = 0; powerInfo[i].type != -1 && i < 100; i++ )
        {
          /* Query the info for this ID */
          dwResult = pNtPowerInformation (powerInfo[i].type, NULL, 0, buffer,
                                          PERFORMANCE_BUFFER_SIZE - 2048);
          if (dwResult != ERROR_SUCCESS)
            continue;
          if (debug_me)
            log_debug ("rndw32#slow_gatherer: %u bytes from powerinfo %d\n",
                       powerInfo[i].size, i);
          (*add) (buffer, powerInfo[i].size, requester);
          no_results++;
        }
      gcry_assert (i < 100);
    }
  gcry_free (buffer);

  /* We couldn't get enough results from the kernel, fall back to the
     somewhat troublesome registry poll.  */
  if (no_results < 15)
    registry_poll (add, requester);
}
Beispiel #19
0
static void
cipher_bench ( const char *algoname )
{
  static int header_printed;
  int algo;
  gcry_cipher_hd_t hd;
  int i;
  int keylen, blklen;
  char key[128];
  char *outbuf, *buf;
  char *raw_outbuf, *raw_buf;
  size_t allocated_buflen, buflen;
  int repetitions;
  static struct { int mode; const char *name; int blocked; } modes[] = {
    { GCRY_CIPHER_MODE_ECB, "   ECB/Stream", 1 },
    { GCRY_CIPHER_MODE_CBC, "      CBC", 1 },
    { GCRY_CIPHER_MODE_CFB, "      CFB", 0 },
    { GCRY_CIPHER_MODE_OFB, "      OFB", 0 },
    { GCRY_CIPHER_MODE_CTR, "      CTR", 0 },
    { GCRY_CIPHER_MODE_STREAM, "", 0 },
    {0}
  };
  int modeidx;
  gcry_error_t err = GPG_ERR_NO_ERROR;


  if (!algoname)
    {
      for (i=1; i < 400; i++)
        if ( !gcry_cipher_test_algo (i) )
          cipher_bench (gcry_cipher_algo_name (i));
      return;
    }

  if (large_buffers)
    {
      allocated_buflen = 1024 * 100;
      repetitions = 10;
    }
  else
    {
      allocated_buflen = 1024;
      repetitions = 1000;
    }
  repetitions *= cipher_repetitions;

  raw_buf = gcry_xmalloc (allocated_buflen+15);
  buf = (raw_buf
         + ((16 - ((size_t)raw_buf & 0x0f)) % buffer_alignment));
  outbuf = raw_outbuf = gcry_xmalloc (allocated_buflen+15);
  outbuf = (raw_outbuf
            + ((16 - ((size_t)raw_outbuf & 0x0f)) % buffer_alignment));

  if (!header_printed)
    {
      if (cipher_repetitions != 1)
        printf ("Running each test %d times.\n", cipher_repetitions);
      printf ("%-12s", "");
      for (modeidx=0; modes[modeidx].mode; modeidx++)
        if (*modes[modeidx].name)
          printf (" %-15s", modes[modeidx].name );
      putchar ('\n');
      printf ("%-12s", "");
      for (modeidx=0; modes[modeidx].mode; modeidx++)
        if (*modes[modeidx].name)
          printf (" ---------------" );
      putchar ('\n');
      header_printed = 1;
    }

  algo = gcry_cipher_map_name (algoname);
  if (!algo)
    {
      fprintf (stderr, PGM ": invalid cipher algorithm `%s'\n", algoname);
      exit (1);
    }

  keylen = gcry_cipher_get_algo_keylen (algo);
  if (!keylen)
    {
      fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n",
	       algoname);
      exit (1);
    }
  if ( keylen > sizeof key )
    {
        fprintf (stderr, PGM ": algo %d, keylength problem (%d)\n",
                 algo, keylen );
        exit (1);
    }
  for (i=0; i < keylen; i++)
    key[i] = i + (clock () & 0xff);

  blklen = gcry_cipher_get_algo_blklen (algo);
  if (!blklen)
    {
      fprintf (stderr, PGM ": failed to get block length for algorithm `%s'\n",
	       algoname);
      exit (1);
    }

  printf ("%-12s", gcry_cipher_algo_name (algo));
  fflush (stdout);

  for (modeidx=0; modes[modeidx].mode; modeidx++)
    {
      if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM)
          | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM))
        continue;

      for (i=0; i < sizeof buf; i++)
        buf[i] = i;

      err = gcry_cipher_open (&hd, algo, modes[modeidx].mode, 0);
      if (err)
        {
          fprintf (stderr, PGM ": error opening cipher `%s'\n", algoname);
          exit (1);
        }

      if (!cipher_with_keysetup)
        {
          err = gcry_cipher_setkey (hd, key, keylen);
          if (err)
            {
              fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
                       gpg_strerror (err));
              gcry_cipher_close (hd);
              exit (1);
            }
        }

      buflen = allocated_buflen;
      if (modes[modeidx].blocked)
        buflen = (buflen / blklen) * blklen;

      start_timer ();
      for (i=err=0; !err && i < repetitions; i++)
        {
          if (cipher_with_keysetup)
            {
              err = gcry_cipher_setkey (hd, key, keylen);
              if (err)
                {
                  fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
                           gpg_strerror (err));
                  gcry_cipher_close (hd);
                  exit (1);
                }
            }
          err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen);
        }
      stop_timer ();

      printf (" %s", elapsed_time ());
      fflush (stdout);
      gcry_cipher_close (hd);
      if (err)
        {
          fprintf (stderr, "gcry_cipher_encrypt failed: %s\n",
                   gpg_strerror (err) );
          exit (1);
        }

      err = gcry_cipher_open (&hd, algo, modes[modeidx].mode, 0);
      if (err)
        {
          fprintf (stderr, PGM ": error opening cipher `%s'/n", algoname);
          exit (1);
        }

      if (!cipher_with_keysetup)
        {
          err = gcry_cipher_setkey (hd, key, keylen);
          if (err)
            {
              fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
                       gpg_strerror (err));
              gcry_cipher_close (hd);
              exit (1);
            }
        }

      start_timer ();
      for (i=err=0; !err && i < repetitions; i++)
        {
          if (cipher_with_keysetup)
            {
              err = gcry_cipher_setkey (hd, key, keylen);
              if (err)
                {
                  fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
                           gpg_strerror (err));
                  gcry_cipher_close (hd);
                  exit (1);
                }
            }
          err = gcry_cipher_decrypt ( hd, outbuf, buflen,  buf, buflen);
        }
      stop_timer ();
      printf (" %s", elapsed_time ());
      fflush (stdout);
      gcry_cipher_close (hd);
      if (err)
        {
          fprintf (stderr, "gcry_cipher_decrypt failed: %s\n",
                   gpg_strerror (err) );
          exit (1);
        }
    }

  putchar ('\n');
  gcry_free (raw_buf);
  gcry_free (raw_outbuf);
}