mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-26 22:32:07 +01:00
More signature builder experimentations
This commit is contained in:
parent
e9dc26b1da
commit
de926e022f
8 changed files with 168 additions and 21 deletions
|
@ -43,8 +43,8 @@ public abstract class AbstractSignatureBuilder<B extends AbstractSignatureBuilde
|
||||||
this.publicSigningKey = signingKey.getPublicKey();
|
this.publicSigningKey = signingKey.getPublicKey();
|
||||||
this.hashAlgorithm = negotiateHashAlgorithm(publicSigningKey);
|
this.hashAlgorithm = negotiateHashAlgorithm(publicSigningKey);
|
||||||
|
|
||||||
unhashedSubpackets = new SignatureSubpacketGeneratorWrapper();
|
unhashedSubpackets = SignatureSubpacketGeneratorWrapper.createEmptySubpackets();
|
||||||
hashedSubpackets = new SignatureSubpacketGeneratorWrapper(publicSigningKey);
|
hashedSubpackets = SignatureSubpacketGeneratorWrapper.createHashedSubpackets(publicSigningKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbstractSignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector, PGPSignature archetypeSignature) throws WrongPassphraseException {
|
public AbstractSignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector, PGPSignature archetypeSignature) throws WrongPassphraseException {
|
||||||
|
@ -57,8 +57,8 @@ public abstract class AbstractSignatureBuilder<B extends AbstractSignatureBuilde
|
||||||
this.publicSigningKey = certificationKey.getPublicKey();
|
this.publicSigningKey = certificationKey.getPublicKey();
|
||||||
this.hashAlgorithm = negotiateHashAlgorithm(publicSigningKey);
|
this.hashAlgorithm = negotiateHashAlgorithm(publicSigningKey);
|
||||||
|
|
||||||
unhashedSubpackets = new SignatureSubpacketGeneratorWrapper(archetypeSignature.getUnhashedSubPackets());
|
unhashedSubpackets = SignatureSubpacketGeneratorWrapper.refreshUnhashedSubpackets(archetypeSignature);
|
||||||
hashedSubpackets = new SignatureSubpacketGeneratorWrapper(publicSigningKey, archetypeSignature.getHashedSubPackets());
|
hashedSubpackets = SignatureSubpacketGeneratorWrapper.refreshHashedSubpackets(publicSigningKey, archetypeSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HashAlgorithm negotiateHashAlgorithm(PGPPublicKey publicKey) {
|
protected HashAlgorithm negotiateHashAlgorithm(PGPPublicKey publicKey) {
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.signature.builder;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
|
import org.pgpainless.algorithm.SignatureType;
|
||||||
|
import org.pgpainless.exception.WrongPassphraseException;
|
||||||
|
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
|
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
|
||||||
|
|
||||||
|
public class PrimaryKeyBindingSignatureBuilder extends AbstractSignatureBuilder<PrimaryKeyBindingSignatureBuilder> {
|
||||||
|
|
||||||
|
public PrimaryKeyBindingSignatureBuilder(PGPSecretKey subkey, SecretKeyRingProtector subkeyProtector)
|
||||||
|
throws WrongPassphraseException {
|
||||||
|
super(SignatureType.PRIMARYKEY_BINDING, subkey, subkeyProtector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SelfSignatureSubpackets getHashedSubpackets() {
|
||||||
|
return hashedSubpackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SelfSignatureSubpackets getUnhashedSubpackets() {
|
||||||
|
return unhashedSubpackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isValidSignatureType(SignatureType type) {
|
||||||
|
return type == SignatureType.PRIMARYKEY_BINDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSignature build(PGPPublicKey primaryKey) throws PGPException {
|
||||||
|
return buildAndInitSignatureGenerator()
|
||||||
|
.generateCertification(primaryKey, publicSigningKey);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.signature.builder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
|
import org.pgpainless.algorithm.KeyFlag;
|
||||||
|
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
|
import org.pgpainless.signature.subpackets.BindingSignatureCallback;
|
||||||
|
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
|
||||||
|
|
||||||
|
public class SignatureBuilder {
|
||||||
|
|
||||||
|
public SubkeyBindingSignatureBuilder subkeyBindingSignatureBuilder(
|
||||||
|
PGPSecretKey primaryKey,
|
||||||
|
SecretKeyRingProtector primaryKeyProtector,
|
||||||
|
PGPSecretKey subkey,
|
||||||
|
SecretKeyRingProtector subkeyProtector,
|
||||||
|
@Nullable BindingSignatureCallback subkeyBindingSubpacketsCallback,
|
||||||
|
@Nullable BindingSignatureCallback primaryKeyBindingSubpacketsCallback,
|
||||||
|
KeyFlag... flags)
|
||||||
|
throws PGPException, IOException {
|
||||||
|
if (flags.length == 0) {
|
||||||
|
throw new IllegalArgumentException("Keyflags for subkey binding cannot be empty.");
|
||||||
|
}
|
||||||
|
SubkeyBindingSignatureBuilder subkeyBindingBuilder = new SubkeyBindingSignatureBuilder(primaryKey, primaryKeyProtector);
|
||||||
|
|
||||||
|
SelfSignatureSubpackets hashedSubpackets = subkeyBindingBuilder.getHashedSubpackets();
|
||||||
|
hashedSubpackets.setKeyFlags(flags);
|
||||||
|
|
||||||
|
boolean isSigningKey = false;
|
||||||
|
for (KeyFlag flag : flags) {
|
||||||
|
if (flag == KeyFlag.SIGN_DATA) {
|
||||||
|
isSigningKey = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isSigningKey) {
|
||||||
|
PGPSignature backsig = primaryKeyBindingSignature(
|
||||||
|
subkey, subkeyProtector, primaryKey.getPublicKey(), primaryKeyBindingSubpacketsCallback);
|
||||||
|
hashedSubpackets.addEmbeddedSignature(backsig);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subkeyBindingSubpacketsCallback != null) {
|
||||||
|
subkeyBindingSubpacketsCallback.modifyHashedSubpackets(subkeyBindingBuilder.getHashedSubpackets());
|
||||||
|
subkeyBindingSubpacketsCallback.modifyUnhashedSubpackets(subkeyBindingBuilder.getUnhashedSubpackets());
|
||||||
|
}
|
||||||
|
|
||||||
|
return subkeyBindingBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSignature primaryKeyBindingSignature(
|
||||||
|
PGPSecretKey subkey,
|
||||||
|
SecretKeyRingProtector subkeyProtector,
|
||||||
|
PGPPublicKey primaryKey,
|
||||||
|
BindingSignatureCallback primaryKeyBindingSubpacketsCallback) throws PGPException {
|
||||||
|
|
||||||
|
PrimaryKeyBindingSignatureBuilder builder = new PrimaryKeyBindingSignatureBuilder(subkey, subkeyProtector);
|
||||||
|
if (primaryKeyBindingSubpacketsCallback != null) {
|
||||||
|
primaryKeyBindingSubpacketsCallback.modifyHashedSubpackets(builder.getHashedSubpackets());
|
||||||
|
primaryKeyBindingSubpacketsCallback.modifyUnhashedSubpackets(builder.getUnhashedSubpackets());
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build(primaryKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,8 +15,9 @@ import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
|
||||||
|
|
||||||
public class SubkeyBindingSignatureBuilder extends AbstractSignatureBuilder<SubkeyBindingSignatureBuilder> {
|
public class SubkeyBindingSignatureBuilder extends AbstractSignatureBuilder<SubkeyBindingSignatureBuilder> {
|
||||||
|
|
||||||
public SubkeyBindingSignatureBuilder(SignatureType signatureType, PGPSecretKey signingKey, SecretKeyRingProtector protector) throws WrongPassphraseException {
|
public SubkeyBindingSignatureBuilder(PGPSecretKey signingKey, SecretKeyRingProtector protector)
|
||||||
super(signatureType, signingKey, protector);
|
throws WrongPassphraseException {
|
||||||
|
super(SignatureType.SUBKEY_BINDING, signingKey, protector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.signature.subpackets;
|
||||||
|
|
||||||
|
public interface BindingSignatureCallback {
|
||||||
|
|
||||||
|
void modifyHashedSubpackets(SelfSignatureSubpackets subpackets);
|
||||||
|
|
||||||
|
void modifyUnhashedSubpackets(SelfSignatureSubpackets subpackets);
|
||||||
|
}
|
|
@ -75,23 +75,44 @@ public class SignatureSubpacketGeneratorWrapper
|
||||||
private final List<SignatureSubpacket> unsupportedSubpackets = new ArrayList<>();
|
private final List<SignatureSubpacket> unsupportedSubpackets = new ArrayList<>();
|
||||||
|
|
||||||
public SignatureSubpacketGeneratorWrapper() {
|
public SignatureSubpacketGeneratorWrapper() {
|
||||||
setSignatureCreationTime(new Date());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SignatureSubpacketGeneratorWrapper(PGPPublicKey issuer) {
|
public static SignatureSubpacketGeneratorWrapper refreshHashedSubpackets(PGPPublicKey issuer, PGPSignature oldSignature) {
|
||||||
setSignatureCreationTime(new Date());
|
return createHashedSubpacketsFrom(issuer, oldSignature.getHashedSubPackets());
|
||||||
setIssuerFingerprintAndKeyId(issuer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SignatureSubpacketGeneratorWrapper(PGPPublicKey issuer, PGPSignatureSubpacketVector base) {
|
public static SignatureSubpacketGeneratorWrapper refreshUnhashedSubpackets(PGPSignature oldSignature) {
|
||||||
extractSubpacketsFromVector(base);
|
return createSubpacketsFrom(oldSignature.getUnhashedSubPackets());
|
||||||
setSignatureCreationTime(new Date());
|
|
||||||
setIssuerFingerprintAndKeyId(issuer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SignatureSubpacketGeneratorWrapper(PGPSignatureSubpacketVector base) {
|
public static SignatureSubpacketGeneratorWrapper createHashedSubpacketsFrom(PGPPublicKey issuer, PGPSignatureSubpacketVector base) {
|
||||||
extractSubpacketsFromVector(base);
|
SignatureSubpacketGeneratorWrapper wrapper = createSubpacketsFrom(base);
|
||||||
setSignatureCreationTime(new Date());
|
wrapper.setIssuerFingerprintAndKeyId(issuer);
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SignatureSubpacketGeneratorWrapper createSubpacketsFrom(PGPSignatureSubpacketVector base) {
|
||||||
|
SignatureSubpacketGeneratorWrapper wrapper = new SignatureSubpacketGeneratorWrapper();
|
||||||
|
wrapper.extractSubpacketsFromVector(base);
|
||||||
|
wrapper.setSignatureCreationTime(new Date());
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SignatureSubpacketGeneratorWrapper createEmptySubpackets() {
|
||||||
|
return new SignatureSubpacketGeneratorWrapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SignatureSubpacketGeneratorWrapper createHashedSubpackets() {
|
||||||
|
SignatureSubpacketGeneratorWrapper wrapper = new SignatureSubpacketGeneratorWrapper();
|
||||||
|
wrapper.setSignatureCreationTime(new Date());
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SignatureSubpacketGeneratorWrapper createHashedSubpackets(PGPPublicKey issuer) {
|
||||||
|
SignatureSubpacketGeneratorWrapper wrapper = createHashedSubpackets();
|
||||||
|
wrapper.setIssuerFingerprintAndKeyId(issuer);
|
||||||
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void extractSubpacketsFromVector(PGPSignatureSubpacketVector base) {
|
private void extractSubpacketsFromVector(PGPSignatureSubpacketVector base) {
|
||||||
|
|
|
@ -20,7 +20,6 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.pgpainless.PGPainless;
|
import org.pgpainless.PGPainless;
|
||||||
import org.pgpainless.algorithm.EncryptionPurpose;
|
import org.pgpainless.algorithm.EncryptionPurpose;
|
||||||
import org.pgpainless.algorithm.KeyFlag;
|
import org.pgpainless.algorithm.KeyFlag;
|
||||||
import org.pgpainless.algorithm.SignatureType;
|
|
||||||
import org.pgpainless.key.info.KeyRingInfo;
|
import org.pgpainless.key.info.KeyRingInfo;
|
||||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
import org.pgpainless.util.Passphrase;
|
import org.pgpainless.util.Passphrase;
|
||||||
|
@ -40,7 +39,7 @@ public class SubkeyBindingSignatureBuilderTest {
|
||||||
PGPPublicKey subkey = PGPainless.inspectKeyRing(tempSubkeyRing)
|
PGPPublicKey subkey = PGPainless.inspectKeyRing(tempSubkeyRing)
|
||||||
.getEncryptionSubkeys(EncryptionPurpose.STORAGE_AND_COMMUNICATIONS).get(0);
|
.getEncryptionSubkeys(EncryptionPurpose.STORAGE_AND_COMMUNICATIONS).get(0);
|
||||||
|
|
||||||
SubkeyBindingSignatureBuilder skbb = new SubkeyBindingSignatureBuilder(SignatureType.SUBKEY_BINDING, secretKey.getSecretKey(), protector);
|
SubkeyBindingSignatureBuilder skbb = new SubkeyBindingSignatureBuilder(secretKey.getSecretKey(), protector);
|
||||||
skbb.getHashedSubpackets().addNotationData(false, "testnotation@pgpainless.org", "hello-world");
|
skbb.getHashedSubpackets().addNotationData(false, "testnotation@pgpainless.org", "hello-world");
|
||||||
skbb.getHashedSubpackets().setKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE);
|
skbb.getHashedSubpackets().setKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE);
|
||||||
PGPSignature binding = skbb.build(subkey);
|
PGPSignature binding = skbb.build(subkey);
|
||||||
|
|
|
@ -69,13 +69,13 @@ public class SignatureSubpacketGeneratorWrapperTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void createWrapper() {
|
public void createWrapper() {
|
||||||
wrapper = new SignatureSubpacketGeneratorWrapper(key);
|
wrapper = SignatureSubpacketGeneratorWrapper.createHashedSubpackets(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void initialStateTest() {
|
public void initialStateTest() {
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
wrapper = new SignatureSubpacketGeneratorWrapper();
|
wrapper = SignatureSubpacketGeneratorWrapper.createHashedSubpackets();
|
||||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||||
|
|
||||||
assertEquals(now.getTime(), vector.getSignatureCreationTime().getTime(), 1000);
|
assertEquals(now.getTime(), vector.getSignatureCreationTime().getTime(), 1000);
|
||||||
|
|
Loading…
Reference in a new issue