Patch ASN.1 BER encoding of integers and length + unit tests

This commit is contained in:
Quentin 2021-09-16 13:51:43 +02:00
parent 2a844bd559
commit a08be6b395
Signed by: quentin
GPG key ID: A98E9B769E4FF428
3 changed files with 160 additions and 10 deletions

View file

@ -223,19 +223,33 @@ func parseInt64(bytes []byte) (ret int64, err error) {
return return
} }
func sizeInt64(i int64) (size int) { func sizeInt64(i int64) int {
for ; i != 0 || size == 0; i >>= 8 { n := 1
size++
for i > 127 {
n++
i >>= 8
} }
return
for i < -128 {
n++
i >>= 8
}
return n
} }
func writeInt64(bytes *Bytes, i int64) (size int) { func writeInt64(bytes *Bytes, i int64) int {
for ; i != 0 || size == 0; i >>= 8 { // Write at least one byte even if the value is 0 n := sizeInt64(i)
bytes.writeBytes([]byte{byte(i)}) buf := [8]byte{}
size++
for j := 0; j < n; j++ {
b := i >> uint((n-1-j)*8)
buf[j] = byte(b)
} }
return bytes.writeBytes(buf[:n])
return n
} }
// parseInt treats the given bytes as a big-endian, signed integer and returns // parseInt treats the given bytes as a big-endian, signed integer and returns
@ -713,7 +727,13 @@ func writeTagAndLength(bytes *Bytes, t TagAndLength) (size int) {
panic("Can't have a negative length") panic("Can't have a negative length")
} else if t.Length >= 128 { } else if t.Length >= 128 {
lengthBytes := writeInt64(bytes, int64(t.Length)) lengthBytes := 0
val := t.Length
for val > 0 {
lengthBytes++
bytes.writeBytes([]byte{byte(val & 0xff)})
val >>= 8
}
bytes.writeBytes([]byte{byte(0x80 | byte(lengthBytes))}) bytes.writeBytes([]byte{byte(0x80 | byte(lengthBytes))})
size += lengthBytes + 1 size += lengthBytes + 1

54
goldap/asn1_test.go Normal file
View file

@ -0,0 +1,54 @@
package message
import (
"testing"
"bytes"
)
func TestSizeInt64(t *testing.T) {
s := sizeInt64(0)
if s != 1 {
t.Errorf("computed size is %d, expected 1", s)
}
s = sizeInt64(127)
if s != 1 {
t.Errorf("computed size is %d, expected 1", s)
}
s = sizeInt64(128)
if s != 2 {
t.Errorf("computed size is %d, expected 2", s)
}
s = sizeInt64(50000)
if s != 3 {
t.Errorf("computed size is %d, expected 3", s)
}
s = sizeInt64(-12345)
if s != 2 {
t.Errorf("computed size is %d, expected 2", s)
}
}
func TestWriteInt64(t *testing.T) {
vtests := []int64{0, 127, 128, 50000, -12345}
expsize := []int{1, 1, 2, 3, 2}
expresult := [][]byte{{0x00}, {0x7F}, {0x00, 0x80}, {0x00, 0xc3, 0x50}, {0xcf, 0xc7}}
for idx, v := range vtests {
fs := sizeInt64(v)
b := NewBytes(fs, make([]byte, fs))
t.Log("computing", v)
s := writeInt64(b, v)
if s != expsize[idx] {
t.Errorf("computed size is %d, expected %d", s, expsize[idx])
}
if !bytes.Equal(b.Bytes(), expresult[idx]) {
t.Errorf("wrong computed bytes, got %v, expected %v", b.Bytes(), expresult[idx])
}
a, e := parseInt64(b.Bytes())
t.Log("parse", a, e)
}
}

76
goldap/message_test.go Normal file
View file

@ -0,0 +1,76 @@
package message
import (
"testing"
"fmt"
)
func toHex(b []byte) (r string) {
r = "[ "
for _, e := range b {
r += fmt.Sprintf("0x%x ", e)
}
return r + "]"
}
func TestMessageID(t *testing.T) {
m := NewLDAPMessageWithProtocolOp(UnbindRequest{})
m.SetMessageID(128)
buf, err := m.Write()
if err != nil {
t.Errorf("marshalling failed with %v", err)
}
t.Logf("%v", toHex(buf.Bytes()))
ret, err := ReadLDAPMessage(NewBytes(0, buf.Bytes()))
if err != nil {
t.Errorf("unmarshalling failed with %v", err)
}
if _, ok := ret.ProtocolOp().(UnbindRequest); !ok {
t.Errorf("should be an unbind request")
}
if ret.MessageID() != 128 {
t.Errorf("Expect message id 128, got %d", ret.MessageID())
}
t.Log("Done, marshal/unmarshall worked")
}
func TestSearchEntry(t *testing.T) {
m := NewLDAPMessageWithProtocolOp(SearchResultEntry{
objectName:"cn=êige€nbgtz,ou=users,dc=deuxfleurs,dc=fr",
attributes: PartialAttributeList{
PartialAttribute{
type_:"displayname",
vals:[]AttributeValue{"êiGe€NBgTZ"},
},
PartialAttribute{
type_:"objectclass",
vals:[]AttributeValue{"inetOrgPerson"},
},
PartialAttribute{
type_:"objectclass",
vals:[]AttributeValue{"organizationalPerson"},
},
PartialAttribute{
type_:"objectclass",
vals:[]AttributeValue{"person"},
},
PartialAttribute{
type_:"objectclass",
vals:[]AttributeValue{"top"},
},
PartialAttribute{
type_:"structuralobjectclass",
vals:[]AttributeValue{"inetOrgPerson"},
},
},
})
m.SetMessageID(24)
buf, err := m.Write()
if err != nil {
t.Errorf("marshalling failed with %v", err)
}
if buf.Bytes()[0] != 0x30 {
t.Logf("Malformed message: %v", toHex(buf.Bytes()))
}
}