Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP1:Update
openssl-1_0_0.35258
0009-rsa-rsa_ssl.c-make-RSA_padding_check_SSLv2...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0009-rsa-rsa_ssl.c-make-RSA_padding_check_SSLv23-constant.patch of Package openssl-1_0_0.35258
From 110ef88b99f1acc6b976f2e49153734924181db2 Mon Sep 17 00:00:00 2001 From: Andy Polyakov <appro@openssl.org> Date: Fri, 14 Sep 2018 17:24:13 +0200 Subject: [PATCH 5/5] rsa/rsa_ssl.c: make RSA_padding_check_SSLv23 constant-time. Copy of RSA_padding_check_PKCS1_type_2 with a twist that rejects padding if nul delimiter is preceded by 8 consecutive 0x03 bytes. Reviewed-by: Richard Levitte <levitte@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (cherry picked from commit 603221407ddc6404f8c417c6beadebf84449074c) Resolved conflicts: crypto/rsa/rsa_ssl.c (Merged from https://github.com/openssl/openssl/pull/7737) --- crypto/rsa/rsa_ssl.c | 134 +++++++++++++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 37 deletions(-) diff --git a/crypto/rsa/rsa_ssl.c b/crypto/rsa/rsa_ssl.c index 831f75aaf4..e9a5fe2385 100644 --- a/crypto/rsa/rsa_ssl.c +++ b/crypto/rsa/rsa_ssl.c @@ -61,6 +61,7 @@ #include <openssl/bn.h> #include <openssl/rsa.h> #include <openssl/rand.h> +#include "constant_time_locl.h" int RSA_padding_add_SSLv23(unsigned char *to, int tlen, const unsigned char *from, int flen) @@ -101,57 +102,116 @@ int RSA_padding_add_SSLv23(unsigned char *to, int tlen, return (1); } +/* + * Copy of RSA_padding_check_PKCS1_type_2 with a twist that rejects padding + * if nul delimiter is preceded by 8 consecutive 0x03 bytes. It also + * preserves error code reporting for backward compatibility. + */ int RSA_padding_check_SSLv23(unsigned char *to, int tlen, const unsigned char *from, int flen, int num) { - int i, j, k; - const unsigned char *p; + int i; + /* |em| is the encoded message, zero-padded to exactly |num| bytes */ + unsigned char *em = NULL; + unsigned int good, found_zero_byte, mask, threes_in_row; + int zero_index = 0, msg_index, mlen = -1, err; - p = from; if (flen < 10) { RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, RSA_R_DATA_TOO_SMALL); return (-1); } - /* Accept even zero-padded input */ - if (flen == num) { - if (*(p++) != 0) { - RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, RSA_R_BLOCK_TYPE_IS_NOT_02); - return -1; - } - flen--; + + em = OPENSSL_malloc(num); + if (em == NULL) { + RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, ERR_R_MALLOC_FAILURE); + return -1; } - if ((num != (flen + 1)) || (*(p++) != 02)) { - RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, RSA_R_BLOCK_TYPE_IS_NOT_02); - return (-1); + /* + * Caller is encouraged to pass zero-padded message created with + * BN_bn2binpad. Trouble is that since we can't read out of |from|'s + * bounds, it's impossible to have an invariant memory access pattern + * in case |from| was not zero-padded in advance. + */ + for (from += flen, em += num, i = 0; i < num; i++) { + mask = ~constant_time_is_zero(flen); + flen -= 1 & mask; + from -= 1 & mask; + *--em = *from & mask; } + from = em; + + good = constant_time_is_zero(from[0]); + good &= constant_time_eq(from[1], 2); + err = constant_time_select_int(good, 0, RSA_R_BLOCK_TYPE_IS_NOT_02); + mask = ~good; /* scan over padding data */ - j = flen - 1; /* one for type */ - for (i = 0; i < j; i++) - if (*(p++) == 0) - break; - - if ((i == j) || (i < 8)) { - RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, - RSA_R_NULL_BEFORE_BLOCK_MISSING); - return (-1); - } - for (k = -9; k < -1; k++) { - if (p[k] != 0x03) - break; - } - if (k == -1) { - RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, RSA_R_SSLV3_ROLLBACK_ATTACK); - return (-1); + found_zero_byte = 0; + threes_in_row = 0; + for (i = 2; i < num; i++) { + unsigned int equals0 = constant_time_is_zero(from[i]); + + zero_index = constant_time_select_int(~found_zero_byte & equals0, + i, zero_index); + found_zero_byte |= equals0; + + threes_in_row += 1 & ~found_zero_byte; + threes_in_row &= found_zero_byte | constant_time_eq(from[i], 3); } - i++; /* Skip over the '\0' */ - j -= i; - if (j > tlen) { - RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, RSA_R_DATA_TOO_LARGE); - return (-1); + /* + * PS must be at least 8 bytes long, and it starts two bytes into |from|. + * If we never found a 0-byte, then |zero_index| is 0 and the check + * also fails. + */ + good &= constant_time_ge(zero_index, 2 + 8); + err = constant_time_select_int(mask | good, err, + RSA_R_NULL_BEFORE_BLOCK_MISSING); + mask = ~good; + + good &= constant_time_lt(threes_in_row, 8); + err = constant_time_select_int(mask | good, err, + RSA_R_SSLV3_ROLLBACK_ATTACK); + mask = ~good; + + /* + * Skip the zero byte. This is incorrect if we never found a zero-byte + * but in this case we also do not copy the message out. + */ + msg_index = zero_index + 1; + mlen = num - msg_index; + + /* + * For good measure, do this check in constant time as well. + */ + good &= constant_time_ge(tlen, mlen); + err = constant_time_select_int(mask | good, err, RSA_R_DATA_TOO_LARGE); + + /* + * Even though we can't fake result's length, we can pretend copying + * |tlen| bytes where |mlen| bytes would be real. Last |tlen| of |num| + * bytes are viewed as circular buffer with start at |tlen|-|mlen'|, + * where |mlen'| is "saturated" |mlen| value. Deducing information + * about failure or |mlen| would take attacker's ability to observe + * memory access pattern with byte granularity *as it occurs*. It + * should be noted that failure is indistinguishable from normal + * operation if |tlen| is fixed by protocol. + */ + tlen = constant_time_select_int(constant_time_lt(num, tlen), num, tlen); + msg_index = constant_time_select_int(good, msg_index, num - tlen); + mlen = num - msg_index; + for (from += msg_index, mask = good, i = 0; i < tlen; i++) { + unsigned int equals = constant_time_eq(i, mlen); + + from -= tlen & equals; /* if (i == mlen) rewind */ + mask &= mask ^ equals; /* if (i == mlen) mask = 0 */ + to[i] = constant_time_select_8(mask, from[i], to[i]); } - memcpy(to, p, (unsigned int)j); - return (j); + OPENSSL_cleanse(em, num); + OPENSSL_free(em); + RSAerr(RSA_F_RSA_PADDING_CHECK_SSLV23, err); + err_clear_last_constant_time(1 & good); + + return constant_time_select_int(good, mlen, -1); } -- 2.20.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor