This commit is contained in:
max furman 2020-06-23 11:10:45 -07:00
parent 2ebfc73f77
commit 1951669e13
12 changed files with 122 additions and 20 deletions

View file

@ -308,6 +308,16 @@ func (o *order) finalize(db nosql.DB, csr *x509.CertificateRequest, auth SignAut
}
}
if len(csr.IPAddresses) > 0 {
return nil, BadCSRErr(errors.Errorf("CSR contains IP Address SANs, but should only contain DNS Names"))
}
if len(csr.EmailAddresses) > 0 {
return nil, BadCSRErr(errors.Errorf("CSR contains Email Address SANs, but should only contain DNS Names"))
}
if len(csr.URIs) > 0 {
return nil, BadCSRErr(errors.Errorf("CSR contains URI SANs, but should only contain DNS Names"))
}
// Get authorizations from the ACME provisioner.
ctx := provisioner.NewContextWithMethod(context.Background(), provisioner.SignMethod)
signOps, err := p.AuthorizeSign(ctx, "")

View file

@ -287,6 +287,8 @@ func (p *AWS) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
so = append(so, ipAddressesValidator([]net.IP{
net.ParseIP(doc.PrivateIP),
}))
so = append(so, emailAddressesValidator(nil))
so = append(so, urisValidator(nil))
}
return append(so,

View file

@ -284,6 +284,9 @@ func (p *Azure) AuthorizeSign(ctx context.Context, token string) ([]SignOption,
// name will work only inside the virtual network
so = append(so, commonNameValidator(name))
so = append(so, dnsNamesValidator([]string{name}))
so = append(so, ipAddressesValidator(nil))
so = append(so, emailAddressesValidator(nil))
so = append(so, urisValidator(nil))
}
return append(so,

View file

@ -228,6 +228,9 @@ func (p *GCP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
so = append(so, dnsNamesValidator([]string{
dnsName1, dnsName2,
}))
so = append(so, ipAddressesValidator(nil))
so = append(so, emailAddressesValidator(nil))
so = append(so, urisValidator(nil))
}
return append(so,

View file

@ -8,7 +8,6 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/cli/crypto/x509util"
"github.com/smallstep/cli/jose"
)
@ -152,19 +151,15 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
claims.SANs = []string{claims.Subject}
}
dnsNames, ips, emails := x509util.SplitSANs(claims.SANs)
return []SignOption{
return append([]SignOption{
// modifiers / withOptions
newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID),
profileDefaultDuration(p.claimer.DefaultTLSCertDuration()),
// validators
commonNameValidator(claims.Subject),
defaultPublicKeyValidator{},
dnsNamesValidator(dnsNames),
emailAddressesValidator(emails),
ipAddressesValidator(ips),
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
}, nil
}, sansValidators(claims.SANs)), nil
}
// AuthorizeRenew returns an error if the renewal is disabled.

View file

@ -7,6 +7,7 @@ import (
"crypto/x509/pkix"
"encoding/asn1"
"net"
"net/url"
"reflect"
"time"
@ -195,6 +196,50 @@ func (v emailAddressesValidator) Valid(req *x509.CertificateRequest) error {
return nil
}
// urisValidator validates the URI SANs of a certificate request.
type urisValidator []*url.URL
// Valid checks that certificate request IP Addresses match those configured in
// the bootstrap (token) flow.
func (v urisValidator) Valid(req *x509.CertificateRequest) error {
want := make(map[string]bool)
for _, u := range v {
want[u.String()] = true
}
got := make(map[string]bool)
for _, u := range req.URIs {
got[u.String()] = true
}
if !reflect.DeepEqual(want, got) {
return errors.Errorf("URIs claim failed - got %v, want %v", req.URIs, v)
}
return nil
}
func sansValidators(sans []string) []SignOption {
dnsNames, ips, emails, uris := x509util.SplitSANs(sans)
return []SignOption{dnsNamesValidator(dnsNames), emailAddressesValidator(emails),
ipAddressesValidator(ips), urisValidator(uris)}
}
// ExtraExtensionsEnforcer enforces only those extra extensions that are strictly
// managed by step-ca. All other "extra extensions" are dropped.
type ExtraExtensionsEnforcer struct{}
// Enforce removes all extensions except the step provisioner extension, if it
// exists. If the step provisioner extension is not present, then remove all
// extra extensions from the cert.
func (eee ExtraExtensionsEnforcer) Enforce(cert *x509.Certificate) error {
for _, ext := range cert.Extensions {
if ext.Id.Equal(stepOIDProvisioner) {
cert.ExtraExtensions = []pkix.Extension{ext}
return nil
}
}
cert.ExtraExtensions = nil
return nil
}
// profileDefaultDuration is a wrapper against x509util.WithOption to conform
// the SignOption interface.
type profileDefaultDuration time.Duration

View file

@ -246,6 +246,42 @@ func Test_ipAddressesValidator_Valid(t *testing.T) {
}
}
func Test_urisValidator_Valid(t *testing.T) {
u1, err := url.Parse("https://ca.smallstep.com")
assert.FatalError(t, err)
u2, err := url.Parse("https://google.com/index.html")
assert.FatalError(t, err)
u3, err := url.Parse("https://foo.bar.baz")
assert.FatalError(t, err)
fu, err := url.Parse("https://unexpected.com")
assert.FatalError(t, err)
type args struct {
req *x509.CertificateRequest
}
tests := []struct {
name string
v urisValidator
args args
wantErr bool
}{
{"ok0", []*url.URL{}, args{&x509.CertificateRequest{URIs: []*url.URL{}}}, false},
{"ok1", []*url.URL{u1}, args{&x509.CertificateRequest{URIs: []*url.URL{u1}}}, false},
{"ok2", []*url.URL{u1, u2}, args{&x509.CertificateRequest{URIs: []*url.URL{u2, u1}}}, false},
{"ok3", []*url.URL{u2, u1, u3}, args{&x509.CertificateRequest{URIs: []*url.URL{u3, u2, u1}}}, false},
{"fail1", []*url.URL{u1}, args{&x509.CertificateRequest{URIs: []*url.URL{u2}}}, true},
{"fail2", []*url.URL{u1}, args{&x509.CertificateRequest{URIs: []*url.URL{u2, u1}}}, true},
{"fail3", []*url.URL{u1, u2}, args{&x509.CertificateRequest{URIs: []*url.URL{u1, fu}}}, 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("urisValidator.Valid() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func Test_validityValidator_Valid(t *testing.T) {
type test struct {
cert *x509.Certificate

View file

@ -9,7 +9,6 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/errs"
"github.com/smallstep/cli/crypto/x509util"
"github.com/smallstep/cli/jose"
)
@ -194,9 +193,7 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
claims.SANs = []string{claims.Subject}
}
dnsNames, ips, emails := x509util.SplitSANs(claims.SANs)
return []SignOption{
return append([]SignOption{
// modifiers / withOptions
newProvisionerExtensionOption(TypeX5C, p.Name, ""),
profileLimitDuration{p.claimer.DefaultTLSCertDuration(),
@ -204,11 +201,8 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
// validators
commonNameValidator(claims.Subject),
defaultPublicKeyValidator{},
dnsNamesValidator(dnsNames),
emailAddressesValidator(emails),
ipAddressesValidator(ips),
newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()),
}, nil
}, sansValidators(claims.SANs)), nil
}
// AuthorizeRenew returns an error if the renewal is disabled.

View file

@ -103,8 +103,8 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Opti
}
}
// Certificate modifier after validation
for _, m := range forcedModifiers {
// Certificate modifiers after validation
for _, m := range append(forcedModifiers, provisioner.ExtraExtensionsEnforcer{}) {
if err := m.Enforce(leaf.Subject()); err != nil {
return nil, errs.Wrap(http.StatusUnauthorized, err, "authority.Sign", opts...)
}

View file

@ -1066,7 +1066,7 @@ func CreateSignRequest(ott string) (*api.SignRequest, crypto.PrivateKey, error)
return nil, nil, errors.Wrap(err, "error generating key")
}
dnsNames, ips, emails := x509util.SplitSANs(claims.SANs)
dnsNames, ips, emails, uris := x509util.SplitSANs(claims.SANs)
if claims.Email != "" {
emails = append(emails, claims.Email)
}
@ -1079,6 +1079,7 @@ func CreateSignRequest(ott string) (*api.SignRequest, crypto.PrivateKey, error)
DNSNames: dnsNames,
IPAddresses: ips,
EmailAddresses: emails,
URIs: uris,
}
csr, err := x509.CreateCertificateRequest(rand.Reader, template, pk)
@ -1137,7 +1138,7 @@ func createCertificateRequest(commonName string, sans []string, key crypto.Priva
if len(sans) == 0 {
sans = []string{commonName}
}
dnsNames, ips, emails := x509util.SplitSANs(sans)
dnsNames, ips, emails, uris := x509util.SplitSANs(sans)
template := &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: commonName,
@ -1145,6 +1146,7 @@ func createCertificateRequest(commonName string, sans []string, key crypto.Priva
DNSNames: dnsNames,
IPAddresses: ips,
EmailAddresses: emails,
URIs: uris,
}
csr, err := x509.CreateCertificateRequest(rand.Reader, template, key)
if err != nil {

3
go.mod
View file

@ -27,5 +27,6 @@ require (
gopkg.in/square/go-jose.v2 v2.4.0
)
//replace github.com/smallstep/cli => ../cli
replace github.com/smallstep/cli => ../cli
//replace github.com/smallstep/nosql => ../nosql

11
go.sum
View file

@ -21,12 +21,16 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/semver/v3 v3.0.1 h1:2kKm5lb7dKVrt5TYUiAavE6oFc1cFT0057UVGT+JqLk=
github.com/Masterminds/semver/v3 v3.0.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/sprig/v3 v3.0.0 h1:KSQz7Nb08/3VU9E4ns29dDxcczhOD1q7O1UfM4G3t3g=
github.com/Masterminds/sprig/v3 v3.0.0/go.mod h1:NEUY/Qq8Gdm2xgYA+NwJM6wmfdRV9xkh8h/Rld20R0U=
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
@ -55,6 +59,7 @@ github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQ
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bombsimon/wsl/v2 v2.0.0 h1:+Vjcn+/T5lSrO8Bjzhk4v14Un/2UyCA1E3V5j9nwTkQ=
github.com/bombsimon/wsl/v2 v2.0.0/go.mod h1:mf25kr/SqFEPhhcxW1+7pxzGlW+hIl/hYTKY95VwV8U=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
@ -68,6 +73,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@ -83,6 +89,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@ -273,6 +280,7 @@ github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
@ -290,6 +298,7 @@ github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU
github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM=
@ -372,6 +381,7 @@ github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
github.com/newrelic/go-agent v2.15.0+incompatible h1:IB0Fy+dClpBq9aEoIrLyQXzU34JyI1xVTanPLB/+jvU=
github.com/newrelic/go-agent v2.15.0+incompatible/go.mod h1:a8Fv1b/fYhFSReoTU6HDkTYIMZeSVNffmoS726Y0LzQ=
github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
@ -792,6 +802,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I=
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo=