[patch]Add DER decoding of ASN.1 structure negTokenResp of SPNEGO

Shirish Pargaonkar <[email protected]>
Newsgroups gmane.linux.file-systems.cifs
Message-ID <[email protected]>
This patch adds DER decoding of ASN.1 structure negTokenResp of SPNEGO.

Currently, only security mechanism used/handled in CIFS using SPNEGO
is Kerberos,
so use the function decode_negTokenResp to check the response to
negTokenInit sent by Kerberos.
I am not sure in case of Kerberos, what follows in the negTokenResp i.e.
how does kerberos blob look like if the negstate is accept-incomplete,
so I let it go further
instead of returning from decode_negTokenResp but at some point we will need a
function to handle that blob.

_______________________________________________
linux-cifs-client mailing list
[email protected]
https://lists.samba.org/mailman/listinfo/linux-cifs-client
cifs_asn1.1.patch (application/octet-stream, 5 KB)
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c
index 20692fb..b295761 100644
--- a/fs/cifs/asn1.c
+++ b/fs/cifs/asn1.c
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include "cifspdu.h"
+#include "ntlmssp.h"
 #include "cifsglob.h"
 #include "cifs_debug.h"
 #include "cifsproto.h"
@@ -125,7 +126,6 @@ asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch)
 	return 1;
 }
 
-#if 0 /* will be needed later by spnego decoding/encoding of ntlmssp */
 static unsigned char
 asn1_enum_decode(struct asn1_ctx *ctx, __le32 *val)
 {
@@ -145,7 +145,6 @@ asn1_enum_decode(struct asn1_ctx *ctx, __le32 *val)
 	ctx->pointer++;
 	return 1;
 }
-#endif
 
 static unsigned char
 asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag)
@@ -683,3 +682,120 @@ decode_negtoken_exit:
 
 	return 1;
 }
+
+int
+decode_negTokenResp(unsigned char *security_blob, int length,
+					struct cifsSesInfo *ses)
+{
+	unsigned int cls, con, tag, oidlen, rc;
+	unsigned long *oid = NULL;
+	unsigned char *end;
+	struct asn1_ctx ctx;
+	int negstate;
+
+	/* cifs_dump_mem(" Received SecBlob ", security_blob, length); */
+
+	asn1_open(&ctx, security_blob, length);
+
+	/* GSSAPI/SPNEGO header */
+	if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+		cFYI(1, ("Error decoding negTokenResp header"));
+		return 0;
+	} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
+		   || (tag != ASN1_BOL)) {
+		cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag));
+		return 0;
+	}
+
+	/* negTokenarg or negTokenResp   Sequence */
+	if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+		cFYI(1, ("Error decoding 2nd part of negTokenInit"));
+		return 0;
+	} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
+		   || (tag != ASN1_SEQ)) {
+		cFYI(1,
+		     ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
+		      cls, con, tag, end, *end));
+		return 0;
+	}
+
+	/* negstate */
+	if (asn1_header_decode
+	    (&ctx, &end, &cls, &con, &tag) == 0) {
+		cFYI(1, ("Error decoding 2nd part of negTokenInit"));
+		return 0;
+	} else if ((cls == ASN1_CTX) && (con == ASN1_CON) &&
+			 (tag == ASN1_EOC)) {
+			/* Enumerated */
+			if (!asn1_enum_decode(&ctx, &negstate)) {
+				cFYI(1, ("Error decoding enum negstate val "));
+				return 0;
+			}
+	} else {
+		cFYI(1,
+		     ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
+		      cls, con, tag, end, *end));
+		return 0;
+	}
+
+	if ((negstate == 0)) {
+		cFYI(1, ("negTokenResponse Success, no more processing: %d",
+					negstate));
+		return 1;
+	}
+
+	if ((negstate == 2) || (negstate == 3)) {
+		cFYI(1, ("Do not handle either reject or request-MIC: %d",
+					negstate));
+		return 0;
+	}
+
+	/* supportedMech, no need to compare and decipher*/
+	rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
+	if (!rc) {
+		cFYI(1, ("Error decoding negTokenInit hdr exit2"));
+		return 0;
+	}
+
+	rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
+	if (!rc) {
+		cFYI(1, ("Error decoding negTokenInit hdr exit2"));
+		return 0;
+	}
+	if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
+		if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) {
+
+			cFYI(1, ("OID len = %d oid = 0x%lx 0x%lx "
+				 "0x%lx 0x%lx", oidlen, *oid,
+				 *(oid + 1), *(oid + 2), *(oid + 3)));
+			if (!compare_oid(oid, oidlen, NTLMSSP_OID,
+							NTLMSSP_OID_LEN)) {
+				cFYI(1, ("negTokenResp Incorrect sec mech"));
+				kfree(oid);
+				return 0;
+			}
+
+			kfree(oid);
+		}
+	}
+
+	/* responseToken */
+	if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+		cFYI(1, ("Error decoding responseTokenit3"));
+		return 0;
+	}
+
+	/* octet string */
+	if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
+		cFYI(1, ("Error decoding responseTokenit3"));
+		return 0;
+	}
+
+	/* If and when we decide to add NTLMSSP SPNEGO functionality,
+	   we will need this call.
+		if (decode_ntlmssp_challenge(ctx.pointer,
+				sizeof(CHALLENGE_MESSAGE), ses)) {
+	 */
+
+	return 1;
+}
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c419416..d6d34d2 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -74,6 +74,7 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
 			enum securityEnum *secType);
+extern int decode_negTokenResp(unsigned char *, int, struct cifsSesInfo *);
 extern int cifs_convert_address(char *src, void *dst);
 extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
 extern void header_assemble(struct smb_hdr *, char /* command */ ,
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 7085a62..1983ce2 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -903,6 +903,15 @@ ssetup_ntlmssp_authenticate:
 			rc = -EINVAL;
 			goto ssetup_exit;
 		}
+
+		if ((type == Kerberos || type == MSKerberos)) {
+			if (!decode_negTokenResp(bcc_ptr, blob_len, ses)) {
+				cERROR(1, ("Kerberos Authentication Error"));
+				rc = 1;
+				goto ssetup_exit;
+			}
+		}
+
 		if (phase == NtLmChallenge) {
 			rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
 			/* now goto beginning for ntlmssp authenticate phase */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.