mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-24 11:57:59 +01:00
Enforce key capabilities for primary key and add tests
This commit is contained in:
parent
378890f83a
commit
f384ce84be
4 changed files with 47 additions and 34 deletions
|
@ -59,10 +59,7 @@ enum class PublicKeyAlgorithm(
|
|||
/** Diffie-Hellman key exchange algorithm. */
|
||||
DIFFIE_HELLMAN(21, false, true),
|
||||
|
||||
/**
|
||||
* Digital Signature Algorithm based on twisted Edwards Curves.
|
||||
* For OpenPGP v4 only.
|
||||
*/
|
||||
/** Digital Signature Algorithm based on twisted Edwards Curves. For OpenPGP v4 only. */
|
||||
EDDSA(22, true, false),
|
||||
;
|
||||
|
||||
|
|
|
@ -35,9 +35,7 @@ open class GenerateOpenPgpKey(
|
|||
private val preferences: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
|
||||
) {
|
||||
|
||||
/**
|
||||
* Builder for OpenPGP secret keys.
|
||||
*/
|
||||
/** Builder for OpenPGP secret keys. */
|
||||
abstract class OpenPgpKeyBuilder(
|
||||
protected val policy: Policy,
|
||||
protected val referenceTime: Date,
|
||||
|
@ -96,6 +94,9 @@ open class GenerateOpenPgpKey(
|
|||
) : OpenPgpKeyBuilder(policy, referenceTime, preferences) {
|
||||
|
||||
init {
|
||||
require(primaryKeyType.canCertify) {
|
||||
"KeyType $primaryKeyType MUST be certification capable."
|
||||
}
|
||||
sanitizePublicKeyAlgorithms(primaryKeyType, policy)
|
||||
}
|
||||
|
||||
|
@ -203,9 +204,8 @@ open class GenerateOpenPgpKey(
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a new subkey to be used for encryption.
|
||||
* The binding signature will mark the key as encryption-capable using both
|
||||
* [KeyFlag.ENCRYPT_COMMS] and [KeyFlag.ENCRYPT_STORAGE].
|
||||
* Add a new subkey to be used for encryption. The binding signature will mark the key as
|
||||
* encryption-capable using both [KeyFlag.ENCRYPT_COMMS] and [KeyFlag.ENCRYPT_STORAGE].
|
||||
*
|
||||
* @param keyType type of the encryption subkey
|
||||
* @param creationTime time of creation of the subkey
|
||||
|
@ -224,13 +224,12 @@ open class GenerateOpenPgpKey(
|
|||
keyType,
|
||||
creationTime,
|
||||
bindingTime,
|
||||
listOf(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)
|
||||
)
|
||||
listOf(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS))
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new subkey to be used for creating data signatures.
|
||||
* The binding signature will mark the key as signing-capable using [KeyFlag.SIGN_DATA].
|
||||
* Add a new subkey to be used for creating data signatures. The binding signature will mark
|
||||
* the key as signing-capable using [KeyFlag.SIGN_DATA].
|
||||
*
|
||||
* @param keyType type of the signing subkey
|
||||
* @param creationTime time of creation of the subkey
|
||||
|
@ -242,20 +241,17 @@ open class GenerateOpenPgpKey(
|
|||
creationTime: Date = referenceTime,
|
||||
bindingTime: Date = creationTime
|
||||
) = apply {
|
||||
require(keyType.canSign) {
|
||||
"KeyType $keyType cannot be used for signing keys."
|
||||
}
|
||||
require(keyType.canSign) { "KeyType $keyType cannot be used for signing keys." }
|
||||
addSubkey(keyType, creationTime, bindingTime, listOf(KeyFlag.SIGN_DATA))
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the finished OpenPGP key.
|
||||
* By default, the key will not be protected using passphrases.
|
||||
* To set a passphrase, you can provide [SecretKeyRingProtector.unlockAnyKeyWith] with
|
||||
* a passphrase of your choice.
|
||||
* Build the finished OpenPGP key. By default, the key will not be protected using
|
||||
* passphrases. To set a passphrase, you can provide
|
||||
* [SecretKeyRingProtector.unlockAnyKeyWith] with a passphrase of your choice.
|
||||
*
|
||||
* @param protector protector to secure the secret keys using passphrases.
|
||||
* Defaults to [SecretKeyRingProtector.unprotectedKeys].
|
||||
* @param protector protector to secure the secret keys using passphrases. Defaults to
|
||||
* [SecretKeyRingProtector.unprotectedKeys].
|
||||
* @return OpenPGP Secret Key
|
||||
*/
|
||||
fun build(
|
||||
|
|
|
@ -37,10 +37,8 @@ class OpenPgpComponentKeyBuilder {
|
|||
|
||||
internal var key = generateKeyPair()
|
||||
|
||||
fun subkey(
|
||||
type: KeyType,
|
||||
creationTime: Date = certificateCreationTime
|
||||
): V4SubkeyBuilder = V4SubkeyBuilder(type, creationTime, policy, primaryKey())
|
||||
fun subkey(type: KeyType, creationTime: Date = certificateCreationTime): V4SubkeyBuilder =
|
||||
V4SubkeyBuilder(type, creationTime, policy, primaryKey())
|
||||
|
||||
internal abstract fun primaryKey(): V4PrimaryKeyBuilder
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
package org.pgpainless.key.generation
|
||||
|
||||
import java.io.InputStream
|
||||
import org.bouncycastle.bcpg.attr.ImageAttribute
|
||||
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVectorGenerator
|
||||
import org.bouncycastle.util.io.Streams
|
||||
import org.junit.jupiter.api.Assertions.assertArrayEquals
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
|
@ -33,11 +31,6 @@ class GenerateOpenPgpKeyTest {
|
|||
GenerateOpenPgpKey(Policy.getInstance(), date)
|
||||
.buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER))
|
||||
.addUserId("Alice")
|
||||
.addUserAttribute(
|
||||
PGPUserAttributeSubpacketVectorGenerator()
|
||||
.apply { setImageAttribute(ImageAttribute.JPEG, byteArrayOf()) }
|
||||
.generate(),
|
||||
)
|
||||
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
|
||||
.addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||
.build(SecretKeyRingProtector.unprotectedKeys())
|
||||
|
@ -63,6 +56,35 @@ class GenerateOpenPgpKeyTest {
|
|||
println(PGPainless.asciiArmor(key))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun primaryKeyMustBeCertificationCapable() {
|
||||
assertThrows<IllegalArgumentException> {
|
||||
GenerateOpenPgpKey(Policy.getInstance())
|
||||
.buildV4Key(
|
||||
KeyType.XDH(XDHSpec._X25519)) // XDH is not signing/certification capable
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun encryptionSubkeyMustBeEncryptionCapable() {
|
||||
val builder =
|
||||
GenerateOpenPgpKey(Policy.getInstance()).buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||
|
||||
assertThrows<IllegalArgumentException> {
|
||||
builder.addEncryptionSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun signingSubkeysMustBeSigningCapable() {
|
||||
val builder =
|
||||
GenerateOpenPgpKey(Policy.getInstance()).buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||
|
||||
assertThrows<IllegalArgumentException> {
|
||||
builder.addSigningSubkey(KeyType.XDH(XDHSpec._X25519))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKeyGenerationWithUnacceptablePKAlgorithmFails() {
|
||||
// Policy only allows RSA 4096 algorithms
|
||||
|
|
Loading…
Reference in a new issue