1611 lines · 35.3 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* Simplified ASN.1 notation parser * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) */ #include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <stdbool.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <fcntl.h>#include <sys/stat.h>#include <linux/asn1_ber_bytecode.h> enum token_type {	DIRECTIVE_ABSENT,	DIRECTIVE_ALL,	DIRECTIVE_ANY,	DIRECTIVE_APPLICATION,	DIRECTIVE_AUTOMATIC,	DIRECTIVE_BEGIN,	DIRECTIVE_BIT,	DIRECTIVE_BMPString,	DIRECTIVE_BOOLEAN,	DIRECTIVE_BY,	DIRECTIVE_CHARACTER,	DIRECTIVE_CHOICE,	DIRECTIVE_CLASS,	DIRECTIVE_COMPONENT,	DIRECTIVE_COMPONENTS,	DIRECTIVE_CONSTRAINED,	DIRECTIVE_CONTAINING,	DIRECTIVE_DEFAULT,	DIRECTIVE_DEFINED,	DIRECTIVE_DEFINITIONS,	DIRECTIVE_EMBEDDED,	DIRECTIVE_ENCODED,	DIRECTIVE_ENCODING_CONTROL,	DIRECTIVE_END,	DIRECTIVE_ENUMERATED,	DIRECTIVE_EXCEPT,	DIRECTIVE_EXPLICIT,	DIRECTIVE_EXPORTS,	DIRECTIVE_EXTENSIBILITY,	DIRECTIVE_EXTERNAL,	DIRECTIVE_FALSE,	DIRECTIVE_FROM,	DIRECTIVE_GeneralString,	DIRECTIVE_GeneralizedTime,	DIRECTIVE_GraphicString,	DIRECTIVE_IA5String,	DIRECTIVE_IDENTIFIER,	DIRECTIVE_IMPLICIT,	DIRECTIVE_IMPLIED,	DIRECTIVE_IMPORTS,	DIRECTIVE_INCLUDES,	DIRECTIVE_INSTANCE,	DIRECTIVE_INSTRUCTIONS,	DIRECTIVE_INTEGER,	DIRECTIVE_INTERSECTION,	DIRECTIVE_ISO646String,	DIRECTIVE_MAX,	DIRECTIVE_MIN,	DIRECTIVE_MINUS_INFINITY,	DIRECTIVE_NULL,	DIRECTIVE_NumericString,	DIRECTIVE_OBJECT,	DIRECTIVE_OCTET,	DIRECTIVE_OF,	DIRECTIVE_OPTIONAL,	DIRECTIVE_ObjectDescriptor,	DIRECTIVE_PATTERN,	DIRECTIVE_PDV,	DIRECTIVE_PLUS_INFINITY,	DIRECTIVE_PRESENT,	DIRECTIVE_PRIVATE,	DIRECTIVE_PrintableString,	DIRECTIVE_REAL,	DIRECTIVE_RELATIVE_OID,	DIRECTIVE_SEQUENCE,	DIRECTIVE_SET,	DIRECTIVE_SIZE,	DIRECTIVE_STRING,	DIRECTIVE_SYNTAX,	DIRECTIVE_T61String,	DIRECTIVE_TAGS,	DIRECTIVE_TRUE,	DIRECTIVE_TeletexString,	DIRECTIVE_UNION,	DIRECTIVE_UNIQUE,	DIRECTIVE_UNIVERSAL,	DIRECTIVE_UTCTime,	DIRECTIVE_UTF8String,	DIRECTIVE_UniversalString,	DIRECTIVE_VideotexString,	DIRECTIVE_VisibleString,	DIRECTIVE_WITH,	NR__DIRECTIVES,	TOKEN_ASSIGNMENT = NR__DIRECTIVES,	TOKEN_OPEN_CURLY,	TOKEN_CLOSE_CURLY,	TOKEN_OPEN_SQUARE,	TOKEN_CLOSE_SQUARE,	TOKEN_OPEN_ACTION,	TOKEN_CLOSE_ACTION,	TOKEN_COMMA,	TOKEN_NUMBER,	TOKEN_TYPE_NAME,	TOKEN_ELEMENT_NAME,	NR__TOKENS}; static const unsigned char token_to_tag[NR__TOKENS] = {	/* EOC goes first */	[DIRECTIVE_BOOLEAN]		= ASN1_BOOL,	[DIRECTIVE_INTEGER]		= ASN1_INT,	[DIRECTIVE_BIT]			= ASN1_BTS,	[DIRECTIVE_OCTET]		= ASN1_OTS,	[DIRECTIVE_NULL]		= ASN1_NULL,	[DIRECTIVE_OBJECT]		= ASN1_OID,	[DIRECTIVE_ObjectDescriptor]	= ASN1_ODE,	[DIRECTIVE_EXTERNAL]		= ASN1_EXT,	[DIRECTIVE_REAL]		= ASN1_REAL,	[DIRECTIVE_ENUMERATED]		= ASN1_ENUM,	[DIRECTIVE_EMBEDDED]		= 0,	[DIRECTIVE_UTF8String]		= ASN1_UTF8STR,	[DIRECTIVE_RELATIVE_OID]	= ASN1_RELOID,	/* 14 */	/* 15 */	[DIRECTIVE_SEQUENCE]		= ASN1_SEQ,	[DIRECTIVE_SET]			= ASN1_SET,	[DIRECTIVE_NumericString]	= ASN1_NUMSTR,	[DIRECTIVE_PrintableString]	= ASN1_PRNSTR,	[DIRECTIVE_T61String]		= ASN1_TEXSTR,	[DIRECTIVE_TeletexString]	= ASN1_TEXSTR,	[DIRECTIVE_VideotexString]	= ASN1_VIDSTR,	[DIRECTIVE_IA5String]		= ASN1_IA5STR,	[DIRECTIVE_UTCTime]		= ASN1_UNITIM,	[DIRECTIVE_GeneralizedTime]	= ASN1_GENTIM,	[DIRECTIVE_GraphicString]	= ASN1_GRASTR,	[DIRECTIVE_VisibleString]	= ASN1_VISSTR,	[DIRECTIVE_GeneralString]	= ASN1_GENSTR,	[DIRECTIVE_UniversalString]	= ASN1_UNITIM,	[DIRECTIVE_CHARACTER]		= ASN1_CHRSTR,	[DIRECTIVE_BMPString]		= ASN1_BMPSTR,}; static const char asn1_classes[4][5] = {	[ASN1_UNIV]	= "UNIV",	[ASN1_APPL]	= "APPL",	[ASN1_CONT]	= "CONT",	[ASN1_PRIV]	= "PRIV"}; static const char asn1_methods[2][5] = {	[ASN1_UNIV]	= "PRIM",	[ASN1_APPL]	= "CONS"}; static const char *const asn1_universal_tags[32] = {	"EOC",	"BOOL",	"INT",	"BTS",	"OTS",	"NULL",	"OID",	"ODE",	"EXT",	"REAL",	"ENUM",	"EPDV",	"UTF8STR",	"RELOID",	NULL,		/* 14 */	NULL,		/* 15 */	"SEQ",	"SET",	"NUMSTR",	"PRNSTR",	"TEXSTR",	"VIDSTR",	"IA5STR",	"UNITIM",	"GENTIM",	"GRASTR",	"VISSTR",	"GENSTR",	"UNISTR",	"CHRSTR",	"BMPSTR",	NULL		/* 31 */}; static const char *filename;static const char *grammar_name;static const char *outputname;static const char *headername; static const char *const directives[NR__DIRECTIVES] = {#define _(X) [DIRECTIVE_##X] = #X	_(ABSENT),	_(ALL),	_(ANY),	_(APPLICATION),	_(AUTOMATIC),	_(BEGIN),	_(BIT),	_(BMPString),	_(BOOLEAN),	_(BY),	_(CHARACTER),	_(CHOICE),	_(CLASS),	_(COMPONENT),	_(COMPONENTS),	_(CONSTRAINED),	_(CONTAINING),	_(DEFAULT),	_(DEFINED),	_(DEFINITIONS),	_(EMBEDDED),	_(ENCODED),	[DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",	_(END),	_(ENUMERATED),	_(EXCEPT),	_(EXPLICIT),	_(EXPORTS),	_(EXTENSIBILITY),	_(EXTERNAL),	_(FALSE),	_(FROM),	_(GeneralString),	_(GeneralizedTime),	_(GraphicString),	_(IA5String),	_(IDENTIFIER),	_(IMPLICIT),	_(IMPLIED),	_(IMPORTS),	_(INCLUDES),	_(INSTANCE),	_(INSTRUCTIONS),	_(INTEGER),	_(INTERSECTION),	_(ISO646String),	_(MAX),	_(MIN),	[DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",	[DIRECTIVE_NULL] = "NULL",	_(NumericString),	_(OBJECT),	_(OCTET),	_(OF),	_(OPTIONAL),	_(ObjectDescriptor),	_(PATTERN),	_(PDV),	[DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",	_(PRESENT),	_(PRIVATE),	_(PrintableString),	_(REAL),	[DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",	_(SEQUENCE),	_(SET),	_(SIZE),	_(STRING),	_(SYNTAX),	_(T61String),	_(TAGS),	_(TRUE),	_(TeletexString),	_(UNION),	_(UNIQUE),	_(UNIVERSAL),	_(UTCTime),	_(UTF8String),	_(UniversalString),	_(VideotexString),	_(VisibleString),	_(WITH)}; struct action {	struct action	*next;	char		*name;	unsigned char	index;}; static struct action *action_list;static unsigned nr_actions; struct token {	unsigned short	line;	enum token_type	token_type : 8;	unsigned char	size;	struct action	*action;	char		*content;	struct type	*type;}; static struct token *token_list;static unsigned nr_tokens;static bool verbose_opt;static bool debug_opt; #define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)#define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0) static int directive_compare(const void *_key, const void *_pdir){	const struct token *token = _key;	const char *const *pdir = _pdir, *dir = *pdir;	size_t dlen, clen;	int val; 	dlen = strlen(dir);	clen = (dlen < token->size) ? dlen : token->size; 	//debug("cmp(%s,%s) = ", token->content, dir); 	val = memcmp(token->content, dir, clen);	if (val != 0) {		//debug("%d [cmp]\n", val);		return val;	} 	if (dlen == token->size) {		//debug("0\n");		return 0;	}	//debug("%d\n", (int)dlen - (int)token->size);	return dlen - token->size; /* shorter -> negative */} /* * Tokenise an ASN.1 grammar */static void tokenise(char *buffer, char *end){	struct token *tokens;	char *line, *nl, *start, *p, *q;	unsigned tix, lineno; 	/* Assume we're going to have half as many tokens as we have	 * characters	 */	token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));	if (!tokens) {		perror(NULL);		exit(1);	}	tix = 0; 	lineno = 0;	while (buffer < end) {		/* First of all, break out a line */		lineno++;		line = buffer;		nl = memchr(line, '\n', end - buffer);		if (!nl) {			buffer = nl = end;		} else {			buffer = nl + 1;			*nl = '\0';		} 		/* Remove "--" comments */		p = line;	next_comment:		while ((p = memchr(p, '-', nl - p))) {			if (p[1] == '-') {				/* Found a comment; see if there's a terminator */				q = p + 2;				while ((q = memchr(q, '-', nl - q))) {					if (q[1] == '-') {						/* There is - excise the comment */						q += 2;						memmove(p, q, nl - q);						goto next_comment;					}					q++;				}				*p = '\0';				nl = p;				break;			} else {				p++;			}		} 		p = line;		while (p < nl) {			/* Skip white space */			while (p < nl && isspace(*p))				*(p++) = 0;			if (p >= nl)				break; 			tokens[tix].line = lineno;			start = p; 			/* Handle string tokens */			if (isalpha(*p)) {				const char **dir; 				/* Can be a directive, type name or element				 * name.  Find the end of the name.				 */				q = p + 1;				while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))					q++;				tokens[tix].size = q - p;				p = q; 				tokens[tix].content = malloc(tokens[tix].size + 1);				if (!tokens[tix].content) {					perror(NULL);					exit(1);				}				memcpy(tokens[tix].content, start, tokens[tix].size);				tokens[tix].content[tokens[tix].size] = 0;								/* If it begins with a lowercase letter then				 * it's an element name				 */				if (islower(tokens[tix].content[0])) {					tokens[tix++].token_type = TOKEN_ELEMENT_NAME;					continue;				} 				/* Otherwise we need to search the directive				 * table				 */				dir = bsearch(&tokens[tix], directives,					      sizeof(directives) / sizeof(directives[1]),					      sizeof(directives[1]),					      directive_compare);				if (dir) {					tokens[tix++].token_type = dir - directives;					continue;				} 				tokens[tix++].token_type = TOKEN_TYPE_NAME;				continue;			} 			/* Handle numbers */			if (isdigit(*p)) {				/* Find the end of the number */				q = p + 1;				while (q < nl && (isdigit(*q)))					q++;				tokens[tix].size = q - p;				p = q;				tokens[tix].content = malloc(tokens[tix].size + 1);				if (!tokens[tix].content) {					perror(NULL);					exit(1);				}				memcpy(tokens[tix].content, start, tokens[tix].size);				tokens[tix].content[tokens[tix].size] = 0;				tokens[tix++].token_type = TOKEN_NUMBER;				continue;			} 			if (nl - p >= 3) {				if (memcmp(p, "::=", 3) == 0) {					p += 3;					tokens[tix].size = 3;					tokens[tix].content = "::=";					tokens[tix++].token_type = TOKEN_ASSIGNMENT;					continue;				}			} 			if (nl - p >= 2) {				if (memcmp(p, "({", 2) == 0) {					p += 2;					tokens[tix].size = 2;					tokens[tix].content = "({";					tokens[tix++].token_type = TOKEN_OPEN_ACTION;					continue;				}				if (memcmp(p, "})", 2) == 0) {					p += 2;					tokens[tix].size = 2;					tokens[tix].content = "})";					tokens[tix++].token_type = TOKEN_CLOSE_ACTION;					continue;				}			} 

Lines 1–500 of 1611.