mirror of
https://github.com/ancsemi/Haven.git
synced 2026-10-26 00:29:14 +00:00
48 lines
3.2 KiB
JavaScript
48 lines
3.2 KiB
JavaScript
'use strict';
|
|
const assert = require('node:assert/strict');
|
|
const test = require('node:test');
|
|
const fs = require('fs');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
const { execFileSync } = require('child_process');
|
|
const { inspectCertChain, certAdvice } = require('../src/certCheck');
|
|
const { generate } = require('../src/selfsignedCert');
|
|
const hasOpenssl = (() => { try { execFileSync('openssl', ['version'], { stdio: 'ignore' }); return true; } catch { return false; } })();
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'haven-chain-'));
|
|
const ssl = (...args) => execFileSync('openssl', args, { cwd: dir, stdio: 'pipe' });
|
|
const read = f => fs.readFileSync(path.join(dir, f), 'utf8');
|
|
function chain() {
|
|
ssl('req', '-x509', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:P-256', '-nodes', '-keyout', 'root.key', '-out', 'root.pem', '-days', '30', '-subj', '/CN=Test Root', '-addext', 'basicConstraints=critical,CA:TRUE');
|
|
ssl('req', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:P-256', '-nodes', '-keyout', 'int.key', '-out', 'int.csr', '-subj', '/CN=Test Intermediate');
|
|
fs.writeFileSync(path.join(dir, 'ca.ext'), 'basicConstraints=critical,CA:TRUE\n');
|
|
ssl('x509', '-req', '-in', 'int.csr', '-CA', 'root.pem', '-CAkey', 'root.key', '-CAcreateserial', '-out', 'int.pem', '-days', '30', '-extfile', 'ca.ext');
|
|
ssl('req', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:P-256', '-nodes', '-keyout', 'leaf.key', '-out', 'leaf.csr', '-subj', '/CN=haven.example');
|
|
ssl('x509', '-req', '-in', 'leaf.csr', '-CA', 'int.pem', '-CAkey', 'int.key', '-CAcreateserial', '-out', 'leaf.pem', '-days', '30');
|
|
return { root: read('root.pem'), int: read('int.pem'), leaf: read('leaf.pem') };
|
|
}
|
|
test.after(() => fs.rmSync(dir, { recursive: true, force: true }));
|
|
test('a leaf without its intermediates is reported as a missing chain, with fullchain.pem named', { skip: !hasOpenssl && 'openssl not installed' }, () => {
|
|
const { root, int, leaf } = chain();
|
|
assert.equal(inspectCertChain(leaf).issue, 'missing_chain');
|
|
assert.equal(inspectCertChain(leaf + int).issue, null);
|
|
assert.equal(inspectCertChain(int + leaf).issue, 'untrusted');
|
|
assert.equal(inspectCertChain(leaf + int + root).issue, 'untrusted');
|
|
fs.writeFileSync(path.join(dir, 'fullchain.pem'), leaf + int);
|
|
const advice = certAdvice(inspectCertChain(leaf), path.join(dir, 'cert.pem'));
|
|
assert.match(advice, /no intermediate certificates/);
|
|
assert.ok(advice.includes(`SSL_CERT_PATH=${path.join(dir, 'fullchain.pem')}`));
|
|
assert.equal(certAdvice(inspectCertChain(leaf + int), path.join(dir, 'fullchain.pem')), null);
|
|
});
|
|
test('Haven\'s own self-signed certificate is not a chain problem', () => {
|
|
const { cert } = generate({ names: ['localhost'] });
|
|
assert.equal(inspectCertChain(cert).issue, 'self_signed');
|
|
assert.equal(certAdvice(inspectCertChain(cert), '/x/cert.pem'), null);
|
|
});
|
|
test('an expired certificate and an empty file say so', () => {
|
|
const { cert } = generate({ names: ['localhost'], days: 1 });
|
|
const status = inspectCertChain(cert, Date.now() + 3 * 86400000);
|
|
assert.equal(status.issue, 'expired');
|
|
assert.match(certAdvice(status, '/x/cert.pem'), /expired on .*certbot renew/);
|
|
assert.equal(inspectCertChain('not a cert').issue, 'unreadable');
|
|
});
|