First draft of an external TLS provider app.
@ -12,7 +12,11 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||
classpath 'com.android.tools.build:gradle:3.1.3'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
repositories {
|
||||
google()
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
// ExternalCertificateProvider.aidl
|
||||
package de.blinkt.openvpn.api;
|
||||
|
||||
|
||||
/*
|
||||
* This is very simple interface that is specialised to have only the minimal set of crypto
|
||||
* operation that are needed for OpenVPN to authenticate with an external certificate
|
||||
*/
|
||||
interface ExternalCertificateProvider {
|
||||
/**
|
||||
* Requests signing the data with RSA/ECB/PKCS1PADDING
|
||||
* for RSA certficate and with NONEwithECDSA for EC certificates
|
||||
* @parm alias the parameter that
|
||||
*/
|
||||
byte[] getSignedData(String alias, in byte[] data);
|
||||
|
||||
/**
|
||||
* Requests a
|
||||
*/
|
||||
String[] getCertificateChain(in String alias);
|
||||
|
||||
/**
|
||||
* request an Intent that should be started when user uses the select certificate box
|
||||
* the already selected alias will be provided in the extra android.security.extra.KEY_ALIAS
|
||||
* if applicable
|
||||
*/
|
||||
|
||||
}
|
@ -18,7 +18,7 @@ interface IOpenVPNAPIService {
|
||||
boolean addVPNProfile (String name, String config);
|
||||
|
||||
/** start a profile using a config as inline string. Make sure that all needed data is inlined,
|
||||
* e.g., using <ca>...</ca> or <auth-user-data>...</auth-user-data>
|
||||
* e.g., using <ca>...</ca> or <auth-user-pass>...</auth-user-pass>
|
||||
* See the OpenVPN manual page for more on inlining files */
|
||||
void startVPN (in String inlineconfig);
|
||||
|
||||
|
@ -4,4 +4,5 @@
|
||||
*/
|
||||
|
||||
include ':main'
|
||||
include ':tlsexternalcertprovider'
|
||||
include ':remoteExample'
|
||||
|
1
tlsexternalcertprovider/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
54
tlsexternalcertprovider/build.gradle
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 Arne Schwabe
|
||||
* Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
*/
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
|
||||
ext {
|
||||
bouncycastleVersion = '1.49'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
|
||||
|
||||
defaultConfig {
|
||||
applicationId "de.blinkt.externalcertprovider"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 27
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
targetCompatibility 1.8
|
||||
sourceCompatibility 1.8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation (
|
||||
'org.bouncycastle:bcprov-jdk15on:' + bouncycastleVersion,
|
||||
'org.bouncycastle:bcprov-ext-jdk15on:' + bouncycastleVersion,
|
||||
'org.bouncycastle:bcpkix-jdk15on:' + bouncycastleVersion,
|
||||
'org.bouncycastle:bcmail-jdk15on:' + bouncycastleVersion,
|
||||
'org.bouncycastle:bcpg-jdk15on:' + bouncycastleVersion
|
||||
)
|
||||
|
||||
}
|
21
tlsexternalcertprovider/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 Arne Schwabe
|
||||
* Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
*/
|
||||
|
||||
package de.blinkt.externalcertprovider;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("de.blinkt.externalcertprovider", appContext.getPackageName());
|
||||
}
|
||||
}
|
43
tlsexternalcertprovider/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2012-2018 Arne Schwabe
|
||||
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
|
||||
package="de.blinkt.externalcertprovider">
|
||||
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
>
|
||||
|
||||
<!--
|
||||
OpenVPN for android will search for all application that have a activity that fulfils this
|
||||
intent. It will be called when the user presses the select button and should return the selected
|
||||
alias in the android.security.extra.KEY_ALIAS extra on setResult.
|
||||
|
||||
the already selected alias will be provided in the extra android.security.extra.KEY_ALIAS
|
||||
if applicable
|
||||
-->
|
||||
<activity android:name=".SelectCertificateActivity">
|
||||
<intent-filter>
|
||||
<category android:name="de.blinkt.openvpn.CertProviderSelect"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
<service
|
||||
android:name=".ExternalCertService"
|
||||
tools:ignore="ExportedService">
|
||||
<intent-filter>
|
||||
<action android:name="de.blinkt.openvpn.api.ExternalCertificateProvider" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -0,0 +1,28 @@
|
||||
// ExternalCertificateProvider.aidl
|
||||
package de.blinkt.openvpn.api;
|
||||
|
||||
|
||||
/*
|
||||
* This is very simple interface that is specialised to have only the minimal set of crypto
|
||||
* operation that are needed for OpenVPN to authenticate with an external certificate
|
||||
*/
|
||||
interface ExternalCertificateProvider {
|
||||
/**
|
||||
* Requests signing the data with RSA/ECB/PKCS1PADDING
|
||||
* for RSA certficate and with NONEwithECDSA for EC certificates
|
||||
* @parm alias the parameter that
|
||||
*/
|
||||
byte[] getSignedData(String alias, in byte[] data);
|
||||
|
||||
/**
|
||||
* Requests a
|
||||
*/
|
||||
String[] getCertificateChain(in String alias);
|
||||
|
||||
/**
|
||||
* request an Intent that should be started when user uses the select certificate box
|
||||
* the already selected alias will be provided in the extra android.security.extra.KEY_ALIAS
|
||||
* if applicable
|
||||
*/
|
||||
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 Arne Schwabe
|
||||
* Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
*/
|
||||
|
||||
package de.blinkt.externalcertprovider;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import de.blinkt.openvpn.api.ExternalCertificateProvider;
|
||||
import org.bouncycastle.openssl.PEMKeyPair;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
|
||||
/**
|
||||
* This is a VERY basic implementation.
|
||||
* It does not even check if the service is even allowed to use the API
|
||||
* see ExternalOpenVPNService for an example of checking caller's creditionals
|
||||
*/
|
||||
public class ExternalCertService extends Service {
|
||||
|
||||
String pemkey = "-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDsZY/pEsIaW+ZW\n" +
|
||||
"KgipgjotRHijADuwn+cnEECT7/HMPqCqBKKAGxOp5v6B1nCQqNjU3jDYNQDSvmLw\n" +
|
||||
"SNr8FY3Exm0LmfErgwAK0yojC+XN+TXfQ2EVcq2VmPZzIUFeoN1HJ6DVmtRBqBwd\n" +
|
||||
"VyBxF4/3KJ4+B87s1Q5CTx50R45HndIUKCcsFBD10Za1k3SE7/kE3o1Kb993q+rR\n" +
|
||||
"WNNE/loEAf8Gepf3/eNXSOHw30ATn2YjWuNVVD1UOe4A+RLx0t90LrrX8I3G3RhY\n" +
|
||||
"HJMiC3X6qNbgtS8tudT+uU+G4nVIFmD7P8m0MEIp+zuzK7lZgWpG80WDv/3VGv83\n" +
|
||||
"DG9b/WHxAgMBAAECggEBAIOdaCpUD02trOh8LqZxowJhBOl7z7/ex0uweMPk67LT\n" +
|
||||
"i5AdVHwOlzwZJ8oSIknoOBEMRBWcLQEojt1JMuL2/R95emzjIKshHHzqZKNulFvB\n" +
|
||||
"TIUpdnwChTKtH0mqUkLlPU3Ienty4IpNlpmfUKimfbkWHERdBJBHbtDsTABhdo3X\n" +
|
||||
"9pCF/yRKqJS2Fy/Mkl3gv1y/NB1OL4Jhl7vQbf+kmgfQN2qdOVe2BOKQ8NlPUDmE\n" +
|
||||
"/1XNIDaE3s6uvUaoFfwowzsCCwN2/8QrRMMKkjvV+lEVtNmQdYxj5Xj5IwS0vkK0\n" +
|
||||
"6icsngW87cpZxxc1zsRWcSTloy5ohub4FgKhlolmigECgYEA+cBlxzLvaMzMlBQY\n" +
|
||||
"kCac9KQMvVL+DIFHlZA5i5L/9pRVp4JJwj3GUoehFJoFhsxnKr8HZyLwBKlCmUVm\n" +
|
||||
"VxnshRWiAU18emUmeAtSGawlAS3QXhikVZDdd/L20YusLT+DXV81wlKR97/r9+17\n" +
|
||||
"klQOLkSdPm9wcMDOWMNHX8bUg8kCgYEA8k+hQv6+TR/+Beao2IIctFtw/EauaJiJ\n" +
|
||||
"wW5ql1cpCLPMAOQUvjs0Km3zqctfBF8mUjdkcyJ4uhL9FZtfywY22EtRIXOJ/8VR\n" +
|
||||
"we65mVo6RLR8YVM54sihanuFOnlyF9LIBWB+9pUfh1/Y7DSebh7W73uxhAxQhi3Y\n" +
|
||||
"QwfIQIFd8OkCgYBalH4VXhLYhpaYCiXSej6ot6rrK2N6c5Tb2MAWMA1nh+r84tMP\n" +
|
||||
"gMoh+pDgYPAqMI4mQbxUmqZEeoLuBe6VHpDav7rPECRaW781AJ4ZM4cEQ3Jz/inz\n" +
|
||||
"4qOAMn10CF081/Ez9ykPPlU0bsYNWHNd4eB2xWnmUBKOwk7UgJatVPaUiQKBgQCI\n" +
|
||||
"f18CVGpzG9CHFnaK8FCnMNOm6VIaTcNcGY0mD81nv5Dt943P054BQMsAHTY7SjZW\n" +
|
||||
"HioRyZtkhonXAB2oSqnekh7zzxgv4sG5k3ct8evdBCcE1FNJc2eqikZ0uDETRoOy\n" +
|
||||
"s7cRxNNr+QxDkyikM+80HOPU1PMPgwfOSrX90GJQ8QKBgEBKohGMV/sNa4t14Iau\n" +
|
||||
"qO8aagoqh/68K9GFXljsl3/iCSa964HIEREtW09Qz1w3dotEgp2w8bsDa+OwWrLy\n" +
|
||||
"0SY7T5jRViM3cDWRlUBLrGGiL0FiwsfqiRiji60y19erJgrgyGVIb1kIgIBRkgFM\n" +
|
||||
"2MMweASzTmZcri4PA/5C0HYb\n" +
|
||||
"-----END PRIVATE KEY-----\n";
|
||||
|
||||
String[] certchain = new String[]{"-----BEGIN CERTIFICATE-----\n" +
|
||||
"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\n" +
|
||||
"CAKK4CXz9EM=\n" +
|
||||
"-----END CERTIFICATE-----\n"
|
||||
,
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIGKDCCBBCgAwIBAgIJAKFO3vqQ8q6BMA0GCSqGSIb3DQEBCwUAMGYxCzAJBgNV\n" +
|
||||
"BAYTAktHMQswCQYDVQQIEwJOQTEQMA4GA1UEBxMHQklTSEtFSzEVMBMGA1UEChMM\n" +
|
||||
"T3BlblZQTi1URVNUMSEwHwYJKoZIhvcNAQkBFhJtZUBteWhvc3QubXlkb21haW4w\n" +
|
||||
"HhcNMTQxMDIyMjE1OTUyWhcNMjQxMDE5MjE1OTUyWjBmMQswCQYDVQQGEwJLRzEL\n" +
|
||||
"MAkGA1UECBMCTkExEDAOBgNVBAcTB0JJU0hLRUsxFTATBgNVBAoTDE9wZW5WUE4t\n" +
|
||||
"VEVTVDEhMB8GCSqGSIb3DQEJARYSbWVAbXlob3N0Lm15ZG9tYWluMIICIjANBgkq\n" +
|
||||
"hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsJVPCqt3vtoDW2U0DII1QIh2Qs0dqh88\n" +
|
||||
"8nivxAIm2LTq93e9fJhsq3P/UVYAYSeCIrekXypR0EQgSgcNTvGBMe20BoHO5yvb\n" +
|
||||
"GjKPmjfLj6XRotCOGy8EDl/hLgRY9efiA8wsVfuvF2q/FblyJQPR/gPiDtTmUiqF\n" +
|
||||
"qXa7AJmMrqFsnWppOuGd7Qc6aTsae4TF1e/gUTCTraa7NeHowDaKhdyFmEEnCYR5\n" +
|
||||
"CeUsx2JlFWAH8PCrxBpHYbmGyvS0kH3+rQkaSM/Pzc2bS4ayHaOYRK5XsGq8XiNG\n" +
|
||||
"KTTLnSaCdPeHsI+3xMHmEh+u5Og2DFGgvyD22gde6W2ezvEKCUDrzR7bsnYqqyUy\n" +
|
||||
"n7LxnkPXGyvR52T06G8KzLKQRmDlPIXhzKMO07qkHmIonXTdF7YI1azwHpAtN4dS\n" +
|
||||
"rUe1bvjiTSoEsQPfOAyvD0RMK/CBfgEZUzAB50e/IlbZ84c0DJfUMOm4xCyft1HF\n" +
|
||||
"YpYeyCf5dxoIjweCPOoP426+aTXM7kqq0ieIr6YxnKV6OGGLKEY+VNZh1DS7enqV\n" +
|
||||
"HP5i8eimyuUYPoQhbK9xtDGMgghnc6Hn8BldPMcvz98HdTEH4rBfA3yNuCxLSNow\n" +
|
||||
"4jJuLjNXh2QeiUtWtkXja7ec+P7VqKTduJoRaX7cs+8E3ImigiRnvmK+npk7Nt1y\n" +
|
||||
"YE9hBRhSoLsCAwEAAaOB2DCB1TAdBgNVHQ4EFgQUK0DlyX319JY46S/jL9lAZMmO\n" +
|
||||
"BZswgZgGA1UdIwSBkDCBjYAUK0DlyX319JY46S/jL9lAZMmOBZuhaqRoMGYxCzAJ\n" +
|
||||
"BgNVBAYTAktHMQswCQYDVQQIEwJOQTEQMA4GA1UEBxMHQklTSEtFSzEVMBMGA1UE\n" +
|
||||
"ChMMT3BlblZQTi1URVNUMSEwHwYJKoZIhvcNAQkBFhJtZUBteWhvc3QubXlkb21h\n" +
|
||||
"aW6CCQChTt76kPKugTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG\n" +
|
||||
"9w0BAQsFAAOCAgEABc77f4C4P8fIS+V8qCJmVNSDU44UZBc+D+J6ZTgW8JeOHUIj\n" +
|
||||
"Bh++XDg3gwat7pIWQ8AU5R7h+fpBI9n3dadyIsMHGwSogHY9Gw7di2RVtSFajEth\n" +
|
||||
"rvrq0JbzpwoYedMh84sJ2qI/DGKW9/Is9+O52fR+3z3dY3gNRDPQ5675BQ5CQW9I\n" +
|
||||
"AJgLOqzD8Q0qrXYi7HaEqzNx6p7RDTuhFgvTd+vS5d5+28Z5fm2umnq+GKHF8W5P\n" +
|
||||
"ylp2Js119FTVO7brusAMKPe5emc7tC2ov8OFFemQvfHR41PLryap2VD81IOgmt/J\n" +
|
||||
"kX/j/y5KGux5HZ3lxXqdJbKcAq4NKYQT0mCkRD4l6szaCEJ+k0SiM9DdTcBDefhR\n" +
|
||||
"9q+pCOyMh7d8QjQ1075mF7T+PGkZQUW1DUjEfrZhICnKgq+iEoUmM0Ee5WtRqcnu\n" +
|
||||
"5BTGQ2mSfc6rV+Vr+eYXqcg7Nxb3vFXYSTod1UhefonVqwdmyJ2sC79zp36Tbo2+\n" +
|
||||
"65NW2WJK7KzPUyOJU0U9bcu0utvDOvGWmG+aHbymJgcoFzvZmlXqMXn97pSFn4jV\n" +
|
||||
"y3SLRgJXOw1QLXL2Y5abcuoBVr4gCOxxk2vBeVxOMRXNqSWZOFIF1bu/PxuDA+Sa\n" +
|
||||
"hEi44aHbPXt9opdssz/hdGfd8Wo7vEJrbg7c6zR6C/Akav1Rzy9oohIdgOw=\n" +
|
||||
"-----END CERTIFICATE-----\n"};
|
||||
private final ExternalCertificateProvider.Stub mBinder = new ExternalCertificateProvider.Stub() {
|
||||
|
||||
@Override
|
||||
public byte[] getSignedData(String alias, byte[] data) throws RemoteException {
|
||||
try {
|
||||
|
||||
// This is more or less code that has been just modified long enough that it works
|
||||
// Don't take it as good example how to get a Privatekey
|
||||
StringReader keyreader = new StringReader(certchain + pemkey);
|
||||
PEMParser pemparser = new PEMParser(keyreader);
|
||||
|
||||
PEMKeyPair bcKeyPair = (PEMKeyPair) pemparser.readObject();
|
||||
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bcKeyPair.getPrivateKeyInfo().getEncoded());
|
||||
KeyFactory kf = KeyFactory.getInstance("RSA");
|
||||
PrivateKey key = kf.generatePrivate(keySpec);
|
||||
|
||||
// The actual signing
|
||||
|
||||
Cipher signer;
|
||||
signer = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
|
||||
|
||||
|
||||
signer.init(Cipher.ENCRYPT_MODE, key);
|
||||
|
||||
byte[] signed_bytes = signer.doFinal(data);
|
||||
return signed_bytes;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeySpecException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Something failed, return null
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getCertificateChain(String alias) throws RemoteException {
|
||||
|
||||
return certchain;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 Arne Schwabe
|
||||
* Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
*/
|
||||
|
||||
package de.blinkt.externalcertprovider;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.security.KeyChain;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class SelectCertificateActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
findViewById(R.id.nicecert).setOnClickListener((v) ->
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(KeyChain.EXTRA_KEY_ALIAS, "mynicecert");
|
||||
setResult(RESULT_OK);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<!--
|
||||
~ Copyright (c) 2012-2018 Arne Schwabe
|
||||
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0"/>
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1"/>
|
||||
</vector>
|
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2012-2018 Arne Schwabe
|
||||
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
-->
|
||||
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="108dp"
|
||||
android:width="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path android:fillColor="#26A69A"
|
||||
android:pathData="M0,0h108v108h-108z"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
</vector>
|
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2012-2018 Arne Schwabe
|
||||
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
-->
|
||||
|
||||
<LinearLayout android:orientation="vertical"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".SelectCertificateActivity">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="This demo app has no sophisticated selection!"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/nicecert"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Send mynicecert as string back to app"
|
||||
|
||||
/>
|
||||
</LinearLayout>
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2012-2018 Arne Schwabe
|
||||
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
-->
|
||||
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2012-2018 Arne Schwabe
|
||||
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
-->
|
||||
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
BIN
tlsexternalcertprovider/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 4.9 KiB |
BIN
tlsexternalcertprovider/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 15 KiB |
8
tlsexternalcertprovider/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<!--
|
||||
~ Copyright (c) 2012-2018 Arne Schwabe
|
||||
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">ExternalCertProvider</string>
|
||||
</resources>
|
10
tlsexternalcertprovider/src/main/res/values/styles.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!--
|
||||
~ Copyright (c) 2012-2018 Arne Schwabe
|
||||
~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
|
||||
|
||||
</resources>
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2018 Arne Schwabe
|
||||
* Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
|
||||
*/
|
||||
|
||||
package de.blinkt.externalcertprovider;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|