From f14b93d95fdf824cd97d2b4a10b49a8952e3c121 Mon Sep 17 00:00:00 2001 From: Dmitry Donskoy Date: Tue, 16 Oct 2018 14:30:56 +0300 Subject: [PATCH] [android] Supported client cert - added cert for uploader --- android/jni/CMakeLists.txt | 2 +- .../{platform => util}/HttpUploader.cpp | 48 +++--- .../com/mapswithme/maps/MwmApplication.java | 2 - .../AdditionalKeyStoresSSLSocketFactory.java | 161 ------------------ .../util/ClientCertTLSSocketFactory.java | 20 +-- .../src/com/mapswithme/util/HttpUploader.java | 4 +- 6 files changed, 32 insertions(+), 205 deletions(-) rename android/jni/com/mapswithme/{platform => util}/HttpUploader.cpp (58%) delete mode 100644 android/src/com/mapswithme/util/AdditionalKeyStoresSSLSocketFactory.java diff --git a/android/jni/CMakeLists.txt b/android/jni/CMakeLists.txt index db8a0263ec..7493edd031 100644 --- a/android/jni/CMakeLists.txt +++ b/android/jni/CMakeLists.txt @@ -74,7 +74,7 @@ set( com/mapswithme/opengl/androidoglcontextfactory.cpp com/mapswithme/opengl/gl3stub.c com/mapswithme/platform/HttpThread.cpp - com/mapswithme/platform/HttpUploader.cpp + com/mapswithme/util/HttpUploader.cpp com/mapswithme/platform/HttpUserAgent.cpp com/mapswithme/platform/GuiThread.cpp com/mapswithme/platform/Language.cpp diff --git a/android/jni/com/mapswithme/platform/HttpUploader.cpp b/android/jni/com/mapswithme/util/HttpUploader.cpp similarity index 58% rename from android/jni/com/mapswithme/platform/HttpUploader.cpp rename to android/jni/com/mapswithme/util/HttpUploader.cpp index 5b53caf619..cbd8119e3c 100644 --- a/android/jni/com/mapswithme/platform/HttpUploader.cpp +++ b/android/jni/com/mapswithme/util/HttpUploader.cpp @@ -1,8 +1,8 @@ #include -#include "com/mapswithme/core/jni_helper.hpp" #include "com/mapswithme/core/ScopedEnv.hpp" #include "com/mapswithme/core/ScopedLocalRef.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "platform/http_uploader.hpp" @@ -18,16 +18,16 @@ namespace platform::HttpUploader::Result ToNativeResult(JNIEnv * env, jobject const src) { static jmethodID const getHttpCode = - env->GetMethodID(g_httpUploaderResultClazz, "getHttpCode", "()I"); + env->GetMethodID(g_httpUploaderResultClazz, "getHttpCode", "()I"); static jmethodID const getDescription = - env->GetMethodID(g_httpUploaderResultClazz, "getDescription", "()Ljava/lang/String;"); + env->GetMethodID(g_httpUploaderResultClazz, "getDescription", "()Ljava/lang/String;"); platform::HttpUploader::Result result; result.m_httpCode = static_cast(env->CallIntMethod(src, getHttpCode)); jni::ScopedLocalRef const description( - env, static_cast(env->CallObjectMethod(src, getDescription))); + env, static_cast(env->CallObjectMethod(src, getDescription))); result.m_description = jni::ToNativeString(env, description.get()); return result; @@ -43,10 +43,11 @@ HttpUploader::Result HttpUploader::Upload() const CHECK(env, ()); static jmethodID const httpUploaderConstructor = - jni::GetConstructorID(env, g_httpUploaderClazz, "(Ljava/lang/String;Ljava/lang/String;" - "[Lcom/mapswithme/util/KeyValue;" - "[Lcom/mapswithme/util/KeyValue;" - "Ljava/lang/String;Ljava/lang/String;Z)V"); + jni::GetConstructorID(env, g_httpUploaderClazz, + "(Ljava/lang/String;Ljava/lang/String;" + "[Lcom/mapswithme/util/KeyValue;" + "[Lcom/mapswithme/util/KeyValue;" + "Ljava/lang/String;Ljava/lang/String;Z)V"); jni::ScopedLocalRef const method(env, jni::ToJavaString(env, m_method)); jni::ScopedLocalRef const url(env, jni::ToJavaString(env, m_url)); @@ -56,15 +57,15 @@ HttpUploader::Result HttpUploader::Upload() const jni::ScopedLocalRef const filePath(env, jni::ToJavaString(env, m_filePath)); jni::ScopedLocalRef const httpUploaderObject( - env, env->NewObject(g_httpUploaderClazz, httpUploaderConstructor, method.get(), url.get(), - params.get(), headers.get(), fileKey.get(), filePath.get(), - static_cast(m_needClientAuth))); + env, env->NewObject(g_httpUploaderClazz, httpUploaderConstructor, method.get(), url.get(), + params.get(), headers.get(), fileKey.get(), filePath.get(), + static_cast(m_needClientAuth))); static jmethodID const uploadId = jni::GetMethodID(env, httpUploaderObject, "upload", "()Lcom/mapswithme/util/HttpUploader$Result;"); - jni::ScopedLocalRef const result( - env, env->CallObjectMethod(httpUploaderObject, uploadId)); + jni::ScopedLocalRef const result(env, + env->CallObjectMethod(httpUploaderObject, uploadId)); if (jni::HandleJavaException(env)) { @@ -76,16 +77,19 @@ HttpUploader::Result HttpUploader::Upload() const return ToNativeResult(env, result); } -} // namespace platform +} // namespace platform -JNIEXPORT jstring JNICALL -Java_com_mapswithme_util_HttpUploader_nativeUserBindingCertificate(JNIEnv * env, jclass) +extern "C" { - return jni::ToJavaString(env, USER_BINDING_PKCS12); -} + JNIEXPORT jstring JNICALL + Java_com_mapswithme_util_HttpUploader_nativeUserBindingCertificate(JNIEnv * env, jclass) + { + return jni::ToJavaString(env, USER_BINDING_PKCS12); + } -JNIEXPORT jstring JNICALL -Java_com_mapswithme_util_HttpUploader_nativeUserBindingPassword(JNIEnv * env, jclass) -{ - return jni::ToJavaString(env, USER_BINDING_PKCS12_PASSWORD); + JNIEXPORT jstring JNICALL + Java_com_mapswithme_util_HttpUploader_nativeUserBindingPassword(JNIEnv * env, jclass) + { + return jni::ToJavaString(env, USER_BINDING_PKCS12_PASSWORD); + } } diff --git a/android/src/com/mapswithme/maps/MwmApplication.java b/android/src/com/mapswithme/maps/MwmApplication.java index 78aa3c9815..1b65acb01d 100644 --- a/android/src/com/mapswithme/maps/MwmApplication.java +++ b/android/src/com/mapswithme/maps/MwmApplication.java @@ -1,10 +1,8 @@ package com.mapswithme.maps; -import android.app.Activity; import android.app.Application; import android.content.Context; import android.content.SharedPreferences; -import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.annotation.NonNull; diff --git a/android/src/com/mapswithme/util/AdditionalKeyStoresSSLSocketFactory.java b/android/src/com/mapswithme/util/AdditionalKeyStoresSSLSocketFactory.java deleted file mode 100644 index 5a0108614c..0000000000 --- a/android/src/com/mapswithme/util/AdditionalKeyStoresSSLSocketFactory.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.mapswithme.util; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Arrays; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import org.apache.http.conn.ssl.SSLSocketFactory; - -/** - * Allows you to trust certificates from additional KeyStores in addition to - * the default KeyStore - */ -public class AdditionalKeyStoresSSLSocketFactory extends javax.net.ssl.SSLSocketFactory -{ - protected SSLContext sslContext = SSLContext.getInstance("TLS"); - - public AdditionalKeyStoresSSLSocketFactory(KeyStore keyStore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(keyStore, "".toCharArray()); - sslContext.init(kmf.getKeyManagers(), new TrustManager[]{new ClientKeyStoresTrustManager(keyStore)}, new SecureRandom()); - } - - @Override - public String[] getDefaultCipherSuites() - { - return new String[0]; - } - - @Override - public String[] getSupportedCipherSuites() - { - return new String[0]; - } - - @Override - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { - return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); - } - - @Override - public Socket createSocket() throws IOException { - return sslContext.getSocketFactory().createSocket(); - } - - @Override - public Socket createSocket(String host, int port) throws IOException, UnknownHostException - { - return null; - } - - @Override - public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException - { - return null; - } - - @Override - public Socket createSocket(InetAddress host, int port) throws IOException - { - return null; - } - - @Override - public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException - { - return null; - } - - /** - * Based on http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager - */ - public static class ClientKeyStoresTrustManager implements X509TrustManager { - - protected ArrayList x509TrustManagers = new ArrayList(); - - protected ClientKeyStoresTrustManager(KeyStore... additionalkeyStores) { - final ArrayList factories = new ArrayList(); - - try { - // The default Trustmanager with default keystore - final TrustManagerFactory original = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - original.init((KeyStore) null); - factories.add(original); - - for ( KeyStore keyStore : additionalkeyStores ) { - final TrustManagerFactory additionalCerts = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - additionalCerts.init(keyStore); - factories.add(additionalCerts); - } - - } catch (Exception e) { - throw new RuntimeException(e); - } - - /* - * Iterate over the returned trustmanagers, and hold on - * to any that are X509TrustManagers - */ - for (TrustManagerFactory tmf : factories) - for ( TrustManager tm : tmf.getTrustManagers() ) - if (tm instanceof X509TrustManager) - x509TrustManagers.add( (X509TrustManager) tm ); - - if ( x509TrustManagers.size() == 0 ) - throw new RuntimeException("Couldn't find any X509TrustManagers"); - - } - - public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { - for ( X509TrustManager tm : x509TrustManagers ) { - try { - tm.checkClientTrusted(chain, authType); - return; - } catch ( CertificateException e ) { - - } - } - throw new CertificateException(); - } - - /* - * Loop over the trustmanagers until we find one that accepts our server - */ - public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { - for ( X509TrustManager tm : x509TrustManagers ) { - try { - tm.checkServerTrusted(chain, authType); - return; - } catch ( CertificateException e ) { - - } - } - throw new CertificateException(); - } - - public X509Certificate[] getAcceptedIssuers() { - final ArrayList list = new ArrayList(); - for ( X509TrustManager tm : x509TrustManagers ) - list.addAll(Arrays.asList(tm.getAcceptedIssuers())); - return list.toArray(new X509Certificate[list.size()]); - } - } - -} diff --git a/android/src/com/mapswithme/util/ClientCertTLSSocketFactory.java b/android/src/com/mapswithme/util/ClientCertTLSSocketFactory.java index a345c973a1..d2e97ea686 100644 --- a/android/src/com/mapswithme/util/ClientCertTLSSocketFactory.java +++ b/android/src/com/mapswithme/util/ClientCertTLSSocketFactory.java @@ -3,27 +3,21 @@ package com.mapswithme.util; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.mapswithme.util.log.Logger; -import com.mapswithme.util.log.LoggerFactory; - import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.io.InputStream; import java.security.KeyStore; import java.security.SecureRandom; public class ClientCertTLSSocketFactory { - private static final Logger LOGGER = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.NETWORK); - private static final String TAG = ClientCertTLSSocketFactory.class.getSimpleName(); - private static final String PROTOCOL = "TLS"; private static final String ALGORITHM = "X509"; private static final String KEY_STORE_TYPE = "PKCS12"; + @NonNull public static SSLSocketFactory create(@NonNull byte[] payload, @Nullable char[] password) { InputStream inputStream = null; @@ -44,17 +38,7 @@ public class ClientCertTLSSocketFactory { } finally { - if (inputStream != null) - { - try - { - inputStream.close(); - } - catch (IOException e) - { - LOGGER.d(TAG, "Stream not closed", e); - } - } + Utils.closeSafely(inputStream); } } } diff --git a/android/src/com/mapswithme/util/HttpUploader.java b/android/src/com/mapswithme/util/HttpUploader.java index 16d6e072c6..ee47f0cb2a 100644 --- a/android/src/com/mapswithme/util/HttpUploader.java +++ b/android/src/com/mapswithme/util/HttpUploader.java @@ -5,6 +5,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; +import android.util.Base64; import com.mapswithme.maps.BuildConfig; import com.mapswithme.maps.Framework; import com.mapswithme.util.log.Logger; @@ -149,7 +150,8 @@ public final class HttpUploader { String cert = HttpUploader.nativeUserBindingCertificate(); String pwd = HttpUploader.nativeUserBindingPassword(); - SSLSocketFactory socketFactory = ClientCertTLSSocketFactory.create(cert.getBytes(), pwd.toCharArray()); + byte[] decodedCert = Base64.decode(cert, Base64.DEFAULT); + SSLSocketFactory socketFactory = ClientCertTLSSocketFactory.create(decodedCert, pwd.toCharArray()); connection.setSSLSocketFactory(socketFactory); }