Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* OID Services, Test Classes and Helper added.

* Testcases modified, Unknown Certificatetype added to validation, overload added for validation.

* Updated tests

* Updated formatting

* Updated tests

* Update

Co-authored-by: Oleksandr Sarapulov <[email protected]>
  • Loading branch information
SchulzeStTSI and oleksandrsarapulovgl authored Jul 1, 2021
1 parent 0aeb3a5 commit e3e8644
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 144 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

package dgca.verifier.app.decoder.cose

import dgca.verifier.app.decoder.model.CertificateType
import dgca.verifier.app.decoder.model.VerificationResult
import java.security.cert.Certificate

Expand All @@ -31,4 +32,5 @@ import java.security.cert.Certificate
interface CryptoService {

fun validate(cose: ByteArray, certificate: Certificate, verificationResult: VerificationResult)
fun validate(cose: ByteArray, certificate: Certificate, verificationResult: VerificationResult, certificateType: CertificateType)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import com.upokecenter.cbor.CBORObject
import dgca.verifier.app.decoder.ECDSA_256
import dgca.verifier.app.decoder.RSA_PSS_256
import dgca.verifier.app.decoder.convertToDer
import dgca.verifier.app.decoder.model.CertificateType
import dgca.verifier.app.decoder.model.VerificationResult
import dgca.verifier.app.decoder.services.X509
import dgca.verifier.app.decoder.verify
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
import org.bouncycastle.jce.provider.BouncyCastleProvider
Expand All @@ -39,13 +41,32 @@ import java.security.spec.RSAPublicKeySpec
/**
* Verifies COSE signature
*/
class VerificationCryptoService : CryptoService {
class VerificationCryptoService(private val x509: X509) : CryptoService {

init {
Security.addProvider(BouncyCastleProvider()) // for SHA256withRSA/PSS
}

override fun validate(cose: ByteArray, certificate: Certificate, verificationResult: VerificationResult) {
override fun validate(
cose: ByteArray,
certificate: Certificate,
verificationResult: VerificationResult,
certificateType: CertificateType
) {
validate(cose, certificate, verificationResult)

verificationResult.coseVerified =
verificationResult.coseVerified && (certificateType == CertificateType.UNKNOWN || x509.isSuitable(
certificate.encoded,
certificateType
))
}

override fun validate(
cose: ByteArray,
certificate: Certificate,
verificationResult: VerificationResult
) {
val verificationKey = certificate.publicKey
verificationResult.coseVerified = try {
val messageObject = CBORObject.DecodeFromBytes(cose)
Expand All @@ -66,7 +87,8 @@ class VerificationCryptoService : CryptoService {
)
}
RSA_PSS_256 -> {
val bytes = SubjectPublicKeyInfo.getInstance(certificate.publicKey.encoded).publicKeyData.bytes
val bytes =
SubjectPublicKeyInfo.getInstance(certificate.publicKey.encoded).publicKeyData.bytes
val rsaPublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(bytes)
val spec = RSAPublicKeySpec(rsaPublicKey.modulus, rsaPublicKey.publicExponent)
val key = KeyFactory.getInstance("RSA").generatePublic(spec)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package dgca.verifier.app.decoder.model

enum class CertificateType {
UNKNOWN,VACCINATION,RECOVERY,TEST
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,12 @@ data class GreenCertificate(
} catch (ex: Exception) {
""
}.toLowerCase(Locale.ROOT)
}

fun getType(): CertificateType {
if (vaccinations?.isNotEmpty() == true)
return CertificateType.VACCINATION
if (tests?.isNotEmpty() == true) return CertificateType.TEST
if (recoveryStatements?.isNotEmpty() == true) return CertificateType.RECOVERY
return CertificateType.UNKNOWN
}
}
61 changes: 61 additions & 0 deletions decoder/src/main/java/dgca/verifier/app/decoder/services/X509.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package dgca.verifier.app.decoder.services

import dgca.verifier.app.decoder.model.CertificateType
import java.io.ByteArrayInputStream
import java.security.cert.*


class X509 {
private val OID_TEST = "1.3.6.1.4.1.1847.2021.1.1"
private val OID_ALT_TEST = "1.3.6.1.4.1.0.1847.2021.1.1"
private val OID_VACCINATION = "1.3.6.1.4.1.1847.2021.1.2"
private val OID_ALT_VACCINATION = "1.3.6.1.4.1.0.1847.2021.1.2"
private val OID_RECOVERY = "1.3.6.1.4.1.1847.2021.1.3"
private val OID_ALT_RECOVERY = "1.3.6.1.4.1.0.1847.2021.1.3"

fun checkIsSuitable(cert: String?, certType: CertificateType?): Boolean {
val b64: ByteArray = org.bouncycastle.util.encoders.Base64.decode(cert)
return isSuitable(b64, certType)
}

fun isSuitable(data: ByteArray?, certificateType: CertificateType?): Boolean {
try {
val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
val cert: Certificate = cf.generateCertificate(ByteArrayInputStream(data))
if (isType(cert as X509Certificate)) {
val extendedKeys = cert.extendedKeyUsage
return when (certificateType) {
CertificateType.TEST -> extendedKeys.contains(OID_TEST) || extendedKeys.contains(
OID_ALT_TEST
)
CertificateType.VACCINATION -> extendedKeys.contains(OID_VACCINATION) || extendedKeys.contains(
OID_ALT_VACCINATION
)
CertificateType.RECOVERY -> extendedKeys.contains(OID_RECOVERY) || extendedKeys.contains(
OID_ALT_RECOVERY
)
CertificateType.UNKNOWN -> false
else -> false
}
}
} catch (e: CertificateException) {
return false
}
return true
}

private fun isType(certificate: X509Certificate): Boolean {
return try {
val extendedKeyUsage: List<String> = certificate.extendedKeyUsage ?: return false

extendedKeyUsage.contains(OID_TEST)
|| extendedKeyUsage.contains(OID_ALT_TEST)
|| extendedKeyUsage.contains(OID_RECOVERY)
|| extendedKeyUsage.contains(OID_ALT_RECOVERY)
|| extendedKeyUsage.contains(OID_VACCINATION)
|| extendedKeyUsage.contains(OID_ALT_VACCINATION)
} catch (e: CertificateParsingException) {
false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import dgca.verifier.app.decoder.prefixvalidation.DefaultPrefixValidationService
import dgca.verifier.app.decoder.prefixvalidation.PrefixValidationService
import dgca.verifier.app.decoder.schema.DefaultSchemaValidator
import dgca.verifier.app.decoder.schema.SchemaValidator
import dgca.verifier.app.decoder.services.X509
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.CoreMatchers.notNullValue
import org.hamcrest.CoreMatchers.nullValue
Expand Down Expand Up @@ -45,7 +46,7 @@ class CertificateTestRunner {
prefixValidationService = DefaultPrefixValidationService()
base45Service = DefaultBase45Service()
compressorService = DefaultCompressorService()
cryptoService = VerificationCryptoService()
cryptoService = VerificationCryptoService(X509())
coseService = DefaultCoseService()
schemaValidator = DefaultSchemaValidator()
cborService = DefaultCborService()
Expand Down
139 changes: 0 additions & 139 deletions decoder/src/test/java/dgca/verifier/app/decoder/QrCodeTests.java

This file was deleted.

Loading

0 comments on commit e3e8644

Please sign in to comment.