760 lines
18 KiB
Go
760 lines
18 KiB
Go
package message
|
|
|
|
// Below code is largely inspired from the standard golang library encoding/asn
|
|
// If put BEGIN / END tags in the comments to give the original library name
|
|
import (
|
|
// "errors"
|
|
"fmt"
|
|
"math/big"
|
|
// "strconv"
|
|
// "time"
|
|
)
|
|
|
|
//
|
|
// BEGIN: encoding/asn1/common.go
|
|
//
|
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
const (
|
|
tagBoolean = 1
|
|
tagInteger = 2
|
|
// tagBitString = 3
|
|
tagOctetString = 4
|
|
// tagOID = 6
|
|
tagEnum = 10
|
|
// tagUTF8String = 12
|
|
tagSequence = 16
|
|
tagSet = 17
|
|
// tagPrintableString = 19
|
|
// tagT61String = 20
|
|
// tagIA5String = 22
|
|
// tagUTCTime = 23
|
|
// tagGeneralizedTime = 24
|
|
tagGeneralString = 27
|
|
)
|
|
|
|
var tagNames = map[int]string{
|
|
tagBoolean: "BOOLEAN",
|
|
tagInteger: "INTEGER",
|
|
tagOctetString: "OCTET STRING",
|
|
tagEnum: "ENUM",
|
|
tagSequence: "SEQUENCE",
|
|
tagSet: "SET",
|
|
}
|
|
|
|
const (
|
|
classUniversal = 0
|
|
classApplication = 1
|
|
classContextSpecific = 2
|
|
// classPrivate = 3
|
|
)
|
|
|
|
var classNames = map[int]string{
|
|
classUniversal: "UNIVERSAL",
|
|
classApplication: "APPLICATION",
|
|
classContextSpecific: "CONTEXT SPECIFIC",
|
|
}
|
|
|
|
const (
|
|
isCompound = true
|
|
isNotCompound = false
|
|
)
|
|
|
|
var compoundNames = map[bool]string{
|
|
isCompound: "COMPOUND",
|
|
isNotCompound: "NOT COMPOUND",
|
|
}
|
|
|
|
type TagAndLength struct {
|
|
Class, Tag, Length int
|
|
IsCompound bool
|
|
}
|
|
|
|
//
|
|
// END: encoding/asn1/common.go
|
|
//
|
|
|
|
func (t *TagAndLength) Expect(class int, tag int, isCompound bool) (err error) {
|
|
err = t.ExpectClass(class)
|
|
if err != nil {
|
|
return LdapError{fmt.Sprintf("Expect: %s.", err)}
|
|
}
|
|
err = t.ExpectTag(tag)
|
|
if err != nil {
|
|
return LdapError{fmt.Sprintf("Expect: %s.", err)}
|
|
}
|
|
err = t.ExpectCompound(isCompound)
|
|
if err != nil {
|
|
return LdapError{fmt.Sprintf("Expect: %s.", err)}
|
|
}
|
|
return
|
|
}
|
|
func (t *TagAndLength) ExpectClass(class int) (err error) {
|
|
if class != t.Class {
|
|
err = SyntaxError{fmt.Sprintf("ExpectClass: wrong tag class: got %d (%s), expected %d (%s)", t.Class, classNames[t.Class], class, classNames[class])}
|
|
}
|
|
return
|
|
}
|
|
func (t *TagAndLength) ExpectTag(tag int) (err error) {
|
|
if tag != t.Tag {
|
|
err = SyntaxError{fmt.Sprintf("ExpectTag: wrong tag value: got %d (%s), expected %d (%s)", t.Tag, tagNames[t.Tag], tag, tagNames[tag])}
|
|
}
|
|
return
|
|
}
|
|
func (t *TagAndLength) ExpectCompound(isCompound bool) (err error) {
|
|
if isCompound != t.IsCompound {
|
|
err = SyntaxError{fmt.Sprintf("ExpectCompound: wrong tag compound: got %t (%s), expected %t (%s)", t.IsCompound, compoundNames[t.IsCompound], isCompound, compoundNames[isCompound])}
|
|
}
|
|
return
|
|
}
|
|
|
|
func ParseTagAndLength(bytes []byte, initOffset int) (ret TagAndLength, offset int, err error) {
|
|
ret, offset, err = parseTagAndLength(bytes, initOffset)
|
|
return
|
|
}
|
|
|
|
//
|
|
// BEGIN encoding/asn1/asn1.go
|
|
//
|
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package asn1 implements parsing of DER-encoded ASN.1 data structures,
|
|
// as defined in ITU-T Rec X.690.
|
|
//
|
|
// See also ``A Layman's Guide to a Subset of ASN.1, BER, and DER,''
|
|
// http://luca.ntop.org/Teaching/Appunti/asn1.html.
|
|
// package asn1
|
|
|
|
// ASN.1 is a syntax for specifying abstract objects and BER, DER, PER, XER etc
|
|
// are different encoding formats for those objects. Here, we'll be dealing
|
|
// with DER, the Distinguished Encoding Rules. DER is used in X.509 because
|
|
// it's fast to parse and, unlike BER, has a unique encoding for every object.
|
|
// When calculating hashes over objects, it's important that the resulting
|
|
// bytes be the same at both ends and DER removes this margin of error.
|
|
//
|
|
// ASN.1 is very complex and this package doesn't attempt to implement
|
|
// everything by any means.
|
|
|
|
//import (
|
|
// "fmt"
|
|
// "math/big"
|
|
// "reflect"
|
|
// "strconv"
|
|
// "time"
|
|
//)
|
|
|
|
// A StructuralError suggests that the ASN.1 data is valid, but the Go type
|
|
// which is receiving it doesn't match.
|
|
type StructuralError struct {
|
|
Msg string
|
|
}
|
|
|
|
func (e StructuralError) Error() string { return "asn1: structure error: " + e.Msg }
|
|
|
|
// A SyntaxError suggests that the ASN.1 data is invalid.
|
|
type SyntaxError struct {
|
|
Msg string
|
|
}
|
|
|
|
func (e SyntaxError) Error() string { return "asn1: syntax error: " + e.Msg }
|
|
|
|
// We start by dealing with each of the primitive types in turn.
|
|
|
|
// BOOLEAN
|
|
|
|
func parseBool(bytes []byte) (ret bool, err error) {
|
|
if len(bytes) > 1 {
|
|
err = SyntaxError{"invalid boolean: should be encoded on one byte only"}
|
|
return
|
|
} else if len(bytes) == 0 {
|
|
err = SyntaxError{"invalid boolean: no data to read"}
|
|
}
|
|
|
|
// DER demands that "If the encoding represents the boolean value TRUE,
|
|
// its single contents octet shall have all eight bits set to one."
|
|
// Thus only 0 and 255 are valid encoded values.
|
|
switch bytes[0] {
|
|
case 0:
|
|
ret = false
|
|
case 0xff:
|
|
ret = true
|
|
default:
|
|
err = SyntaxError{"invalid boolean: should be 0x00 of 0xFF"}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func sizeBool(b bool) int {
|
|
return 1
|
|
}
|
|
|
|
func writeBool(bytes *Bytes, b bool) int {
|
|
if b == false {
|
|
return bytes.writeBytes([]byte{0x00})
|
|
} else {
|
|
return bytes.writeBytes([]byte{0xff})
|
|
}
|
|
}
|
|
|
|
// INTEGER
|
|
|
|
// parseInt64 treats the given bytes as a big-endian, signed integer and
|
|
// returns the result.
|
|
func parseInt64(bytes []byte) (ret int64, err error) {
|
|
if len(bytes) > 8 {
|
|
// We'll overflow an int64 in this case.
|
|
err = StructuralError{"integer too large"}
|
|
return
|
|
}
|
|
for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
|
|
ret <<= 8
|
|
ret |= int64(bytes[bytesRead])
|
|
}
|
|
|
|
// Shift up and down in order to sign extend the result.
|
|
ret <<= 64 - uint8(len(bytes))*8
|
|
ret >>= 64 - uint8(len(bytes))*8
|
|
return
|
|
}
|
|
|
|
func sizeInt64(i int64) int {
|
|
n := 1
|
|
|
|
for i > 127 {
|
|
n++
|
|
i >>= 8
|
|
}
|
|
|
|
for i < -128 {
|
|
n++
|
|
i >>= 8
|
|
}
|
|
|
|
return n
|
|
}
|
|
|
|
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)
|
|
}
|
|
bytes.writeBytes(buf[:n])
|
|
|
|
return n
|
|
}
|
|
|
|
// parseInt treats the given bytes as a big-endian, signed integer and returns
|
|
// the result.
|
|
func parseInt32(bytes []byte) (int32, error) {
|
|
ret64, err := parseInt64(bytes)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if ret64 != int64(int32(ret64)) {
|
|
return 0, StructuralError{"integer too large"}
|
|
}
|
|
return int32(ret64), nil
|
|
}
|
|
|
|
func sizeInt32(i int32) int {
|
|
return sizeInt64(int64(i))
|
|
}
|
|
|
|
func writeInt32(bytes *Bytes, i int32) int {
|
|
return writeInt64(bytes, int64(i))
|
|
}
|
|
|
|
var bigOne = big.NewInt(1)
|
|
|
|
// // parseBigInt treats the given bytes as a big-endian, signed integer and returns
|
|
// // the result.
|
|
// func parseBigInt(bytes []byte) *big.Int {
|
|
// ret := new(big.Int)
|
|
// if len(bytes) > 0 && bytes[0]&0x80 == 0x80 {
|
|
// // This is a negative number.
|
|
// notBytes := make([]byte, len(bytes))
|
|
// for i := range notBytes {
|
|
// notBytes[i] = ^bytes[i]
|
|
// }
|
|
// ret.SetBytes(notBytes)
|
|
// ret.Add(ret, bigOne)
|
|
// ret.Neg(ret)
|
|
// return ret
|
|
// }
|
|
// ret.SetBytes(bytes)
|
|
// return ret
|
|
// }
|
|
|
|
// // BIT STRING
|
|
|
|
// // BitString is the structure to use when you want an ASN.1 BIT STRING type. A
|
|
// // bit string is padded up to the nearest byte in memory and the number of
|
|
// // valid bits is recorded. Padding bits will be zero.
|
|
// type BitString struct {
|
|
// Bytes []byte // bits packed into bytes.
|
|
// BitLength int // length in bits.
|
|
// }
|
|
|
|
// // At returns the bit at the given index. If the index is out of range it
|
|
// // returns false.
|
|
// func (b BitString) At(i int) int {
|
|
// if i < 0 || i >= b.BitLength {
|
|
// return 0
|
|
// }
|
|
// x := i / 8
|
|
// y := 7 - uint(i%8)
|
|
// return int(b.Bytes[x]>>y) & 1
|
|
// }
|
|
|
|
// // RightAlign returns a slice where the padding bits are at the beginning. The
|
|
// // slice may share memory with the BitString.
|
|
// func (b BitString) RightAlign() []byte {
|
|
// shift := uint(8 - (b.BitLength % 8))
|
|
// if shift == 8 || len(b.Bytes) == 0 {
|
|
// return b.Bytes
|
|
// }
|
|
|
|
// a := make([]byte, len(b.Bytes))
|
|
// a[0] = b.Bytes[0] >> shift
|
|
// for i := 1; i < len(b.Bytes); i++ {
|
|
// a[i] = b.Bytes[i-1] << (8 - shift)
|
|
// a[i] |= b.Bytes[i] >> shift
|
|
// }
|
|
|
|
// return a
|
|
// }
|
|
|
|
// // parseBitString parses an ASN.1 bit string from the given byte slice and returns it.
|
|
// func parseBitString(bytes []byte) (ret BitString, err error) {
|
|
// if len(bytes) == 0 {
|
|
// err = SyntaxError{"zero length BIT STRING"}
|
|
// return
|
|
// }
|
|
// paddingBits := int(bytes[0])
|
|
// if paddingBits > 7 ||
|
|
// len(bytes) == 1 && paddingBits > 0 ||
|
|
// bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {
|
|
// err = SyntaxError{"invalid padding bits in BIT STRING"}
|
|
// return
|
|
// }
|
|
// ret.BitLength = (len(bytes)-1)*8 - paddingBits
|
|
// ret.Bytes = bytes[1:]
|
|
// return
|
|
// }
|
|
|
|
// OBJECT IDENTIFIER
|
|
|
|
// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
|
|
// type ObjectIdentifier []int
|
|
|
|
// // Equal reports whether oi and other represent the same identifier.
|
|
// func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
|
|
// if len(oi) != len(other) {
|
|
// return false
|
|
// }
|
|
// for i := 0; i < len(oi); i++ {
|
|
// if oi[i] != other[i] {
|
|
// return false
|
|
// }
|
|
// }
|
|
|
|
// return true
|
|
// }
|
|
|
|
// func (oi ObjectIdentifier) String() string {
|
|
// var s string
|
|
|
|
// for i, v := range oi {
|
|
// if i > 0 {
|
|
// s += "."
|
|
// }
|
|
// s += strconv.Itoa(v)
|
|
// }
|
|
|
|
// return s
|
|
// }
|
|
|
|
// // parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
|
|
// // returns it. An object identifier is a sequence of variable length integers
|
|
// // that are assigned in a hierarchy.
|
|
// func parseObjectIdentifier(bytes []byte) (s []int, err error) {
|
|
// if len(bytes) == 0 {
|
|
// err = SyntaxError{"zero length OBJECT IDENTIFIER"}
|
|
// return
|
|
// }
|
|
|
|
// // In the worst case, we get two elements from the first byte (which is
|
|
// // encoded differently) and then every varint is a single byte long.
|
|
// s = make([]int, len(bytes)+1)
|
|
|
|
// // The first varint is 40*value1 + value2:
|
|
// // According to this packing, value1 can take the values 0, 1 and 2 only.
|
|
// // When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
|
|
// // then there are no restrictions on value2.
|
|
// v, offset, err := parseBase128Int(bytes, 0)
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
// if v < 80 {
|
|
// s[0] = v / 40
|
|
// s[1] = v % 40
|
|
// } else {
|
|
// s[0] = 2
|
|
// s[1] = v - 80
|
|
// }
|
|
|
|
// i := 2
|
|
// for ; offset < len(bytes); i++ {
|
|
// v, offset, err = parseBase128Int(bytes, offset)
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
// s[i] = v
|
|
// }
|
|
// s = s[0:i]
|
|
// return
|
|
// }
|
|
|
|
// ENUMERATED
|
|
|
|
// An Enumerated is represented as a plain int.
|
|
type Enumerated int
|
|
|
|
// FLAG
|
|
|
|
// A Flag accepts any data and is set to true if present.
|
|
type Flag bool
|
|
|
|
// parseBase128Int parses a base-128 encoded int from the given offset in the
|
|
// given byte slice. It returns the value and the new offset.
|
|
func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) {
|
|
offset = initOffset
|
|
for shifted := 0; offset < len(bytes); shifted++ {
|
|
if shifted > 4 {
|
|
err = StructuralError{"base 128 integer too large"}
|
|
return
|
|
}
|
|
ret <<= 7
|
|
b := bytes[offset]
|
|
ret |= int(b & 0x7f)
|
|
offset++
|
|
if b&0x80 == 0 {
|
|
return
|
|
}
|
|
}
|
|
err = SyntaxError{"truncated base 128 integer"}
|
|
return
|
|
}
|
|
|
|
func sizeBase128Int(value int) (size int) {
|
|
for i := value; i > 0; i >>= 7 {
|
|
size++
|
|
}
|
|
return
|
|
}
|
|
|
|
// Write start as the end of the slice and goes back
|
|
// We assume we have enough size
|
|
func writeBase128Int(bytes *Bytes, value int) (size int) {
|
|
for ; value > 0 || size == 0; value >>= 7 { // Write at least one byte even if the value is 0
|
|
// Get the 7 lowest bits
|
|
b := byte(value) & 0x7f
|
|
if value < 128 {
|
|
b |= 0x80
|
|
}
|
|
bytes.writeBytes([]byte{b})
|
|
size++
|
|
}
|
|
return
|
|
}
|
|
|
|
// // UTCTime
|
|
|
|
// func parseUTCTime(bytes []byte) (ret time.Time, err error) {
|
|
// s := string(bytes)
|
|
// ret, err = time.Parse("0601021504Z0700", s)
|
|
// if err != nil {
|
|
// ret, err = time.Parse("060102150405Z0700", s)
|
|
// }
|
|
// if err == nil && ret.Year() >= 2050 {
|
|
// // UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
|
|
// ret = ret.AddDate(-100, 0, 0)
|
|
// }
|
|
|
|
// return
|
|
// }
|
|
|
|
// // parseGeneralizedTime parses the GeneralizedTime from the given byte slice
|
|
// // and returns the resulting time.
|
|
// func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) {
|
|
// return time.Parse("20060102150405Z0700", string(bytes))
|
|
// }
|
|
|
|
// // PrintableString
|
|
|
|
// // parsePrintableString parses a ASN.1 PrintableString from the given byte
|
|
// // array and returns it.
|
|
// func parsePrintableString(bytes []byte) (ret string, err error) {
|
|
// for _, b := range bytes {
|
|
// if !isPrintable(b) {
|
|
// err = SyntaxError{"PrintableString contains invalid character"}
|
|
// return
|
|
// }
|
|
// }
|
|
// ret = string(bytes)
|
|
// return
|
|
// }
|
|
|
|
// // isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
|
|
// func isPrintable(b byte) bool {
|
|
// return 'a' <= b && b <= 'z' ||
|
|
// 'A' <= b && b <= 'Z' ||
|
|
// '0' <= b && b <= '9' ||
|
|
// '\'' <= b && b <= ')' ||
|
|
// '+' <= b && b <= '/' ||
|
|
// b == ' ' ||
|
|
// b == ':' ||
|
|
// b == '=' ||
|
|
// b == '?' ||
|
|
// // This is technically not allowed in a PrintableString.
|
|
// // However, x509 certificates with wildcard strings don't
|
|
// // always use the correct string type so we permit it.
|
|
// b == '*'
|
|
// }
|
|
|
|
// // IA5String
|
|
|
|
// // parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
|
|
// // byte slice and returns it.
|
|
// func parseIA5String(bytes []byte) (ret string, err error) {
|
|
// for _, b := range bytes {
|
|
// if b >= 0x80 {
|
|
// err = SyntaxError{"IA5String contains invalid character"}
|
|
// return
|
|
// }
|
|
// }
|
|
// ret = string(bytes)
|
|
// return
|
|
// }
|
|
|
|
// // T61String
|
|
|
|
// // parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
|
|
// // byte slice and returns it.
|
|
// func parseT61String(bytes []byte) (ret string, err error) {
|
|
// return string(bytes), nil
|
|
// }
|
|
|
|
// UTF8String
|
|
|
|
// parseUTF8String parses a ASN.1 UTF8String (raw UTF-8) from the given byte
|
|
// array and returns it.
|
|
// func parseUTF8String(bytes []byte) (ret string, err error) {
|
|
// return string(bytes), nil
|
|
// }
|
|
// func sizeUTF8String(s string) int {
|
|
// return len(s)
|
|
// }
|
|
// func writeUTF8String(bytes *Bytes, s string) int {
|
|
// return bytes.writeString(s)
|
|
// }
|
|
|
|
// Octet string
|
|
func parseOctetString(bytes []byte) (ret []byte, err error) {
|
|
return bytes, nil
|
|
}
|
|
func sizeOctetString(s []byte) int {
|
|
return len(s)
|
|
}
|
|
func writeOctetString(bytes *Bytes, s []byte) int {
|
|
return bytes.writeBytes(s)
|
|
}
|
|
|
|
// A RawValue represents an undecoded ASN.1 object.
|
|
type RawValue struct {
|
|
Class, Tag int
|
|
IsCompound bool
|
|
Bytes []byte
|
|
FullBytes []byte // includes the tag and length
|
|
}
|
|
|
|
// RawContent is used to signal that the undecoded, DER data needs to be
|
|
// preserved for a struct. To use it, the first field of the struct must have
|
|
// this type. It's an error for any of the other fields to have this type.
|
|
type RawContent []byte
|
|
|
|
// Tagging
|
|
|
|
// parseTagAndLength parses an ASN.1 tag and length pair from the given offset
|
|
// into a byte slice. It returns the parsed data and the new offset. SET and
|
|
// SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we
|
|
// don't distinguish between ordered and unordered objects in this code.
|
|
func parseTagAndLength(bytes []byte, initOffset int) (ret TagAndLength, offset int, err error) {
|
|
offset = initOffset
|
|
b := bytes[offset]
|
|
offset++
|
|
ret.Class = int(b >> 6)
|
|
ret.IsCompound = b&0x20 == 0x20
|
|
ret.Tag = int(b & 0x1f)
|
|
|
|
// If the bottom five bits are set, then the tag number is actually base 128
|
|
// encoded afterwards
|
|
if ret.Tag == 0x1f {
|
|
ret.Tag, offset, err = parseBase128Int(bytes, offset)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
if offset >= len(bytes) {
|
|
err = SyntaxError{"truncated tag or length"}
|
|
return
|
|
}
|
|
b = bytes[offset]
|
|
offset++
|
|
if b&0x80 == 0 {
|
|
// The length is encoded in the bottom 7 bits.
|
|
ret.Length = int(b & 0x7f)
|
|
} else {
|
|
// Bottom 7 bits give the number of length bytes to follow.
|
|
numBytes := int(b & 0x7f)
|
|
if numBytes == 0 {
|
|
err = SyntaxError{"indefinite length found (not DER)"}
|
|
return
|
|
}
|
|
ret.Length = 0
|
|
for i := 0; i < numBytes; i++ {
|
|
if offset >= len(bytes) {
|
|
err = SyntaxError{"truncated tag or length"}
|
|
return
|
|
}
|
|
b = bytes[offset]
|
|
offset++
|
|
if ret.Length >= 1<<23 {
|
|
// We can't shift ret.length up without
|
|
// overflowing.
|
|
err = StructuralError{"length too large"}
|
|
return
|
|
}
|
|
ret.Length <<= 8
|
|
ret.Length |= int(b)
|
|
if ret.Length == 0 {
|
|
// DER requires that lengths be minimal.
|
|
err = StructuralError{"superfluous leading zeros in length"}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// func writeTagAndLength(out *forkableWriter, t tagAndLength) (err error) {
|
|
// b := uint8(t.class) << 6
|
|
// if t.isCompound {
|
|
// b |= 0x20
|
|
// }
|
|
// if t.tag >= 31 {
|
|
// b |= 0x1f
|
|
// err = out.WriteByte(b)
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
// err = marshalBase128Int(out, int64(t.tag))
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
// } else {
|
|
// b |= uint8(t.tag)
|
|
// err = out.WriteByte(b)
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
// }
|
|
|
|
// if t.length >= 128 {
|
|
// l := lengthLength(t.length)
|
|
// err = out.WriteByte(0x80 | byte(l))
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
// err = marshalLength(out, t.length)
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
// } else {
|
|
// err = out.WriteByte(byte(t.length))
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
// }
|
|
|
|
// return nil
|
|
// }
|
|
|
|
func sizeTagAndLength(tag int, length int) (size int) {
|
|
// Compute the size of the tag
|
|
size = 1
|
|
if tag >= 31 {
|
|
// Long-form identifier if the tag is greater than 30
|
|
// http://en.wikipedia.org/wiki/X.690#Identifier_tags_greater_than_30
|
|
size += sizeBase128Int(tag)
|
|
}
|
|
// Compute the size of the length using the definite form
|
|
// http://en.wikipedia.org/wiki/X.690#The_definite_form
|
|
size += 1
|
|
if length >= 128 {
|
|
size += 1
|
|
for length > 255 {
|
|
size++
|
|
length >>= 8
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func writeTagAndLength(bytes *Bytes, t TagAndLength) (size int) {
|
|
// We are writing backward, so write the length bytes first
|
|
if t.Length < 0 {
|
|
panic("Can't have a negative length")
|
|
|
|
} else if t.Length >= 128 {
|
|
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
|
|
|
|
} else if t.Length < 128 {
|
|
size += bytes.writeBytes([]byte{byte(t.Length)})
|
|
}
|
|
// Then write the tag
|
|
b := uint8(t.Class) << 6
|
|
if t.IsCompound {
|
|
b |= 0x20
|
|
}
|
|
if t.Tag >= 31 {
|
|
b |= 0x1f
|
|
size += writeBase128Int(bytes, t.Tag)
|
|
} else {
|
|
b |= uint8(t.Tag)
|
|
}
|
|
size += bytes.writeBytes([]byte{byte(b)})
|
|
return
|
|
}
|
|
|
|
//
|
|
// END encoding/asn1/asn1.go
|
|
//
|