From: mdw Date: Sat, 17 Apr 2004 10:46:08 +0000 (+0000) Subject: Support elliptic curves, and bigger hashes. X-Git-Url: https://git.distorted.org.uk/~mdw/become/commitdiff_plain/1554751791fdc733a5f106915f684a31e419797b Support elliptic curves, and bigger hashes. --- diff --git a/configure.in b/configure.in index c5767f8..d673178 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl -*-m4-*- dnl -dnl $Id: configure.in,v 1.21 2004/04/08 01:36:20 mdw Exp $ +dnl $Id: configure.in,v 1.22 2004/04/17 10:46:08 mdw Exp $ dnl dnl Source for auto configuration for `become' dnl @@ -94,7 +94,7 @@ mdw_OPT_TRACE dnl --- Libraries --- mdw_MLIB(2.0.1) -mdw_CATACOMB(2.0.1) +mdw_CATACOMB(2.1.0) mdw_CHECK_MANYLIBS(socket, socket,, [AC_MSG_ERROR([Socket library not found])]) diff --git a/src/check.c b/src/check.c index c899196..f6560d5 100644 --- a/src/check.c +++ b/src/check.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: check.c,v 1.13 2004/04/08 01:36:20 mdw Exp $ + * $Id: check.c,v 1.14 2004/04/17 10:46:08 mdw Exp $ * * Check validity of requests * @@ -62,12 +62,13 @@ /* --- Catacomb headers --- */ #include -#include +#include #include +#include +#include #include #include #include -#include /* --- Local headers --- */ @@ -138,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; @@ -152,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; @@ -163,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 --- */ @@ -278,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"); ) } diff --git a/src/daemon.c b/src/daemon.c index a91a8a5..3320512 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: daemon.c,v 1.17 2004/04/08 01:36:20 mdw Exp $ + * $Id: daemon.c,v 1.18 2004/04/17 10:46:08 mdw Exp $ * * Running a `become' daemon * @@ -63,8 +63,10 @@ /* --- Catacomb headers --- */ #include -#include +#include #include +#include +#include #include #include #include @@ -96,7 +98,7 @@ static sel_state daemon__sel; /* Select context */ static sel_file daemon__listen; /* Listening socket selector */ static const char *daemon__config; /* Configuration file for daemon */ static const char *daemon__keyfile; /* Keyring file for daemon */ -static dsa_priv daemon__key; /* The key data */ +static gdsa daemon__key; /* The key data */ /*----- Main code ---------------------------------------------------------*/ @@ -144,34 +146,95 @@ static void daemon__moan(const char *f, int line, const char *msg, void *p) void daemon_readKey(const char *kf) { - key_packstruct kps[DSA_PRIVFETCHSZ]; key_packdef *kp; key_file f; key *k; int err; + const char *sn; + const char *hn; + const char *errmsg; + gdsa g; if (daemon__keyfile) return; T( trace(TRACE_DAEMON, "daemon: reading key from `%s'", kf); ) if (key_open(&f, kf, KOPEN_READ, daemon__moan, 0)) - return; - kp = key_fetchinit(dsa_privfetch, kps, &daemon__key); - if ((k = key_bytype(&f, "become-dsa")) == 0) - err = KERR_NOTFOUND; - else - err = key_fetch(kp, k); - if (err) - syslog(LOG_ERR, "couldn't load key: %s", key_strerror(err)); - else { - mp_copy(daemon__key.dp.p); - mp_copy(daemon__key.dp.q); - mp_copy(daemon__key.dp.g); - mp_copy(daemon__key.x); - mp_copy(daemon__key.y); - daemon__keyfile = kf; + goto fail_0; + if ((k = key_bytype(&f, "become")) == 0) { + syslog(LOG_ERR, "no key of type `become' found"); + goto fail_1; + } + if ((hn = key_getattr(&f, k, "hash")) == 0) + hn = "sha"; + sn = key_getattr(&f, k, "sig"); + g.r = &rand_global; + if ((g.h = ghash_byname(hn)) == 0) { + syslog(LOG_ERR, "key uses unknown hash algorithm `%s'", hn); + goto fail_1; + } + if (!sn || strcmp(sn, "dsa") == 0) { + dh_priv dp; + kp = key_fetchinit(dh_privfetch, 0, &dp); + if ((err = key_fetch(kp, k)) != 0) { + syslog(LOG_ERR, "error loading key: %s", key_strerror(err)); + goto fail_2; + } + if ((g.g = group_prime(&dp.dp)) == 0) { + syslog(LOG_ERR, "bad prime group in key"); + goto fail_3; + } + g.p = G_CREATE(g.g); + if (G_FROMINT(g.g, g.p, dp.y)) { + syslog(LOG_ERR, "bad public key"); + goto fail_4; + } + g.u = mp_copy(dp.x); + } else if (strcmp(sn, "ecdsa") == 0) { + ec_priv ep; + ec_info ei; + kp = key_fetchinit(ec_privfetch, 0, &ep); + if ((err = key_fetch(kp, k)) != 0) { + syslog(LOG_ERR, "error loading key: %s", key_strerror(err)); + goto fail_2; + } + if ((errmsg = ec_getinfo(&ei, ep.cstr)) != 0) { + syslog(LOG_ERR, "bad curve in key: %s", errmsg); + goto fail_3; + } + g.g = group_ec(&ei); + g.p = G_CREATE(g.g); + if (G_FROMEC(g.g, g.p, &ep.p)) { + syslog(LOG_ERR, "bad public point"); + goto fail_4; + } + g.u = mp_copy(ep.x); + } else { + syslog(LOG_ERR, "key uses unknown signature scheme `%s'", sn); + goto fail_1; } key_fetchdone(kp); + daemon__keyfile = kf; key_close(&f); + if (daemon__key.g) { + mp_drop(daemon__key.u); + G_DESTROY(daemon__key.g, daemon__key.p); + G_DESTROYGROUP(daemon__key.g); + } + daemon__key = g; + T( trace(TRACE_DAEMON, "daemon: key read ok"); ) + return; + +fail_4: + G_DESTROY(g.g, g.p); +fail_3: + G_DESTROYGROUP(g.g); +fail_2: + key_fetchdone(kp); +fail_1: + key_close(&f); +fail_0: + T( trace(TRACE_DAEMON, "daemon: failed to read key"); ) + return; } /* --- @daemon__readConfig@ --- * @@ -215,15 +278,14 @@ void daemon__read(int fd, unsigned mode, void *p) unsigned char buff[65536]; /* Buffer for incoming packets */ struct sockaddr_in sin; /* Address of packet sender */ char sender[64]; /* Sender's hostname (resolved) */ - octet h[SHA_HASHSZ]; /* Hash of the transmission buffer */ - sha_ctx hc; /* Hashing context */ + ghash *h; /* Hash context */ request rq; /* Request buffer for verification */ ssize_t sz; /* Length of incoming message */ socklen_t slen; /* Length of incoming address */ uint32 u; /* Scratch integer */ uint16 ul; /* And another */ struct hostent *he; /* Resolve structure */ - mp *m, *k, *r, *s; /* Integers for signing */ + gdsa_sig s = GDSA_SIG_INIT; /* Signature block */ int ans; /* Answer from the check */ buf b; /* Buffer for parsing request */ @@ -263,7 +325,7 @@ void daemon__read(int fd, unsigned mode, void *p) rq.host = sin.sin_addr; buf_init(&b, buff, sz); - if (buf_ensure(&b, SHA_HASHSZ)) goto fail; BSTEP(&b, SHA_HASHSZ); + if (buf_ensure(&b, 64)) goto fail; BSTEP(&b, 64); if (buf_getu32(&b, &u)) goto fail; rq.from = u; if (buf_getu32(&b, &u)) goto fail; rq.to = u; if (buf_getu16(&b, &ul) || buf_ensure(&b, ul) || ul >= sizeof(rq.cmd)) @@ -275,9 +337,8 @@ void daemon__read(int fd, unsigned mode, void *p) /* --- Hash the request block --- */ - sha_init(&hc); - sha_hash(&hc, buff, sz); - sha_done(&hc, h); + h = GH_INIT(daemon__key.h); + GH_HASH(h, buff, sz); /* --- Build a reply block --- */ @@ -285,27 +346,20 @@ void daemon__read(int fd, unsigned mode, void *p) syslog(LOG_INFO, "request from %s for %i to become %i to run %s %s", sender, rq.from, rq.to, rq.cmd, ans ? "granted" : "denied"); buf_init(&b, buff, sizeof(buff)); - if (buf_put(&b, h, sizeof(h)) || buf_putbyte(&b, ans)) - goto fail; + buf_put(&b, GH_DONE(h, 0), GH_CLASS(h)->hashsz); + buf_putbyte(&b, ans); + if (BBAD(&b)) goto fail; /* --- Sign the reply block --- */ - sha_init(&hc); - sha_hash(&hc, BBASE(&b), BLEN(&b)); - sha_done(&hc, h); - m = mp_loadb(MP_NEW, h, sizeof(h)); - rand_get(RAND_GLOBAL, h, sizeof(h)); - k = mp_loadb(MP_NEWSEC, h, sizeof(h)); - r = s = MP_NEW; - dsa_mksig(&daemon__key.dp, daemon__key.x, m, k, &r, &s); - buf_putmp(&b, r); - buf_putmp(&b, s); - mp_drop(m); - mp_drop(k); - mp_drop(r); - mp_drop(s); - if (BBAD(&b)) - goto fail; + h = gdsa_beginhash(&daemon__key); + GH_HASH(h, BBASE(&b), BLEN(&b)); + gdsa_endhash(&daemon__key, h); + gdsa_sign(&daemon__key, &s, GH_DONE(h, 0), 0); + GH_DESTROY(h); + buf_putmp(&b, s.r); buf_putmp(&b, s.s); + mp_drop(s.r); mp_drop(s.s); + if (BBAD(&b)) goto fail; /* --- Send the reply off --- */ @@ -373,7 +427,6 @@ static void daemon__rescan(int n, void *p) rule_end(); netg_end(); userdb_end(); - dsa_privfree(&daemon__key); userdb_init(); userdb_local(); userdb_yp();