mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-27 06:42:05 +01:00
Rearrange armored input stream workaround code
This commit is contained in:
parent
1983cfb4ac
commit
944d79b009
4 changed files with 87 additions and 41 deletions
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.pgpainless.key.parsing;
|
package org.pgpainless.key.parsing;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -25,7 +24,6 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import org.bouncycastle.bcpg.ArmoredInputStream;
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPMarker;
|
import org.bouncycastle.openpgp.PGPMarker;
|
||||||
import org.bouncycastle.openpgp.PGPObjectFactory;
|
import org.bouncycastle.openpgp.PGPObjectFactory;
|
||||||
|
@ -33,12 +31,10 @@ import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.PGPUtil;
|
|
||||||
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
|
|
||||||
import org.bouncycastle.util.io.Streams;
|
import org.bouncycastle.util.io.Streams;
|
||||||
import org.pgpainless.implementation.ImplementationFactory;
|
import org.pgpainless.implementation.ImplementationFactory;
|
||||||
import org.pgpainless.key.collection.PGPKeyRingCollection;
|
import org.pgpainless.key.collection.PGPKeyRingCollection;
|
||||||
import org.pgpainless.util.ArmoredInputStreamFactory;
|
import org.pgpainless.util.ArmorUtils;
|
||||||
|
|
||||||
public class KeyRingReader {
|
public class KeyRingReader {
|
||||||
|
|
||||||
|
@ -109,7 +105,7 @@ public class KeyRingReader {
|
||||||
|
|
||||||
public static PGPPublicKeyRing readPublicKeyRing(@Nonnull InputStream inputStream) throws IOException {
|
public static PGPPublicKeyRing readPublicKeyRing(@Nonnull InputStream inputStream) throws IOException {
|
||||||
PGPObjectFactory objectFactory = new PGPObjectFactory(
|
PGPObjectFactory objectFactory = new PGPObjectFactory(
|
||||||
getDecoderStream(inputStream),
|
ArmorUtils.getDecoderStream(inputStream),
|
||||||
ImplementationFactory.getInstance().getKeyFingerprintCalculator());
|
ImplementationFactory.getInstance().getKeyFingerprintCalculator());
|
||||||
Object next;
|
Object next;
|
||||||
do {
|
do {
|
||||||
|
@ -131,7 +127,7 @@ public class KeyRingReader {
|
||||||
public static PGPPublicKeyRingCollection readPublicKeyRingCollection(@Nonnull InputStream inputStream)
|
public static PGPPublicKeyRingCollection readPublicKeyRingCollection(@Nonnull InputStream inputStream)
|
||||||
throws IOException, PGPException {
|
throws IOException, PGPException {
|
||||||
PGPObjectFactory objectFactory = new PGPObjectFactory(
|
PGPObjectFactory objectFactory = new PGPObjectFactory(
|
||||||
getDecoderStream(inputStream),
|
ArmorUtils.getDecoderStream(inputStream),
|
||||||
ImplementationFactory.getInstance().getKeyFingerprintCalculator());
|
ImplementationFactory.getInstance().getKeyFingerprintCalculator());
|
||||||
|
|
||||||
List<PGPPublicKeyRing> rings = new ArrayList<>();
|
List<PGPPublicKeyRing> rings = new ArrayList<>();
|
||||||
|
@ -161,7 +157,7 @@ public class KeyRingReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PGPSecretKeyRing readSecretKeyRing(@Nonnull InputStream inputStream) throws IOException {
|
public static PGPSecretKeyRing readSecretKeyRing(@Nonnull InputStream inputStream) throws IOException {
|
||||||
InputStream decoderStream = getDecoderStream(inputStream);
|
InputStream decoderStream = ArmorUtils.getDecoderStream(inputStream);
|
||||||
PGPObjectFactory objectFactory = new PGPObjectFactory(
|
PGPObjectFactory objectFactory = new PGPObjectFactory(
|
||||||
decoderStream,
|
decoderStream,
|
||||||
ImplementationFactory.getInstance().getKeyFingerprintCalculator());
|
ImplementationFactory.getInstance().getKeyFingerprintCalculator());
|
||||||
|
@ -187,7 +183,7 @@ public class KeyRingReader {
|
||||||
public static PGPSecretKeyRingCollection readSecretKeyRingCollection(@Nonnull InputStream inputStream)
|
public static PGPSecretKeyRingCollection readSecretKeyRingCollection(@Nonnull InputStream inputStream)
|
||||||
throws IOException, PGPException {
|
throws IOException, PGPException {
|
||||||
PGPObjectFactory objectFactory = new PGPObjectFactory(
|
PGPObjectFactory objectFactory = new PGPObjectFactory(
|
||||||
getDecoderStream(inputStream),
|
ArmorUtils.getDecoderStream(inputStream),
|
||||||
ImplementationFactory.getInstance().getKeyFingerprintCalculator());
|
ImplementationFactory.getInstance().getKeyFingerprintCalculator());
|
||||||
|
|
||||||
List<PGPSecretKeyRing> rings = new ArrayList<>();
|
List<PGPSecretKeyRing> rings = new ArrayList<>();
|
||||||
|
@ -220,34 +216,4 @@ public class KeyRingReader {
|
||||||
throws IOException, PGPException {
|
throws IOException, PGPException {
|
||||||
return new PGPKeyRingCollection(inputStream, isSilent);
|
return new PGPKeyRingCollection(inputStream, isSilent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Hacky workaround for #96.
|
|
||||||
* For {@link PGPPublicKeyRingCollection#PGPPublicKeyRingCollection(InputStream, KeyFingerPrintCalculator)}
|
|
||||||
* or {@link PGPSecretKeyRingCollection#PGPSecretKeyRingCollection(InputStream, KeyFingerPrintCalculator)}
|
|
||||||
* to read all PGPKeyRings properly, we apparently have to make sure that the {@link InputStream} that is given
|
|
||||||
* as constructor argument is a {@link PGPUtil.BufferedInputStreamExt}.
|
|
||||||
* Since {@link PGPUtil#getDecoderStream(InputStream)} will return an {@link org.bouncycastle.bcpg.ArmoredInputStream}
|
|
||||||
* if the underlying input stream contains armored data, we have to nest two method calls to make sure that the
|
|
||||||
* end-result is a {@link PGPUtil.BufferedInputStreamExt}.
|
|
||||||
*
|
|
||||||
* This is a hacky solution.
|
|
||||||
*
|
|
||||||
* @param inputStream input stream
|
|
||||||
* @return BufferedInputStreamExt
|
|
||||||
*/
|
|
||||||
private static InputStream getDecoderStream(InputStream inputStream) throws IOException {
|
|
||||||
InputStream decoderStream = PGPUtil.getDecoderStream(inputStream);
|
|
||||||
// Data is not armored -> return
|
|
||||||
if (decoderStream instanceof BufferedInputStream) {
|
|
||||||
return decoderStream;
|
|
||||||
}
|
|
||||||
// Wrap armored input stream with fix for #159
|
|
||||||
if (decoderStream instanceof ArmoredInputStream) {
|
|
||||||
decoderStream = ArmoredInputStreamFactory.get(decoderStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
decoderStream = PGPUtil.getDecoderStream(decoderStream);
|
|
||||||
return decoderStream;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
import org.bouncycastle.openpgp.PGPSignature;
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
||||||
import org.bouncycastle.openpgp.PGPSignatureList;
|
import org.bouncycastle.openpgp.PGPSignatureList;
|
||||||
import org.bouncycastle.openpgp.PGPUtil;
|
|
||||||
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
|
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
import org.pgpainless.PGPainless;
|
import org.pgpainless.PGPainless;
|
||||||
|
@ -48,6 +47,7 @@ import org.pgpainless.key.util.OpenPgpKeyAttributeUtil;
|
||||||
import org.pgpainless.key.util.RevocationAttributes;
|
import org.pgpainless.key.util.RevocationAttributes;
|
||||||
import org.pgpainless.policy.Policy;
|
import org.pgpainless.policy.Policy;
|
||||||
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
|
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
|
||||||
|
import org.pgpainless.util.ArmorUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods related to signatures.
|
* Utility methods related to signatures.
|
||||||
|
@ -196,7 +196,7 @@ public class SignatureUtils {
|
||||||
|
|
||||||
public static List<PGPSignature> readSignatures(InputStream inputStream) throws IOException, PGPException {
|
public static List<PGPSignature> readSignatures(InputStream inputStream) throws IOException, PGPException {
|
||||||
List<PGPSignature> signatures = new ArrayList<>();
|
List<PGPSignature> signatures = new ArrayList<>();
|
||||||
InputStream pgpIn = PGPUtil.getDecoderStream(inputStream);
|
InputStream pgpIn = ArmorUtils.getDecoderStream(inputStream);
|
||||||
PGPObjectFactory objectFactory = new PGPObjectFactory(
|
PGPObjectFactory objectFactory = new PGPObjectFactory(
|
||||||
pgpIn, ImplementationFactory.getInstance().getKeyFingerprintCalculator());
|
pgpIn, ImplementationFactory.getInstance().getKeyFingerprintCalculator());
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package org.pgpainless.util;
|
package org.pgpainless.util;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -32,6 +33,8 @@ import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
|
import org.bouncycastle.openpgp.PGPUtil;
|
||||||
|
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
|
||||||
import org.bouncycastle.util.io.Streams;
|
import org.bouncycastle.util.io.Streams;
|
||||||
import org.pgpainless.algorithm.HashAlgorithm;
|
import org.pgpainless.algorithm.HashAlgorithm;
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||||
|
@ -204,4 +207,32 @@ public class ArmorUtils {
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hacky workaround for #96.
|
||||||
|
* For {@link PGPPublicKeyRingCollection#PGPPublicKeyRingCollection(InputStream, KeyFingerPrintCalculator)}
|
||||||
|
* or {@link PGPSecretKeyRingCollection#PGPSecretKeyRingCollection(InputStream, KeyFingerPrintCalculator)}
|
||||||
|
* to read all PGPKeyRings properly, we apparently have to make sure that the {@link InputStream} that is given
|
||||||
|
* as constructor argument is a {@link PGPUtil.BufferedInputStreamExt}.
|
||||||
|
* Since {@link PGPUtil#getDecoderStream(InputStream)} will return an {@link org.bouncycastle.bcpg.ArmoredInputStream}
|
||||||
|
* if the underlying input stream contains armored data, we have to nest two method calls to make sure that the
|
||||||
|
* end-result is a {@link PGPUtil.BufferedInputStreamExt}.
|
||||||
|
*
|
||||||
|
* This is a hacky solution.
|
||||||
|
*
|
||||||
|
* @param inputStream input stream
|
||||||
|
* @return BufferedInputStreamExt
|
||||||
|
*/
|
||||||
|
public static InputStream getDecoderStream(InputStream inputStream) throws IOException {
|
||||||
|
InputStream decoderStream = PGPUtil.getDecoderStream(inputStream);
|
||||||
|
// Data is not armored -> return
|
||||||
|
if (decoderStream instanceof BufferedInputStream) {
|
||||||
|
return decoderStream;
|
||||||
|
}
|
||||||
|
// Wrap armored input stream with fix for #159
|
||||||
|
decoderStream = CRCingArmoredInputStreamWrapper.possiblyWrap(decoderStream);
|
||||||
|
|
||||||
|
decoderStream = PGPUtil.getDecoderStream(decoderStream);
|
||||||
|
return decoderStream;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Paul Schaub.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pgpainless.signature;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class MissingCRCChecksumInSignatureArmorIsOkay {
|
||||||
|
|
||||||
|
public static final String ARMORED_SIGNATURE_WITH_MISSING_CRC_SUM = "-----BEGIN PGP SIGNATURE-----\n" +
|
||||||
|
"\n" +
|
||||||
|
"wsE7BAABCgBvBYJgyf3FCRD7/MgqAV5zMEcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" +
|
||||||
|
"cy5zZXF1b2lhLXBncC5vcmdbH+E3jkMYSiFZOF5cHIUCy8UjqEvHbrCCxxhnEu1J\n" +
|
||||||
|
"ThYhBNGmbhojsYLJmA94jPv8yCoBXnMwAACzOAv/QAmXX9mPJ4Xtk1SNKPH11izO\n" +
|
||||||
|
"G8OK+dKL46O7AQGJFjdwiA8SdyFatVzUUNHcyi0HJ2iNes5DPObxDweqy9MijHkx\n" +
|
||||||
|
"U4RotWUwdhGoTWqAj3cipDXJZi4MD46qi8AkmmT1xGk3GuPH/ymgbefMIZymczKw\n" +
|
||||||
|
"1YjDoq0AFVCeBWekCsVjZsUYBamgG0WNKEKXk3bNHObaUAqpJZFKvZKslZByyuOm\n" +
|
||||||
|
"nq5BlscmalWTxhDPNZDPigFeoa+MI72ckquD9cJG3P4WHaWos0EfkWDwIRhB4888\n" +
|
||||||
|
"5jB4moQr6dDfELbtEqcBj9CecrXmPqv18qmoIgR9tAeeJsyqIC5TS9j6iDoYJ9bJ\n" +
|
||||||
|
"4H4OcfJtTtXMSMPppH/hEOS88R/F2m0Szc4leyHtXSZXZ2I8RJLG4u+2RZlh+vBh\n" +
|
||||||
|
"sakyriei09Kz3Gdk6deDCO0uCrYQA7GQ9xFMzrfay1B0Lr7pAe8BTg6xuauwfGZh\n" +
|
||||||
|
"wDz6hyIxJ3IhAln5GX7NGsXu3eoEjMfZZ29rY7BC\n" +
|
||||||
|
"-----END PGP SIGNATURE-----";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void assertMissingCRCSumInSignatureArmorIsOkay() throws PGPException, IOException {
|
||||||
|
List<PGPSignature> signatureList = SignatureUtils.readSignatures(ARMORED_SIGNATURE_WITH_MISSING_CRC_SUM);
|
||||||
|
assertEquals(1, signatureList.size());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue