I am trying to do certificate pinning. The network library my company used doesn't support pinning. So I have to do it manually.
This is the code I use
protected Void doInBackground(Void... params) {
String actualKey = "OpenSSLRSAPublicKey{modulus=ccf0883ebc511bb86f7f6e360385cf3a" +
"8720fa0d9f3367278baf2fd43d29c21b4384f09ae14207beeb429563639d4388aca65a3" +
"a5f5d2c902bf33e6df904598e6a5a1c037add731bdce606c664368cbc4bb7e269bbda82" +
"ff20bd9ca484f5bd660d5628bca4a8f376acf1cab07f0d9476df283ef44d3bf52d4b730" +
"3187cf587cbb2ce981e01b6cb32ba4f9b197b60013ff19215abb7d2ca9608007df82641" +
"b05127ec9557927e8bd68ff183f8b72720f93152f207f89b446e38fc7aa3db4928f5fb7" +
"92f33898381e7bc5ddb612d2e3a3191854797add8e0d47ed9f7da709e55a89aa7369620" +
"2d90275ada9d43fb462a16839787b6ea3c83df66a1d6e528a38d0d,publicExponent=1" +
"0001}";
try {
SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket("prisonvoicemail.com", 443);
socket.startHandshake();
Certificate[] certs = socket.getSession().getPeerCertificates();
Certificate cert = certs[0];
String key = cert.getPublicKey().toString();
Log.d(LOG_TAG, key);
if(key.equals(actualKey)){
Log.d(LOG_TAG, "Success");
} else {
Log.d(LOG_TAG, "Failure");
}
} catch (IOException e){
e.printStackTrace();
}
return null;
But for some reason it doesn't work. When I connect normally it get success, when I connect through a proxy (mitmproxy) to test a different certificate simulating a man in the middle attack, I also get success. It's like its completely bypassing the proxy and going straight to the normal certificiate. I don't know why this is.
Related
Attempting to establish an SSLSession using a self-signed certificate and the new-ish Network Security Configuration method as well as cwac-netsecurity library for backward compatibility works on all other versions of android (that I have tried) except Android 7.0.
I have an android app that connects to a device to provide a UI for that device. The connection uses a TLSv1 SSLSocket and a self-signed server certificate on the device side. Prior to Nougat, I had the server certs embedded as a BKS key store and loaded at run-time to create a custom TrustManager in order to intialize the SSL context and create the socket. This no longer works under Android 7+. Following some other questions on SO (Cannot connect via SSL using self signed certificate on Android 7 and above), I was able to use the Network Security Configuration method to establish the SSLSocket connection on an Android 8 device (https://developer.android.com/training/articles/security-config#ConfigCustom). For backward compatibility, I am using the cwac-netsecurity library from CommonsWare (https://github.com/commonsguy/cwac-netsecurity). I built a small test application and am testing against openssl s_server. What I have written establishes an SSLSession successfully from android devices running 4.4, 6.0, and 8.0. For some reason however, it does not do so on an android device running 7.0. Here are code snippets that show the test. Any help would be appreciated.
Test code in android app
{
// createSocketFactory
SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault(); //null;
TrustManagerBuilder tmb = new TrustManagerBuilder();
tmb.withManifestConfig(MainActivity.this);
tmb.withCertChainListener(
new CertChainListener()
{
#Override
public void onChain(X509Certificate[] chain, String domain)
{
if (domain == null)
{
Log.d(TAG, "onChain: Certificate chain for request to unknown domain");
}
else
{
Log.d(TAG, "onChain: Certificate chain for request to: " + domain);
}
for (X509Certificate cert : chain)
{
Log.d(TAG, "onChain: Subject: " + cert.getSubjectX500Principal().getName());
Log.d(TAG, "onChain: Issuer: " + cert.getIssuerX500Principal().getName());
}
}
});
CompositeTrustManager ctm = tmb.build();
try
{
SSLContext sc = SSLContext.getInstance("TLSv1");
sc.init(null, new TrustManager[] { ctm }, new SecureRandom());
factory = sc.getSocketFactory();
}
catch (NoSuchAlgorithmException e)
{
Log.e(TAG, "createSocketFactory: failed to get SSLContext", e);
}
catch (KeyManagementException e)
{
Log.e(TAG, "createSocketFactory: failed to init SSLContext from CompositeTrustManager");
}
// createSslSocket
SSLSocket socket = null;
String addr = "172.31.106.60";
int port = 50001;
if (factory != null)
{
Log.d(TAG, "createSocketFactory - SUCCESS");
try
{
socket = (SSLSocket)factory.createSocket(addr, port);
Log.d(TAG, "createAltSocket - SUCCESS");
socket.setEnabledProtocols(new String[] { "TLSv1" });
socket.setEnabledCipherSuites(new String[] { "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" });
socket.setTcpNoDelay(true);
socket.setKeepAlive(true);
}
catch (IOException e)
{
Log.e(TAG, "createSslSocket - Couldn't create SSLSocket", e);
try
{
socket.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
finally
{
socket = null;
}
}
}
else
{
Log.d(TAG, "createSocketFactory - FAILED");
}
// testSslSocket
if (socket != null && socket.isConnected())
{
SSLSession session = socket.getSession();
if (session != null && session.isValid())
Log.d(TAG, "testSslSocket: SESSION SUCCESS");
else
Log.d(TAG, "testSslSocket: SESSION FAILED");
try
{
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
network_securiity_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="#raw/test_cert_chain"/>
<certificates src="system"/>
</trust-anchors>
</base-config>
</network-security-config>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.ssltesting">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:networkSecurityConfig="#xml/network_security_config">
<meta-data
android:name="android.security.net.config"
android:resource="#xml/network_security_config" />
test server
openssl s_server -tls1 -WWW -accept 50001 -cert test.crt -key mcv.key -state
In all working cases, the SSLSession is valid at the end of the test routine, and I get logging from the CertChainListener. However, when running this on my Android 7.0 device, all is quiet. I get no logging from the CertChainListener, the SSLSession is not valid, and I get the following on the server side:
Using default temp DH parameters
ACCEPT
SSL_accept:before/accept initialization
SSL3 alert write:fatal:handshake failure
SSL_accept:error in error
140386525526784:error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher:s3_srvr.c:1417:
ACCEPT
I am using SSLSocket to connect to a server. I want to use ssl SNI extension. I can use SSLParameter.setServerNames in java. But it appears in android it is not available till sdk 24. What are my options here?
I had the same problem, solved by using reflection.
Connect the socket using:
SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) sf.createSocket(uri.getHost(), 443);
setSNIHost(sf, socket, uri.getHost());
SSLSession s = socket.getSession();
where setSNIHost is declared as:
public void setSNIHost(final SSLSocketFactory factory, final SSLSocket socket, final String hostname) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
Log.i(TAG, "Setting SNI via SSLParameters");
SNIHostName sniHostName = new SNIHostName(hostname);
SSLParameters sslParameters = socket.getSSLParameters();
List<SNIServerName> sniHostNameList = new ArrayList<>(1);
sniHostNameList.add(sniHostName);
sslParameters.setServerNames(sniHostNameList);
socket.setSSLParameters(sslParameters);
} else if (factory instanceof android.net.SSLCertificateSocketFactory) {
Log.i(TAG, "Setting SNI via SSLCertificateSocketFactory");
((android.net.SSLCertificateSocketFactory)factory).setHostname(socket, hostname);
} else {
Log.i(TAG, "Setting SNI via reflection");
try {
socket.getClass().getMethod("setHostname", String.class).invoke(socket, hostname);
} catch (Throwable e) {
Log.e(TAG, "Could not call SSLSocket#setHostname(String) method ", e);
}
}
}
I don't really remember where I copied the code for the reflection, I simply added the support for API 24.
I am trying to implement an FTP server in my application using the Apache FTP server library.
The server is up and running and working fine, but only once.
Note: I am using a hardcoded user for now. username: test and password: test
So in order:
App is launched, server is started, lets all FTP clients login.
App is killed by user.
App is started by user and server is started. Replies 530 authentication failed to user logging in with username: test and password: test
After that it responds with 530 authentication failed
My code below for making the server:
public void makePropertiesFile(){
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/user.properties");
if(file.exists() == false){
try {
file.createNewFile();
logMessage("user.properties File did not exist, made one");
properties = file;
this.addUsers();
} catch (IOException e) {
e.printStackTrace();
}
}
else {
logMessage("File already exists, no need to recreate");
userManagerFactory = new PropertiesUserManagerFactory();
userManagerFactory.setFile(properties);
userManagerFactory.setPasswordEncryptor(new SaltedPasswordEncryptor());
org.apache.ftpserver.ftplet.UserManager userManager = userManagerFactory.createUserManager();
serverFactory.setUserManager(userManager);
}
}
public void addUsers(){
userManagerFactory = new PropertiesUserManagerFactory();
userManagerFactory.setFile(properties);
userManagerFactory.setPasswordEncryptor(new SaltedPasswordEncryptor());
baseUser = new BaseUser();
baseUser.setName("test");
baseUser.setPassword("test");
baseUser.setHomeDirectory(Environment.getExternalStorageDirectory().getAbsolutePath());
baseUser.setEnabled(true);
List<Authority> authorities = new ArrayList<Authority>();
authorities.add(new WritePermission());
baseUser.setAuthorities(authorities);
org.apache.ftpserver.ftplet.UserManager userManager = userManagerFactory.createUserManager();
try {
userManager.save(baseUser);
} catch (FtpException e) {
e.printStackTrace();
logMessage("Could not save User");
}
serverFactory.setUserManager(userManager);
}
public void start(){
serverFactory = new FtpServerFactory();
listenerFactory = new ListenerFactory();
listenerFactory.setPort(port);
serverFactory.addListener("default",listenerFactory.createListener());
ftpServer = serverFactory.createServer();
this.makePropertiesFile();
try {
ftpServer.start();
logMessage("Started FTP server on port: " + port);
} catch (FtpException e) {
e.printStackTrace();
logMessage("Failed to start FTP server on port: " + port);
}
}
see this link http://androidexample.com/FTP_File_Upload_From_Sdcard_to_server/index.php?view=article_discription&aid=98&aaid=120
has a working project FTP with Android app
I try establish a https server in android for other phones to connect,but
only iphone6 sometimes can connected , ipod ,android browser all failed to get the webserver content.
(the browser message is fail to establish safe connect)
I use nanohttpd's simpleServer Class to establish it.
my CA is here
http://www.mediafire.com/download/53f6e9uveb47kqv/ca.cer
// for client to download
http://www.mediafire.com/download/v9i58n38yb85co5/server.p12
//for server to load keystore
CA password both are singuler .
Here is my sslServerSocket Code
char[]kspass = KEYSTOREPASS.toCharArray();
char[]ctpass = KEYSTOREPASS.toCharArray();
try {
KeyStore ks = KeyStore.getInstance("PKCS12");
//ks.load(new FileInputStream("file:///android_asset/singuler.keystore"),kspass);
ks.load(getResources().getAssets().open("server.p12"),kspass);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, ctpass);
TrustManagerFactory tmFactory = TrustManagerFactory.getInstance("X509");
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);
//webServer.makeSecure(NanoHTTPD.makeSSLSocketFactory(ks, kmf.getKeyManagers()));
webServerSSL.makeSecure(sc.getServerSocketFactory());
} catch (Exception e) {
// TODO: handle exceptionser
Log.i("test", e.toString());
}
try {
webServer.start(15);
webServerSSL.start(15);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
webServer = null;
webServerSSL=null;
Log.i("test", e.toString());
}
Can any one help me ?
Thank you.
I found the answer
Whe start nanohttpd server , need set the timeout millonseconds for every connect socket,especial for https request.
How can access to wss:// protocol in java ?
i use benkay / java-socket.io.client
but it's not support wss protocol.
i tried use SSLEngine. but it's very hard work.
how can connect to ssl in java ?
I tried change SocketChannel by SSLEngine. but it is not worked.
ssl channel is ok. but i can't wire this original websocket part.
this is source code.
client = SocketChannel.open(remote);
client.configureBlocking(false);
//client.connect(remote);
selector = Selector.open();
this.conn = new WebSocket(client, new LinkedBlockingQueue<ByteBuffer>(), this);
client.register(selector, SelectionKey.OP_READ);
try {
sslClient = new SSLClient(keyStore, storepass.toCharArray(), client);
sslClient.beginHandShake();
startClient()
} catch (Exception e) {
e.printStackTrace();
}
this point uncorret ?? i don't know .. not same the original websocket code.. may problem is this point. how can fix it ??
public void startClient()
{
try
{
while(true)
{
if(selector.select() <= 0)
{
continue;
}
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while(it.hasNext())
{
SelectionKey key = (SelectionKey)it.next();
Log.e("key","key");
if(key.isReadable())
{
read(key);
}
it.remove();
}
}
}
catch(Exception e)
{
}
}
and SSLClient is http://rapidant.tistory.com/attachment/cfile25.uf#121346414D45B0960BD01B.zip
key store : change JKS to BKS, not problem.
how can wrap the SocketChannel ?
(Web browser it worked.)
You could check out my fork of the Autobahn WebSocket Library.
Secure WebSockets based upon Autobahn
You don't want to use SSLEngine on Android because it is broken.