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 🙏

© 2026 – Pkg Stats / Ryan Hefner

node-certkit

v1.1.1

Published

Node-only TypeScript PKI and cryptography library for certificate handling (PKCS#12, X.509, RSA).

Readme

node-certkit

Main Checks

Node-only TypeScript toolkit for PKI, certificates, and cryptography.

Features

  • X.509 — create, parse, sign, and verify certificates and chains
  • CSR (PKCS#10) — create and verify certificate signing requests
  • PKCS#12 / PFX — load and export password-protected certificate bundles
  • PKCS#8 — private key encoding and PEM conversion
  • RSA — key generation, sign/verify, PSS, and OAEP
  • ASN.1 / DER — encode and decode ASN.1 structures
  • PEM — encode and decode PEM blocks
  • Symmetric ciphers — AES (ECB, CBC, CFB, OFB, CTR, GCM), DES/3DES, RC2
  • Digests — MD5, SHA-1, SHA-256, SHA-384, SHA-512, HMAC
  • PBKDF2 — password-based key derivation
  • PRNG — Fortuna random number generator
  • Math — BigInteger and probable-prime generation

This library does not include TLS, HTTP, SSH, browser bundles, or Ed25519. It targets server-side Node.js workflows such as certificate issuance, PKCS#12 handling, and low-level PKI operations.

Requirements

  • Node.js >= 24

Installation

npm install node-certkit

Usage

The package is published as CommonJS (lib/). Both import styles are supported:

CommonJS

const certkit = require('node-certkit').default;

ESM (Node.js consuming CJS)

import certkit from 'node-certkit';

Self-signed certificate

import certkit from 'node-certkit';

const keys = certkit.pki.rsa.generateKeyPair(2048);
const cert = certkit.pki.createCertificate();

cert.publicKey = keys.publicKey;
cert.serialNumber = '01';
cert.validity.notBefore = new Date();
cert.validity.notAfter = new Date();
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);

const attrs = [{name: 'commonName', value: 'example.org'}];
cert.setSubject(attrs);
cert.setIssuer(attrs);
cert.sign(keys.privateKey);

console.log(certkit.pki.certificateToPem(cert));

See examples/create-cert.js for a full example with extensions.

Certificate signing request (CSR)

import certkit from 'node-certkit';

const keys = certkit.pki.rsa.generateKeyPair(2048);
const csr = certkit.pki.createCertificationRequest();

csr.publicKey = keys.publicKey;
csr.setSubject([{name: 'commonName', value: 'example.org'}]);
csr.sign(keys.privateKey);

console.log(certkit.pki.certificationRequestToPem(csr));
console.log(csr.verify()); // true

See examples/create-csr.js.

PKCS#12 / PFX

Create a PKCS#12 bundle and load it back:

import certkit from 'node-certkit';

const keys = certkit.pki.rsa.generateKeyPair(2048);
const cert = certkit.pki.createCertificate();
// ... configure and sign cert ...

const password = 'secret';
const asn1 = certkit.pkcs12.toPkcs12Asn1(
  keys.privateKey, [cert], password,
  {generateLocalKeyId: true, friendlyName: 'my-cert'});
const der = certkit.asn1.toDer(asn1).getBytes();

const loaded = certkit.pkcs12.pkcs12FromAsn1(
  certkit.asn1.fromDer(der), false, password);

See examples/create-pkcs12.js for chain verification and bag extraction.

RSA sign and verify

import certkit from 'node-certkit';

const keys = certkit.pki.rsa.generateKeyPair(2048);
const md = certkit.md.sha256.create();
md.update('sign this', 'utf8');

const signature = keys.privateKey.sign(md);
const verified = keys.publicKey.verify(md.digest().getBytes(), signature);

AES-GCM

import certkit from 'node-certkit';

const key = certkit.random.getBytesSync(16);
const iv = certkit.random.getBytesSync(12);
const cipher = certkit.cipher.createCipher('AES-GCM', key);
cipher.start({iv, tagLength: 128});
cipher.update(certkit.util.createBuffer('hello'));
cipher.finish();

const encrypted = cipher.output.getBytes();
const tag = cipher.mode.tag.getBytes();

Message digests and HMAC

import certkit from 'node-certkit';

const md = certkit.md.sha256.create();
md.update('message', 'utf8');
console.log(md.digest().toHex());

const hmac = certkit.hmac.create();
hmac.start('sha256', 'secret-key');
hmac.update('message', 'utf8');
console.log(hmac.digest().toHex());

PBKDF2

import certkit from 'node-certkit';

const key = certkit.pkdf2('password', 'salt', 32, 100000, 'sha256');

ASN.1 and PEM

import certkit from 'node-certkit';

const pem = certkit.pki.certificateToPem(cert);
const parsed = certkit.pki.certificateFromPem(pem);

const asn1 = certkit.asn1.fromDer(derBytes);
const der = certkit.asn1.toDer(asn1).getBytes();

API overview

The default export is a flat namespace assembled at load time. Main areas:

| Namespace | Purpose | |-----------|---------| | certkit.pki | X.509, CSR, PEM, OIDs, CA store, chain verification | | certkit.pki.rsa | RSA key generation | | certkit.pkcs12 | PKCS#12 load and export | | certkit.asn1 | ASN.1 DER encoding and decoding | | certkit.cipher / certkit.aes / certkit.des / certkit.rc2 | Symmetric encryption | | certkit.md / certkit.md5 / certkit.sha1 / certkit.sha256 / certkit.sha512 | Digests | | certkit.hmac | HMAC | | certkit.pbkdf2 | PBKDF2 key derivation | | certkit.pem | Generic PEM encode/decode | | certkit.util | Buffers, Base64, hex, encoding helpers | | certkit.random / certkit.prng | Random bytes and PRNG | | certkit.jsbn | BigInteger | | certkit.prime | Probable-prime generation | | certkit.pkcs1 | RSA-OAEP encoding | | certkit.pss | RSA-PSS | | certkit.mgf / certkit.mgf1 | Mask generation functions |

Named exports from the package entry:

import certkit, {createCertkit} from 'node-certkit';

TypeScript / migrating from node-forge

This package ships its own types (no @types/node-forge needed). The runtime API is intentionally similar to node-forge; most call sites only need to change the import:

// before
import forge from 'node-forge';

// after
import certkit from 'node-certkit';

Type equivalents

| node-forge (@types/node-forge) | node-certkit | |----------------------------------|--------------| | forge.pkcs12.PKCS12Pfx | Pkcs12Pfx or certkit.pkcs12.Pkcs12Pfx (named import) | | forge.pki.Certificate | X509Certificate or certkit.pki.Certificate (named import) | | forge.pki.rsa.PrivateKey | RsaPrivateKey or certkit.pki.rsa.PrivateKey (named import) | | forge.asn1.Asn1 | Asn1Object or certkit.asn1.Asn1 (named import) | | forge.util.ByteBuffer | ByteStringBuffer or certkit.util.ByteBuffer (named import) |

Importing types

Important: import certkit from 'node-certkit' gives you the runtime API only. Forge-style namespace types such as certkit.pki.rsa.PrivateKey require the named import (same instance, merged with the type namespace):

// TS2503: Cannot find namespace 'certkit' — default import has no type namespace
import certkit from 'node-certkit';
let key: certkit.pki.rsa.PrivateKey; // error

// Correct: named import for runtime + namespace types
import { certkit, type Pkcs12Pfx } from 'node-certkit';

let privateKey: certkit.pki.rsa.PrivateKey | null = null;
let certificate: certkit.pki.Certificate | null = null;

With default import, use named type exports instead of namespace paths:

import certkit, { type Pkcs12Pfx, type RsaPrivateKey, type X509Certificate } from 'node-certkit';

function getKey(p12: Pkcs12Pfx): string {
  const bags = p12.getBags({ bagType: certkit.pki.oids.keyBag });
  // ...
}

NFSe certificate load (typed)

Typical flow when rebuilding a PKCS#12 for NFSe — uses named import throughout:

import { certkit, type Pkcs12Pfx } from 'node-certkit';

export function loadCertificateNFSe(p12: Pkcs12Pfx) {
  let privateKey: certkit.pki.rsa.PrivateKey | null = null;
  let certificate: certkit.pki.Certificate | null = null;
  const caCertificates: certkit.pki.Certificate[] = [];

  for (const safeContent of p12.safeContents) {
    for (const bag of safeContent.safeBags) {
      if (bag.type === certkit.pki.oids.keyBag) {
        privateKey = bag.key ?? null; // bag.key is optional
      }
      if (bag.type === certkit.pki.oids.certBag && bag.cert) {
        const bc = bag.cert.getExtension('basicConstraints');
        if (!bc || bc['cA'] === false) {
          certificate = bag.cert;
        } else {
          caCertificates.push(bag.cert);
        }
      }
    }
  }

  const tempPassword = Math.random().toString(36).substring(2);
  const p12Asn1 = certkit.pkcs12.toPkcs12Asn1(
    privateKey!,
    [certificate!, ...caCertificates],
    tempPassword,
    { algorithm: '3des' }
  );
  const p12Der = certkit.asn1.toDer(p12Asn1).getBytes();
  return { p12Buffer: Buffer.from(p12Der, 'binary'), tempPassword };
}

Note: bag.certChain from node-forge typings is not populated by certkit; use bag.cert only. safeContents[].safeBags is already Pkcs12Bag[] (no need for Object.values + Array.isArray).

PKCS#12 load (typed)

import certkit, { type Pkcs12Pfx } from 'node-certkit';

const decoded = certkit.util.binary.base64.decode(base64Pfx);
const asn = certkit.asn1.fromDer(new certkit.util.ByteStringBuffer(decoded));
const p12: Pkcs12Pfx = certkit.pkcs12.pkcs12FromAsn1(asn, true, password);

util.binary.base64.decode(input) returns Uint8Array (no need to wrap with new Uint8Array(...) unless you want a copy).

Stricter null checks

Unlike @types/node-forge (which used any in several places), certkit types are strict. certificate.subject.getField(...) returns DnAttribute | null:

const cn = certificate.subject.getField({ name: 'commonName' });
if (!cn) {
  throw new Error('commonName not found in certificate subject');
}
const values = cn.value.toString().split(':');

Testing

Prepare to run tests

npm install

Running tests

Tests run with Vitest against the TypeScript sources in src/:

npm test

Watch mode:

npm run test:watch

Type-check tests only (strict, no emit):

npm run test:types

Public API type regression (consumer usage + golden test):

npm run test:types:public

Published declaration file (lib/index.d.ts):

npm run build && npm run test:dts

Security regression tests live under tests/security/ and are included in npm test.

Snapshots and fixtures

  • tests/api-surface.snapshot.json and tests/instance-shape.snapshot.json are compared by snapshot tests. Do not regenerate them to silence failures without investigating each divergence.
  • tests/fixtures/ holds PKCS#12 golden inputs for certificate-load tests.

License

MIT

Credits

Based on node-forge by Digital Bazaar.