Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MR414N-ID
GitHub Repository: MR414N-ID/botku2
Path: blob/master/node_modules/asn1/lib/ber/reader.js
1126 views
1
// Copyright 2011 Mark Cavage <[email protected]> All rights reserved.
2
3
var assert = require('assert');
4
var Buffer = require('safer-buffer').Buffer;
5
6
var ASN1 = require('./types');
7
var errors = require('./errors');
8
9
10
// --- Globals
11
12
var newInvalidAsn1Error = errors.newInvalidAsn1Error;
13
14
15
16
// --- API
17
18
function Reader(data) {
19
if (!data || !Buffer.isBuffer(data))
20
throw new TypeError('data must be a node Buffer');
21
22
this._buf = data;
23
this._size = data.length;
24
25
// These hold the "current" state
26
this._len = 0;
27
this._offset = 0;
28
}
29
30
Object.defineProperty(Reader.prototype, 'length', {
31
enumerable: true,
32
get: function () { return (this._len); }
33
});
34
35
Object.defineProperty(Reader.prototype, 'offset', {
36
enumerable: true,
37
get: function () { return (this._offset); }
38
});
39
40
Object.defineProperty(Reader.prototype, 'remain', {
41
get: function () { return (this._size - this._offset); }
42
});
43
44
Object.defineProperty(Reader.prototype, 'buffer', {
45
get: function () { return (this._buf.slice(this._offset)); }
46
});
47
48
49
/**
50
* Reads a single byte and advances offset; you can pass in `true` to make this
51
* a "peek" operation (i.e., get the byte, but don't advance the offset).
52
*
53
* @param {Boolean} peek true means don't move offset.
54
* @return {Number} the next byte, null if not enough data.
55
*/
56
Reader.prototype.readByte = function (peek) {
57
if (this._size - this._offset < 1)
58
return null;
59
60
var b = this._buf[this._offset] & 0xff;
61
62
if (!peek)
63
this._offset += 1;
64
65
return b;
66
};
67
68
69
Reader.prototype.peek = function () {
70
return this.readByte(true);
71
};
72
73
74
/**
75
* Reads a (potentially) variable length off the BER buffer. This call is
76
* not really meant to be called directly, as callers have to manipulate
77
* the internal buffer afterwards.
78
*
79
* As a result of this call, you can call `Reader.length`, until the
80
* next thing called that does a readLength.
81
*
82
* @return {Number} the amount of offset to advance the buffer.
83
* @throws {InvalidAsn1Error} on bad ASN.1
84
*/
85
Reader.prototype.readLength = function (offset) {
86
if (offset === undefined)
87
offset = this._offset;
88
89
if (offset >= this._size)
90
return null;
91
92
var lenB = this._buf[offset++] & 0xff;
93
if (lenB === null)
94
return null;
95
96
if ((lenB & 0x80) === 0x80) {
97
lenB &= 0x7f;
98
99
if (lenB === 0)
100
throw newInvalidAsn1Error('Indefinite length not supported');
101
102
if (lenB > 4)
103
throw newInvalidAsn1Error('encoding too long');
104
105
if (this._size - offset < lenB)
106
return null;
107
108
this._len = 0;
109
for (var i = 0; i < lenB; i++)
110
this._len = (this._len << 8) + (this._buf[offset++] & 0xff);
111
112
} else {
113
// Wasn't a variable length
114
this._len = lenB;
115
}
116
117
return offset;
118
};
119
120
121
/**
122
* Parses the next sequence in this BER buffer.
123
*
124
* To get the length of the sequence, call `Reader.length`.
125
*
126
* @return {Number} the sequence's tag.
127
*/
128
Reader.prototype.readSequence = function (tag) {
129
var seq = this.peek();
130
if (seq === null)
131
return null;
132
if (tag !== undefined && tag !== seq)
133
throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
134
': got 0x' + seq.toString(16));
135
136
var o = this.readLength(this._offset + 1); // stored in `length`
137
if (o === null)
138
return null;
139
140
this._offset = o;
141
return seq;
142
};
143
144
145
Reader.prototype.readInt = function () {
146
return this._readTag(ASN1.Integer);
147
};
148
149
150
Reader.prototype.readBoolean = function () {
151
return (this._readTag(ASN1.Boolean) === 0 ? false : true);
152
};
153
154
155
Reader.prototype.readEnumeration = function () {
156
return this._readTag(ASN1.Enumeration);
157
};
158
159
160
Reader.prototype.readString = function (tag, retbuf) {
161
if (!tag)
162
tag = ASN1.OctetString;
163
164
var b = this.peek();
165
if (b === null)
166
return null;
167
168
if (b !== tag)
169
throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
170
': got 0x' + b.toString(16));
171
172
var o = this.readLength(this._offset + 1); // stored in `length`
173
174
if (o === null)
175
return null;
176
177
if (this.length > this._size - o)
178
return null;
179
180
this._offset = o;
181
182
if (this.length === 0)
183
return retbuf ? Buffer.alloc(0) : '';
184
185
var str = this._buf.slice(this._offset, this._offset + this.length);
186
this._offset += this.length;
187
188
return retbuf ? str : str.toString('utf8');
189
};
190
191
Reader.prototype.readOID = function (tag) {
192
if (!tag)
193
tag = ASN1.OID;
194
195
var b = this.readString(tag, true);
196
if (b === null)
197
return null;
198
199
var values = [];
200
var value = 0;
201
202
for (var i = 0; i < b.length; i++) {
203
var byte = b[i] & 0xff;
204
205
value <<= 7;
206
value += byte & 0x7f;
207
if ((byte & 0x80) === 0) {
208
values.push(value);
209
value = 0;
210
}
211
}
212
213
value = values.shift();
214
values.unshift(value % 40);
215
values.unshift((value / 40) >> 0);
216
217
return values.join('.');
218
};
219
220
221
Reader.prototype._readTag = function (tag) {
222
assert.ok(tag !== undefined);
223
224
var b = this.peek();
225
226
if (b === null)
227
return null;
228
229
if (b !== tag)
230
throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
231
': got 0x' + b.toString(16));
232
233
var o = this.readLength(this._offset + 1); // stored in `length`
234
if (o === null)
235
return null;
236
237
if (this.length > 4)
238
throw newInvalidAsn1Error('Integer too long: ' + this.length);
239
240
if (this.length > this._size - o)
241
return null;
242
this._offset = o;
243
244
var fb = this._buf[this._offset];
245
var value = 0;
246
247
for (var i = 0; i < this.length; i++) {
248
value <<= 8;
249
value |= (this._buf[this._offset++] & 0xff);
250
}
251
252
if ((fb & 0x80) === 0x80 && i !== 4)
253
value -= (1 << (i * 8));
254
255
return value >> 0;
256
};
257
258
259
260
// --- Exported API
261
262
module.exports = Reader;
263
264