parse BER-TLV with multiple length bytes
This commit is contained in:
parent
d6f78d1951
commit
d8a6a41ca7
|
@ -2,10 +2,17 @@ package apdu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrUnsupportedLenth80 = errors.New("length cannot be 0x80")
|
||||||
|
ErrLengthTooBig = errors.New("length cannot be more than 3 bytes")
|
||||||
|
)
|
||||||
|
|
||||||
// ErrTagNotFound is an error returned if a tag is not found in a TLV sequence.
|
// ErrTagNotFound is an error returned if a tag is not found in a TLV sequence.
|
||||||
type ErrTagNotFound struct {
|
type ErrTagNotFound struct {
|
||||||
tag uint8
|
tag uint8
|
||||||
|
@ -36,7 +43,7 @@ func findTag(raw []byte, occurrence int, tags ...uint8) ([]byte, error) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tag uint8
|
tag uint8
|
||||||
length uint8
|
length uint32
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -49,11 +56,7 @@ func findTag(raw []byte, occurrence int, tags ...uint8) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
length, err = buf.ReadByte()
|
length, buf, err = parseLength(buf)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
data := make([]byte, length)
|
data := make([]byte, length)
|
||||||
if length != 0 {
|
if length != 0 {
|
||||||
_, err = buf.Read(data)
|
_, err = buf.Read(data)
|
||||||
|
@ -77,3 +80,34 @@ func findTag(raw []byte, occurrence int, tags ...uint8) ([]byte, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseLength(buf *bytes.Buffer) (uint32, *bytes.Buffer, error) {
|
||||||
|
length, err := buf.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if length == 0x80 {
|
||||||
|
return 0, nil, ErrUnsupportedLenth80
|
||||||
|
}
|
||||||
|
|
||||||
|
if length > 0x80 {
|
||||||
|
lengthSize := length - 0x80
|
||||||
|
if lengthSize > 3 {
|
||||||
|
return 0, nil, ErrLengthTooBig
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make([]byte, lengthSize)
|
||||||
|
_, err = buf.Read(data)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
num := make([]byte, 4)
|
||||||
|
copy(num[4-lengthSize:], data)
|
||||||
|
|
||||||
|
return binary.BigEndian.Uint32(num), buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint32(length), buf, nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package apdu
|
package apdu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/status-im/keycard-go/hexutils"
|
"github.com/status-im/keycard-go/hexutils"
|
||||||
|
@ -42,6 +43,61 @@ func TestFindTag(t *testing.T) {
|
||||||
assert.Equal(t, &ErrTagNotFound{uint8(0xC3)}, err)
|
assert.Equal(t, &ErrTagNotFound{uint8(0xC3)}, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseLength(t *testing.T) {
|
||||||
|
scenarios := []struct {
|
||||||
|
data []byte
|
||||||
|
expectedLength uint32
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
data: []byte{0x01, 0xAA},
|
||||||
|
expectedLength: 1,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte{0x7F, 0xAA},
|
||||||
|
expectedLength: 127,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte{0x81, 0x80, 0xAA},
|
||||||
|
expectedLength: 128,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte{0x82, 0x80, 0x80, 0xAA},
|
||||||
|
expectedLength: 32896,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte{0x83, 0x80, 0x80, 0x80, 0xAA},
|
||||||
|
expectedLength: 8421504,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte{0x80, 0xAA},
|
||||||
|
expectedLength: 0,
|
||||||
|
err: ErrUnsupportedLenth80,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: []byte{0x84, 0xAA},
|
||||||
|
expectedLength: 0,
|
||||||
|
err: ErrLengthTooBig,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
buf := bytes.NewBuffer(s.data)
|
||||||
|
length, _, err := parseLength(buf)
|
||||||
|
if s.err == nil {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, s.expectedLength, length)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, s.err, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFindTagN(t *testing.T) {
|
func TestFindTagN(t *testing.T) {
|
||||||
data := hexutils.HexToBytes("0A 01 A1 0A 01 A2")
|
data := hexutils.HexToBytes("0A 01 A1 0A 01 A2")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue