rpc: spkm3 update

This updates the spkm3 code to bring it up to date with our current
understanding of the spkm3 spec.

In doing so, we're changing the downcall format used by gssd in the spkm3 case,
which will cause an incompatilibity with old userland spkm3 support.  Since the
old code a) didn't implement the protocol correctly, and b) was never
distributed except in the form of some experimental patches from the citi web
site, we're assuming this is OK.

We do detect the old downcall format and print warning (and fail).  We also
include a version number in the new downcall format, to be used in the
future in case any further change is required.

In some more detail:

	- fix integrity support
	- removed dependency on NIDs. instead OIDs are used
	- known OID values for algorithms added.
	- fixed some context fields and types

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c
index 544eb6f..e54581c 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_unseal.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_unseal.c
@@ -54,66 +54,70 @@
 		struct xdr_buf *message_buffer, /* signbuf */
 		int toktype)
 {
+	s32			checksum_type;
 	s32			code;
 	struct xdr_netobj	wire_cksum = {.len =0, .data = NULL};
 	char			cksumdata[16];
 	struct xdr_netobj	md5cksum = {.len = 0, .data = cksumdata};
 	unsigned char		*ptr = (unsigned char *)read_token->data;
-	unsigned char           *cksum;
+	unsigned char		*cksum;
 	int			bodysize, md5elen;
 	int			mic_hdrlen;
 	u32			ret = GSS_S_DEFECTIVE_TOKEN;
 
-	dprintk("RPC: spkm3_read_token read_token->len %d\n", read_token->len);
-
 	if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
 					&bodysize, &ptr, read_token->len))
 		goto out;
 
 	/* decode the token */
 
-	if (toktype == SPKM_MIC_TOK) {
-
-		if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum))) 
-			goto out;
-
-		if (*cksum++ != 0x03) {
-			dprintk("RPC: spkm3_read_token BAD checksum type\n");
-			goto out;
-		}
-		md5elen = *cksum++; 
-		cksum++; 	/* move past the zbit */
-	
-		if(!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16))
-			goto out;
-
-		/* HARD CODED FOR MD5 */
-
-		/* compute the checksum of the message.
-		*  ptr + 2 = start of header piece of checksum
-		*  mic_hdrlen + 2 = length of header piece of checksum
-		*/
-		ret = GSS_S_DEFECTIVE_TOKEN;
-		code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2, 
-					mic_hdrlen + 2, 
-		                        message_buffer, 0, &md5cksum);
-
-		if (code)
-			goto out;
-
-		dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n", 
-			wire_cksum.len);
-
-		ret = GSS_S_BAD_SIG;
-		code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
-		if (code)
-			goto out;
-
-	} else { 
-		dprintk("RPC: BAD or UNSUPPORTED SPKM3 token type: %d\n",toktype);
+	if (toktype != SPKM_MIC_TOK) {
+		dprintk("RPC: BAD SPKM3 token type: %d\n", toktype);
 		goto out;
 	}
 
+	if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum)))
+		goto out;
+
+	if (*cksum++ != 0x03) {
+		dprintk("RPC: spkm3_read_token BAD checksum type\n");
+		goto out;
+	}
+	md5elen = *cksum++;
+	cksum++; 	/* move past the zbit */
+
+	if (!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16))
+		goto out;
+
+	/* HARD CODED FOR MD5 */
+
+	/* compute the checksum of the message.
+	 * ptr + 2 = start of header piece of checksum
+	 * mic_hdrlen + 2 = length of header piece of checksum
+	 */
+	ret = GSS_S_DEFECTIVE_TOKEN;
+	if (!g_OID_equal(&ctx->intg_alg, &hmac_md5_oid)) {
+		dprintk("RPC: gss_spkm3_seal: unsupported I-ALG algorithm\n");
+		goto out;
+	}
+
+	checksum_type = CKSUMTYPE_HMAC_MD5;
+
+	code = make_spkm3_checksum(checksum_type,
+		&ctx->derived_integ_key, ptr + 2, mic_hdrlen + 2,
+		message_buffer, 0, &md5cksum);
+
+	if (code)
+		goto out;
+
+	ret = GSS_S_BAD_SIG;
+	code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
+	if (code) {
+		dprintk("RPC: bad MIC checksum\n");
+		goto out;
+	}
+
+
 	/* XXX: need to add expiration and sequencing */
 	ret = GSS_S_COMPLETE;
 out: