github.com/emmansun/gmsm@v0.29.1/pkcs7/ber.go (about)

     1  package pkcs7
     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  	berLen := len(ber)
   137  	if offset >= berLen {
   138  		return nil, 0, errors.New("ber2der: offset is after end of ber data")
   139  	}
   140  	tagStart := offset
   141  	b := ber[offset]
   142  	offset++
   143  	if offset >= berLen {
   144  		return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
   145  	}
   146  	tag := b & 0x1F // last 5 bits
   147  	if tag == 0x1F {
   148  		tag = 0
   149  		for ber[offset] >= 0x80 {
   150  			tag = tag<<7 + ber[offset] - 0x80
   151  			offset++
   152  			if offset > berLen {
   153  				return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
   154  			}
   155  		}
   156  		// jvehent 20170227: this doesn't appear to be used anywhere...
   157  		//tag = tag*128 + ber[offset] - 0x80
   158  		offset++
   159  		if offset > berLen {
   160  			return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
   161  		}
   162  	}
   163  	tagEnd := offset
   164  
   165  	kind := b & 0x20
   166  	if kind == 0 {
   167  		debugprint("--> Primitive\n")
   168  	} else {
   169  		debugprint("--> Constructed\n")
   170  	}
   171  	// read length
   172  	var length int
   173  	l := ber[offset]
   174  	offset++
   175  	if offset > berLen {
   176  		return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
   177  	}
   178  	indefinite := false
   179  	if l > 0x80 {
   180  		numberOfBytes := (int)(l & 0x7F)
   181  		if numberOfBytes > 4 { // int is only guaranteed to be 32bit
   182  			return nil, 0, errors.New("ber2der: BER tag length too long")
   183  		}
   184  		if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F {
   185  			return nil, 0, errors.New("ber2der: BER tag length is negative")
   186  		}
   187  		if (int)(ber[offset]) == 0x0 {
   188  			return nil, 0, errors.New("ber2der: BER tag length has leading zero")
   189  		}
   190  		debugprint("--> (compute length) indicator byte: %x\n", l)
   191  		debugprint("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes])
   192  		for i := 0; i < numberOfBytes; i++ {
   193  			length = length<<8 + (int)(ber[offset])
   194  			offset++
   195  			if offset > berLen {
   196  				return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
   197  			}
   198  		}
   199  	} else if l == 0x80 {
   200  		indefinite = true
   201  	} else {
   202  		length = (int)(l)
   203  	}
   204  	if length < 0 {
   205  		return nil, 0, errors.New("ber2der: invalid negative value found in BER tag length")
   206  	}
   207  	//fmt.Printf("--> length        : %d\n", length)
   208  	contentEnd := offset + length
   209  	if contentEnd > len(ber) {
   210  		return nil, 0, errors.New("ber2der: BER tag length is more than available data")
   211  	}
   212  	debugprint("--> content start : %d\n", offset)
   213  	debugprint("--> content end   : %d\n", contentEnd)
   214  	debugprint("--> content       : % X\n", ber[offset:contentEnd])
   215  	var obj asn1Object
   216  	if indefinite && kind == 0 {
   217  		return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding")
   218  	}
   219  	if kind == 0 {
   220  		obj = asn1Primitive{
   221  			tagBytes: ber[tagStart:tagEnd],
   222  			length:   length,
   223  			content:  ber[offset:contentEnd],
   224  		}
   225  	} else {
   226  		var subObjects []asn1Object
   227  		for (offset < contentEnd) || indefinite {
   228  			var subObj asn1Object
   229  			var err error
   230  			subObj, offset, err = readObject(ber, offset)
   231  			if err != nil {
   232  				return nil, 0, err
   233  			}
   234  			subObjects = append(subObjects, subObj)
   235  
   236  			if indefinite {
   237  				terminated, err := isIndefiniteTermination(ber, offset)
   238  				if err != nil {
   239  					return nil, 0, err
   240  				}
   241  
   242  				if terminated {
   243  					break
   244  				}
   245  			}
   246  		}
   247  		obj = asn1Structured{
   248  			tagBytes: ber[tagStart:tagEnd],
   249  			content:  subObjects,
   250  		}
   251  	}
   252  
   253  	// Apply indefinite form length with 0x0000 terminator.
   254  	if indefinite {
   255  		contentEnd = offset + 2
   256  	}
   257  
   258  	return obj, contentEnd, nil
   259  }
   260  
   261  func isIndefiniteTermination(ber []byte, offset int) (bool, error) {
   262  	if len(ber)-offset < 2 {
   263  		return false, errors.New("ber2der: Invalid BER format")
   264  	}
   265  
   266  	return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil
   267  }
   268  
   269  func debugprint(format string, a ...any) {
   270  	//fmt.Printf(format, a)
   271  }