/* -*-c-*-
*
- * $Id: daemon.c,v 1.16 2003/11/29 23:39:16 mdw Exp $
+ * $Id$
*
* Running a `become' daemon
*
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/*----- Revision history --------------------------------------------------*
- *
- * $Log: daemon.c,v $
- * Revision 1.16 2003/11/29 23:39:16 mdw
- * Debianization.
- *
- * Revision 1.15 2003/10/26 11:57:46 mdw
- * Fix key reloading core dumps. Change advice on keys.
- *
- * Revision 1.14 2003/10/17 16:30:22 mdw
- * Reload keys and config files automatically.
- *
- * Revision 1.13 2003/10/12 10:00:06 mdw
- * Fix for daemon mode. Oops.
- *
- * Revision 1.12 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.11 1999/05/04 16:17:12 mdw
- * Change to header file name for parser. See log for `parse.h' for
- * details.
- *
- * Revision 1.10 1998/04/23 13:23:09 mdw
- * Support new interface to configuration file parser.
- *
- * Revision 1.9 1998/01/12 16:45:59 mdw
- * Fix copyright date.
- *
- * Revision 1.8 1997/09/26 09:14:58 mdw
- * Merged blowfish branch into trunk.
- *
- * Revision 1.7.2.1 1997/09/26 09:08:05 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.7 1997/09/17 10:23:23 mdw
- * Fix a typo. Port numbers are in network order now, so don't change them.
- *
- * Revision 1.6 1997/09/09 18:17:06 mdw
- * Allow default port to be given as a service name or port number.
- *
- * Revision 1.5 1997/08/20 16:17:10 mdw
- * More sensible restart routine: `_reinit' functions replaced by `_end' and
- * `_init' functions.
- *
- * Revision 1.4 1997/08/07 10:00:37 mdw
- * (Log entry for previous version is bogus.) Read netgroups database.
- * Give up privileges permanently on startup.
- *
- * Revision 1.2 1997/08/04 10:24:21 mdw
- * Sources placed under CVS control.
- *
- * Revision 1.1 1997/07/21 13:47:50 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/paranoia.h>
#include <catacomb/rand.h>
-#include <catacomb/sha.h>
/* --- Local headers --- */
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 ---------------------------------------------------------*/
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@ --- *
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 */
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))
/* --- 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 --- */
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 --- */
rule_end();
netg_end();
userdb_end();
- dsa_privfree(&daemon__key);
userdb_init();
userdb_local();
userdb_yp();