...

Source file src/github.com/digitorus/pkcs7/ber.go

Documentation: github.com/digitorus/pkcs7

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

View as plain text