-
Notifications
You must be signed in to change notification settings - Fork 26
/
ber.js
119 lines (112 loc) · 3.08 KB
/
ber.js
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
paramikojs.BER = function (content) {
this.content = content;
this.idx = 0;
}
paramikojs.BER.prototype = {
toString : function() {
return this.content;
},
decode : function() {
return this.decode_next();
},
decode_next : function() {
if (this.idx >= this.content.length) {
return null;
}
var ident = this.content[this.idx].charCodeAt(0);
var t;
this.idx += 1;
if ((ident & 31) == 31) {
// identifier > 30
ident = 0;
while (this.idx < this.content.length) {
t = this.content[this.idx].charCodeAt(0);
this.idx += 1;
ident = (ident << 7) | (t & 0x7f);
if (!(t & 0x80)) {
break;
}
}
}
if (this.idx >= this.content.length) {
return null;
}
// now fetch length
var size = this.content[this.idx].charCodeAt(0);
this.idx += 1;
if (size & 0x80) {
// more complimicated...
// FIXME: theoretically should handle indefinite-length (0x80)
t = size & 0x7f;
if (this.idx + t > this.content.length) {
return null;
}
size = paramikojs.util.inflate_long(this.content.substring(this.idx, this.idx + t), true).intValue();
this.idx += t;
}
if (this.idx + size > this.content.length) {
// can't fit
return null;
}
var data = this.content.substring(this.idx, this.idx + size);
this.idx += size;
// now switch on id
if (ident == 0x30) {
// sequence
return this.decode_sequence(data);
} else if (ident == 2) {
// int
return paramikojs.util.inflate_long(data);
} else {
// 1: boolean (00 false, otherwise true)
throw new paramikojs.ssh_exception.BERException('Unknown ber encoding type ' + ident + ' (robey is lazy)');
}
},
decode_sequence : function(data) {
var out = [];
var b = new paramikojs.BER(data);
while (true) {
var x = b.decode_next();
if (!x) {
break;
}
out.push(x);
}
return out;
},
encode_tlv : function(ident, val) {
// no need to support ident > 31 here
this.content += String.fromCharCode(ident);
if (val.length > 0x7f) {
var lenstr = paramikojs.util.deflate_long(val.length);
this.content += String.fromCharCode(0x80 + lenstr.length) + lenstr;
} else {
this.content += String.fromCharCode(val.length);
}
this.content += val;
},
encode : function(x) {
if (typeof x == "boolean") {
if (x) {
this.encode_tlv(1, '\xff');
} else {
this.encode_tlv(1, '\x00');
}
} else if (typeof x == "number") {
this.encode_tlv(2, paramikojs.util.deflate_long(x));
} else if (typeof x == "string") {
this.encode_tlv(4, x);
} else if (x instanceof Array) {
this.encode_tlv(0x30, this.encode_sequence(x));
} else {
throw new paramikojs.ssh_exception.BERException('Unknown type for encoding: ' + typeof x);
}
},
encode_sequence : function(data) {
var b = new paramikojs.BER();
for (var x = 0; x < data.length; ++x) {
b.encode(data[x]);
}
return str(b);
}
};