mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-09 02:09:38 +02:00
Compare commits
5 commits
db0d753867
...
b3602bf2e4
Author | SHA1 | Date | |
---|---|---|---|
b3602bf2e4 | |||
afbd4e6105 | |||
2270c69af7 | |||
9a8ecb7fa0 | |||
ffebdda214 |
11 changed files with 407 additions and 98 deletions
|
@ -175,52 +175,4 @@ interface BaseSignatureSubpackets {
|
||||||
fun addEmbeddedSignature(embeddedSignature: EmbeddedSignature): BaseSignatureSubpackets
|
fun addEmbeddedSignature(embeddedSignature: EmbeddedSignature): BaseSignatureSubpackets
|
||||||
|
|
||||||
fun clearEmbeddedSignatures(): BaseSignatureSubpackets
|
fun clearEmbeddedSignatures(): BaseSignatureSubpackets
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
/** Factory method for a [Callback] that does nothing. */
|
|
||||||
@JvmStatic fun nop() = object : Callback {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory function with receiver, which returns a [Callback] that modifies the hashed
|
|
||||||
* subpacket area of a [BaseSignatureSubpackets] object.
|
|
||||||
*
|
|
||||||
* Can be called like this:
|
|
||||||
* ```
|
|
||||||
* val callback = BaseSignatureSubpackets.applyHashed {
|
|
||||||
* setCreationTime(date)
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun applyHashed(function: BaseSignatureSubpackets.() -> Unit): Callback {
|
|
||||||
return object : Callback {
|
|
||||||
override fun modifyHashedSubpackets(hashedSubpackets: BaseSignatureSubpackets) {
|
|
||||||
function(hashedSubpackets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory function with receiver, which returns a [Callback] that modifies the unhashed
|
|
||||||
* subpacket area of a [BaseSignatureSubpackets] object.
|
|
||||||
*
|
|
||||||
* Can be called like this:
|
|
||||||
* ```
|
|
||||||
* val callback = BaseSignatureSubpackets.applyUnhashed {
|
|
||||||
* setCreationTime(date)
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun applyUnhashed(function: BaseSignatureSubpackets.() -> Unit): Callback {
|
|
||||||
return object : Callback {
|
|
||||||
override fun modifyUnhashedSubpackets(unhashedSubpackets: BaseSignatureSubpackets) {
|
|
||||||
function(unhashedSubpackets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,22 @@ package org.pgpainless.signature.subpackets
|
||||||
|
|
||||||
interface CertificationSubpackets : BaseSignatureSubpackets {
|
interface CertificationSubpackets : BaseSignatureSubpackets {
|
||||||
|
|
||||||
interface Callback : SignatureSubpacketCallback<CertificationSubpackets>
|
interface Callback : SignatureSubpacketCallback<CertificationSubpackets> {
|
||||||
|
fun then(nextCallback: SignatureSubpacketCallback<CertificationSubpackets>): Callback {
|
||||||
|
val currCallback = this
|
||||||
|
return object : Callback {
|
||||||
|
override fun modifyHashedSubpackets(hashedSubpackets: CertificationSubpackets) {
|
||||||
|
currCallback.modifyHashedSubpackets(hashedSubpackets)
|
||||||
|
nextCallback.modifyHashedSubpackets(hashedSubpackets)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun modifyUnhashedSubpackets(unhashedSubpackets: CertificationSubpackets) {
|
||||||
|
currCallback.modifyUnhashedSubpackets(unhashedSubpackets)
|
||||||
|
nextCallback.modifyUnhashedSubpackets(unhashedSubpackets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,32 @@ package org.pgpainless.signature.subpackets
|
||||||
|
|
||||||
import org.bouncycastle.bcpg.sig.RevocationReason
|
import org.bouncycastle.bcpg.sig.RevocationReason
|
||||||
import org.pgpainless.key.util.RevocationAttributes
|
import org.pgpainless.key.util.RevocationAttributes
|
||||||
|
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets.Callback
|
||||||
|
|
||||||
interface RevocationSignatureSubpackets : BaseSignatureSubpackets {
|
interface RevocationSignatureSubpackets : BaseSignatureSubpackets {
|
||||||
|
|
||||||
interface Callback : SignatureSubpacketCallback<RevocationSignatureSubpackets>
|
interface Callback : SignatureSubpacketCallback<RevocationSignatureSubpackets> {
|
||||||
|
fun then(
|
||||||
|
nextCallback: SignatureSubpacketCallback<RevocationSignatureSubpackets>
|
||||||
|
): Callback {
|
||||||
|
val currCallback = this
|
||||||
|
return object : Callback {
|
||||||
|
override fun modifyHashedSubpackets(
|
||||||
|
hashedSubpackets: RevocationSignatureSubpackets
|
||||||
|
) {
|
||||||
|
currCallback.modifyHashedSubpackets(hashedSubpackets)
|
||||||
|
nextCallback.modifyHashedSubpackets(hashedSubpackets)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun modifyUnhashedSubpackets(
|
||||||
|
unhashedSubpackets: RevocationSignatureSubpackets
|
||||||
|
) {
|
||||||
|
currCallback.modifyUnhashedSubpackets(unhashedSubpackets)
|
||||||
|
nextCallback.modifyUnhashedSubpackets(unhashedSubpackets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun setRevocationReason(
|
fun setRevocationReason(
|
||||||
revocationAttributes: RevocationAttributes
|
revocationAttributes: RevocationAttributes
|
||||||
|
|
|
@ -121,6 +121,10 @@ interface SelfSignatureSubpackets : BaseSignatureSubpackets {
|
||||||
algorithms: PreferredAEADCiphersuites.Builder?
|
algorithms: PreferredAEADCiphersuites.Builder?
|
||||||
): SelfSignatureSubpackets
|
): SelfSignatureSubpackets
|
||||||
|
|
||||||
|
fun setPreferredAEADCiphersuites(
|
||||||
|
preferredAEADCiphersuites: PreferredAEADCiphersuites?
|
||||||
|
): SelfSignatureSubpackets
|
||||||
|
|
||||||
@Deprecated("Use of this subpacket is discouraged.")
|
@Deprecated("Use of this subpacket is discouraged.")
|
||||||
fun addRevocationKey(revocationKey: PGPPublicKey): SelfSignatureSubpackets
|
fun addRevocationKey(revocationKey: PGPPublicKey): SelfSignatureSubpackets
|
||||||
|
|
||||||
|
|
|
@ -70,51 +70,6 @@ class SignatureSubpackets(
|
||||||
fun createEmptySubpackets(): SignatureSubpackets {
|
fun createEmptySubpackets(): SignatureSubpackets {
|
||||||
return SignatureSubpackets(PGPSignatureSubpacketGenerator())
|
return SignatureSubpackets(PGPSignatureSubpacketGenerator())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Factory method for a [Callback] that does nothing. */
|
|
||||||
@JvmStatic fun nop() = object : Callback {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory function with receiver, which returns a [Callback] that modifies the hashed
|
|
||||||
* subpacket area of a [SignatureSubpackets] object.
|
|
||||||
*
|
|
||||||
* Can be called like this:
|
|
||||||
* ```
|
|
||||||
* val callback = SignatureSubpackets.applyHashed {
|
|
||||||
* setCreationTime(date)
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun applyHashed(function: SignatureSubpackets.() -> Unit): Callback {
|
|
||||||
return object : Callback {
|
|
||||||
override fun modifyHashedSubpackets(hashedSubpackets: SignatureSubpackets) {
|
|
||||||
function(hashedSubpackets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory function with receiver, which returns a [Callback] that modifies the unhashed
|
|
||||||
* subpacket area of a [SignatureSubpackets] object.
|
|
||||||
*
|
|
||||||
* Can be called like this:
|
|
||||||
* ```
|
|
||||||
* val callback = SignatureSubpackets.applyUnhashed {
|
|
||||||
* setCreationTime(date)
|
|
||||||
* ...
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun applyUnhashed(function: SignatureSubpackets.() -> Unit): Callback {
|
|
||||||
return object : Callback {
|
|
||||||
override fun modifyUnhashedSubpackets(unhashedSubpackets: SignatureSubpackets) {
|
|
||||||
function(unhashedSubpackets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setRevocationReason(
|
override fun setRevocationReason(
|
||||||
|
@ -326,9 +281,15 @@ class SignatureSubpackets(
|
||||||
|
|
||||||
override fun setPreferredAEADCiphersuites(
|
override fun setPreferredAEADCiphersuites(
|
||||||
algorithms: PreferredAEADCiphersuites.Builder?
|
algorithms: PreferredAEADCiphersuites.Builder?
|
||||||
): SignatureSubpackets = apply {
|
): SignatureSubpackets = setPreferredAEADCiphersuites(algorithms?.build())
|
||||||
|
|
||||||
|
override fun setPreferredAEADCiphersuites(
|
||||||
|
preferredAEADCiphersuites: PreferredAEADCiphersuites?
|
||||||
|
) = apply {
|
||||||
subpacketsGenerator.removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS)
|
subpacketsGenerator.removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS)
|
||||||
algorithms?.let { subpacketsGenerator.setPreferredAEADCiphersuites(algorithms) }
|
preferredAEADCiphersuites?.let {
|
||||||
|
subpacketsGenerator.setPreferredAEADCiphersuites(it.isCritical, it.rawAlgorithms)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addRevocationKey(revocationKey: PGPPublicKey): SignatureSubpackets = apply {
|
override fun addRevocationKey(revocationKey: PGPPublicKey): SignatureSubpackets = apply {
|
||||||
|
|
|
@ -61,6 +61,11 @@ class SignatureSubpacketsHelper {
|
||||||
PreferredAlgorithms(
|
PreferredAlgorithms(
|
||||||
it.type, it.isCritical, it.isLongLength, it.data))
|
it.type, it.isCritical, it.isLongLength, it.data))
|
||||||
}
|
}
|
||||||
|
SignatureSubpacket.preferredAEADAlgorithms ->
|
||||||
|
(subpacket as PreferredAEADCiphersuites).let {
|
||||||
|
subpackets.setPreferredAEADCiphersuites(
|
||||||
|
PreferredAEADCiphersuites(it.isCritical, it.rawAlgorithms))
|
||||||
|
}
|
||||||
SignatureSubpacket.revocationKey ->
|
SignatureSubpacket.revocationKey ->
|
||||||
(subpacket as RevocationKey).let {
|
(subpacket as RevocationKey).let {
|
||||||
subpackets.addRevocationKey(
|
subpackets.addRevocationKey(
|
||||||
|
@ -130,7 +135,6 @@ class SignatureSubpacketsHelper {
|
||||||
SignatureSubpacket.keyServerPreferences,
|
SignatureSubpacket.keyServerPreferences,
|
||||||
SignatureSubpacket.preferredKeyServers,
|
SignatureSubpacket.preferredKeyServers,
|
||||||
SignatureSubpacket.placeholder,
|
SignatureSubpacket.placeholder,
|
||||||
SignatureSubpacket.preferredAEADAlgorithms,
|
|
||||||
SignatureSubpacket.attestedCertification ->
|
SignatureSubpacket.attestedCertification ->
|
||||||
subpackets.addResidualSubpacket(subpacket)
|
subpackets.addResidualSubpacket(subpacket)
|
||||||
else -> subpackets.addResidualSubpacket(subpacket)
|
else -> subpackets.addResidualSubpacket(subpacket)
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.bouncycastle;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.api.OpenPGPPolicy;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.bouncycastle.PolicyAdapter;
|
||||||
|
import org.pgpainless.policy.Policy;
|
||||||
|
import org.pgpainless.util.NotationRegistry;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class PolicyAdapterTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotationRegistryAdaption() {
|
||||||
|
NotationRegistry pgpainlessNotationReg = new NotationRegistry();
|
||||||
|
pgpainlessNotationReg.addKnownNotation("foo");
|
||||||
|
|
||||||
|
Policy policy = PGPainless.getInstance().getAlgorithmPolicy()
|
||||||
|
.copy()
|
||||||
|
.withNotationRegistry(pgpainlessNotationReg)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
PolicyAdapter adapter = new PolicyAdapter(policy);
|
||||||
|
OpenPGPPolicy.OpenPGPNotationRegistry bcNotationReg = adapter.getNotationRegistry();
|
||||||
|
assertTrue(bcNotationReg.isNotationKnown("foo"));
|
||||||
|
assertFalse(bcNotationReg.isNotationKnown("bar"));
|
||||||
|
bcNotationReg.addKnownNotation("bar");
|
||||||
|
|
||||||
|
assertTrue(pgpainlessNotationReg.isKnownNotation("bar"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.signature.subpackets;
|
||||||
|
|
||||||
|
import kotlin.Unit;
|
||||||
|
import org.bouncycastle.bcpg.SignatureSubpacket;
|
||||||
|
import org.bouncycastle.bcpg.sig.IssuerFingerprint;
|
||||||
|
import org.bouncycastle.bcpg.sig.NotationData;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.key.TestKeys;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.pgpainless.signature.subpackets.SignatureSubpacketsTest.toArray;
|
||||||
|
|
||||||
|
public class CertificationSubpacketsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNopDoesNothing() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
CertificationSubpackets.Callback cb = CertificationSubpackets.nop();
|
||||||
|
|
||||||
|
cb.modifyHashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
cb.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyHashed() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
CertificationSubpackets.Callback cb = CertificationSubpackets.applyHashed(
|
||||||
|
selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setIssuerFingerprint(new IssuerFingerprint(false, 4, TestKeys.ROMEO_FINGERPRINT.getBytes()));
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
// The callback only applies to hashed subpackets, so modifying unhashed area does nothing
|
||||||
|
cb.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
cb.modifyHashedSubpackets(subpackets);
|
||||||
|
assertEquals(1, toArray(subpackets).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyUnhashed() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
CertificationSubpackets.Callback cb = CertificationSubpackets.applyUnhashed(
|
||||||
|
selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setIssuerKeyId(123L);
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
// The callback only applies to unhashed subpackets, so modifying hashed area does nothing
|
||||||
|
cb.modifyHashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
cb.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(1, toArray(subpackets).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThen() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
|
||||||
|
CertificationSubpackets.Callback first = CertificationSubpackets.applyHashed(selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setIssuerFingerprint(new IssuerFingerprint(false, 4, TestKeys.ROMEO_FINGERPRINT.getBytes()));
|
||||||
|
selfSignatureSubpackets.addNotationData(false, "test@pgpainless.org", "foo");
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
CertificationSubpackets.Callback second = CertificationSubpackets.applyHashed(selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setIssuerFingerprint(new IssuerFingerprint(true, 4, TestKeys.ROMEO_FINGERPRINT.getBytes()));
|
||||||
|
selfSignatureSubpackets.addNotationData(false, "test@pgpainless.org", "bar");
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
CertificationSubpackets.Callback both = first.then(second);
|
||||||
|
both.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
both.modifyHashedSubpackets(subpackets);
|
||||||
|
|
||||||
|
SignatureSubpacket[] array = toArray(subpackets);
|
||||||
|
assertEquals(3, array.length);
|
||||||
|
NotationData n1 = (NotationData) array[0];
|
||||||
|
assertEquals("foo", n1.getNotationValue());
|
||||||
|
IssuerFingerprint fingerprint = (IssuerFingerprint) array[1];
|
||||||
|
assertTrue(fingerprint.isCritical());
|
||||||
|
NotationData n2 = (NotationData) array[2];
|
||||||
|
assertEquals("bar", n2.getNotationValue());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.signature.subpackets;
|
||||||
|
|
||||||
|
import kotlin.Unit;
|
||||||
|
import org.bouncycastle.bcpg.SignatureSubpacket;
|
||||||
|
import org.bouncycastle.bcpg.sig.NotationData;
|
||||||
|
import org.bouncycastle.bcpg.sig.RevocationReason;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.key.util.RevocationAttributes;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.pgpainless.signature.subpackets.SignatureSubpacketsTest.toArray;
|
||||||
|
|
||||||
|
public class RevocationSignatureSubpacketsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNopDoesNothing() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
RevocationSignatureSubpackets.Callback cb = RevocationSignatureSubpackets.nop();
|
||||||
|
|
||||||
|
cb.modifyHashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
cb.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyHashed() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
RevocationSignatureSubpackets.Callback cb = RevocationSignatureSubpackets.applyHashed(
|
||||||
|
selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setRevocationReason(true, RevocationAttributes.Reason.KEY_COMPROMISED, "Leaked");
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
// The callback only applies to hashed subpackets, so modifying unhashed area does nothing
|
||||||
|
cb.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
cb.modifyHashedSubpackets(subpackets);
|
||||||
|
assertEquals(1, toArray(subpackets).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyUnhashed() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
RevocationSignatureSubpackets.Callback cb = RevocationSignatureSubpackets.applyUnhashed(
|
||||||
|
selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setIssuerKeyId(123L);
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
// The callback only applies to unhashed subpackets, so modifying hashed area does nothing
|
||||||
|
cb.modifyHashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
cb.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(1, toArray(subpackets).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThen() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
|
||||||
|
RevocationSignatureSubpackets.Callback first = RevocationSignatureSubpackets.applyHashed(selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setRevocationReason(true, RevocationAttributes.Reason.KEY_COMPROMISED, "Leakett (typo)");
|
||||||
|
selfSignatureSubpackets.addNotationData(false, "test@pgpainless.org", "foo");
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
RevocationSignatureSubpackets.Callback second = RevocationSignatureSubpackets.applyHashed(selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setRevocationReason(true, RevocationAttributes.Reason.KEY_COMPROMISED, "Leaked");
|
||||||
|
selfSignatureSubpackets.addNotationData(false, "test@pgpainless.org", "bar");
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
RevocationSignatureSubpackets.Callback both = first.then(second);
|
||||||
|
both.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
both.modifyHashedSubpackets(subpackets);
|
||||||
|
|
||||||
|
SignatureSubpacket[] array = toArray(subpackets);
|
||||||
|
assertEquals(3, array.length);
|
||||||
|
NotationData n1 = (NotationData) array[0];
|
||||||
|
assertEquals("foo", n1.getNotationValue());
|
||||||
|
RevocationReason reason = (RevocationReason) array[1];
|
||||||
|
assertEquals(RevocationAttributes.Reason.KEY_COMPROMISED.code(), reason.getRevocationReason());
|
||||||
|
NotationData n2 = (NotationData) array[2];
|
||||||
|
assertEquals("bar", n2.getNotationValue());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.signature.subpackets;
|
||||||
|
|
||||||
|
import kotlin.Unit;
|
||||||
|
import org.bouncycastle.bcpg.SignatureSubpacket;
|
||||||
|
import org.bouncycastle.bcpg.sig.KeyFlags;
|
||||||
|
import org.bouncycastle.bcpg.sig.NotationData;
|
||||||
|
import org.bouncycastle.bcpg.sig.PreferredAlgorithms;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.algorithm.HashAlgorithm;
|
||||||
|
import org.pgpainless.algorithm.KeyFlag;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.pgpainless.signature.subpackets.SignatureSubpacketsTest.toArray;
|
||||||
|
|
||||||
|
public class SelfSignatureSubpacketsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNopDoesNothing() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
SelfSignatureSubpackets.Callback cb = SelfSignatureSubpackets.nop();
|
||||||
|
|
||||||
|
cb.modifyHashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
cb.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyHashed() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
SelfSignatureSubpackets.Callback cb = SelfSignatureSubpackets.applyHashed(
|
||||||
|
selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setKeyFlags(KeyFlag.CERTIFY_OTHER);
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
// The callback only applies to hashed subpackets, so modifying unhashed area does nothing
|
||||||
|
cb.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
cb.modifyHashedSubpackets(subpackets);
|
||||||
|
assertEquals(1, toArray(subpackets).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyUnhashed() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
SelfSignatureSubpackets.Callback cb = SelfSignatureSubpackets.applyUnhashed(
|
||||||
|
selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setIssuerKeyId(123L);
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
// The callback only applies to unhashed subpackets, so modifying hashed area does nothing
|
||||||
|
cb.modifyHashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
cb.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(1, toArray(subpackets).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThen() {
|
||||||
|
SignatureSubpackets subpackets = new SignatureSubpackets();
|
||||||
|
|
||||||
|
SelfSignatureSubpackets.Callback first = SelfSignatureSubpackets.applyHashed(selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setPreferredHashAlgorithms(HashAlgorithm.SHA256, HashAlgorithm.SHA512);
|
||||||
|
selfSignatureSubpackets.setKeyFlags(KeyFlag.CERTIFY_OTHER);
|
||||||
|
selfSignatureSubpackets.addNotationData(false, "test@pgpainless.org", "foo");
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
SelfSignatureSubpackets.Callback second = SelfSignatureSubpackets.applyHashed(selfSignatureSubpackets -> {
|
||||||
|
selfSignatureSubpackets.setKeyFlags(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA);
|
||||||
|
selfSignatureSubpackets.addNotationData(false, "test@pgpainless.org", "bar");
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
});
|
||||||
|
|
||||||
|
SelfSignatureSubpackets.Callback both = first.then(second);
|
||||||
|
both.modifyUnhashedSubpackets(subpackets);
|
||||||
|
assertEquals(0, toArray(subpackets).length);
|
||||||
|
|
||||||
|
both.modifyHashedSubpackets(subpackets);
|
||||||
|
|
||||||
|
SignatureSubpacket[] array = toArray(subpackets);
|
||||||
|
assertEquals(4, array.length);
|
||||||
|
PreferredAlgorithms hashAlgs = (PreferredAlgorithms) array[0];
|
||||||
|
assertArrayEquals(
|
||||||
|
new int[] {HashAlgorithm.SHA256.getAlgorithmId(), HashAlgorithm.SHA512.getAlgorithmId()},
|
||||||
|
hashAlgs.getPreferences());
|
||||||
|
NotationData n1 = (NotationData) array[1];
|
||||||
|
assertEquals("foo", n1.getNotationValue());
|
||||||
|
KeyFlags flags = (KeyFlags) array[2];
|
||||||
|
assertEquals(KeyFlag.toBitmask(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA), flags.getFlags());
|
||||||
|
NotationData n2 = (NotationData) array[3];
|
||||||
|
assertEquals("bar", n2.getNotationValue());
|
||||||
|
}
|
||||||
|
}
|
|
@ -534,4 +534,8 @@ public class SignatureSubpacketsTest {
|
||||||
PreferredAlgorithms aeadAlgorithms = (PreferredAlgorithms) vector.getSubpacket(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS);
|
PreferredAlgorithms aeadAlgorithms = (PreferredAlgorithms) vector.getSubpacket(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS);
|
||||||
assertArrayEquals(aead.getPreferences(), aeadAlgorithms.getPreferences());
|
assertArrayEquals(aead.getPreferences(), aeadAlgorithms.getPreferences());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SignatureSubpacket[] toArray(SignatureSubpackets subpackets) {
|
||||||
|
return subpackets.getSubpacketsGenerator().generate().toArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue