From ed639261d99f7060842a805c02560e2c52ddd189 Mon Sep 17 00:00:00 2001
From: Matthias Urhahn <matthias.urhahn@sap.com>
Date: Wed, 9 Jun 2021 11:21:54 +0200
Subject: [PATCH] Refactor DigitalCovidCertificate JSON/UI interfaces. (#3384)

Rename and move classes/interfaces related to qrcode (json) and interfaces used for our UIs.
Next features will require us to group multiple certificates, if they share common interfaces, it will be easier to work with.
---
 .../vaccination/CertificateQrCodeCensor.kt    | 19 +++---
 .../CertificatePersonIdentifier.kt            | 26 +-------
 .../common/certificate/CwaCovidCertificate.kt | 29 +++++++++
 .../common/certificate/Dcc.kt                 | 50 +++++++++++++++
 .../common/certificate/DccData.kt             |  6 ++
 .../common/certificate/DccHeader.kt           |  9 +++
 .../decoder/DccCoseDecoder.kt}                |  4 +-
 .../decoder/DccHeaderParser.kt}               |  9 +--
 .../common/decoder/RawCOSEObject.kt           |  3 +
 .../common/qrcode/DccQrCode.kt                | 16 +++++
 .../common/qrcode/QrCodeString.kt             |  3 +
 .../test/core/TestCertificate.kt              | 22 +------
 .../core/certificate/TestCertificateData.kt   |  8 ---
 ...rtificateDccParser.kt => TestDccParser.kt} | 14 ++---
 .../{TestCertificateDccV1.kt => TestDccV1.kt} | 33 ++++------
 .../test/core/qrcode/TestCertificateQRCode.kt | 11 ++--
 .../qrcode/TestCertificateQRCodeExtractor.kt  | 29 ++++-----
 .../core/storage/TestCertificateContainer.kt  | 26 ++++----
 .../vaccination/core/VaccinatedPerson.kt      |  2 +-
 .../core/VaccinationCertificate.kt            | 23 +------
 .../core/certificate/CoseCertificateHeader.kt |  9 ---
 .../certificate/HealthCertificateHeader.kt    |  9 ---
 .../core/certificate/RawCOSEObject.kt         |  3 -
 ...accinationDGCV1.kt => VaccinationDccV1.kt} | 32 ++++------
 ...CV1Parser.kt => VaccinationDccV1Parser.kt} | 14 ++---
 .../core/qrcode/VaccinationCertificateData.kt | 12 ----
 .../qrcode/VaccinationCertificateQRCode.kt    | 16 ++---
 .../core/qrcode/VaccinationQRCodeExtractor.kt | 24 ++++----
 .../core/repository/VaccinationRepository.kt  |  3 +-
 .../storage/VaccinatedPersonData.kt           |  2 +-
 .../storage/VaccinationContainer.kt           | 46 ++++++--------
 .../ui/details/VaccinationDetailsViewModel.kt |  4 +-
 .../ui/list/VaccinationListViewModel.kt       |  4 +-
 .../CertificateQrCodeCensorTest.kt            | 19 +++---
 .../common/CertificatePersonIdentifierTest.kt |  1 +
 .../execution/TestCertificateProcessorTest.kt |  2 +-
 .../test/TestCertificateRepositoryTest.kt     |  2 +-
 .../qrcode/TestCertificateDccParserTest.kt    |  8 +--
 .../TestCertificateQRCodeExtractorTest.kt     | 28 ++++-----
 .../vaccination/core/VaccinationTestData.kt   | 61 ++++++++++---------
 .../qrcode/VaccinationQRCodeExtractorTest.kt  |  8 +--
 .../storage/VaccinationContainerTest.kt       |  2 +-
 42 files changed, 327 insertions(+), 324 deletions(-)
 rename Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/{ => certificate}/CertificatePersonIdentifier.kt (61%)
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/Dcc.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccData.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccHeader.kt
 rename Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/{vaccination/core/certificate/HealthCertificateCOSEDecoder.kt => common/decoder/DccCoseDecoder.kt} (94%)
 rename Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/{vaccination/core/certificate/HealthCertificateHeaderParser.kt => common/decoder/DccHeaderParser.kt} (86%)
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/RawCOSEObject.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/DccQrCode.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/QrCodeString.kt
 delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestCertificateData.kt
 rename Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/{TestCertificateDccParser.kt => TestDccParser.kt} (86%)
 rename Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/{TestCertificateDccV1.kt => TestDccV1.kt} (63%)
 delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/CoseCertificateHeader.kt
 delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/HealthCertificateHeader.kt
 delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/RawCOSEObject.kt
 rename Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/{VaccinationDGCV1.kt => VaccinationDccV1.kt} (59%)
 rename Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/{VaccinationDGCV1Parser.kt => VaccinationDccV1Parser.kt} (87%)
 delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateData.kt

diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt
index fe0d08c1c..8ea9f61d7 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt
@@ -3,8 +3,9 @@ package de.rki.coronawarnapp.bugreporting.censors.vaccination
 import dagger.Reusable
 import de.rki.coronawarnapp.bugreporting.censors.BugCensor
 import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensorContainer
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDGCV1
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationCertificateData
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
 import java.util.LinkedList
 import javax.inject.Inject
 
@@ -35,7 +36,7 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor {
 
                 newMessage = censorNameData(nameData, newMessage)
 
-                vaccinationDatas.forEach { data ->
+                payload.let { data ->
                     newMessage = censorVaccinationData(data, newMessage)
                 }
             }
@@ -45,7 +46,7 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor {
     }
 
     private fun censorVaccinationData(
-        vaccinationData: VaccinationDGCV1.VaccinationData,
+        vaccinationData: VaccinationDccV1.VaccinationData,
         message: CensorContainer
     ): CensorContainer {
         var newMessage = message
@@ -76,8 +77,8 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor {
         )
 
         newMessage = newMessage.censor(
-            vaccinationData.countryOfVaccination,
-            "vaccinationData/countryOfVaccination"
+            vaccinationData.certificateCountry,
+            "vaccinationData/certificateCountry"
         )
 
         newMessage = newMessage.censor(
@@ -100,7 +101,7 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor {
         return newMessage
     }
 
-    private fun censorNameData(nameData: VaccinationDGCV1.NameData, message: CensorContainer): CensorContainer {
+    private fun censorNameData(nameData: Dcc.NameData, message: CensorContainer): CensorContainer {
         var newMessage = message
 
         nameData.familyName?.let { fName ->
@@ -146,8 +147,8 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor {
 
         fun clearQRCodeStringToCensor() = synchronized(qrCodeStringsToCensor) { qrCodeStringsToCensor.clear() }
 
-        private val certsToCensor = LinkedList<VaccinationCertificateData>()
-        fun addCertificateToCensor(cert: VaccinationCertificateData) = synchronized(certsToCensor) {
+        private val certsToCensor = LinkedList<DccData<VaccinationDccV1>>()
+        fun addCertificateToCensor(cert: DccData<VaccinationDccV1>) = synchronized(certsToCensor) {
             certsToCensor.apply {
                 if (contains(cert)) return@apply
                 addFirst(cert)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/CertificatePersonIdentifier.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CertificatePersonIdentifier.kt
similarity index 61%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/CertificatePersonIdentifier.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CertificatePersonIdentifier.kt
index dcfd255a3..3148343d4 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/CertificatePersonIdentifier.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CertificatePersonIdentifier.kt
@@ -1,12 +1,8 @@
-package de.rki.coronawarnapp.covidcertificate.common
+package de.rki.coronawarnapp.covidcertificate.common.certificate
 
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_DOB_MISMATCH
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_NAME_MISMATCH
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
-import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestCertificateDccV1
-import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCode
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDGCV1
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationCertificateQRCode
 import de.rki.coronawarnapp.util.HashExtensions.toSHA256
 import org.joda.time.LocalDate
 import timber.log.Timber
@@ -50,23 +46,3 @@ data class CertificatePersonIdentifier(
         }
     }
 }
-
-val VaccinationDGCV1.personIdentifier: CertificatePersonIdentifier
-    get() = CertificatePersonIdentifier(
-        dateOfBirth = dateOfBirth,
-        lastNameStandardized = nameData.familyNameStandardized,
-        firstNameStandardized = nameData.givenNameStandardized
-    )
-
-val VaccinationCertificateQRCode.personIdentifier: CertificatePersonIdentifier
-    get() = parsedData.certificate.personIdentifier
-
-val TestCertificateDccV1.personIdentifier: CertificatePersonIdentifier
-    get() = CertificatePersonIdentifier(
-        dateOfBirth = dateOfBirth,
-        lastNameStandardized = nameData.familyNameStandardized,
-        firstNameStandardized = nameData.givenNameStandardized
-    )
-
-val TestCertificateQRCode.personIdentifier: CertificatePersonIdentifier
-    get() = testCertificateData.certificate.personIdentifier
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt
new file mode 100644
index 000000000..bd58201d2
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt
@@ -0,0 +1,29 @@
+package de.rki.coronawarnapp.covidcertificate.common.certificate
+
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
+import org.joda.time.Instant
+import org.joda.time.LocalDate
+
+/**
+ * For use with the UI
+ */
+interface CwaCovidCertificate {
+    // Header
+    val issuer: String
+    val issuedAt: Instant
+    val expiresAt: Instant
+
+    val qrCode: QrCodeString
+
+    val firstName: String?
+
+    val lastName: String
+    val fullName: String
+    val dateOfBirth: LocalDate
+
+    val personIdentifier: CertificatePersonIdentifier
+
+    val certificateIssuer: String
+    val certificateCountry: String
+    val certificateId: String
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/Dcc.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/Dcc.kt
new file mode 100644
index 000000000..8d8c4b030
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/Dcc.kt
@@ -0,0 +1,50 @@
+package de.rki.coronawarnapp.covidcertificate.common.certificate
+
+import com.google.gson.annotations.SerializedName
+import org.joda.time.LocalDate
+
+interface Dcc<PayloadType : Dcc.Payload> {
+    data class NameData(
+        @SerializedName("fn") internal val familyName: String?,
+        @SerializedName("fnt") internal val familyNameStandardized: String,
+        @SerializedName("gn") internal val givenName: String?,
+        @SerializedName("gnt") internal val givenNameStandardized: String?,
+    ) {
+        val firstName: String?
+            get() = if (givenName.isNullOrBlank()) givenNameStandardized else givenName
+
+        val lastName: String
+            get() = if (familyName.isNullOrBlank()) familyNameStandardized else familyName
+
+        val fullName: String
+            get() = when {
+                firstName.isNullOrBlank() -> lastName
+                else -> "$firstName $lastName"
+            }
+    }
+
+    val version: String
+    val nameData: NameData
+    val dob: String
+
+    val dateOfBirth: LocalDate
+        get() = LocalDate.parse(dob)
+
+    val payloads: List<PayloadType>
+    val payload: PayloadType
+        get() = payloads.single()
+
+    val personIdentifier: CertificatePersonIdentifier
+        get() = CertificatePersonIdentifier(
+            dateOfBirth = dateOfBirth,
+            lastNameStandardized = nameData.familyNameStandardized,
+            firstNameStandardized = nameData.givenNameStandardized
+        )
+
+    interface Payload {
+        val targetId: String
+        val certificateCountry: String
+        val certificateIssuer: String
+        val uniqueCertificateIdentifier: String
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccData.kt
new file mode 100644
index 000000000..89a2aac6b
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccData.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.covidcertificate.common.certificate
+
+data class DccData<CertT : Dcc<*>>(
+    val header: DccHeader,
+    val certificate: CertT,
+)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccHeader.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccHeader.kt
new file mode 100644
index 000000000..4964d7074
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/DccHeader.kt
@@ -0,0 +1,9 @@
+package de.rki.coronawarnapp.covidcertificate.common.certificate
+
+import org.joda.time.Instant
+
+data class DccHeader(
+    val issuer: String,
+    val issuedAt: Instant,
+    val expiresAt: Instant,
+)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/HealthCertificateCOSEDecoder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccCoseDecoder.kt
similarity index 94%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/HealthCertificateCOSEDecoder.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccCoseDecoder.kt
index 4662a3c84..51773c925 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/HealthCertificateCOSEDecoder.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccCoseDecoder.kt
@@ -1,4 +1,4 @@
-package de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate
+package de.rki.coronawarnapp.covidcertificate.common.decoder
 
 import com.upokecenter.cbor.CBORObject
 import de.rki.coronawarnapp.covidcertificate.cryptography.AesCryptography
@@ -9,7 +9,7 @@ import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateE
 import timber.log.Timber
 import javax.inject.Inject
 
-class HealthCertificateCOSEDecoder @Inject constructor(
+class DccCoseDecoder @Inject constructor(
     private val aesEncryptor: AesCryptography
 ) {
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/HealthCertificateHeaderParser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccHeaderParser.kt
similarity index 86%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/HealthCertificateHeaderParser.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccHeaderParser.kt
index 8878f55ad..2bac92a71 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/HealthCertificateHeaderParser.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/DccHeaderParser.kt
@@ -1,7 +1,8 @@
-package de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate
+package de.rki.coronawarnapp.covidcertificate.common.decoder
 
 import com.upokecenter.cbor.CBORObject
 import dagger.Reusable
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccHeader
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_EXP
@@ -10,9 +11,9 @@ import org.joda.time.Instant
 import javax.inject.Inject
 
 @Reusable
-class HealthCertificateHeaderParser @Inject constructor() {
+class DccHeaderParser @Inject constructor() {
 
-    fun parse(map: CBORObject): CoseCertificateHeader = try {
+    fun parse(map: CBORObject): DccHeader = try {
         val issuer: String = map[keyIssuer]?.AsString() ?: throw InvalidHealthCertificateException(HC_CWT_NO_ISS)
 
         val issuedAt: Instant = map[keyIssuedAt]?.run {
@@ -23,7 +24,7 @@ class HealthCertificateHeaderParser @Inject constructor() {
             Instant.ofEpochSecond(AsNumber().ToInt64Checked())
         } ?: throw InvalidHealthCertificateException(HC_CWT_NO_EXP)
 
-        HealthCertificateHeader(
+        DccHeader(
             issuer = issuer,
             issuedAt = issuedAt,
             expiresAt = expiresAt,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/RawCOSEObject.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/RawCOSEObject.kt
new file mode 100644
index 000000000..233796803
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/decoder/RawCOSEObject.kt
@@ -0,0 +1,3 @@
+package de.rki.coronawarnapp.covidcertificate.common.decoder
+
+typealias RawCOSEObject = ByteArray
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/DccQrCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/DccQrCode.kt
new file mode 100644
index 000000000..9d1527dd0
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/DccQrCode.kt
@@ -0,0 +1,16 @@
+package de.rki.coronawarnapp.covidcertificate.common.qrcode
+
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+
+interface DccQrCode<DccT : Dcc<*>> {
+    val qrCode: QrCodeString
+    val data: DccData<DccT>
+
+    val personIdentifier: CertificatePersonIdentifier
+        get() = data.certificate.personIdentifier
+
+    val uniqueCertificateIdentifier: String
+        get() = data.certificate.payload.uniqueCertificateIdentifier
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/QrCodeString.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/QrCodeString.kt
new file mode 100644
index 000000000..9c8208fe1
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/qrcode/QrCodeString.kt
@@ -0,0 +1,3 @@
+package de.rki.coronawarnapp.covidcertificate.common.qrcode
+
+typealias QrCodeString = String
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt
index b03f5ab10..b4589236a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt
@@ -1,15 +1,9 @@
 package de.rki.coronawarnapp.covidcertificate.test.core
 
-import de.rki.coronawarnapp.covidcertificate.common.CertificatePersonIdentifier
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.QrCodeString
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CwaCovidCertificate
 import org.joda.time.Instant
-import org.joda.time.LocalDate
 
-interface TestCertificate {
-    val firstName: String?
-    val lastName: String
-
-    val dateOfBirth: LocalDate
+interface TestCertificate : CwaCovidCertificate {
 
     /**
      * Disease or agent targeted (required)
@@ -30,16 +24,4 @@ interface TestCertificate {
     val sampleCollectedAt: Instant
     val testResultAt: Instant?
     val testCenter: String
-
-    val certificateIssuer: String
-    val certificateCountry: String
-    val certificateId: String
-
-    val personIdentifier: CertificatePersonIdentifier
-
-    val issuer: String
-    val issuedAt: Instant
-    val expiresAt: Instant
-
-    val qrCode: QrCodeString
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestCertificateData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestCertificateData.kt
deleted file mode 100644
index 862b61f0c..000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestCertificateData.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package de.rki.coronawarnapp.covidcertificate.test.core.certificate
-
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.CoseCertificateHeader
-
-data class TestCertificateData(
-    val header: CoseCertificateHeader,
-    val certificate: TestCertificateDccV1,
-)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestCertificateDccParser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccParser.kt
similarity index 86%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestCertificateDccParser.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccParser.kt
index 61a4a1ac1..96f3c7445 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestCertificateDccParser.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccParser.kt
@@ -15,10 +15,10 @@ import timber.log.Timber
 import javax.inject.Inject
 
 @Reusable
-class TestCertificateDccParser @Inject constructor(
+class TestDccParser @Inject constructor(
     @BaseGson private val gson: Gson,
 ) {
-    fun parse(map: CBORObject): TestCertificateDccV1 = try {
+    fun parse(map: CBORObject): TestDccV1 = try {
         map[keyHCert]?.run {
             this[keyEuDgcV1]?.run {
                 toCertificate()
@@ -31,19 +31,19 @@ class TestCertificateDccParser @Inject constructor(
     }
 
     @Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
-    private fun TestCertificateDccV1.validate(): TestCertificateDccV1 {
-        if (testCertificateData.isNullOrEmpty()) {
+    private fun TestDccV1.validate(): TestDccV1 {
+        if (payloads.isNullOrEmpty()) {
             throw InvalidTestCertificateException(NO_TEST_ENTRY)
         }
         // check for non null (Gson does not enforce it) & force date parsing
         version!!
         nameData.familyNameStandardized!!
         dateOfBirth
-        testCertificateData.forEach {
+        payload.let {
             it.testResultAt
             it.sampleCollectedAt
             it.certificateIssuer!!
-            it.countryOfTest!!
+            it.certificateCountry!!
             it.targetId!!
             it.testCenter!!
             it.testResult!!
@@ -54,7 +54,7 @@ class TestCertificateDccParser @Inject constructor(
 
     private fun CBORObject.toCertificate() = try {
         val json = ToJSONString()
-        gson.fromJson<TestCertificateDccV1>(json).validate()
+        gson.fromJson<TestDccV1>(json).validate()
     } catch (e: InvalidTestCertificateException) {
         throw e
     } catch (e: Throwable) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestCertificateDccV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccV1.kt
similarity index 63%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestCertificateDccV1.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccV1.kt
index 062878f47..c10516798 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestCertificateDccV1.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/certificate/TestDccV1.kt
@@ -1,25 +1,19 @@
 package de.rki.coronawarnapp.covidcertificate.test.core.certificate
 
 import com.google.gson.annotations.SerializedName
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
 import org.joda.time.Instant
-import org.joda.time.LocalDate
 
-data class TestCertificateDccV1(
-    @SerializedName("ver") val version: String,
-    @SerializedName("nam") val nameData: NameData,
-    @SerializedName("dob") val dob: String,
-    @SerializedName("t") val testCertificateData: List<TestCertificateData>,
-) {
-    data class NameData(
-        @SerializedName("fn") val familyName: String?,
-        @SerializedName("fnt") val familyNameStandardized: String,
-        @SerializedName("gn") val givenName: String?,
-        @SerializedName("gnt") val givenNameStandardized: String?,
-    )
+data class TestDccV1(
+    @SerializedName("ver") override val version: String,
+    @SerializedName("nam") override val nameData: Dcc.NameData,
+    @SerializedName("dob") override val dob: String,
+    @SerializedName("t") override val payloads: List<TestCertificateData>,
+) : Dcc<TestDccV1.TestCertificateData> {
 
     data class TestCertificateData(
         // Disease or agent targeted, e.g. "tg": "840539006"
-        @SerializedName("tg") val targetId: String,
+        @SerializedName("tg") override val targetId: String,
         // Type of Test (required) eg "LP217198-3"
         @SerializedName("tt") val testType: String,
         // Test Result (required) e. g. "tr": "260415000"
@@ -35,12 +29,12 @@ data class TestCertificateDccV1(
         // Testing Center (required) "tc": "GGD Fryslân, L-Heliconweg",
         @SerializedName("tc") val testCenter: String,
         // Country of Test (required)
-        @SerializedName("co") val countryOfTest: String,
+        @SerializedName("co") override val certificateCountry: String,
         // Certificate Issuer, e.g. "is": "Ministry of Public Health, Welfare and Sport",
-        @SerializedName("is") val certificateIssuer: String,
+        @SerializedName("is") override val certificateIssuer: String,
         // Unique Certificate Identifier, e.g.  "ci": "urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ"
-        @SerializedName("ci") val uniqueCertificateIdentifier: String
-    ) {
+        @SerializedName("ci") override val uniqueCertificateIdentifier: String
+    ) : Dcc.Payload {
 
         val testResultAt: Instant?
             get() = dr?.let { Instant.parse(it) }
@@ -48,7 +42,4 @@ data class TestCertificateDccV1(
         val sampleCollectedAt: Instant
             get() = Instant.parse(sc)
     }
-
-    val dateOfBirth: LocalDate
-        get() = LocalDate.parse(dob)
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCode.kt
index 9dc25f420..5e2063068 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCode.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCode.kt
@@ -1,8 +1,11 @@
 package de.rki.coronawarnapp.covidcertificate.test.core.qrcode
 
-import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestCertificateData
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.DccQrCode
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccV1
 
 data class TestCertificateQRCode(
-    val qrCode: String,
-    val testCertificateData: TestCertificateData,
-)
+    override val qrCode: QrCodeString,
+    override val data: DccData<TestDccV1>,
+) : DccQrCode<TestDccV1>
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractor.kt
index cf8963cbd..51a8de2f1 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractor.kt
@@ -2,6 +2,10 @@ package de.rki.coronawarnapp.covidcertificate.test.core.qrcode
 
 import com.upokecenter.cbor.CBORObject
 import dagger.Reusable
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccCoseDecoder
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccHeaderParser
+import de.rki.coronawarnapp.covidcertificate.common.decoder.RawCOSEObject
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_BASE45_ENCODING_FAILED
@@ -10,11 +14,8 @@ import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateE
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_COMPRESSION_FAILED
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidTestCertificateException
-import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestCertificateData
-import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestCertificateDccParser
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.HealthCertificateCOSEDecoder
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.HealthCertificateHeaderParser
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.RawCOSEObject
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccParser
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccV1
 import de.rki.coronawarnapp.util.compression.deflate
 import de.rki.coronawarnapp.util.compression.inflate
 import de.rki.coronawarnapp.util.encoding.Base45Decoder
@@ -23,9 +24,9 @@ import javax.inject.Inject
 
 @Reusable
 class TestCertificateQRCodeExtractor @Inject constructor(
-    private val coseDecoder: HealthCertificateCOSEDecoder,
-    private val headerParser: HealthCertificateHeaderParser,
-    private val bodyParser: TestCertificateDccParser,
+    private val coseDecoder: DccCoseDecoder,
+    private val headerParser: DccHeaderParser,
+    private val bodyParser: TestDccParser,
 ) {
 
     /**
@@ -37,7 +38,7 @@ class TestCertificateQRCodeExtractor @Inject constructor(
     ): TestCertificateQRCode {
         val rawCoseObject = rawCoseObjectEncrypted.decrypt(decryptionKey)
         return TestCertificateQRCode(
-            testCertificateData = rawCoseObject.decode(),
+            data = rawCoseObject.decode(),
             qrCode = rawCoseObject.encode()
         )
     }
@@ -46,7 +47,7 @@ class TestCertificateQRCodeExtractor @Inject constructor(
      * May throw an **[InvalidTestCertificateException]**
      */
     fun extract(qrCode: String) = TestCertificateQRCode(
-        testCertificateData = qrCode.extract(),
+        data = qrCode.extract(),
         qrCode = qrCode
     )
 
@@ -62,7 +63,7 @@ class TestCertificateQRCodeExtractor @Inject constructor(
         throw InvalidTestCertificateException(HC_COSE_MESSAGE_INVALID)
     }
 
-    private fun String.extract(): TestCertificateData =
+    private fun String.extract(): DccData<TestDccV1> =
         removePrefix(PREFIX)
             .decodeBase45()
             .decompress()
@@ -72,7 +73,7 @@ class TestCertificateQRCodeExtractor @Inject constructor(
         return PREFIX + compress().encodeBase45()
     }
 
-    private fun RawCOSEObject.decode(): TestCertificateData = try {
+    private fun RawCOSEObject.decode(): DccData<TestDccV1> = try {
         coseDecoder.decode(this).parse()
     } catch (e: InvalidHealthCertificateException) {
         throw InvalidTestCertificateException(e.errorCode)
@@ -81,8 +82,8 @@ class TestCertificateQRCodeExtractor @Inject constructor(
         throw InvalidTestCertificateException(HC_COSE_MESSAGE_INVALID)
     }
 
-    private fun CBORObject.parse(): TestCertificateData = try {
-        TestCertificateData(
+    private fun CBORObject.parse(): DccData<TestDccV1> = try {
+        DccData(
             header = headerParser.parse(this),
             certificate = bodyParser.parse(this)
         ).also {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt
index e97c7b876..972fcc5db 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt
@@ -1,11 +1,11 @@
 package de.rki.coronawarnapp.covidcertificate.test.core.storage
 
-import de.rki.coronawarnapp.covidcertificate.common.CertificatePersonIdentifier
-import de.rki.coronawarnapp.covidcertificate.common.personIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
 import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificate
-import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestCertificateData
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccV1
 import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCodeExtractor
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.QrCodeString
 import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.TestCertificateValueSets
 import org.joda.time.Instant
 import org.joda.time.LocalDate
@@ -18,8 +18,8 @@ data class TestCertificateContainer(
 ) : StoredTestCertificateData by data {
 
     @delegate:Transient
-    private val certificateData: TestCertificateData by lazy {
-        data.testCertificateQrCode!!.let { qrCodeExtractor.extract(it).testCertificateData }
+    private val certificateData: DccData<TestDccV1> by lazy {
+        data.testCertificateQrCode!!.let { qrCodeExtractor.extract(it).data }
     }
 
     val isPublicKeyRegistered: Boolean
@@ -31,7 +31,7 @@ data class TestCertificateContainer(
     val certificateId: String?
         get() {
             if (isCertificateRetrievalPending) return null
-            return certificateData.certificate.testCertificateData.single().uniqueCertificateIdentifier
+            return certificateData.certificate.payload.uniqueCertificateIdentifier
         }
 
     fun toTestCertificate(
@@ -42,16 +42,20 @@ data class TestCertificateContainer(
 
         val header = certificateData.header
         val certificate = certificateData.certificate
-        val testCertificate = certificate.testCertificateData.single()
+        val testCertificate = certificate.payload
 
         return object : TestCertificate {
             override val personIdentifier: CertificatePersonIdentifier
                 get() = certificate.personIdentifier
 
             override val firstName: String?
-                get() = certificate.nameData.givenName
+                get() = certificate.nameData.firstName
+
             override val lastName: String
-                get() = certificate.nameData.familyName ?: certificate.nameData.familyNameStandardized
+                get() = certificate.nameData.lastName
+
+            override val fullName: String
+                get() = certificate.nameData.fullName
 
             override val dateOfBirth: LocalDate
                 get() = certificate.dateOfBirth
@@ -76,7 +80,7 @@ data class TestCertificateContainer(
             override val certificateIssuer: String
                 get() = header.issuer
             override val certificateCountry: String
-                get() = Locale(userLocale.language, testCertificate.countryOfTest.uppercase())
+                get() = Locale(userLocale.language, testCertificate.certificateCountry.uppercase())
                     .getDisplayCountry(userLocale)
             override val certificateId: String
                 get() = testCertificate.uniqueCertificateIdentifier
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinatedPerson.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinatedPerson.kt
index a5592ef6d..942fe20bd 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinatedPerson.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinatedPerson.kt
@@ -1,6 +1,6 @@
 package de.rki.coronawarnapp.covidcertificate.vaccination.core
 
-import de.rki.coronawarnapp.covidcertificate.common.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinatedPersonData
 import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.VaccinationValueSets
 import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt
index 9428b8f24..21efe369b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt
@@ -1,17 +1,10 @@
 package de.rki.coronawarnapp.covidcertificate.vaccination.core
 
-import de.rki.coronawarnapp.covidcertificate.common.CertificatePersonIdentifier
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.QrCodeString
-import org.joda.time.Instant
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CwaCovidCertificate
 import org.joda.time.LocalDate
 
-interface VaccinationCertificate {
-    val firstName: String?
-    val lastName: String
+interface VaccinationCertificate : CwaCovidCertificate {
 
-    val fullName: String
-
-    val dateOfBirth: LocalDate
     val vaccinatedAt: LocalDate
 
     val vaccineTypeName: String
@@ -20,16 +13,4 @@ interface VaccinationCertificate {
 
     val doseNumber: Int
     val totalSeriesOfDoses: Int
-
-    val certificateIssuer: String
-    val certificateCountry: String
-    val certificateId: String
-
-    val personIdentifier: CertificatePersonIdentifier
-
-    val issuer: String
-    val issuedAt: Instant
-    val expiresAt: Instant
-
-    val vaccinationQrCodeString: QrCodeString
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/CoseCertificateHeader.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/CoseCertificateHeader.kt
deleted file mode 100644
index 8b26288ec..000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/CoseCertificateHeader.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate
-
-import org.joda.time.Instant
-
-interface CoseCertificateHeader {
-    val issuer: String
-    val issuedAt: Instant
-    val expiresAt: Instant
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/HealthCertificateHeader.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/HealthCertificateHeader.kt
deleted file mode 100644
index ed7761cb5..000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/HealthCertificateHeader.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate
-
-import org.joda.time.Instant
-
-data class HealthCertificateHeader(
-    override val issuer: String,
-    override val issuedAt: Instant,
-    override val expiresAt: Instant,
-) : CoseCertificateHeader
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/RawCOSEObject.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/RawCOSEObject.kt
deleted file mode 100644
index c3b69dfe1..000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/RawCOSEObject.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate
-
-typealias RawCOSEObject = ByteArray
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDGCV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1.kt
similarity index 59%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDGCV1.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1.kt
index 29ed50270..3583458aa 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDGCV1.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1.kt
@@ -1,24 +1,19 @@
 package de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate
 
 import com.google.gson.annotations.SerializedName
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
 import org.joda.time.LocalDate
 
-data class VaccinationDGCV1(
-    @SerializedName("ver") val version: String,
-    @SerializedName("nam") val nameData: NameData,
-    @SerializedName("dob") val dob: String,
-    @SerializedName("v") val vaccinationDatas: List<VaccinationData>,
-) {
-    data class NameData(
-        @SerializedName("fn") val familyName: String?,
-        @SerializedName("fnt") val familyNameStandardized: String,
-        @SerializedName("gn") val givenName: String?,
-        @SerializedName("gnt") val givenNameStandardized: String?,
-    )
+data class VaccinationDccV1(
+    @SerializedName("ver") override val version: String,
+    @SerializedName("nam") override val nameData: Dcc.NameData,
+    @SerializedName("dob") override val dob: String,
+    @SerializedName("v") override val payloads: List<VaccinationData>,
+) : Dcc<VaccinationDccV1.VaccinationData> {
 
     data class VaccinationData(
         // Disease or agent targeted, e.g. "tg": "840539006"
-        @SerializedName("tg") val targetId: String,
+        @SerializedName("tg") override val targetId: String,
         // Vaccine or prophylaxis, e.g. "vp": "1119349007"
         @SerializedName("vp") val vaccineId: String,
         // Vaccine medicinal product,e.g. "mp": "EU/1/20/1528",
@@ -32,16 +27,13 @@ data class VaccinationDGCV1(
         // Date of Vaccination, e.g. "dt" : "2021-04-21"
         @SerializedName("dt") val dt: String,
         // Country of Vaccination, e.g. "co": "NL"
-        @SerializedName("co") val countryOfVaccination: String,
+        @SerializedName("co") override val certificateCountry: String,
         // Certificate Issuer, e.g. "is": "Ministry of Public Health, Welfare and Sport",
-        @SerializedName("is") val certificateIssuer: String,
+        @SerializedName("is") override val certificateIssuer: String,
         // Unique Certificate Identifier, e.g.  "ci": "urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ"
-        @SerializedName("ci") val uniqueCertificateIdentifier: String
-    ) {
+        @SerializedName("ci") override val uniqueCertificateIdentifier: String
+    ) : Dcc.Payload {
         val vaccinatedAt: LocalDate
             get() = LocalDate.parse(dt)
     }
-
-    val dateOfBirth: LocalDate
-        get() = LocalDate.parse(dob)
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDGCV1Parser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1Parser.kt
similarity index 87%
rename from Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDGCV1Parser.kt
rename to Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1Parser.kt
index e60e0f170..7b4f9b0c2 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDGCV1Parser.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1Parser.kt
@@ -15,11 +15,11 @@ import de.rki.coronawarnapp.util.serialization.fromJson
 import javax.inject.Inject
 
 @Reusable
-class VaccinationDGCV1Parser @Inject constructor(
+class VaccinationDccV1Parser @Inject constructor(
     @BaseGson private val gson: Gson
 ) {
 
-    fun parse(map: CBORObject): VaccinationDGCV1 = try {
+    fun parse(map: CBORObject): VaccinationDccV1 = try {
         map[keyHCert]?.run {
             this[keyEuDgcV1]?.run {
                 toCertificate()
@@ -32,18 +32,18 @@ class VaccinationDGCV1Parser @Inject constructor(
     }
 
     @Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
-    private fun VaccinationDGCV1.validate(): VaccinationDGCV1 {
-        if (vaccinationDatas.isNullOrEmpty()) {
+    private fun VaccinationDccV1.validate(): VaccinationDccV1 {
+        if (payloads.isNullOrEmpty()) {
             throw InvalidVaccinationCertificateException(VC_NO_VACCINATION_ENTRY)
         }
         // check for non null (Gson does not enforce it) & force date parsing
         version!!
         nameData.familyNameStandardized.isNotBlank()
         dateOfBirth
-        vaccinationDatas.forEach {
+        payload.let {
             it.vaccinatedAt
             it.certificateIssuer.isNotBlank()
-            it.countryOfVaccination.isNotBlank()
+            it.certificateCountry.isNotBlank()
             it.marketAuthorizationHolderId.isNotBlank()
             it.medicalProductId.isNotBlank()
             it.targetId.isNotBlank()
@@ -55,7 +55,7 @@ class VaccinationDGCV1Parser @Inject constructor(
 
     private fun CBORObject.toCertificate() = try {
         val json = ToJSONString()
-        gson.fromJson<VaccinationDGCV1>(json).validate()
+        gson.fromJson<VaccinationDccV1>(json).validate()
     } catch (e: InvalidVaccinationCertificateException) {
         throw e
     } catch (e: Throwable) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateData.kt
deleted file mode 100644
index 5fcafc382..000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateData.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode
-
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.CoseCertificateHeader
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDGCV1
-
-/**
- * Represents the parsed data from the QR code
- */
-data class VaccinationCertificateData(
-    val header: CoseCertificateHeader,
-    val certificate: VaccinationDGCV1,
-)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateQRCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateQRCode.kt
index c90117e5e..ad88fb591 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateQRCode.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationCertificateQRCode.kt
@@ -1,11 +1,11 @@
 package de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode
 
-data class VaccinationCertificateQRCode(
-    val qrCodeString: QrCodeString,
-    val parsedData: VaccinationCertificateData,
-) {
-    val uniqueCertificateIdentifier: String
-        get() = parsedData.certificate.vaccinationDatas.single().uniqueCertificateIdentifier
-}
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.DccQrCode
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
 
-typealias QrCodeString = String
+data class VaccinationCertificateQRCode(
+    override val qrCode: QrCodeString,
+    override val data: DccData<VaccinationDccV1>
+) : DccQrCode<VaccinationDccV1>
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt
index b467ddff1..362c7f7a6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractor.kt
@@ -2,24 +2,26 @@ package de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode
 
 import de.rki.coronawarnapp.bugreporting.censors.vaccination.CertificateQrCodeCensor
 import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccCoseDecoder
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccHeaderParser
+import de.rki.coronawarnapp.covidcertificate.common.decoder.RawCOSEObject
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.HealthCertificateCOSEDecoder
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.HealthCertificateHeaderParser
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.RawCOSEObject
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDGCV1Parser
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1Parser
 import de.rki.coronawarnapp.util.compression.inflate
 import de.rki.coronawarnapp.util.encoding.Base45Decoder
 import timber.log.Timber
 import javax.inject.Inject
 
 class VaccinationQRCodeExtractor @Inject constructor(
-    private val coseDecoder: HealthCertificateCOSEDecoder,
-    private val headerParser: HealthCertificateHeaderParser,
-    private val bodyParser: VaccinationDGCV1Parser,
+    private val coseDecoder: DccCoseDecoder,
+    private val headerParser: DccHeaderParser,
+    private val bodyParser: VaccinationDccV1Parser,
 ) : QrCodeExtractor<VaccinationCertificateQRCode> {
 
     override fun canHandle(rawString: String): Boolean = rawString.startsWith(PREFIX)
@@ -34,8 +36,8 @@ class VaccinationQRCodeExtractor @Inject constructor(
             .parse()
 
         return VaccinationCertificateQRCode(
-            parsedData = parsedData,
-            qrCodeString = rawString,
+            qrCode = rawString,
+            data = parsedData,
         )
     }
 
@@ -53,11 +55,11 @@ class VaccinationQRCodeExtractor @Inject constructor(
         throw InvalidVaccinationCertificateException(HC_ZLIB_DECOMPRESSION_FAILED)
     }
 
-    fun RawCOSEObject.parse(): VaccinationCertificateData = try {
+    fun RawCOSEObject.parse(): DccData<VaccinationDccV1> = try {
         Timber.v("Parsing COSE for vaccination certificate.")
         val cbor = coseDecoder.decode(this)
 
-        VaccinationCertificateData(
+        DccData(
             header = headerParser.parse(cbor),
             certificate = bodyParser.parse(cbor)
         ).also {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/VaccinationRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/VaccinationRepository.kt
index c8b7136e6..187a85d33 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/VaccinationRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/VaccinationRepository.kt
@@ -1,8 +1,7 @@
 package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository
 
 import de.rki.coronawarnapp.bugreporting.reportProblem
-import de.rki.coronawarnapp.covidcertificate.common.CertificatePersonIdentifier
-import de.rki.coronawarnapp.covidcertificate.common.personIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_ALREADY_REGISTERED
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinatedPersonData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinatedPersonData.kt
index 516e8867f..ab4663c66 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinatedPersonData.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinatedPersonData.kt
@@ -1,7 +1,7 @@
 package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage
 
 import com.google.gson.annotations.SerializedName
-import de.rki.coronawarnapp.covidcertificate.common.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
 
 data class VaccinatedPersonData(
     @SerializedName("vaccinationData") val vaccinations: Set<VaccinationContainer> = emptySet()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt
index 1b8804fe1..61aa1c599 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt
@@ -2,13 +2,12 @@ package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storag
 
 import androidx.annotation.Keep
 import com.google.gson.annotations.SerializedName
-import de.rki.coronawarnapp.covidcertificate.common.CertificatePersonIdentifier
-import de.rki.coronawarnapp.covidcertificate.common.personIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccHeader
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationCertificate
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.CoseCertificateHeader
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDGCV1
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.QrCodeString
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationCertificateData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationCertificateQRCode
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeExtractor
 import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.VaccinationValueSets
@@ -24,25 +23,25 @@ data class VaccinationContainer internal constructor(
 
     // Either set by [ContainerPostProcessor] or via [toVaccinationContainer]
     @Transient lateinit var qrCodeExtractor: VaccinationQRCodeExtractor
-    @Transient internal var preParsedData: VaccinationCertificateData? = null
+    @Transient internal var preParsedData: DccData<VaccinationDccV1>? = null
 
     // Otherwise GSON unsafes reflection to create this class, and sets the LAZY to null
     @Suppress("unused")
     constructor() : this("", Instant.EPOCH)
 
     @delegate:Transient
-    internal val certificateData: VaccinationCertificateData by lazy {
-        preParsedData ?: qrCodeExtractor.extract(vaccinationQrCode).parsedData
+    internal val certificateData: DccData<VaccinationDccV1> by lazy {
+        preParsedData ?: qrCodeExtractor.extract(vaccinationQrCode).data
     }
 
-    val header: CoseCertificateHeader
+    val header: DccHeader
         get() = certificateData.header
 
-    val certificate: VaccinationDGCV1
+    val certificate: VaccinationDccV1
         get() = certificateData.certificate
 
-    val vaccination: VaccinationDGCV1.VaccinationData
-        get() = certificate.vaccinationDatas.single()
+    val vaccination: VaccinationDccV1.VaccinationData
+        get() = certificate.payload
 
     val certificateId: String
         get() = vaccination.uniqueCertificateIdentifier
@@ -58,20 +57,13 @@ data class VaccinationContainer internal constructor(
             get() = certificate.personIdentifier
 
         override val firstName: String?
-            get() = if (certificate.nameData.givenName.isNullOrBlank())
-                certificate.nameData.givenNameStandardized
-            else certificate.nameData.givenName
+            get() = certificate.nameData.firstName
 
         override val lastName: String
-            get() = if (certificate.nameData.familyName.isNullOrBlank())
-                certificate.nameData.familyNameStandardized
-            else certificate.nameData.familyName!!
+            get() = certificate.nameData.lastName
 
         override val fullName: String
-            get() = when {
-                firstName.isNullOrBlank() -> lastName
-                else -> "$firstName $lastName"
-            }
+            get() = certificate.nameData.fullName
 
         override val dateOfBirth: LocalDate
             get() = certificate.dateOfBirth
@@ -97,7 +89,7 @@ data class VaccinationContainer internal constructor(
         override val certificateCountry: String
             get() = Locale(
                 userLocale.language,
-                vaccination.countryOfVaccination.uppercase()
+                vaccination.certificateCountry.uppercase()
             ).getDisplayCountry(userLocale)
 
         override val certificateId: String
@@ -110,7 +102,7 @@ data class VaccinationContainer internal constructor(
         override val expiresAt: Instant
             get() = header.expiresAt
 
-        override val vaccinationQrCodeString: QrCodeString
+        override val qrCode: QrCodeString
             get() = vaccinationQrCode
     }
 }
@@ -119,9 +111,9 @@ fun VaccinationCertificateQRCode.toVaccinationContainer(
     scannedAt: Instant,
     qrCodeExtractor: VaccinationQRCodeExtractor,
 ) = VaccinationContainer(
-    vaccinationQrCode = this.qrCodeString,
+    vaccinationQrCode = this.qrCode,
     scannedAt = scannedAt,
 ).apply {
     this.qrCodeExtractor = qrCodeExtractor
-    preParsedData = parsedData
+    preParsedData = data
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsViewModel.kt
index 863a6c7c9..9cb494dd2 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/details/VaccinationDetailsViewModel.kt
@@ -60,8 +60,8 @@ class VaccinationDetailsViewModel @AssistedInject constructor(
     private fun generateQrCode(certificate: VaccinationCertificate?) = launch {
         try {
             mutableStateFlow.value = certificate?.let {
-                qrCodeText = it.vaccinationQrCodeString
-                qrCodeGenerator.createQrCode(it.vaccinationQrCodeString)
+                qrCodeText = it.qrCode
+                qrCodeGenerator.createQrCode(it.qrCode)
             }
         } catch (e: Exception) {
             Timber.d(e, "generateQrCode failed for vaccinationCertificate=%s", certificate)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListViewModel.kt
index 707490bbe..9dea2c350 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/list/VaccinationListViewModel.kt
@@ -56,7 +56,7 @@ class VaccinationListViewModel @AssistedInject constructor(
         // immediately ...
         emit(null)
         // ... and after the QR code was generated, it is emitted
-        emit(qrCodeGenerator.createQrCode(it.getMostRecentVaccinationCertificate.vaccinationQrCodeString))
+        emit(qrCodeGenerator.createQrCode(it.getMostRecentVaccinationCertificate.qrCode))
     }
 
     val uiState: LiveData<UiState> = combine(vaccinatedPersonFlow, vaccinationQrCodeFlow) { vaccinatedPerson, qrCode ->
@@ -92,7 +92,7 @@ class VaccinationListViewModel @AssistedInject constructor(
                     onQrCodeClick = {
                         events.postValue(
                             Event.NavigateToQrCodeFullScreen(
-                                qrCode = vaccinatedPerson.getMostRecentVaccinationCertificate.vaccinationQrCodeString,
+                                qrCode = vaccinatedPerson.getMostRecentVaccinationCertificate.qrCode,
                                 positionInList = 0
                             )
                         )
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt
index 572a3d710..ed3ee7d48 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt
@@ -1,7 +1,8 @@
 package de.rki.coronawarnapp.bugreporting.censors.vaccination
 
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDGCV1
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationCertificateData
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
 import io.kotest.matchers.shouldBe
 import io.mockk.MockKAnnotations
 import io.mockk.mockk
@@ -15,19 +16,19 @@ internal class CertificateQrCodeCensorTest {
 
     private val testRawString =
         "HC1:6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3.ZH9M9ESIGUBA KWML/O6HXK 0D+4O5VC9:BPCNYKMXEE1JAA/CZIK0JK1WL260X638J3-E3GG396B-43FZT-43:S0X37*ZV+FNI6HXY0ZSVILVQJF//05MVZJ5V.499TXY9KK9+OC+G9QJPNF67J6QW67KQY466PPM4MLJE+.PDB9L6Q2+PFQ5DB96PP5/P-59A%N+892 7J235II3NJ7PK7SLQMIJSBHVA7UJQWT.+S+ND%%M%331BH.IA.C8KRDL4O54O4IGUJKJGI0JAXD15IAXMFU*GSHGHD63DAOC9JU0H11+*4.\$S6ZC0JBZAB-C3QHISKE MCAOI8%M3V96-PY\$N6XOWLIBPIAYU:*JIRHUF2XZQ4H9 XJ72WG1K36VF/9BL56%E8T1OEEG%5TW5A 6YO67N6UCE:WT6BT-UMM:ABJK2TMDN1:FW-%T+\$D78NDSC3%5F61NYS-P9LOE0%J/ZAY:N5L4H-H/LH:AO3FU JHG7K46IOIMT.RE%PHLA21JRI3HTC\$AH"
-    private val testCertificateData = VaccinationCertificateData(
+    private val testCertificateData = DccData(
         header = mockk(),
-        certificate = VaccinationDGCV1(
+        certificate = VaccinationDccV1(
             version = "1",
-            nameData = VaccinationDGCV1.NameData(
+            nameData = Dcc.NameData(
                 familyName = "Kevin",
                 familyNameStandardized = "KEVIN",
                 givenName = "Bob",
                 givenNameStandardized = "BOB"
             ),
             dob = "1969-11-16",
-            vaccinationDatas = listOf(
-                VaccinationDGCV1.VaccinationData(
+            payloads = listOf(
+                VaccinationDccV1.VaccinationData(
                     targetId = "12345",
                     vaccineId = "1214765",
                     medicalProductId = "aaEd/easd",
@@ -35,7 +36,7 @@ internal class CertificateQrCodeCensorTest {
                     doseNumber = 2,
                     totalSeriesOfDoses = 5,
                     dt = "1969-04-20",
-                    countryOfVaccination = "DE",
+                    certificateCountry = "DE",
                     certificateIssuer = "Herbert",
                     uniqueCertificateIdentifier = "urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ"
                 )
@@ -77,7 +78,7 @@ internal class CertificateQrCodeCensorTest {
             "vaccinationCertificate/dateOfBirth, i have been vaccinated with: vaccinationData/targetId " +
             "vaccinationData/vaccineId vaccinationData/medicalProductId" +
             " vaccinationData/marketAuthorizationHolderId vaccinationData/vaccinatedAt" +
-            " vaccinationData/countryOfVaccination vaccinationData/certificateIssuer" +
+            " vaccinationData/certificateCountry vaccinationData/certificateIssuer" +
             " vaccinationData/uniqueCertificateIdentifier"
     }
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/common/CertificatePersonIdentifierTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/common/CertificatePersonIdentifierTest.kt
index 2b4da9308..f0b34bd13 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/common/CertificatePersonIdentifierTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/common/CertificatePersonIdentifierTest.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.covidcertificate.common
 
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_DOB_MISMATCH
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.VC_NAME_MISMATCH
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateProcessorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateProcessorTest.kt
index cada4eae0..605e0e21c 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateProcessorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/execution/TestCertificateProcessorTest.kt
@@ -84,7 +84,7 @@ class TestCertificateProcessorTest : BaseTest() {
 
         coEvery { qrCodeExtractor.extract(any(), any()) } returns mockk<TestCertificateQRCode>().apply {
             every { qrCode } returns "qrCode"
-            every { testCertificateData } returns mockk()
+            every { data } returns mockk()
         }
     }
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateRepositoryTest.kt
index 3a4dd7cde..75e7d3204 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateRepositoryTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateRepositoryTest.kt
@@ -63,7 +63,7 @@ class TestCertificateRepositoryTest : BaseTest() {
 
         coEvery { qrCodeExtractor.extract(any(), any()) } returns mockk<TestCertificateQRCode>().apply {
             every { qrCode } returns "qrCode"
-            every { testCertificateData } returns mockk()
+            every { data } returns mockk()
         }
         every { valueSetsRepository.latestTestCertificateValueSets } returns emptyFlow()
     }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateDccParserTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateDccParserTest.kt
index 3603b4954..f9f50f5c6 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateDccParserTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateDccParserTest.kt
@@ -3,7 +3,7 @@ package de.rki.coronawarnapp.covidcertificate.test.core.qrcode
 import com.google.gson.Gson
 import com.upokecenter.cbor.CBORObject
 import de.rki.coronawarnapp.covidcertificate.test.TestData
-import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestCertificateDccParser
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccParser
 import io.kotest.matchers.shouldBe
 import okio.ByteString.Companion.decodeHex
 import org.joda.time.LocalDate
@@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test
 
 class TestCertificateDccParserTest {
 
-    private val bodyParser = TestCertificateDccParser(Gson())
+    private val bodyParser = TestDccParser(Gson())
 
     @Test
     fun `happy path cose decryption with Ellen Cheng`() {
@@ -28,9 +28,9 @@ class TestCertificateDccParserTest {
             dateOfBirth shouldBe LocalDate.parse("1998-02-26")
             version shouldBe "1.2.1"
 
-            with(testCertificateData[0]) {
+            with(payloads[0]) {
                 uniqueCertificateIdentifier shouldBe "URN:UVCI:01:AT:71EE2559DE38C6BF7304FB65A1A451EC#3"
-                countryOfTest shouldBe "AT"
+                certificateCountry shouldBe "AT"
                 certificateIssuer shouldBe "Ministry of Health, Austria"
                 targetId shouldBe "840539006"
                 sampleCollectedAt shouldBe org.joda.time.Instant.parse("2021-02-20T12:34:56+00:00")
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractorTest.kt
index 8b67db97d..39226fcec 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/core/qrcode/TestCertificateQRCodeExtractorTest.kt
@@ -1,14 +1,14 @@
 package de.rki.coronawarnapp.covidcertificate.test.core.qrcode
 
 import com.google.gson.Gson
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccCoseDecoder
+import de.rki.coronawarnapp.covidcertificate.common.decoder.DccHeaderParser
 import de.rki.coronawarnapp.covidcertificate.cryptography.AesCryptography
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidTestCertificateException
 import de.rki.coronawarnapp.covidcertificate.test.TestData
-import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestCertificateDccParser
+import de.rki.coronawarnapp.covidcertificate.test.core.certificate.TestDccParser
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationQrCodeTestData
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.HealthCertificateCOSEDecoder
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.HealthCertificateHeaderParser
 import io.kotest.assertions.throwables.shouldThrow
 import io.kotest.matchers.shouldBe
 import okio.ByteString.Companion.decodeBase64
@@ -18,21 +18,21 @@ import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 
 class TestCertificateQRCodeExtractorTest : BaseTest() {
-    private val coseDecoder = HealthCertificateCOSEDecoder(AesCryptography())
-    private val headerParser = HealthCertificateHeaderParser()
-    private val bodyParser = TestCertificateDccParser(Gson())
+    private val coseDecoder = DccCoseDecoder(AesCryptography())
+    private val headerParser = DccHeaderParser()
+    private val bodyParser = TestDccParser(Gson())
     private val extractor = TestCertificateQRCodeExtractor(coseDecoder, headerParser, bodyParser)
 
     @Test
     fun `happy path qr code`() {
         val qrCode = extractor.extract(TestData.qrCodeTestCertificate)
-        with(qrCode.testCertificateData.header) {
+        with(qrCode.data.header) {
             issuer shouldBe "AT"
             issuedAt shouldBe Instant.parse("2021-06-01T10:12:48.000Z")
             expiresAt shouldBe Instant.parse("2021-06-03T10:12:48.000Z")
         }
 
-        with(qrCode.testCertificateData.certificate) {
+        with(qrCode.data.certificate) {
             with(nameData) {
                 familyName shouldBe "Musterfrau-Gößinger"
                 familyNameStandardized shouldBe "MUSTERFRAU<GOESSINGER"
@@ -43,9 +43,9 @@ class TestCertificateQRCodeExtractorTest : BaseTest() {
             dateOfBirth shouldBe LocalDate.parse("1998-02-26")
             version shouldBe "1.2.1"
 
-            with(testCertificateData[0]) {
+            with(payloads[0]) {
                 uniqueCertificateIdentifier shouldBe "URN:UVCI:01:AT:71EE2559DE38C6BF7304FB65A1A451EC#3"
-                countryOfTest shouldBe "AT"
+                certificateCountry shouldBe "AT"
                 certificateIssuer shouldBe "Ministry of Health, Austria"
                 targetId shouldBe "840539006"
                 sampleCollectedAt shouldBe Instant.parse("2021-02-20T12:34:56+00:00")
@@ -63,12 +63,12 @@ class TestCertificateQRCodeExtractorTest : BaseTest() {
             val coseObject = coseWithEncryptedPayload.decodeBase64()!!.toByteArray()
             val dek = dek.decodeBase64()!!.toByteArray()
             val result = extractor.extract(dek, coseObject)
-            with(result.testCertificateData.certificate.nameData) {
+            with(result.data.certificate.nameData) {
                 familyName shouldBe "Cheng"
                 givenName shouldBe "Ellen"
             }
             val result2 = extractor.extract(result.qrCode)
-            with(result2.testCertificateData.certificate.nameData) {
+            with(result2.data.certificate.nameData) {
                 familyName shouldBe "Cheng"
                 givenName shouldBe "Ellen"
             }
@@ -81,12 +81,12 @@ class TestCertificateQRCodeExtractorTest : BaseTest() {
             val coseObject = coseWithEncryptedPayload.decodeBase64()!!.toByteArray()
             val dek = dek.decodeBase64()!!.toByteArray()
             val result = extractor.extract(dek, coseObject)
-            with(result.testCertificateData.certificate.nameData) {
+            with(result.data.certificate.nameData) {
                 familyName shouldBe "Calamandrei"
                 givenName shouldBe "Brian"
             }
             val result2 = extractor.extract(result.qrCode)
-            with(result2.testCertificateData.certificate.nameData) {
+            with(result2.data.certificate.nameData) {
                 familyName shouldBe "Calamandrei"
                 givenName shouldBe "Brian"
             }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestData.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestData.kt
index 7446be10c..079022777 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestData.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestData.kt
@@ -1,8 +1,9 @@
 package de.rki.coronawarnapp.covidcertificate.vaccination.core
 
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.HealthCertificateHeader
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDGCV1
-import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationCertificateData
+import de.rki.coronawarnapp.covidcertificate.common.certificate.Dcc
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
+import de.rki.coronawarnapp.covidcertificate.common.certificate.DccHeader
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.certificate.VaccinationDccV1
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationCertificateQRCode
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeExtractor
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinatedPersonData
@@ -19,17 +20,17 @@ class VaccinationTestData @Inject constructor(
     val personAVac1QRCodeString =
         "HC1:6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3KXH9M9ESIGUBA KWML%6S5B9-+P70Q5VC9:BPCNYKMXEE1JAA/CXGG0JK1WL260X638J3-E3ND3DAJ-43TTTO3HK1H3QBCWNZ83UQJ:T0/8F7V0HKN:Q8.HBV+0SZ4GH00T9UKP0T9WC5PF6846A\$Q$76QW6%V98T5\$FQMI5DN9QZ5Y0Q\$UPE%5MZ5*T57ZA\$O7T6LEJOA+MZ55EII-EB1EKC422JBBD0D2K.EJJ14B2MP41WTRZPQEC5L64HX6IAS 8S8FT/MAMXP6QS03L0QIRR97I2HOAXL92L0. KOKG8VG5SI:TU+MMPZ55%PBT1YEGEA7IB65C94JBQ2NLEE:NQ% GC3MXHFLF9OIFN0IZ95LJL80P1FDLW452I8941:HH3M41GTNP8EFUNT$.FTD852IWKP/HLIJL8JF8JF172IMAS EDAHMXFBFBQSKJE72KV\$FHJ%3O%6:XM+1QD+T2/VKKER3L3%1THL7MGY.1S:T:GLOX6OCE7+RWYL3.C-L27WNV0G::M74O%K7C50AAEI4"
 
-    val personAVac1Certificate = VaccinationDGCV1(
+    val personAVac1Certificate = VaccinationDccV1(
         version = "1.0.0",
-        nameData = VaccinationDGCV1.NameData(
+        nameData = Dcc.NameData(
             givenName = "Andreas",
             givenNameStandardized = "ANDREAS",
             familyName = "Astrá Eins",
             familyNameStandardized = "ASTRA<EINS",
         ),
         dob = "1966-11-11",
-        vaccinationDatas = listOf(
-            VaccinationDGCV1.VaccinationData(
+        payloads = listOf(
+            VaccinationDccV1.VaccinationData(
                 targetId = "840539006",
                 vaccineId = "1119305005",
                 medicalProductId = "EU/1/21/1529",
@@ -37,27 +38,27 @@ class VaccinationTestData @Inject constructor(
                 doseNumber = 1,
                 totalSeriesOfDoses = 2,
                 dt = "2021-03-01",
-                countryOfVaccination = "DE",
+                certificateCountry = "DE",
                 certificateIssuer = "Bundesministerium für Gesundheit - Test01",
                 uniqueCertificateIdentifier = "01DE/00001/1119305005/7T1UG87G61Y7NRXIBQJDTYQ9#S",
             )
         )
     )
 
-    val personAVac1CertificateHeader = HealthCertificateHeader(
+    val personAVac1CertificateHeader = DccHeader(
         issuer = "DE",
         issuedAt = Instant.parse("2021-05-11T09:25:00.000Z"),
         expiresAt = Instant.parse("2022-05-11T09:25:00.000Z"),
     )
 
-    val personAVac1CertificateData = VaccinationCertificateData(
+    val personAVac1CertificateData = DccData(
         certificate = personAVac1Certificate,
         header = personAVac1CertificateHeader
     )
 
     val personAVac1QRCode = VaccinationCertificateQRCode(
-        qrCodeString = personAVac1QRCodeString,
-        parsedData = personAVac1CertificateData,
+        qrCode = personAVac1QRCodeString,
+        data = personAVac1CertificateData,
     )
 
     val personAVac1Container = VaccinationContainer(
@@ -71,17 +72,17 @@ class VaccinationTestData @Inject constructor(
     val personAVac2QRCodeString =
         "6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3D H9M9ESIGUBA KWMLYX1HXK 0DV:D5VC9:BPCNYKMXEE1JAA/CZIK0JK1WL260X638J3-E3ND3DAJ-43TTTMDF6S8:B73QN VNZ.0K6HYI3CNN96BPHNW*0I85V.499TXY9KK9%OC+G9QJPNF67J6QW67KQ9G66PPM4MLJE+.PDB9L6Q2+PFQ5DB96PP5/P-59A%N+892 7J235II3NJ7PK7SLQMIPUBN9CIZI.EJJ14B2MP41IZRZPQEC5L64HX6IAS 8SAFT/MAMXP6QS03L0QIRR97I2HOAXL92L0. KOKGGVG5SI:TU+MMPZ55%PBT1YEGEA7IB65C94JBQ2NLEE:NQ% GC3MXHFLF9OIFN0IZ95LJL80P1FDLW452I8941:HH3M41GTNP8EFUNT\$.FTD852IWKP/HLIJL8JF8JF172E2JA0K*WDQMPB8T3%KLUSR43M.F\$QBQDR\$VT7V01Y7J0BOZLH+D-QF6MO\$R3%XB+.4QI596GY\$SITJP5BS0DFROC.7B.2RTB*UNYSM$*00HIL+H"
 
-    val personAVac2Certificate = VaccinationDGCV1(
+    val personAVac2Certificate = VaccinationDccV1(
         version = "1.0.0",
-        nameData = VaccinationDGCV1.NameData(
+        nameData = Dcc.NameData(
             givenName = "Andreas",
             givenNameStandardized = "ANDREAS",
             familyName = "Astrá Eins",
             familyNameStandardized = "ASTRA<EINS",
         ),
         dob = "1966-11-11",
-        vaccinationDatas = listOf(
-            VaccinationDGCV1.VaccinationData(
+        payloads = listOf(
+            VaccinationDccV1.VaccinationData(
                 targetId = "840539006",
                 vaccineId = "1119305005",
                 medicalProductId = "EU/1/21/1529",
@@ -89,27 +90,27 @@ class VaccinationTestData @Inject constructor(
                 doseNumber = 2,
                 totalSeriesOfDoses = 2,
                 dt = "2021-04-27",
-                countryOfVaccination = "DE",
+                certificateCountry = "DE",
                 certificateIssuer = "Bundesministerium für Gesundheit - Test01",
                 uniqueCertificateIdentifier = "01DE/00001/1119305005/6IPYBAIDWEWRWW73QEP92FQSN#S",
             )
         )
     )
 
-    val personAVac2CertificateHeader = HealthCertificateHeader(
+    val personAVac2CertificateHeader = DccHeader(
         issuer = "DE",
         issuedAt = Instant.parse("2021-05-11T09:26:08.000Z"),
         expiresAt = Instant.parse("2022-05-11T09:26:08.000Z"),
     )
 
-    val personAVac2CertificateData = VaccinationCertificateData(
+    val personAVac2CertificateData = DccData(
         certificate = personAVac2Certificate,
         header = personAVac2CertificateHeader
     )
 
     val personAVac2QRCode = VaccinationCertificateQRCode(
-        qrCodeString = personAVac2QRCodeString,
-        parsedData = personAVac2CertificateData,
+        qrCode = personAVac2QRCodeString,
+        data = personAVac2CertificateData,
     )
 
     val personAVac2Container = VaccinationContainer(
@@ -127,17 +128,17 @@ class VaccinationTestData @Inject constructor(
     val personBVac1QRCodeString =
         "HC1:6BFOXN*TS0BI\$ZD.P9UOL97O4-2HH77HRM3DSPTLRR+%3QVH9M9ESIGUBA KWML:SPHXK 0DMYF5VC9:BPCNYKMXEE1JAA/CZIK0JK1WL260X638J3-E3ND3DAJ-43 QTCPFFIJRF3O8H43HX37DUF GFE VMJJYC3SM74E5V.499TXY9KK9+OC+G9QJPNF67J6QW67KQ2G66PPM4MLJE+.PDB9L6Q2+PFQ5DB96PP5/P-59A%N+892 7J235II3NJ7PK7SLQMIPUBN9CIZI.EJJ14B2MP41AZRSEQEC5L64HX6IAS3DS2980IQ.DPUHLW\$GAHLW 70SO:GOLIROGO3T59YLQM14+OP\$I/XK\$M8CL6PZB*L8PK99Q9E\$BDZIF9J8-I\$GI0 J1ALL:F71APC9*KF6LF/NLR/FZ.COKEH-BB4OQ9OG4C5AO**HOELK2AZ7LBLEH-BHPLV5GK3DNKE\$JDVPLW1KD0KCZG.M1LUSB5BCQRJ\$DB5N9%V/GO4IHIBBJ-BI%NWRS%LR%\$KR46325NABFDDAFHD9PZP11COD5U*2KQXCA5W8HH/K51DQO8O0-SOSENFH9101U8$3"
 
-    val personBVac1Certificate = VaccinationDGCV1(
+    val personBVac1Certificate = VaccinationDccV1(
         version = "1.0.0",
-        nameData = VaccinationDGCV1.NameData(
+        nameData = Dcc.NameData(
             givenName = "Boris",
             givenNameStandardized = "BORIS",
             familyName = "Johnson Gültig",
             familyNameStandardized = "JOHNSON<GUELTIG",
         ),
         dob = "1966-11-11",
-        vaccinationDatas = listOf(
-            VaccinationDGCV1.VaccinationData(
+        payloads = listOf(
+            VaccinationDccV1.VaccinationData(
                 targetId = "840539006",
                 vaccineId = "1119305005",
                 medicalProductId = "EU/1/20/1525",
@@ -145,27 +146,27 @@ class VaccinationTestData @Inject constructor(
                 doseNumber = 1,
                 totalSeriesOfDoses = 1,
                 dt = "2021-04-20",
-                countryOfVaccination = "DE",
+                certificateCountry = "DE",
                 certificateIssuer = "Bundesministerium für Gesundheit - Test01",
                 uniqueCertificateIdentifier = "01DE/00001/1119305005/3H24U2KVOTPCSINK7N64F2OB9#S",
             )
         )
     )
 
-    val personBVac1CertificateHeader = HealthCertificateHeader(
+    val personBVac1CertificateHeader = DccHeader(
         issuer = "DE",
         issuedAt = Instant.parse("2021-05-11T09:23:03.000Z"),
         expiresAt = Instant.parse("2022-05-11T09:23:03.000Z"),
     )
 
-    val personBVac1CertificateData = VaccinationCertificateData(
+    val personBVac1CertificateData = DccData(
         certificate = personBVac1Certificate,
         header = personBVac1CertificateHeader
     )
 
     val personBVac1QRCode = VaccinationCertificateQRCode(
-        qrCodeString = personBVac1QRCodeString,
-        parsedData = personBVac1CertificateData,
+        qrCode = personBVac1QRCodeString,
+        data = personBVac1CertificateData,
     )
 
     val personBVac1Container = VaccinationContainer(
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt
index a740c1d22..a6634d63a 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeExtractorTest.kt
@@ -42,13 +42,13 @@ class VaccinationQRCodeExtractorTest : BaseTest() {
     fun `happy path extraction with data`() {
         val qrCode = extractor.extract(VaccinationQrCodeTestData.validVaccinationQrCode3)
 
-        with(qrCode.parsedData.header) {
+        with(qrCode.data.header) {
             issuer shouldBe "AT"
             issuedAt shouldBe Instant.ofEpochSecond(1620392021)
             expiresAt shouldBe Instant.ofEpochSecond(1620564821)
         }
 
-        with(qrCode.parsedData.certificate) {
+        with(qrCode.data.certificate) {
             with(nameData) {
                 familyName shouldBe "Musterfrau-Gößinger"
                 familyNameStandardized shouldBe "MUSTERFRAU<GOESSINGER"
@@ -59,9 +59,9 @@ class VaccinationQRCodeExtractorTest : BaseTest() {
             dateOfBirth shouldBe LocalDate.parse("1998-02-26")
             version shouldBe "1.0.0"
 
-            with(vaccinationDatas[0]) {
+            with(payloads[0]) {
                 uniqueCertificateIdentifier shouldBe "urn:uvci:01:AT:10807843F94AEE0EE5093FBC254BD813P"
-                countryOfVaccination shouldBe "AT"
+                certificateCountry shouldBe "AT"
                 doseNumber shouldBe 1
                 dt shouldBe "2021-02-18"
                 certificateIssuer shouldBe "BMSGPK Austria"
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainerTest.kt
index 4498d70dc..7c9d5d97f 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainerTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainerTest.kt
@@ -1,6 +1,6 @@
 package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage
 
-import de.rki.coronawarnapp.covidcertificate.common.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.DaggerVaccinationTestComponent
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationTestData
 import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.DefaultValueSet
-- 
GitLab