quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

test_suite_psa_crypto_ecp.function (5784B)


      1 /* BEGIN_HEADER */
      2 /* Unit tests for internal functions for built-in ECC mechanisms. */
      3 #include <psa/crypto.h>
      4 
      5 #include "psa_crypto_ecp.h"
      6 
      7 #if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE)
      8 /*
      9  * Check if a buffer is all-0 bytes:
     10  * return   1 if it is,
     11  *          0 if it isn't.
     12  *
     13  * TODO: we use this in multiple test suites. Move it to framework/tests/src.
     14  */
     15 static int buffer_is_all_zero(const uint8_t *buf, size_t size)
     16 {
     17     for (size_t i = 0; i < size; i++) {
     18         if (buf[i] != 0) {
     19             return 0;
     20         }
     21     }
     22     return 1;
     23 }
     24 
     25 typedef struct {
     26     unsigned bit_bot;           /* lowest non-forced bit */
     27     unsigned bit_top;           /* highest non-forced bit */
     28 } ecc_private_key_stats_t;
     29 
     30 /* Do some sanity checks on an ECC private key. This is not intended to be
     31  * a full validity check, just to catch some potential mistakes. */
     32 static int check_ecc_private_key(psa_ecc_family_t family, size_t bits,
     33                                  const uint8_t *key, size_t key_length,
     34                                  ecc_private_key_stats_t *stats)
     35 {
     36     int ok = 0;
     37 
     38     /* Check the expected length (same calculation for all curves). */
     39     TEST_EQUAL(PSA_BITS_TO_BYTES(bits), key_length);
     40 
     41     /* All-bits zero is invalid and means no key material was copied to the
     42      * output buffer, or a grave RNG pluming failure. */
     43     TEST_ASSERT(!buffer_is_all_zero(key, key_length));
     44 
     45     /* Check the top byte of the value for non-byte-aligned curve sizes.
     46      * This is a partial endianness check. */
     47     if (bits % 8 != 0) {
     48         /* All supported non-byte-aligned curve sizes are for Weierstrass
     49          * curves with a big-endian representation. */
     50         uint8_t top_byte = key[0];
     51         uint8_t mask = 0xff << (bits & 8);
     52         TEST_EQUAL(top_byte & mask, 0);
     53     }
     54 
     55     /* Check masked bits on Curve25519 and Curve448 scalars.
     56      * See RFC 7748 \S4.1 (we expect the "decoded" form here). */
     57 #if defined(MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255)
     58     if (family == PSA_ECC_FAMILY_MONTGOMERY && bits == 255) {
     59         TEST_EQUAL(key[0] & 0xf8, key[0]);
     60         TEST_EQUAL(key[31] & 0xc0, 0x40);
     61     }
     62 #endif /* MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_255 */
     63 #if defined(MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448)
     64     if (family == PSA_ECC_FAMILY_MONTGOMERY && bits == 448) {
     65         TEST_EQUAL(key[0] & 0xfc, key[0]);
     66         TEST_EQUAL(key[55] & 0x80, 0x80);
     67     }
     68 #endif /* MBEDTLS_PSA_BUILTIN_ECC_MONTGOMERY_448 */
     69 
     70     /* Don't bother to check that the value is in the exact permitted range
     71      * (1 to p-1 for Weierstrass curves, 2^{n-1} to p-1 for Montgomery curves).
     72      * We would need to bring in bignum machinery, and on most curves
     73      * the probability of a number being out of range is negligible.
     74      */
     75 
     76     /* Collect statistics on random-valued bits */
     77     /* Defaults for big-endian numbers */
     78     uint8_t bit_bot_mask = 0x01;
     79     size_t bit_bot_index = key_length - 1;
     80     uint8_t bit_top_mask = (bits % 8 == 0 ? 0x80 : 1 << (bits % 8 - 1));
     81     size_t bit_top_index = 0;
     82     if (family == PSA_ECC_FAMILY_MONTGOMERY) {
     83         bit_bot_index = 0;
     84         bit_top_index = key_length - 1;
     85         if (bits == 255) {
     86             bit_bot_mask = 0x08;
     87             bit_top_mask = 0x20;
     88         } else {
     89             bit_bot_mask = 0x04;
     90             bit_top_mask = 0x40;
     91         }
     92     }
     93     if (key[bit_bot_index] & bit_bot_mask) {
     94         ++stats->bit_bot;
     95     }
     96     if (key[bit_top_index] & bit_top_mask) {
     97         ++stats->bit_top;
     98     }
     99 
    100     ok = 1;
    101 exit:
    102     return ok;
    103 }
    104 #endif
    105 
    106 /* END_HEADER */
    107 
    108 /* BEGIN_DEPENDENCIES
    109  * depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY
    110  * END_DEPENDENCIES
    111  */
    112 
    113 /* BEGIN_CASE depends_on:MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE */
    114 void generate_key(int family_arg, int bits_arg,
    115                   int output_size_arg,
    116                   psa_status_t expected_status)
    117 {
    118     psa_ecc_family_t family = family_arg;
    119     size_t bits = bits_arg;
    120     size_t output_size = output_size_arg;
    121 
    122     uint8_t *output = NULL;
    123     size_t output_length = SIZE_MAX;
    124     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    125     psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(family));
    126     psa_set_key_bits(&attributes, bits);
    127     ecc_private_key_stats_t stats = { 0, 0 };
    128 
    129     PSA_INIT();
    130     TEST_CALLOC(output, output_size);
    131 
    132     /* In success cases, run multiple iterations so that we can make
    133      * statistical observations. */
    134     unsigned iteration_count = expected_status == PSA_SUCCESS ? 256 : 1;
    135     for (unsigned i = 0; i < iteration_count; i++) {
    136         mbedtls_test_set_step(i);
    137         TEST_EQUAL(mbedtls_psa_ecp_generate_key(&attributes,
    138                                                 output, output_size,
    139                                                 &output_length),
    140                    expected_status);
    141         if (expected_status == PSA_SUCCESS) {
    142             TEST_LE_U(output_length, output_size);
    143             TEST_ASSERT(check_ecc_private_key(family, bits,
    144                                               output, output_length,
    145                                               &stats));
    146         }
    147     }
    148 
    149     if (expected_status == PSA_SUCCESS) {
    150         /* For selected bits, check that we saw the values 0 and 1 each
    151          * at least some minimum number of times. The iteration count and
    152          * the minimum are chosen so that a random failure is unlikely
    153          * to more than cryptographic levels. */
    154         unsigned const min_times = 10;
    155         TEST_LE_U(min_times, stats.bit_bot);
    156         TEST_LE_U(stats.bit_bot, iteration_count - min_times);
    157         TEST_LE_U(min_times, stats.bit_top);
    158         TEST_LE_U(stats.bit_top, iteration_count - min_times);
    159     }
    160 
    161 exit:
    162     PSA_DONE();
    163     mbedtls_free(output);
    164 }
    165 /* END_CASE */