Update vdstools to latest version

And migrate the code to use the public API only.

This version doesn't include the Kermit logging library
which would have required a minSdk raise.
This commit is contained in:
Markus Fisch
2026-04-09 10:58:34 +02:00
parent d740aa121b
commit de00ed779a
5 changed files with 33 additions and 45 deletions
+1 -1
View File
@@ -83,7 +83,7 @@ dependencies {
implementation 'androidx.camera:camera-view:1.4.2'
implementation 'com.github.markusfisch:ScalingImageView:1.4.3'
implementation 'com.github.markusfisch:zxing-cpp:v3.0.2.3'
implementation 'de.tsenger:vdstools:0.14.0'
implementation 'de.tsenger:vdstools:0.16.0-SNAPSHOT'
implementation 'org.bouncycastle:bcpkix-jdk15to18:1.83'
// Testing
@@ -17,10 +17,7 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.Provider
import java.security.Security
import java.security.cert.X509Certificate
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.TimeZone
object IdbVerifier {
private const val MASTER_LIST_ASSET = "DE_ML_2026-01-08-12-20-54.ml"
@@ -44,32 +41,25 @@ object IdbVerifier {
context.getString(R.string.idb_verification_unsigned)
)
)
val headerCertificateReference = seal.payLoad.idbHeader.certificateReference
val embeddedSignerCertificate = seal.payLoad.idbSignerCertificate
?.certBytes
?.let {
parseCertificate(it)
}
if (seal.payLoad.idbSignerCertificate != null && embeddedSignerCertificate == null) {
return listOf(
SealField(
R.string.idb_verification,
context.getString(
R.string.idb_verification_invalid_signer_certificate
)
)
)
}
val signerCertificate = embeddedSignerCertificate
?: context.findCertificateByReference(headerCertificateReference)
val headerCertificateReference = seal.signerCertReference
?.hexToByteArrayOrNull()
val signerCertificate = context.findCertificateByReference(
headerCertificateReference
)
val curveName = signerCertificate?.let {
curveNameFrom(it)
}
val signatureResult = if (signerCertificate == null || curveName.isNullOrBlank()) {
val signedBytes = seal.signedBytes
val signatureResult = if (
signerCertificate == null ||
curveName.isNullOrBlank() ||
signedBytes == null
) {
Verifier.Result.VerifyError
} else {
Verifier(
seal,
signedBytes,
signatureInfo.plainSignatureBytes,
signerCertificate.publicKey.encoded,
curveName
).verify()
@@ -113,9 +103,7 @@ object IdbVerifier {
),
SealField(
R.string.vds_signing_date,
parseSigningDate(
signatureInfo.signingDate.toString()
).toString()
signatureInfo.signingDate.toString()
),
SealField(
R.string.idb_signature_verification,
@@ -139,12 +127,14 @@ object IdbVerifier {
return fields
}
private fun parseSigningDate(value: String): Date? {
private fun String.hexToByteArrayOrNull(): ByteArray? {
if (length % 2 != 0) {
return null
}
return runCatching {
SimpleDateFormat("yyyy-MM-dd", Locale.US).apply {
isLenient = false
timeZone = TimeZone.getTimeZone("UTC")
}.parse(value)
ByteArray(length / 2) { index ->
substring(index * 2, index * 2 + 2).toInt(16).toByte()
}
}.getOrNull()
}
@@ -172,14 +162,6 @@ object IdbVerifier {
}
}
private fun parseCertificate(certificateBytes: ByteArray): X509Certificate? {
return runCatching {
JcaX509CertificateConverter()
.setProvider(provider)
.getCertificate(X509CertificateHolder(certificateBytes))
}.getOrNull()
}
private fun Context.findCertificateByReference(
certificateReference: ByteArray?
): X509Certificate? {
@@ -109,8 +109,9 @@ object IdlParser {
// Detect this by checking that the marker matches the key prefix
// (jurisdiction fields always share their 2-char subfile prefix).
val seg = if (skipSubtype && p - start >= 4 &&
data[start] == data[start + 2] &&
data[start + 1] == data[start + 3]) {
data[start] == data[start + 2] &&
data[start + 1] == data[start + 3]
) {
start + 2
} else {
start
@@ -2,7 +2,7 @@ package de.markusfisch.android.binaryeye.content
import android.content.Context
import de.markusfisch.android.binaryeye.R
import de.tsenger.vdstools.DataEncoder
import de.tsenger.vdstools.asn1.DerTlv
import de.tsenger.vdstools.generic.Message
import de.tsenger.vdstools.generic.MessageCoding
import de.tsenger.vdstools.generic.MessageValue
@@ -10,6 +10,7 @@ import de.tsenger.vdstools.generic.Seal
import de.tsenger.vdstools.idb.IdbSeal
import org.json.JSONArray
import org.json.JSONObject
import de.tsenger.vdstools.generic.SealParser as VdsSealParser
data class SealField(val name: Any, val value: String)
private data class IdbChildMessageDefinition(
@@ -27,7 +28,7 @@ object SealParser {
bytes: ByteArray
): List<SealField>? = try {
context.buildFields(
Seal.fromString(bytes.toString(Charsets.ISO_8859_1))
VdsSealParser().parse(bytes.toString(Charsets.ISO_8859_1))
)
} catch (_: Exception) {
null
@@ -66,7 +67,7 @@ object SealParser {
private fun Message.childMessages(): List<Message> {
val childDefinitionsByTag = idbChildMessagesByName[name] ?: return emptyList()
return runCatching {
DataEncoder.parseDerTLvs(value.rawBytes).mapNotNull { derTlv ->
DerTlv.parseAll(value.rawBytes).mapNotNull { derTlv ->
val childTag = derTlv.tag.toInt() and 0xff
val childDefinition = childDefinitionsByTag[childTag]
?: return@mapNotNull null
+4
View File
@@ -10,6 +10,10 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
name = 'Central Portal Snapshots'
url = uri('https://central.sonatype.com/repository/maven-snapshots/')
}
maven { url 'https://jitpack.io' }
}
}