1 /**
2  * asn.cpp
3  * This file is part of the YATE Project http://YATE.null.ro
4  *
5  * ASN.1 Library
6  *
7  * Yet Another Telephony Engine - a fully featured software PBX and IVR
8  * Copyright (C) 2004-2014 Null Team
9  *
10  * This software is distributed under multiple licenses;
11  * see the COPYING file in the main directory for licensing
12  * information for this specific distribution.
13  *
14  * This use of this software may be subject to additional restrictions.
15  * See the LEGAL file in the main directory for details.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 #include "yateasn.h"
23 
24 using namespace TelEngine;
25 
26 static String s_libName = "ASNLib";
27 
ASNLib()28 ASNLib::ASNLib()
29 {}
30 
~ASNLib()31 ASNLib::~ASNLib()
32 {}
33 
decodeLength(DataBlock & data)34 int ASNLib::decodeLength(DataBlock& data) {
35 
36     XDebug(s_libName.c_str(),DebugAll,"::decodeLength() - from data='%p'",&data);
37     int length = 0;
38     uint8_t lengthByte = data[0];
39 
40     if (lengthByte & ASN_LONG_LENGTH) { // the length is represented on more than one byte
41 
42 	lengthByte &= ~ASN_LONG_LENGTH;	/* turn MSB off */
43 	if (lengthByte == 0) {
44 	    data.cut(-1);
45 	    return IndefiniteForm;
46 	}
47 
48 	if (lengthByte > sizeof(int))
49 	    return InvalidLengthOrTag;
50 
51 	for (int i = 0 ; i < lengthByte ; i++)
52 	    length = (length << 8) + data[1 + i];
53 
54 	data.cut(-lengthByte - 1);
55 	return length;
56 
57     } else { // one byte for length
58 	length = (int) lengthByte;
59 	data.cut(-1);
60 	return length;
61     }
62 }
63 
buildLength(DataBlock & data)64 DataBlock ASNLib::buildLength(DataBlock& data)
65 {
66     XDebug(s_libName.c_str(),DebugAll,"::buildLength() - encode length=%d",data.length());
67     DataBlock lenDb;
68     if (data.length() < 0)
69 	return lenDb;
70     if (data.length() < ASN_LONG_LENGTH) {
71 	uint8_t l = data.length();
72 	lenDb.append(&l, 1);
73 	return lenDb;
74     }
75     else {
76     	uint8_t longLen = ASN_LONG_LENGTH;
77 	int len = data.length();
78 	while (len > 0) {
79 	    uint8_t v = len & 0xFF;
80 	    lenDb.insert(DataBlock(&v,1));
81 	    len >>= 8;
82 	}
83 	longLen |= lenDb.length();
84 	lenDb.insert(DataBlock(&longLen,1));
85 	return lenDb;
86     }
87    return lenDb;
88 }
89 
matchEOC(DataBlock & data)90 int ASNLib::matchEOC(DataBlock& data)
91 {
92     /**
93      * EoC = 00 00
94      */
95     XDebug(s_libName.c_str(),DebugAll,"::matchEOC() in data='%p'",&data);
96     if (data.length() < 2)
97 	return InvalidLengthOrTag;
98     if (data[0] == 0 && data[1] == 0) {
99     	data.cut(-2);
100     	return 2;
101     }
102     return InvalidLengthOrTag;
103 }
104 
105 
parseUntilEoC(DataBlock & data,int length)106 int ASNLib::parseUntilEoC(DataBlock& data, int length)
107 {
108     if (length >= (int)data.length() || ASNLib::matchEOC(data) > 0)
109 	return length;
110     while (data.length() && ASNLib::matchEOC(data) < 0) {
111 	// compute tag portion length
112 	AsnTag tag;
113 	AsnTag::decode(tag,data);
114 	length += tag.coding().length();
115 	data.cut(-(int)tag.coding().length());
116 	// compute length portion length
117 	int initLen = data.length();
118 	int len = ASNLib::decodeLength(data);
119 	length += initLen - data.length();
120 
121 	bool checkEoC = (len == ASNLib::IndefiniteForm);
122 	if (!checkEoC && len < 0)
123 	    return length;
124 
125 	if (checkEoC) {
126 	    length = parseUntilEoC(data,length);
127 	    if (ASNLib::matchEOC(data) > 0)
128 		length += 2;
129 	}
130 	else {
131 	    length += len;
132 	    data.cut(-len);
133 	}
134     }
135     return length;
136 }
137 
decodeBoolean(DataBlock & data,bool * val,bool tagCheck)138 int ASNLib::decodeBoolean(DataBlock& data, bool* val, bool tagCheck)
139 {
140     /**
141      * boolean = 0x01 length byte (byte == 0 => false, byte != 0 => true)
142      */
143     XDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() from data='%p'",&data);
144     if (data.length() < 2)
145 	return InvalidLengthOrTag;
146 #ifdef DEBUG
147     unsigned int initLen = data.length();
148 #endif
149     if (tagCheck) {
150 	int type = data[0];
151 	if ((type != BOOLEAN)) {
152 	    XDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid Tag in data='%p'",&data);
153 	    return InvalidLengthOrTag;
154 	}
155 	data.cut(-1);
156     }
157     int length = decodeLength(data);
158     if (length < 0) {
159 	DDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid Length in data='%p'",&data);
160 	return length;
161     }
162 
163     if ((unsigned int)length > data.length() || length != 1) {
164 	DDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid Length in data='%p'",&data);
165 	return InvalidLengthOrTag;
166     }
167     if (!val) {
168         data.cut(-1);
169         DDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid buffer for return data");
170         return InvalidContentsError;
171     }
172     *val = false;
173     if ((data[0] & 0xFF) != 0)
174 	*val = true;
175     data.cut(-1);
176 #ifdef DEBUG
177     Debug(s_libName.c_str(),DebugAll,"::decodeBoolean() - decoded boolean value from data='%p', consumed %u bytes",
178     	&data, initLen - data.length());
179 #endif
180     return length;
181 }
182 
decodeInteger(DataBlock & data,u_int64_t & intVal,unsigned int bytes,bool tagCheck)183 int ASNLib::decodeInteger(DataBlock& data, u_int64_t& intVal, unsigned int bytes, bool tagCheck)
184 {
185     /**
186      * integer = 0x02 length byte {byte}*
187      */
188     XDebug(s_libName.c_str(),DebugAll,"::decodeInteger() from  data='%p'",&data);
189     int64_t value = 0;
190     if (data.length() < 2)
191 	return InvalidLengthOrTag;
192 #ifdef DEBUG
193     unsigned int initLen = data.length();
194 #endif
195     if (tagCheck) {
196 	int type = data[0];
197 	if ((type != INTEGER)) {
198 	    XDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Tag in data='%p'",&data);
199 	    return InvalidLengthOrTag;
200 	}
201 	data.cut(-1);
202     }
203     int length = decodeLength(data);
204     if (length < 0) {
205 	DDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Length in data='%p'",&data);
206 	return length;
207     }
208 
209     if ((unsigned int)length > data.length()) {
210 	DDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Length in data='%p'",&data);
211 	return InvalidLengthOrTag;
212     }
213 
214     if ((unsigned int)length > bytes) {
215     	DDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Length: decoded length=%d greater than requested length=%u in data='%p'",
216     			length,bytes,&data);
217     	return InvalidLengthOrTag;
218     }
219 
220     if (data[0] & 0x80)
221 	value = -1; /* integer is negative */
222     int j = 0;
223     while (j < length) {
224 	value = (value << 8) | data[j];
225 	j++;
226     }
227     intVal = (u_int64_t) value;
228     data.cut(-length);
229 #ifdef DEBUG
230     Debug(s_libName.c_str(),DebugAll,"::decodeInteger() - decoded integer value from  data='%p', consumed %u bytes",
231     	&data, initLen - data.length());
232 #endif
233     return length;
234 }
235 
decodeUINT8(DataBlock & data,u_int8_t * intVal,bool tagCheck)236 int ASNLib::decodeUINT8(DataBlock& data, u_int8_t* intVal, bool tagCheck)
237 {
238     XDebug(s_libName.c_str(),DebugAll,"::decodeUINT8()");
239     u_int64_t val;
240     int l = decodeInteger(data,val,sizeof(u_int8_t),tagCheck);
241     if (!intVal) {
242         DDebug(s_libName.c_str(),DebugAll,"::decodeUINT8() - Invalid buffer for return data");
243         return InvalidContentsError;
244     }
245     *intVal = (u_int8_t) val;
246     return l;
247 }
248 
decodeUINT16(DataBlock & data,u_int16_t * intVal,bool tagCheck)249 int ASNLib::decodeUINT16(DataBlock& data, u_int16_t* intVal, bool tagCheck)
250 {
251     XDebug(s_libName.c_str(),DebugAll,"::decodeUINT16() from data='%p'",&data);
252     u_int64_t val;
253     int l = decodeInteger(data,val,sizeof(u_int16_t),tagCheck);
254     if (!intVal) {
255         DDebug(s_libName.c_str(),DebugAll,"::decodeUINT16() - Invalid buffer for return data");
256         return InvalidContentsError;
257     }
258     *intVal = (u_int16_t) val;
259     return l;
260 }
261 
decodeUINT32(DataBlock & data,u_int32_t * intVal,bool tagCheck)262 int ASNLib::decodeUINT32(DataBlock& data, u_int32_t* intVal, bool tagCheck)
263 {
264     XDebug(s_libName.c_str(),DebugAll,"::decodeUINT32() from data='%p'",&data);
265     u_int64_t val;
266     int l = decodeInteger(data,val,sizeof(u_int32_t),tagCheck);
267     if (!intVal) {
268         DDebug(s_libName.c_str(),DebugAll,"::decodeUINT32() - Invalid buffer for return data");
269         return InvalidContentsError;
270     }
271     *intVal = (u_int32_t) val;
272     return l;
273 }
274 
decodeUINT64(DataBlock & data,u_int64_t * intVal,bool tagCheck)275 int ASNLib::decodeUINT64(DataBlock& data, u_int64_t* intVal, bool tagCheck)
276 {
277     XDebug(s_libName.c_str(),DebugAll,"::decodeUINT64() from data='%p'",&data);
278     u_int64_t val;
279     int l = decodeInteger(data,val,sizeof(u_int64_t),tagCheck);
280     if (!intVal) {
281         DDebug(s_libName.c_str(),DebugAll,"::decodeUINT64() - Invalid buffer for return data");
282         return InvalidContentsError;
283     }
284     *intVal = val;
285     return l;
286 }
287 
decodeINT8(DataBlock & data,int8_t * intVal,bool tagCheck)288 int ASNLib::decodeINT8(DataBlock& data, int8_t* intVal, bool tagCheck)
289 {
290     XDebug(s_libName.c_str(),DebugAll,"::decodeINT8() from data='%p'",&data);
291     u_int64_t val;
292     int l = decodeInteger(data,val,sizeof(int8_t),tagCheck);
293     if (!intVal) {
294         DDebug(s_libName.c_str(),DebugAll,"::decodeINT8() - Invalid buffer for return data");
295         return InvalidContentsError;
296     }
297     *intVal = (int8_t) val;
298     return l;
299 }
300 
decodeINT16(DataBlock & data,int16_t * intVal,bool tagCheck)301 int ASNLib::decodeINT16(DataBlock& data, int16_t* intVal, bool tagCheck)
302 {
303     XDebug(s_libName.c_str(),DebugAll,"::decodeINT16() from data='%p'",&data);
304     u_int64_t val;
305     int l = decodeInteger(data,val,sizeof(int16_t),tagCheck);
306     if (!intVal) {
307         DDebug(s_libName.c_str(),DebugAll,"::decodeINT16() - Invalid buffer for return data");
308         return InvalidContentsError;
309     }
310     *intVal = (int16_t) val;
311     return l;
312 }
313 
decodeINT32(DataBlock & data,int32_t * intVal,bool tagCheck)314 int ASNLib::decodeINT32(DataBlock& data, int32_t* intVal, bool tagCheck)
315 {
316     XDebug(s_libName.c_str(),DebugAll,"::decodeINT32() from data='%p'",&data);
317     u_int64_t val;
318     int l = decodeInteger(data,val,sizeof(int32_t),tagCheck);
319     if (!intVal) {
320         DDebug(s_libName.c_str(),DebugAll,"::decodeINT32() - Invalid buffer for return data");
321         return InvalidContentsError;
322     }
323     *intVal = (int32_t) val;
324     return l;
325 }
326 
decodeINT64(DataBlock & data,int64_t * intVal,bool tagCheck)327 int ASNLib::decodeINT64(DataBlock& data, int64_t* intVal, bool tagCheck)
328 {
329     XDebug(s_libName.c_str(),DebugAll,"::decodeINT64() from data='%p'",&data);
330     u_int64_t val;
331     int l = decodeInteger(data,val,sizeof(int64_t),tagCheck);
332     if (!intVal) {
333         DDebug(s_libName.c_str(),DebugAll,"::decodeINT64() - Invalid buffer for return data");
334         return InvalidContentsError;
335     }
336     *intVal = val;
337     return l;
338 }
339 
decodeBitString(DataBlock & data,String * val,bool tagCheck)340 int ASNLib::decodeBitString(DataBlock& data, String* val, bool tagCheck)
341 {
342     /**
343      * bitstring ::= 0x03 asnlength unusedBytes {byte}*
344      */
345     XDebug(s_libName.c_str(),DebugAll, "::decodeBitString() from data='%p'",&data);
346     if (data.length() < 2)
347 	return InvalidLengthOrTag;
348 #ifdef DEBUG
349     unsigned int initLen = data.length();
350 #endif
351     if (tagCheck) {
352 	int type = data[0];
353 	if ((type != BIT_STRING)) {
354 	    XDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid Tag in data='%p'",&data);
355 	    return InvalidLengthOrTag;
356 	}
357 	data.cut(-1);
358     }
359     int length = decodeLength(data);
360     if (length < 0) {
361 	DDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid Length in data='%p'",&data);
362 	return length;
363     }
364 
365     if ((unsigned int)length > data.length()) {
366 	DDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid Length in data='%p'",&data);
367 	return InvalidLengthOrTag;
368     }
369 
370     if (data[0] > 7){
371 	DDebug(s_libName.c_str(),DebugAll, "::decodeBitString() - Invalid bitstring, unused bytes > 7 in data='%p'",&data);
372 	return InvalidLengthOrTag;
373     }
374     int unused = data[0];
375     data.cut(-1);
376     length--;
377     int j = 0;
378     if (!val) {
379         DDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid buffer for return data");
380         data.cut(-length);
381         return InvalidContentsError;
382     }
383     *val = "";
384     while (j < length) {
385 	uint8_t byte = data[j];
386 	for (int i = 7; i > -1; i--) {
387 	    int c = (byte >> i) % 2;
388 	    *val += c;
389 	}
390 	j++;
391     }
392     *val = val->substr(0, length * 8 - unused);
393     data.cut(-length);
394 #ifdef DEBUG
395     Debug(s_libName.c_str(),DebugAll,"::decodeBitString() - decoded bit string value from  data='%p', consumed %u bytes",
396     	&data, initLen - data.length());
397 #endif
398     return length;
399 }
400 
decodeOctetString(DataBlock & db,OctetString * strVal,bool tagCheck)401 int ASNLib::decodeOctetString(DataBlock& db, OctetString* strVal, bool tagCheck)
402 {
403     /**
404      *  octet string ::= 0x04 asnlength {byte}*
405      */
406     XDebug(s_libName.c_str(),DebugAll,":decodeOctetString() from data='%p'",&db);
407     if (db.length() < 2)
408 	return InvalidLengthOrTag;
409 #ifdef DEBUG
410     unsigned int initLen = db.length();
411 #endif
412     if (tagCheck) {
413 	int type = db[0];
414 	if (type != OCTET_STRING) {
415 	    XDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid Tag in data='%p'",&db);
416 	    return InvalidLengthOrTag;
417 	}
418 	db.cut(-1);
419     }
420     int length = decodeLength(db);
421     if (length < 0) {
422 	DDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid Length in data='%p'",&db);
423 	return length;
424     }
425     if ((unsigned int)length > db.length()) {
426 	DDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid Length in data='%p'",&db);
427 	return InvalidLengthOrTag;
428     }
429     if (!strVal) {
430         DDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid buffer for return data");
431         return InvalidContentsError;
432     }
433     strVal->assign((void*)db.data(0,length),length);
434     db.cut(-length);
435 #ifdef DEBUG
436     Debug(s_libName.c_str(),DebugAll,"::decodeOctetString() - decoded octet string value from  data='%p', consumed %u bytes",
437     	&db, initLen - db.length());
438 #endif
439     return length;
440 }
441 
decodeNull(DataBlock & data,bool tagCheck)442 int ASNLib::decodeNull(DataBlock& data, bool tagCheck)
443 {
444     /**
445      * ASN.1 null := 0x05 00
446      */
447     XDebug(s_libName.c_str(),DebugAll,"::decodeNull() from data='%p'",&data);
448     if (tagCheck) {
449 	if (data.length() < 2)
450 	    return InvalidLengthOrTag;
451 
452 	if (data[0] != NULL_ID) {
453 	    XDebug(s_libName.c_str(),DebugAll, "::decodeNull() - Invalid Tag in data='%p'",&data);
454 	    return InvalidLengthOrTag;
455 	}
456 	data.cut(-1);
457     }
458     int length = decodeLength(data);
459     if (length != 0) {
460 	DDebug(s_libName.c_str(),DebugAll,"::decodeNull() - Invalid Length in data='%p'",&data);
461 	return InvalidLengthOrTag;;
462     }
463     DDebug(s_libName.c_str(),DebugAll,"::decodeNull() - decoded null value from  data='%p', consumed %u bytes",
464     		&data, (tagCheck ? 2 : 1));
465     return length;
466 }
467 
decodeOID(DataBlock & data,ASNObjId * obj,bool tagCheck)468 int ASNLib::decodeOID(DataBlock& data, ASNObjId* obj, bool tagCheck)
469 {
470    /**
471     * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
472     * subidentifier ::= {leadingbyte}* lastbyte
473     * leadingbyte ::= 1 7bites
474     * lastbyte ::= 0 7bites
475     */
476     XDebug(s_libName.c_str(),DebugAll,"::decodeOID() from data='%p'",&data);
477     if (data.length() < 2)
478 	return InvalidLengthOrTag;
479 #ifdef DEBUG
480     unsigned int initLen = data.length();
481 #endif
482     if (tagCheck) {
483 	if (data[0] != OBJECT_ID) {
484 	    XDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid Tag in data='%p'",&data);
485 	    return InvalidLengthOrTag;
486 	}
487 	data.cut(-1);
488     }
489     int length = decodeLength(data);
490     if (length < 0) {
491 	DDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid Length in data='%p'",&data);
492 	return length;
493     }
494 
495     if ((unsigned int)length > data.length()) {
496 	DDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid Length in data='%p'",&data);
497 	return InvalidLengthOrTag;
498     }
499 
500     if (length == 0) {
501 	obj = 0;
502 	return length;
503     }
504 
505     int j = 0;
506     String oid = "";
507     unsigned int longNo = 0;
508     while (j < length) {
509     // first byte contains 2 identifiers : x,y. The byte is 40 * x + y . x can only be 0,1,2 so if x > 2, x stays 2 and the rest goes into y
510 	if (j == 0) {
511 	    unsigned int x = data[j] / 40;
512 	    unsigned int y = data[j] % 40;
513 	    if (x > 2) {
514 		y = (x - 2) * 40 + y;
515 		x = 2;
516 	    }
517 	    oid += x;
518 	    oid += ".";
519 	    oid += y;
520 	    oid += ".";
521 	}
522 	else {
523 	    uint8_t byte = data[j];
524 	    longNo += byte & ~ASN_BIT8;
525 	    if ((byte & ASN_BIT8) == ASN_BIT8)
526 		longNo <<= 7;
527 	    else {
528 		oid += longNo;
529 		longNo = 0;
530 		if (j != length -1)
531 		    oid += ".";
532 	    }
533       }
534       j++;
535     }
536     data.cut(-length);
537     if (!obj) {
538         DDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid buffer for return data");
539         return InvalidContentsError;
540     }
541     *obj = oid;
542 #ifdef DEBUG
543     Debug(s_libName.c_str(),DebugAll,"::decodeOID() - decoded object ID from  data='%p', consumed %u bytes",
544     	&data, initLen - data.length());
545 #endif
546     return length;
547 }
548 
decodeReal(DataBlock & db,float * realVal,bool tagCheck)549 int ASNLib::decodeReal(DataBlock& db, float* realVal, bool tagCheck)
550 {
551     if (db.length() < 2)
552 	return InvalidLengthOrTag;
553     unsigned int initLen = db.length();
554     if (tagCheck) {
555 	if (db[0] != REAL) {
556 	    XDebug(s_libName.c_str(),DebugAll,"::decodeReal() - Invalid Tag in data='%p'",&db);
557 	    return InvalidLengthOrTag;
558 	}
559 	db.cut(-1);
560     }
561     int length = decodeLength(db);
562     if (length < 0) {
563 	DDebug(s_libName.c_str(),DebugAll,"::decodeReal() - Invalid Length in data='%p'",&db);
564 	return length;
565     }
566     if ((unsigned int)length > db.length()) {
567 	DDebug(s_libName.c_str(),DebugAll,"::decodeReal() - Invalid Length in data='%p'",&db);
568 	return InvalidLengthOrTag;
569     }
570     db.cut(-length);
571     Debug(s_libName.c_str(),DebugInfo,"::decodeReal() - real value decoding not implemented, skipping over the %u bytes of the encoding",
572     		initLen - db.length());
573     return 0;
574 }
575 
decodeString(DataBlock & data,String * str,int * type,bool tagCheck)576 int ASNLib::decodeString(DataBlock& data, String* str, int* type, bool tagCheck)
577 {
578     XDebug(s_libName.c_str(),DebugAll,"::decodeString() from data='%p'",&data);
579     if (data.length() < 2)
580 	return InvalidLengthOrTag;
581 #ifdef DEBUG
582     unsigned int initLen = data.length();
583 #endif
584     if (tagCheck) {
585 	if (data[0] != NUMERIC_STR ||
586 	    data[0] != PRINTABLE_STR ||
587 	    data[0] != IA5_STR ||
588 	    data[0] != VISIBLE_STR
589 	    ) {
590 	    XDebug(s_libName.c_str(),DebugAll,"::decodeString() -  Invalid Tag in data='%p'",&data);
591 	    return InvalidLengthOrTag;
592 	}
593 	if (type)
594 	    *type = data[0];
595 	data.cut(-1);
596     }
597     int length = decodeLength(data);
598     if (length < 0) {
599 	DDebug(s_libName.c_str(),DebugAll,"::decodeString() -Invalid Length in data='%p'",&data);
600 	return length;
601     }
602 
603     if ((unsigned int)length > data.length()) {
604 	DDebug(s_libName.c_str(),DebugAll,"::decodeString() -Invalid Length in data='%p'",&data);
605 	return InvalidLengthOrTag;
606     }
607 
608     String var = "";
609     for (int i = 0; i < length; i++)
610 	var += (char) (data[i] & 0x7f);
611     data.cut(-length);
612     if (!str || !type) {
613         DDebug(s_libName.c_str(),DebugAll,"::decodeString() - Invalid buffer for return data");
614         return InvalidContentsError;
615     }
616     *str = var;
617 #ifdef DEBUG
618     Debug(s_libName.c_str(),DebugInfo,"::decodeString() - decode string value from data='%p', consumed %u bytes",
619     	&data,initLen - data.length());
620 #endif
621     return length;
622 }
623 
624 
decodeUtf8(DataBlock & data,String * str,bool tagCheck)625 int ASNLib::decodeUtf8(DataBlock& data, String* str, bool tagCheck)
626 {
627     XDebug(s_libName.c_str(),DebugAll,"::decodeUtf8() from data='%p'",&data);
628     if (data.length() < 2)
629 	return InvalidLengthOrTag;
630 #ifdef DEBUG
631     unsigned int initLen = data.length();
632 #endif
633     if (tagCheck) {
634 	if (data[0] != UTF8_STR) {
635 	    XDebug(s_libName.c_str(),DebugAll,"::decodeUtf8() - Invalid Tag in data='%p'",&data);
636 	    return InvalidLengthOrTag;
637 	}
638 	data.cut(-1);
639     }
640     int length = decodeLength(data);
641     if (length < 0) {
642 	DDebug(s_libName.c_str(),DebugAll,"::decodeUtf8() -Invalid Length in data='%p'",&data);
643 	return length;
644     }
645 
646     if ((unsigned int)length > data.length()) {
647 	Debug(s_libName.c_str(),DebugAll,"::decodeUtf8() - Invalid Length in data='%p'",&data);
648 	return InvalidLengthOrTag;
649     }
650 
651     String var = "";
652     for (int i = 0; i < length; i++)
653 	var += (char) (data[i]);
654     data.cut(-length);
655     if (String::lenUtf8(var.c_str()) < 0)
656 	return ParseError;
657     if (!str) {
658         DDebug(s_libName.c_str(),DebugAll,"::decodeUTF8() - Invalid buffer for return data");
659         return InvalidContentsError;
660     }
661     *str = var;
662 #ifdef DEBUG
663     Debug(s_libName.c_str(),DebugAll,"::decodeUtf8() - decoded an UTF8 string value from data='%p', consumed %u bytes",&data,initLen - data.length());
664 #endif
665     return length;
666 }
667 
decodeGenTime(DataBlock & data,unsigned int * time,unsigned int * fractions,bool * utc,bool tagCheck)668 int ASNLib::decodeGenTime(DataBlock& data, unsigned int* time, unsigned int* fractions, bool* utc, bool tagCheck)
669 {
670     XDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() from data='%p'",&data);
671     if (data.length() < 2)
672 	return InvalidLengthOrTag;
673 #ifdef DEBUG
674     unsigned int initLen = data.length();
675 #endif
676     if (tagCheck) {
677 	if (data[0] != GENERALIZED_TIME) {
678 	    XDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid Tag in data='%p'",&data);
679 	    return InvalidLengthOrTag;
680 	}
681 	data.cut(-1);
682     }
683     int length = decodeLength(data);
684     if (length < 0) {
685 	DDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid Length in data='%p'",&data);
686 	return length;
687     }
688 
689     if ((unsigned int)length > data.length() || length < 14) {
690 	DDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid Length in data='%p'",&data);
691 	return InvalidLengthOrTag;
692     }
693     String date = "";
694     for (int i = 0; i < length; i++)
695 	date += (char) (data[i]);
696     data.cut(-length);
697 
698     if (!(utc && fractions && time)) {
699         DDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid buffer for return data");
700         return InvalidContentsError;
701     }
702 
703     unsigned int year, month, day, hours, minutes, seconds;
704     int timeDiff = 0;
705 
706     *utc = false;
707     *fractions = 0;
708 
709     if (date[date.length() - 1] == 'Z') {
710 	*utc = true;
711 	date = date.substr(0,date.length() - 1);
712     }
713     else {
714 	int pos = date.find('-');
715 	if (pos < 0)
716 	    pos = date.find('+');
717 	if (pos >0 && pos != (int)date.length() - 5)
718 	    return InvalidContentsError;
719 	if (pos > 0) {
720 	    char sign = date.at(pos);
721 	    unsigned int hDiff = (unsigned int) date.substr(date.length() - 4,2).toInteger(-1,10);
722 	    if (hDiff > 11)
723 		return InvalidContentsError;
724 	    unsigned int mDiff = (unsigned int) date.substr(date.length() - 2,2).toInteger(-1,10);
725 	    if (mDiff > 59)
726 		return InvalidContentsError;
727 	    unsigned int diff = Time::toEpoch(1970,1,1,hDiff,mDiff,0);
728 	    if (sign == '-')
729 		timeDiff = diff;
730 	    else
731 		timeDiff -= diff;
732 	    *utc = true;
733 	    date = date.substr(0,date.length() - 5);
734 	}
735     }
736     ObjList* list = date.split('.');
737     if (!list || list->count() > 2)
738 	return InvalidContentsError;
739     if (list->count() == 2)
740 	*fractions = (*list)[1]->toString().toInteger(0,10);
741 
742     String dateTime = (*list)[0]->toString();
743     TelEngine::destruct(list);
744 
745     year = dateTime.substr(0,4).toInteger(-1,10);
746     month = dateTime.substr(4,2).toInteger(-1,10);
747     day = dateTime.substr(6,2).toInteger(-1,10);
748     hours = dateTime.substr(8,2).toInteger(-1,10);
749     minutes = dateTime.substr(10,2).toInteger(-1,10);
750     seconds = dateTime.substr(12,2).toInteger(-1,10);
751     if (year < 1970 || month > 12 || day > 31 || hours > 23 || minutes > 59 || seconds > 59)
752 	return InvalidContentsError;
753 
754     unsigned int epochTime = Time::toEpoch(year,month,day,hours,minutes,seconds);
755     if (epochTime == (unsigned int) -1)
756 	return InvalidContentsError;
757     *time = epochTime + timeDiff;
758 #ifdef DEBUG
759     Debug(s_libName.c_str(),DebugAll,"::decodeGenTime() - decoded time value from data='%p', consumed %u bytes",&data,initLen - data.length());
760 #endif
761     return length;
762 }
763 
decodeUTCTime(DataBlock & data,unsigned int * time,bool tagCheck)764 int ASNLib::decodeUTCTime(DataBlock& data, unsigned int* time, bool tagCheck)
765 {
766     XDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() from data='%p'",&data);
767     if (data.length() < 2)
768 	return InvalidLengthOrTag;
769 #ifdef DEBUG
770     unsigned int initLen = data.length();
771 #endif
772     if (tagCheck) {
773 	if (data[0] != UTC_TIME) {
774 	    XDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid Tag in data='%p'",&data);
775 	    return InvalidLengthOrTag;
776 	}
777 	data.cut(-1);
778     }
779     int length = decodeLength(data);
780     if (length < 0) {
781 	DDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid Length in data='%p'",&data);
782 	return length;
783     }
784 
785     if ((unsigned int)length > data.length() || length < 11) {
786 	DDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid Length in data='%p'",&data);
787 	return InvalidLengthOrTag;
788     }
789     String date = "";
790     for (int i = 0; i < length; i++)
791 	date += (char) (data[i]);
792     data.cut(-length);
793 
794     if (!time) {
795         DDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid buffer for return data");
796         return InvalidContentsError;
797     }
798     unsigned int year = 0, month = 0, day = 0, hours = 0, minutes = 0, seconds = 0;
799     int timeDiff = 0;
800 
801     int len = date.length();
802     if (date[date.length() - 1] == 'Z')
803 	date = date.substr(0,len - 1);
804     else {
805 	int pos = date.find('-');
806 	if (pos < 0)
807 	    pos = date.find('+');
808 	if ((pos >0 && pos != len - 5) || pos < 0)
809 	    return InvalidContentsError;
810 	if (pos > 0) {
811 	    char sign = date.at(pos);
812 	    unsigned int hDiff = (unsigned int) date.substr(len - 4,2).toInteger(-1,10);
813 	    if (hDiff > 11)
814 		return InvalidContentsError;
815 	    unsigned int mDiff = (unsigned int) date.substr(len - 2,2).toInteger(-1,10);
816 	    if (mDiff > 59)
817 		return InvalidContentsError;
818 	    unsigned int diff = Time::toEpoch(1970,1,1,hDiff,mDiff,0);
819 	    if (sign == '-')
820 		timeDiff = diff;
821 	    else
822 		timeDiff -= diff;
823 	    date = date.substr(0,len - 5);
824 	}
825     }
826     year = date.substr(0,2).toInteger(-1,10);
827     year = (year > 50) ? 1900 + year : 2000 + year;
828     month = date.substr(2,2).toInteger(-1,10);
829     day = date.substr(4,2).toInteger(-1,10);
830     hours = date.substr(6,2).toInteger(-1,10);
831     minutes = date.substr(8,2).toInteger(-1,10);
832     if (date.length() > 10)
833 	seconds = date.substr(10,2).toInteger(-1,10);
834     if (year < 1970 || month > 12 || day > 31 || hours > 23 || minutes > 59 || seconds > 59)
835 	return InvalidContentsError;
836 
837     unsigned int epochTime = Time::toEpoch(year,month,day,hours,minutes,seconds);
838     if (epochTime == (unsigned int) -1)
839 	return InvalidContentsError;
840     *time = epochTime + timeDiff;
841 #ifdef DEBUG
842     Debug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - decoded time value from data='%p', consumed %u bytes",&data,initLen - data.length());
843 #endif
844     return length;
845 }
846 
decodeAny(DataBlock data,DataBlock * val,bool tagCheck)847 int ASNLib::decodeAny(DataBlock data, DataBlock* val, bool tagCheck)
848 {
849     XDebug(s_libName.c_str(),DebugAll,"::decodeAny() from data='%p'",&data);
850     if (!val) {
851         DDebug(s_libName.c_str(),DebugAll,"::decodeAny() - Invalid buffer for return data");
852         return InvalidContentsError;
853     }
854     val->append(data);
855     return data.length();
856 }
857 
decodeSequence(DataBlock & data,bool tagCheck)858 int ASNLib::decodeSequence(DataBlock& data, bool tagCheck)
859 {
860     XDebug(s_libName.c_str(),DebugAll,"::decodeSequence() from data='%p'",&data);
861     if (data.length() < 2)
862 	return InvalidLengthOrTag;
863 #ifdef DEBUG
864     unsigned int initLen = data.length();
865 #endif
866     if (tagCheck) {
867 	if (data[0] != SEQUENCE) {
868 	    DDebug(s_libName.c_str(),DebugAll,"::decodeSequence() - Invalid Tag in data='%p'",&data);
869 	    return InvalidLengthOrTag;
870 	}
871 	data.cut(-1);
872     }
873     int length = decodeLength(data);
874     if (length < 0)
875 	Debug(s_libName.c_str(),DebugAll,"::decodeSequence() - Invalid Length in data='%p'",&data);
876 #ifdef DEBUG
877     Debug(s_libName.c_str(),DebugAll,"::decodeSequence() - decoded sequence tags from data='%p', consumed %u bytes",&data,initLen - data.length());
878 #endif
879     return length;
880 }
881 
decodeSet(DataBlock & data,bool tagCheck)882 int ASNLib::decodeSet(DataBlock& data, bool tagCheck)
883 {
884     XDebug(s_libName.c_str(),DebugAll,"::decodeSet() from data='%p",&data);
885     if (data.length() < 2)
886 	return InvalidLengthOrTag;
887 #ifdef DEBUG
888     unsigned int initLen = data.length();
889 #endif
890     if (tagCheck) {
891 	if (data[0] != SET) {
892 	    DDebug(s_libName.c_str(),DebugAll,"::decodeSet() - Invalid Tag in data='%p'",&data);
893 	    return InvalidLengthOrTag;
894 	}
895 	data.cut(-1);
896     }
897     int length = decodeLength(data);
898 #ifdef DEBUG
899     if (length < 0)
900 	Debug(s_libName.c_str(),DebugAll,"::decodeSet() - Invalid Length in data='%p'",&data);
901     else
902 	Debug(s_libName.c_str(),DebugAll,"::decodeSet() - decoded set tags from data='%p', consumed %u bytes",&data,initLen - data.length());
903 #endif
904     return length;
905 }
906 
encodeBoolean(bool val,bool tagCheck)907 DataBlock ASNLib::encodeBoolean(bool val, bool tagCheck)
908 {
909     /**
910      * ASN.1 boolean ::= 0x01 asnlength=0x01 byte
911      */
912     DataBlock data;
913     uint8_t b = BOOLEAN;
914     if (tagCheck) {
915 	data.append(&b, 1);
916 	b = 1;
917 	data.append(&b, 1);
918     }
919     b = val ? 1 : 0;
920     data.append(&b, 1);
921     XDebug(s_libName.c_str(),DebugAll,"::encodeBoolean('%s') - encoded boolean value into %u bytes",String::boolText(val),data.length());
922     return data;
923 }
924 
encodeInteger(u_int64_t intVal,bool tagCheck)925 DataBlock ASNLib::encodeInteger(u_int64_t intVal, bool tagCheck)
926 {
927     /**
928      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
929      */
930     DataBlock data;
931     uint8_t tag = INTEGER;
932 
933     // 9 consecutive ones or zeros are not allowed at the beginning of an integer
934     int size = sizeof(u_int64_t);
935     uint16_t msb = (uint16_t)(intVal >> ((size - 1) * 8 - 1));
936 
937     while (((msb & 0x1FF) == 0 || (msb & 0x1FF) == 0x1FF) && (size - 1 >= 1)) {
938 	size--;
939 	msb = (uint16_t)(intVal >> ((size - 1) * 8 - 1));
940     }
941     if (size == 0)
942 	return data;
943 
944     DataBlock contents;
945     while(size) {
946 	uint8_t byte = (uint8_t)(intVal >> ((size - 1) * 8));
947 	contents.append(&byte, 1);
948 	size--;
949     }
950 
951     if (contents.length() == 0)
952 	return data;
953     if (tagCheck) {
954 	data.append(&tag, 1);
955 	DataBlock len = buildLength(contents);
956 	data.append(len);
957     }
958     data.append(contents);
959     XDebug(s_libName.c_str(),DebugAll,"::encodeInteger('" FMT64 "') - encoded into %u bytes",intVal,data.length());
960     return data;
961 }
962 
encodeBitString(String val,bool tagCheck)963 DataBlock ASNLib::encodeBitString(String val, bool tagCheck)
964 {
965     /**
966      * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
967      */
968     DataBlock data;
969     uint8_t tag = BIT_STRING;
970     DataBlock contents;
971 
972     int l = val.length();
973     uint8_t trail = (-l) & 0x07;
974     for (int i = 0; i < trail; i++)
975 	val += "0";
976     contents.append(&trail, 1);
977 
978     for (unsigned int i = 0; i < val.length(); i += 8) {
979 	uint8_t hex = val.substr(i, 8).toInteger(0,2);
980 	contents.append(&hex, 1);
981     }
982 
983     if (tagCheck) {
984 	data.append(&tag,1);
985 	DataBlock len = buildLength(contents);
986 	data.append(len);
987     }
988     data.append(contents);
989     XDebug(s_libName.c_str(),DebugAll,"::encodeBitString('%s') - encoded bit string into %u bytes",val.c_str(),data.length());
990     return data;
991 }
992 
encodeOctetString(OctetString strVal,bool tagCheck)993 DataBlock ASNLib::encodeOctetString(OctetString strVal, bool tagCheck)
994 {
995     /**
996       * ASN.1 octet string ::= 0x04 asnlength byte {byte}*
997       */
998     DataBlock data;
999     uint8_t tag = OCTET_STRING;
1000     if (tagCheck) {
1001 	data.append(&tag, 1);
1002 	DataBlock len = buildLength(strVal);
1003 	data.append(len);
1004     }
1005     data.append(strVal);
1006     XDebug(s_libName.c_str(),DebugAll,"ASNLib::encodeOctetString('%s') - encoded octet string into %u bytes",
1007     		strVal.toHexString().c_str(),data.length());
1008     return data;
1009 }
1010 
encodeNull(bool tagCheck)1011 DataBlock ASNLib::encodeNull(bool tagCheck)
1012 {
1013     /**
1014       *	ASN.1 null ::= 0x05 00
1015       */
1016     XDebug(s_libName.c_str(),DebugAll,"::encodeNull()");
1017     DataBlock data;
1018     uint8_t tag = NULL_ID;
1019     if (tagCheck) {
1020 	data.append(&tag, 1);
1021 	tag = 0;
1022 	data.append(&tag, 1);
1023     }
1024     return data;
1025 }
1026 
encodeOID(ASNObjId obj,bool tagCheck)1027 DataBlock ASNLib::encodeOID(ASNObjId obj, bool tagCheck)
1028 {
1029     /**
1030       * ASN.1 object id ::= 0x06 asnlength byte {byte}*
1031       */
1032     DataBlock data;
1033     uint8_t tag = OBJECT_ID;
1034 
1035     DataBlock cont = obj.getIds();
1036     DataBlock contents;
1037 
1038     if (cont.length() == 0)
1039 	return data;
1040 
1041     // first byte is built following the rule first = 40 * x + y
1042     // x must not be greater than 2 (joint-iso-ccitt identifier)
1043     if (cont[0] > 2) {
1044     	Debug(s_libName.c_str(),DebugAll,"::encodeOID('%s') - first identifier is greater than the maximum allowed identifier 'joint-iso-ccitt'(2)",
1045     			obj.toString().c_str());
1046     	return data;
1047     }
1048     uint8_t first = 40 * cont[0];
1049     if (cont.length() > 1) {
1050     	// y must not be greater than 39 if x < 2
1051     	if (cont[0] < 2 && cont[1] > 39) {
1052     	    Debug(s_libName.c_str(),DebugAll,"::encodeOID('%s') - cannot encode second identifier, its value is not allowed for the first identifier",
1053     			obj.toString().c_str());
1054     	    return data;
1055     	}
1056     	first += cont[1];
1057     	cont.cut(-1);
1058     }
1059     contents.append(&first, 1);
1060     cont.cut(-1);
1061 
1062     contents.append(cont);
1063     if (tagCheck) {
1064 	data.append(&tag,1);
1065 	DataBlock len = buildLength(contents);
1066 	data.append(len);
1067     }
1068     data.append(contents);
1069     XDebug(s_libName.c_str(),DebugAll,"::encodeOID('%s') - encoded object ID into %u bytes",obj.toString().c_str(),data.length());
1070     return data;
1071 }
1072 
encodeReal(float val,bool tagCheck)1073 DataBlock ASNLib::encodeReal(float val, bool tagCheck)
1074 {
1075     Debug(s_libName.c_str(),DebugInfo,"::encodeReal() - STUB: encoding for real values not implemented");
1076     DataBlock data;
1077     return data;
1078 }
1079 
encodeString(String str,int type,bool tagCheck)1080 DataBlock ASNLib::encodeString(String str, int type, bool tagCheck)
1081 {
1082     DataBlock data;
1083     uint8_t tag = type;
1084 
1085     DataBlock contents;
1086     if (type == NUMERIC_STR ||
1087 	type == PRINTABLE_STR ||
1088 	type == IA5_STR ||
1089 	type == VISIBLE_STR )
1090 	contents.append(str);
1091 
1092     if (contents.length() == 0)
1093 	return data;
1094 
1095     if (tagCheck) {
1096 	data.append(&tag, 1);
1097 	DataBlock len = buildLength(contents);
1098 	data.append(len);
1099     }
1100     data.append(contents);
1101     XDebug(s_libName.c_str(),DebugAll,"::encodeString() - encoded string into %u bytes",data.length());
1102     return data;
1103 }
1104 
encodeUtf8(String str,bool tagCheck)1105 DataBlock ASNLib::encodeUtf8(String str, bool tagCheck)
1106 {
1107     DDebug(s_libName.c_str(),DebugAll,"::encodeUtf8()");
1108     DataBlock data;
1109     uint8_t tag = UTF8_STR;
1110     DataBlock contents;
1111     contents.append(str);
1112     if (tagCheck) {
1113 	data.append(&tag, 1);
1114 	DataBlock len = buildLength(contents);
1115 	data.append(len);
1116     }
1117     data.append(contents);
1118     XDebug(s_libName.c_str(),DebugAll,"::encodeString() - encoded UTF8 string into %u bytes",data.length());
1119     return data;
1120 }
1121 
encodeGenTime(unsigned int time,unsigned int fractions,bool tagCheck)1122 DataBlock ASNLib::encodeGenTime(unsigned int time, unsigned int fractions, bool tagCheck)
1123 {
1124     DataBlock data;
1125     uint8_t tag = GENERALIZED_TIME;
1126 
1127     int year;
1128     unsigned int month, day, hours, minutes, seconds;
1129     if (!Time::toDateTime(time, year, month, day, hours, minutes, seconds))
1130 	return data;
1131     String dateTime = "";
1132     dateTime += year;
1133     (month < 10) ? dateTime += 0 : "";
1134     dateTime += month;
1135     (day < 10) ? dateTime += 0 : "";
1136     dateTime += day;
1137     (hours < 10) ? dateTime += 0 : "";
1138     dateTime += hours;
1139     (minutes < 10) ? dateTime += 0 : "";
1140     dateTime += minutes;
1141     (seconds < 10) ? dateTime += 0 : "";
1142     dateTime += seconds;
1143     if (fractions != 0) {
1144 	dateTime += ".";
1145 	dateTime += fractions;
1146     }
1147     dateTime += 'Z';
1148     DataBlock contents;
1149     contents.append(dateTime);
1150     if (tagCheck) {
1151 	data.append(&tag, 1);
1152 	DataBlock len = buildLength(contents);
1153 	data.append(len);
1154     }
1155     data.append(contents);
1156     XDebug(s_libName.c_str(),DebugAll,"::encodeGenTime(time='%u', fractions='%u') - encoded time value into %u bytes",time,fractions,data.length());
1157     return data;
1158 }
1159 
encodeUTCTime(unsigned int time,bool tagCheck)1160 DataBlock ASNLib::encodeUTCTime(unsigned int time, bool tagCheck)
1161 {
1162     DataBlock data;
1163     uint8_t tag = UTC_TIME;
1164 
1165     int year;
1166     unsigned int month, day, hours, minutes, seconds;
1167     if (!Time::toDateTime(time, year, month, day, hours, minutes, seconds))
1168 	return data;
1169     String dateTime = "";
1170     (year % 100 < 10) ?  dateTime += 0 : "";
1171     dateTime += (year % 100);
1172     (month < 10) ? dateTime += 0 : "";
1173     dateTime += month;
1174     (day < 10) ? dateTime += 0 : "";
1175     dateTime += day;
1176     (hours < 10) ? dateTime += 0 : "";
1177     dateTime += hours;
1178     (minutes < 10) ? dateTime += 0 : "";
1179     dateTime += minutes;
1180     (seconds < 10) ? dateTime += 0 : "";
1181     dateTime += seconds;
1182 
1183     dateTime += 'Z';
1184 
1185     DataBlock contents;
1186     contents.append(dateTime);
1187     if (tagCheck) {
1188 	data.append(&tag, 1);
1189 	DataBlock len = buildLength(contents);
1190 	data.append(len);
1191     }
1192     data.append(contents);
1193     XDebug(s_libName.c_str(),DebugAll,"::encodeUTCTime(time='%u') - encoded time value into %u bytes",time,data.length());
1194     return data;
1195 }
1196 
encodeAny(DataBlock data,bool tagCheck)1197 DataBlock ASNLib::encodeAny(DataBlock data, bool tagCheck)
1198 {
1199     XDebug(s_libName.c_str(),DebugAll,"::encodeAny()");
1200     DataBlock db;
1201     db.append(data);
1202     return db;
1203 }
1204 
encodeSequence(DataBlock & data,bool tagCheck)1205 int ASNLib::encodeSequence(DataBlock& data, bool tagCheck)
1206 {
1207     DataBlock len;
1208     if (tagCheck) {
1209 	len = buildLength(data);
1210 	data.insert(len);
1211 	DataBlock db;
1212 	u_int8_t tag = SEQUENCE;
1213 	db.append(&tag, 1);
1214 	data.insert(db);
1215     }
1216     XDebug(s_libName.c_str(),DebugAll,"::encodeSequence() - added sequence tag and length for a block of %d bytes",data.length());
1217     return len.length();
1218 }
1219 
encodeSet(DataBlock & data,bool tagCheck)1220 int ASNLib::encodeSet(DataBlock& data, bool tagCheck)
1221 {
1222     DDebug(s_libName.c_str(),DebugAll,"::encodeSet()");
1223     DataBlock len;
1224     if (tagCheck) {
1225 	len = buildLength(data);
1226 	data.insert(len);
1227 	DataBlock db;
1228 	u_int8_t tag = SET;
1229 	db.append(&tag, 1);
1230 	data.insert(db);
1231     }
1232     XDebug(s_libName.c_str(),DebugAll,"::encodeSet() - added set tag and length for a block of %d bytes",data.length());
1233     return len.length();
1234 }
1235 
1236 /**
1237   * AsnTag
1238   */
decode(AsnTag & tag,DataBlock & data)1239 void AsnTag::decode(AsnTag& tag, DataBlock& data)
1240 {
1241     XDebug(s_libName.c_str(),DebugAll,"AsnTag::decode()");
1242     tag.classType((Class)(data[0] & 0xc0));
1243     tag.type((Type)(data[0] & 0x20));
1244 
1245     unsigned int code = 0;
1246     code |= data[0] & 0x1f;
1247     unsigned int len = 1;
1248     if (IS_EXTENSION_ID(code) && data.length() >= 2) { // extended tag
1249 	code = 0;
1250 	while (len < data.length() && (data[len] & ASN_BIT8) == ASN_BIT8) {
1251 	    code = code << 8;
1252 	    code |= (data[len] & 0x7f);
1253 	    len++;
1254 	}
1255 	code |= data[len] & 0x7f;
1256     }
1257     tag.code(code);
1258     tag.encode();
1259 }
1260 
encode(Class clas,Type type,unsigned int code,DataBlock & data)1261 void AsnTag::encode(Class clas, Type type, unsigned int code, DataBlock& data)
1262 {
1263     XDebug(s_libName.c_str(),DebugAll,"AsnTag::encode(clas=0x%x, type=0x%x, code=%u)",clas,type,code);
1264     if (code < 31) {
1265 	u_int8_t tag = clas | type | code;
1266 	data.insert(DataBlock(&tag,sizeof(tag)));
1267     }
1268     else {
1269 	u_int8_t last = clas | type | 31;
1270 	DataBlock coding;
1271  	coding.append(&last,sizeof(last));
1272 	int size = sizeof(unsigned int);
1273 	bool start = false;
1274 	while (size > 1) {
1275 	    u_int8_t msb = (code >> ((size - 1) * 8));
1276 	    if (start) {
1277 		msb |= 0x80;
1278 		coding.append(&msb,sizeof(msb));
1279 	    }
1280 	    else {
1281 		if (msb == 0) {
1282 		    size--;
1283 		    continue;
1284 		}
1285 		else {
1286 		    start = true;
1287 		    msb |= 0x80;
1288 		    coding.append(&msb,sizeof(msb));
1289 		}
1290 	    }
1291 	    size--;
1292 	}
1293 	last = code;
1294 	coding.append(&last,sizeof(last));
1295 	data.insert(coding);
1296     }
1297 #ifdef XDEBUG
1298     String str;
1299     str.hexify(data.data(),data.length(),' ');
1300     Debug(s_libName.c_str(),DebugAll,"AsnTag::encode(clas=0x%x, type=0x%x, code=%u) tag=%s",clas,type,code,str.c_str());
1301 #endif
1302 }
1303 
1304 /**
1305   * ASNObjId
1306   */
ASNObjId()1307 ASNObjId::ASNObjId()
1308 {
1309 }
1310 
ASNObjId(const String & val)1311 ASNObjId::ASNObjId(const String& val)
1312     : m_value(val)
1313 {
1314     DDebug(s_libName.c_str(),DebugAll,"ASNObjId('%s') created",val.c_str());
1315 }
1316 
ASNObjId(const String & name,const String & val)1317 ASNObjId::ASNObjId(const String& name, const String& val)
1318     : m_value(val), m_name(name)
1319 {
1320     DDebug(s_libName.c_str(),DebugAll,"ASNObjId('%s', '%s') created",name.c_str(),val.c_str());
1321 }
1322 
ASNObjId(AsnMib * mib)1323 ASNObjId::ASNObjId(AsnMib* mib)
1324 {
1325     DDebug(s_libName.c_str(),DebugAll,"ASNObjId() created from AsnMib [%p]",mib);
1326     if (mib) {
1327 	m_name = mib->getName();
1328 	m_value = mib->getOID();
1329     }
1330 }
1331 
~ASNObjId()1332 ASNObjId::~ASNObjId()
1333 {
1334     m_ids.clear();
1335 }
1336 
toDataBlock()1337 void ASNObjId::toDataBlock()
1338 {
1339     DDebug(s_libName.c_str(),DebugAll,"ASNObjId::toDataBlock() '%s'", m_value.c_str());
1340     m_ids.clear();
1341     ObjList* list = m_value.split('.',false);
1342     if (list) {
1343     	for (ObjList* o = list->skipNull(); o; o = o->skipNext()) {
1344     	    String* s = static_cast<String*>(o->get());
1345     	    int val = s->toInteger();
1346     	    if (val < 128)
1347 	    	m_ids.append(&val, 1);
1348 	    else {
1349 	        DataBlock db;
1350 	        int size = sizeof(int);
1351 	        uint8_t v = val;
1352 	        v = v & 0x7f;
1353 	        db.append(&v,1);
1354 	        size--;
1355 	        val = val >> 7;
1356 	        while (val != 0) {
1357 		    v = val;
1358 		    v = v & 0x7f;
1359 		    v = v | 0x80;
1360 		    DataBlock tmp;
1361 		    tmp.append(&v,1);
1362 		    db.insert(tmp);
1363 		    size--;
1364 		    val = val >> 7;
1365 	    	}
1366 	    	m_ids.append(db);
1367     	    }
1368 	}
1369 	TelEngine::destruct(list);
1370     }
1371 }
1372 
getIds()1373 DataBlock ASNObjId::getIds()
1374 {
1375     toDataBlock();
1376     return m_ids;
1377 }
1378 
1379 /**
1380   * AsnMib
1381   */
1382 TokenDict AsnMib::s_access[] = {
1383     {"accessible-for-notify",	AsnMib::accessibleForNotify},
1384     {"read-only",		AsnMib::readOnly},
1385     {"read-write", 		AsnMib::readWrite},
1386     {"read-create",		AsnMib::readCreate},
1387     {0,0}
1388 };
1389 
AsnMib(NamedList & params)1390 AsnMib::AsnMib(NamedList& params)
1391 {
1392     if (!params)
1393 	return;
1394     m_index = 0;
1395     m_oid = params;
1396     m_name = params.getValue("name","");
1397     m_access = params.getValue("access","");
1398     m_accessVal = lookup(m_access,s_access,0);
1399     m_type = params.getValue("type","");
1400     m_revision = params.getValue("revision","");
1401     XDebug(s_libName.c_str(),DebugAll,"new AsnMib created with oid : '%s', access : '%s', type : '%s'",
1402 	    m_oid.c_str(),m_access.c_str(),m_type.c_str());
1403 }
1404 
compareTo(AsnMib * mib)1405 int AsnMib::compareTo(AsnMib* mib)
1406 {
1407     if (!mib)
1408 	return 1;
1409     DDebug(s_libName,DebugInfo,"AsnMib::compareTo('%s'='%s' [%p]) this=%s[%s] [%p]",
1410     		mib->getName().c_str(),mib->toString().c_str(),mib,getName().c_str(),toString().c_str(),this);
1411 
1412     // they're equal
1413     if (toString() == mib->toString())
1414     	return 0;
1415 
1416     ObjList* myIDs = toString().split('.',false);
1417     ObjList* mibIDs = mib->toString().split('.',false);
1418 
1419     ObjList* o1 = myIDs->skipNull();
1420     ObjList* o2 = mibIDs->skipNull();
1421     while (o1 && o2) {
1422     	String* str1 = static_cast<String*>(o1->get());
1423     	o1 = o1->skipNext();
1424     	String* str2 = static_cast<String*>(o2->get());
1425     	o2 = o2->skipNext();
1426     	int diff = str1->toInteger() - str2->toInteger();
1427     	if (diff == 0)
1428     	    continue;
1429     	if (diff > 0) {
1430     	    TelEngine::destruct(myIDs);
1431     	    TelEngine::destruct(mibIDs);
1432     	    return 1;
1433     	}
1434     	if (diff < 0) {
1435     	    TelEngine::destruct(myIDs);
1436     	    TelEngine::destruct(mibIDs);
1437     	    return -1;
1438     	}
1439     }
1440 
1441     int retValue = 0;
1442     if (!o1)
1443     	retValue = -1;
1444     else if (!o2)
1445     	retValue = 1;
1446     TelEngine::destruct(myIDs);
1447     TelEngine::destruct(mibIDs);
1448     return retValue;
1449 }
1450 
1451 /* vi: set ts=8 sw=4 sts=4 noet: */
1452