cregit-Linux how code gets into the kernel

Release 4.10 fs/cifs/asn1.c

Directory: fs/cifs
/*
 * 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"

/*****************************************************************************
 *
 * 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_ENUM	10	
/* Enumerated */

#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  10

#define KRB5_OID_LEN  7

#define KRB5U2U_OID_LEN  8

#define MSKRB5_OID_LEN  7

static 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 };

static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 };

static unsigned long KRB5U2U_OID[8] = { 1, 2, 840, 113554, 1, 2, 2, 3 };

static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 };

/*
 * 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 void asn1_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; }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french46100.00%1100.00%
Total46100.00%1100.00%


static unsigned char asn1_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; }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french52100.00%1100.00%
Total52100.00%1100.00%

#if 0 /* will be needed later by spnego decoding/encoding of ntlmssp */ static unsigned char asn1_enum_decode(struct asn1_ctx *ctx, __le32 *val) { unsigned char ch; if (ctx->pointer >= ctx->end) { ctx->error = ASN1_ERR_DEC_EMPTY; return 0; } ch = *(ctx->pointer)++; /* ch has 0xa, ptr points to length octet */ if ((ch) == ASN1_ENUM) /* if ch value is ENUM, 0xa */ *val = *(++(ctx->pointer)); /* value has enum value */ else return 0; ctx->pointer++; return 1; } #endif
static unsigned char asn1_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; }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french69100.00%1100.00%
Total69100.00%1100.00%


static unsigned char asn1_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; }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french101100.00%1100.00%
Total101100.00%1100.00%


static unsigned char asn1_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--; } } } /* don't trust len bigger than ctx buffer */ if (*len > ctx->end - ctx->pointer) return 0; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french13088.44%150.00%
chris wrightchris wright1711.56%150.00%
Total147100.00%2100.00%


static unsigned char asn1_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; /* primitive shall be definite, indefinite shall be constructed */ if (*con == ASN1_PRI && !def) return 0; if (def) *eoc = ctx->pointer + len; else *eoc = NULL; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french10187.83%375.00%
chris wrightchris wright1412.17%125.00%
Total115100.00%4100.00%


static unsigned char asn1_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; } }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french119100.00%2100.00%
Total119100.00%2100.00%

/* 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 char asn1_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 char asn1_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; }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french69100.00%1100.00%
Total69100.00%1100.00%


static int asn1_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; /* first subid actually encodes first two subids */ if (size < 2 || size > UINT_MAX/sizeof(unsigned long)) return 0; *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; }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french25592.73%250.00%
chris wrightchris wright196.91%125.00%
jan beulichjan beulich10.36%125.00%
Total275100.00%4100.00%


static int compare_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; } }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french73100.00%2100.00%
Total73100.00%2100.00%

/* BB check for endian conversion issues here */
int decode_negTokenInit(unsigned char *security_blob, int length, struct TCP_Server_Info *server) { struct asn1_ctx ctx; unsigned char *end; unsigned char *sequence_end; unsigned long *oid = NULL; unsigned int cls, con, tag, oidlen, rc; /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */ asn1_open(&ctx, security_blob, length); /* GSSAPI header */ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { cifs_dbg(FYI, "Error decoding negTokenInit header\n"); return 0; } else if ((cls != ASN1_APL) || (con != ASN1_CON) || (tag != ASN1_EOC)) { cifs_dbg(FYI, "cls = %d con = %d tag = %d\n", cls, con, tag); return 0; } /* Check for SPNEGO OID -- remember to free obj->oid */ rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); if (rc) { if ((tag == ASN1_OJI) && (con == ASN1_PRI) && (cls == ASN1_UNI)) { 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; } /* SPNEGO OID not present or garbled -- bail out */ if (!rc) { cifs_dbg(FYI, "Error decoding negTokenInit header\n"); return 0; } /* SPNEGO */ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { cifs_dbg(FYI, "Error decoding negTokenInit\n"); return 0; } else if ((cls != ASN1_CTX) || (con != ASN1_CON) || (tag != ASN1_EOC)) { cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p (%d) exit 0\n", cls, con, tag, end, *end); return 0; } /* negTokenInit */ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { cifs_dbg(FYI, "Error decoding negTokenInit\n"); return 0; } else if ((cls != ASN1_UNI) || (con != ASN1_CON) || (tag != ASN1_SEQ)) { cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p (%d) exit 1\n", cls, con, tag, end, *end); return 0; } /* sequence */ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { cifs_dbg(FYI, "Error decoding 2nd part of negTokenInit\n"); return 0; } else if ((cls != ASN1_CTX) || (con != ASN1_CON) || (tag != ASN1_EOC)) { cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p (%d) exit 0\n", cls, con, tag, end, *end); return 0; } /* sequence of */ if (asn1_header_decode (&ctx, &sequence_end, &cls, &con, &tag) == 0) { cifs_dbg(FYI, "Error decoding 2nd part of negTokenInit\n"); return 0; } else if ((cls != ASN1_UNI) || (con != ASN1_CON) || (tag != ASN1_SEQ)) { cifs_dbg(FYI, "cls = %d con = %d tag = %d end = %p (%d) exit 1\n", cls, con, tag, end, *end); return 0; } /* list of security mechanisms */ while (!asn1_eoc_decode(&ctx, sequence_end)) { rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); if (!rc) { cifs_dbg(FYI, "Error decoding negTokenInit hdr exit2\n"); return 0; } if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) { cifs_dbg(FYI, "OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx\n", oidlen, *oid, *(oid + 1), *(oid + 2), *(oid + 3)); if (compare_oid(oid, oidlen, MSKRB5_OID, MSKRB5_OID_LEN)) server->sec_mskerberos = true; else if (compare_oid(oid, oidlen, KRB5U2U_OID, KRB5U2U_OID_LEN)) server->sec_kerberosu2u = true; else if (compare_oid(oid, oidlen, KRB5_OID, KRB5_OID_LEN)) server->sec_kerberos = true; else if (compare_oid(oid, oidlen, NTLMSSP_OID, NTLMSSP_OID_LEN)) server->sec_ntlmssp = true; kfree(oid); } } else { cifs_dbg(FYI, "Should be an oid what is going on?\n"); } } /* * We currently ignore anything at the end of the SPNEGO blob after * the mechTypes have been parsed, since none of that info is * used at the moment. */ return 1; }

Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french65784.23%853.33%
joe perchesjoe perches708.97%213.33%
jeff laytonjeff layton526.67%426.67%
chris wrightchris wright10.13%16.67%
Total780100.00%15100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
steve frenchsteve french201489.71%1458.33%
jeff laytonjeff layton1084.81%416.67%
joe perchesjoe perches703.12%28.33%
chris wrightchris wright512.27%28.33%
jan beulichjan beulich10.04%14.17%
daniel mackdaniel mack10.04%14.17%
Total2245100.00%24100.00%
Directory: fs/cifs
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.