[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 */