92 lines
4.2 KiB
Kotlin
92 lines
4.2 KiB
Kotlin
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package org.pgpainless.decryption_verification.syntax_check
|
|
|
|
import org.pgpainless.exception.MalformedOpenPgpMessageException
|
|
|
|
/**
|
|
* This class describes the syntax for OpenPGP messages as specified by rfc4880.
|
|
*
|
|
* See [rfc4880 - §11.3. OpenPGP Messages](https://www.rfc-editor.org/rfc/rfc4880#section-11.3) See
|
|
* [Blog post about theoretic background and translation of grammar to PDA syntax](https://blog.jabberhead.tk/2022/09/14/using-pushdown-automata-to-verify-packet-sequences/)
|
|
* See
|
|
* [Blog post about practically implementing the PDA for packet syntax validation](https://blog.jabberhead.tk/2022/10/26/implementing-packet-sequence-validation-using-pushdown-automata/)
|
|
*/
|
|
class OpenPgpMessageSyntax : Syntax {
|
|
|
|
override fun transition(from: State, input: InputSymbol, stackItem: StackSymbol?): Transition {
|
|
return when (from) {
|
|
State.OPENPGP_MESSAGE -> fromOpenPgpMessage(input, stackItem)
|
|
State.LITERAL_MESSAGE -> fromLiteralMessage(input, stackItem)
|
|
State.COMPRESSED_MESSAGE -> fromCompressedMessage(input, stackItem)
|
|
State.ENCRYPTED_MESSAGE -> fromEncryptedMessage(input, stackItem)
|
|
State.VALID -> fromValid(input, stackItem)
|
|
else -> throw MalformedOpenPgpMessageException(from, input, stackItem)
|
|
}
|
|
}
|
|
|
|
fun fromOpenPgpMessage(input: InputSymbol, stackItem: StackSymbol?): Transition {
|
|
if (stackItem !== StackSymbol.MSG) {
|
|
throw MalformedOpenPgpMessageException(State.OPENPGP_MESSAGE, input, stackItem)
|
|
}
|
|
return when (input) {
|
|
InputSymbol.LITERAL_DATA -> Transition(State.LITERAL_MESSAGE)
|
|
InputSymbol.SIGNATURE -> Transition(State.OPENPGP_MESSAGE, StackSymbol.MSG)
|
|
InputSymbol.ONE_PASS_SIGNATURE ->
|
|
Transition(State.OPENPGP_MESSAGE, StackSymbol.OPS, StackSymbol.MSG)
|
|
InputSymbol.COMPRESSED_DATA -> Transition(State.COMPRESSED_MESSAGE)
|
|
InputSymbol.ENCRYPTED_DATA -> Transition(State.ENCRYPTED_MESSAGE)
|
|
InputSymbol.END_OF_SEQUENCE ->
|
|
throw MalformedOpenPgpMessageException(State.OPENPGP_MESSAGE, input, stackItem)
|
|
else -> throw MalformedOpenPgpMessageException(State.OPENPGP_MESSAGE, input, stackItem)
|
|
}
|
|
}
|
|
|
|
@Throws(MalformedOpenPgpMessageException::class)
|
|
fun fromLiteralMessage(input: InputSymbol, stackItem: StackSymbol?): Transition {
|
|
if (input == InputSymbol.SIGNATURE && stackItem == StackSymbol.OPS) {
|
|
return Transition(State.LITERAL_MESSAGE)
|
|
}
|
|
if (input == InputSymbol.END_OF_SEQUENCE && stackItem == StackSymbol.TERMINUS) {
|
|
return Transition(State.VALID)
|
|
}
|
|
|
|
throw MalformedOpenPgpMessageException(State.LITERAL_MESSAGE, input, stackItem)
|
|
}
|
|
|
|
@Throws(MalformedOpenPgpMessageException::class)
|
|
fun fromCompressedMessage(input: InputSymbol, stackItem: StackSymbol?): Transition {
|
|
if (input == InputSymbol.SIGNATURE && stackItem == StackSymbol.OPS) {
|
|
return Transition(State.COMPRESSED_MESSAGE)
|
|
}
|
|
if (input == InputSymbol.END_OF_SEQUENCE && stackItem == StackSymbol.TERMINUS) {
|
|
return Transition(State.VALID)
|
|
}
|
|
|
|
throw MalformedOpenPgpMessageException(State.COMPRESSED_MESSAGE, input, stackItem)
|
|
}
|
|
|
|
@Throws(MalformedOpenPgpMessageException::class)
|
|
fun fromEncryptedMessage(input: InputSymbol, stackItem: StackSymbol?): Transition {
|
|
if (input == InputSymbol.SIGNATURE && stackItem == StackSymbol.OPS) {
|
|
return Transition(State.ENCRYPTED_MESSAGE)
|
|
}
|
|
if (input == InputSymbol.END_OF_SEQUENCE && stackItem == StackSymbol.TERMINUS) {
|
|
return Transition(State.VALID)
|
|
}
|
|
|
|
throw MalformedOpenPgpMessageException(State.ENCRYPTED_MESSAGE, input, stackItem)
|
|
}
|
|
|
|
@Throws(MalformedOpenPgpMessageException::class)
|
|
fun fromValid(input: InputSymbol, stackItem: StackSymbol?): Transition {
|
|
if (input == InputSymbol.END_OF_SEQUENCE) {
|
|
// allow subsequent read() calls.
|
|
return Transition(State.VALID)
|
|
}
|
|
throw MalformedOpenPgpMessageException(State.VALID, input, stackItem)
|
|
}
|
|
}
|