otp/hotp_test.go

219 lines
4.9 KiB
Go

package otp
import "testing"
var rfc4226Secret = "12345678901234567890"
var rfc4226Codes = []string{
"755224",
"287082",
"359152",
"969429",
"338314",
"254676",
"287922",
"162583",
"399871",
"520489",
}
var baseRFC4226URL = "otpauth://hotp/IETF:ReferenceImplementation?counter=0&digits=6&issuer=IETF&secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"
func TestRFC4226OTP(t *testing.T) {
issuer := "IETF"
label := "ReferenceImplementation"
o := NewHOTPKeyOptions()
o.Secret = []byte(rfc4226Secret)
o.Issuer = issuer
o.Label = label
h := NewHOTPKey(o)
code, counter := h.IntegrityCheck()
if code != rfc4226Codes[counter] {
t.Logf("Invalid HOTP code for counter %d", counter)
t.Logf("\tExpected:\t%s\n", rfc4226Codes[counter])
t.Logf("\tActual: \t%s\n", code)
t.FailNow()
}
for counter, code := range rfc4226Codes[1:] {
generated := h.OTP()
if code != generated {
t.Logf("Invalid HOTP code for counter %d", counter)
t.Logf("\tExpected:\t%s\n", code)
t.Logf("\tActual: \t%s\n", generated)
t.FailNow()
}
}
if h.Issuer() != issuer {
t.Log("Invalid Issuer found")
t.Logf("\tExpected:\t%s\n", issuer)
t.Logf("\tActual: \t%s\n", h.Issuer())
t.FailNow()
}
if h.Label() != label {
t.Log("Invalid Issuer found")
t.Logf("\tExpected:\t%s\n", label)
t.Logf("\tActual: \t%s\n", h.Label())
t.FailNow()
}
if h.Type() != HOTP {
t.Log("Invalid Key type found")
t.Logf("\tExpected:\t%s\n", HOTP)
t.Logf("\tActual: \t%s\n", h.Type())
t.FailNow()
}
}
func TestRFC4226CustomCounter(t *testing.T) {
issuer := "IETF"
label := "ReferenceImplementation"
o := NewHOTPKeyOptions()
o.Secret = []byte(rfc4226Secret)
o.Issuer = issuer
o.Label = label
h := NewHOTPKey(o)
code, counter := h.IntegrityCheck()
if code != rfc4226Codes[counter] {
t.Logf("Invalid HOTP code for counter %d", counter)
t.Logf("\tExpected:\t%s\n", rfc4226Codes[counter])
t.Logf("\tActual: \t%s\n", code)
t.FailNow()
}
for counter, code := range rfc4226Codes[1:] {
if !h.Verify(code, uint64(counter)) {
t.Logf("Invalid HOTP code for counter %d", counter)
t.Logf("\tExpected:\t%s\n", code)
t.FailNow()
}
}
}
func TestRFC4226FromURL(t *testing.T) {
h, err := FromURL(baseRFC4226URL)
if err != nil {
t.Log(err.Error())
t.FailNow()
}
k := h.(*HOTPKey)
code, counter := k.IntegrityCheck()
if code != rfc4226Codes[counter] {
t.Logf("Invalid HOTP code for counter %d", counter)
t.Logf("\tExpected:\t%s\n", rfc4226Codes[counter])
t.Logf("\tActual: \t%s\n", code)
t.FailNow()
}
for counter, code := range rfc4226Codes[1:] {
generated := h.OTP()
if code != generated {
t.Logf("Invalid HOTP code for counter %d", counter)
t.Logf("\tExpected:\t%s\n", code)
t.Logf("\tActual: \t%s\n", generated)
t.FailNow()
}
}
}
func TestRFC4226ToURL(t *testing.T) {
o := NewHOTPKeyOptions()
o.Secret = []byte(rfc4226Secret)
o.Issuer = "IETF"
o.Label = "ReferenceImplementation"
h := NewHOTPKey(o)
if h.URL() != baseRFC4226URL {
t.Log("Invalid URL from RFC 4226 reference HOTP key")
t.Logf("\tExpected:\t%s\n", baseRFC4226URL)
t.Logf("\tActual: \t%s\n", h.URL())
t.FailNow()
}
}
func TestRFC4226Verify(t *testing.T) {
o := NewHOTPKeyOptions()
o.Secret = []byte(rfc4226Secret)
h := NewHOTPKey(o)
for counter, code := range rfc4226Codes {
if !h.Verify(code) {
t.Logf("Invalid HOTP code for counter %d", counter)
t.Logf("\tExpected:\t%s\n", code)
t.FailNow()
}
}
}
func TestRFC4226CustomValidate(t *testing.T) {
secret := []byte(rfc4226Secret)
for counter, code := range rfc4226Codes {
if !ValidateCustom(secret, uint64(counter), code) {
t.Logf("Invalid HOTP code for counter %d", counter)
t.Logf("\tExpected:\t%s\n", code)
t.FailNow()
}
}
}
func TestRFC4226CustomCode(t *testing.T) {
secret := []byte(rfc4226Secret)
for counter, code := range rfc4226Codes {
generated := CustomCode(secret, uint64(counter), uint(len(code)))
if code != generated {
t.Logf("Invalid HOTP code for counter %d", counter)
t.Logf("\tExpected:\t%s\n", code)
t.Logf("\tActual: \t%s\n", generated)
t.FailNow()
}
}
}
func TestHOTPVerify(t *testing.T) {
k := NewHOTPKey()
first := k.OTP()
if !k.Verify(first) { //successful verify increments counter
t.Logf("HOTP key %s failed to properly verify the first code - %s", k.URL(), first)
t.FailNow()
}
if !k.Verify(first) { //successful verify increments counter
t.Logf("HOTP key %s failed to properly verify the first code - %s", k.URL(), first)
t.Logf("First code should still be verified because of AllowedSkew")
t.FailNow()
}
if k.Verify(first) { //Key should have advanced to the next code
t.Logf("HOTP key %s should not have verified the first code - %s", k.URL(), first)
t.FailNow()
}
k.SetSkew(3)
if !k.Verify(first) { //successful verify increments counter
t.Logf("HOTP key %s failed to properly verify the first code - %s", k.URL(), first)
t.Logf("First code should still be verified because of AllowedSkew")
t.FailNow()
}
}