lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 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 | static void test_fail_message_va(const char *prefix, const char *file, |
| 76 | int line, const char *type, |
| 77 | const char *left, const char *right, |
| 78 | const char *op, const char *fmt, va_list ap) |
| 79 | { |
| 80 | test_fail_message_prefix(prefix, file, line, type, left, right, op); |
| 81 | if (fmt != NULL) { |
| 82 | test_vprintf_stderr(fmt, ap); |
| 83 | test_printf_stderr("\n"); |
| 84 | } |
| 85 | test_flush_stderr(); |
| 86 | } |
| 87 | |
| 88 | static void test_fail_message(const char *prefix, const char *file, |
| 89 | int line, const char *type, |
| 90 | const char *left, const char *right, |
| 91 | const char *op, const char *fmt, ...) |
| 92 | { |
| 93 | va_list ap; |
| 94 | |
| 95 | va_start(ap, fmt); |
| 96 | test_fail_message_va(prefix, file, line, type, left, right, op, fmt, ap); |
| 97 | va_end(ap); |
| 98 | } |
| 99 | |
| 100 | void test_info_c90(const char *desc, ...) |
| 101 | { |
| 102 | va_list ap; |
| 103 | |
| 104 | va_start(ap, desc); |
| 105 | test_fail_message_va("INFO", NULL, -1, NULL, NULL, NULL, NULL, desc, ap); |
| 106 | va_end(ap); |
| 107 | } |
| 108 | |
| 109 | void test_info(const char *file, int line, const char *desc, ...) |
| 110 | { |
| 111 | va_list ap; |
| 112 | |
| 113 | va_start(ap, desc); |
| 114 | test_fail_message_va("INFO", file, line, NULL, NULL, NULL, NULL, desc, ap); |
| 115 | va_end(ap); |
| 116 | } |
| 117 | |
| 118 | void test_error_c90(const char *desc, ...) |
| 119 | { |
| 120 | va_list ap; |
| 121 | |
| 122 | va_start(ap, desc); |
| 123 | test_fail_message_va(NULL, NULL, -1, NULL, NULL, NULL, NULL, desc, ap); |
| 124 | va_end(ap); |
| 125 | test_printf_stderr("\n"); |
| 126 | } |
| 127 | |
| 128 | void test_error(const char *file, int line, const char *desc, ...) |
| 129 | { |
| 130 | va_list ap; |
| 131 | |
| 132 | va_start(ap, desc); |
| 133 | test_fail_message_va(NULL, file, line, NULL, NULL, NULL, NULL, desc, ap); |
| 134 | va_end(ap); |
| 135 | test_printf_stderr("\n"); |
| 136 | } |
| 137 | |
| 138 | void test_perror(const char *s) |
| 139 | { |
| 140 | /* |
| 141 | * Using openssl_strerror_r causes linking issues since it isn't |
| 142 | * exported from libcrypto.so |
| 143 | */ |
| 144 | TEST_error("%s: %s", s, strerror(errno)); |
| 145 | } |
| 146 | |
| 147 | void test_note(const char *fmt, ...) |
| 148 | { |
| 149 | if (fmt != NULL) { |
| 150 | va_list ap; |
| 151 | |
| 152 | va_start(ap, fmt); |
| 153 | test_vprintf_stderr(fmt, ap); |
| 154 | va_end(ap); |
| 155 | test_printf_stderr("\n"); |
| 156 | } |
| 157 | test_flush_stderr(); |
| 158 | } |
| 159 | |
| 160 | void test_openssl_errors(void) |
| 161 | { |
| 162 | ERR_print_errors_cb(openssl_error_cb, NULL); |
| 163 | ERR_clear_error(); |
| 164 | } |
| 165 | |
| 166 | /* |
| 167 | * Define some comparisons between pairs of various types. |
| 168 | * These functions return 1 if the test is true. |
| 169 | * Otherwise, they return 0 and pretty-print diagnostics. |
| 170 | * |
| 171 | * In each case the functions produced are: |
| 172 | * int test_name_eq(const type t1, const type t2, const char *desc, ...); |
| 173 | * int test_name_ne(const type t1, const type t2, const char *desc, ...); |
| 174 | * int test_name_lt(const type t1, const type t2, const char *desc, ...); |
| 175 | * int test_name_le(const type t1, const type t2, const char *desc, ...); |
| 176 | * int test_name_gt(const type t1, const type t2, const char *desc, ...); |
| 177 | * int test_name_ge(const type t1, const type t2, const char *desc, ...); |
| 178 | * |
| 179 | * The t1 and t2 arguments are to be compared for equality, inequality, |
| 180 | * less than, less than or equal to, greater than and greater than or |
| 181 | * equal to respectively. If the specified condition holds, the functions |
| 182 | * return 1. If the condition does not hold, the functions print a diagnostic |
| 183 | * message and return 0. |
| 184 | * |
| 185 | * The desc argument is a printf format string followed by its arguments and |
| 186 | * this is included in the output if the condition being tested for is false. |
| 187 | */ |
| 188 | #define DEFINE_COMPARISON(type, name, opname, op, fmt) \ |
| 189 | int test_ ## name ## _ ## opname(const char *file, int line, \ |
| 190 | const char *s1, const char *s2, \ |
| 191 | const type t1, const type t2) \ |
| 192 | { \ |
| 193 | if (t1 op t2) \ |
| 194 | return 1; \ |
| 195 | test_fail_message(NULL, file, line, #type, s1, s2, #op, \ |
| 196 | "[" fmt "] compared to [" fmt "]", \ |
| 197 | t1, t2); \ |
| 198 | return 0; \ |
| 199 | } |
| 200 | |
| 201 | #define DEFINE_COMPARISONS(type, name, fmt) \ |
| 202 | DEFINE_COMPARISON(type, name, eq, ==, fmt) \ |
| 203 | DEFINE_COMPARISON(type, name, ne, !=, fmt) \ |
| 204 | DEFINE_COMPARISON(type, name, lt, <, fmt) \ |
| 205 | DEFINE_COMPARISON(type, name, le, <=, fmt) \ |
| 206 | DEFINE_COMPARISON(type, name, gt, >, fmt) \ |
| 207 | DEFINE_COMPARISON(type, name, ge, >=, fmt) |
| 208 | |
| 209 | DEFINE_COMPARISONS(int, int, "%d") |
| 210 | DEFINE_COMPARISONS(unsigned int, uint, "%u") |
| 211 | DEFINE_COMPARISONS(char, char, "%c") |
| 212 | DEFINE_COMPARISONS(unsigned char, uchar, "%u") |
| 213 | DEFINE_COMPARISONS(long, long, "%ld") |
| 214 | DEFINE_COMPARISONS(unsigned long, ulong, "%lu") |
| 215 | DEFINE_COMPARISONS(size_t, size_t, "%zu") |
| 216 | |
| 217 | DEFINE_COMPARISON(void *, ptr, eq, ==, "%p") |
| 218 | DEFINE_COMPARISON(void *, ptr, ne, !=, "%p") |
| 219 | |
| 220 | int test_ptr_null(const char *file, int line, const char *s, const void *p) |
| 221 | { |
| 222 | if (p == NULL) |
| 223 | return 1; |
| 224 | test_fail_message(NULL, file, line, "ptr", s, "NULL", "==", "%p", p); |
| 225 | return 0; |
| 226 | } |
| 227 | |
| 228 | int test_ptr(const char *file, int line, const char *s, const void *p) |
| 229 | { |
| 230 | if (p != NULL) |
| 231 | return 1; |
| 232 | test_fail_message(NULL, file, line, "ptr", s, "NULL", "!=", "%p", p); |
| 233 | return 0; |
| 234 | } |
| 235 | |
| 236 | int test_true(const char *file, int line, const char *s, int b) |
| 237 | { |
| 238 | if (b) |
| 239 | return 1; |
| 240 | test_fail_message(NULL, file, line, "bool", s, "true", "==", "false"); |
| 241 | return 0; |
| 242 | } |
| 243 | |
| 244 | int test_false(const char *file, int line, const char *s, int b) |
| 245 | { |
| 246 | if (!b) |
| 247 | return 1; |
| 248 | test_fail_message(NULL, file, line, "bool", s, "false", "==", "true"); |
| 249 | return 0; |
| 250 | } |
| 251 | |
| 252 | int test_str_eq(const char *file, int line, const char *st1, const char *st2, |
| 253 | const char *s1, const char *s2) |
| 254 | { |
| 255 | if (s1 == NULL && s2 == NULL) |
| 256 | return 1; |
| 257 | if (s1 == NULL || s2 == NULL || strcmp(s1, s2) != 0) { |
| 258 | test_fail_string_message(NULL, file, line, "string", st1, st2, "==", |
| 259 | s1, s1 == NULL ? 0 : strlen(s1), |
| 260 | s2, s2 == NULL ? 0 : strlen(s2)); |
| 261 | return 0; |
| 262 | } |
| 263 | return 1; |
| 264 | } |
| 265 | |
| 266 | int test_str_ne(const char *file, int line, const char *st1, const char *st2, |
| 267 | const char *s1, const char *s2) |
| 268 | { |
| 269 | if ((s1 == NULL) ^ (s2 == NULL)) |
| 270 | return 1; |
| 271 | if (s1 == NULL || strcmp(s1, s2) == 0) { |
| 272 | test_fail_string_message(NULL, file, line, "string", st1, st2, "!=", |
| 273 | s1, s1 == NULL ? 0 : strlen(s1), |
| 274 | s2, s2 == NULL ? 0 : strlen(s2)); |
| 275 | return 0; |
| 276 | } |
| 277 | return 1; |
| 278 | } |
| 279 | |
| 280 | int test_strn_eq(const char *file, int line, const char *st1, const char *st2, |
| 281 | const char *s1, const char *s2, size_t len) |
| 282 | { |
| 283 | if (s1 == NULL && s2 == NULL) |
| 284 | return 1; |
| 285 | if (s1 == NULL || s2 == NULL || strncmp(s1, s2, len) != 0) { |
| 286 | test_fail_string_message(NULL, file, line, "string", st1, st2, "==", |
| 287 | s1, s1 == NULL ? 0 : OPENSSL_strnlen(s1, len), |
| 288 | s2, s2 == NULL ? 0 : OPENSSL_strnlen(s2, len)); |
| 289 | return 0; |
| 290 | } |
| 291 | return 1; |
| 292 | } |
| 293 | |
| 294 | int test_strn_ne(const char *file, int line, const char *st1, const char *st2, |
| 295 | const char *s1, const char *s2, size_t len) |
| 296 | { |
| 297 | if ((s1 == NULL) ^ (s2 == NULL)) |
| 298 | return 1; |
| 299 | if (s1 == NULL || strncmp(s1, s2, len) == 0) { |
| 300 | test_fail_string_message(NULL, file, line, "string", st1, st2, "!=", |
| 301 | s1, s1 == NULL ? 0 : OPENSSL_strnlen(s1, len), |
| 302 | s2, s2 == NULL ? 0 : OPENSSL_strnlen(s2, len)); |
| 303 | return 0; |
| 304 | } |
| 305 | return 1; |
| 306 | } |
| 307 | |
| 308 | int test_mem_eq(const char *file, int line, const char *st1, const char *st2, |
| 309 | const void *s1, size_t n1, const void *s2, size_t n2) |
| 310 | { |
| 311 | if (s1 == NULL && s2 == NULL) |
| 312 | return 1; |
| 313 | if (n1 != n2 || s1 == NULL || s2 == NULL || memcmp(s1, s2, n1) != 0) { |
| 314 | test_fail_memory_message(NULL, file, line, "memory", st1, st2, "==", |
| 315 | s1, n1, s2, n2); |
| 316 | return 0; |
| 317 | } |
| 318 | return 1; |
| 319 | } |
| 320 | |
| 321 | int test_mem_ne(const char *file, int line, const char *st1, const char *st2, |
| 322 | const void *s1, size_t n1, const void *s2, size_t n2) |
| 323 | { |
| 324 | if ((s1 == NULL) ^ (s2 == NULL)) |
| 325 | return 1; |
| 326 | if (n1 != n2) |
| 327 | return 1; |
| 328 | if (s1 == NULL || memcmp(s1, s2, n1) == 0) { |
| 329 | test_fail_memory_message(NULL, file, line, "memory", st1, st2, "!=", |
| 330 | s1, n1, s2, n2); |
| 331 | return 0; |
| 332 | } |
| 333 | return 1; |
| 334 | } |
| 335 | |
| 336 | #define DEFINE_BN_COMPARISONS(opname, op, zero_cond) \ |
| 337 | int test_BN_ ## opname(const char *file, int line, \ |
| 338 | const char *s1, const char *s2, \ |
| 339 | const BIGNUM *t1, const BIGNUM *t2) \ |
| 340 | { \ |
| 341 | if (BN_cmp(t1, t2) op 0) \ |
| 342 | return 1; \ |
| 343 | test_fail_bignum_message(NULL, file, line, "BIGNUM", s1, s2, \ |
| 344 | #op, t1, t2); \ |
| 345 | return 0; \ |
| 346 | } \ |
| 347 | int test_BN_ ## opname ## _zero(const char *file, int line, \ |
| 348 | const char *s, const BIGNUM *a) \ |
| 349 | { \ |
| 350 | if (a != NULL &&(zero_cond)) \ |
| 351 | return 1; \ |
| 352 | test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", \ |
| 353 | s, "0", #op, a); \ |
| 354 | return 0; \ |
| 355 | } |
| 356 | |
| 357 | DEFINE_BN_COMPARISONS(eq, ==, BN_is_zero(a)) |
| 358 | DEFINE_BN_COMPARISONS(ne, !=, !BN_is_zero(a)) |
| 359 | DEFINE_BN_COMPARISONS(gt, >, !BN_is_negative(a) && !BN_is_zero(a)) |
| 360 | DEFINE_BN_COMPARISONS(ge, >=, !BN_is_negative(a) || BN_is_zero(a)) |
| 361 | DEFINE_BN_COMPARISONS(lt, <, BN_is_negative(a) && !BN_is_zero(a)) |
| 362 | DEFINE_BN_COMPARISONS(le, <=, BN_is_negative(a) || BN_is_zero(a)) |
| 363 | |
| 364 | int test_BN_eq_one(const char *file, int line, const char *s, const BIGNUM *a) |
| 365 | { |
| 366 | if (a != NULL && BN_is_one(a)) |
| 367 | return 1; |
| 368 | test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", s, "1", "==", a); |
| 369 | return 0; |
| 370 | } |
| 371 | |
| 372 | int test_BN_odd(const char *file, int line, const char *s, const BIGNUM *a) |
| 373 | { |
| 374 | if (a != NULL && BN_is_odd(a)) |
| 375 | return 1; |
| 376 | test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", "ODD(", ")", s, a); |
| 377 | return 0; |
| 378 | } |
| 379 | |
| 380 | int test_BN_even(const char *file, int line, const char *s, const BIGNUM *a) |
| 381 | { |
| 382 | if (a != NULL && !BN_is_odd(a)) |
| 383 | return 1; |
| 384 | test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", "EVEN(", ")", s, |
| 385 | a); |
| 386 | return 0; |
| 387 | } |
| 388 | |
| 389 | int test_BN_eq_word(const char *file, int line, const char *bns, const char *ws, |
| 390 | const BIGNUM *a, BN_ULONG w) |
| 391 | { |
| 392 | BIGNUM *bw; |
| 393 | |
| 394 | if (a != NULL && BN_is_word(a, w)) |
| 395 | return 1; |
| 396 | if ((bw = BN_new()) != NULL) |
| 397 | BN_set_word(bw, w); |
| 398 | test_fail_bignum_message(NULL, file, line, "BIGNUM", bns, ws, "==", a, bw); |
| 399 | BN_free(bw); |
| 400 | return 0; |
| 401 | } |
| 402 | |
| 403 | int test_BN_abs_eq_word(const char *file, int line, const char *bns, |
| 404 | const char *ws, const BIGNUM *a, BN_ULONG w) |
| 405 | { |
| 406 | BIGNUM *bw, *aa; |
| 407 | |
| 408 | if (a != NULL && BN_abs_is_word(a, w)) |
| 409 | return 1; |
| 410 | if ((aa = BN_dup(a)) != NULL) |
| 411 | BN_set_negative(aa, 0); |
| 412 | if ((bw = BN_new()) != NULL) |
| 413 | BN_set_word(bw, w); |
| 414 | test_fail_bignum_message(NULL, file, line, "BIGNUM", bns, ws, "abs==", |
| 415 | aa, bw); |
| 416 | BN_free(bw); |
| 417 | BN_free(aa); |
| 418 | return 0; |
| 419 | } |
| 420 | |
| 421 | static const char *print_time(const ASN1_TIME *t) |
| 422 | { |
| 423 | return t == NULL ? "<null>" : (char *)ASN1_STRING_get0_data(t); |
| 424 | } |
| 425 | |
| 426 | #define DEFINE_TIME_T_COMPARISON(opname, op) \ |
| 427 | int test_time_t_ ## opname(const char *file, int line, \ |
| 428 | const char *s1, const char *s2, \ |
| 429 | const time_t t1, const time_t t2) \ |
| 430 | { \ |
| 431 | ASN1_TIME *at1 = ASN1_TIME_set(NULL, t1); \ |
| 432 | ASN1_TIME *at2 = ASN1_TIME_set(NULL, t2); \ |
| 433 | int r = at1 != NULL && at2 != NULL \ |
| 434 | && ASN1_TIME_compare(at1, at2) op 0; \ |
| 435 | if (!r) \ |
| 436 | test_fail_message(NULL, file, line, "time_t", s1, s2, #op, \ |
| 437 | "[%s] compared to [%s]", \ |
| 438 | print_time(at1), print_time(at2)); \ |
| 439 | ASN1_STRING_free(at1); \ |
| 440 | ASN1_STRING_free(at2); \ |
| 441 | return r; \ |
| 442 | } |
| 443 | DEFINE_TIME_T_COMPARISON(eq, ==) |
| 444 | DEFINE_TIME_T_COMPARISON(ne, !=) |
| 445 | DEFINE_TIME_T_COMPARISON(gt, >) |
| 446 | DEFINE_TIME_T_COMPARISON(ge, >=) |
| 447 | DEFINE_TIME_T_COMPARISON(lt, <) |
| 448 | DEFINE_TIME_T_COMPARISON(le, <=) |