Skip to content

Instantly share code, notes, and snippets.

@lapo-luchini
Created August 18, 2017 16:18
Show Gist options
  • Save lapo-luchini/5d770e91dee2b258fd006fbf6ed38ffc to your computer and use it in GitHub Desktop.
Save lapo-luchini/5d770e91dee2b258fd006fbf6ed38ffc to your computer and use it in GitHub Desktop.
'use strict';
const
asn1 = require('asn1.js'),
rfc5280 = require('asn1.js-rfc5280'),
Version = asn1.define('Version', function () {
this.int({
1: 'v1',
});
}),
MessageImprint = asn1.define('MessageImprint', function () {
this.seq().obj(
this.key('hashAlgorithm').use(rfc5280.AlgorithmIdentifier),
this.key('hashedMessage').octstr()
);
}),
TimeStampReq = asn1.define('TimeStampReq', function () {
this.seq().obj(
this.key('version').use(Version),
this.key('messageImprint').use(MessageImprint),
this.key('reqPolicy').objid().optional(),
this.key('nonce').int().optional(),
this.key('certReq').bool().optional()
//this.key('extensions').use(Extensions).optional(), // not supported at this time
);
}),
PKIStatusInfo = asn1.define('PKIStatusInfo', function () {
this.seq().obj(
this.key('status').int({
0: 'granted', // when the PKIStatus contains the value zero a TimeStampToken, as requested, is present
1: 'grantedWithMods', // when the PKIStatus contains the value one a TimeStampToken, with modifications, is present
2: 'rejection',
3: 'waiting',
4: 'revocationWarning', // this message contains a warning that a revocation is imminent
5: 'revocationNotification', // notification that a revocation has occurred
}),
this.key('statusString').optional().seqof(this.utf8str()), // PKIFreeText as defined in RFC4210
this.key('failInfo').optional().bitstr({
'0': 'badAlg',
'2': 'badRequest',
'5': 'badDataFormat',
'14': 'timeNotAvailable',
'15': 'unacceptedPolicy',
'16': 'unacceptedExtension',
'17': 'addInfoNotAvailable',
'25': 'systemFailure'
})
);
}),
CertificateChoices = asn1.define('CertificateChoices', function () {
this.choice({
certificate: this.use(rfc5280.Certificate),
extendedCertificate: this.implicit(0).use(rfc5280.Certificate),
v1AttrCert: this.implicit(1).use(rfc5280.Certificate),
v2AttrCert: this.implicit(2).use(rfc5280.Certificate),
other: this.implicit(3).seq().obj(
this.key('otherCertFormat').objid(),
this.key('otherCert').any()
)
});
}),
RevocationInfoChoice = asn1.define('RevocationInfoChoice', function () {
this.choice({
crl: this.use(rfc5280.CertificateList),
other: this.implicit(1).seq().obj(
this.key('otherRevInfoFormat').objid(),
this.key('otherRevInfo').any()
)
});
}),
SignerInfo = asn1.define('SignerInfo', function () {
this.seq().obj(
this.key('version').int(),
this.key('sid').choice({
issuerAndSerialNumber: this.seq().obj(
this.key('issuer').use(rfc5280.Name),
this.key('serialNumber').use(rfc5280.CertificateSerialNumber)
)
}),
this.key('digestAlgorithm').use(rfc5280.AlgorithmIdentifier),
this.key('signedAttrs').optional().implicit(0).setof(common.Attribute),
this.key('signatureAlgorithm').use(rfc5280.AlgorithmIdentifier),
this.key('signature').octstr(),
this.key('unsignedAttrs').optional().implicit(1).setof(common.Attribute)
);
}),
SignedData = asn1.define('SignedData', function () {
this.seq().obj(
this.key('version').int(),
this.key('digestAlgorithms').setof(rfc5280.AlgorithmIdentifier),
this.key('encapContentInfo').seq().obj(
this.key('eContentType').objid(),
this.key('eContent').optional().explicit(0).octstr(),//.contains(TSTInfo),
),
this.key('certificates').optional().implicit(0).setof(CertificateChoices),
this.key('crls').optional().implicit(1).setof(RevocationInfoChoice),
this.key('signerInfos').setof(SignerInfo)
)
}),
TimeStampToken = asn1.define('TimeStampToken', function () {
this.seq().obj(
this.key('contentType').objid(),
this.key('content').optional().explicit(0).use(SignedData)
);
}),
TimeStampResp = asn1.define('TimeStampResp', function () {
this.seq().obj(
this.key('status').use(PKIStatusInfo),
this.key('timeStampToken').optional().use(TimeStampToken) // would be use(TimeStampToken), but not decoded at this time
);
}),
TSTInfo = asn1.define('TSTInfo', function () {
this.seq().obj(
this.key('version').use(Version),
this.key('policy').objid(),
this.key('messageImprint').use(MessageImprint), // MUST have the same value as the similar field in TimeStampReq
this.key('serialNumber').int(), // Time-Stamping users MUST be ready to accommodate integers up to 160 bits.
this.key('genTime').gentime(),
this.key('accuracy').optional().any(), //TODO Accuracy
this.key('ordering').bool().def(false),
this.key('nonce').optional().int(), // MUST be present if the similar field was present in TimeStampReq. In that case it MUST have the same value.
// tsa [0] GeneralName OPTIONAL
// extensions [1] IMPLICIT Extensions OPTIONAL
);
}),
str = '308206a030030201003082069706092a864886f70d010702a08206883080020103310f300d060960864801650304020105003080060b2a864886f70d0109100104a0802480046a306802010106032a0304302f300b06096086480165030402010420780c8c51ea21b68bca74ae30ab802b458955ad56f6152b23d2daacb34b62bf00021500b77d8590c5dcc1143351b2866b32cfb5518c3581181332303137303831383136313031352e3830385a0101ff000000000000a0803082039e30820286a003020102020458761652300d06092a864886f70d0101020500303a310b3009060355040613024954310f300d060355040a0c06416e64786f72311a301806035504030c11416e64786f7220506f7274616c20545341301e170d3137303131313131323933315a170d3237303131313131323933315a303a310b3009060355040613024954310f300d060355040a0c06416e64786f72311a301806035504030c11416e64786f7220506f7274616c2054534130820122300d06092a864886f70d01010105000382010f003082010a02820101008e6f17600b485a3d3bc5272657d117785642e66abd50187d04639b0fac85f2e0d345b379c28a2a123ff1fcefaa159ce350685bd8f7434ec880b19d64e4b01be34c725ed22eac98306851cb9b9889b80f16ef821b1a5b572085c14c5dc5a14afbdcccfba643c4d44e69df9ce462c8d659e3f523117767379860a9039529347a5e7e6d29728819104a067d89eeb0580db1d2fbc5199ebd69afb0e3eea60e6cd9f6337d6e47c3c1d0442cc4db8c63babfa4d13c8356fc3fb7a28b3e7eca3d15fb29408f97ab883533b7c0d6220e1c33d81f09dfd7f0ad9884f3a2958806cf917fb86ed794220ccc5043bce062175ab2dd2144d6546a11092a138eea1f9e9def4b4f0203010001a381ab3081a830650603551d23045e305c8014b7552cf03ab7fd784c212cb6d47adc315d4e7d74a13ea43c303a310b3009060355040613024954310f300d060355040a1306416e64786f72311a301806035504031311416e64786f7220506f7274616c20545341820458761652301d0603551d0e04160414b7552cf03ab7fd784c212cb6d47adc315d4e7d74300b0603551d0f0404030204f030130603551d25040c300a06082b06010505070308300d06092a864886f70d0101020500038201010014908064e38c6b1f6dcc0b586f9d838c1c2561f8a4e4b6abf5b44fb0cb0f30a4de52095ae4f2782822cbb8768b942b017903539c8ea69b1eb729c0c29f0aa2ccd477af51116ac846f3e1a88c9e4fc97bc01f9ae7eda95afdf0f5641aaf5e805ee4f4930d4a2a5e77518d9046df9456a2dc7376d71ad30378743f077576ee3255ff2eb96eaa4d7485d702915130080ef108d1044d98378ee13666ddd7cc9b4ba505b0c4ef88c3bd46f313d991a9ebd14ebd2acfd6c6ac83e9ff173e5ff29dfd9026ee2c8f964d53250db4392273d421c5fbcf4c4f2c5d6a2792e81aa0d07ddd457e7d4fd9f57644609647f56b07d5ed8b56e697bfbedea454f3dab9ab1f52f44c0000318202413082023d0201013042303a310b3009060355040613024954310f300d060355040a0c06416e64786f72311a301806035504030c11416e64786f7220506f7274616c20545341020458761652300d06096086480165030402010500a081d1301a06092a864886f70d010903310d060b2a864886f70d0109100104301c06092a864886f70d010905310f170d3137303831383136313031355a302b060b2a864886f70d010910020c311c301a301830160414ee6f53b5b1d9f1323009f378922b9201a3547e6a302f06092a864886f70d01090431220420f572705055d9cbe88cff0127b62819eec1b4f761d772f0d468df022e2cd2f0753037060b2a864886f70d010910022f3128302630243022042072d8d3d7d67c25597d184dafb5fdd9792f512c1275a4993c91efa1db98bd9441300d06092a864886f70d01010105000482010062b0949525ecc2d5b097f4ffdbb7107a7814a57fd6306f3b70337a2b93206fd28c809ea65e3150a4f2fcca7e2a5523f2617226f4ad2d0eed71a02f8b2c6c0837e538f0a2a21200a749d8dfc1141d4773eb261e31d016e0fa6c5c96b59bcad0d0364bd12f25656b3083c18433eca3889ad21227455a3ec55b28a8b30bbdb38c0ed842d4b6695316faddb6903bb1deccc0ade2e7ebb55d1e65ddf2c050d2cf0c3788f4d8fb4da02d3d3dd6e661169a3e94718605586d29199d5d2fa954d3147ffc34434d0b44a0395f309a69fe1e0f8995d6d020ad89ed026aea364a548d62393a093a8ba40c5a40ae308c1edaf64f127984e352565fbcff9f3807f088e958a0a40000';
console.log(TimeStampResp.decode(Buffer.from(str, 'hex')));
console.log(TimeStampResp.decode(Buffer.from(str, 'hex'), 'der', {
partial: 1,
track: function (path, start, end, type) {
console.log([ type, path, start, end ]);
}
}));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment