Change api of functions Authority.Sign, Authority.Renew

Returns certificate chain instead of 2 members.

Implements #126
This commit is contained in:
Jozef Kralik 2019-10-09 21:57:12 +02:00
parent e2858e17b0
commit bc6074f596
10 changed files with 109 additions and 61 deletions

View file

@ -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)
}

View file

@ -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) {