dicekeys / seeding-webauthn

A spec for deriving FIDO key pairs from a seed
9 stars 0 forks source link

Should extState be authenticated by credentialMac and thus part of the generated key? #8

Closed UppaJung closed 4 years ago

UppaJung commented 4 years ago

The most conventional way to use a MAC for the credentialId would be to MAC all of the fields.

We discussed two reasons why we might not want to include the extState in the MAC.

  1. A user might want to correct the extState value, which they can't do if it's MAC'd.
  2. A replacement authenticator might not have enough memory to keep the same extState value

Regarding (1), once the extState is part of a credentialId, the relying party will be using that ID as an identifier and will not want it changed. Hence, it's not really able to change it regardles.

Regarding (2), a replica authenticator doesn't need to have matching extState. It only uses extState when registering new keys. For any existing keys, the extState is sent to it. A replacement authenticator will work just fine even if it doesn't have the same extState.

As such, unless there's another good reason put forth or I've made a mistake in discarding the above two, I'm going to propose we stick with having a MAC behave in the most common way: MAC'ing all the data in the message that comes before it.

nickray commented 4 years ago

I think I am fine with keeping extState in the credentialMac, although probably for different reasons than you.

Current

Pro:

Con:

The optionality of extState in MC is what brings me nearly on board, its necessity in verification during GA is what still bothers me.

Alternative

The only alternative I could think of is the following (which has downsides of its own), just writing it down to get this out of my system:

credentialId = version || uniqueId || coreMac [, || extState || extMac ]
coreMac = HMAC(seed, rpIdHash || version || uniqueId)
C[0] = HMAC(seed, coreMac)   # NB: no extState used here!
extMac = HMAC(seed, rpIdHash || version || uniqueId || coreMac || extState)
 # or possibly just: HMAC(seed, coreMac || extState)

where square brackets in credentialId mean

During GA, it would be compulsory to recalculate/check coreMac ( = bound to RP, uniqueId not modified), but optional to do so for extMac (extState authentic).

Pros:

Cons:

I guess the original alternative as discussed earlier today was not having the second MAC, but just removing extState from the usual MAC and switching order to credentialId = version || uniqueId || MAC || extState.

Remarks

In practice, STM32L432 has 64KB of RAM while LPC55S69 has 320KB, so we have enough RAM :)

I somewhat fear if extState handling is needed in GA operations, then some (anti-extState) implementations may only be interoperable with others that do not include extState in the credential ID (i.e., calculate coreMac instead of credentialMac, complain if they do not coincide).

UppaJung commented 4 years ago

Okay, then I'll close this

I somewhat fear if extState handling is needed in GA operations, then some (anti-extState) implementations may only be interoperable with others that do not include extState in the credential ID (i.e., calculate coreMac instead of credentialMac, complain if they do not coincide).

As we may have future versions that change things, having a MAC authenticate all the bytes that come before it in a message is the most standard approach that's least likely to change if the format changes in future versions. If you're an anti-extState implementer, just ignore the field and just know that you're using MACs the way they're supposed to be used: with no need to have any idea what's in the message itself.