Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions .vac/boringssl-upstream.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
"ref": "refs/heads/main",
"mirror_url": "https://github.com/google/boringssl.git"
},
"previous_upstream_sha": "05fb4bcd239ec7bd7db0d606dcf131e62e24509e",
"current_upstream_sha": "beddb582d9e8786a07d79f1cf054d4792b3dd81f",
"last_synced_at": "2026-05-18T07:46:08Z",
"previous_upstream_sha": "beddb582d9e8786a07d79f1cf054d4792b3dd81f",
"current_upstream_sha": "956bac6e4db9b33789dcedb5ea3f28e51030cead",
"last_synced_at": "2026-05-25T07:56:06Z",
"local_patch": {
"description": "Use portable C code for fiat_p256 mul/sqr on Windows by removing ADX assembly dispatch.",
"commit": "d6238994c547f070c1e053aada216ee3ce67e8e0",
"path": ".vac/patches/fiat-p256-windows.patch",
"sha256": "97f9d35fe2ac3e6c9d488558faaa40a36135394e595926391e9224c6599ccd19"
},
"last_verification": {
"github_mirror_sha": "beddb582d9e8786a07d79f1cf054d4792b3dd81f",
"github_mirror_sha": "956bac6e4db9b33789dcedb5ea3f28e51030cead",
"patch_replayed": true,
"fiat_p256_adx_dispatch_absent": true
},
Expand All @@ -39,6 +39,13 @@
"new_upstream_sha": "beddb582d9e8786a07d79f1cf054d4792b3dd81f",
"github_mirror_sha": "beddb582d9e8786a07d79f1cf054d4792b3dd81f",
"local_patch_sha256": "97f9d35fe2ac3e6c9d488558faaa40a36135394e595926391e9224c6599ccd19"
},
{
"synced_at": "2026-05-25T07:56:06Z",
"previous_upstream_sha": "beddb582d9e8786a07d79f1cf054d4792b3dd81f",
"new_upstream_sha": "956bac6e4db9b33789dcedb5ea3f28e51030cead",
"github_mirror_sha": "956bac6e4db9b33789dcedb5ea3f28e51030cead",
"local_patch_sha256": "97f9d35fe2ac3e6c9d488558faaa40a36135394e595926391e9224c6599ccd19"
}
]
}
2 changes: 1 addition & 1 deletion crypto/bio/bio.cc
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ static int bio_read_all(Bio *bio, uint8_t **out, size_t *out_len,
if (n == 0) {
*out_len = done;
return 1;
} else if (n == -1) {
} else if (n < 0) {
OPENSSL_free(*out);
return 0;
}
Expand Down
40 changes: 40 additions & 0 deletions crypto/bio/bio_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,46 @@ TEST(BIOTest, ReadASN1) {
}
}

TEST(BIOTest, ReadASN1ErrorNegative) {
// A custom BIO whose bread callback returns a negative value other than -1.
BIO_METHOD *meth = BIO_meth_new(BIO_TYPE_SOURCE_SINK, "evil");
ASSERT_TRUE(meth);
BIO_meth_set_read(meth, [](BIO *bio, char *buf, int len) -> int {
int *call_count = reinterpret_cast<int *>(BIO_get_data(bio));
(*call_count)++;
if (*call_count == 1) {
if (len < 2) {
return -1;
}
buf[0] = '\x30';
buf[1] = '\x80';
return 2;
}
return -2;
});
BIO_meth_set_ctrl(
meth, [](BIO *bio, int cmd, long larg, void *parg) -> long { return 1; });

UniquePtr<BIO> bio(BIO_new(meth));
ASSERT_TRUE(bio);

int call_count = 0;
BIO_set_data(bio.get(), &call_count);
BIO_set_init(bio.get(), 1);

uint8_t *out = nullptr;
size_t out_len = 0;
int ok = BIO_read_asn1(bio.get(), &out, &out_len, 1000);
EXPECT_EQ(ok, 0);
if (ok == 1) {
OPENSSL_free(out);
}

bio.reset();
BIO_meth_free(meth);
}


TEST(BIOTest, MemReadOnly) {
// A memory BIO created from |BIO_new_mem_buf| is a read-only buffer.
static const char kData[] = "abcdefghijklmno";
Expand Down
11 changes: 7 additions & 4 deletions crypto/bytestring/bytestring_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ TEST(CBSTest, Skip) {

TEST(CBSTest, GetUint) {
static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26};
uint8_t u8;
uint16_t u16;
uint32_t u32;
Expand All @@ -75,12 +76,14 @@ TEST(CBSTest, GetUint) {
EXPECT_EQ(0x40506u, u32);
ASSERT_TRUE(CBS_get_u32(&data, &u32));
EXPECT_EQ(0x708090au, u32);
ASSERT_TRUE(CBS_get_u48(&data, &u64));
EXPECT_EQ(0xb0c0d0e0f10u, u64);
ASSERT_TRUE(CBS_get_u64(&data, &u64));
EXPECT_EQ(0xb0c0d0e0f101112u, u64);
EXPECT_EQ(0x1112131415161718u, u64);
ASSERT_TRUE(CBS_get_last_u8(&data, &u8));
EXPECT_EQ(0x14u, u8);
EXPECT_EQ(0x1au, u8);
ASSERT_TRUE(CBS_get_last_u8(&data, &u8));
EXPECT_EQ(0x13u, u8);
EXPECT_EQ(0x19u, u8);
EXPECT_FALSE(CBS_get_u8(&data, &u8));
EXPECT_FALSE(CBS_get_last_u8(&data, &u8));

Expand Down
2 changes: 2 additions & 0 deletions crypto/bytestring/cbs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ int CBS_get_u32le(CBS *cbs, uint32_t *out) {
return 1;
}

int CBS_get_u48(CBS *cbs, uint64_t *out) { return cbs_get_u(cbs, out, 6); }

int CBS_get_u64(CBS *cbs, uint64_t *out) { return cbs_get_u(cbs, out, 8); }

int CBS_get_u64le(CBS *cbs, uint64_t *out) {
Expand Down
21 changes: 19 additions & 2 deletions crypto/fipsmodule/rsa/rsa_impl.cc.inc
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,23 @@ static int rsa_generate_key_impl(RSAImpl *rsa, int bits, const BIGNUM *e_value,
return 0;
}

// The smallest reasonable RSA exponent is 3, and it definitely must be odd.
// Catching these here prevents endless loops or slow computation when trying
// to generate keys later, and results in a better error code.
if (
// Would fail in |bn_lcm_consttime| as it only allows positive integers.
BN_is_negative(e_value) ||
// Would fail in |generate_prime| as only one |rsa->p|-1 is coprime with
// an even |e_value| and that one is a little bit short. (The R in RSA
// doesn't stand for Rabin.)
!BN_is_odd(e_value) ||
// Would loop endlessly because it'll always compute an |rsa->d| exponent
// of 1, which is too small.
BN_is_one(e_value)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
return 0;
}

UniquePtr<BN_CTX> ctx(BN_CTX_new());
if (ctx == nullptr) {
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
Expand Down Expand Up @@ -800,8 +817,8 @@ static int rsa_generate_key_impl(RSAImpl *rsa, int bits, const BIGNUM *e_value,
if (!generate_prime(rsa->p.get(), prime_bits, rsa->e.get(), nullptr,
pow2_prime_bits_100, ctx.get(), cb) ||
!BN_GENCB_call(cb, 3, 0) ||
!generate_prime(rsa->q.get(), prime_bits, rsa->e.get(), rsa->p.get(), pow2_prime_bits_100,
ctx.get(), cb) ||
!generate_prime(rsa->q.get(), prime_bits, rsa->e.get(), rsa->p.get(),
pow2_prime_bits_100, ctx.get(), cb) ||
!BN_GENCB_call(cb, 3, 1)) {
OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
return 0;
Expand Down
45 changes: 45 additions & 0 deletions crypto/rsa/rsa_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,51 @@ TEST(RSATest, CheckKey) {
ERR_clear_error();
}

TEST(RSATest, KeygenBadExponent) {
UniquePtr<RSA> rsa_opaque(RSA_new());
RSAImpl *rsa = FromOpaque(rsa_opaque.get());
ASSERT_TRUE(rsa);

UniquePtr<BIGNUM> e(BN_new());
ASSERT_TRUE(e);

// 3 is the smallest allowed public key value.
ASSERT_TRUE(BN_set_word(e.get(), 3));
ASSERT_TRUE(RSA_generate_key_ex(rsa, 2048, e.get(), nullptr));

// Maybe I prefer the Rabin scheme. But this is an RSA API!
ASSERT_TRUE(BN_set_word(e.get(), 2));
EXPECT_FALSE(RSA_generate_key_ex(rsa, 2048, e.get(), nullptr));
EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_RSA, RSA_R_BAD_E_VALUE));

// Rabin-Shamir-Adleman? Nope.
ASSERT_TRUE(BN_set_word(e.get(), 6));
EXPECT_FALSE(RSA_generate_key_ex(rsa, 2048, e.get(), nullptr));
EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_RSA, RSA_R_BAD_E_VALUE));

// RSA with exponent 1 is a joke. But we already use ROT26 for that purpose.
ASSERT_TRUE(BN_set_word(e.get(), 1));
EXPECT_FALSE(RSA_generate_key_ex(rsa, 2048, e.get(), nullptr));
EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_RSA, RSA_R_BAD_E_VALUE));

// RSA with exponent 0 is also known as /dev/null, and not supported here.
ASSERT_TRUE(BN_set_word(e.get(), 0));
EXPECT_FALSE(RSA_generate_key_ex(rsa, 2048, e.get(), nullptr));
EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_RSA, RSA_R_BAD_E_VALUE));

// Now this is just silly - perfectly fine RSA with e=3, except with an extra
// inversion that cryptographically does nothing at all except waste cycles.
// Throw it away.
ASSERT_TRUE(BN_set_word(e.get(), 3));
BN_set_negative(e.get(), 1);
EXPECT_FALSE(RSA_generate_key_ex(rsa, 2048, e.get(), nullptr));
EXPECT_TRUE(ErrorEquals(ERR_get_error(), ERR_LIB_RSA, RSA_R_BAD_E_VALUE));

// To validate nothing got corrupted, try good old 65537.
ASSERT_TRUE(BN_set_word(e.get(), RSA_F4));
EXPECT_TRUE(RSA_generate_key_ex(rsa, 2048, e.get(), nullptr));
}

TEST(RSATest, KeygenFail) {
UniquePtr<RSA> rsa_opaque(RSA_new());
RSAImpl *rsa = FromOpaque(rsa_opaque.get());
Expand Down
30 changes: 30 additions & 0 deletions crypto/x509/x509_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8434,6 +8434,36 @@ TEST(X509Test, ParamInheritance) {
// The new value is used.
EXPECT_EQ(X509_VERIFY_PARAM_get_depth(dest.get()), 10);
}

// |X509_VERIFY_PARAM_inherit| and |X509_VERIFY_PARAM_set1| must fail if the
// source parameter is poisoned.
{
UniquePtr<X509_VERIFY_PARAM> dest(X509_VERIFY_PARAM_new());
ASSERT_TRUE(dest);
UniquePtr<X509_VERIFY_PARAM> src(X509_VERIFY_PARAM_new());
ASSERT_TRUE(src);

// Poison the source parameter (using an embedded NUL in hostname).
ASSERT_FALSE(X509_VERIFY_PARAM_set1_host(src.get(), "a", 2));

EXPECT_FALSE(X509_VERIFY_PARAM_inherit(dest.get(), src.get()));
EXPECT_FALSE(X509_VERIFY_PARAM_set1(dest.get(), src.get()));
}

// |X509_VERIFY_PARAM_inherit| and |X509_VERIFY_PARAM_set1| must fail if the
// destination parameter is poisoned.
{
UniquePtr<X509_VERIFY_PARAM> dest(X509_VERIFY_PARAM_new());
ASSERT_TRUE(dest);
UniquePtr<X509_VERIFY_PARAM> src(X509_VERIFY_PARAM_new());
ASSERT_TRUE(src);

// Poison the destination parameter (using an embedded NUL in hostname).
ASSERT_FALSE(X509_VERIFY_PARAM_set1_host(dest.get(), "a", 2));

EXPECT_FALSE(X509_VERIFY_PARAM_inherit(dest.get(), src.get()));
EXPECT_FALSE(X509_VERIFY_PARAM_set1(dest.get(), src.get()));
}
}

TEST(X509Test, PublicKeyCache) {
Expand Down
18 changes: 11 additions & 7 deletions crypto/x509/x509_vpm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,21 @@ static void copy_int_param(T *dest, const T *src, T default_val,
}
}

// x509_verify_param_copy copies fields from |src| to |dest|. If both |src| and
// x509_verify_param_merge merges fields from |src| to |dest|. If both |src| and
// |dest| have some field set, |prefer_src| determines whether |src| or |dest|'s
// version is used.
static int x509_verify_param_copy(X509_VERIFY_PARAM *dest,
const X509_VERIFY_PARAM *src,
bool prefer_src) {
static int x509_verify_param_merge(X509_VERIFY_PARAM *dest,
const X509_VERIFY_PARAM *src,
bool prefer_src) {
if (src == nullptr) {
return 1;
}

if (src->poison || dest->poison) {
OPENSSL_PUT_ERROR(X509, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}

copy_int_param(&dest->purpose, &src->purpose, /*default_val=*/0, prefer_src);
copy_int_param(&dest->trust, &src->trust, /*default_val=*/0, prefer_src);
copy_int_param(&dest->depth, &src->depth, /*default_val=*/-1, prefer_src);
Expand Down Expand Up @@ -175,22 +180,21 @@ static int x509_verify_param_copy(X509_VERIFY_PARAM *dest,
}
}

dest->poison = src->poison;
return 1;
}

int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
const X509_VERIFY_PARAM *src) {
// Prefer the destination. That is, this function only changes unset
// parameters in |dest|.
return x509_verify_param_copy(dest, src, /*prefer_src=*/false);
return x509_verify_param_merge(dest, src, /*prefer_src=*/false);
}

int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
const X509_VERIFY_PARAM *from) {
// Prefer the source. That is, values in |to| are only preserved if they were
// unset in |from|.
return x509_verify_param_copy(to, from, /*prefer_src=*/true);
return x509_verify_param_merge(to, from, /*prefer_src=*/true);
}

static int int_x509_param_set1(char **pdest, size_t *pdestlen, const char *src,
Expand Down
2 changes: 1 addition & 1 deletion include/openssl/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ extern "C" {
// A consumer may use this symbol in the preprocessor to temporarily build
// against multiple revisions of BoringSSL at the same time. It is not
// recommended to do so for longer than is necessary.
#define BORINGSSL_API_VERSION 40
#define BORINGSSL_API_VERSION 41

#if defined(BORINGSSL_SHARED_LIBRARY)

Expand Down
4 changes: 4 additions & 0 deletions include/openssl/bytestring.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ OPENSSL_EXPORT int CBS_get_u32(CBS *cbs, uint32_t *out);
// |cbs| and advances |cbs|. It returns one on success and zero on error.
OPENSSL_EXPORT int CBS_get_u32le(CBS *cbs, uint32_t *out);

// CBS_get_u48 sets |*out| to the next, big-endian 48-bit value from |cbs| and
// advances |cbs|. It returns one on success and zero on error.
OPENSSL_EXPORT int CBS_get_u48(CBS *cbs, uint64_t *out);

// CBS_get_u64 sets |*out| to the next, big-endian uint64_t value from |cbs|
// and advances |cbs|. It returns one on success and zero on error.
OPENSSL_EXPORT int CBS_get_u64(CBS *cbs, uint64_t *out);
Expand Down
2 changes: 2 additions & 0 deletions include/openssl/prefix_symbols.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ssl/d1_both.cc
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ bool dtls1_process_handshake_fragments(SSL *ssl, uint8_t *out_alert,
implicit_ack = true;
}

if (msg_hdr.seq - ssl->d1->handshake_read_seq > SSL_MAX_HANDSHAKE_FLIGHT) {
if (msg_hdr.seq - ssl->d1->handshake_read_seq >= SSL_MAX_HANDSHAKE_FLIGHT) {
// Ignore fragments too far in the future.
skipped_fragments = true;
continue;
Expand Down
16 changes: 16 additions & 0 deletions ssl/ssl_privkey.cc
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,16 @@ enum ssl_private_key_result_t ssl_private_key_sign(
assert(!hs->can_release_private_key);

if (key_method != nullptr) {
if (key_method->sign == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return ssl_private_key_failure;
}
enum ssl_private_key_result_t ret;
if (hs->pending_private_key_op) {
if (key_method->complete == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return ssl_private_key_failure;
}
ret = key_method->complete(ssl, out, out_len, max_out);
} else {
ret = key_method->sign(ssl, out, out_len, max_out, sigalg, in.data(),
Expand Down Expand Up @@ -321,8 +329,16 @@ enum ssl_private_key_result_t ssl_private_key_decrypt(SSL_HANDSHAKE *hs,
const SSLCredential *const cred = hs->credential.get();
assert(!hs->can_release_private_key);
if (cred->key_method != nullptr) {
if (cred->key_method->decrypt == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return ssl_private_key_failure;
}
enum ssl_private_key_result_t ret;
if (hs->pending_private_key_op) {
if (cred->key_method->complete == nullptr) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return ssl_private_key_failure;
}
ret = cred->key_method->complete(ssl, out, out_len, max_out);
} else {
ret = cred->key_method->decrypt(ssl, out, out_len, max_out, in.data(),
Expand Down
Loading