Closed anarcat closed 3 years ago
I've not used yubikeys in hotp mode, but does your command line giving both -o oath-hotp
and -o oath-hotp8
mean that you're trying to use 8 digit codes? This PAM module doesn't support that.
is that something which could be fixed or maybe configurable?
and yes, codes do seem to be 8 digits...
Feature request https://github.com/google/google-authenticator-libpam/issues/20
If you remove -o oath-hotp8
, does it just work?
If you remove -o oath-hotp8, does it just work?
nope. it sends 6 digits, but somehow i still get "Invalid verification code for"... maybe i'm doing something wrong when converting the secret?
Dunno. It should work.
I think the secret conversion must be the problem, yes. It really should work. I say that because GA obviously works with Google accounts that use TOTPs, and presumably HOTP should work just as well. And yubikey oath has been used to log in to Google with TOTP. So it almost logically follows that yubikey oath should work with HOTP.
To test this you should scan the QR code you get, and convert to yk, and play around until you get the same code. So that you don't have to involve PAM and logs and stuff.
Generate a few codes, though, to make sure it's not just a counter off-by-one or something.
To test this you should scan the QR code you get, and convert to yk, and play around until you get the same code.
Note sure how to do this... what does the qrcode have to do with anything?
Did you see the python code I pasted? does it seem reasonable to you?
The QR code lets you load it in the app. The app is compatible with the PAM module. If you get the same code in the app and with the yubikey, then you have succeeded.
I just ran the code, and no that doesn't look right. I think you want b'\x00'
, not b'0'
.
#!/usr/bin/python3
import base64
import binascii
def foo(s):
remainder = len(s) % 8
if remainder > 0:
s += "======"
secret = base64.b32decode(s)
if len(secret) < 20:
secret += b'\x00' * (20 - len(secret))
return binascii.hexlify(secret).decode('ascii')
print(foo('N' * 26))
This gives 6b5ad6b5ad6b5ad6b5ad6b5ad6b5ad6b00000000
instead of 6b5ad6b5ad6b5ad6b5ad6b5ad6b5ad6b30303030
.
duuuh of course! and it works now, thanks!! that's awesome! closing this. :)
(although maybe docs could be updated to show how it works... you'll forgive me but i'll try to update my howto first ;)
note: magic script lives here now https://gitlab.com/anarcat/scripts/blob/master/oath-convert
Looking at the howto. I prefer PIV mode instead of going via gpg, myself. I have some articles about that on https://blog.habets.se/
i think I tried that but gave up. I don't remember exactly why, but I seem to remember it was conflicting with the 2FA HOTP application or something. Also, it's kind of convenient to have the authentication certificate embedded in my OpenPGP key, as people can just fetch and verify the key the normal way and use:
gpg --export-ssh-keys anarcat@debian.org
... to get my SSH key. I guess it would be possible to encapsulate in OpenPGP in the PIV method as well, but that seems rather... complicated.
In theory, this plugin should work with hardware tokens like the Yubikey, which supports OATH+HOTP. In practice, it doesn't work out of the box: the secret generated by the script is base32-encoded, while ykpersonalize expects a hex string. The secret is also 16 bytes instead of the expected 20.
Has anyone tried to make this plugin work with yubikeys? So far my attempts are failing and i'm just wondering if i'm missing anything obvious. So far the YK folks have been quite helpful and simply said to "pad the value with zeros", but so far it doesn't work for me. This is the (python) code I have so far to convert between the two:
I am setting the google authenticator plugin side with:
And writing it to the yubikey with:
The error I'm getting from the pam module is:
The module is hooked into sshd with:
I'm successfully using liboath-pam right now with the yubikey, FWIW.