1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-10 18:59:39 +02:00

Compare commits

..

20 commits

Author SHA1 Message Date
7daa3783bc
Fuzz PGPObjectFactory 2025-07-23 11:27:02 +02:00
4d46edf3b6
Add fuzzer test for generate-key for testing fuzzed passphrases and user-ids 2025-07-23 11:27:01 +02:00
7656bcd101
key packet fuzzing tests: Use OpenPGPKey/OpenPGPCertificate API 2025-07-23 11:27:01 +02:00
9f8ce475eb
Replace consumeAsBytes(XXX) with consumeRemainingAsBytes() 2025-07-23 11:27:01 +02:00
4f8c52d215
Fix IndexOutOfBounds, but keep decryption with only SK working 2025-07-23 11:27:01 +02:00
16a2bf27eb
gitignore all .cifuzz-corpus directories 2025-07-23 11:27:01 +02:00
742f8fa1a3
Move jazzerVersion to version.gradle 2025-07-23 11:27:00 +02:00
916809ad60
More fuzzing tests and vectors 2025-07-23 11:27:00 +02:00
002bd87136
Even more fuzzing 2025-07-23 11:27:00 +02:00
05cea3e5a9
More fuzzing 2025-07-23 11:27:00 +02:00
95eb73a8c7
Add more test vectors 2025-07-23 11:27:00 +02:00
06b3452c6c
Add fuzzing data to REUSE.toml 2025-07-23 11:27:00 +02:00
307b3ae40b
Fuzzer tests 2025-07-23 11:26:59 +02:00
0d8ce6a50b
Fuzz different methods 2025-07-23 11:26:59 +02:00
32dc1fa1a1
Add pgpainless-sop/.cifuzz-corpus/* to .gitignore 2025-07-23 11:26:59 +02:00
4a4f85767a
SOP armor: catch IOException during inspection of data 2025-07-23 11:26:59 +02:00
d1826eb961
OpenPGPInputStream: Expose inspectBuffer method 2025-07-23 11:26:59 +02:00
0d807cb6b8
Fix typo in error message 2025-07-23 11:26:40 +02:00
9b0a3cd4c7
Do not trim passphrases automatically 2025-07-23 11:26:28 +02:00
0ee31b232a
Allow UserIDs with trailing/leading whitespace and escape newlines in ASCII armor 2025-07-23 11:26:17 +02:00
5 changed files with 22 additions and 15 deletions

View file

@ -45,9 +45,6 @@ class KeyRingBuilder : KeyRingBuilderInterface<KeyRingBuilder> {
} }
override fun addUserId(userId: CharSequence): KeyRingBuilder = apply { override fun addUserId(userId: CharSequence): KeyRingBuilder = apply {
require(!userId.contains("\n") && !userId.contains("\r")) {
"User-ID cannot contain newlines and/or carriage returns."
}
userIds[userId.toString()] = null userIds[userId.toString()] = null
} }

View file

@ -569,11 +569,10 @@ class SecretKeyRingEditor(
} }
private fun sanitizeUserId(userId: CharSequence): CharSequence = private fun sanitizeUserId(userId: CharSequence): CharSequence =
userId.toString().also { // I'm not sure, what kind of sanitization is needed.
require(!it.contains("\n") && !it.contains("\r")) { // Newlines are allowed, they just need to be escaped when emitted in an ASCII armor header
"UserId cannot contain newlines and/or carriage returns." // Trailing/Leading whitespace is also fine.
} userId.toString()
}
private fun callbackFromRevocationAttributes(attributes: RevocationAttributes?) = private fun callbackFromRevocationAttributes(attributes: RevocationAttributes?) =
object : RevocationSignatureSubpackets.Callback { object : RevocationSignatureSubpackets.Callback {

View file

@ -247,7 +247,8 @@ class ArmorUtils {
.add(OpenPgpFingerprint.of(publicKey).prettyPrint()) .add(OpenPgpFingerprint.of(publicKey).prettyPrint())
// Primary / First User ID // Primary / First User ID
(primary ?: first)?.let { (primary ?: first)?.let {
headerMap.getOrPut(HEADER_COMMENT) { mutableSetOf() }.add(it) headerMap.getOrPut(HEADER_COMMENT) { mutableSetOf() }
.add(it.replace("\n", "\\n").replace("\r", "\\r"))
} }
// X-1 further identities // X-1 further identities
when (userIds.size) { when (userIds.size) {

View file

@ -11,14 +11,9 @@ import org.bouncycastle.util.Arrays
* *
* @param chars may be null for empty passwords. * @param chars may be null for empty passwords.
*/ */
class Passphrase(chars: CharArray?) { class Passphrase(private val chars: CharArray?) {
private val lock = Any() private val lock = Any()
private var valid = true private var valid = true
private val chars: CharArray?
init {
this.chars = chars;//trimWhitespace(chars)
}
/** /**
* Return a copy of the underlying char array. A return value of null represents an empty * Return a copy of the underlying char array. A return value of null represents an empty
@ -67,6 +62,11 @@ class Passphrase(chars: CharArray?) {
override fun hashCode(): Int = getChars()?.let { String(it) }.hashCode() override fun hashCode(): Int = getChars()?.let { String(it) }.hashCode()
/**
* Return a copy of this [Passphrase], but with whitespace characters trimmed off.
*
* @return copy with trimmed whitespace
*/
fun withTrimmedWhitespace(): Passphrase = Passphrase(trimWhitespace(chars)) fun withTrimmedWhitespace(): Passphrase = Passphrase(trimWhitespace(chars))
companion object { companion object {

View file

@ -100,4 +100,14 @@ public class GenerateKeyTest {
assertThrows(SOPGPException.UnsupportedProfile.class, () -> assertThrows(SOPGPException.UnsupportedProfile.class, () ->
sop.generateKey().profile("invalid")); sop.generateKey().profile("invalid"));
} }
@Test
public void generateKeyWithNewlinesInUserId() throws IOException {
byte[] keyBytes = sop.generateKey()
.userId("Foo\n\nBar")
.generate()
.getBytes();
assertTrue(new String(keyBytes).contains("Foo\\n\\nBar"));
}
} }