├── .github ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── release-drafter.yml └── workflows │ ├── cd.yaml │ └── codeql.yml ├── .gitignore ├── .hgignore ├── .mvn ├── extensions.xml └── maven.config ├── HISTORY.txt ├── Jenkinsfile ├── LICENSE.txt ├── README.txt ├── pom.xml ├── src ├── com │ └── trilead │ │ └── ssh2 │ │ ├── ChannelCondition.java │ │ ├── Connection.java │ │ ├── ConnectionInfo.java │ │ ├── ConnectionMonitor.java │ │ ├── DHGexParameters.java │ │ ├── DebugLogger.java │ │ ├── ExtendedServerHostKeyVerifier.java │ │ ├── HTTPProxyData.java │ │ ├── HTTPProxyException.java │ │ ├── IOWarningException.java │ │ ├── InteractiveCallback.java │ │ ├── KnownHosts.java │ │ ├── LocalPortForwarder.java │ │ ├── LocalStreamForwarder.java │ │ ├── ProxyData.java │ │ ├── RandomFactory.java │ │ ├── SCPClient.java │ │ ├── SFTPException.java │ │ ├── SFTPv3Client.java │ │ ├── SFTPv3DirectoryEntry.java │ │ ├── SFTPv3FileAttributes.java │ │ ├── SFTPv3FileHandle.java │ │ ├── ServerHostKeyVerifier.java │ │ ├── Session.java │ │ ├── StreamGobbler.java │ │ ├── auth │ │ ├── AgentIdentity.java │ │ ├── AgentProxy.java │ │ ├── AuthenticationManager.java │ │ └── GSSContextKrb5.java │ │ ├── channel │ │ ├── Channel.java │ │ ├── ChannelInputStream.java │ │ ├── ChannelManager.java │ │ ├── ChannelOutputStream.java │ │ ├── FifoBuffer.java │ │ ├── IChannelWorkerThread.java │ │ ├── LocalAcceptThread.java │ │ ├── RemoteAcceptThread.java │ │ ├── RemoteForwardingData.java │ │ ├── RemoteX11AcceptThread.java │ │ ├── StreamForwarder.java │ │ └── X11ServerData.java │ │ ├── crypto │ │ ├── Base64.java │ │ ├── CertificateDecoder.java │ │ ├── CryptoWishList.java │ │ ├── KeyMaterial.java │ │ ├── PEMDecoder.java │ │ ├── PEMStructure.java │ │ ├── SimpleDERReader.java │ │ ├── cipher │ │ │ ├── AES.java │ │ │ ├── BlockCipher.java │ │ │ ├── BlockCipherFactory.java │ │ │ ├── BlowFish.java │ │ │ ├── CBCMode.java │ │ │ ├── CTRMode.java │ │ │ ├── CipherInputStream.java │ │ │ ├── CipherOutputStream.java │ │ │ ├── DES.java │ │ │ ├── DESede.java │ │ │ └── NullCipher.java │ │ ├── dh │ │ │ ├── Curve25519Exchange.java │ │ │ ├── DhExchange.java │ │ │ ├── DhGroupExchange.java │ │ │ ├── EcDhExchange.java │ │ │ └── GenericDhExchange.java │ │ └── digest │ │ │ ├── Digest.java │ │ │ ├── HMAC.java │ │ │ ├── HashForSSH2Types.java │ │ │ ├── JreMessageDigestWrapper.java │ │ │ ├── MAC.java │ │ │ ├── MD5.java │ │ │ ├── MessageMac.java │ │ │ └── SHA1.java │ │ ├── jenkins │ │ ├── FilterAlgorithms.java │ │ ├── FilterEncrytionAlgorithms.java │ │ ├── FilterHostKeyAlgorithms.java │ │ ├── FilterKexAlgorithms.java │ │ ├── FilterMacAlgorithms.java │ │ └── SFTPClient.java │ │ ├── log │ │ └── Logger.java │ │ ├── packets │ │ ├── PacketChannelOpenConfirmation.java │ │ ├── PacketChannelOpenFailure.java │ │ ├── PacketChannelTrileadPing.java │ │ ├── PacketChannelWindowAdjust.java │ │ ├── PacketDisconnect.java │ │ ├── PacketGlobalCancelForwardRequest.java │ │ ├── PacketGlobalForwardRequest.java │ │ ├── PacketGlobalTrileadPing.java │ │ ├── PacketIgnore.java │ │ ├── PacketKexDHInit.java │ │ ├── PacketKexDHReply.java │ │ ├── PacketKexDhGexGroup.java │ │ ├── PacketKexDhGexInit.java │ │ ├── PacketKexDhGexReply.java │ │ ├── PacketKexDhGexRequest.java │ │ ├── PacketKexDhGexRequestOld.java │ │ ├── PacketKexInit.java │ │ ├── PacketNewKeys.java │ │ ├── PacketOpenDirectTCPIPChannel.java │ │ ├── PacketOpenSessionChannel.java │ │ ├── PacketServiceAccept.java │ │ ├── PacketServiceRequest.java │ │ ├── PacketSessionExecCommand.java │ │ ├── PacketSessionPtyRequest.java │ │ ├── PacketSessionStartShell.java │ │ ├── PacketSessionSubsystemRequest.java │ │ ├── PacketSessionX11Request.java │ │ ├── PacketSignal.java │ │ ├── PacketUserauthBanner.java │ │ ├── PacketUserauthFailure.java │ │ ├── PacketUserauthInfoRequest.java │ │ ├── PacketUserauthInfoResponse.java │ │ ├── PacketUserauthRequestGssapiWithMic.java │ │ ├── PacketUserauthRequestInteractive.java │ │ ├── PacketUserauthRequestNone.java │ │ ├── PacketUserauthRequestPassword.java │ │ ├── PacketUserauthRequestPublicKey.java │ │ ├── PacketUserauthTokenGssapiWithMic.java │ │ ├── PacketWindowChange.java │ │ ├── Packets.java │ │ ├── TypesReader.java │ │ └── TypesWriter.java │ │ ├── sftp │ │ ├── AttrTextHints.java │ │ ├── AttribBits.java │ │ ├── AttribFlags.java │ │ ├── AttribPermissions.java │ │ ├── AttribTypes.java │ │ ├── ErrorCodes.java │ │ ├── OpenFlags.java │ │ └── Packet.java │ │ ├── signature │ │ ├── DSAKeyAlgorithm.java │ │ ├── DSAPrivateKey.java │ │ ├── DSAPublicKey.java │ │ ├── DSASHA1Verify.java │ │ ├── DSASignature.java │ │ ├── ECDSAKeyAlgorithm.java │ │ ├── ED25519KeyAlgorithm.java │ │ ├── KeyAlgorithm.java │ │ ├── KeyAlgorithmManager.java │ │ ├── OpenSshCertificateDecoder.java │ │ ├── RSAKeyAlgorithm.java │ │ ├── RSAPrivateKey.java │ │ ├── RSAPublicKey.java │ │ ├── RSASHA1Verify.java │ │ └── RSASignature.java │ │ ├── transport │ │ ├── Acceptor.java │ │ ├── ClientServerHello.java │ │ ├── KexManager.java │ │ ├── KexParameters.java │ │ ├── KexState.java │ │ ├── MessageHandler.java │ │ ├── NegotiateException.java │ │ ├── NegotiatedParameters.java │ │ ├── TransportConnection.java │ │ └── TransportManager.java │ │ └── util │ │ ├── IOUtils.java │ │ ├── TimeoutService.java │ │ └── Tokenizer.java └── spotbugs │ └── excludesFilter.xml ├── test ├── Receiver.java ├── Sender.java ├── com │ └── trilead │ │ └── ssh2 │ │ ├── KerberosTest.java │ │ ├── KnownHostsTest.java │ │ ├── SFTPClientTest.java │ │ ├── channel │ │ ├── ConnectionRule.java │ │ ├── FifoBufferTest.java │ │ └── RoundtripTest.java │ │ ├── crypto │ │ ├── SimpleDERReaderTest.java │ │ ├── cipher │ │ │ ├── BlockCipherTest.java │ │ │ ├── ProtectedKeys.java │ │ │ ├── aes128_cbc.pem │ │ │ ├── aes192_cbc.pem │ │ │ ├── aes256_cbc.pem │ │ │ ├── des_cbc.pem │ │ │ ├── des_ede3_cbc.pem │ │ │ ├── key.pem │ │ │ └── key.pem.pub │ │ └── dh │ │ │ └── Curve25519ExchangeTest.java │ │ ├── jenkins │ │ └── FilterAlgorithmsTest.java │ │ ├── signature │ │ ├── DSAKeyAlgorithmTest.java │ │ ├── ECDSAKeyAlgorithmTest.java │ │ ├── ED25519KeyAlgorithmTest.java │ │ ├── RSAKeyAlgorithmTest.java │ │ ├── dsa-testkey-unprotected-newformat.txt │ │ ├── dsa-testkey-unprotected.txt │ │ ├── ecdsa-sha2-nistp256-testkey-unprotected-newformat.txt │ │ ├── ecdsa-sha2-nistp256-testkey-unprotected.txt │ │ ├── ecdsa-sha2-nistp384-testkey-unprotected-newformat.txt │ │ ├── ecdsa-sha2-nistp384-testkey-unprotected.txt │ │ ├── ecdsa-sha2-nistp521-testkey-unprotected-newformat.txt │ │ ├── ecdsa-sha2-nistp521-testkey-unprotected.txt │ │ ├── ed25519-testkey-protected-ctr.txt │ │ ├── ed25519-testkey-protected.txt │ │ ├── ed25519-testkey-unprotected.txt │ │ ├── rsa-testkey-unprotected-newformat.txt │ │ └── rsa-testkey-unprotected.txt │ │ └── transport │ │ ├── CallHomeTest.java │ │ ├── JULLoggerSetup.java │ │ ├── JulLogConsumer.java │ │ ├── KexManagerTest.java │ │ ├── MyServerHostKeyVerifierImpl.java │ │ ├── Netopeer2TestContainer.java │ │ └── SshCallHomeClient.java ├── docker │ ├── Dockerfile │ ├── nacm.xml │ ├── ssh_callhome.xml │ └── ssh_listen.xml └── krb5_test.sh └── workflows └── cd.yaml /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jenkinsci/trilead-ssh2-developers 2 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | See [JENKINS-XXXXX](https://issues.jenkins-ci.org/browse/JENKINS-XXXXX). 2 | 3 | 7 | 8 | ### Submitter checklist 9 | 10 | - [ ] JIRA issue is well described 11 | - [ ] Appropriate autotests or explanation to why this change has no tests 12 | 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "github-actions" 8 | directory: / 9 | schedule: 10 | interval: "daily" -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | _extends: .github -------------------------------------------------------------------------------- /.github/workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins 2 | 3 | name: cd 4 | on: 5 | workflow_dispatch: 6 | check_run: 7 | types: 8 | - completed 9 | 10 | jobs: 11 | maven-cd: 12 | uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1 13 | secrets: 14 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} 15 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "main" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "main" ] 20 | schedule: 21 | - cron: '41 0 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'java' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v4 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v3 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v3 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v3 73 | with: 74 | category: "/language:${{matrix.language}}" 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven build files 2 | target/ 3 | 4 | # IntelliJ project files 5 | *.iml 6 | *.ipr 7 | *.iws 8 | .idea/ 9 | 10 | # Eclipse project files 11 | .settings/ 12 | .classpath 13 | .project 14 | .metadata 15 | .loadpath 16 | bin/ 17 | 18 | #Netbeans files 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | nbactions.xml 25 | nb-configuration.xml 26 | 27 | #vscode 28 | .vscode/* 29 | 30 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | target 2 | trilead-ssh2.iml 3 | trilead-ssh2.iws 4 | trilead-ssh2.ipr 5 | -------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.8 6 | 7 | 8 | -------------------------------------------------------------------------------- /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -Dchangelist.format=%d.v%s -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent { label 'linux' } 3 | stages { 4 | stage('Checkout') { 5 | steps { 6 | script { 7 | infra.checkoutSCM() 8 | } 9 | } 10 | } 11 | stage('Build') { 12 | steps { 13 | script { 14 | m2repo = "${pwd tmp: true}/m2repo" 15 | String jdk = "21" 16 | List mavenOptions = [ 17 | '--update-snapshots', 18 | "-Dmaven.repo.local=$m2repo", 19 | '-Dmaven.test.failure.ignore', 20 | "-Dset.changelist", 21 | "-Djava.security.egd=file:/dev/./urandom", 22 | "clean install" 23 | ] 24 | 25 | infra.runMaven(mavenOptions, jdk) 26 | } 27 | } 28 | post { 29 | always { 30 | /* 31 | archiveArtifacts(allowEmptyArchive: true, 32 | artifacts: "** /target/trilead*.jar", 33 | onlyIfSuccessful: false) 34 | */ 35 | junit(allowEmptyResults: true, 36 | keepLongStdio: true, 37 | testResults: "**/target/surefire-reports/**/*.xml") 38 | script { 39 | def m2repo = "${pwd tmp: true}/m2repo" 40 | // No easy way to load both of these in one command: https://stackoverflow.com/q/23521889/12916 41 | String version = sh script: 'mvn -Dset.changelist -Dexpression=project.version -q -DforceStdout help:evaluate', returnStdout: true 42 | echo "Collecting $version from $m2repo for possible Incrementals publishing" 43 | dir(m2repo) { 44 | archiveArtifacts "org/jenkins-ci/trilead-ssh2/$version/*$version*" 45 | } 46 | infra.maybePublishIncrementals() 47 | } 48 | } 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | 2 | Trilead SSH-2 for Java - build 212 3 | ================================== 4 | 5 | http://www.trilead.com 6 | 7 | Trilead SSH-2 for Java is a library which implements the SSH-2 protocol in pure Java 8 | (minimum required JRE: 1.4.2). It allows one to connect to SSH servers from within 9 | Java programs. It supports SSH sessions (remote command execution and shell access), 10 | local and remote port forwarding, local stream forwarding, X11 forwarding, SCP and SFTP. 11 | There are no dependencies on any JCE provider, as all crypto functionality is included. 12 | 13 | This distribution contains the source code, examples, javadoc and the FAQ. 14 | It also includes a pre-compiled jar version of the library which is ready to use. 15 | 16 | - Please read the included LICENCE.txt 17 | - Latest changes can be found in HISTORY.txt 18 | 19 | The latest version of the FAQ is available on the website. 20 | 21 | Please feel free to contact us. We welcome feedback of any kind! 22 | Contact: support@trilead.com or go to the public forum at http://www.trilead.com 23 | 24 | Zurich, March 2008 25 | 26 | ## Algorithm filters 27 | 28 | The algorithm filters can be used to restrict the algorithms that are used by the library. 29 | The filters will remove the algorithms you specify from the SSH algorithms negotiation between client and server. 30 | The library supports the following algorithm filters: 31 | * Kex (Key Exchange) algorithm filter 32 | * Host Key algorithm filter 33 | * Encryption algorithm filter 34 | * MAC algorithm filter 35 | 36 | To filter algorithms enable the filters using the following System properties: 37 | 38 | 39 | * com.trilead.ssh2.jenkins.FilterKexAlgorithms.enabled (default: true) 40 | * com.trilead.ssh2.jenkins.FilterHostKeyAlgorithms.enabled (default: true) 41 | * com.trilead.ssh2.jenkins.FilterMacAlgorithms.enabled (default: true) 42 | * com.trilead.ssh2.jenkins.FilterEncrytionAlgorithms.enabled (default: true) 43 | 44 | The algorithms are specified as a comma separated list of algorithm names. 45 | To configure the algorithm filters, use the following System properties: 46 | 47 | * com.trilead.ssh2.jenkins.FilterKexAlgorithms.algorithms 48 | * com.trilead.ssh2.jenkins.FilterHostKeyAlgorithms.algorithms 49 | * com.trilead.ssh2.jenkins.FilterMacAlgorithms.algorithms 50 | * com.trilead.ssh2.jenkins.FilterEncrytionAlgorithms.algorithms 51 | 52 | Example 53 | ```bash 54 | java -Dcom.trilead.ssh2.jenkins.FilterKexAlgorithms.enabled=true \ 55 | -Dcom.trilead.ssh2.jenkins.FilterKexAlgorithms.algorithms=diffie-hellman-group-exchange-sha256 \ 56 | -jar jenkins.war 57 | ``` 58 | 59 | To check the algorithms filtered by the library, check the `Filter*` classes at the package [`com.trilead.ssh2.jenkins`](src/com/trilead/ssh2/jenkins). -------------------------------------------------------------------------------- /src/com/trilead/ssh2/ChannelCondition.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * Contains constants that can be used to specify what conditions to wait for on 6 | * a SSH-2 channel (e.g., represented by a {@link Session}). 7 | * 8 | * @see Session#waitForCondition(int, long) 9 | * 10 | * @author Christian Plattner, plattner@trilead.com 11 | * @version $Id: ChannelCondition.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 12 | */ 13 | 14 | public abstract interface ChannelCondition 15 | { 16 | /** 17 | * A timeout has occurred, none of your requested conditions is fulfilled. 18 | * However, other conditions may be true - therefore, NEVER use the "==" 19 | * operator to test for this (or any other) condition. Always use 20 | * something like ((cond & ChannelCondition.CLOSED) != 0). 21 | */ 22 | public static final int TIMEOUT = 1; 23 | 24 | /** 25 | * The underlying SSH-2 channel, however not necessarily the whole connection, 26 | * has been closed. This implies EOF. Note that there may still 27 | * be unread stdout or stderr data in the local window, i.e, STDOUT_DATA 28 | * or/and STDERR_DATA may be set at the same time. 29 | */ 30 | public static final int CLOSED = 2; 31 | 32 | /** 33 | * There is stdout data available that is ready to be consumed. 34 | */ 35 | public static final int STDOUT_DATA = 4; 36 | 37 | /** 38 | * There is stderr data available that is ready to be consumed. 39 | */ 40 | public static final int STDERR_DATA = 8; 41 | 42 | /** 43 | * EOF on has been reached, no more _new_ stdout or stderr data will arrive 44 | * from the remote server. However, there may be unread stdout or stderr 45 | * data, i.e, STDOUT_DATA or/and STDERR_DATA 46 | * may be set at the same time. 47 | */ 48 | public static final int EOF = 16; 49 | 50 | /** 51 | * The exit status of the remote process is available. 52 | * Some servers never send the exist status, or occasionally "forget" to do so. 53 | */ 54 | public static final int EXIT_STATUS = 32; 55 | 56 | /** 57 | * The exit signal of the remote process is available. 58 | */ 59 | public static final int EXIT_SIGNAL = 64; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/ConnectionInfo.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * In most cases you probably do not need the information contained in here. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: ConnectionInfo.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | public class ConnectionInfo 11 | { 12 | /** 13 | * The used key exchange (KEX) algorithm in the latest key exchange. 14 | */ 15 | public String keyExchangeAlgorithm; 16 | 17 | /** 18 | * The currently used crypto algorithm for packets from to the client to the 19 | * server. 20 | */ 21 | public String clientToServerCryptoAlgorithm; 22 | /** 23 | * The currently used crypto algorithm for packets from to the server to the 24 | * client. 25 | */ 26 | public String serverToClientCryptoAlgorithm; 27 | 28 | /** 29 | * The currently used MAC algorithm for packets from to the client to the 30 | * server. 31 | */ 32 | public String clientToServerMACAlgorithm; 33 | /** 34 | * The currently used MAC algorithm for packets from to the server to the 35 | * client. 36 | */ 37 | public String serverToClientMACAlgorithm; 38 | 39 | /** 40 | * The type of the server host key 41 | */ 42 | public String serverHostKeyAlgorithm; 43 | /** 44 | * The server host key that was sent during the latest key exchange. 45 | */ 46 | public byte[] serverHostKey; 47 | 48 | /** 49 | * Number of kex exchanges performed on this connection so far. 50 | */ 51 | public int keyExchangeCounter = 0; 52 | } 53 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/ConnectionMonitor.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * A ConnectionMonitor is used to get notified when the 6 | * underlying socket of a connection is closed. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: ConnectionMonitor.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 10 | */ 11 | 12 | public interface ConnectionMonitor 13 | { 14 | /** 15 | * This method is called after the connection's underlying 16 | * socket has been closed. E.g., due to the {@link Connection#close()} request of the 17 | * user, if the peer closed the connection, due to a fatal error during connect() 18 | * (also if the socket cannot be established) or if a fatal error occured on 19 | * an established connection. 20 | *

21 | * This is an experimental feature. 22 | *

23 | * You MUST NOT make any assumption about the thread that invokes this method. 24 | *

25 | * Please note: if the connection is not connected (e.g., there was no successful 26 | * connect() call), then the invocation of {@link Connection#close()} will NOT trigger 27 | * this method. 28 | * 29 | * @see Connection#addConnectionMonitor(ConnectionMonitor) 30 | * 31 | * @param reason Includes an indication why the socket was closed. 32 | */ 33 | public void connectionLost(Throwable reason); 34 | } -------------------------------------------------------------------------------- /src/com/trilead/ssh2/DebugLogger.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | /** 4 | * An interface which needs to be implemented if you 5 | * want to capture debugging messages. 6 | * 7 | * @see Connection#enableDebugging(boolean, DebugLogger) 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: DebugLogger.java,v 1.1 2008/03/03 07:01:36 cplattne Exp $ 11 | * @deprecated 12 | * Logging all goes to JDK java.util.logging 13 | */ 14 | public interface DebugLogger 15 | { 16 | 17 | /** 18 | * Log a debug message. 19 | * 20 | * @param level 0-99, 99 is a the most verbose level 21 | * @param className the class that generated the message 22 | * @param message the debug message 23 | */ 24 | public void log(int level, String className, String message); 25 | } 26 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/ExtendedServerHostKeyVerifier.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * This extends the {@link ServerHostKeyVerifier} interface by allowing the remote server to indicate it has multiple 7 | * server key algorithms available. After authentication, the {@link #getKnownKeyAlgorithmsForHost(String, int)} method 8 | * may be called and compared against the list of server-controller keys. If a key algorithm has been added then 9 | * {@link #addServerHostKey(String, int, String, byte[])} will be called. If a key algorithm has been removed, then 10 | * {@link #removeServerHostKey(String, int, String, byte[])} will be called. 11 | * 12 | * @author Kenny Root 13 | */ 14 | public abstract class ExtendedServerHostKeyVerifier implements ServerHostKeyVerifier { 15 | /** 16 | * Called during connection to determine which keys are known for this host. 17 | * 18 | * @param hostname the hostname used to create the {@link Connection} object 19 | * @param port the server's remote TCP port 20 | * @return list of hostkey algorithms for the given hostname and port combination 21 | * or {@code null} if none are known. 22 | */ 23 | public abstract List getKnownKeyAlgorithmsForHost(String hostname, int port); 24 | 25 | /** 26 | * After authentication, if the server indicates it no longer uses this key, this method will be called 27 | * for the app to remove its record of it. 28 | * 29 | * @param hostname the hostname used to create the {@link Connection} object 30 | * @param port the server's remote TCP port 31 | * @param serverHostKeyAlgorithm key algorithm of removed key 32 | * @param serverHostKey key data of removed key 33 | */ 34 | public abstract void removeServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, 35 | byte[] serverHostKey); 36 | 37 | /** 38 | * After authentication, if the server indicates it has another keyAlgorithm, this method will be 39 | * called for the app to add it to its record of known keys for this hostname. 40 | * 41 | * @param hostname the hostname used to create the {@link Connection} object 42 | * @param port the server's remote TCP port 43 | * @param keyAlgorithm SSH standard name for the key to be added 44 | * @param serverHostKey SSH encoding of the key data for the key to be added 45 | */ 46 | public abstract void addServerHostKey(String hostname, int port, String keyAlgorithm, byte[] serverHostKey); 47 | } 48 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/HTTPProxyException.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * May be thrown upon connect() if a HTTP proxy is being used. 8 | * 9 | * @see Connection#connect() 10 | * @see Connection#setProxyData(ProxyData) 11 | * 12 | * @author Christian Plattner, plattner@trilead.com 13 | * @version $Id: HTTPProxyException.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 14 | */ 15 | 16 | public class HTTPProxyException extends IOException 17 | { 18 | private static final long serialVersionUID = 2241537397104426186L; 19 | 20 | public final String httpResponse; 21 | public final int httpErrorCode; 22 | 23 | public HTTPProxyException(String httpResponse, int httpErrorCode) 24 | { 25 | super("HTTP Proxy Error (" + httpErrorCode + " " + httpResponse + ")"); 26 | this.httpResponse = httpResponse; 27 | this.httpErrorCode = httpErrorCode; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/IOWarningException.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author Thomas Singer 7 | */ 8 | public final class IOWarningException extends IOException { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | // Setup ================================================================== 13 | 14 | public IOWarningException(String message) { 15 | super(message); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/InteractiveCallback.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * An InteractiveCallback is used to respond to challenges sent 6 | * by the server if authentication mode "keyboard-interactive" is selected. 7 | * 8 | * @see Connection#authenticateWithKeyboardInteractive(String, 9 | * String[], InteractiveCallback) 10 | * 11 | * @author Christian Plattner, plattner@trilead.com 12 | * @version $Id: InteractiveCallback.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 13 | */ 14 | 15 | public interface InteractiveCallback 16 | { 17 | /** 18 | * This callback interface is used during a "keyboard-interactive" 19 | * authentication. Every time the server sends a set of challenges (however, 20 | * most often just one challenge at a time), this callback function will be 21 | * called to give your application a chance to talk to the user and to 22 | * determine the response(s). 23 | *

24 | * Some copy-paste information from the standard: a command line interface 25 | * (CLI) client SHOULD print the name and instruction (if non-empty), adding 26 | * newlines. Then for each prompt in turn, the client SHOULD display the 27 | * prompt and read the user input. The name and instruction fields MAY be 28 | * empty strings, the client MUST be prepared to handle this correctly. The 29 | * prompt field(s) MUST NOT be empty strings. 30 | *

31 | * Please refer to draft-ietf-secsh-auth-kbdinteract-XX.txt for the details. 32 | *

33 | * Note: clients SHOULD use control character filtering as discussed in 34 | * RFC4251 to avoid attacks by including 35 | * terminal control characters in the fields to be displayed. 36 | * 37 | * @param name 38 | * the name String sent by the server. 39 | * @param instruction 40 | * the instruction String sent by the server. 41 | * @param numPrompts 42 | * number of prompts - may be zero (in this case, you should just 43 | * return a String array of length zero). 44 | * @param prompt 45 | * an array (length numPrompts) of Strings 46 | * @param echo 47 | * an array (length numPrompts) of booleans. For 48 | * each prompt, the corresponding echo field indicates whether or 49 | * not the user input should be echoed as characters are typed. 50 | * @return an array of reponses - the array size must match the parameter 51 | * numPrompts. 52 | * @throws Exception exception 53 | */ 54 | public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) 55 | throws Exception; 56 | } 57 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/LocalPortForwarder.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | import java.io.IOException; 5 | import java.net.InetSocketAddress; 6 | 7 | import com.trilead.ssh2.channel.ChannelManager; 8 | import com.trilead.ssh2.channel.LocalAcceptThread; 9 | 10 | 11 | /** 12 | * A LocalPortForwarder forwards TCP/IP connections to a local 13 | * port via the secure tunnel to another host (which may or may not be identical 14 | * to the remote SSH-2 server). Checkout {@link Connection#createLocalPortForwarder(int, String, int)} 15 | * on how to create one. 16 | * 17 | * @author Christian Plattner, plattner@trilead.com 18 | * @version $Id: LocalPortForwarder.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 19 | */ 20 | public class LocalPortForwarder 21 | { 22 | ChannelManager cm; 23 | 24 | String host_to_connect; 25 | 26 | int port_to_connect; 27 | 28 | LocalAcceptThread lat; 29 | 30 | LocalPortForwarder(ChannelManager cm, int local_port, String host_to_connect, int port_to_connect) 31 | throws IOException 32 | { 33 | this.cm = cm; 34 | this.host_to_connect = host_to_connect; 35 | this.port_to_connect = port_to_connect; 36 | 37 | lat = new LocalAcceptThread(cm, local_port, host_to_connect, port_to_connect); 38 | lat.setDaemon(true); 39 | lat.start(); 40 | } 41 | 42 | LocalPortForwarder(ChannelManager cm, InetSocketAddress addr, String host_to_connect, int port_to_connect) 43 | throws IOException 44 | { 45 | this.cm = cm; 46 | this.host_to_connect = host_to_connect; 47 | this.port_to_connect = port_to_connect; 48 | 49 | lat = new LocalAcceptThread(cm, addr, host_to_connect, port_to_connect); 50 | lat.setDaemon(true); 51 | lat.start(); 52 | } 53 | 54 | /** 55 | * Stop TCP/IP forwarding of newly arriving connections. 56 | * 57 | * @throws IOException the io exception 58 | */ 59 | public void close() throws IOException 60 | { 61 | lat.stopWorking(); 62 | } 63 | 64 | public int getLocalPort() 65 | { 66 | return lat.getLocalPort(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/LocalStreamForwarder.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | import com.trilead.ssh2.channel.Channel; 9 | import com.trilead.ssh2.channel.ChannelManager; 10 | import com.trilead.ssh2.channel.LocalAcceptThread; 11 | 12 | 13 | /** 14 | * A LocalStreamForwarder forwards an Input- and Outputstream 15 | * pair via the secure tunnel to another host (which may or may not be identical 16 | * to the remote SSH-2 server). 17 | * 18 | * @author Christian Plattner, plattner@trilead.com 19 | * @version $Id: LocalStreamForwarder.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 20 | */ 21 | public class LocalStreamForwarder 22 | { 23 | ChannelManager cm; 24 | 25 | String host_to_connect; 26 | int port_to_connect; 27 | LocalAcceptThread lat; 28 | 29 | Channel cn; 30 | 31 | LocalStreamForwarder(ChannelManager cm, String host_to_connect, int port_to_connect) throws IOException 32 | { 33 | this.cm = cm; 34 | this.host_to_connect = host_to_connect; 35 | this.port_to_connect = port_to_connect; 36 | 37 | cn = cm.openDirectTCPIPChannel(host_to_connect, port_to_connect, "127.0.0.1", 0); 38 | } 39 | 40 | /** 41 | * @return An InputStream object. 42 | * @throws IOException the io exception 43 | */ 44 | public InputStream getInputStream() throws IOException 45 | { 46 | return cn.getStdoutStream(); 47 | } 48 | 49 | /** 50 | * Get the OutputStream. Please be aware that the implementation MAY use an 51 | * internal buffer. To make sure that the buffered data is sent over the 52 | * tunnel, you have to call the flush method of the 53 | * OutputStream. To signal EOF, please use the 54 | * close method of the OutputStream. 55 | * 56 | * @return An OutputStream object. 57 | * @throws IOException the io exception 58 | */ 59 | public OutputStream getOutputStream() throws IOException 60 | { 61 | return cn.getStdinStream(); 62 | } 63 | 64 | /** 65 | * Close the underlying SSH forwarding channel and free up resources. 66 | * You can also use this method to force the shutdown of the underlying 67 | * forwarding channel. Pending output (OutputStream not flushed) will NOT 68 | * be sent. Pending input (InputStream) can still be read. If the shutdown 69 | * operation is already in progress (initiated from either side), then this 70 | * call is a no-op. 71 | * 72 | * @throws IOException the io exception 73 | */ 74 | public void close() throws IOException 75 | { 76 | cm.closeChannel(cn, "Closed due to user request.", true); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/ProxyData.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * An abstract marker interface implemented by all proxy data implementations. 6 | * 7 | * @see HTTPProxyData 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: ProxyData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 11 | */ 12 | 13 | public abstract interface ProxyData 14 | { 15 | } 16 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/RandomFactory.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import java.security.NoSuchAlgorithmException; 4 | import java.security.SecureRandom; 5 | 6 | /** 7 | * Creates {@link SecureRandom} 8 | * 9 | * @author Kohsuke Kawaguchi 10 | */ 11 | public class RandomFactory { 12 | public static SecureRandom create() { 13 | try { 14 | // JENKINS-20108 15 | // on Unix, "new SecureRandom()" uses NativePRNG that uses a VM-wide lock, which results in 16 | // SecureRandom.nextInt() contention when there are lots of concurrent connections. 17 | // SHA1PRNG avoids this problem. This PRNG still gets seeded from (blocking) /dev/random, 18 | // which assures security. 19 | // 20 | // note that SHA1PRNG is not a standard. See http://security.stackexchange.com/questions/47871/ 21 | // 22 | // there's also http://coding.tocea.com/scertify-code/dont-use-the-sha1-prng-randomness-generator/ 23 | // which claims SHA1PRNG has "statistical defects" without details. I discount the credibility of 24 | // this claim based on the lack of details, and that this is not reported as a vulnerability upstream. 25 | return SecureRandom.getInstance("SHA1PRNG"); 26 | } catch (NoSuchAlgorithmException e) { 27 | // fall back 28 | return new SecureRandom(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/SFTPException.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | import java.io.IOException; 5 | 6 | import com.trilead.ssh2.sftp.ErrorCodes; 7 | 8 | 9 | /** 10 | * Used in combination with the SFTPv3Client. This exception wraps 11 | * error messages sent by the SFTP server. 12 | * 13 | * @author Christian Plattner, plattner@trilead.com 14 | * @version $Id: SFTPException.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 15 | */ 16 | 17 | public class SFTPException extends IOException 18 | { 19 | private static final long serialVersionUID = 578654644222421811L; 20 | 21 | private final String sftpErrorMessage; 22 | private final int sftpErrorCode; 23 | 24 | private static String constructMessage(String s, int errorCode) 25 | { 26 | String[] detail = ErrorCodes.getDescription(errorCode); 27 | 28 | if (detail == null) 29 | return s + " (UNKNOW SFTP ERROR CODE)"; 30 | 31 | return s + " (" + detail[0] + ": " + detail[1] + ")"; 32 | } 33 | 34 | SFTPException(String msg, int errorCode) 35 | { 36 | super(constructMessage(msg, errorCode)); 37 | sftpErrorMessage = msg; 38 | sftpErrorCode = errorCode; 39 | } 40 | 41 | /** 42 | * Get the error message sent by the server. Often, this 43 | * message does not help a lot (e.g., "failure"). 44 | * 45 | * @return the plain string as sent by the server. 46 | */ 47 | public String getServerErrorMessage() 48 | { 49 | return sftpErrorMessage; 50 | } 51 | 52 | /** 53 | * Get the error code sent by the server. 54 | * 55 | * @return an error code as defined in the SFTP specs. 56 | */ 57 | public int getServerErrorCode() 58 | { 59 | return sftpErrorCode; 60 | } 61 | 62 | /** 63 | * Get the symbolic name of the error code as given in the SFTP specs. 64 | * 65 | * @return e.g., "SSH_FX_INVALID_FILENAME". 66 | */ 67 | public String getServerErrorCodeSymbol() 68 | { 69 | String[] detail = ErrorCodes.getDescription(sftpErrorCode); 70 | 71 | if (detail == null) 72 | return "UNKNOW SFTP ERROR CODE " + sftpErrorCode; 73 | 74 | return detail[0]; 75 | } 76 | 77 | /** 78 | * Get the description of the error code as given in the SFTP specs. 79 | * 80 | * @return e.g., "The filename is not valid." 81 | */ 82 | public String getServerErrorCodeVerbose() 83 | { 84 | String[] detail = ErrorCodes.getDescription(sftpErrorCode); 85 | 86 | if (detail == null) 87 | return "The error code " + sftpErrorCode + " is unknown."; 88 | 89 | return detail[1]; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/SFTPv3DirectoryEntry.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * A SFTPv3DirectoryEntry as returned by {@link SFTPv3Client#ls(String)}. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: SFTPv3DirectoryEntry.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | 11 | public class SFTPv3DirectoryEntry 12 | { 13 | /** 14 | * A relative name within the directory, without any path components. 15 | */ 16 | public String filename; 17 | 18 | /** 19 | * An expanded format for the file name, similar to what is returned by 20 | * "ls -l" on Un*x systems. 21 | *

22 | * The format of this field is unspecified by the SFTP v3 protocol. 23 | * It MUST be suitable for use in the output of a directory listing 24 | * command (in fact, the recommended operation for a directory listing 25 | * command is to simply display this data). However, clients SHOULD NOT 26 | * attempt to parse the longname field for file attributes; they SHOULD 27 | * use the attrs field instead. 28 | *

29 | * The recommended format for the longname field is as follows:
30 | * -rwxr-xr-x 1 mjos staff 348911 Mar 25 14:29 t-filexfer 31 | */ 32 | public String longEntry; 33 | 34 | /** 35 | * The attributes of this entry. 36 | */ 37 | public SFTPv3FileAttributes attributes; 38 | } 39 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/SFTPv3FileHandle.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * A SFTPv3FileHandle. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: SFTPv3FileHandle.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | 11 | public class SFTPv3FileHandle 12 | { 13 | final SFTPv3Client client; 14 | final byte[] fileHandle; 15 | boolean isClosed = false; 16 | 17 | /* The constructor is NOT public */ 18 | 19 | SFTPv3FileHandle(SFTPv3Client client, byte[] h) 20 | { 21 | this.client = client; 22 | this.fileHandle = h; 23 | } 24 | 25 | /** 26 | * Get the SFTPv3Client instance which created this handle. 27 | * 28 | * @return A SFTPv3Client instance. 29 | */ 30 | public SFTPv3Client getClient() 31 | { 32 | return client; 33 | } 34 | 35 | /** 36 | * Check if this handle was closed with the {@link SFTPv3Client#closeFile(SFTPv3FileHandle)} method 37 | * of the SFTPv3Client instance which created the handle. 38 | * 39 | * @return if the handle is closed. 40 | */ 41 | public boolean isClosed() 42 | { 43 | return isClosed; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/ServerHostKeyVerifier.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2; 3 | 4 | /** 5 | * A callback interface used to implement a client specific method of checking 6 | * server host keys. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: ServerHostKeyVerifier.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 10 | */ 11 | 12 | public interface ServerHostKeyVerifier 13 | { 14 | /** 15 | * The actual verifier method, it will be called by the key exchange code 16 | * on EVERY key exchange - this can happen several times during the lifetime 17 | * of a connection. 18 | *

19 | * Note: SSH-2 servers are allowed to change their hostkey at ANY time. 20 | * 21 | * @param hostname the hostname used to create the {@link Connection} object 22 | * @param port the remote TCP port 23 | * @param serverHostKeyAlgorithm the public key algorithm 24 | * @param serverHostKey the server's public key blob 25 | * @return if the client wants to accept the server's host key - if not, the 26 | * connection will be closed. 27 | * @throws Exception Will be wrapped with an IOException, extended version of returning false =) 28 | */ 29 | public boolean verifyServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey) 30 | throws Exception; 31 | } 32 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/auth/AgentIdentity.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.auth; 2 | 3 | public interface AgentIdentity { 4 | public String getAlgName(); 5 | public byte[] getPublicKeyBlob(); 6 | public byte[] sign(byte[] data); 7 | } 8 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/auth/AgentProxy.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.auth; 2 | 3 | import java.util.Collection; 4 | 5 | public interface AgentProxy { 6 | public Collection/**/ getIdentities(); 7 | } 8 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/channel/ChannelInputStream.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | /** 8 | * ChannelInputStream. 9 | * 10 | * @author Christian Plattner, plattner@trilead.com 11 | * @version $Id: ChannelInputStream.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 12 | */ 13 | public final class ChannelInputStream extends InputStream 14 | { 15 | Channel c; 16 | 17 | boolean isClosed = false; 18 | boolean isEOF = false; 19 | boolean extendedFlag = false; 20 | 21 | ChannelInputStream(Channel c, boolean isExtended) 22 | { 23 | this.c = c; 24 | this.extendedFlag = isExtended; 25 | } 26 | 27 | public int available() throws IOException 28 | { 29 | if (isEOF) 30 | return 0; 31 | 32 | int avail = c.cm.getAvailable(c, extendedFlag); 33 | 34 | /* We must not return -1 on EOF */ 35 | 36 | return (avail > 0) ? avail : 0; 37 | } 38 | 39 | public void close() throws IOException 40 | { 41 | isClosed = true; 42 | } 43 | 44 | public int read(byte[] b, int off, int len) throws IOException 45 | { 46 | if (b == null) 47 | throw new NullPointerException(); 48 | 49 | if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length)) 50 | throw new IndexOutOfBoundsException(); 51 | 52 | if (len == 0) 53 | return 0; 54 | 55 | if (isEOF) 56 | return -1; 57 | 58 | int ret = c.cm.getChannelData(c, extendedFlag, b, off, len); 59 | 60 | if (ret == -1) 61 | { 62 | isEOF = true; 63 | } 64 | 65 | return ret; 66 | } 67 | 68 | public int read(byte[] b) throws IOException 69 | { 70 | return read(b, 0, b.length); 71 | } 72 | 73 | public int read() throws IOException 74 | { 75 | /* Yes, this stream is pure and unbuffered, a single byte read() is slow */ 76 | 77 | final byte b[] = new byte[1]; 78 | 79 | int ret = read(b, 0, 1); 80 | 81 | if (ret != 1) 82 | return -1; 83 | 84 | return b[0] & 0xff; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/channel/ChannelOutputStream.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.channel; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | /** 7 | * ChannelOutputStream. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: ChannelOutputStream.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 11 | */ 12 | public final class ChannelOutputStream extends OutputStream 13 | { 14 | Channel c; 15 | 16 | boolean isClosed = false; 17 | 18 | ChannelOutputStream(Channel c) 19 | { 20 | this.c = c; 21 | } 22 | 23 | public void write(int b) throws IOException 24 | { 25 | byte[] buff = new byte[1]; 26 | 27 | buff[0] = (byte) b; 28 | 29 | write(buff, 0, 1); 30 | } 31 | 32 | public void close() throws IOException 33 | { 34 | if (isClosed == false) 35 | { 36 | isClosed = true; 37 | c.cm.sendEOF(c); 38 | } 39 | } 40 | 41 | public void flush() throws IOException 42 | { 43 | if (isClosed) 44 | throw new IOException("This OutputStream is closed."); 45 | 46 | /* This is a no-op, since this stream is unbuffered */ 47 | } 48 | 49 | public void write(byte[] b, int off, int len) throws IOException 50 | { 51 | if (isClosed) 52 | throw new IOException("This OutputStream is closed."); 53 | 54 | if (b == null) 55 | throw new NullPointerException(); 56 | 57 | if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length)) 58 | throw new IndexOutOfBoundsException(); 59 | 60 | if (len == 0) 61 | return; 62 | 63 | c.cm.sendData(c, b, off, len); 64 | } 65 | 66 | public void write(byte[] b) throws IOException 67 | { 68 | write(b, 0, b.length); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/channel/IChannelWorkerThread.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | /** 5 | * IChannelWorkerThread. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: IChannelWorkerThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | interface IChannelWorkerThread 11 | { 12 | public void stopWorking(); 13 | } 14 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/channel/RemoteAcceptThread.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | import java.io.IOException; 5 | import java.io.InterruptedIOException; 6 | import java.net.Socket; 7 | 8 | import com.trilead.ssh2.log.Logger; 9 | 10 | 11 | /** 12 | * RemoteAcceptThread. 13 | * 14 | * @author Christian Plattner, plattner@trilead.com 15 | * @version $Id: RemoteAcceptThread.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 16 | */ 17 | public class RemoteAcceptThread extends Thread 18 | { 19 | private static final Logger log = Logger.getLogger(RemoteAcceptThread.class); 20 | 21 | Channel c; 22 | 23 | String remoteConnectedAddress; 24 | int remoteConnectedPort; 25 | String remoteOriginatorAddress; 26 | int remoteOriginatorPort; 27 | String targetAddress; 28 | int targetPort; 29 | 30 | Socket s; 31 | 32 | public RemoteAcceptThread(Channel c, String remoteConnectedAddress, int remoteConnectedPort, 33 | String remoteOriginatorAddress, int remoteOriginatorPort, String targetAddress, int targetPort) 34 | { 35 | this.c = c; 36 | this.remoteConnectedAddress = remoteConnectedAddress; 37 | this.remoteConnectedPort = remoteConnectedPort; 38 | this.remoteOriginatorAddress = remoteOriginatorAddress; 39 | this.remoteOriginatorPort = remoteOriginatorPort; 40 | this.targetAddress = targetAddress; 41 | this.targetPort = targetPort; 42 | 43 | if (log.isEnabled()) 44 | log.log(30, "RemoteAcceptThread: " + remoteConnectedAddress + "/" + remoteConnectedPort + ", R: " 45 | + remoteOriginatorAddress + "/" + remoteOriginatorPort); 46 | } 47 | 48 | public void run() 49 | { 50 | try 51 | { 52 | c.cm.sendOpenConfirmation(c); 53 | 54 | s = new Socket(targetAddress, targetPort); 55 | 56 | StreamForwarder r2l = new StreamForwarder(c, null, null, c.getStdoutStream(), s.getOutputStream(), 57 | "RemoteToLocal"); 58 | StreamForwarder l2r = new StreamForwarder(c, null, null, s.getInputStream(), c.getStdinStream(), 59 | "LocalToRemote"); 60 | 61 | /* No need to start two threads, one can be executed in the current thread */ 62 | 63 | r2l.setDaemon(true); 64 | r2l.start(); 65 | l2r.run(); 66 | 67 | while (r2l.isAlive()) 68 | { 69 | try 70 | { 71 | r2l.join(); 72 | } 73 | catch (InterruptedException e) 74 | { 75 | throw new InterruptedIOException(); 76 | } 77 | } 78 | 79 | /* If the channel is already closed, then this is a no-op */ 80 | 81 | c.cm.closeChannel(c, "EOF on both streams reached.", true); 82 | s.close(); 83 | } 84 | catch (IOException e) 85 | { 86 | log.log(50, "IOException in proxy code",e); 87 | 88 | try 89 | { 90 | c.cm.closeChannel(c, "IOException in proxy code (" + e.getMessage() + ")", true); 91 | } 92 | catch (IOException e1) 93 | { 94 | } 95 | try 96 | { 97 | if (s != null) 98 | s.close(); 99 | } 100 | catch (IOException e1) 101 | { 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/channel/RemoteForwardingData.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | /** 5 | * RemoteForwardingData. Data about a requested remote forwarding. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: RemoteForwardingData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | */ 10 | public class RemoteForwardingData 11 | { 12 | public String bindAddress; 13 | public int bindPort; 14 | 15 | String targetAddress; 16 | int targetPort; 17 | } 18 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/channel/StreamForwarder.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.channel; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.net.Socket; 7 | 8 | /** 9 | * A StreamForwarder forwards data between two given streams. 10 | * If two StreamForwarder threads are used (one for each direction) 11 | * then one can be configured to shutdown the underlying channel/socket 12 | * if both threads have finished forwarding (EOF). 13 | * 14 | * @author Christian Plattner, plattner@trilead.com 15 | * @version $Id: StreamForwarder.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 16 | */ 17 | public class StreamForwarder extends Thread 18 | { 19 | OutputStream os; 20 | InputStream is; 21 | byte[] buffer; 22 | Channel c; 23 | StreamForwarder sibling; 24 | Socket s; 25 | String mode; 26 | 27 | StreamForwarder(Channel c, StreamForwarder sibling, Socket s, InputStream is, OutputStream os, String mode) 28 | throws IOException 29 | { 30 | this.is = is; 31 | this.os = os; 32 | this.mode = mode; 33 | this.c = c; 34 | this.sibling = sibling; 35 | this.s = s; 36 | // window size is for the other side of the network with some latency. 37 | // we don't need such a big buffer for a copy stream tight loop 38 | this.buffer = new byte[8192/*c.channelBufferSize*/]; 39 | } 40 | 41 | public void run() 42 | { 43 | try 44 | { 45 | while (true) 46 | { 47 | int len = is.read(buffer); 48 | if (len <= 0) 49 | break; 50 | os.write(buffer, 0, len); 51 | os.flush(); 52 | } 53 | } 54 | catch (IOException ignore) 55 | { 56 | try 57 | { 58 | c.cm.closeChannel(c, "Closed due to exception in StreamForwarder (" + mode + "): " 59 | + ignore.getMessage(), true); 60 | } 61 | catch (IOException e) 62 | { 63 | } 64 | } 65 | finally 66 | { 67 | try 68 | { 69 | os.close(); 70 | } 71 | catch (IOException e1) 72 | { 73 | } 74 | try 75 | { 76 | is.close(); 77 | } 78 | catch (IOException e2) 79 | { 80 | } 81 | 82 | if (sibling != null) 83 | { 84 | while (sibling.isAlive()) 85 | { 86 | try 87 | { 88 | sibling.join(); 89 | } 90 | catch (InterruptedException e) 91 | { 92 | } 93 | } 94 | 95 | try 96 | { 97 | c.cm.closeChannel(c, "StreamForwarder (" + mode + ") is cleaning up the connection", true); 98 | } 99 | catch (IOException e3) 100 | { 101 | } 102 | 103 | try 104 | { 105 | if (s != null) 106 | s.close(); 107 | } 108 | catch (IOException e1) 109 | { 110 | } 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/channel/X11ServerData.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.channel; 3 | 4 | /** 5 | * X11ServerData. Data regarding an x11 forwarding target. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: X11ServerData.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 9 | * 10 | */ 11 | public class X11ServerData 12 | { 13 | public String hostname; 14 | public int port; 15 | public byte[] x11_magic_cookie; /* not the remote (fake) one, the local (real) one */ 16 | } 17 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/CertificateDecoder.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto; 2 | 3 | import java.io.IOException; 4 | import java.security.KeyPair; 5 | 6 | /** 7 | * @author Michael Clarke 8 | */ 9 | public abstract class CertificateDecoder { 10 | 11 | public abstract String getStartLine(); 12 | 13 | public abstract String getEndLine(); 14 | 15 | public KeyPair createKeyPair(PEMStructure pemStructure, String password) throws IOException { 16 | return createKeyPair(pemStructure); 17 | } 18 | 19 | protected abstract KeyPair createKeyPair(PEMStructure pemStructure) throws IOException; 20 | } 21 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/CryptoWishList.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto; 3 | 4 | import com.trilead.ssh2.crypto.cipher.BlockCipherFactory; 5 | import com.trilead.ssh2.crypto.digest.MessageMac; 6 | import com.trilead.ssh2.jenkins.FilterEncrytionAlgorithms; 7 | import com.trilead.ssh2.jenkins.FilterHostKeyAlgorithms; 8 | import com.trilead.ssh2.jenkins.FilterKexAlgorithms; 9 | import com.trilead.ssh2.jenkins.FilterMacAlgorithms; 10 | import com.trilead.ssh2.transport.KexManager; 11 | 12 | 13 | /** 14 | * CryptoWishList. 15 | * 16 | * @author Christian Plattner, plattner@trilead.com 17 | * @version $Id: CryptoWishList.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 18 | */ 19 | public class CryptoWishList 20 | { 21 | public String[] kexAlgorithms = FilterKexAlgorithms.filter(KexManager.getDefaultKexAlgorithmList()); 22 | public String[] serverHostKeyAlgorithms = FilterHostKeyAlgorithms.filter(KexManager.getDefaultServerHostkeyAlgorithmList()); 23 | public String[] c2s_enc_algos = FilterEncrytionAlgorithms.filter(BlockCipherFactory.getDefaultCipherList()); 24 | public String[] s2c_enc_algos = FilterEncrytionAlgorithms.filter(BlockCipherFactory.getDefaultCipherList()); 25 | public String[] c2s_mac_algos = FilterMacAlgorithms.filter(MessageMac.getMacs()); 26 | public String[] s2c_mac_algos = FilterMacAlgorithms.filter(MessageMac.getMacs()); 27 | } -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/KeyMaterial.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto; 3 | 4 | 5 | import java.math.BigInteger; 6 | 7 | import com.trilead.ssh2.crypto.digest.HashForSSH2Types; 8 | 9 | /** 10 | * Establishes key material for iv/key/mac (both directions). 11 | * 12 | * @author Christian Plattner, plattner@trilead.com 13 | * @version $Id: KeyMaterial.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 14 | */ 15 | public class KeyMaterial 16 | { 17 | public byte[] initial_iv_client_to_server; 18 | public byte[] initial_iv_server_to_client; 19 | public byte[] enc_key_client_to_server; 20 | public byte[] enc_key_server_to_client; 21 | public byte[] integrity_key_client_to_server; 22 | public byte[] integrity_key_server_to_client; 23 | 24 | private static byte[] calculateKey(HashForSSH2Types sh, BigInteger K, byte[] H, byte type, byte[] SessionID, 25 | int keyLength) 26 | { 27 | byte[] res = new byte[keyLength]; 28 | 29 | int dglen = sh.getDigestLength(); 30 | int numRounds = (keyLength + dglen - 1) / dglen; 31 | 32 | byte[][] tmp = new byte[numRounds][]; 33 | 34 | sh.reset(); 35 | sh.updateBigInt(K); 36 | sh.updateBytes(H); 37 | sh.updateByte(type); 38 | sh.updateBytes(SessionID); 39 | 40 | tmp[0] = sh.getDigest(); 41 | 42 | int off = 0; 43 | int produced = Math.min(dglen, keyLength); 44 | 45 | System.arraycopy(tmp[0], 0, res, off, produced); 46 | 47 | keyLength -= produced; 48 | off += produced; 49 | 50 | for (int i = 1; i < numRounds; i++) 51 | { 52 | sh.updateBigInt(K); 53 | sh.updateBytes(H); 54 | 55 | for (int j = 0; j < i; j++) 56 | sh.updateBytes(tmp[j]); 57 | 58 | tmp[i] = sh.getDigest(); 59 | 60 | produced = Math.min(dglen, keyLength); 61 | System.arraycopy(tmp[i], 0, res, off, produced); 62 | keyLength -= produced; 63 | off += produced; 64 | } 65 | 66 | return res; 67 | } 68 | 69 | public static KeyMaterial create(String hashType, byte[] H, BigInteger K, byte[] SessionID, int keyLengthCS, 70 | int blockSizeCS, int macLengthCS, int keyLengthSC, int blockSizeSC, int macLengthSC) 71 | throws IllegalArgumentException 72 | { 73 | KeyMaterial km = new KeyMaterial(); 74 | 75 | HashForSSH2Types sh = new HashForSSH2Types(hashType); 76 | 77 | km.initial_iv_client_to_server = calculateKey(sh, K, H, (byte) 'A', SessionID, blockSizeCS); 78 | 79 | km.initial_iv_server_to_client = calculateKey(sh, K, H, (byte) 'B', SessionID, blockSizeSC); 80 | 81 | km.enc_key_client_to_server = calculateKey(sh, K, H, (byte) 'C', SessionID, keyLengthCS); 82 | 83 | km.enc_key_server_to_client = calculateKey(sh, K, H, (byte) 'D', SessionID, keyLengthSC); 84 | 85 | km.integrity_key_client_to_server = calculateKey(sh, K, H, (byte) 'E', SessionID, macLengthCS); 86 | 87 | km.integrity_key_server_to_client = calculateKey(sh, K, H, (byte) 'F', SessionID, macLengthSC); 88 | 89 | return km; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/PEMStructure.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto; 3 | 4 | import java.util.Arrays; 5 | import java.util.Objects; 6 | 7 | /** 8 | * Parsed PEM structure. 9 | * 10 | * @author Christian Plattner, plattner@trilead.com 11 | * @version $Id: PEMStructure.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 12 | */ 13 | 14 | public class PEMStructure 15 | { 16 | int pemType; 17 | String[] dekInfo; 18 | String procType[]; 19 | byte[] data; 20 | 21 | public byte[] getData() { 22 | return data; 23 | } 24 | 25 | @Override 26 | public boolean equals(Object o) { 27 | if (this == o) 28 | return true; 29 | if (o == null || getClass() != o.getClass()) 30 | return false; 31 | PEMStructure that = (PEMStructure) o; 32 | return pemType == that.pemType 33 | && Arrays.equals(dekInfo, that.dekInfo) 34 | && Arrays.equals(procType, that.procType) 35 | && Arrays.equals(data, that.data); 36 | } 37 | 38 | @Override 39 | public int hashCode() { 40 | int result = Objects.hash(pemType); 41 | result = 31 * result + Arrays.hashCode(dekInfo); 42 | result = 31 * result + Arrays.hashCode(procType); 43 | result = 31 * result + Arrays.hashCode(data); 44 | return result; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | final StringBuilder sb = new StringBuilder("PEMStructure{"); 50 | sb.append("pemType=").append(pemType); 51 | sb.append(", dekInfo=").append(Arrays.toString(dekInfo)); 52 | sb.append(", procType=").append(Arrays.toString(procType)); 53 | sb.append(", data=").append(java.util.Base64.getEncoder().encodeToString(data)); 54 | sb.append(", data.length=").append(data.length); 55 | sb.append('}'); 56 | return sb.toString(); 57 | } 58 | } -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/cipher/BlockCipher.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.cipher; 2 | 3 | /** 4 | * BlockCipher. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: BlockCipher.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 8 | */ 9 | public interface BlockCipher 10 | { 11 | public void init(boolean forEncryption, byte[] key); 12 | 13 | public int getBlockSize(); 14 | 15 | public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff); 16 | } 17 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/cipher/CBCMode.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.cipher; 2 | 3 | /** 4 | * CBCMode. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: CBCMode.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 8 | */ 9 | public class CBCMode implements BlockCipher 10 | { 11 | BlockCipher tc; 12 | int blockSize; 13 | boolean doEncrypt; 14 | 15 | byte[] cbc_vector; 16 | byte[] tmp_vector; 17 | 18 | public void init(boolean forEncryption, byte[] key) 19 | { 20 | } 21 | 22 | public CBCMode(BlockCipher tc, byte[] iv, boolean doEncrypt) 23 | throws IllegalArgumentException 24 | { 25 | this.tc = tc; 26 | this.blockSize = tc.getBlockSize(); 27 | this.doEncrypt = doEncrypt; 28 | 29 | if (this.blockSize != iv.length) 30 | throw new IllegalArgumentException("IV must be " + blockSize 31 | + " bytes long! (currently " + iv.length + ")"); 32 | 33 | this.cbc_vector = new byte[blockSize]; 34 | this.tmp_vector = new byte[blockSize]; 35 | System.arraycopy(iv, 0, cbc_vector, 0, blockSize); 36 | } 37 | 38 | public int getBlockSize() 39 | { 40 | return blockSize; 41 | } 42 | 43 | private void encryptBlock(byte[] src, int srcoff, byte[] dst, int dstoff) 44 | { 45 | for (int i = 0; i < blockSize; i++) 46 | cbc_vector[i] ^= src[srcoff + i]; 47 | 48 | tc.transformBlock(cbc_vector, 0, dst, dstoff); 49 | 50 | System.arraycopy(dst, dstoff, cbc_vector, 0, blockSize); 51 | } 52 | 53 | private void decryptBlock(byte[] src, int srcoff, byte[] dst, int dstoff) 54 | { 55 | /* Assume the worst, src and dst are overlapping... */ 56 | 57 | System.arraycopy(src, srcoff, tmp_vector, 0, blockSize); 58 | 59 | tc.transformBlock(src, srcoff, dst, dstoff); 60 | 61 | for (int i = 0; i < blockSize; i++) 62 | dst[dstoff + i] ^= cbc_vector[i]; 63 | 64 | /* ...that is why we need a tmp buffer. */ 65 | 66 | byte[] swap = cbc_vector; 67 | cbc_vector = tmp_vector; 68 | tmp_vector = swap; 69 | } 70 | 71 | public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) 72 | { 73 | if (doEncrypt) 74 | encryptBlock(src, srcoff, dst, dstoff); 75 | else 76 | decryptBlock(src, srcoff, dst, dstoff); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/cipher/CTRMode.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.cipher; 3 | 4 | /** 5 | * This is CTR mode as described in draft-ietf-secsh-newmodes-XY.txt 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: CTRMode.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class CTRMode implements BlockCipher 11 | { 12 | byte[] X; 13 | byte[] Xenc; 14 | 15 | BlockCipher bc; 16 | int blockSize; 17 | boolean doEncrypt; 18 | 19 | int count = 0; 20 | 21 | public void init(boolean forEncryption, byte[] key) 22 | { 23 | } 24 | 25 | public CTRMode(BlockCipher tc, byte[] iv, boolean doEnc) throws IllegalArgumentException 26 | { 27 | bc = tc; 28 | blockSize = bc.getBlockSize(); 29 | doEncrypt = doEnc; 30 | 31 | if (blockSize != iv.length) 32 | throw new IllegalArgumentException("IV must be " + blockSize + " bytes long! (currently " + iv.length + ")"); 33 | 34 | X = new byte[blockSize]; 35 | Xenc = new byte[blockSize]; 36 | 37 | System.arraycopy(iv, 0, X, 0, blockSize); 38 | } 39 | 40 | public final int getBlockSize() 41 | { 42 | return blockSize; 43 | } 44 | 45 | public final void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) 46 | { 47 | bc.transformBlock(X, 0, Xenc, 0); 48 | 49 | for (int i = 0; i < blockSize; i++) 50 | { 51 | dst[dstoff + i] = (byte) (src[srcoff + i] ^ Xenc[i]); 52 | } 53 | 54 | for (int i = (blockSize - 1); i >= 0; i--) 55 | { 56 | X[i]++; 57 | if (X[i] != 0) 58 | break; 59 | 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/cipher/NullCipher.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.cipher; 2 | 3 | /** 4 | * NullCipher. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: NullCipher.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 8 | */ 9 | public class NullCipher implements BlockCipher 10 | { 11 | private int blockSize = 8; 12 | 13 | public NullCipher() 14 | { 15 | } 16 | 17 | public NullCipher(int blockSize) 18 | { 19 | this.blockSize = blockSize; 20 | } 21 | 22 | public void init(boolean forEncryption, byte[] key) 23 | { 24 | } 25 | 26 | public int getBlockSize() 27 | { 28 | return blockSize; 29 | } 30 | 31 | public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) 32 | { 33 | System.arraycopy(src, srcoff, dst, dstoff, blockSize); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/dh/Curve25519Exchange.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.dh; 2 | 3 | import com.google.crypto.tink.subtle.X25519; 4 | 5 | import java.io.IOException; 6 | import java.math.BigInteger; 7 | import java.security.InvalidKeyException; 8 | 9 | /** 10 | * Created by Kenny Root on 1/23/16. 11 | */ 12 | public class Curve25519Exchange extends GenericDhExchange { 13 | public static final String NAME = "curve25519-sha256"; 14 | public static final String ALT_NAME = "curve25519-sha256@libssh.org"; 15 | public static final int KEY_SIZE = 32; 16 | 17 | private byte[] clientPublic; 18 | private byte[] clientPrivate; 19 | private byte[] serverPublic; 20 | 21 | public Curve25519Exchange() { 22 | super(); 23 | } 24 | 25 | /* 26 | * Used to test known vectors. 27 | */ 28 | public Curve25519Exchange(byte[] secret) throws InvalidKeyException { 29 | if (secret.length != KEY_SIZE) { 30 | throw new AssertionError("secret must be key size"); 31 | } 32 | clientPrivate = secret.clone(); 33 | } 34 | 35 | @Override 36 | public void init(String name) throws IOException { 37 | if (!NAME.equals(name) && !ALT_NAME.equals(name)) { 38 | throw new IOException("Invalid name " + name); 39 | } 40 | 41 | clientPrivate = X25519.generatePrivateKey(); 42 | try { 43 | clientPublic = X25519.publicFromPrivate(clientPrivate); 44 | } catch (InvalidKeyException e) { 45 | throw new IOException(e); 46 | } 47 | } 48 | 49 | @Override 50 | public byte[] getE() { 51 | return clientPublic.clone(); 52 | } 53 | 54 | @Override 55 | protected byte[] getServerE() { 56 | return serverPublic.clone(); 57 | } 58 | 59 | @Override 60 | public void setF(byte[] f) throws IOException { 61 | if (f.length != KEY_SIZE) { 62 | throw new IOException("Server sent invalid key length " + f.length + " (expected " + 63 | KEY_SIZE + ")"); 64 | } 65 | serverPublic = f.clone(); 66 | try { 67 | byte[] sharedSecretBytes = X25519.computeSharedSecret(clientPrivate, serverPublic); 68 | int allBytes = 0; 69 | for (int i = 0; i < sharedSecretBytes.length; i++) { 70 | allBytes |= sharedSecretBytes[i]; 71 | } 72 | if (allBytes == 0) { 73 | throw new IOException("Invalid key computed; all zeroes"); 74 | } 75 | sharedSecret = new BigInteger(1, sharedSecretBytes); 76 | } catch (InvalidKeyException e) { 77 | throw new IOException(e); 78 | } 79 | } 80 | 81 | @Override 82 | public String getHashAlgo() { 83 | return "SHA-256"; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/dh/DhGroupExchange.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.dh; 3 | 4 | import java.math.BigInteger; 5 | import java.security.SecureRandom; 6 | 7 | import com.trilead.ssh2.DHGexParameters; 8 | import com.trilead.ssh2.crypto.digest.HashForSSH2Types; 9 | 10 | 11 | /** 12 | * DhGroupExchange. 13 | * 14 | * @author Christian Plattner, plattner@trilead.com 15 | * @version $Id: DhGroupExchange.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 16 | */ 17 | public class DhGroupExchange 18 | { 19 | /* Given by the standard */ 20 | 21 | private BigInteger p; 22 | private BigInteger g; 23 | 24 | /* Client public and private */ 25 | 26 | private BigInteger e; 27 | private BigInteger x; 28 | 29 | /* Server public */ 30 | 31 | private BigInteger f; 32 | 33 | /* Shared secret */ 34 | 35 | private BigInteger k; 36 | 37 | public DhGroupExchange(BigInteger p, BigInteger g) 38 | { 39 | this.p = p; 40 | this.g = g; 41 | } 42 | 43 | public void init(SecureRandom rnd) 44 | { 45 | k = null; 46 | 47 | x = new BigInteger(p.bitLength() - 1, rnd); 48 | e = g.modPow(x, p); 49 | } 50 | 51 | /** 52 | * @return Returns the e. 53 | */ 54 | public BigInteger getE() 55 | { 56 | if (e == null) 57 | throw new IllegalStateException("Not initialized!"); 58 | 59 | return e; 60 | } 61 | 62 | /** 63 | * @return Returns the shared secret k. 64 | */ 65 | public BigInteger getK() 66 | { 67 | if (k == null) 68 | throw new IllegalStateException("Shared secret not yet known, need f first!"); 69 | 70 | return k; 71 | } 72 | 73 | /** 74 | * Sets f and calculates the shared secret. 75 | * @param f f. 76 | */ 77 | public void setF(BigInteger f) 78 | { 79 | if (e == null) 80 | throw new IllegalStateException("Not initialized!"); 81 | 82 | BigInteger zero = BigInteger.valueOf(0); 83 | 84 | if (zero.compareTo(f) >= 0 || p.compareTo(f) <= 0) 85 | throw new IllegalArgumentException("Invalid f specified!"); 86 | 87 | this.f = f; 88 | this.k = f.modPow(x, p); 89 | } 90 | 91 | public byte[] calculateH(String hashAlgo, byte[] clientversion, byte[] serverversion, 92 | byte[] clientKexPayload, byte[] serverKexPayload, byte[] hostKey, DHGexParameters para) 93 | { 94 | HashForSSH2Types hash = new HashForSSH2Types(hashAlgo); 95 | 96 | hash.updateByteString(clientversion); 97 | hash.updateByteString(serverversion); 98 | hash.updateByteString(clientKexPayload); 99 | hash.updateByteString(serverKexPayload); 100 | hash.updateByteString(hostKey); 101 | if (para.getMin_group_len() > 0) 102 | hash.updateUINT32(para.getMin_group_len()); 103 | hash.updateUINT32(para.getPref_group_len()); 104 | if (para.getMax_group_len() > 0) 105 | hash.updateUINT32(para.getMax_group_len()); 106 | hash.updateBigInt(p); 107 | hash.updateBigInt(g); 108 | hash.updateBigInt(e); 109 | hash.updateBigInt(f); 110 | hash.updateBigInt(k); 111 | 112 | return hash.getDigest(); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/dh/GenericDhExchange.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.dh; 3 | 4 | import java.io.IOException; 5 | import java.io.UnsupportedEncodingException; 6 | import java.math.BigInteger; 7 | import java.security.SecureRandom; 8 | 9 | import com.trilead.ssh2.crypto.digest.HashForSSH2Types; 10 | import com.trilead.ssh2.log.Logger; 11 | 12 | 13 | /** 14 | * DhExchange. 15 | * 16 | * @author Christian Plattner, plattner@trilead.com 17 | * @version $Id: DhExchange.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ 18 | */ 19 | public abstract class GenericDhExchange 20 | { 21 | private static final Logger log = Logger.getLogger(GenericDhExchange.class); 22 | 23 | /* Shared secret */ 24 | 25 | BigInteger sharedSecret; 26 | 27 | protected GenericDhExchange() 28 | { 29 | } 30 | 31 | public static GenericDhExchange getInstance(String algo) { 32 | if (Curve25519Exchange.NAME.equals(algo) || Curve25519Exchange.ALT_NAME.equals(algo)) { 33 | return new Curve25519Exchange(); 34 | } 35 | if (algo.startsWith("ecdh-sha2-")) { 36 | return new EcDhExchange(); 37 | } else { 38 | return new DhExchange(); 39 | } 40 | } 41 | 42 | public abstract void init(String name) throws IOException; 43 | 44 | /** 45 | * @return Returns the e (public value) 46 | * @throws IllegalStateException 47 | */ 48 | public abstract byte[] getE(); 49 | 50 | /** 51 | * @return Returns the server's e (public value) 52 | * @throws IllegalStateException 53 | */ 54 | protected abstract byte[] getServerE(); 55 | 56 | /** 57 | * @return Returns the shared secret k. 58 | * @throws IllegalStateException 59 | */ 60 | public BigInteger getK() 61 | { 62 | if (sharedSecret == null) 63 | throw new IllegalStateException("Shared secret not yet known, need f first!"); 64 | 65 | return sharedSecret; 66 | } 67 | 68 | /** 69 | * @param f 70 | */ 71 | public abstract void setF(byte[] f) throws IOException; 72 | 73 | public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload, 74 | byte[] serverKexPayload, byte[] hostKey) throws UnsupportedEncodingException 75 | { 76 | HashForSSH2Types hash = new HashForSSH2Types(getHashAlgo()); 77 | 78 | if (log.isEnabled()) 79 | { 80 | log.log(90, "Client: '" + new String(clientversion) + "'"); 81 | log.log(90, "Server: '" + new String(serverversion) + "'"); 82 | } 83 | 84 | hash.updateByteString(clientversion); 85 | hash.updateByteString(serverversion); 86 | hash.updateByteString(clientKexPayload); 87 | hash.updateByteString(serverKexPayload); 88 | hash.updateByteString(hostKey); 89 | hash.updateByteString(getE()); 90 | hash.updateByteString(getServerE()); 91 | hash.updateBigInt(sharedSecret); 92 | 93 | return hash.getDigest(); 94 | } 95 | 96 | public abstract String getHashAlgo(); 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/digest/Digest.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.digest; 3 | 4 | /** 5 | * Digest. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: Digest.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 9 | */ 10 | public interface Digest 11 | { 12 | public int getDigestLength(); 13 | 14 | public void update(byte b); 15 | 16 | public void update(byte[] b); 17 | 18 | public void update(byte b[], int off, int len); 19 | 20 | public void reset(); 21 | 22 | public void digest(byte[] out); 23 | 24 | public void digest(byte[] out, int off); 25 | } 26 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/digest/HMAC.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.digest; 3 | 4 | /** 5 | * HMAC. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: HMAC.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 9 | */ 10 | @Deprecated 11 | public final class HMAC implements Digest 12 | { 13 | Digest md; 14 | byte[] k_xor_ipad; 15 | byte[] k_xor_opad; 16 | 17 | byte[] tmp; 18 | 19 | int size; 20 | 21 | public HMAC(Digest md, byte[] key, int size) 22 | { 23 | this.md = md; 24 | this.size = size; 25 | 26 | tmp = new byte[md.getDigestLength()]; 27 | 28 | final int BLOCKSIZE = 64; 29 | 30 | k_xor_ipad = new byte[BLOCKSIZE]; 31 | k_xor_opad = new byte[BLOCKSIZE]; 32 | 33 | if (key.length > BLOCKSIZE) 34 | { 35 | md.reset(); 36 | md.update(key); 37 | md.digest(tmp); 38 | key = tmp; 39 | } 40 | 41 | System.arraycopy(key, 0, k_xor_ipad, 0, key.length); 42 | System.arraycopy(key, 0, k_xor_opad, 0, key.length); 43 | 44 | for (int i = 0; i < BLOCKSIZE; i++) 45 | { 46 | k_xor_ipad[i] ^= 0x36; 47 | k_xor_opad[i] ^= 0x5C; 48 | } 49 | md.update(k_xor_ipad); 50 | } 51 | 52 | public final int getDigestLength() 53 | { 54 | return size; 55 | } 56 | 57 | public final void update(byte b) 58 | { 59 | md.update(b); 60 | } 61 | 62 | public final void update(byte[] b) 63 | { 64 | md.update(b); 65 | } 66 | 67 | public final void update(byte[] b, int off, int len) 68 | { 69 | md.update(b, off, len); 70 | } 71 | 72 | public final void reset() 73 | { 74 | md.reset(); 75 | md.update(k_xor_ipad); 76 | } 77 | 78 | public final void digest(byte[] out) 79 | { 80 | digest(out, 0); 81 | } 82 | 83 | public final void digest(byte[] out, int off) 84 | { 85 | md.digest(tmp); 86 | 87 | md.update(k_xor_opad); 88 | md.update(tmp); 89 | 90 | md.digest(tmp); 91 | 92 | System.arraycopy(tmp, 0, out, off, size); 93 | 94 | md.update(k_xor_ipad); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.crypto.digest; 3 | 4 | import java.math.BigInteger; 5 | import java.security.GeneralSecurityException; 6 | import java.security.MessageDigest; 7 | 8 | /** 9 | * HashForSSH2Types. 10 | * 11 | * @author Christian Plattner, plattner@trilead.com 12 | * @version $Id: HashForSSH2Types.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 13 | */ 14 | public class HashForSSH2Types 15 | { 16 | 17 | /** 18 | * Overwriting this value will not cause the result of the 19 | * digest to change 20 | * @deprecated the actual message digest is held in a private field 21 | */ 22 | @Deprecated 23 | Digest md; 24 | 25 | private final Digest messageDigest; 26 | 27 | 28 | 29 | public HashForSSH2Types(Digest md) 30 | { 31 | super(); 32 | this.md = md; 33 | this.messageDigest = md; 34 | } 35 | 36 | public HashForSSH2Types(String type) 37 | { 38 | this(new JreMessageDigestWrapper(createMessageDigest(type))); 39 | } 40 | 41 | private static MessageDigest createMessageDigest(String algorithm) { 42 | try { 43 | return MessageDigest.getInstance(algorithm); 44 | } catch (GeneralSecurityException ex) { 45 | throw new IllegalArgumentException("Could not get Message digest instance", ex); 46 | } 47 | } 48 | 49 | public void updateByte(byte b) 50 | { 51 | /* HACK - to test it with J2ME */ 52 | byte[] tmp = new byte[1]; 53 | tmp[0] = b; 54 | messageDigest.update(tmp); 55 | } 56 | 57 | public void updateBytes(byte[] b) 58 | { 59 | messageDigest.update(b); 60 | } 61 | 62 | public void updateUINT32(int v) 63 | { 64 | messageDigest.update((byte) (v >> 24)); 65 | messageDigest.update((byte) (v >> 16)); 66 | messageDigest.update((byte) (v >> 8)); 67 | messageDigest.update((byte) (v)); 68 | } 69 | 70 | public void updateByteString(byte[] b) 71 | { 72 | updateUINT32(b.length); 73 | updateBytes(b); 74 | } 75 | 76 | public void updateBigInt(BigInteger b) 77 | { 78 | updateByteString(b.toByteArray()); 79 | } 80 | 81 | public void reset() 82 | { 83 | messageDigest.reset(); 84 | } 85 | 86 | public int getDigestLength() 87 | { 88 | return messageDigest.getDigestLength(); 89 | } 90 | 91 | public byte[] getDigest() 92 | { 93 | byte[] tmp = new byte[messageDigest.getDigestLength()]; 94 | getDigest(tmp); 95 | return tmp; 96 | } 97 | 98 | public void getDigest(byte[] out) 99 | { 100 | getDigest(out, 0); 101 | } 102 | 103 | public void getDigest(byte[] out, int off) 104 | { 105 | messageDigest.digest(out, off); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/crypto/digest/JreMessageDigestWrapper.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.crypto.digest; 2 | 3 | import java.security.MessageDigest; 4 | 5 | /** 6 | * @author Michael Clarke 7 | */ 8 | public class JreMessageDigestWrapper implements Digest { 9 | 10 | private final MessageDigest digest; 11 | 12 | public JreMessageDigestWrapper(MessageDigest digest) { 13 | super(); 14 | this.digest = digest; 15 | } 16 | 17 | public int getDigestLength() { 18 | return digest.getDigestLength(); 19 | } 20 | 21 | public void update(byte b) { 22 | digest.update(b); 23 | } 24 | 25 | public void update(byte[] b) { 26 | digest.update(b); 27 | } 28 | 29 | public void update(byte[] b, int off, int len) { 30 | digest.update(b, off, len); 31 | } 32 | 33 | public void reset() { 34 | digest.reset(); 35 | } 36 | 37 | public void digest(byte[] out) { 38 | byte[] output = digest.digest(); 39 | System.arraycopy(output, 0, out, 0, out.length); 40 | } 41 | 42 | public void digest(byte[] out, int off) { 43 | byte[] output = digest.digest(); 44 | System.arraycopy(output, 0, out, off, out.length); 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/jenkins/FilterEncrytionAlgorithms.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.jenkins; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import com.trilead.ssh2.log.Logger; 9 | 10 | /** 11 | * Filter encryption algorithms. 12 | * The reason for this filter is that some algorithms have security issues. 13 | * The filter can be disabled by setting the system property 14 | * com.trilead.ssh2.jenkins.FilterEncrytionAlgorithms.enabled to false. 15 | * The list of algorithms to filter can be set by setting the system property 16 | * com.trilead.ssh2.jenkins.FilterEncrytionAlgorithms.algorithms (e.g. type01,type02,type03). 17 | */ 18 | public class FilterEncrytionAlgorithms { 19 | /* 20 | * The list of algorithms to filter by default. 21 | */ 22 | private static final List filteredAlgorithms = Collections.emptyList(); 23 | 24 | /** 25 | * Filter algorithms. 26 | * @param algorithms The algorithms to filter. 27 | * @return The filtered algorithms. 28 | */ 29 | public static String[] filter(String[] algorithms) { 30 | FilterAlgorithms filter = new FilterAlgorithms(FilterEncrytionAlgorithms.class.getName(), filteredAlgorithms); 31 | return filter.filter(algorithms); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/jenkins/FilterHostKeyAlgorithms.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.jenkins; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | import com.trilead.ssh2.log.Logger; 8 | 9 | /** 10 | * Filter host key algorithms. 11 | * The reason for this filter is that some algorithms have security issues. 12 | * The filter can be disabled by setting the system property 13 | * com.trilead.ssh2.jenkins.FilterHostKeyAlgorithms.enabled to false. 14 | * The list of algorithms to filter can be set by setting the system property 15 | * com.trilead.ssh2.jenkins.FilterHostKeyAlgorithms.algorithms (e.g. type01,type02,type03). 16 | */ 17 | public class FilterHostKeyAlgorithms { 18 | /* 19 | * The list of algorithms to filter. 20 | */ 21 | private static final List filteredAlgorithms = Collections.emptyList(); 22 | 23 | /** 24 | * Filter algorithms. 25 | * @param algorithms The algorithms to filter. 26 | * @return The filtered algorithms. 27 | */ 28 | public static String[] filter(String[] algorithms) { 29 | FilterAlgorithms filter = new FilterAlgorithms(FilterHostKeyAlgorithms.class.getName(), filteredAlgorithms); 30 | return filter.filter(algorithms); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/jenkins/FilterKexAlgorithms.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.jenkins; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.trilead.ssh2.log.Logger; 7 | 8 | /** 9 | * Filter KEX algorithms. 10 | * The reason for this filter is that some algorithms have security issues. 11 | * The filter can be disabled by setting the system property 12 | * com.trilead.ssh2.jenkins.FilterKexAlgorithms.enabled to false. 13 | * The list of algorithms to filter can be set by setting the system property 14 | * com.trilead.ssh2.jenkins.FilterKexAlgorithms.algorithms (e.g. type01,type02,type03). 15 | */ 16 | public class FilterKexAlgorithms { 17 | /* 18 | * The list of algorithms to filter. 19 | */ 20 | private static final List filteredAlgorithms = new ArrayList<>( 21 | List.of( 22 | // Terrapin attack see https://en.wikipedia.org/wiki/Terrapin_attack 23 | "chacha20-poly1305@openssh.com")); 24 | 25 | /** 26 | * Filter algorithms. 27 | * @param algorithms The algorithms to filter. 28 | * @return The filtered algorithms. 29 | */ 30 | public static String[] filter(String[] algorithms) { 31 | FilterAlgorithms filter = new FilterAlgorithms(FilterKexAlgorithms.class.getName(), filteredAlgorithms); 32 | return filter.filter(algorithms); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/jenkins/FilterMacAlgorithms.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.jenkins; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.trilead.ssh2.log.Logger; 7 | 8 | /** 9 | * Filter host key algorithms. 10 | * The reason for this filter is that some algorithms have security issues. 11 | * The filter can be disabled by setting the system property 12 | * com.trilead.ssh2.jenkins.FilterHostKeyAlgorithms.enabled to false. 13 | * The list of algorithms to filter can be set by setting the system property 14 | * com.trilead.ssh2.jenkins.FilterHostKeyAlgorithms.algorithms (e.g. type01,type02,type03). 15 | */ 16 | public class FilterMacAlgorithms { 17 | /* 18 | * The list of algorithms to filter. 19 | */ 20 | private static final List filteredAlgorithms = new ArrayList<>( 21 | List.of( 22 | // Terrapin attack see https://en.wikipedia.org/wiki/Terrapin_attack 23 | "hmac-sha2-512-etm@openssh.com", 24 | // Terrapin attack see https://en.wikipedia.org/wiki/Terrapin_attack 25 | "hmac-sha2-256-etm@openssh.com")); 26 | 27 | /** 28 | * Filter algorithms. 29 | * @param algorithms The algorithms to filter. 30 | * @return The filtered algorithms. 31 | */ 32 | public static String[] filter(String[] algorithms) { 33 | FilterAlgorithms filter = new FilterAlgorithms(FilterMacAlgorithms.class.getName(), filteredAlgorithms); 34 | return filter.filter(algorithms); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/log/Logger.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.log; 3 | 4 | import com.trilead.ssh2.DebugLogger; 5 | 6 | import java.util.logging.Level; 7 | 8 | /** 9 | * Logger - a very simple logger, mainly used during development. 10 | * Is not based on log4j (to reduce external dependencies). 11 | * However, if needed, something like log4j could easily be 12 | * hooked in. 13 | *

14 | * For speed reasons, the static variables are not protected 15 | * with semaphores. In other words, if you dynamicaly change the 16 | * logging settings, then some threads may still use the old setting. 17 | * 18 | * @author Christian Plattner, plattner@trilead.com 19 | * @version $Id: Logger.java,v 1.2 2008/03/03 07:01:36 cplattne Exp $ 20 | */ 21 | 22 | public class Logger 23 | { 24 | public static boolean enabled = false; 25 | public static DebugLogger logger = null; 26 | 27 | private java.util.logging.Logger log; 28 | 29 | public final static Logger getLogger(Class x) 30 | { 31 | return new Logger(x); 32 | } 33 | 34 | public Logger(Class x) 35 | { 36 | this.log = java.util.logging.Logger.getLogger(x.getName()); 37 | } 38 | 39 | public final boolean isEnabled() 40 | { 41 | return true; 42 | } 43 | 44 | public final void log(int lv, String message) 45 | { 46 | log.log(level(lv),message); 47 | } 48 | 49 | public final void log(int lv, String message, Throwable cause) 50 | { 51 | log.log(level(lv),message,cause); 52 | } 53 | 54 | private Level level(int lv) { 55 | if (lv<=20) return Level.FINE; 56 | if (lv<=50) return Level.FINER; 57 | return Level.FINEST; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketChannelOpenConfirmation.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketChannelOpenConfirmation. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketChannelOpenConfirmation.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketChannelOpenConfirmation 12 | { 13 | byte[] payload; 14 | 15 | public int recipientChannelID; 16 | public int senderChannelID; 17 | public int initialWindowSize; 18 | public int maxPacketSize; 19 | 20 | public PacketChannelOpenConfirmation(int recipientChannelID, int senderChannelID, int initialWindowSize, 21 | int maxPacketSize) 22 | { 23 | this.recipientChannelID = recipientChannelID; 24 | this.senderChannelID = senderChannelID; 25 | this.initialWindowSize = initialWindowSize; 26 | this.maxPacketSize = maxPacketSize; 27 | } 28 | 29 | public PacketChannelOpenConfirmation(byte payload[], int off, int len) throws IOException 30 | { 31 | this.payload = new byte[len]; 32 | System.arraycopy(payload, off, this.payload, 0, len); 33 | 34 | TypesReader tr = new TypesReader(payload, off, len); 35 | 36 | int packet_type = tr.readByte(); 37 | 38 | if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION) 39 | throw new IOException( 40 | "This is not a SSH_MSG_CHANNEL_OPEN_CONFIRMATION! (" 41 | + packet_type + ")"); 42 | 43 | recipientChannelID = tr.readUINT32(); 44 | senderChannelID = tr.readUINT32(); 45 | initialWindowSize = tr.readUINT32(); 46 | maxPacketSize = tr.readUINT32(); 47 | 48 | if (tr.remain() != 0) 49 | throw new IOException("Padding in SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet!"); 50 | } 51 | 52 | public byte[] getPayload() 53 | { 54 | if (payload == null) 55 | { 56 | TypesWriter tw = new TypesWriter(); 57 | tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION); 58 | tw.writeUINT32(recipientChannelID); 59 | tw.writeUINT32(senderChannelID); 60 | tw.writeUINT32(initialWindowSize); 61 | tw.writeUINT32(maxPacketSize); 62 | payload = tw.getBytes(); 63 | } 64 | return payload; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketChannelOpenFailure.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketChannelOpenFailure. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketChannelOpenFailure.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketChannelOpenFailure 12 | { 13 | byte[] payload; 14 | 15 | public int recipientChannelID; 16 | public int reasonCode; 17 | public String description; 18 | public String languageTag; 19 | 20 | public PacketChannelOpenFailure(int recipientChannelID, int reasonCode, String description, 21 | String languageTag) 22 | { 23 | this.recipientChannelID = recipientChannelID; 24 | this.reasonCode = reasonCode; 25 | this.description = description; 26 | this.languageTag = languageTag; 27 | } 28 | 29 | public PacketChannelOpenFailure(byte payload[], int off, int len) throws IOException 30 | { 31 | this.payload = new byte[len]; 32 | System.arraycopy(payload, off, this.payload, 0, len); 33 | 34 | TypesReader tr = new TypesReader(payload, off, len); 35 | 36 | int packet_type = tr.readByte(); 37 | 38 | if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN_FAILURE) 39 | throw new IOException( 40 | "This is not a SSH_MSG_CHANNEL_OPEN_FAILURE! (" 41 | + packet_type + ")"); 42 | 43 | recipientChannelID = tr.readUINT32(); 44 | reasonCode = tr.readUINT32(); 45 | description = tr.readString(); 46 | languageTag = tr.readString(); 47 | 48 | if (tr.remain() != 0) 49 | throw new IOException("Padding in SSH_MSG_CHANNEL_OPEN_FAILURE packet!"); 50 | } 51 | 52 | public byte[] getPayload() 53 | { 54 | if (payload == null) 55 | { 56 | TypesWriter tw = new TypesWriter(); 57 | tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN_FAILURE); 58 | tw.writeUINT32(recipientChannelID); 59 | tw.writeUINT32(reasonCode); 60 | tw.writeString(description); 61 | tw.writeString(languageTag); 62 | payload = tw.getBytes(); 63 | } 64 | return payload; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketChannelTrileadPing.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketChannelTrileadPing. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketChannelTrileadPing.java,v 1.1 2008/03/03 07:01:36 9 | * cplattne Exp $ 10 | */ 11 | public class PacketChannelTrileadPing 12 | { 13 | byte[] payload; 14 | 15 | public int recipientChannelID; 16 | 17 | public PacketChannelTrileadPing(int recipientChannelID) 18 | { 19 | this.recipientChannelID = recipientChannelID; 20 | } 21 | 22 | public byte[] getPayload() 23 | { 24 | if (payload == null) 25 | { 26 | TypesWriter tw = new TypesWriter(); 27 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 28 | tw.writeUINT32(recipientChannelID); 29 | tw.writeString("trilead-ping"); 30 | tw.writeBoolean(true); 31 | payload = tw.getBytes(); 32 | } 33 | return payload; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketChannelWindowAdjust.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketChannelWindowAdjust. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketChannelWindowAdjust.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketChannelWindowAdjust 12 | { 13 | byte[] payload; 14 | 15 | public int recipientChannelID; 16 | public int windowChange; 17 | 18 | public PacketChannelWindowAdjust(int recipientChannelID, int windowChange) 19 | { 20 | this.recipientChannelID = recipientChannelID; 21 | this.windowChange = windowChange; 22 | } 23 | 24 | public PacketChannelWindowAdjust(byte payload[], int off, int len) throws IOException 25 | { 26 | this.payload = new byte[len]; 27 | System.arraycopy(payload, off, this.payload, 0, len); 28 | 29 | TypesReader tr = new TypesReader(payload, off, len); 30 | 31 | int packet_type = tr.readByte(); 32 | 33 | if (packet_type != Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST) 34 | throw new IOException( 35 | "This is not a SSH_MSG_CHANNEL_WINDOW_ADJUST! (" 36 | + packet_type + ")"); 37 | 38 | recipientChannelID = tr.readUINT32(); 39 | windowChange = tr.readUINT32(); 40 | 41 | if (tr.remain() != 0) 42 | throw new IOException("Padding in SSH_MSG_CHANNEL_WINDOW_ADJUST packet!"); 43 | } 44 | 45 | public byte[] getPayload() 46 | { 47 | if (payload == null) 48 | { 49 | TypesWriter tw = new TypesWriter(); 50 | tw.writeByte(Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST); 51 | tw.writeUINT32(recipientChannelID); 52 | tw.writeUINT32(windowChange); 53 | payload = tw.getBytes(); 54 | } 55 | return payload; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketDisconnect.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * PacketDisconnect. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketDisconnect.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ 11 | */ 12 | public class PacketDisconnect 13 | { 14 | byte[] payload; 15 | 16 | int reason; 17 | String desc; 18 | String lang; 19 | 20 | public PacketDisconnect(byte payload[], int off, int len) throws IOException 21 | { 22 | this.payload = new byte[len]; 23 | System.arraycopy(payload, off, this.payload, 0, len); 24 | 25 | TypesReader tr = new TypesReader(payload, off, len); 26 | 27 | int packet_type = tr.readByte(); 28 | 29 | if (packet_type != Packets.SSH_MSG_DISCONNECT) 30 | throw new IOException("This is not a Disconnect Packet! (" + packet_type + ")"); 31 | 32 | reason = tr.readUINT32(); 33 | desc = tr.readString(); 34 | lang = tr.readString(); 35 | } 36 | 37 | public PacketDisconnect(int reason, String desc, String lang) 38 | { 39 | this.reason = reason; 40 | this.desc = desc; 41 | this.lang = lang; 42 | } 43 | 44 | public byte[] getPayload() 45 | { 46 | if (payload == null) 47 | { 48 | TypesWriter tw = new TypesWriter(); 49 | tw.writeByte(Packets.SSH_MSG_DISCONNECT); 50 | tw.writeUINT32(reason); 51 | tw.writeString(desc); 52 | tw.writeString(lang); 53 | payload = tw.getBytes(); 54 | } 55 | return payload; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketGlobalCancelForwardRequest.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketGlobalCancelForwardRequest. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketGlobalCancelForwardRequest.java,v 1.1 2007/10/15 12:49:55 9 | * cplattne Exp $ 10 | */ 11 | public class PacketGlobalCancelForwardRequest 12 | { 13 | byte[] payload; 14 | 15 | public boolean wantReply; 16 | public String bindAddress; 17 | public int bindPort; 18 | 19 | public PacketGlobalCancelForwardRequest(boolean wantReply, String bindAddress, int bindPort) 20 | { 21 | this.wantReply = wantReply; 22 | this.bindAddress = bindAddress; 23 | this.bindPort = bindPort; 24 | } 25 | 26 | public byte[] getPayload() 27 | { 28 | if (payload == null) 29 | { 30 | TypesWriter tw = new TypesWriter(); 31 | tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST); 32 | 33 | tw.writeString("cancel-tcpip-forward"); 34 | tw.writeBoolean(wantReply); 35 | tw.writeString(bindAddress); 36 | tw.writeUINT32(bindPort); 37 | 38 | payload = tw.getBytes(); 39 | } 40 | return payload; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketGlobalForwardRequest.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketGlobalForwardRequest. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketGlobalForwardRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketGlobalForwardRequest 11 | { 12 | byte[] payload; 13 | 14 | public boolean wantReply; 15 | public String bindAddress; 16 | public int bindPort; 17 | 18 | public PacketGlobalForwardRequest(boolean wantReply, String bindAddress, int bindPort) 19 | { 20 | this.wantReply = wantReply; 21 | this.bindAddress = bindAddress; 22 | this.bindPort = bindPort; 23 | } 24 | 25 | public byte[] getPayload() 26 | { 27 | if (payload == null) 28 | { 29 | TypesWriter tw = new TypesWriter(); 30 | tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST); 31 | 32 | tw.writeString("tcpip-forward"); 33 | tw.writeBoolean(wantReply); 34 | tw.writeString(bindAddress); 35 | tw.writeUINT32(bindPort); 36 | 37 | payload = tw.getBytes(); 38 | } 39 | return payload; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketGlobalTrileadPing.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketGlobalTrileadPing. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketGlobalTrileadPing.java,v 1.1 2008/03/03 07:01:36 cplattne Exp $ 9 | */ 10 | public class PacketGlobalTrileadPing 11 | { 12 | byte[] payload; 13 | 14 | public PacketGlobalTrileadPing() 15 | { 16 | } 17 | 18 | public byte[] getPayload() 19 | { 20 | if (payload == null) 21 | { 22 | TypesWriter tw = new TypesWriter(); 23 | tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST); 24 | 25 | tw.writeString("trilead-ping"); 26 | tw.writeBoolean(true); 27 | 28 | payload = tw.getBytes(); 29 | } 30 | return payload; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketIgnore.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * PacketIgnore. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketIgnore.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketIgnore 13 | { 14 | byte[] payload; 15 | 16 | byte[] data; 17 | 18 | public void setData(byte[] data) 19 | { 20 | this.data = data; 21 | payload = null; 22 | } 23 | 24 | public PacketIgnore() 25 | { 26 | } 27 | 28 | public PacketIgnore(byte payload[], int off, int len) throws IOException 29 | { 30 | this.payload = new byte[len]; 31 | System.arraycopy(payload, off, this.payload, 0, len); 32 | 33 | TypesReader tr = new TypesReader(payload, off, len); 34 | 35 | int packet_type = tr.readByte(); 36 | 37 | if (packet_type != Packets.SSH_MSG_IGNORE) 38 | throw new IOException("This is not a SSH_MSG_IGNORE packet! (" + packet_type + ")"); 39 | 40 | /* Could parse String body */ 41 | } 42 | 43 | public byte[] getPayload() 44 | { 45 | if (payload == null) 46 | { 47 | TypesWriter tw = new TypesWriter(); 48 | tw.writeByte(Packets.SSH_MSG_IGNORE); 49 | 50 | if (data != null) 51 | tw.writeString(data, 0, data.length); 52 | else 53 | tw.writeString(""); 54 | 55 | payload = tw.getBytes(); 56 | } 57 | return payload; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketKexDHInit.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | /** 4 | * PacketKexDHInit. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: PacketKexDHInit.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 8 | */ 9 | public class PacketKexDHInit 10 | { 11 | byte[] payload; 12 | 13 | byte[] publicKey; 14 | 15 | public PacketKexDHInit(byte[] publicKey) 16 | { 17 | this.publicKey = publicKey; 18 | } 19 | 20 | public byte[] getPayload() 21 | { 22 | if (payload == null) 23 | { 24 | TypesWriter tw = new TypesWriter(); 25 | tw.writeByte(Packets.SSH_MSG_KEXDH_INIT); 26 | tw.writeString(publicKey, 0, publicKey.length); 27 | payload = tw.getBytes(); 28 | } 29 | return payload; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketKexDHReply.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | 6 | /** 7 | * PacketKexDHReply. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketKexDHReply.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketKexDHReply 13 | { 14 | byte[] payload; 15 | 16 | byte[] hostKey; 17 | byte [] publicKey; 18 | byte[] signature; 19 | 20 | public PacketKexDHReply(byte payload[], int off, int len) throws IOException 21 | { 22 | this.payload = new byte[len]; 23 | System.arraycopy(payload, off, this.payload, 0, len); 24 | 25 | TypesReader tr = new TypesReader(payload, off, len); 26 | 27 | int packet_type = tr.readByte(); 28 | 29 | if (packet_type != Packets.SSH_MSG_KEXDH_REPLY) 30 | throw new IOException("This is not a SSH_MSG_KEXDH_REPLY! (" 31 | + packet_type + ")"); 32 | 33 | hostKey = tr.readByteString(); 34 | publicKey = tr.readByteString(); 35 | signature = tr.readByteString(); 36 | 37 | if (tr.remain() != 0) throw new IOException("PADDING IN SSH_MSG_KEXDH_REPLY!"); 38 | } 39 | 40 | public byte[] getF() 41 | { 42 | return publicKey; 43 | 44 | } 45 | 46 | public byte[] getHostKey() 47 | { 48 | return hostKey; 49 | } 50 | 51 | public byte[] getSignature() 52 | { 53 | return signature; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketKexDhGexGroup.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | import java.math.BigInteger; 6 | 7 | /** 8 | * PacketKexDhGexGroup. 9 | * 10 | * @author Christian Plattner, plattner@trilead.com 11 | * @version $Id: PacketKexDhGexGroup.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 12 | */ 13 | public class PacketKexDhGexGroup 14 | { 15 | byte[] payload; 16 | 17 | BigInteger p; 18 | BigInteger g; 19 | 20 | public PacketKexDhGexGroup(byte payload[], int off, int len) throws IOException 21 | { 22 | this.payload = new byte[len]; 23 | System.arraycopy(payload, off, this.payload, 0, len); 24 | 25 | TypesReader tr = new TypesReader(payload, off, len); 26 | 27 | int packet_type = tr.readByte(); 28 | 29 | if (packet_type != Packets.SSH_MSG_KEX_DH_GEX_GROUP) 30 | throw new IllegalArgumentException( 31 | "This is not a SSH_MSG_KEX_DH_GEX_GROUP! (" + packet_type 32 | + ")"); 33 | 34 | p = tr.readMPINT(); 35 | g = tr.readMPINT(); 36 | 37 | if (tr.remain() != 0) 38 | throw new IOException("PADDING IN SSH_MSG_KEX_DH_GEX_GROUP!"); 39 | } 40 | 41 | public BigInteger getG() 42 | { 43 | return g; 44 | } 45 | 46 | public BigInteger getP() 47 | { 48 | return p; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketKexDhGexInit.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.math.BigInteger; 4 | 5 | /** 6 | * PacketKexDhGexInit. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketKexDhGexInit.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketKexDhGexInit 12 | { 13 | byte[] payload; 14 | 15 | BigInteger e; 16 | 17 | public PacketKexDhGexInit(BigInteger e) 18 | { 19 | this.e = e; 20 | } 21 | 22 | public byte[] getPayload() 23 | { 24 | if (payload == null) 25 | { 26 | TypesWriter tw = new TypesWriter(); 27 | tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_INIT); 28 | tw.writeMPInt(e); 29 | payload = tw.getBytes(); 30 | } 31 | return payload; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketKexDhGexReply.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | import java.math.BigInteger; 7 | 8 | /** 9 | * PacketKexDhGexReply. 10 | * 11 | * @author Christian Plattner, plattner@trilead.com 12 | * @version $Id: PacketKexDhGexReply.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 13 | */ 14 | public class PacketKexDhGexReply 15 | { 16 | byte[] payload; 17 | 18 | byte[] hostKey; 19 | BigInteger f; 20 | byte[] signature; 21 | 22 | public PacketKexDhGexReply(byte payload[], int off, int len) throws IOException 23 | { 24 | this.payload = new byte[len]; 25 | System.arraycopy(payload, off, this.payload, 0, len); 26 | 27 | TypesReader tr = new TypesReader(payload, off, len); 28 | 29 | int packet_type = tr.readByte(); 30 | 31 | if (packet_type != Packets.SSH_MSG_KEX_DH_GEX_REPLY) 32 | throw new IOException("This is not a SSH_MSG_KEX_DH_GEX_REPLY! (" + packet_type + ")"); 33 | 34 | hostKey = tr.readByteString(); 35 | f = tr.readMPINT(); 36 | signature = tr.readByteString(); 37 | 38 | if (tr.remain() != 0) 39 | throw new IOException("PADDING IN SSH_MSG_KEX_DH_GEX_REPLY!"); 40 | } 41 | 42 | public BigInteger getF() 43 | { 44 | return f; 45 | } 46 | 47 | public byte[] getHostKey() 48 | { 49 | return hostKey; 50 | } 51 | 52 | public byte[] getSignature() 53 | { 54 | return signature; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketKexDhGexRequest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import com.trilead.ssh2.DHGexParameters; 4 | 5 | /** 6 | * PacketKexDhGexRequest. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketKexDhGexRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketKexDhGexRequest 12 | { 13 | byte[] payload; 14 | 15 | int min; 16 | int n; 17 | int max; 18 | 19 | public PacketKexDhGexRequest(DHGexParameters para) 20 | { 21 | this.min = para.getMin_group_len(); 22 | this.n = para.getPref_group_len(); 23 | this.max = para.getMax_group_len(); 24 | } 25 | 26 | public byte[] getPayload() 27 | { 28 | if (payload == null) 29 | { 30 | TypesWriter tw = new TypesWriter(); 31 | tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_REQUEST); 32 | tw.writeUINT32(min); 33 | tw.writeUINT32(n); 34 | tw.writeUINT32(max); 35 | payload = tw.getBytes(); 36 | } 37 | return payload; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketKexDhGexRequestOld.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import com.trilead.ssh2.DHGexParameters; 5 | 6 | /** 7 | * PacketKexDhGexRequestOld. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketKexDhGexRequestOld.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketKexDhGexRequestOld 13 | { 14 | byte[] payload; 15 | 16 | int n; 17 | 18 | public PacketKexDhGexRequestOld(DHGexParameters para) 19 | { 20 | this.n = para.getPref_group_len(); 21 | } 22 | 23 | public byte[] getPayload() 24 | { 25 | if (payload == null) 26 | { 27 | TypesWriter tw = new TypesWriter(); 28 | tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_REQUEST_OLD); 29 | tw.writeUINT32(n); 30 | payload = tw.getBytes(); 31 | } 32 | return payload; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketNewKeys.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketNewKeys. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketNewKeys.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketNewKeys 12 | { 13 | byte[] payload; 14 | 15 | public PacketNewKeys() 16 | { 17 | } 18 | 19 | public PacketNewKeys(byte payload[], int off, int len) throws IOException 20 | { 21 | this.payload = new byte[len]; 22 | System.arraycopy(payload, off, this.payload, 0, len); 23 | 24 | TypesReader tr = new TypesReader(payload, off, len); 25 | 26 | int packet_type = tr.readByte(); 27 | 28 | if (packet_type != Packets.SSH_MSG_NEWKEYS) 29 | throw new IOException("This is not a SSH_MSG_NEWKEYS! (" 30 | + packet_type + ")"); 31 | 32 | if (tr.remain() != 0) 33 | throw new IOException("Padding in SSH_MSG_NEWKEYS packet!"); 34 | } 35 | 36 | public byte[] getPayload() 37 | { 38 | if (payload == null) 39 | { 40 | TypesWriter tw = new TypesWriter(); 41 | tw.writeByte(Packets.SSH_MSG_NEWKEYS); 42 | payload = tw.getBytes(); 43 | } 44 | return payload; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketOpenDirectTCPIPChannel.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | 4 | /** 5 | * PacketOpenDirectTCPIPChannel. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketOpenDirectTCPIPChannel.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketOpenDirectTCPIPChannel 11 | { 12 | byte[] payload; 13 | 14 | int channelID; 15 | int initialWindowSize; 16 | int maxPacketSize; 17 | 18 | String host_to_connect; 19 | int port_to_connect; 20 | String originator_IP_address; 21 | int originator_port; 22 | 23 | public PacketOpenDirectTCPIPChannel(int channelID, int initialWindowSize, int maxPacketSize, 24 | String host_to_connect, int port_to_connect, String originator_IP_address, 25 | int originator_port) 26 | { 27 | this.channelID = channelID; 28 | this.initialWindowSize = initialWindowSize; 29 | this.maxPacketSize = maxPacketSize; 30 | this.host_to_connect = host_to_connect; 31 | this.port_to_connect = port_to_connect; 32 | this.originator_IP_address = originator_IP_address; 33 | this.originator_port = originator_port; 34 | } 35 | 36 | public byte[] getPayload() 37 | { 38 | if (payload == null) 39 | { 40 | TypesWriter tw = new TypesWriter(); 41 | 42 | tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN); 43 | tw.writeString("direct-tcpip"); 44 | tw.writeUINT32(channelID); 45 | tw.writeUINT32(initialWindowSize); 46 | tw.writeUINT32(maxPacketSize); 47 | tw.writeString(host_to_connect); 48 | tw.writeUINT32(port_to_connect); 49 | tw.writeString(originator_IP_address); 50 | tw.writeUINT32(originator_port); 51 | 52 | payload = tw.getBytes(); 53 | } 54 | return payload; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketOpenSessionChannel.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketOpenSessionChannel. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketOpenSessionChannel.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketOpenSessionChannel 12 | { 13 | byte[] payload; 14 | 15 | int channelID; 16 | int initialWindowSize; 17 | int maxPacketSize; 18 | 19 | public PacketOpenSessionChannel(int channelID, int initialWindowSize, 20 | int maxPacketSize) 21 | { 22 | this.channelID = channelID; 23 | this.initialWindowSize = initialWindowSize; 24 | this.maxPacketSize = maxPacketSize; 25 | } 26 | 27 | public PacketOpenSessionChannel(byte payload[], int off, int len) throws IOException 28 | { 29 | this.payload = new byte[len]; 30 | System.arraycopy(payload, off, this.payload, 0, len); 31 | 32 | TypesReader tr = new TypesReader(payload); 33 | 34 | int packet_type = tr.readByte(); 35 | 36 | if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN) 37 | throw new IOException("This is not a SSH_MSG_CHANNEL_OPEN! (" 38 | + packet_type + ")"); 39 | 40 | channelID = tr.readUINT32(); 41 | initialWindowSize = tr.readUINT32(); 42 | maxPacketSize = tr.readUINT32(); 43 | 44 | if (tr.remain() != 0) 45 | throw new IOException("Padding in SSH_MSG_CHANNEL_OPEN packet!"); 46 | } 47 | 48 | public byte[] getPayload() 49 | { 50 | if (payload == null) 51 | { 52 | TypesWriter tw = new TypesWriter(); 53 | tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN); 54 | tw.writeString("session"); 55 | tw.writeUINT32(channelID); 56 | tw.writeUINT32(initialWindowSize); 57 | tw.writeUINT32(maxPacketSize); 58 | payload = tw.getBytes(); 59 | } 60 | return payload; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketServiceAccept.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * PacketServiceAccept. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketServiceAccept.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ 11 | */ 12 | public class PacketServiceAccept 13 | { 14 | byte[] payload; 15 | 16 | String serviceName; 17 | 18 | public PacketServiceAccept(String serviceName) 19 | { 20 | this.serviceName = serviceName; 21 | } 22 | 23 | public PacketServiceAccept(byte payload[], int off, int len) throws IOException 24 | { 25 | this.payload = new byte[len]; 26 | System.arraycopy(payload, off, this.payload, 0, len); 27 | 28 | TypesReader tr = new TypesReader(payload, off, len); 29 | 30 | int packet_type = tr.readByte(); 31 | 32 | if (packet_type != Packets.SSH_MSG_SERVICE_ACCEPT) 33 | throw new IOException("This is not a SSH_MSG_SERVICE_ACCEPT! (" + packet_type + ")"); 34 | 35 | /* Be clever in case the server is not. Some servers seem to violate RFC4253 */ 36 | 37 | if (tr.remain() > 0) 38 | { 39 | serviceName = tr.readString(); 40 | } 41 | else 42 | { 43 | serviceName = ""; 44 | } 45 | 46 | if (tr.remain() != 0) 47 | throw new IOException("Padding in SSH_MSG_SERVICE_ACCEPT packet!"); 48 | } 49 | 50 | public byte[] getPayload() 51 | { 52 | if (payload == null) 53 | { 54 | TypesWriter tw = new TypesWriter(); 55 | tw.writeByte(Packets.SSH_MSG_SERVICE_ACCEPT); 56 | tw.writeString(serviceName); 57 | payload = tw.getBytes(); 58 | } 59 | return payload; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketServiceRequest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketServiceRequest. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketServiceRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketServiceRequest 12 | { 13 | byte[] payload; 14 | 15 | String serviceName; 16 | 17 | public PacketServiceRequest(String serviceName) 18 | { 19 | this.serviceName = serviceName; 20 | } 21 | 22 | public PacketServiceRequest(byte payload[], int off, int len) throws IOException 23 | { 24 | this.payload = new byte[len]; 25 | System.arraycopy(payload, off, this.payload, 0, len); 26 | 27 | TypesReader tr = new TypesReader(payload, off, len); 28 | 29 | int packet_type = tr.readByte(); 30 | 31 | if (packet_type != Packets.SSH_MSG_SERVICE_REQUEST) 32 | throw new IOException("This is not a SSH_MSG_SERVICE_REQUEST! (" 33 | + packet_type + ")"); 34 | 35 | serviceName = tr.readString(); 36 | 37 | if (tr.remain() != 0) 38 | throw new IOException("Padding in SSH_MSG_SERVICE_REQUEST packet!"); 39 | } 40 | 41 | public byte[] getPayload() 42 | { 43 | if (payload == null) 44 | { 45 | TypesWriter tw = new TypesWriter(); 46 | tw.writeByte(Packets.SSH_MSG_SERVICE_REQUEST); 47 | tw.writeString(serviceName); 48 | payload = tw.getBytes(); 49 | } 50 | return payload; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketSessionExecCommand.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | 4 | /** 5 | * PacketSessionExecCommand. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketSessionExecCommand.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketSessionExecCommand 11 | { 12 | byte[] payload; 13 | 14 | public int recipientChannelID; 15 | public boolean wantReply; 16 | public String command; 17 | 18 | public PacketSessionExecCommand(int recipientChannelID, boolean wantReply, String command) 19 | { 20 | this.recipientChannelID = recipientChannelID; 21 | this.wantReply = wantReply; 22 | this.command = command; 23 | } 24 | 25 | public byte[] getPayload() 26 | { 27 | if (payload == null) 28 | { 29 | TypesWriter tw = new TypesWriter(); 30 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 31 | tw.writeUINT32(recipientChannelID); 32 | tw.writeString("exec"); 33 | tw.writeBoolean(wantReply); 34 | tw.writeString(command); 35 | payload = tw.getBytes(); 36 | } 37 | return payload; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketSessionPtyRequest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | 4 | /** 5 | * PacketSessionPtyRequest. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketSessionPtyRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketSessionPtyRequest 11 | { 12 | byte[] payload; 13 | 14 | public int recipientChannelID; 15 | public boolean wantReply; 16 | public String term; 17 | public int character_width; 18 | public int character_height; 19 | public int pixel_width; 20 | public int pixel_height; 21 | public byte[] terminal_modes; 22 | 23 | public PacketSessionPtyRequest(int recipientChannelID, boolean wantReply, String term, 24 | int character_width, int character_height, int pixel_width, int pixel_height, 25 | byte[] terminal_modes) 26 | { 27 | this.recipientChannelID = recipientChannelID; 28 | this.wantReply = wantReply; 29 | this.term = term; 30 | this.character_width = character_width; 31 | this.character_height = character_height; 32 | this.pixel_width = pixel_width; 33 | this.pixel_height = pixel_height; 34 | this.terminal_modes = terminal_modes; 35 | } 36 | 37 | public byte[] getPayload() 38 | { 39 | if (payload == null) 40 | { 41 | TypesWriter tw = new TypesWriter(); 42 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 43 | tw.writeUINT32(recipientChannelID); 44 | tw.writeString("pty-req"); 45 | tw.writeBoolean(wantReply); 46 | tw.writeString(term); 47 | tw.writeUINT32(character_width); 48 | tw.writeUINT32(character_height); 49 | tw.writeUINT32(pixel_width); 50 | tw.writeUINT32(pixel_height); 51 | tw.writeString(terminal_modes, 0, terminal_modes.length); 52 | 53 | payload = tw.getBytes(); 54 | } 55 | return payload; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketSessionStartShell.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketSessionStartShell. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketSessionStartShell.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketSessionStartShell 11 | { 12 | byte[] payload; 13 | 14 | public int recipientChannelID; 15 | public boolean wantReply; 16 | 17 | public PacketSessionStartShell(int recipientChannelID, boolean wantReply) 18 | { 19 | this.recipientChannelID = recipientChannelID; 20 | this.wantReply = wantReply; 21 | } 22 | 23 | public byte[] getPayload() 24 | { 25 | if (payload == null) 26 | { 27 | TypesWriter tw = new TypesWriter(); 28 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 29 | tw.writeUINT32(recipientChannelID); 30 | tw.writeString("shell"); 31 | tw.writeBoolean(wantReply); 32 | payload = tw.getBytes(); 33 | } 34 | return payload; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketSessionSubsystemRequest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | 4 | /** 5 | * PacketSessionSubsystemRequest. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketSessionSubsystemRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketSessionSubsystemRequest 11 | { 12 | byte[] payload; 13 | 14 | public int recipientChannelID; 15 | public boolean wantReply; 16 | public String subsystem; 17 | 18 | public PacketSessionSubsystemRequest(int recipientChannelID, boolean wantReply, String subsystem) 19 | { 20 | this.recipientChannelID = recipientChannelID; 21 | this.wantReply = wantReply; 22 | this.subsystem = subsystem; 23 | } 24 | 25 | public byte[] getPayload() 26 | { 27 | if (payload == null) 28 | { 29 | TypesWriter tw = new TypesWriter(); 30 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 31 | tw.writeUINT32(recipientChannelID); 32 | tw.writeString("subsystem"); 33 | tw.writeBoolean(wantReply); 34 | tw.writeString(subsystem); 35 | payload = tw.getBytes(); 36 | tw.getBytes(payload); 37 | } 38 | return payload; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketSessionX11Request.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketSessionX11Request. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketSessionX11Request.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketSessionX11Request 11 | { 12 | byte[] payload; 13 | 14 | public int recipientChannelID; 15 | public boolean wantReply; 16 | 17 | public boolean singleConnection; 18 | String x11AuthenticationProtocol; 19 | String x11AuthenticationCookie; 20 | int x11ScreenNumber; 21 | 22 | public PacketSessionX11Request(int recipientChannelID, boolean wantReply, boolean singleConnection, 23 | String x11AuthenticationProtocol, String x11AuthenticationCookie, int x11ScreenNumber) 24 | { 25 | this.recipientChannelID = recipientChannelID; 26 | this.wantReply = wantReply; 27 | 28 | this.singleConnection = singleConnection; 29 | this.x11AuthenticationProtocol = x11AuthenticationProtocol; 30 | this.x11AuthenticationCookie = x11AuthenticationCookie; 31 | this.x11ScreenNumber = x11ScreenNumber; 32 | } 33 | 34 | public byte[] getPayload() 35 | { 36 | if (payload == null) 37 | { 38 | TypesWriter tw = new TypesWriter(); 39 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 40 | tw.writeUINT32(recipientChannelID); 41 | tw.writeString("x11-req"); 42 | tw.writeBoolean(wantReply); 43 | 44 | tw.writeBoolean(singleConnection); 45 | tw.writeString(x11AuthenticationProtocol); 46 | tw.writeString(x11AuthenticationCookie); 47 | tw.writeUINT32(x11ScreenNumber); 48 | 49 | payload = tw.getBytes(); 50 | } 51 | return payload; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketSignal.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Delivers a signal from client to server. 8 | * 9 | * See section 6.9 of RFC 4254. 10 | * 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public class PacketSignal { 14 | byte[] payload; 15 | 16 | public int recipientChannelID; 17 | public String signalName; 18 | 19 | public PacketSignal(int recipientChannelID, String signalName) { 20 | this.recipientChannelID = recipientChannelID; 21 | 22 | if (signalName.startsWith("SIG")) signalName=signalName.substring(3); 23 | this.signalName = signalName; 24 | } 25 | 26 | public byte[] getPayload() 27 | { 28 | if (payload == null) 29 | { 30 | TypesWriter tw = new TypesWriter(); 31 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 32 | tw.writeUINT32(recipientChannelID); 33 | tw.writeString("signal"); 34 | tw.writeBoolean(false); 35 | tw.writeString(signalName); 36 | 37 | payload = tw.getBytes(); 38 | } 39 | return payload; 40 | } 41 | 42 | private static final Map SIGNALS = new HashMap(); 43 | 44 | public static String strsignal(int i) { 45 | return SIGNALS.get(i); 46 | } 47 | 48 | static { 49 | SIGNALS.put(14,"ALRM"); 50 | SIGNALS.put( 1,"HUP"); 51 | SIGNALS.put( 2,"INT"); 52 | SIGNALS.put( 9,"KILL"); 53 | SIGNALS.put(13,"PIPE"); 54 | SIGNALS.put(15,"TERM"); 55 | SIGNALS.put( 6,"ABRT"); 56 | SIGNALS.put( 8,"FPE"); 57 | SIGNALS.put( 4,"ILL"); 58 | SIGNALS.put( 3,"QUIT"); 59 | SIGNALS.put(11,"SEGV"); 60 | SIGNALS.put( 5,"TRAP"); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketUserauthBanner.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * PacketUserauthBanner. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: PacketUserauthBanner.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | */ 11 | public class PacketUserauthBanner 12 | { 13 | byte[] payload; 14 | 15 | String message; 16 | String language; 17 | 18 | public PacketUserauthBanner(String message, String language) 19 | { 20 | this.message = message; 21 | this.language = language; 22 | } 23 | 24 | public String getBanner() 25 | { 26 | return message; 27 | } 28 | 29 | public PacketUserauthBanner(byte payload[], int off, int len) throws IOException 30 | { 31 | this.payload = new byte[len]; 32 | System.arraycopy(payload, off, this.payload, 0, len); 33 | 34 | TypesReader tr = new TypesReader(payload, off, len); 35 | 36 | int packet_type = tr.readByte(); 37 | 38 | if (packet_type != Packets.SSH_MSG_USERAUTH_BANNER) 39 | throw new IOException("This is not a SSH_MSG_USERAUTH_BANNER! (" + packet_type + ")"); 40 | 41 | message = tr.readString("UTF-8"); 42 | language = tr.readString(); 43 | 44 | if (tr.remain() != 0) 45 | throw new IOException("Padding in SSH_MSG_USERAUTH_REQUEST packet!"); 46 | } 47 | 48 | public byte[] getPayload() 49 | { 50 | if (payload == null) 51 | { 52 | TypesWriter tw = new TypesWriter(); 53 | tw.writeByte(Packets.SSH_MSG_USERAUTH_BANNER); 54 | tw.writeString(message); 55 | tw.writeString(language); 56 | payload = tw.getBytes(); 57 | } 58 | return payload; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketUserauthFailure.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * PacketUserauthBanner. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketUserauthFailure.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketUserauthFailure 13 | { 14 | byte[] payload; 15 | 16 | String[] authThatCanContinue; 17 | boolean partialSuccess; 18 | 19 | public PacketUserauthFailure(String[] authThatCanContinue, boolean partialSuccess) 20 | { 21 | this.authThatCanContinue = authThatCanContinue; 22 | this.partialSuccess = partialSuccess; 23 | } 24 | 25 | public PacketUserauthFailure(byte payload[], int off, int len) throws IOException 26 | { 27 | this.payload = new byte[len]; 28 | System.arraycopy(payload, off, this.payload, 0, len); 29 | 30 | TypesReader tr = new TypesReader(payload, off, len); 31 | 32 | int packet_type = tr.readByte(); 33 | 34 | if (packet_type != Packets.SSH_MSG_USERAUTH_FAILURE) 35 | throw new IOException("This is not a SSH_MSG_USERAUTH_FAILURE! (" + packet_type + ")"); 36 | 37 | authThatCanContinue = tr.readNameList(); 38 | partialSuccess = tr.readBoolean(); 39 | 40 | if (tr.remain() != 0) 41 | throw new IOException("Padding in SSH_MSG_USERAUTH_FAILURE packet!"); 42 | } 43 | 44 | public String[] getAuthThatCanContinue() 45 | { 46 | return authThatCanContinue; 47 | } 48 | 49 | public boolean isPartialSuccess() 50 | { 51 | return partialSuccess; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketUserauthInfoRequest.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | import java.io.IOException; 5 | 6 | /** 7 | * PacketUserauthInfoRequest. 8 | * 9 | * @author Christian Plattner, plattner@trilead.com 10 | * @version $Id: PacketUserauthInfoRequest.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 11 | */ 12 | public class PacketUserauthInfoRequest 13 | { 14 | byte[] payload; 15 | 16 | String name; 17 | String instruction; 18 | String languageTag; 19 | int numPrompts; 20 | 21 | String prompt[]; 22 | boolean echo[]; 23 | 24 | public PacketUserauthInfoRequest(byte payload[], int off, int len) throws IOException 25 | { 26 | this.payload = new byte[len]; 27 | System.arraycopy(payload, off, this.payload, 0, len); 28 | 29 | TypesReader tr = new TypesReader(payload, off, len); 30 | 31 | int packet_type = tr.readByte(); 32 | 33 | if (packet_type != Packets.SSH_MSG_USERAUTH_INFO_REQUEST) 34 | throw new IOException("This is not a SSH_MSG_USERAUTH_INFO_REQUEST! (" + packet_type + ")"); 35 | 36 | name = tr.readString(); 37 | instruction = tr.readString(); 38 | languageTag = tr.readString(); 39 | 40 | numPrompts = tr.readUINT32(); 41 | 42 | prompt = new String[numPrompts]; 43 | echo = new boolean[numPrompts]; 44 | 45 | for (int i = 0; i < numPrompts; i++) 46 | { 47 | prompt[i] = tr.readString(); 48 | echo[i] = tr.readBoolean(); 49 | } 50 | 51 | if (tr.remain() != 0) 52 | throw new IOException("Padding in SSH_MSG_USERAUTH_INFO_REQUEST packet!"); 53 | } 54 | 55 | public boolean[] getEcho() 56 | { 57 | return echo; 58 | } 59 | 60 | public String getInstruction() 61 | { 62 | return instruction; 63 | } 64 | 65 | public String getLanguageTag() 66 | { 67 | return languageTag; 68 | } 69 | 70 | public String getName() 71 | { 72 | return name; 73 | } 74 | 75 | public int getNumPrompts() 76 | { 77 | return numPrompts; 78 | } 79 | 80 | public String[] getPrompt() 81 | { 82 | return prompt; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketUserauthInfoResponse.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.packets; 3 | 4 | /** 5 | * PacketUserauthInfoResponse. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: PacketUserauthInfoResponse.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 9 | */ 10 | public class PacketUserauthInfoResponse 11 | { 12 | byte[] payload; 13 | 14 | String[] responses; 15 | 16 | public PacketUserauthInfoResponse(String[] responses) 17 | { 18 | this.responses = responses; 19 | } 20 | 21 | public byte[] getPayload() 22 | { 23 | if (payload == null) 24 | { 25 | TypesWriter tw = new TypesWriter(); 26 | tw.writeByte(Packets.SSH_MSG_USERAUTH_INFO_RESPONSE); 27 | tw.writeUINT32(responses.length); 28 | for (int i = 0; i < responses.length; i++) 29 | tw.writeString(responses[i]); 30 | 31 | payload = tw.getBytes(); 32 | } 33 | return payload; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketUserauthRequestGssapiWithMic.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | public class PacketUserauthRequestGssapiWithMic { 4 | 5 | private static final String GSSAPI_WITH_MIC = "gssapi-with-mic"; 6 | 7 | private static final String SSH_CONNECTION = "ssh-connection"; 8 | 9 | byte[][] supported_oid={ 10 | // OID 1.2.840.113554.1.2.2 in DER 11 | {(byte)0x6,(byte)0x9,(byte)0x2a,(byte)0x86,(byte)0x48, 12 | (byte)0x86,(byte)0xf7,(byte)0x12,(byte)0x1,(byte)0x2, 13 | (byte)0x2} 14 | }; 15 | 16 | byte[] payload; 17 | 18 | private String user; 19 | 20 | public PacketUserauthRequestGssapiWithMic(String user) 21 | { 22 | this.user = user; 23 | } 24 | 25 | public byte[] getPayload() 26 | { 27 | if (payload == null) 28 | { 29 | TypesWriter tw = new TypesWriter(); 30 | tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); 31 | tw.writeString(user); 32 | tw.writeString(SSH_CONNECTION); 33 | tw.writeString(GSSAPI_WITH_MIC); 34 | tw.writeUINT32(supported_oid.length); 35 | for(int i=0; i 1) //take the first generated token and send it to the server 53 | break; 54 | } catch (GSSException | SecurityException e) 55 | { 56 | if (LOGGER.isEnabled()) { 57 | LOGGER.log(50, "Could not get token", e); 58 | } 59 | } 60 | } 61 | 62 | TypesWriter tw = new TypesWriter(); 63 | tw.writeByte(Packets.SSH_MSG_USERAUTH_INFO_RESPONSE); 64 | tw.writeString(token,0,token.length); 65 | payload = tw.getBytes(); 66 | } 67 | return payload; 68 | } 69 | 70 | public byte[] getMicPayload(byte[] sessionIdentifier) { 71 | 72 | payload = null; 73 | 74 | TypesWriter tw = new TypesWriter(); 75 | 76 | tw.writeString(sessionIdentifier, 0, sessionIdentifier.length); 77 | tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST); 78 | tw.writeString(user); 79 | tw.writeString(SSH_CONNECTION); 80 | tw.writeString(GSSAPI_WITH_MIC); 81 | 82 | byte[] message = tw.getBytes(); 83 | byte[] mic; 84 | try 85 | { 86 | mic = context.getMIC(message, 0, message.length); 87 | } catch (GSSException e) 88 | { 89 | if (LOGGER.isEnabled()) { 90 | LOGGER.log(50, "Could not get MIC", e); 91 | } 92 | mic = null; 93 | } 94 | 95 | if(mic==null) 96 | { 97 | return null; 98 | } 99 | 100 | tw = new TypesWriter(); 101 | tw.writeByte(Packets.SSH_MSG_USERAUTH_GSSAPI_MIC); 102 | tw.writeString(mic, 0, mic.length); 103 | 104 | payload = tw.getBytes(); 105 | 106 | return payload; 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/packets/PacketWindowChange.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.packets; 2 | 3 | /** 4 | * Indicates that that size of the terminal (window) size has changed on the client side. 5 | * 6 | * See section 6.7 of RFC 4254. 7 | * 8 | * @author Kohsuke Kawaguchi 9 | */ 10 | public class PacketWindowChange { 11 | byte[] payload; 12 | 13 | public int recipientChannelID; 14 | public int character_width; 15 | public int character_height; 16 | public int pixel_width; 17 | public int pixel_height; 18 | 19 | public PacketWindowChange(int recipientChannelID, 20 | int character_width, int character_height, int pixel_width, int pixel_height) 21 | { 22 | this.recipientChannelID = recipientChannelID; 23 | this.character_width = character_width; 24 | this.character_height = character_height; 25 | this.pixel_width = pixel_width; 26 | this.pixel_height = pixel_height; 27 | } 28 | 29 | public byte[] getPayload() 30 | { 31 | if (payload == null) 32 | { 33 | TypesWriter tw = new TypesWriter(); 34 | tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST); 35 | tw.writeUINT32(recipientChannelID); 36 | tw.writeString("window-change"); 37 | tw.writeBoolean(false); 38 | tw.writeUINT32(character_width); 39 | tw.writeUINT32(character_height); 40 | tw.writeUINT32(pixel_width); 41 | tw.writeUINT32(pixel_height); 42 | 43 | payload = tw.getBytes(); 44 | } 45 | return payload; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/sftp/AttrTextHints.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.sftp; 3 | 4 | /** 5 | * 6 | * Values for the 'text-hint' field in the SFTP ATTRS data type. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: AttrTextHints.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | * 11 | */ 12 | public class AttrTextHints 13 | { 14 | /** 15 | * The server knows the file is a text file, and should be opened 16 | * using the SSH_FXF_ACCESS_TEXT_MODE flag. 17 | */ 18 | public static final int SSH_FILEXFER_ATTR_KNOWN_TEXT = 0x00; 19 | 20 | /** 21 | * The server has applied a heuristic or other mechanism and 22 | * believes that the file should be opened with the 23 | * SSH_FXF_ACCESS_TEXT_MODE flag. 24 | */ 25 | public static final int SSH_FILEXFER_ATTR_GUESSED_TEXT = 0x01; 26 | 27 | /** 28 | * The server knows the file has binary content. 29 | */ 30 | public static final int SSH_FILEXFER_ATTR_KNOWN_BINARY = 0x02; 31 | 32 | /** 33 | * The server has applied a heuristic or other mechanism and 34 | * believes has binary content, and should not be opened with the 35 | * SSH_FXF_ACCESS_TEXT_MODE flag. 36 | */ 37 | public static final int SSH_FILEXFER_ATTR_GUESSED_BINARY = 0x03; 38 | } 39 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/sftp/AttribPermissions.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.sftp; 3 | 4 | /** 5 | * 6 | * Permissions for the 'permissions' field in the SFTP ATTRS data type. 7 | *

8 | * "The 'permissions' field contains a bit mask specifying file permissions. 9 | * These permissions correspond to the st_mode field of the stat structure 10 | * defined by POSIX [IEEE.1003-1.1996]." 11 | * 12 | * @author Christian Plattner, plattner@trilead.com 13 | * @version $Id: AttribPermissions.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 14 | * 15 | */ 16 | public class AttribPermissions 17 | { 18 | /* Octal values! */ 19 | 20 | public static final int S_IRUSR = 0400; 21 | public static final int S_IWUSR = 0200; 22 | public static final int S_IXUSR = 0100; 23 | public static final int S_IRGRP = 0040; 24 | public static final int S_IWGRP = 0020; 25 | public static final int S_IXGRP = 0010; 26 | public static final int S_IROTH = 0004; 27 | public static final int S_IWOTH = 0002; 28 | public static final int S_IXOTH = 0001; 29 | public static final int S_ISUID = 04000; 30 | public static final int S_ISGID = 02000; 31 | public static final int S_ISVTX = 01000; 32 | } 33 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/sftp/AttribTypes.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.sftp; 3 | 4 | /** 5 | * 6 | * Types for the 'type' field in the SFTP ATTRS data type. 7 | *

8 | * "On a POSIX system, these values would be derived from the mode field 9 | * of the stat structure. SPECIAL should be used for files that are of 10 | * a known type which cannot be expressed in the protocol. UNKNOWN 11 | * should be used if the type is not known." 12 | * 13 | * @author Christian Plattner, plattner@trilead.com 14 | * @version $Id: AttribTypes.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 15 | * 16 | */ 17 | public class AttribTypes 18 | { 19 | public static final int SSH_FILEXFER_TYPE_REGULAR = 1; 20 | public static final int SSH_FILEXFER_TYPE_DIRECTORY = 2; 21 | public static final int SSH_FILEXFER_TYPE_SYMLINK = 3; 22 | public static final int SSH_FILEXFER_TYPE_SPECIAL = 4; 23 | public static final int SSH_FILEXFER_TYPE_UNKNOWN = 5; 24 | public static final int SSH_FILEXFER_TYPE_SOCKET = 6; 25 | public static final int SSH_FILEXFER_TYPE_CHAR_DEVICE = 7; 26 | public static final int SSH_FILEXFER_TYPE_BLOCK_DEVICE = 8; 27 | public static final int SSH_FILEXFER_TYPE_FIFO = 9; 28 | } 29 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/sftp/Packet.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.sftp; 3 | 4 | /** 5 | * 6 | * SFTP Paket Types 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: Packet.java,v 1.1 2007/10/15 12:49:55 cplattne Exp $ 10 | * 11 | */ 12 | public class Packet 13 | { 14 | public static final int SSH_FXP_INIT = 1; 15 | public static final int SSH_FXP_VERSION = 2; 16 | public static final int SSH_FXP_OPEN = 3; 17 | public static final int SSH_FXP_CLOSE = 4; 18 | public static final int SSH_FXP_READ = 5; 19 | public static final int SSH_FXP_WRITE = 6; 20 | public static final int SSH_FXP_LSTAT = 7; 21 | public static final int SSH_FXP_FSTAT = 8; 22 | public static final int SSH_FXP_SETSTAT = 9; 23 | public static final int SSH_FXP_FSETSTAT = 10; 24 | public static final int SSH_FXP_OPENDIR = 11; 25 | public static final int SSH_FXP_READDIR = 12; 26 | public static final int SSH_FXP_REMOVE = 13; 27 | public static final int SSH_FXP_MKDIR = 14; 28 | public static final int SSH_FXP_RMDIR = 15; 29 | public static final int SSH_FXP_REALPATH = 16; 30 | public static final int SSH_FXP_STAT = 17; 31 | public static final int SSH_FXP_RENAME = 18; 32 | public static final int SSH_FXP_READLINK = 19; 33 | public static final int SSH_FXP_SYMLINK = 20; 34 | 35 | public static final int SSH_FXP_STATUS = 101; 36 | public static final int SSH_FXP_HANDLE = 102; 37 | public static final int SSH_FXP_DATA = 103; 38 | public static final int SSH_FXP_NAME = 104; 39 | public static final int SSH_FXP_ATTRS = 105; 40 | 41 | public static final int SSH_FXP_EXTENDED = 200; 42 | public static final int SSH_FXP_EXTENDED_REPLY = 201; 43 | } 44 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/signature/DSAPrivateKey.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.signature; 2 | 3 | import java.math.BigInteger; 4 | 5 | /** 6 | * DSAPrivateKey. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: DSAPrivateKey.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 10 | * @deprecated use {@link java.security.interfaces.DSAPrivateKey} 11 | * @see java.security.interfaces.DSAPrivateKey 12 | */ 13 | @Deprecated 14 | public class DSAPrivateKey 15 | { 16 | private BigInteger p; 17 | private BigInteger q; 18 | private BigInteger g; 19 | private BigInteger x; 20 | private BigInteger y; 21 | 22 | public DSAPrivateKey(BigInteger p, BigInteger q, BigInteger g, 23 | BigInteger y, BigInteger x) 24 | { 25 | this.p = p; 26 | this.q = q; 27 | this.g = g; 28 | this.y = y; 29 | this.x = x; 30 | } 31 | 32 | public BigInteger getP() 33 | { 34 | return p; 35 | } 36 | 37 | public BigInteger getQ() 38 | { 39 | return q; 40 | } 41 | 42 | public BigInteger getG() 43 | { 44 | return g; 45 | } 46 | 47 | public BigInteger getY() 48 | { 49 | return y; 50 | } 51 | 52 | public BigInteger getX() 53 | { 54 | return x; 55 | } 56 | 57 | public DSAPublicKey getPublicKey() 58 | { 59 | return new DSAPublicKey(p, q, g, y); 60 | } 61 | } -------------------------------------------------------------------------------- /src/com/trilead/ssh2/signature/DSAPublicKey.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.signature; 2 | 3 | import java.math.BigInteger; 4 | 5 | /** 6 | * DSAPublicKey. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: DSAPublicKey.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 10 | * @deprecated use {@link java.security.interfaces.DSAPublicKey} 11 | * @see java.security.interfaces.DSAPublicKey 12 | */ 13 | public class DSAPublicKey 14 | { 15 | private BigInteger p; 16 | private BigInteger q; 17 | private BigInteger g; 18 | private BigInteger y; 19 | 20 | public DSAPublicKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y) 21 | { 22 | this.p = p; 23 | this.q = q; 24 | this.g = g; 25 | this.y = y; 26 | } 27 | 28 | public BigInteger getP() 29 | { 30 | return p; 31 | } 32 | 33 | public BigInteger getQ() 34 | { 35 | return q; 36 | } 37 | 38 | public BigInteger getG() 39 | { 40 | return g; 41 | } 42 | 43 | public BigInteger getY() 44 | { 45 | return y; 46 | } 47 | } -------------------------------------------------------------------------------- /src/com/trilead/ssh2/signature/DSASignature.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.signature; 2 | 3 | import java.math.BigInteger; 4 | 5 | /** 6 | * DSASignature. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: DSASignature.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 10 | * @deprecated signatures are now stored in ray byte[] form. 11 | */ 12 | @Deprecated 13 | public class DSASignature 14 | { 15 | private BigInteger r; 16 | private BigInteger s; 17 | 18 | public DSASignature(BigInteger r, BigInteger s) 19 | { 20 | this.r = r; 21 | this.s = s; 22 | } 23 | 24 | public BigInteger getR() 25 | { 26 | return r; 27 | } 28 | 29 | public BigInteger getS() 30 | { 31 | return s; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/signature/KeyAlgorithm.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.signature; 2 | 3 | import com.trilead.ssh2.crypto.CertificateDecoder; 4 | 5 | import java.io.IOException; 6 | import java.security.GeneralSecurityException; 7 | import java.security.PrivateKey; 8 | import java.security.Provider; 9 | import java.security.PublicKey; 10 | import java.security.SecureRandom; 11 | import java.security.Signature; 12 | import java.util.List; 13 | 14 | /** 15 | * @author Michael Clarke 16 | */ 17 | public abstract class KeyAlgorithm { 18 | 19 | private final String signatureAlgorithm; 20 | private final String keyFormat; 21 | private final Class keyType; 22 | private final Provider provider; 23 | 24 | protected KeyAlgorithm(String signatureAlgorithm, String keyFormat, Class keyType) { 25 | this(signatureAlgorithm, keyFormat, keyType, null); 26 | } 27 | 28 | protected KeyAlgorithm(String signatureAlgorithm, String keyFormat, Class keyType, Provider provider) { 29 | super(); 30 | this.signatureAlgorithm = signatureAlgorithm; 31 | this.keyFormat = keyFormat; 32 | this.keyType = keyType; 33 | this.provider = provider; 34 | } 35 | 36 | public byte[] generateSignature(byte[] message, R pk, SecureRandom rnd) throws IOException { 37 | try { 38 | Signature signature = (null == provider ? Signature.getInstance(signatureAlgorithm) : Signature.getInstance(signatureAlgorithm, provider)); 39 | signature.initSign(pk, rnd); 40 | signature.update(message); 41 | return signature.sign(); 42 | } catch (GeneralSecurityException ex) { 43 | throw new IOException("Could not generate signature", ex); 44 | } 45 | } 46 | 47 | public boolean verifySignature(byte[] message, byte[] ds, U dpk) throws IOException { 48 | try { 49 | Signature signature = (null == provider ? Signature.getInstance(signatureAlgorithm) : Signature.getInstance(signatureAlgorithm, provider)); 50 | signature.initVerify(dpk); 51 | signature.update(message); 52 | return signature.verify(ds); 53 | } catch (GeneralSecurityException ex) { 54 | throw new IOException("Could not verify signature", ex); 55 | } 56 | } 57 | 58 | public String getKeyFormat() { 59 | return keyFormat; 60 | } 61 | 62 | public abstract byte[] encodeSignature(byte[] signature) throws IOException; 63 | 64 | public abstract byte[] decodeSignature(byte[] encodedSignature) throws IOException; 65 | 66 | public abstract byte[] encodePublicKey(U publicKey) throws IOException; 67 | 68 | public abstract PublicKey decodePublicKey(byte[] encodedPublicKey) throws IOException; 69 | 70 | public abstract List getCertificateDecoders(); 71 | 72 | public boolean supportsKey(PrivateKey key) { 73 | return keyType.isAssignableFrom(key.getClass()); 74 | } 75 | 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/signature/KeyAlgorithmManager.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.signature; 2 | 3 | import java.security.GeneralSecurityException; 4 | import java.security.KeyFactory; 5 | import java.security.PrivateKey; 6 | import java.security.PublicKey; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | /** 13 | * @author Michael Clarke 14 | */ 15 | public final class KeyAlgorithmManager { 16 | 17 | private static final Collection> supportedAlgorithms = buildSupportAlgorithmsList(); 18 | 19 | private KeyAlgorithmManager() { 20 | super(); 21 | // static access only 22 | } 23 | 24 | public static Collection> getSupportedAlgorithms() { 25 | return supportedAlgorithms; 26 | } 27 | 28 | private static Collection> buildSupportAlgorithmsList() { 29 | List> algorithms = new ArrayList<>(); 30 | algorithms.add(new ED25519KeyAlgorithm()); 31 | 32 | try { 33 | KeyFactory.getInstance("EC"); 34 | algorithms.add(new ECDSAKeyAlgorithm.ECDSASha2Nistp521()); 35 | algorithms.add(new ECDSAKeyAlgorithm.ECDSASha2Nistp384()); 36 | algorithms.add(new ECDSAKeyAlgorithm.ECDSASha2Nistp256()); 37 | } catch (GeneralSecurityException ex) { 38 | // we don't use ECDSA algorithms in this case 39 | } 40 | // https://tools.ietf.org/html/rfc8332 41 | algorithms.add(new RSAKeyAlgorithm("SHA256withRSA", "rsa-sha2-256")); 42 | algorithms.add(new RSAKeyAlgorithm("SHA512withRSA", "rsa-sha2-512")); 43 | 44 | 45 | // TODO: remove SHA-1 support soon 46 | algorithms.add(new RSAKeyAlgorithm()); 47 | algorithms.add(new DSAKeyAlgorithm()); 48 | 49 | return (Collection) Collections.unmodifiableCollection(algorithms); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/signature/RSAPrivateKey.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.signature; 2 | 3 | import java.math.BigInteger; 4 | import java.security.KeyPair; 5 | import java.security.KeyFactory; 6 | import java.security.NoSuchAlgorithmException; 7 | import java.security.GeneralSecurityException; 8 | import java.security.spec.RSAPublicKeySpec; 9 | import java.security.spec.RSAPrivateKeySpec; 10 | import java.security.spec.InvalidKeySpecException; 11 | 12 | /** 13 | * RSAPrivateKey. 14 | * 15 | * @author Christian Plattner, plattner@trilead.com 16 | * @version $Id: RSAPrivateKey.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 17 | * @deprecated use {@link java.security.interfaces.RSAPrivateKey} 18 | * @see java.security.interfaces.RSAPrivateKey 19 | */ 20 | public class RSAPrivateKey 21 | { 22 | private BigInteger d; 23 | private BigInteger e; 24 | private BigInteger n; 25 | 26 | public RSAPrivateKey(BigInteger d, BigInteger e, BigInteger n) 27 | { 28 | this.d = d; 29 | this.e = e; 30 | this.n = n; 31 | } 32 | 33 | public BigInteger getD() 34 | { 35 | return d; 36 | } 37 | 38 | public BigInteger getE() 39 | { 40 | return e; 41 | } 42 | 43 | public BigInteger getN() 44 | { 45 | return n; 46 | } 47 | 48 | public RSAPublicKey getPublicKey() 49 | { 50 | return new RSAPublicKey(e, n); 51 | } 52 | 53 | /** 54 | * Converts this to a JCE API representation of the RSA key pair. 55 | * 56 | * @return the key pair 57 | * @throws GeneralSecurityException the general security exception 58 | */ 59 | public KeyPair toJCEKeyPair() throws GeneralSecurityException { 60 | KeyFactory kf = KeyFactory.getInstance("RSA"); 61 | return new KeyPair( 62 | kf.generatePublic(new RSAPublicKeySpec(getN(), getE())), 63 | kf.generatePrivate(new RSAPrivateKeySpec(getN(), getD()))); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/signature/RSAPublicKey.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.signature; 2 | 3 | import java.math.BigInteger; 4 | 5 | /** 6 | * RSAPublicKey. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id: RSAPublicKey.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 10 | * @deprecated use {@link java.security.interfaces.RSAPublicKey} 11 | * @see java.security.interfaces.RSAPublicKey 12 | */ 13 | public class RSAPublicKey 14 | { 15 | BigInteger e; 16 | BigInteger n; 17 | 18 | public RSAPublicKey(BigInteger e, BigInteger n) 19 | { 20 | this.e = e; 21 | this.n = n; 22 | } 23 | 24 | public BigInteger getE() 25 | { 26 | return e; 27 | } 28 | 29 | public BigInteger getN() 30 | { 31 | return n; 32 | } 33 | } -------------------------------------------------------------------------------- /src/com/trilead/ssh2/signature/RSASignature.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.signature; 3 | 4 | import java.math.BigInteger; 5 | 6 | 7 | /** 8 | * RSASignature. 9 | * 10 | * @author Christian Plattner, plattner@trilead.com 11 | * @version $Id: RSASignature.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 12 | * @deprecated signatures are now stored as raw byte arrays 13 | */ 14 | @Deprecated 15 | public class RSASignature 16 | { 17 | BigInteger s; 18 | 19 | public BigInteger getS() 20 | { 21 | return s; 22 | } 23 | 24 | public RSASignature(BigInteger s) 25 | { 26 | this.s = s; 27 | } 28 | } -------------------------------------------------------------------------------- /src/com/trilead/ssh2/transport/Acceptor.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | import java.io.IOException; 4 | import java.net.SocketTimeoutException; 5 | import java.net.Socket; 6 | import java.net.ServerSocket; 7 | 8 | import com.trilead.ssh2.Connection; 9 | import com.trilead.ssh2.ConnectionInfo; 10 | import com.trilead.ssh2.ServerHostKeyVerifier; 11 | 12 | /** 13 | * This class is similar to {@link Connection} but is 14 | * used to accept incoming connections from clients. 15 | * Example use-cases are 'NETCONF Call Home' or 16 | * 'reverse SSH'. 17 | * 18 | */ 19 | public class Acceptor extends Connection{ 20 | 21 | /** 22 | * Constuctor 23 | * @param hostname is the hostname that this class is running on. 24 | * @param port is the port that is used for incoming connections. 25 | */ 26 | public Acceptor(String hostname,int port){ 27 | super(hostname,port); 28 | } 29 | /** 30 | * This method reuses most of methods for {@link Connection#connect(ServerHostKeyVerifier, int, int, int)}. Parameters and descriptions applies here too. 31 | * The main difference between 32 | * this class and {@link Connection} is that we use {@link ServerSocket} and we bind with the port specified in constructor. The {@link ServerSocket#accept()} 33 | * will wait (blocks) for an incoming connection for max {@param connectTimeout} . If connection is completed a {@link Socket} is returned and we set a timeout of this socket using 34 | * {@param readTimeout}. 35 | * 36 | * @throws SocketTimeoutException If there is no incoming connection within {@param connectTimeout}. 37 | * 38 | */ 39 | public ConnectionInfo accept(ServerHostKeyVerifier verifier, int connectTimeout, int readTimeout, int kexTimeout) throws IOException{ 40 | if (tm != null) { 41 | throw new IOException("Connection to " + hostname + " is already in connected state!"); 42 | } 43 | if (connectTimeout < 0) 44 | throw new IllegalArgumentException("connectTimeout must be non-negative!"); 45 | 46 | if (kexTimeout < 0) 47 | throw new IllegalArgumentException("kexTimeout must be non-negative!"); 48 | 49 | tm = new TransportManager(hostname, port); 50 | tm.setEnabledCallHomeSSH(true); 51 | 52 | tm.setConnectionMonitors(connectionMonitors); 53 | try { 54 | tm.initialize(cryptoWishList, verifier, dhgexpara, connectTimeout, readTimeout, getOrCreateSecureRND(), 55 | proxyData); 56 | } catch (SocketTimeoutException ste) { 57 | throw (SocketTimeoutException) new SocketTimeoutException( 58 | "The accept() operation on the socket timed out.").initCause(ste); 59 | } 60 | 61 | tm.setTcpNoDelay(tcpNoDelay); 62 | 63 | /* Wait until first KEX has finished */ 64 | return tm.getConnectionInfo(1); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/transport/KexParameters.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | /** 4 | * KexParameters. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: KexParameters.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 8 | */ 9 | public class KexParameters 10 | { 11 | public byte[] cookie; 12 | public String[] kex_algorithms; 13 | public String[] server_host_key_algorithms; 14 | public String[] encryption_algorithms_client_to_server; 15 | public String[] encryption_algorithms_server_to_client; 16 | public String[] mac_algorithms_client_to_server; 17 | public String[] mac_algorithms_server_to_client; 18 | public String[] compression_algorithms_client_to_server; 19 | public String[] compression_algorithms_server_to_client; 20 | public String[] languages_client_to_server; 21 | public String[] languages_server_to_client; 22 | public boolean first_kex_packet_follows; 23 | public int reserved_field1; 24 | } 25 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/transport/KexState.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | 4 | import java.math.BigInteger; 5 | 6 | import com.trilead.ssh2.DHGexParameters; 7 | import com.trilead.ssh2.crypto.dh.DhGroupExchange; 8 | import com.trilead.ssh2.crypto.dh.GenericDhExchange; 9 | import com.trilead.ssh2.packets.PacketKexInit; 10 | 11 | /** 12 | * KexState. 13 | * 14 | * @author Christian Plattner, plattner@trilead.com 15 | * @version $Id: KexState.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 16 | */ 17 | public class KexState 18 | { 19 | public PacketKexInit localKEX; 20 | public PacketKexInit remoteKEX; 21 | public NegotiatedParameters np; 22 | public int state = 0; 23 | 24 | public BigInteger K; 25 | public byte[] H; 26 | 27 | public byte[] hostkey; 28 | 29 | public GenericDhExchange dhx; 30 | public DhGroupExchange dhgx; 31 | public DHGexParameters dhgexParameters; 32 | private String hashAlgorithm; 33 | 34 | public void setHashAlgorithm(String hashAlgorithm) { 35 | this.hashAlgorithm = hashAlgorithm; 36 | } 37 | 38 | public String getHashAlgorithm() { 39 | return hashAlgorithm; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/transport/MessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * MessageHandler. 7 | * 8 | * @author Christian Plattner, plattner@trilead.com 9 | * @version $Id : MessageHandler.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 10 | */ 11 | public interface MessageHandler 12 | { 13 | /** 14 | * Handle message. 15 | * 16 | * @param msg the msg 17 | * @param msglen the msglen 18 | * @throws IOException the io exception 19 | */ 20 | public void handleMessage(byte[] msg, int msglen) throws IOException; 21 | 22 | /** 23 | * Called to inform that no more messages will be delivered. 24 | * 25 | * @param cause For diagnosis, the reason that caused the transport to close down. 26 | * @throws IOException the io exception 27 | */ 28 | public void handleEndMessage(Throwable cause) throws IOException; 29 | } 30 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/transport/NegotiateException.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | /** 4 | * NegotiateException. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: NegotiateException.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $ 8 | */ 9 | public class NegotiateException extends Exception 10 | { 11 | public NegotiateException(String message) { 12 | super(message); 13 | } 14 | 15 | private static final long serialVersionUID = 3689910669428143157L; 16 | } 17 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/transport/NegotiatedParameters.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | /** 4 | * NegotiatedParameters. 5 | * 6 | * @author Christian Plattner, plattner@trilead.com 7 | * @version $Id: NegotiatedParameters.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 8 | */ 9 | public class NegotiatedParameters 10 | { 11 | public boolean guessOK; 12 | public String kex_algo; 13 | public String server_host_key_algo; 14 | public String enc_algo_client_to_server; 15 | public String enc_algo_server_to_client; 16 | public String mac_algo_client_to_server; 17 | public String mac_algo_server_to_client; 18 | public String comp_algo_client_to_server; 19 | public String comp_algo_server_to_client; 20 | public String lang_client_to_server; 21 | public String lang_server_to_client; 22 | } 23 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/util/IOUtils.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.util; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | 6 | /** 7 | * @author Kohsuke Kawaguchi 8 | */ 9 | public class IOUtils { 10 | public static void closeQuietly(Closeable c) { 11 | try { 12 | c.close(); 13 | } catch (IOException e) { 14 | // ignore error 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/com/trilead/ssh2/util/Tokenizer.java: -------------------------------------------------------------------------------- 1 | 2 | package com.trilead.ssh2.util; 3 | 4 | /** 5 | * Tokenizer. Why? Because StringTokenizer is not available in J2ME. 6 | * 7 | * @author Christian Plattner, plattner@trilead.com 8 | * @version $Id: Tokenizer.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $ 9 | */ 10 | public class Tokenizer 11 | { 12 | /** 13 | * Exists because StringTokenizer is not available in J2ME. 14 | * Returns an array with at least 1 entry. 15 | * 16 | * @param source must be non-null 17 | * @param delimiter delimiter 18 | * @return an array of Strings 19 | */ 20 | public static String[] parseTokens(String source, char delimiter) 21 | { 22 | int numtoken = 1; 23 | 24 | for (int i = 0; i < source.length(); i++) 25 | { 26 | if (source.charAt(i) == delimiter) 27 | numtoken++; 28 | } 29 | 30 | String list[] = new String[numtoken]; 31 | int nextfield = 0; 32 | 33 | for (int i = 0; i < numtoken; i++) 34 | { 35 | if (nextfield >= source.length()) 36 | { 37 | list[i] = ""; 38 | } 39 | else 40 | { 41 | int idx = source.indexOf(delimiter, nextfield); 42 | if (idx == -1) 43 | idx = source.length(); 44 | list[i] = source.substring(nextfield, idx); 45 | nextfield = idx + 1; 46 | } 47 | } 48 | 49 | return list; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/spotbugs/excludesFilter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /test/Receiver.java: -------------------------------------------------------------------------------- 1 | import com.trilead.ssh2.Connection; 2 | import com.trilead.ssh2.Session; 3 | import com.trilead.ssh2.channel.ConnectionRule; 4 | 5 | import java.io.DataInputStream; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * Test the throughput of the data retrieval. 10 | * 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public class Receiver { 14 | public static void main(String[] args) throws Exception { 15 | Connection connection = new ConnectionRule().getConnection(); 16 | final Session session = connection.openSession(); 17 | 18 | session.execCommand("cat /dev/zero"); 19 | session.getStdin().close(); 20 | session.getStderr().close(); 21 | 22 | byte[] buf = new byte[10*1024*1024]; 23 | DataInputStream in = new DataInputStream(session.getStdout()); 24 | 25 | int j=0; 26 | while (true) { 27 | for (int i=0; i<5; i++) { 28 | long start = System.nanoTime(); 29 | in.readFully(buf); 30 | long end = System.nanoTime(); 31 | System.out.println("Took "+ TimeUnit.NANOSECONDS.toMillis(end-start)); 32 | } 33 | 34 | int sz = 1024 * 1024 * (j++ % 2 == 0 ? 4 : 1); 35 | session.setWindowSize(sz); 36 | System.out.println("Adjusting size to "+sz); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /test/Sender.java: -------------------------------------------------------------------------------- 1 | import com.trilead.ssh2.Connection; 2 | import com.trilead.ssh2.Session; 3 | import com.trilead.ssh2.channel.ConnectionRule; 4 | 5 | import java.util.Random; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * Test the throughput of the data transmission. 10 | * 11 | * @author Kohsuke Kawaguchi 12 | */ 13 | public class Sender { 14 | public static void main(String[] args) throws Exception { 15 | Connection connection = new ConnectionRule().getConnection(); 16 | final Session session = connection.openSession(); 17 | 18 | session.execCommand("cat > /dev/null"); 19 | session.getStdout().close(); 20 | session.getStderr().close(); 21 | 22 | Random r = new Random(); 23 | byte[] buf = new byte[10*1024*1024]; 24 | 25 | while (true) { 26 | r.nextBytes(buf); 27 | long start = System.nanoTime(); 28 | session.getStdin().write(buf); 29 | long end = System.nanoTime(); 30 | System.out.println("Took "+TimeUnit.NANOSECONDS.toMillis(end-start)); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/com/trilead/ssh2/KerberosTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import java.io.IOException; 7 | 8 | import static org.junit.Assert.assertFalse; 9 | import static org.junit.Assert.assertTrue; 10 | 11 | /* 12 | This is a test class for the Kerberos authentication, it requires an Kerberos environment 13 | it was tested with the environment defined here https://github.com/criteo/kerberos-docker.git 14 | 15 | "KRB5_HOST=krb5-service-instance-com" 16 | "KRB5_USER=bob" 17 | 18 | @author Kuisathaverat 19 | */ 20 | public class KerberosTest { 21 | 22 | @Before 23 | public void beforeMethod() { 24 | org.junit.Assume.assumeTrue(System.getenv("KRB5_HOST") != null); 25 | org.junit.Assume.assumeTrue(System.getenv("KRB5_USER") != null); 26 | } 27 | 28 | @Test 29 | public void testConnection() throws IOException { 30 | String host = System.getenv("KRB5_HOST"); 31 | String user = System.getenv("KRB5_USER"); 32 | Connection con = new Connection(host); 33 | con.connect(); 34 | assertTrue(con.authenticateWithGssapiWithMic(user)); 35 | } 36 | 37 | @Test 38 | public void testConnectionFAIL() throws IOException { 39 | String host = System.getenv("KRB5_HOST"); 40 | String user = System.getenv("KRB5_USER"); 41 | Connection con = new Connection(host); 42 | con.connect(); 43 | assertFalse(con.authenticateWithGssapiWithMic(user + "NotExists")); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/com/trilead/ssh2/SFTPClientTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2; 2 | 3 | import com.trilead.ssh2.channel.ConnectionRule; 4 | import com.trilead.ssh2.jenkins.SFTPClient; 5 | import org.apache.commons.io.IOUtils; 6 | import org.junit.Rule; 7 | import org.junit.Test; 8 | 9 | import java.io.InputStream; 10 | import java.io.OutputStream; 11 | 12 | import static org.junit.Assert.assertNotNull; 13 | import static org.junit.Assert.assertTrue; 14 | 15 | public class SFTPClientTest { 16 | public static final String TMP_TEST = "/tmp/test"; 17 | public static final String PATH_FILE = TMP_TEST + "/file"; 18 | public static final int POSIX_PERMISSION = 0700; 19 | public static final String FILE_CONTENT = "test"; 20 | 21 | @Rule 22 | public ConnectionRule con = new ConnectionRule(); 23 | 24 | @Test 25 | public void connectionTest() throws Exception { 26 | SFTPClient sftpClient = new SFTPClient(con.getConnection()); 27 | sftpClient.mkdirs(TMP_TEST, POSIX_PERMISSION); 28 | 29 | OutputStream out = sftpClient.writeToFile(PATH_FILE); 30 | assertNotNull(out); 31 | IOUtils.write(FILE_CONTENT, out); 32 | out.close(); 33 | 34 | InputStream in = sftpClient.read(PATH_FILE); 35 | assertNotNull(in); 36 | assertNotNull(IOUtils.readLines(in)); 37 | in.close(); 38 | 39 | sftpClient.chmod(PATH_FILE, POSIX_PERMISSION); 40 | assertTrue(sftpClient.exists(PATH_FILE)); 41 | sftpClient.close(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/com/trilead/ssh2/channel/ConnectionRule.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.channel; 2 | 3 | import com.trilead.ssh2.Connection; 4 | import org.apache.commons.io.IOUtils; 5 | import org.junit.Rule; 6 | import org.junit.rules.ExternalResource; 7 | import org.testcontainers.containers.GenericContainer; 8 | 9 | import static org.junit.Assert.assertTrue; 10 | 11 | /** 12 | * Connect to a remote SSH server 13 | * 14 | * @author Kohsuke Kawaguchi 15 | */ 16 | public class ConnectionRule extends ExternalResource { 17 | public static final String USER = "jenkins"; 18 | public static final int SSH_PORT = 22; 19 | 20 | @Rule 21 | public GenericContainer sshContainer = new GenericContainer("jenkins/ssh-agent"); 22 | 23 | private Connection connection; 24 | 25 | public Connection getConnection() throws Exception { 26 | if (connection==null) // in case this is used outside JUnit 27 | before(); 28 | return connection; 29 | } 30 | 31 | @Override 32 | public void before() throws Exception { 33 | String publicKey = IOUtils.toString(getClass().getResourceAsStream("../crypto/cipher/key.pem.pub")); 34 | String privateKey = IOUtils.toString(getClass().getResourceAsStream("../crypto/cipher/key.pem")); 35 | sshContainer.withEnv("JENKINS_AGENT_SSH_PUBKEY", publicKey) 36 | .withExposedPorts(SSH_PORT) 37 | .start(); 38 | 39 | int port = sshContainer.getMappedPort(SSH_PORT); 40 | String ip = sshContainer.getContainerIpAddress(); 41 | 42 | connection = new Connection(ip, port); 43 | connection.enableDebugging(true, null); 44 | connection.setTCPNoDelay(true); 45 | connection.connect(); 46 | 47 | connection.authenticateWithPublicKey(USER, privateKey.toCharArray(),null); 48 | assertTrue(connection.isAuthenticationComplete()); 49 | } 50 | 51 | @Override 52 | public void after() { 53 | if (connection!=null) 54 | connection.close(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/com/trilead/ssh2/channel/RoundtripTest.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.channel; 2 | 3 | import com.trilead.ssh2.Session; 4 | import org.apache.commons.io.IOUtils; 5 | import org.junit.Assert; 6 | import org.junit.Rule; 7 | import org.junit.Test; 8 | 9 | import java.io.ByteArrayOutputStream; 10 | import java.util.Random; 11 | import java.util.concurrent.Callable; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.Executors; 14 | import java.util.concurrent.Future; 15 | 16 | /** 17 | * @author Kohsuke Kawaguchi 18 | */ 19 | public class RoundtripTest { 20 | @Rule 21 | public ConnectionRule con = new ConnectionRule(); 22 | 23 | @Test 24 | public void dataXfer() throws Exception { 25 | final Session s = con.getConnection().openSession(); 26 | s.execCommand("cat"); 27 | 28 | s.getStderr().close(); 29 | 30 | ExecutorService es = Executors.newFixedThreadPool(1); 31 | Future reader = es.submit(new Callable() { 32 | public byte[] call() throws Exception { 33 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 34 | IOUtils.copy(s.getStdout(), baos); 35 | return baos.toByteArray(); 36 | } 37 | }); 38 | 39 | byte[] data = new byte[10*1024*1024]; 40 | Random r = new Random(); 41 | r.nextBytes(data); 42 | 43 | int inc; 44 | for (int i=0; i 13 | * org.slf4j 14 | * slf4j-jdk14 15 | * 2.0.0 16 | * 17 | * } 18 | * This class only setup JUL and then configures logging 19 | * to console. 20 | * 21 | * 22 | */ 23 | class JULLoggerSetup { 24 | public static void setupJULLogger() { 25 | Logger rootLogger = Logger.getLogger(""); 26 | rootLogger.setLevel(Level.ALL); // Set global logging level 27 | 28 | // Remove default handlers 29 | for (var handler : rootLogger.getHandlers()) { 30 | rootLogger.removeHandler(handler); 31 | } 32 | 33 | // Add a ConsoleHandler for JUL to print logs to the console 34 | ConsoleHandler consoleHandler = new ConsoleHandler(); 35 | consoleHandler.setLevel(Level.ALL); // Log everything 36 | consoleHandler.setFormatter(new SimpleFormatter()); // Use simple log format 37 | 38 | // Add the new handler to the root logger 39 | rootLogger.addHandler(consoleHandler); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /test/com/trilead/ssh2/transport/JulLogConsumer.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | import org.testcontainers.containers.output.OutputFrame; 4 | import org.testcontainers.containers.output.OutputFrame.OutputType; 5 | import com.trilead.ssh2.log.Logger; 6 | import java.util.function.Consumer; 7 | 8 | /** 9 | * Consumer used to get logging for testcontainers. 10 | */ 11 | class JulLogConsumer implements Consumer { 12 | private final Logger logger; 13 | 14 | // Constructor to initialize the JUL Logger 15 | public JulLogConsumer(Logger logger) { 16 | this.logger = logger; 17 | } 18 | 19 | @Override 20 | public void accept(OutputFrame outputFrame) { 21 | if (outputFrame != null) { 22 | String message = outputFrame.getUtf8String().trim(); // Get log message 23 | OutputType type = outputFrame.getType(); // Get output type (STDOUT, STDERR) 24 | 25 | // Map OutputFrame types to appropriate log levels 26 | if (type == OutputType.STDOUT) { 27 | logger.log(800,message); // Standard output as INFO logs 28 | } else if (type == OutputType.STDERR) { 29 | logger.log(900,message); // Standard error as WARNING logs 30 | } else if (type == OutputType.END) { 31 | logger.log(1000,"Container log stream closed."); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test/com/trilead/ssh2/transport/MyServerHostKeyVerifierImpl.java: -------------------------------------------------------------------------------- 1 | package com.trilead.ssh2.transport; 2 | 3 | import com.trilead.ssh2.ServerHostKeyVerifier; 4 | 5 | class MyServerHostKeyVerifierImpl implements ServerHostKeyVerifier{ 6 | 7 | @Override 8 | public boolean verifyServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey) { 9 | // Always accept any host key (Fake verifier) 10 | System.out.println("Fake HostKeyVerifier: Host " + hostname + " accepted without verification."); 11 | return true; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /test/docker/nacm.xml: -------------------------------------------------------------------------------- 1 | 2 | false 3 | 4 | -------------------------------------------------------------------------------- /test/docker/ssh_callhome.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | default-client 5 | 6 | 7 | ssh-default 8 | 9 | 10 | localhost 11 | 12 | 13 | 14 | 15 | default-key 16 | 17 | genkey 18 | 19 | 20 | 21 | 22 | default-ssh 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/docker/ssh_listen.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | default-ssh 6 | 7 | 8 | 0.0.0.0 9 | 10 | 11 | 12 | 13 | default-key 14 | 15 | genkey 16 | 17 | 18 | 19 | 20 | 21 | 22 | netconf 23 | $0$netconf 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/krb5_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # The script is used to provision a Kerberos environment an run some authentication tests againts it. 4 | # it use the enviroment defined in https://github.com/criteo/kerberos-docker.git 5 | # Author: Kuisathaverat 6 | # 7 | 8 | git clone https://github.com/criteo/kerberos-docker.git 9 | cd kerberos-docker 10 | make install 11 | cd .. 12 | docker cp . krb5-machine-instance-com:/root/trilead-ssh2 13 | docker exec -it -w "/root/trilead-ssh2" -e "KRB5_HOST=krb5-service-instance-com" -e "KRB5_USER=bob" krb5-machine-instance-com mvn clean test -Dtest=KerberosTest -------------------------------------------------------------------------------- /workflows/cd.yaml: -------------------------------------------------------------------------------- 1 | # Note: additional setup is required, see https://www.jenkins.io/redirect/continuous-delivery-of-plugins 2 | 3 | name: cd 4 | on: 5 | workflow_dispatch: 6 | check_run: 7 | types: 8 | - completed 9 | 10 | jobs: 11 | validate: 12 | runs-on: ubuntu-latest 13 | outputs: 14 | should_release: ${{ steps.verify-ci-status.outputs.result == 'success' && steps.interesting-categories.outputs.interesting == 'true' }} 15 | steps: 16 | - name: Verify CI status 17 | uses: jenkins-infra/verify-ci-status-action@v1.2.0 18 | id: verify-ci-status 19 | with: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | output_result: true 22 | 23 | - name: Release Drafter 24 | uses: release-drafter/release-drafter@v5 25 | if: steps.verify-ci-status.outputs.result == 'success' 26 | with: 27 | name: next 28 | tag: next 29 | version: next 30 | env: 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | 33 | - name: Check interesting categories 34 | uses: jenkins-infra/interesting-category-action@v1.0.0 35 | id: interesting-categories 36 | if: steps.verify-ci-status.outputs.result == 'success' 37 | with: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | 40 | release: 41 | runs-on: ubuntu-latest 42 | needs: [validate] 43 | if: needs.validate.outputs.should_release == 'true' 44 | steps: 45 | - name: Check out 46 | uses: actions/checkout@v2.3.4 47 | with: 48 | fetch-depth: 0 49 | - name: Set up JDK 8 50 | uses: actions/setup-java@v2 51 | with: 52 | distribution: 'adopt' 53 | java-version: 8 54 | - name: Release 55 | uses: jenkins-infra/jenkins-maven-cd-action@v1.2.0 56 | with: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} 59 | MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }} --------------------------------------------------------------------------------