Home | History | Annotate | Line # | Download | only in testutil
      1 /*
      2  * Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the OpenSSL license (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include "../testutil.h"
     11 #include "output.h"
     12 #include "tu_local.h"
     13 
     14 #include <errno.h>
     15 #include <string.h>
     16 #include <ctype.h>
     17 #include "internal/nelem.h"
     18 #include <openssl/asn1.h>
     19 
     20 /*
     21  * Output a failed test first line.
     22  * All items are optional are generally not preinted if passed as NULL.
     23  * The special cases are for prefix where "ERROR" is assumed and for left
     24  * and right where a non-failure message is produced if either is NULL.
     25  */
     26 void test_fail_message_prefix(const char *prefix, const char *file,
     27                               int line, const char *type,
     28                               const char *left, const char *right,
     29                               const char *op)
     30 {
     31     test_printf_stderr("%s: ", prefix != NULL ? prefix : "ERROR");
     32     if (type)
     33         test_printf_stderr("(%s) ", type);
     34     if (op != NULL) {
     35         if (left != NULL && right != NULL)
     36             test_printf_stderr("'%s %s %s' failed", left, op, right);
     37         else
     38             test_printf_stderr("'%s'", op);
     39     }
     40     if (file != NULL) {
     41         test_printf_stderr(" @ %s:%d", file, line);
     42     }
     43     test_printf_stderr("\n");
     44 }
     45 
     46 /*
     47  * A common routine to output test failure messages.  Generally this should not
     48  * be called directly, rather it should be called by the following functions.
     49  *
     50  * |desc| is a printf formatted description with arguments |args| that is
     51  * supplied by the user and |desc| can be NULL.  |type| is the data type
     52  * that was tested (int, char, ptr, ...).  |fmt| is a system provided
     53  * printf format with following arguments that spell out the failure
     54  * details i.e. the actual values compared and the operator used.
     55  *
     56  * The typical use for this is from an utility test function:
     57  *
     58  * int test6(const char *file, int line, int n) {
     59  *     if (n != 6) {
     60  *         test_fail_message(1, file, line, "int", "value %d is not %d", n, 6);
     61  *         return 0;
     62  *     }
     63  *     return 1;
     64  * }
     65  *
     66  * calling test6(3, "oops") will return 0 and produce out along the lines of:
     67  *      FAIL oops: (int) value 3 is not 6\n
     68  */
     69 static void test_fail_message(const char *prefix, const char *file, int line,
     70                               const char *type, const char *left,
     71                               const char *right, const char *op,
     72                               const char *fmt, ...)
     73             PRINTF_FORMAT(8, 9);
     74 
     75 PRINTF_FORMAT(8, 0)
     76 static void test_fail_message_va(const char *prefix, const char *file,
     77                                  int line, const char *type,
     78                                  const char *left, const char *right,
     79                                  const char *op, const char *fmt, va_list ap)
     80 {
     81     test_fail_message_prefix(prefix, file, line, type, left, right, op);
     82     if (fmt != NULL) {
     83         test_vprintf_stderr(fmt, ap);
     84         test_printf_stderr("\n");
     85     }
     86     test_flush_stderr();
     87 }
     88 
     89 static void test_fail_message(const char *prefix, const char *file,
     90                               int line, const char *type,
     91                               const char *left, const char *right,
     92                               const char *op, const char *fmt, ...)
     93 {
     94     va_list ap;
     95 
     96     va_start(ap, fmt);
     97     test_fail_message_va(prefix, file, line, type, left, right, op, fmt, ap);
     98     va_end(ap);
     99 }
    100 
    101 void test_info_c90(const char *desc, ...)
    102 {
    103     va_list ap;
    104 
    105     va_start(ap, desc);
    106     test_fail_message_va("INFO", NULL, -1, NULL, NULL, NULL, NULL, desc, ap);
    107     va_end(ap);
    108 }
    109 
    110 void test_info(const char *file, int line, const char *desc, ...)
    111 {
    112     va_list ap;
    113 
    114     va_start(ap, desc);
    115     test_fail_message_va("INFO", file, line, NULL, NULL, NULL, NULL, desc, ap);
    116     va_end(ap);
    117 }
    118 
    119 void test_error_c90(const char *desc, ...)
    120 {
    121     va_list ap;
    122 
    123     va_start(ap, desc);
    124     test_fail_message_va(NULL, NULL, -1, NULL, NULL, NULL, NULL, desc, ap);
    125     va_end(ap);
    126     test_printf_stderr("\n");
    127 }
    128 
    129 void test_error(const char *file, int line, const char *desc, ...)
    130 {
    131     va_list ap;
    132 
    133     va_start(ap, desc);
    134     test_fail_message_va(NULL, file, line, NULL, NULL, NULL, NULL, desc, ap);
    135     va_end(ap);
    136     test_printf_stderr("\n");
    137 }
    138 
    139 void test_perror(const char *s)
    140 {
    141     /*
    142      * Using openssl_strerror_r causes linking issues since it isn't
    143      * exported from libcrypto.so
    144      */
    145     TEST_error("%s: %s", s, strerror(errno));
    146 }
    147 
    148 void test_note(const char *fmt, ...)
    149 {
    150     if (fmt != NULL) {
    151         va_list ap;
    152 
    153         va_start(ap, fmt);
    154         test_vprintf_stderr(fmt, ap);
    155         va_end(ap);
    156         test_printf_stderr("\n");
    157     }
    158     test_flush_stderr();
    159 }
    160 
    161 void test_openssl_errors(void)
    162 {
    163     ERR_print_errors_cb(openssl_error_cb, NULL);
    164     ERR_clear_error();
    165 }
    166 
    167 /*
    168  * Define some comparisons between pairs of various types.
    169  * These functions return 1 if the test is true.
    170  * Otherwise, they return 0 and pretty-print diagnostics.
    171  *
    172  * In each case the functions produced are:
    173  *  int test_name_eq(const type t1, const type t2, const char *desc, ...);
    174  *  int test_name_ne(const type t1, const type t2, const char *desc, ...);
    175  *  int test_name_lt(const type t1, const type t2, const char *desc, ...);
    176  *  int test_name_le(const type t1, const type t2, const char *desc, ...);
    177  *  int test_name_gt(const type t1, const type t2, const char *desc, ...);
    178  *  int test_name_ge(const type t1, const type t2, const char *desc, ...);
    179  *
    180  * The t1 and t2 arguments are to be compared for equality, inequality,
    181  * less than, less than or equal to, greater than and greater than or
    182  * equal to respectively.  If the specified condition holds, the functions
    183  * return 1.  If the condition does not hold, the functions print a diagnostic
    184  * message and return 0.
    185  *
    186  * The desc argument is a printf format string followed by its arguments and
    187  * this is included in the output if the condition being tested for is false.
    188  */
    189 #define DEFINE_COMPARISON(type, name, opname, op, fmt)                  \
    190     int test_ ## name ## _ ## opname(const char *file, int line,        \
    191                                      const char *s1, const char *s2,    \
    192                                      const type t1, const type t2)      \
    193     {                                                                   \
    194         if (t1 op t2)                                                   \
    195             return 1;                                                   \
    196         test_fail_message(NULL, file, line, #type, s1, s2, #op,         \
    197                           "[" fmt "] compared to [" fmt "]",            \
    198                           t1, t2);                                      \
    199         return 0;                                                       \
    200     }
    201 
    202 #define DEFINE_COMPARISONS(type, name, fmt)                             \
    203     DEFINE_COMPARISON(type, name, eq, ==, fmt)                          \
    204     DEFINE_COMPARISON(type, name, ne, !=, fmt)                          \
    205     DEFINE_COMPARISON(type, name, lt, <, fmt)                           \
    206     DEFINE_COMPARISON(type, name, le, <=, fmt)                          \
    207     DEFINE_COMPARISON(type, name, gt, >, fmt)                           \
    208     DEFINE_COMPARISON(type, name, ge, >=, fmt)
    209 
    210 DEFINE_COMPARISONS(int, int, "%d")
    211 DEFINE_COMPARISONS(unsigned int, uint, "%u")
    212 DEFINE_COMPARISONS(char, char, "%c")
    213 DEFINE_COMPARISONS(unsigned char, uchar, "%u")
    214 DEFINE_COMPARISONS(long, long, "%ld")
    215 DEFINE_COMPARISONS(unsigned long, ulong, "%lu")
    216 DEFINE_COMPARISONS(size_t, size_t, "%zu")
    217 
    218 DEFINE_COMPARISON(void *, ptr, eq, ==, "%p")
    219 DEFINE_COMPARISON(void *, ptr, ne, !=, "%p")
    220 
    221 int test_ptr_null(const char *file, int line, const char *s, const void *p)
    222 {
    223     if (p == NULL)
    224         return 1;
    225     test_fail_message(NULL, file, line, "ptr", s, "NULL", "==", "%p", p);
    226     return 0;
    227 }
    228 
    229 int test_ptr(const char *file, int line, const char *s, const void *p)
    230 {
    231     if (p != NULL)
    232         return 1;
    233     test_fail_message(NULL, file, line, "ptr", s, "NULL", "!=", "%p", p);
    234     return 0;
    235 }
    236 
    237 int test_true(const char *file, int line, const char *s, int b)
    238 {
    239     if (b)
    240         return 1;
    241     test_fail_message(NULL, file, line, "bool", s, "true", "==", "false");
    242     return 0;
    243 }
    244 
    245 int test_false(const char *file, int line, const char *s, int b)
    246 {
    247     if (!b)
    248         return 1;
    249     test_fail_message(NULL, file, line, "bool", s, "false", "==", "true");
    250     return 0;
    251 }
    252 
    253 int test_str_eq(const char *file, int line, const char *st1, const char *st2,
    254                 const char *s1, const char *s2)
    255 {
    256     if (s1 == NULL && s2 == NULL)
    257       return 1;
    258     if (s1 == NULL || s2 == NULL || strcmp(s1, s2) != 0) {
    259         test_fail_string_message(NULL, file, line, "string", st1, st2, "==",
    260                                  s1, s1 == NULL ? 0 : strlen(s1),
    261                                  s2, s2 == NULL ? 0 : strlen(s2));
    262         return 0;
    263     }
    264     return 1;
    265 }
    266 
    267 int test_str_ne(const char *file, int line, const char *st1, const char *st2,
    268                 const char *s1, const char *s2)
    269 {
    270     if ((s1 == NULL) ^ (s2 == NULL))
    271       return 1;
    272     if (s1 == NULL || strcmp(s1, s2) == 0) {
    273         test_fail_string_message(NULL, file, line, "string", st1, st2, "!=",
    274                                  s1, s1 == NULL ? 0 : strlen(s1),
    275                                  s2, s2 == NULL ? 0 : strlen(s2));
    276         return 0;
    277     }
    278     return 1;
    279 }
    280 
    281 int test_strn_eq(const char *file, int line, const char *st1, const char *st2,
    282                  const char *s1, const char *s2, size_t len)
    283 {
    284     if (s1 == NULL && s2 == NULL)
    285       return 1;
    286     if (s1 == NULL || s2 == NULL || strncmp(s1, s2, len) != 0) {
    287         test_fail_string_message(NULL, file, line, "string", st1, st2, "==",
    288                                  s1, s1 == NULL ? 0 : OPENSSL_strnlen(s1, len),
    289                                  s2, s2 == NULL ? 0 : OPENSSL_strnlen(s2, len));
    290         return 0;
    291     }
    292     return 1;
    293 }
    294 
    295 int test_strn_ne(const char *file, int line, const char *st1, const char *st2,
    296                  const char *s1, const char *s2, size_t len)
    297 {
    298     if ((s1 == NULL) ^ (s2 == NULL))
    299       return 1;
    300     if (s1 == NULL || strncmp(s1, s2, len) == 0) {
    301         test_fail_string_message(NULL, file, line, "string", st1, st2, "!=",
    302                                  s1, s1 == NULL ? 0 : OPENSSL_strnlen(s1, len),
    303                                  s2, s2 == NULL ? 0 : OPENSSL_strnlen(s2, len));
    304         return 0;
    305     }
    306     return 1;
    307 }
    308 
    309 int test_mem_eq(const char *file, int line, const char *st1, const char *st2,
    310                 const void *s1, size_t n1, const void *s2, size_t n2)
    311 {
    312     if (s1 == NULL && s2 == NULL)
    313         return 1;
    314     if (n1 != n2 || s1 == NULL || s2 == NULL || memcmp(s1, s2, n1) != 0) {
    315         test_fail_memory_message(NULL, file, line, "memory", st1, st2, "==",
    316                                  s1, n1, s2, n2);
    317         return 0;
    318     }
    319     return 1;
    320 }
    321 
    322 int test_mem_ne(const char *file, int line, const char *st1, const char *st2,
    323                 const void *s1, size_t n1, const void *s2, size_t n2)
    324 {
    325     if ((s1 == NULL) ^ (s2 == NULL))
    326         return 1;
    327     if (n1 != n2)
    328         return 1;
    329     if (s1 == NULL || memcmp(s1, s2, n1) == 0) {
    330         test_fail_memory_message(NULL, file, line, "memory", st1, st2, "!=",
    331                                  s1, n1, s2, n2);
    332         return 0;
    333     }
    334     return 1;
    335 }
    336 
    337 #define DEFINE_BN_COMPARISONS(opname, op, zero_cond)                    \
    338     int test_BN_ ## opname(const char *file, int line,                  \
    339                            const char *s1, const char *s2,              \
    340                            const BIGNUM *t1, const BIGNUM *t2)          \
    341     {                                                                   \
    342         if (BN_cmp(t1, t2) op 0)                                        \
    343             return 1;                                                   \
    344         test_fail_bignum_message(NULL, file, line, "BIGNUM", s1, s2,    \
    345                                  #op, t1, t2);                          \
    346         return 0;                                                       \
    347     }                                                                   \
    348     int test_BN_ ## opname ## _zero(const char *file, int line,         \
    349                                     const char *s, const BIGNUM *a)     \
    350     {                                                                   \
    351         if (a != NULL &&(zero_cond))                                    \
    352             return 1;                                                   \
    353         test_fail_bignum_mono_message(NULL, file, line, "BIGNUM",       \
    354                                       s, "0", #op, a);                  \
    355         return 0;                                                       \
    356     }
    357 
    358 DEFINE_BN_COMPARISONS(eq, ==, BN_is_zero(a))
    359 DEFINE_BN_COMPARISONS(ne, !=, !BN_is_zero(a))
    360 DEFINE_BN_COMPARISONS(gt, >,  !BN_is_negative(a) && !BN_is_zero(a))
    361 DEFINE_BN_COMPARISONS(ge, >=, !BN_is_negative(a) || BN_is_zero(a))
    362 DEFINE_BN_COMPARISONS(lt, <,  BN_is_negative(a) && !BN_is_zero(a))
    363 DEFINE_BN_COMPARISONS(le, <=, BN_is_negative(a) || BN_is_zero(a))
    364 
    365 int test_BN_eq_one(const char *file, int line, const char *s, const BIGNUM *a)
    366 {
    367     if (a != NULL && BN_is_one(a))
    368         return 1;
    369     test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", s, "1", "==", a);
    370     return 0;
    371 }
    372 
    373 int test_BN_odd(const char *file, int line, const char *s, const BIGNUM *a)
    374 {
    375     if (a != NULL && BN_is_odd(a))
    376         return 1;
    377     test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", "ODD(", ")", s, a);
    378     return 0;
    379 }
    380 
    381 int test_BN_even(const char *file, int line, const char *s, const BIGNUM *a)
    382 {
    383     if (a != NULL && !BN_is_odd(a))
    384         return 1;
    385     test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", "EVEN(", ")", s,
    386                                   a);
    387     return 0;
    388 }
    389 
    390 int test_BN_eq_word(const char *file, int line, const char *bns, const char *ws,
    391                     const BIGNUM *a, BN_ULONG w)
    392 {
    393     BIGNUM *bw;
    394 
    395     if (a != NULL && BN_is_word(a, w))
    396         return 1;
    397     if ((bw = BN_new()) != NULL)
    398         BN_set_word(bw, w);
    399     test_fail_bignum_message(NULL, file, line, "BIGNUM", bns, ws, "==", a, bw);
    400     BN_free(bw);
    401     return 0;
    402 }
    403 
    404 int test_BN_abs_eq_word(const char *file, int line, const char *bns,
    405                         const char *ws, const BIGNUM *a, BN_ULONG w)
    406 {
    407     BIGNUM *bw, *aa;
    408 
    409     if (a != NULL && BN_abs_is_word(a, w))
    410         return 1;
    411     if ((aa = BN_dup(a)) != NULL)
    412         BN_set_negative(aa, 0);
    413     if ((bw = BN_new()) != NULL)
    414         BN_set_word(bw, w);
    415     test_fail_bignum_message(NULL, file, line, "BIGNUM", bns, ws, "abs==",
    416                              aa, bw);
    417     BN_free(bw);
    418     BN_free(aa);
    419     return 0;
    420 }
    421 
    422 static const char *print_time(const ASN1_TIME *t)
    423 {
    424     return t == NULL ? "<null>" : (const char *)ASN1_STRING_get0_data(t);
    425 }
    426 
    427 #define DEFINE_TIME_T_COMPARISON(opname, op)                            \
    428     int test_time_t_ ## opname(const char *file, int line,              \
    429                                const char *s1, const char *s2,          \
    430                                const time_t t1, const time_t t2)        \
    431     {                                                                   \
    432         ASN1_TIME *at1 = ASN1_TIME_set(NULL, t1);                       \
    433         ASN1_TIME *at2 = ASN1_TIME_set(NULL, t2);                       \
    434         int r = at1 != NULL && at2 != NULL                              \
    435                 && ASN1_TIME_compare(at1, at2) op 0;                    \
    436         if (!r)                                                         \
    437             test_fail_message(NULL, file, line, "time_t", s1, s2, #op,  \
    438                               "[%s] compared to [%s]",                  \
    439                               print_time(at1), print_time(at2));        \
    440         ASN1_STRING_free(at1);                                          \
    441         ASN1_STRING_free(at2);                                          \
    442         return r;                                                       \
    443     }
    444 DEFINE_TIME_T_COMPARISON(eq, ==)
    445 DEFINE_TIME_T_COMPARISON(ne, !=)
    446 DEFINE_TIME_T_COMPARISON(gt, >)
    447 DEFINE_TIME_T_COMPARISON(ge, >=)
    448 DEFINE_TIME_T_COMPARISON(lt, <)
    449 DEFINE_TIME_T_COMPARISON(le, <=)
    450