diff options
Diffstat (limited to 'bcpkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibExpanderProvider.java')
-rw-r--r-- | bcpkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibExpanderProvider.java | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibExpanderProvider.java b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibExpanderProvider.java new file mode 100644 index 0000000..15729a7 --- /dev/null +++ b/bcpkix/src/main/java/org/bouncycastle/cms/jcajce/ZlibExpanderProvider.java @@ -0,0 +1,116 @@ +package org.bouncycastle.cms.jcajce; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.InflaterInputStream; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.operator.InputExpander; +import org.bouncycastle.operator.InputExpanderProvider; +import org.bouncycastle.util.io.StreamOverflowException; + +public class ZlibExpanderProvider + implements InputExpanderProvider +{ + private final long limit; + + /** + * Base constructor. Create an expander which will not limit the size of any objects expanded in the stream. + */ + public ZlibExpanderProvider() + { + this.limit = -1; + } + + /** + * Create a provider which caps the number of expanded bytes that can be produced when the + * compressed stream is parsed. + * + * @param limit max number of bytes allowed in an expanded stream. + */ + public ZlibExpanderProvider(long limit) + { + this.limit = limit; + } + + public InputExpander get(final AlgorithmIdentifier algorithm) + { + return new InputExpander() + { + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithm; + } + + public InputStream getInputStream(InputStream comIn) + { + InputStream s = new InflaterInputStream(comIn); + if (limit >= 0) + { + s = new LimitedInputStream(s, limit); + } + return s; + } + }; + } + + private static class LimitedInputStream + extends FilterInputStream + { + private long remaining; + + public LimitedInputStream(InputStream input, long limit) + { + super(input); + + this.remaining = limit; + } + + public int read() + throws IOException + { + // Only a single 'extra' byte will ever be read + if (remaining >= 0) + { + int b = super.in.read(); + if (b < 0 || --remaining >= 0) + { + return b; + } + } + + throw new StreamOverflowException("expanded byte limit exceeded"); + } + + public int read(byte[] buf, int off, int len) + throws IOException + { + if (len < 1) + { + // This will give correct exceptions/returns for strange lengths + return super.read(buf, off, len); + } + + if (remaining < 1) + { + // Will either return EOF or throw exception + read(); + return -1; + } + + /* + * Limit the underlying request to 'remaining' bytes. This ensures the + * caller will see the full 'limit' bytes before getting an exception. + * Also, only one extra byte will ever be read. + */ + int actualLen = (remaining > len ? len : (int)remaining); + int numRead = super.in.read(buf, off, actualLen); + if (numRead > 0) + { + remaining -= numRead; + } + return numRead; + } + } +} |