mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-10 18:59:39 +02:00
Wip
This commit is contained in:
parent
25c95804ce
commit
176574df50
10 changed files with 238 additions and 374 deletions
|
@ -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()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class KeySpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
SignatureSubpackets getSubpacketGenerator() {
|
public SignatureSubpackets getSubpacketGenerator() {
|
||||||
return subpacketGenerator;
|
return subpacketGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue