diff options
Diffstat (limited to 'libraries/spongycastle/pg/src/main/java/org/spongycastle/bcpg/SignatureSubpacketInputStream.java')
-rw-r--r-- | libraries/spongycastle/pg/src/main/java/org/spongycastle/bcpg/SignatureSubpacketInputStream.java | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/libraries/spongycastle/pg/src/main/java/org/spongycastle/bcpg/SignatureSubpacketInputStream.java b/libraries/spongycastle/pg/src/main/java/org/spongycastle/bcpg/SignatureSubpacketInputStream.java new file mode 100644 index 000000000..678062a58 --- /dev/null +++ b/libraries/spongycastle/pg/src/main/java/org/spongycastle/bcpg/SignatureSubpacketInputStream.java @@ -0,0 +1,159 @@ +package org.spongycastle.bcpg; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import org.spongycastle.bcpg.sig.Exportable; +import org.spongycastle.bcpg.sig.IssuerKeyID; +import org.spongycastle.bcpg.sig.KeyExpirationTime; +import org.spongycastle.bcpg.sig.KeyFlags; +import org.spongycastle.bcpg.sig.NotationData; +import org.spongycastle.bcpg.sig.PreferredAlgorithms; +import org.spongycastle.bcpg.sig.PrimaryUserID; +import org.spongycastle.bcpg.sig.Revocable; +import org.spongycastle.bcpg.sig.SignatureCreationTime; +import org.spongycastle.bcpg.sig.SignatureExpirationTime; +import org.spongycastle.bcpg.sig.SignerUserID; +import org.spongycastle.bcpg.sig.TrustSignature; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.io.Streams; + +/** + * reader for signature sub-packets + */ +public class SignatureSubpacketInputStream + extends InputStream implements SignatureSubpacketTags +{ + InputStream in; + + public SignatureSubpacketInputStream( + InputStream in) + { + this.in = in; + } + + public int available() + throws IOException + { + return in.available(); + } + + public int read() + throws IOException + { + return in.read(); + } + + public SignatureSubpacket readPacket() + throws IOException + { + int l = this.read(); + int bodyLen = 0; + + if (l < 0) + { + return null; + } + + if (l < 192) + { + bodyLen = l; + } + else if (l <= 223) + { + bodyLen = ((l - 192) << 8) + (in.read()) + 192; + } + else if (l == 255) + { + bodyLen = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read(); + } + else + { + // TODO Error? + } + + int tag = in.read(); + + if (tag < 0) + { + throw new EOFException("unexpected EOF reading signature sub packet"); + } + + byte[] data = new byte[bodyLen - 1]; + + // + // this may seem a bit strange but it turns out some applications miscode the length + // in fixed length fields, so we check the length we do get, only throwing an exception if + // we really cannot continue + // + int bytesRead = Streams.readFully(in, data); + + boolean isCritical = ((tag & 0x80) != 0); + int type = tag & 0x7f; + + if (bytesRead != data.length) + { + switch (type) + { + case CREATION_TIME: + data = checkData(data, 4, bytesRead, "Signature Creation Time"); + break; + case ISSUER_KEY_ID: + data = checkData(data, 8, bytesRead, "Issuer"); + break; + case KEY_EXPIRE_TIME: + data = checkData(data, 4, bytesRead, "Signature Key Expiration Time"); + break; + case EXPIRE_TIME: + data = checkData(data, 4, bytesRead, "Signature Expiration Time"); + break; + default: + throw new EOFException("truncated subpacket data."); + } + } + + switch (type) + { + case CREATION_TIME: + return new SignatureCreationTime(isCritical, data); + case KEY_EXPIRE_TIME: + return new KeyExpirationTime(isCritical, data); + case EXPIRE_TIME: + return new SignatureExpirationTime(isCritical, data); + case REVOCABLE: + return new Revocable(isCritical, data); + case EXPORTABLE: + return new Exportable(isCritical, data); + case ISSUER_KEY_ID: + return new IssuerKeyID(isCritical, data); + case TRUST_SIG: + return new TrustSignature(isCritical, data); + case PREFERRED_COMP_ALGS: + case PREFERRED_HASH_ALGS: + case PREFERRED_SYM_ALGS: + return new PreferredAlgorithms(type, isCritical, data); + case KEY_FLAGS: + return new KeyFlags(isCritical, data); + case PRIMARY_USER_ID: + return new PrimaryUserID(isCritical, data); + case SIGNER_USER_ID: + return new SignerUserID(isCritical, data); + case NOTATION_DATA: + return new NotationData(isCritical, data); + } + + return new SignatureSubpacket(type, isCritical, data); + } + + private byte[] checkData(byte[] data, int expected, int bytesRead, String name) + throws EOFException + { + if (bytesRead != expected) + { + throw new EOFException("truncated " + name + " subpacket data."); + } + + return Arrays.copyOfRange(data, 0, expected); + } +} |