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

fix(739) SignatureECDSAN destroying private key #740

Merged
merged 1 commit into from
Jan 8, 2025

Conversation

ikucuze
Copy link
Contributor

@ikucuze ikucuze commented Jan 7, 2025

fix for bug 739

@ikucuze
Copy link
Contributor Author

ikucuze commented Jan 7, 2025

fixes: #739

@norrisjeremy
Copy link
Contributor

No, I very much oppose this.
We are not going to stop zero'ing private key data.

@ikucuze
Copy link
Contributor Author

ikucuze commented Jan 7, 2025

PR updated to always perform a copy of the array instead of not 0-ing it

Copy link
Contributor

@norrisjeremy norrisjeremy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems acceptable to me by best limiting any potential impact.

@@ -351,7 +351,8 @@ public byte[] getSignature(byte[] data) {
.asSubclass(SignatureECDSA.class);
SignatureECDSA ecdsa = c.getDeclaredConstructor().newInstance();
ecdsa.init();
ecdsa.setPrvKey(prv_array);
// issue 730: prv_array could be destroyed by ecdsa signing process if its first bit is 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you fix this to correctly point to issue 739 and not issue 730 (which is unrelated).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I would prefer if we included a full link to https://github.com/mwiede/jsch/issues/739 in the comment text, so that future readers don't have to figure out what issue 739 means.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry. don't know how I did that

Copy link
Contributor Author

@ikucuze ikucuze Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made me realize 2 things:
This copy of the private key has to be cleaned... as we don't know if ecdsa signing will clean it...
So I need Util.bzero to be changed to public.
Would you prefer then:

      byte[] keyCopy = Arrays.copyOf(prv_array, prv_array.length);
      ecdsa.setPrvKey(keyCopy);
      Util.bzero(keyCopy);

I also need to change the caller of setPubKey with the same fix :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a new secured fixed regarding cleaning the key copy.
The resulting code starts to get ugly because of that unneeded copy...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert those changes and simply constrain this change to making a copy of prv_array that is passed to ecdsa.setPrvKey().

The whole point of what I am asking you to do is to make as minimally invasive changes as possible to fix the issue you reported.
That way we reduce the chance of introducing any sort of regression or any sort of new vulnerability as much as possible.
The JSch codebase is very old and extremely fragile, and we try to minimize risk as much as possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made me realize 2 things: This copy of the private key has to be cleaned... as we don't know if ecdsa signing will clean it... So I need Util.bzero to be changed to public. Would you prefer then:

      byte[] keyCopy = Arrays.copyOf(prv_array, prv_array.length);
      ecdsa.setPrvKey(keyCopy);
      Util.bzero(keyCopy);

I also need to change the caller of setPubKey with the same fix :(

There is zero reason to zero the public key, as that is not sensitive data.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, just pushed a fix only for private key, adding a cleaning to the copy for security purpose

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert the unnecessary changes to src/main/java/com/jcraft/jsch/jce/Util.java.

@@ -351,7 +351,8 @@ public byte[] getSignature(byte[] data) {
.asSubclass(SignatureECDSA.class);
SignatureECDSA ecdsa = c.getDeclaredConstructor().newInstance();
ecdsa.init();
ecdsa.setPrvKey(prv_array);
// issue 739: prv_array could be destroyed by ecdsa signing process if its first bit is 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change this to point at https://github.com/mwiede/jsch/issues/739 instead of issue 739?
That way future readers don't have to figure out how to find what issue 739 means.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@ikucuze ikucuze force-pushed the master branch 3 times, most recently from c8324cc to 25a0496 Compare January 7, 2025 13:42
Copy link
Contributor

@norrisjeremy norrisjeremy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert all these changes back to the minimally invasive change you had originally, which was to simply to call escda.setPrvKey(Arrays.copyOf(prv_array, prv_array.length));.

The whole point of this is to minimize risk as much as possible (both for any regressions as well as any newly introduced vulnerabilities) whilst fixing the issue you originally reported, which is that you were unable to create multiple sessions from a single JSch object instance.

@ikucuze ikucuze force-pushed the master branch 2 times, most recently from 1d013ef to dd77694 Compare January 7, 2025 14:17
@@ -26,8 +26,8 @@

package com.jcraft.jsch.jce;

class Util {
static void bzero(byte[] foo) {
public class Util {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no reason for this class to be made public.
Please revert this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needed to clean the copy

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is unneeded though to accomplish what you have proposed.
src/main/java/com/jcraft/jsch/KeyPairECDSA.java will be utilizing the class src/main/java/com/jcraft/jsch/Util.java, not src/main/java/com/jcraft/jsch/jce/Util.java.
Therefore there is no need for the changes to make src/main/java/com/jcraft/jsch/jce/Util.java public.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I was unaware of this duplicate code... fixed.

@ikucuze
Copy link
Contributor Author

ikucuze commented Jan 7, 2025

escda.setPrvKey(Arrays.copyOf(prv_array, prv_array.length));.

This is not acceptable as the copy array might stay in memory without cleaning in case of a positive number, thus setPrvKey won't clean it.
You fought for keeping the cleaning in SignatureECDSAN even if the priv_key is a parameter and not under its responsability. I think the responsability of the cleaning is in the hand of the code originating the data. Thus KeyPairECDSA is now reponsible to clean this copy, and for me was also was responsible for cleaning the original prv_array (and it does that correctly in its dispose() ).

@norrisjeremy
Copy link
Contributor

escda.setPrvKey(Arrays.copyOf(prv_array, prv_array.length));.

This is not acceptable as the copy array might stay in memory without cleaning in case of a positive number, thus setPrvKey won't clean it. You fought for keeping the cleaning in SignatureECDSAN even if the priv_key is a parameter and not under its responsability. I think the responsability of the cleaning is in the hand of the code originating the data. Thus KeyPairECDSA is now reponsible to clean this copy, and for me was also was responsible for cleaning the original prv_array (and it does that correctly in its dispose() ).

I'll agree to keeping the introduction of Util.bzero() of the prv_array copy.

@ikucuze
Copy link
Contributor Author

ikucuze commented Jan 7, 2025

I'll agree to keeping the introduction of Util.bzero() of the prv_array copy.

Ok, pushed that. Copy of public key do not get cleaned.
Copy of private key is done, by making Util public.
pushed that now

Copy link
Contributor

@norrisjeremy norrisjeremy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please execute mvn formatter:format so that your changes are properly formatted and allow the Maven build to succeed.

Copy link

sonarqubecloud bot commented Jan 7, 2025

Copy link
Contributor

@norrisjeremy norrisjeremy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am good with these changes now.

@mwiede mwiede merged commit b7e92bf into mwiede:master Jan 8, 2025
8 checks passed
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

Successfully merging this pull request may close these issues.

3 participants