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/go.mod b/go.mod index a7c8e3441..5283d728c 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/stretchr/testify v1.8.4 // indirect github.com/weppos/publicsuffix-go v0.30.0 // indirect github.com/ziutek/mymysql v1.5.4 // indirect - golang.org/x/net v0.22.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/go.sum b/go.sum index 40b8a5a3c..eaff789c1 100644 --- a/go.sum +++ b/go.sum @@ -458,8 +458,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 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 diff --git a/vendor/modules.txt b/vendor/modules.txt index cb8033fad..ecf5a5554 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -149,7 +149,7 @@ golang.org/x/crypto/pkcs12/internal/rc2 golang.org/x/crypto/scrypt golang.org/x/crypto/ssh golang.org/x/crypto/ssh/internal/bcrypt_pbkdf -# golang.org/x/net v0.22.0 +# golang.org/x/net v0.23.0 ## explicit; go 1.18 golang.org/x/net/context/ctxhttp golang.org/x/net/idna