Skip to content

Commit

Permalink
Add optional checkpoints for moduli screening. feedback & ok deraadt
Browse files Browse the repository at this point in the history
  • Loading branch information
daztucker committed Oct 16, 2011
1 parent 23e90d9 commit fddbcce
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 9 deletions.
69 changes: 66 additions & 3 deletions ssh/moduli.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: moduli.c,v 1.22 2010/11/10 01:33:07 djm Exp $ */
/* $OpenBSD: moduli.c,v 1.23 2011/10/16 11:02:46 dtucker Exp $ */
/*
* Copyright 1994 Phil Karn <karn@qualcomm.com>
* Copyright 1996-1998, 2003 William Allen Simpson <wsimpson@greendragon.com>
Expand Down Expand Up @@ -47,6 +47,7 @@
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <unistd.h>

#include "xmalloc.h"
#include "dh.h"
Expand Down Expand Up @@ -133,7 +134,7 @@ static u_int32_t largebits, largememory; /* megabytes */
static BIGNUM *largebase;

int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
int prime_test(FILE *, FILE *, u_int32_t, u_int32_t);
int prime_test(FILE *, FILE *, u_int32_t, u_int32_t, char *);

/*
* print moduli out in consistent form,
Expand Down Expand Up @@ -434,20 +435,68 @@ gen_candidates(FILE *out, u_int32_t memory, u_int32_t power, BIGNUM *start)
return (ret);
}

static void
write_checkpoint(char *cpfile, u_int32_t lineno)
{
FILE *fp;
char tmpfile[MAXPATHLEN];
int r;

r = snprintf(tmpfile, sizeof(tmpfile), "%s.XXXXXXXXXX", cpfile);
if (r == -1 || r >= MAXPATHLEN) {
logit("write_checkpoint: temp pathname too long");
return;
}
if ((r = mkstemp(tmpfile)) == -1) {
logit("mkstemp(%s): %s", tmpfile, strerror(errno));
return;
}
if ((fp = fdopen(r, "w")) == NULL) {
logit("write_checkpoint: fdopen: %s", strerror(errno));
close(r);
return;
}
if (fprintf(fp, "%lu\n", (unsigned long)lineno) > 0 && fclose(fp) == 0
&& rename(tmpfile, cpfile) == 0)
debug3("wrote checkpoint line %lu to '%s'",
(unsigned long)lineno, cpfile);
else
logit("failed to write to checkpoint file '%s': %s", cpfile,
strerror(errno));
}

static unsigned long
read_checkpoint(char *cpfile)
{
FILE *fp;
unsigned long lineno = 0;

if ((fp = fopen(cpfile, "r")) == NULL)
return 0;
if (fscanf(fp, "%lu\n", &lineno) < 1)
logit("Failed to load checkpoint from '%s'", cpfile);
else
logit("Loaded checkpoint from '%s' line %lu", cpfile, lineno);
fclose(fp);
return lineno;
}

/*
* perform a Miller-Rabin primality test
* on the list of candidates
* (checking both q and p)
* The result is a list of so-call "safe" primes
*/
int
prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted)
prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted,
char *checkpoint_file)
{
BIGNUM *q, *p, *a;
BN_CTX *ctx;
char *cp, *lp;
u_int32_t count_in = 0, count_out = 0, count_possible = 0;
u_int32_t generator_known, in_tests, in_tries, in_type, in_size;
unsigned long last_processed = 0;
time_t time_start, time_stop;
int res;

Expand All @@ -468,10 +517,21 @@ prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted)
debug2("%.24s Final %u Miller-Rabin trials (%x generator)",
ctime(&time_start), trials, generator_wanted);

if (checkpoint_file != NULL)
last_processed = read_checkpoint(checkpoint_file);

res = 0;
lp = xmalloc(QLINESIZE + 1);
while (fgets(lp, QLINESIZE + 1, in) != NULL) {
count_in++;
if (checkpoint_file != NULL) {
if (count_in <= last_processed) {
debug3("skipping line %u, before checkpoint",
count_in);
continue;
}
write_checkpoint(checkpoint_file, count_in);
}
if (strlen(lp) < 14 || *lp == '!' || *lp == '#') {
debug2("%10u: comment or short line", count_in);
continue;
Expand Down Expand Up @@ -640,6 +700,9 @@ prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted)
BN_free(q);
BN_CTX_free(ctx);

if (checkpoint_file != NULL)
unlink(checkpoint_file);

logit("%.24s Found %u safe primes of %u candidates in %ld seconds",
ctime(&time_stop), count_out, count_possible,
(long) (time_stop - time_start));
Expand Down
13 changes: 11 additions & 2 deletions ssh/ssh-keygen.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keygen.1,v 1.107 2011/09/07 02:18:31 deraadt Exp $
.\" $OpenBSD: ssh-keygen.1,v 1.108 2011/10/16 11:02:46 dtucker Exp $
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Expand Down Expand Up @@ -35,7 +35,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: September 7 2011 $
.Dd $Mdocdate: October 16 2011 $
.Dt SSH-KEYGEN 1
.Os
.Sh NAME
Expand Down Expand Up @@ -104,6 +104,7 @@
.Fl f Ar input_file
.Op Fl v
.Op Fl a Ar num_trials
.Op Fl K Ar checkpt
.Op Fl W Ar generator
.Nm ssh-keygen
.Fl s Ar ca_key
Expand Down Expand Up @@ -296,6 +297,14 @@ in the format specified by the
.Fl m
option and print an OpenSSH compatible private
(or public) key to stdout.
.It Fl K Ar checkpt
Write the last line processed to the file
.Ar checkpt
while performing DH candidate screening using the
.Fl T
option.
This will be used to skip lines in the input file that have already been
processed if the job is restarted.
This option allows importing keys from other software, including several
commercial SSH implementations.
The default import format is
Expand Down
16 changes: 12 additions & 4 deletions ssh/ssh-keygen.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.210 2011/04/18 00:46:05 djm Exp $ */
/* $OpenBSD: ssh-keygen.c,v 1.211 2011/10/16 11:02:46 dtucker Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Expand Down Expand Up @@ -149,7 +149,7 @@ char hostname[MAXHOSTNAMELEN];

/* moduli.c */
int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
int prime_test(FILE *, FILE *, u_int32_t, u_int32_t);
int prime_test(FILE *, FILE *, u_int32_t, u_int32_t, char *);

static void
type_bits_valid(int type, u_int32_t *bitsp)
Expand Down Expand Up @@ -1868,6 +1868,7 @@ usage(void)
fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n");
fprintf(stderr, " -g Use generic DNS resource record format.\n");
fprintf(stderr, " -H Hash names in known_hosts file.\n");
fprintf(stderr, " -K checkpt Write checkpoints to this file.\n");
fprintf(stderr, " -h Generate host certificate instead of a user certificate.\n");
fprintf(stderr, " -I key_id Key identifier to include in certificate.\n");
fprintf(stderr, " -i Import foreign format to OpenSSH key file.\n");
Expand Down Expand Up @@ -1903,6 +1904,7 @@ int
main(int argc, char **argv)
{
char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
char *checkpoint = NULL;
char out_file[MAXPATHLEN], *rr_hostname = NULL;
Key *private, *public;
struct passwd *pw;
Expand Down Expand Up @@ -1935,7 +1937,7 @@ main(int argc, char **argv)
exit(1);
}

while ((opt = getopt(argc, argv, "AegiqpclBHLhvxXyF:b:f:t:D:I:P:m:N:n:"
while ((opt = getopt(argc, argv, "AegiqpclBHLhvxXyF:b:f:t:D:I:K:P:m:N:n:"
"O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) {
switch (opt) {
case 'A':
Expand Down Expand Up @@ -2086,6 +2088,11 @@ main(int argc, char **argv)
sizeof(out_file))
fatal("Output filename too long");
break;
case 'K':
if (strlen(optarg) >= MAXPATHLEN)
fatal("Checkpoint filename too long");
checkpoint = xstrdup(optarg);
break;
case 'S':
/* XXX - also compare length against bits */
if (BN_hex2bn(&start, optarg) == 0)
Expand Down Expand Up @@ -2208,7 +2215,8 @@ main(int argc, char **argv)
fatal("Couldn't open moduli file \"%s\": %s",
out_file, strerror(errno));
}
if (prime_test(in, out, trials, generator_wanted) != 0)
if (prime_test(in, out, trials, generator_wanted, checkpoint)
!= 0)
fatal("modulus screening failed");
return (0);
}
Expand Down

0 comments on commit fddbcce

Please sign in to comment.