#line 2 "suites/target_test.function" #include "greentea-client/test_env.h" /** * \brief Increments pointer and asserts that it does not overflow. * * \param p Pointer to byte array * \param start Pointer to start of byte array * \param len Length of byte array * \param step Increment size * */ #define INCR_ASSERT(p, start, len, step) \ do { \ TEST_HELPER_ASSERT((p) >= (start)); \ TEST_HELPER_ASSERT(sizeof(*(p)) == sizeof(*(start))); \ /* <= is checked to support use inside a loop where \ pointer is incremented after reading data. */ \ TEST_HELPER_ASSERT((uint32_t)(((p) - (start)) + (step)) <= (len)); \ (p) += (step); \ } while (0) /** * \brief 4 byte align unsigned char pointer * * \param p Pointer to byte array * \param start Pointer to start of byte array * \param len Length of byte array * */ #define ALIGN_32BIT(p, start, len) \ do { \ uint32_t align = (-(uintptr_t)(p)) % 4; \ INCR_ASSERT((p), (start), (len), align); \ } while (0) /** * \brief Verify dependencies. Dependency identifiers are * encoded in the buffer as 8 bit unsigned integers. * * \param count Number of dependencies. * \param dep_p Pointer to buffer. * * \return DEPENDENCY_SUPPORTED if success else DEPENDENCY_NOT_SUPPORTED. */ int verify_dependencies(uint8_t count, uint8_t *dep_p) { uint8_t i; for (i = 0; i < count; i++) { if (dep_check((int)(dep_p[i])) != DEPENDENCY_SUPPORTED) return DEPENDENCY_NOT_SUPPORTED; } return DEPENDENCY_SUPPORTED; } /** * \brief Receives hex string on serial interface, and converts to a byte. * * \param none * * \return unsigned int8 */ uint8_t receive_byte() { uint8_t byte; uint8_t c[3]; size_t len; c[0] = greentea_getc(); c[1] = greentea_getc(); c[2] = '\0'; TEST_HELPER_ASSERT(mbedtls_test_unhexify(&byte, sizeof(byte), c, &len) == 0); TEST_HELPER_ASSERT(len != 2); return byte; } /** * \brief Receives unsigned integer on serial interface. * Integers are encoded in network order, and sent as hex ascii string. * * \param none * * \return unsigned int */ uint32_t receive_uint32() { uint32_t value; size_t len; const uint8_t c_be[8] = { greentea_getc(), greentea_getc(), greentea_getc(), greentea_getc(), greentea_getc(), greentea_getc(), greentea_getc(), greentea_getc() }; const uint8_t c[9] = { c_be[6], c_be[7], c_be[4], c_be[5], c_be[2], c_be[3], c_be[0], c_be[1], '\0' }; TEST_HELPER_ASSERT( mbedtls_test_unhexify((uint8_t *)&value, sizeof(value), c, &len) == 0); TEST_HELPER_ASSERT(len != 8); return value; } /** * \brief Parses out an unsigned 32 int value from the byte array. * Integers are encoded in network order. * * \param p Pointer to byte array * * \return unsigned int */ uint32_t parse_uint32(uint8_t *p) { uint32_t value; value = *p++ << 24; value |= *p++ << 16; value |= *p++ << 8; value |= *p; return value; } /** * \brief Receives test data on serial as greentea key,value pair: * {{;}} * * \param data_len Out pointer to hold received data length. * * \return Byte array. */ uint8_t *receive_data(uint32_t *data_len) { uint32_t i = 0, errors = 0; char c; uint8_t *data = NULL; /* Read opening braces */ i = 0; while (i < 2) { c = greentea_getc(); /* Ignore any prevous CR LF characters */ if (c == '\n' || c == '\r') continue; i++; if (c != '{') return NULL; } /* Read data length */ *data_len = receive_uint32(); data = (uint8_t *)malloc(*data_len); TEST_HELPER_ASSERT(data != NULL); greentea_getc(); // read ';' received after key i.e. *data_len for (i = 0; i < *data_len; i++) data[i] = receive_byte(); /* Read closing braces */ for (i = 0; i < 2; i++) { c = greentea_getc(); if (c != '}') { errors++; break; } } if (errors) { free(data); data = NULL; *data_len = 0; } return data; } /** * \brief Parse the received byte array and count the number of arguments * to the test function passed as type hex. * * \param count Parameter count * \param data Received Byte array * \param data_len Byte array length * * \return count of hex params */ uint32_t find_hex_count(uint8_t count, uint8_t *data, uint32_t data_len) { uint32_t i = 0, sz = 0; char c; uint8_t *p = NULL; uint32_t hex_count = 0; p = data; for (i = 0; i < count; i++) { c = (char)*p; INCR_ASSERT(p, data, data_len, 1); /* Align p to 4 bytes for int, expression, string len or hex length */ ALIGN_32BIT(p, data, data_len); /* Network to host conversion */ sz = (int32_t)parse_uint32(p); INCR_ASSERT(p, data, data_len, sizeof(int32_t)); if (c == 'H' || c == 'S') { INCR_ASSERT(p, data, data_len, sz); hex_count += (c == 'H') ? 1 : 0; } } return hex_count; } /** * \brief Parses received byte array for test parameters. * * \param count Parameter count * \param data Received Byte array * \param data_len Byte array length * \param error Parsing error out variable. * * \return Array of parsed parameters allocated on heap. * Note: Caller has the responsibility to delete * the memory after use. */ void ** parse_parameters(uint8_t count, uint8_t *data, uint32_t data_len, int *error) { uint32_t i = 0, hex_count = 0; char c; void **params = NULL; void **cur = NULL; uint8_t *p = NULL; hex_count = find_hex_count(count, data, data_len); params = (void **)malloc(sizeof(void *) * (count + hex_count)); TEST_HELPER_ASSERT(params != NULL); cur = params; p = data; /* Parameters */ for (i = 0; i < count; i++) { c = (char)*p; INCR_ASSERT(p, data, data_len, 1); /* Align p to 4 bytes for int, expression, string len or hex length */ ALIGN_32BIT(p, data, data_len); /* Network to host conversion */ *((int32_t *)p) = (int32_t)parse_uint32(p); switch (c) { case 'E': { if (get_expression(*((int32_t *)p), (int32_t *)p)) { *error = KEY_VALUE_MAPPING_NOT_FOUND; goto exit; } } /* Intentional fall through */ case 'I': { *cur++ = (void *)p; INCR_ASSERT(p, data, data_len, sizeof(int32_t)); } break; case 'H': /* Intentional fall through */ case 'S': { uint32_t *sz = (uint32_t *)p; INCR_ASSERT(p, data, data_len, sizeof(int32_t)); *cur++ = (void *)p; if (c == 'H') *cur++ = (void *)sz; INCR_ASSERT(p, data, data_len, (*sz)); } break; default: { *error = DISPATCH_INVALID_TEST_DATA; goto exit; } break; } } exit: if (*error) { free(params); params = NULL; } return params; } /** * \brief Sends greentea key and int value pair to host. * * \param key key string * \param value integer value * * \return void */ void send_key_integer(char *key, int value) { char str[50]; snprintf(str, sizeof(str), "%d", value); greentea_send_kv(key, str); } /** * \brief Sends test setup failure to the host. * * \param failure Test set failure * * \return void */ void send_failure(int failure) { send_key_integer("F", failure); } /** * \brief Sends test status to the host. * * \param status Test status (PASS=0/FAIL=!0) * * \return void */ void send_status(int status) { send_key_integer("R", status); } /** * \brief Embedded implementation of execute_tests(). * Ignores command line and received test data * on serial. * * \param argc not used * \param argv not used * * \return Program exit status. */ int execute_tests(int args, const char **argv) { int ret = 0; uint32_t data_len = 0; uint8_t count = 0, function_id; void **params = NULL; uint8_t *data = NULL, *p = NULL; GREENTEA_SETUP(800, "mbedtls_test"); greentea_send_kv("GO", " "); while (1) { ret = 0; mbedtls_test_info_reset(); data_len = 0; data = receive_data(&data_len); if (data == NULL) continue; p = data; do { /* Read dependency count */ count = *p; TEST_HELPER_ASSERT(count < data_len); INCR_ASSERT(p, data, data_len, sizeof(uint8_t)); ret = verify_dependencies(count, p); if (ret != DEPENDENCY_SUPPORTED) break; if (count) INCR_ASSERT(p, data, data_len, count); /* Read function id */ function_id = *p; INCR_ASSERT(p, data, data_len, sizeof(uint8_t)); if ((ret = check_test(function_id)) != DISPATCH_TEST_SUCCESS) break; /* Read number of parameters */ count = *p; INCR_ASSERT(p, data, data_len, sizeof(uint8_t)); /* Parse parameters if present */ if (count) { params = parse_parameters(count, p, data_len - (p - data), &ret); if (ret) break; } ret = dispatch_test(function_id, params); } while (0); if (data) { free(data); data = NULL; } if (params) { free(params); params = NULL; } if (ret) send_failure(ret); else send_status(mbedtls_test_info.result); } return 0; }