From e4ad73eef8db436df0122a4d742d62c2ea9a346f Mon Sep 17 00:00:00 2001 From: oleksandrsarapulovgl <82441124+oleksandrsarapulovgl@users.noreply.github.com> Date: Mon, 14 Feb 2022 11:41:50 +0200 Subject: [PATCH] Certificate revocation (#73) --- decoder/build.gradle | 2 +- .../dgca/verifier/app/decoder/Extensions.kt | 85 +++++++++++++++---- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/decoder/build.gradle b/decoder/build.gradle index c4f55f0..638ee9e 100644 --- a/decoder/build.gradle +++ b/decoder/build.gradle @@ -7,7 +7,7 @@ android { compileSdkVersion 30 defaultConfig { - minSdkVersion 21 + minSdkVersion 23 targetSdkVersion 30 versionCode 1 versionName "1.0.0" diff --git a/decoder/src/main/java/dgca/verifier/app/decoder/Extensions.kt b/decoder/src/main/java/dgca/verifier/app/decoder/Extensions.kt index a6bc187..c7962a5 100644 --- a/decoder/src/main/java/dgca/verifier/app/decoder/Extensions.kt +++ b/decoder/src/main/java/dgca/verifier/app/decoder/Extensions.kt @@ -22,18 +22,24 @@ package dgca.verifier.app.decoder +import android.security.keystore.KeyGenParameterSpec +import android.security.keystore.KeyProperties import android.util.Base64 import com.upokecenter.cbor.CBORObject import dgca.verifier.app.decoder.model.KeyPairData import java.io.ByteArrayInputStream -import java.security.KeyPairGenerator -import java.security.MessageDigest +import java.security.* import java.security.cert.CertificateFactory import java.security.cert.X509Certificate +import java.security.spec.ECGenParameterSpec const val ECDSA_256 = -7 const val RSA_PSS_256 = -37 +const val ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore" +const val SHA_256_WITH_ECDSA = "SHA256withECDSA" +const val SHA_256_WITH_RSA = "SHA256WithRSA" + fun ByteArray.toBase64(): String = Base64.encodeToString(this, Base64.NO_WRAP) fun ByteArray.toHexString(): String = joinToString("") { "%02x".format(it) } @@ -44,6 +50,8 @@ fun String.hexToByteArray(): ByteArray = chunked(2) fun String.fromBase64(): ByteArray = Base64.decode(this, Base64.NO_WRAP) +fun String.toBase64(): String = Base64.encodeToString(this.toByteArray(), Base64.NO_WRAP) + fun String.base64ToX509Certificate(): X509Certificate? { val decoded = Base64.decode(this, Base64.NO_WRAP) val inputStream = ByteArrayInputStream(decoded) @@ -57,23 +65,68 @@ fun ByteArray.toHash(): String { .toBase64() } -fun ByteArray.generateKeyPair(): KeyPairData? { +private fun provideEcKeyPairData(alias: String): KeyPairData { + val keyPairGen = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, ANDROID_KEYSTORE_PROVIDER) + val keyPairGeneratorSpec = KeyGenParameterSpec.Builder( + alias, + KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY + ) + .setAlgorithmParameterSpec(ECGenParameterSpec("secp256r1")) + .setDigests( + KeyProperties.DIGEST_SHA256, + KeyProperties.DIGEST_SHA384, + KeyProperties.DIGEST_SHA512 + ) + .setKeySize(256) + .build() + keyPairGen.initialize(keyPairGeneratorSpec) + return KeyPairData(SHA_256_WITH_ECDSA, keyPairGen.generateKeyPair()) +} + +private fun provideRsaKeyPairData(alias: String): KeyPairData { + val keyPairGen = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE_PROVIDER) + val keyGenParameterSpec = KeyGenParameterSpec.Builder( + alias, + KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY + ) + .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) + .setKeySize(2048) + .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) + .build() + + keyPairGen.initialize(keyGenParameterSpec) + return KeyPairData(SHA_256_WITH_RSA, keyPairGen.generateKeyPair()) +} + +fun ByteArray.generateKeyPairFor(alias: String): KeyPairData? { val messageObject = CBORObject.DecodeFromBytes(this) val protectedHeader = messageObject[0].GetByteString() // get algorithm from header - when (CBORObject.DecodeFromBytes(protectedHeader).get(1).AsInt32Value()) { - ECDSA_256 -> { - val keyPairGen = KeyPairGenerator.getInstance("EC") - keyPairGen.initialize(256) - return KeyPairData("SHA256withECDSA", keyPairGen.generateKeyPair()) - } - RSA_PSS_256 -> { - val keyPairGen = KeyPairGenerator.getInstance("RSA") - keyPairGen.initialize(2048) - return KeyPairData("SHA256WithRSA", keyPairGen.generateKeyPair()) - } + return when (CBORObject.DecodeFromBytes(protectedHeader).get(1).AsInt32Value()) { + ECDSA_256 -> provideEcKeyPairData(alias) + RSA_PSS_256 -> provideRsaKeyPairData(alias) + else -> null + } +} + +fun getKeyPairFor(alias: String): KeyPairData { + val ks: KeyStore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER) + ks.load(null) + val entry: KeyStore.Entry = ks.getEntry(alias, null) + val privateKey: PrivateKey = (entry as KeyStore.PrivateKeyEntry).privateKey + val publicKey: PublicKey = ks.getCertificate(alias).publicKey + val keyPair = KeyPair(publicKey, privateKey) + val algo = when (privateKey.algorithm) { + KeyProperties.KEY_ALGORITHM_EC -> SHA_256_WITH_ECDSA + KeyProperties.KEY_ALGORITHM_RSA -> SHA_256_WITH_RSA + else -> throw IllegalArgumentException() } + return KeyPairData(algo, keyPair) +} - return null -} \ No newline at end of file +fun deleteKeyPairFor(alias: String) { + val ks: KeyStore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER) + ks.load(null) + ks.deleteEntry(alias) +}