blob: bb83a40765cb2632d818ade1d4bbcfc2110a0747 [file] [log] [blame]
David Benjamina5974bf2015-03-25 23:49:37 -04001/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2 * All rights reserved.
3 *
4 * This package is an SSL implementation written
5 * by Eric Young (eay@cryptsoft.com).
6 * The implementation was written so as to conform with Netscapes SSL.
7 *
8 * This library is free for commercial and non-commercial use as long as
9 * the following conditions are aheared to. The following conditions
10 * apply to all code found in this distribution, be it the RC4, RSA,
11 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
12 * included with this distribution is covered by the same copyright terms
13 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14 *
15 * Copyright remains Eric Young's, and as such any Copyright notices in
16 * the code are not to be removed.
17 * If this package is used in a product, Eric Young should be given attribution
18 * as the author of the parts of the library used.
19 * This can be in the form of a textual message at program startup or
20 * in documentation (online or textual) provided with the package.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 * must display the following acknowledgement:
32 * "This product includes cryptographic software written by
33 * Eric Young (eay@cryptsoft.com)"
34 * The word 'cryptographic' can be left out if the rouines from the library
35 * being used are not cryptographic related :-).
36 * 4. If you include any Windows specific code (or a derivative thereof) from
37 * the apps directory (application code) you must include an acknowledgement:
38 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * The licence and distribution terms for any publically available version or
53 * derivative of this code cannot be changed. i.e. this code cannot simply be
54 * copied and put under another distribution licence
55 * [including the GNU Public Licence.]
56 */
57/* ====================================================================
58 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
59 *
60 * Portions of the attached software ("Contribution") are developed by
61 * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
62 *
63 * The Contribution is licensed pursuant to the Eric Young open source
64 * license provided above.
65 *
66 * The binary polynomial arithmetic software is originally written by
67 * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
68 * Laboratories. */
69
David Benjaminc561aa62015-05-09 01:38:06 -040070/* For BIGNUM format macros. */
71#if !defined(__STDC_FORMAT_MACROS)
72#define __STDC_FORMAT_MACROS
73#endif
74
David Benjamin8b66fef2016-06-26 17:58:55 -040075#include <assert.h>
David Benjamin15eaafb2015-05-27 14:51:51 -040076#include <errno.h>
David Benjamin5e9bdc12016-06-26 16:56:29 -040077#include <limits.h>
David Benjamina5974bf2015-03-25 23:49:37 -040078#include <stdio.h>
79#include <string.h>
80
David Benjaminef14b2d2015-11-11 14:01:27 -080081#include <utility>
82
David Benjamina5974bf2015-03-25 23:49:37 -040083#include <openssl/bn.h>
84#include <openssl/crypto.h>
85#include <openssl/err.h>
86#include <openssl/mem.h>
87
Steven Valdezcb966542016-08-17 16:56:14 -040088#include "../internal.h"
89#include "../test/file_test.h"
90#include "../test/scoped_types.h"
91#include "../test/test_util.h"
David Benjamina5974bf2015-03-25 23:49:37 -040092
93
David Benjamine701f162015-12-03 11:04:24 -050094static int HexToBIGNUM(ScopedBIGNUM *out, const char *in) {
95 BIGNUM *raw = NULL;
96 int ret = BN_hex2bn(&raw, in);
97 out->reset(raw);
98 return ret;
99}
100
David Benjamin80137ba2016-06-26 15:03:41 -0400101static ScopedBIGNUM GetBIGNUM(FileTest *t, const char *attribute) {
102 std::string hex;
103 if (!t->GetAttribute(&hex, attribute)) {
104 return nullptr;
105 }
106
107 ScopedBIGNUM ret;
108 if (HexToBIGNUM(&ret, hex.c_str()) != static_cast<int>(hex.size())) {
109 t->PrintLine("Could not decode '%s'.", hex.c_str());
110 return nullptr;
111 }
112 return ret;
113}
114
David Benjamin5e9bdc12016-06-26 16:56:29 -0400115static bool GetInt(FileTest *t, int *out, const char *attribute) {
116 ScopedBIGNUM ret = GetBIGNUM(t, attribute);
117 if (!ret) {
118 return false;
119 }
120
121 BN_ULONG word = BN_get_word(ret.get());
122 if (word > INT_MAX) {
123 return false;
124 }
125
126 *out = static_cast<int>(word);
127 return true;
128}
129
David Benjamin80137ba2016-06-26 15:03:41 -0400130static bool ExpectBIGNUMsEqual(FileTest *t, const char *operation,
131 const BIGNUM *expected, const BIGNUM *actual) {
132 if (BN_cmp(expected, actual) == 0) {
133 return true;
134 }
135
Adam Langley10f97f32016-07-12 08:09:33 -0700136 ScopedOpenSSLString expected_str(BN_bn2hex(expected));
137 ScopedOpenSSLString actual_str(BN_bn2hex(actual));
David Benjamin80137ba2016-06-26 15:03:41 -0400138 if (!expected_str || !actual_str) {
David Benjamina5974bf2015-03-25 23:49:37 -0400139 return false;
140 }
141
David Benjamin80137ba2016-06-26 15:03:41 -0400142 t->PrintLine("Got %s =", operation);
143 t->PrintLine("\t%s", actual_str.get());
144 t->PrintLine("wanted:");
145 t->PrintLine("\t%s", expected_str.get());
146 return false;
147}
148
David Benjamin30581032016-06-26 15:18:28 -0400149static bool TestSum(FileTest *t, BN_CTX *ctx) {
David Benjamin80137ba2016-06-26 15:03:41 -0400150 ScopedBIGNUM a = GetBIGNUM(t, "A");
151 ScopedBIGNUM b = GetBIGNUM(t, "B");
152 ScopedBIGNUM sum = GetBIGNUM(t, "Sum");
153 if (!a || !b || !sum) {
154 return false;
David Benjamina5974bf2015-03-25 23:49:37 -0400155 }
David Benjamin80137ba2016-06-26 15:03:41 -0400156
157 ScopedBIGNUM ret(BN_new());
158 if (!ret ||
159 !BN_add(ret.get(), a.get(), b.get()) ||
160 !ExpectBIGNUMsEqual(t, "A + B", sum.get(), ret.get()) ||
161 !BN_sub(ret.get(), sum.get(), a.get()) ||
162 !ExpectBIGNUMsEqual(t, "Sum - A", b.get(), ret.get()) ||
163 !BN_sub(ret.get(), sum.get(), b.get()) ||
164 !ExpectBIGNUMsEqual(t, "Sum - B", a.get(), ret.get())) {
165 return false;
166 }
167
Brian Smithe4bf8b32016-07-01 13:36:06 -1000168 // Test that the functions work when |r| and |a| point to the same |BIGNUM|,
169 // or when |r| and |b| point to the same |BIGNUM|. TODO: Test the case where
170 // all of |r|, |a|, and |b| point to the same |BIGNUM|.
171 if (!BN_copy(ret.get(), a.get()) ||
172 !BN_add(ret.get(), ret.get(), b.get()) ||
173 !ExpectBIGNUMsEqual(t, "A + B (r is a)", sum.get(), ret.get()) ||
174 !BN_copy(ret.get(), b.get()) ||
175 !BN_add(ret.get(), a.get(), ret.get()) ||
176 !ExpectBIGNUMsEqual(t, "A + B (r is b)", sum.get(), ret.get()) ||
177 !BN_copy(ret.get(), sum.get()) ||
178 !BN_sub(ret.get(), ret.get(), a.get()) ||
179 !ExpectBIGNUMsEqual(t, "Sum - A (r is a)", b.get(), ret.get()) ||
180 !BN_copy(ret.get(), a.get()) ||
181 !BN_sub(ret.get(), sum.get(), ret.get()) ||
182 !ExpectBIGNUMsEqual(t, "Sum - A (r is b)", b.get(), ret.get()) ||
183 !BN_copy(ret.get(), sum.get()) ||
184 !BN_sub(ret.get(), ret.get(), b.get()) ||
185 !ExpectBIGNUMsEqual(t, "Sum - B (r is a)", a.get(), ret.get()) ||
186 !BN_copy(ret.get(), b.get()) ||
187 !BN_sub(ret.get(), sum.get(), ret.get()) ||
188 !ExpectBIGNUMsEqual(t, "Sum - B (r is b)", a.get(), ret.get())) {
189 return false;
190 }
191
Brian Smith3d4030b2016-07-01 14:12:40 -1000192 // Test |BN_uadd| and |BN_usub| with the prerequisites they are documented as
193 // having. Note that these functions are frequently used when the
194 // prerequisites don't hold. In those cases, they are supposed to work as if
195 // the prerequisite hold, but we don't test that yet. TODO: test that.
196 if (!BN_is_negative(a.get()) &&
197 !BN_is_negative(b.get()) && BN_cmp(a.get(), b.get()) >= 0) {
198 if (!BN_uadd(ret.get(), a.get(), b.get()) ||
199 !ExpectBIGNUMsEqual(t, "A +u B", sum.get(), ret.get()) ||
200 !BN_usub(ret.get(), sum.get(), a.get()) ||
201 !ExpectBIGNUMsEqual(t, "Sum -u A", b.get(), ret.get()) ||
202 !BN_usub(ret.get(), sum.get(), b.get()) ||
203 !ExpectBIGNUMsEqual(t, "Sum -u B", a.get(), ret.get())) {
204 return false;
205 }
206
207 // Test that the functions work when |r| and |a| point to the same |BIGNUM|,
208 // or when |r| and |b| point to the same |BIGNUM|. TODO: Test the case where
209 // all of |r|, |a|, and |b| point to the same |BIGNUM|.
210 if (!BN_copy(ret.get(), a.get()) ||
211 !BN_uadd(ret.get(), ret.get(), b.get()) ||
212 !ExpectBIGNUMsEqual(t, "A +u B (r is a)", sum.get(), ret.get()) ||
213 !BN_copy(ret.get(), b.get()) ||
214 !BN_uadd(ret.get(), a.get(), ret.get()) ||
215 !ExpectBIGNUMsEqual(t, "A +u B (r is b)", sum.get(), ret.get()) ||
216 !BN_copy(ret.get(), sum.get()) ||
217 !BN_usub(ret.get(), ret.get(), a.get()) ||
218 !ExpectBIGNUMsEqual(t, "Sum -u A (r is a)", b.get(), ret.get()) ||
219 !BN_copy(ret.get(), a.get()) ||
220 !BN_usub(ret.get(), sum.get(), ret.get()) ||
221 !ExpectBIGNUMsEqual(t, "Sum -u A (r is b)", b.get(), ret.get()) ||
222 !BN_copy(ret.get(), sum.get()) ||
223 !BN_usub(ret.get(), ret.get(), b.get()) ||
224 !ExpectBIGNUMsEqual(t, "Sum -u B (r is a)", a.get(), ret.get()) ||
225 !BN_copy(ret.get(), b.get()) ||
226 !BN_usub(ret.get(), sum.get(), ret.get()) ||
227 !ExpectBIGNUMsEqual(t, "Sum -u B (r is b)", a.get(), ret.get())) {
228 return false;
229 }
230 }
231
Brian Smithfe47ba22016-07-01 11:46:21 -1000232 // Test with |BN_add_word| and |BN_sub_word| if |b| is small enough.
233 BN_ULONG b_word = BN_get_word(b.get());
234 if (!BN_is_negative(b.get()) && b_word != (BN_ULONG)-1) {
235 if (!BN_copy(ret.get(), a.get()) ||
236 !BN_add_word(ret.get(), b_word) ||
237 !ExpectBIGNUMsEqual(t, "A + B (word)", sum.get(), ret.get()) ||
238 !BN_copy(ret.get(), sum.get()) ||
239 !BN_sub_word(ret.get(), b_word) ||
240 !ExpectBIGNUMsEqual(t, "Sum - B (word)", a.get(), ret.get())) {
241 return false;
242 }
243 }
244
David Benjamina5974bf2015-03-25 23:49:37 -0400245 return true;
246}
247
David Benjamin30581032016-06-26 15:18:28 -0400248static bool TestLShift1(FileTest *t, BN_CTX *ctx) {
249 ScopedBIGNUM a = GetBIGNUM(t, "A");
250 ScopedBIGNUM lshift1 = GetBIGNUM(t, "LShift1");
David Benjamine1caf392016-06-26 17:12:23 -0400251 ScopedBIGNUM zero(BN_new());
252 if (!a || !lshift1 || !zero) {
David Benjamin30581032016-06-26 15:18:28 -0400253 return false;
254 }
255
David Benjamine1caf392016-06-26 17:12:23 -0400256 BN_zero(zero.get());
257
258 ScopedBIGNUM ret(BN_new()), two(BN_new()), remainder(BN_new());
259 if (!ret || !two || !remainder ||
David Benjamin30581032016-06-26 15:18:28 -0400260 !BN_set_word(two.get(), 2) ||
261 !BN_add(ret.get(), a.get(), a.get()) ||
262 !ExpectBIGNUMsEqual(t, "A + A", lshift1.get(), ret.get()) ||
263 !BN_mul(ret.get(), a.get(), two.get(), ctx) ||
264 !ExpectBIGNUMsEqual(t, "A * 2", lshift1.get(), ret.get()) ||
David Benjamine1caf392016-06-26 17:12:23 -0400265 !BN_div(ret.get(), remainder.get(), lshift1.get(), two.get(), ctx) ||
David Benjamin30581032016-06-26 15:18:28 -0400266 !ExpectBIGNUMsEqual(t, "LShift1 / 2", a.get(), ret.get()) ||
David Benjamine1caf392016-06-26 17:12:23 -0400267 !ExpectBIGNUMsEqual(t, "LShift1 % 2", zero.get(), remainder.get()) ||
David Benjamin30581032016-06-26 15:18:28 -0400268 !BN_lshift1(ret.get(), a.get()) ||
269 !ExpectBIGNUMsEqual(t, "A << 1", lshift1.get(), ret.get()) ||
270 !BN_rshift1(ret.get(), lshift1.get()) ||
271 !ExpectBIGNUMsEqual(t, "LShift >> 1", a.get(), ret.get()) ||
272 !BN_rshift1(ret.get(), lshift1.get()) ||
273 !ExpectBIGNUMsEqual(t, "LShift >> 1", a.get(), ret.get())) {
274 return false;
275 }
276
277 // Set the LSB to 1 and test rshift1 again.
David Benjamin56cbbe5b2016-07-02 14:24:30 -0400278 if (!BN_set_bit(lshift1.get(), 0) ||
279 !BN_div(ret.get(), nullptr /* rem */, lshift1.get(), two.get(), ctx) ||
David Benjamin30581032016-06-26 15:18:28 -0400280 !ExpectBIGNUMsEqual(t, "(LShift1 | 1) / 2", a.get(), ret.get()) ||
281 !BN_rshift1(ret.get(), lshift1.get()) ||
282 !ExpectBIGNUMsEqual(t, "(LShift | 1) >> 1", a.get(), ret.get())) {
283 return false;
284 }
285
286 return true;
287}
288
David Benjamin5e9bdc12016-06-26 16:56:29 -0400289static bool TestLShift(FileTest *t, BN_CTX *ctx) {
290 ScopedBIGNUM a = GetBIGNUM(t, "A");
291 ScopedBIGNUM lshift = GetBIGNUM(t, "LShift");
Adam Langleyd42e4b22016-06-27 15:57:57 -0700292 int n = 0;
David Benjamin5e9bdc12016-06-26 16:56:29 -0400293 if (!a || !lshift || !GetInt(t, &n, "N")) {
294 return false;
295 }
296
297 ScopedBIGNUM ret(BN_new());
298 if (!ret ||
299 !BN_lshift(ret.get(), a.get(), n) ||
300 !ExpectBIGNUMsEqual(t, "A << N", lshift.get(), ret.get()) ||
301 !BN_rshift(ret.get(), lshift.get(), n) ||
302 !ExpectBIGNUMsEqual(t, "A >> N", a.get(), ret.get())) {
303 return false;
304 }
305
306 return true;
307}
308
309static bool TestRShift(FileTest *t, BN_CTX *ctx) {
310 ScopedBIGNUM a = GetBIGNUM(t, "A");
311 ScopedBIGNUM rshift = GetBIGNUM(t, "RShift");
Adam Langleyd42e4b22016-06-27 15:57:57 -0700312 int n = 0;
David Benjamin5e9bdc12016-06-26 16:56:29 -0400313 if (!a || !rshift || !GetInt(t, &n, "N")) {
314 return false;
315 }
316
317 ScopedBIGNUM ret(BN_new());
318 if (!ret ||
319 !BN_rshift(ret.get(), a.get(), n) ||
320 !ExpectBIGNUMsEqual(t, "A >> N", rshift.get(), ret.get())) {
321 return false;
322 }
323
324 return true;
325}
326
David Benjamine1caf392016-06-26 17:12:23 -0400327static bool TestSquare(FileTest *t, BN_CTX *ctx) {
328 ScopedBIGNUM a = GetBIGNUM(t, "A");
329 ScopedBIGNUM square = GetBIGNUM(t, "Square");
330 ScopedBIGNUM zero(BN_new());
331 if (!a || !square || !zero) {
332 return false;
333 }
334
335 BN_zero(zero.get());
336
337 ScopedBIGNUM ret(BN_new()), remainder(BN_new());
338 if (!ret ||
339 !BN_sqr(ret.get(), a.get(), ctx) ||
340 !ExpectBIGNUMsEqual(t, "A^2", square.get(), ret.get()) ||
341 !BN_mul(ret.get(), a.get(), a.get(), ctx) ||
342 !ExpectBIGNUMsEqual(t, "A * A", square.get(), ret.get()) ||
343 !BN_div(ret.get(), remainder.get(), square.get(), a.get(), ctx) ||
344 !ExpectBIGNUMsEqual(t, "Square / A", a.get(), ret.get()) ||
345 !ExpectBIGNUMsEqual(t, "Square % A", zero.get(), remainder.get())) {
346 return false;
347 }
348
349 BN_set_negative(a.get(), 0);
350 if (!BN_sqrt(ret.get(), square.get(), ctx) ||
351 !ExpectBIGNUMsEqual(t, "sqrt(Square)", a.get(), ret.get())) {
352 return false;
353 }
354
David Benjamin28a8c2f2016-07-02 20:48:45 -0400355 // BN_sqrt should fail on non-squares and negative numbers.
356 if (!BN_is_zero(square.get())) {
357 ScopedBIGNUM tmp(BN_new());
358 if (!tmp || !BN_copy(tmp.get(), square.get())) {
359 return false;
360 }
361 BN_set_negative(tmp.get(), 1);
362
363 if (BN_sqrt(ret.get(), tmp.get(), ctx)) {
364 t->PrintLine("BN_sqrt succeeded on a negative number");
365 return false;
366 }
367 ERR_clear_error();
368
369 BN_set_negative(tmp.get(), 0);
370 if (!BN_add(tmp.get(), tmp.get(), BN_value_one())) {
371 return false;
372 }
373 if (BN_sqrt(ret.get(), tmp.get(), ctx)) {
374 t->PrintLine("BN_sqrt succeeded on a non-square");
375 return false;
376 }
377 ERR_clear_error();
378 }
379
David Benjamine1caf392016-06-26 17:12:23 -0400380 return true;
381}
382
David Benjamincca1c112016-06-26 17:28:55 -0400383static bool TestProduct(FileTest *t, BN_CTX *ctx) {
384 ScopedBIGNUM a = GetBIGNUM(t, "A");
385 ScopedBIGNUM b = GetBIGNUM(t, "B");
386 ScopedBIGNUM product = GetBIGNUM(t, "Product");
387 ScopedBIGNUM zero(BN_new());
388 if (!a || !b || !product || !zero) {
389 return false;
390 }
391
392 BN_zero(zero.get());
393
394 ScopedBIGNUM ret(BN_new()), remainder(BN_new());
395 if (!ret || !remainder ||
396 !BN_mul(ret.get(), a.get(), b.get(), ctx) ||
397 !ExpectBIGNUMsEqual(t, "A * B", product.get(), ret.get()) ||
398 !BN_div(ret.get(), remainder.get(), product.get(), a.get(), ctx) ||
399 !ExpectBIGNUMsEqual(t, "Product / A", b.get(), ret.get()) ||
400 !ExpectBIGNUMsEqual(t, "Product % A", zero.get(), remainder.get()) ||
401 !BN_div(ret.get(), remainder.get(), product.get(), b.get(), ctx) ||
402 !ExpectBIGNUMsEqual(t, "Product / B", a.get(), ret.get()) ||
403 !ExpectBIGNUMsEqual(t, "Product % B", zero.get(), remainder.get())) {
404 return false;
405 }
406
407 return true;
408}
409
David Benjamin8b66fef2016-06-26 17:58:55 -0400410static bool TestQuotient(FileTest *t, BN_CTX *ctx) {
411 ScopedBIGNUM a = GetBIGNUM(t, "A");
412 ScopedBIGNUM b = GetBIGNUM(t, "B");
413 ScopedBIGNUM quotient = GetBIGNUM(t, "Quotient");
414 ScopedBIGNUM remainder = GetBIGNUM(t, "Remainder");
415 if (!a || !b || !quotient || !remainder) {
416 return false;
417 }
418
419 ScopedBIGNUM ret(BN_new()), ret2(BN_new());
420 if (!ret || !ret2 ||
421 !BN_div(ret.get(), ret2.get(), a.get(), b.get(), ctx) ||
422 !ExpectBIGNUMsEqual(t, "A / B", quotient.get(), ret.get()) ||
423 !ExpectBIGNUMsEqual(t, "A % B", remainder.get(), ret2.get()) ||
424 !BN_mul(ret.get(), quotient.get(), b.get(), ctx) ||
425 !BN_add(ret.get(), ret.get(), remainder.get()) ||
426 !ExpectBIGNUMsEqual(t, "Quotient * B + Remainder", a.get(), ret.get())) {
427 return false;
428 }
429
430 // Test with |BN_mod_word| and |BN_div_word| if the divisor is small enough.
431 BN_ULONG b_word = BN_get_word(b.get());
432 if (!BN_is_negative(b.get()) && b_word != (BN_ULONG)-1) {
433 BN_ULONG remainder_word = BN_get_word(remainder.get());
434 assert(remainder_word != (BN_ULONG)-1);
435 if (!BN_copy(ret.get(), a.get())) {
436 return false;
437 }
438 BN_ULONG ret_word = BN_div_word(ret.get(), b_word);
439 if (ret_word != remainder_word) {
440 t->PrintLine("Got A %% B (word) = " BN_HEX_FMT1 ", wanted " BN_HEX_FMT1
441 "\n",
442 ret_word, remainder_word);
443 return false;
444 }
445 if (!ExpectBIGNUMsEqual(t, "A / B (word)", quotient.get(), ret.get())) {
446 return false;
447 }
448
449 ret_word = BN_mod_word(a.get(), b_word);
450 if (ret_word != remainder_word) {
451 t->PrintLine("Got A %% B (word) = " BN_HEX_FMT1 ", wanted " BN_HEX_FMT1
452 "\n",
453 ret_word, remainder_word);
454 return false;
455 }
456 }
457
David Benjamine8317a52016-07-02 20:14:30 -0400458 // Test BN_nnmod.
459 if (!BN_is_negative(b.get())) {
460 ScopedBIGNUM nnmod(BN_new());
461 if (!nnmod ||
462 !BN_copy(nnmod.get(), remainder.get()) ||
463 (BN_is_negative(nnmod.get()) &&
464 !BN_add(nnmod.get(), nnmod.get(), b.get())) ||
465 !BN_nnmod(ret.get(), a.get(), b.get(), ctx) ||
466 !ExpectBIGNUMsEqual(t, "A % B (non-negative)", nnmod.get(),
467 ret.get())) {
468 return false;
469 }
470 }
471
David Benjamin8b66fef2016-06-26 17:58:55 -0400472 return true;
473}
474
David Benjamin5a13e402016-07-02 20:33:07 -0400475static bool TestModMul(FileTest *t, BN_CTX *ctx) {
476 ScopedBIGNUM a = GetBIGNUM(t, "A");
477 ScopedBIGNUM b = GetBIGNUM(t, "B");
478 ScopedBIGNUM m = GetBIGNUM(t, "M");
479 ScopedBIGNUM mod_mul = GetBIGNUM(t, "ModMul");
480 if (!a || !b || !m || !mod_mul) {
481 return false;
482 }
483
484 ScopedBIGNUM ret(BN_new());
485 if (!ret ||
486 !BN_mod_mul(ret.get(), a.get(), b.get(), m.get(), ctx) ||
487 !ExpectBIGNUMsEqual(t, "A * B (mod M)", mod_mul.get(), ret.get())) {
488 return false;
489 }
490
491 if (BN_is_odd(m.get())) {
492 // Reduce |a| and |b| and test the Montgomery version.
493 ScopedBN_MONT_CTX mont(BN_MONT_CTX_new());
494 ScopedBIGNUM a_tmp(BN_new()), b_tmp(BN_new());
495 if (!mont || !a_tmp || !b_tmp ||
496 !BN_MONT_CTX_set(mont.get(), m.get(), ctx) ||
497 !BN_nnmod(a_tmp.get(), a.get(), m.get(), ctx) ||
498 !BN_nnmod(b_tmp.get(), b.get(), m.get(), ctx) ||
499 !BN_to_montgomery(a_tmp.get(), a_tmp.get(), mont.get(), ctx) ||
500 !BN_to_montgomery(b_tmp.get(), b_tmp.get(), mont.get(), ctx) ||
501 !BN_mod_mul_montgomery(ret.get(), a_tmp.get(), b_tmp.get(), mont.get(),
502 ctx) ||
503 !BN_from_montgomery(ret.get(), ret.get(), mont.get(), ctx) ||
504 !ExpectBIGNUMsEqual(t, "A * B (mod M) (Montgomery)",
505 mod_mul.get(), ret.get())) {
506 return false;
507 }
508 }
509
510 return true;
511}
512
David Benjamin45a8c8a2016-07-03 10:05:56 -0400513static bool TestModExp(FileTest *t, BN_CTX *ctx) {
514 ScopedBIGNUM a = GetBIGNUM(t, "A");
515 ScopedBIGNUM e = GetBIGNUM(t, "E");
516 ScopedBIGNUM m = GetBIGNUM(t, "M");
517 ScopedBIGNUM mod_exp = GetBIGNUM(t, "ModExp");
518 if (!a || !e || !m || !mod_exp) {
519 return false;
520 }
521
522 ScopedBIGNUM ret(BN_new());
523 if (!ret ||
524 !BN_mod_exp(ret.get(), a.get(), e.get(), m.get(), ctx) ||
525 !ExpectBIGNUMsEqual(t, "A ^ E (mod M)", mod_exp.get(), ret.get())) {
526 return false;
527 }
528
529 if (BN_is_odd(m.get())) {
530 if (!BN_mod_exp_mont(ret.get(), a.get(), e.get(), m.get(), ctx, NULL) ||
531 !ExpectBIGNUMsEqual(t, "A ^ E (mod M) (Montgomery)", mod_exp.get(),
532 ret.get()) ||
533 !BN_mod_exp_mont_consttime(ret.get(), a.get(), e.get(), m.get(), ctx,
534 NULL) ||
535 !ExpectBIGNUMsEqual(t, "A ^ E (mod M) (constant-time)", mod_exp.get(),
536 ret.get())) {
537 return false;
538 }
539 }
540
541 return true;
542}
543
David Benjamin4cb00ba2016-07-03 11:52:58 -0400544static bool TestExp(FileTest *t, BN_CTX *ctx) {
545 ScopedBIGNUM a = GetBIGNUM(t, "A");
546 ScopedBIGNUM e = GetBIGNUM(t, "E");
547 ScopedBIGNUM exp = GetBIGNUM(t, "Exp");
548 if (!a || !e || !exp) {
549 return false;
550 }
551
552 ScopedBIGNUM ret(BN_new());
553 if (!ret ||
554 !BN_exp(ret.get(), a.get(), e.get(), ctx) ||
555 !ExpectBIGNUMsEqual(t, "A ^ E", exp.get(), ret.get())) {
556 return false;
557 }
558
559 return true;
560}
561
David Benjaminffb7adc2016-07-03 15:19:20 -0400562static bool TestModSqrt(FileTest *t, BN_CTX *ctx) {
563 ScopedBIGNUM a = GetBIGNUM(t, "A");
564 ScopedBIGNUM p = GetBIGNUM(t, "P");
565 ScopedBIGNUM mod_sqrt = GetBIGNUM(t, "ModSqrt");
566 if (!a || !p || !mod_sqrt) {
567 return false;
568 }
569
570 ScopedBIGNUM ret(BN_new());
571 ScopedBIGNUM ret2(BN_new());
572 if (!ret ||
573 !ret2 ||
574 !BN_mod_sqrt(ret.get(), a.get(), p.get(), ctx) ||
575 // There are two possible answers.
576 !BN_sub(ret2.get(), p.get(), ret.get())) {
577 return false;
578 }
579
580 if (BN_cmp(ret2.get(), mod_sqrt.get()) != 0 &&
581 !ExpectBIGNUMsEqual(t, "sqrt(A) (mod P)", mod_sqrt.get(), ret.get())) {
582 return false;
583 }
584
585 return true;
586}
587
Brian Smith286fbf22016-07-25 14:20:32 -1000588static bool TestModInv(FileTest *t, BN_CTX *ctx) {
589 ScopedBIGNUM a = GetBIGNUM(t, "A");
590 ScopedBIGNUM m = GetBIGNUM(t, "M");
591 ScopedBIGNUM mod_inv = GetBIGNUM(t, "ModInv");
592 if (!a || !m || !mod_inv) {
593 return false;
594 }
595
596 ScopedBIGNUM ret(BN_new());
597 if (!ret ||
598 !BN_mod_inverse(ret.get(), a.get(), m.get(), ctx) ||
599 !ExpectBIGNUMsEqual(t, "inv(A) (mod M)", mod_inv.get(), ret.get())) {
600 return false;
601 }
602
603 BN_set_flags(a.get(), BN_FLG_CONSTTIME);
604
605 if (!ret ||
606 !BN_mod_inverse(ret.get(), a.get(), m.get(), ctx) ||
607 !ExpectBIGNUMsEqual(t, "inv(A) (mod M) (constant-time)", mod_inv.get(),
608 ret.get())) {
609 return false;
610 }
611
612 return true;
613}
614
David Benjamin80137ba2016-06-26 15:03:41 -0400615struct Test {
616 const char *name;
David Benjamin30581032016-06-26 15:18:28 -0400617 bool (*func)(FileTest *t, BN_CTX *ctx);
David Benjamin80137ba2016-06-26 15:03:41 -0400618};
David Benjamina5974bf2015-03-25 23:49:37 -0400619
David Benjamin80137ba2016-06-26 15:03:41 -0400620static const Test kTests[] = {
621 {"Sum", TestSum},
David Benjamin30581032016-06-26 15:18:28 -0400622 {"LShift1", TestLShift1},
David Benjamin5e9bdc12016-06-26 16:56:29 -0400623 {"LShift", TestLShift},
624 {"RShift", TestRShift},
David Benjamine1caf392016-06-26 17:12:23 -0400625 {"Square", TestSquare},
David Benjamincca1c112016-06-26 17:28:55 -0400626 {"Product", TestProduct},
David Benjamin8b66fef2016-06-26 17:58:55 -0400627 {"Quotient", TestQuotient},
David Benjamin5a13e402016-07-02 20:33:07 -0400628 {"ModMul", TestModMul},
David Benjamin45a8c8a2016-07-03 10:05:56 -0400629 {"ModExp", TestModExp},
David Benjamin4cb00ba2016-07-03 11:52:58 -0400630 {"Exp", TestExp},
David Benjaminffb7adc2016-07-03 15:19:20 -0400631 {"ModSqrt", TestModSqrt},
Brian Smith286fbf22016-07-25 14:20:32 -1000632 {"ModInv", TestModInv},
David Benjamin80137ba2016-06-26 15:03:41 -0400633};
634
635static bool RunTest(FileTest *t, void *arg) {
David Benjamin30581032016-06-26 15:18:28 -0400636 BN_CTX *ctx = reinterpret_cast<BN_CTX *>(arg);
David Benjamin80137ba2016-06-26 15:03:41 -0400637 for (const Test &test : kTests) {
638 if (t->GetType() != test.name) {
639 continue;
David Benjamina5974bf2015-03-25 23:49:37 -0400640 }
David Benjamin30581032016-06-26 15:18:28 -0400641 return test.func(t, ctx);
David Benjamina5974bf2015-03-25 23:49:37 -0400642 }
David Benjamin80137ba2016-06-26 15:03:41 -0400643 t->PrintLine("Unknown test type: %s", t->GetType().c_str());
644 return false;
David Benjamina5974bf2015-03-25 23:49:37 -0400645}
646
David Benjamin96f94472016-06-26 17:31:02 -0400647static bool TestBN2BinPadded(BN_CTX *ctx) {
David Benjamina5974bf2015-03-25 23:49:37 -0400648 uint8_t zeros[256], out[256], reference[128];
649
650 memset(zeros, 0, sizeof(zeros));
651
652 // Test edge case at 0.
653 ScopedBIGNUM n(BN_new());
654 if (!n || !BN_bn2bin_padded(NULL, 0, n.get())) {
655 fprintf(stderr,
656 "BN_bn2bin_padded failed to encode 0 in an empty buffer.\n");
657 return false;
658 }
659 memset(out, -1, sizeof(out));
660 if (!BN_bn2bin_padded(out, sizeof(out), n.get())) {
661 fprintf(stderr,
662 "BN_bn2bin_padded failed to encode 0 in a non-empty buffer.\n");
663 return false;
664 }
665 if (memcmp(zeros, out, sizeof(out))) {
666 fprintf(stderr, "BN_bn2bin_padded did not zero buffer.\n");
667 return false;
668 }
669
670 // Test a random numbers at various byte lengths.
671 for (size_t bytes = 128 - 7; bytes <= 128; bytes++) {
David Benjamind224d522016-08-16 10:03:45 -0400672 if (!BN_rand(n.get(), bytes * 8, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY)) {
Brian Smith83a82982015-04-09 16:21:10 -1000673 ERR_print_errors_fp(stderr);
David Benjamina5974bf2015-03-25 23:49:37 -0400674 return false;
675 }
676 if (BN_num_bytes(n.get()) != bytes ||
677 BN_bn2bin(n.get(), reference) != bytes) {
678 fprintf(stderr, "Bad result from BN_rand; bytes.\n");
679 return false;
680 }
681 // Empty buffer should fail.
682 if (BN_bn2bin_padded(NULL, 0, n.get())) {
683 fprintf(stderr,
684 "BN_bn2bin_padded incorrectly succeeded on empty buffer.\n");
685 return false;
686 }
687 // One byte short should fail.
688 if (BN_bn2bin_padded(out, bytes - 1, n.get())) {
689 fprintf(stderr, "BN_bn2bin_padded incorrectly succeeded on short.\n");
690 return false;
691 }
692 // Exactly right size should encode.
693 if (!BN_bn2bin_padded(out, bytes, n.get()) ||
694 memcmp(out, reference, bytes) != 0) {
695 fprintf(stderr, "BN_bn2bin_padded gave a bad result.\n");
696 return false;
697 }
698 // Pad up one byte extra.
699 if (!BN_bn2bin_padded(out, bytes + 1, n.get()) ||
700 memcmp(out + 1, reference, bytes) || memcmp(out, zeros, 1)) {
701 fprintf(stderr, "BN_bn2bin_padded gave a bad result.\n");
702 return false;
703 }
704 // Pad up to 256.
705 if (!BN_bn2bin_padded(out, sizeof(out), n.get()) ||
706 memcmp(out + sizeof(out) - bytes, reference, bytes) ||
707 memcmp(out, zeros, sizeof(out) - bytes)) {
708 fprintf(stderr, "BN_bn2bin_padded gave a bad result.\n");
709 return false;
710 }
711 }
712
713 return true;
714}
David Benjaminc85573c2015-04-20 19:52:31 -0400715
716static int DecimalToBIGNUM(ScopedBIGNUM *out, const char *in) {
717 BIGNUM *raw = NULL;
718 int ret = BN_dec2bn(&raw, in);
719 out->reset(raw);
720 return ret;
721}
722
David Benjamin96f94472016-06-26 17:31:02 -0400723static bool TestDec2BN(BN_CTX *ctx) {
David Benjaminc85573c2015-04-20 19:52:31 -0400724 ScopedBIGNUM bn;
725 int ret = DecimalToBIGNUM(&bn, "0");
726 if (ret != 1 || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) {
727 fprintf(stderr, "BN_dec2bn gave a bad result.\n");
728 return false;
729 }
730
731 ret = DecimalToBIGNUM(&bn, "256");
732 if (ret != 3 || !BN_is_word(bn.get(), 256) || BN_is_negative(bn.get())) {
733 fprintf(stderr, "BN_dec2bn gave a bad result.\n");
734 return false;
735 }
736
737 ret = DecimalToBIGNUM(&bn, "-42");
738 if (ret != 3 || !BN_abs_is_word(bn.get(), 42) || !BN_is_negative(bn.get())) {
739 fprintf(stderr, "BN_dec2bn gave a bad result.\n");
740 return false;
741 }
742
743 ret = DecimalToBIGNUM(&bn, "-0");
744 if (ret != 2 || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) {
745 fprintf(stderr, "BN_dec2bn gave a bad result.\n");
746 return false;
747 }
748
749 ret = DecimalToBIGNUM(&bn, "42trailing garbage is ignored");
750 if (ret != 2 || !BN_abs_is_word(bn.get(), 42) || BN_is_negative(bn.get())) {
751 fprintf(stderr, "BN_dec2bn gave a bad result.\n");
752 return false;
753 }
754
755 return true;
756}
757
David Benjamin96f94472016-06-26 17:31:02 -0400758static bool TestHex2BN(BN_CTX *ctx) {
David Benjaminc85573c2015-04-20 19:52:31 -0400759 ScopedBIGNUM bn;
760 int ret = HexToBIGNUM(&bn, "0");
761 if (ret != 1 || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) {
762 fprintf(stderr, "BN_hex2bn gave a bad result.\n");
763 return false;
764 }
765
766 ret = HexToBIGNUM(&bn, "256");
767 if (ret != 3 || !BN_is_word(bn.get(), 0x256) || BN_is_negative(bn.get())) {
768 fprintf(stderr, "BN_hex2bn gave a bad result.\n");
769 return false;
770 }
771
772 ret = HexToBIGNUM(&bn, "-42");
773 if (ret != 3 || !BN_abs_is_word(bn.get(), 0x42) || !BN_is_negative(bn.get())) {
774 fprintf(stderr, "BN_hex2bn gave a bad result.\n");
775 return false;
776 }
777
778 ret = HexToBIGNUM(&bn, "-0");
779 if (ret != 2 || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) {
780 fprintf(stderr, "BN_hex2bn gave a bad result.\n");
781 return false;
782 }
783
784 ret = HexToBIGNUM(&bn, "abctrailing garbage is ignored");
785 if (ret != 3 || !BN_is_word(bn.get(), 0xabc) || BN_is_negative(bn.get())) {
786 fprintf(stderr, "BN_hex2bn gave a bad result.\n");
787 return false;
788 }
789
790 return true;
791}
792
793static ScopedBIGNUM ASCIIToBIGNUM(const char *in) {
794 BIGNUM *raw = NULL;
795 if (!BN_asc2bn(&raw, in)) {
796 return nullptr;
797 }
798 return ScopedBIGNUM(raw);
799}
800
David Benjamin96f94472016-06-26 17:31:02 -0400801static bool TestASC2BN(BN_CTX *ctx) {
David Benjaminc85573c2015-04-20 19:52:31 -0400802 ScopedBIGNUM bn = ASCIIToBIGNUM("0");
803 if (!bn || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) {
804 fprintf(stderr, "BN_asc2bn gave a bad result.\n");
805 return false;
806 }
807
808 bn = ASCIIToBIGNUM("256");
809 if (!bn || !BN_is_word(bn.get(), 256) || BN_is_negative(bn.get())) {
810 fprintf(stderr, "BN_asc2bn gave a bad result.\n");
811 return false;
812 }
813
814 bn = ASCIIToBIGNUM("-42");
815 if (!bn || !BN_abs_is_word(bn.get(), 42) || !BN_is_negative(bn.get())) {
816 fprintf(stderr, "BN_asc2bn gave a bad result.\n");
817 return false;
818 }
819
820 bn = ASCIIToBIGNUM("0x1234");
821 if (!bn || !BN_is_word(bn.get(), 0x1234) || BN_is_negative(bn.get())) {
822 fprintf(stderr, "BN_asc2bn gave a bad result.\n");
823 return false;
824 }
825
826 bn = ASCIIToBIGNUM("0X1234");
827 if (!bn || !BN_is_word(bn.get(), 0x1234) || BN_is_negative(bn.get())) {
828 fprintf(stderr, "BN_asc2bn gave a bad result.\n");
829 return false;
830 }
831
832 bn = ASCIIToBIGNUM("-0xabcd");
833 if (!bn || !BN_abs_is_word(bn.get(), 0xabcd) || !BN_is_negative(bn.get())) {
834 fprintf(stderr, "BN_asc2bn gave a bad result.\n");
835 return false;
836 }
837
838 bn = ASCIIToBIGNUM("-0");
839 if (!bn || !BN_is_zero(bn.get()) || BN_is_negative(bn.get())) {
840 fprintf(stderr, "BN_asc2bn gave a bad result.\n");
841 return false;
842 }
843
844 bn = ASCIIToBIGNUM("123trailing garbage is ignored");
845 if (!bn || !BN_is_word(bn.get(), 123) || BN_is_negative(bn.get())) {
846 fprintf(stderr, "BN_asc2bn gave a bad result.\n");
847 return false;
848 }
849
850 return true;
851}
David Benjaminb3a7b512015-05-26 18:35:28 -0400852
Matt Braithwaite64887252015-08-11 17:17:28 -0700853struct MPITest {
854 const char *base10;
855 const char *mpi;
856 size_t mpi_len;
857};
858
859static const MPITest kMPITests[] = {
860 { "0", "\x00\x00\x00\x00", 4 },
861 { "1", "\x00\x00\x00\x01\x01", 5 },
862 { "-1", "\x00\x00\x00\x01\x81", 5 },
863 { "128", "\x00\x00\x00\x02\x00\x80", 6 },
864 { "256", "\x00\x00\x00\x02\x01\x00", 6 },
865 { "-256", "\x00\x00\x00\x02\x81\x00", 6 },
866};
867
David Benjamin96f94472016-06-26 17:31:02 -0400868static bool TestMPI() {
Matt Braithwaite64887252015-08-11 17:17:28 -0700869 uint8_t scratch[8];
870
Steven Valdezcb966542016-08-17 16:56:14 -0400871 for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMPITests); i++) {
Matt Braithwaite64887252015-08-11 17:17:28 -0700872 const MPITest &test = kMPITests[i];
873 ScopedBIGNUM bn(ASCIIToBIGNUM(test.base10));
874 const size_t mpi_len = BN_bn2mpi(bn.get(), NULL);
875 if (mpi_len > sizeof(scratch)) {
876 fprintf(stderr, "MPI test #%u: MPI size is too large to test.\n",
877 (unsigned)i);
878 return false;
879 }
880
881 const size_t mpi_len2 = BN_bn2mpi(bn.get(), scratch);
882 if (mpi_len != mpi_len2) {
883 fprintf(stderr, "MPI test #%u: length changes.\n", (unsigned)i);
884 return false;
885 }
886
887 if (mpi_len != test.mpi_len ||
888 memcmp(test.mpi, scratch, mpi_len) != 0) {
889 fprintf(stderr, "MPI test #%u failed:\n", (unsigned)i);
890 hexdump(stderr, "Expected: ", test.mpi, test.mpi_len);
891 hexdump(stderr, "Got: ", scratch, mpi_len);
892 return false;
893 }
894
895 ScopedBIGNUM bn2(BN_mpi2bn(scratch, mpi_len, NULL));
896 if (bn2.get() == nullptr) {
897 fprintf(stderr, "MPI test #%u: failed to parse\n", (unsigned)i);
898 return false;
899 }
900
901 if (BN_cmp(bn.get(), bn2.get()) != 0) {
902 fprintf(stderr, "MPI test #%u: wrong result\n", (unsigned)i);
903 return false;
904 }
905 }
906
907 return true;
908}
909
David Benjamin96f94472016-06-26 17:31:02 -0400910static bool TestRand() {
David Benjaminb3a7b512015-05-26 18:35:28 -0400911 ScopedBIGNUM bn(BN_new());
912 if (!bn) {
913 return false;
914 }
915
916 // Test BN_rand accounts for degenerate cases with |top| and |bottom|
917 // parameters.
David Benjamind224d522016-08-16 10:03:45 -0400918 if (!BN_rand(bn.get(), 0, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY) ||
David Benjaminb3a7b512015-05-26 18:35:28 -0400919 !BN_is_zero(bn.get())) {
920 fprintf(stderr, "BN_rand gave a bad result.\n");
921 return false;
922 }
David Benjamind224d522016-08-16 10:03:45 -0400923 if (!BN_rand(bn.get(), 0, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ODD) ||
David Benjaminb3a7b512015-05-26 18:35:28 -0400924 !BN_is_zero(bn.get())) {
925 fprintf(stderr, "BN_rand gave a bad result.\n");
926 return false;
927 }
928
David Benjamind224d522016-08-16 10:03:45 -0400929 if (!BN_rand(bn.get(), 1, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY) ||
David Benjaminb3a7b512015-05-26 18:35:28 -0400930 !BN_is_word(bn.get(), 1)) {
931 fprintf(stderr, "BN_rand gave a bad result.\n");
932 return false;
933 }
David Benjamind224d522016-08-16 10:03:45 -0400934 if (!BN_rand(bn.get(), 1, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ANY) ||
David Benjaminb3a7b512015-05-26 18:35:28 -0400935 !BN_is_word(bn.get(), 1)) {
936 fprintf(stderr, "BN_rand gave a bad result.\n");
937 return false;
938 }
David Benjamind224d522016-08-16 10:03:45 -0400939 if (!BN_rand(bn.get(), 1, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ODD) ||
David Benjaminb3a7b512015-05-26 18:35:28 -0400940 !BN_is_word(bn.get(), 1)) {
941 fprintf(stderr, "BN_rand gave a bad result.\n");
942 return false;
943 }
944
David Benjamind224d522016-08-16 10:03:45 -0400945 if (!BN_rand(bn.get(), 2, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ANY) ||
David Benjaminb3a7b512015-05-26 18:35:28 -0400946 !BN_is_word(bn.get(), 3)) {
947 fprintf(stderr, "BN_rand gave a bad result.\n");
948 return false;
949 }
950
951 return true;
952}
David Benjaminb9c579d2015-06-11 22:52:07 -0400953
954struct ASN1Test {
955 const char *value_ascii;
956 const char *der;
957 size_t der_len;
958};
959
960static const ASN1Test kASN1Tests[] = {
961 {"0", "\x02\x01\x00", 3},
962 {"1", "\x02\x01\x01", 3},
963 {"127", "\x02\x01\x7f", 3},
964 {"128", "\x02\x02\x00\x80", 4},
965 {"0xdeadbeef", "\x02\x05\x00\xde\xad\xbe\xef", 7},
966 {"0x0102030405060708",
967 "\x02\x08\x01\x02\x03\x04\x05\x06\x07\x08", 10},
968 {"0xffffffffffffffff",
969 "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", 11},
970};
971
972struct ASN1InvalidTest {
973 const char *der;
974 size_t der_len;
975};
976
977static const ASN1InvalidTest kASN1InvalidTests[] = {
978 // Bad tag.
979 {"\x03\x01\x00", 3},
980 // Empty contents.
981 {"\x02\x00", 2},
David Benjaminb9c579d2015-06-11 22:52:07 -0400982};
983
Adam Langleydd31c4e2016-02-02 08:49:30 -0800984// kASN1BuggyTests contains incorrect encodings and the corresponding, expected
985// results of |BN_parse_asn1_unsigned_buggy| given that input.
David Benjamin4c60d352015-09-23 12:23:01 -0400986static const ASN1Test kASN1BuggyTests[] = {
987 // Negative numbers.
David Benjamin231cb822015-09-15 16:47:35 -0400988 {"128", "\x02\x01\x80", 3},
989 {"255", "\x02\x01\xff", 3},
David Benjamin4c60d352015-09-23 12:23:01 -0400990 // Unnecessary leading zeros.
991 {"1", "\x02\x02\x00\x01", 4},
David Benjamin231cb822015-09-15 16:47:35 -0400992};
993
David Benjamin96f94472016-06-26 17:31:02 -0400994static bool TestASN1() {
David Benjaminb9c579d2015-06-11 22:52:07 -0400995 for (const ASN1Test &test : kASN1Tests) {
996 ScopedBIGNUM bn = ASCIIToBIGNUM(test.value_ascii);
997 if (!bn) {
998 return false;
999 }
1000
1001 // Test that the input is correctly parsed.
1002 ScopedBIGNUM bn2(BN_new());
1003 if (!bn2) {
1004 return false;
1005 }
1006 CBS cbs;
1007 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
David Benjaminacb24512015-12-22 15:02:01 -05001008 if (!BN_parse_asn1_unsigned(&cbs, bn2.get()) || CBS_len(&cbs) != 0) {
David Benjaminb9c579d2015-06-11 22:52:07 -04001009 fprintf(stderr, "Parsing ASN.1 INTEGER failed.\n");
1010 return false;
1011 }
1012 if (BN_cmp(bn.get(), bn2.get()) != 0) {
1013 fprintf(stderr, "Bad parse.\n");
1014 return false;
1015 }
1016
1017 // Test the value serializes correctly.
1018 CBB cbb;
1019 uint8_t *der;
1020 size_t der_len;
1021 CBB_zero(&cbb);
1022 if (!CBB_init(&cbb, 0) ||
David Benjaminacb24512015-12-22 15:02:01 -05001023 !BN_marshal_asn1(&cbb, bn.get()) ||
David Benjaminb9c579d2015-06-11 22:52:07 -04001024 !CBB_finish(&cbb, &der, &der_len)) {
1025 CBB_cleanup(&cbb);
1026 return false;
1027 }
Adam Langley10f97f32016-07-12 08:09:33 -07001028 ScopedOpenSSLBytes delete_der(der);
David Benjaminb9c579d2015-06-11 22:52:07 -04001029 if (der_len != test.der_len ||
1030 memcmp(der, reinterpret_cast<const uint8_t*>(test.der), der_len) != 0) {
1031 fprintf(stderr, "Bad serialization.\n");
1032 return false;
1033 }
David Benjamin231cb822015-09-15 16:47:35 -04001034
Adam Langleydd31c4e2016-02-02 08:49:30 -08001035 // |BN_parse_asn1_unsigned_buggy| parses all valid input.
David Benjamin231cb822015-09-15 16:47:35 -04001036 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
David Benjaminacb24512015-12-22 15:02:01 -05001037 if (!BN_parse_asn1_unsigned_buggy(&cbs, bn2.get()) || CBS_len(&cbs) != 0) {
David Benjamin231cb822015-09-15 16:47:35 -04001038 fprintf(stderr, "Parsing ASN.1 INTEGER failed.\n");
1039 return false;
1040 }
1041 if (BN_cmp(bn.get(), bn2.get()) != 0) {
1042 fprintf(stderr, "Bad parse.\n");
1043 return false;
1044 }
David Benjaminb9c579d2015-06-11 22:52:07 -04001045 }
1046
1047 for (const ASN1InvalidTest &test : kASN1InvalidTests) {
1048 ScopedBIGNUM bn(BN_new());
1049 if (!bn) {
1050 return false;
1051 }
1052 CBS cbs;
1053 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
David Benjaminacb24512015-12-22 15:02:01 -05001054 if (BN_parse_asn1_unsigned(&cbs, bn.get())) {
David Benjaminb9c579d2015-06-11 22:52:07 -04001055 fprintf(stderr, "Parsed invalid input.\n");
1056 return false;
1057 }
1058 ERR_clear_error();
David Benjamin231cb822015-09-15 16:47:35 -04001059
1060 // All tests in kASN1InvalidTests are also rejected by
Adam Langleydd31c4e2016-02-02 08:49:30 -08001061 // |BN_parse_asn1_unsigned_buggy|.
David Benjamin231cb822015-09-15 16:47:35 -04001062 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
David Benjaminacb24512015-12-22 15:02:01 -05001063 if (BN_parse_asn1_unsigned_buggy(&cbs, bn.get())) {
David Benjamin231cb822015-09-15 16:47:35 -04001064 fprintf(stderr, "Parsed invalid input.\n");
1065 return false;
1066 }
1067 ERR_clear_error();
1068 }
1069
David Benjamin4c60d352015-09-23 12:23:01 -04001070 for (const ASN1Test &test : kASN1BuggyTests) {
Adam Langleydd31c4e2016-02-02 08:49:30 -08001071 // These broken encodings are rejected by |BN_parse_asn1_unsigned|.
David Benjamin231cb822015-09-15 16:47:35 -04001072 ScopedBIGNUM bn(BN_new());
1073 if (!bn) {
1074 return false;
1075 }
1076
1077 CBS cbs;
1078 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
David Benjaminacb24512015-12-22 15:02:01 -05001079 if (BN_parse_asn1_unsigned(&cbs, bn.get())) {
David Benjamin231cb822015-09-15 16:47:35 -04001080 fprintf(stderr, "Parsed invalid input.\n");
1081 return false;
1082 }
1083 ERR_clear_error();
1084
Adam Langleydd31c4e2016-02-02 08:49:30 -08001085 // However |BN_parse_asn1_unsigned_buggy| accepts them.
David Benjamin231cb822015-09-15 16:47:35 -04001086 ScopedBIGNUM bn2 = ASCIIToBIGNUM(test.value_ascii);
1087 if (!bn2) {
1088 return false;
1089 }
1090
1091 CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
David Benjaminacb24512015-12-22 15:02:01 -05001092 if (!BN_parse_asn1_unsigned_buggy(&cbs, bn.get()) || CBS_len(&cbs) != 0) {
David Benjamin231cb822015-09-15 16:47:35 -04001093 fprintf(stderr, "Parsing (invalid) ASN.1 INTEGER failed.\n");
1094 return false;
1095 }
1096
1097 if (BN_cmp(bn.get(), bn2.get()) != 0) {
1098 fprintf(stderr, "\"Bad\" parse.\n");
1099 return false;
1100 }
David Benjaminb9c579d2015-06-11 22:52:07 -04001101 }
1102
1103 // Serializing negative numbers is not supported.
1104 ScopedBIGNUM bn = ASCIIToBIGNUM("-1");
1105 if (!bn) {
1106 return false;
1107 }
1108 CBB cbb;
1109 CBB_zero(&cbb);
1110 if (!CBB_init(&cbb, 0) ||
David Benjaminacb24512015-12-22 15:02:01 -05001111 BN_marshal_asn1(&cbb, bn.get())) {
David Benjaminb9c579d2015-06-11 22:52:07 -04001112 fprintf(stderr, "Serialized negative number.\n");
1113 CBB_cleanup(&cbb);
1114 return false;
1115 }
David Benjamin8b66fef2016-06-26 17:58:55 -04001116 ERR_clear_error();
David Benjaminb9c579d2015-06-11 22:52:07 -04001117 CBB_cleanup(&cbb);
1118
1119 return true;
1120}
David Benjamincca1c112016-06-26 17:28:55 -04001121
David Benjamin8b66fef2016-06-26 17:58:55 -04001122static bool TestNegativeZero(BN_CTX *ctx) {
David Benjamincca1c112016-06-26 17:28:55 -04001123 ScopedBIGNUM a(BN_new());
1124 ScopedBIGNUM b(BN_new());
1125 ScopedBIGNUM c(BN_new());
David Benjamin899b9b12016-08-02 13:09:19 -04001126 if (!a || !b || !c) {
David Benjamincca1c112016-06-26 17:28:55 -04001127 return false;
1128 }
1129
1130 // Test that BN_mul never gives negative zero.
1131 if (!BN_set_word(a.get(), 1)) {
1132 return false;
1133 }
1134 BN_set_negative(a.get(), 1);
1135 BN_zero(b.get());
David Benjamin8b66fef2016-06-26 17:58:55 -04001136 if (!BN_mul(c.get(), a.get(), b.get(), ctx)) {
David Benjamincca1c112016-06-26 17:28:55 -04001137 return false;
1138 }
1139 if (!BN_is_zero(c.get()) || BN_is_negative(c.get())) {
David Benjamin2b314fa2016-08-02 12:49:38 -04001140 fprintf(stderr, "Multiplication test failed.\n");
David Benjamincca1c112016-06-26 17:28:55 -04001141 return false;
1142 }
1143
David Benjamin899b9b12016-08-02 13:09:19 -04001144 for (int consttime = 0; consttime < 2; consttime++) {
1145 ScopedBIGNUM numerator(BN_new()), denominator(BN_new());
1146 if (!numerator || !denominator) {
1147 return false;
1148 }
David Benjamin8b66fef2016-06-26 17:58:55 -04001149
David Benjamin899b9b12016-08-02 13:09:19 -04001150 if (consttime) {
1151 BN_set_flags(numerator.get(), BN_FLG_CONSTTIME);
1152 BN_set_flags(denominator.get(), BN_FLG_CONSTTIME);
1153 }
1154
1155 // Test that BN_div never gives negative zero in the quotient.
1156 if (!BN_set_word(numerator.get(), 1) ||
1157 !BN_set_word(denominator.get(), 2)) {
1158 return false;
1159 }
1160 BN_set_negative(numerator.get(), 1);
1161 if (!BN_div(a.get(), b.get(), numerator.get(), denominator.get(), ctx)) {
1162 return false;
1163 }
1164 if (!BN_is_zero(a.get()) || BN_is_negative(a.get())) {
1165 fprintf(stderr, "Incorrect quotient (consttime = %d).\n", consttime);
1166 return false;
1167 }
1168
1169 // Test that BN_div never gives negative zero in the remainder.
1170 if (!BN_set_word(denominator.get(), 1)) {
1171 return false;
1172 }
1173 if (!BN_div(a.get(), b.get(), numerator.get(), denominator.get(), ctx)) {
1174 return false;
1175 }
1176 if (!BN_is_zero(b.get()) || BN_is_negative(b.get())) {
1177 fprintf(stderr, "Incorrect remainder (consttime = %d).\n", consttime);
1178 return false;
1179 }
David Benjamin2b314fa2016-08-02 12:49:38 -04001180 }
1181
1182 // Test that BN_set_negative will not produce a negative zero.
1183 BN_zero(a.get());
1184 BN_set_negative(a.get(), 1);
1185 if (BN_is_negative(a.get())) {
1186 fprintf(stderr, "BN_set_negative produced a negative zero.\n");
1187 return false;
1188 }
1189
1190 // Test that forcibly creating a negative zero does not break |BN_bn2hex| or
1191 // |BN_bn2dec|.
1192 a->neg = 1;
1193 ScopedOpenSSLString dec(BN_bn2dec(a.get()));
1194 ScopedOpenSSLString hex(BN_bn2hex(a.get()));
1195 if (!dec || !hex ||
1196 strcmp(dec.get(), "-0") != 0 ||
1197 strcmp(hex.get(), "-0") != 0) {
1198 fprintf(stderr, "BN_bn2dec or BN_bn2hex failed with negative zero.\n");
David Benjamin8b66fef2016-06-26 17:58:55 -04001199 return false;
1200 }
1201
1202 return true;
1203}
1204
David Benjamindcc55312016-06-26 18:15:12 -04001205static bool TestBadModulus(BN_CTX *ctx) {
David Benjamin8b66fef2016-06-26 17:58:55 -04001206 ScopedBIGNUM a(BN_new());
1207 ScopedBIGNUM b(BN_new());
1208 ScopedBIGNUM zero(BN_new());
David Benjamindcc55312016-06-26 18:15:12 -04001209 ScopedBN_MONT_CTX mont(BN_MONT_CTX_new());
1210 if (!a || !b || !zero || !mont) {
David Benjamin8b66fef2016-06-26 17:58:55 -04001211 return false;
1212 }
1213
1214 BN_zero(zero.get());
1215
1216 if (BN_div(a.get(), b.get(), BN_value_one(), zero.get(), ctx)) {
David Benjamin2b314fa2016-08-02 12:49:38 -04001217 fprintf(stderr, "Division by zero unexpectedly succeeded.\n");
David Benjamin8b66fef2016-06-26 17:58:55 -04001218 return false;
1219 }
1220 ERR_clear_error();
1221
David Benjamindcc55312016-06-26 18:15:12 -04001222 if (BN_mod_mul(a.get(), BN_value_one(), BN_value_one(), zero.get(), ctx)) {
David Benjamin2b314fa2016-08-02 12:49:38 -04001223 fprintf(stderr, "BN_mod_mul with zero modulus unexpectedly succeeded.\n");
David Benjamindcc55312016-06-26 18:15:12 -04001224 return false;
1225 }
1226 ERR_clear_error();
1227
1228 if (BN_mod_exp(a.get(), BN_value_one(), BN_value_one(), zero.get(), ctx)) {
David Benjamin2b314fa2016-08-02 12:49:38 -04001229 fprintf(stderr, "BN_mod_exp with zero modulus unexpectedly succeeded.\n");
David Benjamindcc55312016-06-26 18:15:12 -04001230 return 0;
1231 }
1232 ERR_clear_error();
1233
Brian Smithb72f66f2016-07-01 11:34:10 -10001234 if (BN_mod_exp_mont(a.get(), BN_value_one(), BN_value_one(), zero.get(), ctx,
1235 NULL)) {
David Benjamin2b314fa2016-08-02 12:49:38 -04001236 fprintf(stderr,
1237 "BN_mod_exp_mont with zero modulus unexpectedly succeeded.\n");
Brian Smithb72f66f2016-07-01 11:34:10 -10001238 return 0;
1239 }
1240 ERR_clear_error();
1241
David Benjamindcc55312016-06-26 18:15:12 -04001242 if (BN_mod_exp_mont_consttime(a.get(), BN_value_one(), BN_value_one(),
1243 zero.get(), ctx, nullptr)) {
David Benjamin2b314fa2016-08-02 12:49:38 -04001244 fprintf(stderr,
1245 "BN_mod_exp_mont_consttime with zero modulus unexpectedly "
1246 "succeeded.\n");
David Benjamindcc55312016-06-26 18:15:12 -04001247 return 0;
1248 }
1249 ERR_clear_error();
1250
1251 if (BN_MONT_CTX_set(mont.get(), zero.get(), ctx)) {
David Benjamin2b314fa2016-08-02 12:49:38 -04001252 fprintf(stderr,
1253 "BN_MONT_CTX_set unexpectedly succeeded for zero modulus.\n");
David Benjamindcc55312016-06-26 18:15:12 -04001254 return false;
1255 }
1256 ERR_clear_error();
1257
1258 // Some operations also may not be used with an even modulus.
1259
1260 if (!BN_set_word(b.get(), 16)) {
1261 return false;
1262 }
1263
1264 if (BN_MONT_CTX_set(mont.get(), b.get(), ctx)) {
David Benjamin2b314fa2016-08-02 12:49:38 -04001265 fprintf(stderr,
1266 "BN_MONT_CTX_set unexpectedly succeeded for even modulus.\n");
David Benjamindcc55312016-06-26 18:15:12 -04001267 return false;
1268 }
1269 ERR_clear_error();
1270
Brian Smithb72f66f2016-07-01 11:34:10 -10001271 if (BN_mod_exp_mont(a.get(), BN_value_one(), BN_value_one(), b.get(), ctx,
1272 NULL)) {
David Benjamin2b314fa2016-08-02 12:49:38 -04001273 fprintf(stderr,
1274 "BN_mod_exp_mont with even modulus unexpectedly succeeded.\n");
Brian Smithb72f66f2016-07-01 11:34:10 -10001275 return 0;
1276 }
1277 ERR_clear_error();
1278
David Benjamindcc55312016-06-26 18:15:12 -04001279 if (BN_mod_exp_mont_consttime(a.get(), BN_value_one(), BN_value_one(),
1280 b.get(), ctx, nullptr)) {
David Benjamin2b314fa2016-08-02 12:49:38 -04001281 fprintf(stderr,
1282 "BN_mod_exp_mont_consttime with even modulus unexpectedly "
1283 "succeeded.\n");
David Benjamindcc55312016-06-26 18:15:12 -04001284 return 0;
1285 }
1286 ERR_clear_error();
1287
David Benjamincca1c112016-06-26 17:28:55 -04001288 return true;
1289}
David Benjamin32a37802016-06-26 18:17:31 -04001290
1291// TestExpModZero tests that 1**0 mod 1 == 0.
1292static bool TestExpModZero() {
1293 ScopedBIGNUM zero(BN_new()), a(BN_new()), r(BN_new());
David Benjamind224d522016-08-16 10:03:45 -04001294 if (!zero || !a || !r ||
1295 !BN_rand(a.get(), 1024, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY)) {
David Benjamin32a37802016-06-26 18:17:31 -04001296 return false;
1297 }
1298 BN_zero(zero.get());
1299
1300 if (!BN_mod_exp(r.get(), a.get(), zero.get(), BN_value_one(), nullptr) ||
1301 !BN_is_zero(r.get()) ||
1302 !BN_mod_exp_mont(r.get(), a.get(), zero.get(), BN_value_one(), nullptr,
1303 nullptr) ||
1304 !BN_is_zero(r.get()) ||
1305 !BN_mod_exp_mont_consttime(r.get(), a.get(), zero.get(), BN_value_one(),
1306 nullptr, nullptr) ||
1307 !BN_is_zero(r.get()) ||
1308 !BN_mod_exp_mont_word(r.get(), 42, zero.get(), BN_value_one(), nullptr,
1309 nullptr) ||
1310 !BN_is_zero(r.get())) {
1311 return false;
1312 }
1313
1314 return true;
1315}
1316
1317static bool TestSmallPrime(BN_CTX *ctx) {
1318 static const unsigned kBits = 10;
1319
1320 ScopedBIGNUM r(BN_new());
1321 if (!r || !BN_generate_prime_ex(r.get(), static_cast<int>(kBits), 0, NULL,
1322 NULL, NULL)) {
1323 return false;
1324 }
1325 if (BN_num_bits(r.get()) != kBits) {
1326 fprintf(stderr, "Expected %u bit prime, got %u bit number\n", kBits,
1327 BN_num_bits(r.get()));
1328 return false;
1329 }
1330
1331 return true;
1332}
David Benjamin47489442016-07-09 15:22:50 -07001333
David Benjaminccd511e2016-07-29 12:11:34 -04001334static bool TestCmpWord() {
1335 static const BN_ULONG kMaxWord = (BN_ULONG)-1;
1336
1337 ScopedBIGNUM r(BN_new());
1338 if (!r ||
1339 !BN_set_word(r.get(), 0)) {
1340 return false;
1341 }
1342
1343 if (BN_cmp_word(r.get(), 0) != 0 ||
1344 BN_cmp_word(r.get(), 1) >= 0 ||
1345 BN_cmp_word(r.get(), kMaxWord) >= 0) {
1346 fprintf(stderr, "BN_cmp_word compared against 0 incorrectly.\n");
1347 return false;
1348 }
1349
1350 if (!BN_set_word(r.get(), 100)) {
1351 return false;
1352 }
1353
1354 if (BN_cmp_word(r.get(), 0) <= 0 ||
1355 BN_cmp_word(r.get(), 99) <= 0 ||
1356 BN_cmp_word(r.get(), 100) != 0 ||
1357 BN_cmp_word(r.get(), 101) >= 0 ||
1358 BN_cmp_word(r.get(), kMaxWord) >= 0) {
1359 fprintf(stderr, "BN_cmp_word compared against 100 incorrectly.\n");
1360 return false;
1361 }
1362
1363 BN_set_negative(r.get(), 1);
1364
1365 if (BN_cmp_word(r.get(), 0) >= 0 ||
1366 BN_cmp_word(r.get(), 100) >= 0 ||
1367 BN_cmp_word(r.get(), kMaxWord) >= 0) {
1368 fprintf(stderr, "BN_cmp_word compared against -100 incorrectly.\n");
1369 return false;
1370 }
1371
1372 if (!BN_set_word(r.get(), kMaxWord)) {
1373 return false;
1374 }
1375
1376 if (BN_cmp_word(r.get(), 0) <= 0 ||
1377 BN_cmp_word(r.get(), kMaxWord - 1) <= 0 ||
1378 BN_cmp_word(r.get(), kMaxWord) != 0) {
1379 fprintf(stderr, "BN_cmp_word compared against kMaxWord incorrectly.\n");
1380 return false;
1381 }
1382
1383 if (!BN_add(r.get(), r.get(), BN_value_one())) {
1384 return false;
1385 }
1386
1387 if (BN_cmp_word(r.get(), 0) <= 0 ||
1388 BN_cmp_word(r.get(), kMaxWord) <= 0) {
1389 fprintf(stderr, "BN_cmp_word compared against kMaxWord + 1 incorrectly.\n");
1390 return false;
1391 }
1392
1393 BN_set_negative(r.get(), 1);
1394
1395 if (BN_cmp_word(r.get(), 0) >= 0 ||
1396 BN_cmp_word(r.get(), kMaxWord) >= 0) {
1397 fprintf(stderr,
1398 "BN_cmp_word compared against -kMaxWord - 1 incorrectly.\n");
1399 return false;
1400 }
1401
1402 return true;
1403}
1404
David Benjamin7c040752016-08-22 22:19:01 -07001405static bool TestBN2Dec() {
1406 static const char *kBN2DecTests[] = {
1407 "0",
1408 "1",
1409 "-1",
1410 "100",
1411 "-100",
1412 "123456789012345678901234567890",
1413 "-123456789012345678901234567890",
1414 "123456789012345678901234567890123456789012345678901234567890",
1415 "-123456789012345678901234567890123456789012345678901234567890",
1416 };
1417
1418 for (const char *test : kBN2DecTests) {
1419 ScopedBIGNUM bn;
1420 int ret = DecimalToBIGNUM(&bn, test);
1421 if (ret == 0) {
1422 return false;
1423 }
1424
1425 ScopedOpenSSLString dec(BN_bn2dec(bn.get()));
1426 if (!dec) {
1427 fprintf(stderr, "BN_bn2dec failed on %s.\n", test);
1428 return false;
1429 }
1430
1431 if (strcmp(dec.get(), test) != 0) {
1432 fprintf(stderr, "BN_bn2dec gave %s, wanted %s.\n", dec.get(), test);
1433 return false;
1434 }
1435 }
1436
1437 return true;
1438}
1439
David Benjamin47489442016-07-09 15:22:50 -07001440int main(int argc, char *argv[]) {
1441 CRYPTO_library_init();
1442
1443 if (argc != 2) {
1444 fprintf(stderr, "%s TEST_FILE\n", argv[0]);
1445 return 1;
1446 }
1447
Adam Langley10f97f32016-07-12 08:09:33 -07001448 ScopedBN_CTX ctx(BN_CTX_new());
David Benjamin47489442016-07-09 15:22:50 -07001449 if (!ctx) {
1450 return 1;
1451 }
1452
Adam Langley10f97f32016-07-12 08:09:33 -07001453 if (!TestBN2BinPadded(ctx.get()) ||
1454 !TestDec2BN(ctx.get()) ||
1455 !TestHex2BN(ctx.get()) ||
1456 !TestASC2BN(ctx.get()) ||
1457 !TestMPI() ||
1458 !TestRand() ||
1459 !TestASN1() ||
1460 !TestNegativeZero(ctx.get()) ||
1461 !TestBadModulus(ctx.get()) ||
1462 !TestExpModZero() ||
David Benjaminccd511e2016-07-29 12:11:34 -04001463 !TestSmallPrime(ctx.get()) ||
David Benjamin7c040752016-08-22 22:19:01 -07001464 !TestCmpWord() ||
1465 !TestBN2Dec()) {
David Benjamin47489442016-07-09 15:22:50 -07001466 return 1;
1467 }
1468
Adam Langley10f97f32016-07-12 08:09:33 -07001469 return FileTestMain(RunTest, ctx.get(), argv[1]);
David Benjamin47489442016-07-09 15:22:50 -07001470}