npm package: @ownd-project/ts-toolbox
Description: TypeScript toolbox for SD-JWT and X.509 certificate operations
Author: OWND Project
Latest version: 1.0.1

# @ownd-project/ts-toolbox

TypeScript toolbox for SD-JWT (Selective Disclosure JWT) and X.509 certificate operations.

[![npm version](https://badge.fury.io/js/%40ownd-project%2Fts-toolbox.svg)](https://badge.fury.io/js/%40ownd-project%2Fts-toolbox)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Features

- 🔐 **SD-JWT (Selective Disclosure JWT)**: Issue and verify privacy-preserving credentials with selective disclosure
- 📜 **X.509 Certificate Management**: Generate, verify, and parse X.509 certificates and certificate chains
- 🔄 **Format Conversion**: Convert between JWK, PEM, and other cryptographic formats
- 🌲 **Tree-shaking Support**: Import only what you need for minimal bundle size
- 📦 **TypeScript Native**: Full type safety with comprehensive type definitions
- ✅ **Well-tested**: Comprehensive test suite with 17+ test cases

## Installation

```bash
npm install @ownd-project/ts-toolbox
```

## Quick Start

### SD-JWT Operations

#### Issue an SD-JWT Credential

```typescript
import { issueFlatCredential } from '@ownd-project/ts-toolbox/sd-jwt';
import { PrivateJwk } from 'elliptic-jwk';

const issuerPrivateJwk: PrivateJwk = {
  kty: 'EC',
  crv: 'P-256',
  x: '...',
  y: '...',
  d: '...'
};

const claims = {
  iss: 'https://issuer.example.com',
  iat: Math.floor(Date.now() / 1000),
  first_name: 'John',
  last_name: 'Doe',
  is_older_than_18: true,
  is_older_than_65: false
};

// Issue SD-JWT with X.509 certificate chain
const x5c = ['base64-encoded-cert'];
const credential = await issueFlatCredential(claims, issuerPrivateJwk, x5c);
```

#### Verify an SD-JWT Credential

```typescript
import { verifySdJwt } from '@ownd-project/ts-toolbox/sd-jwt';

const result = await verifySdJwt(credential, {
  skipVerifyChain: false,  // Verify X.509 certificate chain
  trustedRootCerts: [rootCertPem]  // Optional: custom root CA
});

if (result.ok) {
  console.log('Verified claims:', result.payload);
} else {
  console.error('Verification failed:', result.error);
}
```

#### Decode SD-JWT (without verification)

```typescript
import { decodeSdJwt } from '@ownd-project/ts-toolbox/sd-jwt';

const { issueJwt, disclosures } = decodeSdJwt(credential);
console.log('JWT:', issueJwt);
console.log('Disclosures:', disclosures);
```

### X.509 Certificate Operations

#### Generate a Root CA Certificate

```typescript
import { generateRootCaCsr, generateRootCertificate } from '@ownd-project/ts-toolbox/x509';
import * as jsrsasign from 'jsrsasign';

// Generate key pair
const keyPair = jsrsasign.KEYUTIL.generateKeypair('EC', 'secp256r1');

// Generate CSR with Root CA extensions
const csr = generateRootCaCsr(
  '/C=US/O=Example/CN=example.com',
  jsrsasign.KEYUTIL.getPEM(keyPair.pubKeyObj),
  jsrsasign.KEYUTIL.getPEM(keyPair.prvKeyObj, 'PKCS8PRV'),
  'SHA256withECDSA'
);

// Generate self-signed root certificate
const rootCert = generateRootCertificate(
  csr,
  new Date(Date.UTC(2024, 0, 1)),
  new Date(Date.UTC(2034, 0, 1)),
  'SHA256withECDSA',
  jsrsasign.KEYUTIL.getPEM(keyPair.prvKeyObj, 'PKCS8PRV')
);
```

#### Verify Certificate Chain

```typescript
import { verifyCertificateChain } from '@ownd-project/ts-toolbox/x509';

// Verify against system root certificates
await verifyCertificateChain([leafCert, intermediateCert, rootCert]);

// Verify against custom trusted roots
await verifyCertificateChain(
  [leafCert, intermediateCert],
  { trustedRootCerts: [customRootCertPem] }
);
```

#### Parse Certificate Information

```typescript
import { getCertificatesInfo } from '@ownd-project/ts-toolbox/x509';

// Accepts both PEM format and base64-encoded certificates
const certInfo = getCertificatesInfo([certPem]);

console.log('Subject:', certInfo[0].subject.commonName);
console.log('Issuer:', certInfo[0].issuer.commonName);
console.log('Serial Number:', certInfo[0].serialNumber);
console.log('Valid From:', certInfo[0].notBefore);
console.log('Valid Until:', certInfo[0].notAfter);
```

#### Generate Certificate Revocation List (CRL)

```typescript
import { generateCrl } from '@ownd-project/ts-toolbox/x509';

const revokedCerts = [
  {
    serialNumber: 'a1b2c3d4',
    revocationDate: new Date(),
    reason: 1  // Key compromise
  }
];

const crl = generateCrl(
  revokedCerts,
  '/C=US/O=Example/CN=example.com',
  1,  // CRL number
  new Date(Date.UTC(2025, 0, 1)),  // Next update
  'SHA256withECDSA',
  'keyIdentifierHex',
  issuerPrivateKeyPEM
);
```

### Format Conversion

```typescript
import { ellipticJwkToPem, getKeyAlgorithm } from '@ownd-project/ts-toolbox/converter';

// Convert JWK to PEM
const pemKeys = await ellipticJwkToPem({
  kty: 'EC',
  crv: 'P-256',
  x: '...',
  y: '...',
  d: '...'
});

console.log('Public Key PEM:', pemKeys.publicKey);
console.log('Private Key PEM:', pemKeys.privateKey);

// Get JWT algorithm from JWK
const alg = getKeyAlgorithm(jwk);  // Returns 'ES256', 'ES384', or 'ES512'
```

## API Documentation

### SD-JWT Module (`@ownd-project/ts-toolbox/sd-jwt`)

#### Issue Functions
- `issueFlatCredential(claims, issuerJwk, x5c)` - Issue SD-JWT with all claims selectively disclosable
- `issueCredentialCore(payload, disclosureFrame, issuerJwk, x5c)` - Issue SD-JWT with custom disclosure frame
- `getDisclosableClaims(claims)` - Get list of claims that can be selectively disclosed

#### Verify Functions
- `verifySdJwt(compactSDJWT, options)` - Verify SD-JWT and return disclosed claims
- `verifyJwt(jwt, options)` - Verify JWT with X.509 or JWK
- `decodeSdJwt(sdjwt)` - Decode SD-JWT without verification
- `createDefaultVerifier(options)` - Create default JWT verifier function
- `defaultKeyBindingVerifier(kbjwt, holderJWK)` - Default key binding verifier
- `defaultGetHasher(hashAlg)` - Default hasher implementation

#### Types
- `PublicKeySetting` - Options for public key verification
- `VerifySdJwtOptions` - Options for SD-JWT verification

#### Constants
- `AlwaysDisclosedClaimNames` - Standard JWT claims that are always disclosed

### X.509 Module (`@ownd-project/ts-toolbox/x509`)

#### Certificate Issue Functions
- `generateCsr(subject, publicKeyPem, privateKeyPem, algorithm, extensions)` - Generate CSR
- `generateRootCaCsr(subject, publicKeyPem, privateKeyPem, algorithm)` - Generate Root CA CSR with proper extensions
- `generateRootCertificate(csr, notBefore, notAfter, algorithm, issuerPrivateKeyPEM)` - Generate self-signed root certificate
- `generateCertificate(csr, issuerName, notBefore, notAfter, algorithm, issuerPrivateKeyPEM)` - Generate signed certificate
- `trimmer(str)` - Remove PEM headers/footers and newlines

#### Certificate Verification Functions
- `verifyCertificateChain(certs, options)` - Verify X.509 certificate chain

#### Certificate Revocation Functions
- `generateCrl(revokedCertificates, issuerName, crlNumber, nextUpdate, algorithm, keyIdentifierHex, issuerPrivateKeyPEM)` - Generate CRL

#### Certificate Parsing Functions
- `getCertificatesInfo(certs)` - Parse certificate information (accepts PEM or base64)
- `certificateStr2Array(certs)` - Convert PEM string to array of base64 certificates

#### Types
- `CertificateInfo` - Parsed certificate information
- `RevokedCertificate` - Revoked certificate entry for CRL

#### Constants
- `CSR_PEM_PREAMBLE` - "-----BEGIN CERTIFICATE REQUEST-----"
- `CSR_PEM_POSTAMBLE` - "-----END CERTIFICATE REQUEST-----"
- `CERT_PEM_PREAMBLE` - "-----BEGIN CERTIFICATE-----"
- `CERT_PEM_POSTAMBLE` - "-----END CERTIFICATE-----"

### Converter Module (`@ownd-project/ts-toolbox/converter`)

#### Certificate Conversion
- `jsonCertChainToPem(jsonCertChain)` - Convert JSON certificate chain to PEM

#### Binary/Hex Format Utilities
- `hexToBinary(hex)` - Convert hex string to binary Buffer
- `sha1Binary(binary)` - Calculate SHA-1 hash of binary data

#### Key Conversion
- `ellipticJwkToPem(jwk)` - Convert elliptic curve JWK to PEM format
- `getKeyAlgorithm(jwk)` - Get JWT algorithm name from JWK
- `checkEcdsaKeyEquality(pem1, pem2)` - Check if two ECDSA keys are equal

#### Types
- `PemKeyPair` - PEM key pair (public and private keys)

### Shared Utilities

#### Result Type
```typescript
type Result<T, E> =
  | { ok: true; payload: T }
  | { ok: false; error: E };
```

#### Date/Time Functions
- `formatDateTimeForDisplay(date)` - Format date for X.509 certificate display
- `formatDateToCustomCompactForm(date)` - Format date in compact form
- `getCurrentUTCDate()` - Get current UTC date

## Tree-shaking Support

This package is optimized for tree-shaking. Import only the modules you need:

```typescript
// ❌ Imports everything (~100KB)
import { verifySdJwt, generateRootCertificate } from '@ownd-project/ts-toolbox';

// ✅ Imports only SD-JWT verification (~30KB)
import { verifySdJwt } from '@ownd-project/ts-toolbox/sd-jwt';

// ✅ Imports only X.509 certificate generation (~40KB)
import { generateRootCertificate } from '@ownd-project/ts-toolbox/x509';

// ✅ Imports only format converters (~10KB)
import { ellipticJwkToPem } from '@ownd-project/ts-toolbox/converter';
```

## Development

### Build

```bash
npm run build
```

### Test

```bash
npm test
```

### Clean

```bash
npm run clean
```

## Dependencies

This package relies on the following libraries:
- [@meeco/sd-jwt](https://github.com/Meeco/sd-jwt) - SD-JWT implementation
- [jose](https://github.com/panva/jose) - JavaScript Object Signing and Encryption
- [pkijs](https://github.com/PeculiarVentures/PKI.js) - X.509 certificate chain validation
- [jsrsasign](https://github.com/kjur/jsrsasign) - RSA-Sign JavaScript Library
- [elliptic-jwk](https://github.com/aidantwoods/elliptic-jwk) - Elliptic curve JWK utilities

## License

MIT

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## Repository

https://github.com/OWND-Project/ts-toolbox

## Issues

https://github.com/OWND-Project/ts-toolbox/issues