mirror of
https://github.com/nabbar/golib.git
synced 2025-09-27 04:06:05 +08:00
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:
89
certificates/auth/encode.go
Normal file
89
certificates/auth/encode.go
Normal 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)
|
||||
}
|
55
certificates/auth/format.go
Normal file
55
certificates/auth/format.go
Normal 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)
|
||||
}
|
99
certificates/auth/interface.go
Normal file
99
certificates/auth/interface.go
Normal 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))
|
||||
}
|
62
certificates/auth/models.go
Normal file
62
certificates/auth/models.go
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
86
certificates/authClient.go
Normal file
86
certificates/authClient.go
Normal 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
165
certificates/ca/encode.go
Normal 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
61
certificates/ca/format.go
Normal 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)
|
||||
}
|
||||
}
|
78
certificates/ca/interface.go
Normal file
78
certificates/ca/interface.go
Normal 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
69
certificates/ca/models.go
Normal 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
84
certificates/cert.go
Normal 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
|
||||
}
|
||||
}
|
214
certificates/certificates_config_test.go
Normal file
214
certificates/certificates_config_test.go
Normal 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))
|
||||
})
|
||||
})
|
||||
})
|
75
certificates/certificates_suite_test.go
Normal file
75
certificates/certificates_suite_test.go
Normal 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())
|
||||
}
|
||||
}
|
||||
})
|
165
certificates/certs/config.go
Normal file
165
certificates/certs/config.go
Normal 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
|
||||
}
|
244
certificates/certs/encode.go
Normal file
244
certificates/certs/encode.go
Normal 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
|
||||
}
|
86
certificates/certs/format.go
Normal file
86
certificates/certs/format.go
Normal 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
|
||||
}
|
76
certificates/certs/interface.go
Normal file
76
certificates/certs/interface.go
Normal 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
|
||||
}
|
||||
}
|
75
certificates/certs/models.go
Normal file
75
certificates/certs/models.go
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
89
certificates/cipher/encode.go
Normal file
89
certificates/cipher/encode.go
Normal 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)
|
||||
}
|
100
certificates/cipher/format.go
Normal file
100
certificates/cipher/format.go
Normal 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())
|
||||
}
|
199
certificates/cipher/interface.go
Normal file
199
certificates/cipher/interface.go
Normal 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))
|
||||
}
|
62
certificates/cipher/models.go
Normal file
62
certificates/cipher/models.go
Normal 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
52
certificates/ciphers.go
Normal 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
|
||||
}
|
@@ -30,26 +30,24 @@ import (
|
||||
"fmt"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
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 {
|
||||
CurveList []string `mapstructure:"curveList" json:"curveList" yaml:"curveList" toml:"curveList"`
|
||||
CipherList []string `mapstructure:"cipherList" json:"cipherList" yaml:"cipherList" toml:"cipherList"`
|
||||
RootCAString []string `mapstructure:"rootCA" json:"rootCA" yaml:"rootCA" toml:"rootCA"`
|
||||
RootCAFile []string `mapstructure:"rootCAFiles" json:"rootCAFiles" yaml:"rootCAFiles" toml:"rootCAFiles"`
|
||||
ClientCAString []string `mapstructure:"clientCA" json:"clientCA" yaml:"clientCA" toml:"clientCA"`
|
||||
ClientCAFiles []string `mapstructure:"clientCAFiles" json:"clientCAFiles" yaml:"clientCAFiles" toml:"clientCAFiles"`
|
||||
CertPairString []Certif `mapstructure:"certPair" json:"certPair" yaml:"certPair" toml:"certPair"`
|
||||
CertPairFile []Certif `mapstructure:"certPairFiles" json:"certPairFiles" yaml:"certPairFiles" toml:"certPairFiles"`
|
||||
VersionMin string `mapstructure:"versionMin" json:"versionMin" yaml:"versionMin" toml:"versionMin"`
|
||||
VersionMax string `mapstructure:"versionMax" json:"versionMax" yaml:"versionMax" toml:"versionMax"`
|
||||
AuthClient string `mapstructure:"authClient" json:"authClient" yaml:"authClient" toml:"authClient"`
|
||||
CurveList []tlscrv.Curves `mapstructure:"curveList" json:"curveList" yaml:"curveList" toml:"curveList"`
|
||||
CipherList []tlscpr.Cipher `mapstructure:"cipherList" json:"cipherList" yaml:"cipherList" toml:"cipherList"`
|
||||
RootCA []tlscas.Cert `mapstructure:"rootCA" json:"rootCA" yaml:"rootCA" toml:"rootCA"`
|
||||
ClientCA []tlscas.Cert `mapstructure:"clientCA" json:"clientCA" yaml:"clientCA" toml:"clientCA"`
|
||||
Certs []tlscrt.Certif `mapstructure:"certs" json:"certs" yaml:"certs" toml:"certs"`
|
||||
VersionMin tlsvrs.Version `mapstructure:"versionMin" json:"versionMin" yaml:"versionMin" toml:"versionMin"`
|
||||
VersionMax tlsvrs.Version `mapstructure:"versionMax" json:"versionMax" yaml:"versionMax" toml:"versionMax"`
|
||||
AuthClient tlsaut.ClientAuth `mapstructure:"authClient" json:"authClient" yaml:"authClient" toml:"authClient"`
|
||||
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"`
|
||||
@@ -76,7 +74,7 @@ func (c *Config) Validate() liberr.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) New() (TLSConfig, liberr.Error) {
|
||||
func (c *Config) New() TLSConfig {
|
||||
if c.InheritDefault {
|
||||
return c.NewFrom(Default)
|
||||
} else {
|
||||
@@ -85,117 +83,114 @@ func (c *Config) New() (TLSConfig, liberr.Error) {
|
||||
}
|
||||
|
||||
// nolint #gocognit
|
||||
func (c *Config) NewFrom(cfg TLSConfig) (TLSConfig, liberr.Error) {
|
||||
var t *config
|
||||
func (c *Config) NewFrom(cfg TLSConfig) TLSConfig {
|
||||
var t *Config
|
||||
|
||||
if cfg != nil {
|
||||
t = asStruct(cfg.Clone())
|
||||
t = cfg.Config()
|
||||
}
|
||||
|
||||
if t == nil {
|
||||
t = asStruct(New())
|
||||
t.caRoot = SystemRootCA()
|
||||
t = &Config{}
|
||||
}
|
||||
|
||||
if c.VersionMin != "" {
|
||||
t.tlsMinVersion = StringToTlsVersion(c.VersionMin)
|
||||
if c.VersionMin != tlsvrs.VersionUnknown {
|
||||
t.VersionMin = c.VersionMin
|
||||
}
|
||||
|
||||
if c.VersionMax != "" {
|
||||
t.tlsMaxVersion = StringToTlsVersion(c.VersionMax)
|
||||
if c.VersionMax != tlsvrs.VersionUnknown {
|
||||
t.VersionMax = c.VersionMax
|
||||
}
|
||||
|
||||
if c.DynamicSizingDisable {
|
||||
t.dynSizingDisabled = true
|
||||
t.DynamicSizingDisable = true
|
||||
}
|
||||
|
||||
if c.SessionTicketDisable {
|
||||
t.ticketSessionDisabled = true
|
||||
t.SessionTicketDisable = true
|
||||
}
|
||||
|
||||
if c.AuthClient != "" {
|
||||
t.clientAuth = StringToClientAuth(c.AuthClient)
|
||||
if c.AuthClient != tlsaut.NoClientCert {
|
||||
t.AuthClient = c.AuthClient
|
||||
}
|
||||
|
||||
if len(c.CipherList) > 0 {
|
||||
for _, a := range c.CipherList {
|
||||
if len(a) < 1 {
|
||||
continue
|
||||
if tlscpr.Check(a.Uint16()) {
|
||||
t.CipherList = append(t.CipherList, a)
|
||||
}
|
||||
t.cipherList = append(t.cipherList, StringToCipherKey(a))
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.CurveList) > 0 {
|
||||
for _, a := range c.CurveList {
|
||||
if len(a) < 1 {
|
||||
continue
|
||||
}
|
||||
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 tlscrv.Check(a.Uint16()) {
|
||||
t.CurveList = append(t.CurveList, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.ClientCAString) > 0 {
|
||||
for _, s := range c.ClientCAString {
|
||||
if len(s) < 1 {
|
||||
continue
|
||||
}
|
||||
t.AddClientCAString(s)
|
||||
if len(c.RootCA) > 0 {
|
||||
for _, s := range c.RootCA {
|
||||
t.RootCA = append(t.RootCA, s)
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.ClientCAFiles) > 0 {
|
||||
for _, f := range c.ClientCAFiles {
|
||||
if len(f) < 1 {
|
||||
continue
|
||||
}
|
||||
if e := t.AddClientCAFile(f); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
if len(c.ClientCA) > 0 {
|
||||
for _, s := range c.ClientCA {
|
||||
t.ClientCA = append(t.ClientCA, s)
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.CertPairString) > 0 {
|
||||
for _, s := range c.CertPairString {
|
||||
if len(s.Key) < 1 || len(s.Pem) < 1 {
|
||||
continue
|
||||
}
|
||||
if e := t.AddCertificatePairString(s.Key, s.Pem); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
if len(c.Certs) > 0 {
|
||||
for _, s := range c.Certs {
|
||||
t.Certs = append(t.Certs, s)
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.CertPairFile) > 0 {
|
||||
for _, f := range c.CertPairFile {
|
||||
if len(f.Key) < 1 || len(f.Pem) < 1 {
|
||||
continue
|
||||
}
|
||||
if e := t.AddCertificatePairFile(f.Key, f.Pem); e != nil {
|
||||
return nil, e
|
||||
res := &config{
|
||||
rand: nil,
|
||||
cert: make([]tlscrt.Cert, 0),
|
||||
cipherList: make([]tlscpr.Cipher, 0),
|
||||
curveList: make([]tlscrv.Curves, 0),
|
||||
caRoot: make([]tlscas.Cert, 0),
|
||||
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
52
certificates/curves.go
Normal 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
|
||||
}
|
89
certificates/curves/encode.go
Normal file
89
certificates/curves/encode.go
Normal 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)
|
||||
}
|
98
certificates/curves/format.go
Normal file
98
certificates/curves/format.go
Normal 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())
|
||||
}
|
120
certificates/curves/interface.go
Normal file
120
certificates/curves/interface.go
Normal 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))
|
||||
}
|
62
certificates/curves/models.go
Normal file
62
certificates/curves/models.go
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@@ -29,9 +29,15 @@ package certificates
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io"
|
||||
"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
|
||||
@@ -39,50 +45,62 @@ type FctTLSDefault func() TLSConfig
|
||||
type FctRootCA func() []string
|
||||
|
||||
type TLSConfig interface {
|
||||
RegisterRand(rand io.Reader)
|
||||
|
||||
AddRootCAString(rootCA string) bool
|
||||
AddRootCAFile(pemFile string) liberr.Error
|
||||
GetRootCA() *x509.CertPool
|
||||
AddRootCAFile(pemFile string) error
|
||||
GetRootCA() []tlscas.Cert
|
||||
GetRootCAPool() *x509.CertPool
|
||||
|
||||
AddClientCAString(ca string) bool
|
||||
AddClientCAFile(pemFile string) liberr.Error
|
||||
GetClientCA() *x509.CertPool
|
||||
AddClientCAFile(pemFile string) error
|
||||
GetClientCA() []tlscas.Cert
|
||||
GetClientCAPool() *x509.CertPool
|
||||
SetClientAuth(a tlsaut.ClientAuth)
|
||||
|
||||
AddCertificatePairString(key, crt string) liberr.Error
|
||||
AddCertificatePairFile(keyFile, crtFile string) liberr.Error
|
||||
AddCertificatePairString(key, crt string) error
|
||||
AddCertificatePairFile(keyFile, crtFile string) error
|
||||
LenCertificatePair() int
|
||||
CleanCertificatePair()
|
||||
GetCertificatePair() []tls.Certificate
|
||||
|
||||
SetVersionMin(vers uint16)
|
||||
SetVersionMax(vers uint16)
|
||||
SetClientAuth(cAuth tls.ClientAuthType)
|
||||
SetCipherList(cipher []uint16)
|
||||
SetCurveList(curves []tls.CurveID)
|
||||
SetVersionMin(v tlsvrs.Version)
|
||||
GetVersionMin() tlsvrs.Version
|
||||
SetVersionMax(v tlsvrs.Version)
|
||||
GetVersionMax() tlsvrs.Version
|
||||
|
||||
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)
|
||||
SetSessionTicketDisabled(flag bool)
|
||||
|
||||
Clone() TLSConfig
|
||||
TLS(serverName string) *tls.Config
|
||||
TlsConfig(serverName string) *tls.Config
|
||||
Config() *Config
|
||||
}
|
||||
|
||||
var Default = New()
|
||||
|
||||
func New() TLSConfig {
|
||||
return &config{
|
||||
caRoot: nil,
|
||||
cert: nil,
|
||||
|
||||
tlsMinVersion: 0,
|
||||
tlsMaxVersion: 0,
|
||||
|
||||
cipherList: nil,
|
||||
curveList: nil,
|
||||
|
||||
rand: nil,
|
||||
cert: make([]tlscrt.Cert, 0),
|
||||
cipherList: make([]tlscpr.Cipher, 0),
|
||||
curveList: make([]tlscrv.Curves, 0),
|
||||
caRoot: make([]tlscas.Cert, 0),
|
||||
clientAuth: tlsaut.NoClientCert,
|
||||
clientCA: make([]tlscas.Cert, 0),
|
||||
tlsMinVersion: tlsvrs.VersionUnknown,
|
||||
tlsMaxVersion: tlsvrs.VersionUnknown,
|
||||
dynSizingDisabled: 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.
|
||||
func AddRootCAFile(rootFile string) liberr.Error {
|
||||
func AddRootCAFile(rootFile string) error {
|
||||
return Default.AddRootCAFile(rootFile)
|
||||
}
|
||||
|
||||
@@ -102,17 +120,17 @@ func AddCACertificateContents(caContent string) bool {
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
@@ -137,37 +155,47 @@ func AppendCertificates(cert []tls.Certificate) []tls.Certificate {
|
||||
|
||||
// Deprecated: use local config and no more globals default config.
|
||||
func GetRootCA() *x509.CertPool {
|
||||
return Default.GetRootCA()
|
||||
return Default.GetRootCAPool()
|
||||
}
|
||||
|
||||
// Deprecated: use local config and no more globals default config.
|
||||
func GetClientCA() *x509.CertPool {
|
||||
return Default.GetClientCA()
|
||||
return Default.GetClientCAPool()
|
||||
}
|
||||
|
||||
// Deprecated: use local config and no more globals default config.
|
||||
func SetVersionMin(vers uint16) {
|
||||
Default.SetVersionMin(vers)
|
||||
Default.SetVersionMin(tlsvrs.ParseInt(int(vers)))
|
||||
}
|
||||
|
||||
// Deprecated: use local config and no more globals default config.
|
||||
func SetVersionMax(vers uint16) {
|
||||
Default.SetVersionMax(vers)
|
||||
Default.SetVersionMax(tlsvrs.ParseInt(int(vers)))
|
||||
}
|
||||
|
||||
// Deprecated: use local config and no more globals default config.
|
||||
func SetClientAuth(auth string) {
|
||||
Default.SetClientAuth(StringToClientAuth(auth))
|
||||
Default.SetClientAuth(tlsaut.Parse(auth))
|
||||
}
|
||||
|
||||
// Deprecated: use local config and no more globals default config.
|
||||
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.
|
||||
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.
|
||||
@@ -191,11 +219,11 @@ func GetTlsConfigCertificates() *tls.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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
@@ -27,329 +27,212 @@
|
||||
package certificates
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"io"
|
||||
|
||||
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 {
|
||||
cert []tls.Certificate
|
||||
cipherList []uint16
|
||||
curveList []tls.CurveID
|
||||
caRoot *x509.CertPool
|
||||
clientAuth tls.ClientAuthType
|
||||
clientCA *x509.CertPool
|
||||
tlsMinVersion uint16
|
||||
tlsMaxVersion uint16
|
||||
rand io.Reader
|
||||
cert []tlscrt.Cert
|
||||
cipherList []tlscpr.Cipher
|
||||
curveList []tlscrv.Curves
|
||||
caRoot []tlscas.Cert
|
||||
clientAuth tlsaut.ClientAuth
|
||||
clientCA []tlscas.Cert
|
||||
tlsMinVersion tlsvrs.Version
|
||||
tlsMaxVersion tlsvrs.Version
|
||||
dynSizingDisabled bool
|
||||
ticketSessionDisabled bool
|
||||
}
|
||||
|
||||
func (c *config) checkFile(pemFiles ...string) liberr.Error {
|
||||
for _, f := range pemFiles {
|
||||
if f == "" {
|
||||
return ErrorParamEmpty.Error(nil)
|
||||
func (o *config) RegisterRand(rand io.Reader) {
|
||||
o.rand = rand
|
||||
}
|
||||
|
||||
if _, e := os.Stat(f); e != nil {
|
||||
return ErrorFileStat.Error(e)
|
||||
func (o *config) SetVersionMin(v tlsvrs.Version) {
|
||||
o.tlsMinVersion = v
|
||||
}
|
||||
|
||||
/* #nosec */
|
||||
b, e := ioutil.ReadFile(f)
|
||||
if e != nil {
|
||||
return ErrorFileRead.Error(e)
|
||||
func (o *config) GetVersionMin() tlsvrs.Version {
|
||||
return o.tlsMinVersion
|
||||
}
|
||||
|
||||
b = bytes.Trim(b, "\n")
|
||||
b = bytes.Trim(b, "\r")
|
||||
b = bytes.TrimSpace(b)
|
||||
func (o *config) SetVersionMax(v tlsvrs.Version) {
|
||||
o.tlsMaxVersion = v
|
||||
}
|
||||
|
||||
if len(b) < 1 {
|
||||
return ErrorFileEmpty.Error(nil)
|
||||
func (o *config) GetVersionMax() tlsvrs.Version {
|
||||
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)
|
||||
}
|
||||
|
||||
func (c *config) AddRootCAString(rootCA string) bool {
|
||||
if c.caRoot == nil {
|
||||
c.caRoot = SystemRootCA()
|
||||
}
|
||||
|
||||
if rootCA != "" {
|
||||
return c.caRoot.AppendCertsFromPEM([]byte(rootCA))
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *config) AddRootCAFile(pemFile string) liberr.Error {
|
||||
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 {
|
||||
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 (o *config) TlsConfig(serverName string) *tls.Config {
|
||||
return o.TLS(serverName)
|
||||
}
|
||||
|
||||
func (o *config) TLS(serverName string) *tls.Config {
|
||||
/* #nosec */
|
||||
cnf := &tls.Config{
|
||||
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 != "" {
|
||||
cnf.ServerName = serverName
|
||||
}
|
||||
|
||||
if c.ticketSessionDisabled {
|
||||
if o.ticketSessionDisabled {
|
||||
cnf.SessionTicketsDisabled = true
|
||||
}
|
||||
|
||||
if c.dynSizingDisabled {
|
||||
if o.dynSizingDisabled {
|
||||
cnf.DynamicRecordSizingDisabled = true
|
||||
}
|
||||
|
||||
if c.tlsMinVersion != 0 {
|
||||
cnf.MinVersion = c.tlsMinVersion
|
||||
if o.tlsMinVersion != tlsvrs.VersionUnknown {
|
||||
cnf.MinVersion = o.tlsMinVersion.TLS()
|
||||
}
|
||||
|
||||
if c.tlsMaxVersion != 0 {
|
||||
cnf.MaxVersion = c.tlsMaxVersion
|
||||
if o.tlsMaxVersion != tlsvrs.VersionUnknown {
|
||||
cnf.MaxVersion = o.tlsMaxVersion.TLS()
|
||||
}
|
||||
|
||||
if len(c.cipherList) > 0 {
|
||||
cnf.PreferServerCipherSuites = true
|
||||
cnf.CipherSuites = c.cipherList
|
||||
if len(o.cipherList) > 0 {
|
||||
for _, c := range o.cipherList {
|
||||
if c != tlscpr.Unknown {
|
||||
cnf.CipherSuites = append(cnf.CipherSuites, c.TLS())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.curveList) > 0 {
|
||||
cnf.CurvePreferences = c.curveList
|
||||
if len(o.curveList) > 0 {
|
||||
for _, c := range o.curveList {
|
||||
if c != tlscrv.Unknown {
|
||||
cnf.CurvePreferences = append(cnf.CurvePreferences, c.TLS())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c.caRoot != nil {
|
||||
cnf.RootCAs = c.caRoot
|
||||
if o.caRoot != nil {
|
||||
for _, c := range o.caRoot {
|
||||
c.AppendPool(cnf.RootCAs)
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.cert) > 0 {
|
||||
cnf.Certificates = c.cert
|
||||
if len(o.cert) > 0 {
|
||||
for _, c := range o.cert {
|
||||
cnf.Certificates = append(cnf.Certificates, c.TLS())
|
||||
}
|
||||
}
|
||||
|
||||
if c.clientAuth != tls.NoClientCert {
|
||||
cnf.ClientAuth = c.clientAuth
|
||||
if c.clientCA != nil {
|
||||
cnf.ClientCAs = c.clientCA
|
||||
if o.clientAuth != tlsaut.NoClientCert {
|
||||
cnf.ClientAuth = o.clientAuth.TLS()
|
||||
if len(o.clientCA) > 0 {
|
||||
for _, c := range o.clientCA {
|
||||
c.AppendPool(cnf.ClientCAs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cnf
|
||||
}
|
||||
|
||||
func (c *config) cloneCipherList() []uint16 {
|
||||
if c.cipherList == nil {
|
||||
return nil
|
||||
func (o *config) Config() *Config {
|
||||
var crt = make([]tlscrt.Certif, 0)
|
||||
for _, c := range o.cert {
|
||||
crt = append(crt, c.Model())
|
||||
}
|
||||
|
||||
return append(make([]uint16, 0), c.cipherList...)
|
||||
}
|
||||
|
||||
func (c *config) cloneCurveList() []tls.CurveID {
|
||||
if c.curveList == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return append(make([]tls.CurveID, 0), c.curveList...)
|
||||
}
|
||||
|
||||
func (c *config) cloneCertificates() []tls.Certificate {
|
||||
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(),
|
||||
return &Config{
|
||||
CurveList: o.curveList,
|
||||
CipherList: o.cipherList,
|
||||
RootCA: o.caRoot,
|
||||
ClientCA: o.clientCA,
|
||||
Certs: crt,
|
||||
VersionMin: o.tlsMinVersion,
|
||||
VersionMax: o.tlsMaxVersion,
|
||||
AuthClient: o.clientAuth,
|
||||
InheritDefault: false,
|
||||
DynamicSizingDisable: o.dynSizingDisabled,
|
||||
SessionTicketDisable: o.ticketSessionDisabled,
|
||||
}
|
||||
}
|
||||
|
||||
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
79
certificates/rootca.go
Normal 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
|
||||
}
|
@@ -1,8 +1,7 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Nicolas JUHEL
|
||||
* 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
|
||||
@@ -23,7 +22,7 @@
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
*/
|
||||
|
||||
package tlsversion
|
||||
|
||||
|
@@ -1,8 +1,7 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Nicolas JUHEL
|
||||
* 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
|
||||
@@ -23,7 +22,7 @@
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
*/
|
||||
|
||||
package tlsversion
|
||||
|
||||
@@ -53,6 +52,10 @@ func (v Version) Code() string {
|
||||
return s
|
||||
}
|
||||
|
||||
func (v Version) TLS() uint16 {
|
||||
return v.Uint16()
|
||||
}
|
||||
|
||||
func (v Version) Uint16() uint16 {
|
||||
switch v {
|
||||
case VersionTLS10:
|
||||
|
@@ -1,8 +1,7 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Nicolas JUHEL
|
||||
* 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
|
||||
@@ -23,7 +22,7 @@
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
*/
|
||||
|
||||
package tlsversion
|
||||
|
||||
@@ -60,6 +59,8 @@ func ListHigh() []Version {
|
||||
|
||||
func Parse(s string) Version {
|
||||
s = strings.ToLower(s)
|
||||
s = strings.Replace(s, "\"", "", -1)
|
||||
s = strings.Replace(s, "'", "", -1)
|
||||
s = strings.Replace(s, "tls", "", -1)
|
||||
s = strings.Replace(s, "ssl", "", -1)
|
||||
s = strings.Replace(s, ".", "", -1)
|
||||
|
@@ -1,8 +1,7 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Nicolas JUHEL
|
||||
* 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
|
||||
@@ -23,7 +22,7 @@
|
||||
* SOFTWARE.
|
||||
*
|
||||
*
|
||||
**********************************************************************************************************************/
|
||||
*/
|
||||
|
||||
package tlsversion
|
||||
|
||||
|
@@ -27,22 +27,12 @@
|
||||
package certificates
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"os"
|
||||
"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 {
|
||||
if runtime.GOOS == "windows" {
|
||||
return x509.NewCertPool()
|
||||
@@ -53,105 +43,36 @@ func SystemRootCA() *x509.CertPool {
|
||||
}
|
||||
}
|
||||
|
||||
func StringToTlsVersion(tlsVersStr string) uint16 {
|
||||
tlsVersStr = strings.ToLower(tlsVersStr)
|
||||
tlsVersStr = strings.Replace(tlsVersStr, "TLS", "", -1)
|
||||
tlsVersStr = strings.TrimSpace(tlsVersStr)
|
||||
func checkFile(fct func(p []byte) error, pemFiles ...string) error {
|
||||
for _, f := range pemFiles {
|
||||
if f == "" {
|
||||
return ErrorParamEmpty.Error(nil)
|
||||
}
|
||||
|
||||
switch tlsVersStr {
|
||||
case "1", "1.0":
|
||||
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
|
||||
if _, e := os.Stat(f); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
/* #nosec */
|
||||
b, e := os.ReadFile(f)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
b = bytes.Trim(b, "\n")
|
||||
b = bytes.Trim(b, "\r")
|
||||
b = bytes.TrimSpace(b)
|
||||
|
||||
if len(b) < 1 {
|
||||
return ErrorFileEmpty.Error(nil)
|
||||
} else if fct == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if e = fct(b); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
func StringToClientAuth(auth string) tls.ClientAuthType {
|
||||
switch strings.ToLower(auth) {
|
||||
case "request":
|
||||
return tls.RequestClientCert
|
||||
case "require":
|
||||
return tls.RequireAnyClientCert
|
||||
case "verify":
|
||||
return tls.VerifyClientCertIfGiven
|
||||
case "strict":
|
||||
return tls.RequireAndVerifyClientCert
|
||||
default:
|
||||
return tls.NoClientCert
|
||||
}
|
||||
}
|
||||
|
||||
func StringToCipherKey(cipher string) uint16 {
|
||||
cipher = strings.ToLower(cipher)
|
||||
cipher = strings.ReplaceAll(cipher, " ", "")
|
||||
cipher = strings.ReplaceAll(cipher, "_", "")
|
||||
cipher = strings.ReplaceAll(cipher, "-", "")
|
||||
|
||||
rsa := strings.Contains(cipher, "rsa")
|
||||
dhe := strings.Contains(cipher, "ecdhe")
|
||||
dsa := strings.Contains(cipher, "ecdsa")
|
||||
gcm := strings.Contains(cipher, "gcm")
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
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
|
||||
return nil
|
||||
}
|
||||
|
@@ -146,7 +146,7 @@ func (o *componentSmtp) _GetTLS() libtls.TLSConfig {
|
||||
}
|
||||
|
||||
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
|
||||
return &tls.Config{}
|
||||
} else {
|
||||
|
@@ -27,6 +27,8 @@
|
||||
package tls
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
cfgtps "github.com/nabbar/golib/config/types"
|
||||
libver "github.com/nabbar/golib/version"
|
||||
@@ -159,8 +161,8 @@ func (o *componentTls) _runCli() error {
|
||||
|
||||
if cfg, err = o._getConfig(); err != nil {
|
||||
return prt.Error(err)
|
||||
} else if tls, err = cfg.New(); err != nil {
|
||||
return prt.Error(err)
|
||||
} else if tls = cfg.New(); tls == nil {
|
||||
return prt.Error(fmt.Errorf("cannot use tls config for new instance"))
|
||||
} else if o.f != nil {
|
||||
for _, s := range o.f() {
|
||||
tls.AddRootCAString(s)
|
||||
|
@@ -34,7 +34,6 @@ import (
|
||||
libval "github.com/go-playground/validator/v10"
|
||||
libftp "github.com/jlaffaye/ftp"
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
type ConfigTimeZone struct {
|
||||
@@ -81,7 +80,7 @@ type Config struct {
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
if err := libval.New().Struct(c); err != nil {
|
||||
@@ -110,11 +109,11 @@ func (c *Config) RegisterDefaultTLS(fct func() libtls.TLSConfig) {
|
||||
c.ftls = fct
|
||||
}
|
||||
|
||||
func (c *Config) New() (*libftp.ServerConn, liberr.Error) {
|
||||
func (c *Config) New() (*libftp.ServerConn, error) {
|
||||
var opt = make([]libftp.DialOption, 0)
|
||||
|
||||
if tls, err := c.TLS.NewFrom(c.ftls()); err != nil {
|
||||
return nil, err
|
||||
if tls := c.TLS.NewFrom(c.ftls()); tls == nil {
|
||||
return nil, fmt.Errorf("no tls configured")
|
||||
} else if c.ForceTLS {
|
||||
opt = append(opt, libftp.DialWithExplicitTLS(tls.TlsConfig("")))
|
||||
} else {
|
||||
|
@@ -33,46 +33,45 @@ import (
|
||||
"time"
|
||||
|
||||
libftp "github.com/jlaffaye/ftp"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
type FTPClient interface {
|
||||
// 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() liberr.Error
|
||||
Check() error
|
||||
|
||||
// Close send the QUID command to the server if the connection is valid (cf Check).
|
||||
Close()
|
||||
|
||||
// NameList issues an NLST FTP command.
|
||||
NameList(path string) ([]string, liberr.Error)
|
||||
NameList(path string) ([]string, error)
|
||||
|
||||
// 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(path string) liberr.Error
|
||||
ChangeDir(path string) error
|
||||
|
||||
// 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(path string) (int64, liberr.Error)
|
||||
FileSize(path string) (int64, error)
|
||||
|
||||
// GetTime issues the MDTM FTP command to obtain the file modification 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.
|
||||
// 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
|
||||
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.
|
||||
// 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,
|
||||
// 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 creates the specified file with the content of the io.Reader.
|
||||
// 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.
|
||||
// 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.
|
||||
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.
|
||||
// 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.
|
||||
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(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(path string) liberr.Error
|
||||
Delete(path string) error
|
||||
|
||||
// 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(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(path string) liberr.Error
|
||||
RemoveDir(path string) error
|
||||
|
||||
//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{
|
||||
m: sync.Mutex{},
|
||||
cfg: new(atomic.Value),
|
||||
|
@@ -34,7 +34,6 @@ import (
|
||||
"time"
|
||||
|
||||
libftp "github.com/jlaffaye/ftp"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
)
|
||||
|
||||
type ftpClient struct {
|
||||
@@ -96,10 +95,9 @@ func (f *ftpClient) setClient(cli *libftp.ServerConn) {
|
||||
f.cli.Store(cli)
|
||||
}
|
||||
|
||||
func (f *ftpClient) Connect() liberr.Error {
|
||||
func (f *ftpClient) Connect() error {
|
||||
var (
|
||||
e error
|
||||
err liberr.Error
|
||||
cfg *Config
|
||||
cli *libftp.ServerConn
|
||||
)
|
||||
@@ -116,8 +114,8 @@ func (f *ftpClient) Connect() liberr.Error {
|
||||
return ErrorNotInitialized.Error(nil)
|
||||
}
|
||||
|
||||
if cli, err = cfg.New(); err != nil {
|
||||
return err
|
||||
if cli, e = cfg.New(); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
if e = cli.NoOp(); e != nil {
|
||||
@@ -128,7 +126,7 @@ func (f *ftpClient) Connect() liberr.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *ftpClient) Check() liberr.Error {
|
||||
func (f *ftpClient) Check() error {
|
||||
var cli *libftp.ServerConn
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -75,16 +75,13 @@ func (o *dmp) Transport(cfg TransportConfig) *http.Transport {
|
||||
prx = http.ProxyURL(cfg.Proxy)
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
ssl libtls.TLSConfig
|
||||
)
|
||||
var ssl libtls.TLSConfig
|
||||
|
||||
if cfg.TLSConfig == nil {
|
||||
ssl = libtls.New()
|
||||
ssl.SetVersionMin(tls.VersionTLS12)
|
||||
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.SetVersionMin(tls.VersionTLS12)
|
||||
ssl.SetVersionMax(tls.VersionTLS13)
|
||||
|
@@ -37,7 +37,6 @@ import (
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
libdur "github.com/nabbar/golib/duration"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
srvtps "github.com/nabbar/golib/httpserver/types"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
logcfg "github.com/nabbar/golib/logger/config"
|
||||
@@ -210,12 +209,9 @@ func (c *Config) Clone() Config {
|
||||
TLS: libtls.Config{
|
||||
CurveList: c.TLS.CurveList,
|
||||
CipherList: c.TLS.CipherList,
|
||||
RootCAString: c.TLS.RootCAString,
|
||||
RootCAFile: c.TLS.RootCAFile,
|
||||
ClientCAString: c.TLS.ClientCAString,
|
||||
ClientCAFiles: c.TLS.ClientCAFiles,
|
||||
CertPairString: c.TLS.CertPairString,
|
||||
CertPairFile: c.TLS.CertPairFile,
|
||||
RootCA: c.TLS.RootCA,
|
||||
ClientCA: c.TLS.ClientCA,
|
||||
Certs: c.TLS.Certs,
|
||||
VersionMin: c.TLS.VersionMin,
|
||||
VersionMax: c.TLS.VersionMax,
|
||||
AuthClient: c.TLS.AuthClient,
|
||||
@@ -239,17 +235,21 @@ func (c *Config) SetContext(f libctx.FuncContext) {
|
||||
c.getParentContext = f
|
||||
}
|
||||
|
||||
func (c *Config) GetTLS() (libtls.TLSConfig, liberr.Error) {
|
||||
func (c *Config) GetTLS() (libtls.TLSConfig, error) {
|
||||
var def libtls.TLSConfig
|
||||
|
||||
if c.TLS.InheritDefault && c.getTLSDefault != nil {
|
||||
def = c.getTLSDefault()
|
||||
}
|
||||
|
||||
return c.TLS.NewFrom(def)
|
||||
if cfg := c.TLS.NewFrom(def); cfg != nil {
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func (c *Config) CheckTLS() (libtls.TLSConfig, liberr.Error) {
|
||||
return nil, fmt.Errorf("no tls configuration found")
|
||||
}
|
||||
|
||||
func (c *Config) CheckTLS() (libtls.TLSConfig, error) {
|
||||
if ssl, err := c.GetTLS(); err != nil {
|
||||
return nil, err
|
||||
} else if ssl == nil || ssl.LenCertificatePair() < 1 {
|
||||
@@ -337,7 +337,7 @@ func (c *Config) GetHandlerKey() string {
|
||||
return c.HandlerKey
|
||||
}
|
||||
|
||||
func (c *Config) Validate() liberr.Error {
|
||||
func (c *Config) Validate() error {
|
||||
err := ErrorServerValidate.Error(nil)
|
||||
|
||||
if er := libval.New().Struct(c); er != nil {
|
||||
|
@@ -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)
|
||||
|
||||
p.Walk(func(cfg libhtp.Config) bool {
|
||||
var err liberr.Error
|
||||
var err error
|
||||
|
||||
if err = cfg.Validate(); err != nil {
|
||||
e.Add(err)
|
||||
|
@@ -33,7 +33,6 @@ import (
|
||||
|
||||
libval "github.com/go-playground/validator/v10"
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
natcli "github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
@@ -147,7 +146,7 @@ type Client struct {
|
||||
TLSConfig libtls.Config
|
||||
}
|
||||
|
||||
func (c Client) Validate() liberr.Error {
|
||||
func (c Client) Validate() error {
|
||||
err := ErrorConfigValidation.Error(nil)
|
||||
|
||||
if er := libval.New().Struct(c); er != nil {
|
||||
@@ -168,7 +167,7 @@ func (c Client) Validate() liberr.Error {
|
||||
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()
|
||||
|
||||
if c.Url != "" {
|
||||
@@ -273,8 +272,8 @@ func (c Client) NewClient(defTls libtls.TLSConfig) (*natcli.Conn, liberr.Error)
|
||||
}
|
||||
|
||||
if c.Secure {
|
||||
if t, e := c.TLSConfig.NewFrom(defTls); e != nil {
|
||||
return nil, e
|
||||
if t := c.TLSConfig.NewFrom(defTls); t == nil {
|
||||
return nil, fmt.Errorf("no valid tls configuration")
|
||||
} else {
|
||||
opts.TLSConfig = t.TlsConfig("")
|
||||
}
|
||||
|
@@ -38,7 +38,6 @@ import (
|
||||
|
||||
libval "github.com/go-playground/validator/v10"
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libiot "github.com/nabbar/golib/ioutils"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
loglvl "github.com/nabbar/golib/logger/level"
|
||||
@@ -63,7 +62,7 @@ type Config struct {
|
||||
Customs *ConfigCustom `mapstructure:"-" json:"-" yaml:"-" toml:"-"`
|
||||
}
|
||||
|
||||
func (c Config) Validate() liberr.Error {
|
||||
func (c Config) Validate() error {
|
||||
err := ErrorConfigValidation.Error(nil)
|
||||
|
||||
if er := libval.New().Struct(c); er != nil {
|
||||
@@ -84,7 +83,7 @@ func (c Config) Validate() liberr.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Config) LogConfigJson() liberr.Error {
|
||||
func (c Config) LogConfigJson() error {
|
||||
if c.Logs.LogFile == "" {
|
||||
return nil
|
||||
}
|
||||
@@ -129,7 +128,7 @@ func (c Config) LogConfigJson() liberr.Error {
|
||||
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{
|
||||
CheckConfig: false,
|
||||
}
|
||||
@@ -187,7 +186,7 @@ func (c Config) NatsOption(defaultTls libtls.TLSConfig, log liblog.Logger) (*nat
|
||||
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 {
|
||||
return ErrorParamsInvalid.Error(nil)
|
||||
}
|
||||
@@ -209,8 +208,8 @@ func (c *ConfigCustom) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) lib
|
||||
}
|
||||
|
||||
if c.AccountResolverTLS {
|
||||
if t, e := c.AccountResolverTLSConfig.NewFrom(defTls); e != nil {
|
||||
return e
|
||||
if t := c.AccountResolverTLSConfig.NewFrom(defTls); t == nil {
|
||||
return fmt.Errorf("no valid tls config")
|
||||
} else {
|
||||
cfg.AccountResolverTLSConfig = t.TlsConfig("")
|
||||
}
|
||||
@@ -221,7 +220,7 @@ func (c *ConfigCustom) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) lib
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c ConfigAuth) makeOpt(cfg *natsrv.Options) liberr.Error {
|
||||
func (c ConfigAuth) makeOpt(cfg *natsrv.Options) error {
|
||||
if cfg == nil {
|
||||
return ErrorParamsInvalid.Error(nil)
|
||||
}
|
||||
@@ -285,7 +284,7 @@ func (c ConfigAuth) makeOpt(cfg *natsrv.Options) liberr.Error {
|
||||
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 {
|
||||
return nil, ErrorParamsInvalid.Error(nil)
|
||||
}
|
||||
@@ -342,7 +341,7 @@ func (c ConfigNkey) makeOpt(auth ConfigAuth, cfg *natsrv.Options) (*natsrv.NkeyU
|
||||
}, 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 {
|
||||
return nil, ErrorParamsInvalid.Error(nil)
|
||||
}
|
||||
@@ -473,7 +472,7 @@ func (c ConfigPermissionResponse) makeOpt() *natsrv.ResponsePermission {
|
||||
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 {
|
||||
return ErrorParamsInvalid.Error(nil)
|
||||
}
|
||||
@@ -540,7 +539,7 @@ func (c ConfigLogger) makeOpt(log liblog.Logger, cfg *natsrv.Options) liberr.Err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c ConfigLimits) makeOpt(cfg *natsrv.Options) liberr.Error {
|
||||
func (c ConfigLimits) makeOpt(cfg *natsrv.Options) error {
|
||||
if cfg == nil {
|
||||
return ErrorParamsInvalid.Error(nil)
|
||||
}
|
||||
@@ -604,7 +603,7 @@ func (c ConfigLimits) makeOpt(cfg *natsrv.Options) liberr.Error {
|
||||
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 {
|
||||
return ErrorParamsInvalid.Error(nil)
|
||||
}
|
||||
@@ -733,8 +732,8 @@ func (c ConfigSrv) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) liberr.
|
||||
if c.TLS {
|
||||
cfg.TLS = true
|
||||
|
||||
if t, e := c.TLSConfig.NewFrom(defTls); e != nil {
|
||||
return e
|
||||
if t := c.TLSConfig.NewFrom(defTls); t == nil {
|
||||
return fmt.Errorf("no valid tls config")
|
||||
} else {
|
||||
cfg.TLSConfig = t.TlsConfig("")
|
||||
}
|
||||
@@ -757,7 +756,7 @@ func (c ConfigSrv) makeOpt(cfg *natsrv.Options, defTls libtls.TLSConfig) liberr.
|
||||
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{
|
||||
Name: c.Name,
|
||||
Host: c.Host,
|
||||
@@ -786,8 +785,8 @@ func (c ConfigCluster) makeOpt(defTls libtls.TLSConfig) (natsrv.ClusterOpts, lib
|
||||
}
|
||||
|
||||
if c.TLS {
|
||||
if t, e := c.TLSConfig.NewFrom(defTls); e != nil {
|
||||
return cfg, e
|
||||
if t := c.TLSConfig.NewFrom(defTls); t == nil {
|
||||
return cfg, fmt.Errorf("no valid tls config")
|
||||
} else {
|
||||
cfg.TLSConfig = t.TlsConfig("")
|
||||
}
|
||||
@@ -803,7 +802,7 @@ func (c ConfigCluster) makeOpt(defTls libtls.TLSConfig) (natsrv.ClusterOpts, lib
|
||||
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{
|
||||
Name: c.Name,
|
||||
Host: c.Host,
|
||||
@@ -826,8 +825,8 @@ func (c ConfigGateway) makeOpt(defTls libtls.TLSConfig) (natsrv.GatewayOpts, lib
|
||||
}
|
||||
|
||||
if c.TLS {
|
||||
if t, e := c.TLSConfig.NewFrom(defTls); e != nil {
|
||||
return cfg, e
|
||||
if t := c.TLSConfig.NewFrom(defTls); t == nil {
|
||||
return cfg, fmt.Errorf("no valid tls config")
|
||||
} else {
|
||||
cfg.TLSConfig = t.TlsConfig("")
|
||||
}
|
||||
@@ -850,7 +849,7 @@ func (c ConfigGateway) makeOpt(defTls libtls.TLSConfig) (natsrv.GatewayOpts, lib
|
||||
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{
|
||||
Name: "",
|
||||
TLSConfig: nil,
|
||||
@@ -863,8 +862,8 @@ func (c ConfigGatewayRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteGat
|
||||
}
|
||||
|
||||
if c.TLS {
|
||||
if t, e := c.TLSConfig.NewFrom(defTls); e != nil {
|
||||
return nil, e
|
||||
if t := c.TLSConfig.NewFrom(defTls); t == nil {
|
||||
return nil, fmt.Errorf("no valid tls config")
|
||||
} else {
|
||||
res.TLSConfig = t.TlsConfig("")
|
||||
}
|
||||
@@ -891,7 +890,7 @@ func (c ConfigGatewayRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteGat
|
||||
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{
|
||||
Host: c.Host,
|
||||
Port: c.Port,
|
||||
@@ -924,8 +923,8 @@ func (c ConfigLeaf) makeOpt(cfg *natsrv.Options, auth ConfigAuth, defTls libtls.
|
||||
}
|
||||
|
||||
if c.TLS {
|
||||
if t, e := c.TLSConfig.NewFrom(defTls); e != nil {
|
||||
return res, e
|
||||
if t := c.TLSConfig.NewFrom(defTls); t == nil {
|
||||
return res, fmt.Errorf("no valid tls config")
|
||||
} else {
|
||||
res.TLSConfig = t.TlsConfig("")
|
||||
}
|
||||
@@ -951,7 +950,7 @@ func (c ConfigLeaf) makeOpt(cfg *natsrv.Options, auth ConfigAuth, defTls libtls.
|
||||
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{
|
||||
LocalAccount: c.LocalAccount,
|
||||
URLs: make([]*url.URL, 0),
|
||||
@@ -974,8 +973,8 @@ func (c ConfigLeafRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteLeafOp
|
||||
if c.TLS {
|
||||
res.TLS = true
|
||||
|
||||
if t, e := c.TLSConfig.NewFrom(defTls); e != nil {
|
||||
return nil, e
|
||||
if t := c.TLSConfig.NewFrom(defTls); t == nil {
|
||||
return nil, fmt.Errorf("no valid tls config")
|
||||
} else {
|
||||
res.TLSConfig = t.TlsConfig("")
|
||||
}
|
||||
@@ -1009,7 +1008,7 @@ func (c ConfigLeafRemote) makeOpt(defTls libtls.TLSConfig) (*natsrv.RemoteLeafOp
|
||||
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{
|
||||
Host: c.Host,
|
||||
Port: c.Port,
|
||||
@@ -1044,8 +1043,8 @@ func (c ConfigWebsocket) makeOpt(defTls libtls.TLSConfig) (natsrv.WebsocketOpts,
|
||||
if !c.NoTLS {
|
||||
cfg.NoTLS = false
|
||||
|
||||
if t, e := c.TLSConfig.NewFrom(defTls); e != nil {
|
||||
return cfg, e
|
||||
if t := c.TLSConfig.NewFrom(defTls); t == nil {
|
||||
return cfg, fmt.Errorf("no valid tls config")
|
||||
} else {
|
||||
cfg.TLSConfig = t.TlsConfig("")
|
||||
}
|
||||
@@ -1063,7 +1062,7 @@ func (c ConfigWebsocket) makeOpt(defTls libtls.TLSConfig) (natsrv.WebsocketOpts,
|
||||
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{
|
||||
Host: c.Host,
|
||||
Port: c.Port,
|
||||
@@ -1084,8 +1083,8 @@ func (c ConfigMQTT) makeOpt(defTls libtls.TLSConfig) (natsrv.MQTTOpts, liberr.Er
|
||||
}
|
||||
|
||||
if !c.TLS {
|
||||
if t, e := c.TLSConfig.NewFrom(defTls); e != nil {
|
||||
return cfg, e
|
||||
if t := c.TLSConfig.NewFrom(defTls); t == nil {
|
||||
return cfg, fmt.Errorf("no valid tls config")
|
||||
} else {
|
||||
cfg.TLSConfig = t.TlsConfig("")
|
||||
}
|
||||
|
@@ -37,7 +37,6 @@ import (
|
||||
|
||||
libtls "github.com/nabbar/golib/certificates"
|
||||
libctx "github.com/nabbar/golib/context"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
montps "github.com/nabbar/golib/monitor/types"
|
||||
libver "github.com/nabbar/golib/version"
|
||||
natsrv "github.com/nats-io/nats-server/v2/server"
|
||||
@@ -50,8 +49,8 @@ const (
|
||||
)
|
||||
|
||||
type Server interface {
|
||||
Listen(ctx context.Context) liberr.Error
|
||||
Restart(ctx context.Context) liberr.Error
|
||||
Listen(ctx context.Context) error
|
||||
Restart(ctx context.Context) error
|
||||
Shutdown()
|
||||
|
||||
GetOptions() *natsrv.Options
|
||||
@@ -62,9 +61,9 @@ type Server interface {
|
||||
IsReadyTimeout(parent context.Context, dur time.Duration) bool
|
||||
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)
|
||||
ClientCluster(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 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 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)
|
||||
}
|
||||
@@ -89,11 +88,11 @@ type server struct {
|
||||
o *atomic.Value
|
||||
s *atomic.Value
|
||||
r *atomic.Value
|
||||
e liberr.Error
|
||||
e error
|
||||
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() {
|
||||
s.Shutdown()
|
||||
}
|
||||
@@ -123,7 +122,7 @@ func (s *server) Listen(ctx context.Context) liberr.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) Restart(ctx context.Context) liberr.Error {
|
||||
func (s *server) Restart(ctx context.Context) error {
|
||||
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 != "" {
|
||||
opt.Url = s._FormatAddress(o.ClientAdvertise)
|
||||
} else {
|
||||
@@ -222,7 +221,7 @@ func (s *server) ClientAdvertise(ctx context.Context, tick time.Duration, 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)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
if o = s.GetOptions(); o == nil {
|
||||
@@ -290,14 +289,14 @@ func (s *server) _SetServer(srv *natsrv.Server) {
|
||||
s.s.Store(srv)
|
||||
}
|
||||
|
||||
func (s *server) _GetError() liberr.Error {
|
||||
func (s *server) _GetError() error {
|
||||
s.m.Lock()
|
||||
defer s.m.Unlock()
|
||||
|
||||
return s.e
|
||||
}
|
||||
|
||||
func (s *server) _SetError(err liberr.Error) {
|
||||
func (s *server) _SetError(err error) {
|
||||
s.m.Lock()
|
||||
defer s.m.Unlock()
|
||||
|
||||
|
Reference in New Issue
Block a user