leo hendrickson / Mbed OS example-Ethernet-mbed-Cloud-connect
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pal_drbg_test.c Source File

pal_drbg_test.c

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2019 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 
00019 #include "pal.h"
00020 #include "unity.h"
00021 #include "unity_fixture.h"
00022 #include "pal_plat_drbg.h"
00023 #include "pal_plat_drbg.h"
00024 #include "test_runners.h"
00025 
00026 #include <string.h>
00027 #include <stdlib.h>
00028 
00029 #define TRACE_GROUP "PAL"
00030 
00031 TEST_GROUP(pal_drbg);
00032 
00033 #define PAL_RANDOM_TEST_LOOP 100000
00034 #define PAL_RANDOM_ARRAY_TEST_SIZE 100
00035 #define PAL_RANDOM_BUFFER_ARRAY_TEST_SIZE 60
00036 
00037 #define PAL_RUNNING_TEST_TIME   5  //estimation on length of test in seconds
00038 #define PAL_TEST_HIGH_RES_TIMER 100
00039 #define PAL_TEST_HIGH_RES_TIMER2 10
00040 #define PAL_TEST_PERCENTAGE_LOW 95
00041 #define PAL_TEST_PERCENTAGE_HIGH 105
00042 #define PAL_TEST_PERCENTAGE_HUNDRED  100
00043 
00044 
00045 TEST_SETUP(pal_drbg)
00046 {
00047     palStatus_t status = PAL_SUCCESS;
00048     status = pal_init();
00049     TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00050 
00051 #if !PAL_USE_HW_TRNG
00052     // If no hardware trng - entropy must be injected for random to work
00053     uint8_t entropy_buf[48] = { 0 };
00054     status = pal_osEntropyInject(entropy_buf, sizeof(entropy_buf));
00055     TEST_ASSERT(status == PAL_SUCCESS || status == PAL_ERR_ENTROPY_EXISTS);
00056 #endif
00057 
00058 }
00059 
00060 TEST_TEAR_DOWN(pal_drbg)
00061 {
00062     pal_destroy();
00063 }
00064 
00065 
00066 struct randBuf
00067 {
00068     uint8_t rand[6];
00069 };
00070 
00071 /*! \brief Check the random APIs. For each API, the test calls the random API in a loop
00072 * and stores the result. When the loop finishes, we verify that the count of the
00073 * duplication in the stored values is less than the defined random margin value for each API.
00074 *
00075 * | #  |    Step                                                                     |   Expected               |
00076 * |--- |-----------------------------------------------------------------------------|--------------------------|
00077 * | 1  | Fill array with random 32bit values using `pal_osRandom32bit` in a loop.    | PAL_SUCCESS              |
00078 * | 2  | Check array for matching values and make sure there are not too many.       | PAL_SUCCESS              |
00079 * | 3  | Fill array with random values using `pal_osRandomUniform` in a loop.        | PAL_SUCCESS              |
00080 * | 4  | Check array for matching values and make sure there are not too many.       | PAL_SUCCESS              |
00081 * | 5  | Fill array with random byte sequences using `pal_osRandomBuffer` in a loop. | PAL_SUCCESS              |
00082 * | 6  | Check array for matching values and make sure there are not too many.       | PAL_SUCCESS              |
00083 * | 7  | Call pal_osRandom32bit with NULL output parameter.                          | PAL_ERR_INVALID_ARGUMENT |
00084 * | 8  | Call pal_osRandomBuffer with NULL output parameter.                         | PAL_ERR_INVALID_ARGUMENT |
00085 * | 9  | Call pal_osRandomUniform with NULL output parameter.                        | PAL_ERR_INVALID_ARGUMENT |
00086 * | 10 | Call pal_osRandomBuffer while pal is not initialized.                       | PAL_ERR_NOT_INITIALIZED  |
00087 */
00088 TEST(pal_drbg, RandomUnityTest)
00089 {
00090     palStatus_t status = PAL_SUCCESS;
00091     uint32_t randomArray[PAL_RANDOM_ARRAY_TEST_SIZE];
00092     struct randBuf randomBufArray[PAL_RANDOM_BUFFER_ARRAY_TEST_SIZE];
00093     uint32_t randomMargin = 0;
00094 
00095     memset(randomArray, 0x0, sizeof(randomArray));
00096     memset(randomBufArray, 0x0, sizeof(randomBufArray));
00097     /*#1*/
00098     for(int i = 0; i < PAL_RANDOM_ARRAY_TEST_SIZE ; ++i)
00099     {
00100         status = pal_osRandom32bit(&randomArray[i]);
00101         TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00102     }
00103     /*#2*/
00104     for(int k = 0; k < PAL_RANDOM_ARRAY_TEST_SIZE ; ++k)
00105     {
00106         for (int j = k+1 ; j < PAL_RANDOM_ARRAY_TEST_SIZE ; ++j)
00107         {
00108             if (randomArray[k] == randomArray[j])
00109             {
00110                 ++randomMargin;
00111             }
00112         }
00113         randomArray[k] = 0;
00114     }
00115     TEST_ASSERT_TRUE(20 >= randomMargin);
00116     randomMargin = 0;
00117     /*#5*/
00118     for (int i = 0; i < PAL_RANDOM_BUFFER_ARRAY_TEST_SIZE ; ++i)
00119     {
00120         status = pal_osRandomBuffer(randomBufArray[i].rand, sizeof(randomBufArray[i].rand));
00121         TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00122     }
00123     /*#6*/
00124     for(int k = 0; k < PAL_RANDOM_BUFFER_ARRAY_TEST_SIZE ; ++k)
00125     {
00126         for (int j = k+1 ; j < PAL_RANDOM_BUFFER_ARRAY_TEST_SIZE ; ++j)
00127         {
00128             if(0 == memcmp(randomBufArray[k].rand, randomBufArray[j].rand, sizeof(uint8_t)*6))
00129             {
00130                 ++randomMargin;
00131             }
00132         }
00133     }
00134 
00135     TEST_ASSERT_TRUE(10 >= randomMargin);
00136 
00137 #ifdef DEBUG
00138     /*#7*/
00139     status = pal_osRandom32bit(NULL);
00140     TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT , status);
00141 
00142     /*#8*/
00143     status = pal_osRandomBuffer(NULL, 0);
00144     TEST_ASSERT_EQUAL_HEX(PAL_ERR_INVALID_ARGUMENT , status);
00145 
00146 
00147 #endif
00148 
00149 #if (PAL_INITIALIZED_BEFORE_TESTS == 0)
00150     /*#10*/
00151     pal_destroy();
00152 
00153     status = pal_osRandomBuffer(randomBufArray[0].rand, sizeof(randomBufArray[0].rand));
00154     TEST_ASSERT_EQUAL_HEX(PAL_ERR_NOT_INITIALIZED , status);
00155 #endif
00156 }
00157 
00158 
00159 /*! \brief call the random API in a PAL_RANDOM_TEST_LOOP loop.
00160 * | # |    Step                        |   Expected  |
00161 * |---|--------------------------------|-------------|
00162 * | 1 | Call `pal_osRandomBuffer` in a PAL_RANDOM_TEST_LOOP loop .         PAL_SUCCESS |
00163 */
00164 TEST(pal_drbg, loopRandomBigNumber)
00165 {
00166     palStatus_t status = PAL_SUCCESS;
00167     uint8_t loopRandomArray[PAL_RANDOM_ARRAY_TEST_SIZE];
00168 
00169     for (int i = 0; i < PAL_RANDOM_TEST_LOOP; ++i)
00170     {
00171         status = pal_osRandomBuffer(loopRandomArray, sizeof(loopRandomArray));
00172         TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00173     }
00174 }
00175 
00176 // the following functions are not part of PAL's external API hence extern
00177 extern palStatus_t pal_plat_noiseWriteValue(const int32_t* data, uint8_t startBit, uint8_t lenBits, uint8_t* bitsWritten);
00178 extern palStatus_t pal_plat_noiseWriteBuffer(int32_t* buffer, uint16_t lenBits, uint16_t* bitsWritten);
00179 extern palStatus_t pal_plat_noiseRead(int32_t buffer[PAL_NOISE_BUFFER_LEN], bool partial, uint16_t* bitsRead);
00180 
00181 /*! \brief This test verifies the functionality of noise collection
00182 *
00183 * | # |    Step                                                                                    |   Expected  |
00184 * |---|--------------------------------------------------------------------------------------------|-------------|
00185 * | 1 | Reset the noise buffer by reading whatever is available                                     | PAL_SUCCESS |
00186 * | 2 | Write an entire int32_t (all bits) and verify writes and that full read not possible       | PAL_SUCCESS |
00187 * | 3 | Write only some bits of the int32_t and verify writes and that full read not possible      | PAL_SUCCESS |
00188 * | 4 | Write only some bits of the int32_t, implicitly causing splitting the value into 2 indexes | PAL_SUCCESS |
00189 * | 5 | Read whatever was collected thus far (partial read) and verify output                      | PAL_SUCCESS |
00190 * | 6 | Try to read again and verify buffer is empty                                               | PAL_SUCCESS |
00191 * | 7 | Write a buffer excluding the last 7 bits of the last index and verify results              | PAL_SUCCESS |
00192 * | 8 | Fill the buffer and try to write some more data into it                                    | PAL_SUCCESS |
00193 */
00194 TEST(pal_drbg, pal_noise)
00195 {
00196     palStatus_t status;
00197     int32_t outBuffer[PAL_NOISE_BUFFER_LEN] = { 0 };
00198     int32_t inBuffer[] = { 0xB76EC265, 0xD16ACE6E, 0xF56AAD6A };
00199     uint16_t bitsWritten = 0;
00200     uint16_t bitsRead = 0;
00201     int32_t writeValue;
00202     uint8_t i;
00203 
00204     /*#1*/
00205     pal_plat_noiseRead(outBuffer, true, &bitsRead);
00206     memset(outBuffer, 0, PAL_NOISE_SIZE_BYTES);
00207 
00208     /*#2*/
00209     writeValue = 0xCB76102A;
00210     status = pal_plat_noiseWriteValue(&writeValue, 0, 32, (uint8_t*)&bitsWritten); // write all bits
00211     TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00212     TEST_ASSERT_EQUAL(32, bitsWritten);
00213     status = pal_plat_noiseRead(outBuffer, false, &bitsRead);
00214     TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_NOISE_BUFFER_NOT_FULL , status);
00215     TEST_ASSERT_EQUAL(0, bitsRead);
00216 
00217     /*#3*/
00218     status = pal_plat_noiseWriteValue(&writeValue, 3, 20, (uint8_t*)&bitsWritten); // write some of the bits, starting at bit index 3
00219     TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00220     TEST_ASSERT_EQUAL(20, bitsWritten);
00221     status = pal_plat_noiseRead(outBuffer, false, &bitsRead);
00222     TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_NOISE_BUFFER_NOT_FULL , status);
00223     TEST_ASSERT_EQUAL(0, bitsRead);
00224 
00225     /*#4*/
00226     status = pal_plat_noiseWriteValue(&writeValue, 16, 16, (uint8_t*)&bitsWritten); // write some of the bits, starting at bit index 16, this functionality tests splitting the bits into 2 different indexes
00227     TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00228     TEST_ASSERT_EQUAL(16, bitsWritten);
00229     status = pal_plat_noiseRead(outBuffer, false, &bitsRead);
00230     TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_NOISE_BUFFER_NOT_FULL , status);
00231     TEST_ASSERT_EQUAL(0, bitsRead);
00232 
00233     /*#5*/
00234     status = pal_plat_noiseRead(outBuffer, true, &bitsRead); // read whatever collected (resets buffer)
00235     TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00236     TEST_ASSERT_EQUAL(64, bitsRead); // even though we wrote 68 bits by now, output should be 64 since the last byte is not full so we should not receive it back
00237     TEST_ASSERT_EQUAL_HEX(0xCB76102A, outBuffer[0]);
00238     TEST_ASSERT_EQUAL_HEX(0xB76EC205, outBuffer[1]);
00239     TEST_ASSERT_EQUAL_HEX(0, outBuffer[2]);
00240     memset(outBuffer, 0, PAL_NOISE_SIZE_BYTES);
00241 
00242     /*#6*/
00243     status = pal_plat_noiseRead(outBuffer, false, &bitsRead);
00244     TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_NOISE_BUFFER_EMPTY , status);
00245     TEST_ASSERT_EQUAL(0, bitsRead);
00246 
00247     /*#7*/
00248     status = pal_plat_noiseWriteBuffer(inBuffer, ((sizeof(inBuffer) * CHAR_BIT) - 7), &bitsWritten); // write all except for the last 7 bits of index 2
00249     TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00250     TEST_ASSERT_EQUAL(((sizeof(inBuffer) * CHAR_BIT) - 7), bitsWritten);
00251     status = pal_plat_noiseRead(outBuffer, false, &bitsRead);
00252     TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_NOISE_BUFFER_NOT_FULL , status);
00253     TEST_ASSERT_EQUAL(0, bitsRead);
00254     status = pal_plat_noiseRead(outBuffer, true, &bitsRead); // read whatever collected (resets buffer)
00255     TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00256     TEST_ASSERT_NOT_EQUAL(0, bitsRead);
00257     TEST_ASSERT_EQUAL_HEX(inBuffer[0], outBuffer[0]);
00258     TEST_ASSERT_EQUAL_HEX(inBuffer[1], outBuffer[1]);
00259     TEST_ASSERT_EQUAL_HEX(0x6AAD6A, outBuffer[2]);
00260 
00261     /*#8*/
00262     for (i = 0; i <= (sizeof(inBuffer) / sizeof(int32_t)); ++i)
00263     {
00264         status = pal_plat_noiseWriteBuffer(inBuffer, (sizeof(inBuffer) * CHAR_BIT), &bitsWritten);
00265         TEST_ASSERT_EQUAL_HEX(PAL_SUCCESS, status);
00266         TEST_ASSERT_EQUAL_HEX((sizeof(inBuffer) * CHAR_BIT), bitsWritten);
00267     }
00268     status = pal_plat_noiseWriteBuffer(inBuffer, (sizeof(inBuffer) * CHAR_BIT), &bitsWritten);
00269     TEST_ASSERT_EQUAL_HEX(PAL_ERR_RTOS_NOISE_BUFFER_FULL , status);
00270     TEST_ASSERT_EQUAL_HEX(0, bitsWritten);
00271 }