Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception in SSH.NET 2024.2.0 when creating PrivateKeyFile array and passPhrase is an empty string #1572

Open
jverbosky opened this issue Jan 13, 2025 · 5 comments

Comments

@jverbosky
Copy link

jverbosky commented Jan 13, 2025

Description
Started getting an exception in v2024.2.0 when attempting to create a PrivateKeyFile array using a keyfile with an empty password - this configuration works fine in v2024.1.0 & below and has been used in production with a vendor's SFTP server for 2+ years.

Exception Message
The encoded length is not valid under the requested encoding rules, the value may be valid under the BER encoding.

StackTrace

   at System.Formats.Asn1.AsnDecoder.ReadLength(ReadOnlySpan`1 source, AsnEncodingRules ruleSet, Int32& bytesConsumed)
   at System.Formats.Asn1.AsnDecoder.GetPrimitiveContentSpan(ReadOnlySpan`1 source, AsnEncodingRules ruleSet, Asn1Tag expectedTag, UniversalTagNumber tagNumber, Int32& bytesConsumed)
   at System.Formats.Asn1.AsnDecoder.GetIntegerContents(ReadOnlySpan`1 source, AsnEncodingRules ruleSet, Asn1Tag expectedTag, UniversalTagNumber tagNumber, Int32& bytesConsumed)
   at System.Formats.Asn1.AsnDecoder.ReadIntegerBytes(ReadOnlySpan`1 source, AsnEncodingRules ruleSet, Int32& bytesConsumed, Nullable`1 expectedTag)
   at System.Formats.Asn1.AsnReader.ReadInteger(Nullable`1 expectedTag)
   at Renci.SshNet.Security.RsaKey..ctor(Byte[] privateKeyData)
   at Renci.SshNet.PrivateKeyFile.Open(Stream privateKey, String passPhrase)
   at Renci.SshNet.PrivateKeyFile..ctor(String fileName, String passPhrase, String certificateFileName)
   at Renci.SshNet.PrivateKeyFile..ctor(String fileName, String passPhrase)
   at webdevHealthCheck_Services.SftpService.GetSftpConnectionInfo(String sftpServerOption) in E:\Reports\webdevHealthCheck\App\services\remote\SftpService.cs:line 73

Screenshot:
image

To Reproduce
Here's part a basic prototype to confirm the behavior - the call to create the PrivateKeyFile array is where the exception occurs:

static void Main(string[] args)
{
    ConnectionInfo connectionInfo = null;
    List<AuthenticationMethod> authenticationMethods = [];
    string fileName = @"C:\Prototypes\dotnet_sftp_ssh-key\keys\wfgSshAuthKey";
    string passPhrase = "";

    try
    {
        // bug in SSH.NET 2024.2.0 causing this to fail when _sshKeyPassphrase is an empty string
        // - tested 2024.0.0 - fine
        // - tested 2024.1.0 - fine
        // - tested 2024.2.0 - exception
        PrivateKeyFile[] keyFiles = [new(fileName, passPhrase)];
        authenticationMethods.Add(new PrivateKeyAuthenticationMethod(_sftpUsername, keyFiles));

        connectionInfo = new(_sftpServer, _sftpPort, _sftpUsername, authenticationMethods.ToArray());
    }
    catch (Exception ex)
    {
        _logService.LogActivity($"Exception constructing ConnectionInfo object...");
        _logService.LogActivity($"Exception: {ex.Message}");
    }

}

Screenshot - reproduce

image

Expected behavior
In v2024.1.0 and below, a PrivateKeyFile array can be created using an empty string for the passPhrase value, and subsequently used to create a new ConnectionInfo object which can be used to create a new SftpClient instance.

Thank you for your help and please advise if you need any more details to reproduce.

@Rob-Hague
Copy link
Collaborator

Rob-Hague commented Jan 13, 2025

Perhaps we should be reading BER @scott-xu ?

diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs
index e1456ea6..a95b25f1 100644
--- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs
+++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs
@@ -161,7 +161,7 @@ public RsaKey(byte[] privateKeyData)
         {
             ThrowHelper.ThrowIfNull(privateKeyData);

-            var der = new AsnReader(privateKeyData, AsnEncodingRules.DER).ReadSequence();
+            var der = new AsnReader(privateKeyData, AsnEncodingRules.BER).ReadSequence();
             _ = der.ReadInteger(); // skip version

             Modulus = der.ReadInteger();

Is there anywhere that mandates DER rather than just BER for PKCS#1? I don't see anything here:
https://datatracker.ietf.org/doc/html/rfc3447#appendix-A.1.2

P.S. I updated the top post to wrap blocks in triple ticks ` per https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks

@Rob-Hague
Copy link
Collaborator

@jverbosky perhaps you can build this repo with that change above and see if it works for you? Changes were made in this area for 2024.2.0

Do you know how your key was generated i.e. which program?

@jverbosky
Copy link
Author

jverbosky commented Jan 28, 2025

@Rob-Hague apologies for my delayed reply, been busy and had to research how to accomplish what you suggested.


I used a program called VShell for generating the SSH key:
https://www.vandyke.com/products/vshell/docs/guide/public_keys.html

In case it's any help, here's my notes from when I created this key:

SFTP server doesn't use a passphrase, so just hit Enter when prompted for passphrase:

c:\Program Files\VanDyke Software\VShell>vkeygen -b 2048 -f d:\apps\wfgSshAuthKey -c "WFG Server" -O
Generating 'd:\apps\wfgSshAuthKey' keys...
Enter passphrase:
Confirm passphrase:

...then it spits out the MD5, SHA1 & SHA2 values

FWIW, I'm using other SSH keys (that use passwords) created by this app along with SSH.NET, and am able to connect to the respective SFTP servers fine - issue is just with this 'password-less' SSH key.


I was able to build a new DLL from the SSH.NET source code with the 'BER' change and figured out how to include it in my project. But when I run my app and try connecting using the 'password-less' SSH key, I get the following exception:

The type initializer for 'Renci.SshNet.Abstractions.CryptoAbstraction' threw an exception.

The only change I made was to swap to 'BER', so not sure if I might be missing something during the build or if there might be a dependency on DER deeper in SSH.NET - any suggestions?


Reference Screenshots

Image

Image

Image

Image


Thanks for your help!

John

@jverbosky
Copy link
Author

@Rob-Hague well I was re-reading my last post and noticed the 'Message' value in the final screenshot mentioned not being able to load BouncyCastle.Cryptography.

So I tried adding that to the project file and tried running the app, and it connected to the SFTP server and listed some test files just fine now!

So, the fix (for authentication using an SSH key without a password) appears to be the change that you mentioned earlier (DER ~> BER) plus the BouncyCastle.Cryptography package (never had to include that before, FWIW).

Please advise if you need any additional details - otherwise, hoping a new 'option' (DER or BER) can be added to a future SSH.NET release.

Image

Thanks again for your help!

John

@scott-xu
Copy link
Collaborator

scott-xu commented Feb 1, 2025

@jverbosky I can't reproduce the issue. See #1579

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants