Don't crash on certificates without subject alternative names

This commit is contained in:
cketti 2024-01-15 22:01:35 +01:00
parent 28892810f4
commit 213c8c7d11
3 changed files with 49 additions and 6 deletions

View file

@ -23,7 +23,7 @@ class FormatServerCertificateError(
val notValidBeforeInstant = Instant.fromEpochMilliseconds(certificate.notBefore.time)
val notValidAfterInstant = Instant.fromEpochMilliseconds(certificate.notAfter.time)
val subjectAlternativeNames = certificate.subjectAlternativeNames.map { it[1].toString() }
val subjectAlternativeNames = certificate.subjectAlternativeNames.orEmpty().map { it[1].toString() }
val notValidBefore = dateFormat.format(Date(notValidBeforeInstant.toEpochMilliseconds()))
val notValidAfter = dateFormat.format(Date(notValidAfterInstant.toEpochMilliseconds()))

View file

@ -39,12 +39,14 @@ internal fun ServerCertificateView(
TextHeadline6(stringResource(R.string.account_server_certificate_section_title))
Spacer(modifier = Modifier.height(MainTheme.spacings.double))
TextSubtitle2(stringResource(R.string.account_server_certificate_subject_alternative_names))
for (subjectAlternativeName in serverCertificateProperties.subjectAlternativeNames) {
BulletedListItem(serverNameFormatter.format(subjectAlternativeName))
}
if (serverCertificateProperties.subjectAlternativeNames.isNotEmpty()) {
TextSubtitle2(stringResource(R.string.account_server_certificate_subject_alternative_names))
for (subjectAlternativeName in serverCertificateProperties.subjectAlternativeNames) {
BulletedListItem(serverNameFormatter.format(subjectAlternativeName))
}
Spacer(modifier = Modifier.height(MainTheme.spacings.double))
Spacer(modifier = Modifier.height(MainTheme.spacings.double))
}
TextSubtitle2(stringResource(R.string.account_server_certificate_not_valid_before))
TextBody1(text = serverCertificateProperties.notValidBefore)

View file

@ -3,6 +3,7 @@ package app.k9mail.feature.account.server.certificate.domain.usecase
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateError
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateProperties
import assertk.assertThat
import assertk.assertions.isEmpty
import assertk.assertions.isEqualTo
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
@ -51,6 +52,22 @@ class FormatServerCertificateErrorTest {
)
}
@Test
fun `format certificate without subject alternative names`() {
val formatCertificateError = FormatServerCertificateError(
dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT, Locale.ROOT),
)
val serverCertificateError = ServerCertificateError(
hostname = "10.0.0.1",
port = 993,
certificateChain = listOf(readCertificate(CERTIFICATE_WITHOUT_SAN)),
)
val result = formatCertificateError(serverCertificateError)
assertThat(result.serverCertificateProperties.subjectAlternativeNames).isEmpty()
}
private fun readCertificate(asciiArmoredCertificate: String): X509Certificate {
val inputStream = asciiArmoredCertificate.byteInputStream()
@ -92,5 +109,29 @@ class FormatServerCertificateErrorTest {
RwxPuzZEaFZcVlmtqoq8
-----END CERTIFICATE-----
""".trimIndent()
val CERTIFICATE_WITHOUT_SAN = """
-----BEGIN CERTIFICATE-----
MIIDfDCCAmSgAwIBAgIJAJB2iRjpM5OgMA0GCSqGSIb3DQEBCwUAME4xMTAvBgNV
BAsMKE5vIFNOSSBwcm92aWRlZDsgcGxlYXNlIGZpeCB5b3VyIGNsaWVudC4xGTAX
BgNVBAMTEGludmFsaWQyLmludmFsaWQwHhcNMTUwMTAxMDAwMDAwWhcNMzAwMTAx
MDAwMDAwWjBOMTEwLwYDVQQLDChObyBTTkkgcHJvdmlkZWQ7IHBsZWFzZSBmaXgg
eW91ciBjbGllbnQuMRkwFwYDVQQDExBpbnZhbGlkMi5pbnZhbGlkMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzWJP5cMThJgMBeTvRKKl7N6ZcZAbKDVA
tNBNnRhIgSitXxCzKtt9rp2RHkLn76oZjdNO25EPp+QgMiWU/rkkB00Y18Oahw5f
i8s+K9dRv6i+gSOiv2jlIeW/S0hOswUUDH0JXFkEPKILzpl5ML7wdp5kt93vHxa7
HswOtAxEz2WtxMdezm/3CgO3sls20wl3W03iI+kCt7HyvhGy2aRPLhJfeABpQr0U
ku3q6mtomy2cgFawekN/X/aH8KknX799MPcuWutM2q88mtUEBsuZmy2nsjK9J7/y
hhCRDzOV/yY8c5+l/u/rWuwwkZ2lgzGp4xBBfhXdr6+m9kmwWCUm9QIDAQABo10w
WzAOBgNVHQ8BAf8EBAMCAqQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEELsPOJZvPr5PK0bQQWrUrLUwDQYJ
KoZIhvcNAQELBQADggEBALnZ4lRc9WHtafO4Y+0DWp4qgSdaGygzS/wtcRP+S2V+
HFOCeYDmeZ9qs0WpNlrtyeBKzBH8hOt9y8aUbZBw2M1F2Mi23Q+dhAEUfQCOKbIT
tunBuVfDTTbAHUuNl/eyr78v8Egi133z7zVgydVG1KA0AOSCB+B65glbpx+xMCpg
ZLux9THydwg3tPo/LfYbRCof+Mb8I3ZCY9O6FfZGjuxJn+0ux3SDora3NX/FmJ+i
kTCTsMtIFWhH3hoyYAamOOuITpPZHD7yP0lfbuncGDEqAQu2YWbYxRixfq2VSxgv
gWbFcmkgBLYpE8iDWT3Kdluo1+6PHaDaLg2SacOY6Go=
-----END CERTIFICATE-----
""".trimIndent()
}
}