From d54b6130660556bd8826d357b1eb362f1f1e93ac Mon Sep 17 00:00:00 2001 From: Eugene Bekker Date: Fri, 13 Sep 2024 22:51:42 -0400 Subject: [PATCH] enabling support for Subject email (E) overriding --- api/sign/sign_test.go | 12 +++++++++ csr/csr.go | 62 +++++++++++++++++++++++++++++++++++++++++-- signer/local/local.go | 11 ++++++++ signer/signer.go | 6 +++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/api/sign/sign_test.go b/api/sign/sign_test.go index a54b33d8f..38fd18faa 100644 --- a/api/sign/sign_test.go +++ b/api/sign/sign_test.go @@ -13,6 +13,7 @@ import ( "github.com/cloudflare/cfssl/api" "github.com/cloudflare/cfssl/auth" "github.com/cloudflare/cfssl/config" + "github.com/cloudflare/cfssl/csr" "github.com/cloudflare/cfssl/signer" ) @@ -317,6 +318,17 @@ var signTests = []signTest{ ExpectedSuccess: true, ExpectedErrorCode: 0, }, + { + Hosts: []string{}, + Subject: &signer.Subject{ + CN: "example.com", + Names: []csr.Name{csr.Name{E: "jdoe@example.com"}}, + }, + CSRFile: testCSRFile, + ExpectedHTTPStatus: http.StatusOK, + ExpectedSuccess: true, + ExpectedErrorCode: 0, + }, { Hosts: nil, CSRFile: testCSRFile, diff --git a/csr/csr.go b/csr/csr.go index 52039326b..1ac9fbaca 100644 --- a/csr/csr.go +++ b/csr/csr.go @@ -33,6 +33,49 @@ const ( curveP521 = 521 ) +var ( + emailOidInts = []int{1, 2, 840, 113549, 1, 9, 1} + emailOid = asn1.ObjectIdentifier(emailOidInts) + uidOidInts = []int{0, 9, 2342, 19200300, 100, 1, 1} + uidOid = asn1.ObjectIdentifier(uidOidInts) + dcOidInts = []int{0, 9, 2342, 19200300, 100, 1, 25} + dcOid = asn1.ObjectIdentifier(dcOidInts) +) + +// Returns email from the attributes if it exists +func GetEmail(extraNames []pkix.AttributeTypeAndValue) (ok bool, email string) { + for _, en := range extraNames { + if emailOid.Equal(en.Type) { + sval, svalOk := en.Value.(string) + if svalOk { + return true, sval + } + } + } + return false, "" +} + +// Adds the email to the attributes +func AddEmail(extraNames []pkix.AttributeTypeAndValue, email string) []pkix.AttributeTypeAndValue { + extraNames = append(extraNames, + pkix.AttributeTypeAndValue{Type: emailOid, Value: email}) + return extraNames +} + +// Adds the UID to the attributes +func AddUid(extraNames []pkix.AttributeTypeAndValue, uid string) []pkix.AttributeTypeAndValue { + extraNames = append(extraNames, + pkix.AttributeTypeAndValue{Type: uidOid, Value: uid}) + return extraNames +} + +// Adds the Domain Component to the attributes +func AddDc(extraNames []pkix.AttributeTypeAndValue, domainComponent string) []pkix.AttributeTypeAndValue { + extraNames = append(extraNames, + pkix.AttributeTypeAndValue{Type: dcOid, Value: domainComponent}) + return extraNames +} + // A Name contains the SubjectInfo fields. type Name struct { C string `json:"C,omitempty" yaml:"C,omitempty"` // Country @@ -209,7 +252,7 @@ func (cr *CertificateRequest) Name() (pkix.Name, error) { name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: oid, Value: v}) } if n.E != "" { - name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: n.E}) + name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: emailOid, Value: n.E}) } } name.SerialNumber = cr.SerialNumber @@ -339,7 +382,18 @@ func getNames(sub pkix.Name) []Name { nl := len(sub.Locality) np := len(sub.Province) - n := max(nc, norg, nou, nl, np) + ne := 0 + emailOk, email := GetEmail(sub.ExtraNames) + if emailOk { + ne = 1 + } else { + emailOk, email = GetEmail(sub.Names) + if emailOk { + ne = 1 + } + } + + n := max(nc, norg, nou, nl, np, ne) names := make([]Name, n) for i := range names { @@ -358,6 +412,10 @@ func getNames(sub pkix.Name) []Name { if i < np { names[i].ST = sub.Province[i] } + + if ne == 1 { + names[i].E = email + } } return names } diff --git a/signer/local/local.go b/signer/local/local.go index 091ce79ce..63764301c 100644 --- a/signer/local/local.go +++ b/signer/local/local.go @@ -27,6 +27,7 @@ import ( "github.com/cloudflare/cfssl/certdb" "github.com/cloudflare/cfssl/config" + "github.com/cloudflare/cfssl/csr" cferr "github.com/cloudflare/cfssl/errors" "github.com/cloudflare/cfssl/helpers" "github.com/cloudflare/cfssl/info" @@ -254,6 +255,16 @@ func PopulateSubjectFromCSR(s *signer.Subject, req pkix.Name) pkix.Name { if name.SerialNumber == "" { name.SerialNumber = req.SerialNumber } + // Handle Email by the OID + emailOk, email := csr.GetEmail(name.ExtraNames) + if !emailOk || email == "" { + emailOk, email = csr.GetEmail(req.ExtraNames) + if emailOk { + name.Names = csr.AddEmail(req.Names, email) + name.ExtraNames = csr.AddEmail(req.ExtraNames, email) + } + } + return name } diff --git a/signer/signer.go b/signer/signer.go index d5b1f96f0..409630f67 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -95,6 +95,12 @@ func (s *Subject) Name() pkix.Name { appendIf(n.L, &name.Locality) appendIf(n.O, &name.Organization) appendIf(n.OU, &name.OrganizationalUnit) + + // We have to handle Email by its OID + if n.E != "" { + name.Names = csr.AddEmail(name.Names, n.E) + name.ExtraNames = csr.AddEmail(name.ExtraNames, n.E) + } } name.SerialNumber = s.SerialNumber return name