This is a fix for the issue I mentioned at https://github.com/RustCrypto/signatures/pull/534#discussion_r980613066. I believe the present implementation of prehash_to_field_bytes
can't interop with OpenSSL (at least but should be the same for other crypto libraries)...
Description
prehash_to_field_bytes
was zero-padding on the right of the byte sequence but this must be done on the left because the output is evaluated as a integer encoded in big-endian, and its integer representation should be stable regardless of sequence length.
This behavior is defined on various documents including RFC6979 Section 2.3.2., SEC 1 Section 2.3.8., NIST FIPS 186-4 Appendix C.2.1.
- https://datatracker.ietf.org/doc/html/rfc6979#section-2.3.2
- https://www.secg.org/sec1-v2.pdf
- https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.186-4.pdf
Verification
I used the following code to test signing with ecdsa crate and verify with OpenSSL:
use digest::{Digest, FixedOutput};
use ecdsa::signature::hazmat::PrehashSigner;
use elliptic_curve::sec1::ToEncodedPoint;
use openssl::nid::Nid;
const DATA: &str = "data to sign";
fn main() {
let pkey = p384::SecretKey::random(&mut rand::thread_rng());
let signing_key = ecdsa::SigningKey::from(&pkey);
let digest = sha2::Sha256::digest(DATA);
let signature = signing_key.sign_prehash(&digest).unwrap();
//---------//
let point_sec1 = pkey.public_key().to_encoded_point(false).to_bytes();
let signature_der = signature.to_der().to_bytes();
//---------//
let mut ossl_bn_ctx = openssl::bn::BigNumContext::new().unwrap();
let ossl_curve = openssl::ec::EcGroup::from_curve_name(Nid::SECP384R1).unwrap();
let ossl_point =
openssl::ec::EcPoint::from_bytes(&ossl_curve, &point_sec1, &mut ossl_bn_ctx).unwrap();
let ossl_public_key = openssl::ec::EcKey::from_public_key(&ossl_curve, &ossl_point).unwrap();
let ossl_signature = openssl::ecdsa::EcdsaSig::from_der(&signature_der).unwrap();
assert!(ossl_signature.verify(&digest, &ossl_public_key).unwrap());
}
this patch fixes the crate not to fail the above code.