cms: ECC KeyAgreementRecipientInfo initial support#1579
cms: ECC KeyAgreementRecipientInfo initial support#1579baloo merged 33 commits intoRustCrypto:masterfrom
Conversation
cms/Cargo.toml
Outdated
|
|
||
| # optional dependencies | ||
| aes = { version = "=0.9.0-pre.2", optional = true } | ||
| aes-kw = { version ="0.2.1", optional = true } |
There was a problem hiding this comment.
This duplicates the dependency on aes and cipher, we should bump aes-kw to use "aes 0.9.0-pre.2" & "cipher 0.5.0-pre.7".
There was a problem hiding this comment.
Thanks, I'll merge once it's ready
cms/src/builder/kari.rs
Outdated
| /// [RFC 5753 Section 8]: https://datatracker.ietf.org/doc/html/rfc5753#section-8 | ||
| #[allow(clippy::enum_variant_names)] | ||
| #[derive(Clone, Copy)] | ||
| pub enum KeyAgreementAlgorithm { |
There was a problem hiding this comment.
Could we convert that to a trait instead:
pub trait KeyAgreementAlgorithm: AssociatedOid {
fn kdf(secret: &[u8]);
}
And then make a struct like:
struct DhSinglePassStdDhKdf<D> where D:Digest + {
digest: PhantomData<D>,
}
impl<D> KeyAgreementAlgorithm for DhSinglePassStdDhKdf<D> where D:Digest {
fn kdf(secret: &[u8]) {
ansi_x963_kdf::derive_key_into::<D>(secret)
}
}
impl AssociatedOid for DhSinglePassStdDhKdf<sha2::Sha224> {
const OID: ObjectIdentifier = rfc5753::DH_SINGLE_PASS_STD_DH_SHA_224_KDF_SCHEME;
}
There was a problem hiding this comment.
Thanks!
Indeed I was not particularly convinced by the current KDF handling, but I thought it was a fair solution that was easily extensible for other schemes/algo (maybe with the help of a quick macro to derive try_ansi_x963_kdf).
At first I actually went the trait route in my code (close-ish to what you proposed), but then settled on the enum and dispatch function. Rationales were:
- This snippet in
EnvelopedDataBuilderat builder.rs#L890 which caught my eye:
// TODO bk Not good to offer both, `content_encryptor` and `content_encryption_algorithm`.
// We should
// (1) either derive `content_encryption_algorithm` from `content_encryptor` (but this is not
// yet supported by RustCrypto),
// (2) or pass `content_encryption_algorithm` and create an encryptor for it.
// In the first case, we might need a new trait here, e.g. `DynEncryptionAlgorithmIdentifier` in
// analogy to `DynSignatureAlgorithmIdentifier`.
// Going for (2)
// content_encryptor: E,
content_encryption_algorithm: ContentEncryptionAlgorithm,
Even if its not the same situation, I interprated it as "work with enum rather than trait", at least until some is finalized. That was somewhat re-inforced by the current get_hasher() function.
-
Consequently, just passing an enum looked closer to the current API for other builders (having to specify the KA generic in
KeyAgreeRecipientInfoBuilderseemed a tad less user-friendly). -
I thought that if we ended up supporting the other key agreement algorithm (e.g. cofactor ECDH and 1-Pass ECMQV ), we may want to have a more complete trait like:
pub trait KeyAgreementAlgorithm: AssociatedOid {
fn shared_secret()
fn try_kdf(secret: &[u8], other_info: &[u8], key: &mut impl AsMut<[u8]>) -> Result<()>;
}
-> So essentially folding most of the build() logic behind a trait - so to speak.
However not exactly knowing yet:
- what
shared_secret()signature should look like for all. - the input to
try_kdf()would be with other schemes (would that always be aSharedSecret<C>or something moregenericlike&[u8]). - if we should have three structs (
DhSinglePassStdDhKdf,DhSinglePassCoFactorDhKdf,MqvSinglePassKdf) or maybe just one generic for the three schemes.
I figured that a trait was maybe not the best solution yet.
Anyway as you can see, these are more generic thoughts than strong reasons not to, so I am also ok to go the trait route now too.
cms/src/builder/utils/kw.rs
Outdated
| Self::Aes128 => const_oid::db::rfc5911::ID_AES_128_WRAP, | ||
| Self::Aes192 => const_oid::db::rfc5911::ID_AES_192_WRAP, | ||
| Self::Aes256 => const_oid::db::rfc5911::ID_AES_256_WRAP, |
There was a problem hiding this comment.
TODO: We should implement AssociatedOid in https://github.com/RustCrypto/key-wraps/tree/master/aes-kw
There was a problem hiding this comment.
Thanks will merge once its merged upstream
There was a problem hiding this comment.
we will need to move that to a generic parameter as well
There was a problem hiding this comment.
I could add a trait for Key Wrapping too. Do you want the trait to only implement AssociateOid, or the key wrapping logic itself as well (akin to kdf for the KeyAgreement trait)?
|
@nemynm can you rebase? |
5a7a6ca to
aca8958
Compare
|
I can't merge this before we re-integrate x509 and cms in the workspace. I'll need to revisit once that's done. |
|
No worries, in the meantime I'll rebase the PR regularly. |
|
I don't know if rebase is something you can do until we re-unite the workspace (or worth it) |
- Re-organize imports - Adjust comments - Add KeyAgreeRecipientInfoBuilder build logic - Add tests for KeyAgreementAlgorithm and EcKeyEncryptionInfo
|
Could you either merge master or rebase? Thanks a lot! |
|
yes working on a rebase right now |
--------- Co-authored-by: Arthur Gautier <arthur.gautier@arista.com>
|
@baloo rebased it is.
Also some adjustments with latest Let me know any other needed adjustments. |
|
async-signature should be deprecated now (it moved to Could you try this patch: Details |
|
Thanks a lot! |
This PR intends to bring initial support for Elliptic Curve Cryptography (ECC) for CMS - addressing #1544.
KeyAgreementRecipientInfoBuilderfor ECC. For now onlyEnvelopedDatausing(ephemeral-static) ECDHis supported.SHA1and3DESschemes (For SHA1, it could maybe be introduced and gated behind a feature to parse/read/decrypt older/legacy incoming CMS message that use them. However RustCrypto does not seem to support 3DES key wrap)Utils functions:
HashDigestenum to select the hash function to use during key-derivationKeyWrapperis a struct that aims at abstracting the key-wrapping logic for different AES algorithm and different incoming key size.Key Agreement Recipient Info:
KeyAgreementRecipientInfoBuilderis hosted in its own submodule.EcKeyEncryptionInfo- recipient public key (generic over RustCrypto elliptic-curve).While
EcKeyEncryptionInfois essentially the ECC equivalent of the existingKeyEncryptionInfo, it has been introduced to limit API breakage - as it introduces a generic over the chosen elliptic-curve.KeyAgreementAlgorithm- key agreement as per RFC (SHA1 schemes are not supported on purpose, can be amended if needed).KeyWrapAlgorithm- key-wrap algorithm to use.For the sake of simplicity
From<ContentEncryptionAlgorithm> for KeyWrapAlgorithmtrait has been implemented.Testing:
Unit tests have been written in the relevant files. One integration test showcasing
KeyAgreeRecipientInfoBuilderis available, leveraging the existing test P256 key material. Obtained message can be decrypted using:Fixes #1544