network: let client override pins for alternative routing proxies
CP-405
This commit is contained in:
parent
067cd068cf
commit
fa4e784000
|
@ -31,31 +31,37 @@ import javax.net.ssl.X509TrustManager
|
|||
*
|
||||
* @param okBuilder builder to introduce pinning to.
|
||||
* @param host host for which pins are added.
|
||||
* @param pins list of pins in okhttp format.
|
||||
* @param pins list of pins (base64, SHA-256). When empty pinning will be disabled (should be used
|
||||
* only for testing).
|
||||
*/
|
||||
internal fun initPinning(okBuilder: OkHttpClient.Builder, host: String, pins: Array<String>) {
|
||||
val pinner = CertificatePinner.Builder()
|
||||
.add("**.$host", *pins)
|
||||
.build()
|
||||
okBuilder.certificatePinner(pinner)
|
||||
if (pins.isNotEmpty()) {
|
||||
val pinner = CertificatePinner.Builder()
|
||||
.add("**.$host", *pins.map { "sha256/$it" }.toTypedArray())
|
||||
.build()
|
||||
okBuilder.certificatePinner(pinner)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inits given okhttp builder with leaf SPKI pinning. Accepts certificate chain iff leaf certificate
|
||||
* SPKI matches one of the [spkiPins].
|
||||
* SPKI matches one of the [pins].
|
||||
*
|
||||
* @param okBuilder builder to introduce pinning to.
|
||||
* @param spkiPins list of sha-256 SPKI hashes.
|
||||
* @param pins list of pins (base64, SHA-256). When empty, pinning will be disabled and default
|
||||
* certificate verification will be used (should be used only for testing).
|
||||
*/
|
||||
internal fun initSPKIleafPinning(builder: OkHttpClient.Builder, spkiPins: List<String>) {
|
||||
val trustManager = LeafSPKIPinningTrustManager(spkiPins)
|
||||
val sslContext = SSLContext.getInstance("TLS")
|
||||
sslContext.init(null, arrayOf(trustManager), null)
|
||||
builder.sslSocketFactory(sslContext.socketFactory, trustManager)
|
||||
builder.hostnameVerifier(HostnameVerifier { _, _ ->
|
||||
// Verification is based solely on SPKI pinning of leaf certificate
|
||||
true
|
||||
})
|
||||
internal fun initSPKIleafPinning(builder: OkHttpClient.Builder, pins: List<String>) {
|
||||
if (pins.isNotEmpty()) {
|
||||
val trustManager = LeafSPKIPinningTrustManager(pins)
|
||||
val sslContext = SSLContext.getInstance("TLS")
|
||||
sslContext.init(null, arrayOf(trustManager), null)
|
||||
builder.sslSocketFactory(sslContext.socketFactory, trustManager)
|
||||
builder.hostnameVerifier(HostnameVerifier { _, _ ->
|
||||
// Verification is based solely on SPKI pinning of leaf certificate
|
||||
true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
internal class LeafSPKIPinningTrustManager(pinnedSPKIHashes: List<String>) : X509TrustManager {
|
||||
|
|
|
@ -20,16 +20,16 @@ package me.proton.core.network.data.di
|
|||
object Constants {
|
||||
|
||||
/**
|
||||
* Certificate pins for Proton API in OkHttp format.
|
||||
* Certificate pins for Proton API (base64, SHA-256).
|
||||
*/
|
||||
val DEFAULT_PINS = arrayOf(
|
||||
"sha256/IEwk65VSaxv3s1/88vF/rM8PauJoIun3rzVCX5mLS3M",
|
||||
"sha256/drtmcR2kFkM8qJClsuWgUzxgBkePfRCkRpqUesyDmeE=",
|
||||
"sha256/YRGlaY0jyJ4Jw2/4M8FIftwbDIQfh8Sdro96CeEel54=",
|
||||
"sha256/AfMENBVvOS8MnISprtvyPsjKlPooqh8nMB/pvCrpJpw=")
|
||||
val DEFAULT_SPKI_PINS = arrayOf(
|
||||
"IEwk65VSaxv3s1/88vF/rM8PauJoIun3rzVCX5mLS3M",
|
||||
"drtmcR2kFkM8qJClsuWgUzxgBkePfRCkRpqUesyDmeE=",
|
||||
"YRGlaY0jyJ4Jw2/4M8FIftwbDIQfh8Sdro96CeEel54=",
|
||||
"AfMENBVvOS8MnISprtvyPsjKlPooqh8nMB/pvCrpJpw=")
|
||||
|
||||
/**
|
||||
* SPKI pins for alternative Proton API leaf certificates (SHA-256).
|
||||
* SPKI pins for alternative Proton API leaf certificates (base64, SHA-256).
|
||||
*/
|
||||
val ALTERNATIVE_API_SPKI_PINS = listOf(
|
||||
"EU6TS9MO0L/GsDHvVc9D5fChYLNy5JdGYpJw0ccgetM=",
|
||||
|
|
|
@ -79,14 +79,16 @@ class ApiFactory(
|
|||
* @param userData [UserData] to be used in the [ApiManager].
|
||||
* @param interfaceClass Kotlin class for [Api] interface.
|
||||
* @param clientErrorHandlers Extra error handlers provided by the client.
|
||||
* @param certificatePins Overrides [Constants.DEFAULT_PINS]
|
||||
* @param certificatePins Overrides [Constants.DEFAULT_SPKI_PINS]
|
||||
* @param alternativeApiPins Overrides [Constants.ALTERNATIVE_API_SPKI_PINS]
|
||||
* @return [ApiManager] instance.
|
||||
*/
|
||||
fun <Api : BaseRetrofitApi> ApiManager(
|
||||
userData: UserData,
|
||||
interfaceClass: KClass<Api>,
|
||||
clientErrorHandlers: List<ApiErrorHandler<Api>> = emptyList(),
|
||||
certificatePins: Array<String> = Constants.DEFAULT_PINS
|
||||
certificatePins: Array<String> = Constants.DEFAULT_SPKI_PINS,
|
||||
alternativeApiPins: List<String> = Constants.ALTERNATIVE_API_SPKI_PINS
|
||||
): ApiManager<Api> {
|
||||
val pinningStrategy = { builder: OkHttpClient.Builder ->
|
||||
initPinning(builder, URI(baseUrl).host, certificatePins)
|
||||
|
@ -107,7 +109,7 @@ class ApiFactory(
|
|||
createBaseErrorHandlers<Api>(userData, ::javaMonoClockMs, mainScope) + clientErrorHandlers
|
||||
|
||||
val alternativePinningStrategy = { builder: OkHttpClient.Builder ->
|
||||
initSPKIleafPinning(builder, Constants.ALTERNATIVE_API_SPKI_PINS)
|
||||
initSPKIleafPinning(builder, alternativeApiPins)
|
||||
}
|
||||
val dohApiHandler = DohApiHandler(apiClient, primaryBackend, dohProvider, prefs, ::javaWallClockMs) { baseUrl ->
|
||||
ProtonApiBackend(
|
||||
|
|
|
@ -76,7 +76,7 @@ class TestTLSHelper {
|
|||
}
|
||||
|
||||
companion object {
|
||||
val TEST_PINS = arrayOf("sha256/d/dc7p/QKB+PnyVi/JOHUQxrZpfGc2LEdq43JGGii4k=")
|
||||
val BAD_PINS = arrayOf("sha256/a/dc7p/QKB+PnyVi/JOHUQxrZpfGc2LEdq43JGGii4k=")
|
||||
val TEST_PINS = arrayOf("d/dc7p/QKB+PnyVi/JOHUQxrZpfGc2LEdq43JGGii4k=")
|
||||
val BAD_PINS = arrayOf("a/dc7p/QKB+PnyVi/JOHUQxrZpfGc2LEdq43JGGii4k=")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue