Enforce >= 2048 bit rsa keys at the provisioner layer
* Fixes #94 * In the future this should be configurable by provisioner
This commit is contained in:
parent
0939f0d053
commit
2b41faa9cf
22 changed files with 250 additions and 39 deletions
|
@ -24,6 +24,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/smallstep/assert"
|
||||||
"github.com/smallstep/certificates/authority"
|
"github.com/smallstep/certificates/authority"
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
"github.com/smallstep/certificates/logging"
|
"github.com/smallstep/certificates/logging"
|
||||||
|
@ -150,7 +152,7 @@ func parseCertificate(data string) *x509.Certificate {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCertificateRequest(data string) *x509.CertificateRequest {
|
func parseCertificateRequest(data string) *x509.CertificateRequest {
|
||||||
block, _ := pem.Decode([]byte(csrPEM))
|
block, _ := pem.Decode([]byte(data))
|
||||||
if block == nil {
|
if block == nil {
|
||||||
panic("failed to parse certificate request PEM")
|
panic("failed to parse certificate request PEM")
|
||||||
}
|
}
|
||||||
|
@ -385,13 +387,13 @@ func TestSignRequest_Validate(t *testing.T) {
|
||||||
NotAfter time.Time
|
NotAfter time.Time
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fields fields
|
fields fields
|
||||||
wantErr bool
|
err error
|
||||||
}{
|
}{
|
||||||
{"missing csr", fields{CertificateRequest{}, "foobarzar", time.Time{}, time.Time{}}, true},
|
{"missing csr", fields{CertificateRequest{}, "foobarzar", time.Time{}, time.Time{}}, errors.New("missing csr")},
|
||||||
{"invalid csr", fields{CertificateRequest{bad}, "foobarzar", time.Time{}, time.Time{}}, true},
|
{"invalid csr", fields{CertificateRequest{bad}, "foobarzar", time.Time{}, time.Time{}}, errors.New("invalid csr")},
|
||||||
{"missing ott", fields{CertificateRequest{csr}, "", time.Time{}, time.Time{}}, true},
|
{"missing ott", fields{CertificateRequest{csr}, "", time.Time{}, time.Time{}}, errors.New("missing ott")},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -401,8 +403,12 @@ func TestSignRequest_Validate(t *testing.T) {
|
||||||
NotAfter: NewTimeDuration(tt.fields.NotAfter),
|
NotAfter: NewTimeDuration(tt.fields.NotAfter),
|
||||||
NotBefore: NewTimeDuration(tt.fields.NotBefore),
|
NotBefore: NewTimeDuration(tt.fields.NotBefore),
|
||||||
}
|
}
|
||||||
if err := s.Validate(); (err != nil) != tt.wantErr {
|
if err := s.Validate(); err != nil {
|
||||||
t.Errorf("SignRequest.Validate() error = %v, wantErr %v", err, tt.wantErr)
|
if assert.NotNil(t, tt.err) {
|
||||||
|
assert.HasPrefix(t, err.Error(), tt.err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert.Nil(t, tt.err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -446,7 +446,7 @@ func TestAuthority_AuthorizeSign(t *testing.T) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if assert.Nil(t, tc.err) {
|
if assert.Nil(t, tc.err) {
|
||||||
assert.Len(t, 7, got)
|
assert.Len(t, 8, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -538,7 +538,7 @@ func TestAuthority_Authorize(t *testing.T) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if assert.Nil(t, tc.err) {
|
if assert.Nil(t, tc.err) {
|
||||||
assert.Len(t, 7, got)
|
assert.Len(t, 8, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -287,6 +287,7 @@ func (p *AWS) AuthorizeSign(token string) ([]SignOption, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(so,
|
return append(so,
|
||||||
|
defaultPublicKeyValidator{},
|
||||||
commonNameValidator(payload.Claims.Subject),
|
commonNameValidator(payload.Claims.Subject),
|
||||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||||
newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID, "InstanceID", doc.InstanceID),
|
newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID, "InstanceID", doc.InstanceID),
|
||||||
|
|
|
@ -326,11 +326,11 @@ func TestAWS_AuthorizeSign(t *testing.T) {
|
||||||
wantLen int
|
wantLen int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", p1, args{t1}, 4, false},
|
{"ok", p1, args{t1}, 5, false},
|
||||||
{"ok", p2, args{t2}, 6, false},
|
{"ok", p2, args{t2}, 7, false},
|
||||||
{"ok", p2, args{t2Hostname}, 6, false},
|
{"ok", p2, args{t2Hostname}, 7, false},
|
||||||
{"ok", p2, args{t2PrivateIP}, 6, false},
|
{"ok", p2, args{t2PrivateIP}, 7, false},
|
||||||
{"ok", p1, args{t4}, 4, false},
|
{"ok", p1, args{t4}, 5, false},
|
||||||
{"fail account", p3, args{t3}, 0, true},
|
{"fail account", p3, args{t3}, 0, true},
|
||||||
{"fail token", p1, args{"token"}, 0, true},
|
{"fail token", p1, args{"token"}, 0, true},
|
||||||
{"fail subject", p1, args{failSubject}, 0, true},
|
{"fail subject", p1, args{failSubject}, 0, true},
|
||||||
|
|
|
@ -275,6 +275,7 @@ func (p *Azure) AuthorizeSign(token string) ([]SignOption, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(so,
|
return append(so,
|
||||||
|
defaultPublicKeyValidator{},
|
||||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||||
newProvisionerExtensionOption(TypeAzure, p.Name, p.TenantID),
|
newProvisionerExtensionOption(TypeAzure, p.Name, p.TenantID),
|
||||||
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
||||||
|
|
|
@ -281,9 +281,9 @@ func TestAzure_AuthorizeSign(t *testing.T) {
|
||||||
wantLen int
|
wantLen int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", p1, args{t1}, 3, false},
|
{"ok", p1, args{t1}, 4, false},
|
||||||
{"ok", p2, args{t2}, 5, false},
|
{"ok", p2, args{t2}, 6, false},
|
||||||
{"ok", p1, args{t11}, 3, false},
|
{"ok", p1, args{t11}, 4, false},
|
||||||
{"fail tenant", p3, args{t3}, 0, true},
|
{"fail tenant", p3, args{t3}, 0, true},
|
||||||
{"fail resource group", p4, args{t4}, 0, true},
|
{"fail resource group", p4, args{t4}, 0, true},
|
||||||
{"fail token", p1, args{"token"}, 0, true},
|
{"fail token", p1, args{"token"}, 0, true},
|
||||||
|
|
|
@ -228,6 +228,7 @@ func (p *GCP) AuthorizeSign(token string) ([]SignOption, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(so,
|
return append(so,
|
||||||
|
defaultPublicKeyValidator{},
|
||||||
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
|
||||||
newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject, "InstanceID", ce.InstanceID, "InstanceName", ce.InstanceName),
|
newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject, "InstanceID", ce.InstanceID, "InstanceName", ce.InstanceName),
|
||||||
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
|
||||||
|
|
|
@ -311,9 +311,9 @@ func TestGCP_AuthorizeSign(t *testing.T) {
|
||||||
wantLen int
|
wantLen int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", p1, args{t1}, 3, false},
|
{"ok", p1, args{t1}, 4, false},
|
||||||
{"ok", p2, args{t2}, 5, false},
|
{"ok", p2, args{t2}, 6, false},
|
||||||
{"ok", p3, args{t3}, 3, false},
|
{"ok", p3, args{t3}, 4, false},
|
||||||
{"fail token", p1, args{"token"}, 0, true},
|
{"fail token", p1, args{"token"}, 0, true},
|
||||||
{"fail key", p1, args{failKey}, 0, true},
|
{"fail key", p1, args{failKey}, 0, true},
|
||||||
{"fail iss", p1, args{failIss}, 0, true},
|
{"fail iss", p1, args{failIss}, 0, true},
|
||||||
|
|
|
@ -143,6 +143,7 @@ func (p *JWK) AuthorizeSign(token string) ([]SignOption, error) {
|
||||||
|
|
||||||
dnsNames, ips, emails := x509util.SplitSANs(claims.SANs)
|
dnsNames, ips, emails := x509util.SplitSANs(claims.SANs)
|
||||||
return []SignOption{
|
return []SignOption{
|
||||||
|
defaultPublicKeyValidator{},
|
||||||
commonNameValidator(claims.Subject),
|
commonNameValidator(claims.Subject),
|
||||||
dnsNamesValidator(dnsNames),
|
dnsNamesValidator(dnsNames),
|
||||||
ipAddressesValidator(ips),
|
ipAddressesValidator(ips),
|
||||||
|
|
|
@ -265,14 +265,14 @@ func TestJWK_AuthorizeSign(t *testing.T) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if assert.NotNil(t, got) {
|
if assert.NotNil(t, got) {
|
||||||
assert.Len(t, 7, got)
|
assert.Len(t, 8, got)
|
||||||
|
|
||||||
_cnv := got[0]
|
_cnv := got[1]
|
||||||
cnv, ok := _cnv.(commonNameValidator)
|
cnv, ok := _cnv.(commonNameValidator)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.Equals(t, string(cnv), "subject")
|
assert.Equals(t, string(cnv), "subject")
|
||||||
|
|
||||||
_dnv := got[1]
|
_dnv := got[2]
|
||||||
dnv, ok := _dnv.(dnsNamesValidator)
|
dnv, ok := _dnv.(dnsNamesValidator)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
if tt.name == "ok-sans" {
|
if tt.name == "ok-sans" {
|
||||||
|
|
|
@ -264,21 +264,19 @@ func (o *OIDC) AuthorizeSign(token string) ([]SignOption, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Admins should be able to authorize any SAN
|
|
||||||
if o.IsAdmin(claims.Email) {
|
|
||||||
return []SignOption{
|
|
||||||
profileDefaultDuration(o.claimer.DefaultTLSCertDuration()),
|
|
||||||
newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID),
|
|
||||||
newValidityValidator(o.claimer.MinTLSCertDuration(), o.claimer.MaxTLSCertDuration()),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return []SignOption{
|
so := []SignOption{
|
||||||
emailOnlyIdentity(claims.Email),
|
defaultPublicKeyValidator{},
|
||||||
profileDefaultDuration(o.claimer.DefaultTLSCertDuration()),
|
profileDefaultDuration(o.claimer.DefaultTLSCertDuration()),
|
||||||
newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID),
|
newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID),
|
||||||
newValidityValidator(o.claimer.MinTLSCertDuration(), o.claimer.MaxTLSCertDuration()),
|
newValidityValidator(o.claimer.MinTLSCertDuration(), o.claimer.MaxTLSCertDuration()),
|
||||||
}, nil
|
}
|
||||||
|
// Admins should be able to authorize any SAN
|
||||||
|
if o.IsAdmin(claims.Email) {
|
||||||
|
return so, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return append(so, emailOnlyIdentity(claims.Email)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthorizeRenewal returns an error if the renewal is disabled.
|
// AuthorizeRenewal returns an error if the renewal is disabled.
|
||||||
|
|
|
@ -286,9 +286,9 @@ func TestOIDC_AuthorizeSign(t *testing.T) {
|
||||||
} else {
|
} else {
|
||||||
assert.NotNil(t, got)
|
assert.NotNil(t, got)
|
||||||
if tt.name == "admin" {
|
if tt.name == "admin" {
|
||||||
assert.Len(t, 3, got)
|
|
||||||
} else {
|
|
||||||
assert.Len(t, 4, got)
|
assert.Len(t, 4, got)
|
||||||
|
} else {
|
||||||
|
assert.Len(t, 5, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package provisioner
|
package provisioner
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
|
@ -10,6 +12,7 @@ import (
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/smallstep/cli/crypto/x509util"
|
"github.com/smallstep/cli/crypto/x509util"
|
||||||
|
"golang.org/x/crypto/ed25519"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options contains the options that can be passed to the Sign method.
|
// Options contains the options that can be passed to the Sign method.
|
||||||
|
@ -78,7 +81,7 @@ func (e emailOnlyIdentity) Valid(req *x509.CertificateRequest) error {
|
||||||
case len(req.EmailAddresses) == 0:
|
case len(req.EmailAddresses) == 0:
|
||||||
return errors.New("certificate request does not contain any email address")
|
return errors.New("certificate request does not contain any email address")
|
||||||
case len(req.EmailAddresses) > 1:
|
case len(req.EmailAddresses) > 1:
|
||||||
return errors.New("certificate request does not contain too many email addresses")
|
return errors.New("certificate request contains too many email addresses")
|
||||||
case req.EmailAddresses[0] == "":
|
case req.EmailAddresses[0] == "":
|
||||||
return errors.New("certificate request cannot contain an empty email address")
|
return errors.New("certificate request cannot contain an empty email address")
|
||||||
case req.EmailAddresses[0] != string(e):
|
case req.EmailAddresses[0] != string(e):
|
||||||
|
@ -88,6 +91,23 @@ func (e emailOnlyIdentity) Valid(req *x509.CertificateRequest) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// defaultPublicKeyValidator validates the public key of a certificate request.
|
||||||
|
type defaultPublicKeyValidator struct{}
|
||||||
|
|
||||||
|
// Valid checks that certificate request common name matches the one configured.
|
||||||
|
func (v defaultPublicKeyValidator) Valid(req *x509.CertificateRequest) error {
|
||||||
|
switch k := req.PublicKey.(type) {
|
||||||
|
case *rsa.PublicKey:
|
||||||
|
if k.Size() < 256 {
|
||||||
|
return errors.New("rsa key in CSR must be at least 2048 bits (256 bytes)")
|
||||||
|
}
|
||||||
|
case *ecdsa.PublicKey, ed25519.PublicKey:
|
||||||
|
default:
|
||||||
|
return errors.Errorf("unrecognized public key of type '%T' in CSR", k)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// commonNameValidator validates the common name of a certificate request.
|
// commonNameValidator validates the common name of a certificate request.
|
||||||
type commonNameValidator string
|
type commonNameValidator string
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,12 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/smallstep/assert"
|
||||||
|
"github.com/smallstep/cli/crypto/pemutil"
|
||||||
|
"github.com/smallstep/cli/crypto/x509util"
|
||||||
|
stepx509 "github.com/smallstep/cli/pkg/x509"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_emailOnlyIdentity_Valid(t *testing.T) {
|
func Test_emailOnlyIdentity_Valid(t *testing.T) {
|
||||||
|
@ -41,6 +47,72 @@ func Test_emailOnlyIdentity_Valid(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_defaultPublicKeyValidator_Valid(t *testing.T) {
|
||||||
|
_shortRSA, err := pemutil.Read("./testdata/short-rsa.csr")
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
shortRSA, ok := _shortRSA.(*x509.CertificateRequest)
|
||||||
|
assert.Fatal(t, ok)
|
||||||
|
|
||||||
|
_rsa, err := pemutil.Read("./testdata/rsa.csr")
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
rsaCSR, ok := _rsa.(*x509.CertificateRequest)
|
||||||
|
assert.Fatal(t, ok)
|
||||||
|
|
||||||
|
_ecdsa, err := pemutil.Read("./testdata/ecdsa.csr")
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
ecdsaCSR, ok := _ecdsa.(*x509.CertificateRequest)
|
||||||
|
assert.Fatal(t, ok)
|
||||||
|
|
||||||
|
_ed25519, err := pemutil.Read("./testdata/ed25519.csr", pemutil.WithStepCrypto())
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
ed25519CSR, ok := _ed25519.(*stepx509.CertificateRequest)
|
||||||
|
assert.Fatal(t, ok)
|
||||||
|
|
||||||
|
v := defaultPublicKeyValidator{}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
csr *x509.CertificateRequest
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"fail/unrecognized-key-type",
|
||||||
|
&x509.CertificateRequest{PublicKey: "foo"},
|
||||||
|
errors.New("unrecognized public key of type 'string' in CSR"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fail/rsa/too-short",
|
||||||
|
shortRSA,
|
||||||
|
errors.New("rsa key in CSR must be at least 2048 bits (256 bytes)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ok/rsa",
|
||||||
|
rsaCSR,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ok/ecdsa",
|
||||||
|
ecdsaCSR,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ok/ed25519",
|
||||||
|
x509util.ToX509CertificateRequest(ed25519CSR),
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if err := v.Valid(tt.csr); err != nil {
|
||||||
|
if assert.NotNil(t, tt.err) {
|
||||||
|
assert.HasPrefix(t, err.Error(), tt.err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert.Nil(t, tt.err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_commonNameValidator_Valid(t *testing.T) {
|
func Test_commonNameValidator_Valid(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
req *x509.CertificateRequest
|
req *x509.CertificateRequest
|
||||||
|
|
7
authority/provisioner/testdata/ecdsa.csr
vendored
Normal file
7
authority/provisioner/testdata/ecdsa.csr
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIHqMIGRAgEAMA4xDDAKBgNVBAMTA2ZvbzBZMBMGByqGSM49AgEGCCqGSM49AwEH
|
||||||
|
A0IABKdDjTb7XIYCWC4QUq1xn5hgf3J4WpfWbd3C5frKrA4/VdQ+XfpHQIxDoHqh
|
||||||
|
jcWke0SEETc9i6HDDtWv8bXSETegITAfBgkqhkiG9w0BCQ4xEjAQMA4GA1UdEQQH
|
||||||
|
MAWCA2ZvbzAKBggqhkjOPQQDAgNIADBFAiEA1pFLT8p/YogG0o6NEEmdxzwbOzJA
|
||||||
|
A+C+DvoT91c1OcQCIGUjP3s+k6Xwdf/VukUZXTfG1lobmkZhO3vYxAjPkwA7
|
||||||
|
-----END CERTIFICATE REQUEST-----
|
8
authority/provisioner/testdata/ecdsa.key
vendored
Normal file
8
authority/provisioner/testdata/ecdsa.key
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
Proc-Type: 4,ENCRYPTED
|
||||||
|
DEK-Info: AES-256-CBC,54abd40e525b255542ee6161ec438721
|
||||||
|
|
||||||
|
fJvmEc5n0IG4t4FKF+ekKhpog4ods2nZjBR5KLkGH5oSGAOEADSXIRBK76Jnm/nz
|
||||||
|
Kv8ZwGqxNnoJUQyeTMlyg5OnOUAQPyNBPvoItOlD2DP32WJXgQ+NSHB2h9pcBGYG
|
||||||
|
yLWrCtzl9/P9REWskanPO4RujP27Ht62omcMO7SxxNI=
|
||||||
|
-----END EC PRIVATE KEY-----
|
6
authority/provisioner/testdata/ed25519.csr
vendored
Normal file
6
authority/provisioner/testdata/ed25519.csr
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIGuMGICAQAwDjEMMAoGA1UEAxMDZm9vMCowBQYDK2VwAyEA3yF/Igqb5UTp6XOq
|
||||||
|
yj+cZL9nIfjDKrUT0fMzDAHtIqqgITAfBgkqhkiG9w0BCQ4xEjAQMA4GA1UdEQQH
|
||||||
|
MAWCA2ZvbzAFBgMrZXADQQAIAx7N6ezi4NL8n0oJU8v3AmVSi0XvTuIHXUtcLGoU
|
||||||
|
OZtlO3zjWI+DgcT/ADeEKn+T8OazDxcCbTBbHiM2hIsA
|
||||||
|
-----END CERTIFICATE REQUEST-----
|
6
authority/provisioner/testdata/ed25519.key
vendored
Normal file
6
authority/provisioner/testdata/ed25519.key
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIGkMGAGCSqGSIb3DQEFDTBTMDIGCSqGSIb3DQEFDDAlBBDJ0vCXdpPyUiLlbge5
|
||||||
|
1g0jAgMBhqAwDAYIKoZIhvcNAgkAADAdBglghkgBZQMEASoEENtOknzU2eS2mlxl
|
||||||
|
73Yo/IoEQEyJS2EEx3+oYaKlFIB90e1Zkmi8da7d3r2iUlfc7faRAiKChcEvtEas
|
||||||
|
vYF2l9LEZ9DXv1Rm1uyNuSpXuddHScE=
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
16
authority/provisioner/testdata/rsa.csr
vendored
Normal file
16
authority/provisioner/testdata/rsa.csr
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIICdDCCAVwCAQAwDjEMMAoGA1UEAxMDZm9vMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||||
|
AQ8AMIIBCgKCAQEA86h3t/KJylE0/aPxvF9JqPaOwSsGexuDWqDVJSOWBJi/ZqUA
|
||||||
|
Ea2Gy05ZIJkQ5GOy0bUs2JCNCVXVkfPrUkX6IvIlXpTjutjMDYyYGdgQjzpKPnOA
|
||||||
|
v3mO2a7mLMzJunws7pvrUPP7z5KDCKSAPf6VAcu/na8rGDWn1TUYR8hINK1rLQQf
|
||||||
|
OcyNWrr7yLkR84jSsrw/Qgc8NS//F4ccca1NfZecPEtxgcHjKdDQZ3SYRAfb6Dc0
|
||||||
|
jRuvoByAd3q9okOOr70gpMXgpoFVArDynaHMPK9xJ1w2p3s2/NhOYgY9f9rtcWTo
|
||||||
|
afoAcHK1jy5iQCogFUKt1bUCz5IsaYkRt+D+HQIDAQABoCEwHwYJKoZIhvcNAQkO
|
||||||
|
MRIwEDAOBgNVHREEBzAFggNmb28wDQYJKoZIhvcNAQELBQADggEBAOsv1UKwEbcY
|
||||||
|
8Fj2Pl55BjkqQG4PqSQdWJZfK0ol/GRty5XFaTgOUZyTeXOag84OGw0qM0E7kkUa
|
||||||
|
O5QwDOpnmIgg01Ywr4QM166l1iED+eOUscXJMonBAsS3JNYF1JxcDyKzIl/dt9+w
|
||||||
|
JXQ64uquuD57amOs8++ROfKW988HzXm0OnoHj8LZ1Mq2yUmxvnnfVnmMpZWo43sA
|
||||||
|
8NQs4v9dT5wLByFvBjcaWiGVZwZiwT4Q/Msskv9L0o1On0fgCJ6PjLYdblTwMHDZ
|
||||||
|
syH+X8SsUqeEmyvtiRc1XUeFbxS2hnPXJCXeyfljqwsBNGaVhBXcsV2Lg7IaloBF
|
||||||
|
/RyWqQZ44eE=
|
||||||
|
-----END CERTIFICATE REQUEST-----
|
30
authority/provisioner/testdata/rsa.key
vendored
Normal file
30
authority/provisioner/testdata/rsa.key
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
Proc-Type: 4,ENCRYPTED
|
||||||
|
DEK-Info: AES-256-CBC,e77ed7e2d2572b5a246a1c4b994190bb
|
||||||
|
|
||||||
|
29o7UA/L7OF7inTPKkwBrtd8CJdXVQs9R3oJPitmFk8SZbrLHEiEhF1C0uB3xK3s
|
||||||
|
GWQ9O7bjERM3uAvQkd7MSkUUBpyPXS9GFacd85e85d1Ubl6miTAwkFrQnT9yn6n/
|
||||||
|
Fak5JtkmdB6ObfVTioOwT1jdtGTifKg1bIhYISgwqCWhgV2fUFk6HQAAIMXTTRc+
|
||||||
|
ZK1WbunT7LimYrnN3gQ4ylm/4C8nQl3JCGpvWZaRoH91q1LLD6IwWmX0D09F37dU
|
||||||
|
X3KoKv/GvuDlV3H1dUBwxhU+GI5/lItPp9OcdLZnnr67Gs+X+do3MFT1h675TM4N
|
||||||
|
c9QEIJB6RYatLBKHCS7j8W7EbuJAFZ+MCCapP92ERmVVVsWPY+V7CDVQxM2v4X/w
|
||||||
|
7C7JYx8b4xuQbdvu9KVU5irsXg8hBx7kDb/mtWjT4+8+sseLKA4oOmI6XwVMdbow
|
||||||
|
MciGilAIaNtWwQHe0EK9E9tiQfc9OyzxdrfplRckAAehHuPGU7+iMCsigCLT3aiV
|
||||||
|
CDHmnLdTXKIvGe8faTQoJphrb9F8bobGo5D4ZqX5f6gKuPIJsfd/r0GD8VNSF/Q7
|
||||||
|
SJQMhkVyaixFB0gQbmea7sTyScdW+Qne7nLpam3ISgo+G4CAH8W88wLnuHMLmvoC
|
||||||
|
ZE3HvArSeQZ0WPHgB86AfoNRIxd6Emgb+dFyA6wPJC29nZkB8PFSrAHp0zp7KilF
|
||||||
|
fe9K2dVAUBZFhQthQIYAjJmYLCukLhxUALiqdSmQZrt6DSE33K8s5ed2KJu/60G6
|
||||||
|
lZwIzQHPXesRhwmwbkfPB8CyWM+L6osdWv8QyMdM8Wb+66zkhKWBNbm+ccMfP6Zf
|
||||||
|
1ynF/a/DRX8bf81w+nvLsCGTdxVuEVEpuzS1NclKTmYQu58Ol0RgQe2JSxL89n+A
|
||||||
|
JAHUu9g9LcTg2jNPjxeA/vusSXMZRrPqrUCYhHhcgR4mE13uyyFI/9frk0gPpKXp
|
||||||
|
/FislMydWov2JRp1ixzypMBqlFR/zF6j6m3P1g7gchwScWzrZQHD58xdRin4Udiv
|
||||||
|
OR4huswh5v2i/0KozBoUAwbvPGERnMlTaGoBMPJ5Xe/jkBJw3uC3Dhi74uyUCjqU
|
||||||
|
hMQW4RJKmuiZVfAIX0RdgeUWXPs+8pf2pXrpIiVHCAHDrxXNMC7X6/9EcBN15B88
|
||||||
|
W5/KIRngDeB2oVYrn1GfO7iLu1Rd8VFXyaVItOXq7WrL2pwm8ANhWcFDdnXf6jHW
|
||||||
|
BcKss1j8rZxOchksf+ZPXhn3QkdooD9iVONky1zLIsV5GPwMe8+yXwXznzJSbHH7
|
||||||
|
dOfhK93fZqUwx4gFULwCuWIwLTfNmQ3VzdKioGt39RFDVQb+pbR7p9jv899VjsVO
|
||||||
|
TBBpRa00fvbK1H2CMVHnwwIf82M4XypSNGR/tSD3AImZPb5RfZnznoXXCMEfYVsd
|
||||||
|
8/Ry4GHusA+zxCjCxHFtXVkb9sklewJtnUmN5mUzo/81szuigLB5IADR21IOyVBq
|
||||||
|
A4kz96Ta885Z5owhonfZp1HD53pDEbxCuuIy+fgYfjfDSAj3L/QT3ZKrdcIdYQap
|
||||||
|
PhrNRW3j38koAatTLd3+E9KqBO5BiY+T5h+Q3XesWnaXInfu5WKiiEm5hHiejA0C
|
||||||
|
-----END RSA PRIVATE KEY-----
|
10
authority/provisioner/testdata/short-rsa.csr
vendored
Normal file
10
authority/provisioner/testdata/short-rsa.csr
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIBdDCB2wIBADAOMQwwCgYDVQQDEwNmb28wgaIwDQYJKoZIhvcNAQEBBQADgZAA
|
||||||
|
MIGMAoGEAK8dks7oV6kcIFEaWna7CDGYPAE8IL7rNi+ruQ1dIYz+JtxT7OPjbCn/
|
||||||
|
t5iqni96+35iS/8CvMtEuquOMTMSWOWwlurrbTbLqCazuz/g233o8udxSxhny3cY
|
||||||
|
wHogp4cXCX6cFll6DeUnoCEuTTSIu8IBHbK48VfNw4V4gGz6cp/H93HrAgMBAAGg
|
||||||
|
ITAfBgkqhkiG9w0BCQ4xEjAQMA4GA1UdEQQHMAWCA2ZvbzANBgkqhkiG9w0BAQsF
|
||||||
|
AAOBhABCZsYM+Kgje68Z9Fjl2+cBwtQHvZDarh+cz6W1SchinZ1T0aNQvSj/otOe
|
||||||
|
ttnEF4Rq8zqzr4fbv+AF451Mx36AkfgZr9XWGzxidrH+fBCNWXWNR+ymhrL6UFTG
|
||||||
|
2FbarLt9jN2aJLAYQPwtSeGTAZ74tLOPRPnTP6aMfFNg4XCR0uveHA==
|
||||||
|
-----END CERTIFICATE REQUEST-----
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -203,6 +204,33 @@ func TestSign(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fail rsa key too short": func(t *testing.T) *signTest {
|
||||||
|
shortRSAKeyPEM := `-----BEGIN CERTIFICATE REQUEST-----
|
||||||
|
MIIBdDCB2wIBADAOMQwwCgYDVQQDEwNmb28wgaIwDQYJKoZIhvcNAQEBBQADgZAA
|
||||||
|
MIGMAoGEAK8dks7oV6kcIFEaWna7CDGYPAE8IL7rNi+ruQ1dIYz+JtxT7OPjbCn/
|
||||||
|
t5iqni96+35iS/8CvMtEuquOMTMSWOWwlurrbTbLqCazuz/g233o8udxSxhny3cY
|
||||||
|
wHogp4cXCX6cFll6DeUnoCEuTTSIu8IBHbK48VfNw4V4gGz6cp/H93HrAgMBAAGg
|
||||||
|
ITAfBgkqhkiG9w0BCQ4xEjAQMA4GA1UdEQQHMAWCA2ZvbzANBgkqhkiG9w0BAQsF
|
||||||
|
AAOBhABCZsYM+Kgje68Z9Fjl2+cBwtQHvZDarh+cz6W1SchinZ1T0aNQvSj/otOe
|
||||||
|
ttnEF4Rq8zqzr4fbv+AF451Mx36AkfgZr9XWGzxidrH+fBCNWXWNR+ymhrL6UFTG
|
||||||
|
2FbarLt9jN2aJLAYQPwtSeGTAZ74tLOPRPnTP6aMfFNg4XCR0uveHA==
|
||||||
|
-----END CERTIFICATE REQUEST-----`
|
||||||
|
block, _ := pem.Decode([]byte(shortRSAKeyPEM))
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
csr, err := x509.ParseCertificateRequest(block.Bytes)
|
||||||
|
assert.FatalError(t, err)
|
||||||
|
|
||||||
|
return &signTest{
|
||||||
|
auth: a,
|
||||||
|
csr: csr,
|
||||||
|
extraOpts: extraOpts,
|
||||||
|
signOpts: signOpts,
|
||||||
|
err: &apiError{errors.New("sign: rsa key in CSR must be at least 2048 bits (256 bytes)"),
|
||||||
|
http.StatusUnauthorized,
|
||||||
|
context{"csr": csr, "signOptions": signOpts},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
"fail store cert in db": func(t *testing.T) *signTest {
|
"fail store cert in db": func(t *testing.T) *signTest {
|
||||||
csr := getCSR(t, priv)
|
csr := getCSR(t, priv)
|
||||||
_a := testAuthority(t)
|
_a := testAuthority(t)
|
||||||
|
|
Loading…
Reference in a new issue