Reputation: 398
I'm meeting an understanding issue with OTP validation for Yubikey I'm trying to develop in flutter the Validation Protocol V2 (https://developers.yubico.com/OTP/Specifications/OTP_validation_protocol.html)
I don't understand how you obtain the signature I used the vector test from https://developers.yubico.com/OTP/Specifications/Test_vectors.html
my code is
String apiKey = 'mG5be6ZJU1qBGz24yPh/ESM3UdU=';
String keyValue = 'id=1&nonce=jrFwbaYFhn0HoxZIsd9LQ6w2ceU&otp=vvungrrdhvtklknvrtvuvbbkeidikkvgglrvdgrfcdft';
var hmacSha1 = crypto.Hmac(crypto.sha1, apiKey.codeUnits);
crypto.Digest sha1Result = hmacSha1.convert(keyValue.codeUnits);
String hEncode64 = base64.encode(sha1Result.bytes);
final http.Response responseHttp = await http.get(
Uri.parse('https://api.yubico.com/wsapi/2.0/verify?' +
keyValue +
'&h=' +
hEncode64),
);
I don't find the same result as Vector Test (h=%2Bja8S3IjbX593/LAgTBixwPNGX4%3D). -> +ja8S3IjbX593/LAgTBixwPNGX4= But my misunderstanding thing is : when I try to base64 decode your vector test, I can't because it is not utf8 format
and when i try with the test vector available on site, it doesn,'t work
https://api.yubico.com/wsapi/2.0/verify?id=1&otp=vvungrrdhvtklknvrtvuvbbkeidikkvgglrvdgrfcdft&nonce=jrFwbaYFhn0HoxZIsd9LQ6w2ceU&h=%2Bja8S3IjbX593/LAgTBixwPNGX4%3D
h=JE5WcMcXV7vooWkeN2/7A4DpMFo=
t=2021-12-15T12:51:37Z0635
status=BAD_SIGNATURE
Could you help me to understand please my pb
Upvotes: 2
Views: 394
Reputation: 1897
TL;DR: See this bash implementation.
I guess you finally managed to get it running with Dart, but the API can even be curl
ed.
I'm posting this here for future reference for whoever encounters the BAD_SIGNATURE with yubikey in bash.
To correctly generate the HMAC SHA1 with openssl, I had to:
mG5be6ZJU1qBGz24yPh/ESM3UdU=
in the OP's post) and decode it from base64. This generates raw binary data.od
.sed
.xxd
.This finally generated the correct signature.
I've published the steps in the TL;DR in the beginning.
Here's a snapshot:
#!/bin/bash
echo -n "YubiKey token: "
read token
id=$(cat creds | head -1 | cut -d':' -f2)
secret_key=$(cat creds | tail -1 | cut -d':' -f2 | base64 -d | od -A n -v -t x1 | tr -d ' \n')
nonce=$(echo -n $RANDOM | sha256sum | head -c 40 | cut -d ' ' -f1)
challenge="id=$id&nonce=$nonce&otp=$token&sl=100&timeout=8"
signature=$(echo -n $challenge | openssl dgst -sha1 -mac HMAC -macopt hexkey:$(echo -n "$secret_key") | sed 's/^(stdin)= //' | sed -E 's/([[:lower:]])|([[:upper:]])/\U\1\U\2/g'| xxd -r -p | base64)
response=$(curl --silent "https://api.yubico.com/wsapi/2.0/verify?$challenge&h=$signature" | tr '\r' '\n')
echo $response
This uses a file called creds
(obtained by registering an API key here), which contains the following:
Client ID:XXXXX
Secret key:XXXXXXXXXXXXXXXX
Upvotes: 1