* [enctypes round 3: PATCH 01/24] gss_krb5: create a define for token header size and clean up ptr location
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
@ 2008-05-06 21:03 ` Kevin Coffman
2008-05-06 21:03 ` [enctypes round 3: PATCH 02/24] gss_krb5: move gss_krb5_crypto into the krb5 module Kevin Coffman
` (23 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:03 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
cleanup:
Document token header size with a #define instead of open-coding it.
Don't needlessly increment "ptr" past the beginning of the header
which makes the values passed to functions more understandable and
eliminates the need for extra "krb5_hdr" pointer.
Clean up some intersecting white-space issues flagged by checkpatch.pl.
This leaves the checksum length hard-coded at 8 for DES. A later patch
cleans that up.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 3 ++
net/sunrpc/auth_gss/gss_krb5_seal.c | 26 +++++++++--------
net/sunrpc/auth_gss/gss_krb5_unseal.c | 16 +++++------
net/sunrpc/auth_gss/gss_krb5_wrap.c | 50 +++++++++++++++++----------------
4 files changed, 49 insertions(+), 46 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index a10f1fb..e7bbdba 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -51,6 +51,9 @@ struct krb5_ctx {
extern spinlock_t krb5_seq_lock;
+/* The length of the Kerberos GSS token header */
+#define GSS_KRB5_TOK_HDR_LEN (16)
+
#define KG_TOK_MIC_MSG 0x0101
#define KG_TOK_WRAP_MSG 0x0201
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 5f1d36d..b8f42ef 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -78,7 +78,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
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;
+ unsigned char *ptr, *msg_start;
s32 now;
u32 seq_send;
@@ -87,36 +87,36 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
now = get_seconds();
- token->len = g_token_size(&ctx->mech_used, 24);
+ token->len = g_token_size(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8);
ptr = token->data;
- g_make_token_header(&ctx->mech_used, 24, &ptr);
+ g_make_token_header(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8, &ptr);
- *ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
- *ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff);
+ /* ptr now at header described in rfc 1964, section 1.2.1: */
+ ptr[0] = (unsigned char) ((KG_TOK_MIC_MSG >> 8) & 0xff);
+ ptr[1] = (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;
+ msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + 8;
- *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5);
- memset(krb5_hdr + 4, 0xff, 4);
+ *(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5);
+ memset(ptr + 4, 0xff, 4);
- if (make_checksum("md5", krb5_hdr, 8, text, 0, &md5cksum))
+ if (make_checksum("md5", ptr, 8, text, 0, &md5cksum))
return GSS_S_FAILURE;
if (krb5_encrypt(ctx->seq, NULL, md5cksum.data,
md5cksum.data, md5cksum.len))
return GSS_S_FAILURE;
- memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
+ memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8);
spin_lock(&krb5_seq_lock);
seq_send = ctx->seq_send++;
spin_unlock(&krb5_seq_lock);
if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
- seq_send, krb5_hdr + 16, krb5_hdr + 8))
+ seq_send, ptr + GSS_KRB5_TOK_HDR_LEN,
+ ptr + 8))
return GSS_S_FAILURE;
return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index d91a5d0..066ec73 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -92,30 +92,30 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
read_token->len))
return GSS_S_DEFECTIVE_TOKEN;
- if ((*ptr++ != ((KG_TOK_MIC_MSG>>8)&0xff)) ||
- (*ptr++ != ( KG_TOK_MIC_MSG &0xff)) )
+ if ((ptr[0] != ((KG_TOK_MIC_MSG >> 8) & 0xff)) ||
+ (ptr[1] != (KG_TOK_MIC_MSG & 0xff)))
return GSS_S_DEFECTIVE_TOKEN;
/* XXX sanity-check bodysize?? */
- signalg = ptr[0] + (ptr[1] << 8);
+ signalg = ptr[2] + (ptr[3] << 8);
if (signalg != SGN_ALG_DES_MAC_MD5)
return GSS_S_DEFECTIVE_TOKEN;
- sealalg = ptr[2] + (ptr[3] << 8);
+ sealalg = ptr[4] + (ptr[5] << 8);
if (sealalg != SEAL_ALG_NONE)
return GSS_S_DEFECTIVE_TOKEN;
- if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
+ if ((ptr[6] != 0xff) || (ptr[7] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;
- if (make_checksum("md5", ptr - 2, 8, message_buffer, 0, &md5cksum))
+ if (make_checksum("md5", ptr, 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 + GSS_KRB5_TOK_HDR_LEN, 8))
return GSS_S_BAD_SIG;
/* it got through unscathed. Make sure the context is unexpired */
@@ -127,7 +127,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
/* do sequencing checks */
- if (krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction, &seqnum))
+ if (krb5_get_seq_num(ctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8, &direction, &seqnum))
return GSS_S_FAILURE;
if ((ctx->initiate && direction != 0xff) ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index b00b1b4..283cb25 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(struct gss_ctx *ctx, int offset,
char cksumdata[16];
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
int blocksize = 0, plainlen;
- unsigned char *ptr, *krb5_hdr, *msg_start;
+ unsigned char *ptr, *msg_start;
s32 now;
int headlen;
struct page **tmp_pages;
@@ -149,26 +149,26 @@ 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, 24 + plainlen, &ptr);
+ g_make_token_header(&kctx->mech_used,
+ GSS_KRB5_TOK_HDR_LEN + 8 + plainlen, &ptr);
- *ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff);
- *ptr++ = (unsigned char) (KG_TOK_WRAP_MSG&0xff);
+ /* ptr now at header described in rfc 1964, section 1.2.1: */
+ ptr[0] = (unsigned char) ((KG_TOK_WRAP_MSG >> 8) & 0xff);
+ ptr[1] = (unsigned char) (KG_TOK_WRAP_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;
+ msg_start = ptr + 24;
- *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5);
- memset(krb5_hdr + 4, 0xff, 4);
- *(__be16 *)(krb5_hdr + 4) = htons(SEAL_ALG_DES);
+ *(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5);
+ memset(ptr + 4, 0xff, 4);
+ *(__be16 *)(ptr + 4) = htons(SEAL_ALG_DES);
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("md5", ptr, 8, buf,
offset + headlen - blocksize, &md5cksum))
return GSS_S_FAILURE;
buf->pages = tmp_pages;
@@ -176,7 +176,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 - 8, 8);
+ memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8);
spin_lock(&krb5_seq_lock);
seq_send = kctx->seq_send++;
@@ -185,7 +185,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
/* XXX would probably be more efficient to compute checksum
* and encrypt at the same time: */
if ((krb5_make_seq_num(kctx->seq, kctx->initiate ? 0 : 0xff,
- seq_send, krb5_hdr + 16, krb5_hdr + 8)))
+ seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8)))
return GSS_S_FAILURE;
if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - blocksize,
@@ -219,38 +219,38 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf)
buf->len - offset))
return GSS_S_DEFECTIVE_TOKEN;
- if ((*ptr++ != ((KG_TOK_WRAP_MSG>>8)&0xff)) ||
- (*ptr++ != (KG_TOK_WRAP_MSG &0xff)) )
+ if ((ptr[0] != ((KG_TOK_WRAP_MSG >> 8) & 0xff)) ||
+ (ptr[1] != (KG_TOK_WRAP_MSG & 0xff)))
return GSS_S_DEFECTIVE_TOKEN;
/* XXX sanity-check bodysize?? */
/* get the sign and seal algorithms */
- signalg = ptr[0] + (ptr[1] << 8);
+ signalg = ptr[2] + (ptr[3] << 8);
if (signalg != SGN_ALG_DES_MAC_MD5)
return GSS_S_DEFECTIVE_TOKEN;
- sealalg = ptr[2] + (ptr[3] << 8);
+ sealalg = ptr[4] + (ptr[5] << 8);
if (sealalg != SEAL_ALG_DES)
return GSS_S_DEFECTIVE_TOKEN;
- if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
+ if ((ptr[6] != 0xff) || (ptr[7] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;
if (gss_decrypt_xdr_buf(kctx->enc, buf,
- ptr + 22 - (unsigned char *)buf->head[0].iov_base))
+ ptr + GSS_KRB5_TOK_HDR_LEN + 8 - (unsigned char *)buf->head[0].iov_base))
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("md5", ptr, 8, buf,
+ ptr + GSS_KRB5_TOK_HDR_LEN + 8 - (unsigned char *)buf->head[0].iov_base, &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 + GSS_KRB5_TOK_HDR_LEN, 8))
return GSS_S_BAD_SIG;
/* it got through unscathed. Make sure the context is unexpired */
@@ -262,8 +262,8 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf)
/* do sequencing checks */
- if (krb5_get_seq_num(kctx->seq, ptr + 14, ptr + 6, &direction,
- &seqnum))
+ if (krb5_get_seq_num(kctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8,
+ &direction, &seqnum))
return GSS_S_BAD_SIG;
if ((kctx->initiate && direction != 0xff) ||
@@ -274,7 +274,7 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, 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 + GSS_KRB5_TOK_HDR_LEN + 8 + 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] 26+ messages in thread* [enctypes round 3: PATCH 02/24] gss_krb5: move gss_krb5_crypto into the krb5 module
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2008-05-06 21:03 ` [enctypes round 3: PATCH 01/24] gss_krb5: create a define for token header size and clean up ptr location Kevin Coffman
@ 2008-05-06 21:03 ` Kevin Coffman
2008-05-06 21:03 ` [enctypes round 3: PATCH 03/24] rpcauth: update and document available space in xdr_buf when doing privacy Kevin Coffman
` (22 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:03 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
The gss_krb5_crypto.o object belongs in the rpcsec_gss_krb5 module.
Also, there is no need to export symbols from gss_krb5_crypto.c
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/auth_gss/Makefile | 4 ++--
net/sunrpc/auth_gss/gss_krb5_crypto.c | 10 ----------
2 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/net/sunrpc/auth_gss/Makefile b/net/sunrpc/auth_gss/Makefile
index f3431a7..4de8bcf 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
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
obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 1d52308..c93fca2 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -83,8 +83,6 @@ out:
return ret;
}
-EXPORT_SYMBOL(krb5_encrypt);
-
u32
krb5_decrypt(
struct crypto_blkcipher *tfm,
@@ -118,8 +116,6 @@ out:
return ret;
}
-EXPORT_SYMBOL(krb5_decrypt);
-
static int
checksummer(struct scatterlist *sg, void *data)
{
@@ -161,8 +157,6 @@ out:
return err ? GSS_S_FAILURE : 0;
}
-EXPORT_SYMBOL(make_checksum);
-
struct encryptor_desc {
u8 iv[8]; /* XXX hard-coded blocksize */
struct blkcipher_desc desc;
@@ -262,8 +256,6 @@ gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
return ret;
}
-EXPORT_SYMBOL(gss_encrypt_xdr_buf);
-
struct decryptor_desc {
u8 iv[8]; /* XXX hard-coded blocksize */
struct blkcipher_desc desc;
@@ -334,5 +326,3 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
return xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc);
}
-
-EXPORT_SYMBOL(gss_decrypt_xdr_buf);
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 03/24] rpcauth: update and document available space in xdr_buf when doing privacy
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
2008-05-06 21:03 ` [enctypes round 3: PATCH 01/24] gss_krb5: create a define for token header size and clean up ptr location Kevin Coffman
2008-05-06 21:03 ` [enctypes round 3: PATCH 02/24] gss_krb5: move gss_krb5_crypto into the krb5 module Kevin Coffman
@ 2008-05-06 21:03 ` Kevin Coffman
2008-05-06 21:03 ` [enctypes round 3: PATCH 04/24] gss_krb5: Use random value to initialize confounder Kevin Coffman
` (21 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:03 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
Make the client and server code consistent regarding the extra buffer
space made available for the auth code when wrapping data.
Add some comments/documentation about the available buffer space
in the xdr_buf head and tail when gss_wrap is called.
Add a compile-time check to make sure we are not exceeding the available
buffer space.
Add a central function to shift head data.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 25 +++++++++++++++
net/sunrpc/auth_gss/auth_gss.c | 14 ++++++--
net/sunrpc/auth_gss/gss_krb5_crypto.c | 56 +++++++++++++++++++++++++++++++++
net/sunrpc/auth_gss/gss_krb5_wrap.c | 7 ++--
net/sunrpc/auth_gss/gss_mech_switch.c | 14 ++++++++
net/sunrpc/auth_gss/svcauth_gss.c | 15 +++++++++
6 files changed, 123 insertions(+), 8 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index e7bbdba..5bb227e 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -40,6 +40,12 @@
#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 krb5_ctx {
int initiate; /* 1 = initiating, 0 = accepting */
struct crypto_blkcipher *enc;
@@ -113,6 +119,22 @@ enum seal_alg {
#define ENCTYPE_DES3_CBC_SHA1 0x0010
#define ENCTYPE_UNKNOWN 0x01ff
+/*
+ * This compile-time check verifies that we will not exceed the
+ * slack space allotted by the client and server auth_gss code
+ * before they call gss_wrap().
+ */
+#define GSS_KRB5_SLACK_CHECK \
+ BUILD_BUG_ON(GSS_KRB5_TOK_HDR_LEN /* gss token header */ \
+ + GSS_KRB5_MAX_CKSUM_LEN /* gss token checksum */ \
+ + GSS_KRB5_MAX_BLOCKSIZE /* confounder */ \
+ + GSS_KRB5_MAX_BLOCKSIZE /* possible padding */ \
+ + GSS_KRB5_TOK_HDR_LEN /* encrypted hdr in v2 token */\
+ + GSS_KRB5_MAX_CKSUM_LEN /* encryption hmac */ \
+ + 4 + 4 /* RPC verifier */ \
+ + GSS_KRB5_TOK_HDR_LEN \
+ + GSS_KRB5_MAX_CKSUM_LEN > RPC_MAX_AUTH_SIZE)
+
s32
make_checksum(char *, char *header, int hdrlen, struct xdr_buf *body,
int body_offset, struct xdr_netobj *cksum);
@@ -157,3 +179,6 @@ s32
krb5_get_seq_num(struct crypto_blkcipher *key,
unsigned char *cksum,
unsigned char *buf, int *direction, u32 *seqnum);
+
+int
+shift_head_data(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen);
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index cc12d5f..53e027e 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -65,7 +65,7 @@ static const struct rpc_credops gss_nullops;
#define NFS_NGROUPS 16
-#define GSS_CRED_SLACK 1024 /* XXX: unused */
+#define GSS_CRED_SLACK (RPC_MAX_AUTH_SIZE * 2)
/* length of a krb5 verifier (48), plus data added before arguments when
* using integrity (two 4-byte integers): */
#define GSS_VERF_SLACK 100
@@ -1137,15 +1137,21 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
inpages = snd_buf->pages + first;
snd_buf->pages = rqstp->rq_enc_pages;
snd_buf->page_base -= first << PAGE_CACHE_SHIFT;
- /* Give the tail its own page, in case we need extra space in the
- * head when wrapping: */
+ /*
+ * Give the tail its own page, in case we need extra space in the
+ * head when wrapping:
+ *
+ * call_allocate() allocates twice the slack space required
+ * by the authentication flavor to rq_callsize.
+ * For GSS, slack is GSS_CRED_SLACK.
+ */
if (snd_buf->page_len || snd_buf->tail[0].iov_len) {
tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]);
memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len);
snd_buf->tail[0].iov_base = tmp;
}
maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages);
- /* RPC_SLACK_SPACE should prevent this ever happening: */
+ /* slack space should prevent this ever happening: */
BUG_ON(snd_buf->len > snd_buf->buflen);
status = -EIO;
/* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index c93fca2..d0f3371 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -326,3 +326,59 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
return xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc);
}
+
+/*
+ * This function makes the assumption that it was ultimately called
+ * from gss_wrap().
+ *
+ * The client auth_gss code moves any existing tail data into a
+ * separate page before calling gss_wrap.
+ * The server svcauth_gss code ensures that both the head and the
+ * tail have slack space of RPC_MAX_AUTH_SIZE before calling gss_wrap.
+ *
+ * Even with that guarantee, this function may be called more than
+ * once in the processing of gss_wrap(). The best we can do is
+ * verify at compile-time (see GSS_KRB5_SLACK_CHECK) that the
+ * largest expected shift will fit within RPC_MAX_AUTH_SIZE.
+ * At run-time we can verify that a single invocation of this
+ * function doesn't attempt to use more the RPC_MAX_AUTH_SIZE.
+ */
+
+int
+shift_head_data(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen)
+{
+ u8 *p;
+
+ if (shiftlen == 0)
+ return 0;
+
+ GSS_KRB5_SLACK_CHECK;
+ BUG_ON(shiftlen > RPC_MAX_AUTH_SIZE);
+
+ /*
+ * If there is a tail, and it shares a page with the head,
+ * make sure we don't clobber the tail. This is a just a
+ * defensive check.
+ */
+ if (buf->tail[0].iov_base != NULL) {
+ if ((((long)buf->tail[0].iov_base >> PAGE_CACHE_SHIFT) ==
+ ((long)buf->head[0].iov_base >> PAGE_CACHE_SHIFT)) &&
+ buf->tail[0].iov_base - buf->head[0].iov_base < shiftlen) {
+ dprintk("%s: collision: head %p:%zu, tail %p:%zu, "
+ "shiftlen %u\n",
+ __func__, buf->head[0].iov_base,
+ buf->head[0].iov_len, buf->tail[0].iov_base,
+ buf->tail[0].iov_len, shiftlen);
+ return 1;
+ }
+ }
+
+ p = buf->head[0].iov_base + base;
+
+ memmove(p + shiftlen, p, buf->head[0].iov_len - base);
+
+ buf->head[0].iov_len += shiftlen;
+ buf->len += shiftlen;
+
+ return 0;
+}
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 283cb25..e809571 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -130,6 +130,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
dprintk("RPC: gss_wrap_kerberos\n");
+ GSS_KRB5_SLACK_CHECK;
now = get_seconds();
blocksize = crypto_blkcipher_blocksize(kctx->enc);
@@ -142,11 +143,9 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
ptr = buf->head[0].iov_base + offset;
/* shift data to make room for header. */
+ shift_head_data(buf, offset, headlen);
+
/* XXX Would be cleverer to encrypt while copying. */
- /* XXX bounds checking, slack, etc. */
- memmove(ptr + headlen, ptr, buf->head[0].iov_len - offset);
- buf->head[0].iov_len += headlen;
- buf->len += headlen;
BUG_ON((buf->len - offset - headlen) % blocksize);
g_make_token_header(&kctx->mech_used,
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index bce9d52..3cfc197 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -285,6 +285,20 @@ gss_verify_mic(struct gss_ctx *context_handle,
mic_token);
}
+/*
+ * This function is called from both the client and server code.
+ * Each makes guarantees about how much "slack" space is available
+ * for the underlying function in "buf"'s head and tail while
+ * performing the wrap.
+ *
+ * The client and server code allocate RPC_MAX_AUTH_SIZE extra
+ * space in both the head and tail which is available for use by
+ * the wrap function.
+ *
+ * Underlying functions should verify they do not use more than
+ * RPC_MAX_AUTH_SIZE of extra space in either the head or tail
+ * when performing the wrap.
+ */
u32
gss_wrap(struct gss_ctx *ctx_id,
int offset,
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 5905d56..675adeb 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1287,6 +1287,14 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
inpages = resbuf->pages;
/* XXX: Would be better to write some xdr helper functions for
* nfs{2,3,4}xdr.c that place the data right, instead of copying: */
+
+ /*
+ * If there is currently tail data, make sure there is
+ * room for the head, tail, and 2 * RPC_MAX_AUTH_SIZE in
+ * the page, and move the current tail data such that
+ * there is RPC_MAX_AUTH_SIZE slack space available in
+ * both the head and tail.
+ */
if (resbuf->tail[0].iov_base) {
BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base
+ PAGE_SIZE);
@@ -1299,6 +1307,13 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
resbuf->tail[0].iov_len);
resbuf->tail[0].iov_base += RPC_MAX_AUTH_SIZE;
}
+ /*
+ * If there is no current tail data, make sure there is
+ * room for the head data, and 2 * RPC_MAX_AUTH_SIZE in the
+ * allotted page, and set up tail information such that there
+ * is RPC_MAX_AUTH_SIZE slack space available in both the
+ * head and tail.
+ */
if (resbuf->tail[0].iov_base == NULL) {
if (resbuf->head[0].iov_len + 2*RPC_MAX_AUTH_SIZE > PAGE_SIZE)
return -ENOMEM;
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 04/24] gss_krb5: Use random value to initialize confounder
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (2 preceding siblings ...)
2008-05-06 21:03 ` [enctypes round 3: PATCH 03/24] rpcauth: update and document available space in xdr_buf when doing privacy Kevin Coffman
@ 2008-05-06 21:03 ` Kevin Coffman
2008-05-06 21:03 ` [enctypes round 3: PATCH 05/24] Don't expect blocksize to always be 8 when calculating padding Kevin Coffman
` (20 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:03 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
Initialize the value used for the confounder to a random value
rather than starting from zero.
Allow for confounders of length 8 or 16 (which will be needed for AES).
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/auth_gss/gss_krb5_wrap.c | 22 ++++++++++++++++++----
1 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index e809571..a0660f5 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -87,8 +87,8 @@ out:
return 0;
}
-static inline void
-make_confounder(char *p, int blocksize)
+static void
+make_confounder(char *p, u32 conflen)
{
static u64 i = 0;
u64 *q = (u64 *)p;
@@ -102,8 +102,22 @@ make_confounder(char *p, int blocksize)
* uniqueness would mean worrying about atomicity and rollover, and I
* don't care enough. */
- BUG_ON(blocksize != 8);
- *q = i++;
+ /* initialize to random value */
+ if (i == 0) {
+ i = random32();
+ i = (i << 32) | random32();
+ }
+
+ switch (conflen) {
+ case 16:
+ *q++ = i++;
+ /* fall through */
+ case 8:
+ *q++ = i++;
+ break;
+ default:
+ BUG();
+ }
}
/* Assumptions: the head and tail of inbuf are ours to play with.
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 05/24] Don't expect blocksize to always be 8 when calculating padding
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (3 preceding siblings ...)
2008-05-06 21:03 ` [enctypes round 3: PATCH 04/24] gss_krb5: Use random value to initialize confounder Kevin Coffman
@ 2008-05-06 21:03 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 06/24] gss_krb5: split up functions in preparation of adding new enctypes Kevin Coffman
` (19 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:03 UTC (permalink / raw)
To: bfields; +Cc: 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 a0660f5..4c14b0a 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] 26+ messages in thread* [enctypes round 3: PATCH 06/24] gss_krb5: split up functions in preparation of adding new enctypes
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (4 preceding siblings ...)
2008-05-06 21:03 ` [enctypes round 3: PATCH 05/24] Don't expect blocksize to always be 8 when calculating padding Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 07/24] gss_krb5: prepare for new context format Kevin Coffman
` (18 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: 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 | 20 +++++++++++++++--
net/sunrpc/auth_gss/gss_krb5_unseal.c | 21 ++++++++++++++++--
net/sunrpc/auth_gss/gss_krb5_wrap.c | 38 ++++++++++++++++++++++++++++-----
5 files changed, 69 insertions(+), 12 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 5bb227e..12bd0dd 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -48,6 +48,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 60c3dba..c1d5f55 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 b8f42ef..6319b33 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, *msg_start;
@@ -121,3 +120,18 @@ 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) {
+ default:
+ BUG();
+ case ENCTYPE_DES_CBC_RAW:
+ return gss_get_mic_v1(ctx, text, token);
+ }
+}
+
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 066ec73..945609a 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,19 @@ 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) {
+ default:
+ BUG();
+ case ENCTYPE_DES_CBC_RAW:
+ return gss_verify_mic_v1(ctx, message_buffer, read_token);
+ }
+}
+
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 4c14b0a..743fa92 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -125,11 +125,10 @@ make_confounder(char *p, u32 conflen)
/* 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;
@@ -205,10 +204,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];
@@ -296,3 +294,31 @@ 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) {
+ default:
+ BUG();
+ case ENCTYPE_DES_CBC_RAW:
+ return gss_wrap_kerberos_v1(kctx, offset, buf, pages);
+ }
+}
+
+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) {
+ default:
+ BUG();
+ case ENCTYPE_DES_CBC_RAW:
+ return gss_unwrap_kerberos_v1(kctx, offset, buf);
+ }
+}
+
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 07/24] gss_krb5: prepare for new context format
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (5 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 06/24] gss_krb5: split up functions in preparation of adding new enctypes Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 08/24] gss_krb5: introduce encryption type framework Kevin Coffman
` (17 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: 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 c1d5f55..20e6e8e 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] 26+ messages in thread* [enctypes round 3: PATCH 08/24] gss_krb5: introduce encryption type framework
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (6 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 07/24] gss_krb5: prepare for new context format Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 09/24] gss_krb5: add ability to have a keyed checksum (hmac) Kevin Coffman
` (16 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: 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 | 25 +++++++++
net/sunrpc/auth_gss/gss_krb5_crypto.c | 18 +++----
net/sunrpc/auth_gss/gss_krb5_mech.c | 89 +++++++++++++++++++++++++++------
net/sunrpc/auth_gss/gss_krb5_seal.c | 49 +++++++++++-------
net/sunrpc/auth_gss/gss_krb5_unseal.c | 15 +++---
net/sunrpc/auth_gss/gss_krb5_wrap.c | 79 ++++++++++++++++++++++-------
6 files changed, 205 insertions(+), 70 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 12bd0dd..8d79c44 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -4,7 +4,7 @@
* Adapted from MIT Kerberos 5-1.2.1 lib/include/krb5.h,
* lib/gssapi/krb5/gssapiP_krb5.h, and others
*
- * Copyright (c) 2000 The Regents of the University of Michigan.
+ * Copyright (c) 2000-2008 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
@@ -36,6 +36,7 @@
*
*/
+#include <linux/crypto.h>
#include <linux/sunrpc/auth_gss.h>
#include <linux/sunrpc/gss_err.h>
#include <linux/sunrpc/gss_asn1.h>
@@ -46,9 +47,31 @@
/* 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 d0f3371..d3025aa 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -1,7 +1,7 @@
/*
* linux/net/sunrpc/gss_krb5_crypto.c
*
- * Copyright (c) 2000 The Regents of the University of Michigan.
+ * Copyright (c) 2000-2008 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
@@ -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;
@@ -93,13 +93,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;
@@ -158,7 +158,7 @@ out:
}
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;
@@ -199,7 +199,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)
@@ -257,7 +257,7 @@ gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *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;
@@ -279,7 +279,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 20e6e8e..aac9168 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -1,7 +1,7 @@
/*
* linux/net/sunrpc/gss_krb5_mech.c
*
- * Copyright (c) 2001 The Regents of the University of Michigan.
+ * Copyright (c) 2001-2008 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
@@ -48,6 +48,49 @@
# 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 = ARRAY_SIZE(supported_gss_krb5_enctypes);
+
+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 +121,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 +187,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 +221,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 6319b33..f0e9a65 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -3,7 +3,7 @@
*
* Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5seal.c
*
- * Copyright (c) 2000 The Regents of the University of Michigan.
+ * Copyright (c) 2000-2008 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
@@ -71,36 +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 = GSS_KRB5_TOK_HDR_LEN + 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, *msg_start;
+ char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+ struct xdr_netobj md5cksum = {.len = sizeof(cksumdata),
+ .data = cksumdata};
+ void *ptr;
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, GSS_KRB5_TOK_HDR_LEN + 8);
-
- ptr = token->data;
- g_make_token_header(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8, &ptr);
-
- /* ptr now at header described in rfc 1964, section 1.2.1: */
- ptr[0] = (unsigned char) ((KG_TOK_MIC_MSG >> 8) & 0xff);
- ptr[1] = (unsigned char) (KG_TOK_MIC_MSG & 0xff);
-
- msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + 8;
-
- *(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5);
- memset(ptr + 4, 0xff, 4);
+ ptr = setup_token(ctx, token);
- if (make_checksum("md5", ptr, 8, text, 0, &md5cksum))
+ if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 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 945609a..ffba3a9 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -3,7 +3,7 @@
*
* Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5unseal.c
*
- * Copyright (c) 2000 The Regents of the University of Michigan.
+ * Copyright (c) 2000-2008 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
@@ -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;
u32 seqnum;
@@ -98,7 +99,7 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
/* XXX sanity-check bodysize?? */
signalg = ptr[2] + (ptr[3] << 8);
- if (signalg != SGN_ALG_DES_MAC_MD5)
+ if (signalg != ctx->gk5e->signalg)
return GSS_S_DEFECTIVE_TOKEN;
sealalg = ptr[4] + (ptr[5] << 8);
@@ -108,13 +109,15 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
if ((ptr[6] != 0xff) || (ptr[7] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;
- if (make_checksum("md5", ptr, 8, message_buffer, 0, &md5cksum))
+ if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 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 + GSS_KRB5_TOK_HDR_LEN, 8))
+ if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN,
+ 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 743fa92..6de2db3 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -1,3 +1,33 @@
+/*
+ * 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.
+ */
+
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
@@ -129,8 +159,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, *msg_start;
s32 now;
@@ -138,7 +169,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__);
GSS_KRB5_SLACK_CHECK;
now = get_seconds();
@@ -148,8 +179,9 @@ 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,
+ GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength + plainlen) -
+ (buf->len - offset);
ptr = buf->head[0].iov_base + offset;
/* shift data to make room for header. */
@@ -159,25 +191,26 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
BUG_ON((buf->len - offset - headlen) % blocksize);
g_make_token_header(&kctx->mech_used,
- GSS_KRB5_TOK_HDR_LEN + 8 + plainlen, &ptr);
+ GSS_KRB5_TOK_HDR_LEN +
+ kctx->gk5e->cksumlength + plainlen, &ptr);
/* ptr now at header described in rfc 1964, section 1.2.1: */
ptr[0] = (unsigned char) ((KG_TOK_WRAP_MSG >> 8) & 0xff);
ptr[1] = (unsigned char) (KG_TOK_WRAP_MSG & 0xff);
- msg_start = ptr + 24;
+ msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength;
- *(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5);
+ *(__be16 *)(ptr + 2) = cpu_to_le16(kctx->gk5e->signalg);
memset(ptr + 4, 0xff, 4);
- *(__be16 *)(ptr + 4) = htons(SEAL_ALG_DES);
+ *(__be16 *)(ptr + 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", ptr, 8, buf,
+ if (make_checksum((char *)kctx->gk5e->cksum_name, ptr, 8, buf,
offset + headlen - blocksize, &md5cksum))
return GSS_S_FAILURE;
buf->pages = tmp_pages;
@@ -209,8 +242,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;
@@ -219,6 +253,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");
@@ -236,22 +271,27 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
/* get the sign and seal algorithms */
signalg = ptr[2] + (ptr[3] << 8);
- if (signalg != SGN_ALG_DES_MAC_MD5)
+ if (signalg != kctx->gk5e->signalg)
return GSS_S_DEFECTIVE_TOKEN;
sealalg = ptr[4] + (ptr[5] << 8);
- if (sealalg != SEAL_ALG_DES)
+ if (sealalg != kctx->gk5e->sealalg)
return GSS_S_DEFECTIVE_TOKEN;
if ((ptr[6] != 0xff) || (ptr[7] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;
- if (gss_decrypt_xdr_buf(kctx->enc, buf,
- ptr + GSS_KRB5_TOK_HDR_LEN + 8 - (unsigned char *)buf->head[0].iov_base))
+ /*
+ * Data starts after token header and checksum. ptr points
+ * to the beginning of the token header
+ */
+ crypt_offset = ptr + (GSS_KRB5_TOK_HDR_LEN + 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, 8, buf,
- ptr + GSS_KRB5_TOK_HDR_LEN + 8 - (unsigned char *)buf->head[0].iov_base, &md5cksum))
+ if (make_checksum((char *)kctx->gk5e->cksum_name, ptr, 8, buf,
+ crypt_offset, &md5cksum))
return GSS_S_FAILURE;
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
@@ -282,7 +322,8 @@ 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 + GSS_KRB5_TOK_HDR_LEN + 8 + blocksize;
+ data_start = ptr + (GSS_KRB5_TOK_HDR_LEN + 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] 26+ messages in thread* [enctypes round 3: PATCH 09/24] gss_krb5: add ability to have a keyed checksum (hmac)
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (7 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 08/24] gss_krb5: introduce encryption type framework Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 10/24] gss_krb5: import functionality to derive keys into the kernel Kevin Coffman
` (15 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: 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 | 30 +++++++++++-------
6 files changed, 88 insertions(+), 34 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 8d79c44..6fc04d1 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;
@@ -159,9 +163,10 @@ enum seal_alg {
+ GSS_KRB5_TOK_HDR_LEN \
+ GSS_KRB5_MAX_CKSUM_LEN > RPC_MAX_AUTH_SIZE)
-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 d3025aa..389f366 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -124,21 +124,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;
@@ -150,8 +171,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 aac9168..eecee9c 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 f0e9a65..c4df7af 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 *ptr;
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,
ptr = setup_token(ctx, token);
- if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 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, ptr, 8, text, 0, cksumkey, &md5cksum))
return GSS_S_FAILURE;
- memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8);
+ memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, 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 ffba3a9..aff3fce 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,
u32 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[6] != 0xff) || (ptr[7] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;
- if (make_checksum((char *)ctx->gk5e->cksum_name, ptr, 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, 8, message_buffer, 0,
+ cksumkey, &md5cksum))
return GSS_S_FAILURE;
- if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN,
+ if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN,
ctx->gk5e->cksumlength))
return GSS_S_BAD_SIG;
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 6de2db3..f034af3 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -168,6 +168,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__);
@@ -207,18 +208,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, ptr, 8, buf,
- offset + headlen - blocksize, &md5cksum))
+ if (make_checksum(kctx, ptr, 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(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8);
+ memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);
spin_lock(&krb5_seq_lock);
seq_send = kctx->seq_send++;
@@ -254,6 +257,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");
@@ -290,15 +294,17 @@ 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, 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, 8, buf, crypt_offset,
+ cksumkey, &md5cksum))
return GSS_S_FAILURE;
- if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8))
+ if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN,
+ kctx->gk5e->cksumlength))
return GSS_S_BAD_SIG;
/* it got through unscathed. Make sure the context is unexpired */
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 10/24] gss_krb5: import functionality to derive keys into the kernel
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (8 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 09/24] gss_krb5: add ability to have a keyed checksum (hmac) Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 11/24] gss_krb5: handle new context format from gssd Kevin Coffman
` (14 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: 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 | 31 ++++
net/sunrpc/auth_gss/Makefile | 2
net/sunrpc/auth_gss/gss_krb5_keys.c | 252 +++++++++++++++++++++++++++++++++++
net/sunrpc/auth_gss/gss_krb5_mech.c | 1
4 files changed, 285 insertions(+), 1 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 6fc04d1..b17a310 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 {
@@ -148,6 +154,25 @@ enum seal_alg {
#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)
+
+/*
* This compile-time check verifies that we will not exceed the
* slack space allotted by the client and server auth_gss code
* before they call gss_wrap().
@@ -211,3 +236,9 @@ krb5_get_seq_num(struct crypto_blkcipher *key,
int
shift_head_data(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen);
+
+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 4de8bcf..74a2317 100644
--- a/net/sunrpc/auth_gss/Makefile
+++ b/net/sunrpc/auth_gss/Makefile
@@ -10,7 +10,7 @@ auth_rpcgss-objs := auth_gss.o gss_generic_token.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_crypto.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..832ce90
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_krb5_keys.c
@@ -0,0 +1,252 @@
+/*
+ * 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;
+}
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index eecee9c..bff929f 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] 26+ messages in thread* [enctypes round 3: PATCH 11/24] gss_krb5: handle new context format from gssd
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (9 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 10/24] gss_krb5: import functionality to derive keys into the kernel Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 12/24] gss_krb5: add support for triple-des encryption Kevin Coffman
` (13 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: 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 | 237 +++++++++++++++++++++++++++++++++++
2 files changed, 255 insertions(+), 1 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index b17a310..81d6fc2 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;
@@ -151,6 +166,10 @@ enum seal_alg {
#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 bff929f..bf0d0c1 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -48,6 +48,8 @@
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
+static struct gss_api_mech gss_kerberos_mech; /* forward declaration */
+
static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
/*
* DES (All DES enctypes are mapped to the same gss functionality)
@@ -246,6 +248,237 @@ 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];
+ 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;
+
+ ctx->enc = context_v2_alloc_cipher(ctx, rawkey);
+ 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;
+ /* set seq_send for use by "older" enctypes */
+ ctx->seq_send = ctx->seq_send64;
+ if (ctx->seq_send64 != ctx->seq_send) {
+ dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__,
+ (long unsigned)ctx->seq_send64, ctx->seq_send);
+ 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;
+ }
+
+ ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data,
+ gss_kerberos_mech.gm_oid.len, GFP_KERNEL);
+ if (unlikely(ctx->mech_used.data == NULL)) {
+ p = ERR_PTR(-ENOMEM);
+ goto out_err;
+ }
+ ctx->mech_used.len = gss_kerberos_mech.gm_oid.len;
+
+ 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)
@@ -262,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;
@@ -279,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] 26+ messages in thread* [enctypes round 3: PATCH 12/24] gss_krb5: add support for triple-des encryption
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (10 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 11/24] gss_krb5: handle new context format from gssd Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 13/24] Add new pipefs file indicating which Kerberos enctypes the kernel supports Kevin Coffman
` (12 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
Add the final pieces to support the triple-des encryption type.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
fs/Kconfig | 2 +
include/linux/sunrpc/gss_krb5.h | 5 +++
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 +
8 files changed, 90 insertions(+), 0 deletions(-)
diff --git a/fs/Kconfig b/fs/Kconfig
index cf12c40..f5bf82e 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1829,6 +1829,8 @@ config RPCSEC_GSS_KRB5
select CRYPTO_MD5
select CRYPTO_DES
select CRYPTO_CBC
+ select CRYPTO_HMAC
+ select CRYPTO_SHA1
help
Choose Y here to enable Secure RPC using the Kerberos version 5
GSS-API mechanism (RFC 1964).
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 81d6fc2..c686fa9 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -261,3 +261,8 @@ 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 389f366..0c91186 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -185,6 +185,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 832ce90..29c4bc5 100644
--- a/net/sunrpc/auth_gss/gss_krb5_keys.c
+++ b/net/sunrpc/auth_gss/gss_krb5_keys.c
@@ -250,3 +250,56 @@ err_free_cipher:
err_return:
return ret;
}
+
+#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 bf0d0c1..de6fc76 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -71,6 +71,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 = ARRAY_SIZE(supported_gss_krb5_enctypes);
@@ -439,6 +459,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 c4df7af..ba86910 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -143,6 +143,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
default:
BUG();
case ENCTYPE_DES_CBC_RAW:
+ case ENCTYPE_DES3_CBC_RAW:
return gss_get_mic_v1(ctx, text, token);
}
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index aff3fce..becd212 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -153,6 +153,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
default:
BUG();
case ENCTYPE_DES_CBC_RAW:
+ case ENCTYPE_DES3_CBC_RAW:
return gss_verify_mic_v1(ctx, message_buffer, read_token);
}
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index f034af3..c541d20 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -352,6 +352,7 @@ gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
default:
BUG();
case ENCTYPE_DES_CBC_RAW:
+ case ENCTYPE_DES3_CBC_RAW:
return gss_wrap_kerberos_v1(kctx, offset, buf, pages);
}
}
@@ -365,6 +366,7 @@ gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf)
default:
BUG();
case ENCTYPE_DES_CBC_RAW:
+ case ENCTYPE_DES3_CBC_RAW:
return gss_unwrap_kerberos_v1(kctx, offset, buf);
}
}
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 13/24] Add new pipefs file indicating which Kerberos enctypes the kernel supports
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (11 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 12/24] gss_krb5: add support for triple-des encryption Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 14/24] gss_krb5: add DES3 to the list of supported enctypes Kevin Coffman
` (11 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
New file, krb5_info, indicates which Kerberos encryption types are
supported by the kernel rpcsec_gss 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.
ATTENTION: This is a TEMPORARY solution and will not be committed
upstream. The final solution will be to add the enctype
information to the upcall.
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 5a9b0e7..5f159a0 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] 26+ messages in thread* [enctypes round 3: PATCH 14/24] gss_krb5: add DES3 to the list of supported enctypes
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (12 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 13/24] Add new pipefs file indicating which Kerberos enctypes the kernel supports Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 15/24] sunrpc: Export function write_bytes_to_xdr_buf Kevin Coffman
` (10 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
This TEMPORARY patch notifies gssd that DES3 encryption is supported
by the kernel's gss_krb5 code.
This patch will go away when the final solution of adding the
enctype information to the upcall to gssd is implemented.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/rpc_pipe.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 5f159a0..c2d7817 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] 26+ messages in thread* [enctypes round 3: PATCH 15/24] sunrpc: Export function write_bytes_to_xdr_buf
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (13 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 14/24] gss_krb5: add DES3 to the list of supported enctypes Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 16/24] gss_krb5: add support for new token formats in rfc4121 Kevin Coffman
` (9 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
Implementation of the AES encryption for gss_krb5 needs to use
read_bytes_from_xdr_buf() and write_bytes_to_xdr_buf().
The read function is already exported. Export the write function.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/xdr.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 79a55d5..493c95c 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -761,6 +761,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] 26+ messages in thread* [enctypes round 3: PATCH 16/24] gss_krb5: add support for new token formats in rfc4121
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (14 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 15/24] sunrpc: Export function write_bytes_to_xdr_buf Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:04 ` [enctypes round 3: PATCH 17/24] gss_krb5: add remaining pieces to enable AES encryption support Kevin Coffman
` (8 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: 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 | 74 ++++++++++
net/sunrpc/auth_gss/gss_krb5_seal.c | 70 +++++++++
net/sunrpc/auth_gss/gss_krb5_unseal.c | 61 ++++++++
net/sunrpc/auth_gss/gss_krb5_wrap.c | 247 +++++++++++++++++++++++++++++++++
5 files changed, 480 insertions(+), 0 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index c686fa9..c6bb014 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 */
@@ -112,6 +120,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,
@@ -136,6 +156,9 @@ enum seal_alg {
#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)
@@ -212,6 +235,11 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
struct xdr_buf *body, int body_offset, u8 *cksumkey,
struct xdr_netobj *cksumout);
+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 0c91186..66ba0b3 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -198,6 +198,80 @@ out:
return err ? GSS_S_FAILURE : 0;
}
+/*
+ * 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
+ * Inclusion of the header data in the calculation of the
+ * checksum is optional.
+ */
+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;
+ if (header != NULL) {
+ 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;
+}
+
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 ba86910..6f01d87 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 = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength;
+ return krb5_hdr;
+}
+
static u32
gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
struct xdr_netobj *token)
@@ -134,6 +161,46 @@ 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, GSS_KRB5_TOK_HDR_LEN,
+ text, 0, cksumkey, &cksumobj))
+ return GSS_S_FAILURE;
+
+ memcpy(krb5_hdr + GSS_KRB5_TOK_HDR_LEN, 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)
{
@@ -145,6 +212,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);
}
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index becd212..5305b02 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -142,6 +142,64 @@ 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, GSS_KRB5_TOK_HDR_LEN, message_buffer, 0,
+ cksumkey, &cksumobj))
+ return GSS_S_FAILURE;
+
+ if (memcmp(cksumobj.data, ptr + GSS_KRB5_TOK_HDR_LEN,
+ 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,
@@ -155,6 +213,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);
}
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index c541d20..0c47bdd 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -342,6 +342,247 @@ 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 (shift_head_data(buf, offset + GSS_KRB5_TOK_HDR_LEN, rotate_count))
+ goto out;
+ memcpy(buf->head[0].iov_base + offset + GSS_KRB5_TOK_HDR_LEN, tbuf,
+ buf->tail[0].iov_len);
+ /* this is adjusted upwards in 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 - GSS_KRB5_TOK_HDR_LEN);
+
+ 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__);
+
+ GSS_KRB5_SLACK_CHECK;
+
+ 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 */
+ if (shift_head_data(buf, offset, GSS_KRB5_TOK_HDR_LEN))
+ 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[GSS_KRB5_TOK_HDR_LEN];
+ 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 - GSS_KRB5_TOK_HDR_LEN - tailskip,
+ decrypted_hdr, GSS_KRB5_TOK_HDR_LEN);
+ 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;
+ }
+
+ /* do 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 + GSS_KRB5_TOK_HDR_LEN + headskip;
+ BUG_ON(offset + GSS_KRB5_TOK_HDR_LEN + headskip + movelen >
+ buf->head[0].iov_len);
+ memmove(ptr, ptr + GSS_KRB5_TOK_HDR_LEN + headskip, movelen);
+ buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip;
+ buf->len -= GSS_KRB5_TOK_HDR_LEN + headskip;
+
+ return GSS_S_COMPLETE;
+}
+
u32
gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
struct xdr_buf *buf, struct page **pages)
@@ -354,6 +595,9 @@ gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
case ENCTYPE_DES_CBC_RAW:
case ENCTYPE_DES3_CBC_RAW:
return gss_wrap_kerberos_v1(kctx, offset, buf, pages);
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ return gss_wrap_kerberos_v2(kctx, offset, buf, pages);
}
}
@@ -368,6 +612,9 @@ gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf)
case ENCTYPE_DES_CBC_RAW:
case ENCTYPE_DES3_CBC_RAW:
return gss_unwrap_kerberos_v1(kctx, offset, buf);
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ return gss_unwrap_kerberos_v2(kctx, offset, buf);
}
}
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 17/24] gss_krb5: add remaining pieces to enable AES encryption support
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (15 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 16/24] gss_krb5: add support for new token formats in rfc4121 Kevin Coffman
@ 2008-05-06 21:04 ` Kevin Coffman
2008-05-06 21:05 ` [enctypes round 3: PATCH 18/24] gss_krb5: add AES to the list of supported enctypes Kevin Coffman
` (7 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:04 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
Add the remaining pieces to enable support for Kerberos AES
encryption types.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
fs/Kconfig | 2
include/linux/sunrpc/gss_krb5.h | 20 +++
net/sunrpc/auth_gss/gss_krb5_crypto.c | 248 +++++++++++++++++++++++++++++++++
net/sunrpc/auth_gss/gss_krb5_keys.c | 30 ++++
net/sunrpc/auth_gss/gss_krb5_mech.c | 86 ++++++++++-
net/sunrpc/auth_gss/gss_krb5_wrap.c | 2
6 files changed, 378 insertions(+), 10 deletions(-)
diff --git a/fs/Kconfig b/fs/Kconfig
index f5bf82e..08be92c 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1831,6 +1831,8 @@ config RPCSEC_GSS_KRB5
select CRYPTO_CBC
select CRYPTO_HMAC
select CRYPTO_SHA1
+ select CRYPTO_AES
+ select CRYPTO_CTS
help
Choose Y here to enable Secure RPC using the Kerberos version 5
GSS-API mechanism (RFC 1964).
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index c6bb014..2adf16a 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -99,6 +99,8 @@ struct krb5_ctx {
struct crypto_blkcipher *seq;
struct crypto_blkcipher *acceptor_enc;
struct crypto_blkcipher *initiator_enc;
+ struct crypto_blkcipher *acceptor_enc_aux;
+ struct crypto_blkcipher *initiator_enc_aux;
u8 cksum[GSS_KRB5_MAX_KEYLEN];
s32 endtime;
u32 seq_send;
@@ -294,3 +296,21 @@ 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);
+
+void
+make_confounder(char *p, u32 conflen);
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 66ba0b3..c50ec81 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>
@@ -497,3 +498,250 @@ shift_head_data(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen)
return 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;
+ u8 *ecptr;
+ struct crypto_blkcipher *cipher, *aux_cipher;
+ int blocksize;
+ struct page **save_pages;
+ int nblocks, nbytes;
+ struct encryptor_desc desc;
+ u32 cbcbytes;
+
+ if (kctx->initiate) {
+ cipher = kctx->initiator_enc;
+ aux_cipher = kctx->initiator_enc_aux;
+ cksumkey = kctx->initiator_integ;
+ } else {
+ cipher = kctx->acceptor_enc;
+ aux_cipher = kctx->acceptor_enc_aux;
+ cksumkey = kctx->acceptor_integ;
+ }
+ blocksize = crypto_blkcipher_blocksize(cipher);
+
+ /* hide the gss token header and insert the confounder */
+ offset += GSS_KRB5_TOK_HDR_LEN;
+ if (shift_head_data(buf, offset, blocksize))
+ return GSS_S_FAILURE;
+ make_confounder(buf->head[0].iov_base + offset, blocksize);
+ offset -= GSS_KRB5_TOK_HDR_LEN;
+
+ 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,
+ GSS_KRB5_TOK_HDR_LEN);
+ buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN;
+ buf->len += GSS_KRB5_TOK_HDR_LEN;
+
+ /* 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 = make_checksum_v2(kctx, NULL, 0, buf,
+ offset + GSS_KRB5_TOK_HDR_LEN, cksumkey, &hmac);
+ buf->pages = save_pages;
+ if (err)
+ return GSS_S_FAILURE;
+
+ nbytes = buf->len - offset - GSS_KRB5_TOK_HDR_LEN;
+ nblocks = (nbytes + blocksize - 1) / blocksize;
+ cbcbytes = 0;
+ if (nblocks > 2)
+ cbcbytes = (nblocks - 2) * blocksize;
+
+ memset(desc.iv, 0, sizeof(desc.iv));
+
+ if (cbcbytes) {
+ desc.pos = offset + GSS_KRB5_TOK_HDR_LEN;
+ desc.fragno = 0;
+ desc.fraglen = 0;
+ desc.pages = pages;
+ desc.outbuf = buf;
+ desc.desc.info = desc.iv;
+ desc.desc.flags = 0;
+ desc.desc.tfm = aux_cipher;
+
+ sg_init_table(desc.infrags, 4);
+ sg_init_table(desc.outfrags, 4);
+
+ err = xdr_process_buf(buf, offset + GSS_KRB5_TOK_HDR_LEN,
+ 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 + GSS_KRB5_TOK_HDR_LEN + 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 (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;
+ struct crypto_blkcipher *cipher, *aux_cipher;
+ 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;
+ aux_cipher = kctx->acceptor_enc_aux;
+ cksum_key = kctx->acceptor_integ;
+ } else {
+ cipher = kctx->initiator_enc;
+ aux_cipher = kctx->initiator_enc_aux;
+ 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 + GSS_KRB5_TOK_HDR_LEN,
+ (buf->len - offset - GSS_KRB5_TOK_HDR_LEN -
+ 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) {
+ desc.fragno = 0;
+ desc.fraglen = 0;
+ desc.desc.info = desc.iv;
+ desc.desc.flags = 0;
+ desc.desc.tfm = aux_cipher;
+
+ 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 = make_checksum_v2(kctx, NULL, 0, &subbuf, 0,
+ cksum_key, &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 (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 29c4bc5..59bb1e3 100644
--- a/net/sunrpc/auth_gss/gss_krb5_keys.c
+++ b/net/sunrpc/auth_gss/gss_krb5_keys.c
@@ -303,3 +303,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 de6fc76..f626e4b 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -91,6 +91,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 = ARRAY_SIZE(supported_gss_krb5_enctypes);
@@ -269,20 +313,19 @@ out_err:
}
struct crypto_blkcipher *
-context_v2_alloc_cipher(struct krb5_ctx *ctx, u8 *key)
+context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key)
{
struct crypto_blkcipher *cp;
- cp = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name,
- 0, CRYPTO_ALG_ASYNC);
+ cp = crypto_alloc_blkcipher(cname, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(cp)) {
printk("gss_kerberos_mech: unable to initialize "
- "crypto algorithm %s\n", ctx->gk5e->encrypt_name);
+ "crypto algorithm %s\n", cname);
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 algorithm %s\n", cname);
crypto_free_blkcipher(cp);
return NULL;
}
@@ -314,11 +357,13 @@ context_derive_keys_des3(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
keyout.len = keylen;
/* seq uses the raw key */
- ctx->seq = context_v2_alloc_cipher(ctx, rawkey);
+ ctx->seq = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name,
+ rawkey);
if (ctx->seq == NULL)
goto out_err;
- ctx->enc = context_v2_alloc_cipher(ctx, rawkey);
+ ctx->enc = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name,
+ rawkey);
if (ctx->enc == NULL)
goto out_free_seq;
@@ -365,7 +410,9 @@ context_derive_keys_new(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
__func__, err);
goto out_err;
}
- ctx->initiator_enc = context_v2_alloc_cipher(ctx, ctx->initiator_seal);
+ ctx->initiator_enc = context_v2_alloc_cipher(ctx,
+ ctx->gk5e->encrypt_name,
+ ctx->initiator_seal);
if (ctx->initiator_enc == NULL)
goto out_err;
@@ -378,7 +425,9 @@ context_derive_keys_new(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
__func__, err);
goto out_free_initiator_enc;
}
- ctx->acceptor_enc = context_v2_alloc_cipher(ctx, ctx->acceptor_seal);
+ ctx->acceptor_enc = context_v2_alloc_cipher(ctx,
+ ctx->gk5e->encrypt_name,
+ ctx->acceptor_seal);
if (ctx->acceptor_enc == NULL)
goto out_free_initiator_enc;
@@ -422,6 +471,23 @@ context_derive_keys_new(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
goto out_free_acceptor_enc;
}
+ switch (ctx->enctype) {
+ case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
+ case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
+ ctx->initiator_enc_aux =
+ context_v2_alloc_cipher(ctx, "cbc(aes)",
+ ctx->initiator_seal);
+ if (ctx->initiator_enc_aux == NULL)
+ goto out_free_acceptor_enc;
+ ctx->acceptor_enc_aux =
+ context_v2_alloc_cipher(ctx, "cbc(aes)",
+ ctx->acceptor_seal);
+ if (ctx->acceptor_enc_aux == NULL) {
+ crypto_free_blkcipher(ctx->initiator_enc_aux);
+ goto out_free_acceptor_enc;
+ }
+ }
+
return 0;
out_free_acceptor_enc:
@@ -537,6 +603,8 @@ gss_delete_sec_context_kerberos(void *internal_ctx) {
crypto_free_blkcipher(kctx->enc);
crypto_free_blkcipher(kctx->acceptor_enc);
crypto_free_blkcipher(kctx->initiator_enc);
+ crypto_free_blkcipher(kctx->acceptor_enc_aux);
+ crypto_free_blkcipher(kctx->initiator_enc_aux);
kfree(kctx->mech_used.data);
kfree(kctx);
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 0c47bdd..0c65a98 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -114,7 +114,7 @@ out:
return 0;
}
-static void
+void
make_confounder(char *p, u32 conflen)
{
static u64 i = 0;
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 18/24] gss_krb5: add AES to the list of supported enctypes
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (16 preceding siblings ...)
2008-05-06 21:04 ` [enctypes round 3: PATCH 17/24] gss_krb5: add remaining pieces to enable AES encryption support Kevin Coffman
@ 2008-05-06 21:05 ` Kevin Coffman
2008-05-06 21:05 ` [enctypes round 3: PATCH 19/24] gss_krb5: add a usage parameter to the make_checksum function Kevin Coffman
` (6 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:05 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
This TEMPORARY patch notifies gssd that AES encryption is supported
by the kernel's gss_krb5 code.
This patch will go away when the final solution of adding the
enctype information to the upcall to gssd is implemented.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/rpc_pipe.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index c2d7817..d21afb4 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] 26+ messages in thread* [enctypes round 3: PATCH 19/24] gss_krb5: add a usage parameter to the make_checksum function
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (17 preceding siblings ...)
2008-05-06 21:05 ` [enctypes round 3: PATCH 18/24] gss_krb5: add AES to the list of supported enctypes Kevin Coffman
@ 2008-05-06 21:05 ` Kevin Coffman
2008-05-06 21:05 ` [enctypes round 3: PATCH 20/24] gss_krb5: add "raw" session key to context to be used for deriving keys Kevin Coffman
` (5 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:05 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
For arcfour-hmac support, the make_checksum function needs a usage
field to correctly calculate the checksum differently for MIC and
WRAP tokens.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 4 ++--
net/sunrpc/auth_gss/gss_krb5_crypto.c | 15 +++++++++++----
net/sunrpc/auth_gss/gss_krb5_seal.c | 13 +++++++++----
net/sunrpc/auth_gss/gss_krb5_unseal.c | 12 ++++++++----
net/sunrpc/auth_gss/gss_krb5_wrap.c | 4 ++--
5 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 2adf16a..ddadc3a 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -235,12 +235,12 @@ enum seal_alg {
u32
make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
struct xdr_buf *body, int body_offset, u8 *cksumkey,
- struct xdr_netobj *cksumout);
+ unsigned int usage, struct xdr_netobj *cksumout);
u32
make_checksum_v2(struct krb5_ctx *, char *header, int hdrlen,
struct xdr_buf *body, int body_offset, u8 *key,
- struct xdr_netobj *cksum);
+ unsigned int usage, 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 c50ec81..deb3530 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -133,7 +133,7 @@ checksummer(struct scatterlist *sg, void *data)
u32
make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
struct xdr_buf *body, int body_offset, u8 *cksumkey,
- struct xdr_netobj *cksumout)
+ unsigned int usage, struct xdr_netobj *cksumout)
{
struct hash_desc desc;
struct scatterlist sg[1];
@@ -209,7 +209,7 @@ out:
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)
+ unsigned int usage, struct xdr_netobj *cksumout)
{
struct hash_desc desc;
struct scatterlist sg[1];
@@ -556,15 +556,18 @@ gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
int nblocks, nbytes;
struct encryptor_desc desc;
u32 cbcbytes;
+ unsigned int usage;
if (kctx->initiate) {
cipher = kctx->initiator_enc;
aux_cipher = kctx->initiator_enc_aux;
cksumkey = kctx->initiator_integ;
+ usage = KG_USAGE_INITIATOR_SEAL;
} else {
cipher = kctx->acceptor_enc;
aux_cipher = kctx->acceptor_enc_aux;
cksumkey = kctx->acceptor_integ;
+ usage = KG_USAGE_ACCEPTOR_SEAL;
}
blocksize = crypto_blkcipher_blocksize(cipher);
@@ -609,7 +612,8 @@ gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
buf->pages = pages;
err = make_checksum_v2(kctx, NULL, 0, buf,
- offset + GSS_KRB5_TOK_HDR_LEN, cksumkey, &hmac);
+ offset + GSS_KRB5_TOK_HDR_LEN,
+ cksumkey, usage, &hmac);
buf->pages = save_pages;
if (err)
return GSS_S_FAILURE;
@@ -673,15 +677,18 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf,
u8 pkt_hmac[GSS_KRB5_MAX_CKSUM_LEN];
int nblocks, blocksize, cbcbytes;
struct decryptor_desc desc;
+ unsigned int usage;
if (kctx->initiate) {
cipher = kctx->acceptor_enc;
aux_cipher = kctx->acceptor_enc_aux;
cksum_key = kctx->acceptor_integ;
+ usage = KG_USAGE_ACCEPTOR_SEAL;
} else {
cipher = kctx->initiator_enc;
aux_cipher = kctx->initiator_enc_aux;
cksum_key = kctx->initiator_integ;
+ usage = KG_USAGE_INITIATOR_SEAL;
}
blocksize = crypto_blkcipher_blocksize(cipher);
@@ -724,7 +731,7 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf,
our_hmac_obj.data = our_hmac;
ret = make_checksum_v2(kctx, NULL, 0, &subbuf, 0,
- cksum_key, &our_hmac_obj);
+ cksum_key, usage, &our_hmac_obj);
if (ret)
goto out_err;
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 6f01d87..ee46080 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -143,7 +143,8 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
else
cksumkey = NULL;
- if (make_checksum(ctx, ptr, 8, text, 0, cksumkey, &md5cksum))
+ if (make_checksum(ctx, ptr, 8, text, 0, cksumkey,
+ KG_USAGE_SIGN, &md5cksum))
return GSS_S_FAILURE;
memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len);
@@ -171,6 +172,7 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
s32 now;
u64 seq_send;
u8 *cksumkey;
+ unsigned int cksum_usage;
dprintk("RPC: %s\n", __func__);
BUG_ON(ctx == NULL);
@@ -184,13 +186,16 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
spin_unlock(&krb5_seq_lock);
*((u64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send);
- if (ctx->initiate)
+ if (ctx->initiate) {
cksumkey = ctx->initiator_sign;
- else
+ cksum_usage = KG_USAGE_INITIATOR_SIGN;
+ } else {
cksumkey = ctx->acceptor_sign;
+ cksum_usage = KG_USAGE_ACCEPTOR_SIGN;
+ }
if (make_checksum_v2(ctx, krb5_hdr, GSS_KRB5_TOK_HDR_LEN,
- text, 0, cksumkey, &cksumobj))
+ text, 0, cksumkey, cksum_usage, &cksumobj))
return GSS_S_FAILURE;
memcpy(krb5_hdr + GSS_KRB5_TOK_HDR_LEN, cksumobj.data, cksumobj.len);
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 5305b02..5491886 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -116,7 +116,7 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
cksumkey = NULL;
if (make_checksum(ctx, ptr, 8, message_buffer, 0,
- cksumkey, &md5cksum))
+ cksumkey, KG_USAGE_SIGN, &md5cksum))
return GSS_S_FAILURE;
if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN,
@@ -155,6 +155,7 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,
u8 *cksumkey;
u8 flags;
int i;
+ unsigned int cksum_usage;
dprintk("RPC: %s\n", __func__);
@@ -175,13 +176,16 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,
if (ptr[i] != 0xff)
return GSS_S_DEFECTIVE_TOKEN;
- if (ctx->initiate)
+ if (ctx->initiate) {
cksumkey = ctx->acceptor_sign;
- else
+ cksum_usage = KG_USAGE_ACCEPTOR_SIGN;
+ } else {
cksumkey = ctx->initiator_sign;
+ cksum_usage = KG_USAGE_INITIATOR_SIGN;
+ }
if (make_checksum_v2(ctx, ptr, GSS_KRB5_TOK_HDR_LEN, message_buffer, 0,
- cksumkey, &cksumobj))
+ cksumkey, cksum_usage, &cksumobj))
return GSS_S_FAILURE;
if (memcmp(cksumobj.data, ptr + GSS_KRB5_TOK_HDR_LEN,
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 0c65a98..6453dd3 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -217,7 +217,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
tmp_pages = buf->pages;
buf->pages = pages;
if (make_checksum(kctx, ptr, 8, buf, offset + headlen - blocksize,
- cksumkey, &md5cksum))
+ cksumkey, KG_USAGE_SEAL, &md5cksum))
return GSS_S_FAILURE;
buf->pages = tmp_pages;
@@ -300,7 +300,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
cksumkey = NULL;
if (make_checksum(kctx, ptr, 8, buf, crypt_offset,
- cksumkey, &md5cksum))
+ cksumkey, KG_USAGE_SEAL, &md5cksum))
return GSS_S_FAILURE;
if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN,
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 20/24] gss_krb5: add "raw" session key to context to be used for deriving keys
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (18 preceding siblings ...)
2008-05-06 21:05 ` [enctypes round 3: PATCH 19/24] gss_krb5: add a usage parameter to the make_checksum function Kevin Coffman
@ 2008-05-06 21:05 ` Kevin Coffman
2008-05-06 21:05 ` [enctypes round 3: PATCH 21/24] gss_krb5: pass struct krb5_ctx pointer to sequence number functions Kevin Coffman
` (4 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:05 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
Save the "raw" session key in the context. This is needed for deriving
arcfour-hmac keys "on the fly" using the sequence number or checksum.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 1 +
net/sunrpc/auth_gss/gss_krb5_mech.c | 27 +++++++++++++--------------
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index ddadc3a..9753485 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -101,6 +101,7 @@ struct krb5_ctx {
struct crypto_blkcipher *initiator_enc;
struct crypto_blkcipher *acceptor_enc_aux;
struct crypto_blkcipher *initiator_enc_aux;
+ u8 Ksess[GSS_KRB5_MAX_KEYLEN]; /* session key */
u8 cksum[GSS_KRB5_MAX_KEYLEN];
s32 endtime;
u32 seq_send;
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index f626e4b..5564d6b 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -343,7 +343,7 @@ set_cdata(u8 cdata[GSS_KRB5_K5CLENGTH], u32 usage, u8 seed)
}
static int
-context_derive_keys_des3(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
+context_derive_keys_des3(struct krb5_ctx *ctx)
{
struct xdr_netobj c, keyin, keyout;
u8 cdata[GSS_KRB5_K5CLENGTH];
@@ -352,18 +352,18 @@ context_derive_keys_des3(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
c.len = GSS_KRB5_K5CLENGTH;
c.data = cdata;
- keyin.data = rawkey;
- keyin.len = keylen;
- keyout.len = keylen;
+ keyin.data = ctx->Ksess;
+ keyin.len = ctx->gk5e->keylength;
+ keyout.len = ctx->gk5e->keylength;
/* seq uses the raw key */
ctx->seq = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name,
- rawkey);
+ ctx->Ksess);
if (ctx->seq == NULL)
goto out_err;
ctx->enc = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name,
- rawkey);
+ ctx->Ksess);
if (ctx->enc == NULL)
goto out_free_seq;
@@ -388,7 +388,7 @@ out_err:
}
static int
-context_derive_keys_new(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
+context_derive_keys_new(struct krb5_ctx *ctx)
{
struct xdr_netobj c, keyin, keyout;
u8 cdata[GSS_KRB5_K5CLENGTH];
@@ -397,9 +397,9 @@ context_derive_keys_new(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
c.len = GSS_KRB5_K5CLENGTH;
c.data = cdata;
- keyin.data = rawkey;
- keyin.len = keylen;
- keyout.len = keylen;
+ keyin.data = ctx->Ksess;
+ keyin.len = ctx->gk5e->keylength;
+ keyout.len = ctx->gk5e->keylength;
/* initiator seal encryption */
set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_ENCRYPTION);
@@ -501,7 +501,6 @@ out_err:
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));
@@ -537,7 +536,7 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx)
}
keylen = ctx->gk5e->keylength;
- p = simple_get_bytes(p, end, rawkey, keylen);
+ p = simple_get_bytes(p, end, ctx->Ksess, keylen);
if (IS_ERR(p))
goto out_err;
@@ -556,10 +555,10 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx)
switch (ctx->enctype) {
case ENCTYPE_DES3_CBC_RAW:
- return context_derive_keys_des3(ctx, rawkey, keylen);
+ return context_derive_keys_des3(ctx);
case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
- return context_derive_keys_new(ctx, rawkey, keylen);
+ return context_derive_keys_new(ctx);
default:
return -EINVAL;
}
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 21/24] gss_krb5: pass struct krb5_ctx pointer to sequence number functions
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (19 preceding siblings ...)
2008-05-06 21:05 ` [enctypes round 3: PATCH 20/24] gss_krb5: add "raw" session key to context to be used for deriving keys Kevin Coffman
@ 2008-05-06 21:05 ` Kevin Coffman
2008-05-06 21:05 ` [enctypes round 3: PATCH 22/24] gss_krb5: add confounder length to kerberos enctype framework Kevin Coffman
` (3 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:05 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
For the arcfour-hmac support, the make_seq_num and get_seq_num functions
need access to the kerberos context structure. This will be used in a
later patch.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 6 ++++--
net/sunrpc/auth_gss/gss_krb5_seal.c | 5 ++---
net/sunrpc/auth_gss/gss_krb5_seqnum.c | 6 ++++--
net/sunrpc/auth_gss/gss_krb5_unseal.c | 3 ++-
net/sunrpc/auth_gss/gss_krb5_wrap.c | 6 +++---
5 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index 9753485..de87e20 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -275,12 +275,14 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *inbuf,
int offset);
s32
-krb5_make_seq_num(struct crypto_blkcipher *key,
+krb5_make_seq_num(struct krb5_ctx *kctx,
+ struct crypto_blkcipher *key,
int direction,
u32 seqnum, unsigned char *cksum, unsigned char *buf);
s32
-krb5_get_seq_num(struct crypto_blkcipher *key,
+krb5_get_seq_num(struct krb5_ctx *kctx,
+ struct crypto_blkcipher *key,
unsigned char *cksum,
unsigned char *buf, int *direction, u32 *seqnum);
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index ee46080..0048ed7 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -153,9 +153,8 @@ gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text,
seq_send = ctx->seq_send++;
spin_unlock(&krb5_seq_lock);
- if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
- seq_send, ptr + GSS_KRB5_TOK_HDR_LEN,
- ptr + 8))
+ if (krb5_make_seq_num(ctx, ctx->seq, ctx->initiate ? 0 : 0xff,
+ seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8))
return GSS_S_FAILURE;
return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
index f160be6..c7b196d 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
@@ -41,7 +41,8 @@
#endif
s32
-krb5_make_seq_num(struct crypto_blkcipher *key,
+krb5_make_seq_num(struct krb5_ctx *kctx,
+ struct crypto_blkcipher *key,
int direction,
u32 seqnum,
unsigned char *cksum, unsigned char *buf)
@@ -62,7 +63,8 @@ krb5_make_seq_num(struct crypto_blkcipher *key,
}
s32
-krb5_get_seq_num(struct crypto_blkcipher *key,
+krb5_get_seq_num(struct krb5_ctx *kctx,
+ struct crypto_blkcipher *key,
unsigned char *cksum,
unsigned char *buf,
int *direction, u32 *seqnum)
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 5491886..760d628 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -132,7 +132,8 @@ gss_verify_mic_v1(struct krb5_ctx *ctx,
/* do sequencing checks */
- if (krb5_get_seq_num(ctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8, &direction, &seqnum))
+ if (krb5_get_seq_num(ctx, ctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8,
+ &direction, &seqnum))
return GSS_S_FAILURE;
if ((ctx->initiate && direction != 0xff) ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 6453dd3..2a0d72f 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -229,7 +229,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
/* XXX would probably be more efficient to compute checksum
* and encrypt at the same time: */
- if ((krb5_make_seq_num(kctx->seq, kctx->initiate ? 0 : 0xff,
+ if ((krb5_make_seq_num(kctx, kctx->seq, kctx->initiate ? 0 : 0xff,
seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8)))
return GSS_S_FAILURE;
@@ -316,8 +316,8 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
/* do sequencing checks */
- if (krb5_get_seq_num(kctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8,
- &direction, &seqnum))
+ if (krb5_get_seq_num(kctx, kctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN,
+ ptr + 8, &direction, &seqnum))
return GSS_S_BAD_SIG;
if ((kctx->initiate && direction != 0xff) ||
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 22/24] gss_krb5: add confounder length to kerberos enctype framework
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (20 preceding siblings ...)
2008-05-06 21:05 ` [enctypes round 3: PATCH 21/24] gss_krb5: pass struct krb5_ctx pointer to sequence number functions Kevin Coffman
@ 2008-05-06 21:05 ` Kevin Coffman
2008-05-06 21:05 ` [enctypes round 3: PATCH 23/24] gss_krb5: Add support for rc4-hmac encryption type described in rfc4757 Kevin Coffman
` (2 subsequent siblings)
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:05 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
All encryption types use a confounder at the beginning of the
wrap token. In all encryption types except arcfour-hmac, the
confounder is the same as the blocksize. arcfour-hmac has a
blocksize of one, but uses an eight byte confounder.
Add an entry to the crypto framework definitions for the
confounder length and change the wrap/unwrap code to use
the confounder length rather than assuming it is always
the blocksize.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
include/linux/sunrpc/gss_krb5.h | 3 +++
net/sunrpc/auth_gss/gss_krb5_crypto.c | 6 +++---
net/sunrpc/auth_gss/gss_krb5_mech.c | 4 ++++
net/sunrpc/auth_gss/gss_krb5_wrap.c | 12 +++++++-----
4 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index de87e20..d9f3834 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -64,6 +64,9 @@ struct gss_krb5_enctype {
const u16 signalg; /* signing algorithm */
const u16 sealalg; /* sealing algorithm */
const u32 blocksize; /* encryption blocksize */
+ const u32 conflen; /* confounder length
+ (normally the same as
+ the blocksize) */
const u32 cksumlength; /* checksum length */
const u32 keyed_cksum; /* is it a keyed cksum? */
const u32 keybytes; /* raw key len, in bytes */
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index deb3530..6482185 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -573,9 +573,9 @@ gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
/* hide the gss token header and insert the confounder */
offset += GSS_KRB5_TOK_HDR_LEN;
- if (shift_head_data(buf, offset, blocksize))
+ if (shift_head_data(buf, offset, kctx->gk5e->conflen))
return GSS_S_FAILURE;
- make_confounder(buf->head[0].iov_base + offset, blocksize);
+ make_confounder(buf->head[0].iov_base + offset, kctx->gk5e->conflen);
offset -= GSS_KRB5_TOK_HDR_LEN;
if (buf->tail[0].iov_base != NULL) {
@@ -745,7 +745,7 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf,
ret = GSS_S_BAD_SIG;
goto out_err;
}
- *headskip = crypto_blkcipher_blocksize(cipher);
+ *headskip = kctx->gk5e->conflen;
*tailskip = kctx->gk5e->cksumlength;
out_err:
if (ret && ret != GSS_S_BAD_SIG)
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 5564d6b..a7a91b0 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -68,6 +68,7 @@ static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
.keybytes = 7,
.keylength = 8,
.blocksize = 8,
+ .conflen = 8,
.cksumlength = 8,
.keyed_cksum = 0,
},
@@ -88,6 +89,7 @@ static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
.keybytes = 21,
.keylength = 24,
.blocksize = 8,
+ .conflen = 8,
.cksumlength = 20,
.keyed_cksum = 1,
},
@@ -110,6 +112,7 @@ static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
.keybytes = 16,
.keylength = 16,
.blocksize = 16,
+ .conflen = 16,
.cksumlength = 12,
.keyed_cksum = 1,
},
@@ -132,6 +135,7 @@ static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
.keybytes = 32,
.keylength = 32,
.blocksize = 16,
+ .conflen = 16,
.cksumlength = 12,
.keyed_cksum = 1,
},
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 2a0d72f..8269f37 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -169,6 +169,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
struct page **tmp_pages;
u32 seq_send;
u8 *cksumkey;
+ u32 conflen = kctx->gk5e->conflen;
dprintk("RPC: %s\n", __func__);
@@ -178,7 +179,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
blocksize = crypto_blkcipher_blocksize(kctx->enc);
gss_krb5_add_padding(buf, offset, blocksize);
BUG_ON((buf->len - offset) % blocksize);
- plainlen = blocksize + buf->len - offset;
+ plainlen = conflen + buf->len - offset;
headlen = g_token_size(&kctx->mech_used,
GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength + plainlen) -
@@ -206,7 +207,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
memset(ptr + 4, 0xff, 4);
*(__be16 *)(ptr + 4) = cpu_to_le16(kctx->gk5e->sealalg);
- make_confounder(msg_start, blocksize);
+ make_confounder(msg_start, conflen);
if (kctx->gk5e->keyed_cksum)
cksumkey = kctx->cksum;
@@ -216,7 +217,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
/* XXXJBF: UGH!: */
tmp_pages = buf->pages;
buf->pages = pages;
- if (make_checksum(kctx, ptr, 8, buf, offset + headlen - blocksize,
+ if (make_checksum(kctx, ptr, 8, buf, offset + headlen - conflen,
cksumkey, KG_USAGE_SEAL, &md5cksum))
return GSS_S_FAILURE;
buf->pages = tmp_pages;
@@ -233,7 +234,7 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8)))
return GSS_S_FAILURE;
- if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - blocksize,
+ if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - conflen,
pages))
return GSS_S_FAILURE;
@@ -256,6 +257,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;
+ u32 conflen = kctx->gk5e->conflen;
int crypt_offset;
u8 *cksumkey;
@@ -329,7 +331,7 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
blocksize = crypto_blkcipher_blocksize(kctx->enc);
data_start = ptr + (GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength) +
- blocksize;
+ conflen;
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] 26+ messages in thread* [enctypes round 3: PATCH 23/24] gss_krb5: Add support for rc4-hmac encryption type described in rfc4757
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (21 preceding siblings ...)
2008-05-06 21:05 ` [enctypes round 3: PATCH 22/24] gss_krb5: add confounder length to kerberos enctype framework Kevin Coffman
@ 2008-05-06 21:05 ` Kevin Coffman
2008-05-06 21:05 ` [enctypes round 3: PATCH 24/24] gss_krb5: add RC4 to the list of supported enctypes Kevin Coffman
2008-05-07 14:41 ` [enctypes round 3: PATCH 00/24] Add new enctypes for gss_krb5 J. Bruce Fields
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:05 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
Add necessary changes to add kernel support for the rc4-hmac Kerberos
encryption type used by Microsoft and described in rfc4757.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
fs/Kconfig | 2
include/linux/sunrpc/gss_krb5.h | 9 +
net/sunrpc/auth_gss/gss_krb5_crypto.c | 255 +++++++++++++++++++++++++++++++++
net/sunrpc/auth_gss/gss_krb5_mech.c | 96 ++++++++++++
net/sunrpc/auth_gss/gss_krb5_seal.c | 1
net/sunrpc/auth_gss/gss_krb5_seqnum.c | 77 ++++++++++
net/sunrpc/auth_gss/gss_krb5_unseal.c | 1
net/sunrpc/auth_gss/gss_krb5_wrap.c | 66 +++++++--
8 files changed, 494 insertions(+), 13 deletions(-)
diff --git a/fs/Kconfig b/fs/Kconfig
index 08be92c..3220459 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1833,6 +1833,8 @@ config RPCSEC_GSS_KRB5
select CRYPTO_SHA1
select CRYPTO_AES
select CRYPTO_CTS
+ select CRYPTO_ECB
+ select CRYPTO_ARC4
help
Choose Y here to enable Secure RPC using the Kerberos version 5
GSS-API mechanism (RFC 1964).
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h
index d9f3834..1b18c8a 100644
--- a/include/linux/sunrpc/gss_krb5.h
+++ b/include/linux/sunrpc/gss_krb5.h
@@ -318,5 +318,14 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset,
struct xdr_buf *buf, u32 *plainoffset,
u32 *plainlen);
+int
+krb5_rc4_setup_seq_key(struct krb5_ctx *kctx,
+ struct crypto_blkcipher *cipher,
+ unsigned char *cksum);
+
+int
+krb5_rc4_setup_enc_key(struct krb5_ctx *kctx,
+ struct crypto_blkcipher *cipher,
+ s32 seqnum);
void
make_confounder(char *p, u32 conflen);
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 6482185..de99a5d 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -125,6 +125,114 @@ checksummer(struct scatterlist *sg, void *data)
return crypto_hash_update(desc, sg, sg->length);
}
+static int
+arcfour_hmac_md5_usage_to_salt(unsigned int usage, u8 salt[4])
+{
+ unsigned int ms_usage;
+
+ switch (usage) {
+ case KG_USAGE_SIGN:
+ ms_usage = 15;
+ break;
+ case KG_USAGE_SEAL:
+ ms_usage = 13;
+ break;
+ default:
+ return EINVAL;;
+ }
+ salt[0] = (ms_usage >> 0) & 0xff;
+ salt[1] = (ms_usage >> 8) & 0xff;
+ salt[2] = (ms_usage >> 16) & 0xff;
+ salt[3] = (ms_usage >> 24) & 0xff;
+
+ return 0;
+}
+
+static u32
+make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen,
+ struct xdr_buf *body, int body_offset, u8 *cksumkey,
+ unsigned int usage, struct xdr_netobj *cksumout)
+{
+ struct hash_desc desc;
+ struct scatterlist sg[1];
+ int err;
+ u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
+ u8 rc4salt[4];
+ struct crypto_hash *md5;
+ struct crypto_hash *hmac_md5;
+
+ if (cksumkey == NULL)
+ return GSS_S_FAILURE;
+
+ 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;
+ }
+
+ if (arcfour_hmac_md5_usage_to_salt(usage, rc4salt)) {
+ dprintk("%s: invalid usage value %u\n", __func__, usage);
+ return GSS_S_FAILURE;
+ }
+
+ md5 = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(md5))
+ return GSS_S_FAILURE;
+
+ hmac_md5 = crypto_alloc_hash(kctx->gk5e->cksum_name, 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(hmac_md5)) {
+ crypto_free_hash(md5);
+ return GSS_S_FAILURE;
+ }
+
+ desc.tfm = md5;
+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ err = crypto_hash_init(&desc);
+ if (err)
+ goto out;
+ sg_init_one(sg, rc4salt, 4);
+ err = crypto_hash_update(&desc, sg, 4);
+ if (err)
+ goto out;
+
+ sg_init_one(sg, header, hdrlen);
+ err = crypto_hash_update(&desc, sg, hdrlen);
+ 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, checksumdata);
+ if (err)
+ goto out;
+
+ desc.tfm = hmac_md5;
+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ err = crypto_hash_init(&desc);
+ if (err)
+ goto out;
+ err = crypto_hash_setkey(hmac_md5, cksumkey, kctx->gk5e->keylength);
+ if (err)
+ goto out;
+
+ sg_init_one(sg, checksumdata, crypto_hash_digestsize(md5));
+ err = crypto_hash_digest(&desc, sg, crypto_hash_digestsize(md5),
+ checksumdata);
+ if (err)
+ goto out;
+
+ memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength);
+ cksumout->len = kctx->gk5e->cksumlength;
+out:
+ crypto_free_hash(md5);
+ crypto_free_hash(hmac_md5);
+ return err ? GSS_S_FAILURE : 0;
+}
+
/*
* checksum the plaintext data and hdrlen bytes of the token header
* The checksum is performed over the first 8 bytes of the
@@ -141,6 +249,11 @@ make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN];
unsigned int checksumlen;
+ if (kctx->gk5e->ctype == CKSUMTYPE_HMAC_MD5_ARCFOUR)
+ return make_checksum_hmac_md5(kctx, header, hdrlen,
+ body, body_offset,
+ cksumkey, usage, cksumout);
+
if (cksumout->len < kctx->gk5e->cksumlength) {
dprintk("%s: checksum buffer length, %u, too small for %s\n",
__func__, cksumout->len, kctx->gk5e->name);
@@ -752,3 +865,145 @@ out_err:
ret = GSS_S_FAILURE;
return ret;
}
+
+/*
+ * Compute Kseq given the initial session key and the checksum.
+ * Set the key of the given cipher.
+ */
+int
+krb5_rc4_setup_seq_key(struct krb5_ctx *kctx, struct crypto_blkcipher *cipher,
+ unsigned char *cksum)
+{
+ struct crypto_hash *hmac;
+ struct hash_desc desc;
+ struct scatterlist sg[1];
+ u8 Kseq[GSS_KRB5_MAX_KEYLEN];
+ u32 zeroconstant = 0;
+ int err;
+
+ dprintk("%s: entered\n", __func__);
+
+ hmac = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(hmac)) {
+ dprintk("%s: error %ld, allocating hash '%s'\n",
+ __func__, PTR_ERR(hmac), kctx->gk5e->cksum_name);
+ return PTR_ERR(hmac);
+ }
+
+ desc.tfm = hmac;
+ desc.flags = 0;
+
+ err = crypto_hash_init(&desc);
+ if (err)
+ goto out_err;
+
+ /* Compute intermediate Kseq from session key */
+ err = crypto_hash_setkey(hmac, kctx->Ksess, kctx->gk5e->keylength);
+ if (err)
+ goto out_err;
+
+ sg_init_table(sg, 1);
+ sg_set_buf(sg, &zeroconstant, 4);
+
+ err = crypto_hash_digest(&desc, sg, 4, Kseq);
+ if (err)
+ goto out_err;
+
+ /* Compute final Kseq from the checksum and intermediate Kseq */
+ err = crypto_hash_setkey(hmac, Kseq, kctx->gk5e->keylength);
+ if (err)
+ goto out_err;
+
+ sg_set_buf(sg, cksum, 8);
+
+ err = crypto_hash_digest(&desc, sg, 8, Kseq);
+ if (err)
+ goto out_err;
+
+ err = crypto_blkcipher_setkey(cipher, Kseq, kctx->gk5e->keylength);
+ if (err)
+ goto out_err;
+
+ err = 0;
+
+out_err:
+ crypto_free_hash(hmac);
+ dprintk("%s: returning %d\n", __func__, err);
+ return err;
+}
+
+/*
+ * Compute Kcrypt given the initial session key and the plaintext seqnum.
+ * Set the key of cipher kctx->enc.
+ */
+int
+krb5_rc4_setup_enc_key(struct krb5_ctx *kctx, struct crypto_blkcipher *cipher,
+ s32 seqnum)
+{
+ struct crypto_hash *hmac;
+ struct hash_desc desc;
+ struct scatterlist sg[1];
+ u8 Kcrypt[GSS_KRB5_MAX_KEYLEN];
+ u8 zeroconstant[4] = {0};
+ u8 seqnumarray[4];
+ int err, i;
+
+ dprintk("%s: entered, seqnum %u\n", __func__, seqnum);
+
+ hmac = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(hmac)) {
+ dprintk("%s: error %ld, allocating hash '%s'\n",
+ __func__, PTR_ERR(hmac), kctx->gk5e->cksum_name);
+ return PTR_ERR(hmac);
+ }
+
+ desc.tfm = hmac;
+ desc.flags = 0;
+
+ err = crypto_hash_init(&desc);
+ if (err)
+ goto out_err;
+
+ /* Compute intermediate Kcrypt from session key */
+ for (i = 0; i < kctx->gk5e->keylength; i++)
+ Kcrypt[i] = kctx->Ksess[i] ^ 0xf0;
+
+ err = crypto_hash_setkey(hmac, Kcrypt, kctx->gk5e->keylength);
+ if (err)
+ goto out_err;
+
+ sg_init_table(sg, 1);
+ sg_set_buf(sg, zeroconstant, 4);
+
+ err = crypto_hash_digest(&desc, sg, 4, Kcrypt);
+ if (err)
+ goto out_err;
+
+ /* Compute final Kcrypt from the seqnum and intermediate Kcrypt */
+ err = crypto_hash_setkey(hmac, Kcrypt, kctx->gk5e->keylength);
+ if (err)
+ goto out_err;
+
+ seqnumarray[0] = (unsigned char) ((seqnum >> 24) & 0xff);
+ seqnumarray[1] = (unsigned char) ((seqnum >> 16) & 0xff);
+ seqnumarray[2] = (unsigned char) ((seqnum >> 8) & 0xff);
+ seqnumarray[3] = (unsigned char) ((seqnum >> 0) & 0xff);
+
+ sg_set_buf(sg, seqnumarray, 4);
+
+ err = crypto_hash_digest(&desc, sg, 4, Kcrypt);
+ if (err)
+ goto out_err;
+
+ err = crypto_blkcipher_setkey(cipher, Kcrypt, kctx->gk5e->keylength);
+ if (err)
+ goto out_err;
+
+ err = 0;
+
+out_err:
+ crypto_free_hash(hmac);
+ dprintk("%s: returning %d\n", __func__, err);
+ return err;
+}
+
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index a7a91b0..4278061 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -73,6 +73,27 @@ static struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
.keyed_cksum = 0,
},
/*
+ * RC4-HMAC
+ */
+ {
+ .etype = ENCTYPE_ARCFOUR_HMAC,
+ .ctype = CKSUMTYPE_HMAC_MD5_ARCFOUR,
+ .name = "rc4-hmac",
+ .encrypt_name = "ecb(arc4)",
+ .cksum_name = "hmac(md5)",
+ .encrypt = krb5_encrypt,
+ .decrypt = krb5_decrypt,
+ .mk_key = NULL,
+ .signalg = SGN_ALG_HMAC_MD5,
+ .sealalg = SEAL_ALG_MICROSOFT_RC4,
+ .keybytes = 16,
+ .keylength = 16,
+ .blocksize = 1,
+ .conflen = 8,
+ .cksumlength = 8,
+ .keyed_cksum = 1,
+ },
+ /*
* 3DES
*/
{
@@ -391,6 +412,79 @@ out_err:
return -EINVAL;
}
+/*
+ * Note that RC4 depends on deriving keys using the sequence
+ * number or the checksum of a token. Therefore, the final keys
+ * cannot be calculated until the token is being constructed!
+ */
+static int
+context_derive_keys_rc4(struct krb5_ctx *ctx)
+{
+ struct crypto_hash *hmac;
+ char sigkeyconstant[] = "signaturekey";
+ int slen = strlen(sigkeyconstant) + 1; /* include null terminator */
+ struct hash_desc desc;
+ struct scatterlist sg[1];
+ int err;
+
+ dprintk("RPC: %s: entered\n", __func__);
+ /*
+ * derive cksum (aka Ksign) key
+ */
+ hmac = crypto_alloc_hash(ctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(hmac)) {
+ dprintk("%s: error %ld allocating hash '%s'\n",
+ __func__, PTR_ERR(hmac), ctx->gk5e->cksum_name);
+ err = PTR_ERR(hmac);
+ goto out_err;
+ }
+
+ err = crypto_hash_setkey(hmac, ctx->Ksess, ctx->gk5e->keylength);
+ if (err)
+ goto out_err_free_hmac;
+
+ sg_init_table(sg, 1);
+ sg_set_buf(sg, sigkeyconstant, slen);
+
+ desc.tfm = hmac;
+ desc.flags = 0;
+
+ err = crypto_hash_init(&desc);
+ if (err)
+ goto out_err_free_hmac;
+
+ err = crypto_hash_digest(&desc, sg, slen, ctx->cksum);
+ if (err)
+ goto out_err_free_hmac;
+ /*
+ * allocate hash, and blkciphers for data and seqnum encryption
+ */
+ ctx->enc = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(ctx->enc)) {
+ err = PTR_ERR(ctx->enc);
+ goto out_err_free_hmac;
+ }
+
+ ctx->seq = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(ctx->seq)) {
+ crypto_free_blkcipher(ctx->enc);
+ err = PTR_ERR(ctx->seq);
+ goto out_err_free_hmac;
+ }
+
+ dprintk("RPC: %s: returning success\n", __func__);
+
+ err = 0;
+
+out_err_free_hmac:
+ crypto_free_hash(hmac);
+out_err:
+ dprintk("RPC: %s: returning %d\n", __func__, err);
+ return err;
+}
+
static int
context_derive_keys_new(struct krb5_ctx *ctx)
{
@@ -560,6 +654,8 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx)
switch (ctx->enctype) {
case ENCTYPE_DES3_CBC_RAW:
return context_derive_keys_des3(ctx);
+ case ENCTYPE_ARCFOUR_HMAC:
+ return context_derive_keys_rc4(ctx);
case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
return context_derive_keys_new(ctx);
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 0048ed7..c1a1e45 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -215,6 +215,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
BUG();
case ENCTYPE_DES_CBC_RAW:
case ENCTYPE_DES3_CBC_RAW:
+ case ENCTYPE_ARCFOUR_HMAC:
return gss_get_mic_v1(ctx, text, token);
case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
index c7b196d..476a373 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
@@ -40,6 +40,38 @@
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
+static s32
+krb5_make_rc4_seq_num(struct krb5_ctx *kctx, int direction, s32 seqnum,
+ unsigned char *cksum, unsigned char *buf)
+{
+ struct crypto_blkcipher *cipher;
+ unsigned char plain[8];
+ s32 code;
+
+ dprintk("RPC: %s:\n", __func__);
+ cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
+
+ plain[0] = (unsigned char) ((seqnum >> 24) & 0xff);
+ plain[1] = (unsigned char) ((seqnum >> 16) & 0xff);
+ plain[2] = (unsigned char) ((seqnum >> 8) & 0xff);
+ plain[3] = (unsigned char) ((seqnum >> 0) & 0xff);
+ plain[4] = direction;
+ plain[5] = direction;
+ plain[6] = direction;
+ plain[7] = direction;
+
+ code = krb5_rc4_setup_seq_key(kctx, cipher, cksum);
+ if (code)
+ goto out;
+
+ code = krb5_encrypt(cipher, cksum, plain, buf, 8);
+out:
+ crypto_free_blkcipher(cipher);
+ return code;
+}
s32
krb5_make_seq_num(struct krb5_ctx *kctx,
struct crypto_blkcipher *key,
@@ -49,6 +81,10 @@ krb5_make_seq_num(struct krb5_ctx *kctx,
{
unsigned char plain[8];
+ if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC)
+ return krb5_make_rc4_seq_num(kctx, direction, seqnum,
+ cksum, buf);
+
plain[0] = (unsigned char) (seqnum & 0xff);
plain[1] = (unsigned char) ((seqnum >> 8) & 0xff);
plain[2] = (unsigned char) ((seqnum >> 16) & 0xff);
@@ -62,6 +98,43 @@ krb5_make_seq_num(struct krb5_ctx *kctx,
return krb5_encrypt(key, cksum, plain, buf, 8);
}
+static s32
+krb5_get_rc4_seq_num(struct krb5_ctx *kctx, unsigned char *cksum,
+ unsigned char *buf, int *direction, s32 *seqnum)
+{
+ struct crypto_blkcipher *cipher;
+ unsigned char plain[8];
+ s32 code;
+
+ dprintk("RPC: %s:\n", __func__);
+ cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
+
+ code = krb5_rc4_setup_seq_key(kctx, cipher, cksum);
+ if (code)
+ goto out;
+
+ code = krb5_decrypt(cipher, cksum, buf, plain, 8);
+ if (code)
+ goto out;
+
+ if ((plain[4] != plain[5]) || (plain[4] != plain[6])
+ || (plain[4] != plain[7])) {
+ code = (s32)KG_BAD_SEQ;
+ goto out;
+ }
+
+ *direction = plain[4];
+
+ *seqnum = ((plain[0] << 24) | (plain[1] << 16) |
+ (plain[2] << 8) | (plain[3]));
+out:
+ crypto_free_blkcipher(cipher);
+ return code;
+}
+
s32
krb5_get_seq_num(struct krb5_ctx *kctx,
struct crypto_blkcipher *key,
@@ -74,6 +147,10 @@ krb5_get_seq_num(struct krb5_ctx *kctx,
dprintk("RPC: krb5_get_seq_num:\n");
+ if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC)
+ return krb5_get_rc4_seq_num(kctx, cksum, buf,
+ direction, seqnum);
+
if ((code = krb5_decrypt(key, cksum, buf, plain, 8)))
return code;
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 760d628..0307911 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -217,6 +217,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
BUG();
case ENCTYPE_DES_CBC_RAW:
case ENCTYPE_DES3_CBC_RAW:
+ case ENCTYPE_ARCFOUR_HMAC:
return gss_verify_mic_v1(ctx, message_buffer, read_token);
case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 8269f37..5a70d02 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -234,9 +234,26 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8)))
return GSS_S_FAILURE;
- if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - conflen,
- pages))
- return GSS_S_FAILURE;
+ if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) {
+ struct crypto_blkcipher *cipher;
+ int err;
+ cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(cipher))
+ return GSS_S_FAILURE;
+
+ krb5_rc4_setup_enc_key(kctx, cipher, seq_send);
+
+ err = gss_encrypt_xdr_buf(cipher, buf,
+ offset + headlen - conflen, pages);
+ crypto_free_blkcipher(cipher);
+ if (err)
+ return GSS_S_FAILURE;
+ } else {
+ if (gss_encrypt_xdr_buf(kctx->enc, buf,
+ offset + headlen - conflen, pages))
+ return GSS_S_FAILURE;
+ }
return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
}
@@ -293,8 +310,37 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
*/
crypt_offset = ptr + (GSS_KRB5_TOK_HDR_LEN + 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;
+
+ /*
+ * Need plaintext seqnum to derive encryption key for arcfour-hmac
+ */
+ if (krb5_get_seq_num(kctx, kctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN,
+ ptr + 8, &direction, &seqnum))
+ return GSS_S_BAD_SIG;
+
+ if ((kctx->initiate && direction != 0xff) ||
+ (!kctx->initiate && direction != 0))
+ return GSS_S_BAD_SIG;
+
+ if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) {
+ struct crypto_blkcipher *cipher;
+ int err;
+
+ cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(cipher))
+ return GSS_S_FAILURE;
+
+ krb5_rc4_setup_enc_key(kctx, cipher, seqnum);
+
+ err = gss_decrypt_xdr_buf(cipher, buf, crypt_offset);
+ crypto_free_blkcipher(cipher);
+ if (err)
+ return GSS_S_DEFECTIVE_TOKEN;
+ } else {
+ if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset))
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
if (kctx->gk5e->keyed_cksum)
cksumkey = kctx->cksum;
@@ -318,14 +364,6 @@ gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
/* do sequencing checks */
- if (krb5_get_seq_num(kctx, kctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN,
- ptr + 8, &direction, &seqnum))
- return GSS_S_BAD_SIG;
-
- if ((kctx->initiate && direction != 0xff) ||
- (!kctx->initiate && direction != 0))
- return GSS_S_BAD_SIG;
-
/* Copy the data back to the right position. XXX: Would probably be
* better to copy and encrypt at the same time. */
@@ -596,6 +634,7 @@ gss_wrap_kerberos(struct gss_ctx *gctx, int offset,
BUG();
case ENCTYPE_DES_CBC_RAW:
case ENCTYPE_DES3_CBC_RAW:
+ case ENCTYPE_ARCFOUR_HMAC:
return gss_wrap_kerberos_v1(kctx, offset, buf, pages);
case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
@@ -613,6 +652,7 @@ gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf)
BUG();
case ENCTYPE_DES_CBC_RAW:
case ENCTYPE_DES3_CBC_RAW:
+ case ENCTYPE_ARCFOUR_HMAC:
return gss_unwrap_kerberos_v1(kctx, offset, buf);
case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
^ permalink raw reply related [flat|nested] 26+ messages in thread* [enctypes round 3: PATCH 24/24] gss_krb5: add RC4 to the list of supported enctypes
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (22 preceding siblings ...)
2008-05-06 21:05 ` [enctypes round 3: PATCH 23/24] gss_krb5: Add support for rc4-hmac encryption type described in rfc4757 Kevin Coffman
@ 2008-05-06 21:05 ` Kevin Coffman
2008-05-07 14:41 ` [enctypes round 3: PATCH 00/24] Add new enctypes for gss_krb5 J. Bruce Fields
24 siblings, 0 replies; 26+ messages in thread
From: Kevin Coffman @ 2008-05-06 21:05 UTC (permalink / raw)
To: bfields; +Cc: linux-nfs
This TEMPORARY patch notifies gssd that RC4 encryption is supported
by the kernel's gss_krb5 code.
This patch will go away when the final solution of adding the
enctype information to the upcall to gssd is implemented.
Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
---
net/sunrpc/rpc_pipe.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index d21afb4..b1d8ed6 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: 18,17,16,3,1,2\n");
+ seq_printf(m, "enctypes: 18,17,16,23,3,1,2\n");
return 0;
}
^ permalink raw reply related [flat|nested] 26+ messages in thread* Re: [enctypes round 3: PATCH 00/24] Add new enctypes for gss_krb5
[not found] ` <20080506210156.3770.95914.stgit-zTNJhAanYLVZN1qrTdtDg5Vzexx5G7lz@public.gmane.org>
` (23 preceding siblings ...)
2008-05-06 21:05 ` [enctypes round 3: PATCH 24/24] gss_krb5: add RC4 to the list of supported enctypes Kevin Coffman
@ 2008-05-07 14:41 ` J. Bruce Fields
24 siblings, 0 replies; 26+ messages in thread
From: J. Bruce Fields @ 2008-05-07 14:41 UTC (permalink / raw)
To: Kevin Coffman; +Cc: linux-nfs
On Tue, May 06, 2008 at 05:03:28PM -0400, Kevin Coffman wrote:
> This is round 3.
>
> This set of patches adds kernel support for triple-DES (des3-cbc-sha1),
> arcfour (rc4-hmac), and AES (aes128-cts, aes256-cts) encryption to the
> kernel's Kerberos rpcsec_gss code.
>
> These are currently based on Trond's tree as of 05/06/08.
>
> This still includes the first couple of patches you've already applied
> (I couldn't find them in your public git, so I assume I'm missing
> something, or they are applied to your local development git, or
> I'm still missing something...)
No, that was my fault, sorry--I applied them, then didn't push them out
immediately. They should be there now.
I may not take a look at the rest of these till after connectathon (but
I'll try if I get a chance).
--b.
> This round removes the two patches that use global OIDs. Instead,
> krb5 contexts created from the new v2 context format from gssd copy
> the OID from the gss_kerberos_mech structure.
>
> Two issues remain:
>
> 1) The patch to add krb5_info will eventually be replaced with an
> updated upcall which will include the supported enctype information.
> I have split out these portions of the patches to (hopefully) make
> that transition easier.
>
> 2) There is currently no code to handle the possiblity of rotated
> data in the version two tokens. I don't expect we'll see rotated
> data in normal operation, but this should be done eventually for
> completeness.
>
> There are two nfs-utils patches required with this. The first reads
> and parses the list of kernel supported enctypes. The second
> implements the new context format from user-land to kernel.
> These are included in the recent nfs-utils-1.1.2-CITI_NFS4_ALL-1 patches.
>
>
> ------------------
>
> Note: for AES support, the following patch for MIT Kerberos is needed
> to get the right key when there is an acceptor_subkey. [mea culpa]
>
> This fix is scheduled to be included in MIT release 1.6.4, currently
> in beta testing.
>
> This patch should also apply to releases 1.4.0 to 1.6.3.
>
> Index: src/lib/gssapi/krb5/lucid_context.c
> ===================================================================
> --- src/lib/gssapi/krb5/lucid_context.c (revision 20174)
> +++ src/lib/gssapi/krb5/lucid_context.c (revision 20175)
> @@ -231,7 +231,7 @@
> &lctx->cfx_kd.ctx_key)))
> goto error_out;
> if (gctx->have_acceptor_subkey) {
> - if ((retval = copy_keyblock_to_lucid_key(gctx->enc,
> + if ((retval = copy_keyblock_to_lucid_key(gctx->acceptor_subkey,
> &lctx->cfx_kd.acceptor_subkey)))
> goto error_out;
> lctx->cfx_kd.have_acceptor_subkey = 1;
^ permalink raw reply [flat|nested] 26+ messages in thread