zakharovsergey1000 opened a new issue, #470:
URL: https://github.com/apache/mina-sshd/issues/470
### Version
2.9.2
### Bug description
Download the Gerrit code review source code and run all unit tests several
times.
### Actual behavior
In every full unit test run multiple random tests will fail with
NullPointerException:
Caused by: java.lang.NullPointerException
at
org.bouncycastle.math.ec.rfc7748.X25519.generatePrivateKey(X25519.java:54)
at
org.bouncycastle.crypto.params.X25519PrivateKeyParameters.<init>(X25519PrivateKeyParameters.java:24)
at
org.bouncycastle.crypto.generators.X25519KeyPairGenerator.generateKeyPair(X25519KeyPairGenerator.java:23)
at
org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi.generateKeyPair(KeyPairGeneratorSpi.java:193)
at
java.base/java.security.KeyPairGenerator$Delegate.generateKeyPair(KeyPairGenerator.java:722)
at
org.apache.sshd.common.kex.MontgomeryCurve.generateKeyPair(MontgomeryCurve.java:156)
### Expected behavior
There should not be random test fails caused by NullPointerException at
org.apache.sshd.common.kex.MontgomeryCurve.generateKeyPair(MontgomeryCurve.java:156).
All tests should complete successfully every time.
### Relevant log output
```Shell
There was 1 failure:
1)
sshKeyEndpoints(com.google.gerrit.acceptance.rest.binding.AccountsRestApiBindingsIT)
org.eclipse.jgit.errors.TransportException: ssh://[email protected]:43749:
DefaultAuthFuture[ssh-connection]: Failed (NullPointerException) to execute:
null
at
org.eclipse.jgit.transport.sshd.SshdSessionFactory.getSession(SshdSessionFactory.java:263)
at
com.google.gerrit.acceptance.SshSessionMina.getMinaSession(SshSessionMina.java:164)
at
com.google.gerrit.acceptance.SshSessionMina.open(SshSessionMina.java:82)
at
com.google.gerrit.acceptance.AbstractDaemonTest.initSsh(AbstractDaemonTest.java:573)
at
com.google.gerrit.acceptance.AbstractDaemonTest.beforeTest(AbstractDaemonTest.java:479)
at
com.google.gerrit.acceptance.AbstractDaemonTest$1$1.evaluate(AbstractDaemonTest.java:231)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at
org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at
com.google.testing.junit.runner.internal.junit4.CancellableRequestFactory$CancellableRunner.run(CancellableRequestFactory.java:108)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at
com.google.testing.junit.runner.junit4.JUnit4Runner.run(JUnit4Runner.java:116)
at
com.google.testing.junit.runner.BazelTestRunner.runTestsInSuite(BazelTestRunner.java:148)
at
com.google.testing.junit.runner.BazelTestRunner.main(BazelTestRunner.java:75)
Caused by: org.apache.sshd.common.SshException:
DefaultAuthFuture[ssh-connection]: Failed (NullPointerException) to execute:
null
at
org.apache.sshd.common.future.AbstractSshFuture.lambda$verifyResult$1(AbstractSshFuture.java:132)
at
org.apache.sshd.common.future.AbstractSshFuture.formatExceptionMessage(AbstractSshFuture.java:190)
at
org.apache.sshd.common.future.AbstractSshFuture.verifyResult(AbstractSshFuture.java:131)
at
org.apache.sshd.client.future.DefaultAuthFuture.verify(DefaultAuthFuture.java:39)
at
org.apache.sshd.client.future.DefaultAuthFuture.verify(DefaultAuthFuture.java:32)
at
org.apache.sshd.common.future.VerifiableFuture.verify(VerifiableFuture.java:68)
at
org.eclipse.jgit.transport.sshd.SshdSession.connect(SshdSession.java:172)
at
org.eclipse.jgit.transport.sshd.SshdSession.connect(SshdSession.java:101)
at
org.eclipse.jgit.transport.sshd.SshdSessionFactory.getSession(SshdSessionFactory.java:256)
... 40 more
Caused by: java.lang.NullPointerException
at
org.bouncycastle.math.ec.rfc7748.X25519.generatePrivateKey(X25519.java:54)
at
org.bouncycastle.crypto.params.X25519PrivateKeyParameters.<init>(X25519PrivateKeyParameters.java:24)
at
org.bouncycastle.crypto.generators.X25519KeyPairGenerator.generateKeyPair(X25519KeyPairGenerator.java:23)
at
org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi.generateKeyPair(KeyPairGeneratorSpi.java:193)
at
java.base/java.security.KeyPairGenerator$Delegate.generateKeyPair(KeyPairGenerator.java:722)
at
org.apache.sshd.common.kex.MontgomeryCurve.generateKeyPair(MontgomeryCurve.java:156)
at org.apache.sshd.common.kex.XDH.calculateE(XDH.java:45)
at org.apache.sshd.common.kex.AbstractDH.getE(AbstractDH.java:60)
at org.apache.sshd.client.kex.DHGClient.init(DHGClient.java:98)
at
org.apache.sshd.common.session.helpers.AbstractSession.doKexNegotiation(AbstractSession.java:888)
at
org.apache.sshd.common.session.helpers.AbstractSession.handleKexInit(AbstractSession.java:827)
at
org.apache.sshd.common.session.helpers.AbstractSession.doHandleMessage(AbstractSession.java:567)
at
org.apache.sshd.common.session.helpers.AbstractSession.lambda$handleMessage$0(AbstractSession.java:522)
at
org.apache.sshd.common.util.threads.ThreadUtils.runAsInternal(ThreadUtils.java:68)
at
org.apache.sshd.common.session.helpers.AbstractSession.handleMessage(AbstractSession.java:521)
at
org.apache.sshd.common.session.helpers.AbstractSession.decode(AbstractSession.java:1639)
at
org.apache.sshd.common.session.helpers.AbstractSession.messageReceived(AbstractSession.java:482)
at
org.eclipse.jgit.internal.transport.sshd.JGitClientSession.messageReceived(JGitClientSession.java:197)
at
org.apache.sshd.common.session.helpers.AbstractSessionIoHandler.messageReceived(AbstractSessionIoHandler.java:64)
at
org.apache.sshd.common.io.nio2.Nio2Session.handleReadCycleCompletion(Nio2Session.java:407)
at
org.apache.sshd.common.io.nio2.Nio2Session$1.onCompleted(Nio2Session.java:380)
at
org.apache.sshd.common.io.nio2.Nio2Session$1.onCompleted(Nio2Session.java:375)
at
org.apache.sshd.common.io.nio2.Nio2CompletionHandler.lambda$completed$0(Nio2CompletionHandler.java:38)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at
org.apache.sshd.common.io.nio2.Nio2CompletionHandler.completed(Nio2CompletionHandler.java:37)
at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127)
at java.base/sun.nio.ch.Invoker.invokeDirect(Invoker.java:158)
at
java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(UnixAsynchronousSocketChannelImpl.java:562)
at
java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:277)
at
java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:298)
at
org.apache.sshd.common.io.nio2.Nio2Session.doReadCycle(Nio2Session.java:492)
at
org.apache.sshd.common.io.nio2.Nio2Session.doReadCycle(Nio2Session.java:370)
at
org.apache.sshd.common.io.nio2.Nio2Session.startReading(Nio2Session.java:363)
at
org.apache.sshd.common.io.nio2.Nio2Session.startReading(Nio2Session.java:359)
at
org.apache.sshd.common.io.nio2.Nio2Session.startReading(Nio2Session.java:355)
at
org.apache.sshd.common.io.nio2.Nio2Session.startReading(Nio2Session.java:351)
at
org.apache.sshd.common.io.nio2.Nio2Session.startReading(Nio2Session.java:347)
at
org.apache.sshd.common.io.nio2.Nio2Connector$ConnectionCompletionHandler.onCompleted(Nio2Connector.java:163)
at
org.apache.sshd.common.io.nio2.Nio2Connector$ConnectionCompletionHandler.onCompleted(Nio2Connector.java:118)
at
org.apache.sshd.common.io.nio2.Nio2CompletionHandler.lambda$completed$0(Nio2CompletionHandler.java:38)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at
org.apache.sshd.common.io.nio2.Nio2CompletionHandler.completed(Nio2CompletionHandler.java:37)
at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127)
at java.base/sun.nio.ch.Invoker$2.run(Invoker.java:219)
at
java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
at
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
```
### Other information
The keyPairGenerator object in the MontgomeryCurve is a bouncycastle
implementation of the java.security.KeyPairGenerator class. The generateKeyPair
method in class
org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi is not
thread safe and calling the generateKeyPair method in
org.apache.sshd.common.kex.MontgomeryCurve.generateKeyPair() is not
synchronized. Therefore calling this method by multiple threads will often
cause a NullPointerException due to a race conditions.
Consider the following scenario: two threads simultaneously reach the
generateKeyPair() method in class
org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi. Thread
one performs the if (!initialised) check. The "initialised" variable is false.
Therefore, the setupGenerator(algorithm) method is executed. In the
setupGenerator method, the "initialised" variable is assigned true at the very
beginning. And at this moment, execution of the thread one is suspended and
execution of the thread two continues. Thread two evaluates the "initialised"
variable. The variable is true therefore thread two executes the further
command AsymmetricCipherKeyPair kp = generator.generateKeyPair(); the generator
is not yet correctly initialized. Thread two continues its execution and
eventually throws a NullPointerException, which is the result of the generator
not being initialized correctly because the setupGenerator method was not
executed to completion even though the "initialised" va
riable was already set to true. The callstack looks like this:
Caused by: java.lang.NullPointerException
at
org.bouncycastle.math.ec.rfc7748.X25519.generatePrivateKey(X25519.java:54)
at
org.bouncycastle.crypto.params.X25519PrivateKeyParameters.<init>(X25519PrivateKeyParameters.java:24)
at
org.bouncycastle.crypto.generators.X25519KeyPairGenerator.generateKeyPair(X25519KeyPairGenerator.java:23)
at
org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi.generateKeyPair(KeyPairGeneratorSpi.java:193)
at
java.base/java.security.KeyPairGenerator$Delegate.generateKeyPair(KeyPairGenerator.java:722)
at
org.apache.sshd.common.kex.MontgomeryCurve.generateKeyPair(MontgomeryCurve.java:156)
The org.bouncycastle.math.ec.rfc7748.X25519.generatePrivateKey(SecureRandom
random, byte[] k) method executes the random.nextBytes(k) instruction. In this
case, the "random" argument is null, since the setupGenerator(algorithm) method
was not completed yet. The result is a NullPointerException.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]