Name |select_certificate_cb| return values

The |select_certificate_cb| return values are somewhat confusing due
to the fact that they don't match the |cert_cb| ones, despite the
similarities between the two callbacks (they both have "certificate" in
the name! well, sort of).

This also documents the error return value (-1) which was previously
undocumented, and it expands the |SSL_CTX_set_select_certificate_cb|
documentation regarding retrial (by shamelessly copying from
|SSL_CTX_set_ticket_aead_method|).

Also updates other scattered documentation that was missed by previous
changes.

Change-Id: Ib962b31d08e6475e09954cbc3c939988b0ba13f7
Reviewed-on: https://boringssl-review.googlesource.com/14245
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
Alessandro Ghedini 2017-03-14 23:36:00 +00:00 committed by CQ bot account: commit-bot@chromium.org
parent cedc6f1824
commit 57e81e666a
5 changed files with 55 additions and 37 deletions

View File

@ -3144,6 +3144,20 @@ typedef struct ssl_early_callback_ctx {
size_t extensions_len;
} SSL_CLIENT_HELLO;
/* ssl_select_cert_result_t enumerates the possible results from selecting a
* certificate with |select_certificate_cb|. */
enum ssl_select_cert_result_t {
/* ssl_select_cert_success indicates that the certificate selection was
* successful. */
ssl_select_cert_success = 1,
/* ssl_select_cert_retry indicates that the operation could not be
* immediately completed and must be reattempted at a later point. */
ssl_select_cert_retry = 0,
/* ssl_select_cert_error indicates that a fatal error occured and the
* handshake should be terminated. */
ssl_select_cert_error = -1,
};
/* SSL_early_callback_ctx_extension_get searches the extensions in
* |client_hello| for an extension of the given type. If not found, it returns
* zero. Otherwise it sets |out_data| to point to the extension contents (not
@ -3156,14 +3170,18 @@ OPENSSL_EXPORT int SSL_early_callback_ctx_extension_get(
/* SSL_CTX_set_select_certificate_cb sets a callback that is called before most
* ClientHello processing and before the decision whether to resume a session
* is made. The callback may inspect the ClientHello and configure the
* connection. It may then return one to continue the handshake or zero to
* pause the handshake to perform an asynchronous operation. If paused,
* |SSL_get_error| will return |SSL_ERROR_PENDING_CERTIFICATE|.
* connection. See |ssl_select_cert_result_t| for details of the return values.
*
* In the case that a retry is indicated, |SSL_get_error| will return
* |SSL_ERROR_PENDING_CERTIFICATE| and the caller should arrange for the
* high-level operation on |ssl| to be retried at a later time, which will
* result in another call to |cb|.
*
* Note: The |SSL_CLIENT_HELLO| is only valid for the duration of the callback
* and is not valid while the handshake is paused. */
OPENSSL_EXPORT void SSL_CTX_set_select_certificate_cb(
SSL_CTX *ctx, int (*cb)(const SSL_CLIENT_HELLO *));
SSL_CTX *ctx,
enum ssl_select_cert_result_t (*cb)(const SSL_CLIENT_HELLO *));
/* SSL_CTX_set_dos_protection_cb sets a callback that is called once the
* resumption decision for a ClientHello has been made. It can return one to
@ -4112,12 +4130,10 @@ struct ssl_ctx_st {
X509_VERIFY_PARAM *param;
/* select_certificate_cb is called before most ClientHello processing and
* before the decision whether to resume a session is made. It may return one
* to continue the handshake or zero to cause the handshake loop to return
* with an error and cause SSL_get_error to return
* SSL_ERROR_PENDING_CERTIFICATE. Note: when the handshake loop is resumed, it
* will not call the callback a second time. */
int (*select_certificate_cb)(const SSL_CLIENT_HELLO *);
* before the decision whether to resume a session is made. See
* |ssl_select_cert_result_t| for details of the return values. */
enum ssl_select_cert_result_t (*select_certificate_cb)(
const SSL_CLIENT_HELLO *);
/* dos_protection_cb is called once the resumption decision for a ClientHello
* has been made. It returns one to continue the handshake or zero to

View File

@ -812,11 +812,11 @@ static int ssl3_process_client_hello(SSL_HANDSHAKE *hs) {
/* Run the early callback. */
if (ssl->ctx->select_certificate_cb != NULL) {
switch (ssl->ctx->select_certificate_cb(&client_hello)) {
case 0:
case ssl_select_cert_retry:
ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING;
return -1;
case -1:
case ssl_select_cert_error:
/* Connection rejected. */
OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);

View File

@ -2397,8 +2397,9 @@ int SSL_is_server(const SSL *ssl) { return ssl->server; }
int SSL_is_dtls(const SSL *ssl) { return ssl->method->is_dtls; }
void SSL_CTX_set_select_certificate_cb(SSL_CTX *ctx,
int (*cb)(const SSL_CLIENT_HELLO *)) {
void SSL_CTX_set_select_certificate_cb(
SSL_CTX *ctx,
enum ssl_select_cert_result_t (*cb)(const SSL_CLIENT_HELLO *)) {
ctx->select_certificate_cb = cb;
}

View File

@ -2144,17 +2144,6 @@ static int SwitchSessionIDContextSNI(SSL *ssl, int *out_alert, void *arg) {
return SSL_TLSEXT_ERR_OK;
}
static int SwitchSessionIDContextEarly(const SSL_CLIENT_HELLO *client_hello) {
static const uint8_t kContext[] = {3};
if (!SSL_set_session_id_context(client_hello->ssl, kContext,
sizeof(kContext))) {
return -1;
}
return 1;
}
static bool TestSessionIDContext(bool is_dtls, const SSL_METHOD *method,
uint16_t version) {
bssl::UniquePtr<X509> cert = GetTestCertificate();
@ -2226,8 +2215,18 @@ static bool TestSessionIDContext(bool is_dtls, const SSL_METHOD *method,
// Switch the session ID context with the early callback instead.
SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), nullptr);
SSL_CTX_set_select_certificate_cb(server_ctx.get(),
SwitchSessionIDContextEarly);
SSL_CTX_set_select_certificate_cb(
server_ctx.get(),
[](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t {
static const uint8_t kContext[] = {3};
if (!SSL_set_session_id_context(client_hello->ssl, kContext,
sizeof(kContext))) {
return ssl_select_cert_error;
}
return ssl_select_cert_success;
});
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
false /* expect session not reused */)) {
@ -2614,12 +2613,13 @@ TEST(SSLTest, EarlyCallbackVersionSwitch) {
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
SSL_CTX_set_select_certificate_cb(
server_ctx.get(), [](const SSL_CLIENT_HELLO *client_hello) -> int {
server_ctx.get(),
[](const SSL_CLIENT_HELLO *client_hello) -> ssl_select_cert_result_t {
if (!SSL_set_max_proto_version(client_hello->ssl, TLS1_2_VERSION)) {
return -1;
return ssl_select_cert_error;
}
return 1;
return ssl_select_cert_success;
});
bssl::UniquePtr<SSL> client, server;

View File

@ -533,7 +533,8 @@ static bool InstallCertificate(SSL *ssl) {
return true;
}
static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
static enum ssl_select_cert_result_t SelectCertificateCallback(
const SSL_CLIENT_HELLO *client_hello) {
const TestConfig *config = GetTestConfig(client_hello->ssl);
GetTestState(client_hello->ssl)->early_callback_called = true;
@ -547,7 +548,7 @@ static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
client_hello, TLSEXT_TYPE_server_name, &extension_data,
&extension_len)) {
fprintf(stderr, "Could not find server_name extension.\n");
return -1;
return ssl_select_cert_error;
}
CBS_init(&extension, extension_data, extension_len);
@ -558,7 +559,7 @@ static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
!CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
CBS_len(&server_name_list) != 0) {
fprintf(stderr, "Could not decode server_name extension.\n");
return -1;
return ssl_select_cert_error;
}
if (!CBS_mem_equal(&host_name,
@ -569,7 +570,7 @@ static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
}
if (config->fail_early_callback) {
return -1;
return ssl_select_cert_error;
}
// Install the certificate in the early callback.
@ -578,13 +579,13 @@ static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) {
GetTestState(client_hello->ssl)->early_callback_ready;
if (config->async && !early_callback_ready) {
// Install the certificate asynchronously.
return 0;
return ssl_select_cert_retry;
}
if (!InstallCertificate(client_hello->ssl)) {
return -1;
return ssl_select_cert_error;
}
}
return 1;
return ssl_select_cert_success;
}
static bool CheckCertificateRequest(SSL *ssl) {