Yubico / yubikey-personalization

YubiKey Personalization cross-platform library and tool
https://developers.yubico.com/yubikey-personalization/
BSD 2-Clause "Simplified" License
297 stars 83 forks source link

ykchalresp returns the same response for 2 different challenges #174

Closed invidian closed 3 years ago

invidian commented 3 years ago

Running the following script to reproduce:

#!/bin/bash
SLOT=1
DATA=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1)

echo "Generating response for ${#DATA} characters challenge '${DATA}'"
echo
ykchalresp -${SLOT} ${DATA}
echo

echo "Removing one character from DATA to show that response does not change."
DATA="${DATA::-1}"
echo

echo "Generating response for ${#DATA} characters challenge '${DATA}'"
echo
ykchalresp -${SLOT} ${DATA}
echo

echo "Removing one more character from DATA to trigger response change."
DATA=${DATA::-1}
echo

echo "Generating response for ${#DATA} characters challenge '${DATA}'"
echo
ykchalresp -${SLOT} ${DATA}
echo

echo "Adding three extra characters to DATA to exceed allowed challenge size."
DATA="${DATA}xxx"
echo

echo "Generating response for ${#DATA} characters challenge '${DATA}'"
echo
ykchalresp -${SLOT} ${DATA}

Produces the following result:

$ bash ykchalresp-off-by-one.sh
Generating response for 64 characters challenge 'f7DPmXcXCcfLSsYsImWXV6FEY7frzynHOFHonfCA5PURcrYbwhgg5qo7SybKKPLn'

037443e8a86c480848f1dc68157ba31ab682a019

Removing one character from DATA to show that response does not change.

Generating response for 63 characters challenge 'f7DPmXcXCcfLSsYsImWXV6FEY7frzynHOFHonfCA5PURcrYbwhgg5qo7SybKKPL'

037443e8a86c480848f1dc68157ba31ab682a019

Removing one more character from DATA to trigger response change.

Generating response for 62 characters challenge 'f7DPmXcXCcfLSsYsImWXV6FEY7frzynHOFHonfCA5PURcrYbwhgg5qo7SybKKP'

6f2949e72543b7c0ffd2b675fdc7e6b2eeaa5f0a

Adding three extra characters to DATA to exceed allowed challenge size.

Generating response for 65 characters challenge 'f7DPmXcXCcfLSsYsImWXV6FEY7frzynHOFHonfCA5PURcrYbwhgg5qo7SybKKPxxx'

Yubikey core error: wrong size

You can see that in first 2 cases, the given response is the same, where it should be different. Testing against openssl, specifically:

openssl dgst -sha1 -mac HMAC -macopt hexkey:<your challenge response secret key from configuration log>

Gives different result properly.

There seems to be something wrong with boundary checking of input I suppose.

invidian commented 3 years ago

Did some debugging, it seems data sent to the YubiKey is actually different as expected:

$ ./ykchalresp -1 f7DPmXcXCcfLSsYsImWXV6FEY7frzynHOFHonfCA5PURcrYbwhgg5qo7SybKKPZ; ./ykchalresp -1 f7DPmXcXCcfLSsYsImWXV6FEY7frzynHOFHonfCA5PURcrYbwhgg5qo7SybKKPZz
Payload: f7DPmXcXCcfLSsYsImWXV6FEY7frzynHOFHonfCA5PURcrYbwhgg5qo7SybKKPZ
YK_DEBUG: Write 63 bytes to YubiKey :
          yk_write_to_key: 66 37 44 50 6d 58 63 80
          yk_write_to_key: 58 43 63 66 4c 53 73 81
          yk_write_to_key: 59 73 49 6d 57 58 56 82
          yk_write_to_key: 36 46 45 59 37 66 72 83
          yk_write_to_key: 7a 79 6e 48 4f 46 48 84
          yk_write_to_key: 6f 6e 66 43 41 35 50 85
          yk_write_to_key: 55 52 63 72 59 62 77 86
          yk_write_to_key: 68 67 67 35 71 6f 37 87
          yk_write_to_key: 53 79 62 4b 4b 50 5a 88
          yk_write_to_key: 00 30 51 51 00 00 00 89
4e7dfc01e3b0ee66a1aa730fc1ace1d581fa4b43
Payload: f7DPmXcXCcfLSsYsImWXV6FEY7frzynHOFHonfCA5PURcrYbwhgg5qo7SybKKPZz
YK_DEBUG: Write 64 bytes to YubiKey :
          yk_write_to_key: 66 37 44 50 6d 58 63 80
          yk_write_to_key: 58 43 63 66 4c 53 73 81
          yk_write_to_key: 59 73 49 6d 57 58 56 82
          yk_write_to_key: 36 46 45 59 37 66 72 83
          yk_write_to_key: 7a 79 6e 48 4f 46 48 84
          yk_write_to_key: 6f 6e 66 43 41 35 50 85
          yk_write_to_key: 55 52 63 72 59 62 77 86
          yk_write_to_key: 68 67 67 35 71 6f 37 87
          yk_write_to_key: 53 79 62 4b 4b 50 5a 88
          yk_write_to_key: 7a 30 8c 8d 00 00 00 89
4e7dfc01e3b0ee66a1aa730fc1ace1d581fa4b43

Notice:

          yk_write_to_key: 00 30 51 51 00 00 00 89

vs

          yk_write_to_key: 7a 30 8c 8d 00 00 00 89

In last line.

So it seems YubiKey actually hashes only 63 bytes of input, not 64 bytes?

klali commented 3 years ago

This depends on how the YubiKey was configured, if the flag HMAC_LT64 is set the YubiKey will hash up to 63 bytes, considering byte 64 (and additional identical bytes from the end) as padding. If that flag is not set 64 bytes is hashed.

invidian commented 3 years ago

Thanks for the reference @klali. It all make sense now, but I still find it confusing. Is there a way ykchalresp could detect this configuration and act accordingly?

invidian commented 3 years ago

I'm also trying to find the limitations of not setting the hmac-lt64 flag. IIRC, ykman otp chalresp sets it automatically and there is no way of changing it. If so, you need to use ykpersonalize, right? If the flag isn't set, it's only accepting exactly 64 bytes challenge? I wonder when this is needed.

dainnilsson commented 3 years ago

This is correct, ykman does not expose not setting hmac-lt64, and this does mean that challenges need to be 0-63 bytes long. Unfortunately the YubiKey doesn't provide a mechanism to check if this flag is set or not, so there is no way for the tools to know this, and this can lead to some unintuitive behavior sometimes, as you've seen. Personally I haven't seen a use case for not setting hmac-lt64 (ie. always using challenges that are exactly 64 bytes).

invidian commented 3 years ago

Thanks for the explanation. I guess this can be closed now :+1: