Convert ssl3_send_client_hello to CBB.
Start converting the ones we can right now. Some of the messier ones resize init_buf rather than assume the initial size is sufficient, so those will probably wait until init_buf is gone and the handshake's undergone some more invasive surgery. The async ones will also require some thought. But some can be incrementally converted now. BUG=468889 Change-Id: I0bc22e4dca37d9d671a488c42eba864c51933638 Reviewed-on: https://boringssl-review.googlesource.com/6190 Reviewed-by: Adam Langley <alangley@gmail.com>
This commit is contained in:
parent
978f16ea08
commit
e8d53508ca
@ -365,6 +365,55 @@ static bool TestCBBPrefixed() {
|
||||
return buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
|
||||
}
|
||||
|
||||
static bool TestCBBDiscardChild() {
|
||||
ScopedCBB cbb;
|
||||
CBB contents, inner_contents, inner_inner_contents;
|
||||
|
||||
if (!CBB_init(cbb.get(), 0) ||
|
||||
!CBB_add_u8(cbb.get(), 0xaa)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Discarding |cbb|'s children preserves the byte written.
|
||||
CBB_discard_child(cbb.get());
|
||||
|
||||
if (!CBB_add_u8_length_prefixed(cbb.get(), &contents) ||
|
||||
!CBB_add_u8_length_prefixed(cbb.get(), &contents) ||
|
||||
!CBB_add_u8(&contents, 0xbb) ||
|
||||
!CBB_add_u16_length_prefixed(cbb.get(), &contents) ||
|
||||
!CBB_add_u16(&contents, 0xcccc) ||
|
||||
!CBB_add_u24_length_prefixed(cbb.get(), &contents) ||
|
||||
!CBB_add_u24(&contents, 0xdddddd) ||
|
||||
!CBB_add_u8_length_prefixed(cbb.get(), &contents) ||
|
||||
!CBB_add_u8(&contents, 0xff) ||
|
||||
!CBB_add_u8_length_prefixed(&contents, &inner_contents) ||
|
||||
!CBB_add_u8(&inner_contents, 0x42) ||
|
||||
!CBB_add_u16_length_prefixed(&inner_contents, &inner_inner_contents) ||
|
||||
!CBB_add_u8(&inner_inner_contents, 0x99)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Discard everything from |inner_contents| down.
|
||||
CBB_discard_child(&contents);
|
||||
|
||||
uint8_t *buf;
|
||||
size_t buf_len;
|
||||
if (!CBB_finish(cbb.get(), &buf, &buf_len)) {
|
||||
return false;
|
||||
}
|
||||
ScopedOpenSSLBytes scoper(buf);
|
||||
|
||||
static const uint8_t kExpected[] = {
|
||||
0xaa,
|
||||
0,
|
||||
1, 0xbb,
|
||||
0, 2, 0xcc, 0xcc,
|
||||
0, 0, 3, 0xdd, 0xdd, 0xdd,
|
||||
1, 0xff,
|
||||
};
|
||||
return buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
|
||||
}
|
||||
|
||||
static bool TestCBBMisuse() {
|
||||
CBB cbb, child, contents;
|
||||
uint8_t *buf;
|
||||
@ -670,6 +719,7 @@ int main(void) {
|
||||
!TestCBBFinishChild() ||
|
||||
!TestCBBMisuse() ||
|
||||
!TestCBBPrefixed() ||
|
||||
!TestCBBDiscardChild() ||
|
||||
!TestCBBASN1() ||
|
||||
!TestBerConvert() ||
|
||||
!TestASN1Uint64() ||
|
||||
|
@ -360,6 +360,20 @@ int CBB_add_u24(CBB *cbb, uint32_t value) {
|
||||
return cbb_buffer_add_u(cbb->base, value, 3);
|
||||
}
|
||||
|
||||
void CBB_discard_child(CBB *cbb) {
|
||||
if (cbb->child == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
cbb->base->len = cbb->offset;
|
||||
|
||||
cbb->child->base = NULL;
|
||||
cbb->child = NULL;
|
||||
cbb->pending_len_len = 0;
|
||||
cbb->pending_is_asn1 = 0;
|
||||
cbb->offset = 0;
|
||||
}
|
||||
|
||||
int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) {
|
||||
CBB child;
|
||||
size_t i;
|
||||
|
@ -117,6 +117,7 @@ using ScopedX509_SIG = ScopedOpenSSLType<X509_SIG, X509_SIG_free>;
|
||||
|
||||
using ScopedX509Stack = ScopedOpenSSLStack<STACK_OF(X509), X509, X509_free>;
|
||||
|
||||
using ScopedCBB = ScopedOpenSSLContext<CBB, void, CBB_zero, CBB_cleanup>;
|
||||
using ScopedEVP_AEAD_CTX = ScopedOpenSSLContext<EVP_AEAD_CTX, void,
|
||||
EVP_AEAD_CTX_zero,
|
||||
EVP_AEAD_CTX_cleanup>;
|
||||
|
@ -344,6 +344,10 @@ OPENSSL_EXPORT int CBB_add_u16(CBB *cbb, uint16_t value);
|
||||
* returns one on success and zero otherwise. */
|
||||
OPENSSL_EXPORT int CBB_add_u24(CBB *cbb, uint32_t value);
|
||||
|
||||
/* CBB_discard_child discards the current unflushed child of |cbb|. Neither the
|
||||
* child's contents nor the length prefix will be included in the output. */
|
||||
OPENSSL_EXPORT void CBB_discard_child(CBB *cbb);
|
||||
|
||||
/* CBB_add_asn1_uint64 writes an ASN.1 INTEGER into |cbb| using |CBB_add_asn1|
|
||||
* and writes |value| in its contents. It returns one on success and zero on
|
||||
* error. */
|
||||
|
@ -976,7 +976,6 @@ enum ssl_session_result_t ssl_get_prev_session(
|
||||
const struct ssl_early_callback_ctx *ctx);
|
||||
|
||||
STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs);
|
||||
int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p);
|
||||
struct ssl_cipher_preference_list_st *ssl_cipher_preference_list_dup(
|
||||
struct ssl_cipher_preference_list_st *cipher_list);
|
||||
void ssl_cipher_preference_list_free(
|
||||
@ -1104,7 +1103,7 @@ unsigned int dtls1_min_mtu(void);
|
||||
void dtls1_hm_fragment_free(hm_fragment *frag);
|
||||
|
||||
/* some client-only functions */
|
||||
int ssl3_send_client_hello(SSL *s);
|
||||
int ssl3_send_client_hello(SSL *ssl);
|
||||
int ssl3_get_server_hello(SSL *s);
|
||||
int ssl3_get_certificate_request(SSL *s);
|
||||
int ssl3_get_new_session_ticket(SSL *s);
|
||||
@ -1208,8 +1207,13 @@ int tls1_check_ec_tmp_key(SSL *s);
|
||||
|
||||
int tls1_shared_list(SSL *s, const uint8_t *l1, size_t l1len, const uint8_t *l2,
|
||||
size_t l2len, int nmatch);
|
||||
uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *const buf,
|
||||
uint8_t *const limit, size_t header_len);
|
||||
|
||||
/* ssl_add_clienthello_tlsext writes ClientHello extensions to |out|. It
|
||||
* returns one on success and zero on failure. The |header_len| argument is the
|
||||
* length of the ClientHello written so far and is used to compute the padding
|
||||
* length. (It does not include the record header.) */
|
||||
int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len);
|
||||
|
||||
uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf,
|
||||
uint8_t *const limit);
|
||||
int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs);
|
||||
|
257
ssl/s3_clnt.c
257
ssl/s3_clnt.c
@ -589,140 +589,139 @@ end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ssl3_send_client_hello(SSL *s) {
|
||||
uint8_t *buf, *p, *d;
|
||||
int i;
|
||||
unsigned long l;
|
||||
static int ssl3_write_client_cipher_list(SSL *ssl, CBB *out) {
|
||||
/* Prepare disabled cipher masks. */
|
||||
ssl_set_client_disabled(ssl);
|
||||
|
||||
buf = (uint8_t *)s->init_buf->data;
|
||||
if (s->state == SSL3_ST_CW_CLNT_HELLO_A) {
|
||||
if (!s->s3->have_version) {
|
||||
uint16_t max_version = ssl3_get_max_client_version(s);
|
||||
/* Disabling all versions is silly: return an error. */
|
||||
if (max_version == 0) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION);
|
||||
goto err;
|
||||
}
|
||||
s->version = max_version;
|
||||
s->client_version = max_version;
|
||||
}
|
||||
|
||||
/* If the configured session was created at a version higher than our
|
||||
* maximum version, drop it. */
|
||||
if (s->session &&
|
||||
(s->session->session_id_length == 0 || s->session->not_resumable ||
|
||||
(!SSL_IS_DTLS(s) && s->session->ssl_version > s->version) ||
|
||||
(SSL_IS_DTLS(s) && s->session->ssl_version < s->version))) {
|
||||
SSL_set_session(s, NULL);
|
||||
}
|
||||
|
||||
/* else use the pre-loaded session */
|
||||
p = s->s3->client_random;
|
||||
|
||||
/* If resending the ClientHello in DTLS after a HelloVerifyRequest, don't
|
||||
* renegerate the client_random. The random must be reused. */
|
||||
if ((!SSL_IS_DTLS(s) || !s->d1->send_cookie) &&
|
||||
!ssl_fill_hello_random(p, sizeof(s->s3->client_random),
|
||||
0 /* client */)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Do the message type and length last. Note: the final argument to
|
||||
* ssl_add_clienthello_tlsext below depends on the size of this prefix. */
|
||||
d = p = ssl_handshake_start(s);
|
||||
|
||||
/* version indicates the negotiated version: for example from an SSLv2/v3
|
||||
* compatible client hello). The client_version field is the maximum
|
||||
* version we permit and it is also used in RSA encrypted premaster
|
||||
* secrets. Some servers can choke if we initially report a higher version
|
||||
* then renegotiate to a lower one in the premaster secret. This didn't
|
||||
* happen with TLS 1.0 as most servers supported it but it can with TLS 1.1
|
||||
* or later if the server only supports 1.0.
|
||||
*
|
||||
* Possible scenario with previous logic:
|
||||
* 1. Client hello indicates TLS 1.2
|
||||
* 2. Server hello says TLS 1.0
|
||||
* 3. RSA encrypted premaster secret uses 1.2.
|
||||
* 4. Handhaked proceeds using TLS 1.0.
|
||||
* 5. Server sends hello request to renegotiate.
|
||||
* 6. Client hello indicates TLS v1.0 as we now
|
||||
* know that is maximum server supports.
|
||||
* 7. Server chokes on RSA encrypted premaster secret
|
||||
* containing version 1.0.
|
||||
*
|
||||
* For interoperability it should be OK to always use the maximum version
|
||||
* we support in client hello and then rely on the checking of version to
|
||||
* ensure the servers isn't being inconsistent: for example initially
|
||||
* negotiating with TLS 1.0 and renegotiating with TLS 1.2. We do this by
|
||||
* using client_version in client hello and not resetting it to the
|
||||
* negotiated version. */
|
||||
*(p++) = s->client_version >> 8;
|
||||
*(p++) = s->client_version & 0xff;
|
||||
|
||||
/* Random stuff */
|
||||
memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
|
||||
p += SSL3_RANDOM_SIZE;
|
||||
|
||||
/* Session ID */
|
||||
if (s->s3->initial_handshake_complete || s->session == NULL) {
|
||||
/* Renegotiations do not participate in session resumption. */
|
||||
i = 0;
|
||||
} else {
|
||||
i = s->session->session_id_length;
|
||||
}
|
||||
*(p++) = i;
|
||||
if (i != 0) {
|
||||
if (i > (int)sizeof(s->session->session_id)) {
|
||||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
memcpy(p, s->session->session_id, i);
|
||||
p += i;
|
||||
}
|
||||
|
||||
/* cookie stuff for DTLS */
|
||||
if (SSL_IS_DTLS(s)) {
|
||||
if (s->d1->cookie_len > sizeof(s->d1->cookie)) {
|
||||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
*(p++) = s->d1->cookie_len;
|
||||
memcpy(p, s->d1->cookie, s->d1->cookie_len);
|
||||
p += s->d1->cookie_len;
|
||||
}
|
||||
|
||||
/* Ciphers supported */
|
||||
i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &p[2]);
|
||||
if (i == 0) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE);
|
||||
goto err;
|
||||
}
|
||||
s2n(i, p);
|
||||
p += i;
|
||||
|
||||
/* COMPRESSION */
|
||||
*(p++) = 1;
|
||||
*(p++) = 0; /* Add the NULL method */
|
||||
|
||||
/* TLS extensions*/
|
||||
p = ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
|
||||
p - buf);
|
||||
if (p == NULL) {
|
||||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
l = p - d;
|
||||
if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) {
|
||||
goto err;
|
||||
}
|
||||
s->state = SSL3_ST_CW_CLNT_HELLO_B;
|
||||
CBB child;
|
||||
if (!CBB_add_u16_length_prefixed(out, &child)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SSL3_ST_CW_CLNT_HELLO_B */
|
||||
return ssl_do_write(s);
|
||||
STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
|
||||
|
||||
int any_enabled = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
|
||||
const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i);
|
||||
/* Skip disabled ciphers */
|
||||
if (cipher->algorithm_ssl & ssl->cert->mask_ssl ||
|
||||
cipher->algorithm_mkey & ssl->cert->mask_k ||
|
||||
cipher->algorithm_auth & ssl->cert->mask_a) {
|
||||
continue;
|
||||
}
|
||||
any_enabled = 1;
|
||||
if (!CBB_add_u16(&child, ssl_cipher_get_value(cipher))) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If all ciphers were disabled, return the error to the caller. */
|
||||
if (!any_enabled) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For SSLv3, the SCSV is added. Otherwise the renegotiation extension is
|
||||
* added. */
|
||||
if (ssl->client_version == SSL3_VERSION &&
|
||||
!ssl->s3->initial_handshake_complete) {
|
||||
if (!CBB_add_u16(&child, SSL3_CK_SCSV & 0xffff)) {
|
||||
return 0;
|
||||
}
|
||||
/* The renegotiation extension is required to be at index zero. */
|
||||
ssl->s3->tmp.extensions.sent |= (1u << 0);
|
||||
}
|
||||
|
||||
if ((ssl->mode & SSL_MODE_SEND_FALLBACK_SCSV) &&
|
||||
!CBB_add_u16(&child, SSL3_CK_FALLBACK_SCSV & 0xffff)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CBB_flush(out);
|
||||
}
|
||||
|
||||
int ssl3_send_client_hello(SSL *ssl) {
|
||||
if (ssl->state == SSL3_ST_CW_CLNT_HELLO_B) {
|
||||
return ssl_do_write(ssl);
|
||||
}
|
||||
|
||||
CBB cbb;
|
||||
CBB_zero(&cbb);
|
||||
|
||||
assert(ssl->state == SSL3_ST_CW_CLNT_HELLO_A);
|
||||
if (!ssl->s3->have_version) {
|
||||
uint16_t max_version = ssl3_get_max_client_version(ssl);
|
||||
/* Disabling all versions is silly: return an error. */
|
||||
if (max_version == 0) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ssl->version = max_version;
|
||||
/* Only set |ssl->client_version| on the initial handshake. Renegotiations,
|
||||
* although locked to a version, reuse the value. When using the plain RSA
|
||||
* key exchange, the ClientHello version is checked in the premaster secret.
|
||||
* Some servers fail when this value changes. */
|
||||
ssl->client_version = max_version;
|
||||
}
|
||||
|
||||
/* If the configured session was created at a version higher than our
|
||||
* maximum version, drop it. */
|
||||
if (ssl->session != NULL &&
|
||||
(ssl->session->session_id_length == 0 || ssl->session->not_resumable ||
|
||||
(!SSL_IS_DTLS(ssl) && ssl->session->ssl_version > ssl->version) ||
|
||||
(SSL_IS_DTLS(ssl) && ssl->session->ssl_version < ssl->version))) {
|
||||
SSL_set_session(ssl, NULL);
|
||||
}
|
||||
|
||||
/* If resending the ClientHello in DTLS after a HelloVerifyRequest, don't
|
||||
* renegerate the client_random. The random must be reused. */
|
||||
if ((!SSL_IS_DTLS(ssl) || !ssl->d1->send_cookie) &&
|
||||
!ssl_fill_hello_random(ssl->s3->client_random,
|
||||
sizeof(ssl->s3->client_random), 0 /* client */)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Renegotiations do not participate in session resumption. */
|
||||
int has_session = ssl->session != NULL &&
|
||||
!ssl->s3->initial_handshake_complete;
|
||||
|
||||
CBB child;
|
||||
if (!CBB_init_fixed(&cbb, ssl_handshake_start(ssl),
|
||||
ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl)) ||
|
||||
!CBB_add_u16(&cbb, ssl->client_version) ||
|
||||
!CBB_add_bytes(&cbb, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
|
||||
!CBB_add_u8_length_prefixed(&cbb, &child) ||
|
||||
(has_session &&
|
||||
!CBB_add_bytes(&child, ssl->session->session_id,
|
||||
ssl->session->session_id_length))) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (SSL_IS_DTLS(ssl)) {
|
||||
if (!CBB_add_u8_length_prefixed(&cbb, &child) ||
|
||||
!CBB_add_bytes(&child, ssl->d1->cookie, ssl->d1->cookie_len)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
size_t length;
|
||||
if (!ssl3_write_client_cipher_list(ssl, &cbb) ||
|
||||
!CBB_add_u8(&cbb, 1 /* one compression method */) ||
|
||||
!CBB_add_u8(&cbb, 0 /* null compression */) ||
|
||||
!ssl_add_clienthello_tlsext(ssl, &cbb,
|
||||
CBB_len(&cbb) + SSL_HM_HEADER_LENGTH(ssl)) ||
|
||||
!CBB_finish(&cbb, NULL, &length) ||
|
||||
!ssl_set_handshake_header(ssl, SSL3_MT_CLIENT_HELLO, length)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ssl->state = SSL3_ST_CW_CLNT_HELLO_B;
|
||||
return ssl_do_write(ssl);
|
||||
|
||||
err:
|
||||
CBB_cleanup(&cbb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1498,51 +1498,6 @@ int SSL_set_cipher_list(SSL *ssl, const char *str) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p) {
|
||||
size_t i;
|
||||
const SSL_CIPHER *c;
|
||||
CERT *ct = s->cert;
|
||||
uint8_t *q;
|
||||
/* Set disabled masks for this session */
|
||||
ssl_set_client_disabled(s);
|
||||
|
||||
if (sk == NULL) {
|
||||
return 0;
|
||||
}
|
||||
q = p;
|
||||
|
||||
for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
|
||||
c = sk_SSL_CIPHER_value(sk, i);
|
||||
/* Skip disabled ciphers */
|
||||
if (c->algorithm_ssl & ct->mask_ssl ||
|
||||
c->algorithm_mkey & ct->mask_k ||
|
||||
c->algorithm_auth & ct->mask_a) {
|
||||
continue;
|
||||
}
|
||||
s2n(ssl_cipher_get_value(c), p);
|
||||
}
|
||||
|
||||
/* If all ciphers were disabled, return the error to the caller. */
|
||||
if (p == q) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For SSLv3, the SCSV is added. Otherwise the renegotiation extension is
|
||||
* added. */
|
||||
if (s->client_version == SSL3_VERSION &&
|
||||
!s->s3->initial_handshake_complete) {
|
||||
s2n(SSL3_CK_SCSV & 0xffff, p);
|
||||
/* The renegotiation extension is required to be at index zero. */
|
||||
s->s3->tmp.extensions.sent |= (1u << 0);
|
||||
}
|
||||
|
||||
if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) {
|
||||
s2n(SSL3_CK_FALLBACK_SCSV & 0xffff, p);
|
||||
}
|
||||
|
||||
return p - q;
|
||||
}
|
||||
|
||||
STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) {
|
||||
CBS cipher_suites = *cbs;
|
||||
const SSL_CIPHER *c;
|
||||
|
50
ssl/t1_lib.c
50
ssl/t1_lib.c
@ -2228,52 +2228,48 @@ int SSL_extension_supported(unsigned extension_value) {
|
||||
tls_extension_find(&index, extension_value) != NULL;
|
||||
}
|
||||
|
||||
/* header_len is the length of the ClientHello header written so far, used to
|
||||
* compute padding. It does not include the record header. Pass 0 if no padding
|
||||
* is to be done. */
|
||||
uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *const buf,
|
||||
uint8_t *const limit, size_t header_len) {
|
||||
int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) {
|
||||
/* don't add extensions for SSLv3 unless doing secure renegotiation */
|
||||
if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) {
|
||||
return buf;
|
||||
if (ssl->client_version == SSL3_VERSION &&
|
||||
!ssl->s3->send_connection_binding) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CBB cbb, extensions;
|
||||
CBB_zero(&cbb);
|
||||
if (!CBB_init_fixed(&cbb, buf, limit - buf) ||
|
||||
!CBB_add_u16_length_prefixed(&cbb, &extensions)) {
|
||||
size_t orig_len = CBB_len(out);
|
||||
CBB extensions;
|
||||
if (!CBB_add_u16_length_prefixed(out, &extensions)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
s->s3->tmp.extensions.sent = 0;
|
||||
s->s3->tmp.custom_extensions.sent = 0;
|
||||
ssl->s3->tmp.extensions.sent = 0;
|
||||
ssl->s3->tmp.custom_extensions.sent = 0;
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < kNumExtensions; i++) {
|
||||
if (kExtensions[i].init != NULL) {
|
||||
kExtensions[i].init(s);
|
||||
kExtensions[i].init(ssl);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < kNumExtensions; i++) {
|
||||
const size_t len_before = CBB_len(&extensions);
|
||||
if (!kExtensions[i].add_clienthello(s, &extensions)) {
|
||||
if (!kExtensions[i].add_clienthello(ssl, &extensions)) {
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
|
||||
ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (CBB_len(&extensions) != len_before) {
|
||||
s->s3->tmp.extensions.sent |= (1u << i);
|
||||
ssl->s3->tmp.extensions.sent |= (1u << i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!custom_ext_add_clienthello(s, &extensions)) {
|
||||
if (!custom_ext_add_clienthello(ssl, &extensions)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (header_len > 0) {
|
||||
header_len += CBB_len(&extensions);
|
||||
if (!SSL_IS_DTLS(ssl)) {
|
||||
header_len += CBB_len(&extensions) - orig_len;
|
||||
if (header_len > 0xff && header_len < 0x200) {
|
||||
/* Add padding to workaround bugs in F5 terminators. See
|
||||
* https://tools.ietf.org/html/draft-agl-tls-padding-03
|
||||
@ -2301,26 +2297,18 @@ uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *const buf,
|
||||
}
|
||||
}
|
||||
|
||||
if (!CBB_flush(&cbb)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
uint8_t *ret = buf;
|
||||
const size_t cbb_len = CBB_len(&cbb);
|
||||
/* If only two bytes have been written then the extensions are actually empty
|
||||
* and those two bytes are the zero length. In that case, we don't bother
|
||||
* sending the extensions length. */
|
||||
if (cbb_len > 2) {
|
||||
ret += cbb_len;
|
||||
if (CBB_len(&extensions) - orig_len == 2) {
|
||||
CBB_discard_child(out);
|
||||
}
|
||||
|
||||
CBB_cleanup(&cbb);
|
||||
return ret;
|
||||
return CBB_flush(out);
|
||||
|
||||
err:
|
||||
CBB_cleanup(&cbb);
|
||||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf,
|
||||
|
Loading…
Reference in New Issue
Block a user