/* -*-c-*-
*
- * $Id: check.c,v 1.12 2003/11/29 23:39:16 mdw Exp $
+ * $Id: check.c,v 1.14 2004/04/17 10:46:08 mdw Exp $
*
* Check validity of requests
*
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/*----- Revision history --------------------------------------------------*
- *
- * $Log: check.c,v $
- * Revision 1.12 2003/11/29 23:39:16 mdw
- * Debianization.
- *
- * Revision 1.11 2003/10/12 00:14:55 mdw
- * Major overhaul. Now uses DSA signatures rather than the bogus symmetric
- * encrypt-and-hope thing. Integrated with mLib and Catacomb.
- *
- * Revision 1.10 1999/05/04 16:17:12 mdw
- * Change to header file name for parser. See log for `parse.h' for
- * details.
- *
- * Revision 1.9 1998/06/19 13:48:16 mdw
- * Set close-on-exec flag for UDP socket.
- *
- * Revision 1.8 1998/06/18 15:10:44 mdw
- * SECURITY HOLE: the file descriptor for the secret key was left open and
- * inherited by the target process. This is now fixed. Also set
- * close-on-exec flags on key file, close config file carefully, and close
- * UDP socket after receiving reply from server.
- *
- * Revision 1.7 1998/04/23 13:22:08 mdw
- * Support no-network configuration option, and new interface to
- * configuration file parser.
- *
- * Revision 1.6 1998/01/12 16:45:47 mdw
- * Fix copyright date.
- *
- * Revision 1.5 1997/09/26 09:14:58 mdw
- * Merged blowfish branch into trunk.
- *
- * Revision 1.4.2.1 1997/09/26 09:08:01 mdw
- * Use the Blowfish encryption algorithm instead of IDEA. This is partly
- * because I prefer Blowfish (without any particularly strong evidence) but
- * mainly because IDEA is patented and Blowfish isn't.
- *
- * Revision 1.4 1997/08/07 09:52:05 mdw
- * (Log entry for previous version is bogus.) Added support for multiple
- * servers.
- *
- * Revision 1.2 1997/08/04 10:24:20 mdw
- * Sources placed under CVS control.
- *
- * Revision 1.1 1997/07/21 13:47:53 mdw
- * Initial revision
- *
- */
-
/*----- Header files ------------------------------------------------------*/
/* --- ANSI headers --- */
/* --- Catacomb headers --- */
#include <catacomb/buf.h>
-#include <catacomb/dsa.h>
+#include <catacomb/gdsa.h>
#include <catacomb/key.h>
+#include <catacomb/dh.h>
+#include <catacomb/ec-keys.h>
#include <catacomb/mp.h>
#include <catacomb/noise.h>
#include <catacomb/rand.h>
-#include <catacomb/sha.h>
/* --- Local headers --- */
char buff[2048], rbuff[2048];
size_t rqlen;
- octet hmsg[SHA_HASHSZ];
- octet h[SHA_HASHSZ];
- key_packstruct kps[DSA_PUBFETCHSZ];
+ gdsa g;
+ const char *p;
+ ghash *h;
key_packdef *kp;
- dsa_pub kpub;
buf b;
- sha_ctx hc;
int fd;
struct sockaddr_in sin;
socklen_t slen;
int ans;
fd_set fds;
struct timeval start, now, tv;
- mp *m, *r, *s;
+ gdsa_sig s;
key_file f;
key *k;
key_iter ki;
if ((key_open(&f, file_PUBKEY, KOPEN_READ, key_moan, 0)) != 0)
die(1, "couldn't open public keyring");
- kp = key_fetchinit(dsa_pubfetch, kps, &kpub);
/* --- Build the request packet --- */
rand_noisesrc(RAND_GLOBAL, &noise_source);
rand_seed(RAND_GLOBAL, 160);
buf_init(&b, buff, sizeof(buff));
- rand_get(RAND_GLOBAL, buf_get(&b, SHA_HASHSZ), SHA_HASHSZ);
+ rand_get(RAND_GLOBAL, buf_get(&b, 64), 64);
buf_putu32(&b, rq->from);
buf_putu32(&b, rq->to);
buf_putu16(&b, strlen(rq->cmd));
buf_put(&b, rq->cmd, strlen(rq->cmd));
rqlen = BLEN(&b);
- sha_init(&hc);
- sha_hash(&hc, buff, rqlen);
- sha_done(&hc, hmsg);
/* --- Create my socket --- */
continue;
}
- /* --- Unpack and verify the response --- */
-
- buf_init(&b, rbuff, sz);
- if (buf_ensure(&b, sizeof(hmsg))) goto bad;
- if (memcmp(BCUR(&b), hmsg, sizeof(hmsg)) != 0) goto bad;
- BSTEP(&b, sizeof(hmsg));
- if ((ans = buf_getbyte(&b)) < 0) goto bad;
-
- sha_init(&hc);
- sha_hash(&hc, BBASE(&b), BLEN(&b));
- sha_done(&hc, h);
- if ((r = buf_getmp(&b)) == 0 || (s = buf_getmp(&b)) == 0) goto bad;
- m = mp_loadb(MP_NEW, h, sizeof(h));
+ /* --- The hash length varies with the key --- *
+ *
+ * So we have to unpack once for each key. This isn't too bad.
+ */
+ g.r = &rand_global;
+ g.u = 0;
key_mkiter(&ki, &f);
while ((k = key_next(&ki)) != 0) {
if (key_expired(k)) continue;
- if (strcmp(k->type, "become-dsa") != 0) continue;
- if (key_fetch(kp, k)) continue;
- i = dsa_vrfy(&kpub.dp, kpub.y, m, r, s);
- dsa_pubfree(&kpub);
- if (i) {
- key_fetchdone(kp);
- key_close(&f);
- close(fd);
- mp_drop(m);
- mp_drop(r);
- mp_drop(s);
- return (ans);
- }
+ if (strcmp(k->type, "become") != 0) continue;
+
+ /* --- Get a hash function --- */
+
+ if ((p = key_getattr(&f, k, "hash")) == 0)
+ p = "sha";
+ if ((g.h = ghash_byname(p)) == 0)
+ continue;
+
+ /* --- Unpack the key --- */
+
+ p = key_getattr(&f, k, "sig");
+ if (!p || strcmp(p, "dsa") == 0) {
+ dh_pub dp;
+ kp = key_fetchinit(dh_pubfetch, 0, &dp);
+ if (key_fetch(kp, k)) goto fail_1;
+ if ((g.g = group_prime(&dp.dp)) == 0) goto fail_1;
+ g.p = G_CREATE(g.g);
+ if (G_FROMINT(g.g, g.p, dp.y)) goto fail_2;
+ } else if (strcmp(p, "ecdsa") == 0) {
+ ec_pub ep;
+ ec_info ei;
+ kp = key_fetchinit(ec_pubfetch, 0, &ep);
+ if (key_fetch(kp, k)) goto fail_1;
+ if (ec_getinfo(&ei, ep.cstr)) goto fail_1;
+ g.g = group_ec(&ei);
+ g.p = G_CREATE(g.g);
+ if (G_FROMEC(g.g, g.p, &ep.p)) goto fail_2;
+ } else
+ goto fail_0;
+
+ /* --- Unpack the response --- */
+
+ h = GH_INIT(g.h);
+ GH_HASH(h, buff, rqlen);
+ buf_init(&b, rbuff, sz);
+ if (buf_ensure(&b, g.h->hashsz)) goto fail_3;
+ if (memcmp(BCUR(&b), GH_DONE(h, 0), g.h->hashsz) != 0) goto fail_3;
+ BSTEP(&b, g.h->hashsz);
+ if ((ans = buf_getbyte(&b)) < 0) goto fail_3;
+ GH_DESTROY(h);
+
+ /* --- Verify the signature --- */
+
+ h = gdsa_beginhash(&g);
+ GH_HASH(h, BBASE(&b), BLEN(&b));
+ gdsa_endhash(&g, h);
+ s.r = s.s = 0;
+ if ((s.r = buf_getmp(&b)) == 0 ||
+ (s.s = buf_getmp(&b)) == 0)
+ goto fail_4;
+ if (gdsa_verify(&g, &s, GH_DONE(h, 0)))
+ goto fail_4;
+
+ mp_drop(s.r); mp_drop(s.s);
+ GH_DESTROY(h);
+ G_DESTROY(g.g, g.p);
+ G_DESTROYGROUP(g.g);
+ key_fetchdone(kp);
+ key_close(&f);
+ return (ans);
+
+ /* --- Tidy up and try again --- */
+
+ fail_4:
+ mp_drop(s.r); mp_drop(s.s);
+ fail_3:
+ GH_DESTROY(h);
+ G_DESTROY(g.g, g.p);
+ fail_2:
+ G_DESTROYGROUP(g.g);
+ fail_1:
+ key_fetchdone(kp);
+ fail_0:
+ continue;
}
- bad:
T( trace(TRACE_CLIENT,
"client: invalid or corrupt reply packet"); )
}