* [PATCH 01/19] crypto: Add CTS mode required for Kerberos AES support
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
@ 2008-02-21 18:43 ` Kevin Coffman
2008-02-21 18:43 ` [PATCH 02/19] rpc: gss: Add oid values to the gss_api mechanism structures Kevin Coffman
` (17 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:43 UTC (permalink / raw)
To: linux-nfs
Implement CTS wrapper for CBC mode required for support of AES
encryption support for Kerberos (rfc3962).
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
crypto/Kconfig | 11 ++
crypto/Makefile | 1
crypto/cts.c | 347 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
crypto/tcrypt.c | 16 ++-
crypto/tcrypt.h | 209 +++++++++++++++++++++++++++++++++
5 files changed, 582 insertions(+), 2 deletions(-)
diff --git a/crypto/Kconfig b/crypto/Kconfig
index c3166a1..375d269 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -212,6 +212,17 @@ config CRYPTO_CTR
CTR: Counter mode
This block cipher algorithm is required for IPSec.
+config CRYPTO_CTS
+ tristate "CTS support"
+ select CRYPTO_BLKCIPHER
+ help
+ CTS: Cipher Text Stealing
+ This is the Cipher Text Stealing mode as described by
+ Section 8 of rfc2040 and referenced by rfc3962.
+ (rfc3962 includes errata information in its Appendix A)
+ This mode is required for Kerberos gss mechanism support
+ for AES encryption.
+
config CRYPTO_GCM
tristate "GCM/GMAC support"
select CRYPTO_CTR
diff --git a/crypto/Makefile b/crypto/Makefile
index 48c7583..1b95dec 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o
obj-$(CONFIG_CRYPTO_ECB) += ecb.o
obj-$(CONFIG_CRYPTO_CBC) += cbc.o
obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
+obj-$(CONFIG_CRYPTO_CTS) += cts.o
obj-$(CONFIG_CRYPTO_LRW) += lrw.o
obj-$(CONFIG_CRYPTO_XTS) += xts.o
obj-$(CONFIG_CRYPTO_CTR) += ctr.o
diff --git a/crypto/cts.c b/crypto/cts.c
new file mode 100644
index 0000000..6fe968a
--- /dev/null
+++ b/crypto/cts.c
@@ -0,0 +1,347 @@
+/*
+ * CTS: Cipher Text Stealing mode
+ *
+ * COPYRIGHT (c) 2008
+ * The Regents of the University of Michigan
+ * ALL RIGHTS RESERVED
+ *
+ * Permission is granted to use, copy, create derivative works
+ * and redistribute this software and such derivative works
+ * for any purpose, so long as the name of The University of
+ * Michigan is not used in any advertising or publicity
+ * pertaining to the use of distribution of this software
+ * without specific, written prior authorization. If the
+ * above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any
+ * portion of this software, then the disclaimer below must
+ * also be included.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+/* Derived from various:
+ * Copyright (c) 2006 Herbert Xu <herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q@public.gmane.org>
+ */
+
+/*
+ * This is the Cipher Text Stealing mode as described by
+ * Section 8 of rfc2040 and referenced by rfc3962.
+ * rfc3962 includes errata information in its Appendix A.
+ */
+
+#include <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <crypto/scatterwalk.h>
+#include <linux/slab.h>
+
+struct crypto_cts_ctx {
+ struct crypto_blkcipher *child;
+};
+
+static int crypto_cts_setkey(struct crypto_tfm *parent, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypto_cts_ctx *ctx = crypto_tfm_ctx(parent);
+ struct crypto_blkcipher *child = ctx->child;
+ int err;
+
+ crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_blkcipher_set_flags(child, crypto_tfm_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ err = crypto_blkcipher_setkey(child, key, keylen);
+ crypto_tfm_set_flags(parent, crypto_blkcipher_get_flags(child) &
+ CRYPTO_TFM_RES_MASK);
+ return err;
+}
+
+static int cts_cbc_encrypt(struct crypto_cts_ctx *ctx,
+ struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int offset,
+ unsigned int nbytes)
+{
+ int bsize = crypto_blkcipher_blocksize(desc->tfm);
+ u8 tmp[bsize], tmp2[bsize];
+ struct blkcipher_desc lcldesc;
+ struct scatterlist sgsrc[1], sgdst[1];
+ int lastn = nbytes - bsize;
+ u8 iv[bsize];
+ u8 s[bsize * 2], d[bsize * 2];
+ int err;
+
+ if (lastn < 0)
+ return -EINVAL;
+
+ memset(s, 0, sizeof(s));
+ scatterwalk_map_and_copy(s, src, offset, nbytes, 0);
+
+ memcpy(iv, desc->info, bsize);
+
+ lcldesc.tfm = ctx->child;
+ lcldesc.info = iv;
+ lcldesc.flags = desc->flags;
+
+ sg_set_buf(&sgsrc[0], s, bsize);
+ sg_set_buf(&sgdst[0], tmp, bsize);
+ err = crypto_blkcipher_encrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
+
+ memcpy(d + bsize, tmp, lastn);
+
+ lcldesc.info = tmp;
+
+ sg_set_buf(&sgsrc[0], s + bsize, bsize);
+ sg_set_buf(&sgdst[0], tmp2, bsize);
+ err = crypto_blkcipher_encrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
+
+ memcpy(d, tmp2, bsize);
+
+ scatterwalk_map_and_copy(d, dst, offset, nbytes, 1);
+
+ memcpy(desc->info, tmp2, bsize);
+
+ return err;
+}
+
+static int crypto_cts_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct crypto_cts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ int bsize = crypto_blkcipher_blocksize(desc->tfm);
+ int tot_blocks = (nbytes + bsize - 1) / bsize;
+ int cbc_blocks = tot_blocks > 2 ? tot_blocks - 2 : 0;
+ struct blkcipher_desc lcldesc;
+ int err;
+
+ lcldesc.tfm = ctx->child;
+ lcldesc.info = desc->info;
+ lcldesc.flags = desc->flags;
+
+ if (tot_blocks == 1) {
+ err = crypto_blkcipher_encrypt_iv(&lcldesc, dst, src, bsize);
+ } else if (nbytes <= bsize * 2) {
+ err = cts_cbc_encrypt(ctx, desc, dst, src, 0, nbytes);
+ } else {
+ /* do normal function for tot_blocks - 2 */
+ err = crypto_blkcipher_encrypt_iv(&lcldesc, dst, src,
+ cbc_blocks * bsize);
+ if (err == 0) {
+ /* do cts for final two blocks */
+ err = cts_cbc_encrypt(ctx, desc, dst, src,
+ cbc_blocks * bsize,
+ nbytes - (cbc_blocks * bsize));
+ }
+ }
+
+ return err;
+}
+
+static int cts_cbc_decrypt(struct crypto_cts_ctx *ctx,
+ struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int offset,
+ unsigned int nbytes)
+{
+ int bsize = crypto_blkcipher_blocksize(desc->tfm);
+ u8 tmp[bsize];
+ struct blkcipher_desc lcldesc;
+ struct scatterlist sgsrc[1], sgdst[1];
+ int lastn = nbytes - bsize;
+ u8 iv[bsize];
+ u8 s[bsize * 2], d[bsize * 2];
+ int err;
+
+ if (lastn < 0)
+ return -EINVAL;
+
+ scatterwalk_map_and_copy(s, src, offset, nbytes, 0);
+
+ lcldesc.tfm = ctx->child;
+ lcldesc.info = iv;
+ lcldesc.flags = desc->flags;
+
+ /* 1. Decrypt Cn-1 (s) to create Dn (tmp)*/
+ memset(iv, 0, sizeof(iv));
+ sg_set_buf(&sgsrc[0], s, bsize);
+ sg_set_buf(&sgdst[0], tmp, bsize);
+ err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
+ if (err)
+ return err;
+ /* 2. Pad Cn with zeros at the end to create C of length BB */
+ memset(iv, 0, sizeof(iv));
+ memcpy(iv, s + bsize, lastn);
+ /* 3. Exclusive-or Dn (tmp) with C (iv) to create Xn (tmp) */
+ crypto_xor(tmp, iv, bsize);
+ /* 4. Select the first Ln bytes of Xn (tmp) to create Pn */
+ memcpy(d + bsize, tmp, lastn);
+
+ /* 5. Append the tail (BB - Ln) bytes of Xn (tmp) to Cn to create En */
+ memcpy(s + bsize + lastn, tmp + lastn, bsize - lastn);
+ /* 6. Decrypt En to create Pn-1 */
+ memset(iv, 0, sizeof(iv));
+ sg_set_buf(&sgsrc[0], s + bsize, bsize);
+ sg_set_buf(&sgdst[0], d, bsize);
+ err = crypto_blkcipher_decrypt_iv(&lcldesc, sgdst, sgsrc, bsize);
+
+ /* XXX xor with previous block ?? */
+ crypto_xor(d, desc->info, bsize);
+
+ scatterwalk_map_and_copy(d, dst, offset, nbytes, 1);
+
+ memcpy(desc->info, s, bsize);
+ return err;
+}
+
+static int crypto_cts_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct crypto_cts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ int bsize = crypto_blkcipher_blocksize(desc->tfm);
+ int tot_blocks = (nbytes + bsize - 1) / bsize;
+ int cbc_blocks = tot_blocks > 2 ? tot_blocks - 2 : 0;
+ struct blkcipher_desc lcldesc;
+ int err;
+
+ lcldesc.tfm = ctx->child;
+ lcldesc.info = desc->info;
+ lcldesc.flags = desc->flags;
+
+ if (tot_blocks == 1) {
+ err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src, bsize);
+ } else if (nbytes <= bsize * 2) {
+ err = cts_cbc_decrypt(ctx, desc, dst, src, 0, nbytes);
+ } else {
+ /* do normal function for tot_blocks - 2 */
+ err = crypto_blkcipher_decrypt_iv(&lcldesc, dst, src,
+ cbc_blocks * bsize);
+ if (err == 0) {
+ /* do cts for final two blocks */
+ err = cts_cbc_decrypt(ctx, desc, dst, src,
+ cbc_blocks * bsize,
+ nbytes - (cbc_blocks * bsize));
+ }
+ }
+ return err;
+}
+
+static int crypto_cts_init_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_instance *inst = (void *)tfm->__crt_alg;
+ struct crypto_spawn *spawn = crypto_instance_ctx(inst);
+ struct crypto_cts_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_blkcipher *cipher;
+
+ cipher = crypto_spawn_blkcipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
+
+ ctx->child = cipher;
+ return 0;
+}
+
+static void crypto_cts_exit_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_cts_ctx *ctx = crypto_tfm_ctx(tfm);
+ crypto_free_blkcipher(ctx->child);
+}
+
+static struct crypto_instance *crypto_cts_alloc(struct rtattr **tb)
+{
+ struct crypto_instance *inst;
+ struct crypto_alg *alg;
+ int err;
+
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+ if (err)
+ return ERR_PTR(err);
+
+ alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_BLKCIPHER,
+ CRYPTO_ALG_TYPE_MASK);
+ err = PTR_ERR(alg);
+ if (IS_ERR(alg))
+ return ERR_PTR(err);
+
+ inst = ERR_PTR(-EINVAL);
+ if (!is_power_of_2(alg->cra_blocksize))
+ goto out_put_alg;
+
+ inst = crypto_alloc_instance("cts", alg);
+ if (IS_ERR(inst))
+ goto out_put_alg;
+
+ inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER;
+ inst->alg.cra_priority = alg->cra_priority;
+ inst->alg.cra_blocksize = alg->cra_blocksize;
+ inst->alg.cra_alignmask = alg->cra_alignmask;
+ inst->alg.cra_type = &crypto_blkcipher_type;
+
+ /* We access the data as u32s when xoring. */
+ inst->alg.cra_alignmask |= __alignof__(u32) - 1;
+
+ inst->alg.cra_blkcipher.ivsize = alg->cra_blocksize;
+ inst->alg.cra_blkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
+ inst->alg.cra_blkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
+
+ inst->alg.cra_blkcipher.geniv = "seqiv";
+
+ inst->alg.cra_ctxsize = sizeof(struct crypto_cts_ctx);
+
+ inst->alg.cra_init = crypto_cts_init_tfm;
+ inst->alg.cra_exit = crypto_cts_exit_tfm;
+
+ inst->alg.cra_blkcipher.setkey = crypto_cts_setkey;
+ inst->alg.cra_blkcipher.encrypt = crypto_cts_encrypt;
+ inst->alg.cra_blkcipher.decrypt = crypto_cts_decrypt;
+
+out_put_alg:
+ crypto_mod_put(alg);
+ return inst;
+}
+
+static void crypto_cts_free(struct crypto_instance *inst)
+{
+ crypto_drop_spawn(crypto_instance_ctx(inst));
+ kfree(inst);
+}
+
+static struct crypto_template crypto_cts_tmpl = {
+ .name = "cts",
+ .alloc = crypto_cts_alloc,
+ .free = crypto_cts_free,
+ .module = THIS_MODULE,
+};
+
+static int __init crypto_cts_module_init(void)
+{
+ return crypto_register_template(&crypto_cts_tmpl);
+}
+
+static void __exit crypto_cts_module_exit(void)
+{
+ crypto_unregister_template(&crypto_cts_tmpl);
+}
+
+module_init(crypto_cts_module_init);
+module_exit(crypto_cts_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("CTS-CBC) CipherText Stealing for CBC");
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 1ab8c01..103d9e0 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -82,9 +82,8 @@ static char *check[] = {
"des", "md5", "des3_ede", "rot13", "sha1", "sha224", "sha256",
"blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes",
"cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
- "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",
"khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt",
- "camellia", "seed", "salsa20", "lzo", NULL
+ "camellia", "seed", "salsa20", "lzo", "cts", NULL
};
static void hexdump(unsigned char *buf, unsigned int len)
@@ -1301,6 +1300,12 @@ static void do_test(void)
test_cipher("ecb(seed)", DECRYPT, seed_dec_tv_template,
SEED_DEC_TEST_VECTORS);
+ //CTS
+ test_cipher("cts(cbc(aes))", ENCRYPT, cts_mode_enc_tv_template,
+ CTS_MODE_ENC_TEST_VECTORS);
+ test_cipher("cts(cbc(aes))", DECRYPT, cts_mode_dec_tv_template,
+ CTS_MODE_DEC_TEST_VECTORS);
+
test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
@@ -1584,6 +1589,13 @@ static void do_test(void)
AES_CCM_DEC_TEST_VECTORS);
break;
+ case 38:
+ test_cipher("cts(cbc(aes))", ENCRYPT, cts_mode_enc_tv_template,
+ CTS_MODE_ENC_TEST_VECTORS);
+ test_cipher("cts(cbc(aes))", DECRYPT, cts_mode_dec_tv_template,
+ CTS_MODE_DEC_TEST_VECTORS);
+ break;
+
case 100:
test_hash("hmac(md5)", hmac_md5_tv_template,
HMAC_MD5_TEST_VECTORS);
diff --git a/crypto/tcrypt.h b/crypto/tcrypt.h
index f785e56..548716b 100644
--- a/crypto/tcrypt.h
+++ b/crypto/tcrypt.h
@@ -7631,6 +7631,215 @@ static struct cipher_testvec salsa20_stream_enc_tv_template[] = {
};
/*
+ * CTS (Cipher Text Stealing) mode tests
+ */
+#define CTS_MODE_ENC_TEST_VECTORS 6
+#define CTS_MODE_DEC_TEST_VECTORS 6
+static struct cipher_testvec cts_mode_enc_tv_template[] = {
+ { /* from rfc3962 */
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .ilen = 17,
+ .input = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20 },
+ .rlen = 17,
+ .result = { 0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4,
+ 0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f,
+ 0x97 },
+ }, {
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .ilen = 31,
+ .input = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20 },
+ .rlen = 31,
+ .result = { 0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1,
+ 0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22,
+ 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+ 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5 },
+ }, {
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .ilen = 32,
+ .input = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43 },
+ .rlen = 32,
+ .result = { 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+ 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
+ 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+ 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84 },
+ }, {
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .ilen = 47,
+ .input = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
+ 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
+ 0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c },
+ .rlen = 47,
+ .result = { 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+ 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+ 0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c,
+ 0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e,
+ 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+ 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5 },
+ }, {
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .ilen = 48,
+ .input = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
+ 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
+ 0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c, 0x20 },
+ .rlen = 48,
+ .result = { 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+ 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+ 0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
+ 0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8,
+ 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+ 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8 },
+ }, {
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .ilen = 64,
+ .input = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
+ 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
+ 0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c, 0x20,
+ 0x61, 0x6e, 0x64, 0x20, 0x77, 0x6f, 0x6e, 0x74,
+ 0x6f, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x70, 0x2e },
+ .rlen = 64,
+ .result = { 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+ 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+ 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+ 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
+ 0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5,
+ 0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40,
+ 0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
+ 0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8 },
+ }
+};
+
+static struct cipher_testvec cts_mode_dec_tv_template[] = {
+ { /* from rfc3962 */
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .rlen = 17,
+ .result = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20 },
+ .ilen = 17,
+ .input = { 0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4,
+ 0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f,
+ 0x97 },
+ }, {
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .rlen = 31,
+ .result = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20 },
+ .ilen = 31,
+ .input = { 0xfc, 0x00, 0x78, 0x3e, 0x0e, 0xfd, 0xb2, 0xc1,
+ 0xd4, 0x45, 0xd4, 0xc8, 0xef, 0xf7, 0xed, 0x22,
+ 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+ 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5 },
+ }, {
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .rlen = 32,
+ .result = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43 },
+ .ilen = 32,
+ .input = { 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+ 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
+ 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+ 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84 },
+ }, {
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .rlen = 47,
+ .result = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
+ 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
+ 0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c },
+ .ilen = 47,
+ .input = { 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+ 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+ 0xb3, 0xff, 0xfd, 0x94, 0x0c, 0x16, 0xa1, 0x8c,
+ 0x1b, 0x55, 0x49, 0xd2, 0xf8, 0x38, 0x02, 0x9e,
+ 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+ 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5 },
+ }, {
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .rlen = 48,
+ .result = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
+ 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
+ 0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c, 0x20 },
+ .ilen = 48,
+ .input = { 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+ 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+ 0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
+ 0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8,
+ 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+ 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8 },
+ }, {
+ .klen = 16,
+ .key = { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
+ 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 },
+ .rlen = 64,
+ .result = { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
+ 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65,
+ 0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+ 0x20, 0x47, 0x61, 0x75, 0x27, 0x73, 0x20, 0x43,
+ 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x2c, 0x20,
+ 0x70, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x2c, 0x20,
+ 0x61, 0x6e, 0x64, 0x20, 0x77, 0x6f, 0x6e, 0x74,
+ 0x6f, 0x6e, 0x20, 0x73, 0x6f, 0x75, 0x70, 0x2e },
+ .ilen = 64,
+ .input = { 0x97, 0x68, 0x72, 0x68, 0xd6, 0xec, 0xcc, 0xc0,
+ 0xc0, 0x7b, 0x25, 0xe2, 0x5e, 0xcf, 0xe5, 0x84,
+ 0x39, 0x31, 0x25, 0x23, 0xa7, 0x86, 0x62, 0xd5,
+ 0xbe, 0x7f, 0xcb, 0xcc, 0x98, 0xeb, 0xf5, 0xa8,
+ 0x48, 0x07, 0xef, 0xe8, 0x36, 0xee, 0x89, 0xa5,
+ 0x26, 0x73, 0x0d, 0xbc, 0x2f, 0x7b, 0xc8, 0x40,
+ 0x9d, 0xad, 0x8b, 0xbb, 0x96, 0xc4, 0xcd, 0xc0,
+ 0x3b, 0xc1, 0x03, 0xe1, 0xa1, 0x94, 0xbb, 0xd8 },
+ }
+};
+
+/*
* Compression stuff.
*/
#define COMP_BUF_SIZE 512
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 02/19] rpc: gss: Add oid values to the gss_api mechanism structures
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2008-02-21 18:43 ` [PATCH 01/19] crypto: Add CTS mode required for Kerberos AES support Kevin Coffman
@ 2008-02-21 18:43 ` Kevin Coffman
2008-02-21 18:44 ` [PATCH 03/19] sunrpc: make token header values less confusing Kevin Coffman
` (16 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:43 UTC (permalink / raw)
To: linux-nfs
From: Usha Ketineni <uketinen@us.ibm.com>
On NFSV4 server side, these are required as part of the security
triple(oid,qop,service) information being sent in the response of the
SECINFO operation.
Signed-off-by: Usha Ketineni <uketinen@us.ibm.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
fs/nfsd/nfs4xdr.c | 6 +++---
include/linux/sunrpc/gss_api.h | 2 +-
include/linux/sunrpc/gss_krb5.h | 2 ++
net/sunrpc/auth_gss/gss_krb5_mech.c | 4 +++-
net/sunrpc/auth_gss/gss_spkm3_mech.c | 4 +++-
5 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index b0592e7..d6b43eb 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2519,9 +2519,9 @@ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
RESERVE_SPACE(4);
WRITE32(RPC_AUTH_GSS);
ADJUST_ARGS();
- RESERVE_SPACE(4 + gm->gm_oid.len);
- WRITE32(gm->gm_oid.len);
- WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
+ RESERVE_SPACE(4 + gm->gm_oid->len);
+ WRITE32(gm->gm_oid->len);
+ WRITEMEM(gm->gm_oid->data, gm->gm_oid->len);
ADJUST_ARGS();
RESERVE_SPACE(4);
WRITE32(0); /* qop */
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
index 459c5fc..ed0b80c 100644
--- a/include/linux/sunrpc/gss_api.h
+++ b/include/linux/sunrpc/gss_api.h
@@ -76,7 +76,7 @@ struct pf_desc {
struct gss_api_mech {
struct list_head gm_list;
struct module *gm_owner;
- struct xdr_netobj gm_oid;
+ struct xdr_netobj *gm_oid;
char *gm_name;
const struct gss_api_ops *gm_ops;
/* pseudoflavors supported by this mechanism: */
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 5a4b1e0..8c38aba 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -70,6 +70,8 @@ enum seal_alg {
SEAL_ALG_DES3KD = 0x0002
};
+extern struct xdr_netobj krb5_oid;
+
#define KRB5_CKSUM_LENGTH 8
#define CKSUMTYPE_CRC32 0x0001
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 60c3dba..3c070d0 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -232,10 +232,12 @@ static struct pf_desc gss_kerberos_pfs[] = {
},
};
+struct xdr_netobj krb5_oid = {9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
+
static struct gss_api_mech gss_kerberos_mech = {
.gm_name = "krb5",
.gm_owner = THIS_MODULE,
- .gm_oid = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"},
+ .gm_oid = &krb5_oid,
.gm_ops = &gss_kerberos_ops,
.gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs),
.gm_pfs = gss_kerberos_pfs,
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
index 5deb4b6..210b23b 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -214,10 +214,12 @@ static struct pf_desc gss_spkm3_pfs[] = {
{RPC_AUTH_GSS_SPKMI, RPC_GSS_SVC_INTEGRITY, "spkm3i"},
};
+struct xdr_netobj spkm3_oid = {7, "\053\006\001\005\005\001\003"};
+
static struct gss_api_mech gss_spkm3_mech = {
.gm_name = "spkm3",
.gm_owner = THIS_MODULE,
- .gm_oid = {7, "\053\006\001\005\005\001\003"},
+ .gm_oid = &spkm3_oid,
.gm_ops = &gss_spkm3_ops,
.gm_pf_num = ARRAY_SIZE(gss_spkm3_pfs),
.gm_pfs = gss_spkm3_pfs,
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 03/19] sunrpc: make token header values less confusing
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2008-02-21 18:43 ` [PATCH 01/19] crypto: Add CTS mode required for Kerberos AES support Kevin Coffman
2008-02-21 18:43 ` [PATCH 02/19] rpc: gss: Add oid values to the gss_api mechanism structures Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
[not found] ` <20080221184402.19195.57873.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2008-02-21 18:44 ` [PATCH 04/19] Add new pipefs file indicating which Kerberos enctypes the kernel supports Kevin Coffman
` (15 subsequent siblings)
18 siblings, 1 reply; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
g_make_token_header() and g_token_size() add two too many, and
therefore their callers pass in "(logical_value - 2)" rather
than "logical_value" as hard-coded values which causes confusion.
This dates back to the original g_make_token_header which took an
optional token type (token_id) value and added it to the token.
This was removed, but the routine always adds room for the token_id
rather than not.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/auth_gss/gss_generic_token.c | 4 ++--
net/sunrpc/auth_gss/gss_krb5_seal.c | 4 ++--
net/sunrpc/auth_gss/gss_krb5_wrap.c | 4 ++--
net/sunrpc/auth_gss/gss_spkm3_seal.c | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/net/sunrpc/auth_gss/gss_generic_token.c b/net/sunrpc/auth_gss/gss_generic_token.c
index ea8c92e..d83b881 100644
--- a/net/sunrpc/auth_gss/gss_generic_token.c
+++ b/net/sunrpc/auth_gss/gss_generic_token.c
@@ -148,7 +148,7 @@ int
g_token_size(struct xdr_netobj *mech, unsigned int body_size)
{
/* set body_size to sequence contents size */
- body_size += 4 + (int) mech->len; /* NEED overflow check */
+ body_size += 2 + (int) mech->len; /* NEED overflow check */
return(1 + der_length_size(body_size) + body_size);
}
@@ -161,7 +161,7 @@ void
g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf)
{
*(*buf)++ = 0x60;
- der_write_length(buf, 4 + mech->len + body_size);
+ der_write_length(buf, 2 + mech->len + body_size);
*(*buf)++ = 0x06;
*(*buf)++ = (unsigned char) mech->len;
TWRITE_STR(*buf, mech->data, ((int) mech->len));
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index dedcbd6..b2fa785 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -87,10 +87,10 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
now = get_seconds();
- token->len = g_token_size(&ctx->mech_used, 22);
+ token->len = g_token_size(&ctx->mech_used, 24);
ptr = token->data;
- g_make_token_header(&ctx->mech_used, 22, &ptr);
+ g_make_token_header(&ctx->mech_used, 24, &ptr);
*ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
*ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff);
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 3bdc527..a2c92f1 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -137,7 +137,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
BUG_ON((buf->len - offset) % blocksize);
plainlen = blocksize + buf->len - offset;
- headlen = g_token_size(&kctx->mech_used, 22 + plainlen) -
+ headlen = g_token_size(&kctx->mech_used, 24 + plainlen) -
(buf->len - offset);
ptr = buf->head[0].iov_base + offset;
@@ -149,7 +149,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
buf->len += headlen;
BUG_ON((buf->len - offset - headlen) % blocksize);
- g_make_token_header(&kctx->mech_used, 22 + plainlen, &ptr);
+ g_make_token_header(&kctx->mech_used, 24 + plainlen, &ptr);
*ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff);
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
index abf17ce..88505d5 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_seal.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c
@@ -104,7 +104,7 @@ spkm3_make_token(struct spkm3_ctx *ctx,
goto out_err;
asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
- tokenlen = 10 + ctxelen + 1 + md5elen + 1;
+ tokenlen = 12 + ctxelen + 1 + md5elen + 1;
/* Create token header using generic routines */
token->len = g_token_size(&ctx->mech_used, tokenlen);
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 04/19] Add new pipefs file indicating which Kerberos enctypes the kernel supports
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (2 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 03/19] sunrpc: make token header values less confusing Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
[not found] ` <20080221184407.19195.62074.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2008-02-21 18:44 ` [PATCH 05/19] Correct grammer/typos in dprintks Kevin Coffman
` (14 subsequent siblings)
18 siblings, 1 reply; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
New file, krb5_info, indicates which Kerberos encryption types are
supported by the kernel rpcsecgss code. This is used by gssd to
determine which encryption types it should attempt to negotiate
when creating a context with a server.
The server principal's database and keytab encryption types are
what limits what it should negotiate. Therefore, its keytab
should be created with only the enctypes listed by this file.
From: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/rpc_pipe.c | 31 +++++++++++++++++++++++++++++++
1 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 7e19716..5781862 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -385,6 +385,31 @@ static const struct file_operations rpc_info_operations = {
.release = rpc_info_release,
};
+/*
+ * This really belongs in the gss_krb5 code,
+ * but the info file logically belongs here
+ */
+static int
+rpc_show_krb5_info(struct seq_file *m, void *v)
+{
+ seq_printf(m, "enctypes: 3,1,2\n");
+ return 0;
+}
+
+static int
+rpc_krb5_info_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, rpc_show_krb5_info, NULL);
+}
+
+static struct file_operations krb5_info_operations = {
+ .owner = THIS_MODULE,
+ .open = rpc_krb5_info_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/*
* We have a single directory with 1 node in it.
@@ -396,6 +421,7 @@ enum {
RPCAUTH_nfs,
RPCAUTH_portmap,
RPCAUTH_statd,
+ RPCAUTH_krb5_info,
RPCAUTH_RootEOF
};
@@ -429,6 +455,11 @@ static struct rpc_filelist files[] = {
.name = "statd",
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
},
+ [RPCAUTH_krb5_info] = {
+ .name = "krb5_info",
+ .i_fop = &krb5_info_operations,
+ .mode = S_IFREG | S_IRUSR,
+ },
};
enum {
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 05/19] Correct grammer/typos in dprintks
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (3 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 04/19] Add new pipefs file indicating which Kerberos enctypes the kernel supports Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
[not found] ` <20080221184412.19195.93743.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2008-02-21 18:44 ` [PATCH 06/19] Use get_random_bytes() to create confounder Kevin Coffman
` (13 subsequent siblings)
18 siblings, 1 reply; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
cleanup: Fix grammer/typos to use "too" instead of "to"
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/auth_gss/gss_krb5_crypto.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 0dd7923..1d52308 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -66,8 +66,8 @@ krb5_encrypt(
goto out;
if (crypto_blkcipher_ivsize(tfm) > 16) {
- dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n",
- crypto_blkcipher_ivsize(tfm));
+ dprintk("RPC: gss_k5encrypt: tfm iv size too large %d\n",
+ crypto_blkcipher_ivsize(tfm));
goto out;
}
@@ -102,7 +102,7 @@ krb5_decrypt(
goto out;
if (crypto_blkcipher_ivsize(tfm) > 16) {
- dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n",
+ dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n",
crypto_blkcipher_ivsize(tfm));
goto out;
}
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 06/19] Use get_random_bytes() to create confounder
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (4 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 05/19] Correct grammer/typos in dprintks Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
[not found] ` <20080221184417.19195.55123.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2008-02-21 18:44 ` [PATCH 07/19] Don't expect blocksize to always be 8 when calculating padding Kevin Coffman
` (12 subsequent siblings)
18 siblings, 1 reply; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
Instead of using an incementing value for the confounder, use
get_random_bytes() which gives us the desired unpredictable value.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/auth_gss/gss_krb5_wrap.c | 15 +--------------
1 files changed, 1 insertions(+), 14 deletions(-)
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index a2c92f1..7a0002f 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -90,20 +90,7 @@ out:
static inline void
make_confounder(char *p, int blocksize)
{
- static u64 i = 0;
- u64 *q = (u64 *)p;
-
- /* rfc1964 claims this should be "random". But all that's really
- * necessary is that it be unique. And not even that is necessary in
- * our case since our "gssapi" implementation exists only to support
- * rpcsec_gss, so we know that the only buffers we will ever encrypt
- * already begin with a unique sequence number. Just to hedge my bets
- * I'll make a half-hearted attempt at something unique, but ensuring
- * uniqueness would mean worrying about atomicity and rollover, and I
- * don't care enough. */
-
- BUG_ON(blocksize != 8);
- *q = i++;
+ get_random_bytes(p, blocksize);
}
/* Assumptions: the head and tail of inbuf are ours to play with.
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 07/19] Don't expect blocksize to always be 8 when calculating padding
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (5 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 06/19] Use get_random_bytes() to create confounder Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
2008-02-21 18:44 ` [PATCH 08/19] Remove define for KRB5_CKSUM_LENGTH, which will become enctype-dependent Kevin Coffman
` (11 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
Allow blocksizes other than 8 when calculating padding
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/auth_gss/gss_krb5_wrap.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 7a0002f..384f470 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -13,10 +13,7 @@
static inline int
gss_krb5_padding(int blocksize, int length)
{
- /* Most of the code is block-size independent but currently we
- * use only 8: */
- BUG_ON(blocksize != 8);
- return 8 - (length & 7);
+ return blocksize - (length & (blocksize - 1));
}
static inline void
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 08/19] Remove define for KRB5_CKSUM_LENGTH, which will become enctype-dependent
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (6 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 07/19] Don't expect blocksize to always be 8 when calculating padding Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
[not found] ` <20080221184427.19195.16243.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2008-02-21 18:44 ` [PATCH 09/19] gss_krb5: split up functions in preparation of adding new enctypes Kevin Coffman
` (10 subsequent siblings)
18 siblings, 1 reply; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
cleanup: When adding new encryption types, the checksum length
can be different for each enctype. Face the fact that the
current code only supports DES which has a checksum length of 8.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 2 --
net/sunrpc/auth_gss/gss_krb5_seal.c | 3 +--
net/sunrpc/auth_gss/gss_krb5_wrap.c | 4 +---
3 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 8c38aba..47d2110 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -72,8 +72,6 @@ enum seal_alg {
extern struct xdr_netobj krb5_oid;
-#define KRB5_CKSUM_LENGTH 8
-
#define CKSUMTYPE_CRC32 0x0001
#define CKSUMTYPE_RSA_MD4 0x0002
#define CKSUMTYPE_RSA_MD4_DES 0x0003
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index b2fa785..e7b2a52 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -109,8 +109,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
md5cksum.data, md5cksum.len))
return GSS_S_FAILURE;
- memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
- KRB5_CKSUM_LENGTH);
+ memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
spin_lock(&krb5_seq_lock);
seq_send = ctx->seq_send++;
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 384f470..9763bf1 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -160,9 +160,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
md5cksum.data, md5cksum.len))
return GSS_S_FAILURE;
- memcpy(krb5_hdr + 16,
- md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
- KRB5_CKSUM_LENGTH);
+ memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
spin_lock(&krb5_seq_lock);
seq_send = kctx->seq_send++;
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 09/19] gss_krb5: split up functions in preparation of adding new enctypes
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (7 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 08/19] Remove define for KRB5_CKSUM_LENGTH, which will become enctype-dependent Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
2008-02-21 18:44 ` [PATCH 10/19] gss_krb5: prepare for new context format Kevin Coffman
` (9 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
Add encryption type to the krb5 context structure and use it to switch
to the correct functions depending on the encryption type.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 1 +
net/sunrpc/auth_gss/gss_krb5_mech.c | 1 +
net/sunrpc/auth_gss/gss_krb5_seal.c | 21 ++++++++++++++--
net/sunrpc/auth_gss/gss_krb5_unseal.c | 22 ++++++++++++++---
net/sunrpc/auth_gss/gss_krb5_wrap.c | 44 +++++++++++++++++++++++++++++----
5 files changed, 77 insertions(+), 12 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 47d2110..dfe382a 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -42,6 +42,7 @@
struct krb5_ctx {
int initiate; /* 1 = initiating, 0 = accepting */
+ u32 enctype;
struct crypto_blkcipher *enc;
struct crypto_blkcipher *seq;
s32 endtime;
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 3c070d0..477cf07 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -137,6 +137,7 @@ gss_import_sec_context_kerberos(const void *p,
p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate));
if (IS_ERR(p))
goto out_err_free_ctx;
+ ctx->enctype = ENCTYPE_DES_CBC_RAW;
/* The downcall format was designed before we completely understood
* the uses of the context fields; so it includes some stuff we
* just give some minimal sanity-checking, and some we ignore
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index e7b2a52..3b9cc47 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -71,11 +71,10 @@
DEFINE_SPINLOCK(krb5_seq_lock);
-u32
-gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
+static u32
+gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
struct xdr_netobj *token)
{
- struct krb5_ctx *ctx = gss_ctx->internal_ctx_id;
char cksumdata[16];
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
unsigned char *ptr, *krb5_hdr, *msg_start;
@@ -121,3 +120,19 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
}
+
+u32
+gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
+ struct xdr_netobj *token)
+{
+ struct krb5_ctx *ctx = gss_ctx->internal_ctx_id;
+
+ switch (ctx->enctype) {
+ case ENCTYPE_DES_CBC_RAW:
+ return gss_get_mic_v1(ctx, text, token);
+ default:
+ BUG();
+ }
+ return 0;
+}
+
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index e30a993..211eca4 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -71,11 +71,10 @@
/* read_token is a mic token, and message_buffer is the data that the mic was
* supposedly taken over. */
-u32
-gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
+static u32
+gss_verify_mic_v1(struct krb5_ctx *ctx,
struct xdr_buf *message_buffer, struct xdr_netobj *read_token)
{
- struct krb5_ctx *ctx = gss_ctx->internal_ctx_id;
int signalg;
int sealalg;
char cksumdata[16];
@@ -136,3 +135,20 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
return GSS_S_COMPLETE;
}
+
+u32
+gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
+ struct xdr_buf *message_buffer,
+ struct xdr_netobj *read_token)
+{
+ struct krb5_ctx *ctx = gss_ctx->internal_ctx_id;
+
+ switch (ctx->enctype) {
+ case ENCTYPE_DES_CBC_RAW:
+ return gss_verify_mic_v1(ctx, message_buffer, read_token);
+ default:
+ BUG();
+ }
+ return 0;
+}
+
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 9763bf1..9f13411 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -98,11 +98,10 @@ make_confounder(char *p, int blocksize)
/* XXX factor out common code with seal/unseal. */
-u32
-gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
+static u32
+gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
struct xdr_buf *buf, struct page **pages)
{
- struct krb5_ctx *kctx = ctx->internal_ctx_id;
char cksumdata[16];
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
int blocksize = 0, plainlen;
@@ -179,10 +178,9 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
}
-u32
-gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf)
+static u32
+gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
{
- struct krb5_ctx *kctx = ctx->internal_ctx_id;
int signalg;
int sealalg;
char cksumdata[16];
@@ -270,3 +268,37 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf)
return GSS_S_COMPLETE;
}
+
+u32
+gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
+ struct xdr_buf *buf, struct page **pages)
+{
+ struct krb5_ctx *kctx = gctx->internal_ctx_id;
+
+ switch (kctx->enctype) {
+ case ENCTYPE_DES_CBC_RAW:
+ return gss_wrap_kerberos_v1(kctx, offset, buf, pages);
+ break;
+ default:
+ BUG();
+ break;
+ }
+ return 0;
+}
+
+u32
+gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf)
+{
+ struct krb5_ctx *kctx = gctx->internal_ctx_id;
+
+ switch (kctx->enctype) {
+ case ENCTYPE_DES_CBC_RAW:
+ return gss_unwrap_kerberos_v1(kctx, offset, buf);
+ break;
+ default:
+ BUG();
+ break;
+ }
+ return 0;
+}
+
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 10/19] gss_krb5: prepare for new context format
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (8 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 09/19] gss_krb5: split up functions in preparation of adding new enctypes Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
2008-02-21 18:44 ` [PATCH 11/19] gss_krb5: introduce encryption type framework Kevin Coffman
` (8 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
Prepare for new context format by splitting out the old "v1"
context processing function.
From: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/auth_gss/gss_krb5_mech.c | 62 +++++++++++++++++++++++------------
1 files changed, 40 insertions(+), 22 deletions(-)
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 477cf07..f0f0749 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -123,51 +123,47 @@ out_err:
}
static int
-gss_import_sec_context_kerberos(const void *p,
- size_t len,
- struct gss_ctx *ctx_id)
+gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx)
{
- const void *end = (const void *)((const char *)p + len);
- struct krb5_ctx *ctx;
int tmp;
- if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL)))
- goto out_err;
-
p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate));
if (IS_ERR(p))
- goto out_err_free_ctx;
+ goto out_err;
+
+ /* Old format supports only DES! Any other enctype uses new format */
ctx->enctype = ENCTYPE_DES_CBC_RAW;
+
/* The downcall format was designed before we completely understood
* the uses of the context fields; so it includes some stuff we
* just give some minimal sanity-checking, and some we ignore
* completely (like the next twenty bytes): */
if (unlikely(p + 20 > end || p + 20 < p))
- goto out_err_free_ctx;
+ goto out_err;
p += 20;
p = simple_get_bytes(p, end, &tmp, sizeof(tmp));
if (IS_ERR(p))
- goto out_err_free_ctx;
+ goto out_err;
if (tmp != SGN_ALG_DES_MAC_MD5) {
p = ERR_PTR(-ENOSYS);
- goto out_err_free_ctx;
+ goto out_err;
}
p = simple_get_bytes(p, end, &tmp, sizeof(tmp));
if (IS_ERR(p))
- goto out_err_free_ctx;
+ goto out_err;
if (tmp != SEAL_ALG_DES) {
p = ERR_PTR(-ENOSYS);
- goto out_err_free_ctx;
+ goto out_err;
}
p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
if (IS_ERR(p))
- goto out_err_free_ctx;
+ goto out_err;
p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send));
if (IS_ERR(p))
- goto out_err_free_ctx;
+ goto out_err;
p = simple_get_netobj(p, end, &ctx->mech_used);
if (IS_ERR(p))
- goto out_err_free_ctx;
+ goto out_err;
p = get_key(p, end, &ctx->enc);
if (IS_ERR(p))
goto out_err_free_mech;
@@ -179,9 +175,6 @@ gss_import_sec_context_kerberos(const void *p,
goto out_err_free_key2;
}
- ctx_id->internal_ctx_id = ctx;
-
- dprintk("RPC: Successfully imported new context.\n");
return 0;
out_err_free_key2:
@@ -190,12 +183,37 @@ out_err_free_key1:
crypto_free_blkcipher(ctx->enc);
out_err_free_mech:
kfree(ctx->mech_used.data);
-out_err_free_ctx:
- kfree(ctx);
out_err:
return PTR_ERR(p);
}
+static int
+gss_import_sec_context_kerberos(const void *p, size_t len,
+ struct gss_ctx *ctx_id)
+{
+ const void *end = (const void *)((const char *)p + len);
+ struct krb5_ctx *ctx;
+ int ret;
+
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (ctx == NULL)
+ return -ENOMEM;
+ memset(ctx, 0, sizeof(*ctx));
+
+ if (len == 85)
+ ret = gss_import_v1_context(p, end, ctx);
+ else
+ ret = -EINVAL;
+
+ if (ret == 0)
+ ctx_id->internal_ctx_id = ctx;
+ else
+ kfree(ctx);
+
+ dprintk("RPC: %s: returning %d\n", __func__, ret);
+ return ret;
+}
+
static void
gss_delete_sec_context_kerberos(void *internal_ctx) {
struct krb5_ctx *kctx = internal_ctx;
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 11/19] gss_krb5: introduce encryption type framework
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (9 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 10/19] gss_krb5: prepare for new context format Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
2008-02-21 18:44 ` [PATCH 12/19] gss_krb5: add ability to have a keyed checksum (hmac) Kevin Coffman
` (7 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
Add enctype framework and change functions to use the generic
values from it rather than the values hard-coded for des.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 29 +++++++++++
net/sunrpc/auth_gss/gss_krb5_crypto.c | 16 +++---
net/sunrpc/auth_gss/gss_krb5_mech.c | 88 +++++++++++++++++++++++++++------
net/sunrpc/auth_gss/gss_krb5_seal.c | 48 +++++++++++-------
net/sunrpc/auth_gss/gss_krb5_unseal.c | 12 +++--
net/sunrpc/auth_gss/gss_krb5_wrap.c | 49 +++++++++++-------
6 files changed, 175 insertions(+), 67 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index dfe382a..d10d8ce 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -36,13 +36,42 @@
*
*/
+#include <linux/crypto.h>
#include <linux/sunrpc/auth_gss.h>
#include <linux/sunrpc/gss_err.h>
#include <linux/sunrpc/gss_asn1.h>
+/* Maximum checksum function output for the supported crypto algorithms */
+#define GSS_KRB5_MAX_CKSUM_LEN 20
+
+/* Maximum blocksize for the supported crypto algorithms */
+#define GSS_KRB5_MAX_BLOCKSIZE 16
+
+struct gss_krb5_enctype {
+ const u32 etype; /* encryption (key) type */
+ const u32 ctype; /* checksum type */
+ const char *name; /* "friendly" name */
+ const char *encrypt_name; /* crypto encrypt name */
+ const char *cksum_name; /* crypto checksum name */
+ const u16 signalg; /* signing algorithm */
+ const u16 sealalg; /* sealing algorithm */
+ const u32 blocksize; /* encryption blocksize */
+ const u32 cksumlength; /* checksum length */
+ const u32 keyed_cksum; /* is it a keyed cksum? */
+ const u32 keybytes; /* raw key len, in bytes */
+ const u32 keylength; /* final key len, in bytes */
+ u32 (*encrypt) (struct crypto_blkcipher *tfm,
+ void *iv, void *in, void *out,
+ int length); /* encryption function */
+ u32 (*decrypt) (struct crypto_blkcipher *tfm,
+ void *iv, void *in, void *out,
+ int length); /* decryption function */
+};
+
struct krb5_ctx {
int initiate; /* 1 = initiating, 0 = accepting */
u32 enctype;
+ struct gss_krb5_enctype *gk5e; /* enctype-specific info */
struct crypto_blkcipher *enc;
struct crypto_blkcipher *seq;
s32 endtime;
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 1d52308..39643a7 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -59,13 +59,13 @@ krb5_encrypt(
{
u32 ret = -EINVAL;
struct scatterlist sg[1];
- u8 local_iv[16] = {0};
+ u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0};
struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv };
if (length % crypto_blkcipher_blocksize(tfm) != 0)
goto out;
- if (crypto_blkcipher_ivsize(tfm) > 16) {
+ if (crypto_blkcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) {
dprintk("RPC: gss_k5encrypt: tfm iv size too large %d\n",
crypto_blkcipher_ivsize(tfm));
goto out;
@@ -95,13 +95,13 @@ krb5_decrypt(
{
u32 ret = -EINVAL;
struct scatterlist sg[1];
- u8 local_iv[16] = {0};
+ u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0};
struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv };
if (length % crypto_blkcipher_blocksize(tfm) != 0)
goto out;
- if (crypto_blkcipher_ivsize(tfm) > 16) {
+ if (crypto_blkcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) {
dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n",
crypto_blkcipher_ivsize(tfm));
goto out;
@@ -164,7 +164,7 @@ out:
EXPORT_SYMBOL(make_checksum);
struct encryptor_desc {
- u8 iv[8]; /* XXX hard-coded blocksize */
+ u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
struct blkcipher_desc desc;
int pos;
struct xdr_buf *outbuf;
@@ -205,7 +205,7 @@ encryptor(struct scatterlist *sg, void *data)
desc->fraglen += sg->length;
desc->pos += sg->length;
- fraglen = thislen & 7; /* XXX hardcoded blocksize */
+ fraglen = thislen & (crypto_blkcipher_blocksize(desc->desc.tfm) - 1);
thislen -= fraglen;
if (thislen == 0)
@@ -265,7 +265,7 @@ gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
EXPORT_SYMBOL(gss_encrypt_xdr_buf);
struct decryptor_desc {
- u8 iv[8]; /* XXX hard-coded blocksize */
+ u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
struct blkcipher_desc desc;
struct scatterlist frags[4];
int fragno;
@@ -287,7 +287,7 @@ decryptor(struct scatterlist *sg, void *data)
desc->fragno++;
desc->fraglen += sg->length;
- fraglen = thislen & 7; /* XXX hardcoded blocksize */
+ fraglen = thislen & (crypto_blkcipher_blocksize(desc->desc.tfm) - 1);
thislen -= fraglen;
if (thislen == 0)
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index f0f0749..fe88266 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -48,6 +48,50 @@
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
+static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
+ /*
+ * DES (All DES enctypes are mapped to the same gss functionality)
+ */
+ {
+ .etype = ENCTYPE_DES_CBC_RAW,
+ .ctype = CKSUMTYPE_RSA_MD5,
+ .name = "des-cbc-crc",
+ .encrypt_name = "cbc(des)",
+ .cksum_name = "md5",
+ .encrypt = krb5_encrypt,
+ .decrypt = krb5_decrypt,
+ .signalg = SGN_ALG_DES_MAC_MD5,
+ .sealalg = SEAL_ALG_DES,
+ .keybytes = 7,
+ .keylength = 8,
+ .blocksize = 8,
+ .cksumlength = 8,
+ },
+};
+
+static int num_supported_enctypes =
+ sizeof(supported_gss_krb5_enctypes) / sizeof(struct gss_krb5_enctype);
+
+static int
+supported_gss_krb5_enctype(int etype)
+{
+ int i;
+ for (i = 0; i < num_supported_enctypes; i++)
+ if (supported_gss_krb5_enctypes[i].etype == etype)
+ return 1;
+ return 0;
+}
+
+static struct gss_krb5_enctype *
+get_gss_krb5_enctype(int etype)
+{
+ int i;
+ for (i = 0; i < num_supported_enctypes; i++)
+ if (supported_gss_krb5_enctypes[i].etype == etype)
+ return &supported_gss_krb5_enctypes[i];
+ return NULL;
+}
+
static const void *
simple_get_bytes(const void *p, const void *end, void *res, int len)
{
@@ -78,35 +122,45 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
}
static inline const void *
-get_key(const void *p, const void *end, struct crypto_blkcipher **res)
+get_key(const void *p, const void *end,
+ struct krb5_ctx *ctx, struct crypto_blkcipher **res)
{
struct xdr_netobj key;
int alg;
- char *alg_name;
p = simple_get_bytes(p, end, &alg, sizeof(alg));
if (IS_ERR(p))
goto out_err;
+
+ switch (alg) {
+ case ENCTYPE_DES_CBC_CRC:
+ case ENCTYPE_DES_CBC_MD4:
+ case ENCTYPE_DES_CBC_MD5:
+ /* Map all these key types to ENCTYPE_DES_CBC_RAW */
+ alg = ENCTYPE_DES_CBC_RAW;
+ break;
+ }
+
+ if (!supported_gss_krb5_enctype(alg)) {
+ printk("gss_kerberos_mech: unsupported encryption "
+ "key algorithm %d\n", alg);
+ goto out_err;
+ }
p = simple_get_netobj(p, end, &key);
if (IS_ERR(p))
goto out_err;
- switch (alg) {
- case ENCTYPE_DES_CBC_RAW:
- alg_name = "cbc(des)";
- break;
- default:
- printk("gss_kerberos_mech: unsupported algorithm %d\n", alg);
- goto out_err_free_key;
- }
- *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC);
+ *res = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0,
+ CRYPTO_ALG_ASYNC);
if (IS_ERR(*res)) {
- printk("gss_kerberos_mech: unable to initialize crypto algorithm %s\n", alg_name);
+ printk("gss_kerberos_mech: unable to initialize crypto "
+ "algorithm %s\n", ctx->gk5e->encrypt_name);
*res = NULL;
goto out_err_free_key;
}
if (crypto_blkcipher_setkey(*res, key.data, key.len)) {
- printk("gss_kerberos_mech: error setting key for crypto algorithm %s\n", alg_name);
+ printk("gss_kerberos_mech: error setting key for crypto "
+ "algorithm %s\n", ctx->gk5e->encrypt_name);
goto out_err_free_tfm;
}
@@ -134,6 +188,10 @@ gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx)
/* Old format supports only DES! Any other enctype uses new format */
ctx->enctype = ENCTYPE_DES_CBC_RAW;
+ ctx->gk5e = get_gss_krb5_enctype(ctx->enctype);
+ if (ctx->gk5e == NULL)
+ goto out_err;
+
/* The downcall format was designed before we completely understood
* the uses of the context fields; so it includes some stuff we
* just give some minimal sanity-checking, and some we ignore
@@ -164,10 +222,10 @@ gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx)
p = simple_get_netobj(p, end, &ctx->mech_used);
if (IS_ERR(p))
goto out_err;
- p = get_key(p, end, &ctx->enc);
+ p = get_key(p, end, ctx, &ctx->enc);
if (IS_ERR(p))
goto out_err_free_mech;
- p = get_key(p, end, &ctx->seq);
+ p = get_key(p, end, ctx, &ctx->seq);
if (IS_ERR(p))
goto out_err_free_key1;
if (p != end) {
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 3b9cc47..64cabf2 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -71,37 +71,47 @@
DEFINE_SPINLOCK(krb5_seq_lock);
+static char *
+setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token)
+{
+ __be16 *ptr, *krb5_hdr;
+ int body_size = 16 + ctx->gk5e->cksumlength;
+
+ token->len = g_token_size(&ctx->mech_used, body_size);
+
+ ptr = (__be16 *)token->data;
+ g_make_token_header(&ctx->mech_used, body_size, (unsigned char **)&ptr);
+
+ /* ptr now at start of header described in rfc 1964, section 1.2.1: */
+ krb5_hdr = ptr;
+ *ptr++ = KG_TOK_MIC_MSG;
+ *ptr++ = cpu_to_le16(ctx->gk5e->signalg);
+ *ptr++ = SEAL_ALG_NONE;
+ *ptr++ = 0xffff;
+
+ return (char *)krb5_hdr;
+}
+
static u32
gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
struct xdr_netobj *token)
{
- char cksumdata[16];
- struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
- unsigned char *ptr, *krb5_hdr, *msg_start;
+ char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+ struct xdr_netobj md5cksum = {.len = sizeof(cksumdata),
+ .data = cksumdata};
+ void *krb5_hdr;
s32 now;
u32 seq_send;
- dprintk("RPC: gss_krb5_seal\n");
+ dprintk("RPC: %s\n", __func__);
BUG_ON(ctx == NULL);
now = get_seconds();
- token->len = g_token_size(&ctx->mech_used, 24);
-
- ptr = token->data;
- g_make_token_header(&ctx->mech_used, 24, &ptr);
-
- *ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
- *ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff);
-
- /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */
- krb5_hdr = ptr - 2;
- msg_start = krb5_hdr + 24;
-
- *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5);
- memset(krb5_hdr + 4, 0xff, 4);
+ krb5_hdr = setup_token(ctx, token);
- if (make_checksum("md5", krb5_hdr, 8, text, 0, &md5cksum))
+ if (make_checksum((char *)ctx->gk5e->cksum_name, krb5_hdr, 8,
+ text, 0, &md5cksum))
return GSS_S_FAILURE;
if (krb5_encrypt(ctx->seq, NULL, md5cksum.data,
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 211eca4..43bd213 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -77,8 +77,9 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
{
int signalg;
int sealalg;
- char cksumdata[16];
- struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
+ char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+ struct xdr_netobj md5cksum = {.len = sizeof(cksumdata),
+ .data = cksumdata};
s32 now;
int direction;
s32 seqnum;
@@ -98,7 +99,7 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
/* XXX sanity-check bodysize?? */
signalg = ptr[0] + (ptr[1] << 8);
- if (signalg != SGN_ALG_DES_MAC_MD5)
+ if (signalg != ctx->gk5e->signalg)
return GSS_S_DEFECTIVE_TOKEN;
sealalg = ptr[2] + (ptr[3] << 8);
@@ -108,13 +109,14 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;
- if (make_checksum("md5", ptr - 2, 8, message_buffer, 0, &md5cksum))
+ if (make_checksum((char *)ctx->gk5e->cksum_name, ptr - 2, 8,
+ message_buffer, 0, &md5cksum))
return GSS_S_FAILURE;
if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, 16))
return GSS_S_FAILURE;
- if (memcmp(md5cksum.data + 8, ptr + 14, 8))
+ if (memcmp(md5cksum.data + 8, ptr + 14, ctx->gk5e->cksumlength))
return GSS_S_BAD_SIG;
/* it got through unscathed. Make sure the context is unexpired */
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 9f13411..e369696 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -102,8 +102,9 @@ static u32
gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
struct xdr_buf *buf, struct page **pages)
{
- char cksumdata[16];
- struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
+ char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+ struct xdr_netobj md5cksum = {.len = sizeof(cksumdata),
+ .data = cksumdata};
int blocksize = 0, plainlen;
unsigned char *ptr, *krb5_hdr, *msg_start;
s32 now;
@@ -111,7 +112,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
struct page **tmp_pages;
u32 seq_send;
- dprintk("RPC: gss_wrap_kerberos\n");
+ dprintk("RPC: %s\n", __func__);
now = get_seconds();
@@ -120,8 +121,8 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
BUG_ON((buf->len - offset) % blocksize);
plainlen = blocksize + buf->len - offset;
- headlen = g_token_size(&kctx->mech_used, 24 + plainlen) -
- (buf->len - offset);
+ headlen = g_token_size(&kctx->mech_used,
+ 16 + kctx->gk5e->cksumlength + plainlen) - (buf->len - offset);
ptr = buf->head[0].iov_base + offset;
/* shift data to make room for header. */
@@ -132,7 +133,8 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
buf->len += headlen;
BUG_ON((buf->len - offset - headlen) % blocksize);
- g_make_token_header(&kctx->mech_used, 24 + plainlen, &ptr);
+ g_make_token_header(&kctx->mech_used,
+ 16 + kctx->gk5e->cksumlength + plainlen, &ptr);
*ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff);
@@ -140,18 +142,18 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
/* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */
krb5_hdr = ptr - 2;
- msg_start = krb5_hdr + 24;
+ msg_start = krb5_hdr + 16 + kctx->gk5e->cksumlength;
- *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5);
+ *(__be16 *)(krb5_hdr + 2) = cpu_to_le16(kctx->gk5e->signalg);
memset(krb5_hdr + 4, 0xff, 4);
- *(__be16 *)(krb5_hdr + 4) = htons(SEAL_ALG_DES);
+ *(__be16 *)(krb5_hdr + 4) = cpu_to_le16(kctx->gk5e->sealalg);
make_confounder(msg_start, blocksize);
/* XXXJBF: UGH!: */
tmp_pages = buf->pages;
buf->pages = pages;
- if (make_checksum("md5", krb5_hdr, 8, buf,
+ if (make_checksum((char *)kctx->gk5e->cksum_name, krb5_hdr, 8, buf,
offset + headlen - blocksize, &md5cksum))
return GSS_S_FAILURE;
buf->pages = tmp_pages;
@@ -183,8 +185,9 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
{
int signalg;
int sealalg;
- char cksumdata[16];
- struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
+ char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+ struct xdr_netobj md5cksum = {.len = sizeof(cksumdata),
+ .data = cksumdata};
s32 now;
int direction;
s32 seqnum;
@@ -193,6 +196,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
void *data_start, *orig_start;
int data_len;
int blocksize;
+ int crypt_offset;
dprintk("RPC: gss_unwrap_kerberos\n");
@@ -210,29 +214,34 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
/* get the sign and seal algorithms */
signalg = ptr[0] + (ptr[1] << 8);
- if (signalg != SGN_ALG_DES_MAC_MD5)
+ if (signalg != kctx->gk5e->signalg)
return GSS_S_DEFECTIVE_TOKEN;
sealalg = ptr[2] + (ptr[3] << 8);
- if (sealalg != SEAL_ALG_DES)
+ if (sealalg != kctx->gk5e->sealalg)
return GSS_S_DEFECTIVE_TOKEN;
if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;
- if (gss_decrypt_xdr_buf(kctx->enc, buf,
- ptr + 22 - (unsigned char *)buf->head[0].iov_base))
+ /*
+ * Data starts after token header and checksum. ptr points
+ * two past the beginning of the token header (which is 16 bytes)
+ */
+ crypt_offset = ptr + (16 - 2 + kctx->gk5e->cksumlength) -
+ (unsigned char *)buf->head[0].iov_base;
+ if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset))
return GSS_S_DEFECTIVE_TOKEN;
- if (make_checksum("md5", ptr - 2, 8, buf,
- ptr + 22 - (unsigned char *)buf->head[0].iov_base, &md5cksum))
+ if (make_checksum((char *)kctx->gk5e->cksum_name, ptr - 2, 8, buf,
+ crypt_offset, &md5cksum))
return GSS_S_FAILURE;
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
md5cksum.data, md5cksum.len))
return GSS_S_FAILURE;
- if (memcmp(md5cksum.data + 8, ptr + 14, 8))
+ if (memcmp(md5cksum.data + 8, ptr + 14, 8))/* this is still DES-aware */
return GSS_S_BAD_SIG;
/* it got through unscathed. Make sure the context is unexpired */
@@ -256,7 +265,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
* better to copy and encrypt at the same time. */
blocksize = crypto_blkcipher_blocksize(kctx->enc);
- data_start = ptr + 22 + blocksize;
+ data_start = ptr + (16 - 2 + kctx->gk5e->cksumlength) + blocksize;
orig_start = buf->head[0].iov_base + offset;
data_len = (buf->head[0].iov_base + buf->head[0].iov_len) - data_start;
memmove(orig_start, data_start, data_len);
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 12/19] gss_krb5: add ability to have a keyed checksum (hmac)
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (10 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 11/19] gss_krb5: introduce encryption type framework Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
2008-02-21 18:44 ` [PATCH 13/19] gss_krb5: import functionality to derive keys into the kernel Kevin Coffman
` (6 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
Encryption types besides DES may use a keyed checksum (hmac).
Modify the make_checksum() function to allow for a key
and take care of enctype-specific processing such as truncating
the resulting hash.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 11 +++++--
net/sunrpc/auth_gss/gss_krb5_crypto.c | 54 ++++++++++++++++++++++++++++-----
net/sunrpc/auth_gss/gss_krb5_mech.c | 1 +
net/sunrpc/auth_gss/gss_krb5_seal.c | 13 ++++----
net/sunrpc/auth_gss/gss_krb5_unseal.c | 13 +++++---
net/sunrpc/auth_gss/gss_krb5_wrap.c | 29 ++++++++++--------
6 files changed, 87 insertions(+), 34 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index d10d8ce..c33a657 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -41,6 +41,9 @@
#include <linux/sunrpc/gss_err.h>
#include <linux/sunrpc/gss_asn1.h>
+/* Maximum key length (in bytes) for the supported crypto algorithms*/
+#define GSS_KRB5_MAX_KEYLEN 32
+
/* Maximum checksum function output for the supported crypto algorithms */
#define GSS_KRB5_MAX_CKSUM_LEN 20
@@ -74,6 +77,7 @@ struct krb5_ctx {
struct gss_krb5_enctype *gk5e; /* enctype-specific info */
struct crypto_blkcipher *enc;
struct crypto_blkcipher *seq;
+ u8 cksum[GSS_KRB5_MAX_KEYLEN];
s32 endtime;
u32 seq_send;
struct xdr_netobj mech_used;
@@ -142,9 +146,10 @@ extern struct xdr_netobj krb5_oid;
#define ENCTYPE_DES3_CBC_SHA1 0x0010
#define ENCTYPE_UNKNOWN 0x01ff
-s32
-make_checksum(char *, char *header, int hdrlen, struct xdr_buf *body,
- int body_offset, struct xdr_netobj *cksum);
+u32
+make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
+ struct xdr_buf *body, int body_offset, u8 *cksumkey,
+ struct xdr_netobj *cksumout);
u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *,
struct xdr_netobj *);
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 39643a7..8b12f34 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -128,21 +128,42 @@ checksummer(struct scatterlist *sg, void *data)
return crypto_hash_update(desc, sg, sg->length);
}
-/* checksum the plaintext data and hdrlen bytes of the token header */
-s32
-make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body,
- int body_offset, struct xdr_netobj *cksum)
+/*
+ * checksum the plaintext data and hdrlen bytes of the token header
+ * The checksum is performed over the first 8 bytes of the
+ * gss token header and then over the data body
+ */
+u32
+make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
+ struct xdr_buf *body, int body_offset, u8 *cksumkey,
+ struct xdr_netobj *cksumout)
{
- struct hash_desc desc; /* XXX add to ctx? */
+ struct hash_desc desc;
struct scatterlist sg[1];
int err;
+ u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+ unsigned int checksumlen;
+
+ if (cksumout->len < kctx->gk5e->cksumlength) {
+ dprintk("%s: checksum buffer length, %u, too small for %s\n",
+ __func__, cksumout->len, kctx->gk5e->name);
+ return GSS_S_FAILURE;
+ }
- desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC);
+ desc.tfm = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(desc.tfm))
return GSS_S_FAILURE;
- cksum->len = crypto_hash_digestsize(desc.tfm);
desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ checksumlen = crypto_hash_digestsize(desc.tfm);
+
+ if (cksumkey != NULL) {
+ err = crypto_hash_setkey(desc.tfm, cksumkey,
+ kctx->gk5e->keylength);
+ if (err)
+ goto out;
+ }
+
err = crypto_hash_init(&desc);
if (err)
goto out;
@@ -154,8 +175,25 @@ make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body,
checksummer, &desc);
if (err)
goto out;
- err = crypto_hash_final(&desc, cksum->data);
+ err = crypto_hash_final(&desc, checksumdata);
+ if (err)
+ goto out;
+ switch (kctx->gk5e->ctype) {
+ case CKSUMTYPE_RSA_MD5:
+ err = kctx->gk5e->encrypt(kctx->seq, NULL, checksumdata,
+ checksumdata, checksumlen);
+ if (err)
+ goto out;
+ memcpy(cksumout->data,
+ checksumdata + checksumlen - kctx->gk5e->cksumlength,
+ kctx->gk5e->cksumlength);
+ break;
+ default:
+ BUG();
+ break;
+ }
+ cksumout->len = kctx->gk5e->cksumlength;
out:
crypto_free_hash(desc.tfm);
return err ? GSS_S_FAILURE : 0;
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index fe88266..28335cc 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -66,6 +66,7 @@ static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
.keylength = 8,
.blocksize = 8,
.cksumlength = 8,
+ .keyed_cksum = 0,
},
};
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 64cabf2..f5badc7 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -102,6 +102,7 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
void *krb5_hdr;
s32 now;
u32 seq_send;
+ u8 *cksumkey;
dprintk("RPC: %s\n", __func__);
BUG_ON(ctx == NULL);
@@ -110,15 +111,15 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
krb5_hdr = setup_token(ctx, token);
- if (make_checksum((char *)ctx->gk5e->cksum_name, krb5_hdr, 8,
- text, 0, &md5cksum))
- return GSS_S_FAILURE;
+ if (ctx->gk5e->keyed_cksum)
+ cksumkey = ctx->cksum;
+ else
+ cksumkey = NULL;
- if (krb5_encrypt(ctx->seq, NULL, md5cksum.data,
- md5cksum.data, md5cksum.len))
+ if (make_checksum(ctx, krb5_hdr, 8, text, 0, cksumkey, &md5cksum))
return GSS_S_FAILURE;
- memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
+ memcpy(krb5_hdr + 16, md5cksum.data, md5cksum.len);
spin_lock(&krb5_seq_lock);
seq_send = ctx->seq_send++;
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 43bd213..5494ba4 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -85,6 +85,7 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
s32 seqnum;
unsigned char *ptr = (unsigned char *)read_token->data;
int bodysize;
+ u8 *cksumkey;
dprintk("RPC: krb5_read_token\n");
@@ -109,14 +110,16 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;
- if (make_checksum((char *)ctx->gk5e->cksum_name, ptr - 2, 8,
- message_buffer, 0, &md5cksum))
- return GSS_S_FAILURE;
+ if (ctx->gk5e->keyed_cksum)
+ cksumkey = ctx->cksum;
+ else
+ cksumkey = NULL;
- if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, 16))
+ if (make_checksum(ctx, ptr - 2, 8, message_buffer, 0,
+ cksumkey, &md5cksum))
return GSS_S_FAILURE;
- if (memcmp(md5cksum.data + 8, ptr + 14, ctx->gk5e->cksumlength))
+ if (memcmp(md5cksum.data, ptr + 14, ctx->gk5e->cksumlength))
return GSS_S_BAD_SIG;
/* it got through unscathed. Make sure the context is unexpired */
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index e369696..dd6caf3 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -111,6 +111,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
int headlen;
struct page **tmp_pages;
u32 seq_send;
+ u8 *cksumkey;
dprintk("RPC: %s\n", __func__);
@@ -150,18 +151,20 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
make_confounder(msg_start, blocksize);
+ if (kctx->gk5e->keyed_cksum)
+ cksumkey = kctx->cksum;
+ else
+ cksumkey = NULL;
+
/* XXXJBF: UGH!: */
tmp_pages = buf->pages;
buf->pages = pages;
- if (make_checksum((char *)kctx->gk5e->cksum_name, krb5_hdr, 8, buf,
- offset + headlen - blocksize, &md5cksum))
+ if (make_checksum(kctx, krb5_hdr, 8, buf, offset + headlen - blocksize,
+ cksumkey, &md5cksum))
return GSS_S_FAILURE;
buf->pages = tmp_pages;
- if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
- md5cksum.data, md5cksum.len))
- return GSS_S_FAILURE;
- memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
+ memcpy(krb5_hdr + 16, md5cksum.data, md5cksum.len);
spin_lock(&krb5_seq_lock);
seq_send = kctx->seq_send++;
@@ -197,6 +200,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
int data_len;
int blocksize;
int crypt_offset;
+ u8 *cksumkey;
dprintk("RPC: gss_unwrap_kerberos\n");
@@ -233,15 +237,16 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset))
return GSS_S_DEFECTIVE_TOKEN;
- if (make_checksum((char *)kctx->gk5e->cksum_name, ptr - 2, 8, buf,
- crypt_offset, &md5cksum))
- return GSS_S_FAILURE;
+ if (kctx->gk5e->keyed_cksum)
+ cksumkey = kctx->cksum;
+ else
+ cksumkey = NULL;
- if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
- md5cksum.data, md5cksum.len))
+ if (make_checksum(kctx, ptr - 2, 8, buf, crypt_offset,
+ cksumkey, &md5cksum))
return GSS_S_FAILURE;
- if (memcmp(md5cksum.data + 8, ptr + 14, 8))/* this is still DES-aware */
+ if (memcmp(md5cksum.data, ptr + 14, kctx->gk5e->cksumlength))
return GSS_S_BAD_SIG;
/* it got through unscathed. Make sure the context is unexpired */
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 13/19] gss_krb5: import functionality to derive keys into the kernel
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (11 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 12/19] gss_krb5: add ability to have a keyed checksum (hmac) Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
2008-02-21 18:44 ` [PATCH 14/19] gss_krb5: use a global static OID value for krb5 Kevin Coffman
` (5 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
Import the code to derive Kerberos keys from a base key into the
kernel. This will allow us to change the format of the context
information sent down from gssd to include only a single key.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 30 ++++
net/sunrpc/auth_gss/Makefile | 4 -
net/sunrpc/auth_gss/gss_krb5_keys.c | 255 +++++++++++++++++++++++++++++++++++
net/sunrpc/auth_gss/gss_krb5_mech.c | 1
4 files changed, 288 insertions(+), 2 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index c33a657..d326911 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -41,6 +41,9 @@
#include <linux/sunrpc/gss_err.h>
#include <linux/sunrpc/gss_asn1.h>
+/* Length of constant used in key derivation */
+#define GSS_KRB5_K5CLENGTH 5
+
/* Maximum key length (in bytes) for the supported crypto algorithms*/
#define GSS_KRB5_MAX_KEYLEN 32
@@ -69,6 +72,9 @@ struct gss_krb5_enctype {
u32 (*decrypt) (struct crypto_blkcipher *tfm,
void *iv, void *in, void *out,
int length); /* decryption function */
+ u32 (*mk_key) (struct gss_krb5_enctype *gk5e,
+ struct xdr_netobj *in,
+ struct xdr_netobj *out); /* complete key generation */
};
struct krb5_ctx {
@@ -146,6 +152,25 @@ extern struct xdr_netobj krb5_oid;
#define ENCTYPE_DES3_CBC_SHA1 0x0010
#define ENCTYPE_UNKNOWN 0x01ff
+/*
+ * Constants used for key derivation
+ */
+/* for 3DES */
+#define KG_USAGE_SEAL 22
+#define KG_USAGE_SIGN 23
+#define KG_USAGE_SEQ 24
+
+/* from rfc3961 */
+#define KEY_USAGE_SEED_CHECKSUM 0x99
+#define KEY_USAGE_SEED_ENCRYPTION 0xAA
+#define KEY_USAGE_SEED_INTEGRITY 0x55
+
+/* from rfc4121 */
+#define KG_USAGE_ACCEPTOR_SEAL 22
+#define KG_USAGE_ACCEPTOR_SIGN 23
+#define KG_USAGE_INITIATOR_SEAL 24
+#define KG_USAGE_INITIATOR_SIGN 25
+
u32
make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
struct xdr_buf *body, int body_offset, u8 *cksumkey,
@@ -191,3 +216,8 @@ s32
krb5_get_seq_num(struct crypto_blkcipher *key,
unsigned char *cksum,
unsigned char *buf, int *direction, s32 * seqnum);
+
+u32 krb5_derive_key(struct gss_krb5_enctype *gk5e,
+ const struct xdr_netobj *inkey,
+ struct xdr_netobj *outkey,
+ const struct xdr_netobj *in_constant);
diff --git a/net/sunrpc/auth_gss/Makefile b/net/sunrpc/auth_gss/Makefile
index f3431a7..e8981e9 100644
--- a/net/sunrpc/auth_gss/Makefile
+++ b/net/sunrpc/auth_gss/Makefile
@@ -5,12 +5,12 @@
obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o
auth_rpcgss-objs := auth_gss.o gss_generic_token.o \
- gss_mech_switch.o svcauth_gss.o gss_krb5_crypto.o
+ gss_mech_switch.o svcauth_gss.o gss_debug.o
obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \
- gss_krb5_seqnum.o gss_krb5_wrap.o
+ gss_krb5_seqnum.o gss_krb5_wrap.o gss_krb5_crypto.o gss_krb5_keys.o
obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o
diff --git a/net/sunrpc/auth_gss/gss_krb5_keys.c b/net/sunrpc/auth_gss/gss_krb5_keys.c
new file mode 100644
index 0000000..97ec67d
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_krb5_keys.c
@@ -0,0 +1,255 @@
+/*
+ * linux/net/sunrpc/gss_krb5_keys.c
+ *
+ * COPYRIGHT (c) 2008
+ * The Regents of the University of Michigan
+ * ALL RIGHTS RESERVED
+ *
+ * Permission is granted to use, copy, create derivative works
+ * and redistribute this software and such derivative works
+ * for any purpose, so long as the name of The University of
+ * Michigan is not used in any advertising or publicity
+ * pertaining to the use of distribution of this software
+ * without specific, written prior authorization. If the
+ * above copyright notice or any other identification of the
+ * University of Michigan is included in any copy of any
+ * portion of this software, then the disclaimer below must
+ * also be included.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
+ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
+ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
+ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGES.
+ */
+
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/sunrpc/gss_krb5.h>
+#include <linux/sunrpc/xdr.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY RPCDBG_AUTH
+#endif
+
+/*
+ * This is the n-fold function as described in rfc3961, sec 5.1
+ * Taken from MIT Kerberos and modified.
+ */
+
+static void krb5_nfold(u32 inbits, const u8 *in,
+ u32 outbits, u8 *out)
+{
+ int a, b, c, lcm;
+ int byte, i, msbit;
+
+ /* the code below is more readable if I make these bytes
+ instead of bits */
+
+ inbits >>= 3;
+ outbits >>= 3;
+
+ /* first compute lcm(n,k) */
+
+ a = outbits;
+ b = inbits;
+
+ while (b != 0) {
+ c = b;
+ b = a%b;
+ a = c;
+ }
+
+ lcm = outbits*inbits/a;
+
+ /* now do the real work */
+
+ memset(out, 0, outbits);
+ byte = 0;
+
+ /* this will end up cycling through k lcm(k,n)/k times, which
+ is correct */
+ for (i = lcm-1; i >= 0; i--) {
+ /* compute the msbit in k which gets added into this byte */
+ msbit = (
+ /* first, start with the msbit in the first,
+ * unrotated byte */
+ ((inbits << 3) - 1)
+ /* then, for each byte, shift to the right
+ * for each repetition */
+ + (((inbits << 3) + 13) * (i/inbits))
+ /* last, pick out the correct byte within
+ * that shifted repetition */
+ + ((inbits - (i % inbits)) << 3)
+ ) % (inbits << 3);
+
+ /* pull out the byte value itself */
+ byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)|
+ (in[((inbits) - (msbit >> 3)) % inbits]))
+ >> ((msbit & 7) + 1)) & 0xff;
+
+ /* do the addition */
+ byte += out[i % outbits];
+ out[i % outbits] = byte & 0xff;
+
+ /* keep around the carry bit, if any */
+ byte >>= 8;
+
+ }
+
+ /* if there's a carry bit left over, add it back in */
+ if (byte) {
+ for (i = outbits - 1; i >= 0; i--) {
+ /* do the addition */
+ byte += out[i];
+ out[i] = byte & 0xff;
+
+ /* keep around the carry bit, if any */
+ byte >>= 8;
+ }
+ }
+}
+
+/*
+ * This is the DK (derive_key) function as described in rfc3961, sec 5.1
+ * Taken from MIT Kerberos and modified.
+ */
+
+u32 krb5_derive_key(struct gss_krb5_enctype *gk5e,
+ const struct xdr_netobj *inkey,
+ struct xdr_netobj *outkey,
+ const struct xdr_netobj *in_constant)
+{
+ size_t blocksize, keybytes, keylength, n;
+ unsigned char *inblockdata, *outblockdata, *rawkey;
+ struct xdr_netobj inblock, outblock;
+ struct crypto_blkcipher *cipher;
+ u32 ret = EINVAL;
+
+ blocksize = gk5e->blocksize;
+ keybytes = gk5e->keybytes;
+ keylength = gk5e->keylength;
+
+ if ((inkey->len != keylength) || (outkey->len != keylength))
+ goto err_return;
+
+ cipher = crypto_alloc_blkcipher(gk5e->encrypt_name, 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(cipher))
+ goto err_return;
+ if (crypto_blkcipher_setkey(cipher, inkey->data, inkey->len))
+ goto err_return;
+
+ /* allocate and set up buffers */
+
+ ret = ENOMEM;
+ inblockdata = kmalloc(blocksize, GFP_KERNEL);
+ if (inblockdata == NULL)
+ goto err_free_cipher;
+
+ outblockdata = kmalloc(blocksize, GFP_KERNEL);
+ if (outblockdata == NULL)
+ goto err_free_in;
+
+ rawkey = kmalloc(keybytes, GFP_KERNEL);
+ if (rawkey == NULL)
+ goto err_free_out;
+
+ inblock.data = (char *) inblockdata;
+ inblock.len = blocksize;
+
+ outblock.data = (char *) outblockdata;
+ outblock.len = blocksize;
+
+ /* initialize the input block */
+
+ if (in_constant->len == inblock.len) {
+ memcpy(inblock.data, in_constant->data, inblock.len);
+ } else {
+ krb5_nfold(in_constant->len * 8, in_constant->data,
+ inblock.len * 8, inblock.data);
+ }
+
+ /* loop encrypting the blocks until enough key bytes are generated */
+
+ n = 0;
+ while (n < keybytes) {
+ (*(gk5e->encrypt))(cipher, NULL, inblock.data,
+ outblock.data, inblock.len);
+
+ if ((keybytes - n) <= outblock.len) {
+ memcpy(rawkey + n, outblock.data, (keybytes - n));
+ break;
+ }
+
+ memcpy(rawkey + n, outblock.data, outblock.len);
+ memcpy(inblock.data, outblock.data, outblock.len);
+ n += outblock.len;
+ }
+
+ /* postprocess the key */
+
+ inblock.data = (char *) rawkey;
+ inblock.len = keybytes;
+
+ BUG_ON(gk5e->mk_key == NULL);
+ ret = (*(gk5e->mk_key))(gk5e, &inblock, outkey);
+ if (ret) {
+ dprintk("%s: got %d from mk_key function for '%s'\n",
+ __func__, ret, gk5e->encrypt_name);
+ goto err_free_raw;
+ }
+
+ /* clean memory, free resources and exit */
+
+ ret = 0;
+
+err_free_raw:
+ memset(rawkey, 0, keybytes);
+ kfree(rawkey);
+err_free_out:
+ memset(outblockdata, 0, blocksize);
+ kfree(outblockdata);
+err_free_in:
+ memset(inblockdata, 0, blocksize);
+ kfree(inblockdata);
+err_free_cipher:
+ crypto_free_blkcipher(cipher);
+err_return:
+ return ret;
+}
+EXPORT_SYMBOL(krb5_derive_key);
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 28335cc..83973c8 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -60,6 +60,7 @@ static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
.cksum_name = "md5",
.encrypt = krb5_encrypt,
.decrypt = krb5_decrypt,
+ .mk_key = NULL,
.signalg = SGN_ALG_DES_MAC_MD5,
.sealalg = SEAL_ALG_DES,
.keybytes = 7,
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 14/19] gss_krb5: use a global static OID value for krb5
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (12 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 13/19] gss_krb5: import functionality to derive keys into the kernel Kevin Coffman
@ 2008-02-21 18:44 ` Kevin Coffman
2008-02-21 18:45 ` [PATCH 15/19] gss_krb5: handle new context format from gssd Kevin Coffman
` (4 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:44 UTC (permalink / raw)
To: linux-nfs
Rather than depend on the mechanism oid passed down with the context
information, use a static version. The new context format introduced
later will not include the oid.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/auth_gss/gss_krb5_seal.c | 4 ++--
net/sunrpc/auth_gss/gss_krb5_unseal.c | 2 +-
net/sunrpc/auth_gss/gss_krb5_wrap.c | 6 +++---
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index f5badc7..285188d 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -77,10 +77,10 @@ setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token)
__be16 *ptr, *krb5_hdr;
int body_size = 16 + ctx->gk5e->cksumlength;
- token->len = g_token_size(&ctx->mech_used, body_size);
+ token->len = g_token_size(&krb5_oid, body_size);
ptr = (__be16 *)token->data;
- g_make_token_header(&ctx->mech_used, body_size, (unsigned char **)&ptr);
+ g_make_token_header(&krb5_oid, body_size, (unsigned char **)&ptr);
/* ptr now at start of header described in rfc 1964, section 1.2.1: */
krb5_hdr = ptr;
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 5494ba4..c9adcfc 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -89,7 +89,7 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
dprintk("RPC: krb5_read_token\n");
- if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr,
+ if (g_verify_token_header(&krb5_oid, &bodysize, &ptr,
read_token->len))
return GSS_S_DEFECTIVE_TOKEN;
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index dd6caf3..a68677c 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -122,7 +122,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
BUG_ON((buf->len - offset) % blocksize);
plainlen = blocksize + buf->len - offset;
- headlen = g_token_size(&kctx->mech_used,
+ headlen = g_token_size(&krb5_oid,
16 + kctx->gk5e->cksumlength + plainlen) - (buf->len - offset);
ptr = buf->head[0].iov_base + offset;
@@ -134,7 +134,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
buf->len += headlen;
BUG_ON((buf->len - offset - headlen) % blocksize);
- g_make_token_header(&kctx->mech_used,
+ g_make_token_header(&krb5_oid,
16 + kctx->gk5e->cksumlength + plainlen, &ptr);
@@ -205,7 +205,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
dprintk("RPC: gss_unwrap_kerberos\n");
ptr = (u8 *)buf->head[0].iov_base + offset;
- if (g_verify_token_header(&kctx->mech_used, &bodysize, &ptr,
+ if (g_verify_token_header(&krb5_oid, &bodysize, &ptr,
buf->len - offset))
return GSS_S_DEFECTIVE_TOKEN;
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 15/19] gss_krb5: handle new context format from gssd
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (13 preceding siblings ...)
2008-02-21 18:44 ` [PATCH 14/19] gss_krb5: use a global static OID value for krb5 Kevin Coffman
@ 2008-02-21 18:45 ` Kevin Coffman
2008-02-21 18:45 ` [PATCH 16/19] gss_krb5: add support for triple-des encryption Kevin Coffman
` (3 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:45 UTC (permalink / raw)
To: linux-nfs
For encryption types other than DES, gssd sends down context information
in a new format. This new format includes the information needed to
support the new Kerberos GSS-API tokens defined in rfc4121.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 19 +++
net/sunrpc/auth_gss/gss_krb5_mech.c | 236 +++++++++++++++++++++++++++++++++++
2 files changed, 254 insertions(+), 1 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index d326911..e828e98 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -77,16 +77,31 @@ struct gss_krb5_enctype {
struct xdr_netobj *out); /* complete key generation */
};
+/* krb5_ctx flags definitions */
+#define KRB5_CTX_FLAG_INITIATOR 0x00000001
+#define KRB5_CTX_FLAG_CFX 0x00000002
+#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
+
struct krb5_ctx {
int initiate; /* 1 = initiating, 0 = accepting */
u32 enctype;
+ u32 flags;
struct gss_krb5_enctype *gk5e; /* enctype-specific info */
struct crypto_blkcipher *enc;
struct crypto_blkcipher *seq;
+ struct crypto_blkcipher *acceptor_enc;
+ struct crypto_blkcipher *initiator_enc;
u8 cksum[GSS_KRB5_MAX_KEYLEN];
s32 endtime;
u32 seq_send;
+ u64 seq_send64;
struct xdr_netobj mech_used;
+ u8 initiator_sign[GSS_KRB5_MAX_KEYLEN];
+ u8 acceptor_sign[GSS_KRB5_MAX_KEYLEN];
+ u8 initiator_seal[GSS_KRB5_MAX_KEYLEN];
+ u8 acceptor_seal[GSS_KRB5_MAX_KEYLEN];
+ u8 initiator_integ[GSS_KRB5_MAX_KEYLEN];
+ u8 acceptor_integ[GSS_KRB5_MAX_KEYLEN];
};
extern spinlock_t krb5_seq_lock;
@@ -150,6 +165,10 @@ extern struct xdr_netobj krb5_oid;
#define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */
#define ENCTYPE_DES_HMAC_SHA1 0x0008
#define ENCTYPE_DES3_CBC_SHA1 0x0010
+#define ENCTYPE_AES128_CTS_HMAC_SHA1_96 0x0011
+#define ENCTYPE_AES256_CTS_HMAC_SHA1_96 0x0012
+#define ENCTYPE_ARCFOUR_HMAC 0x0017
+#define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018
#define ENCTYPE_UNKNOWN 0x01ff
/*
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 83973c8..fc30538 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -247,6 +247,238 @@ out_err:
return PTR_ERR(p);
}
+struct crypto_blkcipher *
+context_v2_alloc_cipher(struct krb5_ctx *ctx, u8 *key)
+{
+ struct crypto_blkcipher *cp;
+
+ cp = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name,
+ 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(cp)) {
+ printk("gss_kerberos_mech: unable to initialize "
+ "crypto algorithm %s\n", ctx->gk5e->encrypt_name);
+ return NULL;
+ }
+ if (crypto_blkcipher_setkey(cp, key, ctx->gk5e->keylength)) {
+ printk("gss_kerberos_mech: error setting key for "
+ "crypto algorithm %s\n", ctx->gk5e->encrypt_name);
+ crypto_free_blkcipher(cp);
+ return NULL;
+ }
+ return cp;
+}
+
+static inline void
+set_cdata(u8 cdata[GSS_KRB5_K5CLENGTH], u32 usage, u8 seed)
+{
+ cdata[0] = (usage>>24)&0xff;
+ cdata[1] = (usage>>16)&0xff;
+ cdata[2] = (usage>>8)&0xff;
+ cdata[3] = usage&0xff;
+ cdata[4] = seed;
+}
+
+static int
+context_derive_keys_des3(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
+{
+ struct xdr_netobj c, keyin, keyout;
+ u8 cdata[GSS_KRB5_K5CLENGTH];
+#if 0
+ u8 derivedkey[GSS_KRB5_MAX_KEYLEN];
+#endif
+ u32 err;
+
+ c.len = GSS_KRB5_K5CLENGTH;
+ c.data = cdata;
+
+ keyin.data = rawkey;
+ keyin.len = keylen;
+ keyout.len = keylen;
+
+ /* seq uses the raw key */
+ ctx->seq = context_v2_alloc_cipher(ctx, rawkey);
+ if (ctx->seq == NULL)
+ goto out_err;
+
+#if 0
+ /* derive enc */
+ set_cdata(cdata, KG_USAGE_SEQ, KEY_USAGE_SEED_ENCRYPTION);
+ keyout.data = derivedkey;
+ err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
+ if (err) {
+ dprintk("%s: Error %d deriving enc key\n",
+ __func__, err);
+ goto out_free_seq;
+ }
+ ctx->enc = context_v2_alloc_cipher(ctx, derivedkey);
+#else
+ ctx->enc = context_v2_alloc_cipher(ctx, rawkey);
+#endif
+ if (ctx->enc == NULL)
+ goto out_free_seq;
+
+ /* derive cksum */
+ set_cdata(cdata, KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM);
+ keyout.data = ctx->cksum;
+ err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
+ if (err) {
+ dprintk("%s: Error %d deriving cksum key\n",
+ __func__, err);
+ goto out_free_enc;
+ }
+
+ return 0;
+
+out_free_enc:
+ crypto_free_blkcipher(ctx->enc);
+out_free_seq:
+ crypto_free_blkcipher(ctx->seq);
+out_err:
+ return -EINVAL;
+}
+
+static int
+context_derive_keys_new(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
+{
+ struct xdr_netobj c, keyin, keyout;
+ u8 cdata[GSS_KRB5_K5CLENGTH];
+ u32 err;
+
+ c.len = GSS_KRB5_K5CLENGTH;
+ c.data = cdata;
+
+ keyin.data = rawkey;
+ keyin.len = keylen;
+ keyout.len = keylen;
+
+ /* initiator seal encryption */
+ set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_ENCRYPTION);
+ keyout.data = ctx->initiator_seal;
+ err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
+ if (err) {
+ dprintk("%s: Error %d deriving initiator_seal key\n",
+ __func__, err);
+ goto out_err;
+ }
+ ctx->initiator_enc = context_v2_alloc_cipher(ctx, ctx->initiator_seal);
+ if (ctx->initiator_enc == NULL)
+ goto out_err;
+
+ /* acceptor seal encryption */
+ set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_ENCRYPTION);
+ keyout.data = ctx->acceptor_seal;
+ err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
+ if (err) {
+ dprintk("%s: Error %d deriving acceptor_seal key\n",
+ __func__, err);
+ goto out_free_initiator_enc;
+ }
+ ctx->acceptor_enc = context_v2_alloc_cipher(ctx, ctx->acceptor_seal);
+ if (ctx->acceptor_enc == NULL)
+ goto out_free_initiator_enc;
+
+ /* initiator sign checksum */
+ set_cdata(cdata, KG_USAGE_INITIATOR_SIGN, KEY_USAGE_SEED_CHECKSUM);
+ keyout.data = ctx->initiator_sign;
+ err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
+ if (err) {
+ dprintk("%s: Error %d deriving initiator_sign key\n",
+ __func__, err);
+ goto out_free_acceptor_enc;
+ }
+
+ /* acceptor sign checksum */
+ set_cdata(cdata, KG_USAGE_ACCEPTOR_SIGN, KEY_USAGE_SEED_CHECKSUM);
+ keyout.data = ctx->acceptor_sign;
+ err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
+ if (err) {
+ dprintk("%s: Error %d deriving acceptor_sign key\n",
+ __func__, err);
+ goto out_free_acceptor_enc;
+ }
+
+ /* initiator seal integrity */
+ set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_INTEGRITY);
+ keyout.data = ctx->initiator_integ;
+ err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
+ if (err) {
+ dprintk("%s: Error %d deriving initiator_integ key\n",
+ __func__, err);
+ goto out_free_acceptor_enc;
+ }
+
+ /* acceptor seal integrity */
+ set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_INTEGRITY);
+ keyout.data = ctx->acceptor_integ;
+ err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
+ if (err) {
+ dprintk("%s: Error %d deriving acceptor_integ key\n",
+ __func__, err);
+ goto out_free_acceptor_enc;
+ }
+
+ return 0;
+
+out_free_acceptor_enc:
+ crypto_free_blkcipher(ctx->acceptor_enc);
+out_free_initiator_enc:
+ crypto_free_blkcipher(ctx->initiator_enc);
+out_err:
+ return -EINVAL;
+}
+
+static int
+gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx)
+{
+ u8 rawkey[GSS_KRB5_MAX_KEYLEN];
+ int keylen;
+
+ p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags));
+ if (IS_ERR(p))
+ goto out_err;
+ ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR;
+
+ p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
+ if (IS_ERR(p))
+ goto out_err;
+ p = simple_get_bytes(p, end, &ctx->seq_send64, sizeof(ctx->seq_send64));
+ if (IS_ERR(p))
+ goto out_err;
+ p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype));
+ if (IS_ERR(p))
+ goto out_err;
+ ctx->gk5e = get_gss_krb5_enctype(ctx->enctype);
+ if (ctx->gk5e == NULL) {
+ printk("gss_kerberos_mech: unsupported krb5 enctype %u\n",
+ ctx->enctype);
+ p = ERR_PTR(-EINVAL);
+ goto out_err;
+ }
+ keylen = ctx->gk5e->keylength;
+
+ p = simple_get_bytes(p, end, rawkey, keylen);
+ if (IS_ERR(p))
+ goto out_err;
+
+ if (p != end) {
+ p = ERR_PTR(-EINVAL);
+ goto out_err;
+ }
+
+ switch (ctx->enctype) {
+ case ENCTYPE_DES3_CBC_RAW:
+ return context_derive_keys_des3(ctx, rawkey, keylen);
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ return context_derive_keys_new(ctx, rawkey, keylen);
+ default:
+ return -EINVAL;
+ }
+
+out_err:
+ return PTR_ERR(p);
+}
+
static int
gss_import_sec_context_kerberos(const void *p, size_t len,
struct gss_ctx *ctx_id)
@@ -263,7 +495,7 @@ gss_import_sec_context_kerberos(const void *p, size_t len,
if (len == 85)
ret = gss_import_v1_context(p, end, ctx);
else
- ret = -EINVAL;
+ ret = gss_import_v2_context(p, end, ctx);
if (ret == 0)
ctx_id->internal_ctx_id = ctx;
@@ -280,6 +512,8 @@ gss_delete_sec_context_kerberos(void *internal_ctx) {
crypto_free_blkcipher(kctx->seq);
crypto_free_blkcipher(kctx->enc);
+ crypto_free_blkcipher(kctx->acceptor_enc);
+ crypto_free_blkcipher(kctx->initiator_enc);
kfree(kctx->mech_used.data);
kfree(kctx);
}
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 16/19] gss_krb5: add support for triple-des encryption
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (14 preceding siblings ...)
2008-02-21 18:45 ` [PATCH 15/19] gss_krb5: handle new context format from gssd Kevin Coffman
@ 2008-02-21 18:45 ` Kevin Coffman
2008-02-21 18:45 ` [PATCH 17/19] xdr: add a new utility function to shift the head data of an xdr buffer Kevin Coffman
` (2 subsequent siblings)
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:45 UTC (permalink / raw)
To: linux-nfs
Add the final pieces to support the triple-des encryption type.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 4 ++
net/sunrpc/auth_gss/gss_krb5_crypto.c | 3 ++
net/sunrpc/auth_gss/gss_krb5_keys.c | 53 +++++++++++++++++++++++++++++++++
net/sunrpc/auth_gss/gss_krb5_mech.c | 23 ++++++++++++++
net/sunrpc/auth_gss/gss_krb5_seal.c | 1 +
net/sunrpc/auth_gss/gss_krb5_unseal.c | 1 +
net/sunrpc/auth_gss/gss_krb5_wrap.c | 2 +
net/sunrpc/rpc_pipe.c | 2 +
8 files changed, 88 insertions(+), 1 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index e828e98..bf58284 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -240,3 +240,7 @@ u32 krb5_derive_key(struct gss_krb5_enctype *gk5e,
const struct xdr_netobj *inkey,
struct xdr_netobj *outkey,
const struct xdr_netobj *in_constant);
+
+u32 gss_krb5_des3_make_key(struct gss_krb5_enctype *gk5e,
+ struct xdr_netobj *randombits,
+ struct xdr_netobj *key);
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 8b12f34..4f963c2 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -189,6 +189,9 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
checksumdata + checksumlen - kctx->gk5e->cksumlength,
kctx->gk5e->cksumlength);
break;
+ case CKSUMTYPE_HMAC_SHA1_DES3:
+ memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength);
+ break;
default:
BUG();
break;
diff --git a/net/sunrpc/auth_gss/gss_krb5_keys.c b/net/sunrpc/auth_gss/gss_krb5_keys.c
index 97ec67d..a722fba 100644
--- a/net/sunrpc/auth_gss/gss_krb5_keys.c
+++ b/net/sunrpc/auth_gss/gss_krb5_keys.c
@@ -253,3 +253,56 @@ err_return:
return ret;
}
EXPORT_SYMBOL(krb5_derive_key);
+
+#define smask(step) ((1<<step)-1)
+#define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step)))
+#define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1)
+
+static void mit_des_fixup_key_parity(u8 key[8])
+{
+ int i;
+ for (i = 0; i < 8; i++) {
+ key[i] &= 0xfe;
+ key[i] |= 1^parity_char(key[i]);
+ }
+}
+
+/*
+ * This is the des3 key derivation postprocess function
+ */
+u32 gss_krb5_des3_make_key(struct gss_krb5_enctype *gk5e,
+ struct xdr_netobj *randombits,
+ struct xdr_netobj *key)
+{
+ int i;
+ u32 ret = EINVAL;
+
+ if (key->len != 24) {
+ dprintk("%s: key->len is %d\n", __func__, key->len);
+ goto err_out;
+ }
+ if (randombits->len != 21) {
+ dprintk("%s: randombits->len is %d\n",
+ __func__, randombits->len);
+ goto err_out;
+ }
+
+ /* take the seven bytes, move them around into the top 7 bits of the
+ 8 key bytes, then compute the parity bits. Do this three times. */
+
+ for (i = 0; i < 3; i++) {
+ memcpy(key->data + i*8, randombits->data + i*7, 7);
+ key->data[i*8+7] = (((key->data[i*8]&1)<<1) |
+ ((key->data[i*8+1]&1)<<2) |
+ ((key->data[i*8+2]&1)<<3) |
+ ((key->data[i*8+3]&1)<<4) |
+ ((key->data[i*8+4]&1)<<5) |
+ ((key->data[i*8+5]&1)<<6) |
+ ((key->data[i*8+6]&1)<<7));
+
+ mit_des_fixup_key_parity(key->data + i*8);
+ }
+ ret = 0;
+err_out:
+ return(ret);
+}
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index fc30538..2edf28e 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -69,6 +69,26 @@ static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
.cksumlength = 8,
.keyed_cksum = 0,
},
+ /*
+ * 3DES
+ */
+ {
+ .etype = ENCTYPE_DES3_CBC_RAW,
+ .ctype = CKSUMTYPE_HMAC_SHA1_DES3,
+ .name = "des3-hmac-sha1",
+ .encrypt_name = "cbc(des3_ede)",
+ .cksum_name = "hmac(sha1)",
+ .encrypt = krb5_encrypt,
+ .decrypt = krb5_decrypt,
+ .mk_key = gss_krb5_des3_make_key,
+ .signalg = SGN_ALG_HMAC_SHA1_DES3_KD,
+ .sealalg = SEAL_ALG_DES3KD,
+ .keybytes = 21,
+ .keylength = 24,
+ .blocksize = 8,
+ .cksumlength = 20,
+ .keyed_cksum = 1,
+ },
};
static int num_supported_enctypes =
@@ -447,6 +467,9 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx)
p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype));
if (IS_ERR(p))
goto out_err;
+ /* Map ENCTYPE_DES3_CBC_SHA1 to ENCTYPE_DES3_CBC_RAW */
+ if (ctx->enctype == ENCTYPE_DES3_CBC_SHA1)
+ ctx->enctype = ENCTYPE_DES3_CBC_RAW;
ctx->gk5e = get_gss_krb5_enctype(ctx->enctype);
if (ctx->gk5e == NULL) {
printk("gss_kerberos_mech: unsupported krb5 enctype %u\n",
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 285188d..b1d9436 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -140,6 +140,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
switch (ctx->enctype) {
case ENCTYPE_DES_CBC_RAW:
+ case ENCTYPE_DES3_CBC_RAW:
return gss_get_mic_v1(ctx, text, token);
default:
BUG();
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index c9adcfc..7ba63ae 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -150,6 +150,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
switch (ctx->enctype) {
case ENCTYPE_DES_CBC_RAW:
+ case ENCTYPE_DES3_CBC_RAW:
return gss_verify_mic_v1(ctx, message_buffer, read_token);
default:
BUG();
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index a68677c..d59e9b2 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -291,6 +291,7 @@ gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
switch (kctx->enctype) {
case ENCTYPE_DES_CBC_RAW:
+ case ENCTYPE_DES3_CBC_RAW:
return gss_wrap_kerberos_v1(kctx, offset, buf, pages);
break;
default:
@@ -307,6 +308,7 @@ gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf)
switch (kctx->enctype) {
case ENCTYPE_DES_CBC_RAW:
+ case ENCTYPE_DES3_CBC_RAW:
return gss_unwrap_kerberos_v1(kctx, offset, buf);
break;
default:
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 5781862..d84632a 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -392,7 +392,7 @@ static const struct file_operations rpc_info_operations = {
static int
rpc_show_krb5_info(struct seq_file *m, void *v)
{
- seq_printf(m, "enctypes: 3,1,2\n");
+ seq_printf(m, "enctypes: 16,3,1,2\n");
return 0;
}
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 17/19] xdr: add a new utility function to shift the head data of an xdr buffer
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (15 preceding siblings ...)
2008-02-21 18:45 ` [PATCH 16/19] gss_krb5: add support for triple-des encryption Kevin Coffman
@ 2008-02-21 18:45 ` Kevin Coffman
2008-02-21 18:45 ` [PATCH 18/19] gss_krb5: add support for new token formats in rfc4121 Kevin Coffman
2008-02-21 18:45 ` [PATCH 19/19] gss_krb5: add remaining pieces to enable AES encryption support Kevin Coffman
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:45 UTC (permalink / raw)
To: linux-nfs
Add a new xdr helper function that shifts the data in an xdr
buffer's head to make room for new data.
Also add an export for the helper function write_bytes_to_xdr_buf().
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/xdr.h | 2 ++
net/sunrpc/xdr.c | 29 +++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index e4057d7..518d47c 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -164,6 +164,8 @@ extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, unsigned int,
extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, unsigned int);
extern int read_bytes_from_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int);
extern int write_bytes_to_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int);
+extern int xdr_shift_head_data(struct xdr_buf *, int, unsigned int);
+
/*
* Helper structure for copying from an sk_buff.
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 995c3fd..de2c986 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -428,6 +428,34 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len)
EXPORT_SYMBOL(xdr_shift_buf);
/**
+ * xdr_xdr_shift_head_data - Make room for new data within buf->head
+ * @buf: pointer to XDR buffer
+ * @offset: offset within the head to start moving data
+ * @shiftlen: number of bytes to shift the data
+ */
+int
+xdr_shift_head_data(struct xdr_buf *buf, int offset, unsigned int shiftlen)
+{
+ u8 *p;
+
+ if (shiftlen == 0)
+ return 0;
+ /* make sure there is room (assuming head has a page) */
+ if (buf->head[0].iov_len + shiftlen + offset > PAGE_CACHE_SIZE)
+ return 1;
+
+ p = buf->head[0].iov_base + offset;
+
+ memmove(p + shiftlen, p, buf->head[0].iov_len - offset);
+
+ buf->head[0].iov_len += shiftlen;
+ buf->len += shiftlen;
+
+ return 0;
+}
+EXPORT_SYMBOL(xdr_shift_head_data);
+
+/**
* xdr_init_encode - Initialize a struct xdr_stream for sending data.
* @xdr: pointer to xdr_stream struct
* @buf: pointer to XDR buffer in which to encode data
@@ -758,6 +786,7 @@ int write_bytes_to_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, un
__write_bytes_to_xdr_buf(&subbuf, obj, len);
return 0;
}
+EXPORT_SYMBOL(write_bytes_to_xdr_buf);
int
xdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj)
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 18/19] gss_krb5: add support for new token formats in rfc4121
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (16 preceding siblings ...)
2008-02-21 18:45 ` [PATCH 17/19] xdr: add a new utility function to shift the head data of an xdr buffer Kevin Coffman
@ 2008-02-21 18:45 ` Kevin Coffman
2008-02-21 18:45 ` [PATCH 19/19] gss_krb5: add remaining pieces to enable AES encryption support Kevin Coffman
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:45 UTC (permalink / raw)
To: linux-nfs
This is a step toward support for AES encryption types which are required
to use the new token formats defined in rfc4121.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 28 ++++
net/sunrpc/auth_gss/gss_krb5_crypto.c | 71 +++++++++
net/sunrpc/auth_gss/gss_krb5_seal.c | 69 +++++++++
net/sunrpc/auth_gss/gss_krb5_unseal.c | 60 ++++++++
net/sunrpc/auth_gss/gss_krb5_wrap.c | 248 +++++++++++++++++++++++++++++++++
5 files changed, 476 insertions(+), 0 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index bf58284..95b375b 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -53,6 +53,8 @@
/* Maximum blocksize for the supported crypto algorithms */
#define GSS_KRB5_MAX_BLOCKSIZE 16
+struct krb5_ctx;
+
struct gss_krb5_enctype {
const u32 etype; /* encryption (key) type */
const u32 ctype; /* checksum type */
@@ -75,6 +77,12 @@ struct gss_krb5_enctype {
u32 (*mk_key) (struct gss_krb5_enctype *gk5e,
struct xdr_netobj *in,
struct xdr_netobj *out); /* complete key generation */
+ u32 (*encrypt_v2) (struct krb5_ctx *kctx, u32 offset,
+ struct xdr_buf *buf, int ec,
+ struct page **pages); /* v2 encryption function */
+ u32 (*decrypt_v2) (struct krb5_ctx *kctx, u32 offset,
+ struct xdr_buf *buf, u32 *headskip,
+ u32 *tailskip); /* v2 decryption function */
};
/* krb5_ctx flags definitions */
@@ -109,6 +117,18 @@ extern spinlock_t krb5_seq_lock;
#define KG_TOK_MIC_MSG 0x0101
#define KG_TOK_WRAP_MSG 0x0201
+#define KG2_TOK_INITIAL 0x0101
+#define KG2_TOK_RESPONSE 0x0202
+#define KG2_TOK_MIC 0x0404
+#define KG2_TOK_WRAP 0x0504
+
+#define KG2_TOKEN_FLAG_SENTBYACCEPTOR 0x01
+#define KG2_TOKEN_FLAG_SEALED 0x02
+#define KG2_TOKEN_FLAG_ACCEPTORSUBKEY 0x04
+
+#define KG2_RESP_FLAG_ERROR 0x0001
+#define KG2_RESP_FLAG_DELEG_OK 0x0002
+
enum sgn_alg {
SGN_ALG_DES_MAC_MD5 = 0x0000,
SGN_ALG_MD2_5 = 0x0001,
@@ -135,6 +155,9 @@ extern struct xdr_netobj krb5_oid;
#define CKSUMTYPE_RSA_MD5_DES 0x0008
#define CKSUMTYPE_NIST_SHA 0x0009
#define CKSUMTYPE_HMAC_SHA1_DES3 0x000c
+#define CKSUMTYPE_HMAC_SHA1_96_AES128 0x000f
+#define CKSUMTYPE_HMAC_SHA1_96_AES256 0x0010
+#define CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /* Microsoft md5 hmac cksumtype */
/* from gssapi_err_krb5.h */
#define KG_CCACHE_NOMATCH (39756032L)
@@ -195,6 +218,11 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
struct xdr_buf *body, int body_offset, u8 *cksumkey,
struct xdr_netobj *cksumout);
+extern u32
+make_checksum_v2(struct krb5_ctx *, char *header, int hdrlen,
+ struct xdr_buf *body, int body_offset, u8 *key,
+ struct xdr_netobj *cksum);
+
u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *,
struct xdr_netobj *);
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 4f963c2..0c52194 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -204,6 +204,77 @@ out:
EXPORT_SYMBOL(make_checksum);
+/*
+ * checksum the plaintext data and hdrlen bytes of the token header
+ * Per rfc4121, sec. 4.2.4, the checksum is performed over the data
+ * body then over the first 16 octets of the MIC token
+ */
+u32
+make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen,
+ struct xdr_buf *body, int body_offset, u8 *cksumkey,
+ struct xdr_netobj *cksumout)
+{
+ struct hash_desc desc;
+ struct scatterlist sg[1];
+ int err;
+ u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+ unsigned int checksumlen;
+
+ if (kctx->gk5e->keyed_cksum == 0) {
+ dprintk("%s: expected keyed hash for %s\n",
+ __func__, kctx->gk5e->name);
+ return GSS_S_FAILURE;
+ }
+ if (cksumkey == NULL) {
+ dprintk("%s: no key supplied for %s\n",
+ __func__, kctx->gk5e->name);
+ return GSS_S_FAILURE;
+ }
+
+ desc.tfm = crypto_alloc_hash(kctx->gk5e->cksum_name, 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(desc.tfm))
+ return GSS_S_FAILURE;
+ checksumlen = crypto_hash_digestsize(desc.tfm);
+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ err = crypto_hash_setkey(desc.tfm, cksumkey, kctx->gk5e->keylength);
+ if (err)
+ goto out;
+
+ err = crypto_hash_init(&desc);
+ if (err)
+ goto out;
+ err = xdr_process_buf(body, body_offset, body->len - body_offset,
+ checksummer, &desc);
+ if (err)
+ goto out;
+ sg_init_one(sg, header, hdrlen);
+ err = crypto_hash_update(&desc, sg, hdrlen);
+ if (err)
+ goto out;
+ err = crypto_hash_final(&desc, checksumdata);
+ if (err)
+ goto out;
+
+ cksumout->len = kctx->gk5e->cksumlength;
+
+ switch (kctx->gk5e->ctype) {
+ case CKSUMTYPE_HMAC_SHA1_96_AES128:
+ case CKSUMTYPE_HMAC_SHA1_96_AES256:
+ /* note that this truncates the hash */
+ memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength);
+ break;
+ default:
+ BUG();
+ break;
+ }
+out:
+ crypto_free_hash(desc.tfm);
+ return err ? GSS_S_FAILURE : 0;
+}
+EXPORT_SYMBOL(make_checksum_v2);
+
struct encryptor_desc {
u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
struct blkcipher_desc desc;
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index b1d9436..e6083a0 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -92,6 +92,33 @@ setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token)
return (char *)krb5_hdr;
}
+static void *
+setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
+{
+ __be16 *ptr, *krb5_hdr;
+ u8 *p, flags = 0x00;
+
+ if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0)
+ flags |= 0x01;
+ if (ctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
+ flags |= 0x04;
+
+ /* Per rfc 4121, sec 4.2.6.1, there is no header,
+ * just start the token */
+ krb5_hdr = ptr = (__be16 *)token->data;
+
+ *ptr++ = KG2_TOK_MIC;
+ p = (u8 *)ptr;
+ *p++ = flags;
+ *p++ = 0xff;
+ ptr = (__be16 *)p;
+ *ptr++ = 0xffff;
+ *ptr++ = 0xffff;
+
+ token->len = 16 + ctx->gk5e->cksumlength;
+ return krb5_hdr;
+}
+
static u32
gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
struct xdr_netobj *token)
@@ -133,6 +160,45 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
}
u32
+gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
+ struct xdr_netobj *token)
+{
+ char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+ struct xdr_netobj cksumobj = { .len = sizeof(cksumdata),
+ .data = cksumdata};
+ void *krb5_hdr;
+ s32 now;
+ u64 seq_send;
+ u8 *cksumkey;
+
+ dprintk("RPC: %s\n", __func__);
+ BUG_ON(ctx == NULL);
+
+ krb5_hdr = setup_token_v2(ctx, token);
+
+ /* Set up the sequence number. Now 64-bits in clear
+ * text and w/o direction indicator */
+ spin_lock(&krb5_seq_lock);
+ seq_send = ctx->seq_send64++;
+ spin_unlock(&krb5_seq_lock);
+ *((u64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send);
+
+ if (ctx->initiate)
+ cksumkey = ctx->initiator_sign;
+ else
+ cksumkey = ctx->acceptor_sign;
+
+ if (make_checksum_v2(ctx, krb5_hdr, 16, text, 0, cksumkey, &cksumobj))
+ return GSS_S_FAILURE;
+
+ memcpy(krb5_hdr + 16, cksumobj.data, cksumobj.len);
+
+ now = get_seconds();
+
+ return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
+}
+
+u32
gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
struct xdr_netobj *token)
{
@@ -142,6 +208,9 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
case ENCTYPE_DES_CBC_RAW:
case ENCTYPE_DES3_CBC_RAW:
return gss_get_mic_v1(ctx, text, token);
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ return gss_get_mic_v2(ctx, text, token);
default:
BUG();
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 7ba63ae..70d89cd 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -141,6 +141,63 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
return GSS_S_COMPLETE;
}
+static u32
+gss_verify_mic_v2(struct krb5_ctx *ctx,
+ struct xdr_buf *message_buffer, struct xdr_netobj *read_token)
+{
+ char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+ struct xdr_netobj cksumobj = {.len = sizeof(cksumdata),
+ .data = cksumdata};
+ s32 now;
+ u64 seqnum;
+ u8 *ptr = read_token->data;
+ u8 *cksumkey;
+ u8 flags;
+ int i;
+
+ dprintk("RPC: %s\n", __func__);
+
+ if (be16_to_cpu(*((__be16 *)ptr)) != KG2_TOK_MIC)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ flags = ptr[2];
+ if ((!ctx->initiate && (flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)) ||
+ (ctx->initiate && !(flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)))
+ return GSS_S_BAD_SIG;
+
+ if (flags & KG2_TOKEN_FLAG_SEALED) {
+ dprintk("%s: token has unexpected sealed flag\n", __func__);
+ return GSS_S_FAILURE;
+ }
+
+ for (i = 3; i < 8; i++)
+ if (ptr[i] != 0xff)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ if (ctx->initiate)
+ cksumkey = ctx->acceptor_sign;
+ else
+ cksumkey = ctx->initiator_sign;
+
+ if (make_checksum_v2(ctx, ptr, 16, message_buffer, 0,
+ cksumkey, &cksumobj))
+ return GSS_S_FAILURE;
+
+ if (memcmp(cksumobj.data, ptr + 16, ctx->gk5e->cksumlength))
+ return GSS_S_BAD_SIG;
+
+ /* it got through unscathed. Make sure the context is unexpired */
+ now = get_seconds();
+ if (now > ctx->endtime)
+ return GSS_S_CONTEXT_EXPIRED;
+
+ /* do sequencing checks */
+
+ seqnum = be64_to_cpu((__be64 *)ptr + 8);
+
+ return GSS_S_COMPLETE;
+}
+
u32
gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
struct xdr_buf *message_buffer,
@@ -152,6 +209,9 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
case ENCTYPE_DES_CBC_RAW:
case ENCTYPE_DES3_CBC_RAW:
return gss_verify_mic_v1(ctx, message_buffer, read_token);
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ return gss_verify_mic_v2(ctx, message_buffer, read_token);
default:
BUG();
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index d59e9b2..701e001 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -283,6 +283,246 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
return GSS_S_COMPLETE;
}
+#define TEST_ROTATE 0
+#define TEST_EXTRA_COUNT 0
+
+#if TEST_ROTATE
+static u32
+rotate_right(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf,
+ struct page **pages, u16 *rrc)
+{
+ u16 rotate_count = 0;
+ u8 *tbuf;
+
+ /*
+ * As a quick test, if there is tail data that will fit within
+ * the head, move it there
+ */
+
+ /* If there is no tail, don't bother */
+ if (buf->tail[0].iov_base == NULL)
+ goto out;
+
+ /* If head and tail share a page, don't bother */
+ if (buf->tail[0].iov_base - buf->head[0].iov_base < PAGE_CACHE_SIZE)
+ goto out;
+
+ tbuf = kmalloc(buf->tail[0].iov_len, GFP_KERNEL);
+ if (tbuf == NULL)
+ goto out;
+
+ memcpy(tbuf, buf->tail[0].iov_base, buf->tail[0].iov_len);
+
+ /* XXX This assumes there is room in the head */
+ rotate_count = buf->tail[0].iov_len;
+
+ if (xdr_shift_head_data(buf, offset + 16, rotate_count))
+ goto out;
+ memcpy(buf->head[0].iov_base + offset + 16, tbuf,
+ buf->tail[0].iov_len);
+ /* this is adjusted upwards in xdr_shift_head_data(),
+ * but we aren't adjusting the total length */
+ buf->len -= rotate_count;
+
+ buf->tail[0].iov_len -= rotate_count;
+ buf->tail[0].iov_base = NULL; /* Needed? Correct? */
+
+ kfree(tbuf);
+out:
+ *rrc = rotate_count;
+ dprintk("%s: returning with rotate_count of %u\n", __func__, *rrc);
+ return 0;
+}
+#endif
+
+/*
+ * We cannot currently handle tokens with rotated data. We need a
+ * generalized routine to rotate the data in place. It is anticipated
+ * that we won't encounter rotated data in the general case.
+ */
+static u32
+rotate_left(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, u16 rrc)
+{
+ unsigned int realrrc = rrc % (buf->len - offset - 16);
+
+ if (realrrc == 0)
+ return 0;
+
+ dprintk("%s: cannot process token with rotated data: "
+ "rrc %u, realrrc %u\n", __func__, rrc, realrrc);
+ return 1;
+}
+
+static u32
+gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
+ struct xdr_buf *buf, struct page **pages)
+{
+ int blocksize;
+ u8 *ptr, *plainhdr;
+ s32 now;
+ u8 flags = 0x00;
+ __be16 *be16ptr, ec = 0;
+ __be64 *be64ptr;
+ u32 err;
+#if TEST_ROTATE
+ u16 rrc;
+#endif
+#if TEST_EXTRA_COUNT
+ unsigned int plainlen;
+#endif
+
+ dprintk("RPC: %s\n", __func__);
+
+ if (kctx->gk5e->encrypt_v2 == NULL)
+ return GSS_S_FAILURE;
+
+#if TEST_EXTRA_COUNT
+ plainlen = buf->head[0].iov_len - offset
+ + buf->page_len + buf->tail[0].iov_len;
+#endif
+ /* make room for gss token header (always 16 bytes) */
+ if (xdr_shift_head_data(buf, offset, 16))
+ return GSS_S_FAILURE;
+
+ /* construct gss token header */
+ ptr = plainhdr = buf->head[0].iov_base + offset;
+ *ptr++ = (unsigned char) ((KG2_TOK_WRAP>>8) & 0xff);
+ *ptr++ = (unsigned char) (KG2_TOK_WRAP & 0xff);
+
+ if ((kctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0)
+ flags |= KG2_TOKEN_FLAG_SENTBYACCEPTOR;
+ if ((kctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY) != 0)
+ flags |= KG2_TOKEN_FLAG_ACCEPTORSUBKEY;
+ /* We always do confidentiality in wrap tokens */
+ flags |= KG2_TOKEN_FLAG_SEALED;
+
+ *ptr++ = flags;
+ *ptr++ = 0xff;
+ be16ptr = (__be16 *)ptr;
+
+ blocksize = crypto_blkcipher_blocksize(kctx->acceptor_enc);
+#if TEST_EXTRA_COUNT
+ ec = plainlen % blocksize ? blocksize - plainlen % blocksize : 0;
+#endif
+ *be16ptr++ = cpu_to_be16(ec);
+ /* "inner" token header always uses 0 for RRC */
+ *be16ptr++ = cpu_to_be16(0);
+
+ be64ptr = (__be64 *)be16ptr;
+ spin_lock(&krb5_seq_lock);
+ *be64ptr = cpu_to_be64(kctx->seq_send64++);
+ spin_unlock(&krb5_seq_lock);
+
+ err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, ec, pages);
+ if (err)
+ return err;
+
+#if TEST_ROTATE
+ err = rotate_right(kctx, offset, buf, pages, &rrc);
+ if (err)
+ return err;
+ *((__be16 *)(plainhdr + 6)) = cpu_to_be16(rrc);
+#endif
+ now = get_seconds();
+ return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
+}
+
+static u32
+gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
+{
+ s32 now;
+ u64 seqnum;
+ u8 *ptr;
+ u8 flags = 0x00;
+ u16 ec, rrc;
+ int err;
+ u32 headskip, tailskip;
+ u8 decrypted_hdr[16];
+ unsigned int movelen;
+
+
+ dprintk("RPC: %s\n", __func__);
+
+ if (kctx->gk5e->decrypt_v2 == NULL)
+ return GSS_S_FAILURE;
+
+ ptr = buf->head[0].iov_base + offset;
+
+ if (be16_to_cpu(*((__be16 *)ptr)) != KG2_TOK_WRAP)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ flags = ptr[2];
+ if ((!kctx->initiate && (flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)) ||
+ (kctx->initiate && !(flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)))
+ return GSS_S_BAD_SIG;
+
+ if ((flags & KG2_TOKEN_FLAG_SEALED) == 0) {
+ dprintk("%s: token missing expected sealed flag\n", __func__);
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if (ptr[3] != 0xff)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ ec = be16_to_cpup((__be16 *)(ptr + 4));
+ rrc = be16_to_cpup((__be16 *)(ptr + 6));
+
+ seqnum = be64_to_cpup((__be64 *)(ptr + 8));
+
+ if (rrc != 0) {
+ err = rotate_left(kctx, offset, buf, rrc);
+ if (err)
+ return GSS_S_FAILURE;
+ }
+
+ err = (*kctx->gk5e->decrypt_v2)(kctx, offset, buf,
+ &headskip, &tailskip);
+ if (err)
+ return GSS_S_FAILURE;
+
+ /*
+ * Retrieve the decrypted gss token header and verify
+ * it against the original
+ */
+ err = read_bytes_from_xdr_buf(buf, buf->len - 16 - tailskip,
+ decrypted_hdr, 16);
+ if (err) {
+ dprintk("%s: error %u getting decrypted_hdr\n", __func__, err);
+ return GSS_S_FAILURE;
+ }
+ if (memcmp(ptr, decrypted_hdr, 6)
+ || memcmp(ptr + 8, decrypted_hdr + 8, 8)) {
+ dprintk("%s: token hdr, plaintext hdr mismatch!\n", __func__);
+ return GSS_S_FAILURE;
+ }
+
+ /*
+ * XXX do sequencing checks XXX
+ * (v1 tokens currently don't do ANY sequencing checks!!!)
+ */
+
+ /* it got through unscathed. Make sure the context is unexpired */
+ now = get_seconds();
+ if (now > kctx->endtime)
+ return GSS_S_CONTEXT_EXPIRED;
+
+ /*
+ * Move the head data back to the right position in xdr_buf.
+ * We ignore any "ec" data since it might be in the head or
+ * the tail, and we really don't need to deal with it.
+ * Note that buf->head[0].iov_len may indicate the available
+ * head buffer space rather than that actually occupied.
+ */
+ movelen = min_t(unsigned int, buf->head[0].iov_len, buf->len);
+ movelen -= offset + 16 + headskip;
+ BUG_ON(offset + 16 + headskip + movelen > buf->head[0].iov_len);
+ memmove(ptr, ptr + 16 + headskip, movelen);
+ buf->head[0].iov_len -= 16 + headskip;
+ buf->len -= 16 + headskip;
+
+ return GSS_S_COMPLETE;
+}
+
u32
gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
struct xdr_buf *buf, struct page **pages)
@@ -294,6 +534,10 @@ gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
case ENCTYPE_DES3_CBC_RAW:
return gss_wrap_kerberos_v1(kctx, offset, buf, pages);
break;
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ return gss_wrap_kerberos_v2(kctx, offset, buf, pages);
+ break;
default:
BUG();
break;
@@ -311,6 +555,10 @@ gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf)
case ENCTYPE_DES3_CBC_RAW:
return gss_unwrap_kerberos_v1(kctx, offset, buf);
break;
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ return gss_unwrap_kerberos_v2(kctx, offset, buf);
+ break;
default:
BUG();
break;
^ permalink raw reply related [flat|nested] 31+ messages in thread* [PATCH 19/19] gss_krb5: add remaining pieces to enable AES encryption support
[not found] ` <20080221184208.19195.94518.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (17 preceding siblings ...)
2008-02-21 18:45 ` [PATCH 18/19] gss_krb5: add support for new token formats in rfc4121 Kevin Coffman
@ 2008-02-21 18:45 ` Kevin Coffman
18 siblings, 0 replies; 31+ messages in thread
From: Kevin Coffman @ 2008-02-21 18:45 UTC (permalink / raw)
To: linux-nfs
Add the remaining pieces to enable support for Kerberos AES
encryption types.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 12 +
net/sunrpc/auth_gss/gss_krb5_crypto.c | 307 +++++++++++++++++++++++++++++++++
net/sunrpc/auth_gss/gss_krb5_keys.c | 30 +++
net/sunrpc/auth_gss/gss_krb5_mech.c | 44 +++++
net/sunrpc/rpc_pipe.c | 2
5 files changed, 394 insertions(+), 1 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 95b375b..2d60018 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -272,3 +272,15 @@ u32 krb5_derive_key(struct gss_krb5_enctype *gk5e,
u32 gss_krb5_des3_make_key(struct gss_krb5_enctype *gk5e,
struct xdr_netobj *randombits,
struct xdr_netobj *key);
+
+u32 gss_krb5_aes_make_key(struct gss_krb5_enctype *gk5e,
+ struct xdr_netobj *randombits,
+ struct xdr_netobj *key);
+
+u32 gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
+ struct xdr_buf *buf, int ec,
+ struct page **pages);
+
+u32 gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset,
+ struct xdr_buf *buf, u32 *plainoffset,
+ u32 *plainlen);
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 0c52194..92c2eff 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -42,6 +42,7 @@
#include <linux/crypto.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
+#include <linux/random.h>
#include <linux/sunrpc/gss_krb5.h>
#include <linux/sunrpc/xdr.h>
@@ -448,3 +449,309 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
}
EXPORT_SYMBOL(gss_decrypt_xdr_buf);
+
+static s32
+gss_cksum_xdr_buf(struct krb5_ctx *kctx, struct xdr_buf *body, int body_offset,
+ const u8 *key, unsigned int keylen, struct xdr_netobj *out)
+{
+ struct hash_desc desc;
+ int err;
+
+ desc.tfm = crypto_alloc_hash(kctx->gk5e->cksum_name, 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(desc.tfm))
+ return GSS_S_FAILURE;
+ if (out->data == NULL)
+ return GSS_S_FAILURE;
+ if (out->len < crypto_hash_digestsize(desc.tfm))
+ return GSS_S_FAILURE;
+ out->len = crypto_hash_digestsize(desc.tfm);
+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ if (key != NULL && keylen != 0) {
+ err = crypto_hash_setkey(desc.tfm, key, keylen);
+ if (err)
+ goto out;
+ }
+
+ err = crypto_hash_init(&desc);
+ if (err)
+ goto out;
+ err = xdr_process_buf(body, body_offset, body->len - body_offset,
+ checksummer, &desc);
+ if (err)
+ goto out;
+ err = crypto_hash_final(&desc, out->data);
+
+out:
+ crypto_free_hash(desc.tfm);
+ return err ? GSS_S_FAILURE : 0;
+}
+
+static u32
+gss_krb5_cts_crypt(struct crypto_blkcipher *cipher, struct xdr_buf *buf,
+ u32 offset, u8 *iv, struct page **pages, int encrypt)
+{
+ u32 ret;
+ struct scatterlist sg[1];
+ struct blkcipher_desc desc = { .tfm = cipher, .info = iv };
+ u8 data[crypto_blkcipher_blocksize(cipher) * 2];
+ struct page **save_pages;
+ u32 len = buf->len - offset;
+
+ BUG_ON(len > crypto_blkcipher_blocksize(cipher) * 2);
+
+ /*
+ * For encryption, we want to read from the cleartext
+ * page cache pages, and write the encrypted data to
+ * the supplied xdr_buf pages.
+ */
+ save_pages = buf->pages;
+ if (encrypt)
+ buf->pages = pages;
+
+ ret = read_bytes_from_xdr_buf(buf, offset, data, len);
+ buf->pages = save_pages;
+ if (ret)
+ goto out;
+
+ sg_init_one(sg, data, len);
+
+ if (encrypt)
+ ret = crypto_blkcipher_encrypt_iv(&desc, sg, sg, len);
+ else
+ ret = crypto_blkcipher_decrypt_iv(&desc, sg, sg, len);
+
+ if (ret)
+ goto out;
+
+ ret = write_bytes_to_xdr_buf(buf, offset, data, len);
+
+out:
+ return ret;
+}
+
+u32
+gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
+ struct xdr_buf *buf, int ec, struct page **pages)
+{
+ u32 err;
+ struct xdr_netobj hmac;
+ u8 *cksumkey, *enckey;
+ u8 *ecptr;
+ struct crypto_blkcipher *cipher, *cbc = NULL;
+ int blocksize;
+ struct page **save_pages;
+ int nblocks, nbytes;
+ struct encryptor_desc desc;
+ u32 cbcbytes;
+
+ if (kctx->initiate) {
+ cipher = kctx->initiator_enc;
+ enckey = kctx->initiator_seal;
+ cksumkey = kctx->initiator_integ;
+ } else {
+ cipher = kctx->acceptor_enc;
+ enckey = kctx->acceptor_seal;
+ cksumkey = kctx->acceptor_integ;
+ }
+ blocksize = crypto_blkcipher_blocksize(cipher);
+
+ /* hide the gss token header and insert the confounder */
+ offset += 16;
+ if (xdr_shift_head_data(buf, offset, blocksize))
+ return GSS_S_FAILURE;
+ get_random_bytes(buf->head[0].iov_base + offset, blocksize);
+ offset -= 16;
+
+ if (buf->tail[0].iov_base != NULL) {
+ ecptr = buf->tail[0].iov_base + buf->tail[0].iov_len;
+ } else {
+ buf->tail[0].iov_base = buf->head[0].iov_base
+ + buf->head[0].iov_len;
+ buf->tail[0].iov_len = 0;
+ ecptr = buf->tail[0].iov_base;
+ }
+
+ memset(ecptr, 'X', ec);
+ buf->tail[0].iov_len += ec;
+ buf->len += ec;
+
+ /* copy plaintext gss token header after filler (if any) */
+ memcpy(ecptr + ec, buf->head[0].iov_base + offset, 16);
+ buf->tail[0].iov_len += 16;
+ buf->len += 16;
+
+ /* Do the HMAC */
+ hmac.len = GSS_KRB5_MAX_CKSUM_LEN;
+ hmac.data = buf->tail[0].iov_base + buf->tail[0].iov_len;
+
+ /*
+ * When we are called, pages points to the real page cache
+ * data -- which we can't go and encrypt! buf->pages points
+ * to scratch pages which we are going to send off to the
+ * client/server. Swap in the plaintext pages to calculate
+ * the hmac.
+ */
+ save_pages = buf->pages;
+ buf->pages = pages;
+
+ err = gss_cksum_xdr_buf(kctx, buf, offset + 16, cksumkey,
+ kctx->gk5e->keylength, &hmac);
+ buf->pages = save_pages;
+ if (err)
+ return GSS_S_FAILURE;
+
+ nbytes = buf->len - offset - 16;
+ nblocks = (nbytes + blocksize - 1) / blocksize;
+ cbcbytes = 0;
+ if (nblocks > 2)
+ cbcbytes = (nblocks - 2) * blocksize;
+
+ memset(desc.iv, 0, sizeof(desc.iv));
+
+ if (cbcbytes) {
+ /* XXX This does a kzalloc, may need to pre-allocate this! */
+ cbc = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
+ if (cbc == NULL)
+ return GSS_S_FAILURE;
+ err = crypto_blkcipher_setkey(cbc, enckey,
+ kctx->gk5e->keylength);
+ if (err)
+ goto out_err;
+
+ desc.pos = offset + 16;
+ desc.fragno = 0;
+ desc.fraglen = 0;
+ desc.pages = pages;
+ desc.outbuf = buf;
+ desc.desc.info = desc.iv;
+ desc.desc.flags = 0;
+ desc.desc.tfm = cbc;
+
+ sg_init_table(desc.infrags, 4);
+ sg_init_table(desc.outfrags, 4);
+
+ err = xdr_process_buf(buf, offset + 16, cbcbytes,
+ encryptor, &desc);
+ if (err)
+ goto out_err;
+ }
+
+ /* Make sure IV carries forward from any CBC results. */
+ err = gss_krb5_cts_crypt(cipher, buf, offset + 16 + cbcbytes,
+ desc.iv, pages, 1);
+ if (err) {
+ err = GSS_S_FAILURE;
+ goto out_err;
+ }
+
+ /* Now update buf to account for HMAC */
+ buf->tail[0].iov_len += kctx->gk5e->cksumlength;
+ buf->len += kctx->gk5e->cksumlength;
+
+out_err:
+ if (cbc != NULL)
+ crypto_free_blkcipher(cbc);
+ if (err)
+ err = GSS_S_FAILURE;
+ return err;
+}
+
+u32
+gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf,
+ u32 *headskip, u32 *tailskip)
+{
+ struct xdr_buf subbuf;
+ u32 ret = 0;
+ u8 *cksum_key, *enckey;
+ struct crypto_blkcipher *cipher, *cbc = NULL;
+ struct xdr_netobj our_hmac_obj;
+ u8 our_hmac[GSS_KRB5_MAX_CKSUM_LEN];
+ u8 pkt_hmac[GSS_KRB5_MAX_CKSUM_LEN];
+ int nblocks, blocksize, cbcbytes;
+ struct decryptor_desc desc;
+
+ if (kctx->initiate) {
+ cipher = kctx->acceptor_enc;
+ enckey = kctx->acceptor_seal;
+ cksum_key = kctx->acceptor_integ;
+ } else {
+ cipher = kctx->initiator_enc;
+ enckey = kctx->initiator_seal;
+ cksum_key = kctx->initiator_integ;
+ }
+ blocksize = crypto_blkcipher_blocksize(cipher);
+
+
+ /* create a segment skipping the header and leaving out the checksum */
+ xdr_buf_subsegment(buf, &subbuf, offset + 16,
+ (buf->len - offset - 16 - kctx->gk5e->cksumlength));
+
+ nblocks = (subbuf.len + blocksize - 1) / blocksize;
+
+ cbcbytes = 0;
+ if (nblocks > 2)
+ cbcbytes = (nblocks - 2) * blocksize;
+
+ memset(desc.iv, 0, sizeof(desc.iv));
+
+ if (cbcbytes) {
+ /* XXX This does a kzalloc, may need to pre-allocate this! */
+ cbc = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
+ if (cbc == NULL) {
+ ret = GSS_S_FAILURE;
+ goto out_err;
+ }
+ ret = crypto_blkcipher_setkey(cbc, enckey,
+ kctx->gk5e->keylength);
+ if (ret)
+ goto out_err;
+
+ desc.fragno = 0;
+ desc.fraglen = 0;
+ desc.desc.info = desc.iv;
+ desc.desc.flags = 0;
+ desc.desc.tfm = cbc;
+
+ sg_init_table(desc.frags, 4);
+
+ ret = xdr_process_buf(&subbuf, 0, cbcbytes, decryptor, &desc);
+ if (ret)
+ goto out_err;
+ }
+
+ /* Make sure IV carries forward from any CBC results. */
+ ret = gss_krb5_cts_crypt(cipher, &subbuf, cbcbytes, desc.iv, NULL, 0);
+ if (ret)
+ goto out_err;
+
+
+ /* Calculate our hmac over the plaintext data */
+ our_hmac_obj.len = sizeof(our_hmac);
+ our_hmac_obj.data = our_hmac;
+
+ ret = gss_cksum_xdr_buf(kctx, &subbuf, 0, cksum_key,
+ kctx->gk5e->keylength, &our_hmac_obj);
+ if (ret)
+ goto out_err;
+
+ /* Get the packet's hmac value */
+ ret = read_bytes_from_xdr_buf(buf, buf->len - kctx->gk5e->cksumlength,
+ pkt_hmac, kctx->gk5e->cksumlength);
+ if (ret)
+ goto out_err;
+
+ if (memcmp(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) {
+ ret = GSS_S_BAD_SIG;
+ goto out_err;
+ }
+ *headskip = crypto_blkcipher_blocksize(cipher);
+ *tailskip = kctx->gk5e->cksumlength;
+out_err:
+ if (cbc != NULL)
+ crypto_free_blkcipher(cbc);
+ if (ret && ret != GSS_S_BAD_SIG)
+ ret = GSS_S_FAILURE;
+ return ret;
+}
diff --git a/net/sunrpc/auth_gss/gss_krb5_keys.c b/net/sunrpc/auth_gss/gss_krb5_keys.c
index a722fba..351383c 100644
--- a/net/sunrpc/auth_gss/gss_krb5_keys.c
+++ b/net/sunrpc/auth_gss/gss_krb5_keys.c
@@ -306,3 +306,33 @@ u32 gss_krb5_des3_make_key(struct gss_krb5_enctype *gk5e,
err_out:
return(ret);
}
+
+/*
+ * This is the aes key derivation postprocess function
+ */
+u32 gss_krb5_aes_make_key(struct gss_krb5_enctype *gk5e,
+ struct xdr_netobj *randombits,
+ struct xdr_netobj *key)
+{
+ u32 ret = EINVAL;
+
+ if (key->len != 16 && key->len != 32) {
+ dprintk("%s: key->len is %d\n", __func__, key->len);
+ goto err_out;
+ }
+ if (randombits->len != 16 && randombits->len != 32) {
+ dprintk("%s: randombits->len is %d\n",
+ __func__, randombits->len);
+ goto err_out;
+ }
+ if (randombits->len != key->len) {
+ dprintk("%s: randombits->len is %d, key->len is %d\n",
+ __func__, randombits->len, key->len);
+ goto err_out;
+ }
+ memcpy(key->data, randombits->data, key->len);
+ ret = 0;
+err_out:
+ return (ret);
+}
+
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 2edf28e..cfd06ca 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -89,6 +89,50 @@ static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
.cksumlength = 20,
.keyed_cksum = 1,
},
+ /*
+ * AES128
+ */
+ {
+ .etype = ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+ .ctype = CKSUMTYPE_HMAC_SHA1_96_AES128,
+ .name = "aes128-cts",
+ .encrypt_name = "cts(cbc(aes))",
+ .cksum_name = "hmac(sha1)",
+ .encrypt = krb5_encrypt,
+ .decrypt = krb5_decrypt,
+ .mk_key = gss_krb5_aes_make_key,
+ .encrypt_v2 = gss_krb5_aes_encrypt,
+ .decrypt_v2 = gss_krb5_aes_decrypt,
+ .signalg = -1,
+ .sealalg = -1,
+ .keybytes = 16,
+ .keylength = 16,
+ .blocksize = 16,
+ .cksumlength = 12,
+ .keyed_cksum = 1,
+ },
+ /*
+ * AES256
+ */
+ {
+ .etype = ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ .ctype = CKSUMTYPE_HMAC_SHA1_96_AES256,
+ .name = "aes256-cts",
+ .encrypt_name = "cts(cbc(aes))",
+ .cksum_name = "hmac(sha1)",
+ .encrypt = krb5_encrypt,
+ .decrypt = krb5_decrypt,
+ .mk_key = gss_krb5_aes_make_key,
+ .encrypt_v2 = gss_krb5_aes_encrypt,
+ .decrypt_v2 = gss_krb5_aes_decrypt,
+ .signalg = -1,
+ .sealalg = -1,
+ .keybytes = 32,
+ .keylength = 32,
+ .blocksize = 16,
+ .cksumlength = 12,
+ .keyed_cksum = 1,
+ },
};
static int num_supported_enctypes =
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index d84632a..e7f0807 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -392,7 +392,7 @@ static const struct file_operations rpc_info_operations = {
static int
rpc_show_krb5_info(struct seq_file *m, void *v)
{
- seq_printf(m, "enctypes: 16,3,1,2\n");
+ seq_printf(m, "enctypes: 18,17,16,3,1,2\n");
return 0;
}
^ permalink raw reply related [flat|nested] 31+ messages in thread