⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asn1.c

📁 Linux内核自带的cifs模块
💻 C
字号:
/* * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich * * Copyright (c) 2000 RP Internet (www.rpi.net.au). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/slab.h>#include "cifspdu.h"#include "cifsglob.h"#include "cifs_debug.h"#include "cifsproto.h"#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)#include <linux/config.h>#endif/***************************************************************************** * * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse) * *****************************************************************************//* Class */#define ASN1_UNI	0	/* Universal */#define ASN1_APL	1	/* Application */#define ASN1_CTX	2	/* Context */#define ASN1_PRV	3	/* Private *//* Tag */#define ASN1_EOC	0	/* End Of Contents or N/A */#define ASN1_BOL	1	/* Boolean */#define ASN1_INT	2	/* Integer */#define ASN1_BTS	3	/* Bit String */#define ASN1_OTS	4	/* Octet String */#define ASN1_NUL	5	/* Null */#define ASN1_OJI	6	/* Object Identifier  */#define ASN1_OJD	7	/* Object Description */#define ASN1_EXT	8	/* External */#define ASN1_SEQ	16	/* Sequence */#define ASN1_SET	17	/* Set */#define ASN1_NUMSTR	18	/* Numerical String */#define ASN1_PRNSTR	19	/* Printable String */#define ASN1_TEXSTR	20	/* Teletext String */#define ASN1_VIDSTR	21	/* Video String */#define ASN1_IA5STR	22	/* IA5 String */#define ASN1_UNITIM	23	/* Universal Time */#define ASN1_GENTIM	24	/* General Time */#define ASN1_GRASTR	25	/* Graphical String */#define ASN1_VISSTR	26	/* Visible String */#define ASN1_GENSTR	27	/* General String *//* Primitive / Constructed methods*/#define ASN1_PRI	0	/* Primitive */#define ASN1_CON	1	/* Constructed *//* * Error codes. */#define ASN1_ERR_NOERROR		0#define ASN1_ERR_DEC_EMPTY		2#define ASN1_ERR_DEC_EOC_MISMATCH	3#define ASN1_ERR_DEC_LENGTH_MISMATCH	4#define ASN1_ERR_DEC_BADVALUE		5#define SPNEGO_OID_LEN 7#define NTLMSSP_OID_LEN  10static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };/* * ASN.1 context. */struct asn1_ctx {	int error;		/* Error condition */	unsigned char *pointer;	/* Octet just to be decoded */	unsigned char *begin;	/* First octet */	unsigned char *end;	/* Octet after last octet */};/* * Octet string (not null terminated) */struct asn1_octstr {	unsigned char *data;	unsigned int len;};static voidasn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len){	ctx->begin = buf;	ctx->end = buf + len;	ctx->pointer = buf;	ctx->error = ASN1_ERR_NOERROR;}static unsigned charasn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch){	if (ctx->pointer >= ctx->end) {		ctx->error = ASN1_ERR_DEC_EMPTY;		return 0;	}	*ch = *(ctx->pointer)++;	return 1;}static unsigned charasn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag){	unsigned char ch;	*tag = 0;	do {		if (!asn1_octet_decode(ctx, &ch))			return 0;		*tag <<= 7;		*tag |= ch & 0x7F;	} while ((ch & 0x80) == 0x80);	return 1;}static unsigned charasn1_id_decode(struct asn1_ctx *ctx,	       unsigned int *cls, unsigned int *con, unsigned int *tag){	unsigned char ch;	if (!asn1_octet_decode(ctx, &ch))		return 0;	*cls = (ch & 0xC0) >> 6;	*con = (ch & 0x20) >> 5;	*tag = (ch & 0x1F);	if (*tag == 0x1F) {		if (!asn1_tag_decode(ctx, tag))			return 0;	}	return 1;}static unsigned charasn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len){	unsigned char ch, cnt;	if (!asn1_octet_decode(ctx, &ch))		return 0;	if (ch == 0x80)		*def = 0;	else {		*def = 1;		if (ch < 0x80)			*len = ch;		else {			cnt = (unsigned char) (ch & 0x7F);			*len = 0;			while (cnt > 0) {				if (!asn1_octet_decode(ctx, &ch))					return 0;				*len <<= 8;				*len |= ch;				cnt--;			}		}	}	return 1;}static unsigned charasn1_header_decode(struct asn1_ctx *ctx,		   unsigned char **eoc,		   unsigned int *cls, unsigned int *con, unsigned int *tag){	unsigned int def = 0;	unsigned int len = 0;	if (!asn1_id_decode(ctx, cls, con, tag))		return 0;	if (!asn1_length_decode(ctx, &def, &len))		return 0;	if (def)		*eoc = ctx->pointer + len;	else		*eoc = NULL;	return 1;}static unsigned charasn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc){	unsigned char ch;	if (eoc == NULL) {		if (!asn1_octet_decode(ctx, &ch))			return 0;		if (ch != 0x00) {			ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;			return 0;		}		if (!asn1_octet_decode(ctx, &ch))			return 0;		if (ch != 0x00) {			ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;			return 0;		}		return 1;	} else {		if (ctx->pointer != eoc) {			ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH;			return 0;		}		return 1;	}}/* static unsigned char asn1_null_decode(struct asn1_ctx *ctx,				      unsigned char *eoc){	ctx->pointer = eoc;	return 1;}static unsigned char asn1_long_decode(struct asn1_ctx *ctx,				      unsigned char *eoc, long *integer){	unsigned char ch;	unsigned int len;	if (!asn1_octet_decode(ctx, &ch))		return 0;	*integer = (signed char) ch;	len = 1;	while (ctx->pointer < eoc) {		if (++len > sizeof(long)) {			ctx->error = ASN1_ERR_DEC_BADVALUE;			return 0;		}		if (!asn1_octet_decode(ctx, &ch))			return 0;		*integer <<= 8;		*integer |= ch;	}	return 1;}static unsigned char asn1_uint_decode(struct asn1_ctx *ctx,				      unsigned char *eoc,				      unsigned int *integer){	unsigned char ch;	unsigned int len;	if (!asn1_octet_decode(ctx, &ch))		return 0;	*integer = ch;	if (ch == 0)		len = 0;	else		len = 1;	while (ctx->pointer < eoc) {		if (++len > sizeof(unsigned int)) {			ctx->error = ASN1_ERR_DEC_BADVALUE;			return 0;		}		if (!asn1_octet_decode(ctx, &ch))			return 0;		*integer <<= 8;		*integer |= ch;	}	return 1;}static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx,				       unsigned char *eoc,				       unsigned long *integer){	unsigned char ch;	unsigned int len;	if (!asn1_octet_decode(ctx, &ch))		return 0;	*integer = ch;	if (ch == 0)		len = 0;	else		len = 1;	while (ctx->pointer < eoc) {		if (++len > sizeof(unsigned long)) {			ctx->error = ASN1_ERR_DEC_BADVALUE;			return 0;		}		if (!asn1_octet_decode(ctx, &ch))			return 0;		*integer <<= 8;		*integer |= ch;	}	return 1;}static unsigned charasn1_octets_decode(struct asn1_ctx *ctx,		   unsigned char *eoc,		   unsigned char **octets, unsigned int *len){	unsigned char *ptr;	*len = 0;	*octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC);	if (*octets == NULL) {		return 0;	}	ptr = *octets;	while (ctx->pointer < eoc) {		if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) {			kfree(*octets);			*octets = NULL;			return 0;		}		(*len)++;	}	return 1;} */static unsigned charasn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid){	unsigned char ch;	*subid = 0;	do {		if (!asn1_octet_decode(ctx, &ch))			return 0;		*subid <<= 7;		*subid |= ch & 0x7F;	} while ((ch & 0x80) == 0x80);	return 1;}static intasn1_oid_decode(struct asn1_ctx *ctx,		unsigned char *eoc, unsigned long **oid, unsigned int *len){	unsigned long subid;	unsigned int size;	unsigned long *optr;	size = eoc - ctx->pointer + 1;	*oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC);	if (*oid == NULL)		return 0;	optr = *oid;	if (!asn1_subid_decode(ctx, &subid)) {		kfree(*oid);		*oid = NULL;		return 0;	}	if (subid < 40) {		optr[0] = 0;		optr[1] = subid;	} else if (subid < 80) {		optr[0] = 1;		optr[1] = subid - 40;	} else {		optr[0] = 2;		optr[1] = subid - 80;	}	*len = 2;	optr += 2;	while (ctx->pointer < eoc) {		if (++(*len) > size) {			ctx->error = ASN1_ERR_DEC_BADVALUE;			kfree(*oid);			*oid = NULL;			return 0;		}		if (!asn1_subid_decode(ctx, optr++)) {			kfree(*oid);			*oid = NULL;			return 0;		}	}	return 1;}static intcompare_oid(unsigned long *oid1, unsigned int oid1len,	    unsigned long *oid2, unsigned int oid2len){	unsigned int i;	if (oid1len != oid2len)		return 0;	else {		for (i = 0; i < oid1len; i++) {			if (oid1[i] != oid2[i])				return 0;		}		return 1;	}}	/* BB check for endian conversion issues here */intdecode_negTokenInit(unsigned char *security_blob, int length,		    enum securityEnum *secType){	struct asn1_ctx ctx;	unsigned char *end;	unsigned char *sequence_end;	unsigned long *oid = NULL;	unsigned int cls, con, tag, oidlen, rc;	int use_ntlmssp = FALSE;	*secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/	/* cifs_dump_mem(" Received SecBlob ", security_blob, length); */	asn1_open(&ctx, security_blob, length);	if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {		cFYI(1, ("Error decoding negTokenInit header"));		return 0;	} else if ((cls != ASN1_APL) || (con != ASN1_CON)		   || (tag != ASN1_EOC)) {		cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag));		return 0;	} else {		/*      remember to free obj->oid */		rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);		if (rc) {			if ((tag == ASN1_OJI) && (cls == ASN1_PRI)) {				rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);				if (rc) {					rc = compare_oid(oid, oidlen,							 SPNEGO_OID,							 SPNEGO_OID_LEN);					kfree(oid);				}			} else				rc = 0;		}		if (!rc) {			cFYI(1, ("Error decoding negTokenInit header"));			return 0;		}		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {			cFYI(1, ("Error decoding negTokenInit"));			return 0;		} else if ((cls != ASN1_CTX) || (con != ASN1_CON)			   || (tag != ASN1_EOC)) {			cFYI(1,			     ("cls = %d con = %d tag = %d end = %p (%d) exit 0",			      cls, con, tag, end, *end));			return 0;		}		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {			cFYI(1, ("Error decoding 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 1",			      cls, con, tag, end, *end));			return 0;		}		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)) {			cFYI(1,			     ("cls = %d con = %d tag = %d end = %p (%d) exit 0",			      cls, con, tag, end, *end));			return 0;		}		if (asn1_header_decode		    (&ctx, &sequence_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 1",			      cls, con, tag, end, *end));			return 0;		}		while (!asn1_eoc_decode(&ctx, sequence_end)) {			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)) {				rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);				if (rc) {					cFYI(1,					  ("OID len = %d oid = 0x%lx 0x%lx "					   "0x%lx 0x%lx",					   oidlen, *oid, *(oid + 1),					   *(oid + 2), *(oid + 3)));					rc = compare_oid(oid, oidlen,						 NTLMSSP_OID, NTLMSSP_OID_LEN);					kfree(oid);					if (rc)						use_ntlmssp = TRUE;				}			} else {				cFYI(1, ("Should be an oid what is going on?"));			}		}		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {			cFYI(1,			     ("Error decoding last part negTokenInit exit3"));			return 0;		} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {			/* tag = 3 indicating mechListMIC */			cFYI(1,			     ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",			      cls, con, tag, end, *end));			return 0;		}		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {			cFYI(1,			     ("Error decoding last part negTokenInit exit5"));			return 0;		} else if ((cls != ASN1_UNI) || (con != ASN1_CON)			   || (tag != ASN1_SEQ)) {			cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)",				cls, con, tag, end, *end));		}		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {			cFYI(1,			     ("Error decoding last part negTokenInit exit 7"));			return 0;		} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {			cFYI(1,			     ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)",			      cls, con, tag, end, *end));			return 0;		}		if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {			cFYI(1,			     ("Error decoding last part negTokenInit exit9"));			return 0;		} else if ((cls != ASN1_UNI) || (con != ASN1_PRI)			   || (tag != ASN1_GENSTR)) {			cFYI(1,			     ("Exit10 cls = %d con = %d tag = %d end = %p (%d)",			      cls, con, tag, end, *end));			return 0;		}		cFYI(1, ("Need to call asn1_octets_decode() function for %s",			 ctx.pointer));	/* is this UTF-8 or ASCII? */	}	/* if (use_kerberos)	   *secType = Kerberos	   else */	if (use_ntlmssp) {		*secType = NTLMSSP;	}	return 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -