From 635c59ed24d3e16575ce15e536aecb1131e4ee65 Mon Sep 17 00:00:00 2001 From: max furman Date: Fri, 23 Aug 2019 12:09:16 -0700 Subject: [PATCH] Accept emails SANs --- Gopkg.lock | 6 ++--- authority/authorize_test.go | 8 ++----- authority/provisioner/jwk.go | 3 ++- authority/provisioner/jwk_test.go | 2 +- authority/provisioner/sign_options.go | 20 ++++++++++++++++ authority/provisioner/sign_options_test.go | 27 ++++++++++++++++++++++ ca/client.go | 3 +-- 7 files changed, 56 insertions(+), 13 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 9c49f222..0601e9fe 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -276,8 +276,8 @@ revision = "de77670473b5492f5d0bce155b5c01534c2d13f7" [[projects]] - branch = "master" - digest = "1:8eb842c27bca9dae16d77baeba7cf612135033da381faf833bb8c11c29a751c7" + branch = "email" + digest = "1:cef75c86c34990ab5ed7826c35b8241474302c8264c64a0207c155229784479c" name = "github.com/smallstep/cli" packages = [ "command", @@ -298,7 +298,7 @@ "utils", ] pruneopts = "UT" - revision = "98635d188cade54451e3997b530716297ce7fc00" + revision = "18e04f77ce327f282a5265dec5f35ec612868838" [[projects]] branch = "master" diff --git a/authority/authorize_test.go b/authority/authorize_test.go index 368e9807..03a1139f 100644 --- a/authority/authorize_test.go +++ b/authority/authorize_test.go @@ -65,7 +65,6 @@ func TestAuthority_authorizeToken(t *testing.T) { auth *Authority ott string err *apiError - res []interface{} } tests := map[string]func(t *testing.T) *authorizeTest{ "fail/invalid-ott": func(t *testing.T) *authorizeTest { @@ -273,7 +272,6 @@ func TestAuthority_authorizeRevoke(t *testing.T) { auth *Authority opts *RevokeOptions err error - res []interface{} } tests := map[string]func(t *testing.T) *authorizeTest{ "fail/token/invalid-ott": func(t *testing.T) *authorizeTest { @@ -383,7 +381,6 @@ func TestAuthority_AuthorizeSign(t *testing.T) { auth *Authority ott string err *apiError - res []interface{} } tests := map[string]func(t *testing.T) *authorizeTest{ "fail/invalid-ott": func(t *testing.T) *authorizeTest { @@ -449,7 +446,7 @@ func TestAuthority_AuthorizeSign(t *testing.T) { } } else { if assert.Nil(t, tc.err) { - assert.Len(t, 6, got) + assert.Len(t, 7, got) } } }) @@ -476,7 +473,6 @@ func TestAuthority_Authorize(t *testing.T) { auth *Authority ott string err *apiError - res []interface{} } tests := map[string]func(t *testing.T) *authorizeTest{ "fail/invalid-ott": func(t *testing.T) *authorizeTest { @@ -542,7 +538,7 @@ func TestAuthority_Authorize(t *testing.T) { } } else { if assert.Nil(t, tc.err) { - assert.Len(t, 6, got) + assert.Len(t, 7, got) } } }) diff --git a/authority/provisioner/jwk.go b/authority/provisioner/jwk.go index dca5dce9..d0b08fa1 100644 --- a/authority/provisioner/jwk.go +++ b/authority/provisioner/jwk.go @@ -141,11 +141,12 @@ func (p *JWK) AuthorizeSign(token string) ([]SignOption, error) { claims.SANs = []string{claims.Subject} } - dnsNames, ips := x509util.SplitSANs(claims.SANs) + dnsNames, ips, emails := x509util.SplitSANs(claims.SANs) return []SignOption{ commonNameValidator(claims.Subject), dnsNamesValidator(dnsNames), ipAddressesValidator(ips), + emailAddressesValidator(emails), profileDefaultDuration(p.claimer.DefaultTLSCertDuration()), newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID), newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()), diff --git a/authority/provisioner/jwk_test.go b/authority/provisioner/jwk_test.go index 21789ca8..0f45744a 100644 --- a/authority/provisioner/jwk_test.go +++ b/authority/provisioner/jwk_test.go @@ -265,7 +265,7 @@ func TestJWK_AuthorizeSign(t *testing.T) { } } else { if assert.NotNil(t, got) { - assert.Len(t, 6, got) + assert.Len(t, 7, got) _cnv := got[0] cnv, ok := _cnv.(commonNameValidator) diff --git a/authority/provisioner/sign_options.go b/authority/provisioner/sign_options.go index fa7e1d6f..a106e9de 100644 --- a/authority/provisioner/sign_options.go +++ b/authority/provisioner/sign_options.go @@ -157,6 +157,26 @@ func (v ipAddressesValidator) Valid(req *x509.CertificateRequest) error { return nil } +// emailAddressesValidator validates the email address SANs of a certificate request. +type emailAddressesValidator []string + +// Valid checks that certificate request IP Addresses match those configured in +// the bootstrap (token) flow. +func (v emailAddressesValidator) Valid(req *x509.CertificateRequest) error { + want := make(map[string]bool) + for _, s := range v { + want[s] = true + } + got := make(map[string]bool) + for _, s := range req.EmailAddresses { + got[s] = true + } + if !reflect.DeepEqual(want, got) { + return errors.Errorf("certificate request does not contain the valid Email Addresses - got %v, want %v", req.EmailAddresses, v) + } + return nil +} + // validityValidator validates the certificate temporal validity settings. type validityValidator struct { min time.Duration diff --git a/authority/provisioner/sign_options_test.go b/authority/provisioner/sign_options_test.go index 18e5b8d2..bc6d7414 100644 --- a/authority/provisioner/sign_options_test.go +++ b/authority/provisioner/sign_options_test.go @@ -88,6 +88,33 @@ func Test_commonNameSliceValidator_Valid(t *testing.T) { } } +func Test_emailAddressesValidator_Valid(t *testing.T) { + type args struct { + req *x509.CertificateRequest + } + tests := []struct { + name string + v emailAddressesValidator + args args + wantErr bool + }{ + {"ok0", []string{}, args{&x509.CertificateRequest{EmailAddresses: []string{}}}, false}, + {"ok1", []string{"max@smallstep.com"}, args{&x509.CertificateRequest{EmailAddresses: []string{"max@smallstep.com"}}}, false}, + {"ok2", []string{"max@step.com", "mike@step.com"}, args{&x509.CertificateRequest{EmailAddresses: []string{"max@step.com", "mike@step.com"}}}, false}, + {"ok3", []string{"max@step.com", "mike@step.com"}, args{&x509.CertificateRequest{EmailAddresses: []string{"mike@step.com", "max@step.com"}}}, false}, + {"fail1", []string{"max@step.com"}, args{&x509.CertificateRequest{EmailAddresses: []string{"mike@step.com"}}}, true}, + {"fail2", []string{"mike@step.com"}, args{&x509.CertificateRequest{EmailAddresses: []string{"max@step.com", "mike@step.com"}}}, true}, + {"fail3", []string{"mike@step.com", "max@step.com"}, args{&x509.CertificateRequest{DNSNames: []string{"mike@step.com", "mex@step.com"}}}, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := tt.v.Valid(tt.args.req); (err != nil) != tt.wantErr { + t.Errorf("dnsNamesValidator.Valid() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + func Test_dnsNamesValidator_Valid(t *testing.T) { type args struct { req *x509.CertificateRequest diff --git a/ca/client.go b/ca/client.go index c9766293..6ac16e8a 100644 --- a/ca/client.go +++ b/ca/client.go @@ -541,8 +541,7 @@ func CreateSignRequest(ott string) (*api.SignRequest, crypto.PrivateKey, error) return nil, nil, errors.Wrap(err, "error generating key") } - var emails []string - dnsNames, ips := x509util.SplitSANs(claims.SANs) + dnsNames, ips, emails := x509util.SplitSANs(claims.SANs) if claims.Email != "" { emails = append(emails, claims.Email) }