diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragmentTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9d1d1223d2290c7c2fd1becf3a911447d91d5843
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragmentTest.kt
@@ -0,0 +1,196 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.test.espresso.Espresso
+import androidx.test.espresso.matcher.ViewMatchers
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.test.ui.cards.CovidTestCertificateCard
+import de.rki.coronawarnapp.covidcertificate.test.ui.cards.CovidTestCertificateErrorCard
+import de.rki.coronawarnapp.covidcertificate.test.ui.items.CertificatesItem
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinatedPerson
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.CreateVaccinationCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.HeaderInfoVaccinationCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.ImmuneVaccinationCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.NoCovidTestCertificatesCard
+import de.rki.coronawarnapp.covidcertificate.vaccination.ui.cards.VaccinationCard
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import org.joda.time.DateTime
+import org.joda.time.Duration
+import org.joda.time.format.DateTimeFormat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import testhelpers.BaseUITest
+import testhelpers.Screenshot
+import testhelpers.launchFragment2
+import testhelpers.launchInMainActivity
+import testhelpers.selectBottomNavTab
+import testhelpers.takeScreenshot
+
+@RunWith(AndroidJUnit4::class)
+class CertificatesFragmentTest : BaseUITest() {
+
+    @MockK lateinit var viewModel: CertificatesViewModel
+    @MockK lateinit var vaccinatedPerson: VaccinatedPerson
+
+    private val formatter = DateTimeFormat.forPattern("dd.MM.yyyy HH:mm")
+    private val testDate = DateTime.parse("12.05.2021 19:00", formatter).toInstant()
+
+    @Before
+    fun setup() {
+        MockKAnnotations.init(this, relaxed = true)
+        every { vaccinatedPerson.fullName } returns "Max Mustermann"
+        every { vaccinatedPerson.getMostRecentVaccinationCertificate.expiresAt } returns
+            testDate.plus(Duration.standardDays(365)).toInstant()
+
+        setupMockViewModel(
+            object : CertificatesViewModel.Factory {
+                override fun create(): CertificatesViewModel = viewModel
+            }
+        )
+    }
+
+    @After
+    fun teardown() {
+        clearAllViewModels()
+    }
+
+    @Test
+    fun launch_fragment() {
+        launchFragment2<CertificatesFragment>()
+    }
+
+    @Screenshot
+    @Test
+    fun capture_screenshot_empty() {
+        every { viewModel.screenItems } returns getEmptyScreenItems()
+
+        takeScreenshotInMainActivity()
+    }
+
+    private fun getEmptyScreenItems(): LiveData<List<CertificatesItem>> {
+        return MutableLiveData(
+            listOf(
+                HeaderInfoVaccinationCard.Item,
+                CreateVaccinationCard.Item {},
+                NoCovidTestCertificatesCard.Item
+            )
+        )
+    }
+
+    @Screenshot
+    @Test
+    fun capture_screenshot_vaccination_incomplete() {
+        every { vaccinatedPerson.getVaccinationStatus() } returns VaccinatedPerson.Status.INCOMPLETE
+        every { viewModel.screenItems } returns getVaccinationIncompleteScreenItems()
+
+        takeScreenshotInMainActivity("incomplete")
+    }
+
+    private fun getVaccinationIncompleteScreenItems(): LiveData<List<CertificatesItem>> {
+        return MutableLiveData(
+            listOf(
+                HeaderInfoVaccinationCard.Item,
+                VaccinationCard.Item(
+                    vaccinatedPerson = vaccinatedPerson,
+                    onClickAction = {}
+                ),
+                NoCovidTestCertificatesCard.Item
+            )
+        )
+    }
+
+    @Screenshot
+    @Test
+    fun capture_screenshot_vaccination_complete() {
+        every { vaccinatedPerson.getVaccinationStatus() } returns VaccinatedPerson.Status.IMMUNITY
+        every { viewModel.screenItems } returns getVaccinationImmuneScreenItems()
+
+        takeScreenshotInMainActivity("immune")
+    }
+
+    private fun getVaccinationImmuneScreenItems(): LiveData<List<CertificatesItem>> {
+        return MutableLiveData(
+            listOf(
+                HeaderInfoVaccinationCard.Item,
+                ImmuneVaccinationCard.Item(
+                    vaccinatedPerson = vaccinatedPerson,
+                    onClickAction = {}
+                ),
+                NoCovidTestCertificatesCard.Item
+            )
+        )
+    }
+
+    @Screenshot
+    @Test
+    fun capture_screenshot_green_certificate() {
+        every { vaccinatedPerson.getVaccinationStatus() } returns VaccinatedPerson.Status.IMMUNITY
+        every { viewModel.screenItems } returns getVaccinationGreenCertScreenItems()
+
+        takeScreenshotInMainActivity("green")
+    }
+
+    private fun getVaccinationGreenCertScreenItems(): LiveData<List<CertificatesItem>> {
+        return MutableLiveData(
+            listOf(
+                HeaderInfoVaccinationCard.Item,
+                ImmuneVaccinationCard.Item(
+                    vaccinatedPerson = vaccinatedPerson,
+                    onClickAction = {}
+                ),
+                CovidTestCertificateCard.Item(
+                    testDate = testDate,
+                    testPerson = "Max Mustermann"
+                ) { }
+            )
+        )
+    }
+
+    @Screenshot
+    @Test
+    fun capture_screenshot_pending_certificate() {
+        every { vaccinatedPerson.getVaccinationStatus() } returns VaccinatedPerson.Status.IMMUNITY
+        every { viewModel.screenItems } returns getVaccinationPendingCertScreenItems()
+
+        takeScreenshotInMainActivity("pending")
+    }
+
+    private fun getVaccinationPendingCertScreenItems(): LiveData<List<CertificatesItem>> {
+        return MutableLiveData(
+            listOf(
+                HeaderInfoVaccinationCard.Item,
+                ImmuneVaccinationCard.Item(
+                    vaccinatedPerson = vaccinatedPerson,
+                    onClickAction = {}
+                ),
+                CovidTestCertificateErrorCard.Item(
+                    testDate = testDate,
+                    isUpdatingData = false,
+                    onRetryAction = {},
+                    onDeleteAction = {}
+                )
+            )
+        )
+    }
+
+    private fun takeScreenshotInMainActivity(suffix: String = "") {
+        launchInMainActivity<CertificatesFragment>()
+        Espresso.onView(ViewMatchers.withId(R.id.fake_bottom_navigation))
+            .perform(selectBottomNavTab(R.id.green_certificate_graph))
+        takeScreenshot<CertificatesFragment>(suffix)
+    }
+}
+
+@Module
+abstract class CertificatesFragmentTestModule {
+    @ContributesAndroidInjector
+    abstract fun certificatesFragment(): CertificatesFragment
+}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/test/ui/CovidCertificateDetailsFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/test/ui/CovidCertificateDetailsFragmentTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ec0076572f455d92bcc69677f6821d3a753f64eb
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/test/ui/CovidCertificateDetailsFragmentTest.kt
@@ -0,0 +1,143 @@
+package de.rki.coronawarnapp.covidcertificate.test.ui
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.swipeUp
+import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import dagger.Module
+import dagger.android.ContributesAndroidInjector
+import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
+import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString
+import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificate
+import de.rki.coronawarnapp.covidcertificate.test.core.storage.TestCertificateIdentifier
+import de.rki.coronawarnapp.covidcertificate.test.ui.details.CovidCertificateDetailsFragment
+import de.rki.coronawarnapp.covidcertificate.test.ui.details.CovidCertificateDetailsFragmentArgs
+import de.rki.coronawarnapp.covidcertificate.test.ui.details.CovidCertificateDetailsViewModel
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import org.joda.time.DateTime
+import org.joda.time.Instant
+import org.joda.time.LocalDate
+import org.joda.time.format.DateTimeFormat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import testhelpers.BaseUITest
+import testhelpers.Screenshot
+import testhelpers.launchFragment2
+import testhelpers.launchFragmentInContainer2
+import testhelpers.takeScreenshot
+
+@RunWith(AndroidJUnit4::class)
+class VaccinationDetailsFragmentTest : BaseUITest() {
+
+    @MockK lateinit var vaccinationDetailsViewModel: CovidCertificateDetailsViewModel
+    @MockK lateinit var certificatePersonIdentifier: CertificatePersonIdentifier
+
+    private val args = CovidCertificateDetailsFragmentArgs("testCertificateIdentifier").toBundle()
+
+    @Before
+    fun setUp() {
+        MockKAnnotations.init(this, relaxed = true)
+
+        every { vaccinationDetailsViewModel.qrCode } returns bitmapLiveDate()
+
+        setupMockViewModel(
+            object : CovidCertificateDetailsViewModel.Factory {
+                override fun create(testCertificateIdentifier: TestCertificateIdentifier):
+                    CovidCertificateDetailsViewModel = vaccinationDetailsViewModel
+            }
+        )
+    }
+
+    @Test
+    fun launch_fragment() {
+        launchFragment2<CovidCertificateDetailsFragment>(fragmentArgs = args)
+    }
+
+    @Screenshot
+    @Test
+    fun capture_screenshot_incomplete() {
+        every { vaccinationDetailsViewModel.covidCertificate } returns vaccinationDetailsData()
+        launchFragmentInContainer2<CovidCertificateDetailsFragment>(fragmentArgs = args)
+        takeScreenshot<CovidCertificateDetailsFragment>()
+        onView(withId(R.id.coordinator_layout)).perform(swipeUp())
+        takeScreenshot<CovidCertificateDetailsFragment>("_2")
+    }
+
+    private fun bitmapLiveDate(): LiveData<Bitmap> {
+        val applicationContext = ApplicationProvider.getApplicationContext<Context>()
+        return MutableLiveData(
+            BitmapFactory.decodeResource(applicationContext.resources, R.drawable.test_qr_code)
+        )
+    }
+
+    private fun vaccinationDetailsData(): MutableLiveData<TestCertificate> {
+        val formatter = DateTimeFormat.forPattern("dd.MM.yyyy HH:mm")
+        val testDate = DateTime.parse("12.05.2021 19:00", formatter).toInstant()
+        return MutableLiveData(
+            object : TestCertificate {
+                override val targetName: String
+                    get() = "Mustermann, Max"
+                override val testType: String
+                    get() = "SARS-CoV-2-Test"
+                override val testResult: String
+                    get() = "negative"
+                override val testName: String
+                    get() = "Xep"
+                override val testNameAndManufactor: String
+                    get() = "Xup"
+                override val sampleCollectedAt: Instant
+                    get() = testDate
+                override val testResultAt: Instant
+                    get() = testDate
+                override val testCenter: String
+                    get() = "AB123"
+                override val issuer: String
+                    get() = "G0593048274845483647869576478784"
+                override val issuedAt: Instant
+                    get() = testDate
+                override val expiresAt: Instant
+                    get() = testDate
+                override val qrCode: QrCodeString
+                    get() = ""
+                override val firstName: String
+                    get() = "Max"
+                override val lastName: String
+                    get() = "Mustermann"
+                override val fullName: String
+                    get() = "Mustermann, Max"
+                override val dateOfBirth: LocalDate
+                    get() = LocalDate.parse("18.04.1943 00:00", formatter)
+                override val personIdentifier: CertificatePersonIdentifier
+                    get() = certificatePersonIdentifier
+                override val certificateIssuer: String
+                    get() = "G0593048274845483647869576478784"
+                override val certificateCountry: String
+                    get() = "Germany"
+                override val certificateId: String
+                    get() = "05930482748454836478695764787840"
+            }
+        )
+    }
+
+    @After
+    fun tearDown() {
+        clearAllViewModels()
+    }
+}
+
+@Module
+abstract class CovidCertificateDetailsFragmentTestModule {
+    @ContributesAndroidInjector
+    abstract fun covidCertificateDetailsFragment(): CovidCertificateDetailsFragment
+}
diff --git a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
index c8d1be3d5f7627a65ec5a00f7024e585f794c9af..7291b0c9397966b18290e3c0a2f8abb1433b2ef1 100644
--- a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
+++ b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
@@ -3,6 +3,8 @@ package testhelpers
 import dagger.Module
 import de.rki.coronawarnapp.bugreporting.DebugLogTestModule
 import de.rki.coronawarnapp.bugreporting.DebugLogUploadTestModule
+import de.rki.coronawarnapp.covidcertificate.test.ui.CertificatesFragmentTestModule
+import de.rki.coronawarnapp.covidcertificate.test.ui.CovidCertificateDetailsFragmentTestModule
 import de.rki.coronawarnapp.covidcertificate.vaccination.ui.details.VaccinationDetailsFragmentTestModule
 import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListFragmentTestModule
 import de.rki.coronawarnapp.ui.contactdiary.ContactDiaryDayFragmentTestModule
@@ -91,6 +93,8 @@ import de.rki.coronawarnapp.ui.vaccination.VaccinationConsentFragmentTestModule
         VaccinationConsentFragmentTestModule::class,
         VaccinationListFragmentTestModule::class,
         RequestCovidCertificateFragmentTestModule::class,
+        CertificatesFragmentTestModule::class,
+        CovidCertificateDetailsFragmentTestModule::class,
     ]
 )
 class FragmentTestModuleRegistrar
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidator.kt
index 7b31a977326e8cf8f72a7b76938766d79e1c1d3f..4f12913e4e45402456e2a37edb17a920429ae085 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidator.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidator.kt
@@ -13,7 +13,7 @@ class CoronaTestQrCodeValidator @Inject constructor(
 
     fun validate(rawString: String): CoronaTestQRCode {
         return findExtractor(rawString)
-            ?.extract(rawString)
+            ?.extract(rawString, mode = QrCodeExtractor.Mode.TEST_STRICT)
             ?.also { Timber.i("Extracted data from QR code is %s", it) }
             ?: throw InvalidQRCodeException()
     }
@@ -25,5 +25,11 @@ class CoronaTestQrCodeValidator @Inject constructor(
 
 interface QrCodeExtractor<T> {
     fun canHandle(rawString: String): Boolean
-    fun extract(rawString: String): T
+    fun extract(rawString: String, mode: Mode): T
+
+    enum class Mode {
+        TEST_STRICT,
+        CERT_VAC_STRICT,
+        CERT_VAC_LENIENT
+    }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/InvalidQRCodeException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/InvalidQRCodeException.kt
index 24dd420a35009d94e55b06ece7c80802cd6db8eb..30c3cf40d5d9e99b94ffb8946d5afbc4b8b8b0fc 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/InvalidQRCodeException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/InvalidQRCodeException.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.coronatest.qrcode
 
 open class InvalidQRCodeException(
-    message: String = "An error occurred while parsing the qr code"
-) : Exception(message)
+    message: String = "An error occurred while parsing the qr code",
+    cause: Throwable? = null,
+) : Exception(message, cause)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/PcrQrCodeExtractor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/PcrQrCodeExtractor.kt
index 49633e3decd06846753a897897b235a16409cbdd..c94eb873ff48e73c1fca6cd54a7b7994fe46373f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/PcrQrCodeExtractor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/PcrQrCodeExtractor.kt
@@ -8,7 +8,7 @@ class PcrQrCodeExtractor @Inject constructor() : QrCodeExtractor<CoronaTestQRCod
 
     override fun canHandle(rawString: String): Boolean = rawString.startsWith(prefix, ignoreCase = true)
 
-    override fun extract(rawString: String): CoronaTestQRCode.PCR {
+    override fun extract(rawString: String, mode: QrCodeExtractor.Mode): CoronaTestQRCode.PCR {
         val guid = extractGUID(rawString)
         PcrQrCodeCensor.lastGUID = guid
         return CoronaTestQRCode.PCR(guid)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractor.kt
index 2265512e021fba44f390d1bc7eb90bd4d79d4e7a..9175decb73488312d937e2615b641cb6c5b4d460 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractor.kt
@@ -19,7 +19,7 @@ class RapidAntigenQrCodeExtractor @Inject constructor() : QrCodeExtractor<Corona
         return rawString.startsWith(PREFIX1, ignoreCase = true) || rawString.startsWith(PREFIX2, ignoreCase = true)
     }
 
-    override fun extract(rawString: String): CoronaTestQRCode.RapidAntigen {
+    override fun extract(rawString: String, mode: QrCodeExtractor.Mode): CoronaTestQRCode.RapidAntigen {
         Timber.v("extract(rawString=%s)", rawString)
         val payload = CleanPayload(extractData(rawString))
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/exception/InvalidHealthCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/exception/InvalidHealthCertificateException.kt
index b082915d8c1957be2319ef9ca7894158fb9b81c5..401f396e27c7f1d2f7ccc435892e68fccb4e3db4 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/exception/InvalidHealthCertificateException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/exception/InvalidHealthCertificateException.kt
@@ -9,8 +9,9 @@ import de.rki.coronawarnapp.util.ui.LazyString
 
 @Suppress("MaxLineLength")
 open class InvalidHealthCertificateException(
-    val errorCode: ErrorCode
-) : HasHumanReadableError, InvalidQRCodeException(errorCode.message) {
+    val errorCode: ErrorCode,
+    cause: Throwable? = null,
+) : HasHumanReadableError, InvalidQRCodeException(errorCode.message, cause) {
     enum class ErrorCode(
         val message: String
     ) {
@@ -22,6 +23,7 @@ open class InvalidHealthCertificateException(
         HC_COSE_MESSAGE_INVALID("COSE message invalid."),
         HC_CBOR_DECODING_FAILED("CBOR decoding failed."),
         VC_NO_VACCINATION_ENTRY("Vaccination certificate missing."),
+        VC_MULTIPLE_VACCINATION_ENTRIES("Multiple vaccination certificates."),
         NO_TEST_ENTRY("Test certificate missing."),
         VC_PREFIX_INVALID("Prefix invalid."),
         VC_STORING_FAILED("Storing failed."),
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/exception/InvalidVaccinationCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/exception/InvalidVaccinationCertificateException.kt
index 0a38b5300336e3dcfba82169715bcd38f6dab287..63fc7f6728e587b45e5efbd2966d2dbab8fca3c5 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/exception/InvalidVaccinationCertificateException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/exception/InvalidVaccinationCertificateException.kt
@@ -6,7 +6,10 @@ import de.rki.coronawarnapp.util.HumanReadableError
 import de.rki.coronawarnapp.util.ui.CachedString
 import de.rki.coronawarnapp.util.ui.LazyString
 
-class InvalidVaccinationCertificateException(errorCode: ErrorCode) : InvalidHealthCertificateException(errorCode) {
+class InvalidVaccinationCertificateException(
+    errorCode: ErrorCode,
+    cause: Throwable? = null,
+) : InvalidHealthCertificateException(errorCode, cause) {
     override fun toHumanReadableError(context: Context): HumanReadableError {
         var errorCodeString = errorCode.toString()
         errorCodeString = if (errorCodeString.startsWith(PREFIX_VC)) errorCodeString else PREFIX_VC + errorCodeString
@@ -15,20 +18,26 @@ class InvalidVaccinationCertificateException(errorCode: ErrorCode) : InvalidHeal
         )
     }
 
+    val showFaqButton: Boolean
+        get() = errorCode in codesVcInvalid
+
+    private val codesVcInvalid = listOf(
+        ErrorCode.HC_BASE45_DECODING_FAILED,
+        ErrorCode.HC_CBOR_DECODING_FAILED,
+        ErrorCode.HC_COSE_MESSAGE_INVALID,
+        ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED,
+        ErrorCode.HC_COSE_TAG_INVALID,
+        ErrorCode.VC_PREFIX_INVALID,
+        ErrorCode.HC_CWT_NO_DGC,
+        ErrorCode.HC_CWT_NO_EXP,
+        ErrorCode.HC_CWT_NO_HCERT,
+        ErrorCode.HC_CWT_NO_ISS,
+        ErrorCode.JSON_SCHEMA_INVALID
+    )
+
     override val errorMessage: LazyString
         get() = when (errorCode) {
-            ErrorCode.VC_PREFIX_INVALID,
-            ErrorCode.HC_BASE45_DECODING_FAILED,
-            ErrorCode.HC_CBOR_DECODING_FAILED,
-            ErrorCode.HC_COSE_MESSAGE_INVALID,
-            ErrorCode.HC_ZLIB_DECOMPRESSION_FAILED,
-            ErrorCode.HC_COSE_TAG_INVALID,
-            ErrorCode.HC_CWT_NO_DGC,
-            ErrorCode.HC_CWT_NO_EXP,
-            ErrorCode.HC_CWT_NO_HCERT,
-            ErrorCode.HC_CWT_NO_ISS,
-            ErrorCode.JSON_SCHEMA_INVALID,
-            -> CachedString { context ->
+            in codesVcInvalid -> CachedString { context ->
                 context.getString(ERROR_MESSAGE_VC_INVALID)
             }
 
@@ -36,6 +45,10 @@ class InvalidVaccinationCertificateException(errorCode: ErrorCode) : InvalidHeal
                 context.getString(ERROR_MESSAGE_VC_NOT_YET_SUPPORTED)
             }
 
+            ErrorCode.VC_MULTIPLE_VACCINATION_ENTRIES -> CachedString { context ->
+                context.getString(ERROR_MESSAGE_VC_NOT_YET_SUPPORTED)
+            }
+
             ErrorCode.VC_STORING_FAILED -> CachedString { context ->
                 context.getString(ERROR_MESSAGE_VC_SCAN_AGAIN)
             }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt
index 96263715b079593f273d3a19bddbcd80c0d736a2..afd660e979ff7f8197838d140578d3350edb9b55 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt
@@ -89,7 +89,7 @@ class CertificatesFragment : Fragment(R.layout.fragment_certificates), AutoInjec
         setOnMenuItemClickListener {
             when (it.itemId) {
                 R.id.menu_information -> {
-                    doNavigate(CertificatesFragmentDirections.actionCertificatesFragmentToConsentFragment())
+                    doNavigate(CertificatesFragmentDirections.actionCertificatesFragmentToConsentFragment(false))
                     true
                 }
                 else -> onOptionsItemSelected(it)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsFragment.kt
index ae32afd1905d6b97daf944cccf12e4eb8487214a..3e79944b5fb879c6f4fb86541b2ff79a77f4f837 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/details/CovidCertificateDetailsFragment.kt
@@ -68,7 +68,7 @@ class CovidCertificateDetailsFragment : Fragment(R.layout.fragment_covid_certifi
             testCertificate.sampleCollectedAt.toShortDayFormat(),
             testCertificate.sampleCollectedAt.toShortTimeFormat(),
         )
-        name.text = testCertificate.run { "$firstName $lastName" }
+        name.text = testCertificate.run { "$lastName, $firstName" }
         birthDate.text = testCertificate.dateOfBirth.toDayFormat()
         diseaseType.text = testCertificate.targetName
         testType.text = testCertificate.testType
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1.kt
index 3583458aa0c5211d4524647a6c449e81b5bd6af6..e231e3ed67601d3b246d406059bea3260c50fb4d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1.kt
@@ -2,7 +2,9 @@ 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.DateTime
 import org.joda.time.LocalDate
+import timber.log.Timber
 
 data class VaccinationDccV1(
     @SerializedName("ver") override val version: String,
@@ -33,7 +35,29 @@ data class VaccinationDccV1(
         // Unique Certificate Identifier, e.g.  "ci": "urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ"
         @SerializedName("ci") override val uniqueCertificateIdentifier: String
     ) : Dcc.Payload {
+        // Can't use lazy because GSON will NULL it, as we have no no-args constructor
+        private var vaccinatedAtCache: LocalDate? = null
         val vaccinatedAt: LocalDate
-            get() = LocalDate.parse(dt)
+            get() = vaccinatedAtCache ?: dt.toLocalDateLeniently().also {
+                vaccinatedAtCache = it
+            }
+    }
+
+    // Can't use lazy because GSON will NULL it, as we have no no-args constructor
+    private var dateOfBirthCache: LocalDate? = null
+    override val dateOfBirth: LocalDate
+        get() = dateOfBirthCache ?: dob.toLocalDateLeniently().also {
+            dateOfBirthCache = it
+        }
+}
+
+private fun String.toLocalDateLeniently(): LocalDate = try {
+    LocalDate.parse(this)
+} catch (e: Exception) {
+    Timber.w("Irregular date string: %s", this)
+    try {
+        DateTime.parse(this).toLocalDate()
+    } catch (giveUp: Exception) {
+        throw giveUp
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1Parser.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1Parser.kt
index 9a5a488651f200f2d9ebeb33d1ec0e7f60182d24..725d2082d5b77aa8e38c4d2a7662da7f92f5440f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1Parser.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/certificate/VaccinationDccV1Parser.kt
@@ -4,14 +4,11 @@ import com.google.gson.Gson
 import com.upokecenter.cbor.CBORObject
 import dagger.Reusable
 import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidHealthCertificateException
-import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidHealthCertificateException.ErrorCode.HC_CBOR_DECODING_FAILED
-import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_DGC
-import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_HCERT
-import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidHealthCertificateException.ErrorCode.JSON_SCHEMA_INVALID
-import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidHealthCertificateException.ErrorCode.VC_NO_VACCINATION_ENTRY
+import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidHealthCertificateException.ErrorCode
 import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidVaccinationCertificateException
 import de.rki.coronawarnapp.util.serialization.BaseGson
 import de.rki.coronawarnapp.util.serialization.fromJson
+import timber.log.Timber
 import javax.inject.Inject
 
 @Reusable
@@ -19,47 +16,58 @@ class VaccinationDccV1Parser @Inject constructor(
     @BaseGson private val gson: Gson
 ) {
 
-    fun parse(map: CBORObject): VaccinationDccV1 = try {
+    fun parse(map: CBORObject, lenient: Boolean): VaccinationDccV1 = try {
         map[keyHCert]?.run {
             this[keyEuDgcV1]?.run {
-                toCertificate()
-            } ?: throw InvalidVaccinationCertificateException(HC_CWT_NO_DGC)
-        } ?: throw InvalidVaccinationCertificateException(HC_CWT_NO_HCERT)
+                this.toCertificate(lenient = lenient)
+            } ?: throw InvalidVaccinationCertificateException(ErrorCode.HC_CWT_NO_DGC)
+        } ?: throw InvalidVaccinationCertificateException(ErrorCode.HC_CWT_NO_HCERT)
     } catch (e: InvalidHealthCertificateException) {
         throw e
     } catch (e: Throwable) {
-        throw InvalidVaccinationCertificateException(HC_CBOR_DECODING_FAILED)
+        throw InvalidVaccinationCertificateException(ErrorCode.HC_CBOR_DECODING_FAILED, cause = e)
     }
 
     @Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
-    private fun VaccinationDccV1.validate(): VaccinationDccV1 {
-        if (payloads.isNullOrEmpty()) {
-            throw InvalidVaccinationCertificateException(VC_NO_VACCINATION_ENTRY)
+    private fun VaccinationDccV1.toValidated(lenient: Boolean): VaccinationDccV1 = this
+        .run {
+            if (payloads.isEmpty()) throw InvalidVaccinationCertificateException(ErrorCode.VC_NO_VACCINATION_ENTRY)
+
+            if (payloads.size == 1) return@run this
+
+            if (lenient) {
+                Timber.w("Lenient: Vaccination data contained multiple entries.")
+                copy(payloads = listOf(payloads.maxByOrNull { it.vaccinatedAt }!!))
+            } else {
+                throw InvalidVaccinationCertificateException(ErrorCode.VC_MULTIPLE_VACCINATION_ENTRIES)
+            }
         }
-        // check for non null (Gson does not enforce it) & force date parsing
-        require(version.isNotBlank())
-        require(nameData.familyNameStandardized.isNotBlank())
-        dateOfBirth
-        payload.let {
-            it.vaccinatedAt
-            require(it.certificateIssuer.isNotBlank())
-            require(it.certificateCountry.isNotBlank())
-            require(it.marketAuthorizationHolderId.isNotBlank())
-            require(it.medicalProductId.isNotBlank())
-            require(it.targetId.isNotBlank())
-            require(it.doseNumber > 0)
-            require(it.totalSeriesOfDoses > 0)
+        .apply {
+            // Apply otherwise we risk accidentally accessing the original obj in the outer scope
+            // Force date parsing
+            // check for non null (Gson does not enforce it) & force date parsing
+            require(version.isNotBlank())
+            require(nameData.familyNameStandardized.isNotBlank())
+            dateOfBirth
+            payload.let {
+                it.vaccinatedAt
+                require(it.certificateIssuer.isNotBlank())
+                require(it.certificateCountry.isNotBlank())
+                require(it.marketAuthorizationHolderId.isNotBlank())
+                require(it.medicalProductId.isNotBlank())
+                require(it.targetId.isNotBlank())
+                require(it.doseNumber > 0)
+                require(it.totalSeriesOfDoses > 0)
+            }
         }
-        return this
-    }
 
-    private fun CBORObject.toCertificate() = try {
+    private fun CBORObject.toCertificate(lenient: Boolean): VaccinationDccV1 = try {
         val json = ToJSONString()
-        gson.fromJson<VaccinationDccV1>(json).validate()
+        gson.fromJson<VaccinationDccV1>(json).toValidated(lenient = lenient)
     } catch (e: InvalidVaccinationCertificateException) {
         throw e
     } catch (e: Throwable) {
-        throw InvalidVaccinationCertificateException(JSON_SCHEMA_INVALID)
+        throw InvalidVaccinationCertificateException(ErrorCode.JSON_SCHEMA_INVALID)
     }
 
     companion object {
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 5ca2b2aff5d4e907f7af9a71470d29156220b5fa..99fd3123e6b1a3383a93a320197db335ff5c1644 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
@@ -26,14 +26,14 @@ class VaccinationQRCodeExtractor @Inject constructor(
 
     override fun canHandle(rawString: String): Boolean = rawString.startsWith(PREFIX)
 
-    override fun extract(rawString: String): VaccinationCertificateQRCode {
+    override fun extract(rawString: String, mode: QrCodeExtractor.Mode): VaccinationCertificateQRCode {
         CertificateQrCodeCensor.addQRCodeStringToCensor(rawString)
 
         val parsedData = rawString
             .removePrefix(PREFIX)
             .decodeBase45()
             .decompress()
-            .parse()
+            .parse(lenient = mode == QrCodeExtractor.Mode.CERT_VAC_LENIENT)
 
         return VaccinationCertificateQRCode(
             qrCode = rawString,
@@ -55,13 +55,13 @@ class VaccinationQRCodeExtractor @Inject constructor(
         throw InvalidVaccinationCertificateException(HC_ZLIB_DECOMPRESSION_FAILED)
     }
 
-    fun RawCOSEObject.parse(): DccData<VaccinationDccV1> = try {
+    fun RawCOSEObject.parse(lenient: Boolean): DccData<VaccinationDccV1> = try {
         Timber.v("Parsing COSE for vaccination certificate.")
         val cbor = coseDecoder.decode(this)
 
         DccData(
             header = headerParser.parse(cbor),
-            certificate = bodyParser.parse(cbor)
+            certificate = bodyParser.parse(cbor, lenient = lenient)
         ).also {
             CertificateQrCodeCensor.addCertificateToCensor(it)
         }.also {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeValidator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeValidator.kt
index 098ae60b3dee9511a2d5c57f29547982114cbad9..57c93cbf502ff71860761ac47d9b6b5354cc9902 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeValidator.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQRCodeValidator.kt
@@ -17,7 +17,7 @@ class VaccinationQRCodeValidator @Inject constructor(
         // If there is more than one "extractor" in the future, check censoring again.
         // CertificateQrCodeCensor.addQRCodeStringToCensor(rawString)
         return findExtractor(rawString)
-            ?.extract(rawString)
+            ?.extract(rawString, mode = QrCodeExtractor.Mode.CERT_VAC_STRICT)
             ?.also { Timber.i("Extracted data from QR code is %s", it) }
             ?: throw InvalidVaccinationCertificateException(VC_PREFIX_INVALID)
     }
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 61aa1c59989870f4ec1c28cb53496093cf72040b..ca7f06e31c442fba189536d5f1e0b3ea0a542730 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,6 +2,7 @@ package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storag
 
 import androidx.annotation.Keep
 import com.google.gson.annotations.SerializedName
+import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor.Mode
 import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier
 import de.rki.coronawarnapp.covidcertificate.common.certificate.DccData
 import de.rki.coronawarnapp.covidcertificate.common.certificate.DccHeader
@@ -31,7 +32,7 @@ data class VaccinationContainer internal constructor(
 
     @delegate:Transient
     internal val certificateData: DccData<VaccinationDccV1> by lazy {
-        preParsedData ?: qrCodeExtractor.extract(vaccinationQrCode).data
+        preParsedData ?: qrCodeExtractor.extract(vaccinationQrCode, mode = Mode.CERT_VAC_LENIENT).data
     }
 
     val header: DccHeader
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt
index ffb9537416eda49f1d4d29d61afed701da3542a7..b7ab20f24009e3d6493e570de8dcf8f8191f7643 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/ui/scan/VaccinationQrCodeScanFragment.kt
@@ -10,8 +10,10 @@ import com.google.zxing.BarcodeFormat
 import com.journeyapps.barcodescanner.DefaultDecoderFactory
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.bugreporting.ui.toErrorDialogBuilder
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidVaccinationCertificateException
 import de.rki.coronawarnapp.databinding.FragmentScanQrCodeBinding
 import de.rki.coronawarnapp.util.DialogHelper
+import de.rki.coronawarnapp.util.ExternalActionHelper.openUrl
 import de.rki.coronawarnapp.util.di.AutoInject
 import de.rki.coronawarnapp.util.permission.CameraPermissionHelper
 import de.rki.coronawarnapp.util.ui.doNavigate
@@ -67,6 +69,11 @@ class VaccinationQrCodeScanFragment :
             binding.qrCodeScanSpinner.hide()
             it.toErrorDialogBuilder(requireContext()).apply {
                 setOnDismissListener { popBackStack() }
+                if (it is InvalidVaccinationCertificateException && it.showFaqButton) {
+                    setNeutralButton(R.string.error_button_vc_faq) { _, _ ->
+                        openUrl(getString(R.string.error_button_vc_faq_link))
+                    }
+                }
             }.show()
         }
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt
index b7c535d6e3aff991e1e08a40d8a5560e19adb1ff..ab3433e8ae64f52ff3e1f2a746131cc96811dbdb 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInEvent.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.checkins
 
 import de.rki.coronawarnapp.presencetracing.checkins.CheckIn
 import de.rki.coronawarnapp.presencetracing.checkins.qrcode.VerifiedTraceLocation
+import de.rki.coronawarnapp.util.ui.LazyString
 
 sealed class CheckInEvent {
 
@@ -17,6 +18,8 @@ sealed class CheckInEvent {
 
     data class ConfirmSwipeItem(val checkIn: CheckIn, val position: Int) : CheckInEvent()
 
+    data class InvalidQrCode(val errorText: LazyString) : CheckInEvent()
+
     object ShowInformation : CheckInEvent()
 
     object OpenDeviceSettings : CheckInEvent()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt
index 2ca5bc2612083c3f9b6fc75ae8e1c6c923f468a1..73735fe037f5e681b4ffe38b8f083f628b2ea12f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsFragment.kt
@@ -31,6 +31,7 @@ import de.rki.coronawarnapp.util.lists.decorations.TopBottomPaddingDecorator
 import de.rki.coronawarnapp.util.lists.diffutil.update
 import de.rki.coronawarnapp.util.onScroll
 import de.rki.coronawarnapp.util.tryHumanReadableError
+import de.rki.coronawarnapp.util.ui.LazyString
 import de.rki.coronawarnapp.util.ui.doNavigate
 import de.rki.coronawarnapp.util.ui.observe2
 import de.rki.coronawarnapp.util.ui.viewBinding
@@ -66,14 +67,8 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag
         bindRecycler()
         bindFAB()
 
-        viewModel.checkins.observe2(this) { items ->
-            updateViews(items)
-        }
-
-        viewModel.events.observe2(this) {
-            onNavigationEvent(it)
-        }
-
+        viewModel.checkins.observe2(this) { items -> updateViews(items) }
+        viewModel.events.observe2(this) { it?.let { onNavigationEvent(it) } }
         viewModel.errorEvent.observe2(this) {
             val errorForHumans = it.tryHumanReadableError(requireContext())
             Toast.makeText(requireContext(), errorForHumans.description, Toast.LENGTH_LONG).show()
@@ -85,7 +80,7 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag
         viewModel.checkCameraSettings()
     }
 
-    private fun onNavigationEvent(event: CheckInEvent?) {
+    private fun onNavigationEvent(event: CheckInEvent) {
         when (event) {
             is CheckInEvent.ConfirmCheckIn -> {
                 setupAxisTransition()
@@ -127,9 +122,21 @@ class CheckInsFragment : Fragment(R.layout.trace_location_attendee_checkins_frag
                 doNavigate(CheckInsFragmentDirections.actionCheckInsFragmentToCheckInOnboardingFragment(false))
             }
             is CheckInEvent.OpenDeviceSettings -> openDeviceSettings()
+            is CheckInEvent.InvalidQrCode -> showInvalidQrCodeInformation(event.errorText)
         }
     }
 
+    private fun showInvalidQrCodeInformation(lazyErrorText: LazyString) {
+        val errorText = lazyErrorText.get(requireContext())
+        MaterialAlertDialogBuilder(requireContext())
+            .setTitle(R.string.trace_location_attendee_invalid_qr_code_dialog_title)
+            .setMessage(getString(R.string.trace_location_attendee_invalid_qr_code_dialog_message, errorText))
+            .setPositiveButton(R.string.trace_location_attendee_invalid_qr_code_dialog_positive_button) { _, _ ->
+                // NO-OP
+            }
+            .show()
+    }
+
     private fun updateViews(items: List<CheckInsItem>) {
         checkInsAdapter.update(items)
         binding.apply {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt
index 49ff5d5c58b886f892112fdbc136c6aa3a3cb786..c8aaf8345fc7b71785f2e44711f94f95207cbbb6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModel.kt
@@ -20,6 +20,8 @@ import de.rki.coronawarnapp.util.coroutine.AppScope
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.flow.intervalFlow
 import de.rki.coronawarnapp.util.ui.SingleLiveEvent
+import de.rki.coronawarnapp.util.ui.toLazyString
+import de.rki.coronawarnapp.util.ui.toResolvingString
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
 import de.rki.coronawarnapp.util.viewmodel.CWAViewModelFactory
 import kotlinx.coroutines.CoroutineScope
@@ -140,15 +142,24 @@ class CheckInsViewModel @AssistedInject constructor(
     }
 
     private fun verifyUri(uri: String) = launch {
-        Timber.i("uri: $uri")
-        val qrCodePayload = qrCodeUriParser.getQrCodePayload(uri)
-        when (val verifyResult = traceLocationVerifier.verifyTraceLocation(qrCodePayload)) {
-            is TraceLocationVerifier.VerificationResult.Valid -> events.postValue(
-                if (cleanHistory)
-                    CheckInEvent.ConfirmCheckInWithoutHistory(verifyResult.verifiedTraceLocation)
-                else
-                    CheckInEvent.ConfirmCheckIn(verifyResult.verifiedTraceLocation)
-            )
+        try {
+            Timber.i("uri: $uri")
+            val qrCodePayload = qrCodeUriParser.getQrCodePayload(uri)
+            when (val verifyResult = traceLocationVerifier.verifyTraceLocation(qrCodePayload)) {
+                is TraceLocationVerifier.VerificationResult.Valid -> events.postValue(
+                    if (cleanHistory)
+                        CheckInEvent.ConfirmCheckInWithoutHistory(verifyResult.verifiedTraceLocation)
+                    else
+                        CheckInEvent.ConfirmCheckIn(verifyResult.verifiedTraceLocation)
+                )
+                is TraceLocationVerifier.VerificationResult.Invalid -> events.postValue(
+                    CheckInEvent.InvalidQrCode(verifyResult.errorTextRes.toResolvingString())
+                )
+            }
+        } catch (e: Exception) {
+            Timber.d(e, "TraceLocation verification failed")
+            val msg = e.message ?: "QR-Code was invalid"
+            events.postValue(CheckInEvent.InvalidQrCode(msg.toLazyString()))
         }
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt
index 21b663e70d2ee6a4e9859658b1ae959827b7eb0d..0ccd319854341a807c7a5ceffe10ea6f51685831 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ui/ViewBindingExtensions.kt
@@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment
 import androidx.lifecycle.DefaultLifecycleObserver
 import androidx.lifecycle.LifecycleOwner
 import androidx.viewbinding.ViewBinding
+import com.google.android.material.bottomnavigation.BottomNavigationView
 import timber.log.Timber
 import kotlin.properties.ReadOnlyProperty
 import kotlin.reflect.KProperty
@@ -44,12 +45,13 @@ class ViewBindingProperty<ComponentT : LifecycleOwner, BindingT : ViewBinding>(
     private val onDestroyObserver = object : DefaultLifecycleObserver {
         // Called right before Fragment.onDestroyView
         override fun onDestroy(owner: LifecycleOwner) {
+            Timber.tag(TAG).v("onDestroy(%s)", owner)
             localRef?.lifecycle?.removeObserver(this) ?: return
 
             localRef = null
 
             uiHandler.post {
-                Timber.v("Resetting viewBinding")
+                Timber.tag(TAG).v("Resetting viewBinding owner=%s", owner)
                 viewBinding = null
             }
         }
@@ -58,15 +60,34 @@ class ViewBindingProperty<ComponentT : LifecycleOwner, BindingT : ViewBinding>(
     @MainThread
     override fun getValue(thisRef: ComponentT, property: KProperty<*>): BindingT {
         if (localRef == null && viewBinding != null) {
-            Timber.w("Fragment.onDestroyView() was called, but the handler didn't execute our delayed reset.")
+            Timber.tag(TAG).w(
+                "Fragment.onDestroyView(%s) was called, but the handler didn't execute our delayed reset.",
+                thisRef
+            )
             /**
-             * There is a fragment racecondition if you navigate to another fragment and quickly popBackStack().
+             * There is a fragment race condition if you navigate to another fragment and quickly popBackStack().
              * Our uiHandler.post { } will not have executed for some reason.
              * In that case we manually null the old viewBinding, to allow for clean recreation.
              */
             viewBinding = null
         }
 
+        /**
+         * This is a fix for an edge case where the fragment is created but was never visible to the user
+         * [DefaultLifecycleObserver.onDestroy] was never called despite that the [Fragment.onDestroyView] was called,
+         * therefore the ViewBinding will not be set to `null` and will hold the old view ,while Fragment will
+         * inflate a new [View] when navigating back to it. As result of that the screen ends being blank.
+         *
+         * This is very specific case when navigating by deeplink to one of the [BottomNavigationView] destinations,
+         * that is not the "home destination" of the graph.
+         */
+        (localRef as? Fragment)?.view?.let {
+            if (it != viewBinding?.root && localRef === thisRef) {
+                Timber.tag(TAG).w("Different view for the same fragment, resetting old viewBinding")
+                viewBinding = null
+            }
+        }
+
         viewBinding?.let {
             // Only accessible from within the same component
             require(localRef === thisRef)
@@ -76,9 +97,12 @@ class ViewBindingProperty<ComponentT : LifecycleOwner, BindingT : ViewBinding>(
         val lifecycle = lifecycleOwnerProvider(thisRef).lifecycle
 
         return bindingProvider(thisRef).also {
+            Timber.tag(TAG).d("bindingProvider(%s)", thisRef)
             viewBinding = it
             localRef = thisRef
             lifecycle.addObserver(onDestroyObserver)
         }
     }
 }
+
+private const val TAG = "ViewBindingExtension"
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_information.xml b/Corona-Warn-App/src/main/res/layout/fragment_information.xml
index bc53ba5441279ce8870bad5d40ae449452bf192e..6d7a5f498a266e3fcf2c71262da06becd2a1b89e 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_information.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_information.xml
@@ -122,7 +122,14 @@
                     android:paddingBottom="@dimen/spacing_tiny"
                     tools:text="16000000"
                     tools:visibility="visible" />
+
+                <!-- Workaround for scrolling issue where view is
+                approximately as high as available space-->
+                <Space
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/spacing_huge" />
             </LinearLayout>
+
         </ScrollView>
     </androidx.constraintlayout.widget.ConstraintLayout>
 </layout>
diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml
index 8d6853daebc5542e665479f3d2284195825f1590..dad249239d005a512851feaeb41259eba8f1782d 100644
--- a/Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml
+++ b/Corona-Warn-App/src/main/res/layout/vaccination_home_card.xml
@@ -27,7 +27,7 @@
         android:layout_marginTop="@dimen/spacing_small"
         android:accessibilityHeading="true"
         android:focusable="false"
-        android:text="@string/vaccination_card_registration_title_line_1"
+        android:text="@string/vaccination_card_status_title_line_1"
         android:textColor="@color/colorTextPrimary1InvertedStable"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
@@ -41,7 +41,7 @@
         android:layout_marginHorizontal="@dimen/card_padding"
         android:accessibilityHeading="true"
         android:focusable="false"
-        android:text="@string/vaccination_card_registration_title_line_2"
+        android:text="@string/vaccination_card_status_title_line_2"
         android:textColor="@color/colorTextPrimary1InvertedStable"
         android:textStyle="bold"
         app:layout_constraintEnd_toEndOf="parent"
diff --git a/Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml b/Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml
index 8da269c8163145d38375e0e578e9fa33dde004b6..32bfb351b107bc3ca070de3870499eb284cb14b0 100644
--- a/Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml
+++ b/Corona-Warn-App/src/main/res/layout/vaccination_home_immune_card.xml
@@ -27,7 +27,7 @@
         android:layout_marginTop="@dimen/spacing_small"
         android:accessibilityHeading="true"
         android:focusable="false"
-        android:text="@string/vaccination_card_registration_title_line_1"
+        android:text="@string/vaccination_card_status_title_line_1"
         android:textColor="@color/colorTextPrimary1InvertedStable"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
@@ -41,7 +41,7 @@
         android:layout_marginHorizontal="@dimen/card_padding"
         android:accessibilityHeading="true"
         android:focusable="false"
-        android:text="@string/vaccination_card_registration_title_line_2"
+        android:text="@string/vaccination_card_status_title_line_2"
         android:textColor="@color/colorTextPrimary1InvertedStable"
         android:textStyle="bold"
         app:layout_constraintEnd_toEndOf="parent"
diff --git a/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml
index 6eeeb4c291f99bd1526977a9094253cd04784d8e..fe8bd5d56c8839e6420023b221c98576bb25c0d9 100644
--- a/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/vaccination_strings.xml
@@ -48,9 +48,9 @@
     <!-- XBUT: Vaccination List delete button -->
     <string name="vaccination_list_delete_button">"Изтриване"</string>
     <!-- XTXT: Vaccination List deletion dialog title-->
-    <string name="vaccination_list_deletion_dialog_title">"Желаете ли да изтриете сертификата за ваксиниране?"</string>
+    <string name="vaccination_list_deletion_dialog_title">"Желаете ли да изтриете ваксинационния сертификат?"</string>
     <!-- XTXT: Vaccination List deletion dialog message-->
-    <string name="vaccination_list_deletion_dialog_message">"Ако изтриете сертификата за ваксиниране, приложението вече няма да може да използва ваксинацията за удостоверяване на вашия ваксинационен статус."</string>
+    <string name="vaccination_list_deletion_dialog_message">"Ако изтриете сертификата, приложението вече няма да може да използва тази ваксинация за удостоверяване на вашия ваксинационен статус."</string>
     <!-- XBUT: Vaccination List deletion dialog positive button-->
     <string name="vaccination_list_deletion_dialog_positive_button">"Изтриване"</string>
     <!-- XBUT: Vaccination List deletion dialog negative button-->
@@ -86,15 +86,15 @@
     </plurals>
 
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_invalid">"Този QR код не е валиден сертификат за ваксиниране."</string>
+    <string name="error_vc_invalid">"Този QR не е валиден ваксинационен сертификат.\n\nЗа да разберете как можете да се сдобиете със сертификат за извършена ваксинация, вижте страницата ни с често задавани въпроси (ЧЗВ)."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_not_yet_supported">"Този сертификат за ваксиниране все още не се поддържа във версията на вашето приложение. Моля, актуализирайте приложението си или се свържете с горещата линия за технически проблеми от “Информация за приложението”."</string>
+    <string name="error_vc_not_yet_supported">"Този ваксинационен сертификат все още не се поддържа във версията на Вашето приложение. Моля, актуализирайте приложението си или се свържете с горещата линия за технически проблеми, посочена в „Информация за приложението“."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_scan_again">"Сертификатът за ваксиниране не може да бъде запазен на смартфона ви. Моля, опитайте отново по-късно или се свържете с горещата линия за технически проблеми от “Информация за приложението”."</string>
+    <string name="error_vc_scan_again">"Ваксинационният сертификат не може да бъде запазен на смартфона Ви. Моля, опитайте отново по-късно или се свържете с горещата линия за технически проблеми, посочена в „Информация за приложението“."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_already_registered">"Сертификатът за ваксиниране вече е регистриран в приложението ви."</string>
+    <string name="error_vc_already_registered">"Ваксинационният сертификат вече е регистриран в приложението Ви."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_different_person">"Личната информация в този сертификат за ваксиниране не съответства на тази във вече регистрираните сертификати. В приложението можете да регистрирате сертификати само за едно лице."</string>
+    <string name="error_vc_different_person">"Личната информация в този ваксинационен сертификат не съответства на тази във вече регистрираните сертификати. В приложението можете да регистрирате сертификати само за едно лице."</string>
 
     <!-- XTXT: Vaccination Consent title-->
     <string name="vaccination_consent_title">"Вашето съгласие"</string>
@@ -112,5 +112,9 @@
     <string name="vaccination_consent_onboarding_legal_information">"За повече информация относно обработката на данни, прочетете декларацията за поверителност."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Напред"</string>
+    <!-- XBUT: Text for invalid vaccination certificate error button, linking to FAQ-->
+    <string name="error_button_vc_faq">"ЧЗВ за ваксинационни сертификати"</string>
+    <!-- XTXT: Explains user about vaccination certificate: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#vac_cert_invalid -->
+    <string name="error_button_vc_faq_link">"https://www.coronawarn.app/en/faq/#vac_cert_invalid"</string>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml
index 073658eb88562ccd8179fb6d7d22387431636cd3..5dac53f66a7249075be755c34e1f42a74a3e98f1 100644
--- a/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/vaccination_strings.xml
@@ -91,7 +91,7 @@
     <string name="vaccination_card_status_vaccination_complete">"Gültig bis einschließlich %s"</string>
 
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_invalid">Dieser QR-Code ist kein gültiges Impfzertifikat.</string>
+    <string name="error_vc_invalid">Dieser QR-Code ist kein gültiges Impfzertifikat.\n\nWeitere Informationen zum Erhalt Ihres Impfzertifikats finden Sie in den FAQ.</string>
     <!-- XTXT: Vaccination QR code scan error message-->
     <string name="error_vc_not_yet_supported">Dieses Impfzertifikat wird in Ihrer App-Version noch nicht unterstützt. Bitte aktualisieren Sie Ihre App oder wenden Sie sich an die technische Hotline unter „App-Informationen“.</string>
     <!-- XTXT: Vaccination QR code scan error message-->
@@ -117,5 +117,9 @@
     <string name="vaccination_consent_onboarding_legal_information">"Ausführliche Informationen zur Datenverarbeitung finden Sie in der Datenschutzerklärung."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Weiter"</string>
+    <!-- XBUT: Text for invalid vaccination certificate error button, linking to FAQ-->
+    <string name="error_button_vc_faq">FAQ zu Impfzertifikaten</string>
+    <!-- XTXT: Explains user about vaccination certificate: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#vac_cert_invalid -->
+    <string name="error_button_vc_faq_link">https://www.coronawarn.app/de/faq/#vac_cert_invalid</string>
 
 </resources>
diff --git a/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml
index 7ba8457914219ee27e49c4a26182a820c56031a0..e9f2c33cfe132f9ed57c4cc8c892449411360a5d 100644
--- a/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/vaccination_strings.xml
@@ -86,7 +86,7 @@
     </plurals>
 
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_invalid">"This QR code is not a valid vaccination certificate."</string>
+    <string name="error_vc_invalid">"This QR code is not a valid vaccination certificate.\n\nFor more information about how to receive your vaccination certificate, please see our FAQ page."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
     <string name="error_vc_not_yet_supported">"This vaccination certificate is not supported in your app version yet. Please update your app or contact the technical hotline under “App Information”."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
@@ -112,5 +112,9 @@
     <string name="vaccination_consent_onboarding_legal_information">"For more detailed information about data processing, please refer to the privacy notice."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Continue"</string>
+    <!-- XBUT: Text for invalid vaccination certificate error button, linking to FAQ-->
+    <string name="error_button_vc_faq">"FAQ for Vaccination Certificates"</string>
+    <!-- XTXT: Explains user about vaccination certificate: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#vac_cert_invalid -->
+    <string name="error_button_vc_faq_link">"https://www.coronawarn.app/en/faq/#vac_cert_invalid"</string>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml
index b0453ba0a663964ad8981315f5c3bca5759cce57..fbf8ad38370692383771ad67cd0f82eaf5a0b287 100644
--- a/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/vaccination_strings.xml
@@ -86,7 +86,7 @@
     </plurals>
 
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_invalid">"Ten kod QR nie jest ważnym świadectwem szczepienia."</string>
+    <string name="error_vc_invalid">"Ten kod QR nie jest ważnym świadectwem szczepienia.\n\nWięcej informacji na temat tego, jak otrzymać swoje świadectwo szczepienia, znajduje się na naszej stronie „Często zadawane pytania”."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
     <string name="error_vc_not_yet_supported">"To świadectwo szczepienia nie jest jeszcze obsługiwane w Twojej wersji aplikacji. Zaktualizuj aplikację lub skontaktuj się z infolinią techniczną dostępną w sekcji „Informacje o aplikacji”."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
@@ -112,5 +112,9 @@
     <string name="vaccination_consent_onboarding_legal_information">"Więcej informacji na temat przetwarzania danych znajduje się w oświadczeniu o ochronie prywatności."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Kontynuuj"</string>
+    <!-- XBUT: Text for invalid vaccination certificate error button, linking to FAQ-->
+    <string name="error_button_vc_faq">"Często zadawane pytania na temat świadectw szczepień"</string>
+    <!-- XTXT: Explains user about vaccination certificate: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#vac_cert_invalid -->
+    <string name="error_button_vc_faq_link">"https://www.coronawarn.app/en/faq/#vac_cert_invalid"</string>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml
index 94892166137f4678ec56347e3ab69beac5b9893e..276ff68ee28120c6141de936946719d1c965f212 100644
--- a/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/vaccination_strings.xml
@@ -86,7 +86,7 @@
     </plurals>
 
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_invalid">"Acest cod QR nu este un certificat de vaccinare valabil."</string>
+    <string name="error_vc_invalid">"Acest cod QR nu este un certificat de vaccinare valabil.\n\nPentru mai multe informații despre modul în care puteți primi certificatul dvs. de vaccinare, consultați pagina noastră de întrebări frecvente."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
     <string name="error_vc_not_yet_supported">"Acest certificat de vaccinare nu este încă acceptat de versiunea aplicației dvs. Actualizați-vă aplicația sau contactați hotline-ul tehnic din „Informații aplicație”."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
@@ -112,5 +112,9 @@
     <string name="vaccination_consent_onboarding_legal_information">"Pentru mai multe informații despre prelucrarea datelor, consultați înștiințarea de confidențialitate."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Continuare"</string>
+    <!-- XBUT: Text for invalid vaccination certificate error button, linking to FAQ-->
+    <string name="error_button_vc_faq">"Întrebări frecvente privind certificatele de vaccinare"</string>
+    <!-- XTXT: Explains user about vaccination certificate: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#vac_cert_invalid -->
+    <string name="error_button_vc_faq_link">"https://www.coronawarn.app/en/faq/#vac_cert_invalid"</string>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml
index 90a2fe7d930d9215b73f187569875264b208e2ec..b0657b9bd66120e133e6c702353adb9a6e66e791 100644
--- a/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/vaccination_strings.xml
@@ -86,7 +86,7 @@
     </plurals>
 
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_invalid">"Bu QR kod geçerli bir aşı sertifikası değildir."</string>
+    <string name="error_vc_invalid">"Bu QR kodu geçerli bir aşı sertifikası değildir.\n\nAşı sertifikanızı nasıl alacağınız hakkında daha fazla bilgi için lütfen SSS sayfamıza bakın."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
     <string name="error_vc_not_yet_supported">"Bu aşı sertifikası henüz uygulamanızın sürümünde desteklenmiyor. Lütfen uygulamanızı güncelleyin veya “Uygulama Bilgileri” bölümünde belirtilen teknik yardım hattı ile iletişime geçin."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
@@ -112,5 +112,9 @@
     <string name="vaccination_consent_onboarding_legal_information">"Veri işleme hakkında daha ayrıntılı bilgi için lütfen gizlilik bildirimine başvurun."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Devam Et"</string>
+    <!-- XBUT: Text for invalid vaccination certificate error button, linking to FAQ-->
+    <string name="error_button_vc_faq">"Aşı Sertifikaları için SSS"</string>
+    <!-- XTXT: Explains user about vaccination certificate: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#vac_cert_invalid -->
+    <string name="error_button_vc_faq_link">"https://www.coronawarn.app/en/faq/#vac_cert_invalid"</string>
 
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/values/vaccination_strings.xml b/Corona-Warn-App/src/main/res/values/vaccination_strings.xml
index fd2e7fedf15353a3b458ff5bffe859868add1115..275edfe95a43f0098c32624bb8ce7dd9627c4632 100644
--- a/Corona-Warn-App/src/main/res/values/vaccination_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/vaccination_strings.xml
@@ -92,7 +92,7 @@
     <!-- XTXT: Homescreen card complete vaccination status label -->
     <string name="vaccination_card_status_vaccination_complete">"Gültig bis einschließlich %s"</string>
     <!-- XTXT: Vaccination QR code scan error message-->
-    <string name="error_vc_invalid">"This QR code is not a valid vaccination certificate."</string>
+    <string name="error_vc_invalid">"This QR code is not a valid vaccination certificate.\n\nFor more information about how to receive your vaccination certificate, please see our FAQ page."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
     <string name="error_vc_not_yet_supported">"This vaccination certificate is not supported in your app version yet. Please update your app or contact the technical hotline under “App Information”."</string>
     <!-- XTXT: Vaccination QR code scan error message-->
@@ -118,5 +118,9 @@
     <string name="vaccination_consent_onboarding_legal_information">"For more detailed information about data processing, please refer to the privacy notice."</string>
     <!-- XBUT: Text for vaccination consent accept button -->
     <string name="vaccination_consent_accept_button">"Continue"</string>
+    <!-- XBUT: Text for invalid vaccination certificate error button, linking to FAQ-->
+    <string name="error_button_vc_faq">"FAQ for Vaccination Certificates"</string>
+    <!-- XTXT: Explains user about vaccination certificate: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#vac_cert_invalid -->
+    <string name="error_button_vc_faq_link">"https://www.coronawarn.app/en/faq/#vac_cert_invalid"</string>
 
-</resources>
\ No newline at end of file
+</resources>
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQrCodeValidatorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQrCodeValidatorTest.kt
index f9665d0af78f7a9f90b8e8157cd5d915f0e689af..e5cdb3f4c89a6d10f13910bbc6610c7cbb7ebf9f 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQrCodeValidatorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQrCodeValidatorTest.kt
@@ -1,16 +1,21 @@
 package de.rki.coronawarnapp.coronatest.qrcode
 
+import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor.Mode
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import io.kotest.assertions.throwables.shouldThrow
 import io.kotest.matchers.shouldBe
+import io.mockk.spyk
+import io.mockk.verify
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 
 class CoronaTestQrCodeValidatorTest : BaseTest() {
+    private val raExtractor = spyk(RapidAntigenQrCodeExtractor())
+    private val pcrExtractor = spyk(PcrQrCodeExtractor())
 
     @Test
     fun `valid codes are extracted by corresponding extractor`() {
-        val instance = CoronaTestQrCodeValidator(RapidAntigenQrCodeExtractor(), PcrQrCodeExtractor())
+        val instance = CoronaTestQrCodeValidator(raExtractor, pcrExtractor)
         instance.validate(pcrQrCode1).type shouldBe CoronaTest.Type.PCR
         instance.validate(pcrQrCode2).type shouldBe CoronaTest.Type.PCR
         instance.validate(pcrQrCode3).type shouldBe CoronaTest.Type.PCR
@@ -22,7 +27,7 @@ class CoronaTestQrCodeValidatorTest : BaseTest() {
     @Test
     fun `invalid prefix throws exception`() {
         val invalidCode = "HTTPS://somethingelse/?123456-12345678-1234-4DA7-B166-B86D85475064"
-        val instance = CoronaTestQrCodeValidator(RapidAntigenQrCodeExtractor(), PcrQrCodeExtractor())
+        val instance = CoronaTestQrCodeValidator(raExtractor, pcrExtractor)
         shouldThrow<InvalidQRCodeException> {
             instance.validate(invalidCode)
         }
@@ -31,9 +36,18 @@ class CoronaTestQrCodeValidatorTest : BaseTest() {
     @Test
     fun `invalid json throws exception`() {
         val invalidCode = "https://s.coronawarn.app/?v=1#eyJ0aW1lc3RhbXAiOjE2"
-        val instance = CoronaTestQrCodeValidator(RapidAntigenQrCodeExtractor(), PcrQrCodeExtractor())
+        val instance = CoronaTestQrCodeValidator(raExtractor, pcrExtractor)
         shouldThrow<InvalidQRCodeException> {
             instance.validate(invalidCode)
         }
     }
+
+    @Test
+    fun `validator uses strict extraction mode`() {
+        val instance = CoronaTestQrCodeValidator(raExtractor, pcrExtractor)
+        instance.validate(pcrQrCode1).type shouldBe CoronaTest.Type.PCR
+        verify { pcrExtractor.extract(pcrQrCode1, Mode.TEST_STRICT) }
+        instance.validate(raQrCode1).type shouldBe CoronaTest.Type.RAPID_ANTIGEN
+        verify { raExtractor.extract(raQrCode1, Mode.TEST_STRICT) }
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/PcrQrCodeExtractorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/PcrQrCodeExtractorTest.kt
index e4537ff5a6113f3d0c46a6691851bdf94a3a9a69..86e1812719a3d4b1289a23f9568f14f8adc72833 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/PcrQrCodeExtractorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/PcrQrCodeExtractorTest.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.coronatest.qrcode
 
+import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor.Mode.TEST_STRICT
 import io.kotest.matchers.shouldBe
 import org.junit.Test
 import testhelpers.BaseTest
@@ -16,7 +17,7 @@ class PcrQrCodeExtractorTest : BaseTest() {
         val extractor = PcrQrCodeExtractor()
         try {
             if (extractor.canHandle("$prefixString$guid")) {
-                extractor.extract("$prefixString$guid")
+                extractor.extract("$prefixString$guid", mode = TEST_STRICT)
                 conditionToMatch shouldBe true
             } else {
                 conditionToMatch shouldBe false
@@ -77,16 +78,43 @@ class PcrQrCodeExtractorTest : BaseTest() {
 
     @Test
     fun extractGUID() {
-        PcrQrCodeExtractor().extract("$localhostUpperCase$guidUpperCase").qrCodeGUID shouldBe guidUpperCase
-        PcrQrCodeExtractor().extract("$localhostUpperCase$guidLowerCase").qrCodeGUID shouldBe guidLowerCase
-        PcrQrCodeExtractor().extract("$localhostUpperCase$guidMixedCase").qrCodeGUID shouldBe guidMixedCase
+        PcrQrCodeExtractor().extract(
+            "$localhostUpperCase$guidUpperCase",
+            mode = TEST_STRICT
+        ).qrCodeGUID shouldBe guidUpperCase
+        PcrQrCodeExtractor().extract(
+            "$localhostUpperCase$guidLowerCase",
+            mode = TEST_STRICT
+        ).qrCodeGUID shouldBe guidLowerCase
+        PcrQrCodeExtractor().extract(
+            "$localhostUpperCase$guidMixedCase",
+            mode = TEST_STRICT
+        ).qrCodeGUID shouldBe guidMixedCase
 
-        PcrQrCodeExtractor().extract("$localhostLowerCase$guidUpperCase").qrCodeGUID shouldBe guidUpperCase
-        PcrQrCodeExtractor().extract("$localhostLowerCase$guidLowerCase").qrCodeGUID shouldBe guidLowerCase
-        PcrQrCodeExtractor().extract("$localhostLowerCase$guidMixedCase").qrCodeGUID shouldBe guidMixedCase
+        PcrQrCodeExtractor().extract(
+            "$localhostLowerCase$guidUpperCase",
+            mode = TEST_STRICT
+        ).qrCodeGUID shouldBe guidUpperCase
+        PcrQrCodeExtractor().extract(
+            "$localhostLowerCase$guidLowerCase",
+            mode = TEST_STRICT
+        ).qrCodeGUID shouldBe guidLowerCase
+        PcrQrCodeExtractor().extract(
+            "$localhostLowerCase$guidMixedCase",
+            mode = TEST_STRICT
+        ).qrCodeGUID shouldBe guidMixedCase
 
-        PcrQrCodeExtractor().extract("$localhostMixedCase$guidUpperCase").qrCodeGUID shouldBe guidUpperCase
-        PcrQrCodeExtractor().extract("$localhostMixedCase$guidLowerCase").qrCodeGUID shouldBe guidLowerCase
-        PcrQrCodeExtractor().extract("$localhostMixedCase$guidMixedCase").qrCodeGUID shouldBe guidMixedCase
+        PcrQrCodeExtractor().extract(
+            "$localhostMixedCase$guidUpperCase",
+            mode = TEST_STRICT
+        ).qrCodeGUID shouldBe guidUpperCase
+        PcrQrCodeExtractor().extract(
+            "$localhostMixedCase$guidLowerCase",
+            mode = TEST_STRICT
+        ).qrCodeGUID shouldBe guidLowerCase
+        PcrQrCodeExtractor().extract(
+            "$localhostMixedCase$guidMixedCase",
+            mode = TEST_STRICT
+        ).qrCodeGUID shouldBe guidMixedCase
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractorTest.kt
index e78658b69175283df92b1e3ebb58182c62749a61..4a746b6edd43282f85b60c2a88039eb7194f42e4 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/qrcode/RapidAntigenQrCodeExtractorTest.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.coronatest.qrcode
 
+import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor.Mode.TEST_STRICT
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
 import io.kotest.assertions.throwables.shouldThrow
 import io.kotest.matchers.shouldBe
@@ -29,13 +30,13 @@ class RapidAntigenQrCodeExtractorTest : BaseTest() {
     @Test
     fun `extracting valid codes does not throw exception`() {
         listOf(raQrCode1, raQrCode2, raQrCode3, raQrCode4, raQrCode5, raQrCode6, raQrCode7, raQrCode8).forEach {
-            instance.extract(it)
+            instance.extract(it, mode = TEST_STRICT)
         }
     }
 
     @Test
     fun `personal data is extracted`() {
-        val data = instance.extract(raQrCode3)
+        val data = instance.extract(raQrCode3, mode = TEST_STRICT)
         data.type shouldBe CoronaTest.Type.RAPID_ANTIGEN
         data.hash shouldBe "7dce08db0d4abd5ac1d2498b571afb221ca947c75c847d05466b4cfe9d95dc66"
         data.createdAt shouldBe Instant.ofEpochMilli(1619618352000)
@@ -46,7 +47,7 @@ class RapidAntigenQrCodeExtractorTest : BaseTest() {
 
     @Test
     fun `empty strings are treated as null or notset`() {
-        val data = instance.extract(raQrCodeEmptyStrings)
+        val data = instance.extract(raQrCodeEmptyStrings, mode = TEST_STRICT)
         data.type shouldBe CoronaTest.Type.RAPID_ANTIGEN
         data.hash shouldBe "d6e4d0181d8109bf05b346a0d2e0ef0cc472eed70d9df8c4b9ae5c7a009f3e34"
         data.createdAt shouldBe Instant.ofEpochMilli(1619012952000)
@@ -57,14 +58,14 @@ class RapidAntigenQrCodeExtractorTest : BaseTest() {
 
     @Test
     fun `personal data is only valid if complete or completely missing`() {
-        shouldThrow<InvalidQRCodeException> { instance.extract(raQrIncompletePersonalData) }
+        shouldThrow<InvalidQRCodeException> { instance.extract(raQrIncompletePersonalData, mode = TEST_STRICT) }
     }
 
     @Test
     fun `invalid json throws exception`() {
         val invalidCode = "https://s.coronawarn.app/?v=1#eyJ0aW1lc3RhbXAiOjE2"
         shouldThrow<InvalidQRCodeException> {
-            RapidAntigenQrCodeExtractor().extract(invalidCode)
+            RapidAntigenQrCodeExtractor().extract(invalidCode, mode = TEST_STRICT)
         }
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationQrCodeTestData.java b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationQrCodeTestData.java
index 57d6ad6ef5d0542319e8a2716773624f6ca2ec45..449bb349b7bde6a840af11ed0f3c40bf32b3981a 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationQrCodeTestData.java
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationQrCodeTestData.java
@@ -10,4 +10,9 @@ public class VaccinationQrCodeTestData {
     static public String qrCodeWithNonsenseCountry = "HC1:NCF3Y28.P-O0PS3JPU7RBWBA2*9VTS/9VZ+PLUOVTJ$EB7W3R9B3VN/3A44E./EZ.6Y8C$.C.IK6MA$00J1TQZ9$9IU+S7HP%X9%*MW09:4WB/5SWB20V5VFBBREWO+GIIUF4+PBZR7MNX/N1JIIML/X3Z.Q67RMB6:BJYE26A5NNL:CIM-A*/UZTM+QO: ACV6212500GUC+KM-5AUYGUD1330PFBA855/SNDPCSOC3KMR9X$DB61.0AESG$:THFGP-M/VI2SG/ 22SS+V8OP3R8LDJ50HR6S94JMN-84Q0C+2/8FUV9HH6N91GB3/YCHN6ALFFZL3M116O/IBU6QKJK/3FMQ0TLK-.UQOO$%A $J%H0%*J:DE6/DOKTG*F605WRK8G7S96JG0 4IF:B9VM0CIBRF/XNBOH9 SGIFJ/2CX593I0GE7FFDEQ6+UO5D+HM/2IDBI.ET/L725IHPKB/T/Q9KRJ* NOWN$6K8VOZIHJ5R29KQWSPYKYSDZRJ+1IVBFGPMXEVY6JIYI/ CVBTJ-FY%MO%RUTF17S:1OL8PVXHRPTUOTK/VF%U%:IR G";
     static public String qrCodeWithNullValues = "HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH.TAIOO6+I2HU7A28WAI1G$H4AT4V22F/8X*G8QHJUPZ0BR/S09T./0LWTKD33236J3TA3M*4VV2 73-E3GG396B-43O058YIB73A*G3W19UEBY5:PIDHGNTI4L6YO1%UG/YL WO*Z7ON1 *L:O8PN1QP5O PLU9A/RUX96 B0V1ZZB.T12.H.ZJ$%HN 9GTBIQ16-I5NI5K1*TB3:U-1VVS1UU15%HVLIWQHYZKOP6OH6XO9IE5IVU5P2-GA*PE1H6IO2OO9$G40GHS-O:S9UZ4+FJE 4Y3L 78OAJ/9TL4T1C9 UPVD5BT17$1MV15K1DR1FIEC2F5+1T+UC2FSH9 UP+/UXJDTW5CL52U50$EZ*N.KUW*P .UUQKC.U%KIP3FY5LG1A614I%KZYNNEVQ KB+P8$JG+SB.V Q5FN9ZK1BCTD PPQ3X:J15RM*F9TVYPVE6G1OU-5Q.-OP*17:FX+52AWI1C0:HPE2%90Q:H2SFUGVP56O1W:W7MEGZNBC3WJ0J:*JITJ%W6XK2L3S.GA/S14 FD$G";
     static public String qrCodeBlankLastNameStandardized = "HC1:NCFOXN%TS3DH3ZSUZK+.V0ETD%65NL-AH:XIIOO6+ID7BO:H.I5B88MQ3ZMIN9HNO4*J8OX4W$C2VL*LA 43/IE%TE6UG+ZEAT1HQ13W1:O1YUI%F1PN1/T1%%HRP5 R14SI.J9DYHZROVZ05QNZ 20OP748$NI4L6YO1%UG/YL WO*Z7ON1 *L:O8PN1QP5O PLU9A/RUX96 B0V1ZZB.T12.H.ZJ$%HN 9GTBIQ16-I5NI5K1*TB3:U-1VVS1UU15%HVLIWQHYZKOP6OH6XO9IE5IVU5P2-GA*PE1H6IO2OO9$G40GHS-O:S9UZ4+FJE 4Y3L 78OAJ/9TL4T1C9 UP+B9MK93P5AW0:G9.G9/G9F:QQ28R3U6/V.*NT*QM.SY$N-P1S29 34S0BYBRC.UYS1U%O6QKN*Q5-QFRMLNKNM8LK4IYOP$I/XK$M8-L9HCI:ZH2E4UE1B4GC:DN5E:UNJ17$CS*J7.HRT:A /NFZ1FG7K-NXM693K+DD1ET2 D13ST$LGMUW/O7P6CJSZ9NC+Q6DJ1ZJ65QG9MS 1M$FRFTS50*G5V0";
+    // Multiple: Irregular date string: 1978-01-26T00:00:00
+    static public String qrCodeBulgaria = "HC1:NCFOXN*TS0BI$ZDYSHIAL*ECH 8S02109+D3NDC3LE84DIJ99HE1:G4G5%ZVGZ7:ZH6I1%4J.$2TM9*OVHABVCNN95ZTM.KM7755QLQQ5%YQ+GOSSP8/R2$Q.DPVGOP/R  QH$R387-WR9KRN95U/3P+9TG90OARH97KM4HGZJK HGX2MR$CXGG0U2XW4UZ2 NVV5TN%2UP20J5/5LEBFD-48YI+T4D-4HRVUMNMD3323R13-Y6C-4A+2XEN QT QTHC31M3+E3CP456L X4CZKHKB-43.E3KD3OAJ5%IWZKRA38M7323Q05.$S3U2JKB%RBKD3ZQTVJJ$+LQ3QR$P*NIV1JHQE.7W.GLA$2ECJYGCB%GLF9$DF8PQ9Z2*HNA-5NINJ4A*PO5FKYYNJK1G%UJ441JA4JBDC9PAGYCHK4GBLEH-BB.BECH 9MD-HBO55*E12MWKP/HLIJL8JF8JF172V2I0XTWYLM$EJ%MMWB:GSTHS:DW3ZJ0MD$NRF1OS6UE4VO4PFWL:IN9$RR.535T+TCZVFGZVXJPI1EUO9VOF+XBNOSJ/E32V4 L:XMHB0WAWIUJ";
+    static public String qrCodeSweden = "HC1:NCFOXN%TSMAHN-HVN8J7UQMJ4/3RZLH62V2G1PC9CMSRH+QKFNTAVD3B19*AJCBMF6.UCOMIN6R%E5BD7HG8CU6O8QGU68ORJSPAEQOIR+SPCVO.28DDQHQ1BW9XX7ZY7NTICZU1*8X/KQ96/-KKTCY73JC3KD3LWT HB3ZC64JX7JQ1LK$2965VMFD-48YI 3533LC4TZ0BR/S09T./0ZYTS P-$0R:67PPDFPVX1R270:6C$Q0R6EOMUF5LDCPF5RBQ746B46O1N646RM9AL5CBVW566LH 469/9-3AKI6%T6LEQ-P6UQK*%NH$RSC9FFFW+7H9N$W2JO2C6S3UJ92KEST.ZJ-8B ZJ83B 2TAAUZZ2LH2%EUBUJZ0KZPIR145%T0YIF0JEYI1DLNCK1627ACW-T%NSY18KT911GL.EHNTI+SB-5A-ARUQNFW$ 2:.NU6W/CU8WDTFVG:BG3JFCSAVH-4V:HP4$0/.D9OV-RM60R7Z3B8PXICK+L/S1P*O:FG";
+    // vaccinatedAt: Irregular date string: 2021-05-29T15:31:00+02:00
+    static public String qrCodePoland = "HC1:6BFOXN%TS3DH+M8.IAS0RTAN:2MCID:D42:O%CM9W48+5MOOP-I3Z58MJNC5FAPQHIZC4.OI1RM8ZA.A53XHMKN4NN3F85QNPZ0K8C$JCW0KK.A96UJBC.P2R9CZXIAHAPEDG8C5DL-9C.PDI9309D: C+8DV9CA$DPN0NTICZU80LZW4Z*AK.GNNVR*G0C7PHBO33/X086B QTVINMJJDG3AE3RK38FN:43JON$97*97:L32SJ.L78PJ/FJBINB/S7-SN2HOH03I31M3EG3J%4UZ2UI7Y6T4R2H4T8%K+-8*S2E6J1$48X2-36D-I/2DW9J0$9+Q6X46Q3QR$P2OIC0JBLI+USK3UBVTVIJM/I2OC8ALD-ILOVGKFWZ07Y4 CTZ/3+N0ZUIQJAZGA2:UG%UJMI:TU+MM0W5-R53W12XE2O14P3.2O55O:FA$VKN6HQK3OKPEON4QDN7T*.53%1/HVII9H2JS6VS%J*HBXUCY+TU5EBYL5%T3V79YG%Q90MURRHY5D6$NN6VAQI8OEH.5PQ2WJF";
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestComponent.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestComponent.kt
index 8d1e04bbb267f7c39592ba80aa9f8e725072164e..8bd1d78376d0bab27961029f022987fccad415eb 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestComponent.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationTestComponent.kt
@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.covidcertificate.vaccination.core
 import dagger.Component
 import dagger.Module
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeExtractorTest
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQrCodeValidatorTest
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.VaccinationRepositoryTest
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinationContainerTest
 import de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage.VaccinationStorageTest
@@ -23,6 +24,7 @@ interface VaccinationTestComponent {
     fun inject(testClass: VaccinationQRCodeExtractorTest)
     fun inject(testClass: VaccinatedPersonTest)
     fun inject(testClass: VaccinationRepositoryTest)
+    fun inject(testClass: VaccinationQrCodeValidatorTest)
 
     @Component.Factory
     interface Factory {
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 079022777951abd1eedc80dfd9e383b08853b2f4..be9583f22614ad2f72d4a36b2d31e572b36997d8 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
@@ -186,4 +186,14 @@ class VaccinationTestData @Inject constructor(
     ).apply {
         qrCodeExtractor = this@VaccinationTestData.qrCodeExtractor
     }
+
+    val personYVacTwoEntriesQrCode =
+        "HC1:6BFOXN%TSMAHN-HVN8J7UQMJ4/36 L-AHQ+R1WG%MP8*ICG5QKM0658WAULO8NASA3/-2E%5G%5TW5A 6YO6XL6Q3QR\$P*NI92KV6TKOJ06JYZJV1JJ7UGOJUTIJ7J:ZJ83BL8TFVTV9T.ZJC0J*PIZ.TJ STPT*IJ5OI9YI:8DJ:D%PDDIKIWCHAB.YMAHLW 70SO:GOLIROGO3T59YLY1S7HOPC5NDOEC5/64ND7BT5PE4D/5:/6N9R%EPXCROGO+GOVIR-PQ395R4IUHLW\$G-B5ET42HPPEPHCR6W97DON95N14Q6SP+PJD1W9L \$N3-Q.VBAO8MN9*QHAO96Y2/*13A5-8E6V59I9BZK6:IZW4I:A6J3ARN QT1BGL4OMJKR.K\$A1EB14UVC2O+5T3.CE1M33KS2JKA8Y*99CCLLOR/CH0GRP8 GLY 1LA7551DC2U.NVOTJOII:8DKEK%N92T9YQ$0MK%P6\$G9K7QQUY9KI.EK*8XRS-DPA5W64SMVR1NF6D0 2S0.7R:ASENTI094PIDS:T32DRE8N"
+
+    val personYVacTwoEntriesContainer = VaccinationContainer(
+        scannedAt = Instant.ofEpochMilli(1620062834471),
+        vaccinationQrCode = personYVacTwoEntriesQrCode,
+    ).apply {
+        qrCodeExtractor = this@VaccinationTestData.qrCodeExtractor
+    }
 }
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 f4f1ba9748525fed6f803688e938c4cf93953485..b0e8c2fbe520707ff46d6202355714fb1fcb468f 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
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode
 
+import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor.Mode
 import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidHealthCertificateException
 import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidHealthCertificateException.ErrorCode.HC_BASE45_DECODING_FAILED
 import de.rki.coronawarnapp.covidcertificate.common.exception.InvalidHealthCertificateException.ErrorCode.HC_CWT_NO_ISS
@@ -30,17 +31,17 @@ class VaccinationQRCodeExtractorTest : BaseTest() {
 
     @Test
     fun `happy path extraction`() {
-        extractor.extract(VaccinationQrCodeTestData.validVaccinationQrCode)
+        extractor.extract(VaccinationQrCodeTestData.validVaccinationQrCode, mode = Mode.CERT_VAC_STRICT)
     }
 
     @Test
     fun `happy path extraction 2`() {
-        extractor.extract(VaccinationQrCodeTestData.validVaccinationQrCode2)
+        extractor.extract(VaccinationQrCodeTestData.validVaccinationQrCode2, mode = Mode.CERT_VAC_STRICT)
     }
 
     @Test
     fun `happy path extraction with data`() {
-        val qrCode = extractor.extract(VaccinationQrCodeTestData.validVaccinationQrCode3)
+        val qrCode = extractor.extract(VaccinationQrCodeTestData.validVaccinationQrCode3, mode = Mode.CERT_VAC_STRICT)
 
         with(qrCode.data.header) {
             issuer shouldBe "AT"
@@ -77,60 +78,142 @@ class VaccinationQRCodeExtractorTest : BaseTest() {
 
     @Test
     fun `happy path extraction 4`() {
-        extractor.extract(VaccinationQrCodeTestData.validVaccinationQrCode4)
+        extractor.extract(
+            VaccinationQrCodeTestData.validVaccinationQrCode4,
+            mode = Mode.CERT_VAC_STRICT
+        )
     }
 
     @Test
     fun `valid encoding but not a health certificate fails with HC_CWT_NO_ISS`() {
         shouldThrow<InvalidVaccinationCertificateException> {
-            extractor.extract(VaccinationQrCodeTestData.validEncoded)
+            extractor.extract(
+                VaccinationQrCodeTestData.validEncoded,
+                mode = Mode.CERT_VAC_STRICT
+            )
         }.errorCode shouldBe HC_CWT_NO_ISS
     }
 
     @Test
     fun `random string fails with HC_BASE45_DECODING_FAILED`() {
         shouldThrow<InvalidVaccinationCertificateException> {
-            extractor.extract("nothing here to see")
+            extractor.extract(
+                "nothing here to see",
+                mode = Mode.CERT_VAC_STRICT
+            )
         }.errorCode shouldBe HC_BASE45_DECODING_FAILED
     }
 
     @Test
     fun `uncompressed base45 string fails with HC_ZLIB_DECOMPRESSION_FAILED`() {
         shouldThrow<InvalidVaccinationCertificateException> {
-            extractor.extract("6BFOABCDEFGHIJKLMNOPQRSTUVWXYZ %*+-./:")
+            extractor.extract(
+                "6BFOABCDEFGHIJKLMNOPQRSTUVWXYZ %*+-./:",
+                mode = Mode.CERT_VAC_STRICT
+            )
         }.errorCode shouldBe HC_ZLIB_DECOMPRESSION_FAILED
     }
 
     @Test
     fun `vaccination certificate missing fails with VC_NO_VACCINATION_ENTRY`() {
         shouldThrow<InvalidVaccinationCertificateException> {
-            extractor.extract(VaccinationQrCodeTestData.certificateMissing)
+            extractor.extract(
+                VaccinationQrCodeTestData.certificateMissing,
+                mode = Mode.CERT_VAC_STRICT
+            )
         }.errorCode shouldBe VC_NO_VACCINATION_ENTRY
     }
 
     @Test
     fun `test data person A check`() {
-        val extracted = extractor.extract(vaccinationTestData.personAVac1QRCodeString)
+        val extracted = extractor.extract(
+            vaccinationTestData.personAVac1QRCodeString,
+            mode = Mode.CERT_VAC_STRICT
+        )
         extracted shouldBe vaccinationTestData.personAVac1QRCode
     }
 
     @Test
     fun `test data person B check`() {
-        val extracted = extractor.extract(vaccinationTestData.personBVac1QRCodeString)
+        val extracted = extractor.extract(
+            vaccinationTestData.personBVac1QRCodeString,
+            mode = Mode.CERT_VAC_STRICT
+        )
         extracted shouldBe vaccinationTestData.personBVac1QRCode
     }
 
     @Test
     fun `null values fail with JSON_SCHEMA_INVALID`() {
         shouldThrow<InvalidVaccinationCertificateException> {
-            extractor.extract(VaccinationQrCodeTestData.qrCodeWithNullValues)
+            extractor.extract(
+                VaccinationQrCodeTestData.qrCodeWithNullValues,
+                mode = Mode.CERT_VAC_STRICT
+            )
         }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.JSON_SCHEMA_INVALID
     }
 
     @Test
     fun `blank name fails with JSON_SCHEMA_INVALID`() {
         shouldThrow<InvalidVaccinationCertificateException> {
-            extractor.extract(VaccinationQrCodeTestData.qrCodeBlankLastNameStandardized)
+            extractor.extract(
+                VaccinationQrCodeTestData.qrCodeBlankLastNameStandardized,
+                mode = Mode.CERT_VAC_STRICT
+            )
         }.errorCode shouldBe InvalidHealthCertificateException.ErrorCode.JSON_SCHEMA_INVALID
     }
+
+    @Test
+    fun `Bulgarian qr code passes`() {
+        val qrCode = extractor.extract(
+            VaccinationQrCodeTestData.qrCodeBulgaria,
+            mode = Mode.CERT_VAC_STRICT
+        )
+        with(qrCode.data.header) {
+            issuer shouldBe "BG"
+            issuedAt shouldBe Instant.parse("2021-06-02T14:07:56.000Z")
+            expiresAt shouldBe Instant.parse("2022-06-02T14:07:56.000Z")
+        }
+
+        with(qrCode.data.certificate) {
+            with(nameData) {
+                familyName shouldBe "ПЕТКОВ"
+                familyNameStandardized shouldBe "PETKOV"
+                givenName shouldBe "СТАМО ГЕОРГИЕВ"
+                givenNameStandardized shouldBe "STAMO<GEORGIEV"
+            }
+            dob shouldBe "1978-01-26T00:00:00"
+            dateOfBirth shouldBe LocalDate.parse("1978-01-26")
+            version shouldBe "1.0.0"
+
+            payload.apply {
+                uniqueCertificateIdentifier shouldBe "urn:uvci:01:BG:UFR5PLGKU8WDSZK7#0"
+                certificateCountry shouldBe "BG"
+                doseNumber shouldBe 2
+                dt shouldBe "2021-03-09T00:00:00"
+                certificateIssuer shouldBe "Ministry of Health"
+                marketAuthorizationHolderId shouldBe "ORG-100030215"
+                medicalProductId shouldBe "EU/1/20/1528"
+                totalSeriesOfDoses shouldBe 2
+                targetId shouldBe "840539006"
+                vaccineId shouldBe "J07BX03"
+                vaccinatedAt shouldBe LocalDate.parse("2021-03-09")
+            }
+        }
+    }
+
+    @Test
+    fun `Swedish qr code passes`() {
+        extractor.extract(
+            VaccinationQrCodeTestData.qrCodeSweden,
+            mode = Mode.CERT_VAC_STRICT
+        )
+    }
+
+    @Test
+    fun `Polish qr code passes`() {
+        extractor.extract(
+            VaccinationQrCodeTestData.qrCodePoland,
+            mode = Mode.CERT_VAC_STRICT
+        )
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQrCodeValidatorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQrCodeValidatorTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1a169d4301019ab3fb5a9b2efd5b234f8fe4660f
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/qrcode/VaccinationQrCodeValidatorTest.kt
@@ -0,0 +1,34 @@
+package de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode
+
+import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor.Mode
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.DaggerVaccinationTestComponent
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationTestData
+import io.kotest.matchers.shouldBe
+import io.mockk.spyk
+import io.mockk.verify
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+import javax.inject.Inject
+
+class VaccinationQrCodeValidatorTest : BaseTest() {
+    @Inject lateinit var testData: VaccinationTestData
+    @Inject lateinit var vacExtractor: VaccinationQRCodeExtractor
+    private lateinit var vacExtractorSpy: VaccinationQRCodeExtractor
+
+    @BeforeEach
+    fun setup() {
+        DaggerVaccinationTestComponent.factory().create().inject(this)
+
+        vacExtractorSpy = spyk(vacExtractor)
+    }
+
+    @Test
+    fun `validator uses strict extraction mode`() {
+        val instance = VaccinationQRCodeValidator(vacExtractorSpy)
+        instance.validate(testData.personAVac1QRCodeString).apply {
+            uniqueCertificateIdentifier shouldBe testData.personAVac1Container.certificateId
+        }
+        verify { vacExtractorSpy.extract(testData.personAVac1QRCodeString, Mode.CERT_VAC_STRICT) }
+    }
+}
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 7c9d5d97fbaabf88fb8e2f33441b956fa62a9746..2f27974c96c717524a926d978108c9e061e1bd90 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,11 +1,18 @@
 package de.rki.coronawarnapp.covidcertificate.vaccination.core.repository.storage
 
+import de.rki.coronawarnapp.coronatest.qrcode.QrCodeExtractor
 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.vaccination.core.qrcode.VaccinationCertificateQRCode
+import de.rki.coronawarnapp.covidcertificate.vaccination.core.qrcode.VaccinationQRCodeExtractor
 import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.DefaultValueSet
 import de.rki.coronawarnapp.covidcertificate.valueset.valuesets.VaccinationValueSets
 import io.kotest.matchers.shouldBe
+import io.kotest.matchers.shouldNotBe
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.verify
 import org.joda.time.Instant
 import org.joda.time.LocalDate
 import org.junit.jupiter.api.BeforeEach
@@ -137,4 +144,27 @@ class VaccinationContainerTest : BaseTest() {
             certificateCountry shouldBe "YY"
         }
     }
+
+    @Test
+    fun `default parsing mode for containers is lenient`() {
+        val container = VaccinationContainer(
+            vaccinationQrCode = testData.personYVacTwoEntriesQrCode,
+            scannedAt = Instant.EPOCH
+        )
+        val extractor = mockk<VaccinationQRCodeExtractor>().apply {
+            every { extract(any(), any()) } returns mockk<VaccinationCertificateQRCode>().apply {
+                every { data } returns mockk()
+            }
+        }
+        container.qrCodeExtractor = extractor
+
+        container.certificateData shouldNotBe null
+
+        verify { extractor.extract(testData.personYVacTwoEntriesQrCode, QrCodeExtractor.Mode.CERT_VAC_LENIENT) }
+    }
+
+    @Test
+    fun `gracefully handle semi invalid data - multiple entries`() {
+        testData.personYVacTwoEntriesContainer.certificate.payloads.size shouldBe 1
+    }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModelTest.kt
index dbb826612e6d7ebc4439768e9978e2e3030643ec..7045da2f2f847cbf441d5846d646700cd37224ec 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModelTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/presencetracing/attendee/checkins/CheckInsViewModelTest.kt
@@ -3,14 +3,17 @@ package de.rki.coronawarnapp.ui.presencetracing.attendee.checkins
 import androidx.lifecycle.SavedStateHandle
 import de.rki.coronawarnapp.presencetracing.checkins.CheckIn
 import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository
+import de.rki.coronawarnapp.presencetracing.checkins.checkout.CheckOutHandler
+import de.rki.coronawarnapp.presencetracing.checkins.qrcode.InvalidQrCodeDataException
+import de.rki.coronawarnapp.presencetracing.checkins.qrcode.InvalidQrCodeUriException
 import de.rki.coronawarnapp.presencetracing.checkins.qrcode.QRCodeUriParser
 import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocationVerifier
-import de.rki.coronawarnapp.presencetracing.checkins.checkout.CheckOutHandler
 import de.rki.coronawarnapp.server.protocols.internal.pt.TraceLocationOuterClass
 import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.items.ActiveCheckInVH
 import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.items.CameraPermissionVH
 import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.items.PastCheckInVH
 import de.rki.coronawarnapp.ui.presencetracing.attendee.checkins.permission.CameraPermissionProvider
+import io.kotest.assertions.throwables.shouldNotThrow
 import io.kotest.matchers.shouldBe
 import io.kotest.matchers.types.shouldBeInstanceOf
 import io.mockk.MockKAnnotations
@@ -180,6 +183,32 @@ class CheckInsViewModelTest : BaseTest() {
         }
     }
 
+    @Test
+    fun `Handle uri InvalidQrCodeUriException`() = runBlockingTest {
+        every { savedState.get<String>("deeplink.last") } returns null
+        coEvery { qrCodeUriParser.getQrCodePayload(any()) } throws InvalidQrCodeUriException("Invalid")
+        val url = "https://e.coronawarn.app?v=1#place_holder"
+
+        shouldNotThrow<InvalidQrCodeUriException> {
+            createInstance(deepLink = url, scope = this).apply {
+                events.getOrAwaitValue().shouldBeInstanceOf<CheckInEvent.InvalidQrCode>()
+            }
+        }
+    }
+
+    @Test
+    fun `Handle uri InvalidQrCodeDataException`() = runBlockingTest {
+        every { savedState.get<String>("deeplink.last") } returns null
+        coEvery { qrCodeUriParser.getQrCodePayload(any()) } throws InvalidQrCodeDataException("Invalid")
+        val url = "https://e.coronawarn.app?v=1#place_holder"
+
+        shouldNotThrow<InvalidQrCodeDataException> {
+            createInstance(deepLink = url, scope = this).apply {
+                events.getOrAwaitValue().shouldBeInstanceOf<CheckInEvent.InvalidQrCode>()
+            }
+        }
+    }
+
     private fun createInstance(deepLink: String?, scope: CoroutineScope) =
         CheckInsViewModel(
             savedState = savedState,