1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-10 18:59:39 +02:00
This commit is contained in:
Paul Schaub 2021-11-20 16:07:27 +01:00
parent 25c95804ce
commit 176574df50
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
10 changed files with 238 additions and 374 deletions

View file

@ -42,7 +42,6 @@ import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
import org.pgpainless.implementation.ImplementationFactory; import org.pgpainless.implementation.ImplementationFactory;
import org.pgpainless.key.generation.type.KeyType; import org.pgpainless.key.generation.type.KeyType;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnlockSecretKey; import org.pgpainless.key.protection.UnlockSecretKey;
import org.pgpainless.provider.ProviderFactory; import org.pgpainless.provider.ProviderFactory;
import org.pgpainless.signature.subpackets.SignatureSubpackets; import org.pgpainless.signature.subpackets.SignatureSubpackets;
@ -133,6 +132,8 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
PGPKeyPair certKey = generateKeyPair(primaryKeySpec); PGPKeyPair certKey = generateKeyPair(primaryKeySpec);
PGPContentSignerBuilder signer = buildContentSigner(certKey); PGPContentSignerBuilder signer = buildContentSigner(certKey);
PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(signer); PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(signer);
// Prepare primary user-id sig
SignatureSubpackets hashedSubPacketGenerator = primaryKeySpec.getSubpacketGenerator(); SignatureSubpackets hashedSubPacketGenerator = primaryKeySpec.getSubpacketGenerator();
hashedSubPacketGenerator.setPrimaryUserId(); hashedSubPacketGenerator.setPrimaryUserId();
if (expirationDate != null) { if (expirationDate != null) {
@ -142,9 +143,7 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
SignatureSubpacketsHelper.applyTo(hashedSubPacketGenerator, generator); SignatureSubpacketsHelper.applyTo(hashedSubPacketGenerator, generator);
PGPSignatureSubpacketVector hashedSubPackets = generator.generate(); PGPSignatureSubpacketVector hashedSubPackets = generator.generate();
// Generator which the user can get the key pair from
PGPKeyRingGenerator ringGenerator = buildRingGenerator(certKey, signer, keyFingerprintCalculator, hashedSubPackets, secretKeyEncryptor); PGPKeyRingGenerator ringGenerator = buildRingGenerator(certKey, signer, keyFingerprintCalculator, hashedSubPackets, secretKeyEncryptor);
addSubKeys(certKey, ringGenerator); addSubKeys(certKey, ringGenerator);
// Generate secret key ring with only primary user id // Generate secret key ring with only primary user id
@ -155,10 +154,10 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
// Attempt to add additional user-ids to the primary public key // Attempt to add additional user-ids to the primary public key
PGPPublicKey primaryPubKey = secretKeys.next().getPublicKey(); PGPPublicKey primaryPubKey = secretKeys.next().getPublicKey();
PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(secretKeyRing.getSecretKey(), secretKeyDecryptor); PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(secretKeyRing.getSecretKey(), secretKeyDecryptor);
Iterator<String> additionalUserIds = userIds.iterator(); Iterator<String> userIdIterator = this.userIds.iterator();
additionalUserIds.next(); // Skip primary user id userIdIterator.next(); // Skip primary user id
while (additionalUserIds.hasNext()) { while (userIdIterator.hasNext()) {
String additionalUserId = additionalUserIds.next(); String additionalUserId = userIdIterator.next();
signatureGenerator.init(SignatureType.POSITIVE_CERTIFICATION.getCode(), privateKey); signatureGenerator.init(SignatureType.POSITIVE_CERTIFICATION.getCode(), privateKey);
PGPSignature additionalUserIdSignature = PGPSignature additionalUserIdSignature =
signatureGenerator.generateCertification(additionalUserId, primaryPubKey); signatureGenerator.generateCertification(additionalUserId, primaryPubKey);
@ -175,7 +174,6 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
secretKeyList.add(secretKeys.next()); secretKeyList.add(secretKeys.next());
} }
secretKeyRing = new PGPSecretKeyRing(secretKeyList); secretKeyRing = new PGPSecretKeyRing(secretKeyList);
return secretKeyRing; return secretKeyRing;
} }
@ -266,31 +264,4 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
PGPKeyPair pgpKeyPair = ImplementationFactory.getInstance().getPGPKeyPair(type.getAlgorithm(), keyPair, new Date()); PGPKeyPair pgpKeyPair = ImplementationFactory.getInstance().getPGPKeyPair(type.getAlgorithm(), keyPair, new Date());
return pgpKeyPair; return pgpKeyPair;
} }
private static SecretKeyRingProtector protectorFromPassphrase(@Nonnull Passphrase passphrase, long keyId) {
if (!passphrase.isValid()) {
throw new IllegalStateException("Passphrase has been cleared.");
}
if (passphrase.isEmpty()) {
return SecretKeyRingProtector.unprotectedKeys();
} else {
return SecretKeyRingProtector.unlockSingleKeyWith(passphrase, keyId);
}
}
public static PGPSecretKey generatePGPSecretKey(KeySpec keySpec, @Nonnull Passphrase passphrase, boolean isPrimary)
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
PGPDigestCalculator keyFingerprintCalculator = ImplementationFactory.getInstance()
.getV4FingerprintCalculator();
PGPKeyPair keyPair = generateKeyPair(keySpec);
SecretKeyRingProtector protector = protectorFromPassphrase(passphrase, keyPair.getKeyID());
return new PGPSecretKey(
keyPair.getPrivateKey(),
keyPair.getPublicKey(),
keyFingerprintCalculator,
isPrimary,
protector.getEncryptor(keyPair.getKeyID()));
}
} }

View file

@ -47,7 +47,7 @@ public class KeySpec {
} }
@Nonnull @Nonnull
SignatureSubpackets getSubpacketGenerator() { public SignatureSubpackets getSubpacketGenerator() {
return subpacketGenerator; return subpacketGenerator;
} }

View file

@ -26,7 +26,6 @@ import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPKeyRingGenerator; import org.bouncycastle.openpgp.PGPKeyRingGenerator;
import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
@ -36,11 +35,12 @@ import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.HashAlgorithm;
import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.algorithm.PublicKeyAlgorithm; import org.pgpainless.algorithm.PublicKeyAlgorithm;
import org.pgpainless.algorithm.SignatureType; import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.algorithm.negotiation.HashAlgorithmNegotiator;
import org.pgpainless.implementation.ImplementationFactory; import org.pgpainless.implementation.ImplementationFactory;
import org.pgpainless.key.OpenPgpFingerprint; import org.pgpainless.key.OpenPgpFingerprint;
import org.pgpainless.key.generation.KeyRingBuilder; import org.pgpainless.key.generation.KeyRingBuilder;
@ -57,14 +57,14 @@ import org.pgpainless.key.protection.passphrase_provider.SolitaryPassphraseProvi
import org.pgpainless.key.util.KeyRingUtils; import org.pgpainless.key.util.KeyRingUtils;
import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.key.util.RevocationAttributes;
import org.pgpainless.signature.SignatureUtils; import org.pgpainless.signature.SignatureUtils;
import org.pgpainless.signature.builder.PrimaryKeyBindingSignatureBuilder;
import org.pgpainless.signature.builder.RevocationSignatureBuilder; import org.pgpainless.signature.builder.RevocationSignatureBuilder;
import org.pgpainless.signature.builder.SelfSignatureBuilder; import org.pgpainless.signature.builder.SelfSignatureBuilder;
import org.pgpainless.signature.builder.SignatureFactory; import org.pgpainless.signature.builder.SignatureFactory;
import org.pgpainless.signature.builder.SubkeyBindingSignatureBuilder;
import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets; import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets;
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets; import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorUtil; import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorUtil;
import org.pgpainless.signature.subpackets.SignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpacketsHelper;
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
import org.pgpainless.util.CollectionUtils; import org.pgpainless.util.CollectionUtils;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
@ -95,33 +95,21 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
SecretKeyRingProtector protector) throws PGPException { SecretKeyRingProtector protector) throws PGPException {
userId = sanitizeUserId(userId); userId = sanitizeUserId(userId);
List<PGPSecretKey> secretKeyList = new ArrayList<>(); // user-id certifications live on the primary key
Iterator<PGPSecretKey> secretKeyIterator = secretKeyRing.getSecretKeys(); PGPSecretKey primaryKey = secretKeyRing.getSecretKey();
// add user-id certificate to primary key // retain key flags from previous signature
PGPSecretKey primaryKey = secretKeyIterator.next();
PGPPublicKey publicKey = primaryKey.getPublicKey();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing); KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing);
List<KeyFlag> keyFlags = info.getKeyFlagsOf(info.getKeyId()); List<KeyFlag> keyFlags = info.getKeyFlagsOf(info.getKeyId());
SelfSignatureBuilder builder = SignatureFactory.selfCertifyUserId( SelfSignatureBuilder builder = SignatureFactory.selfCertifyUserId(
primaryKey, primaryKey,
protector, protector,
signatureSubpacketCallback, signatureSubpacketCallback,
keyFlags.toArray(new KeyFlag[0])); keyFlags);
builder.setSignatureType(SignatureType.POSITIVE_CERTIFICATION); builder.setSignatureType(SignatureType.POSITIVE_CERTIFICATION);
builder.applyCallback(signatureSubpacketCallback); PGPSignature signature = builder.build(primaryKey.getPublicKey(), userId);
PGPSignature signature = builder.build(publicKey, userId); secretKeyRing = KeyRingUtils.injectCertification(secretKeyRing, userId, signature);
publicKey = PGPPublicKey.addCertification(publicKey,
userId, signature);
primaryKey = PGPSecretKey.replacePublicKey(primaryKey, publicKey);
secretKeyList.add(primaryKey);
while (secretKeyIterator.hasNext()) {
secretKeyList.add(secretKeyIterator.next());
}
secretKeyRing = new PGPSecretKeyRing(secretKeyList);
return this; return this;
} }
@ -138,51 +126,30 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
public SecretKeyRingEditorInterface addSubKey(@Nonnull KeySpec keySpec, public SecretKeyRingEditorInterface addSubKey(@Nonnull KeySpec keySpec,
@Nonnull Passphrase subKeyPassphrase, @Nonnull Passphrase subKeyPassphrase,
SecretKeyRingProtector secretKeyRingProtector) SecretKeyRingProtector secretKeyRingProtector)
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException {
PGPKeyPair keyPair = KeyRingBuilder.generateKeyPair(keySpec);
PGPSecretKey secretSubKey = generateSubKey(keySpec, subKeyPassphrase);
SecretKeyRingProtector subKeyProtector = PasswordBasedSecretKeyRingProtector SecretKeyRingProtector subKeyProtector = PasswordBasedSecretKeyRingProtector
.forKey(secretSubKey, subKeyPassphrase); .forKeyId(keyPair.getKeyID(), subKeyPassphrase);
PGPSignatureSubpacketVector hashedSubpackets = keySpec.getSubpackets();
PGPSignatureSubpacketVector unhashedSubpackets = null;
return addSubKey(secretSubKey, hashedSubpackets, unhashedSubpackets, subKeyProtector, secretKeyRingProtector); SelfSignatureSubpackets.Callback callback = new SelfSignatureSubpackets.Callback() {
@Override
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
SignatureSubpacketsHelper.applyFrom(keySpec.getSubpackets(), (SignatureSubpackets) hashedSubpackets);
}
};
List<KeyFlag> keyFlags = KeyFlag.fromBitmask(keySpec.getSubpackets().getKeyFlags());
KeyFlag firstFlag = keyFlags.remove(0);
KeyFlag[] otherFlags = keyFlags.toArray(new KeyFlag[0]);
return addSubKey(keyPair, callback, subKeyProtector, secretKeyRingProtector, firstFlag, otherFlags);
} }
@Override @Override
@Deprecated public SecretKeyRingEditorInterface addSubKey(PGPKeyPair subkey,
public SecretKeyRingEditorInterface addSubKey(PGPSecretKey secretSubKey,
PGPSignatureSubpacketVector hashedSubpackets,
PGPSignatureSubpacketVector unhashedSubpackets,
SecretKeyRingProtector subKeyProtector,
SecretKeyRingProtector keyRingProtector)
throws PGPException {
PGPPublicKey primaryKey = secretKeyRing.getSecretKey().getPublicKey();
PBESecretKeyDecryptor ringDecryptor = keyRingProtector.getDecryptor(primaryKey.getKeyID());
PBESecretKeyEncryptor subKeyEncryptor = subKeyProtector.getEncryptor(secretSubKey.getKeyID());
PGPDigestCalculator digestCalculator = ImplementationFactory.getInstance().getV4FingerprintCalculator();
PGPContentSignerBuilder contentSignerBuilder =
SignatureUtils.getPgpContentSignerBuilderForKey(primaryKey);
PGPPrivateKey privateSubKey = UnlockSecretKey.unlockSecretKey(secretSubKey, subKeyProtector);
PGPKeyPair subKeyPair = new PGPKeyPair(secretSubKey.getPublicKey(), privateSubKey);
PGPKeyRingGenerator keyRingGenerator = new PGPKeyRingGenerator(
secretKeyRing, ringDecryptor, digestCalculator, contentSignerBuilder, subKeyEncryptor);
keyRingGenerator.addSubKey(subKeyPair, hashedSubpackets, unhashedSubpackets);
secretKeyRing = keyRingGenerator.generateSecretKeyRing();
return this;
}
@Override
public SecretKeyRingEditorInterface addSubKey(PGPSecretKey subkey,
@Nullable SelfSignatureSubpackets.Callback bindingSignatureCallback, @Nullable SelfSignatureSubpackets.Callback bindingSignatureCallback,
@Nullable SelfSignatureSubpackets.Callback backSignatureCallback,
SecretKeyRingProtector subkeyProtector, SecretKeyRingProtector subkeyProtector,
SecretKeyRingProtector primaryKeyProtector, SecretKeyRingProtector primaryKeyProtector,
KeyFlag keyFlag, KeyFlag keyFlag,
@ -193,36 +160,49 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
SignatureSubpacketsUtil.assureKeyCanCarryFlags(subkeyAlgorithm); SignatureSubpacketsUtil.assureKeyCanCarryFlags(subkeyAlgorithm);
PGPSecretKey primaryKey = secretKeyRing.getSecretKey(); PGPSecretKey primaryKey = secretKeyRing.getSecretKey();
SubkeyBindingSignatureBuilder bindingSigBuilder = KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing);
new SubkeyBindingSignatureBuilder(primaryKey, primaryKeyProtector); PublicKeyAlgorithm signingKeyAlgorithm = PublicKeyAlgorithm.fromId(primaryKey.getPublicKey().getAlgorithm());
HashAlgorithm hashAlgorithm = HashAlgorithmNegotiator
.negotiateSignatureHashAlgorithm(PGPainless.getPolicy())
.negotiateHashAlgorithm(info.getPreferredHashAlgorithms());
bindingSigBuilder.applyCallback(bindingSignatureCallback); // While we'd like to rely on our own BindingSignatureBuilder implementation,
bindingSigBuilder.getHashedSubpackets().setKeyFlags(flags); // unfortunately we have to use BCs PGPKeyRingGenerator class since there is no public constructor
// for subkeys. See https://github.com/bcgit/bc-java/pull/1063
PGPKeyRingGenerator ringGenerator = new PGPKeyRingGenerator(
secretKeyRing,
primaryKeyProtector.getDecryptor(primaryKey.getKeyID()),
ImplementationFactory.getInstance().getV4FingerprintCalculator(),
ImplementationFactory.getInstance().getPGPContentSignerBuilder(
signingKeyAlgorithm, hashAlgorithm),
subkeyProtector.getEncryptor(subkey.getKeyID()));
SelfSignatureSubpackets hashedSubpackets = SignatureSubpackets.createHashedSubpackets(primaryKey.getPublicKey());
SelfSignatureSubpackets unhashedSubpackets = SignatureSubpackets.createEmptySubpackets();
hashedSubpackets.setKeyFlags(flags);
if (bindingSignatureCallback != null) {
bindingSignatureCallback.modifyHashedSubpackets(hashedSubpackets);
bindingSignatureCallback.modifyUnhashedSubpackets(unhashedSubpackets);
}
boolean isSigningKey = CollectionUtils.contains(flags, KeyFlag.SIGN_DATA) || boolean isSigningKey = CollectionUtils.contains(flags, KeyFlag.SIGN_DATA) ||
CollectionUtils.contains(flags, KeyFlag.CERTIFY_OTHER); CollectionUtils.contains(flags, KeyFlag.CERTIFY_OTHER);
PGPContentSignerBuilder primaryKeyBindingSigner = null;
if (isSigningKey) { if (isSigningKey) {
// Add embedded back-signature made by subkey over primary key primaryKeyBindingSigner = ImplementationFactory.getInstance().getPGPContentSignerBuilder(subkeyAlgorithm, hashAlgorithm);
PrimaryKeyBindingSignatureBuilder backSigBuilder =
new PrimaryKeyBindingSignatureBuilder(subkey, subkeyProtector);
backSigBuilder.applyCallback(backSignatureCallback);
PGPSignature backSig = backSigBuilder.build(primaryKey.getPublicKey());
bindingSigBuilder.getHashedSubpackets().addEmbeddedSignature(backSig);
} }
PGPSignature bindingSig = bindingSigBuilder.build(subkey.getPublicKey()); ringGenerator.addSubKey(subkey,
subkey = KeyRingUtils.secretKeyPlusSignature(subkey, bindingSig); SignatureSubpacketsHelper.toVector((SignatureSubpackets) hashedSubpackets),
secretKeyRing = KeyRingUtils.secretKeysPlusSecretKey(secretKeyRing, subkey); SignatureSubpacketsHelper.toVector((SignatureSubpackets) unhashedSubpackets),
primaryKeyBindingSigner);
secretKeyRing = ringGenerator.generateSecretKeyRing();
return this; return this;
} }
private PGPSecretKey generateSubKey(@Nonnull KeySpec keySpec,
@Nonnull Passphrase subKeyPassphrase)
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
return KeyRingBuilder.generatePGPSecretKey(keySpec, subKeyPassphrase, false);
}
@Override @Override
public SecretKeyRingEditorInterface revoke(SecretKeyRingProtector secretKeyRingProtector, public SecretKeyRingEditorInterface revoke(SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
@ -252,15 +232,13 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
SecretKeyRingProtector secretKeyRingProtector, SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback subpacketsCallback) @Nullable RevocationSignatureSubpackets.Callback subpacketsCallback)
throws PGPException { throws PGPException {
// retrieve subkey to be revoked
PGPPublicKey revokeeSubKey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, keyID); PGPPublicKey revokeeSubKey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, keyID);
// create revocation
PGPSignature subKeyRevocation = generateRevocation(secretKeyRingProtector, revokeeSubKey, PGPSignature subKeyRevocation = generateRevocation(secretKeyRingProtector, revokeeSubKey,
subpacketsCallback); subpacketsCallback);
revokeeSubKey = PGPPublicKey.addCertification(revokeeSubKey, subKeyRevocation); // inject revocation sig into key ring
secretKeyRing = KeyRingUtils.injectCertification(secretKeyRing, revokeeSubKey, subKeyRevocation);
// Inject revoked public key into key ring
PGPPublicKeyRing publicKeyRing = KeyRingUtils.publicKeyRingFrom(secretKeyRing);
publicKeyRing = PGPPublicKeyRing.insertPublicKey(publicKeyRing, revokeeSubKey);
secretKeyRing = PGPSecretKeyRing.replacePublicKeys(secretKeyRing, publicKeyRing);
return this; return this;
} }
@ -285,6 +263,16 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
return generateRevocation(secretKeyRingProtector, revokeeSubkey, callback); return generateRevocation(secretKeyRingProtector, revokeeSubkey, callback);
} }
@Override
public PGPSignature createRevocationCertificate(
long subkeyId,
SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback certificateSubpacketsCallback)
throws PGPException {
PGPPublicKey revokeeSubkey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, subkeyId);
return generateRevocation(secretKeyRingProtector, revokeeSubkey, certificateSubpacketsCallback);
}
private PGPSignature generateRevocation(SecretKeyRingProtector protector, private PGPSignature generateRevocation(SecretKeyRingProtector protector,
PGPPublicKey revokeeSubKey, PGPPublicKey revokeeSubKey,
@Nullable RevocationSignatureSubpackets.Callback callback) @Nullable RevocationSignatureSubpackets.Callback callback)
@ -371,12 +359,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
signatureBuilder.applyCallback(callback); signatureBuilder.applyCallback(callback);
PGPSignature revocationSignature = signatureBuilder.build(userId); PGPSignature revocationSignature = signatureBuilder.build(userId);
primaryPublicKey = PGPPublicKey.addCertification(primaryPublicKey, userId, revocationSignature); secretKeyRing = KeyRingUtils.injectCertification(secretKeyRing, userId, revocationSignature);
PGPPublicKeyRing publicKeyRing = KeyRingUtils.publicKeyRingFrom(secretKeyRing);
publicKeyRing = PGPPublicKeyRing.insertPublicKey(publicKeyRing, primaryPublicKey);
secretKeyRing = PGPSecretKeyRing.replacePublicKeys(secretKeyRing, publicKeyRing);
return this; return this;
} }

View file

@ -12,10 +12,9 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.key.OpenPgpFingerprint; import org.pgpainless.key.OpenPgpFingerprint;
import org.pgpainless.key.generation.KeySpec; import org.pgpainless.key.generation.KeySpec;
@ -66,18 +65,10 @@ public interface SecretKeyRingEditorInterface {
SecretKeyRingEditorInterface addSubKey(@Nonnull KeySpec keySpec, SecretKeyRingEditorInterface addSubKey(@Nonnull KeySpec keySpec,
@Nullable Passphrase subKeyPassphrase, @Nullable Passphrase subKeyPassphrase,
SecretKeyRingProtector secretKeyRingProtector) SecretKeyRingProtector secretKeyRingProtector)
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException; throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException;
@Deprecated SecretKeyRingEditorInterface addSubKey(PGPKeyPair subkey,
SecretKeyRingEditorInterface addSubKey(PGPSecretKey subKey,
PGPSignatureSubpacketVector hashedSubpackets,
PGPSignatureSubpacketVector unhashedSubpackets,
SecretKeyRingProtector subKeyProtector, SecretKeyRingProtector keyRingProtector)
throws PGPException;
SecretKeyRingEditorInterface addSubKey(PGPSecretKey subkey,
@Nullable SelfSignatureSubpackets.Callback bindingSignatureCallback, @Nullable SelfSignatureSubpackets.Callback bindingSignatureCallback,
@Nullable SelfSignatureSubpackets.Callback backSignatureCallback,
SecretKeyRingProtector subkeyProtector, SecretKeyRingProtector subkeyProtector,
SecretKeyRingProtector primaryKeyProtector, SecretKeyRingProtector primaryKeyProtector,
KeyFlag keyFlag, KeyFlag keyFlag,
@ -244,17 +235,22 @@ public interface SecretKeyRingEditorInterface {
* @return revocation certificate * @return revocation certificate
*/ */
PGPSignature createRevocationCertificate(SecretKeyRingProtector secretKeyRingProtector, PGPSignature createRevocationCertificate(SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException; throws PGPException;
PGPSignature createRevocationCertificate(long subkeyId, PGPSignature createRevocationCertificate(long subkeyId,
SecretKeyRingProtector secretKeyRingProtector, SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException;
PGPSignature createRevocationCertificate(long subkeyId,
SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback certificateSubpacketsCallback)
throws PGPException; throws PGPException;
default PGPSignature createRevocationCertificate(OpenPgpFingerprint subkeyFingerprint, default PGPSignature createRevocationCertificate(OpenPgpFingerprint subkeyFingerprint,
SecretKeyRingProtector secretKeyRingProtector, SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException { throws PGPException {
return createRevocationCertificate(subkeyFingerprint.getKeyId(), secretKeyRingProtector, revocationAttributes); return createRevocationCertificate(subkeyFingerprint.getKeyId(), secretKeyRingProtector, revocationAttributes);
} }

View file

@ -22,9 +22,10 @@ import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector;
import org.pgpainless.PGPainless;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnlockSecretKey; import org.pgpainless.key.protection.UnlockSecretKey;
import org.pgpainless.util.CollectionUtils;
public final class KeyRingUtils { public final class KeyRingUtils {
@ -203,22 +204,121 @@ public final class KeyRingUtils {
return publicKeys; return publicKeys;
} }
public static PGPSecretKeyRing secretKeysPlusPublicKey(PGPSecretKeyRing secretKeys, PGPPublicKey subkey) { public static <T extends PGPKeyRing> T injectCertification(T keyRing, PGPPublicKey certifiedKey, PGPSignature certification) {
PGPPublicKeyRing publicKeys = publicKeyRingFrom(secretKeys); PGPSecretKeyRing secretKeys = null;
PGPPublicKeyRing newPublicKeys = publicKeysPlusPublicKey(publicKeys, subkey); PGPPublicKeyRing publicKeys;
PGPSecretKeyRing newSecretKeys = PGPSecretKeyRing.replacePublicKeys(secretKeys, newPublicKeys); if (keyRing instanceof PGPSecretKeyRing) {
return newSecretKeys; secretKeys = (PGPSecretKeyRing) keyRing;
publicKeys = PGPainless.extractCertificate(secretKeys);
} else {
publicKeys = (PGPPublicKeyRing) keyRing;
} }
public static PGPPublicKeyRing publicKeysPlusPublicKey(PGPPublicKeyRing publicKeys, PGPPublicKey subkey) { certifiedKey = PGPPublicKey.addCertification(certifiedKey, certification);
List<PGPPublicKey> publicKeyList = CollectionUtils.iteratorToList(publicKeys.getPublicKeys()); List<PGPPublicKey> publicKeyList = new ArrayList<>();
publicKeyList.add(subkey); Iterator<PGPPublicKey> publicKeyIterator = publicKeys.iterator();
PGPPublicKeyRing newPublicKeys = new PGPPublicKeyRing(publicKeyList); boolean added = false;
return newPublicKeys; while (publicKeyIterator.hasNext()) {
PGPPublicKey key = publicKeyIterator.next();
if (key.getKeyID() == certifiedKey.getKeyID()) {
added = true;
publicKeyList.add(certifiedKey);
} else {
publicKeyList.add(key);
}
}
if (!added) {
throw new NoSuchElementException("Cannot find public key with id " + Long.toHexString(certifiedKey.getKeyID()) + " in the provided key ring.");
} }
public static PGPSecretKeyRing secretKeysPlusSecretKey(PGPSecretKeyRing secretKeys, PGPSecretKey subkey) { publicKeys = new PGPPublicKeyRing(publicKeyList);
return PGPSecretKeyRing.insertSecretKey(secretKeys, subkey); if (secretKeys == null) {
return (T) publicKeys;
} else {
secretKeys = PGPSecretKeyRing.replacePublicKeys(secretKeys, publicKeys);
return (T) secretKeys;
}
}
public static <T extends PGPKeyRing> T injectCertification(T keyRing, String userId, PGPSignature certification) {
PGPSecretKeyRing secretKeys = null;
PGPPublicKeyRing publicKeys;
if (keyRing instanceof PGPSecretKeyRing) {
secretKeys = (PGPSecretKeyRing) keyRing;
publicKeys = PGPainless.extractCertificate(secretKeys);
} else {
publicKeys = (PGPPublicKeyRing) keyRing;
}
Iterator<PGPPublicKey> publicKeyIterator = publicKeys.iterator();
PGPPublicKey primaryKey = publicKeyIterator.next();
primaryKey = PGPPublicKey.addCertification(primaryKey, userId, certification);
List<PGPPublicKey> publicKeyList = new ArrayList<>();
publicKeyList.add(primaryKey);
while (publicKeyIterator.hasNext()) {
publicKeyList.add(publicKeyIterator.next());
}
publicKeys = new PGPPublicKeyRing(publicKeyList);
if (secretKeys == null) {
return (T) publicKeys;
} else {
secretKeys = PGPSecretKeyRing.replacePublicKeys(secretKeys, publicKeys);
return (T) secretKeys;
}
}
public static <T extends PGPKeyRing> T injectCertification(T keyRing, PGPUserAttributeSubpacketVector userAttributes, PGPSignature certification) {
PGPSecretKeyRing secretKeys = null;
PGPPublicKeyRing publicKeys;
if (keyRing instanceof PGPSecretKeyRing) {
secretKeys = (PGPSecretKeyRing) keyRing;
publicKeys = PGPainless.extractCertificate(secretKeys);
} else {
publicKeys = (PGPPublicKeyRing) keyRing;
}
Iterator<PGPPublicKey> publicKeyIterator = publicKeys.iterator();
PGPPublicKey primaryKey = publicKeyIterator.next();
primaryKey = PGPPublicKey.addCertification(primaryKey, userAttributes, certification);
List<PGPPublicKey> publicKeyList = new ArrayList<>();
publicKeyList.add(primaryKey);
while (publicKeyIterator.hasNext()) {
publicKeyList.add(publicKeyIterator.next());
}
publicKeys = new PGPPublicKeyRing(publicKeyList);
if (secretKeys == null) {
return (T) publicKeys;
} else {
secretKeys = PGPSecretKeyRing.replacePublicKeys(secretKeys, publicKeys);
return (T) secretKeys;
}
}
public static <T extends PGPKeyRing> T keysPlusPublicKey(T keyRing, PGPPublicKey publicKey) {
PGPSecretKeyRing secretKeys = null;
PGPPublicKeyRing publicKeys;
if (keyRing instanceof PGPSecretKeyRing) {
secretKeys = (PGPSecretKeyRing) keyRing;
publicKeys = PGPainless.extractCertificate(secretKeys);
} else {
publicKeys = (PGPPublicKeyRing) keyRing;
}
publicKeys = PGPPublicKeyRing.insertPublicKey(publicKeys, publicKey);
if (secretKeys == null) {
return (T) publicKeys;
} else {
secretKeys = PGPSecretKeyRing.replacePublicKeys(secretKeys, publicKeys);
return (T) secretKeys;
}
}
public static PGPSecretKeyRing keysPlusSecretKey(PGPSecretKeyRing secretKeys, PGPSecretKey secretKey) {
return PGPSecretKeyRing.insertSecretKey(secretKeys, secretKey);
} }
public static PGPSecretKey secretKeyPlusSignature(PGPSecretKey secretKey, PGPSignature signature) { public static PGPSecretKey secretKeyPlusSignature(PGPSecretKey secretKey, PGPSignature signature) {
@ -227,4 +327,5 @@ public final class KeyRingUtils {
PGPSecretKey newSecretKey = PGPSecretKey.replacePublicKey(secretKey, publicKey); PGPSecretKey newSecretKey = PGPSecretKey.replacePublicKey(secretKey, publicKey);
return newSecretKey; return newSecretKey;
} }
} }

View file

@ -4,18 +4,14 @@
package org.pgpainless.signature.builder; package org.pgpainless.signature.builder;
import java.io.IOException; import java.util.List;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.algorithm.SignatureType; import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.exception.WrongPassphraseException; import org.pgpainless.exception.WrongPassphraseException;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.subpackets.BaseSignatureSubpackets;
import org.pgpainless.signature.subpackets.CertificationSubpackets;
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets; import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
public final class SignatureFactory { public final class SignatureFactory {
@ -24,66 +20,14 @@ public final class SignatureFactory {
} }
public static SubkeyBindingSignatureBuilder bindNonSigningSubkey( public static SelfSignatureBuilder selfCertifyUserId(
PGPSecretKey primaryKey, PGPSecretKey primaryKey,
SecretKeyRingProtector primaryKeyProtector, SecretKeyRingProtector primaryKeyProtector,
@Nullable SelfSignatureSubpackets.Callback subkeyBindingSubpacketsCallback, @Nullable SelfSignatureSubpackets.Callback selfSignatureCallback,
KeyFlag... flags) throws WrongPassphraseException { List<KeyFlag> keyFlags)
if (hasSignDataFlag(flags)) { throws WrongPassphraseException {
throw new IllegalArgumentException("Binding a subkey with SIGN_DATA flag requires primary key backsig.\n" + KeyFlag[] keyFlagArray = keyFlags.toArray(new KeyFlag[0]);
"Please use the method bindSigningSubkey() instead."); return selfCertifyUserId(primaryKey, primaryKeyProtector, selfSignatureCallback, keyFlagArray);
}
return bindSubkey(primaryKey, primaryKeyProtector, subkeyBindingSubpacketsCallback, flags);
}
public static SubkeyBindingSignatureBuilder bindSigningSubkey(
PGPSecretKey primaryKey,
SecretKeyRingProtector primaryKeyProtector,
PGPSecretKey subkey,
SecretKeyRingProtector subkeyProtector,
@Nullable SelfSignatureSubpackets.Callback subkeyBindingSubpacketsCallback,
@Nullable SelfSignatureSubpackets.Callback primaryKeyBindingSubpacketsCallback,
KeyFlag... flags)
throws PGPException, IOException {
SubkeyBindingSignatureBuilder subkeyBinder = bindSubkey(primaryKey, primaryKeyProtector, subkeyBindingSubpacketsCallback, flags);
if (hasSignDataFlag(flags)) {
PGPSignature backsig = bindPrimaryKey(
subkey, subkeyProtector, primaryKeyBindingSubpacketsCallback)
.build(primaryKey.getPublicKey());
subkeyBinder.getHashedSubpackets().addEmbeddedSignature(backsig);
}
return subkeyBinder;
}
private static SubkeyBindingSignatureBuilder bindSubkey(PGPSecretKey primaryKey,
SecretKeyRingProtector primaryKeyProtector,
@Nullable SelfSignatureSubpackets.Callback subkeyBindingSubpacketsCallback,
KeyFlag... flags) throws WrongPassphraseException {
if (flags.length == 0) {
throw new IllegalArgumentException("Keyflags for subkey binding cannot be empty.");
}
SubkeyBindingSignatureBuilder subkeyBinder = new SubkeyBindingSignatureBuilder(primaryKey, primaryKeyProtector);
SelfSignatureSubpackets hashedSubpackets = subkeyBinder.getHashedSubpackets();
hashedSubpackets.setKeyFlags(flags);
subkeyBinder.applyCallback(subkeyBindingSubpacketsCallback);
return subkeyBinder;
}
public static PrimaryKeyBindingSignatureBuilder bindPrimaryKey(
PGPSecretKey subkey,
SecretKeyRingProtector subkeyProtector,
@Nullable SelfSignatureSubpackets.Callback primaryKeyBindingSubpacketsCallback) throws WrongPassphraseException {
PrimaryKeyBindingSignatureBuilder primaryKeyBinder = new PrimaryKeyBindingSignatureBuilder(subkey, subkeyProtector);
primaryKeyBinder.applyCallback(primaryKeyBindingSubpacketsCallback);
return primaryKeyBinder;
} }
public static SelfSignatureBuilder selfCertifyUserId( public static SelfSignatureBuilder selfCertifyUserId(
@ -100,55 +44,4 @@ public final class SignatureFactory {
return certifier; return certifier;
} }
public static SelfSignatureBuilder renewSelfCertification(
PGPSecretKey primaryKey,
SecretKeyRingProtector primaryKeyProtector,
@Nullable SelfSignatureSubpackets.Callback selfSignatureCallback,
PGPSignature oldCertification) throws WrongPassphraseException {
SelfSignatureBuilder certifier = new SelfSignatureBuilder(
primaryKey, primaryKeyProtector, oldCertification);
certifier.applyCallback(selfSignatureCallback);
return certifier;
}
public static CertificationSignatureBuilder certifyUserId(
PGPSecretKey signingKey,
SecretKeyRingProtector signingKeyProtector,
@Nullable CertificationSubpackets.Callback subpacketsCallback)
throws WrongPassphraseException {
CertificationSignatureBuilder certifier = new CertificationSignatureBuilder(signingKey, signingKeyProtector);
certifier.applyCallback(subpacketsCallback);
return certifier;
}
public static UniversalSignatureBuilder universalSignature(
SignatureType signatureType,
PGPSecretKey signingKey,
SecretKeyRingProtector signingKeyProtector,
@Nullable BaseSignatureSubpackets.Callback callback)
throws WrongPassphraseException {
UniversalSignatureBuilder builder =
new UniversalSignatureBuilder(signatureType, signingKey, signingKeyProtector);
builder.applyCallback(callback);
return builder;
}
private static boolean hasSignDataFlag(KeyFlag... flags) {
if (flags == null) {
return false;
}
for (KeyFlag flag : flags) {
if (flag == KeyFlag.SIGN_DATA) {
return true;
}
}
return false;
}
} }

View file

@ -170,7 +170,7 @@ public class ModifyKeys {
* @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException
*/ */
@Test @Test
public void addSubkey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { public void addSubkey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
// Protector for unlocking the existing secret key // Protector for unlocking the existing secret key
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAllKeysWith(Passphrase.fromPassword(originalPassphrase), secretKey); SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAllKeysWith(Passphrase.fromPassword(originalPassphrase), secretKey);
Passphrase subkeyPassphrase = Passphrase.fromPassword("subk3yP4ssphr4s3"); Passphrase subkeyPassphrase = Passphrase.fromPassword("subk3yP4ssphr4s3");

View file

@ -16,28 +16,28 @@ import java.util.List;
import org.bouncycastle.bcpg.sig.NotationData; import org.bouncycastle.bcpg.sig.NotationData;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.junit.JUtils; import org.junit.JUtils;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.EncryptionPurpose;
import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.key.OpenPgpV4Fingerprint; import org.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.key.generation.KeyRingBuilder; import org.pgpainless.key.generation.KeyRingBuilder;
import org.pgpainless.key.generation.KeySpec; import org.pgpainless.key.generation.KeySpec;
import org.pgpainless.key.generation.type.KeyType; import org.pgpainless.key.generation.type.KeyType;
import org.pgpainless.key.generation.type.xdh.XDHSpec; import org.pgpainless.key.generation.type.eddsa.EdDSACurve;
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.signature.subpackets.SelfSignatureSubpackets; import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
import org.pgpainless.util.Passphrase;
public class AddSubkeyWithModifiedBindingSignatureSubpackets { public class AddSubkeyWithModifiedBindingSignatureSubpackets {
public static long MILLIS_IN_SEC = 1000;
@Test @Test
public void bindEncryptionSubkeyAndModifyBindingSignatureHashedSubpackets() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException { public void bindEncryptionSubkeyAndModifyBindingSignatureHashedSubpackets() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
@ -45,29 +45,30 @@ public class AddSubkeyWithModifiedBindingSignatureSubpackets {
.modernKeyRing("Alice <alice@pgpainless.org>", null); .modernKeyRing("Alice <alice@pgpainless.org>", null);
KeyRingInfo before = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo before = PGPainless.inspectKeyRing(secretKeys);
PGPSecretKey secretSubkey = KeyRingBuilder.generatePGPSecretKey( PGPKeyPair secretSubkey = KeyRingBuilder.generateKeyPair(
KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_COMMS).build(), KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.SIGN_DATA).build());
Passphrase.emptyPassphrase(), false);
long secondsUntilExpiration = 1000;
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = PGPainless.modifyKeyRing(secretKeys)
.addSubKey(secretSubkey, new SelfSignatureSubpackets.Callback() { .addSubKey(secretSubkey, new SelfSignatureSubpackets.Callback() {
@Override @Override
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) { public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
hashedSubpackets.setKeyExpirationTime(true, 1000); hashedSubpackets.setKeyExpirationTime(true, secondsUntilExpiration);
hashedSubpackets.addNotationData(false, "test@test.test", "test"); hashedSubpackets.addNotationData(false, "test@test.test", "test");
} }
}, null, SecretKeyRingProtector.unprotectedKeys(), protector, KeyFlag.ENCRYPT_COMMS) }, SecretKeyRingProtector.unprotectedKeys(), protector, KeyFlag.SIGN_DATA)
.done(); .done();
KeyRingInfo after = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo after = PGPainless.inspectKeyRing(secretKeys);
List<PGPPublicKey> signingKeys = after.getSigningSubkeys();
signingKeys.removeAll(before.getSigningSubkeys());
assertFalse(signingKeys.isEmpty());
List<PGPPublicKey> encryptionKeys = after.getEncryptionSubkeys(EncryptionPurpose.COMMUNICATIONS); PGPPublicKey newKey = signingKeys.get(0);
encryptionKeys.removeAll(before.getEncryptionSubkeys(EncryptionPurpose.COMMUNICATIONS)); Date now = new Date();
assertFalse(encryptionKeys.isEmpty()); JUtils.assertEquals(
assertEquals(1, encryptionKeys.size()); now.getTime() + MILLIS_IN_SEC * secondsUntilExpiration,
after.getSubkeyExpirationDate(new OpenPgpV4Fingerprint(newKey)).getTime(), 2 * MILLIS_IN_SEC);
PGPPublicKey newKey = encryptionKeys.get(0);
JUtils.assertEquals(new Date().getTime() + 1000 * 1000, after.getSubkeyExpirationDate(new OpenPgpV4Fingerprint(newKey)).getTime(), 2000);
assertTrue(newKey.getSignatures().hasNext()); assertTrue(newKey.getSignatures().hasNext());
PGPSignature binding = newKey.getSignatures().next(); PGPSignature binding = newKey.getSignatures().next();
List<NotationData> notations = SignatureSubpacketsUtil.getHashedNotationData(binding); List<NotationData> notations = SignatureSubpacketsUtil.getHashedNotationData(binding);

View file

@ -39,7 +39,6 @@ import org.pgpainless.key.util.RevocationAttributes;
import org.pgpainless.signature.SignatureUtils; import org.pgpainless.signature.SignatureUtils;
import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets; import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
import org.pgpainless.util.ArmorUtils;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
public class RevokeSubKeyTest { public class RevokeSubKeyTest {
@ -82,11 +81,6 @@ public class RevokeSubKeyTest {
.withReason(RevocationAttributes.Reason.KEY_RETIRED) .withReason(RevocationAttributes.Reason.KEY_RETIRED)
.withDescription("Key no longer used.")); .withDescription("Key no longer used."));
// CHECKSTYLE:OFF
System.out.println("Revocation Certificate:");
System.out.println(ArmorUtils.toAsciiArmoredString(revocationCertificate.getEncoded()));
// CHECKSTYLE:ON
PGPPublicKey publicKey = secretKeys.getPublicKey(); PGPPublicKey publicKey = secretKeys.getPublicKey();
assertFalse(publicKey.hasRevocation()); assertFalse(publicKey.hasRevocation());
@ -107,8 +101,8 @@ public class RevokeSubKeyTest {
.forKey(secretKeys, Passphrase.fromPassword("password123")); .forKey(secretKeys, Passphrase.fromPassword("password123"));
SecretKeyRingEditorInterface editor = PGPainless.modifyKeyRing(secretKeys); SecretKeyRingEditorInterface editor = PGPainless.modifyKeyRing(secretKeys);
PGPSignature keyRevocation = editor.createRevocationCertificate(primaryKey.getKeyID(), protector, null); PGPSignature keyRevocation = editor.createRevocationCertificate(primaryKey.getKeyID(), protector, (RevocationAttributes) null);
PGPSignature subkeyRevocation = editor.createRevocationCertificate(subKey.getKeyID(), protector, null); PGPSignature subkeyRevocation = editor.createRevocationCertificate(subKey.getKeyID(), protector, (RevocationAttributes) null);
assertEquals(SignatureType.KEY_REVOCATION.getCode(), keyRevocation.getSignatureType()); assertEquals(SignatureType.KEY_REVOCATION.getCode(), keyRevocation.getSignatureType());
assertEquals(SignatureType.SUBKEY_REVOCATION.getCode(), subkeyRevocation.getSignatureType()); assertEquals(SignatureType.SUBKEY_REVOCATION.getCode(), subkeyRevocation.getSignatureType());

View file

@ -1,75 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.List;
import org.bouncycastle.bcpg.sig.NotationData;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.EncryptionPurpose;
import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.key.info.KeyRingInfo;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
import org.pgpainless.util.Passphrase;
public class SubkeyBindingSignatureBuilderTest {
@Test
public void testBindSubkeyWithCustomNotation() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
.modernKeyRing("Alice <alice@pgpainless.org>", "passphrase");
KeyRingInfo info = PGPainless.inspectKeyRing(secretKey);
List<PGPPublicKey> previousSubkeys = info.getEncryptionSubkeys(EncryptionPurpose.ANY);
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAllKeysWith(Passphrase.fromPassword("passphrase"), secretKey);
PGPSecretKeyRing tempSubkeyRing = PGPainless.generateKeyRing()
.modernKeyRing("Subkeys", null);
PGPPublicKey subkeyPub = PGPainless.inspectKeyRing(tempSubkeyRing)
.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0);
PGPSecretKey subkeySec = tempSubkeyRing.getSecretKey(subkeyPub.getKeyID());
PGPSignature binding = SignatureFactory.bindNonSigningSubkey(
secretKey.getSecretKey(), protector,
new SelfSignatureSubpackets.Callback() {
@Override
public void modifyHashedSubpackets(SelfSignatureSubpackets subpackets) {
subpackets.addNotationData(false, "testnotation@pgpainless.org", "hello-world");
}
}, KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
.build(subkeyPub);
subkeyPub = PGPPublicKey.addCertification(subkeyPub, binding);
subkeySec = PGPSecretKey.replacePublicKey(subkeySec, subkeyPub);
secretKey = PGPSecretKeyRing.insertSecretKey(secretKey, subkeySec);
info = PGPainless.inspectKeyRing(secretKey);
List<PGPPublicKey> nextSubkeys = info.getEncryptionSubkeys(EncryptionPurpose.ANY);
assertEquals(previousSubkeys.size() + 1, nextSubkeys.size());
subkeyPub = secretKey.getPublicKey(subkeyPub.getKeyID());
Iterator<PGPSignature> newBindingSigs = subkeyPub.getSignaturesForKeyID(secretKey.getPublicKey().getKeyID());
PGPSignature bindingSig = newBindingSigs.next();
assertNotNull(bindingSig);
List<NotationData> notations = SignatureSubpacketsUtil.getHashedNotationData(bindingSig);
assertEquals(1, notations.size());
assertEquals("testnotation@pgpainless.org", notations.get(0).getNotationName());
assertEquals("hello-world", notations.get(0).getNotationValue());
}
}