2021-10-07 15:48:52 +02:00
|
|
|
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
2021-06-24 17:39:03 +02:00
|
|
|
package org.pgpainless.example;
|
|
|
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.AfterEach;
|
|
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import org.pgpainless.PGPainless;
|
|
|
|
import org.pgpainless.algorithm.HashAlgorithm;
|
|
|
|
import org.pgpainless.algorithm.PublicKeyAlgorithm;
|
|
|
|
import org.pgpainless.policy.Policy;
|
|
|
|
import org.pgpainless.util.NotationRegistry;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* PGPainless comes with an algorithm policy.
|
|
|
|
* This policy is consulted during signature verification, such that signatures made using weak algorithms
|
|
|
|
* can be rejected.
|
2021-06-24 17:53:55 +02:00
|
|
|
* Note, that PGPainless distinguishes between hash algorithms used in revocation and non-revocation signatures,
|
|
|
|
* and has different policies for those.
|
2021-06-24 17:39:03 +02:00
|
|
|
*
|
2021-12-28 13:53:25 +01:00
|
|
|
* Furthermore, PGPainless has policies for symmetric encryption algorithms (both for encrypting and decrypting),
|
2021-06-24 17:53:55 +02:00
|
|
|
* for public key algorithms and key lengths, as well as compression algorithms.
|
|
|
|
*
|
|
|
|
* The following examples show how these policies can be modified.
|
2021-06-24 17:39:03 +02:00
|
|
|
*
|
|
|
|
* PGPainless' policy is being accessed by calling {@link PGPainless#getPolicy()}.
|
|
|
|
* Custom sub-policies can be set by calling the setter methods of {@link Policy}.
|
|
|
|
*/
|
|
|
|
public class ManagePolicy {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset PGPainless' policy class to default values.
|
|
|
|
*/
|
|
|
|
@BeforeEach
|
|
|
|
@AfterEach
|
|
|
|
public void resetPolicy() {
|
2021-06-24 17:53:55 +02:00
|
|
|
// Policy for hash algorithms in non-revocation signatures
|
2021-06-24 17:39:03 +02:00
|
|
|
PGPainless.getPolicy().setSignatureHashAlgorithmPolicy(
|
|
|
|
Policy.HashAlgorithmPolicy.defaultSignatureAlgorithmPolicy());
|
2021-06-24 17:53:55 +02:00
|
|
|
// Policy for hash algorithms in revocation signatures
|
2021-06-24 17:39:03 +02:00
|
|
|
PGPainless.getPolicy().setRevocationSignatureHashAlgorithmPolicy(
|
|
|
|
Policy.HashAlgorithmPolicy.defaultRevocationSignatureHashAlgorithmPolicy());
|
2021-06-24 17:53:55 +02:00
|
|
|
// Policy for public key algorithms and bit lengths
|
2021-06-24 17:39:03 +02:00
|
|
|
PGPainless.getPolicy().setPublicKeyAlgorithmPolicy(
|
|
|
|
Policy.PublicKeyAlgorithmPolicy.defaultPublicKeyAlgorithmPolicy());
|
2021-06-24 17:53:55 +02:00
|
|
|
// Policy for acceptable symmetric encryption algorithms when decrypting messages
|
2021-06-24 17:39:03 +02:00
|
|
|
PGPainless.getPolicy().setSymmetricKeyDecryptionAlgorithmPolicy(
|
|
|
|
Policy.SymmetricKeyAlgorithmPolicy.defaultSymmetricKeyDecryptionAlgorithmPolicy());
|
2021-06-24 17:53:55 +02:00
|
|
|
// Policy for acceptable symmetric encryption algorithms when encrypting messages
|
2021-06-24 17:39:03 +02:00
|
|
|
PGPainless.getPolicy().setSymmetricKeyEncryptionAlgorithmPolicy(
|
|
|
|
Policy.SymmetricKeyAlgorithmPolicy.defaultSymmetricKeyEncryptionAlgorithmPolicy());
|
2021-06-24 17:53:55 +02:00
|
|
|
// Policy for acceptable compression algorithms
|
2021-06-24 17:39:03 +02:00
|
|
|
PGPainless.getPolicy().setCompressionAlgorithmPolicy(
|
|
|
|
Policy.CompressionAlgorithmPolicy.defaultCompressionAlgorithmPolicy());
|
2021-06-24 17:53:55 +02:00
|
|
|
// Known notations
|
2021-06-24 17:39:03 +02:00
|
|
|
PGPainless.getPolicy().getNotationRegistry().clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@link HashAlgorithm Hash Algorithms} may get outdated with time. {@link HashAlgorithm#SHA1} is a prominent
|
|
|
|
* example for an algorithm that is nowadays considered unsafe to use and which shall be avoided.
|
|
|
|
*
|
|
|
|
* PGPainless comes with a {@link Policy} class that defines which algorithms are trustworthy and acceptable.
|
|
|
|
* It also allows the user to specify a custom policy tailored to their needs.
|
|
|
|
*
|
|
|
|
* Per default, PGPainless will reject non-revocation signatures that use SHA-1 as hash algorithm.
|
|
|
|
* To inspect PGPainless' default signature hash algorithm policy, see
|
|
|
|
* {@link Policy.HashAlgorithmPolicy#defaultSignatureAlgorithmPolicy()}.
|
|
|
|
*
|
|
|
|
* Since it may be a valid use-case to accept signatures made using SHA-1 as part of a less strict policy,
|
|
|
|
* this example demonstrates how to set a custom signature hash algorithm policy.
|
|
|
|
*/
|
|
|
|
@Test
|
|
|
|
public void setCustomSignatureHashPolicy() {
|
|
|
|
// Get PGPainless' policy singleton
|
|
|
|
Policy policy = PGPainless.getPolicy();
|
|
|
|
|
|
|
|
Policy.HashAlgorithmPolicy sigHashAlgoPolicy = policy.getSignatureHashAlgorithmPolicy();
|
|
|
|
assertTrue(sigHashAlgoPolicy.isAcceptable(HashAlgorithm.SHA512));
|
|
|
|
// Per default, non-revocation signatures using SHA-1 are rejected
|
|
|
|
assertFalse(sigHashAlgoPolicy.isAcceptable(HashAlgorithm.SHA1));
|
|
|
|
|
|
|
|
|
|
|
|
// Create a new custom policy which contains SHA-1
|
|
|
|
Policy.HashAlgorithmPolicy customPolicy = new Policy.HashAlgorithmPolicy(
|
|
|
|
// The default hash algorithm will be used when hash algorithm negotiation fails when creating a sig
|
|
|
|
HashAlgorithm.SHA512,
|
|
|
|
// List of acceptable hash algorithms
|
|
|
|
Arrays.asList(HashAlgorithm.SHA512, HashAlgorithm.SHA384, HashAlgorithm.SHA256, HashAlgorithm.SHA224, HashAlgorithm.SHA1));
|
|
|
|
// Set the hash algo policy as policy for non-revocation signatures
|
|
|
|
policy.setSignatureHashAlgorithmPolicy(customPolicy);
|
|
|
|
|
|
|
|
|
|
|
|
sigHashAlgoPolicy = policy.getSignatureHashAlgorithmPolicy();
|
|
|
|
assertTrue(sigHashAlgoPolicy.isAcceptable(HashAlgorithm.SHA512));
|
|
|
|
// SHA-1 is now acceptable as well
|
|
|
|
assertTrue(sigHashAlgoPolicy.isAcceptable(HashAlgorithm.SHA1));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Similar to hash algorithms, {@link PublicKeyAlgorithm PublicKeyAlgorithms} tend to get outdated eventually.
|
|
|
|
* Per default, PGPainless will reject signatures made by keys of unacceptable algorithm or length.
|
|
|
|
* See {@link Policy.PublicKeyAlgorithmPolicy#defaultPublicKeyAlgorithmPolicy()} to inspect PGPainless' defaults.
|
|
|
|
*
|
|
|
|
* This example demonstrates how to set a custom public key algorithm policy.
|
|
|
|
*/
|
|
|
|
@Test
|
|
|
|
public void setCustomPublicKeyAlgorithmPolicy() {
|
|
|
|
Policy policy = PGPainless.getPolicy();
|
|
|
|
Policy.PublicKeyAlgorithmPolicy pkAlgorithmPolicy = policy.getPublicKeyAlgorithmPolicy();
|
|
|
|
assertTrue(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 4096));
|
|
|
|
assertTrue(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 2048));
|
|
|
|
assertFalse(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 1024));
|
|
|
|
assertTrue(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.ECDSA, 256));
|
|
|
|
|
|
|
|
|
|
|
|
Policy.PublicKeyAlgorithmPolicy customPolicy = new Policy.PublicKeyAlgorithmPolicy(
|
|
|
|
new HashMap<PublicKeyAlgorithm, Integer>(){{
|
|
|
|
// Put minimum bit strengths for acceptable algorithms.
|
|
|
|
// A key is being rejected if it is not listed in the map,
|
|
|
|
// or its length is smaller than the corresponding minimum
|
|
|
|
put(PublicKeyAlgorithm.RSA_GENERAL, 3000);
|
|
|
|
}}
|
|
|
|
);
|
|
|
|
policy.setPublicKeyAlgorithmPolicy(customPolicy);
|
|
|
|
|
|
|
|
|
|
|
|
pkAlgorithmPolicy = policy.getPublicKeyAlgorithmPolicy();
|
|
|
|
assertTrue(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 4096));
|
|
|
|
// RSA 2048 is no longer acceptable
|
|
|
|
assertFalse(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 2048));
|
|
|
|
// ECDSA is no longer acceptable, since it is no longer included in the policy at all
|
|
|
|
assertFalse(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.ECDSA, 256));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* OpenPGP requires implementations to reject signatures which contain critical notation data subpackets
|
|
|
|
* which are not known to the implementation.
|
|
|
|
*
|
|
|
|
* PGPainless allows the user to define which notations should be considered known notations.
|
|
|
|
* The following example demonstrates how to mark the notation value 'unknown@pgpainless.org' as known,
|
|
|
|
* such that signatures containing a critical notation with that name are no longer being invalidated because of it.
|
|
|
|
*/
|
|
|
|
@Test
|
|
|
|
public void manageKnownNotations() {
|
|
|
|
Policy policy = PGPainless.getPolicy();
|
|
|
|
NotationRegistry notationRegistry = policy.getNotationRegistry();
|
|
|
|
assertFalse(notationRegistry.isKnownNotation("unknown@pgpainless.org"));
|
|
|
|
|
|
|
|
|
|
|
|
notationRegistry.addKnownNotation("unknown@pgpainless.org");
|
|
|
|
|
|
|
|
|
|
|
|
assertTrue(notationRegistry.isKnownNotation("unknown@pgpainless.org"));
|
|
|
|
}
|
|
|
|
}
|