chiark / gitweb /
rsa1: Break rsa_loadpriv_core out of rsapriv_apply
[secnet.git] / rsa.c
diff --git a/rsa.c b/rsa.c
index 1c37ef98acf3abec9e641267d532e720efa74f27..b19e898332fe18e3468636b85d385dcd4309fd8b 100644 (file)
--- a/rsa.c
+++ b/rsa.c
@@ -335,19 +335,30 @@ static uint16_t keyfile_get_short(struct cloc loc, FILE *f)
     return r;
 }
 
-static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
-                            list_t *args)
+#define LDFATAL(...)      cfgfatal(loc,__VA_ARGS__)
+#define LDUNSUP(...)      cfgfatal(loc,__VA_ARGS__)
+#define LDFATAL_FILE(...) cfgfatal_maybefile(f,loc,__VA_ARGS__)
+#define LDUNSUP_FILE(...) cfgfatal_maybefile(f,loc,__VA_ARGS__)
+#define FREE(b)           free(b)
+
+static struct rsapriv *rsa_loadpriv_core(FILE *f, struct cloc loc,
+                                        bool_t do_validity_check,
+                                        const char *filename)
 {
-    struct rsapriv *st;
-    FILE *f;
-    cstring_t filename;
-    item_t *i;
+    struct rsapriv *st=0;
     long length;
-    uint8_t *b, *c;
+    uint8_t *b=0, *c=0;
     int cipher_type;
     MP_INT e,d,iqmp,tmp,tmp2,tmp3;
     bool_t valid;
 
+    mpz_init(&e);
+    mpz_init(&d);
+    mpz_init(&iqmp);
+    mpz_init(&tmp);
+    mpz_init(&tmp2);
+    mpz_init(&tmp3);
+
     NEW(st);
     st->cl.description="rsapriv";
     st->cl.type=CL_SIGPRIVKEY;
@@ -360,82 +371,66 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
     st->ops.hash=0;
     st->ops.dispose=0; /* xxx */
     st->loc=loc;
+    mpz_init(&st->n);
+    mpz_init(&st->q);
+    mpz_init(&st->p);
+    mpz_init(&st->dp);
+    mpz_init(&st->dq);
+    mpz_init(&st->w);
 
-    /* Argument is filename pointing to SSH1 private key file */
-    i=list_elem(args,0);
-    if (i) {
-       if (i->type!=t_string) {
-           cfgfatal(i->loc,"rsa-private","first argument must be a string\n");
-       }
-       filename=i->data.string;
-    } else {
-       filename=NULL; /* Make compiler happy */
-       cfgfatal(loc,"rsa-private","you must provide a filename\n");
-    }
-
-    f=fopen(filename,"rb");
     if (!f) {
-       if (just_check_config) {
-           Message(M_WARNING,"rsa-private (%s:%d): cannot open keyfile "
-                   "\"%s\"; assuming it's valid while we check the "
-                   "rest of the configuration\n",loc.file,loc.line,filename);
-           goto assume_valid;
-       } else {
-           fatal_perror("rsa-private (%s:%d): cannot open file \"%s\"",
-                        loc.file,loc.line,filename);
-       }
+       assert(just_check_config);
+       goto assume_valid;
     }
 
     /* Check that the ID string is correct */
     length=strlen(AUTHFILE_ID_STRING)+1;
     b=safe_malloc(length,"rsapriv_apply");
     if (fread(b,length,1,f)!=1 || memcmp(b,AUTHFILE_ID_STRING,length)!=0) {
-       cfgfatal_maybefile(f,loc,"rsa-private","failed to read magic ID"
+       LDUNSUP_FILE("rsa-private","failed to read magic ID"
                           " string from SSH1 private keyfile \"%s\"\n",
                           filename);
     }
-    free(b);
+    FREE(b);
 
     cipher_type=fgetc(f);
     keyfile_get_int(loc,f); /* "Reserved data" */
     if (cipher_type != 0) {
-       cfgfatal(loc,"rsa-private","we don't support encrypted keyfiles\n");
+       LDUNSUP("rsa-private","we don't support encrypted keyfiles\n");
     }
 
     /* Read the public key */
     keyfile_get_int(loc,f); /* Not sure what this is */
     length=(keyfile_get_short(loc,f)+7)/8;
     if (length>RSA_MAX_MODBYTES) {
-       cfgfatal(loc,"rsa-private","implausible length %ld for modulus\n",
+       LDFATAL("rsa-private","implausible length %ld for modulus\n",
                 length);
     }
     b=safe_malloc(length,"rsapriv_apply");
     if (fread(b,length,1,f) != 1) {
-       cfgfatal_maybefile(f,loc,"rsa-private","error reading modulus\n");
+       LDFATAL_FILE("rsa-private","error reading modulus\n");
     }
-    mpz_init(&st->n);
     read_mpbin(&st->n,b,length);
-    free(b);
+    FREE(b);
     length=(keyfile_get_short(loc,f)+7)/8;
     if (length>RSA_MAX_MODBYTES) {
-       cfgfatal(loc,"rsa-private","implausible length %ld for e\n",length);
+       LDFATAL("rsa-private","implausible length %ld for e\n",length);
     }
     b=safe_malloc(length,"rsapriv_apply");
     if (fread(b,length,1,f)!=1) {
-       cfgfatal_maybefile(f,loc,"rsa-private","error reading e\n");
+       LDFATAL_FILE("rsa-private","error reading e\n");
     }
-    mpz_init(&e);
     read_mpbin(&e,b,length);
-    free(b);
+    FREE(b);
     
     length=keyfile_get_int(loc,f);
     if (length>1024) {
-       cfgfatal(loc,"rsa-private","implausibly long (%ld) key comment\n",
+       LDFATAL("rsa-private","implausibly long (%ld) key comment\n",
                 length);
     }
     c=safe_malloc(length+1,"rsapriv_apply");
     if (fread(c,length,1,f)!=1) {
-       cfgfatal_maybefile(f,loc,"rsa-private","error reading key comment\n");
+       LDFATAL_FILE("rsa-private","error reading key comment\n");
     }
     c[length]=0;
 
@@ -443,68 +438,64 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
        keyfile is not encrypted, so they should be */
 
     if (keyfile_get_short(loc,f) != keyfile_get_short(loc,f)) {
-       cfgfatal(loc,"rsa-private","corrupt keyfile\n");
+       LDFATAL("rsa-private","corrupt keyfile\n");
     }
 
     /* Read d */
     length=(keyfile_get_short(loc,f)+7)/8;
     if (length>RSA_MAX_MODBYTES) {
-       cfgfatal(loc,"rsa-private","implausibly long (%ld) decryption key\n",
+       LDFATAL("rsa-private","implausibly long (%ld) decryption key\n",
                 length);
     }
     b=safe_malloc(length,"rsapriv_apply");
     if (fread(b,length,1,f)!=1) {
-       cfgfatal_maybefile(f,loc,"rsa-private",
+       LDFATAL_FILE("rsa-private",
                           "error reading decryption key\n");
     }
-    mpz_init(&d);
     read_mpbin(&d,b,length);
-    free(b);
+    FREE(b);
     /* Read iqmp (inverse of q mod p) */
     length=(keyfile_get_short(loc,f)+7)/8;
     if (length>RSA_MAX_MODBYTES) {
-       cfgfatal(loc,"rsa-private","implausibly long (%ld)"
+       LDFATAL("rsa-private","implausibly long (%ld)"
                 " iqmp auxiliary value\n", length);
     }
     b=safe_malloc(length,"rsapriv_apply");
     if (fread(b,length,1,f)!=1) {
-       cfgfatal_maybefile(f,loc,"rsa-private",
+       LDFATAL_FILE("rsa-private",
                           "error reading decryption key\n");
     }
-    mpz_init(&iqmp);
     read_mpbin(&iqmp,b,length);
-    free(b);
+    FREE(b);
     /* Read q (the smaller of the two primes) */
     length=(keyfile_get_short(loc,f)+7)/8;
     if (length>RSA_MAX_MODBYTES) {
-       cfgfatal(loc,"rsa-private","implausibly long (%ld) q value\n",
+       LDFATAL("rsa-private","implausibly long (%ld) q value\n",
                 length);
     }
     b=safe_malloc(length,"rsapriv_apply");
     if (fread(b,length,1,f)!=1) {
-       cfgfatal_maybefile(f,loc,"rsa-private",
+       LDFATAL_FILE("rsa-private",
                           "error reading q value\n");
     }
-    mpz_init(&st->q);
     read_mpbin(&st->q,b,length);
-    free(b);
+    FREE(b);
     /* Read p (the larger of the two primes) */
     length=(keyfile_get_short(loc,f)+7)/8;
     if (length>RSA_MAX_MODBYTES) {
-       cfgfatal(loc,"rsa-private","implausibly long (%ld) p value\n",
+       LDFATAL("rsa-private","implausibly long (%ld) p value\n",
                 length);
     }
     b=safe_malloc(length,"rsapriv_apply");
     if (fread(b,length,1,f)!=1) {
-       cfgfatal_maybefile(f,loc,"rsa-private",
+       LDFATAL_FILE("rsa-private",
                           "error reading p value\n");
     }
-    mpz_init(&st->p);
     read_mpbin(&st->p,b,length);
-    free(b);
+    FREE(b);
     
-    if (fclose(f)!=0) {
-       fatal_perror("rsa-private (%s:%d): fclose",loc.file,loc.line);
+    if (ferror(f)) {
+       fatal_perror("rsa-private (%s:%d): ferror",loc.file,loc.line);
     }
 
     /*
@@ -512,14 +503,7 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
      * values for fast CRT signing.
      */
     valid=False;
-    i=list_elem(args,1);
-    mpz_init(&tmp);
-    mpz_init(&tmp2);
-    mpz_init(&tmp3);
-    if (i && i->type==t_bool && i->data.bool==False) {
-       Message(M_INFO,"rsa-private (%s:%d): skipping RSA key validity "
-               "check\n",loc.file,loc.line);
-    } else {
+    if (do_validity_check) {
        /* Verify that p*q is equal to n. */
        mpz_mul(&tmp, &st->p, &st->q);
        if (mpz_cmp(&tmp, &st->n) != 0)
@@ -559,9 +543,6 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
      *   dq == d mod (q-1)      similarly mod q
      *   w == iqmp * q          so that w == 0 mod q, and w == 1 mod p
      */
-    mpz_init(&st->dp);
-    mpz_init(&st->dq);
-    mpz_init(&st->w);
     mpz_sub_ui(&tmp, &st->p, 1);
     mpz_mod(&st->dp, &d, &tmp);
     mpz_sub_ui(&tmp, &st->q, 1);
@@ -570,19 +551,64 @@ static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
     
 done_checks:
     if (!valid) {
-       cfgfatal(loc,"rsa-private","file \"%s\" does not contain a "
+       LDFATAL("rsa-private","file \"%s\" does not contain a "
                 "valid RSA key!\n",filename);
     }
     mpz_clear(&tmp);
     mpz_clear(&tmp2);
     mpz_clear(&tmp3);
 
-    free(c);
+    FREE(c);
     mpz_clear(&e);
     mpz_clear(&d);
     mpz_clear(&iqmp);
 
 assume_valid:
+    return st;
+}
+
+static list_t *rsapriv_apply(closure_t *self, struct cloc loc, dict_t *context,
+                            list_t *args)
+{
+    struct rsapriv *st;
+    item_t *i;
+    cstring_t filename;
+    FILE *f;
+
+    /* Argument is filename pointing to SSH1 private key file */
+    i=list_elem(args,0);
+    if (i) {
+       if (i->type!=t_string) {
+           cfgfatal(i->loc,"rsa-private","first argument must be a string\n");
+       }
+       filename=i->data.string;
+    } else {
+       filename=NULL; /* Make compiler happy */
+       cfgfatal(i->loc,"rsa-private","you must provide a filename\n");
+    }
+
+    f=fopen(filename,"rb");
+    if (!f) {
+       if (just_check_config) {
+           Message(M_WARNING,"rsa-private (%s:%d): cannot open keyfile "
+                   "\"%s\"; assuming it's valid while we check the "
+                   "rest of the configuration\n",loc.file,loc.line,filename);
+       } else {
+           fatal_perror("rsa-private (%s:%d): cannot open file \"%s\"",
+                        loc.file,loc.line,filename);
+       }
+    }
+
+    bool_t do_validity_check=True;
+    i=list_elem(args,1);
+    if (i && i->type==t_bool && i->data.bool==False) {
+       Message(M_INFO,"rsa-private (%s:%d): skipping RSA key validity "
+               "check\n",loc.file,loc.line);
+       do_validity_check=False;
+    }
+
+    st=rsa_loadpriv_core(f,loc,do_validity_check,filename);
+    fclose(f);
     return new_closure(&st->cl);
 }