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;