Skip to content

feat: add certificate fetching utility with Android 7.0+ TLS 1.2 support#5745

Open
iamobin wants to merge 2 commits into
2dust:masterfrom
iamobin:fetch-certificate-fingerprint
Open

feat: add certificate fetching utility with Android 7.0+ TLS 1.2 support#5745
iamobin wants to merge 2 commits into
2dust:masterfrom
iamobin:fetch-certificate-fingerprint

Conversation

@iamobin
Copy link
Copy Markdown

@iamobin iamobin commented Jun 6, 2026

Add CertificateFetcher utility to fetch SSL/TLS certificates from remote servers and generate SHA-256 fingerprints for certificate pinning.

Key features:

  • Fetch certificate chains from domains with optional port specification
  • Generate SHA-256 fingerprints for certificate pinning
  • Support custom SNI (Server Name Indication) configuration
  • Optional insecure mode for testing/development
  • Proper TLS 1.2+ support on Android 7.0-7.1 via Conscrypt
  • Material3 button integration in TLS configuration UI

Technical implementation:

  • Uses OkHttp with Conscrypt security provider for modern TLS support
  • Implements custom X509TrustManager to capture certificates during handshake
  • Supports TLS 1.2 and 1.3 with appropriate connection specs
  • Coroutine-based async execution on IO dispatcher

Dependencies added:

  • org.conscrypt:conscrypt-android:2.5.2

Add CertificateFetcher utility to fetch SSL/TLS certificates from remote
servers and generate SHA-256 fingerprints for certificate pinning.

Key features:
- Fetch certificate chains from domains with optional port specification
- Generate SHA-256 fingerprints for certificate pinning
- Support custom SNI (Server Name Indication) configuration
- Optional insecure mode for testing/development
- Proper TLS 1.2+ support on Android 7.0-7.1 via Conscrypt
- Material3 button integration in TLS configuration UI

Technical implementation:
- Uses OkHttp with Conscrypt security provider for modern TLS support
- Implements custom X509TrustManager to capture certificates during handshake
- Supports TLS 1.2 and 1.3 with appropriate connection specs
- Coroutine-based async execution on IO dispatcher

Dependencies added:
- org.conscrypt:conscrypt-android:2.5.2
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a certificate-fetching utility and UI integration to help users obtain SHA-256 certificate fingerprints for TLS pinning, including adding Conscrypt to improve TLS 1.2+ support on Android 7.0–7.1.

Changes:

  • Added CertificateFetcher utility to fetch server certificate chains and compute SHA-256 fingerprints.
  • Integrated a “Fetch Certificate” button into TLS configuration UI and wired it in ServerActivity.
  • Added Conscrypt dependency via version catalog + app Gradle deps.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
V2rayNG/gradle/libs.versions.toml Adds Conscrypt version + library coordinates to the version catalog.
V2rayNG/app/build.gradle.kts Includes Conscrypt dependency in the app module.
V2rayNG/app/src/main/res/values/strings.xml Adds UI strings for certificate fetch flow (loading/success/error).
V2rayNG/app/src/main/res/layout/layout_tls.xml Adds a Material3 “Fetch” button next to the pinned cert fingerprint input.
V2rayNG/app/src/main/res/layout/layout_tls_hysteria2.xml Adds the same “Fetch” button for Hysteria2 TLS layout.
V2rayNG/app/src/main/java/com/v2ray/ang/util/CertificateFetcher.kt New utility for fetching certificate chains and generating SHA-256 fingerprints.
V2rayNG/app/src/main/java/com/v2ray/ang/ui/ServerActivity.kt Wires the button to fetch fingerprints and populate the pinned fingerprint field.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +113 to +115
val defaultTrustManager = runCatching { createDefaultTrustManager() }.getOrNull()

return object : X509TrustManager {
Comment thread V2rayNG/app/src/main/java/com/v2ray/ang/util/CertificateFetcher.kt Outdated
Comment on lines +100 to +107
private fun parseDomainAndPort(domain: String): Pair<String, Int> {
val parts = domain.split(":", limit = 2)
return if (parts.size == 2) {
Pair(parts[0], parts[1].toIntOrNull() ?: 443)
} else {
Pair(domain, 443)
}
}
Comment on lines +58 to +67
runCatching {
client.newCall(request).execute().close()
}.onFailure { exception ->
if (exception is javax.net.ssl.SSLHandshakeException && capturedCertificates.isNullOrEmpty()) {
return@withContext CertificateResult(
fingerprints = emptyList(),
error = "SSL handshake failed: ${exception.message}"
)
}
}
Comment on lines +386 to +391
val port = et_port.text.toString().trim()
val domain = if (port.isNotEmpty() && Utils.parseInt(port) > 0) {
"$address:$port"
} else {
address
}
Comment on lines +154 to +160
return OkHttpClient.Builder()
.sslSocketFactory(sslContext.socketFactory, trustManager)
.connectionSpecs(listOf(connectionSpec, ConnectionSpec.COMPATIBLE_TLS))
.hostnameVerifier { hostname, _ -> hostname == sni || hostname == host }
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build()
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@2dust
Copy link
Copy Markdown
Owner

2dust commented Jun 7, 2026

感谢 PR
有几个问题需要处理:

  1. fetchCertificateFingerprints 函数改成下面的更合适,下面的函数不需要处理 domain 的合并和拆分,ipv6 不会有问题。
suspend fun fetchCertificateFingerprints(
    host: String,
    port: Int = 443,
    serverName: String? = null,
    allowInsecure: Boolean = false
): CertificateResult
  1. 不需要引入 org.conscrypt:conscrypt-android, 直接把 sdk=24和25设置为不支持,因为这两个设备很少,不值得。
  2. 其他 AI 发现的小问题

@2dust
Copy link
Copy Markdown
Owner

2dust commented Jun 7, 2026

AI 有些分析的不对的可以不用处理,处理下你觉得合理的

@iamobin
Copy link
Copy Markdown
Author

iamobin commented Jun 8, 2026

感谢 PR 有几个问题需要处理:

  1. fetchCertificateFingerprints 函数改成下面的更合适,下面的函数不需要处理 domain 的合并和拆分,ipv6 不会有问题。
suspend fun fetchCertificateFingerprints(
    host: String,
    port: Int = 443,
    serverName: String? = null,
    allowInsecure: Boolean = false
): CertificateResult
  1. 不需要引入 org.conscrypt:conscrypt-android, 直接把 sdk=24和25设置为不支持,因为这两个设备很少,不值得。
  2. 其他 AI 发现的小问题

I did some testing and research on this.

If we want to remove Conscrypt, we should drop support for SDK 24–28 and only support API 29+.

On Android 10 (API 29) and above, TLS 1.3 is available natively without needing Conscrypt, and everything works as expected in my tests.

But on API 24–28, removing Conscrypt causes compatibility issues, so keeping it is still required for those versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants