-
-
Notifications
You must be signed in to change notification settings - Fork 963
Description
A NotSupportedException is thrown when generating SSH keys with the "ssh-keygen" command on a Mac with macOS Mojave 10.14.1. With lower versions it's working fine.
Exception:
System.NotSupportedException: Key 'OPENSSH' is not supported.
at Renci.SshNet.PrivateKeyFile.Open(Stream privateKey, String passPhrase)
at Renci.SshNet.PrivateKeyFile..ctor(String fileName, String passPhrase)
Inspecting the generated private key I can see that the header starts with:
"-----BEGIN OPENSSH PRIVATE KEY-----"
Also, If I inspect a private key generated in a Mac with a lower macOS version, I can see something like:
"-----BEGIN RSA PRIVATE KEY-----"
The following code in this repo tries to match a Regex to detect they key name and act based on it. For this reason, It doesn't recognize "OPENSSH" as a valid private key name and it fails:
SSH.NET/src/Renci.SshNet/PrivateKeyFile.cs
Lines 190 to 273 in bd01d97
switch (keyName) | |
{ | |
case "RSA": | |
_key = new RsaKey(decryptedData); | |
HostKey = new KeyHostAlgorithm("ssh-rsa", _key); | |
break; | |
case "DSA": | |
_key = new DsaKey(decryptedData); | |
HostKey = new KeyHostAlgorithm("ssh-dss", _key); | |
break; | |
case "SSH2 ENCRYPTED": | |
var reader = new SshDataReader(decryptedData); | |
var magicNumber = reader.ReadUInt32(); | |
if (magicNumber != 0x3f6ff9eb) | |
{ | |
throw new SshException("Invalid SSH2 private key."); | |
} | |
reader.ReadUInt32(); // Read total bytes length including magic number | |
var keyType = reader.ReadString(SshData.Ascii); | |
var ssh2CipherName = reader.ReadString(SshData.Ascii); | |
var blobSize = (int)reader.ReadUInt32(); | |
byte[] keyData; | |
if (ssh2CipherName == "none") | |
{ | |
keyData = reader.ReadBytes(blobSize); | |
} | |
else if (ssh2CipherName == "3des-cbc") | |
{ | |
if (string.IsNullOrEmpty(passPhrase)) | |
throw new SshPassPhraseNullOrEmptyException("Private key is encrypted but passphrase is empty."); | |
var key = GetCipherKey(passPhrase, 192 / 8); | |
var ssh2Сipher = new TripleDesCipher(key, new CbcCipherMode(new byte[8]), new PKCS7Padding()); | |
keyData = ssh2Сipher.Decrypt(reader.ReadBytes(blobSize)); | |
} | |
else | |
{ | |
throw new SshException(string.Format("Cipher method '{0}' is not supported.", cipherName)); | |
} | |
// TODO: Create two specific data types to avoid using SshDataReader class | |
reader = new SshDataReader(keyData); | |
var decryptedLength = reader.ReadUInt32(); | |
if (decryptedLength > blobSize - 4) | |
throw new SshException("Invalid passphrase."); | |
if (keyType == "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}") | |
{ | |
var exponent = reader.ReadBigIntWithBits();//e | |
var d = reader.ReadBigIntWithBits();//d | |
var modulus = reader.ReadBigIntWithBits();//n | |
var inverseQ = reader.ReadBigIntWithBits();//u | |
var q = reader.ReadBigIntWithBits();//p | |
var p = reader.ReadBigIntWithBits();//q | |
_key = new RsaKey(modulus, exponent, d, p, q, inverseQ); | |
HostKey = new KeyHostAlgorithm("ssh-rsa", _key); | |
} | |
else if (keyType == "dl-modp{sign{dsa-nist-sha1},dh{plain}}") | |
{ | |
var zero = reader.ReadUInt32(); | |
if (zero != 0) | |
{ | |
throw new SshException("Invalid private key"); | |
} | |
var p = reader.ReadBigIntWithBits(); | |
var g = reader.ReadBigIntWithBits(); | |
var q = reader.ReadBigIntWithBits(); | |
var y = reader.ReadBigIntWithBits(); | |
var x = reader.ReadBigIntWithBits(); | |
_key = new DsaKey(p, q, g, y, x); | |
HostKey = new KeyHostAlgorithm("ssh-dss", _key); | |
} | |
else | |
{ | |
throw new NotSupportedException(string.Format("Key type '{0}' is not supported.", keyType)); | |
} | |
break; | |
default: | |
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Key '{0}' is not supported.", keyName)); |
Thanks.