Skip to content

Commit

Permalink
fix: Replace DER with ASN1 BER encoding when parsing distinguishedNam…
Browse files Browse the repository at this point in the history
…es (#505)

* fix: Replace DER with ASN1 BER encoding when parsing distinguishedNames
* Remove leftover comment
  • Loading branch information
cpuschma authored Apr 7, 2024
1 parent 9c14185 commit 2260012
Show file tree
Hide file tree
Showing 4 changed files with 12 additions and 26 deletions.
17 changes: 5 additions & 12 deletions dn.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package ldap

import (
"encoding/asn1"
"encoding/hex"
"errors"
"fmt"
ber "github.com/go-asn1-ber/asn1-ber"
"sort"
"strings"
"unicode"
Expand Down Expand Up @@ -35,9 +35,6 @@ func (a *AttributeTypeAndValue) setValue(s string) error {
// AttributeValue is represented by an number sign ('#' U+0023)
// character followed by the hexadecimal encoding of each of the octets
// of the BER encoding of the X.500 AttributeValue.
//
// WARNING: we only support hex-encoded ASN.1 DER values here, not
// BER encoding. This is a deviation from the RFC.
if len(s) > 0 && s[0] == '#' {
decodedString, err := decodeEncodedString(s[1:])
if err != nil {
Expand Down Expand Up @@ -233,19 +230,15 @@ func encodeString(value string, isValue bool) string {
func decodeEncodedString(str string) (string, error) {
decoded, err := hex.DecodeString(str)
if err != nil {
return "", fmt.Errorf("failed to decode BER encoding: %s", err)
return "", fmt.Errorf("failed to decode BER encoding: %w", err)
}

var rawValue asn1.RawValue
result, err := asn1.Unmarshal(decoded, &rawValue)
packet, err := ber.DecodePacketErr(decoded)
if err != nil {
return "", fmt.Errorf("failed to unmarshal hex-encoded string: %s", err)
}
if len(result) != 0 {
return "", errors.New("trailing data after unmarshalling hex-encoded string")
return "", fmt.Errorf("failed to decode BER encoding: %w", err)
}

return string(rawValue.Bytes), nil
return packet.Data.String(), nil
}

// ParseDN returns a distinguishedName or an error.
Expand Down
2 changes: 1 addition & 1 deletion dn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func TestErrorDNParsing(t *testing.T) {
"1.3.6.1.4.1.1466.0=test+": "DN ended with incomplete type, value pair",
`1.3.6.1.4.1.1466.0=test;`: "DN ended with incomplete type, value pair",
"1.3.6.1.4.1.1466.0=test+,": "incomplete type, value pair",
"DF=#6666666666665006838820013100000746939546349182108463491821809FBFFFFFFFFF": "failed to unmarshal hex-encoded string: asn1: syntax error: data truncated",
"DF=#6666666666665006838820013100000746939546349182108463491821809FBFFFFFFFFF": "failed to decode BER encoding: unexpected EOF",
}

for test, answer := range testcases {
Expand Down
17 changes: 5 additions & 12 deletions v3/dn.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package ldap

import (
"encoding/asn1"
"encoding/hex"
"errors"
"fmt"
ber "github.com/go-asn1-ber/asn1-ber"
"sort"
"strings"
"unicode"
Expand Down Expand Up @@ -35,9 +35,6 @@ func (a *AttributeTypeAndValue) setValue(s string) error {
// AttributeValue is represented by an number sign ('#' U+0023)
// character followed by the hexadecimal encoding of each of the octets
// of the BER encoding of the X.500 AttributeValue.
//
// WARNING: we only support hex-encoded ASN.1 DER values here, not
// BER encoding. This is a deviation from the RFC.
if len(s) > 0 && s[0] == '#' {
decodedString, err := decodeEncodedString(s[1:])
if err != nil {
Expand Down Expand Up @@ -233,19 +230,15 @@ func encodeString(value string, isValue bool) string {
func decodeEncodedString(str string) (string, error) {
decoded, err := hex.DecodeString(str)
if err != nil {
return "", fmt.Errorf("failed to decode BER encoding: %s", err)
return "", fmt.Errorf("failed to decode BER encoding: %w", err)
}

var rawValue asn1.RawValue
result, err := asn1.Unmarshal(decoded, &rawValue)
packet, err := ber.DecodePacketErr(decoded)
if err != nil {
return "", fmt.Errorf("failed to unmarshal hex-encoded string: %s", err)
}
if len(result) != 0 {
return "", errors.New("trailing data after unmarshalling hex-encoded string")
return "", fmt.Errorf("failed to decode BER encoding: %w", err)
}

return string(rawValue.Bytes), nil
return packet.Data.String(), nil
}

// ParseDN returns a distinguishedName or an error.
Expand Down
2 changes: 1 addition & 1 deletion v3/dn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func TestErrorDNParsing(t *testing.T) {
"1.3.6.1.4.1.1466.0=test+": "DN ended with incomplete type, value pair",
`1.3.6.1.4.1.1466.0=test;`: "DN ended with incomplete type, value pair",
"1.3.6.1.4.1.1466.0=test+,": "incomplete type, value pair",
"DF=#6666666666665006838820013100000746939546349182108463491821809FBFFFFFFFFF": "failed to unmarshal hex-encoded string: asn1: syntax error: data truncated",
"DF=#6666666666665006838820013100000746939546349182108463491821809FBFFFFFFFFF": "failed to decode BER encoding: unexpected EOF",
}

for test, answer := range testcases {
Expand Down

0 comments on commit 2260012

Please sign in to comment.