From 6a12b6eda972abae19a441787f863ea8ffc7872f Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Mon, 9 Jun 2025 13:26:37 +0800 Subject: [PATCH] smx509: switch default policy field to Policies --- smx509/oid_test.go | 8 ----- smx509/verify.go | 8 +++++ smx509/x509.go | 27 ++++++++++------- smx509/x509_test.go | 72 +++++++++++++++++++++++++++++++++++---------- 4 files changed, 80 insertions(+), 35 deletions(-) diff --git a/smx509/oid_test.go b/smx509/oid_test.go index 5b762fa..7b43074 100644 --- a/smx509/oid_test.go +++ b/smx509/oid_test.go @@ -97,11 +97,3 @@ func TestOID(t *testing.T) { } } } - -func mustNewOIDFromInts(t *testing.T, ints []uint64) x509.OID { - oid, err := x509.OIDFromInts(ints) - if err != nil { - t.Fatalf("OIDFromInts(%v) unexpected error: %v", ints, err) - } - return oid -} diff --git a/smx509/verify.go b/smx509/verify.go index 7100d11..f8e566a 100644 --- a/smx509/verify.go +++ b/smx509/verify.go @@ -1078,3 +1078,11 @@ NextCert: return true } + +func mustNewOIDFromInts(ints []uint64) x509.OID { + oid, err := x509.OIDFromInts(ints) + if err != nil { + panic(fmt.Sprintf("OIDFromInts(%v) unexpected error: %v", ints, err)) + } + return oid +} diff --git a/smx509/x509.go b/smx509/x509.go index fbf1b4d..d750a6d 100644 --- a/smx509/x509.go +++ b/smx509/x509.go @@ -1147,7 +1147,8 @@ func buildCertExtensions(template *x509.Certificate, subjectIsEmpty bool, author n++ } - if len(template.PolicyIdentifiers) > 0 && + var usePolicies = godebug.Get("x509usepolicies") != "0" + if ((!usePolicies && len(template.PolicyIdentifiers) > 0) || (usePolicies && len(template.Policies) > 0)) && !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) { ret[n], err = marshalCertificatePolicies(template.Policies, template.PolicyIdentifiers) if err != nil { @@ -1337,19 +1338,23 @@ func marshalBasicConstraints(isCA bool, maxPathLen int, maxPathLenZero bool) (pk func marshalCertificatePolicies(policies []x509.OID, policyIdentifiers []asn1.ObjectIdentifier) (pkix.Extension, error) { ext := pkix.Extension{Id: oidExtensionCertificatePolicies} + var usePolicies = godebug.Get("x509usepolicies") != "0" b := cryptobyte.NewBuilder(make([]byte, 0, 128)) b.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { - for _, v := range policies { - child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { - child.AddASN1(cryptobyte_asn1.OBJECT_IDENTIFIER, func(child *cryptobyte.Builder) { - child.AddBytes(getDer(&v)) + if usePolicies { + for _, v := range policies { + child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { + child.AddASN1(cryptobyte_asn1.OBJECT_IDENTIFIER, func(child *cryptobyte.Builder) { + child.AddBytes(getDer(&v)) + }) }) - }) - } - for _, v := range policyIdentifiers { - child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { - child.AddASN1ObjectIdentifier(v) - }) + } + } else { + for _, v := range policyIdentifiers { + child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { + child.AddASN1ObjectIdentifier(v) + }) + } } }) diff --git a/smx509/x509_test.go b/smx509/x509_test.go index c542201..3db269e 100644 --- a/smx509/x509_test.go +++ b/smx509/x509_test.go @@ -28,6 +28,7 @@ import ( "testing" "time" + "github.com/emmansun/gmsm/internal/godebug" "github.com/emmansun/gmsm/sm2" ) @@ -491,8 +492,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) { IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")}, URIs: []*url.URL{parseURI("https://foo.com/wibble#foo")}, - PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, - Policies: []x509.OID{mustNewOIDFromInts(t, []uint64{1, 2, 3, math.MaxUint32, math.MaxUint64})}, + Policies: []x509.OID{mustNewOIDFromInts([]uint64{1, 2, 3, math.MaxUint32, math.MaxUint64})}, PermittedDNSDomains: []string{".example.com", "example.com"}, ExcludedDNSDomains: []string{"bar.example.com"}, PermittedIPRanges: []*net.IPNet{parseCIDR("192.168.1.1/16"), parseCIDR("1.2.3.4/8")}, @@ -530,8 +530,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) { continue } - if len(cert.PolicyIdentifiers) != 1 || !cert.PolicyIdentifiers[0].Equal(template.PolicyIdentifiers[0]) { - t.Errorf("%s: failed to parse policy identifiers: got:%#v want:%#v", test.name, cert.PolicyIdentifiers, template.PolicyIdentifiers) + if len(cert.Policies) != 1 || !cert.Policies[0].Equal(template.Policies[0]) { + t.Errorf("%s: failed to parse policy identifiers: got:%#v want:%#v", test.name, cert.Policies, template.Policies) } if len(cert.PermittedDNSDomains) != 2 || cert.PermittedDNSDomains[0] != ".example.com" || cert.PermittedDNSDomains[1] != "example.com" { @@ -3683,31 +3683,23 @@ func TestCreateCertificateNegativeMaxPathLength(t *testing.T) { } } -func TestCertificateOIDPolicies(t *testing.T) { +func TestCertificateOIDPoliciesGODEBUG(t *testing.T) { + t.Setenv("GODEBUG", "x509usepolicies=0") + template := Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{CommonName: "Cert"}, NotBefore: time.Unix(1000, 0), NotAfter: time.Unix(100000, 0), PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, - Policies: []x509.OID{ - mustNewOIDFromInts(t, []uint64{1, 2, 3, 4, 5}), - mustNewOIDFromInts(t, []uint64{1, 2, 3, math.MaxInt32}), - mustNewOIDFromInts(t, []uint64{1, 2, 3, math.MaxUint32, math.MaxUint64}), - }, } var expectPolicyIdentifiers = []asn1.ObjectIdentifier{ - []int{1, 2, 3, 4, 5}, - []int{1, 2, 3, math.MaxInt32}, []int{1, 2, 3}, } var expectPolicies = []x509.OID{ - mustNewOIDFromInts(t, []uint64{1, 2, 3, 4, 5}), - mustNewOIDFromInts(t, []uint64{1, 2, 3, math.MaxInt32}), - mustNewOIDFromInts(t, []uint64{1, 2, 3, math.MaxUint32, math.MaxUint64}), - mustNewOIDFromInts(t, []uint64{1, 2, 3}), + mustNewOIDFromInts([]uint64{1, 2, 3}), } certDER, err := CreateCertificate(rand.Reader, &template, &template, rsaPrivateKey.Public(), rsaPrivateKey) @@ -3728,3 +3720,51 @@ func TestCertificateOIDPolicies(t *testing.T) { t.Errorf("cert.Policies = %v, want: %v", cert.Policies, expectPolicies) } } + +func TestCertificatePolicies(t *testing.T) { + var usePolicies = godebug.Get("x509usepolicies") != "0" + if !usePolicies { + t.Skip("test relies on default x509usepolicies GODEBUG") + } + + template := Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{CommonName: "Cert"}, + NotBefore: time.Unix(1000, 0), + NotAfter: time.Unix(100000, 0), + PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, + Policies: []x509.OID{mustNewOIDFromInts([]uint64{1, 2, math.MaxUint32 + 1})}, + } + + expectPolicies := []x509.OID{mustNewOIDFromInts([]uint64{1, 2, math.MaxUint32 + 1})} + certDER, err := CreateCertificate(rand.Reader, &template, &template, rsaPrivateKey.Public(), rsaPrivateKey) + if err != nil { + t.Fatalf("CreateCertificate() unexpected error: %v", err) + } + + cert, err := ParseCertificate(certDER) + if err != nil { + t.Fatalf("ParseCertificate() unexpected error: %v", err) + } + + if !slices.EqualFunc(cert.Policies, expectPolicies, x509.OID.Equal) { + t.Errorf("cert.Policies = %v, want: %v", cert.Policies, expectPolicies) + } + + t.Setenv("GODEBUG", "x509usepolicies=1") + expectPolicies = []x509.OID{mustNewOIDFromInts([]uint64{1, 2, math.MaxUint32 + 1})} + + certDER, err = CreateCertificate(rand.Reader, &template, &template, rsaPrivateKey.Public(), rsaPrivateKey) + if err != nil { + t.Fatalf("CreateCertificate() unexpected error: %v", err) + } + + cert, err = ParseCertificate(certDER) + if err != nil { + t.Fatalf("ParseCertificate() unexpected error: %v", err) + } + + if !slices.EqualFunc(cert.Policies, expectPolicies, x509.OID.Equal) { + t.Errorf("cert.Policies = %v, want: %v", cert.Policies, expectPolicies) + } +}