• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PeculiarVentures / ASN1.js / 14130271268

28 Mar 2025 01:41PM UTC coverage: 77.767% (-0.03%) from 77.8%
14130271268

push

github

web-flow
Merge pull request #114 from PeculiarVentures/update

Update dependencies and migrate testing framework to Jest

386 of 652 branches covered (59.2%)

102 of 113 new or added lines in 55 files covered. (90.27%)

16 existing lines in 7 files now uncovered.

1581 of 2033 relevant lines covered (77.77%)

5777.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.45
/src/parser.ts
1
import * as pvtsutils from "pvtsutils";
6✔
2
import { ValueBlock } from "./ValueBlock";
6✔
3
import { BaseBlock } from "./BaseBlock";
6✔
4
import { LocalBaseBlock } from "./internals/LocalBaseBlock";
6✔
5
import { AsnType, typeStore } from "./TypeStore";
6✔
6
import { checkBufferParams } from "./internals/utils";
6✔
7

8
export interface FromBerResult {
9
  offset: number;
10
  result: AsnType;
11
}
12

13
/**
14
 * Local function changing a type for ASN.1 classes
15
 * @param inputObject Incoming object
16
 * @param newType Target type to convert
17
 * @returns Converted object
18
 */
19
function localChangeType<T extends BaseBlock>(inputObject: BaseBlock, newType: new () => T): T {
20
  if (inputObject instanceof newType) {
296✔
21
    return inputObject;
24✔
22
  }
23

24
  const newObject = new newType();
272✔
25
  newObject.idBlock = inputObject.idBlock;
272✔
26
  newObject.lenBlock = inputObject.lenBlock;
272✔
27
  newObject.warnings = inputObject.warnings;
272✔
28
  newObject.valueBeforeDecodeView = inputObject.valueBeforeDecodeView;
272✔
29

30
  return newObject;
272✔
31
}
32

33
/**
34
 * Internal library function for decoding ASN.1 BER
35
 * @param inputBuffer ASN.1 BER encoded array
36
 * @param inputOffset Offset in ASN.1 BER encoded array where decoding should be started
37
 * @param inputLength Maximum length of array of bytes which can be using in this function
38
 * @returns
39
 */
40
export function localFromBER(
6✔
41
  inputBuffer: Uint8Array,
42
  inputOffset = 0,
×
43
  inputLength = inputBuffer.length,
×
44
): FromBerResult {
45
  const incomingOffset = inputOffset; // Need to store initial offset since "inputOffset" is changing in the function
322✔
46

47
  // Create a basic ASN.1 type since we need to return errors and warnings from the function
48
  let returnObject = new BaseBlock({}, ValueBlock);
322✔
49

50
  // Basic check for parameters
51
  const baseBlock = new LocalBaseBlock();
322✔
52
  if (!checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength)) {
322!
53
    returnObject.error = baseBlock.error;
×
54

55
    return {
×
56
      offset: -1,
57
      result: returnObject,
58
    };
59
  }
60

61
  // Getting Uint8Array subarray
62
  const intBuffer = inputBuffer.subarray(inputOffset, inputOffset + inputLength);
322✔
63

64
  // Initial checks
65
  if (!intBuffer.length) {
322!
66
    returnObject.error = "Zero buffer length";
×
67

68
    return {
×
69
      offset: -1,
70
      result: returnObject,
71
    };
72
  }
73

74
  // Decode identification block of ASN.1 BER structure
75
  // console.time("idBlock");
76
  let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength);
322✔
77
  if (returnObject.idBlock.warnings.length) {
322✔
78
    returnObject.warnings.concat(returnObject.idBlock.warnings);
8✔
79
  }
80
  if (resultOffset === -1) {
322✔
81
    returnObject.error = returnObject.idBlock.error;
6✔
82

83
    return {
6✔
84
      offset: -1,
85
      result: returnObject,
86
    };
87
  }
88
  // console.timeEnd("idBlock");
89

90
  inputOffset = resultOffset;
316✔
91
  inputLength -= returnObject.idBlock.blockLength;
316✔
92

93
  // Decode length block of ASN.1 BER structure
94
  // console.time("lengthBlock");
95
  resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength);
316✔
96
  if (returnObject.lenBlock.warnings.length) {
316✔
97
    returnObject.warnings.concat(returnObject.lenBlock.warnings);
6✔
98
  }
99
  if (resultOffset === -1) {
316✔
100
    returnObject.error = returnObject.lenBlock.error;
18✔
101

102
    return {
18✔
103
      offset: -1,
104
      result: returnObject,
105
    };
106
  }
107
  // console.timeEnd("lengthBlock");
108

109
  inputOffset = resultOffset;
298✔
110
  inputLength -= returnObject.lenBlock.blockLength;
298✔
111

112
  // Check for using indefinite length form in encoding for primitive types
113
  if (!returnObject.idBlock.isConstructed
298✔
114
    && returnObject.lenBlock.isIndefiniteForm) {
115
    returnObject.error = "Indefinite length form used for primitive encoding form";
2✔
116

117
    return {
2✔
118
      offset: -1,
119
      result: returnObject,
120
    };
121
  }
122

123
  // Switch ASN.1 block type
124
  let newASN1Type: new () => AsnType = BaseBlock as any;
296✔
125

126
  switch (returnObject.idBlock.tagClass) {
296!
127
    // UNIVERSAL
128
    case 1:
129
      // Check for reserved tag numbers
130
      if ((returnObject.idBlock.tagNumber >= 37)
284!
131
        && (returnObject.idBlock.isHexOnly === false)) {
UNCOV
132
        returnObject.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard";
×
133

134
        return {
×
135
          offset: -1,
136
          result: returnObject,
137
        };
138
      }
139
      switch (returnObject.idBlock.tagNumber) {
284!
140
        case 0: // EndOfContent
141
          // Check for EndOfContent type
142
          if ((returnObject.idBlock.isConstructed)
16!
143
            && (returnObject.lenBlock.length > 0)) {
UNCOV
144
            returnObject.error = "Type [UNIVERSAL 0] is reserved";
×
145

146
            return {
×
147
              offset: -1,
148
              result: returnObject,
149
            };
150
          }
151

152
          newASN1Type = typeStore.EndOfContent;
16✔
153

154
          break;
16✔
155
        case 1: // Boolean
156
          newASN1Type = typeStore.Boolean;
18✔
157
          break;
18✔
158
        case 2: // Integer
159
          newASN1Type = typeStore.Integer;
18✔
160
          break;
18✔
161
        case 3: // BitString
162
          newASN1Type = typeStore.BitString;
68✔
163
          break;
68✔
164
        case 4: // OctetString
165
          newASN1Type = typeStore.OctetString;
30✔
166
          break;
30✔
167
        case 5: // Null
168
          newASN1Type = typeStore.Null;
12✔
169
          break;
12✔
170
        case 6: // ObjectIdentifier
171
          newASN1Type = typeStore.ObjectIdentifier;
28✔
172
          break;
28✔
173
        case 10: // Enumerated
174
          newASN1Type = typeStore.Enumerated;
4✔
175
          break;
4✔
176
        case 12: // Utf8String
177
          newASN1Type = typeStore.Utf8String;
2✔
178
          break;
2✔
179
        case 13: // RelativeObjectIdentifier
180
          newASN1Type = typeStore.RelativeObjectIdentifier;
2✔
181
          break;
2✔
182
        case 14: // TIME
183
          newASN1Type = typeStore.TIME;
×
184
          break;
×
185
        case 15:
186
          returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard";
×
187

188
          return {
×
189
            offset: -1,
190
            result: returnObject,
191
          };
192
        case 16: // Sequence
193
          newASN1Type = typeStore.Sequence;
38✔
194
          break;
38✔
195
        case 17: // Set
196
          newASN1Type = typeStore.Set;
8✔
197
          break;
8✔
198
        case 18: // NumericString
199
          newASN1Type = typeStore.NumericString;
×
200
          break;
×
201
        case 19: // PrintableString
202
          newASN1Type = typeStore.PrintableString;
4✔
203
          break;
4✔
204
        case 20: // TeletexString
205
          newASN1Type = typeStore.TeletexString;
×
206
          break;
×
207
        case 21: // VideotexString
208
          newASN1Type = typeStore.VideotexString;
×
209
          break;
×
210
        case 22: // IA5String
211
          newASN1Type = typeStore.IA5String;
4✔
212
          break;
4✔
213
        case 23: // UTCTime
214
          newASN1Type = typeStore.UTCTime;
4✔
215
          break;
4✔
216
        case 24: // GeneralizedTime
217
          newASN1Type = typeStore.GeneralizedTime;
×
218
          break;
×
219
        case 25: // GraphicString
220
          newASN1Type = typeStore.GraphicString;
×
221
          break;
×
222
        case 26: // VisibleString
223
          newASN1Type = typeStore.VisibleString;
×
224
          break;
×
225
        case 27: // GeneralString
226
          newASN1Type = typeStore.GeneralString;
×
227
          break;
×
228
        case 28: // UniversalString
229
          newASN1Type = typeStore.UniversalString;
2✔
230
          break;
2✔
231
        case 29: // CharacterString
232
          newASN1Type = typeStore.CharacterString;
×
233
          break;
×
234
        case 30: // BmpString
235
          newASN1Type = typeStore.BmpString;
2✔
236
          break;
2✔
237
        case 31: // DATE
238
          newASN1Type = typeStore.DATE;
×
239
          break;
×
240
        case 32: // TimeOfDay
241
          newASN1Type = typeStore.TimeOfDay;
×
242
          break;
×
243
        case 33: // DateTime
244
          newASN1Type = typeStore.DateTime;
×
245
          break;
×
246
        case 34: // Duration
247
          newASN1Type = typeStore.Duration;
×
248
          break;
×
249
        default: {
250
          const newObject = returnObject.idBlock.isConstructed
24!
251
            ? new typeStore.Constructed()
252
            : new typeStore.Primitive();
253

254
          newObject.idBlock = returnObject.idBlock;
24✔
255
          newObject.lenBlock = returnObject.lenBlock;
24✔
256
          newObject.warnings = returnObject.warnings;
24✔
257

258
          returnObject = newObject;
24✔
259
        }
260
      }
261
      break;
284✔
262
    // All other tag classes
263
    case 2: // APPLICATION
264
    case 3: // CONTEXT-SPECIFIC
265
    case 4: // PRIVATE
266
    default: {
267
      newASN1Type = returnObject.idBlock.isConstructed
12✔
268
        ? typeStore.Constructed
269
        : typeStore.Primitive;
270
    }
271
  }
272

273
  // Change type and perform BER decoding
274
  returnObject = localChangeType(returnObject, newASN1Type);
296✔
275
  // console.time("valueBlock");
276
  resultOffset = returnObject.fromBER(
296✔
277
    inputBuffer,
278
    inputOffset,
279
    returnObject.lenBlock.isIndefiniteForm ? inputLength : returnObject.lenBlock.length,
296✔
280
  );
281

282
  // Coping incoming buffer for entire ASN.1 block
283
  returnObject.valueBeforeDecodeView = inputBuffer.subarray(incomingOffset, incomingOffset + returnObject.blockLength);
296✔
284
  // console.timeEnd("valueBlock");
285

286
  return {
296✔
287
    offset: resultOffset,
288
    result: returnObject,
289
  };
290
}
291

292
/**
293
 * Major function for decoding ASN.1 BER array into internal library structures
294
 * @param inputBuffer ASN.1 BER encoded array of bytes
295
 */
296
export function fromBER(inputBuffer: pvtsutils.BufferSource): FromBerResult {
6✔
297
  if (!inputBuffer.byteLength) {
122!
298
    const result = new BaseBlock({}, ValueBlock);
×
299
    result.error = "Input buffer has zero length";
×
300

301
    return {
×
302
      offset: -1,
303
      result,
304
    };
305
  }
306

307
  return localFromBER(pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer).slice(), 0, inputBuffer.byteLength);
122✔
308
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc