1 /*
2  * libpri: An implementation of Primary Rate ISDN
3  *
4  * Copyright (C) 2009 Digium, Inc.
5  *
6  * Richard Mudgett <rmudgett@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2 as published by the
16  * Free Software Foundation. See the LICENSE file included with
17  * this program for more details.
18  *
19  * In addition, when this program is distributed with Asterisk in
20  * any form that would qualify as a 'combined work' or as a
21  * 'derivative work' (but not mere aggregation), you can redistribute
22  * and/or modify the combination under the terms of the license
23  * provided with that copy of Asterisk, instead of the license
24  * terms granted here.
25  */
26 
27 /*!
28  * \file
29  * \brief ASN.1 definitions and prototypes
30  *
31  * \details
32  * This file contains all ASN.1 primitive data structures and
33  * definitions needed for ROSE component encoding and decoding.
34  *
35  * ROSE - Remote Operations Service Element
36  * ASN.1 - Abstract Syntax Notation 1
37  * APDU - Application Protocol Data Unit
38  *
39  * \author Richard Mudgett <rmudgett@digium.com>
40  */
41 
42 #ifndef _LIBPRI_ASN1_H
43 #define _LIBPRI_ASN1_H
44 
45 #include <string.h>
46 #include <sys/types.h>
47 
48 #ifdef __cplusplus
49 extern "C" {
50 #endif
51 
52 /* ------------------------------------------------------------------- */
53 
54 /*! ASN.1 Identifier Octet - Tag class bits */
55 #define ASN1_CLASS_MASK				0xc0
56 #define ASN1_CLASS_UNIVERSAL		0x00	/*!< Universal primitive data types */
57 #define ASN1_CLASS_APPLICATION		0x40	/*!< Application wide data tag */
58 #define ASN1_CLASS_CONTEXT_SPECIFIC	0x80	/*!< Context specifc data tag */
59 #define ASN1_CLASS_PRIVATE			0xc0	/*!< Private organization data tag */
60 
61 /*! ASN.1 Identifier Octet - Primitive/Constructor bit */
62 #define ASN1_PC_MASK				0x20
63 #define ASN1_PC_PRIMITIVE			0x00
64 #define ASN1_PC_CONSTRUCTED			0x20
65 
66 /*! ASN.1 Identifier Octet - Universal data types */
67 #define ASN1_TYPE_MASK				0x1f
68 #define ASN1_TYPE_INDEF_TERM		0x00	/*  0 */
69 #define ASN1_TYPE_BOOLEAN			0x01	/*  1 */
70 #define ASN1_TYPE_INTEGER			0x02	/*  2 */
71 #define ASN1_TYPE_BIT_STRING		0x03	/*  3 */
72 #define ASN1_TYPE_OCTET_STRING		0x04	/*  4 */
73 #define ASN1_TYPE_NULL				0x05	/*  5 */
74 #define ASN1_TYPE_OBJECT_IDENTIFIER	0x06	/*  6 */
75 #define ASN1_TYPE_OBJECT_DESCRIPTOR	0x07	/*  7 */
76 #define ASN1_TYPE_EXTERN			0x08	/*  8 */
77 #define ASN1_TYPE_REAL				0x09	/*  9 */
78 #define ASN1_TYPE_ENUMERATED		0x0a	/* 10 */
79 #define ASN1_TYPE_EMBEDDED_PDV		0x0b	/* 11 */
80 #define ASN1_TYPE_UTF8_STRING		0x0c	/* 12 */
81 #define ASN1_TYPE_RELATIVE_OID		0x0d	/* 13 */
82 /* 0x0e & 0x0f are reserved for future ASN.1 editions */
83 #define ASN1_TYPE_SEQUENCE			0x10	/* 16 */
84 #define ASN1_TYPE_SET				0x11	/* 17 */
85 #define ASN1_TYPE_NUMERIC_STRING	0x12	/* 18 */
86 #define ASN1_TYPE_PRINTABLE_STRING	0x13	/* 19 */
87 #define ASN1_TYPE_TELETEX_STRING	0x14	/* 20 */
88 #define ASN1_TYPE_VIDEOTEX_STRING	0x15	/* 21 */
89 #define ASN1_TYPE_IA5_STRING		0x16	/* 22 */
90 #define ASN1_TYPE_UTC_TIME			0x17	/* 23 */
91 #define ASN1_TYPE_GENERALIZED_TIME	0x18	/* 24 */
92 #define ASN1_TYPE_GRAPHIC_STRING	0x19	/* 25 */
93 #define ASN1_TYPE_VISIBLE_STRING	0x1a	/* 26 */
94 #define ASN1_TYPE_ISO646_STRING		0x1a	/* 26 */
95 #define ASN1_TYPE_GENERAL_STRING	0x1b	/* 27 */
96 #define ASN1_TYPE_UNIVERSAL_STRING	0x1c	/* 28 */
97 #define ASN1_TYPE_CHAR_STRING		0x1d	/* 29 */
98 #define ASN1_TYPE_BMP_STRING		0x1e	/* 30 */
99 #define ASN1_TYPE_EXTENSION			0x1f	/* 31 */
100 
101 #define ASN1_TAG_SEQUENCE	(ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_SEQUENCE)
102 #define ASN1_TAG_SET		(ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_SET)
103 
104 #define ASN1_INDEF_TERM	(ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_INDEF_TERM)
105 #define ASN1_INDEF_TERM_LEN		2
106 
107 struct asn1_oid {
108 	/*! \brief Number of subidentifier values in OID list */
109 	u_int16_t num_values;
110 
111 	/*!
112 	 * \brief OID subidentifier value list
113 	 * \note The first value is really the first two OID subidentifiers.
114 	 * They are compressed using this formula:
115 	 * First_Value = (First_Subidentifier * 40) + Second_Subidentifier
116 	 */
117 	u_int16_t value[10];
118 };
119 
120 #define ASN1_CALL(new_pos, do_it)   \
121 	do                              \
122 	{                               \
123 		(new_pos) = (do_it);        \
124 		if (!(new_pos)) {           \
125 			return NULL;            \
126 		}                           \
127 	} while (0)
128 
129 /*! \brief Determine the ending position of the set or sequence to verify the length. */
130 #define ASN1_END_SETUP(component_end, offset, length, pos, end) \
131 	do {                                                        \
132 		if ((length) < 0) {                                     \
133 			(offset) = ASN1_INDEF_TERM_LEN;                     \
134 			(component_end) = (end);                            \
135 		} else {                                                \
136 			(offset) = 0;                                       \
137 			(component_end) = (pos) + (length);                 \
138 		}                                                       \
139 	} while (0)
140 
141 /*! \brief Account for the indefinite length terminator of the set or sequence. */
142 #define ASN1_END_FIXUP(ctrl, pos, offset, component_end, end)                   \
143 	do {                                                                        \
144 		if (offset) {                                                           \
145 			ASN1_CALL((pos), asn1_dec_indef_end_fixup((ctrl), (pos), (end)));   \
146 		} else if ((pos) != (component_end)) {                                  \
147 			if ((ctrl)->debug & PRI_DEBUG_APDU) {                               \
148 				pri_message((ctrl),                                             \
149 					"  Skipping unused constructed component octets!\n");       \
150 			}                                                                   \
151 			(pos) = (component_end);                                            \
152 		}                                                                       \
153 	} while (0)
154 
155 #define ASN1_DID_NOT_EXPECT_TAG(ctrl, tag)                                      \
156 	do {                                                                        \
157 		if ((ctrl)->debug & PRI_DEBUG_APDU) {                                   \
158 			pri_message((ctrl), "  Did not expect: %s\n", asn1_tag2str(tag));   \
159 		}                                                                       \
160 	} while (0)
161 
162 #define ASN1_CHECK_TAG(ctrl, actual_tag, match_tag, expected_tag)   \
163 	do {                                                            \
164 		if ((match_tag) != (expected_tag)) {                        \
165 			ASN1_DID_NOT_EXPECT_TAG((ctrl), (actual_tag));          \
166 			return NULL;                                            \
167 		}                                                           \
168 	} while (0)
169 
170 
171 const unsigned char *asn1_dec_tag(const unsigned char *tag_pos, const unsigned char *end,
172 	unsigned *tag);
173 const unsigned char *asn1_dec_length(const unsigned char *len_pos,
174 	const unsigned char *end, int *length);
175 const unsigned char *asn1_dec_indef_end_fixup(struct pri *ctrl, const unsigned char *pos,
176 	const unsigned char *end);
177 
178 const unsigned char *asn1_dec_boolean(struct pri *ctrl, const char *name, unsigned tag,
179 	const unsigned char *pos, const unsigned char *end, int32_t *value);
180 const unsigned char *asn1_dec_int(struct pri *ctrl, const char *name, unsigned tag,
181 	const unsigned char *pos, const unsigned char *end, int32_t *value);
182 const unsigned char *asn1_dec_null(struct pri *ctrl, const char *name, unsigned tag,
183 	const unsigned char *pos, const unsigned char *end);
184 const unsigned char *asn1_dec_oid(struct pri *ctrl, const char *name, unsigned tag,
185 	const unsigned char *pos, const unsigned char *end, struct asn1_oid *oid);
186 const unsigned char *asn1_dec_string_bin(struct pri *ctrl, const char *name,
187 	unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size,
188 	unsigned char *str, size_t *str_len);
189 const unsigned char *asn1_dec_string_max(struct pri *ctrl, const char *name,
190 	unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size,
191 	unsigned char *str, size_t *str_len);
192 
193 const char *asn1_tag2str(unsigned tag);
194 void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1,
195 	const unsigned char *end);
196 
197 
198 #define ASN1_LEN_FORM_SHORT     1	/*!< Hint that the final length will be less than 128 octets */
199 #define ASN1_LEN_FORM_LONG_U8   2	/*!< Hint that the final length will be less than 256 octets */
200 #define ASN1_LEN_FORM_LONG_U16  3	/*!< Hint that the final length will be less than 65536 octets */
201 #define ASN1_LEN_INIT(len_pos, end, form_hint)  \
202 	do {                                        \
203 		if ((end) < (len_pos) + (form_hint)) {  \
204 			return NULL;                        \
205 		}                                       \
206 		*(len_pos) = (form_hint);               \
207 		(len_pos) += (form_hint);               \
208 	} while (0)
209 
210 #define ASN1_LEN_FIXUP(len_pos, component_end, end) \
211 	ASN1_CALL((component_end), asn1_enc_length_fixup((len_pos), (component_end), (end)))
212 
213 /*! \brief Use to begin encoding explicit tags, SET, and SEQUENCE constructed groupings. */
214 #define ASN1_CONSTRUCTED_BEGIN(len_pos_save, pos, end, tag) \
215 	do {                                                    \
216 		if ((end) < (pos) + (1 + ASN1_LEN_FORM_SHORT)) {    \
217 			return NULL;                                    \
218 		}                                                   \
219 		*(pos)++ = (tag) | ASN1_PC_CONSTRUCTED;             \
220 		(len_pos_save) = (pos);                             \
221 		*(pos) = ASN1_LEN_FORM_SHORT;                       \
222 		(pos) += ASN1_LEN_FORM_SHORT;                       \
223 	} while (0)
224 
225 /*! \brief Use to end encoding explicit tags, SET, and SEQUENCE constructed groupings. */
226 #define ASN1_CONSTRUCTED_END(len_pos, component_end, end)   \
227 	ASN1_CALL((component_end), asn1_enc_length_fixup((len_pos), (component_end), (end)))
228 
229 #define ASN1_ENC_ERROR(ctrl, msg) \
230 	pri_error((ctrl), "%s error: %s\n", __FUNCTION__, (msg))
231 
232 unsigned char *asn1_enc_length(unsigned char *len_pos, unsigned char *end,
233 	size_t str_len);
234 unsigned char *asn1_enc_length_fixup(unsigned char *len_pos,
235 	unsigned char *component_end, unsigned char *end);
236 
237 unsigned char *asn1_enc_boolean(unsigned char *pos, unsigned char *end, unsigned tag,
238 	int32_t value);
239 unsigned char *asn1_enc_int(unsigned char *pos, unsigned char *end, unsigned tag,
240 	int32_t value);
241 unsigned char *asn1_enc_null(unsigned char *pos, unsigned char *end, unsigned tag);
242 unsigned char *asn1_enc_oid(unsigned char *pos, unsigned char *end, unsigned tag,
243 	const struct asn1_oid *oid);
244 unsigned char *asn1_enc_string_bin(unsigned char *pos, unsigned char *end, unsigned tag,
245 	const unsigned char *str, size_t str_len);
246 unsigned char *asn1_enc_string_max(unsigned char *pos, unsigned char *end, unsigned tag,
247 	const unsigned char *str, size_t max_len);
248 
249 /* ------------------------------------------------------------------- */
250 
251 #ifdef __cplusplus
252 }
253 #endif
254 
255 #endif	/* _LIBPRI_ASN1_H */
256 /* ------------------------------------------------------------------- */
257 /* end asn1.h */
258