OTC VOTE: EVP_PKEY private/public key components

Nicola Tuveri nic.tuv at gmail.com
Thu Nov 12 10:33:13 UTC 2020


On Thu, Nov 12, 2020 at 11:42 AM Dick Franks <rwfranks at acm.org> wrote:
>
> On Wed, 11 Nov 2020 at 14:14, Nicola Tuveri <nic.tuv at gmail.com> wrote:
>>
>>
>> In particular in 1.1.1, the key created as depicted in #12612 that
>> triggered this discussion (Matt posted a useful reproducer among the
>> first comments), is indeed capable of signing in the used pattern, but
>> the pattern is conveniently omitting the validation pass that should
>> be required in any serious use of the API.
>
>
> The private key is a random or pseudo-random 256-bit integer.
> How do you propose to "validate" that?

For ECDSA it's not a a random or pseudo-random 256-bit integer: it's a
random or pseudo-random integer `k`, with `1 <= k < n`, not all
256-bit integers fit into this definition for a 256-bit prime `n`
(where `n` is the order of the generator point for the curve.
Validating the private key guarantees that the input private scalar is
within the correct range.

Sidenote: I don't know how the software in question does keygen, if it
is happening outside of OpenSSL or not, but validating the key
generation step is also crucial, because the random integer generation
should have a uniform distribution over the whole range without any
biases.

>>
>> `EVP_PKEY_check()`
>> (https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_check.html) is
>> one of the many places in 1.1.1 where both the documentation and the
>> behavior assume that an `EVP_PKEY` object is a keypair.
>> Even in the version used by the user that posted the issue, running
>> `EVP_PKEY_check()` on the created key would have revealed that the
>> user was abusing the API.
>
>
>  I was not "abusing the API" as you put it, merely pointing out that the public key is not a required item for performing ECDSA signature generation.  This is a mathematical fact of life that you are going to have to learn to live with.
>

If the documentation of the API says that an `EVP_PKEY` must include a
full keypair, and the functions to validate a manually initialized
`EVP_PKEY` object enforce this, then I stand by my assessment that
writing software that intentionally initializes a non-compliant
`EVP_PKEY` object which would not pass validation functions of the API
(where the documented assumption is enforced) configures as an "API
abuse" from a programming point of view.

I agree that performing an ECDSA signature generation does not require
the public key, and that would be reason in favor of relaxing the
assumption.
I am not saying it is wrong to want to generate signatures only with
the private key, I am saying that it does not fit well with the
OpenSSL API design (and with most other cryptographic libraries, not
just OpenSSL forks, that also have similar "keypair assumptions").

A counter argument to yours is that ECDSA signature verification
requires only the public component, and it is a mathematical fact of
life that knowledge of the private component in this case implies
knowledge of the public component.
A user of a cryptographic library can therefore expect that an
abstract key object embedding knowledge of the private key is capable
of being used in operations requiring knowledge of the public
component, including ECDSA signature verification.
Computing the public component on demand only when such operation is
requested is a sub-optimal design choice from both performance and
security points of views, and robust cryptographic libraries have to
deal with it.

We can reach different compromises, relaxing the documented assumption
as this vote proposes, and then offering API functions for the most
generic use cases and specialized API functions for specific use cases
like yours. I'm not arguing against doing that moving forward, I am
arguing about categorizing the current strict behavior of EC keymgmt
in 3.0 as a "breaking change" and considering the current use pattern
of the reproducer in #12612 against 1.1.1 as "supported" in the
current LTS release.

>>
>> Omitting the `EVP_PKEY_check()` in the reproducer and the user
>> application, would for example allow me to write a DoS attack: the
>> secret scalar could easily be hand-picked to trigger an endless loop
>> in the sign operation.
>
>
> Nonsense.  Each iteration involves a new PRN, which by definition you cannot predict.

~~~sh
; which openssl; openssl version
/usr/bin/openssl
OpenSSL 1.1.1f  31 Mar 2020
; cat > /tmp/p256_invalid.pem
-----BEGIN PRIVATE KEY-----
MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCD/////AAAAAP//////
////vOb6racXnoTzucrC/GMlUQ==
-----END PRIVATE KEY-----
; openssl pkey -check -text -noout -in /tmp/p256_invalid.pem
Key is invalid
Detailed error: point at infinity
Private-Key: (256 bit)
priv:
    ff:ff:ff:ff:00:00:00:00:ff:ff:ff:ff:ff:ff:ff:
    ff:bc:e6:fa:ad:a7:17:9e:84:f3:b9:ca:c2:fc:63:
    25:51
pub:
    00
ASN1 OID: prime256v1
NIST CURVE: P-256
; dd if=/dev/zero of=/tmp/foo.hash bs=1 count=32
; openssl pkeyutl -sign -inkey /tmp/p256_invalid.pem -in /tmp/foo.hash
-out /tmp/sig.der
# here is the infinite loop
~~~

--

Nicola


More information about the openssl-project mailing list