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

📄 asn1.c

📁 ipsec vpn
💻 C
字号:
/* Simple ASN.1 parser * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur * * 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.  See <http://www.fsf.org/copyleft/gpl.txt>. * * 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. * * RCSID $Id: asn1.c,v 1.9 2004/06/29 22:55:27 ken Exp $ */#include <stdlib.h>#include <string.h>#include <time.h>#include <openswan.h>#include "constants.h"#include "oswlog.h"#include "defs.h"#include "asn1.h"#include "oid.h"#include "log.h"/*  If the oid is listed in the oid_names table then the corresponding *  position in the oid_names table is returned otherwise -1 is returned */intknown_oid(chunk_t object){    int oid = 0;    while (object.len)    {	if (oid_names[oid].octet == *object.ptr)	{	    if (--object.len == 0 || oid_names[oid].down == 0)	    {		return oid;          /* found terminal symbol */	    }	    else	    {		object.ptr++; oid++; /* advance to next hex octet */	    }	}	else	{	    if (oid_names[oid].next)		oid = oid_names[oid].next;	    else		return OID_UNKNOWN;	}    }    return -1;}/* *  Decodes the length in bytes of an ASN.1 object */u_intasn1_length(chunk_t *blob){    u_char n;    size_t len;    /* advance from tag field on to length field */    blob->ptr++;    blob->len--;    /* read first octet of length field */    n = *blob->ptr++;    blob->len--;    if ((n & 0x80) == 0) /* single length octet */	return n;    /* composite length, determine number of length octets */    n &= 0x7f;    if (n > blob->len)    {	DBG(DBG_PARSING,	    DBG_log("number of length octets is larger than ASN.1 object")	)	return ASN1_INVALID_LENGTH;    }    if (n > sizeof(len))    {	DBG(DBG_PARSING,	    DBG_log("number of length octets is larger than limit of %d octets"		, (int) sizeof(len))	)	return ASN1_INVALID_LENGTH;    }    len = 0;        while (n-- > 0)    {	len = 256*len + *blob->ptr++;	blob->len--;    }    return len;}/* * codes ASN.1 lengths up to a size of 16'777'215 bytes */voidcode_asn1_length(size_t length, chunk_t *code){    if (length < 128)    {	code->ptr[0] = length;	code->len = 1;    }    else if (length < 256)    {	code->ptr[0] = 0x81;	code->ptr[1] = (u_char) length;	code->len = 2;    }    else if (length < 65536)    {	code->ptr[0] = 0x82;	code->ptr[1] = length >> 8;	code->ptr[2] = length & 0x00ff;	code->len = 3;    }    else    {	code->ptr[0] = 0x83;	code->ptr[1] = length >> 16;	code->ptr[2] = (length >> 8) & 0x00ff;	code->ptr[3] = length & 0x0000ff;	code->len = 4;    }}/* * build an empty asn.1 object with tag and length fields already filled in */u_char*build_asn1_object(chunk_t *object, asn1_t type, size_t datalen){    u_char length_buf[4];    chunk_t length = { length_buf, 0 };    u_char *pos;    /* code the asn.1 length field */    code_asn1_length(datalen, &length);    /* allocate memory for the asn.1 TLV object */    object->len = 1 + length.len + datalen;    object->ptr = alloc_bytes(object->len, "asn1 object");    /* set position pointer at the start of the object */    pos = object->ptr;    /* copy the asn.1 tag field and advance the pointer */   *pos++ = type;      /* copy the asn.1 length field and advance the pointer */   chunkcpy(pos, length);   return pos;}/* * build an empty asn.1 object with explicit tags and length fields already filled in */u_char*build_asn1_explicit_object(chunk_t *object, asn1_t outer_type, asn1_t inner_type,size_t datalen){    u_char length_buf[4];    chunk_t length = { length_buf, 0 };    u_char *pos;    /* code the inner asn.1 length field */    code_asn1_length(datalen, &length);    /*create the outer asn.1 object */    pos = build_asn1_object(object, outer_type, 1 + length.len + datalen);    /* copy the inner asn.1 tag field and advance the pointer */   *pos++ = inner_type;   /* copy the inner asn.1 length field and advance the pointer */   chunkcpy(pos, length);   return pos;}/* *  determines if a character string is of type ASN.1 printableString */boolis_printablestring(chunk_t str){    const char printablestring_charset[] =	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";    u_int i;    for (i = 0; i < str.len; i++)    {	if (strchr(printablestring_charset, str.ptr[i]) == NULL)	    return FALSE;    }    return TRUE;}/* *  Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time */time_tasn1totime(const chunk_t *utctime, asn1_t type){    struct tm t;    time_t tz_offset;    u_char *eot = NULL;    if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)    {	tz_offset = 0; /* Zulu time with a zero time zone offset */    }    else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL)    {	int tz_hour, tz_min;	sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);	tz_offset = 3600*tz_hour + 60*tz_min;  /* positive time zone offset */    }    else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL)    {	int tz_hour, tz_min;	sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);	tz_offset = -3600*tz_hour - 60*tz_min;  /* negative time zone offset */    }    else    {	return 0; /* error in time format */    }    {	const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":						     "%4d%2d%2d%2d%2d";	sscanf(utctime->ptr, format, &t.tm_year, &t.tm_mon, &t.tm_mday,				     &t.tm_hour, &t.tm_min);    }    /* is there a seconds field? */    if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))    {	sscanf(eot-2, "%2d", &t.tm_sec);    }    else    {	t.tm_sec = 0;    }    /* representation of year */    if (t.tm_year >= 1900)    {	t.tm_year -= 1900;    }    else if (t.tm_year >= 100)    {	return 0;    }    else if (t.tm_year < 50)    {	t.tm_year += 100;    }    /* representation of month 0..11*/    t.tm_mon--;    /* set daylight saving time to off */    t.tm_isdst = 0;    /* compensate timezone */    return mktime(&t) - timezone - tz_offset;}/* * Initializes the internal context of the ASN.1 parser */voidasn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0,	bool implicit, u_int cond){    ctx->blobs[0] = blob;    ctx->level0   = level0;    ctx->implicit = implicit;    ctx->cond     = cond;    memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr));}/* * Parses and extracts the next ASN.1 object */boolextract_object(asn1Object_t const *objects,	u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx){    asn1Object_t obj = objects[*objectID];    chunk_t *blob;    chunk_t *blob1;    u_char *start_ptr;    *object = empty_chunk;    if (obj.flags & ASN1_END)  /* end of loop or option found */    {	if (ctx->loopAddr[obj.level] && ctx->blobs[obj.level+1].len > 0)	{	    *objectID = ctx->loopAddr[obj.level]; /* another iteration */	    obj = objects[*objectID];	}	else	{	    ctx->loopAddr[obj.level] = 0;         /* exit loop or option*/	    return TRUE;	}    }    *level = ctx->level0 + obj.level;    blob = ctx->blobs + obj.level;    blob1 = blob + 1;    start_ptr = blob->ptr;   /* handle ASN.1 defaults values */    if ((obj.flags & ASN1_DEF)    && (blob->len == 0 || *start_ptr != obj.type) )    {	/* field is missing */	DBG(DBG_PARSING,	    DBG_log("L%d - %s:", *level, obj.name);	)	if (obj.type & ASN1_CONSTRUCTED)	{	    (*objectID)++ ;  /* skip context-specific tag */	}	return TRUE;    }    /* handle ASN.1 options */    if ( (obj.flags & ASN1_OPT) &&	 ( blob->len == 0 || *start_ptr != obj.type) )    {        /* advance to end of missing option field */	do        	    (*objectID)++;	  while (!((objects[*objectID].flags & ASN1_END) &&		      (objects[*objectID].level == obj.level )));	return TRUE;    }     /* an ASN.1 object must possess at least a tag and length field */     if (blob->len < 2)     {       DBG(DBG_PARSING,           DBG_log("L%d - %s:  ASN.1 object smaller than 2 octets",                   ctx->level0+obj.level, obj.name);       )       return FALSE;     }    blob1->len = asn1_length(blob);    if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len)    {	DBG(DBG_PARSING,	    DBG_log("L%d - %s:  length of ASN1 object invalid or too large",                   *level, obj.name);	)	return FALSE;    }    blob1->ptr = blob->ptr;    blob->ptr += blob1->len;    blob->len -= blob1->len;    /* return raw ASN.1 object without prior type checking */    if (obj.flags & ASN1_RAW)    {	DBG(DBG_PARSING,	    DBG_log("L%d - %s:", *level, obj.name);        )	object->ptr = start_ptr;	object->len = (size_t)(blob->ptr - start_ptr);	return TRUE;    }    if (*start_ptr != obj.type && !(ctx->implicit && *objectID == 0))    {	DBG(DBG_PARSING,	    DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",		*level, obj.name, obj.type, *start_ptr);	    DBG_dump("", start_ptr, (u_int)(blob->ptr - start_ptr));	)	return FALSE;    }    DBG(DBG_PARSING,	DBG_log("L%d - %s:", ctx->level0+obj.level, obj.name);    )    /* In case of "SEQUENCE OF" or "SET OF" start a loop */    if (obj.flags & ASN1_LOOP)    {	if (blob1->len > 0)	{	    /* at least one item, start the loop */	    ctx->loopAddr[obj.level] = *objectID + 1;	}	else	{	    /* no items, advance directly to end of loop */	    do		(*objectID)++;	    while (!((objects[*objectID].flags & ASN1_END)		  && (objects[*objectID].level == obj.level)));	    return TRUE;	}    }    if (obj.flags & ASN1_OBJ)    {	object->ptr = start_ptr;	object->len = (size_t)(blob->ptr - start_ptr);	DBG(ctx->cond,	    DBG_dump_chunk("", *object);	)    }    else if (obj.flags & ASN1_BODY)    {	int oid;	*object = *blob1;	switch (obj.type)	{	case ASN1_OID:	    oid = known_oid(*object);	    if (oid != OID_UNKNOWN)	    {		DBG(DBG_PARSING,		   DBG_log("  '%s'",oid_names[oid].name);		)		return TRUE;	    }	    break;	case ASN1_UTF8STRING:	case ASN1_IA5STRING:	case ASN1_PRINTABLESTRING:	case ASN1_T61STRING:	case ASN1_VISIBLESTRING:	    DBG(DBG_PARSING,		DBG_log("  '%.*s'", (int)object->len, object->ptr);	    )	    return TRUE;	case ASN1_UTCTIME:	case ASN1_GENERALIZEDTIME:	    DBG(DBG_PARSING,		time_t time = asn1totime(object, obj.type);		char tbuf[TIMETOA_BUF];		DBG_log("  '%s'", timetoa(&time, TRUE, tbuf, sizeof(tbuf)));	    )	    return TRUE;	default:	    break;	}	DBG(ctx->cond,	    DBG_dump_chunk("", *object);	)    }    return TRUE;}/* *  tests if a blob contains a valid ASN.1 set or sequence */boolis_asn1(chunk_t blob){    u_int len;    u_char tag = *blob.ptr;    if (tag != ASN1_SEQUENCE && tag != ASN1_SET)    {	DBG(DBG_PARSING,	    DBG_log("  file content is not binary ASN.1");	)	return FALSE;    }    len = asn1_length(&blob);    if (len != blob.len)    {	DBG(DBG_PARSING,	    DBG_log("  file size does not match ASN.1 coded length");	)	return FALSE;    }    return TRUE;}

⌨️ 快捷键说明

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