[openssl-users] CBC ciphers + TLS 1.0 protocol does not work in OpenSSL 1.0.2d

Jakob Bohm jb-openssl at wisemo.com
Thu Dec 10 19:04:05 UTC 2015


On 10/12/2015 19:13, Benjamin Kaduk wrote:
> On 12/10/2015 12:09 PM, openssl-users at dukhovni.org wrote:
>>> On Dec 10, 2015, at 12:45 PM, Jakob Bohm <jb-openssl at wisemo.com> wrote:
>>>
>>> On 10/12/2015 18:33, Viktor Dukhovni wrote:
>>>> On Thu, Dec 10, 2015 at 04:55:29AM -0700, Jayalakshmi bhat wrote:
>>>>
>>>>
>>>>> static inline unsigned int constant_time_msb(unsigned int a) {
>>>>> -  return 0 - (a >> (sizeof(a) * 8 - 1));
>>>>> + return (((unsigned)((int)(a) >> (sizeof(int) * 8 - 1))));
>>>>> }
>>>>>
>>>> The replacement is not right.  This function is supposed to return
>>>> 0xfffffff for inputs with the high bit set, and 0x0000000 for inputs
>>>> with the high bit not set.  Could you try:
>>>>
>>>>      static inline unsigned int constant_time_msb(unsigned int a) {
>>>>        return 0 - (a >> ((int)(sizeof(a) * 8 - 1)));
>>>>      }
>>>>
>>>> Just in case the compiler is promoting "a" to the (larger?) size
>>>> of sizeof(a), which would cause an unsigned "a" to get a zero MSB,
>>>> while a signed "a" would be promoted "correctly".
>>>>
>>> Look again, he is casting a to signed, then doing an
>>> arithmetic right shift to extend the msb (sign bit)
>>> to the rest of the word.  This works on 3 conditions:
>> I saw what he's doing.  casting (a) to an int, instead of leaving
>> it unsigned is not an improvement.  On the assumption that it made
>> a difference for this compiler, I proposed an alternative that tests
>> whether promotion to the type of the shift's right operand is taking
>> place.  It would be good to know whether explicitly casting the shift
>> width to an int helps.  Also that 8 could be replaced by CHAR_BIT
>> just in case.
>>
> Yeah, sizeof returning a size_t that is wider than int, causing
> promotion of the left argument of the shift operator prior to evaluation
> seems a plausible explanation for this behavior.
Please stop the misinformed guesswork and read the
disassembly posted.

The compiler in question gets confused by the long
sequence of nested inline expressions and looses the
truncation from 32 bit unsigned to 8 bit unsigned
char in the shuffle.

Changing back to the old form of constant_time_msb
simplifies the parse tree just enough to avoid the bug.

Unfortunately, as a comment in the 1.0.2 source code
explains, the old form relies on a language feature
not guaranteed by the C standard, which is probably
why the implementation was changed to the one
currently in 1.0.2.

And to those who still don't understand how the old
implementation worked:

1. By casting the unsigned a to a signed int, the msb
   of interest becomes the sign bit.

2. By shifting right the 2's complement signed int by
   the number of non-sign bits (31 on this target),
   the sign bit gets replicated to the other bits so
   negative values (those with the msb set) become -1,
   while positive values (those with the msb clear)
   become +0.

3. Casting back to unsigned int results in the
   desired value of 0xFFFFFFFF or 0x00000000 .

On the ARM platform, shifting right by 31 bits can be
done to the second input of any arithmetic
instruction, thus making it execute in 0.5 instruction
time if combined with some other operation.  Thus the
compiler moves the shift backwards through some
arithmetic steps in the zero testing, resulting in the
code you see in the posted disassembly.



Enjoy

Jakob
-- 
Jakob Bohm, CIO, Partner, WiseMo A/S.  https://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark.  Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mta.openssl.org/pipermail/openssl-users/attachments/20151210/c1c266ce/attachment-0001.html>


More information about the openssl-users mailing list