TritonDataCenter / node-sshpk

Parse, convert, fingerprint and use SSH keys in pure node.js
MIT License
189 stars 50 forks source link

Unable to deal with ed25519 pk #81

Open xxorax opened 2 years ago

xxorax commented 2 years ago

I'm desperatly trying to handle EdDSA / ed25519 private key in any library. Most of them accept only PKCS8 format, while sshpk handle only PKCS1

Even node crypto can't import it :

const crypto = require('crypto')
const sshpk = require('sshpk')

const privkey = sshpk.generatePrivateKey('ed25519')

privkey.toBuffer('pkcs8')
// Error: Ed25519 private keys in pkcs8 format are not supported

const privkeyObj = crypto.createPrivateKey({
  key: privkey.toBuffer('pem'),
  format: 'pem',
})
// Error: error:0909006C:PEM routines:get_name:no start line

const privkeyObj = crypto.createPrivateKey({
  key: privkey.toBuffer('pkcs1'),
  format: 'der',
  type: 'pkcs1'
})
// Error: error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag

Tried on node v12, v16, v17.

Thanks for help

xxorax commented 2 years ago

I was able to export generated ed25519 key to pkcs8 using the ssh2 lib :

const ssh2 = require('ssh2')
const sshpk = require('sshpk')

const pkcs8 = ssh2.utils.parseKey(
      sshpk.generatePrivateKey('ed25519').toString('ssh')
).getPrivatePEM()

Also working with ecdsa key. ecdsa need more gymnastic :

sshpk.parsePrivateKey(
  ssh2.utils.parseKey(sshpk.generatePrivateKey('ecdsa').toString('ssh')).getPrivatePEM(),
  'pem'
).toString('pkcs8')

Hard to fond... It would be more convenient to have such function here.

Thanks !

arekinath commented 2 years ago

This was missing because the support for Ed25519 in PEM in sshpk was written before RFC8410 had been finalised. There's a few little fixes that have to go into the way it's generating and parsing these before it can be enabled, but they're easy enough to do.

With ECDSA, you should just be able to do sshpk.generatePrivateKey('ecdsa').toString('pkcs8'); -- I'm not sure why you're converting it to ssh format and then back again?

xxorax commented 2 years ago

With ECDSA, you should just be able to do sshpk.generatePrivateKey('ecdsa').toString('pkcs8'); -- I'm not sure why you're converting it to ssh format and then back again?

True, and after re-rechecking, sometime there is differences :eyes:

The folliwng will print "test" for each pass, and will stop once pkcs8 are differents

const ssh2 = require('ssh2')
const sshpk = require('sshpk')

const test = function () {
  console.log('test')
  const privkey = sshpk.generatePrivateKey('ecdsa')

  const pkcs8 = sshpk.parsePrivateKey(
    ssh2.utils.parseKey(privkey.toString('ssh')).getPrivatePEM(),
    'pem'
  ).toString('pkcs8')

  if ( pkcs8 !== privkey.toString('pkcs8') ) {
    console.log(pkcs8)
    console.log(privkey.toString('pkcs8'))
    return false
  }
  return true
}

while(test());

Tested on node v12, v16, and v17, also tried on an other cpu. I make some stats, at the end I got ~50% of errors.

On my side I send the pkcs8 to jose.importPKCS8 , and my tests pass 100% of time with the weird convertion I mentionned before.

??? :cloud:

Thanks !