Skip to content

Commit e6e8443

Browse files
committed
allow multiple identical SANs in cert
1 parent f0683c2 commit e6e8443

8 files changed

+95
-75
lines changed

Gopkg.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ required = [
4545
name = "github.com/go-chi/chi"
4646

4747
[[override]]
48-
branch = "master"
48+
branch = "sans"
4949
name = "github.com/smallstep/cli"
5050

5151
[prune]

authority/claims.go

+19-25
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package authority
22

33
import (
4-
"bytes"
5-
"fmt"
64
"net"
7-
"sort"
5+
"reflect"
86
"time"
97

108
"github.com/pkg/errors"
@@ -50,17 +48,16 @@ type dnsNamesClaim struct {
5048

5149
// Valid checks that certificate request common name matches the one configured.
5250
func (c *dnsNamesClaim) Valid(crt *x509.Certificate) error {
53-
sort.Strings(c.names)
54-
sort.Strings(crt.DNSNames)
55-
if len(c.names) != len(crt.DNSNames) {
56-
fmt.Printf("len(c.names) = %+v, len(crt.DNSNames) = %+v\n", len(c.names), len(crt.DNSNames))
57-
return errors.Errorf("DNS names claim failed - got %s, want %s", crt.DNSNames, c.names)
51+
tokMap := make(map[string]int)
52+
for _, e := range c.names {
53+
tokMap[e] = 1
5854
}
59-
for i := range c.names {
60-
if c.names[i] != crt.DNSNames[i] {
61-
fmt.Printf("c.names[i] = %+v, crt.DNSNames[i] = %+v\n", c.names[i], crt.DNSNames[i])
62-
return errors.Errorf("DNS names claim failed - got %s, want %s", crt.DNSNames, c.names)
63-
}
55+
crtMap := make(map[string]int)
56+
for _, e := range crt.DNSNames {
57+
crtMap[e] = 1
58+
}
59+
if !reflect.DeepEqual(tokMap, crtMap) {
60+
return errors.Errorf("DNS names claim failed - got %s, want %s", crt.DNSNames, c.names)
6461
}
6562
return nil
6663
}
@@ -71,19 +68,16 @@ type ipAddressesClaim struct {
7168

7269
// Valid checks that certificate request common name matches the one configured.
7370
func (c *ipAddressesClaim) Valid(crt *x509.Certificate) error {
74-
if len(c.ips) != len(crt.IPAddresses) {
75-
return errors.Errorf("IP Addresses claim failed - got %v, want %v", crt.IPAddresses, c.ips)
71+
tokMap := make(map[string]int)
72+
for _, e := range c.ips {
73+
tokMap[e.String()] = 1
7674
}
77-
sort.Slice(c.ips, func(i, j int) bool {
78-
return bytes.Compare(c.ips[i], c.ips[j]) < 0
79-
})
80-
sort.Slice(crt.IPAddresses, func(i, j int) bool {
81-
return bytes.Compare(crt.IPAddresses[i], crt.IPAddresses[j]) < 0
82-
})
83-
for i := range c.ips {
84-
if !c.ips[i].Equal(crt.IPAddresses[i]) {
85-
return errors.Errorf("IP Addresses claim failed - got %v, want %v", crt.IPAddresses[i], c.ips[i])
86-
}
75+
crtMap := make(map[string]int)
76+
for _, e := range crt.IPAddresses {
77+
crtMap[e.String()] = 1
78+
}
79+
if !reflect.DeepEqual(tokMap, crtMap) {
80+
return errors.Errorf("IP Addresses claim failed - got %v, want %v", crt.IPAddresses, c.ips)
8781
}
8882
return nil
8983
}

authority/claims_test.go

+24-18
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,28 @@ func TestIPAddressesClaim_Valid(t *testing.T) {
5252
crt *x509.Certificate
5353
err error
5454
}{
55-
"unexpected-ip": {
56-
iac: &ipAddressesClaim{name: "127.0.0.1"},
55+
"unexpected-ip-in-crt": {
56+
iac: &ipAddressesClaim{ips: []net.IP{net.ParseIP("127.0.0.1")}},
5757
crt: &x509.Certificate{IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("1.1.1.1")}},
58-
err: errors.New("IP addresses claim failed - got 1.1.1.1, want 127.0.0.1"),
58+
err: errors.New("IP Addresses claim failed - got [127.0.0.1 1.1.1.1], want [127.0.0.1]"),
59+
},
60+
"missing-ip-in-crt": {
61+
iac: &ipAddressesClaim{ips: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("1.1.1.1")}},
62+
crt: &x509.Certificate{IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}},
63+
err: errors.New("IP Addresses claim failed - got [127.0.0.1], want [127.0.0.1 1.1.1.1]"),
5964
},
6065
"invalid-matcher-nonempty-ips": {
61-
iac: &ipAddressesClaim{name: "invalid"},
66+
iac: &ipAddressesClaim{ips: []net.IP{}},
6267
crt: &x509.Certificate{IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}},
63-
err: errors.New("IP addresses claim failed - got [127.0.0.1], want none"),
68+
err: errors.New("IP Addresses claim failed - got [127.0.0.1], want []"),
6469
},
6570
"ok": {
66-
iac: &ipAddressesClaim{name: "127.0.0.1"},
71+
iac: &ipAddressesClaim{ips: []net.IP{net.ParseIP("127.0.0.1")}},
6772
crt: &x509.Certificate{IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}},
6873
},
69-
"ok-empty-ips": {
70-
iac: &ipAddressesClaim{name: "127.0.0.1"},
71-
crt: &x509.Certificate{IPAddresses: []net.IP{}},
74+
"ok-multiple-identical-ip-entries": {
75+
iac: &ipAddressesClaim{ips: []net.IP{net.ParseIP("127.0.0.1")}},
76+
crt: &x509.Certificate{IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("127.0.0.1"), net.ParseIP("127.0.0.1")}},
7277
},
7378
}
7479

@@ -92,21 +97,22 @@ func TestDNSNamesClaim_Valid(t *testing.T) {
9297
crt *x509.Certificate
9398
err error
9499
}{
95-
"wrong-dns-name": {
96-
dnc: &dnsNamesClaim{name: "foo"},
100+
"unexpected-dns-name-in-crt": {
101+
dnc: &dnsNamesClaim{names: []string{"foo"}},
97102
crt: &x509.Certificate{DNSNames: []string{"foo", "bar"}},
98-
err: errors.New("DNS names claim failed - got bar, want foo"),
103+
err: errors.New("DNS names claim failed - got [foo bar], want [foo]"),
99104
},
100105
"ok": {
101-
dnc: &dnsNamesClaim{name: "foo"},
102-
crt: &x509.Certificate{DNSNames: []string{"foo"}},
106+
dnc: &dnsNamesClaim{names: []string{"foo", "bar"}},
107+
crt: &x509.Certificate{DNSNames: []string{"bar", "foo"}},
103108
},
104-
"ok-empty-dnsNames": {
105-
dnc: &dnsNamesClaim{"foo"},
106-
crt: &x509.Certificate{},
109+
"missing-dns-name-in-crt": {
110+
dnc: &dnsNamesClaim{names: []string{"foo", "bar"}},
111+
crt: &x509.Certificate{DNSNames: []string{"foo"}},
112+
err: errors.New("DNS names claim failed - got [foo], want [foo bar]"),
107113
},
108114
"ok-multiple-identical-dns-entries": {
109-
dnc: &dnsNamesClaim{name: "foo"},
115+
dnc: &dnsNamesClaim{names: []string{"foo"}},
110116
crt: &x509.Certificate{DNSNames: []string{"foo", "foo", "foo"}},
111117
},
112118
}

authority/tls.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,15 @@ func (a *Authority) Renew(ocx *x509.Certificate) (*x509.Certificate, *x509.Certi
197197
ExtKeyUsage: oldCert.ExtKeyUsage,
198198
UnknownExtKeyUsage: oldCert.UnknownExtKeyUsage,
199199
BasicConstraintsValid: oldCert.BasicConstraintsValid,
200-
IsCA: oldCert.IsCA,
201-
MaxPathLen: oldCert.MaxPathLen,
202-
MaxPathLenZero: oldCert.MaxPathLenZero,
203-
OCSPServer: oldCert.OCSPServer,
204-
IssuingCertificateURL: oldCert.IssuingCertificateURL,
205-
DNSNames: oldCert.DNSNames,
206-
EmailAddresses: oldCert.EmailAddresses,
207-
IPAddresses: oldCert.IPAddresses,
208-
URIs: oldCert.URIs,
200+
IsCA: oldCert.IsCA,
201+
MaxPathLen: oldCert.MaxPathLen,
202+
MaxPathLenZero: oldCert.MaxPathLenZero,
203+
OCSPServer: oldCert.OCSPServer,
204+
IssuingCertificateURL: oldCert.IssuingCertificateURL,
205+
DNSNames: oldCert.DNSNames,
206+
EmailAddresses: oldCert.EmailAddresses,
207+
IPAddresses: oldCert.IPAddresses,
208+
URIs: oldCert.URIs,
209209
PermittedDNSDomainsCritical: oldCert.PermittedDNSDomainsCritical,
210210
PermittedDNSDomains: oldCert.PermittedDNSDomains,
211211
ExcludedDNSDomains: oldCert.ExcludedDNSDomains,

ca/bootstrap_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ func generateBootstrapToken(ca, subject, sha string) string {
9494
cl := struct {
9595
SHA string `json:"sha"`
9696
jwt.Claims
97+
SANS []string `json:"sans"`
9798
}{
9899
SHA: sha,
99100
Claims: jwt.Claims{
@@ -104,6 +105,7 @@ func generateBootstrapToken(ca, subject, sha string) string {
104105
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
105106
Audience: []string{ca + "/sign"},
106107
},
108+
SANS: []string{subject},
107109
}
108110
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
109111
if err != nil {

ca/ca_test.go

+26-14
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,19 @@ ZEp7knvU2psWRw==
154154
"fail commonname-claim": func(t *testing.T) *signTest {
155155
jti, err := randutil.ASCII(32)
156156
assert.FatalError(t, err)
157-
cl := jwt.Claims{
158-
Subject: "invalid",
159-
Issuer: "step-cli",
160-
NotBefore: jwt.NewNumericDate(now),
161-
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
162-
Audience: validAud,
163-
ID: jti,
157+
cl := struct {
158+
jwt.Claims
159+
SANS []string `json:"sans"`
160+
}{
161+
Claims: jwt.Claims{
162+
Subject: "invalid",
163+
Issuer: "step-cli",
164+
NotBefore: jwt.NewNumericDate(now),
165+
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
166+
Audience: validAud,
167+
ID: jti,
168+
},
169+
SANS: []string{"invalid"},
164170
}
165171
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
166172
assert.FatalError(t, err)
@@ -181,13 +187,19 @@ ZEp7knvU2psWRw==
181187
"ok": func(t *testing.T) *signTest {
182188
jti, err := randutil.ASCII(32)
183189
assert.FatalError(t, err)
184-
cl := jwt.Claims{
185-
Subject: "test.smallstep.com",
186-
Issuer: "step-cli",
187-
NotBefore: jwt.NewNumericDate(now),
188-
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
189-
Audience: validAud,
190-
ID: jti,
190+
cl := struct {
191+
jwt.Claims
192+
SANS []string `json:"sans"`
193+
}{
194+
Claims: jwt.Claims{
195+
Subject: "test.smallstep.com",
196+
Issuer: "step-cli",
197+
NotBefore: jwt.NewNumericDate(now),
198+
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
199+
Audience: validAud,
200+
ID: jti,
201+
},
202+
SANS: []string{"test.smallstep.com"},
191203
}
192204
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
193205
assert.FatalError(t, err)

ca/tls_test.go

+13-7
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,19 @@ func generateOTT(subject string) string {
3939
if err != nil {
4040
panic(err)
4141
}
42-
cl := jwt.Claims{
43-
ID: id,
44-
Subject: subject,
45-
Issuer: "mariano",
46-
NotBefore: jwt.NewNumericDate(now),
47-
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
48-
Audience: []string{"https://127.0.0.1:0/sign"},
42+
cl := struct {
43+
jwt.Claims
44+
SANS []string `json:"sans"`
45+
}{
46+
Claims: jwt.Claims{
47+
ID: id,
48+
Subject: subject,
49+
Issuer: "mariano",
50+
NotBefore: jwt.NewNumericDate(now),
51+
Expiry: jwt.NewNumericDate(now.Add(time.Minute)),
52+
Audience: []string{"https://127.0.0.1:0/sign"},
53+
},
54+
SANS: []string{subject},
4955
}
5056
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
5157
if err != nil {

0 commit comments

Comments
 (0)