Serialize SSL configuration in handoff and check it on application.
A split SSL handshake may involve 2 binaries, potentially built at
different versions: call them the "handoff/handback" binary and the
"handshake" binary. We would like to guarantee that the
handoff/handback binary does not make any promises that the handshake
binary cannot keep.
As a start, this commit serializes |kCiphers| to the handoff message.
When the handoff message is applied to an |SSL|, any configured
ciphers not listed in the handoff message will be removed, in order to
prevent them from being negotiated.
Subsequent commits will apply the same approach to other lists of features.
Change-Id: Idf6dbeadb750c076ab0509c09b9d3f22eb162b9c
Reviewed-on: https://boringssl-review.googlesource.com/c/29264
Reviewed-by: Matt Braithwaite <mab@google.com>
diff --git a/ssl/ssl_cipher.cc b/ssl/ssl_cipher.cc
index 0ed91d6..a420f4d 100644
--- a/ssl/ssl_cipher.cc
+++ b/ssl/ssl_cipher.cc
@@ -156,7 +156,6 @@
BSSL_NAMESPACE_BEGIN
-// kCiphers is an array of all supported ciphers, sorted by id.
static constexpr SSL_CIPHER kCiphers[] = {
// The RSA ciphers
// Cipher 02
@@ -464,7 +463,9 @@
};
-static const size_t kCiphersLen = OPENSSL_ARRAY_SIZE(kCiphers);
+Span<const SSL_CIPHER> AllCiphers() {
+ return MakeConstSpan(kCiphers, OPENSSL_ARRAY_SIZE(kCiphers));
+}
#define CIPHER_ADD 1
#define CIPHER_KILL 2
@@ -707,7 +708,7 @@
CIPHER_ORDER **out_head,
CIPHER_ORDER **out_tail) {
Array<CIPHER_ORDER> co_list;
- if (!co_list.Init(kCiphersLen)) {
+ if (!co_list.Init(OPENSSL_ARRAY_SIZE(kCiphers))) {
return false;
}
@@ -772,6 +773,31 @@
return true;
}
+bool SSLCipherPreferenceList::Init(const SSLCipherPreferenceList& other) {
+ size_t size = sk_SSL_CIPHER_num(other.ciphers.get());
+ Span<const bool> other_flags(other.in_group_flags, size);
+ UniquePtr<STACK_OF(SSL_CIPHER)> other_ciphers(sk_SSL_CIPHER_dup(
+ other.ciphers.get()));
+ if (!other_ciphers) {
+ return false;
+ }
+ return Init(std::move(other_ciphers), other_flags);
+}
+
+void SSLCipherPreferenceList::Remove(const SSL_CIPHER *cipher) {
+ size_t index;
+ if (!sk_SSL_CIPHER_find(ciphers.get(), &index, cipher)) {
+ return;
+ }
+ if (!in_group_flags[index] /* last element of group */ && index > 0) {
+ in_group_flags[index-1] = false;
+ }
+ for (size_t i = index; i < sk_SSL_CIPHER_num(ciphers.get()) - 1; ++i) {
+ in_group_flags[i] = in_group_flags[i+1];
+ }
+ sk_SSL_CIPHER_delete(ciphers.get(), index);
+}
+
// ssl_cipher_apply_rule applies the rule type |rule| to ciphers matching its
// parameters in the linked list from |*head_p| to |*tail_p|. It writes the new
// head and tail of the list to |*head_p| and |*tail_p|, respectively.
@@ -1051,7 +1077,7 @@
// Look for a matching exact cipher. These aren't allowed in multipart
// rules.
if (!multi && ch != '+') {
- for (j = 0; j < kCiphersLen; j++) {
+ for (j = 0; j < OPENSSL_ARRAY_SIZE(kCiphers); j++) {
const SSL_CIPHER *cipher = &kCiphers[j];
if (rule_equals(cipher->name, buf, buf_len) ||
rule_equals(cipher->standard_name, buf, buf_len)) {
@@ -1217,7 +1243,7 @@
UniquePtr<STACK_OF(SSL_CIPHER)> cipherstack(sk_SSL_CIPHER_new_null());
Array<bool> in_group_flags;
if (cipherstack == nullptr ||
- !in_group_flags.Init(kCiphersLen)) {
+ !in_group_flags.Init(OPENSSL_ARRAY_SIZE(kCiphers))) {
return false;
}
@@ -1345,7 +1371,8 @@
c.id = 0x03000000L | value;
return reinterpret_cast<const SSL_CIPHER *>(bsearch(
- &c, kCiphers, kCiphersLen, sizeof(SSL_CIPHER), ssl_cipher_id_cmp));
+ &c, kCiphers, OPENSSL_ARRAY_SIZE(kCiphers), sizeof(SSL_CIPHER),
+ ssl_cipher_id_cmp));
}
uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher) { return cipher->id; }