diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/domain/repository/FileOpeningRepositoryImplTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/domain/repository/FileOpeningRepositoryImplTest.kt
index 66bd01d71..8019bf2f4 100644
--- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/domain/repository/FileOpeningRepositoryImplTest.kt
+++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/domain/repository/FileOpeningRepositoryImplTest.kt
@@ -95,7 +95,7 @@ class FileOpeningRepositoryImplTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {
diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/domain/service/siva/SivaServiceTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/domain/service/siva/SivaServiceTest.kt
index 756dba119..503f6f046 100644
--- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/domain/service/siva/SivaServiceTest.kt
+++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/domain/service/siva/SivaServiceTest.kt
@@ -104,7 +104,7 @@ class SivaServiceTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {
diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/DiagnosticsViewModelTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/DiagnosticsViewModelTest.kt
index 7e3791e8b..5cc058c34 100644
--- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/DiagnosticsViewModelTest.kt
+++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/DiagnosticsViewModelTest.kt
@@ -149,7 +149,7 @@ class DiagnosticsViewModelTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {
diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/FileOpeningViewModelTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/FileOpeningViewModelTest.kt
index 0e6f004d7..742abd24a 100644
--- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/FileOpeningViewModelTest.kt
+++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/FileOpeningViewModelTest.kt
@@ -150,7 +150,7 @@ class FileOpeningViewModelTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
CryptoInitialization().init()
diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/MobileIdViewModelTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/MobileIdViewModelTest.kt
index 551b5b33c..aa01fb740 100644
--- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/MobileIdViewModelTest.kt
+++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/MobileIdViewModelTest.kt
@@ -168,7 +168,7 @@ class MobileIdViewModelTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {
diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/RecentDocumentsViewModelTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/RecentDocumentsViewModelTest.kt
index 991d1cf77..acd64f517 100644
--- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/RecentDocumentsViewModelTest.kt
+++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/RecentDocumentsViewModelTest.kt
@@ -109,7 +109,7 @@ class RecentDocumentsViewModelTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {
diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/SigningViewModelTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/SigningViewModelTest.kt
index 03400e2d7..ac9f95123 100644
--- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/SigningViewModelTest.kt
+++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/SigningViewModelTest.kt
@@ -121,7 +121,7 @@ class SigningViewModelTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {
diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/SmartIdViewModelTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/SmartIdViewModelTest.kt
index fe3e0a8b1..e239d8206 100644
--- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/SmartIdViewModelTest.kt
+++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/SmartIdViewModelTest.kt
@@ -175,7 +175,7 @@ class SmartIdViewModelTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {
diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedContainerViewModelTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedContainerViewModelTest.kt
index cf0ee584e..16b689ebd 100644
--- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedContainerViewModelTest.kt
+++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedContainerViewModelTest.kt
@@ -110,7 +110,7 @@ class SharedContainerViewModelTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {
diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedSettingsViewModelTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedSettingsViewModelTest.kt
index 693e4ec92..2dfcd65db 100644
--- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedSettingsViewModelTest.kt
+++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/viewmodel/shared/SharedSettingsViewModelTest.kt
@@ -103,7 +103,7 @@ class SharedSettingsViewModelTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {
diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/MainActivity.kt b/app/src/main/kotlin/ee/ria/DigiDoc/MainActivity.kt
index 0108d23f3..d93b3d4d8 100644
--- a/app/src/main/kotlin/ee/ria/DigiDoc/MainActivity.kt
+++ b/app/src/main/kotlin/ee/ria/DigiDoc/MainActivity.kt
@@ -56,6 +56,7 @@ import ee.ria.DigiDoc.utilsLib.file.FileUtil.getExternalFileUris
import ee.ria.DigiDoc.utilsLib.file.FileUtil.getLogsDirectory
import ee.ria.DigiDoc.utilsLib.locale.LocaleUtil.getLocale
import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.launch
import java.util.logging.Logger
import javax.inject.Inject
@@ -88,6 +89,8 @@ class MainActivity :
@Inject
lateinit var secureUtil: SecureUtil
+ private val logTag = "MainActivity"
+
private var isAppReady = false
override fun onCreate(savedInstanceState: Bundle?) {
@@ -160,15 +163,21 @@ class MainActivity :
)
val isLoggingEnabled = isDebug || (isDiagnosticsLoggingEnabled && isDiagnosticsLoggingRunning)
lifecycleScope.launch {
- LoggingUtil.initialize(
- applicationContext,
- Logger.getLogger(MainActivity::class.java.name),
- isLoggingEnabled,
- )
- fileTypeSetup.initializeApplicationFileTypesAssociation(componentClassName)
- librarySetup.setupLibraries(applicationContext, isLoggingEnabled)
-
- isAppReady = true
+ try {
+ LoggingUtil.initialize(
+ applicationContext,
+ Logger.getLogger(MainActivity::class.java.name),
+ isLoggingEnabled,
+ )
+ fileTypeSetup.initializeApplicationFileTypesAssociation(componentClassName)
+ librarySetup.setupLibraries(applicationContext, isLoggingEnabled)
+ } catch (ce: CancellationException) {
+ throw ce
+ } catch (t: Throwable) {
+ LoggingUtil.errorLog(logTag, "Unable to complete application setup", t)
+ } finally {
+ isAppReady = true
+ }
setContent {
RIADigiDocTheme(darkTheme = useDarkMode) {
diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DiagnosticsScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DiagnosticsScreen.kt
index 0cd698e23..bcd4572df 100644
--- a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DiagnosticsScreen.kt
+++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/DiagnosticsScreen.kt
@@ -68,6 +68,8 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import ee.ria.DigiDoc.BuildConfig
import ee.ria.DigiDoc.R
+import ee.ria.DigiDoc.configuration.exception.ConfigurationSignatureValidationException
+import ee.ria.DigiDoc.configuration.exception.PublicKeyNotFoundException
import ee.ria.DigiDoc.ui.component.menu.SettingsMenuBottomSheet
import ee.ria.DigiDoc.ui.component.settings.SettingsSwitchItem
import ee.ria.DigiDoc.ui.component.shared.CancelAndOkButtonRow
@@ -91,6 +93,7 @@ import ee.ria.DigiDoc.utilsLib.file.FileUtil.sanitizeString
import ee.ria.DigiDoc.viewmodel.DiagnosticsViewModel
import ee.ria.DigiDoc.viewmodel.shared.SharedMenuViewModel
import ee.ria.DigiDoc.viewmodel.shared.SharedSettingsViewModel
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -219,6 +222,12 @@ fun DiagnosticsScreen(
diagnosticsViewModel.updateConfiguration(context)
}
showMessage(context, R.string.configuration_update_success, SnackbarType.SUCCESS)
+ } catch (_: ConfigurationSignatureValidationException) {
+ showMessage(context, R.string.configuration_update_validation_failed)
+ } catch (_: PublicKeyNotFoundException) {
+ showMessage(context, R.string.configuration_initialization_failed)
+ } catch (ce: CancellationException) {
+ throw ce
} catch (_: Exception) {
showMessage(context, R.string.configuration_update_failed)
}
diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/init/LibrarySetup.kt b/app/src/main/kotlin/ee/ria/DigiDoc/init/LibrarySetup.kt
index ce964e73f..d8cbea270 100644
--- a/app/src/main/kotlin/ee/ria/DigiDoc/init/LibrarySetup.kt
+++ b/app/src/main/kotlin/ee/ria/DigiDoc/init/LibrarySetup.kt
@@ -24,6 +24,8 @@ package ee.ria.DigiDoc.init
import android.content.Context
import android.widget.Toast
import ee.ria.DigiDoc.R
+import ee.ria.DigiDoc.configuration.exception.ConfigurationSignatureValidationException
+import ee.ria.DigiDoc.configuration.exception.PublicKeyNotFoundException
import ee.ria.DigiDoc.configuration.loader.ConfigurationLoader
import ee.ria.DigiDoc.configuration.utils.TSLUtil
import ee.ria.DigiDoc.cryptolib.init.CryptoInitialization
@@ -31,10 +33,15 @@ import ee.ria.DigiDoc.domain.preferences.DataStore
import ee.ria.DigiDoc.libdigidoclib.exceptions.AlreadyInitializedException
import ee.ria.DigiDoc.libdigidoclib.init.Initialization
import ee.ria.DigiDoc.libdigidoclib.init.LibdigidocLibraryLoader
+import ee.ria.DigiDoc.utils.locale.LocaleUtil
import ee.ria.DigiDoc.utils.snackbar.SnackBarManager
+import ee.ria.DigiDoc.utilsLib.locale.LocaleUtil.getLocale
import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.errorLog
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import java.io.InterruptedIOException
import java.net.SocketTimeoutException
@@ -51,61 +58,107 @@ class LibrarySetup
private val configurationLoader: ConfigurationLoader,
private val dataStore: DataStore,
private val libdigidocLibraryLoader: LibdigidocLibraryLoader,
+ private val localeUtil: LocaleUtil,
) {
private val logTag = "LibrarySetup"
+
+ private val setupMutex = Mutex()
private var isConfigured = false
suspend fun setupLibraries(
context: Context,
isLoggingEnabled: Boolean,
) {
+ val localizedContext = localeUtil.updateLocale(context, dataStore.getLocale() ?: getLocale("en"))
+
libdigidocLibraryLoader.init(context)
cryptoInitialization.init(isLoggingEnabled)
- if (!isConfigured) {
- withContext(IO) {
- try {
- TSLUtil.setupTSLFiles(context)
- configurationLoader.initConfiguration(
- context,
- dataStore.getProxySetting(),
- dataStore.getManualProxySettings(),
- )
- isConfigured = true
- } catch (ex: Exception) {
- if (ex !is UnknownHostException &&
- ex !is SocketTimeoutException &&
- ex !is InterruptedIOException
- ) {
- errorLog(
- logTag,
- "Unable to initialize configuration: ",
- ex,
+ setupMutex.withLock {
+ if (!isConfigured) {
+ withContext(IO) {
+ try {
+ TSLUtil.setupTSLFiles(context)
+ configurationLoader.initConfiguration(
+ context,
+ dataStore.getProxySetting(),
+ dataStore.getManualProxySettings(),
)
+ isConfigured = true
+ } catch (ex: ConfigurationSignatureValidationException) {
+ errorLog(logTag, "Configuration signature validation failed", ex)
+
+ val hasConfiguration = configurationLoader.getConfigurationFlow().value != null
+ isConfigured = hasConfiguration
+
+ withContext(Main) {
+ SnackBarManager.showMessage(
+ localizedContext,
+ if (hasConfiguration) {
+ R.string.configuration_update_validation_failed
+ } else {
+ R.string.configuration_initialization_failed
+ },
+ )
+ }
+ } catch (ex: PublicKeyNotFoundException) {
+ errorLog(logTag, "Bundled signing key unavailable", ex)
+
withContext(Main) {
SnackBarManager.showMessage(
- context,
+ localizedContext,
R.string.configuration_initialization_failed,
)
}
+ } catch (ce: CancellationException) {
+ throw ce
+ } catch (ex: Exception) {
+ if (ex !is UnknownHostException &&
+ ex !is SocketTimeoutException &&
+ ex !is InterruptedIOException
+ ) {
+ errorLog(
+ logTag,
+ "Unable to initialize configuration: ",
+ ex,
+ )
+ withContext(Main) {
+ SnackBarManager.showMessage(
+ localizedContext,
+ R.string.configuration_initialization_failed,
+ )
+ }
+ }
+ }
+
+ if (configurationLoader.getConfigurationFlow().value == null) {
+ try {
+ configurationLoader.loadLocalConfiguration(context)
+ } catch (ce: CancellationException) {
+ throw ce
+ } catch (fallbackFailure: Exception) {
+ errorLog(logTag, "Unable to load local configuration", fallbackFailure)
+ }
}
}
}
- }
- try {
- initialization.init(context, isLoggingEnabled)
- } catch (e: Exception) {
- if (e !is AlreadyInitializedException) {
- errorLog(logTag, "Unable to initialize libdigidocpp", e)
- withContext(Main) {
- Toast
- .makeText(
- context,
- R.string.libdigidocpp_initialization_failed,
- Toast.LENGTH_LONG,
- ).show()
+ try {
+ initialization.init(context, isLoggingEnabled)
+ } catch (ce: CancellationException) {
+ throw ce
+ } catch (e: Exception) {
+ if (e !is AlreadyInitializedException) {
+ errorLog(logTag, "Unable to initialize libdigidocpp", e)
+ withContext(Main) {
+ Toast
+ .makeText(
+ localizedContext,
+ R.string.libdigidocpp_initialization_failed,
+ Toast.LENGTH_LONG,
+ ).show()
+ }
}
}
}
diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml
index e069e2a03..d9e13eaf4 100644
--- a/app/src/main/res/values-et/strings.xml
+++ b/app/src/main/res/values-et/strings.xml
@@ -485,6 +485,7 @@
Konfiguratsioon uuendatud
RIA DigiDoci konfiguratsiooni värskendamine õnnestus
Palun kontrolli internetiühendust ja võrgu sätteid
+ Serveris olev konfiguratsioonifail ei valideeru
Keel muudetud
Teema muudetud
Seade väärtus muudetud
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c5c37fcc9..4ba1443fc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -485,6 +485,7 @@
Configuration updated
RIA DigiDoc configuration update was successful
Please check your internet connection and network settings
+ The configuration file located on the server cannot be validated
Language changed
Theme changed
Setting value changed
diff --git a/app/src/test/kotlin/ee/ria/DigiDoc/init/LibrarySetupTest.kt b/app/src/test/kotlin/ee/ria/DigiDoc/init/LibrarySetupTest.kt
new file mode 100644
index 000000000..4186c7f87
--- /dev/null
+++ b/app/src/test/kotlin/ee/ria/DigiDoc/init/LibrarySetupTest.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2017 - 2026 Riigi Infosüsteemi Amet
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+@file:Suppress("PackageName")
+
+package ee.ria.DigiDoc.init
+
+import android.content.Context
+import android.content.res.AssetManager
+import ee.ria.DigiDoc.R
+import ee.ria.DigiDoc.configuration.exception.ConfigurationSignatureValidationException
+import ee.ria.DigiDoc.configuration.loader.ConfigurationLoader
+import ee.ria.DigiDoc.configuration.provider.ConfigurationProvider
+import ee.ria.DigiDoc.cryptolib.init.CryptoInitialization
+import ee.ria.DigiDoc.domain.preferences.DataStore
+import ee.ria.DigiDoc.libdigidoclib.init.Initialization
+import ee.ria.DigiDoc.libdigidoclib.init.LibdigidocLibraryLoader
+import ee.ria.DigiDoc.network.proxy.ManualProxy
+import ee.ria.DigiDoc.network.proxy.ProxySetting
+import ee.ria.DigiDoc.utils.locale.LocaleUtil
+import ee.ria.DigiDoc.utilsLib.MainDispatcherRule
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.kotlin.any
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+import java.net.UnknownHostException
+import java.nio.file.Files
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class LibrarySetupTest {
+ @get:Rule
+ val mainDispatcherRule = MainDispatcherRule()
+
+ private lateinit var context: Context
+ private lateinit var localizedContext: Context
+ private lateinit var configurationLoader: ConfigurationLoader
+ private lateinit var initialization: Initialization
+ private lateinit var librarySetup: LibrarySetup
+
+ @Before
+ fun setUp() {
+ val assets = mock()
+ whenever(assets.list("tslFiles")).thenReturn(emptyArray())
+
+ context = mock()
+ whenever(context.cacheDir).thenReturn(Files.createTempDirectory("librarySetupTest").toFile())
+ whenever(context.assets).thenReturn(assets)
+
+ localizedContext = mock()
+ whenever(localizedContext.getString(any())).thenReturn("message")
+
+ val dataStore = mock()
+ whenever(dataStore.getProxySetting()).thenReturn(ProxySetting.NO_PROXY)
+ whenever(dataStore.getManualProxySettings()).thenReturn(ManualProxy("", 80, "", ""))
+
+ val localeUtil = mock()
+ whenever(localeUtil.updateLocale(any(), any())).thenReturn(localizedContext)
+
+ configurationLoader = mock()
+
+ initialization = mock()
+
+ librarySetup =
+ LibrarySetup(
+ initialization,
+ mock(),
+ configurationLoader,
+ dataStore,
+ mock(),
+ localeUtil,
+ )
+ }
+
+ @Test
+ fun librarySetup_setupLibraries_showsValidationMessageWhenCentralConfigurationCannotBeValidated() =
+ runTest {
+ givenLoadedConfiguration(true)
+ givenInitConfigurationFails(ConfigurationSignatureValidationException())
+
+ librarySetup.setupLibraries(context, false)
+
+ verify(localizedContext).getString(R.string.configuration_update_validation_failed)
+ verify(localizedContext, never()).getString(R.string.configuration_initialization_failed)
+ verify(context, never()).getString(any())
+ }
+
+ @Test
+ fun librarySetup_setupLibraries_showsInitializationFailedMessageWhenNoConfigurationLoaded() =
+ runTest {
+ givenLoadedConfiguration(false)
+ givenInitConfigurationFails(ConfigurationSignatureValidationException())
+
+ librarySetup.setupLibraries(context, false)
+
+ verify(localizedContext).getString(R.string.configuration_initialization_failed)
+ verify(localizedContext, never()).getString(R.string.configuration_update_validation_failed)
+ }
+
+ @Test
+ fun librarySetup_setupLibraries_showsNoMessageWhenNetworkIsUnavailable() =
+ runTest {
+ givenLoadedConfiguration(true)
+ givenInitConfigurationFails(UnknownHostException())
+
+ librarySetup.setupLibraries(context, false)
+
+ verify(localizedContext, never()).getString(any())
+ }
+
+ @Test
+ fun librarySetup_setupLibraries_showsInitializationFailedMessageWhenConfigurationFailsForOtherReason() =
+ runTest {
+ givenLoadedConfiguration(true)
+ givenInitConfigurationFails(IllegalStateException("broken"))
+
+ librarySetup.setupLibraries(context, false)
+
+ verify(localizedContext).getString(R.string.configuration_initialization_failed)
+ verify(localizedContext, never()).getString(R.string.configuration_update_validation_failed)
+ }
+
+ @Test
+ fun librarySetup_setupLibraries_doesNotRetryConfigurationWhenValidationFailedButConfigurationLoaded() =
+ runTest {
+ givenLoadedConfiguration(true)
+ givenInitConfigurationFails(ConfigurationSignatureValidationException())
+
+ librarySetup.setupLibraries(context, false)
+ librarySetup.setupLibraries(context, false)
+
+ verify(configurationLoader, times(1)).initConfiguration(any(), anyOrNull(), any())
+ verify(initialization, times(2)).init(any(), any())
+ }
+
+ @Test
+ fun librarySetup_setupLibraries_configuresOnceWhenEnteredConcurrently() =
+ runTest {
+ givenLoadedConfiguration(true)
+
+ coroutineScope {
+ launch { librarySetup.setupLibraries(context, false) }
+ launch { librarySetup.setupLibraries(context, false) }
+ }
+
+ verify(configurationLoader, times(1)).initConfiguration(any(), anyOrNull(), any())
+ verify(initialization, times(2)).init(any(), any())
+ }
+
+ @Test
+ fun librarySetup_setupLibraries_loadsFallbackConfigurationWhenNoneLoaded() =
+ runTest {
+ givenLoadedConfiguration(false)
+ givenInitConfigurationFails(IllegalStateException("broken"))
+
+ librarySetup.setupLibraries(context, false)
+
+ verify(configurationLoader).loadLocalConfiguration(context)
+ }
+
+ @Test
+ fun librarySetup_setupLibraries_skipsFallbackWhenConfigurationAlreadyLoaded() =
+ runTest {
+ givenLoadedConfiguration(true)
+ givenInitConfigurationFails(IllegalStateException("broken"))
+
+ librarySetup.setupLibraries(context, false)
+
+ verify(configurationLoader, never()).loadLocalConfiguration(any())
+ }
+
+ private fun givenLoadedConfiguration(loaded: Boolean) {
+ val configuration = if (loaded) mock() else null
+ whenever(configurationLoader.getConfigurationFlow()).thenReturn(MutableStateFlow(configuration))
+ }
+
+ private suspend fun givenInitConfigurationFails(throwable: Throwable) {
+ whenever(configurationLoader.initConfiguration(any(), anyOrNull(), any())).thenThrow(throwable)
+ }
+}
diff --git a/codemagic.yaml b/codemagic.yaml
index 9852d7346..cafdfe4d4 100644
--- a/codemagic.yaml
+++ b/codemagic.yaml
@@ -103,14 +103,24 @@ workflows:
# Get repo.ria values from environmental variables, as CodeMagic doesn't have access to repo.ria domain
if [[ "${{ inputs.defaultCentralConfigurationTslUrl_input }}" == *"ria.test"* ]]; then
echo "Using repo.ria configuration"
- echo $REPO_RIA_DEFAULT_PROPERTIES | base64 --decode > $CONFIG_DIR/configuration.properties
- echo $REPO_RIA_CONFIG | base64 --decode > $CONFIG_DIR/default-config.json
- echo $REPO_RIA_PUB_KEY | base64 --decode > $CONFIG_DIR/default-config.pub
- echo $REPO_RIA_RSA | base64 --decode > $CONFIG_DIR/default-config.rsa
+ echo $REPO_RIA_EC_DEFAULT_PROPERTIES | base64 --decode > $CONFIG_DIR/configuration.properties
+ echo $REPO_RIA_EC_CONFIG | base64 --decode > $CONFIG_DIR/default-config.json
+ echo $REPO_RIA_EC_PUB_KEY | base64 --decode > $CONFIG_DIR/default-config.ecpub
+ echo $REPO_RIA_EC_SIGNATURE | base64 --decode > $CONFIG_DIR/default-config.ecc
echo $REPO_RIA_TRUSTED_TEST_MP | base64 --decode > $TSL_FILES_DIR/trusted-test-mp.xml
echo $REPO_RIA_TL_MP_TEST_EE | base64 --decode > $TSL_FILES_DIR/tl-mp-test-EE.xml
# EE_T.xml is too large to use in environmental variable. Using compressed variant
+ set -o pipefail
echo $REPO_RIA_EE_TSL | base64 --decode | gunzip > $TSL_FILES_DIR/EE_T.xml
+ for configFile in "$CONFIG_DIR/configuration.properties" "$CONFIG_DIR/default-config.json" \
+ "$CONFIG_DIR/default-config.ecpub" "$CONFIG_DIR/default-config.ecc" \
+ "$TSL_FILES_DIR/trusted-test-mp.xml" "$TSL_FILES_DIR/tl-mp-test-EE.xml" \
+ "$TSL_FILES_DIR/EE_T.xml"; do
+ if [ ! -s "$configFile" ]; then
+ echo "ERROR: $configFile is missing or empty"
+ exit 1
+ fi
+ done
else
echo "Not using repo.ria configuration"
fi
diff --git a/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/cache/ConfigurationCacheTest.kt b/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/cache/ConfigurationCacheTest.kt
index 081d92a89..27ab23111 100644
--- a/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/cache/ConfigurationCacheTest.kt
+++ b/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/cache/ConfigurationCacheTest.kt
@@ -58,12 +58,11 @@ class ConfigurationCacheTest {
@Test
fun configurationCache_cacheConfigurationFiles_success() {
- ConfigurationCache.cacheConfigurationFiles(context, testStringData, testStringData, testByteArrayData)
+ ConfigurationCache.cacheConfigurationFiles(context, testStringData, testByteArrayData)
- assertEquals(3, File(context.cacheDir, CACHE_CONFIG_FOLDER).listFiles()?.size ?: 0)
+ assertEquals(2, File(context.cacheDir, CACHE_CONFIG_FOLDER).listFiles()?.size ?: 0)
assertTrue(File(File(context.cacheDir, CACHE_CONFIG_FOLDER), "active-config.json").exists())
- assertTrue(File(File(context.cacheDir, CACHE_CONFIG_FOLDER), "active-config.pub").exists())
- assertTrue(File(File(context.cacheDir, CACHE_CONFIG_FOLDER), "active-config.rsa").exists())
+ assertTrue(File(File(context.cacheDir, CACHE_CONFIG_FOLDER), "active-config.ecc").exists())
}
@Test
diff --git a/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/domain/model/ConfigurationViewModelTest.kt b/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/domain/model/ConfigurationViewModelTest.kt
deleted file mode 100644
index 2ef956dd2..000000000
--- a/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/domain/model/ConfigurationViewModelTest.kt
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2017 - 2026 Riigi Infosüsteemi Amet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-@file:Suppress("PackageName")
-
-package ee.ria.DigiDoc.configuration.domain.model
-
-import androidx.arch.core.executor.testing.InstantTaskExecutorRule
-import androidx.lifecycle.Observer
-import ee.ria.DigiDoc.common.Constant.Defaults.DEFAULT_UUID_VALUE
-import ee.ria.DigiDoc.configuration.provider.ConfigurationProvider
-import ee.ria.DigiDoc.configuration.repository.ConfigurationRepository
-import ee.ria.DigiDoc.network.proxy.ManualProxy
-import ee.ria.DigiDoc.network.proxy.ProxySetting
-import kotlinx.coroutines.runBlocking
-import org.junit.Assert
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
-import org.mockito.MockitoAnnotations
-import org.mockito.junit.MockitoJUnitRunner
-import java.util.Date
-import java.util.UUID
-
-@RunWith(MockitoJUnitRunner::class)
-class ConfigurationViewModelTest {
- @get:Rule
- val instantTaskExecutorRule = InstantTaskExecutorRule()
-
- @Mock
- private lateinit var repository: ConfigurationRepository
-
- @Mock
- private lateinit var configurationProviderObserver: Observer
-
- private lateinit var proxySetting: ProxySetting
- private lateinit var manualProxy: ManualProxy
-
- private lateinit var viewModel: ConfigurationViewModel
-
- @Before
- fun setUp() {
- MockitoAnnotations.openMocks(this)
- viewModel = ConfigurationViewModel(repository)
-
- proxySetting = ProxySetting.NO_PROXY
- manualProxy = ManualProxy("", 80, "", "")
- }
-
- @Test
- fun configurationViewModel_getConfiguration_success() =
- runBlocking {
- `when`(repository.getConfiguration())
- .thenReturn(createMockConfigurationProvider())
- viewModel.configuration.observeForever(configurationProviderObserver)
-
- val configuration = viewModel.getConfiguration()
-
- Assert.assertNotNull(configuration)
- Assert.assertEquals(1, configuration?.metaInf?.serial)
- }
-
- @Test
- fun configurationViewModel_fetchConfiguration_configurationIsFetchedAndChanged() =
- runBlocking {
- val configurationProvider = createMockConfigurationProvider()
- `when`(repository.getCentralConfiguration(proxySetting, manualProxy))
- .thenReturn(configurationProvider)
- viewModel.configuration.observeForever(configurationProviderObserver)
-
- viewModel.fetchConfiguration(0L, proxySetting, manualProxy)
-
- verify(repository, times(1)).getCentralConfiguration(proxySetting, manualProxy)
- verify(configurationProviderObserver, times(1))
- .onChanged(configurationProvider)
- }
-
- @Test
- fun configurationViewModel_fetchConfiguration_configurationFetchedButNotChanged() =
- runBlocking {
- val configurationProvider = createMockConfigurationProvider()
- `when`(repository.getCentralConfiguration(proxySetting, manualProxy))
- .thenReturn(configurationProvider)
- viewModel.configuration.observeForever(configurationProviderObserver)
-
- viewModel.fetchConfiguration(Date().time, proxySetting, manualProxy)
-
- verify(repository, times(1)).getCentralConfiguration(proxySetting, manualProxy)
- verify(configurationProviderObserver, never())
- .onChanged(configurationProvider)
- }
-
- private fun createMockConfigurationProvider(): ConfigurationProvider =
- ConfigurationProvider(
- ConfigurationProvider.MetaInf("url", "date", 1, 1),
- "sivaUrl",
- mapOf(
- DEFAULT_UUID_VALUE to
- ConfigurationProvider.CDOC2Conf(
- uuid = UUID.randomUUID(),
- name = "RIA",
- post = "https://cdoc2.id.ee:8443",
- fetch = "https://cdoc2.id.ee:8444",
- ),
- ),
- false,
- false,
- DEFAULT_UUID_VALUE,
- "tslUrl",
- emptyList(),
- "tsaUrl",
- "ldapPersonUrl",
- ldapPersonUrls = listOf("ldapPersonUrl"),
- "ldapCorpUrl",
- "midRestUrl",
- "midSkRestUrl",
- "sidV2RestUrl",
- "sidV2SkRestUrl",
- emptyList(),
- Date(),
- Date(),
- )
-}
diff --git a/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderTest.kt b/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderTest.kt
index ec0b295e2..ccc9daf51 100644
--- a/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderTest.kt
+++ b/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderTest.kt
@@ -34,9 +34,8 @@ import ee.ria.DigiDoc.configuration.properties.ConfigurationProperties
import ee.ria.DigiDoc.configuration.properties.ConfigurationPropertiesImpl
import ee.ria.DigiDoc.configuration.provider.ConfigurationProvider
import ee.ria.DigiDoc.configuration.repository.CentralConfigurationRepository
+import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_ECC
import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_JSON
-import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_PUB
-import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_RSA
import ee.ria.DigiDoc.configuration.utils.Constant.CACHE_CONFIG_FOLDER
import ee.ria.DigiDoc.configuration.utils.Constant.CONFIGURATION_LAST_UPDATE_CHECK_DATE_PROPERTY_NAME
import ee.ria.DigiDoc.configuration.utils.Constant.CONFIGURATION_PREFERENCES
@@ -111,13 +110,12 @@ class ConfigurationLoaderTest {
propertiesFile = AssetFile.getAssetFileAsFile(context, "config/configuration.properties")
confFile = AssetFile.getAssetFileAsFile(context, "config/default-config.json")
- publicKeyFile = AssetFile.getAssetFileAsFile(context, "config/default-config.pub")
- signatureFile = AssetFile.getAssetFileAsFile(context, "config/default-config.rsa")
+ publicKeyFile = AssetFile.getAssetFileAsFile(context, "config/default-config.ecpub")
+ signatureFile = AssetFile.getAssetFileAsFile(context, "config/default-config.ecc")
File(context.cacheDir, CACHE_CONFIG_FOLDER).mkdirs()
Files.copy(confFile, File(File(context.cacheDir, CACHE_CONFIG_FOLDER), CACHED_CONFIG_JSON))
- Files.copy(publicKeyFile, File(File(context.cacheDir, CACHE_CONFIG_FOLDER), CACHED_CONFIG_PUB))
- Files.copy(signatureFile, File(File(context.cacheDir, CACHE_CONFIG_FOLDER), CACHED_CONFIG_RSA))
+ Files.copy(signatureFile, File(File(context.cacheDir, CACHE_CONFIG_FOLDER), CACHED_CONFIG_ECC))
proxySetting = ProxySetting.NO_PROXY
manualProxy = ManualProxy("", 80, "", "")
@@ -127,8 +125,7 @@ class ConfigurationLoaderTest {
fun tearDown() {
File(context.cacheDir, PROPERTIES_FILE_NAME).delete()
File(File(context.cacheDir, CACHE_CONFIG_FOLDER), CACHED_CONFIG_JSON).delete()
- File(File(context.cacheDir, CACHE_CONFIG_FOLDER), CACHED_CONFIG_PUB).delete()
- File(File(context.cacheDir, CACHE_CONFIG_FOLDER), CACHED_CONFIG_RSA).delete()
+ File(File(context.cacheDir, CACHE_CONFIG_FOLDER), CACHED_CONFIG_ECC).delete()
File(context.cacheDir, CACHE_CONFIG_FOLDER).delete()
}
@@ -191,10 +188,9 @@ class ConfigurationLoaderTest {
val confData = mockConfigurationProvider()
val centralConfig = gson.toJson(confData)
- val centralPublicKey = "Public Key"
+ val centralPublicKey = publicKeyFile.readText()
val centralSignature = "dGVzdA=="
`when`(centralConfigurationRepository.fetchConfiguration()).thenReturn(centralConfig)
- `when`(centralConfigurationRepository.fetchPublicKey()).thenReturn(centralPublicKey)
`when`(centralConfigurationRepository.fetchSignature()).thenReturn(centralSignature)
doNothing()
@@ -217,7 +213,7 @@ class ConfigurationLoaderTest {
// Write random text to file, to make sure that current signature and new signature are different
val configFolder = File(context.cacheDir, CACHE_CONFIG_FOLDER)
configFolder.mkdirs()
- val signatureFile = File(configFolder, CACHED_CONFIG_RSA)
+ val signatureFile = File(configFolder, CACHED_CONFIG_ECC)
FileWriter(signatureFile).use { writer ->
writer.write("dGVzdDI=")
@@ -237,10 +233,9 @@ class ConfigurationLoaderTest {
val confData = mockConfigurationProvider()
val centralConfig = gson.toJson(confData)
- val centralPublicKey = "Public Key"
+ val centralPublicKey = publicKeyFile.readText()
val centralSignature = "dGVzdA=="
`when`(centralConfigurationRepository.fetchConfiguration()).thenReturn(centralConfig)
- `when`(centralConfigurationRepository.fetchPublicKey()).thenReturn(centralPublicKey)
`when`(centralConfigurationRepository.fetchSignature()).thenReturn(centralSignature)
doNothing()
@@ -263,7 +258,7 @@ class ConfigurationLoaderTest {
// Write same signature to file, to make sure that current signature and new signature match
val configFolder = File(context.cacheDir, CACHE_CONFIG_FOLDER)
configFolder.mkdirs()
- val signatureFile = File(configFolder, CACHED_CONFIG_RSA)
+ val signatureFile = File(configFolder, CACHED_CONFIG_ECC)
FileWriter(signatureFile).use { writer ->
writer.write(String(Base64.getDecoder().decode(centralSignature)))
}
@@ -276,33 +271,6 @@ class ConfigurationLoaderTest {
configFolder.delete()
}
- @Test
- fun configurationLoader_loadCentralConfigurationData_success() =
- runBlocking {
- val confData = mockConfigurationProvider()
-
- val centralConfig = gson.toJson(confData)
- val centralPublicKey = "Public Key"
- val centralSignature = "dGVzdA=="
- `when`(centralConfigurationRepository.fetchConfiguration()).thenReturn(centralConfig)
- `when`(centralConfigurationRepository.fetchPublicKey()).thenReturn(centralPublicKey)
- `when`(centralConfigurationRepository.fetchSignature()).thenReturn(centralSignature)
-
- doNothing()
- .`when`(configurationSignatureVerifier)
- .verifyConfigurationSignature(
- centralConfig,
- centralPublicKey,
- Base64.getDecoder().decode(centralSignature),
- )
-
- val configurationData =
- configurationLoader
- .loadCentralConfigurationData("serviceUri", "Tests")
-
- assertNotNull(configurationData)
- }
-
@Test
fun configurationLoader_shouldCheckForUpdates_returnTrueWhenEnoughDaysPassed() =
runBlocking {
diff --git a/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepositoryTest.kt b/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepositoryTest.kt
index 8e968b6f0..22db38f95 100644
--- a/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepositoryTest.kt
+++ b/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepositoryTest.kt
@@ -57,18 +57,6 @@ class CentralConfigurationRepositoryTest {
verify(configurationService).fetchConfiguration()
}
- @Test
- fun centralConfigurationRepository_fetchPublicKey_success(): Unit =
- runBlocking {
- val expectedPublicKey = "Example Public Key"
- `when`(configurationService.fetchPublicKey()).thenReturn(expectedPublicKey)
-
- val result = centralConfigurationRepository.fetchPublicKey()
-
- assertEquals(expectedPublicKey, result)
- verify(configurationService).fetchPublicKey()
- }
-
@Test
fun centralConfigurationRepository_fetchSignature_success(): Unit =
runBlocking {
diff --git a/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepositoryTest.kt b/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepositoryTest.kt
index 4be9358ad..71f0401d6 100644
--- a/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepositoryTest.kt
+++ b/config-lib/src/androidTest/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepositoryTest.kt
@@ -44,7 +44,6 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnitRunner
import java.util.UUID
@@ -70,7 +69,7 @@ class ConfigurationRepositoryTest {
@Before
fun setUp() {
`when`(configurationLoader.getConfigurationFlow()).thenReturn(configurationFlow)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
Dispatchers.setMain(testDispatcher)
proxySetting = ProxySetting.NO_PROXY
@@ -103,18 +102,6 @@ class ConfigurationRepositoryTest {
assertNull(result)
}
- @Test
- fun configurationRepository_getCentralConfiguration_success() =
- runBlocking {
- val configurationProvider = mockConfigurationProvider()
- configurationFlow.value = configurationProvider
-
- val result = configurationRepository.getCentralConfiguration(proxySetting, manualProxy)
- assertNotNull(result)
- assertEquals(configurationProvider, result)
- verify(configurationLoader).loadCentralConfiguration(context, proxySetting, manualProxy)
- }
-
@Test
fun configurationRepository_observeConfigurationUpdates_success() =
runBlocking {
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/ConfigurationSignatureVerifier.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/ConfigurationSignatureVerifier.kt
index f69925938..8de9e77b0 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/ConfigurationSignatureVerifier.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/ConfigurationSignatureVerifier.kt
@@ -21,9 +21,11 @@
package ee.ria.DigiDoc.configuration
+import ee.ria.DigiDoc.configuration.exception.ConfigurationSignatureValidationException
import ee.ria.DigiDoc.configuration.utils.SignatureVerifier
interface ConfigurationSignatureVerifier {
+ @Throws(ConfigurationSignatureValidationException::class)
fun verifyConfigurationSignature(
config: String,
publicKey: String,
@@ -37,7 +39,15 @@ class ConfigurationSignatureVerifierImpl : ConfigurationSignatureVerifier {
publicKey: String,
signature: ByteArray,
) {
- val signatureValid: Boolean = SignatureVerifier.verify(signature, publicKey, config)
- check(signatureValid) { "Configuration signature validation failed!" }
+ val signatureValid =
+ try {
+ SignatureVerifier.verify(signature, publicKey, config)
+ } catch (e: IllegalStateException) {
+ throw ConfigurationSignatureValidationException(e)
+ }
+
+ if (!signatureValid) {
+ throw ConfigurationSignatureValidationException()
+ }
}
}
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/cache/ConfigurationCache.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/cache/ConfigurationCache.kt
index 033e3f848..9d2171b57 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/cache/ConfigurationCache.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/cache/ConfigurationCache.kt
@@ -22,9 +22,8 @@
package ee.ria.DigiDoc.configuration.cache
import android.content.Context
+import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_ECC
import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_JSON
-import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_PUB
-import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_RSA
import ee.ria.DigiDoc.configuration.utils.Constant.CACHE_CONFIG_FOLDER
import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil
import java.io.File
@@ -39,12 +38,10 @@ object ConfigurationCache {
fun cacheConfigurationFiles(
context: Context,
confData: String,
- publicKey: String,
signature: ByteArray,
) {
cacheFile(context, CACHED_CONFIG_JSON, confData)
- cacheFile(context, CACHED_CONFIG_PUB, publicKey)
- cacheFile(context, CACHED_CONFIG_RSA, signature)
+ cacheFile(context, CACHED_CONFIG_ECC, signature)
}
private fun cacheFile(
@@ -71,6 +68,7 @@ object ConfigurationCache {
}
}
+ @Suppress("SameParameterValue")
private fun cacheFile(
context: Context,
fileName: String,
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/di/ConfigModules.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/di/ConfigModules.kt
index 2a399a0f2..4ad0035c5 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/di/ConfigModules.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/di/ConfigModules.kt
@@ -21,12 +21,10 @@
package ee.ria.DigiDoc.configuration.di
-import android.content.Context
import com.google.gson.Gson
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
-import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import ee.ria.DigiDoc.configuration.ConfigurationProperty
import ee.ria.DigiDoc.configuration.ConfigurationSignatureVerifier
@@ -71,10 +69,8 @@ class ConfigModules {
fun provideConfigurationSignatureVerifier(): ConfigurationSignatureVerifier = ConfigurationSignatureVerifierImpl()
@Provides
- fun provideConfigurationRepository(
- @ApplicationContext context: Context,
- configurationLoader: ConfigurationLoader,
- ): ConfigurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ fun provideConfigurationRepository(configurationLoader: ConfigurationLoader): ConfigurationRepository =
+ ConfigurationRepositoryImpl(configurationLoader)
@Provides
fun provideCentralConfigurationRepository(
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/domain/model/ConfigurationViewModel.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/domain/model/ConfigurationViewModel.kt
deleted file mode 100644
index 51f8c2a10..000000000
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/domain/model/ConfigurationViewModel.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2017 - 2026 Riigi Infosüsteemi Amet
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-@file:Suppress("PackageName")
-
-package ee.ria.DigiDoc.configuration.domain.model
-
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.ViewModel
-import dagger.hilt.android.lifecycle.HiltViewModel
-import ee.ria.DigiDoc.configuration.provider.ConfigurationProvider
-import ee.ria.DigiDoc.configuration.repository.ConfigurationRepository
-import ee.ria.DigiDoc.network.proxy.ManualProxy
-import ee.ria.DigiDoc.network.proxy.ProxySetting
-import kotlinx.coroutines.Dispatchers.IO
-import kotlinx.coroutines.withContext
-import java.util.Date
-import javax.inject.Inject
-
-@HiltViewModel
-class ConfigurationViewModel
- @Inject
- constructor(
- private val repository: ConfigurationRepository,
- ) : ViewModel() {
- private val _configuration = MutableLiveData()
- val configuration: MutableLiveData = _configuration
-
- suspend fun fetchConfiguration(
- lastUpdate: Long,
- proxySetting: ProxySetting?,
- manualProxy: ManualProxy,
- ) {
- withContext(IO) {
- try {
- val configurationProvider = repository.getCentralConfiguration(proxySetting, manualProxy)
- val confUpdateDate = configurationProvider?.configurationUpdateDate
- if (lastUpdate == 0L || (confUpdateDate != null && confUpdateDate.after(Date(lastUpdate)))) {
- _configuration.postValue(configurationProvider)
- }
- } catch (_: Exception) {
- // Handle error
- }
- }
- }
-
- fun getConfiguration(): ConfigurationProvider? = repository.getConfiguration()
- }
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/exception/ConfigurationSignatureValidationException.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/exception/ConfigurationSignatureValidationException.kt
new file mode 100644
index 000000000..23a44a54f
--- /dev/null
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/exception/ConfigurationSignatureValidationException.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 - 2026 Riigi Infosüsteemi Amet
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+@file:Suppress("PackageName")
+
+package ee.ria.DigiDoc.configuration.exception
+
+class ConfigurationSignatureValidationException(
+ cause: Throwable? = null,
+) : Exception("Configuration signature validation failed", cause)
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/exception/PublicKeyNotFoundException.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/exception/PublicKeyNotFoundException.kt
new file mode 100644
index 000000000..f4ef05698
--- /dev/null
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/exception/PublicKeyNotFoundException.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 - 2026 Riigi Infosüsteemi Amet
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+@file:Suppress("PackageName")
+
+package ee.ria.DigiDoc.configuration.exception
+
+class PublicKeyNotFoundException(
+ message: String,
+ cause: Throwable? = null,
+) : Exception(message, cause)
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoader.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoader.kt
index 9a33a04e0..83663879e 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoader.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoader.kt
@@ -23,13 +23,13 @@ package ee.ria.DigiDoc.configuration.loader
import android.content.Context
import ee.ria.DigiDoc.configuration.ConfigurationProperty
-import ee.ria.DigiDoc.configuration.domain.model.ConfigurationData
import ee.ria.DigiDoc.configuration.provider.ConfigurationProvider
import ee.ria.DigiDoc.network.proxy.ManualProxy
import ee.ria.DigiDoc.network.proxy.ProxySetting
import kotlinx.coroutines.flow.StateFlow
interface ConfigurationLoader {
+ @Throws(Exception::class)
suspend fun initConfiguration(
context: Context,
proxySetting: ProxySetting?,
@@ -45,13 +45,9 @@ interface ConfigurationLoader {
afterCentralCheck: Boolean,
)
- suspend fun loadDefaultConfiguration(context: Context)
+ suspend fun loadLocalConfiguration(context: Context)
- @Throws(Exception::class)
- suspend fun loadCentralConfigurationData(
- configurationServiceUrl: String,
- userAgent: String,
- ): ConfigurationData
+ suspend fun loadDefaultConfiguration(context: Context)
@Throws(Exception::class)
suspend fun loadCentralConfiguration(
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderImpl.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderImpl.kt
index 625ec2c0b..dd3f7a084 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderImpl.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderImpl.kt
@@ -26,28 +26,30 @@ import com.google.gson.Gson
import ee.ria.DigiDoc.configuration.ConfigurationProperty
import ee.ria.DigiDoc.configuration.ConfigurationSignatureVerifier
import ee.ria.DigiDoc.configuration.cache.ConfigurationCache
-import ee.ria.DigiDoc.configuration.domain.model.ConfigurationData
+import ee.ria.DigiDoc.configuration.exception.ConfigurationSignatureValidationException
+import ee.ria.DigiDoc.configuration.exception.PublicKeyNotFoundException
import ee.ria.DigiDoc.configuration.properties.ConfigurationProperties
import ee.ria.DigiDoc.configuration.provider.ConfigurationProvider
import ee.ria.DigiDoc.configuration.repository.CentralConfigurationRepository
import ee.ria.DigiDoc.configuration.utils.ConfigurationUtil
+import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_ECC
import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_JSON
-import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_PUB
-import ee.ria.DigiDoc.configuration.utils.Constant.CACHED_CONFIG_RSA
import ee.ria.DigiDoc.configuration.utils.Constant.CACHE_CONFIG_FOLDER
+import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIG_ECC
+import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIG_ECPUB
import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIG_JSON
-import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIG_PUB
-import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIG_RSA
import ee.ria.DigiDoc.network.proxy.ManualProxy
import ee.ria.DigiDoc.network.proxy.ProxySetting
import ee.ria.DigiDoc.utilsLib.date.DateUtil
import ee.ria.DigiDoc.utilsLib.extensions.removeWhitespaces
import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.errorLog
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.io.File
+import java.io.IOException
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.temporal.ChronoUnit
@@ -89,33 +91,19 @@ class ConfigurationLoaderImpl
if (shouldCheckForUpdates(context)) {
try {
loadCentralConfigurationCore(context, proxySetting, manualProxy)
+ } catch (e: ConfigurationSignatureValidationException) {
+ errorLog(logTag, "Central configuration signature validation failed", e)
+ restoreLocalConfiguration(context)
+ throw e
+ } catch (ce: CancellationException) {
+ throw ce
} catch (e: Exception) {
errorLog(logTag, "Unable to check Central configuration. Using current configuration", e)
+ restoreLocalConfiguration(context)
}
}
}
- // Load default configuration if cached configuration does not succeed
- private suspend fun loadLocalConfiguration(context: Context) {
- try {
- loadCachedConfiguration(context, false)
- } catch (e: Exception) {
- errorLog(logTag, "Unable to load cached configuration. Using default configuration", e)
- loadDefaultConfiguration(context)
- }
- }
-
- private fun getConfigCacheDir(context: Context): File = File(context.cacheDir, CACHE_CONFIG_FOLDER)
-
- private fun decodeSignature(signatureBytes: ByteArray): ByteArray {
- val signatureText = String(signatureBytes, Charsets.UTF_8)
- return if (ConfigurationUtil.isBase64(signatureText)) {
- Base64.getDecoder().decode(signatureText)
- } else {
- signatureBytes
- }
- }
-
override fun getConfigurationFlow(): StateFlow = configurationFlow
override suspend fun loadConfigurationProperty(context: Context): ConfigurationProperty {
@@ -133,22 +121,21 @@ class ConfigurationLoaderImpl
) {
val cacheDir = getConfigCacheDir(context)
val confFile = File(cacheDir, CACHED_CONFIG_JSON)
- val publicKeyFile = File(cacheDir, CACHED_CONFIG_PUB)
- val signatureFile = File(cacheDir, CACHED_CONFIG_RSA)
+ val signatureFile = File(cacheDir, CACHED_CONFIG_ECC)
- val isCacheComplete = confFile.exists() && publicKeyFile.exists() && signatureFile.exists()
+ val isCacheComplete = confFile.exists() && signatureFile.exists()
if (!isCacheComplete) {
loadDefaultConfiguration(context)
return
}
val configText = confFile.readText()
- val publicKey = publicKeyFile.readText()
+ val publicKey = bundledPublicKey(context)
val signature = decodeSignature(signatureFile.readBytes())
configurationSignatureVerifier.verifyConfigurationSignature(configText, publicKey, signature)
val configurationProvider = gson.fromJson(configText, ConfigurationProvider::class.java)
- ConfigurationCache.cacheConfigurationFiles(context, configText, publicKey, signature)
+ ConfigurationCache.cacheConfigurationFiles(context, configText, signature)
if (!afterCentralCheck) {
configurationProperties.updateProperties(
@@ -172,25 +159,35 @@ class ConfigurationLoaderImpl
}
}
+ // Load default configuration if cached configuration does not succeed
+ override suspend fun loadLocalConfiguration(context: Context) {
+ try {
+ loadCachedConfiguration(context, false)
+ } catch (e: Exception) {
+ errorLog(logTag, "Unable to load cached configuration. Using default configuration", e)
+ loadDefaultConfiguration(context)
+ }
+ }
+
override suspend fun loadDefaultConfiguration(context: Context) {
val assets = context.assets
val confData = assets.open("config/${DEFAULT_CONFIG_JSON}").bufferedReader().use { it.readText() }
- val publicKey = assets.open("config/${DEFAULT_CONFIG_PUB}").bufferedReader().use { it.readText() }
- val signature = decodeSignature(assets.open("config/${DEFAULT_CONFIG_RSA}").readBytes())
+ val publicKey = bundledPublicKey(context)
+ val signature =
+ decodeSignature(assets.open("config/${DEFAULT_CONFIG_ECC}").use { it.readBytes() })
configurationSignatureVerifier.verifyConfigurationSignature(confData, publicKey, signature)
ConfigurationCache.cacheConfigurationFiles(
context,
confData,
- publicKey,
signature,
)
val configurationProvider = gson.fromJson(confData, ConfigurationProvider::class.java)
configurationProperties.updateProperties(
context,
- DateUtil.getConfigurationDate(configurationProvider.metaInf.date),
+ null,
DateUtil.getConfigurationDate(configurationProvider.metaInf.date),
configurationProvider.metaInf.serial,
)
@@ -201,25 +198,6 @@ class ConfigurationLoaderImpl
configurationFlow.value = configurationProvider
}
- @Throws(Exception::class)
- override suspend fun loadCentralConfigurationData(
- configurationServiceUrl: String,
- userAgent: String,
- ): ConfigurationData {
- val centralSignature =
- Base64.getDecoder().decode(centralConfigurationRepository.fetchSignature().trim())
- val centralConfig = centralConfigurationRepository.fetchConfiguration()
- val centralPublicKey = centralConfigurationRepository.fetchPublicKey()
-
- configurationSignatureVerifier.verifyConfigurationSignature(
- centralConfig,
- centralPublicKey,
- centralSignature,
- )
-
- return ConfigurationData(centralConfig, centralPublicKey, centralSignature)
- }
-
@Throws(Exception::class)
override suspend fun loadCentralConfiguration(
context: Context,
@@ -229,6 +207,64 @@ class ConfigurationLoaderImpl
loadCentralConfigurationCore(context, proxySetting, proxy)
}
+ override suspend fun shouldCheckForUpdates(context: Context): Boolean {
+ val lastExecutionDate =
+ configurationProperties
+ .getConfigurationLastCheckDate(context)
+ ?.toInstant()
+ ?.atZone(ZoneId.systemDefault())
+ ?.toLocalDateTime()
+
+ if (lastExecutionDate == null) {
+ return true
+ }
+
+ val currentDate = LocalDateTime.now()
+
+ val daysSinceLastUpdateCheck = ChronoUnit.DAYS.between(lastExecutionDate, currentDate)
+
+ return daysSinceLastUpdateCheck >= 4
+ }
+
+ private suspend fun restoreLocalConfiguration(context: Context) {
+ try {
+ loadLocalConfiguration(context)
+ } catch (recoveryFailure: Exception) {
+ errorLog(logTag, "Unable to restore local configuration", recoveryFailure)
+ }
+ }
+
+ private fun getConfigCacheDir(context: Context): File = File(context.cacheDir, CACHE_CONFIG_FOLDER)
+
+ private fun bundledPublicKey(context: Context): String {
+ val publicKey =
+ try {
+ context.assets
+ .open("config/${DEFAULT_CONFIG_ECPUB}")
+ .bufferedReader()
+ .use { it.readText() }
+ } catch (e: IOException) {
+ throw PublicKeyNotFoundException("Bundled ${DEFAULT_CONFIG_ECPUB} is missing", e)
+ }
+
+ return publicKey.ifBlank {
+ throw PublicKeyNotFoundException("Bundled ${DEFAULT_CONFIG_ECPUB} is empty")
+ }
+ }
+
+ private fun decodeSignature(signatureBytes: ByteArray): ByteArray {
+ val signatureText = String(signatureBytes, Charsets.UTF_8).removeWhitespaces().trim()
+ if (signatureText.isEmpty()) {
+ return signatureBytes
+ }
+
+ return if (ConfigurationUtil.isBase64(signatureText)) {
+ Base64.getDecoder().decode(signatureText)
+ } else {
+ signatureBytes
+ }
+ }
+
@Throws(Exception::class)
private suspend fun loadCentralConfigurationCore(
context: Context,
@@ -236,7 +272,7 @@ class ConfigurationLoaderImpl
proxy: ManualProxy,
) {
val cachedSignature =
- ConfigurationCache.getCachedFile(context, CACHED_CONFIG_RSA)
+ ConfigurationCache.getCachedFile(context, CACHED_CONFIG_ECC)
val currentSignature = cachedSignature.readBytes()
@@ -245,16 +281,17 @@ class ConfigurationLoaderImpl
centralConfigurationRepository.setupProxy(proxySetting, proxy)
val centralSignature =
- Base64.getDecoder().decode(
- centralConfigurationRepository.fetchSignature().removeWhitespaces().trim(),
- )
+ try {
+ Base64.getDecoder().decode(
+ centralConfigurationRepository.fetchSignature().removeWhitespaces().trim(),
+ )
+ } catch (e: IllegalArgumentException) {
+ throw ConfigurationSignatureValidationException(e)
+ }
if (!currentSignature.contentEquals(centralSignature)) {
val centralConfig = centralConfigurationRepository.fetchConfiguration()
- val centralPublicKey = centralConfigurationRepository.fetchPublicKey()
-
- val centralConfigurationProvider =
- gson.fromJson(centralConfig, ConfigurationProvider::class.java)
+ val centralPublicKey = bundledPublicKey(context)
configurationSignatureVerifier.verifyConfigurationSignature(
centralConfig,
@@ -262,6 +299,9 @@ class ConfigurationLoaderImpl
centralSignature,
)
+ val centralConfigurationProvider =
+ gson.fromJson(centralConfig, ConfigurationProvider::class.java)
+
if (ConfigurationUtil.isSerialNewerThanCached(
configurationFlow.value?.metaInf?.serial ?: 0,
centralConfigurationProvider.metaInf.serial,
@@ -270,7 +310,6 @@ class ConfigurationLoaderImpl
ConfigurationCache.cacheConfigurationFiles(
context,
centralConfig,
- centralPublicKey,
centralSignature,
)
configurationProperties.updateProperties(
@@ -299,23 +338,4 @@ class ConfigurationLoaderImpl
loadCachedConfiguration(context, true)
}
}
-
- override suspend fun shouldCheckForUpdates(context: Context): Boolean {
- val lastExecutionDate =
- configurationProperties
- .getConfigurationLastCheckDate(context)
- ?.toInstant()
- ?.atZone(ZoneId.systemDefault())
- ?.toLocalDateTime()
-
- if (lastExecutionDate == null) {
- return true
- }
-
- val currentDate = LocalDateTime.now()
-
- val daysSinceLastUpdateCheck = ChronoUnit.DAYS.between(lastExecutionDate, currentDate)
-
- return daysSinceLastUpdateCheck >= 4
- }
}
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepository.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepository.kt
index ad86acd03..65de00cf0 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepository.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepository.kt
@@ -31,11 +31,7 @@ interface CentralConfigurationRepository {
suspend fun fetchConfiguration(): String
@Throws(Exception::class)
- @GET("config.pub")
- suspend fun fetchPublicKey(): String
-
- @Throws(Exception::class)
- @GET("config.rsa")
+ @GET("config.ecc")
suspend fun fetchSignature(): String
suspend fun setupProxy(
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepositoryImpl.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepositoryImpl.kt
index cda0497d3..4132a222c 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepositoryImpl.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/CentralConfigurationRepositoryImpl.kt
@@ -35,8 +35,6 @@ class CentralConfigurationRepositoryImpl
) : CentralConfigurationRepository {
override suspend fun fetchConfiguration(): String = configurationService.fetchConfiguration()
- override suspend fun fetchPublicKey(): String = configurationService.fetchPublicKey()
-
@Throws(Exception::class)
override suspend fun fetchSignature(): String = configurationService.fetchSignature()
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepository.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepository.kt
index 10ba075f3..95adfbcb1 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepository.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepository.kt
@@ -22,17 +22,9 @@
package ee.ria.DigiDoc.configuration.repository
import ee.ria.DigiDoc.configuration.provider.ConfigurationProvider
-import ee.ria.DigiDoc.network.proxy.ManualProxy
-import ee.ria.DigiDoc.network.proxy.ProxySetting
interface ConfigurationRepository {
fun getConfiguration(): ConfigurationProvider?
- @Throws(Exception::class)
- suspend fun getCentralConfiguration(
- proxySetting: ProxySetting?,
- manualProxy: ManualProxy,
- ): ConfigurationProvider?
-
suspend fun observeConfigurationUpdates(onUpdate: suspend (ConfigurationProvider) -> Unit)
}
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepositoryImpl.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepositoryImpl.kt
index 0efcf12e9..a5121e186 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepositoryImpl.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/repository/ConfigurationRepositoryImpl.kt
@@ -21,11 +21,8 @@
package ee.ria.DigiDoc.configuration.repository
-import android.content.Context
import ee.ria.DigiDoc.configuration.loader.ConfigurationLoader
import ee.ria.DigiDoc.configuration.provider.ConfigurationProvider
-import ee.ria.DigiDoc.network.proxy.ManualProxy
-import ee.ria.DigiDoc.network.proxy.ProxySetting
import kotlinx.coroutines.flow.filterNotNull
import javax.inject.Inject
import javax.inject.Singleton
@@ -34,20 +31,10 @@ import javax.inject.Singleton
class ConfigurationRepositoryImpl
@Inject
constructor(
- private val context: Context,
private val configurationLoader: ConfigurationLoader,
) : ConfigurationRepository {
override fun getConfiguration(): ConfigurationProvider? = configurationLoader.getConfigurationFlow().value
- @Throws(Exception::class)
- override suspend fun getCentralConfiguration(
- proxySetting: ProxySetting?,
- manualProxy: ManualProxy,
- ): ConfigurationProvider? {
- configurationLoader.loadCentralConfiguration(context, proxySetting, manualProxy)
- return getConfiguration()
- }
-
override suspend fun observeConfigurationUpdates(onUpdate: suspend (ConfigurationProvider) -> Unit) {
configurationLoader
.getConfigurationFlow()
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/service/CentralConfigurationService.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/service/CentralConfigurationService.kt
index 2f965cb19..8e5958747 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/service/CentralConfigurationService.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/service/CentralConfigurationService.kt
@@ -48,8 +48,6 @@ import javax.inject.Singleton
interface CentralConfigurationService {
suspend fun fetchConfiguration(): String
- suspend fun fetchPublicKey(): String
-
suspend fun fetchSignature(): String
suspend fun setupProxy(
@@ -90,16 +88,6 @@ open class CentralConfigurationServiceImpl
return retrofit.fetchConfiguration()
}
- override suspend fun fetchPublicKey(): String {
- val retrofit =
- constructRetrofit(
- configurationProperty.centralConfigurationServiceUrl,
- constructHttpClient(defaultTimeout, proxySetting, manualProxy),
- ).create(CentralConfigurationRepository::class.java)
-
- return retrofit.fetchPublicKey()
- }
-
@Throws(Exception::class)
override suspend fun fetchSignature(): String {
val retrofit =
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/task/FetchAndPackageDefaultConfigurationTask.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/task/FetchAndPackageDefaultConfigurationTask.kt
index 2a0e66223..f013fa33f 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/task/FetchAndPackageDefaultConfigurationTask.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/task/FetchAndPackageDefaultConfigurationTask.kt
@@ -30,9 +30,9 @@ import ee.ria.DigiDoc.configuration.utils.Constant.CONFIGURATION_DOWNLOAD_DATE_P
import ee.ria.DigiDoc.configuration.utils.Constant.CONFIGURATION_UPDATE_INTERVAL_PROPERTY
import ee.ria.DigiDoc.configuration.utils.Constant.CONFIGURATION_VERSION_SERIAL_PROPERTY
import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIGURATION_PROPERTIES_FILE_NAME
+import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIG_ECC
+import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIG_ECPUB
import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIG_JSON
-import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIG_PUB
-import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_CONFIG_RSA
import ee.ria.DigiDoc.configuration.utils.Constant.DEFAULT_UPDATE_INTERVAL
import ee.ria.DigiDoc.configuration.utils.Constant.PROPERTIES_FILE_NAME
import ee.ria.DigiDoc.configuration.utils.Parser
@@ -44,6 +44,7 @@ import ee.ria.DigiDoc.utilsLib.file.FileUtil
import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.errorLog
import kotlinx.coroutines.runBlocking
import okhttp3.OkHttpClient
+import okhttp3.Request
import okhttp3.internal.tls.OkHostnameVerifier
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
@@ -80,7 +81,7 @@ object FetchAndPackageDefaultConfigurationTask {
OkHttpClient
.Builder()
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
- .addInterceptor(UserAgentInterceptor("Jenkins"))
+ .addInterceptor(UserAgentInterceptor("Codemagic"))
.addInterceptor(NetworkInterceptor())
.hostnameVerifier(OkHostnameVerifier)
.connectTimeout(defaultTimeout, TimeUnit.SECONDS)
@@ -100,10 +101,17 @@ object FetchAndPackageDefaultConfigurationTask {
val centralConfigurationRepository = retrofit.create(CentralConfigurationRepository::class.java)
+ val publicKeyRequest = Request.Builder().url("$configurationServiceUrl/config.ecpub").build()
+ val publicKey =
+ okHttpClient.newCall(publicKeyRequest).execute().use { response ->
+ check(response.isSuccessful) { "Unable to fetch config.ecpub: ${response.code}" }
+ response.body.string()
+ }
+
val configurationData =
ConfigurationData(
centralConfigurationRepository.fetchConfiguration(),
- centralConfigurationRepository.fetchPublicKey(),
+ publicKey,
Base64.getDecoder().decode(centralConfigurationRepository.fetchSignature().trim().removeWhitespaces()),
)
@@ -115,8 +123,8 @@ object FetchAndPackageDefaultConfigurationTask {
confServiceUrl: String,
args: Array,
) {
- verifyConfigurationSignature(confData)
assertConfigurationLoaded(confData)
+ verifyConfigurationSignature(confData)
storeAsDefaultConfiguration(confData)
val configurationParser = Parser(confData.configurationJson)
val confVersionSerial: Int = configurationParser.parseIntValue("META-INF", "SERIAL")
@@ -168,9 +176,10 @@ object FetchAndPackageDefaultConfigurationTask {
private fun assertConfigurationLoaded(confData: ConfigurationData) {
check(
!(
- confData.configurationJson == null ||
+ confData.configurationJson.isNullOrBlank() ||
confData.configurationSignature == null ||
- confData.configurationSignaturePublicKey == null
+ confData.configurationSignature.isEmpty() ||
+ confData.configurationSignaturePublicKey.isNullOrBlank()
),
) {
"Configuration loading has failed"
@@ -179,8 +188,8 @@ object FetchAndPackageDefaultConfigurationTask {
private fun storeAsDefaultConfiguration(confData: ConfigurationData) {
confData.configurationJson?.let { storeFile(DEFAULT_CONFIG_JSON, it) }
- confData.configurationSignature?.let { storeFile(DEFAULT_CONFIG_RSA, it) }
- confData.configurationSignaturePublicKey?.let { storeFile(DEFAULT_CONFIG_PUB, it) }
+ confData.configurationSignature?.let { storeFile(DEFAULT_CONFIG_ECC, it) }
+ confData.configurationSignaturePublicKey?.let { storeFile(DEFAULT_CONFIG_ECPUB, it) }
}
private fun storeApplicationProperties(
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/utils/Constant.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/utils/Constant.kt
index 4c31b6b2f..1526e8fcb 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/utils/Constant.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/utils/Constant.kt
@@ -22,10 +22,6 @@
package ee.ria.DigiDoc.configuration.utils
object Constant {
- const val FORCE_LOAD_CENTRAL_CONFIGURATION =
- "ee.ria.digidoc.configuration.FORCE_LOAD_CENTRAL_CONFIGURATION"
- const val LAST_CONFIGURATION_UPDATE = "ee.ria.digidoc.configuration.LAST_CONFIGURATION_UPDATE"
-
const val CENTRAL_CONFIGURATION_SERVICE_URL_PROPERTY = "central-configuration-service.url"
const val CONFIGURATION_UPDATE_INTERVAL_PROPERTY = "configuration.update-interval"
const val CONFIGURATION_VERSION_SERIAL_PROPERTY = "configuration.version-serial"
@@ -38,16 +34,14 @@ object Constant {
"default-configuration.properties"
const val DEFAULT_CONFIG_JSON = "default-config.json"
- const val DEFAULT_CONFIG_RSA = "default-config.rsa"
- const val DEFAULT_CONFIG_PUB = "default-config.pub"
+ const val DEFAULT_CONFIG_ECC = "default-config.ecc"
+ const val DEFAULT_CONFIG_ECPUB = "default-config.ecpub"
const val CACHED_CONFIG_JSON = "active-config.json"
- const val CACHED_CONFIG_RSA = "active-config.rsa"
- const val CACHED_CONFIG_PUB = "active-config.pub"
+ const val CACHED_CONFIG_ECC = "active-config.ecc"
const val CONFIGURATION_PREFERENCES = "ConfigurationPreferences"
const val CACHE_CONFIG_FOLDER = "/config/"
- const val CONFIGURATION_INFO_FILE_NAME = "configuration-info.properties"
const val CONFIGURATION_LAST_UPDATE_CHECK_DATE_PROPERTY_NAME =
"configuration.last-update-check-date"
const val CONFIGURATION_UPDATE_DATE_PROPERTY_NAME = "configuration.update-date"
diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/utils/SignatureVerifier.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/utils/SignatureVerifier.kt
index 663a0a537..5129865b7 100644
--- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/utils/SignatureVerifier.kt
+++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/utils/SignatureVerifier.kt
@@ -23,69 +23,59 @@ package ee.ria.DigiDoc.configuration.utils
import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.errorLog
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
-import org.bouncycastle.crypto.params.RSAKeyParameters
-import org.bouncycastle.crypto.util.PublicKeyFactory
import org.bouncycastle.openssl.PEMParser
import java.io.IOException
import java.io.StringReader
import java.nio.charset.StandardCharsets
-import java.security.InvalidKeyException
+import java.security.GeneralSecurityException
import java.security.KeyFactory
-import java.security.NoSuchAlgorithmException
import java.security.PublicKey
import java.security.Signature
-import java.security.SignatureException
-import java.security.spec.InvalidKeySpecException
-import java.security.spec.RSAPublicKeySpec
+import java.security.interfaces.ECPublicKey
+import java.security.spec.X509EncodedKeySpec
object SignatureVerifier {
private val LOG_TAG = javaClass.simpleName
+ private const val CONVERSION_ERROR = "Failed to convert SubjectPublicKeyInfo to EC java.security.PublicKey"
+ private const val PARSE_ERROR = "Failed to parse PEM encoded public key"
+ private const val NOT_SPKI_ERROR =
+ "PEM did not contain SubjectPublicKeyInfo. Make sure it's 'BEGIN PUBLIC KEY' (SPKI)."
+ private const val VERIFY_ERROR = "Failed to verify signature"
+
fun verify(
signature: ByteArray,
publicKeyPEM: String,
signedContent: String,
): Boolean {
- val publicKeyInfo: SubjectPublicKeyInfo =
- parsePublicKeyInfo(publicKeyPEM)
+ val publicKeyInfo = parsePublicKeyInfo(publicKeyPEM)
val publicKey = convertPublicKeyInfoToPublicKey(publicKeyInfo)
return verifySignature(signature, publicKey, signedContent)
}
private fun convertPublicKeyInfoToPublicKey(publicKeyInfo: SubjectPublicKeyInfo): PublicKey =
try {
- val keyParams: RSAKeyParameters =
- PublicKeyFactory.createKey(publicKeyInfo) as RSAKeyParameters
- val publicKeySpec = RSAPublicKeySpec(keyParams.modulus, keyParams.exponent)
- val keyFactory = KeyFactory.getInstance("RSA")
- keyFactory.generatePublic(publicKeySpec)
- } catch (e: InvalidKeySpecException) {
- errorLog(LOG_TAG, "PublicKey conversion failed", e)
- throw IllegalStateException(
- "Failed to convert org.bouncycastle.asn1.x509.SubjectPublicKeyInfo to kotlin.security.PublicKey",
- e,
- )
- } catch (e: NoSuchAlgorithmException) {
- errorLog(LOG_TAG, "PublicKey conversion failed", e)
- throw IllegalStateException(
- "Failed to convert org.bouncycastle.asn1.x509.SubjectPublicKeyInfo to kotlin.security.PublicKey",
- e,
- )
+ val keySpec = X509EncodedKeySpec(publicKeyInfo.encoded)
+ KeyFactory.getInstance("EC").generatePublic(keySpec)
+ } catch (e: GeneralSecurityException) {
+ fail(CONVERSION_ERROR, e)
} catch (e: IOException) {
- errorLog(LOG_TAG, "PublicKey conversion failed", e)
- throw IllegalStateException(
- "Failed to convert org.bouncycastle.asn1.x509.SubjectPublicKeyInfo to kotlin.security.PublicKey",
- e,
- )
+ fail(CONVERSION_ERROR, e)
+ } catch (e: RuntimeException) {
+ fail(CONVERSION_ERROR, e)
}
- private fun parsePublicKeyInfo(PKCS1PublicKeyPEM: String): SubjectPublicKeyInfo {
- try {
- PEMParser(StringReader(PKCS1PublicKeyPEM))
- .use { pemParser -> return pemParser.readObject() as SubjectPublicKeyInfo }
- } catch (e: IOException) {
- throw IllegalStateException("Failed to parse PEM encoded PKCS#1 public key", e)
- }
+ private fun parsePublicKeyInfo(publicKeyPem: String): SubjectPublicKeyInfo {
+ val pemObject =
+ try {
+ PEMParser(StringReader(publicKeyPem)).use { it.readObject() }
+ } catch (e: IOException) {
+ fail(PARSE_ERROR, e)
+ } catch (e: RuntimeException) {
+ fail(PARSE_ERROR, e)
+ }
+
+ return pemObject as? SubjectPublicKeyInfo ?: fail(NOT_SPKI_ERROR)
}
private fun verifySignature(
@@ -94,18 +84,35 @@ object SignatureVerifier {
signedContent: String,
): Boolean =
try {
- val signature = Signature.getInstance("SHA512withRSA")
+ val signature = Signature.getInstance(pickEcdsaAlgorithm(publicKey))
signature.initVerify(publicKey)
signature.update(signedContent.toByteArray(StandardCharsets.UTF_8))
signature.verify(signatureBytes)
- } catch (e: NoSuchAlgorithmException) {
- errorLog(LOG_TAG, "Signature verification failed", e)
- throw IllegalStateException("Failed to verify signature", e)
- } catch (e: SignatureException) {
- errorLog(LOG_TAG, "Signature verification failed", e)
- throw IllegalStateException("Failed to verify signature", e)
- } catch (e: InvalidKeyException) {
- errorLog(LOG_TAG, "Signature verification failed", e)
- throw IllegalStateException("Failed to verify signature", e)
+ } catch (e: GeneralSecurityException) {
+ fail(VERIFY_ERROR, e)
+ } catch (e: IllegalArgumentException) {
+ fail(VERIFY_ERROR, e)
+ }
+
+ private fun fail(
+ message: String,
+ cause: Throwable? = null,
+ ): Nothing {
+ errorLog(LOG_TAG, message, cause)
+ throw IllegalStateException(message, cause)
+ }
+
+ private fun pickEcdsaAlgorithm(publicKey: PublicKey): String {
+ val ecKey =
+ publicKey as? ECPublicKey
+ ?: fail("Public key is not EC (ECDSA). Got: ${publicKey.algorithm}")
+
+ val fieldSizeBits = ecKey.params.curve.field.fieldSize
+
+ return when {
+ fieldSizeBits <= 256 -> "SHA256withECDSA"
+ fieldSizeBits <= 384 -> "SHA384withECDSA"
+ else -> "SHA512withECDSA"
}
+ }
}
diff --git a/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/ConfigurationSignatureVerifierImplTest.kt b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/ConfigurationSignatureVerifierImplTest.kt
new file mode 100644
index 000000000..7394d763b
--- /dev/null
+++ b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/ConfigurationSignatureVerifierImplTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2017 - 2026 Riigi Infosüsteemi Amet
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+@file:Suppress("PackageName")
+
+package ee.ria.DigiDoc.configuration
+
+import ee.ria.DigiDoc.configuration.exception.ConfigurationSignatureValidationException
+import ee.ria.DigiDoc.configuration.shared.TestConfigurationFiles
+import org.junit.Assert.assertThrows
+import org.junit.Test
+
+class ConfigurationSignatureVerifierImplTest {
+ private val verifier = ConfigurationSignatureVerifierImpl()
+
+ @Test
+ fun verifyConfigurationSignatureSucceedsForMatchingSignature() {
+ verifier.verifyConfigurationSignature(config(), publicKey(), signature())
+ }
+
+ @Test
+ fun verifyConfigurationSignatureThrowsValidationExceptionWhenConfigTampered() {
+ assertThrows(ConfigurationSignatureValidationException::class.java) {
+ verifier.verifyConfigurationSignature(config() + "a", publicKey(), signature())
+ }
+ }
+
+ @Test
+ fun verifyConfigurationSignatureThrowsValidationExceptionWhenSignatureCorrupted() {
+ val corrupted = signature().copyOf()
+ corrupted[0] = (corrupted[0] + 1).toByte()
+
+ assertThrows(ConfigurationSignatureValidationException::class.java) {
+ verifier.verifyConfigurationSignature(config(), publicKey(), corrupted)
+ }
+ }
+
+ @Test
+ fun verifyConfigurationSignatureThrowsValidationExceptionWhenSignatureEmpty() {
+ assertThrows(ConfigurationSignatureValidationException::class.java) {
+ verifier.verifyConfigurationSignature(config(), publicKey(), ByteArray(0))
+ }
+ }
+
+ @Test
+ fun verifyConfigurationSignatureThrowsValidationExceptionWhenPublicKeyMalformed() {
+ assertThrows(ConfigurationSignatureValidationException::class.java) {
+ verifier.verifyConfigurationSignature(config(), "not a pem", signature())
+ }
+ }
+
+ private fun config(): String = TestConfigurationFiles.config()
+
+ private fun publicKey(): String = TestConfigurationFiles.publicKey()
+
+ private fun signature(): ByteArray = TestConfigurationFiles.signature()
+}
diff --git a/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderImplTest.kt b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderImplTest.kt
new file mode 100644
index 000000000..f5dbf0be4
--- /dev/null
+++ b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/loader/ConfigurationLoaderImplTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2017 - 2026 Riigi Infosüsteemi Amet
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+@file:Suppress("PackageName")
+
+package ee.ria.DigiDoc.configuration.loader
+
+import android.content.Context
+import android.content.res.AssetManager
+import com.google.gson.Gson
+import ee.ria.DigiDoc.configuration.ConfigurationProperty
+import ee.ria.DigiDoc.configuration.ConfigurationSignatureVerifier
+import ee.ria.DigiDoc.configuration.exception.PublicKeyNotFoundException
+import ee.ria.DigiDoc.configuration.properties.ConfigurationProperties
+import ee.ria.DigiDoc.configuration.repository.CentralConfigurationRepository
+import ee.ria.DigiDoc.network.proxy.ManualProxy
+import ee.ria.DigiDoc.network.proxy.ProxySetting
+import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertArrayEquals
+import org.junit.Assert.assertThrows
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when`
+import org.mockito.kotlin.any
+import org.mockito.kotlin.check
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.verify
+import java.io.ByteArrayInputStream
+import java.io.File
+import java.io.FileNotFoundException
+import java.nio.file.Files
+import java.time.LocalDateTime
+
+class ConfigurationLoaderImplTest {
+ private lateinit var context: Context
+ private lateinit var assets: AssetManager
+ private lateinit var centralConfigurationRepository: CentralConfigurationRepository
+ private lateinit var configurationSignatureVerifier: ConfigurationSignatureVerifier
+ private lateinit var configurationProperties: ConfigurationProperties
+ private lateinit var configurationLoader: ConfigurationLoader
+
+ @Before
+ fun setUp() {
+ assets = mock(AssetManager::class.java)
+ context = mock(Context::class.java)
+ `when`(context.assets).thenReturn(assets)
+ `when`(assets.open("config/default-config.json"))
+ .thenReturn(ByteArrayInputStream("{}".toByteArray()))
+
+ centralConfigurationRepository = mock(CentralConfigurationRepository::class.java)
+ configurationSignatureVerifier = mock(ConfigurationSignatureVerifier::class.java)
+ configurationProperties = mock(ConfigurationProperties::class.java)
+
+ configurationLoader =
+ ConfigurationLoaderImpl(
+ Gson(),
+ centralConfigurationRepository,
+ ConfigurationProperty(),
+ configurationProperties,
+ configurationSignatureVerifier,
+ )
+ }
+
+ @Test
+ fun configurationLoader_loadDefaultConfiguration_decodesBase64SignatureCarryingTrailingNewline() {
+ val bundledKey = "-----BEGIN PUBLIC KEY-----\nBUNDLED\n-----END PUBLIC KEY-----\n"
+ `when`(assets.open("config/default-config.ecpub"))
+ .thenReturn(ByteArrayInputStream(bundledKey.toByteArray()))
+ `when`(assets.open("config/default-config.ecc"))
+ .thenReturn(ByteArrayInputStream("dGVzdA==\n".toByteArray()))
+
+ try {
+ runBlocking { configurationLoader.loadDefaultConfiguration(context) }
+ } catch (_: Exception) {
+ }
+
+ verify(configurationSignatureVerifier).verifyConfigurationSignature(
+ any(),
+ any(),
+ check { assertArrayEquals("test".toByteArray(), it) },
+ )
+ }
+
+ @Test
+ fun configurationLoader_loadCentralConfiguration_verifiesWithBundledKeyNotAServerSuppliedOne() {
+ val bundledKey = "-----BEGIN PUBLIC KEY-----\nBUNDLED\n-----END PUBLIC KEY-----\n"
+ val cacheDir = Files.createTempDirectory("loaderCentralTest").toFile()
+ File(cacheDir, "config").mkdirs()
+ File(cacheDir, "config/active-config.ecc").writeBytes("stale".toByteArray())
+
+ `when`(context.cacheDir).thenReturn(cacheDir)
+ `when`(assets.open("config/default-config.ecpub"))
+ .thenReturn(ByteArrayInputStream(bundledKey.toByteArray()))
+ `when`(configurationProperties.getConfigurationProperties(context))
+ .thenReturn(ConfigurationProperty("https://example.org", 4, 1, LocalDateTime.now()))
+
+ try {
+ runBlocking {
+ `when`(centralConfigurationRepository.fetchSignature()).thenReturn("dGVzdA==")
+ `when`(centralConfigurationRepository.fetchConfiguration()).thenReturn("{}")
+
+ configurationLoader.loadCentralConfiguration(
+ context,
+ ProxySetting.NO_PROXY,
+ ManualProxy("", 80, "", ""),
+ )
+ }
+ } catch (_: Exception) {
+ }
+
+ verify(configurationSignatureVerifier).verifyConfigurationSignature(any(), eq(bundledKey), any())
+ }
+
+ @Test
+ fun configurationLoader_loadDefaultConfiguration_throwsWhenBundledPublicKeyIsEmpty() {
+ `when`(assets.open("config/default-config.ecpub"))
+ .thenReturn(ByteArrayInputStream(ByteArray(0)))
+
+ assertThrows(PublicKeyNotFoundException::class.java) {
+ runBlocking { configurationLoader.loadDefaultConfiguration(context) }
+ }
+ }
+
+ @Test
+ fun configurationLoader_loadDefaultConfiguration_throwsWhenBundledPublicKeyIsBlank() {
+ `when`(assets.open("config/default-config.ecpub"))
+ .thenReturn(ByteArrayInputStream(" \n".toByteArray()))
+
+ assertThrows(PublicKeyNotFoundException::class.java) {
+ runBlocking { configurationLoader.loadDefaultConfiguration(context) }
+ }
+ }
+
+ @Test
+ fun configurationLoader_loadDefaultConfiguration_throwsWhenBundledPublicKeyIsMissing() {
+ `when`(assets.open("config/default-config.ecpub"))
+ .thenThrow(FileNotFoundException("config/default-config.ecpub"))
+
+ assertThrows(PublicKeyNotFoundException::class.java) {
+ runBlocking { configurationLoader.loadDefaultConfiguration(context) }
+ }
+ }
+
+ @Test
+ fun configurationLoader_loadDefaultConfiguration_verifiesWithBundledKeyAndNeverTheServerKey() {
+ val bundledKey = "-----BEGIN PUBLIC KEY-----\nBUNDLED\n-----END PUBLIC KEY-----\n"
+ `when`(assets.open("config/default-config.ecpub"))
+ .thenReturn(ByteArrayInputStream(bundledKey.toByteArray()))
+ `when`(assets.open("config/default-config.ecc"))
+ .thenReturn(ByteArrayInputStream(byteArrayOf(1, 2, 3)))
+
+ try {
+ runBlocking { configurationLoader.loadDefaultConfiguration(context) }
+ } catch (_: Exception) {
+ }
+
+ verify(configurationSignatureVerifier).verifyConfigurationSignature(any(), eq(bundledKey), any())
+ }
+}
diff --git a/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/service/CentralConfigurationServiceImplTest.kt b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/service/CentralConfigurationServiceImplTest.kt
index cf9a8b6d9..b10f1b0f9 100644
--- a/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/service/CentralConfigurationServiceImplTest.kt
+++ b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/service/CentralConfigurationServiceImplTest.kt
@@ -149,17 +149,6 @@ class CentralConfigurationServiceImplTest {
assertEquals(expected, result)
}
- @Test
- fun centralConfigurationServiceImpl_fetchPublicKey_returnsResponse() =
- runTest {
- val expected = "public-key-value"
- mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(expected))
-
- val result = service.fetchPublicKey()
-
- assertEquals(expected, result)
- }
-
@Test
fun centralConfigurationServiceImpl_fetchSignature_returnsResponse() =
runTest {
diff --git a/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/shared/TestConfigurationFiles.kt b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/shared/TestConfigurationFiles.kt
new file mode 100644
index 000000000..909985b45
--- /dev/null
+++ b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/shared/TestConfigurationFiles.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 - 2026 Riigi Infosüsteemi Amet
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+@file:Suppress("PackageName")
+
+package ee.ria.DigiDoc.configuration.shared
+
+import ee.ria.DigiDoc.utilsLib.file.FileUtil
+
+internal object TestConfigurationFiles {
+ fun config(): String = bytes("config.json").toString(Charsets.UTF_8)
+
+ fun publicKey(): String = text("config.ecpub")
+
+ fun signature(): ByteArray = bytes("config.ecc")
+
+ private fun bytes(name: String): ByteArray =
+ classLoader().getResourceAsStream(name).use { FileUtil.readFileContentBytes(it) }
+
+ private fun text(name: String): String =
+ classLoader().getResourceAsStream(name).use { FileUtil.readFileContent(it) }
+
+ private fun classLoader(): ClassLoader =
+ javaClass.classLoader ?: throw IllegalStateException("Unable to get ClassLoader")
+}
diff --git a/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/utils/SignatureVerifierTest.kt b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/utils/SignatureVerifierTest.kt
index 38ffa82bc..d8f0ccad2 100644
--- a/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/utils/SignatureVerifierTest.kt
+++ b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/utils/SignatureVerifierTest.kt
@@ -21,84 +21,60 @@
package ee.ria.DigiDoc.configuration.utils
-import ee.ria.DigiDoc.utilsLib.file.FileUtil
+import ee.ria.DigiDoc.configuration.shared.TestConfigurationFiles
import junit.framework.TestCase
+import org.junit.Assert.assertThrows
import org.junit.Test
-import java.io.IOException
-import java.util.Optional
class SignatureVerifierTest {
@Test
fun verifyValidSignature() {
- val classLoader =
- Optional
- .ofNullable(javaClass.getClassLoader())
- .orElseThrow {
- IllegalStateException(
- "Unable to get ClassLoader",
- )
- }
- try {
- classLoader.getResourceAsStream("config.json").use { configJsonStream ->
- classLoader.getResourceAsStream("config.rsa").use { configSignatureStream ->
- classLoader
- .getResourceAsStream("config.pub")
- .use { configSignaturePublicKeyStream ->
- val configJson: String =
- FileUtil.readFileContent(configJsonStream)
- val configSignature: ByteArray =
- FileUtil.readFileContentBytes(configSignatureStream)
- val configSignaturePublicKey: String =
- FileUtil.readFileContent(configSignaturePublicKeyStream)
- TestCase.assertTrue(
- SignatureVerifier.verify(
- configSignature,
- configSignaturePublicKey,
- configJson,
- ),
- )
- }
- }
- }
- } catch (_: IOException) {
- throw IllegalStateException("Unable to read resource")
- }
+ TestCase.assertTrue(SignatureVerifier.verify(signature(), publicKey(), config()))
}
@Test
fun verifyInvalidSignature() {
- val classLoader =
- Optional
- .ofNullable(javaClass.getClassLoader())
- .orElseThrow {
- IllegalStateException(
- "Unable to get ClassLoader",
- )
- }
- try {
- classLoader.getResourceAsStream("config.json").use { configJsonStream ->
- classLoader.getResourceAsStream("config.rsa").use { configSignatureStream ->
- classLoader
- .getResourceAsStream("config.pub")
- .use { configSignaturePublicKeyStream ->
- val configJson: String =
- FileUtil.readFileContent(configJsonStream)
- val configSignature: ByteArray =
- FileUtil.readFileContentBytes(configSignatureStream)
- val configSignaturePublicKey: String =
- FileUtil.readFileContent(configSignaturePublicKeyStream)
- TestCase.assertFalse(
- SignatureVerifier.verify(
- configSignature,
- configSignaturePublicKey,
- configJson + "a",
- ),
- )
- }
- }
+ TestCase.assertFalse(SignatureVerifier.verify(signature(), publicKey(), config() + "a"))
+ }
+
+ @Test
+ fun verifyDoesNotAcceptGarbageSignatureBytes() {
+ val accepted =
+ try {
+ SignatureVerifier.verify(byteArrayOf(1, 2, 3, 4), publicKey(), config())
+ } catch (_: IllegalStateException) {
+ false
}
- } catch (_: IOException) {
- throw IllegalStateException("Unable to read resource")
+
+ TestCase.assertFalse(accepted)
+ }
+
+ @Test
+ fun verifyThrowsIllegalStateWhenPublicKeyPemIsEmpty() {
+ assertThrows(IllegalStateException::class.java) {
+ SignatureVerifier.verify(ByteArray(0), "", "content")
+ }
+ }
+
+ @Test
+ fun verifyThrowsIllegalStateWhenPublicKeyPemIsNotPem() {
+ assertThrows(IllegalStateException::class.java) {
+ SignatureVerifier.verify(ByteArray(0), "not a pem at all", "content")
+ }
+ }
+
+ @Test
+ fun verifyThrowsIllegalStateWhenPublicKeyPemBodyIsGarbage() {
+ val garbagePem =
+ "-----BEGIN PUBLIC KEY-----\nbm90IGEgcHVibGljIGtleQ==\n-----END PUBLIC KEY-----\n"
+ assertThrows(IllegalStateException::class.java) {
+ SignatureVerifier.verify(ByteArray(0), garbagePem, "content")
}
}
+
+ private fun config(): String = TestConfigurationFiles.config()
+
+ private fun publicKey(): String = TestConfigurationFiles.publicKey()
+
+ private fun signature(): ByteArray = TestConfigurationFiles.signature()
}
diff --git a/config-lib/src/test/resources/config.ecc b/config-lib/src/test/resources/config.ecc
new file mode 100644
index 000000000..2155f2674
Binary files /dev/null and b/config-lib/src/test/resources/config.ecc differ
diff --git a/config-lib/src/test/resources/config.ecpub b/config-lib/src/test/resources/config.ecpub
new file mode 100644
index 000000000..37ab76a78
--- /dev/null
+++ b/config-lib/src/test/resources/config.ecpub
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBT8nzRGnA7I5s5c+wi/kz4a86j449
+mRfeDzQRoulSKQSEvryfdFRoze4p6XvY++FOVmuHglszbxcRv1oqT5aAEuYBxOS0
+Z85VukvGON3NxD2SBcifANr9f0LTBvu+p9+wOZm+nsK/9CMsCjEGrQ7KGjyQ7Vfk
+pJoriwpp3JnCvIuLSak=
+-----END PUBLIC KEY-----
diff --git a/config-lib/src/test/resources/config.json b/config-lib/src/test/resources/config.json
index f9a9928ab..cddc34484 100644
--- a/config-lib/src/test/resources/config.json
+++ b/config-lib/src/test/resources/config.json
@@ -1,79 +1,113 @@
{
- "TERA-SUPPORTED": "1.0.0.5",
- "TERA-URL": "https://puhver.ria.ee/tsa",
- "TERA-EXCL-DIRS-OSX": "/Users/$user/Library/Caches",
- "TERA-EXCL-DIRS-UBUNTU": "/var/tmp",
- "TERA-EXCL-DIRS-WIN": "C:/Users/$user/AppData/Local/Temp",
"META-INF": {
+ "VER": 1,
+ "SERIAL": 200,
"URL": "https://id.eesti.ee/config.json",
- "DATE": "20190816123015Z",
- "SERIAL": 94,
- "VER": 1
+ "DATE": "20251210103015Z"
},
- "PICTURE-URL": "https://sisene.www.eesti.ee/idportaal/portaal.idpilt",
- "QDIGIDOC4-SUPPORTED": "4.2.0.42",
- "QDIGIDOC4-LATEST": "4.2.2.0",
- "TERA-DEFAULT-OUT-EXTENSION": ".asics",
- "TSA-URL": "http://dd-at.ria.ee/tsa",
- "QESTEIDUTIL-LATEST": "3.12.10.1265",
- "MID-SIGN-URL": "https://digidocservice.sk.ee",
- "OSX-LATEST": "19.7.0.1834",
- "QESTEIDUTIL-SUPPORTED": "4.0.0.23",
- "EIDUPDATER-URL-TOECC": "https://installer.id.ee/media/teavitus/",
- "WIN-DOWNLOAD": "https://installer.id.ee/media/win/Open-EID-19.7.0.1837_x86.exe",
- "QDIGIDOC-SUPPORTED": "4.0.0.23",
+ "TSL-URL": "https://ec.europa.eu/tools/lotl/eu-lotl.xml",
"TSL-CERTS": [
- "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",
- "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"
+ "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"
],
- "WIN-LATEST": "19.7.0.1837",
- "OCSP-URL-ISSUER": {
- "KLASS3-SK 2010": "http://ocsp.sk.ee",
- "KLASS3-SK 2016": "http://ocsp.sk.ee",
- "TEST of KLASS3-SK 2010": "http://demo.sk.ee/ocsp",
- "VRK CA for Test Purposes - G2": "http://demo.sk.ee/ocsp",
- "VRK CA for Test Purposes - G3": "http://demo.sk.ee/ocsp",
- "TEST of ESTEID-SK 2011": "http://demo.sk.ee/ocsp",
- "TEST of ESTEID-SK 2015": "http://demo.sk.ee/ocsp",
- "ESTEID-SK 2011": "http://ocsp.sk.ee",
- "TEST of KLASS3-SK 2016": "http://demo.sk.ee/ocsp",
- "EID-SK 2016": "http://ocsp.sk.ee",
- "EID-SK 2011": "http://ocsp.sk.ee",
- "ESTEID-SK 2015": "http://ocsp.sk.ee",
- "Nacionalinis sertifikavimo centras (IssuingCA A)": "http://demo.sk.ee/ocsp"
- },
- "WIN-UPGRADECODE": "{f1c4d351-269d-4bee-8cdb-6ea70c968875}",
+ "TSA-URL": "https://eid-dd.ria.ee/ts",
+ "OCSP-URL-ISSUER": {},
"LDAP-PERSON-URL": "ldaps://esteid.ldap.sk.ee",
- "OSX-DOWNLOAD": "https://installer.id.ee/media/osx/Open-EID_19.7.0.1834.dmg",
"LDAP-CORP-URL": "ldaps://k3.ldap.sk.ee",
- "QDIGIDOC-LATEST": "3.13.6.1525",
+ "MID-PROXY-URL": "https://eid-dd.ria.ee/mid",
+ "MID-SK-URL": "https://mid.sk.ee/mid-api",
+ "SIDV2-PROXY-URL": "https://eid-dd.ria.ee/sid/v2",
+ "SIDV2-SK-URL": "https://rp-api.smart-id.com/v2",
+ "SIVA-URL": "https://siva.eesti.ee/V3/validate",
+ "SIVA-CERT": "",
+ "LDAP-PERSON-URLS": [
+ "ldaps://esteid.ldap.sk.ee",
+ "ldaps://ldap.eidpki.ee/dc=ldap,dc=eidpki,dc=ee"
+ ],
+ "CDOC2-CONF": {
+ "00000000-0000-0000-0000-000000000000": {
+ "NAME": "RIA",
+ "POST": "https://cdoc2.id.ee:8443",
+ "FETCH": "https://cdoc2.id.ee:8444"
+ }
+ },
+ "CDOC2-USE-KEYSERVER": false,
+ "CDOC2-DEFAULT-KEYSERVER": "00000000-0000-0000-0000-000000000000",
+ "QDIGIDOC4-SUPPORTED": "4.8.2.0",
+ "QDIGIDOC4-LATEST": "4.9.0.0",
+ "WIN-LATEST": "25.10.23.8403",
+ "WIN-DOWNLOAD": "https://installer.id.ee/media/win/Open-EID-25.10.23.8403.exe",
+ "WIN-UPGRADECODE": "{f1c4d351-269d-4bee-8cdb-6ea70c968875}",
+ "OSX-LATEST": "25.10.0.235",
+ "OSX-DOWNLOAD": "https://installer.id.ee/media/osx/Open-EID_25.10.0.235.dmg",
"CERT-BUNDLE": [
- "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",
- "MIIFBTCCA+2gAwIBAgIQKVKTqv2MxtRNgzCjwmRRDTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMB4XDTExMDMxODEwMTQ1OVoXDTI0MDMxODEwMTQ1OVowZDELMAkGA1UEBhMCRUUxIjAgBgNVBAoMGUFTIFNlcnRpZml0c2VlcmltaXNrZXNrdXMxFzAVBgNVBAMMDkVTVEVJRC1TSyAyMDExMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz6XxsZh6r/aXcNe3kSpNMOqmQoAXUpzzcr4ZSaGZh/7JHIiplvNi6tbW/lK7sAiRsb65KzMWROEauld66ggbDPga6kU97C+AXGu7+DROXstjUOv6VlrHZVAnLmIOkycpWaxjM+EfQPZuDxEbkw96B3/fG69Zbp3s9y6WEhwU5Y9IiQl8YTkGnNUxidQbON1BGQm+HVEsgTf22J6r6G3FsE07rnMNskNC3DjuLSCUKF4kH0rVGVK9BdiCdFaZjHEykjwjIGzqnyxyRKe4YbJ6B9ABm95eSFgMBHtZEYU+q0VUIQGhAGAurOTXjWi1TssA42mnLGQZEI5GXMXtabp51AgMBAAGjggGgMIIBnDASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjCB9gYDVR0gBIHuMIHrMIHoBgsrBgEEAc4fZAEBATCB2DCBsgYIKwYBBQUHAgIwgaUegaIASwBhAHMAdQB0AGEAdABhAGsAcwBlACAAaQBzAGkAawB1AHQAdAD1AGUAbgBkAGEAdgBhAGwAZQAgAGQAbwBrAHUAbQBlAG4AZABpAGwAZQAgAGsAYQBuAHQAYQB2AGEAdABlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0AGkAZABlACAAdgDkAGwAagBhAHMAdABhAG0AaQBzAGUAawBzAC4wIQYIKwYBBQUHAgEWFWh0dHBzOi8vd3d3LnNrLmVlL0NQUzAdBgNVHQ4EFgQUe2ryVVBcuNl6CIdBrvqiKz1bV3YwHwYDVR0jBBgwFoAUEvJaPupWHL/NBqzx8SXJqUvUFJkwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL3d3dy5zay5lZS9yZXBvc2l0b3J5L2NybHMvZWVjY3JjYS5jcmwwDQYJKoZIhvcNAQEFBQADggEBAKC4IN3FC2gVDIH05TNMgFrQOCGSnXhzoJclRLoQ81BCOXTZI4qn7N74FHEnrAy6uNG7SS5qANqSaPIL8dp63jg/L4qn4iWaB5q5GGJOV07SnTHS7gUrqChGClnUeHxiZbL13PkP37Lnc+TKl1SKfgtn5FbH5cqrhvbA/VF3Yzlimu+L7EVohW9HKxZ//z8kDn6ieiPFfZdTOov/0eXVLlxqklybUuS6LYRRDiqQupgBKQBTwNbC8x0UHX00HokW+dCVcQvsUbv4xLhRq/MvyTthE+RdbkrV0JuzbfZvADfj75nA3+ZAzFYS5ZpMOjZ9p4rQVKpzQTklrF0m6mkdcEo=",
- "MIIGcDCCBVigAwIBAgIQRUgJC4ec7yFWcqzT3mwbWzANBgkqhkiG9w0BAQwFADB1MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCAXDTE1MTIxNzEyMzg0M1oYDzIwMzAxMjE3MjM1OTU5WjBjMQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEXMBUGA1UEYQwOTlRSRUUtMTA3NDcwMTMxFzAVBgNVBAMMDkVTVEVJRC1TSyAyMDE1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0oH61NDxbdW9k8nLA1qGaL4B7vydod2Ewp/STBZB3wEtIJCLdkpEsS8pXfFiRqwDVsgGGbu+Q99trlb5LI7yi7rIkRov5NftBdSNPSU5rAhYPQhvZZQgOwRaHa5Ey+BaLJHmLqYQS9hQvQsCYyws+xVvNFUpK0pGD64iycqdMuBl/nWq3fLuZppwBh0VFltm4nhr/1S0R9TRJpqFUGbGr4OK/DwebQ5PjhdS40gCUNwmC7fPQ4vIH+x+TCk2aG+u3MoAz0IrpVWqiwzG/vxreuPPAkgXeFCeYf6fXLsGz4WivsZFbph2pMjELu6sltlBXfAG3fGv43t91VXicyzR/eT5dsB+zFsW1sHV+1ONPr+qzgDxCH2cmuqoZNfIIq+buob3eA8ee+XpJKJQr+1qGrmhggjvAhc7m6cU4x/QfxwRYhIVNhJf+sKVThkQhbJ9XxuKk3c18wymwL1mpDD0PIGJqlssMeiuJ4IzagFbgESGNDUd4icm0hQT8CmQeUm1GbWeBYseqPhMQX97QFBLXJLVy2SCyoAz7Bq1qA43++EcibN+yBc1nQs2Zoq8ck9MK0bCxDMeUkQUz6VeQGp69ImOQrsw46qTz0mtdQrMSbnkXCuLan5dPm284J9HmaqiYi6j6KLcZ2NkUnDQFesBVlMEm+fHa2iR6lnAFYZ06UECAwEAAaOCAgowggIGMB8GA1UdIwQYMBaAFBLyWj7qVhy/zQas8fElyalL1BSZMB0GA1UdDgQWBBSzq4i8mdVipIUqCM20HXI7g3JHUTAOBgNVHQ8BAf8EBAMCAQYwdwYDVR0gBHAwbjAIBgYEAI96AQIwCQYHBACL7EABAjAwBgkrBgEEAc4fAQEwIzAhBggrBgEFBQcCARYVaHR0cHM6Ly93d3cuc2suZWUvQ1BTMAsGCSsGAQQBzh8BAjALBgkrBgEEAc4fAQMwCwYJKwYBBAHOHwEEMBIGA1UdEwEB/wQIMAYBAf8CAQAwQQYDVR0eBDowOKE2MASCAiIiMAqHCAAAAAAAAAAAMCKHIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMCcGA1UdJQQgMB4GCCsGAQUFBwMJBggrBgEFBQcDAgYIKwYBBQUHAwQwfAYIKwYBBQUHAQEEcDBuMCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcC5zay5lZS9DQTBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5zay5lZS9jZXJ0cy9FRV9DZXJ0aWZpY2F0aW9uX0NlbnRyZV9Sb290X0NBLmRlci5jcnQwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL3d3dy5zay5lZS9yZXBvc2l0b3J5L2NybHMvZWVjY3JjYS5jcmwwDQYJKoZIhvcNAQEMBQADggEBAHRWDGI3P00r2sOnlvLHKk9eE7X93eT+4e5TeaQsOpE5zQRUTtshxN8Bnx2ToQ9rgi18q+MwXm2f0mrGakYYG0bix7ZgDQvCMD/kuRYmwLGdfsTXwh8KuL6uSHF+U/ZTss6qG7mxCHG9YvebkN5Yj/rYRvZ9/uJ9rieByxw4wo7b19p22PXkAkXP5y3+qK/Oet98lqwI97kJhiS2zxFYRk+dXbazmoVHnozYKmsZaSUvoYNNH19tpS7BLdsgi9KpbvQLb5ywIMq9ut3+b2Xvzq8yzmHMFtLIJ6Afu1jJpqD82BUAFcvi5vhnP8M7b974R18WCOpgNQvXDI+2/8ZINeU=",
- "MIIErDCCA5SgAwIBAgIQAznVp1LayatNgy6bN8f9QjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMB4XDTExMDMxODEwMDYxOFoXDTI0MDMxODEwMDYxOFowbTELMAkGA1UEBhMCRUUxIjAgBgNVBAoTGUFTIFNlcnRpZml0c2VlcmltaXNrZXNrdXMxITAfBgNVBAsTGFNlcnRpZml0c2VlcmltaXN0ZWVudXNlZDEXMBUGA1UEAxMOS0xBU1MzLVNLIDIwMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrlaYRX2v89k8Hd0ADaOfnUcIn7iM6aOXkAR+jp5827ZhDqDyNddF9ZUoBgPghGNIrkHbH7qwex39YnI0ka24lCjcwEMvQMPbyPnX/a4RyJ+wEZttmjBl++FfrZK54L+vD7Dyy4YYB0Og9ktB4qptsDBj+giiv/MGPeGeNs3TacJdNb7+3splTPtPKlDfrufvq4H6jNOv9S9bC+j2VVY9uCFXUro8AA3hoOEKJdSjlpYCa51N8KGLVJYRuc/K81xqi054Jz+Cy/HY/AcXkk2JkxlpJoEXmcuTkxjO/QE/Xbd+mRJHnq6+HurOiKcxKwZCPAa+d+dvRPkbyq9ohMXH9AgMBAAGjggE+MIIBOjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBxjCBlAYDVR0gBIGMMIGJMIGGBgsrBgEEAc4fZAEBATB3MCEGCCsGAQUFBwIBFhVodHRwczovL3d3dy5zay5lZS9jcHMwUgYIKwYBBQUHAgIwRh5EAEEAcwB1AHQAdQBzAGUAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQALgAgAEMAbwByAHAAbwByAGEAdABlACAASQBEAC4wHQYDVR0OBBYEFF11FBGM9KWOQo97skBEo+7WejtyMB8GA1UdIwQYMBaAFBLyWj7qVhy/zQas8fElyalL1BSZMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly93d3cuc2suZWUvcmVwb3NpdG9yeS9jcmxzL2VlY2NyY2EuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC3qNBgY2I9Wqm4LZYKAjCYkc2Nltm1RS9frMvQJ4aEE4Y4TtW2LPcQp2lenOf9aYdEB8G/E9CytZSPlFuvDdsdknj6fg1XCeu6ITR2wIkxJeAeLQvrFEfb1mcAa5tU9RNalZhYc7MFMFQTjQP+GBNxz+KIjNDVASFdv7TCe7GBjsW8Dfes9lQGHaWsBRkHCyuPGIHfH+cmMuhLtWqa4Qlg4f54kcsGO7s4buKtk6XqEj8Cj2ITdfk/aUs9QoxxkYWGwSUlCueTamzufXEJo9yz5Jp6IFdGjotmjb/EBUCf2sFfI83a4Cm1D3L3/KYb5g3cYlDEpPWNqbNuA1XosIqK",
- "MIIGYDCCBUigAwIBAgIQD2VSu5trtzD6hsNN/ETpETANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIFNlcnZlciBDQTAeFw0xNjA2MjkwMDAwMDBaFw0xOTA4MjkxMjAwMDBaMHcxCzAJBgNVBAYTAkVFMREwDwYDVQQIEwhIYXJqdW1hYTEQMA4GA1UEBxMHVGFsbGlubjEuMCwGA1UEChMlRXN0b25pYW4gSW5mb3JtYXRpb24gU3lzdGVtIEF1dGhvcml0eTETMBEGA1UEAwwKKi5lZXN0aS5lZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVJIqmmq7Z0jCppSUtNEVisEFG8u51YN6x7CbAWHXTeS+LzXSE2E/1z/cD5KBZfCWoOXlmloB/nwuXYp/uBL5dVWqxIfL6oiAAkWX1nC+qrnunr3y2kjYX8V+VEDIgLc3LZDe4LsZLXYInMbFS0Ri3DVxX2OFMhOHpyVOvOH8qbhRdbOccS5HLBbf6qXL6uXjMy+ntSf/+QdfwqYFG/C+dAFDrFHxUpBcuB3Bc86fGjZHAfsEuOp5WkzOK1RvfTOfcd6QerFDbEzF87JWhvsv0xnFv9CwIEYWCuQIoH7eFBpJJ/JsnqghpcgWuQHzEGBDC//J/OScM7CQq4+HPlp+zaylN2iE/ttMzsoDV7m9IIEmsl3pt+Syom42SUWZ8ch9K5e4XaHwFA2VWTloNMO5kpNBqZjfXElywYFp1b+LeGSQ8R5Js+P7mWhGCUO2NhP3KXSrHtUB9DkCCUhbnsr/MBEWzkKDjCribE8IWxeBNjU9WhMTVi7Xj5J7fCCLyZ+VkOP7R8Kuqvixz8p5pdaoHVDF8IBLZayUUVSf6OqfEhKoXUt+2mF4ZZFUg7obKPwRrIzxyG0/exOGyP8FXUuolHMr+hTrwtSuloc3tbio5B8UVGSd8j7OVNXqKC4psgDSlp38PcubyehCGLa5bN5zJsqeLZtdaIkVL99FEdZ7ozAgMBAAGjggHtMIIB6TAfBgNVHSMEGDAWgBRRaP+QrwIHdTzM2WVkYqISuFlyOzAdBgNVHQ4EFgQUz8kOnh82UA6nPH0DCFrVwSkqXUgwHwYDVR0RBBgwFoIKKi5lZXN0aS5lZYIIZWVzdGkuZWUwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjB1BgNVHR8EbjBsMDSgMqAwhi5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzUuY3JsMDSgMqAwhi5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1zZXJ2ZXItZzUuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQICMIGDBggrBgEFBQcBAQR3MHUwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggrBgEFBQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkhpZ2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAOTtFXk9wddPvtGz6RbTMUK0ZKmcs2zOAVNnugrVk6eSoR0II9X3fNHPiMmFhu0U++pD/Y1BDDRpIawacFWMF2OeAsnXZXLlCeoPotlbqXQfouFdY1u9Bw58ezJJzXO9l6B7NtQnEgSKxxE5MlZRiEuLM+gCaCrS4VvUgrmDjChEqzWl/3clZXIziuLBBhlCzZ465xNfeSrWWjSawdpoBgw/yjHVvhGoLufRs/4lOt4pXsr1YRhgyqo1ghek0ged1JycCeXlw6pRX+eZ8BPLePukjqS3FzCuWmpsfjSlsn+0NM7nFgTzQqJnf1jCg++tBnuwLilRkZ0D1WKXGKsuTSQ==",
"MIIGgTCCBWmgAwIBAgIQXlM7EyVgNCtYSVcwizB43DANBgkqhkiG9w0BAQwFADB1MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCAXDTE2MTIwODEyNTA1NloYDzIwMzAxMjE3MjM1OTU5WjCBhjELMAkGA1UEBhMCRUUxIjAgBgNVBAoMGUFTIFNlcnRpZml0c2VlcmltaXNrZXNrdXMxITAfBgNVBAsMGFNlcnRpZml0c2VlcmltaXN0ZWVudXNlZDEXMBUGA1UEYQwOTlRSRUUtMTA3NDcwMTMxFzAVBgNVBAMMDktMQVNTMy1TSyAyMDE2MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlkOLeKQPKK1U8VK7z2Dzt2SX2KblGqrBmOXfzlImzXHxGVopSeji2/4MdR5Ok6NJqXxanbyufXXRTeuE5nQ8Olzr5+9U21DPmVUADFNWnDLy6NWyqE3CvrYp7tVOHbfTb9Mf3ECvQNt8YM0HGwdSfc8kGXuX8d4oixxeG4AD+wrj1+LJ0ioaQFlS6Tbcwq3xEO0WVv1hMrJOoMmPpaqrvRLcoikpmjnPm/Gtfx64FcyXiMmNxFDnROVMgr1OQKbxAdlX3Iu32fcXjXesCTcACLlNRMi5Sb1wowjGEpqL2H53+JDIrdE7hM0uUqX4aaT5etaUh0o2hxOBHg3m6WRAZmBPqO1BqIBN6PRMWYgab7BBtJMUKXE+FUaNy9Lb8jraX85t3IwN/hbbMx3wUAqZvoQVIaJu2tsP8eTGJUd6jES9q9rH788LNf2w9o16blr1cM0AkzfbPf1ktClERcQd+iEhAPluSjKwMHIehRQGwGGuo7db4QXKhXDXPGK5YRw6Q56mp+BpSqJJqpdlQCieEXbHm9sHsoP5yaQygZI8nJpd0nlpdcTq91aEjrWuuksQTNDG9++8NSAql2G/BVCesWx/zR0KtcWecMPUVfe7qEEFurWsewpLgZFsk5RLtNGwyTEgHHBfJqAJC8l2VMfbbsEW+tcjdMqb6BHgT6hNCx8CAwEAAaOCAfcwggHzMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgHGMIHTBgNVHSAEgcswgcgwgYQGCSsGAQQBzh8HAzB3MCEGCCsGAQUFBwIBFhVodHRwczovL3d3dy5zay5lZS9jcHMwUgYIKwYBBQUHAgIwRh5EAEEAcwB1AHQAdQBzAGUAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQALgAgAEMAbwByAHAAbwByAGEAdABlACAASQBEAC4wCAYGZ4EMAQICMAsGCSsGAQQBzh8HAjAIBgYEAI96AQEwCQYHBACL7EABATAIBgYEAI96AQcwCQYHBACL7EABAzAdBgNVHQ4EFgQUrl5Y9fLy2cGO2e9OB9t1ylDihwAwHwYDVR0jBBgwFoAUEvJaPupWHL/NBqzx8SXJqUvUFJkweAYIKwYBBQUHAQEEbDBqMCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcC5zay5lZS9DQTBGBggrBgEFBQcwAoY6aHR0cDovL3NrLmVlL2NlcnRzL0VFX0NlcnRpZmljYXRpb25fQ2VudHJlX1Jvb3RfQ0EuZGVyLmNydDA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vd3d3LnNrLmVlL3JlcG9zaXRvcnkvY3Jscy9lZWNjcmNhLmNybDANBgkqhkiG9w0BAQwFAAOCAQEAah2vGqi+Pe5+CPtarh0vCQWOm233nl5Y9qL+JqG5PccowQ41kzf4qknmP6BHfisYGQsRc75K07A+/BdlFrLMbP3fFsuTi7+HAmAjXYEq35G49GAQg52+HvZiBe+RtbR8yOOar5fAKnzS1yNy9M1z7g7yMcEouk3TUebe2aanMvzabc7qgV3HGDfZkzhL9PlcjmFl0LQEflef/6sdMhy6C0HiditdLSUZYfSySJpb6lvJBGdN4Vrbo2fNtL3qIc+vX1Jvh/qLFIFmFXuC6lIjFJFtpIbCIQMtHoMXdI1A5JzzkmrTLPTSYDAQXXn9RPnzsRz2GnlYRV4xGayDGbUyow==",
- "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"
+ "MIIFuzCCBKOgAwIBAgIIB7tYMxdqiRQwDQYJKoZIhvcNAQELBQAweTEtMCsGA1UEAwwkRGV2ZWxvcGVyIElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcNMjIwODAzMDc0MjEzWhcNMjcwMjAxMjIxMjE1WjCBqTEaMBgGCgmSJomT8ixkAQEMCkVUODQ3UUpWOUYxRjBEBgNVBAMMPURldmVsb3BlciBJRCBJbnN0YWxsZXI6IFJpaWdpIEluZm9zw7xzdGVlbWkgQW1ldCAoRVQ4NDdRSlY5RikxEzARBgNVBAsMCkVUODQ3UUpWOUYxITAfBgNVBAoMGFJpaWdpIEluZm9zw7xzdGVlbWkgQW1ldDELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDb/Y5hBrdR/IgotXMxrSILtD5P3n6PlMsVPH0xlnIU8x9qRT7TPZf50FnN55WYXz12vSST1Z7hOGC6Lii4Rf9hxa96bKIeuoI+L+86fh6rV2TqsXRB2U7otcvdZR4OW39wvLmDGkPaDzuQGoKCsaMIjQ5lXBc7CfNP32sKqtBH8MedmJoXeolYhN65STTIAY2B71XSWrwHH2I3pHFN7Kr2ggGZA6MLCzm/yH2xryhqbqOjlxXvIjD7gmho7kCWmvZzEF192N3n2RbxJnPRCvoK6WB9HsFs+/6zuZTV3Io0pJA3n5Ax5iFdrCw/L22HvSkB3sOMZRa4JYBykQ9BqWF3AgMBAAGjggIUMIICEDAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFFcX7aLP3HyYoRDg/L6HLSzy4xdUMEAGCCsGAQUFBwEBBDQwMjAwBggrBgEFBQcwAYYkaHR0cDovL29jc3AuYXBwbGUuY29tL29jc3AwMy1kZXZpZDA3MIIBHQYDVR0gBIIBFDCCARAwggEMBgkqhkiG92NkBQEwgf4wgcMGCCsGAQUFBwICMIG2DIGzUmVsaWFuY2Ugb24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2NlcHRhbmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRpZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wNgYIKwYBBQUHAgEWKmh0dHA6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5LzAXBgNVHSUBAf8EDTALBgkqhkiG92NkBA0wHQYDVR0OBBYEFFAAcixtXY1mEP5ackgjI9X+9PraMA4GA1UdDwEB/wQEAwIHgDAfBgoqhkiG92NkBgEhBBEMDzIwMTIwODI3MDAwMDAwWjATBgoqhkiG92NkBgEOAQH/BAIFADANBgkqhkiG9w0BAQsFAAOCAQEAgZNNYbV7Hw7L3qqTGWP76QQyjIw7XfzIIVlKHcThOw6gihW2bgz0/uC62b2IBBxklF6+M/u7dgGN2cp29mn5A/EoWLNnCigpWBkpH+fh8j3FqkEVOZCHftz3BiuxGSuSd5jgULlj7XkFfymZlbelzLnKtVF2ypRBivAXalLQdf/f504uHg5IGR3YGkI6JO8ah6lyN4AQe4QATx9eHLH2KafX0Yb1+SaNFoGvNa50+r4mu+IHRUYukc60KB0zwnOXVSKDVabHIXY8VowqrSZQNdXZKwyz686eqWe3IW+82RSBeULtlIlhm1j3AwBx0VtOsOYCB6GbPlN1eCWGOT0fsg==",
+ "MIIFuTCCA6GgAwIBAgIQdGXMmxhPDu1hWuq15s9LKTANBgkqhkiG9w0BAQwFADBmMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEhMB8GA1UEAwwYU0sgSUQgU29sdXRpb25zIFJPT1QgRzFSMB4XDTIxMTAwNDExNTExN1oXDTQxMTAwNDExNTExN1owZjELMAkGA1UEBhMCRUUxGzAZBgNVBAoMElNLIElEIFNvbHV0aW9ucyBBUzEXMBUGA1UEYQwOTlRSRUUtMTA3NDcwMTMxITAfBgNVBAMMGFNLIElEIFNvbHV0aW9ucyBST09UIEcxUjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL7mnRyYj4tyd8hvdY3RKvbRCDa70qUX+bi6GV081Y40QlpNvbZiB/Q31bMxOuHMZ9qmMktJyAS4d3LXaOsvrJT3kVg9Wk9+SJ071pMT4jKdelFR0e4pIM28DwLsfQ9n32kCyOTbSLz0cZ8RnZUW3Yk8qX2ORnFtn/oscJW4EWCBOh3hYlIK8MEyDqNr5MByrZ9Ew5LebDYxeOqa1KereTXVrF8RmWYpuXGuuMen5ujZtBjaF2LlSsb/chX4PtapgUZKLHVfPjVlpBlx1IAKcQCWorB/vqQeeBqGzLimlG7FiSA1IodYMQCncXqcY/Z/nbQTSNkRJd6xHVzCVJv6EqlW6lVnak6nJ5uCyITlVj3/oDxODiNe3Sc14/vPu4YvjX1U9NsNuC4VZiScarTSbgphi/TWmFkX3Cvyb1abBNJSbN7R7R4An49Wl28uN87h7mu7HydcCF0Urqm1kjLryK7Y0ApGD5v6U3kRpIXvaqCr/+TVmBCiDvvwaMvxlZ+PpUOJMscYtWm8ijouup5AeFqnQWFzjZjF7ssL7u7Gf28xuWUj8yOJOWpKsMlkgTYz4GuroYsRcbjWOxTbjk9amRiHfMoQO3EjMBCq3fZUcRfomgc9xhu03Rj/P+sCkFI1kZDQaC5HH6KtnvO5F4INqgQlOIPuaaYGlaCCqeGoWG/ZAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSVDbdkGMKmm2Z22Pz8mlokvCjWzTAfBgNVHSMEGDAWgBSVDbdkGMKmm2Z22Pz8mlokvCjWzTANBgkqhkiG9w0BAQwFAAOCAgEAO8FcJcrsEGZXQasT4PtTN1DhvBtABv9iNR8rEeS9k0bTj4Y5FZ2kGeeYHscW3S9fxM3718nkbCTdGCJX2UM2aw+WZ9pNLjwNUuumxXE8ydnX0TLX7UozULBH7oIoYUJ5a6OFT/ZfJ4WfET7WXapIYzyl2rQ3VJnjoHLq5u6PqhnU8kJ41tivjsttmlbVJ1LKKMrbv2JoOv39E4NukarlK/vJ0CDWKGIhziusS/Uj1dxnQ4tYzakMlni3suNcgAl7atMShIUP1VjDDfcIs0V8RUfDVXEuyFsCU2FYxTeTwc7NA8V4zqtNKVHgkUoJkDaJM3EMyscyUf0EibBxMUt/uDLGmcHG/ap3fyNxG8ewtB44ky1DJ6LR6Boq2ieIkhM5TdHrYldZ39i66Kd7ssFXcUgDzrcQI/wVlCKnjnbhVnsNyB/W6FzdIqYzTzwMC4BYhsiJQ9AuEyPDJuetp8Rzdg59zdgiC1zqTMkIWxe5Kdnu/9QzvB12lXyTAS1xGKEWt7XM3MzhPZjYaB0EHrXdpd79k0YP9gxYIILISa20rWl95IbiYSVR6LvgiZOJV39SyPKHbRDECL2uz9s0ZgZku0B1yrwUwsL4YW8dNRw7InVzH/EoMANVkhuNQDiF9/zGQX3/5fcX5tJZaD3vy9mYJAJ5d/vhcGOqHbI3s2W27+c=",
+ "MIICtDCCAhagAwIBAgIQSmaL1ubiC3FhWulCIhJ3+zAKBggqhkjOPQQDBDBmMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEhMB8GA1UEAwwYU0sgSUQgU29sdXRpb25zIFJPT1QgRzFFMB4XDTIxMTAwNDExNDUwNloXDTQxMTAwNDExNDUwNlowZjELMAkGA1UEBhMCRUUxGzAZBgNVBAoMElNLIElEIFNvbHV0aW9ucyBBUzEXMBUGA1UEYQwOTlRSRUUtMTA3NDcwMTMxITAfBgNVBAMMGFNLIElEIFNvbHV0aW9ucyBST09UIEcxRTCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAN+zN0QNRH0pL6ozIEqFSBiqASoVlcgoi2+epQ6fU/gJ5ZbySnNtjcfxqqi3sW+XHK3IXN2kwMImzWx/P7S4ZhRfAJNJi6qPmyyDnXIE17jUuqVBcPZwpap3cqQND3FA3/wgs3r/dnBHyQD4M2ihf3j4IDy/ANl6IiI2D4Z50ik4QUfYo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUhnRPOus48rCn7u25hZudgwlFMWswHwYDVR0jBBgwFoAUhnRPOus48rCn7u25hZudgwlFMWswCgYIKoZIzj0EAwQDgYsAMIGHAkF+pYLDdJjsHc7hvW0dlIPk6riZKr3PDe6+3t3Paq+Udb4OGw3yzJoxCKQbnLULtlN6weO6wupBn91X+wX6QbCy/gJCAK/JtP1UsWLkmxCannuKGOIH8CgcKIXdW/z7/TQLfrygdJMgZ5TjzLMHXoX3gKSTNpCuZEeamEYBzd8HKLDnKYWV",
+ "MIIDiDCCAuqgAwIBAgIQH5sBIc4ZTj1hWvEFaRQX9DAKBggqhkjOPQQDAzBmMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEhMB8GA1UEAwwYU0sgSUQgU29sdXRpb25zIFJPT1QgRzFFMB4XDTIxMTAwNDEyMTgxMloXDTM2MTAwNDEyMTgxMlowZzELMAkGA1UEBhMCRUUxGzAZBgNVBAoMElNLIElEIFNvbHV0aW9ucyBBUzEXMBUGA1UEYQwOTlRSRUUtMTA3NDcwMTMxIjAgBgNVBAMMGVNLIElEIFNvbHV0aW9ucyBPUkcgMjAyMUUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT5UvJTY26GyX5dkIOsjGOvy4W1MFXjWgXW3q9aqT1yuEOUyuPnHtm/fTUiIXY5PCVviBhdqubUdP/U9bxOs6M6oTptGU9SJgQ7JY9tK4HbpJPk+J3Iz1JHMqq3JCktyUWjggFaMIIBVjAfBgNVHSMEGDAWgBSGdE866zjysKfu7bmFm52DCUUxazAdBgNVHQ4EFgQU/Inn/EN4/+wsw4Soo4DjI0ga1CgwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwbQYIKwYBBQUHAQEEYTBfMCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcC5zay5lZS9DQTA7BggrBgEFBQcwAoYvaHR0cDovL2Muc2suZWUvU0tfSURfU29sdXRpb25zX1JPT1RfRzFFLmRlci5jcnQwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2Muc2suZWUvU0tfUk9PVF9HMUUuY3JsMFAGA1UdIARJMEcwRQYEVR0gADA9MDsGCCsGAQUFBwIBFi9odHRwczovL3d3dy5za2lkc29sdXRpb25zLmV1L2VuL3JlcG9zaXRvcnkvQ1BTLzAKBggqhkjOPQQDAwOBiwAwgYcCQXQIw72bQj2lOzbDp3xy5TlFqBPQBIN0YbWV+TSenzGfqT6aQjHTZ9migRQeEXw97kXLSD3wN/g9LQ9Ok1dZvDQ3AkIAt+bOVtVzJr+43e8IFl4Cot5wPywcmI042EtuAT1SJ7lOkIUoaQZ6ZPj3pnI+5wX+z6s753MznY97AdwpGvEADkE=",
+ "MIIGszCCBJugAwIBAgIQTrdBH/kVRQFhWvLs8/TEtjANBgkqhkiG9w0BAQwFADBmMQswCQYDVQQGEwJFRTEbMBkGA1UECgwSU0sgSUQgU29sdXRpb25zIEFTMRcwFQYDVQRhDA5OVFJFRS0xMDc0NzAxMzEhMB8GA1UEAwwYU0sgSUQgU29sdXRpb25zIFJPT1QgRzFSMB4XDTIxMTAwNDEyMjYyMFoXDTM2MTAwNDEyMjYyMFowZzELMAkGA1UEBhMCRUUxGzAZBgNVBAoMElNLIElEIFNvbHV0aW9ucyBBUzEXMBUGA1UEYQwOTlRSRUUtMTA3NDcwMTMxIjAgBgNVBAMMGVNLIElEIFNvbHV0aW9ucyBPUkcgMjAyMVIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCv5c8Zz+xsh2xEQ3R4grFpZjzzJuRkHXs0xhVHNhJG8WZh6NldtLBHJPVT1PD8au9ism51NJMirstdbuYVBuoGXIBf+1/lg0M4KaLEOb1wgz/BXhBgRDMXjGdqlv24MnPx5Il0qTb2G7pBauksvTIOKWncM1CvcBA46zWjXHRGNv87BJcACaaU9/DA4hZZ1/my0Z+d+Fdh2YNCqfXWEJ8Sz3UVO16QMas2g8mL5vsp/0Viy4HAX5Gw+XwUmU+HKqdtHf0iW0zjTdUafOPdrbt0f1ivIi9FtZ9CpBXxUPdgC798VnK3jsaUwGwlKhXf7coT+6ulGSvERGCeWQ9yLfoswAieqDZ7Zp7iDG6CTMvMfn+dTdHqmkIWG2JYcFW9QVoCyQKTjvZfxtO1xAcVavvgXa+vaXX8EsyQqnYF7Zkp5PzB5/x9jmX70HBHEPc1CLarxYpMLLPc3FqtMiX2wVqv5HtfKuE8Q6xqmcQWMbjl51xHBrMOD51ahOs3W9bq6NT/BsHvzZ+fSFcjRjh4Jq7OFN/ymA0hD4+rbrixgpkJ3w1iA2mLyPT5BfwL2fEGMxtWxFj7y2ETzXN/mW34+CqyJcQHRYeXs9/bvg1iXiRyTCZA0Mkw8Z8E56PyXbNnhH6AOMg7S1YQ7yXFXzESEJaJ7mBZl5jPg4t/FThzPHnwwwIDAQABo4IBWjCCAVYwHwYDVR0jBBgwFoAUlQ23ZBjCpptmdtj8/JpaJLwo1s0wHQYDVR0OBBYEFOLGphjgoLJJ8oWgse1E8b2HyKY2MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMG0GCCsGAQUFBwEBBGEwXzAgBggrBgEFBQcwAYYUaHR0cDovL29jc3Auc2suZWUvQ0EwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jLnNrLmVlL1NLX0lEX1NvbHV0aW9uc19ST09UX0cxUi5kZXIuY3J0MC8GA1UdHwQoMCYwJKAioCCGHmh0dHA6Ly9jLnNrLmVlL1NLX1JPT1RfRzFSLmNybDBQBgNVHSAESTBHMEUGBFUdIAAwPTA7BggrBgEFBQcCARYvaHR0cHM6Ly93d3cuc2tpZHNvbHV0aW9ucy5ldS9lbi9yZXBvc2l0b3J5L0NQUy8wDQYJKoZIhvcNAQEMBQADggIBAC/df7QO74rBXo+wQnChGnbtpWZSdISgqMKtBhO3hAvy7s27odXThZi9fLPEpqw9CI5NSeGz6e5HGc258o4kYzhymMLF7Hyne2S5OVvfJ25XMtXOR23MGC4Yn1ogZXNPlaZULvty/1UzSLbjdGDnkfdHWTEPJPskXHS1CM70ZM2wGtfAjPRW90wThSZAh6CS/KNlJTTOjYMDYknQPTESiUV33YiB7xL5wV/9ymoM03IvZ0ew0ktY1YNsfr4eb3FfcFmCiXMRmPYbdncxBvyzLXxHoZtZJq2y3SHpPb1fqWv+LQC6+c3YeEYYyzNVwCgpdOpvr3QU6imr2H8eIcKCe5unD+gJFZC4+ITcF56RLQ/uzddwez+QYjWyIg9ZEwfvZZOqoWzvhxNlgr2yUs8cPV6rK3I+STVvS4BgwsGQlVrbddwllNHDVHbO3h6zSkjqUhYcAHWCHzptbjtl5GOVs/55m2/knlrxl8MuDXPl5h2PosaVqO7dI+2Sl/rpDTwyPlfnwdV8vKS6m81yc7H2pn29EspMBTE6/dRoaq2q0B17lt9ojuhkEus8QCbuFWs0avUnmDALqZq2qBg878WFSEIxS87EJ6X/zFm9kf/u+4aCN9hul2YzqQ/saFpWsvg083GHz1gNiikXYeUwygZmqqOj8tbX+thcE+XU/HSLWlHR",
+ "MIIGxjCCBa6gAwIBAgIQA8Yzby4uMFubV6H4HnhL6jANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjQxMDE2MDAwMDAwWhcNMjUxMTE2MjM1OTU5WjBVMQswCQYDVQQGEwJFRTEQMA4GA1UEBxMHVGFsbGlubjEhMB8GA1UECgwYUmlpZ2kgSW5mb3PDvHN0ZWVtaSBBbWV0MREwDwYDVQQDDAgqLnJpYS5lZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABCy4JcIKZk8dFBMjUv2qMLeEkuxr5EM0/+KxUxkJSs3vJpkhzIZ320m7ym76aj9CMZEuiyQqRnT7nHYJzOaIEm9XHeinCsY0HAwRrCDlrbldV28HjNYG8CGA/2/JSNPOw6OCBDowggQ2MB8GA1UdIwQYMBaAFHSFgMBmx9833s+9KTeqAx2+7c0XMB0GA1UdDgQWBBTYTWBJrjJMwWtZ4Ox4IonISfoAZDCByAYDVR0RBIHAMIG9gggqLnJpYS5lZYILcG9zdC5yaWEuZWWCC2VkZ2UucmlhLmVlggpzaXAucmlhLmVlggttZWV0LnJpYS5lZYINZGlhbGluLnJpYS5lZYITbHluY2Rpc2NvdmVyLnJpYS5lZYILbGRhcC5yaWEuZWWCDGRjLTAxLnJpYS5lZYIMZGMtMDIucmlhLmVlggtzbXRwLnJpYS5lZYINZXhjLTAxLnJpYS5lZYINZXhjLTAyLnJpYS5lZYIGcmlhLmVlMD4GA1UdIAQ3MDUwMwYGZ4EMAQICMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCA4gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGfBgNVHR8EgZcwgZQwSKBGoESGQmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDBIoEagRIZCaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsRzJUTFNSU0FTSEEyNTYyMDIwQ0ExLTEuY3JsMIGHBggrBgEFBQcBAQR7MHkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBRBggrBgEFBQcwAoZFaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsRzJUTFNSU0FTSEEyNTYyMDIwQ0ExLTEuY3J0MAwGA1UdEwEB/wQCMAAwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2ABLxTjS9U3JMhAYZw48/ehP457Vih4icbTAFhOvlhiY6AAABkpSklM8AAAQDAEcwRQIgGEmPYtbPkmR9NdEXeu5gqucySes9Ra7vciW7xhg2LasCIQDdOmZgr6L+QN+bBIKGgB/T6yzxQLRvKNvPETtgE9jvXQB2AMz7D2qFcQll/pWbU87psnwi6YVcDZeNtql+VMD+TA2wAAABkpSklCgAAAQDAEcwRQIgL0rRZd8MJkoVtmjg8G6bGyxVaXub4wexaXbtbQ4RVAcCIQDSkDns7vUGL0Crsc5i0xMwAro5iqyZEOyGCli8L2nFmQB2ABoE/0nQVB1Ar/agw7/x2MRnL07s7iNAaJhrF0Au3Il9AAABkpSklYgAAAQDAEcwRQIgKsnhYJ8AJ1h5zMlbIEeh2YiWc8aURcDf+GO/xTd8g4ACIQDIWX1+RBmHQKwe/pnohZDqMDIaSmyM7ZX6B1a6AkvBKzANBgkqhkiG9w0BAQsFAAOCAQEAsXhGL7QxYtuGVftNpwQpNJJ/bgTLnCEmgl6iU+dhrOR+LcahaP0+vLZwfuh9JHAYH/Ql5nLf2qH9iZUXGL29V7Go0Mn/vxOQ5xX1ltVf8E1beVOoBQQN3osvZtQy/Ye6Hgidmer4+8bpQMnqnNpFOKmqi1ACK9pGSXd/W5nJMOXGTygiVxBPI4f1rebBvuaDB3hq3BW8E40/67Xzjl+lXfTX2shJj5I3N+OMViqDIMhtqlRLMmEcl8kktvzKpul/+eQTx494Yt0lf0WekpW+rgjF4YqCN5JoTUHx+lwLaKlIsvT74F39Y/61SMnR5xGxF8gb3lmYgJNPcENHszJgAA==",
+ "MIIFrzCCA5egAwIBAgIQB5fgn6klk3Ga6n/J2RL1NTANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMB4XDTI1MDExMDAwMDAwMFoXDTI2MDExMTIzNTk1OVowZTELMAkGA1UEBhMCRUUxEDAOBgNVBAcTB1RhbGxpbm4xITAfBgNVBAoMGFJpaWdpIEluZm9zw7xzdGVlbWkgQW1ldDEhMB8GA1UEAwwYUmlpZ2kgSW5mb3PDvHN0ZWVtaSBBbWV0MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEnNF5qfUrm6gdc6MspP1v+SzGv2K6K9gwKCIwSfjRBumooxNTzSd9gW+SdCzdRKoRhSt8tPT9XELvRHpcj1ayT/tnffybcxaFoKCtZ2eMJ8zwK/w1sVGWCbRz2ky5pxtCo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0OBBYEFC+MYSkxqDrEsEsA/p6zxu72gNXBMD4GA1UdIAQ3MDUwMwYGZ4EMAQQBMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCBqjBToFGgT4ZNaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQDL+Lh2/OuFacwpHs+G3R0z1j9cY7psSFE2J7iSxcRmTc/Ds3TSaWW9+kcgwjDZxskMoZbD1SS2gZJZ7AFUhd7lYg15M20p4I0a14BizL+AjLtgwRcergb7ZMjeyFtbgkQgyhjtZr+XT7BwY2DXo5wwWy8RFVLwkrMjXhFN7HEiWJ2KIX1cAYhOXMcAyxLfxIrVX3UT8p1BM18ieGPwwzI0oJ1g5rEwnuqfg8PBFtcaRK9F0Smr9HMR6h7ebKCOi9O83awyP/V91ZOkGfNGf0BKXSvGB+54Ee41UUket+HE+rjZPxXQtwaXxcyVjI0Xk4+054LAgy4+MGKB+cYXZa4aEY51FHSYDO1l8vt8ZJscey29OiJ6c++tPLw1YMhhDMv/EhbOcjK4k09kXZUtgohEAuch9RsD/9OFqP6idH7vAJeeOC2Ve30xhsa5u3EpK4MTK7khBOGX0vNxCiyYOz4nvq7JrYyxtWrRvC9C9+TukvJU8K5NMtyQ0S2cwvsCT78y0761cAxVQSwR/639U0UtA7SEwfTJTU0V/ITkh75bKv2I9w5LjFzXiRPqJ2qHhoc8J1QyKfftF30yoMqvaIevPN3+DBSSYW2XpxI23OC6V9KVeBqZ6S1qq8LrZicfO5b3Tr/++4ta5Vq+mwKd7o2c9gQ+tHzQNDnrWla2mv6qhg==",
+ "MIIG3DCCBcSgAwIBAgIQBbJ7uT3/ymP1xXXusMNIoDANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjUwMTEzMDAwMDAwWhcNMjYwMjEzMjM1OTU5WjBQMQswCQYDVQQGEwJFRTEQMA4GA1UEBxMHVGFsbGlubjEbMBkGA1UEChMSU0sgSUQgU29sdXRpb25zIEFTMRIwEAYDVQQDEwltaWQuc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJj5wsSl1jz3D9bKwA6DtGEfl6AdXon31REZEPfDPxe23m9gPF9QhTH81VkUYXpg3qIHa1tmroq3MBYIqcTjE3l3FcPx9ZYZfbPfsMkzfSS+R762+SJb3HRge0AKSMs0BmwFQmta2IZun9+1s7Tdad9VcSYOVCQne6gE58vpczEHODZyBAyNR3WIXNbpN8OKRkwrzWE/pGuCiIxOI6/x6ZBKFqlfBxTamgMmTpiVs9VRw0Y6zpdsTUN90AMzBnTeMw2cViPDHBZdoxesug3ydmOGJKuOyZ8Y62lg2agKXd/sYvKxFxhycUqwNZaY69RYFfQj+Fi9W6OFFu6sDojHtrAgMBAAGjggOnMIIDozAfBgNVHSMEGDAWgBR0hYDAZsffN97PvSk3qgMdvu3NFzAdBgNVHQ4EFgQUNDmELZDdwFcMi5n44aLx3QIGlkQwOAYDVR0RBDEwL4IJbWlkLnNrLmVlggxzdGF0dXMuc2suZWWCFGRpZ2lkb2NzZXJ2aWNlLnNrLmVlMD4GA1UdIAQ3MDUwMwYGZ4EMAQICMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGfBgNVHR8EgZcwgZQwSKBGoESGQmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDBIoEagRIZCaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsRzJUTFNSU0FTSEEyNTYyMDIwQ0ExLTEuY3JsMIGHBggrBgEFBQcBAQR7MHkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBRBggrBgEFBQcwAoZFaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsRzJUTFNSU0FTSEEyNTYyMDIwQ0ExLTEuY3J0MAwGA1UdEwEB/wQCMAAwggF8BgorBgEEAdZ5AgQCBIIBbASCAWgBZgB1AA5XlLzzrqk+MxssmQez95Dfm8I9cTIl3SGpJaxhxU4hAAABlF7eZH0AAAQDAEYwRAIgY5GT4ke/Qge0a/GWOE+SUYOGFcaxias8dE9p947+G5MCIEplA74KIY20uRkXefjPAHPgE7CWv8x+BCCTg1jss5m2AHYAZBHEbKQS7KeJHKICLgC8q08oB9QeNSer6v7VA8l9zfAAAAGUXt5kvQAABAMARzBFAiEArQbIR7E+55rHLNl6Yrsew8I1nboMW44OA7xJhFLwDYQCIFMh/yrJv7furwfp5N+d+Sw269+G9JiwKqBAG2O7XfMeAHUASZybad4dfOz8Nt7Nh2SmuFuvCoeAGdFVUvvp6ynd+MMAAAGUXt5k0AAABAMARjBEAiAJQZH0Jqo8VMu9zyLZaAxcG+vdSn25GXzCa1jDX5isBQIgNYemDUj1NnpFVvPQYc1zQliVa51+Ng0jkBvP8XkgFuAwDQYJKoZIhvcNAQELBQADggEBAE52Z1X2abc6obKwCpuutKcppIsY0LeNUUOsqxSbubQ8y8XHtN4GtXjjQUC0WjMiJ8/gPT97mSXLXeylfnxkyT5/NNCpYGyU+qAuJsvzhLG5G3+R7PR7TtTyZCRjmVnCs64i+ZcQyrHSXxkoeZu3K+Mk+1k0ON8ndf7zD9Y9PwZSdnZzGjkMurUB1DXLPbBAiGAqF7N9YlUlg3itRr2F0jSdeZZpGZ9+PRRarKw2v2ritaw45Z2/7MWdZoeEIGUWidfFIK+WtT6tUbXQFjMvUHBClyehNeaZfxdECxkYYvEba0b5oDgzbc/0G9xwlMJW/ieNHRqy47g+yt0PzZH6KDc=",
+ "MIIGzTCCBbWgAwIBAgIQA5+kJCNnvx53jn4TwHD0BjANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjUwOTA5MDAwMDAwWhcNMjYxMDEwMjM1OTU5WjBaMQswCQYDVQQGEwJFRTEQMA4GA1UEBxMHVGFsbGlubjEbMBkGA1UEChMSU0sgSUQgU29sdXRpb25zIEFTMRwwGgYDVQQDExNycC1hcGkuc21hcnQtaWQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoIy/bUgMYw2tJcSKE9vmUakpY4VaLNs7cHQiwQdXjiuMTzTkWuU91Vd36WV54tys9r3VV79QjX0Tab3bWshir9b5/LeO4SbsHHkAkblha5slENskZG5g/5g2Hz9GuAq2iaUJg5kqiys8cQNHfvRWB3TSOyechI2Ifd8uujvn88bAq3N5s++avqgXxPiK4owp6Mjhi3uilbABjGPqvHSRcLfyIP1N/+vkbevbNFCRGTscl2FziqPnjOcF8mTEAaXlMtcEneifH0ExMYXlxvPccL6qhMIgZngTgz0vovYMH0PgPCr0gwEauPBiVi8js26Z0dHXs/aNLzp10baIBbyoCwIDAQABo4IDjjCCA4owHwYDVR0jBBgwFoAUdIWAwGbH3zfez70pN6oDHb7tzRcwHQYDVR0OBBYEFM1Ph6kBRDqiudsf36FON7PGcxjHMB4GA1UdEQQXMBWCE3JwLWFwaS5zbWFydC1pZC5jb20wPgYDVR0gBDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwgZ8GA1UdHwSBlzCBlDBIoEagRIZCaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsRzJUTFNSU0FTSEEyNTYyMDIwQ0ExLTEuY3JsMEigRqBEhkJodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHMlRMU1JTQVNIQTI1NjIwMjBDQTEtMS5jcmwwgYcGCCsGAQUFBwEBBHsweTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFEGCCsGAQUFBzAChkVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHMlRMU1JTQVNIQTI1NjIwMjBDQTEtMS5jcnQwDAYDVR0TAQH/BAIwADCCAX0GCisGAQQB1nkCBAIEggFtBIIBaQFnAHUA2AlVO5RPev/IFhlvlE+Fq7D4/F6HVSYPFdEucrtFSxQAAAGZLkmZCgAABAMARjBEAiBlPU616DGJeKiJBR74i+o3wjzlVMIY5zxOGMurKOyFQwIgWA3UmS98yhyNcdMT7ukbc8s8zY5cW/wydEqYHYXwVUYAdgDCMX5XRRmjRe5/ON6ykEHrx8IhWiK/f9W1rXaa2Q5SzQAAAZkuSZj9AAAEAwBHMEUCIHMc4LOBEy/e9Wa5qzPnHIT5wVUdBXgayxLUrIwaJBD/AiEA8FMbqN2fxJ+A5oS3x0C6EbOrYqcoMJm/YTPH+6JuICwAdgCUTkOH+uzB74HzGSQmqBhlAcfTXzgCAT9yZ31VNy4Z2AAAAZkuSZkNAAAEAwBHMEUCIQDnyAd6Fj0JOBa5DI3kXPXfGdbmv1NztOg3gyxaeuyaMwIgNuVf2mJXA/aHoc1faD9RsRM2VGCRxUemgV/smvt8sPwwDQYJKoZIhvcNAQELBQADggEBAExTQwgHpEQuJCMSvaEVKsxNIqL+7eUymMsH2EV5kKaBw7v2ROpqImXt4F4WGca/fKWYLZ/ILOVxjd57AQynueJWO86UrEM/SPe4wFZAf0OUk600v2K4EFFq/CXMzrYYJX2izgsgTvmcR/aUnMuRuyD2Du/EAUN0FPgy8pAggdyLhZzIALn03cNoyxoFo3frY6Px1tSOZZpA0RNSoYnHx3a6KHl0dNZi8s/sbJEoZVBehcfUqb2uUzWGeojjkzed5kB9vF7AAOsw1Thaphq15ob/XTm+6GJ3+J9kq5n9PKD7Cefvj4uuyLgmdZuMMj3CiZosoqfGcE8/KkCJqfhEBrM=",
+ "MIIGHjCCBQagAwIBAgIQDMrg7qvZoQQsopLpvfChaDANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjUwOTEyMDAwMDAwWhcNMjYxMDEzMjM1OTU5WjBXMQswCQYDVQQGEwJFRTEQMA4GA1UEBxMHVGFsbGlubjEhMB8GA1UECgwYUmlpZ2kgSW5mb3PDvHN0ZWVtaSBBbWV0MRMwEQYDVQQDDAoqLmVlc3RpLmVlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4IpdslJS5cTk0BZoXYzSyh/tqp8Obis/ql0ki0p2GgqBOhQmBq6yVZoeILEQ9wcbohDvJRIVmtUzuHDoGLNl/hn0IkgipnwUsFarDWxCEVDcB9spfvIx/fLd/VSE1f/yo4IDkDCCA4wwHwYDVR0jBBgwFoAUdIWAwGbH3zfez70pN6oDHb7tzRcwHQYDVR0OBBYEFKMVzJLJqEbwX0HMnXZt1iUtPduLMB8GA1UdEQQYMBaCCiouZWVzdGkuZWWCCGVlc3RpLmVlMD4GA1UdIAQ3MDUwMwYGZ4EMAQICMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCA4gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGfBgNVHR8EgZcwgZQwSKBGoESGQmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDBIoEagRIZCaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsRzJUTFNSU0FTSEEyNTYyMDIwQ0ExLTEuY3JsMIGHBggrBgEFBQcBAQR7MHkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBRBggrBgEFBQcwAoZFaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsRzJUTFNSU0FTSEEyNTYyMDIwQ0ExLTEuY3J0MAwGA1UdEwEB/wQCMAAwggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2ANdtfRDRp/V3wsfpX9cAv/mCyTNaZeHQswFzF8DIxWl3AAABmT2Vwu8AAAQDAEcwRQIgGbSUAK8bl5A8b5v0FSp/o135hO2ylcRi1hzYZkVMIhICIQDlR0ckG3H87FrkOegK0T139V2uIP7Y62xM7NjikcjefwB1AMIxfldFGaNF7n843rKQQevHwiFaIr9/1bWtdprZDlLNAAABmT2VwygAAAQDAEYwRAIgVjGiyemVVj1fEuJRODvfuPba+jklXittElL1yGSDgcoCIHWhZp4I07CVZzFA17nvA8B5vITZvaJv8pA1k89IczrKAHcAlE5Dh/rswe+B8xkkJqgYZQHH0184AgE/cmd9VTcuGdgAAAGZPZXDOAAABAMASDBGAiEA9vhIokXmoGiCcyJ1U+4gPzbXDgwLlCMw06JZOl4b+TECIQCggmWLTLjIAbeKzWVnPq4HbWt1wJ96vmoG2xxpwnldKzANBgkqhkiG9w0BAQsFAAOCAQEAZLwfi2XkaFt4LFKcuVXvRV9zQQUR7fixiNnwL7aXun6603nt3TSXGkwFe2E6yiJWecCAuSb/H7JCTWA8pei+GPnrfExlZ4quZnYC9OQ/qifTekJP1LduWPrVmoSTVsBiy2mK0PpWIyiRSCDyacZZcbF/DI90xM4lkOeSt4TgQg6eHXu28ak+deBEHo0gHqyP2bMRaXM8f9Ep3lthKk3LprHB7GKqKAKT9DDpgrUtarGNa2q6XucsH6eSYKG8Dt3PhmxGCauSh/yv2aSKgHKbyklDqAy03xjRArwSPK4GBVPBWx0KCjktFj8YpgSF8ph15V+lYDZYZ0qfHDR8AN1RJQ==",
+ "MIIGgDCCBWigAwIBAgIQDHOt+EmMGn2HOzfhe9B7ZTANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIgVExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjUxMDE3MDAwMDAwWhcNMjYxMTE3MjM1OTU5WjBVMQswCQYDVQQGEwJFRTEQMA4GA1UEBxMHVGFsbGlubjEhMB8GA1UECgwYUmlpZ2kgSW5mb3PDvHN0ZWVtaSBBbWV0MREwDwYDVQQDDAgqLnJpYS5lZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABOqyzlVtOV6ZyOzqz9Y6Es18VV6VRF9GBNYr3ljLv4Mhe2MmLxLRnrHi71J596AlPfVO44g3cxLd7+C06pa2JiWNnXpDmVHG/E0+22DhFXGSFAs4A4P541N8/aDUlU0CfKOCA/QwggPwMB8GA1UdIwQYMBaAFHSFgMBmx9833s+9KTeqAx2+7c0XMB0GA1UdDgQWBBQ3qFelA5/OC5uNUIcS8HToB3VmJTCBiwYDVR0RBIGDMIGAgggqLnJpYS5lZYILcG9zdC5yaWEuZWWCC2VkZ2UucmlhLmVlggtsZGFwLnJpYS5lZYIMZGMtMDEucmlhLmVlggxkYy0wMi5yaWEuZWWCC3NtdHAucmlhLmVlgg1leGMtMDEucmlhLmVlgg1leGMtMDIucmlhLmVlggZyaWEuZWUwPgYDVR0gBDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIDiDATBgNVHSUEDDAKBggrBgEFBQcDATCBnwYDVR0fBIGXMIGUMEigRqBEhkJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHMlRMU1JTQVNIQTI1NjIwMjBDQTEtMS5jcmwwSKBGoESGQmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDCBhwYIKwYBBQUHAQEEezB5MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wUQYIKwYBBQUHMAKGRWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNydDAMBgNVHRMBAf8EAjAAMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdwDXbX0Q0af1d8LH6V/XAL/5gskzWmXh0LMBcxfAyMVpdwAAAZnxHHegAAAEAwBIMEYCIQDbYfrzJ6ZSb85MX+NyF1pz7YEZsxn3SxzvvFJ4QD4b7wIhAKlGk+pWB/oYT0OF9S3LlhcUxJtz667OwhncYhkpaM8mAHUAwjF+V0UZo0XufzjespBB68fCIVoiv3/Vta12mtkOUs0AAAGZ8Rx3WQAABAMARjBEAiB3t69Ky0tXi7s5JZ7dsl4CtZ69rJLD0aZUTHeTQCHa4gIgAm3ZguHxRQLGWUa06JtStsKzKZakQk5RWKSToN3P0QoAdwCUTkOH+uzB74HzGSQmqBhlAcfTXzgCAT9yZ31VNy4Z2AAAAZnxHHdqAAAEAwBIMEYCIQDgqNclAoixTSuNx3irFOd78qRVrNRwXuYFjkInVFb8ngIhAKWEClxFeNrQ9yZbc4qMmO66Oz8OubWlsfgYHZC0jao/MA0GCSqGSIb3DQEBCwUAA4IBAQB3LTXOdbuOswocNge7uLrRz3zypn3QqS4SrIE/0CTBaXl7VEMQLiKEbZL4bTUoatrgFkSxolqXwYc0U0y6K021Jg63lwsj7C74IhytxdOgXqz3fZ0C3gOPWwmEMPEogD+zLf9pibKi10+/X2JIshBvGE91KOvD0Z91oq+5g9oxVSisugkKeTl9ivW4UPs+llYAMDooNWZkwFLMdzSgaAiWOz4qnr4otITEqPuWhsKxJwyAtY2cVp9qFLJ9CMXY1IqgXdxHx1iLnot1XQuOSqqQZ1tYsfKazth0ef89NQEouc4ejCbMlggg7vijWk1fPjyWZZh3lUIkdSV8b6TrmUmn",
+ "MIIDDzCCApagAwIBAgIUUFQrcGtK7/jCP+GyAOTPvbglGlcwCgYIKoZIzj0EAwMwWDEUMBIGA1UEAwwLRUVHb3ZDQTIwMjUxFzAVBgNVBGEMDk5UUkVFLTE3MDY2MDQ5MRowGAYDVQQKDBFaZXRlcyBFc3RvbmlhIE/DnDELMAkGA1UEBhMCRUUwHhcNMjUwNTA3MTMyMDA3WhcNNDAwNTAzMTMyMDA2WjBXMRMwEQYDVQQDDApFU1RFSUQyMDI1MRcwFQYDVQRhDA5OVFJFRS0xNzA2NjA0OTEaMBgGA1UECgwRWmV0ZXMgRXN0b25pYSBPw5wxCzAJBgNVBAYTAkVFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdSEmb1AnxN7G22CCEQ3ts2YZNieTUZP4Vc4iObhmL/um4EXkiA4HgyCiR5T6olKAEkPdxFBsfmcLoPN+TmBO8ZpLGEqy1Vwf59ahDW7dQiLXTIAEiGCoXSWI9MvtHDZ2o4IBIDCCARwwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSqgKibD7tLpn7FAvRyzSzxpSnZtzBABggrBgEFBQcBAQQ0MDIwMAYIKwYBBQUHMAKGJGh0dHA6Ly9jcnQuZWlkcGtpLmVlL0VFR292Q0EyMDI1LmNydDA9BgNVHSAENjA0MDIGBFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9yZXBvc2l0b3J5LmVpZHBraS5lZTA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vY3JsLmVpZHBraS5lZS9FRUdvdkNBMjAyNS5jcmwwHQYDVR0OBBYEFJLAOLC4NhJo9crtZu5HKohtpo3oMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjANipgLQqdM985dSFZfKvU9A7Sz2YdmmUSZBxu0lL7QXKzqa0ZDyXmf03NPLNAC6dICMBQiROZbLoPezO9LDl847UbENx85hloLlzweWjqPrY++Xj8FjCD1C9hnblsVgj3XAA==",
+ "MIICljCCAhygAwIBAgIUKbkXJo8FWjthNs7Hgduq1RiXqwswCgYIKoZIzj0EAwMwWDEUMBIGA1UEAwwLRUVHb3ZDQTIwMjUxFzAVBgNVBGEMDk5UUkVFLTE3MDY2MDQ5MRowGAYDVQQKDBFaZXRlcyBFc3RvbmlhIE/DnDELMAkGA1UEBhMCRUUwHhcNMjUwNTA2MDgxODEzWhcNNDAwNTA1MDgxODEyWjBYMRQwEgYDVQQDDAtFRUdvdkNBMjAyNTEXMBUGA1UEYQwOTlRSRUUtMTcwNjYwNDkxGjAYBgNVBAoMEVpldGVzIEVzdG9uaWEgT8OcMQswCQYDVQQGEwJFRTB2MBAGByqGSM49AgEGBSuBBAAiA2IABH0zMU4DUN/Ay6gUdWzMUDAYFaau0flpuuicO2bfK7kHNGw+psRRn6DaF/4cVQd8qHxbDF2xN4jJf1bSpQHLsc2RZHSCI8qb4E9GmB5MDoVVxiXnBHOOW3+55Qm/BfwcwaOBpjCBozASBgNVHRMBAf8ECDAGAQH/AgEBMB8GA1UdIwQYMBaAFKqAqJsPu0umfsUC9HLNLPGlKdm3MD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRwczovL3JlcG9zaXRvcnkuZWlkcGtpLmVlMB0GA1UdDgQWBBSqgKibD7tLpn7FAvRyzSzxpSnZtzAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwOy8+eV+yYNXtXcEEdOuQd60O7lXucK3W4cDewxEoEXb4iTYFswWUZq3DacfmeE+/AjEAkzHeNdruQqKfvqTFB3eNRnMycNcnJ3rmGe37u9zgH8wnQUuMhUClOGxeRcK4NV9I",
+ "MIIDoDCCAyegAwIBAgISBUdhRNOo1bXcZGI1+B1vwKZzMAoGCCqGSM49BAMDMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJFNzAeFw0yNTExMDkyMjA0MzFaFw0yNjAyMDcyMjA0MzBaMBYxFDASBgNVBAMTC2Nkb2MyLmlkLmVlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEVt9SqxzY0NYNsKygXEm3oFpgvBytSzwf5apEhbv6aXgpp8h1B06Uw4Q3Yxr9ZsspcO+5loGSQUCev8wmNkVOtj0cBGnVQXCciml9mNd3/tX29nLLbotOxHIjBfrc3qaZo4ICGjCCAhYwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQYnBQVuZlKJA/pTzdshpeBWeGR8jAfBgNVHSMEGDAWgBSuSJ7chx1EoG/aouVgdAR4wpwAgDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly9lNy5pLmxlbmNyLm9yZy8wFgYDVR0RBA8wDYILY2RvYzIuaWQuZWUwEwYDVR0gBAwwCjAIBgZngQwBAgEwLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL2U3LmMubGVuY3Iub3JnLzExNi5jcmwwggEEBgorBgEEAdZ5AgQCBIH1BIHyAPAAdgBkEcRspBLsp4kcogIuALyrTygH1B41J6vq/tUDyX3N8AAAAZpq285VAAAEAwBHMEUCIHK46Zs1qCYx8zRczC1aigCESU6elwKmLsyhhpoDdjd2AiEAmBbCL2EMffb32y8+dCn1DhEILxJ0NpkYU1e5BsneddwAdgAOV5S8866pPjMbLJkHs/eQ35vCPXEyJd0hqSWsYcVOIQAAAZpq285WAAAEAwBHMEUCIGqLeCx94YcwnsTJ56Qt+GChY4b0lO/eWaJmuRVLOsXnAiEAv27lUIMHJ3a2tDdALBqJmjiRsEuBMDYRyjlY0h1a2H4wCgYIKoZIzj0EAwMDZwAwZAIwKspSm2IOnmy/ovKzG3mhQ6DKZfX1I4xjNlDVlu6E3e4BmzQ5EM7FXVX3ilomxP9xAjAT3p3oGHBormjrhHpc9TVJi/d4nnmya/m1Uwe3h611ALaHGiVD3tMPLIzsiSPG8w8="
],
- "TSL-URL": "https://ec.europa.eu/tools/lotl/eu-lotl.xml",
- "EIDUPDATER-URL": "https://installer.id.ee/media/teavitus/",
- "EMAIL-ACTIVATE-URL": "https://sisene.www.eesti.ee/idportaal/postisysteem.lisa_suunamine?=%1",
- "MID-SIGN-TEST-URL": "https://tsp.demo.sk.ee",
- "EMAIL-REDIRECT-URL": "https://sisene.www.eesti.ee/idportaal/postisysteem.naita_suunamised",
- "SIVA-URL": "https://siva.eesti.ee/V2/validate"
-}
\ No newline at end of file
+ "LDAP-CERTS": [
+ "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"
+ ],
+ "ALLOWED-EXTENSIONS": [
+ "ddoc",
+ "bdoc",
+ "edoc",
+ "adoc",
+ "asice",
+ "cdoc",
+ "asics",
+ "txt",
+ "doc",
+ "docx",
+ "odt",
+ "ods",
+ "tex",
+ "wks",
+ "wps",
+ "wpd",
+ "rtf",
+ "xlr",
+ "xls",
+ "xlsx",
+ "pdf",
+ "key",
+ "odp",
+ "pps",
+ "ppt",
+ "pptx",
+ "png",
+ "jpg",
+ "jpeg",
+ "bmp",
+ "ai",
+ "gif",
+ "ico",
+ "ps",
+ "psd",
+ "tif",
+ "tiff",
+ "csv",
+ "cdoc2"
+ ]
+}
diff --git a/config-lib/src/test/resources/config.pub b/config-lib/src/test/resources/config.pub
deleted file mode 100644
index a3935c91f..000000000
--- a/config-lib/src/test/resources/config.pub
+++ /dev/null
@@ -1,8 +0,0 @@
------BEGIN RSA PUBLIC KEY-----
-MIIBCgKCAQEAu7GeS3jgvLjKL8ZgA4DlT3n3+/IQpoSlO0ErRIVT5upbY7yDf0mj
-Cc8Xaqr91aBHjYnrEAz+nkmb12BuJCp/C3xQXnXEQchF2J+HfMbIClJ7TCl2951k
-kuKdZpNeZ/iim0uRTs1UA0ews0+CPLAAklEpC1h5+fK8Uwl9+5h+v5jj/9P06ey0
-8H3VpxX4Nu0XTU2QcXocv5BTYJKxLKQicEL+nstpBrRI2Cqgwcd2Fz2qp8M9KJvI
-TKW0TD2EKgq6nYELXPRNl/KOsVt7RGyUutd809GARfcOotvhHy2qzHoWlr3pY2ZO
-zMSpZbisPvbOJ4fIyPhkbWBr7a3ytquOmQIDAQAB
------END RSA PUBLIC KEY-----
\ No newline at end of file
diff --git a/config-lib/src/test/resources/config.rsa b/config-lib/src/test/resources/config.rsa
deleted file mode 100644
index d4fd7a85b..000000000
Binary files a/config-lib/src/test/resources/config.rsa and /dev/null differ
diff --git a/config-lib/src/test/resources/configuration.properties b/config-lib/src/test/resources/configuration.properties
index 482ab9f33..015acee7c 100644
--- a/config-lib/src/test/resources/configuration.properties
+++ b/config-lib/src/test/resources/configuration.properties
@@ -1,4 +1,4 @@
-central-configuration-service.url=https://id.eesti.ee/
+central-configuration-service.url=https://id.eesti.ee
configuration.update-interval=4
-configuration.version-serial=94
-configuration.download-date=04-09-2019 15:04:19
\ No newline at end of file
+configuration.version-serial=200
+configuration.download-date=07-01-2026 16:33:26
\ No newline at end of file
diff --git a/crypto-lib/src/androidTest/kotlin/ee/ria/DigiDoc/cryptolib/CryptoContainerTest.kt b/crypto-lib/src/androidTest/kotlin/ee/ria/DigiDoc/cryptolib/CryptoContainerTest.kt
index b4d4f2c91..c98d0a83b 100644
--- a/crypto-lib/src/androidTest/kotlin/ee/ria/DigiDoc/cryptolib/CryptoContainerTest.kt
+++ b/crypto-lib/src/androidTest/kotlin/ee/ria/DigiDoc/cryptolib/CryptoContainerTest.kt
@@ -169,7 +169,7 @@ class CryptoContainerTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
CryptoInitialization().init(
isLoggingEnabled = true,
)
diff --git a/id-card-lib/src/androidTest/kotlin/ee/ria/DigiDoc/domain/service/IdCardServiceImplTest.kt b/id-card-lib/src/androidTest/kotlin/ee/ria/DigiDoc/domain/service/IdCardServiceImplTest.kt
index 7e410ee77..35a7dd0d4 100644
--- a/id-card-lib/src/androidTest/kotlin/ee/ria/DigiDoc/domain/service/IdCardServiceImplTest.kt
+++ b/id-card-lib/src/androidTest/kotlin/ee/ria/DigiDoc/domain/service/IdCardServiceImplTest.kt
@@ -121,7 +121,7 @@ class IdCardServiceImplTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- val configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ val configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {
diff --git a/libdigidoc-lib/src/androidTest/kotlin/ee/ria/DigiDoc/libdigidoclib/SignedContainerTest.kt b/libdigidoc-lib/src/androidTest/kotlin/ee/ria/DigiDoc/libdigidoclib/SignedContainerTest.kt
index 9c0afadb9..5a1fc5d4f 100644
--- a/libdigidoc-lib/src/androidTest/kotlin/ee/ria/DigiDoc/libdigidoclib/SignedContainerTest.kt
+++ b/libdigidoc-lib/src/androidTest/kotlin/ee/ria/DigiDoc/libdigidoclib/SignedContainerTest.kt
@@ -90,7 +90,7 @@ class SignedContainerTest {
ConfigurationPropertiesImpl(),
ConfigurationSignatureVerifierImpl(),
)
- configurationRepository = ConfigurationRepositoryImpl(context, configurationLoader)
+ configurationRepository = ConfigurationRepositoryImpl(configurationLoader)
LibdigidocLibraryLoader().init(context)
Initialization(configurationRepository).init(context)
} catch (_: Exception) {