UnknownHostKey Exception in Accessing GitHub Securely - java

I'm using jgit to access a repository in GitHub securely. I did the following to generate keys for secure communication between GitHub and my client code.
Generated the key pair:
ssh-keygen -t rsa
Added the public key to GitHub account with Account Settings -> SSH keys -> add SSH key
Added the private key generated in step 1 to the local host with:
ssh-add id_rsa
After doing this, when I try to access GitHub and make a clone, I still get the following error:
org.eclipse.jgit.api.errors.TransportException: git#github.com:test/test_repo.git: UnknownHostKey: github.com. RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48
at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:137)
at org.eclipse.jgit.api.CloneCommand.fetch(CloneCommand.java:178)
at org.eclipse.jgit.api.CloneCommand.call(CloneCommand.java:125)
This is the code that I used:
String localPath, remotePath;
Repository localRepo;
Git git;
localPath = <path_to_local_repository>;
remotePath = "git#github.com:test/test_repo.git";
try {
localRepo = new FileRepository(localPath + "/.git");
} catch (IOException e) {
e.printStackTrace();
}
git = new Git(localRepo);
CloneCommand cloneCmd = git.cloneRepository().
setURI(remotePath).
setDirectory(new File(localPath));
try {
cloneCmd.call();
} catch (GitAPIException e) {
log.error("git clone operation failed");
e.printStackTrace();
}
Kindly let me know the issue here and what should I do to rectify it.
Thanks.

It happens because you have no entry for github in ~/.ssh/known_hosts, and JSch used in jgit defaults to rejecting session in this case. Refer to this question for solutions: com.jcraft.jsch.JSchException: UnknownHostKey
To set the ssh session property, you need to create a session factory for jgit:
SshSessionFactory.setInstance(new JschConfigSessionFactory() {
public void configure(Host hc, Session session) {
session.setConfig("StrictHostKeyChecking", "no");
}
})
or add StrictHostKeyChecking=no to ~/.ssh/config

As this thread is first result to :
com.jcraft.jsch.JSchException: UnknownHostKey: gitservername. RSA key
fingerprint"
and the only answer, if the problem persists, is to disable StrictHostKeyChecking, which is not acceptable for security purposes.
If the problem persists, you should have a look to this answer from another thread :
https://stackoverflow.com/a/44777270/13184312
What solved the persisting problem is :
ssh-keyscan -H -t rsa gitservername >> ~/.ssh/known_hosts

Related

StrictHostChecking with JSCH API [duplicate]

I'm running a java program where I transfer a file from one folder to another, using Java SFTP. The problem I'm having is that I'm getting the following error in my Java SFTP (using JSch) :
C:\Oracle\Middleware\Oracle_Home\oracle_common\jdk\bin\javaw.exe
-server -classpath C:\JDeveloper\mywork\Java_Hello_World.adf;C:\JDeveloper\mywork\Java_Hello_World\Client\classes;C:\Users\ADMIN\Downloads\jsch-0.1.53.jar
-Djavax.net.ssl.trustStore=C:\Users\IBM_AD~1\AppData\Local\Temp\trustStore5840796204189742395.jks
FileTransfer com.jcraft.jsch.JSchException: UnknownHostKey: 127.0.0.1.
RSA key fingerprint is a2:39:3f:44:88:e9:1f:d7:d1:71:f4:85:98:fb:90:dc
at com.jcraft.jsch.Session.checkHost(Session.java:797) at
com.jcraft.jsch.Session.connect(Session.java:342) at
com.jcraft.jsch.Session.connect(Session.java:183) at
FileTransfer.main(FileTransfer.java:33) Process exited with exit code
0.
The following is my code so far:
FileTransfer fileTransfer = new FileTransfer();
JSch jsch = new JSch();
try {
String host = "127.0.0.1";
int port = 22;
String user = "user";
Session session = jsch.getSession(user, host, port);
session = jsch.getSession("username", "127.0.0.1", 22);
session.connect(); // bug here , java.net.ConnectException
ChannelSftp sftp = null;
sftp = (ChannelSftp)session.openChannel("sftp") ; //channel;
//extra config code
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
// end extra config code
sftp.rename("C:\\Users\\ADMIN\\Desktop\\Work\\ConnectOne_Bancorp\\Java_Work\\SFTP_1\\house.bmp", "C:\\Users\\ADMIN\\Desktop\\Work\\ConnectOne_Bancorp\\Java_Work\\SFTP_2\\house.bmp");
session.disconnect();
} catch (JSchException e) {
e.printStackTrace();
} catch (SftpException e) {
e.printStackTrace();
} //end-catch
My Cygwin is set up, and I checked (with netstat -a -b ) that it's running.
You are trying to skip a host key checking by setting StrictHostKeyChecking to no.
But you have to do that before the checking, i.e. before the session.connect().
Anyway, you should never do this, unless you do not care about security. The host key checking is there to protect you from man-in-the-middle attacks.
Instead, set up an expected host key to let JSch verify it.
For example:
Call JSch.setKnownHosts providing a path to a .ssh/known_hosts-like file.
To generate the .ssh/known_hosts-like file, you can use an ssh-keyscan command from OpenSSH. If you are connecting from a *nix server, you should have the command available, just run
ssh-keyscan example.com > known_hosts
It will have a format like:
example.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0hVqZOvZ7yWgie9OHdTORJVI5fJJoH1yEGamAd5G3werH0z7e9ybtq1mGUeRkJtea7bzru0ISR0EZ9HIONoGYrDmI7S+BiwpDBUKjva4mAsvzzvsy6Ogy/apkxm6Kbcml8u4wjxaOw3NKzKqeBvR3pc+nQVA+SJUZq8D2XBRd4EDUFXeLzwqwen9G7gSLGB1hJkSuRtGRfOHbLUuCKNR8RV82i3JvlSnAwb3MwN0m3WGdlJA8J+5YAg4e6JgSKrsCObZK7W1R6iuyuH1zA+dtAHyDyYVHB4FnYZPL0hgz2PSb9c+iDEiFcT/lT4/dQ+kRW6DYn66lS8peS8zCJ9CSQ==
And reference the generated known_hosts file in your JSch code.
If you are on Windows, you can get a Windows build of ssh-keyscan from Win32-OpenSSH project or Git for Windows.
Call JSch.getHostKeyRepository().add() to provide the expected host key (e.g. hard-coded, as your other credentials).
See Creating JSch HostKey instance from a public key in .pub format.
jsch version : 0.1.55
my problem solved by running :
ssh-keyscan -t rsa <HOST_NAME> >> ~/.ssh/known_hosts
ssh-keyscan -t rsa <IP_ADDRESS_OF_HOST_NAME> >> ~/.ssh/known_hosts
**in my case jsch was looking for ip address in known_hosts file
jsch.setKnownHosts(System.getProperty("user.home")+"/.ssh/known_hosts");
Aside: by "Cygwin" I assume you mean sshd or sftpd, because Cygwin itself doesn't do SSH.
Anyway, if you want Jsch client to accept any key from the host, move the .setConfig calls that sets StrictHostKeyChecking no so it is before session.connect(). Alternatively you must provide access to a store containing the correct key(s) for your hosts(s) as #Martin explains -- and you should always do that when connecting to anything other than "localhost" or possibly a machine certain to be on the same, physically-secure network segment (such as a wired LAN hub within a single room).

Java JDBC unable to connect to a Oracle database with SSL

I have configured a Oracle 11g database server to work with SSL using a wallet and self signed certificate.
Tested it with local client (sqlplus) and it works without any issues.
Now I'm trying to connect the database using Java JDBC.
Currently I'm getting an error:
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
Here is my code:
public static void main(String[] args)
{
Connection connection = null;
String url = "jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=192.168.200.191)(PORT=1522))(CONNECT_DATA=(SERVICE_NAME=VDB)))";
Properties props = new Properties();
props.setProperty("user", "dbuser");
props.setProperty("password", "dbpass");
props.setProperty("oracle.net.ssl_cipher_suites","(SSL_RSA_WITH_3DES_EDE_CBC_SHA)");
/* Load the database driver */
try
{
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
connection = DriverManager.getConnection(url,props);
if (connection != null) {
System.out.println("You made it, take control your database now!");
} else {
System.out.println("Failed to make connection!");
}
}
catch (SQLException ex) {
ex.printStackTrace();
}
}
I did some more research, and found that if the wallet is configured as 'auto_login', I can try the following:
Connection connection = null;
String url = "jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=192.168.200.191)(PORT=1522))(CONNECT_DATA=(SERVICE_NAME=VDB)))";
Properties props = new Properties();
props.setProperty("user", "dbuser");
props.setProperty("password", "dbpass");
props.setProperty("javax.net.ssl.trustStore", "C:\\oracle\\wallet\\cwallet.sso");
props.setProperty("javax.net.ssl.trustStoreType","SSO");
/* Load the database driver */
try
{
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
connection = DriverManager.getConnection(url,props);
if (connection != null) {
System.out.println("You made it, take control your database now!");
} else {
System.out.println("Failed to make connection!");
}
}
catch (SQLException ex) {
ex.printStackTrace();
}
In this case, I'm getting:
java.security.NoSuchAlgorithmException: SSO KeyStore not available
I've added 3 Jars: oraclepki.jar, osdt_cert.jar, osdt_core.jar
Attempted to run the last version of the code, getting exception:
java.lang.ClassNotFoundException: com.phaos.crypto.AuthenticationException
Perhaps I should specify the wallet location? as I did in the tnsnames.ora file? or specify the certificate CN?
Please advise, thanks.
Using services or resources that requires certificates within your application, require that you somehow trust the certificate issuer or certificate itself. In this case, I guess you will have to trust the certificate itself as it is self-signed and not issued by a well-known CA (already trusted by the trust-store bundled with the JRE you're using).
In order to do this, export the certificate that you use together with your database and locate a file called "cacerts". The file exists within your jdk-installation folder. Example:
/path/to/jdk/jre/lib/security/cacerts
The easiest thing to do, is just to import the certificate to this file (you can use some commands to do this, or if you're lazy like me - download KSE and click the Import-button: http://keystore-explorer.org/). You may also specify your own trust-store using properties mentioned here:
https://docs.oracle.com/cd/E19830-01/819-4712/ablqw/index.html
If you choose to use a custom trust-store, you have more control regarding the cacerts - as if you're choosing to update to a newer jdk installation, that installation will use the cacerts issued with the jdk :-).
Anyway. Hope it helped a bit.
The JVM tries to establish a chain of trust of the server's certificate towards any known trusted CAs. You can either obtain a certificate from a CA which is trusted by your Java's default TrustStore or you can provide your own CA certificate (the one you used to sign the self-signed certificate) to your JVM by generating your own TrustStore. You would then pass the TrustStore e.g. using the command line argument -Djavax.net.ssl.trustStore= when starting your application.
Keep in mind that passing a custom TrustStore requires you to either add all CAs which are contained in your JRE's default TrustStore or you live with the fact that no chains of trust can be established to any certificates not issued by your own CA.
A third option is adding your own CA certificate to your system's global TrustStore which leads to any Java application accepting certificates from your CA. This is a shortcut but might not be in your best interest if you require a strict separation of CAs.
I think below link may be helpful to you.
http://docs.oracle.com/cd/B19306_01/java.102/b14355/sslthin.htm#BABHFBJD
Found the solution, as I'm using SSO need to specify both keystore and truststore.
Connection connection = null;
String url = "jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS=(PROTOCOL=tcps)(HOST=192.168.200.191)(PORT=1522))(CONNECT_DATA=(SERVICE_NAME=NNVSDB)))";
Properties props = new Properties();
props.setProperty("user", "dbuser");
props.setProperty("password", "dbpass");
//Single sign on
props.setProperty("javax.net.ssl.trustStore", "C:\\oracle\\wallet\\cwallet.sso");
props.setProperty("javax.net.ssl.trustStoreType","SSO");
props.setProperty("javax.net.ssl.keyStore","C:\\oracle\\wallet\\cwallet.sso");
props.setProperty("javax.net.ssl.keyStoreType","SSO");
props.setProperty("oracle.net.authentication_services","(TCPS)");
/* Load the database driver */
try
{
Security.addProvider(new oracle.security.pki.OraclePKIProvider());
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
connection = DriverManager.getConnection(url,props);
if (connection != null) {
System.out.println("You made it, take control your database now!");
} else {
System.out.println("Failed to make connection!");
}
}
catch (SQLException ex) {
ex.printStackTrace();
}

JSch hostKey not recognised with Titan SFTP server

I have an issue with my hostkey verification via JSch. I am using jsch 0.1.53, for my application, and the server I am connecting to is SouthRiverTech's Titan SFTP server.
I have tried generating a keypair with Puttygen, the Titan inbuilt key generator, and also with JSch's inbuilt libraries. The settings I used was RSA, 2048 bits.
The keys created by JSch's inbuilt libraries didn't seem to work. The keys generated by Titan and Puttygen were able to be used with winSCP, but kept giving me a "Reject Hostkey" error with JSch, which should be an issue with the known_hosts file. From what I have found, the known_hosts file should be the same as a public key file, but do tell me if I am wrong. I have set Titan's SFTP version to version 3.
I have the same keys set for the user profile in Titan to find out where the error lies, but to no avail. So far I have yet to find any answers online regarding hostkey issue between JSch and Titan server. This has been giving me a huge headache.
Thank you in advance for any answers you might have. I will try my best to post any information I might have missed out.
EDIT
Further debugging came up with JSchException: UnknownHostKey, followed by the RSA key fingerprint which is used by the server. My client key fingerprint and the server key fingerprint are the same, so why is this happening?
EDIT
Here is my Java code:
knownHostsFile = "D:/Keys/test.pub";
privateKey = "D:/Keys/test";
Session session = null;
Channel channel = null;
for(int i = 0; i < 3; i++) {
try {
logger.debug("Starting Upload");
JSch ssh=new JSch();
logger.debug("setting hosts - public key");
ssh.setKnownHosts(knownHostsFile);
logger.debug("Known hosts set as "+knownHostsFile);
logger.debug("Setting identity - private key");
ssh.addIdentity(privateKey);
logger.debug("identity set");
try {
int hostSFTPPort = Integer.parseInt(sftpPort);
if (!hostUserName.equalsIgnoreCase("no")
&& !hostPassword.equalsIgnoreCase("no")
&& !hostAddress.equalsIgnoreCase("no")) {
session=ssh.getSession(hostUserName,hostAddress,hostSFTPPort);
session.setPassword(hostPassword);
}
} catch (NumberFormatException ef){
logger.debug(ef);
}
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "yes");
config.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
session.setConfig(config);
logger.debug("Establishing connection...");
session.connect(120000);
logger.debug("Connection established.");
logger.debug("Creating SFTP Channel.");
channel=session.openChannel("sftp");
logger.debug("Channel assigned. Connecting channel...");
channel.connect(120000);
logger.debug("SFTP Channel created.");
ChannelSftp sftp = (ChannelSftp) channel;
logger.debug("connection:"+sftp.isConnected());
if(sftp.isConnected()) {
result=Constants.CONNECTION_ONLINE;
}
session.disconnect();
channel.disconnect();
break;
} catch (JSchException e) {
logger.debug(e);
logger.debug(session.getHost());
logger.debug(session.getHostKey());
logger.debug("Continuing next loop......");
throw new JSchException("Session.connect failed",e);
} catch (Exception ex) {
logger.debug(ex);
logger.debug("Continuing next loop......");
continue;
}
}
Here is a picture of the Server admin console
Here are the keys I'm having trouble with:
This one does not seem to work with winSCP, and was created in a Linux environment
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA4R+w9rGUsBNJGZxAdnbnA7FMfGGhx3YaLYZtKf9wzKm8NkZeYIuh1fJ6ViX6RmdO55QxQ3PmBIg8QdhQ8m6SizEt9OGeXU2AnEbX/sbj54oHmiFsv24eDFzr7nrDKnrcllByob3LqjeOy5zg27kJt860oh6BAJfimdqVtETSXR1JHfqUIqGxIqsvyKEotX8gjoGkgsW653f18dW5PJKSEvrq6k1SL0bfgSAA0rN4nUq3JzDvowg5ijkOl91/lj8+FEQ7SjWmguTSx5BoI/CTxatCwNZSdzNED/u5A8I3716JuY7MEiTciPdzspGAXS2mHOtsDPkT7z6jvKQ6hWWv/w== test1#10.70.149.178
This one works with winSCP, and was created in a Windows environment
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "test"
AAAAB3NzaC1yc2EAAAABJQAAAQEA9a1nnbl/DV2Zo7s1IUifeC5suRmdO2ikSb0ToteO9uvA
gg0zYKA1iH52ysC+4Ni86Ceal4oWGl1dXZRKOaWNH6175uDTI1aBfPBvOddBheTeSQAWOkaM
eL5PDDabLkaKZ1GrtbTeEFOD/Kj/dVREhT5/OcEdFmCbHK6+vr2klrtH2xOd/Qeb89BzDFaj
weNER3fFnHVqy5/Nugo3n7CsiBxuK8KOVN4WpDHzrVe/tjAfVZyH8l4XHlR7bWA5rlAGwt0Y
HILQ+lT1PRmi5PiDq7WuP7NF3QhWjG/D1u/5PC/DzxjTOxwwmXfYj2T2OkE/2/tHSdU4geYr
+1ivdASJ5w==
---- END SSH2 PUBLIC KEY ----
You are confusing an account key pair with a host key (pair).
The JSchException "reject HostKey: ..." indicates that the server's public key (aka host key) differs from the public key known by your code or cached in the known_hosts file.
The server's host key is typically not generated by PuTTYgen (though it might be possible) and definitely has nothing to do with WinSCP. In PuTTYgen you typically generate an account key pair (which you can then use e.g. in WinSCP).
For details, see my article Understanding SSH key pairs.
The account key pair and host key pair have nothing to do with each other. Whatever you use for the account key, it won't make JSch accept the server's host key. Just forget this idea. It's completely wrong.
You have to provide the correct host key in the known_hosts file (or other implementation of the JSch HostKeyRepository interface). You cannot use a .pub file for the known_hosts file. The known_hosts file has a set format like:
IP_address ssh-rsa public_key
You can also use KnownHosts.add to set the expected hostkey on runtime.

JSch: UnknownHostKey exception even when the hostkey fingerprint is present in the known_hosts file

There are two questions about this exception already:
JSchException: UnknownHostKey and
com.jcraft.jsch.JSchException: UnknownHostKey
I am using a Windows machine and trying to connect to a VM created with Vagrant running Ubuntu. Here is my code:
public static void main(String[] args) {
String host = "localhost";
String username = "vagrant";
int port = 2200;
String privateKey = "C:\\keys\\openSSH_pair1\\open_ssh_private";
JSch js = new JSch();
try {
js.addIdentity(privateKey, "pass");
js.setKnownHosts("C:\\Users\\user\\.ssh\\known_hosts");
Session session = js.getSession(username, host, port);
session.connect();
System.out.println("Connected");
} catch (JSchException e) {
e.printStackTrace();
}
}
#Pascal suggests setting strictHostKeyChecking to no, which works for me, but this is not the preferred solution. His preferred solution is to SSH from the command line so that the host will be added to the known_hosts file. I have Git installed and executed ssh -i openSSH_pair1\open_ssh_private vagrant#localhost -p 2200
and received this output before being prompted for the pass phrase and establishing a connection
The authenticity of host '[localhost]:2200 ([127.0.0.1]:2200)' can't
be established. ECDSA key fingerprint is
11:5d:55:29:8a:77:d8:08:b4:00:9b:a3:61:93:fe:e5. Are you sure you want
to continue connecting (yes/no)? yes Warning: Permanently added
'[localhost]:2200' (ECDSA) to the list of known hosts.
So now my known_hosts file in git_home\.ssh contains an entry for localhost:2200, I also placed the known_hosts file into user_home\.ssh. I also put my private key on the VM I'm trying to ssh into and ran this to generate a public key and add it to the authorized_keys
ssh-keygen -y -f open_ssh_private > open_ssh_gen.pub
cat open_ssh_gen.pub >> ~/.ssh/authorized_keys
However I still get this exception
com.jcraft.jsch.JSchException: UnknownHostKey: localhost. RSA key fingerprint is 50:db:75:ba:11:2f:43:c9:ab:14:40:6d:7f:a1:ee:e3
at com.jcraft.jsch.Session.checkHost(Session.java:797)
at com.jcraft.jsch.Session.connect(Session.java:342)
at com.jcraft.jsch.Session.connect(Session.java:183)
at connect.Main.main(Main.java:24)
The answer to the other question suggests adding the below which doesn't work for me either
js.setKnownHosts("C:\\Users\\user\\.ssh\\known_hosts");
The problem is that you have added ECDSA host key to the known_hosts, as the ssh prefers that key type:
ECDSA key fingerprint is 11:5d:55:29:8a:77:d8:08:b4:00:9b:a3:61:93:fe:e5.
But JSch prefers RSA key, which it won't find in the known_hosts:
RSA key fingerprint is 50:db:75:ba:11:2f:43:c9:ab:14:40:6d:7f:a1:ee:e3
You probably need JCE to enable ECDSA In JSch.
See JSch Algorithm negotiation fail.
Or make ssh use RSA key with -o HostKeyAlgorithms=ssh-rsa.
See How can I force SSH to give an RSA key instead of ECDSA?
You can also use ssh-keyscan:
ssh-keyscan -t rsa example.com

Smack XMPP: Can't login to openfire server: "SASLErrorException: SASLError using DIGEST-MD5: not-authorized"

I am trying to create a basic connection and login to an Openfire server that I have installed. I have the following user in my users database which I created through the Openfire web admin interface:
User: user
Password: 12345678
I can connect fine to the server as the connection returns true in my sout. The problem is when it tries to log in I get the following error:
org.jivesoftware.smack.sasl.SASLErrorException: SASLError using DIGEST-MD5: not-authorized
I have the following code:
private XMPPConnection connection;
public void connect(String serverIP) {
try {
System.setProperty("smack.debugEnabled", "true");
ConnectionConfiguration config = new ConnectionConfiguration(serverIP, 5223);
config.setDebuggerEnabled(true);
config.setSocketFactory(new DummySSLSocketFactory());
config.setSecurityMode(ConnectionConfiguration.SecurityMode.enabled);
config.setCompressionEnabled(true);
connection = new XMPPTCPConnection(config);
connection.connect();
System.out.println("Connected: " + connection.isConnected());
connection.login("user", "12345678");
System.out.println("Logged in: " + connection.isAuthenticated());
} catch (SmackException | IOException | XMPPException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
connectionHandler test = new connectionHandler();
test.connect("localhost");
}
If anyone can correct what I am doing wrong I would be really grateful.
I have also tried the username as the email would be for example
user#localhost.com
or
user#localhost
I finally managed to find the answer to this. The problem (possibly not even a problem) was that the authentication methods weren't set in the server config and as default allowed all methods. The first one chosen in java seems to be DIGEST-MD5 which was what was causing the errors. To fix this I added:
<sasl>
<mechs> PLAIN </mechs>
</sasl>
before the last closing tag of the openfire.xml found in the config folder of the server. This can also be changed in the ofproperty database table for the column called sasl.mechs.
Hopefully this helps someone (possibly me) in the future.
P.S. this is unsecure if not using SSL (port 5223 by default)
SASLError using DIGEST-MD5: not-authorized
This is most likely caused because you did not configure the correct XMPP domain (/service name) in your ConnectionConfiguration. DIGEST-MD5 would not only fail if the username or password is wrong, but also if the wrong XMPP domain is used.

Categories