Yubico / php-u2flib-server

(OBSOLETE) U2F library in PHP
https://developers.yubico.com/php-u2flib-server/
BSD 2-Clause "Simplified" License
288 stars 68 forks source link

Firefox support #58

Closed vinpel closed 6 years ago

vinpel commented 6 years ago

Hello,

First thanks for this amazing library, the library is compatible with Firefox ?

Current firefox version : 58.0a1 (2017-11-06) (64 bits) I test with a yubikey neo

With firefox :

when i use the library on my site it work in Chrome, Opéra but not firefox

vinpel commented 6 years ago

I was able to make it work. I changed the javascript file with this one : https://demo.yubico.com/js/u2f-api.js

The javascript call are a little different, here are snippset of my own code to make it work with the library :

When you register a key:

<?php
  list($requete, $signs) = $u2f->getRegisterData($regs);
?>
<script>
    var request = <?=json_encode($requete)?>;
    var signs     = <?=json_encode($signs)?>;
    var appId    = request.appId;
    var registerRequests = [{version: request.version, challenge: request.challenge}];
    u2f.register(appId, registerRequests, signs , function(deviceResponse) {
      ...
    });
</script>

Authentificate :

<?php
 $authenticateData=$u2f->getAuthenticateData($registrations);
 list($requete, $signs) = $u2f->getRegisterData($registrations);
 $challenge        = $authenticateData[0]->challenge;
 $appId            = $authenticateData[0]->appId;

 foreach ($authenticateData as $unecle) {
   $key['version']   = $unecle->version;
   $key['keyHandle'] = $unecle->keyHandle;
   $registeredKey[]  = $key;
 }
?>
<script>
  var appId          = '<?=$appId;?>';
  var challenge      = <?=json_encode($challenge);?>;
  var registeredKeys = <?=json_encode($registeredKey);?>;
  u2f.sign(appId, challenge, registeredKeys, function(deviceResponse) {
    if(deviceResponse.errorCode && deviceResponse.errorCode != 0) {
</script>
Loksly commented 6 years ago

warning:

foreach ($authenticateData as $unecle) {
   $key['version']   = $unecle->version;
   $key['keyHandle'] = $unecle->keyHandle;
   $registeredKey[]  = $key;
 }

I guess should be:

foreach ($authenticateData as $unecle) {
   $key = array(); //<---
   $key['version']   = $unecle->version;
   $key['keyHandle'] = $unecle->keyHandle;
   $registeredKey[]  = $key;
 }

(Sorry if this comment is wrong, I don't have enough knownledge about this library. I was only talking about PHP code semantics)

klali commented 6 years ago

Did you have to change anything in the library except using the newer javascript api? Did you have to change the samples when using that?

vinpel commented 6 years ago

no the library U2F.php is the same.

with the new .js file the call are different, so i have preferd to update the code in my part, without changing the library.

If i have time i will make a PR

andryyy commented 6 years ago

@vinpel In your example u2f.register(appId, registerRequests, signs , cb) does not work when signs is not []. As soon as I pass the previously registred keys as signs to u2f.register, it just fails without any error. @Yubico seems to use [] on their demo page, which will overwrite any previously stored keys.

andryyy commented 6 years ago

It's possible it just silently ignores the same key as it is "excluded". I wonder how I can catch that...

emlun commented 6 years ago

@andryyy Yes, the 3rd parameter to u2f.register is a list of already registered credential identifiers, so that you don't register a new credential on a U2F device that already has one. The Yubico demo page sends [] so you don't have to clear the server's key storage to try registering again (YubiKey devices don't actually store U2F keys on board, so there's no risk of filling the device with garbage keys).

@vinpel Do you have issues with this the first time you try to register a key, or only if you retry the same key again?

andryyy commented 6 years ago

@emlun Yes, I got that, but is it expected that u2f.register silently discards the request then? Previously it would raise errorno 4. Cannot test with a second key actually. :-(

emlun commented 6 years ago

Basically it's because the browser waits for the possibility that you plug in a new device to create a key on that one too. Chrome and Firefox seem to handle the situation differently. Chrome times out with errno 4 (~key already registered), Firefox now times out with errno 1 (~no device available). I also think I remember Firefox returning errno 4 previously.

My guess is that the change is due to privacy considerations - if the command returns different error codes for the cases "No device present" and "Key is present, but user didn't agree by touching the device", then it's possible for a malicious RP (e.g., an ad network) to perfectly identify you (i.e., track you) without your consent.

This behavour (timing out with the same error code in both cases) is also how the upcoming Web Authentication standard will handle the situation. Perhaps Firefox has backported the behaviour from their WebAuthn prototype to U2F as well.

andryyy commented 6 years ago

Thank you @emlun !

vinpel commented 6 years ago

i don't have any issue ( my sample are extracted/recreated from a whole site) I use 2 key register / authentificate with succes

emlun commented 6 years ago

Great! Looks like we can close this, then. Please feel free to reopen the issue if you have anything else to ask or add.