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