diff --git a/api/next/75325.txt b/api/next/75325.txt new file mode 100644 index 00000000000..dc241efef2d --- /dev/null +++ b/api/next/75325.txt @@ -0,0 +1,2 @@ +pkg crypto/x509, func OIDFromASN1OID(asn1.ObjectIdentifier) (OID, error) #75325 +pkg crypto/x509, method (ExtKeyUsage) OID() OID #75325 diff --git a/doc/next/6-stdlib/99-minor/crypto/x509/75325.md b/doc/next/6-stdlib/99-minor/crypto/x509/75325.md new file mode 100644 index 00000000000..a133e66209b --- /dev/null +++ b/doc/next/6-stdlib/99-minor/crypto/x509/75325.md @@ -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]. \ No newline at end of file diff --git a/src/crypto/x509/oid.go b/src/crypto/x509/oid.go index c60daa7540c..8bf19a14333 100644 --- a/src/crypto/x509/oid.go +++ b/src/crypto/x509/oid.go @@ -393,3 +393,15 @@ func (oid OID) toASN1OID() (asn1.ObjectIdentifier, bool) { 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) +} diff --git a/src/crypto/x509/oid_test.go b/src/crypto/x509/oid_test.go index ce3a0672a6a..efc71fc2dc7 100644 --- a/src/crypto/x509/oid_test.go +++ b/src/crypto/x509/oid_test.go @@ -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) + } +} diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 85e8fceedcb..7953b615f50 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -687,6 +687,19 @@ func oidFromExtKeyUsage(eku ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) { 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. type Certificate struct { Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature). diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index 98f3f7941c8..183ee303fae 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -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) } } + +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) + } + } +}