mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-15 00:42:06 +01:00
When adding userId: Inherits common signature subpackets from primary userId
This commit is contained in:
parent
1b12cc1e09
commit
a4e244111c
5 changed files with 79 additions and 5 deletions
|
@ -4,6 +4,8 @@
|
|||
|
||||
package org.pgpainless.algorithm;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
@ -54,4 +56,14 @@ public enum CompressionAlgorithm {
|
|||
public int getAlgorithmId() {
|
||||
return algorithmId;
|
||||
}
|
||||
|
||||
public static int[] toAlgorithmIds(Collection<CompressionAlgorithm> algorithms) {
|
||||
int[] ids = new int[algorithms.size()];
|
||||
int i = 0;
|
||||
for (Iterator<CompressionAlgorithm> iterator = algorithms.iterator(); iterator.hasNext(); ) {
|
||||
int id = iterator.next().getAlgorithmId();
|
||||
ids[i++] = id;
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
package org.pgpainless.algorithm;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bouncycastle.bcpg.HashAlgorithmTags;
|
||||
|
@ -85,4 +87,14 @@ public enum HashAlgorithm {
|
|||
public String getAlgorithmName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static int[] toAlgorithmIds(Collection<HashAlgorithm> algorithms) {
|
||||
int[] ids = new int[algorithms.size()];
|
||||
int i = 0;
|
||||
for (Iterator<HashAlgorithm> iterator = algorithms.iterator(); iterator.hasNext(); ) {
|
||||
int id = iterator.next().getAlgorithmId();
|
||||
ids[i++] = id;
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
package org.pgpainless.algorithm;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
@ -124,4 +126,14 @@ public enum SymmetricKeyAlgorithm {
|
|||
public int getAlgorithmId() {
|
||||
return algorithmId;
|
||||
}
|
||||
|
||||
public static int[] toAlgorithmIds(Collection<SymmetricKeyAlgorithm> algorithms) {
|
||||
int[] ids = new int[algorithms.size()];
|
||||
int i = 0;
|
||||
for (Iterator<SymmetricKeyAlgorithm> iterator = algorithms.iterator(); iterator.hasNext(); ) {
|
||||
int id = iterator.next().getAlgorithmId();
|
||||
ids[i++] = id;
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,10 @@ import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
|||
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
|
||||
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.AlgorithmSuite;
|
||||
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||
import org.pgpainless.algorithm.Feature;
|
||||
import org.pgpainless.algorithm.HashAlgorithm;
|
||||
import org.pgpainless.algorithm.SignatureType;
|
||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||
|
@ -41,6 +45,7 @@ import org.pgpainless.implementation.ImplementationFactory;
|
|||
import org.pgpainless.key.OpenPgpFingerprint;
|
||||
import org.pgpainless.key.generation.KeyRingBuilder;
|
||||
import org.pgpainless.key.generation.KeySpec;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
import org.pgpainless.key.protection.CachingSecretKeyRingProtector;
|
||||
import org.pgpainless.key.protection.KeyRingProtectionSettings;
|
||||
import org.pgpainless.key.protection.PasswordBasedSecretKeyRingProtector;
|
||||
|
@ -82,7 +87,25 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
|
|||
PGPSecretKey primaryKey = secretKeyIterator.next();
|
||||
PGPPublicKey publicKey = primaryKey.getPublicKey();
|
||||
PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(primaryKey, secretKeyRingProtector);
|
||||
publicKey = addUserIdToPubKey(userId, privateKey, publicKey);
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing);
|
||||
PGPSignature primaryUserIdSignature = info.getLatestUserIdCertification(info.getPrimaryUserId());
|
||||
PGPSignatureSubpacketVector primaryHashedSubpackets = primaryUserIdSignature.getHashedSubPackets();
|
||||
|
||||
AlgorithmSuite algorithmSuite = AlgorithmSuite.getDefaultAlgorithmSuite();
|
||||
PGPSignatureSubpacketGenerator hashedSubpackets = new PGPSignatureSubpacketGenerator();
|
||||
hashedSubpackets.setIssuerKeyID(false, primaryKey.getKeyID());
|
||||
hashedSubpackets.setIssuerFingerprint(false, primaryKey);
|
||||
hashedSubpackets.setKeyFlags(true, primaryHashedSubpackets.getKeyFlags());
|
||||
hashedSubpackets.setPreferredCompressionAlgorithms(false,
|
||||
CompressionAlgorithm.toAlgorithmIds(algorithmSuite.getCompressionAlgorithms()));
|
||||
hashedSubpackets.setPreferredHashAlgorithms(false,
|
||||
HashAlgorithm.toAlgorithmIds(algorithmSuite.getHashAlgorithms()));
|
||||
hashedSubpackets.setPreferredSymmetricAlgorithms(false,
|
||||
SymmetricKeyAlgorithm.toAlgorithmIds(algorithmSuite.getSymmetricKeyAlgorithms()));
|
||||
hashedSubpackets.setFeature(false, Feature.MODIFICATION_DETECTION.getFeatureId());
|
||||
|
||||
publicKey = addUserIdToPubKey(userId, privateKey, publicKey, hashedSubpackets.generate(), null);
|
||||
primaryKey = PGPSecretKey.replacePublicKey(primaryKey, publicKey);
|
||||
|
||||
secretKeyList.add(primaryKey);
|
||||
|
@ -96,12 +119,19 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
|
|||
return this;
|
||||
}
|
||||
|
||||
private static PGPPublicKey addUserIdToPubKey(String userId, PGPPrivateKey privateKey, PGPPublicKey publicKey) throws PGPException {
|
||||
private static PGPPublicKey addUserIdToPubKey(String userId,
|
||||
PGPPrivateKey privateKey,
|
||||
PGPPublicKey publicKey,
|
||||
@Nullable PGPSignatureSubpacketVector hashedSubpackets,
|
||||
@Nullable PGPSignatureSubpacketVector unhashedSubpackets)
|
||||
throws PGPException {
|
||||
if (privateKey.getKeyID() != publicKey.getKeyID()) {
|
||||
throw new IllegalArgumentException("Key-ID mismatch!");
|
||||
}
|
||||
// Create signature with new user-id and add it to the public key
|
||||
PGPSignatureGenerator signatureGenerator = SignatureUtils.getSignatureGeneratorFor(publicKey);
|
||||
signatureGenerator.setHashedSubpackets(hashedSubpackets);
|
||||
signatureGenerator.setUnhashedSubpackets(unhashedSubpackets);
|
||||
signatureGenerator.init(SignatureType.POSITIVE_CERTIFICATION.getCode(), privateKey);
|
||||
|
||||
PGPSignature userIdSignature = signatureGenerator.generateCertification(userId, publicKey);
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.io.IOException;
|
|||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
|
@ -19,6 +20,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
|||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.KeyFlag;
|
||||
import org.pgpainless.implementation.ImplementationFactory;
|
||||
import org.pgpainless.key.TestKeys;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
|
@ -31,16 +33,20 @@ public class AddUserIdTest {
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("org.pgpainless.util.TestImplementationFactoryProvider#provideImplementationFactories")
|
||||
public void addUserIdToExistingKeyRing(ImplementationFactory implementationFactory) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, InterruptedException {
|
||||
|
||||
public void addUserIdToExistingKeyRing(ImplementationFactory implementationFactory) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException {
|
||||
ImplementationFactory.setFactoryImplementation(implementationFactory);
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("alice@wonderland.lit", "rabb1th0le");
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.simpleEcKeyRing("alice@wonderland.lit", "rabb1th0le");
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
Iterator<String> userIds = info.getValidUserIds().iterator();
|
||||
assertEquals("alice@wonderland.lit", userIds.next());
|
||||
assertFalse(userIds.hasNext());
|
||||
List<KeyFlag> primaryUserIdKeyFlags = info.getKeyFlagsOf(info.getPrimaryUserId());
|
||||
|
||||
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector.forKey(secretKeys, Passphrase.fromPassword("rabb1th0le"));
|
||||
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
|
||||
.forKey(secretKeys, Passphrase.fromPassword("rabb1th0le"));
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
.addUserId("cheshirecat@wonderland.lit", protector)
|
||||
.done();
|
||||
|
@ -50,6 +56,8 @@ public class AddUserIdTest {
|
|||
assertEquals("alice@wonderland.lit", userIds.next());
|
||||
assertEquals("cheshirecat@wonderland.lit", userIds.next());
|
||||
assertFalse(userIds.hasNext());
|
||||
info = PGPainless.inspectKeyRing(secretKeys);
|
||||
assertEquals(primaryUserIdKeyFlags, info.getKeyFlagsOf("cheshirecat@wonderland.lit"));
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
.revokeUserId("cheshirecat@wonderland.lit", protector)
|
||||
|
|
Loading…
Reference in a new issue