163 lines
5.0 KiB
JavaScript
163 lines
5.0 KiB
JavaScript
'use strict'
|
|
|
|
const bareCrypto = require('bare-crypto')
|
|
const { Ber } = require('asn1')
|
|
const { Buffer: Asn1Buffer } = require('safer-buffer')
|
|
const { getCiphers, getHashes } = require('./lists.js')
|
|
const { wrapSign, wrapVerify } = require('./pem-ed25519.js')
|
|
|
|
const nextTick =
|
|
typeof queueMicrotask === 'function'
|
|
? (fn) => queueMicrotask(fn)
|
|
: (fn) => setTimeout(fn, 0)
|
|
|
|
/**
|
|
* Encode Ed25519 raw keys as SPKI / PKCS#8 DER (same layout as Node/OpenSSL RFC 8410),
|
|
* which bare-ssh2 `lib/keygen.js` parses via `convertKeys`.
|
|
*/
|
|
function ed25519RawToDer(pub32, privSeed32) {
|
|
const pub = Asn1Buffer.from(pub32)
|
|
const priv = Asn1Buffer.from(privSeed32)
|
|
|
|
const pubWriter = new Ber.Writer()
|
|
pubWriter.startSequence()
|
|
pubWriter.startSequence()
|
|
pubWriter.writeOID('1.3.101.112')
|
|
pubWriter.endSequence()
|
|
pubWriter.startSequence(Ber.BitString)
|
|
pubWriter.writeByte(0x00)
|
|
pubWriter._ensure(pub.length)
|
|
pubWriter._buf.set(pub, pubWriter._offset)
|
|
pubWriter._offset += pub.length
|
|
pubWriter.endSequence()
|
|
pubWriter.endSequence()
|
|
|
|
const privWriter = new Ber.Writer()
|
|
privWriter.startSequence()
|
|
privWriter.writeInt(0x00, Ber.Integer)
|
|
privWriter.startSequence()
|
|
privWriter.writeOID('1.3.101.112')
|
|
privWriter.endSequence()
|
|
privWriter.startSequence(Ber.OctetString)
|
|
privWriter.writeBuffer(priv, Ber.OctetString)
|
|
privWriter.endSequence()
|
|
privWriter.endSequence()
|
|
|
|
return { publicKey: pubWriter.buffer, privateKey: privWriter.buffer }
|
|
}
|
|
|
|
function generateKeyPairSyncBareEd25519(type, options) {
|
|
const pubEnc = (options && options.publicKeyEncoding) || {}
|
|
const privEnc = (options && options.privateKeyEncoding) || {}
|
|
if (
|
|
String(type).toLowerCase() !== 'ed25519' ||
|
|
pubEnc.type !== 'spki' ||
|
|
pubEnc.format !== 'der' ||
|
|
privEnc.type !== 'pkcs8' ||
|
|
privEnc.format !== 'der'
|
|
) {
|
|
throw new Error(
|
|
'Bare crypto shim: generateKeyPairSync only supports ed25519 with { spki, der } / { pkcs8, der } encodings'
|
|
)
|
|
}
|
|
const { publicKey, privateKey } = bareCrypto.generateKeyPair('ed25519')
|
|
const pubRaw = publicKey._key
|
|
const privRaw = privateKey._key
|
|
const pub32 = Asn1Buffer.from(pubRaw)
|
|
let priv32 = Asn1Buffer.from(privRaw)
|
|
if (priv32.length === 64) priv32 = Asn1Buffer.from(priv32.subarray(0, 32))
|
|
if (pub32.length !== 32 || priv32.length !== 32) {
|
|
throw new Error('Unexpected Ed25519 key material length from bare-crypto')
|
|
}
|
|
return ed25519RawToDer(pub32, priv32)
|
|
}
|
|
|
|
function generateKeyPairSync(type, options) {
|
|
if (typeof bareCrypto.generateKeyPairSync === 'function') {
|
|
return bareCrypto.generateKeyPairSync(type, options)
|
|
}
|
|
const t = String(type || '').toLowerCase()
|
|
if (t === 'x25519') {
|
|
const x = require('./x25519-compat.js')
|
|
if (options && Object.keys(options).length > 0) {
|
|
const pubEnc = options.publicKeyEncoding || {}
|
|
const privEnc = options.privateKeyEncoding || {}
|
|
if (
|
|
pubEnc.type !== 'spki' ||
|
|
pubEnc.format !== 'der' ||
|
|
privEnc.type !== 'pkcs8' ||
|
|
privEnc.format !== 'der'
|
|
) {
|
|
throw new Error(
|
|
'Bare crypto shim: x25519 generateKeyPairSync only supports default or spki/pkcs8 der'
|
|
)
|
|
}
|
|
}
|
|
return x.generateKeyPairSync()
|
|
}
|
|
if (t === 'ed25519') return generateKeyPairSyncBareEd25519(type, options)
|
|
throw new Error(`Bare crypto shim: generateKeyPairSync not supported for type ${type}`)
|
|
}
|
|
|
|
function generateKeyPair(type, options, callback) {
|
|
if (typeof options === 'function') {
|
|
callback = options
|
|
options = undefined
|
|
}
|
|
const native = bareCrypto.generateKeyPair
|
|
if (typeof callback === 'function') {
|
|
if (typeof native === 'function' && native.length >= 3) {
|
|
return native.call(bareCrypto, type, options, callback)
|
|
}
|
|
nextTick(() => {
|
|
try {
|
|
const pair = generateKeyPairSync(type, options)
|
|
callback(null, pair.publicKey, pair.privateKey)
|
|
} catch (err) {
|
|
callback(err)
|
|
}
|
|
})
|
|
return
|
|
}
|
|
if (typeof native === 'function') {
|
|
return native.call(bareCrypto, type, options)
|
|
}
|
|
}
|
|
|
|
function createPublicKey(descriptor) {
|
|
if (
|
|
descriptor &&
|
|
descriptor.type === 'spki' &&
|
|
descriptor.format === 'der' &&
|
|
descriptor.key
|
|
) {
|
|
return require('./x25519-compat.js').createPublicKeyFromSpkiDer(descriptor.key)
|
|
}
|
|
if (typeof bareCrypto.createPublicKey === 'function') {
|
|
return bareCrypto.createPublicKey(descriptor)
|
|
}
|
|
throw new Error('Bare crypto shim: createPublicKey only supports X25519 SPKI DER on Bare')
|
|
}
|
|
|
|
function diffieHellman(opts) {
|
|
return require('./x25519-compat.js').diffieHellman(opts)
|
|
}
|
|
|
|
function createECDH(curveName) {
|
|
throw new Error(
|
|
`Bare crypto shim: createECDH(${curveName}) is not implemented; bare-ssh2 should negotiate curve25519-sha256`
|
|
)
|
|
}
|
|
|
|
module.exports = Object.assign({}, bareCrypto, {
|
|
getCiphers,
|
|
getHashes,
|
|
generateKeyPairSync,
|
|
generateKeyPair,
|
|
createPublicKey,
|
|
diffieHellman,
|
|
createECDH,
|
|
sign: wrapSign(bareCrypto, bareCrypto.sign.bind(bareCrypto)),
|
|
verify: wrapVerify(bareCrypto, bareCrypto.verify.bind(bareCrypto))
|
|
})
|