asn.1中的方括号

asn.1编码以tag + length + value为基本单元,IMPLICIT模式是用context-specific tag替换后面通常是universal的tag;EXPLICIT模式是用context-specific tag的tlv包裏里层的universal tag的tlv。

ber编码时,会默认为EXPLICIT模式。

在bnf范式语法中

1
2
3
4
5
圆括号(): 相当于C语言算术表达式中圆括号()的作用。
尖括号<>: 内包含的为必选项。 
方括号[]: 内包含的为可选项。 
花括号{}: 内包含的为可重复0至无数次的项。 
|: 或or的意思;若要表示并and的意思,直接两个符号之间空白间隔。

而在asn.1语法中,方括号[Index]指示的是context-specific tag值,即0xA0 + Index;花括号{}用于SEQUENCE,SET或CHOICE的定义。如

1
2
Number2 ::= [7] IMPLICIT [1] INTEGER
AccountedClosed ::= [2] EXPLICIT BOOLEAN

这里Number2的tag值为0xA7;而对于AccountedClosed,当其值为true时其ber编码为

1
0xA2 0x3 0x1 0x1 0xFF

refer to:
https://blog.csdn.net/sever2012/article/details/7767867
https://www.cnblogs.com/qook/p/5957436.html

asn.1编码的转换

这个工具在

1
strongswan/src/libstrongswan/asn1

以下是使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
 
#define INTEGER_SIZE 32
 
static chunk_t chunk_to_asn1(chunk_t chunk)
{
	chunk_t x;
	chunk_t y;
	chunk_t hash;
	chunk_t content;
	chunk_t asn1;
 
	x.ptr = chunk.ptr;
	x.len = INTEGER_SIZE;
	y.ptr = chunk.ptr + INTEGER_SIZE;
	y.len = INTEGER_SIZE;
	content.ptr = y.ptr + INTEGER_SIZE;
	content.len = chunk.len - INTEGER_SIZE * 3;
	hash.ptr = content.ptr + content.len;
	hash.len = INTEGER_SIZE;
 
	asn1 = asn1_wrap(ASN1_SEQUENCE, "mmmm",
		asn1_integer("c", x),
		asn1_integer("c", y),
		asn1_simple_object(ASN1_OCTET_STRING, hash),
		asn1_simple_object(ASN1_OCTET_STRING, content));
 
	chunk_free(&chunk);
	return asn1;
}
 
static const asn1Object_t patterns[] = {
	{ 0, "seq",			ASN1_SEQUENCE,		ASN1_NONE }, /*  0 */
	{ 1,   "x",			ASN1_INTEGER,		ASN1_BODY }, /*  1 */
	{ 1,   "y",			ASN1_INTEGER,		ASN1_BODY }, /*  2 */
	{ 1,   "hash",			ASN1_OCTET_STRING,	ASN1_BODY }, /*  3 */
	{ 1,   "content",		ASN1_OCTET_STRING,	ASN1_BODY }, /*  4 */
	{ 0, "exit",			ASN1_EOC,		ASN1_EXIT }
};
#define PATTERN_KEY_X			1
#define PATTERN_KEY_Y			2
#define PATTERN_KEY_HASH		3
#define PATTERN_KEY_CONTENT		4
 
static chunk_t correct_integer(chunk_t chunk)
{
	if (chunk.len == INTEGER_SIZE + 1)
		return chunk_skip(chunk, 1);
	return chunk;
}
 
static bool parse_asn1(chunk_t asn1, chunk_t* x, chunk_t* y, chunk_t* hash, chunk_t* content)
{
	chunk_t object;
	asn1_parser_t *parser;
	bool success = FALSE;
	int object_id, oid, i;
 
	parser = asn1_parser_create(patterns, asn1);
 
	while (parser->iterate(parser, &object_id, &object))
	{
		switch (object_id)
		{
			case PATTERN_KEY_X:
				*x = correct_integer(object);
				break;
			case PATTERN_KEY_Y:
				*y = correct_integer(object);
				break;
			case PATTERN_KEY_HASH:
				*hash = object;
				break;
			case PATTERN_KEY_CONTENT:
				*content = object;
				break;
		}
	}
	success = parser->success(parser);
	parser->destroy(parser);
	return success;
}
 
static bool chunk_from_asn1(chunk_t* chunk, chunk_t asn1)
{
	chunk_t x;
	chunk_t y;
	chunk_t hash;
	chunk_t content;
 
	if (!parse_asn1(asn1, &x, &y, &hash, &content))
		return false;
 
	*chunk = chunk_cat("cccc", x, y, content, hash);
	return true;
}
 
static void random_data(chunk_t chunk)
{
	int fd = open("/dev/urandom", O_RDONLY);
	read(fd, chunk.ptr, chunk.len);
	close(fd);
}
 
int test()
{
	bool is_ok;
	chunk_t result;
	chunk_t asn1;
	chunk_t total = chunk_alloc(INTEGER_SIZE * 3 + 345);
 
	random_data(total);
 
	asn1 = chunk_to_asn1(total);
	is_ok = chunk_from_asn1(&result, asn1);
 
	chunk_free(&result);
	chunk_free(&asn1);
	chunk_free(&total);
	return is_ok;
}

因为asn1模块里对ASN1_INTEGER类型有个two's complement处理,如果这个数最高位为1,则在此数前加一个0值字节,所以correct_integer函数的目地在于更正输出。