Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80647 views
1
var inherits = require('inherits');
2
var Buffer = require('buffer').Buffer;
3
4
var asn1 = require('../../asn1');
5
var base = asn1.base;
6
var bignum = asn1.bignum;
7
8
// Import DER constants
9
var der = asn1.constants.der;
10
11
function DEREncoder(entity) {
12
this.enc = 'der';
13
this.name = entity.name;
14
this.entity = entity;
15
16
// Construct base tree
17
this.tree = new DERNode();
18
this.tree._init(entity.body);
19
};
20
module.exports = DEREncoder;
21
22
DEREncoder.prototype.encode = function encode(data, reporter) {
23
return this.tree._encode(data, reporter).join();
24
};
25
26
// Tree methods
27
28
function DERNode(parent) {
29
base.Node.call(this, 'der', parent);
30
}
31
inherits(DERNode, base.Node);
32
33
DERNode.prototype._encodeComposite = function encodeComposite(tag,
34
primitive,
35
cls,
36
content) {
37
var encodedTag = encodeTag(tag, primitive, cls, this.reporter);
38
39
// Short form
40
if (content.length < 0x80) {
41
var header = new Buffer(2);
42
header[0] = encodedTag;
43
header[1] = content.length;
44
return this._createEncoderBuffer([ header, content ]);
45
}
46
47
// Long form
48
// Count octets required to store length
49
var lenOctets = 1;
50
for (var i = content.length; i >= 0x100; i >>= 8)
51
lenOctets++;
52
53
var header = new Buffer(1 + 1 + lenOctets);
54
header[0] = encodedTag;
55
header[1] = 0x80 | lenOctets;
56
57
for (var i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8)
58
header[i] = j & 0xff;
59
60
return this._createEncoderBuffer([ header, content ]);
61
};
62
63
DERNode.prototype._encodeStr = function encodeStr(str, tag) {
64
if (tag === 'octstr')
65
return this._createEncoderBuffer(str);
66
else if (tag === 'bitstr')
67
return this._createEncoderBuffer([ str.unused | 0, str.data ]);
68
else if (tag === 'ia5str')
69
return this._createEncoderBuffer(str);
70
return this.reporter.error('Encoding of string type: ' + tag +
71
' unsupported');
72
};
73
74
DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) {
75
if (typeof id === 'string') {
76
if (!values)
77
return this.reporter.error('string objid given, but no values map found');
78
if (!values.hasOwnProperty(id))
79
return this.reporter.error('objid not found in values map');
80
id = values[id].split(/\s+/g);
81
for (var i = 0; i < id.length; i++)
82
id[i] |= 0;
83
} else if (Array.isArray(id)) {
84
id = id.slice();
85
}
86
87
if (!Array.isArray(id)) {
88
return this.reporter.error('objid() should be either array or string, ' +
89
'got: ' + JSON.stringify(id));
90
}
91
92
if (!relative) {
93
if (id[1] >= 40)
94
return this.reporter.error('Second objid identifier OOB');
95
id.splice(0, 2, id[0] * 40 + id[1]);
96
}
97
98
// Count number of octets
99
var size = 0;
100
for (var i = 0; i < id.length; i++) {
101
var ident = id[i];
102
for (size++; ident >= 0x80; ident >>= 7)
103
size++;
104
}
105
106
var objid = new Buffer(size);
107
var offset = objid.length - 1;
108
for (var i = id.length - 1; i >= 0; i--) {
109
var ident = id[i];
110
objid[offset--] = ident & 0x7f;
111
while ((ident >>= 7) > 0)
112
objid[offset--] = 0x80 | (ident & 0x7f);
113
}
114
115
return this._createEncoderBuffer(objid);
116
};
117
118
function two(num) {
119
if (num < 10)
120
return '0' + num;
121
else
122
return num;
123
}
124
125
DERNode.prototype._encodeTime = function encodeTime(time, tag) {
126
var str;
127
var date = new Date(time);
128
129
if (tag === 'gentime') {
130
str = [
131
two(date.getFullYear()),
132
two(date.getUTCMonth() + 1),
133
two(date.getUTCDate()),
134
two(date.getUTCHours()),
135
two(date.getUTCMinutes()),
136
two(date.getUTCSeconds()),
137
'Z'
138
].join('');
139
} else if (tag === 'utctime') {
140
str = [
141
two(date.getFullYear() % 100),
142
two(date.getUTCMonth() + 1),
143
two(date.getUTCDate()),
144
two(date.getUTCHours()),
145
two(date.getUTCMinutes()),
146
two(date.getUTCSeconds()),
147
'Z'
148
].join('');
149
} else {
150
this.reporter.error('Encoding ' + tag + ' time is not supported yet');
151
}
152
153
return this._encodeStr(str, 'octstr');
154
};
155
156
DERNode.prototype._encodeNull = function encodeNull() {
157
return this._createEncoderBuffer('');
158
};
159
160
DERNode.prototype._encodeInt = function encodeInt(num, values) {
161
if (typeof num === 'string') {
162
if (!values)
163
return this.reporter.error('String int or enum given, but no values map');
164
if (!values.hasOwnProperty(num)) {
165
return this.reporter.error('Values map doesn\'t contain: ' +
166
JSON.stringify(num));
167
}
168
num = values[num];
169
}
170
171
// Bignum, assume big endian
172
if (typeof num !== 'number' && !Buffer.isBuffer(num)) {
173
var numArray = num.toArray();
174
if (num.sign === false && numArray[0] & 0x80) {
175
numArray.unshift(0);
176
}
177
num = new Buffer(numArray);
178
}
179
180
if (Buffer.isBuffer(num)) {
181
var size = num.length;
182
if (num.length === 0)
183
size++;
184
185
var out = new Buffer(size);
186
num.copy(out);
187
if (num.length === 0)
188
out[0] = 0
189
return this._createEncoderBuffer(out);
190
}
191
192
if (num < 0x80)
193
return this._createEncoderBuffer(num);
194
195
if (num < 0x100)
196
return this._createEncoderBuffer([0, num]);
197
198
var size = 1;
199
for (var i = num; i >= 0x100; i >>= 8)
200
size++;
201
202
var out = new Array(size);
203
for (var i = out.length - 1; i >= 0; i--) {
204
out[i] = num & 0xff;
205
num >>= 8;
206
}
207
if(out[0] & 0x80) {
208
out.unshift(0);
209
}
210
211
return this._createEncoderBuffer(new Buffer(out));
212
};
213
214
DERNode.prototype._encodeBool = function encodeBool(value) {
215
return this._createEncoderBuffer(value ? 0xff : 0);
216
};
217
218
DERNode.prototype._use = function use(entity, obj) {
219
if (typeof entity === 'function')
220
entity = entity(obj);
221
return entity._getEncoder('der').tree;
222
};
223
224
DERNode.prototype._skipDefault = function skipDefault(dataBuffer, reporter, parent) {
225
var state = this._baseState;
226
var i;
227
if (state['default'] === null)
228
return false;
229
230
var data = dataBuffer.join();
231
if (state.defaultBuffer === undefined)
232
state.defaultBuffer = this._encodeValue(state['default'], reporter, parent).join();
233
234
if (data.length !== state.defaultBuffer.length)
235
return false;
236
237
for (i=0; i < data.length; i++)
238
if (data[i] !== state.defaultBuffer[i])
239
return false;
240
241
return true;
242
};
243
244
// Utility methods
245
246
function encodeTag(tag, primitive, cls, reporter) {
247
var res;
248
249
if (tag === 'seqof')
250
tag = 'seq';
251
else if (tag === 'setof')
252
tag = 'set';
253
254
if (der.tagByName.hasOwnProperty(tag))
255
res = der.tagByName[tag];
256
else if (typeof tag === 'number' && (tag | 0) === tag)
257
res = tag;
258
else
259
return reporter.error('Unknown tag: ' + tag);
260
261
if (res >= 0x1f)
262
return reporter.error('Multi-octet tag encoding unsupported');
263
264
if (!primitive)
265
res |= 0x20;
266
267
res |= (der.tagClassByName[cls || 'universal'] << 6);
268
269
return res;
270
}
271
272