import { X509Certificate } from 'node:crypto'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { describe, expect, it } from 'vitest'; import { csrPublicKeyOf } from './cert-csr'; import { keyIdOf } from './cert-keys'; import { detectBlob } from './cert-model'; import type { CsrItem } from './cert-types'; const fx = (name: string) => readFileSync(join(__dirname, '__fixtures__', name)); function csrs(name: string): CsrItem[] { const r = detectBlob(fx(name), { file: 0, path: name, passwords: [] }); return r.items.filter((i): i is CsrItem => i.kind === 'csr'); } describe('Zertifikatsanfragen (CSR)', () => { it('RSA-CSR als PEM: Inhaber, SAN aus der extensionRequest, Schluessel', () => { const [csr] = csrs('rsa-leaf.csr'); expect(csr).toBeDefined(); expect(csr.kind).toBe('csr'); expect(csr.cn).toBe('www.example.test'); expect(csr.organization).toBe('Tessera Test'); expect(csr.san).toEqual(['www.example.test', 'example.test']); expect(csr.keyType).toBe('RSA'); expect(csr.keyBits).toBe(2048); expect(csr.curve).toBeNull(); expect(csr.id).toMatch(/^r-[0-9a-f]{16}$/); expect(csr.pem.startsWith('-----BEGIN CERTIFICATE REQUEST-----')).toBe(true); expect(csr.baseName).toBe('www.example.test'); expect(csr.sources).toEqual([{ file: 0, path: 'rsa-leaf.csr' }]); }); it('EC-CSR als PEM: P-256', () => { const [csr] = csrs('ec-leaf.csr'); expect(csr.cn).toBe('ec.example.test'); expect(csr.keyType).toBe('EC'); expect(csr.curve).toBe('P-256'); expect(csr.keyBits).toBe(256); expect(csr.san).toContain('ec.example.test'); }); it('PEM und DER derselben Anfrage teilen die Kennung', () => { expect(csrs('rsa-leaf.csr')[0].id).toBe(csrs('rsa-leaf.csr.der')[0].id); expect(csrs('ec-leaf.csr')[0].id).toBe(csrs('ec-leaf.csr.der')[0].id); expect(csrs('rsa-leaf.csr')[0].id).not.toBe(csrs('ec-leaf.csr')[0].id); }); it('der Schluessel der Anfrage ist der des Zertifikats (SPKI)', () => { for (const [csr, cert] of [ ['rsa-leaf.csr', 'rsa-leaf.pem'], ['ec-leaf.csr.der', 'ec-leaf.pem'], ]) { const [item] = csrs(csr); const { id, spki } = csrPublicKeyOf(item.pem); const x = new X509Certificate(fx(cert)); expect(id).toBe(keyIdOf(x.publicKey)); expect(spki.equals(x.publicKey.export({ type: 'spki', format: 'der' }))).toBe(true); } }); it('keyId und certIds setzt erst die Zuordnung', () => { const [csr] = csrs('rsa-leaf.csr'); expect(csr.keyId).toBeNull(); expect(csr.certIds).toEqual([]); }); it('ein Zertifikat oder Schluessel wird nie als CSR gelesen', () => { for (const name of ['rsa-leaf.cer', 'ec-leaf-key-sec1.der', 'rsa-chain.p7c']) { expect(csrs(name)).toEqual([]); } }); it('abgeschnittene und kaputte Anfragen ergeben nur „unbekannt“', () => { const half = fx('rsa-leaf.csr.der').subarray(0, 200); const r = detectBlob(half, { file: 4, path: 'halb.csr', passwords: [] }); expect(r.items).toEqual([]); expect(r.ignored).toEqual([{ file: 4, path: 'halb.csr', reason: 'unknown' }]); const brokenPem = Buffer.from( '-----BEGIN CERTIFICATE REQUEST-----\nQUJDREVGR0hJSktMTU5PUA==\n-----END CERTIFICATE REQUEST-----\n', ); expect(detectBlob(brokenPem, { file: 0, path: 'k.csr', passwords: [] }).items).toEqual([]); }); });