Skip to main content

WrapScheme

Enum WrapScheme 

Source
#[non_exhaustive]
pub enum WrapScheme { CmsAes256Gcm, RsaOaepSha256, RsaAesKeyWrapSha256, Aes128Kw, Aes256Kw, Aes128Kwp, Aes256Kwp, }
Expand description

The wrapping scheme a step requests, or a backend reports.

A scheme names a container and the parts of it Rite fixes. What varies with the recipient is recorded in WrapDescription instead.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

CmsAes256Gcm

CMS AuthEnvelopedData (RFC 5083) with AES-256-GCM content encryption. Output: CMS ContentInfo DER.

The encapsulation follows the recipient key: RSA takes key transport, EC takes the RFC 5753 key-agreement path, and a KEM recipient takes the RFC 9629 key-encapsulation path.

CMS-RSA-CBC, the EnvelopedData variant with AES-256-CBC, was removed. It carried no integrity protection, so unwrapping imported whatever decrypted; PCI PIN v3.1 requirement 18-3 bans unauthenticated key encryption. Restoring it would take an authenticated construction around it, which is what the deployments that do use CBC (X9 TR-34, AD CS key archival) wrap it in.

§

RsaOaepSha256

RSAES-OAEP with SHA-256, as raw ciphertext (RFC 8017).

Output is exactly the modulus size and describes nothing about itself. The payload ceiling is k - 2*hLen - 2: 190 bytes under RSA-2048, 446 under RSA-4096, which fits a symmetric key or an EC private key and never fits an RSA one. Self::RsaAesKeyWrapSha256 exists for that.

§

RsaAesKeyWrapSha256

RSA-AES key wrap with SHA-256 (PKCS#11 CKM_RSA_AES_KEY_WRAP).

An ephemeral AES key under RSAES-OAEP, concatenated with the payload under AES-KWP (RFC 5649). The OAEP part comes first and is exactly the modulus size, which is how a recipient splits the two.

This is the shape cloud KMS import expects, and it carries no size ceiling. The digest is in the name because it is not recoverable from the bytes and recipients differ: AWS names both RSA_AES_KEY_WRAP_SHA_256 and RSA_AES_KEY_WRAP_SHA_1, and Azure BYOK specifies SHA-1.

§

Aes128Kw

AES Key Wrap under a 128-bit KEK (RFC 3394, PKCS#11 CKM_AES_KEY_WRAP).

The payload must be a multiple of 8 bytes and at least 16, which a PKCS#8 private key is not, so this carries another symmetric key and little else. Self::Aes128Kwp has no such rule.

§

Aes256Kw

AES Key Wrap under a 256-bit KEK (RFC 3394).

§

Aes128Kwp

AES Key Wrap with Padding under a 128-bit KEK (RFC 5649, PKCS#11 CKM_AES_KEY_WRAP_KWP).

Carries a payload of any length. This is what Thales recommends over CBC for wrapping, and what OpenStack Barbican moved to in 2024 after its hardcoded CKM_AES_CBC_PAD broke against Luna firmware in FIPS mode.

§

Aes256Kwp

AES Key Wrap with Padding under a 256-bit KEK (RFC 5649).

Implementations§

Source§

impl WrapScheme

Source

pub fn fixed_description(self) -> Option<WrapDescription>

The description this scheme fixes, where it fixes one.

None for a self-describing scheme: what a CMS wrap did follows the recipient key, so it is read out of the artifact rather than known in advance. A raw mechanism has no such freedom, which is the same fact that makes its description an assertion.

This is the one place that says what a raw scheme produces. A backend builds its description from here rather than restating the OIDs, and permits compares against it, so the two cannot disagree.

Source

pub fn required_kek(self) -> Option<KeyAlgorithm>

The one key algorithm this scheme wraps under, where it names one.

use rite_sdk::{KeyAlgorithm, WrapScheme};

assert_eq!(WrapScheme::Aes256Kwp.required_kek(), Some(KeyAlgorithm::Aes256));
// CMS admits a family, so it names none.
assert_eq!(WrapScheme::CmsAes256Gcm.required_kek(), None);

None where the scheme admits a family rather than a single algorithm. The AES schemes name a KEK size, because the RFC 3394 and RFC 5649 object identifiers are per-size and fixed_description has only the scheme to go on. Naming it is also what makes a ceremony that expects a 256-bit KEK refuse a 128-bit one instead of wrapping under it in silence.

Source

pub fn accepts_recipient(self, algorithm: KeyAlgorithm) -> bool

Whether a key of this algorithm can receive a wrap under this scheme.

Narrower than KeyAlgorithm::can_receive_wrap, which answers for CMS, where the recipient key selects the encapsulation. The RSA mechanisms accept nothing but RSA, and the AES mechanisms nothing but the KEK size in their name.

A symmetric key passes here and still cannot arrive as recipient:, since that path takes a public key and a symmetric key has none. An AES scheme is reachable only under wrapping_key:.

Source

pub fn permits(self, description: &WrapDescription) -> bool

Whether description is one this scheme admits.

The check is what keeps a recorded scheme from contradicting the artifact it labels. For a self-describing scheme it is a structural test against what was read out of the bytes; for a raw mechanism the description is fixed, so equality is the whole test.

Source

pub fn is_self_describing(self) -> bool

Whether a verifier can re-derive the wrap’s algorithms from the bytes.

This is the line between evidence and assertion. A CMS artifact carries its own algorithm identifiers, so rite verify reads them back and compares them against the transcript; raw mechanism output carries nothing, so the recorded algorithms are what the backend reports having invoked and no offline check can confirm them.

Matched exhaustively on purpose: a scheme added without answering this would otherwise default into being treated as evidence.

Trait Implementations§

Source§

impl Clone for WrapScheme

Source§

fn clone(&self) -> WrapScheme

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for WrapScheme

Source§

impl Debug for WrapScheme

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for WrapScheme

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for WrapScheme

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for WrapScheme

Source§

impl From<WrapScheme> for String

Source§

fn from(a: WrapScheme) -> String

Converts to this type from the input type.
Source§

impl FromStr for WrapScheme

Source§

type Err = ParseError

The associated error which can be returned from parsing.
Source§

fn from_str(s: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
Source§

impl PartialEq for WrapScheme

Source§

fn eq(&self, other: &WrapScheme) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for WrapScheme

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for WrapScheme

Source§

impl TryFrom<String> for WrapScheme

Source§

type Error = ParseError

The type returned in the event of a conversion error.
Source§

fn try_from(s: String) -> Result<Self, Self::Error>

Performs the conversion.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.