crypto/x509: add ExtKeyUsage.OID method

And OIDFromASN1OID for converting between asn1.ObjectIdentifier and OID.

Fixes #75325

Change-Id: I3b84dce54346d88aab731ffe30d0fef07b014f04
Reviewed-on: https://go-review.googlesource.com/c/go/+/724761
Reviewed-by: Neal Patel <nealpatel@google.com>
Auto-Submit: Roland Shoemaker <roland@golang.org>
Commit-Queue: Neal Patel <nealpatel@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Roland Shoemaker 2025-11-26 09:21:13 -08:00 committed by Gopher Robot
parent 623ef28135
commit e2cae9ecdf
6 changed files with 64 additions and 0 deletions

2
api/next/75325.txt Normal file
View file

@ -0,0 +1,2 @@
pkg crypto/x509, func OIDFromASN1OID(asn1.ObjectIdentifier) (OID, error) #75325
pkg crypto/x509, method (ExtKeyUsage) OID() OID #75325

View file

@ -0,0 +1,4 @@
The [ExtKeyUsage] type now has an OID method that returns the corresponding OID for the EKU.
The new [OIDFromASN1OID] function allows converting an [encoding/asn1.ObjectIdentifier] into
an [OID].

View file

@ -393,3 +393,15 @@ func (oid OID) toASN1OID() (asn1.ObjectIdentifier, bool) {
return out, true return out, true
} }
// OIDFromASN1OID creates a new OID using asn1OID.
func OIDFromASN1OID(asn1OID asn1.ObjectIdentifier) (OID, error) {
uint64OID := make([]uint64, 0, len(asn1OID))
for _, component := range asn1OID {
if component < 0 {
return OID{}, errors.New("x509: OID components must be non-negative")
}
uint64OID = append(uint64OID, uint64(component))
}
return OIDFromInts(uint64OID)
}

View file

@ -343,3 +343,27 @@ func BenchmarkOIDMarshalUnmarshalText(b *testing.B) {
} }
} }
} }
func TestOIDFromASN1OID(t *testing.T) {
negativeComponentOID := asn1.ObjectIdentifier{-1}
_, err := OIDFromASN1OID(negativeComponentOID)
if err == nil || err.Error() != "x509: OID components must be non-negative" {
t.Fatalf("OIDFromASN1OID() = %v; want = \"x509: OID components must be non-negative\"", err)
}
shortOID := asn1.ObjectIdentifier{1}
_, err = OIDFromASN1OID(shortOID)
if err == nil || err != errInvalidOID {
t.Fatalf("OIDFromASN1OID() = %v; want = %q", err, errInvalidOID)
}
invalidOIDFirstComponent := asn1.ObjectIdentifier{255, 1}
_, err = OIDFromASN1OID(invalidOIDFirstComponent)
if err == nil || err != errInvalidOID {
t.Fatalf("OIDFromASN1OID() = %v; want = %q", err, errInvalidOID)
}
invalidOIDSecondComponent := asn1.ObjectIdentifier{1, 255}
_, err = OIDFromASN1OID(invalidOIDSecondComponent)
if err == nil || err != errInvalidOID {
t.Fatalf("OIDFromASN1OID() = %v; want = %q", err, errInvalidOID)
}
}

View file

@ -687,6 +687,19 @@ func oidFromExtKeyUsage(eku ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) {
return return
} }
// OID returns the ASN.1 object identifier of the EKU.
func (eku ExtKeyUsage) OID() OID {
asn1OID, ok := oidFromExtKeyUsage(eku)
if !ok {
panic("x509: internal error: known ExtKeyUsage has no OID")
}
oid, err := OIDFromASN1OID(asn1OID)
if err != nil {
panic("x509: internal error: known ExtKeyUsage has invalid OID")
}
return oid
}
// A Certificate represents an X.509 certificate. // A Certificate represents an X.509 certificate.
type Certificate struct { type Certificate struct {
Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature). Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature).

View file

@ -4263,3 +4263,12 @@ func TestCreateCertificateNegativeMaxPathLength(t *testing.T) {
t.Fatalf(`CreateCertificate() = %v; want = "x509: invalid MaxPathLen, must be greater or equal to -1"`, err) t.Fatalf(`CreateCertificate() = %v; want = "x509: invalid MaxPathLen, must be greater or equal to -1"`, err)
} }
} }
func TestEKUOIDS(t *testing.T) {
for _, eku := range extKeyUsageOIDs {
oid := eku.extKeyUsage.OID()
if !oid.EqualASN1OID(eku.oid) {
t.Errorf("extKeyUsage %v: expected OID %v, got %v", eku.extKeyUsage, eku.oid, oid)
}
}
}