github.com/Hyperledger-TWGC/tjfoc-gm@v1.4.0/x509/ber.go (about)

     1  package x509
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  )
     7  
     8  var encodeIndent = 0
     9  
    10  type asn1Object interface {
    11  	EncodeTo(writer *bytes.Buffer) error
    12  }
    13  
    14  type asn1Structured struct {
    15  	tagBytes []byte
    16  	content  []asn1Object
    17  }
    18  
    19  func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
    20  	//fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes)
    21  	encodeIndent++
    22  	inner := new(bytes.Buffer)
    23  	for _, obj := range s.content {
    24  		err := obj.EncodeTo(inner)
    25  		if err != nil {
    26  			return err
    27  		}
    28  	}
    29  	encodeIndent--
    30  	out.Write(s.tagBytes)
    31  	encodeLength(out, inner.Len())
    32  	out.Write(inner.Bytes())
    33  	return nil
    34  }
    35  
    36  type asn1Primitive struct {
    37  	tagBytes []byte
    38  	length   int
    39  	content  []byte
    40  }
    41  
    42  func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error {
    43  	_, err := out.Write(p.tagBytes)
    44  	if err != nil {
    45  		return err
    46  	}
    47  	if err = encodeLength(out, p.length); err != nil {
    48  		return err
    49  	}
    50  	//fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length)
    51  	//fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content))
    52  	out.Write(p.content)
    53  
    54  	return nil
    55  }
    56  
    57  func ber2der(ber []byte) ([]byte, error) {
    58  	if len(ber) == 0 {
    59  		return nil, errors.New("ber2der: input ber is empty")
    60  	}
    61  	//fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber))
    62  	out := new(bytes.Buffer)
    63  
    64  	obj, _, err := readObject(ber, 0)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	obj.EncodeTo(out)
    69  
    70  	// if offset < len(ber) {
    71  	//	return nil, fmt.Errorf("ber2der: Content longer than expected. Got %d, expected %d", offset, len(ber))
    72  	//}
    73  
    74  	return out.Bytes(), nil
    75  }
    76  
    77  // encodes lengths that are longer than 127 into string of bytes
    78  func marshalLongLength(out *bytes.Buffer, i int) (err error) {
    79  	n := lengthLength(i)
    80  
    81  	for ; n > 0; n-- {
    82  		err = out.WriteByte(byte(i >> uint((n-1)*8)))
    83  		if err != nil {
    84  			return
    85  		}
    86  	}
    87  
    88  	return nil
    89  }
    90  
    91  // computes the byte length of an encoded length value
    92  func lengthLength(i int) (numBytes int) {
    93  	numBytes = 1
    94  	for i > 255 {
    95  		numBytes++
    96  		i >>= 8
    97  	}
    98  	return
    99  }
   100  
   101  // encodes the length in DER format
   102  // If the length fits in 7 bits, the value is encoded directly.
   103  //
   104  // Otherwise, the number of bytes to encode the length is first determined.
   105  // This number is likely to be 4 or less for a 32bit length. This number is
   106  // added to 0x80. The length is encoded in big endian encoding follow after
   107  //
   108  // Examples:
   109  //  length | byte 1 | bytes n
   110  //  0      | 0x00   | -
   111  //  120    | 0x78   | -
   112  //  200    | 0x81   | 0xC8
   113  //  500    | 0x82   | 0x01 0xF4
   114  //
   115  func encodeLength(out *bytes.Buffer, length int) (err error) {
   116  	if length >= 128 {
   117  		l := lengthLength(length)
   118  		err = out.WriteByte(0x80 | byte(l))
   119  		if err != nil {
   120  			return
   121  		}
   122  		err = marshalLongLength(out, length)
   123  		if err != nil {
   124  			return
   125  		}
   126  	} else {
   127  		err = out.WriteByte(byte(length))
   128  		if err != nil {
   129  			return
   130  		}
   131  	}
   132  	return
   133  }
   134  
   135  func readObject(ber []byte, offset int) (asn1Object, int, error) {
   136  	//fmt.Printf("\n====> Starting readObject at offset: %d\n\n", offset)
   137  	tagStart := offset
   138  	b := ber[offset]
   139  	offset++
   140  	tag := b & 0x1F // last 5 bits
   141  	if tag == 0x1F {
   142  		tag = 0
   143  		for ber[offset] >= 0x80 {
   144  			tag = tag*128 + ber[offset] - 0x80
   145  			offset++
   146  		}
   147  		tag = tag*128 + ber[offset] - 0x80
   148  		offset++
   149  	}
   150  	tagEnd := offset
   151  
   152  	kind := b & 0x20
   153  	/*
   154  		if kind == 0 {
   155  			fmt.Print("--> Primitive\n")
   156  		} else {
   157  			fmt.Print("--> Constructed\n")
   158  		}
   159  	*/
   160  	// read length
   161  	var length int
   162  	l := ber[offset]
   163  	offset++
   164  	indefinite := false
   165  	if l > 0x80 {
   166  		numberOfBytes := (int)(l & 0x7F)
   167  		if numberOfBytes > 4 { // int is only guaranteed to be 32bit
   168  			return nil, 0, errors.New("ber2der: BER tag length too long")
   169  		}
   170  		if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F {
   171  			return nil, 0, errors.New("ber2der: BER tag length is negative")
   172  		}
   173  		if 0x0 == (int)(ber[offset]) {
   174  			return nil, 0, errors.New("ber2der: BER tag length has leading zero")
   175  		}
   176  		//fmt.Printf("--> (compute length) indicator byte: %x\n", l)
   177  		//fmt.Printf("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes])
   178  		for i := 0; i < numberOfBytes; i++ {
   179  			length = length*256 + (int)(ber[offset])
   180  			offset++
   181  		}
   182  	} else if l == 0x80 {
   183  		indefinite = true
   184  	} else {
   185  		length = (int)(l)
   186  	}
   187  
   188  	//fmt.Printf("--> length        : %d\n", length)
   189  	contentEnd := offset + length
   190  	if contentEnd > len(ber) {
   191  		return nil, 0, errors.New("ber2der: BER tag length is more than available data")
   192  	}
   193  	//fmt.Printf("--> content start : %d\n", offset)
   194  	//fmt.Printf("--> content end   : %d\n", contentEnd)
   195  	//fmt.Printf("--> content       : % X\n", ber[offset:contentEnd])
   196  	var obj asn1Object
   197  	if indefinite && kind == 0 {
   198  		return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding")
   199  	}
   200  	if kind == 0 {
   201  		obj = asn1Primitive{
   202  			tagBytes: ber[tagStart:tagEnd],
   203  			length:   length,
   204  			content:  ber[offset:contentEnd],
   205  		}
   206  	} else {
   207  		var subObjects []asn1Object
   208  		for (offset < contentEnd) || indefinite {
   209  			var subObj asn1Object
   210  			var err error
   211  			subObj, offset, err = readObject(ber, offset)
   212  			if err != nil {
   213  				return nil, 0, err
   214  			}
   215  			subObjects = append(subObjects, subObj)
   216  
   217  			if indefinite {
   218  				terminated, err := isIndefiniteTermination(ber, offset)
   219  				if err != nil {
   220  					return nil, 0, err
   221  				}
   222  
   223  				if terminated {
   224  					break
   225  				}
   226  			}
   227  		}
   228  		obj = asn1Structured{
   229  			tagBytes: ber[tagStart:tagEnd],
   230  			content:  subObjects,
   231  		}
   232  	}
   233  
   234  	// Apply indefinite form length with 0x0000 terminator.
   235  	if indefinite {
   236  		contentEnd = offset + 2
   237  	}
   238  
   239  	return obj, contentEnd, nil
   240  }
   241  
   242  func isIndefiniteTermination(ber []byte, offset int) (bool, error) {
   243  	if len(ber)-offset < 2 {
   244  		return false, errors.New("ber2der: Invalid BER format")
   245  	}
   246  
   247  	return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil
   248  }