From 1fbc14b768f923dce52a880b119870d4199dff08 Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Tue, 30 May 2023 01:34:25 +0200
Subject: [PATCH 01/18] Replace BC dependency with PGPainless (pulls in BC)
---
core/pom.xml | 8 ++------
deb/pom.xml | 2 +-
pom.xml | 14 ++++----------
3 files changed, 7 insertions(+), 17 deletions(-)
diff --git a/core/pom.xml b/core/pom.xml
index 84dbd4a..bf74d2e 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -13,12 +13,8 @@
- org.bouncycastle
- bcprov-jdk18on
-
-
- org.bouncycastle
- bcpg-jdk18on
+ org.pgpainless
+ pgpainless-core
diff --git a/deb/pom.xml b/deb/pom.xml
index 6d13788..3695d3f 100644
--- a/deb/pom.xml
+++ b/deb/pom.xml
@@ -51,4 +51,4 @@
-
\ No newline at end of file
+
diff --git a/pom.xml b/pom.xml
index 8beffc8..2eb4140 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,7 +74,7 @@
8
1.8
- 1.71
+ 1.73
1.21
31.1-jre
5.8.2
@@ -117,16 +117,10 @@
-
-
- org.bouncycastle
- bcprov-jdk18on
- ${bouncycastle.version}
-
- org.bouncycastle
- bcpg-jdk18on
- ${bouncycastle.version}
+ org.pgpainless
+ pgpainless-core
+ 1.5.1
From bb2289fef65fe84e5c29c80434f153961a8d9310 Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Tue, 30 May 2023 01:48:48 +0200
Subject: [PATCH 02/18] Change default signature hash algorithm from SHA1 to
SHA256
---
.../packager/rpm/signature/RsaHeaderSignatureProcessor.java | 2 +-
.../eclipse/packager/rpm/signature/RsaSignatureProcessor.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaHeaderSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaHeaderSignatureProcessor.java
index 7bd2b26..473cca8 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaHeaderSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaHeaderSignatureProcessor.java
@@ -50,7 +50,7 @@ public RsaHeaderSignatureProcessor(final PGPPrivateKey privateKey, final HashAlg
}
public RsaHeaderSignatureProcessor(final PGPPrivateKey privateKey) {
- this(privateKey, HashAlgorithmTags.SHA1);
+ this(privateKey, HashAlgorithmTags.SHA256);
}
@Override
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaSignatureProcessor.java
index 91f4335..123c993 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaSignatureProcessor.java
@@ -53,7 +53,7 @@ public RsaSignatureProcessor(final PGPPrivateKey privateKey, final HashAlgorithm
}
public RsaSignatureProcessor(final PGPPrivateKey privateKey) {
- this(privateKey, HashAlgorithmTags.SHA1);
+ this(privateKey, HashAlgorithmTags.SHA256);
}
@Override
From 4b1827dd6d430f5cc3eae16c8b92200be7a8a5ee Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Tue, 30 May 2023 02:29:31 +0200
Subject: [PATCH 03/18] Base the SigningStream on PGPainless
---
.../packager/security/pgp/SigningStream.java | 111 ++++++++++--------
.../packager/rpm/yum/RepositoryCreator.java | 31 +++--
2 files changed, 81 insertions(+), 61 deletions(-)
diff --git a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
index 8203d97..d3a23b8 100644
--- a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
+++ b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
@@ -13,50 +13,52 @@
package org.eclipse.packager.security.pgp;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Objects;
-
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
-import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.openpgp.PGPException;
-import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
-import org.bouncycastle.openpgp.PGPSignatureGenerator;
-import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
+import org.pgpainless.PGPainless;
+import org.pgpainless.algorithm.DocumentSignatureType;
+import org.pgpainless.encryption_signing.EncryptionResult;
+import org.pgpainless.encryption_signing.EncryptionStream;
+import org.pgpainless.encryption_signing.ProducerOptions;
+import org.pgpainless.encryption_signing.SigningOptions;
+import org.pgpainless.key.protection.SecretKeyRingProtector;
+import org.pgpainless.util.ArmoredOutputStreamFactory;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Objects;
public class SigningStream extends OutputStream {
private final OutputStream stream;
- private final PGPPrivateKey privateKey;
-
- private final boolean inline;
+ private final PGPSecretKeyRing secretKeys;
- private PGPSignatureGenerator signatureGenerator;
+ private final SecretKeyRingProtector protector;
- private ArmoredOutputStream armoredOutput;
+ private final boolean inline;
private boolean initialized;
private final String version;
- private final int digestAlgorithm;
+ private EncryptionStream signingStream;
/**
* Create a new signing stream
*
* @param stream the actual output stream
- * @param privateKey the private key to sign with
- * @param digestAlgorithm the digest algorithm to use, from
- * {@link HashAlgorithmTags}
+ * @param secretKeys the signing key ring
+ * @param protector protector to unlock the signing key
* @param inline whether to sign inline or just write the signature
* @param version the optional version which will be in the signature comment
*/
- public SigningStream(final OutputStream stream, final PGPPrivateKey privateKey, final int digestAlgorithm, final boolean inline, final String version) {
+ public SigningStream(final OutputStream stream, final PGPSecretKeyRing secretKeys, final SecretKeyRingProtector protector, final boolean inline, final String version) {
this.stream = stream;
- this.privateKey = privateKey;
- this.digestAlgorithm = digestAlgorithm;
+ this.secretKeys = secretKeys;
+ this.protector = protector;
this.inline = inline;
this.version = version;
}
@@ -65,13 +67,12 @@ public SigningStream(final OutputStream stream, final PGPPrivateKey privateKey,
* Create a new signing stream
*
* @param stream the actual output stream
- * @param privateKey the private key to sign with
- * @param digestAlgorithm the digest algorithm to use, from
- * {@link HashAlgorithmTags}
+ * @param secretKeys the signing key ring
+ * @param protector protector to unlock the signing key
* @param inline whether to sign inline or just write the signature
*/
- public SigningStream(final OutputStream stream, final PGPPrivateKey privateKey, final int digestAlgorithm, final boolean inline) {
- this(stream, privateKey, digestAlgorithm, inline, null);
+ public SigningStream(final OutputStream stream, final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector, final boolean inline) {
+ this(stream, secretKeys, protector, inline, null);
}
protected void testInit() throws IOException {
@@ -81,17 +82,35 @@ protected void testInit() throws IOException {
this.initialized = true;
- try {
- this.signatureGenerator = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(this.privateKey.getPublicKeyPacket().getAlgorithm(), this.digestAlgorithm));
- this.signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, this.privateKey);
-
- this.armoredOutput = new ArmoredOutputStream(this.stream);
- if (this.version != null) {
- this.armoredOutput.setHeader("Version", this.version);
- }
+ ArmoredOutputStreamFactory.setVersionInfo(version);
- if (this.inline) {
- this.armoredOutput.beginClearText(this.digestAlgorithm);
+ try {
+ if (inline) {
+
+ SigningOptions signingOptions = SigningOptions.get();
+ signingOptions.addInlineSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
+ ProducerOptions producerOptions = ProducerOptions.sign(signingOptions)
+ .setCleartextSigned();
+
+ signingStream = PGPainless.encryptAndOrSign()
+ .onOutputStream(stream) // write data and sig to the output stream
+ .withOptions(producerOptions);
+
+ } else {
+
+ SigningOptions signingOptions = SigningOptions.get();
+ signingOptions.addDetachedSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
+ ProducerOptions producerOptions = ProducerOptions.sign(signingOptions);
+
+ signingStream = PGPainless.encryptAndOrSign()
+ .onOutputStream(
+ // do not output the plaintext data, just emit the signature in close()
+ new OutputStream() {
+ @Override
+ public void write(int i) throws IOException {
+ // Ignore data
+ }
+ }).withOptions(producerOptions);
}
} catch (final PGPException e) {
throw new IOException(e);
@@ -109,28 +128,24 @@ public void write(final byte[] b, final int off, final int len) throws IOExcepti
testInit();
- if (this.inline) {
- this.armoredOutput.write(b, off, len);
- }
- this.signatureGenerator.update(b, off, len);
+ signingStream.write(b, off, len);
}
@Override
public void close() throws IOException {
testInit();
- if (this.inline) {
- this.armoredOutput.endClearText();
- }
+ signingStream.close();
- try {
- final PGPSignature signature = this.signatureGenerator.generate();
- signature.encode(new BCPGOutputStream(this.armoredOutput));
- } catch (final PGPException e) {
- throw new IOException(e);
+ if (this.inline) {
+ return;
}
- this.armoredOutput.close();
+ EncryptionResult result = signingStream.getResult();
+ final PGPSignature signature = result.getDetachedSignatures().values().iterator().next().iterator().next();;
+ ArmoredOutputStream armoredOutput = ArmoredOutputStreamFactory.get(stream);
+ signature.encode(new BCPGOutputStream(armoredOutput));
+ armoredOutput.close();
super.close();
}
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java b/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
index 6bb9600..4fdce91 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
@@ -14,6 +14,7 @@
package org.eclipse.packager.rpm.yum;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.time.Instant;
import java.util.Arrays;
@@ -39,8 +40,7 @@
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-import org.bouncycastle.bcpg.HashAlgorithmTags;
-import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.eclipse.packager.io.IOConsumer;
import org.eclipse.packager.io.OutputSpooler;
import org.eclipse.packager.io.SpoolOutTarget;
@@ -51,6 +51,8 @@
import org.eclipse.packager.rpm.info.RpmInformation.Changelog;
import org.eclipse.packager.rpm.info.RpmInformation.Dependency;
import org.eclipse.packager.security.pgp.SigningStream;
+import org.pgpainless.PGPainless;
+import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -439,23 +441,26 @@ public Builder setSigning(final Function signingStre
return this;
}
- public Builder setSigning(final PGPPrivateKey privateKey) {
- return setSigning(privateKey, HashAlgorithmTags.SHA1);
- }
-
- public Builder setSigning(final PGPPrivateKey privateKey, final HashAlgorithm hashAlgorithm) {
- return setSigning(privateKey, hashAlgorithm.getValue());
- }
-
- public Builder setSigning(final PGPPrivateKey privateKey, final int digestAlgorithm) {
- if (privateKey != null) {
- this.signingStreamCreator = output -> new SigningStream(output, privateKey, digestAlgorithm, false);
+ public Builder setSigning(final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector) {
+ if (secretKeys != null) {
+ return setSigning(output -> new SigningStream(output, secretKeys, protector, false));
} else {
this.signingStreamCreator = null;
}
return this;
}
+ public Builder setSigning(final InputStream keyInputStream)
+ throws IOException {
+ return setSigning(keyInputStream, SecretKeyRingProtector.unprotectedKeys());
+ }
+
+ public Builder setSigning(final InputStream keyInputStream, SecretKeyRingProtector keyProtector)
+ throws IOException {
+ PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(keyInputStream);
+ return setSigning(secretKeys, keyProtector);
+ }
+
public RepositoryCreator build() {
return new RepositoryCreator(this.target, this.xmlContext == null ? new DefaultXmlContext() : this.xmlContext, this.signingStreamCreator);
}
From dce7bfa8a074a37b49c2553bd07b76d109b323e6 Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Tue, 30 May 2023 02:32:02 +0200
Subject: [PATCH 04/18] Add PgpHeaderSignatureProcessor and
PgpSignatureProcessor
---
.../PgpHeaderSignatureProcessor.java | 94 +++++++++++++++++++
.../rpm/signature/PgpSignatureProcessor.java | 82 ++++++++++++++++
2 files changed, 176 insertions(+)
create mode 100644 rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
create mode 100644 rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
new file mode 100644
index 0000000..de594d9
--- /dev/null
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, 2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+
+package org.eclipse.packager.rpm.signature;
+
+import org.bouncycastle.openpgp.PGPSecretKeyRing;
+import org.eclipse.packager.rpm.RpmSignatureTag;
+import org.eclipse.packager.rpm.header.Header;
+import org.pgpainless.PGPainless;
+import org.pgpainless.algorithm.DocumentSignatureType;
+import org.pgpainless.encryption_signing.EncryptionResult;
+import org.pgpainless.encryption_signing.EncryptionStream;
+import org.pgpainless.encryption_signing.ProducerOptions;
+import org.pgpainless.encryption_signing.SigningOptions;
+import org.pgpainless.key.protection.SecretKeyRingProtector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+/**
+ * An RSA signature processor for the header section only.
+ */
+public class PgpHeaderSignatureProcessor implements SignatureProcessor {
+ private final static Logger logger = LoggerFactory.getLogger(PgpHeaderSignatureProcessor.class);
+
+ private final PGPSecretKeyRing secretKeys;
+ private final SecretKeyRingProtector protector;
+ private byte[] value;
+
+ protected PgpHeaderSignatureProcessor(final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector) {
+ this.secretKeys = Objects.requireNonNull(secretKeys);
+ this.protector = Objects.requireNonNull(protector);
+ }
+
+ public PgpHeaderSignatureProcessor(final PGPSecretKeyRing secretKeys) {
+ this(secretKeys, SecretKeyRingProtector.unprotectedKeys());
+ }
+
+ @Override
+ public void feedHeader(final ByteBuffer header) {
+ try {
+ OutputStream sink = new OutputStream() {
+ @Override
+ public void write(int i) throws IOException {
+ // ignore "ciphertext"
+ }
+ };
+ EncryptionStream signingStream = PGPainless.encryptAndOrSign()
+ .onOutputStream(sink)
+ .withOptions(ProducerOptions.sign(SigningOptions.get()
+ .addDetachedSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT)));
+
+ if (header.hasArray()) {
+ signingStream.write(header.array(), header.position(), header.remaining());
+ } else {
+ final byte[] buffer = new byte[header.remaining()];
+ header.get(buffer);
+ signingStream.write(buffer);
+ }
+
+ signingStream.close();
+ EncryptionResult result = signingStream.getResult();
+
+ this.value = result.getDetachedSignatures().values().iterator().next().iterator().next().getEncoded();
+ logger.info("RSA HEADER: {}", this.value);
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void feedPayloadData(final ByteBuffer data) {
+ // we only work on the header data
+ }
+
+ @Override
+ public void finish(final Header signature) {
+ signature.putBlob(RpmSignatureTag.RSAHEADER, this.value);
+ }
+}
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
new file mode 100644
index 0000000..d1693a0
--- /dev/null
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
@@ -0,0 +1,82 @@
+package org.eclipse.packager.rpm.signature;
+
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPSecretKeyRing;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.eclipse.packager.rpm.RpmSignatureTag;
+import org.eclipse.packager.rpm.header.Header;
+import org.pgpainless.PGPainless;
+import org.pgpainless.algorithm.DocumentSignatureType;
+import org.pgpainless.encryption_signing.EncryptionResult;
+import org.pgpainless.encryption_signing.EncryptionStream;
+import org.pgpainless.encryption_signing.ProducerOptions;
+import org.pgpainless.encryption_signing.SigningOptions;
+import org.pgpainless.key.protection.SecretKeyRingProtector;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+public class PgpSignatureProcessor implements SignatureProcessor {
+
+ private final EncryptionStream signingStream;
+
+ public PgpSignatureProcessor(final PGPSecretKeyRing signingKey, final SecretKeyRingProtector protector) {
+ OutputStream sink = new OutputStream() {
+ @Override
+ public void write(int i) throws IOException {
+ // get rid of the "ciphertext"
+ }
+ };
+
+ try {
+ this.signingStream = PGPainless.encryptAndOrSign()
+ .onOutputStream(sink)
+ .withOptions(
+ ProducerOptions.sign(
+ SigningOptions.get()
+ .addDetachedSignature(protector, signingKey, DocumentSignatureType.BINARY_DOCUMENT)
+ )
+ );
+ } catch (PGPException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void feedHeader(ByteBuffer header) {
+ feedData(header);
+ }
+
+ @Override
+ public void feedPayloadData(ByteBuffer data) {
+ feedData(data);
+ }
+
+ private void feedData(ByteBuffer data) {
+ try {
+ if (data.hasArray()) {
+ signingStream.write(data.array(), data.position(), data.remaining());
+ } else {
+ final byte[] buffer = new byte[data.remaining()];
+ data.get(buffer);
+ signingStream.write(buffer);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void finish(Header signature) {
+ try {
+ signingStream.close();
+ EncryptionResult result = signingStream.getResult();
+ PGPSignature sig = result.getDetachedSignatures().values().iterator().next().iterator().next();
+ signature.putBlob(RpmSignatureTag.PGP, sig.getEncoded());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
From 977a59ec196e3ebd27a2d738db0e1d6eddf63f60 Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Tue, 30 May 2023 02:38:05 +0200
Subject: [PATCH 05/18] Base RpmFileSignatureProcessor on new
PgpSignatureProcessor
---
.../signature/RpmFileSignatureProcessor.java | 35 ++++++++++---------
.../RpmFileSignatureProcessorTest.java | 2 +-
2 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
index 20235c1..ad59500 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
@@ -32,7 +32,6 @@
import org.bouncycastle.openpgp.bc.BcPGPSecretKeyRing;
import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
-import org.eclipse.packager.rpm.HashAlgorithm;
import org.eclipse.packager.rpm.RpmSignatureTag;
import org.eclipse.packager.rpm.Rpms;
import org.eclipse.packager.rpm.header.Header;
@@ -40,10 +39,13 @@
import org.eclipse.packager.rpm.info.RpmInformation;
import org.eclipse.packager.rpm.info.RpmInformations;
import org.eclipse.packager.rpm.parse.RpmInputStream;
+import org.pgpainless.PGPainless;
+import org.pgpainless.key.protection.SecretKeyRingProtector;
+import org.pgpainless.util.Passphrase;
/**
* Sign existing RPM file by calling
- * {@link #perform(File, InputStream, String, OutputStream, HashAlgorithm)}
+ * {@link #perform(File, InputStream, String, OutputStream)}
*/
public class RpmFileSignatureProcessor {
@@ -62,10 +64,9 @@ private RpmFileSignatureProcessor() {
* @param passphrase : passphrase to decrypt the private key
* @param out : {@link OutputStream} to write to
* @throws IOException
- * @throws PGPException
*/
- public static void perform(File rpm, InputStream privateKeyIn, String passphrase, OutputStream out, HashAlgorithm hashAlgorithm)
- throws IOException, PGPException {
+ public static void perform(File rpm, InputStream privateKeyIn, String passphrase, OutputStream out)
+ throws IOException {
final long leadLength = 96;
long signatureHeaderStart = 0L;
@@ -81,8 +82,9 @@ public static void perform(File rpm, InputStream privateKeyIn, String passphrase
throw new IOException("The file " + rpm.getName() + " does not exist");
}
- // Extract private key
- PGPPrivateKey privateKey = getPrivateKey(privateKeyIn, passphrase);
+ PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(privateKeyIn);
+ SecretKeyRingProtector protector = passphrase == null ? SecretKeyRingProtector.unprotectedKeys() :
+ SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword(passphrase));
// Get the information of the RPM
try (RpmInputStream rpmIn = new RpmInputStream(new FileInputStream(rpm))) {
@@ -109,7 +111,7 @@ public static void perform(File rpm, InputStream privateKeyIn, String passphrase
IOUtils.readFully(channelIn, payloadHeaderBuff);
ByteBuffer payloadBuff = ByteBuffer.allocate((int) payloadSize);
IOUtils.readFully(channelIn, payloadBuff);
- signatureHeader = getSignature(privateKey, payloadHeaderBuff, payloadBuff, archiveSize, hashAlgorithm);
+ signatureHeader = getSignature(secretKeys, protector, payloadHeaderBuff, payloadBuff, archiveSize);
}
// Write to the OutputStream
@@ -127,18 +129,18 @@ public static void perform(File rpm, InputStream privateKeyIn, String passphrase
* "https://rpm-software-management.github.io/rpm/manual/format.html">https://rpm-software-management.github.io/rpm/manual/format.html
*
*
- * @param privateKey : private key already extracted
+ * @param secretKeys signing key
+ * @param protector signing key protector
* @param payloadHeader : Payload's header as {@link ByteBuffer}
* @param payload : Payload as {@link ByteBuffer}
* @param archiveSize : archiveSize retrieved in {@link RpmInformation}
- * @param hashAlgorithm
* @return the signature header as a bytes array
* @throws IOException
*/
- private static byte[] getSignature(PGPPrivateKey privateKey, ByteBuffer payloadHeader, ByteBuffer payload,
- long archiveSize, HashAlgorithm hashAlgorithm) throws IOException {
+ private static byte[] getSignature(PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector, ByteBuffer payloadHeader, ByteBuffer payload,
+ long archiveSize) throws IOException {
Header signatureHeader = new Header<>();
- List signatureProcessors = getSignatureProcessors(privateKey, hashAlgorithm);
+ List signatureProcessors = getSignatureProcessors(secretKeys, protector);
payloadHeader.flip();
payload.flip();
for (SignatureProcessor processor : signatureProcessors) {
@@ -183,17 +185,18 @@ private static byte[] safeReadBuffer(ByteBuffer buf) throws IOException {
* {@link SignatureProcessors}
*
*
- * @param privateKey : the private key, already extracted
+ * @param secretKeys signing secret key
+ * @param protector protector to unlock the secret key
* @return {@link List} of {@link SignatureProcessor}
*/
- private static List getSignatureProcessors(PGPPrivateKey privateKey, HashAlgorithm hashAlgorithm) {
+ private static List getSignatureProcessors(PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector) {
List signatureProcessors = new ArrayList<>();
signatureProcessors.add(SignatureProcessors.size());
signatureProcessors.add(SignatureProcessors.sha256Header());
signatureProcessors.add(SignatureProcessors.sha1Header());
signatureProcessors.add(SignatureProcessors.md5());
signatureProcessors.add(SignatureProcessors.payloadSize());
- signatureProcessors.add(new RsaSignatureProcessor(privateKey, hashAlgorithm));
+ signatureProcessors.add(new PgpSignatureProcessor(secretKeys, protector));
return signatureProcessors;
}
diff --git a/rpm/src/test/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessorTest.java b/rpm/src/test/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessorTest.java
index a3931cb..a26c507 100644
--- a/rpm/src/test/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessorTest.java
+++ b/rpm/src/test/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessorTest.java
@@ -76,7 +76,7 @@ public void testSigningExistingRpm() throws IOException, PGPException {
try (FileOutputStream resultOut = new FileOutputStream(signedRpm);
InputStream privateKeyStream = new FileInputStream(private_key)) {
// Sign the RPM
- RpmFileSignatureProcessor.perform(rpm, privateKeyStream, passPhrase, resultOut, HashAlgorithm.SHA256);
+ RpmFileSignatureProcessor.perform(rpm, privateKeyStream, passPhrase, resultOut);
// Read the initial (unsigned) rpm file
RpmInputStream initialRpm = new RpmInputStream(new FileInputStream(rpm));
From e1cd281a84341b4985b05b5ea436b9f39a0e00cc Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Tue, 30 May 2023 09:44:58 +0200
Subject: [PATCH 06/18] Remove extraneous semicolon
---
.../java/org/eclipse/packager/security/pgp/SigningStream.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
index d3a23b8..918e528 100644
--- a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
+++ b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
@@ -142,7 +142,7 @@ public void close() throws IOException {
}
EncryptionResult result = signingStream.getResult();
- final PGPSignature signature = result.getDetachedSignatures().values().iterator().next().iterator().next();;
+ final PGPSignature signature = result.getDetachedSignatures().values().iterator().next().iterator().next();
ArmoredOutputStream armoredOutput = ArmoredOutputStreamFactory.get(stream);
signature.encode(new BCPGOutputStream(armoredOutput));
armoredOutput.close();
From b6f03da339e2b037daab8b62c7a3c9f232a4ed59 Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Tue, 30 May 2023 09:46:56 +0200
Subject: [PATCH 07/18] Fix copyright statement in PgpHeaderSignatureProcessor
---
.../packager/rpm/signature/PgpHeaderSignatureProcessor.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
index de594d9..6d94431 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2019 Contributors to the Eclipse Foundation
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
From 49967ee264d94bf4ebb5fa05cde9f4e3ac812105 Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Tue, 30 May 2023 09:47:39 +0200
Subject: [PATCH 08/18] Fix copyright statement in new PgpSignatureProcessor
classes
---
.../rpm/signature/PgpSignatureProcessor.java | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
index d1693a0..6eb17fb 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
@@ -1,3 +1,16 @@
+/*
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+
package org.eclipse.packager.rpm.signature;
import org.bouncycastle.openpgp.PGPException;
From 489bd04ec3629e141def800dea6221667aa9e0f5 Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Mon, 5 Jun 2023 21:48:56 +0200
Subject: [PATCH 09/18] Add back and deprecate some old signing logic
---
.../packager/security/pgp/SigningStream.java | 116 +++++++-------
.../packager/security/pgp/SigningStream2.java | 150 ++++++++++++++++++
.../packager/rpm/yum/RepositoryCreator.java | 90 ++++++++++-
3 files changed, 290 insertions(+), 66 deletions(-)
create mode 100644 core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java
diff --git a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
index 918e528..88926c3 100644
--- a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
+++ b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
@@ -13,52 +13,55 @@
package org.eclipse.packager.security.pgp;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Objects;
+
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.openpgp.PGPException;
-import org.bouncycastle.openpgp.PGPSecretKeyRing;
+import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPSignature;
-import org.pgpainless.PGPainless;
-import org.pgpainless.algorithm.DocumentSignatureType;
-import org.pgpainless.encryption_signing.EncryptionResult;
-import org.pgpainless.encryption_signing.EncryptionStream;
-import org.pgpainless.encryption_signing.ProducerOptions;
-import org.pgpainless.encryption_signing.SigningOptions;
-import org.pgpainless.key.protection.SecretKeyRingProtector;
-import org.pgpainless.util.ArmoredOutputStreamFactory;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Objects;
+import org.bouncycastle.openpgp.PGPSignatureGenerator;
+import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
+/**
+ * Signing Stream.
+ * @deprecated use {@link SigningStream2} instead.
+ */
+@Deprecated
public class SigningStream extends OutputStream {
private final OutputStream stream;
- private final PGPSecretKeyRing secretKeys;
-
- private final SecretKeyRingProtector protector;
+ private final PGPPrivateKey privateKey;
private final boolean inline;
+ private PGPSignatureGenerator signatureGenerator;
+
+ private ArmoredOutputStream armoredOutput;
+
private boolean initialized;
private final String version;
- private EncryptionStream signingStream;
+ private final int digestAlgorithm;
/**
* Create a new signing stream
*
* @param stream the actual output stream
- * @param secretKeys the signing key ring
- * @param protector protector to unlock the signing key
+ * @param privateKey the private key to sign with
+ * @param digestAlgorithm the digest algorithm to use, from
+ * {@link HashAlgorithmTags}
* @param inline whether to sign inline or just write the signature
* @param version the optional version which will be in the signature comment
*/
- public SigningStream(final OutputStream stream, final PGPSecretKeyRing secretKeys, final SecretKeyRingProtector protector, final boolean inline, final String version) {
+ public SigningStream(final OutputStream stream, final PGPPrivateKey privateKey, final int digestAlgorithm, final boolean inline, final String version) {
this.stream = stream;
- this.secretKeys = secretKeys;
- this.protector = protector;
+ this.privateKey = privateKey;
+ this.digestAlgorithm = digestAlgorithm;
this.inline = inline;
this.version = version;
}
@@ -67,12 +70,13 @@ public SigningStream(final OutputStream stream, final PGPSecretKeyRing secretKey
* Create a new signing stream
*
* @param stream the actual output stream
- * @param secretKeys the signing key ring
- * @param protector protector to unlock the signing key
+ * @param privateKey the private key to sign with
+ * @param digestAlgorithm the digest algorithm to use, from
+ * {@link HashAlgorithmTags}
* @param inline whether to sign inline or just write the signature
*/
- public SigningStream(final OutputStream stream, final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector, final boolean inline) {
- this(stream, secretKeys, protector, inline, null);
+ public SigningStream(final OutputStream stream, final PGPPrivateKey privateKey, final int digestAlgorithm, final boolean inline) {
+ this(stream, privateKey, digestAlgorithm, inline, null);
}
protected void testInit() throws IOException {
@@ -82,35 +86,17 @@ protected void testInit() throws IOException {
this.initialized = true;
- ArmoredOutputStreamFactory.setVersionInfo(version);
-
try {
- if (inline) {
-
- SigningOptions signingOptions = SigningOptions.get();
- signingOptions.addInlineSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
- ProducerOptions producerOptions = ProducerOptions.sign(signingOptions)
- .setCleartextSigned();
-
- signingStream = PGPainless.encryptAndOrSign()
- .onOutputStream(stream) // write data and sig to the output stream
- .withOptions(producerOptions);
-
- } else {
-
- SigningOptions signingOptions = SigningOptions.get();
- signingOptions.addDetachedSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
- ProducerOptions producerOptions = ProducerOptions.sign(signingOptions);
-
- signingStream = PGPainless.encryptAndOrSign()
- .onOutputStream(
- // do not output the plaintext data, just emit the signature in close()
- new OutputStream() {
- @Override
- public void write(int i) throws IOException {
- // Ignore data
- }
- }).withOptions(producerOptions);
+ this.signatureGenerator = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(this.privateKey.getPublicKeyPacket().getAlgorithm(), this.digestAlgorithm));
+ this.signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, this.privateKey);
+
+ this.armoredOutput = new ArmoredOutputStream(this.stream);
+ if (this.version != null) {
+ this.armoredOutput.setHeader("Version", this.version);
+ }
+
+ if (this.inline) {
+ this.armoredOutput.beginClearText(this.digestAlgorithm);
}
} catch (final PGPException e) {
throw new IOException(e);
@@ -128,24 +114,28 @@ public void write(final byte[] b, final int off, final int len) throws IOExcepti
testInit();
- signingStream.write(b, off, len);
+ if (this.inline) {
+ this.armoredOutput.write(b, off, len);
+ }
+ this.signatureGenerator.update(b, off, len);
}
@Override
public void close() throws IOException {
testInit();
- signingStream.close();
-
if (this.inline) {
- return;
+ this.armoredOutput.endClearText();
+ }
+
+ try {
+ final PGPSignature signature = this.signatureGenerator.generate();
+ signature.encode(new BCPGOutputStream(this.armoredOutput));
+ } catch (final PGPException e) {
+ throw new IOException(e);
}
- EncryptionResult result = signingStream.getResult();
- final PGPSignature signature = result.getDetachedSignatures().values().iterator().next().iterator().next();
- ArmoredOutputStream armoredOutput = ArmoredOutputStreamFactory.get(stream);
- signature.encode(new BCPGOutputStream(armoredOutput));
- armoredOutput.close();
+ this.armoredOutput.close();
super.close();
}
diff --git a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java
new file mode 100644
index 0000000..61d1ba5
--- /dev/null
+++ b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2015, 2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+
+package org.eclipse.packager.security.pgp;
+
+import org.bouncycastle.bcpg.ArmoredOutputStream;
+import org.bouncycastle.bcpg.BCPGOutputStream;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPSecretKeyRing;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.pgpainless.PGPainless;
+import org.pgpainless.algorithm.DocumentSignatureType;
+import org.pgpainless.encryption_signing.EncryptionResult;
+import org.pgpainless.encryption_signing.EncryptionStream;
+import org.pgpainless.encryption_signing.ProducerOptions;
+import org.pgpainless.encryption_signing.SigningOptions;
+import org.pgpainless.key.protection.SecretKeyRingProtector;
+import org.pgpainless.util.ArmoredOutputStreamFactory;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Objects;
+
+public class SigningStream2 extends OutputStream {
+ private final OutputStream stream;
+
+ private final PGPSecretKeyRing secretKeys;
+
+ private final SecretKeyRingProtector protector;
+
+ private final boolean inline;
+
+ private boolean initialized;
+
+ private EncryptionStream signingStream;
+
+ /**
+ * Create a new signing stream
+ *
+ * @param stream the actual output stream
+ * @param secretKeys the signing key ring
+ * @param protector protector to unlock the signing key
+ * @param inline whether to sign inline or just write the signature
+ * @param version the optional version which will be in the signature comment
+ */
+ public SigningStream2(final OutputStream stream, final PGPSecretKeyRing secretKeys, final SecretKeyRingProtector protector, final boolean inline, final String version) {
+ this.stream = stream;
+ this.secretKeys = secretKeys;
+ this.protector = protector;
+ this.inline = inline;
+
+ ArmoredOutputStreamFactory.setVersionInfo(version);
+ }
+
+ /**
+ * Create a new signing stream
+ *
+ * @param stream the actual output stream
+ * @param secretKeys the signing key ring
+ * @param protector protector to unlock the signing key
+ * @param inline whether to sign inline or just write the signature
+ */
+ public SigningStream2(final OutputStream stream, final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector, final boolean inline) {
+ this(stream, secretKeys, protector, inline, null);
+ }
+
+ protected void testInit() throws IOException {
+ if (this.initialized) {
+ return;
+ }
+
+ this.initialized = true;
+
+
+ try {
+ if (inline) {
+
+ SigningOptions signingOptions = SigningOptions.get();
+ signingOptions.addInlineSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
+ ProducerOptions producerOptions = ProducerOptions.sign(signingOptions)
+ .setCleartextSigned();
+
+ signingStream = PGPainless.encryptAndOrSign()
+ .onOutputStream(stream) // write data and sig to the output stream
+ .withOptions(producerOptions);
+
+ } else {
+
+ SigningOptions signingOptions = SigningOptions.get();
+ signingOptions.addDetachedSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
+ ProducerOptions producerOptions = ProducerOptions.sign(signingOptions);
+
+ signingStream = PGPainless.encryptAndOrSign()
+ .onOutputStream(
+ // do not output the plaintext data, just emit the signature in close()
+ new OutputStream() {
+ @Override
+ public void write(int i) throws IOException {
+ // Ignore data
+ }
+ }).withOptions(producerOptions);
+ }
+ } catch (final PGPException e) {
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ public void write(final int b) throws IOException {
+ write(new byte[] { (byte) b });
+ }
+
+ @Override
+ public void write(final byte[] b, final int off, final int len) throws IOException {
+ Objects.requireNonNull(b);
+
+ testInit();
+
+ signingStream.write(b, off, len);
+ }
+
+ @Override
+ public void close() throws IOException {
+ testInit();
+
+ signingStream.close();
+
+ if (this.inline) {
+ return;
+ }
+
+ EncryptionResult result = signingStream.getResult();
+ final PGPSignature signature = result.getDetachedSignatures().values().iterator().next().iterator().next();
+ ArmoredOutputStream armoredOutput = ArmoredOutputStreamFactory.get(stream);
+ signature.encode(new BCPGOutputStream(armoredOutput));
+ armoredOutput.close();
+
+ super.close();
+ }
+}
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java b/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
index 4fdce91..52afcd9 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
@@ -40,6 +40,8 @@
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.eclipse.packager.io.IOConsumer;
import org.eclipse.packager.io.OutputSpooler;
@@ -51,6 +53,7 @@
import org.eclipse.packager.rpm.info.RpmInformation.Changelog;
import org.eclipse.packager.rpm.info.RpmInformation.Dependency;
import org.eclipse.packager.security.pgp.SigningStream;
+import org.eclipse.packager.security.pgp.SigningStream2;
import org.pgpainless.PGPainless;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.w3c.dom.Document;
@@ -436,31 +439,112 @@ public Builder setXmlContext(final XmlContext xmlContext) {
return this;
}
- public Builder setSigning(final Function signingStreamCreator) {
- this.signingStreamCreator = signingStreamCreator;
+ /**
+ * Enable signing using an (unprotected) PGP private key.
+ *
+ * @param privateKey unlocked PGP private key
+ * @return builder
+ * @deprecated use {@link #setSigning(PGPSecretKeyRing)} instead.
+ */
+ @Deprecated
+ public Builder setSigning(final PGPPrivateKey privateKey) {
+ return setSigning(privateKey, HashAlgorithmTags.SHA256);
+ }
+
+ /**
+ * Enable signing using a PGP private key using the given digest algorithm.
+ *
+ * @param privateKey unlocked PGP private key
+ * @param hashAlgorithm digest algorithm to be used in the signature
+ * @return builder
+ * @deprecated use {@link #setSigning(PGPSecretKeyRing)} instead.
+ */
+ @Deprecated
+ public Builder setSigning(final PGPPrivateKey privateKey, final HashAlgorithm hashAlgorithm) {
+ return setSigning(privateKey, hashAlgorithm.getValue());
+ }
+
+ /**
+ * Enable signing using a PGP private key, using the given digest algorithm.
+ *
+ * @param privateKey unlocked PGP private key
+ * @param digestAlgorithm digest algorithm to be used in the signature
+ * @return builder
+ * @deprecated use {@link #setSigning(PGPSecretKeyRing, SecretKeyRingProtector)} instead.
+ */
+ @Deprecated
+ public Builder setSigning(final PGPPrivateKey privateKey, final int digestAlgorithm) {
+ if (privateKey != null) {
+ this.signingStreamCreator = output -> new SigningStream(output, privateKey, digestAlgorithm, false);
+ } else {
+ this.signingStreamCreator = null;
+ }
return this;
}
+ /**
+ * Enable signing using an (unprotected) PGP secret key.
+ *
+ * @param secretKeys secret key
+ * @return builder
+ */
+ public Builder setSigning(final PGPSecretKeyRing secretKeys) {
+ return setSigning(secretKeys, SecretKeyRingProtector.unprotectedKeys());
+ }
+
+ /**
+ * Enable signing using a PGP secret key.
+ *
+ * @param secretKeys secret key
+ * @param protector protector to unlock the secret key
+ * @return builder
+ */
public Builder setSigning(final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector) {
if (secretKeys != null) {
- return setSigning(output -> new SigningStream(output, secretKeys, protector, false));
+ return setSigning(output -> new SigningStream2(output, secretKeys, protector, false));
} else {
this.signingStreamCreator = null;
}
return this;
}
+ /**
+ * Enable signing using a PGP secret key.
+ *
+ * @param keyInputStream input stream containing the (unprotected) secret key.
+ * @return builder
+ * @throws IOException if the key cannot be parsed
+ */
public Builder setSigning(final InputStream keyInputStream)
throws IOException {
return setSigning(keyInputStream, SecretKeyRingProtector.unprotectedKeys());
}
+ /**
+ * Enable signing using a PGP secret key.
+ *
+ * @param keyInputStream input stream containing the secret key.
+ * @param keyProtector protector to unlock the secret key.
+ * @return builder
+ * @throws IOException if the key cannot be parsed
+ */
public Builder setSigning(final InputStream keyInputStream, SecretKeyRingProtector keyProtector)
throws IOException {
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(keyInputStream);
return setSigning(secretKeys, keyProtector);
}
+ /**
+ * Apply PGP signing to the data stream.
+ *
+ * @param signingStreamCreator function that wraps the output stream into a signing stream.
+ * @return builder
+ */
+ public Builder setSigning(final Function signingStreamCreator) {
+ this.signingStreamCreator = signingStreamCreator;
+ return this;
+ }
+
public RepositoryCreator build() {
return new RepositoryCreator(this.target, this.xmlContext == null ? new DefaultXmlContext() : this.xmlContext, this.signingStreamCreator);
}
From 060d2e8a682dcd962dc670e9b7dde7be7d256b9c Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Mon, 12 Jun 2023 13:19:27 +0200
Subject: [PATCH 10/18] Bump PGPainless to 1.5.3 and support provided key-IDs
---
.../packager/security/pgp/PgpHelper.java | 23 ++++++++
.../packager/security/pgp/SigningStream2.java | 45 ++++++++++++---
pom.xml | 2 +-
.../PgpHeaderSignatureProcessor.java | 19 ++++++-
.../rpm/signature/PgpSignatureProcessor.java | 40 +++++++++++--
.../signature/RpmFileSignatureProcessor.java | 57 +++++--------------
.../packager/rpm/yum/RepositoryCreator.java | 38 +++++++++++--
.../org/eclipse/packager/rpm/WriterTest.java | 37 ++++++------
8 files changed, 180 insertions(+), 81 deletions(-)
diff --git a/core/src/main/java/org/eclipse/packager/security/pgp/PgpHelper.java b/core/src/main/java/org/eclipse/packager/security/pgp/PgpHelper.java
index b7169e0..8a5b8ea 100644
--- a/core/src/main/java/org/eclipse/packager/security/pgp/PgpHelper.java
+++ b/core/src/main/java/org/eclipse/packager/security/pgp/PgpHelper.java
@@ -33,6 +33,10 @@
import org.bouncycastle.openpgp.bc.BcPGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
+import org.pgpainless.PGPainless;
+import org.pgpainless.key.protection.SecretKeyRingProtector;
+import org.pgpainless.key.util.KeyIdUtil;
+import org.pgpainless.util.Passphrase;
public final class PgpHelper {
private PgpHelper() {
@@ -133,4 +137,23 @@ public static PGPSecretKey loadSecretKey(final InputStream input, final String k
return null;
}
+
+ public static PGPSecretKeyRing loadSecretKeyRing(InputStream inputStream)
+ throws IOException {
+ return PGPainless.readKeyRing().secretKeyRing(inputStream);
+ }
+
+ public static long parseKeyId(String keyId) {
+ if (keyId == null) {
+ return 0L;
+ }
+ return KeyIdUtil.fromLongKeyId(keyId);
+ }
+
+ public static SecretKeyRingProtector protectorFromPassword(String password) {
+ if (password == null || password.isEmpty()) {
+ return SecretKeyRingProtector.unprotectedKeys();
+ }
+ return SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword(password));
+ }
}
diff --git a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java
index 61d1ba5..136dc78 100644
--- a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java
+++ b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java
@@ -16,6 +16,7 @@
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.pgpainless.PGPainless;
@@ -29,6 +30,7 @@
import java.io.IOException;
import java.io.OutputStream;
+import java.util.List;
import java.util.Objects;
public class SigningStream2 extends OutputStream {
@@ -38,6 +40,8 @@ public class SigningStream2 extends OutputStream {
private final SecretKeyRingProtector protector;
+ private final long keyId;
+
private final boolean inline;
private boolean initialized;
@@ -53,10 +57,16 @@ public class SigningStream2 extends OutputStream {
* @param inline whether to sign inline or just write the signature
* @param version the optional version which will be in the signature comment
*/
- public SigningStream2(final OutputStream stream, final PGPSecretKeyRing secretKeys, final SecretKeyRingProtector protector, final boolean inline, final String version) {
+ public SigningStream2(final OutputStream stream,
+ final PGPSecretKeyRing secretKeys,
+ final SecretKeyRingProtector protector,
+ final long keyId,
+ final boolean inline,
+ final String version) {
this.stream = stream;
this.secretKeys = secretKeys;
this.protector = protector;
+ this.keyId = keyId;
this.inline = inline;
ArmoredOutputStreamFactory.setVersionInfo(version);
@@ -70,8 +80,12 @@ public SigningStream2(final OutputStream stream, final PGPSecretKeyRing secretKe
* @param protector protector to unlock the signing key
* @param inline whether to sign inline or just write the signature
*/
- public SigningStream2(final OutputStream stream, final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector, final boolean inline) {
- this(stream, secretKeys, protector, inline, null);
+ public SigningStream2(final OutputStream stream,
+ final PGPSecretKeyRing secretKeys,
+ final SecretKeyRingProtector protector,
+ final long keyId,
+ final boolean inline) {
+ this(stream, secretKeys, protector, keyId, inline, null);
}
protected void testInit() throws IOException {
@@ -81,12 +95,25 @@ protected void testInit() throws IOException {
this.initialized = true;
-
try {
+ long signingKeyId = keyId;
+ if (signingKeyId == 0) {
+ List signingKeys = PGPainless.inspectKeyRing(secretKeys).getSigningSubkeys();
+ if (signingKeys.isEmpty()) {
+ throw new PGPException("No available signing subkey found.");
+ }
+ // Sign with first signing subkey found
+ signingKeyId = signingKeys.get(0).getKeyID();
+ }
+
if (inline) {
SigningOptions signingOptions = SigningOptions.get();
- signingOptions.addInlineSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
+ if (keyId != 0) {
+ signingOptions.addInlineSignature(protector, secretKeys, signingKeyId);
+ } else {
+ signingOptions.addInlineSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
+ }
ProducerOptions producerOptions = ProducerOptions.sign(signingOptions)
.setCleartextSigned();
@@ -97,7 +124,11 @@ protected void testInit() throws IOException {
} else {
SigningOptions signingOptions = SigningOptions.get();
- signingOptions.addDetachedSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
+ if (keyId != 0) {
+ signingOptions.addDetachedSignature(protector, secretKeys, keyId);
+ } else {
+ signingOptions.addDetachedSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
+ }
ProducerOptions producerOptions = ProducerOptions.sign(signingOptions);
signingStream = PGPainless.encryptAndOrSign()
@@ -140,7 +171,7 @@ public void close() throws IOException {
}
EncryptionResult result = signingStream.getResult();
- final PGPSignature signature = result.getDetachedSignatures().values().iterator().next().iterator().next();
+ final PGPSignature signature = result.getDetachedSignatures().flatten().iterator().next();
ArmoredOutputStream armoredOutput = ArmoredOutputStreamFactory.get(stream);
signature.encode(new BCPGOutputStream(armoredOutput));
armoredOutput.close();
diff --git a/pom.xml b/pom.xml
index 2eb4140..c376c9e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -120,7 +120,7 @@
org.pgpainless
pgpainless-core
- 1.5.1
+ 1.5.3
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
index 6d94431..659122b 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
@@ -39,11 +39,19 @@ public class PgpHeaderSignatureProcessor implements SignatureProcessor {
private final PGPSecretKeyRing secretKeys;
private final SecretKeyRingProtector protector;
+ private final long keyId;
private byte[] value;
- protected PgpHeaderSignatureProcessor(final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector) {
+ public PgpHeaderSignatureProcessor(final PGPSecretKeyRing secretKeys,
+ final SecretKeyRingProtector protector,
+ final long keyId) {
this.secretKeys = Objects.requireNonNull(secretKeys);
this.protector = Objects.requireNonNull(protector);
+ this.keyId = keyId;
+ }
+
+ public PgpHeaderSignatureProcessor(final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector) {
+ this(secretKeys, protector, 0);
}
public PgpHeaderSignatureProcessor(final PGPSecretKeyRing secretKeys) {
@@ -59,10 +67,15 @@ public void write(int i) throws IOException {
// ignore "ciphertext"
}
};
+ SigningOptions signingOptions = SigningOptions.get();
+ if (keyId == 0) {
+ signingOptions.addDetachedSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
+ } else {
+ signingOptions.addDetachedSignature(protector, secretKeys, keyId);
+ }
EncryptionStream signingStream = PGPainless.encryptAndOrSign()
.onOutputStream(sink)
- .withOptions(ProducerOptions.sign(SigningOptions.get()
- .addDetachedSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT)));
+ .withOptions(ProducerOptions.sign(signingOptions));
if (header.hasArray()) {
signingStream.write(header.array(), header.position(), header.remaining());
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
index 6eb17fb..d9f58c9 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
@@ -34,7 +34,34 @@ public class PgpSignatureProcessor implements SignatureProcessor {
private final EncryptionStream signingStream;
+ /**
+ * Signature Processor using a non-protected signing key.
+ *
+ * @param signingKey signing key
+ */
+ public PgpSignatureProcessor(final PGPSecretKeyRing signingKey) {
+ this(signingKey, SecretKeyRingProtector.unprotectedKeys());
+ }
+
+ /**
+ * Signature Processor using a PGP signing key that can be unlocked by the protector.
+ *
+ * @param signingKey signing key
+ * @param protector protector to unlock the signing key
+ */
public PgpSignatureProcessor(final PGPSecretKeyRing signingKey, final SecretKeyRingProtector protector) {
+ this(signingKey, protector, 0);
+ }
+
+ /**
+ * Signature Processor using a PGP signing key that can be unlocked by the protector.
+ * The signing key to use is determined by the given key-id. If the id is 0, the signing subkey is auto-detected.
+ *
+ * @param signingKey signing key
+ * @param protector protector to unlock the signing key
+ * @param keyId id of the signing subkey (or 0 for autodetect)
+ */
+ public PgpSignatureProcessor(final PGPSecretKeyRing signingKey, final SecretKeyRingProtector protector, long keyId) {
OutputStream sink = new OutputStream() {
@Override
public void write(int i) throws IOException {
@@ -43,14 +70,15 @@ public void write(int i) throws IOException {
};
try {
+ SigningOptions signingOptions = SigningOptions.get();
+ if (keyId != 0) {
+ signingOptions.addDetachedSignature(protector, signingKey, keyId);
+ } else {
+ signingOptions.addDetachedSignature(protector, signingKey, DocumentSignatureType.BINARY_DOCUMENT);
+ }
this.signingStream = PGPainless.encryptAndOrSign()
.onOutputStream(sink)
- .withOptions(
- ProducerOptions.sign(
- SigningOptions.get()
- .addDetachedSignature(protector, signingKey, DocumentSignatureType.BINARY_DOCUMENT)
- )
- );
+ .withOptions(ProducerOptions.sign(signingOptions));
} catch (PGPException | IOException e) {
throw new RuntimeException(e);
}
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
index ad59500..2ba8e81 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
@@ -12,26 +12,8 @@
********************************************************************************/
package org.eclipse.packager.rpm.signature;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.ArrayList;
-import java.util.List;
-
import org.apache.commons.compress.utils.IOUtils;
-import org.bouncycastle.bcpg.ArmoredInputStream;
-import org.bouncycastle.openpgp.PGPException;
-import org.bouncycastle.openpgp.PGPPrivateKey;
-import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
-import org.bouncycastle.openpgp.bc.BcPGPSecretKeyRing;
-import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
-import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
import org.eclipse.packager.rpm.RpmSignatureTag;
import org.eclipse.packager.rpm.Rpms;
import org.eclipse.packager.rpm.header.Header;
@@ -39,9 +21,19 @@
import org.eclipse.packager.rpm.info.RpmInformation;
import org.eclipse.packager.rpm.info.RpmInformations;
import org.eclipse.packager.rpm.parse.RpmInputStream;
-import org.pgpainless.PGPainless;
+import org.eclipse.packager.security.pgp.PgpHelper;
import org.pgpainless.key.protection.SecretKeyRingProtector;
-import org.pgpainless.util.Passphrase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.List;
/**
* Sign existing RPM file by calling
@@ -82,9 +74,8 @@ public static void perform(File rpm, InputStream privateKeyIn, String passphrase
throw new IOException("The file " + rpm.getName() + " does not exist");
}
- PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(privateKeyIn);
- SecretKeyRingProtector protector = passphrase == null ? SecretKeyRingProtector.unprotectedKeys() :
- SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword(passphrase));
+ PGPSecretKeyRing secretKeys = PgpHelper.loadSecretKeyRing(privateKeyIn);
+ SecretKeyRingProtector protector = PgpHelper.protectorFromPassword(passphrase);
// Get the information of the RPM
try (RpmInputStream rpmIn = new RpmInputStream(new FileInputStream(rpm))) {
@@ -199,24 +190,4 @@ private static List getSignatureProcessors(PGPSecretKeyRing
signatureProcessors.add(new PgpSignatureProcessor(secretKeys, protector));
return signatureProcessors;
}
-
- /**
- *
- * Decrypt and retrieve the private key
- *
- *
- * @param privateKeyIn : InputStream containing the encrypted private key
- * @param passphrase : passphrase to decrypt private key
- * @return private key as {@link PGPPrivateKey}
- * @throws PGPException : if the private key cannot be extrated
- * @throws IOException : if error happened with InputStream
- */
- private static PGPPrivateKey getPrivateKey(InputStream privateKeyIn, String passphrase)
- throws PGPException, IOException {
- ArmoredInputStream armor = new ArmoredInputStream(privateKeyIn);
- PGPSecretKeyRing secretKeyRing = new BcPGPSecretKeyRing(armor);
- PGPSecretKey secretKey = secretKeyRing.getSecretKey();
- return secretKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider())
- .build(passphrase.toCharArray()));
- }
}
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java b/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
index 52afcd9..2580d83 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
@@ -52,6 +52,7 @@
import org.eclipse.packager.rpm.info.RpmInformation;
import org.eclipse.packager.rpm.info.RpmInformation.Changelog;
import org.eclipse.packager.rpm.info.RpmInformation.Dependency;
+import org.eclipse.packager.security.pgp.PgpHelper;
import org.eclipse.packager.security.pgp.SigningStream;
import org.eclipse.packager.security.pgp.SigningStream2;
import org.pgpainless.PGPainless;
@@ -500,8 +501,20 @@ public Builder setSigning(final PGPSecretKeyRing secretKeys) {
* @return builder
*/
public Builder setSigning(final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector) {
+ return setSigning(secretKeys, protector, 0);
+ }
+
+ /**
+ * Enable signing using a PGP secret key.
+ *
+ * @param secretKeys secret key
+ * @param protector protector to unlock the secret key
+ * @param keyId ID of the signing subkey, or 0 if the signing subkey is auto-detected
+ * @return builder
+ */
+ public Builder setSigning(final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector, long keyId) {
if (secretKeys != null) {
- return setSigning(output -> new SigningStream2(output, secretKeys, protector, false));
+ return setSigning(output -> new SigningStream2(output, secretKeys, protector, keyId, false));
} else {
this.signingStreamCreator = null;
}
@@ -528,10 +541,27 @@ public Builder setSigning(final InputStream keyInputStream)
* @return builder
* @throws IOException if the key cannot be parsed
*/
- public Builder setSigning(final InputStream keyInputStream, SecretKeyRingProtector keyProtector)
+ public Builder setSigning(final InputStream keyInputStream,
+ final SecretKeyRingProtector keyProtector)
+ throws IOException {
+ return setSigning(keyInputStream, keyProtector, 0);
+ }
+
+ /**
+ * Enable signing using a PGP secret key.
+ *
+ * @param keyInputStream input stream containing the secret key.
+ * @param keyProtector protector to unlock the secret key.
+ * @param keyId ID of the signing subkey, or 0 for auto-detect
+ * @return builder
+ * @throws IOException if the key cannot be parsed
+ */
+ public Builder setSigning(final InputStream keyInputStream,
+ final SecretKeyRingProtector keyProtector,
+ final long keyId)
throws IOException {
- PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(keyInputStream);
- return setSigning(secretKeys, keyProtector);
+ PGPSecretKeyRing secretKeys = PgpHelper.loadSecretKeyRing(keyInputStream);
+ return setSigning(secretKeys, keyProtector, keyId);
}
/**
diff --git a/rpm/src/test/java/org/eclipse/packager/rpm/WriterTest.java b/rpm/src/test/java/org/eclipse/packager/rpm/WriterTest.java
index cc2977a..34f1f52 100644
--- a/rpm/src/test/java/org/eclipse/packager/rpm/WriterTest.java
+++ b/rpm/src/test/java/org/eclipse/packager/rpm/WriterTest.java
@@ -13,21 +13,6 @@
package org.eclipse.packager.rpm;
-import static java.util.EnumSet.of;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
-import java.util.LinkedList;
-import java.util.List;
-
import org.bouncycastle.openpgp.PGPException;
import org.eclipse.packager.rpm.app.Dumper;
import org.eclipse.packager.rpm.build.BuilderContext;
@@ -41,11 +26,26 @@
import org.eclipse.packager.rpm.deps.RpmDependencyFlags;
import org.eclipse.packager.rpm.header.Header;
import org.eclipse.packager.rpm.parse.RpmInputStream;
-import org.eclipse.packager.rpm.signature.RsaHeaderSignatureProcessor;
+import org.eclipse.packager.rpm.signature.PgpHeaderSignatureProcessor;
import org.eclipse.packager.security.pgp.PgpHelper;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.LinkedList;
+import java.util.List;
+
+import static java.util.EnumSet.of;
+
public class WriterTest {
private static final Path OUT_BASE = Paths.get("target", "data", "out");
@@ -194,7 +194,10 @@ public void test3() throws IOException, PGPException {
if (keyId != null && keyChain != null) {
try (InputStream stream = Files.newInputStream(Paths.get(keyChain))) {
- builder.addSignatureProcessor(new RsaHeaderSignatureProcessor(PgpHelper.loadPrivateKey(stream, keyId, keyPassphrase), HashAlgorithm.from(System.getProperty("writerTest.hashAlgo"))));
+ builder.addSignatureProcessor(new PgpHeaderSignatureProcessor(
+ PgpHelper.loadSecretKeyRing(stream),
+ PgpHelper.protectorFromPassword(keyPassphrase),
+ PgpHelper.parseKeyId(keyId)));
}
}
From bcf9966e3fa77b1fd8f3b5e8e0236a72573afc5f Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Mon, 12 Jun 2023 13:22:38 +0200
Subject: [PATCH 11/18] Flatten set of signatures
---
.../packager/rpm/signature/PgpHeaderSignatureProcessor.java | 2 +-
.../eclipse/packager/rpm/signature/PgpSignatureProcessor.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
index 659122b..852b6f8 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
@@ -88,7 +88,7 @@ public void write(int i) throws IOException {
signingStream.close();
EncryptionResult result = signingStream.getResult();
- this.value = result.getDetachedSignatures().values().iterator().next().iterator().next().getEncoded();
+ this.value = result.getDetachedSignatures().flatten().iterator().next().getEncoded();
logger.info("RSA HEADER: {}", this.value);
} catch (final Exception e) {
throw new RuntimeException(e);
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
index d9f58c9..7c5f58a 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
@@ -113,7 +113,7 @@ public void finish(Header signature) {
try {
signingStream.close();
EncryptionResult result = signingStream.getResult();
- PGPSignature sig = result.getDetachedSignatures().values().iterator().next().iterator().next();
+ PGPSignature sig = result.getDetachedSignatures().flatten().iterator().next();
signature.putBlob(RpmSignatureTag.PGP, sig.getEncoded());
} catch (IOException e) {
throw new RuntimeException(e);
From a2ac3878c374c7b516bc0f31c393b2f12ad5cb26 Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Fri, 29 Mar 2024 20:06:12 +0100
Subject: [PATCH 12/18] Fix codestyle isses
---
.../packager/security/pgp/PgpHelper.java | 2 +-
.../packager/security/pgp/SigningStream.java | 1 +
.../packager/security/pgp/SigningStream2.java | 51 ++++++++++---------
.../PgpHeaderSignatureProcessor.java | 21 ++++----
.../rpm/signature/PgpSignatureProcessor.java | 21 ++++----
.../signature/RpmFileSignatureProcessor.java | 30 +++++------
.../packager/rpm/yum/RepositoryCreator.java | 22 ++++----
.../org/eclipse/packager/rpm/WriterTest.java | 36 ++++++-------
.../RpmFileSignatureProcessorTest.java | 24 ++++-----
9 files changed, 109 insertions(+), 99 deletions(-)
diff --git a/core/src/main/java/org/eclipse/packager/security/pgp/PgpHelper.java b/core/src/main/java/org/eclipse/packager/security/pgp/PgpHelper.java
index 8a5b8ea..15f6f53 100644
--- a/core/src/main/java/org/eclipse/packager/security/pgp/PgpHelper.java
+++ b/core/src/main/java/org/eclipse/packager/security/pgp/PgpHelper.java
@@ -139,7 +139,7 @@ public static PGPSecretKey loadSecretKey(final InputStream input, final String k
}
public static PGPSecretKeyRing loadSecretKeyRing(InputStream inputStream)
- throws IOException {
+ throws IOException {
return PGPainless.readKeyRing().secretKeyRing(inputStream);
}
diff --git a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
index dc953ab..7655f13 100644
--- a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
+++ b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream.java
@@ -28,6 +28,7 @@
/**
* Signing Stream.
+ *
* @deprecated use {@link SigningStream2} instead.
*/
@Deprecated
diff --git a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java
index 136dc78..bb6c08a 100644
--- a/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java
+++ b/core/src/main/java/org/eclipse/packager/security/pgp/SigningStream2.java
@@ -13,6 +13,11 @@
package org.eclipse.packager.security.pgp;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Objects;
+
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.openpgp.PGPException;
@@ -28,11 +33,6 @@
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.util.ArmoredOutputStreamFactory;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.Objects;
-
public class SigningStream2 extends OutputStream {
private final OutputStream stream;
@@ -58,11 +58,11 @@ public class SigningStream2 extends OutputStream {
* @param version the optional version which will be in the signature comment
*/
public SigningStream2(final OutputStream stream,
- final PGPSecretKeyRing secretKeys,
- final SecretKeyRingProtector protector,
- final long keyId,
- final boolean inline,
- final String version) {
+ final PGPSecretKeyRing secretKeys,
+ final SecretKeyRingProtector protector,
+ final long keyId,
+ final boolean inline,
+ final String version) {
this.stream = stream;
this.secretKeys = secretKeys;
this.protector = protector;
@@ -81,10 +81,10 @@ public SigningStream2(final OutputStream stream,
* @param inline whether to sign inline or just write the signature
*/
public SigningStream2(final OutputStream stream,
- final PGPSecretKeyRing secretKeys,
- final SecretKeyRingProtector protector,
- final long keyId,
- final boolean inline) {
+ final PGPSecretKeyRing secretKeys,
+ final SecretKeyRingProtector protector,
+ final long keyId,
+ final boolean inline) {
this(stream, secretKeys, protector, keyId, inline, null);
}
@@ -115,11 +115,11 @@ protected void testInit() throws IOException {
signingOptions.addInlineSignature(protector, secretKeys, DocumentSignatureType.BINARY_DOCUMENT);
}
ProducerOptions producerOptions = ProducerOptions.sign(signingOptions)
- .setCleartextSigned();
+ .setCleartextSigned();
signingStream = PGPainless.encryptAndOrSign()
- .onOutputStream(stream) // write data and sig to the output stream
- .withOptions(producerOptions);
+ .onOutputStream(stream) // write data and sig to the output stream
+ .withOptions(producerOptions);
} else {
@@ -132,14 +132,15 @@ protected void testInit() throws IOException {
ProducerOptions producerOptions = ProducerOptions.sign(signingOptions);
signingStream = PGPainless.encryptAndOrSign()
- .onOutputStream(
- // do not output the plaintext data, just emit the signature in close()
- new OutputStream() {
- @Override
- public void write(int i) throws IOException {
- // Ignore data
- }
- }).withOptions(producerOptions);
+ .onOutputStream(
+ // do not output the plaintext data, just emit the signature in close()
+ new OutputStream() {
+ @Override
+ public void write(int i) throws IOException {
+ // Ignore data
+ }
+ })
+ .withOptions(producerOptions);
}
} catch (final PGPException e) {
throw new IOException(e);
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
index 852b6f8..fe57572 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
@@ -13,6 +13,11 @@
package org.eclipse.packager.rpm.signature;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.eclipse.packager.rpm.RpmSignatureTag;
import org.eclipse.packager.rpm.header.Header;
@@ -26,11 +31,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.util.Objects;
-
/**
* An RSA signature processor for the header section only.
*/
@@ -38,13 +38,16 @@ public class PgpHeaderSignatureProcessor implements SignatureProcessor {
private final static Logger logger = LoggerFactory.getLogger(PgpHeaderSignatureProcessor.class);
private final PGPSecretKeyRing secretKeys;
+
private final SecretKeyRingProtector protector;
+
private final long keyId;
+
private byte[] value;
public PgpHeaderSignatureProcessor(final PGPSecretKeyRing secretKeys,
- final SecretKeyRingProtector protector,
- final long keyId) {
+ final SecretKeyRingProtector protector,
+ final long keyId) {
this.secretKeys = Objects.requireNonNull(secretKeys);
this.protector = Objects.requireNonNull(protector);
this.keyId = keyId;
@@ -74,8 +77,8 @@ public void write(int i) throws IOException {
signingOptions.addDetachedSignature(protector, secretKeys, keyId);
}
EncryptionStream signingStream = PGPainless.encryptAndOrSign()
- .onOutputStream(sink)
- .withOptions(ProducerOptions.sign(signingOptions));
+ .onOutputStream(sink)
+ .withOptions(ProducerOptions.sign(signingOptions));
if (header.hasArray()) {
signingStream.write(header.array(), header.position(), header.remaining());
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
index 7c5f58a..dc140d6 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpSignatureProcessor.java
@@ -13,6 +13,10 @@
package org.eclipse.packager.rpm.signature;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
@@ -26,10 +30,6 @@
import org.pgpainless.encryption_signing.SigningOptions;
import org.pgpainless.key.protection.SecretKeyRingProtector;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-
public class PgpSignatureProcessor implements SignatureProcessor {
private final EncryptionStream signingStream;
@@ -44,7 +44,8 @@ public PgpSignatureProcessor(final PGPSecretKeyRing signingKey) {
}
/**
- * Signature Processor using a PGP signing key that can be unlocked by the protector.
+ * Signature Processor using a PGP signing key that can be unlocked by the
+ * protector.
*
* @param signingKey signing key
* @param protector protector to unlock the signing key
@@ -54,8 +55,10 @@ public PgpSignatureProcessor(final PGPSecretKeyRing signingKey, final SecretKeyR
}
/**
- * Signature Processor using a PGP signing key that can be unlocked by the protector.
- * The signing key to use is determined by the given key-id. If the id is 0, the signing subkey is auto-detected.
+ * Signature Processor using a PGP signing key that can be unlocked by the
+ * protector.
+ * The signing key to use is determined by the given key-id. If the id is 0, the
+ * signing subkey is auto-detected.
*
* @param signingKey signing key
* @param protector protector to unlock the signing key
@@ -77,8 +80,8 @@ public void write(int i) throws IOException {
signingOptions.addDetachedSignature(protector, signingKey, DocumentSignatureType.BINARY_DOCUMENT);
}
this.signingStream = PGPainless.encryptAndOrSign()
- .onOutputStream(sink)
- .withOptions(ProducerOptions.sign(signingOptions));
+ .onOutputStream(sink)
+ .withOptions(ProducerOptions.sign(signingOptions));
} catch (PGPException | IOException e) {
throw new RuntimeException(e);
}
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
index 08a979d..20c00c6 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
@@ -8,10 +8,21 @@
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
- * mat1e, Groupe EDF - initial API and implementation
+ * mat1e, Groupe EDF - initial API and implementation
********************************************************************************/
package org.eclipse.packager.rpm.signature;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.List;
+
import org.apache.commons.compress.utils.IOUtils;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.eclipse.packager.rpm.RpmSignatureTag;
@@ -24,17 +35,6 @@
import org.eclipse.packager.security.pgp.PgpHelper;
import org.pgpainless.key.protection.SecretKeyRingProtector;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Sign existing RPM file by calling
* {@link #perform(File, InputStream, String, OutputStream)}
@@ -58,7 +58,7 @@ private RpmFileSignatureProcessor() {
* @throws IOException
*/
public static void perform(File rpm, InputStream privateKeyIn, String passphrase, OutputStream out)
- throws IOException {
+ throws IOException {
final long leadLength = 96;
long signatureHeaderStart = 0L;
@@ -89,7 +89,7 @@ public static void perform(File rpm, InputStream privateKeyIn, String passphrase
}
if (signatureHeaderStart == 0L || signatureHeaderLength == 0L || payloadHeaderStart == 0L
- || payloadHeaderLength == 0L || payloadStart == 0L || archiveSize == 0L) {
+ || payloadHeaderLength == 0L || payloadStart == 0L || archiveSize == 0L) {
throw new IOException("Unable to read " + rpm.getName() + " informations.");
}
@@ -129,7 +129,7 @@ public static void perform(File rpm, InputStream privateKeyIn, String passphrase
* @throws IOException
*/
private static byte[] getSignature(PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector, ByteBuffer payloadHeader, ByteBuffer payload,
- long archiveSize) throws IOException {
+ long archiveSize) throws IOException {
Header signatureHeader = new Header<>();
List signatureProcessors = getSignatureProcessors(secretKeys, protector);
payloadHeader.flip();
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java b/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
index 2580d83..50015ae 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/yum/RepositoryCreator.java
@@ -55,7 +55,6 @@
import org.eclipse.packager.security.pgp.PgpHelper;
import org.eclipse.packager.security.pgp.SigningStream;
import org.eclipse.packager.security.pgp.SigningStream2;
-import org.pgpainless.PGPainless;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -471,7 +470,8 @@ public Builder setSigning(final PGPPrivateKey privateKey, final HashAlgorithm ha
* @param privateKey unlocked PGP private key
* @param digestAlgorithm digest algorithm to be used in the signature
* @return builder
- * @deprecated use {@link #setSigning(PGPSecretKeyRing, SecretKeyRingProtector)} instead.
+ * @deprecated use {@link #setSigning(PGPSecretKeyRing, SecretKeyRingProtector)}
+ * instead.
*/
@Deprecated
public Builder setSigning(final PGPPrivateKey privateKey, final int digestAlgorithm) {
@@ -509,7 +509,8 @@ public Builder setSigning(final PGPSecretKeyRing secretKeys, SecretKeyRingProtec
*
* @param secretKeys secret key
* @param protector protector to unlock the secret key
- * @param keyId ID of the signing subkey, or 0 if the signing subkey is auto-detected
+ * @param keyId ID of the signing subkey, or 0 if the signing subkey is
+ * auto-detected
* @return builder
*/
public Builder setSigning(final PGPSecretKeyRing secretKeys, SecretKeyRingProtector protector, long keyId) {
@@ -529,7 +530,7 @@ public Builder setSigning(final PGPSecretKeyRing secretKeys, SecretKeyRingProtec
* @throws IOException if the key cannot be parsed
*/
public Builder setSigning(final InputStream keyInputStream)
- throws IOException {
+ throws IOException {
return setSigning(keyInputStream, SecretKeyRingProtector.unprotectedKeys());
}
@@ -542,8 +543,8 @@ public Builder setSigning(final InputStream keyInputStream)
* @throws IOException if the key cannot be parsed
*/
public Builder setSigning(final InputStream keyInputStream,
- final SecretKeyRingProtector keyProtector)
- throws IOException {
+ final SecretKeyRingProtector keyProtector)
+ throws IOException {
return setSigning(keyInputStream, keyProtector, 0);
}
@@ -557,9 +558,9 @@ public Builder setSigning(final InputStream keyInputStream,
* @throws IOException if the key cannot be parsed
*/
public Builder setSigning(final InputStream keyInputStream,
- final SecretKeyRingProtector keyProtector,
- final long keyId)
- throws IOException {
+ final SecretKeyRingProtector keyProtector,
+ final long keyId)
+ throws IOException {
PGPSecretKeyRing secretKeys = PgpHelper.loadSecretKeyRing(keyInputStream);
return setSigning(secretKeys, keyProtector, keyId);
}
@@ -567,7 +568,8 @@ public Builder setSigning(final InputStream keyInputStream,
/**
* Apply PGP signing to the data stream.
*
- * @param signingStreamCreator function that wraps the output stream into a signing stream.
+ * @param signingStreamCreator function that wraps the output stream into a
+ * signing stream.
* @return builder
*/
public Builder setSigning(final Function signingStreamCreator) {
diff --git a/rpm/src/test/java/org/eclipse/packager/rpm/WriterTest.java b/rpm/src/test/java/org/eclipse/packager/rpm/WriterTest.java
index 34f1f52..6707bb1 100644
--- a/rpm/src/test/java/org/eclipse/packager/rpm/WriterTest.java
+++ b/rpm/src/test/java/org/eclipse/packager/rpm/WriterTest.java
@@ -13,6 +13,21 @@
package org.eclipse.packager.rpm;
+import static java.util.EnumSet.of;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.LinkedList;
+import java.util.List;
+
import org.bouncycastle.openpgp.PGPException;
import org.eclipse.packager.rpm.app.Dumper;
import org.eclipse.packager.rpm.build.BuilderContext;
@@ -31,21 +46,6 @@
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
-import java.util.LinkedList;
-import java.util.List;
-
-import static java.util.EnumSet.of;
-
public class WriterTest {
private static final Path OUT_BASE = Paths.get("target", "data", "out");
@@ -195,9 +195,9 @@ public void test3() throws IOException, PGPException {
if (keyId != null && keyChain != null) {
try (InputStream stream = Files.newInputStream(Paths.get(keyChain))) {
builder.addSignatureProcessor(new PgpHeaderSignatureProcessor(
- PgpHelper.loadSecretKeyRing(stream),
- PgpHelper.protectorFromPassword(keyPassphrase),
- PgpHelper.parseKeyId(keyId)));
+ PgpHelper.loadSecretKeyRing(stream),
+ PgpHelper.protectorFromPassword(keyPassphrase),
+ PgpHelper.parseKeyId(keyId)));
}
}
diff --git a/rpm/src/test/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessorTest.java b/rpm/src/test/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessorTest.java
index a26c507..36d742c 100644
--- a/rpm/src/test/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessorTest.java
+++ b/rpm/src/test/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessorTest.java
@@ -8,8 +8,8 @@
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
- * mat1e, Groupe EDF - initial API and implementation
- * Jens Reimann, Red Hat, Inc
+ * mat1e, Groupe EDF - initial API and implementation
+ * Jens Reimann, Red Hat, Inc
********************************************************************************/
package org.eclipse.packager.rpm.signature;
@@ -28,7 +28,6 @@
import java.util.Optional;
import org.bouncycastle.openpgp.PGPException;
-import org.eclipse.packager.rpm.HashAlgorithm;
import org.eclipse.packager.rpm.RpmSignatureTag;
import org.eclipse.packager.rpm.Rpms;
import org.eclipse.packager.rpm.parse.InputHeader;
@@ -74,7 +73,7 @@ public void testSigningExistingRpm() throws IOException, PGPException {
signedRpm.createNewFile();
try (FileOutputStream resultOut = new FileOutputStream(signedRpm);
- InputStream privateKeyStream = new FileInputStream(private_key)) {
+ InputStream privateKeyStream = new FileInputStream(private_key)) {
// Sign the RPM
RpmFileSignatureProcessor.perform(rpm, privateKeyStream, passPhrase, resultOut);
@@ -130,7 +129,8 @@ public void verifyRpmSignature() throws Exception {
String publicKeyName = publicKey.getName();
String rpmFileName = signedRpm.getName();
- // prepare the script for validating the signature, this includes importing the key and running a verbose check
+ // prepare the script for validating the signature, this includes importing the
+ // key and running a verbose check
String script = String.format("rpm --import /%s && rpm --verbose --checksig /%s", publicKeyName, rpmFileName);
// SElinux labeling
@@ -142,14 +142,14 @@ public void verifyRpmSignature() throws Exception {
}
});
-
- // create the actual command, which we run inside a container, to not mess up the host systems RPM configuration and
+ // create the actual command, which we run inside a container, to not mess up
+ // the host systems RPM configuration and
// because this gives us a predictable RPM version.
String[] command = new String[] {
- CONTAINER, "run", "-tiq", "--rm",
- "-v", publicKey + ":/" + publicKeyName + mountSuffix,
- "-v", signedRpm + ":/" + rpmFileName + mountSuffix,
- "registry.access.redhat.com/ubi9/ubi-minimal:latest", "bash", "-c", script
+ CONTAINER, "run", "-tiq", "--rm",
+ "-v", publicKey + ":/" + publicKeyName + mountSuffix,
+ "-v", signedRpm + ":/" + rpmFileName + mountSuffix,
+ "registry.access.redhat.com/ubi9/ubi-minimal:latest", "bash", "-c", script
};
// dump command for local testing
@@ -176,7 +176,7 @@ private static void dumpCommand(String[] command) {
private static String run(String... command) throws IOException, InterruptedException {
Process process = new ProcessBuilder(command)
- .start();
+ .start();
String stdout = new String(ByteStreams.toByteArray(process.getInputStream()));
process.waitFor();
return stdout;
From b90e86cd0336fb72d523810d9ddc9eff61c693da Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Fri, 29 Mar 2024 20:06:24 +0100
Subject: [PATCH 13/18] Bump PGPainless to 1.6.7
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 2ee5e1b..50cd9c9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -121,7 +121,7 @@
org.pgpainless
pgpainless-core
- 1.5.3
+ 1.6.7
From 68f8658bf51147ba95c171155880ce4d1d946dcd Mon Sep 17 00:00:00 2001
From: David Walluck
Date: Fri, 29 Mar 2024 20:55:50 +0100
Subject: [PATCH 14/18] Fix IOUtils import
---
.../packager/rpm/signature/RpmFileSignatureProcessor.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
index 20c00c6..073db5a 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RpmFileSignatureProcessor.java
@@ -23,7 +23,7 @@
import java.util.ArrayList;
import java.util.List;
-import org.apache.commons.compress.utils.IOUtils;
+import org.apache.commons.io.IOUtils;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.eclipse.packager.rpm.RpmSignatureTag;
import org.eclipse.packager.rpm.Rpms;
From d68ab1addac56a9703fecf8a25b0ed9f1d0c6734 Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Fri, 29 Mar 2024 22:30:35 +0100
Subject: [PATCH 15/18] For DSA signatures: Put DSAHEADER blob
---
.../PgpHeaderSignatureProcessor.java | 27 +++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
index fe57572..3eed941 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
@@ -18,7 +18,9 @@
import java.nio.ByteBuffer;
import java.util.Objects;
+import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
+import org.bouncycastle.openpgp.PGPSignature;
import org.eclipse.packager.rpm.RpmSignatureTag;
import org.eclipse.packager.rpm.header.Header;
import org.pgpainless.PGPainless;
@@ -43,6 +45,8 @@ public class PgpHeaderSignatureProcessor implements SignatureProcessor {
private final long keyId;
+ private PGPSignature signature;
+
private byte[] value;
public PgpHeaderSignatureProcessor(final PGPSecretKeyRing secretKeys,
@@ -91,7 +95,8 @@ public void write(int i) throws IOException {
signingStream.close();
EncryptionResult result = signingStream.getResult();
- this.value = result.getDetachedSignatures().flatten().iterator().next().getEncoded();
+ this.signature = result.getDetachedSignatures().flatten().iterator().next();
+ this.value = signature.getEncoded();
logger.info("RSA HEADER: {}", this.value);
} catch (final Exception e) {
throw new RuntimeException(e);
@@ -105,6 +110,24 @@ public void feedPayloadData(final ByteBuffer data) {
@Override
public void finish(final Header signature) {
- signature.putBlob(RpmSignatureTag.RSAHEADER, this.value);
+ switch (this.signature.getKeyAlgorithm()) {
+ // RSA
+ case PublicKeyAlgorithmTags.RSA_GENERAL:
+ case PublicKeyAlgorithmTags.RSA_ENCRYPT:
+ case PublicKeyAlgorithmTags.RSA_SIGN:
+ signature.putBlob(RpmSignatureTag.RSAHEADER, this.value);
+ break;
+
+ // DSA
+ case PublicKeyAlgorithmTags.DSA:
+ case PublicKeyAlgorithmTags.ECDSA:
+ case PublicKeyAlgorithmTags.EDDSA_LEGACY:
+ signature.putBlob(RpmSignatureTag.DSAHEADER, this.value);
+ break;
+
+ default:
+ throw new RuntimeException("Unsupported public key algorithm id: " + this.signature.getKeyAlgorithm());
+ }
+
}
}
From b2a8d25ce6de241c4edafa3b070f42f95e33deab Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Sat, 30 Mar 2024 02:24:43 +0100
Subject: [PATCH 16/18] Remove unused algorithm tags
---
.../rpm/signature/PgpHeaderSignatureProcessor.java | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
index 3eed941..06b6f3d 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
@@ -112,16 +112,13 @@ public void feedPayloadData(final ByteBuffer data) {
public void finish(final Header signature) {
switch (this.signature.getKeyAlgorithm()) {
// RSA
- case PublicKeyAlgorithmTags.RSA_GENERAL:
- case PublicKeyAlgorithmTags.RSA_ENCRYPT:
- case PublicKeyAlgorithmTags.RSA_SIGN:
+ case PublicKeyAlgorithmTags.RSA_GENERAL: // 1
signature.putBlob(RpmSignatureTag.RSAHEADER, this.value);
break;
// DSA
- case PublicKeyAlgorithmTags.DSA:
- case PublicKeyAlgorithmTags.ECDSA:
- case PublicKeyAlgorithmTags.EDDSA_LEGACY:
+ case PublicKeyAlgorithmTags.DSA: // 17
+ case PublicKeyAlgorithmTags.EDDSA_LEGACY: // 22
signature.putBlob(RpmSignatureTag.DSAHEADER, this.value);
break;
From de14b425db4ccec520d44e8306255d575243b64f Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Sat, 30 Mar 2024 14:27:52 +0100
Subject: [PATCH 17/18] Add deprecation notices to RsaSignatureProcessor and
RsaHeaderSignatureProcessor
---
.../packager/rpm/signature/RsaHeaderSignatureProcessor.java | 3 +++
.../eclipse/packager/rpm/signature/RsaSignatureProcessor.java | 3 +++
2 files changed, 6 insertions(+)
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaHeaderSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaHeaderSignatureProcessor.java
index 473cca8..c8c104b 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaHeaderSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaHeaderSignatureProcessor.java
@@ -29,7 +29,10 @@
/**
* An RSA signature processor for the header section only.
+ *
+ * @deprecated use {@link PgpHeaderSignatureProcessor} instead.
*/
+@Deprecated
public class RsaHeaderSignatureProcessor implements SignatureProcessor {
private final static Logger logger = LoggerFactory.getLogger(RsaHeaderSignatureProcessor.class);
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaSignatureProcessor.java
index 123c993..1ba88b9 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/RsaSignatureProcessor.java
@@ -29,7 +29,10 @@
/**
* An RSA signature processor for both header and payload.
+ *
+ * @deprecated use {@link PgpSignatureProcessor} instead.
*/
+@Deprecated
public class RsaSignatureProcessor implements SignatureProcessor {
private final static Logger logger = LoggerFactory.getLogger(RsaSignatureProcessor.class);
From c2c9b844607b00d35eedcc1384d461f7e508d49b Mon Sep 17 00:00:00 2001
From: Paul Schaub
Date: Sat, 30 Mar 2024 14:29:59 +0100
Subject: [PATCH 18/18] Move logging statements to finish(), differentiating
RSA and DSA
---
.../rpm/signature/PgpHeaderSignatureProcessor.java | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
index 06b6f3d..54730ff 100644
--- a/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
+++ b/rpm/src/main/java/org/eclipse/packager/rpm/signature/PgpHeaderSignatureProcessor.java
@@ -97,7 +97,6 @@ public void write(int i) throws IOException {
this.signature = result.getDetachedSignatures().flatten().iterator().next();
this.value = signature.getEncoded();
- logger.info("RSA HEADER: {}", this.value);
} catch (final Exception e) {
throw new RuntimeException(e);
}
@@ -112,13 +111,15 @@ public void feedPayloadData(final ByteBuffer data) {
public void finish(final Header signature) {
switch (this.signature.getKeyAlgorithm()) {
// RSA
- case PublicKeyAlgorithmTags.RSA_GENERAL: // 1
+ case PublicKeyAlgorithmTags.RSA_GENERAL: // 1
+ logger.info("RSA HEADER: {}", this.value);
signature.putBlob(RpmSignatureTag.RSAHEADER, this.value);
break;
// DSA
- case PublicKeyAlgorithmTags.DSA: // 17
- case PublicKeyAlgorithmTags.EDDSA_LEGACY: // 22
+ case PublicKeyAlgorithmTags.DSA: // 17
+ case PublicKeyAlgorithmTags.EDDSA_LEGACY: // 22
+ logger.info("DSA HEADER: {}", this.value);
signature.putBlob(RpmSignatureTag.DSAHEADER, this.value);
break;