CAdES / PKCS#7 parallel signatures indefinite-length vs definite-length encoding lazy reader

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

CAdES / PKCS#7 parallel signatures indefinite-length vs definite-length encoding lazy reader

Giacomo Boccardo
Hi,
    in order to add a parallel signature to a CAdES (PKCS#7 obviously)
signed document I need to read something from the previous signature
like the digest algorithm used and the signed data version to build the
new structure. To avoid reading all the bytes to get only what I need, I
wrote the following SignedDataParser lazy reader

static SignedDataParser getSignedDataParser(final BufferedInputStream
bIS) throws IOException {
    final int buffSize = 8_192;
    bIS.mark(buffSize);
    final byte[] readBytes = StreamUtils.read(bIS, buffSize);
    bIS.reset();

    final InputStream in = new ASN1InputStream(new
ByteArrayInputStream(readBytes), readBytes.length, true);
    final ASN1StreamParser asn1IS = new ASN1StreamParser(in);
    final ASN1SequenceParser contentInfoAsn1 = (ASN1SequenceParser)
asn1IS.readObject();
    final ContentInfoParser contentInfo = new
ContentInfoParser(contentInfoAsn1);
    return
SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE));
}

and I use it like

final BufferedInputStream bIS = new BufferedInputStream(signedDocument,
4097);
final SignedDataParser signedData = getSignedDataParser(bIS);
final ASN1SetParser digAlgs = signedData.getDigestAlgorithms();
ASN1Integer signedDataVersion = signedData.getVersion();

This code works properly when the ASN.1 uses an indefinite-length
encoding, while if the encoding is definite it fails at

final ASN1SequenceParser contentInfoAsn1 = (ASN1SequenceParser)
asn1IS.readObject();

with the exception

java.io.IOException: corrupted stream - out of bounds length found

    at org.bouncycastle.asn1.ASN1InputStream.readLength(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readObject(Unknown Source)
    at [...].getSignedDataParser

Obviously, increasing the "buffSize" is a workaround, but it cannot be a
general solution and it would make the lazy reader useless.

What I don't clearly understand is whether there's any specification
which states that using the indefinite-length encoding is mandatory for
CAdES signatures.
If the definite-length encoding is allowed, is there any way to modify
that code?

Thanks in advance,
  Giacomo


Reply | Threaded
Open this post in threaded view
|

Re: CAdES / PKCS#7 parallel signatures indefinite-length vs definite-length encoding lazy reader

Peter Dettman-3
Hi Giacomo,
The error happens because you are truncating the stream before giving it
to the parser. The parser then sees a "definite length" longer than the
actual input and complains.

The truncation should be unnecessary anyway since the streaming parsers
will only read ahead lazily. Just parse the original document directly.

Regards,
Pete Dettman

On 10/6/20 7:03 am, Giacomo Boccardo wrote:

> Hi,
>     in order to add a parallel signature to a CAdES (PKCS#7 obviously)
> signed document I need to read something from the previous signature
> like the digest algorithm used and the signed data version to build the
> new structure. To avoid reading all the bytes to get only what I need, I
> wrote the following SignedDataParser lazy reader
>
> static SignedDataParser getSignedDataParser(final BufferedInputStream
> bIS) throws IOException {
>     final int buffSize = 8_192;
>     bIS.mark(buffSize);
>     final byte[] readBytes = StreamUtils.read(bIS, buffSize);
>     bIS.reset();
>
>     final InputStream in = new ASN1InputStream(new
> ByteArrayInputStream(readBytes), readBytes.length, true);
>     final ASN1StreamParser asn1IS = new ASN1StreamParser(in);
>     final ASN1SequenceParser contentInfoAsn1 = (ASN1SequenceParser)
> asn1IS.readObject();
>     final ContentInfoParser contentInfo = new
> ContentInfoParser(contentInfoAsn1);
>     return
> SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE));
> }
>
> and I use it like
>
> final BufferedInputStream bIS = new BufferedInputStream(signedDocument,
> 4097);
> final SignedDataParser signedData = getSignedDataParser(bIS);
> final ASN1SetParser digAlgs = signedData.getDigestAlgorithms();
> ASN1Integer signedDataVersion = signedData.getVersion();
>
> This code works properly when the ASN.1 uses an indefinite-length
> encoding, while if the encoding is definite it fails at
>
> final ASN1SequenceParser contentInfoAsn1 = (ASN1SequenceParser)
> asn1IS.readObject();
>
> with the exception
>
> java.io.IOException: corrupted stream - out of bounds length found
>
>     at org.bouncycastle.asn1.ASN1InputStream.readLength(Unknown Source)
>     at org.bouncycastle.asn1.ASN1StreamParser.readObject(Unknown Source)
>     at [...].getSignedDataParser
>
> Obviously, increasing the "buffSize" is a workaround, but it cannot be a
> general solution and it would make the lazy reader useless.
>
> What I don't clearly understand is whether there's any specification
> which states that using the indefinite-length encoding is mandatory for
> CAdES signatures.
> If the definite-length encoding is allowed, is there any way to modify
> that code?
>
> Thanks in advance,
>   Giacomo
>
>


Reply | Threaded
Open this post in threaded view
|

Re: CAdES / PKCS#7 parallel signatures indefinite-length vs definite-length encoding lazy reader

Giacomo Boccardo
Hi Peter,

    I just figured out that I can obtain the same information from
CMSSignedDataParser without pre-parsing the stream using a
SignedDataParser! I probably wrote the code that way when I was using an
older version of BouncyCastle.

Does anyone know if it is mandatory to use the indefinite-length
encoding for valid CAdES signatures or the definite-length one is
absolutely acceptable?

Thanks,
    Giacomo

Peter Dettman wrote on 10/06/2020 07:08:

> Hi Giacomo,
> The error happens because you are truncating the stream before giving it
> to the parser. The parser then sees a "definite length" longer than the
> actual input and complains.
>
> The truncation should be unnecessary anyway since the streaming parsers
> will only read ahead lazily. Just parse the original document directly.
>
> Regards,
> Pete Dettman
>
> On 10/6/20 7:03 am, Giacomo Boccardo wrote:
>> Hi,
>>     in order to add a parallel signature to a CAdES (PKCS#7 obviously)
>> signed document I need to read something from the previous signature
>> like the digest algorithm used and the signed data version to build the
>> new structure. To avoid reading all the bytes to get only what I need, I
>> wrote the following SignedDataParser lazy reader
>>
>> static SignedDataParser getSignedDataParser(final BufferedInputStream
>> bIS) throws IOException {
>>     final int buffSize = 8_192;
>>     bIS.mark(buffSize);
>>     final byte[] readBytes = StreamUtils.read(bIS, buffSize);
>>     bIS.reset();
>>
>>     final InputStream in = new ASN1InputStream(new
>> ByteArrayInputStream(readBytes), readBytes.length, true);
>>     final ASN1StreamParser asn1IS = new ASN1StreamParser(in);
>>     final ASN1SequenceParser contentInfoAsn1 = (ASN1SequenceParser)
>> asn1IS.readObject();
>>     final ContentInfoParser contentInfo = new
>> ContentInfoParser(contentInfoAsn1);
>>     return
>> SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE));
>> }
>>
>> and I use it like
>>
>> final BufferedInputStream bIS = new BufferedInputStream(signedDocument,
>> 4097);
>> final SignedDataParser signedData = getSignedDataParser(bIS);
>> final ASN1SetParser digAlgs = signedData.getDigestAlgorithms();
>> ASN1Integer signedDataVersion = signedData.getVersion();
>>
>> This code works properly when the ASN.1 uses an indefinite-length
>> encoding, while if the encoding is definite it fails at
>>
>> final ASN1SequenceParser contentInfoAsn1 = (ASN1SequenceParser)
>> asn1IS.readObject();
>>
>> with the exception
>>
>> java.io.IOException: corrupted stream - out of bounds length found
>>
>>     at org.bouncycastle.asn1.ASN1InputStream.readLength(Unknown Source)
>>     at org.bouncycastle.asn1.ASN1StreamParser.readObject(Unknown Source)
>>     at [...].getSignedDataParser
>>
>> Obviously, increasing the "buffSize" is a workaround, but it cannot be a
>> general solution and it would make the lazy reader useless.
>>
>> What I don't clearly understand is whether there's any specification
>> which states that using the indefinite-length encoding is mandatory for
>> CAdES signatures.
>> If the definite-length encoding is allowed, is there any way to modify
>> that code?
>>
>> Thanks in advance,
>>   Giacomo
>>
>>
>