Skip to content

Commit

Permalink
Merge branch 'main' into ec-nistp-scalar-mul-gen-table
Browse files Browse the repository at this point in the history
  • Loading branch information
dkostic committed Jul 1, 2024
2 parents 06cada8 + 05d3bfd commit c72f9a0
Show file tree
Hide file tree
Showing 23 changed files with 389 additions and 118 deletions.
1 change: 1 addition & 0 deletions crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,7 @@ if(BUILD_TESTING)
digest_extra/digest_test.cc
dilithium/p_dilithium_test.cc
dsa/dsa_test.cc
des/des_test.cc
endian_test.cc
err/err_test.cc
evp_extra/evp_extra_test.cc
Expand Down
14 changes: 7 additions & 7 deletions crypto/cipher_extra/e_des.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ static int des_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
DES_cblock *deskey = (DES_cblock *)key;
EVP_DES_KEY *dat = (EVP_DES_KEY *)ctx->cipher_data;

DES_set_key(deskey, &dat->ks.ks);
DES_set_key_unchecked(deskey, &dat->ks.ks);
return 1;
}

Expand Down Expand Up @@ -147,9 +147,9 @@ static int des_ede3_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
DES_cblock *deskey = (DES_cblock *)key;
DES_EDE_KEY *dat = (DES_EDE_KEY *)ctx->cipher_data;

DES_set_key(&deskey[0], &dat->ks.ks[0]);
DES_set_key(&deskey[1], &dat->ks.ks[1]);
DES_set_key(&deskey[2], &dat->ks.ks[2]);
DES_set_key_unchecked(&deskey[0], &dat->ks.ks[0]);
DES_set_key_unchecked(&deskey[1], &dat->ks.ks[1]);
DES_set_key_unchecked(&deskey[2], &dat->ks.ks[2]);

return 1;
}
Expand Down Expand Up @@ -185,9 +185,9 @@ static int des_ede_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
DES_cblock *deskey = (DES_cblock *)key;
DES_EDE_KEY *dat = (DES_EDE_KEY *)ctx->cipher_data;

DES_set_key(&deskey[0], &dat->ks.ks[0]);
DES_set_key(&deskey[1], &dat->ks.ks[1]);
DES_set_key(&deskey[0], &dat->ks.ks[2]);
DES_set_key_unchecked(&deskey[0], &dat->ks.ks[0]);
DES_set_key_unchecked(&deskey[1], &dat->ks.ks[1]);
DES_set_key_unchecked(&deskey[0], &dat->ks.ks[2]);

return 1;
}
Expand Down
68 changes: 65 additions & 3 deletions crypto/des/des.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ static const uint32_t DES_SPtrans[8][64] = {
((t) = ((((a) << (16 - (n))) ^ (a)) & (m)), \
(a) = (a) ^ (t) ^ ((t) >> (16 - (n))))

void DES_set_key(const DES_cblock *key, DES_key_schedule *schedule) {
void DES_set_key_unchecked(const DES_cblock *key, DES_key_schedule *schedule) {
static const int shifts2[16] = {0, 0, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 0};
uint32_t c, d, t, s, t2;
Expand Down Expand Up @@ -349,9 +349,38 @@ void DES_set_key(const DES_cblock *key, DES_key_schedule *schedule) {
}
}

// SP 800-67r2 section 2, the last bit of each byte in DES_cblock.bytes is used
// for parity. The parity bits should be set to the complement of the modulo 2
// sum of the previous seven bits
static int DES_check_key_parity(const DES_cblock *key) {
uint8_t result = UINT8_MAX;

for (size_t i = 0; i < DES_KEY_SZ; i++) {
uint8_t b = key->bytes[i];
b ^= b >> 4;
b ^= b >> 2;
b ^= b >> 1;
result &= constant_time_eq_8(b & 1, 1);
}
return result & 1;
}

int DES_set_key(const DES_cblock *key, DES_key_schedule *schedule)
{
int result = 0;

if (!DES_check_key_parity(key)) {
result = -1;
}
if (DES_is_weak_key(key)) {
result = -2;
}
DES_set_key_unchecked(key, schedule);
return result;
}

int DES_key_sched(const DES_cblock *key, DES_key_schedule *schedule) {
DES_set_key(key, schedule);
return 1;
return DES_set_key(key, schedule);
}

static const uint8_t kOddParity[256] = {
Expand Down Expand Up @@ -383,6 +412,39 @@ void DES_set_odd_parity(DES_cblock *key) {
}
}

// Weak keys have unintended behaviors which may hurt the security of their use
// see SP 800-67r2 section 3.3.2
static const DES_cblock weak_keys[] = {
// Weak keys: encryption is equal to decryption (encrypting twice produces the original plaintext)
{{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}},
{{0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE}},
{{0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E}},
{{0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1}},
// Semi-weak keys: encryption with one of these keys is equal to encryption with a different key
{{0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE}},
{{0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01}},
{{0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1}},
{{0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E}},
{{0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1}},
{{0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01}},
{{0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE}},
{{0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E}},
{{0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E}},
{{0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01}},
{{0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE}},
{{0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1}}
};

int DES_is_weak_key(const DES_cblock *key)
{
crypto_word_t result = 0;
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(weak_keys); i++) {
int match = CRYPTO_memcmp(&weak_keys[i], key, sizeof(DES_cblock));
result |= constant_time_is_zero_w(match);
}
return (int)(result & 1);
}

static void DES_encrypt1(uint32_t *data, const DES_key_schedule *ks, int enc) {
uint32_t l, r, t, u;

Expand Down
50 changes: 50 additions & 0 deletions crypto/des/des_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#include <openssl/des.h>

#include <gtest/gtest.h>

TEST(DESTest, WeakKeys) {
// The all 2 key is not weak and has odd parity
DES_cblock validKey = {{2, 2, 2, 2, 2, 2, 2, 2}};
EXPECT_FALSE(DES_is_weak_key(&validKey));
DES_key_schedule des;
EXPECT_EQ(0, DES_set_key(&validKey, &des));

// Weak key example from SP 800-67r2 section 3.3.2
static const DES_cblock weakKey = {{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}};
EXPECT_TRUE(DES_is_weak_key(&weakKey));
EXPECT_EQ(-2, DES_set_key(&weakKey, &des));
}

// If it wasn't for MSVC this could be __builtin_popcount, if this was C++20
// it could be std::popcount
static int countSetBits(uint8_t n) {
int count = 0;
while (n) {
count += n & 1;
n >>= 1;
}
return count;
}

TEST(DESTest, Parity) {
// The all 2 key is not weak and has odd parity for each byte
DES_cblock key = {{2, 2, 2, 2, 2, 2, 2, 2}};
DES_key_schedule des;
int result = DES_set_key(&key, &des);
EXPECT_EQ(result, 0);

for (uint8_t i = 0; i < 255; i++) {
key.bytes[0] = i;
result = DES_set_key(&key, &des);
int bitsSet = countSetBits(i);
int oddParity = bitsSet % 2 == 1;
if (oddParity) {
EXPECT_EQ(result, 0);
} else {
EXPECT_EQ(result, -1);
}
}
}
2 changes: 2 additions & 0 deletions crypto/fipsmodule/cpucap/cpu_arm_freebsd.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ void OPENSSL_cpuid_setup(void) {
// left at zero. The rest of this function will then gracefully report
// the features are absent.
elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
#if defined(AT_HWCAP2)
elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2));
#endif

// Matching OpenSSL, only report other features if NEON is present.
if (hwcap & HWCAP_NEON) {
Expand Down
4 changes: 4 additions & 0 deletions crypto/fipsmodule/cpucap/cpu_arm_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,11 @@ void OPENSSL_cpuid_setup(void) {
// this is now rare (see Chrome's Net.NeedsHWCAP2Workaround metric), but AES
// and PMULL extensions are very useful, so we still carry the workaround
// for now.
#if defined(AT_HWCAP2)
unsigned long hwcap2 = getauxval(AT_HWCAP2);
#else
unsigned long hwcap2 = 0;
#endif
if (hwcap2 == 0) {
hwcap2 = crypto_get_arm_hwcap2_from_cpuinfo(&cpuinfo);
g_needs_hwcap2_workaround = hwcap2 != 0;
Expand Down
4 changes: 4 additions & 0 deletions crypto/fipsmodule/cpucap/cpu_ppc64le.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ static void handle_cpu_env(unsigned long *out, const char *in) {
extern uint8_t OPENSSL_cpucap_initialized;

void OPENSSL_cpuid_setup(void) {
#if defined(AT_HWCAP2)
OPENSSL_ppc64le_hwcap2 = getauxval(AT_HWCAP2);
#else
OPENSSL_ppc64le_hwcap2 = 0;
#endif
OPENSSL_cpucap_initialized = 1;

// OPENSSL_ppccap is a 64-bit hex string which may start with "0x".
Expand Down
10 changes: 8 additions & 2 deletions crypto/fipsmodule/ec/ec_nistp.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,14 @@ void ec_nistp_point_add(const ec_nistp_meth *ctx,
// Returns i-th bit of the scalar (zero or one).
// The caller is responsible for making sure i is within bounds of the scalar.
static int16_t get_bit(const EC_SCALAR *in, size_t i) {
uint8_t *in_bytes = (uint8_t*)in->words;
return (in_bytes[i >> 3] >> (i & 7)) & 1;
// |in->words| is an array of BN_ULONGs which can be either 8 or 4 bytes long.
#if defined(OPENSSL_64_BIT)
OPENSSL_STATIC_ASSERT(sizeof(BN_ULONG) == 8, bn_ulong_not_eight_bytes);
return (in->words[i >> 6] >> (i & 63)) & 1;
#else
OPENSSL_STATIC_ASSERT(sizeof(BN_ULONG) == 4, bn_ulong_not_four_bytes);
return (in->words[i >> 5] >> (i & 31)) & 1;
#endif
}

#define DIV_AND_CEIL(a, b) ((a + b - 1) / b)
Expand Down
4 changes: 2 additions & 2 deletions crypto/fipsmodule/service_indicator/service_indicator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4280,7 +4280,7 @@ TEST(ServiceIndicatorTest, DRBG) {
// Since this is running in FIPS mode it should end in FIPS
// Update this when the AWS-LC version number is modified
TEST(ServiceIndicatorTest, AWSLCVersionString) {
ASSERT_STREQ(awslc_version_string(), "AWS-LC FIPS 1.30.1");
ASSERT_STREQ(awslc_version_string(), "AWS-LC FIPS 1.31.0");
}

#else
Expand Down Expand Up @@ -4323,6 +4323,6 @@ TEST(ServiceIndicatorTest, BasicTest) {
// Since this is not running in FIPS mode it shouldn't end in FIPS
// Update this when the AWS-LC version number is modified
TEST(ServiceIndicatorTest, AWSLCVersionString) {
ASSERT_STREQ(awslc_version_string(), "AWS-LC 1.30.1");
ASSERT_STREQ(awslc_version_string(), "AWS-LC 1.31.0");
}
#endif // AWSLC_FIPS
2 changes: 1 addition & 1 deletion include/openssl/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ extern "C" {
// ServiceIndicatorTest.AWSLCVersionString
// Note: there are two versions of this test. Only one test is compiled
// depending on FIPS mode.
#define AWSLC_VERSION_NUMBER_STRING "1.30.1"
#define AWSLC_VERSION_NUMBER_STRING "1.31.0"

#if defined(BORINGSSL_SHARED_LIBRARY)

Expand Down
21 changes: 16 additions & 5 deletions include/openssl/des.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,22 @@ typedef struct DES_ks {
#define DES_CBC_MODE 0
#define DES_PCBC_MODE 1

// DES_set_key performs a key schedule and initialises |schedule| with |key|.
OPENSSL_EXPORT void DES_set_key(const DES_cblock *key,
DES_key_schedule *schedule);

// DES_key_sched calls |DES_set_key| and returns 1.
// DES_is_weak_key checks if |key| is a weak or semi-weak key, see SP 800-67r2
// section 3.3.2
OPENSSL_EXPORT int DES_is_weak_key(const DES_cblock *key);

// DES_set_key checks that |key| is not weak and the parity before calling
// |DES_set_key_unchecked|. The key schedule is always initialized, the checks
// only affect the return value:
// 0: key is not weak and has odd parity
// -1: key is not odd
// -2: key is a weak key, the parity might also be even
OPENSSL_EXPORT int DES_set_key(const DES_cblock *key, DES_key_schedule *schedule);

// DES_set_key_unchecked performs a key schedule and initialises |schedule| with |key|.
OPENSSL_EXPORT void DES_set_key_unchecked(const DES_cblock *key, DES_key_schedule *schedule);

// DES_key_sched calls |DES_set_key|.
OPENSSL_EXPORT int DES_key_sched(const DES_cblock *key, DES_key_schedule *schedule);

// DES_set_odd_parity sets the parity bits (the least-significant bits in each
Expand Down
52 changes: 39 additions & 13 deletions include/openssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3289,7 +3289,8 @@ OPENSSL_EXPORT int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos,

// SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is called
// during ClientHello processing in order to select an ALPN protocol from the
// client's list of offered protocols.
// client's list of offered protocols. |SSL_select_next_proto| is an optional
// utility function which may be useful in implementing this callback.
//
// The callback is passed a wire-format (i.e. a series of non-empty, 8-bit
// length-prefixed strings) ALPN protocol list in |in|. To select a protocol,
Expand Down Expand Up @@ -3458,7 +3459,8 @@ OPENSSL_EXPORT void SSL_CTX_set_next_protos_advertised_cb(
// set to point to the selected protocol (which may be within |in|). The length
// of the protocol name must be written into |*out_len|. The server's advertised
// protocols are provided in |in| and |in_len|. The callback can assume that
// |in| is syntactically valid.
// |in| is syntactically valid. |SSL_select_next_proto| is an optional utility
// function which may be useful in implementing this callback.
//
// The client must select a protocol. It is fatal to the connection if this
// callback returns a value other than |SSL_TLSEXT_ERR_OK|.
Expand All @@ -3481,21 +3483,45 @@ OPENSSL_EXPORT void SSL_get0_next_proto_negotiated(const SSL *ssl,
const uint8_t **out_data,
unsigned *out_len);

// SSL_select_next_proto implements the standard protocol selection. It is
// expected that this function is called from the callback set by
// SSL_select_next_proto implements the standard protocol selection for either
// ALPN servers or NPN clients. It is expected that this function is called from
// the callback set by |SSL_CTX_set_alpn_select_cb| or
// |SSL_CTX_set_next_proto_select_cb|.
//
// |peer| and |supported| must be vectors of 8-bit, length-prefixed byte strings
// containing the peer and locally-configured protocols, respectively. The
// length byte itself is not included in the length. A byte string of length 0
// is invalid. No byte string may be truncated. |supported| is assumed to be
// non-empty.
//
// This function finds the first protocol in |peer| which is also in
// |supported|. If one was found, it sets |*out| and |*out_len| to point to it
// and returns |OPENSSL_NPN_NEGOTIATED|. Otherwise, it returns
// |peer| and |supported| contain the peer and locally-configured protocols,
// respectively. This function finds the first protocol in |peer| which is also
// in |supported|. If one was found, it sets |*out| and |*out_len| to point to
// it and returns |OPENSSL_NPN_NEGOTIATED|. Otherwise, it returns
// |OPENSSL_NPN_NO_OVERLAP| and sets |*out| and |*out_len| to the first
// supported protocol.
//
// In ALPN, the server should only select protocols among those that the client
// offered. Thus, if this function returns |OPENSSL_NPN_NO_OVERLAP|, the caller
// should ignore |*out| and return |SSL_TLSEXT_ERR_ALERT_FATAL| from
// |SSL_CTX_set_alpn_select_cb|'s callback to indicate there was no match.
//
// In NPN, the client may either select one of the server's protocols, or an
// "opportunistic" protocol as described in Section 6 of
// draft-agl-tls-nextprotoneg-03. When this function returns
// |OPENSSL_NPN_NO_OVERLAP|, |*out| implicitly selects the first supported
// protocol for use as the opportunistic protocol. The caller may use it,
// ignore it and select a different opportunistic protocol, or ignore it and
// select no protocol (empty string).
//
// |peer| and |supported| must be vectors of 8-bit, length-prefixed byte
// strings. The length byte itself is not included in the length. A byte string
// of length 0 is invalid. No byte string may be truncated. |supported| must be
// non-empty; a caller that supports no ALPN/NPN protocols should skip
// negotiating the extension, rather than calling this function. If any of these
// preconditions do not hold, this function will return |OPENSSL_NPN_NO_OVERLAP|
// and set |*out| and |*out_len| to an empty buffer for robustness, but callers
// are not recommended to rely on this. An empty buffer is not a valid output
// for |SSL_CTX_set_alpn_select_cb|'s callback.
//
// WARNING: |*out| and |*out_len| may alias either |peer| or |supported| and may
// not be used after one of those buffers is modified or released. Additionally,
// this function is not const-correct for compatibility reasons. Although |*out|
// is a non-const pointer, callers may not modify the buffer though |*out|.
OPENSSL_EXPORT int SSL_select_next_proto(uint8_t **out, uint8_t *out_len,
const uint8_t *peer, unsigned peer_len,
const uint8_t *supported,
Expand Down
17 changes: 10 additions & 7 deletions ssl/extensions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1473,16 +1473,19 @@ bool ssl_is_alpn_protocol_allowed(const SSL_HANDSHAKE *hs,
}

// Check that the protocol name is one of the ones we advertised.
CBS client_protocol_name_list =
MakeConstSpan(hs->config->alpn_client_proto_list),
client_protocol_name;
while (CBS_len(&client_protocol_name_list) > 0) {
if (!CBS_get_u8_length_prefixed(&client_protocol_name_list,
&client_protocol_name)) {
return ssl_alpn_list_contains_protocol(hs->config->alpn_client_proto_list,
protocol);
}

bool ssl_alpn_list_contains_protocol(Span<const uint8_t> list,
Span<const uint8_t> protocol) {
CBS cbs = list, candidate;
while (CBS_len(&cbs) > 0) {
if (!CBS_get_u8_length_prefixed(&cbs, &candidate)) {
return false;
}

if (client_protocol_name == protocol) {
if (candidate == protocol) {
return true;
}
}
Expand Down
Loading

0 comments on commit c72f9a0

Please sign in to comment.