Skip to content

Commit 503b4d7

Browse files
author
Watson Ladd
authored
Merge pull request #1205 from cloudflare/watson/fix-delegation-support
Support for DelegationUsage extension
2 parents 29ae05f + a8591c3 commit 503b4d7

File tree

5 files changed

+81
-15
lines changed

5 files changed

+81
-15
lines changed

cli/testdata/csr.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@
1818
"1.2.3.4.5": "abc"
1919
}
2020
}
21-
]
22-
}
21+
],
22+
"delegation_enabled": true
23+
}

csr/csr.go

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type Name struct {
3737
L string `json:"L,omitempty" yaml:"L,omitempty"` // Locality
3838
O string `json:"O,omitempty" yaml:"O,omitempty"` // OrganisationName
3939
OU string `json:"OU,omitempty" yaml:"OU,omitempty"` // OrganisationalUnitName
40-
E string `json:"E,omitempty" yaml:"E,omitempty"`
40+
E string `json:"E,omitempty" yaml:"E,omitempty"`
4141
SerialNumber string `json:"SerialNumber,omitempty" yaml:"SerialNumber,omitempty"`
4242
OID map[string]string `json:"OID,omitempty", yaml:"OID,omitempty"`
4343
}
@@ -136,14 +136,15 @@ type CAConfig struct {
136136
// A CertificateRequest encapsulates the API interface to the
137137
// certificate request functionality.
138138
type CertificateRequest struct {
139-
CN string `json:"CN" yaml:"CN"`
140-
Names []Name `json:"names" yaml:"names"`
141-
Hosts []string `json:"hosts" yaml:"hosts"`
142-
KeyRequest *KeyRequest `json:"key,omitempty" yaml:"key,omitempty"`
143-
CA *CAConfig `json:"ca,omitempty" yaml:"ca,omitempty"`
144-
SerialNumber string `json:"serialnumber,omitempty" yaml:"serialnumber,omitempty"`
145-
Extensions []pkix.Extension `json:"extensions,omitempty" yaml:"extensions,omitempty"`
146-
CRL string `json:"crl_url,omitempty" yaml:"crl_url,omitempty"`
139+
CN string `json:"CN" yaml:"CN"`
140+
Names []Name `json:"names" yaml:"names"`
141+
Hosts []string `json:"hosts" yaml:"hosts"`
142+
KeyRequest *KeyRequest `json:"key,omitempty" yaml:"key,omitempty"`
143+
CA *CAConfig `json:"ca,omitempty" yaml:"ca,omitempty"`
144+
SerialNumber string `json:"serialnumber,omitempty" yaml:"serialnumber,omitempty"`
145+
DelegationEnabled bool `json:"delegation_enabled,omitempty" yaml:"delegation_enabled,omitempty"`
146+
Extensions []pkix.Extension `json:"extensions,omitempty" yaml:"extensions,omitempty"`
147+
CRL string `json:"crl_url,omitempty" yaml:"crl_url,omitempty"`
147148
}
148149

149150
// New returns a new, empty CertificateRequest with a
@@ -196,9 +197,9 @@ func (cr *CertificateRequest) Name() (pkix.Name, error) {
196197
}
197198
name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: oid, Value: v})
198199
}
199-
if n.E != "" {
200-
name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: n.E})
201-
}
200+
if n.E != "" {
201+
name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: n.E})
202+
}
202203
}
203204
name.SerialNumber = cr.SerialNumber
204205
return name, nil
@@ -430,6 +431,10 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
430431
}
431432
}
432433

434+
if req.DelegationEnabled {
435+
tpl.ExtraExtensions = append(tpl.Extensions, helpers.DelegationExtension)
436+
}
437+
433438
if req.Extensions != nil {
434439
err = appendExtensionsToCSR(req.Extensions, &tpl)
435440
if err != nil {

csr/csr_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,3 +786,50 @@ func TestExtractCertificateRequest(t *testing.T) {
786786
t.Fatal("Bad Certificate Request!")
787787
}
788788
}
789+
790+
// TestDelegationCSR tests that we create requests with the DC extension
791+
func TestDelegationCSR(t *testing.T) {
792+
var cr = &CertificateRequest{
793+
CN: "Test Common Name",
794+
Names: []Name{
795+
{
796+
C: "US",
797+
ST: "California",
798+
L: "San Francisco",
799+
O: "CloudFlare, Inc.",
800+
OU: "Systems Engineering",
801+
},
802+
{
803+
C: "GB",
804+
ST: "London",
805+
L: "London",
806+
O: "CloudFlare, Inc",
807+
OU: "Systems Engineering",
808+
},
809+
},
810+
DelegationEnabled: true,
811+
Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
812+
KeyRequest: NewKeyRequest(),
813+
}
814+
csr, _, err := ParseRequest(cr)
815+
if err != nil {
816+
t.Fatal("could not generate csr")
817+
}
818+
unPem, _ := pem.Decode(csr)
819+
if unPem == nil {
820+
t.Fatal("Failed to decode pem")
821+
}
822+
res, err := x509.ParseCertificateRequest(unPem.Bytes)
823+
if err != nil {
824+
t.Fatalf("spat out nonsense as a csr: %v", err)
825+
}
826+
found := false
827+
for _, ext := range res.Extensions {
828+
if ext.Id.Equal(helpers.DelegationUsage) {
829+
found = true
830+
}
831+
}
832+
if !found {
833+
t.Fatal("generated csr has no extension")
834+
}
835+
}

helpers/helpers.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ const OneYear = 8760 * time.Hour
3939
// OneDay is a time.Duration representing a day's worth of seconds.
4040
const OneDay = 24 * time.Hour
4141

42+
// DelegationUsage is the OID for the DelegationUseage extensions
43+
var DelegationUsage = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44363, 44}
44+
45+
// DelegationExtension
46+
var DelegationExtension = pkix.Extension{
47+
Id: DelegationUsage,
48+
Critical: false,
49+
Value: []byte{0x05, 0x00}, // ASN.1 NULL
50+
}
51+
4252
// InclusiveDate returns the time.Time representation of a date - 1
4353
// nanosecond. This allows time.After to be used inclusively.
4454
func InclusiveDate(year int, month time.Month, day int) time.Time {

signer/signer.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/cloudflare/cfssl/config"
2121
"github.com/cloudflare/cfssl/csr"
2222
cferr "github.com/cloudflare/cfssl/errors"
23+
"github.com/cloudflare/cfssl/helpers"
2324
"github.com/cloudflare/cfssl/info"
2425
)
2526

@@ -45,7 +46,7 @@ type Extension struct {
4546
// Extensions provided in the signRequest are copied into the certificate, as
4647
// long as they are in the ExtensionWhitelist for the signer's policy.
4748
// Extensions requested in the CSR are ignored, except for those processed by
48-
// ParseCertificateRequest (mainly subjectAltName).
49+
// ParseCertificateRequest (mainly subjectAltName) and DelegationUsage.
4950
type SignRequest struct {
5051
Hosts []string `json:"hosts"`
5152
Request string `json:"certificate_request"`
@@ -240,6 +241,8 @@ func ParseCertificateRequest(s Signer, p *config.SigningProfile, csrBytes []byte
240241
template.IsCA = constraints.IsCA
241242
template.MaxPathLen = constraints.MaxPathLen
242243
template.MaxPathLenZero = template.MaxPathLen == 0
244+
} else if val.Id.Equal(helpers.DelegationUsage) {
245+
template.ExtraExtensions = append(template.ExtraExtensions, val)
243246
} else {
244247
// If the profile has 'copy_extensions' to true then lets add it
245248
if p.CopyExtensions {

0 commit comments

Comments
 (0)