fixes gpg verification

This commit is contained in:
Sebastian Sdorra
2020-07-30 11:58:11 +02:00
parent a1153df50a
commit 274ce561fe
15 changed files with 108 additions and 187 deletions

View File

@@ -24,29 +24,27 @@
package sonia.scm.security.gpg;
import org.bouncycastle.bcpg.ArmoredInputStream;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPObjectFactory;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureList;
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.security.PublicKey;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.Set;
import static sonia.scm.security.gpg.PgpPublicKeyExtractor.getFromRawKey;
public class GpgKey implements PublicKey {
private static final Logger LOG = LoggerFactory.getLogger(GpgKey.class);
@@ -90,35 +88,59 @@ public class GpgKey implements PublicKey {
public boolean verify(InputStream stream, byte[] signature) {
boolean verified = false;
try {
ArmoredInputStream armoredInputStream = new ArmoredInputStream(new ByteArrayInputStream(signature));
PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(armoredInputStream, null);
PGPSignature pgpSignature = ((PGPSignatureList) pgpObjectFactory.nextObject()).get(0);
PGPContentVerifierBuilderProvider provider = new JcaPGPContentVerifierBuilderProvider();
Optional<PGPPublicKey> pgpPublicKey = getFromRawKey(raw);
if (pgpPublicKey.isPresent()) {
pgpSignature.init(provider, pgpPublicKey.get());
char[] buffer = new char[1024];
int bytesRead = 0;
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
while (bytesRead != -1) {
bytesRead = in.read(buffer, 0, 1024);
pgpSignature.update(new String(buffer).getBytes(StandardCharsets.UTF_8));
}
verified = pgpSignature.verify();
}
verified = verify(stream, asDecodedStream(signature));
} catch (IOException | PGPException e) {
LOG.error("Could not verify GPG key", e);
}
return verified;
}
private boolean verify(InputStream stream, InputStream signature) throws IOException, PGPException {
PGPObjectFactory pgpObjectFactory = new JcaPGPObjectFactory(signature);
Object o = pgpObjectFactory.nextObject();
if (o instanceof PGPSignatureList) {
return verify(stream, ((PGPSignatureList) o).get(0));
} else if (o instanceof PGPCompressedData) {
return verify(stream, ((PGPCompressedData) o).getDataStream());
} else {
LOG.warn("could not find valid signature, only found {}", o);
return false;
}
}
private boolean verify(InputStream stream, PGPSignature signature) throws IOException, PGPException {
PGPPublicKey publicKey = findKey(signature);
if (publicKey != null) {
JcaPGPContentVerifierBuilderProvider provider = new JcaPGPContentVerifierBuilderProvider();
signature.init(provider, publicKey);
int bytesRead;
byte[] buffer = new byte[1024];
while ((bytesRead = stream.read(buffer, 0, buffer.length)) != -1) {
signature.update(buffer, 0, bytesRead);
}
return signature.verify();
} else {
LOG.warn("failed to parse public gpg key");
}
return false;
}
private PGPPublicKey findKey(PGPSignature signature) throws IOException {
PGPObjectFactory pgpObjectFactory = new JcaPGPObjectFactory(asDecodedStream(raw));
PGPPublicKeyRing keyRing = (PGPPublicKeyRing) pgpObjectFactory.nextObject();
return keyRing.getPublicKey(signature.getKeyID());
}
private InputStream asDecodedStream(String content) throws IOException {
return asDecodedStream(content.getBytes(StandardCharsets.US_ASCII));
}
private InputStream asDecodedStream(byte[] bytes) throws IOException {
return PGPUtil.getDecoderStream(new ByteArrayInputStream(bytes));
}
}

View File

@@ -49,8 +49,6 @@ import static sonia.scm.security.gpg.PgpPublicKeyExtractor.getFromRawKey;
@Singleton
public class PublicKeyStore {
private static final Logger LOG = LoggerFactory.getLogger(PublicKeyStore.class);
private static final String STORE_NAME = "gpg_public_keys";
private static final String SUBKEY_STORE_NAME = "gpg_public_sub_keys";