SCLogDebug("line: '%s'", line);
uint8_t decoded[strlen(line)];
- uint32_t len =
- DecodeBase64(decoded, (const uint8_t *)line, strlen(line), BASE64_MODE_STRICT);
- if (len == 0)
+ 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);
+ if (code == BASE64_ECODE_ERR)
FatalError(SC_ERR_FATAL, "bad base64 encoding %s/%s",
set->name, set->load);
- if (DatasetAdd(set, (const uint8_t *)decoded, len) < 0)
+ if (DatasetAdd(set, (const uint8_t *)decoded, num_decoded) < 0)
FatalError(SC_ERR_FATAL, "dataset data add failed %s/%s",
set->name, set->load);
cnt++;
*r = '\0';
uint8_t decoded[strlen(line)];
- uint32_t len =
- DecodeBase64(decoded, (const uint8_t *)line, strlen(line), BASE64_MODE_STRICT);
- if (len == 0)
+ 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);
+ if (code == BASE64_ECODE_ERR)
FatalError(SC_ERR_FATAL, "bad base64 encoding %s/%s",
set->name, set->load);
FatalError(SC_ERR_FATAL, "die: bad rep");
SCLogDebug("rep %u", rep.value);
- if (DatasetAddwRep(set, (const uint8_t *)decoded, len, &rep) < 0)
+ if (DatasetAddwRep(set, (const uint8_t *)decoded, num_decoded, &rep) < 0)
FatalError(SC_ERR_FATAL, "dataset data add failed %s/%s",
set->name, set->load);
cnt++;
switch (set->type) {
case DATASET_TYPE_STRING: {
uint8_t decoded[strlen(string)];
- uint32_t len = DecodeBase64(
- decoded, (const uint8_t *)string, strlen(string), BASE64_MODE_STRICT);
- if (len == 0) {
+ 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);
+ if (code == BASE64_ECODE_ERR) {
return -2;
}
- return DatasetAddString(set, decoded, len);
+ return DatasetAddString(set, decoded, num_decoded);
}
case DATASET_TYPE_MD5: {
if (strlen(string) != 32)
switch (set->type) {
case DATASET_TYPE_STRING: {
uint8_t decoded[strlen(string)];
- uint32_t len = DecodeBase64(
- decoded, (const uint8_t *)string, strlen(string), BASE64_MODE_STRICT);
- if (len == 0) {
+ 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);
+ if (code == BASE64_ECODE_ERR) {
return -2;
}
- return DatasetRemoveString(set, decoded, len);
+ return DatasetRemoveString(set, decoded, num_decoded);
}
case DATASET_TYPE_MD5: {
if (strlen(string) != 32)
* \brief Decodes a base64-encoded string buffer into an ascii-encoded byte buffer
*
* \param dest The destination byte buffer
+ * \param dest_size The destination byte buffer size
* \param src The source string
* \param len The length of the source string
- * \param strict If set file on invalid byte, otherwise return what has been
- * decoded.
+ * \param consumed_bytes The bytes that were actually processed/consumed
+ * \param decoded_bytes The bytes that were decoded
+ * \param mode The mode in which decoding should happen
*
- * \return Number of bytes decoded, or 0 if no data is decoded or it fails
+ * \return Error code indicating success or failures with parsing
*/
-uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len, Base64Mode mode)
+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)
{
int val;
- uint32_t padding = 0, numDecoded = 0, bbidx = 0, valid = 1, i;
+ uint32_t padding = 0, bbidx = 0, sp = 0, leading_sp = 0;
uint8_t *dptr = dest;
uint8_t b64[B64_BLOCK] = { 0,0,0,0 };
-
+ bool valid = true;
+ Base64Ecode ecode = BASE64_ECODE_OK;
+ *decoded_bytes = 0;
/* Traverse through each alpha-numeric letter in the source array */
- for(i = 0; i < len && src[i] != 0; i++) {
-
+ for (uint32_t i = 0; i < len && src[i] != 0; i++) {
/* Get decimal representation */
val = GetBase64Value(src[i]);
if (val < 0) {
- if (mode == BASE64_MODE_RFC2045 && src[i] == ' ') {
+ if ((mode == BASE64_MODE_RFC2045) && (src[i] == ' ')) {
+ if (bbidx == 0) {
+ /* Special case where last block of data has a leading space */
+ leading_sp++;
+ }
+ sp++;
continue;
}
/* Invalid character found, so decoding fails */
if (src[i] != '=') {
- valid = 0;
+ valid = false;
if (mode != BASE64_MODE_RELAX) {
- numDecoded = 0;
+ *decoded_bytes = 0;
}
+ ecode = BASE64_ECODE_ERR;
break;
}
padding++;
if (bbidx == B64_BLOCK) {
/* For every 4 bytes, add 3 bytes but deduct the '=' padded blocks */
- numDecoded += ASCII_BLOCK - (padding < B64_BLOCK ?
- padding : ASCII_BLOCK);
+ uint32_t numDecoded_blk = ASCII_BLOCK - (padding < B64_BLOCK ? padding : ASCII_BLOCK);
+ if (dest_size < *decoded_bytes + numDecoded_blk) {
+ SCLogDebug("Destination buffer full");
+ ecode = BASE64_ECODE_BUF;
+ break;
+ }
/* Decode base-64 block into ascii block and move pointer */
DecodeBase64Block(dptr, b64);
dptr += ASCII_BLOCK;
-
+ *decoded_bytes += numDecoded_blk;
/* Reset base-64 block and index */
bbidx = 0;
padding = 0;
+ *consumed_bytes += B64_BLOCK + sp;
+ sp = 0;
+ leading_sp = 0;
+ memset(&b64, 0, sizeof(b64));
}
}
-
/* Finish remaining b64 bytes by padding */
- if (valid && bbidx > 0) {
-
+ if (valid && bbidx > 0 && (mode != BASE64_MODE_RFC2045)) {
/* Decode remaining */
- numDecoded += ASCII_BLOCK - (B64_BLOCK - bbidx);
+ *decoded_bytes += ASCII_BLOCK - (B64_BLOCK - bbidx);
DecodeBase64Block(dptr, b64);
}
- if (numDecoded == 0) {
+ if (*decoded_bytes == 0) {
SCLogDebug("base64 decoding failed");
}
- return numDecoded;
+ *consumed_bytes += leading_sp;
+ return ecode;
}
#ifdef UNITTESTS
+static int B64DecodeCompleteString(void)
+{
+ /*
+ * SGVsbG8gV29ybGR6 : Hello Worldz
+ * */
+ const char *src = "SGVsbG8gV29ybGR6";
+ const char *fin_str = "Hello Worldz";
+ uint32_t consumed_bytes = 0, num_decoded = 0;
+ uint8_t dst[strlen(fin_str)];
+ Base64Ecode code = DecodeBase64(dst, strlen(fin_str), (const uint8_t *)src, strlen(src),
+ &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045);
+ FAIL_IF(code != BASE64_ECODE_OK);
+ FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0);
+ FAIL_IF(num_decoded != 12);
+ FAIL_IF(consumed_bytes != strlen(src));
+ PASS;
+}
+
+static int B64DecodeInCompleteString(void)
+{
+ /*
+ * SGVsbG8gV29ybGR6 : Hello Worldz
+ * */
+ const char *src = "SGVsbG8gV29ybGR";
+ const char *fin_str = "Hello Wor"; // bc it'll error out on last 3 bytes
+ uint32_t consumed_bytes = 0, num_decoded = 0;
+ uint8_t dst[strlen(fin_str)];
+ Base64Ecode code = DecodeBase64(dst, strlen(fin_str), (const uint8_t *)src, strlen(src),
+ &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045);
+ FAIL_IF(code != BASE64_ECODE_OK);
+ FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0);
+ FAIL_IF(num_decoded != 9);
+ FAIL_IF(consumed_bytes == strlen(src));
+ PASS;
+}
+
+static int B64DecodeCompleteStringWSp(void)
+{
+ /*
+ * SGVsbG8gV29ybGQ= : Hello World
+ * */
+
+ const char *src = "SGVs bG8 gV29y bGQ=";
+ const char *fin_str = "Hello World";
+ uint8_t dst[strlen(fin_str) + 1]; // 1 for the padding byte
+ uint32_t consumed_bytes = 0, num_decoded = 0;
+ Base64Ecode code = DecodeBase64(dst, strlen(fin_str), (const uint8_t *)src, strlen(src),
+ &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045);
+ FAIL_IF(code != BASE64_ECODE_OK);
+ FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0);
+ FAIL_IF(num_decoded != 11);
+ FAIL_IF(consumed_bytes != strlen(src));
+ PASS;
+}
+
+static int B64DecodeInCompleteStringWSp(void)
+{
+ /*
+ * SGVsbG8gV29ybGQ= : Hello World
+ * Special handling for this case (sp in remainder) done in ProcessBase64Remainder
+ * */
+
+ const char *src = "SGVs bG8 gV29y bGQ";
+ const char *fin_str = "Hello Wor";
+ uint32_t consumed_bytes = 0, num_decoded = 0;
+ uint8_t dst[strlen(fin_str)];
+ Base64Ecode code = DecodeBase64(dst, strlen(fin_str), (const uint8_t *)src, strlen(src),
+ &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045);
+ FAIL_IF(code != BASE64_ECODE_OK);
+ FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0);
+ FAIL_IF(num_decoded != 9); // bc we don't put padding in RFC2045 mode
+ FAIL_IF(consumed_bytes != strlen(src) - 3);
+ PASS;
+}
-static int DecodeString(void)
+static int B64DecodeStringBiggerThanBuffer(void)
{
/*
- * SGV sbG8= : Hello
* SGVsbG8gV29ybGQ= : Hello World
* */
const char *src = "SGVs bG8 gV29y bGQ=";
- uint8_t *dst = SCMalloc(sizeof(src) * 30);
- int res = DecodeBase64(dst, (const uint8_t *)src, 30, 1);
- printf("%d\n", res);
- printf("dst str = \"%s\"", (const char *)dst);
- FAIL_IF(res <= 0);
- SCFree(dst);
+ const char *fin_str = "Hello Wor";
+ uint32_t consumed_bytes = 0, num_decoded = 0;
+ uint8_t dst[strlen(fin_str)];
+ Base64Ecode code = DecodeBase64(dst, strlen(fin_str), (const uint8_t *)src, strlen(src),
+ &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045);
+ FAIL_IF(code != BASE64_ECODE_BUF);
+ FAIL_IF(memcmp(dst, fin_str, strlen(fin_str)) != 0);
+ FAIL_IF(num_decoded != 9); // dest buf is 10, so 9 got consumed
+ FAIL_IF(consumed_bytes != 15);
+ PASS;
+}
+
+static int B64DecodeStringEndingSpaces(void)
+{
+ const char *src = "0YPhA d H";
+ uint32_t consumed_bytes = 0, num_decoded = 0;
+ uint8_t dst[10];
+ Base64Ecode code = DecodeBase64(dst, sizeof(dst), (const uint8_t *)src, strlen(src),
+ &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045);
+ FAIL_IF(code != BASE64_ECODE_OK);
+ FAIL_IF(num_decoded != 3);
+ FAIL_IF(consumed_bytes != 4);
PASS;
}
void Base64RegisterTests(void)
{
- UtRegisterTest("DecodeString", DecodeString);
+ UtRegisterTest("B64DecodeCompleteStringWSp", B64DecodeCompleteStringWSp);
+ UtRegisterTest("B64DecodeInCompleteStringWSp", B64DecodeInCompleteStringWSp);
+ UtRegisterTest("B64DecodeCompleteString", B64DecodeCompleteString);
+ UtRegisterTest("B64DecodeInCompleteString", B64DecodeInCompleteString);
+ UtRegisterTest("B64DecodeStringBiggerThanBuffer", B64DecodeStringBiggerThanBuffer);
+ UtRegisterTest("B64DecodeStringEndingSpaces", B64DecodeStringEndingSpaces);
}
#endif
#include "util-unittest.h"
#include "util-memcmp.h"
#include "util-print.h"
+#include "util-validate.h"
+#include "rust.h"
/* Character constants */
#ifndef CR
MimeDecParseState *state, int force)
{
uint32_t ret;
- uint8_t remainder = 0, remdec = 0;
-
- SCLogDebug("Base64 line remainder found: %u", state->bvr_len);
+ uint8_t remainder = 0;
+ uint32_t remdec = 0;
+ uint32_t consumed_bytes = 0;
+ uint32_t cnt = 0;
/* Fill in block with first few bytes of current line */
remainder = B64_BLOCK - state->bvr_len;
remainder = remainder < len ? remainder : len;
- if (remainder && buf) {
- memcpy(state->bvremain + state->bvr_len, buf, remainder);
+ if (buf) {
+ uint8_t tmp[B64_BLOCK];
+ uint32_t rem = 0;
+ for (uint8_t i = 0; i < state->bvr_len; i++) {
+ /* Special case of SP in remainder */
+ if (state->bvremain[i] != ' ') {
+ tmp[cnt++] = state->bvremain[i];
+ } else {
+ rem++;
+ }
+ }
+ if (cnt != 4) {
+ /* Special case where the buf where we take extra bytes from contains SP */
+ for (uint32_t i = 0; i < len && cnt < 4; i++) {
+ if (buf[i] != ' ') {
+ tmp[cnt++] = buf[i];
+ } else {
+ rem++;
+ }
+ }
+ }
+ memcpy(state->bvremain, tmp, cnt);
+ state->bvr_len += remainder;
+ remainder += rem;
}
- state->bvr_len += remainder;
-
/* If data chunk buffer will be full, then clear it now */
if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) {
}
}
- /* Only decode if divisible by 4 */
if (state->bvr_len == B64_BLOCK || force) {
- remdec = DecodeBase64(state->data_chunk + state->data_chunk_len, state->bvremain,
- state->bvr_len, BASE64_MODE_RFC2045);
- if (remdec > 0) {
+ uint32_t avail_space = DATA_CHUNK_SIZE - state->data_chunk_len;
+ Base64Ecode code = DecodeBase64(state->data_chunk + state->data_chunk_len, avail_space,
+ state->bvremain, state->bvr_len, &consumed_bytes, &remdec, BASE64_MODE_RFC2045);
+ if (remdec > 0 && (code == BASE64_ECODE_OK || code == BASE64_ECODE_BUF)) {
/* Track decoded length */
state->stack->top->data->decoded_body_len += remdec;
/* Update length */
state->data_chunk_len += remdec;
-
/* If data chunk buffer is now full, then clear */
if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) {
"failed");
}
}
- } else {
+ } else if (code == BASE64_ECODE_ERR) {
/* Track failed base64 */
state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64;
state->msg->anomaly_flags |= ANOM_INVALID_BASE64;
MimeDecParseState *state)
{
int ret = MIME_DEC_OK;
- uint8_t rem1 = 0, rem2 = 0;
- uint32_t numDecoded, remaining, offset, avail, tobuf;
-
+ uint8_t rem1 = 0;
+ uint32_t numDecoded, remaining, offset;
/* Track long line */
if (len > MAX_ENC_LINE_LEN) {
state->stack->top->data->anomaly_flags |= ANOM_LONG_ENC_LINE;
len, MAX_ENC_LINE_LEN);
}
+ if (state->bvr_len + len < B64_BLOCK) {
+ memcpy(state->bvremain + state->bvr_len, buf, len);
+ state->bvr_len += len;
+ len = 0;
+ }
+
/* First process remaining from previous line */
if (state->bvr_len > 0) {
-
- SCLogDebug("Base64 line remainder found: %u", state->bvr_len);
-
/* Process remainder and return number of bytes pulled from current buffer */
- rem1 = ProcessBase64Remainder(buf, len, state, 0);
+ rem1 = ProcessBase64Remainder(buf, (uint8_t)len, state, 0);
+ int32_t remainder_b64 = len - rem1;
+ if (remainder_b64 < B64_BLOCK) {
+ memcpy(state->bvremain, buf + rem1, remainder_b64);
+ state->bvr_len += remainder_b64;
+ return ret;
+ }
}
- /* No error and at least some more data needs to be decoded */
- if ((int) (len - rem1) > 0) {
-
- /* Determine whether we need to save a remainder if not divisible by 4 */
- rem2 = (len - rem1) % B64_BLOCK;
- if (rem2 > 0) {
-
- SCLogDebug("Base64 saving remainder: %u", rem2);
+ remaining = len - rem1;
+ offset = rem1;
+ while (remaining > 0 && remaining >= B64_BLOCK) {
+ uint32_t consumed_bytes = 0;
+ uint32_t avail_space = DATA_CHUNK_SIZE - state->data_chunk_len;
+ Base64Ecode code = DecodeBase64(state->data_chunk + state->data_chunk_len, avail_space,
+ buf + offset, remaining, &consumed_bytes, &numDecoded, BASE64_MODE_RFC2045);
- memcpy(state->bvremain, buf + (len - rem2), rem2);
- state->bvr_len = rem2;
- }
-
- /* Process remaining in loop in case buffer fills up */
- remaining = len - rem1 - rem2;
- offset = rem1;
- while (remaining > 0) {
+ DEBUG_VALIDATE_BUG_ON(consumed_bytes > remaining);
- /* Determine amount to add to buffer */
- avail = (DATA_CHUNK_SIZE - state->data_chunk_len) * B64_BLOCK / ASCII_BLOCK;
- tobuf = avail > remaining ? remaining : avail;
- while (tobuf % 4 != 0) {
- tobuf--;
- }
+ uint32_t leftover_bytes = remaining - consumed_bytes;
+ if (numDecoded > 0 && (code == BASE64_ECODE_OK || code == BASE64_ECODE_BUF)) {
+ /* Track decoded length */
+ state->stack->top->data->decoded_body_len += numDecoded;
+ /* Update length */
+ state->data_chunk_len += numDecoded;
- if (tobuf < B64_BLOCK) {
- SCLogDebug("Error: Invalid state for decoding base-64 block");
+ if ((int)(DATA_CHUNK_SIZE - state->data_chunk_len) < 0) {
+ SCLogDebug("Error: Invalid Chunk length: %u", state->data_chunk_len);
return MIME_DEC_ERR_PARSE;
}
-
- SCLogDebug("Decoding: %u", len - rem1 - rem2);
-
- numDecoded = DecodeBase64(state->data_chunk + state->data_chunk_len, buf + offset,
- tobuf, BASE64_MODE_RFC2045);
- if (numDecoded > 0) {
-
- /* Track decoded length */
- state->stack->top->data->decoded_body_len += numDecoded;
-
- /* Update length */
- state->data_chunk_len += numDecoded;
-
- if ((int) (DATA_CHUNK_SIZE - state->data_chunk_len) < 0) {
- SCLogDebug("Error: Invalid Chunk length: %u",
- state->data_chunk_len);
- ret = MIME_DEC_ERR_PARSE;
+ /* If buffer full, then invoke callback */
+ if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) {
+ /* Invoke pre-processor and callback */
+ ret = ProcessDecodedDataChunk(state->data_chunk, state->data_chunk_len, state);
+ if (ret != MIME_DEC_OK) {
+ SCLogDebug("Error: ProcessDecodedDataChunk() function failed");
break;
}
-
- /* If buffer full, then invoke callback */
- if (DATA_CHUNK_SIZE - state->data_chunk_len < ASCII_BLOCK) {
-
- /* Invoke pre-processor and callback */
- ret = ProcessDecodedDataChunk(state->data_chunk,
- state->data_chunk_len, state);
- if (ret != MIME_DEC_OK) {
- SCLogDebug("Error: ProcessDecodedDataChunk() "
- "function failed");
- }
- }
- } else {
- /* Track failed base64 */
- state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64;
- state->msg->anomaly_flags |= ANOM_INVALID_BASE64;
- SCLogDebug("Error: DecodeBase64() function failed");
- PrintChars(SC_LOG_DEBUG, "Base64 failed string", buf + offset, tobuf);
}
-
- /* Update counts */
- remaining -= tobuf;
- offset += tobuf;
+ } else if (code == BASE64_ECODE_ERR) {
+ /* Track failed base64 */
+ state->stack->top->data->anomaly_flags |= ANOM_INVALID_BASE64;
+ state->msg->anomaly_flags |= ANOM_INVALID_BASE64;
+ SCLogDebug("Error: DecodeBase64() function failed");
+ ret = MIME_DEC_ERR_DATA;
+ break;
+ }
+ if (leftover_bytes < B64_BLOCK) {
+ memcpy(state->bvremain, buf + offset + consumed_bytes, leftover_bytes);
+ state->bvr_len = leftover_bytes;
+ return MIME_DEC_OK;
+ }
+ /* Update counts */
+ remaining -= consumed_bytes;
+ offset += consumed_bytes;
+ /* If remaining is 4 by this time, it's likely due to error/spaces during processing */
+ if (remaining == 4) {
+ memcpy(state->bvremain, buf + offset, remaining);
+ state->bvr_len = remaining;
+ break;
+ }
+ if ((remaining > 0 && remaining < B64_BLOCK) ||
+ (remaining > 0 && (remaining < B64_BLOCK) && consumed_bytes < remaining)) {
+ memcpy(state->bvremain, buf + offset, remaining);
+ state->bvr_len = remaining;
+ break;
}
}
-
return ret;
}
MimeDecFreeEntity(entity);
if (expected_count != line_count) {
- SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d",
- expected_count, line_count);
+ SCLogInfo("Warning: Line count is invalid: expected - %d actual - %d", expected_count,
+ line_count);
return 0;
}
static int MimeBase64DecodeTest01(void)
{
int ret = 0;
+ uint32_t consumed_bytes = 0, num_decoded = 0;
const char *msg = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@"
"#$%^&*()-=_+,./;'[]<>?:";
if (dst == NULL)
return 0;
- ret = DecodeBase64(dst, (const uint8_t *)base64msg, strlen(base64msg), BASE64_MODE_RFC2045);
+ ret = DecodeBase64(dst, strlen(msg) + 1, (const uint8_t *)base64msg, strlen(base64msg),
+ &consumed_bytes, &num_decoded, BASE64_MODE_RFC2045);
if (memcmp(dst, msg, strlen(msg)) == 0) {
ret = 1;
PASS;
}
+static int MimeDecParseSmallRemInp(void)
+{
+ // Remainder dA
+ // New input: AAAA
+ char mimemsg[] = "TWltZSBkZWNvZGluZyB pcyBzbyBO T1QgZnV uISBJIGNhbm5vdA";
+
+ uint32_t line_count = 0;
+
+ MimeDecGetConfig()->decode_base64 = true;
+ MimeDecGetConfig()->decode_quoted_printable = true;
+ MimeDecGetConfig()->extract_urls = true;
+
+ /* Init parser */
+ MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback);
+ state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT;
+
+ const char *str = "From: Sender1";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "To: Recipient1";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "Content-Type: text/plain";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "Content-Transfer-Encoding: base64";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state));
+
+ str = "AAAA";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ /* Completed */
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state));
+
+ MimeDecEntity *msg = state->msg;
+ FAIL_IF_NOT(msg);
+
+ /* filename is not too long */
+ FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME);
+
+ MimeDecFreeEntity(msg);
+
+ /* De Init parser */
+ MimeDecDeInitParser(state);
+
+ PASS;
+}
+
+static int MimeDecParseRemSp(void)
+{
+ // Should have remainder vd A
+ char mimemsg[] = "TWltZSBkZWNvZGluZyBpc yBzbyBOT1QgZnVuISBJIGNhbm5vd A";
+
+ uint32_t line_count = 0;
+
+ MimeDecGetConfig()->decode_base64 = true;
+ MimeDecGetConfig()->decode_quoted_printable = true;
+ MimeDecGetConfig()->extract_urls = true;
+
+ /* Init parser */
+ MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback);
+ state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT;
+
+ const char *str = "From: Sender1";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "To: Recipient1";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "Content-Type: text/plain";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "Content-Transfer-Encoding: base64";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state));
+ /* Completed */
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state));
+
+ MimeDecEntity *msg = state->msg;
+ FAIL_IF_NOT(msg);
+
+ /* filename is not too long */
+ FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME);
+
+ MimeDecFreeEntity(msg);
+
+ /* De Init parser */
+ MimeDecDeInitParser(state);
+
+ PASS;
+}
+
+static int MimeDecVerySmallInp(void)
+{
+ // Remainder: A
+ // New input: aA
+ char mimemsg[] = "TWltZSBkZWNvZGluZyB pcyBzbyBO T1QgZnV uISBJIGNhbm5vA";
+
+ uint32_t line_count = 0;
+
+ MimeDecGetConfig()->decode_base64 = true;
+ MimeDecGetConfig()->decode_quoted_printable = true;
+ MimeDecGetConfig()->extract_urls = true;
+
+ /* Init parser */
+ MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback);
+ state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT;
+
+ const char *str = "From: Sender1";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "To: Recipient1";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "Content-Type: text/plain";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "Content-Transfer-Encoding: base64";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state));
+
+ str = "aA";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ /* Completed */
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state));
+
+ MimeDecEntity *msg = state->msg;
+ FAIL_IF_NOT(msg);
+
+ /* filename is not too long */
+ FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME);
+
+ MimeDecFreeEntity(msg);
+
+ /* De Init parser */
+ MimeDecDeInitParser(state);
+
+ PASS;
+}
+
+static int MimeDecParseOddLen(void)
+{
+ char mimemsg[] = "TWltZSBkZWNvZGluZyB pcyBzbyBO T1QgZnV uISBJIGNhbm5vdA";
+
+ uint32_t line_count = 0;
+
+ MimeDecGetConfig()->decode_base64 = true;
+ MimeDecGetConfig()->decode_quoted_printable = true;
+ MimeDecGetConfig()->extract_urls = true;
+
+ /* Init parser */
+ MimeDecParseState *state = MimeDecInitParser(&line_count, TestDataChunkCallback);
+ state->stack->top->data->ctnt_flags |= CTNT_IS_ATTACHMENT;
+
+ const char *str = "From: Sender1";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "To: Recipient1";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "Content-Type: text/plain";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "Content-Transfer-Encoding: base64";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ str = "";
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)str, strlen(str), 1, state));
+
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseLine((uint8_t *)mimemsg, strlen(mimemsg), 1, state));
+ /* Completed */
+ FAIL_IF_NOT(MIME_DEC_OK == MimeDecParseComplete(state));
+
+ MimeDecEntity *msg = state->msg;
+ FAIL_IF_NOT(msg);
+
+ /* filename is not too long */
+ FAIL_IF(msg->anomaly_flags & ANOM_LONG_FILENAME);
+
+ MimeDecFreeEntity(msg);
+
+ /* De Init parser */
+ MimeDecDeInitParser(state);
+
+ PASS;
+}
+
static int MimeDecParseLongFilename02(void)
{
/* contains 40 character filename and 500+ characters following filename */
UtRegisterTest("MimeIsIpv6HostTest01", MimeIsIpv6HostTest01);
UtRegisterTest("MimeDecParseLongFilename01", MimeDecParseLongFilename01);
UtRegisterTest("MimeDecParseLongFilename02", MimeDecParseLongFilename02);
+ UtRegisterTest("MimeDecParseSmallRemInp", MimeDecParseSmallRemInp);
+ UtRegisterTest("MimeDecParseRemSp", MimeDecParseRemSp);
+ UtRegisterTest("MimeDecVerySmallInp", MimeDecVerySmallInp);
+ UtRegisterTest("MimeDecParseOddLen", MimeDecParseOddLen);
#endif /* UNITTESTS */
}