OTP routines
This commit is contained in:
parent
55ae63dc1d
commit
f975a19f65
|
@ -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
|
||||||
|
}
|
4
main.go
4
main.go
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
Loading…
Reference in New Issue