Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Is RSA PSS key loading from PKCS#8 supported? #422

Closed
taleks opened this issue Mar 26, 2024 · 7 comments
Closed

Is RSA PSS key loading from PKCS#8 supported? #422

taleks opened this issue Mar 26, 2024 · 7 comments

Comments

@taleks
Copy link

taleks commented Mar 26, 2024

Hi,

Are RSA PSS keys supported in rsa crate for loading from PKCS#8? Documentation has that small greyish checkbox for "PSS: Sign & Verify" bullet (though it is not clear what does it mean as there is no any legend) plus https://docs.rs/rsa/latest/rsa/index.html#pkcs8-rsa-key-encoding mentions related traits, so I assumed it is supported. But maybe I was a bit too hasty in that assumption.

If those are supported what is the right way to load RSA PSS private key?

Context

I am trying to load private key https://www.rfc-editor.org/rfc/rfc9421.html#name-example-rsa-pss-key

Test code is:

use base64::Engine;
use base64::prelude::BASE64_STANDARD;
use pkcs8::{DecodePrivateKey, PrivateKeyInfo};
use rsa::RsaPrivateKey;

const RSA_PSS: &str = include_str!("data/rsa2048_rfc9421.pem");

fn main() {
    let line = RSA_PSS.replace("\n", "")
        .replace("-----BEGIN PRIVATE KEY-----", "")
        .replace("-----END PRIVATE KEY-----", "");

    let bytes = BASE64_STANDARD.decode(line).unwrap();
    let pk = PrivateKeyInfo::try_from(bytes.as_slice()).unwrap();

    println!("Key info: {:?}", pk);

    if let Err(err) = RsaPrivateKey::from_pkcs8_pem(RSA_PSS) {
        println!("Error: {err}")
    }
}

Output is:

Key info: PrivateKeyInfo { version: V1, algorithm: AlgorithmIdentifier { oid: ObjectIdentifier(1.2.840.113549.1.1.10), parameters: None }, public_key: None, .. }
Error: public key error: unknown/unsupported algorithm OID: 1.2.840.113549.1.1.1

My understanding is that .10 is OID for rsassa-pss, while .1 is rsaEncryption.

Validation fails here https://github.com/RustCrypto/RSA/blob/master/src/encoding.rs#L15-L23

pkcs1::ALGORITHM_OID comes from https://github.com/RustCrypto/formats/blob/master/pkcs1/src/lib.rs#L55 where it is defined as 1.2.840.113549.1.1.1.

Not really related but...

I believe error message "public key error: unknown/unsupported algorithm OID: 1.2.840.113549.1.1.1" is misleading as code https://github.com/RustCrypto/RSA/blob/master/src/encoding.rs#L16 asserts that oid is equal to pkcs1::ALGORITHM_OID.

    algorithm.assert_algorithm_oid(pkcs1::ALGORITHM_OID)?;

And spki's code is

pub fn assert_algorithm_oid(&self, expected_oid: ObjectIdentifier) -> Result<ObjectIdentifier> {
    if self.oid == expected_oid {
        Ok(expected_oid)
    } else {
        Err(Error::OidUnknown { oid: expected_oid }) // <--- should be self.oid I guess
    }
}

plus "public key" itself in that message does not look right to me.

@tarcieri
Copy link
Member

tarcieri commented Mar 26, 2024

If it's truly a PSS key, try using rsa::pss::SigningKey.

I agree that should probably be self.oid rather than expected_oid in spki.

If you can make that change locally and add a [patch.crates-io] directive to point to your local copy of spki, you should be able to get the OID out.

Not sure if you can post the private key in question or not but that would be helpful in figuring out what's going wrong as well.

If you can't post the private key (totally understandable), openssl asn1parse -in data/rsa2048_rfc9421.pem and all of the lines except for the final OCTET STRING would be very helpful and should also be non-sensitive.

@taleks
Copy link
Author

taleks commented Mar 27, 2024

Hi @tarcieri, thanks for the answer.

Private key is example key from RFC 9421 https://www.rfc-editor.org/rfc/rfc9421.html#name-example-rsa-pss-key

Here is output of openssl asn1parse -in data/rsa2048_rfc9421.pem

openssl asn1parse -in data/rsa2048_rfc9421.pem
    0:d=0  hl=4 l=1214 cons: SEQUENCE          
    4:d=1  hl=2 l=   1 prim: INTEGER           :00
    7:d=1  hl=2 l=  11 cons: SEQUENCE          
    9:d=2  hl=2 l=   9 prim: OBJECT            :rsassaPss
   20:d=1  hl=4 l=1194 prim: OCTET STRING      [HEX DUMP]: ... 

If it's truly a PSS key, try using rsa::pss::SigningKey.

You mean update sample code above to something like this?

rsa::pss::SigningKey::from_pkcs8_pem(RSA_2048_PEM_EXAMPLE)

I believe DecodePrivateKey trait is not defined for SigningKey, at least I see only EncodePrivateKey here https://github.com/RustCrypto/RSA/blob/master/src/pss/signing_key.rs#L181-L188 and my IDE fails to find any related imports.

I also tried it this way:

    let pk = PrivateKeyInfo::try_from(bytes.as_slice()).unwrap(); // same as in sample in the first message
    let rsa_key = RsaPrivateKey::try_from(pk); // <-- Err(PublicKey(OidUnknown { oid: ObjectIdentifier(1.2.840.113549.1.1.1) }))
    let signing_key = rsa::pss::SigningKey::<Sha512>::new(rsa_key.unwrap());

@tarcieri
Copy link
Member

Indeed you're right, we don't have a DecodePrivateKey impl for rsa::pss::SigningKey.

To the extent we support that OID at all, it's in the signature encoding itself: https://github.com/RustCrypto/RSA/blob/7341cd0/src/pss.rs#L243

cc @lumag

@lumag
Copy link
Contributor

lumag commented Mar 27, 2024

Hmm, let me take a look.

@lumag
Copy link
Contributor

lumag commented Mar 27, 2024

#424

@tarcieri
Copy link
Member

@taleks #424 is merged but that's on our current v0.10-pre development series. It would be good to get confirmation it addresses your issue

@taleks
Copy link
Author

taleks commented Mar 28, 2024

@tarcieri Could not check it in actual project yet as there is dependencies version conflict, but code extracted to separate workspace works with as expected with the recent commit e54fb7d and rsa::pss::SigningKey::<Sha512>::from_pkcs8_pem(...) to load key for signing messages.

Thank you folks for the prompt response and fix.

tarcieri added a commit to RustCrypto/formats that referenced this issue Apr 1, 2024
As noted in RustCrypto/RSA#422, we're not returning the actual "unknown
OID" encountered in these cases, but the expected one, which makes it
hard to debug mismatches.
tarcieri added a commit to RustCrypto/formats that referenced this issue Apr 1, 2024
As noted in RustCrypto/RSA#422, we're not returning the actual "unknown
OID" encountered in these cases, but the expected one, which makes it
hard to debug mismatches.
tarcieri added a commit to RustCrypto/formats that referenced this issue Apr 4, 2024
As noted in RustCrypto/RSA#422, we're not returning the actual "unknown
OID" encountered in these cases, but the expected one, which makes it
hard to debug mismatches.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants