import { describe, expect, it } from "vitest"; import { AuthorityKeyIdentifierExtension, BasicConstraintsExtension, KeyUsageFlags, KeyUsagesExtension, SubjectKeyIdentifierExtension, X509CertificateGenerator, } from "@peculiar/x509"; import { checkCertificateHostname, inspectCryptoInput, parsePemBlocks, } from "../../src/crypto/inspection"; describe("crypto input inspection", () => { it("parses bounded PEM blocks and detects encrypted key material", () => { const pem = "-----BEGIN ENCRYPTED PRIVATE KEY-----\nAQID\n-----END ENCRYPTED PRIVATE KEY-----"; expect(parsePemBlocks(pem)).toMatchObject([ { label: "ENCRYPTED PRIVATE KEY", encrypted: true }, ]); expect(parsePemBlocks(pem)[0]?.bytes).toEqual(Uint8Array.of(1, 2, 3)); }); it("computes the RFC 7638 thumbprint without serialising private values", async () => { const inspection = await inspectCryptoInput( JSON.stringify({ kty: "RSA", n: "AQAB", e: "AQAB", d: "do-not-display", kid: "test", }), ); expect(inspection.items[0]?.facts["RFC 7638 SHA-256 thumbprint"]).toMatch( /^[A-Za-z0-9_-]{43}$/u, ); expect(JSON.stringify(inspection)).not.toContain("do-not-display"); expect(inspection.items[0]?.findings[0]?.severity).toBe("warning"); }); it("does not use a legacy common-name hostname fallback", () => { expect( checkCertificateHostname( { id: "x", type: "X.509 certificate", title: "x", facts: {}, findings: [], dnsNames: [], }, "example.com", ), ).toEqual({ valid: false, message: "Select a certificate." }); }); it("rejects unrelated JSON", async () => { await expect(inspectCryptoInput('{"hello":"world"}')).rejects.toThrow( /JWK or a JWKS/u, ); await expect(inspectCryptoInput("null")).rejects.toThrow(/PEM or JWK/u); }); it("rejects wildcards and invalid labels as hostname inputs", () => { const item = { id: "x", type: "X.509 certificate", title: "x", facts: {}, findings: [], certificate: {} as never, dnsNames: ["*.example.com"], }; expect(checkCertificateHostname(item, "*.example.com").valid).toBe(false); expect(checkCertificateHostname(item, "bad_label.example.com").valid).toBe( false, ); }); it("builds an explicitly untrusted path with signature and CA checks", async () => { const algorithm = { name: "ECDSA", namedCurve: "P-256", hash: "SHA-256", } as const; const rootKeys = await crypto.subtle.generateKey( { name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"], ); const root = await X509CertificateGenerator.createSelfSigned( { serialNumber: "01", name: "CN=Local Test Root", notBefore: new Date("2029-01-01T00:00:00Z"), notAfter: new Date("2035-01-01T00:00:00Z"), signingAlgorithm: algorithm, keys: rootKeys, extensions: [ new BasicConstraintsExtension(true, 1, true), new KeyUsagesExtension( KeyUsageFlags.keyCertSign | KeyUsageFlags.cRLSign, true, ), await SubjectKeyIdentifierExtension.create(rootKeys.publicKey), ], }, crypto, ); const leafKeys = await crypto.subtle.generateKey( { name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"], ); const leaf = await X509CertificateGenerator.create( { serialNumber: "02", subject: "CN=Leaf", issuer: root.subject, notBefore: new Date("2029-01-01T00:00:00Z"), notAfter: new Date("2031-01-01T00:00:00Z"), signingAlgorithm: algorithm, publicKey: leafKeys.publicKey, signingKey: rootKeys.privateKey, extensions: [ new BasicConstraintsExtension(false, undefined, true), await AuthorityKeyIdentifierExtension.create(rootKeys.publicKey), ], }, crypto, ); const inspection = await inspectCryptoInput( `${leaf.toString("pem")}\n${root.toString("pem")}`, new Date("2030-01-01T00:00:00Z"), ); expect(inspection.paths).toHaveLength(1); expect(inspection.paths[0]).toMatchObject({ status: "self-signed-anchor-present", trusted: false, certificates: ["CN=Leaf", "CN=Local Test Root"], }); expect(inspection.paths[0]?.links[0]).toMatchObject({ signatureValid: true, issuerIsCa: true, keyCertSignAllowed: true, authorityKeyIdentifierMatched: true, }); }); });