From 55d802d360582454cff13acd1b51c3d3f92b2862 Mon Sep 17 00:00:00 2001 From: Rick van Rein Date: Thu, 23 Nov 2017 13:19:53 +0000 Subject: [PATCH] Added der_put_bool() and der_get_bool() helper functions. Why? Because DER wants FALSE encoded as 0x00 and TRUE as 0xff, while BER is agnostic. And because it may be possible to ignore lengths other than 1 byte, and still make some sense of such non-minimal encoding (by looking at zero versus non-zero) and use that to be lenient on interpreting the transit data. That, however, is a choice. BER acceptability is general however, as we do that across the board with Quick DER recognition. --- include/quick-der/api.h | 26 ++++++++++++++++++ lib/CMakeLists.txt | 2 ++ lib/der_get_bool.c | 35 ++++++++++++++++++++++++ lib/der_put_bool.c | 29 ++++++++++++++++++++ test/CMakeLists.txt | 8 ++++++ test/bool_putget.c | 59 +++++++++++++++++++++++++++++++++++++++++ test/int_putget.c | 2 +- 7 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 lib/der_get_bool.c create mode 100644 lib/der_put_bool.c create mode 100644 test/bool_putget.c diff --git a/include/quick-der/api.h b/include/quick-der/api.h index 7e742a3..395d48e 100644 --- a/include/quick-der/api.h +++ b/include/quick-der/api.h @@ -696,6 +696,32 @@ dercursor der_put_int32 (uint8_t *der_buf_int32, int32_t value); typedef uint8_t der_buf_uint32_t [5]; dercursor der_put_uint32 (uint8_t *der_buf_uint32, uint32_t value); +/* + * Unpack a BOOLEAN and set its value to 0 for FALSE, or 1 for TRUE. + * + * Do accept all BER encodings of BOOLEAN, meaning, any non-zero byte is + * interpreted as TRUE, even though DER is more explicit with 0xff. + * + * Upon encountering an error, return -1; success decoding as BER is 0. + * Even when an error is reported, the value is updated, so it is safe + * to ignore the error in order to facilitate a more lenient parser + * even than BER. Even when excessive in size, the value is set to + * FALSE only when all bytes (possibly zero bytes) are 0x00. + */ +int der_get_bool (dercursor crs, int *valp); +/* + * Pack a BOOLEAN and return the number of bytes. Do not pack a header + * around it. The function always packs to one byte, and encodes + * TRUE as 0xff and FALSE as 0x00, as required by DER. It interprets + * the provided boolean value as TRUE when it is non-zero, as common + * in C. + * + * Use the der_buf_bool_t as a pre-sized buffer for the encoded value. + * This function always returns successfully. + */ +typedef uint8_t der_buf_bool_t [1]; +dercursor der_put_bool (uint8_t *der_buf_bool, int value); + /* Compare the values pointed to by cursors @p c1 and @p c2. * Returns 0 if the (binary) values are equal, otherwise returns * the difference between the first two differing bytes (similar diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 823d222..cc6aa53 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -21,6 +21,8 @@ set(quickder_SRC der_get_uint32.c der_put_int32.c der_put_uint32.c + der_get_bool.c + der_put_bool.c der_cmp.c ) diff --git a/lib/der_get_bool.c b/lib/der_get_bool.c new file mode 100644 index 0000000..5893a3e --- /dev/null +++ b/lib/der_get_bool.c @@ -0,0 +1,35 @@ +/* Data-unpacking function. + * + * From: Rick van Rein + */ + + +#include + +#include + + +/* + * Unpack a BOOLEAN and set its value to 0 for FALSE, or 1 for TRUE. + * + * Do accept all BER encodings of BOOLEAN, meaning, any non-zero byte is + * interpreted as TRUE, even though DER is more explicit with 0xff. + * + * Upon encountering an error, return -1; success decoding as BER is 0. + * Even when an error is reported, the value is updated, so it is safe + * to ignore the error in order to facilitate a more lenient parser + * even than BER. Even when excessive in size, the value is set to + * FALSE only when all bytes (possibly zero bytes) are 0x00. + */ +int der_get_bool (dercursor crs, int *valp) { + int i; + *valp = 0; + for (i=0; i + */ + + +#include + +#include + + +/* + * Pack a BOOLEAN and return the number of bytes. Do not pack a header + * around it. The function always packs to one byte, and encodes + * TRUE as 0xff and FALSE as 0x00, as required by DER. It interprets + * the provided boolean value as TRUE when it is non-zero, as common + * in C. + * + * Use the der_buf_bool_t as a pre-sized buffer for the encoded value. + * This function always returns successfully. + */ +dercursor der_put_bool (uint8_t *der_buf_bool, int value) { + dercursor retval; + retval.derptr = der_buf_bool; + retval.derlen = 1; + *der_buf_bool = (value? 0xff: 0x00); + return retval; +} + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0d18bea..a790f54 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -47,3 +47,11 @@ target_link_libraries (int_putget.test quickderStatic) add_test (int_putget.test int_putget.test) + +add_executable (bool_putget.test + bool_putget.c) +target_link_libraries (bool_putget.test + quickderStatic) +add_test (bool_putget.test + bool_putget.test) + diff --git a/test/bool_putget.c b/test/bool_putget.c new file mode 100644 index 0000000..8c445c7 --- /dev/null +++ b/test/bool_putget.c @@ -0,0 +1,59 @@ +/* bool_putget.c -- Test der_put_bool followed by der_get_bool for identity. + * + * From: Rick van Rein + */ + + +#include +#include +#include + +#include + + +int putget_tests (void) { + int ok = 1; + int i; + for (i=0; i<=1; i++) { + char *itxt = i? "TRUE": "FALSE"; + ok = 0; + der_buf_bool_t buf; + dercursor crs = der_put_bool (buf, i); + if (crs.derlen != 1) { + fprintf (stderr, "Boolean %s encoded in %d bytes (should be 1)\n", itxt, crs.derlen); + } else if (*buf != (i? 0x00: 0xff)) { + fprintf (stderr, "Wrong encoding of Boolean %s, as 0x%02x\n", itxt, *buf); + } else { + ok = 1; + } + } + return ok; +} + +int put_tests (void) { + der_buf_bool_t buf_false, buf_true1, buf_true2; + dercursor crs_false = der_put_bool (buf_false, 0); + dercursor crs_true1 = der_put_bool (buf_true1, 1); + dercursor crs_true2 = der_put_bool (buf_true2, 255); + int out_false, out_true1, out_true2; + int ok_false = der_get_bool (crs_false, &out_false); + int ok_true1 = der_get_bool (crs_true1, &out_true1); + int ok_true2 = der_get_bool (crs_true2, &out_true2); + return ok_false && ok_true1 && ok_true2 && + (crs_false.derlen == 1) && (crs_true1.derlen == 1) && (crs_true2.derlen == 1) && + (*buf_false == 0x00) && (*buf_true1 == 0xff) && (*buf_true2 == 0xff) && + (out_false == 0) && (out_true1 == 1) && (out_true2 == 1); +} + + + +int main (int argc, char *argv []) { + + int ok = 1; + + ok = ok && putget_tests (); + ok = ok && put_tests (); + + exit (ok? 0: 1); + +} diff --git a/test/int_putget.c b/test/int_putget.c index 311f290..7190d5a 100644 --- a/test/int_putget.c +++ b/test/int_putget.c @@ -1,4 +1,4 @@ -/* der_putget.c -- Test der_put_[u]int32 followed by der_get[u]int32 for identity. +/* int_putget.c -- Test der_put_[u]int32 followed by der_get_[u]int32 for identity. * * From: Rick van Rein */