fcac0a3bfd
- Private Schlüssel (PKCS#1, PKCS#8, SEC1; PEM und DER; unverschlüsselt, verschlüsselt, klassisch verschlüsselt) für RSA und EC über node:crypto - PKCS#12 lesen (OpenSSL 3, kompatibel, RC2; EC-Zertifikate und -Schlüssel), auch ohne Endung und im ZIP - Zertifikatsanfragen (CSR) als PEM und DER mit Inhaber, SAN und Schlüssel - Zuordnung von Schlüssel und Anfrage zum Zertifikat (checkPrivateKey, SPKI-Vergleich) - Feld passwords je Datei, gesperrte Dateien fragen nach dem Passwort; kein Passwort in Antwort oder Log - Oberfläche: Passwortfeld mit Anzeigen/Verbergen, Schlüssel- und Anfragekarten im Reiter Analysieren Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
85 lines
3.3 KiB
TypeScript
85 lines
3.3 KiB
TypeScript
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([]);
|
|
});
|
|
});
|