On Thu, Nov 12, 2020 at 11:42 AM Dick Franks <rwfra...@acm.org> wrote: > > On Wed, 11 Nov 2020 at 14:14, Nicola Tuveri <nic....@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