PKI-Lite - v1.2.1
    Preparing search index...

    PKI-Lite Examples

    This directory contains example scripts demonstrating how to use the PKI-Lite library.

    import { PrivateKeyInfo } from 'pki-lite/keys/PrivateKeyInfo.js'
    import { Certificate } from 'pki-lite/x509/Certificate.js'

    const privateKeyPem = `-----BEGIN PRIVATE KEY-----{your private key here}-----END PRIVATE`
    const certPem = `-----BEGIN CERTIFICATE-----{your certificate here}-----END CERTIFICATE-----`

    const selfSigned = await Certificate.createSelfSigned({
    subject: 'CN=Test Self-Signed Certificate, O=My Organization, C=US',
    validity: {
    notBefore: new Date('2023-01-01T00:00:00Z'),
    notAfter: new Date('2024-01-01T00:00:00Z'),
    },
    privateKeyInfo: PrivateKeyInfo.fromPem(privateKeyPem),
    subjectPublicKeyInfo:
    Certificate.fromPem(certPem).tbsCertificate.subjectPublicKeyInfo,
    })

    console.log('Self-Signed Certificate PEM:', selfSigned.toPem())
    import { PFX } from 'pki-lite/pkcs12/PFX.js'

    const pem = `-----BEGIN PKCS12-----
    {your pfx data here}
    -----END PKCS12-----`

    const pfx = PFX.fromPem(pem)
    console.log('PFX version:', pfx.version)
    console.log('Has MAC data:', !!pfx.macData)

    const bags = await pfx.getBags('test')
    console.log(`Found ${bags.length} bags`)

    const privateKeys = await pfx.getPrivateKeys('test')
    console.log(`Found ${privateKeys.length} private keys`)
    privateKeys.forEach((key, index) => {
    console.log(`Private Key ${index + 1}:`, key.getPrivateKey().toPem())
    })

    const certificates = await pfx.getX509Certificates('test')
    console.log(`Found ${certificates.length} certificates`)
    certificates.forEach((cert, index) => {
    console.log(`Certificate ${index + 1}:`, cert.toPem())
    })
    import { DigestAlgorithmIdentifier } from 'pki-lite/algorithms/AlgorithmIdentifier.js'
    import { MessageImprint } from 'pki-lite/timestamp/MessageImprint.js'
    import { TimeStampReq } from 'pki-lite/timestamp/TimeStampReq.js'

    // 1. Create a message to be timestamped (usually this would be a signature)
    const messageToTimestamp = new TextEncoder().encode('Hello, World!')

    // 2. Create a hash of the message using SHA-256
    const hashBuffer = await crypto.subtle.digest('SHA-256', messageToTimestamp)
    const hashBytes = new Uint8Array(hashBuffer)

    console.log(
    'Message hash (SHA-256):',
    Array.from(hashBytes)
    .map((b) => b.toString(16).padStart(2, '0'))
    .join(''),
    )

    // 3. Create the MessageImprint
    const hashAlgorithm = DigestAlgorithmIdentifier.digestAlgorithm('SHA-256')
    const messageImprint = new MessageImprint({
    hashAlgorithm: hashAlgorithm,
    hashedMessage: hashBytes,
    })

    // 4. Create the TimeStampReq
    const nonce = crypto.getRandomValues(new Uint8Array(8)) // Random 8-byte nonce
    const tsReq = TimeStampReq.create({
    messageImprint,
    certReq: true, // Request certificates in the response
    nonce: nonce,
    })

    console.log('TimeStampReq created:')
    console.log('- Version:', tsReq.version)
    console.log('- Hash Algorithm:', tsReq.messageImprint.hashAlgorithm.algorithm)
    console.log('- Certificate Requested:', tsReq.certReq)

    // 5. Generate the DER encoding for sending to a TSA server
    const derEncoded = tsReq.toDer()
    console.log('DER encoded request size:', derEncoded.length, 'bytes')

    const response = await tsReq.request({
    url: 'https://freetsa.org/tsr',
    timeout: 10000,
    })

    console.log('Response status:', response.status.getStatusDescription())

    if (response.isSuccess()) {
    console.log('Timestamp token received!')
    const tokenDer = response.getTimeStampTokenDer()
    if (tokenDer) {
    console.log('Token size:', tokenDer.length, 'bytes')
    }
    }

    // 7. Demonstrate parsing a TimeStampReq from DER
    const parsedReq = TimeStampReq.fromDer(derEncoded)
    console.log('Parsed request version:', parsedReq.version)
    console.log('Parsed request certReq:', parsedReq.certReq)

    console.log('TimeStampResp created:')
    console.log('- Status:', response.status.getStatusDescription())
    console.log('- Success:', response.isSuccess())
    console.log('- Has token:', !!response.timeStampToken)

    const respDer = response.toDer()
    console.log('DER encoded response size:', respDer.length, 'bytes')
    import { Certificate } from 'pki-lite/x509/Certificate.js'

    const certPem = `-----BEGIN CERTIFICATE-----{your certificate here}-----END CERTIFICATE-----`
    const certificate = Certificate.fromPem(certPem)

    // NB: This will only work if the CRL distribution point is accessible
    const crl = await certificate.requestCrl()
    if (!crl) {
    console.log('No CRL found')
    } else {
    console.log('Successfully found CRL', crl.toString())
    }
    import { Certificate } from 'pki-lite/x509/Certificate.js'

    const certPem =
    '-----BEGIN CERTIFICATE-----{your certificate here}-----END CERTIFICATE-----'
    const issuerCertPem =
    '-----BEGIN CERTIFICATE-----{your issuer certificate here}-----END CERTIFICATE-----'
    const certificate = Certificate.fromPem(certPem)

    // NB: This will only work if the OCSP responder is accessible
    const ocsp = await certificate.requestOcsp({
    issuerCertificate: Certificate.fromPem(issuerCertPem),
    })

    if (!ocsp) {
    console.log('No OCSP response found')
    } else {
    console.log('OCSP Response:', ocsp.toString())
    }
    // Make sure to import the extended crypto module to enable these algorithms
    import 'pki-lite-crypto-extended'

    import { AlgorithmIdentifier } from 'pki-lite/algorithms/AlgorithmIdentifier'

    const algorithm = AlgorithmIdentifier.contentEncryptionAlgorithm({
    type: 'SHA1_3DES_3KEY_CBC',
    params: {
    salt: new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef]),
    iterationCount: 2048,
    },
    })

    console.log('Algorithm OID:', algorithm.algorithm.toString())

    const toBeEncrypted = new TextEncoder().encode('Hello, World!')
    const encrypted = await algorithm.encrypt(
    toBeEncrypted,
    'password', // Can also be a Uint8Array<ArrayBuffer>
    )

    const decrypted = await algorithm.decrypt(
    encrypted,
    'password', // Can also be a Uint8Array<ArrayBuffer>
    )
    console.log('Decrypted data:', new TextDecoder().decode(decrypted))
    import { PrivateKeyInfo } from 'pki-lite/keys/PrivateKeyInfo'
    import { SignedData } from 'pki-lite/pkcs7/SignedData'
    import { Certificate } from 'pki-lite/x509/Certificate'

    const certPem = `-----BEGIN CERTIFICATE-----{your certificate here}-----END CERTIFICATE-----`
    const keyPem = `-----BEGIN PRIVATE KEY-----{your private key here}-----END PRIVATE KEY-----`

    const certificate = Certificate.fromPem(certPem)
    const privateKey = PrivateKeyInfo.fromPem(keyPem)

    const signedData = await SignedData.builder()
    .setData(new TextEncoder().encode('Hello, World!'))
    .addCertificate(certificate)
    .addSigner({
    certificate,
    privateKeyInfo: privateKey,
    tsa: {
    url: 'http://timestamp.digicert.com',
    },
    })
    .build()

    console.log(signedData.toCms())
    import { KeyGen } from 'pki-lite/core/KeyGen.js'
    import { EnvelopedData } from 'pki-lite/pkcs7/EnvelopedData'
    import { Certificate } from 'pki-lite/x509/Certificate'

    console.log('=== Enveloped Data Example ===\n')

    // Generate a key pair and create a certificate for the recipient
    console.log('Generating RSA key pair for recipient...')
    const keyPair = await KeyGen.generateRsaPair({ keySize: 2048 })

    console.log('Creating recipient certificate...')
    const certificate = await Certificate.builder()
    .setSubject('CN=Recipient, O=Example Org')
    .setPublicKey(keyPair.publicKey)
    .setPrivateKey(keyPair.privateKey)
    .setValidityDays(365)
    .generateSerialNumber()
    .selfSign()

    console.log('✓ Certificate created\n')

    // Create enveloped data (encrypted message)
    console.log('Creating enveloped data...')
    const plaintext = 'Hello, World! This is a secret message.'
    const envelopedData = await EnvelopedData.builder()
    .setData(new TextEncoder().encode(plaintext))
    .addRecipient({ certificate })
    .build()

    console.log('✓ Enveloped data created')
    console.log('\nEnveloped Data (CMS):')
    console.log(envelopedData.toCms().toString())

    // Decrypt the enveloped data
    console.log('\nDecrypting...')
    const decrypted = await envelopedData.decrypt(keyPair.privateKey)
    console.log('✓ Decrypted successfully')
    console.log('Decrypted text:', new TextDecoder().decode(decrypted))
    import { KeyGen } from 'pki-lite/core/KeyGen.js'

    // Generate an RSA key pair with 2048-bit key size
    console.log('Generating RSA-2048 key pair...')
    const rsaKeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })

    console.log('RSA Private Key (PEM):')
    console.log(rsaKeyPair.privateKey.toPem())
    console.log('\nRSA Public Key (PEM):')
    console.log(rsaKeyPair.publicKey.toPem())

    // Generate an ECDSA key pair using P-256 curve
    console.log('\n\nGenerating ECDSA P-256 key pair...')
    const ecKeyPair = await KeyGen.generateEcPair({ namedCurve: 'P-256' })

    console.log('EC Private Key (PEM):')
    console.log(ecKeyPair.privateKey.toPem())
    console.log('\nEC Public Key (PEM):')
    console.log(ecKeyPair.publicKey.toPem())

    // Generate an ECDSA key pair using P-384 curve
    console.log('\n\nGenerating ECDSA P-384 key pair...')
    const ecP384KeyPair = await KeyGen.generateEcPair({ namedCurve: 'P-384' })

    console.log('EC P-384 Private Key (PEM):')
    console.log(ecP384KeyPair.privateKey.toPem())

    // You can also extract the raw key objects
    const privateKey = rsaKeyPair.privateKey.getPrivateKey()
    console.log('\n\nRSA Private Key type:', privateKey.constructor.name)

    const ecPrivateKey = ecKeyPair.privateKey.getPrivateKey()
    console.log('EC Private Key type:', ecPrivateKey.constructor.name)
    import { KeyGen } from 'pki-lite/core/KeyGen.js'
    import { CertificateRequest } from 'pki-lite/x509/CertificateRequest.js'

    // Generate a key pair
    console.log('Generating RSA key pair...')
    const keyPair = await KeyGen.generateRsaPair()
    console.log('✓ Key pair generated\n')

    // Build and sign the CSR
    const csr = await CertificateRequest.builder()
    .setSubject('CN=example.com, O=Example Organization, C=US')
    .setPublicKey(keyPair.publicKey)
    .setPrivateKey(keyPair.privateKey)
    .addKeyUsage({
    digitalSignature: true,
    keyEncipherment: true,
    })
    .addExtendedKeyUsage({
    serverAuth: true,
    })
    .addSubjectAltName('example.com', 'www.example.com')
    .build()

    // Output the CSR in PEM format
    console.log('Certificate Signing Request (PEM):')
    console.log(csr.toPem())

    // You can also verify the CSR by parsing it back
    const parsedCsr = CertificateRequest.fromPem(csr.toPem())
    console.log('\n✓ CSR successfully created and parsed')
    console.log('Subject:', parsedCsr.requestInfo.subject.toString())
    console.log(
    'Signature Algorithm:',
    parsedCsr.signatureAlgorithm.algorithm.toString(),
    )
    console.log(
    'Number of attributes:',
    parsedCsr.requestInfo.attributes?.length ?? 0,
    )
    import { KeyGen } from 'pki-lite/core/KeyGen.js'
    import { Certificate } from 'pki-lite/x509/Certificate.js'

    console.log('=== Step 1: Generate CA Key Pair ===')
    const caKeyPair = await KeyGen.generateRsaPair({ keySize: 4096 })
    console.log('✓ CA key pair generated')

    console.log('\n=== Step 2: Create CA Certificate (Self-Signed) ===')

    // Build and sign the CA certificate
    const caCertificate = await Certificate.builder()
    .setSubject('CN=Example CA, O=Example Organization, C=US')
    .setPublicKey(caKeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey)
    .setValidityDays(3650) // 10 years
    .generateSerialNumber()
    .addBasicConstraints(true, 0) // CA with path length 0
    .addKeyUsage({
    keyCertSign: true, // Can sign certificates
    cRLSign: true, // Can sign CRLs
    })
    .selfSign()

    console.log('✓ CA certificate created')
    console.log(' Subject:', caCertificate.tbsCertificate.subject.toString())
    console.log(' Serial:', caCertificate.tbsCertificate.serialNumber.toString())
    console.log(
    ' Valid from:',
    caCertificate.tbsCertificate.validity.notBefore.toISOString(),
    )
    console.log(
    ' Valid until:',
    caCertificate.tbsCertificate.validity.notAfter.toISOString(),
    )

    console.log('\n=== Step 3: Generate End-Entity Key Pair ===')
    const endEntityKeyPair = await KeyGen.generateRsaPair()
    console.log('✓ End-entity key pair generated')

    console.log('\n=== Step 4: Issue End-Entity Certificate ===')

    // Build and sign the end-entity certificate with the CA
    const endEntityCertificate = await Certificate.builder()
    .setSubject('CN=example.com, O=Example Organization, C=US')
    .setIssuer(caCertificate) // The CA certificate
    .setPublicKey(endEntityKeyPair.publicKey)
    .setIssuerPrivateKey(caKeyPair.privateKey) // Sign with CA's private key
    .setValidityDays(365) // 1 year
    .generateSerialNumber()
    .addBasicConstraints(false) // Not a CA
    .addKeyUsage({
    digitalSignature: true,
    keyEncipherment: true,
    })
    .addExtendedKeyUsage({
    serverAuth: true,
    clientAuth: true,
    })
    .addSubjectAltName('example.com', 'www.example.com', '*.example.com')
    .sign()

    console.log('✓ End-entity certificate issued')
    console.log(
    ' Subject:',
    endEntityCertificate.tbsCertificate.subject.toString(),
    )
    console.log(' Issuer:', endEntityCertificate.tbsCertificate.issuer.toString())
    console.log(
    ' Serial:',
    endEntityCertificate.tbsCertificate.serialNumber.toString(),
    )
    console.log(
    ' Valid from:',
    endEntityCertificate.tbsCertificate.validity.notBefore.toISOString(),
    )
    console.log(
    ' Valid until:',
    endEntityCertificate.tbsCertificate.validity.notAfter.toISOString(),
    )

    console.log('\n=== Step 5: Verify Certificate Chain ===')
    // Verify the signature on the end-entity certificate using the CA's public key
    const isValid = await endEntityCertificate.isIssuedBy(caCertificate)
    console.log('✓ Certificate chain verification:', isValid ? 'VALID' : 'INVALID')

    console.log('\n=== Certificates in PEM Format ===')
    console.log('\n--- CA Certificate ---')
    console.log(caCertificate.toPem())

    console.log('\n--- End-Entity Certificate ---')
    console.log(endEntityCertificate.toPem())

    console.log('\n--- End-Entity Private Key ---')
    console.log(endEntityKeyPair.privateKey.toPem())
    import { KeyGen } from 'pki-lite/core/KeyGen.js'
    import { Certificate } from 'pki-lite/x509/Certificate.js'
    import { CertificateValidator } from 'pki-lite/core/CertificateValidator.js'

    console.log('=== Certificate Chain Validation Example ===\n')

    // Generate keys and create a certificate chain for demonstration
    console.log('Setting up certificate chain...')

    // Generate keys for each level
    const rootKeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    const intermediateKeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    const endEntityKeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })

    // Create root CA certificate
    const rootCert = await Certificate.builder()
    .setSubject('CN=Root CA, O=Example Root CA, C=US')
    .setPublicKey(rootKeyPair.publicKey)
    .setPrivateKey(rootKeyPair.privateKey)
    .setValidityDays(3650) // 10 years
    .generateSerialNumber()
    .addBasicConstraints(true, 2) // CA with path length 2
    .addKeyUsage({ keyCertSign: true, cRLSign: true })
    .selfSign()

    // Create intermediate CA certificate signed by root
    const intermediateCert = await Certificate.builder()
    .setSubject('CN=Intermediate CA, O=Example Intermediate CA, C=US')
    .setIssuer(rootCert.tbsCertificate.subject)
    .setPublicKey(intermediateKeyPair.publicKey)
    .setPrivateKey(rootKeyPair.privateKey) // Signed by root
    .setValidityDays(1825) // 5 years
    .generateSerialNumber()
    .addBasicConstraints(true, 0) // CA with path length 0
    .addKeyUsage({ keyCertSign: true, cRLSign: true })
    .build()

    // Create end-entity certificate signed by intermediate
    const endEntityCert = await Certificate.builder()
    .setSubject('CN=www.example.com, O=Example Corp, C=US')
    .setIssuer(intermediateCert.tbsCertificate.subject)
    .setPublicKey(endEntityKeyPair.publicKey)
    .setPrivateKey(intermediateKeyPair.privateKey) // Signed by intermediate
    .setValidityDays(365) // 1 year
    .generateSerialNumber()
    .addBasicConstraints(false) // Not a CA
    .addKeyUsage({ digitalSignature: true, keyEncipherment: true })
    .addExtendedKeyUsage({ serverAuth: true })
    .addSubjectAltName('www.example.com', 'example.com')
    .build()

    console.log('✓ Certificate chain created\n')

    console.log('Loaded certificates:')
    console.log(' Root CA:', rootCert.tbsCertificate.subject.toString())
    console.log(
    ' Intermediate CA:',
    intermediateCert.tbsCertificate.subject.toString(),
    )
    console.log(' End Entity:', endEntityCert.tbsCertificate.subject.toString())

    console.log('\n=== Validation 1: Basic Certificate Validation ===')
    const validator = new CertificateValidator()

    // Validate just the end-entity certificate (without chain validation)
    const basicValidation = await validator.validate(endEntityCert, {
    checkSignature: false, // Don't check signature without issuer
    })

    console.log('Validation Status:', basicValidation.status)
    console.log('Is Valid:', basicValidation.isValid)
    console.log('Messages:', basicValidation.messages.join(', '))
    console.log('Validated At:', basicValidation.validatedAt.toISOString())

    console.log('\n=== Validation 2: Certificate Chain Validation ===')

    // Validate the full certificate chain
    const chainValidation = await validator.validate(endEntityCert, {
    validateChain: true,
    checkSignature: true,
    enforceCAConstraints: true,
    trustAnchors: [
    {
    certificate: rootCert,
    },
    ],
    otherCertificates: [intermediateCert], // Intermediate certificates for chain building
    })

    console.log('Chain Validation Status:', chainValidation.status)
    console.log('Is Valid:', chainValidation.isValid)
    console.log('Messages:', chainValidation.messages.join(', '))

    if (chainValidation.chain) {
    console.log('\nCertificate Chain:')
    console.log(' Is Complete:', chainValidation.chain.isComplete)
    console.log(' Chain Length:', chainValidation.chain.certificates.length)
    chainValidation.chain.certificates.forEach((cert, index) => {
    console.log(` [${index}] ${cert.tbsCertificate.subject.toString()}`)
    })
    }

    console.log('\nDiagnostics:')
    console.log(
    ' Steps Performed:',
    chainValidation.diagnostics.stepsPerformed.length,
    )
    chainValidation.diagnostics.stepsPerformed.forEach((step) => {
    console.log(` - ${step}`)
    })

    if (chainValidation.diagnostics.warnings.length > 0) {
    console.log(' Warnings:', chainValidation.diagnostics.warnings.length)
    chainValidation.diagnostics.warnings.forEach((warning) => {
    console.log(` ! ${warning}`)
    })
    }

    console.log('\n=== Validation 3: With Custom Validation Time ===')

    // Validate with a specific date (useful for checking historical validity)
    const historicalDate = new Date('2023-06-01T00:00:00Z')
    const historicalValidation = await validator.validate(endEntityCert, {
    validationTime: historicalDate,
    timeTolerance: 300000, // 5 minutes tolerance in milliseconds
    })

    console.log('Historical Validation Status:', historicalValidation.status)
    console.log('Is Valid:', historicalValidation.isValid)
    console.log('Validation Time:', historicalDate.toISOString())

    console.log('\n=== Validation 4: With Revocation Checking (CRL) ===')

    // If you have CRLs available
    const crl = await endEntityCert.requestCrl()
    if (crl) {
    const crlValidation = await validator.validate(
    endEntityCert,
    {
    checkCRL: true,
    },
    {
    crls: [crl],
    issuerCertificate: intermediateCert,
    },
    )

    console.log('CRL Validation Status:', crlValidation.status)
    console.log('Is Valid:', crlValidation.isValid)
    console.log('Revocation Status:')
    console.log(' Is Revoked:', crlValidation.revocationStatus.isRevoked)
    console.log(' Source:', crlValidation.revocationStatus.source)
    if (crlValidation.revocationStatus.reason !== undefined) {
    console.log(' Reason:', crlValidation.revocationStatus.reason)
    }
    } else {
    console.log('No CRL available for this certificate')
    }

    console.log('\n=== Validation 5: With Name Constraints ===')

    // Validate with name constraints (if the CA has name constraints)
    const nameConstraintsValidation = await validator.validate(endEntityCert, {
    validateChain: true,
    validateNameConstraints: true,
    trustAnchors: [
    {
    certificate: rootCert,
    // nameConstraints: customNameConstraints, // Add custom constraints if needed
    },
    ],
    otherCertificates: [intermediateCert],
    })

    console.log(
    'Name Constraints Validation Status:',
    nameConstraintsValidation.status,
    )
    console.log('Is Valid:', nameConstraintsValidation.isValid)

    console.log('\n=== Validation 6: Policy Validation ===')

    // Validate with required policies
    const policyValidation = await validator.validate(endEntityCert, {
    validateChain: true,
    validatePolicies: true,
    requiredPolicies: ['1.3.6.1.4.1.99999.1.2.3'], // Example policy OID
    trustAnchors: [
    {
    certificate: rootCert,
    },
    ],
    otherCertificates: [intermediateCert],
    })

    console.log('Policy Validation Status:', policyValidation.status)
    console.log('Is Valid:', policyValidation.isValid)
    if (policyValidation.policyResult) {
    console.log('Policy Result:')
    console.log(' Is Valid:', policyValidation.policyResult.isValid)
    console.log(
    ' Valid Policies:',
    policyValidation.policyResult.validPolicies,
    )
    console.log(' Violations:', policyValidation.policyResult.violations)
    }

    console.log('\n=== Certificate Information ===')

    // Extract useful information from a certificate
    console.log('\nEnd Entity Certificate Details:')
    console.log(' Version:', endEntityCert.tbsCertificate.version + 1) // Version is 0-indexed
    console.log(
    ' Serial Number:',
    endEntityCert.tbsCertificate.serialNumber.toString(),
    )
    console.log(' Subject:', endEntityCert.tbsCertificate.subject.toString())
    console.log(' Issuer:', endEntityCert.tbsCertificate.issuer.toString())
    console.log(
    ' Not Before:',
    endEntityCert.tbsCertificate.validity.notBefore.toISOString(),
    )
    console.log(
    ' Not After:',
    endEntityCert.tbsCertificate.validity.notAfter.toISOString(),
    )
    console.log(
    ' Signature Algorithm:',
    endEntityCert.signatureAlgorithm.algorithm.toString(),
    )

    if (endEntityCert.tbsCertificate.extensions) {
    console.log(' Extensions:', endEntityCert.tbsCertificate.extensions.length)
    endEntityCert.tbsCertificate.extensions.forEach((ext) => {
    console.log(` - ${ext.extnID.value} (Critical: ${ext.critical})`)
    })
    }
    import { KeyGen } from 'pki-lite/core/KeyGen.js'
    import { Certificate } from 'pki-lite/x509/Certificate.js'
    import { GeneralName } from 'pki-lite/x509/GeneralName.js'

    console.log('=== Certificate Builder Examples ===\n')

    // Generate keys for the examples
    console.log('Generating key pairs...')
    const keyPair1 = await KeyGen.generateRsaPair({ keySize: 2048 })
    const keyPair2 = await KeyGen.generateEcPair({ namedCurve: 'P-256' })
    console.log('✓ Key pairs generated\n')

    // Example 1: Basic self-signed certificate with minimal configuration
    console.log('=== Example 1: Basic Self-Signed Certificate ===')
    const basicCert = await Certificate.builder()
    .setSubject('CN=Basic Certificate')
    .setPublicKey(keyPair1.publicKey)
    .setPrivateKey(keyPair1.privateKey)
    .setValidityDays(365)
    .generateSerialNumber()
    .selfSign()

    console.log('✓ Basic certificate created')
    console.log(' Subject:', basicCert.tbsCertificate.subject.toString())
    console.log(' Serial:', basicCert.tbsCertificate.serialNumber.toString())

    // Example 2: Certificate with specific validity period
    console.log('\n=== Example 2: Certificate with Specific Validity Period ===')
    const startDate = new Date('2024-01-01T00:00:00Z')
    const endDate = new Date('2025-01-01T00:00:00Z')

    const timedCert = await Certificate.builder()
    .setSubject('CN=Timed Certificate, O=Example Org')
    .setPublicKey(keyPair1.publicKey)
    .setPrivateKey(keyPair1.privateKey)
    .setValidityPeriod(startDate, endDate)
    .generateSerialNumber()
    .selfSign()

    console.log('✓ Timed certificate created')
    console.log(
    ' Valid from:',
    timedCert.tbsCertificate.validity.notBefore.toISOString(),
    )
    console.log(
    ' Valid until:',
    timedCert.tbsCertificate.validity.notAfter.toISOString(),
    )

    // Example 3: Server certificate with extensions using builder helpers
    console.log('\n=== Example 3: Server Certificate with Extensions ===')
    const serverCert = await Certificate.builder()
    .setSubject('CN=api.example.com, O=Example Organization, C=US')
    .setPublicKey(keyPair1.publicKey)
    .setPrivateKey(keyPair1.privateKey)
    .setValidityDays(365)
    .generateSerialNumber()
    .addKeyUsage({
    digitalSignature: true,
    keyEncipherment: true,
    })
    .addExtendedKeyUsage({
    serverAuth: true,
    clientAuth: true,
    })
    .addSubjectAltName(
    'api.example.com',
    '*.api.example.com',
    new GeneralName.rfc822Name({ value: 'admin@example.com' }),
    )
    .addBasicConstraints(false) // Not a CA
    .selfSign()

    console.log('✓ Server certificate created')
    console.log(' Extensions:', serverCert.tbsCertificate.extensions?.length ?? 0)

    // Example 4: EC certificate with specific algorithm
    console.log('\n=== Example 4: EC Certificate with Custom Algorithm ===')
    const ecCert = await Certificate.builder()
    .setSubject('CN=EC Certificate')
    .setPublicKey(keyPair2.publicKey)
    .setPrivateKey(keyPair2.privateKey)
    .setValidityDays(365)
    .generateSerialNumber()
    .setAlgorithm({
    type: 'ECDSA',
    params: { namedCurve: 'P-256', hash: 'SHA-256' },
    })
    .selfSign()

    console.log('✓ EC certificate created')
    console.log(' Algorithm:', ecCert.signatureAlgorithm.algorithm.toString())

    // Example 5: CA certificate with path length constraint
    console.log('\n=== Example 5: CA Certificate with Path Length Constraint ===')
    const caKeyPair = await KeyGen.generateRsaPair({ keySize: 4096 })

    const caCert = await Certificate.builder()
    .setSubject('CN=Example Root CA, O=Example Org, C=US')
    .setPublicKey(caKeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey)
    .setValidityDays(3650) // 10 years
    .generateSerialNumber()
    .addBasicConstraints(true, 1) // CA with path length 1
    .addKeyUsage({
    keyCertSign: true,
    cRLSign: true,
    })
    .setVersion(2) // X.509 v3
    .selfSign()

    console.log('✓ CA certificate created')
    console.log(' Subject:', caCert.tbsCertificate.subject.toString())
    console.log(' Is CA: true')
    console.log(' Path Length Constraint: 1')

    // Example 6: Issuing a certificate from the CA
    console.log('\n=== Example 6: Certificate Issued by CA ===')
    const userKeyPair = await KeyGen.generateRsaPair()

    const issuedCert = await Certificate.builder()
    .setSubject('CN=John Doe, O=Example Org, C=US')
    .setIssuer(caCert) // Set the CA as issuer
    .setPublicKey(userKeyPair.publicKey)
    .setIssuerPrivateKey(caKeyPair.privateKey) // Use CA's private key to sign
    .setValidityDays(365)
    .generateSerialNumber()
    .addBasicConstraints(false) // Not a CA
    .sign()

    console.log('✓ User certificate issued by CA')
    console.log(' Subject:', issuedCert.tbsCertificate.subject.toString())
    console.log(' Issuer:', issuedCert.tbsCertificate.issuer.toString())

    // Verify the issued certificate
    const isValid = await issuedCert.isIssuedBy(caCert)
    console.log(' Signature valid:', isValid)

    // Example 7: Custom serial number
    console.log('\n=== Example 7: Certificate with Custom Serial Number ===')
    const customSerial = new Uint8Array([
    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
    ])

    const customSerialCert = await Certificate.builder()
    .setSubject('CN=Custom Serial')
    .setPublicKey(keyPair1.publicKey)
    .setPrivateKey(keyPair1.privateKey)
    .setValidityDays(365)
    .setSerialNumber(customSerial)
    .selfSign()

    console.log('✓ Certificate with custom serial created')
    console.log(
    ' Serial:',
    customSerialCert.tbsCertificate.serialNumber.toString(),
    )

    console.log('\n=== All Examples Completed ===')
    console.log('\nCertificate Builder Features:')
    console.log(' • Fluent API for creating certificates')
    console.log(' • Helper methods for common extensions:')
    console.log(' - addKeyUsage() - Key usage flags')
    console.log(' - addExtendedKeyUsage() - Extended key usage purposes')
    console.log(' - addBasicConstraints() - CA status and path length')
    console.log(' - addSubjectAltName() - Alternative names')
    console.log(' • Support for both self-signed and CA-signed certificates')
    console.log('\nExport certificates using:')
    console.log(' • certificate.toPem() - Export as PEM')
    console.log(' • certificate.toDer() - Export as DER')
    console.log(' • certificate.toString() - View ASN.1 structure')
    import { PFX } from 'pki-lite/pkcs12/PFX.js'
    import { KeyGen } from 'pki-lite/core/KeyGen.js'
    import { Certificate } from 'pki-lite/x509/Certificate.js'

    console.log('=== PFX Builder Examples ===\n')

    // Generate a key pair for the examples
    console.log('Generating RSA key pair...')
    const keyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    console.log('✓ Key pair generated\n')

    // Create a self-signed certificate
    console.log('Creating self-signed certificate...')
    const certificate = await Certificate.builder()
    .setSubject('CN=Example User, O=Example Org, C=US')
    .setPublicKey(keyPair.publicKey)
    .setPrivateKey(keyPair.privateKey)
    .setValidityDays(365)
    .generateSerialNumber()
    .addKeyUsage({
    digitalSignature: true,
    keyEncipherment: true,
    })
    .selfSign()
    console.log('✓ Certificate created\n')

    // Example 1: Basic PFX with certificate and private key
    console.log('=== Example 1: Basic PFX with Certificate and Private Key ===')
    const basicPfx = await PFX.builder()
    .addCertificate(certificate)
    .addPrivateKey(keyPair.privateKey)
    .setPassword('mySecurePassword123')
    .build()

    console.log('✓ PFX created')
    console.log(' Has MAC data:', !!basicPfx.macData)
    console.log(' PFX size:', basicPfx.toDer().length, 'bytes\n')

    // Example 2: PFX with friendly name
    console.log('=== Example 2: PFX with Friendly Name ===')
    const namedPfx = await PFX.builder()
    .addCertificate(certificate)
    .addPrivateKey(keyPair.privateKey)
    .setPassword('mySecurePassword123')
    .setFriendlyName('My Digital Identity')
    .setIterations(100000) // Higher iterations for better security
    .build()

    console.log('✓ PFX with friendly name created')
    console.log(' Iterations:', namedPfx.macData?.iterations)
    console.log(' PFX size:', namedPfx.toDer().length, 'bytes\n')

    // Example 3: PFX with certificate chain
    console.log('=== Example 3: PFX with Certificate Chain ===')

    // Generate a CA key pair
    const caKeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })

    // Create a CA certificate
    const caCert = await Certificate.builder()
    .setSubject('CN=Example CA, O=Example Org, C=US')
    .setPublicKey(caKeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey)
    .setValidityDays(3650)
    .generateSerialNumber()
    .addBasicConstraints(true, 2) // CA with pathLen=2
    .addKeyUsage({
    keyCertSign: true,
    cRLSign: true,
    })
    .selfSign()

    // Create an end-entity certificate signed by CA
    const endEntityKeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    const endEntityCert = await Certificate.builder()
    .setSubject('CN=End Entity, O=Example Org, C=US')
    .setIssuer(caCert.tbsCertificate.subject)
    .setPublicKey(endEntityKeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey) // Signed by CA
    .setValidityDays(365)
    .generateSerialNumber()
    .addKeyUsage({
    digitalSignature: true,
    keyEncipherment: true,
    })
    .addExtendedKeyUsage({
    clientAuth: true,
    emailProtection: true,
    })
    .build()

    // Build PFX with certificate chain
    const chainPfx = await PFX.builder()
    .addCertificate(endEntityCert) // End entity cert first
    .addCertificate(caCert) // CA cert for chain
    .addPrivateKey(endEntityKeyPair.privateKey)
    .setPassword('mySecurePassword123')
    .setFriendlyName('My Identity with Chain')
    .setIterations(100000)
    .build()

    console.log('✓ PFX with certificate chain created')
    console.log(' Certificates in chain: 2')
    console.log(' PFX size:', chainPfx.toDer().length, 'bytes\n')

    // Example 4: Export and verify PFX
    console.log('=== Example 4: Export and Verify PFX ===')

    // Export to PEM format
    const pfxPem = basicPfx.toPem()
    console.log('✓ PFX exported to PEM format')
    console.log(' PEM preview:', pfxPem.substring(0, 50) + '...\n')

    // Verify by parsing and extracting contents
    const password = 'mySecurePassword123'
    const parsedPfx = PFX.fromPem(pfxPem)

    const extractedCerts = await parsedPfx.getX509Certificates(password)
    const extractedKeys = await parsedPfx.getPrivateKeys(password)

    console.log('✓ PFX verified successfully')
    console.log(' Extracted certificates:', extractedCerts.length)
    console.log(' Extracted private keys:', extractedKeys.length)
    console.log(
    ' Certificate subject:',
    extractedCerts[0].tbsCertificate.subject.toString(),
    )

    // Example 5: Using PFX.create() shorthand
    console.log('\n=== Example 5: Using PFX.create() Shorthand ===')
    const shorthandPfx = await PFX.create({
    certificates: [certificate],
    privateKeys: [keyPair.privateKey],
    password: 'mySecurePassword123',
    friendlyName: 'Quick Identity',
    })

    console.log('✓ PFX created using shorthand method')
    console.log(' PFX size:', shorthandPfx.toDer().length, 'bytes')
    import { EncryptedData } from 'pki-lite/pkcs7/EncryptedData.js'
    import { OIDs } from 'pki-lite/core/OIDs.js'
    import { getCryptoProvider } from 'pki-lite/core/crypto/provider.js'

    console.log('=== EncryptedData Builder Examples ===\n')

    const secretMessage = new TextEncoder().encode(
    'This is a secret message that needs to be encrypted!',
    )
    const password = 'mySecurePassword123'

    // Example 1: Basic encryption with default settings (PBES2)
    console.log('=== Example 1: Basic Encryption with Default Settings ===')
    const basicEncrypted = await EncryptedData.builder()
    .setContentType('DATA')
    .setData(secretMessage)
    .setPassword(password)
    .build()

    console.log('✓ Data encrypted with default PBES2 algorithm')
    console.log(' Version:', basicEncrypted.version)
    console.log(
    ' Content type:',
    basicEncrypted.encryptedContentInfo.contentType.value,
    )
    console.log(
    ' Encrypted size:',
    basicEncrypted.encryptedContentInfo.encryptedContent?.bytes.length,
    'bytes',
    )
    console.log(
    ' Algorithm:',
    basicEncrypted.encryptedContentInfo.contentEncryptionAlgorithm.friendlyName,
    )

    // Decrypt to verify
    const provider = getCryptoProvider()
    const algorithm1 = provider.toSymmetricEncryptionAlgorithmParams(
    basicEncrypted.encryptedContentInfo.contentEncryptionAlgorithm,
    )
    const decrypted1 = await provider.decryptSymmetric(
    basicEncrypted.encryptedContentInfo.encryptedContent!.bytes,
    password as any, // Type definitions need updating to accept string
    algorithm1,
    )
    console.log('✓ Decrypted successfully:', new TextDecoder().decode(decrypted1))
    console.log()

    // Example 2: Encryption with custom PBKDF2 iterations
    console.log('=== Example 2: Custom Iterations for PBKDF2 ===')
    const customIterations = await EncryptedData.builder()
    .setContentType('DATA')
    .setData(secretMessage)
    .setPassword(password)
    .setAlgorithm({
    type: 'PBES2',
    params: {
    derivationAlgorithm: {
    type: 'PBKDF2',
    params: {
    salt: crypto.getRandomValues(new Uint8Array(16)),
    iterationCount: 100000, // Higher security
    hash: 'SHA-256',
    },
    },
    encryptionAlgorithm: {
    type: 'AES_256_CBC',
    params: {
    nonce: crypto.getRandomValues(new Uint8Array(16)),
    },
    },
    },
    })
    .build()

    console.log('✓ Data encrypted with 100,000 PBKDF2 iterations')
    console.log(
    ' Algorithm:',
    customIterations.encryptedContentInfo.contentEncryptionAlgorithm
    .friendlyName,
    )
    console.log()

    // Example 3: Encryption with SHA-512 hash
    console.log('=== Example 3: Using SHA-512 for Key Derivation ===')
    const sha512Encrypted = await EncryptedData.builder()
    .setContentType('DATA')
    .setData(secretMessage)
    .setPassword(password)
    .setAlgorithm({
    type: 'PBES2',
    params: {
    derivationAlgorithm: {
    type: 'PBKDF2',
    params: {
    salt: crypto.getRandomValues(new Uint8Array(16)),
    iterationCount: 50000,
    hash: 'SHA-512', // More secure hash
    },
    },
    encryptionAlgorithm: {
    type: 'AES_256_CBC',
    params: {
    nonce: crypto.getRandomValues(new Uint8Array(16)),
    },
    },
    },
    })
    .build()

    console.log('✓ Data encrypted using SHA-512 for key derivation')
    console.log(
    ' Algorithm:',
    sha512Encrypted.encryptedContentInfo.contentEncryptionAlgorithm
    .friendlyName,
    )
    console.log()

    // Example 4: Encryption with AES-128 (smaller key size)
    console.log('=== Example 4: Using AES-128-CBC ===')
    const aes128Encrypted = await EncryptedData.builder()
    .setContentType('DATA')
    .setData(secretMessage)
    .setPassword(password)
    .setAlgorithm({
    type: 'PBES2',
    params: {
    derivationAlgorithm: {
    type: 'PBKDF2',
    params: {
    salt: crypto.getRandomValues(new Uint8Array(16)),
    iterationCount: 10000,
    hash: 'SHA-256',
    },
    },
    encryptionAlgorithm: {
    type: 'AES_128_CBC',
    params: {
    nonce: crypto.getRandomValues(new Uint8Array(16)),
    },
    },
    },
    })
    .build()

    console.log('✓ Data encrypted with AES-128-CBC')
    console.log()

    // Example 5: Using EncryptedData.create() shorthand
    console.log('=== Example 5: Using EncryptedData.create() Shorthand ===')
    const shorthand = await EncryptedData.create({
    contentType: 'DATA',
    data: secretMessage,
    password,
    iterations: 50000,
    })

    console.log('✓ Data encrypted using shorthand method')
    console.log(' Encrypted size:', shorthand.toDer().length, 'bytes')
    console.log()

    // Example 6: Export to DER and convert to CMS
    console.log('=== Example 6: Export and Convert to CMS ===')
    const der = basicEncrypted.toDer()
    console.log('✓ Encrypted data exported to DER')
    console.log(' DER size:', der.length, 'bytes')

    // Convert to CMS ContentInfo
    const cms = basicEncrypted.asCms()
    console.log('✓ Converted to CMS ContentInfo')
    console.log(' Content type:', cms.contentType.value)
    console.log(' CMS size:', cms.toDer().length, 'bytes')
    import { CertificateList } from 'pki-lite/x509/CertificateList.js'
    import { KeyGen } from 'pki-lite/core/KeyGen.js'
    import { Certificate } from 'pki-lite/x509/Certificate.js'
    import { Extension } from 'pki-lite/x509/Extension.js'
    import { OIDs } from 'pki-lite/core/OIDs.js'

    console.log('=== CRL Builder Examples ===\n')

    // First, create a CA certificate and key pair
    console.log('Setting up CA...')
    const caKeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    const caCert = await Certificate.builder()
    .setSubject('CN=Example CA, O=Example Org, C=US')
    .setPublicKey(caKeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey)
    .setValidityDays(3650)
    .generateSerialNumber()
    .addBasicConstraints(true, 2)
    .addKeyUsage({
    keyCertSign: true,
    cRLSign: true,
    })
    .selfSign()
    console.log('✓ CA certificate created\n')

    // Create some end-entity certificates to revoke
    console.log('Creating certificates to revoke...')
    const cert1KeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    const cert1 = await Certificate.builder()
    .setSubject('CN=User 1, O=Example Org, C=US')
    .setIssuer(caCert.tbsCertificate.subject)
    .setPublicKey(cert1KeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey)
    .setValidityDays(365)
    .setSerialNumber(1001)
    .addKeyUsage({
    digitalSignature: true,
    keyEncipherment: true,
    })
    .build()

    const cert2KeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    const cert2 = await Certificate.builder()
    .setSubject('CN=User 2, O=Example Org, C=US')
    .setIssuer(caCert.tbsCertificate.subject)
    .setPublicKey(cert2KeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey)
    .setValidityDays(365)
    .setSerialNumber(1002)
    .addKeyUsage({
    digitalSignature: true,
    keyEncipherment: true,
    })
    .build()

    console.log('✓ Test certificates created\n')

    // Example 1: Basic CRL with revoked certificates
    console.log('=== Example 1: Basic CRL with Revoked Certificates ===')
    const basicCrl = await CertificateList.builder()
    .setIssuerFromCertificate(caCert)
    .setPrivateKey(caKeyPair.privateKey)
    .setThisUpdate(new Date())
    .setNextUpdate(new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)) // 30 days
    .addRevokedCertificate({
    serialNumber: 1001,
    revocationDate: new Date(),
    })
    .addRevokedCertificate({
    serialNumber: 1002,
    revocationDate: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // 7 days ago
    })
    .build()

    console.log('✓ Basic CRL created')
    console.log(' Issuer:', basicCrl.tbsCertList.issuer.toString())
    console.log(' This Update:', basicCrl.tbsCertList.thisUpdate)
    console.log(' Next Update:', basicCrl.tbsCertList.nextUpdate)
    console.log(
    ' Revoked Certificates:',
    basicCrl.tbsCertList.revokedCertificates?.length || 0,
    )
    console.log(' CRL size:', basicCrl.toDer().length, 'bytes\n')

    // Example 2: Revoking certificates by reference
    console.log('=== Example 2: Revoking Certificates by Reference ===')
    const referenceCrl = await CertificateList.builder()
    .setIssuerFromCertificate(caCert)
    .setPrivateKey(caKeyPair.privateKey)
    .revokeCertificate(cert1) // Revokes using current time
    .revokeCertificate(cert2, new Date(Date.now() - 14 * 24 * 60 * 60 * 1000)) // 14 days ago
    .build()

    console.log('✓ CRL created by revoking certificate references')
    console.log(
    ' Revoked Certificates:',
    referenceCrl.tbsCertList.revokedCertificates?.length || 0,
    )
    console.log()

    // Example 3: CRL with CRL Number extension
    console.log('=== Example 3: CRL with CRL Number Extension ===')
    const crlNumberExtension = new Extension({
    extnID: OIDs.EXTENSION.CRL_NUMBER,
    critical: false,
    extnValue: new Uint8Array([0x02, 0x01, 0x01]), // Integer 1 (ASN.1 DER encoded)
    })

    const numberedCrl = await CertificateList.builder()
    .setIssuerFromCertificate(caCert)
    .setPrivateKey(caKeyPair.privateKey)
    .addExtension(crlNumberExtension)
    .revokeCertificate(cert1)
    .build()

    console.log('✓ CRL with CRL Number extension created')
    console.log(' Extensions:', numberedCrl.tbsCertList.extensions?.length || 0)
    console.log(
    ' CRL version:',
    numberedCrl.tbsCertList.version === 1 ? 'v2' : 'v1',
    )
    console.log()

    // Example 4: Empty CRL (no revoked certificates)
    console.log('=== Example 4: Empty CRL ===')
    const emptyCrl = await CertificateList.builder()
    .setIssuerFromCertificate(caCert)
    .setPrivateKey(caKeyPair.privateKey)
    .setThisUpdate(new Date())
    .setNextUpdate(new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)) // 7 days
    .build()

    console.log('✓ Empty CRL created (no revoked certificates)')
    console.log(
    ' Revoked Certificates:',
    emptyCrl.tbsCertList.revokedCertificates?.length || 0,
    )
    console.log(' CRL version:', emptyCrl.tbsCertList.version === 1 ? 'v2' : 'v1')
    console.log()

    // Example 5: Export and parse CRL
    console.log('=== Example 5: Export and Parse CRL ===')

    // Export to PEM
    const crlPem = basicCrl.toPem()
    console.log('✓ CRL exported to PEM format')
    console.log(' PEM preview:', crlPem.substring(0, 50) + '...')

    // Parse back from PEM
    const parsedCrl = CertificateList.fromPem(crlPem)
    console.log('✓ CRL parsed from PEM')
    console.log(
    ' Issuer matches:',
    parsedCrl.tbsCertList.issuer.toString() ===
    basicCrl.tbsCertList.issuer.toString(),
    )
    console.log(
    ' Revoked count matches:',
    parsedCrl.tbsCertList.revokedCertificates?.length ===
    basicCrl.tbsCertList.revokedCertificates?.length,
    )
    console.log()

    // Example 6: Checking if a certificate is revoked
    console.log('=== Example 6: Checking Revocation Status ===')
    const serialToCheck = cert1.tbsCertificate.serialNumber.toString()
    const isRevoked = basicCrl.tbsCertList.revokedCertificates?.some(
    (revoked) => revoked.userCertificate.toString() === serialToCheck,
    )

    console.log(
    `Certificate with serial ${serialToCheck}:`,
    isRevoked ? 'REVOKED' : 'Valid',
    )

    if (isRevoked) {
    const revokedEntry = basicCrl.tbsCertList.revokedCertificates?.find(
    (revoked) => revoked.userCertificate.toString() === serialToCheck,
    )
    console.log(' Revocation Date:', revokedEntry?.revocationDate)
    }
    import { OCSPResponse } from 'pki-lite/ocsp/OCSPResponse.js'
    import { CertID } from 'pki-lite/ocsp/CertID.js'
    import { KeyGen } from 'pki-lite/core/KeyGen.js'
    import { Certificate } from 'pki-lite/x509/Certificate.js'
    import { OCSPResponseStatus } from 'pki-lite/ocsp/OCSPResponseStatus.js'

    console.log('=== OCSP Response Builder Examples ===\n')

    // Setup: Create CA and certificates
    console.log('Setting up CA and certificates...')
    const caKeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    const caCert = await Certificate.builder()
    .setSubject('CN=OCSP CA, O=Example Org, C=US')
    .setPublicKey(caKeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey)
    .setValidityDays(3650)
    .generateSerialNumber()
    .addBasicConstraints(true, 2)
    .addKeyUsage({
    keyCertSign: true,
    cRLSign: true,
    })
    .selfSign()

    // Create an OCSP responder key
    const responderKeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    const responderCert = await Certificate.builder()
    .setSubject('CN=OCSP Responder, O=Example Org, C=US')
    .setIssuer(caCert.tbsCertificate.subject)
    .setPublicKey(responderKeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey)
    .setValidityDays(365)
    .generateSerialNumber()
    .addKeyUsage({
    digitalSignature: true,
    })
    .addExtendedKeyUsage({
    ocspSigning: true,
    })
    .build()

    // Create some end-entity certificates
    const cert1KeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    const cert1 = await Certificate.builder()
    .setSubject('CN=User 1, O=Example Org, C=US')
    .setIssuer(caCert.tbsCertificate.subject)
    .setPublicKey(cert1KeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey)
    .setValidityDays(365)
    .setSerialNumber(2001)
    .build()

    const cert2KeyPair = await KeyGen.generateRsaPair({ keySize: 2048 })
    const cert2 = await Certificate.builder()
    .setSubject('CN=User 2, O=Example Org, C=US')
    .setIssuer(caCert.tbsCertificate.subject)
    .setPublicKey(cert2KeyPair.publicKey)
    .setPrivateKey(caKeyPair.privateKey)
    .setValidityDays(365)
    .setSerialNumber(2002)
    .build()

    console.log('✓ Setup complete\n')

    // Example 1: Basic OCSP response with good status (using Certificate directly)
    console.log('=== Example 1: Basic OCSP Response (Good Status) ===')

    const goodResponse = await OCSPResponse.builder()
    .setResponderFromCertificate(responderCert)
    .setPrivateKey(responderKeyPair.privateKey)
    .addResponse(caCert, cert1, 'good') // Pass issuer and certificate!
    .build()

    console.log('✓ OCSP response created with good status')
    console.log(' Response Status:', goodResponse.responseStatus.value)
    const basicResp1 = goodResponse.getBasicOCSPResponse()
    console.log(' Responses:', basicResp1.tbsResponseData.responses.length)
    console.log(
    ' Certificate Status:',
    basicResp1.tbsResponseData.responses[0].certStatus.status,
    )
    console.log(' Response size:', goodResponse.toDer().length, 'bytes\n')

    // Example 2: OCSP response with revoked status
    console.log('=== Example 2: OCSP Response with Revoked Status ===')
    const revocationDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) // 7 days ago

    const revokedResponse = await OCSPResponse.builder()
    .setResponderFromCertificate(responderCert)
    .setPrivateKey(responderKeyPair.privateKey)
    .addResponse(caCert, cert2, 'revoked', {
    revocationTime: revocationDate,
    revocationReason: 0, // unspecified reason
    })
    .build()

    console.log('✓ OCSP response created with revoked status')
    const basicResp2 = revokedResponse.getBasicOCSPResponse()
    console.log(
    ' Certificate Status:',
    basicResp2.tbsResponseData.responses[0].certStatus.status,
    )
    console.log(
    ' Revocation Time:',
    basicResp2.tbsResponseData.responses[0].certStatus.revocationTime,
    )
    console.log()

    // Example 3: Multiple certificate responses in one OCSP response
    console.log('=== Example 3: Multiple Certificate Responses ===')
    const multiResponse = await OCSPResponse.builder()
    .setResponderFromCertificate(responderCert)
    .setPrivateKey(responderKeyPair.privateKey)
    .addResponse(caCert, cert1, 'good') // Add multiple responses!
    .addResponse(caCert, cert2, 'revoked', {
    revocationTime: revocationDate,
    revocationReason: 0,
    })
    .build()

    console.log('✓ OCSP response with multiple certificates created')
    const basicResp3 = multiResponse.getBasicOCSPResponse()
    console.log(' Total responses:', basicResp3.tbsResponseData.responses.length)
    console.log(
    ' Response 1 status:',
    basicResp3.tbsResponseData.responses[0].certStatus.status,
    )
    console.log(
    ' Response 2 status:',
    basicResp3.tbsResponseData.responses[1].certStatus.status,
    )
    console.log()

    // Example 4: OCSP response with custom validity period
    console.log('=== Example 4: Custom Validity Period ===')
    const now = new Date()
    const tomorrow = new Date(now.getTime() + 24 * 60 * 60 * 1000)
    const nextWeek = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000)

    const customValidityResponse = await OCSPResponse.builder()
    .setResponderFromCertificate(responderCert)
    .setPrivateKey(responderKeyPair.privateKey)
    .setProducedAt(now)
    .addResponse(caCert, cert1, 'good', {
    thisUpdate: tomorrow,
    nextUpdate: nextWeek,
    })
    .build()

    console.log('✓ OCSP response with custom validity created')
    const basicResp4 = customValidityResponse.getBasicOCSPResponse()
    console.log(' Produced At:', basicResp4.tbsResponseData.producedAt)
    console.log(
    ' This Update:',
    basicResp4.tbsResponseData.responses[0].thisUpdate.time,
    )
    console.log(
    ' Next Update:',
    basicResp4.tbsResponseData.responses[0].nextUpdate?.time,
    )
    console.log()

    // Example 5: OCSP response with responder certificate included
    console.log('=== Example 5: Including Responder Certificate ===')
    const withCertResponse = await OCSPResponse.builder()
    .setResponderFromCertificate(responderCert)
    .setPrivateKey(responderKeyPair.privateKey)
    .addResponse(caCert, cert1, 'good')
    .addCertificate(responderCert) // Include responder cert for validation
    .build()

    console.log('✓ OCSP response with responder certificate created')
    const basicResp5 = withCertResponse.getBasicOCSPResponse()
    console.log(' Included certificates:', basicResp5.certs?.length || 0)
    if (basicResp5.certs && basicResp5.certs.length > 0) {
    console.log(
    ' Responder cert subject:',
    basicResp5.certs[0].tbsCertificate.subject.toString(),
    )
    }
    console.log()

    // Example 6: Error response (no signature required)
    console.log('=== Example 6: Error Response ===')
    const errorResponse = await OCSPResponse.builder()
    .setResponseStatus(OCSPResponseStatus.malformedRequest)
    .build()

    console.log('✓ Error response created')
    console.log(' Response Status:', errorResponse.responseStatus.value)
    console.log(' Has response bytes:', !!errorResponse.responseBytes)
    console.log()

    // Example 7: Using OCSPResponse.forCertificate() shorthand
    console.log('=== Example 7: Using forCertificate() Shorthand ===')
    const shorthandResponse = await OCSPResponse.forCertificate({
    issuerCertificate: caCert,
    subjectCertificate: cert1,
    privateKey: responderKeyPair.privateKey,
    responderID: responderCert.tbsCertificate.subject,
    })

    console.log('✓ OCSP response created using shorthand method')
    console.log(' Response Status:', shorthandResponse.responseStatus.value)
    console.log(' Response size:', shorthandResponse.toDer().length, 'bytes')
    console.log()

    // Example 8: Export and parse OCSP response
    console.log('=== Example 8: Export and Parse OCSP Response ===')
    const der = goodResponse.toDer()
    console.log('✓ OCSP response exported to DER')
    console.log(' DER size:', der.length, 'bytes')

    const parsed = OCSPResponse.fromDer(der)
    console.log('✓ OCSP response parsed from DER')
    console.log(
    ' Status matches:',
    parsed.responseStatus.value === goodResponse.responseStatus.value,
    )