summaryrefslogtreecommitdiffstats
path: root/usr.sbin/xntpd/lib/authkeys.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/xntpd/lib/authkeys.c')
-rw-r--r--usr.sbin/xntpd/lib/authkeys.c602
1 files changed, 602 insertions, 0 deletions
diff --git a/usr.sbin/xntpd/lib/authkeys.c b/usr.sbin/xntpd/lib/authkeys.c
new file mode 100644
index 0000000..2d46eee
--- /dev/null
+++ b/usr.sbin/xntpd/lib/authkeys.c
@@ -0,0 +1,602 @@
+/* authkeys.c,v 3.1 1993/07/06 01:07:51 jbj Exp
+ * authkeys.c - routines to manage the storage of authentication keys
+ */
+#include <stdio.h>
+
+#include "ntp_types.h"
+#include "ntp_string.h"
+#include "ntp_malloc.h"
+#include "ntp_stdlib.h"
+
+/*
+ * Structure to store keys in in the hash table.
+ */
+struct savekey {
+ struct savekey *next;
+ union {
+#ifdef DES
+ U_LONG DES_key[2];
+#endif
+#ifdef MD5
+ char MD5_key[32];
+#endif
+ } k;
+ U_LONG keyid;
+ u_short flags;
+#ifdef MD5
+ int keylen;
+#endif
+};
+
+#define KEY_TRUSTED 0x1 /* this key is trusted */
+#define KEY_KNOWN 0x2 /* this key is known */
+
+#ifdef DES
+#define KEY_DES 0x100 /* this is a DES type key */
+#endif
+
+#ifdef MD5
+#define KEY_MD5 0x200 /* this is a MD5 type key */
+#endif
+
+/*
+ * The hash table. This is indexed by the low order bits of the
+ * keyid. We make this fairly big for potentially busy servers.
+ */
+#define HASHSIZE 64
+#define HASHMASK ((HASHSIZE)-1)
+#define KEYHASH(keyid) ((keyid) & HASHMASK)
+
+struct savekey *key_hash[HASHSIZE];
+
+U_LONG authkeynotfound;
+U_LONG authkeylookups;
+U_LONG authnumkeys;
+U_LONG authuncached;
+U_LONG authkeyuncached;
+U_LONG authnokey; /* calls to encrypt with no key */
+U_LONG authencryptions;
+U_LONG authdecryptions;
+U_LONG authdecryptok;
+
+/*
+ * Storage for free key structures. We malloc() such things but
+ * never free them.
+ */
+struct savekey *authfreekeys;
+int authnumfreekeys;
+
+#define MEMINC 12 /* number of new free ones to get at once */
+
+
+#ifdef DES
+/*
+ * Size of the key schedule
+ */
+#define KEY_SCHED_SIZE 128 /* number of octets to store key schedule */
+
+/*
+ * The zero key, which we always have. Store the permutted key
+ * zero in here.
+ */
+#define ZEROKEY_L 0x01010101 /* odd parity zero key */
+#define ZEROKEY_R 0x01010101 /* right half of same */
+u_char DESzeroekeys[KEY_SCHED_SIZE];
+u_char DESzerodkeys[KEY_SCHED_SIZE];
+u_char DEScache_ekeys[KEY_SCHED_SIZE];
+u_char DEScache_dkeys[KEY_SCHED_SIZE];
+#endif
+
+/*
+ * The key cache. We cache the last key we looked at here.
+ */
+U_LONG cache_keyid;
+u_short cache_flags;
+
+#ifdef MD5
+int cache_keylen;
+char *cache_key;
+#endif
+
+/*
+ * init_auth - initialize internal data
+ */
+void
+init_auth()
+{
+ U_LONG zerokey[2];
+
+ /*
+ * Initialize hash table and free list
+ */
+ bzero((char *)key_hash, sizeof key_hash);
+ cache_flags = cache_keyid = 0;
+
+ authnumfreekeys = authkeynotfound = authkeylookups = 0;
+ authnumkeys = authuncached = authkeyuncached = authnokey = 0;
+ authencryptions = authdecryptions = authdecryptok = 0;
+
+#ifdef DES
+ /*
+ * Initialize the zero key
+ */
+ zerokey[0] = ZEROKEY_L;
+ zerokey[1] = ZEROKEY_R;
+ /* could just zero all */
+ DESauth_subkeys(zerokey, DESzeroekeys, DESzerodkeys);
+#endif
+}
+
+
+/*
+ * auth_findkey - find a key in the hash table
+ */
+struct savekey *
+auth_findkey(keyno)
+ U_LONG keyno;
+{
+ register struct savekey *sk;
+
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid)
+ return sk;
+ sk = sk->next;
+ }
+ return 0;
+}
+
+
+/*
+ * auth_havekey - return whether a key is known
+ */
+int
+auth_havekey(keyno)
+ U_LONG keyno;
+{
+ register struct savekey *sk;
+
+ if (keyno == 0 || (keyno == cache_keyid))
+ return 1;
+
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid) {
+ if (sk->flags & KEY_KNOWN)
+ return 1;
+ else {
+ authkeynotfound++;
+ return 0;
+ }
+ }
+ sk = sk->next;
+ }
+ authkeynotfound++;
+ return 0;
+}
+
+
+/*
+ * authhavekey - return whether a key is known. Permute and cache
+ * the key as a side effect.
+ */
+int
+authhavekey(keyno)
+ U_LONG keyno;
+{
+ register struct savekey *sk;
+
+ authkeylookups++;
+ if (keyno == 0 || keyno == cache_keyid)
+ return 1;
+
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid)
+ break;
+ sk = sk->next;
+ }
+
+ if (sk == 0 || !(sk->flags & KEY_KNOWN)) {
+ authkeynotfound++;
+ return 0;
+ }
+
+ cache_keyid = sk->keyid;
+ cache_flags = sk->flags;
+#ifdef MD5
+ if (sk->flags & KEY_MD5) {
+ cache_keylen = sk->keylen;
+ cache_key = (char *) sk->k.MD5_key; /* XXX */
+ return 1;
+ }
+#endif
+
+#ifdef DES
+ if (sk->flags & KEY_DES) {
+ DESauth_subkeys(sk->k.DES_key, DEScache_ekeys, DEScache_dkeys);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+
+/*
+ * auth_moremem - get some more free key structures
+ */
+int
+auth_moremem()
+{
+ register struct savekey *sk;
+ register int i;
+
+ sk = (struct savekey *)malloc(MEMINC * sizeof(struct savekey));
+ if (sk == 0)
+ return 0;
+
+ for (i = MEMINC; i > 0; i--) {
+ sk->next = authfreekeys;
+ authfreekeys = sk++;
+ }
+ authnumfreekeys += MEMINC;
+ return authnumfreekeys;
+}
+
+
+/*
+ * authtrust - declare a key to be trusted/untrusted
+ */
+void
+authtrust(keyno, trust)
+ U_LONG keyno;
+ int trust;
+{
+ register struct savekey *sk;
+
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid)
+ break;
+ sk = sk->next;
+ }
+
+ if (sk == 0 && !trust)
+ return;
+
+ if (sk != 0) {
+ if (cache_keyid == keyno)
+ cache_flags = cache_keyid = 0;
+
+ if (trust) {
+ sk->flags |= KEY_TRUSTED;
+ return;
+ }
+
+ sk->flags &= ~KEY_TRUSTED;
+ if (!(sk->flags & KEY_KNOWN)) {
+ register struct savekey *skp;
+
+ skp = key_hash[KEYHASH(keyno)];
+ if (skp == sk) {
+ key_hash[KEYHASH(keyno)] = sk->next;
+ } else {
+ while (skp->next != sk)
+ skp = skp->next;
+ skp->next = sk->next;
+ }
+ authnumkeys--;
+
+ sk->next = authfreekeys;
+ authfreekeys = sk;
+ authnumfreekeys++;
+ }
+ return;
+ }
+
+ if (authnumfreekeys == 0)
+ if (auth_moremem() == 0)
+ return;
+
+ sk = authfreekeys;
+ authfreekeys = sk->next;
+ authnumfreekeys--;
+
+ sk->keyid = keyno;
+ sk->flags = KEY_TRUSTED;
+ sk->next = key_hash[KEYHASH(keyno)];
+ key_hash[KEYHASH(keyno)] = sk;
+ authnumkeys++;
+ return;
+}
+
+
+/*
+ * authistrusted - determine whether a key is trusted
+ */
+int
+authistrusted(keyno)
+ U_LONG keyno;
+{
+ register struct savekey *sk;
+
+ if (keyno == cache_keyid)
+ return ((cache_flags & KEY_TRUSTED) != 0);
+
+ authkeyuncached++;
+
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid)
+ break;
+ sk = sk->next;
+ }
+
+ if (sk == 0 || !(sk->flags & KEY_TRUSTED))
+ return 0;
+ return 1;
+}
+
+
+
+#ifdef DES
+/*
+ * DESauth_setkey - set a key into the key array
+ */
+void
+DESauth_setkey(keyno, key)
+ U_LONG keyno;
+ const U_LONG *key;
+{
+ register struct savekey *sk;
+
+ /*
+ * See if we already have the key. If so just stick in the
+ * new value.
+ */
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid) {
+ sk->k.DES_key[0] = key[0];
+ sk->k.DES_key[1] = key[1];
+ sk->flags |= KEY_KNOWN | KEY_DES;
+ if (cache_keyid == keyno)
+ cache_flags = cache_keyid = 0;
+ return;
+ }
+ sk = sk->next;
+ }
+
+ /*
+ * Need to allocate new structure. Do it.
+ */
+ if (authnumfreekeys == 0) {
+ if (auth_moremem() == 0)
+ return;
+ }
+
+ sk = authfreekeys;
+ authfreekeys = sk->next;
+ authnumfreekeys--;
+
+ sk->k.DES_key[0] = key[0];
+ sk->k.DES_key[1] = key[1];
+ sk->keyid = keyno;
+ sk->flags = KEY_KNOWN | KEY_DES;
+ sk->next = key_hash[KEYHASH(keyno)];
+ key_hash[KEYHASH(keyno)] = sk;
+ authnumkeys++;
+ return;
+}
+#endif
+
+#ifdef MD5
+void
+MD5auth_setkey(keyno, key)
+ U_LONG keyno;
+ const U_LONG *key;
+{
+ register struct savekey *sk;
+
+ /*
+ * See if we already have the key. If so just stick in the
+ * new value.
+ */
+ sk = key_hash[KEYHASH(keyno)];
+ while (sk != 0) {
+ if (keyno == sk->keyid) {
+ strncpy(sk->k.MD5_key, (char *)key, sizeof(sk->k.MD5_key));
+ if ((sk->keylen = strlen((char *)key)) >
+ sizeof(sk->k.MD5_key))
+ sk->keylen = sizeof(sk->k.MD5_key);
+
+ sk->flags |= KEY_KNOWN | KEY_MD5;
+ if (cache_keyid == keyno)
+ cache_flags = cache_keyid = 0;
+ return;
+ }
+ sk = sk->next;
+ }
+
+ /*
+ * Need to allocate new structure. Do it.
+ */
+ if (authnumfreekeys == 0) {
+ if (auth_moremem() == 0)
+ return;
+ }
+
+ sk = authfreekeys;
+ authfreekeys = sk->next;
+ authnumfreekeys--;
+
+ strncpy(sk->k.MD5_key, (char *)key, sizeof(sk->k.MD5_key));
+ if ((sk->keylen = strlen((char *)key)) > sizeof(sk->k.MD5_key))
+ sk->keylen = sizeof(sk->k.MD5_key);
+
+ sk->keyid = keyno;
+ sk->flags = KEY_KNOWN | KEY_MD5;
+ sk->next = key_hash[KEYHASH(keyno)];
+ key_hash[KEYHASH(keyno)] = sk;
+ authnumkeys++;
+ return;
+}
+#endif
+
+/*
+ * auth_delkeys - delete all known keys, in preparation for rereading
+ * the keys file (presumably)
+ */
+void
+auth_delkeys()
+{
+ register struct savekey *sk;
+ register struct savekey **skp;
+ register int i;
+
+ for (i = 0; i < HASHSIZE; i++) {
+ skp = &(key_hash[i]);
+ sk = key_hash[i];
+ while (sk != 0) {
+ sk->flags &= ~(KEY_KNOWN
+#ifdef MD5
+ | KEY_MD5
+#endif
+#ifdef DES
+ | KEY_DES
+#endif
+ );
+ if (sk->flags == 0) {
+ *skp = sk->next;
+ authnumkeys--;
+ sk->next = authfreekeys;
+ authfreekeys = sk;
+ authnumfreekeys++;
+ sk = *skp;
+ } else {
+ skp = &(sk->next);
+ sk = sk->next;
+ }
+ }
+ }
+}
+
+
+/*
+ * auth1crypt - support for two stage encryption, part 1.
+ */
+void
+auth1crypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* length of all encrypted data */
+{
+ if (keyno && keyno != cache_keyid) {
+ authkeyuncached++;
+ if (!authhavekey(keyno)) {
+ authnokey++;
+ return;
+ }
+ }
+
+#ifdef DES
+ if (!keyno || (cache_flags & KEY_DES)) {
+ DESauth1crypt(keyno, pkt, length);
+ return;
+ }
+#endif
+
+#ifdef MD5
+ if (cache_flags & KEY_MD5) {
+ MD5auth1crypt(keyno, pkt, length);
+ return;
+ }
+#endif
+}
+
+
+/*
+ * auth1crypt - support for two stage encryption, part 1.
+ */
+int
+auth2crypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* total length of encrypted area */
+{
+ if (keyno && keyno != cache_keyid) {
+ authkeyuncached++;
+ if (!authhavekey(keyno)) {
+ authnokey++;
+ return 0;
+ }
+ }
+
+#ifdef DES
+ if (!keyno || (cache_flags & KEY_DES))
+ return DESauth2crypt(keyno, pkt, length);
+#endif
+
+#ifdef MD5
+ if (cache_flags & KEY_MD5)
+ return MD5auth2crypt(keyno, pkt, length);
+#endif
+
+ return 0;
+}
+
+int
+authencrypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* length of encrypted portion of packet */
+{
+ int sendlength = 0;
+
+ if (keyno && keyno != cache_keyid) {
+ authkeyuncached++;
+ if (!authhavekey(keyno)) {
+ authnokey++;
+ return 0;
+ }
+ }
+
+#ifdef DES
+ if (!keyno || (cache_flags & KEY_DES))
+ return sendlength = DESauthencrypt(keyno, pkt, length);
+#endif
+
+#ifdef MD5
+ if (cache_flags & KEY_MD5)
+ return MD5authencrypt(keyno, pkt, length);
+#endif
+ return 0;
+}
+
+
+int
+authdecrypt(keyno, pkt, length)
+ U_LONG keyno;
+ U_LONG *pkt;
+ int length; /* length of variable data in octets */
+{
+ if (keyno && (keyno != cache_keyid)) {
+ authkeyuncached++;
+ if (!authhavekey(keyno)) {
+ authnokey++;
+ return 0;
+ }
+ }
+
+#ifdef DES
+ if (!keyno || (cache_flags & KEY_DES))
+ return DESauthdecrypt(keyno, pkt, length);
+#endif
+
+#ifdef MD5
+ if (cache_flags & KEY_MD5)
+ return MD5authdecrypt(keyno, pkt, length);
+#endif
+
+ return 0;
+}
OpenPOWER on IntegriCloud