From 06db0bc64c06b2ceb3e2e30e232c57731049a446 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 3 Oct 2019 10:39:41 -0700 Subject: [PATCH 1/3] Fix broken link in getting started guide --- docs/GETTING_STARTED.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 219c564e..9e399993 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -176,7 +176,7 @@ created when you initilialized your PKI. In order to properly validate this certificate clients need access to the public root of trust, aka the public root certificate. If you are using the `step cli` on the same host where you initialized your PKI (the `root_ca.crt` is stored on disk locally), then you can -continue to [setting up your environment](setting-up-environment-variables), +continue to [setting up your environment](#setup-env), otherwise we will show you how to easily download your root certificate in the following step. @@ -215,9 +215,10 @@ In the examples below we will use `https://ca.smallstep.com:8080`. 3. Test. ``` - * step ca health + $ step ca health ``` + #### Setting up Environment Defaults This is optional, but we recommend you populate a `defaults.json` file with a From fb7298fe9593a65e1bedc3eae2b58e0f86274b58 Mon Sep 17 00:00:00 2001 From: Joseph Voss Date: Mon, 7 Oct 2019 11:38:37 -0400 Subject: [PATCH 2/3] Fix formatting around step certificate install link --- docs/acme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/acme.md b/docs/acme.md index 072aa0fa..5aec7206 100644 --- a/docs/acme.md +++ b/docs/acme.md @@ -71,8 +71,8 @@ There are two ways to address this problem: 1. Explicitly configure your ACME client to trust `step-ca`'s root certificate, or 2. Add `step-ca`'s root certificate to your system’s default trust store (e.g., - using `[step certificate - install](https://smallstep.com/docs/cli/certificate/install/)`) + using [`step certificate + install`](https://smallstep.com/docs/cli/certificate/install/)) If you’re using your CA for TLS in production, explicitly configuring your ACME client to only trust your root certificate is a better option. We’ll From bc6074f596d9852134663ae6fc98075500c3ea1c Mon Sep 17 00:00:00 2001 From: Jozef Kralik Date: Wed, 9 Oct 2019 21:57:12 +0200 Subject: [PATCH 3/3] Change api of functions Authority.Sign, Authority.Renew Returns certificate chain instead of 2 members. Implements #126 --- acme/common.go | 2 +- acme/order.go | 6 ++--- acme/order_test.go | 12 +++++----- api/api.go | 54 +++++++++++++++++++++++++++++-------------- api/api_test.go | 18 +++++++-------- authority/tls.go | 36 ++++++++++++++--------------- authority/tls_test.go | 12 ++++++---- ca/bootstrap_test.go | 6 ++--- ca/client_test.go | 8 +++++++ ca/tls_test.go | 16 +++++++++++++ 10 files changed, 109 insertions(+), 61 deletions(-) diff --git a/acme/common.go b/acme/common.go index 577c35cd..71e10cb6 100644 --- a/acme/common.go +++ b/acme/common.go @@ -12,7 +12,7 @@ import ( // SignAuthority is the interface implemented by a CA authority. type SignAuthority interface { - Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) + Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) LoadProvisionerByID(string) (provisioner.Interface, error) } diff --git a/acme/order.go b/acme/order.go index 5133ca1b..8d22b7db 100644 --- a/acme/order.go +++ b/acme/order.go @@ -274,7 +274,7 @@ func (o *order) finalize(db nosql.DB, csr *x509.CertificateRequest, auth SignAut } // Create and store a new certificate. - leaf, inter, err := auth.Sign(csr, provisioner.Options{ + certChain, err := auth.Sign(csr, provisioner.Options{ NotBefore: provisioner.NewTimeDuration(o.NotBefore), NotAfter: provisioner.NewTimeDuration(o.NotAfter), }, signOps...) @@ -285,8 +285,8 @@ func (o *order) finalize(db nosql.DB, csr *x509.CertificateRequest, auth SignAut cert, err := newCert(db, CertOptions{ AccountID: o.AccountID, OrderID: o.ID, - Leaf: leaf, - Intermediates: []*x509.Certificate{inter}, + Leaf: certChain[0], + Intermediates: certChain[1:], }) if err != nil { return nil, err diff --git a/acme/order_test.go b/acme/order_test.go index 31601fae..18a46589 100644 --- a/acme/order_test.go +++ b/acme/order_test.go @@ -789,19 +789,19 @@ func TestOrderUpdateStatus(t *testing.T) { } type mockSignAuth struct { - sign func(csr *x509.CertificateRequest, signOpts provisioner.Options, extraOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) + sign func(csr *x509.CertificateRequest, signOpts provisioner.Options, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error) loadProvisionerByID func(string) (provisioner.Interface, error) ret1, ret2 interface{} err error } -func (m *mockSignAuth) Sign(csr *x509.CertificateRequest, signOpts provisioner.Options, extraOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) { +func (m *mockSignAuth) Sign(csr *x509.CertificateRequest, signOpts provisioner.Options, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error) { if m.sign != nil { return m.sign(csr, signOpts, extraOpts...) } else if m.err != nil { - return nil, nil, m.err + return nil, m.err } - return m.ret1.(*x509.Certificate), m.ret2.(*x509.Certificate), m.err + return []*x509.Certificate{m.ret1.(*x509.Certificate), m.ret2.(*x509.Certificate)}, m.err } func (m *mockSignAuth) LoadProvisionerByID(id string) (provisioner.Interface, error) { @@ -1082,9 +1082,9 @@ func TestOrderFinalize(t *testing.T) { res: clone, csr: csr, sa: &mockSignAuth{ - sign: func(csr *x509.CertificateRequest, pops provisioner.Options, signOps ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) { + sign: func(csr *x509.CertificateRequest, pops provisioner.Options, signOps ...provisioner.SignOption) ([]*x509.Certificate, error) { assert.Equals(t, len(signOps), 4) - return crt, inter, nil + return []*x509.Certificate{crt, inter}, nil }, }, db: &db.MockNoSQLDB{ diff --git a/api/api.go b/api/api.go index 3850d921..d1ff7d1d 100644 --- a/api/api.go +++ b/api/api.go @@ -33,8 +33,8 @@ type Authority interface { AuthorizeSign(ott string) ([]provisioner.SignOption, error) GetTLSOptions() *tlsutil.TLSOptions Root(shasum string) (*x509.Certificate, error) - Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) - Renew(peer *x509.Certificate) (*x509.Certificate, *x509.Certificate, error) + Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) + Renew(peer *x509.Certificate) ([]*x509.Certificate, error) LoadProvisionerByCertificate(*x509.Certificate) (provisioner.Interface, error) LoadProvisionerByID(string) (provisioner.Interface, error) GetProvisioners(cursor string, limit int) (provisioner.List, string, error) @@ -211,10 +211,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"` - TLSOptions *tlsutil.TLSOptions `json:"tlsOptions,omitempty"` - TLS *tls.ConnectionState `json:"-"` + ServerPEM Certificate `json:"crt"` + CaPEM Certificate `json:"ca"` + CertChainPEM []Certificate `json:"certChain"` + TLSOptions *tlsutil.TLSOptions `json:"tlsOptions,omitempty"` + TLS *tls.ConnectionState `json:"-"` } // RootsResponse is the response object of the roots request. @@ -275,6 +276,14 @@ func (h *caHandler) Root(w http.ResponseWriter, r *http.Request) { JSON(w, &RootResponse{RootPEM: Certificate{cert}}) } +func certChainToPEM(certChain []*x509.Certificate) []Certificate { + certChainPEM := make([]Certificate, 0, len(certChain)) + for _, c := range certChain { + certChainPEM = append(certChainPEM, Certificate{c}) + } + return certChainPEM +} + // Sign is an HTTP handler that reads a certificate request and an // one-time-token (ott) from the body and creates a new certificate with the // information in the certificate request. @@ -302,17 +311,22 @@ func (h *caHandler) Sign(w http.ResponseWriter, r *http.Request) { return } - cert, root, err := h.Authority.Sign(body.CsrPEM.CertificateRequest, opts, signOpts...) + certChain, err := h.Authority.Sign(body.CsrPEM.CertificateRequest, opts, signOpts...) if err != nil { WriteError(w, Forbidden(err)) return } - - logCertificate(w, cert) + certChainPEM := certChainToPEM(certChain) + var caPEM Certificate + if len(certChainPEM) > 0 { + caPEM = certChainPEM[1] + } + logCertificate(w, certChain[0]) JSONStatus(w, &SignResponse{ - ServerPEM: Certificate{cert}, - CaPEM: Certificate{root}, - TLSOptions: h.Authority.GetTLSOptions(), + ServerPEM: certChainPEM[0], + CaPEM: caPEM, + CertChainPEM: certChainPEM, + TLSOptions: h.Authority.GetTLSOptions(), }, http.StatusCreated) } @@ -324,17 +338,23 @@ func (h *caHandler) Renew(w http.ResponseWriter, r *http.Request) { return } - cert, root, err := h.Authority.Renew(r.TLS.PeerCertificates[0]) + certChain, err := h.Authority.Renew(r.TLS.PeerCertificates[0]) if err != nil { WriteError(w, Forbidden(err)) return } + certChainPEM := certChainToPEM(certChain) + var caPEM Certificate + if len(certChainPEM) > 0 { + caPEM = certChainPEM[1] + } - logCertificate(w, cert) + logCertificate(w, certChain[0]) JSONStatus(w, &SignResponse{ - ServerPEM: Certificate{cert}, - CaPEM: Certificate{root}, - TLSOptions: h.Authority.GetTLSOptions(), + ServerPEM: certChainPEM[0], + CaPEM: caPEM, + CertChainPEM: certChainPEM, + TLSOptions: h.Authority.GetTLSOptions(), }, http.StatusCreated) } diff --git a/api/api_test.go b/api/api_test.go index d141247c..a253f4cd 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -501,10 +501,10 @@ type mockAuthority struct { authorizeSign func(ott string) ([]provisioner.SignOption, error) getTLSOptions func() *tlsutil.TLSOptions root func(shasum string) (*x509.Certificate, error) - sign func(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) + sign func(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) signSSH func(key ssh.PublicKey, opts provisioner.SSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) signSSHAddUser func(key ssh.PublicKey, cert *ssh.Certificate) (*ssh.Certificate, error) - renew func(cert *x509.Certificate) (*x509.Certificate, *x509.Certificate, error) + renew func(cert *x509.Certificate) ([]*x509.Certificate, error) loadProvisionerByCertificate func(cert *x509.Certificate) (provisioner.Interface, error) loadProvisionerByID func(provID string) (provisioner.Interface, error) getProvisioners func(nextCursor string, limit int) (provisioner.List, string, error) @@ -540,11 +540,11 @@ func (m *mockAuthority) Root(shasum string) (*x509.Certificate, error) { return m.ret1.(*x509.Certificate), m.err } -func (m *mockAuthority) Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) { +func (m *mockAuthority) Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error) { if m.sign != nil { return m.sign(cr, opts, signOpts...) } - return m.ret1.(*x509.Certificate), m.ret2.(*x509.Certificate), m.err + return []*x509.Certificate{m.ret1.(*x509.Certificate), m.ret2.(*x509.Certificate)}, m.err } func (m *mockAuthority) SignSSH(key ssh.PublicKey, opts provisioner.SSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, error) { @@ -561,11 +561,11 @@ func (m *mockAuthority) SignSSHAddUser(key ssh.PublicKey, cert *ssh.Certificate) return m.ret1.(*ssh.Certificate), m.err } -func (m *mockAuthority) Renew(cert *x509.Certificate) (*x509.Certificate, *x509.Certificate, error) { +func (m *mockAuthority) Renew(cert *x509.Certificate) ([]*x509.Certificate, error) { if m.renew != nil { return m.renew(cert) } - return m.ret1.(*x509.Certificate), m.ret2.(*x509.Certificate), m.err + return []*x509.Certificate{m.ret1.(*x509.Certificate), m.ret2.(*x509.Certificate)}, m.err } func (m *mockAuthority) GetProvisioners(nextCursor string, limit int) (provisioner.List, string, error) { @@ -724,8 +724,8 @@ func Test_caHandler_Sign(t *testing.T) { t.Fatal(err) } - expected1 := []byte(`{"crt":"` + strings.Replace(certPEM, "\n", `\n`, -1) + `\n","ca":"` + strings.Replace(rootPEM, "\n", `\n`, -1) + `\n"}`) - expected2 := []byte(`{"crt":"` + strings.Replace(stepCertPEM, "\n", `\n`, -1) + `\n","ca":"` + strings.Replace(rootPEM, "\n", `\n`, -1) + `\n"}`) + expected1 := []byte(`{"crt":"` + strings.Replace(certPEM, "\n", `\n`, -1) + `\n","ca":"` + strings.Replace(rootPEM, "\n", `\n`, -1) + `\n","certChain":["` + strings.Replace(certPEM, "\n", `\n`, -1) + `\n","` + strings.Replace(rootPEM, "\n", `\n`, -1) + `\n"]}`) + expected2 := []byte(`{"crt":"` + strings.Replace(stepCertPEM, "\n", `\n`, -1) + `\n","ca":"` + strings.Replace(rootPEM, "\n", `\n`, -1) + `\n","certChain":["` + strings.Replace(stepCertPEM, "\n", `\n`, -1) + `\n","` + strings.Replace(rootPEM, "\n", `\n`, -1) + `\n"]}`) tests := []struct { name string @@ -798,7 +798,7 @@ func Test_caHandler_Renew(t *testing.T) { {"renew error", cs, nil, nil, fmt.Errorf("an error"), http.StatusForbidden}, } - expected := []byte(`{"crt":"` + strings.Replace(certPEM, "\n", `\n`, -1) + `\n","ca":"` + strings.Replace(rootPEM, "\n", `\n`, -1) + `\n"}`) + expected := []byte(`{"crt":"` + strings.Replace(certPEM, "\n", `\n`, -1) + `\n","ca":"` + strings.Replace(rootPEM, "\n", `\n`, -1) + `\n","certChain":["` + strings.Replace(certPEM, "\n", `\n`, -1) + `\n","` + strings.Replace(rootPEM, "\n", `\n`, -1) + `\n"]}`) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/authority/tls.go b/authority/tls.go index 84227667..eb20639e 100644 --- a/authority/tls.go +++ b/authority/tls.go @@ -56,7 +56,7 @@ func withDefaultASN1DN(def *x509util.ASN1DN) x509util.WithOption { } // Sign creates a signed certificate from a certificate signing request. -func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Options, extraOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) { +func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Options, extraOpts ...provisioner.SignOption) ([]*x509.Certificate, error) { var ( errContext = apiCtx{"csr": csr, "signOptions": signOpts} mods = []x509util.WithOption{withDefaultASN1DN(a.config.AuthorityConfig.Template)} @@ -69,66 +69,66 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Opti certValidators = append(certValidators, k) case provisioner.CertificateRequestValidator: if err := k.Valid(csr); err != nil { - return nil, nil, &apiError{errors.Wrap(err, "sign"), http.StatusUnauthorized, errContext} + return nil, &apiError{errors.Wrap(err, "sign"), http.StatusUnauthorized, errContext} } case provisioner.ProfileModifier: mods = append(mods, k.Option(signOpts)) default: - return nil, nil, &apiError{errors.Errorf("sign: invalid extra option type %T", k), + return nil, &apiError{errors.Errorf("sign: invalid extra option type %T", k), http.StatusInternalServerError, errContext} } } if err := csr.CheckSignature(); err != nil { - return nil, nil, &apiError{errors.Wrap(err, "sign: invalid certificate request"), + return nil, &apiError{errors.Wrap(err, "sign: invalid certificate request"), http.StatusBadRequest, errContext} } leaf, err := x509util.NewLeafProfileWithCSR(csr, issIdentity.Crt, issIdentity.Key, mods...) if err != nil { - return nil, nil, &apiError{errors.Wrapf(err, "sign"), http.StatusInternalServerError, errContext} + return nil, &apiError{errors.Wrapf(err, "sign"), http.StatusInternalServerError, errContext} } for _, v := range certValidators { if err := v.Valid(leaf.Subject()); err != nil { - return nil, nil, &apiError{errors.Wrap(err, "sign"), http.StatusUnauthorized, errContext} + return nil, &apiError{errors.Wrap(err, "sign"), http.StatusUnauthorized, errContext} } } crtBytes, err := leaf.CreateCertificate() if err != nil { - return nil, nil, &apiError{errors.Wrap(err, "sign: error creating new leaf certificate"), + return nil, &apiError{errors.Wrap(err, "sign: error creating new leaf certificate"), http.StatusInternalServerError, errContext} } serverCert, err := x509.ParseCertificate(crtBytes) if err != nil { - return nil, nil, &apiError{errors.Wrap(err, "sign: error parsing new leaf certificate"), + return nil, &apiError{errors.Wrap(err, "sign: error parsing new leaf certificate"), http.StatusInternalServerError, errContext} } caCert, err := x509.ParseCertificate(issIdentity.Crt.Raw) if err != nil { - return nil, nil, &apiError{errors.Wrap(err, "sign: error parsing intermediate certificate"), + return nil, &apiError{errors.Wrap(err, "sign: error parsing intermediate certificate"), http.StatusInternalServerError, errContext} } if err = a.db.StoreCertificate(serverCert); err != nil { if err != db.ErrNotImplemented { - return nil, nil, &apiError{errors.Wrap(err, "sign: error storing certificate in db"), + return nil, &apiError{errors.Wrap(err, "sign: error storing certificate in db"), http.StatusInternalServerError, errContext} } } - return serverCert, caCert, nil + return []*x509.Certificate{serverCert, caCert}, nil } // Renew creates a new Certificate identical to the old certificate, except // with a validity window that begins 'now'. -func (a *Authority) Renew(oldCert *x509.Certificate) (*x509.Certificate, *x509.Certificate, error) { +func (a *Authority) Renew(oldCert *x509.Certificate) ([]*x509.Certificate, error) { // Check step provisioner extensions if err := a.authorizeRenewal(oldCert); err != nil { - return nil, nil, err + return nil, err } // Issuer @@ -181,26 +181,26 @@ func (a *Authority) Renew(oldCert *x509.Certificate) (*x509.Certificate, *x509.C leaf, err := x509util.NewLeafProfileWithTemplate(newCert, issIdentity.Crt, issIdentity.Key) if err != nil { - return nil, nil, &apiError{err, http.StatusInternalServerError, apiCtx{}} + return nil, &apiError{err, http.StatusInternalServerError, apiCtx{}} } crtBytes, err := leaf.CreateCertificate() if err != nil { - return nil, nil, &apiError{errors.Wrap(err, "error renewing certificate from existing server certificate"), + return nil, &apiError{errors.Wrap(err, "error renewing certificate from existing server certificate"), http.StatusInternalServerError, apiCtx{}} } serverCert, err := x509.ParseCertificate(crtBytes) if err != nil { - return nil, nil, &apiError{errors.Wrap(err, "error parsing new server certificate"), + return nil, &apiError{errors.Wrap(err, "error parsing new server certificate"), http.StatusInternalServerError, apiCtx{}} } caCert, err := x509.ParseCertificate(issIdentity.Crt.Raw) if err != nil { - return nil, nil, &apiError{errors.Wrap(err, "error parsing intermediate certificate"), + return nil, &apiError{errors.Wrap(err, "error parsing intermediate certificate"), http.StatusInternalServerError, apiCtx{}} } - return serverCert, caCert, nil + return []*x509.Certificate{serverCert, caCert}, nil } // RevokeOptions are the options for the Revoke API. diff --git a/authority/tls_test.go b/authority/tls_test.go index 8d443fd4..3ad796c0 100644 --- a/authority/tls_test.go +++ b/authority/tls_test.go @@ -276,7 +276,7 @@ ttnEF4Rq8zqzr4fbv+AF451Mx36AkfgZr9XWGzxidrH+fBCNWXWNR+ymhrL6UFTG t.Run(name, func(t *testing.T) { tc := genTestCase(t) - leaf, intermediate, err := tc.auth.Sign(tc.csr, tc.signOpts, tc.extraOpts...) + certChain, err := tc.auth.Sign(tc.csr, tc.signOpts, tc.extraOpts...) if err != nil { if assert.NotNil(t, tc.err) { switch v := err.(type) { @@ -289,6 +289,8 @@ ttnEF4Rq8zqzr4fbv+AF451Mx36AkfgZr9XWGzxidrH+fBCNWXWNR+ymhrL6UFTG } } } else { + leaf := certChain[0] + intermediate := certChain[1] if assert.Nil(t, tc.err) { assert.Equals(t, leaf.NotBefore, signOpts.NotBefore.Time().Truncate(time.Second)) assert.Equals(t, leaf.NotAfter, signOpts.NotAfter.Time().Truncate(time.Second)) @@ -453,11 +455,11 @@ func TestRenew(t *testing.T) { tc, err := genTestCase() assert.FatalError(t, err) - var leaf, intermediate *x509.Certificate + var certChain []*x509.Certificate if tc.auth != nil { - leaf, intermediate, err = tc.auth.Renew(tc.crt) + certChain, err = tc.auth.Renew(tc.crt) } else { - leaf, intermediate, err = a.Renew(tc.crt) + certChain, err = a.Renew(tc.crt) } if err != nil { if assert.NotNil(t, tc.err) { @@ -471,6 +473,8 @@ func TestRenew(t *testing.T) { } } } else { + leaf := certChain[0] + intermediate := certChain[1] if assert.Nil(t, tc.err) { assert.Equals(t, leaf.NotAfter.Sub(leaf.NotBefore), tc.crt.NotAfter.Sub(crt.NotBefore)) diff --git a/ca/bootstrap_test.go b/ca/bootstrap_test.go index baa23d7e..3449b45a 100644 --- a/ca/bootstrap_test.go +++ b/ca/bootstrap_test.go @@ -303,7 +303,7 @@ func TestBootstrapClient(t *testing.T) { t.Errorf("BootstrapClient() error reading response: %v", err) return } - if renewal.CaPEM.Certificate == nil || renewal.ServerPEM.Certificate == nil { + if renewal.CaPEM.Certificate == nil || renewal.ServerPEM.Certificate == nil || len(renewal.CertChainPEM) == 0 { t.Errorf("BootstrapClient() invalid renewal response: %v", renewal) } } @@ -375,7 +375,7 @@ func TestBootstrapClientServerRotation(t *testing.T) { if err := readJSON(resp.Body, &renew); err != nil { return errors.Wrap(err, "client.Post() error reading response") } - if renew.ServerPEM.Certificate == nil || renew.CaPEM.Certificate == nil { + if renew.ServerPEM.Certificate == nil || renew.CaPEM.Certificate == nil || len(renew.CertChainPEM) == 0 { return errors.New("client.Post() unexpected response found") } // test with bootstrap server @@ -492,7 +492,7 @@ func TestBootstrapClientServerFederation(t *testing.T) { if err := readJSON(resp.Body, &renew); err != nil { return errors.Wrap(err, "client.Post() error reading response") } - if renew.ServerPEM.Certificate == nil || renew.CaPEM.Certificate == nil { + if renew.ServerPEM.Certificate == nil || renew.CaPEM.Certificate == nil || len(renew.CertChainPEM) == 0 { return errors.New("client.Post() unexpected response found") } // test with bootstrap server diff --git a/ca/client_test.go b/ca/client_test.go index 1c90e52b..dd9f7228 100644 --- a/ca/client_test.go +++ b/ca/client_test.go @@ -253,6 +253,10 @@ func TestClient_Sign(t *testing.T) { ok := &api.SignResponse{ ServerPEM: api.Certificate{Certificate: parseCertificate(certPEM)}, CaPEM: api.Certificate{Certificate: parseCertificate(rootPEM)}, + CertChainPEM: []api.Certificate{ + {Certificate: parseCertificate(certPEM)}, + {Certificate: parseCertificate(rootPEM)}, + }, } request := &api.SignRequest{ CsrPEM: api.CertificateRequest{CertificateRequest: parseCertificateRequest(csrPEM)}, @@ -406,6 +410,10 @@ func TestClient_Renew(t *testing.T) { ok := &api.SignResponse{ ServerPEM: api.Certificate{Certificate: parseCertificate(certPEM)}, CaPEM: api.Certificate{Certificate: parseCertificate(rootPEM)}, + CertChainPEM: []api.Certificate{ + {Certificate: parseCertificate(certPEM)}, + {Certificate: parseCertificate(rootPEM)}, + }, } unauthorized := api.Unauthorized(fmt.Errorf("Unauthorized")) badRequest := api.BadRequest(fmt.Errorf("Bad Request")) diff --git a/ca/tls_test.go b/ca/tls_test.go index b88e825a..bf29e9a6 100644 --- a/ca/tls_test.go +++ b/ca/tls_test.go @@ -417,6 +417,10 @@ func TestCertificate(t *testing.T) { ok := &api.SignResponse{ ServerPEM: api.Certificate{Certificate: cert}, CaPEM: api.Certificate{Certificate: parseCertificate(rootPEM)}, + CertChainPEM: []api.Certificate{ + {Certificate: cert}, + {Certificate: parseCertificate(rootPEM)}, + }, } tests := []struct { name string @@ -446,6 +450,10 @@ func TestIntermediateCertificate(t *testing.T) { ok := &api.SignResponse{ ServerPEM: api.Certificate{Certificate: parseCertificate(certPEM)}, CaPEM: api.Certificate{Certificate: intermediate}, + CertChainPEM: []api.Certificate{ + {Certificate: parseCertificate(certPEM)}, + {Certificate: intermediate}, + }, } tests := []struct { name string @@ -475,6 +483,10 @@ func TestRootCertificateCertificate(t *testing.T) { ok := &api.SignResponse{ ServerPEM: api.Certificate{Certificate: parseCertificate(certPEM)}, CaPEM: api.Certificate{Certificate: parseCertificate(rootPEM)}, + CertChainPEM: []api.Certificate{ + {Certificate: parseCertificate(certPEM)}, + {Certificate: parseCertificate(rootPEM)}, + }, TLS: &tls.ConnectionState{VerifiedChains: [][]*x509.Certificate{ {root, root}, }}, @@ -482,6 +494,10 @@ func TestRootCertificateCertificate(t *testing.T) { noTLS := &api.SignResponse{ ServerPEM: api.Certificate{Certificate: parseCertificate(certPEM)}, CaPEM: api.Certificate{Certificate: parseCertificate(rootPEM)}, + CertChainPEM: []api.Certificate{ + {Certificate: parseCertificate(certPEM)}, + {Certificate: parseCertificate(rootPEM)}, + }, } tests := []struct { name string