Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

The From<RSAPublicKey> implementation for VerifyingKey returns unprefixed Keys, this should be documented #341

Open
ixolius opened this issue Jun 22, 2023 · 3 comments · May be fixed by #472

Comments

@ixolius
Copy link

ixolius commented Jun 22, 2023

I created a pair of RSA keys using Openssl .
private.key.pem.txt
public.key.pem.txt
Now I have the following code:

use std::fs::File;
use std::io::Read;

use rsa::pkcs8::LineEnding;
use rsa::traits::PublicKeyParts;

use rsa::pkcs8::spki::EncodePublicKey;
use rsa::RsaPrivateKey;
use rsa::RsaPublicKey;
use rsa::pkcs1v15::VerifyingKey;
use rsa::pkcs8::{DecodePrivateKey, DecodePublicKey};
use rsa::pkcs1v15::{SigningKey, Signature};
use rsa::signature::DigestSigner;
use rsa::signature::{Keypair, SignatureEncoding, Verifier, Signer};
use rsa::sha2::{Digest, Sha256};


fn main() {

    let private_key = 
        RsaPrivateKey::read_pkcs8_pem_file("private.key.pem.txt")
        .expect("Could not read private key");
    let signing_key: SigningKey<Sha256> = SigningKey::new(private_key);
    let mut public_key_string = String::new();
    let mut public_key_file = File::open("public.key.pem.txt").unwrap();
    public_key_file.read_to_string(&mut public_key_string).unwrap();
    let public_key = RsaPublicKey::from_public_key_pem(&public_key_string).unwrap();
    let verifying_key_lib = signing_key.verifying_key();
    let verifying_key_openssl: VerifyingKey<Sha256> = VerifyingKey::from(public_key.clone());
    //test public key equality
    let n_lib = verifying_key_lib.as_ref().n();
    let n_openssl = verifying_key_openssl.as_ref().n();
    assert_eq!(n_lib,n_openssl);
    let e_lib = verifying_key_lib.as_ref().e();
    let e_openssl = verifying_key_openssl.as_ref().e();
    assert_eq!(e_lib, e_openssl);
    let size_lib = verifying_key_lib.as_ref().size();
    let size_openssl = verifying_key_openssl.as_ref().size();
    assert_eq!(size_lib, size_openssl);

    // Sign
    let data = b"hello world";
    let mut digest = <Sha256 as Digest>::new();
    digest.update(data);
    let sig2 = signing_key.sign_digest(digest);
    let signature = <SigningKey<Sha256> as Signer<Signature>>::sign(&signing_key, data);
    println!("Public key (openssl): {}", verifying_key_openssl.as_ref().to_public_key_pem(LineEnding::LF).unwrap());
    println!("Public key (lib): {}", public_key.to_public_key_pem(LineEnding::LF).unwrap());
    assert_ne!(signature.to_bytes().as_ref(), data.as_slice());

    // Verify
    verifying_key_openssl.verify(data, &signature)
        .unwrap_or_else(|e|  println!("Error verifying data with direct signature: {}", e));
    verifying_key_openssl.verify(data, &sig2)
        .unwrap_or_else(|e|  println!("Error verifying data with digest signature: {}", e));
    verifying_key_lib.verify(data, &signature)
        .unwrap_or_else(|e|  println!("Error verifying data with direct signature (lib): {}", e));
    verifying_key_lib.verify(data, &sig2)
        .unwrap_or_else(|e|  println!("Error verifying data with digest signature (lib): {}", e));
}

This works for the lib Key, but not for the openssl key. And there are supposed to be equal!

However, if i change

 let verifying_key_openssl: VerifyingKey<Sha256> = VerifyingKey::from(public_key.clone());

to

let verifying_key_openssl: VerifyingKey<Sha256> = VerifyingKey::new(public_key.clone());

each verification passes.
It took me hours to debug this. The problem is the definition of the from method.

impl<D> From<RsaPublicKey> for VerifyingKey<D>
where
    D: Digest,
{
    fn from(key: RsaPublicKey) -> Self {
        Self::new_unprefixed(key)
    }
}

(from: https://docs.rs/rsa/0.9.2/src/rsa/pkcs1v15/verifying_key.rs.html#167-169)

I'm not sure whether it is possible to modify the implementation and maybe there are good reasons for this behavior. But there should be something like a warning for the from method in the documentation, like this:

The resulting VerifyingKey is unprefixed, which is uncommon. In most cases you’ll want to use VerifyingKey::new instead.

as it is done with VerifyingKey::new_unprefixed.

This issue is closely related to #238

The Cargo.toml for the example code is
Cargo.toml.txt

@tarcieri
Copy link
Member

It seems like we should just change the implementation to call ::new.

It's a breaking change though, so it would have to be done in a v0.10 release.

@ixolius
Copy link
Author

ixolius commented Jun 26, 2023

In my opinion, changing the implementation of ::new would be the preferable option.
I'd offer to file a PR, if necessary.

@tarcieri
Copy link
Member

tarcieri commented Jul 8, 2023

You can open a PR and we can make the change in the next breaking release.

baloo added a commit to baloo/RSA that referenced this issue Feb 5, 2025
As discussed in RustCrypto#341, `pkcs1v15::VerifyingKey::from` should use the
prefixed keys.
@baloo baloo linked a pull request Feb 5, 2025 that will close this issue
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants