From 5143da13114ca369486b2fd9de588c00b2e1ba20 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sun, 3 Jan 2021 17:01:08 +0100 Subject: [PATCH] Verify that keys can carry certain key flags --- .../key/generation/KeySpecBuilder.java | 25 +++++++++ .../key/generation/type/KeyType.java | 44 ++++++++++++++- .../key/generation/type/ecc/ecdh/ECDH.java | 7 ++- .../key/generation/type/ecc/ecdsa/ECDSA.java | 8 ++- .../key/generation/type/eddsa/EdDSA.java | 7 ++- .../type/elgamal/ElGamal_ENCRYPT.java | 8 ++- .../type/elgamal/ElGamal_GENERAL.java | 9 ++- .../key/generation/type/rsa/RSA.java | 7 ++- .../key/generation/type/xdh/XDH.java | 7 ++- .../key/generation/IllegalKeyFlagsTest.java | 56 +++++++++++++++++++ 10 files changed, 167 insertions(+), 11 deletions(-) create mode 100644 pgpainless-core/src/test/java/org/pgpainless/key/generation/IllegalKeyFlagsTest.java diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java index 5e212ed2..acc75f78 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java @@ -38,10 +38,35 @@ public class KeySpecBuilder implements KeySpecBuilderInterface { @Override public WithDetailedConfiguration withKeyFlags(@Nonnull KeyFlag... flags) { + assureKeyCanCarryFlags(flags); this.hashedSubPackets.setKeyFlags(false, KeyFlag.toBitmask(flags)); return new WithDetailedConfigurationImpl(); } + private void assureKeyCanCarryFlags(KeyFlag... flags) { + final int mask = KeyFlag.toBitmask(flags); + + if (!type.canCertify() && KeyFlag.hasKeyFlag(mask, KeyFlag.CERTIFY_OTHER)) { + throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag CERTIFY_OTHER."); + } + + if (!type.canSign() && KeyFlag.hasKeyFlag(mask, KeyFlag.SIGN_DATA)) { + throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag SIGN_DATA."); + } + + if (!type.canEncryptCommunication() && KeyFlag.hasKeyFlag(mask, KeyFlag.ENCRYPT_COMMS)) { + throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag ENCRYPT_COMMS."); + } + + if (!type.canEncryptStorage() && KeyFlag.hasKeyFlag(mask, KeyFlag.ENCRYPT_STORAGE)) { + throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag ENCRYPT_STORAGE."); + } + + if (!type.canAuthenticate() && KeyFlag.hasKeyFlag(mask, KeyFlag.AUTHENTICATION)) { + throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag AUTHENTIACTION."); + } + } + @Override public KeySpec withInheritedSubPackets() { return new KeySpec(type, null, true); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java index 3fd45558..668e4fe4 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java @@ -52,12 +52,50 @@ public interface KeyType { AlgorithmParameterSpec getAlgorithmSpec(); /** - * Return true if the key that is generated from this type is able to carry the CERTIFY_OTHERS key flag. + * Return true if the key that is generated from this type is able to carry the SIGN_DATA key flag. + * See {@link org.pgpainless.algorithm.KeyFlag#SIGN_DATA}. + * + * @return true if the key can sign. + */ + boolean canSign(); + + /** + * Return true if the key that is generated from this type is able to carry the CERTIFY_OTHER key flag. * See {@link org.pgpainless.algorithm.KeyFlag#CERTIFY_OTHER}. * - * @return true if the key is able to certify others + * @return true if the key is able to certify other keys */ - boolean canCertify(); + default boolean canCertify() { + return canSign(); + } + + /** + * Return true if the key that is generated from this type is able to carry the AUTHENTICATION key flag. + * See {@link org.pgpainless.algorithm.KeyFlag#AUTHENTICATION}. + * + * @return true if the key is able to be used for authentication purposes. + */ + default boolean canAuthenticate() { + return canSign(); + } + + /** + * Return true if the key that is generated from this type is able to carry the ENCRYPT_COMMS key flag. + * See {@link org.pgpainless.algorithm.KeyFlag#ENCRYPT_COMMS}. + * + * @return true if the key can encrypt communication + */ + boolean canEncryptCommunication(); + + /** + * Return true if the key that is generated from this type is able to carry the ENCRYPT_STORAGE key flag. + * See {@link org.pgpainless.algorithm.KeyFlag#ENCRYPT_STORAGE}. + * + * @return true if the key can encrypt for storage + */ + default boolean canEncryptStorage() { + return canEncryptCommunication(); + } static KeyType RSA(RsaLength length) { return RSA.withLength(length); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdh/ECDH.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdh/ECDH.java index b3662574..b5967874 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdh/ECDH.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdh/ECDH.java @@ -51,7 +51,12 @@ public final class ECDH implements KeyType { } @Override - public boolean canCertify() { + public boolean canSign() { return false; } + + @Override + public boolean canEncryptCommunication() { + return true; + } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdsa/ECDSA.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdsa/ECDSA.java index beb65b9d..6e68e6f6 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdsa/ECDSA.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdsa/ECDSA.java @@ -52,7 +52,13 @@ public final class ECDSA implements KeyType { } @Override - public boolean canCertify() { + public boolean canSign() { return true; } + + @Override + public boolean canEncryptCommunication() { + return false; + } + } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSA.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSA.java index fb746af9..3c8bb171 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSA.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSA.java @@ -52,7 +52,12 @@ public final class EdDSA implements KeyType { } @Override - public boolean canCertify() { + public boolean canSign() { return true; } + + @Override + public boolean canEncryptCommunication() { + return false; + } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal_ENCRYPT.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal_ENCRYPT.java index ff29c78f..b7da3c76 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal_ENCRYPT.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal_ENCRYPT.java @@ -50,7 +50,13 @@ public final class ElGamal_ENCRYPT implements KeyType { } @Override - public boolean canCertify() { + public boolean canSign() { return false; } + + @Override + public boolean canEncryptCommunication() { + return true; + } + } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal_GENERAL.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal_GENERAL.java index 0ff11108..09289678 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal_GENERAL.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal_GENERAL.java @@ -51,7 +51,12 @@ public class ElGamal_GENERAL implements KeyType { } @Override - public boolean canCertify() { - return false; + public boolean canSign() { + return true; + } + + @Override + public boolean canEncryptCommunication() { + return true; } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/rsa/RSA.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/rsa/RSA.java index 13fb48ad..44aa504a 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/rsa/RSA.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/rsa/RSA.java @@ -53,7 +53,12 @@ public class RSA implements KeyType { } @Override - public boolean canCertify() { + public boolean canSign() { + return true; + } + + @Override + public boolean canEncryptCommunication() { return true; } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDH.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDH.java index c660a8eb..50b1aa7b 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDH.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDH.java @@ -49,7 +49,12 @@ public final class XDH implements KeyType { } @Override - public boolean canCertify() { + public boolean canSign() { return false; } + + @Override + public boolean canEncryptCommunication() { + return true; + } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/IllegalKeyFlagsTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/IllegalKeyFlagsTest.java new file mode 100644 index 00000000..852d6068 --- /dev/null +++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/IllegalKeyFlagsTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2021 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pgpainless.key.generation; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; +import org.pgpainless.PGPainless; +import org.pgpainless.algorithm.KeyFlag; +import org.pgpainless.key.generation.type.KeyType; +import org.pgpainless.key.generation.type.eddsa.EdDSACurve; +import org.pgpainless.key.generation.type.xdh.XDHCurve; + +public class IllegalKeyFlagsTest { + + @Test + public void testKeyCannotCarryFlagsTest() { + assertThrows(IllegalArgumentException.class, () -> PGPainless.generateKeyRing() + .withMasterKey(KeySpec.getBuilder(KeyType.XDH(XDHCurve._X25519)) + .withKeyFlags(KeyFlag.SIGN_DATA) // <- should throw + .withDefaultAlgorithms())); + + assertThrows(IllegalArgumentException.class, () -> PGPainless.generateKeyRing() + .withMasterKey(KeySpec.getBuilder(KeyType.XDH(XDHCurve._X25519)) + .withKeyFlags(KeyFlag.CERTIFY_OTHER) // <- should throw + .withDefaultAlgorithms())); + + assertThrows(IllegalArgumentException.class, () -> PGPainless.generateKeyRing() + .withMasterKey(KeySpec.getBuilder(KeyType.XDH(XDHCurve._X25519)) + .withKeyFlags(KeyFlag.AUTHENTICATION) // <- should throw + .withDefaultAlgorithms())); + + assertThrows(IllegalArgumentException.class, () -> PGPainless.generateKeyRing() + .withMasterKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519)) + .withKeyFlags(KeyFlag.ENCRYPT_COMMS) // <- should throw + .withDefaultAlgorithms())); + + assertThrows(IllegalArgumentException.class, () -> PGPainless.generateKeyRing() + .withMasterKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519)) + .withKeyFlags(KeyFlag.ENCRYPT_STORAGE) // <- should throw as well + .withDefaultAlgorithms())); + } +}