My code works, yet I have a question.
According to my code my client is proposing to the server to use TLSv1.3. Since the connection is established, I believe this is the case. However, I want to see some kind of confirmation from the server. Is this possible?
SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
SSLContext sslContext = sslUtil.createSSLContext();
String[] supportedProtocols = sslContext.getDefaultSSLParameters().getProtocols();
System.out.println("Supported Protocols = " + Arrays.toString(supportedProtocols));
String TLSversion = "TLSv1.3";
System.out.println("TLS version = " + TLSversion);
SSLSocketFactory sslSocketFactory = sslUtil.createSSLSocketFactory(TLSversion);
try
{
LDAPConnection ldc = new LDAPConnection(sslSocketFactory);
ldc.connect(this.getHost(), this.getPort());
return ldc;
}
catch (LDAPException le)
{
System.out.println(le);
};
Related
I am using java 1.6.0_111 which doesn't support tlsv1.2, but my server only accepts tlsv1.2, So I tried with bouncycastle provider but still it is not working it throwing the connection reset error. even though i increased connecttimeout to 30000 it still getting error at conn.getoutputstream.
Below is my code:
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
Security.insertProviderAt(new BouncyCastleProvider(), 1);
Security.removeProvider(BouncyCastleJsseProvider.PROVIDER_NAME);
Security.insertProviderAt(new BouncyCastleJsseProvider(), 2);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2", new BouncyCastleJsseProvider());
log("The Supported Protocols are::"+Arrays.asList(protocols));
/*sslContext.init(null, tmf.getTrustManagers(), null);
SSLContext.setDefault(sslContext);;*/
String https_url ="myprodurl";
String json = mattArray.toString().trim();
URL url = new URL(https_url);
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
log("after opening connection");
conn.setConnectTimeout(30000);
log("step1");
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
log("step2");
OutputStream os = conn.getOutputStream();
log("step3");
os.write(json.getBytes("UTF-8"));
log("step4");
os.close();
log("after closing outputstream");
InputStream in = new BufferedInputStream(conn.getInputStream());
String response = IOUtils.toString(in, "UTF-8");
log("Result after Reading JSON Response\n\n");
log(response);
The error I got:
2020-02-04 21:00:42,386 [system] [DEBUG] test - ERROR2 :java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at com.ibm.jsse2.a.a(a.java:148)
at com.ibm.jsse2.a.a(a.java:96)
at com.ibm.jsse2.tc.a(tc.java:302)
at com.ibm.jsse2.tc.g(tc.java:208)
at com.ibm.jsse2.tc.a(tc.java:482)
at com.ibm.jsse2.tc.startHandshake(tc.java:597)
at com.ibm.net.ssl.www2.protocol.https.c.afterConnect(c.java:44)
at com.ibm.net.ssl.www2.protocol.https.d.connect(d.java:36)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1014)
at com.ibm.net.ssl.www2.protocol.https.b.getOutputStream(b.java:66)
I can't test IBM j6, but with Sun/Oracle j6 (6u45, last free release) which has the same limitation to TLS1.0, your method of setting the providerlist works for me given I have no other code changing the defaults, and so does explicitly setting either the SSLContext default, the HttpsURLConnection default, or the connection instance, as I said. The latter three do need bcprov in the provider list if the server wants to use ECC, as many servers today do, because Sun j6 didn't have an ECC provider; I'm not sure about IBM j6. For my test server I can use my default truststore (because I have previously set my default truststore to handle my test servers); this may differ for you. OTOH I have to use an explicit not default random source or I get mysterious errors.
My test code for these four methods (with option to include bcprov in latter three) is:
static void SO60068561BouncyTLS (String[] args) throws Exception {
String url = args[0];
int n = Integer.parseInt (args[1]);
Provider p1 = (Provider)Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance();
Provider p2 = (Provider)Class.forName("org.bouncycastle.jsse.provider.BouncyCastleJsseProvider").newInstance();
SSLContext ctx = null;
if( n == 1 ){ Security.insertProviderAt(p1, 1); Security.insertProviderAt(p2, 2); }
else{ ctx = SSLContext.getInstance("TLSv1.2", p2); ctx.init(null, null, new SecureRandom()); }
if( n < 0 ){ Security.addProvider(p1); n = -n; }
if( n == 2 ) SSLContext.setDefault (ctx);
else if( n == 3 ) HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());
HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
if( n == 4 ) conn.setSSLSocketFactory(ctx.getSocketFactory());
conn.connect();
System.out.println (conn.getCipherSuite()+" "+conn.getResponseCode());
}
To create the certificates(pfx for C#, jks for Java) I followed this guide
C# client:
X509Certificate cert = new X509Certificate2(certPath, "pass");
TStreamTransport socket = new TTLSSocket(host, port, cert, (o, c, chain, errors) => true, null);
var transport = new TBufferedTransport(socket);
TProtocol protocol = new TBinaryProtocol(transport);
_client = new HfmConnectorService.Client(protocol);
_client.InputProtocol.Transport.Open();
Java Server:
TSSLTransportFactory.TSSLTransportParameters params = new TSSLTransportFactory.TSSLTransportParameters();
File keystoreFile = new File(System.getProperty("user.dir") + "\\keystore\\hfmcon.jks");
if(!keystoreFile.exists())
throw new IOException("Keystore file missing");
params.setKeyStore(keystoreFile.getPath(), "pass");
TServerSocket serverTransport = TSSLTransportFactory.getServerSocket(port, 10000, InetAddress.getByName("localhost"), params);
The client times out on this line
_client.InputProtocol.Transport.Open();
I need to connect to remote server via FTPS (implicit or explicit). I successfully connected to server via FileZilla. Also I tested code to retrieve file from public ftp: ftp.mozilla.org
Now I need the same code for ftps. I have problem with private key and KeyStore
String keyPath = "src/test/resources/keys/thekey.ppk";
FTPSClient client = new FTPSClient();
FileOutputStream fos = null;
try {
KeyStore ks = KeyStore.getInstance("JKS"); //
FileInputStream fis = new FileInputStream(keyPath);
ks.load(fis, "".toCharArray());//java.io.IOException: Invalid keystore format
fis.close();
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(ks, "".toCharArray());
System.out.println("connecting to 1.1.1.1...");
client.setDefaultTimeout(10000);
client.connect("1.1.1.1", 2190);
System.out.println("loggin in...");
System.out.println("login: " + client.login("login", "pass"));
String remoteDir = "/pub/downloaded/";
String remoteFileName = "testMsg.txt";
String localFileName = "testMsg.local.txt";
fos = new FileOutputStream(localFileName);
System.out.println("retrieving file...");
boolean isRetrieved = client.retrieveFile(remoteDir + remoteFileName, fos);
System.out.print("File: " + remoteDir + remoteFileName + "; IsRetrieved: " + isRetrieved + "\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
}
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
Keys were generated in PuTTY format. What else options can I put here KeyStore.getInstance("JKS").
If ommit the part with KeyStore than code reach line with client.retrieveFile and suspends for a long time.
Need help to import keys, plz.
FTPS stands for FTP-over-SSL. SSL uses X.509 certificates for authentication (we omit other rarely used methods now). Putty is SSH/SFTP client (where SFTP stands for SSH File Transfer Protocol) and putty keys are SSH keys. Consequently you can't use SSH keys for SSL authentication.
I write FTPS server, and I have problems with ssl connection after AUTH TLS command.
Simple example:
try
{
int ServerPort = 21;
ServerSocket FtpExServer = new ServerSocket(ServerPort);
while(true)
{
Socket S = FtpExServer.accept();
InputStreamReader ISR = new InputStreamReader(S.getInputStream());
OutputStreamWriter OSW = new OutputStreamWriter(S.getOutputStream());
BufferedReader ClientSocketReader = new BufferedReader(ISR);
PrintWriter ClientSocketWriter = new PrintWriter(OSW, true);
ClientSocketWriter.println("220 Welcome to FTP server.");
print(ClientSocketReader.readLine());
ClientSocketWriter.println("234 AUTH TLS successful");
char[] passphrase = "pass".toCharArray();
char[] cpassphrase = "cpass".toCharArray();
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(new FileInputStream("keystore.jks"), passphrase);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, cpassphrase);
SSLContext context = SSLContext.getInstance("TLS");
KeyManager[] keyManagers = kmf.getKeyManagers();
context.init(keyManagers, null, null);
SSLServerSocketFactory ssf = context.getServerSocketFactory();
SSLServerSocket ss = (SSLServerSocket) ssf.createServerSocket(990);
ss.setSoTimeout(2000);
SSLSocket s = (SSLSocket)ss.accept();
ISR = new InputStreamReader(s.getInputStream());
OSW = new OutputStreamWriter(s.getOutputStream());
ClientSocketReader = new BufferedReader(ISR);
ClientSocketWriter = new PrintWriter(OSW, true);
ClientSocketWriter.println("234 AUTH TLS successful");
print(ClientSocketReader.readLine());
ClientSocketWriter.println("331 Password required for smie");
print(ClientSocketReader.readLine());
ClientSocketWriter.println("230 User smie logged in");
print(ClientSocketReader.readLine());
ClientSocketWriter.println("215 UNIX Type: L8");
print(ClientSocketReader.readLine());
ClientSocketWriter.println("550 Command not suported.");
}
}
catch(Exception e)
{
print(e);
}
Description: FTP client(for example MoveITFreely) connect to server on port 21. After send command "AUTH TLS", server send "234 AUTH TLS successful". Now client must to connect to server on port 990(?), but client dont connect and get timeout exception.
What i do wrong?
There exist two methods to add SSL to FTP.
First method is called implicit SSL. It means that the server is listening on port 990 and when the client connects to it, first SSL/TLS negotiation is performed, and then the established connection is used as a command channel for communication (for data channel SSL handshake is also performed in a similar manner).
Second method is what you attempt to use. It's called explicit SSL. The client connects on port 21, sends AUTH TLS and starts SSL negotiation on existing connection. Data channel can be secured or not secured depending on how you want it (you specify this using PROT command).
You mixed the methods. I suggest that you read detailed explanation in Wikipedia before going further. Then read RFC for explicit TLS.
Update: Also you'd need SSLClientSocket, not SSLServerSocket.
i need to send a v3certificate from the server to the client using socket.
To do this:
server side, i generate a certificate which i encode with base64.encode , then i send it to the client.
Client side, i receive the string which contain the certificate,
Server code:
X509Certificate certificate = ...;
sendAnswer(new String(certificate.getEncoded()));
public static void sendAnswer(String ans) {
try {
s.shutdownInput();
PrintWriter output = new PrintWriter(s.getOutputStream(), true);
output.println(new String(Base64.encode(ans.getBytes())));
output.close();
} catch (IOException ex) {
Logger.getLogger(serverThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
Client code
String value = sendMessage(..);//method which receive the certificate from the server
InputStream inStream = null;
X509Certificate cert=null;
inStream = new ByteArrayInputStream(value.getBytes());
CertificateFactory cf = CertificateFactory.getInstance("X.509","BC");
cert = (X509Certificate)cf.generateCertificate(inStream);
public static String sendMessage(String url, int port, String tag, byte[] mex1) {
Socket link;
String reply = "";
byte[] replyDec = null;
link = new Socket(InetAddress.getByName(url), port);
InputStream i = null;
try {
i = link.getInputStream();
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
Scanner input = new Scanner(i);
while (input.hasNextLine()) {
reply += input.nextLine();
}
replyDec = Base64.decode(reply);
input.close();
link.close();
return new String(replyDec);
}
Almost everything works, in the client side if i print the string i receive i get a text which contain extra character and the certificate data. But it gives me an error when creating the certificate, client side.
This is the error:
java.security.cert.CertificateException: java.io.IOException: DER length more than 4 bytes: 111
at org.bouncycastle.jce.provider.JDKX509CertificateFactory.engineGenerateCertificate(Unknown Source)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:322)
and this is the line from which it comes from
cert = (X509Certificate) cf.generateCertificate(inStream);
Anyone can help me?
Thanks in advance
Throw it all away and use SSL, which already does all that.
You can send the certificate through socket by stream of bytes:
in sender side after configuration of socket:
ObjectOutputStream toServer;
toServer = new ObjectOutputStream(socket.getOutputStream());
byte[] frame = theCertificate.getEncoded();
toServer.writeObject(frame);
in receiver side after configuration of socket:
ObjectInputStream fromClient;
fromClient = new ObjectInputStream(socket.getInputStream());
byte[] cert = fromClient.readObject();
java.security.cert.Certificate jsCert = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(cert));
now you can use this certificate. for example as retrieving the public key:
PublicKey thepublicKey = jsCert.getPublicKey();
It looks possible that your problem might be due to using a PrintWriter to send, and possibly something different to read (scanner). You could try using a StringWriter and StringReader to have a match at either end and then also you can debug if what you send is a perfect match for what you receive.