/* * xdr.c * ----- * Serialization/deserialization routines, using XDR (RFC 4506) encoding. * These functions are not part of the public libhal API. * * Copyright (c) 2016-2018, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of the NORDUnet nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include /* ptrdiff_t */ #include /* memcpy, memset */ #include "hal.h" #include "hal_internal.h" /* htonl/ntohl */ #include "xdr_internal.h" static int verbose = 0; /* suppress assert() error messages */ void hal_log(const hal_log_level_t level, const char *format, ...) { } #define DEFINE_HAL_ERROR(_code_,_text_) #_code_, static char *err_name[] = { HAL_ERROR_LIST }; #undef DEFINE_HAL_ERROR static void hexdump(uint8_t *buf, uint32_t len) { for (uint32_t i = 0; i < len; ++i) { printf("%02x", buf[i]); if (i < len - 1) printf(" "); } } #define test(name, result, expected) \ if ((err = result) != expected) { \ if (!verbose) printf("%s: ", func); \ printf("%s test returned %s, expected %s\n", \ name, err_name[err], err_name[expected]); \ ++nerr; \ } #define test_value(val, exp) \ if (val != exp) { \ if (!verbose) printf("%s: ", func); \ printf("value = %u, expected %u\n", val, exp); \ ++nerr; \ } #define test_len(len, exp) \ if (len != exp) { \ if (!verbose) printf("%s: ", func); \ printf("len = %lu, expected %u\n", len, exp); \ ++nerr; \ } #define test_memcmp(buf, exp, len) \ if (memcmp(buf, exp, len) != 0) { \ if (!verbose) printf("%s: ", func); \ printf("buffer = ["); \ hexdump(buf, len); \ printf("], expected ["); \ hexdump(exp, len); \ printf("]\n"); \ ++nerr; \ } #define test_bufptr(bfp, exp) \ if (bfp != exp) { \ if (!verbose) printf("%s: ", func); \ printf("buf ptr = %p, expected %p\n", bfp, exp); \ ++nerr; \ } static int test_hal_xdr_encode_int(void) { hal_error_t err = HAL_OK; int nerr = 0; uint8_t *null = NULL; uint8_t buf[4] = {0}; uint8_t *bufptr = buf; uint8_t *limit = buf + sizeof(buf); uint8_t exp[4] = { 0x00, 0x11, 0x22, 0x33 }; uint32_t value = 0x00112233; const char *func = "hal_xdr_encode_int"; if (verbose) printf("%s... ", func); test("null outbuf", hal_xdr_encode_int(NULL, limit, value), HAL_ERROR_ASSERTION_FAILED); test("null outbuf", hal_xdr_encode_int(&null, limit, value), HAL_ERROR_ASSERTION_FAILED); test("null limit", hal_xdr_encode_int(&bufptr, NULL, value), HAL_ERROR_ASSERTION_FAILED); test("outbuf overflow", hal_xdr_encode_int(&bufptr, buf, value), HAL_ERROR_XDR_BUFFER_OVERFLOW); test("outbuf overflow", hal_xdr_encode_int(&bufptr, buf + 3, value), HAL_ERROR_XDR_BUFFER_OVERFLOW); test("valid write", hal_xdr_encode_int(&bufptr, limit, value), HAL_OK); test_memcmp(buf, exp, sizeof(exp)); test_bufptr(bufptr, buf + 4); if (verbose && nerr == 0) printf("PASS\n"); return nerr; } static int test_hal_xdr_decode_int(void) { hal_error_t err = HAL_OK; int nerr = 0; const uint8_t *null = NULL; const uint8_t buf[4] = { 0x00, 0x11, 0x22, 0x33 }; const uint8_t *bufptr = buf; const uint8_t * const limit = buf + sizeof(buf); uint32_t value = 0; const uint32_t exp = 0x00112233; const char *func = "hal_xdr_decode_int"; if (verbose) printf("%s... ", func); test("null inbuf", hal_xdr_decode_int(NULL, limit, &value), HAL_ERROR_ASSERTION_FAILED); test("null inbuf", hal_xdr_decode_int(&null, limit, &value), HAL_ERROR_ASSERTION_FAILED); test("null limit", hal_xdr_decode_int(&bufptr, NULL, &value), HAL_ERROR_ASSERTION_FAILED); test("null value", hal_xdr_decode_int(&bufptr, limit, NULL), HAL_ERROR_ASSERTION_FAILED); test("inbuf overflow", hal_xdr_decode_int(&bufptr, buf, &value), HAL_ERROR_XDR_BUFFER_OVERFLOW); test("inbuf overflow", hal_xdr_decode_int(&bufptr, buf + 3, &value), HAL_ERROR_XDR_BUFFER_OVERFLOW); test("valid read", hal_xdr_decode_int(&bufptr, limit, &value), HAL_OK); test_value(value, exp); test_bufptr(bufptr, buf + 4); if (verbose && nerr == 0) printf("PASS\n"); return nerr; } static int test_hal_xdr_decode_int_peek(void) { hal_error_t err = HAL_OK; int nerr = 0; const uint8_t buf[4] = { 0x00, 0x11, 0x22, 0x33 }; const uint8_t *bufptr = buf; const uint8_t * const limit = buf + sizeof(buf); uint32_t value = 0; const uint32_t exp = 0x00112233; const char *func = "hal_xdr_decode_int_peek"; if (verbose) printf("%s... ", func); test("valid read", hal_xdr_decode_int_peek(&bufptr, limit, &value), HAL_OK); test_value(value, exp); test_bufptr(bufptr, buf); if (verbose && nerr == 0) printf("PASS\n"); return nerr; } static int test_hal_xdr_encode_fixed_opaque(void) { hal_error_t err = HAL_OK; int nerr = 0; uint8_t *null = NULL; uint8_t buf[8]; uint8_t *bufptr = buf; uint8_t *limit = buf + sizeof(buf); uint8_t src[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; uint8_t exp3[4] = { 0x00, 0x11, 0x22, 0x00 }; uint8_t exp4[4] = { 0x00, 0x11, 0x22, 0x33 }; uint8_t exp5[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00 }; const char *func = "hal_xdr_encode_fixed_opaque"; if (verbose) printf("%s... ", func); test("null outbuf", hal_xdr_encode_fixed_opaque(NULL, limit, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED); test("null outbuf", hal_xdr_encode_fixed_opaque(&null, limit, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED); test("null limit", hal_xdr_encode_fixed_opaque(&bufptr, NULL, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED); test("null value", hal_xdr_encode_fixed_opaque(&bufptr, limit, NULL, sizeof(src)), HAL_ERROR_ASSERTION_FAILED); test("outbuf overflow", hal_xdr_encode_fixed_opaque(&bufptr, buf, src, sizeof(src)), HAL_ERROR_XDR_BUFFER_OVERFLOW); memset(buf, 0xff, sizeof(buf)); test("write 3", hal_xdr_encode_fixed_opaque(&bufptr, limit, src, 3), HAL_OK); test_memcmp(buf, exp3, sizeof(exp3)); test_bufptr(bufptr, buf + 4); bufptr = buf; memset(buf, 0xff, sizeof(buf)); test("write 4", hal_xdr_encode_fixed_opaque(&bufptr, limit, src, 4), HAL_OK); test_memcmp(buf, exp4, sizeof(exp4)); test_bufptr(bufptr, buf + 4) bufptr = buf; memset(buf, 0xff, sizeof(buf)); test("write 5", hal_xdr_encode_fixed_opaque(&bufptr, limit, src, 5), HAL_OK); test_memcmp(buf, exp5, sizeof(exp5)); test_bufptr(bufptr, buf + 8); bufptr = buf; memset(buf, 0xff, sizeof(buf)); test("write 8", hal_xdr_encode_fixed_opaque(&bufptr, limit, src, 8), HAL_OK); test_memcmp(buf, src, sizeof(src)); test_bufptr(bufptr, buf + 8) if (verbose && nerr == 0) printf("PASS\n"); return nerr; } static int test_hal_xdr_decode_fixed_opaque(void) { hal_error_t err = HAL_OK; int nerr = 0; const uint8_t *null = NULL; const uint8_t buf[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; const uint8_t *bufptr = buf; const uint8_t *limit = buf + sizeof(buf); uint8_t value[8]; uint8_t exp3[4] = { 0x00, 0x11, 0x22, 0x00 }; uint8_t exp4[4] = { 0x00, 0x11, 0x22, 0x33 }; uint8_t exp5[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00 }; const char *func = "hal_xdr_decode_fixed_opaque"; if (verbose) printf("%s... ", func); test("null inbuf", hal_xdr_decode_fixed_opaque(NULL, limit, value, sizeof(value)), HAL_ERROR_ASSERTION_FAILED); test("null inbuf", hal_xdr_decode_fixed_opaque(&null, limit, value, sizeof(value)), HAL_ERROR_ASSERTION_FAILED); test("null limit", hal_xdr_decode_fixed_opaque(&bufptr, NULL, value, sizeof(value)), HAL_ERROR_ASSERTION_FAILED); test("null value", hal_xdr_decode_fixed_opaque(&bufptr, limit, NULL, sizeof(value)), HAL_ERROR_ASSERTION_FAILED); test("inbuf overflow", hal_xdr_decode_fixed_opaque(&bufptr, buf, value, sizeof(value)), HAL_ERROR_XDR_BUFFER_OVERFLOW); memset(value, 0xff, sizeof(value)); test("read 3", hal_xdr_decode_fixed_opaque(&bufptr, limit, value, 3), HAL_OK); test_memcmp(value, exp3, sizeof(exp3)); test_bufptr(bufptr, buf + 4); bufptr = buf; memset(value, 0xff, sizeof(value)); test("read 4", hal_xdr_decode_fixed_opaque(&bufptr, limit, value, 4), HAL_OK); test_memcmp(value, exp4, sizeof(exp4)); test_bufptr(bufptr, buf + 4); bufptr = buf; memset(value, 0xff, sizeof(value)); test("read 5", hal_xdr_decode_fixed_opaque(&bufptr, limit, value, 5), HAL_OK); test_memcmp(value, exp5, sizeof(exp5)); test_bufptr(bufptr, buf + 8); if (verbose && nerr == 0) printf("PASS\n"); return nerr; } static int test_hal_xdr_encode_variable_opaque(void) { hal_error_t err = HAL_OK; int nerr = 0; uint8_t *null = NULL; uint8_t buf[12]; uint8_t *bufptr = buf; uint8_t *limit = buf + sizeof(buf); uint8_t src[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; uint8_t exp3[8] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x11, 0x22, 0x00 }; uint8_t exp4[8] = { 0x00, 0x00, 0x00, 0x04, 0x00, 0x11, 0x22, 0x33 }; uint8_t exp5[12] = { 0x00, 0x00, 0x00, 0x05, 0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00 }; uint8_t exp8[12] = { 0x00, 0x00, 0x00, 0x08, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; const char *func = "hal_xdr_encode_variable_opaque"; if (verbose) printf("%s... ", func); test("null outbuf", hal_xdr_encode_variable_opaque(NULL, limit, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED); test("null outbuf", hal_xdr_encode_variable_opaque(&null, limit, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED); test("null limit", hal_xdr_encode_variable_opaque(&bufptr, NULL, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED); test("null value", hal_xdr_encode_variable_opaque(&bufptr, limit, NULL, sizeof(src)), HAL_ERROR_ASSERTION_FAILED); test("outbuf overflow", hal_xdr_encode_variable_opaque(&bufptr, buf, src, sizeof(src)), HAL_ERROR_XDR_BUFFER_OVERFLOW); memset(buf, 0xff, sizeof(buf)); test("write 3", hal_xdr_encode_variable_opaque(&bufptr, limit, src, 3), HAL_OK); test_memcmp(buf, exp3, sizeof(exp3)); test_bufptr(bufptr, buf + 8); bufptr = buf; memset(buf, 0xff, sizeof(buf)); test("write 4", hal_xdr_encode_variable_opaque(&bufptr, limit, src, 4), HAL_OK); test_memcmp(buf, exp4, sizeof(exp4)); test_bufptr(bufptr, buf + 8) bufptr = buf; memset(buf, 0xff, sizeof(buf)); test("write 5", hal_xdr_encode_variable_opaque(&bufptr, limit, src, 5), HAL_OK); test_memcmp(buf, exp5, sizeof(exp5)); test_bufptr(bufptr, buf + 12); bufptr = buf; memset(buf, 0xff, sizeof(buf)); test("write 8", hal_xdr_encode_variable_opaque(&bufptr, limit, src, 8), HAL_OK); test_memcmp(buf, exp8, sizeof(exp8)); test_bufptr(bufptr, buf + 12) if (verbose && nerr == 0) printf("PASS\n"); return nerr; } static int test_hal_xdr_decode_variable_opaque(void) { hal_error_t err = HAL_OK; int nerr = 0; const uint8_t *null = NULL; uint8_t buf[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; const uint8_t *bufptr = buf; const uint8_t *limit = buf + sizeof(buf); uint8_t value[12]; size_t len; uint8_t exp3[4] = { 0x00, 0x11, 0x22, 0x00 }; uint8_t exp4[4] = { 0x00, 0x11, 0x22, 0x33 }; uint8_t exp5[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00 }; uint8_t exp8[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; const char *func = "hal_xdr_decode_variable_opaque"; if (verbose) printf("%s... ", func); test("null inbuf", hal_xdr_decode_variable_opaque(NULL, limit, value, &len, sizeof(value)), HAL_ERROR_ASSERTION_FAILED); test("null inbuf", hal_xdr_decode_variable_opaque(&null, limit, value, &len, sizeof(value)), HAL_ERROR_ASSERTION_FAILED); test("null limit", hal_xdr_decode_variable_opaque(&bufptr, NULL, value, &len, sizeof(value)), HAL_ERROR_ASSERTION_FAILED); test("null value", hal_xdr_decode_variable_opaque(&bufptr, limit, NULL, &len, sizeof(value)), HAL_ERROR_ASSERTION_FAILED); test("inbuf overflow", hal_xdr_decode_variable_opaque(&bufptr, buf, value, &len, sizeof(value)), HAL_ERROR_XDR_BUFFER_OVERFLOW); buf[3] = 0x03; memset(value, 0xff, sizeof(value)); test("read 3", hal_xdr_decode_variable_opaque(&bufptr, limit, value, &len, sizeof(value)), HAL_OK); test_len(len, 3); test_memcmp(value, exp3, sizeof(exp3)); test_bufptr(bufptr, buf + 8); bufptr = buf; buf[3] = 0x04; memset(value, 0xff, sizeof(value)); test("read 4", hal_xdr_decode_variable_opaque(&bufptr, limit, value, &len, sizeof(value)), HAL_OK); test_len(len, 4); test_memcmp(value, exp4, sizeof(exp4)); test_bufptr(bufptr, buf + 8); bufptr = buf; buf[3] = 0x05; memset(value, 0xff, sizeof(value)); test("read 5", hal_xdr_decode_variable_opaque(&bufptr, limit, value, &len, sizeof(value)), HAL_OK); test_len(len, 5); test_memcmp(value, exp5, sizeof(exp5)); test_bufptr(bufptr, buf + 12); bufptr = buf; buf[3] = 0x08; memset(value, 0xff, sizeof(value)); test("read 8", hal_xdr_decode_variable_opaque(&bufptr, limit, value, &len, sizeof(value)), HAL_OK); test_len(len, 8); test_memcmp(value, exp8, sizeof(exp8)); test_bufptr(bufptr, buf + 12); if (verbose && nerr == 0) printf("PASS\n"); return nerr; } int main(int argc, char *argv[]) { if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'v') verbose = 1; int nerr = 0; nerr += test_hal_xdr_encode_int(); nerr += test_hal_xdr_decode_int(); nerr += test_hal_xdr_decode_int_peek(); nerr += test_hal_xdr_encode_fixed_opaque(); nerr += test_hal_xdr_decode_fixed_opaque(); nerr += test_hal_xdr_encode_variable_opaque(); nerr += test_hal_xdr_decode_variable_opaque(); if (nerr) printf("%d failures\n", nerr); return nerr; }