OTP routines

This commit is contained in:
Xavier Henner 2019-07-09 12:34:45 +02:00
parent 55ae63dc1d
commit f975a19f65
4 changed files with 138 additions and 17 deletions

57
crypto.go Normal file
View File

@ -0,0 +1,57 @@
package main
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base32"
"encoding/binary"
"errors"
"fmt"
"hash"
"math"
"strings"
"time"
)
func ComputeHmac256(message string, secret string) []byte {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(message))
return h.Sum(nil)
}
func encodeSecret(secret []byte) string {
return strings.TrimRight(base32.StdEncoding.EncodeToString(secret), "=")
}
func GenericTotpCode(secret string, t time.Time, algo string, digits int, period int) (string, error) {
var mac hash.Hash
var format string
now := [8]byte{}
binary.BigEndian.PutUint64(now[:], uint64(math.Floor(float64(t.Unix())/float64(period))))
binsecret, _ := base32.StdEncoding.DecodeString(secret)
switch algo {
case "sha1":
mac = hmac.New(sha1.New, binsecret)
case "sha256":
mac = hmac.New(sha256.New, binsecret)
default:
return "", errors.New("unsupported algorithm")
}
switch digits {
case 6:
format = "%06d"
case 8:
format = "%08d"
default:
return "", errors.New("unsupported code size")
}
mac.Write(now[:])
sum := mac.Sum(nil)
return fmt.Sprintf(format, (binary.BigEndian.Uint32(sum[sum[len(sum)-1]&0xf:])&0x7fffffff)%1000000), nil
}

View File

@ -35,6 +35,10 @@ func main() {
server.slackTemplate2 = config.GetString("config.slackTemplate2", "") server.slackTemplate2 = config.GetString("config.slackTemplate2", "")
server.cacheDir = config.GetString("config.cacheDir", "") server.cacheDir = config.GetString("config.cacheDir", "")
server.authCa = config.GetString("config.authCa", "") server.authCa = config.GetString("config.authCa", "")
server.otpMasterSecrets = parseConfigArray(config, "config.masterSecrets")
if len(server.otpMasterSecrets) == 0 {
server.otpMasterSecrets = append(server.otpMasterSecrets, "*******************")
}
server.syslog = false server.syslog = false
if *logToSyslog { if *logToSyslog {

42
otp.go Normal file
View File

@ -0,0 +1,42 @@
package main
import (
"log"
"time"
)
func (s *OpenVpnMgt) GenerateOTP(user string) ([]string, error) {
return s.GenerateOTPGeneric(user, 30, "sha1", 10, 6)
}
// alternative OTP generator, not used at the moment
func (s *OpenVpnMgt) GenerateSlackOTP(user string) ([]string, error) {
return s.GenerateOTPGeneric(user, 60, "sha256", 30, 8)
}
func (s *OpenVpnMgt) GenerateOTPGeneric(user string, period int, algo string, secretLen int, digits int) ([]string, error) {
codes := []string{}
now := time.Now()
secret := encodeSecret(ComputeHmac256(user, s.otpMasterSecrets[0])[:secretLen])
code, err := GenericTotpCode(secret, now, algo, digits, period)
if err != nil {
return codes, err
}
// the first code is the generic one
codes = append(codes, code)
for i := 1; i < 3; i++ {
code, _ = GenericTotpCode(secret, now.Add(-1*time.Second*time.Duration(period*i)), algo, digits, period)
codes = append(codes, code)
}
for j := 1; j < len(s.otpMasterSecrets); j++ {
secret = encodeSecret(ComputeHmac256(user, s.otpMasterSecrets[j])[:secretLen])
for i := 0; i < 3; i++ {
code, _ = GenericTotpCode(secret, now.Add(-1*time.Second*time.Duration(period*i)), algo, digits, period)
codes = append(codes, code)
}
}
return codes, nil
}

View File

@ -13,23 +13,24 @@ import (
// Server represents the server // Server represents the server
type OpenVpnMgt struct { type OpenVpnMgt struct {
Port string Port string
buf *bufio.ReadWriter buf *bufio.ReadWriter
connected bool connected bool
m sync.RWMutex m sync.RWMutex
ret chan []string ret chan []string
ldap map[string]ldapConfig ldap map[string]ldapConfig
authCa string authCa string
vpnlogUrl string vpnlogUrl string
mailRelay string mailRelay string
MailFrom string MailFrom string
CcPwnPassword string CcPwnPassword string
pwnTemplate string pwnTemplate string
newAsTemplate string newAsTemplate string
slackTemplate string slackTemplate string
slackTemplate2 string slackTemplate2 string
cacheDir string cacheDir string
syslog bool syslog bool
otpMasterSecrets []string
} }
// NewServer returns a pointer to a new server // NewServer returns a pointer to a new server
@ -86,6 +87,23 @@ func (s *OpenVpnMgt) Auth(c *vpnSession) (error, bool) {
c.password = "" c.password = ""
} }
// if the otp is indicated, we check it against the valid codes as soon as
// possible
otpvalidated := false
if c.otpCode != "" {
codes, err := s.GenerateOTP(c.Login)
if err != nil {
return err, false
}
for _, possible := range codes {
if possible == c.otpCode {
otpvalidated = true
}
}
}
log.Println(otpvalidated)
c.Profile = "" c.Profile = ""
login := []string{c.Login} login := []string{c.Login}
pass := c.password pass := c.password