Skip to content

PKCS

PFX / PKCS#12

Create a PFX bundle

ts
import {
  createSelfSignedCertificate,
  unwrap,
} from 'micro509';
import { createPfx } from 'micro509/pkcs';

const ca = await createSelfSignedCertificate({
  subject: { commonName: 'Demo CA' },
  extensions: { basicConstraints: { ca: true } },
});
const cert = await createSelfSignedCertificate({
  subject: { commonName: 'leaf.example' },
});

// createPfx returns a typed result; unwrap once inputs are validated
const pfx = unwrap(
  await createPfx({
    certificates: [
      { certificate: cert.certificate.pem },
      { certificate: ca.certificate.pem },
    ],
    privateKeys: [{ privateKey: cert.keyPair.privateKey }],
    encryption: { password: 'secret' },
    mac: { password: 'secret' },
  }),
);

console.log(`\
der bytes:  ${pfx.der.length}
base64 len: ${pfx.base64.length}`);

console.log(pfx.pem);

Parse a PFX bundle

ts
import {
  createSelfSignedCertificate,
  unwrap,
} from 'micro509';
import { createPfx, parsePfxDer } from 'micro509/pkcs';

// Build a PFX inline to parse back
const cert = await createSelfSignedCertificate({
  subject: { commonName: 'leaf.example' },
});
const pfx = unwrap(
  await createPfx({
    certificates: [{ certificate: cert.certificate.pem }],
    privateKeys: [{ privateKey: cert.keyPair.privateKey }],
    encryption: { password: 'secret' },
    mac: { password: 'secret' },
  }),
);

const result = await parsePfxDer(pfx.der, {
  password: 'secret',
});

if (result.ok) {
  const { certificates, privateKeys, bags } = result.value;
  const leafCert = certificates[0];
  console.log(`\
certs:        ${certificates.length}
private keys: ${privateKeys.length}
bags:         ${bags.length}
subject:      ${leafCert?.subject.values.commonName}
`);
} else {
  console.log(`parse failed: ${result.error.code}`);
}

PKCS#7 / CMS

Create a certificate bag

ts
import {
  createSelfSignedCertificate,
  unwrap,
} from 'micro509';
import { createPkcs7CertBagPem } from 'micro509/pkcs';

// Two real certificates to bundle
const a = await createSelfSignedCertificate({
  subject: { commonName: 'a.example' },
});
const b = await createSelfSignedCertificate({
  subject: { commonName: 'b.example' },
});

// createPkcs7CertBagPem returns a typed result; unwrap on the success path
const bag = unwrap(
  createPkcs7CertBagPem([
    a.certificate.pem,
    b.certificate.pem,
  ]),
);

console.log(`der bytes: ${bag.der.length}`);
console.log(bag.pem);

Parse a certificate bag

ts
import {
  createSelfSignedCertificate,
  unwrap,
} from 'micro509';
import {
  createPkcs7CertBagPem,
  parsePkcs7CertBagPem,
} from 'micro509/pkcs';

// Build a real cert bag inline
const a = await createSelfSignedCertificate({
  subject: { commonName: 'a.example' },
});
const b = await createSelfSignedCertificate({
  subject: { commonName: 'b.example' },
});
const bag = unwrap(
  createPkcs7CertBagPem([
    a.certificate.pem,
    b.certificate.pem,
  ]),
);

const result = parsePkcs7CertBagPem(bag.pem);

if (result.ok) {
  const certificates = result.value;
  console.log(`certs: ${certificates.length}`);
  for (const cert of certificates) {
    console.log(cert.subject.values.commonName);
  }
} else {
  console.log(`parse failed: ${result.error.code}`);
}

Sign and verify content

ts
import { createSelfSignedCertificate } from 'micro509';
import {
  createPkcs7SignedDataPem,
  verifyPkcs7SignedData,
} from 'micro509/pkcs';

// A signer is a certificate + its matching private key
const signer = await createSelfSignedCertificate({
  subject: { commonName: 'signer.example' },
  extensions: { keyUsage: ['digitalSignature'] },
});

// Sign content -> attached CMS SignedData (RFC 5652)
const content = new TextEncoder().encode('hello');
const signed = await createPkcs7SignedDataPem({
  content,
  signers: [
    {
      certificate: signer.certificate.pem,
      privateKey: signer.keyPair.privateKey,
    },
  ],
});

// Creation returns a typed result; verify on success
if (!signed.ok) {
  console.log(`sign failed: ${signed.error.code}`);
} else {
  const result = await verifyPkcs7SignedData(
    signed.value.pem,
  );
  if (result.ok) {
    const sd = result.value;
    const info = sd.signerInfos[0];
    console.log('verified: true');
    console.log(`\
signers:  ${sd.signerInfos.length}
digest:   ${info?.digestAlgorithmName}`);
  } else {
    console.log(`verify: ${result.error.code}`);
  }
}

PEM utilities

ts
import { createSelfSignedCertificate } from 'micro509';
import {
  categorizePemBlocks,
  pemDecode,
  pemEncode,
  splitPemBlocks,
} from 'micro509/pem';

// A real certificate to feed the PEM helpers
const { certificate } = await createSelfSignedCertificate({
  subject: { commonName: 'pem.example' },
});
const pem = certificate.pem;

// Decode a single PEM block to DER
const der = pemDecode('CERTIFICATE', pem);

// Encode DER back to PEM
const pemEncoded = pemEncode('CERTIFICATE', der);

// Split a multi-block PEM file
const multiPem = `${pem}\n${pem}`;
const blocks = splitPemBlocks(multiPem);

// Categorize blocks by type
const { certificates, certificateRequests, privateKeys } =
  categorizePemBlocks(multiPem);

console.log(`\
der bytes:    ${der.length}
round-trip:   ${pemEncoded === pem}
blocks:       ${blocks.length}
certs:        ${certificates.length}
csrs:         ${certificateRequests.length}
private keys: ${privateKeys.length}`);

Released under the MIT License.