diff --git a/Corona-Warn-App/build.gradle b/Corona-Warn-App/build.gradle
index e019130e234c5583f3c222b03c296f93e0a3c42f..948ff9a9f433ca51ceebe8bfe1726be49a643aec 100644
--- a/Corona-Warn-App/build.gradle
+++ b/Corona-Warn-App/build.gradle
@@ -441,6 +441,4 @@ dependencies {
 
     // HCert
     implementation("com.upokecenter:cbor:4.4.1")
-
-    implementation("bouncycastle:bcprov-jdk16:136")
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/TestCertificateRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/TestCertificateRepository.kt
index 8f3c1b148093f66d685c9d294dc116a0c6fd898a..8656d45a6b112e8d2846d02d38e7ea926bad2495 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/TestCertificateRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/TestCertificateRepository.kt
@@ -8,6 +8,11 @@ import de.rki.coronawarnapp.coronatest.type.TestCertificateContainer
 import de.rki.coronawarnapp.coronatest.type.TestCertificateIdentifier
 import de.rki.coronawarnapp.coronatest.type.pcr.PCRCertificateContainer
 import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACertificateContainer
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.RSA_DECRYPTION_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.RSA_KP_GENERATION_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.InvalidTestCertificateException
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_202
 import de.rki.coronawarnapp.covidcertificate.server.CovidCertificateServer
 import de.rki.coronawarnapp.covidcertificate.server.TestCertificateComponents
 import de.rki.coronawarnapp.covidcertificate.test.TestCertificateQRCodeExtractor
@@ -247,7 +252,11 @@ class TestCertificateRepository @Inject constructor(
                 return cert
             }
 
-            val rsaKeyPair = rsaKeyPairGenerator.generate()
+            val rsaKeyPair = try {
+                rsaKeyPairGenerator.generate()
+            } catch (e: Throwable) {
+                throw InvalidTestCertificateException(RSA_KP_GENERATION_FAILED)
+            }
 
             withContext(dispatcherProvider.IO) {
                 certificateServer.registerPublicKeyForTest(
@@ -315,21 +324,29 @@ class TestCertificateRepository @Inject constructor(
 
                 try {
                     executeRequest()
-                } catch (e: Exception) {
-                    // TODO catch a specific error that reflects error code DGC_COMP_202
-                    delay(certConfig.waitForRetry.millis)
-                    executeRequest()
+                } catch (e: TestCertificateServerException) {
+                    if (e.errorCode == DCC_COMP_202) {
+                        delay(certConfig.waitForRetry.millis)
+                        executeRequest()
+                    } else {
+                        throw e
+                    }
                 }
             }
             Timber.tag(TAG).i("Test certificate components successfully request for %s: %s", cert, components)
 
-            val encryptionkey = rsaCryptography.decrypt(
-                toDecrypt = components.dataEncryptionKeyBase64.decodeBase64()!!,
-                privateKey = cert.rsaPrivateKey!!
-            )
+            val encryptionKey = try {
+                rsaCryptography.decrypt(
+                    toDecrypt = components.dataEncryptionKeyBase64.decodeBase64()!!,
+                    privateKey = cert.rsaPrivateKey!!
+                )
+            } catch (e: Throwable) {
+                Timber.tag(TAG).e(e, "RSA_DECRYPTION_FAILED")
+                throw InvalidTestCertificateException(RSA_DECRYPTION_FAILED)
+            }
 
             val extractedData = qrCodeExtractor.extract(
-                decryptionKey = encryptionkey.toByteArray(),
+                decryptionKey = encryptionKey.toByteArray(),
                 rawCoseObjectEncrypted = components.encryptedCoseTestCertificateBase64.decodeBase64()!!.toByteArray()
             )
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptography.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptography.kt
index 261fc2a020db85d8e5e56851dfdbbca88acc2234..ac294903083ca20e2b70d57069d63223fc9d7c18 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptography.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptography.kt
@@ -1,36 +1,24 @@
 package de.rki.coronawarnapp.covidcertificate.cryptography
 
 import com.google.android.gms.common.util.Hex
-import dagger.Reusable
-import org.bouncycastle.jce.provider.BouncyCastleProvider
-import org.bouncycastle.util.encoders.Base64.decode
-import java.security.Security
 import javax.crypto.Cipher
 import javax.crypto.spec.IvParameterSpec
 import javax.crypto.spec.SecretKeySpec
 import javax.inject.Inject
 
-@Reusable
 class AesCryptography @Inject constructor() {
 
-    private val ivParameterSpec
-        get() = IvParameterSpec(Hex.stringToBytes("00000000000000000000000000000000"))
-
     fun decrypt(
         decryptionKey: ByteArray,
         encryptedData: ByteArray
-    ): ByteArray {
-        Security.addProvider(BouncyCastleProvider())
-        val keySpec = SecretKeySpec(decode(decryptionKey), ALGORITHM)
-        val input = decode(encryptedData)
-        return with(Cipher.getInstance(TRANSFORMATION)) {
-            init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec)
-            val output = ByteArray(getOutputSize(input.size))
-            var outputLength = update(input, 0, input.size, output, 0)
-            outputLength += doFinal(output, outputLength)
-            output.copyOfRange(0, outputLength)
-        }
+    ): ByteArray = with(Cipher.getInstance(TRANSFORMATION)) {
+        val keySpec = SecretKeySpec(decryptionKey, ALGORITHM)
+        init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec)
+        doFinal(encryptedData)
     }
+
+    private val ivParameterSpec
+        get() = IvParameterSpec(Hex.stringToBytes("00000000000000000000000000000000"))
 }
 
 private const val ALGORITHM = "AES"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/ErrorMessage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/ErrorMessage.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9c96623b96597c703525b5bcea1542c234d6a8af
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/ErrorMessage.kt
@@ -0,0 +1,14 @@
+package de.rki.coronawarnapp.covidcertificate.exception
+
+import de.rki.coronawarnapp.R
+
+const val ERROR_MESSAGE_GENERIC = R.string.errors_generic_text_unknown_error_cause
+
+// TODO change to correct error message once provided
+const val ERROR_MESSAGE_TRY_AGAIN = ERROR_MESSAGE_GENERIC
+const val ERROR_MESSAGE_DCC_NOT_SUPPORTED_BY_LAB = ERROR_MESSAGE_GENERIC
+const val ERROR_MESSAGE_NO_NETWORK = ERROR_MESSAGE_GENERIC
+const val ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE = ERROR_MESSAGE_GENERIC
+const val ERROR_MESSAGE_TRY_AGAIN_DCC_NOT_AVAILABLE_YET = ERROR_MESSAGE_GENERIC
+const val ERROR_MESSAGE_CLIENT_ERROR_CALL_HOTLINE = ERROR_MESSAGE_GENERIC
+const val ERROR_MESSAGE_DCC_EXPIRED = ERROR_MESSAGE_GENERIC
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt
index 16b90b3db903c63889f85a15146735b99dfdea4f..fe31b111213737dbfc4e4fa7645e8950bf0b28ef 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidHealthCertificateException.kt
@@ -1,7 +1,6 @@
 package de.rki.coronawarnapp.covidcertificate.exception
 
 import android.content.Context
-import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.coronatest.qrcode.InvalidQRCodeException
 import de.rki.coronawarnapp.util.HasHumanReadableError
 import de.rki.coronawarnapp.util.HumanReadableError
@@ -34,26 +33,8 @@ open class InvalidHealthCertificateException(
         HC_CWT_NO_EXP("Expiration date missing."),
         HC_CWT_NO_HCERT("Health certificate missing."),
         HC_CWT_NO_ISS("Issuer missing."),
+
         AES_DECRYPTION_FAILED("AES decryption failed"),
-        DCC_COMP_202("DCC Test Certificate Components failed with error 202: DCC pending."),
-        DCC_COMP_400("DCC Test Certificate Components failed with error 400: Bad request (e.g. wrong format of registration token)"),
-        DCC_COMP_404("DCC Test Certificate Components failed with error 404: Registration token does not exist."),
-        DCC_COMP_410("DCC Test Certificate Components failed with error 410: DCC already cleaned up."),
-        DCC_COMP_412("DCC Test Certificate Components failed with error 412: Test result not yet received"),
-        DCC_COMP_500_INTERNAL("DCC Test Certificate Components failed with error 500: Internal server error."),
-        DCC_COMP_500_LAB_INVALID_RESPONSE("DCC Test Certificate Components failed with error 500: Lab Invalid response"),
-        DCC_COMP_500_SIGNING_CLIENT_ERROR("DCC Test Certificate Components failed with error 500: Signing client error"),
-        DCC_COMP_500_SIGNING_SERVER_ERROR("DCC Test Certificate Components failed with error 500: Signing server error"),
-        DCC_COMP_NO_NETWORK("DCC Test Certificate Components failed due to no network connection."),
-        DCC_COSE_MESSAGE_INVALID("COSE message invalid."),
-        DCC_COSE_TAG_INVALID("COSE tag invalid."),
-        PKR_400("Public Key Registration failed with error 400: Bad request (e.g. wrong format of registration token or public key)."),
-        PKR_403("Public Key Registration failed with error 403: Registration token is not allowed to issue a DCC."),
-        PKR_404("Public Key Registration failed with error 404: Registration token does not exist."),
-        PKR_409("Public Key Registration failed with error 409: Registration token is already assigned to a public key."),
-        PKR_500("Public Key Registration failed with error 500: Internal server error."),
-        PKR_FAILED("Private key request failed."),
-        PKR_NO_NETWORK("Private key request failed due to no network connection."),
         RSA_DECRYPTION_FAILED("RSA decryption failed."),
         RSA_KP_GENERATION_FAILED("RSA key pair generation failed."),
     }
@@ -65,9 +46,7 @@ open class InvalidHealthCertificateException(
 
     override fun toHumanReadableError(context: Context): HumanReadableError {
         return HumanReadableError(
-            description = errorMessage.get(context)
+            description = errorMessage.get(context) + "/n/n$errorCode"
         )
     }
 }
-
-private const val ERROR_MESSAGE_GENERIC = R.string.errors_generic_text_unknown_error_cause
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt
index ca8909e4605f99dc8bfbf1cc785ba622c60ad2dc..360301b1c893587a41a7087834bce0335e694cb6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/InvalidTestCertificateException.kt
@@ -1,92 +1,31 @@
 package de.rki.coronawarnapp.covidcertificate.exception
 
 import android.content.Context
-import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.util.HumanReadableError
 import de.rki.coronawarnapp.util.ui.CachedString
 import de.rki.coronawarnapp.util.ui.LazyString
 
 class InvalidTestCertificateException(errorCode: ErrorCode) : InvalidHealthCertificateException(errorCode) {
     override fun toHumanReadableError(context: Context): HumanReadableError {
-        var errorCodeString = errorCode.toString()
-        errorCodeString = if (errorCodeString.startsWith(PREFIX_TC)) errorCodeString else PREFIX_TC + errorCodeString
         return HumanReadableError(
-            description = errorMessage.get(context) + "\n\n$errorCodeString"
+            description = errorMessage.get(context) + "\n\n$errorCode"
         )
     }
 
     override val errorMessage: LazyString
         get() = when (errorCode) {
 
-            ErrorCode.DCC_COMP_NO_NETWORK,
-            ErrorCode.PKR_NO_NETWORK -> CachedString { context ->
-                context.getString(ERROR_MESSAGE_NO_NETWORK)
-            }
-
-            ErrorCode.DCC_COMP_202 -> CachedString { context ->
-                context.getString(ERROR_MESSAGE_TRY_AGAIN_DCC_NOT_AVAILABLE_YET)
-            }
-
-            ErrorCode.DCC_COMP_410 -> CachedString { context ->
-                context.getString(ERROR_MESSAGE_DCC_EXPIRED)
-            }
-
-            // TODO
-/*            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,*/
-
             ErrorCode.AES_DECRYPTION_FAILED,
             ErrorCode.RSA_DECRYPTION_FAILED,
-            ErrorCode.DCC_COSE_MESSAGE_INVALID,
-            ErrorCode.DCC_COSE_TAG_INVALID,
-            ErrorCode.DCC_COMP_404,
-            ErrorCode.DCC_COMP_412,
-            ErrorCode.PKR_403,
-            ErrorCode.PKR_404 -> CachedString { context ->
+            ErrorCode.HC_COSE_MESSAGE_INVALID,
+            ErrorCode.HC_COSE_TAG_INVALID -> CachedString { context ->
                 context.getString(ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE)
             }
 
-            ErrorCode.DCC_COMP_400,
-            ErrorCode.PKR_400 -> CachedString { context ->
-                context.getString(ERROR_MESSAGE_CLIENT_ERROR_CALL_HOTLINE)
-            }
-
-            ErrorCode.PKR_FAILED,
-            ErrorCode.RSA_KP_GENERATION_FAILED,
-            ErrorCode.PKR_500,
-            ErrorCode.DCC_COMP_500_INTERNAL -> CachedString { context ->
+            ErrorCode.RSA_KP_GENERATION_FAILED -> CachedString { context ->
                 context.getString(ERROR_MESSAGE_TRY_AGAIN)
             }
 
-            ErrorCode.HC_BASE45_ENCODING_FAILED,
-            ErrorCode.HC_ZLIB_COMPRESSION_FAILED,
-            ErrorCode.NO_TEST_ENTRY,
-            ErrorCode.DCC_COMP_500_LAB_INVALID_RESPONSE,
-            ErrorCode.DCC_COMP_500_SIGNING_CLIENT_ERROR,
-            ErrorCode.DCC_COMP_500_SIGNING_SERVER_ERROR,
-            ErrorCode.PKR_409 -> CachedString { context ->
-                context.getString(ERROR_MESSAGE_GENERIC)
-            }
             else -> super.errorMessage
         }
 }
-
-private const val PREFIX_TC = "TC_"
-private const val ERROR_MESSAGE_GENERIC = R.string.errors_generic_text_unknown_error_cause
-
-// TODO change to correct error message once provided
-private const val ERROR_MESSAGE_TRY_AGAIN = ERROR_MESSAGE_GENERIC
-private const val ERROR_MESSAGE_DCC_NOT_SUPPORTED_BY_LAB = ERROR_MESSAGE_GENERIC
-private const val ERROR_MESSAGE_NO_NETWORK = ERROR_MESSAGE_GENERIC
-private const val ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE = ERROR_MESSAGE_GENERIC
-private const val ERROR_MESSAGE_TRY_AGAIN_DCC_NOT_AVAILABLE_YET = ERROR_MESSAGE_GENERIC
-private const val ERROR_MESSAGE_CLIENT_ERROR_CALL_HOTLINE = ERROR_MESSAGE_GENERIC
-private const val ERROR_MESSAGE_DCC_EXPIRED = ERROR_MESSAGE_GENERIC
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/TestCertificateServerException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/TestCertificateServerException.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0935900237be8945628a49e506bd0a8bc7218ecb
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/TestCertificateServerException.kt
@@ -0,0 +1,102 @@
+package de.rki.coronawarnapp.covidcertificate.exception
+
+import android.content.Context
+import androidx.annotation.StringRes
+import de.rki.coronawarnapp.util.HasHumanReadableError
+import de.rki.coronawarnapp.util.HumanReadableError
+import de.rki.coronawarnapp.util.ui.CachedString
+import de.rki.coronawarnapp.util.ui.LazyString
+
+class TestCertificateServerException(
+    val errorCode: ErrorCode
+) : HasHumanReadableError, Throwable(errorCode.message) {
+
+    override fun toHumanReadableError(context: Context): HumanReadableError {
+        return HumanReadableError(
+            description = errorMessage.get(context)
+        )
+    }
+
+    val errorMessage: LazyString
+        get() = CachedString { context ->
+            context.getString(errorCode.stringRes)
+        }
+
+    enum class ErrorCode(
+        val message: String,
+        @StringRes val stringRes: Int
+    ) {
+        DCC_COMP_202(
+            "DCC Components request failed with error 202: DCC pending.",
+            ERROR_MESSAGE_TRY_AGAIN_DCC_NOT_AVAILABLE_YET
+        ),
+        DCC_COMP_400(
+            "DCC Components request failed with error 400: Bad request (e.g. wrong format of registration token)",
+            ERROR_MESSAGE_CLIENT_ERROR_CALL_HOTLINE
+        ),
+        DCC_COMP_404(
+            "DCC Components request failed with error 404: Registration token does not exist.",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        DCC_COMP_410(
+            "DCC Components request failed with error 410: DCC already cleaned up.",
+            ERROR_MESSAGE_DCC_EXPIRED
+        ),
+        DCC_COMP_412(
+            "DCC Components request failed with error 412: Test result not yet received",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        DCC_COMP_500(
+            "DCC Test Certificate Components failed with error 500: Internal server error.",
+            ERROR_MESSAGE_TRY_AGAIN
+        ),
+        // TODO error message not defined
+        DCC_COMP_500_LAB_INVALID_RESPONSE(
+            "DCC Components failed with error 500: Lab Invalid response",
+            ERROR_MESSAGE_GENERIC
+        ),
+        // TODO error message not defined
+        DCC_COMP_500_SIGNING_CLIENT_ERROR(
+            "DCC Components failed with error 500: Signing client error",
+            ERROR_MESSAGE_GENERIC
+        ),
+        // TODO error message not defined
+        DCC_COMP_500_SIGNING_SERVER_ERROR(
+            "DCC Components failed with error 500: Signing server error",
+            ERROR_MESSAGE_GENERIC
+        ),
+        DCC_COMP_NO_NETWORK(
+            "DCC Test Certificate Components failed due to no network connection.",
+            ERROR_MESSAGE_NO_NETWORK
+        ),
+        PKR_400(
+            "Public Key Registration failed with 400: " +
+                "Bad request (e.g. wrong format of registration token or public key).",
+            ERROR_MESSAGE_CLIENT_ERROR_CALL_HOTLINE
+        ),
+        PKR_403(
+            "Public Key Registration failed with 403: Registration token is not allowed to issue a DCC.",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        PKR_404(
+            "Public Key Registration failed with 404: Registration token does not exist.",
+            ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
+        ),
+        PKR_409(
+            "Public Key Registration failed with 409: Registration token is already assigned to a public key.",
+            ERROR_MESSAGE_GENERIC
+        ),
+        PKR_500(
+            "Public Key Registration failed with 500: Internal server error.",
+            ERROR_MESSAGE_TRY_AGAIN
+        ),
+        PKR_FAILED(
+            "Private key request failed.",
+            ERROR_MESSAGE_TRY_AGAIN
+        ),
+        PKR_NO_NETWORK(
+            "Private key request failed due to no network connection.",
+            ERROR_MESSAGE_NO_NETWORK
+        ),
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/CovidCertificateApiV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/CovidCertificateApiV1.kt
index 393236da309f022d973086b833f8b50199f5b41c..29e2b32e8719f3398c3a4efb90d179f66a890801 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/CovidCertificateApiV1.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/CovidCertificateApiV1.kt
@@ -15,16 +15,24 @@ interface CovidCertificateApiV1 {
     @POST("/version/v1/publicKey")
     suspend fun sendPublicKey(
         @Body requestBody: PublicKeyUploadRequest
-    )
+    ): Response<Unit>
 
     data class ComponentsRequest(
         @SerializedName("registrationToken") val registrationToken: String,
     )
 
     data class ComponentsResponse(
-        @SerializedName("dek") val dek: String,
-        @SerializedName("dcc") val dcc: String
-    )
+        @SerializedName("dek") val dek: String? = null,
+        @SerializedName("dcc") val dcc: String? = null,
+        @SerializedName("reason") val errorReason: String? = null
+    ) {
+        enum class Reason(val errorString: String) {
+            SIGNING_CLIENT_ERROR("SIGNING_CLIENT_ERROR"),
+            SIGNING_SERVER_ERROR("SIGNING_SERVER_ERROR"),
+            LAB_INVALID_RESPONSE("LAB_INVALID_RESPONSE"),
+            INTERNAL("INTERNAL")
+        }
+    }
 
     @POST("/version/v1/publicKey")
     suspend fun getComponents(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/CovidCertificateServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/CovidCertificateServer.kt
index 9e4eed79c1466af27331882ba14c914df6b6b2e2..7d8996322f0e04cca4a0bfe690cc5675f03df599 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/CovidCertificateServer.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/CovidCertificateServer.kt
@@ -3,8 +3,32 @@ package de.rki.coronawarnapp.covidcertificate.server
 import dagger.Lazy
 import dagger.Reusable
 import de.rki.coronawarnapp.coronatest.type.RegistrationToken
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_202
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_400
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_404
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_410
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_412
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_500
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_500_LAB_INVALID_RESPONSE
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_500_SIGNING_CLIENT_ERROR
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_500_SIGNING_SERVER_ERROR
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.DCC_COMP_NO_NETWORK
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_400
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_403
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_404
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_409
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_500
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_FAILED
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException.ErrorCode.PKR_NO_NETWORK
+import de.rki.coronawarnapp.covidcertificate.server.CovidCertificateApiV1.ComponentsResponse.Reason.INTERNAL
+import de.rki.coronawarnapp.covidcertificate.server.CovidCertificateApiV1.ComponentsResponse.Reason.LAB_INVALID_RESPONSE
+import de.rki.coronawarnapp.covidcertificate.server.CovidCertificateApiV1.ComponentsResponse.Reason.SIGNING_CLIENT_ERROR
+import de.rki.coronawarnapp.covidcertificate.server.CovidCertificateApiV1.ComponentsResponse.Reason.SIGNING_SERVER_ERROR
 import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
 import de.rki.coronawarnapp.util.encryption.rsa.RSAKey
+import de.rki.coronawarnapp.util.network.NetworkStateProvider
+import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.withContext
 import timber.log.Timber
 import javax.inject.Inject
@@ -12,42 +36,77 @@ import javax.inject.Inject
 @Reusable
 class CovidCertificateServer @Inject constructor(
     private val dccApi: Lazy<CovidCertificateApiV1>,
-    private val dispatcherProvider: DispatcherProvider
+    private val dispatcherProvider: DispatcherProvider,
+    private val networkStateProvider: NetworkStateProvider
 ) {
 
     private val api: CovidCertificateApiV1
         get() = dccApi.get()
 
+    @Throws(TestCertificateServerException::class)
     suspend fun registerPublicKeyForTest(
         testRegistrationToken: RegistrationToken,
         publicKey: RSAKey.Public,
     ): Unit = withContext(dispatcherProvider.IO) {
         Timber.tag(TAG).v("registerPublicKeyForTest(token=%s, key=%s)", testRegistrationToken, publicKey)
-        api.sendPublicKey(
-            requestBody = CovidCertificateApiV1.PublicKeyUploadRequest(
-                registrationToken = testRegistrationToken,
-                publicKey = publicKey.base64
+        if (!isInternetAvailable()) {
+            throw TestCertificateServerException(PKR_NO_NETWORK)
+        }
+        try {
+            val response = api.sendPublicKey(
+                requestBody = CovidCertificateApiV1.PublicKeyUploadRequest(
+                    registrationToken = testRegistrationToken,
+                    publicKey = publicKey.base64
+                )
             )
-        )
+            when (response.code()) {
+                400 -> throw TestCertificateServerException(PKR_400)
+                403 -> throw TestCertificateServerException(PKR_403)
+                404 -> throw TestCertificateServerException(PKR_404)
+                409 -> throw TestCertificateServerException(PKR_409)
+                500 -> throw TestCertificateServerException(PKR_500)
+            }
+        } catch (e: Throwable) {
+            throw TestCertificateServerException(PKR_FAILED)
+        }
     }
 
-    @Throws(DccException::class)
+    @Throws(TestCertificateServerException::class)
     suspend fun requestCertificateForTest(
         testRegistrationToken: RegistrationToken,
     ): TestCertificateComponents = withContext(dispatcherProvider.IO) {
         Timber.tag(TAG).v("requestCertificateForTest(token=%s)", testRegistrationToken)
+        if (!isInternetAvailable()) {
+            throw TestCertificateServerException(DCC_COMP_NO_NETWORK)
+        }
         val response = api.getComponents(
             requestBody = CovidCertificateApiV1.ComponentsRequest(testRegistrationToken)
         )
-        // TODO replace with InvalidTestCertificateException + correct error codes
-        if (response.code() == 202) throw DccException()
-        val result = response.body() ?: throw DccException()
+        when (response.code()) {
+            202 -> throw TestCertificateServerException(DCC_COMP_202)
+            400 -> throw TestCertificateServerException(DCC_COMP_400)
+            404 -> throw TestCertificateServerException(DCC_COMP_404)
+            410 -> throw TestCertificateServerException(DCC_COMP_410)
+            412 -> throw TestCertificateServerException(DCC_COMP_412)
+            500 -> when (response.body()?.errorReason) {
+                INTERNAL.errorString -> throw TestCertificateServerException(DCC_COMP_500)
+                SIGNING_CLIENT_ERROR.errorString ->
+                    throw TestCertificateServerException(DCC_COMP_500_SIGNING_CLIENT_ERROR)
+                SIGNING_SERVER_ERROR.errorString ->
+                    throw TestCertificateServerException(DCC_COMP_500_SIGNING_SERVER_ERROR)
+                LAB_INVALID_RESPONSE.errorString ->
+                    throw TestCertificateServerException(DCC_COMP_500_LAB_INVALID_RESPONSE)
+            }
+        }
+        val result = response.body()!! // throw exception?
         TestCertificateComponents(
-            dataEncryptionKeyBase64 = result.dek,
-            encryptedCoseTestCertificateBase64 = result.dcc
+            dataEncryptionKeyBase64 = result.dek!!,
+            encryptedCoseTestCertificateBase64 = result.dcc!!
         )
     }
 
+    private suspend fun isInternetAvailable() = networkStateProvider.networkState.first().isInternetAvailable
+
     companion object {
         private const val TAG = "CovidCertificateServer"
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/DccException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/DccException.kt
deleted file mode 100644
index 058cb8292f375a08f757561e70e9b37adfc9ac5a..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/server/DccException.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package de.rki.coronawarnapp.covidcertificate.server
-
-class DccException : Exception()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateCOSEDecoder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateCOSEDecoder.kt
index 2fd765e1e11d46b2397d5bb5f68b64ab96d8c518..f084c7673186622b6c24275bf78e9fb484bdd3a6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateCOSEDecoder.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/vaccination/core/certificate/HealthCertificateCOSEDecoder.kt
@@ -6,7 +6,6 @@ import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateE
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.AES_DECRYPTION_FAILED
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_COSE_MESSAGE_INVALID
 import de.rki.coronawarnapp.covidcertificate.exception.InvalidHealthCertificateException.ErrorCode.HC_COSE_TAG_INVALID
-import de.rki.coronawarnapp.util.encoding.base64
 import timber.log.Timber
 import javax.inject.Inject
 
@@ -41,7 +40,7 @@ class HealthCertificateCOSEDecoder @Inject constructor(
     private fun ByteArray.decrypt(decryptionKey: ByteArray) = try {
         aesEncryptor.decrypt(
             decryptionKey = decryptionKey,
-            encryptedData = this.base64().toByteArray()
+            encryptedData = this
         )
     } catch (e: Throwable) {
         Timber.e(e)
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptographyTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptographyTest.kt
index 1d9ecfde2fe05727f63a3641a4a85efc46c44e39..b98b171ad5c9667de587c4dd45a260678d4fcab4 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptographyTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/cryptography/AesCryptographyTest.kt
@@ -1,6 +1,7 @@
 package de.rki.coronawarnapp.covidcertificate.cryptography
 
 import io.kotest.matchers.shouldBe
+import okio.ByteString.Companion.decodeBase64
 import org.junit.jupiter.api.Test
 import testhelpers.BaseTest
 
@@ -8,8 +9,8 @@ class AesCryptographyTest : BaseTest() {
 
     @Test
     fun `decrypt Hello World`() {
-        val des = "d56t/juMw5r4qNx1n1igs1pobUjZBT5yq0Ct7MHUuKM=".toByteArray()
-        val encryptedString = "WFOLewp8DWqY/8IWUHEDwg==".toByteArray()
+        val des = "d56t/juMw5r4qNx1n1igs1pobUjZBT5yq0Ct7MHUuKM=".decodeBase64()!!.toByteArray()
+        val encryptedString = "WFOLewp8DWqY/8IWUHEDwg==".decodeBase64()!!.toByteArray()
         AesCryptography().decrypt(
             des,
             encryptedData = encryptedString
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractorTest.kt
index ef3f817acac28c8d695179985a117937c7e2b5a3..0fa2e01caf16a8d470df2468c735bbb70b5894ab 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/test/TestCertificateQRCodeExtractorTest.kt
@@ -59,7 +59,7 @@ class TestCertificateQRCodeExtractorTest : BaseTest() {
     fun `happy path cose decryption with Ellen Cheng`() {
         with(TestData.EllenCheng()) {
             val coseObject = coseWithEncryptedPayload.decodeBase64()!!.toByteArray()
-            val dek = dek.toByteArray()
+            val dek = dek.decodeBase64()!!.toByteArray()
             val result = extractor.extract(dek, coseObject)
             with(result.testCertificateData.certificate.nameData) {
                 familyName shouldBe "Cheng"
@@ -77,7 +77,7 @@ class TestCertificateQRCodeExtractorTest : BaseTest() {
     fun `happy path cose decryption with Brian Calamandrei`() {
         with(TestData.BrianCalamandrei()) {
             val coseObject = coseWithEncryptedPayload.decodeBase64()!!.toByteArray()
-            val dek = dek.toByteArray()
+            val dek = dek.decodeBase64()!!.toByteArray()
             val result = extractor.extract(dek, coseObject)
             with(result.testCertificateData.certificate.nameData) {
                 familyName shouldBe "Calamandrei"