50 lines
1.7 KiB
JavaScript
50 lines
1.7 KiB
JavaScript
import {
|
|
createHash,
|
|
createPrivateKey,
|
|
createPublicKey,
|
|
sign,
|
|
timingSafeEqual,
|
|
verify,
|
|
} from 'node:crypto'
|
|
import { readFileSync } from 'node:fs'
|
|
|
|
const args = process.argv.slice(2)
|
|
const privateKey = createPrivateKey(readFileSync(option('--private-key')))
|
|
const publicKey = createPublicKey(readFileSync(option('--public-key')))
|
|
|
|
if (privateKey.asymmetricKeyType !== 'ed25519' || publicKey.asymmetricKeyType !== 'ed25519') {
|
|
fail('Both release-evidence keys must be Ed25519.')
|
|
}
|
|
|
|
const derivedPublic = createPublicKey(privateKey).export({ type: 'spki', format: 'der' })
|
|
const suppliedPublic = publicKey.export({ type: 'spki', format: 'der' })
|
|
if (derivedPublic.length !== suppliedPublic.length || !timingSafeEqual(derivedPublic, suppliedPublic)) {
|
|
fail('Release-evidence private and public keys do not match.')
|
|
}
|
|
|
|
const message = Buffer.from('d3ro-release-evidence-key-pair-check-v1')
|
|
const signature = sign(null, message, privateKey)
|
|
if (!verify(null, message, publicKey, signature)) fail('Release-evidence signature round trip failed.')
|
|
|
|
const keyId = createHash('sha256').update(suppliedPublic).digest('hex')
|
|
const expectedKeyId = option('--expected-key-id')
|
|
if (keyId !== expectedKeyId) fail(`Release-evidence key ID mismatch: ${keyId}`)
|
|
|
|
process.stdout.write(`${JSON.stringify({
|
|
ok: true,
|
|
algorithm: 'Ed25519',
|
|
keyId,
|
|
signatureRoundTrip: true,
|
|
}, null, 2)}\n`)
|
|
|
|
function option(name) {
|
|
const index = args.indexOf(name)
|
|
const value = index === -1 ? undefined : args[index + 1]
|
|
if (!value || value.startsWith('--')) fail(`${name} is required.`)
|
|
return value
|
|
}
|
|
|
|
function fail(message) {
|
|
process.stderr.write(`[release-evidence-key] ${message}\n`)
|
|
process.exit(1)
|
|
}
|