beanit / asn1bean

ASN1bean (formerly known as jASN1) is a Java ASN.1 BER and DER encoding/decoding library
https://www.beanit.com/asn1/
Apache License 2.0
110 stars 45 forks source link

Sanity check on buffer allocation based for definite length sequences #20

Closed kimholan closed 5 years ago

kimholan commented 5 years ago

I am trying out jASN1 to convert non-streaming DER-encoded data to Java classes generated using an ASN.1-schema.

The current API has no features to sanity check the buffer allocation which can lead to memory exhaustion due to eagerly overallocating byte buffers.

Are you interested in modifying the API to specifify an upper limit to sanity check these kinds of length?

Example:


import com.beanit.jasn1.ber.types.BerOctetString;
import org.junit.Assert;
import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;

public class BerOctetStringTest {

    @Test
    public void test() throws IOException {
        BerOctetString reverseMalformed = new BerOctetString();
        try {
            byte[] malformed = {4, -124, 8, 0, 0, 0};
            reverseMalformed.decode(new ByteArrayInputStream(malformed));
            Assert.fail();
        } catch (EOFException cause) {
            // expected
        } finally {
            // buffer was already allocated
            Assert.assertEquals(134217728, reverseMalformed.value.length);
        }
    }
}`
sfeuerhahn commented 5 years ago

sounds like a good idea, but what should be the upper limit allowed? I don't want to limit the allowed use cases for the library.

kimholan commented 5 years ago

The simplest way would be to use a ByteArrayOutputStream, but it might be overdoing for when the byte arrays are small - and a lot of methods in BAOS are synchronized (although current JVMs should be optimize this).

The code gets a bit ugly though when wanting to offer several code paths. For example:

    if (length.val != 0) {
      if (length.val >  65535) {
        ByteArrayOutputStream bufferStream = new ByteArrayOutputStream();
        byte[] buffer= new byte[8192];
        int n;
        while ( (n=is.read(buffer, 0, buffer.length))!=-1 ) {
           bufferStream.write(buffer,0,n);
        }
        value = bufferStream.toByteArray();
      } else {
        Util.readFully(is,value);
      }

      codeLength += length.val;
    }

Maybe you should just ignore this. One can always just fork this and modify it for their own demands. :D

The code generator easy to understand as it is. :smile:

sfeuerhahn commented 5 years ago

I will leave that as it is for now. But keep it in mind for future revisions.