aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2021-09-16 13:51:43 +0200
committerQuentin Dufour <quentin@deuxfleurs.fr>2021-09-16 13:51:43 +0200
commita08be6b395949a74efc8115a726112d64e96b44d (patch)
tree7d187ef4c3a59a4e8b8bd7abec7dff958846a28a
parent2a844bd5590fc58a9f68346eaa0554e9df4625f1 (diff)
downloadbottin-a08be6b395949a74efc8115a726112d64e96b44d.tar.gz
bottin-a08be6b395949a74efc8115a726112d64e96b44d.zip
Patch ASN.1 BER encoding of integers and length + unit tests
-rw-r--r--goldap/asn1.go40
-rw-r--r--goldap/asn1_test.go54
-rw-r--r--goldap/message_test.go76
3 files changed, 160 insertions, 10 deletions
diff --git a/goldap/asn1.go b/goldap/asn1.go
index d1539d9..08164eb 100644
--- a/goldap/asn1.go
+++ b/goldap/asn1.go
@@ -223,19 +223,33 @@ func parseInt64(bytes []byte) (ret int64, err error) {
return
}
-func sizeInt64(i int64) (size int) {
- for ; i != 0 || size == 0; i >>= 8 {
- size++
+func sizeInt64(i int64) int {
+ n := 1
+
+ for i > 127 {
+ n++
+ i >>= 8
}
- return
+
+ for i < -128 {
+ n++
+ i >>= 8
+ }
+
+ return n
}
-func writeInt64(bytes *Bytes, i int64) (size int) {
- for ; i != 0 || size == 0; i >>= 8 { // Write at least one byte even if the value is 0
- bytes.writeBytes([]byte{byte(i)})
- size++
+func writeInt64(bytes *Bytes, i int64) int {
+ n := sizeInt64(i)
+ buf := [8]byte{}
+
+ 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
@@ -713,7 +727,13 @@ func writeTagAndLength(bytes *Bytes, t TagAndLength) (size int) {
panic("Can't have a negative length")
} 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))})
size += lengthBytes + 1
diff --git a/goldap/asn1_test.go b/goldap/asn1_test.go
new file mode 100644
index 0000000..eb11d29
--- /dev/null
+++ b/goldap/asn1_test.go
@@ -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)
+ }
+}
diff --git a/goldap/message_test.go b/goldap/message_test.go
new file mode 100644
index 0000000..9d10d98
--- /dev/null
+++ b/goldap/message_test.go
@@ -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()))
+ }
+}