From 7023d6aeb38285ac23cddb46f475b5ab4dc67372 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 26 Jul 2021 20:20:54 +0200 Subject: [PATCH 01/15] New sample program to benchmark certificate loading Signed-off-by: Gilles Peskine --- programs/.gitignore | 1 + programs/Makefile | 6 +- programs/x509/CMakeLists.txt | 5 +- programs/x509/load_roots.c | 207 ++++++++++++++++++++++++++++++ visualc/VS2010/load_roots.vcxproj | 173 +++++++++++++++++++++++++ visualc/VS2010/mbedTLS.sln | 13 ++ 6 files changed, 403 insertions(+), 2 deletions(-) create mode 100644 programs/x509/load_roots.c create mode 100644 visualc/VS2010/load_roots.vcxproj diff --git a/programs/.gitignore b/programs/.gitignore index d9ca31c6299b..f0d72d74767e 100644 --- a/programs/.gitignore +++ b/programs/.gitignore @@ -55,6 +55,7 @@ x509/cert_app x509/cert_req x509/crl_app x509/cert_write +x509/load_roots x509/req_app # generated files diff --git a/programs/Makefile b/programs/Makefile index d5ebfd71b337..538744d48c9c 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -74,7 +74,7 @@ APPS = aes/crypt_and_hash$(EXEXT) \ util/pem2der$(EXEXT) util/strerror$(EXEXT) \ x509/cert_app$(EXEXT) x509/crl_app$(EXEXT) \ x509/cert_req$(EXEXT) x509/cert_write$(EXEXT) \ - x509/req_app$(EXEXT) + x509/load_roots$(EXEXT) x509/req_app$(EXEXT) ifdef PTHREAD APPS += ssl/ssl_pthread_server$(EXEXT) @@ -285,6 +285,10 @@ x509/cert_req$(EXEXT): x509/cert_req.c $(DEP) echo " CC x509/cert_req.c" $(CC) $(LOCAL_CFLAGS) $(CFLAGS) x509/cert_req.c $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ +x509/load_roots$(EXEXT): x509/load_roots.c $(DEP) + echo " CC x509/load_roots.c" + $(CC) $(LOCAL_CFLAGS) $(CFLAGS) x509/load_roots.c $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ + x509/req_app$(EXEXT): x509/req_app.c $(DEP) echo " CC x509/req_app.c" $(CC) $(LOCAL_CFLAGS) $(CFLAGS) x509/req_app.c $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ diff --git a/programs/x509/CMakeLists.txt b/programs/x509/CMakeLists.txt index 39b8b5bab39b..4331ca686e02 100644 --- a/programs/x509/CMakeLists.txt +++ b/programs/x509/CMakeLists.txt @@ -25,6 +25,9 @@ target_link_libraries(cert_req ${libs}) add_executable(cert_write cert_write.c) target_link_libraries(cert_write ${libs}) -install(TARGETS cert_app crl_app req_app cert_req cert_write +add_executable(load_roots load_roots.c) +target_link_libraries(load_roots ${libs}) + +install(TARGETS cert_app crl_app req_app cert_req cert_write load_roots DESTINATION "bin" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) diff --git a/programs/x509/load_roots.c b/programs/x509/load_roots.c new file mode 100644 index 000000000000..5baf08b0c3df --- /dev/null +++ b/programs/x509/load_roots.c @@ -0,0 +1,207 @@ +/* + * Root CA reading application + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + * + * This file is provided under the Apache License 2.0, or the + * GNU General Public License v2.0 or later. + * + * ********** + * Apache License 2.0: + * + * 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. + * + * ********** + * + * ********** + * GNU General Public License v2.0 or later: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * ********** + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_time time +#define mbedtls_time_t time_t +#define mbedtls_fprintf fprintf +#define mbedtls_printf printf +#define mbedtls_exit exit +#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS +#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE +#endif /* MBEDTLS_PLATFORM_C */ + +#if !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_FS_IO) || \ + !defined(MBEDTLS_TIMING_C) +int main( void ) +{ + mbedtls_printf("MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_FS_IO and/or " + "MBEDTLS_TIMING_C not defined.\n"); + mbedtls_exit( 0 ); +} +#else + +#include "mbedtls/error.h" +#include "mbedtls/timing.h" +#include "mbedtls/x509_crt.h" + +#include +#include +#include + +#define DFL_ITERATIONS 1 +#define DFL_PRIME_CACHE 1 + +#define USAGE \ + "\n usage: load_roots param=<>... [--] {FILE|DIR}...\n" \ + "\n acceptable parameters:\n" \ + " iterations=%%d Iteration count (not including cache priming); default: 1\n" \ + " prime=%%d Prime the disk read cache? Default: 1 (yes)\n" \ + "\n" + + +/* + * global options + */ +struct options +{ + const char **filenames; /* NULL-terminated list of file names */ + unsigned iterations; /* Number of iterations to time */ + int prime_cache; /* Prime the disk read cache? */ +} opt; + + +int read_certificates( const char *const *filenames ) +{ + mbedtls_x509_crt cas; + int ret = 0; + const char *const *cur; + char error_message[200]; + + mbedtls_x509_crt_init( &cas ); + + for( cur = filenames; *cur != NULL; cur++ ) + { + ret = mbedtls_x509_crt_parse_file( &cas, *cur ); + if( ret != 0 ) + { + mbedtls_strerror( ret, error_message, sizeof( error_message ) ); + printf( "\n%s: -0x%04x (%s)\n", *cur, -ret, error_message ); + goto exit; + } + } + +exit: + mbedtls_x509_crt_free( &cas ); + return( ret == 0 ); +} + +int main( int argc, char *argv[] ) +{ + int exit_code = MBEDTLS_EXIT_FAILURE; + unsigned i, j; + struct mbedtls_timing_hr_time timer; + unsigned long ms; + + if( argc == 0 ) + { + mbedtls_printf( USAGE ); + goto exit; + } + + opt.filenames = NULL; + opt.iterations = DFL_ITERATIONS; + opt.prime_cache = DFL_PRIME_CACHE; + + for( i = 1; i < (unsigned) argc; i++ ) + { + char *p = argv[i]; + char *q = NULL; + + if( strcmp( p, "--" ) == 0 ) + break; + if( ( q = strchr( p, '=' ) ) == NULL ) + break; + *q++ = '\0'; + + for( j = 0; p + j < q; j++ ) + { + if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' ) + argv[i][j] |= 0x20; + } + + if( strcmp( p, "iterations" ) == 0 ) + { + opt.iterations = atoi( q ); + } + else if( strcmp( p, "prime" ) == 0 ) + { + opt.iterations = atoi( q ) != 0; + } + else + mbedtls_printf( "Unknown option: %s\n", p ); + } + + opt.filenames = (const char**) argv + i; + if( *opt.filenames == 0 ) + { + mbedtls_printf( "Missing list of certificate files to parse\n" ); + goto exit; + } + + mbedtls_printf( "Parsing %u certificates", argc - i ); + if( opt.prime_cache ) + { + if( ! read_certificates( opt.filenames ) ) + goto exit; + mbedtls_printf( " " ); + } + + (void) mbedtls_timing_get_timer( &timer, 1 ); + for( i = 1; i <= opt.iterations; i++ ) + { + if( ! read_certificates( opt.filenames ) ) + goto exit; + mbedtls_printf( "." ); + } + ms = mbedtls_timing_get_timer( &timer, 0 ); + mbedtls_printf( "\n%u iterations -> %lu ms\n", opt.iterations, ms ); + exit_code = MBEDTLS_EXIT_SUCCESS; + +exit: + mbedtls_exit( exit_code ); +} +#endif /* necessary configuration */ diff --git a/visualc/VS2010/load_roots.vcxproj b/visualc/VS2010/load_roots.vcxproj new file mode 100644 index 000000000000..95385734af57 --- /dev/null +++ b/visualc/VS2010/load_roots.vcxproj @@ -0,0 +1,173 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + {46cf2d25-6a36-4189-b59c-e4815388e554} + true + + + + {65EB85E6-C928-689F-8335-126F78025220} + Win32Proj + load_roots + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + $(Configuration)\$(TargetName)\ + + + true + $(Configuration)\$(TargetName)\ + + + false + $(Configuration)\$(TargetName)\ + + + false + $(Configuration)\$(TargetName)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../../include + + + Console + true + NotSet + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + Debug + + + false + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../../include + + + Console + true + NotSet + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + Debug + + + false + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../../include + + + Console + true + true + true + Release + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ../../include + + + Console + true + true + true + Release + %(AdditionalDependencies); + + + + + + diff --git a/visualc/VS2010/mbedTLS.sln b/visualc/VS2010/mbedTLS.sln index 57a8d4da33b8..c19b26b88cdb 100644 --- a/visualc/VS2010/mbedTLS.sln +++ b/visualc/VS2010/mbedTLS.sln @@ -233,6 +233,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cert_write", "cert_write.vc {46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "load_roots", "load_roots.vcxproj", "{65EB85E6-C928-689F-8335-126F78025220}" + ProjectSection(ProjectDependencies) = postProject + {46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "req_app", "req_app.vcxproj", "{486B1375-5CFA-C2D2-DD89-C9F497BADCB3}" ProjectSection(ProjectDependencies) = postProject {46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554} @@ -622,6 +627,14 @@ Global {35E52E46-3BA9-4361-41D3-53663C2E9B8A}.Release|Win32.Build.0 = Release|Win32 {35E52E46-3BA9-4361-41D3-53663C2E9B8A}.Release|x64.ActiveCfg = Release|x64 {35E52E46-3BA9-4361-41D3-53663C2E9B8A}.Release|x64.Build.0 = Release|x64 + {65EB85E6-C928-689F-8335-126F78025220}.Debug|Win32.ActiveCfg = Debug|Win32 + {65EB85E6-C928-689F-8335-126F78025220}.Debug|Win32.Build.0 = Debug|Win32 + {65EB85E6-C928-689F-8335-126F78025220}.Debug|x64.ActiveCfg = Debug|x64 + {65EB85E6-C928-689F-8335-126F78025220}.Debug|x64.Build.0 = Debug|x64 + {65EB85E6-C928-689F-8335-126F78025220}.Release|Win32.ActiveCfg = Release|Win32 + {65EB85E6-C928-689F-8335-126F78025220}.Release|Win32.Build.0 = Release|Win32 + {65EB85E6-C928-689F-8335-126F78025220}.Release|x64.ActiveCfg = Release|x64 + {65EB85E6-C928-689F-8335-126F78025220}.Release|x64.Build.0 = Release|x64 {486B1375-5CFA-C2D2-DD89-C9F497BADCB3}.Debug|Win32.ActiveCfg = Debug|Win32 {486B1375-5CFA-C2D2-DD89-C9F497BADCB3}.Debug|Win32.Build.0 = Debug|Win32 {486B1375-5CFA-C2D2-DD89-C9F497BADCB3}.Debug|x64.ActiveCfg = Debug|x64 From a47fdcf119b6541e0d847414aced7e10d67d1580 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 28 Jul 2021 11:33:04 +0200 Subject: [PATCH 02/15] Base64 decoding: don't use the table for '=' Base64 decoding uses equality comparison tests for characters that don't leak information about the content of the data other than its length, such as whitespace. Do this with '=' as well, since it only reveals information about the length. This way the table lookup can focus on character validity and decoding value. Signed-off-by: Gilles Peskine --- library/base64.c | 64 +++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/library/base64.c b/library/base64.c index 692e11e3fae7..752c0ca01512 100644 --- a/library/base64.c +++ b/library/base64.c @@ -85,7 +85,7 @@ static const unsigned char base64_dec_map[128] = 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, - 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 127, 127, 127, 127, 127, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, @@ -121,31 +121,6 @@ static void mbedtls_base64_cond_assign_uchar( unsigned char * dest, const unsign *dest = ( ( *src ) & mask ) | ( ( *dest ) & ~mask ); } -/* - * Constant flow conditional assignment to uint_32 - */ -static void mbedtls_base64_cond_assign_uint32( uint32_t * dest, const uint32_t src, - uint32_t condition ) -{ - /* 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 - - /* Generate bitmask from condition, mask will either be 0xFFFFFFFF or 0 */ - uint32_t mask = ( condition | -condition ); - mask >>= 31; - mask = -mask; - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif - - *dest = ( src & mask ) | ( ( *dest ) & ~mask ); -} - /* * Constant flow check for equality */ @@ -304,17 +279,22 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, if( x != 0 ) return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); - if( src[i] == '=' && ++j > 2 ) - return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); - - dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] ); - - if( src[i] > 127 || dec_map_lookup == 127 ) - return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); - - if( dec_map_lookup < 64 && j != 0 ) + if( src[i] > 127 ) return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + if( src[i] == '=' ) + { + if( ++j > 2 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + } + else + { + if( j != 0 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] ); + if( dec_map_lookup == 127 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + } n++; } @@ -342,10 +322,16 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, if( *src == '\r' || *src == '\n' || *src == ' ' ) continue; - dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src ); - - mbedtls_base64_cond_assign_uint32( &j, j - 1, mbedtls_base64_eq( dec_map_lookup, 64 ) ); - x = ( x << 6 ) | ( dec_map_lookup & 0x3F ); + if( *src == '=' ) + { + --j; + x = x << 6; + } + else + { + dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src ); + x = ( x << 6 ) | ( dec_map_lookup & 0x3F ); + } if( ++n == 4 ) { From f4a0a271d658e849ca6b4705936063b68d335ddb Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 28 Jul 2021 13:54:02 +0200 Subject: [PATCH 03/15] Base64 decoding: use ranges instead of tables Instead of doing constant-flow table lookup, which requires 128 memory loads for each lookup into a 128-entry table, do a range-based calculation, which requires more CPU instructions per range but there are only 5 ranges. Experimentally, this is ~12x faster on my PC (based on programs/x509/load_roots). The code is slightly smaller, too. Signed-off-by: Gilles Peskine --- library/base64.c | 64 +++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/library/base64.c b/library/base64.c index 752c0ca01512..ae506b67ce65 100644 --- a/library/base64.c +++ b/library/base64.c @@ -77,23 +77,6 @@ static const unsigned char base64_enc_map[64] = '8', '9', '+', '/' }; -static const unsigned char base64_dec_map[128] = -{ - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, - 127, 127, 127, 127, 127, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 127, 127, 127, 127, 127 -}; - #define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ /* @@ -164,6 +147,18 @@ static unsigned char mbedtls_base64_table_lookup( const unsigned char * const ta return result; } +/* Return 0xff if low <= c <= high, 0 otherwise. + * + * Constant flow with respect to c. + */ +static unsigned char mask_of_range( unsigned char low, unsigned char high, + unsigned char c ) +{ + unsigned low_mask = ( c - low ) >> 8; + unsigned high_mask = ( c - high - 1 ) >> 8; + return( ~low_mask & high_mask & 0xff ); +} + /* * Encode a buffer into base64 format */ @@ -242,6 +237,34 @@ int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, return( 0 ); } +/* Given a Base64 digit, return its value. + * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'), + * return -1. + * + * The implementation assumes that letters are consecutive (e.g. ASCII + * but not EBCDIC). + * + * The implementation is constant-flow (no branch or memory access depending + * on the value of c) unless the compiler inlines and optimizes a specific + * access. + */ +static signed char dec_value( unsigned char c ) +{ + unsigned char val = 0; + /* For each range of digits, if c is in that range, mask val with + * the corresponding value. Since c can only be in a single range, + * only at most one masking will change val. Set val to one plus + * the desired value so that it stays 0 if c is in none of the ranges. */ + val |= mask_of_range( 'A', 'Z', c ) & ( c - 'A' + 0 + 1 ); + val |= mask_of_range( 'a', 'z', c ) & ( c - 'a' + 26 + 1 ); + val |= mask_of_range( '0', '9', c ) & ( c - '0' + 52 + 1 ); + val |= mask_of_range( '+', '+', c ) & ( c - '+' + 62 + 1 ); + val |= mask_of_range( '/', '/', c ) & ( c - '/' + 63 + 1 ); + /* At this point, val is 0 if c is an invalid digit and v+1 if c is + * a digit with the value v. */ + return( val - 1 ); +} + /* * Decode a base64-formatted buffer */ @@ -251,7 +274,6 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, size_t i, n; uint32_t j, x; unsigned char *p; - unsigned char dec_map_lookup; /* First pass: check for validity and get output length */ for( i = n = j = 0; i < slen; i++ ) @@ -291,8 +313,7 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, { if( j != 0 ) return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); - dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] ); - if( dec_map_lookup == 127 ) + if( dec_value( src[i] ) < 0 ) return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); } n++; @@ -329,8 +350,7 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, } else { - dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src ); - x = ( x << 6 ) | ( dec_map_lookup & 0x3F ); + x = ( x << 6 ) | ( dec_value( *src ) & 0x3F ); } if( ++n == 4 ) From ea96b3aed9c9d6d9ba51b360142d814ed3fe709e Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 28 Jul 2021 14:20:06 +0200 Subject: [PATCH 04/15] Base64 decode: simplify local variables Document what each local variable does when it isn't obvious from the name. Don't reuse a variable for different purposes. This commit has very little impact on the generated code (same code size on a sample Thumb build), although it does fix a theoretical bug that 2^32 spaces inside a line would be ignored instead of treated as an error. Signed-off-by: Gilles Peskine --- library/base64.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/library/base64.c b/library/base64.c index ae506b67ce65..17a283406868 100644 --- a/library/base64.c +++ b/library/base64.c @@ -271,19 +271,22 @@ static signed char dec_value( unsigned char c ) int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen ) { - size_t i, n; - uint32_t j, x; + size_t i; /* index in source */ + size_t n; /* number of digits or trailing = in source */ + uint32_t x; /* value accumulator */ + unsigned equals = 0; + int spaces_present = 0; unsigned char *p; /* First pass: check for validity and get output length */ - for( i = n = j = 0; i < slen; i++ ) + for( i = n = 0; i < slen; i++ ) { /* Skip spaces before checking for EOL */ - x = 0; + spaces_present = 0; while( i < slen && src[i] == ' ' ) { ++i; - ++x; + spaces_present = 1; } /* Spaces at end of buffer are OK */ @@ -298,7 +301,7 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, continue; /* Space inside a line is an error */ - if( x != 0 ) + if( spaces_present ) return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); if( src[i] > 127 ) @@ -306,12 +309,12 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, if( src[i] == '=' ) { - if( ++j > 2 ) + if( ++equals > 2 ) return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); } else { - if( j != 0 ) + if( equals != 0 ) return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); if( dec_value( src[i] ) < 0 ) return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); @@ -330,7 +333,7 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, * n = ( ( n * 6 ) + 7 ) >> 3; */ n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 ); - n -= j; + n -= equals; if( dst == NULL || dlen < n ) { @@ -338,27 +341,24 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); } - for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) - { + equals = 0; + for( n = x = 0, p = dst; i > 0; i--, src++ ) + { if( *src == '\r' || *src == '\n' || *src == ' ' ) continue; + x = x << 6; if( *src == '=' ) - { - --j; - x = x << 6; - } + ++equals; else - { - x = ( x << 6 ) | ( dec_value( *src ) & 0x3F ); - } + x |= dec_value( *src ); if( ++n == 4 ) { n = 0; - if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); - if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); - if( j > 2 ) *p++ = (unsigned char)( x ); + *p++ = (unsigned char)( x >> 16 ); + if( equals <= 1 ) *p++ = (unsigned char)( x >> 8 ); + if( equals <= 0 ) *p++ = (unsigned char)( x ); } } From b44517ebb35d8f9af2881bab5e058a600e4cbf03 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 28 Jul 2021 14:31:39 +0200 Subject: [PATCH 05/15] Base64 encoding: use ranges instead of tables Instead of doing constant-flow table lookup, which requires 64 memory loads for each lookup into a 64-entry table, do a range-based calculation, which requires more CPU instructions per range but there are only 5 ranges. I expect a significant performance gain (although smaller than for decoding since the encoding table is half the size), but I haven't measured. Code size is slightly smaller. Signed-off-by: Gilles Peskine --- library/base64.c | 122 ++++++++++------------------------------------- 1 file changed, 25 insertions(+), 97 deletions(-) diff --git a/library/base64.c b/library/base64.c index 17a283406868..edab35ec9161 100644 --- a/library/base64.c +++ b/library/base64.c @@ -66,87 +66,8 @@ #endif /* MBEDTLS_PLATFORM_C */ #endif /* MBEDTLS_SELF_TEST */ -static const unsigned char base64_enc_map[64] = -{ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', - 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', - 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', - 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '+', '/' -}; - #define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ -/* - * Constant flow conditional assignment to unsigned char - */ -static void mbedtls_base64_cond_assign_uchar( unsigned char * dest, const unsigned char * const src, - unsigned char condition ) -{ - /* 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 - - /* Generate bitmask from condition, mask will either be 0xFF or 0 */ - unsigned char mask = ( condition | -condition ); - mask >>= 7; - mask = -mask; - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif - - *dest = ( ( *src ) & mask ) | ( ( *dest ) & ~mask ); -} - -/* - * Constant flow check for equality - */ -static unsigned char mbedtls_base64_eq( size_t in_a, size_t in_b ) -{ - size_t difference = in_a ^ in_b; - - /* 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 - - difference |= -difference; - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif - - /* cope with the varying size of size_t per platform */ - difference >>= ( sizeof( difference ) * 8 - 1 ); - - return (unsigned char) ( 1 ^ difference ); -} - -/* - * Constant flow lookup into table. - */ -static unsigned char mbedtls_base64_table_lookup( const unsigned char * const table, - const size_t table_size, const size_t table_index ) -{ - size_t i; - unsigned char result = 0; - - for( i = 0; i < table_size; ++i ) - { - mbedtls_base64_cond_assign_uchar( &result, &table[i], mbedtls_base64_eq( i, table_index ) ); - } - - return result; -} - /* Return 0xff if low <= c <= high, 0 otherwise. * * Constant flow with respect to c. @@ -159,6 +80,24 @@ static unsigned char mask_of_range( unsigned char low, unsigned char high, return( ~low_mask & high_mask & 0xff ); } +/* Given a value in the range 0..63, return the corresponding Base64 digit. + * The implementation assumes that letters are consecutive (e.g. ASCII + * but not EBCDIC). + */ +static unsigned char enc_char( unsigned char val ) +{ + unsigned char digit = 0; + /* For each range of values, if val is in that range, mask digit with + * the corresponding value. Since val can only be in a single range, + * only at most one masking will change digit. */ + digit |= mask_of_range( 0, 25, val ) & ( 'A' + val ); + digit |= mask_of_range( 26, 51, val ) & ( 'a' + val - 26 ); + digit |= mask_of_range( 52, 61, val ) & ( '0' + val - 52 ); + digit |= mask_of_range( 62, 62, val ) & '+'; + digit |= mask_of_range( 63, 63, val ) & '/'; + return( digit ); +} + /* * Encode a buffer into base64 format */ @@ -199,17 +138,10 @@ int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, C2 = *src++; C3 = *src++; - *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), - ( ( C1 >> 2 ) & 0x3F ) ); - - *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), - ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) ); - - *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), - ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) ); - - *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), - ( C3 & 0x3F ) ); + *p++ = enc_char( ( C1 >> 2 ) & 0x3F ); + *p++ = enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ); + *p++ = enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ); + *p++ = enc_char( C3 & 0x3F ); } if( i < slen ) @@ -217,15 +149,11 @@ int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, C1 = *src++; C2 = ( ( i + 1 ) < slen ) ? *src++ : 0; - *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), - ( ( C1 >> 2 ) & 0x3F ) ); - - *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), - ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) ); + *p++ = enc_char( ( C1 >> 2 ) & 0x3F ); + *p++ = enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ); if( ( i + 1 ) < slen ) - *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ), - ( ( ( C2 & 15 ) << 2 ) & 0x3F ) ); + *p++ = enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F ); else *p++ = '='; *p++ = '='; From 32e9530531bfdd412a5be27ed2645d1636e0348f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 28 Jul 2021 14:37:14 +0200 Subject: [PATCH 06/15] Base64 range-based constant-flow code: changelog entry Signed-off-by: Gilles Peskine --- ChangeLog.d/base64-ranges.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ChangeLog.d/base64-ranges.txt diff --git a/ChangeLog.d/base64-ranges.txt b/ChangeLog.d/base64-ranges.txt new file mode 100644 index 000000000000..8ffba2deecd4 --- /dev/null +++ b/ChangeLog.d/base64-ranges.txt @@ -0,0 +1,4 @@ +Changes + * Improve the performance of base64 constant-flow code. The result is still + slower than the original non-constant-flow implementation, but much faster + than the previous constant-flow implemenation. Fixes #4814. From 231b67a6b2b5caf2262bd6c59176acd67a317e53 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 30 Jul 2021 12:56:21 +0200 Subject: [PATCH 07/15] Base64 decode: simplify local variables (n) n was used for two different purposes. Give it a different name the second time. This does not seem to change the generated code when compiling with optimization for size or performance. Signed-off-by: Gilles Peskine --- library/base64.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/base64.c b/library/base64.c index edab35ec9161..b7c2d16a5f88 100644 --- a/library/base64.c +++ b/library/base64.c @@ -202,6 +202,7 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, size_t i; /* index in source */ size_t n; /* number of digits or trailing = in source */ uint32_t x; /* value accumulator */ + unsigned accumulated_digits = 0; unsigned equals = 0; int spaces_present = 0; unsigned char *p; @@ -270,7 +271,7 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, } equals = 0; - for( n = x = 0, p = dst; i > 0; i--, src++ ) + for( x = 0, p = dst; i > 0; i--, src++ ) { if( *src == '\r' || *src == '\n' || *src == ' ' ) continue; @@ -281,9 +282,9 @@ int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, else x |= dec_value( *src ); - if( ++n == 4 ) + if( ++accumulated_digits == 4 ) { - n = 0; + accumulated_digits = 0; *p++ = (unsigned char)( x >> 16 ); if( equals <= 1 ) *p++ = (unsigned char)( x >> 8 ); if( equals <= 0 ) *p++ = (unsigned char)( x ); From bbf97cd1d010ed551903bd837494a61f00294d2c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 30 Jul 2021 12:57:22 +0200 Subject: [PATCH 08/15] mask_of_range: simplify high comparison To test c <= high, instead of testing the sign of (high + 1) - c, negate the sign of high - c (as we're doing for c - low). This is a little easier to read and shaves 2 instructions off the arm thumb build with arm-none-eabi-gcc 7.3.1. Signed-off-by: Gilles Peskine --- library/base64.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/base64.c b/library/base64.c index b7c2d16a5f88..b89313062b67 100644 --- a/library/base64.c +++ b/library/base64.c @@ -75,9 +75,11 @@ static unsigned char mask_of_range( unsigned char low, unsigned char high, unsigned char c ) { - unsigned low_mask = ( c - low ) >> 8; - unsigned high_mask = ( c - high - 1 ) >> 8; - return( ~low_mask & high_mask & 0xff ); + /* low_mask is: 0 if low <= c, 0x...ff if low > c */ + unsigned low_mask = ( (unsigned) c - low ) >> 8; + /* high_mask is: 0 if c <= high, 0x...ff if high > c */ + unsigned high_mask = ( (unsigned) high - c ) >> 8; + return( ~( low_mask | high_mask ) & 0xff ); } /* Given a value in the range 0..63, return the corresponding Base64 digit. From 5bc763d62273592bcade1ffa0f35ebe8463a7d8d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 30 Jul 2021 13:00:10 +0200 Subject: [PATCH 09/15] load_roots: arguments must be files I had originally thought to support directories with mbedtls_x509_crt_parse_path but it would have complicated the code more than I cared for. Remove a remnant of the original project in the documentation. Signed-off-by: Gilles Peskine --- programs/x509/load_roots.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/x509/load_roots.c b/programs/x509/load_roots.c index 5baf08b0c3df..de9914e86299 100644 --- a/programs/x509/load_roots.c +++ b/programs/x509/load_roots.c @@ -86,7 +86,7 @@ int main( void ) #define DFL_PRIME_CACHE 1 #define USAGE \ - "\n usage: load_roots param=<>... [--] {FILE|DIR}...\n" \ + "\n usage: load_roots param=<>... [--] FILE...\n" \ "\n acceptable parameters:\n" \ " iterations=%%d Iteration count (not including cache priming); default: 1\n" \ " prime=%%d Prime the disk read cache? Default: 1 (yes)\n" \ From 051b1da49022b4ff8183752d679d7549d686a8e4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 30 Jul 2021 13:01:36 +0200 Subject: [PATCH 10/15] load_roots: fix no-argument detection Signed-off-by: Gilles Peskine --- programs/x509/load_roots.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/x509/load_roots.c b/programs/x509/load_roots.c index de9914e86299..69357ff3ad0a 100644 --- a/programs/x509/load_roots.c +++ b/programs/x509/load_roots.c @@ -136,7 +136,7 @@ int main( int argc, char *argv[] ) struct mbedtls_timing_hr_time timer; unsigned long ms; - if( argc == 0 ) + if( argc <= 1 ) { mbedtls_printf( USAGE ); goto exit; From 9f6ab290b181dfbe66d99c6be63819341a0a15d6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 30 Jul 2021 13:01:52 +0200 Subject: [PATCH 11/15] load_roots: properly error out on an invalid option Signed-off-by: Gilles Peskine --- programs/x509/load_roots.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/programs/x509/load_roots.c b/programs/x509/load_roots.c index 69357ff3ad0a..040ef296e4a0 100644 --- a/programs/x509/load_roots.c +++ b/programs/x509/load_roots.c @@ -172,7 +172,11 @@ int main( int argc, char *argv[] ) opt.iterations = atoi( q ) != 0; } else + { mbedtls_printf( "Unknown option: %s\n", p ); + mbedtls_printf( USAGE ); + goto exit; + } } opt.filenames = (const char**) argv + i; From 0b39970c99036ee30fc331f40f60b04ae08463f3 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 3 Aug 2021 13:15:04 +0200 Subject: [PATCH 12/15] Fix printf format signedness error Signed-off-by: Gilles Peskine --- programs/x509/load_roots.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/programs/x509/load_roots.c b/programs/x509/load_roots.c index 040ef296e4a0..ba398f9b37b8 100644 --- a/programs/x509/load_roots.c +++ b/programs/x509/load_roots.c @@ -119,7 +119,8 @@ int read_certificates( const char *const *filenames ) if( ret != 0 ) { mbedtls_strerror( ret, error_message, sizeof( error_message ) ); - printf( "\n%s: -0x%04x (%s)\n", *cur, -ret, error_message ); + printf( "\n%s: -0x%04x (%s)\n", + *cur, (unsigned) -ret, error_message ); goto exit; } } From 29d29c208eee5563c60b6d4a8ce0c5f480b6f497 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 6 Aug 2021 14:37:01 +0200 Subject: [PATCH 13/15] Fix the build of sample programs without mbedtls_strerror Signed-off-by: Gilles Peskine --- ChangeLog.d/no-strerror.txt | 3 +++ programs/pkey/key_app_writer.c | 12 +++++++----- programs/x509/load_roots.c | 7 ++++++- 3 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 ChangeLog.d/no-strerror.txt diff --git a/ChangeLog.d/no-strerror.txt b/ChangeLog.d/no-strerror.txt new file mode 100644 index 000000000000..69743a871570 --- /dev/null +++ b/ChangeLog.d/no-strerror.txt @@ -0,0 +1,3 @@ +Bugfix + * Fix the build of sample programs when neither MBEDTLS_ERROR_C nor + MBEDTLS_ERROR_STRERROR_DUMMY is enabled. diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c index afe024a34f75..3f03f101826c 100644 --- a/programs/pkey/key_app_writer.c +++ b/programs/pkey/key_app_writer.c @@ -224,7 +224,9 @@ int main( int argc, char *argv[] ) { int ret = 1; int exit_code = MBEDTLS_EXIT_FAILURE; - char buf[1024]; +#if defined(MBEDTLS_ERROR_C) + char buf[200]; +#endif int i; char *p, *q; @@ -235,7 +237,9 @@ int main( int argc, char *argv[] ) * Set to sane values */ mbedtls_pk_init( &key ); +#if defined(MBEDTLS_ERROR_C) memset( buf, 0, sizeof( buf ) ); +#endif mbedtls_mpi_init( &N ); mbedtls_mpi_init( &P ); mbedtls_mpi_init( &Q ); mbedtls_mpi_init( &D ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &DP ); @@ -323,8 +327,7 @@ int main( int argc, char *argv[] ) if( ret != 0 ) { - mbedtls_strerror( ret, (char *) buf, sizeof(buf) ); - mbedtls_printf( " failed\n ! mbedtls_pk_parse_keyfile returned -0x%04x - %s\n\n", -ret, buf ); + mbedtls_printf( " failed\n ! mbedtls_pk_parse_keyfile returned -0x%04x", -ret ); goto exit; } @@ -384,8 +387,7 @@ int main( int argc, char *argv[] ) if( ret != 0 ) { - mbedtls_strerror( ret, (char *) buf, sizeof(buf) ); - mbedtls_printf( " failed\n ! mbedtls_pk_parse_public_key returned -0x%04x - %s\n\n", -ret, buf ); + mbedtls_printf( " failed\n ! mbedtls_pk_parse_public_key returned -0x%04x", -ret ); goto exit; } diff --git a/programs/x509/load_roots.c b/programs/x509/load_roots.c index ba398f9b37b8..6a40949ec2dc 100644 --- a/programs/x509/load_roots.c +++ b/programs/x509/load_roots.c @@ -109,7 +109,6 @@ int read_certificates( const char *const *filenames ) mbedtls_x509_crt cas; int ret = 0; const char *const *cur; - char error_message[200]; mbedtls_x509_crt_init( &cas ); @@ -118,9 +117,15 @@ int read_certificates( const char *const *filenames ) ret = mbedtls_x509_crt_parse_file( &cas, *cur ); if( ret != 0 ) { +#if defined(MBEDTLS_ERROR_C) || defined(MBEDTLS_ERROR_STRERROR_DUMMY) + char error_message[200]; mbedtls_strerror( ret, error_message, sizeof( error_message ) ); printf( "\n%s: -0x%04x (%s)\n", *cur, (unsigned) -ret, error_message ); +#else + printf( "\n%s: -0x%04x\n", + *cur, (unsigned) -ret ); +#endif goto exit; } } From cda1281ee2210f7901dde41d332d83ec1baa81dc Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 25 Oct 2021 21:13:27 +0200 Subject: [PATCH 14/15] Fix copypasta in comment Signed-off-by: Gilles Peskine --- library/base64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/base64.c b/library/base64.c index b89313062b67..b1bd330ddd3a 100644 --- a/library/base64.c +++ b/library/base64.c @@ -77,7 +77,7 @@ static unsigned char mask_of_range( unsigned char low, unsigned char high, { /* low_mask is: 0 if low <= c, 0x...ff if low > c */ unsigned low_mask = ( (unsigned) c - low ) >> 8; - /* high_mask is: 0 if c <= high, 0x...ff if high > c */ + /* high_mask is: 0 if c <= high, 0x...ff if c > high */ unsigned high_mask = ( (unsigned) high - c ) >> 8; return( ~( low_mask | high_mask ) & 0xff ); } From 8e82c78954288d7c35071b79ff0f2dc8acd955e6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 25 Oct 2021 21:14:06 +0200 Subject: [PATCH 15/15] Fix typo in documentation Signed-off-by: Gilles Peskine --- ChangeLog.d/base64-ranges.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.d/base64-ranges.txt b/ChangeLog.d/base64-ranges.txt index 8ffba2deecd4..e3f3862bfb18 100644 --- a/ChangeLog.d/base64-ranges.txt +++ b/ChangeLog.d/base64-ranges.txt @@ -1,4 +1,4 @@ Changes * Improve the performance of base64 constant-flow code. The result is still slower than the original non-constant-flow implementation, but much faster - than the previous constant-flow implemenation. Fixes #4814. + than the previous constant-flow implementation. Fixes #4814.