Closed santiagorodriguez96 closed 9 months ago
This is a tricky one: the response should succeed but it fails instead with an WebAuthn::AttestationStatementVerificationError
because it fails to verify the attestation trustworthiness – step 21 of the process for Registering a New Credential.
In this test case, the acceptable trust anchor obtained by following the FIDO Metadata Service is the same as the attestation certificate:
MIIEQTCCAimgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBoTEYMBYGA1UEAwwPRklETzIgVEVTVCBST09UMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMQwwCgYDVQQLDANDV0cxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNWTESMBAGA1UEBwwJV2FrZWZpZWxkMB4XDTE4MDUyMzE0Mzk0M1oXDTI4MDUyMDE0Mzk0M1owgcIxIzAhBgNVBAMMGkZJRE8yIEJBVENIIEtFWSBwcmltZTI1NnYxMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0aW9uMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTVkxEjAQBgNVBAcMCVdha2VmaWVsZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE86Xl6rbB+8rpf232RJlnYse+9yAEAqdsbyMPZVbxeqmZtZf8S/UIqvjp7wzQE/Wrm9J5FL8IBDeMvMsRuJtUajLDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFFZN98D4xlW2oR9sTRnzv0Hi/QF5MA0GCSqGSIb3DQEBCwUAA4ICAQCH3aCf+CCJBdEtQc4JpOnUelwGGw7DxnBMokHHBgrzJxDn9BFcFwxGLxrFV7EfYehQNOD+74OS8fZRgZiNf9EDGAYiHh0+CspfBWd20zCIjlCdDBcyhwq3PLJ65JC/og3CT9AK4kvks4DI+01RYxNv9S8Jx1haO1lgU55hBIr1P/p21ZKnpcCEhPjB/cIFrHJqL5iJGfed+LXni9Suq24OHnp44Mrv4h7OD2elu5yWfdfFb+RGG2TYURFIGYGijsii093w0ZMBOfBS+3Xq/DrHeZbZrrNkY455gJCZ5eV83Nrt9J9/UF0VZHl/hwnSAUC/b3tN/l0ZlC9kPcNzJD04l4ndFBD2KdfQ2HGTX7pybWLZ7yH2BM3ui2OpiacaOzd7OE91rHYB2uZyQ7jdg25yF9M8QI9NHM/itCjdBvAYt4QCT8dX6gmZiIGR2F/YXZAsybtJ16pnUmODVbW80lPbzy+PUQYX79opeD9u6MBorzr9g08Elpb1F3DgSd8VSLlsR2QPllKl4AcJDMIOfZHOQGOzatMV7ipEVRa0L5FnjAWpHHvSNcsjD4Cul562mO3MlI2pCyo+US+nIzG5XZmOeu4Db/Kw/dEPOo2ztHwlU0qKJ7REBsbt63jdQtlwLuiLHwkpiwnrAOZfwbLLu9Yz4tL1eJlQffuwS/Aolsz7HA==
You can check this by looking at the attestationRootCertificates
field of the correspondent authenticator metadata statement for this test case:
while the attestation certificate that comes in the response is:
params # => {"id"=>"J4TY6xBVEuqUr3gO2hNeGGyawtazZ6hMh7izv9hbZ_U", "rawId"=>"J4TY6xBVEuqUr3gO2hNeGGyawtazZ6hMh7izv9hbZ_U", "response"=>{"attestationObject"=>"o2NmbXRmcGFja2VkZ2F0dFN0bXSjY2FsZyZjc2lnWEgwRgIhAJRbrR7GjXy6Zy7iCRTOOfP26cngXWxLmlXvgjInNS3-AiEA3h5TwgBeR3wBRQH87s-VeeWUYll9jd9oDaHiEBFPK1FjeDVjgVkERTCCBEEwggIpoAMCAQICAQEwDQYJKoZIhvcNAQELBQAwgaExGDAWBgNVBAMMD0ZJRE8yIFRFU1QgUk9PVDExMC8GCSqGSIb3DQEJARYiY29uZm9ybWFuY2UtdG9vbHNAZmlkb2FsbGlhbmNlLm9yZzEWMBQGA1UECgwNRklETyBBbGxpYW5jZTEMMAoGA1UECwwDQ1dHMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTVkxEjAQBgNVBAcMCVdha2VmaWVsZDAeFw0xODA1MjMxNDM5NDNaFw0yODA1MjAxNDM5NDNaMIHCMSMwIQYDVQQDDBpGSURPMiBCQVRDSCBLRVkgcHJpbWUyNTZ2MTExMC8GCSqGSIb3DQEJARYiY29uZm9ybWFuY2UtdG9vbHNAZmlkb2FsbGlhbmNlLm9yZzEWMBQGA1UECgwNRklETyBBbGxpYW5jZTEiMCAGA1UECwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1ZMRIwEAYDVQQHDAlXYWtlZmllbGQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARPOl5eq2wfvK6X9t9kSZZ2LHvvcgBAKnbG8jD2VW8XqpmbWX_Ev1CKr46e8M0BP1q5vSeRS_CAQ3jLzLEbibVGoywwKjAJBgNVHRMEAjAAMB0GA1UdDgQWBBRWTffA-MZVtqEfbE0Z879B4v0BeTANBgkqhkiG9w0BAQsFAAOCAgEAh92gn_ggiQXRLUHOCaTp1HpcBhsOw8ZwTKJBxwYK8ycQ5_QRXBcMRi8axVexH2HoUDTg_u-DkvH2UYGYjX_RAxgGIh4dPgrKXwVndtMwiI5QnQwXMocKtzyyeuSQv6INwk_QCuJL5LOAyPtNUWMTb_UvCcdYWjtZYFOeYQSK9T_6dtWSp6XAhIT4wf3CBaxyai-YiRn3nfi154vUrqtuDh56eODK7-Iezg9npbucln3XxW_kRhtk2FERSBmBoo7IotPd8NGTATnwUvt16vw6x3mW2a6zZGOOeYCQmeXlfNza7fSff1BdFWR5f4cJ0gFAv297Tf5dGZQvZD3DcyQ9OJeJ3RQQ9inX0Nhxk1-6cm1i2e8h9gTN7otjqYmnGjs3ezhPdax2AdrmckO43YNuchfTPECPTRzP4rQo3QbwGLeEAk_HV-oJmYiBkdhf2F2QLMm7SdeqZ1Jjg1W1vNJT288vj1EGF-_aKXg_bujAaK86_YNPBJaW9Rdw4EnfFUi5bEdkD5ZSpeAHCQzCDn2RzkBjs2rTFe4qRFUWtC-RZ4wFqRx70jXLIw-ArpeetpjtzJSNqQsqPlEvpyMxuV2ZjnruA2_ysP3RDzqNs7R8JVNKiie0RAbG7et43ULZcC7oix8JKYsJ6wDmX8Gyy7vWM-LS9XiZUH37sEvwKJbM-xxoYXV0aERhdGFYpEmWDeWIDoxodDQXD2R2YFuP5K65ooYyx5lc87qDHZdjQQAAAJZbZdrBevRG5opPhwH8xPO0ACAnhNjrEFUS6pSveA7aE14YbJrC1rNnqEyHuLO_2Ftn9aUBAgMmIAEhWCDWwknOPFz8eYIUh2n1AnpO6O3_YZeCgAqXDZtG9r3NBiJYIJcCqSAiBJZxyjY7KhHsvEhrTLjOjf5FBjPVEFYXjOpU", "clientDataJSON"=>"eyJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjQ1NjciLCJjaGFsbGVuZ2UiOiJqVHR6NGJ5WmFHaHN3SmxubGdwS1NxMUpESlpJU2FIS0ZIaDVvS1RLdmFJIiwidHlwZSI6IndlYmF1dGhuLmNyZWF0ZSJ9"}, "getClientExtensionResults"=>{}, "type"=>"public-key"}
WebAuthn::AttestationStatement::Packed.new(CBOR.decode(relying_party.encoder.decode(params["response"]["attestationObject"]))["attStmt"]).attestation_certificate.to_pem # => "-----BEGIN CERTIFICATE-----\nMIIEQTCCAimgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBoTEYMBYGA1UEAwwPRklE\nTzIgVEVTVCBST09UMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0Bm\naWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMQwwCgYDVQQL\nDANDV0cxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNWTESMBAGA1UEBwwJV2FrZWZp\nZWxkMB4XDTE4MDUyMzE0Mzk0M1oXDTI4MDUyMDE0Mzk0M1owgcIxIzAhBgNVBAMM\nGkZJRE8yIEJBVENIIEtFWSBwcmltZTI1NnYxMTEwLwYJKoZIhvcNAQkBFiJjb25m\nb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFs\nbGlhbmNlMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0aW9uMQswCQYD\nVQQGEwJVUzELMAkGA1UECAwCTVkxEjAQBgNVBAcMCVdha2VmaWVsZDBZMBMGByqG\nSM49AgEGCCqGSM49AwEHA0IABE86Xl6rbB+8rpf232RJlnYse+9yAEAqdsbyMPZV\nbxeqmZtZf8S/UIqvjp7wzQE/Wrm9J5FL8IBDeMvMsRuJtUajLDAqMAkGA1UdEwQC\nMAAwHQYDVR0OBBYEFFZN98D4xlW2oR9sTRnzv0Hi/QF5MA0GCSqGSIb3DQEBCwUA\nA4ICAQCH3aCf+CCJBdEtQc4JpOnUelwGGw7DxnBMokHHBgrzJxDn9BFcFwxGLxrF\nV7EfYehQNOD+74OS8fZRgZiNf9EDGAYiHh0+CspfBWd20zCIjlCdDBcyhwq3PLJ6\n5JC/og3CT9AK4kvks4DI+01RYxNv9S8Jx1haO1lgU55hBIr1P/p21ZKnpcCEhPjB\n/cIFrHJqL5iJGfed+LXni9Suq24OHnp44Mrv4h7OD2elu5yWfdfFb+RGG2TYURFI\nGYGijsii093w0ZMBOfBS+3Xq/DrHeZbZrrNkY455gJCZ5eV83Nrt9J9/UF0VZHl/\nhwnSAUC/b3tN/l0ZlC9kPcNzJD04l4ndFBD2KdfQ2HGTX7pybWLZ7yH2BM3ui2Op\niacaOzd7OE91rHYB2uZyQ7jdg25yF9M8QI9NHM/itCjdBvAYt4QCT8dX6gmZiIGR\n2F/YXZAsybtJ16pnUmODVbW80lPbzy+PUQYX79opeD9u6MBorzr9g08Elpb1F3Dg\nSd8VSLlsR2QPllKl4AcJDMIOfZHOQGOzatMV7ipEVRa0L5FnjAWpHHvSNcsjD4Cu\nl562mO3MlI2pCyo+US+nIzG5XZmOeu4Db/Kw/dEPOo2ztHwlU0qKJ7REBsbt63jd\nQtlwLuiLHwkpiwnrAOZfwbLLu9Yz4tL1eJlQffuwS/Aolsz7HA==\n-----END CERTIFICATE-----\n"
The problem is that OpenSSL::X509::Store#verify
fails to verify given that the certificate is not considered a CA certificate and thus it's ignored – to put it simply, this is what the gem ends up doing in this case for verifying the trustworthiness:
root_certificate = OpenSSL::X509::Certificate.new(Base64.decode64("MIIEQTCCAimgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBoTEYMBYGA1UEAwwPRklETzIgVEVTVCBST09UMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMQwwCgYDVQQLDANDV0cxCzAJB
gNVBAYTAlVTMQswCQYDVQQIDAJNWTESMBAGA1UEBwwJV2FrZWZpZWxkMB4XDTE4MDUyMzE0Mzk0M1oXDTI4MDUyMDE0Mzk0M1owgcIxIzAhBgNVBAMMGkZJRE8yIEJBVENIIEtFWSBwcmltZTI1NnYxMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMSIwIAYDVQQLDBlBdXR
oZW50aWNhdG9yIEF0dGVzdGF0aW9uMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTVkxEjAQBgNVBAcMCVdha2VmaWVsZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE86Xl6rbB+8rpf232RJlnYse+9yAEAqdsbyMPZVbxeqmZtZf8S/UIqvjp7wzQE/Wrm9J5FL8IBDeMvMsRuJtUajLDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFFZN98D4xlW2oR9sTRnzv0Hi/
QF5MA0GCSqGSIb3DQEBCwUAA4ICAQCH3aCf+CCJBdEtQc4JpOnUelwGGw7DxnBMokHHBgrzJxDn9BFcFwxGLxrFV7EfYehQNOD+74OS8fZRgZiNf9EDGAYiHh0+CspfBWd20zCIjlCdDBcyhwq3PLJ65JC/og3CT9AK4kvks4DI+01RYxNv9S8Jx1haO1lgU55hBIr1P/p21ZKnpcCEhPjB/cIFrHJqL5iJGfed+LXni9Suq24OHnp44Mrv4h7OD2elu5yWfdfFb+R
GG2TYURFIGYGijsii093w0ZMBOfBS+3Xq/DrHeZbZrrNkY455gJCZ5eV83Nrt9J9/UF0VZHl/hwnSAUC/b3tN/l0ZlC9kPcNzJD04l4ndFBD2KdfQ2HGTX7pybWLZ7yH2BM3ui2OpiacaOzd7OE91rHYB2uZyQ7jdg25yF9M8QI9NHM/itCjdBvAYt4QCT8dX6gmZiIGR2F/YXZAsybtJ16pnUmODVbW80lPbzy+PUQYX79opeD9u6MBorzr9g08Elpb1F3DgSd8VS
LlsR2QPllKl4AcJDMIOfZHOQGOzatMV7ipEVRa0L5FnjAWpHHvSNcsjD4Cul562mO3MlI2pCyo+US+nIzG5XZmOeu4Db/Kw/dEPOo2ztHwlU0qKJ7REBsbt63jdQtlwLuiLHwkpiwnrAOZfwbLLu9Yz4tL1eJlQffuwS/Aolsz7HA=="))
store = OpenSSL::X509::Store.new.tap { |store| store.add_cert(root_certificate) }
root_certificate.find_extension("basicConstraints").value #=> "CA:FALSE"
store.verify(root_certificate, [root_certificate]) #=> false
store.error_string #=> unable to locate issuer certificate
It is expected for the server to succeed according to this comment on this issue in conformance-test-tools
:
If authenticator returns one, and one only certificate, and this certificate is equal to one of the certificates in the attestationRootCertificates, then server shall accept without checking. certificate chain.
How to run FIDO2 conformance tests: https://github.com/cedarcode/webauthn-ruby/tree/master/spec/conformance.