Skip to content

Commit c027192

Browse files
vjanellecbroglie
authored andcommitted
(#921) URI SAN records
Support URI san records.
1 parent ea4033a commit c027192

6 files changed

Lines changed: 59 additions & 21 deletions

File tree

config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import (
3232
// mechanism.
3333
type CSRWhitelist struct {
3434
Subject, PublicKeyAlgorithm, PublicKey, SignatureAlgorithm bool
35-
DNSNames, IPAddresses, EmailAddresses bool
35+
DNSNames, IPAddresses, EmailAddresses, URIs bool
3636
}
3737

3838
// OID is our own version of asn1's ObjectIdentifier, so we can define a custom

csr/csr.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"errors"
1515
"net"
1616
"net/mail"
17+
"net/url"
1718
"strings"
1819

1920
cferr "github.com/cloudflare/cfssl/errors"
@@ -268,6 +269,9 @@ func getHosts(cert *x509.Certificate) []string {
268269
for _, email := range cert.EmailAddresses {
269270
hosts = append(hosts, email)
270271
}
272+
for _, uri := range cert.URIs {
273+
hosts = append(hosts, uri.String())
274+
}
271275

272276
return hosts
273277
}
@@ -379,6 +383,8 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
379383
tpl.IPAddresses = append(tpl.IPAddresses, ip)
380384
} else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
381385
tpl.EmailAddresses = append(tpl.EmailAddresses, email.Address)
386+
} else if uri, err := url.ParseRequestURI(req.Hosts[i]); err == nil && uri != nil {
387+
tpl.URIs = append(tpl.URIs, uri)
382388
} else {
383389
tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
384390
}

csr/csr_test.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func TestParseRequest(t *testing.T) {
108108
OU: "Systems Engineering",
109109
},
110110
},
111-
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com"},
111+
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com", "https://www.cloudflare.com"},
112112
KeyRequest: NewBasicKeyRequest(),
113113
}
114114

@@ -347,7 +347,7 @@ func TestDefaultBasicKeyRequest(t *testing.T) {
347347
},
348348
},
349349
CN: "cloudflare.com",
350-
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com"},
350+
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com", "https://www.cloudflare.com"},
351351
}
352352
_, priv, err := ParseRequest(req)
353353
if err != nil {
@@ -387,7 +387,7 @@ func TestRSACertRequest(t *testing.T) {
387387
},
388388
},
389389
CN: "cloudflare.com",
390-
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com"},
390+
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com", "https://www.cloudflare.com"},
391391
KeyRequest: &BasicKeyRequest{"rsa", 2048},
392392
}
393393
_, _, err := ParseRequest(req)
@@ -444,7 +444,7 @@ func TestGenerator(t *testing.T) {
444444
},
445445
},
446446
CN: "cloudflare.com",
447-
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com"},
447+
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com", "https://www.cloudflare.com"},
448448
KeyRequest: &BasicKeyRequest{"rsa", 2048},
449449
}
450450

@@ -479,6 +479,10 @@ func TestGenerator(t *testing.T) {
479479
t.Fatal("SAN parsing error")
480480
}
481481

482+
if len(csr.URIs) != 1 {
483+
t.Fatal("SAN parsing error")
484+
}
485+
482486
}
483487

484488
// TestBadGenerator ensures that a request that fails the validator is
@@ -518,7 +522,7 @@ func TestWeakCSR(t *testing.T) {
518522
},
519523
},
520524
CN: "cloudflare.com",
521-
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com"},
525+
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com", "https://www.cloudflare.com"},
522526
KeyRequest: &BasicKeyRequest{"rsa", 1024},
523527
}
524528
g := &Generator{testValidator}
@@ -579,7 +583,7 @@ func TestGenerate(t *testing.T) {
579583
},
580584
},
581585
CN: "cloudflare.com",
582-
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com"},
586+
Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com", "https://www.cloudflare.com"},
583587
KeyRequest: &BasicKeyRequest{"ecdsa", 256},
584588
}
585589

@@ -614,6 +618,10 @@ func TestGenerate(t *testing.T) {
614618
if len(csr.EmailAddresses) != 1 {
615619
t.Fatal("SAN parsing error")
616620
}
621+
622+
if len(csr.URIs) != 1 {
623+
t.Fatal("SAN parsing error")
624+
}
617625
}
618626

619627
// TestReGenerate ensures Regenerate() is abel to use the provided CSR as a template for signing a new

signer/local/local.go

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"net"
1717
"net/http"
1818
"net/mail"
19+
"net/url"
1920
"os"
2021

2122
"github.com/cloudflare/cfssl/certdb"
@@ -105,6 +106,7 @@ func (s *Signer) sign(template *x509.Certificate) (cert []byte, err error) {
105106
}
106107
template.DNSNames = nil
107108
template.EmailAddresses = nil
109+
template.URIs = nil
108110
s.ca = template
109111
initRoot = true
110112
}
@@ -159,20 +161,23 @@ func PopulateSubjectFromCSR(s *signer.Subject, req pkix.Name) pkix.Name {
159161
return name
160162
}
161163

162-
// OverrideHosts fills template's IPAddresses, EmailAddresses, and DNSNames with the
164+
// OverrideHosts fills template's IPAddresses, EmailAddresses, DNSNames, and URIs with the
163165
// content of hosts, if it is not nil.
164166
func OverrideHosts(template *x509.Certificate, hosts []string) {
165167
if hosts != nil {
166168
template.IPAddresses = []net.IP{}
167169
template.EmailAddresses = []string{}
168170
template.DNSNames = []string{}
171+
template.URIs = []*url.URL{}
169172
}
170173

171174
for i := range hosts {
172175
if ip := net.ParseIP(hosts[i]); ip != nil {
173176
template.IPAddresses = append(template.IPAddresses, ip)
174177
} else if email, err := mail.ParseAddress(hosts[i]); err == nil && email != nil {
175178
template.EmailAddresses = append(template.EmailAddresses, email.Address)
179+
} else if uri, err := url.ParseRequestURI(hosts[i]); err == nil && uri != nil {
180+
template.URIs = append(template.URIs, uri)
176181
} else {
177182
template.DNSNames = append(template.DNSNames, hosts[i])
178183
}
@@ -232,6 +237,9 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
232237
if profile.CSRWhitelist.EmailAddresses {
233238
safeTemplate.EmailAddresses = csrTemplate.EmailAddresses
234239
}
240+
if profile.CSRWhitelist.URIs {
241+
safeTemplate.URIs = csrTemplate.URIs
242+
}
235243
}
236244

237245
if req.CRLOverride != "" {
@@ -277,6 +285,11 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
277285
return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
278286
}
279287
}
288+
for _, name := range safeTemplate.URIs {
289+
if profile.NameWhitelist.Find([]byte(name.String())) == nil {
290+
return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
291+
}
292+
}
280293
}
281294

282295
if profile.ClientProvidesSerialNumbers {
@@ -467,17 +480,17 @@ func (s *Signer) SignFromPrecert(precert *x509.Certificate, scts []ct.SignedCert
467480
// Create the new tbsCert from precert. Do explicit copies of any slices so that we don't
468481
// use memory that may be altered by us or the caller at a later stage.
469482
tbsCert := x509.Certificate{
470-
SignatureAlgorithm: precert.SignatureAlgorithm,
471-
PublicKeyAlgorithm: precert.PublicKeyAlgorithm,
472-
PublicKey: precert.PublicKey,
473-
Version: precert.Version,
474-
SerialNumber: precert.SerialNumber,
475-
Issuer: precert.Issuer,
476-
Subject: precert.Subject,
477-
NotBefore: precert.NotBefore,
478-
NotAfter: precert.NotAfter,
479-
KeyUsage: precert.KeyUsage,
480-
BasicConstraintsValid: precert.BasicConstraintsValid,
483+
SignatureAlgorithm: precert.SignatureAlgorithm,
484+
PublicKeyAlgorithm: precert.PublicKeyAlgorithm,
485+
PublicKey: precert.PublicKey,
486+
Version: precert.Version,
487+
SerialNumber: precert.SerialNumber,
488+
Issuer: precert.Issuer,
489+
Subject: precert.Subject,
490+
NotBefore: precert.NotBefore,
491+
NotAfter: precert.NotAfter,
492+
KeyUsage: precert.KeyUsage,
493+
BasicConstraintsValid: precert.BasicConstraintsValid,
481494
IsCA: precert.IsCA,
482495
MaxPathLen: precert.MaxPathLen,
483496
MaxPathLenZero: precert.MaxPathLenZero,

signer/local/local_test.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"net"
1515
"net/http"
1616
"net/http/httptest"
17+
"net/url"
1718
"reflect"
1819
"regexp"
1920
"sort"
@@ -525,7 +526,7 @@ func TestOverrideSubject(t *testing.T) {
525526
s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile)
526527

527528
request := signer.SignRequest{
528-
Hosts: []string{"127.0.0.1", "localhost", "xyz@example.com"},
529+
Hosts: []string{"127.0.0.1", "localhost", "xyz@example.com", "https://www.cloudflare.com"},
529530
Request: string(csrPEM),
530531
Subject: req,
531532
}
@@ -597,7 +598,7 @@ func TestOverwriteHosts(t *testing.T) {
597598
for _, hosts := range [][]string{
598599
nil,
599600
{},
600-
{"127.0.0.1", "localhost", "xyz@example.com"},
601+
{"127.0.0.1", "localhost", "xyz@example.com", "https://www.cloudflare.com"},
601602
} {
602603
request := signer.SignRequest{
603604
Hosts: hosts,
@@ -625,6 +626,10 @@ func TestOverwriteHosts(t *testing.T) {
625626
certHosts = append(certHosts, email)
626627
}
627628

629+
for _, uri := range cert.URIs {
630+
certHosts = append(certHosts, uri.String())
631+
}
632+
628633
// compare the sorted host lists
629634
sort.Strings(certHosts)
630635
sort.Strings(request.Hosts)
@@ -1330,6 +1335,9 @@ func TestSignFromPrecert(t *testing.T) {
13301335
if err != nil {
13311336
t.Fatalf("Failed to generate test key: %s", err)
13321337
}
1338+
1339+
_uri, _ := url.Parse("https://www.cloudflare.com")
1340+
13331341
precertBytes, err := testSigner.sign(&x509.Certificate{
13341342
SignatureAlgorithm: x509.SHA512WithRSA,
13351343
PublicKey: k.Public(),
@@ -1347,6 +1355,7 @@ func TestSignFromPrecert(t *testing.T) {
13471355
IssuingCertificateURL: []string{"url"},
13481356
DNSNames: []string{"example.com"},
13491357
EmailAddresses: []string{"email@example.com"},
1358+
URIs: []*url.URL{_uri},
13501359
IPAddresses: []net.IP{net.ParseIP("1.1.1.1")},
13511360
CRLDistributionPoints: []string{"crl"},
13521361
PolicyIdentifiers: []asn1.ObjectIdentifier{{1, 2, 3}},

signer/signer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certific
192192
DNSNames: csrv.DNSNames,
193193
IPAddresses: csrv.IPAddresses,
194194
EmailAddresses: csrv.EmailAddresses,
195+
URIs: csrv.URIs,
195196
}
196197

197198
for _, val := range csrv.Extensions {
@@ -320,6 +321,7 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si
320321
}
321322
template.DNSNames = nil
322323
template.EmailAddresses = nil
324+
template.URIs = nil
323325
}
324326
template.SubjectKeyId = ski
325327

0 commit comments

Comments
 (0)