Skip to content

Commit

Permalink
pss: support DecodePrivateKey and DecodePublicKey traits (#424)
Browse files Browse the repository at this point in the history
* pkcs1v15: ensure that these keys are used only with the old RSA OID

RSA PSS keys can be used either with the old rsaEncryption OID or with
the id-RSASSA-PSS, while PKCS1v15 are limited to rsaEncryption. Enforce
this limitation before adding support for is-RSASSA-PSS handling.

Signed-off-by: Dmitry Baryshkov <[email protected]>

* feat: allow id-RSASSA-PSS in verify_algorithm_id()

Allow both rsaEncoding and id-RSASSA-PSS OIDs in verify_algorithm_id().

Signed-off-by: Dmitry Baryshkov <[email protected]>

* pss: support DecodePrivateKey and DecodePublicKey traits

Implement necessary conversion traits to enable DecodePrivateKey and
DecodePublicKey traits implementation.

---------

Signed-off-by: Dmitry Baryshkov <[email protected]>
  • Loading branch information
lumag authored Mar 27, 2024
1 parent d011ca5 commit e54fb7d
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 10 deletions.
25 changes: 19 additions & 6 deletions src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,29 @@ use crate::{
BigUint, RsaPrivateKey, RsaPublicKey,
};
use core::convert::{TryFrom, TryInto};
use pkcs8::{der::Encode, Document, EncodePrivateKey, EncodePublicKey, SecretDocument};
use pkcs8::{
der::Encode, Document, EncodePrivateKey, EncodePublicKey, ObjectIdentifier, SecretDocument,
};
use zeroize::Zeroizing;

/// ObjectID for the RSA PSS keys
pub const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10");

/// Verify that the `AlgorithmIdentifier` for a key is correct.
fn verify_algorithm_id(algorithm: &pkcs8::AlgorithmIdentifierRef) -> pkcs8::spki::Result<()> {
algorithm.assert_algorithm_oid(pkcs1::ALGORITHM_OID)?;

if algorithm.parameters_any()? != pkcs8::der::asn1::Null.into() {
return Err(pkcs8::spki::Error::KeyMalformed);
}
match algorithm.oid {
pkcs1::ALGORITHM_OID => {
if algorithm.parameters_any()? != pkcs8::der::asn1::Null.into() {
return Err(pkcs8::spki::Error::KeyMalformed);
}
}
ID_RSASSA_PSS => {
if !algorithm.parameters.is_none() {
return Err(pkcs8::spki::Error::KeyMalformed);
}
}
_ => return Err(pkcs8::spki::Error::OidUnknown { oid: algorithm.oid }),
};

Ok(())
}
Expand Down
3 changes: 3 additions & 0 deletions src/pkcs1v15/signing_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ where
type Error = pkcs8::Error;

fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
private_key_info
.algorithm
.assert_algorithm_oid(pkcs1::ALGORITHM_OID)?;
RsaPrivateKey::try_from(private_key_info).map(Self::new)
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/pkcs1v15/verifying_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ where
type Error = pkcs8::spki::Error;

fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
spki.algorithm.assert_algorithm_oid(pkcs1::ALGORITHM_OID)?;

RsaPublicKey::try_from(spki).map(Self::new)
}
}
5 changes: 2 additions & 3 deletions src/pss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use self::{
use alloc::{boxed::Box, vec::Vec};
use core::fmt::{self, Debug};

use const_oid::{AssociatedOid, ObjectIdentifier};
use const_oid::AssociatedOid;
use digest::{Digest, DynDigest, FixedOutputReset};
use num_bigint::BigUint;
use pkcs1::RsaPssParams;
Expand All @@ -32,6 +32,7 @@ use rand_core::CryptoRngCore;
use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad};
use crate::algorithms::pss::*;
use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
use crate::encoding::ID_RSASSA_PSS;
use crate::errors::{Error, Result};
use crate::traits::PublicKeyParts;
use crate::traits::SignatureScheme;
Expand Down Expand Up @@ -240,8 +241,6 @@ fn get_pss_signature_algo_id<D>(salt_len: u8) -> pkcs8::spki::Result<AlgorithmId
where
D: Digest + AssociatedOid,
{
const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10");

let pss_params = RsaPssParams::new::<D>(salt_len);

Ok(AlgorithmIdentifierOwned {
Expand Down
15 changes: 15 additions & 0 deletions src/pss/signing_key.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{get_pss_signature_algo_id, sign_digest, Signature, VerifyingKey};
use crate::encoding::ID_RSASSA_PSS;
use crate::{Result, RsaPrivateKey};
use const_oid::AssociatedOid;
use core::marker::PhantomData;
Expand Down Expand Up @@ -219,4 +220,18 @@ where
}
}

impl<D> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<D>
where
D: Digest + AssociatedOid,
{
type Error = pkcs8::Error;

fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
private_key_info
.algorithm
.assert_algorithm_oid(ID_RSASSA_PSS)?;
RsaPrivateKey::try_from(private_key_info).map(Self::new)
}
}

impl<D> ZeroizeOnDrop for SigningKey<D> where D: Digest {}
23 changes: 22 additions & 1 deletion src/pss/verifying_key.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use super::{verify_digest, Signature};
use crate::encoding::ID_RSASSA_PSS;
use crate::RsaPublicKey;
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use pkcs8::{
spki::{der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier},
Document, EncodePublicKey,
AssociatedOid, Document, EncodePublicKey,
};
use signature::{hazmat::PrehashVerifier, DigestVerifier, Verifier};

Expand Down Expand Up @@ -156,3 +157,23 @@ where
key.inner
}
}

impl<D> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for VerifyingKey<D>
where
D: Digest + AssociatedOid,
{
type Error = pkcs8::spki::Error;

fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
match spki.algorithm.oid {
ID_RSASSA_PSS | pkcs1::ALGORITHM_OID => (),
_ => {
return Err(spki::Error::OidUnknown {
oid: spki.algorithm.oid,
});
}
}

RsaPublicKey::try_from(spki).map(Self::new)
}
}
Binary file added tests/examples/pkcs8/rsa2048-rfc9421-priv.der
Binary file not shown.
Binary file added tests/examples/pkcs8/rsa2048-rfc9421-pub.der
Binary file not shown.
30 changes: 30 additions & 0 deletions tests/pkcs8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@ const RSA_2048_PRIV_PEM: &str = include_str!("examples/pkcs8/rsa2048-priv.pem");
#[cfg(feature = "pem")]
const RSA_2048_PUB_PEM: &str = include_str!("examples/pkcs8/rsa2048-pub.pem");

/// RSA-2048 PSS PKCS#8 private key encoded as DER
const RSA_2048_PSS_PRIV_DER: &[u8] = include_bytes!("examples/pkcs8/rsa2048-rfc9421-priv.der");

/// RSA-2048 PSS PKCS#8 public key encoded as DER
const RSA_2048_PSS_PUB_DER: &[u8] = include_bytes!("examples/pkcs8/rsa2048-rfc9421-pub.der");

use hex_literal::hex;
use rsa::{
pkcs1v15,
pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey},
pss,
traits::{PrivateKeyParts, PublicKeyParts},
RsaPrivateKey, RsaPublicKey,
};
Expand Down Expand Up @@ -51,6 +58,29 @@ fn decode_rsa2048_pub_der() {
let _ = pkcs1v15::VerifyingKey::<Sha256>::from_public_key_der(RSA_2048_PUB_DER).unwrap();
}

#[test]
fn decode_rsa2048_pss_priv_der() {
let key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PSS_PRIV_DER).unwrap();

assert_eq!(&key.n().to_bytes_be(), &hex!("AF8B669B7AF6D1677F3DBAAF3F5B36F9012DBE9B91695F18AB8D208D447CCB6463C5AE9DA46D865C76CF7EF32CF1CB7E2E1D461F8E71DBC470DD1CB9DE69BEA005E3C90F3A3A70E467937C9586E0803E0EDF0E8CEA902F2E4864F79027753AE27DB2053CD53C3CF30EECECAB1401EA803B339E33C59933AD08470DD99D45A5681C870B982CF2FE5A892A96D775D67AAACE2F9B27D72F48A00361D50000DE5652DCDDA62CBA2DB4E04B13FBA1C894E139F483923A683649EC0F0BCE8D0A4B2658A00E3CE66A9C3B419501D570F65AB868E4FDBFA77E9DBE1B9CD91056494B4377D502F266FB17433A9F4B08D08DE3C576A670CE90557AF94F67579A3273A5C8DB"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
assert_eq!(&key.d().to_bytes_be(), &hex!("9407C8A9FA426289954A17C02A7C1FDA50FD234C0A8E41EC0AD64289FE24025C10AAA5BA37EB482F76DD391F9559FD10D590480EDA4EF7552B1BBA5A9ECCAB3C445B36B44994F8981323D31E4093D670FE9768ACBA2C862CD04D9C5A0A7C1800E0A01B3C96506AD14857D0A7DF82521E7A4DE7ED9E86B7860581ED9301C5B659B3785DF2BB96EA45CA8E871F25918981CC3004505CB25E3927539F968C04FD0F3B86D0CA4E4E4714D449E39C88F254164B501E4BC66F29BB2ABC847F01FC4E4B342FB5A1CF23FAD0F2F7C52F4534E262F66FB3CEDC1821718342E28CD860EC213783DA6236A07A0F332003D30748EC1C12556D7CA7587E8E07DCE1D95EC4A611"));
assert_eq!(&key.primes()[0].to_bytes_be(), &hex!("E55FBA212239C846821579BE7E4D44336C700167A478F542032BEBF506D3945382670B7D5B08D48E1B4A46EB22E54ABE21867FB6AD96444E00B386FF14710CB69D80111E3721CBE65CFA8A141A1492D5434BB7538481EBB27462D54EDD1EA55DC2230431EE63C4A3609EC28BA67ABEE0DCA1A12E8E796BB5485A331BD27DC509"));
assert_eq!(&key.primes()[1].to_bytes_be(), &hex!("C3EC0875ED7B5B96340A9869DD9674B8CF0E52AD4092B57620A6AEA981DA0F1013DF610CE1C8B630C111DA7214128E20FF8DA55B4CD8A2E145A8E370BF4F87C8EB203E9752A8A442E562E09F455769B8DA35CCBA2A134F5DE274020B6A7620F03DE276FCBFDE2B0356438DD17DD40152AB80C1277B4849A643CB158AA07ADBC3"));

let _ = pss::SigningKey::<Sha256>::from_pkcs8_der(RSA_2048_PSS_PRIV_DER).unwrap();
}

#[test]
fn decode_rsa2048_pss_pub_der() {
let key = RsaPublicKey::from_public_key_der(RSA_2048_PSS_PUB_DER).unwrap();

assert_eq!(&key.n().to_bytes_be(), &hex!("AF8B669B7AF6D1677F3DBAAF3F5B36F9012DBE9B91695F18AB8D208D447CCB6463C5AE9DA46D865C76CF7EF32CF1CB7E2E1D461F8E71DBC470DD1CB9DE69BEA005E3C90F3A3A70E467937C9586E0803E0EDF0E8CEA902F2E4864F79027753AE27DB2053CD53C3CF30EECECAB1401EA803B339E33C59933AD08470DD99D45A5681C870B982CF2FE5A892A96D775D67AAACE2F9B27D72F48A00361D50000DE5652DCDDA62CBA2DB4E04B13FBA1C894E139F483923A683649EC0F0BCE8D0A4B2658A00E3CE66A9C3B419501D570F65AB868E4FDBFA77E9DBE1B9CD91056494B4377D502F266FB17433A9F4B08D08DE3C576A670CE90557AF94F67579A3273A5C8DB"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));

let _ = pss::VerifyingKey::<Sha256>::from_public_key_der(RSA_2048_PSS_PUB_DER).unwrap();
}

#[test]
fn encode_rsa2048_priv_der() {
let key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap();
Expand Down

0 comments on commit e54fb7d

Please sign in to comment.