+ /*
+ * Now verify the validity of the key, and set up the auxiliary
+ * values for fast CRT signing.
+ */
+ valid=False;
+ 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)
+ goto done_checks;
+
+ /*
+ * Verify that d*e is congruent to 1 mod (p-1), and mod
+ * (q-1). This is equivalent to it being congruent to 1 mod
+ * lambda(n) = lcm(p-1,q-1). The usual `textbook' condition,
+ * that d e == 1 (mod (p-1)(q-1)) is sufficient, but not
+ * actually necessary.
+ */
+ mpz_mul(&tmp, &d, &e);
+ mpz_sub_ui(&tmp2, &st->p, 1);
+ mpz_mod(&tmp3, &tmp, &tmp2);
+ if (mpz_cmp_si(&tmp3, 1) != 0)
+ goto done_checks;
+ mpz_sub_ui(&tmp2, &st->q, 1);
+ mpz_mod(&tmp3, &tmp, &tmp2);
+ if (mpz_cmp_si(&tmp3, 1) != 0)
+ goto done_checks;
+
+ /* Verify that q*iqmp is congruent to 1 mod p. */
+ mpz_mul(&tmp, &st->q, &iqmp);
+ mpz_mod(&tmp2, &tmp, &st->p);
+ if (mpz_cmp_si(&tmp2, 1) != 0)
+ goto done_checks;
+ }
+ /* Now we know the key is valid (or we don't care). */
+ valid = True;
+
+ /*
+ * Now we compute auxiliary values dp, dq and w to allow us
+ * to use the CRT optimisation when signing.
+ *
+ * dp == d mod (p-1) so that a^dp == a^d mod p, for all a
+ * dq == d mod (q-1) similarly mod q
+ * w == iqmp * q so that w == 0 mod q, and w == 1 mod p
+ */
+ mpz_sub_ui(&tmp, &st->p, 1);
+ mpz_mod(&st->dp, &d, &tmp);
+ mpz_sub_ui(&tmp, &st->q, 1);
+ mpz_mod(&st->dq, &d, &tmp);
+ mpz_mul(&st->w, &iqmp, &st->q);
+
+done_checks:
+ if (!valid) {
+ LDFATAL("file does not contain a "
+ "valid RSA key!\n");
+ }
+
+assume_valid:
+out:
+ mpz_clear(&tmp);
+ mpz_clear(&tmp2);
+ mpz_clear(&tmp3);
+
+ FREE(b);
+ FREE(c);
+ mpz_clear(&e);
+ mpz_clear(&d);
+ mpz_clear(&iqmp);
+
+ return st;
+
+error_out:
+ if (st) rsapriv_dispose(st);
+ st=0;
+ goto out;
+}
+
+static bool_t postreadcheck_tryload(struct load_ctx *l, FILE *f)
+{
+ assert(!ferror(f));
+ if (feof(f)) { load_err(l,0,0,"eof mid-integer"); return False; }
+ return True;
+}
+
+bool_t rsa1_loadpriv(const struct sigscheme_info *algo,
+ struct buffer_if *privkeydata,
+ struct sigprivkey_if **sigpriv_r,
+ struct log_if *log, struct cloc loc)
+{
+ FILE *f=0;
+ struct rsapriv *st=0;
+
+ f=fmemopen(privkeydata->start,privkeydata->size,"r");
+ if (!f) {
+ slilog(log,M_ERR,"failed to fmemopen private key file\n");
+ goto error_out;
+ }
+
+ struct load_ctx l[1];
+ l->what="rsa1priv load";
+ l->verror=verror_tryload;
+ l->postreadcheck=postreadcheck_tryload;
+ l->loc=loc;
+ l->u.tryload.log=log;
+
+ st=rsa_loadpriv_core(l,f,loc,False);
+ if (!st) goto error_out;
+ goto out;
+
+ error_out:
+ FREE(st);
+ out:
+ if (f) fclose(f);
+ if (!st) return False;
+ *sigpriv_r=&st->ops;
+ return True;
+}
+
+static bool_t postreadcheck_apply(struct load_ctx *l, FILE *f)
+{
+ cfgfile_postreadcheck(l->loc,f);
+ return True;
+}
+
+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;
+ struct load_ctx l[1];
+
+ l->what="rsa-private";
+ l->verror=verror_cfgfatal;
+ l->postreadcheck=postreadcheck_apply;
+ l->loc=loc;
+
+ /* 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;