asn1-ts
Version:
ASN.1 encoding and decoding, including BER, CER, and DER.
123 lines (122 loc) • 5.02 kB
JavaScript
import * as errors from "../../../errors.mjs";
import convertBytesToText from "../../../utils/convertBytesToText.mjs";
import validateDateTime from "../../../validators/validateDateTime.mjs";
const SMALLEST_CORRECT_GENERALIZED_TIME = "2000120123".length;
const PERIOD = ".".charCodeAt(0);
const COMMA = ",".charCodeAt(0);
const Z = "Z".charCodeAt(0);
const PLUS = "+".charCodeAt(0);
const MINUS = "-".charCodeAt(0);
var FractionalUnits;
(function (FractionalUnits) {
FractionalUnits[FractionalUnits["Hours"] = 0] = "Hours";
FractionalUnits[FractionalUnits["Minutes"] = 1] = "Minutes";
FractionalUnits[FractionalUnits["Seconds"] = 2] = "Seconds";
})(FractionalUnits || (FractionalUnits = {}));
;
function isStop(s, i) {
const char = s.charCodeAt(i);
return (char === PERIOD) || (char === COMMA);
}
export default function decodeGeneralizedTime(value) {
if (value.length < SMALLEST_CORRECT_GENERALIZED_TIME) {
throw new errors.ASN1Error("Malformed GeneralizedTime string.");
}
if (value.length > 32) {
throw new errors.ASN1Error("Outrageously large GeneralizedTime string.");
}
const dateString = convertBytesToText(value);
const year = Number(dateString.slice(0, 4));
const month = (Number(dateString.slice(4, 6)) - 1);
const date = Number(dateString.slice(6, 8));
const hours = Number(dateString.slice(8, 10));
if (value.length === 10) {
validateDateTime("GeneralizedTime", year, month, date, hours, 0, 0);
return new Date(year, month, date, hours, 0, 0);
}
let i = 10;
while (value[i] && value[i] >= 0x30 && value[i] <= 0x39)
i++;
let minutes = 0;
let seconds = 0;
let milliseconds = 0;
let fractionUnits = FractionalUnits.Hours;
if (i == 14) {
minutes = Number.parseInt(dateString.slice(10, 12), 10);
seconds = Number.parseInt(dateString.slice(12, 14), 10);
fractionUnits = 2;
}
else if (i == 12) {
minutes = Number.parseInt(dateString.slice(10, 12), 10);
fractionUnits = 1;
}
else if (i != 10) {
throw new errors.ASN1Error("Malformed GeneralizedTime string.");
}
if (value[i] === undefined) {
validateDateTime("GeneralizedTime", year, month, date, hours, minutes, seconds);
return new Date(year, month, date, hours, minutes, seconds);
}
if (isStop(dateString, i)) {
i++;
let j = i;
while (value[j] && value[j] >= 0x30 && value[j] <= 0x39)
j++;
const fractionString = `0.${dateString.slice(i, j)}`;
i = j;
const fraction = Number.parseFloat(fractionString);
if (fractionUnits === FractionalUnits.Hours) {
minutes = Math.floor(60 * fraction);
seconds = Math.floor((60 * 60 * fraction) % 60);
}
else if (fractionUnits === FractionalUnits.Minutes) {
seconds = Math.floor(60 * fraction);
}
else if (fractionUnits === FractionalUnits.Seconds) {
milliseconds = Math.floor(1000 * fraction);
}
else {
throw new Error("internal asn1-ts error: invalid FractionalUnits");
}
}
if (value[i] === undefined) {
validateDateTime("GeneralizedTime", year, month, date, hours, minutes, seconds);
return new Date(year, month, date, hours, minutes, seconds, milliseconds);
}
if (value[i] === Z) {
validateDateTime("GeneralizedTime", year, month, date, hours, minutes, seconds);
return new Date(Date.UTC(year, month, date, hours, minutes, seconds, milliseconds));
}
if (value[i] === PLUS || value[i] === MINUS) {
const isPositive = value[i] === PLUS;
i++;
let j = i;
while (value[j] && value[j] >= 0x30 && value[j] <= 0x39)
j++;
const offsetSize = j - i;
if (value[j] !== undefined) {
throw new errors.ASN1Error("Malformed GeneralizedTime string.");
}
let offsetHour = 0;
let offsetMinute = 0;
if (offsetSize === 4) {
offsetHour = Number.parseInt(dateString.slice(j - 4, j - 2), 10);
offsetMinute = Number.parseInt(dateString.slice(j - 2, j), 10);
}
else if (offsetSize === 2) {
offsetHour = Number.parseInt(dateString.slice(j - 2, j));
}
else {
throw new errors.ASN1Error("Malformed GeneralizedTime string.");
}
let epochTimeInMS = Date.UTC(year, month, date, hours, minutes, seconds, milliseconds);
const sign = isPositive ? -1 : 1;
epochTimeInMS += sign * ((offsetHour * 60 * 60 * 1000) + (offsetMinute * 60 * 1000));
return new Date(epochTimeInMS);
}
if (value[i] !== undefined) {
throw new errors.ASN1Error("Malformed GeneralizedTime string.");
}
validateDateTime("GeneralizedTime", year, month, date, hours, minutes, seconds);
return new Date(Date.UTC(year, month, date, hours, minutes, seconds, milliseconds));
}