@file-viewer/renderer-ofd 2.1.23 → 2.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +1 -0
- package/README.md +1 -0
- package/dist/ofd.js +10 -4
- package/package.json +5 -3
- package/vendor/dltech/ofd/ofd_parser.js +136 -18
- package/vendor/dltech/ofd/ofd_render.js +9 -9
- package/vendor/dltech/ofd/ofd_util.js +16 -5
- package/vendor/dltech/ofd/ses_signature_parser.js +196 -0
- package/vendor/lapo-asn1js/README.md +3 -0
- package/vendor/lapo-asn1js/asn1.js +525 -0
- package/vendor/lapo-asn1js/base64.js +82 -0
- package/vendor/lapo-asn1js/hex.js +51 -0
- package/vendor/lapo-asn1js/int10.js +90 -0
- package/vendor/lapo-asn1js/oids.js +2455 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
import Int10 from './int10.js';
|
|
2
|
+
import oids from './oids.js';
|
|
3
|
+
var
|
|
4
|
+
ellipsis = "\u2026",
|
|
5
|
+
reTimeS = /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/,
|
|
6
|
+
reTimeL = /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/;
|
|
7
|
+
|
|
8
|
+
function stringCut(str, len) {
|
|
9
|
+
if (str.length > len)
|
|
10
|
+
str = str.substring(0, len) + ellipsis;
|
|
11
|
+
return str;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function Stream(enc, pos) {
|
|
15
|
+
if (enc instanceof Stream) {
|
|
16
|
+
this.enc = enc.enc;
|
|
17
|
+
this.pos = enc.pos;
|
|
18
|
+
} else {
|
|
19
|
+
// enc should be an array or a binary string
|
|
20
|
+
this.enc = enc;
|
|
21
|
+
this.pos = pos;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
Stream.prototype.get = function (pos) {
|
|
25
|
+
if (pos === undefined)
|
|
26
|
+
pos = this.pos++;
|
|
27
|
+
if (pos >= this.enc.length)
|
|
28
|
+
throw 'Requesting byte offset ' + pos + ' on a stream of length ' + this.enc.length;
|
|
29
|
+
return (typeof this.enc == "string") ? this.enc.charCodeAt(pos) : this.enc[pos];
|
|
30
|
+
};
|
|
31
|
+
Stream.prototype.hexDigits = "0123456789ABCDEF";
|
|
32
|
+
Stream.prototype.hexByte = function (b) {
|
|
33
|
+
return this.hexDigits.charAt((b >> 4) & 0xF) + this.hexDigits.charAt(b & 0xF);
|
|
34
|
+
};
|
|
35
|
+
Stream.prototype.hexDump = function (start, end, raw) {
|
|
36
|
+
var s = "";
|
|
37
|
+
for (var i = start; i < end; ++i) {
|
|
38
|
+
s += this.hexByte(this.get(i));
|
|
39
|
+
if (raw !== true)
|
|
40
|
+
switch (i & 0xF) {
|
|
41
|
+
case 0x7: s += " "; break;
|
|
42
|
+
case 0xF: s += "\n"; break;
|
|
43
|
+
default: s += " ";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return s;
|
|
47
|
+
};
|
|
48
|
+
var b64Safe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
49
|
+
Stream.prototype.b64Dump = function (start, end) {
|
|
50
|
+
var extra = (end - start) % 3,
|
|
51
|
+
s = '',
|
|
52
|
+
i, c;
|
|
53
|
+
for (i = start; i + 2 < end; i += 3) {
|
|
54
|
+
c = this.get(i) << 16 | this.get(i + 1) << 8 | this.get(i + 2);
|
|
55
|
+
s += b64Safe.charAt(c >> 18 & 0x3F);
|
|
56
|
+
s += b64Safe.charAt(c >> 12 & 0x3F);
|
|
57
|
+
s += b64Safe.charAt(c >> 6 & 0x3F);
|
|
58
|
+
s += b64Safe.charAt(c & 0x3F);
|
|
59
|
+
}
|
|
60
|
+
if (extra > 0) {
|
|
61
|
+
c = this.get(i) << 16;
|
|
62
|
+
if (extra > 1) c |= this.get(i + 1) << 8;
|
|
63
|
+
s += b64Safe.charAt(c >> 18 & 0x3F);
|
|
64
|
+
s += b64Safe.charAt(c >> 12 & 0x3F);
|
|
65
|
+
if (extra == 2) s += b64Safe.charAt(c >> 6 & 0x3F);
|
|
66
|
+
}
|
|
67
|
+
return s;
|
|
68
|
+
};
|
|
69
|
+
Stream.prototype.isASCII = function (start, end) {
|
|
70
|
+
for (var i = start; i < end; ++i) {
|
|
71
|
+
var c = this.get(i);
|
|
72
|
+
if (c < 32 || c > 176)
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
};
|
|
77
|
+
Stream.prototype.parseStringISO = function (start, end) {
|
|
78
|
+
var s = "";
|
|
79
|
+
for (var i = start; i < end; ++i)
|
|
80
|
+
s += String.fromCharCode(this.get(i));
|
|
81
|
+
return s;
|
|
82
|
+
};
|
|
83
|
+
Stream.prototype.parseStringUTF = function (start, end) {
|
|
84
|
+
function ex(c) { // must be 10xxxxxx
|
|
85
|
+
if ((c < 0x80) || (c >= 0xC0))
|
|
86
|
+
throw new Error('Invalid UTF-8 continuation byte: ' + c);
|
|
87
|
+
return (c & 0x3F);
|
|
88
|
+
}
|
|
89
|
+
function surrogate(cp) {
|
|
90
|
+
if (cp < 0x10000)
|
|
91
|
+
throw new Error('UTF-8 overlong encoding, codepoint encoded in 4 bytes: ' + cp);
|
|
92
|
+
// we could use String.fromCodePoint(cp) but let's be nice to older browsers and use surrogate pairs
|
|
93
|
+
cp -= 0x10000;
|
|
94
|
+
return String.fromCharCode((cp >> 10) + 0xD800, (cp & 0x3FF) + 0xDC00);
|
|
95
|
+
}
|
|
96
|
+
var s = "";
|
|
97
|
+
for (var i = start; i < end; ) {
|
|
98
|
+
var c = this.get(i++);
|
|
99
|
+
if (c < 0x80) // 0xxxxxxx (7 bit)
|
|
100
|
+
s += String.fromCharCode(c);
|
|
101
|
+
else if (c < 0xC0)
|
|
102
|
+
throw new Error('Invalid UTF-8 starting byte: ' + c);
|
|
103
|
+
else if (c < 0xE0) // 110xxxxx 10xxxxxx (11 bit)
|
|
104
|
+
s += String.fromCharCode(((c & 0x1F) << 6) | ex(this.get(i++)));
|
|
105
|
+
else if (c < 0xF0) // 1110xxxx 10xxxxxx 10xxxxxx (16 bit)
|
|
106
|
+
s += String.fromCharCode(((c & 0x0F) << 12) | (ex(this.get(i++)) << 6) | ex(this.get(i++)));
|
|
107
|
+
else if (c < 0xF8) // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (21 bit)
|
|
108
|
+
s += surrogate(((c & 0x07) << 18) | (ex(this.get(i++)) << 12) | (ex(this.get(i++)) << 6) | ex(this.get(i++)));
|
|
109
|
+
else
|
|
110
|
+
throw new Error('Invalid UTF-8 starting byte (since 2003 it is restricted to 4 bytes): ' + c);
|
|
111
|
+
}
|
|
112
|
+
return s;
|
|
113
|
+
};
|
|
114
|
+
Stream.prototype.parseStringBMP = function (start, end) {
|
|
115
|
+
var str = "", hi, lo;
|
|
116
|
+
for (var i = start; i < end; ) {
|
|
117
|
+
hi = this.get(i++);
|
|
118
|
+
lo = this.get(i++);
|
|
119
|
+
str += String.fromCharCode((hi << 8) | lo);
|
|
120
|
+
}
|
|
121
|
+
return str;
|
|
122
|
+
};
|
|
123
|
+
Stream.prototype.parseTime = function (start, end, shortYear) {
|
|
124
|
+
var s = this.parseStringISO(start, end),
|
|
125
|
+
m = (shortYear ? reTimeS : reTimeL).exec(s);
|
|
126
|
+
if (!m)
|
|
127
|
+
return "Unrecognized time: " + s;
|
|
128
|
+
if (shortYear) {
|
|
129
|
+
// to avoid querying the timer, use the fixed range [1970, 2069]
|
|
130
|
+
// it will conform with ITU X.400 [-10, +40] sliding window until 2030
|
|
131
|
+
m[1] = +m[1];
|
|
132
|
+
m[1] += (m[1] < 70) ? 2000 : 1900;
|
|
133
|
+
}
|
|
134
|
+
s = m[1] + "-" + m[2] + "-" + m[3] + " " + m[4];
|
|
135
|
+
if (m[5]) {
|
|
136
|
+
s += ":" + m[5];
|
|
137
|
+
if (m[6]) {
|
|
138
|
+
s += ":" + m[6];
|
|
139
|
+
if (m[7])
|
|
140
|
+
s += "." + m[7];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (m[8]) {
|
|
144
|
+
s += " UTC";
|
|
145
|
+
if (m[8] != 'Z') {
|
|
146
|
+
s += m[8];
|
|
147
|
+
if (m[9])
|
|
148
|
+
s += ":" + m[9];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return s;
|
|
152
|
+
};
|
|
153
|
+
Stream.prototype.parseInteger = function (start, end) {
|
|
154
|
+
var v = this.get(start),
|
|
155
|
+
neg = (v > 127),
|
|
156
|
+
pad = neg ? 255 : 0,
|
|
157
|
+
len,
|
|
158
|
+
s = '';
|
|
159
|
+
// skip unuseful bits (not allowed in DER)
|
|
160
|
+
while (v == pad && ++start < end)
|
|
161
|
+
v = this.get(start);
|
|
162
|
+
len = end - start;
|
|
163
|
+
if (len === 0)
|
|
164
|
+
return neg ? '-1' : '0';
|
|
165
|
+
// show bit length of huge integers
|
|
166
|
+
if (len > 4) {
|
|
167
|
+
s = v;
|
|
168
|
+
len <<= 3;
|
|
169
|
+
while (((s ^ pad) & 0x80) == 0) {
|
|
170
|
+
s <<= 1;
|
|
171
|
+
--len;
|
|
172
|
+
}
|
|
173
|
+
s = "(" + len + " bit)\n";
|
|
174
|
+
}
|
|
175
|
+
// decode the integer
|
|
176
|
+
if (neg) v = v - 256;
|
|
177
|
+
var n = new Int10(v);
|
|
178
|
+
for (var i = start + 1; i < end; ++i)
|
|
179
|
+
n.mulAdd(256, this.get(i));
|
|
180
|
+
return s + n.toString();
|
|
181
|
+
};
|
|
182
|
+
Stream.prototype.parseBitString = function (start, end, maxLength) {
|
|
183
|
+
var unusedBits = this.get(start);
|
|
184
|
+
if (unusedBits > 7)
|
|
185
|
+
throw 'Invalid BitString with unusedBits=' + unusedBits;
|
|
186
|
+
var lenBit = ((end - start - 1) << 3) - unusedBits,
|
|
187
|
+
s = "";
|
|
188
|
+
for (var i = start + 1; i < end; ++i) {
|
|
189
|
+
var b = this.get(i),
|
|
190
|
+
skip = (i == end - 1) ? unusedBits : 0;
|
|
191
|
+
for (var j = 7; j >= skip; --j)
|
|
192
|
+
s += (b >> j) & 1 ? "1" : "0";
|
|
193
|
+
if (s.length > maxLength)
|
|
194
|
+
s = stringCut(s, maxLength);
|
|
195
|
+
}
|
|
196
|
+
return { size: lenBit, str: s };
|
|
197
|
+
};
|
|
198
|
+
Stream.prototype.parseOctetString = function (start, end, maxLength) {
|
|
199
|
+
var len = end - start,
|
|
200
|
+
s;
|
|
201
|
+
try {
|
|
202
|
+
s = this.parseStringUTF(start, end);
|
|
203
|
+
var v;
|
|
204
|
+
for (i = 0; i < s.length; ++i) {
|
|
205
|
+
v = s.charCodeAt(i);
|
|
206
|
+
if (v < 32 && v != 9 && v != 10 && v != 13) // [\t\r\n] are (kinda) printable
|
|
207
|
+
throw new Error('Unprintable character at index ' + i + ' (code ' + s.charCodeAt(i) + ")");
|
|
208
|
+
}
|
|
209
|
+
return { size: len, str: s };
|
|
210
|
+
} catch (e) {
|
|
211
|
+
// ignore
|
|
212
|
+
}
|
|
213
|
+
maxLength /= 2; // we work in bytes
|
|
214
|
+
if (len > maxLength)
|
|
215
|
+
end = start + maxLength;
|
|
216
|
+
s = '';
|
|
217
|
+
for (var i = start; i < end; ++i)
|
|
218
|
+
s += this.hexByte(this.get(i));
|
|
219
|
+
if (len > maxLength)
|
|
220
|
+
s += ellipsis;
|
|
221
|
+
return { size: len, str: s };
|
|
222
|
+
};
|
|
223
|
+
Stream.prototype.parseOID = function (start, end, maxLength) {
|
|
224
|
+
var s = '',
|
|
225
|
+
n = new Int10(),
|
|
226
|
+
bits = 0;
|
|
227
|
+
for (var i = start; i < end; ++i) {
|
|
228
|
+
var v = this.get(i);
|
|
229
|
+
n.mulAdd(128, v & 0x7F);
|
|
230
|
+
bits += 7;
|
|
231
|
+
if (!(v & 0x80)) { // finished
|
|
232
|
+
if (s === '') {
|
|
233
|
+
n = n.simplify();
|
|
234
|
+
if (n instanceof Int10) {
|
|
235
|
+
n.sub(80);
|
|
236
|
+
s = "2." + n.toString();
|
|
237
|
+
} else {
|
|
238
|
+
var m = n < 80 ? n < 40 ? 0 : 1 : 2;
|
|
239
|
+
s = m + "." + (n - m * 40);
|
|
240
|
+
}
|
|
241
|
+
} else
|
|
242
|
+
s += "." + n.toString();
|
|
243
|
+
if (s.length > maxLength)
|
|
244
|
+
return stringCut(s, maxLength);
|
|
245
|
+
n = new Int10();
|
|
246
|
+
bits = 0;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (bits > 0)
|
|
250
|
+
s += ".incomplete";
|
|
251
|
+
if (typeof oids === 'object') {
|
|
252
|
+
var oid = oids[s];
|
|
253
|
+
if (oid) {
|
|
254
|
+
if (oid.d) s += "\n" + oid.d;
|
|
255
|
+
if (oid.c) s += "\n" + oid.c;
|
|
256
|
+
if (oid.w) s += "\n(warning!)";
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return s;
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
function ASN1(stream, header, length, tag, tagLen, sub) {
|
|
263
|
+
if (!(tag instanceof ASN1Tag)) throw 'Invalid tag value.';
|
|
264
|
+
this.stream = stream;
|
|
265
|
+
this.header = header;
|
|
266
|
+
this.length = length;
|
|
267
|
+
this.tag = tag;
|
|
268
|
+
this.tagLen = tagLen;
|
|
269
|
+
this.sub = sub;
|
|
270
|
+
}
|
|
271
|
+
ASN1.prototype.typeName = function () {
|
|
272
|
+
switch (this.tag.tagClass) {
|
|
273
|
+
case 0: // universal
|
|
274
|
+
switch (this.tag.tagNumber) {
|
|
275
|
+
case 0x00: return "EOC";
|
|
276
|
+
case 0x01: return "BOOLEAN";
|
|
277
|
+
case 0x02: return "INTEGER";
|
|
278
|
+
case 0x03: return "BIT_STRING";
|
|
279
|
+
case 0x04: return "OCTET_STRING";
|
|
280
|
+
case 0x05: return "NULL";
|
|
281
|
+
case 0x06: return "OBJECT_IDENTIFIER";
|
|
282
|
+
case 0x07: return "ObjectDescriptor";
|
|
283
|
+
case 0x08: return "EXTERNAL";
|
|
284
|
+
case 0x09: return "REAL";
|
|
285
|
+
case 0x0A: return "ENUMERATED";
|
|
286
|
+
case 0x0B: return "EMBEDDED_PDV";
|
|
287
|
+
case 0x0C: return "UTF8String";
|
|
288
|
+
case 0x10: return "SEQUENCE";
|
|
289
|
+
case 0x11: return "SET";
|
|
290
|
+
case 0x12: return "NumericString";
|
|
291
|
+
case 0x13: return "PrintableString"; // ASCII subset
|
|
292
|
+
case 0x14: return "TeletexString"; // aka T61String
|
|
293
|
+
case 0x15: return "VideotexString";
|
|
294
|
+
case 0x16: return "IA5String"; // ASCII
|
|
295
|
+
case 0x17: return "UTCTime";
|
|
296
|
+
case 0x18: return "GeneralizedTime";
|
|
297
|
+
case 0x19: return "GraphicString";
|
|
298
|
+
case 0x1A: return "VisibleString"; // ASCII subset
|
|
299
|
+
case 0x1B: return "GeneralString";
|
|
300
|
+
case 0x1C: return "UniversalString";
|
|
301
|
+
case 0x1E: return "BMPString";
|
|
302
|
+
}
|
|
303
|
+
return "Universal_" + this.tag.tagNumber.toString();
|
|
304
|
+
case 1: return "Application_" + this.tag.tagNumber.toString();
|
|
305
|
+
case 2: return "[" + this.tag.tagNumber.toString() + "]"; // Context
|
|
306
|
+
case 3: return "Private_" + this.tag.tagNumber.toString();
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
function recurse(el, parser, maxLength) {
|
|
310
|
+
var differentTags = false;
|
|
311
|
+
if (el.sub) el.sub.forEach(function (e1) {
|
|
312
|
+
if (e1.tag.tagClass != el.tag.tagClass || e1.tag.tagNumber != el.tag.tagNumber)
|
|
313
|
+
differentTags = true;
|
|
314
|
+
});
|
|
315
|
+
if (!el.sub || differentTags)
|
|
316
|
+
return el.stream[parser](el.posContent(), el.posContent() + Math.abs(el.length), maxLength);
|
|
317
|
+
var d = { size: 0, str: '' };
|
|
318
|
+
el.sub.forEach(function (el) {
|
|
319
|
+
var d1 = recurse(el, parser, maxLength - d.str.length);
|
|
320
|
+
d.size += d1.size;
|
|
321
|
+
d.str += d1.str;
|
|
322
|
+
});
|
|
323
|
+
return d;
|
|
324
|
+
}
|
|
325
|
+
/** A string preview of the content (intended for humans). */
|
|
326
|
+
ASN1.prototype.content = function (maxLength) {
|
|
327
|
+
if (this.tag === undefined)
|
|
328
|
+
return null;
|
|
329
|
+
if (maxLength === undefined)
|
|
330
|
+
maxLength = Infinity;
|
|
331
|
+
var content = this.posContent(),
|
|
332
|
+
len = Math.abs(this.length);
|
|
333
|
+
if (!this.tag.isUniversal()) {
|
|
334
|
+
if (this.sub !== null)
|
|
335
|
+
return "(" + this.sub.length + " elem)";
|
|
336
|
+
var d1 = this.stream.parseOctetString(content, content + len, maxLength);
|
|
337
|
+
return "(" + d1.size + " byte)\n" + d1.str;
|
|
338
|
+
}
|
|
339
|
+
switch (this.tag.tagNumber) {
|
|
340
|
+
case 0x01: // BOOLEAN
|
|
341
|
+
return (this.stream.get(content) === 0) ? "false" : "true";
|
|
342
|
+
case 0x02: // INTEGER
|
|
343
|
+
return this.stream.parseInteger(content, content + len);
|
|
344
|
+
case 0x03: // BIT_STRING
|
|
345
|
+
var d = recurse(this, 'parseBitString', maxLength);
|
|
346
|
+
return "(" + d.size + " bit)\n" + d.str;
|
|
347
|
+
case 0x04: // OCTET_STRING
|
|
348
|
+
d = recurse(this, 'parseOctetString', maxLength);
|
|
349
|
+
return "(" + d.size + " byte)\n" + d.str;
|
|
350
|
+
//case 0x05: // NULL
|
|
351
|
+
case 0x06: // OBJECT_IDENTIFIER
|
|
352
|
+
return this.stream.parseOID(content, content + len, maxLength);
|
|
353
|
+
//case 0x07: // ObjectDescriptor
|
|
354
|
+
//case 0x08: // EXTERNAL
|
|
355
|
+
//case 0x09: // REAL
|
|
356
|
+
case 0x0A: // ENUMERATED
|
|
357
|
+
return this.stream.parseInteger(content, content + len);
|
|
358
|
+
//case 0x0B: // EMBEDDED_PDV
|
|
359
|
+
case 0x10: // SEQUENCE
|
|
360
|
+
case 0x11: // SET
|
|
361
|
+
if (this.sub !== null)
|
|
362
|
+
return "(" + this.sub.length + " elem)";
|
|
363
|
+
else
|
|
364
|
+
return "(no elem)";
|
|
365
|
+
case 0x0C: // UTF8String
|
|
366
|
+
return stringCut(this.stream.parseStringUTF(content, content + len), maxLength);
|
|
367
|
+
case 0x12: // NumericString
|
|
368
|
+
case 0x13: // PrintableString
|
|
369
|
+
case 0x14: // TeletexString
|
|
370
|
+
case 0x15: // VideotexString
|
|
371
|
+
case 0x16: // IA5String
|
|
372
|
+
case 0x1A: // VisibleString
|
|
373
|
+
case 0x1B: // GeneralString
|
|
374
|
+
//case 0x19: // GraphicString
|
|
375
|
+
//case 0x1C: // UniversalString
|
|
376
|
+
return stringCut(this.stream.parseStringISO(content, content + len), maxLength);
|
|
377
|
+
case 0x1E: // BMPString
|
|
378
|
+
return stringCut(this.stream.parseStringBMP(content, content + len), maxLength);
|
|
379
|
+
case 0x17: // UTCTime
|
|
380
|
+
case 0x18: // GeneralizedTime
|
|
381
|
+
return this.stream.parseTime(content, content + len, (this.tag.tagNumber == 0x17));
|
|
382
|
+
}
|
|
383
|
+
return null;
|
|
384
|
+
};
|
|
385
|
+
ASN1.prototype.toString = function () {
|
|
386
|
+
return this.typeName() + "@" + this.stream.pos + "[header:" + this.header + ",length:" + this.length + ",sub:" + ((this.sub === null) ? 'null' : this.sub.length) + "]";
|
|
387
|
+
};
|
|
388
|
+
ASN1.prototype.toPrettyString = function (indent) {
|
|
389
|
+
if (indent === undefined) indent = '';
|
|
390
|
+
var s = indent + this.typeName() + " @" + this.stream.pos;
|
|
391
|
+
if (this.length >= 0)
|
|
392
|
+
s += "+";
|
|
393
|
+
s += this.length;
|
|
394
|
+
if (this.tag.tagConstructed)
|
|
395
|
+
s += " (constructed)";
|
|
396
|
+
else if ((this.tag.isUniversal() && ((this.tag.tagNumber == 0x03) || (this.tag.tagNumber == 0x04))) && (this.sub !== null))
|
|
397
|
+
s += " (encapsulates)";
|
|
398
|
+
var content = this.content();
|
|
399
|
+
if (content)
|
|
400
|
+
s += ": " + content.replace(/\n/g, '|');
|
|
401
|
+
s += "\n";
|
|
402
|
+
if (this.sub !== null) {
|
|
403
|
+
indent += ' ';
|
|
404
|
+
for (var i = 0, max = this.sub.length; i < max; ++i)
|
|
405
|
+
s += this.sub[i].toPrettyString(indent);
|
|
406
|
+
}
|
|
407
|
+
return s;
|
|
408
|
+
};
|
|
409
|
+
ASN1.prototype.posStart = function () {
|
|
410
|
+
return this.stream.pos;
|
|
411
|
+
};
|
|
412
|
+
ASN1.prototype.posContent = function () {
|
|
413
|
+
return this.stream.pos + this.header;
|
|
414
|
+
};
|
|
415
|
+
ASN1.prototype.posEnd = function () {
|
|
416
|
+
return this.stream.pos + this.header + Math.abs(this.length);
|
|
417
|
+
};
|
|
418
|
+
/** Position of the length. */
|
|
419
|
+
ASN1.prototype.posLen = function() {
|
|
420
|
+
return this.stream.pos + this.tagLen;
|
|
421
|
+
};
|
|
422
|
+
ASN1.prototype.toHexString = function () {
|
|
423
|
+
return this.stream.hexDump(this.posStart(), this.posEnd(), true);
|
|
424
|
+
};
|
|
425
|
+
ASN1.prototype.toB64String = function () {
|
|
426
|
+
return this.stream.b64Dump(this.posStart(), this.posEnd());
|
|
427
|
+
};
|
|
428
|
+
ASN1.decodeLength = function (stream) {
|
|
429
|
+
var buf = stream.get(),
|
|
430
|
+
len = buf & 0x7F;
|
|
431
|
+
if (len == buf) // first bit was 0, short form
|
|
432
|
+
return len;
|
|
433
|
+
if (len === 0) // long form with length 0 is a special case
|
|
434
|
+
return null; // undefined length
|
|
435
|
+
if (len > 6) // no reason to use Int10, as it would be a huge buffer anyways
|
|
436
|
+
throw "Length over 48 bits not supported at position " + (stream.pos - 1);
|
|
437
|
+
buf = 0;
|
|
438
|
+
for (var i = 0; i < len; ++i)
|
|
439
|
+
buf = (buf * 256) + stream.get();
|
|
440
|
+
return buf;
|
|
441
|
+
};
|
|
442
|
+
function ASN1Tag(stream) {
|
|
443
|
+
var buf = stream.get();
|
|
444
|
+
this.tagClass = buf >> 6;
|
|
445
|
+
this.tagConstructed = ((buf & 0x20) !== 0);
|
|
446
|
+
this.tagNumber = buf & 0x1F;
|
|
447
|
+
if (this.tagNumber == 0x1F) { // long tag
|
|
448
|
+
var n = new Int10();
|
|
449
|
+
do {
|
|
450
|
+
buf = stream.get();
|
|
451
|
+
n.mulAdd(128, buf & 0x7F);
|
|
452
|
+
} while (buf & 0x80);
|
|
453
|
+
this.tagNumber = n.simplify();
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
ASN1Tag.prototype.isUniversal = function () {
|
|
457
|
+
return this.tagClass === 0x00;
|
|
458
|
+
};
|
|
459
|
+
ASN1Tag.prototype.isEOC = function () {
|
|
460
|
+
return this.tagClass === 0x00 && this.tagNumber === 0x00;
|
|
461
|
+
};
|
|
462
|
+
ASN1.decode = function (stream, offset) {
|
|
463
|
+
if (!(stream instanceof Stream))
|
|
464
|
+
stream = new Stream(stream, offset || 0);
|
|
465
|
+
var streamStart = new Stream(stream),
|
|
466
|
+
tag = new ASN1Tag(stream),
|
|
467
|
+
tagLen = stream.pos - streamStart.pos,
|
|
468
|
+
len = ASN1.decodeLength(stream),
|
|
469
|
+
start = stream.pos,
|
|
470
|
+
header = start - streamStart.pos,
|
|
471
|
+
sub = null,
|
|
472
|
+
getSub = function () {
|
|
473
|
+
sub = [];
|
|
474
|
+
if (len !== null) {
|
|
475
|
+
// definite length
|
|
476
|
+
var end = start + len;
|
|
477
|
+
if (end > stream.enc.length)
|
|
478
|
+
throw 'Container at offset ' + start + ' has a length of ' + len + ', which is past the end of the stream';
|
|
479
|
+
while (stream.pos < end)
|
|
480
|
+
sub[sub.length] = ASN1.decode(stream);
|
|
481
|
+
if (stream.pos != end)
|
|
482
|
+
throw 'Content size is not correct for container at offset ' + start;
|
|
483
|
+
} else {
|
|
484
|
+
// undefined length
|
|
485
|
+
try {
|
|
486
|
+
for (;;) {
|
|
487
|
+
var s = ASN1.decode(stream);
|
|
488
|
+
if (s.tag.isEOC())
|
|
489
|
+
break;
|
|
490
|
+
sub[sub.length] = s;
|
|
491
|
+
}
|
|
492
|
+
len = start - stream.pos; // undefined lengths are represented as negative values
|
|
493
|
+
} catch (e) {
|
|
494
|
+
throw 'Exception while decoding undefined length content at offset ' + start + ': ' + e;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
if (tag.tagConstructed) {
|
|
499
|
+
// must have valid content
|
|
500
|
+
getSub();
|
|
501
|
+
} else if (tag.isUniversal() && ((tag.tagNumber == 0x03) || (tag.tagNumber == 0x04))) {
|
|
502
|
+
// sometimes BitString and OctetString are used to encapsulate ASN.1
|
|
503
|
+
try {
|
|
504
|
+
if (tag.tagNumber == 0x03)
|
|
505
|
+
if (stream.get() != 0)
|
|
506
|
+
throw "BIT STRINGs with unused bits cannot encapsulate.";
|
|
507
|
+
getSub();
|
|
508
|
+
for (var i = 0; i < sub.length; ++i)
|
|
509
|
+
if (sub[i].tag.isEOC())
|
|
510
|
+
throw 'EOC is not supposed to be actual content.';
|
|
511
|
+
} catch (e) {
|
|
512
|
+
// but silently ignore when they don't
|
|
513
|
+
sub = null;
|
|
514
|
+
//DEBUG console.log('Could not decode structure at ' + start + ':', e);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (sub === null) {
|
|
518
|
+
if (len === null)
|
|
519
|
+
throw "We can't skip over an invalid tag with undefined length at offset " + start;
|
|
520
|
+
stream.pos = start + Math.abs(len);
|
|
521
|
+
}
|
|
522
|
+
return new ASN1(streamStart, header, len, tag, tagLen, sub);
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
export default ASN1;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
var Base64 = {},
|
|
2
|
+
decoder, // populated on first usage
|
|
3
|
+
haveU8 = (typeof Uint8Array == 'function');
|
|
4
|
+
|
|
5
|
+
Base64.decode = function (a) {
|
|
6
|
+
var isString = (typeof a == 'string');
|
|
7
|
+
var i;
|
|
8
|
+
if (decoder === undefined) {
|
|
9
|
+
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
|
10
|
+
ignore = "= \f\n\r\t\u00A0\u2028\u2029";
|
|
11
|
+
decoder = [];
|
|
12
|
+
for (i = 0; i < 64; ++i)
|
|
13
|
+
decoder[b64.charCodeAt(i)] = i;
|
|
14
|
+
for (i = 0; i < ignore.length; ++i)
|
|
15
|
+
decoder[ignore.charCodeAt(i)] = -1;
|
|
16
|
+
// RFC 3548 URL & file safe encoding
|
|
17
|
+
decoder['-'.charCodeAt(0)] = decoder['+'.charCodeAt(0)];
|
|
18
|
+
decoder['_'.charCodeAt(0)] = decoder['/'.charCodeAt(0)];
|
|
19
|
+
}
|
|
20
|
+
var out = haveU8 ? new Uint8Array(a.length * 3 >> 2) : [];
|
|
21
|
+
var bits = 0, char_count = 0, len = 0;
|
|
22
|
+
for (i = 0; i < a.length; ++i) {
|
|
23
|
+
var c = isString ? a.charCodeAt(i) : a[i];
|
|
24
|
+
if (c == 61) // '='.charCodeAt(0)
|
|
25
|
+
break;
|
|
26
|
+
c = decoder[c];
|
|
27
|
+
if (c == -1)
|
|
28
|
+
continue;
|
|
29
|
+
if (c === undefined)
|
|
30
|
+
throw 'Illegal character at offset ' + i;
|
|
31
|
+
bits |= c;
|
|
32
|
+
if (++char_count >= 4) {
|
|
33
|
+
out[len++] = (bits >> 16);
|
|
34
|
+
out[len++] = (bits >> 8) & 0xFF;
|
|
35
|
+
out[len++] = bits & 0xFF;
|
|
36
|
+
bits = 0;
|
|
37
|
+
char_count = 0;
|
|
38
|
+
} else {
|
|
39
|
+
bits <<= 6;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
switch (char_count) {
|
|
43
|
+
case 1:
|
|
44
|
+
throw "Base64 encoding incomplete: at least 2 bits missing";
|
|
45
|
+
case 2:
|
|
46
|
+
out[len++] = (bits >> 10);
|
|
47
|
+
break;
|
|
48
|
+
case 3:
|
|
49
|
+
out[len++] = (bits >> 16);
|
|
50
|
+
out[len++] = (bits >> 8) & 0xFF;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
if (haveU8 && out.length > len) // in case it was originally longer because of ignored characters
|
|
54
|
+
out = out.subarray(0, len);
|
|
55
|
+
return out;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
Base64.pretty = function (str) {
|
|
59
|
+
// fix padding
|
|
60
|
+
if (str.length % 4 > 0)
|
|
61
|
+
str = (str + '===').slice(0, str.length + str.length % 4);
|
|
62
|
+
// convert RFC 3548 to standard Base64
|
|
63
|
+
str = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
64
|
+
// 80 column width
|
|
65
|
+
return str.replace(/(.{80})/g, '$1\n');
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
Base64.re = /-----BEGIN [^-]+-----([A-Za-z0-9+/=\s]+)-----END [^-]+-----|begin-base64[^\n]+\n([A-Za-z0-9+/=\s]+)====/;
|
|
69
|
+
Base64.unarmor = function (a) {
|
|
70
|
+
var m = Base64.re.exec(a);
|
|
71
|
+
if (m) {
|
|
72
|
+
if (m[1])
|
|
73
|
+
a = m[1];
|
|
74
|
+
else if (m[2])
|
|
75
|
+
a = m[2];
|
|
76
|
+
else
|
|
77
|
+
throw "RegExp out of sync";
|
|
78
|
+
}
|
|
79
|
+
return Base64.decode(a);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export default Base64;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
var Hex = {},
|
|
2
|
+
decoder, // populated on first usage
|
|
3
|
+
haveU8 = (typeof Uint8Array == 'function');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Decodes an hexadecimal value.
|
|
7
|
+
* @param {string|Array|Uint8Array} a - a string representing hexadecimal data, or an array representation of its charcodes
|
|
8
|
+
*/
|
|
9
|
+
Hex.decode = function(a) {
|
|
10
|
+
var isString = (typeof a == 'string');
|
|
11
|
+
var i;
|
|
12
|
+
if (decoder === undefined) {
|
|
13
|
+
var hex = "0123456789ABCDEF",
|
|
14
|
+
ignore = " \f\n\r\t\u00A0\u2028\u2029";
|
|
15
|
+
decoder = [];
|
|
16
|
+
for (i = 0; i < 16; ++i)
|
|
17
|
+
decoder[hex.charCodeAt(i)] = i;
|
|
18
|
+
hex = hex.toLowerCase();
|
|
19
|
+
for (i = 10; i < 16; ++i)
|
|
20
|
+
decoder[hex.charCodeAt(i)] = i;
|
|
21
|
+
for (i = 0; i < ignore.length; ++i)
|
|
22
|
+
decoder[ignore.charCodeAt(i)] = -1;
|
|
23
|
+
}
|
|
24
|
+
var out = haveU8 ? new Uint8Array(a.length >> 1) : [],
|
|
25
|
+
bits = 0,
|
|
26
|
+
char_count = 0,
|
|
27
|
+
len = 0;
|
|
28
|
+
for (i = 0; i < a.length; ++i) {
|
|
29
|
+
var c = isString ? a.charCodeAt(i) : a[i];
|
|
30
|
+
c = decoder[c];
|
|
31
|
+
if (c == -1)
|
|
32
|
+
continue;
|
|
33
|
+
if (c === undefined)
|
|
34
|
+
throw 'Illegal character at offset ' + i;
|
|
35
|
+
bits |= c;
|
|
36
|
+
if (++char_count >= 2) {
|
|
37
|
+
out[len++] = bits;
|
|
38
|
+
bits = 0;
|
|
39
|
+
char_count = 0;
|
|
40
|
+
} else {
|
|
41
|
+
bits <<= 4;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (char_count)
|
|
45
|
+
throw "Hex encoding incomplete: 4 bits missing";
|
|
46
|
+
if (haveU8 && out.length > len) // in case it was originally longer because of ignored characters
|
|
47
|
+
out = out.subarray(0, len);
|
|
48
|
+
return out;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default Hex;
|