From 4fd944a74330254fc3e9805cd349e40b3afebc86 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 1 Aug 2023 21:50:10 +0800 Subject: [PATCH] fix: remove readOnlySlice Signed-off-by: Junjie Gao --- internal/encoding/asn1/asn1.go | 106 +++++++++++++------------- internal/encoding/asn1/common.go | 14 ++-- internal/encoding/asn1/constructed.go | 24 +++--- internal/encoding/asn1/io.go | 9 --- internal/encoding/asn1/primitive.go | 18 +++-- internal/encoding/asn1/slice.go | 87 --------------------- 6 files changed, 84 insertions(+), 174 deletions(-) delete mode 100644 internal/encoding/asn1/io.go delete mode 100644 internal/encoding/asn1/slice.go diff --git a/internal/encoding/asn1/asn1.go b/internal/encoding/asn1/asn1.go index 18f1b5f1..fe7a4a21 100644 --- a/internal/encoding/asn1/asn1.go +++ b/internal/encoding/asn1/asn1.go @@ -6,22 +6,21 @@ package asn1 import ( "bytes" "encoding/asn1" - "io" ) // Common errors var ( - ErrEarlyEOF = asn1.SyntaxError{Msg: "early EOF"} - ErrUnsupportedLength = asn1.StructuralError{Msg: "length method not supported"} - ErrUnsupportedIndefinedLenth = asn1.StructuralError{Msg: "indefinite length not supported"} - ErrInvalidSlice = asn1.StructuralError{Msg: "invalid slice"} - ErrInvalidOffset = asn1.StructuralError{Msg: "invalid offset"} + ErrEarlyEOF = asn1.SyntaxError{Msg: "early EOF"} + ErrUnsupportedLen = asn1.StructuralError{Msg: "length method not supported"} + ErrUnsupportedIndefinedLen = asn1.StructuralError{Msg: "indefinite length not supported"} + ErrInvalidSlice = asn1.StructuralError{Msg: "invalid slice"} + ErrInvalidOffset = asn1.StructuralError{Msg: "invalid offset"} ) // value represents an ASN.1 value. type value interface { // Encode encodes the value to the value writer in DER. - Encode(valueWriter) error + Encode(*bytes.Buffer) error // EncodedLen returns the length in bytes of the encoded data. EncodedLen() int @@ -29,7 +28,7 @@ type value interface { // ConvertToDER converts BER-encoded ASN.1 data structures to DER-encoded. func ConvertToDER(ber []byte) ([]byte, error) { - v, err := decode(newReadOnlySlice(ber)) + v, _, err := decode(ber) if err != nil { return nil, err } @@ -41,92 +40,89 @@ func ConvertToDER(ber []byte) ([]byte, error) { } // decode decodes BER-encoded ASN.1 data structures. -func decode(r readOnlySlice) (value, error) { - identifier, isPrimitiveValue, err := decodeIdentifier(r) +func decode(r []byte) (value, []byte, error) { + identifier, r, err := decodeIdentifier(r) if err != nil { - return nil, err + return nil, nil, err } - contentLength, err := decodeLength(r) + contentLength, r, err := decodeLength(r) if err != nil { - return nil, err + return nil, nil, err } - content, err := r.Slice(r.Offset(), r.Offset()+contentLength) - if err != nil { - return nil, err + + if contentLength > len(r) { + return nil, nil, ErrEarlyEOF } - if err = r.Seek(r.Offset() + contentLength); err != nil { - return nil, err + content := r[:contentLength] + r = r[contentLength:] + + isPrimitive := identifier[0]&0x20 == 0 + // primitive value + if isPrimitive { + return newPrimitiveValue(identifier, content), r, nil } - if isPrimitiveValue { - return newPrimitiveValue(identifier, content), nil + // constructed value + v, err := newConstructedValue(identifier, content) + if err != nil { + return nil, nil, err } - return newConstructedValue(identifier, content) + return v, r, nil } // decodeIdentifier decodes decodeIdentifier octets. -func decodeIdentifier(r readOnlySlice) (readOnlySlice, bool, error) { - b, err := r.ReadByte() - if err != nil { - return nil, false, err +func decodeIdentifier(r []byte) ([]byte, []byte, error) { + offset := 0 + if len(r) < 1 { + return nil, nil, ErrEarlyEOF } - isPrimitive := b&0x20 == 0 + b := r[offset] + offset++ - tagBytesCount := 1 // high-tag-number form if b&0x1f == 0x1f { - for { - b, err = r.ReadByte() - if err != nil { - return nil, false, err - } - tagBytesCount++ - if b&0x80 != 0 { - break - } + for offset < len(r) && r[offset]&0x80 == 0x80 { + offset++ } } - - identifier, err := r.Slice(r.Offset()-tagBytesCount, r.Offset()) - if err != nil { - return nil, false, err - } - return identifier, isPrimitive, nil + return r[:offset], r[offset:], nil } // decodeLength decodes length octets. // Indefinite length is not supported -func decodeLength(r io.ByteReader) (int, error) { - b, err := r.ReadByte() - if err != nil { - return 0, err +func decodeLength(r []byte) (int, []byte, error) { + offset := 0 + if len(r) < 1 { + return 0, nil, ErrEarlyEOF } + b := r[offset] + offset++ switch { case b < 0x80: // short form - return int(b), nil + return int(b), r[offset:], nil case b == 0x80: // Indefinite-length method is not supported. - return 0, ErrUnsupportedIndefinedLenth + return 0, nil, ErrUnsupportedIndefinedLen } // long form n := int(b & 0x7f) if n > 4 { // length must fit the memory space of the int type. - return 0, ErrUnsupportedLength + return 0, nil, ErrUnsupportedLen } var length int for i := 0; i < n; i++ { - b, err = r.ReadByte() - if err != nil { - return 0, err + if offset >= len(r) { + return 0, nil, ErrEarlyEOF } - length = (length << 8) | int(b) + length = (length << 8) | int(r[offset]) + offset++ } if length < 0 { // double check in case that length is over 31 bits. - return 0, ErrUnsupportedLength + return 0, nil, ErrUnsupportedLen } - return length, nil + return length, r[offset:], nil } diff --git a/internal/encoding/asn1/common.go b/internal/encoding/asn1/common.go index dbdc9912..0c904cb1 100644 --- a/internal/encoding/asn1/common.go +++ b/internal/encoding/asn1/common.go @@ -1,16 +1,18 @@ package asn1 -import "io" +import ( + "bytes" +) -// encodeLength encodes length octets in DER. -func encodeLength(w io.ByteWriter, length int) error { +// encodeLen encodes length octets in DER. +func encodeLen(w *bytes.Buffer, length int) error { // DER restriction: short form must be used for length less than 128 if length < 0x80 { return w.WriteByte(byte(length)) } // DER restriction: long form must be encoded in the minimum number of octets - lengthSize := encodedLengthSize(length) + lengthSize := encodedLenSize(length) err := w.WriteByte(0x80 | byte(lengthSize-1)) if err != nil { return err @@ -23,8 +25,8 @@ func encodeLength(w io.ByteWriter, length int) error { return nil } -// encodedLengthSize gives the number of octets used for encoding the length. -func encodedLengthSize(length int) int { +// encodedLenSize gives the number of octets used for encoding the length. +func encodedLenSize(length int) int { if length < 0x80 { return 1 } diff --git a/internal/encoding/asn1/constructed.go b/internal/encoding/asn1/constructed.go index 2fe37abe..26a142f1 100644 --- a/internal/encoding/asn1/constructed.go +++ b/internal/encoding/asn1/constructed.go @@ -1,18 +1,24 @@ package asn1 +import "bytes" + // constructedValue represents a value in constructed encoding. type constructedValue struct { - identifier readOnlySlice + identifier []byte length int members []value } // newConstructedValue builds the constructed value. -func newConstructedValue(identifier readOnlySlice, content readOnlySlice) (value, error) { - var members []value +func newConstructedValue(identifier []byte, content []byte) (value, error) { + var ( + members []value + value value + err error + ) encodedLength := 0 - for content.Offset() < content.Length() { - value, err := decode(content) + for len(content) > 0 { + value, content, err = decode(content) if err != nil { return nil, err } @@ -28,12 +34,12 @@ func newConstructedValue(identifier readOnlySlice, content readOnlySlice) (value } // Encode encodes the constructed value to the value writer in DER. -func (v constructedValue) Encode(w valueWriter) error { - _, err := w.ReadFrom(v.identifier) +func (v constructedValue) Encode(w *bytes.Buffer) error { + _, err := w.Write(v.identifier) if err != nil { return err } - if err = encodeLength(w, v.length); err != nil { + if err = encodeLen(w, v.length); err != nil { return err } for _, value := range v.members { @@ -46,5 +52,5 @@ func (v constructedValue) Encode(w valueWriter) error { // EncodedLen returns the length in bytes of the encoded data. func (v constructedValue) EncodedLen() int { - return v.identifier.Length() + encodedLengthSize(v.length) + v.length + return len(v.identifier) + encodedLenSize(v.length) + v.length } diff --git a/internal/encoding/asn1/io.go b/internal/encoding/asn1/io.go deleted file mode 100644 index e9f5ec26..00000000 --- a/internal/encoding/asn1/io.go +++ /dev/null @@ -1,9 +0,0 @@ -package asn1 - -import "io" - -// valueWriter is the interface for writing a value. -type valueWriter interface { - io.ReaderFrom - io.ByteWriter -} diff --git a/internal/encoding/asn1/primitive.go b/internal/encoding/asn1/primitive.go index 0c9719d2..f13f2d7b 100644 --- a/internal/encoding/asn1/primitive.go +++ b/internal/encoding/asn1/primitive.go @@ -1,13 +1,15 @@ package asn1 +import "bytes" + // primitiveValue represents a value in primitive encoding. type primitiveValue struct { - identifier readOnlySlice - content readOnlySlice + identifier []byte + content []byte } // newPrimitiveValue builds the primitive value. -func newPrimitiveValue(identifier readOnlySlice, content readOnlySlice) value { +func newPrimitiveValue(identifier []byte, content []byte) value { return primitiveValue{ identifier: identifier, content: content, @@ -15,19 +17,19 @@ func newPrimitiveValue(identifier readOnlySlice, content readOnlySlice) value { } // Encode encodes the primitive value to the value writer in DER. -func (v primitiveValue) Encode(w valueWriter) error { - _, err := w.ReadFrom(v.identifier) +func (v primitiveValue) Encode(w *bytes.Buffer) error { + _, err := w.Write(v.identifier) if err != nil { return err } - if err = encodeLength(w, v.content.Length()); err != nil { + if err = encodeLen(w, len(v.content)); err != nil { return err } - _, err = w.ReadFrom(v.content) + _, err = w.Write(v.content) return err } // EncodedLen returns the length in bytes of the encoded data. func (v primitiveValue) EncodedLen() int { - return v.identifier.Length() + encodedLengthSize(v.content.Length()) + v.content.Length() + return len(v.identifier) + encodedLenSize(len(v.content)) + len(v.content) } diff --git a/internal/encoding/asn1/slice.go b/internal/encoding/asn1/slice.go deleted file mode 100644 index 5a5574ea..00000000 --- a/internal/encoding/asn1/slice.go +++ /dev/null @@ -1,87 +0,0 @@ -package asn1 - -import "io" - -// readOnlySlice is an interface that represents a read-only slice of bytes. -type readOnlySlice interface { - io.ByteReader - io.Reader - - // Length returns the length of the slice. - Length() int - - // Offset returns the current offset of the slice. - Offset() int - - // Seek sets the current offset of the slice to the given value. - Seek(offset int) error - - // Slice returns a new ReadOnlySlice that represents a sub-slice of the current slice. - // The sub-slice starts at the given begin index and ends at the given end index (exclusive). - Slice(begin int, end int) (readOnlySlice, error) -} - -// byteSlice is a struct that implements the ReadOnlySlice interface. -type byteSlice struct { - data []byte - offset int -} - -// newReadOnlySlice creates a new ReadOnlySlice from the given byte slice. -func newReadOnlySlice(data []byte) readOnlySlice { - return &byteSlice{ - data: data, - offset: 0, - } -} - -// ReadByte reads and returns a single byte from the slice. -// If the end of the slice has been reached, it returns an error. -func (r *byteSlice) ReadByte() (byte, error) { - if r.offset >= len(r.data) { - return 0, ErrEarlyEOF - } - b := r.data[r.offset] - r.offset++ - return b, nil -} - -// Read reads up to len(p) bytes from the slice into p. -func (r *byteSlice) Read(p []byte) (int, error) { - if r.offset >= len(r.data) { - return 0, io.EOF - } - n := copy(p, r.data[r.offset:]) - r.offset += n - return n, nil -} - -// Length returns the length of the slice. -func (r *byteSlice) Length() int { - return len(r.data) -} - -// Offset returns the current offset of the slice. -func (r *byteSlice) Offset() int { - return r.offset -} - -// Seek sets the current offset of the slice to the given value. -func (r *byteSlice) Seek(offset int) error { - if offset < 0 || offset > len(r.data) { - return ErrInvalidOffset - } - r.offset = offset - return nil -} - -// Slice returns a new ReadOnlySlice that represents a sub-slice of the current slice. -func (r *byteSlice) Slice(begin int, end int) (readOnlySlice, error) { - if begin < 0 || end < 0 || begin > end || end > len(r.data) { - return nil, ErrInvalidSlice - } - return &byteSlice{ - data: r.data[begin:end], - offset: 0, - }, nil -}