From 85705694ca446e73d788d72ec160e64273a344e5 Mon Sep 17 00:00:00 2001 From: Roland Groen Date: Wed, 6 Nov 2024 12:45:50 +0100 Subject: [PATCH] Fix issue with other types of SAN values The testcases did not take in account that there could be other types of otherName attributes, like the class 2, tag 2 alternative host name. This commit fixes that issue. --- vdr/didx509/x509_utils.go | 29 ++++++++++++++++------------- vdr/didx509/x509_utils_test.go | 22 ++++++++++++++-------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/vdr/didx509/x509_utils.go b/vdr/didx509/x509_utils.go index 98fe2f817..4f6804db0 100644 --- a/vdr/didx509/x509_utils.go +++ b/vdr/didx509/x509_utils.go @@ -104,21 +104,24 @@ func findOtherNameValues(cert *x509.Certificate) ([]string, error) { // findSanValues extracts the SAN values from a given pkix.Extension, returning the resulting values or an error. func findSanValues(extension pkix.Extension) ([]string, error) { var values []string - err := forEachSan(extension.Value, func(data []byte) error { - var other OtherName - _, err := asn1.UnmarshalWithParams(data, &other, "tag:0") - if err != nil { - return err - } - if other.TypeID.Equal(OtherNameType) { - var value string - _, err = asn1.Unmarshal(other.Value.Bytes, &value) + err := forEachSan(extension.Value, func(v *asn1.RawValue) error { + if v.Class == asn1.ClassContextSpecific && v.Tag == 0 { + var other OtherName + _, err := asn1.UnmarshalWithParams(v.FullBytes, &other, "tag:0") if err != nil { return err } - values = append(values, value) + if other.TypeID.Equal(OtherNameType) { + var value string + _, err = asn1.Unmarshal(other.Value.Bytes, &value) + if err != nil { + return err + } + values = append(values, value) + } } return nil + }) if err != nil { return make([]string, 0), err @@ -127,7 +130,7 @@ func findSanValues(extension pkix.Extension) ([]string, error) { } // forEachSan processes each SAN extension in the certificate -func forEachSan(extension []byte, callback func(data []byte) error) error { +func forEachSan(extension []byte, callback func(data *asn1.RawValue) error) error { var seq asn1.RawValue rest, err := asn1.Unmarshal(extension, &seq) if err != nil { @@ -150,7 +153,7 @@ func isSANSequence(seq asn1.RawValue) bool { } // processSANSequence processes the SAN sequence and invokes the callback on each element -func processSANSequence(rest []byte, callback func(data []byte) error) error { +func processSANSequence(rest []byte, callback func(data *asn1.RawValue) error) error { for len(rest) > 0 { var v asn1.RawValue var err error @@ -160,7 +163,7 @@ func processSANSequence(rest []byte, callback func(data []byte) error) error { return err } - if err := callback(v.FullBytes); err != nil { + if err := callback(&v); err != nil { return err } } diff --git a/vdr/didx509/x509_utils_test.go b/vdr/didx509/x509_utils_test.go index fc4de62f3..6fee677a0 100644 --- a/vdr/didx509/x509_utils_test.go +++ b/vdr/didx509/x509_utils_test.go @@ -181,7 +181,7 @@ func SigningCertTemplate(serialNumber *big.Int, identifiers []string) (*x509.Cer // Either the ExtraExtensions SubjectAlternativeNameType is set, or the Subject Alternate Name values are set, // both don't mix if len(identifiers) > 0 { - err := setSanAlternativeName(&tmpl, identifiers) + err := setSanAlternativeName(&tmpl, identifiers, "testhost.example.com") if err != nil { return nil, err } @@ -193,8 +193,14 @@ func SigningCertTemplate(serialNumber *big.Int, identifiers []string) (*x509.Cer return &tmpl, nil } -func setSanAlternativeName(tmpl *x509.Certificate, identifiers []string) error { +func setSanAlternativeName(tmpl *x509.Certificate, identifiers []string, altHostName string) error { var list []asn1.RawValue + // Add the alternative host name first + value, err := toRawValue(altHostName, "tag:2") + if err != nil { + return err + } + list = append(list, *value) for _, identifier := range identifiers { raw, err := toRawValue(identifier, "ia5") @@ -230,8 +236,8 @@ func setSanAlternativeName(tmpl *x509.Certificate, identifiers []string) error { } // toRawValue marshals an ASN.1 identifier with a given tag, then unmarshals it into a RawValue structure. -func toRawValue(identifier any, tag string) (*asn1.RawValue, error) { - b, err := asn1.MarshalWithParams(identifier, tag) +func toRawValue(value any, tag string) (*asn1.RawValue, error) { + b, err := asn1.MarshalWithParams(value, tag) if err != nil { return nil, err } @@ -493,8 +499,8 @@ func TestProcessSANSequence(t *testing.T) { panic(err) } wrongValueErr := errors.New("wrong value") - callback := func(data []byte) error { - if !bytes.Equal(data, testRawValue.FullBytes) { + callback := func(v *asn1.RawValue) error { + if !bytes.Equal(v.FullBytes, testRawValue.FullBytes) { return wrongValueErr } return nil @@ -552,8 +558,8 @@ func TestForEachSan(t *testing.T) { panic(err) } wrongValueErr := errors.New("wrong value") - callback := func(data []byte) error { - if !bytes.Equal(data, testEncapsulatedValue.FullBytes) { + callback := func(v *asn1.RawValue) error { + if !bytes.Equal(v.FullBytes, testEncapsulatedValue.FullBytes) { return wrongValueErr } return nil