Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,81 +16,146 @@
* Annotation interface for marking and categorizing modifiable variables within a class.
*
* <p>This annotation provides metadata about a modifiable variable field, including its semantic
* type (what kind of data it represents) and format (how the data is encoded). This information can
* be used for reflection-based analysis, serialization, or other operations that need to understand
* the purpose of different variables.
*
* <p>//TODO This class has not been touched or used much for a while and needs refactoring.
* type (what kind of data it represents) and format (how the data is encoded). This information is
* used for reflection-based analysis, serialization, and testing scenarios.
*
* <p>The annotation is retained at runtime and can only be applied to fields.
*
* <p>Usage examples:
*
* <pre>{@code
* // Variable length field
* @ModifiableVariableProperty(purpose = Purpose.LENGTH, minLength = 1, maxLength = 4)
* private ModifiableInteger messageLength;
*
* // Signature with specific encoding and length
* @ModifiableVariableProperty(
* purpose = Purpose.SIGNATURE,
* encoding = Encoding.ASN1_DER,
* minLength = 70,
* maxLength = 73)
* private ModifiableByteArray digitalSignature;
*
* // Random value
* @ModifiableVariableProperty(purpose = Purpose.RANDOM)
* private ModifiableByteArray nonce;
*
* // Variable-length data with description
* @ModifiableVariableProperty(
* purpose = Purpose.PLAINTEXT,
* encoding = Encoding.UTF8,
* maxLength = 1024)
* private ModifiableByteArray applicationData;
* }</pre>
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ModifiableVariableProperty {

/**
* Semantic types that can be assigned to modifiable variables. These values describe the
* purpose or role of the variable.
* Semantic purpose categories for modifiable variables. These describe the role or function of
* the variable within any protocol or data structure.
*/
enum Type {
enum Purpose {
/** Variable representing a length field */
LENGTH,
/** Variable representing a count field */
/** Variable representing a count or quantity field */
COUNT,
/** Variable representing padding */
/** Variable representing padding or filler bytes */
PADDING,
/** Variable representing one or more (array of) TLS constants */
TLS_CONSTANT,
/** Variable representing a protocol constant or enumerated value */
CONSTANT,
/** Variable representing a cryptographic signature */
SIGNATURE,
/** Variable representing encrypted data */
/** Variable representing encrypted or ciphered data */
CIPHERTEXT,
/** Variable representing a message authentication code */
HMAC,
/** Variable representing a public key */
PUBLIC_KEY,
/** Variable representing a private key */
PRIVATE_KEY,
/** Variable representing key material */
/** Variable representing a message authentication code or hash */
MAC,
/** Variable representing cryptographic key material */
KEY_MATERIAL,
/** Variable representing a certificate */
CERTIFICATE,
/** Variable representing a plain protocol message, always in a decrypted state */
PLAIN_PROTOCOL_MESSAGE,
/** Variable representing a plain record */
PLAIN_RECORD,
/** Variable representing a cookie */
COOKIE,
/** Default type when no specific type is applicable */
NONE,
/** Variable that switches behavior */
BEHAVIOR_SWITCH
/** Variable representing plaintext protocol data */
PLAINTEXT,
/** Variable representing a random value, nonce, or salt */
RANDOM,
/** Variable representing a session or connection identifier */
IDENTIFIER,
/** Variable representing a timestamp or temporal value */
TIMESTAMP,
/** Default purpose when no specific category applies */
UNSPECIFIED
}

/**
* Encoding formats that can be used for modifiable variables. These values describe how the
* data is encoded.
* Encoding formats for modifiable variables. These describe how the data is encoded,
* structured, or represented.
*/
enum Format {
/** ASN.1 encoding format */
ASN1,
/** PKCS#1 encoding format */
enum Encoding {
/** ASN.1 Distinguished Encoding Rules format */
ASN1_DER,
/** ASN.1 Basic Encoding Rules format */
ASN1_BER,
/** PKCS#1 format for RSA key encoding */
PKCS1,
/** Default format when no specific format is applicable */
NONE
/** PKCS#8 format for private key information */
PKCS8,
/** X.509 format for certificates */
X509,
/** PEM (Privacy-Enhanced Mail) text format */
PEM,
/** Base64 text encoding */
BASE64,
/** Hexadecimal string representation */
HEX_STRING,
/** Raw binary data */
BINARY,
/** UTF-8 text encoding */
UTF8,
/** Unsigned big-endian encoding */
UNSIGNED_BIG_ENDIAN,
/** Unsigned little-endian encoding */
UNSIGNED_LITTLE_ENDIAN,
/** Signed big-endian encoding */
SIGNED_BIG_ENDIAN,
/** Signed little-endian encoding */
SIGNED_LITTLE_ENDIAN,

/** JSON text format */
JSON,
/** XML text format */
XML,
/** Default encoding when not specified */
UNSPECIFIED
}

/**
* Specifies the semantic type of the annotated variable.
* Specifies the semantic purpose of the annotated variable.
*
* @return The type of the variable
* @return The purpose category of the variable
*/
Type type() default Type.NONE;
Purpose purpose() default Purpose.UNSPECIFIED;

/**
* Specifies the encoding format of the annotated variable.
*
* @return The format of the variable
* @return The encoding format of the variable
*/
Encoding encoding() default Encoding.UNSPECIFIED;

/**
* Specifies the minimum length (in bytes) of the variable's value. Use -1 to indicate no
* minimum constraint.
*
* @return The minimum length in bytes, or -1 if unconstrained
*/
int minLength() default -1;

/**
* Specifies the maximum length (in bytes) of the variable's value. Use -1 to indicate no
* maximum constraint.
*
* @return The maximum length in bytes, or -1 if unconstrained
*/
Format format() default Format.NONE;
int maxLength() default -1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@

import de.rub.nds.modifiablevariable.HoldsModifiableVariable;
import de.rub.nds.modifiablevariable.ModifiableVariable;
import de.rub.nds.modifiablevariable.ModifiableVariableProperty;
import de.rub.nds.modifiablevariable.ModifiableVariableProperty.Encoding;
import de.rub.nds.modifiablevariable.ModifiableVariableProperty.Purpose;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

Expand All @@ -23,6 +26,10 @@
* locate fields that are either of type ModifiableVariable or are annotated with {@link
* HoldsModifiableVariable}.
*
* <p>Additionally, this class provides specialized methods for working with the {@link
* ModifiableVariableProperty} annotation to categorize and analyze fields by their semantic
* meaning, encoding format, and protocol context.
*
* <p>This class cannot be instantiated and all methods are static.
*/
public final class ModifiableVariableAnalyzer {
Expand Down Expand Up @@ -205,4 +212,125 @@ public static List<ModifiableVariableListHolder> getAllModifiableVariableHolders
}
return result;
}

/**
* Retrieves all fields in a class hierarchy that are annotated with ModifiableVariableProperty.
*
* @param clazz The class to analyze
* @return A list of fields annotated with ModifiableVariableProperty
*/
public static List<Field> getAnnotatedFields(Class<?> clazz) {
List<Field> annotatedFields = new ArrayList<>();
Class<?> currentClass = clazz;

while (currentClass != null && currentClass != Object.class) {
for (Field field : currentClass.getDeclaredFields()) {
if (field.isAnnotationPresent(ModifiableVariableProperty.class)) {
annotatedFields.add(field);
}
}
currentClass = currentClass.getSuperclass();
}

return annotatedFields;
}

/**
* Groups annotated fields by their semantic purpose.
*
* @param clazz The class to analyze
* @return A map where keys are Purpose enum values and values are lists of fields
*/
public static Map<Purpose, List<Field>> groupFieldsByPurpose(Class<?> clazz) {
return getAnnotatedFields(clazz).stream()
.collect(
Collectors.groupingBy(
field ->
field.getAnnotation(ModifiableVariableProperty.class)
.purpose()));
}

/**
* Groups annotated fields by their encoding format.
*
* @param clazz The class to analyze
* @return A map where keys are Encoding enum values and values are lists of fields
*/
public static Map<Encoding, List<Field>> groupFieldsByEncoding(Class<?> clazz) {
return getAnnotatedFields(clazz).stream()
.collect(
Collectors.groupingBy(
field ->
field.getAnnotation(ModifiableVariableProperty.class)
.encoding()));
}

/**
* Finds all fields of a specific semantic purpose.
*
* @param clazz The class to analyze
* @param purpose The semantic purpose to search for
* @return A list of fields with the specified purpose
*/
public static List<Field> getFieldsByPurpose(Class<?> clazz, Purpose purpose) {
return getAnnotatedFields(clazz).stream()
.filter(
field ->
field.getAnnotation(ModifiableVariableProperty.class).purpose()
== purpose)
.collect(Collectors.toList());
}

/**
* Finds all fields with a specific encoding format.
*
* @param clazz The class to analyze
* @param encoding The encoding format to search for
* @return A list of fields with the specified encoding
*/
public static List<Field> getFieldsByEncoding(Class<?> clazz, Encoding encoding) {
return getAnnotatedFields(clazz).stream()
.filter(
field ->
field.getAnnotation(ModifiableVariableProperty.class).encoding()
== encoding)
.collect(Collectors.toList());
}

/**
* Checks if a field has a ModifiableVariableProperty annotation.
*
* @param field The field to check
* @return true if the field is annotated, false otherwise
*/
public static boolean isAnnotated(Field field) {
return field.isAnnotationPresent(ModifiableVariableProperty.class);
}

/**
* Gets the ModifiableVariableProperty annotation from a field.
*
* @param field The field to examine
* @return The annotation or null if not present
*/
public static ModifiableVariableProperty getAnnotation(Field field) {
return field.getAnnotation(ModifiableVariableProperty.class);
}

/**
* Validates that all ModifiableVariable fields in a class have proper annotations. This is
* useful for ensuring coding standards compliance.
*
* @param clazz The class to validate
* @return A list of field names that are ModifiableVariable but lack annotations
*/
public static List<String> getUnannotatedModifiableVariables(Class<?> clazz) {
List<Field> allModifiableFields =
ReflectionHelper.getFieldsUpTo(clazz, null, ModifiableVariable.class);

return allModifiableFields.stream()
.filter(field -> !isAnnotated(field))
.map(Field::getName)
.collect(Collectors.toList());
}
}
Loading