forked from gotify/android
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCertUtils.kt
More file actions
127 lines (115 loc) · 5.04 KB
/
Copy pathCertUtils.kt
File metadata and controls
127 lines (115 loc) · 5.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package com.github.gotify.api
import android.annotation.SuppressLint
import com.github.gotify.SSLSettings
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
import java.security.GeneralSecurityException
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.Certificate
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import javax.net.ssl.KeyManager
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
import okhttp3.OkHttpClient
import org.tinylog.kotlin.Logger
internal object CertUtils {
const val CA_CERT_NAME = "ca-cert.crt"
const val CLIENT_CERT_NAME = "client-cert.p12"
@SuppressLint("CustomX509TrustManager")
private val trustAll = object : X509TrustManager {
@SuppressLint("TrustAllX509TrustManager")
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
}
@SuppressLint("TrustAllX509TrustManager")
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
}
override fun getAcceptedIssuers() = arrayOf<X509Certificate>()
}
fun parseCertificate(inputStream: InputStream): Certificate {
try {
val certificateFactory = CertificateFactory.getInstance("X509")
return certificateFactory.generateCertificate(inputStream)
} catch (e: Exception) {
throw IllegalArgumentException("certificate is invalid")
}
}
fun applySslSettings(builder: OkHttpClient.Builder, settings: SSLSettings) {
// Modified from ApiClient.applySslSettings in the client package.
try {
val trustManagers = mutableSetOf<TrustManager>()
val keyManagers = mutableSetOf<KeyManager>()
if (settings.validateSSL) {
// Custom SSL validation
settings.caCertPath?.let { trustManagers.addAll(certToTrustManager(it)) }
} else {
// Disable SSL validation
trustManagers.add(trustAll)
builder.hostnameVerifier { _, _ -> true }
}
settings.clientCertPath?.let {
keyManagers.addAll(certToKeyManager(it, settings.clientCertPassword))
}
if (trustManagers.isNotEmpty() || keyManagers.isNotEmpty()) {
if (trustManagers.isEmpty()) {
// Fall back to system trust managers
trustManagers.addAll(defaultSystemTrustManager())
}
val context = SSLContext.getInstance("TLS")
context.init(
keyManagers.toTypedArray(),
trustManagers.toTypedArray(),
SecureRandom()
)
builder.sslSocketFactory(
context.socketFactory,
trustManagers.elementAt(0) as X509TrustManager
)
}
} catch (e: Exception) {
// We shouldn't have issues since the cert is verified on login.
Logger.error(e, "Failed to apply SSL settings")
}
}
@Throws(GeneralSecurityException::class)
private fun certToTrustManager(certPath: String): Array<TrustManager> {
val certificateFactory = CertificateFactory.getInstance("X.509")
val certificates = FileInputStream(File(certPath)).use(
certificateFactory::generateCertificates
)
require(certificates.isNotEmpty()) { "expected non-empty set of trusted certificates" }
val caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply { load(null) }
certificates.forEachIndexed { index, certificate ->
val certificateAlias = "ca$index"
caKeyStore.setCertificateEntry(certificateAlias, certificate)
}
val trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(caKeyStore)
return trustManagerFactory.trustManagers
}
@Throws(GeneralSecurityException::class)
private fun certToKeyManager(certPath: String, certPassword: String?): Array<KeyManager> {
require(certPassword != null) { "empty client certificate password" }
val keyStore = KeyStore.getInstance("PKCS12")
FileInputStream(File(certPath)).use {
keyStore.load(it, certPassword.toCharArray())
}
val keyManagerFactory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
keyManagerFactory.init(keyStore, certPassword.toCharArray())
return keyManagerFactory.keyManagers
}
private fun defaultSystemTrustManager(): Array<TrustManager> {
val trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm()
)
trustManagerFactory.init(null as KeyStore?)
return trustManagerFactory.trustManagers
}
}