[android] Supported client cert - added cert for uploader

This commit is contained in:
Dmitry Donskoy 2018-10-16 14:30:56 +03:00 committed by Aleksandr Zatsepin
parent 1305da5b91
commit f14b93d95f
6 changed files with 32 additions and 205 deletions

View file

@ -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

View file

@ -1,8 +1,8 @@
#include <jni.h>
#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<int32_t>(env->CallIntMethod(src, getHttpCode));
jni::ScopedLocalRef<jstring> const description(
env, static_cast<jstring>(env->CallObjectMethod(src, getDescription)));
env, static_cast<jstring>(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<jstring> const method(env, jni::ToJavaString(env, m_method));
jni::ScopedLocalRef<jstring> const url(env, jni::ToJavaString(env, m_url));
@ -56,15 +57,15 @@ HttpUploader::Result HttpUploader::Upload() const
jni::ScopedLocalRef<jstring> const filePath(env, jni::ToJavaString(env, m_filePath));
jni::ScopedLocalRef<jobject> const httpUploaderObject(
env, env->NewObject(g_httpUploaderClazz, httpUploaderConstructor, method.get(), url.get(),
params.get(), headers.get(), fileKey.get(), filePath.get(),
static_cast<jboolean>(m_needClientAuth)));
env, env->NewObject(g_httpUploaderClazz, httpUploaderConstructor, method.get(), url.get(),
params.get(), headers.get(), fileKey.get(), filePath.get(),
static_cast<jboolean>(m_needClientAuth)));
static jmethodID const uploadId = jni::GetMethodID(env, httpUploaderObject, "upload",
"()Lcom/mapswithme/util/HttpUploader$Result;");
jni::ScopedLocalRef<jobject> const result(
env, env->CallObjectMethod(httpUploaderObject, uploadId));
jni::ScopedLocalRef<jobject> 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);
}
}

View file

@ -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;

View file

@ -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<X509TrustManager> x509TrustManagers = new ArrayList<X509TrustManager>();
protected ClientKeyStoresTrustManager(KeyStore... additionalkeyStores) {
final ArrayList<TrustManagerFactory> factories = new ArrayList<TrustManagerFactory>();
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<X509Certificate> list = new ArrayList<X509Certificate>();
for ( X509TrustManager tm : x509TrustManagers )
list.addAll(Arrays.asList(tm.getAcceptedIssuers()));
return list.toArray(new X509Certificate[list.size()]);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}