Upgrade pkcs1 to 0.4.1

This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update rust/crates/pkcs1
For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md

Test: TreeHugger
Change-Id: I75199656097167fce5b1b043f8e93b326aacde9a
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index c6845d7..8acf345 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "edbfb4db0ddfd1f95c7ed29ca480e4a93ec1737e"
+    "sha1": "40fbcf36aa1d1e20685424576da37b7df0279d3b"
   },
   "path_in_vcs": "pkcs1"
 }
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index d6898bd..5201719 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,8 +1,6 @@
 // This file is generated by cargo2android.py --config cargo2android.json.
 // Do not modify this file as changes will be overridden on upgrade.
 
-
-
 package {
     default_applicable_licenses: ["external_rust_crates_pkcs1_license"],
 }
@@ -37,7 +35,7 @@
     name: "libpkcs1",
     crate_name: "pkcs1",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.4.0",
+    cargo_pkg_version: "0.4.1",
     srcs: ["src/lib.rs"],
     edition: "2021",
     features: [
@@ -48,6 +46,7 @@
     rustlibs: [
         "libder",
         "libpkcs8",
+        "libspki",
         "libzeroize",
     ],
     apex_available: [
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e607ae7..7e95122 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,14 @@
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## 0.4.1 (2022-10-10)
+### Added
+- `RsaPssParams` support ([#698])
+- `RsaOaepParams` support ([#733])
+
+[#698]: https://github.com/RustCrypto/formats/pull/698
+[#733]: https://github.com/RustCrypto/formats/pull/733
+
 ## 0.4.0 (2022-05-08)
 ### Changed
 - Replace document types with `doc::{Document, SecretDocument}` types ([#571])
diff --git a/Cargo.toml b/Cargo.toml
index e193698..b73c625 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
 edition = "2021"
 rust-version = "1.57"
 name = "pkcs1"
-version = "0.4.0"
+version = "0.4.1"
 authors = ["RustCrypto Developers"]
 description = """
 Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #1:
@@ -36,7 +36,6 @@
 ]
 license = "Apache-2.0 OR MIT"
 repository = "https://github.com/RustCrypto/formats/tree/master/pkcs1"
-resolver = "2"
 
 [package.metadata.docs.rs]
 all-features = true
@@ -54,11 +53,18 @@
 optional = true
 default-features = false
 
+[dependencies.spki]
+version = "0.6"
+
 [dependencies.zeroize]
 version = "1"
 optional = true
 default-features = false
 
+[dev-dependencies.const-oid]
+version = "0.9"
+features = ["db"]
+
 [dev-dependencies.hex-literal]
 version = "0.3"
 
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 00f6414..fb1fa3f 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
 [package]
 name = "pkcs1"
-version = "0.4.0" # Also update html_root_url in lib.rs when bumping this
+version = "0.4.1"
 description = """
 Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #1:
 RSA Cryptography Specifications Version 2.2 (RFC 8017)
@@ -16,6 +16,7 @@
 
 [dependencies]
 der = { version = "0.6", features = ["oid"], path = "../der" }
+spki = { version = "0.6", path = "../spki" }
 
 # optional dependencies
 pkcs8 = { version = "0.9", optional = true, default-features = false, path = "../pkcs8" }
@@ -24,6 +25,7 @@
 [dev-dependencies]
 hex-literal = "0.3"
 tempfile = "3"
+const-oid = { version = "0.9", path = "../const-oid", features = ["db"] }
 
 [features]
 alloc = ["der/alloc", "pkcs8/alloc", "zeroize/alloc"]
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..68ddaa3
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2021-2022 The RustCrypto Project Developers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
index a0641dd..51c2998 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/pkcs1
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
 name: "pkcs1"
 description: "Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.2 (RFC 8017)."
 third_party {
@@ -7,14 +11,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/pkcs1/pkcs1-0.4.0.crate"
+    value: "https://static.crates.io/crates/pkcs1/pkcs1-0.4.1.crate"
   }
-  version: "0.4.0"
-  # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+  version: "0.4.1"
   license_type: NOTICE
   last_upgrade_date {
     year: 2022
-    month: 9
-    day: 6
+    month: 12
+    day: 13
   }
 }
diff --git a/src/lib.rs b/src/lib.rs
index edbb128..9176c8d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,9 +2,8 @@
 #![cfg_attr(docsrs, feature(doc_cfg))]
 #![doc = include_str!("../README.md")]
 #![doc(
-    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
-    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
-    html_root_url = "https://docs.rs/pkcs1/0.4.0-pre"
+    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
+    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
 )]
 #![forbid(unsafe_code, clippy::unwrap_used)]
 #![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
@@ -19,6 +18,7 @@
 extern crate std;
 
 mod error;
+mod params;
 mod private_key;
 mod public_key;
 mod traits;
@@ -29,8 +29,9 @@
     asn1::{ObjectIdentifier, UIntRef},
 };
 
-pub use self::{
+pub use crate::{
     error::{Error, Result},
+    params::{RsaOaepParams, RsaPssParams, TrailerField},
     private_key::RsaPrivateKey,
     public_key::RsaPublicKey,
     traits::{DecodeRsaPrivateKey, DecodeRsaPublicKey},
diff --git a/src/params.rs b/src/params.rs
new file mode 100644
index 0000000..e803473
--- /dev/null
+++ b/src/params.rs
@@ -0,0 +1,301 @@
+//! PKCS#1 RSA parameters.
+
+use crate::{Error, Result};
+use der::asn1::{AnyRef, ObjectIdentifier};
+use der::{
+    asn1::ContextSpecificRef, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Reader, Sequence,
+    Tag, TagMode, TagNumber, Writer,
+};
+use spki::AlgorithmIdentifier;
+
+const OID_SHA_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26");
+const OID_MGF_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.8");
+const OID_PSPECIFIED: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.9");
+
+// TODO(tarcieri): make `AlgorithmIdentifier` generic around params; use `OID_SHA_1`
+const SEQ_OID_SHA_1_DER: &[u8] = &[0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a];
+
+const SHA_1_AI: AlgorithmIdentifier<'_> = AlgorithmIdentifier {
+    oid: OID_SHA_1,
+    parameters: None,
+};
+
+const SALT_LEN_DEFAULT: u8 = 20;
+
+/// `TrailerField` as defined in [RFC 8017 Appendix 2.3].
+/// ```text
+/// TrailerField ::= INTEGER { trailerFieldBC(1) }
+/// ```
+/// [RFC 8017 Appendix 2.3]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.3
+#[derive(Clone, Debug, Copy, PartialEq, Eq)]
+#[repr(u8)]
+pub enum TrailerField {
+    /// the only supported value (0xbc, default)
+    BC = 1,
+}
+
+impl Default for TrailerField {
+    fn default() -> Self {
+        Self::BC
+    }
+}
+
+impl<'a> DecodeValue<'a> for TrailerField {
+    fn decode_value<R: Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self> {
+        match u8::decode_value(decoder, header)? {
+            1 => Ok(TrailerField::BC),
+            _ => Err(Self::TAG.value_error()),
+        }
+    }
+}
+
+impl EncodeValue for TrailerField {
+    fn value_len(&self) -> der::Result<der::Length> {
+        Ok(der::Length::ONE)
+    }
+
+    fn encode_value(&self, writer: &mut dyn Writer) -> der::Result<()> {
+        (*self as u8).encode_value(writer)
+    }
+}
+
+impl FixedTag for TrailerField {
+    const TAG: Tag = Tag::Integer;
+}
+
+/// PKCS#1 RSASSA-PSS parameters as defined in [RFC 8017 Appendix 2.3]
+///
+/// ASN.1 structure containing a serialized RSASSA-PSS parameters:
+/// ```text
+/// RSASSA-PSS-params ::= SEQUENCE {
+///     hashAlgorithm      [0] HashAlgorithm      DEFAULT sha1,
+///     maskGenAlgorithm   [1] MaskGenAlgorithm   DEFAULT mgf1SHA1,
+///     saltLength         [2] INTEGER            DEFAULT 20,
+///     trailerField       [3] TrailerField       DEFAULT trailerFieldBC
+/// }
+/// HashAlgorithm ::= AlgorithmIdentifier
+/// MaskGenAlgorithm ::= AlgorithmIdentifier
+/// ```
+///
+/// [RFC 8017 Appendix 2.3]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.3
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct RsaPssParams<'a> {
+    /// Hash Algorithm
+    pub hash: AlgorithmIdentifier<'a>,
+
+    /// Mask Generation Function (MGF)
+    pub mask_gen: AlgorithmIdentifier<'a>,
+
+    /// Salt length
+    pub salt_len: u8,
+
+    /// Trailer field (i.e. [`TrailerField::BC`])
+    pub trailer_field: TrailerField,
+}
+
+impl<'a> Default for RsaPssParams<'a> {
+    fn default() -> Self {
+        Self {
+            hash: SHA_1_AI,
+            mask_gen: default_mgf1_sha1(),
+            salt_len: SALT_LEN_DEFAULT,
+            trailer_field: Default::default(),
+        }
+    }
+}
+
+impl<'a> DecodeValue<'a> for RsaPssParams<'a> {
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
+        reader.read_nested(header.length, |reader| {
+            Ok(Self {
+                hash: reader
+                    .context_specific(TagNumber::N0, TagMode::Explicit)?
+                    .unwrap_or(SHA_1_AI),
+                mask_gen: reader
+                    .context_specific(TagNumber::N1, TagMode::Explicit)?
+                    .unwrap_or_else(default_mgf1_sha1),
+                salt_len: reader
+                    .context_specific(TagNumber::N2, TagMode::Explicit)?
+                    .unwrap_or(SALT_LEN_DEFAULT),
+                trailer_field: reader
+                    .context_specific(TagNumber::N3, TagMode::Explicit)?
+                    .unwrap_or_default(),
+            })
+        })
+    }
+}
+
+impl<'a> Sequence<'a> for RsaPssParams<'a> {
+    fn fields<F, T>(&self, f: F) -> der::Result<T>
+    where
+        F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
+    {
+        f(&[
+            &if self.hash == SHA_1_AI {
+                None
+            } else {
+                Some(ContextSpecificRef {
+                    tag_number: TagNumber::N0,
+                    tag_mode: TagMode::Explicit,
+                    value: &self.hash,
+                })
+            },
+            &if self.mask_gen == default_mgf1_sha1() {
+                None
+            } else {
+                Some(ContextSpecificRef {
+                    tag_number: TagNumber::N1,
+                    tag_mode: TagMode::Explicit,
+                    value: &self.mask_gen,
+                })
+            },
+            &if self.salt_len == SALT_LEN_DEFAULT {
+                None
+            } else {
+                Some(ContextSpecificRef {
+                    tag_number: TagNumber::N2,
+                    tag_mode: TagMode::Explicit,
+                    value: &self.salt_len,
+                })
+            },
+            &if self.trailer_field == TrailerField::default() {
+                None
+            } else {
+                Some(ContextSpecificRef {
+                    tag_number: TagNumber::N3,
+                    tag_mode: TagMode::Explicit,
+                    value: &self.trailer_field,
+                })
+            },
+        ])
+    }
+}
+
+impl<'a> TryFrom<&'a [u8]> for RsaPssParams<'a> {
+    type Error = Error;
+
+    fn try_from(bytes: &'a [u8]) -> Result<Self> {
+        Ok(Self::from_der(bytes)?)
+    }
+}
+
+/// Default Mask Generation Function (MGF): SHA-1.
+fn default_mgf1_sha1<'a>() -> AlgorithmIdentifier<'a> {
+    AlgorithmIdentifier {
+        oid: OID_MGF_1,
+        parameters: Some(
+            AnyRef::new(Tag::Sequence, SEQ_OID_SHA_1_DER)
+                .expect("error creating default MGF1 params"),
+        ),
+    }
+}
+
+/// PKCS#1 RSAES-OAEP parameters as defined in [RFC 8017 Appendix 2.1]
+///
+/// ASN.1 structure containing a serialized RSAES-OAEP parameters:
+/// ```text
+/// RSAES-OAEP-params ::= SEQUENCE {
+///     hashAlgorithm      [0] HashAlgorithm     DEFAULT sha1,
+///     maskGenAlgorithm   [1] MaskGenAlgorithm  DEFAULT mgf1SHA1,
+///     pSourceAlgorithm   [2] PSourceAlgorithm  DEFAULT pSpecifiedEmpty
+/// }
+/// HashAlgorithm ::= AlgorithmIdentifier
+/// MaskGenAlgorithm ::= AlgorithmIdentifier
+/// PSourceAlgorithm ::= AlgorithmIdentifier
+/// ```
+///
+/// [RFC 8017 Appendix 2.1]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.1
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct RsaOaepParams<'a> {
+    /// Hash Algorithm
+    pub hash: AlgorithmIdentifier<'a>,
+
+    /// Mask Generation Function (MGF)
+    pub mask_gen: AlgorithmIdentifier<'a>,
+
+    /// The source (and possibly the value) of the label L
+    pub p_source: AlgorithmIdentifier<'a>,
+}
+
+impl<'a> Default for RsaOaepParams<'a> {
+    fn default() -> Self {
+        Self {
+            hash: SHA_1_AI,
+            mask_gen: default_mgf1_sha1(),
+            p_source: default_pempty_string(),
+        }
+    }
+}
+
+impl<'a> DecodeValue<'a> for RsaOaepParams<'a> {
+    fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
+        reader.read_nested(header.length, |reader| {
+            Ok(Self {
+                hash: reader
+                    .context_specific(TagNumber::N0, TagMode::Explicit)?
+                    .unwrap_or(SHA_1_AI),
+                mask_gen: reader
+                    .context_specific(TagNumber::N1, TagMode::Explicit)?
+                    .unwrap_or_else(default_mgf1_sha1),
+                p_source: reader
+                    .context_specific(TagNumber::N2, TagMode::Explicit)?
+                    .unwrap_or_else(default_pempty_string),
+            })
+        })
+    }
+}
+
+impl<'a> Sequence<'a> for RsaOaepParams<'a> {
+    fn fields<F, T>(&self, f: F) -> der::Result<T>
+    where
+        F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
+    {
+        f(&[
+            &if self.hash == SHA_1_AI {
+                None
+            } else {
+                Some(ContextSpecificRef {
+                    tag_number: TagNumber::N0,
+                    tag_mode: TagMode::Explicit,
+                    value: &self.hash,
+                })
+            },
+            &if self.mask_gen == default_mgf1_sha1() {
+                None
+            } else {
+                Some(ContextSpecificRef {
+                    tag_number: TagNumber::N1,
+                    tag_mode: TagMode::Explicit,
+                    value: &self.mask_gen,
+                })
+            },
+            &if self.p_source == default_pempty_string() {
+                None
+            } else {
+                Some(ContextSpecificRef {
+                    tag_number: TagNumber::N2,
+                    tag_mode: TagMode::Explicit,
+                    value: &self.p_source,
+                })
+            },
+        ])
+    }
+}
+
+impl<'a> TryFrom<&'a [u8]> for RsaOaepParams<'a> {
+    type Error = Error;
+
+    fn try_from(bytes: &'a [u8]) -> Result<Self> {
+        Ok(Self::from_der(bytes)?)
+    }
+}
+
+/// Default Source Algorithm, empty string
+fn default_pempty_string<'a>() -> AlgorithmIdentifier<'a> {
+    AlgorithmIdentifier {
+        oid: OID_PSPECIFIED,
+        parameters: Some(
+            AnyRef::new(Tag::OctetString, &[]).expect("error creating default OAEP params"),
+        ),
+    }
+}
diff --git a/src/traits.rs b/src/traits.rs
index edf06c1..c70820c 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -191,7 +191,7 @@
 }
 
 #[cfg(all(feature = "alloc", feature = "pkcs8"))]
-#[cfg_attr(docsrs, doc(all(feature = "alloc", feature = "pkcs8")))]
+#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs8"))))]
 impl<T: pkcs8::EncodePrivateKey> EncodeRsaPrivateKey for T {
     fn to_pkcs1_der(&self) -> Result<SecretDocument> {
         let pkcs8_doc = self.to_pkcs8_der()?;
@@ -202,7 +202,7 @@
 }
 
 #[cfg(all(feature = "alloc", feature = "pkcs8"))]
-#[cfg_attr(docsrs, doc(all(feature = "alloc", feature = "pkcs8")))]
+#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs8"))))]
 impl<T: pkcs8::EncodePublicKey> EncodeRsaPublicKey for T {
     fn to_pkcs1_der(&self) -> Result<Document> {
         let doc = self.to_public_key_der()?;
diff --git a/tests/params.rs b/tests/params.rs
new file mode 100644
index 0000000..6954934
--- /dev/null
+++ b/tests/params.rs
@@ -0,0 +1,178 @@
+//! PKCS#1 algorithm params tests
+
+use const_oid::db;
+use der::{
+    asn1::{ObjectIdentifier, OctetStringRef},
+    Decode, Encode,
+};
+use hex_literal::hex;
+use pkcs1::{RsaOaepParams, RsaPssParams, TrailerField};
+
+/// Default PSS parameters using all default values (SHA1, MGF1)
+const RSA_PSS_PARAMETERS_DEFAULTS: &[u8] = &hex!("3000");
+/// Example PSS parameters using SHA256 instead of SHA1
+const RSA_PSS_PARAMETERS_SHA2_256: &[u8] = &hex!("3030a00d300b0609608648016503040201a11a301806092a864886f70d010108300b0609608648016503040201a203020120");
+
+/// Default OAEP parameters using all default values (SHA1, MGF1, Empty)
+const RSA_OAEP_PARAMETERS_DEFAULTS: &[u8] = &hex!("3000");
+/// Example OAEP parameters using SHA256 instead of SHA1 and 'abc' as label
+const RSA_OAEP_PARAMETERS_SHA2_256: &[u8] = &hex!("303fa00d300b0609608648016503040201a11a301806092a864886f70d010108300b0609608648016503040201a212301006092a864886f70d0101090403abcdef");
+
+#[test]
+fn decode_pss_param() {
+    let param = RsaPssParams::try_from(RSA_PSS_PARAMETERS_SHA2_256).unwrap();
+
+    assert!(param
+        .hash
+        .assert_algorithm_oid(db::rfc5912::ID_SHA_256)
+        .is_ok());
+    assert_eq!(param.hash.parameters, None);
+    assert!(param
+        .mask_gen
+        .assert_algorithm_oid(db::rfc5912::ID_MGF_1)
+        .is_ok());
+    assert_eq!(
+        param
+            .mask_gen
+            .parameters_any()
+            .unwrap()
+            .sequence(|reader| Ok(ObjectIdentifier::decode(reader)?))
+            .unwrap(),
+        db::rfc5912::ID_SHA_256
+    );
+    assert_eq!(param.salt_len, 32);
+    assert_eq!(param.trailer_field, TrailerField::BC);
+}
+
+#[test]
+fn encode_pss_param() {
+    let mut buf = [0_u8; 256];
+    let param = RsaPssParams::try_from(RSA_PSS_PARAMETERS_SHA2_256).unwrap();
+    assert_eq!(
+        param.encode_to_slice(&mut buf).unwrap(),
+        RSA_PSS_PARAMETERS_SHA2_256
+    );
+}
+
+#[test]
+fn decode_pss_param_default() {
+    let param = RsaPssParams::try_from(RSA_PSS_PARAMETERS_DEFAULTS).unwrap();
+
+    assert!(param
+        .hash
+        .assert_algorithm_oid(db::rfc5912::ID_SHA_1)
+        .is_ok());
+    assert_eq!(param.hash.parameters, None);
+    assert!(param
+        .mask_gen
+        .assert_algorithm_oid(db::rfc5912::ID_MGF_1)
+        .is_ok());
+    assert_eq!(
+        param
+            .mask_gen
+            .parameters_any()
+            .unwrap()
+            .sequence(|reader| Ok(ObjectIdentifier::decode(reader)?))
+            .unwrap(),
+        db::rfc5912::ID_SHA_1
+    );
+    assert_eq!(param.salt_len, 20);
+    assert_eq!(param.trailer_field, TrailerField::BC);
+    assert_eq!(param, Default::default())
+}
+
+#[test]
+fn encode_pss_param_default() {
+    let mut buf = [0_u8; 256];
+    assert_eq!(
+        RsaPssParams::default().encode_to_slice(&mut buf).unwrap(),
+        RSA_PSS_PARAMETERS_DEFAULTS
+    );
+}
+
+#[test]
+fn decode_oaep_param() {
+    let param = RsaOaepParams::try_from(RSA_OAEP_PARAMETERS_SHA2_256).unwrap();
+
+    assert!(param
+        .hash
+        .assert_algorithm_oid(db::rfc5912::ID_SHA_256)
+        .is_ok());
+    assert_eq!(param.hash.parameters, None);
+    assert!(param
+        .mask_gen
+        .assert_algorithm_oid(db::rfc5912::ID_MGF_1)
+        .is_ok());
+    assert_eq!(
+        param
+            .mask_gen
+            .parameters_any()
+            .unwrap()
+            .sequence(|reader| Ok(ObjectIdentifier::decode(reader)?))
+            .unwrap(),
+        db::rfc5912::ID_SHA_256
+    );
+    assert!(param
+        .p_source
+        .assert_algorithm_oid(db::rfc5912::ID_P_SPECIFIED)
+        .is_ok());
+    assert_eq!(
+        param.p_source.parameters_any().unwrap().octet_string(),
+        OctetStringRef::new(&[0xab, 0xcd, 0xef])
+    );
+}
+
+#[test]
+fn encode_oaep_param() {
+    let mut buf = [0_u8; 256];
+    let param = RsaOaepParams::try_from(RSA_OAEP_PARAMETERS_SHA2_256).unwrap();
+    assert_eq!(
+        param.encode_to_slice(&mut buf).unwrap(),
+        RSA_OAEP_PARAMETERS_SHA2_256
+    );
+}
+
+#[test]
+fn decode_oaep_param_default() {
+    let param = RsaOaepParams::try_from(RSA_OAEP_PARAMETERS_DEFAULTS).unwrap();
+
+    assert!(param
+        .hash
+        .assert_algorithm_oid(db::rfc5912::ID_SHA_1)
+        .is_ok());
+    assert_eq!(param.hash.parameters, None);
+    assert!(param
+        .mask_gen
+        .assert_algorithm_oid(db::rfc5912::ID_MGF_1)
+        .is_ok());
+    assert_eq!(
+        param
+            .mask_gen
+            .parameters_any()
+            .unwrap()
+            .sequence(|reader| Ok(ObjectIdentifier::decode(reader)?))
+            .unwrap(),
+        db::rfc5912::ID_SHA_1
+    );
+    assert!(param
+        .p_source
+        .assert_algorithm_oid(db::rfc5912::ID_P_SPECIFIED)
+        .is_ok());
+    assert!(param
+        .p_source
+        .parameters_any()
+        .unwrap()
+        .octet_string()
+        .unwrap()
+        .is_empty(),);
+    assert_eq!(param, Default::default())
+}
+
+#[test]
+fn encode_oaep_param_default() {
+    let mut buf = [0_u8; 256];
+    assert_eq!(
+        RsaOaepParams::default().encode_to_slice(&mut buf).unwrap(),
+        RSA_OAEP_PARAMETERS_DEFAULTS
+    );
+}