Yes yes, Cunningham's law etc etc!
I want to play around with 2FA codes. So, I started looking for the specification. Turns out, there isn't one. Not really.
IANA has a provisional registration - but no spec.
It links to an archived Google Wiki which, as we'll come on to, isn't sufficient.
There's some documentation from Yubico which is mostly a copy of the Google wiki with some incompatible tweaks.
The Internet Initiative Japan has a subtly different spec which includes an
icon parameter not seen in any other.
Hidden halfway down the IETF tracker for Extensions to Salted Challenge Response (SCRAM) for 2 factor authentication is yet another specification which is incompatible with the others!
Oh, and IBM has yet another one!
Of course, Apple have their own special Apple-specific version. It is identical to Google's, but uses the
apple-otpauth: scheme. Because.
Here's a quick table comparing them:
|No encoding specified||No encoding specified||URI Encoding||N/A||No encoding specified|
|URI encoding||URI encoding||URI encoding||N/A||No encoding specified|
|Arbitrary length Base32||Arbitrary length Base32||Arbitrary length Base32||40 * HEXCHAR||Not specified|
|SHA1 / SHA256 / SHA512||SHA1 / SHA256 / SHA512||SHA1 / SHA256 / SHA512 / MD5||-||HmacSHA1 / HmacSHA256 / HmacSHA512|
|6 / 8||6 / 7 / 8||6 / 8||-||6 - 9 characters or numbers|
|Arbitrary number of seconds||15 / 30 / 60||Arbitrary number of seconds||-||Arbitrary number of seconds|
|URL encoding||URL encoding||No encoding specified||1*CHAR||No encoding specified|
I tried creating a variety of codes on the fringes of the specification - more than 8 digits, lower than 15 second periods, weird issuers - to see what would happen if my trusting friends scanned them with their TOTP apps.
Even weirder, in the Android app it is a 10 digit OTP but on the windows app it's a normal 6 digit one.— Sam Nalty (@samnalty) May 6, 2022
Seems to work as my others do (in Google Authenticator), apart from the name is emojis and some RTL text— Ben Nuttall (@ben_nuttall) May 6, 2022
Keychain in iOS seemed to ingest it, but not sure where it went...— Serge (@kerguio) May 6, 2022
Authy says "Token format invalid"— John (@Johninnit) May 6, 2022
Formally standardised specifications are a good thing. They mean that everyone is on a level playing-field and innovation can happen without actors enclosing the commons.
More prosaically, it means that users can be confident that any app will work with any code from any provider. And implementers can have a forum where they can propose enhancements to the spec which won't break users' devices.
The URI encoding trips up a number of publishers - more on that in a later blog post.
Should there be a maximum or minimum length to the secret? Why? Why not?
Is it a wise idea to fix those algorithms? Does it matter if a weaker one is in there? Can they be deprecated?
Why just 6 or 8 digits? What's wrong with an arbitrary number of digits? What about using letters or other symbols?
The period is in seconds. Does that mean whole seconds? Can users reliably type in 8 digit codes which change every 15 seconds?
"Issuer" is in there twice. What if they don't match each other?
Do users want an "icon"? Should it be a Base64 encoded graphic? If so, what format? If not, is a URL sufficient?
I'm sure there are half-a-dozen more gripes you could come up with.
I am so tired of Google getting bored halfway through designing something - and then expecting the rest of us to just figure out what they meant.
We're now in a situation where everyone is (rightly) pushing TOTP for 2FA, but there's no formal specification for how users can scan those codes into their apps. There's no way to propose changes. And there's no guarantee that a user will be able to reliably scan the codes they are given.