forked from TrueCloudLab/certificates
Move TLSOption, TLSVersion, CipherSuites and ASN1DN to certificates.
This commit is contained in:
parent
77624c6b1c
commit
4943ae58d8
12 changed files with 384 additions and 55 deletions
|
@ -23,7 +23,6 @@ import (
|
|||
"github.com/smallstep/certificates/authority/provisioner"
|
||||
"github.com/smallstep/certificates/errs"
|
||||
"github.com/smallstep/certificates/logging"
|
||||
"github.com/smallstep/cli/crypto/tlsutil"
|
||||
)
|
||||
|
||||
// Authority is the interface implemented by a CA authority.
|
||||
|
@ -32,7 +31,7 @@ type Authority interface {
|
|||
// context specifies the Authorize[Sign|Revoke|etc.] method.
|
||||
Authorize(ctx context.Context, ott string) ([]provisioner.SignOption, error)
|
||||
AuthorizeSign(ott string) ([]provisioner.SignOption, error)
|
||||
GetTLSOptions() *tlsutil.TLSOptions
|
||||
GetTLSOptions() *authority.TLSOptions
|
||||
Root(shasum string) (*x509.Certificate, error)
|
||||
Sign(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error)
|
||||
Renew(peer *x509.Certificate) ([]*x509.Certificate, error)
|
||||
|
|
|
@ -32,7 +32,6 @@ import (
|
|||
"github.com/smallstep/certificates/errs"
|
||||
"github.com/smallstep/certificates/logging"
|
||||
"github.com/smallstep/certificates/templates"
|
||||
"github.com/smallstep/cli/crypto/tlsutil"
|
||||
"github.com/smallstep/cli/jose"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
@ -547,7 +546,7 @@ type mockAuthority struct {
|
|||
ret1, ret2 interface{}
|
||||
err error
|
||||
authorizeSign func(ott string) ([]provisioner.SignOption, error)
|
||||
getTLSOptions func() *tlsutil.TLSOptions
|
||||
getTLSOptions func() *authority.TLSOptions
|
||||
root func(shasum string) (*x509.Certificate, error)
|
||||
sign func(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error)
|
||||
renew func(cert *x509.Certificate) ([]*x509.Certificate, error)
|
||||
|
@ -584,11 +583,11 @@ func (m *mockAuthority) AuthorizeSign(ott string) ([]provisioner.SignOption, err
|
|||
return m.ret1.([]provisioner.SignOption), m.err
|
||||
}
|
||||
|
||||
func (m *mockAuthority) GetTLSOptions() *tlsutil.TLSOptions {
|
||||
func (m *mockAuthority) GetTLSOptions() *authority.TLSOptions {
|
||||
if m.getTLSOptions != nil {
|
||||
return m.getTLSOptions()
|
||||
}
|
||||
return m.ret1.(*tlsutil.TLSOptions)
|
||||
return m.ret1.(*authority.TLSOptions)
|
||||
}
|
||||
|
||||
func (m *mockAuthority) Root(shasum string) (*x509.Certificate, error) {
|
||||
|
@ -881,7 +880,7 @@ func Test_caHandler_Sign(t *testing.T) {
|
|||
authorizeSign: func(ott string) ([]provisioner.SignOption, error) {
|
||||
return tt.certAttrOpts, tt.autherr
|
||||
},
|
||||
getTLSOptions: func() *tlsutil.TLSOptions {
|
||||
getTLSOptions: func() *authority.TLSOptions {
|
||||
return nil
|
||||
},
|
||||
}).(*caHandler)
|
||||
|
@ -932,7 +931,7 @@ func Test_caHandler_Renew(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := New(&mockAuthority{
|
||||
ret1: tt.cert, ret2: tt.root, err: tt.err,
|
||||
getTLSOptions: func() *tlsutil.TLSOptions {
|
||||
getTLSOptions: func() *authority.TLSOptions {
|
||||
return nil
|
||||
},
|
||||
}).(*caHandler)
|
||||
|
@ -993,7 +992,7 @@ func Test_caHandler_Rekey(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := New(&mockAuthority{
|
||||
ret1: tt.cert, ret2: tt.root, err: tt.err,
|
||||
getTLSOptions: func() *tlsutil.TLSOptions {
|
||||
getTLSOptions: func() *authority.TLSOptions {
|
||||
return nil
|
||||
},
|
||||
}).(*caHandler)
|
||||
|
|
12
api/sign.go
12
api/sign.go
|
@ -5,9 +5,9 @@ import (
|
|||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/smallstep/certificates/authority"
|
||||
"github.com/smallstep/certificates/authority/provisioner"
|
||||
"github.com/smallstep/certificates/errs"
|
||||
"github.com/smallstep/cli/crypto/tlsutil"
|
||||
)
|
||||
|
||||
// SignRequest is the request body for a certificate signature request.
|
||||
|
@ -37,11 +37,11 @@ func (s *SignRequest) Validate() error {
|
|||
|
||||
// SignResponse is the response object of the certificate signature request.
|
||||
type SignResponse struct {
|
||||
ServerPEM Certificate `json:"crt"`
|
||||
CaPEM Certificate `json:"ca"`
|
||||
CertChainPEM []Certificate `json:"certChain"`
|
||||
TLSOptions *tlsutil.TLSOptions `json:"tlsOptions,omitempty"`
|
||||
TLS *tls.ConnectionState `json:"-"`
|
||||
ServerPEM Certificate `json:"crt"`
|
||||
CaPEM Certificate `json:"ca"`
|
||||
CertChainPEM []Certificate `json:"certChain"`
|
||||
TLSOptions *authority.TLSOptions `json:"tlsOptions,omitempty"`
|
||||
TLS *tls.ConnectionState `json:"-"`
|
||||
}
|
||||
|
||||
// Sign is an HTTP handler that reads a certificate request and an
|
||||
|
|
|
@ -12,15 +12,13 @@ import (
|
|||
"github.com/smallstep/certificates/db"
|
||||
kms "github.com/smallstep/certificates/kms/apiv1"
|
||||
"github.com/smallstep/certificates/templates"
|
||||
"github.com/smallstep/cli/crypto/tlsutil"
|
||||
"github.com/smallstep/cli/crypto/x509util"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultTLSOptions represents the default TLS version as well as the cipher
|
||||
// suites used in the TLS certificates.
|
||||
DefaultTLSOptions = tlsutil.TLSOptions{
|
||||
CipherSuites: x509util.CipherSuites{
|
||||
DefaultTLSOptions = TLSOptions{
|
||||
CipherSuites: CipherSuites{
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
|
@ -61,15 +59,27 @@ type Config struct {
|
|||
DB *db.Config `json:"db,omitempty"`
|
||||
Monitoring json.RawMessage `json:"monitoring,omitempty"`
|
||||
AuthorityConfig *AuthConfig `json:"authority,omitempty"`
|
||||
TLS *tlsutil.TLSOptions `json:"tls,omitempty"`
|
||||
TLS *TLSOptions `json:"tls,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Templates *templates.Templates `json:"templates,omitempty"`
|
||||
}
|
||||
|
||||
// ASN1DN contains ASN1.DN attributes that are used in Subject and Issuer
|
||||
// x509 Certificate blocks.
|
||||
type ASN1DN struct {
|
||||
Country string `json:"country,omitempty" step:"country"`
|
||||
Organization string `json:"organization,omitempty" step:"organization"`
|
||||
OrganizationalUnit string `json:"organizationalUnit,omitempty" step:"organizationalUnit"`
|
||||
Locality string `json:"locality,omitempty" step:"locality"`
|
||||
Province string `json:"province,omitempty" step:"province"`
|
||||
StreetAddress string `json:"streetAddress,omitempty" step:"streetAddress"`
|
||||
CommonName string `json:"commonName,omitempty" step:"commonName"`
|
||||
}
|
||||
|
||||
// AuthConfig represents the configuration options for the authority.
|
||||
type AuthConfig struct {
|
||||
Provisioners provisioner.List `json:"provisioners"`
|
||||
Template *x509util.ASN1DN `json:"template,omitempty"`
|
||||
Template *ASN1DN `json:"template,omitempty"`
|
||||
Claims *provisioner.Claims `json:"claims,omitempty"`
|
||||
DisableIssuedAtCheck bool `json:"disableIssuedAtCheck,omitempty"`
|
||||
Backdate *provisioner.Duration `json:"backdate,omitempty"`
|
||||
|
@ -82,7 +92,7 @@ func (c *AuthConfig) init() {
|
|||
c.Provisioners = provisioner.List{}
|
||||
}
|
||||
if c.Template == nil {
|
||||
c.Template = &x509util.ASN1DN{}
|
||||
c.Template = &ASN1DN{}
|
||||
}
|
||||
if c.Backdate == nil {
|
||||
c.Backdate = &provisioner.Duration{
|
||||
|
|
|
@ -7,8 +7,6 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"github.com/smallstep/assert"
|
||||
"github.com/smallstep/certificates/authority/provisioner"
|
||||
"github.com/smallstep/cli/crypto/tlsutil"
|
||||
"github.com/smallstep/cli/crypto/x509util"
|
||||
stepJOSE "github.com/smallstep/cli/jose"
|
||||
)
|
||||
|
||||
|
@ -35,7 +33,7 @@ func TestConfigValidate(t *testing.T) {
|
|||
type ConfigValidateTest struct {
|
||||
config *Config
|
||||
err error
|
||||
tls tlsutil.TLSOptions
|
||||
tls TLSOptions
|
||||
}
|
||||
tests := map[string]func(*testing.T) ConfigValidateTest{
|
||||
"empty-address": func(t *testing.T) ConfigValidateTest {
|
||||
|
@ -141,7 +139,7 @@ func TestConfigValidate(t *testing.T) {
|
|||
DNSNames: []string{"test.smallstep.com"},
|
||||
Password: "pass",
|
||||
AuthorityConfig: ac,
|
||||
TLS: &tlsutil.TLSOptions{},
|
||||
TLS: &TLSOptions{},
|
||||
},
|
||||
tls: DefaultTLSOptions,
|
||||
}
|
||||
|
@ -156,8 +154,8 @@ func TestConfigValidate(t *testing.T) {
|
|||
DNSNames: []string{"test.smallstep.com"},
|
||||
Password: "pass",
|
||||
AuthorityConfig: ac,
|
||||
TLS: &tlsutil.TLSOptions{
|
||||
CipherSuites: x509util.CipherSuites{
|
||||
TLS: &TLSOptions{
|
||||
CipherSuites: CipherSuites{
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
},
|
||||
MinVersion: 1.0,
|
||||
|
@ -165,8 +163,8 @@ func TestConfigValidate(t *testing.T) {
|
|||
Renegotiation: true,
|
||||
},
|
||||
},
|
||||
tls: tlsutil.TLSOptions{
|
||||
CipherSuites: x509util.CipherSuites{
|
||||
tls: TLSOptions{
|
||||
CipherSuites: CipherSuites{
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
},
|
||||
MinVersion: 1.0,
|
||||
|
@ -185,8 +183,8 @@ func TestConfigValidate(t *testing.T) {
|
|||
DNSNames: []string{"test.smallstep.com"},
|
||||
Password: "pass",
|
||||
AuthorityConfig: ac,
|
||||
TLS: &tlsutil.TLSOptions{
|
||||
CipherSuites: x509util.CipherSuites{
|
||||
TLS: &TLSOptions{
|
||||
CipherSuites: CipherSuites{
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
},
|
||||
MinVersion: 1.2,
|
||||
|
@ -217,7 +215,7 @@ func TestConfigValidate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAuthConfigValidate(t *testing.T) {
|
||||
asn1dn := x509util.ASN1DN{
|
||||
asn1dn := ASN1DN{
|
||||
Country: "Tazmania",
|
||||
Organization: "Acme Co",
|
||||
Locality: "Landscapes",
|
||||
|
@ -245,7 +243,7 @@ func TestAuthConfigValidate(t *testing.T) {
|
|||
|
||||
type AuthConfigValidateTest struct {
|
||||
ac *AuthConfig
|
||||
asn1dn x509util.ASN1DN
|
||||
asn1dn ASN1DN
|
||||
err error
|
||||
}
|
||||
tests := map[string]func(*testing.T) AuthConfigValidateTest{
|
||||
|
@ -258,7 +256,7 @@ func TestAuthConfigValidate(t *testing.T) {
|
|||
"ok-empty-provisioners": func(t *testing.T) AuthConfigValidateTest {
|
||||
return AuthConfigValidateTest{
|
||||
ac: &AuthConfig{},
|
||||
asn1dn: x509util.ASN1DN{},
|
||||
asn1dn: ASN1DN{},
|
||||
}
|
||||
},
|
||||
"ok-empty-asn1dn-template": func(t *testing.T) AuthConfigValidateTest {
|
||||
|
@ -266,7 +264,7 @@ func TestAuthConfigValidate(t *testing.T) {
|
|||
ac: &AuthConfig{
|
||||
Provisioners: p,
|
||||
},
|
||||
asn1dn: x509util.ASN1DN{},
|
||||
asn1dn: ASN1DN{},
|
||||
}
|
||||
},
|
||||
"ok-custom-asn1dn": func(t *testing.T) AuthConfigValidateTest {
|
||||
|
|
|
@ -17,21 +17,20 @@ import (
|
|||
"github.com/smallstep/certificates/db"
|
||||
"github.com/smallstep/certificates/errs"
|
||||
"github.com/smallstep/cli/crypto/pemutil"
|
||||
"github.com/smallstep/cli/crypto/tlsutil"
|
||||
x509legacy "github.com/smallstep/cli/crypto/x509util"
|
||||
"github.com/smallstep/cli/jose"
|
||||
"go.step.sm/crypto/x509util"
|
||||
)
|
||||
|
||||
// GetTLSOptions returns the tls options configured.
|
||||
func (a *Authority) GetTLSOptions() *tlsutil.TLSOptions {
|
||||
func (a *Authority) GetTLSOptions() *TLSOptions {
|
||||
return a.config.TLS
|
||||
}
|
||||
|
||||
var oidAuthorityKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 35}
|
||||
var oidSubjectKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 14}
|
||||
|
||||
func withDefaultASN1DN(def *x509legacy.ASN1DN) provisioner.CertificateModifierFunc {
|
||||
func withDefaultASN1DN(def *ASN1DN) provisioner.CertificateModifierFunc {
|
||||
return func(crt *x509.Certificate, opts provisioner.SignOptions) error {
|
||||
if def == nil {
|
||||
return errors.New("default ASN1DN template cannot be nil")
|
||||
|
|
157
authority/tls_options.go
Normal file
157
authority/tls_options.go
Normal file
|
@ -0,0 +1,157 @@
|
|||
package authority
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultTLSMinVersion default minimum version of TLS.
|
||||
DefaultTLSMinVersion = TLSVersion(1.2)
|
||||
// DefaultTLSMaxVersion default maximum version of TLS.
|
||||
DefaultTLSMaxVersion = TLSVersion(1.3)
|
||||
// DefaultTLSRenegotiation default TLS connection renegotiation policy.
|
||||
DefaultTLSRenegotiation = false // Never regnegotiate.
|
||||
// DefaultTLSCipherSuites specifies default step ciphersuite(s).
|
||||
DefaultTLSCipherSuites = CipherSuites{
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
}
|
||||
// ApprovedTLSCipherSuites smallstep approved ciphersuites.
|
||||
ApprovedTLSCipherSuites = CipherSuites{
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
|
||||
}
|
||||
)
|
||||
|
||||
// TLSVersion represents a TLS version number.
|
||||
type TLSVersion float64
|
||||
|
||||
// Validate implements models.Validator and checks that a cipher suite is
|
||||
// valid.
|
||||
func (v TLSVersion) Validate() error {
|
||||
if _, ok := tlsVersions[v]; ok {
|
||||
return nil
|
||||
}
|
||||
return errors.Errorf("%f is not a valid tls version", v)
|
||||
}
|
||||
|
||||
// Value returns the Go constant for the TLSVersion.
|
||||
func (v TLSVersion) Value() uint16 {
|
||||
return tlsVersions[v]
|
||||
}
|
||||
|
||||
// String returns the Go constant for the TLSVersion.
|
||||
func (v TLSVersion) String() string {
|
||||
k := v.Value()
|
||||
switch k {
|
||||
case tls.VersionTLS10:
|
||||
return "1.0"
|
||||
case tls.VersionTLS11:
|
||||
return "1.1"
|
||||
case tls.VersionTLS12:
|
||||
return "1.2"
|
||||
case tls.VersionTLS13:
|
||||
return "1.3"
|
||||
default:
|
||||
return fmt.Sprintf("unexpected value: %f", v)
|
||||
}
|
||||
}
|
||||
|
||||
// tlsVersions has the list of supported tls version.
|
||||
var tlsVersions = map[TLSVersion]uint16{
|
||||
// Defaults to TLS 1.3
|
||||
0: tls.VersionTLS13,
|
||||
// Options
|
||||
1.0: tls.VersionTLS10,
|
||||
1.1: tls.VersionTLS11,
|
||||
1.2: tls.VersionTLS12,
|
||||
1.3: tls.VersionTLS13,
|
||||
}
|
||||
|
||||
// CipherSuites represents an array of string codes representing the cipher
|
||||
// suites.
|
||||
type CipherSuites []string
|
||||
|
||||
// Validate implements models.Validator and checks that a cipher suite is
|
||||
// valid.
|
||||
func (c CipherSuites) Validate() error {
|
||||
for _, s := range c {
|
||||
if _, ok := cipherSuites[s]; !ok {
|
||||
return errors.Errorf("%s is not a valid cipher suite", s)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value returns an []uint16 for the cipher suites.
|
||||
func (c CipherSuites) Value() []uint16 {
|
||||
values := make([]uint16, len(c))
|
||||
for i, s := range c {
|
||||
values[i] = cipherSuites[s]
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// cipherSuites has the list of supported cipher suites.
|
||||
var cipherSuites = map[string]uint16{
|
||||
"TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
|
||||
}
|
||||
|
||||
// TLSOptions represents the TLS options that can be specified on *tls.Config
|
||||
// types to configure HTTPS servers and clients.
|
||||
type TLSOptions struct {
|
||||
CipherSuites CipherSuites `json:"cipherSuites"`
|
||||
MinVersion TLSVersion `json:"minVersion"`
|
||||
MaxVersion TLSVersion `json:"maxVersion"`
|
||||
Renegotiation bool `json:"renegotiation"`
|
||||
}
|
||||
|
||||
// TLSConfig returns the tls.Config equivalent of the TLSOptions.
|
||||
func (t *TLSOptions) TLSConfig() *tls.Config {
|
||||
var rs tls.RenegotiationSupport
|
||||
if t.Renegotiation {
|
||||
rs = tls.RenegotiateFreelyAsClient
|
||||
} else {
|
||||
rs = tls.RenegotiateNever
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
CipherSuites: t.CipherSuites.Value(),
|
||||
MinVersion: t.MinVersion.Value(),
|
||||
MaxVersion: t.MaxVersion.Value(),
|
||||
Renegotiation: rs,
|
||||
}
|
||||
}
|
169
authority/tls_options_test.go
Normal file
169
authority/tls_options_test.go
Normal file
|
@ -0,0 +1,169 @@
|
|||
package authority
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTLSVersion_Validate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
v TLSVersion
|
||||
wantErr bool
|
||||
}{
|
||||
{"default", TLSVersion(0), false},
|
||||
{"1.0", TLSVersion(1.0), false},
|
||||
{"1.1", TLSVersion(1.1), false},
|
||||
{"1.2", TLSVersion(1.2), false},
|
||||
{"1.3", TLSVersion(1.3), false},
|
||||
{"0.99", TLSVersion(0.99), true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := tt.v.Validate(); (err != nil) != tt.wantErr {
|
||||
t.Errorf("TLSVersion.Validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSVersion_String(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
v TLSVersion
|
||||
want string
|
||||
}{
|
||||
{"default", TLSVersion(0), "1.3"},
|
||||
{"1.0", TLSVersion(1.0), "1.0"},
|
||||
{"1.1", TLSVersion(1.1), "1.1"},
|
||||
{"1.2", TLSVersion(1.2), "1.2"},
|
||||
{"1.3", TLSVersion(1.3), "1.3"},
|
||||
{"0.99", TLSVersion(0.99), "unexpected value: 0.990000"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.v.String(); got != tt.want {
|
||||
t.Errorf("TLSVersion.String() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCipherSuites_Validate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
c CipherSuites
|
||||
wantErr bool
|
||||
}{
|
||||
{"TLS_RSA_WITH_RC4_128_SHA", CipherSuites{"TLS_RSA_WITH_RC4_128_SHA"}, false},
|
||||
{"TLS_RSA_WITH_3DES_EDE_CBC_SHA", CipherSuites{"TLS_RSA_WITH_3DES_EDE_CBC_SHA"}, false},
|
||||
{"TLS_RSA_WITH_AES_128_CBC_SHA", CipherSuites{"TLS_RSA_WITH_AES_128_CBC_SHA"}, false},
|
||||
{"TLS_RSA_WITH_AES_256_CBC_SHA", CipherSuites{"TLS_RSA_WITH_AES_256_CBC_SHA"}, false},
|
||||
{"TLS_RSA_WITH_AES_128_CBC_SHA256", CipherSuites{"TLS_RSA_WITH_AES_128_CBC_SHA256"}, false},
|
||||
{"TLS_RSA_WITH_AES_128_GCM_SHA256", CipherSuites{"TLS_RSA_WITH_AES_128_GCM_SHA256"}, false},
|
||||
{"TLS_RSA_WITH_AES_256_GCM_SHA384", CipherSuites{"TLS_RSA_WITH_AES_256_GCM_SHA384"}, false},
|
||||
{"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", CipherSuites{"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"}, false},
|
||||
{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", CipherSuites{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"}, false},
|
||||
{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", CipherSuites{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"}, false},
|
||||
{"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", CipherSuites{"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"}, false},
|
||||
{"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", CipherSuites{"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"}, false},
|
||||
{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", CipherSuites{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"}, false},
|
||||
{"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", CipherSuites{"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"}, false},
|
||||
{"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", CipherSuites{"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"}, false},
|
||||
{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", CipherSuites{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"}, false},
|
||||
{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", CipherSuites{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"}, false},
|
||||
{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", CipherSuites{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"}, false},
|
||||
{"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", CipherSuites{"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"}, false},
|
||||
{"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", CipherSuites{"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"}, false},
|
||||
{"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", CipherSuites{"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"}, false},
|
||||
{"multiple", CipherSuites{"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"}, false},
|
||||
{"fail", CipherSuites{"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", "TLS_BAD_CIPHERSUITE"}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := tt.c.Validate(); (err != nil) != tt.wantErr {
|
||||
t.Errorf("CipherSuites.Validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCipherSuites_Value(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
c CipherSuites
|
||||
want []uint16
|
||||
}{
|
||||
{"TLS_RSA_WITH_RC4_128_SHA", CipherSuites{"TLS_RSA_WITH_RC4_128_SHA"}, []uint16{tls.TLS_RSA_WITH_RC4_128_SHA}},
|
||||
{"TLS_RSA_WITH_3DES_EDE_CBC_SHA", CipherSuites{"TLS_RSA_WITH_3DES_EDE_CBC_SHA"}, []uint16{tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA}},
|
||||
{"TLS_RSA_WITH_AES_128_CBC_SHA", CipherSuites{"TLS_RSA_WITH_AES_128_CBC_SHA"}, []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA}},
|
||||
{"TLS_RSA_WITH_AES_256_CBC_SHA", CipherSuites{"TLS_RSA_WITH_AES_256_CBC_SHA"}, []uint16{tls.TLS_RSA_WITH_AES_256_CBC_SHA}},
|
||||
{"TLS_RSA_WITH_AES_128_CBC_SHA256", CipherSuites{"TLS_RSA_WITH_AES_128_CBC_SHA256"}, []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA256}},
|
||||
{"TLS_RSA_WITH_AES_128_GCM_SHA256", CipherSuites{"TLS_RSA_WITH_AES_128_GCM_SHA256"}, []uint16{tls.TLS_RSA_WITH_AES_128_GCM_SHA256}},
|
||||
{"TLS_RSA_WITH_AES_256_GCM_SHA384", CipherSuites{"TLS_RSA_WITH_AES_256_GCM_SHA384"}, []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384}},
|
||||
{"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", CipherSuites{"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"}, []uint16{tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA}},
|
||||
{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", CipherSuites{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"}, []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA}},
|
||||
{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", CipherSuites{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"}, []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256}},
|
||||
{"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", CipherSuites{"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"}, []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}},
|
||||
{"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", CipherSuites{"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"}, []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}},
|
||||
{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", CipherSuites{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"}, []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384}},
|
||||
{"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", CipherSuites{"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"}, []uint16{tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305}},
|
||||
{"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", CipherSuites{"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"}, []uint16{tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}},
|
||||
{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", CipherSuites{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"}, []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}},
|
||||
{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", CipherSuites{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"}, []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}},
|
||||
{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", CipherSuites{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"}, []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256}},
|
||||
{"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", CipherSuites{"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"}, []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}},
|
||||
{"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", CipherSuites{"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"}, []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}},
|
||||
{"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", CipherSuites{"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"}, []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305}},
|
||||
{"multiple", CipherSuites{"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"}, []uint16{tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}},
|
||||
{"fail", CipherSuites{"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", "TLS_BAD_CIPHERSUITE"}, []uint16{tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 0}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.c.Value(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("CipherSuites.Value() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSOptions_TLSConfig(t *testing.T) {
|
||||
type fields struct {
|
||||
CipherSuites CipherSuites
|
||||
MinVersion TLSVersion
|
||||
MaxVersion TLSVersion
|
||||
Renegotiation bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want *tls.Config
|
||||
}{
|
||||
{"default", fields{DefaultTLSCipherSuites, DefaultTLSMinVersion, DefaultTLSMaxVersion, DefaultTLSRenegotiation}, &tls.Config{
|
||||
CipherSuites: []uint16{tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
|
||||
MinVersion: tls.VersionTLS12,
|
||||
MaxVersion: tls.VersionTLS13,
|
||||
Renegotiation: tls.RenegotiateNever,
|
||||
}},
|
||||
{"renegotation", fields{DefaultTLSCipherSuites, DefaultTLSMinVersion, DefaultTLSMaxVersion, true}, &tls.Config{
|
||||
CipherSuites: []uint16{tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
|
||||
MinVersion: tls.VersionTLS12,
|
||||
MaxVersion: tls.VersionTLS13,
|
||||
Renegotiation: tls.RenegotiateFreelyAsClient,
|
||||
}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := &TLSOptions{
|
||||
CipherSuites: tt.fields.CipherSuites,
|
||||
MinVersion: tt.fields.MinVersion,
|
||||
MaxVersion: tt.fields.MaxVersion,
|
||||
Renegotiation: tt.fields.Renegotiation,
|
||||
}
|
||||
if got := o.TLSConfig(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("TLSOptions.TLSConfig() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -22,7 +22,6 @@ import (
|
|||
"github.com/smallstep/certificates/errs"
|
||||
"github.com/smallstep/cli/crypto/keys"
|
||||
"github.com/smallstep/cli/crypto/pemutil"
|
||||
"github.com/smallstep/cli/crypto/tlsutil"
|
||||
"github.com/smallstep/cli/crypto/x509util"
|
||||
"github.com/smallstep/cli/jose"
|
||||
"gopkg.in/square/go-jose.v2/jwt"
|
||||
|
@ -122,7 +121,7 @@ func TestAuthority_Sign(t *testing.T) {
|
|||
|
||||
a := testAuthority(t)
|
||||
assert.FatalError(t, err)
|
||||
a.config.AuthorityConfig.Template = &x509util.ASN1DN{
|
||||
a.config.AuthorityConfig.Template = &ASN1DN{
|
||||
Country: "Tazmania",
|
||||
Organization: "Acme Co",
|
||||
Locality: "Landscapes",
|
||||
|
@ -478,7 +477,7 @@ func TestAuthority_Renew(t *testing.T) {
|
|||
assert.FatalError(t, err)
|
||||
|
||||
a := testAuthority(t)
|
||||
a.config.AuthorityConfig.Template = &x509util.ASN1DN{
|
||||
a.config.AuthorityConfig.Template = &ASN1DN{
|
||||
Country: "Tazmania",
|
||||
Organization: "Acme Co",
|
||||
Locality: "Landscapes",
|
||||
|
@ -705,7 +704,7 @@ func TestAuthority_Rekey(t *testing.T) {
|
|||
assert.FatalError(t, err)
|
||||
|
||||
a := testAuthority(t)
|
||||
a.config.AuthorityConfig.Template = &x509util.ASN1DN{
|
||||
a.config.AuthorityConfig.Template = &ASN1DN{
|
||||
Country: "Tazmania",
|
||||
Organization: "Acme Co",
|
||||
Locality: "Landscapes",
|
||||
|
@ -946,7 +945,7 @@ func TestAuthority_Rekey(t *testing.T) {
|
|||
func TestAuthority_GetTLSOptions(t *testing.T) {
|
||||
type renewTest struct {
|
||||
auth *Authority
|
||||
opts *tlsutil.TLSOptions
|
||||
opts *TLSOptions
|
||||
}
|
||||
tests := map[string]func() (*renewTest, error){
|
||||
"default": func() (*renewTest, error) {
|
||||
|
@ -955,8 +954,8 @@ func TestAuthority_GetTLSOptions(t *testing.T) {
|
|||
},
|
||||
"non-default": func() (*renewTest, error) {
|
||||
a := testAuthority(t)
|
||||
a.config.TLS = &tlsutil.TLSOptions{
|
||||
CipherSuites: x509util.CipherSuites{
|
||||
a.config.TLS = &TLSOptions{
|
||||
CipherSuites: CipherSuites{
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
},
|
||||
|
|
|
@ -79,7 +79,7 @@ func TestCASign(t *testing.T) {
|
|||
pub, priv, err := keys.GenerateDefaultKeyPair()
|
||||
assert.FatalError(t, err)
|
||||
|
||||
asn1dn := &x509util.ASN1DN{
|
||||
asn1dn := &authority.ASN1DN{
|
||||
Country: "Tazmania",
|
||||
Organization: "Acme Co",
|
||||
Locality: "Landscapes",
|
||||
|
@ -558,7 +558,7 @@ func TestCARenew(t *testing.T) {
|
|||
pub, _, err := keys.GenerateDefaultKeyPair()
|
||||
assert.FatalError(t, err)
|
||||
|
||||
asn1dn := &x509util.ASN1DN{
|
||||
asn1dn := &authority.ASN1DN{
|
||||
Country: "Tazmania",
|
||||
Organization: "Acme Co",
|
||||
Locality: "Landscapes",
|
||||
|
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
|||
module github.com/smallstep/certificates
|
||||
|
||||
go 1.13
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.51.0
|
||||
|
|
11
pki/pki.go
11
pki/pki.go
|
@ -23,7 +23,6 @@ import (
|
|||
"github.com/smallstep/cli/config"
|
||||
"github.com/smallstep/cli/crypto/keys"
|
||||
"github.com/smallstep/cli/crypto/pemutil"
|
||||
"github.com/smallstep/cli/crypto/tlsutil"
|
||||
"github.com/smallstep/cli/crypto/x509util"
|
||||
"github.com/smallstep/cli/errs"
|
||||
"github.com/smallstep/cli/jose"
|
||||
|
@ -432,11 +431,11 @@ func (p *PKI) GenerateConfig(opt ...Option) (*authority.Config, error) {
|
|||
DisableIssuedAtCheck: false,
|
||||
Provisioners: provisioner.List{prov},
|
||||
},
|
||||
TLS: &tlsutil.TLSOptions{
|
||||
MinVersion: x509util.DefaultTLSMinVersion,
|
||||
MaxVersion: x509util.DefaultTLSMaxVersion,
|
||||
Renegotiation: x509util.DefaultTLSRenegotiation,
|
||||
CipherSuites: x509util.DefaultTLSCipherSuites,
|
||||
TLS: &authority.TLSOptions{
|
||||
MinVersion: authority.DefaultTLSMinVersion,
|
||||
MaxVersion: authority.DefaultTLSMaxVersion,
|
||||
Renegotiation: authority.DefaultTLSRenegotiation,
|
||||
CipherSuites: authority.DefaultTLSCipherSuites,
|
||||
},
|
||||
Templates: p.getTemplates(),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue