Compare commits

..

2 Commits

Author SHA1 Message Date
David Benjamin 4d7ba4e4e5 bn/asm/rsaz-avx2.pl: fix digit correction bug in rsaz_1024_mul_avx2.
Credit to OSS-Fuzz for finding this.

CVE-2017-3738

(Imported from upstream's 5630661aecbea5fe3c4740f5fea744a1f07a6253 and
77d75993651b63e872244a3256e37967bb3c3e9e.)

Confirmed with Intel SDE that the fix makes the test vector pass and
that, without the fix, the test vector does not. (Well, we knew the
latter already, since it was our test vector.)

(cherry-picked from 296a61d600)

Change-Id: I167aa3407ddab3b434bacbd18e099c55aa40ac4c
Reviewed-on: https://boringssl-review.googlesource.com/23884
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-on: https://boringssl-review.googlesource.com/23924
2017-12-07 19:16:01 +00:00
Adam Langley 9f69f139ed Clear bottom three bits of password scalar in SPAKE2.
Due to a copy-paste error, the call to |left_shift_3| is missing after
reducing the password scalar in SPAKE2. This means that three bits of
the password leak in Alice's message. (Two in Bob's message as the point
N happens to have order 4l, not 8l.)

The “correct” fix is to put in the missing call to |left_shift_3|, but
that would be a breaking change. In order to fix this in a unilateral
way, we add points of small order to the masking point to bring it into
prime-order subgroup.

BUG=chromium:778101

Change-Id: I440931a3df7f009b324d2a3e3af2d893a101804f
Reviewed-on: https://boringssl-review.googlesource.com/22445
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
2017-11-16 08:19:54 -08:00
1128 changed files with 12055 additions and 14891 deletions
+1 -23
View File
@@ -72,9 +72,6 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
if(NOT BORINGSSL_ALLOW_CXX_RUNTIME)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
endif()
@@ -238,24 +235,6 @@ if (ASAN)
set(OPENSSL_NO_ASM "1")
endif()
if(CFI)
if(NOT CLANG)
message(FATAL_ERROR "Cannot enable CFI unless using Clang")
endif()
# TODO(crbug.com/785442): Remove -fsanitize-cfi-icall-generalize-pointers.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=cfi -fno-sanitize-trap=cfi -fsanitize-cfi-icall-generalize-pointers -flto")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=cfi -fno-sanitize-trap=cfi -fsanitize-cfi-icall-generalize-pointers -flto")
# We use Chromium's copy of clang, which requires -fuse-ld=lld if building
# with -flto. That, in turn, can't handle -ggdb.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld")
string(REPLACE "-ggdb" "-g" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
string(REPLACE "-ggdb" "-g" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
# -flto causes object files to contain LLVM bitcode. Mixing those with
# assembly output in the same static library breaks the linker.
set(OPENSSL_NO_ASM "1")
endif()
if (GCOV)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
@@ -328,7 +307,7 @@ if (ANDROID AND ${ARCH} STREQUAL "arm")
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR}")
endif()
if (${ARCH} STREQUAL "x86" AND APPLE AND ${CMAKE_VERSION} VERSION_LESS "3.0")
if (${ARCH} STREQUAL "x86" AND APPLE)
# With CMake 2.8.x, ${CMAKE_SYSTEM_PROCESSOR} evalutes to i386 on OS X,
# but clang defaults to 64-bit builds on OS X unless otherwise told.
# Set ARCH to x86_64 so clang and CMake agree. This is fixed in CMake 3.
@@ -356,7 +335,6 @@ add_custom_command(
add_library(crypto_test_data OBJECT crypto_test_data.cc)
add_subdirectory(crypto)
add_subdirectory(third_party/fiat)
add_subdirectory(ssl)
add_subdirectory(ssl/test)
add_subdirectory(fipstools)
+1 -27
View File
@@ -6,9 +6,7 @@ Contributors to BoringSSL are required to follow the CLA rules for Chromium:
https://cla.developers.google.com/clas
Some files from Intel are under yet another license, which is also included
underneath. Files in third_party/ have their own licenses, as described
therein. The MIT license, for third_party/fiat, which, unlike other third_party
directories, is compiled into non-test libraries, is included below.
underneath.
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the
OpenSSL License and the original SSLeay license apply to the toolkit. See below
@@ -192,27 +190,3 @@ Some files from Intel carry the following license:
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The code in third_party/fiat carries the MIT license:
Copyright (c) 2015-2016 the fiat-crypto authors (see
https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-2
View File
@@ -179,7 +179,6 @@ add_library(
$<TARGET_OBJECTS:chacha>
$<TARGET_OBJECTS:poly1305>
$<TARGET_OBJECTS:curve25519>
$<TARGET_OBJECTS:fiat>
$<TARGET_OBJECTS:buf>
$<TARGET_OBJECTS:bn_extra>
$<TARGET_OBJECTS:bio>
@@ -221,7 +220,6 @@ add_executable(
asn1/asn1_test.cc
base64/base64_test.cc
buf/buf_test.cc
bio/bio_test.cc
bytestring/bytestring_test.cc
chacha/chacha_test.cc
+9 -20
View File
@@ -56,7 +56,6 @@
#include <openssl/asn1.h>
#include <limits.h>
#include <string.h>
#include <openssl/err.h>
@@ -111,6 +110,7 @@ int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v)
long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a)
{
int neg = 0, i;
long r = 0;
if (a == NULL)
return (0L);
@@ -120,31 +120,20 @@ long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a)
else if (i != V_ASN1_ENUMERATED)
return -1;
OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) >= sizeof(long),
long_larger_than_uint64_t);
if (a->length > (int)sizeof(uint64_t)) {
if (a->length > (int)sizeof(long)) {
/* hmm... a bit ugly */
return -1;
return (0xffffffffL);
}
if (a->data == NULL)
return 0;
uint64_t r64 = 0;
if (a->data != NULL) {
for (i = 0; i < a->length; i++) {
r64 <<= 8;
r64 |= (unsigned char)a->data[i];
}
if (r64 > LONG_MAX) {
return -1;
}
for (i = 0; i < a->length; i++) {
r <<= 8;
r |= (unsigned char)a->data[i];
}
long r = (long) r64;
if (neg)
r = -r;
return r;
return (r);
}
ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai)
-3
View File
@@ -81,9 +81,6 @@ int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, void *x)
int i, j = 0, n, ret = 1;
n = i2d(x, NULL);
if (n <= 0)
return 0;
b = (char *)OPENSSL_malloc(n);
if (b == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
+8 -19
View File
@@ -57,7 +57,6 @@
#include <openssl/asn1.h>
#include <string.h>
#include <limits.h>
#include <openssl/err.h>
#include <openssl/mem.h>
@@ -386,6 +385,7 @@ int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
long ASN1_INTEGER_get(const ASN1_INTEGER *a)
{
int neg = 0, i;
long r = 0;
if (a == NULL)
return (0L);
@@ -395,31 +395,20 @@ long ASN1_INTEGER_get(const ASN1_INTEGER *a)
else if (i != V_ASN1_INTEGER)
return -1;
OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) >= sizeof(long),
long_larger_than_uint64_t);
if (a->length > (int)sizeof(uint64_t)) {
if (a->length > (int)sizeof(long)) {
/* hmm... a bit ugly, return all ones */
return -1;
}
if (a->data == NULL)
return 0;
uint64_t r64 = 0;
if (a->data != NULL) {
for (i = 0; i < a->length; i++) {
r64 <<= 8;
r64 |= (unsigned char)a->data[i];
}
if (r64 > LONG_MAX) {
return -1;
}
for (i = 0; i < a->length; i++) {
r <<= 8;
r |= (unsigned char)a->data[i];
}
long r = (long) r64;
if (neg)
r = -r;
return r;
return (r);
}
ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai)
+128
View File
@@ -87,6 +87,134 @@ int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp)
return (objsize);
}
int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
{
int i, first, len = 0, c, use_bn;
char ftmp[24], *tmp = ftmp;
int tmpsize = sizeof ftmp;
const char *p;
unsigned long l;
BIGNUM *bl = NULL;
if (num == 0)
return (0);
else if (num == -1)
num = strlen(buf);
p = buf;
c = *(p++);
num--;
if ((c >= '0') && (c <= '2')) {
first = c - '0';
} else {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_FIRST_NUM_TOO_LARGE);
goto err;
}
if (num <= 0) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_SECOND_NUMBER);
goto err;
}
c = *(p++);
num--;
for (;;) {
if (num <= 0)
break;
if ((c != '.') && (c != ' ')) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_SEPARATOR);
goto err;
}
l = 0;
use_bn = 0;
for (;;) {
if (num <= 0)
break;
num--;
c = *(p++);
if ((c == ' ') || (c == '.'))
break;
if ((c < '0') || (c > '9')) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_DIGIT);
goto err;
}
if (!use_bn && l >= ((ULONG_MAX - 80) / 10L)) {
use_bn = 1;
if (!bl)
bl = BN_new();
if (!bl || !BN_set_word(bl, l))
goto err;
}
if (use_bn) {
if (!BN_mul_word(bl, 10L)
|| !BN_add_word(bl, c - '0'))
goto err;
} else
l = l * 10L + (long)(c - '0');
}
if (len == 0) {
if ((first < 2) && (l >= 40)) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE);
goto err;
}
if (use_bn) {
if (!BN_add_word(bl, first * 40))
goto err;
} else
l += (long)first *40;
}
i = 0;
if (use_bn) {
int blsize;
blsize = BN_num_bits(bl);
blsize = (blsize + 6) / 7;
if (blsize > tmpsize) {
if (tmp != ftmp)
OPENSSL_free(tmp);
tmpsize = blsize + 32;
tmp = OPENSSL_malloc(tmpsize);
if (!tmp)
goto err;
}
while (blsize--) {
BN_ULONG t = BN_div_word(bl, 0x80L);
if (t == (BN_ULONG)-1)
goto err;
tmp[i++] = (unsigned char)t;
}
} else {
for (;;) {
tmp[i++] = (unsigned char)l & 0x7f;
l >>= 7L;
if (l == 0L)
break;
}
}
if (out != NULL) {
if (len + i > olen) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL);
goto err;
}
while (--i > 0)
out[len++] = tmp[i] | 0x80;
out[len++] = tmp[0];
} else
len += i;
}
if (tmp != ftmp)
OPENSSL_free(tmp);
if (bl)
BN_free(bl);
return (len);
err:
if (tmp != ftmp)
OPENSSL_free(tmp);
if (bl)
BN_free(bl);
return (0);
}
int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a)
{
return OBJ_obj2txt(buf, buf_len, a, 0);
-3
View File
@@ -90,9 +90,6 @@ int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
int combine);
#if defined(__cplusplus)
} /* extern C */
+4 -2
View File
@@ -59,7 +59,8 @@
#include <openssl/asn1t.h>
#include <openssl/mem.h>
#include "asn1_locl.h"
static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
int combine);
/* Free up an ASN1 structure */
@@ -73,7 +74,8 @@ void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
asn1_item_combine_free(pval, it, 0);
}
void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine)
static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
int combine)
{
const ASN1_TEMPLATE *tt = NULL, *seqtt;
const ASN1_EXTERN_FUNCS *ef;
+2 -3
View File
@@ -63,7 +63,6 @@
#include <openssl/mem.h>
#include <openssl/obj.h>
#include "asn1_locl.h"
#include "../internal.h"
@@ -202,7 +201,7 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
return 1;
memerr2:
asn1_item_combine_free(pval, it, combine);
ASN1_item_ex_free(pval, it);
memerr:
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
#ifdef CRYPTO_MDEBUG
@@ -212,7 +211,7 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
return 0;
auxerr2:
asn1_item_combine_free(pval, it, combine);
ASN1_item_ex_free(pval, it);
auxerr:
OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR);
#ifdef CRYPTO_MDEBUG
+16
View File
@@ -42,6 +42,22 @@ int BN_parse_asn1_unsigned(CBS *cbs, BIGNUM *ret) {
return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL;
}
int BN_parse_asn1_unsigned_buggy(CBS *cbs, BIGNUM *ret) {
CBS child;
if (!CBS_get_asn1(cbs, &child, CBS_ASN1_INTEGER) ||
CBS_len(&child) == 0) {
OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
return 0;
}
// This function intentionally does not reject negative numbers or non-minimal
// encodings. Estonian IDs issued between September 2014 to September 2015 are
// broken. See https://crbug.com/532048 and https://crbug.com/534766.
//
// TODO(davidben): Remove this code and callers in March 2016.
return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL;
}
int BN_marshal_asn1(CBB *cbb, const BIGNUM *bn) {
// Negative numbers are unsupported.
if (BN_is_negative(bn)) {
-14
View File
@@ -131,20 +131,6 @@ size_t BUF_MEM_grow_clean(BUF_MEM *buf, size_t len) {
return BUF_MEM_grow(buf, len);
}
int BUF_MEM_append(BUF_MEM *buf, const void *in, size_t len) {
size_t new_len = buf->length + len;
if (new_len < len) {
OPENSSL_PUT_ERROR(BUF, ERR_R_OVERFLOW);
return 0;
}
if (!BUF_MEM_reserve(buf, new_len)) {
return 0;
}
OPENSSL_memcpy(buf->data + buf->length, in, len);
buf->length = new_len;
return 1;
}
char *BUF_strdup(const char *str) {
if (str == NULL) {
return NULL;
-97
View File
@@ -1,97 +0,0 @@
/* Copyright (c) 2017, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <openssl/buf.h>
#include <string.h>
#include <string>
#include <gtest/gtest.h>
TEST(BufTest, Basic) {
bssl::UniquePtr<BUF_MEM> buf(BUF_MEM_new());
ASSERT_TRUE(buf);
EXPECT_EQ(0u, buf->length);
// Use BUF_MEM_reserve to increase buf->max.
ASSERT_TRUE(BUF_MEM_reserve(buf.get(), 200));
EXPECT_GE(buf->max, 200u);
EXPECT_EQ(0u, buf->length);
// BUF_MEM_reserve with a smaller cap is a no-op.
size_t old_max = buf->max;
ASSERT_TRUE(BUF_MEM_reserve(buf.get(), 100));
EXPECT_EQ(old_max, buf->max);
EXPECT_EQ(0u, buf->length);
// BUF_MEM_grow can increase the length without reallocating.
ASSERT_EQ(100u, BUF_MEM_grow(buf.get(), 100));
EXPECT_EQ(100u, buf->length);
EXPECT_EQ(old_max, buf->max);
memset(buf->data, 'A', buf->length);
// If BUF_MEM_reserve reallocates, it preserves the contents.
ASSERT_TRUE(BUF_MEM_reserve(buf.get(), old_max + 1));
ASSERT_GE(buf->max, old_max + 1);
EXPECT_EQ(100u, buf->length);
for (size_t i = 0; i < 100; i++) {
EXPECT_EQ('A', buf->data[i]);
}
// BUF_MEM_grow should zero everything beyond buf->length.
memset(buf->data, 'B', buf->max);
ASSERT_EQ(150u, BUF_MEM_grow(buf.get(), 150));
EXPECT_EQ(150u, buf->length);
for (size_t i = 0; i < 100; i++) {
EXPECT_EQ('B', buf->data[i]);
}
for (size_t i = 100; i < 150; i++) {
EXPECT_EQ(0, buf->data[i]);
}
// BUF_MEM_grow can rellocate if necessary.
size_t new_len = buf->max + 1;
ASSERT_EQ(new_len, BUF_MEM_grow(buf.get(), new_len));
EXPECT_GE(buf->max, new_len);
EXPECT_EQ(new_len, buf->length);
for (size_t i = 0; i < 100; i++) {
EXPECT_EQ('B', buf->data[i]);
}
for (size_t i = 100; i < new_len; i++) {
EXPECT_EQ(0, buf->data[i]);
}
// BUF_MEM_grow can shink.
ASSERT_EQ(50u, BUF_MEM_grow(buf.get(), 50));
EXPECT_EQ(50u, buf->length);
for (size_t i = 0; i < 50; i++) {
EXPECT_EQ('B', buf->data[i]);
}
}
TEST(BufTest, Append) {
bssl::UniquePtr<BUF_MEM> buf(BUF_MEM_new());
ASSERT_TRUE(buf);
ASSERT_TRUE(BUF_MEM_append(buf.get(), nullptr, 0));
ASSERT_TRUE(BUF_MEM_append(buf.get(), "hello ", 6));
ASSERT_TRUE(BUF_MEM_append(buf.get(), nullptr, 0));
ASSERT_TRUE(BUF_MEM_append(buf.get(), "world", 5));
std::string str(128, 'A');
ASSERT_TRUE(BUF_MEM_append(buf.get(), str.data(), str.size()));
EXPECT_EQ("hello world" + str, std::string(buf->data, buf->length));
}
-54
View File
@@ -787,57 +787,3 @@ TEST(CBSTest, BitString) {
CBS_asn1_bitstring_has_bit(&cbs, test.bit));
}
}
TEST(CBBTest, AddOIDFromText) {
const struct {
const char *in;
bool ok;
std::vector<uint8_t> out;
} kTests[] = {
// Some valid values.
{"1.2.3.4", true, {0x2a, 0x3, 0x4}},
{"1.2.840.113554.4.1.72585",
true,
{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09}},
// Test edge cases around the first component.
{"0.39", true, {0x27}},
{"0.40", false, {}},
{"1.0", true, {0x28}},
{"1.39", true, {0x4f}},
{"1.40", false, {}},
{"2.0", true, {0x50}},
{"2.1", true, {0x51}},
{"2.40", true, {0x78}},
// The empty string is not an OID.
{"", false, {}},
// No empty components.
{".1.2.3.4.5", false, {}},
{"1..2.3.4.5", false, {}},
{"1.2.3.4.5.", false, {}},
// There must be at least two components.
{"1", false, {}},
// No extra leading zeros.
{"00.1.2.3.4", false, {}},
{"01.1.2.3.4", false, {}},
// Check for overflow.
{"1.2.4294967295", true, {0x2a, 0x8f, 0xff, 0xff, 0xff, 0x7f}},
{"1.2.4294967296", false, {}},
// 40*A + B overflows.
{"2.4294967215", true, {0x8f, 0xff, 0xff, 0xff, 0x7f}},
{"2.4294967216", false, {}},
};
for (const auto &t : kTests) {
SCOPED_TRACE(t.in);
bssl::ScopedCBB cbb;
ASSERT_TRUE(CBB_init(cbb.get(), 0));
int ok = CBB_add_asn1_oid_from_text(cbb.get(), t.in, strlen(t.in));
EXPECT_EQ(t.ok, static_cast<bool>(ok));
if (ok) {
uint8_t *out;
size_t len;
ASSERT_TRUE(CBB_finish(cbb.get(), &out, &len));
bssl::UniquePtr<uint8_t> free_out(out);
EXPECT_EQ(Bytes(t.out), Bytes(out, len));
}
}
}
-93
View File
@@ -15,7 +15,6 @@
#include <openssl/bytestring.h>
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <openssl/mem.h>
@@ -329,32 +328,6 @@ int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) {
return cbb_add_length_prefixed(cbb, out_contents, 3);
}
// add_base128_integer encodes |v| as a big-endian base-128 integer where the
// high bit of each byte indicates where there is more data. This is the
// encoding used in DER for both high tag number form and OID components.
static int add_base128_integer(CBB *cbb, uint32_t v) {
unsigned len_len = 0;
unsigned copy = v;
while (copy > 0) {
len_len++;
copy >>= 7;
}
if (len_len == 0) {
len_len = 1; // Zero is encoded with one byte.
}
for (unsigned i = len_len - 1; i < len_len; i--) {
uint8_t byte = (v >> (7 * i)) & 0x7f;
if (i != 0) {
// The high bit denotes whether there is more data.
byte |= 0x80;
}
if (!CBB_add_u8(cbb, byte)) {
return 0;
}
}
return 1;
}
int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag) {
if (tag > 0xff ||
(tag & 0x1f) == 0x1f) {
@@ -500,69 +473,3 @@ int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) {
return CBB_flush(cbb);
}
// parse_dotted_decimal parses one decimal component from |cbs|, where |cbs| is
// an OID literal, e.g., "1.2.840.113554.4.1.72585". It consumes both the
// component and the dot, so |cbs| may be passed into the function again for the
// next value.
static int parse_dotted_decimal(CBS *cbs, uint32_t *out) {
*out = 0;
int seen_digit = 0;
for (;;) {
// Valid terminators for a component are the end of the string or a
// non-terminal dot. If the string ends with a dot, this is not a valid OID
// string.
uint8_t u;
if (!CBS_get_u8(cbs, &u) ||
(u == '.' && CBS_len(cbs) > 0)) {
break;
}
if (u < '0' || u > '9' ||
// Forbid stray leading zeros.
(seen_digit && *out == 0) ||
// Check for overflow.
*out > UINT32_MAX / 10 ||
*out * 10 > UINT32_MAX - (u - '0')) {
return 0;
}
*out = *out * 10 + (u - '0');
seen_digit = 1;
}
// The empty string is not a legal OID component.
return seen_digit;
}
int CBB_add_asn1_oid_from_text(CBB *cbb, const char *text, size_t len) {
if (!CBB_flush(cbb)) {
return 0;
}
CBS cbs;
CBS_init(&cbs, (const uint8_t *)text, len);
// OIDs must have at least two components.
uint32_t a, b;
if (!parse_dotted_decimal(&cbs, &a) ||
!parse_dotted_decimal(&cbs, &b)) {
return 0;
}
// The first component is encoded as 40 * |a| + |b|. This assumes that |a| is
// 0, 1, or 2 and that, when it is 0 or 1, |b| is at most 39.
if (a > 2 ||
(a < 2 && b > 39) ||
b > UINT32_MAX - 80 ||
!add_base128_integer(cbb, 40 * a + b)) {
return 0;
}
// The remaining components are encoded unmodified.
while (CBS_len(&cbs) > 0) {
if (!parse_dotted_decimal(&cbs, &a) ||
!add_base128_integer(cbb, a)) {
return 0;
}
}
return 1;
}
+2 -2
View File
@@ -791,13 +791,13 @@ int CONF_parse_list(const char *list, char sep, int remove_whitespace,
}
}
int CONF_modules_load_file(const char *filename, const char *appname,
int CONF_modules_load_file(CONF_MUST_BE_NULL *filename, const char *appname,
unsigned long flags) {
return 1;
}
void CONF_modules_free(void) {}
void OPENSSL_config(const char *config_name) {}
void OPENSSL_config(CONF_MUST_BE_NULL *config_name) {}
void OPENSSL_no_config(void) {}
+17 -17
View File
@@ -164,7 +164,7 @@ void OPENSSL_cpuid_setup(void) {
uint32_t num_extended_ids = eax;
if (num_extended_ids >= 0x80000001) {
OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0x80000001);
if (ecx & (1u << 11)) {
if (ecx & (1 << 11)) {
has_amd_xop = 1;
}
}
@@ -193,68 +193,68 @@ void OPENSSL_cpuid_setup(void) {
OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 1);
// Adjust the hyper-threading bit.
if (edx & (1u << 28)) {
if (edx & (1 << 28)) {
uint32_t num_logical_cores = (ebx >> 16) & 0xff;
if (cores_per_cache == 1 || num_logical_cores <= 1) {
edx &= ~(1u << 28);
edx &= ~(1 << 28);
}
}
// Reserved bit #20 was historically repurposed to control the in-memory
// representation of RC4 state. Always set it to zero.
edx &= ~(1u << 20);
edx &= ~(1 << 20);
// Reserved bit #30 is repurposed to signal an Intel CPU.
if (is_intel) {
edx |= (1u << 30);
edx |= (1 << 30);
// Clear the XSAVE bit on Knights Landing to mimic Silvermont. This enables
// some Silvermont-specific codepaths which perform better. See OpenSSL
// commit 64d92d74985ebb3d0be58a9718f9e080a14a8e7f.
if ((eax & 0x0fff0ff0) == 0x00050670 /* Knights Landing */ ||
(eax & 0x0fff0ff0) == 0x00080650 /* Knights Mill (per SDE) */) {
ecx &= ~(1u << 26);
ecx &= ~(1 << 26);
}
} else {
edx &= ~(1u << 30);
edx &= ~(1 << 30);
}
// The SDBG bit is repurposed to denote AMD XOP support.
if (has_amd_xop) {
ecx |= (1u << 11);
ecx |= (1 << 11);
} else {
ecx &= ~(1u << 11);
ecx &= ~(1 << 11);
}
uint64_t xcr0 = 0;
if (ecx & (1u << 27)) {
if (ecx & (1 << 27)) {
// XCR0 may only be queried if the OSXSAVE bit is set.
xcr0 = OPENSSL_xgetbv(0);
}
// See Intel manual, volume 1, section 14.3.
if ((xcr0 & 6) != 6) {
// YMM registers cannot be used.
ecx &= ~(1u << 28); // AVX
ecx &= ~(1u << 12); // FMA
ecx &= ~(1u << 11); // AMD XOP
ecx &= ~(1 << 28); // AVX
ecx &= ~(1 << 12); // FMA
ecx &= ~(1 << 11); // AMD XOP
// Clear AVX2 and AVX512* bits.
//
// TODO(davidben): Should bits 17 and 26-28 also be cleared? Upstream
// doesn't clear those.
extended_features &=
~((1u << 5) | (1u << 16) | (1u << 21) | (1u << 30) | (1u << 31));
~((1 << 5) | (1 << 16) | (1 << 21) | (1 << 30) | (1 << 31));
}
// See Intel manual, volume 1, section 15.2.
if ((xcr0 & 0xe6) != 0xe6) {
// Clear AVX512F. Note we don't touch other AVX512 extensions because they
// can be used with YMM.
extended_features &= ~(1u << 16);
extended_features &= ~(1 << 16);
}
// Disable ADX instructions on Knights Landing. See OpenSSL commit
// 64d92d74985ebb3d0be58a9718f9e080a14a8e7f.
if ((ecx & (1u << 26)) == 0) {
extended_features &= ~(1u << 19);
if ((ecx & (1 << 26)) == 0) {
extended_features &= ~(1 << 19);
}
OPENSSL_ia32cap_P[0] = edx;
+4 -16
View File
@@ -40,18 +40,6 @@
OPENSSL_ARM || OPENSSL_AARCH64) */
// Our assembly does not use the GOT to reference symbols, which means
// references to visible symbols will often require a TEXTREL. This is
// undesirable, so all assembly-referenced symbols should be hidden. CPU
// capabilities are the only such symbols defined in C. Explicitly hide them,
// rather than rely on being built with -fvisibility=hidden.
#if defined(OPENSSL_WINDOWS)
#define HIDDEN
#else
#define HIDDEN __attribute__((visibility("hidden")))
#endif
// The capability variables are defined in this file in order to work around a
// linker bug. When linking with a .a, if no symbols in a .o are referenced
// then the .o is discarded, even if it has constructor functions.
@@ -69,11 +57,11 @@
// archive, linking on OS X will fail to resolve common symbols. By
// initialising it to zero, it becomes a "data symbol", which isn't so
// affected.
HIDDEN uint32_t OPENSSL_ia32cap_P[4] = {0};
uint32_t OPENSSL_ia32cap_P[4] = {0};
#elif defined(OPENSSL_PPC64LE)
HIDDEN unsigned long OPENSSL_ppc64le_hwcap2 = 0;
unsigned long OPENSSL_ppc64le_hwcap2 = 0;
#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
@@ -81,7 +69,7 @@ HIDDEN unsigned long OPENSSL_ppc64le_hwcap2 = 0;
#if defined(OPENSSL_STATIC_ARMCAP)
HIDDEN uint32_t OPENSSL_armcap_P =
uint32_t OPENSSL_armcap_P =
#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__)
ARMV7_NEON |
#endif
@@ -100,7 +88,7 @@ HIDDEN uint32_t OPENSSL_armcap_P =
0;
#else
HIDDEN uint32_t OPENSSL_armcap_P = 0;
uint32_t OPENSSL_armcap_P = 0;
#endif
#endif
+1
View File
@@ -21,6 +21,7 @@ add_library(
OBJECT
curve25519.c
spake25519.c
x25519-x86_64.c
File diff suppressed because it is too large Load Diff
@@ -1,24 +1,16 @@
// The MIT License (MIT)
//
// Copyright (c) 2015-2016 the fiat-crypto authors (see the AUTHORS file).
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
/* Copyright (c) 2015, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#ifndef OPENSSL_HEADER_CURVE25519_INTERNAL_H
#define OPENSSL_HEADER_CURVE25519_INTERNAL_H
@@ -47,14 +39,9 @@ void x25519_NEON(uint8_t out[32], const uint8_t scalar[32],
// fe means field element. Here the field is \Z/(2^255-19). An element t,
// entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
// t[3]+2^102 t[4]+...+2^230 t[9].
// fe limbs are bounded by 1.125*2^26,1.125*2^25,1.125*2^26,1.125*2^25,etc.
// Multiplication and carrying produce fe from fe_loose.
typedef struct fe { uint32_t v[10]; } fe;
// fe_loose limbs are bounded by 3.375*2^26,3.375*2^25,3.375*2^26,3.375*2^25,etc.
// Addition and subtraction produce fe_loose from (fe, fe).
typedef struct fe_loose { uint32_t v[10]; } fe_loose;
// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
// context.
typedef int32_t fe[10];
/* ge means group element.
@@ -82,23 +69,23 @@ typedef struct {
} ge_p3;
typedef struct {
fe_loose X;
fe_loose Y;
fe_loose Z;
fe_loose T;
fe X;
fe Y;
fe Z;
fe T;
} ge_p1p1;
typedef struct {
fe_loose yplusx;
fe_loose yminusx;
fe_loose xy2d;
fe yplusx;
fe yminusx;
fe xy2d;
} ge_precomp;
typedef struct {
fe_loose YplusX;
fe_loose YminusX;
fe_loose Z;
fe_loose T2d;
fe YplusX;
fe YminusX;
fe Z;
fe T2d;
} ge_cached;
void x25519_ge_tobytes(uint8_t *s, const ge_p2 *h);
+11 -11
View File
@@ -22,8 +22,8 @@
#include <openssl/rand.h>
#include <openssl/sha.h>
#include "internal.h"
#include "../internal.h"
#include "../../third_party/fiat/internal.h"
// The following precomputation tables are for the following
@@ -44,14 +44,14 @@
// see curve25519.c in this directory.
//
// Exact copies of the source code are kept in bug 27296743.
//
// import hashlib
// import ed25519 as E # http://ed25519.cr.yp.to/python/ed25519.py
//
// SEED_N = 'edwards25519 point generation seed (N)'
// SEED_M = 'edwards25519 point generation seed (M)'
/*
import hashlib
import ed25519 as E # http://ed25519.cr.yp.to/python/ed25519.py
SEED_N = 'edwards25519 point generation seed (N)'
SEED_M = 'edwards25519 point generation seed (M)'
def genpoint(seed):
v = hashlib.sha256(seed).digest()
it = 1
@@ -73,10 +73,10 @@ def genpoint(seed):
def gentable(P):
t = []
for i in range(1,16):
k = ((i >> 3 & 1) * (1 << 192) +
(i >> 2 & 1) * (1 << 128) +
(i >> 1 & 1) * (1 << 64) +
(i & 1))
k = (i >> 3 & 1) * (1 << 192) + \
(i >> 2 & 1) * (1 << 128) + \
(i >> 1 & 1) * (1 << 64) + \
(i & 1)
t.append(E.scalarmult(P, k))
return ''.join(E.encodeint(x) + E.encodeint(y) for (x,y) in t)
+1 -1
View File
@@ -23,7 +23,7 @@
#include <gtest/gtest.h>
#include "../internal.h"
#include "../../third_party/fiat/internal.h"
#include "internal.h"
// TODO(agl): add tests with fixed vectors once SPAKE2 is nailed down.
+1 -1
View File
@@ -24,7 +24,7 @@
#include <string.h>
#include "../internal.h"
#include "../../third_party/fiat/internal.h"
#include "internal.h"
#if defined(BORINGSSL_X25519_X86_64)
-19
View File
@@ -105,22 +105,3 @@ TEST(X25519Test, Iterated) {
EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
}
TEST(X25519Test, DISABLED_IteratedLarge) {
// Taken from https://tools.ietf.org/html/rfc7748#section-5.2.
uint8_t scalar[32] = {9}, point[32] = {9}, out[32];
for (unsigned i = 0; i < 1000000; i++) {
EXPECT_TRUE(X25519(out, scalar, point));
OPENSSL_memcpy(point, scalar, sizeof(point));
OPENSSL_memcpy(scalar, out, sizeof(scalar));
}
static const uint8_t kExpected[32] = {
0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97,
0x29, 0x7e, 0x57, 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c,
0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24,
};
EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
}
+21 -9
View File
@@ -82,9 +82,6 @@
// Rabin-Miller
#define DSS_prime_checks 50
static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
BIGNUM **out_r);
static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT;
DSA *DSA_new(void) {
@@ -120,6 +117,8 @@ void DSA_free(DSA *dsa) {
BN_clear_free(dsa->g);
BN_clear_free(dsa->pub_key);
BN_clear_free(dsa->priv_key);
BN_clear_free(dsa->kinv);
BN_clear_free(dsa->r);
BN_MONT_CTX_free(dsa->method_mont_p);
BN_MONT_CTX_free(dsa->method_mont_q);
CRYPTO_MUTEX_cleanup(&dsa->method_mont_lock);
@@ -545,13 +544,14 @@ void DSA_SIG_free(DSA_SIG *sig) {
OPENSSL_free(sig);
}
DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, const DSA *dsa) {
DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, DSA *dsa) {
BIGNUM *kinv = NULL, *r = NULL, *s = NULL;
BIGNUM m;
BIGNUM xr;
BN_CTX *ctx = NULL;
int reason = ERR_R_BN_LIB;
DSA_SIG *ret = NULL;
int noredo = 0;
BN_init(&m);
BN_init(&xr);
@@ -571,8 +571,16 @@ DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, const DSA *dsa) {
}
redo:
if (!dsa_sign_setup(dsa, ctx, &kinv, &r)) {
goto err;
if (dsa->kinv == NULL || dsa->r == NULL) {
if (!DSA_sign_setup(dsa, ctx, &kinv, &r)) {
goto err;
}
} else {
kinv = dsa->kinv;
dsa->kinv = NULL;
r = dsa->r;
dsa->r = NULL;
noredo = 1;
}
if (digest_len > BN_num_bytes(dsa->q)) {
@@ -605,6 +613,10 @@ redo:
// Redo if r or s is zero as required by FIPS 186-3: this is
// very unlikely.
if (BN_is_zero(r) || BN_is_zero(s)) {
if (noredo) {
reason = DSA_R_NEED_NEW_SETUP_VALUES;
goto err;
}
goto redo;
}
ret = DSA_SIG_new();
@@ -746,7 +758,7 @@ err:
}
int DSA_sign(int type, const uint8_t *digest, size_t digest_len,
uint8_t *out_sig, unsigned int *out_siglen, const DSA *dsa) {
uint8_t *out_sig, unsigned int *out_siglen, DSA *dsa) {
DSA_SIG *s;
s = DSA_do_sign(digest, digest_len, dsa);
@@ -836,8 +848,8 @@ int DSA_size(const DSA *dsa) {
return ret;
}
static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
BIGNUM **out_r) {
int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
BIGNUM **out_r) {
BN_CTX *ctx;
BIGNUM k, kq, *kinv = NULL, *r = NULL;
int ret = 0;
+2 -2
View File
@@ -67,9 +67,9 @@
#include "../internal.h"
static const unsigned kParametersTag =
static const uint8_t kParametersTag =
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0;
static const unsigned kPublicKeyTag =
static const uint8_t kPublicKeyTag =
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
-97
View File
@@ -14,7 +14,6 @@
#include <stdio.h>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
@@ -24,7 +23,6 @@
#include <openssl/ec.h>
#include <openssl/ec_key.h>
#include <openssl/ecdh.h>
#include <openssl/err.h>
#include <openssl/nid.h>
#include "../test/file_test.h"
@@ -114,98 +112,3 @@ TEST(ECDHTest, TestVectors) {
Bytes(actual_z.data(), static_cast<size_t>(ret)));
});
}
// MakeCustomGroup returns an |EC_GROUP| containing a non-standard group. (P-256
// with the wrong generator.)
static bssl::UniquePtr<EC_GROUP> MakeCustomGroup() {
static const uint8_t kP[] = {
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const uint8_t kA[] = {
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
};
static const uint8_t kB[] = {
0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd,
0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b,
};
static const uint8_t kX[] = {
0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e,
0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d,
0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a,
};
static const uint8_t kY[] = {
0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3,
0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5,
0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1,
};
static const uint8_t kOrder[] = {
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
};
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
bssl::UniquePtr<BIGNUM> x(BN_bin2bn(kX, sizeof(kX), nullptr));
bssl::UniquePtr<BIGNUM> y(BN_bin2bn(kY, sizeof(kY), nullptr));
bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
if (!ctx || !p || !a || !b || !x || !y || !order) {
return nullptr;
}
bssl::UniquePtr<EC_GROUP> group(
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
if (!group) {
return nullptr;
}
bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
if (!generator ||
!EC_POINT_set_affine_coordinates_GFp(group.get(), generator.get(),
x.get(), y.get(), ctx.get()) ||
!EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
BN_value_one())) {
return nullptr;
}
return group;
}
TEST(ECDHTest, GroupMismatch) {
const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
std::vector<EC_builtin_curve> curves(num_curves);
EC_get_builtin_curves(curves.data(), num_curves);
// Instantiate all the built-in curves.
std::vector<bssl::UniquePtr<EC_GROUP>> groups;
for (const auto &curve : curves) {
groups.emplace_back(EC_GROUP_new_by_curve_name(curve.nid));
ASSERT_TRUE(groups.back());
}
// Also create some arbitrary group. (This is P-256 with the wrong generator.)
groups.push_back(MakeCustomGroup());
ASSERT_TRUE(groups.back());
for (const auto &a : groups) {
for (const auto &b : groups) {
if (a.get() == b.get()) {
continue;
}
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
ASSERT_TRUE(EC_KEY_set_group(key.get(), a.get()));
ASSERT_TRUE(EC_KEY_generate_key(key.get()));
// ECDH across the groups should not work.
char out[64];
const EC_POINT *peer = EC_GROUP_get0_generator(b.get());
EXPECT_EQ(-1,
ECDH_compute_key(out, sizeof(out), peer, key.get(), nullptr));
ERR_clear_error();
}
}
}
+8 -1
View File
@@ -73,6 +73,13 @@ int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig,
(EC_KEY*) eckey /* cast away const */);
}
return ECDSA_sign_ex(type, digest, digest_len, sig, sig_len, NULL, NULL,
eckey);
}
int ECDSA_sign_ex(int type, const uint8_t *digest, size_t digest_len,
uint8_t *sig, unsigned int *sig_len, const BIGNUM *kinv,
const BIGNUM *r, const EC_KEY *eckey) {
int ret = 0;
ECDSA_SIG *s = NULL;
@@ -82,7 +89,7 @@ int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig,
goto err;
}
s = ECDSA_do_sign(digest, digest_len, eckey);
s = ECDSA_do_sign_ex(digest, digest_len, kinv, r, eckey);
if (s == NULL) {
*sig_len = 0;
goto err;
-1
View File
@@ -17,7 +17,6 @@ EC,110,INVALID_FIELD
EC,111,INVALID_FORM
EC,112,INVALID_GROUP_ORDER
EC,113,INVALID_PRIVATE_KEY
EC,133,INVALID_SCALAR
EC,114,MISSING_PARAMETERS
EC,115,MISSING_PRIVATE_KEY
EC,116,NON_NAMED_CURVE
-1
View File
@@ -1,2 +1 @@
OBJ,101,INVALID_OID_STRING
OBJ,100,UNKNOWN_NID
-1
View File
@@ -53,7 +53,6 @@ SSL,143,DTLS_MESSAGE_TOO_BIG
SSL,257,DUPLICATE_EXTENSION
SSL,264,DUPLICATE_KEY_SHARE
SSL,144,ECC_CERT_NOT_FOR_SIGNING
SSL,282,EMPTY_HELLO_RETRY_REQUEST
SSL,145,EMS_STATE_INCONSISTENT
SSL,146,ENCRYPTED_LENGTH_TOO_LONG
SSL,147,ERROR_ADDING_EXTENSION
+23 -2
View File
@@ -63,9 +63,19 @@
#include <openssl/rsa.h>
#include "../fipsmodule/rsa/internal.h"
#include "../internal.h"
#include "internal.h"
static struct CRYPTO_STATIC_MUTEX g_buggy_lock = CRYPTO_STATIC_MUTEX_INIT;
static int g_buggy = 0;
void EVP_set_buggy_rsa_parser(int buggy) {
CRYPTO_STATIC_MUTEX_lock_write(&g_buggy_lock);
g_buggy = buggy;
CRYPTO_STATIC_MUTEX_unlock_write(&g_buggy_lock);
}
static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) {
// See RFC 3279, section 2.3.1.
CBB spki, algorithm, oid, null, key_bitstring;
@@ -86,6 +96,11 @@ static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) {
}
static int rsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
int buggy;
CRYPTO_STATIC_MUTEX_lock_read(&g_buggy_lock);
buggy = g_buggy;
CRYPTO_STATIC_MUTEX_unlock_read(&g_buggy_lock);
// See RFC 3279, section 2.3.1.
// The parameters must be NULL.
@@ -97,7 +112,13 @@ static int rsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
return 0;
}
RSA *rsa = RSA_parse_public_key(key);
// Estonian IDs issued between September 2014 to September 2015 are
// broken. See https://crbug.com/532048 and https://crbug.com/534766.
//
// TODO(davidben): Switch this to the strict version in March 2016 or when
// Chromium can force client certificates down a different codepath, whichever
// comes first.
RSA *rsa = buggy ? RSA_parse_public_key_buggy(key) : RSA_parse_public_key(key);
if (rsa == NULL || CBS_len(key) != 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
RSA_free(rsa);
@@ -161,7 +182,7 @@ static int int_rsa_size(const EVP_PKEY *pkey) {
}
static int rsa_bits(const EVP_PKEY *pkey) {
return RSA_bits(pkey->pkey.rsa);
return BN_num_bits(pkey->pkey.rsa->n);
}
static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); }
+1
View File
@@ -113,6 +113,7 @@
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
#include <openssl/stack.h>
#include <openssl/thread.h>
+3 -3
View File
@@ -200,7 +200,7 @@ asm_AES_encrypt:
#ifndef __thumb2__
sub r3,pc,#8 @ asm_AES_encrypt
#else
adr r3,.
adr r3,asm_AES_encrypt
#endif
stmdb sp!,{r1,r4-r12,lr}
#ifdef __APPLE__
@@ -450,7 +450,7 @@ _armv4_AES_set_encrypt_key:
#ifndef __thumb2__
sub r3,pc,#8 @ asm_AES_set_encrypt_key
#else
adr r3,.
adr r3,asm_AES_set_encrypt_key
#endif
teq r0,#0
#ifdef __thumb2__
@@ -976,7 +976,7 @@ asm_AES_decrypt:
#ifndef __thumb2__
sub r3,pc,#8 @ asm_AES_decrypt
#else
adr r3,.
adr r3,asm_AES_decrypt
#endif
stmdb sp!,{r1,r4-r12,lr}
#ifdef __APPLE__
+3 -3
View File
@@ -744,7 +744,7 @@ $code.=<<___;
.type _bsaes_decrypt8,%function
.align 4
_bsaes_decrypt8:
adr $const,.
adr $const,_bsaes_decrypt8
vldmia $key!, {@XMM[9]} @ round 0 key
#ifdef __APPLE__
adr $const,.LM0ISR
@@ -843,7 +843,7 @@ _bsaes_const:
.type _bsaes_encrypt8,%function
.align 4
_bsaes_encrypt8:
adr $const,.
adr $const,_bsaes_encrypt8
vldmia $key!, {@XMM[9]} @ round 0 key
#ifdef __APPLE__
adr $const,.LM0SR
@@ -951,7 +951,7 @@ $code.=<<___;
.type _bsaes_key_convert,%function
.align 4
_bsaes_key_convert:
adr $const,.
adr $const,_bsaes_key_convert
vld1.8 {@XMM[7]}, [$inp]! @ load round 0 key
#ifdef __APPLE__
adr $const,.LM0
+11 -7
View File
@@ -133,7 +133,7 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
while (dif) {
dif--;
t1 = *(ap++);
t2 = t1 + 1;
t2 = (t1 + 1) & BN_MASK2;
*(rp++) = t2;
if (t2) {
carry = 0;
@@ -162,6 +162,8 @@ int BN_add_word(BIGNUM *a, BN_ULONG w) {
BN_ULONG l;
int i;
w &= BN_MASK2;
// degenerate case: w is zero
if (!w) {
return 1;
@@ -183,7 +185,7 @@ int BN_add_word(BIGNUM *a, BN_ULONG w) {
}
for (i = 0; w != 0 && i < a->top; i++) {
a->d[i] = l = a->d[i] + w;
a->d[i] = l = (a->d[i] + w) & BN_MASK2;
w = (w > l) ? 1 : 0;
}
@@ -283,12 +285,12 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
t2 = *(bp++);
if (carry) {
carry = (t1 <= t2);
t1 -= t2 + 1;
t1 = (t1 - t2 - 1) & BN_MASK2;
} else {
carry = (t1 < t2);
t1 -= t2;
t1 = (t1 - t2) & BN_MASK2;
}
*(rp++) = t1;
*(rp++) = t1 & BN_MASK2;
}
if (carry) // subtracted
@@ -301,7 +303,7 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
while (dif) {
dif--;
t1 = *(ap++);
t2 = t1 - 1;
t2 = (t1 - 1) & BN_MASK2;
*(rp++) = t2;
if (t1) {
break;
@@ -323,6 +325,8 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
int BN_sub_word(BIGNUM *a, BN_ULONG w) {
int i;
w &= BN_MASK2;
// degenerate case: w is zero
if (!w) {
return 1;
@@ -357,7 +361,7 @@ int BN_sub_word(BIGNUM *a, BN_ULONG w) {
a->d[i] -= w;
break;
} else {
a->d[i] -= w;
a->d[i] = (a->d[i] - w) & BN_MASK2;
i++;
w = 1;
}
+16 -19
View File
@@ -93,11 +93,11 @@
#undef sqr
#define sqr(r0, r1, a) __asm__("mulq %2" : "=a"(r0), "=d"(r1) : "a"(a) : "cc");
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
BN_ULONG w) {
BN_ULONG c1 = 0;
if (num == 0) {
if (num <= 0) {
return (c1);
}
@@ -126,11 +126,10 @@ BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
return c1;
}
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
BN_ULONG w) {
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) {
BN_ULONG c1 = 0;
if (num == 0) {
if (num <= 0) {
return c1;
}
@@ -157,8 +156,8 @@ BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
return c1;
}
void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, size_t n) {
if (n == 0) {
void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
if (n <= 0) {
return;
}
@@ -185,11 +184,11 @@ void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, size_t n) {
}
BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
size_t n) {
int n) {
BN_ULONG ret;
size_t i = 0;
if (n == 0) {
if (n <= 0) {
return 0;
}
@@ -202,8 +201,7 @@ BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
" adcq (%5,%2,8),%0 \n"
" movq %0,(%3,%2,8) \n"
" lea 1(%2),%2 \n"
" dec %1 \n"
" jnz 1b \n"
" loop 1b \n"
" sbbq %0,%0 \n"
: "=&r"(ret), "+c"(n), "+r"(i)
: "r"(rp), "r"(ap), "r"(bp)
@@ -213,11 +211,11 @@ BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
}
BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
size_t n) {
int n) {
BN_ULONG ret;
size_t i = 0;
if (n == 0) {
if (n <= 0) {
return 0;
}
@@ -230,8 +228,7 @@ BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
" sbbq (%5,%2,8),%0 \n"
" movq %0,(%3,%2,8) \n"
" lea 1(%2),%2 \n"
" dec %1 \n"
" jnz 1b \n"
" loop 1b \n"
" sbbq %0,%0 \n"
: "=&r"(ret), "+c"(n), "+r"(i)
: "r"(rp), "r"(ap), "r"(bp)
@@ -283,7 +280,7 @@ BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2)
void bn_mul_comba8(BN_ULONG r[16], const BN_ULONG a[8], const BN_ULONG b[8]) {
void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
BN_ULONG c1, c2, c3;
c1 = 0;
@@ -385,7 +382,7 @@ void bn_mul_comba8(BN_ULONG r[16], const BN_ULONG a[8], const BN_ULONG b[8]) {
r[15] = c1;
}
void bn_mul_comba4(BN_ULONG r[8], const BN_ULONG a[4], const BN_ULONG b[4]) {
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
BN_ULONG c1, c2, c3;
c1 = 0;
@@ -423,7 +420,7 @@ void bn_mul_comba4(BN_ULONG r[8], const BN_ULONG a[4], const BN_ULONG b[4]) {
r[7] = c2;
}
void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[8]) {
void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
BN_ULONG c1, c2, c3;
c1 = 0;
@@ -497,7 +494,7 @@ void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[8]) {
r[15] = c1;
}
void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]) {
void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
BN_ULONG c1, c2, c3;
c1 = 0;
+2 -10
View File
@@ -3190,19 +3190,11 @@ $code.=<<___;
.align 32
.Lsqrx8x_break:
xor $zero,$zero
sub 16+8(%rsp),%rbx # mov 16(%rsp),%cf
adcx $zero,%r8
sub 16+8(%rsp),%r8 # consume last carry
mov 24+8(%rsp),$carry # initial $tptr, borrow $carry
adcx $zero,%r9
mov 0*8($aptr),%rdx # a[8], modulo-scheduled
adc \$0,%r10
xor %ebp,%ebp # xor $zero,$zero
mov %r8,0*8($tptr)
adc \$0,%r11
adc \$0,%r12
adc \$0,%r13
adc \$0,%r14
adc \$0,%r15
cmp $carry,$tptr # cf=0, of=0
je .Lsqrx8x_outer_loop
+68 -258
View File
@@ -93,7 +93,6 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "./internal.h"
#include "../../internal.h"
#include "../../test/file_test.h"
#include "../../test/test_util.h"
@@ -357,11 +356,9 @@ static void TestSquare(FileTest *t, BN_CTX *ctx) {
ASSERT_TRUE(BN_mul(ret.get(), a.get(), a.get(), ctx));
EXPECT_BIGNUMS_EQUAL("A * A", square.get(), ret.get());
if (!BN_is_zero(a.get())) {
ASSERT_TRUE(BN_div(ret.get(), remainder.get(), square.get(), a.get(), ctx));
EXPECT_BIGNUMS_EQUAL("Square / A", a.get(), ret.get());
EXPECT_BIGNUMS_EQUAL("Square % A", zero.get(), remainder.get());
}
ASSERT_TRUE(BN_div(ret.get(), remainder.get(), square.get(), a.get(), ctx));
EXPECT_BIGNUMS_EQUAL("Square / A", a.get(), ret.get());
EXPECT_BIGNUMS_EQUAL("Square % A", zero.get(), remainder.get());
BN_set_negative(a.get(), 0);
ASSERT_TRUE(BN_sqrt(ret.get(), square.get(), ctx));
@@ -384,31 +381,6 @@ static void TestSquare(FileTest *t, BN_CTX *ctx) {
<< "BN_sqrt succeeded on a non-square";
ERR_clear_error();
}
#if !defined(BORINGSSL_SHARED_LIBRARY)
if (static_cast<size_t>(a->top) <= BN_SMALL_MAX_WORDS) {
for (size_t num_a = a->top; num_a <= BN_SMALL_MAX_WORDS; num_a++) {
SCOPED_TRACE(num_a);
size_t num_r = 2 * num_a;
// Use newly-allocated buffers so ASan will catch out-of-bounds writes.
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[num_a]),
r_words(new BN_ULONG[num_r]);
OPENSSL_memset(a_words.get(), 0, num_a * sizeof(BN_ULONG));
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_mul_small(r_words.get(), num_r, a_words.get(), num_a,
a_words.get(), num_a));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), num_r));
EXPECT_BIGNUMS_EQUAL("A * A (words)", square.get(), ret.get());
OPENSSL_memset(r_words.get(), 'A', num_r * sizeof(BN_ULONG));
ASSERT_TRUE(bn_sqr_small(r_words.get(), num_r, a_words.get(), num_a));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), num_r));
EXPECT_BIGNUMS_EQUAL("A^2 (words)", square.get(), ret.get());
}
}
#endif
}
static void TestProduct(FileTest *t, BN_CTX *ctx) {
@@ -429,46 +401,13 @@ static void TestProduct(FileTest *t, BN_CTX *ctx) {
ASSERT_TRUE(BN_mul(ret.get(), a.get(), b.get(), ctx));
EXPECT_BIGNUMS_EQUAL("A * B", product.get(), ret.get());
if (!BN_is_zero(a.get())) {
ASSERT_TRUE(
BN_div(ret.get(), remainder.get(), product.get(), a.get(), ctx));
EXPECT_BIGNUMS_EQUAL("Product / A", b.get(), ret.get());
EXPECT_BIGNUMS_EQUAL("Product % A", zero.get(), remainder.get());
}
ASSERT_TRUE(BN_div(ret.get(), remainder.get(), product.get(), a.get(), ctx));
EXPECT_BIGNUMS_EQUAL("Product / A", b.get(), ret.get());
EXPECT_BIGNUMS_EQUAL("Product % A", zero.get(), remainder.get());
if (!BN_is_zero(b.get())) {
ASSERT_TRUE(
BN_div(ret.get(), remainder.get(), product.get(), b.get(), ctx));
EXPECT_BIGNUMS_EQUAL("Product / B", a.get(), ret.get());
EXPECT_BIGNUMS_EQUAL("Product % B", zero.get(), remainder.get());
}
#if !defined(BORINGSSL_SHARED_LIBRARY)
if (!BN_is_negative(product.get()) &&
static_cast<size_t>(a->top) <= BN_SMALL_MAX_WORDS &&
static_cast<size_t>(b->top) <= BN_SMALL_MAX_WORDS) {
for (size_t num_a = a->top; num_a <= BN_SMALL_MAX_WORDS; num_a++) {
SCOPED_TRACE(num_a);
for (size_t num_b = b->top; num_b <= BN_SMALL_MAX_WORDS; num_b++) {
SCOPED_TRACE(num_b);
size_t num_r = num_a + num_b;
// Use newly-allocated buffers so ASan will catch out-of-bounds writes.
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[num_a]),
b_words(new BN_ULONG[num_b]), r_words(new BN_ULONG[num_r]);
OPENSSL_memset(a_words.get(), 0, num_a * sizeof(BN_ULONG));
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
OPENSSL_memset(b_words.get(), 0, num_b * sizeof(BN_ULONG));
OPENSSL_memcpy(b_words.get(), b->d, b->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_mul_small(r_words.get(), num_r, a_words.get(), num_a,
b_words.get(), num_b));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), num_r));
EXPECT_BIGNUMS_EQUAL("A * B (words)", product.get(), ret.get());
}
}
}
#endif
ASSERT_TRUE(BN_div(ret.get(), remainder.get(), product.get(), b.get(), ctx));
EXPECT_BIGNUMS_EQUAL("Product / B", a.get(), ret.get());
EXPECT_BIGNUMS_EQUAL("Product % B", zero.get(), remainder.get());
}
static void TestQuotient(FileTest *t, BN_CTX *ctx) {
@@ -542,39 +481,15 @@ static void TestModMul(FileTest *t, BN_CTX *ctx) {
ASSERT_TRUE(a_tmp);
ASSERT_TRUE(b_tmp);
ASSERT_TRUE(BN_MONT_CTX_set(mont.get(), m.get(), ctx));
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
ASSERT_TRUE(BN_nnmod(b.get(), b.get(), m.get(), ctx));
ASSERT_TRUE(BN_to_montgomery(a_tmp.get(), a.get(), mont.get(), ctx));
ASSERT_TRUE(BN_to_montgomery(b_tmp.get(), b.get(), mont.get(), ctx));
ASSERT_TRUE(BN_nnmod(a_tmp.get(), a.get(), m.get(), ctx));
ASSERT_TRUE(BN_nnmod(b_tmp.get(), b.get(), m.get(), ctx));
ASSERT_TRUE(BN_to_montgomery(a_tmp.get(), a_tmp.get(), mont.get(), ctx));
ASSERT_TRUE(BN_to_montgomery(b_tmp.get(), b_tmp.get(), mont.get(), ctx));
ASSERT_TRUE(BN_mod_mul_montgomery(ret.get(), a_tmp.get(), b_tmp.get(),
mont.get(), ctx));
ASSERT_TRUE(BN_from_montgomery(ret.get(), ret.get(), mont.get(), ctx));
EXPECT_BIGNUMS_EQUAL("A * B (mod M) (Montgomery)", mod_mul.get(),
ret.get());
#if !defined(BORINGSSL_SHARED_LIBRARY)
if (m->top <= BN_SMALL_MAX_WORDS) {
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[m->top]),
b_words(new BN_ULONG[m->top]), r_words(new BN_ULONG[m->top]);
OPENSSL_memset(a_words.get(), 0, m->top * sizeof(BN_ULONG));
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
OPENSSL_memset(b_words.get(), 0, m->top * sizeof(BN_ULONG));
OPENSSL_memcpy(b_words.get(), b->d, b->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m->top, a_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_to_montgomery_small(b_words.get(), m->top, b_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_mod_mul_montgomery_small(
r_words.get(), m->top, a_words.get(), m->top, b_words.get(), m->top,
mont.get()));
// Use the second half of |tmp| so ASan will catch out-of-bounds writes.
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
EXPECT_BIGNUMS_EQUAL("A * B (mod M) (Montgomery, words)", mod_mul.get(),
ret.get());
}
#endif
}
}
@@ -605,8 +520,8 @@ static void TestModSquare(FileTest *t, BN_CTX *ctx) {
ASSERT_TRUE(mont);
ASSERT_TRUE(a_tmp);
ASSERT_TRUE(BN_MONT_CTX_set(mont.get(), m.get(), ctx));
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
ASSERT_TRUE(BN_to_montgomery(a_tmp.get(), a.get(), mont.get(), ctx));
ASSERT_TRUE(BN_nnmod(a_tmp.get(), a.get(), m.get(), ctx));
ASSERT_TRUE(BN_to_montgomery(a_tmp.get(), a_tmp.get(), mont.get(), ctx));
ASSERT_TRUE(BN_mod_mul_montgomery(ret.get(), a_tmp.get(), a_tmp.get(),
mont.get(), ctx));
ASSERT_TRUE(BN_from_montgomery(ret.get(), ret.get(), mont.get(), ctx));
@@ -620,38 +535,6 @@ static void TestModSquare(FileTest *t, BN_CTX *ctx) {
ASSERT_TRUE(BN_from_montgomery(ret.get(), ret.get(), mont.get(), ctx));
EXPECT_BIGNUMS_EQUAL("A * A_copy (mod M) (Montgomery)", mod_square.get(),
ret.get());
#if !defined(BORINGSSL_SHARED_LIBRARY)
if (m->top <= BN_SMALL_MAX_WORDS) {
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[m->top]),
a_copy_words(new BN_ULONG[m->top]), r_words(new BN_ULONG[m->top]);
OPENSSL_memset(a_words.get(), 0, m->top * sizeof(BN_ULONG));
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m->top, a_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_mod_mul_montgomery_small(
r_words.get(), m->top, a_words.get(), m->top, a_words.get(), m->top,
mont.get()));
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
EXPECT_BIGNUMS_EQUAL("A * A (mod M) (Montgomery, words)",
mod_square.get(), ret.get());
// Repeat the operation with |a_copy_words|.
OPENSSL_memcpy(a_copy_words.get(), a_words.get(),
m->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_mod_mul_montgomery_small(
r_words.get(), m->top, a_words.get(), m->top, a_copy_words.get(),
m->top, mont.get()));
// Use the second half of |tmp| so ASan will catch out-of-bounds writes.
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
EXPECT_BIGNUMS_EQUAL("A * A_copy (mod M) (Montgomery, words)",
mod_square.get(), ret.get());
}
#endif
}
}
@@ -680,28 +563,6 @@ static void TestModExp(FileTest *t, BN_CTX *ctx) {
ctx, NULL));
EXPECT_BIGNUMS_EQUAL("A ^ E (mod M) (constant-time)", mod_exp.get(),
ret.get());
#if !defined(BORINGSSL_SHARED_LIBRARY)
if (m->top <= BN_SMALL_MAX_WORDS) {
bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new());
ASSERT_TRUE(mont.get());
ASSERT_TRUE(BN_MONT_CTX_set(mont.get(), m.get(), ctx));
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
std::unique_ptr<BN_ULONG[]> r_words(new BN_ULONG[m->top]),
a_words(new BN_ULONG[m->top]);
OPENSSL_memset(a_words.get(), 0, m->top * sizeof(BN_ULONG));
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m->top, a_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_mod_exp_mont_small(r_words.get(), m->top, a_words.get(),
m->top, e->d, e->top, mont.get()));
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
m->top, mont.get()));
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
EXPECT_BIGNUMS_EQUAL("A ^ E (mod M) (Montgomery, words)", mod_exp.get(),
ret.get());
}
#endif
}
}
@@ -917,27 +778,27 @@ static int DecimalToBIGNUM(bssl::UniquePtr<BIGNUM> *out, const char *in) {
TEST_F(BNTest, Dec2BN) {
bssl::UniquePtr<BIGNUM> bn;
int ret = DecimalToBIGNUM(&bn, "0");
ASSERT_EQ(1, ret);
EXPECT_EQ(1, ret);
EXPECT_TRUE(BN_is_zero(bn.get()));
EXPECT_FALSE(BN_is_negative(bn.get()));
ret = DecimalToBIGNUM(&bn, "256");
ASSERT_EQ(3, ret);
EXPECT_EQ(3, ret);
EXPECT_TRUE(BN_is_word(bn.get(), 256));
EXPECT_FALSE(BN_is_negative(bn.get()));
ret = DecimalToBIGNUM(&bn, "-42");
ASSERT_EQ(3, ret);
EXPECT_EQ(3, ret);
EXPECT_TRUE(BN_abs_is_word(bn.get(), 42));
EXPECT_TRUE(BN_is_negative(bn.get()));
ret = DecimalToBIGNUM(&bn, "-0");
ASSERT_EQ(2, ret);
EXPECT_EQ(2, ret);
EXPECT_TRUE(BN_is_zero(bn.get()));
EXPECT_FALSE(BN_is_negative(bn.get()));
ret = DecimalToBIGNUM(&bn, "42trailing garbage is ignored");
ASSERT_EQ(2, ret);
EXPECT_EQ(2, ret);
EXPECT_TRUE(BN_abs_is_word(bn.get(), 42));
EXPECT_FALSE(BN_is_negative(bn.get()));
}
@@ -945,27 +806,27 @@ TEST_F(BNTest, Dec2BN) {
TEST_F(BNTest, Hex2BN) {
bssl::UniquePtr<BIGNUM> bn;
int ret = HexToBIGNUM(&bn, "0");
ASSERT_EQ(1, ret);
EXPECT_EQ(1, ret);
EXPECT_TRUE(BN_is_zero(bn.get()));
EXPECT_FALSE(BN_is_negative(bn.get()));
ret = HexToBIGNUM(&bn, "256");
ASSERT_EQ(3, ret);
EXPECT_EQ(3, ret);
EXPECT_TRUE(BN_is_word(bn.get(), 0x256));
EXPECT_FALSE(BN_is_negative(bn.get()));
ret = HexToBIGNUM(&bn, "-42");
ASSERT_EQ(3, ret);
EXPECT_EQ(3, ret);
EXPECT_TRUE(BN_abs_is_word(bn.get(), 0x42));
EXPECT_TRUE(BN_is_negative(bn.get()));
ret = HexToBIGNUM(&bn, "-0");
ASSERT_EQ(2, ret);
EXPECT_EQ(2, ret);
EXPECT_TRUE(BN_is_zero(bn.get()));
EXPECT_FALSE(BN_is_negative(bn.get()));
ret = HexToBIGNUM(&bn, "abctrailing garbage is ignored");
ASSERT_EQ(3, ret);
EXPECT_EQ(3, ret);
EXPECT_TRUE(BN_is_word(bn.get(), 0xabc));
EXPECT_FALSE(BN_is_negative(bn.get()));
}
@@ -1139,11 +1000,16 @@ static const ASN1InvalidTest kASN1InvalidTests[] = {
{"\x03\x01\x00", 3},
// Empty contents.
{"\x02\x00", 2},
};
// kASN1BuggyTests contains incorrect encodings and the corresponding, expected
// results of |BN_parse_asn1_unsigned_buggy| given that input.
static const ASN1Test kASN1BuggyTests[] = {
// Negative numbers.
{"\x02\x01\x80", 3},
{"\x02\x01\xff", 3},
{"128", "\x02\x01\x80", 3},
{"255", "\x02\x01\xff", 3},
// Unnecessary leading zeros.
{"\x02\x02\x00\x01", 4},
{"1", "\x02\x02\x00\x01", 4},
};
TEST_F(BNTest, ASN1) {
@@ -1170,6 +1036,12 @@ TEST_F(BNTest, ASN1) {
ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
bssl::UniquePtr<uint8_t> delete_der(der);
EXPECT_EQ(Bytes(test.der, test.der_len), Bytes(der, der_len));
// |BN_parse_asn1_unsigned_buggy| parses all valid input.
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
ASSERT_TRUE(BN_parse_asn1_unsigned_buggy(&cbs, bn2.get()));
EXPECT_EQ(0u, CBS_len(&cbs));
EXPECT_BIGNUMS_EQUAL("decode ASN.1 buggy", bn.get(), bn2.get());
}
for (const ASN1InvalidTest &test : kASN1InvalidTests) {
@@ -1181,6 +1053,35 @@ TEST_F(BNTest, ASN1) {
EXPECT_FALSE(BN_parse_asn1_unsigned(&cbs, bn.get()))
<< "Parsed invalid input.";
ERR_clear_error();
// All tests in kASN1InvalidTests are also rejected by
// |BN_parse_asn1_unsigned_buggy|.
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
EXPECT_FALSE(BN_parse_asn1_unsigned_buggy(&cbs, bn.get()))
<< "Parsed invalid input.";
ERR_clear_error();
}
for (const ASN1Test &test : kASN1BuggyTests) {
SCOPED_TRACE(Bytes(test.der, test.der_len));
// These broken encodings are rejected by |BN_parse_asn1_unsigned|.
bssl::UniquePtr<BIGNUM> bn(BN_new());
ASSERT_TRUE(bn);
CBS cbs;
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
EXPECT_FALSE(BN_parse_asn1_unsigned(&cbs, bn.get()))
<< "Parsed invalid input.";
ERR_clear_error();
// However |BN_parse_asn1_unsigned_buggy| accepts them.
bssl::UniquePtr<BIGNUM> bn2 = ASCIIToBIGNUM(test.value_ascii);
ASSERT_TRUE(bn2);
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
ASSERT_TRUE(BN_parse_asn1_unsigned_buggy(&cbs, bn.get()));
EXPECT_EQ(0u, CBS_len(&cbs));
EXPECT_BIGNUMS_EQUAL("decode ASN.1 buggy", bn2.get(), bn.get());
}
// Serializing negative numbers is not supported.
@@ -1757,94 +1658,3 @@ TEST_F(BNTest, PrimeChecking) {
nullptr /* callback */));
EXPECT_EQ(0, is_probably_prime_2);
}
#if !defined(BORINGSSL_SHARED_LIBRARY)
TEST_F(BNTest, LessThanWords) {
// kTestVectors is an array of 256-bit values in sorted order.
static const BN_ULONG kTestVectors[][256 / BN_BITS2] = {
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x00000002), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x0000ffff), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x83339914), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0xfffffffe), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0xffffffff), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xed17ac85, 0x83339914), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x83339914), TOBN(0x00000000, 0x00000001),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0x00000000, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xed17ac85, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xed17ac85, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xed17ac85, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xffffffff, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
};
// Determine where the single-word values stop.
size_t one_word;
for (one_word = 0; one_word < OPENSSL_ARRAY_SIZE(kTestVectors); one_word++) {
int is_word = 1;
for (size_t i = 1; i < OPENSSL_ARRAY_SIZE(kTestVectors[one_word]); i++) {
if (kTestVectors[one_word][i] != 0) {
is_word = 0;
break;
}
}
if (!is_word) {
break;
}
}
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kTestVectors); i++) {
SCOPED_TRACE(i);
for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(kTestVectors); j++) {
SCOPED_TRACE(j);
EXPECT_EQ(i < j ? 1 : 0,
bn_less_than_words(kTestVectors[i], kTestVectors[j],
OPENSSL_ARRAY_SIZE(kTestVectors[i])));
for (size_t k = 0; k < one_word; k++) {
SCOPED_TRACE(k);
EXPECT_EQ(k <= i && i < j ? 1 : 0,
bn_in_range_words(kTestVectors[i], kTestVectors[k][0],
kTestVectors[j],
OPENSSL_ARRAY_SIZE(kTestVectors[i])));
}
}
}
EXPECT_EQ(0, bn_less_than_words(NULL, NULL, 0));
EXPECT_EQ(0, bn_in_range_words(NULL, 0, NULL, 0));
}
#endif // !BORINGSSL_SHARED_LIBRARY
-234
View File
@@ -1,234 +0,0 @@
// Copyright (c) 2017, Google Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package main
import (
"bufio"
"crypto/sha1"
"encoding/hex"
"errors"
"fmt"
"io"
"io/ioutil"
"math/big"
"os"
"path/filepath"
"strings"
)
type test struct {
LineNumber int
Type string
Values map[string]*big.Int
}
type testScanner struct {
scanner *bufio.Scanner
lineNo int
err error
test test
}
func newTestScanner(r io.Reader) *testScanner {
return &testScanner{scanner: bufio.NewScanner(r)}
}
func (s *testScanner) scanLine() bool {
if !s.scanner.Scan() {
return false
}
s.lineNo++
return true
}
func (s *testScanner) addAttribute(line string) (key string, ok bool) {
fields := strings.SplitN(line, "=", 2)
if len(fields) != 2 {
s.setError(errors.New("invalid syntax"))
return "", false
}
key = strings.TrimSpace(fields[0])
value := strings.TrimSpace(fields[1])
valueInt, ok := new(big.Int).SetString(value, 16)
if !ok {
s.setError(fmt.Errorf("could not parse %q", value))
return "", false
}
if _, dup := s.test.Values[key]; dup {
s.setError(fmt.Errorf("duplicate key %q", key))
return "", false
}
s.test.Values[key] = valueInt
return key, true
}
func (s *testScanner) Scan() bool {
s.test = test{
Values: make(map[string]*big.Int),
}
// Scan until the first attribute.
for {
if !s.scanLine() {
return false
}
if len(s.scanner.Text()) != 0 && s.scanner.Text()[0] != '#' {
break
}
}
var ok bool
s.test.Type, ok = s.addAttribute(s.scanner.Text())
if !ok {
return false
}
s.test.LineNumber = s.lineNo
for s.scanLine() {
if len(s.scanner.Text()) == 0 {
break
}
if s.scanner.Text()[0] == '#' {
continue
}
if _, ok := s.addAttribute(s.scanner.Text()); !ok {
return false
}
}
return s.scanner.Err() == nil
}
func (s *testScanner) Test() test {
return s.test
}
func (s *testScanner) Err() error {
if s.err != nil {
return s.err
}
return s.scanner.Err()
}
func (s *testScanner) setError(err error) {
s.err = fmt.Errorf("line %d: %s", s.lineNo, err)
}
func checkKeys(t test, keys ...string) bool {
var foundErrors bool
for _, k := range keys {
if _, ok := t.Values[k]; !ok {
fmt.Fprintf(os.Stderr, "Line %d: missing key %q.\n", t.LineNumber, k)
foundErrors = true
}
}
for k, _ := range t.Values {
var found bool
for _, k2 := range keys {
if k == k2 {
found = true
break
}
}
if !found {
fmt.Fprintf(os.Stderr, "Line %d: unexpected key %q.\n", t.LineNumber, k)
foundErrors = true
}
}
return !foundErrors
}
func appendLengthPrefixed(ret, b []byte) []byte {
ret = append(ret, byte(len(b)>>8), byte(len(b)))
ret = append(ret, b...)
return ret
}
func appendUnsigned(ret []byte, n *big.Int) []byte {
b := n.Bytes()
if n.Sign() == 0 {
b = []byte{0}
}
return appendLengthPrefixed(ret, b)
}
func appendSigned(ret []byte, n *big.Int) []byte {
var sign byte
if n.Sign() < 0 {
sign = 1
}
b := []byte{sign}
b = append(b, n.Bytes()...)
if n.Sign() == 0 {
b = append(b, 0)
}
return appendLengthPrefixed(ret, b)
}
func main() {
if len(os.Args) != 3 {
fmt.Fprintf(os.Stderr, "Usage: %s TESTS FUZZ_DIR\n", os.Args[0])
os.Exit(1)
}
in, err := os.Open(os.Args[1])
if err != nil {
fmt.Fprintf(os.Stderr, "Error opening %s: %s.\n", os.Args[0], err)
os.Exit(1)
}
defer in.Close()
fuzzerDir := os.Args[2]
scanner := newTestScanner(in)
for scanner.Scan() {
var fuzzer string
var b []byte
test := scanner.Test()
switch test.Type {
case "Quotient":
if checkKeys(test, "A", "B", "Quotient", "Remainder") {
fuzzer = "bn_div"
b = appendSigned(b, test.Values["A"])
b = appendSigned(b, test.Values["B"])
}
case "ModExp":
if checkKeys(test, "A", "E", "M", "ModExp") {
fuzzer = "bn_mod_exp"
b = appendSigned(b, test.Values["A"])
b = appendUnsigned(b, test.Values["E"])
b = appendUnsigned(b, test.Values["M"])
}
}
if len(fuzzer) != 0 {
hash := sha1.Sum(b)
path := filepath.Join(fuzzerDir, fuzzer + "_corpus", hex.EncodeToString(hash[:]))
if err := ioutil.WriteFile(path, b, 0666); err != nil {
fmt.Fprintf(os.Stderr, "Error writing to %s: %s.\n", path, err)
os.Exit(1)
}
}
}
if scanner.Err() != nil {
fmt.Fprintf(os.Stderr, "Error reading tests: %s.\n", scanner.Err())
}
}
-28
View File
@@ -5349,12 +5349,6 @@ A = -e53ad05c88568f09f616797f0b7f2756fb543d691ec2a5b645c1e5892a247302826419a35b1
Square = eea8028b26e0df090504d54da714a6f5f2695202e53cff479c78aedd47a8dc676243ec586740fde53b3eca9ca02b91031ce766242184109503fbe25b1b6d318e3cd5970fabd16dfa22984dd2e9f1e0f14c189170fc69c031d66663703e6235a942d51a4545bd7b0769d01d302ce2b00b83f01568a1e378f61fd0ca6201b0490330580cd9de85719e174a71915d7efbf65cd73d8f4e66f27e0dd3144d58ec09ed0f7ed7d1238ee596922807100fb7a11127944ddcdec6a9ca3bbf6df7301e354f3f049bfb7c275b43c3d8cda5907a932fba507c9145ea3166081c1b48fcc710ee32cd931f936c796b14f8a78a592e67753a7c9e428a01719c8ba82652f3a89fae110
A = -3dcb44be1e54c5a5d7db48055ca9afa1ebe2ae648aa6e16ac497502a7deee09ffa124720fad0ab163ce8b3ea6a90f110ea52b67dbc424d0cf1e8c9726dfd9e45bebcefaa5cd5706edeed27896525f31c6bbea3d67ee97badefabf3e2532470b66e3ae3100f66ddf50cf02fc3a8e3f44c304251d3b6a7ca3a6e4bd5d16a41bd97a4
Square = 0
A = 0
Square = 1
A = 1
# Product tests.
#
@@ -5960,22 +5954,6 @@ Product = -366c125f96b38b58d01c939c27c4100af3377eabb792b5491a
A = a57da276998c548101f514e9f
B = -542fb814f45924aa09a16f2a6
Product = 0
A = 0
B = 542fb814f45924aa09a16f2a6
Product = 0
A = 542fb814f45924aa09a16f2a6
B = 0
Product = 542fb814f45924aa09a16f2a6
A = 1
B = 542fb814f45924aa09a16f2a6
Product = 542fb814f45924aa09a16f2a6
A = 542fb814f45924aa09a16f2a6
B = 1
# Quotient tests.
#
@@ -9919,12 +9897,6 @@ ModSquare = fffffffdfffffd01000009000002f6fffdf403000312000402f3fff5f602fe080a00
A = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff00000000
M = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff
# Regression test for CVE-2017-3736.
ModSquare = fe06fe0b06160c09
A = fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f8f800000000000010000000006c000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffff8f8f8f800000000000010000000006c000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffff00fcfdfc
# A in Montgomery form is fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8ffeadbcfc4dae7fff908e92820306b9544d954000000006c000000000000000000000000000000000000000000000000000000000000000000ff030202fffff8ffebdbcfc4dae7fff908e92820306b9544d954000000006c000000ff0302030000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01fc00ff02ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00fcfdfcffffffffff000000000000000000ff0302030000000000ffffffffffffffffff00fcfdfdff030202ff00000000ffffffffffffffffff00fcfdfcffffffffff
M = fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f8f800000000000010000000006c000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffff8f8f8f800000000000010000000006c000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffff
# ModExp tests.
#
-15
View File
@@ -57,10 +57,8 @@
#include <openssl/bn.h>
#include <openssl/mem.h>
#include <openssl/type_check.h>
#include "internal.h"
#include "../../internal.h"
int BN_ucmp(const BIGNUM *a, const BIGNUM *b) {
@@ -176,19 +174,6 @@ int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl) {
return bn_cmp_words(a, b, cl);
}
int bn_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len) {
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
crypto_word_t_too_small);
int ret = 0;
// Process the words in little-endian order.
for (size_t i = 0; i < len; i++) {
crypto_word_t eq = constant_time_eq_w(a[i], b[i]);
crypto_word_t lt = constant_time_lt_w(a[i], b[i]);
ret = constant_time_select_int(eq, ret, constant_time_select_int(lt, 1, 0));
}
return ret;
}
int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) {
switch (bn->top) {
case 1:
+46 -53
View File
@@ -128,7 +128,7 @@ static BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) {
}
ret = q << BN_BITS4;
h = (h << BN_BITS4) | (l >> BN_BITS4);
h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2;
l = (l & BN_MASK2l) << BN_BITS4;
}
@@ -178,33 +178,28 @@ static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out,
#endif
}
// BN_div computes "quotient := numerator / divisor", rounding towards zero,
// and sets up |rem| such that "quotient * divisor + rem = numerator" holds.
//
// BN_div computes dv := num / divisor, rounding towards
// zero, and sets up rm such that dv*divisor + rm = num holds.
// Thus:
//
// quotient->neg == numerator->neg ^ divisor->neg
// (unless the result is zero)
// rem->neg == numerator->neg
// (unless the remainder is zero)
//
// If |quotient| or |rem| is NULL, the respective value is not returned.
// dv->neg == num->neg ^ divisor->neg (unless the result is zero)
// rm->neg == num->neg (unless the remainder is zero)
// If 'dv' or 'rm' is NULL, the respective value is not returned.
//
// This was specifically designed to contain fewer branches that may leak
// sensitive information; see "New Branch Prediction Vulnerabilities in OpenSSL
// and Necessary Software Countermeasures" by Onur Acıçmez, Shay Gueron, and
// Jean-Pierre Seifert.
int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
const BIGNUM *divisor, BN_CTX *ctx) {
int norm_shift, loop;
BIGNUM wnum;
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
BN_CTX *ctx) {
int norm_shift, i, loop;
BIGNUM *tmp, wnum, *snum, *sdiv, *res;
BN_ULONG *resp, *wnump;
BN_ULONG d0, d1;
int num_n, div_n;
// Invalid zero-padding would have particularly bad consequences
// so don't just rely on bn_check_top() here
if ((numerator->top > 0 && numerator->d[numerator->top - 1] == 0) ||
if ((num->top > 0 && num->d[num->top - 1] == 0) ||
(divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) {
OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED);
return 0;
@@ -216,27 +211,26 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
}
BN_CTX_start(ctx);
BIGNUM *tmp = BN_CTX_get(ctx);
BIGNUM *snum = BN_CTX_get(ctx);
BIGNUM *sdiv = BN_CTX_get(ctx);
BIGNUM *res = NULL;
if (quotient == NULL) {
tmp = BN_CTX_get(ctx);
snum = BN_CTX_get(ctx);
sdiv = BN_CTX_get(ctx);
if (dv == NULL) {
res = BN_CTX_get(ctx);
} else {
res = quotient;
res = dv;
}
if (sdiv == NULL || res == NULL) {
if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL) {
goto err;
}
// First we normalise the numbers
norm_shift = BN_BITS2 - (BN_num_bits(divisor) % BN_BITS2);
if (!BN_lshift(sdiv, divisor, norm_shift)) {
norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2);
if (!(BN_lshift(sdiv, divisor, norm_shift))) {
goto err;
}
sdiv->neg = 0;
norm_shift += BN_BITS2;
if (!BN_lshift(snum, numerator, norm_shift)) {
if (!(BN_lshift(snum, num, norm_shift))) {
goto err;
}
snum->neg = 0;
@@ -248,7 +242,7 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
if (!bn_wexpand(snum, sdiv->top + 2)) {
goto err;
}
for (int i = snum->top; i < sdiv->top + 2; i++) {
for (i = snum->top; i < sdiv->top + 2; i++) {
snum->d[i] = 0;
}
snum->top = sdiv->top + 2;
@@ -281,15 +275,15 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
wnump = &(snum->d[num_n - 1]);
// Setup to 'res'
res->neg = (numerator->neg ^ divisor->neg);
if (!bn_wexpand(res, loop + 1)) {
res->neg = (num->neg ^ divisor->neg);
if (!bn_wexpand(res, (loop + 1))) {
goto err;
}
res->top = loop - 1;
resp = &(res->d[loop - 1]);
// space for temp
if (!bn_wexpand(tmp, div_n + 1)) {
if (!bn_wexpand(tmp, (div_n + 1))) {
goto err;
}
@@ -301,11 +295,11 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
resp--;
}
for (int i = 0; i < loop - 1; i++, wnump--, resp--) {
for (i = 0; i < loop - 1; i++, wnump--, resp--) {
BN_ULONG q, l0;
// the first part of the loop uses the top two words of snum and sdiv to
// calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv
BN_ULONG n0, n1, rm = 0;
BN_ULONG n0, n1, rem = 0;
n0 = wnump[0];
n1 = wnump[-1];
@@ -313,18 +307,18 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
q = BN_MASK2;
} else {
// n0 < d0
bn_div_rem_words(&q, &rm, n0, n1, d0);
bn_div_rem_words(&q, &rem, n0, n1, d0);
#ifdef BN_ULLONG
BN_ULLONG t2 = (BN_ULLONG)d1 * q;
for (;;) {
if (t2 <= ((((BN_ULLONG)rm) << BN_BITS2) | wnump[-2])) {
if (t2 <= ((((BN_ULLONG)rem) << BN_BITS2) | wnump[-2])) {
break;
}
q--;
rm += d0;
if (rm < d0) {
break; // don't let rm overflow
rem += d0;
if (rem < d0) {
break; // don't let rem overflow
}
t2 -= d1;
}
@@ -332,14 +326,13 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
BN_ULONG t2l, t2h;
BN_UMULT_LOHI(t2l, t2h, d1, q);
for (;;) {
if (t2h < rm ||
(t2h == rm && t2l <= wnump[-2])) {
if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) {
break;
}
q--;
rm += d0;
if (rm < d0) {
break; // don't let rm overflow
rem += d0;
if (rem < d0) {
break; // don't let rem overflow
}
if (t2l < d1) {
t2h--;
@@ -370,21 +363,18 @@ int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
// store part of the result
*resp = q;
}
bn_correct_top(snum);
if (rem != NULL) {
// Keep a copy of the neg flag in numerator because if |rem| == |numerator|
// |BN_rshift| will overwrite it.
int neg = numerator->neg;
if (!BN_rshift(rem, snum, norm_shift)) {
if (rm != NULL) {
// Keep a copy of the neg flag in num because if rm==num
// BN_rshift() will overwrite it.
int neg = num->neg;
if (!BN_rshift(rm, snum, norm_shift)) {
goto err;
}
if (!BN_is_zero(rem)) {
rem->neg = neg;
if (!BN_is_zero(rm)) {
rm->neg = neg;
}
}
bn_correct_top(res);
BN_CTX_end(ctx);
return 1;
@@ -579,6 +569,8 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
BN_ULONG ret = 0;
int i, j;
w &= BN_MASK2;
if (!w) {
// actually this an error (division by zero)
return (BN_ULONG) - 1;
@@ -600,7 +592,7 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
BN_ULONG d;
BN_ULONG unused_rem;
bn_div_rem_words(&d, &unused_rem, ret, l, w);
ret = l - (d * w);
ret = (l - ((d * w) & BN_MASK2)) & BN_MASK2;
a->d[i] = d;
}
@@ -642,6 +634,7 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
}
#endif
w &= BN_MASK2;
for (i = a->top - 1; i >= 0; i--) {
#ifndef BN_ULLONG
ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w;
+85 -242
View File
@@ -188,6 +188,9 @@ err:
return ret;
}
// maximum precomputation table size for *variable* sliding windows
#define TABLE_SIZE 32
typedef struct bn_recp_ctx_st {
BIGNUM N; // the divisor
BIGNUM Nr; // the reciprocal
@@ -390,8 +393,8 @@ err:
return ret;
}
// BN_window_bits_for_exponent_size returns sliding window size for mod_exp with
// a |b| bit exponent.
// BN_window_bits_for_exponent_size -- macro for sliding window mod_exp
// functions
//
// For window size 'w' (w >= 2) and a random 'b' bits exponent, the number of
// multiplications is a constant plus on average
@@ -413,35 +416,11 @@ err:
//
// (with draws in between). Very small exponents are often selected
// with low Hamming weight, so we use w = 1 for b <= 23.
static int BN_window_bits_for_exponent_size(int b) {
if (b > 671) {
return 6;
}
if (b > 239) {
return 5;
}
if (b > 79) {
return 4;
}
if (b > 23) {
return 3;
}
return 1;
}
// TABLE_SIZE is the maximum precomputation table size for *variable* sliding
// windows. This must be 2^(max_window - 1), where max_window is the largest
// value returned from |BN_window_bits_for_exponent_size|.
#define TABLE_SIZE 32
// TABLE_BITS_SMALL is the smallest value returned from
// |BN_window_bits_for_exponent_size| when |b| is at most |BN_BITS2| *
// |BN_SMALL_MAX_WORDS| words.
#define TABLE_BITS_SMALL 5
// TABLE_SIZE_SMALL is the same as |TABLE_SIZE|, but when |b| is at most
// |BN_BITS2| * |BN_SMALL_MAX_WORDS|.
#define TABLE_SIZE_SMALL (1 << (TABLE_BITS_SMALL - 1))
#define BN_window_bits_for_exponent_size(b) \
((b) > 671 ? 6 : \
(b) > 239 ? 5 : \
(b) > 79 ? 4 : \
(b) > 23 ? 3 : 1)
static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx) {
@@ -522,7 +501,7 @@ static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
int wvalue; // The 'value' of the window
int wend; // The bottom bit of the window
if (!BN_is_bit_set(p, wstart)) {
if (BN_is_bit_set(p, wstart) == 0) {
if (!start) {
if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx)) {
goto err;
@@ -594,11 +573,19 @@ int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont) {
int i, j, bits, ret = 0, wstart, window;
int start = 1;
BIGNUM *d, *r;
const BIGNUM *aa;
// Table of variables obtained from 'ctx'
BIGNUM *val[TABLE_SIZE];
BN_MONT_CTX *new_mont = NULL;
if (!BN_is_odd(m)) {
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
return 0;
}
int bits = BN_num_bits(p);
bits = BN_num_bits(p);
if (bits == 0) {
// x**0 mod 1 is still zero.
if (BN_is_one(m)) {
@@ -608,13 +595,9 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
return BN_one(rr);
}
int ret = 0;
BIGNUM *val[TABLE_SIZE];
BN_MONT_CTX *new_mont = NULL;
BN_CTX_start(ctx);
BIGNUM *d = BN_CTX_get(ctx);
BIGNUM *r = BN_CTX_get(ctx);
d = BN_CTX_get(ctx);
r = BN_CTX_get(ctx);
val[0] = BN_CTX_get(ctx);
if (!d || !r || !val[0]) {
goto err;
@@ -629,7 +612,6 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
mont = new_mont;
}
const BIGNUM *aa;
if (a->neg || BN_ucmp(a, m) >= 0) {
if (!BN_nnmod(val[0], a, m, ctx)) {
goto err;
@@ -644,52 +626,53 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
ret = 1;
goto err;
}
// We exponentiate by looking at sliding windows of the exponent and
// precomputing powers of |aa|. Windows may be shifted so they always end on a
// set bit, so only precompute odd powers. We compute val[i] = aa^(2*i + 1)
// for i = 0 to 2^(window-1), all in Montgomery form.
int window = BN_window_bits_for_exponent_size(bits);
if (!BN_to_montgomery(val[0], aa, mont, ctx)) {
goto err;
goto err; // 1
}
window = BN_window_bits_for_exponent_size(bits);
if (window > 1) {
if (!BN_mod_mul_montgomery(d, val[0], val[0], mont, ctx)) {
goto err;
goto err; // 2
}
for (int i = 1; i < 1 << (window - 1); i++) {
val[i] = BN_CTX_get(ctx);
if (val[i] == NULL ||
j = 1 << (window - 1);
for (i = 1; i < j; i++) {
if (((val[i] = BN_CTX_get(ctx)) == NULL) ||
!BN_mod_mul_montgomery(val[i], val[i - 1], d, mont, ctx)) {
goto err;
}
}
}
// Set |r| to one in Montgomery form. If the high bit of |m| is set, |m| is
// close to R and we subtract rather than perform Montgomery reduction.
if (m->d[m->top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
if (!bn_wexpand(r, m->top)) {
start = 1; // This is used to avoid multiplication etc
// when there is only the value '1' in the
// buffer.
wstart = bits - 1; // The top bit of the window
j = m->top; // borrow j
if (m->d[j - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
if (!bn_wexpand(r, j)) {
goto err;
}
// r = 2^(top*BN_BITS2) - m
r->d[0] = 0 - m->d[0];
for (int i = 1; i < m->top; i++) {
r->d[i] = ~m->d[i];
// 2^(top*BN_BITS2) - m
r->d[0] = (0 - m->d[0]) & BN_MASK2;
for (i = 1; i < j; i++) {
r->d[i] = (~m->d[i]) & BN_MASK2;
}
r->top = m->top;
// The upper words will be zero if the corresponding words of |m| were
// 0xfff[...], so call |bn_correct_top|.
r->top = j;
// Upper words will be zero if the corresponding words of 'm'
// were 0xfff[...], so decrement r->top accordingly.
bn_correct_top(r);
} else if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) {
goto err;
}
int r_is_one = 1;
int wstart = bits - 1; // The top bit of the window.
for (;;) {
if (!BN_is_bit_set(p, wstart)) {
if (!r_is_one && !BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
int wvalue; // The 'value' of the window
int wend; // The bottom bit of the window
if (BN_is_bit_set(p, wstart) == 0) {
if (!start && !BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
goto err;
}
if (wstart == 0) {
@@ -699,37 +682,44 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
continue;
}
// We now have wstart on a set bit. Find the largest window we can use.
int wvalue = 1;
int wsize = 0;
for (int i = 1; i < window && i <= wstart; i++) {
// We now have wstart on a 'set' bit, we now need to work out how bit a
// window to do. To do this we need to scan forward until the last set bit
// before the end of the window
wvalue = 1;
wend = 0;
for (i = 1; i < window; i++) {
if (wstart - i < 0) {
break;
}
if (BN_is_bit_set(p, wstart - i)) {
wvalue <<= (i - wsize);
wvalue <<= (i - wend);
wvalue |= 1;
wsize = i;
wend = i;
}
}
// Shift |r| to the end of the window.
if (!r_is_one) {
for (int i = 0; i < wsize + 1; i++) {
// wend is the size of the current window
j = wend + 1;
// add the 'bytes above'
if (!start) {
for (i = 0; i < j; i++) {
if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
goto err;
}
}
}
assert(wvalue & 1);
assert(wvalue < (1 << window));
// wvalue will be an odd number < 2^window
if (!BN_mod_mul_montgomery(r, r, val[wvalue >> 1], mont, ctx)) {
goto err;
}
r_is_one = 0;
if (wstart == wsize) {
// move the 'window' down further
wstart -= wend + 1;
start = 0;
if (wstart < 0) {
break;
}
wstart -= wsize + 1;
}
if (!BN_from_montgomery(rr, r, mont, ctx)) {
@@ -743,160 +733,12 @@ err:
return ret;
}
int bn_mod_exp_mont_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_ULONG *p, size_t num_p,
const BN_MONT_CTX *mont) {
const BN_ULONG *n = mont->N.d;
size_t num_n = mont->N.top;
if (num_n != num_a || num_n != num_r || num_n > BN_SMALL_MAX_WORDS) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
if (!BN_is_odd(&mont->N)) {
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
return 0;
}
unsigned bits = 0;
if (num_p != 0) {
bits = BN_num_bits_word(p[num_p - 1]) + (num_p - 1) * BN_BITS2;
}
if (bits == 0) {
OPENSSL_memset(r, 0, num_r * sizeof(BN_ULONG));
if (!BN_is_one(&mont->N)) {
r[0] = 1;
}
return 1;
}
// We exponentiate by looking at sliding windows of the exponent and
// precomputing powers of |a|. Windows may be shifted so they always end on a
// set bit, so only precompute odd powers. We compute val[i] = a^(2*i + 1) for
// i = 0 to 2^(window-1), all in Montgomery form.
unsigned window = BN_window_bits_for_exponent_size(bits);
if (window > TABLE_BITS_SMALL) {
window = TABLE_BITS_SMALL; // Tolerate excessively large |p|.
}
int ret = 0;
BN_ULONG val[TABLE_SIZE_SMALL][BN_SMALL_MAX_WORDS];
OPENSSL_memcpy(val[0], a, num_n * sizeof(BN_ULONG));
if (window > 1) {
BN_ULONG d[BN_SMALL_MAX_WORDS];
if (!bn_mod_mul_montgomery_small(d, num_n, val[0], num_n, val[0], num_n,
mont)) {
goto err;
}
for (unsigned i = 1; i < 1u << (window - 1); i++) {
if (!bn_mod_mul_montgomery_small(val[i], num_n, val[i - 1], num_n, d,
num_n, mont)) {
goto err;
}
}
}
// Set |r| to one in Montgomery form. If the high bit of |m| is set, |m| is
// close to R and we subtract rather than perform Montgomery reduction.
if (n[num_n - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
// r = 2^(top*BN_BITS2) - m
r[0] = 0 - n[0];
for (size_t i = 1; i < num_n; i++) {
r[i] = ~n[i];
}
} else if (!bn_from_montgomery_small(r, num_r, mont->RR.d, mont->RR.top,
mont)) {
goto err;
}
int r_is_one = 1;
unsigned wstart = bits - 1; // The top bit of the window.
for (;;) {
if (!bn_is_bit_set_words(p, num_p, wstart)) {
if (!r_is_one &&
!bn_mod_mul_montgomery_small(r, num_r, r, num_r, r, num_r, mont)) {
goto err;
}
if (wstart == 0) {
break;
}
wstart--;
continue;
}
// We now have wstart on a set bit. Find the largest window we can use.
unsigned wvalue = 1;
unsigned wsize = 0;
for (unsigned i = 1; i < window && i <= wstart; i++) {
if (bn_is_bit_set_words(p, num_p, wstart - i)) {
wvalue <<= (i - wsize);
wvalue |= 1;
wsize = i;
}
}
// Shift |r| to the end of the window.
if (!r_is_one) {
for (unsigned i = 0; i < wsize + 1; i++) {
if (!bn_mod_mul_montgomery_small(r, num_r, r, num_r, r, num_r, mont)) {
goto err;
}
}
}
assert(wvalue & 1);
assert(wvalue < (1u << window));
if (!bn_mod_mul_montgomery_small(r, num_r, r, num_r, val[wvalue >> 1],
num_n, mont)) {
goto err;
}
r_is_one = 0;
if (wstart == wsize) {
break;
}
wstart -= wsize + 1;
}
ret = 1;
err:
OPENSSL_cleanse(val, sizeof(val));
return ret;
}
int bn_mod_inverse_prime_mont_small(BN_ULONG *r, size_t num_r,
const BN_ULONG *a, size_t num_a,
const BN_MONT_CTX *mont) {
const BN_ULONG *p = mont->N.d;
size_t num_p = mont->N.top;
if (num_p > BN_SMALL_MAX_WORDS || num_p == 0) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
// Per Fermat's Little Theorem, a^-1 = a^(p-2) (mod p) for p prime.
BN_ULONG p_minus_two[BN_SMALL_MAX_WORDS];
OPENSSL_memcpy(p_minus_two, p, num_p * sizeof(BN_ULONG));
if (p_minus_two[0] >= 2) {
p_minus_two[0] -= 2;
} else {
p_minus_two[0] -= 2;
for (size_t i = 1; i < num_p; i++) {
if (p_minus_two[i]-- != 0) {
break;
}
}
}
return bn_mod_exp_mont_small(r, num_r, a, num_a, p_minus_two, num_p, mont);
}
// |BN_mod_exp_mont_consttime| stores the precomputed powers in a specific
// BN_mod_exp_mont_consttime() stores the precomputed powers in a specific
// layout so that accessing any of these table values shows the same access
// pattern as far as cache lines are concerned. The following functions are
// used to transfer a BIGNUM from/to that table.
static void copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf,
int idx, int window) {
static int copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf, int idx,
int window) {
int i, j;
const int width = 1 << window;
BN_ULONG *table = (BN_ULONG *) buf;
@@ -908,6 +750,8 @@ static void copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf,
for (i = 0, j = idx; i < top; i++, j += width) {
table[j] = b->d[i];
}
return 1;
}
static int copy_from_prebuf(BIGNUM *b, int top, unsigned char *buf, int idx,
@@ -1119,9 +963,9 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
// by Shay Gueron's suggestion
if (m->d[top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
// 2^(top*BN_BITS2) - m
tmp.d[0] = 0 - m->d[0];
tmp.d[0] = (0 - m->d[0]) & BN_MASK2;
for (i = 1; i < top; i++) {
tmp.d[i] = ~m->d[i];
tmp.d[i] = (~m->d[i]) & BN_MASK2;
}
tmp.top = top;
} else if (!BN_to_montgomery(&tmp, BN_value_one(), mont, ctx)) {
@@ -1259,27 +1103,26 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
} else
#endif
{
copy_to_prebuf(&tmp, top, powerbuf, 0, window);
copy_to_prebuf(&am, top, powerbuf, 1, window);
if (!copy_to_prebuf(&tmp, top, powerbuf, 0, window) ||
!copy_to_prebuf(&am, top, powerbuf, 1, window)) {
goto err;
}
// If the window size is greater than 1, then calculate
// val[i=2..2^winsize-1]. Powers are computed as a*a^(i-1)
// (even powers could instead be computed as (a^(i/2))^2
// to use the slight performance advantage of sqr over mul).
if (window > 1) {
if (!BN_mod_mul_montgomery(&tmp, &am, &am, mont, ctx)) {
if (!BN_mod_mul_montgomery(&tmp, &am, &am, mont, ctx) ||
!copy_to_prebuf(&tmp, top, powerbuf, 2, window)) {
goto err;
}
copy_to_prebuf(&tmp, top, powerbuf, 2, window);
for (i = 3; i < numPowers; i++) {
// Calculate a^i = a^(i-1) * a
if (!BN_mod_mul_montgomery(&tmp, &am, &tmp, mont, ctx)) {
if (!BN_mod_mul_montgomery(&tmp, &am, &tmp, mont, ctx) ||
!copy_to_prebuf(&tmp, top, powerbuf, i, window)) {
goto err;
}
copy_to_prebuf(&tmp, top, powerbuf, i, window);
}
}
+47 -42
View File
@@ -124,11 +124,12 @@
#endif // !BN_ULLONG
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
BN_ULONG w) {
BN_ULONG c1 = 0;
if (num == 0) {
assert(num >= 0);
if (num <= 0) {
return c1;
}
@@ -152,11 +153,11 @@ BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
return c1;
}
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
BN_ULONG w) {
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) {
BN_ULONG c1 = 0;
if (num == 0) {
assert(num >= 0);
if (num <= 0) {
return c1;
}
@@ -178,8 +179,9 @@ BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
return c1;
}
void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, size_t n) {
if (n == 0) {
void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
assert(n >= 0);
if (n <= 0) {
return;
}
@@ -202,25 +204,26 @@ void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, size_t n) {
#ifdef BN_ULLONG
BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
size_t n) {
int n) {
BN_ULLONG ll = 0;
if (n == 0) {
return 0;
assert(n >= 0);
if (n <= 0) {
return (BN_ULONG)0;
}
while (n & ~3) {
ll += (BN_ULLONG)a[0] + b[0];
r[0] = (BN_ULONG)ll;
r[0] = (BN_ULONG)ll & BN_MASK2;
ll >>= BN_BITS2;
ll += (BN_ULLONG)a[1] + b[1];
r[1] = (BN_ULONG)ll;
r[1] = (BN_ULONG)ll & BN_MASK2;
ll >>= BN_BITS2;
ll += (BN_ULLONG)a[2] + b[2];
r[2] = (BN_ULONG)ll;
r[2] = (BN_ULONG)ll & BN_MASK2;
ll >>= BN_BITS2;
ll += (BN_ULLONG)a[3] + b[3];
r[3] = (BN_ULONG)ll;
r[3] = (BN_ULONG)ll & BN_MASK2;
ll >>= BN_BITS2;
a += 4;
b += 4;
@@ -229,7 +232,7 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
}
while (n) {
ll += (BN_ULLONG)a[0] + b[0];
r[0] = (BN_ULONG)ll;
r[0] = (BN_ULONG)ll & BN_MASK2;
ll >>= BN_BITS2;
a++;
b++;
@@ -242,37 +245,38 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
#else // !BN_ULLONG
BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
size_t n) {
int n) {
BN_ULONG c, l, t;
if (n == 0) {
assert(n >= 0);
if (n <= 0) {
return (BN_ULONG)0;
}
c = 0;
while (n & ~3) {
t = a[0];
t += c;
t = (t + c) & BN_MASK2;
c = (t < c);
l = t + b[0];
l = (t + b[0]) & BN_MASK2;
c += (l < t);
r[0] = l;
t = a[1];
t += c;
t = (t + c) & BN_MASK2;
c = (t < c);
l = t + b[1];
l = (t + b[1]) & BN_MASK2;
c += (l < t);
r[1] = l;
t = a[2];
t += c;
t = (t + c) & BN_MASK2;
c = (t < c);
l = t + b[2];
l = (t + b[2]) & BN_MASK2;
c += (l < t);
r[2] = l;
t = a[3];
t += c;
t = (t + c) & BN_MASK2;
c = (t < c);
l = t + b[3];
l = (t + b[3]) & BN_MASK2;
c += (l < t);
r[3] = l;
a += 4;
@@ -282,9 +286,9 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
}
while (n) {
t = a[0];
t += c;
t = (t + c) & BN_MASK2;
c = (t < c);
l = t + b[0];
l = (t + b[0]) & BN_MASK2;
c += (l < t);
r[0] = l;
a++;
@@ -298,36 +302,37 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
#endif // !BN_ULLONG
BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
size_t n) {
int n) {
BN_ULONG t1, t2;
int c = 0;
if (n == 0) {
assert(n >= 0);
if (n <= 0) {
return (BN_ULONG)0;
}
while (n & ~3) {
t1 = a[0];
t2 = b[0];
r[0] = t1 - t2 - c;
r[0] = (t1 - t2 - c) & BN_MASK2;
if (t1 != t2) {
c = (t1 < t2);
}
t1 = a[1];
t2 = b[1];
r[1] = t1 - t2 - c;
r[1] = (t1 - t2 - c) & BN_MASK2;
if (t1 != t2) {
c = (t1 < t2);
}
t1 = a[2];
t2 = b[2];
r[2] = t1 - t2 - c;
r[2] = (t1 - t2 - c) & BN_MASK2;
if (t1 != t2) {
c = (t1 < t2);
}
t1 = a[3];
t2 = b[3];
r[3] = t1 - t2 - c;
r[3] = (t1 - t2 - c) & BN_MASK2;
if (t1 != t2) {
c = (t1 < t2);
}
@@ -339,7 +344,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
while (n) {
t1 = a[0];
t2 = b[0];
r[0] = t1 - t2 - c;
r[0] = (t1 - t2 - c) & BN_MASK2;
if (t1 != t2) {
c = (t1 < t2);
}
@@ -367,7 +372,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
t += (c0); /* no carry */ \
(c0) = (BN_ULONG)Lw(t); \
hi = (BN_ULONG)Hw(t); \
(c1) += (hi); \
(c1) = ((c1) + (hi)) & BN_MASK2; \
if ((c1) < hi) { \
(c2)++; \
} \
@@ -380,14 +385,14 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
BN_ULLONG tt = t + (c0); /* no carry */ \
(c0) = (BN_ULONG)Lw(tt); \
hi = (BN_ULONG)Hw(tt); \
(c1) += hi; \
(c1) = ((c1) + hi) & BN_MASK2; \
if ((c1) < hi) { \
(c2)++; \
} \
t += (c0); /* no carry */ \
(c0) = (BN_ULONG)Lw(t); \
hi = (BN_ULONG)Hw(t); \
(c1) += hi; \
(c1) = ((c1) + hi) & BN_MASK2; \
if ((c1) < hi) { \
(c2)++; \
} \
@@ -400,7 +405,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
t += (c0); /* no carry */ \
(c0) = (BN_ULONG)Lw(t); \
hi = (BN_ULONG)Hw(t); \
(c1) += hi; \
(c1) = ((c1) + hi) & BN_MASK2; \
if ((c1) < hi) { \
(c2)++; \
} \
@@ -453,7 +458,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
#endif // !BN_ULLONG
void bn_mul_comba8(BN_ULONG r[16], const BN_ULONG a[8], const BN_ULONG b[8]) {
void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
BN_ULONG c1, c2, c3;
c1 = 0;
@@ -555,7 +560,7 @@ void bn_mul_comba8(BN_ULONG r[16], const BN_ULONG a[8], const BN_ULONG b[8]) {
r[15] = c1;
}
void bn_mul_comba4(BN_ULONG r[8], const BN_ULONG a[4], const BN_ULONG b[4]) {
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
BN_ULONG c1, c2, c3;
c1 = 0;
@@ -593,7 +598,7 @@ void bn_mul_comba4(BN_ULONG r[8], const BN_ULONG a[4], const BN_ULONG b[4]) {
r[7] = c2;
}
void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[8]) {
void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
BN_ULONG c1, c2, c3;
c1 = 0;
@@ -667,7 +672,7 @@ void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[8]) {
r[15] = c1;
}
void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]) {
void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
BN_ULONG c1, c2, c3;
c1 = 0;
+33 -175
View File
@@ -142,39 +142,41 @@ extern "C" {
#if !defined(_MSC_VER)
// MSVC doesn't support two-word integers on 64-bit.
#define BN_ULLONG uint128_t
#define BN_ULLONG uint128_t
#endif
#define BN_BITS2 64
#define BN_BYTES 8
#define BN_BITS4 32
#define BN_MASK2 (0xffffffffffffffffUL)
#define BN_MASK2l (0xffffffffUL)
#define BN_MASK2h (0xffffffff00000000UL)
#define BN_MASK2h1 (0xffffffff80000000UL)
#define BN_BITS2 64
#define BN_BYTES 8
#define BN_BITS4 32
#define BN_MASK2 (0xffffffffffffffffUL)
#define BN_MASK2l (0xffffffffUL)
#define BN_MASK2h (0xffffffff00000000UL)
#define BN_MASK2h1 (0xffffffff80000000UL)
#define BN_MONT_CTX_N0_LIMBS 1
#define BN_DEC_CONV (10000000000000000000UL)
#define BN_DEC_NUM 19
#define BN_TBIT (0x8000000000000000UL)
#define BN_DEC_CONV (10000000000000000000UL)
#define BN_DEC_NUM 19
#define TOBN(hi, lo) ((BN_ULONG)(hi) << 32 | (lo))
#elif defined(OPENSSL_32_BIT)
#define BN_ULLONG uint64_t
#define BN_BITS2 32
#define BN_BYTES 4
#define BN_BITS4 16
#define BN_MASK2 (0xffffffffUL)
#define BN_MASK2l (0xffffUL)
#define BN_MASK2h1 (0xffff8000UL)
#define BN_MASK2h (0xffff0000UL)
#define BN_ULLONG uint64_t
#define BN_BITS2 32
#define BN_BYTES 4
#define BN_BITS4 16
#define BN_MASK2 (0xffffffffUL)
#define BN_MASK2l (0xffffUL)
#define BN_MASK2h1 (0xffff8000UL)
#define BN_MASK2h (0xffff0000UL)
// On some 32-bit platforms, Montgomery multiplication is done using 64-bit
// arithmetic with SIMD instructions. On such platforms, |BN_MONT_CTX::n0|
// needs to be two words long. Only certain 32-bit platforms actually make use
// of n0[1] and shorter R value would suffice for the others. However,
// currently only the assembly files know which is which.
#define BN_MONT_CTX_N0_LIMBS 2
#define BN_DEC_CONV (1000000000UL)
#define BN_DEC_NUM 9
#define BN_TBIT (0x80000000UL)
#define BN_DEC_CONV (1000000000UL)
#define BN_DEC_NUM 9
#define TOBN(hi, lo) (lo), (hi)
#else
@@ -189,8 +191,8 @@ extern "C" {
}
#if defined(BN_ULLONG)
#define Lw(t) ((BN_ULONG)(t))
#define Hw(t) ((BN_ULONG)((t) >> BN_BITS2))
#define Lw(t) (((BN_ULONG)(t))&BN_MASK2)
#define Hw(t) (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2)
#endif
// bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or
@@ -210,50 +212,16 @@ int bn_expand(BIGNUM *bn, size_t bits);
// least significant word first.
int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num);
// bn_mul_add_words multiples |ap| by |w|, adds the result to |rp|, and places
// the result in |rp|. |ap| and |rp| must both be |num| words long. It returns
// the carry word of the operation. |ap| and |rp| may be equal but otherwise may
// not alias.
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
BN_ULONG w);
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
// bn_mul_words multiples |ap| by |w| and places the result in |rp|. |ap| and
// |rp| must both be |num| words long. It returns the carry word of the
// operation. |ap| and |rp| may be equal but otherwise may not alias.
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num, BN_ULONG w);
// bn_sqr_words sets |rp[2*i]| and |rp[2*i+1]| to |ap[i]|'s square, for all |i|
// up to |num|. |ap| is an array of |num| words and |rp| an array of |2*num|
// words. |ap| and |rp| may not alias.
//
// This gives the contribution of the |ap[i]*ap[i]| terms when squaring |ap|.
void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num);
// bn_add_words adds |ap| to |bp| and places the result in |rp|, each of which
// are |num| words long. It returns the carry bit, which is one if the operation
// overflowed and zero otherwise. Any pair of |ap|, |bp|, and |rp| may be equal
// to each other but otherwise may not alias.
BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
size_t num);
// bn_sub_words subtracts |bp| from |ap| and places the result in |rp|. It
// returns the borrow bit, which is one if the computation underflowed and zero
// otherwise. Any pair of |ap|, |bp|, and |rp| may be equal to each other but
// otherwise may not alias.
BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
size_t num);
// bn_mul_comba4 sets |r| to the product of |a| and |b|.
void bn_mul_comba4(BN_ULONG r[8], const BN_ULONG a[4], const BN_ULONG b[4]);
// bn_mul_comba8 sets |r| to the product of |a| and |b|.
void bn_mul_comba8(BN_ULONG r[16], const BN_ULONG a[8], const BN_ULONG b[8]);
// bn_sqr_comba8 sets |r| to |a|^2.
void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[4]);
// bn_sqr_comba4 sets |r| to |a|^2.
void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]);
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a);
void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a);
// bn_cmp_words returns a value less than, equal to or greater than zero if
// the, length |n|, array |a| is less than, equal to or greater than |b|.
@@ -265,29 +233,6 @@ int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n);
// the length of |a| minus the length of |b|.
int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl);
// bn_less_than_words returns one if |a| < |b| and zero otherwise, where |a|
// and |b| both are |len| words long. It runs in constant time.
int bn_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len);
// bn_in_range_words returns one if |min_inclusive| <= |a| < |max_exclusive|,
// where |a| and |max_exclusive| both are |len| words long. This function leaks
// which of [0, min_inclusive), [min_inclusive, max_exclusive), and
// [max_exclusive, 2^(BN_BITS2*len)) contains |a|, but otherwise the value of
// |a| is secret.
int bn_in_range_words(const BN_ULONG *a, BN_ULONG min_inclusive,
const BN_ULONG *max_exclusive, size_t len);
// bn_rand_range_words sets |out| to a uniformly distributed random number from
// |min_inclusive| to |max_exclusive|. Both |out| and |max_exclusive| are |len|
// words long.
//
// This function runs in time independent of the result, but |min_inclusive| and
// |max_exclusive| are public data. (Information about the range is unavoidably
// leaked by how many iterations it took to select a number.)
int bn_rand_range_words(BN_ULONG *out, BN_ULONG min_inclusive,
const BN_ULONG *max_exclusive, size_t len,
const uint8_t additional_data[32]);
int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
const BN_ULONG *np, const BN_ULONG *n0, int num);
@@ -318,93 +263,6 @@ int bn_mod_inverse_secret_prime(BIGNUM *out, const BIGNUM *a, const BIGNUM *p,
// -2 on error.
int bn_jacobi(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
// bn_is_bit_set_words returns one if bit |bit| is set in |a| and zero
// otherwise.
int bn_is_bit_set_words(const BN_ULONG *a, size_t num, unsigned bit);
// Low-level operations for small numbers.
//
// The following functions implement algorithms suitable for use with scalars
// and field elements in elliptic curves. They rely on the number being small
// both to stack-allocate various temporaries and because they do not implement
// optimizations useful for the larger values used in RSA.
// BN_SMALL_MAX_WORDS is the largest size input these functions handle. This
// limit allows temporaries to be more easily stack-allocated. This limit is set
// to accommodate P-521.
#if defined(OPENSSL_32_BIT)
#define BN_SMALL_MAX_WORDS 17
#else
#define BN_SMALL_MAX_WORDS 9
#endif
// bn_mul_small sets |r| to |a|*|b|. |num_r| must be |num_a| + |num_b|. |r| may
// not alias with |a| or |b|. This function returns one on success and zero if
// lengths are inconsistent.
int bn_mul_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a,
const BN_ULONG *b, size_t num_b);
// bn_sqr_small sets |r| to |a|^2. |num_a| must be at most |BN_SMALL_MAX_WORDS|.
// |num_r| must be |num_a|*2. |r| and |a| may not alias. This function returns
// one on success and zero on programmer error.
int bn_sqr_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a);
// In the following functions, the modulus must be at most |BN_SMALL_MAX_WORDS|
// words long.
// bn_to_montgomery_small sets |r| to |a| translated to the Montgomery domain.
// |num_a| and |num_r| must be the length of the modulus, which is
// |mont->N.top|. |a| must be fully reduced. This function returns one on
// success and zero if lengths are inconsistent. |r| and |a| may alias.
int bn_to_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_MONT_CTX *mont);
// bn_from_montgomery_small sets |r| to |a| translated out of the Montgomery
// domain. |num_r| must be the length of the modulus, which is |mont->N.top|.
// |a| must be at most |mont->N.top| * R and |num_a| must be at most 2 *
// |mont->N.top|. This function returns one on success and zero if lengths are
// inconsistent. |r| and |a| may alias.
int bn_from_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_MONT_CTX *mont);
// bn_mod_mul_montgomery_small sets |r| to |a| * |b| mod |mont->N|. Both inputs
// and outputs are in the Montgomery domain. |num_r| must be the length of the
// modulus, which is |mont->N.top|. This function returns one on success and
// zero on internal error or inconsistent lengths. Any two of |r|, |a|, and |b|
// may alias.
//
// This function requires |a| * |b| < N * R, where N is the modulus and R is the
// Montgomery divisor, 2^(N.top * BN_BITS2). This should generally be satisfied
// by ensuring |a| and |b| are fully reduced, however ECDSA has one computation
// which requires the more general bound.
int bn_mod_mul_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_ULONG *b, size_t num_b,
const BN_MONT_CTX *mont);
// bn_mod_exp_mont_small sets |r| to |a|^|p| mod |mont->N|. It returns one on
// success and zero on programmer or internal error. Both inputs and outputs are
// in the Montgomery domain. |num_r| and |num_a| must be |mont->N.top|, which
// must be at most |BN_SMALL_MAX_WORDS|. |a| must be fully-reduced. This
// function runs in time independent of |a|, but |p| and |mont->N| are public
// values.
//
// Note this function differs from |BN_mod_exp_mont| which uses Montgomery
// reduction but takes input and output outside the Montgomery domain. Combine
// this function with |bn_from_montgomery_small| and |bn_to_montgomery_small|
// if necessary.
int bn_mod_exp_mont_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_ULONG *p, size_t num_p,
const BN_MONT_CTX *mont);
// bn_mod_inverse_prime_mont_small sets |r| to |a|^-1 mod |mont->N|. |mont->N|
// must be a prime. |num_r| and |num_a| must be |mont->N.top|, which must be at
// most |BN_SMALL_MAX_WORDS|. |a| must be fully-reduced. This function runs in
// time independent of |a|, but |mont->N| is a public value.
int bn_mod_inverse_prime_mont_small(BN_ULONG *r, size_t num_r,
const BN_ULONG *a, size_t num_a,
const BN_MONT_CTX *mont);
#if defined(__cplusplus)
} // extern C
+68 -121
View File
@@ -114,7 +114,6 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/thread.h>
#include <openssl/type_check.h>
#include "internal.h"
#include "../../internal.h"
@@ -208,13 +207,14 @@ int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) {
mont->n0[1] = 0;
#endif
// Save RR = R**2 (mod N). R is the smallest power of 2**BN_BITS2 such that R
// Save RR = R**2 (mod N). R is the smallest power of 2**BN_BITS such that R
// > mod. Even though the assembly on some 32-bit platforms works with 64-bit
// values, using |BN_BITS2| here, rather than |BN_MONT_CTX_N0_LIMBS *
// BN_BITS2|, is correct because R**2 will still be a multiple of the latter
// as |BN_MONT_CTX_N0_LIMBS| is either one or two.
//
// XXX: This is not constant time with respect to |mont->N|, but it should be.
// XXX: This is not constant time with respect to |mont->N|, but it should
// be.
unsigned lgBigR = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2;
if (!bn_mod_exp_base_2_vartime(&mont->RR, lgBigR * 2, &mont->N)) {
return 0;
@@ -260,75 +260,87 @@ int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
return BN_mod_mul_montgomery(ret, a, &mont->RR, mont, ctx);
}
static int bn_from_montgomery_in_place(BN_ULONG *r, size_t num_r, BN_ULONG *a,
size_t num_a, const BN_MONT_CTX *mont) {
const BN_ULONG *n = mont->N.d;
size_t num_n = mont->N.top;
if (num_r != num_n || num_a != 2 * num_n) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
// Add multiples of |n| to |r| until R = 2^(nl * BN_BITS2) divides it. On
// input, we had |r| < |n| * R, so now |r| < 2 * |n| * R. Note that |r|
// includes |carry| which is stored separately.
BN_ULONG n0 = mont->n0[0];
BN_ULONG carry = 0;
for (size_t i = 0; i < num_n; i++) {
BN_ULONG v = bn_mul_add_words(a + i, n, num_n, a[i] * n0);
v += carry + a[i + num_n];
carry |= (v != a[i + num_n]);
carry &= (v <= a[i + num_n]);
a[i + num_n] = v;
}
// Shift |num_n| words to divide by R. We have |a| < 2 * |n|. Note that |a|
// includes |carry| which is stored separately.
a += num_n;
// |a| thus requires at most one additional subtraction |n| to be reduced.
// Subtract |n| and select the answer in constant time.
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
crypto_word_t_too_small);
BN_ULONG v = bn_sub_words(r, a, n, num_n) - carry;
// |v| is one if |a| - |n| underflowed or zero if it did not. Note |v| cannot
// be -1. That would imply the subtraction did not fit in |num_n| words, and
// we know at most one subtraction is needed.
v = 0u - v;
for (size_t i = 0; i < num_n; i++) {
r[i] = constant_time_select_w(v, a[i], r[i]);
a[i] = 0;
}
return 1;
}
static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
const BN_MONT_CTX *mont) {
BN_ULONG *ap, *np, *rp, n0, v, carry;
int nl, max, i;
const BIGNUM *n = &mont->N;
if (n->top == 0) {
nl = n->top;
if (nl == 0) {
ret->top = 0;
return 1;
}
int max = (2 * n->top); // carry is stored separately
if (!bn_wexpand(r, max) ||
!bn_wexpand(ret, n->top)) {
max = (2 * nl); // carry is stored separately
if (!bn_wexpand(r, max)) {
return 0;
}
// Clear the top words of |r|.
if (max > r->top) {
OPENSSL_memset(r->d + r->top, 0, (max - r->top) * sizeof(BN_ULONG));
}
r->top = max;
ret->top = n->top;
if (!bn_from_montgomery_in_place(ret->d, ret->top, r->d, r->top, mont)) {
r->neg ^= n->neg;
np = n->d;
rp = r->d;
// clear the top words of T
if (max > r->top) {
OPENSSL_memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG));
}
r->top = max;
n0 = mont->n0[0];
for (carry = 0, i = 0; i < nl; i++, rp++) {
v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2);
v = (v + carry + rp[nl]) & BN_MASK2;
carry |= (v != rp[nl]);
carry &= (v <= rp[nl]);
rp[nl] = v;
}
if (!bn_wexpand(ret, nl)) {
return 0;
}
ret->top = nl;
ret->neg = r->neg;
rp = ret->d;
ap = &(r->d[nl]);
{
BN_ULONG *nrp;
uintptr_t m;
v = bn_sub_words(rp, ap, np, nl) - carry;
// if subtraction result is real, then trick unconditional memcpy below to
// perform in-place "refresh" instead of actual copy.
m = (0u - (uintptr_t)v);
nrp = (BN_ULONG *)(((uintptr_t)rp & ~m) | ((uintptr_t)ap & m));
for (i = 0, nl -= 4; i < nl; i += 4) {
BN_ULONG t1, t2, t3, t4;
t1 = nrp[i + 0];
t2 = nrp[i + 1];
t3 = nrp[i + 2];
ap[i + 0] = 0;
t4 = nrp[i + 3];
ap[i + 1] = 0;
rp[i + 0] = t1;
ap[i + 2] = 0;
rp[i + 1] = t2;
ap[i + 3] = 0;
rp[i + 2] = t3;
rp[i + 3] = t4;
}
for (nl += 4; i < nl; i++) {
rp[i] = nrp[i], ap[i] = 0;
}
}
bn_correct_top(r);
bn_correct_top(ret);
return 1;
}
@@ -416,68 +428,3 @@ err:
BN_CTX_end(ctx);
return ret;
}
int bn_to_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_MONT_CTX *mont) {
return bn_mod_mul_montgomery_small(r, num_r, a, num_a, mont->RR.d,
mont->RR.top, mont);
}
int bn_from_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_MONT_CTX *mont) {
size_t num_n = mont->N.top;
if (num_a > 2 * num_n || num_r != num_n || num_n > BN_SMALL_MAX_WORDS) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
BN_ULONG tmp[BN_SMALL_MAX_WORDS * 2];
size_t num_tmp = 2 * num_n;
OPENSSL_memcpy(tmp, a, num_a * sizeof(BN_ULONG));
OPENSSL_memset(tmp + num_a, 0, (num_tmp - num_a) * sizeof(BN_ULONG));
int ret = bn_from_montgomery_in_place(r, num_r, tmp, num_tmp, mont);
OPENSSL_cleanse(tmp, num_tmp * sizeof(BN_ULONG));
return ret;
}
int bn_mod_mul_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
size_t num_a, const BN_ULONG *b, size_t num_b,
const BN_MONT_CTX *mont) {
size_t num_n = mont->N.top;
if (num_r != num_n || num_a + num_b > 2 * num_n ||
num_n > BN_SMALL_MAX_WORDS) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
#if defined(OPENSSL_BN_ASM_MONT)
// |bn_mul_mont| requires at least 128 bits of limbs, at least for x86.
if (num_n >= (128 / BN_BITS2) &&
num_a == num_n &&
num_b == num_n) {
if (!bn_mul_mont(r, a, b, mont->N.d, mont->n0, num_n)) {
assert(0); // The check above ensures this won't happen.
OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
return 0;
}
return 1;
}
#endif
// Compute the product.
BN_ULONG tmp[2 * BN_SMALL_MAX_WORDS];
size_t num_tmp = 2 * num_n;
size_t num_ab = num_a + num_b;
if (a == b && num_a == num_b) {
if (!bn_sqr_small(tmp, num_ab, a, num_a)) {
return 0;
}
} else if (!bn_mul_small(tmp, num_ab, a, num_a, b, num_b)) {
return 0;
}
// Zero-extend to full width and reduce.
OPENSSL_memset(tmp + num_ab, 0, (num_tmp - num_ab) * sizeof(BN_ULONG));
int ret = bn_from_montgomery_in_place(r, num_r, tmp, num_tmp, mont);
OPENSSL_cleanse(tmp, num_tmp * sizeof(BN_ULONG));
return ret;
}
+60 -93
View File
@@ -59,48 +59,50 @@
#include <assert.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "internal.h"
#include "../../internal.h"
#define BN_MUL_RECURSIVE_SIZE_NORMAL 16
#define BN_SQR_RECURSIVE_SIZE_NORMAL BN_MUL_RECURSIVE_SIZE_NORMAL
static void bn_mul_normal(BN_ULONG *r, const BN_ULONG *a, size_t na,
const BN_ULONG *b, size_t nb) {
static void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b,
int nb) {
BN_ULONG *rr;
if (na < nb) {
size_t itmp = na;
int itmp;
BN_ULONG *ltmp;
itmp = na;
na = nb;
nb = itmp;
const BN_ULONG *ltmp = a;
ltmp = a;
a = b;
b = ltmp;
}
BN_ULONG *rr = &(r[na]);
if (nb == 0) {
OPENSSL_memset(r, 0, na * sizeof(BN_ULONG));
rr = &(r[na]);
if (nb <= 0) {
(void)bn_mul_words(r, a, na, 0);
return;
} else {
rr[0] = bn_mul_words(r, a, na, b[0]);
}
rr[0] = bn_mul_words(r, a, na, b[0]);
for (;;) {
if (--nb == 0) {
if (--nb <= 0) {
return;
}
rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]);
if (--nb == 0) {
if (--nb <= 0) {
return;
}
rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]);
if (--nb == 0) {
if (--nb <= 0) {
return;
}
rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]);
if (--nb == 0) {
if (--nb <= 0) {
return;
}
rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]);
@@ -139,7 +141,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
if (dl < 0) {
for (;;) {
t = b[0];
r[0] = 0 - t - c;
r[0] = (0 - t - c) & BN_MASK2;
if (t != 0) {
c = 1;
}
@@ -148,7 +150,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
}
t = b[1];
r[1] = 0 - t - c;
r[1] = (0 - t - c) & BN_MASK2;
if (t != 0) {
c = 1;
}
@@ -157,7 +159,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
}
t = b[2];
r[2] = 0 - t - c;
r[2] = (0 - t - c) & BN_MASK2;
if (t != 0) {
c = 1;
}
@@ -166,7 +168,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
}
t = b[3];
r[3] = 0 - t - c;
r[3] = (0 - t - c) & BN_MASK2;
if (t != 0) {
c = 1;
}
@@ -181,7 +183,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
int save_dl = dl;
while (c) {
t = a[0];
r[0] = t - c;
r[0] = (t - c) & BN_MASK2;
if (t != 0) {
c = 0;
}
@@ -190,7 +192,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
}
t = a[1];
r[1] = t - c;
r[1] = (t - c) & BN_MASK2;
if (t != 0) {
c = 0;
}
@@ -199,7 +201,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
}
t = a[2];
r[2] = t - c;
r[2] = (t - c) & BN_MASK2;
if (t != 0) {
c = 0;
}
@@ -208,7 +210,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
}
t = a[3];
r[3] = t - c;
r[3] = (t - c) & BN_MASK2;
if (t != 0) {
c = 0;
}
@@ -292,8 +294,8 @@ BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
// a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
// a[1]*b[1]
// dnX may not be positive, but n2/2+dnX has to be
static void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
int n2, int dna, int dnb, BN_ULONG *t) {
static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
int dna, int dnb, BN_ULONG *t) {
int n = n2 / 2, c1, c2;
int tna = n + dna, tnb = n + dnb;
unsigned int neg, zero;
@@ -405,7 +407,7 @@ static void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
if (c1) {
p = &(r[n + n2]);
lo = *p;
ln = lo + c1;
ln = (lo + c1) & BN_MASK2;
*p = ln;
// The overflow will stop before we over write
@@ -414,7 +416,7 @@ static void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
do {
p++;
lo = *p;
ln = lo + 1;
ln = (lo + 1) & BN_MASK2;
*p = ln;
} while (ln == 0);
}
@@ -424,9 +426,8 @@ static void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
// n+tn is the word length
// t needs to be n*4 is size, as does r
// tnX may not be negative but less than n
static void bn_mul_part_recursive(BN_ULONG *r, const BN_ULONG *a,
const BN_ULONG *b, int n, int tna, int tnb,
BN_ULONG *t) {
static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
int tna, int tnb, BN_ULONG *t) {
int i, j, n2 = n * 2;
int c1, c2, neg;
BN_ULONG ln, lo, *p;
@@ -543,7 +544,7 @@ static void bn_mul_part_recursive(BN_ULONG *r, const BN_ULONG *a,
if (c1) {
p = &(r[n + n2]);
lo = *p;
ln = lo + c1;
ln = (lo + c1) & BN_MASK2;
*p = ln;
// The overflow will stop before we over write
@@ -552,7 +553,7 @@ static void bn_mul_part_recursive(BN_ULONG *r, const BN_ULONG *a,
do {
p++;
lo = *p;
ln = lo + 1;
ln = (lo + 1) & BN_MASK2;
*p = ln;
} while (ln == 0);
}
@@ -657,57 +658,38 @@ err:
return ret;
}
int bn_mul_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a,
const BN_ULONG *b, size_t num_b) {
if (num_r != num_a + num_b) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
// TODO(davidben): Should this call |bn_mul_comba4| too? |BN_mul| does not
// hit that code.
if (num_a == 8 && num_b == 8) {
bn_mul_comba8(r, a, b);
} else {
bn_mul_normal(r, a, num_a, b, num_b);
}
return 1;
}
// tmp must have 2*n words
static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, size_t n,
BN_ULONG *tmp) {
if (n == 0) {
return;
}
static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp) {
int i, j, max;
const BN_ULONG *ap;
BN_ULONG *rp;
size_t max = n * 2;
const BN_ULONG *ap = a;
BN_ULONG *rp = r;
max = n * 2;
ap = a;
rp = r;
rp[0] = rp[max - 1] = 0;
rp++;
j = n;
// Compute the contribution of a[i] * a[j] for all i < j.
if (n > 1) {
if (--j > 0) {
ap++;
rp[n - 1] = bn_mul_words(rp, ap, n - 1, ap[-1]);
rp[j] = bn_mul_words(rp, ap, j, ap[-1]);
rp += 2;
}
if (n > 2) {
for (size_t i = n - 2; i > 0; i--) {
ap++;
rp[i] = bn_mul_add_words(rp, ap, i, ap[-1]);
rp += 2;
}
for (i = n - 2; i > 0; i--) {
j--;
ap++;
rp[j] = bn_mul_add_words(rp, ap, j, ap[-1]);
rp += 2;
}
// The final result fits in |max| words, so none of the following operations
// will overflow.
// Double |r|, giving the contribution of a[i] * a[j] for all i != j.
bn_add_words(r, r, r, max);
// Add in the contribution of a[i] * a[i] for all i.
// There will not be a carry
bn_sqr_words(tmp, a, n);
bn_add_words(r, r, tmp, max);
}
@@ -720,8 +702,7 @@ static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, size_t n,
// a[0]*b[0]
// a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
// a[1]*b[1]
static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2,
BN_ULONG *t) {
static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t) {
int n = n2 / 2;
int zero, c1;
BN_ULONG ln, lo, *p;
@@ -776,7 +757,7 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2,
if (c1) {
p = &(r[n + n2]);
lo = *p;
ln = lo + c1;
ln = (lo + c1) & BN_MASK2;
*p = ln;
// The overflow will stop before we over write
@@ -785,7 +766,7 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2,
do {
p++;
lo = *p;
ln = lo + 1;
ln = (lo + 1) & BN_MASK2;
*p = ln;
} while (ln == 0);
}
@@ -793,6 +774,9 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2,
}
int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
BN_ULONG ll;
w &= BN_MASK2;
if (!bn->top) {
return 1;
}
@@ -802,7 +786,7 @@ int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
return 1;
}
BN_ULONG ll = bn_mul_words(bn->d, bn->d, bn->top, w);
ll = bn_mul_words(bn->d, bn->d, bn->top, w);
if (ll) {
if (!bn_wexpand(bn, bn->top + 1)) {
return 0;
@@ -883,20 +867,3 @@ err:
BN_CTX_end(ctx);
return ret;
}
int bn_sqr_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a) {
if (num_r != 2 * num_a || num_a > BN_SMALL_MAX_WORDS) {
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
if (num_a == 4) {
bn_sqr_comba4(r, a);
} else if (num_a == 8) {
bn_sqr_comba8(r, a);
} else {
BN_ULONG tmp[2 * BN_SMALL_MAX_WORDS];
bn_sqr_normal(r, a, num_a, tmp);
OPENSSL_cleanse(tmp, 2 * num_a * sizeof(BN_ULONG));
}
return 1;
}
+64 -80
View File
@@ -113,16 +113,18 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <openssl/type_check.h>
#include "internal.h"
#include "../../internal.h"
#include "../rand/internal.h"
static const uint8_t kDefaultAdditionalData[32] = {0};
int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
static int bn_rand_with_additional_data(BIGNUM *rnd, int bits, int top,
int bottom,
const uint8_t additional_data[32]) {
uint8_t *buf = NULL;
int ret = 0, bit, bytes, mask;
@@ -157,7 +159,7 @@ int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
}
// Make a random number and set the top and bottom bits.
RAND_bytes(buf, bytes);
RAND_bytes_with_additional_data(buf, bytes, additional_data);
if (top != BN_RAND_TOP_ANY) {
if (top == BN_RAND_TOP_TWO && bits > 1) {
@@ -190,104 +192,54 @@ err:
return ret;
}
int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
return bn_rand_with_additional_data(rnd, bits, top, bottom,
kDefaultAdditionalData);
}
int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom) {
return BN_rand(rnd, bits, top, bottom);
}
// bn_less_than_word returns one if the number represented by |len| words at |a|
// is less than |b| and zero otherwise. It performs this computation in time
// independent of the value of |a|. |b| is assumed public.
static int bn_less_than_word(const BN_ULONG *a, size_t len, BN_ULONG b) {
if (b == 0) {
return 0;
}
if (len == 0) {
return 1;
}
// |a| < |b| iff a[1..len-1] are all zero and a[0] < b.
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
crypto_word_t_too_small);
crypto_word_t mask = 0;
for (size_t i = 1; i < len; i++) {
mask |= a[i];
}
// |mask| is now zero iff a[1..len-1] are all zero.
mask = constant_time_is_zero_w(mask);
mask &= constant_time_lt_w(a[0], b);
return constant_time_select_int(mask, 1, 0);
}
int bn_in_range_words(const BN_ULONG *a, BN_ULONG min_inclusive,
const BN_ULONG *max_exclusive, size_t len) {
return bn_less_than_words(a, max_exclusive, len) &&
!bn_less_than_word(a, len, min_inclusive);
}
int bn_rand_range_words(BN_ULONG *out, BN_ULONG min_inclusive,
const BN_ULONG *max_exclusive, size_t len,
const uint8_t additional_data[32]) {
// This function implements the equivalent of steps 4 through 7 of FIPS 186-4
// appendices B.4.2 and B.5.2. When called in those contexts, |max_exclusive|
// is n and |min_inclusive| is one.
// Compute the bit length of |max_exclusive| (step 1), in terms of a number of
// |words| worth of entropy to fill and a mask of bits to clear in the top
// word.
size_t words = len;
while (words > 0 && max_exclusive[words - 1] == 0) {
words--;
}
if (words == 0 ||
(words == 1 && max_exclusive[0] <= min_inclusive)) {
static int bn_rand_range_with_additional_data(
BIGNUM *r, BN_ULONG min_inclusive, const BIGNUM *max_exclusive,
const uint8_t additional_data[32]) {
if (BN_cmp_word(max_exclusive, min_inclusive) <= 0) {
OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE);
return 0;
}
BN_ULONG mask = max_exclusive[words - 1];
// This sets all bits in |mask| below the most significant bit.
mask |= mask >> 1;
mask |= mask >> 2;
mask |= mask >> 4;
mask |= mask >> 8;
mask |= mask >> 16;
#if defined(OPENSSL_64_BIT)
mask |= mask >> 32;
#endif
// Fill any unused words with zero.
OPENSSL_memset(out + words, 0, (len - words) * sizeof(BN_ULONG));
// This function is used to implement steps 4 through 7 of FIPS 186-4
// appendices B.4.2 and B.5.2. When called in those contexts, |max_exclusive|
// is n and |min_inclusive| is one.
unsigned count = 100;
unsigned n = BN_num_bits(max_exclusive); // n > 0
do {
if (!--count) {
OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS);
return 0;
}
// Steps 4 and 5. Use |words| and |mask| together to obtain a string of N
// bits, where N is the bit length of |max_exclusive|.
RAND_bytes_with_additional_data((uint8_t *)out, words * sizeof(BN_ULONG),
additional_data);
out[words - 1] &= mask;
if (// steps 4 and 5
!bn_rand_with_additional_data(r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY,
additional_data) ||
// step 7
!BN_add_word(r, min_inclusive)) {
return 0;
}
// Step 6. This loops if |r| >= |max_exclusive|. This is identical to
// checking |r| > |max_exclusive| - 1 or |r| - 1 > |max_exclusive| - 2, the
// formulation stated in FIPS 186-4.
} while (BN_cmp(r, max_exclusive) >= 0);
// If out >= max_exclusive or out < min_inclusive, retry. This implements
// the equivalent of steps 6 and 7 without leaking the value of |out|.
} while (!bn_in_range_words(out, min_inclusive, max_exclusive, words));
return 1;
}
int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive,
const BIGNUM *max_exclusive) {
if (!bn_wexpand(r, max_exclusive->top) ||
!bn_rand_range_words(r->d, min_inclusive, max_exclusive->d,
max_exclusive->top, kDefaultAdditionalData)) {
return 0;
}
r->neg = 0;
r->top = max_exclusive->top;
bn_correct_top(r);
return 1;
return bn_rand_range_with_additional_data(r, min_inclusive, max_exclusive,
kDefaultAdditionalData);
}
int BN_rand_range(BIGNUM *r, const BIGNUM *range) {
@@ -297,3 +249,35 @@ int BN_rand_range(BIGNUM *r, const BIGNUM *range) {
int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) {
return BN_rand_range(r, range);
}
int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv,
const uint8_t *message, size_t message_len,
BN_CTX *ctx) {
// We copy |priv| into a local buffer to avoid furthur exposing its
// length.
uint8_t private_bytes[96];
size_t todo = sizeof(priv->d[0]) * priv->top;
if (todo > sizeof(private_bytes)) {
// No reasonable DSA or ECDSA key should have a private key
// this large and we don't handle this case in order to avoid
// leaking the length of the private key.
OPENSSL_PUT_ERROR(BN, BN_R_PRIVATE_KEY_TOO_LARGE);
return 0;
}
OPENSSL_memcpy(private_bytes, priv->d, todo);
OPENSSL_memset(private_bytes + todo, 0, sizeof(private_bytes) - todo);
// Pass a SHA512 hash of the private key and message as additional data into
// the RBG. This is a hardening measure against entropy failure.
OPENSSL_COMPILE_ASSERT(SHA512_DIGEST_LENGTH >= 32,
additional_data_is_too_large_for_sha512);
SHA512_CTX sha;
uint8_t digest[SHA512_DIGEST_LENGTH];
SHA512_Init(&sha);
SHA512_Update(&sha, private_bytes, sizeof(private_bytes));
SHA512_Update(&sha, message, message_len);
SHA512_Final(digest, &sha);
// Select a value k from [1, range-1], following FIPS 186-4 appendix B.5.2.
return bn_rand_range_with_additional_data(out, 1, range, digest);
}
+28 -26
View File
@@ -90,8 +90,8 @@ int BN_lshift(BIGNUM *r, const BIGNUM *a, int n) {
} else {
for (i = a->top - 1; i >= 0; i--) {
l = f[i];
t[nw + i + 1] |= l >> rb;
t[nw + i] = l << lb;
t[nw + i + 1] |= (l >> rb) & BN_MASK2;
t[nw + i] = (l << lb) & BN_MASK2;
}
}
OPENSSL_memset(t, 0, nw * sizeof(t[0]));
@@ -121,8 +121,8 @@ int BN_lshift1(BIGNUM *r, const BIGNUM *a) {
c = 0;
for (i = 0; i < a->top; i++) {
t = *(ap++);
*(rp++) = (t << 1) | c;
c = t >> (BN_BITS2 - 1);
*(rp++) = ((t << 1) | c) & BN_MASK2;
c = (t & BN_TBIT) ? 1 : 0;
}
if (c) {
*rp = 1;
@@ -173,12 +173,11 @@ int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) {
} else {
l = *(f++);
for (i = j - 1; i != 0; i--) {
tmp = l >> rb;
tmp = (l >> rb) & BN_MASK2;
l = *(f++);
*(t++) = tmp | (l << lb);
*(t++) = (tmp | (l << lb)) & BN_MASK2;
}
l >>= rb;
if (l) {
if ((l = (l >> rb) & BN_MASK2)) {
*(t) = l;
}
}
@@ -209,14 +208,14 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a) {
}
rp = r->d;
t = ap[--i];
c = t << (BN_BITS2 - 1);
c = (t & 1) ? BN_TBIT : 0;
if (t >>= 1) {
rp[i] = t;
}
while (i > 0) {
t = ap[--i];
rp[i] = (t >> 1) | c;
c = t << (BN_BITS2 - 1);
rp[i] = ((t >> 1) & BN_MASK2) | c;
c = (t & 1) ? BN_TBIT : 0;
}
r->top = j;
@@ -228,17 +227,19 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a) {
}
int BN_set_bit(BIGNUM *a, int n) {
int i, j, k;
if (n < 0) {
return 0;
}
int i = n / BN_BITS2;
int j = n % BN_BITS2;
i = n / BN_BITS2;
j = n % BN_BITS2;
if (a->top <= i) {
if (!bn_wexpand(a, i + 1)) {
return 0;
}
for (int k = a->top; k < i + 1; k++) {
for (k = a->top; k < i + 1; k++) {
a->d[k] = 0;
}
a->top = i + 1;
@@ -267,29 +268,30 @@ int BN_clear_bit(BIGNUM *a, int n) {
return 1;
}
int bn_is_bit_set_words(const BN_ULONG *a, size_t num, unsigned bit) {
unsigned i = bit / BN_BITS2;
unsigned j = bit % BN_BITS2;
if (i >= num) {
return 0;
}
return (a[i] >> j) & 1;
}
int BN_is_bit_set(const BIGNUM *a, int n) {
int i, j;
if (n < 0) {
return 0;
}
return bn_is_bit_set_words(a->d, a->top, n);
i = n / BN_BITS2;
j = n % BN_BITS2;
if (a->top <= i) {
return 0;
}
return (a->d[i]>>j)&1;
}
int BN_mask_bits(BIGNUM *a, int n) {
int b, w;
if (n < 0) {
return 0;
}
int w = n / BN_BITS2;
int b = n % BN_BITS2;
w = n / BN_BITS2;
b = n % BN_BITS2;
if (w >= a->top) {
return 0;
}
-2
View File
@@ -611,5 +611,3 @@ int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
int EVP_add_cipher_alias(const char *a, const char *b) {
return 1;
}
void EVP_CIPHER_CTX_set_flags(const EVP_CIPHER_CTX *ctx, uint32_t flags) {}
+151 -252
View File
@@ -77,12 +77,9 @@
#include "internal.h"
#include "../../internal.h"
#include "../bn/internal.h"
#include "../delocate.h"
static void ec_point_free(EC_POINT *point, int free_group);
static const uint8_t kP224Params[6 * 28] = {
// p
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -280,6 +277,63 @@ DEFINE_METHOD_FUNCTION(struct built_in_curves, OPENSSL_built_in_curves) {
#endif
}
// built_in_curve_scalar_field_monts contains Montgomery contexts for
// performing inversions in the scalar fields of each of the built-in
// curves. It's protected by |built_in_curve_scalar_field_monts_once|.
DEFINE_LOCAL_DATA(BN_MONT_CTX **, built_in_curve_scalar_field_monts) {
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
BN_MONT_CTX **monts =
OPENSSL_malloc(sizeof(BN_MONT_CTX *) * OPENSSL_NUM_BUILT_IN_CURVES);
if (monts == NULL) {
return;
}
OPENSSL_memset(monts, 0, sizeof(BN_MONT_CTX *) * OPENSSL_NUM_BUILT_IN_CURVES);
BIGNUM *order = BN_new();
BN_CTX *bn_ctx = BN_CTX_new();
BN_MONT_CTX *mont_ctx = NULL;
if (bn_ctx == NULL ||
order == NULL) {
goto err;
}
for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
const struct built_in_curve *curve = &curves->curves[i];
const unsigned param_len = curve->param_len;
const uint8_t *params = curve->params;
mont_ctx = BN_MONT_CTX_new();
if (mont_ctx == NULL) {
goto err;
}
if (!BN_bin2bn(params + 5 * param_len, param_len, order) ||
!BN_MONT_CTX_set(mont_ctx, order, bn_ctx)) {
goto err;
}
monts[i] = mont_ctx;
mont_ctx = NULL;
}
*out = monts;
goto done;
err:
BN_MONT_CTX_free(mont_ctx);
for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
BN_MONT_CTX_free(monts[i]);
}
OPENSSL_free((BN_MONT_CTX**) monts);
done:
BN_free(order);
BN_CTX_free(bn_ctx);
}
EC_GROUP *ec_group_new(const EC_METHOD *meth) {
EC_GROUP *ret;
@@ -300,7 +354,6 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) {
}
OPENSSL_memset(ret, 0, sizeof(EC_GROUP));
ret->references = 1;
ret->meth = meth;
BN_init(&ret->order);
@@ -312,35 +365,16 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) {
return ret;
}
static void ec_group_set0_generator(EC_GROUP *group, EC_POINT *generator) {
assert(group->generator == NULL);
assert(group == generator->group);
// Avoid a reference cycle. |group->generator| does not maintain an owning
// pointer to |group|.
group->generator = generator;
int is_zero = CRYPTO_refcount_dec_and_test_zero(&group->references);
assert(!is_zero);
(void)is_zero;
}
EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *ctx) {
if (BN_num_bytes(p) > EC_MAX_SCALAR_BYTES) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FIELD);
return NULL;
}
EC_GROUP *ret = ec_group_new(EC_GFp_mont_method());
if (ret == NULL) {
return NULL;
}
if (ret->meth->group_set_curve == NULL) {
if (ret->meth->group_set_curve == 0) {
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
EC_GROUP_free(ret);
return NULL;
return 0;
}
if (!ret->meth->group_set_curve(ret, p, a, b, ctx)) {
EC_GROUP_free(ret);
@@ -351,19 +385,9 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
const BIGNUM *order, const BIGNUM *cofactor) {
if (group->curve_name != NID_undef || group->generator != NULL ||
generator->group != group) {
if (group->curve_name != NID_undef || group->generator != NULL) {
// |EC_GROUP_set_generator| may only be used with |EC_GROUP|s returned by
// |EC_GROUP_new_curve_GFp| and may only used once on each group.
// Additionally, |generator| must been created from
// |EC_GROUP_new_curve_GFp|, not a copy, so that
// |generator->group->generator| is set correctly.
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
if (BN_num_bytes(order) > EC_MAX_SCALAR_BYTES) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FIELD);
return 0;
}
@@ -373,44 +397,15 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
return 0;
}
// Require that p < 2×order. This simplifies some ECDSA operations.
//
// Note any curve which did not satisfy this must have been invalid or use a
// tiny prime (less than 17). See the proof in |field_element_to_scalar| in
// the ECDSA implementation.
BIGNUM *tmp = BN_new();
if (tmp == NULL ||
!BN_lshift1(tmp, order)) {
BN_free(tmp);
return 0;
}
int ok = BN_cmp(tmp, &group->field) > 0;
BN_free(tmp);
if (!ok) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER);
return 0;
}
EC_POINT *copy = EC_POINT_new(group);
if (copy == NULL ||
!EC_POINT_copy(copy, generator) ||
!BN_copy(&group->order, order)) {
EC_POINT_free(copy);
return 0;
}
BN_MONT_CTX_free(group->order_mont);
group->order_mont = BN_MONT_CTX_new();
if (group->order_mont == NULL ||
!BN_MONT_CTX_set(group->order_mont, &group->order, NULL)) {
return 0;
}
ec_group_set0_generator(group, copy);
return 1;
group->generator = EC_POINT_new(group);
return group->generator != NULL &&
EC_POINT_copy(group->generator, generator) &&
BN_copy(&group->order, order);
}
static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) {
static EC_GROUP *ec_group_new_from_data(unsigned built_in_index) {
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
const struct built_in_curve *curve = &curves->curves[built_in_index];
EC_GROUP *group = NULL;
EC_POINT *P = NULL;
BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL;
@@ -459,14 +454,12 @@ static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) {
goto err;
}
group->order_mont = BN_MONT_CTX_new();
if (group->order_mont == NULL ||
!BN_MONT_CTX_set(group->order_mont, &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
const BN_MONT_CTX **monts = *built_in_curve_scalar_field_monts();
if (monts != NULL) {
group->order_mont = monts[built_in_index];
}
ec_group_set0_generator(group, P);
group->generator = P;
P = NULL;
ok = 1;
@@ -485,118 +478,87 @@ err:
return group;
}
// Built-in groups are allocated lazily and static once allocated.
// TODO(davidben): Make these actually static. https://crbug.com/boringssl/20.
struct built_in_groups_st {
EC_GROUP *groups[OPENSSL_NUM_BUILT_IN_CURVES];
};
DEFINE_BSS_GET(struct built_in_groups_st, built_in_groups);
DEFINE_STATIC_MUTEX(built_in_groups_lock);
EC_GROUP *EC_GROUP_new_by_curve_name(int nid) {
struct built_in_groups_st *groups = built_in_groups_bss_get();
EC_GROUP **group_ptr = NULL;
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
const struct built_in_curve *curve = NULL;
EC_GROUP *ret = NULL;
for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
if (curves->curves[i].nid == nid) {
curve = &curves->curves[i];
group_ptr = &groups->groups[i];
const struct built_in_curve *curve = &curves->curves[i];
if (curve->nid == nid) {
ret = ec_group_new_from_data(i);
break;
}
}
if (curve == NULL) {
if (ret == NULL) {
OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
return NULL;
}
CRYPTO_STATIC_MUTEX_lock_read(built_in_groups_lock_bss_get());
EC_GROUP *ret = *group_ptr;
CRYPTO_STATIC_MUTEX_unlock_read(built_in_groups_lock_bss_get());
if (ret != NULL) {
return ret;
}
ret = ec_group_new_from_data(curve);
if (ret == NULL) {
return NULL;
}
EC_GROUP *to_free = NULL;
CRYPTO_STATIC_MUTEX_lock_write(built_in_groups_lock_bss_get());
if (*group_ptr == NULL) {
*group_ptr = ret;
// Filling in |ret->curve_name| makes |EC_GROUP_free| and |EC_GROUP_dup|
// into no-ops. At this point, |ret| is considered static.
ret->curve_name = nid;
} else {
to_free = ret;
ret = *group_ptr;
}
CRYPTO_STATIC_MUTEX_unlock_write(built_in_groups_lock_bss_get());
EC_GROUP_free(to_free);
ret->curve_name = nid;
return ret;
}
void EC_GROUP_free(EC_GROUP *group) {
if (group == NULL ||
// Built-in curves are static.
group->curve_name != NID_undef ||
!CRYPTO_refcount_dec_and_test_zero(&group->references)) {
if (!group) {
return;
}
if (group->meth->group_finish != NULL) {
if (group->meth->group_finish != 0) {
group->meth->group_finish(group);
}
ec_point_free(group->generator, 0 /* don't free group */);
EC_POINT_free(group->generator);
BN_free(&group->order);
BN_MONT_CTX_free(group->order_mont);
OPENSSL_free(group);
}
const BN_MONT_CTX *ec_group_get_order_mont(const EC_GROUP *group) {
return group->order_mont;
}
EC_GROUP *EC_GROUP_dup(const EC_GROUP *a) {
if (a == NULL ||
// Built-in curves are static.
a->curve_name != NID_undef) {
return (EC_GROUP *)a;
if (a == NULL) {
return NULL;
}
// Groups are logically immutable (but for |EC_GROUP_set_generator| which must
// be called early on), so we simply take a reference.
EC_GROUP *group = (EC_GROUP *)a;
CRYPTO_refcount_inc(&group->references);
return group;
if (a->meth->group_copy == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return NULL;
}
EC_GROUP *ret = ec_group_new(a->meth);
if (ret == NULL) {
return NULL;
}
ret->order_mont = a->order_mont;
ret->curve_name = a->curve_name;
if (a->generator != NULL) {
ret->generator = EC_POINT_dup(a->generator, ret);
if (ret->generator == NULL) {
goto err;
}
}
if (!BN_copy(&ret->order, &a->order) ||
!ret->meth->group_copy(ret, a)) {
goto err;
}
return ret;
err:
EC_GROUP_free(ret);
return NULL;
}
int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ignored) {
// Note this function returns 0 if equal and non-zero otherwise.
if (a == b) {
return 0;
}
if (a->curve_name != b->curve_name) {
return 1;
}
if (a->curve_name != NID_undef) {
// Built-in curves may be compared by curve name alone.
return 0;
}
// |a| and |b| are both custom curves. We compare the entire curve
// structure. If |a| or |b| is incomplete (due to legacy OpenSSL mistakes,
// custom curve construction is sadly done in two parts) but otherwise not the
// same object, we consider them always unequal.
return a->generator == NULL ||
b->generator == NULL ||
BN_cmp(&a->order, &b->order) != 0 ||
BN_cmp(&a->field, &b->field) != 0 ||
BN_cmp(&a->a, &b->a) != 0 ||
BN_cmp(&a->b, &b->b) != 0 ||
ec_GFp_simple_cmp(a, a->generator, b->generator, NULL) != 0;
return a->curve_name == NID_undef ||
b->curve_name == NID_undef ||
a->curve_name != b->curve_name;
}
const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) {
@@ -646,9 +608,9 @@ EC_POINT *EC_POINT_new(const EC_GROUP *group) {
return NULL;
}
ret->group = EC_GROUP_dup(group);
if (ret->group == NULL ||
!ec_GFp_simple_point_init(ret)) {
ret->meth = group->meth;
if (!ec_GFp_simple_point_init(ret)) {
OPENSSL_free(ret);
return NULL;
}
@@ -656,25 +618,28 @@ EC_POINT *EC_POINT_new(const EC_GROUP *group) {
return ret;
}
static void ec_point_free(EC_POINT *point, int free_group) {
void EC_POINT_free(EC_POINT *point) {
if (!point) {
return;
}
ec_GFp_simple_point_finish(point);
if (free_group) {
EC_GROUP_free(point->group);
}
OPENSSL_free(point);
}
void EC_POINT_free(EC_POINT *point) {
ec_point_free(point, 1 /* free group */);
void EC_POINT_clear_free(EC_POINT *point) {
if (!point) {
return;
}
ec_GFp_simple_point_clear_finish(point);
OPENSSL_free(point);
}
void EC_POINT_clear_free(EC_POINT *point) { EC_POINT_free(point); }
int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src) {
if (EC_GROUP_cmp(dest->group, src->group, NULL) != 0) {
if (dest->meth != src->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -700,7 +665,7 @@ EC_POINT *EC_POINT_dup(const EC_POINT *a, const EC_GROUP *group) {
}
int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
if (group->meth != point->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -708,7 +673,7 @@ int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) {
}
int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
if (group->meth != point->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -717,7 +682,7 @@ int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) {
int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
BN_CTX *ctx) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
if (group->meth != point->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -726,8 +691,7 @@ int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b,
BN_CTX *ctx) {
if (EC_GROUP_cmp(group, a->group, NULL) != 0 ||
EC_GROUP_cmp(group, b->group, NULL) != 0) {
if ((group->meth != a->meth) || (a->meth != b->meth)) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return -1;
}
@@ -735,7 +699,7 @@ int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b,
}
int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
if (group->meth != point->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -745,7 +709,7 @@ int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) {
int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[],
BN_CTX *ctx) {
for (size_t i = 0; i < num; i++) {
if (EC_GROUP_cmp(group, points[i]->group, NULL) != 0) {
if (group->meth != points[i]->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -760,7 +724,7 @@ int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
if (group->meth != point->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -770,7 +734,7 @@ int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
const BIGNUM *x, const BIGNUM *y,
BN_CTX *ctx) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
if (group->meth != point->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -788,9 +752,8 @@ int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
const EC_POINT *b, BN_CTX *ctx) {
if (EC_GROUP_cmp(group, r->group, NULL) != 0 ||
EC_GROUP_cmp(group, a->group, NULL) != 0 ||
EC_GROUP_cmp(group, b->group, NULL) != 0) {
if ((group->meth != r->meth) || (r->meth != a->meth) ||
(a->meth != b->meth)) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -800,8 +763,7 @@ int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
BN_CTX *ctx) {
if (EC_GROUP_cmp(group, r->group, NULL) != 0 ||
EC_GROUP_cmp(group, a->group, NULL) != 0) {
if ((group->meth != r->meth) || (r->meth != a->meth)) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -810,7 +772,7 @@ int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) {
if (EC_GROUP_cmp(group, a->group, NULL) != 0) {
if (group->meth != a->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -823,59 +785,13 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
// nothing to multiply. But, nobody should be calling this function with
// nothing to multiply in the first place.
if ((g_scalar == NULL && p_scalar == NULL) ||
(p == NULL) != (p_scalar == NULL)) {
((p == NULL) != (p_scalar == NULL))) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
// We cannot easily process arbitrary scalars in constant-time, and there is
// no need to do so. Require that scalars be the same size as the order.
//
// One could require they be fully reduced, but some consumers try to check
// that |order| * |pubkey| is the identity. This comes from following NIST SP
// 800-56A section 5.6.2.3.2. (Though all our curves have cofactor one, so
// this check isn't useful.)
int ret = 0;
EC_SCALAR g_scalar_storage, p_scalar_storage;
EC_SCALAR *g_scalar_arg = NULL, *p_scalar_arg = NULL;
unsigned order_bits = BN_num_bits(&group->order);
if (g_scalar != NULL) {
if (BN_is_negative(g_scalar) || BN_num_bits(g_scalar) > order_bits ||
!ec_bignum_to_scalar(group, &g_scalar_storage, g_scalar)) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
goto err;
}
g_scalar_arg = &g_scalar_storage;
}
if (p_scalar != NULL) {
if (BN_is_negative(p_scalar) || BN_num_bits(p_scalar) > order_bits ||
!ec_bignum_to_scalar(group, &p_scalar_storage, p_scalar)) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
goto err;
}
p_scalar_arg = &p_scalar_storage;
}
ret = ec_point_mul_scalar(group, r, g_scalar_arg, p, p_scalar_arg, ctx);
err:
OPENSSL_cleanse(&g_scalar_storage, sizeof(g_scalar_storage));
OPENSSL_cleanse(&p_scalar_storage, sizeof(p_scalar_storage));
return ret;
}
int ec_point_mul_scalar(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar, const EC_POINT *p,
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
if ((g_scalar == NULL && p_scalar == NULL) ||
(p == NULL) != (p_scalar == NULL)) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (EC_GROUP_cmp(group, r->group, NULL) != 0 ||
(p != NULL && EC_GROUP_cmp(group, p->group, NULL) != 0)) {
if (group->meth != r->meth ||
(p != NULL && group->meth != p->meth)) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -887,7 +803,7 @@ int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
const BIGNUM *y, const BIGNUM *z,
BN_CTX *ctx) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
if (group->meth != point->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -924,20 +840,3 @@ size_t EC_get_builtin_curves(EC_builtin_curve *out_curves,
return OPENSSL_NUM_BUILT_IN_CURVES;
}
int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
const BIGNUM *in) {
if (BN_is_negative(in) || in->top > group->order.top) {
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
return 0;
}
OPENSSL_memset(out->words, 0, group->order.top * sizeof(BN_ULONG));
OPENSSL_memcpy(out->words, in->d, in->top * sizeof(BN_ULONG));
return 1;
}
int ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out,
const uint8_t additional_data[32]) {
return bn_rand_range_words(out->words, 1, group->order.d, group->order.top,
additional_data);
}
+27
View File
@@ -90,6 +90,32 @@ void ec_GFp_mont_group_finish(EC_GROUP *group) {
ec_GFp_simple_group_finish(group);
}
int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) {
BN_MONT_CTX_free(dest->mont);
dest->mont = NULL;
if (!ec_GFp_simple_group_copy(dest, src)) {
return 0;
}
if (src->mont != NULL) {
dest->mont = BN_MONT_CTX_new();
if (dest->mont == NULL) {
return 0;
}
if (!BN_MONT_CTX_copy(dest->mont, src->mont)) {
goto err;
}
}
return 1;
err:
BN_MONT_CTX_free(dest->mont);
dest->mont = NULL;
return 0;
}
int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
BN_CTX *new_ctx = NULL;
@@ -267,6 +293,7 @@ err:
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_mont_method) {
out->group_init = ec_GFp_mont_group_init;
out->group_finish = ec_GFp_mont_group_finish;
out->group_copy = ec_GFp_mont_group_copy;
out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates = ec_GFp_mont_point_get_affine_coordinates;
out->mul = ec_wNAF_mul /* XXX: Not constant time. */;
-59
View File
@@ -276,33 +276,6 @@ TEST(ECTest, ArbitraryCurve) {
// The key must be valid according to the new group too.
EXPECT_TRUE(EC_KEY_check_key(key2.get()));
// Make a second instance of |group|.
bssl::UniquePtr<EC_GROUP> group2(
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
ASSERT_TRUE(group2);
bssl::UniquePtr<EC_POINT> generator2(EC_POINT_new(group2.get()));
ASSERT_TRUE(generator2);
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
group2.get(), generator2.get(), gx.get(), gy.get(), ctx.get()));
ASSERT_TRUE(EC_GROUP_set_generator(group2.get(), generator2.get(),
order.get(), BN_value_one()));
EXPECT_EQ(0, EC_GROUP_cmp(group.get(), group.get(), NULL));
EXPECT_EQ(0, EC_GROUP_cmp(group2.get(), group.get(), NULL));
// group3 uses the wrong generator.
bssl::UniquePtr<EC_GROUP> group3(
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
ASSERT_TRUE(group3);
bssl::UniquePtr<EC_POINT> generator3(EC_POINT_new(group3.get()));
ASSERT_TRUE(generator3);
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
group3.get(), generator3.get(), x.get(), y.get(), ctx.get()));
ASSERT_TRUE(EC_GROUP_set_generator(group3.get(), generator3.get(),
order.get(), BN_value_one()));
EXPECT_NE(0, EC_GROUP_cmp(group.get(), group3.get(), NULL));
}
class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
@@ -407,38 +380,6 @@ TEST_P(ECCurveTest, MulZero) {
<< "p * 0 did not return point at infinity.";
}
// Test that multiplying by the order produces ∞ and, moreover, that callers may
// do so. |EC_POINT_mul| is almost exclusively used with reduced scalars, with
// this exception. This comes from consumers following NIST SP 800-56A section
// 5.6.2.3.2. (Though all our curves have cofactor one, so this check isn't
// useful.)
TEST_P(ECCurveTest, MulOrder) {
bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
ASSERT_TRUE(group);
// Test that g × order = ∞.
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
ASSERT_TRUE(point);
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(),
EC_GROUP_get0_order(group.get()), nullptr, nullptr,
nullptr));
EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
<< "g * order did not return point at infinity.";
// Test that p × order = ∞, for some arbitrary p.
bssl::UniquePtr<BIGNUM> forty_two(BN_new());
ASSERT_TRUE(forty_two);
ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), forty_two.get(), nullptr,
nullptr, nullptr));
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), nullptr, point.get(),
EC_GROUP_get0_order(group.get()), nullptr));
EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
<< "p * order did not return point at infinity.";
}
// Test that 10×∞ + G = G.
TEST_P(ECCurveTest, Mul) {
bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
+19 -53
View File
@@ -73,37 +73,16 @@
#include <openssl/bn.h>
#include <openssl/ex_data.h>
#include <openssl/thread.h>
#include <openssl/type_check.h>
#include "../bn/internal.h"
#if defined(__cplusplus)
extern "C" {
#endif
// Cap the size of all field elements and scalars, including custom curves, to
// 66 bytes, large enough to fit secp521r1 and brainpoolP512r1, which appear to
// be the largest fields anyone plausibly uses.
#define EC_MAX_SCALAR_BYTES 66
#define EC_MAX_SCALAR_WORDS ((66 + BN_BYTES - 1) / BN_BYTES)
OPENSSL_COMPILE_ASSERT(EC_MAX_SCALAR_WORDS <= BN_SMALL_MAX_WORDS,
bn_small_functions_applicable);
// An EC_SCALAR is a |BN_num_bits(order)|-bit integer. Only the first
// |order->top| words are used. An |EC_SCALAR| is specific to an |EC_GROUP| and
// must not be mixed between groups. Unless otherwise specified, it is fully
// reduced modulo the |order|.
typedef union {
// bytes is the representation of the scalar in little-endian order.
uint8_t bytes[EC_MAX_SCALAR_BYTES];
BN_ULONG words[EC_MAX_SCALAR_WORDS];
} EC_SCALAR;
struct ec_method_st {
int (*group_init)(EC_GROUP *);
void (*group_finish)(EC_GROUP *);
int (*group_copy)(EC_GROUP *, const EC_GROUP *);
int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *);
int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *,
@@ -114,8 +93,8 @@ struct ec_method_st {
// Computes |r = p_scalar*p| if g_scalar is null. At least one of |g_scalar|
// and |p_scalar| must be non-null, and |p| must be non-null if |p_scalar| is
// non-null.
int (*mul)(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx);
int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx);
// 'field_mul' and 'field_sqr' can be used by 'add' and 'dbl' so that the
// same implementations of point operations can be used with different
@@ -135,14 +114,12 @@ const EC_METHOD *EC_GFp_mont_method(void);
struct ec_group_st {
const EC_METHOD *meth;
// Unlike all other |EC_POINT|s, |generator| does not own |generator->group|
// to avoid a reference cycle.
EC_POINT *generator;
BIGNUM order;
int curve_name; // optional NID for named curve
BN_MONT_CTX *order_mont; // data for ECDSA inverse
const BN_MONT_CTX *order_mont; // data for ECDSA inverse
// The following members are handled by the method functions,
// even if they appear generic
@@ -153,17 +130,13 @@ struct ec_group_st {
int a_is_minus3; // enable optimized point arithmetics for special case
CRYPTO_refcount_t references;
BN_MONT_CTX *mont; // Montgomery structure.
BIGNUM one; // The value one.
} /* EC_GROUP */;
struct ec_point_st {
// group is an owning reference to |group|, unless this is
// |group->generator|.
EC_GROUP *group;
const EC_METHOD *meth;
BIGNUM X;
BIGNUM Y;
@@ -172,33 +145,20 @@ struct ec_point_st {
} /* EC_POINT */;
EC_GROUP *ec_group_new(const EC_METHOD *meth);
int ec_group_copy(EC_GROUP *dest, const EC_GROUP *src);
// ec_bignum_to_scalar converts |in| to an |EC_SCALAR| and writes it to |*out|.
// |in| must be non-negative and have at most |BN_num_bits(&group->order)| bits.
// It returns one on success and zero on error. It does not ensure |in| is fully
// reduced.
int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
const BIGNUM *in);
// ec_group_get_order_mont returns a Montgomery context for operations modulo
// |group|'s order. It may return NULL in the case that |group| is not a
// built-in group.
const BN_MONT_CTX *ec_group_get_order_mont(const EC_GROUP *group);
// ec_random_nonzero_scalar sets |out| to a uniformly selected random value from
// 1 to |group->order| - 1. It returns one on success and zero on error.
int ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out,
const uint8_t additional_data[32]);
// ec_point_mul_scalar sets |r| to generator * |g_scalar| + |p| *
// |p_scalar|. Unlike other functions which take |EC_SCALAR|, |g_scalar| and
// |p_scalar| need not be fully reduced. They need only contain as many bits as
// the order.
int ec_point_mul_scalar(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar, const EC_POINT *p,
const EC_SCALAR *p_scalar, BN_CTX *ctx);
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx);
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx);
// method functions in simple.c
int ec_GFp_simple_group_init(EC_GROUP *);
void ec_GFp_simple_group_finish(EC_GROUP *);
int ec_GFp_simple_group_copy(EC_GROUP *, const EC_GROUP *);
int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *);
int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a,
@@ -206,12 +166,17 @@ int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a,
unsigned ec_GFp_simple_group_get_degree(const EC_GROUP *);
int ec_GFp_simple_point_init(EC_POINT *);
void ec_GFp_simple_point_finish(EC_POINT *);
void ec_GFp_simple_point_clear_finish(EC_POINT *);
int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *);
int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *);
int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *,
const BIGNUM *x,
const BIGNUM *y,
const BIGNUM *z, BN_CTX *);
int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *,
const EC_POINT *, BIGNUM *x,
BIGNUM *y, BIGNUM *z,
BN_CTX *);
int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
const BIGNUM *x, const BIGNUM *y,
BN_CTX *);
@@ -240,6 +205,7 @@ int ec_GFp_mont_group_init(EC_GROUP *);
int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
const BIGNUM *b, BN_CTX *);
void ec_GFp_mont_group_finish(EC_GROUP *);
int ec_GFp_mont_group_copy(EC_GROUP *, const EC_GROUP *);
int ec_GFp_mont_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
const BIGNUM *b, BN_CTX *);
int ec_GFp_mont_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+3 -3
View File
@@ -251,7 +251,7 @@ err:
int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
const uint8_t *buf, size_t len, BN_CTX *ctx) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
if (group->meth != point->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -261,7 +261,7 @@ int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point,
point_conversion_form_t form, uint8_t *buf,
size_t len, BN_CTX *ctx) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
if (group->meth != point->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
@@ -396,7 +396,7 @@ err:
int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
int y_bit, BN_CTX *ctx) {
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
if (group->meth != point->meth) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
+41 -7
View File
@@ -1038,13 +1038,14 @@ static int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group,
}
static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar,
const EC_POINT *p,
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
const BIGNUM *g_scalar, const EC_POINT *p,
const BIGNUM *p_scalar, BN_CTX *ctx) {
int ret = 0;
BN_CTX *new_ctx = NULL;
BIGNUM *x, *y, *z, *tmp_scalar;
p224_felem_bytearray g_secret, p_secret;
p224_felem p_pre_comp[17][3];
p224_felem_bytearray tmp;
p224_felem x_in, y_in, z_in, x_out, y_out, z_out;
if (ctx == NULL) {
@@ -1066,7 +1067,23 @@ static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
if (p != NULL && p_scalar != NULL) {
// We treat NULL scalars as 0, and NULL points as points at infinity, i.e.,
// they contribute nothing to the linear combination.
OPENSSL_memset(&p_secret, 0, sizeof(p_secret));
OPENSSL_memset(&p_pre_comp, 0, sizeof(p_pre_comp));
size_t num_bytes;
// reduce g_scalar to 0 <= g_scalar < 2^224
if (BN_num_bits(p_scalar) > 224 || BN_is_negative(p_scalar)) {
// this is an unusual input, and we don't guarantee
// constant-timeness
if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
num_bytes = BN_bn2bin(tmp_scalar, tmp);
} else {
num_bytes = BN_bn2bin(p_scalar, tmp);
}
p224_flip_endian(p_secret, tmp, num_bytes);
// precompute multiples
if (!p224_BN_to_felem(x_out, &p->X) ||
!p224_BN_to_felem(y_out, &p->Y) ||
@@ -1092,10 +1109,26 @@ static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
}
}
p224_batch_mul(x_out, y_out, z_out,
(p != NULL && p_scalar != NULL) ? p_scalar->bytes : NULL,
g_scalar != NULL ? g_scalar->bytes : NULL,
(const p224_felem(*)[3])p_pre_comp);
if (g_scalar != NULL) {
OPENSSL_memset(g_secret, 0, sizeof(g_secret));
size_t num_bytes;
// reduce g_scalar to 0 <= g_scalar < 2^224
if (BN_num_bits(g_scalar) > 224 || BN_is_negative(g_scalar)) {
// this is an unusual input, and we don't guarantee constant-timeness
if (!BN_nnmod(tmp_scalar, g_scalar, &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
num_bytes = BN_bn2bin(tmp_scalar, tmp);
} else {
num_bytes = BN_bn2bin(g_scalar, tmp);
}
p224_flip_endian(g_secret, tmp, num_bytes);
}
p224_batch_mul(
x_out, y_out, z_out, (p != NULL && p_scalar != NULL) ? p_secret : NULL,
g_scalar != NULL ? g_secret : NULL, (const p224_felem(*)[3])p_pre_comp);
// reduce the output to its unique minimal representation
p224_felem_contract(x_in, x_out);
@@ -1118,6 +1151,7 @@ err:
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp224_method) {
out->group_init = ec_GFp_simple_group_init;
out->group_finish = ec_GFp_simple_group_finish;
out->group_copy = ec_GFp_simple_group_copy;
out->group_set_curve = ec_GFp_simple_group_set_curve;
out->point_get_affine_coordinates =
ec_GFp_nistp224_point_get_affine_coordinates;
+40 -6
View File
@@ -1582,13 +1582,14 @@ static int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group,
}
static int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar,
const EC_POINT *p,
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
const BIGNUM *g_scalar, const EC_POINT *p,
const BIGNUM *p_scalar, BN_CTX *ctx) {
int ret = 0;
BN_CTX *new_ctx = NULL;
BIGNUM *x, *y, *z, *tmp_scalar;
felem_bytearray g_secret, p_secret;
smallfelem p_pre_comp[17][3];
felem_bytearray tmp;
smallfelem x_in, y_in, z_in;
felem x_out, y_out, z_out;
@@ -1610,7 +1611,21 @@ static int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
if (p != NULL && p_scalar != NULL) {
// We treat NULL scalars as 0, and NULL points as points at infinity, i.e.,
// they contribute nothing to the linear combination.
OPENSSL_memset(&p_secret, 0, sizeof(p_secret));
OPENSSL_memset(&p_pre_comp, 0, sizeof(p_pre_comp));
size_t num_bytes;
// Reduce g_scalar to 0 <= g_scalar < 2^256.
if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) {
// This is an unusual input, and we don't guarantee constant-timeness.
if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
num_bytes = BN_bn2bin(tmp_scalar, tmp);
} else {
num_bytes = BN_bn2bin(p_scalar, tmp);
}
flip_endian(p_secret, tmp, num_bytes);
// Precompute multiples.
if (!BN_to_felem(x_out, &p->X) ||
!BN_to_felem(y_out, &p->Y) ||
@@ -1635,10 +1650,28 @@ static int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
}
}
if (g_scalar != NULL) {
size_t num_bytes;
OPENSSL_memset(g_secret, 0, sizeof(g_secret));
// reduce g_scalar to 0 <= g_scalar < 2^256
if (BN_num_bits(g_scalar) > 256 || BN_is_negative(g_scalar)) {
// this is an unusual input, and we don't guarantee
// constant-timeness.
if (!BN_nnmod(tmp_scalar, g_scalar, &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
num_bytes = BN_bn2bin(tmp_scalar, tmp);
} else {
num_bytes = BN_bn2bin(g_scalar, tmp);
}
flip_endian(g_secret, tmp, num_bytes);
}
batch_mul(x_out, y_out, z_out,
(p != NULL && p_scalar != NULL) ? p_scalar->bytes : NULL,
g_scalar != NULL ? g_scalar->bytes : NULL,
(const smallfelem(*)[3]) & p_pre_comp);
(p != NULL && p_scalar != NULL) ? p_secret : NULL,
g_scalar != NULL ? g_secret : NULL,
(const smallfelem(*)[3]) &p_pre_comp);
// reduce the output to its unique minimal representation
felem_contract(x_in, x_out);
@@ -1661,6 +1694,7 @@ err:
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp256_method) {
out->group_init = ec_GFp_simple_group_init;
out->group_finish = ec_GFp_simple_group_finish;
out->group_copy = ec_GFp_simple_group_copy;
out->group_set_curve = ec_GFp_simple_group_set_curve;
out->point_get_affine_coordinates =
ec_GFp_nistp256_point_get_affine_coordinates;
+122 -17
View File
@@ -216,8 +216,8 @@ static int ecp_nistz256_bignum_to_field_elem(BN_ULONG out[P256_LIMBS],
// r = p * p_scalar
static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
const EC_POINT *p,
const EC_SCALAR *p_scalar) {
const EC_POINT *p, const BIGNUM *p_scalar,
BN_CTX *ctx) {
assert(p != NULL);
assert(p_scalar != NULL);
@@ -229,8 +229,55 @@ static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
// ~1599 ((96 * 16) + 63) bytes of stack space.
alignas(64) P256_POINT table[16];
uint8_t p_str[33];
OPENSSL_memcpy(p_str, p_scalar->bytes, 32);
p_str[32] = 0;
int ret = 0;
BN_CTX *new_ctx = NULL;
int ctx_started = 0;
if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) {
if (ctx == NULL) {
new_ctx = BN_CTX_new();
if (new_ctx == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err;
}
ctx = new_ctx;
}
BN_CTX_start(ctx);
ctx_started = 1;
BIGNUM *mod = BN_CTX_get(ctx);
if (mod == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!BN_nnmod(mod, p_scalar, &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
p_scalar = mod;
}
int j;
for (j = 0; j < p_scalar->top * BN_BYTES; j += BN_BYTES) {
BN_ULONG d = p_scalar->d[j / BN_BYTES];
p_str[j + 0] = d & 0xff;
p_str[j + 1] = (d >> 8) & 0xff;
p_str[j + 2] = (d >> 16) & 0xff;
p_str[j + 3] = (d >>= 24) & 0xff;
if (BN_BYTES == 8) {
d >>= 8;
p_str[j + 4] = d & 0xff;
p_str[j + 5] = (d >> 8) & 0xff;
p_str[j + 6] = (d >> 16) & 0xff;
p_str[j + 7] = (d >> 24) & 0xff;
}
}
for (; j < 33; j++) {
p_str[j] = 0;
}
// table[0] is implicitly (0,0,0) (the point at infinity), therefore it is
// not stored. All other values are actually stored with an offset of -1 in
@@ -241,7 +288,7 @@ static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
!ecp_nistz256_bignum_to_field_elem(row[1 - 1].Y, &p->Y) ||
!ecp_nistz256_bignum_to_field_elem(row[1 - 1].Z, &p->Z)) {
OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
return 0;
goto err;
}
ecp_nistz256_point_double(&row[2 - 1], &row[1 - 1]);
@@ -307,13 +354,19 @@ static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
ecp_nistz256_point_add(r, r, &h);
return 1;
ret = 1;
err:
if (ctx_started) {
BN_CTX_end(ctx);
}
BN_CTX_free(new_ctx);
return ret;
}
static int ecp_nistz256_points_mul(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar,
const EC_POINT *p_,
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
static int ecp_nistz256_points_mul(
const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
const EC_POINT *p_, const BIGNUM *p_scalar, BN_CTX *ctx) {
assert((p_ != NULL) == (p_scalar != NULL));
static const unsigned kWindowSize = 7;
@@ -324,10 +377,54 @@ static int ecp_nistz256_points_mul(const EC_GROUP *group, EC_POINT *r,
P256_POINT_AFFINE a;
} t, p;
int ret = 0;
BN_CTX *new_ctx = NULL;
int ctx_started = 0;
if (g_scalar != NULL) {
uint8_t p_str[33];
OPENSSL_memcpy(p_str, g_scalar->bytes, 32);
p_str[32] = 0;
if (BN_num_bits(g_scalar) > 256 || BN_is_negative(g_scalar)) {
if (ctx == NULL) {
new_ctx = BN_CTX_new();
if (new_ctx == NULL) {
goto err;
}
ctx = new_ctx;
}
BN_CTX_start(ctx);
ctx_started = 1;
BIGNUM *tmp_scalar = BN_CTX_get(ctx);
if (tmp_scalar == NULL) {
goto err;
}
if (!BN_nnmod(tmp_scalar, g_scalar, &group->order, ctx)) {
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
goto err;
}
g_scalar = tmp_scalar;
}
uint8_t p_str[33] = {0};
int i;
for (i = 0; i < g_scalar->top * BN_BYTES; i += BN_BYTES) {
BN_ULONG d = g_scalar->d[i / BN_BYTES];
p_str[i + 0] = d & 0xff;
p_str[i + 1] = (d >> 8) & 0xff;
p_str[i + 2] = (d >> 16) & 0xff;
p_str[i + 3] = (d >>= 24) & 0xff;
if (BN_BYTES == 8) {
d >>= 8;
p_str[i + 4] = d & 0xff;
p_str[i + 5] = (d >> 8) & 0xff;
p_str[i + 6] = (d >> 16) & 0xff;
p_str[i + 7] = (d >> 24) & 0xff;
}
}
for (; i < (int) sizeof(p_str); i++) {
p_str[i] = 0;
}
// First window
unsigned wvalue = (p_str[0] << 1) & kMask;
@@ -348,7 +445,7 @@ static int ecp_nistz256_points_mul(const EC_GROUP *group, EC_POINT *r,
OPENSSL_memset(p.p.Z, 0, sizeof(p.p.Z));
copy_conditional(p.p.Z, ONE, is_not_zero(wvalue >> 1));
for (int i = 1; i < 37; i++) {
for (i = 1; i < 37; i++) {
unsigned off = (index - 1) / 8;
wvalue = p_str[off] | p_str[off + 1] << 8;
wvalue = (wvalue >> ((index - 1) % 8)) & kMask;
@@ -372,8 +469,8 @@ static int ecp_nistz256_points_mul(const EC_GROUP *group, EC_POINT *r,
out = &p.p;
}
if (!ecp_nistz256_windowed_mul(group, out, p_, p_scalar)) {
return 0;
if (!ecp_nistz256_windowed_mul(group, out, p_, p_scalar, ctx)) {
goto err;
}
if (!p_is_infinity) {
@@ -388,7 +485,14 @@ static int ecp_nistz256_points_mul(const EC_GROUP *group, EC_POINT *r,
return 0;
}
return 1;
ret = 1;
err:
if (ctx_started) {
BN_CTX_end(ctx);
}
BN_CTX_free(new_ctx);
return ret;
}
static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point,
@@ -443,6 +547,7 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point,
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistz256_method) {
out->group_init = ec_GFp_mont_group_init;
out->group_finish = ec_GFp_mont_group_finish;
out->group_copy = ec_GFp_mont_group_copy;
out->group_set_curve = ec_GFp_mont_group_set_curve;
out->point_get_affine_coordinates = ecp_nistz256_get_affine;
out->mul = ecp_nistz256_points_mul;
+64 -3
View File
@@ -104,6 +104,18 @@ void ec_GFp_simple_group_finish(EC_GROUP *group) {
BN_free(&group->one);
}
int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) {
if (!BN_copy(&dest->field, &src->field) ||
!BN_copy(&dest->a, &src->a) ||
!BN_copy(&dest->b, &src->b) ||
!BN_copy(&dest->one, &src->one)) {
return 0;
}
dest->a_is_minus3 = src->a_is_minus3;
return 1;
}
int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
const BIGNUM *a, const BIGNUM *b,
BN_CTX *ctx) {
@@ -237,6 +249,12 @@ void ec_GFp_simple_point_finish(EC_POINT *point) {
BN_free(&point->Z);
}
void ec_GFp_simple_point_clear_finish(EC_POINT *point) {
BN_clear_free(&point->X);
BN_clear_free(&point->Y);
BN_clear_free(&point->Z);
}
int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) {
if (!BN_copy(&dest->X, &src->X) ||
!BN_copy(&dest->Y, &src->Y) ||
@@ -295,6 +313,49 @@ err:
return ret;
}
int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
const EC_POINT *point,
BIGNUM *x, BIGNUM *y,
BIGNUM *z, BN_CTX *ctx) {
BN_CTX *new_ctx = NULL;
int ret = 0;
if (group->meth->field_decode != 0) {
if (ctx == NULL) {
ctx = new_ctx = BN_CTX_new();
if (ctx == NULL) {
return 0;
}
}
if (x != NULL && !group->meth->field_decode(group, x, &point->X, ctx)) {
goto err;
}
if (y != NULL && !group->meth->field_decode(group, y, &point->Y, ctx)) {
goto err;
}
if (z != NULL && !group->meth->field_decode(group, z, &point->Z, ctx)) {
goto err;
}
} else {
if (x != NULL && !BN_copy(x, &point->X)) {
goto err;
}
if (y != NULL && !BN_copy(y, &point->Y)) {
goto err;
}
if (z != NULL && !BN_copy(z, &point->Z)) {
goto err;
}
}
ret = 1;
err:
BN_CTX_free(new_ctx);
return ret;
}
int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
EC_POINT *point, const BIGNUM *x,
const BIGNUM *y, BN_CTX *ctx) {
@@ -753,11 +814,11 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
const BIGNUM *tmp1_, *tmp2_;
int ret = -1;
if (ec_GFp_simple_is_at_infinity(group, a)) {
return ec_GFp_simple_is_at_infinity(group, b) ? 0 : 1;
if (EC_POINT_is_at_infinity(group, a)) {
return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
}
if (ec_GFp_simple_is_at_infinity(group, b)) {
if (EC_POINT_is_at_infinity(group, b)) {
return 1;
}
+9 -27
View File
@@ -122,6 +122,11 @@ static int8_t *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) {
sign = -1;
}
if (scalar->d == NULL || scalar->top == 0) {
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
goto err;
}
len = BN_num_bits(scalar);
// The modified wNAF may be one digit longer than binary representation
// (*ret_len will be set to the actual length, i.e. at most
@@ -231,9 +236,8 @@ static size_t window_bits_for_scalar_size(size_t b) {
return 1;
}
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r,
const EC_SCALAR *g_scalar_raw, const EC_POINT *p,
const EC_SCALAR *p_scalar_raw, BN_CTX *ctx) {
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx) {
BN_CTX *new_ctx = NULL;
const EC_POINT *generator = NULL;
EC_POINT *tmp = NULL;
@@ -258,32 +262,13 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r,
goto err;
}
}
BN_CTX_start(ctx);
// Convert from |EC_SCALAR| to |BIGNUM|. |BIGNUM| is not constant-time, but
// neither is the rest of this function.
BIGNUM *g_scalar = NULL, *p_scalar = NULL;
if (g_scalar_raw != NULL) {
g_scalar = BN_CTX_get(ctx);
if (g_scalar == NULL ||
!bn_set_words(g_scalar, g_scalar_raw->words, group->order.top)) {
goto err;
}
}
if (p_scalar_raw != NULL) {
p_scalar = BN_CTX_get(ctx);
if (p_scalar == NULL ||
!bn_set_words(p_scalar, p_scalar_raw->words, group->order.top)) {
goto err;
}
}
// TODO: This function used to take |points| and |scalars| as arrays of
// |num| elements. The code below should be simplified to work in terms of |p|
// and |p_scalar|.
size_t num = p != NULL ? 1 : 0;
const EC_POINT **points = p != NULL ? &p : NULL;
BIGNUM **scalars = p != NULL ? &p_scalar : NULL;
const BIGNUM **scalars = p != NULL ? &p_scalar : NULL;
total_num = num;
@@ -448,9 +433,6 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r,
ret = 1;
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
}
BN_CTX_free(new_ctx);
EC_POINT_free(tmp);
OPENSSL_free(wsize);
@@ -464,7 +446,7 @@ err:
}
if (val != NULL) {
for (i = 0; i < num_val; i++) {
EC_POINT_free(val[i]);
EC_POINT_clear_free(val[i]);
}
OPENSSL_free(val);
+209 -207
View File
@@ -58,72 +58,37 @@
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/sha.h>
#include <openssl/type_check.h>
#include "../bn/internal.h"
#include "../ec/internal.h"
#include "../../internal.h"
// digest_to_scalar interprets |digest_len| bytes from |digest| as a scalar for
// ECDSA. Note this value is not fully reduced modulo the order, only the
// correct number of bits.
static void digest_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
const uint8_t *digest, size_t digest_len) {
const BIGNUM *order = &group->order;
size_t num_bits = BN_num_bits(order);
// Need to truncate digest if it is too long: first truncate whole bytes.
// digest_to_bn interprets |digest_len| bytes from |digest| as a big-endian
// number and sets |out| to that value. It then truncates |out| so that it's,
// at most, as long as |order|. It returns one on success and zero otherwise.
static int digest_to_bn(BIGNUM *out, const uint8_t *digest, size_t digest_len,
const BIGNUM *order) {
size_t num_bits;
num_bits = BN_num_bits(order);
// Need to truncate digest if it is too long: first truncate whole
// bytes.
if (8 * digest_len > num_bits) {
digest_len = (num_bits + 7) / 8;
}
OPENSSL_memset(out, 0, sizeof(EC_SCALAR));
for (size_t i = 0; i < digest_len; i++) {
out->bytes[i] = digest[digest_len - 1 - i];
if (!BN_bin2bn(digest, digest_len, out)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
return 0;
}
// If still too long truncate remaining bits with a shift
if (8 * digest_len > num_bits) {
size_t shift = 8 - (num_bits & 0x7);
for (int i = 0; i < order->top - 1; i++) {
out->words[i] =
(out->words[i] >> shift) | (out->words[i + 1] << (BN_BITS2 - shift));
}
out->words[order->top - 1] >>= shift;
}
}
// field_element_to_scalar reduces |r| modulo |group->order|. |r| must
// previously have been reduced modulo |group->field|.
static int field_element_to_scalar(const EC_GROUP *group, BIGNUM *r) {
// We must have p < 2×order, assuming p is not tiny (p >= 17). Thus rather we
// can reduce by performing at most one subtraction.
//
// Proof: We only work with prime order curves, so the number of points on
// the curve is the order. Thus Hasse's theorem gives:
//
// |order - (p + 1)| <= 2×sqrt(p)
// p + 1 - order <= 2×sqrt(p)
// p + 1 - 2×sqrt(p) <= order
// p + 1 - 2×(p/4) < order (p/4 > sqrt(p) for p >= 17)
// p/2 < p/2 + 1 < order
// p < 2×order
//
// Additionally, one can manually check this property for built-in curves. It
// is enforced for legacy custom curves in |EC_GROUP_set_generator|.
//
// TODO(davidben): Introduce |EC_FIELD_ELEMENT|, make this a function from
// |EC_FIELD_ELEMENT| to |EC_SCALAR|, and cut out the |BIGNUM|. Does this need
// to be constant-time for signing? |r| is the x-coordinate for kG, which is
// public unless k was rerolled because |s| was zero.
assert(!BN_is_negative(r));
assert(BN_cmp(r, &group->field) < 0);
if (BN_cmp(r, &group->order) >= 0 &&
!BN_sub(r, r, &group->order)) {
if ((8 * digest_len > num_bits) &&
!BN_rshift(out, out, 8 - (num_bits & 0x7))) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
return 0;
}
assert(!BN_is_negative(r));
assert(BN_cmp(r, &group->order) < 0);
return 1;
}
@@ -151,87 +116,67 @@ void ECDSA_SIG_free(ECDSA_SIG *sig) {
OPENSSL_free(sig);
}
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **out_r,
const BIGNUM **out_s) {
if (out_r != NULL) {
*out_r = sig->r;
}
if (out_s != NULL) {
*out_s = sig->s;
}
}
int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) {
if (r == NULL || s == NULL) {
return 0;
}
BN_free(sig->r);
BN_free(sig->s);
sig->r = r;
sig->s = s;
return 1;
ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
const EC_KEY *key) {
return ECDSA_do_sign_ex(digest, digest_len, NULL, NULL, key);
}
int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
const ECDSA_SIG *sig, const EC_KEY *eckey) {
const EC_GROUP *group = EC_KEY_get0_group(eckey);
const EC_POINT *pub_key = EC_KEY_get0_public_key(eckey);
if (group == NULL || pub_key == NULL || sig == NULL) {
int ret = 0;
BN_CTX *ctx;
BIGNUM *u1, *u2, *m, *X;
EC_POINT *point = NULL;
const EC_GROUP *group;
const EC_POINT *pub_key;
// check input values
if ((group = EC_KEY_get0_group(eckey)) == NULL ||
(pub_key = EC_KEY_get0_public_key(eckey)) == NULL ||
sig == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_MISSING_PARAMETERS);
return 0;
}
BN_CTX *ctx = BN_CTX_new();
ctx = BN_CTX_new();
if (!ctx) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
return 0;
}
int ret = 0;
EC_POINT *point = NULL;
BN_CTX_start(ctx);
BIGNUM *X = BN_CTX_get(ctx);
if (X == NULL) {
u1 = BN_CTX_get(ctx);
u2 = BN_CTX_get(ctx);
m = BN_CTX_get(ctx);
X = BN_CTX_get(ctx);
if (u1 == NULL || u2 == NULL || m == NULL || X == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
goto err;
}
EC_SCALAR r, s, m, u1, u2, s_inv_mont;
const BIGNUM *order = EC_GROUP_get0_order(group);
if (BN_is_zero(sig->r) ||
BN_is_negative(sig->r) ||
BN_ucmp(sig->r, order) >= 0 ||
!ec_bignum_to_scalar(group, &r, sig->r) ||
BN_is_zero(sig->s) ||
BN_is_negative(sig->s) ||
BN_ucmp(sig->s, order) >= 0 ||
!ec_bignum_to_scalar(group, &s, sig->s)) {
if (BN_is_zero(sig->r) || BN_is_negative(sig->r) ||
BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s) ||
BN_is_negative(sig->s) || BN_ucmp(sig->s, order) >= 0) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
goto err;
}
// s_inv_mont = s^-1 mod order. We convert the result to Montgomery form for
// the products below.
// calculate tmp1 = inv(S) mod order
int no_inverse;
if (!BN_mod_inverse_odd(X, &no_inverse, sig->s, order, ctx) ||
!ec_bignum_to_scalar(group, &s_inv_mont, X) ||
!bn_to_montgomery_small(s_inv_mont.words, order->top, s_inv_mont.words,
order->top, group->order_mont)) {
if (!BN_mod_inverse_odd(u2, &no_inverse, sig->s, order, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
goto err;
}
// u1 = m * s_inv_mont mod order
// u2 = r * s_inv_mont mod order
//
// |s_inv_mont| is in Montgomery form while |m| and |r| are not, so |u1| and
// |u2| will be taken out of Montgomery form, as desired. Note that, although
// |m| is not fully reduced, |bn_mod_mul_montgomery_small| only requires the
// product not exceed R * |order|. |s_inv_mont| is fully reduced and |m| <
// 2^BN_num_bits(order) <= R, so this holds.
digest_to_scalar(group, &m, digest, digest_len);
if (!bn_mod_mul_montgomery_small(u1.words, order->top, m.words, order->top,
s_inv_mont.words, order->top,
group->order_mont) ||
!bn_mod_mul_montgomery_small(u2.words, order->top, r.words, order->top,
s_inv_mont.words, order->top,
group->order_mont)) {
if (!digest_to_bn(m, digest, digest_len, order)) {
goto err;
}
// u1 = m * tmp mod order
if (!BN_mod_mul(u1, m, u2, order, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
goto err;
}
// u2 = r * w mod q
if (!BN_mod_mul(u2, sig->r, u2, order, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
goto err;
}
@@ -240,7 +185,7 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!ec_point_mul_scalar(group, point, &u1, pub_key, &u2, ctx)) {
if (!EC_POINT_mul(group, point, u1, pub_key, u2, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
goto err;
}
@@ -248,12 +193,12 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
goto err;
}
if (!field_element_to_scalar(group, X)) {
if (!BN_nnmod(u1, X, order, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
goto err;
}
// The signature is correct iff |X| is equal to |sig->r|.
if (BN_ucmp(X, sig->r) != 0) {
// if the signature is correct u1 is equal to sig->r
if (BN_ucmp(u1, sig->r) != 0) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
goto err;
}
@@ -267,26 +212,45 @@ err:
return ret;
}
static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx,
EC_SCALAR *out_kinv_mont, BIGNUM **rp,
const uint8_t *digest, size_t digest_len,
const EC_SCALAR *priv_key) {
static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
BIGNUM **rp, const uint8_t *digest,
size_t digest_len) {
BN_CTX *ctx = NULL;
BIGNUM *k = NULL, *kinv = NULL, *r = NULL, *tmp = NULL;
EC_POINT *tmp_point = NULL;
const EC_GROUP *group;
int ret = 0;
EC_SCALAR k;
BIGNUM *r = BN_new(); // this value is later returned in *rp
if (r == NULL) {
if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (ctx_in == NULL) {
if ((ctx = BN_CTX_new()) == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
return 0;
}
} else {
ctx = ctx_in;
}
k = BN_new();
kinv = BN_new(); // this value is later returned in *kinvp
r = BN_new(); // this value is later returned in *rp
tmp = BN_new();
if (k == NULL || kinv == NULL || r == NULL || tmp == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
goto err;
}
const EC_GROUP *group = EC_KEY_get0_group(eckey);
const BIGNUM *order = EC_GROUP_get0_order(group);
tmp_point = EC_POINT_new(group);
if (tmp_point == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
goto err;
}
const BIGNUM *order = EC_GROUP_get0_order(group);
// Check that the size of the group order is FIPS compliant (FIPS 186-4
// B.5.2).
if (BN_num_bits(order) < 160) {
@@ -295,130 +259,171 @@ static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx,
}
do {
// Include the private key and message digest in the k generation.
// If possible, we'll include the private key and message digest in the k
// generation. The |digest| argument is only empty if |ECDSA_sign_setup| is
// being used.
if (eckey->fixed_k != NULL) {
if (!ec_bignum_to_scalar(group, &k, eckey->fixed_k)) {
if (!BN_copy(k, eckey->fixed_k)) {
goto err;
}
} else {
// Pass a SHA512 hash of the private key and digest as additional data
// into the RBG. This is a hardening measure against entropy failure.
OPENSSL_COMPILE_ASSERT(SHA512_DIGEST_LENGTH >= 32,
additional_data_is_too_large_for_sha512);
SHA512_CTX sha;
uint8_t additional_data[SHA512_DIGEST_LENGTH];
SHA512_Init(&sha);
SHA512_Update(&sha, priv_key->words, order->top * sizeof(BN_ULONG));
SHA512_Update(&sha, digest, digest_len);
SHA512_Final(additional_data, &sha);
if (!ec_random_nonzero_scalar(group, &k, additional_data)) {
goto err;
}
}
// Compute k^-1. We leave it in the Montgomery domain as an optimization for
// later operations.
if (!bn_to_montgomery_small(out_kinv_mont->words, order->top, k.words,
order->top, group->order_mont) ||
!bn_mod_inverse_prime_mont_small(out_kinv_mont->words, order->top,
out_kinv_mont->words, order->top,
group->order_mont)) {
} else if (digest_len > 0) {
do {
if (!BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey),
digest, digest_len, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
goto err;
}
} while (BN_is_zero(k));
} else if (!BN_rand_range_ex(k, 1, order)) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
goto err;
}
// Compute r, the x-coordinate of generator * k.
if (!ec_point_mul_scalar(group, tmp_point, &k, NULL, NULL, ctx) ||
!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, r, NULL,
// Compute the inverse of k. The order is a prime, so use Fermat's Little
// Theorem. Note |ec_group_get_order_mont| may return NULL but
// |bn_mod_inverse_prime| allows this.
if (!bn_mod_inverse_prime(kinv, k, order, ctx,
ec_group_get_order_mont(group))) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
goto err;
}
// We do not want timing information to leak the length of k,
// so we compute G*k using an equivalent scalar of fixed
// bit-length.
if (!BN_add(k, k, order)) {
goto err;
}
if (BN_num_bits(k) <= BN_num_bits(order)) {
if (!BN_add(k, k, order)) {
goto err;
}
}
// compute r the x-coordinate of generator * k
if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
goto err;
}
if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, tmp, NULL,
ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
goto err;
}
if (!field_element_to_scalar(group, r)) {
if (!BN_nnmod(r, tmp, order, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
goto err;
}
} while (BN_is_zero(r));
// clear old values if necessary
BN_clear_free(*rp);
BN_clear_free(*kinvp);
// save the pre-computed values
*rp = r;
r = NULL;
*kinvp = kinv;
ret = 1;
err:
OPENSSL_cleanse(&k, sizeof(k));
BN_clear_free(r);
BN_clear_free(k);
if (!ret) {
BN_clear_free(kinv);
BN_clear_free(r);
}
if (ctx_in == NULL) {
BN_CTX_free(ctx);
}
EC_POINT_free(tmp_point);
BN_clear_free(tmp);
return ret;
}
ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
const EC_KEY *eckey) {
int ECDSA_sign_setup(const EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv,
BIGNUM **rp) {
return ecdsa_sign_setup(eckey, ctx, kinv, rp, NULL, 0);
}
ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len,
const BIGNUM *in_kinv, const BIGNUM *in_r,
const EC_KEY *eckey) {
int ok = 0;
BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL;
const BIGNUM *ckinv;
BN_CTX *ctx = NULL;
const EC_GROUP *group;
ECDSA_SIG *ret;
const BIGNUM *priv_key;
if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED);
return NULL;
}
const EC_GROUP *group = EC_KEY_get0_group(eckey);
const BIGNUM *priv_key_bn = EC_KEY_get0_private_key(eckey);
if (group == NULL || priv_key_bn == NULL) {
group = EC_KEY_get0_group(eckey);
priv_key = EC_KEY_get0_private_key(eckey);
if (group == NULL || priv_key == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
const BIGNUM *order = EC_GROUP_get0_order(group);
int ok = 0;
ECDSA_SIG *ret = ECDSA_SIG_new();
BN_CTX *ctx = BN_CTX_new();
EC_SCALAR kinv_mont, priv_key, r_mont, s, tmp, m;
if (ret == NULL || ctx == NULL) {
ret = ECDSA_SIG_new();
if (!ret) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
return NULL;
}
s = ret->s;
digest_to_scalar(group, &m, digest, digest_len);
if (!ec_bignum_to_scalar(group, &priv_key, priv_key_bn)) {
if ((ctx = BN_CTX_new()) == NULL ||
(tmp = BN_new()) == NULL ||
(m = BN_new()) == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
goto err;
}
const BIGNUM *order = EC_GROUP_get0_order(group);
if (!digest_to_bn(m, digest, digest_len, order)) {
goto err;
}
for (;;) {
if (!ecdsa_sign_setup(eckey, ctx, &kinv_mont, &ret->r, digest, digest_len,
&priv_key)) {
goto err;
if (in_kinv == NULL || in_r == NULL) {
if (!ecdsa_sign_setup(eckey, ctx, &kinv, &ret->r, digest, digest_len)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_ECDSA_LIB);
goto err;
}
ckinv = kinv;
} else {
ckinv = in_kinv;
if (BN_copy(ret->r, in_r) == NULL) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
goto err;
}
}
// Compute priv_key * r (mod order). Note if only one parameter is in the
// Montgomery domain, |bn_mod_mul_montgomery_small| will compute the answer
// in the normal domain.
if (!ec_bignum_to_scalar(group, &r_mont, ret->r) ||
!bn_to_montgomery_small(r_mont.words, order->top, r_mont.words,
order->top, group->order_mont) ||
!bn_mod_mul_montgomery_small(s.words, order->top, priv_key.words,
order->top, r_mont.words, order->top,
group->order_mont)) {
if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
goto err;
}
// Compute s += m in constant time. Reduce one copy of |order| if necessary.
// Note this does not leave |s| fully reduced. We have
// |m| < 2^BN_num_bits(order), so subtracting |order| leaves
// 0 <= |s| < 2^BN_num_bits(order).
BN_ULONG carry = bn_add_words(s.words, s.words, m.words, order->top);
BN_ULONG v = bn_sub_words(tmp.words, s.words, order->d, order->top) - carry;
v = 0u - v;
for (int i = 0; i < order->top; i++) {
s.words[i] = constant_time_select_w(v, s.words[i], tmp.words[i]);
}
// Finally, multiply s by k^-1. That was retained in Montgomery form, so the
// same technique as the previous multiplication works. Although the
// previous step did not fully reduce |s|, |bn_mod_mul_montgomery_small|
// only requires the product not exceed R * |order|. |kinv_mont| is fully
// reduced and |s| < 2^BN_num_bits(order) <= R, so this holds.
if (!bn_mod_mul_montgomery_small(s.words, order->top, s.words, order->top,
kinv_mont.words, order->top,
group->order_mont) ||
!bn_set_words(ret->s, s.words, order->top)) {
if (!BN_mod_add_quick(s, tmp, m, order)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
goto err;
}
if (!BN_is_zero(ret->s)) {
if (!BN_mod_mul(s, s, ckinv, order, ctx)) {
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
goto err;
}
if (BN_is_zero(s)) {
// if kinv and r have been supplied by the caller
// don't to generate new kinv and r values
if (in_kinv != NULL && in_r != NULL) {
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NEED_NEW_SETUP_VALUES);
goto err;
}
} else {
// s != 0 => we have a valid signature
break;
}
@@ -432,11 +437,8 @@ err:
ret = NULL;
}
BN_CTX_free(ctx);
OPENSSL_cleanse(&kinv_mont, sizeof(kinv_mont));
OPENSSL_cleanse(&priv_key, sizeof(priv_key));
OPENSSL_cleanse(&r_mont, sizeof(r_mont));
OPENSSL_cleanse(&s, sizeof(s));
OPENSSL_cleanse(&tmp, sizeof(tmp));
OPENSSL_cleanse(&m, sizeof(m));
BN_clear_free(m);
BN_clear_free(tmp);
BN_clear_free(kinv);
return ret;
}
+73 -110
View File
@@ -64,21 +64,20 @@
#include <openssl/nid.h>
#include <openssl/rand.h>
#include "../ec/internal.h"
#include "../../test/file_test.h"
enum API {
kEncodedAPI,
kRawAPI,
enum Api {
kEncodedApi,
kRawApi,
};
// VerifyECDSASig checks that verifying |ecdsa_sig| gives |expected_result|.
static void VerifyECDSASig(API api, const uint8_t *digest, size_t digest_len,
static void VerifyECDSASig(Api api, const uint8_t *digest, size_t digest_len,
const ECDSA_SIG *ecdsa_sig, EC_KEY *eckey,
int expected_result) {
switch (api) {
case kEncodedAPI: {
case kEncodedApi: {
uint8_t *der;
size_t der_len;
ASSERT_TRUE(ECDSA_SIG_to_bytes(&der, &der_len, ecdsa_sig));
@@ -88,7 +87,7 @@ static void VerifyECDSASig(API api, const uint8_t *digest, size_t digest_len,
break;
}
case kRawAPI:
case kRawApi:
EXPECT_EQ(expected_result,
ECDSA_do_verify(digest, digest_len, ecdsa_sig, eckey));
break;
@@ -101,7 +100,7 @@ static void VerifyECDSASig(API api, const uint8_t *digest, size_t digest_len,
// TestTamperedSig verifies that signature verification fails when a valid
// signature is tampered with. |ecdsa_sig| must be a valid signature, which will
// be modified.
static void TestTamperedSig(API api, const uint8_t *digest,
static void TestTamperedSig(Api api, const uint8_t *digest,
size_t digest_len, ECDSA_SIG *ecdsa_sig,
EC_KEY *eckey, const BIGNUM *order) {
SCOPED_TRACE(api);
@@ -207,7 +206,7 @@ TEST(ECDSATest, BuiltinCurves) {
bssl::UniquePtr<ECDSA_SIG> ecdsa_sig(
ECDSA_SIG_from_bytes(signature.data(), signature.size()));
ASSERT_TRUE(ecdsa_sig);
TestTamperedSig(kEncodedAPI, digest, 20, ecdsa_sig.get(), eckey.get(),
TestTamperedSig(kEncodedApi, digest, 20, ecdsa_sig.get(), eckey.get(),
order);
// Test ECDSA_SIG signing and verification.
@@ -229,7 +228,7 @@ TEST(ECDSATest, BuiltinCurves) {
ERR_clear_error();
// Verify a tampered signature.
TestTamperedSig(kRawAPI, digest, 20, ecdsa_sig.get(), eckey.get(), order);
TestTamperedSig(kRawApi, digest, 20, ecdsa_sig.get(), eckey.get(), order);
}
}
@@ -283,32 +282,6 @@ static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
return nullptr;
}
static bssl::UniquePtr<EC_GROUP> MakeCustomClone(const EC_GROUP *group) {
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
bssl::UniquePtr<BIGNUM> p(BN_new()), a(BN_new()), b(BN_new()), x(BN_new()),
y(BN_new());
if (!ctx || !p || !a || !b || !x || !y ||
!EC_GROUP_get_curve_GFp(group, p.get(), a.get(), b.get(), ctx.get()) ||
!EC_POINT_get_affine_coordinates_GFp(
group, EC_GROUP_get0_generator(group), x.get(), y.get(), ctx.get())) {
return nullptr;
}
bssl::UniquePtr<EC_GROUP> ret(
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
if (!ret) {
return nullptr;
}
bssl::UniquePtr<EC_POINT> g(EC_POINT_new(ret.get()));
if (!g ||
!EC_POINT_set_affine_coordinates_GFp(ret.get(), g.get(), x.get(), y.get(),
ctx.get()) ||
!EC_GROUP_set_generator(ret.get(), g.get(), EC_GROUP_get0_order(group),
BN_value_one())) {
return nullptr;
}
return ret;
}
static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
std::vector<uint8_t> bytes;
if (!t->GetBytes(&bytes, key)) {
@@ -321,90 +294,80 @@ static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
TEST(ECDSATest, VerifyTestVectors) {
FileTestGTest("crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt",
[](FileTest *t) {
for (bool custom_group : {false, true}) {
SCOPED_TRACE(custom_group);
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
ASSERT_TRUE(group);
if (custom_group) {
group = MakeCustomClone(group.get());
ASSERT_TRUE(group);
}
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
ASSERT_TRUE(x);
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
ASSERT_TRUE(y);
bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R");
ASSERT_TRUE(r);
bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S");
ASSERT_TRUE(s);
std::vector<uint8_t> digest;
ASSERT_TRUE(t->GetBytes(&digest, "Digest"));
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
ASSERT_TRUE(group);
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
ASSERT_TRUE(x);
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
ASSERT_TRUE(y);
bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R");
ASSERT_TRUE(r);
bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S");
ASSERT_TRUE(s);
std::vector<uint8_t> digest;
ASSERT_TRUE(t->GetBytes(&digest, "Digest"));
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
ASSERT_TRUE(key);
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
ASSERT_TRUE(pub_key);
bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new());
ASSERT_TRUE(sig);
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
group.get(), pub_key.get(), x.get(), y.get(), nullptr));
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
ASSERT_TRUE(BN_copy(sig->r, r.get()));
ASSERT_TRUE(BN_copy(sig->s, s.get()));
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
ASSERT_TRUE(key);
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
ASSERT_TRUE(pub_key);
bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new());
ASSERT_TRUE(sig);
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(),
x.get(), y.get(), nullptr));
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
ASSERT_TRUE(BN_copy(sig->r, r.get()));
ASSERT_TRUE(BN_copy(sig->s, s.get()));
EXPECT_EQ(
t->HasAttribute("Invalid") ? 0 : 1,
ECDSA_do_verify(digest.data(), digest.size(), sig.get(), key.get()));
}
EXPECT_EQ(
t->HasAttribute("Invalid") ? 0 : 1,
ECDSA_do_verify(digest.data(), digest.size(), sig.get(), key.get()));
});
}
TEST(ECDSATest, SignTestVectors) {
FileTestGTest("crypto/fipsmodule/ecdsa/ecdsa_sign_tests.txt",
[](FileTest *t) {
for (bool custom_group : {false, true}) {
SCOPED_TRACE(custom_group);
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
ASSERT_TRUE(group);
if (custom_group) {
group = MakeCustomClone(group.get());
ASSERT_TRUE(group);
}
bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private");
ASSERT_TRUE(priv_key);
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
ASSERT_TRUE(x);
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
ASSERT_TRUE(y);
bssl::UniquePtr<BIGNUM> k = GetBIGNUM(t, "K");
ASSERT_TRUE(k);
bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R");
ASSERT_TRUE(r);
bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S");
ASSERT_TRUE(s);
std::vector<uint8_t> digest;
ASSERT_TRUE(t->GetBytes(&digest, "Digest"));
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
ASSERT_TRUE(group);
bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private");
ASSERT_TRUE(priv_key);
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
ASSERT_TRUE(x);
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
ASSERT_TRUE(y);
bssl::UniquePtr<BIGNUM> k = GetBIGNUM(t, "K");
ASSERT_TRUE(k);
bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R");
ASSERT_TRUE(r);
bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S");
ASSERT_TRUE(s);
std::vector<uint8_t> digest;
ASSERT_TRUE(t->GetBytes(&digest, "Digest"));
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
ASSERT_TRUE(key);
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
ASSERT_TRUE(pub_key);
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get()));
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
group.get(), pub_key.get(), x.get(), y.get(), nullptr));
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
ASSERT_TRUE(EC_KEY_check_key(key.get()));
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
ASSERT_TRUE(key);
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
ASSERT_TRUE(pub_key);
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get()));
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(),
x.get(), y.get(), nullptr));
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
ASSERT_TRUE(EC_KEY_check_key(key.get()));
// Set the fixed k for testing purposes.
key->fixed_k = k.release();
bssl::UniquePtr<ECDSA_SIG> sig(
ECDSA_do_sign(digest.data(), digest.size(), key.get()));
ASSERT_TRUE(sig);
// |ECDSA_do_sign_ex| expects |k| to already be inverted.
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
ASSERT_TRUE(ctx);
ASSERT_TRUE(BN_mod_inverse(k.get(), k.get(),
EC_GROUP_get0_order(group.get()), ctx.get()));
EXPECT_EQ(0, BN_cmp(r.get(), sig->r));
EXPECT_EQ(0, BN_cmp(s.get(), sig->s));
}
bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_do_sign_ex(
digest.data(), digest.size(), k.get(), r.get(), key.get()));
ASSERT_TRUE(sig);
EXPECT_EQ(0, BN_cmp(r.get(), sig->r));
EXPECT_EQ(0, BN_cmp(s.get(), sig->s));
});
}
@@ -86,7 +86,6 @@ $code=<<___;
.type _aesni_ctr32_ghash_6x,\@abi-omnipotent
.align 32
_aesni_ctr32_ghash_6x:
.cfi_startproc
vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb
sub \$6,$len
vpxor $Z0,$Z0,$Z0 # $Z0 = 0
@@ -411,7 +410,6 @@ _aesni_ctr32_ghash_6x:
vpxor $Z0,$Xi,$Xi # modulo-scheduled
ret
.cfi_endproc
.size _aesni_ctr32_ghash_6x,.-_aesni_ctr32_ghash_6x
___
######################################################################
@@ -424,7 +422,6 @@ $code.=<<___;
.type aesni_gcm_decrypt,\@function,6
.align 32
aesni_gcm_decrypt:
.cfi_startproc
xor $ret,$ret
# We call |_aesni_ctr32_ghash_6x|, which requires at least 96 (0x60)
@@ -433,19 +430,12 @@ aesni_gcm_decrypt:
jb .Lgcm_dec_abort
lea (%rsp),%rax # save stack pointer
.cfi_def_cfa_register %rax
push %rbx
.cfi_push %rbx
push %rbp
.cfi_push %rbp
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
___
$code.=<<___ if ($win64);
lea -0xa8(%rsp),%rsp
@@ -545,23 +535,15 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -48(%rax),%r15
.cfi_restore %r15
mov -40(%rax),%r14
.cfi_restore %r14
mov -32(%rax),%r13
.cfi_restore %r13
mov -24(%rax),%r12
.cfi_restore %r12
mov -16(%rax),%rbp
.cfi_restore %rbp
mov -8(%rax),%rbx
.cfi_restore %rbx
lea (%rax),%rsp # restore %rsp
.cfi_def_cfa_register %rsp
.Lgcm_dec_abort:
mov $ret,%rax # return value
ret
.cfi_endproc
.size aesni_gcm_decrypt,.-aesni_gcm_decrypt
___
@@ -569,7 +551,6 @@ $code.=<<___;
.type _aesni_ctr32_6x,\@abi-omnipotent
.align 32
_aesni_ctr32_6x:
.cfi_startproc
vmovdqu 0x00-0x80($key),$Z0 # borrow $Z0 for $rndkey
vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb
lea -1($rounds),%r13
@@ -656,14 +637,12 @@ _aesni_ctr32_6x:
vpshufb $Ii,$T1,$T1 # next counter value
vpxor $Z0,$inout5,$inout5
jmp .Loop_ctr32
.cfi_endproc
.size _aesni_ctr32_6x,.-_aesni_ctr32_6x
.globl aesni_gcm_encrypt
.type aesni_gcm_encrypt,\@function,6
.align 32
aesni_gcm_encrypt:
.cfi_startproc
xor $ret,$ret
# We call |_aesni_ctr32_6x| twice, each call consuming 96 bytes of
@@ -673,19 +652,12 @@ aesni_gcm_encrypt:
jb .Lgcm_enc_abort
lea (%rsp),%rax # save stack pointer
.cfi_def_cfa_register %rax
push %rbx
.cfi_push %rbx
push %rbp
.cfi_push %rbp
push %r12
.cfi_push %r12
push %r13
.cfi_push %r13
push %r14
.cfi_push %r14
push %r15
.cfi_push %r15
___
$code.=<<___ if ($win64);
lea -0xa8(%rsp),%rsp
@@ -957,23 +929,15 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov -48(%rax),%r15
.cfi_restore %r15
mov -40(%rax),%r14
.cfi_restore %r14
mov -32(%rax),%r13
.cfi_restore %r13
mov -24(%rax),%r12
.cfi_restore %r12
mov -16(%rax),%rbp
.cfi_restore %rbp
mov -8(%rax),%rbx
.cfi_restore %rbx
lea (%rax),%rsp # restore %rsp
.cfi_def_cfa_register %rsp
.Lgcm_enc_abort:
mov $ret,%rax # return value
ret
.cfi_endproc
.size aesni_gcm_encrypt,.-aesni_gcm_encrypt
___
+15 -14
View File
@@ -62,8 +62,7 @@ void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
assert(len == 0 || (in != NULL && out != NULL));
if (STRICT_ALIGNMENT &&
((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
0) {
((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
while (len >= 16) {
for (n = 0; n < 16; ++n) {
out[n] = in[n] ^ iv[n];
@@ -77,7 +76,7 @@ void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
} else {
while (len >= 16) {
for (n = 0; n < 16; n += sizeof(size_t)) {
store_word_le(out + n, load_word_le(in + n) ^ load_word_le(iv + n));
*(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(iv + n);
}
(*block)(out, out, key);
iv = out;
@@ -130,8 +129,7 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
const uint8_t *iv = ivec;
if (STRICT_ALIGNMENT &&
((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
0) {
((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
while (len >= 16) {
(*block)(in, out, key);
for (n = 0; n < 16; ++n) {
@@ -144,9 +142,11 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
}
} else if (16 % sizeof(size_t) == 0) { // always true
while (len >= 16) {
size_t *out_t = (size_t *)out, *iv_t = (size_t *)iv;
(*block)(in, out, key);
for (n = 0; n < 16; n += sizeof(size_t)) {
store_word_le(out + n, load_word_le(out + n) ^ load_word_le(iv + n));
for (n = 0; n < 16 / sizeof(size_t); n++) {
out_t[n] ^= iv_t[n];
}
iv = in;
len -= 16;
@@ -160,8 +160,7 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
// directly to |out| would overwrite a ciphertext block before it is used as
// the next block's IV. Decrypt to a temporary block instead.
if (STRICT_ALIGNMENT &&
((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
0) {
((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
uint8_t c;
while (len >= 16) {
(*block)(in, tmp.c, key);
@@ -176,12 +175,14 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
}
} else if (16 % sizeof(size_t) == 0) { // always true
while (len >= 16) {
size_t c, *out_t = (size_t *)out, *ivec_t = (size_t *)ivec;
const size_t *in_t = (const size_t *)in;
(*block)(in, tmp.c, key);
for (n = 0; n < 16; n += sizeof(size_t)) {
size_t c = load_word_le(in + n);
store_word_le(out + n,
tmp.t[n / sizeof(size_t)] ^ load_word_le(ivec + n));
store_word_le(ivec + n, c);
for (n = 0; n < 16 / sizeof(size_t); n++) {
c = in_t[n];
out_t[n] = tmp.t[n] ^ ivec_t[n];
ivec_t[n] = c;
}
len -= 16;
in += 16;
+8 -12
View File
@@ -72,8 +72,7 @@ void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
n = (n + 1) % 16;
}
#if STRICT_ALIGNMENT
if (((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
0) {
if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
while (l < len) {
if (n == 0) {
(*block)(ivec, ivec, key);
@@ -89,9 +88,7 @@ void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
while (len >= 16) {
(*block)(ivec, ivec, key);
for (; n < 16; n += sizeof(size_t)) {
size_t tmp = load_word_le(ivec + n) ^ load_word_le(in + n);
store_word_le(ivec + n, tmp);
store_word_le(out + n, tmp);
*(size_t *)(out + n) = *(size_t *)(ivec + n) ^= *(size_t *)(in + n);
}
len -= 16;
out += 16;
@@ -115,11 +112,9 @@ void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
--len;
n = (n + 1) % 16;
}
if (STRICT_ALIGNMENT &&
((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
0) {
if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
while (l < len) {
uint8_t c;
unsigned char c;
if (n == 0) {
(*block)(ivec, ivec, key);
}
@@ -134,9 +129,9 @@ void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
while (len >= 16) {
(*block)(ivec, ivec, key);
for (; n < 16; n += sizeof(size_t)) {
size_t t = load_word_le(in + n);
store_word_le(out + n, load_word_le(ivec + n) ^ t);
store_word_le(ivec + n, t);
size_t t = *(size_t *)(in + n);
*(size_t *)(out + n) = *(size_t *)(ivec + n) ^ t;
*(size_t *)(ivec + n) = t;
}
len -= 16;
out += 16;
@@ -232,3 +227,4 @@ void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block);
}
}
+3 -4
View File
@@ -100,8 +100,7 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
}
#if STRICT_ALIGNMENT
if (((uintptr_t)in | (uintptr_t)out |
(uintptr_t)ecount_buf) % sizeof(size_t) != 0) {
if (((size_t)in | (size_t)out | (size_t)ecount_buf) % sizeof(size_t) != 0) {
size_t l = 0;
while (l < len) {
if (n == 0) {
@@ -122,8 +121,8 @@ void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
(*block)(ivec, ecount_buf, key);
ctr128_inc(ivec);
for (n = 0; n < 16; n += sizeof(size_t)) {
store_word_le(out + n,
load_word_le(in + n) ^ load_word_le(ecount_buf + n));
*(size_t *)(out + n) = *(const size_t *)(in + n) ^
*(const size_t *)(ecount_buf + n);
}
len -= 16;
out += 16;
+36 -25
View File
@@ -550,7 +550,8 @@ int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) {
}
int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key,
const uint8_t *in, uint8_t *out, size_t len) {
const unsigned char *in, unsigned char *out,
size_t len) {
unsigned int n, ctr;
uint64_t mlen = ctx->len.u[1];
block128_f block = ctx->block;
@@ -591,8 +592,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key,
return 1;
}
}
if (STRICT_ALIGNMENT &&
((uintptr_t)in | (uintptr_t)out) % sizeof(size_t) != 0) {
if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) {
for (size_t i = 0; i < len; ++i) {
if (n == 0) {
(*block)(ctx->Yi.c, ctx->EKi.c, key);
@@ -614,12 +614,14 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key,
size_t j = GHASH_CHUNK;
while (j) {
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
(*block)(ctx->Yi.c, ctx->EKi.c, key);
++ctr;
ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
for (size_t i = 0; i < 16; i += sizeof(size_t)) {
store_word_le(out + i,
load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
out_t[i] = in_t[i] ^ ctx->EKi.t[i];
}
out += 16;
in += 16;
@@ -631,12 +633,14 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key,
size_t len_blocks = len & kSizeTWithoutLower4Bits;
if (len_blocks != 0) {
while (len >= 16) {
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
(*block)(ctx->Yi.c, ctx->EKi.c, key);
++ctr;
ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
for (size_t i = 0; i < 16; i += sizeof(size_t)) {
store_word_le(out + i,
load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
out_t[i] = in_t[i] ^ ctx->EKi.t[i];
}
out += 16;
in += 16;
@@ -646,13 +650,14 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key,
}
#else
while (len >= 16) {
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
(*block)(ctx->Yi.c, ctx->EKi.c, key);
++ctr;
ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
for (size_t i = 0; i < 16; i += sizeof(size_t)) {
size_t tmp = load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)];
store_word_le(out + i, tmp);
ctx->Xi.t[i / sizeof(size_t)] ^= tmp;
for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
ctx->Xi.t[i] ^= out_t[i] = in_t[i] ^ ctx->EKi.t[i];
}
GCM_MUL(ctx, Xi);
out += 16;
@@ -719,8 +724,7 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key,
return 1;
}
}
if (STRICT_ALIGNMENT &&
((uintptr_t)in | (uintptr_t)out) % sizeof(size_t) != 0) {
if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) {
for (size_t i = 0; i < len; ++i) {
uint8_t c;
if (n == 0) {
@@ -746,12 +750,14 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key,
GHASH(ctx, in, GHASH_CHUNK);
while (j) {
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
(*block)(ctx->Yi.c, ctx->EKi.c, key);
++ctr;
ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
for (size_t i = 0; i < 16; i += sizeof(size_t)) {
store_word_le(out + i,
load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
out_t[i] = in_t[i] ^ ctx->EKi.t[i];
}
out += 16;
in += 16;
@@ -763,12 +769,14 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key,
if (len_blocks != 0) {
GHASH(ctx, in, len_blocks);
while (len >= 16) {
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
(*block)(ctx->Yi.c, ctx->EKi.c, key);
++ctr;
ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
for (size_t i = 0; i < 16; i += sizeof(size_t)) {
store_word_le(out + i,
load_word_le(in + i) ^ ctx->EKi.t[i / sizeof(size_t)]);
for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
out_t[i] = in_t[i] ^ ctx->EKi.t[i];
}
out += 16;
in += 16;
@@ -777,13 +785,16 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key,
}
#else
while (len >= 16) {
size_t *out_t = (size_t *)out;
const size_t *in_t = (const size_t *)in;
(*block)(ctx->Yi.c, ctx->EKi.c, key);
++ctr;
ctx->Yi.d[3] = CRYPTO_bswap4(ctr);
for (size_t i = 0; i < 16; i += sizeof(size_t)) {
size_t c = load_word_le(in + i);
store_word_le(out + i, c ^ ctx->EKi.t[i / sizeof(size_t)]);
ctx->Xi.t[i / sizeof(size_t)] ^= c;
for (size_t i = 0; i < 16 / sizeof(size_t); ++i) {
size_t c = in_t[i];
out_t[i] = c ^ ctx->EKi.t[i];
ctx->Xi.t[i] ^= c;
}
GCM_MUL(ctx, Xi);
out += 16;
-10
View File
@@ -109,16 +109,6 @@ static inline void PUTU32(void *out, uint32_t v) {
OPENSSL_memcpy(out, &v, sizeof(v));
}
static inline size_t load_word_le(const void *in) {
size_t v;
OPENSSL_memcpy(&v, in, sizeof(v));
return v;
}
static inline void store_word_le(void *out, size_t v) {
OPENSSL_memcpy(out, &v, sizeof(v));
}
// block128_f is the type of a 128-bit, block cipher.
typedef void (*block128_f)(const uint8_t in[16], uint8_t out[16],
const void *key);
+4
View File
@@ -119,6 +119,10 @@ int RSA_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
extern const BN_ULONG kBoringSSLRSASqrtTwo[];
extern const size_t kBoringSSLRSASqrtTwoLen;
// rsa_less_than_words returns one if |a| < |b| and zero otherwise, where |a|
// and |b| both are |len| words long. It runs in constant time.
int rsa_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len);
// rsa_greater_than_pow2 returns one if |b| is greater than 2^|n| and zero
// otherwise.
int rsa_greater_than_pow2(const BIGNUM *b, int n);
-2
View File
@@ -157,8 +157,6 @@ int RSA_up_ref(RSA *rsa) {
return 1;
}
unsigned RSA_bits(const RSA *rsa) { return BN_num_bits(rsa->n); }
void RSA_get0_key(const RSA *rsa, const BIGNUM **out_n, const BIGNUM **out_e,
const BIGNUM **out_d) {
if (out_n != NULL) {
+19 -9
View File
@@ -775,6 +775,19 @@ const BN_ULONG kBoringSSLRSASqrtTwo[] = {
};
const size_t kBoringSSLRSASqrtTwoLen = OPENSSL_ARRAY_SIZE(kBoringSSLRSASqrtTwo);
int rsa_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len) {
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
crypto_word_t_too_small);
int ret = 0;
// Process the words in little-endian order.
for (size_t i = 0; i < len; i++) {
crypto_word_t eq = constant_time_eq_w(a[i], b[i]);
crypto_word_t lt = constant_time_lt_w(a[i], b[i]);
ret = constant_time_select_int(eq, ret, constant_time_select_int(lt, 1, 0));
}
return ret;
}
int rsa_greater_than_pow2(const BIGNUM *b, int n) {
if (BN_is_negative(b) || n == INT_MAX) {
return 0;
@@ -794,16 +807,11 @@ static int generate_prime(BIGNUM *out, int bits, const BIGNUM *e,
return 0;
}
// See FIPS 186-4 appendix B.3.3, steps 4 and 5. Note |bits| here is nlen/2.
// Use the limit from steps 4.7 and 5.8 for most values of |e|. When |e| is 3,
// the 186-4 limit is too low, so we use a higher one. Note this case is not
// reachable from |RSA_generate_key_fips|.
if (bits >= INT_MAX/32) {
// Ensure the bound on |tries| does not overflow.
if (bits >= INT_MAX/5) {
OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE);
return 0;
}
int limit = BN_is_word(e, 3) ? bits * 32 : bits * 5;
int ret = 0, tries = 0, rand_tries = 0;
BN_CTX_start(ctx);
@@ -812,6 +820,8 @@ static int generate_prime(BIGNUM *out, int bits, const BIGNUM *e,
goto err;
}
// See FIPS 186-4 appendix B.3.3, steps 4 and 5. Note |bits| here is
// nlen/2.
for (;;) {
// Generate a random number of length |bits| where the bottom bit is set
// (steps 4.2, 4.3, 5.2 and 5.3) and the top bit is set (implied by the
@@ -853,7 +863,7 @@ static int generate_prime(BIGNUM *out, int bits, const BIGNUM *e,
if (to_check > out_len) {
to_check = out_len;
}
if (!bn_less_than_words(
if (!rsa_less_than_words(
kBoringSSLRSASqrtTwo + kBoringSSLRSASqrtTwoLen - to_check,
out->d + out_len - to_check, to_check)) {
continue;
@@ -880,7 +890,7 @@ static int generate_prime(BIGNUM *out, int bits, const BIGNUM *e,
// If we've tried too many times to find a prime, abort (steps 4.7 and
// 5.8).
tries++;
if (tries >= limit) {
if (tries >= bits * 5) {
OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS);
goto err;
}
-19
View File
@@ -73,25 +73,6 @@ static const size_t kMinNumBuckets = 16;
static const size_t kMaxAverageChainLength = 2;
static const size_t kMinAverageChainLength = 1;
struct lhash_st {
// num_items contains the total number of items in the hash table.
size_t num_items;
// buckets is an array of |num_buckets| pointers. Each points to the head of
// a chain of LHASH_ITEM objects that have the same hash value, mod
// |num_buckets|.
LHASH_ITEM **buckets;
// num_buckets contains the length of |buckets|. This value is always >=
// kMinNumBuckets.
size_t num_buckets;
// callback_depth contains the current depth of |lh_doall| or |lh_doall_arg|
// calls. If non-zero then this suppresses resizing of the |buckets| array,
// which would otherwise disrupt the iteration.
unsigned callback_depth;
lhash_cmp_func comp;
lhash_hash_func hash;
};
_LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp) {
_LHASH *ret = OPENSSL_malloc(sizeof(_LHASH));
if (ret == NULL) {
+69 -29
View File
@@ -389,30 +389,16 @@ const char *OBJ_nid2ln(int nid) {
return obj->ln;
}
static ASN1_OBJECT *create_object_with_text_oid(int (*get_nid)(void),
const char *oid,
const char *short_name,
const char *long_name) {
uint8_t *buf;
size_t len;
CBB cbb;
if (!CBB_init(&cbb, 32) ||
!CBB_add_asn1_oid_from_text(&cbb, oid, strlen(oid)) ||
!CBB_finish(&cbb, &buf, &len)) {
OPENSSL_PUT_ERROR(OBJ, OBJ_R_INVALID_OID_STRING);
CBB_cleanup(&cbb);
return NULL;
}
ASN1_OBJECT *ret = ASN1_OBJECT_create(get_nid ? get_nid() : NID_undef, buf,
len, short_name, long_name);
OPENSSL_free(buf);
return ret;
}
ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) {
int nid = NID_undef;
ASN1_OBJECT *op = NULL;
unsigned char *buf;
unsigned char *p;
const unsigned char *bufp;
int contents_len, total_len;
if (!dont_search_names) {
int nid = OBJ_sn2nid(s);
nid = OBJ_sn2nid(s);
if (nid == NID_undef) {
nid = OBJ_ln2nid(s);
}
@@ -422,7 +408,31 @@ ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) {
}
}
return create_object_with_text_oid(NULL, s, NULL, NULL);
// Work out size of content octets
contents_len = a2d_ASN1_OBJECT(NULL, 0, s, -1);
if (contents_len <= 0) {
return NULL;
}
// Work out total size
total_len = ASN1_object_size(0, contents_len, V_ASN1_OBJECT);
buf = OPENSSL_malloc(total_len);
if (buf == NULL) {
OPENSSL_PUT_ERROR(OBJ, ERR_R_MALLOC_FAILURE);
return NULL;
}
p = buf;
// Write out tag+length
ASN1_put_object(&p, 0, contents_len, V_ASN1_OBJECT, V_ASN1_UNIVERSAL);
// Write out contents
a2d_ASN1_OBJECT(p, contents_len, s, -1);
bufp = buf;
op = d2i_ASN1_OBJECT(NULL, &bufp, total_len);
OPENSSL_free(buf);
return op;
}
static int strlcpy_int(char *dst, const char *src, int dst_size) {
@@ -611,11 +621,41 @@ static int obj_add_object(ASN1_OBJECT *obj) {
}
int OBJ_create(const char *oid, const char *short_name, const char *long_name) {
ASN1_OBJECT *op =
create_object_with_text_oid(obj_next_nid, oid, short_name, long_name);
if (op == NULL ||
!obj_add_object(op)) {
return NID_undef;
int ret = NID_undef;
ASN1_OBJECT *op = NULL;
unsigned char *buf = NULL;
int len;
len = a2d_ASN1_OBJECT(NULL, 0, oid, -1);
if (len <= 0) {
goto err;
}
return op->nid;
buf = OPENSSL_malloc(len);
if (buf == NULL) {
OPENSSL_PUT_ERROR(OBJ, ERR_R_MALLOC_FAILURE);
goto err;
}
len = a2d_ASN1_OBJECT(buf, len, oid, -1);
if (len == 0) {
goto err;
}
op = (ASN1_OBJECT *)ASN1_OBJECT_create(obj_next_nid(), buf, len, short_name,
long_name);
if (op == NULL) {
goto err;
}
if (obj_add_object(op)) {
ret = op->nid;
}
op = NULL;
err:
ASN1_OBJECT_free(op);
OPENSSL_free(buf);
return ret;
}
+2 -2
View File
@@ -764,13 +764,13 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
int PEM_def_callback(char *buf, int size, int rwflag, void *userdata)
{
if (!buf || !userdata || size < 0) {
if (!buf || !userdata) {
return 0;
}
size_t len = strlen((char *)userdata);
if (len >= (size_t)size) {
return 0;
}
BUF_strlcpy(buf, userdata, (size_t)size);
strcpy(buf, (char *)userdata);
return len;
}
+55 -4
View File
@@ -85,6 +85,57 @@ static inline poly1305_state_internal *poly1305_aligned_state(
return (poly1305_state_internal *)(((uint64_t)state + 63) & ~63);
}
// copy 0-63 bytes
static inline void
poly1305_block_copy(uint8_t *dst, const uint8_t *src, size_t bytes) {
size_t offset = src - dst;
if (bytes & 32) {
_mm_storeu_si128((xmmi *)(dst + 0),
_mm_loadu_si128((const xmmi *)(dst + offset + 0)));
_mm_storeu_si128((xmmi *)(dst + 16),
_mm_loadu_si128((const xmmi *)(dst + offset + 16)));
dst += 32;
}
if (bytes & 16) {
_mm_storeu_si128((xmmi *)dst, _mm_loadu_si128((const xmmi *)(dst + offset)));
dst += 16;
}
if (bytes & 8) {
*(uint64_t *)dst = *(const uint64_t *)(dst + offset);
dst += 8;
}
if (bytes & 4) {
*(uint32_t *)dst = *(const uint32_t *)(dst + offset);
dst += 4;
}
if (bytes & 2) {
*(uint16_t *)dst = *(uint16_t *)(dst + offset);
dst += 2;
}
if (bytes & 1) {
*(uint8_t *)dst = *(uint8_t *)(dst + offset);
}
}
// zero 0-15 bytes
static inline void poly1305_block_zero(uint8_t *dst, size_t bytes) {
if (bytes & 8) {
*(uint64_t *)dst = 0;
dst += 8;
}
if (bytes & 4) {
*(uint32_t *)dst = 0;
dst += 4;
}
if (bytes & 2) {
*(uint16_t *)dst = 0;
dst += 2;
}
if (bytes & 1) {
*(uint8_t *)dst = 0;
}
}
static inline size_t poly1305_min(size_t a, size_t b) {
return (a < b) ? a : b;
}
@@ -670,7 +721,7 @@ void CRYPTO_poly1305_update(poly1305_state *state, const uint8_t *m,
bytes -= 32;
} else {
want = poly1305_min(32 - st->leftover, bytes);
OPENSSL_memcpy(st->buffer + st->leftover, m, want);
poly1305_block_copy(st->buffer + st->leftover, m, want);
bytes -= want;
m += want;
st->leftover += want;
@@ -686,7 +737,7 @@ void CRYPTO_poly1305_update(poly1305_state *state, const uint8_t *m,
// handle leftover
if (st->leftover) {
want = poly1305_min(64 - st->leftover, bytes);
OPENSSL_memcpy(st->buffer + st->leftover, m, want);
poly1305_block_copy(st->buffer + st->leftover, m, want);
bytes -= want;
m += want;
st->leftover += want;
@@ -706,7 +757,7 @@ void CRYPTO_poly1305_update(poly1305_state *state, const uint8_t *m,
}
if (bytes) {
OPENSSL_memcpy(st->buffer + st->leftover, m, bytes);
poly1305_block_copy(st->buffer + st->leftover, m, bytes);
st->leftover += bytes;
}
}
@@ -782,7 +833,7 @@ poly1305_donna_atmost15bytes:
}
m[leftover++] = 1;
OPENSSL_memset(m + leftover, 0, 16 - leftover);
poly1305_block_zero(m + leftover, 16 - leftover);
leftover = 16;
t0 = U8TO64_LE(m + 0);
+22 -3
View File
@@ -69,15 +69,22 @@
#include "../internal.h"
static int parse_integer(CBS *cbs, BIGNUM **out) {
static int parse_integer_buggy(CBS *cbs, BIGNUM **out, int buggy) {
assert(*out == NULL);
*out = BN_new();
if (*out == NULL) {
return 0;
}
if (buggy) {
return BN_parse_asn1_unsigned_buggy(cbs, *out);
}
return BN_parse_asn1_unsigned(cbs, *out);
}
static int parse_integer(CBS *cbs, BIGNUM **out) {
return parse_integer_buggy(cbs, out, 0 /* not buggy */);
}
static int marshal_integer(CBB *cbb, BIGNUM *bn) {
if (bn == NULL) {
// An RSA object may be missing some components.
@@ -87,14 +94,14 @@ static int marshal_integer(CBB *cbb, BIGNUM *bn) {
return BN_marshal_asn1(cbb, bn);
}
RSA *RSA_parse_public_key(CBS *cbs) {
static RSA *parse_public_key(CBS *cbs, int buggy) {
RSA *ret = RSA_new();
if (ret == NULL) {
return NULL;
}
CBS child;
if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
!parse_integer(&child, &ret->n) ||
!parse_integer_buggy(&child, &ret->n, buggy) ||
!parse_integer(&child, &ret->e) ||
CBS_len(&child) != 0) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
@@ -112,6 +119,18 @@ RSA *RSA_parse_public_key(CBS *cbs) {
return ret;
}
RSA *RSA_parse_public_key(CBS *cbs) {
return parse_public_key(cbs, 0 /* not buggy */);
}
RSA *RSA_parse_public_key_buggy(CBS *cbs) {
// Estonian IDs issued between September 2014 to September 2015 are
// broken. See https://crbug.com/532048 and https://crbug.com/534766.
//
// TODO(davidben): Remove this code and callers in March 2016.
return parse_public_key(cbs, 1 /* buggy */);
}
RSA *RSA_public_key_from_bytes(const uint8_t *in, size_t in_len) {
CBS cbs;
CBS_init(&cbs, in, in_len);
+59
View File
@@ -622,6 +622,13 @@ TEST(RSATest, ASN1) {
sizeof(kEstonianRSAKey)));
EXPECT_FALSE(rsa);
ERR_clear_error();
// But |RSA_parse_public_key_buggy| will accept it.
CBS cbs;
CBS_init(&cbs, kEstonianRSAKey, sizeof(kEstonianRSAKey));
rsa.reset(RSA_parse_public_key_buggy(&cbs));
EXPECT_TRUE(rsa);
EXPECT_EQ(0u, CBS_len(&cbs));
}
TEST(RSATest, BadExponent) {
@@ -735,6 +742,58 @@ TEST(RSATest, SqrtTwo) {
EXPECT_EQ(3072u / 2u, bits);
}
TEST(RSATest, LessThanWords) {
// kTestVectors is an array of 256-bit values in sorted order.
static const BN_ULONG kTestVectors[][256 / BN_BITS2] = {
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000)},
{TOBN(0x00000000, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0x00000000, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xed17ac85, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xed17ac85, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xed17ac85, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xffffffff, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
};
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kTestVectors); i++) {
SCOPED_TRACE(i);
for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(kTestVectors); j++) {
SCOPED_TRACE(j);
EXPECT_EQ(i < j ? 1 : 0,
rsa_less_than_words(kTestVectors[i], kTestVectors[j],
OPENSSL_ARRAY_SIZE(kTestVectors[i])));
}
}
EXPECT_EQ(0, rsa_less_than_words(NULL, NULL, 0));
}
TEST(RSATest, GreaterThanPow2) {
bssl::UniquePtr<BIGNUM> b(BN_new());
BN_zero(b.get());
+3 -1
View File
@@ -61,6 +61,7 @@
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
#include <openssl/thread.h>
#include <openssl/x509.h>
@@ -234,7 +235,8 @@ static int add_cert_dir(BY_DIR *ctx, const char *dir, int type)
by_dir_entry_free(ent);
return 0;
}
BUF_strlcpy(ent->dir, ss, len + 1);
strncpy(ent->dir, ss, len);
ent->dir[len] = '\0';
if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) {
by_dir_entry_free(ent);
return 0;
+1
View File
@@ -59,6 +59,7 @@
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/lhash.h>
#include <openssl/pem.h>
#include <openssl/thread.h>
+1
View File
@@ -58,6 +58,7 @@
#include <string.h>
#include <openssl/err.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
#include <openssl/thread.h>
#include <openssl/x509.h>
+3 -1
View File
@@ -59,6 +59,7 @@
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/x509.h>
@@ -101,7 +102,8 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len)
buf = b->data;
OPENSSL_free(b);
}
BUF_strlcpy(buf, "NO X509_NAME", len);
strncpy(buf, "NO X509_NAME", len);
buf[len - 1] = '\0';
return buf;
}
-39
View File
@@ -26,7 +26,6 @@
#include <openssl/pem.h>
#include <openssl/pool.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "../internal.h"
@@ -997,41 +996,3 @@ TEST(X509Test, TestPrintUTCTIME) {
std::string(reinterpret_cast<const char *>(contents), len));
}
}
TEST(X509Test, PrettyPrintIntegers) {
static const char *kTests[] = {
// Small numbers are pretty-printed in decimal.
"0",
"-1",
"1",
"42",
"-42",
"256",
"-256",
// Large numbers are pretty-printed in hex to avoid taking quadratic time.
"0x0123456789",
"-0x0123456789",
};
for (const char *in : kTests) {
SCOPED_TRACE(in);
BIGNUM *bn = nullptr;
ASSERT_TRUE(BN_asc2bn(&bn, in));
bssl::UniquePtr<BIGNUM> free_bn(bn);
{
bssl::UniquePtr<ASN1_INTEGER> asn1(BN_to_ASN1_INTEGER(bn, nullptr));
ASSERT_TRUE(asn1);
bssl::UniquePtr<char> out(i2s_ASN1_INTEGER(nullptr, asn1.get()));
ASSERT_TRUE(out.get());
EXPECT_STREQ(in, out.get());
}
{
bssl::UniquePtr<ASN1_ENUMERATED> asn1(BN_to_ASN1_ENUMERATED(bn, nullptr));
ASSERT_TRUE(asn1);
bssl::UniquePtr<char> out(i2s_ASN1_ENUMERATED(nullptr, asn1.get()));
ASSERT_TRUE(out.get());
EXPECT_STREQ(in, out.get());
}
}
}
+6
View File
@@ -54,7 +54,13 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#include <openssl/asn1.h>
#include <openssl/buf.h>
#include <openssl/cipher.h>
#include <openssl/evp.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/x509.h>
const char *X509_verify_cert_error_string(long n)
+1
View File
@@ -61,6 +61,7 @@
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/thread.h>
+1
View File
@@ -57,6 +57,7 @@
#include <string.h>
#include <openssl/buf.h>
#include <openssl/lhash.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/stack.h>
+2 -2
View File
@@ -105,8 +105,8 @@ int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype,
return 1;
}
void X509_ALGOR_get0(const ASN1_OBJECT **paobj, int *pptype, const void **ppval,
const X509_ALGOR *algor)
void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, void **ppval,
X509_ALGOR *algor)
{
if (paobj)
*paobj = algor->algorithm;
+4 -3
View File
@@ -166,9 +166,9 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
for (i = 0; i < 8; i++) {
BIO_snprintf(htmp, sizeof htmp, "%X", p[0] << 8 | p[1]);
p += 2;
BUF_strlcat(oline, htmp, sizeof(oline));
strcat(oline, htmp);
if (i != 7)
BUF_strlcat(oline, ":", sizeof(oline));
strcat(oline, ":");
}
} else {
if (!X509V3_add_value("IP Address", "<invalid>", &ret))
@@ -588,7 +588,8 @@ static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx)
objtmp = OPENSSL_malloc(objlen + 1);
if (objtmp == NULL)
return 0;
BUF_strlcpy(objtmp, value, objlen + 1);
strncpy(objtmp, value, objlen);
objtmp[objlen] = 0;
gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0);
OPENSSL_free(objtmp);
if (!gen->d.otherName->type_id)
-1
View File
@@ -231,7 +231,6 @@ int GENERAL_NAME_set0_othername(GENERAL_NAME *gen,
oth = OTHERNAME_new();
if (!oth)
return 0;
ASN1_TYPE_free(oth->value);
oth->type_id = oid;
oth->value = value;
GENERAL_NAME_set0_value(gen, GEN_OTHERNAME, oth);
+2 -1
View File
@@ -192,7 +192,8 @@ static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD
OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
goto err;
}
BUF_strlcpy(objtmp, cnf->name, objlen + 1);
strncpy(objtmp, cnf->name, objlen);
objtmp[objlen] = 0;
acc->method = OBJ_txt2obj(objtmp, 0);
if (!acc->method) {
OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_OBJECT);
+7 -15
View File
@@ -288,9 +288,9 @@ void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit,
int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value,
int crit, unsigned long flags)
{
int errcode, extidx = -1;
X509_EXTENSION *ext = NULL, *extmp;
STACK_OF(X509_EXTENSION) *ret = NULL;
int extidx = -1;
int errcode;
X509_EXTENSION *ext, *extmp;
unsigned long ext_op = flags & X509V3_ADD_OP_MASK;
/*
@@ -348,21 +348,13 @@ int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value,
return 1;
}
if ((ret = *x) == NULL
&& (ret = sk_X509_EXTENSION_new_null()) == NULL)
goto m_fail;
if (!sk_X509_EXTENSION_push(ret, ext))
goto m_fail;
if (!*x && !(*x = sk_X509_EXTENSION_new_null()))
return -1;
if (!sk_X509_EXTENSION_push(*x, ext))
return -1;
*x = ret;
return 1;
m_fail:
if (ret != *x)
sk_X509_EXTENSION_free(ret);
X509_EXTENSION_free(ext);
return -1;
err:
if (!(flags & X509V3_ADD_SILENT))
OPENSSL_PUT_ERROR(X509V3, errcode);
+2 -41
View File
@@ -155,45 +155,6 @@ int X509V3_add_value_bool_nf(char *name, int asn1_bool,
return 1;
}
static char *bignum_to_string(const BIGNUM *bn)
{
char *tmp, *ret;
size_t len;
/*
* Display large numbers in hex and small numbers in decimal. Converting to
* decimal takes quadratic time and is no more useful than hex for large
* numbers.
*/
if (BN_num_bits(bn) < 32) {
return BN_bn2dec(bn);
}
tmp = BN_bn2hex(bn);
if (tmp == NULL) {
return NULL;
}
len = strlen(tmp) + 3;
ret = OPENSSL_malloc(len);
if (ret == NULL) {
OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
OPENSSL_free(tmp);
return NULL;
}
/* Prepend "0x", but place it after the "-" if negative. */
if (tmp[0] == '-') {
BUF_strlcpy(ret, "-0x", len);
BUF_strlcat(ret, tmp + 1, len);
} else {
BUF_strlcpy(ret, "0x", len);
BUF_strlcat(ret, tmp, len);
}
OPENSSL_free(tmp);
return ret;
}
char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a)
{
BIGNUM *bntmp = NULL;
@@ -201,7 +162,7 @@ char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a)
if (!a)
return NULL;
if (!(bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) ||
!(strtmp = bignum_to_string(bntmp)))
!(strtmp = BN_bn2dec(bntmp)))
OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
BN_free(bntmp);
return strtmp;
@@ -214,7 +175,7 @@ char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, ASN1_INTEGER *a)
if (!a)
return NULL;
if (!(bntmp = ASN1_INTEGER_to_BN(a, NULL)) ||
!(strtmp = bignum_to_string(bntmp)))
!(strtmp = BN_bn2dec(bntmp)))
OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE);
BN_free(bntmp);
return strtmp;
-18
View File
@@ -2,24 +2,6 @@ include_directories(../include)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-prototypes")
add_executable(
bn_mod_exp
bn_mod_exp.cc
)
target_link_libraries(bn_mod_exp Fuzzer)
target_link_libraries(bn_mod_exp crypto)
add_executable(
bn_div
bn_div.cc
)
target_link_libraries(bn_div Fuzzer)
target_link_libraries(bn_div crypto)
add_executable(
privkey
-69
View File
@@ -1,69 +0,0 @@
/* Copyright (c) 2017, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/span.h>
#define CHECK(expr) \
do { \
if (!(expr)) { \
printf("%s failed\n", #expr); \
abort(); \
} \
} while (false)
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
CBS cbs, child0, child1;
uint8_t sign0, sign1;
CBS_init(&cbs, buf, len);
if (!CBS_get_u16_length_prefixed(&cbs, &child0) ||
!CBS_get_u8(&child0, &sign0) ||
CBS_len(&child0) == 0 ||
!CBS_get_u16_length_prefixed(&cbs, &child1) ||
!CBS_get_u8(&child1, &sign1) ||
CBS_len(&child1) == 0) {
return 0;
}
bssl::UniquePtr<BIGNUM> numerator(
BN_bin2bn(CBS_data(&child0), CBS_len(&child0), nullptr));
BN_set_negative(numerator.get(), sign0 % 2);
bssl::UniquePtr<BIGNUM> divisor(
BN_bin2bn(CBS_data(&child1), CBS_len(&child1), nullptr));
BN_set_negative(divisor.get(), sign1 % 2);
if (BN_is_zero(divisor.get())) {
return 0;
}
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
bssl::UniquePtr<BIGNUM> result(BN_new());
bssl::UniquePtr<BIGNUM> remainder(BN_new());
CHECK(ctx);
CHECK(result);
CHECK(remainder);
CHECK(BN_div(result.get(), remainder.get(), numerator.get(), divisor.get(),
ctx.get()));
CHECK(BN_ucmp(remainder.get(), divisor.get()) < 0);
// Check that result*divisor+remainder = numerator.
CHECK(BN_mul(result.get(), result.get(), divisor.get(), ctx.get()));
CHECK(BN_add(result.get(), result.get(), remainder.get()));
CHECK(BN_cmp(result.get(), numerator.get()) == 0);
return 0;
}

Some files were not shown because too many files have changed in this diff Show More