npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@root/asn1

v1.0.2

Published

VanillaJS, Lightweight, Zero-Dependency, ASN.1 encoder and decoder.

Downloads

42,355

Readme

@root/asn1

Built by The Root Company for Greenlock and Keypairs.js

Lightweight, Zero-Dependency ASN.1 encoder and decoder for Node.js and Browsers, in less than 300 lines of vanilla JavaScript

| 1.6k gzipped | 4.2k minified | 8.4k pretty |

  • [x] Zero External Dependencies
  • [x] Universal Support
    • [x] Node.js
    • [x] Browsers
  • [x] Vanilla JS

This ASN.1 codec is built for simplicity. It encodes into DER format and decodes into a simple, classless Array of Arrays and values.

Most people don't actually want to work with ANS.1 directly, but rather intend to work with pre-defined x509 schemas.

If you're most people, you're actually looking for one or more of these:

Want to contribute? Need commercial support?

Usage

ASN.1 DER consists values which have

  • a type (2-bit class, 6-bit tag)
  • a coded length
  • zero or more values

Common types include:

0x30 SEQUENCE
0x02 INTEGER*
0x03 BIT STRING**
0x04 OCTET STRING
0x05 NULL
0x06 OBJECT IDENTIFIER
0x0C UTF8String
0x16 IA5String (ASCII)
0x17 UTCTime
0x31 SET
0xA0 context-specific***
0xA3 context-specific***

* INTEGERS are always BigInt-encoded (a leading '00' for positive numbers with a 1 in the most-significant-bit position)

**BIT STRINGS have a leading "bit mask" which, for all practical purposes, is actually always '00'

*** See https://stackoverflow.com/a/15071901/151312

The core value in this library is that it:

  • correctly sums the byte length of children elements
  • correctly encodes BigInts

Parser Usage

There are three options:

  • der (required) - the input bytes as a buffer
  • json (default) - returns hex strings for values, rather than buffers
  • verbose - returns a more human-friendly object that is useful for debugging
ASN1.parse({ der: `<Buffer>`, json: true, verbose: true });

Default (hex) output:

[
	'30',
	[
		['02', '01'],
		['04', '2c8996...'],
		['a0', [['06', '2a8648...']]],
		['a1', [['03', '04bdd8...']]]
	]
];

Verbose output:

{ type: 48,
  lengthSize: 0,
  length: 119,
  children:
   [ { type: 2, lengthSize: 0, length: 1, value: <Buffer 01> },
     { type: 4,
       lengthSize: 0,
       length: 32,
       value:
        <Buffer 2c 89 96 ...>,
       children: [] },
     { type: 160, lengthSize: 0, length: 10, children: [Array] },
     { type: 161, lengthSize: 0, length: 68, children: [Array] } ] }

Packer Usage

You can use either of two syntaxes. One is much easier to read than the other.

Ironically, hex strings are used in place of buffers for efficiency.

ASN1.Any(hexType, hexBytes1, hexBytes2, ...);
ASN1.UInt(hexBigInt);
ASN1.BitStr(hexBitStream);

In practice, you'll be cascading the objects into a final hex string:

// result is a hex-encoded DER
var der = hexToBuf(
  ASN1.Any('30'                         // Sequence
  , ASN1.UInt('01')                     // Integer (Version 1)
  , ASN1.Any('04', '07CAD7...')         // Octet String
  , ASN1.Any('A0', '06082A...')         // [0] Object ID (context-specific)
  , ASN1.Any('A1',                      // [1] (context-specific value)
      ASN1.BitStr('04BDD8...')
    )
  )
);

Alternatively you can pack either the sparse array or verbose object, using hex strings or buffers:

  • json when set to true will return a hex-encoded DER rather than a DER buffer
var buf = Uint8Array.from([0x01]);

ASN1.pack(
	[
		'30',
		[
			['02', buf],
			['04', '07CAD7...'],
			['A0', '06082A...'],
			['A1', ['03', '04BDD8...']]
		]
	],
	{ json: false }
);
var buf = Uint8Array.from([0x01]);

ASN1.pack(
	{
		type: 48,
		children: [
			{ type: 2, value: '01' },
			{ type: 4, value: '2c 89 96 ...', children: [] },
			{ type: 160, children: [...] },
			{ type: 161, children: [...] }
		]
	},
	{ json: false }
);

Install

This package contains both node-specific and browser-specific code, and the package.json#browser field ensures that your package manager will automatically choose the correct code for your environment.

Node (and Webpack)

npm install -g @root/asn1
var asn1 = require('@root/asn1');
// just the packer
var asn1 = require('@root/asn1/packer');

// just the parser
var asn1 = require('@root/asn1/parser');

Browsers (Vanilla JS)

<script src="https://unpkg.com/@root/asn1/dist/asn1.all.js"></script>
<script src="https://unpkg.com/@root/asn1/dist/asn1.all.min.js"></script>
var ASN1 = window.ASN1;

Examples

Decoding DER to JSON-ASN.1

var PEM = require('@root/pem/packer');
var Enc = require('@root/encoding');
var ASN1 = require('@root/asn1/parser');
var pem = [
	'-----BEGIN EC PRIVATE KEY-----',
	'MHcCAQEEICyJlsaqkx2z9yx0H6rHA0lM3/7jXjxqn/VOhExHDuR6oAoGCCqGSM49',
	'AwEHoUQDQgAEvdjQ3T6VBX82LIKDzepYgRsz3HgRwp83yPuonu6vqoshSQRe0Aye',
	'mmdXUDX2wTZsmFSjhY9uroRiBbGZrigbKA==',
	'-----END EC PRIVATE KEY-----'
].join('\n');
var der = PEM.parseBlock(pem).bytes;
var asn1 = ASN1.parse({ der: der, json: true, verbose: false });
[
	"30",
	[
		["02", "01"],
		[
			"04",
			"2c8996c6aa931db3f72c741faac703494cdffee35e3c6a9ff54e844c470ee47a"
		],
		["a0", [["06", "2a8648ce3d030107"]]],
		[
			"a1",
			[
				[
					"03",
					"04bdd8d0dd3e95057f362c8283cdea58811b33dc7811c29f37c8fba89eeeafaa8b2149045ed00c9e9a67575035f6c1366c9854a3858f6eae846205b199ae281b28"
				]
			]
		]
	]
]
{
	"type": 48,
	"lengthSize": 0,
	"length": 119,
	"children": [
		{ "type": 2, "lengthSize": 0, "length": 1, "value": "01" },
		{
			"type": 4,
			"lengthSize": 0,
			"length": 32,
			"value": "2c8996c6aa931db3f72c741faac703494cdffee35e3c6a9ff54e844c470ee47a",
			"children": []
		},
		{
			"type": 160,
			"lengthSize": 0,
			"length": 10,
			"children": [
				{
					"type": 6,
					"lengthSize": 0,
					"length": 8,
					"value": "2a8648ce3d030107"
				}
			]
		},
		{
			"type": 161,
			"lengthSize": 0,
			"length": 68,
			"children": [
				{
					"type": 3,
					"lengthSize": 0,
					"length": 66,
					"value": "04bdd8d0dd3e95057f362c8283cdea58811b33dc7811c29f37c8fba89eeeafaa8b2149045ed00c9e9a67575035f6c1366c9854a3858f6eae846205b199ae281b28",
					"children": []
				}
			]
		}
	]
}

Encoding ASN.1 to DER

Here's an example of an SEC1-encoded EC P-256 Public/Private Keypair:

var ASN1 = require('@root/asn1/packer');
var Enc = require('@root/encoding');
var PEM = require('@root/pem/packer');
// 1.2.840.10045.3.1.7
// prime256v1 (ANSI X9.62 named elliptic curve)
var OBJ_ID_EC_256 = '06 08 2A8648CE3D030107';
var jwk = {
	crv: 'P-256',
	d: 'LImWxqqTHbP3LHQfqscDSUzf_uNePGqf9U6ETEcO5Ho',
	kty: 'EC',
	x: 'vdjQ3T6VBX82LIKDzepYgRsz3HgRwp83yPuonu6vqos',
	y: 'IUkEXtAMnppnV1A19sE2bJhUo4WPbq6EYgWxma4oGyg',
	kid: 'MnfJYyS9W5gUjrJLdn8ePMzik8ZJz2qc-VZmKOs_oCw'
};
var d = Enc.base64ToHex(jwk.d);
var x = Enc.base64ToHex(jwk.x);
var y = Enc.base64ToHex(jwk.y);
var der = Enc.hexToBuf(
  ASN1.Any('30'                         // Sequence
  , ASN1.UInt('01')                     // Integer (Version 1)
  , ASN1.Any('04', d)                   // Octet String
  , ASN1.Any('A0', OBJ_ID_EC_256)       // [0] Object ID
  , ASN1.Any('A1',                      // [1] Embedded EC/ASN1 public key
      ASN1.BitStr('04' + x + y)
    )
  )
);

var pem = PEM.packBlock({
  type: 'EC PRIVATE KEY',
  bytes: der
});

Disabiguation

ASN1.Any(typ, hexVal, ...)

There was once an actual ASN.1 type with the literal name 'Any'. It was deprecated in 1994 and the Any in this API simply means "give any value"

Contributions

Did this project save you some time? Maybe make your day? Even save the day?

Please say "thanks" via Paypal or Patreon:

Where does your contribution go?

Root is a collection of experts who trust each other and enjoy working together on deep-tech, Indie Web projects.

Our goal is to operate as a sustainable community.

Your contributions - both in code and especially monetarily - help to not just this project, but also our broader work of projects that fuel the Indie Web.

Commercial Support

Do you need...

  • more features?
  • bugfixes, on your timeline?
  • custom code, built by experts?
  • commercial support and licensing?

Contact [email protected] for support options.

Legal

Copyright AJ ONeal, Root 2018-2019

MPL-2.0 | Terms of Use | Privacy Policy