1 /* $OpenBSD: bn_unit.c,v 1.7 2023/06/21 07:15:38 jsing Exp $ */ 2 3 /* 4 * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <err.h> 20 #include <limits.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include <openssl/bn.h> 26 27 static int 28 test_bn_print_wrapper(char *a, size_t size, const char *descr, 29 int (*to_bn)(BIGNUM **, const char *)) 30 { 31 int ret; 32 33 ret = to_bn(NULL, a); 34 if (ret != 0 && (ret < 0 || (size_t)ret != size - 1)) { 35 fprintf(stderr, "unexpected %s() return" 36 "want 0 or %zu, got %d\n", descr, size - 1, ret); 37 return 1; 38 } 39 40 return 0; 41 } 42 43 static int 44 test_bn_print_null_derefs(void) 45 { 46 size_t size = INT_MAX / 4 + 4; 47 size_t datalimit = (size + 500 * 1024) / 1024; 48 char *a; 49 char digit; 50 int failed = 0; 51 52 if ((a = malloc(size)) == NULL) { 53 warn("malloc(%zu) failed (make sure data limit is >= %zu KiB)", 54 size, datalimit); 55 return 0; 56 } 57 58 /* Fill with a random digit since coverity doesn't like us using '0'. */ 59 digit = '0' + arc4random_uniform(10); 60 61 memset(a, digit, size - 1); 62 a[size - 1] = '\0'; 63 64 failed |= test_bn_print_wrapper(a, size, "BN_dec2bn", BN_dec2bn); 65 failed |= test_bn_print_wrapper(a, size, "BN_hex2bn", BN_hex2bn); 66 67 free(a); 68 69 return failed; 70 } 71 72 static int 73 test_bn_num_bits(void) 74 { 75 BIGNUM *bn; 76 int i, num_bits; 77 int failed = 0; 78 79 if ((bn = BN_new()) == NULL) 80 errx(1, "BN_new"); 81 82 if ((num_bits = BN_num_bits(bn)) != 0) { 83 warnx("BN_num_bits(0): got %d, want 0", num_bits); 84 failed |= 1; 85 } 86 87 if (!BN_set_word(bn, 1)) 88 errx(1, "BN_set_word"); 89 90 for (i = 0; i <= 5 * BN_BITS2; i++) { 91 if ((num_bits = BN_num_bits(bn)) != i + 1) { 92 warnx("BN_num_bits(1 << %d): got %d, want %d", 93 i, num_bits, i + 1); 94 failed |= 1; 95 } 96 if (!BN_lshift1(bn, bn)) 97 errx(1, "BN_lshift1"); 98 } 99 100 if (BN_hex2bn(&bn, "0000000000000000010000000000000000") != 34) 101 errx(1, "BN_hex2bn"); 102 103 if ((num_bits = BN_num_bits(bn)) != 65) { 104 warnx("BN_num_bits(1 << 64) padded: got %d, want %d", 105 num_bits, 65); 106 failed |= 1; 107 } 108 109 BN_free(bn); 110 111 return failed; 112 } 113 114 static int 115 test_bn_num_bits_word(void) 116 { 117 BN_ULONG w = 1; 118 int i, num_bits; 119 int failed = 0; 120 121 if ((num_bits = BN_num_bits_word(0)) != 0) { 122 warnx("BN_num_bits_word(0): want 0, got %d", num_bits); 123 failed |= 1; 124 } 125 126 for (i = 0; i < BN_BITS2; i++) { 127 if ((num_bits = BN_num_bits_word(w << i)) != i + 1) { 128 warnx("BN_num_bits_word(0x%llx): want %d, got %d", 129 (unsigned long long)(w << i), i + 1, num_bits); 130 failed |= 1; 131 } 132 } 133 134 return failed; 135 } 136 137 #define BN_FLG_ALL_KNOWN \ 138 (BN_FLG_STATIC_DATA | BN_FLG_CONSTTIME | BN_FLG_MALLOCED) 139 140 static int 141 bn_check_expected_flags(const BIGNUM *bn, int expected, const char *fn, 142 const char *descr) 143 { 144 int flags, got; 145 int ret = 1; 146 147 flags = BN_get_flags(bn, BN_FLG_ALL_KNOWN); 148 149 if ((got = flags & expected) != expected) { 150 fprintf(stderr, "%s: %s: expected flags: want %x, got %x\n", 151 fn, descr, expected, got); 152 ret = 0; 153 } 154 155 if ((got = flags & ~expected) != 0) { 156 fprintf(stderr, "%s: %s: unexpected flags: want %x, got %x\n", 157 fn, descr, 0, got); 158 ret = 0; 159 } 160 161 return ret; 162 } 163 164 static int 165 test_bn_copy_copies_flags(void) 166 { 167 BIGNUM *dst, *src; 168 int failed = 0; 169 170 if ((dst = BN_new()) == NULL) 171 errx(1, "%s: src = BN_new()", __func__); 172 173 if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED, 174 __func__, "dst after BN_new")) 175 failed |= 1; 176 177 if (BN_copy(dst, BN_value_one()) == NULL) 178 errx(1, "%s: bn_copy()", __func__); 179 180 if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED, 181 __func__, "dst after bn_copy")) 182 failed |= 1; 183 184 if ((src = BN_new()) == NULL) 185 errx(1, "%s: src = BN_new()", __func__); 186 187 BN_set_flags(src, BN_FLG_CONSTTIME); 188 189 if (!bn_check_expected_flags(src, BN_FLG_MALLOCED | BN_FLG_CONSTTIME, 190 __func__, "src after BN_set_flags")) 191 failed |= 1; 192 193 if (!BN_set_word(src, 57)) 194 errx(1, "%s: BN_set_word(src, 57)", __func__); 195 196 if (BN_copy(dst, src) == NULL) 197 errx(1, "%s: BN_copy(dst, src)", __func__); 198 199 if (BN_cmp(src, dst) != 0) { 200 fprintf(stderr, "copy not equal to original\n"); 201 failed |= 1; 202 } 203 204 if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED | BN_FLG_CONSTTIME, 205 __func__, "dst after BN_copy(dst, src)")) 206 failed |= 1; 207 208 BN_free(dst); 209 BN_free(src); 210 211 return failed; 212 } 213 214 static int 215 test_bn_copy_consttime_is_sticky(void) 216 { 217 BIGNUM *src, *dst; 218 int failed = 0; 219 220 if ((src = BN_new()) == NULL) 221 errx(1, "%s: src = BN_new()", __func__); 222 223 if (!bn_check_expected_flags(src, BN_FLG_MALLOCED, 224 __func__, "src after BN_new")) 225 failed |= 1; 226 227 if ((dst = BN_new()) == NULL) 228 errx(1, "%s: dst = BN_new()", __func__); 229 230 if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED, 231 __func__, "dst after BN_new")) 232 failed |= 1; 233 234 BN_set_flags(dst, BN_FLG_CONSTTIME); 235 236 if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED | BN_FLG_CONSTTIME, 237 __func__, "src after BN_new")) 238 failed |= 1; 239 240 if (BN_copy(dst, BN_value_one()) == NULL) 241 errx(1, "%s: bn_copy()", __func__); 242 243 if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED | BN_FLG_CONSTTIME, 244 __func__, "dst after bn_copy")) 245 failed |= 1; 246 247 BN_free(dst); 248 BN_free(src); 249 250 return failed; 251 } 252 253 static int 254 test_bn_dup_consttime_is_sticky(void) 255 { 256 BIGNUM *src, *dst; 257 int failed = 0; 258 259 if (!bn_check_expected_flags(BN_value_one(), BN_FLG_STATIC_DATA, 260 __func__, "flags on BN_value_one()")) 261 failed |= 1; 262 263 if ((dst = BN_dup(BN_value_one())) == NULL) 264 errx(1, "%s: dst = BN_dup(BN_value_one())", __func__); 265 266 if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED, 267 __func__, "dst after BN_dup(BN_value_one())")) 268 failed |= 1; 269 270 BN_free(dst); 271 272 if ((src = BN_new()) == NULL) 273 errx(1, "%s: src = BN_new()", __func__); 274 275 BN_set_flags(src, BN_FLG_CONSTTIME); 276 277 if (!bn_check_expected_flags(src, BN_FLG_MALLOCED | BN_FLG_CONSTTIME, 278 __func__, "src after BN_new")) 279 failed |= 1; 280 281 if ((dst = BN_dup(src)) == NULL) 282 errx(1, "%s: dst = BN_dup(src)", __func__); 283 284 if (!bn_check_expected_flags(dst, BN_FLG_MALLOCED | BN_FLG_CONSTTIME, 285 __func__, "dst after bn_copy")) 286 failed |= 1; 287 288 BN_free(dst); 289 BN_free(src); 290 291 return failed; 292 } 293 294 int 295 main(void) 296 { 297 int failed = 0; 298 299 failed |= test_bn_print_null_derefs(); 300 failed |= test_bn_num_bits(); 301 failed |= test_bn_num_bits_word(); 302 failed |= test_bn_copy_copies_flags(); 303 failed |= test_bn_copy_consttime_is_sticky(); 304 failed |= test_bn_dup_consttime_is_sticky(); 305 306 return failed; 307 } 308