Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@

<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpg-jdk18on</artifactId>
<groupId>org.pgpainless</groupId>
<artifactId>pgpainless-core</artifactId>
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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 {
Expand All @@ -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);
Expand All @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion deb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@
</plugins>
</build>

</project>
</project>
14 changes: 4 additions & 10 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
<java.release>8</java.release>
<java.source>1.8</java.source>

<bouncycastle.version>1.71</bouncycastle.version>
<bouncycastle.version>1.73</bouncycastle.version>
<commons-compress.version>1.21</commons-compress.version>
<guava.version>31.1-jre</guava.version>
<junit.jupiter.version>5.8.2</junit.jupiter.version>
Expand Down Expand Up @@ -117,16 +117,10 @@

<dependencyManagement>
<dependencies>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpg-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
<groupId>org.pgpainless</groupId>
<artifactId>pgpainless-core</artifactId>
<version>1.5.1</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -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<RpmSignatureTag> signature) {
signature.putBlob(RpmSignatureTag.RSAHEADER, this.value);
}
}
Loading