1 1.1 christos /* 2 1.1 christos * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. 3 1.1 christos * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4 1.1 christos * 5 1.1 christos * Licensed under the Apache License 2.0 (the "License"). You may not use 6 1.1 christos * this file except in compliance with the License. You can obtain a copy 7 1.1 christos * in the file LICENSE in the source distribution or at 8 1.1 christos * https://www.openssl.org/source/license.html 9 1.1 christos */ 10 1.1 christos 11 1.1 christos #include <string.h> 12 1.1 christos #include <openssl/params.h> 13 1.1 christos #include "testutil.h" 14 1.1 christos 15 1.1 christos /* On machines that dont support <inttypes.h> just disable the tests */ 16 1.1 christos #if !defined(OPENSSL_NO_INTTYPES_H) 17 1.1 christos 18 1.1.1.2 christos #ifdef OPENSSL_SYS_VMS 19 1.1.1.2 christos #define strtoumax strtoull 20 1.1.1.2 christos #define strtoimax strtoll 21 1.1.1.2 christos #endif 22 1.1 christos 23 1.1 christos typedef struct { 24 1.1 christos OSSL_PARAM *param; 25 1.1 christos int32_t i32; 26 1.1 christos int64_t i64; 27 1.1 christos uint32_t u32; 28 1.1 christos uint64_t u64; 29 1.1 christos double d; 30 1.1 christos int valid_i32, valid_i64, valid_u32, valid_u64, valid_d; 31 1.1 christos void *ref, *datum; 32 1.1 christos size_t size; 33 1.1 christos } PARAM_CONVERSION; 34 1.1 christos 35 1.1 christos static int param_conversion_load_stanza(PARAM_CONVERSION *pc, const STANZA *s) 36 1.1 christos { 37 1.1 christos 38 1.1 christos static int32_t datum_i32, ref_i32; 39 1.1 christos static int64_t datum_i64, ref_i64; 40 1.1 christos static uint32_t datum_u32, ref_u32; 41 1.1 christos static uint64_t datum_u64, ref_u64; 42 1.1 christos static double datum_d, ref_d; 43 1.1 christos static OSSL_PARAM params[] = { 44 1.1.1.2 christos OSSL_PARAM_int32("int32", &datum_i32), 45 1.1.1.2 christos OSSL_PARAM_int64("int64", &datum_i64), 46 1.1 christos OSSL_PARAM_uint32("uint32", &datum_u32), 47 1.1 christos OSSL_PARAM_uint64("uint64", &datum_u64), 48 1.1 christos OSSL_PARAM_double("double", &datum_d), 49 1.1 christos OSSL_PARAM_END 50 1.1 christos }; 51 1.1 christos int def_i32 = 0, def_i64 = 0, def_u32 = 0, def_u64 = 0, def_d = 0; 52 1.1 christos const PAIR *pp = s->pairs; 53 1.1 christos const char *type = NULL; 54 1.1 christos char *p; 55 1.1 christos int i; 56 1.1 christos 57 1.1 christos memset(pc, 0, sizeof(*pc)); 58 1.1 christos 59 1.1 christos for (i = 0; i < s->numpairs; i++, pp++) { 60 1.1 christos p = ""; 61 1.1 christos if (OPENSSL_strcasecmp(pp->key, "type") == 0) { 62 1.1 christos if (type != NULL) { 63 1.1 christos TEST_info("Line %d: multiple type lines", s->curr); 64 1.1 christos return 0; 65 1.1 christos } 66 1.1 christos pc->param = OSSL_PARAM_locate(params, type = pp->value); 67 1.1 christos if (pc->param == NULL) { 68 1.1 christos TEST_info("Line %d: unknown type line", s->curr); 69 1.1 christos return 0; 70 1.1 christos } 71 1.1 christos } else if (OPENSSL_strcasecmp(pp->key, "int32") == 0) { 72 1.1 christos if (def_i32++) { 73 1.1 christos TEST_info("Line %d: multiple int32 lines", s->curr); 74 1.1 christos return 0; 75 1.1 christos } 76 1.1 christos if (OPENSSL_strcasecmp(pp->value, "invalid") != 0) { 77 1.1 christos pc->valid_i32 = 1; 78 1.1 christos pc->i32 = (int32_t)strtoimax(pp->value, &p, 10); 79 1.1 christos } 80 1.1 christos } else if (OPENSSL_strcasecmp(pp->key, "int64") == 0) { 81 1.1 christos if (def_i64++) { 82 1.1 christos TEST_info("Line %d: multiple int64 lines", s->curr); 83 1.1 christos return 0; 84 1.1 christos } 85 1.1 christos if (OPENSSL_strcasecmp(pp->value, "invalid") != 0) { 86 1.1 christos pc->valid_i64 = 1; 87 1.1 christos pc->i64 = (int64_t)strtoimax(pp->value, &p, 10); 88 1.1 christos } 89 1.1 christos } else if (OPENSSL_strcasecmp(pp->key, "uint32") == 0) { 90 1.1 christos if (def_u32++) { 91 1.1 christos TEST_info("Line %d: multiple uint32 lines", s->curr); 92 1.1 christos return 0; 93 1.1 christos } 94 1.1 christos if (OPENSSL_strcasecmp(pp->value, "invalid") != 0) { 95 1.1 christos pc->valid_u32 = 1; 96 1.1 christos pc->u32 = (uint32_t)strtoumax(pp->value, &p, 10); 97 1.1 christos } 98 1.1 christos } else if (OPENSSL_strcasecmp(pp->key, "uint64") == 0) { 99 1.1 christos if (def_u64++) { 100 1.1 christos TEST_info("Line %d: multiple uint64 lines", s->curr); 101 1.1 christos return 0; 102 1.1 christos } 103 1.1 christos if (OPENSSL_strcasecmp(pp->value, "invalid") != 0) { 104 1.1 christos pc->valid_u64 = 1; 105 1.1 christos pc->u64 = (uint64_t)strtoumax(pp->value, &p, 10); 106 1.1 christos } 107 1.1 christos } else if (OPENSSL_strcasecmp(pp->key, "double") == 0) { 108 1.1 christos if (def_d++) { 109 1.1 christos TEST_info("Line %d: multiple double lines", s->curr); 110 1.1 christos return 0; 111 1.1 christos } 112 1.1 christos if (OPENSSL_strcasecmp(pp->value, "invalid") != 0) { 113 1.1 christos pc->valid_d = 1; 114 1.1 christos pc->d = strtod(pp->value, &p); 115 1.1 christos } 116 1.1 christos } else { 117 1.1 christos TEST_info("Line %d: unknown keyword %s", s->curr, pp->key); 118 1.1 christos return 0; 119 1.1 christos } 120 1.1 christos if (*p != '\0') { 121 1.1 christos TEST_info("Line %d: extra characters at end '%s' for %s", 122 1.1.1.2 christos s->curr, p, pp->key); 123 1.1 christos return 0; 124 1.1 christos } 125 1.1 christos } 126 1.1 christos 127 1.1 christos if (!TEST_ptr(type)) { 128 1.1 christos TEST_info("Line %d: type not found", s->curr); 129 1.1 christos return 0; 130 1.1 christos } 131 1.1 christos 132 1.1 christos if (OPENSSL_strcasecmp(type, "int32") == 0) { 133 1.1 christos if (!TEST_true(def_i32) || !TEST_true(pc->valid_i32)) { 134 1.1 christos TEST_note("errant int32 on line %d", s->curr); 135 1.1 christos return 0; 136 1.1 christos } 137 1.1 christos datum_i32 = ref_i32 = pc->i32; 138 1.1 christos pc->datum = &datum_i32; 139 1.1 christos pc->ref = &ref_i32; 140 1.1 christos pc->size = sizeof(ref_i32); 141 1.1 christos } else if (OPENSSL_strcasecmp(type, "int64") == 0) { 142 1.1 christos if (!TEST_true(def_i64) || !TEST_true(pc->valid_i64)) { 143 1.1 christos TEST_note("errant int64 on line %d", s->curr); 144 1.1 christos return 0; 145 1.1 christos } 146 1.1 christos datum_i64 = ref_i64 = pc->i64; 147 1.1 christos pc->datum = &datum_i64; 148 1.1 christos pc->ref = &ref_i64; 149 1.1 christos pc->size = sizeof(ref_i64); 150 1.1 christos } else if (OPENSSL_strcasecmp(type, "uint32") == 0) { 151 1.1 christos if (!TEST_true(def_u32) || !TEST_true(pc->valid_u32)) { 152 1.1 christos TEST_note("errant uint32 on line %d", s->curr); 153 1.1 christos return 0; 154 1.1 christos } 155 1.1 christos datum_u32 = ref_u32 = pc->u32; 156 1.1 christos pc->datum = &datum_u32; 157 1.1 christos pc->ref = &ref_u32; 158 1.1 christos pc->size = sizeof(ref_u32); 159 1.1 christos } else if (OPENSSL_strcasecmp(type, "uint64") == 0) { 160 1.1 christos if (!TEST_true(def_u64) || !TEST_true(pc->valid_u64)) { 161 1.1 christos TEST_note("errant uint64 on line %d", s->curr); 162 1.1 christos return 0; 163 1.1 christos } 164 1.1 christos datum_u64 = ref_u64 = pc->u64; 165 1.1 christos pc->datum = &datum_u64; 166 1.1 christos pc->ref = &ref_u64; 167 1.1 christos pc->size = sizeof(ref_u64); 168 1.1 christos } else if (OPENSSL_strcasecmp(type, "double") == 0) { 169 1.1 christos if (!TEST_true(def_d) || !TEST_true(pc->valid_d)) { 170 1.1 christos TEST_note("errant double on line %d", s->curr); 171 1.1 christos return 0; 172 1.1 christos } 173 1.1 christos datum_d = ref_d = pc->d; 174 1.1 christos pc->datum = &datum_d; 175 1.1 christos pc->ref = &ref_d; 176 1.1 christos pc->size = sizeof(ref_d); 177 1.1 christos } else { 178 1.1 christos TEST_error("type unknown at line %d", s->curr); 179 1.1 christos return 0; 180 1.1 christos } 181 1.1 christos return 1; 182 1.1 christos } 183 1.1 christos 184 1.1 christos static int param_conversion_test(const PARAM_CONVERSION *pc, int line) 185 1.1 christos { 186 1.1 christos int32_t i32; 187 1.1 christos int64_t i64; 188 1.1 christos uint32_t u32; 189 1.1 christos uint64_t u64; 190 1.1 christos double d; 191 1.1 christos 192 1.1 christos if (!pc->valid_i32) { 193 1.1 christos if (!TEST_false(OSSL_PARAM_get_int32(pc->param, &i32)) 194 1.1.1.2 christos || !TEST_ulong_ne(ERR_get_error(), 0)) { 195 1.1 christos TEST_note("unexpected valid conversion to int32 on line %d", line); 196 1.1 christos return 0; 197 1.1 christos } 198 1.1 christos } else { 199 1.1 christos if (!TEST_true(OSSL_PARAM_get_int32(pc->param, &i32)) 200 1.1 christos || !TEST_true(i32 == pc->i32)) { 201 1.1 christos TEST_note("unexpected conversion to int32 on line %d", line); 202 1.1 christos return 0; 203 1.1 christos } 204 1.1 christos memset(pc->datum, 44, pc->size); 205 1.1 christos if (!TEST_true(OSSL_PARAM_set_int32(pc->param, i32)) 206 1.1 christos || !TEST_mem_eq(pc->datum, pc->size, pc->ref, pc->size)) { 207 1.1 christos TEST_note("unexpected valid conversion from int32 on line %d", 208 1.1.1.2 christos line); 209 1.1 christos return 0; 210 1.1 christos } 211 1.1 christos } 212 1.1 christos 213 1.1 christos if (!pc->valid_i64) { 214 1.1 christos if (!TEST_false(OSSL_PARAM_get_int64(pc->param, &i64)) 215 1.1.1.2 christos || !TEST_ulong_ne(ERR_get_error(), 0)) { 216 1.1 christos TEST_note("unexpected valid conversion to int64 on line %d", line); 217 1.1 christos return 0; 218 1.1 christos } 219 1.1 christos } else { 220 1.1 christos if (!TEST_true(OSSL_PARAM_get_int64(pc->param, &i64)) 221 1.1 christos || !TEST_true(i64 == pc->i64)) { 222 1.1 christos TEST_note("unexpected conversion to int64 on line %d", line); 223 1.1 christos return 0; 224 1.1 christos } 225 1.1 christos memset(pc->datum, 44, pc->size); 226 1.1 christos if (!TEST_true(OSSL_PARAM_set_int64(pc->param, i64)) 227 1.1 christos || !TEST_mem_eq(pc->datum, pc->size, pc->ref, pc->size)) { 228 1.1 christos TEST_note("unexpected valid conversion from int64 on line %d", 229 1.1.1.2 christos line); 230 1.1 christos return 0; 231 1.1 christos } 232 1.1 christos } 233 1.1 christos 234 1.1 christos if (!pc->valid_u32) { 235 1.1 christos if (!TEST_false(OSSL_PARAM_get_uint32(pc->param, &u32)) 236 1.1.1.2 christos || !TEST_ulong_ne(ERR_get_error(), 0)) { 237 1.1 christos TEST_note("unexpected valid conversion to uint32 on line %d", line); 238 1.1 christos return 0; 239 1.1 christos } 240 1.1 christos } else { 241 1.1 christos if (!TEST_true(OSSL_PARAM_get_uint32(pc->param, &u32)) 242 1.1 christos || !TEST_true(u32 == pc->u32)) { 243 1.1 christos TEST_note("unexpected conversion to uint32 on line %d", line); 244 1.1 christos return 0; 245 1.1 christos } 246 1.1 christos memset(pc->datum, 44, pc->size); 247 1.1 christos if (!TEST_true(OSSL_PARAM_set_uint32(pc->param, u32)) 248 1.1 christos || !TEST_mem_eq(pc->datum, pc->size, pc->ref, pc->size)) { 249 1.1 christos TEST_note("unexpected valid conversion from uint32 on line %d", 250 1.1.1.2 christos line); 251 1.1 christos return 0; 252 1.1 christos } 253 1.1 christos } 254 1.1 christos 255 1.1 christos if (!pc->valid_u64) { 256 1.1 christos if (!TEST_false(OSSL_PARAM_get_uint64(pc->param, &u64)) 257 1.1.1.2 christos || !TEST_ulong_ne(ERR_get_error(), 0)) { 258 1.1 christos TEST_note("unexpected valid conversion to uint64 on line %d", line); 259 1.1 christos return 0; 260 1.1 christos } 261 1.1 christos } else { 262 1.1 christos if (!TEST_true(OSSL_PARAM_get_uint64(pc->param, &u64)) 263 1.1 christos || !TEST_true(u64 == pc->u64)) { 264 1.1 christos TEST_note("unexpected conversion to uint64 on line %d", line); 265 1.1 christos return 0; 266 1.1 christos } 267 1.1 christos memset(pc->datum, 44, pc->size); 268 1.1 christos if (!TEST_true(OSSL_PARAM_set_uint64(pc->param, u64)) 269 1.1 christos || !TEST_mem_eq(pc->datum, pc->size, pc->ref, pc->size)) { 270 1.1 christos TEST_note("unexpected valid conversion from uint64 on line %d", 271 1.1.1.2 christos line); 272 1.1 christos return 0; 273 1.1 christos } 274 1.1 christos } 275 1.1 christos 276 1.1 christos if (!pc->valid_d) { 277 1.1 christos if (!TEST_false(OSSL_PARAM_get_double(pc->param, &d)) 278 1.1.1.2 christos || !TEST_ulong_ne(ERR_get_error(), 0)) { 279 1.1 christos TEST_note("unexpected valid conversion to double on line %d", line); 280 1.1 christos return 0; 281 1.1 christos } 282 1.1 christos } else { 283 1.1 christos if (!TEST_true(OSSL_PARAM_get_double(pc->param, &d))) { 284 1.1 christos TEST_note("unable to convert to double on line %d", line); 285 1.1 christos return 0; 286 1.1 christos } 287 1.1 christos /* 288 1.1 christos * Check for not a number (NaN) without using the libm functions. 289 1.1 christos * When d is a NaN, the standard requires d == d to be false. 290 1.1 christos * It's less clear if d != d should be true even though it generally is. 291 1.1 christos * Hence we use the equality test and a not. 292 1.1 christos */ 293 1.1 christos if (!(d == d)) { 294 1.1 christos /* 295 1.1 christos * We've encountered a NaN so check it's really meant to be a NaN. 296 1.1 christos * We ignore the case where the two values are both different NaN, 297 1.1 christos * that's not resolvable without knowing the underlying format 298 1.1 christos * or using libm functions. 299 1.1 christos */ 300 1.1 christos if (!TEST_false(pc->d == pc->d)) { 301 1.1 christos TEST_note("unexpected NaN on line %d", line); 302 1.1 christos return 0; 303 1.1 christos } 304 1.1 christos } else if (!TEST_true(d == pc->d)) { 305 1.1 christos TEST_note("unexpected conversion to double on line %d", line); 306 1.1 christos return 0; 307 1.1 christos } 308 1.1 christos memset(pc->datum, 44, pc->size); 309 1.1 christos if (!TEST_true(OSSL_PARAM_set_double(pc->param, d)) 310 1.1 christos || !TEST_mem_eq(pc->datum, pc->size, pc->ref, pc->size)) { 311 1.1 christos TEST_note("unexpected valid conversion from double on line %d", 312 1.1.1.2 christos line); 313 1.1 christos return 0; 314 1.1 christos } 315 1.1 christos } 316 1.1 christos 317 1.1 christos return 1; 318 1.1 christos } 319 1.1 christos 320 1.1 christos static int run_param_file_tests(int i) 321 1.1 christos { 322 1.1 christos STANZA *s; 323 1.1 christos PARAM_CONVERSION pc; 324 1.1 christos const char *testfile = test_get_argument(i); 325 1.1 christos int res = 1; 326 1.1 christos 327 1.1 christos if (!TEST_ptr(s = OPENSSL_zalloc(sizeof(*s)))) 328 1.1 christos return 0; 329 1.1 christos if (!test_start_file(s, testfile)) { 330 1.1 christos OPENSSL_free(s); 331 1.1 christos return 0; 332 1.1 christos } 333 1.1 christos 334 1.1 christos while (!BIO_eof(s->fp)) { 335 1.1 christos if (!test_readstanza(s)) { 336 1.1 christos res = 0; 337 1.1 christos goto end; 338 1.1 christos } 339 1.1 christos if (s->numpairs != 0) 340 1.1 christos if (!param_conversion_load_stanza(&pc, s) 341 1.1 christos || !param_conversion_test(&pc, s->curr)) 342 1.1 christos res = 0; 343 1.1 christos test_clearstanza(s); 344 1.1 christos } 345 1.1 christos end: 346 1.1 christos test_end_file(s); 347 1.1 christos OPENSSL_free(s); 348 1.1 christos return res; 349 1.1 christos } 350 1.1 christos 351 1.1 christos #endif /* OPENSSL_NO_INTTYPES_H */ 352 1.1 christos 353 1.1 christos OPT_TEST_DECLARE_USAGE("file...\n") 354 1.1 christos 355 1.1 christos int setup_tests(void) 356 1.1 christos { 357 1.1 christos size_t n; 358 1.1 christos 359 1.1 christos if (!test_skip_common_options()) { 360 1.1 christos TEST_error("Error parsing test options\n"); 361 1.1 christos return 0; 362 1.1 christos } 363 1.1 christos 364 1.1 christos n = test_get_argument_count(); 365 1.1 christos if (n == 0) 366 1.1 christos return 0; 367 1.1 christos 368 1.1 christos #if !defined(OPENSSL_NO_INTTYPES_H) 369 1.1 christos ADD_ALL_TESTS(run_param_file_tests, n); 370 1.1 christos #endif /* OPENSSL_NO_INTTYPES_H */ 371 1.1 christos 372 1.1 christos return 1; 373 1.1 christos } 374