From 818cb9327b5793de45f797aeb3239fb8f16b68f0 Mon Sep 17 00:00:00 2001 From: Mateusz Poliwczak Date: Sat, 19 Aug 2023 11:54:48 +0200 Subject: [PATCH] add test, support creating certificates with new OID type Change-Id: Icc7b68161dca294e6524f6efb1c690b80b48f96e --- src/crypto/x509/oid.go | 8 ++++++ src/crypto/x509/x509.go | 27 ++++++++++++++------ src/crypto/x509/x509_test.go | 49 ++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/src/crypto/x509/oid.go b/src/crypto/x509/oid.go index 7d7a865f02e51b..30b9e471e4604c 100644 --- a/src/crypto/x509/oid.go +++ b/src/crypto/x509/oid.go @@ -43,6 +43,14 @@ func newOIDFromDER(der []byte) (OID, bool) { return OID{der}, true } +func mustNewOIDFromInts(ints []uint64) OID { + oid, err := OIDFromInts(ints) + if err != nil { + panic("crypto/x509: mustNewOIDFromInts: " + err.Error()) + } + return oid +} + // OIDFromInts creates a new OID using ints, each integer is a separate component. func OIDFromInts(oid []uint64) (OID, error) { if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) { diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 6fd9ac5c888385..607c02b1f534ad 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -1183,7 +1183,7 @@ func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKe if len(template.PolicyIdentifiers) > 0 && !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) { - ret[n], err = marshalCertificatePolicies(template.PolicyIdentifiers) + ret[n], err = marshalCertificatePolicies(template.Policies, template.PolicyIdentifiers) if err != nil { return nil, err } @@ -1368,14 +1368,27 @@ func marshalBasicConstraints(isCA bool, maxPathLen int, maxPathLenZero bool) (pk return ext, err } -func marshalCertificatePolicies(policyIdentifiers []asn1.ObjectIdentifier) (pkix.Extension, error) { +func marshalCertificatePolicies(policies []OID, policyIdentifiers []asn1.ObjectIdentifier) (pkix.Extension, error) { ext := pkix.Extension{Id: oidExtensionCertificatePolicies} - policies := make([]policyInformation, len(policyIdentifiers)) - for i, policy := range policyIdentifiers { - policies[i].Policy = policy - } + + 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(v.der) + }) + }) + } + for _, v := range policyIdentifiers { + child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { + child.AddASN1ObjectIdentifier(v) + }) + } + }) + var err error - ext.Value, err = asn1.Marshal(policies) + ext.Value, err = b.Bytes() return ext, err } diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index 19deeab54d96e2..853be23d4374f2 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -24,12 +24,14 @@ import ( "fmt" "internal/testenv" "io" + "math" "math/big" "net" "net/url" "os/exec" "reflect" "runtime" + "slices" "strings" "testing" "time" @@ -671,6 +673,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) { URIs: []*url.URL{parseURI("https://foo.com/wibble#foo")}, PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, + Policies: []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")}, @@ -3917,3 +3920,49 @@ func TestDuplicateAttributesCSR(t *testing.T) { t.Fatal("ParseCertificateRequest should succeed when parsing CSR with duplicate attributes") } } + +func TestCertificateOIDPolicies(t *testing.T) { + 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: []OID{ + mustNewOIDFromInts([]uint64{1, 2, 3, 4, 5}), + mustNewOIDFromInts([]uint64{1, 2, 3, math.MaxInt32}), + mustNewOIDFromInts([]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 = []OID{ + mustNewOIDFromInts([]uint64{1, 2, 3, 4, 5}), + mustNewOIDFromInts([]uint64{1, 2, 3, math.MaxInt32}), + mustNewOIDFromInts([]uint64{1, 2, 3, math.MaxUint32, math.MaxUint64}), + mustNewOIDFromInts([]uint64{1, 2, 3}), + } + + 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.PolicyIdentifiers, expectPolicyIdentifiers, slices.Equal[asn1.ObjectIdentifier]) { + t.Errorf("cert.PolicyIdentifiers = %v, want: %v", cert.PolicyIdentifiers, expectPolicyIdentifiers) + } + + if !slices.EqualFunc(cert.Policies, expectPolicies, func(o1, o2 OID) bool { return o1.Equal(o2) }) { + t.Errorf("cert.Policies = %v, want: %v", cert.Policies, expectPolicies) + } +}