1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-11-23 04:42:06 +01:00

Wip: Add test for signature structure, set fingerprint on primary user-id self sig

This commit is contained in:
Paul Schaub 2021-11-20 21:12:12 +01:00
parent 76e19359b4
commit 6a137698c4
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
2 changed files with 77 additions and 16 deletions

View file

@ -14,10 +14,11 @@ import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Map;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bouncycastle.bcpg.sig.KeyFlags; import org.bouncycastle.bcpg.sig.KeyFlags;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
@ -44,6 +45,7 @@ import org.pgpainless.implementation.ImplementationFactory;
import org.pgpainless.key.generation.type.KeyType; import org.pgpainless.key.generation.type.KeyType;
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.SelfSignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpackets; import org.pgpainless.signature.subpackets.SignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpacketsHelper; import org.pgpainless.signature.subpackets.SignatureSubpacketsHelper;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
@ -54,7 +56,7 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
private KeySpec primaryKeySpec; private KeySpec primaryKeySpec;
private final List<KeySpec> subkeySpecs = new ArrayList<>(); private final List<KeySpec> subkeySpecs = new ArrayList<>();
private final Set<String> userIds = new LinkedHashSet<>(); private final Map<String, SelfSignatureSubpackets.Callback> userIds = new LinkedHashMap<>();
private Passphrase passphrase = Passphrase.emptyPassphrase(); private Passphrase passphrase = Passphrase.emptyPassphrase();
private Date expirationDate = null; private Date expirationDate = null;
@ -73,7 +75,14 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
@Override @Override
public KeyRingBuilder addUserId(@Nonnull String userId) { public KeyRingBuilder addUserId(@Nonnull String userId) {
this.userIds.add(userId.trim()); this.userIds.put(userId.trim(), null);
return this;
}
public KeyRingBuilder addUserId(
@Nonnull String userId,
@Nullable SelfSignatureSubpackets.Callback subpacketsCallback) {
this.userIds.put(userId.trim(), subpacketsCallback);
return this; return this;
} }
@ -135,6 +144,7 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
// Prepare primary user-id sig // Prepare primary user-id sig
SignatureSubpackets hashedSubPacketGenerator = primaryKeySpec.getSubpacketGenerator(); SignatureSubpackets hashedSubPacketGenerator = primaryKeySpec.getSubpacketGenerator();
hashedSubPacketGenerator.setIssuerFingerprintAndKeyId(certKey.getPublicKey());
hashedSubPacketGenerator.setPrimaryUserId(); hashedSubPacketGenerator.setPrimaryUserId();
if (expirationDate != null) { if (expirationDate != null) {
hashedSubPacketGenerator.setKeyExpirationTime(certKey.getPublicKey(), expirationDate); hashedSubPacketGenerator.setKeyExpirationTime(certKey.getPublicKey(), expirationDate);
@ -143,7 +153,8 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
SignatureSubpacketsHelper.applyTo(hashedSubPacketGenerator, generator); SignatureSubpacketsHelper.applyTo(hashedSubPacketGenerator, generator);
PGPSignatureSubpacketVector hashedSubPackets = generator.generate(); PGPSignatureSubpacketVector hashedSubPackets = generator.generate();
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
@ -154,15 +165,27 @@ 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> userIdIterator = this.userIds.iterator(); Iterator<Map.Entry<String, SelfSignatureSubpackets.Callback>> userIdIterator =
this.userIds.entrySet().iterator();
userIdIterator.next(); // Skip primary user id userIdIterator.next(); // Skip primary user id
while (userIdIterator.hasNext()) { while (userIdIterator.hasNext()) {
String additionalUserId = userIdIterator.next(); Map.Entry<String, SelfSignatureSubpackets.Callback> additionalUserId = userIdIterator.next();
String userIdString = additionalUserId.getKey();
SelfSignatureSubpackets.Callback callback = additionalUserId.getValue();
SelfSignatureSubpackets subpackets = null;
if (callback == null) {
subpackets = hashedSubPacketGenerator;
} else {
subpackets = SignatureSubpackets.createHashedSubpackets(primaryPubKey);
callback.modifyHashedSubpackets(subpackets);
}
signatureGenerator.init(SignatureType.POSITIVE_CERTIFICATION.getCode(), privateKey); signatureGenerator.init(SignatureType.POSITIVE_CERTIFICATION.getCode(), privateKey);
signatureGenerator.setHashedSubpackets(
SignatureSubpacketsHelper.toVector((SignatureSubpackets) subpackets));
PGPSignature additionalUserIdSignature = PGPSignature additionalUserIdSignature =
signatureGenerator.generateCertification(additionalUserId, primaryPubKey); signatureGenerator.generateCertification(userIdString, primaryPubKey);
primaryPubKey = PGPPublicKey.addCertification(primaryPubKey, primaryPubKey = PGPPublicKey.addCertification(primaryPubKey,
additionalUserId, additionalUserIdSignature); userIdString, additionalUserIdSignature);
} }
// "reassemble" secret key ring with modified primary key // "reassemble" secret key ring with modified primary key
@ -183,7 +206,7 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
PGPSignatureSubpacketVector hashedSubPackets, PGPSignatureSubpacketVector hashedSubPackets,
PBESecretKeyEncryptor secretKeyEncryptor) PBESecretKeyEncryptor secretKeyEncryptor)
throws PGPException { throws PGPException {
String primaryUserId = userIds.iterator().next(); String primaryUserId = userIds.entrySet().iterator().next().getKey();
return new PGPKeyRingGenerator( return new PGPKeyRingGenerator(
SignatureType.POSITIVE_CERTIFICATION.getCode(), certKey, SignatureType.POSITIVE_CERTIFICATION.getCode(), certKey,
primaryUserId, keyFingerprintCalculator, primaryUserId, keyFingerprintCalculator,
@ -199,7 +222,8 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
} else { } else {
PGPSignatureSubpacketVector hashedSubpackets = subKeySpec.getSubpackets(); PGPSignatureSubpacketVector hashedSubpackets = subKeySpec.getSubpackets();
try { try {
hashedSubpackets = addPrimaryKeyBindingSignatureIfNecessary(primaryKey, subKey, hashedSubpackets); hashedSubpackets = addPrimaryKeyBindingSignatureIfNecessary(
primaryKey, subKey, hashedSubpackets);
} catch (IOException e) { } catch (IOException e) {
throw new PGPException("Exception while adding primary key binding signature to signing subkey", e); throw new PGPException("Exception while adding primary key binding signature to signing subkey", e);
} }
@ -208,10 +232,12 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
} }
} }
private PGPSignatureSubpacketVector addPrimaryKeyBindingSignatureIfNecessary(PGPKeyPair primaryKey, PGPKeyPair subKey, PGPSignatureSubpacketVector hashedSubpackets) private PGPSignatureSubpacketVector addPrimaryKeyBindingSignatureIfNecessary(
PGPKeyPair primaryKey, PGPKeyPair subKey, PGPSignatureSubpacketVector hashedSubpackets)
throws PGPException, IOException { throws PGPException, IOException {
int keyFlagMask = hashedSubpackets.getKeyFlags(); int keyFlagMask = hashedSubpackets.getKeyFlags();
if (!KeyFlag.hasKeyFlag(keyFlagMask, KeyFlag.SIGN_DATA) && !KeyFlag.hasKeyFlag(keyFlagMask, KeyFlag.CERTIFY_OTHER)) { if (!KeyFlag.hasKeyFlag(keyFlagMask, KeyFlag.SIGN_DATA) &&
!KeyFlag.hasKeyFlag(keyFlagMask, KeyFlag.CERTIFY_OTHER)) {
return hashedSubpackets; return hashedSubpackets;
} }
@ -224,14 +250,16 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
} }
private PGPContentSignerBuilder buildContentSigner(PGPKeyPair certKey) { private PGPContentSignerBuilder buildContentSigner(PGPKeyPair certKey) {
HashAlgorithm hashAlgorithm = PGPainless.getPolicy().getSignatureHashAlgorithmPolicy().defaultHashAlgorithm(); HashAlgorithm hashAlgorithm = PGPainless.getPolicy()
.getSignatureHashAlgorithmPolicy().defaultHashAlgorithm();
return ImplementationFactory.getInstance().getPGPContentSignerBuilder( return ImplementationFactory.getInstance().getPGPContentSignerBuilder(
certKey.getPublicKey().getAlgorithm(), certKey.getPublicKey().getAlgorithm(),
hashAlgorithm.getAlgorithmId()); hashAlgorithm.getAlgorithmId());
} }
private PBESecretKeyEncryptor buildSecretKeyEncryptor(PGPDigestCalculator keyFingerprintCalculator) { private PBESecretKeyEncryptor buildSecretKeyEncryptor(PGPDigestCalculator keyFingerprintCalculator) {
SymmetricKeyAlgorithm keyEncryptionAlgorithm = PGPainless.getPolicy().getSymmetricKeyEncryptionAlgorithmPolicy() SymmetricKeyAlgorithm keyEncryptionAlgorithm = PGPainless.getPolicy()
.getSymmetricKeyEncryptionAlgorithmPolicy()
.getDefaultSymmetricKeyAlgorithm(); .getDefaultSymmetricKeyAlgorithm();
if (!passphrase.isValid()) { if (!passphrase.isValid()) {
throw new IllegalStateException("Passphrase was cleared."); throw new IllegalStateException("Passphrase was cleared.");
@ -261,7 +289,8 @@ public class KeyRingBuilder implements KeyRingBuilderInterface<KeyRingBuilder> {
KeyPair keyPair = certKeyGenerator.generateKeyPair(); KeyPair keyPair = certKeyGenerator.generateKeyPair();
// Form PGP key pair // Form PGP key pair
PGPKeyPair pgpKeyPair = ImplementationFactory.getInstance().getPGPKeyPair(type.getAlgorithm(), keyPair, new Date()); PGPKeyPair pgpKeyPair = ImplementationFactory.getInstance()
.getPGPKeyPair(type.getAlgorithm(), keyPair, new Date());
return pgpKeyPair; return pgpKeyPair;
} }
} }

View file

@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.key.generation;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless;
import org.pgpainless.key.info.KeyRingInfo;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class KeyGenerationSubpacketsTest {
@Test
public void verifyDefaultSubpackets()
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice", null);
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
PGPSignature userIdSig = info.getLatestUserIdCertification("Alice");
assertNotNull(userIdSig);
assertNotNull(userIdSig.getHashedSubPackets().getIssuerFingerprint());
}
}