cedarcode / webauthn-ruby

WebAuthn ruby server library ― Make your Ruby/Rails web server become a conformant WebAuthn Relying Party
https://rubygems.org/gems/webauthn
MIT License
658 stars 55 forks source link

Getting AttestationStatementVerificationError while registering using a custom U2F #310

Closed tarun14110 closed 4 years ago

tarun14110 commented 4 years ago

I am trying to get a custom U2F token work. My demo website sends attestation:"none" for registration. My U2F token uses self-signing for attestation and put 16 bits of aaguid to zeroes. According to the below statement from https://www.w3.org/TR/webauthn-1/#credential-public-key, it should successfully verify.

If the AAGUID in the attested credential data is 16 zero bytes, credentialCreationData.attestationObjectResult.fmt is "packed", and "x5c" & "ecdaaKeyId" are both absent from credentialCreationData.attestationObjectResult, then self attestation is being used and no further action is needed.

But, I am getting an error AttestationStatementVerificationError. What might be the possible reason for the error? I have attached the string that my U2F token returns to the website for registration.

Parameters: {"type"=>"public-key", "id"=>"DXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBA", "rawId"=>"DXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBA", "response"=>{"clientDataJSON"=>"eyJjaGFsbGVuZ2UiOiJiU19wQ0dLU25Md2hFVlNhbk1HdWlMQ0x1ZkQ0VVRJenltS2p0WFpXOV9zIiwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0", "attestationObject"=>"o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEAfs0DsQM_JBFbd0D1cLOZkMcR5d7aXz0kRGMO-wwkN8_g4LRUTX9lrCSCg7yEiN8SmRKISp73jWXKQ5IccIL5haGF1dGhEYXRhWMRJlg3liA6MaHQ0Fw9kdmBbj-SuuaKGMseZXPO6gx2XY0EAAAAAAAAAAAAAAAAAAAAAAAAAAABADXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBKUBAgMmIAEhWCCKiSrV-j5nbuPhBPOhqkHpHWd9rCY60hFERkYDrwl1FyJYIGA7G5JzzIGjBPqQw8LJunmqIox3Z4zr5BEG98fcRM5X"}, "credential_nickname"=>"mon6", "registration"=>{"type"=>"public-key", "id"=>"DXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBA", "rawId"=>"DXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBA", "response"=>{"clientDataJSON"=>"eyJjaGFsbGVuZ2UiOiJiU19wQ0dLU25Md2hFVlNhbk1HdWlMQ0x1ZkQ0VVRJenltS2p0WFpXOV9zIiwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0", "attestationObject"=>"o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEAfs0DsQM_JBFbd0D1cLOZkMcR5d7aXz0kRGMO-wwkN8_g4LRUTX9lrCSCg7yEiN8SmRKISp73jWXKQ5IccIL5haGF1dGhEYXRhWMRJlg3liA6MaHQ0Fw9kdmBbj-SuuaKGMseZXPO6gx2XY0EAAAAAAAAAAAAAAAAAAAAAAAAAAABADXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBKUBAgMmIAEhWCCKiSrV-j5nbuPhBPOhqkHpHWd9rCY60hFERkYDrwl1FyJYIGA7G5JzzIGjBPqQw8LJunmqIox3Z4zr5BEG98fcRM5X"}}}

grzuy commented 4 years ago

Hi @tarun14110,

Wrote the below script and put it into my local webauthn-ruby library root and run ruby issue-310.rb several times playing with byebug statements in different places in the library code, and my troubleshooting tells me what's returning false in the verification chain is https://github.com/cedarcode/webauthn-ruby/blob/cd466b40bb489c38dcabb40f205ee4bf0f83b842/lib/webauthn/attestation_statement/packed.rb#L21.

Apparently the signature is invalid.

# issue-310.rb

params = {
  "type"=>"public-key",
  "id"=>"DXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBA",
  "rawId"=>"DXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBA",
  "response"=>{
    "clientDataJSON"=>"eyJjaGFsbGVuZ2UiOiJiU19wQ0dLU25Md2hFVlNhbk1HdWlMQ0x1ZkQ0VVRJenltS2p0WFpXOV9zIiwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0",
    "attestationObject"=>"o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEAfs0DsQM_JBFbd0D1cLOZkMcR5d7aXz0kRGMO-wwkN8_g4LRUTX9lrCSCg7yEiN8SmRKISp73jWXKQ5IccIL5haGF1dGhEYXRhWMRJlg3liA6MaHQ0Fw9kdmBbj-SuuaKGMseZXPO6gx2XY0EAAAAAAAAAAAAAAAAAAAAAAAAAAABADXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBKUBAgMmIAEhWCCKiSrV-j5nbuPhBPOhqkHpHWd9rCY60hFERkYDrwl1FyJYIGA7G5JzzIGjBPqQw8LJunmqIox3Z4zr5BEG98fcRM5X"
  },
  "credential_nickname"=>"mon6",
  "registration"=>{
    "type"=>"public-key",
    "id"=>"DXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBA",
    "rawId"=>"DXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBA",
    "response"=>{
      "clientDataJSON"=>"eyJjaGFsbGVuZ2UiOiJiU19wQ0dLU25Md2hFVlNhbk1HdWlMQ0x1ZkQ0VVRJenltS2p0WFpXOV9zIiwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0",
      "attestationObject"=>"o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZyZjc2lnWEAfs0DsQM_JBFbd0D1cLOZkMcR5d7aXz0kRGMO-wwkN8_g4LRUTX9lrCSCg7yEiN8SmRKISp73jWXKQ5IccIL5haGF1dGhEYXRhWMRJlg3liA6MaHQ0Fw9kdmBbj-SuuaKGMseZXPO6gx2XY0EAAAAAAAAAAAAAAAAAAAAAAAAAAABADXXvZFNsJyezHteb2T1VQr7NdMYz9M4DteomLhyLjcnzTSl9cot0ggMNl8kTRR4kUTYReLXBT8mGLOJKI0UZBKUBAgMmIAEhWCCKiSrV-j5nbuPhBPOhqkHpHWd9rCY60hFERkYDrwl1FyJYIGA7G5JzzIGjBPqQw8LJunmqIox3Z4zr5BEG98fcRM5X"
    }
  }
}

require "bundler/setup"
require "webauthn"
require "byebug"

attestation_object_bytes = Base64.urlsafe_decode64(params["response"]["attestationObject"])
client_data_json = Base64.urlsafe_decode64(params["response"]["clientDataJSON"])

attestation_object = WebAuthn::AttestationObject.deserialize(attestation_object_bytes)
client_data = WebAuthn::ClientData.new(client_data_json)

puts attestation_object.valid_attestation_statement?(client_data.hash)
grzuy commented 4 years ago

Closing for now given I can't see any issue in the library code. Let me know if you think there actually is and we can re-open.

Thank you!

tarun14110 commented 4 years ago

@grzuy Thanks a lot. I'm able to register successfully. Your debugging script helped me with the debugging process. Now, I'm getting Verification failed: WebAuthn::TypeVerificationError while authentication.

I made a similar script like yours for authentication to help me with debugging but I'm getting an error on it

`validate': Incompatible algorithm and key (RuntimeError)

params = {"type"=>"public-key", 
    "id"=>"WnlEZ01iWG52QmhkN0tnZnhCZWpKVkNoMjNOSjNlVk52U2o1MW9pWGxJTUQrcWdqYmVMT3p4TzBRTjJWYXkvaWtUb1FJWW1PL09ZbFNzSWpTVFJBSkE9PUBsb2NhbGhvc3Q=", 
    "rawId"=>"WnlEZ01iWG52QmhkN0tnZnhCZWpKVkNoMjNOSjNlVk52U2o1MW9pWGxJTUQrcWdqYmVMT3p4TzBRTjJWYXkvaWtUb1FJWW1PL09ZbFNzSWpTVFJBSkE9PUBsb2NhbGhvc3Q", 
    "response"=>{
        "clientDataJSON"=>"eyJjaGFsbGVuZ2UiOiJiaExKcUh6U2U3clJJWlpaRjZKekVhOGlhbE43azByQlR2LWhhWVVkLWZFIiwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJjaHJvbWUtZXh0ZW5zaW9uOi8va2NkaG5pZ2FrYWpqZGVlamVrbmhja2dsaGljbGtlb2QiLCJ0b2tlbkJpbmRpbmciOnsic3RhdHVzIjoibm90LXN1cHBvcnRlZCJ9LCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0", 
        "authenticatorData"=>"XrwlL61LKPUFL9scrQoOvQNU8793_lluuCPgHw2VHH0AAAABAA", 
        "signature"=>"FK4oomA6YmzLu0Ag-x7iDTLjukjZfGgoaimSU4ZNlusMasipTe-OQzWHYlNVaPK1AVtjZ8dqYQJMvegexsWbBw", 
        "userHandle"=>""}, 
    "session"=>{
        "type"=>"public-key", 
        "id"=>"WnlEZ01iWG52QmhkN0tnZnhCZWpKVkNoMjNOSjNlVk52U2o1MW9pWGxJTUQrcWdqYmVMT3p4TzBRTjJWYXkvaWtUb1FJWW1PL09ZbFNzSWpTVFJBSkE9PUBsb2NhbGhvc3Q=", 
        "rawId"=>"WnlEZ01iWG52QmhkN0tnZnhCZWpKVkNoMjNOSjNlVk52U2o1MW9pWGxJTUQrcWdqYmVMT3p4TzBRTjJWYXkvaWtUb1FJWW1PL09ZbFNzSWpTVFJBSkE9PUBsb2NhbGhvc3Q", 
        "response"=>{
            "clientDataJSON"=>"eyJjaGFsbGVuZ2UiOiJiaExKcUh6U2U3clJJWlpaRjZKekVhOGlhbE43azByQlR2LWhhWVVkLWZFIiwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJjaHJvbWUtZXh0ZW5zaW9uOi8va2NkaG5pZ2FrYWpqZGVlamVrbmhja2dsaGljbGtlb2QiLCJ0b2tlbkJpbmRpbmciOnsic3RhdHVzIjoibm90LXN1cHBvcnRlZCJ9LCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0", 
            "authenticatorData"=>"XrwlL61LKPUFL9scrQoOvQNU8793_lluuCPgHw2VHH0AAAABAA", 
            "signature"=>"FK4oomA6YmzLu0Ag-x7iDTLjukjZfGgoaimSU4ZNlusMasipTe-OQzWHYlNVaPK1AVtjZ8dqYQJMvegexsWbBw", 
            "userHandle"=>""}}}

require "bundler/setup"
require "webauthn"
require "byebug"

authenticator_data_bytes = Base64.urlsafe_decode64(params["response"]["authenticatorData"])
client_data_json = Base64.urlsafe_decode64(params["response"]["clientDataJSON"])
signature = Base64.urlsafe_decode64(params["response"]["signature"])

authenticator_data = WebAuthn::AuthenticatorData.deserialize(authenticator_data_bytes)
client_data = WebAuthn::ClientData.new(client_data_json)

puts WebAuthn::SignatureVerifier
        .new( -7, Base64.urlsafe_decode64("pQECAyYgASFYIGNIWc3GFBYad6u4CTWDXtuB9e5U1cTSYbcVICyE2WyTIlgg0m2lW8SRNKTc0BdI9EgzQPYcOtDWDqmzmOjpnt5Kb0U"))
        .verify(signature, authenticator_data_bytes + client_data.hash)
grzuy commented 4 years ago

@grzuy Thanks a lot. I'm able to register successfully. Your debugging script helped me with the debugging process.

Glad it helped!

Now, I'm getting Verification failed: WebAuthn::TypeVerificationError while authentication.

Right.

As specified in step 11 in https://www.w3.org/TR/webauthn-2/#sctn-verifying-assertion, the client data type for an Authentication should be webauthn.get, but in your params I see (run puts client_data.type in your script) it's set to webauthn.create.

I made a similar script like yours for authentication to help me with debugging but I'm getting an error on it

`validate': Incompatible algorithm and key (RuntimeError)

params = {"type"=>"public-key", 
  "id"=>"WnlEZ01iWG52QmhkN0tnZnhCZWpKVkNoMjNOSjNlVk52U2o1MW9pWGxJTUQrcWdqYmVMT3p4TzBRTjJWYXkvaWtUb1FJWW1PL09ZbFNzSWpTVFJBSkE9PUBsb2NhbGhvc3Q=", 
  "rawId"=>"WnlEZ01iWG52QmhkN0tnZnhCZWpKVkNoMjNOSjNlVk52U2o1MW9pWGxJTUQrcWdqYmVMT3p4TzBRTjJWYXkvaWtUb1FJWW1PL09ZbFNzSWpTVFJBSkE9PUBsb2NhbGhvc3Q", 
  "response"=>{
      "clientDataJSON"=>"eyJjaGFsbGVuZ2UiOiJiaExKcUh6U2U3clJJWlpaRjZKekVhOGlhbE43azByQlR2LWhhWVVkLWZFIiwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJjaHJvbWUtZXh0ZW5zaW9uOi8va2NkaG5pZ2FrYWpqZGVlamVrbmhja2dsaGljbGtlb2QiLCJ0b2tlbkJpbmRpbmciOnsic3RhdHVzIjoibm90LXN1cHBvcnRlZCJ9LCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0", 
      "authenticatorData"=>"XrwlL61LKPUFL9scrQoOvQNU8793_lluuCPgHw2VHH0AAAABAA", 
      "signature"=>"FK4oomA6YmzLu0Ag-x7iDTLjukjZfGgoaimSU4ZNlusMasipTe-OQzWHYlNVaPK1AVtjZ8dqYQJMvegexsWbBw", 
      "userHandle"=>""}, 
  "session"=>{
      "type"=>"public-key", 
      "id"=>"WnlEZ01iWG52QmhkN0tnZnhCZWpKVkNoMjNOSjNlVk52U2o1MW9pWGxJTUQrcWdqYmVMT3p4TzBRTjJWYXkvaWtUb1FJWW1PL09ZbFNzSWpTVFJBSkE9PUBsb2NhbGhvc3Q=", 
      "rawId"=>"WnlEZ01iWG52QmhkN0tnZnhCZWpKVkNoMjNOSjNlVk52U2o1MW9pWGxJTUQrcWdqYmVMT3p4TzBRTjJWYXkvaWtUb1FJWW1PL09ZbFNzSWpTVFJBSkE9PUBsb2NhbGhvc3Q", 
      "response"=>{
          "clientDataJSON"=>"eyJjaGFsbGVuZ2UiOiJiaExKcUh6U2U3clJJWlpaRjZKekVhOGlhbE43azByQlR2LWhhWVVkLWZFIiwiaGFzaEFsZ29yaXRobSI6IlNIQS0yNTYiLCJvcmlnaW4iOiJjaHJvbWUtZXh0ZW5zaW9uOi8va2NkaG5pZ2FrYWpqZGVlamVrbmhja2dsaGljbGtlb2QiLCJ0b2tlbkJpbmRpbmciOnsic3RhdHVzIjoibm90LXN1cHBvcnRlZCJ9LCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0", 
          "authenticatorData"=>"XrwlL61LKPUFL9scrQoOvQNU8793_lluuCPgHw2VHH0AAAABAA", 
          "signature"=>"FK4oomA6YmzLu0Ag-x7iDTLjukjZfGgoaimSU4ZNlusMasipTe-OQzWHYlNVaPK1AVtjZ8dqYQJMvegexsWbBw", 
          "userHandle"=>""}}}

require "bundler/setup"
require "webauthn"
require "byebug"

authenticator_data_bytes = Base64.urlsafe_decode64(params["response"]["authenticatorData"])
client_data_json = Base64.urlsafe_decode64(params["response"]["clientDataJSON"])
signature = Base64.urlsafe_decode64(params["response"]["signature"])

authenticator_data = WebAuthn::AuthenticatorData.deserialize(authenticator_data_bytes)
client_data = WebAuthn::ClientData.new(client_data_json)

puts WebAuthn::SignatureVerifier
        .new( -7, Base64.urlsafe_decode64("pQECAyYgASFYIGNIWc3GFBYad6u4CTWDXtuB9e5U1cTSYbcVICyE2WyTIlgg0m2lW8SRNKTc0BdI9EgzQPYcOtDWDqmzmOjpnt5Kb0U"))
        .verify(signature, authenticator_data_bytes + client_data.hash)

For what is worth, I'd recommend you use WebAuthn::Credential.from_get(params) in the script to actually recreate the issue - not using the internal SignatureVerifier which is being called with the wrong parameters here - reason why it's raising RuntimeError.

tarun14110 commented 4 years ago

Thanks, @grzuy Your suggestions helped me to get it to work, at least on the demo website. It's been a long time I have been trying to get this to work.

grzuy commented 4 years ago

Excellent!

:clap: :smiley:

tarun14110 commented 4 years ago

@grzuy what would be the right place to ask further questions?

I was able to get it working on the webauthn-rails-demo-app but now getting an error while registering the U2F on Github. Github uses this library, so I thought it would work with GitHub if it works with the demo app. Their developer support said that I'm getting below error on their end.

OpenSSL::PKey::PKeyError EVP_VerifyFinal: nested asn1 error

grzuy commented 4 years ago

@grzuy what would be the right place to ask further questions?

I'd say the Gitter channel https://gitter.im/cedarcode/webauthn-ruby or posting to StackOverflow with the webauthn tag.

I was able to get it working on the webauthn-rails-demo-app but now getting an error while registering the U2F on Github. Github uses this library, so I thought it would work with GitHub if it works with the demo app. Their developer support said that I'm getting below error on their end.

OpenSSL::PKey::PKeyError EVP_VerifyFinal: nested asn1 error

Bummer. Difficult to say.

Only I can assume it's the error is when using a public key to verify a signature. That can be the credential public key or a certificate pubilc key if certificate chain validation is being performed.