X-Git-Url: https://git.distorted.org.uk/~mdw/become/blobdiff_plain/b0f66028a9a17a845590a4fe737a4f5e46f6b778..f2b3b677e6a78b32a859cf02050d16ea6d7660f5:/src/check.c diff --git a/src/check.c b/src/check.c index ed561a7..2dddf32 100644 --- a/src/check.c +++ b/src/check.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: check.c,v 1.12 2003/11/29 23:39:16 mdw Exp $ + * $Id$ * * Check validity of requests * @@ -26,56 +26,6 @@ * 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 --- */ @@ -112,12 +62,13 @@ /* --- Catacomb headers --- */ #include -#include +#include #include +#include +#include #include #include #include -#include /* --- Local headers --- */ @@ -188,13 +139,11 @@ static int check__ask(request *rq, struct sockaddr_in *serv, size_t n_serv) 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; @@ -202,7 +151,7 @@ static int check__ask(request *rq, struct sockaddr_in *serv, size_t n_serv) 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; @@ -213,22 +162,18 @@ static int check__ask(request *rq, struct sockaddr_in *serv, size_t n_serv) 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 --- */ @@ -328,39 +273,93 @@ static int check__ask(request *rq, struct sockaddr_in *serv, size_t n_serv) 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"); ) } @@ -379,7 +378,7 @@ static int check__ask(request *rq, struct sockaddr_in *serv, size_t n_serv) * Use: Asks one or several servers whether a request is acceptable. */ -int check__client(request *rq, FILE *fp) +static int check__client(request *rq, FILE *fp) { /* --- Format of the file --- * *