Bug#285371: Still a problem.

Andreas Metzler Andreas Metzler <ametzler@downhill.at.eu.org>, 285371@bugs.debian.org
Sun, 19 Dec 2004 15:35:36 +0100


--tKW2IUtsqtDRztdT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On 2004-12-14 Andreas Metzler <ametzler@downhill.at.eu.org> wrote:
> On 2004-12-14 "Yazz D. Atlas" <yazz@230volts.net> wrote:
> [...]
> > Is there a way to generate this by hand? If I could just generate it 
> > correctly  then I could have it run when /etc/cron.daily/exim4-base is 
> > called.
> [...]

> You can try to use the attached file to generate gnutls-params-new and
> mv it it to gnutls-params instead removing gnutls-params, however as
> it does exactly the same thing as exim4 I doubt you'll favour better.

Have you tried this? If not can you check how long the attached
version takes?

gcc -Wall -o exim_gnutls-params -O2 -g exim_gnutls-params.c  -lgnutls
time ./exim_gnutls-params -v --indefinitely /var/spool/exim4

What does
sysctl -n kernel/random/entropy_avail
say on your system?
              cu andreas
-- 
"See, I told you they'd listen to Reason," [SPOILER] Svfurlr fnlf,
fuhggvat qbja gur juveyvat tha.
Neal Stephenson in "Snow Crash"
                                           http://downhill.aus.cc/

--tKW2IUtsqtDRztdT
Content-Type: text/x-csrc; charset=us-ascii
Content-Disposition: attachment; filename="exim_gnutls-params.c"

/*#include "exim.h"*/

/* Heading stuff for GnuTLS */
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#include <signal.h>
#include <syslog.h>


/* #include "mytypes.h" */
/* extracted from mytypes.h *
*/
typedef int BOOL;
typedef unsigned char uschar;
#define FALSE         0
#define TRUE          1
#define US   (unsigned char *)
#define CS   (char *)
#define CCS  (const char *)

#define Ustrcmp(s,t)       strcmp(CCS(s),CCS(t))
#ifdef O_BINARY                                        /* This is for Cygwin,  */
#define Uopen(s,n,m)       open(CCS(s),(n)|O_BINARY,m) /* where all files must */
#else                                                  /* be opened as binary  */
#define Uopen(s,n,m)       open(CCS(s),n,m)            /* to avoid problems    */
#endif                                                 /* with CRLF endings.   */
/*
 extracted from mytypes.h */


#define UNKNOWN_NAME "unknown"
#define DH_BITS      768
#define RSA_BITS     512


/*************************************************
*               Handle TLS error                 *
*************************************************/
/*
Argument:
  prefix    text to include in the logged error
  err       a GnuTLS error number, or 0 if local error

Returns:    OK/DEFER/FAIL
*/

int gnutls_timeout=3;

static int
gnutls_error(uschar *prefix, int err)
{
  if (err==0)
    fprintf(stderr,"%s",prefix);
  else
    fprintf(stderr,"%s %s",prefix,gnutls_strerror(err));
  return 1;
}


/*************************************************
*        Write/read datum to/from file           *
*************************************************/

/* These functions are used for saving and restoring the RSA and D-H parameters
for use by all Exim processes. Data that is read is placed in malloc'd store
because that's what happens for newly generated data.

Arguments:
  fd          the file descriptor
  d           points to the datum

returns:      FALSE on error (errno set)
*/

static BOOL
write_datum(int fd, gnutls_datum *d)
{
if (write(fd, &(d->size), sizeof(d->size)) != sizeof(d->size)) return FALSE;
if (write(fd, d->data, d->size) != d->size) return FALSE;
return TRUE;
}

void tooktolong()
{
  fprintf(stderr, "Timeout occured after %d seconds\n",gnutls_timeout);
  syslog(LOG_ERR | LOG_MAIL, "Timeout occured after %d seconds\n",gnutls_timeout);
  exit(1);
}

/*************************************************
*          Setup up RSA and DH parameters        *
*************************************************/

/* Generating the RSA and D-H parameters takes a long time. They only need to
be re-generated every so often, depending on security policy. What we do is to
keep these parameters in a file in the spool directory. If the file does not
exist, we generate them. This means that it is easy to cause a regeneration.
*/

int
main(int argc, char **argv)
{
int fd, ret, verbose=FALSE;
gnutls_datum m, e, d, p, q, u, prime, generator;
uschar filename[200]="";
#define GNUTLSPARAMFILE "/gnutls-params"
struct stat statbuf;
unsigned int rsa_bits = RSA_BITS;
unsigned int dh_bits = DH_BITS;
gnutls_rsa_params rsa_params = NULL;
gnutls_dh_params dh_params = NULL;
uschar tempfilename[sizeof(filename) + 10];


if (0==geteuid()||0==getegid()) {
  fprintf(stderr,"Please run as exim user and exim group.\n");
  return 1;
  /*
  setgid(exim_gid);
  setuid(exim_uid);
  if (verbose) printf("Dropped privileges\n");
  */
}

signal(SIGALRM,tooktolong);


while (argc > 1)
  {
    if (Ustrcmp(argv[1], "-v") == 0) verbose=TRUE;
    else if (Ustrcmp(argv[1], "--indefinitely")== 0) gnutls_timeout=0;
    else break;
    argv++;
    argc--;
  }
if (argc!=2) {
  printf("Usage: %s [-v] [--indefinitely] spooldir\n",argv[0]);
  return 1;
}

/* Set up the name of the cache file */
if (strlen(argv[1])+strlen(GNUTLSPARAMFILE)>=200)
  return gnutls_error(US"overlong filename", 0);
strcat(filename,argv[1]);
strcat(filename,GNUTLSPARAMFILE);

/* exit if cache file exist 
if (0==(stat(CS filename,&statbuf))) {
  if (verbose) printf("File [%s] exists, exiting.\n",filename);
  return 0;
}
*/

ret=gnutls_global_init();
if (ret < 0) return gnutls_error(US"tls-init", ret);

/* Initialize the data structures for holding the parameters */
ret = gnutls_rsa_params_init(&rsa_params);
if (ret < 0) return gnutls_error(US"init rsa_params", ret);

ret = gnutls_dh_params_init(&dh_params);
if (ret < 0) return gnutls_error(US"init dh_params", ret);

if (verbose) printf("generating %d bit RSA key...\n", RSA_BITS);
alarm(gnutls_timeout);
ret = gnutls_rsa_params_generate2(rsa_params, RSA_BITS);
alarm(0);
if (ret < 0) return gnutls_error(US"RSA key generation", ret);

if (verbose) printf("generating %d bit Diffie-Hellman key...\n",
  DH_BITS);
alarm(gnutls_timeout);
ret = gnutls_dh_params_generate2(dh_params, DH_BITS);
alarm(0);
if (ret < 0) return gnutls_error(US"D-H key generation", ret);

/* Write the parameters to a file in the spool directory so that we
can use them from other Exim processes. */
sprintf(CS tempfilename, "%s-%d", filename, (int)getpid());
fd = Uopen(tempfilename, O_WRONLY|O_CREAT, 0400);
if (fd < 0){
  fprintf(stderr, "Failed to open %s for writing, error %s\n",
      tempfilename,strerror(errno));
  return 1;
}

ret = gnutls_rsa_params_export_raw(rsa_params, &m, &e, &d, &p, &q, &u,
  &rsa_bits);
if (ret < 0) return gnutls_error(US"RSA params export", ret);

ret = gnutls_dh_params_export_raw(dh_params, &prime, &generator, &dh_bits);
if (ret < 0) return gnutls_error(US"DH params export", ret);

if (!write_datum(fd, &m) ||
    !write_datum(fd, &e) ||
    !write_datum(fd, &d) ||
    !write_datum(fd, &p) ||
    !write_datum(fd, &q) ||
    !write_datum(fd, &u) ||
    !write_datum(fd, &prime) ||
    !write_datum(fd, &generator))
  return gnutls_error(US"TLS cache write failed", 0);

(void)close(fd);

if (rename(CS tempfilename, CS filename) < 0)
  fprintf(stderr, "failed to rename %s as %s: %s\n",
    tempfilename, filename, strerror(errno));

if (verbose) printf("wrote RSA and D-H parameters to file %s\n",filename);
return 0;
}
/*
 * vim:tabstop=2:expandtab:shiftwidth=2
*/

--tKW2IUtsqtDRztdT--