Skip to content

implementation of CKM_RSA_AES_KEY_WRAP mechanism#480

Open
keldonin wants to merge 1 commit into
latchset:mainfrom
keldonin:implement_ckm_rsa_aes_key_wrap
Open

implementation of CKM_RSA_AES_KEY_WRAP mechanism#480
keldonin wants to merge 1 commit into
latchset:mainfrom
keldonin:implement_ckm_rsa_aes_key_wrap

Conversation

@keldonin

Copy link
Copy Markdown
Contributor

Description

This PR adds support for CKM_RSA_AES_KEY_WRAP wrapping mechanism, that combines in one go RSA wrapping of a temporary AES key, then AES wrapping of any extractable key.

Checklist

  • Test suite updated
  • Rustdoc string were added or updated
  • CHANGELOG and/or other documentation added or updated
  • This is not a code change

Reviewer's checklist:

  • Any issues marked for closing are fully addressed
  • There is a test suite reasonably covering new functionality or modifications
  • This feature/change has adequate documentation added
  • A changelog entry is added if the change is significant
  • Code conform to coding style that today cannot yet be enforced via the check style test
  • Commits have short titles and sensible text
  • Doc string are properly updated

Copilot AI review requested due to automatic review settings July 12, 2026 21:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds PKCS#11 v3.1 support for the CKM_RSA_AES_KEY_WRAP composite wrapping mechanism (RSA-OAEP wrap of a temporary AES key + AES-KWP wrap of the target key), along with test vectors, warnings for weak wrapping strength, and FIPS indicators/changelog updates.

Changes:

  • Implemented CKM_RSA_AES_KEY_WRAP in the RSA mechanism layer and registered it in the mechanism table.
  • Added unit tests plus an OpenSSL-generated interoperability test vector (JSON) for unwrap validation.
  • Added weak-wrap warning utilities and a FIPS indicators table entry; updated the changelog.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
testdata/rsa_aes_key_wrap.json Adds an OpenSSL-generated interop vector for RSA-AES key wrap framing and unwrap validation.
src/tests/rsa.rs Adds wrap/unwrap round-trip tests and an interoperability unwrap test using the JSON vector.
src/rsa.rs Implements and registers the CKM_RSA_AES_KEY_WRAP mechanism, including ephemeral AES key generation and composite wrap/unwrap logic.
src/misc.rs Adds helper logic to detect/log weak key wrap strength relative to AES key size.
src/fips/indicators.rs Extends the FIPS mechanism indicators table to include CKM_RSA_AES_KEY_WRAP.
CHANGELOG.md Notes the new mechanism support under Unreleased.
Comments suppressed due to low confidence (1)

CHANGELOG.md:11

  • The Unreleased entry is currently listed before the "### What Changed" section, leaving that section empty. This is inconsistent with the formatting used in the rest of the changelog (bullets are under "### What Changed").
## [Unreleased]

* Added support for CKM_RSA_AES_KEY_WRAP mechanism

### What Changed


Comment thread src/rsa.rs
return Err(CKR_WRAPPING_KEY_TYPE_INCONSISTENT)?;
}

let params = mech.get_parameters::<CK_RSA_AES_KEY_WRAP_PARAMS>()?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a fix for the get_parameters() function, rather than this place.

Comment thread src/rsa.rs
return Err(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT)?;
}

let params = mech.get_parameters::<CK_RSA_AES_KEY_WRAP_PARAMS>()?;
Comment thread src/rsa.rs

/* AES-KWP output length (C2), per NIST SP800-38F: the input padded to
* an 8-byte boundary plus an 8-byte integrity check block */
let c2_len = ((keydata.len() + AES_BLOCK_SIZE - 1) / 8) * 8;
@keldonin

Copy link
Copy Markdown
Contributor Author

@simo5 I didn't realize there was a similar PR in the queue, although it seems to be hanging for a while now. I'm fine either way, provided that support for this mechanism is eventually merged into the code base.

Let me know of your pref,

Regards

@Jakuje

Jakuje commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

The #448 did not get update for months so we would better get one active merged than none.

Comment thread src/rsa.rs

/// Implements the RSA AES key wrap operation (Wrap)
///
/// [RSA AES KEY WRAP](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html#_Toc111203524)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the 3.2 is already out so I would reference the latest issue here:

https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.2/pkcs11-spec-v3.2.html#_Toc234407237

Comment thread src/rsa.rs
return Err(CKR_WRAPPING_KEY_TYPE_INCONSISTENT)?;
}

let params = mech.get_parameters::<CK_RSA_AES_KEY_WRAP_PARAMS>()?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a fix for the get_parameters() function, rather than this place.

Comment thread src/fips/indicators.rs
| CKF_DECRYPT
| CKF_WRAP
| CKF_UNWRAP
| CKF_DERIVE,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have the CKF_DERIVE on other wrapping mechanisms, but not on the output AES key itself, see the AES key definition above in FipsKeyType.
If I see right, the only AES Derive operation that exists in specs are CKM_AES_CBC_ENCRYPT_DATA and CKM_AES_ECB_ENCRYPT_DATA, which are not FIPS methods so I think the genflags should not contain the DERIVE. Otherwise the derve should be also on the AES key to be consistent. This is more to @simo5 to clarify FIPS considerations here.

Comment thread src/tests/rsa.rs
(CKA_SENSITIVE, true),
(CKA_UNWRAP, true),
(CKA_DECRYPT, true),
(CKA_EXTRACTABLE, true),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the wrapping key need to be extractable for this test?

Comment thread src/tests/rsa.rs
(CKA_EXPONENT_2, exponent_2.as_slice()),
(CKA_COEFFICIENT, coefficient.as_slice()),
],
&[(CKA_UNWRAP, true), (CKA_DECRYPT, true)],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the explicit DECRYPT flag on the private key needed for the unwrapping operation? I guess this is due to the reuse of the decrypt operation, which does the flag check. I wonder if we should not bypass that in this case (and do the checks only externally to low-level encryption/decryption functions).

I know the usage could be limited with the ALLOWED_MECHANISMS, but I would consider limiting the usage also on the attributes level to either wrapping or encryption without the need for the other one.

Comment thread src/misc.rs
Comment on lines +87 to +89
assert!(!is_weak_key_wrap(112, 128));
assert!(!is_weak_key_wrap(128, 128));
assert!(!is_weak_key_wrap(80, 128));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could these be sorted by size?

Comment thread src/rsa.rs
Comment on lines +63 to +74
/// Mechanism object implementing the CKM_RSA_AES_KEY_WRAP composite key
/// wrapping mechanism.
static RSA_AES_KW_MECH: LazyLock<Box<dyn Mechanism>> = LazyLock::new(|| {
Box::new(RsaAesKeyWrapMechanism {
info: CK_MECHANISM_INFO {
ulMinKeySize: CK_ULONG::try_from(MIN_RSA_SIZE_BITS).unwrap(),
ulMaxKeySize: CK_ULONG::try_from(MAX_RSA_SIZE_BITS).unwrap(),
flags: CKF_WRAP | CKF_UNWRAP,
},
})
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: why not include this mechanism into the RSA_MECHS table? I do not have a strong opinion either way, but we have all the others. Not sure if there is some performance difference in having one or more LazyLock, boxes.

Comment thread src/rsa.rs
Comment on lines +903 to +904
ulParameterLen: CK_ULONG::try_from(std::mem::size_of::<
CK_RSA_PKCS_OAEP_PARAMS,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we use the convenience macro sizeof! here from misc.rs?

Suggested change
ulParameterLen: CK_ULONG::try_from(std::mem::size_of::<
CK_RSA_PKCS_OAEP_PARAMS,
ulParameterLen: sizeof!(CK_RSA_PKCS_OAEP_PARAMS),

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

Successfully merging this pull request may close these issues.

3 participants