Add SNI support to redbean and improve SSL perf

This change makes SSL virtual hosting possible. You can now load
multiple certificates for multiple domains and redbean will just
figure out which one to use, even if you only have 1 ip address.
You can also use a jumbo certificate that lists all your domains
in the the subject alternative names.

This change also makes performance improvements to MbedTLS. Here
are some benchmarks vs. cc1920749e

                                   BEFORE    AFTER   (microsecs)
suite_ssl.com                     2512881   191738 13.11x faster
suite_pkparse.com                   36291     3295 11.01x faster
suite_x509parse.com                854669   120293  7.10x faster
suite_pkwrite.com                    6549     1265  5.18x faster
suite_ecdsa.com                     53347    18778  2.84x faster
suite_pk.com                        49051    18717  2.62x faster
suite_ecdh.com                      19535     9502  2.06x faster
suite_shax.com                      15848     7965  1.99x faster
suite_rsa.com                      353257   184828  1.91x faster
suite_x509write.com                162646    85733  1.90x faster
suite_ecp.com                       20503    11050  1.86x faster
suite_hmac_drbg.no_reseed.com       19528    11417  1.71x faster
suite_hmac_drbg.nopr.com            12460     8010  1.56x faster
suite_mpi.com                      687124   442661  1.55x faster
suite_hmac_drbg.pr.com              11890     7752  1.53x faster

There aren't any special tricks to the performance imporvements.
It's mostly due to code cleanup, assembly and intel instructions
like mulx, adox, and adcx.
This commit is contained in:
Justine Tunney 2021-07-19 14:55:20 -07:00
parent f3e28aa192
commit 398f0c16fb
190 changed files with 14367 additions and 8928 deletions

View file

@ -1,4 +1,23 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:4;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright The Mbed TLS Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 │
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "third_party/mbedtls/common.h"
#include "third_party/mbedtls/debug.h"
#include "third_party/mbedtls/error.h"
@ -235,7 +254,7 @@ static int ssl_get_remaining_space_in_datagram( mbedtls_ssl_context const *ssl )
static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
size_t remaining, expansion;
size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
@ -400,7 +419,7 @@ static int ssl_build_inner_plaintext( unsigned char *content,
if( remaining < pad )
return( -1 );
memset( content + len, 0, pad );
mbedtls_platform_zeroize( content + len, pad );
len += pad;
remaining -= pad;
@ -588,7 +607,7 @@ static void ssl_build_record_nonce( unsigned char *dst_iv,
size_t i;
/* Start with Fixed IV || 0 */
memset( dst_iv, 0, dst_iv_len );
mbedtls_platform_zeroize( dst_iv, dst_iv_len );
memcpy( dst_iv, fixed_iv, fixed_iv_len );
dst_iv += dst_iv_len - dynamic_iv_len;
@ -793,7 +812,7 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl,
#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER)
if( mode == MBEDTLS_MODE_STREAM )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
size_t olen;
MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %" MBEDTLS_PRINTF_SIZET ", "
"including %d bytes of padding",
@ -824,7 +843,7 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl,
mode == MBEDTLS_MODE_CCM ||
mode == MBEDTLS_MODE_CHACHAPOLY )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
unsigned char iv[12];
unsigned char *dynamic_iv;
size_t dynamic_iv_len;
@ -921,7 +940,7 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl,
#if defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC)
if( mode == MBEDTLS_MODE_CBC )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
size_t padlen, i;
size_t olen;
@ -1088,7 +1107,7 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl,
* This function is implemented without using comparison operators, as those
* might be translated to branches by some compilers on some platforms.
*/
static size_t mbedtls_ssl_cf_mask_from_bit( size_t bit )
static inline size_t mbedtls_ssl_cf_mask_from_bit( size_t bit )
{
/* MSVC has a warning about unary minus on unsigned integer types,
* but this is well-defined and precisely what we want to do here. */
@ -1113,17 +1132,14 @@ static size_t mbedtls_ssl_cf_mask_from_bit( size_t bit )
* This function is implemented without using comparison operators, as those
* might be translated to branches by some compilers on some platforms.
*/
static size_t mbedtls_ssl_cf_mask_lt( size_t x, size_t y )
static inline size_t mbedtls_ssl_cf_mask_lt( size_t x, size_t y )
{
/* This has the most significant bit set if and only if x < y */
const size_t sub = x - y;
/* sub1 = (x < y) ? 1 : 0 */
const size_t sub1 = sub >> ( sizeof( sub ) * 8 - 1 );
/* mask = (x < y) ? 0xff... : 0x00... */
const size_t mask = mbedtls_ssl_cf_mask_from_bit( sub1 );
return( mask );
}
@ -1138,7 +1154,7 @@ static size_t mbedtls_ssl_cf_mask_lt( size_t x, size_t y )
* This function is implemented without using comparison operators, as those
* might be translated to branches by some compilers on some platforms.
*/
static size_t mbedtls_ssl_cf_mask_ge( size_t x, size_t y )
static inline size_t mbedtls_ssl_cf_mask_ge( size_t x, size_t y )
{
return( ~mbedtls_ssl_cf_mask_lt( x, y ) );
}
@ -1154,28 +1170,23 @@ static size_t mbedtls_ssl_cf_mask_ge( size_t x, size_t y )
* This function is implemented without using comparison operators, as those
* might be translated to branches by some compilers on some platforms.
*/
static size_t mbedtls_ssl_cf_bool_eq( size_t x, size_t y )
static inline size_t mbedtls_ssl_cf_bool_eq( size_t x, size_t y )
{
/* diff = 0 if x == y, non-zero otherwise */
const size_t diff = x ^ y;
/* MSVC has a warning about unary minus on unsigned integer types,
* but this is well-defined and precisely what we want to do here. */
#if defined(_MSC_VER)
#pragma warning( push )
#pragma warning( disable : 4146 )
#endif
/* diff_msb's most significant bit is equal to x != y */
const size_t diff_msb = ( diff | -diff );
#if defined(_MSC_VER)
#pragma warning( pop )
#endif
/* diff1 = (x != y) ? 1 : 0 */
const size_t diff1 = diff_msb >> ( sizeof( diff_msb ) * 8 - 1 );
return( 1 ^ diff1 );
}
@ -1193,12 +1204,17 @@ static void mbedtls_ssl_cf_memcpy_if_eq( unsigned char *dst,
size_t len,
size_t c1, size_t c2 )
{
/* mask = c1 == c2 ? 0xff : 0x00 */
size_t i;
uint64_t x, y;
const size_t equal = mbedtls_ssl_cf_bool_eq( c1, c2 );
const unsigned char mask = (unsigned char) mbedtls_ssl_cf_mask_from_bit( equal );
/* dst[i] = c1 == c2 ? src[i] : dst[i] */
for( size_t i = 0; i < len; i++ )
for (i = 0; i + 8 <= len; i += 8) {
__builtin_memcpy( &x, dst + i, 8 );
__builtin_memcpy( &y, src + i, 8 );
x = ( x & ~-equal ) | ( y & -equal );
__builtin_memcpy( dst + i, &x, 8 );
}
for( ; i < len; i++ )
dst[i] = ( src[i] & mask ) | ( dst[i] & ~mask );
}
@ -1238,11 +1254,8 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_ssl_cf_hmac(
const size_t hash_size = mbedtls_md_get_size( ctx->md_info );
unsigned char aux_out[MBEDTLS_MD_MAX_SIZE];
mbedtls_md_context_t aux;
size_t offset;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_md_init( &aux );
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
#define MD_CHK( func_call ) \
do { \
@ -1251,13 +1264,18 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_ssl_cf_hmac(
goto cleanup; \
} while( 0 )
MD_CHK( mbedtls_md_setup( &aux, ctx->md_info, 0 ) );
/* After hmac_start() of hmac_reset(), ikey has already been hashed,
* so we can start directly with the message */
MD_CHK( mbedtls_md_update( ctx, add_data, add_data_len ) );
MD_CHK( mbedtls_md_update( ctx, data, min_data_len ) );
#if 1
MD_CHK( mbedtls_md_update( ctx, data + min_data_len, data_len_secret - min_data_len ) );
MD_CHK( mbedtls_md_finish( ctx, output ) );
#else /* come on! */
mbedtls_md_context_t aux;
mbedtls_md_init( &aux );
MD_CHK( mbedtls_md_setup( &aux, ctx->md_info, 0 ) );
/* For each possible length, compute the hash up to that point */
for( offset = min_data_len; offset <= max_data_len; offset++ )
{
@ -1266,10 +1284,11 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_ssl_cf_hmac(
/* Keep only the correct inner_hash in the output buffer */
mbedtls_ssl_cf_memcpy_if_eq( output, aux_out, hash_size,
offset, data_len_secret );
if( offset < max_data_len )
MD_CHK( mbedtls_md_update( ctx, data + offset, 1 ) );
}
mbedtls_md_free( &aux );
#endif
/* Now compute HASH(okey + inner_hash) */
MD_CHK( mbedtls_md_starts( ctx ) );
@ -1283,7 +1302,6 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_ssl_cf_hmac(
#undef MD_CHK
cleanup:
mbedtls_md_free( &aux );
return( ret );
}
@ -1300,7 +1318,6 @@ MBEDTLS_STATIC_TESTABLE void mbedtls_ssl_cf_memcpy_offset(
size_t len )
{
size_t offset;
for( offset = offset_min; offset <= offset_max; offset++ )
{
mbedtls_ssl_cf_memcpy_if_eq( dst, src_base + offset, len,
@ -1911,7 +1928,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl,
*/
static int ssl_compress_buf( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
unsigned char *msg_post = ssl->out_msg;
ptrdiff_t bytes_written = ssl->out_msg - ssl->out_buf;
size_t len_pre = ssl->out_msglen;
@ -1963,7 +1980,7 @@ static int ssl_compress_buf( mbedtls_ssl_context *ssl )
static int ssl_decompress_buf( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
unsigned char *msg_post = ssl->in_msg;
ptrdiff_t header_bytes = ssl->in_msg - ssl->in_buf;
size_t len_pre = ssl->in_msglen;
@ -2031,7 +2048,7 @@ static int ssl_decompress_buf( mbedtls_ssl_context *ssl )
*/
int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
size_t len;
#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
size_t in_buf_len = ssl->in_buf_len;
@ -2252,7 +2269,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want )
*/
int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
unsigned char *buf;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> flush output" ) );
@ -2452,7 +2469,7 @@ int mbedtls_ssl_resend( mbedtls_ssl_context *ssl )
*/
int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_flight_transmit" ) );
if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING )
@ -2689,7 +2706,7 @@ void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl )
*/
int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
const size_t hs_len = ssl->out_msglen - 4;
const unsigned char hs_type = ssl->out_msg[0];
@ -2798,7 +2815,7 @@ int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl )
/* Handshake hashes are computed without fragmentation,
* so set frag_offset = 0 and frag_len = hs_len for now */
memset( ssl->out_msg + 6, 0x00, 3 );
mbedtls_platform_zeroize( ssl->out_msg + 6, 3 );
memcpy( ssl->out_msg + 9, ssl->out_msg + 1, 3 );
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
@ -3179,7 +3196,7 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl )
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
unsigned int recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5];
if( ssl_check_hs_header( ssl ) != 0 )
@ -3289,7 +3306,7 @@ void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl )
}
/* Create a fresh last entry */
memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) );
mbedtls_platform_zeroize( hs_buf, sizeof( mbedtls_ssl_hs_buffer ) );
}
#endif
}
@ -3323,7 +3340,7 @@ static inline uint64_t ssl_load_six_bytes( unsigned char *buf )
static int mbedtls_ssl_dtls_record_replay_check( mbedtls_ssl_context *ssl, uint8_t *record_in_ctr )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
unsigned char *original_in_ctr;
// save original in_ctr
@ -3547,7 +3564,7 @@ static int ssl_check_dtls_clihlo_cookie(
*/
static int ssl_handle_possible_reconnect( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
size_t len;
if( ssl->conf->f_cookie_write == NULL ||
@ -4054,7 +4071,7 @@ static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl );
int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl,
unsigned update_hs_digest )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read record" ) );
@ -4419,7 +4436,7 @@ static int ssl_buffer_message( mbedtls_ssl_context *ssl )
/* Prepare final header: copy msg_type, length and message_seq,
* then add standardised fragment_offset and fragment_length */
memcpy( hs_buf->data, ssl->in_msg, 6 );
memset( hs_buf->data + 6, 0, 3 );
mbedtls_platform_zeroize( hs_buf->data + 6, 3 );
memcpy( hs_buf->data + 9, hs_buf->data + 1, 3 );
hs_buf->is_valid = 1;
@ -4717,7 +4734,7 @@ static int ssl_buffer_future_record( mbedtls_ssl_context *ssl,
static int ssl_get_next_record( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
mbedtls_record rec;
#if defined(MBEDTLS_SSL_PROTO_DTLS)
@ -4946,7 +4963,7 @@ static int ssl_get_next_record( mbedtls_ssl_context *ssl )
int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
/*
* Handle particular types of records
@ -5106,7 +5123,7 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl,
unsigned char level,
unsigned char message )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
if( ssl == NULL || ssl->conf == NULL )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
@ -5131,7 +5148,7 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl,
int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write change cipher spec" ) );
@ -5154,7 +5171,7 @@ int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl )
int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse change cipher spec" ) );
@ -5201,7 +5218,7 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl )
}
else
#endif /* MBEDTLS_SSL_PROTO_DTLS */
memset( ssl->in_ctr, 0, 8 );
mbedtls_platform_zeroize( ssl->in_ctr, 8 );
mbedtls_ssl_update_in_pointers( ssl );
@ -5616,7 +5633,7 @@ static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl )
*/
int mbedtls_ssl_read( mbedtls_ssl_context *ssl, void *buf, size_t len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
size_t n;
if( ssl == NULL || ssl->conf == NULL )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
@ -5968,7 +5985,7 @@ static int ssl_write_real( mbedtls_ssl_context *ssl,
static int ssl_write_split( mbedtls_ssl_context *ssl,
const unsigned char *buf, size_t len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
if( ssl->conf->cbc_record_splitting ==
MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED ||
len <= 1 ||
@ -6053,7 +6070,7 @@ static int ssl_write_split( mbedtls_ssl_context *ssl,
*/
int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const void *buf, size_t len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write" ) );
if( ssl == NULL || ssl->conf == NULL )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
@ -6096,7 +6113,7 @@ int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const void *buf, size_t len )
*/
int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
int ret = MBEDTLS_ERR_THIS_CORRUPTION;
if( ssl == NULL || ssl->conf == NULL )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write close notify" ) );
@ -6163,7 +6180,7 @@ static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl,
hs->buffering.total_bytes_buffered -= hs_buf->data_len;
mbedtls_platform_zeroize( hs_buf->data, hs_buf->data_len );
mbedtls_free( hs_buf->data );
memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) );
mbedtls_platform_zeroize( hs_buf, sizeof( mbedtls_ssl_hs_buffer ) );
}
}