Package certificates:

- rework package to allow convert config to model and retrive config from model
- add sub package to manage cipher, curves, auth client, tls version, certificates, root ca...
- add some small test (can be expande to having more coverage)
- optimize some code

Package httpcli:
- update code following change in certificates

Package httpserver:
- update code following change in certificates

Package Config/Components:
- update code following change in certificates

Package FTPClient:
- update code following change in certificates

Package Nats:
- update code following change in certificates
This commit is contained in:
Nicolas JUHEL
2024-12-03 11:17:11 +01:00
parent eca6890e32
commit 22b364593e
47 changed files with 3313 additions and 707 deletions

View File

@@ -0,0 +1,89 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package auth
import (
"fmt"
"gopkg.in/yaml.v3"
)
func (a *ClientAuth) unmarshall(val []byte) error {
*a = parseBytes(val)
return nil
}
func (a ClientAuth) MarshalJSON() ([]byte, error) {
t := a.String()
b := make([]byte, 0, len(t)+2)
b = append(b, '"')
b = append(b, []byte(t)...)
b = append(b, '"')
return b, nil
}
func (a *ClientAuth) UnmarshalJSON(bytes []byte) error {
return a.unmarshall(bytes)
}
func (a ClientAuth) MarshalYAML() (interface{}, error) {
return []byte(a.String()), nil
}
func (a *ClientAuth) UnmarshalYAML(value *yaml.Node) error {
return a.unmarshall([]byte(value.Value))
}
func (a ClientAuth) MarshalTOML() ([]byte, error) {
return []byte(a.String()), nil
}
func (a *ClientAuth) UnmarshalTOML(i interface{}) error {
if p, k := i.([]byte); k {
return a.unmarshall(p)
}
if p, k := i.(string); k {
return a.unmarshall([]byte(p))
}
return fmt.Errorf("tls client Auth: value not in valid format")
}
func (a ClientAuth) MarshalText() ([]byte, error) {
return []byte(a.String()), nil
}
func (a *ClientAuth) UnmarshalText(bytes []byte) error {
return a.unmarshall(bytes)
}
func (a ClientAuth) MarshalCBOR() ([]byte, error) {
return []byte(a.String()), nil
}
func (a *ClientAuth) UnmarshalCBOR(bytes []byte) error {
return a.unmarshall(bytes)
}

View File

@@ -0,0 +1,55 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package auth
import (
"crypto/tls"
"strings"
)
func (a ClientAuth) String() string {
switch a {
case RequireAndVerifyClientCert:
return strict + " " + require + " " + verify
case VerifyClientCertIfGiven:
return verify
case RequireAnyClientCert:
return require
case RequestClientCert:
return request
default:
return none
}
}
func (a ClientAuth) Code() string {
return strings.ToLower(a.String())
}
func (a ClientAuth) TLS() tls.ClientAuthType {
return tls.ClientAuthType(a)
}

View File

@@ -0,0 +1,99 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package auth
import (
"crypto/tls"
"strings"
)
const (
strict = "strict"
require = "require"
verify = "verify"
request = "request"
none = "none"
)
type ClientAuth tls.ClientAuthType
const (
NoClientCert = ClientAuth(tls.NoClientCert)
RequestClientCert = ClientAuth(tls.RequestClientCert)
RequireAnyClientCert = ClientAuth(tls.RequireAnyClientCert)
VerifyClientCertIfGiven = ClientAuth(tls.VerifyClientCertIfGiven)
RequireAndVerifyClientCert = ClientAuth(tls.RequireAndVerifyClientCert)
)
func List() []ClientAuth {
return []ClientAuth{
NoClientCert,
RequestClientCert,
RequireAnyClientCert,
VerifyClientCertIfGiven,
RequireAndVerifyClientCert,
}
}
func Parse(s string) ClientAuth {
s = strings.ToLower(s)
s = strings.Replace(s, "\"", "", -1)
s = strings.Replace(s, "'", "", -1)
s = strings.TrimSpace(s)
switch {
case strings.Contains(s, strict) || (strings.Contains(s, require) && strings.Contains(s, verify)):
return RequireAndVerifyClientCert
case strings.Contains(s, verify):
return VerifyClientCertIfGiven
case strings.Contains(s, require) && !strings.Contains(s, verify):
return RequireAnyClientCert
case strings.Contains(s, request):
return RequestClientCert
default:
return NoClientCert
}
}
func ParseInt(d int) ClientAuth {
switch tls.ClientAuthType(d) {
case tls.RequireAndVerifyClientCert:
return RequireAndVerifyClientCert
case tls.VerifyClientCertIfGiven:
return VerifyClientCertIfGiven
case tls.RequireAnyClientCert:
return RequireAnyClientCert
case tls.RequestClientCert:
return RequestClientCert
default:
return NoClientCert
}
}
func parseBytes(p []byte) ClientAuth {
return Parse(string(p))
}

View File

@@ -0,0 +1,62 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package auth
import (
"reflect"
libmap "github.com/mitchellh/mapstructure"
)
func ViperDecoderHook() libmap.DecodeHookFuncType {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
var (
z = ClientAuth(0)
t string
k bool
)
// Check if the data type matches the expected one
if from.Kind() != reflect.String {
return data, nil
} else if t, k = data.(string); !k {
return data, nil
}
// Check if the target type matches the expected one
if to != reflect.TypeOf(z) {
return data, nil
}
// Format/decode/parse the data and return the new value
if e := z.unmarshall([]byte(t)); e != nil {
return nil, e
} else {
return z, nil
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package certificates
import (
"crypto/x509"
tlsaut "github.com/nabbar/golib/certificates/auth"
tlscas "github.com/nabbar/golib/certificates/ca"
)
func (o *config) SetClientAuth(a tlsaut.ClientAuth) {
o.clientAuth = a
}
func (o *config) GetClientCA() []tlscas.Cert {
var res = make([]tlscas.Cert, 0)
for _, c := range o.clientCA {
res = append(res, c)
}
return res
}
func (o *config) GetClientCAPool() *x509.CertPool {
var res = x509.NewCertPool()
for _, ca := range o.clientCA {
ca.AppendPool(res)
}
return res
}
func (o *config) AddClientCAString(ca string) bool {
if ca != "" {
if c, e := tlscas.Parse(ca); e == nil {
o.clientCA = append(o.clientCA, c)
return true
}
}
return false
}
func (o *config) AddClientCAFile(pemFile string) error {
var fct = func(p []byte) error {
if c, e := tlscas.ParseByte(p); e != nil {
return e
} else {
o.clientCA = append(o.clientCA, c)
return nil
}
}
if e := checkFile(fct, pemFile); e != nil {
return e
} else {
return nil
}
}

165
certificates/ca/encode.go Normal file
View File

@@ -0,0 +1,165 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package ca
import (
"bytes"
"crypto/x509"
"encoding/json"
"encoding/pem"
"os"
"github.com/fxamacker/cbor/v2"
"github.com/pelletier/go-toml/v2"
"gopkg.in/yaml.v3"
)
func isFile(path string) bool {
f, e := os.Stat(path)
if e != nil {
return false
}
return !f.IsDir()
}
func (o *mod) unMarshall(p []byte) error {
if len(p) < 1 {
return ErrInvalidPairCertificate
}
p = bytes.TrimSpace(p)
// remove \n\r
p = bytes.Trim(p, "\n")
p = bytes.Trim(p, "\r")
// do again if \r\n
p = bytes.Trim(p, "\n")
p = bytes.Trim(p, "\r")
p = bytes.TrimSpace(p)
v := make([]*x509.Certificate, 0)
for {
block, rest := pem.Decode(p)
if block == nil {
break
}
if block.Type == "CERTIFICATE" {
if c, e := x509.ParseCertificate(block.Bytes); e == nil {
v = append(v, c)
}
} else if fs := string(block.Bytes); isFile(fs) {
if b, e := os.ReadFile(fs); e == nil {
if crt, err := x509.ParseCertificate(b); err == nil {
v = append(v, crt)
}
}
}
p = rest
}
o.c = v
return nil
}
func (o *mod) MarshalText() (text []byte, err error) {
if s, e := o.Chain(); e != nil {
return nil, e
} else {
return []byte(s), nil
}
}
func (o *mod) UnmarshalText(text []byte) error {
return o.unMarshall(text)
}
func (o *mod) MarshalBinary() (data []byte, err error) {
return o.MarshalCBOR()
}
func (o *mod) UnmarshalBinary(data []byte) error {
return o.UnmarshalCBOR(data)
}
func (o *mod) MarshalJSON() ([]byte, error) {
if s, e := o.Chain(); e != nil {
return nil, e
} else {
return json.Marshal(s)
}
}
func (o *mod) UnmarshalJSON(bytes []byte) error {
return o.unMarshall(bytes)
}
func (o *mod) MarshalYAML() (interface{}, error) {
if s, e := o.Chain(); e != nil {
return nil, e
} else {
return yaml.Marshal(s)
}
}
func (o *mod) UnmarshalYAML(value *yaml.Node) error {
return o.unMarshall([]byte(value.Value))
}
func (o *mod) MarshalTOML() ([]byte, error) {
if s, e := o.Chain(); e != nil {
return nil, e
} else {
return toml.Marshal(s)
}
}
func (o *mod) UnmarshalTOML(i interface{}) error {
if p, k := i.([]byte); k {
return o.unMarshall(p)
}
if s, k := i.(string); k {
return o.unMarshall([]byte(s))
}
return ErrInvalidCertificate
}
func (o *mod) MarshalCBOR() ([]byte, error) {
if s, e := o.Chain(); e != nil {
return nil, e
} else {
return cbor.Marshal(s)
}
}
func (o *mod) UnmarshalCBOR(bytes []byte) error {
return o.unMarshall(bytes)
}

61
certificates/ca/format.go Normal file
View File

@@ -0,0 +1,61 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package ca
import (
"bytes"
"crypto/x509"
"encoding/pem"
)
func (o *mod) String() string {
s, _ := o.Chain()
return s
}
func (o *mod) Chain() (string, error) {
var buf = bytes.NewBuffer(make([]byte, 0))
for _, c := range o.c {
if c == nil {
continue
} else if e := pem.Encode(buf, &pem.Block{Type: "CERTIFICATE", Bytes: c.Raw}); e != nil {
return "", e
}
}
return buf.String(), nil
}
func (o *mod) AppendPool(p *x509.CertPool) {
for _, c := range o.c {
if c == nil {
continue
}
p.AddCert(c)
}
}

View File

@@ -0,0 +1,78 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package ca
import (
"crypto/x509"
"encoding"
"encoding/json"
"errors"
"fmt"
"github.com/fxamacker/cbor/v2"
"github.com/pelletier/go-toml"
"gopkg.in/yaml.v3"
)
var (
ErrInvalidPairCertificate = errors.New("invalid pair certificate")
ErrInvalidCertificate = errors.New("invalid certificate")
)
type Cert interface {
encoding.TextMarshaler
encoding.TextUnmarshaler
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
json.Marshaler
json.Unmarshaler
yaml.Marshaler
yaml.Unmarshaler
toml.Marshaler
toml.Unmarshaler
cbor.Marshaler
cbor.Unmarshaler
fmt.Stringer
AppendPool(p *x509.CertPool)
}
func Parse(str string) (Cert, error) {
return ParseByte([]byte(str))
}
func ParseByte(p []byte) (Cert, error) {
c := &mod{
c: make([]*x509.Certificate, 0),
}
if e := c.unMarshall(p); e != nil {
return nil, e
}
return c, nil
}

69
certificates/ca/models.go Normal file
View File

@@ -0,0 +1,69 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package ca
import (
"crypto/x509"
"reflect"
libmap "github.com/mitchellh/mapstructure"
)
type mod struct {
c []*x509.Certificate
}
func ViperDecoderHook() libmap.DecodeHookFuncType {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
var (
z = &mod{
c: make([]*x509.Certificate, 0),
}
t string
k bool
)
// Check if the data type matches the expected one
if from.Kind() != reflect.String {
return data, nil
} else if t, k = data.(string); !k {
return data, nil
}
// Check if the target type matches the expected one
if to != reflect.TypeOf(z) {
return data, nil
}
// Format/decode/parse the data and return the new value
if e := z.unMarshall([]byte(t)); e != nil {
return nil, e
} else {
return z, nil
}
}
}

84
certificates/cert.go Normal file
View File

@@ -0,0 +1,84 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package certificates
import (
"crypto/tls"
tlscrt "github.com/nabbar/golib/certificates/certs"
)
func (o *config) LenCertificatePair() int {
return len(o.cert)
}
func (o *config) CleanCertificatePair() {
o.cert = make([]tlscrt.Cert, 0)
}
func (o *config) GetCertificatePair() []tls.Certificate {
var res = make([]tls.Certificate, 0)
for _, c := range o.cert {
res = append(res, c.TLS())
}
return res
}
func (o *config) AddCertificatePairString(key, crt string) error {
if c, e := tlscrt.ParsePair(key, crt); e != nil {
return e
} else {
o.cert = append(o.cert, c)
return nil
}
}
func (o *config) AddCertificatePairFile(keyFile, crtFile string) error {
var (
key = make([]byte, 0)
pub = make([]byte, 0)
fct = func(p []byte) error {
if len(key) < 1 {
copy(key, p)
} else {
copy(pub, p)
}
return nil
}
)
if e := checkFile(fct, keyFile, crtFile); e != nil {
return e
} else if c, e := tlscrt.ParsePair(string(key), string(pub)); e != nil {
return e
} else {
o.cert = append(o.cert, c)
return nil
}
}

View File

@@ -0,0 +1,214 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package certificates_test
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/json"
"encoding/pem"
"math/big"
"net"
"os"
"time"
libtls "github.com/nabbar/golib/certificates"
tlscrt "github.com/nabbar/golib/certificates/certs"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func genCertififcate() ([]byte, []byte) {
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
Expect(err).ToNot(HaveOccurred())
Expect(priv).ToNot(BeNil())
keyUsage := x509.KeyUsageDigitalSignature
notBefore := time.Now()
notAfter := notBefore.Add(time.Hour * 24 * 365)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
Expect(err).ToNot(HaveOccurred())
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Acme Co"},
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: keyUsage,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
template.DNSNames = append(template.DNSNames, "example.com")
template.DNSNames = append(template.DNSNames, "localhost")
if ip := net.ParseIP("127.0.0.1"); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
}
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
Expect(err).ToNot(HaveOccurred())
bufPub := bytes.NewBuffer(make([]byte, 0))
err = pem.Encode(bufPub, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
Expect(err).ToNot(HaveOccurred())
bufKey := bytes.NewBuffer(make([]byte, 0))
privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
Expect(err).ToNot(HaveOccurred())
err = pem.Encode(bufKey, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
Expect(err).ToNot(HaveOccurred())
return bufPub.Bytes(), bufKey.Bytes()
}
func writeGenCert(pub, key string) {
p, k := genCertififcate()
f, e := os.Create(pub)
Expect(e).ToNot(HaveOccurred())
_, e = f.Write(p)
Expect(e).ToNot(HaveOccurred())
Expect(f.Close()).ToNot(HaveOccurred())
f, e = os.Create(key)
Expect(e).ToNot(HaveOccurred())
_, e = f.Write(k)
Expect(e).ToNot(HaveOccurred())
Expect(f.Close()).ToNot(HaveOccurred())
}
func getConfigFile() []byte {
writeGenCert(pubFile, keyFile)
str := &tlscrt.ConfigPair{
Key: keyFile,
Pub: pubFile,
}
p, e := json.Marshal(str)
Expect(e).ToNot(HaveOccurred())
var oldConfig string = `{
"authClient": "none",
"certs": [` + string(p) + `],
"cipherList": ["RSA_AES_128_GCM_SHA256", "RSA_AES_256_GCM_SHA384", "ECDHE_RSA_AES_128_GCM_SHA256", "ECDHE_ECDSA_AES_128_GCM_SHA256", "ECDHE_RSA_AES_256_GCM_SHA384", "ECDHE_ECDSA_AES_256_GCM_SHA384", "ECDHE_RSA_CHACHA20_POLY1305_SHA256", "ECDHE_ECDSA_CHACHA20_POLY1305_SHA256", "AES_128_GCM_SHA256", "AES_256_GCM_SHA384", "CHACHA20_POLY1305_SHA256"],
"clientCA": [],
"curveList": ["X25519", "P256", "P384", "P521"],
"dynamicSizingDisable": false,
"inheritDefault": false,
"rootCA": [],
"sessionTicketDisable": false,
"versionMax": "1.3",
"versionMin": "1.2"
}`
return []byte(oldConfig)
}
func getConfigChain() []byte {
pub, key := genCertififcate()
str := "\n" + string(pub) + string(key)
buf, err := json.Marshal(str)
Expect(err).ToNot(HaveOccurred())
var oldConfig string = `{
"authClient": "none",
"certs": [` + string(buf) + `],
"cipherList": ["RSA_AES_128_GCM_SHA256", "RSA_AES_256_GCM_SHA384", "ECDHE_RSA_AES_128_GCM_SHA256", "ECDHE_ECDSA_AES_128_GCM_SHA256", "ECDHE_RSA_AES_256_GCM_SHA384", "ECDHE_ECDSA_AES_256_GCM_SHA384", "ECDHE_RSA_CHACHA20_POLY1305_SHA256", "ECDHE_ECDSA_CHACHA20_POLY1305_SHA256", "AES_128_GCM_SHA256", "AES_256_GCM_SHA384", "CHACHA20_POLY1305_SHA256"],
"clientCA": [],
"curveList": ["X25519", "P256", "P384", "P521"],
"dynamicSizingDisable": false,
"inheritDefault": false,
"rootCA": [],
"sessionTicketDisable": false,
"versionMax": "1.3",
"versionMin": "1.2"
}`
return []byte(oldConfig)
}
var _ = Describe("certificates test", func() {
Context("Using a config json", func() {
It("must success to new Config when certificates are paste as file mode", func() {
cfg := libtls.Config{}
p := getConfigFile()
Expect(len(p)).To(BeNumerically(">", 0))
e := json.Unmarshal(p, &cfg)
Expect(e).ToNot(HaveOccurred())
cnf := cfg.New()
Expect(cnf).ToNot(BeNil())
Expect(len(cnf.GetCertificatePair())).To(Equal(1))
cfgtls := cnf.TLS("localhost")
Expect(cfgtls).ToNot(BeNil())
Expect(len(cfgtls.Certificates)).To(Equal(1))
Expect(len(cfgtls.CipherSuites)).To(BeNumerically(">", 0))
Expect(len(cfgtls.CurvePreferences)).To(BeNumerically(">", 0))
p, e = json.Marshal(cnf.Config())
Expect(e).ToNot(HaveOccurred())
Expect(len(p)).To(BeNumerically(">", 0))
})
It("must success to new Config when certificates are paste as chain mode", func() {
cfg := libtls.Config{}
p := getConfigChain()
Expect(len(p)).To(BeNumerically(">", 0))
e := json.Unmarshal(p, &cfg)
Expect(e).ToNot(HaveOccurred())
cnf := cfg.New()
Expect(cnf).ToNot(BeNil())
Expect(len(cnf.GetCertificatePair())).To(Equal(1))
cfgtls := cnf.TLS("localhost")
Expect(cfgtls).ToNot(BeNil())
Expect(len(cfgtls.Certificates)).To(Equal(1))
Expect(len(cfgtls.CipherSuites)).To(BeNumerically(">", 0))
Expect(len(cfgtls.CurvePreferences)).To(BeNumerically(">", 0))
p, e = json.Marshal(cnf)
Expect(e).ToNot(HaveOccurred())
Expect(len(p)).To(BeNumerically(">", 0))
})
})
})

View File

@@ -0,0 +1,75 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package certificates_test
import (
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"time"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
/*
Using https://onsi.github.io/ginkgo/
Running with $> ginkgo -cover .
*/
type EmptyStruct struct{}
var (
keyFile string
pubFile string
)
// TestGolibEncodingAESHelper tests the Golib AES Encoding Helper function.
func TestGolibArchiveHelper(t *testing.T) {
time.Sleep(500 * time.Millisecond) // Adding delay for better testing synchronization
RegisterFailHandler(Fail) // Registering fail handler for better test failure reporting
RunSpecs(t, "Certificates Helper Suite") // Running the test suite for Encoding AES Helper
}
var _ = BeforeSuite(func() {
keyFile = filepath.Join(os.Getenv("GOPATH"), "src", strings.Replace(reflect.TypeOf(EmptyStruct{}).PkgPath(), "_test", "", -1), "test_ed25519.key")
pubFile = filepath.Join(os.Getenv("GOPATH"), "src", strings.Replace(reflect.TypeOf(EmptyStruct{}).PkgPath(), "_test", "", -1), "test_ed25519.pub")
})
var _ = AfterSuite(func() {
if keyFile != "" {
if _, e := os.Stat(keyFile); e == nil {
Expect(os.Remove(keyFile)).ToNot(HaveOccurred())
}
}
if pubFile != "" {
if _, e := os.Stat(pubFile); e == nil {
Expect(os.Remove(pubFile)).ToNot(HaveOccurred())
}
}
})

View File

@@ -0,0 +1,165 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package certs
import (
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"os"
"strings"
)
var (
ErrInvalidPairCertificate = errors.New("invalid pair certificate")
ErrInvalidCertificate = errors.New("invalid certificate")
ErrInvalidPrivateKey = errors.New("invalid private key")
)
func cleanPem(s string) string {
s = strings.TrimSpace(s)
// remove \n\r
s = strings.Trim(s, "\n")
s = strings.Trim(s, "\r")
// do again if \r\n
s = strings.Trim(s, "\n")
s = strings.Trim(s, "\r")
return strings.TrimSpace(s)
}
type Config interface {
Cert() (*tls.Certificate, error)
}
type ConfigPair struct {
Key string `mapstructure:"key" json:"key" yaml:"key" toml:"key"`
Pub string `mapstructure:"pub" json:"pub" yaml:"pub" toml:"pub"`
}
func (c *ConfigPair) Cert() (*tls.Certificate, error) {
c.Key = cleanPem(c.Key)
c.Pub = cleanPem(c.Pub)
if c == nil {
return nil, ErrInvalidPairCertificate
} else if len(c.Key) < 1 || len(c.Pub) < 1 {
return nil, ErrInvalidPairCertificate
}
if _, e := os.Stat(c.Key); e == nil {
if b, e := os.ReadFile(c.Key); e == nil {
c.Key = cleanPem(string(b))
}
}
if _, e := os.Stat(c.Pub); e == nil {
if b, e := os.ReadFile(c.Pub); e == nil {
c.Pub = cleanPem(string(b))
}
}
if crt, err := tls.X509KeyPair([]byte(c.Pub), []byte(c.Key)); err != nil {
return nil, err
} else {
return &crt, nil
}
}
type ConfigChain string
func (c *ConfigChain) Cert() (*tls.Certificate, error) {
var (
err error
crt tls.Certificate
)
if c == nil {
return nil, ErrInvalidPairCertificate
} else if len(*c) < 1 {
return nil, ErrInvalidPairCertificate
}
s := string(*c)
if _, e := os.Stat(s); e == nil {
if b, e := os.ReadFile(s); e == nil {
s = cleanPem(string(b))
}
}
p := []byte(cleanPem(s))
for {
block, rest := pem.Decode(p)
if block == nil {
break
}
if block.Type == "CERTIFICATE" {
crt.Certificate = append(crt.Certificate, block.Bytes)
} else {
crt.PrivateKey, err = c.getPrivateKey(block.Bytes)
if err != nil {
return nil, err
}
}
p = rest
}
if len(crt.Certificate) == 0 {
return nil, ErrInvalidCertificate
} else if crt.PrivateKey == nil {
return nil, ErrInvalidCertificate
}
return &crt, nil
}
func (c *ConfigChain) getPrivateKey(der []byte) (crypto.PrivateKey, error) {
if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
return key, nil
}
if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
switch k := key.(type) {
case *rsa.PrivateKey, *ecdsa.PrivateKey:
return k, nil
default:
return nil, ErrInvalidPrivateKey
}
}
if key, err := x509.ParseECPrivateKey(der); err == nil {
return key, nil
}
return nil, ErrInvalidPrivateKey
}

View File

@@ -0,0 +1,244 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package certs
import (
"crypto/tls"
"encoding/json"
"github.com/fxamacker/cbor/v2"
"github.com/pelletier/go-toml/v2"
"gopkg.in/yaml.v3"
)
func (o *Certif) unMarshall(p []byte) error {
if o.UnmarshalJSON(p) == nil {
return nil
} else if o.UnmarshalYAML(&yaml.Node{Value: string(p)}) != nil {
return nil
} else if o.UnmarshalTOML(p) != nil {
return nil
} else if o.UnmarshalCBOR(p) != nil {
return nil
} else if o.UnmarshalText(p) != nil {
return nil
}
return ErrInvalidCertificate
}
func (o *Certif) MarshalText() (text []byte, err error) {
return []byte(o.String()), err
}
func (o *Certif) UnmarshalText(text []byte) error {
var (
chn = ConfigChain(text)
crt *tls.Certificate
err error
)
if crt, err = chn.Cert(); err != nil {
return err
} else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate
} else {
o.c = *crt
return nil
}
}
func (o *Certif) MarshalBinary() (data []byte, err error) {
return o.MarshalCBOR()
}
func (o *Certif) UnmarshalBinary(data []byte) error {
return o.UnmarshalCBOR(data)
}
func (o *Certif) MarshalJSON() ([]byte, error) {
t := o.String()
return json.Marshal(t)
}
func (o *Certif) UnmarshalJSON(bytes []byte) error {
var (
cfg ConfigPair
chn ConfigChain
crt *tls.Certificate
err error
)
if err = json.Unmarshal(bytes, &cfg); err == nil {
if crt, err = cfg.Cert(); err != nil {
return err
} else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate
} else {
o.c = *crt
return nil
}
} else if err = json.Unmarshal(bytes, &chn); err == nil {
if crt, err = chn.Cert(); err != nil {
return err
} else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate
} else {
o.c = *crt
return nil
}
}
return ErrInvalidCertificate
}
func (o *Certif) MarshalYAML() (interface{}, error) {
t := o.String()
return yaml.Marshal(t)
}
func (o *Certif) UnmarshalYAML(value *yaml.Node) error {
var (
src = []byte(value.Value)
cfg ConfigPair
chn ConfigChain
crt *tls.Certificate
err error
)
if err = yaml.Unmarshal(src, &cfg); err == nil {
if crt, err = cfg.Cert(); err != nil {
return err
} else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate
} else {
o.c = *crt
return nil
}
} else if err = yaml.Unmarshal(src, &chn); err == nil {
if crt, err = chn.Cert(); err != nil {
return err
} else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate
} else {
o.c = *crt
return nil
}
}
return ErrInvalidCertificate
}
func (o *Certif) MarshalTOML() ([]byte, error) {
t := o.String()
return toml.Marshal(t)
}
func (o *Certif) UnmarshalTOML(i interface{}) error {
var (
p []byte
s string
k bool
)
if p, k = i.([]byte); !k {
if s, k = i.(string); k {
p = []byte(s)
} else {
return ErrInvalidCertificate
}
}
if len(p) < 1 {
return ErrInvalidCertificate
}
var (
cfg ConfigPair
chn ConfigChain
crt *tls.Certificate
err error
)
if err = toml.Unmarshal(p, &cfg); err == nil {
if crt, err = cfg.Cert(); err != nil {
return err
} else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate
} else {
o.c = *crt
return nil
}
} else if err = toml.Unmarshal(p, &chn); err == nil {
if crt, err = chn.Cert(); err != nil {
return err
} else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate
} else {
o.c = *crt
return nil
}
}
return ErrInvalidCertificate
}
func (o *Certif) MarshalCBOR() ([]byte, error) {
t := o.String()
return cbor.Marshal(t)
}
func (o *Certif) UnmarshalCBOR(bytes []byte) error {
var (
cfg ConfigPair
chn ConfigChain
crt *tls.Certificate
err error
)
if err = cbor.Unmarshal(bytes, &cfg); err == nil {
if crt, err = cfg.Cert(); err != nil {
return err
} else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate
} else {
o.c = *crt
return nil
}
} else if err = cbor.Unmarshal(bytes, &chn); err == nil {
if crt, err = chn.Cert(); err != nil {
return err
} else if crt == nil || len(crt.Certificate) == 0 {
return ErrInvalidPairCertificate
} else {
o.c = *crt
return nil
}
}
return ErrInvalidCertificate
}

View File

@@ -0,0 +1,86 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package certs
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/pem"
)
func (o *Certif) String() string {
str, _ := o.Chain()
return str
}
func (o *Certif) Pair() (pub string, key string, err error) {
var (
bufPub = bytes.NewBuffer(make([]byte, 0))
bufKey = bytes.NewBuffer(make([]byte, 0))
)
for _, certDER := range o.c.Certificate {
block := &pem.Block{
Type: "CERTIFICATE",
Bytes: certDER,
}
if err = pem.Encode(bufPub, block); err != nil {
return "", "", err
}
}
// Afficher la clé privée si disponible
if o.c.PrivateKey != nil {
var p []byte
if p, err = x509.MarshalPKCS8PrivateKey(o.c.PrivateKey); err != nil {
return "", "", err
} else {
privateKeyBlock := &pem.Block{
Type: "PRIVATE KEY",
Bytes: p,
}
if err = pem.Encode(bufKey, privateKeyBlock); err != nil {
return "", "", err
}
}
}
return bufPub.String(), bufKey.String(), nil
}
func (o *Certif) Chain() (string, error) {
if pub, key, err := o.Pair(); err != nil {
return "", err
} else {
return pub + key, nil
}
}
func (o *Certif) TLS() tls.Certificate {
return o.c
}

View File

@@ -0,0 +1,76 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package certs
import (
"crypto/tls"
"encoding"
"encoding/json"
"fmt"
"github.com/fxamacker/cbor/v2"
"github.com/pelletier/go-toml"
"gopkg.in/yaml.v3"
)
type Cert interface {
encoding.TextMarshaler
encoding.TextUnmarshaler
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
json.Marshaler
json.Unmarshaler
yaml.Marshaler
yaml.Unmarshaler
toml.Marshaler
toml.Unmarshaler
cbor.Marshaler
cbor.Unmarshaler
fmt.Stringer
TLS() tls.Certificate
Model() Certif
}
func Parse(chain string) (Cert, error) {
c := ConfigChain(chain)
return parseCert(&c)
}
func ParsePair(key, pub string) (Cert, error) {
return parseCert(&ConfigPair{Key: key, Pub: pub})
}
func parseCert(cfg Config) (Cert, error) {
if c, e := cfg.Cert(); e != nil {
return nil, e
} else if c == nil {
return nil, ErrInvalidPairCertificate
} else {
return &Certif{c: *c}, nil
}
}

View File

@@ -0,0 +1,75 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package certs
import (
"crypto/tls"
"reflect"
libmap "github.com/mitchellh/mapstructure"
)
type Certif struct {
c tls.Certificate
}
func (o *Certif) Cert() Cert {
return o
}
func (o *Certif) Model() Certif {
return *o
}
func ViperDecoderHook() libmap.DecodeHookFuncType {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
var (
z = &Certif{c: tls.Certificate{}}
t string
k bool
)
// Check if the data type matches the expected one
if from.Kind() != reflect.String {
return data, nil
} else if t, k = data.(string); !k {
return data, nil
}
// Check if the target type matches the expected one
if to != reflect.TypeOf(z) {
return data, nil
}
// Format/decode/parse the data and return the new value
if e := z.unMarshall([]byte(t)); e != nil {
return nil, e
} else {
return z, nil
}
}
}

View File

@@ -0,0 +1,89 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package curves
import (
"fmt"
"gopkg.in/yaml.v3"
)
func (v *Cipher) unmarshall(val []byte) error {
*v = parseBytes(val)
return nil
}
func (v Cipher) MarshalJSON() ([]byte, error) {
t := v.String()
b := make([]byte, 0, len(t)+2)
b = append(b, '"')
b = append(b, []byte(t)...)
b = append(b, '"')
return b, nil
}
func (v *Cipher) UnmarshalJSON(bytes []byte) error {
return v.unmarshall(bytes)
}
func (v Cipher) MarshalYAML() (interface{}, error) {
return []byte(v.String()), nil
}
func (v *Cipher) UnmarshalYAML(value *yaml.Node) error {
return v.unmarshall([]byte(value.Value))
}
func (v Cipher) MarshalTOML() ([]byte, error) {
return []byte(v.String()), nil
}
func (v *Cipher) UnmarshalTOML(i interface{}) error {
if p, k := i.([]byte); k {
return v.unmarshall(p)
}
if p, k := i.(string); k {
return v.unmarshall([]byte(p))
}
return fmt.Errorf("cipher: value not in valid format")
}
func (v Cipher) MarshalText() ([]byte, error) {
return []byte(v.String()), nil
}
func (v *Cipher) UnmarshalText(bytes []byte) error {
return v.unmarshall(bytes)
}
func (v Cipher) MarshalCBOR() ([]byte, error) {
return []byte(v.String()), nil
}
func (v *Cipher) UnmarshalCBOR(bytes []byte) error {
return v.unmarshall(bytes)
}

View File

@@ -0,0 +1,100 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package curves
import (
"strings"
)
func (v Cipher) String() string {
return strings.Join(v.Code(), "_")
}
func (v Cipher) Code() []string {
switch v {
case TLS_RSA_WITH_AES_128_GCM_SHA256:
return []string{"rsa", "aes", "128", "gcm", "sha256"}
case TLS_RSA_WITH_AES_256_GCM_SHA384:
return []string{"rsa", "aes", "256", "gcm", "sha384"}
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
return []string{"ecdhe", "rsa", "aes", "128", "gcm", "sha256"}
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
return []string{"ecdhe", "ecdsa", "aes", "128", "gcm", "sha256"}
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
return []string{"ecdhe", "rsa", "aes", "256", "gcm", "sha384"}
case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
return []string{"ecdhe", "ecdsa", "aes", "256", "gcm", "sha384"}
case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
return []string{"ecdhe", "rsa", "chacha20", "poly1305", "sha256"}
case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
return []string{"ecdhe", "ecdsa", "chacha20", "poly1305", "sha256"}
case TLS_AES_128_GCM_SHA256:
return []string{"aes", "128", "gcm", "sha256"}
case TLS_AES_256_GCM_SHA384:
return []string{"aes", "256", "gcm", "sha384"}
case TLS_CHACHA20_POLY1305_SHA256:
return []string{"chacha20", "poly1305", "sha256"}
default:
return []string{}
}
}
func (v Cipher) Cipher() uint16 {
return uint16(v)
}
func (v Cipher) TLS() uint16 {
return v.Cipher()
}
func (v Cipher) Uint16() uint16 {
return v.Cipher()
}
func (v Cipher) Uint() uint {
return uint(v.Cipher())
}
func (v Cipher) Uint32() uint32 {
return uint32(v.Cipher())
}
func (v Cipher) Uint64() uint64 {
return uint64(v.Cipher())
}
func (v Cipher) Int() int {
return int(v.Cipher())
}
func (v Cipher) Int32() int32 {
return int32(v.Cipher())
}
func (v Cipher) Int64() int64 {
return int64(v.Cipher())
}

View File

@@ -0,0 +1,199 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package curves
import (
"crypto/tls"
"math"
"slices"
"strings"
)
type Cipher uint16
const (
Unknown Cipher = Cipher(0)
// TLS 1.0 - 1.2 cipher suites.
TLS_RSA_WITH_AES_128_GCM_SHA256 = Cipher(tls.TLS_RSA_WITH_AES_128_GCM_SHA256)
TLS_RSA_WITH_AES_256_GCM_SHA384 = Cipher(tls.TLS_RSA_WITH_AES_256_GCM_SHA384)
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = Cipher(tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = Cipher(tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = Cipher(tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = Cipher(tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = Cipher(tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256)
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = Cipher(tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256)
// TLS 1.3 cipher suites.
TLS_AES_128_GCM_SHA256 = Cipher(tls.TLS_AES_128_GCM_SHA256)
TLS_AES_256_GCM_SHA384 = Cipher(tls.TLS_AES_256_GCM_SHA384)
TLS_CHACHA20_POLY1305_SHA256 = Cipher(tls.TLS_CHACHA20_POLY1305_SHA256)
)
func List() []Cipher {
return []Cipher{
TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
TLS_CHACHA20_POLY1305_SHA256,
}
}
func ListString() []string {
var res = make([]string, 0)
for _, c := range List() {
res = append(res, c.String())
}
return res
}
func Parse(s string) Cipher {
s = strings.ToLower(s)
s = strings.Replace(s, "\"", "", -1)
s = strings.Replace(s, "'", "", -1)
s = strings.Replace(s, "tls", "", -1)
s = strings.Replace(s, ".", "_", -1)
s = strings.Replace(s, "-", "_", -1)
s = strings.Replace(s, " ", "_", -1)
s = strings.TrimSpace(s)
p := strings.Split(s, "_")
switch {
case containString(p, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256.Code()):
return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
case containString(p, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.Code()):
return TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
case containString(p, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384.Code()):
return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
case containString(p, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384.Code()):
return TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
case containString(p, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256.Code()):
return TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
case containString(p, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256.Code()):
return TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
case containString(p, TLS_CHACHA20_POLY1305_SHA256.Code()):
return TLS_CHACHA20_POLY1305_SHA256
case containString(p, TLS_RSA_WITH_AES_128_GCM_SHA256.Code()):
return TLS_RSA_WITH_AES_128_GCM_SHA256
case containString(p, TLS_RSA_WITH_AES_256_GCM_SHA384.Code()):
return TLS_RSA_WITH_AES_256_GCM_SHA384
case containString(p, TLS_AES_128_GCM_SHA256.Code()):
return TLS_AES_128_GCM_SHA256
case containString(p, TLS_AES_256_GCM_SHA384.Code()):
return TLS_AES_256_GCM_SHA384
default:
return Unknown
}
}
func containString[S ~[]string](s S, v S) bool {
keys := []string{
"chacha20",
"poly1305",
"ecdhe",
"rsa",
"ecdsa",
"aes",
"128",
"256",
"sha256",
"sha384",
"gcm",
}
for _, k := range keys {
if !keyContainString(s, v, k) {
return false
}
}
return true
}
func keyContainString[S ~[]string](s S, v S, k string) bool {
if slices.Contains(s, k) && !slices.Contains(v, k) {
return false
} else if !slices.Contains(s, k) && slices.Contains(v, k) {
return false
}
return true
}
func ParseInt(d int) Cipher {
if d > math.MaxUint16 {
d = math.MaxUint16
} else if d < 1 {
d = 0
}
switch uint16(d) {
case tls.TLS_RSA_WITH_AES_128_GCM_SHA256:
return TLS_RSA_WITH_AES_128_GCM_SHA256
case tls.TLS_RSA_WITH_AES_256_GCM_SHA384:
return TLS_RSA_WITH_AES_256_GCM_SHA384
case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
case tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
return TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
case tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
case tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
return TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
case tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
return TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
case tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
return TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
case tls.TLS_AES_128_GCM_SHA256:
return TLS_AES_128_GCM_SHA256
case tls.TLS_AES_256_GCM_SHA384:
return TLS_AES_256_GCM_SHA384
case tls.TLS_CHACHA20_POLY1305_SHA256:
return TLS_CHACHA20_POLY1305_SHA256
default:
return Unknown
}
}
func Check(cipher uint16) bool {
if c := ParseInt(int(cipher)); c == Unknown {
return false
}
return true
}
func parseBytes(p []byte) Cipher {
return Parse(string(p))
}

View File

@@ -0,0 +1,62 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package curves
import (
"reflect"
libmap "github.com/mitchellh/mapstructure"
)
func ViperDecoderHook() libmap.DecodeHookFuncType {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
var (
z = Cipher(0)
t string
k bool
)
// Check if the data type matches the expected one
if from.Kind() != reflect.String {
return data, nil
} else if t, k = data.(string); !k {
return data, nil
}
// Check if the target type matches the expected one
if to != reflect.TypeOf(z) {
return data, nil
}
// Format/decode/parse the data and return the new value
if e := z.unmarshall([]byte(t)); e != nil {
return nil, e
} else {
return z, nil
}
}
}

52
certificates/ciphers.go Normal file
View File

@@ -0,0 +1,52 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package certificates
import tlscpr "github.com/nabbar/golib/certificates/cipher"
func (o *config) SetCipherList(c []tlscpr.Cipher) {
o.cipherList = make([]tlscpr.Cipher, 0)
o.AddCiphers(c...)
}
func (o *config) AddCiphers(c ...tlscpr.Cipher) {
for _, i := range c {
o.cipherList = append(o.cipherList, i)
}
}
func (o *config) GetCiphers() []tlscpr.Cipher {
var res = make([]tlscpr.Cipher, 0)
for _, i := range o.cipherList {
if tlscpr.Check(i.Uint16()) {
res = append(res, i)
}
}
return res
}

View File

@@ -30,29 +30,27 @@ import (
"fmt" "fmt"
libval "github.com/go-playground/validator/v10" libval "github.com/go-playground/validator/v10"
tlsaut "github.com/nabbar/golib/certificates/auth"
tlscas "github.com/nabbar/golib/certificates/ca"
tlscrt "github.com/nabbar/golib/certificates/certs"
tlscpr "github.com/nabbar/golib/certificates/cipher"
tlscrv "github.com/nabbar/golib/certificates/curves"
tlsvrs "github.com/nabbar/golib/certificates/tlsversion"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
) )
type Certif struct {
Key string `mapstructure:"key" json:"key" yaml:"key" toml:"key"`
Pem string `mapstructure:"pem" json:"pem" yaml:"pem" toml:"pem"`
}
type Config struct { type Config struct {
CurveList []string `mapstructure:"curveList" json:"curveList" yaml:"curveList" toml:"curveList"` CurveList []tlscrv.Curves `mapstructure:"curveList" json:"curveList" yaml:"curveList" toml:"curveList"`
CipherList []string `mapstructure:"cipherList" json:"cipherList" yaml:"cipherList" toml:"cipherList"` CipherList []tlscpr.Cipher `mapstructure:"cipherList" json:"cipherList" yaml:"cipherList" toml:"cipherList"`
RootCAString []string `mapstructure:"rootCA" json:"rootCA" yaml:"rootCA" toml:"rootCA"` RootCA []tlscas.Cert `mapstructure:"rootCA" json:"rootCA" yaml:"rootCA" toml:"rootCA"`
RootCAFile []string `mapstructure:"rootCAFiles" json:"rootCAFiles" yaml:"rootCAFiles" toml:"rootCAFiles"` ClientCA []tlscas.Cert `mapstructure:"clientCA" json:"clientCA" yaml:"clientCA" toml:"clientCA"`
ClientCAString []string `mapstructure:"clientCA" json:"clientCA" yaml:"clientCA" toml:"clientCA"` Certs []tlscrt.Certif `mapstructure:"certs" json:"certs" yaml:"certs" toml:"certs"`
ClientCAFiles []string `mapstructure:"clientCAFiles" json:"clientCAFiles" yaml:"clientCAFiles" toml:"clientCAFiles"` VersionMin tlsvrs.Version `mapstructure:"versionMin" json:"versionMin" yaml:"versionMin" toml:"versionMin"`
CertPairString []Certif `mapstructure:"certPair" json:"certPair" yaml:"certPair" toml:"certPair"` VersionMax tlsvrs.Version `mapstructure:"versionMax" json:"versionMax" yaml:"versionMax" toml:"versionMax"`
CertPairFile []Certif `mapstructure:"certPairFiles" json:"certPairFiles" yaml:"certPairFiles" toml:"certPairFiles"` AuthClient tlsaut.ClientAuth `mapstructure:"authClient" json:"authClient" yaml:"authClient" toml:"authClient"`
VersionMin string `mapstructure:"versionMin" json:"versionMin" yaml:"versionMin" toml:"versionMin"` InheritDefault bool `mapstructure:"inheritDefault" json:"inheritDefault" yaml:"inheritDefault" toml:"inheritDefault"`
VersionMax string `mapstructure:"versionMax" json:"versionMax" yaml:"versionMax" toml:"versionMax"` DynamicSizingDisable bool `mapstructure:"dynamicSizingDisable" json:"dynamicSizingDisable" yaml:"dynamicSizingDisable" toml:"dynamicSizingDisable"`
AuthClient string `mapstructure:"authClient" json:"authClient" yaml:"authClient" toml:"authClient"` SessionTicketDisable bool `mapstructure:"sessionTicketDisable" json:"sessionTicketDisable" yaml:"sessionTicketDisable" toml:"sessionTicketDisable"`
InheritDefault bool `mapstructure:"inheritDefault" json:"inheritDefault" yaml:"inheritDefault" toml:"inheritDefault"`
DynamicSizingDisable bool `mapstructure:"dynamicSizingDisable" json:"dynamicSizingDisable" yaml:"dynamicSizingDisable" toml:"dynamicSizingDisable"`
SessionTicketDisable bool `mapstructure:"sessionTicketDisable" json:"sessionTicketDisable" yaml:"sessionTicketDisable" toml:"sessionTicketDisable"`
} }
func (c *Config) Validate() liberr.Error { func (c *Config) Validate() liberr.Error {
@@ -76,7 +74,7 @@ func (c *Config) Validate() liberr.Error {
return nil return nil
} }
func (c *Config) New() (TLSConfig, liberr.Error) { func (c *Config) New() TLSConfig {
if c.InheritDefault { if c.InheritDefault {
return c.NewFrom(Default) return c.NewFrom(Default)
} else { } else {
@@ -85,117 +83,114 @@ func (c *Config) New() (TLSConfig, liberr.Error) {
} }
// nolint #gocognit // nolint #gocognit
func (c *Config) NewFrom(cfg TLSConfig) (TLSConfig, liberr.Error) { func (c *Config) NewFrom(cfg TLSConfig) TLSConfig {
var t *config var t *Config
if cfg != nil { if cfg != nil {
t = asStruct(cfg.Clone()) t = cfg.Config()
} }
if t == nil { if t == nil {
t = asStruct(New()) t = &Config{}
t.caRoot = SystemRootCA()
} }
if c.VersionMin != "" { if c.VersionMin != tlsvrs.VersionUnknown {
t.tlsMinVersion = StringToTlsVersion(c.VersionMin) t.VersionMin = c.VersionMin
} }
if c.VersionMax != "" { if c.VersionMax != tlsvrs.VersionUnknown {
t.tlsMaxVersion = StringToTlsVersion(c.VersionMax) t.VersionMax = c.VersionMax
} }
if c.DynamicSizingDisable { if c.DynamicSizingDisable {
t.dynSizingDisabled = true t.DynamicSizingDisable = true
} }
if c.SessionTicketDisable { if c.SessionTicketDisable {
t.ticketSessionDisabled = true t.SessionTicketDisable = true
} }
if c.AuthClient != "" { if c.AuthClient != tlsaut.NoClientCert {
t.clientAuth = StringToClientAuth(c.AuthClient) t.AuthClient = c.AuthClient
} }
if len(c.CipherList) > 0 { if len(c.CipherList) > 0 {
for _, a := range c.CipherList { for _, a := range c.CipherList {
if len(a) < 1 { if tlscpr.Check(a.Uint16()) {
continue t.CipherList = append(t.CipherList, a)
} }
t.cipherList = append(t.cipherList, StringToCipherKey(a))
} }
} }
if len(c.CurveList) > 0 { if len(c.CurveList) > 0 {
for _, a := range c.CurveList { for _, a := range c.CurveList {
if len(a) < 1 { if tlscrv.Check(a.Uint16()) {
continue t.CurveList = append(t.CurveList, a)
}
t.curveList = append(t.curveList, StringToCurveID(a))
}
}
if len(c.RootCAString) > 0 {
for _, s := range c.RootCAString {
if len(s) < 1 {
continue
}
t.AddRootCAString(s)
}
}
if len(c.RootCAFile) > 0 {
for _, f := range c.RootCAFile {
if len(f) < 1 {
continue
}
if e := t.AddRootCAFile(f); e != nil {
return nil, e
} }
} }
} }
if len(c.ClientCAString) > 0 { if len(c.RootCA) > 0 {
for _, s := range c.ClientCAString { for _, s := range c.RootCA {
if len(s) < 1 { t.RootCA = append(t.RootCA, s)
continue
}
t.AddClientCAString(s)
} }
} }
if len(c.ClientCAFiles) > 0 { if len(c.ClientCA) > 0 {
for _, f := range c.ClientCAFiles { for _, s := range c.ClientCA {
if len(f) < 1 { t.ClientCA = append(t.ClientCA, s)
continue
}
if e := t.AddClientCAFile(f); e != nil {
return nil, e
}
} }
} }
if len(c.CertPairString) > 0 { if len(c.Certs) > 0 {
for _, s := range c.CertPairString { for _, s := range c.Certs {
if len(s.Key) < 1 || len(s.Pem) < 1 { t.Certs = append(t.Certs, s)
continue
}
if e := t.AddCertificatePairString(s.Key, s.Pem); e != nil {
return nil, e
}
} }
} }
if len(c.CertPairFile) > 0 { res := &config{
for _, f := range c.CertPairFile { rand: nil,
if len(f.Key) < 1 || len(f.Pem) < 1 { cert: make([]tlscrt.Cert, 0),
continue cipherList: make([]tlscpr.Cipher, 0),
} curveList: make([]tlscrv.Curves, 0),
if e := t.AddCertificatePairFile(f.Key, f.Pem); e != nil { caRoot: make([]tlscas.Cert, 0),
return nil, e clientAuth: t.AuthClient,
} clientCA: make([]tlscas.Cert, 0),
tlsMinVersion: t.VersionMin,
tlsMaxVersion: t.VersionMax,
dynSizingDisabled: t.DynamicSizingDisable,
ticketSessionDisabled: t.SessionTicketDisable,
}
if len(t.Certs) > 0 {
for _, s := range t.Certs {
res.cert = append(res.cert, s.Cert())
} }
} }
return t, nil if len(t.CipherList) > 0 {
for _, s := range t.CipherList {
res.cipherList = append(res.cipherList, s)
}
}
if len(t.CurveList) > 0 {
for _, s := range t.CurveList {
res.curveList = append(res.curveList, s)
}
}
if len(t.RootCA) > 0 {
for _, s := range t.RootCA {
res.caRoot = append(res.caRoot, s)
}
}
if len(t.ClientCA) > 0 {
for _, s := range t.ClientCA {
res.clientCA = append(res.clientCA, s)
}
}
return res
} }

52
certificates/curves.go Normal file
View File

@@ -0,0 +1,52 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package certificates
import tlscrv "github.com/nabbar/golib/certificates/curves"
func (o *config) SetCurveList(c []tlscrv.Curves) {
o.curveList = make([]tlscrv.Curves, 0)
o.AddCurves(c...)
}
func (o *config) AddCurves(c ...tlscrv.Curves) {
for _, i := range c {
o.curveList = append(o.curveList, i)
}
}
func (o *config) GetCurves() []tlscrv.Curves {
var res = make([]tlscrv.Curves, 0)
for _, i := range o.curveList {
if tlscrv.Check(i.Uint16()) {
res = append(res, i)
}
}
return res
}

View File

@@ -0,0 +1,89 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package curves
import (
"fmt"
"gopkg.in/yaml.v3"
)
func (v *Curves) unmarshall(val []byte) error {
*v = parseBytes(val)
return nil
}
func (v Curves) MarshalJSON() ([]byte, error) {
t := v.String()
b := make([]byte, 0, len(t)+2)
b = append(b, '"')
b = append(b, []byte(t)...)
b = append(b, '"')
return b, nil
}
func (v *Curves) UnmarshalJSON(bytes []byte) error {
return v.unmarshall(bytes)
}
func (v Curves) MarshalYAML() (interface{}, error) {
return []byte(v.String()), nil
}
func (v *Curves) UnmarshalYAML(value *yaml.Node) error {
return v.unmarshall([]byte(value.Value))
}
func (v Curves) MarshalTOML() ([]byte, error) {
return []byte(v.String()), nil
}
func (v *Curves) UnmarshalTOML(i interface{}) error {
if p, k := i.([]byte); k {
return v.unmarshall(p)
}
if p, k := i.(string); k {
return v.unmarshall([]byte(p))
}
return fmt.Errorf("size: value not in valid format")
}
func (v Curves) MarshalText() ([]byte, error) {
return []byte(v.String()), nil
}
func (v *Curves) UnmarshalText(bytes []byte) error {
return v.unmarshall(bytes)
}
func (v Curves) MarshalCBOR() ([]byte, error) {
return []byte(v.String()), nil
}
func (v *Curves) UnmarshalCBOR(bytes []byte) error {
return v.unmarshall(bytes)
}

View File

@@ -0,0 +1,98 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package curves
import (
"crypto/tls"
"strings"
)
func (v Curves) String() string {
switch v {
case X25519:
return "X25519"
case P256:
return "P256"
case P384:
return "P384"
case P521:
return "P521"
default:
return ""
}
}
func (v Curves) Code() string {
return strings.ToLower(v.String())
}
func (v Curves) CurveID() tls.CurveID {
switch v {
case X25519:
return tls.X25519
case P256:
return tls.CurveP256
case P384:
return tls.CurveP384
case P521:
return tls.CurveP521
default:
return 0
}
}
func (v Curves) TLS() tls.CurveID {
return v.CurveID()
}
func (v Curves) Uint16() uint16 {
return uint16(v.CurveID())
}
func (v Curves) Uint() uint {
return uint(v.CurveID())
}
func (v Curves) Uint32() uint32 {
return uint32(v.CurveID())
}
func (v Curves) Uint64() uint64 {
return uint64(v.CurveID())
}
func (v Curves) Int() int {
return int(v.CurveID())
}
func (v Curves) Int32() int32 {
return int32(v.CurveID())
}
func (v Curves) Int64() int64 {
return int64(v.CurveID())
}

View File

@@ -0,0 +1,120 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package curves
import (
"crypto/tls"
"math"
"strings"
)
type Curves uint16
const (
Unknown Curves = iota
X25519 = Curves(tls.X25519)
P256 = Curves(tls.CurveP256)
P384 = Curves(tls.CurveP384)
P521 = Curves(tls.CurveP521)
)
func List() []Curves {
return []Curves{
X25519,
P256,
P384,
P521,
}
}
func ListString() []string {
var res = make([]string, 0)
for _, c := range List() {
res = append(res, c.String())
}
return res
}
func Parse(s string) Curves {
s = strings.ToLower(s)
s = strings.Replace(s, "\"", "", -1)
s = strings.Replace(s, "'", "", -1)
s = strings.Replace(s, "x", "", -1)
s = strings.Replace(s, "X", "", -1)
s = strings.Replace(s, "p", "", -1)
s = strings.Replace(s, "P", "", -1)
s = strings.Replace(s, ".", "", -1)
s = strings.Replace(s, "-", "", -1)
s = strings.Replace(s, "_", "", -1)
s = strings.Replace(s, " ", "", -1)
s = strings.TrimSpace(s)
switch {
case strings.EqualFold(s, "25519"):
return X25519
case strings.EqualFold(s, "256"):
return P256
case strings.EqualFold(s, "384"):
return P384
case strings.EqualFold(s, "521"):
return P521
default:
return Unknown
}
}
func ParseInt(d int) Curves {
if d > math.MaxUint16 {
d = math.MaxUint16
} else if d < 1 {
d = 0
}
switch tls.CurveID(d) {
case tls.X25519:
return X25519
case tls.CurveP256:
return P256
case tls.CurveP384:
return P384
case tls.CurveP521:
return P521
default:
return Unknown
}
}
func Check(curves uint16) bool {
if c := ParseInt(int(curves)); c == Unknown {
return false
}
return true
}
func parseBytes(p []byte) Curves {
return Parse(string(p))
}

View File

@@ -0,0 +1,62 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package curves
import (
"reflect"
libmap "github.com/mitchellh/mapstructure"
)
func ViperDecoderHook() libmap.DecodeHookFuncType {
return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) {
var (
z = Curves(0)
t string
k bool
)
// Check if the data type matches the expected one
if from.Kind() != reflect.String {
return data, nil
} else if t, k = data.(string); !k {
return data, nil
}
// Check if the target type matches the expected one
if to != reflect.TypeOf(z) {
return data, nil
}
// Format/decode/parse the data and return the new value
if e := z.unmarshall([]byte(t)); e != nil {
return nil, e
} else {
return z, nil
}
}
}

View File

@@ -29,9 +29,15 @@ package certificates
import ( import (
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"io"
"net/http" "net/http"
liberr "github.com/nabbar/golib/errors" tlsaut "github.com/nabbar/golib/certificates/auth"
tlscas "github.com/nabbar/golib/certificates/ca"
tlscrt "github.com/nabbar/golib/certificates/certs"
tlscpr "github.com/nabbar/golib/certificates/cipher"
tlscrv "github.com/nabbar/golib/certificates/curves"
tlsvrs "github.com/nabbar/golib/certificates/tlsversion"
) )
type FctHttpClient func(def TLSConfig, servername string) *http.Client type FctHttpClient func(def TLSConfig, servername string) *http.Client
@@ -39,50 +45,62 @@ type FctTLSDefault func() TLSConfig
type FctRootCA func() []string type FctRootCA func() []string
type TLSConfig interface { type TLSConfig interface {
RegisterRand(rand io.Reader)
AddRootCAString(rootCA string) bool AddRootCAString(rootCA string) bool
AddRootCAFile(pemFile string) liberr.Error AddRootCAFile(pemFile string) error
GetRootCA() *x509.CertPool GetRootCA() []tlscas.Cert
GetRootCAPool() *x509.CertPool
AddClientCAString(ca string) bool AddClientCAString(ca string) bool
AddClientCAFile(pemFile string) liberr.Error AddClientCAFile(pemFile string) error
GetClientCA() *x509.CertPool GetClientCA() []tlscas.Cert
GetClientCAPool() *x509.CertPool
SetClientAuth(a tlsaut.ClientAuth)
AddCertificatePairString(key, crt string) liberr.Error AddCertificatePairString(key, crt string) error
AddCertificatePairFile(keyFile, crtFile string) liberr.Error AddCertificatePairFile(keyFile, crtFile string) error
LenCertificatePair() int LenCertificatePair() int
CleanCertificatePair() CleanCertificatePair()
GetCertificatePair() []tls.Certificate GetCertificatePair() []tls.Certificate
SetVersionMin(vers uint16) SetVersionMin(v tlsvrs.Version)
SetVersionMax(vers uint16) GetVersionMin() tlsvrs.Version
SetClientAuth(cAuth tls.ClientAuthType) SetVersionMax(v tlsvrs.Version)
SetCipherList(cipher []uint16) GetVersionMax() tlsvrs.Version
SetCurveList(curves []tls.CurveID)
SetCipherList(c []tlscpr.Cipher)
AddCiphers(c ...tlscpr.Cipher)
GetCiphers() []tlscpr.Cipher
SetCurveList(c []tlscrv.Curves)
AddCurves(c ...tlscrv.Curves)
GetCurves() []tlscrv.Curves
SetDynamicSizingDisabled(flag bool) SetDynamicSizingDisabled(flag bool)
SetSessionTicketDisabled(flag bool) SetSessionTicketDisabled(flag bool)
Clone() TLSConfig Clone() TLSConfig
TLS(serverName string) *tls.Config
TlsConfig(serverName string) *tls.Config TlsConfig(serverName string) *tls.Config
Config() *Config
} }
var Default = New() var Default = New()
func New() TLSConfig { func New() TLSConfig {
return &config{ return &config{
caRoot: nil, rand: nil,
cert: nil, cert: make([]tlscrt.Cert, 0),
cipherList: make([]tlscpr.Cipher, 0),
tlsMinVersion: 0, curveList: make([]tlscrv.Curves, 0),
tlsMaxVersion: 0, caRoot: make([]tlscas.Cert, 0),
clientAuth: tlsaut.NoClientCert,
cipherList: nil, clientCA: make([]tlscas.Cert, 0),
curveList: nil, tlsMinVersion: tlsvrs.VersionUnknown,
tlsMaxVersion: tlsvrs.VersionUnknown,
dynSizingDisabled: false, dynSizingDisabled: false,
ticketSessionDisabled: false, ticketSessionDisabled: false,
clientAuth: 0,
clientCA: nil,
} }
} }
@@ -92,7 +110,7 @@ func AddRootCAContents(rootContent string) bool {
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func AddRootCAFile(rootFile string) liberr.Error { func AddRootCAFile(rootFile string) error {
return Default.AddRootCAFile(rootFile) return Default.AddRootCAFile(rootFile)
} }
@@ -102,17 +120,17 @@ func AddCACertificateContents(caContent string) bool {
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func AddCACertificateFile(caFile string) liberr.Error { func AddCACertificateFile(caFile string) error {
return Default.AddClientCAFile(caFile) return Default.AddClientCAFile(caFile)
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func AddCertificatePairString(key, crt string) liberr.Error { func AddCertificatePairString(key, crt string) error {
return Default.AddCertificatePairString(key, crt) return Default.AddCertificatePairString(key, crt)
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func AddCertificatePairFile(keyFile, crtFile string) liberr.Error { func AddCertificatePairFile(keyFile, crtFile string) error {
return Default.AddCertificatePairFile(keyFile, crtFile) return Default.AddCertificatePairFile(keyFile, crtFile)
} }
@@ -137,37 +155,47 @@ func AppendCertificates(cert []tls.Certificate) []tls.Certificate {
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func GetRootCA() *x509.CertPool { func GetRootCA() *x509.CertPool {
return Default.GetRootCA() return Default.GetRootCAPool()
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func GetClientCA() *x509.CertPool { func GetClientCA() *x509.CertPool {
return Default.GetClientCA() return Default.GetClientCAPool()
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func SetVersionMin(vers uint16) { func SetVersionMin(vers uint16) {
Default.SetVersionMin(vers) Default.SetVersionMin(tlsvrs.ParseInt(int(vers)))
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func SetVersionMax(vers uint16) { func SetVersionMax(vers uint16) {
Default.SetVersionMax(vers) Default.SetVersionMax(tlsvrs.ParseInt(int(vers)))
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func SetClientAuth(auth string) { func SetClientAuth(auth string) {
Default.SetClientAuth(StringToClientAuth(auth)) Default.SetClientAuth(tlsaut.Parse(auth))
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func SetCipherList(cipher []uint16) { func SetCipherList(cipher []uint16) {
Default.SetCipherList(cipher) Default.SetCipherList(make([]tlscpr.Cipher, 0))
for _, i := range cipher {
c := tlscpr.ParseInt(int(i))
Default.AddCiphers(c)
}
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func SetCurve(curves []tls.CurveID) { func SetCurve(curves []tls.CurveID) {
Default.SetCurveList(curves) Default.SetCurveList(make([]tlscrv.Curves, 0))
for _, i := range curves {
c := tlscrv.ParseInt(int(i))
Default.AddCurves(c)
}
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
@@ -191,11 +219,11 @@ func GetTlsConfigCertificates() *tls.Config {
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func AddCertificateContents(keyContents, certContents string) liberr.Error { func AddCertificateContents(keyContents, certContents string) error {
return Default.AddCertificatePairString(keyContents, certContents) return Default.AddCertificatePairString(keyContents, certContents)
} }
// Deprecated: use local config and no more globals default config. // Deprecated: use local config and no more globals default config.
func AddCertificateFile(keyFile, certFile string) liberr.Error { func AddCertificateFile(keyFile, certFile string) error {
return Default.AddCertificatePairFile(keyFile, certFile) return Default.AddCertificatePairFile(keyFile, certFile)
} }

View File

@@ -27,329 +27,212 @@
package certificates package certificates
import ( import (
"bytes"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"io/ioutil" "io"
"os"
"strings"
liberr "github.com/nabbar/golib/errors" tlsaut "github.com/nabbar/golib/certificates/auth"
tlscas "github.com/nabbar/golib/certificates/ca"
tlscrt "github.com/nabbar/golib/certificates/certs"
tlscpr "github.com/nabbar/golib/certificates/cipher"
tlscrv "github.com/nabbar/golib/certificates/curves"
tlsvrs "github.com/nabbar/golib/certificates/tlsversion"
) )
type config struct { type config struct {
cert []tls.Certificate rand io.Reader
cipherList []uint16 cert []tlscrt.Cert
curveList []tls.CurveID cipherList []tlscpr.Cipher
caRoot *x509.CertPool curveList []tlscrv.Curves
clientAuth tls.ClientAuthType caRoot []tlscas.Cert
clientCA *x509.CertPool clientAuth tlsaut.ClientAuth
tlsMinVersion uint16 clientCA []tlscas.Cert
tlsMaxVersion uint16 tlsMinVersion tlsvrs.Version
tlsMaxVersion tlsvrs.Version
dynSizingDisabled bool dynSizingDisabled bool
ticketSessionDisabled bool ticketSessionDisabled bool
} }
func (c *config) checkFile(pemFiles ...string) liberr.Error { func (o *config) RegisterRand(rand io.Reader) {
for _, f := range pemFiles { o.rand = rand
if f == "" { }
return ErrorParamEmpty.Error(nil)
}
if _, e := os.Stat(f); e != nil { func (o *config) SetVersionMin(v tlsvrs.Version) {
return ErrorFileStat.Error(e) o.tlsMinVersion = v
} }
/* #nosec */ func (o *config) GetVersionMin() tlsvrs.Version {
b, e := ioutil.ReadFile(f) return o.tlsMinVersion
if e != nil { }
return ErrorFileRead.Error(e)
}
b = bytes.Trim(b, "\n") func (o *config) SetVersionMax(v tlsvrs.Version) {
b = bytes.Trim(b, "\r") o.tlsMaxVersion = v
b = bytes.TrimSpace(b) }
if len(b) < 1 { func (o *config) GetVersionMax() tlsvrs.Version {
return ErrorFileEmpty.Error(nil) return o.tlsMaxVersion
}
func (o *config) SetDynamicSizingDisabled(flag bool) {
o.dynSizingDisabled = flag
}
func (o *config) SetSessionTicketDisabled(flag bool) {
o.ticketSessionDisabled = flag
}
func (o *config) Clone() TLSConfig {
cfg := &config{
rand: o.rand,
cert: make([]tlscrt.Cert, 0),
cipherList: make([]tlscpr.Cipher, 0),
curveList: make([]tlscrv.Curves, 0),
caRoot: make([]tlscas.Cert, 0),
clientAuth: o.clientAuth,
clientCA: make([]tlscas.Cert, 0),
tlsMinVersion: o.tlsMinVersion,
tlsMaxVersion: o.tlsMaxVersion,
dynSizingDisabled: o.dynSizingDisabled,
ticketSessionDisabled: o.ticketSessionDisabled,
}
if len(o.cert) > 0 {
for _, c := range o.cert {
cfg.cert = append(cfg.cert, c)
} }
} }
return nil if len(o.cipherList) > 0 {
for _, c := range o.cipherList {
if tlscpr.Check(c.Uint16()) {
cfg.cipherList = append(cfg.cipherList, c)
}
}
}
if len(o.curveList) > 0 {
for _, c := range o.curveList {
if tlscpr.Check(c.Uint16()) {
cfg.curveList = append(cfg.curveList, c)
}
}
}
if len(o.caRoot) > 0 {
for _, c := range o.caRoot {
cfg.caRoot = append(cfg.caRoot, c)
}
}
if len(o.clientCA) > 0 {
for _, c := range o.clientCA {
cfg.clientCA = append(cfg.clientCA, c)
}
}
return cfg
} }
func (c *config) AddRootCAString(rootCA string) bool { func (o *config) TlsConfig(serverName string) *tls.Config {
if c.caRoot == nil { return o.TLS(serverName)
c.caRoot = SystemRootCA()
}
if rootCA != "" {
return c.caRoot.AppendCertsFromPEM([]byte(rootCA))
}
return false
} }
func (c *config) AddRootCAFile(pemFile string) liberr.Error { func (o *config) TLS(serverName string) *tls.Config {
if e := c.checkFile(pemFile); e != nil {
return e
}
if c.caRoot == nil {
c.caRoot = SystemRootCA()
}
//nolint #nosec
/* #nosec */
b, _ := ioutil.ReadFile(pemFile)
if c.caRoot.AppendCertsFromPEM(b) {
return nil
}
return ErrorCertAppend.Error(nil)
}
func (c *config) AddClientCAString(ca string) bool {
if c.clientCA == nil {
c.clientCA = x509.NewCertPool()
}
if ca != "" {
return c.clientCA.AppendCertsFromPEM([]byte(ca))
}
return false
}
func (c *config) AddClientCAFile(pemFile string) liberr.Error {
if e := c.checkFile(pemFile); e != nil {
return e
}
if c.clientCA == nil {
c.clientCA = x509.NewCertPool()
}
//nolint #nosec
/* #nosec */
b, _ := ioutil.ReadFile(pemFile)
if c.clientCA.AppendCertsFromPEM(b) {
return nil
}
return ErrorCertAppend.Error(nil)
}
func (c *config) AddCertificatePairString(key, crt string) liberr.Error {
if len(c.cert) == 0 {
c.cert = make([]tls.Certificate, 0)
}
key = strings.Trim(key, "\n")
crt = strings.Trim(crt, "\n")
key = strings.Trim(key, "\r")
crt = strings.Trim(crt, "\r")
key = strings.TrimSpace(key)
crt = strings.TrimSpace(crt)
if len(key) < 1 || len(crt) < 1 {
return ErrorParamEmpty.Error(nil)
}
p, err := tls.X509KeyPair([]byte(crt), []byte(key))
if err != nil {
return ErrorCertKeyPairParse.Error(err)
}
c.cert = append(c.cert, p)
return nil
}
func (c *config) AddCertificatePairFile(keyFile, crtFile string) liberr.Error {
if e := c.checkFile(keyFile, crtFile); e != nil {
return e
}
if len(c.cert) == 0 {
c.cert = make([]tls.Certificate, 0)
}
if p, e := tls.LoadX509KeyPair(crtFile, keyFile); e != nil {
return ErrorCertKeyPairLoad.Error(e)
} else {
c.cert = append(c.cert, p)
return nil
}
}
func (c *config) TlsConfig(serverName string) *tls.Config {
/* #nosec */ /* #nosec */
cnf := &tls.Config{ cnf := &tls.Config{
InsecureSkipVerify: false, Rand: nil,
Certificates: make([]tls.Certificate, 0),
RootCAs: SystemRootCA(),
ServerName: "",
ClientAuth: tls.NoClientCert,
ClientCAs: x509.NewCertPool(),
InsecureSkipVerify: false,
CipherSuites: make([]uint16, 0),
SessionTicketsDisabled: false,
MinVersion: 0,
MaxVersion: 0,
CurvePreferences: make([]tls.CurveID, 0),
DynamicRecordSizingDisabled: false,
Renegotiation: tls.RenegotiateNever,
} }
if serverName != "" { if serverName != "" {
cnf.ServerName = serverName cnf.ServerName = serverName
} }
if c.ticketSessionDisabled { if o.ticketSessionDisabled {
cnf.SessionTicketsDisabled = true cnf.SessionTicketsDisabled = true
} }
if c.dynSizingDisabled { if o.dynSizingDisabled {
cnf.DynamicRecordSizingDisabled = true cnf.DynamicRecordSizingDisabled = true
} }
if c.tlsMinVersion != 0 { if o.tlsMinVersion != tlsvrs.VersionUnknown {
cnf.MinVersion = c.tlsMinVersion cnf.MinVersion = o.tlsMinVersion.TLS()
} }
if c.tlsMaxVersion != 0 { if o.tlsMaxVersion != tlsvrs.VersionUnknown {
cnf.MaxVersion = c.tlsMaxVersion cnf.MaxVersion = o.tlsMaxVersion.TLS()
} }
if len(c.cipherList) > 0 { if len(o.cipherList) > 0 {
cnf.PreferServerCipherSuites = true for _, c := range o.cipherList {
cnf.CipherSuites = c.cipherList if c != tlscpr.Unknown {
cnf.CipherSuites = append(cnf.CipherSuites, c.TLS())
}
}
} }
if len(c.curveList) > 0 { if len(o.curveList) > 0 {
cnf.CurvePreferences = c.curveList for _, c := range o.curveList {
if c != tlscrv.Unknown {
cnf.CurvePreferences = append(cnf.CurvePreferences, c.TLS())
}
}
} }
if c.caRoot != nil { if o.caRoot != nil {
cnf.RootCAs = c.caRoot for _, c := range o.caRoot {
c.AppendPool(cnf.RootCAs)
}
} }
if len(c.cert) > 0 { if len(o.cert) > 0 {
cnf.Certificates = c.cert for _, c := range o.cert {
cnf.Certificates = append(cnf.Certificates, c.TLS())
}
} }
if c.clientAuth != tls.NoClientCert { if o.clientAuth != tlsaut.NoClientCert {
cnf.ClientAuth = c.clientAuth cnf.ClientAuth = o.clientAuth.TLS()
if c.clientCA != nil { if len(o.clientCA) > 0 {
cnf.ClientCAs = c.clientCA for _, c := range o.clientCA {
c.AppendPool(cnf.ClientCAs)
}
} }
} }
return cnf return cnf
} }
func (c *config) cloneCipherList() []uint16 { func (o *config) Config() *Config {
if c.cipherList == nil { var crt = make([]tlscrt.Certif, 0)
return nil for _, c := range o.cert {
crt = append(crt, c.Model())
} }
return append(make([]uint16, 0), c.cipherList...) return &Config{
} CurveList: o.curveList,
CipherList: o.cipherList,
func (c *config) cloneCurveList() []tls.CurveID { RootCA: o.caRoot,
if c.curveList == nil { ClientCA: o.clientCA,
return nil Certs: crt,
} VersionMin: o.tlsMinVersion,
VersionMax: o.tlsMaxVersion,
return append(make([]tls.CurveID, 0), c.curveList...) AuthClient: o.clientAuth,
} InheritDefault: false,
DynamicSizingDisable: o.dynSizingDisabled,
func (c *config) cloneCertificates() []tls.Certificate { SessionTicketDisable: o.ticketSessionDisabled,
if c.cert == nil {
return nil
}
return append(make([]tls.Certificate, 0), c.cert...)
}
func (c *config) cloneRootCA() *x509.CertPool {
if c.caRoot == nil {
return nil
}
list := *c.caRoot
return &list
}
func (c *config) cloneClientCA() *x509.CertPool {
if c.clientCA == nil {
return nil
}
list := *c.clientCA
return &list
}
func (c *config) Clone() TLSConfig {
return &config{
caRoot: c.cloneRootCA(),
cert: c.cloneCertificates(),
tlsMinVersion: c.tlsMinVersion,
tlsMaxVersion: c.tlsMaxVersion,
cipherList: c.cloneCipherList(),
curveList: c.cloneCurveList(),
dynSizingDisabled: c.dynSizingDisabled,
ticketSessionDisabled: c.ticketSessionDisabled,
clientAuth: c.clientAuth,
clientCA: c.cloneClientCA(),
} }
} }
func asStruct(cfg TLSConfig) *config {
if c, ok := cfg.(*config); ok {
return c
}
return nil
}
func (c *config) GetRootCA() *x509.CertPool {
return c.caRoot
}
func (c *config) GetClientCA() *x509.CertPool {
return c.clientCA
}
func (c *config) LenCertificatePair() int {
return len(c.cert)
}
func (c *config) CleanCertificatePair() {
c.cert = make([]tls.Certificate, 0)
}
func (c *config) GetCertificatePair() []tls.Certificate {
return c.cert
}
func (c *config) SetVersionMin(vers uint16) {
c.tlsMinVersion = vers
}
func (c *config) SetVersionMax(vers uint16) {
c.tlsMaxVersion = vers
}
func (c *config) SetClientAuth(cAuth tls.ClientAuthType) {
c.clientAuth = cAuth
}
func (c *config) SetCipherList(cipher []uint16) {
c.cipherList = cipher
}
func (c *config) SetCurveList(curves []tls.CurveID) {
c.curveList = curves
}
func (c *config) SetDynamicSizingDisabled(flag bool) {
c.dynSizingDisabled = flag
}
func (c *config) SetSessionTicketDisabled(flag bool) {
c.ticketSessionDisabled = flag
}

79
certificates/rootca.go Normal file
View File

@@ -0,0 +1,79 @@
/*
* MIT License
*
* Copyright (c) 2020 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
package certificates
import (
"crypto/x509"
tlscas "github.com/nabbar/golib/certificates/ca"
)
func (o *config) GetRootCA() []tlscas.Cert {
var res = make([]tlscas.Cert, 0)
for _, c := range o.caRoot {
res = append(res, c)
}
return res
}
func (o *config) GetRootCAPool() *x509.CertPool {
var res = x509.NewCertPool()
for _, ca := range o.caRoot {
ca.AppendPool(res)
}
return res
}
func (o *config) AddRootCAString(rootCA string) bool {
if rootCA != "" {
if c, e := tlscas.Parse(rootCA); e == nil {
o.caRoot = append(o.caRoot, c)
return true
}
}
return false
}
func (o *config) AddRootCAFile(pemFile string) error {
var fct = func(p []byte) error {
if c, e := tlscas.ParseByte(p); e != nil {
return e
} else {
o.caRoot = append(o.caRoot, c)
return nil
}
}
if e := checkFile(fct, pemFile); e != nil {
return e
}
return nil
}

View File

@@ -1,29 +1,28 @@
/*********************************************************************************************************************** /*
* MIT License
* *
* MIT License * Copyright (c) 2020 Nicolas JUHEL
* *
* Copyright (c) 2022 Nicolas JUHEL * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * The above copyright notice and this permission notice shall be included in all
* of this software and associated documentation files (the "Software"), to deal * copies or substantial portions of the Software.
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* copies or substantial portions of the Software. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * SOFTWARE.
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* *
* *
**********************************************************************************************************************/ */
package tlsversion package tlsversion

View File

@@ -1,29 +1,28 @@
/*********************************************************************************************************************** /*
* MIT License
* *
* MIT License * Copyright (c) 2020 Nicolas JUHEL
* *
* Copyright (c) 2022 Nicolas JUHEL * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * The above copyright notice and this permission notice shall be included in all
* of this software and associated documentation files (the "Software"), to deal * copies or substantial portions of the Software.
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* copies or substantial portions of the Software. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * SOFTWARE.
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* *
* *
**********************************************************************************************************************/ */
package tlsversion package tlsversion
@@ -53,6 +52,10 @@ func (v Version) Code() string {
return s return s
} }
func (v Version) TLS() uint16 {
return v.Uint16()
}
func (v Version) Uint16() uint16 { func (v Version) Uint16() uint16 {
switch v { switch v {
case VersionTLS10: case VersionTLS10:

View File

@@ -1,29 +1,28 @@
/*********************************************************************************************************************** /*
* MIT License
* *
* MIT License * Copyright (c) 2020 Nicolas JUHEL
* *
* Copyright (c) 2022 Nicolas JUHEL * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * The above copyright notice and this permission notice shall be included in all
* of this software and associated documentation files (the "Software"), to deal * copies or substantial portions of the Software.
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* copies or substantial portions of the Software. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * SOFTWARE.
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* *
* *
**********************************************************************************************************************/ */
package tlsversion package tlsversion
@@ -60,6 +59,8 @@ func ListHigh() []Version {
func Parse(s string) Version { func Parse(s string) Version {
s = strings.ToLower(s) s = strings.ToLower(s)
s = strings.Replace(s, "\"", "", -1)
s = strings.Replace(s, "'", "", -1)
s = strings.Replace(s, "tls", "", -1) s = strings.Replace(s, "tls", "", -1)
s = strings.Replace(s, "ssl", "", -1) s = strings.Replace(s, "ssl", "", -1)
s = strings.Replace(s, ".", "", -1) s = strings.Replace(s, ".", "", -1)

View File

@@ -1,29 +1,28 @@
/*********************************************************************************************************************** /*
* MIT License
* *
* MIT License * Copyright (c) 2020 Nicolas JUHEL
* *
* Copyright (c) 2022 Nicolas JUHEL * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * The above copyright notice and this permission notice shall be included in all
* of this software and associated documentation files (the "Software"), to deal * copies or substantial portions of the Software.
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* copies or substantial portions of the Software. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * SOFTWARE.
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* *
* *
**********************************************************************************************************************/ */
package tlsversion package tlsversion

View File

@@ -27,22 +27,12 @@
package certificates package certificates
import ( import (
"crypto/tls" "bytes"
"crypto/x509" "crypto/x509"
"os"
"runtime" "runtime"
"strings"
) )
// Deprecated: use StringToCipherKey.
func GetCipherKey(cipher string) uint16 {
return StringToCipherKey(cipher)
}
// Deprecated: use StringToCurveID.
func GetCurveID(curveRef string) tls.CurveID {
return StringToCurveID(curveRef)
}
func SystemRootCA() *x509.CertPool { func SystemRootCA() *x509.CertPool {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
return x509.NewCertPool() return x509.NewCertPool()
@@ -53,105 +43,36 @@ func SystemRootCA() *x509.CertPool {
} }
} }
func StringToTlsVersion(tlsVersStr string) uint16 { func checkFile(fct func(p []byte) error, pemFiles ...string) error {
tlsVersStr = strings.ToLower(tlsVersStr) for _, f := range pemFiles {
tlsVersStr = strings.Replace(tlsVersStr, "TLS", "", -1) if f == "" {
tlsVersStr = strings.TrimSpace(tlsVersStr) return ErrorParamEmpty.Error(nil)
}
switch tlsVersStr { if _, e := os.Stat(f); e != nil {
case "1", "1.0": return e
return tls.VersionTLS10 }
case "1.1":
return tls.VersionTLS11
case "1.2":
return tls.VersionTLS12
case "1.3":
return tls.VersionTLS13
default:
return tls.VersionTLS12
}
}
func StringToClientAuth(auth string) tls.ClientAuthType { /* #nosec */
switch strings.ToLower(auth) { b, e := os.ReadFile(f)
case "request": if e != nil {
return tls.RequestClientCert return e
case "require": }
return tls.RequireAnyClientCert
case "verify":
return tls.VerifyClientCertIfGiven
case "strict":
return tls.RequireAndVerifyClientCert
default:
return tls.NoClientCert
}
}
func StringToCipherKey(cipher string) uint16 { b = bytes.Trim(b, "\n")
cipher = strings.ToLower(cipher) b = bytes.Trim(b, "\r")
cipher = strings.ReplaceAll(cipher, " ", "") b = bytes.TrimSpace(b)
cipher = strings.ReplaceAll(cipher, "_", "")
cipher = strings.ReplaceAll(cipher, "-", "")
rsa := strings.Contains(cipher, "rsa") if len(b) < 1 {
dhe := strings.Contains(cipher, "ecdhe") return ErrorFileEmpty.Error(nil)
dsa := strings.Contains(cipher, "ecdsa") } else if fct == nil {
gcm := strings.Contains(cipher, "gcm") continue
aes1 := strings.Contains(cipher, "aes128") }
aes2 := strings.Contains(cipher, "aes256")
cha := strings.Contains(cipher, "chacha20")
poly := strings.Contains(cipher, "poly1305")
switch {
// TLS v1.0 - v1.2
case !dhe && rsa && aes1 && !gcm:
return tls.TLS_RSA_WITH_AES_128_CBC_SHA256
case !dhe && rsa && aes1 && gcm:
return tls.TLS_RSA_WITH_AES_128_GCM_SHA256
case !dhe && rsa && aes2 && gcm:
return tls.TLS_RSA_WITH_AES_256_GCM_SHA384
case dhe && dsa && aes1 && !gcm:
return tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
case dhe && rsa && aes1 && !gcm:
return tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
case dhe && rsa && aes1 && gcm:
return tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
case dhe && dsa && aes1 && gcm:
return tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
case dhe && rsa && aes2 && gcm:
return tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
case dhe && dsa && aes2 && gcm:
return tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
case rsa && (cha || poly):
return tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
case dsa && (cha || poly):
return tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
// TLS v1.3
case aes1 && gcm:
return tls.TLS_AES_128_GCM_SHA256
case aes2 && gcm:
return tls.TLS_AES_256_GCM_SHA384
case cha || poly:
return tls.TLS_CHACHA20_POLY1305_SHA256
if e = fct(b); e != nil {
return e
}
} }
return 0 return nil
}
func StringToCurveID(curveRef string) tls.CurveID {
curveRef = strings.ToLower(curveRef)
if strings.Contains(curveRef, "p2") {
return tls.CurveP256
} else if strings.Contains(curveRef, "p3") {
return tls.CurveP384
} else if strings.Contains(curveRef, "p5") {
return tls.CurveP521
} else if strings.Contains(curveRef, "x25") {
return tls.X25519
}
return 0
} }

View File

@@ -146,7 +146,7 @@ func (o *componentSmtp) _GetTLS() libtls.TLSConfig {
} }
func (o *componentSmtp) _GetTLSConfig(cfg libtls.Config) *tls.Config { func (o *componentSmtp) _GetTLSConfig(cfg libtls.Config) *tls.Config {
if i, e := cfg.NewFrom(o._GetTLS()); e != nil { if i := cfg.NewFrom(o._GetTLS()); i == nil {
// #nosec // #nosec
return &tls.Config{} return &tls.Config{}
} else { } else {

View File

@@ -27,6 +27,8 @@
package tls package tls
import ( import (
"fmt"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
cfgtps "github.com/nabbar/golib/config/types" cfgtps "github.com/nabbar/golib/config/types"
libver "github.com/nabbar/golib/version" libver "github.com/nabbar/golib/version"
@@ -159,8 +161,8 @@ func (o *componentTls) _runCli() error {
if cfg, err = o._getConfig(); err != nil { if cfg, err = o._getConfig(); err != nil {
return prt.Error(err) return prt.Error(err)
} else if tls, err = cfg.New(); err != nil { } else if tls = cfg.New(); tls == nil {
return prt.Error(err) return prt.Error(fmt.Errorf("cannot use tls config for new instance"))
} else if o.f != nil { } else if o.f != nil {
for _, s := range o.f() { for _, s := range o.f() {
tls.AddRootCAString(s) tls.AddRootCAString(s)

View File

@@ -34,7 +34,6 @@ import (
libval "github.com/go-playground/validator/v10" libval "github.com/go-playground/validator/v10"
libftp "github.com/jlaffaye/ftp" libftp "github.com/jlaffaye/ftp"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors"
) )
type ConfigTimeZone struct { type ConfigTimeZone struct {
@@ -81,7 +80,7 @@ type Config struct {
} }
// Validate allow checking if the config' struct is valid with the awaiting model // Validate allow checking if the config' struct is valid with the awaiting model
func (c *Config) Validate() liberr.Error { func (c *Config) Validate() error {
var e = ErrorValidatorError.Error(nil) var e = ErrorValidatorError.Error(nil)
if err := libval.New().Struct(c); err != nil { if err := libval.New().Struct(c); err != nil {
@@ -110,11 +109,11 @@ func (c *Config) RegisterDefaultTLS(fct func() libtls.TLSConfig) {
c.ftls = fct c.ftls = fct
} }
func (c *Config) New() (*libftp.ServerConn, liberr.Error) { func (c *Config) New() (*libftp.ServerConn, error) {
var opt = make([]libftp.DialOption, 0) var opt = make([]libftp.DialOption, 0)
if tls, err := c.TLS.NewFrom(c.ftls()); err != nil { if tls := c.TLS.NewFrom(c.ftls()); tls == nil {
return nil, err return nil, fmt.Errorf("no tls configured")
} else if c.ForceTLS { } else if c.ForceTLS {
opt = append(opt, libftp.DialWithExplicitTLS(tls.TlsConfig(""))) opt = append(opt, libftp.DialWithExplicitTLS(tls.TlsConfig("")))
} else { } else {

View File

@@ -33,46 +33,45 @@ import (
"time" "time"
libftp "github.com/jlaffaye/ftp" libftp "github.com/jlaffaye/ftp"
liberr "github.com/nabbar/golib/errors"
) )
type FTPClient interface { type FTPClient interface {
// Connect establish the connection to server with the given configuration registered. // Connect establish the connection to server with the given configuration registered.
Connect() liberr.Error Connect() error
// Check try to retrieve a valid connection to the server and send an NOOP command to check the connection. // Check try to retrieve a valid connection to the server and send an NOOP command to check the connection.
Check() liberr.Error Check() error
// Close send the QUID command to the server if the connection is valid (cf Check). // Close send the QUID command to the server if the connection is valid (cf Check).
Close() Close()
// NameList issues an NLST FTP command. // NameList issues an NLST FTP command.
NameList(path string) ([]string, liberr.Error) NameList(path string) ([]string, error)
// List issues a LIST FTP command. // List issues a LIST FTP command.
List(path string) ([]*libftp.Entry, liberr.Error) List(path string) ([]*libftp.Entry, error)
// ChangeDir issues a CWD FTP command, which changes the current directory to the specified path. // ChangeDir issues a CWD FTP command, which changes the current directory to the specified path.
ChangeDir(path string) liberr.Error ChangeDir(path string) error
// CurrentDir issues a PWD FTP command, which Returns the path of the current directory. // CurrentDir issues a PWD FTP command, which Returns the path of the current directory.
CurrentDir() (string, liberr.Error) CurrentDir() (string, error)
// FileSize issues a SIZE FTP command, which Returns the size of the file. // FileSize issues a SIZE FTP command, which Returns the size of the file.
FileSize(path string) (int64, liberr.Error) FileSize(path string) (int64, error)
// GetTime issues the MDTM FTP command to obtain the file modification time. // GetTime issues the MDTM FTP command to obtain the file modification time.
// It returns a UTC time. // It returns a UTC time.
GetTime(path string) (time.Time, liberr.Error) GetTime(path string) (time.Time, error)
// SetTime issues the MFMT FTP command to set the file modification time. // SetTime issues the MFMT FTP command to set the file modification time.
// Also it can use a non-standard form of the MDTM command supported by the VsFtpd server instead of MFMT for the same purpose. // Also it can use a non-standard form of the MDTM command supported by the VsFtpd server instead of MFMT for the same purpose.
// See "mdtm_write" in https://security.appspot.com/vsftpd/vsftpd_conf.html // See "mdtm_write" in https://security.appspot.com/vsftpd/vsftpd_conf.html
SetTime(path string, t time.Time) liberr.Error SetTime(path string, t time.Time) error
// Retr issues a RETR FTP command to fetch the specified file from the remote FTP server. // Retr issues a RETR FTP command to fetch the specified file from the remote FTP server.
// The returned ReadCloser must be closed to cleanup the FTP data connection. // The returned ReadCloser must be closed to cleanup the FTP data connection.
Retr(path string) (*libftp.Response, liberr.Error) Retr(path string) (*libftp.Response, error)
// RetrFrom issues a RETR FTP command to fetch the specified file from the remote FTP server, // RetrFrom issues a RETR FTP command to fetch the specified file from the remote FTP server,
// the server will not send the offset first bytes of the file. // the server will not send the offset first bytes of the file.
@@ -82,38 +81,38 @@ type FTPClient interface {
// Stor issues a STOR FTP command to store a file to the remote FTP server. // Stor issues a STOR FTP command to store a file to the remote FTP server.
// Stor creates the specified file with the content of the io.Reader. // Stor creates the specified file with the content of the io.Reader.
// Hint: io.Pipe() can be used if an io.Writer is required. // Hint: io.Pipe() can be used if an io.Writer is required.
Stor(path string, r io.Reader) liberr.Error Stor(path string, r io.Reader) error
// StorFrom issues a STOR FTP command to store a file to the remote FTP server. // StorFrom issues a STOR FTP command to store a file to the remote FTP server.
// Stor creates the specified file with the content of the io.Reader, writing on the server will start at the given file offset. // Stor creates the specified file with the content of the io.Reader, writing on the server will start at the given file offset.
// Hint: io.Pipe() can be used if an io.Writer is required. // Hint: io.Pipe() can be used if an io.Writer is required.
StorFrom(path string, r io.Reader, offset uint64) liberr.Error StorFrom(path string, r io.Reader, offset uint64) error
// Append issues a APPE FTP command to store a file to the remote FTP server. // Append issues a APPE FTP command to store a file to the remote FTP server.
// If a file already exists with the given path, then the content of the io.Reader is appended. // If a file already exists with the given path, then the content of the io.Reader is appended.
// Otherwise, a new file is created with that content. Hint: io.Pipe() can be used if an io.Writer is required. // Otherwise, a new file is created with that content. Hint: io.Pipe() can be used if an io.Writer is required.
Append(path string, r io.Reader) liberr.Error Append(path string, r io.Reader) error
// Rename renames a file on the remote FTP server. // Rename renames a file on the remote FTP server.
Rename(from, to string) liberr.Error Rename(from, to string) error
// Delete issues a DELE FTP command to delete the specified file from the remote FTP server. // Delete issues a DELE FTP command to delete the specified file from the remote FTP server.
Delete(path string) liberr.Error Delete(path string) error
// RemoveDirRecur deletes a non-empty folder recursively using RemoveDir and Delete. // RemoveDirRecur deletes a non-empty folder recursively using RemoveDir and Delete.
RemoveDirRecur(path string) liberr.Error RemoveDirRecur(path string) error
// MakeDir issues a MKD FTP command to create the specified directory on the remote FTP server. // MakeDir issues a MKD FTP command to create the specified directory on the remote FTP server.
MakeDir(path string) liberr.Error MakeDir(path string) error
// RemoveDir issues a RMD FTP command to remove the specified directory from the remote FTP server. // RemoveDir issues a RMD FTP command to remove the specified directory from the remote FTP server.
RemoveDir(path string) liberr.Error RemoveDir(path string) error
//Walk prepares the internal walk function so that the caller can begin traversing the directory. //Walk prepares the internal walk function so that the caller can begin traversing the directory.
Walk(root string) (*libftp.Walker, liberr.Error) Walk(root string) (*libftp.Walker, error)
} }
func New(cfg *Config) (FTPClient, liberr.Error) { func New(cfg *Config) (FTPClient, error) {
c := &ftpClient{ c := &ftpClient{
m: sync.Mutex{}, m: sync.Mutex{},
cfg: new(atomic.Value), cfg: new(atomic.Value),

View File

@@ -34,7 +34,6 @@ import (
"time" "time"
libftp "github.com/jlaffaye/ftp" libftp "github.com/jlaffaye/ftp"
liberr "github.com/nabbar/golib/errors"
) )
type ftpClient struct { type ftpClient struct {
@@ -96,10 +95,9 @@ func (f *ftpClient) setClient(cli *libftp.ServerConn) {
f.cli.Store(cli) f.cli.Store(cli)
} }
func (f *ftpClient) Connect() liberr.Error { func (f *ftpClient) Connect() error {
var ( var (
e error e error
err liberr.Error
cfg *Config cfg *Config
cli *libftp.ServerConn cli *libftp.ServerConn
) )
@@ -116,8 +114,8 @@ func (f *ftpClient) Connect() liberr.Error {
return ErrorNotInitialized.Error(nil) return ErrorNotInitialized.Error(nil)
} }
if cli, err = cfg.New(); err != nil { if cli, e = cfg.New(); e != nil {
return err return e
} }
if e = cli.NoOp(); e != nil { if e = cli.NoOp(); e != nil {
@@ -128,7 +126,7 @@ func (f *ftpClient) Connect() liberr.Error {
return nil return nil
} }
func (f *ftpClient) Check() liberr.Error { func (f *ftpClient) Check() error {
var cli *libftp.ServerConn var cli *libftp.ServerConn
if cli = f.getClient(); cli == nil { if cli = f.getClient(); cli == nil {
@@ -153,7 +151,7 @@ func (f *ftpClient) Close() {
} }
} }
func (f *ftpClient) NameList(path string) ([]string, liberr.Error) { func (f *ftpClient) NameList(path string) ([]string, error) {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return nil, err return nil, err
} }
@@ -165,7 +163,7 @@ func (f *ftpClient) NameList(path string) ([]string, liberr.Error) {
} }
} }
func (f *ftpClient) List(path string) ([]*libftp.Entry, liberr.Error) { func (f *ftpClient) List(path string) ([]*libftp.Entry, error) {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return nil, err return nil, err
} }
@@ -177,7 +175,7 @@ func (f *ftpClient) List(path string) ([]*libftp.Entry, liberr.Error) {
} }
} }
func (f *ftpClient) ChangeDir(path string) liberr.Error { func (f *ftpClient) ChangeDir(path string) error {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return err return err
} }
@@ -189,7 +187,7 @@ func (f *ftpClient) ChangeDir(path string) liberr.Error {
} }
} }
func (f *ftpClient) CurrentDir() (string, liberr.Error) { func (f *ftpClient) CurrentDir() (string, error) {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return "", err return "", err
} }
@@ -201,7 +199,7 @@ func (f *ftpClient) CurrentDir() (string, liberr.Error) {
} }
} }
func (f *ftpClient) FileSize(path string) (int64, liberr.Error) { func (f *ftpClient) FileSize(path string) (int64, error) {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return 0, err return 0, err
} }
@@ -213,7 +211,7 @@ func (f *ftpClient) FileSize(path string) (int64, liberr.Error) {
} }
} }
func (f *ftpClient) GetTime(path string) (time.Time, liberr.Error) { func (f *ftpClient) GetTime(path string) (time.Time, error) {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return time.Time{}, err return time.Time{}, err
} }
@@ -225,7 +223,7 @@ func (f *ftpClient) GetTime(path string) (time.Time, liberr.Error) {
} }
} }
func (f *ftpClient) SetTime(path string, t time.Time) liberr.Error { func (f *ftpClient) SetTime(path string, t time.Time) error {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return err return err
} }
@@ -237,7 +235,7 @@ func (f *ftpClient) SetTime(path string, t time.Time) liberr.Error {
} }
} }
func (f *ftpClient) Retr(path string) (*libftp.Response, liberr.Error) { func (f *ftpClient) Retr(path string) (*libftp.Response, error) {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return nil, err return nil, err
} }
@@ -261,7 +259,7 @@ func (f *ftpClient) RetrFrom(path string, offset uint64) (*libftp.Response, erro
} }
} }
func (f *ftpClient) Stor(path string, r io.Reader) liberr.Error { func (f *ftpClient) Stor(path string, r io.Reader) error {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return err return err
} }
@@ -273,7 +271,7 @@ func (f *ftpClient) Stor(path string, r io.Reader) liberr.Error {
} }
} }
func (f *ftpClient) StorFrom(path string, r io.Reader, offset uint64) liberr.Error { func (f *ftpClient) StorFrom(path string, r io.Reader, offset uint64) error {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return err return err
} }
@@ -285,7 +283,7 @@ func (f *ftpClient) StorFrom(path string, r io.Reader, offset uint64) liberr.Err
} }
} }
func (f *ftpClient) Append(path string, r io.Reader) liberr.Error { func (f *ftpClient) Append(path string, r io.Reader) error {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return err return err
} }
@@ -297,7 +295,7 @@ func (f *ftpClient) Append(path string, r io.Reader) liberr.Error {
} }
} }
func (f *ftpClient) Rename(from, to string) liberr.Error { func (f *ftpClient) Rename(from, to string) error {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return err return err
} }
@@ -309,7 +307,7 @@ func (f *ftpClient) Rename(from, to string) liberr.Error {
} }
} }
func (f *ftpClient) Delete(path string) liberr.Error { func (f *ftpClient) Delete(path string) error {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return err return err
} }
@@ -321,7 +319,7 @@ func (f *ftpClient) Delete(path string) liberr.Error {
} }
} }
func (f *ftpClient) RemoveDirRecur(path string) liberr.Error { func (f *ftpClient) RemoveDirRecur(path string) error {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return err return err
} }
@@ -333,7 +331,7 @@ func (f *ftpClient) RemoveDirRecur(path string) liberr.Error {
} }
} }
func (f *ftpClient) MakeDir(path string) liberr.Error { func (f *ftpClient) MakeDir(path string) error {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return err return err
} }
@@ -345,7 +343,7 @@ func (f *ftpClient) MakeDir(path string) liberr.Error {
} }
} }
func (f *ftpClient) RemoveDir(path string) liberr.Error { func (f *ftpClient) RemoveDir(path string) error {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return err return err
} }
@@ -357,7 +355,7 @@ func (f *ftpClient) RemoveDir(path string) liberr.Error {
} }
} }
func (f *ftpClient) Walk(root string) (*libftp.Walker, liberr.Error) { func (f *ftpClient) Walk(root string) (*libftp.Walker, error) {
if err := f.Check(); err != nil { if err := f.Check(); err != nil {
return nil, err return nil, err
} }

View File

@@ -75,16 +75,13 @@ func (o *dmp) Transport(cfg TransportConfig) *http.Transport {
prx = http.ProxyURL(cfg.Proxy) prx = http.ProxyURL(cfg.Proxy)
} }
var ( var ssl libtls.TLSConfig
err error
ssl libtls.TLSConfig
)
if cfg.TLSConfig == nil { if cfg.TLSConfig == nil {
ssl = libtls.New() ssl = libtls.New()
ssl.SetVersionMin(tls.VersionTLS12) ssl.SetVersionMin(tls.VersionTLS12)
ssl.SetVersionMax(tls.VersionTLS13) ssl.SetVersionMax(tls.VersionTLS13)
} else if ssl, err = cfg.TLSConfig.New(); err != nil { } else if ssl = cfg.TLSConfig.New(); ssl == nil {
ssl = libtls.New() ssl = libtls.New()
ssl.SetVersionMin(tls.VersionTLS12) ssl.SetVersionMin(tls.VersionTLS12)
ssl.SetVersionMax(tls.VersionTLS13) ssl.SetVersionMax(tls.VersionTLS13)

View File

@@ -37,7 +37,6 @@ import (
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
libdur "github.com/nabbar/golib/duration" libdur "github.com/nabbar/golib/duration"
liberr "github.com/nabbar/golib/errors"
srvtps "github.com/nabbar/golib/httpserver/types" srvtps "github.com/nabbar/golib/httpserver/types"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
logcfg "github.com/nabbar/golib/logger/config" logcfg "github.com/nabbar/golib/logger/config"
@@ -210,12 +209,9 @@ func (c *Config) Clone() Config {
TLS: libtls.Config{ TLS: libtls.Config{
CurveList: c.TLS.CurveList, CurveList: c.TLS.CurveList,
CipherList: c.TLS.CipherList, CipherList: c.TLS.CipherList,
RootCAString: c.TLS.RootCAString, RootCA: c.TLS.RootCA,
RootCAFile: c.TLS.RootCAFile, ClientCA: c.TLS.ClientCA,
ClientCAString: c.TLS.ClientCAString, Certs: c.TLS.Certs,
ClientCAFiles: c.TLS.ClientCAFiles,
CertPairString: c.TLS.CertPairString,
CertPairFile: c.TLS.CertPairFile,
VersionMin: c.TLS.VersionMin, VersionMin: c.TLS.VersionMin,
VersionMax: c.TLS.VersionMax, VersionMax: c.TLS.VersionMax,
AuthClient: c.TLS.AuthClient, AuthClient: c.TLS.AuthClient,
@@ -239,17 +235,21 @@ func (c *Config) SetContext(f libctx.FuncContext) {
c.getParentContext = f c.getParentContext = f
} }
func (c *Config) GetTLS() (libtls.TLSConfig, liberr.Error) { func (c *Config) GetTLS() (libtls.TLSConfig, error) {
var def libtls.TLSConfig var def libtls.TLSConfig
if c.TLS.InheritDefault && c.getTLSDefault != nil { if c.TLS.InheritDefault && c.getTLSDefault != nil {
def = c.getTLSDefault() def = c.getTLSDefault()
} }
return c.TLS.NewFrom(def) if cfg := c.TLS.NewFrom(def); cfg != nil {
return cfg, nil
}
return nil, fmt.Errorf("no tls configuration found")
} }
func (c *Config) CheckTLS() (libtls.TLSConfig, liberr.Error) { func (c *Config) CheckTLS() (libtls.TLSConfig, error) {
if ssl, err := c.GetTLS(); err != nil { if ssl, err := c.GetTLS(); err != nil {
return nil, err return nil, err
} else if ssl == nil || ssl.LenCertificatePair() < 1 { } else if ssl == nil || ssl.LenCertificatePair() < 1 {
@@ -337,7 +337,7 @@ func (c *Config) GetHandlerKey() string {
return c.HandlerKey return c.HandlerKey
} }
func (c *Config) Validate() liberr.Error { func (c *Config) Validate() error {
err := ErrorServerValidate.Error(nil) err := ErrorServerValidate.Error(nil)
if er := libval.New().Struct(c); er != nil { if er := libval.New().Struct(c); er != nil {

View File

@@ -91,11 +91,11 @@ func (p Config) Walk(fct FuncWalkConfig) {
} }
} }
func (p Config) Validate() liberr.Error { func (p Config) Validate() error {
var e = ErrorPoolValidate.Error(nil) var e = ErrorPoolValidate.Error(nil)
p.Walk(func(cfg libhtp.Config) bool { p.Walk(func(cfg libhtp.Config) bool {
var err liberr.Error var err error
if err = cfg.Validate(); err != nil { if err = cfg.Validate(); err != nil {
e.Add(err) e.Add(err)

View File

@@ -33,7 +33,6 @@ import (
libval "github.com/go-playground/validator/v10" libval "github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors"
natcli "github.com/nats-io/nats.go" natcli "github.com/nats-io/nats.go"
) )
@@ -147,7 +146,7 @@ type Client struct {
TLSConfig libtls.Config TLSConfig libtls.Config
} }
func (c Client) Validate() liberr.Error { func (c Client) Validate() error {
err := ErrorConfigValidation.Error(nil) err := ErrorConfigValidation.Error(nil)
if er := libval.New().Struct(c); er != nil { if er := libval.New().Struct(c); er != nil {
@@ -168,7 +167,7 @@ func (c Client) Validate() liberr.Error {
return nil return nil
} }
func (c Client) NewClient(defTls libtls.TLSConfig) (*natcli.Conn, liberr.Error) { func (c Client) NewClient(defTls libtls.TLSConfig) (*natcli.Conn, error) {
opts := natcli.GetDefaultOptions() opts := natcli.GetDefaultOptions()
if c.Url != "" { if c.Url != "" {
@@ -273,8 +272,8 @@ func (c Client) NewClient(defTls libtls.TLSConfig) (*natcli.Conn, liberr.Error)
} }
if c.Secure { if c.Secure {
if t, e := c.TLSConfig.NewFrom(defTls); e != nil { if t := c.TLSConfig.NewFrom(defTls); t == nil {
return nil, e return nil, fmt.Errorf("no valid tls configuration")
} else { } else {
opts.TLSConfig = t.TlsConfig("") opts.TLSConfig = t.TlsConfig("")
} }

View File

@@ -38,7 +38,6 @@ import (
libval "github.com/go-playground/validator/v10" libval "github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors"
libiot "github.com/nabbar/golib/ioutils" libiot "github.com/nabbar/golib/ioutils"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
loglvl "github.com/nabbar/golib/logger/level" loglvl "github.com/nabbar/golib/logger/level"
@@ -63,7 +62,7 @@ type Config struct {
Customs *ConfigCustom `mapstructure:"-" json:"-" yaml:"-" toml:"-"` Customs *ConfigCustom `mapstructure:"-" json:"-" yaml:"-" toml:"-"`
} }
func (c Config) Validate() liberr.Error { func (c Config) Validate() error {
err := ErrorConfigValidation.Error(nil) err := ErrorConfigValidation.Error(nil)
if er := libval.New().Struct(c); er != nil { if er := libval.New().Struct(c); er != nil {
@@ -84,7 +83,7 @@ func (c Config) Validate() liberr.Error {
return nil return nil
} }
func (c Config) LogConfigJson() liberr.Error { func (c Config) LogConfigJson() error {
if c.Logs.LogFile == "" { if c.Logs.LogFile == "" {
return nil return nil
} }
@@ -129,7 +128,7 @@ func (c Config) LogConfigJson() liberr.Error {
return nil return nil
} }
func (c Config) NatsOption(defaultTls libtls.TLSConfig, log liblog.Logger) (*natsrv.Options, liberr.Error) { func (c Config) NatsOption(defaultTls libtls.TLSConfig, log liblog.Logger) (*natsrv.Options, error) {
cfg := &natsrv.Options{ cfg := &natsrv.Options{
CheckConfig: false, CheckConfig: false,
} }
@@ -187,7 +186,7 @@ func (c Config) NatsOption(defaultTls libtls.TLSConfig, log liblog.Logger) (*nat
return cfg, nil return cfg, nil
} }
func (c *ConfigCustom) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) liberr.Error { func (c *ConfigCustom) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) error {
if cfg == nil { if cfg == nil {
return ErrorParamsInvalid.Error(nil) return ErrorParamsInvalid.Error(nil)
} }
@@ -209,8 +208,8 @@ func (c *ConfigCustom) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) lib
} }
if c.AccountResolverTLS { if c.AccountResolverTLS {
if t, e := c.AccountResolverTLSConfig.NewFrom(defTls); e != nil { if t := c.AccountResolverTLSConfig.NewFrom(defTls); t == nil {
return e return fmt.Errorf("no valid tls config")
} else { } else {
cfg.AccountResolverTLSConfig = t.TlsConfig("") cfg.AccountResolverTLSConfig = t.TlsConfig("")
} }
@@ -221,7 +220,7 @@ func (c *ConfigCustom) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) lib
return nil return nil
} }
func (c ConfigAuth) makeOpt(cfg *natsrv.Options) liberr.Error { func (c ConfigAuth) makeOpt(cfg *natsrv.Options) error {
if cfg == nil { if cfg == nil {
return ErrorParamsInvalid.Error(nil) return ErrorParamsInvalid.Error(nil)
} }
@@ -285,7 +284,7 @@ func (c ConfigAuth) makeOpt(cfg *natsrv.Options) liberr.Error {
return nil return nil
} }
func (c ConfigNkey) makeOpt(auth ConfigAuth, cfg *natsrv.Options) (*natsrv.NkeyUser, liberr.Error) { func (c ConfigNkey) makeOpt(auth ConfigAuth, cfg *natsrv.Options) (*natsrv.NkeyUser, error) {
if cfg == nil { if cfg == nil {
return nil, ErrorParamsInvalid.Error(nil) return nil, ErrorParamsInvalid.Error(nil)
} }
@@ -342,7 +341,7 @@ func (c ConfigNkey) makeOpt(auth ConfigAuth, cfg *natsrv.Options) (*natsrv.NkeyU
}, nil }, nil
} }
func (c ConfigUser) makeOpt(auth ConfigAuth, cfg *natsrv.Options) (*natsrv.User, liberr.Error) { func (c ConfigUser) makeOpt(auth ConfigAuth, cfg *natsrv.Options) (*natsrv.User, error) {
if cfg == nil { if cfg == nil {
return nil, ErrorParamsInvalid.Error(nil) return nil, ErrorParamsInvalid.Error(nil)
} }
@@ -473,7 +472,7 @@ func (c ConfigPermissionResponse) makeOpt() *natsrv.ResponsePermission {
return res return res
} }
func (c ConfigLogger) makeOpt(log liblog.Logger, cfg *natsrv.Options) liberr.Error { func (c ConfigLogger) makeOpt(log liblog.Logger, cfg *natsrv.Options) error {
if cfg == nil { if cfg == nil {
return ErrorParamsInvalid.Error(nil) return ErrorParamsInvalid.Error(nil)
} }
@@ -540,7 +539,7 @@ func (c ConfigLogger) makeOpt(log liblog.Logger, cfg *natsrv.Options) liberr.Err
return nil return nil
} }
func (c ConfigLimits) makeOpt(cfg *natsrv.Options) liberr.Error { func (c ConfigLimits) makeOpt(cfg *natsrv.Options) error {
if cfg == nil { if cfg == nil {
return ErrorParamsInvalid.Error(nil) return ErrorParamsInvalid.Error(nil)
} }
@@ -604,7 +603,7 @@ func (c ConfigLimits) makeOpt(cfg *natsrv.Options) liberr.Error {
return nil return nil
} }
func (c ConfigSrv) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) liberr.Error { func (c ConfigSrv) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) error {
if cfg == nil { if cfg == nil {
return ErrorParamsInvalid.Error(nil) return ErrorParamsInvalid.Error(nil)
} }
@@ -733,8 +732,8 @@ func (c ConfigSrv) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) liberr.
if c.TLS { if c.TLS {
cfg.TLS = true cfg.TLS = true
if t, e := c.TLSConfig.NewFrom(defTls); e != nil { if t := c.TLSConfig.NewFrom(defTls); t == nil {
return e return fmt.Errorf("no valid tls config")
} else { } else {
cfg.TLSConfig = t.TlsConfig("") cfg.TLSConfig = t.TlsConfig("")
} }
@@ -757,7 +756,7 @@ func (c ConfigSrv) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) liberr.
return nil return nil
} }
func (c ConfigCluster) makeOpt(defTls libtls.TLSConfig) (natsrv.ClusterOpts, liberr.Error) { func (c ConfigCluster) makeOpt(defTls libtls.TLSConfig) (natsrv.ClusterOpts, error) {
cfg := natsrv.ClusterOpts{ cfg := natsrv.ClusterOpts{
Name: c.Name, Name: c.Name,
Host: c.Host, Host: c.Host,
@@ -786,8 +785,8 @@ func (c ConfigCluster) makeOpt(defTls libtls.TLSConfig) (natsrv.ClusterOpts, lib
} }
if c.TLS { if c.TLS {
if t, e := c.TLSConfig.NewFrom(defTls); e != nil { if t := c.TLSConfig.NewFrom(defTls); t == nil {
return cfg, e return cfg, fmt.Errorf("no valid tls config")
} else { } else {
cfg.TLSConfig = t.TlsConfig("") cfg.TLSConfig = t.TlsConfig("")
} }
@@ -803,7 +802,7 @@ func (c ConfigCluster) makeOpt(defTls libtls.TLSConfig) (natsrv.ClusterOpts, lib
return cfg, nil return cfg, nil
} }
func (c ConfigGateway) makeOpt(defTls libtls.TLSConfig) (natsrv.GatewayOpts, liberr.Error) { func (c ConfigGateway) makeOpt(defTls libtls.TLSConfig) (natsrv.GatewayOpts, error) {
cfg := natsrv.GatewayOpts{ cfg := natsrv.GatewayOpts{
Name: c.Name, Name: c.Name,
Host: c.Host, Host: c.Host,
@@ -826,8 +825,8 @@ func (c ConfigGateway) makeOpt(defTls libtls.TLSConfig) (natsrv.GatewayOpts, lib
} }
if c.TLS { if c.TLS {
if t, e := c.TLSConfig.NewFrom(defTls); e != nil { if t := c.TLSConfig.NewFrom(defTls); t == nil {
return cfg, e return cfg, fmt.Errorf("no valid tls config")
} else { } else {
cfg.TLSConfig = t.TlsConfig("") cfg.TLSConfig = t.TlsConfig("")
} }
@@ -850,7 +849,7 @@ func (c ConfigGateway) makeOpt(defTls libtls.TLSConfig) (natsrv.GatewayOpts, lib
return cfg, nil return cfg, nil
} }
func (c ConfigGatewayRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteGatewayOpts, liberr.Error) { func (c ConfigGatewayRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteGatewayOpts, error) {
res := &natsrv.RemoteGatewayOpts{ res := &natsrv.RemoteGatewayOpts{
Name: "", Name: "",
TLSConfig: nil, TLSConfig: nil,
@@ -863,8 +862,8 @@ func (c ConfigGatewayRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteGat
} }
if c.TLS { if c.TLS {
if t, e := c.TLSConfig.NewFrom(defTls); e != nil { if t := c.TLSConfig.NewFrom(defTls); t == nil {
return nil, e return nil, fmt.Errorf("no valid tls config")
} else { } else {
res.TLSConfig = t.TlsConfig("") res.TLSConfig = t.TlsConfig("")
} }
@@ -891,7 +890,7 @@ func (c ConfigGatewayRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteGat
return res, nil return res, nil
} }
func (c ConfigLeaf) makeOpt(cfg *natsrv.Options, auth ConfigAuth, defTls libtls.TLSConfig) (natsrv.LeafNodeOpts, liberr.Error) { func (c ConfigLeaf) makeOpt(cfg *natsrv.Options, auth ConfigAuth, defTls libtls.TLSConfig) (natsrv.LeafNodeOpts, error) {
res := natsrv.LeafNodeOpts{ res := natsrv.LeafNodeOpts{
Host: c.Host, Host: c.Host,
Port: c.Port, Port: c.Port,
@@ -924,8 +923,8 @@ func (c ConfigLeaf) makeOpt(cfg *natsrv.Options, auth ConfigAuth, defTls libtls.
} }
if c.TLS { if c.TLS {
if t, e := c.TLSConfig.NewFrom(defTls); e != nil { if t := c.TLSConfig.NewFrom(defTls); t == nil {
return res, e return res, fmt.Errorf("no valid tls config")
} else { } else {
res.TLSConfig = t.TlsConfig("") res.TLSConfig = t.TlsConfig("")
} }
@@ -951,7 +950,7 @@ func (c ConfigLeaf) makeOpt(cfg *natsrv.Options, auth ConfigAuth, defTls libtls.
return res, nil return res, nil
} }
func (c ConfigLeafRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteLeafOpts, liberr.Error) { func (c ConfigLeafRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteLeafOpts, error) {
res := &natsrv.RemoteLeafOpts{ res := &natsrv.RemoteLeafOpts{
LocalAccount: c.LocalAccount, LocalAccount: c.LocalAccount,
URLs: make([]*url.URL, 0), URLs: make([]*url.URL, 0),
@@ -974,8 +973,8 @@ func (c ConfigLeafRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteLeafOp
if c.TLS { if c.TLS {
res.TLS = true res.TLS = true
if t, e := c.TLSConfig.NewFrom(defTls); e != nil { if t := c.TLSConfig.NewFrom(defTls); t == nil {
return nil, e return nil, fmt.Errorf("no valid tls config")
} else { } else {
res.TLSConfig = t.TlsConfig("") res.TLSConfig = t.TlsConfig("")
} }
@@ -1009,7 +1008,7 @@ func (c ConfigLeafRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteLeafOp
return res, nil return res, nil
} }
func (c ConfigWebsocket) makeOpt(defTls libtls.TLSConfig) (natsrv.WebsocketOpts, liberr.Error) { func (c ConfigWebsocket) makeOpt(defTls libtls.TLSConfig) (natsrv.WebsocketOpts, error) {
cfg := natsrv.WebsocketOpts{ cfg := natsrv.WebsocketOpts{
Host: c.Host, Host: c.Host,
Port: c.Port, Port: c.Port,
@@ -1044,8 +1043,8 @@ func (c ConfigWebsocket) makeOpt(defTls libtls.TLSConfig) (natsrv.WebsocketOpts,
if !c.NoTLS { if !c.NoTLS {
cfg.NoTLS = false cfg.NoTLS = false
if t, e := c.TLSConfig.NewFrom(defTls); e != nil { if t := c.TLSConfig.NewFrom(defTls); t == nil {
return cfg, e return cfg, fmt.Errorf("no valid tls config")
} else { } else {
cfg.TLSConfig = t.TlsConfig("") cfg.TLSConfig = t.TlsConfig("")
} }
@@ -1063,7 +1062,7 @@ func (c ConfigWebsocket) makeOpt(defTls libtls.TLSConfig) (natsrv.WebsocketOpts,
return cfg, nil return cfg, nil
} }
func (c ConfigMQTT) makeOpt(defTls libtls.TLSConfig) (natsrv.MQTTOpts, liberr.Error) { func (c ConfigMQTT) makeOpt(defTls libtls.TLSConfig) (natsrv.MQTTOpts, error) {
cfg := natsrv.MQTTOpts{ cfg := natsrv.MQTTOpts{
Host: c.Host, Host: c.Host,
Port: c.Port, Port: c.Port,
@@ -1084,8 +1083,8 @@ func (c ConfigMQTT) makeOpt(defTls libtls.TLSConfig) (natsrv.MQTTOpts, liberr.Er
} }
if !c.TLS { if !c.TLS {
if t, e := c.TLSConfig.NewFrom(defTls); e != nil { if t := c.TLSConfig.NewFrom(defTls); t == nil {
return cfg, e return cfg, fmt.Errorf("no valid tls config")
} else { } else {
cfg.TLSConfig = t.TlsConfig("") cfg.TLSConfig = t.TlsConfig("")
} }

View File

@@ -37,7 +37,6 @@ import (
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
liberr "github.com/nabbar/golib/errors"
montps "github.com/nabbar/golib/monitor/types" montps "github.com/nabbar/golib/monitor/types"
libver "github.com/nabbar/golib/version" libver "github.com/nabbar/golib/version"
natsrv "github.com/nats-io/nats-server/v2/server" natsrv "github.com/nats-io/nats-server/v2/server"
@@ -50,8 +49,8 @@ const (
) )
type Server interface { type Server interface {
Listen(ctx context.Context) liberr.Error Listen(ctx context.Context) error
Restart(ctx context.Context) liberr.Error Restart(ctx context.Context) error
Shutdown() Shutdown()
GetOptions() *natsrv.Options GetOptions() *natsrv.Options
@@ -62,9 +61,9 @@ type Server interface {
IsReadyTimeout(parent context.Context, dur time.Duration) bool IsReadyTimeout(parent context.Context, dur time.Duration) bool
WaitReady(ctx context.Context, tick time.Duration) WaitReady(ctx context.Context, tick time.Duration)
ClientAdvertise(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err liberr.Error) ClientAdvertise(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err error)
ClientCluster(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err liberr.Error) ClientCluster(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err error)
ClientServer(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err liberr.Error) ClientServer(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err error)
Monitor(ctx libctx.FuncContext, vrs libver.Version) (montps.Monitor, error) Monitor(ctx libctx.FuncContext, vrs libver.Version) (montps.Monitor, error)
} }
@@ -89,11 +88,11 @@ type server struct {
o *atomic.Value o *atomic.Value
s *atomic.Value s *atomic.Value
r *atomic.Value r *atomic.Value
e liberr.Error e error
m sync.Mutex m sync.Mutex
} }
func (s *server) Listen(ctx context.Context) liberr.Error { func (s *server) Listen(ctx context.Context) error {
if s.IsRunning() || s.IsReady() { if s.IsRunning() || s.IsReady() {
s.Shutdown() s.Shutdown()
} }
@@ -123,7 +122,7 @@ func (s *server) Listen(ctx context.Context) liberr.Error {
return nil return nil
} }
func (s *server) Restart(ctx context.Context) liberr.Error { func (s *server) Restart(ctx context.Context) error {
return s.Listen(ctx) return s.Listen(ctx)
} }
@@ -212,7 +211,7 @@ func (s *server) WaitReady(ctx context.Context, tick time.Duration) {
} }
} }
func (s *server) ClientAdvertise(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err liberr.Error) { func (s *server) ClientAdvertise(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err error) {
if o := s.GetOptions(); o != nil && o.ClientAdvertise != "" { if o := s.GetOptions(); o != nil && o.ClientAdvertise != "" {
opt.Url = s._FormatAddress(o.ClientAdvertise) opt.Url = s._FormatAddress(o.ClientAdvertise)
} else { } else {
@@ -222,7 +221,7 @@ func (s *server) ClientAdvertise(ctx context.Context, tick time.Duration, defTls
return opt.NewClient(defTls) return opt.NewClient(defTls)
} }
func (s *server) ClientCluster(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err liberr.Error) { func (s *server) ClientCluster(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err error) {
s.WaitReady(ctx, tick) s.WaitReady(ctx, tick)
if srv := s._GetServer(); srv != nil { if srv := s._GetServer(); srv != nil {
@@ -236,7 +235,7 @@ func (s *server) ClientCluster(ctx context.Context, tick time.Duration, defTls l
return opt.NewClient(defTls) return opt.NewClient(defTls)
} }
func (s *server) ClientServer(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err liberr.Error) { func (s *server) ClientServer(ctx context.Context, tick time.Duration, defTls libtls.TLSConfig, opt Client) (cli *natcli.Conn, err error) {
var o *natsrv.Options var o *natsrv.Options
if o = s.GetOptions(); o == nil { if o = s.GetOptions(); o == nil {
@@ -290,14 +289,14 @@ func (s *server) _SetServer(srv *natsrv.Server) {
s.s.Store(srv) s.s.Store(srv)
} }
func (s *server) _GetError() liberr.Error { func (s *server) _GetError() error {
s.m.Lock() s.m.Lock()
defer s.m.Unlock() defer s.m.Unlock()
return s.e return s.e
} }
func (s *server) _SetError(err liberr.Error) { func (s *server) _SetError(err error) {
s.m.Lock() s.m.Lock()
defer s.m.Unlock() defer s.m.Unlock()