Implement afsconf_GetRXGKKey 99/11099/17
authorBenjamin Kaduk <kaduk@mit.edu>
Wed, 26 Mar 2014 10:24:02 +0000 (06:24 -0400)
committerBenjamin Kaduk <kaduk@mit.edu>
Sun, 24 Mar 2019 09:49:40 +0000 (05:49 -0400)
Also afsconf_GetLatestRXGKKey, as a side effect, since we want to have
a single getkey function both for getting encrypting and decrypting keys;
a kvno/enctype pair of 0/0 indicates that the "get latest" behavior is
desired.

Implement both functions in terms of an internal helper that takes
as an argument the type of key to look for in the KeyFileExt.  We
can reuse these helpers wholesale for per-fileserver keys, later.

This also requires implementing an ordering on the quality of the
different RFC 3961 enctypes (which are stored as the subtype of keys
of type afsconf_rxgk). This is subject to debate on the actual
ordering, but since the IANA enctype registry changes rarely, just
assign a full ordering on the standardized (symmetric!) enctypes.
Implement this via a new function, rxgk_enctype_better, in
rxgk_crypto_rfc3961.c.

Introduce a new header file, rxgk_types.h, so we can avoid including
the entire rxgk.h header in cellconfig.p.h.

Change-Id: I81389b21238fd6588cc4381b026816005f81a30c
Reviewed-on: https://gerrit.openafs.org/11099
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>

src/auth/cellconfig.p.h
src/auth/keys.c
src/auth/liboafs_auth.la.sym
src/rxgk/Makefile.in
src/rxgk/liboafs_rxgk.la.sym
src/rxgk/rxgk.h
src/rxgk/rxgk_crypto_rfc3961.c
src/rxgk/rxgk_types.h [new file with mode: 0644]

index c9423c0..7fe21dd 100644 (file)
@@ -40,6 +40,8 @@ Creation date:
 #include <rx/rx_opaque.h>
 #include <opr/queue.h>
 
+#include <rx/rxgk_types.h>
+
 #define        MAXCELLCHARS    64
 #define        MAXHOSTCHARS    64
 #define MAXHOSTSPERCELL  8
@@ -138,8 +140,13 @@ struct ktc_encryptionKey;
 extern afs_int32 afsconf_GetLatestKey(struct afsconf_dir *adir,
                                      afs_int32 * avno,
                                      struct ktc_encryptionKey *akey);
+extern afs_int32 afsconf_GetLatestRXGKKey(struct afsconf_dir *adir,
+                                         afs_int32 *avno, afs_int32 *enctype,
+                                         rxgk_key *key);
 extern int afsconf_GetKey(void *rock, int avno,
                          struct ktc_encryptionKey *akey);
+extern int afsconf_GetRXGKKey(void *rock, afs_int32 *avno, afs_int32 *enctype,
+                             rxgk_key *key);
 extern int afsconf_AddKey(struct afsconf_dir *adir, afs_int32 akvno,
                          char akey[8], afs_int32 overwrite);
 extern int afsconf_DeleteKey(struct afsconf_dir *adir, afs_int32 akvno);
index b1959c7..59543e8 100644 (file)
 /* Need rx/rx.h to get working assert(), used by LOCK_GLOBAL_MUTEX */
 #include <rx/rx.h>
 #include <rx/rx_atomic.h>
+#ifdef AFS_RXGK_ENV
+#include <rx/rxgk.h>
+#endif
 
+#include <afs/opr.h>
 #include <afs/stds.h>
 #include <afs/pthread_glock.h>
 #include <afs/afsutil.h>
@@ -768,6 +772,117 @@ afsconf_GetKey(void *rock, int kvno, struct ktc_encryptionKey *key)
     return 0;
 }
 
+static int
+_afsconf_GetLatestRXGKKey(afsconf_keyType type, struct afsconf_dir *rock,
+                         afs_int32 *avno, afs_int32 *enctype, rxgk_key *key)
+{
+#ifdef AFS_RXGK_ENV
+    struct afsconf_typedKeyList *list = NULL;
+    struct afsconf_typedKey *typedKey = NULL;
+    afs_int32 code;
+    int key_i;
+
+    code = afsconf_GetLatestKeysByType(rock, type, &list);
+    if (code != 0)
+       goto done;
+
+    for (key_i = 0; key_i < list->nkeys; key_i++) {
+       if (typedKey == NULL)
+           typedKey = list->keys[key_i];
+       else if (rxgk_enctype_better(typedKey->subType, list->keys[key_i]->subType))
+           typedKey = list->keys[key_i];
+    }
+
+    opr_Assert(typedKey != NULL);
+
+    /* We picked a key; copy to the output parameters */
+    code = rxgk_make_key(key, typedKey->key.val, typedKey->key.len,
+                        typedKey->subType);
+    if (code != 0)
+       goto done;
+    if (avno != NULL)
+       *avno = typedKey->kvno;
+    if (enctype != NULL)
+       *enctype = typedKey->subType;
+
+ done:
+    afsconf_PutTypedKeyList(&list);
+    return code;
+#else  /* AFS_RXGK_ENV */
+    return AFSCONF_NOTFOUND;
+#endif
+}
+
+/**
+ * Obtain the "best" rxgk key from KeyFileExt
+ *
+ * Return the key and its enctype and kvno, for encrypting outgoing tokens.
+ *
+ * @param[in] rock     The configuration directory to be used.
+ * @param[out] avno    The key version number of key.
+ * @param[out] enctype The RFC 3961 enctype of key.
+ * @param[out] key     The returned rxgk key.
+ */
+int
+afsconf_GetLatestRXGKKey(struct afsconf_dir *rock, afs_int32 *avno,
+                        afs_int32 *enctype, rxgk_key *key)
+{
+    return _afsconf_GetLatestRXGKKey(afsconf_rxgk, rock, avno, enctype, key);
+}
+
+static int
+_afsconf_GetRXGKKey(afsconf_keyType type, void *rock, afs_int32 *avno,
+                   afs_int32 *enctype, rxgk_key *key)
+{
+#ifdef AFS_RXGK_ENV
+    struct afsconf_dir *dir = rock;
+    struct afsconf_typedKey *typedKey;
+    afs_int32 code;
+
+    /* No information at all means "pick the best/newest one". */
+    if (*avno == 0 && *enctype == 0)
+       return _afsconf_GetLatestRXGKKey(type, dir, avno, enctype, key);
+
+    code = afsconf_GetKeyByTypes(dir, type, *avno, *enctype, &typedKey);
+    if (code != 0)
+       return code;
+
+    code = rxgk_make_key(key, typedKey->key.val, typedKey->key.len,
+                        typedKey->subType);
+    afsconf_typedKey_put(&typedKey);
+
+    return code;
+#else  /* AFS_RXGK_ENV */
+    return AFSCONF_NOTFOUND;
+#endif
+}
+
+/**
+ * Obtain a particular RXGK key from KeyFileExt
+ *
+ * Use the specified kvno and enctype to fetch an rxgk key from KeyFileExt
+ * and return it as an rxgk_key.  Specifying the kvno/enctype pair as both
+ * zeros causes the "best" rxgk key to be returned, and the kvno/enctype
+ * of that key returned to the caller.
+ *
+ * @param[in] rock      An afsconf_dir* for the configuration directory. This
+ *                     is a void* just so this can be easily used as a
+ *                     callback function that uses a void* rock.
+ * @param[inout] avno  The requested kvno (if non-zero), or zero to request
+ *                     the latest key and have its kvno returned in this
+ *                     parameter.
+ * @param[inout] enctype       The requested enctype (if non-zero), or zero
+ *                             to request the latest key and have its
+ *                             enctype returned in this parameter.
+ * @param[out] key     The returned rxgk key.
+ */
+int
+afsconf_GetRXGKKey(void *rock, afs_int32 *avno,
+                  afs_int32 *enctype, rxgk_key *key)
+{
+    return _afsconf_GetRXGKKey(afsconf_rxgk, rock, avno, enctype, key);
+}
+
 int
 afsconf_AddKey(struct afsconf_dir *dir, afs_int32 kvno, char key[8],
               afs_int32 overwrite)
index 5497f99..fbf88d0 100644 (file)
@@ -15,8 +15,10 @@ afsconf_GetCellInfo
 afsconf_GetExtendedCellInfo
 afsconf_GetKey
 afsconf_GetLatestKey
+afsconf_GetLatestRXGKKey
 afsconf_GetLocalCell
 afsconf_GetNoAuthFlag
+afsconf_GetRXGKKey
 afsconf_IsLocalRealmMatch
 afsconf_Open
 afsconf_ParseNetFiles
index fa398b1..16da77d 100644 (file)
@@ -3,8 +3,8 @@ include @TOP_OBJDIR@/src/config/Makefile.config
 include @TOP_OBJDIR@/src/config/Makefile.pthread
 include @TOP_OBJDIR@/src/config/Makefile.libtool
 
-INCLS= ${TOP_INCDIR}/rx/rx.h ${TOP_INCDIR}/rx/rxgk.h ${TOP_INCDIR}/rx/rxgk_errs.h \
-       ${TOP_INCDIR}/rx/rxgk_int.h
+INCLS= ${TOP_INCDIR}/rx/rx.h ${TOP_INCDIR}/rx/rxgk.h ${TOP_INCDIR}/rx/rxgk_types.h \
+       ${TOP_INCDIR}/rx/rxgk_errs.h ${TOP_INCDIR}/rx/rxgk_int.h
 
 LT_objs = rxgk_client.lo rxgk_server.lo rxgk_errs.lo rxgk_int.cs.lo \
        rxgk_int.xdr.lo rxgk_int.ss.lo rxgk_procs.lo rxgk_token.lo \
@@ -26,13 +26,17 @@ generated: \
 
 depinstall: \
        ${TOP_INCDIR}/rx/rxgk.h \
+       ${TOP_INCDIR}/rx/rxgk_types.h \
        ${TOP_INCDIR}/rx/rxgk_errs.h \
        ${TOP_INCDIR}/rx/rxgk_int.h
 
 ${TOP_INCDIR}/rx/rxgk.h: ${srcdir}/rxgk.h ${TOP_INCDIR}/rx/rxgk_errs.h \
-               ${TOP_INCDIR}/rx/rxgk_int.h
+               ${TOP_INCDIR}/rx/rxgk_int.h ${TOP_INCDIR}/rx/rxgk_types.h
        ${INSTALL_DATA} ${srcdir}/rxgk.h $@
 
+${TOP_INCDIR}/rx/rxgk_types.h: ${srcdir}/rxgk_types.h
+       ${INSTALL_DATA} ${srcdir}/rxgk_types.h $@
+
 ${TOP_INCDIR}/rx/rxgk_errs.h: rxgk_errs.h
        ${INSTALL_DATA} $? $@
 
@@ -73,18 +77,20 @@ rxgk_errs.c: rxgk_errs.et
 #
 test: all
 
-install: liboafs_rxgk.la rxgk.h rxgk_errs.h rxgk_int.h
+install: liboafs_rxgk.la rxgk.h rxgk_types.h rxgk_errs.h rxgk_int.h
        if [ "@ENABLE_RXGK@" = yes ]; then \
                ${INSTALL} -d ${DESTDIR}${includedir}/rx; \
                ${INSTALL_DATA} ${srcdir}/rxgk.h ${DESTDIR}${includedir}/rx/rxgk.h ; \
+               ${INSTALL_DATA} ${srcdir}/rxgk_types.h ${DESTDIR}${includedir}/rx/rxgk_types.h ; \
                ${INSTALL_DATA} rxgk_errs.h ${DESTDIR}${includedir}/rx/rxgk_errs.h ; \
                ${INSTALL_DATA} rxgk_int.h ${DESTDIR}${includedir}/rx/rxgk_int.h ; \
        fi
 
-dest: liboafs_rxgk.la rxgk.h rxgk_errs.h rxgk_int.h
+dest: liboafs_rxgk.la rxgk.h rxgk_types.h rxgk_errs.h rxgk_int.h
        if [ "@ENABLE_RXGK@" = yes ]; then \
                ${INSTALL} -d ${DEST}${includedir}/rx; \
                ${INSTALL_DATA} ${srcdir}/rxgk.h ${DEST}/include/rx/rxgk.h ; \
+               ${INSTALL_DATA} ${srcdir}/rxgk_types.h ${DEST}/include/rx/rxgk_types.h ; \
                ${INSTALL_DATA} rxgk_errs.h ${DEST}/include/rx/rxgk_errs.h ; \
                ${INSTALL_DATA} rxgk_int.h ${DEST}/include/rx/rxgk_int.h ; \
        fi
index c784879..4c61ec9 100644 (file)
@@ -9,6 +9,7 @@ rxgk_copy_key
 rxgk_decrypt_in_key
 rxgk_derive_tk
 rxgk_encrypt_in_key
+rxgk_enctype_better
 rxgk_make_key
 rxgk_make_token
 rxgk_mic_in_key
index f92d6f0..e68b9bc 100644 (file)
@@ -42,6 +42,9 @@
 /* Pull in the protocol description */
 #include <rx/rxgk_int.h>
 
+/* Pull in our basic type definitions */
+#include <rx/rxgk_types.h>
+
 /* RX-internal headers we depend on. */
 #include <rx/rx_opaque.h>
 #include <rx/rx_identity.h>
@@ -65,10 +68,6 @@ static_inline rxgkTime RXGK_NOW(void)
     return secondsToRxgkTime(tv.tv_sec) + (rxgkTime)tv.tv_usec * 10;
 }
 
-/* rxgk_key is an opaque type to wrap our RFC3961 implementation's concept
- * of a key.  It has (at least) the keyblock and length, and enctype. */
-typedef struct rxgk_key_s * rxgk_key;
-
 typedef afs_int32 (*rxgk_getkey_func)(void *rock, afs_int32 *kvno,
                                      afs_int32 *enctype, rxgk_key *key);
 
@@ -108,6 +107,7 @@ afs_int32 rxgk_derive_tk(rxgk_key *tk, rxgk_key k0, afs_uint32 epoch,
                         afs_uint32 key_number) AFS_NONNULL();
 afs_int32 rxgk_cipher_expansion(rxgk_key k0, afs_uint32 *len_out) AFS_NONNULL();
 afs_int32 rxgk_nonce(RXGK_Data *nonce, afs_uint32 len) AFS_NONNULL();
+int rxgk_enctype_better(afs_int32 old_enctype, afs_int32 new_enctype);
 
 /* rxgk_token.c */
 afs_int32 rxgk_make_token(struct rx_opaque *out, RXGK_TokenInfo *info,
index df8745a..fc5eb8a 100644 (file)
@@ -800,3 +800,58 @@ rxgk_nonce(RXGK_Data *nonce, afs_uint32 len)
     krb5_generate_random_block(nonce->val, len);
     return 0;
 }
+
+/* Returns the "score" of an enctype, giving a rough ordering of enctypes by
+ * strength. Higher scores are better. */
+static_inline int
+etype_score(afs_int32 etype)
+{
+    switch (etype) {
+       case ETYPE_ARCFOUR_HMAC_MD5_56: return 0;
+       case ETYPE_DES_CBC_MD4:         return 1;
+       case ETYPE_DES_CBC_CRC:         return 2;
+       case ETYPE_DES_CBC_MD5:         return 3;
+       case ETYPE_ARCFOUR_HMAC_MD5:    return 4;
+       case ETYPE_DES3_CBC_SHA1:       return 5;
+
+       case 25 /* camellia128 */:          return 6;
+       case ETYPE_AES128_CTS_HMAC_SHA1_96: return 7;
+
+       /* aes128-cts-hmac-sha256-128 */
+       case 19:                            return 8;
+
+       case 26 /* camellia256 */:          return 9;
+       case ETYPE_AES256_CTS_HMAC_SHA1_96: return 10;
+
+       /* aes256-cts-hmac-sha384-192 */
+       case 20:                            return 11;
+    }
+    return -1;
+}
+
+/**
+ * Determines which of the two given enctypes is "stronger".
+ *
+ * @param[in] old_enctype      An enctype to compare.
+ * @param[in] new_enctype      Another enctype to compare.
+ *
+ * @return 1 if new_enctype is better/stronger than old_enctype. 0 otherwise.
+ */
+int
+rxgk_enctype_better(afs_int32 old_enctype, afs_int32 new_enctype)
+{
+    int old_score, new_score;
+
+    /* Negative enctypes are reserved for local use. */
+    if (new_enctype < 0) return 1;
+    if (old_enctype < 0) return 0;
+
+    old_score = etype_score(old_enctype);
+    new_score = etype_score(new_enctype);
+
+    if (old_score < new_score) {
+       /* 'new' enctype is better */
+       return 1;
+    }
+    return 0;
+}
diff --git a/src/rxgk/rxgk_types.h b/src/rxgk/rxgk_types.h
new file mode 100644 (file)
index 0000000..70cae44
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013, 2014 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Basic public type definitions for RXGK.
+ */
+
+#ifndef OPENAFS_RXGK_TYPES_H
+#define OPENAFS_RXGK_TYPES_H
+
+/* rxgk_key is an opaque type to wrap our RFC3961 implementation's concept
+ * of a key.  It has (at least) the keyblock and length, and enctype. */
+typedef struct rxgk_key_s * rxgk_key;
+
+#endif /* OPENAFS_RXGK_TYPES_H */