-
-
Notifications
You must be signed in to change notification settings - Fork 970
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.