Example #1
0
// 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
}
Example #2
0
// 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)
	}
}
Example #3
0
// 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
}
Example #4
0
func decryptHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()

	Metrics.Requests.Add(1)

	otp := r.FormValue("otp")

	if otp == "" {
		Metrics.Errors.Add(1)
		glog.Info("ERR No OTP provided")
		http.Error(w, "ERR No OTP provided", http.StatusOK)
		return
	}

	if len(otp) < 32 || len(otp) > 48 || !yubikey.ModHexP([]byte(otp)) {
		Metrics.Errors.Add(1)
		glog.Info("ERR Invalid OTP format: ", otp)
		http.Error(w, "ERR Invalid OTP format", http.StatusOK)
		return
	}

	pubid, yotp, err := yubikey.ParseOTPString(otp)

	stmt, err := KeysDB.Prepare("SELECT aeskey, internalname FROM yubikeys WHERE publicname = ? AND active = 1")
	if err != nil {
		Metrics.Errors.Add(1)
		glog.Error("ERR DB error during Prepare(): ", err)
		http.Error(w, "ERR Database error", http.StatusOK)
		return
	}
	defer stmt.Close()
	var aeskeyHex string
	var name string
	err = stmt.QueryRow(string(pubid)).Scan(&aeskeyHex, &name)
	if err != nil {
		Metrics.Errors.Add(1)
		if err == sql.ErrNoRows {
			glog.Info("ERR Unknown yubikey: ", string(pubid))
			http.Error(w, "ERR Unknown yubikey", http.StatusOK)
		} else {
			glog.Error("ERR DB error during SELECT: ", err)
			http.Error(w, "ERR Database error", http.StatusOK)
		}
		return
	}

	var aesKey yubikey.Key

	hex.Decode(aesKey[:], []byte(aeskeyHex)) // error ignored, we trust the database

	token, err := yotp.Parse(aesKey)
	if err != nil {
		Metrics.Errors.Add(1)
		glog.Info("ERR Corrupt OTP (Parse failed): ", otp)
		http.Error(w, "ERR Corrupt OTP", http.StatusOK)
		return
	}

	nameBytes, _ /* err */ := hex.DecodeString(name) // error ignored, we trust the database

	if !bytes.Equal(nameBytes, token.Uid[:]) {
		Metrics.Errors.Add(1)
		glog.Warning("ERR Corrupt OTP (UID mismatch): ", otp)
		http.Error(w, "ERR Corrupt OTP", http.StatusOK)
		return
	}

	response := fmt.Sprintf("OK counter=%04x low=%04x high=%02x use=%02x", token.Ctr, token.Tstpl, token.Tstph, token.Use)

	glog.Info(response)
	fmt.Fprintf(w, response)
}