Projekt

Obecné

Profil

Stáhnout (7.85 KB) Statistiky
| Větev: | Revize:
1
var inherits = require('inherits');
2

    
3
var asn1 = require('../../asn1');
4
var base = asn1.base;
5
var bignum = asn1.bignum;
6

    
7
// Import DER constants
8
var der = asn1.constants.der;
9

    
10
function DERDecoder(entity) {
11
  this.enc = 'der';
12
  this.name = entity.name;
13
  this.entity = entity;
14

    
15
  // Construct base tree
16
  this.tree = new DERNode();
17
  this.tree._init(entity.body);
18
};
19
module.exports = DERDecoder;
20

    
21
DERDecoder.prototype.decode = function decode(data, options) {
22
  if (!(data instanceof base.DecoderBuffer))
23
    data = new base.DecoderBuffer(data, options);
24

    
25
  return this.tree._decode(data, options);
26
};
27

    
28
// Tree methods
29

    
30
function DERNode(parent) {
31
  base.Node.call(this, 'der', parent);
32
}
33
inherits(DERNode, base.Node);
34

    
35
DERNode.prototype._peekTag = function peekTag(buffer, tag, any) {
36
  if (buffer.isEmpty())
37
    return false;
38

    
39
  var state = buffer.save();
40
  var decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"');
41
  if (buffer.isError(decodedTag))
42
    return decodedTag;
43

    
44
  buffer.restore(state);
45

    
46
  return decodedTag.tag === tag || decodedTag.tagStr === tag ||
47
    (decodedTag.tagStr + 'of') === tag || any;
48
};
49

    
50
DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) {
51
  var decodedTag = derDecodeTag(buffer,
52
                                'Failed to decode tag of "' + tag + '"');
53
  if (buffer.isError(decodedTag))
54
    return decodedTag;
55

    
56
  var len = derDecodeLen(buffer,
57
                         decodedTag.primitive,
58
                         'Failed to get length of "' + tag + '"');
59

    
60
  // Failure
61
  if (buffer.isError(len))
62
    return len;
63

    
64
  if (!any &&
65
      decodedTag.tag !== tag &&
66
      decodedTag.tagStr !== tag &&
67
      decodedTag.tagStr + 'of' !== tag) {
68
    return buffer.error('Failed to match tag: "' + tag + '"');
69
  }
70

    
71
  if (decodedTag.primitive || len !== null)
72
    return buffer.skip(len, 'Failed to match body of: "' + tag + '"');
73

    
74
  // Indefinite length... find END tag
75
  var state = buffer.save();
76
  var res = this._skipUntilEnd(
77
      buffer,
78
      'Failed to skip indefinite length body: "' + this.tag + '"');
79
  if (buffer.isError(res))
80
    return res;
81

    
82
  len = buffer.offset - state.offset;
83
  buffer.restore(state);
84
  return buffer.skip(len, 'Failed to match body of: "' + tag + '"');
85
};
86

    
87
DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) {
88
  while (true) {
89
    var tag = derDecodeTag(buffer, fail);
90
    if (buffer.isError(tag))
91
      return tag;
92
    var len = derDecodeLen(buffer, tag.primitive, fail);
93
    if (buffer.isError(len))
94
      return len;
95

    
96
    var res;
97
    if (tag.primitive || len !== null)
98
      res = buffer.skip(len)
99
    else
100
      res = this._skipUntilEnd(buffer, fail);
101

    
102
    // Failure
103
    if (buffer.isError(res))
104
      return res;
105

    
106
    if (tag.tagStr === 'end')
107
      break;
108
  }
109
};
110

    
111
DERNode.prototype._decodeList = function decodeList(buffer, tag, decoder,
112
                                                    options) {
113
  var result = [];
114
  while (!buffer.isEmpty()) {
115
    var possibleEnd = this._peekTag(buffer, 'end');
116
    if (buffer.isError(possibleEnd))
117
      return possibleEnd;
118

    
119
    var res = decoder.decode(buffer, 'der', options);
120
    if (buffer.isError(res) && possibleEnd)
121
      break;
122
    result.push(res);
123
  }
124
  return result;
125
};
126

    
127
DERNode.prototype._decodeStr = function decodeStr(buffer, tag) {
128
  if (tag === 'bitstr') {
129
    var unused = buffer.readUInt8();
130
    if (buffer.isError(unused))
131
      return unused;
132
    return { unused: unused, data: buffer.raw() };
133
  } else if (tag === 'bmpstr') {
134
    var raw = buffer.raw();
135
    if (raw.length % 2 === 1)
136
      return buffer.error('Decoding of string type: bmpstr length mismatch');
137

    
138
    var str = '';
139
    for (var i = 0; i < raw.length / 2; i++) {
140
      str += String.fromCharCode(raw.readUInt16BE(i * 2));
141
    }
142
    return str;
143
  } else if (tag === 'numstr') {
144
    var numstr = buffer.raw().toString('ascii');
145
    if (!this._isNumstr(numstr)) {
146
      return buffer.error('Decoding of string type: ' +
147
                          'numstr unsupported characters');
148
    }
149
    return numstr;
150
  } else if (tag === 'octstr') {
151
    return buffer.raw();
152
  } else if (tag === 'objDesc') {
153
    return buffer.raw();
154
  } else if (tag === 'printstr') {
155
    var printstr = buffer.raw().toString('ascii');
156
    if (!this._isPrintstr(printstr)) {
157
      return buffer.error('Decoding of string type: ' +
158
                          'printstr unsupported characters');
159
    }
160
    return printstr;
161
  } else if (/str$/.test(tag)) {
162
    return buffer.raw().toString();
163
  } else {
164
    return buffer.error('Decoding of string type: ' + tag + ' unsupported');
165
  }
166
};
167

    
168
DERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) {
169
  var result;
170
  var identifiers = [];
171
  var ident = 0;
172
  while (!buffer.isEmpty()) {
173
    var subident = buffer.readUInt8();
174
    ident <<= 7;
175
    ident |= subident & 0x7f;
176
    if ((subident & 0x80) === 0) {
177
      identifiers.push(ident);
178
      ident = 0;
179
    }
180
  }
181
  if (subident & 0x80)
182
    identifiers.push(ident);
183

    
184
  var first = (identifiers[0] / 40) | 0;
185
  var second = identifiers[0] % 40;
186

    
187
  if (relative)
188
    result = identifiers;
189
  else
190
    result = [first, second].concat(identifiers.slice(1));
191

    
192
  if (values) {
193
    var tmp = values[result.join(' ')];
194
    if (tmp === undefined)
195
      tmp = values[result.join('.')];
196
    if (tmp !== undefined)
197
      result = tmp;
198
  }
199

    
200
  return result;
201
};
202

    
203
DERNode.prototype._decodeTime = function decodeTime(buffer, tag) {
204
  var str = buffer.raw().toString();
205
  if (tag === 'gentime') {
206
    var year = str.slice(0, 4) | 0;
207
    var mon = str.slice(4, 6) | 0;
208
    var day = str.slice(6, 8) | 0;
209
    var hour = str.slice(8, 10) | 0;
210
    var min = str.slice(10, 12) | 0;
211
    var sec = str.slice(12, 14) | 0;
212
  } else if (tag === 'utctime') {
213
    var year = str.slice(0, 2) | 0;
214
    var mon = str.slice(2, 4) | 0;
215
    var day = str.slice(4, 6) | 0;
216
    var hour = str.slice(6, 8) | 0;
217
    var min = str.slice(8, 10) | 0;
218
    var sec = str.slice(10, 12) | 0;
219
    if (year < 70)
220
      year = 2000 + year;
221
    else
222
      year = 1900 + year;
223
  } else {
224
    return buffer.error('Decoding ' + tag + ' time is not supported yet');
225
  }
226

    
227
  return Date.UTC(year, mon - 1, day, hour, min, sec, 0);
228
};
229

    
230
DERNode.prototype._decodeNull = function decodeNull(buffer) {
231
  return null;
232
};
233

    
234
DERNode.prototype._decodeBool = function decodeBool(buffer) {
235
  var res = buffer.readUInt8();
236
  if (buffer.isError(res))
237
    return res;
238
  else
239
    return res !== 0;
240
};
241

    
242
DERNode.prototype._decodeInt = function decodeInt(buffer, values) {
243
  // Bigint, return as it is (assume big endian)
244
  var raw = buffer.raw();
245
  var res = new bignum(raw);
246

    
247
  if (values)
248
    res = values[res.toString(10)] || res;
249

    
250
  return res;
251
};
252

    
253
DERNode.prototype._use = function use(entity, obj) {
254
  if (typeof entity === 'function')
255
    entity = entity(obj);
256
  return entity._getDecoder('der').tree;
257
};
258

    
259
// Utility methods
260

    
261
function derDecodeTag(buf, fail) {
262
  var tag = buf.readUInt8(fail);
263
  if (buf.isError(tag))
264
    return tag;
265

    
266
  var cls = der.tagClass[tag >> 6];
267
  var primitive = (tag & 0x20) === 0;
268

    
269
  // Multi-octet tag - load
270
  if ((tag & 0x1f) === 0x1f) {
271
    var oct = tag;
272
    tag = 0;
273
    while ((oct & 0x80) === 0x80) {
274
      oct = buf.readUInt8(fail);
275
      if (buf.isError(oct))
276
        return oct;
277

    
278
      tag <<= 7;
279
      tag |= oct & 0x7f;
280
    }
281
  } else {
282
    tag &= 0x1f;
283
  }
284
  var tagStr = der.tag[tag];
285

    
286
  return {
287
    cls: cls,
288
    primitive: primitive,
289
    tag: tag,
290
    tagStr: tagStr
291
  };
292
}
293

    
294
function derDecodeLen(buf, primitive, fail) {
295
  var len = buf.readUInt8(fail);
296
  if (buf.isError(len))
297
    return len;
298

    
299
  // Indefinite form
300
  if (!primitive && len === 0x80)
301
    return null;
302

    
303
  // Definite form
304
  if ((len & 0x80) === 0) {
305
    // Short form
306
    return len;
307
  }
308

    
309
  // Long form
310
  var num = len & 0x7f;
311
  if (num > 4)
312
    return buf.error('length octect is too long');
313

    
314
  len = 0;
315
  for (var i = 0; i < num; i++) {
316
    len <<= 8;
317
    var j = buf.readUInt8(fail);
318
    if (buf.isError(j))
319
      return j;
320
    len |= j;
321
  }
322

    
323
  return len;
324
}
(1-1/3)