1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-24 11:57:59 +01:00

Sanitize key flags

This commit is contained in:
Paul Schaub 2024-02-22 13:58:47 +01:00
parent 61c6c2116a
commit 6cfeba064e
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
2 changed files with 131 additions and 42 deletions

View file

@ -20,6 +20,7 @@ import org.pgpainless.algorithm.AlgorithmSuite
import org.pgpainless.algorithm.CertificationType
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.algorithm.PublicKeyAlgorithm
import org.pgpainless.implementation.ImplementationFactory
import org.pgpainless.key.generation.DefinePrimaryKey.PrimaryKeyBuilder
import org.pgpainless.key.generation.DefineSubkeys.SubkeyBuilder
@ -169,7 +170,13 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
keyFlags: List<KeyFlag>? = listOf(KeyFlag.CERTIFY_OTHER),
creationTime: Date = this.creationTime,
block: PrimaryKeyBlock? = null
): O = doSetPrimaryKey(type, keyFlags, creationTime, block)
): O {
require(type.canCertify) {
"Primary key cannot use algorithm ${type.algorithm} because it needs to be " +
"signing capable."
}
return doSetPrimaryKey(type, keyFlags, creationTime, block)
}
fun setPrimaryKey(type: KeyType, block: PrimaryKeyBlock?): O =
setPrimaryKey(type, listOf(KeyFlag.CERTIFY_OTHER), this.creationTime, block)
@ -200,6 +207,10 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
// Do nothing
}
protected open fun sanitizeKeyFlags(algorithm: PublicKeyAlgorithm, keyFlags: List<KeyFlag>?) {
// Do nothing
}
/**
* Function that can be applied to the primary key.
*
@ -407,14 +418,23 @@ internal constructor(
@JvmOverloads
fun addSubkey(
type: KeyType,
flags: List<KeyFlag>? = null,
creationTime: Date = this.creationTime,
block: SubkeyBlock? = null
): B =
apply {
sanitizeKeyFlags(type.algorithm, flags)
sanitizeSubkeyCreationTime(creationTime, primaryKey)
var subkey = generateSubkey(type, creationTime)
subkey = invokeOnSubkey(subkey, block)
val subkeyBlock =
block
?: {
addBindingSignature(
SelfSignatureSubpackets.applyHashed { flags?.let { setKeyFlags(it) } },
bindingTime = creationTime)
}
subkey = invokeOnSubkey(subkey, subkeyBlock)
subkeys.add(subkey)
}
as B
@ -490,6 +510,10 @@ internal constructor(
// Do nothing
}
protected open fun sanitizeKeyFlags(algorithm: PublicKeyAlgorithm, keyFlags: List<KeyFlag>?) {
// Do nothing
}
/**
* Function that can be applied to subkeys.
*
@ -723,8 +747,6 @@ internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmS
creationTime: Date,
block: PrimaryKeyBlock?
): OpinionatedDefineSubkeysV4 {
// Check algorithm is signing capable
require(type.algorithm.isSigningCapable()) { "Primary Key MUST be capable of signing." }
// Check key strength
require(policy.publicKeyAlgorithmPolicy.isAcceptable(type.algorithm, type.bitStrength)) {
@ -732,6 +754,9 @@ internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmS
" for the current public key algorithm policy."
}
// Sanitize key flags
sanitizeKeyFlags(type.algorithm, keyFlags)
// Remember flags for DK and UID signatures
this.keyFlags = keyFlags
@ -762,6 +787,27 @@ internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmS
"key was created at ${primaryKey.publicKey.creationTime.formatUTC()}."
}
}
override fun sanitizeKeyFlags(algorithm: PublicKeyAlgorithm, keyFlags: List<KeyFlag>?) {
keyFlags?.forEach { flag ->
when (flag) {
KeyFlag.CERTIFY_OTHER,
KeyFlag.SIGN_DATA,
KeyFlag.AUTHENTICATION ->
require(algorithm.isSigningCapable()) {
"Primary key cannot carry key flag $flag because the " +
"algorithm $algorithm is not signing capable."
}
KeyFlag.ENCRYPT_COMMS,
KeyFlag.ENCRYPT_STORAGE ->
require(algorithm.isEncryptionCapable()) {
"Primary key cannot carry key flag $flag because the " +
"algorithm $algorithm is not encryption capable."
}
else -> {} // no special requirements for SPLIT and SHARED
}
}
}
}
/**
@ -842,11 +888,10 @@ internal constructor(primaryKey: PGPKeyPair, policy: Policy, creationTime: Date)
fun addSigningSubkey(
type: KeyType,
creationTime: Date = this.creationTime,
block: SubkeyBlock? = {
addBindingSignature(
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.SIGN_DATA) })
}
) = addSubkey(type, creationTime, block)
block: SubkeyBlock? = null
): OpinionatedDefineSubkeysV4 {
return addSubkey(type, listOf(KeyFlag.SIGN_DATA), creationTime, block)
}
/**
* Add a subkey for signing messages to the OpenPGP key.
@ -868,13 +913,11 @@ internal constructor(primaryKey: PGPKeyPair, policy: Policy, creationTime: Date)
fun addEncryptionSubkey(
type: KeyType,
creationTime: Date = this.creationTime,
block: SubkeyBlock? = {
addBindingSignature(
SelfSignatureSubpackets.applyHashed {
setKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
})
}
) = addSubkey(type, creationTime, block)
block: SubkeyBlock? = null,
): OpinionatedDefineSubkeysV4 {
return addSubkey(
type, listOf(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE), creationTime, block)
}
/**
* Add a subkey for message encryption to the OpenPGP key.
@ -907,6 +950,27 @@ internal constructor(primaryKey: PGPKeyPair, policy: Policy, creationTime: Date)
"Primary key was created at ${primaryKey.publicKey.creationTime.formatUTC()}."
}
}
override fun sanitizeKeyFlags(algorithm: PublicKeyAlgorithm, keyFlags: List<KeyFlag>?) {
keyFlags?.forEach { flag ->
when (flag) {
KeyFlag.CERTIFY_OTHER,
KeyFlag.SIGN_DATA,
KeyFlag.AUTHENTICATION ->
require(algorithm.isSigningCapable()) {
"Subkey cannot carry key flag $flag because the " +
"algorithm $algorithm is not signing capable."
}
KeyFlag.ENCRYPT_COMMS,
KeyFlag.ENCRYPT_STORAGE ->
require(algorithm.isEncryptionCapable()) {
"Subkey cannot carry key flag $flag because the " +
"algorithm $algorithm is not encryption capable."
}
else -> {} // no special requirements for SPLIT and SHARED
}
}
}
}
/**
@ -1078,17 +1142,9 @@ class OpenPgpKeyTemplates private constructor() {
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.CERTIFY_OTHER) })
}
// singing key
.addSubkey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addBindingSignature(
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.SIGN_DATA) })
}
.addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))
// encryption key
.addSubkey(KeyType.XDH(XDHSpec._X25519)) {
addBindingSignature(
SelfSignatureSubpackets.applyHashed {
setKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
})
}
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
.build()
/**
@ -1122,17 +1178,9 @@ class OpenPgpKeyTemplates private constructor() {
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.CERTIFY_OTHER) })
}
// signing key
.addSubkey(KeyType.RSA(length)) {
addBindingSignature(
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.SIGN_DATA) })
}
.addSigningSubkey(KeyType.RSA(length))
// encryption key
.addSubkey(KeyType.RSA(length)) {
addBindingSignature(
SelfSignatureSubpackets.applyHashed {
setKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
})
}
.addEncryptionSubkey(KeyType.RSA(length))
.build()
/**

View file

@ -109,10 +109,7 @@ class OpenPgpKeyGeneratorTest {
val key =
OpenPgpKeyGenerator.buildV4Key()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
addBindingSignature(
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.SIGN_DATA) })
}
.addSubkey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.SIGN_DATA))
.build()
assertFalse(
@ -376,7 +373,7 @@ class OpenPgpKeyGeneratorTest {
assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy, t1)
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey(KeyType.XDH(XDHSpec._X25519), t0)
.addSubkey(KeyType.XDH(XDHSpec._X25519), null, t0)
}
}
@ -389,7 +386,7 @@ class OpenPgpKeyGeneratorTest {
OpenPgpKeyGenerator.buildV4Key(policy, t1)
.unopinionated()
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey(KeyType.XDH(XDHSpec._X25519), t0)
.addSubkey(KeyType.XDH(XDHSpec._X25519), null, t0)
}
@Test
@ -442,6 +439,50 @@ class OpenPgpKeyGeneratorTest {
}
}
@Test
fun `opinionated set primary key to encryption key fails`() {
val policy = Policy()
assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy).setPrimaryKey(KeyType.XDH(XDHSpec._X25519))
}
}
@Test
fun `opinionated set primary key to sign-only algorithm but with encryption flag fails`() {
val policy = Policy()
assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy)
.setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519),
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.ENCRYPT_STORAGE))
}
}
@Test
fun `unopinionated set primary key to sign-only algorithm but with encryption flag is okay`() {
val policy = Policy()
OpenPgpKeyGenerator.buildV4Key(policy)
.unopinionated()
.setPrimaryKey(
KeyType.EDDSA(EdDSACurve._Ed25519),
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.ENCRYPT_STORAGE))
}
@Test
fun `opinionated add encryption-only subkey with additional sign flag fails`() {
val policy = Policy()
assertThrows<IllegalArgumentException> {
OpenPgpKeyGenerator.buildV4Key(policy)
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
.addSubkey(
KeyType.XDH(XDHSpec._X25519), listOf(KeyFlag.ENCRYPT_COMMS, KeyFlag.SIGN_DATA))
}
}
@Test
fun `add image attribute to key`() {
// smallest JPEG according to https://stackoverflow.com/a/2349470/11150851