Files
qinglong/packages/ql3-worker-runtime/test/helpers/certificateAuthority.cjs
T

101 lines
2.8 KiB
JavaScript

'use strict';
require('reflect-metadata');
const { randomBytes, webcrypto } = require('node:crypto');
const {
BasicConstraintsExtension,
ExtendedKeyUsage,
ExtendedKeyUsageExtension,
KeyUsageFlags,
KeyUsagesExtension,
Pkcs10CertificateRequest,
SubjectKeyIdentifierExtension,
X509CertificateGenerator,
} = require('@peculiar/x509');
const algorithm = Object.freeze({
name: 'ECDSA',
namedCurve: 'P-256',
hash: 'SHA-256',
});
async function createCertificateAuthority(options = {}) {
const now = options.now ?? Date.now();
const keys = await webcrypto.subtle.generateKey(algorithm, true, [
'sign',
'verify',
]);
const name = 'CN=QingLong Worker Test CA';
const certificate = await X509CertificateGenerator.createSelfSigned(
{
serialNumber: randomBytes(16).toString('hex'),
name,
notBefore: new Date(now - 60_000),
notAfter: new Date(now + 365 * 24 * 60 * 60_000),
signingAlgorithm: algorithm,
keys,
extensions: [
new BasicConstraintsExtension(true, 1, true),
new KeyUsagesExtension(
KeyUsageFlags.keyCertSign | KeyUsageFlags.cRLSign,
true,
),
await SubjectKeyIdentifierExtension.create(
keys.publicKey,
false,
webcrypto,
),
],
},
webcrypto,
);
return Object.freeze({
certificatePem: certificate.toString('pem'),
async issue(certificateSigningRequestPem, issueOptions = {}) {
const request = new Pkcs10CertificateRequest(
certificateSigningRequestPem,
);
if (!(await request.verify(webcrypto))) {
throw new Error('test CSR signature is invalid');
}
const notBeforeMs = issueOptions.notBeforeMs ?? now - 60_000;
const notAfterMs = issueOptions.notAfterMs ?? now + 30 * 24 * 60 * 60_000;
const extensions = [
new BasicConstraintsExtension(false, undefined, true),
new KeyUsagesExtension(KeyUsageFlags.digitalSignature, true),
await SubjectKeyIdentifierExtension.create(
request.publicKey,
false,
webcrypto,
),
];
if (issueOptions.clientAuth !== false) {
extensions.splice(
1,
0,
new ExtendedKeyUsageExtension([ExtendedKeyUsage.clientAuth], true),
);
}
const leaf = await X509CertificateGenerator.create(
{
serialNumber: randomBytes(16).toString('hex'),
subject: request.subject,
issuer: name,
notBefore: new Date(notBeforeMs),
notAfter: new Date(notAfterMs),
signingAlgorithm: algorithm,
publicKey: request.publicKey,
signingKey: keys.privateKey,
extensions,
},
webcrypto,
);
return leaf.toString('pem');
},
});
}
module.exports = { createCertificateAuthority };