yeah so as a temporary measure, i'm using ssh-keygen for now.
but i'll need to natively incorporate it still.
This commit is contained in:
parent
d7ffbea913
commit
7f98e7aa15
@ -31,7 +31,7 @@ import (
|
||||
"r00t2.io/sysutils/paths"
|
||||
)
|
||||
|
||||
func TestConfig(config *[]byte) (bool, error) {
|
||||
func ChkConfig(config *[]byte) (bool, error) {
|
||||
var sysPaths []string
|
||||
var binPath string
|
||||
var tmpConf *os.File
|
||||
|
138
dh/func_gen.go
138
dh/func_gen.go
@ -18,6 +18,17 @@
|
||||
|
||||
package dh
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"r00t2.io/sshsecure/moduli"
|
||||
"r00t2.io/sshsecure/utils"
|
||||
)
|
||||
|
||||
/*
|
||||
OpenSSH does prime generation and primality checking a *little* weird.
|
||||
|
||||
@ -35,4 +46,129 @@ package dh
|
||||
And that's why I'm a sad panda and porting moduli.c to native Golang.
|
||||
*/
|
||||
|
||||
func SieveLarge()
|
||||
// Generate builds a slice of moduli.Entry entries.
|
||||
// TODO: DO THIS NATIVELY. Idealy with goroutines and a channel? buffer? for the primes and sieving.
|
||||
func Generate() (moduliEntries []moduli.Entry, err error) {
|
||||
|
||||
var outFile *os.File
|
||||
var filteredFile string
|
||||
var raw []byte
|
||||
var m *moduli.Moduli = new(moduli.Moduli)
|
||||
|
||||
if outFile, err = genPrimes(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if filteredFile, err = sieve(outFile); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if raw, err = ioutil.ReadFile(filteredFile); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = moduli.Unmarshal(raw, m); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
moduliEntries = m.Groups
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// genPrimes builds a slice of acceptable primes for sieve.
|
||||
// TODO: DO THIS NATIVELY.
|
||||
func genPrimes() (outFile *os.File, err error) {
|
||||
|
||||
var cmdStr []string = []string{"ssh-keygen", "-q"}
|
||||
var cmdStr2 []string
|
||||
var cmd *exec.Cmd
|
||||
var sshVer utils.SshVerInfo
|
||||
// These are various versions we need to compare against for determining features.
|
||||
var ver81 *semver.Version
|
||||
|
||||
if outFile, err = ioutil.TempFile("", ".SSHSecure.moduli.*"); err != nil {
|
||||
return
|
||||
}
|
||||
if err = outFile.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
if err = os.Remove(outFile.Name()); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if sshVer, err = utils.GetSshVer(""); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// They changed the command syntax/options in 8.1. We need to determine if we're at or above that version or not.
|
||||
if ver81, err = semver.NewVersion("8.1.0"); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if sshVer.SemVer.Compare(ver81) >= 0 {
|
||||
cmdStr2 = []string{
|
||||
"-M", "generate",
|
||||
"-O", "bits=4096",
|
||||
outFile.Name(),
|
||||
}
|
||||
} else {
|
||||
cmdStr2 = []string{
|
||||
"-b", "4096",
|
||||
"-G", outFile.Name(),
|
||||
}
|
||||
}
|
||||
cmdStr = append(cmdStr, cmdStr2...)
|
||||
|
||||
cmd = exec.Command(cmdStr[0], strings.Join(cmdStr[1:], " "))
|
||||
if err = cmd.Run(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// sieve filters out unsuitable primes. See #1 and #2 in the comments at the top of this file.
|
||||
// TODO: DO THIS NATIVELY.
|
||||
func sieve(inFile *os.File) (newFile string, err error) {
|
||||
|
||||
var cmdStr []string = []string{"ssh-keygen", "-q"}
|
||||
var cmdStr2 []string
|
||||
var cmd *exec.Cmd
|
||||
var sshVer utils.SshVerInfo
|
||||
// These are various versions we need to compare against for determining features.
|
||||
var ver81 *semver.Version
|
||||
|
||||
if sshVer, err = utils.GetSshVer(""); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
newFile = inFile.Name() + ".filtered"
|
||||
|
||||
// They changed the command syntax/options in 8.1. We need to determine if we're at or above that version or not.
|
||||
if ver81, err = semver.NewVersion("8.1.0"); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if sshVer.SemVer.Compare(ver81) >= 0 {
|
||||
cmdStr2 = []string{
|
||||
"-M", "screen",
|
||||
"-O", "bits=4096",
|
||||
"-f", inFile.Name(),
|
||||
newFile,
|
||||
}
|
||||
} else {
|
||||
cmdStr2 = []string{
|
||||
"-T", newFile,
|
||||
"-f", inFile.Name(),
|
||||
}
|
||||
}
|
||||
cmdStr = append(cmdStr, cmdStr2...)
|
||||
|
||||
cmd = exec.Command(cmdStr[0], strings.Join(cmdStr[1:], " "))
|
||||
if err = cmd.Run(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
1
go.mod
1
go.mod
@ -4,6 +4,7 @@ go 1.16
|
||||
|
||||
require (
|
||||
github.com/Luzifer/go-dhparam v1.1.0
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a
|
||||
github.com/go-restruct/restruct v1.2.0-alpha
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
2
go.sum
2
go.sum
@ -1,5 +1,7 @@
|
||||
github.com/Luzifer/go-dhparam v1.1.0 h1:uJXDwqAVy1H4zWjmsYVmaa9yUD2Pm3SsdW4KU8d27zc=
|
||||
github.com/Luzifer/go-dhparam v1.1.0/go.mod h1:3Kuj59C67/G2EzQHjUzAryaAa70K5fqvStR2VkFLszU=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFnmy/yg3qDTft4rE5DY2uJ/cCxCe3q0XTU=
|
||||
|
@ -24,14 +24,14 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
`time`
|
||||
"time"
|
||||
|
||||
`github.com/Luzifer/go-dhparam`
|
||||
"github.com/Luzifer/go-dhparam"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
// NewModuli returns a Moduli populated with Entry items.
|
||||
func NewModuli(usePreGen ... bool) (m *Moduli, err error) {
|
||||
func NewModuli(usePreGen ...bool) (m *Moduli, err error) {
|
||||
|
||||
var doPreGen bool
|
||||
|
||||
@ -117,13 +117,13 @@ func Generate(m *Moduli) (err error) {
|
||||
var e Entry
|
||||
|
||||
e = Entry{
|
||||
Time: time.Now(),
|
||||
Size: bitLen,
|
||||
Time: time.Now(),
|
||||
Size: bitLen,
|
||||
Generator: uint8(generator),
|
||||
/*
|
||||
Type: 0,
|
||||
Tests: 0,
|
||||
Trials: 0,
|
||||
Type: 0,
|
||||
Tests: 0,
|
||||
Trials: 0,
|
||||
*/
|
||||
}
|
||||
|
||||
@ -143,7 +143,7 @@ func Generate(m *Moduli) (err error) {
|
||||
e.Modulus = *dh.P
|
||||
|
||||
// TODO: https://stackoverflow.com/questions/18499352/golang-concurrency-how-to-append-to-the-same-slice-from-different-goroutines
|
||||
m.Params = append(m.Params, e)
|
||||
m.Groups = append(m.Groups, e)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,13 +34,12 @@ var reSkipLine, _ = regexp.Compile(`^\s*(#.*)?$`)
|
||||
|
||||
// Marshal returns the /etc/ssh/moduli format of m.
|
||||
// Format of: Time Type Tests Tries Size Generator Modulus
|
||||
// TODO: remember to write newline at end
|
||||
func (m *Moduli) Marshal() (bytesOut []byte, err error) {
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
b.Write([]byte(header))
|
||||
for _, i := range m.Params {
|
||||
for _, i := range m.Groups {
|
||||
line, err := i.marshalEntry()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -49,6 +48,8 @@ func (m *Moduli) Marshal() (bytesOut []byte, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
b.Write([]byte("\n"))
|
||||
|
||||
bytesOut = b.Bytes()
|
||||
|
||||
return
|
||||
@ -98,7 +99,7 @@ func Unmarshal(data []byte, m *Moduli) (err error) {
|
||||
entries = append(entries, e)
|
||||
}
|
||||
|
||||
m.Params = entries
|
||||
m.Groups = entries
|
||||
|
||||
return
|
||||
}
|
||||
@ -149,7 +150,7 @@ func (m *Moduli) Harden() (err error) {
|
||||
|
||||
var entries []Entry
|
||||
|
||||
for _, e := range m.Params {
|
||||
for _, e := range m.Groups {
|
||||
|
||||
e.Time = time.Now()
|
||||
|
||||
@ -157,9 +158,9 @@ func (m *Moduli) Harden() (err error) {
|
||||
entries = append(entries, e)
|
||||
}
|
||||
}
|
||||
m.Params = entries
|
||||
m.Groups = entries
|
||||
|
||||
if len(m.Params) < recMinMod {
|
||||
if len(m.Groups) < recMinMod {
|
||||
err = errors.New("does not meet recommended minimum moduli")
|
||||
return
|
||||
}
|
||||
|
@ -23,10 +23,10 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Moduli contains all data needed for generated /etc/ssh/moduli. of ModuliEntry entries.
|
||||
// Moduli contains all data needed for generated /etc/ssh/moduli of Entry entries.
|
||||
type Moduli struct {
|
||||
Header string
|
||||
Params []Entry
|
||||
Groups []Entry
|
||||
}
|
||||
|
||||
// Entry is a struct reflecting the format of a single /etc/ssh/moduli entry. See moduli(5) for details.
|
||||
|
143
utils/func.go
Normal file
143
utils/func.go
Normal file
@ -0,0 +1,143 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
)
|
||||
|
||||
// GetSshVer returns an SshVerInfo. If verStr is an empty string, get the version automatically.
|
||||
func GetSshVer(verStr string) (ver SshVerInfo, err error) {
|
||||
|
||||
var newVerStr string
|
||||
var sslVer OpenSslInfo
|
||||
var sslVerStr string
|
||||
var ptrn *regexp.Regexp
|
||||
var matches []string
|
||||
var verSlice [3]uint
|
||||
var n int
|
||||
var sver *semver.Version
|
||||
|
||||
if verStr == "" {
|
||||
var out []byte
|
||||
cmd := exec.Command("ssh", "-V")
|
||||
if err = cmd.Run(); err != nil {
|
||||
return
|
||||
}
|
||||
if out, err = cmd.Output(); err != nil {
|
||||
return
|
||||
}
|
||||
verStr = string(out)
|
||||
}
|
||||
|
||||
if ptrn, err = regexp.Compile(`^(?:Open|Sun_)SSH_(?P<sshver>[0-9.]+)(?:p?(?P<patchver>[0-9.]+))?,\s*(?P<sslverstr>.*)?$`); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
matches = ptrn.FindStringSubmatch(verStr)
|
||||
|
||||
// Reformat verStr to the combined version string.
|
||||
newVerStr = fmt.Sprintf(
|
||||
"%v.%v",
|
||||
matches[ptrn.SubexpIndex("sshver")],
|
||||
matches[ptrn.SubexpIndex("patchver")],
|
||||
)
|
||||
|
||||
sslVerStr = matches[ptrn.SubexpIndex("sslverstr")]
|
||||
|
||||
if sslVer, err = GetSslVer(sslVerStr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for idx, s := range strings.Split(newVerStr, ".") {
|
||||
if n, err = strconv.Atoi(s); err != nil {
|
||||
return
|
||||
}
|
||||
verSlice[idx] = uint(n)
|
||||
}
|
||||
|
||||
if sver, err = semver.NewVersion(newVerStr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ver = SshVerInfo{
|
||||
Major: verSlice[0],
|
||||
Minor: verSlice[1],
|
||||
Patch: verSlice[2],
|
||||
Raw: verStr,
|
||||
SslInfo: sslVer,
|
||||
SemVer: *sver,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetSslVer returns an OpenSslInfo. If verStr is an empty string, get the version automatically.
|
||||
func GetSslVer(verStr string) (ver OpenSslInfo, err error) {
|
||||
|
||||
var matches []string
|
||||
var verSlice [3]uint
|
||||
var newVerStr string
|
||||
var ptrn *regexp.Regexp
|
||||
var sver *semver.Version
|
||||
// TODO: confirm the day is zero-padded.
|
||||
var tfmt string = `02 Jan 2006`
|
||||
var n int
|
||||
var t time.Time
|
||||
|
||||
if verStr == "" {
|
||||
var out []byte
|
||||
cmd := exec.Command("openssl", "version")
|
||||
if err = cmd.Run(); err != nil {
|
||||
return
|
||||
}
|
||||
if out, err = cmd.Output(); err != nil {
|
||||
return
|
||||
}
|
||||
verStr = string(out)
|
||||
}
|
||||
|
||||
if ptrn, err = regexp.Compile(`^(?:Open|Sun_)SSL\s+(FIPS\s+)?(?P<sslver>[0-9.]+)(?P<sslrel>[A-Za-z]+)?\s+(?P<time>(?P<day>[0-9]{1,2})\s(?P<month>[A-Za-z]+)\s(?P<year>[0-9]{4}))$`); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
matches = ptrn.FindStringSubmatch(verStr)
|
||||
|
||||
for idx, s := range strings.Split(matches[ptrn.SubexpIndex("sslver")], ".") {
|
||||
if n, err = strconv.Atoi(s); err != nil {
|
||||
return
|
||||
}
|
||||
verSlice[idx] = uint(n)
|
||||
}
|
||||
|
||||
if t, err = time.Parse(tfmt, matches[ptrn.SubexpIndex("time")]); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
newVerStr = fmt.Sprintf(
|
||||
"%v-%v",
|
||||
matches[ptrn.SubexpIndex("sslver")],
|
||||
matches[ptrn.SubexpIndex("sslrel")],
|
||||
)
|
||||
|
||||
if sver, err = semver.NewVersion(newVerStr); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ver = OpenSslInfo{
|
||||
Major: verSlice[0],
|
||||
Minor: verSlice[1],
|
||||
Patch: verSlice[2],
|
||||
Revision: matches[ptrn.SubexpIndex("sslrel")],
|
||||
BuildDate: t,
|
||||
Raw: verStr,
|
||||
SemVer: *sver,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
@ -2,9 +2,30 @@ package utils
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
)
|
||||
|
||||
type runInfo struct {
|
||||
TimeStarted time.Time
|
||||
Pid int
|
||||
}
|
||||
|
||||
type SshVerInfo struct {
|
||||
Major uint
|
||||
Minor uint
|
||||
Patch uint
|
||||
Raw string
|
||||
SemVer semver.Version
|
||||
SslInfo OpenSslInfo
|
||||
}
|
||||
|
||||
type OpenSslInfo struct {
|
||||
Major uint
|
||||
Minor uint
|
||||
Patch uint
|
||||
Revision string
|
||||
BuildDate time.Time
|
||||
Raw string
|
||||
SemVer semver.Version
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user