From 3d4336bab7192eb796a4edc8416d2fe055e0aa71 Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Thu, 17 Oct 2024 09:59:19 -0400 Subject: [PATCH] edits --- docs/web2fa.md | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/docs/web2fa.md b/docs/web2fa.md index f53c1838..ea2e016c 100644 --- a/docs/web2fa.md +++ b/docs/web2fa.md @@ -2,14 +2,17 @@ How to support [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238) TOTP (Time based One Time Password) 2FA check, on our little embedded -device without a clock? +device without a real-time clock? -Solution: Store the preshared secret in the Colcard, and send that +Solution: Store the pre-shared secret in the Coldcard, and send that securely to a trusted webserver which knows the time and can do a fancy UX. The backend accepts the numeric code and reveals a secret that can be used back on the Coldcard to authorize an action. -## History / Background +For the Mk4, the secret is 8 digit numeric code to be entered, +for the COLDCARD Q, it is a QR code to be scanned. + +### History / Background The HSM feature uses HOTP tokens, which do not require a backend, but are not as robust as time-based tokens. @@ -22,40 +25,44 @@ but we may find other uses for it. - Web backend has a ECC keypair, with pubkey known to CC firmware releases. - Usual 2fa base32 secret is picked by CC and stored in CC (so that server is stateless) - CC creates URL encrypted to the pubkey of server, containing args: - - shared secret - - the good nonce (16 bytes, or only 8 decimal digits for Mk4) to be provided back + - shared secret for TOTP (same value as held in user's phone) + - the response nonce (16 bytes, or 8 digits for Mk4) to be revealed to the user on successful auth - flag if Q model, so can provide a QR to be scanned in that case (rather than digits) - - some text label for what's being approved [presented to user so they can pick - correct 2fa shared secret] - - above is all encrypted in the URL. + - some text label for what's being approved, which is presented to user so they can pick + correct 2fa shared secret. + - above is all encrypted in transit, and only the server can decrypt - user is sent to that encrypted URL using NFC tap on the Coldcard - user arrives at server: - shown label [which also indicates the server can be trusted, since only it could decrypt it] - prompt for 6 digits from authenticator app - - does [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238) 2FA check + - does [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238) 2FA check using current time - checks using current time and the shared secret provided by CC, fails if wrong. - time based failure: offer retry (they typed too slow / minor clock drift) - can offer to retry, but also do some rate limiting (only one attempt per 30-sec period) - server will store very recent responses so attacker cannot get two codes in any 30sec period (ie. blocks immediate reuse of same URL) -- if Q, show a QR code to be scanned, with the full nonce -- for non-Q system, a 8-digit decimal value is given: user has to enter that into the Coldcard -- web site shows instructions about what to do next on product. + - until a valid code is given, user is stuck here +- when valid token received: + - if Q, show a QR code to be scanned, with the full nonce + - for non-Q system, a 8-digit decimal value is given: user has to enter that into the Coldcard + - web site shows instructions about what to do next on product. ## From Coldcard PoV -- makes complex encrypted URL, waits for number back (or QR) +- makes complex encrypted URL, which contains a nonce it wants, waits for that nonce back (or QR) - it's either the nonce from the URL, or fail -- if the good nonce, then we know the server knows our shared secret and we - are trusting it actually verify the 2FA token. +- if the right nonce, then we know the server knows the decryption key, and we + are trusting it actually verify the 2FA token properly. ## Encryption - Simple ECDH - CC picks a secp256k1 keypair, generates compressed pubkey -- multiplies that by server's known public key, sha256(that coordinate) is the session key +- multiplies that private key by server's known public key +- apply sha256(resulting coordinate) => the session key - apply AES-256-CTR over URL contents (ascii text) -- prepend 33 bytes of pubkey, and base64url encode the result +- prepend 33 bytes of pubkey, and base64url encode all of it +- full url is: `https://coldcard.com/2fa?{base64 encoded binary}` ## Trust Issues @@ -66,6 +73,8 @@ but we may find other uses for it. - Only we can run the server, because the private key is company-secret. - MiTM and network snoopers get nothing because HTTPS is used and only your browser can see the nonce, and only after you've given the right digits. +- Coinkite server could skip the 2FA checks and just give you the answer + you want to type into the Coldcard. Again, you have to trust us on that. ## URL Format