Files
safetynet/tests/broker-tls-certificates.test.mjs

41 lines
2.9 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
import {X509Certificate} from 'node:crypto';
import https from 'node:https';
const require=createRequire(import.meta.url);
const {createSessionCertificates}=require('../apps/network-broker/tls-certificates.cjs');
test('session leaf has exact SAN, bounded lifetime, valid signature and no CA authority',async()=>{
const issuer=await createSessionCertificates({current:()=>true,authorized:()=>true});
try{for(const authority of ['example.com:443','127.0.0.1:443','[::1]:443','[::ffff:c000:201]:443']){
const leaf=issuer.resolve({authority}),certificate=new X509Certificate(leaf.cert);
assert.equal(certificate.ca,false);assert.equal(certificate.verify(certificate.publicKey),true);
assert.equal(certificate.checkHost('attacker.test',{subject:'never'}),undefined);
assert.ok(Date.parse(certificate.validTo)<=Date.now()+3600000);
assert.equal(issuer.resolve({authority}),leaf);
const metadata=issuer.publicMetadata({authority});
assert.deepEqual(Object.keys(metadata).sort(),['authority','cert','expiresAt','fingerprint256']);
assert.equal(metadata.fingerprint256,certificate.fingerprint256);
}}finally{issuer.close();}
assert.throws(()=>issuer.resolve({authority:'example.com:443'}),/broker-certificate-unavailable/);
});
test('deny, revocation and cache exhaustion do not issue or reuse leaves',async()=>{
let active=true,allowed=true;
const issuer=await createSessionCertificates({maxAuthorities:1,current:()=>active,authorized:()=>allowed});
try{issuer.resolve({authority:'example.com:443'});
assert.throws(()=>issuer.resolve({authority:'other.test:443'}),/broker-certificate-unavailable/);
allowed=false;assert.throws(()=>issuer.resolve({authority:'example.com:443'}),/broker-certificate-unavailable/);
allowed=true;active=false;assert.throws(()=>issuer.resolve({authority:'example.com:443'}),/broker-certificate-unavailable/);
}finally{issuer.close();}
});
test('generated certificate works with verified physical HTTPS and rejects a different hostname',async()=>{
const issuer=await createSessionCertificates({current:()=>true,authorized:()=>true});
const leaf=issuer.resolve({authority:'localhost:443'});
const server=https.createServer({key:leaf.key,cert:leaf.cert},(_request,response)=>response.end('public'));
try{await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));
const request=servername=>new Promise((resolve,reject)=>{https.get({host:'127.0.0.1',port:server.address().port,servername,ca:leaf.cert,agent:false},response=>{let body='';response.on('data',part=>body+=part);response.on('end',()=>resolve(body));}).on('error',reject);});
assert.equal(await request('localhost'),'public');
await assert.rejects(request('attacker.test'),{code:'ERR_TLS_CERT_ALTNAME_INVALID'});
}finally{await new Promise(resolve=>server.close(resolve));issuer.close();}
});