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