Skip to content

Commit

Permalink
detect/base64: Use Rust defined modes everywhere
Browse files Browse the repository at this point in the history
Issue: 6487

To avoid ambiguity, a single definition for base 64 decoding modes will
be used. The Rust base64 transform contains the definitions for the
existing mode types: Strict, RFC2045, RFC4648
  • Loading branch information
jlucovsky authored and victorjulien committed Jun 22, 2024
1 parent 01e20c9 commit 5b97f40
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 55 deletions.
37 changes: 33 additions & 4 deletions rust/src/detect/transform_base64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,39 @@ use std::str;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DetectBase64Mode {
Base64ModeRelax = 0,
Base64ModeRFC2045,
/* If the following strings were to be passed to the decoder with RFC2045 mode,
* the results would be as follows. See the unittest B64TestVectorsRFC2045 in
* src/util-base64.c
*
* BASE64("") = ""
* BASE64("f") = "Zg=="
* BASE64("fo") = "Zm8="
* BASE64("foo") = "Zm9v"
* BASE64("foob") = "Zm9vYg=="
* BASE64("fooba") = "Zm9vYmE="
* BASE64("foobar") = "Zm9vYmFy"
* BASE64("foobar") = "Zm 9v Ym Fy" <-- Notice how the spaces are ignored
* BASE64("foobar") = "Zm$9vYm.Fy" # According to RFC 2045, All line breaks or *other
* characters* not found in base64 alphabet must be ignored by decoding software
* */
Base64ModeRFC2045, /* SPs are allowed during transfer but must be skipped by Decoder */
Base64ModeStrict,
Base64ModeRFC4648,
/* If the following strings were to be passed to the decoder with RFC4648 mode,
* the results would be as follows. See the unittest B64TestVectorsRFC4648 in
* src/util-base64.c
*
* BASE64("") = ""
* BASE64("f") = "Zg=="
* BASE64("fo") = "Zm8="
* BASE64("foo") = "Zm9v"
* BASE64("foob") = "Zm9vYg=="
* BASE64("fooba") = "Zm9vYmE="
* BASE64("foobar") = "Zm9vYmFy"
* BASE64("f") = "Zm 9v Ym Fy" <-- Notice how the processing stops once space is encountered
* BASE64("f") = "Zm$9vYm.Fy" <-- Notice how the processing stops once an invalid char is
* encountered
* */
Base64ModeRFC4648, /* reject the encoded data if it contains characters outside the base alphabet */
}

pub const TRANSFORM_FROM_BASE64_MODE_DEFAULT: DetectBase64Mode = DetectBase64Mode::Base64ModeRFC4648;
Expand Down Expand Up @@ -120,8 +150,7 @@ fn parse_transform_base64(
)(input)?;

// Too many options?
if values.len() > DETECT_TRANSFORM_BASE64_MAX_PARAM_COUNT
{
if values.len() > DETECT_TRANSFORM_BASE64_MAX_PARAM_COUNT {
return Err(make_error(format!("Incorrect argument string; at least 1 value must be specified but no more than {}: {:?}",
DETECT_TRANSFORM_BASE64_MAX_PARAM_COUNT, input)));
}
Expand Down
7 changes: 4 additions & 3 deletions src/datasets.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "suricata-common.h"
#include "suricata.h"
#include "rust.h"
#include "conf.h"
#include "datasets.h"
#include "datasets-string.h"
Expand Down Expand Up @@ -522,7 +523,7 @@ static int DatasetLoadString(Dataset *set)
uint8_t decoded[strlen(line)];
uint32_t consumed = 0, num_decoded = 0;
Base64Ecode code = DecodeBase64(decoded, strlen(line), (const uint8_t *)line,
strlen(line), &consumed, &num_decoded, BASE64_MODE_STRICT);
strlen(line), &consumed, &num_decoded, Base64ModeStrict);
if (code == BASE64_ECODE_ERR) {
FatalErrorOnInit("bad base64 encoding %s/%s", set->name, set->load);
continue;
Expand All @@ -543,7 +544,7 @@ static int DatasetLoadString(Dataset *set)
uint8_t decoded[strlen(line)];
uint32_t consumed = 0, num_decoded = 0;
Base64Ecode code = DecodeBase64(decoded, strlen(line), (const uint8_t *)line,
strlen(line), &consumed, &num_decoded, BASE64_MODE_STRICT);
strlen(line), &consumed, &num_decoded, Base64ModeStrict);
if (code == BASE64_ECODE_ERR) {
FatalErrorOnInit("bad base64 encoding %s/%s", set->name, set->load);
continue;
Expand Down Expand Up @@ -1606,7 +1607,7 @@ static int DatasetOpSerialized(Dataset *set, const char *string, DatasetOpFunc D
uint8_t decoded[strlen(string)];
uint32_t consumed = 0, num_decoded = 0;
Base64Ecode code = DecodeBase64(decoded, strlen(string), (const uint8_t *)string,
strlen(string), &consumed, &num_decoded, BASE64_MODE_STRICT);
strlen(string), &consumed, &num_decoded, Base64ModeStrict);
if (code == BASE64_ECODE_ERR) {
return -2;
}
Expand Down
2 changes: 1 addition & 1 deletion src/detect-base64-decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ int DetectBase64DecodeDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s

uint32_t consumed = 0, num_decoded = 0;
(void)DecodeBase64(det_ctx->base64_decoded, det_ctx->base64_decoded_len_max, payload,
decode_len, &consumed, &num_decoded, BASE64_MODE_RFC4648);
decode_len, &consumed, &num_decoded, Base64ModeRFC4648);
det_ctx->base64_decoded_len = num_decoded;
SCLogDebug("Decoded %d bytes from base64 data.",
det_ctx->base64_decoded_len);
Expand Down
2 changes: 1 addition & 1 deletion src/tests/fuzz/fuzz_decodebase64.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ static void Base64FuzzTest(const uint8_t *src, size_t len, size_t dest_size)
if (dest == NULL)
return;

for (uint8_t mode = BASE64_MODE_RELAX; mode <= BASE64_MODE_RFC4648; mode++) {
for (uint8_t mode = Base64ModeRelax; mode <= Base64ModeRFC4648; mode++) {
uint32_t consumed_bytes = 0;
uint32_t decoded_bytes = 0;

Expand Down
14 changes: 7 additions & 7 deletions src/util-base64.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,19 +274,19 @@ static inline Base64Ecode DecodeBase64RFC4648(uint8_t *dest, uint32_t dest_size,
* \return Error code indicating success or failures with parsing
*/
Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src, uint32_t len,
uint32_t *consumed_bytes, uint32_t *decoded_bytes, Base64Mode mode)
uint32_t *consumed_bytes, uint32_t *decoded_bytes, DetectBase64Mode mode)
{
*decoded_bytes = 0;
Base64Ecode ret = BASE64_ECODE_OK;
switch (mode) {
case BASE64_MODE_RFC4648:
case Base64ModeRFC4648:
ret = DecodeBase64RFC4648(
dest, dest_size, src, len, consumed_bytes, decoded_bytes, false);
break;
case BASE64_MODE_RFC2045:
case Base64ModeRFC2045:
ret = DecodeBase64RFC2045(dest, dest_size, src, len, consumed_bytes, decoded_bytes);
break;
case BASE64_MODE_STRICT:
case Base64ModeStrict:
ret = DecodeBase64RFC4648(
dest, dest_size, src, len, consumed_bytes, decoded_bytes, true);
break;
Expand All @@ -303,7 +303,7 @@ Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src,
uint32_t consumed_bytes = 0, num_decoded = 0; \
uint8_t dst[dest_size]; \
Base64Ecode code = DecodeBase64(dst, dest_size, (const uint8_t *)src, strlen(src), \
&consumed_bytes, &num_decoded, BASE64_MODE_RFC2045); \
&consumed_bytes, &num_decoded, Base64ModeRFC2045); \
FAIL_IF(code != ecode); \
FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0); \
FAIL_IF(num_decoded != exp_decoded); \
Expand All @@ -315,7 +315,7 @@ Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src,
uint32_t consumed_bytes = 0, num_decoded = 0; \
uint8_t dst[dest_size]; \
Base64Ecode code = DecodeBase64(dst, dest_size, (const uint8_t *)src, strlen(src), \
&consumed_bytes, &num_decoded, BASE64_MODE_RFC4648); \
&consumed_bytes, &num_decoded, Base64ModeRFC4648); \
FAIL_IF(code != ecode); \
FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0); \
FAIL_IF(num_decoded != exp_decoded); \
Expand Down Expand Up @@ -387,7 +387,7 @@ static int B64DecodeStringEndingSpaces(void)
uint32_t consumed_bytes = 0, num_decoded = 0;
uint8_t dst[10];
Base64Ecode code = DecodeBase64(dst, sizeof(dst), (const uint8_t *)src, 9, &consumed_bytes,
&num_decoded, BASE64_MODE_RFC2045);
&num_decoded, Base64ModeRFC2045);
FAIL_IF(code != BASE64_ECODE_OK);
FAIL_IF(num_decoded != 3);
FAIL_IF(consumed_bytes != 4);
Expand Down
41 changes: 2 additions & 39 deletions src/util-base64.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,49 +26,12 @@
#define SURICATA_UTIL_BASE64_H_

#include "suricata-common.h"
#include "rust.h"

/* Constants */
#define ASCII_BLOCK 3
#define B64_BLOCK 4

typedef enum {
BASE64_MODE_RELAX,
/* If the following strings were to be passed to the decoder with RFC2045 mode,
* the results would be as follows. See the unittest B64TestVectorsRFC2045 in
* src/util-base64.c
*
* BASE64("") = ""
* BASE64("f") = "Zg=="
* BASE64("fo") = "Zm8="
* BASE64("foo") = "Zm9v"
* BASE64("foob") = "Zm9vYg=="
* BASE64("fooba") = "Zm9vYmE="
* BASE64("foobar") = "Zm9vYmFy"
* BASE64("foobar") = "Zm 9v Ym Fy" <-- Notice how the spaces are ignored
* BASE64("foobar") = "Zm$9vYm.Fy" # According to RFC 2045, All line breaks or *other
* characters* not found in base64 alphabet must be ignored by decoding software
* */
BASE64_MODE_RFC2045, /* SPs are allowed during transfer but must be skipped by Decoder */
BASE64_MODE_STRICT,
/* If the following strings were to be passed to the decoder with RFC4648 mode,
* the results would be as follows. See the unittest B64TestVectorsRFC4648 in
* src/util-base64.c
*
* BASE64("") = ""
* BASE64("f") = "Zg=="
* BASE64("fo") = "Zm8="
* BASE64("foo") = "Zm9v"
* BASE64("foob") = "Zm9vYg=="
* BASE64("fooba") = "Zm9vYmE="
* BASE64("foobar") = "Zm9vYmFy"
* BASE64("f") = "Zm 9v Ym Fy" <-- Notice how the processing stops once space is encountered
* BASE64("f") = "Zm$9vYm.Fy" <-- Notice how the processing stops once an invalid char is
* encountered
* */
BASE64_MODE_RFC4648, /* reject the encoded data if it contains characters outside the base
alphabet */
} Base64Mode;

typedef enum {
BASE64_ECODE_ERR = -1,
BASE64_ECODE_OK = 0,
Expand All @@ -77,7 +40,7 @@ typedef enum {

/* Function prototypes */
Base64Ecode DecodeBase64(uint8_t *dest, uint32_t dest_size, const uint8_t *src, uint32_t len,
uint32_t *consumed_bytes, uint32_t *decoded_bytes, Base64Mode mode);
uint32_t *consumed_bytes, uint32_t *decoded_bytes, DetectBase64Mode mode);
bool IsBase64Alphabet(uint8_t encoded_byte);

#endif
Expand Down

0 comments on commit 5b97f40

Please sign in to comment.