From: Trond Myklebust <trond.myklebust@fys.uio.no>

RPCSEC_GSS: Miscellaneous cleanups of the krb5 code required for the
integrity checksumming.


---

 include/linux/sunrpc/gss_krb5.h       |   20 +----
 net/sunrpc/auth_gss/gss_krb5_crypto.c |   44 +++++------
 net/sunrpc/auth_gss/gss_krb5_mech.c   |   28 +++----
 net/sunrpc/auth_gss/gss_krb5_seal.c   |   43 ++--------
 net/sunrpc/auth_gss/gss_krb5_unseal.c |  134 ++++++++--------------------------
 5 files changed, 84 insertions(+), 185 deletions(-)

diff -puN include/linux/sunrpc/gss_krb5.h~nfs-11-krb5_cleanup include/linux/sunrpc/gss_krb5.h
--- 25/include/linux/sunrpc/gss_krb5.h~nfs-11-krb5_cleanup	2004-01-09 22:16:14.000000000 -0800
+++ 25-akpm/include/linux/sunrpc/gss_krb5.h	2004-01-09 22:16:14.000000000 -0800
@@ -50,7 +50,6 @@ struct krb5_ctx {
 	struct crypto_tfm	*seq;
 	s32			endtime;
 	u32			seq_send;
-	u32			seq_recv;
 	struct xdr_netobj	mech_used;
 };
 
@@ -73,7 +72,7 @@ enum seal_alg {
 	SEAL_ALG_DES3KD = 0x0002
 };
 
-#define RSA_MD5_CKSUM_LENGTH 16
+#define KRB5_CKSUM_LENGTH 8
 
 #define CKSUMTYPE_CRC32			0x0001
 #define CKSUMTYPE_RSA_MD4		0x0002
@@ -100,16 +99,6 @@ enum seal_alg {
 #define KG_EMPTY_CCACHE                          (39756044L)
 #define KG_NO_CTYPES                             (39756045L)
 
-#define KV5M_PRINCIPAL                           (-1760647423L)
-#define KV5M_KEYBLOCK                            (-1760647421L)
-#define KV5M_CHECKSUM                            (-1760647420L)
-#define KV5M_ADDRESS                             (-1760647390L)
-#define KV5M_AUTHENTICATOR                       (-1760647410L)
-#define KV5M_AUTH_CONTEXT                        (-1760647383L)
-#define KV5M_AUTHDATA                            (-1760647414L)
-#define KV5M_GSS_OID                             (-1760647372L)
-#define KV5M_GSS_QUEUE                           (-1760647371L)
-
 /* per Kerberos v5 protocol spec crypto types from the wire. 
  * these get mapped to linux kernel crypto routines.  
  */
@@ -126,14 +115,13 @@ enum seal_alg {
 #define ENCTYPE_UNKNOWN         0x01ff
 
 s32
-krb5_make_checksum(s32 cksumtype,
-		   struct xdr_netobj *input,
+krb5_make_checksum(s32 cksumtype, char *header, char *body, int body_len,
 		   struct xdr_netobj *cksum);
 
 u32
 krb5_make_token(struct krb5_ctx *context_handle, int qop_req,
-	struct xdr_netobj * input_message_buffer,
-	struct xdr_netobj * output_message_buffer, int toktype);
+	struct xdr_netobj *input_message_buffer,
+	struct xdr_netobj *output_message_buffer, int toktype);
 
 u32
 krb5_read_token(struct krb5_ctx *context_handle,
diff -puN net/sunrpc/auth_gss/gss_krb5_crypto.c~nfs-11-krb5_cleanup net/sunrpc/auth_gss/gss_krb5_crypto.c
--- 25/net/sunrpc/auth_gss/gss_krb5_crypto.c~nfs-11-krb5_cleanup	2004-01-09 22:16:14.000000000 -0800
+++ 25-akpm/net/sunrpc/auth_gss/gss_krb5_crypto.c	2004-01-09 22:16:14.000000000 -0800
@@ -122,14 +122,23 @@ out:
 	return(ret);
 }
 
+void
+buf_to_sg(struct scatterlist *sg, char *ptr, int len) {
+	sg->page = virt_to_page(ptr);
+	sg->offset = offset_in_page(ptr);
+	sg->length = len;
+}
+
+/* checksum the plaintext data and the first 8 bytes of the krb5 token header,
+ * as specified by the rfc: */
 s32
-krb5_make_checksum(s32 cksumtype, struct xdr_netobj *input,
+krb5_make_checksum(s32 cksumtype, char *header, char *body, int body_len, 
 		   struct xdr_netobj *cksum)
 {
-	s32			ret = -EINVAL;
-	struct scatterlist	sg[1];
-	char			*cksumname;
-	struct crypto_tfm	*tfm;
+	char                            *cksumname;
+	struct crypto_tfm               *tfm = NULL; /* XXX add to ctx? */
+	struct scatterlist              sg[2];
+	u32                             code = GSS_S_FAILURE;
 
 	switch (cksumtype) {
 		case CKSUMTYPE_RSA_MD5:
@@ -143,24 +152,17 @@ krb5_make_checksum(s32 cksumtype, struct
 	if (!(tfm = crypto_alloc_tfm(cksumname, 0)))
 		goto out;
 	cksum->len = crypto_tfm_alg_digestsize(tfm);
+	if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL)
+		goto out;
 
-	if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL) {
-		ret = -ENOMEM;
-		goto out_free_tfm;
-	}
-	sg[0].page = virt_to_page(input->data);
-	sg[0].offset = offset_in_page(input->data);
-	sg[0].length = input->len;
-
+	buf_to_sg(&sg[0], header, 8);
+	buf_to_sg(&sg[1], body, body_len);
 	crypto_digest_init(tfm);
-	crypto_digest_update(tfm, sg, 1);
+	crypto_digest_update(tfm, sg, 2);
 	crypto_digest_final(tfm, cksum->data);
-
-	ret = 0;
-
-out_free_tfm:
-	crypto_free_tfm(tfm);
+	code = 0;
 out:
-	dprintk("RPC: gss_k5cksum: returning %d\n", ret);
-	return (ret);
+	if (tfm)
+		crypto_free_tfm(tfm);
+	return code;
 }
diff -puN net/sunrpc/auth_gss/gss_krb5_mech.c~nfs-11-krb5_cleanup net/sunrpc/auth_gss/gss_krb5_mech.c
--- 25/net/sunrpc/auth_gss/gss_krb5_mech.c~nfs-11-krb5_cleanup	2004-01-09 22:16:14.000000000 -0800
+++ 25-akpm/net/sunrpc/auth_gss/gss_krb5_mech.c	2004-01-09 22:16:14.000000000 -0800
@@ -98,7 +98,7 @@ get_key(char **p, char *end, struct cryp
 			alg_mode = CRYPTO_TFM_MODE_CBC;
 			break;
 		default:
-			dprintk("RPC: get_key: unsupported algorithm %d", alg);
+			dprintk("RPC: get_key: unsupported algorithm %d\n", alg);
 			goto out_err_free_key;
 	}
 	if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
@@ -168,7 +168,7 @@ out_err:
 	return GSS_S_FAILURE;
 }
 
-void
+static void
 gss_delete_sec_context_kerberos(void *internal_ctx) {
 	struct krb5_ctx *kctx = internal_ctx;
 
@@ -181,16 +181,16 @@ gss_delete_sec_context_kerberos(void *in
 	kfree(kctx);
 }
 
-u32
+static u32
 gss_verify_mic_kerberos(struct gss_ctx		*ctx,
-			struct xdr_netobj	*signbuf,
-			struct xdr_netobj	*checksum,
-			u32		*qstate) {
+			struct xdr_netobj	*message,
+			struct xdr_netobj	*mic_token,
+			u32			*qstate) {
 	u32 maj_stat = 0;
 	int qop_state;
 	struct krb5_ctx *kctx = ctx->internal_ctx_id;
 
-	maj_stat = krb5_read_token(kctx, checksum, signbuf, &qop_state,
+	maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state,
 				   KG_TOK_MIC_MSG);
 	if (!maj_stat && qop_state)
 	    *qstate = qop_state;
@@ -199,21 +199,17 @@ gss_verify_mic_kerberos(struct gss_ctx		
 	return maj_stat;
 }
 
-u32
+static u32
 gss_get_mic_kerberos(struct gss_ctx	*ctx,
 		     u32		qop,
-		     struct xdr_netobj	*message_buffer,
-		     struct xdr_netobj	*message_token) {
+		     struct xdr_netobj	*message,
+		     struct xdr_netobj	*mic_token) {
 	u32 err = 0;
 	struct krb5_ctx *kctx = ctx->internal_ctx_id;
 
-	if (!message_buffer->data) return GSS_S_FAILURE;
-
-	dprintk("RPC: gss_get_mic_kerberos:"
-		" message_buffer->len %d\n",message_buffer->len);
+	if (!message->data) return GSS_S_FAILURE;
 
-	err = krb5_make_token(kctx, qop, message_buffer,
-			      message_token, KG_TOK_MIC_MSG);
+	err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG);
 
 	dprintk("RPC: gss_get_mic_kerberos returning %d\n",err);
 
diff -puN net/sunrpc/auth_gss/gss_krb5_seal.c~nfs-11-krb5_cleanup net/sunrpc/auth_gss/gss_krb5_seal.c
--- 25/net/sunrpc/auth_gss/gss_krb5_seal.c~nfs-11-krb5_cleanup	2004-01-09 22:16:14.000000000 -0800
+++ 25-akpm/net/sunrpc/auth_gss/gss_krb5_seal.c	2004-01-09 22:16:14.000000000 -0800
@@ -63,14 +63,13 @@
 #include <linux/jiffies.h>
 #include <linux/sunrpc/gss_krb5.h>
 #include <linux/random.h>
+#include <asm/scatterlist.h>
 #include <linux/crypto.h>
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY        RPCDBG_AUTH
 #endif
 
-#define CKSUM_SIZE	8
-
 static inline int
 gss_krb5_padding(int blocksize, int length) {
 	/* Most of the code is block-size independent but in practice we
@@ -79,29 +78,6 @@ gss_krb5_padding(int blocksize, int leng
 	return 8 - (length & 7);
 }
 
-/* checksum the plaintext data and the first 8 bytes of the krb5 token header,
- * as specified by the rfc: */
-static u32
-compute_checksum(s32 checksum_type, char *header, char *body, int body_len,
-		 struct xdr_netobj *md5cksum) {
-	char			*data_ptr;
-	struct xdr_netobj	plaind;
-	u32			code = GSS_S_FAILURE;
-
-	if (!(data_ptr = kmalloc(8 + body_len, GFP_KERNEL)))
-		goto out;
-	memcpy(data_ptr, header, 8);
-	memcpy(data_ptr + 8, body, body_len);
-	plaind.len = 8 + body_len;
-	plaind.data = data_ptr;
-	code = krb5_make_checksum(checksum_type, &plaind, md5cksum);
-	kfree(data_ptr);
-	code = 0;
-
-out:
-	return code;
-}
-
 u32
 krb5_make_token(struct krb5_ctx *ctx, int qop_req,
 		   struct xdr_netobj * text, struct xdr_netobj * token,
@@ -113,10 +89,12 @@ krb5_make_token(struct krb5_ctx *ctx, in
 	unsigned char		*ptr, *krb5_hdr, *msg_start;
 	s32			now;
 
-	dprintk("RPC: gss_krb5_seal");
+	dprintk("RPC:     gss_krb5_seal\n");
 
 	now = jiffies;
 
+	token->data = NULL;
+
 	if (qop_req != 0)
 		goto out_err;
 
@@ -167,8 +145,8 @@ krb5_make_token(struct krb5_ctx *ctx, in
 
 		memset(msg_start + blocksize + text->len, pad, pad);
 
-		if (compute_checksum(checksum_type, krb5_hdr, msg_start,
-				     tmsglen, &md5cksum))
+		if (krb5_make_checksum(checksum_type, krb5_hdr, msg_start,
+				       tmsglen, &md5cksum))
 			goto out_err;
 
 		if (krb5_encrypt(ctx->enc, NULL, msg_start, msg_start,
@@ -176,8 +154,8 @@ krb5_make_token(struct krb5_ctx *ctx, in
 			goto out_err;
 
 	} else { /* Sign only.  */
-		if (compute_checksum(checksum_type, krb5_hdr, text->data,
-					text->len, &md5cksum))
+		if (krb5_make_checksum(checksum_type, krb5_hdr, text->data,
+				       text->len, &md5cksum))
 			goto out_err;
 	}
 
@@ -187,10 +165,11 @@ krb5_make_token(struct krb5_ctx *ctx, in
 				  md5cksum.data, md5cksum.len))
 			goto out_err;
 		memcpy(krb5_hdr + 16,
-		       md5cksum.data + md5cksum.len - CKSUM_SIZE, CKSUM_SIZE);
+		       md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
+		       KRB5_CKSUM_LENGTH);
 
 		dprintk("make_seal_token: cksum data: \n");
-		print_hexl((u32 *) (krb5_hdr + 16), CKSUM_SIZE, 0);
+		print_hexl((u32 *) (krb5_hdr + 16), KRB5_CKSUM_LENGTH, 0);
 		break;
 	default:
 		BUG();
diff -puN net/sunrpc/auth_gss/gss_krb5_unseal.c~nfs-11-krb5_cleanup net/sunrpc/auth_gss/gss_krb5_unseal.c
--- 25/net/sunrpc/auth_gss/gss_krb5_unseal.c~nfs-11-krb5_cleanup	2004-01-09 22:16:14.000000000 -0800
+++ 25-akpm/net/sunrpc/auth_gss/gss_krb5_unseal.c	2004-01-09 22:16:14.000000000 -0800
@@ -68,7 +68,12 @@
 #endif
 
 
-/* message_buffer is an input if MIC and an output if WRAP. */
+/* message_buffer is an input if toktype is MIC and an output if it is WRAP:
+ * If toktype is MIC: read_token is a mic token, and message_buffer is the
+ *   data that the mic was supposedly taken over.
+ * If toktype is WRAP: read_token is a wrap token, and message_buffer is used
+ *   to return the decrypted data.
+ */
 
 u32
 krb5_read_token(struct krb5_ctx *ctx,
@@ -76,20 +81,13 @@ krb5_read_token(struct krb5_ctx *ctx,
 		struct xdr_netobj *message_buffer,
 		int *qop_state, int toktype)
 {
-	s32			code;
-	int			tmsglen = 0;
-	int			conflen = 0;
 	int			signalg;
 	int			sealalg;
 	struct xdr_netobj	token = {.len = 0, .data = NULL};
 	s32			checksum_type;
-	struct xdr_netobj	cksum;
 	struct xdr_netobj	md5cksum = {.len = 0, .data = NULL};
-	struct xdr_netobj	plaind;
-	char			*data_ptr;
 	s32			now;
 	unsigned char		*plain = NULL;
-	int			cksum_len = 0;
 	int			plainlen = 0;
 	int			direction;
 	s32			seqnum;
@@ -97,10 +95,9 @@ krb5_read_token(struct krb5_ctx *ctx,
 	int			bodysize;
 	u32			ret = GSS_S_DEFECTIVE_TOKEN;
 
-	dprintk("RPC: krb5_read_token\n");
+	dprintk("RPC:      krb5_read_token\n");
 
-	if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
-					&bodysize, &ptr, toktype,
+	if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr, toktype,
 					read_token->len))
 		goto out;
 
@@ -138,40 +135,22 @@ krb5_read_token(struct krb5_ctx *ctx,
 	     signalg != SGN_ALG_HMAC_SHA1_DES3_KD))
 		goto out;
 
-	/* starting with a single alg */
-	switch (signalg) {
-	case SGN_ALG_DES_MAC_MD5:
-		cksum_len = 8;
-		break;
-	default:
-		goto out;
-	}
-
-	if (toktype == KG_TOK_WRAP_MSG)
-		tmsglen = bodysize - (14 + cksum_len);
-
-	/* get the token parameters */
-
-	/* decode the message, if WRAP */
-
 	if (toktype == KG_TOK_WRAP_MSG) {
-		dprintk("RPC: krb5_read_token KG_TOK_WRAP_MSG\n");
+		int conflen = crypto_tfm_alg_blocksize(ctx->enc);
+		int padlen;
 
-		plain = kmalloc(tmsglen, GFP_KERNEL);
-		ret = GSS_S_FAILURE;
-		if (plain ==  NULL)
-			goto out;
+		plainlen = bodysize - (14 + KRB5_CKSUM_LENGTH);
+		plain = ptr + 14 + KRB5_CKSUM_LENGTH;
 
-		code = krb5_decrypt(ctx->enc, NULL,
-				   ptr + 14 + cksum_len, plain,
-				   tmsglen);
-		if (code)
+		ret = krb5_decrypt(ctx->enc, NULL, plain, plain, plainlen);
+		if (ret)
 			goto out;
 
-		plainlen = tmsglen;
-
-		conflen = crypto_tfm_alg_blocksize(ctx->enc);
-		token.len = tmsglen - conflen - plain[tmsglen - 1];
+		ret = GSS_S_FAILURE;
+		padlen = plain[plainlen -1];
+		if ((padlen < 1) || (padlen > 8))
+			goto out;
+		token.len = plainlen - conflen - padlen;
 
 		if (token.len) {
 			token.data = kmalloc(token.len, GFP_KERNEL);
@@ -181,15 +160,13 @@ krb5_read_token(struct krb5_ctx *ctx,
 		}
 
 	} else if (toktype == KG_TOK_MIC_MSG) {
-		dprintk("RPC: krb5_read_token KG_TOK_MIC_MSG\n");
 		token = *message_buffer;
 		plain = token.data;
 		plainlen = token.len;
 	} else {
-		token.len = 0;
-		token.data = NULL;
-		plain = token.data;
-		plainlen = token.len;
+		printk("RPC: bad toktype in krb5_read_token");
+		ret = GSS_S_FAILURE;
+		goto out;
 	}
 
 	dprintk("RPC krb5_read_token: token.len %d plainlen %d\n", token.len,
@@ -209,67 +186,26 @@ krb5_read_token(struct krb5_ctx *ctx,
 
 	switch (signalg) {
 	case SGN_ALG_DES_MAC_MD5:
-		dprintk("RPC krb5_read_token SGN_ALG_DES_MAC_MD5\n");
-		/* compute the checksum of the message.
-		 * 8 = bytes of token body to be checksummed according to spec 
-		 */
-
-		data_ptr = kmalloc(8 + plainlen, GFP_KERNEL);
-		ret = GSS_S_FAILURE;
-		if (!data_ptr)
+		ret = krb5_make_checksum(checksum_type, ptr - 2, plain,
+					 plainlen, &md5cksum);
+		if (ret)
 			goto out;
 
-		memcpy(data_ptr, ptr - 2, 8);
-		memcpy(data_ptr + 8, plain, plainlen);
-
-		plaind.len = 8 + plainlen;
-		plaind.data = data_ptr;
-
-		code = krb5_make_checksum(checksum_type,
-					    &plaind, &md5cksum);
-
-		kfree(data_ptr);
-
-		if (code)
+		ret = krb5_encrypt(ctx->seq, NULL, md5cksum.data,
+				   md5cksum.data, 16);
+		if (ret)
 			goto out;
 
-		code = krb5_encrypt(ctx->seq, NULL, md5cksum.data,
-					  md5cksum.data, 16);
-		if (code)
+		if (memcmp(md5cksum.data + 8, ptr + 14, 8)) {
+			ret = GSS_S_BAD_SIG;
 			goto out;
-
-		if (signalg == 0)
-			cksum.len = 8;
-		else
-			cksum.len = 16;
-		cksum.data = md5cksum.data + 16 - cksum.len;
-
-		dprintk
-		    ("RPC: krb5_read_token: memcmp digest cksum.len %d:\n",
-		     cksum.len);
-		dprintk("          md5cksum.data\n");
-		print_hexl((u32 *) md5cksum.data, 16, 0);
-		dprintk("          cksum.data:\n");
-		print_hexl((u32 *) cksum.data, cksum.len, 0);
-		{
-			u32 *p;
-
-			(u8 *) p = ptr + 14;
-			dprintk("          ptr+14:\n");
-			print_hexl(p, cksum.len, 0);
 		}
-
-		code = memcmp(cksum.data, ptr + 14, cksum.len);
 		break;
 	default:
 		ret = GSS_S_DEFECTIVE_TOKEN;
 		goto out;
 	}
 
-	ret = GSS_S_BAD_SIG;
-	if (code)
-		goto out;
-
 	/* it got through unscathed.  Make sure the context is unexpired */
 
 	if (toktype == KG_TOK_WRAP_MSG)
@@ -287,8 +223,8 @@ krb5_read_token(struct krb5_ctx *ctx,
 	/* do sequencing checks */
 
 	ret = GSS_S_BAD_SIG;
-	if ((code = krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction,
-				   &seqnum)))
+	if ((ret = krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction,
+				    &seqnum)))
 		goto out;
 
 	if ((ctx->initiate && direction != 0xff) ||
@@ -298,9 +234,7 @@ krb5_read_token(struct krb5_ctx *ctx,
 	ret = GSS_S_COMPLETE;
 out:
 	if (md5cksum.data) kfree(md5cksum.data);
-	if (toktype == KG_TOK_WRAP_MSG) {
-		if (plain) kfree(plain);
-		if (ret && token.data) kfree(token.data);
-	}
+	if ((toktype == KG_TOK_WRAP_MSG) && ret && token.data)
+		kfree(token.data);
 	return ret;
 }

_