<div dir="ltr">Background<br>==========<br><br>[PR#14759](<a href="https://github.com/openssl/openssl/pull/14759">https://github.com/openssl/openssl/pull/14759</a>) (Set<br>blinding=yes property on some algorithm implementations) is a fix for<br>[Issue#14654](<a href="https://github.com/openssl/openssl/issues/14654">https://github.com/openssl/openssl/issues/14654</a>) which<br>itself is a spin-off of<br>[Issue#14616](<a href="https://github.com/openssl/openssl/issues/14616">https://github.com/openssl/openssl/issues/14616</a>).<br><br>The original issue is about _Deprecated low level key API's that have no<br>replacements_, among which the following received special attention and<br>were issued a dedicated issue during an OTC meeting:<br><br>~~~c<br>// RSA functions on RSA_FLAG_*<br>void RSA_clear_flags(RSA *r, int flags);<br>int RSA_test_flags(const RSA *r, int flags);<br>void RSA_set_flags(RSA *r, int flags);<br><br>// RSA_FLAG_* about blinding<br>#define RSA_FLAG_BLINDING<br>#define RSA_FLAG_NO_BLINDING<br><br>// RSA functions directly on blinding<br>int RSA_blinding_on(RSA *rsa, BN_CTX *ctx);<br>void RSA_blinding_off(RSA *rsa);<br>BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *ctx);<br>~~~<br><br>The decision the sprung Issue#14616 and PR#14759 was to use the<br>propquery mechanism to let providers advertise algorithms as<br>`blinding=yes` to select secure implementations if there are insecure<br>ones present as well.<br><br>Similarly it was discussed the potential `consttime=yes` property that<br>would work in a similar way: if applied properly for our current<br>implementations that are not fully constant time it would allow a<br>user/sysadmin/developer to prefer a third party implementation for the<br>same algorithm with better security guarantees.<br>In some contexts the consttime implementation might be seriously<br>penalizing in terms of performance and in the contexts where const time<br>is not required this would allow to select accordingly.<br><br>Definition for the blinding property<br>------------------------------------<br><br>The current definition of the `blinding` property applies to<br>provider-native algorithm implementations for the `asym_cipher` and<br>`signature` operations:<br><br>```pod<br>=head2 Properties<br><br>The following property is set by some of the OpenSSL signature<br>algorithms.<br><br>=over 4<br><br>=item "blinding"<br><br>This boolean property is set to "yes" if the implementation performs<br>blinding to prevent some side-channel attacks.<br>```<br><br>Rationale<br>=========<br><br>Property queries are our decision making process for implementation<br>selection, and has been part of the design for 3.0 since the Brisbane<br>design meetings: I am not opposing the use of the property query<br>mechanism to select algorithms here, but the semantics of the properties<br>we decide to adopt (and thus endorse and encourage also for use by 3rd<br>parties).<br>In particular I see the following issues with choices like<br>`blinding=yes` or `consttime=yes`.<br><br>Design promotes insecure by default<br>-----------------------------------<br><br>This design is a slippery slope into patterns that go against the<br>"secure by default" best practices.<br>Users/administrators/developers should not have to opt-in for the safer<br>implementation, but the other way around: the opt-in should be for the<br>less safe but more performant implementations after evaluating the<br>consequences of such a choice in specific contexts.<br>We shouldn't have users having to query for `consttime=yes` algorithms<br>but rather for `consttime=no` explicitly in specific conditions.<br>So if this was the only issue with PR#14759 my recommendation would be<br>to rather flag the non-blinding implementations as such rather than the<br>other way around as is currently done.<br><br>The scenario in which 3rd party providers offer insecure algorithms not<br>flagged as such with `consttime=no` or `blinding=no` IMO would then fall<br>under the "know your providers" umbrella: if you are installing provider<br>X you should be well aware that you are trusting X's authors "to do the<br>right thing".<br><br>The project history showed us how the risk for insecure-by-default<br>designs and its consequences are not just an hypothetical matter of<br>debate: for example, `BN_FLG_CONSTTIME` has been with us since version<br>0.9.8f (and even before that under the `BN_FLG_EXP_CONSTTIME` name),<br>well over 14 years, in which the decision of having the flag off by<br>default and requiring to manually enabling it when desired has been the<br>cause of many vulnerabilities and fixes, that are still a concern today,<br>as we fixed yet another instance of forgetting to set it just some weeks<br>ago (PR#13889).<br><br>In this case, though, I expect that just flipping the default is not<br>enough to accept this PR: the problem of going with the negative<br>versions of these flags is that such design can't be made future proof<br>as we wish to do: we can't know in advance all possible properties that<br>should be declared as `=no` by an algorithm released today as part of<br>our providers when new relevant properties might be defined in the<br>future.<br>E.g., what if after 3.0 is released a ECCKiila provider was released and<br>opted to tag its implementations as `formally_verified`?<br>They could add `formally_verified=yes` but then they would fall into the<br>"insecure by default" pattern: users would need to opt-in for the safer<br>version instead of getting it by default, but there is no other option<br>given that our and others' providers' offerings were not preemptively<br>flagged with `formally_verified=no`.<br><br>Scope of propquery semantics<br>----------------------------<br><br>This follows directly from the previous example. The design of the<br>propquery mechanism seems (IMO) to be limited to provide<br>__well-defined__ semantics for the properties only within the scope of a<br>single provider (and a single provider version at that).<br><br>If a given provider offered at runtime for the same algorithm two or<br>more versions, one flagged as `consttime=no` and one with<br>consttime guarantees, then it could provide documentation to its<br>userbase on how to setup default propqueries in the configuration file<br>at installation time or to application developers to embed them in their<br>code depending on the use case, to select the `consttime=no` offering<br>when such a thing is perceived as desirable for whatever (ill-guided :P)<br>reason.<br><br>But doing this across providers does not really work, because other<br>provider authors might have not flagged their insecure implementations<br>with `consttime=no`, or because there might be very different opinions<br>on what qualifies as "fully consttime" (that evolve over time with<br>different threat models and attacker capabilities):<br>provX's `consttime=yes` might be "more consttime" than provY's<br>`consttime=yes`.<br>For example provX is similar to our default provider, and<br>offers an EC algorithm built on top of a generic BIGNUM module so its<br>generic implementation supports any valid EC curve named or custom and<br>orgX made sure that the ECDH/ECDSA and ECmath layers of the<br>implementation follow state-of-the-art practices regarding<br>secret-dependant code execution or data access so they flag their<br>EC implementation as `consttime=yes`, even though the underlying BIGNUM<br>module has limited consttime guarantees, so in certain circumstances a<br>dynamic `realloc` or some other seemingly minor thing could leak a few<br>secret bits to a motivated attacker.<br>provY is similar to our default provider, and provides an EC algorithm,<br>but instead of having a generic codepath they only support a subset of<br>named curves (e.g. only P256 and P521) each with a dedicated<br>implementation that removes the need for a generic BIGNUM layer and<br>instead embeds its specific consttime field arithmetic in each curve<br>implementation (e.g. they provide our `ecp_nistz256.c` and<br>`ecp_nistp521.c` implementations only). provY's ECDH/ECDSA, ECmath and<br>FFmath layers all follow best consttime practices so they flag as<br>`consttime=yes` their EC offering.<br>Now `constime=yes` is not well-defined anymore across providers, making<br>it quite useless for users and providers to use `consttime=yes` or<br>`consttime=no` to pick among offerings from different providers.<br><br>The same would be true within the same organization and provider, across<br>provider versions. Let's say tomorrow we were to merge a PR that made<br>all of BIGNUM resistant against all currently known timing side-channel<br>techniques. Coincidentally we decided to mark all our pubkey providers<br>as `consttime=yes` after verifying that all the layers above BIGNUM are<br>also timing-resistant to current techniques.<br>Fast-forward a year and a new CPU design flaw is discovered, giving a<br>remote attacker a side-channel with unprecedented resolution and<br>SNR: our previous `consttime=yes` semantic would not stand the<br>test of time and the disruption of semantics could have ripple-effects<br>within our providers and to the stack of applications that embedded<br>`consttime=yes` as a selection mechanism to pick among offerings from<br>various provider versions with now ill-defined qualifiers.<br><br>If we can agree, even just on some level or some specific cases like<br>these, that the definitions of properties in propqueries have their<br>scope limited to the single provider version, what is the point of<br>exposing `blinding=*` to our users, given that at runtime we don't offer<br>alternative implementations for the same algorithm with different<br>properties?<br>(I mean, yes we have alternative choices at runtime in some cases, but<br>not at the algorithm level in the provider API, they are buried well<br>within each algorithm implementation that offers such choices)<br><br>Too vague/coarse semantics<br>--------------------------<br><br>Elaborating further from the examples above, there is also a conceptual<br>issue at the base of the OTC discussion that led to PR#14759, namely<br>that "blinding is a property of an algorithm: either an implementation<br>does blinding or it doesn't".<br><br>But this is not entirely true: blinding is applied to individual<br>operations at various levels.<br>RSA is a special case that has the luxury of resting its security on<br>basically a single mathematical operation (modular exponentiation) over<br>a single mathematical layer of abstraction (finite field math provided<br>by BIGNUM): so it is enough to apply blinding to the modular<br>exponentiation to say "this algorithm implementations does blinding".<br>That is not true anymore already for DSA signing (that relies on the<br>same single finite field math abstraction provided by BIGNUM, but<br>already rests on two operation, exponentiation and modular inversion)<br>and one more layer deep with ECDH/ECDSA where you have two operations<br>(scalar multiplication and modular inversion), of which the first<br>is composed of math operations coming from the EC arithmetic layer of<br>abstraction, and each of those operation themselves are built as the<br>composition of many operations from the same FF arithmetic layer from<br>BIGNUM.<br>The number of levels of abstraction involved in an implementation keeps<br>rising steeply when we move into the realm of upcoming post-quantum<br>algorithms.<br>When you have multiple operations from multiple layers, applying binding<br>efficiently is non-trivial, one maybe blinds only the EC scalarmul but<br>not the FF modinv, because the first takes the bulk of the computation<br>time and common consensus at some point in time is that there is little<br>point in blinding the modinv if its SNR is deemed too low to be<br>exploitable. But what happens when this does not hold anymore? What is<br>the meaning of `blinding=yes` for an EC implementation that applied<br>blinding only to scalarmul and not to modinv because that was the best<br>practice at the time it was written?<br>What if blinding is applied to the scalarmul but the FF operation to<br>perform the blinding already leaks a small amount because BIGNUM?<br>A small leakage might not be considered a problem with 2048+ RSA<br>keys (shared opinion might be that 1 or 3 bits of knowledge wouldn't<br>give the attacker a noticeable boost compared to other tools in their<br>arsenal) but the same few bits have been proven sufficient to break even<br>P384 or P521 keys (which are above the security level of RSA 2048) with<br>limited effort and costs: what is the meaning of `blinding=yes` in the<br>case where the blinding implementation itself reveals information on the<br>secret it should protect?<br><br>What if the blinding operation itself is not leaking a single bit by<br>itself, but it magnifies some effect from the underlying level of<br>abstraction (e.g., blinding scalarmul could make the nonce bigger than<br>the prime order subgroup size `n`, and the specific scalarmul<br>implementation must guarantee that its scalar input is less than `n` to<br>compute correctly, so it has a special branch to be robust and handle<br>bigger scalars coming from blinding, creating a magnifying lens for an<br>attacker when the branch is taken, as that says something on the<br>probability of the high order bits of the scalar being set)?<br>This might seem as having nothing to do with the semantics of<br>`blinding=yes`, but it does for providers like ours where we apply<br>blinding at top abstraction layer (and in the case of certain paths also<br>in strategic points in the second layer) but then have a number of<br>different sub-algorithm implementations that behave very differently:<br>depending on the curve name (and encoding format when parsing a key) you<br>might end up in the generic prime/binary curves implementation, or in<br>one of the specific ones like nistz256 or nistp521.<br><br>Applying `blinding=yes` like this:<br><br>```c<br>{"ECDSA","provider=default,blinding=yes",ossl_ecdsa_signature_functions}<br>```<br><br>is already making the semantics of the `blinding` property ill-defined,<br>and affecting its effectiveness/purpose as a decision mechanism to be<br>exposed to users: we have different codepaths under the same umbrella<br>flagged as applying blinding, but even within it that blinding has very<br>different shades of "yes".<br><br>As @t8m said "Security is not a boolean value" and my point here is that<br>neither is `blinding` or `consttime` and similar: they come in shades<br>(even the `formally_verified` one: maybe the EC layer is formally<br>verified by tools, but the underlying FF module might come with<br>different guarantees, etc.) and the threshold by which SOTA deems the<br>quality to become "yes*" or "no*" changes over time (e.g., it was fine<br>to only blind scalarmul yesterday, so implementation X was considered as<br>a blinding implementation, but today also modinv blinding is required so<br>the same implementation X is now deemed non-blinding).<br><br>Alternative<br>-----------<br><br>Support for the specific `RSA_FLAG_BLINDING`&co functionality could<br>instead just be dropped.<br>My understanding is that its usefulness is already limited to legacy<br>compatibility with engines which anyway would not play nicely with the<br>new provider/core architecture.<br><br>More in general, as a mechanism to select secure implementations if<br>there are insecure ones present as well, the problem can already be<br>solved applying the "know your providers" mantra in combination with the<br>use of the `provider=default`, `provider=provX` properties to pick<br>across the offerings of multiple providers.<br><br>This wouldn't cover the use case (is this even supported/tested right<br>now?) of a single provider registering the same algorithm twice with<br>different alternative implementations and properties: in this case<br>though it would be possible to use a property definition local to the<br>specific provider version, and its documentation would inform the users<br>of how to use propquery to select what and the related conditions and<br>caveats. Luckily this last case does not affect our implementations, as<br>we don't offer competing algorithms at the provider level.<br><br>Although I wouldn't propose to do it, if we really really wanted to<br>retain the functionality of `RSA_FLAG_BLINDING` and have<br>algorithms exposing knobs with the capability of turning on/off (or<br>1000/500/0) whatever degree of blinding they support, we could achieve<br>this with existing ctrls/params as we do for many other tunable knobs.<br>Using ctrls/params over doing this on a propquery level has the<br>advantage that the definition/semantics can be scoped with more<br>granularity than offered at the provider level.<br>As a user/sysadmin, if I have done the evaluation of the specific<br>context that could lead me to responsibly decide to pick no-blinding,<br>no-consttime, no-secure or similar hazardous choices, I would expect to<br>be anyway in a situation where I have so much control over my<br>system, software and environment that patching the code to pass a param<br>or call a ctrl function deeply inside my application shouldn't be a<br>blocker at all.<br><br>Summary<br>-------<br><br>I am opposed to merging PR#14759 for several reasons:<br><br>- it lends itself to insecure-by-default patterns, repeating mistakes<br>  from the past<br>- the validity scope for similar properties is somewhat limited to a<br>  single provider version, so its effectiveness against its purpose of<br>  being a selection mechanism for users to pick among competing<br>  algorithms offered by different providers is limited (and has the<br>  potential to hunt us back in the future)<br>- its definition and semantics are vague, its applicability as an<br>  algorithm property too coarse to be well-defined even inside our own<br>  providers<br>- `secure`, `blinding`, `consttime`, etc. are not boolean properties of<br>  algorithms (even if I really wish they could be)<br>- it's one more vague concept for everyone to understand, and one more<br>  item with not-too-clear logic for the project to handle and maintain<br>  for the foreseeable future<br>- we have already established alternatives in the form of<br>  per-implementation params or ctrls to tune some security parameters<br>  that can alter the execution flow of our implementations<br><br>Also, from a more generic usability perspective and thinking of<br>supporting those in our Community developing 3rd party providers, I<br>think we should also<br><br>- [in the vote] take a position on what are good/bad ideas when devising<br>  provider-specific properties, and have some official guidelines in the<br>  documentation about it by the time final 3.0.0 is release, and<br>- [not in the vote, could be a separate discussion] document what<br>  mechanisms we plan to put in place to coordinate efforts<br>  which will allow for some carefully evaluated properties to have<br>  well-defined semantics (with versioning?) across providers/vendors<br>  (some form of registry of properties, with well-defined criteria for<br>  maintaining it?)<br><br>Proposed vote text<br>==================<br><br>    Do not merge PR#14759, prevent declaring properties similar to<br>    `blinding=yes` or `consttime=yes` in our implementations and<br>    discourage 3rd parties from adopting similar designs.<br><br><br><br><br>Please provide feedback on the vote text, I would like to open the vote<br>on Monday and have some public debate about its points via the list<br>rather then compress it on the OTC meeting which already has enough<br>items in agenda!<br><br>Thanks,<br><br>Nicola<br></div>