@indrajala/asn1der
Version:
parse ASN.1 DER structures
139 lines • 7.04 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Asn1Node = exports.parseGeneralizedTimeString = exports.parseUtcString = void 0;
const asn1der_1 = require("../asn1der");
const descriptions_1 = require("./descriptions");
const enums_1 = require("./enums");
const oid_1 = require("./oid");
// 'YYMMDD 000000 Z'
exports.parseUtcString = (s) => {
const yyyy = 2000 + parseInt(s.substring(0, 2));
const mm = parseInt(s.substring(2, 4));
const dd = parseInt(s.substring(4, 6));
const hours = parseInt(s.substring(6, 8));
const mins = parseInt(s.substring(8, 10));
const seconds = parseInt(s.substring(10, 12));
// console.log(`${yyyy}/${mm}/${dd} ${hours}:${mins}:${seconds}`);
return new Date(Date.UTC(yyyy, mm - 1, dd, hours, mins, seconds));
};
// YYYYMMDD000000Z
// YYYY MM DD 00 00 00 Z
// e.g.
// 19920521000000Z
// 19920622123421Z
// 19920722132100.3Z
//
exports.parseGeneralizedTimeString = (s) => {
const yyyy = parseInt(s.substring(0, 4));
const mm = parseInt(s.substring(4, 6));
const dd = parseInt(s.substring(6, 8));
const hours = parseInt(s.substring(8, 10));
const mins = parseInt(s.substring(10, 12));
const seconds = parseInt(s.substring(12, 14));
const hasFractionalSeconds = s[14] == '.';
const ms = (hasFractionalSeconds)
? parseInt(s.substring(15, s.length - 1)) * 1000
: 0;
// console.log(`${yyyy}/${mm}/${dd} ${hours}:${mins}:${seconds}`);
return new Date(Date.UTC(yyyy, mm - 1, dd, hours, mins, seconds, ms));
};
class Asn1Node {
constructor(raw, identifier, length, content, children) {
this.toString = (tagNumberLookup = null) => {
const tagNumberLookupIsRelevant = [
enums_1.Asn1Class.Application,
enums_1.Asn1Class.ContextSpecific,
enums_1.Asn1Class.Private
].includes(this.identifier.class);
// console.log(`tag number: ${this.identifier.tagNumber}`);
// console.log(`lookup has: ${tagNumberLookup?.has(this.identifier.tagNumber)}`);
const tagDescription = ((tagNumberLookup != null)
&& (tagNumberLookup.has(this.identifier.tagNumber))
&& tagNumberLookupIsRelevant)
? tagNumberLookup.get(this.identifier.tagNumber) + ` [${this.identifier.tagNumber}]`
: (descriptions_1.asn1TagDescription.has(this.identifier.tagNumber))
? descriptions_1.asn1TagDescription.get(this.identifier.tagNumber)
: null;
const label = (tagDescription != null)
? tagDescription
: `${this.identifier.tagNumber}`;
const oidStr = (this.identifier.tagNumber == enums_1.Asn1Tag.ObjectIdentifier)
? asn1der_1.parseOID(this.content)
: 'badly formed OID';
const oidDescription = (oid_1.x509OIDs.has(oidStr))
? oid_1.x509OIDs.get(oidStr)
: 'unknown OID';
const contentHex = this.getContentAsHex();
const hexLimit = 20;
const cleanContentHex = (contentHex.length > hexLimit)
? contentHex.substring(0, hexLimit) + '...'
: contentHex;
const universalContentStr = (this.identifier.tagNumber == enums_1.Asn1Tag.ObjectIdentifier)
? `${oidStr} (${oidDescription})`
: (this.identifier.tagNumber == enums_1.Asn1Tag.UTF8String)
? this.getUTF8String()
: (this.identifier.tagNumber == enums_1.Asn1Tag.PrintableString)
? this.getPrintableString()
: (this.identifier.tagNumber == enums_1.Asn1Tag.UTCTime)
? this.getUTCTime().toString()
: (this.identifier.tagNumber == enums_1.Asn1Tag.Integer)
? this.getInteger().toString()
: (this.identifier.tagNumber == enums_1.Asn1Tag.IA5String)
? this.getIA5String()
: (this.identifier.tagNumber == enums_1.Asn1Tag.Boolean)
? this.getBoolean()
: (this.identifier.tagNumber == enums_1.Asn1Tag.GeneralizedTime)
? this.getGeneralizedTime().toString()
: cleanContentHex;
const contentStr = (this.identifier.class == enums_1.Asn1Class.Universal)
? universalContentStr
: cleanContentHex;
return `${label} - ${contentStr}`;
};
this.getUTF8String = () => this.content.toString('utf-8');
this.getPrintableString = () => this.content.toString('ascii');
this.getUTCTime = () => exports.parseUtcString(this.content.toString('ascii'));
this.getGeneralizedTime = () => exports.parseGeneralizedTimeString(this.content.toString('ascii'));
this.getIA5String = () => this.content.toString('ascii');
this.getBoolean = () => !(this.content.readInt8(0) == 0);
this.getInteger = () => parseInt(this.content.toString('hex'), 16);
this.getSetElementsAsIntegers = () => this.children.map(child => child.getInteger());
this.getSetElements = () => this.children;
this.getNull = () => this.identifier.tagNumber == enums_1.Asn1Tag.Null;
this.getContentAsHex = () => this.content.toString('hex');
// TODO fix argument order
this.summary = (indent, tagNumberLookup) => {
const childrenReport = [];
this.children
.forEach(child => childrenReport.push(...child.summary(indent, tagNumberLookup)));
return [
this.toString(tagNumberLookup),
...childrenReport.map(line => ' '.repeat(indent) + line)
];
};
this.getChildAtZIndex = (zindex) => this.children[zindex];
this.getChildWithTagNumber = (tagNumber) => this.children.find(it => it.identifier.tagNumber == tagNumber);
this.get = (path) => {
const steps = path.split('.');
const firstStep = steps[0];
const firstStepTarget = (firstStep.startsWith('#'))
? this.getChildWithTagNumber(parseInt(firstStep.substring(1)))
: this.getChildAtZIndex(parseInt(firstStep));
return (steps.length == 1)
? firstStepTarget
: (firstStepTarget)
? firstStepTarget.get(steps.slice(1).join('.'))
: null;
};
this.reparse = () => {
this.children = asn1der_1.parseDER(this.content);
};
this.raw = raw;
this.identifier = identifier;
this.length = length;
this.content = content;
this.children = children;
}
}
exports.Asn1Node = Asn1Node;
//# sourceMappingURL=Asn1Node.js.map