Merge pull request #440 from mkkeffeler/smallstep-by-provisioner-appendedcert

Begins to fix issue 87
This commit is contained in:
Mariano Cano 2020-12-28 17:49:00 -08:00 committed by GitHub
commit 00c6f08612
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 54 additions and 60 deletions

View file

@ -164,7 +164,7 @@ func (a *Authority) init() error {
// Read intermediate and create X509 signer for default CAS. // Read intermediate and create X509 signer for default CAS.
if options.Is(casapi.SoftCAS) { if options.Is(casapi.SoftCAS) {
options.Issuer, err = pemutil.ReadCertificate(a.config.IntermediateCert) options.CertificateChain, err = pemutil.ReadCertificateBundle(a.config.IntermediateCert)
if err != nil { if err != nil {
return err return err
} }

View file

@ -96,8 +96,8 @@ func WithX509Signer(crt *x509.Certificate, s crypto.Signer) Option {
return func(a *Authority) error { return func(a *Authority) error {
srv, err := cas.New(context.Background(), casapi.Options{ srv, err := cas.New(context.Background(), casapi.Options{
Type: casapi.SoftCAS, Type: casapi.SoftCAS,
Issuer: crt,
Signer: s, Signer: s,
CertificateChain: []*x509.Certificate{crt},
}) })
if err != nil { if err != nil {
return err return err

View file

@ -56,7 +56,7 @@ func (m *certificateDurationEnforcer) Enforce(cert *x509.Certificate) error {
} }
func getDefaultIssuer(a *Authority) *x509.Certificate { func getDefaultIssuer(a *Authority) *x509.Certificate {
return a.x509CAService.(*softcas.SoftCAS).Issuer return a.x509CAService.(*softcas.SoftCAS).CertificateChain[len(a.x509CAService.(*softcas.SoftCAS).CertificateChain)-1]
} }
func getDefaultSigner(a *Authority) crypto.Signer { func getDefaultSigner(a *Authority) crypto.Signer {
@ -671,7 +671,7 @@ func TestAuthority_Renew(t *testing.T) {
intCert, intSigner := generateIntermidiateCertificate(t, rootCert, rootSigner) intCert, intSigner := generateIntermidiateCertificate(t, rootCert, rootSigner)
_a := testAuthority(t) _a := testAuthority(t)
_a.x509CAService.(*softcas.SoftCAS).Issuer = intCert _a.x509CAService.(*softcas.SoftCAS).CertificateChain = []*x509.Certificate{intCert}
_a.x509CAService.(*softcas.SoftCAS).Signer = intSigner _a.x509CAService.(*softcas.SoftCAS).Signer = intSigner
return &renewTest{ return &renewTest{
auth: _a, auth: _a,
@ -878,7 +878,7 @@ func TestAuthority_Rekey(t *testing.T) {
intCert, intSigner := generateIntermidiateCertificate(t, rootCert, rootSigner) intCert, intSigner := generateIntermidiateCertificate(t, rootCert, rootSigner)
_a := testAuthority(t) _a := testAuthority(t)
_a.x509CAService.(*softcas.SoftCAS).Issuer = intCert _a.x509CAService.(*softcas.SoftCAS).CertificateChain = []*x509.Certificate{intCert}
_a.x509CAService.(*softcas.SoftCAS).Signer = intSigner _a.x509CAService.(*softcas.SoftCAS).Signer = intSigner
return &renewTest{ return &renewTest{
auth: _a, auth: _a,

View file

@ -21,9 +21,9 @@ type Options struct {
// `projects/*/locations/*/certificateAuthorities/*`. // `projects/*/locations/*/certificateAuthorities/*`.
CertificateAuthority string `json:"certificateAuthority"` CertificateAuthority string `json:"certificateAuthority"`
// Issuer and signer are the issuer certificate and signer used in SoftCAS. // Certificate and signer are the issuer certificate,along with any other bundled certificates to be returned in the chain for consumers, and signer used in SoftCAS.
// They are configured in ca.json crt and key properties. // They are configured in ca.json crt and key properties.
Issuer *x509.Certificate `json:"-"` CertificateChain []*x509.Certificate
Signer crypto.Signer `json:"-"` Signer crypto.Signer `json:"-"`
// IsCreator is set to true when we're creating a certificate authority. Is // IsCreator is set to true when we're creating a certificate authority. Is

View file

@ -70,7 +70,7 @@ func TestOptions_Validate(t *testing.T) {
Type: tt.fields.Type, Type: tt.fields.Type,
CredentialsFile: tt.fields.CredentialsFile, CredentialsFile: tt.fields.CredentialsFile,
CertificateAuthority: tt.fields.CertificateAuthority, CertificateAuthority: tt.fields.CertificateAuthority,
Issuer: tt.fields.Issuer, CertificateChain: []*x509.Certificate{tt.fields.Issuer},
Signer: tt.fields.Signer, Signer: tt.fields.Signer,
} }
if err := o.Validate(); (err != nil) != tt.wantErr { if err := o.Validate(); (err != nil) != tt.wantErr {
@ -120,7 +120,7 @@ func TestOptions_Is(t *testing.T) {
Type: tt.fields.Type, Type: tt.fields.Type,
CredentialsFile: tt.fields.CredentialsFile, CredentialsFile: tt.fields.CredentialsFile,
CertificateAuthority: tt.fields.CertificateAuthority, CertificateAuthority: tt.fields.CertificateAuthority,
Issuer: tt.fields.Issuer, CertificateChain: []*x509.Certificate{tt.fields.Issuer},
Signer: tt.fields.Signer, Signer: tt.fields.Signer,
} }
if got := o.Is(tt.args.t); got != tt.want { if got := o.Is(tt.args.t); got != tt.want {

View file

@ -31,7 +31,7 @@ func (m *mockCAS) RevokeCertificate(req *apiv1.RevokeCertificateRequest) (*apiv1
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
expected := &softcas.SoftCAS{ expected := &softcas.SoftCAS{
Issuer: &x509.Certificate{Subject: pkix.Name{CommonName: "Test Issuer"}}, CertificateChain: []*x509.Certificate{{Subject: pkix.Name{CommonName: "Test Issuer"}}},
Signer: ed25519.PrivateKey{}, Signer: ed25519.PrivateKey{},
} }
@ -50,17 +50,17 @@ func TestNew(t *testing.T) {
wantErr bool wantErr bool
}{ }{
{"ok default", args{context.Background(), apiv1.Options{ {"ok default", args{context.Background(), apiv1.Options{
Issuer: &x509.Certificate{Subject: pkix.Name{CommonName: "Test Issuer"}}, CertificateChain: []*x509.Certificate{{Subject: pkix.Name{CommonName: "Test Issuer"}}},
Signer: ed25519.PrivateKey{}, Signer: ed25519.PrivateKey{},
}}, expected, false}, }}, expected, false},
{"ok softcas", args{context.Background(), apiv1.Options{ {"ok softcas", args{context.Background(), apiv1.Options{
Type: "softcas", Type: "softcas",
Issuer: &x509.Certificate{Subject: pkix.Name{CommonName: "Test Issuer"}}, CertificateChain: []*x509.Certificate{{Subject: pkix.Name{CommonName: "Test Issuer"}}},
Signer: ed25519.PrivateKey{}, Signer: ed25519.PrivateKey{},
}}, expected, false}, }}, expected, false},
{"ok SoftCAS", args{context.Background(), apiv1.Options{ {"ok SoftCAS", args{context.Background(), apiv1.Options{
Type: "SoftCAS", Type: "SoftCAS",
Issuer: &x509.Certificate{Subject: pkix.Name{CommonName: "Test Issuer"}}, CertificateChain: []*x509.Certificate{{Subject: pkix.Name{CommonName: "Test Issuer"}}},
Signer: ed25519.PrivateKey{}, Signer: ed25519.PrivateKey{},
}}, expected, false}, }}, expected, false},
{"fail empty", args{context.Background(), apiv1.Options{}}, (*softcas.SoftCAS)(nil), true}, {"fail empty", args{context.Background(), apiv1.Options{}}, (*softcas.SoftCAS)(nil), true},

View file

@ -26,7 +26,7 @@ var now = func() time.Time {
// SoftCAS implements a Certificate Authority Service using Golang or KMS // SoftCAS implements a Certificate Authority Service using Golang or KMS
// crypto. This is the default CAS used in step-ca. // crypto. This is the default CAS used in step-ca.
type SoftCAS struct { type SoftCAS struct {
Issuer *x509.Certificate CertificateChain []*x509.Certificate
Signer crypto.Signer Signer crypto.Signer
KeyManager kms.KeyManager KeyManager kms.KeyManager
} }
@ -36,14 +36,14 @@ type SoftCAS struct {
func New(ctx context.Context, opts apiv1.Options) (*SoftCAS, error) { func New(ctx context.Context, opts apiv1.Options) (*SoftCAS, error) {
if !opts.IsCreator { if !opts.IsCreator {
switch { switch {
case opts.Issuer == nil: case len(opts.CertificateChain) == 0:
return nil, errors.New("softCAS 'issuer' cannot be nil") return nil, errors.New("softCAS 'CertificateChain' cannot be nil")
case opts.Signer == nil: case opts.Signer == nil:
return nil, errors.New("softCAS 'signer' cannot be nil") return nil, errors.New("softCAS 'signer' cannot be nil")
} }
} }
return &SoftCAS{ return &SoftCAS{
Issuer: opts.Issuer, CertificateChain: opts.CertificateChain,
Signer: opts.Signer, Signer: opts.Signer,
KeyManager: opts.KeyManager, KeyManager: opts.KeyManager,
}, nil }, nil
@ -66,18 +66,16 @@ func (c *SoftCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1
if req.Template.NotAfter.IsZero() { if req.Template.NotAfter.IsZero() {
req.Template.NotAfter = t.Add(req.Lifetime) req.Template.NotAfter = t.Add(req.Lifetime)
} }
req.Template.Issuer = c.Issuer.Subject req.Template.Issuer = c.CertificateChain[0].Subject
cert, err := x509util.CreateCertificate(req.Template, c.Issuer, req.Template.PublicKey, c.Signer) cert, err := x509util.CreateCertificate(req.Template, c.CertificateChain[0], req.Template.PublicKey, c.Signer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &apiv1.CreateCertificateResponse{ return &apiv1.CreateCertificateResponse{
Certificate: cert, Certificate: cert,
CertificateChain: []*x509.Certificate{ CertificateChain: c.CertificateChain,
c.Issuer,
},
}, nil }, nil
} }
@ -93,18 +91,16 @@ func (c *SoftCAS) RenewCertificate(req *apiv1.RenewCertificateRequest) (*apiv1.R
t := now() t := now()
req.Template.NotBefore = t.Add(-1 * req.Backdate) req.Template.NotBefore = t.Add(-1 * req.Backdate)
req.Template.NotAfter = t.Add(req.Lifetime) req.Template.NotAfter = t.Add(req.Lifetime)
req.Template.Issuer = c.Issuer.Subject req.Template.Issuer = c.CertificateChain[0].Subject
cert, err := x509util.CreateCertificate(req.Template, c.Issuer, req.Template.PublicKey, c.Signer) cert, err := x509util.CreateCertificate(req.Template, c.CertificateChain[0], req.Template.PublicKey, c.Signer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &apiv1.RenewCertificateResponse{ return &apiv1.RenewCertificateResponse{
Certificate: cert, Certificate: cert,
CertificateChain: []*x509.Certificate{ CertificateChain: c.CertificateChain,
c.Issuer,
},
}, nil }, nil
} }
@ -114,9 +110,7 @@ func (c *SoftCAS) RenewCertificate(req *apiv1.RenewCertificateRequest) (*apiv1.R
func (c *SoftCAS) RevokeCertificate(req *apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) { func (c *SoftCAS) RevokeCertificate(req *apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) {
return &apiv1.RevokeCertificateResponse{ return &apiv1.RevokeCertificateResponse{
Certificate: req.Certificate, Certificate: req.Certificate,
CertificateChain: []*x509.Certificate{ CertificateChain: c.CertificateChain,
c.Issuer,
},
}, nil }, nil
} }

View file

@ -182,9 +182,9 @@ func TestNew(t *testing.T) {
want *SoftCAS want *SoftCAS
wantErr bool wantErr bool
}{ }{
{"ok", args{context.Background(), apiv1.Options{Issuer: testIssuer, Signer: testSigner}}, &SoftCAS{Issuer: testIssuer, Signer: testSigner}, false}, {"ok", args{context.Background(), apiv1.Options{CertificateChain: []*x509.Certificate{testIssuer}, Signer: testSigner}}, &SoftCAS{CertificateChain: []*x509.Certificate{testIssuer}, Signer: testSigner}, false},
{"fail no issuer", args{context.Background(), apiv1.Options{Signer: testSigner}}, nil, true}, {"fail no issuer", args{context.Background(), apiv1.Options{Signer: testSigner}}, nil, true},
{"fail no signer", args{context.Background(), apiv1.Options{Issuer: testIssuer}}, nil, true}, {"fail no signer", args{context.Background(), apiv1.Options{CertificateChain: []*x509.Certificate{testIssuer}}}, nil, true},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -208,11 +208,11 @@ func TestNew_register(t *testing.T) {
} }
want := &SoftCAS{ want := &SoftCAS{
Issuer: testIssuer, CertificateChain: []*x509.Certificate{testIssuer},
Signer: testSigner, Signer: testSigner,
} }
got, err := newFn(context.Background(), apiv1.Options{Issuer: testIssuer, Signer: testSigner}) got, err := newFn(context.Background(), apiv1.Options{CertificateChain: []*x509.Certificate{testIssuer}, Signer: testSigner})
if err != nil { if err != nil {
t.Errorf("New() error = %v", err) t.Errorf("New() error = %v", err)
return return
@ -286,7 +286,7 @@ func TestSoftCAS_CreateCertificate(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &SoftCAS{ c := &SoftCAS{
Issuer: tt.fields.Issuer, CertificateChain: []*x509.Certificate{tt.fields.Issuer},
Signer: tt.fields.Signer, Signer: tt.fields.Signer,
} }
got, err := c.CreateCertificate(tt.args.req) got, err := c.CreateCertificate(tt.args.req)
@ -342,7 +342,7 @@ func TestSoftCAS_RenewCertificate(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &SoftCAS{ c := &SoftCAS{
Issuer: tt.fields.Issuer, CertificateChain: []*x509.Certificate{tt.fields.Issuer},
Signer: tt.fields.Signer, Signer: tt.fields.Signer,
} }
got, err := c.RenewCertificate(tt.args.req) got, err := c.RenewCertificate(tt.args.req)
@ -395,7 +395,7 @@ func TestSoftCAS_RevokeCertificate(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &SoftCAS{ c := &SoftCAS{
Issuer: tt.fields.Issuer, CertificateChain: []*x509.Certificate{tt.fields.Issuer},
Signer: tt.fields.Signer, Signer: tt.fields.Signer,
} }
got, err := c.RevokeCertificate(tt.args.req) got, err := c.RevokeCertificate(tt.args.req)
@ -524,7 +524,7 @@ func TestSoftCAS_CreateCertificateAuthority(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &SoftCAS{ c := &SoftCAS{
Issuer: tt.fields.Issuer, CertificateChain: []*x509.Certificate{tt.fields.Issuer},
Signer: tt.fields.Signer, Signer: tt.fields.Signer,
KeyManager: tt.fields.KeyManager, KeyManager: tt.fields.KeyManager,
} }