diff options
author | Evgenii Potapov <potapov@rutoken.ru> | 2020-11-12 09:23:34 +0300 |
---|---|---|
committer | Arne Schwabe <arne@rfc2549.org> | 2020-11-23 10:53:22 +0100 |
commit | a6de5a9e4d8d757414c5e2f94eb806be9216dda3 (patch) | |
tree | 4fe085c140e4e3824a9cbfb2b1b59f99d190934d | |
parent | dd6d365fb67ca992617e87a04ab61b17feffdecd (diff) |
Provide a padding type for externalCertificateProvider
Based on server-side OpenSSL behaviour the data to be signed by
externalCertificateProvider may be or may be not padded already.
To choose the proper signing mechanism we need to pass external info.
3 files changed, 50 insertions, 11 deletions
diff --git a/main/src/main/aidl/de/blinkt/openvpn/api/ExternalCertificateProvider.aidl b/main/src/main/aidl/de/blinkt/openvpn/api/ExternalCertificateProvider.aidl index c6db965b..951cff96 100644 --- a/main/src/main/aidl/de/blinkt/openvpn/api/ExternalCertificateProvider.aidl +++ b/main/src/main/aidl/de/blinkt/openvpn/api/ExternalCertificateProvider.aidl @@ -1,16 +1,16 @@ // 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 { /** + * @deprecated use {@link #getSignedDataWithExtra} instead * Requests signing the data with RSA/ECB/PKCS1PADDING * for RSA certficate and with NONEwithECDSA for EC certificates - * @parm alias the parameter that + * @param alias user certificate identifier */ byte[] getSignedData(in String alias, in byte[] data); @@ -36,4 +36,21 @@ interface ExternalCertificateProvider { * */ Bundle getCertificateMetaData(in String alias); + + /** + * Requests signing the data with RSA/ECB/PKCS1PADDING or RSA/ECB/nopadding + * for RSA certficate and with NONEwithECDSA for EC certificates + * @param alias user certificate identifier + * @param data the data to be signed + * @param extra additional information. + * Should contain the following keys: + * <p><ul> + * <li>int key "de.blinkt.openvpn.api.RSA_PADDING_TYPE", may be set as: + * <p><ul> + * <li>0 - for RSA/ECB/nopadding + * <li>1 - for RSA/ECB/PKCS1PADDING + * </ul><p> + * </ul><p> + */ + byte[] getSignedDataWithExtra(in String alias, in byte[] data, in Bundle extra); } diff --git a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java index 2cb12296..2ccff18b 100644 --- a/main/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/main/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -12,6 +12,7 @@ import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; +import android.os.Bundle; import android.preference.PreferenceManager; import android.security.KeyChain; import android.security.KeyChainException; @@ -82,6 +83,7 @@ public class VpnProfile implements Serializable, Cloneable { private static final long serialVersionUID = 7085688938959334563L; private static final int AUTH_RETRY_NONE_KEEP = 1; private static final int AUTH_RETRY_INTERACT = 3; + private static final String EXTRA_RSA_PADDING_TYPE = "de.blinkt.openvpn.api.RSA_PADDING_TYPE"; public static String DEFAULT_DNS1 = "8.8.8.8"; public static String DEFAULT_DNS2 = "8.8.4.4"; // variable named wrong and should haven beeen transient @@ -1148,10 +1150,16 @@ public class VpnProfile implements Serializable, Cloneable { public String getSignedData(Context c, String b64data, boolean pkcs1padding) { byte[] data = Base64.decode(b64data, Base64.DEFAULT); byte[] signed_bytes; - if (mAuthenticationType == TYPE_EXTERNAL_APP) - signed_bytes = getExtAppSignedData(c, data); - else + if (mAuthenticationType == TYPE_EXTERNAL_APP) { + RsaPaddingType paddingType = pkcs1padding ? RsaPaddingType.PKCS1_PADDING : RsaPaddingType.NO_PADDING; + Bundle extra = new Bundle(); + extra.putInt(EXTRA_RSA_PADDING_TYPE, paddingType.ordinal()); + + signed_bytes = getExtAppSignedData(c, data, extra); + } + else { signed_bytes = getKeyChainSignedData(data, pkcs1padding); + } if (signed_bytes != null) return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); @@ -1159,11 +1167,11 @@ public class VpnProfile implements Serializable, Cloneable { return null; } - private byte[] getExtAppSignedData(Context c, byte[] data) { + private byte[] getExtAppSignedData(Context c, byte[] data, Bundle extra) { if (TextUtils.isEmpty(mExternalAuthenticator)) return null; try { - return ExtAuthHelper.signData(c, mExternalAuthenticator, mAlias, data); + return ExtAuthHelper.signData(c, mExternalAuthenticator, mAlias, data, extra); } catch (KeyChainException | InterruptedException e) { VpnStatus.logError(R.string.error_extapp_sign, mExternalAuthenticator, e.getClass().toString(), e.getLocalizedMessage()); return null; @@ -1257,7 +1265,13 @@ public class VpnProfile implements Serializable, Cloneable { } } - + /** + * The order of elements is important! + */ + private enum RsaPaddingType { + NO_PADDING, + PKCS1_PADDING + } } diff --git a/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java b/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java index a62a4c62..d102dce2 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java +++ b/main/src/main/java/de/blinkt/openvpn/core/ExtAuthHelper.java @@ -108,15 +108,23 @@ public class ExtAuthHelper { public static byte[] signData(@NonNull Context context, @NonNull String extAuthPackageName, @NonNull String alias, - @NonNull byte[] data + @NonNull byte[] data, + @NonNull Bundle extra ) throws KeyChainException, InterruptedException { - try (ExternalAuthProviderConnection authProviderConnection = bindToExtAuthProvider(context.getApplicationContext(), extAuthPackageName)) { + try (ExternalAuthProviderConnection authProviderConnection = + bindToExtAuthProvider(context.getApplicationContext(), extAuthPackageName)) { ExternalCertificateProvider externalAuthProvider = authProviderConnection.getService(); - return externalAuthProvider.getSignedData(alias, data); + + byte[] result = externalAuthProvider.getSignedDataWithExtra(alias, data, extra); + // When the desired method is not implemented, a default implementation is called, returning null + if (result == null) + result = externalAuthProvider.getSignedData(alias, data); + + return result; } catch (RemoteException e) { throw new KeyChainException(e); |