From b85dc1b2ea68ab7ca7e11ab545bb88f4dbb59bdb Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 25 Jan 2024 03:01:21 +0100 Subject: fix VpnCertificateValidatorTest, extract CertificateHelper (returns a fingerprint for a x509 cert) from ConfigHelper --- .../base/utils/CertificateHelper.java | 64 ++++++++++++++++++++++ .../providersetup/ProviderApiManagerBase.java | 2 +- .../eip/VpnCertificateValidatorTest.java | 21 +++---- .../leap/bitmaskclient/testutils/MockHelper.java | 14 +---- 4 files changed, 76 insertions(+), 25 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/utils/CertificateHelper.java diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/CertificateHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/CertificateHelper.java new file mode 100644 index 00000000..11202734 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/CertificateHelper.java @@ -0,0 +1,64 @@ +package se.leap.bitmaskclient.base.utils; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import de.blinkt.openvpn.core.NativeUtils; + +public class CertificateHelper { + + public interface CertificateHelperInterface { + String getFingerprintFromCertificate(X509Certificate certificate, String encoding) throws NoSuchAlgorithmException, CertificateEncodingException; + + } + + public static class DefaultCertificateHelper implements CertificateHelperInterface { + + public String byteArrayToHex(byte[] input) { + int readBytes = input.length; + StringBuffer hexData = new StringBuffer(); + int onebyte; + for (int i = 0; i < readBytes; i++) { + onebyte = ((0x000000ff & input[i]) | 0xffffff00); + hexData.append(Integer.toHexString(onebyte).substring(6)); + } + return hexData.toString(); + } + + /** + * Calculates the hexadecimal representation of a sha256/sha1 fingerprint of a certificate + * + * @param certificate + * @param encoding + * @return + * @throws NoSuchAlgorithmException + * @throws CertificateEncodingException + */ + @Override + public String getFingerprintFromCertificate(X509Certificate certificate, String encoding) throws NoSuchAlgorithmException, CertificateEncodingException { + byte[] byteArray = MessageDigest.getInstance(encoding).digest(certificate.getEncoded()); + return byteArrayToHex(byteArray); + } + } + + private static CertificateHelperInterface instance = new DefaultCertificateHelper(); + + @VisibleForTesting + public CertificateHelper(CertificateHelperInterface helperInterface) { + if (!NativeUtils.isUnitTest()) { + throw new IllegalStateException("CertificateHelper injected with CertificateHelperInterface outside of an unit test"); + } + instance = helperInterface; + } + + @NonNull + public static String getFingerprintFromCertificate(X509Certificate certificate, String encoding) throws NoSuchAlgorithmException, CertificateEncodingException { + return instance.getFingerprintFromCertificate(certificate, encoding); + } + +} diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 08067d38..05c5448a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -47,7 +47,7 @@ import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_API_IP; import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_IP; import static se.leap.bitmaskclient.base.utils.RSAHelper.parseRsaKeyFromString; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getDomainFromMainURL; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.getFingerprintFromCertificate; +import static se.leap.bitmaskclient.base.utils.CertificateHelper.getFingerprintFromCertificate; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.deleteProviderDetailsFromPreferences; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getFromPersistedProvider; diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/VpnCertificateValidatorTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/VpnCertificateValidatorTest.java index 1cb47f43..a951f144 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/VpnCertificateValidatorTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/VpnCertificateValidatorTest.java @@ -2,25 +2,20 @@ package se.leap.bitmaskclient.eip; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateEncodingException; import java.util.Calendar; -import se.leap.bitmaskclient.base.utils.ConfigHelper; +import se.leap.bitmaskclient.base.utils.CertificateHelper; import se.leap.bitmaskclient.testutils.TestCalendarProvider; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static se.leap.bitmaskclient.testutils.MockHelper.mockConfigHelper; +import static se.leap.bitmaskclient.testutils.MockHelper.mockCertificateHelper; import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString; -@RunWith(PowerMockRunner.class) -@PrepareForTest({ConfigHelper.class}) public class VpnCertificateValidatorTest { @Before @@ -31,7 +26,7 @@ public class VpnCertificateValidatorTest { public void test_isValid() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem")); Calendar c = new Calendar.Builder().setDate(2018, 1, 1).setCalendarType("gregorian").build(); - mockConfigHelper("falseFingerPrint"); + CertificateHelper helper = mockCertificateHelper("falseFingerPrint"); VpnCertificateValidator validator = new VpnCertificateValidator(cert); validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); assertTrue( validator.isValid()); @@ -41,7 +36,7 @@ public class VpnCertificateValidatorTest { public void test_isValid_lessThan1day_returnFalse() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem")); Calendar c = new Calendar.Builder().setDate(2024, 3, 28).setCalendarType("gregorian").build(); - mockConfigHelper("falseFingerPrint"); + CertificateHelper helper = mockCertificateHelper("falseFingerPrint"); VpnCertificateValidator validator = new VpnCertificateValidator(cert); validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); assertFalse( validator.isValid()); @@ -51,7 +46,7 @@ public class VpnCertificateValidatorTest { public void test_isValid_multipleCerts_failIfOneExpires() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("float.hexacab.org.pem")); Calendar c = new Calendar.Builder().setDate(2024, 3, 28).setCalendarType("gregorian").build(); - mockConfigHelper("falseFingerPrint"); + CertificateHelper helper = mockCertificateHelper("falseFingerPrint"); VpnCertificateValidator validator = new VpnCertificateValidator(cert); validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); assertFalse(validator.isValid()); @@ -61,7 +56,7 @@ public class VpnCertificateValidatorTest { public void test_isValid_multipleCerts_allValid() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("float.hexacab.org.pem")); Calendar c = new Calendar.Builder().setDate(2024, 3, 27).setCalendarType("gregorian").build(); - mockConfigHelper("falseFingerPrint"); + CertificateHelper helper = mockCertificateHelper("falseFingerPrint"); VpnCertificateValidator validator = new VpnCertificateValidator(cert); validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); assertTrue(validator.isValid()); @@ -71,7 +66,7 @@ public class VpnCertificateValidatorTest { public void test_shouldBeUpdated_lessThan8days_returnTrue() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("float.hexacab.org.pem")); Calendar c = new Calendar.Builder().setDate(2024, 3, 21).setCalendarType("gregorian").build(); - mockConfigHelper("falseFingerPrint"); + CertificateHelper helper = mockCertificateHelper("falseFingerPrint"); VpnCertificateValidator validator = new VpnCertificateValidator(cert); validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); assertTrue(validator.shouldBeUpdated()); @@ -81,7 +76,7 @@ public class VpnCertificateValidatorTest { public void test_shouldBeUpdated_moreThan8days_returnFalse() throws NoSuchAlgorithmException, CertificateEncodingException, IOException { String cert = getInputAsString(getClass().getClassLoader().getResourceAsStream("float.hexacab.org.pem")); Calendar c = new Calendar.Builder().setDate(2024, 3, 20).setCalendarType("gregorian").build(); - mockConfigHelper("falseFingerPrint"); + CertificateHelper helper = mockCertificateHelper("falseFingerPrint"); VpnCertificateValidator validator = new VpnCertificateValidator(cert); validator.setCalendarProvider(new TestCalendarProvider(c.getTimeInMillis())); assertFalse(validator.shouldBeUpdated()); diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java index daa67282..869e3190 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java @@ -50,7 +50,6 @@ import java.math.BigInteger; import java.net.UnknownHostException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateEncodingException; -import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.util.ArrayList; import java.util.Arrays; @@ -69,7 +68,7 @@ import okhttp3.OkHttpClient; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.models.ProviderObservable; -import se.leap.bitmaskclient.base.utils.ConfigHelper; +import se.leap.bitmaskclient.base.utils.CertificateHelper; import se.leap.bitmaskclient.base.utils.FileHelper; import se.leap.bitmaskclient.base.utils.InputStreamHelper; import se.leap.bitmaskclient.base.utils.ObfsVpnHelper; @@ -473,15 +472,8 @@ public class MockHelper { }); } - public static void mockConfigHelper(String mockedFingerprint) throws CertificateEncodingException, NoSuchAlgorithmException { - mockStatic(ConfigHelper.class); - when(ConfigHelper.getFingerprintFromCertificate(any(X509Certificate.class), anyString())).thenReturn(mockedFingerprint); - when(ConfigHelper.checkErroneousDownload(anyString())).thenCallRealMethod(); - when(ConfigHelper.parseX509CertificatesFromString(anyString())).thenCallRealMethod(); - when(ConfigHelper.getProviderFormattedString(any(Resources.class), anyInt())).thenCallRealMethod(); - when(ConfigHelper.isIPv4(anyString())).thenCallRealMethod(); - when(ConfigHelper.isDefaultBitmask()).thenReturn(true); - when(ConfigHelper.getDomainFromMainURL(anyString())).thenCallRealMethod(); + public static CertificateHelper mockCertificateHelper(String mockedFingerprint) { + return new CertificateHelper((certificate, encoding) -> mockedFingerprint); } public static void mockPreferenceHelper(final Provider providerFromPrefs) { -- cgit v1.2.3