Give ssl_cipher_preference_list_st a destructor.
Change-Id: I578a284c6a8cae773a97d3d30ad8a5cd13f56164
Reviewed-on: https://boringssl-review.googlesource.com/27491
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Steven Valdez <svaldez@google.com>
diff --git a/ssl/handshake_server.cc b/ssl/handshake_server.cc
index 84004de..6404cc9 100644
--- a/ssl/handshake_server.cc
+++ b/ssl/handshake_server.cc
@@ -332,14 +332,14 @@
static const SSL_CIPHER *ssl3_choose_cipher(
SSL_HANDSHAKE *hs, const SSL_CLIENT_HELLO *client_hello,
- const struct ssl_cipher_preference_list_st *server_pref) {
+ const SSLCipherPreferenceList *server_pref) {
SSL *const ssl = hs->ssl;
const STACK_OF(SSL_CIPHER) *prio, *allow;
// in_group_flags will either be NULL, or will point to an array of bytes
// which indicate equal-preference groups in the |prio| stack. See the
- // comment about |in_group_flags| in the |ssl_cipher_preference_list_st|
+ // comment about |in_group_flags| in the |SSLCipherPreferenceList|
// struct.
- const uint8_t *in_group_flags;
+ const bool *in_group_flags;
// group_min contains the minimal index so far found in a group, or -1 if no
// such value exists yet.
int group_min = -1;
@@ -351,13 +351,13 @@
}
if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) {
- prio = server_pref->ciphers;
+ prio = server_pref->ciphers.get();
in_group_flags = server_pref->in_group_flags;
allow = client_pref.get();
} else {
prio = client_pref.get();
in_group_flags = NULL;
- allow = server_pref->ciphers;
+ allow = server_pref->ciphers.get();
}
uint32_t mask_k, mask_a;
@@ -375,7 +375,7 @@
(c->algorithm_auth & mask_a) &&
// Check the cipher is in the |allow| list.
sk_SSL_CIPHER_find(allow, &cipher_index, c)) {
- if (in_group_flags != NULL && in_group_flags[i] == 1) {
+ if (in_group_flags != NULL && in_group_flags[i]) {
// This element of |prio| is in a group. Update the minimum index found
// so far and continue looking.
if (group_min == -1 || (size_t)group_min > cipher_index) {
@@ -389,7 +389,7 @@
}
}
- if (in_group_flags != NULL && in_group_flags[i] == 0 && group_min != -1) {
+ if (in_group_flags != NULL && !in_group_flags[i] && group_min != -1) {
// We are about to leave a group, but we found a match in it, so that's
// our answer.
return sk_SSL_CIPHER_value(allow, group_min);
diff --git a/ssl/internal.h b/ssl/internal.h
index f1fc63f..b258589 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -457,9 +457,48 @@
#define SSL_HANDSHAKE_MAC_SHA256 0x2
#define SSL_HANDSHAKE_MAC_SHA384 0x4
-// SSL_MAX_DIGEST is the number of digest types which exist. When adding a new
-// one, update the table in ssl_cipher.c.
-#define SSL_MAX_DIGEST 4
+// An SSLCipherPreferenceList contains a list of SSL_CIPHERs with equal-
+// preference groups. For TLS clients, the groups are moot because the server
+// picks the cipher and groups cannot be expressed on the wire. However, for
+// servers, the equal-preference groups allow the client's preferences to be
+// partially respected. (This only has an effect with
+// SSL_OP_CIPHER_SERVER_PREFERENCE).
+//
+// The equal-preference groups are expressed by grouping SSL_CIPHERs together.
+// All elements of a group have the same priority: no ordering is expressed
+// within a group.
+//
+// The values in |ciphers| are in one-to-one correspondence with
+// |in_group_flags|. (That is, sk_SSL_CIPHER_num(ciphers) is the number of
+// bytes in |in_group_flags|.) The bytes in |in_group_flags| are either 1, to
+// indicate that the corresponding SSL_CIPHER is not the last element of a
+// group, or 0 to indicate that it is.
+//
+// For example, if |in_group_flags| contains all zeros then that indicates a
+// traditional, fully-ordered preference. Every SSL_CIPHER is the last element
+// of the group (i.e. they are all in a one-element group).
+//
+// For a more complex example, consider:
+// ciphers: A B C D E F
+// in_group_flags: 1 1 0 0 1 0
+//
+// That would express the following, order:
+//
+// A E
+// B -> D -> F
+// C
+struct SSLCipherPreferenceList {
+ static constexpr bool kAllowUniquePtr = true;
+
+ SSLCipherPreferenceList() = default;
+ ~SSLCipherPreferenceList();
+
+ bool Init(UniquePtr<STACK_OF(SSL_CIPHER)> ciphers,
+ Span<const bool> in_group_flags);
+
+ UniquePtr<STACK_OF(SSL_CIPHER)> ciphers;
+ bool *in_group_flags = nullptr;
+};
// ssl_cipher_get_evp_aead sets |*out_aead| to point to the correct EVP_AEAD
// object for |cipher| protocol version |version|. It sets |*out_mac_secret_len|
@@ -477,13 +516,12 @@
const SSL_CIPHER *cipher);
// ssl_create_cipher_list evaluates |rule_str|. It sets |*out_cipher_list| to a
-// newly-allocated |ssl_cipher_preference_list_st| containing the result. It
-// returns true on success and false on failure. If |strict| is true, nonsense
-// will be rejected. If false, nonsense will be silently ignored. An empty
-// result is considered an error regardless of |strict|.
-bool ssl_create_cipher_list(
- struct ssl_cipher_preference_list_st **out_cipher_list,
- const char *rule_str, bool strict);
+// newly-allocated |SSLCipherPreferenceList| containing the result. It returns
+// true on success and false on failure. If |strict| is true, nonsense will be
+// rejected. If false, nonsense will be silently ignored. An empty result is
+// considered an error regardless of |strict|.
+bool ssl_create_cipher_list(SSLCipherPreferenceList **out_cipher_list,
+ const char *rule_str, bool strict);
// ssl_cipher_get_value returns the cipher suite id of |cipher|.
uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher);
@@ -1921,41 +1959,6 @@
// crypto/x509.
extern const SSL_X509_METHOD ssl_noop_x509_method;
-// ssl_cipher_preference_list_st contains a list of SSL_CIPHERs with
-// equal-preference groups. For TLS clients, the groups are moot because the
-// server picks the cipher and groups cannot be expressed on the wire. However,
-// for servers, the equal-preference groups allow the client's preferences to
-// be partially respected. (This only has an effect with
-// SSL_OP_CIPHER_SERVER_PREFERENCE).
-//
-// The equal-preference groups are expressed by grouping SSL_CIPHERs together.
-// All elements of a group have the same priority: no ordering is expressed
-// within a group.
-//
-// The values in |ciphers| are in one-to-one correspondence with
-// |in_group_flags|. (That is, sk_SSL_CIPHER_num(ciphers) is the number of
-// bytes in |in_group_flags|.) The bytes in |in_group_flags| are either 1, to
-// indicate that the corresponding SSL_CIPHER is not the last element of a
-// group, or 0 to indicate that it is.
-//
-// For example, if |in_group_flags| contains all zeros then that indicates a
-// traditional, fully-ordered preference. Every SSL_CIPHER is the last element
-// of the group (i.e. they are all in a one-element group).
-//
-// For a more complex example, consider:
-// ciphers: A B C D E F
-// in_group_flags: 1 1 0 0 1 0
-//
-// That would express the following, order:
-//
-// A E
-// B -> D -> F
-// C
-struct ssl_cipher_preference_list_st {
- STACK_OF(SSL_CIPHER) *ciphers;
- uint8_t *in_group_flags;
-};
-
struct tlsext_ticket_key {
static constexpr bool kAllowUniquePtr = true;
@@ -1998,7 +2001,7 @@
// configuration.
enum tls13_variant_t tls13_variant;
- struct ssl_cipher_preference_list_st *cipher_list;
+ SSLCipherPreferenceList *cipher_list;
X509_STORE *cert_store;
LHASH_OF(SSL_SESSION) *sessions;
@@ -2621,7 +2624,7 @@
X509_VERIFY_PARAM *param;
// crypto
- struct ssl_cipher_preference_list_st *cipher_list;
+ SSLCipherPreferenceList *cipher_list;
// session info
@@ -2853,13 +2856,9 @@
void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session,
uint32_t timeout);
-void ssl_cipher_preference_list_free(
- struct ssl_cipher_preference_list_st *cipher_list);
-
// ssl_get_cipher_preferences returns the cipher preference list for TLS 1.2 and
// below.
-const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(
- const SSL *ssl);
+const SSLCipherPreferenceList *ssl_get_cipher_preferences(const SSL *ssl);
void ssl_update_cache(SSL_HANDSHAKE *hs, int mode);
diff --git a/ssl/s3_lib.cc b/ssl/s3_lib.cc
index baa5a17..b1fc5fb 100644
--- a/ssl/s3_lib.cc
+++ b/ssl/s3_lib.cc
@@ -215,8 +215,7 @@
ssl->s3 = NULL;
}
-const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(
- const SSL *ssl) {
+const SSLCipherPreferenceList *ssl_get_cipher_preferences(const SSL *ssl) {
if (ssl->cipher_list != NULL) {
return ssl->cipher_list;
}
diff --git a/ssl/ssl_cipher.cc b/ssl/ssl_cipher.cc
index 32e6c2c..f02fa8a 100644
--- a/ssl/ssl_cipher.cc
+++ b/ssl/ssl_cipher.cc
@@ -811,9 +811,14 @@
*head = curr;
}
-static void ssl_cipher_collect_ciphers(CIPHER_ORDER *co_list,
- CIPHER_ORDER **head_p,
- CIPHER_ORDER **tail_p) {
+static bool ssl_cipher_collect_ciphers(Array<CIPHER_ORDER> *out_co_list,
+ CIPHER_ORDER **out_head,
+ CIPHER_ORDER **out_tail) {
+ Array<CIPHER_ORDER> co_list;
+ if (!co_list.Init(kCiphersLen)) {
+ return false;
+ }
+
size_t co_list_num = 0;
for (const SSL_CIPHER &cipher : kCiphers) {
// TLS 1.3 ciphers do not participate in this mechanism.
@@ -844,9 +849,35 @@
co_list[co_list_num - 1].next = NULL;
- *head_p = &co_list[0];
- *tail_p = &co_list[co_list_num - 1];
+ *out_head = &co_list[0];
+ *out_tail = &co_list[co_list_num - 1];
+ } else {
+ *out_head = nullptr;
+ *out_tail = nullptr;
}
+ *out_co_list = std::move(co_list);
+ return true;
+}
+
+SSLCipherPreferenceList::~SSLCipherPreferenceList() {
+ OPENSSL_free(in_group_flags);
+}
+
+bool SSLCipherPreferenceList::Init(UniquePtr<STACK_OF(SSL_CIPHER)> ciphers_arg,
+ Span<const bool> in_group_flags_arg) {
+ if (sk_SSL_CIPHER_num(ciphers_arg.get()) != in_group_flags_arg.size()) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return false;
+ }
+
+ Array<bool> copy;
+ if (!copy.CopyFrom(in_group_flags_arg)) {
+ return false;
+ }
+ ciphers = std::move(ciphers_arg);
+ size_t unused_len;
+ copy.Release(&in_group_flags, &unused_len);
+ return true;
}
// ssl_cipher_apply_rule applies the rule type |rule| to ciphers matching its
@@ -1201,15 +1232,8 @@
return true;
}
-bool ssl_create_cipher_list(
- struct ssl_cipher_preference_list_st **out_cipher_list,
- const char *rule_str, bool strict) {
- STACK_OF(SSL_CIPHER) *cipherstack = NULL;
- CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr;
- uint8_t *in_group_flags = NULL;
- unsigned int num_in_group_flags = 0;
- struct ssl_cipher_preference_list_st *pref_list = NULL;
-
+bool ssl_create_cipher_list(SSLCipherPreferenceList **out_cipher_list,
+ const char *rule_str, bool strict) {
// Return with error if nothing to do.
if (rule_str == NULL || out_cipher_list == NULL) {
return false;
@@ -1218,14 +1242,12 @@
// Now we have to collect the available ciphers from the compiled in ciphers.
// We cannot get more than the number compiled in, so it is used for
// allocation.
- co_list = (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * kCiphersLen);
- if (co_list == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ Array<CIPHER_ORDER> co_list;
+ CIPHER_ORDER *head = nullptr, *tail = nullptr;
+ if (!ssl_cipher_collect_ciphers(&co_list, &head, &tail)) {
return false;
}
- ssl_cipher_collect_ciphers(co_list, &head, &tail);
-
// Now arrange all ciphers by preference:
// TODO(davidben): Compute this order once and copy it.
@@ -1285,7 +1307,7 @@
if (strncmp(rule_str, "DEFAULT", 7) == 0) {
if (!ssl_cipher_process_rulestr(SSL_DEFAULT_CIPHER_LIST, &head, &tail,
strict)) {
- goto err;
+ return false;
}
rule_p += 7;
if (*rule_p == ':') {
@@ -1295,75 +1317,52 @@
if (*rule_p != '\0' &&
!ssl_cipher_process_rulestr(rule_p, &head, &tail, strict)) {
- goto err;
+ return false;
}
// Allocate new "cipherstack" for the result, return with error
// if we cannot get one.
- cipherstack = sk_SSL_CIPHER_new_null();
- if (cipherstack == NULL) {
- goto err;
- }
-
- in_group_flags = (uint8_t *)OPENSSL_malloc(kCiphersLen);
- if (!in_group_flags) {
- goto err;
+ UniquePtr<STACK_OF(SSL_CIPHER)> cipherstack(sk_SSL_CIPHER_new_null());
+ Array<bool> in_group_flags;
+ if (cipherstack == nullptr ||
+ !in_group_flags.Init(kCiphersLen)) {
+ return false;
}
// The cipher selection for the list is done. The ciphers are added
// to the resulting precedence to the STACK_OF(SSL_CIPHER).
- for (curr = head; curr != NULL; curr = curr->next) {
+ size_t num_in_group_flags = 0;
+ for (CIPHER_ORDER *curr = head; curr != NULL; curr = curr->next) {
if (curr->active) {
- if (!sk_SSL_CIPHER_push(cipherstack, curr->cipher)) {
- goto err;
+ if (!sk_SSL_CIPHER_push(cipherstack.get(), curr->cipher)) {
+ return false;
}
in_group_flags[num_in_group_flags++] = curr->in_group;
}
}
- OPENSSL_free(co_list); // Not needed any longer
- co_list = NULL;
- pref_list = (ssl_cipher_preference_list_st *)OPENSSL_malloc(
- sizeof(struct ssl_cipher_preference_list_st));
- if (!pref_list) {
- goto err;
+ UniquePtr<SSLCipherPreferenceList> pref_list =
+ MakeUnique<SSLCipherPreferenceList>();
+ if (!pref_list ||
+ !pref_list->Init(
+ std::move(cipherstack),
+ MakeConstSpan(in_group_flags).subspan(0, num_in_group_flags))) {
+ return false;
}
- pref_list->ciphers = cipherstack;
- pref_list->in_group_flags = NULL;
- if (num_in_group_flags) {
- pref_list->in_group_flags = (uint8_t *)OPENSSL_malloc(num_in_group_flags);
- if (!pref_list->in_group_flags) {
- goto err;
- }
- OPENSSL_memcpy(pref_list->in_group_flags, in_group_flags,
- num_in_group_flags);
+
+ if (*out_cipher_list) {
+ Delete(*out_cipher_list);
}
- OPENSSL_free(in_group_flags);
- in_group_flags = NULL;
- if (*out_cipher_list != NULL) {
- ssl_cipher_preference_list_free(*out_cipher_list);
- }
- *out_cipher_list = pref_list;
- pref_list = NULL;
+ *out_cipher_list = pref_list.release();
// Configuring an empty cipher list is an error but still updates the
// output.
- if (sk_SSL_CIPHER_num((*out_cipher_list)->ciphers) == 0) {
+ if (sk_SSL_CIPHER_num((*out_cipher_list)->ciphers.get()) == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
return false;
}
return true;
-
-err:
- OPENSSL_free(co_list);
- OPENSSL_free(in_group_flags);
- sk_SSL_CIPHER_free(cipherstack);
- if (pref_list) {
- OPENSSL_free(pref_list->in_group_flags);
- }
- OPENSSL_free(pref_list);
- return false;
}
uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher) {
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 8f1de02..78a1860 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -272,16 +272,6 @@
return ret;
}
-void ssl_cipher_preference_list_free(
- struct ssl_cipher_preference_list_st *cipher_list) {
- if (cipher_list == NULL) {
- return;
- }
- sk_SSL_CIPHER_free(cipher_list->ciphers);
- OPENSSL_free(cipher_list->in_group_flags);
- OPENSSL_free(cipher_list);
-}
-
void ssl_update_cache(SSL_HANDSHAKE *hs, int mode) {
SSL *const ssl = hs->ssl;
SSL_CTX *ctx = ssl->session_ctx;
@@ -622,7 +612,7 @@
CRYPTO_MUTEX_cleanup(&ctx->lock);
lh_SSL_SESSION_free(ctx->sessions);
- ssl_cipher_preference_list_free(ctx->cipher_list);
+ Delete(ctx->cipher_list);
Delete(ctx->cert);
sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->client_custom_extensions,
SSL_CUSTOM_EXTENSION_free);
@@ -765,7 +755,7 @@
BIO_free_all(ssl->wbio);
// add extra stuff
- ssl_cipher_preference_list_free(ssl->cipher_list);
+ Delete(ssl->cipher_list);
SSL_SESSION_free(ssl->session);
@@ -1820,11 +1810,11 @@
}
STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx) {
- return ctx->cipher_list->ciphers;
+ return ctx->cipher_list->ciphers.get();
}
int SSL_CTX_cipher_in_group(const SSL_CTX *ctx, size_t i) {
- if (i >= sk_SSL_CIPHER_num(ctx->cipher_list->ciphers)) {
+ if (i >= sk_SSL_CIPHER_num(ctx->cipher_list->ciphers.get())) {
return 0;
}
return ctx->cipher_list->in_group_flags[i];
@@ -1835,13 +1825,8 @@
return NULL;
}
- const struct ssl_cipher_preference_list_st *prefs =
- ssl_get_cipher_preferences(ssl);
- if (prefs == NULL) {
- return NULL;
- }
-
- return prefs->ciphers;
+ const SSLCipherPreferenceList *prefs = ssl_get_cipher_preferences(ssl);
+ return prefs == nullptr ? nullptr : prefs->ciphers.get();
}
const char *SSL_get_cipher_list(const SSL *ssl, int n) {