Describe the bug
I am generating the QR Code using the WEB frontend template application.
Upon scanning the QR Code with the Verifier App, I am consistently getting an error "Verification failed: failed to load certificate"
Expected behaviour
Verification should be successfull.
Steps to reproduce the issue
- Installed DGC Issuer Service, DGC Verifier Service.
- Uploaded all required certificates, including the signed DSC and configured them accordingly in the services layer.
- Modified the BASE_URL in the Android application : File: NetworkModule.kt as to point to my verifier service
- Compiled and run on Android
- Scan the QR Code as generated by the Web Frontend Template application
- Displays invalid on screen, and Android Studio Logs shows
D/VerificationViewModel$decode: Verification failed: failed to load certificate
Upon some debugging, I have found a discrepancy which might/might not be the cause of the invalid result.
In the file: VerificationViewModel.kt
Notice the 2 bold Debug Lines I've added.
schemaValidator.validate(coseData.cbor, verificationResult)
greenCertificate = cborService.decode(coseData.cbor, verificationResult)
**Timber.d("DEBUG Verification Result: %s", verificationResult)**
val certificate = verifierRepository.getCertificate(kid.toBase64())
**Timber.d("DEBUG KID: %s" ,kid.toBase64())**
if (certificate == null) {
Timber.d("Verification failed: failed to load certificate")
return@withContext
}
and their output:
D/VerificationViewModel$decode: DEBUG Verification Result: VerificationResult:
base45Decoded: true
valSuitePrefix: HC1:
zlibDecoded: true
coseVerified: false
cborDecoded: true
isSchemaValid: true
D/VerificationViewModel$decode: DEBUG KID: 2Ga7nn3--CU=
Firstly, notice that coseVerified = false , Looking into the android core library, file: DefaultCoseSerivce.kt, I noticed that the verificationResult.Verified is hard coded to false, without any opporunity to set it to true within the decode function
override fun decode(input: ByteArray, verificationResult: VerificationResult): CoseData? {
**verificationResult.coseVerified = false**
return try {
val messageObject = CBORObject.DecodeFromBytes(input)
val content = messageObject[2].GetByteString()
val rgbProtected = messageObject[0].GetByteString()
val key = HeaderKeys.KID.AsCBOR()
var kid = CBORObject.DecodeFromBytes(rgbProtected).get(key)
// Kid in unprotected header
if (kid == null) {
kid = messageObject[1].get(key)
}
val kidByteString = kid.GetByteString()
CoseData(content, kidByteString)
} catch (e: Throwable) {
null
}
}
Secondly ,the KID
I have noticed that the KID is presented in the debug log as follows:
2Ga7nn3--CU=
however, in the verifier service, it's presented like this:
2Ga7nn3++CU=
notice the "--" vs "++" difference.
and for completeness sake, the DSC follows:
{
"kid": "2Ga7nn3++CU=",
"timestamp": "2021-05-12T12:28:38+02:00",
"country": "CY",
"certificateType": "DSC",
"thumbprint": "d866bb9e7dfef8255345678cb5722057084424331c7efd8c0eced9b52739c09f",
"signature": "MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCAMIICbDCCAhKgAwIBAgIURWuo6N0RLfrkJ/DaZO0KYr6fRu0wCgYIKoZIzj0EAwIwgZMxCzAJBgNVBAYTAkNZMRAwDgYDVQQIDAdOaWNvc2lhMRAwDgYDVQQHDAdOaWNvc2lhMS0wKwYDVQQKDCROYXRpb25hbCBlSGVhbHRoIEF1dGhvcml0eSBvZiBDeXBydXMxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxGTAXBgNVBAMMEFVQTE9BRF9ER0NfQ1lfMDEwHhcNMjEwNTEwMDcwMzI3WhcNMjMwNTEwMDcwMzI3WjCBkzELMAkGA1UEBhMCQ1kxEDAOBgNVBAgMB05pY29zaWExEDAOBgNVBAcMB05pY29zaWExLTArBgNVBAoMJE5hdGlvbmFsIGVIZWFsdGggQXV0aG9yaXR5IG9mIEN5cHJ1czEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEZMBcGA1UEAwwQVVBMT0FEX0RHQ19DWV8wMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCFf0s8yXh7oSXaZKrGFEp8M6Jf8r/EjgLtNmZ07wJuCYDtnlDSJme43ERrsC5gzGQ491N5kPT65vDl1qylqO7GjQjBAMA8GA1UdEwEB/wQFMAMCAQAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBQ/y+7LCYF6CqZGkM/ecYc10XB14zAKBggqhkjOPQQDAgNIADBFAiB+N59qtZwkqmWc/3Dl5gZMpbVrr8+u0+FY9MEQgBUsDAIhAL+NzoJpvG+waRjAN2eZ7d+TB6OlhuRrPp2Ed1LN94iWAAAxggH+MIIB+gIBATCBrDCBkzELMAkGA1UEBhMCQ1kxEDAOBgNVBAgMB05pY29zaWExEDAOBgNVBAcMB05pY29zaWExLTArBgNVBAoMJE5hdGlvbmFsIGVIZWFsdGggQXV0aG9yaXR5IG9mIEN5cHJ1czEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEZMBcGA1UEAwwQVVBMT0FEX0RHQ19DWV8wMQIURWuo6N0RLfrkJ/DaZO0KYr6fRu0wCwYJYIZIAWUDBAIBoIHkMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIxMDUxMjEwMjQ1N1owLwYJKoZIhvcNAQkEMSIEINhmu559/vglU0VnjLVyIFcIRCQzHH79jA7O2bUnOcCfMHkGCSqGSIb3DQEJDzFsMGowCwYJYIZIAWUDBAEqMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMCAgEoMAoGCCqGSM49BAMCBEYwRAIgCb+nI9Prsvylmsmdfn8n2ySopLnCVLbKd38900PZO/MCIHF2lA4OEyFBiCoHqzW8pY5a7FaSi8ZMzcOKh3bGgdjEAAAAAAAA",
"rawData": "MIICHjCCAcQCFDtxKq28G7KiGukkC62ELU4BBvBbMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJDWTEQMA4GA1UECAwHTmljb3NpYTEQMA4GA1UEBwwHTmljb3NpYTEtMCsGA1UECgwkTmF0aW9uYWwgZUhlYWx0aCBBdXRob3JpdHkgb2YgQ3lwcnVzMRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRcwFQYDVQQDDA5DU0NBX0RHQ19DWV8wMTAeFw0yMTA1MTIxMDIzMDZaFw0yMzA1MDIxMDIzMDZaMIGQMQswCQYDVQQGEwJDWTEQMA4GA1UECAwHTmljb3NpYTEQMA4GA1UEBwwHTmljb3NpYTEtMCsGA1UECgwkTmF0aW9uYWwgZUhlYWx0aCBBdXRob3JpdHkgb2YgQ3lwcnVzMRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRYwFAYDVQQDDA1EU0NfREdDX0NZXzAxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPybvhD4bGNlyPCpz9aiIpnB09ceGEc4z1l5Q8CoQ3sMvXHM3n7+3zX4K7V16VNI09bH1rmCttVRtO8cN/JpG/TAKBggqhkjOPQQDAgNIADBFAiAufANVRuChmYz8oMJgjlFuNMlT3C5zys/gESMgrbdS8AIhAPLA6P1SJL7TdkbjtyRIqpvz1M+m9NJP919tcZ7xoJjP"
},
Technical details
Hosted on Kubernetes, using Nginx Ingress Reverse Proxy, Centos 7
bug