// NewYubiKey takes the key and initial OTP and returns an // authenticator. func NewYubiKey(key []byte, initialOTP string) (*Authenticator, error) { pub, otp, err := yubikey.ParseOTPString(initialOTP) if err != nil { return nil, err } tmpKey := yubikey.NewKey(key) token, err := otp.Parse(tmpKey) if err != nil { return nil, err } util.Zero(tmpKey[:]) config := &YubiKeyConfig{ Counter: getTokenCounter(token), Key: key, Public: pub, } defer util.Zero(config.Key[:]) auth := &Authenticator{ Type: TypeYubiKey, Last: initialOTP, Secret: config.Bytes(), } return auth, nil }
// TestBuildUserToken builds the test user token from an OTP. func TestBuildUserToken(t *testing.T) { key, err := hex.DecodeString(testYubiKey) if err != nil { t.Fatalf("%v", err) } tmpKey := yubikey.NewKey(key) _, otp, err := yubikey.ParseOTPString(testInitialYKOTP) if err != nil { t.Fatalf("%v", err) } yubiToken, err = otp.Parse(tmpKey) if err != nil { t.Fatalf("%v", err) } }
// ValidateYubiKey takes an Authenticator that is presumed to be a // YubiKey authenticator and attempts to validate the given OTP // using it. The YubiKey authenticator will always need to be updated // when successful to account for changes in the counter, and to // update the last OTP. func ValidateYubiKey(auth *Authenticator, otp string) (bool, error) { if (auth == nil) || (auth.Type != TypeYubiKey) { return false, ErrInvalidAuthenticator } if auth.Last == otp { return false, ErrValidationFail } config, err := ParseYubiKeyConfig(auth.Secret) if err != nil { return false, ErrInvalidAuthenticator } tmpKey := yubikey.NewKey(config.Key) defer util.Zero(tmpKey[:]) pub, ykOTP, err := yubikey.ParseOTPString(otp) if err != nil { return false, ErrValidationFail } if !bytes.Equal(pub, config.Public) { return false, ErrValidationFail } userToken, err := ykOTP.Parse(tmpKey) if err != nil { return false, ErrValidationFail } if getTokenCounter(userToken) < config.Counter { return false, ErrValidationFail } config.Counter = getTokenCounter(userToken) auth.Last = otp auth.Secret = config.Bytes() return true, nil }