From 83eec9093c8a3f177268a9164182e8ba3958dbc8 Mon Sep 17 00:00:00 2001 From: Benjamin Kaduk Date: Wed, 26 Mar 2014 06:24:02 -0400 Subject: [PATCH] Implement afsconf_GetRXGKKey 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 Reviewed-by: Benjamin Kaduk --- src/auth/cellconfig.p.h | 7 ++ src/auth/keys.c | 115 +++++++++++++++++++++++++++++++++ src/auth/liboafs_auth.la.sym | 2 + src/rxgk/Makefile.in | 16 +++-- src/rxgk/liboafs_rxgk.la.sym | 1 + src/rxgk/rxgk.h | 8 +-- src/rxgk/rxgk_crypto_rfc3961.c | 55 ++++++++++++++++ src/rxgk/rxgk_types.h | 42 ++++++++++++ 8 files changed, 237 insertions(+), 9 deletions(-) create mode 100644 src/rxgk/rxgk_types.h diff --git a/src/auth/cellconfig.p.h b/src/auth/cellconfig.p.h index c9423c0b7f..7fe21ddc20 100644 --- a/src/auth/cellconfig.p.h +++ b/src/auth/cellconfig.p.h @@ -40,6 +40,8 @@ Creation date: #include #include +#include + #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); diff --git a/src/auth/keys.c b/src/auth/keys.c index b1959c729a..59543e8818 100644 --- a/src/auth/keys.c +++ b/src/auth/keys.c @@ -32,7 +32,11 @@ /* Need rx/rx.h to get working assert(), used by LOCK_GLOBAL_MUTEX */ #include #include +#ifdef AFS_RXGK_ENV +#include +#endif +#include #include #include #include @@ -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) diff --git a/src/auth/liboafs_auth.la.sym b/src/auth/liboafs_auth.la.sym index 5497f994ad..fbf88d056f 100644 --- a/src/auth/liboafs_auth.la.sym +++ b/src/auth/liboafs_auth.la.sym @@ -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 diff --git a/src/rxgk/Makefile.in b/src/rxgk/Makefile.in index fa398b14ee..16da77d22c 100644 --- a/src/rxgk/Makefile.in +++ b/src/rxgk/Makefile.in @@ -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 diff --git a/src/rxgk/liboafs_rxgk.la.sym b/src/rxgk/liboafs_rxgk.la.sym index c78487900e..4c61ec97c3 100644 --- a/src/rxgk/liboafs_rxgk.la.sym +++ b/src/rxgk/liboafs_rxgk.la.sym @@ -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 diff --git a/src/rxgk/rxgk.h b/src/rxgk/rxgk.h index f92d6f0b94..e68b9bc3b3 100644 --- a/src/rxgk/rxgk.h +++ b/src/rxgk/rxgk.h @@ -42,6 +42,9 @@ /* Pull in the protocol description */ #include +/* Pull in our basic type definitions */ +#include + /* RX-internal headers we depend on. */ #include #include @@ -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, diff --git a/src/rxgk/rxgk_crypto_rfc3961.c b/src/rxgk/rxgk_crypto_rfc3961.c index df8745a1ce..fc5eb8a414 100644 --- a/src/rxgk/rxgk_crypto_rfc3961.c +++ b/src/rxgk/rxgk_crypto_rfc3961.c @@ -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 index 0000000000..70cae4493c --- /dev/null +++ b/src/rxgk/rxgk_types.h @@ -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 */