Commit 0d8311c5 authored by Tomáš Stefan's avatar Tomáš Stefan

Go through all references to the signature dictionary

parent 6bbfd2d7
#ifndef PDF_SIGIL_ACROFORM_H
#define PDF_SIGIL_ACROFORM_H
#include "types.h"
sigil_err_t process_acroform(sigil_t *sgl);
int sigil_auxiliary_self_test(int verbosity);
#endif //PDF_SIGIL_ACROFORM_H
......@@ -20,6 +20,9 @@ sigil_err_t pdf_peek_char(sigil_t *sgl, char *result);
sigil_err_t pdf_move_pos_rel(sigil_t *sgl, ssize_t shift_bytes);
sigil_err_t pdf_move_pos_abs(sigil_t *sgl, size_t position);
sigil_err_t pdf_goto_obj(sigil_t *sgl, reference_t *ref);
sigil_err_t get_curr_position(sigil_t *sgl, size_t *result);
sigil_err_t skip_leading_whitespaces(sigil_t *sgl);
sigil_err_t skip_array(sigil_t *sgl);
......@@ -30,6 +33,9 @@ sigil_err_t parse_number(sigil_t *sgl, size_t *number);
sigil_err_t parse_word(sigil_t *sgl, const char *word);
sigil_err_t parse_indirect_reference(sigil_t *sgl, reference_t *ref);
sigil_err_t parse_dict_key(sigil_t *sgl, dict_key_t *dict_key);
sigil_err_t parse_ref_array(sigil_t *sgl, ref_array_t *ref_array);
sigil_err_t reference_to_offset(sigil_t *sgl, const reference_t *ref, size_t *result);
const char *sigil_err_string(sigil_err_t err);
......
#ifndef PDF_SIGIL_CATALOG_DICT_H
#define PDF_SIGIL_CATALOG_DICT_H
#include "types.h"
sigil_err_t process_catalog_dictionary(sigil_t *sgl);
int sigil_header_self_test(int verbosity);
#endif /* PDF_SIGIL_CATALOG_DICT_H */
......@@ -11,6 +11,9 @@
// capacity to choose for the first xref allocation
#define XREF_PREALLOCATION 10
// capacity to choose for the first allocation in array of fields
#define REF_ARRAY_PREALLOCATION 10
// threshold in bytes for loading whole file into buffer
#define THRESHOLD_FILE_BUFFERING 10485760
......
......@@ -3,27 +3,39 @@
#ifdef __unix__
#define COLOR_RED "\x1b[31m"
#define COLOR_GREEN "\x1b[32m"
#define COLOR_RESET "\x1b[0m"
#define COLOR_RED "\x1b[31m"
#define COLOR_GREEN "\x1b[32m"
#define COLOR_RESET "\x1b[0m"
#else
#define COLOR_RED ""
#define COLOR_GREEN ""
#define COLOR_RESET ""
#define COLOR_RED ""
#define COLOR_GREEN ""
#define COLOR_RESET ""
#endif
#define XREF_TYPE_UNSET 0
#define XREF_TYPE_TABLE 1
#define XREF_TYPE_STREAM 2
#define XREF_TYPE_UNSET 0
#define XREF_TYPE_TABLE 1
#define XREF_TYPE_STREAM 2
#define DICT_KEY_UNKNOWN 0
#define DICT_KEY_Size 1
#define DICT_KEY_Prev 2
#define DICT_KEY_Root 3
#define DICT_KEY_UNKNOWN 0
#define DICT_KEY_Size 1
#define DICT_KEY_Prev 2
#define DICT_KEY_Root 3
#define DICT_KEY_AcroForm 4
#define DICT_KEY_Fields 5
#define DICT_KEY_SigFlags 6
#define DICT_KEY_FT 7
#define DICT_KEY_V 8
#define DICT_KEY_SubFilter 9
#define DICT_KEY_Cert 10
#define DICT_KEY_Contents 11
#define DICT_KEY_ByteRange 12
#define DEALLOCATE_FILE 0x01
#define DEALLOCATE_BUFFER 0x02
#define SUBFILTER_UNKNOWN 0
#define SUBFILTER_adbe_x509_rsa_sha1 1
#define DEALLOCATE_FILE 0x01
#define DEALLOCATE_BUFFER 0x02
#define ERR_NO 0
#define ERR_ALLOCATION 1
......@@ -33,5 +45,6 @@
#define ERR_NOT_IMPLEMENTED 5
#define ERR_NO_DATA 6
#define ERR_END_OF_DICT 7
#define ERR_NO_SIGNATURE 8
#endif /* PDF_SIGIL_CONSTANTS_H */
#ifndef PDF_SIGIL_SIG_DICT_H
#define PDF_SIGIL_SIG_DICT_H
#include "types.h"
sigil_err_t process_sig_dict(sigil_t *sgl);
int sigil_sigil_self_test(int verbosity);
#endif /* PDF_SIGIL_SIG_DICT_H */
#ifndef PDF_SIGIL_SIG_FIELD_H
#define PDF_SIGIL_SIG_FIELD_H
#include "types.h"
sigil_err_t find_sig_field(sigil_t *sgl);
sigil_err_t process_sig_field(sigil_t *sgl);
int sigil_sigil_self_test(int verbosity);
#endif /* PDF_SIGIL_SIG_FIELD_H */
......@@ -12,7 +12,7 @@
typedef uint32_t sigil_err_t;
typedef uint32_t keyword_t;
typedef uint32_t subfilter_t;
typedef uint32_t dict_key_t;
......@@ -21,6 +21,17 @@ typedef struct {
size_t generation_num;
} reference_t;
typedef struct range_t {
size_t start;
size_t length;
struct range_t *next;
} range_t;
typedef struct {
reference_t **entry;
size_t capacity;
} ref_array_t;
typedef struct xref_entry_t {
size_t byte_offset;
size_t generation_num;
......@@ -49,8 +60,17 @@ typedef struct {
short xref_type;
xref_t *xref;
reference_t ref_catalog_dict;
reference_t ref_acroform;
size_t offset_acroform;
reference_t ref_sig_field;
reference_t ref_sig_dict;
size_t offset_sig_dict;
ref_array_t fields;
size_t pdf_start_offset; /* offset of %PDF-x.y */
size_t startxref;
size_t sig_flags;
subfilter_t subfilter;
range_t *byte_range;
} sigil_t;
#endif /* PDF_SIGIL_TYPES_H */
#include <types.h>
#include "acroform.h"
#include "auxiliary.h"
#include "constants.h"
#include "types.h"
sigil_err_t process_acroform(sigil_t *sgl)
{
sigil_err_t err;
dict_key_t dict_key;
if (sgl == NULL)
return ERR_PARAMETER;
if (sgl->offset_acroform <= 0 && sgl->ref_acroform.object_num > 0) {
err = pdf_goto_obj(sgl, &(sgl->ref_acroform));
if (err != ERR_NO)
return err;
} else {
err = pdf_move_pos_abs(sgl, sgl->offset_acroform);
if (err != ERR_NO)
return err;
}
err = parse_word(sgl, "<<");
if (err != ERR_NO)
return err;
while ((err = parse_dict_key(sgl, &dict_key)) == ERR_NO) {
switch (dict_key) {
case DICT_KEY_Fields:
err = parse_ref_array(sgl, &(sgl->fields));
if (err != ERR_NO)
return err;
break;
case DICT_KEY_SigFlags:
err = parse_number(sgl, &(sgl->sig_flags));
if (err != ERR_NO)
return err;
break;
case DICT_KEY_UNKNOWN:
err = skip_dict_unknown_value(sgl);
if (err != ERR_NO)
return err;
break;
default:
return ERR_PDF_CONTENT;
}
}
if (err == ERR_END_OF_DICT)
return ERR_NO;
return err;
}
\ No newline at end of file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "auxiliary.h"
#include "config.h"
#include "constants.h"
#include "sigil.h"
#include "types.h"
#define DICT_KEY_MAX 10
#define DICT_KEY_MAX 20
void sigil_zeroize(void *a, size_t bytes)
......@@ -191,6 +194,70 @@ sigil_err_t pdf_move_pos_abs(sigil_t *sgl, size_t position)
return ERR_NO_DATA;
}
sigil_err_t pdf_goto_obj(sigil_t *sgl, reference_t *ref)
{
sigil_err_t err;
size_t offset,
tmp;
if (sgl == NULL || ref == NULL)
return ERR_PARAMETER;
if (ref->object_num <= 0 &&
ref->generation_num <= 0)
{
return ERR_NO_DATA;
}
err = reference_to_offset(sgl, ref, &offset);
if (err != ERR_NO)
return err;
err = pdf_move_pos_abs(sgl, offset);
if (err != ERR_NO)
return err;
err = parse_number(sgl, &tmp);
if (err != ERR_NO)
return err;
if (tmp != ref->object_num)
return ERR_PDF_CONTENT;
err = parse_number(sgl, &tmp);
if (err != ERR_NO)
return err;
if (tmp != ref->generation_num)
return ERR_PDF_CONTENT;
err = parse_word(sgl, "obj");
if (err != ERR_NO)
return err;
return ERR_NO;
}
sigil_err_t get_curr_position(sigil_t *sgl, size_t *result)
{
if (sgl == NULL || result == NULL)
return ERR_PARAMETER;
if (sgl->pdf_data.buffer != NULL) {
*result = sgl->pdf_data.buf_pos;
return ERR_NO;
}
if (sgl->pdf_data.file != NULL) {
*result = (size_t)ftell(sgl->pdf_data.file);
if (*result < 0)
return ERR_IO;
return ERR_NO;
}
return ERR_NO_DATA;
}
sigil_err_t skip_leading_whitespaces(sigil_t *sgl)
{
sigil_err_t err;
......@@ -272,26 +339,43 @@ sigil_err_t skip_dict_unknown_value(sigil_t *sgl)
{
sigil_err_t err;
char c;
int first_non_whitespace = 1;
while ((err = pdf_peek_char(sgl, &c)) == ERR_NO) {
switch (c) {
case '/':
return ERR_NO;
case '[':
if ((err = pdf_move_pos_rel(sgl, 1)) != ERR_NO)
return err;
if ((err = skip_array(sgl)) != ERR_NO)
return err;
return ERR_NO;
case '<':
if ((err = pdf_move_pos_rel(sgl, 1)) != ERR_NO)
return err;
if ((err = pdf_peek_char(sgl, &c)) != ERR_NO)
return err;
if (c != '<')
if (first_non_whitespace && !is_whitespace(c)) {
first_non_whitespace = 0;
switch (c) {
case '/':
if ((err = pdf_move_pos_rel(sgl, 1)) != ERR_NO)
return err;
break;
if ((err = skip_dictionary(sgl)) != ERR_NO)
return err;
case '[':
if ((err = pdf_move_pos_rel(sgl, 1)) != ERR_NO)
return err;
if ((err = skip_array(sgl)) != ERR_NO)
return err;
return ERR_NO;
case '<':
if ((err = pdf_move_pos_rel(sgl, 1)) != ERR_NO)
return err;
if ((err = pdf_peek_char(sgl, &c)) != ERR_NO)
return err;
if (c != '<')
break;
if ((err = skip_dictionary(sgl)) != ERR_NO)
return err;
return ERR_NO;
default:
break;
}
continue;
}
switch (c) {
case '/': // key of next entry
case '>': // end of dictionary
return ERR_NO;
case EOF:
return ERR_PDF_CONTENT;
......@@ -420,12 +504,35 @@ sigil_err_t parse_dict_key(sigil_t *sgl, dict_key_t *dict_key)
return err;
}
tmp[count] = '\0';
if (err != ERR_NO)
return err;
if (strncmp(tmp, "Size", 4) == 0) {
*dict_key = DICT_KEY_Size;
} else if (strncmp(tmp, "Prev", 4) == 0) {
*dict_key = DICT_KEY_Prev;
} else if (strncmp(tmp, "Root", 4) == 0) {
*dict_key = DICT_KEY_Root;
} else if (strncmp(tmp, "AcroForm", 8) == 0) {
*dict_key = DICT_KEY_AcroForm;
} else if (strncmp(tmp, "Fields", 6) == 0) {
*dict_key = DICT_KEY_Fields;
} else if (strncmp(tmp, "SigFlags", 8) == 0) {
*dict_key = DICT_KEY_SigFlags;
} else if (strncmp(tmp, "FT", 2) == 0) {
*dict_key = DICT_KEY_FT;
} else if (strncmp(tmp, "V", 1) == 0) {
*dict_key = DICT_KEY_V;
} else if (strncmp(tmp, "SubFilter", 9) == 0) {
*dict_key = DICT_KEY_SubFilter;
} else if (strncmp(tmp, "Cert", 4) == 0) {
*dict_key = DICT_KEY_Cert;
} else if (strncmp(tmp, "Contents", 8) == 0) {
*dict_key = DICT_KEY_Contents;
} else if (strncmp(tmp, "ByteRange", 9) == 0) {
*dict_key = DICT_KEY_ByteRange;
} else {
*dict_key = DICT_KEY_UNKNOWN;
}
......@@ -433,6 +540,88 @@ sigil_err_t parse_dict_key(sigil_t *sgl, dict_key_t *dict_key)
return ERR_NO;
}
// parsing array of indirect references into ref_array
sigil_err_t parse_ref_array(sigil_t *sgl, ref_array_t *ref_array)
{
sigil_err_t err;
size_t position;
reference_t reference;
if (sgl == NULL || ref_array == NULL)
return ERR_PARAMETER;
if ((err = parse_word(sgl, "[")) != ERR_NO)
return err;
if (parse_word(sgl, "]") == ERR_NO) // empty array
return ERR_NO;
if (ref_array->capacity <= 0) {
ref_array->entry = malloc(sizeof(*ref_array->entry) * REF_ARRAY_PREALLOCATION);
if (ref_array->entry == NULL)
return ERR_ALLOCATION;
sigil_zeroize(ref_array->entry, sizeof(*ref_array->entry) * REF_ARRAY_PREALLOCATION);
ref_array->capacity = REF_ARRAY_PREALLOCATION;
}
position = 0;
while ((err = parse_indirect_reference(sgl,&reference)) == ERR_NO) {
if (position >= ref_array->capacity) {
ref_array->entry = realloc(ref_array->entry,
sizeof(*ref_array->entry) * ref_array->capacity * 2);
if (ref_array->entry == NULL)
return ERR_ALLOCATION;
sigil_zeroize(ref_array->entry + ref_array->capacity,
sizeof(*ref_array->entry) * ref_array->capacity);
ref_array->capacity *= 2;
}
if (ref_array->entry[position] == NULL) {
ref_array->entry[position] = malloc(sizeof(reference_t));
if (ref_array->entry[position] == NULL)
return ERR_ALLOCATION;
}
ref_array->entry[position]->object_num = reference.object_num;
ref_array->entry[position]->generation_num = reference.generation_num;
if (parse_word(sgl, "]") == ERR_NO)
return ERR_NO;
position++;
}
return err;
}
sigil_err_t reference_to_offset(sigil_t *sgl, const reference_t *ref, size_t *result)
{
xref_entry_t *xref_entry;
if (sgl == NULL || ref == NULL || sgl->xref == NULL)
return ERR_PARAMETER;
if (sgl->xref->capacity <= ref->object_num)
return ERR_NO_DATA;
xref_entry = sgl->xref->entry[ref->object_num];
while (xref_entry != NULL) {
if (xref_entry->generation_num == ref->generation_num) {
*result = xref_entry->byte_offset;
return ERR_NO;
}
xref_entry = xref_entry->next;
}
return ERR_NO_DATA;
}
const char *sigil_err_string(sigil_err_t err)
{
switch (err) {
......
#include "acroform.h"
#include "auxiliary.h"
#include "catalog_dict.h"
#include "constants.h"
#include "types.h"
sigil_err_t process_catalog_dictionary(sigil_t *sgl)
{
sigil_err_t err;
size_t offset;
dict_key_t dict_key;
char c;
if (sgl == NULL)
return ERR_PARAMETER;
if (sgl->ref_catalog_dict.object_num <= 0 &&
sgl->ref_catalog_dict.generation_num <= 0)
{
return ERR_NO_DATA;
}
err = pdf_goto_obj(sgl, &(sgl->ref_catalog_dict));
if (err != ERR_NO)
return err;
err = parse_word(sgl, "<<");
if (err != ERR_NO)
return err;
while ((err = parse_dict_key(sgl, &dict_key)) == ERR_NO) {
switch (dict_key) {
case DICT_KEY_AcroForm:
if ((err = skip_leading_whitespaces(sgl)) != ERR_NO)
return err;
if ((err = pdf_peek_char(sgl, &c)) != ERR_NO)
return err;
if (c == '<') {
if ((err = get_curr_position(sgl, &offset)) != ERR_NO)
return err;
sgl->offset_acroform = offset;
if ((err = parse_word(sgl, "<<")) != ERR_NO)
return err;
err = skip_dictionary(sgl);
if (err != ERR_NO)
return err;
} else {
err = parse_indirect_reference(sgl, &(sgl->ref_acroform));
if (err != ERR_NO)
return err;
}
break;
case DICT_KEY_UNKNOWN:
err = skip_dict_unknown_value(sgl);
if (err != ERR_NO)
return err;
break;
default:
return ERR_PDF_CONTENT;
}
}
if (err == ERR_END_OF_DICT)
return ERR_NO;
return err;
}
......@@ -29,6 +29,14 @@ int sigil_config_self_test(int verbosity)
print_test_result(1, verbosity);
// TEST: REF_ARRAY_PREALLOCATION
print_test_item("FIELDS_PREALLOCATION", verbosity);
if (REF_ARRAY_PREALLOCATION < 1)
goto failed;
print_test_result(1, verbosity);
// TEST: THRESHOLD_FILE_BUFFERING
print_test_item("THRESHOLD_FILE_BUFFERING", verbosity);
......
#include <stdlib.h>
#include <string.h>
#include <types.h>
#include "auxiliary.h"
#include "constants.h"
#include "sig_dict.h"
#define SUBFILTER_MAX 30
static sigil_err_t parse_subfilter(sigil_t *sgl)
{
sigil_err_t err;
int count = 0;
char tmp[SUBFILTER_MAX],
c;
sigil_zeroize(tmp, SUBFILTER_MAX * sizeof(*tmp));
err = parse_word(sgl, "/");
if (err != ERR_NO)
return err;
while ((err = pdf_peek_char(sgl, &c)) == ERR_NO) {
if (is_whitespace(c)) {
if (count <= 0)
return ERR_PDF_CONTENT;
break;
} else {
if (count >= SUBFILTER_MAX - 1)
return ERR_PDF_CONTENT;
tmp[count++] = c;
}
if ((err = pdf_move_pos_rel(sgl, 1)) != ERR_NO)
return err;
}
if (err != ERR_NO)
return err;
if (strncmp(tmp, "adbe.x509.rsa_sha1", 18) == 0) {
sgl->subfilter = SUBFILTER_adbe_x509_rsa_sha1;
} else {
sgl->subfilter = SUBFILTER_UNKNOWN;
}
return ERR_NO;
}
static sigil_err_t parse_byte_range(sigil_t *sgl)
{
sigil_err_t err;
range_t **byte_range;
size_t start,
length;
err = parse_word(sgl, "[");
if (err != ERR_NO)
return err;
byte_range = &(sgl->byte_range);
while (1) {
if (parse_word(sgl, "]") == ERR_NO)
return ERR_NO;
err = parse_number(sgl, &start);
if (err != ERR_NO)
return err;
err = parse_number(sgl, &length);
if (err != ERR_NO)
return err;
if (*byte_range == NULL) {
*byte_range = malloc(sizeof(**byte_range));
if (*byte_range == NULL)
return ERR_ALLOCATION;
sigil_zeroize(*byte_range, sizeof(**byte_range));
}
(*byte_range)->start = start;
(*byte_range)->length = length;
byte_range = &((*byte_range)->next);
}
}
sigil_err_t process_sig_dict(sigil_t *sgl)
{
sigil_err_t err;
dict_key_t dict_key;
if (sgl == NULL)
return ERR_PARAMETER;
if (sgl->offset_sig_dict <= 0 && sgl->ref_sig_dict.object_num > 0) {
err = pdf_goto_obj(sgl, &(sgl->ref_sig_dict));
if (err != ERR_NO)
return err;
} else {
err = pdf_move_pos_abs(sgl, sgl->offset_sig_dict);
if (err != ERR_NO)
return err;
}
err = parse_word(sgl, "<<");
if (err != ERR_NO)
return err;
while ((err = parse_dict_key(sgl, &dict_key)) == ERR_NO) {
switch (dict_key) {
case DICT_KEY_SubFilter:
if ((err = parse_subfilter(sgl)) != ERR_NO)
return err;
break;
case DICT_KEY_Cert:
break;
case DICT_KEY_Contents:
break;
case DICT_KEY_ByteRange:
if ((err = parse_byte_range(sgl)) != ERR_NO)
return err;
break;
case DICT_KEY_UNKNOWN:
err = skip_dict_unknown_value(sgl);
if (err != ERR_NO)
return err;
break;
default:
return ERR_PDF_CONTENT;
}
}
if (err == ERR_END_OF_DICT)
return ERR_NO;
return err;
}