Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-63601

trilead api 1.0.9 fails clone from ssh repository using 3DES/MD5-encrypted private key

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed (View Workflow)
    • Priority: Critical
    • Resolution: Fixed
    • Component/s: trilead-api-plugin
    • Labels:
      None
    • Environment:
      Jenkins 2.249.1-rc
      Git client plugin 3.4.0 with JGit enabled
      Git plugin 4.2.2
    • Similar Issues:
    • Released As:
       trilead-api-1.0.11

      Description

      I installed trilead-api-plugin 1.0.9 on my Jenkins 2.249.1-rc test instance. A job that had been successfully cloning a private GitLab repository using ssh with JGit now fails to clone. Likewise a private GitHub repository using ssh also fails to clone. With trilead api plugin 1.0.9, the clone fails with this stack trace:

      Cloning the remote Git repository
      ERROR: SSH authentication failed
      java.security.NoSuchAlgorithmException: Cannot find any provider supporting PBEWithMD5AndDESede
      	at javax.crypto.Cipher.getInstance(Cipher.java:543)
      	at com.trilead.ssh2.crypto.cipher.JreCipherWrapper.getInstance(JreCipherWrapper.java:23)
      Caused: java.lang.IllegalArgumentException
      	at com.trilead.ssh2.crypto.cipher.JreCipherWrapper.getInstance(JreCipherWrapper.java:26)
      	at com.trilead.ssh2.crypto.PEMDecoder.decryptPEM(PEMDecoder.java:353)
      	at com.trilead.ssh2.crypto.PEMDecoder.decodeKeyPair(PEMDecoder.java:492)
      	at com.trilead.ssh2.auth.AuthenticationManager.authenticatePublicKey(AuthenticationManager.java:290)
      	at com.trilead.ssh2.Connection.authenticateWithPublicKey(Connection.java:472)
      	at com.cloudbees.jenkins.plugins.sshcredentials.impl.TrileadSSHPublicKeyAuthenticator.doAuthenticate(TrileadSSHPublicKeyAuthenticator.java:109)
      	at com.cloudbees.jenkins.plugins.sshcredentials.SSHAuthenticator.authenticate(SSHAuthenticator.java:436)
      	at com.cloudbees.jenkins.plugins.sshcredentials.SSHAuthenticator.authenticate(SSHAuthenticator.java:473)
      	at org.jenkinsci.plugins.gitclient.trilead.TrileadSessionFactory.getSession(TrileadSessionFactory.java:39)
      	at org.eclipse.jgit.transport.SshTransport.getSession(SshTransport.java:107)
      	at org.eclipse.jgit.transport.TransportGitSsh$SshFetchConnection.<init>(TransportGitSsh.java:254)
      	at org.eclipse.jgit.transport.TransportGitSsh.openFetch(TransportGitSsh.java:144)
      	at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:105)
      	at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:91)
      	at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1260)
      	at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:211)
      	at org.jenkinsci.plugins.gitclient.JGitAPIImpl$4.execute(JGitAPIImpl.java:1482)
      	at org.jenkinsci.plugins.gitclient.RemoteGitImpl$CommandInvocationHandler$GitCommandMasterToSlaveCallable.call(RemoteGitImpl.java:161)
      	at org.jenkinsci.plugins.gitclient.RemoteGitImpl$CommandInvocationHandler$GitCommandMasterToSlaveCallable.call(RemoteGitImpl.java:154)
      	at hudson.remoting.UserRequest.perform(UserRequest.java:211)
      	at hudson.remoting.UserRequest.perform(UserRequest.java:54)
      	at hudson.remoting.Request$2.run(Request.java:375)
      	at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:73)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      	at java.lang.Thread.run(Thread.java:748)
      ERROR: Error cloning remote repo 'origin'
      hudson.plugins.git.GitException: org.eclipse.jgit.api.errors.TransportException: git@gitlab.com:MarkEWaite/tasks.git: remote hung up unexpectedly
      	at org.jenkinsci.plugins.gitclient.JGitAPIImpl$4.execute(JGitAPIImpl.java:1490)
      	at org.jenkinsci.plugins.gitclient.RemoteGitImpl$CommandInvocationHandler$GitCommandMasterToSlaveCallable.call(RemoteGitImpl.java:161)
      	at org.jenkinsci.plugins.gitclient.RemoteGitImpl$CommandInvocationHandler$GitCommandMasterToSlaveCallable.call(RemoteGitImpl.java:154)
      	at hudson.remoting.UserRequest.perform(UserRequest.java:211)
      	at hudson.remoting.UserRequest.perform(UserRequest.java:54)
      	at hudson.remoting.Request$2.run(Request.java:375)
      	at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:73)
      	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      	at java.lang.Thread.run(Thread.java:748)
      	Suppressed: hudson.remoting.Channel$CallSiteStackTrace: Remote call to gcp-ubuntu-18-b
      		at hudson.remoting.Channel.attachCallSiteStackTrace(Channel.java:1800)
      		at hudson.remoting.UserRequest$ExceptionResponse.retrieve(UserRequest.java:357)
      		at hudson.remoting.Channel.call(Channel.java:1001)
      		at org.jenkinsci.plugins.gitclient.RemoteGitImpl$CommandInvocationHandler.execute(RemoteGitImpl.java:146)
      		at sun.reflect.GeneratedMethodAccessor279.invoke(Unknown Source)
      		at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      		at java.lang.reflect.Method.invoke(Method.java:498)
      		at org.jenkinsci.plugins.gitclient.RemoteGitImpl$CommandInvocationHandler.invoke(RemoteGitImpl.java:132)
      		at com.sun.proxy.$Proxy113.execute(Unknown Source)
      		at hudson.plugins.git.GitSCM.retrieveChanges(GitSCM.java:1184)
      		at hudson.plugins.git.GitSCM.checkout(GitSCM.java:1262)
      		at hudson.scm.SCM.checkout(SCM.java:505)
      		at hudson.model.AbstractProject.checkout(AbstractProject.java:1206)
      		at hudson.model.AbstractBuild$AbstractBuildExecution.defaultCheckout(AbstractBuild.java:574)
      		at jenkins.scm.SCMCheckoutStrategy.checkout(SCMCheckoutStrategy.java:86)
      		at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:499)
      		at hudson.model.Run.execute(Run.java:1894)
      		at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
      		at hudson.model.ResourceController.execute(ResourceController.java:97)
      		at hudson.model.Executor.run(Executor.java:428)
      Caused by: org.eclipse.jgit.api.errors.TransportException: git@gitlab.com:MarkEWaite/tasks.git: remote hung up unexpectedly
      	at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:222)
      	at org.jenkinsci.plugins.gitclient.JGitAPIImpl$4.execute(JGitAPIImpl.java:1482)
      	... 10 more
      Caused by: org.eclipse.jgit.errors.TransportException: git@gitlab.com:MarkEWaite/tasks.git: remote hung up unexpectedly
      	at org.eclipse.jgit.transport.TransportGitSsh$SshFetchConnection.<init>(TransportGitSsh.java:270)
      	at org.eclipse.jgit.transport.TransportGitSsh.openFetch(TransportGitSsh.java:144)
      	at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:105)
      	at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:91)
      	at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1260)
      	at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:211)
      	... 11 more
      Caused by: java.lang.IllegalStateException: Cannot open session, connection is not authenticated.
      	at com.trilead.ssh2.Connection.openSession(Connection.java:1080)
      	at org.jenkinsci.plugins.gitclient.trilead.TrileadSession$ProcessImpl.<init>(TrileadSession.java:43)
      	at org.jenkinsci.plugins.gitclient.trilead.TrileadSession.exec(TrileadSession.java:33)
      	at org.eclipse.jgit.transport.TransportGitSsh$SshFetchConnection.<init>(TransportGitSsh.java:254)
      	... 16 more
      ERROR: Error cloning remote repo 'origin'
      

      The job works successfully with trilead api plugin 1.0.8.

      The trilead api plugin 1.0.9 does not fail when cloning a repository from Assembla, Beanstalk, Bitbucket, or Microsoft.

        Attachments

          Issue Links

            Activity

            Hide
            markewaite Mark Waite added a comment -

            I was using JDK 8u262 from AdoptOpenJDK in my testing. I can also check with JDK 11.0.8 from AdoptOpenJDK if that helps.

            Show
            markewaite Mark Waite added a comment - I was using JDK 8u262 from AdoptOpenJDK in my testing. I can also check with JDK 11.0.8 from AdoptOpenJDK if that helps.
            Hide
            jvz Matt Sicker added a comment - - edited

            Ok, I think I discovered the source of the problem (besides a lack of unit tests to catch it):

            https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher shows that the PBE ciphers are named as PBEWithDigestAndEncryption. In this case, Digest is MD5, and Encryption would be DESede from that same table. In fact, if I test out Cipher.getInstance("PBEWithSHA1AndDESede"), that works, but if I try using PBEWithMD5AndDESede, it doesn't; BUT, if I use PBEWithMD5AndTripleDES, it does work! This looks like an OpenJDK bug to be honest.

            Edit: looking through OpenJDK, this is likely because the SHA1 variant is implemented via their PKCS12 code while the MD5 variant is implemented via a separate class. Take a look at the various PBE classes here: https://github.com/openjdk/jdk/tree/master/src/java.base/share/classes/com/sun/crypto/provider

            Edit2: the worst part here is that they're incompatible! The PBEWithMD5AndFoo variant must use TripleDES, while the PBEWithSHA1AndFoo must use DESede; neither supports the other name! Take a look: https://github.com/openjdk/jdk/blob/e20004d7c170dc9f25f23c0a5dbf3a4c67db9423/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java#L280-L284

            Show
            jvz Matt Sicker added a comment - - edited Ok, I think I discovered the source of the problem (besides a lack of unit tests to catch it): https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher shows that the PBE ciphers are named as PBEWithDigestAndEncryption. In this case, Digest is MD5, and Encryption would be DESede from that same table. In fact, if I test out Cipher.getInstance("PBEWithSHA1AndDESede"), that works, but if I try using PBEWithMD5AndDESede, it doesn't; BUT, if I use PBEWithMD5AndTripleDES, it does work! This looks like an OpenJDK bug to be honest. Edit: looking through OpenJDK, this is likely because the SHA1 variant is implemented via their PKCS12 code while the MD5 variant is implemented via a separate class . Take a look at the various PBE classes here: https://github.com/openjdk/jdk/tree/master/src/java.base/share/classes/com/sun/crypto/provider Edit2: the worst part here is that they're incompatible! The PBEWithMD5AndFoo variant must use TripleDES, while the PBEWithSHA1AndFoo must use DESede; neither supports the other name! Take a look: https://github.com/openjdk/jdk/blob/e20004d7c170dc9f25f23c0a5dbf3a4c67db9423/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java#L280-L284
            Hide
            ifernandezcalvo Ivan Fernandez Calvo added a comment -

            There is also no PBE providers for MD5 + AES, so I will try to integrate the proposal in the PR that works as expected for all the ciphers in the JreCipherWrapper, I will have some time this weekend.

            Show
            ifernandezcalvo Ivan Fernandez Calvo added a comment - There is also no PBE providers for MD5 + AES, so I will try to integrate the proposal in the PR that works as expected for all the ciphers in the JreCipherWrapper, I will have some time this weekend.
            Show
            jvz Matt Sicker added a comment - Is there one in BouncyCastle? There's a list of providers here: https://github.com/bcgit/bc-java/tree/738dfc0132323d66ad27e7ec366666ed3e0638ab/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric
            Hide
            ifernandezcalvo Ivan Fernandez Calvo added a comment -

            finally, I keep it simple, not new dependencies it uses the JDK providers. I have tested the result on a test environment https://github.com/kuisathaverat/jenkins-issues/tree/master/JENKINS-63601, all Keys works for connecting agents and it is possible to connect with git an encrypted key provided from credentials.
            I am going to release a new version 1.0.11 this weekend https://github.com/jenkinsci/trilead-api-plugin/pull/13

            Show
            ifernandezcalvo Ivan Fernandez Calvo added a comment - finally, I keep it simple, not new dependencies it uses the JDK providers. I have tested the result on a test environment https://github.com/kuisathaverat/jenkins-issues/tree/master/JENKINS-63601 , all Keys works for connecting agents and it is possible to connect with git an encrypted key provided from credentials. I am going to release a new version 1.0.11 this weekend https://github.com/jenkinsci/trilead-api-plugin/pull/13

              People

              Assignee:
              ifernandezcalvo Ivan Fernandez Calvo
              Reporter:
              markewaite Mark Waite
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: