diff --git a/Gopkg.lock b/Gopkg.lock index daa327002..f5485cc96 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -311,7 +311,7 @@ [[projects]] branch = "master" - digest = "1:875a13bf23c93e78f7759f10131b2de18f672a500cd2958ae845391f9582105a" + digest = "1:4f1ae73851c1c30b0a5c5256f77a0f6c718110bdf6f4f31e7af374b2fdc3185e" name = "github.com/smallstep/certificates" packages = [ "acme", @@ -326,7 +326,7 @@ "server", ] pruneopts = "UT" - revision = "397c6466a275a80dcdafbd5794019f6dcb2cd8ff" + revision = "0a96062b7696db218cf42c046e8dbec19b176114" [[projects]] branch = "master" diff --git a/command/ca/renew.go b/command/ca/renew.go index 6da77150d..358337986 100644 --- a/command/ca/renew.go +++ b/command/ca/renew.go @@ -400,16 +400,17 @@ func (r *renewer) Renew(outFile string) (*api.SignResponse, error) { return nil, errors.Wrap(err, "error renewing certificate") } - serverBlock, err := pemutil.Serialize(resp.ServerPEM.Certificate) - if err != nil { - return nil, err + if resp.CertChainPEM == nil || len(resp.CertChainPEM) == 0 { + resp.CertChainPEM = []api.Certificate{resp.ServerPEM, resp.CaPEM} } - caBlock, err := pemutil.Serialize(resp.CaPEM.Certificate) - if err != nil { - return nil, err + var data []byte + for _, certPEM := range resp.CertChainPEM { + pemblk, err := pemutil.Serialize(certPEM) + if err != nil { + return nil, errors.Wrap(err, "error serializing certificate PEM") + } + data = append(data, pem.EncodeToMemory(pemblk)...) } - data := append(pem.EncodeToMemory(serverBlock), pem.EncodeToMemory(caBlock)...) - if err := utils.WriteFile(outFile, data, 0600); err != nil { return nil, errs.FileError(err, outFile) } diff --git a/utils/cautils/certificate_flow.go b/utils/cautils/certificate_flow.go index e117ff77d..acf305be8 100644 --- a/utils/cautils/certificate_flow.go +++ b/utils/cautils/certificate_flow.go @@ -199,15 +199,17 @@ func (f *CertificateFlow) Sign(ctx *cli.Context, token string, csr api.Certifica return err } - serverBlock, err := pemutil.Serialize(resp.ServerPEM.Certificate) - if err != nil { - return err + if resp.CertChainPEM == nil || len(resp.CertChainPEM) == 0 { + resp.CertChainPEM = []api.Certificate{resp.ServerPEM, resp.CaPEM} } - caBlock, err := pemutil.Serialize(resp.CaPEM.Certificate) - if err != nil { - return err + var data []byte + for _, certPEM := range resp.CertChainPEM { + pemblk, err := pemutil.Serialize(certPEM) + if err != nil { + return errors.Wrap(err, "error serializing from step-ca API response") + } + data = append(data, pem.EncodeToMemory(pemblk)...) } - data := append(pem.EncodeToMemory(serverBlock), pem.EncodeToMemory(caBlock)...) return utils.WriteFile(crtFile, data, 0600) } diff --git a/utils/cautils/offline.go b/utils/cautils/offline.go index 2965fe341..dbc1039f7 100644 --- a/utils/cautils/offline.go +++ b/utils/cautils/offline.go @@ -137,6 +137,14 @@ func (c *OfflineCA) Provisioners() provisioner.List { return c.config.AuthorityConfig.Provisioners } +func certChainToPEM(certChain []*x509.Certificate) []api.Certificate { + certChainPEM := make([]api.Certificate, 0, len(certChain)) + for _, c := range certChain { + certChainPEM = append(certChainPEM, api.Certificate{Certificate: c}) + } + return certChainPEM +} + // Sign is a wrapper on top of certificates Authorize and Sign methods. It // returns an api.SignResponse with the requested certificate and the // intermediate. @@ -150,14 +158,20 @@ func (c *OfflineCA) Sign(req *api.SignRequest) (*api.SignResponse, error) { NotBefore: req.NotBefore, NotAfter: req.NotAfter, } - cert, ca, err := c.authority.Sign(req.CsrPEM.CertificateRequest, signOpts, opts...) + certChain, err := c.authority.Sign(req.CsrPEM.CertificateRequest, signOpts, opts...) if err != nil { return nil, err } + certChainPEM := certChainToPEM(certChain) + var caPEM api.Certificate + if len(certChainPEM) > 1 { + caPEM = certChainPEM[1] + } return &api.SignResponse{ - ServerPEM: api.Certificate{Certificate: cert}, - CaPEM: api.Certificate{Certificate: ca}, - TLSOptions: c.authority.GetTLSOptions(), + ServerPEM: certChainPEM[0], + CaPEM: caPEM, + CertChainPEM: certChainPEM, + TLSOptions: c.authority.GetTLSOptions(), }, nil } @@ -201,14 +215,20 @@ func (c *OfflineCA) Renew(rt http.RoundTripper) (*api.SignResponse, error) { return nil, errors.Wrap(err, "error parsing certificate") } // renew cert using authority - cert, ca, err := c.authority.Renew(peer) + certChain, err := c.authority.Renew(peer) if err != nil { return nil, err } + certChainPEM := certChainToPEM(certChain) + var caPEM api.Certificate + if len(certChainPEM) > 1 { + caPEM = certChainPEM[1] + } return &api.SignResponse{ - ServerPEM: api.Certificate{Certificate: cert}, - CaPEM: api.Certificate{Certificate: ca}, - TLSOptions: c.authority.GetTLSOptions(), + ServerPEM: certChainPEM[0], + CaPEM: caPEM, + CertChainPEM: certChainPEM, + TLSOptions: c.authority.GetTLSOptions(), }, nil }