Files
dsh/upstream/container/platform/tools/sign.mjs
T

34 lines
1.6 KiB
JavaScript

#!/usr/bin/env node
import { createHash, createPrivateKey, createPublicKey, sign } from 'node:crypto'
import { readFile, writeFile } from 'node:fs/promises'
import { canonicalJson } from '../lib/canonical-json.mjs'
function usage() {
console.error('usage: sign.mjs canonicalize <input> <output> | key-id <public-key-pem> | sign <private-key-pem> <document> <signature-output>')
process.exitCode = 64
}
const [command, ...args] = process.argv.slice(2)
if (command === 'canonicalize' && args.length === 2) {
await writeFile(args[1], canonicalJson(JSON.parse(await readFile(args[0], 'utf8'))), { flag: 'wx' })
} else if (command === 'key-id' && args.length === 1) {
const key = createPublicKey(await readFile(args[0]))
if (key.asymmetricKeyType !== 'ed25519') throw new Error('public key must be Ed25519')
const der = key.export({ format: 'der', type: 'spki' })
process.stdout.write(`${createHash('sha256').update(der).digest('hex')}\n`)
} else if (command === 'sign' && args.length === 3) {
const privateKey = createPrivateKey(await readFile(args[0]))
if (privateKey.asymmetricKeyType !== 'ed25519') throw new Error('private key must be Ed25519')
const publicKey = createPublicKey(privateKey)
const der = publicKey.export({ format: 'der', type: 'spki' })
const document = await readFile(args[1])
const signature = {
schema: 1,
algorithm: 'Ed25519',
keyId: createHash('sha256').update(der).digest('hex'),
signature: sign(null, document, privateKey).toString('base64'),
}
await writeFile(args[2], canonicalJson(signature), { flag: 'wx', mode: 0o600 })
} else usage()