WIP: Use constant time by default#5969
Conversation
We also provide a flag to switch off constant time implementations for performance reasons.
|
See https://github.com/HACS-workshop/spectre-mitigations/blob/master/crypto_guidelines.md#1-do-not-conditionally-choose-between-constant-and-non-constant-time. I'm biased, but I think BoringSSL's solution, which was to use separate APIs for constant-time and non-constant-time implementations, is better, in general. |
|
Agreed, though I suppose that too is unsurprising. :-) Echoing what I wrote on openssl-project: In a crypto library, something like "modular exponentiation" is not a complete API contract. Rather, you need contracts like "modular exponentiation with secret fully-reduced base and public exponent" or "modular exponentiation with secret fully-reduced base and secret exponent publicly bounded by such-and-such". Cast in that light, I think it becomes much clearer that they should be separate functions. You could even imagine embedding secrecy into the type (either for safety or to take advantage of some future compiler annotations), in which case separate functions is necessary. This PR instead makes things even further dependent on bit propagation, which was a large part of why the old scheme was error-prone and difficult to analyze. While the flipped default probably helps a bit, most Separate functions, in contrast, place the algorithm decision right at the call site, where one typically thinks about it. It's much easier to reason about what code runs where, and whether the right code runs. |
|
Separate functions feels better to me as well. Trying to track public vs private automatically is a noble ideal but it relies on the programmer setting things correctly every time. This PR will be easier/safer than having to remember to set and clear the constant time flag but the risk seems high still. Separate functions has this risk too but it is more in the face -- someone looking at the documentation will see both versions immediately rather than having to remember to look at this other page of documentation, which they mightn't even know exists, for the public/private differentiator. I'd advocate adding a suffix A separate item along similar lines would be making the small memory model builds only have the constant time flavour of these routines. |
|
Thanks for the link and other feedback. A separate API does seem like a good idea. I'm going to leave this PR open for a while longer to see if there is any other feedback. |
|
I agree with above commentators that it is better to have distinct API endpoints for what are in fact distinct operations. Bikeshedding here, but I'd say rather than |
|
I opened #6078 to track this issue, so I'm going to close this PR. |
The BIGNUM library defaults to a non-constant time implementation of various operations. Where we want to force a constant time implementation we have to remember to set the
BN_FLG_CONSTTIMEflag. Experience has shown that we often forget to do this. For example see:This is not intended to be an exhaustive list - there are probably others cases that I haven't listed.
The difficulty of changing the default is that this will have a performance impact for cases where constant time is not a requirement. It is unclear to me how many of those cases there are are and whether we should be worried about it or not.
This PR switches the default so that we always use a constant time implementation unless data is specifically marked as public. It also attempts to track what data is private and what data is public. For example if an operation takes two inputs and has one output (e.g. BN_add()) then we mark the output as public if both inputs are also public. Otherwise we mark the output as private. When its gets to a decision as to whether to take a constant time path or not, if any input is marked as private then the constant time path is taken. BIGNUMs are created private by default. This PR adds a number of new functions for creating public BIGNUMs instead and uses them throughout libcrypto where applicable.
This is WIP because there are no tests or documentation as yet. Before I go any further with this I'd like feedback on the approach and whether this is something we should pursue now (i.e. for 1.1.1) or later (post 1.1.1) or not at all.