i += ssh1_read_bignum(buf+i, &key->p);
if (len-i < 0) goto end;
- ret = 1;
+ if (!rsa_verify(key)) {
+ freersakey(key);
+ ret = 0;
+ } else
+ ret = 1;
+
end:
memset(buf, 0, sizeof(buf)); /* burn the evidence */
return ret;
*
* where the sequence-number increases from zero. As many of these
* hashes are used as necessary.
+ *
+ * NOTE! It is important that all _public_ data can be verified
+ * with reference to the _private_ data. There exist attacks based
+ * on modifying the public key but leaving the private section
+ * intact.
+ *
+ * With RSA, this is easy: verify that n = p*q, and also verify
+ * that e*d == 1 modulo (p-1)(q-1). With DSA (if we were ever to
+ * support it), we would need to store extra data in the private
+ * section other than just x.
*/
static int read_header(FILE *fp, char *header) {
ret->comment = comment;
ret->data = alg->createkey(public_blob, public_blob_len,
private_blob, private_blob_len);
+ if (!ret->data) {
+ sfree(ret->comment);
+ sfree(ret);
+ ret = NULL;
+ }
sfree(public_blob);
sfree(private_blob);
return ret;
}
}
+/*
+ * Verify that the public data in an RSA key matches the private
+ * data.
+ */
+int rsa_verify(struct RSAKey *key) {
+ Bignum n, ed, pm1, qm1, pm1qm1;
+ int cmp;
+
+ /* n must equal pq. */
+ n = bigmul(key->p, key->q);
+ cmp = bignum_cmp(n, key->modulus);
+ freebn(n);
+ if (cmp != 0)
+ return 0;
+
+ /* e * d must be congruent to 1, modulo (p-1)(q-1). */
+ pm1 = copybn(key->p);
+ decbn(pm1);
+ qm1 = copybn(key->q);
+ decbn(qm1);
+ pm1qm1 = bigmul(pm1, qm1);
+ freebn(pm1);
+ freebn(qm1);
+ ed = modmul(key->exponent, key->private_exponent, pm1qm1);
+ sfree(pm1qm1);
+ cmp = bignum_cmp(ed, One);
+ sfree(ed);
+ if (cmp != 0)
+ return 0;
+}
+
void freersakey(struct RSAKey *key) {
if (key->modulus) freebn(key->modulus);
if (key->exponent) freebn(key->exponent);
len = rsastr_len(rsa);
p = smalloc(len);
- rsastr_fmt(p, rsa);
+ rsastr_fmt(p, rsa);
return p;
}
rsa->q = getmp(&pb, &priv_len);
rsa->iqmp = getmp(&pb, &priv_len);
+ if (!rsa_verify(rsa)) {
+ rsa2_freekey(rsa);
+ return NULL;
+ }
+
return rsa;
}