stateless-dane
Version:
A library/utility for Stateless DANE certificates
162 lines (138 loc) • 4.46 kB
JavaScript
#!/usr/bin/env node
'use strict';
const fs = require('node:fs');
const Config = require('bcfg');
const { NodeClient } = require('hs-client');
const rsa = require('bcrypto/lib/rsa');
const { StatelessDANECertificate } = require('../lib');
const pkg = require('../package.json');
const nodePorts = {
main: 12037,
testnet: 13037,
regtest: 14037,
simnet: 15037
};
const HELP = `
stateless-dane v${pkg.version}
Usage:
stateless-dane inspect-cert <filepath>
stateless-dane generate <name> [--sign <true|false>] [--public-key-file <filepath>]
stateless-dane get-ext-data <name> [--parsed <true|false>]
Options:
--sign <bool> whether to sign the certificate (default: true)
--parsed <bool> whether to return parsed extension data (default: true)
--public-key-file <filepath> create a certificate with this public key file, expects json (default: generated keypair)
(example of public key format can be found at examples/sample-public-key.json)
[all hsd client options like http-host, api-key, etc.]
[Global options]
--port custom port for name (default: 443)
--resolver-ip resolver IP to use for fetching dnssec chain
--resolver-port resolver port to use for fetching dnssec chain
Examples:
* Inspect an existing certificate:
$ stateless-dane inspect-cert /tmp/cert.pem
* Generate a new certificate for letsdane:
$ stateless-dane generate letsdane
* Only get raw extension data to be used by other cert issuers:
$ stateless-dane get-ext-data letsdane --parsed false
`;
// Main
(async () => {
// HSD Node Client
const config = new Config('hsd', {
suffix: 'network',
fallback: 'main',
alias: {
'n': 'network',
'u': 'url',
'uri': 'url',
'k': 'api-key',
's': 'ssl',
'h': 'http-host',
'p': 'http-port'
}
});
config.load({
argv: true,
env: true,
});
config.open('hsd.conf');
const network = config.str('network', 'main');
const nodeClient = new NodeClient({
url: config.str('url'),
apiKey: config.str('api-key'),
ssl: config.bool('ssl'),
host: config.str('http-host'),
port: config.uint('http-port')
|| nodePorts[network]
|| nodePorts.main,
timeout: config.uint('timeout'),
limit: config.uint('limit')
});
const command = config.str(0);
const sign = config.bool('sign', true);
const publicKeyFile = config.str('public-key-file');
var publicKeyJson
if (publicKeyFile) {
publicKeyJson = JSON.parse(fs.readFileSync(publicKeyFile, 'utf8'));
}
const parsed = config.bool('parsed', true);
const options = {
port: config.str('port') || undefined,
resolverIP: config.str('resolver-ip') || undefined,
resolverPort: config.str('resolver-port') || undefined,
}
switch (command) {
case 'inspect-cert':
{
const filepath = config.str(1);
if (!filepath) {
console.log(HELP);
return;
}
const cert = StatelessDANECertificate.fromPath(nodeClient, filepath, options);
console.log(JSON.stringify(cert.format(), null, 4));
}
break;
case 'generate':
{
const name = config.str([1, 'name']);
if (!name) {
console.log(HELP);
return;
}
const cert = new StatelessDANECertificate(nodeClient, name, options);
if (publicKeyJson) {
const parsed = {
n: Buffer.from(publicKeyJson.n, 'hex'),
e: Buffer.from(publicKeyJson.e, 'hex'),
};
cert.publicKey = rsa.publicKeyImport(parsed);
}
await cert.create();
if (sign) {
cert.sign();
}
console.log(cert.cert.toPEM());
}
break;
case 'get-ext-data':
{
const name = config.str([1, 'name']);
if (!name) {
console.log(HELP);
return;
}
const cert = new StatelessDANECertificate(nodeClient, name, options);
const extensions = await Promise.all([
cert._getUrkelProofExtension(),
cert._getDnssecChainExtension(),
]);
console.log(JSON.stringify(extensions.map(ext => ext.getJSON(parsed))));
}
break;
default:
console.log(HELP);
return;
}
})().catch(console.error);