Skip to content

Commit

Permalink
merge: pull request #22 from namib-project/rustcrypto_backend
Browse files Browse the repository at this point in the history
Add a RustCrypto based backend for cryptographic COSE operations
  • Loading branch information
pulsastrix authored Aug 9, 2024
2 parents f64c2ac + 6e9b9e4 commit 0f6a7c2
Show file tree
Hide file tree
Showing 38 changed files with 1,367 additions and 63 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,23 @@ jobs:
with:
command: test

test_all_features:
name: Test Suite (all features)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: test
args: --all-features

test_nostd:
name: Test Suite (no_std)
runs-on: ubuntu-latest
Expand Down
29 changes: 28 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ exclude = [
[features]
default = ["std", "openssl"]
std = ["serde/std", "ciborium/std", "serde_bytes/std", "erased-serde/std", "derive_builder/std"]
rustcrypto = ["rustcrypto-aes-gcm", "rustcrypto-aes-kw", "rustcrypto-ecdsa", "rustcrypto-hmac"]
rustcrypto-encrypt = ["rustcrypto-aes-gcm"]
rustcrypto-sign = ["rustcrypto-ecdsa"]
rustcrypto-key-distribution = ["rustcrypto-aes-kw"]
rustcrypto-mac = ["rustcrypto-hmac"]
rustcrypto-aes-gcm = ["dep:aes-gcm", "dep:typenum", "dep:aead", "dep:aes"]
rustcrypto-aes-kw = ["dep:aes-kw", "dep:aes", "dep:typenum", "dep:crypto-common"]
rustcrypto-ecdsa = ["dep:ecdsa", "dep:p256", "dep:p384", "dep:digest", "dep:sha2", "dep:elliptic-curve"]
rustcrypto-hmac = ["dep:hmac", "dep:digest", "dep:sha2"]

[dependencies]
serde = { version = "1.0", default-features = false, features = ["derive"] }
Expand All @@ -31,10 +40,28 @@ enumflags2 = { version = "^0.7", default-features = false }
rand = { version = "^0.8", default-features = false }
openssl = { version = "^0.10", optional = true }
lazy_static = "1.4.0"
aes-gcm = { version = "0.10.3", optional = true, default-features = false, features = ["alloc", "aes"] }
typenum = { version = "1.17.0", optional = true, default-features = false, features = ["const-generics"] }
crypto-common = { version = "0.1.6", optional = true, default-features = false }
aead = { version = "0.5.2", optional = true, default-features = false }
aes-kw = { version = "0.2.1", optional = true, default-features = false, features = ["alloc"] }
aes = { version = "0.8.4", optional = true, default-features = false }
hmac = { version = "0.12.1", optional = true, default-features = false }
digest = { version = "0.10.7", optional = true, default-features = false }
sha2 = { version = "0.10.8", optional = true, default-features = false }
elliptic-curve = { version = "0.13.8", default-features = false, optional = true }
ecdsa = { version = "0.16.9", optional = true, default-features = false, features = ["sha2"] }
p256 = { version = "0.13.2", optional = true, default-features = false, features = ["alloc", "ecdsa", "arithmetic"] }
p384 = { version = "0.13.0", optional = true, default-features = false, features = ["alloc", "ecdsa", "arithmetic"] }
# P-521 must implement DigestPrimitive in order to be usable in ECDSA, which was only recently added and is not released yet.
# p521 = { version = "0.14.0-pre.1", optional = true }

[dev-dependencies]
hex = { version = "^0.4", features = ["serde"] }
base64 = "0.22.1"
rstest = "0.21.0"
rstest = "0.22.0"
serde_json = "1.0.118"
rand = { version = "^0.8", default-features = false, features = ["std_rng", "std"] }

[build-dependencies]
cfg_aliases = "0.2.1"
45 changes: 45 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
use cfg_aliases::cfg_aliases;

fn main() {
// Set up some aliases for conditional compilation (in order to avoid repetition).
cfg_aliases! {
rustcrypto_encrypt_base: {
any(
feature = "rustcrypto-aes-gcm"
)
},
rustcrypto_sign_base: {
any(
feature = "rustcrypto-ecdsa"
)
},
rustcrypto_key_distribution_base: {
any(
feature = "rustcrypto-aes-kw"
)
},
rustcrypto_mac_base: {
any(
feature = "rustcrypto-hmac"
)
},
rustcrypto_base: {
any(
rustcrypto_encrypt_base,
rustcrypto_sign_base,
rustcrypto_key_distribution_base,
rustcrypto_mac_base
)
},
}
}
2 changes: 1 addition & 1 deletion src/common/cbor_map/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/common/cbor_values/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/common/cbor_values/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/common/scope/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/common/scope/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/common/test_helper.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022-2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/endpoints/creation_hint/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/endpoints/creation_hint/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/endpoints/token_req/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/endpoints/token_req/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/error/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022, 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 The NAMIB Project Developers.
* Copyright (c) 2022-2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
Expand Down
4 changes: 4 additions & 0 deletions src/token/cose/crypto_impl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@
/// Cryptographic backend based on the OpenSSL library (accessed using the `openssl` crate).
#[cfg(feature = "openssl")]
pub mod openssl;

/// Cryptographic backend based on the RustCrypto collection of crates.
#[cfg(rustcrypto_base)]
pub mod rustcrypto;
1 change: 1 addition & 0 deletions src/token/cose/crypto_impl/openssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ impl From<openssl::aes::KeyError> for CoseCipherError<CoseOpensslCipherError> {
///
/// Generic properties of this backend:
/// - [ ] Can derive EC public key components if only the private component (d) is present.
/// - [ ] Can work with compressed EC public keys (EC keys using point compression)
///
/// Algorithm support:
/// - Signature Algorithms (for COSE_Sign and COSE_Sign1)
Expand Down
110 changes: 110 additions & 0 deletions src/token/cose/crypto_impl/rustcrypto/encrypt/aes_gcm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright (c) 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
use aead::{Aead, AeadCore, Key, KeyInit, Nonce, Payload};
use aes::Aes192;
use aes_gcm::{Aes128Gcm, Aes256Gcm, AesGcm};
use coset::{iana, Algorithm};
use rand::CryptoRng;
use rand::RngCore;
use typenum::consts::U12;

use crate::error::CoseCipherError;
use crate::token::cose::{CoseSymmetricKey, CryptoBackend};

use super::RustCryptoContext;

impl<RNG: RngCore + CryptoRng> RustCryptoContext<RNG> {
/// Perform an AEAD encryption operation on `plaintext` and the additional authenticated
/// data `aad` using the given `iv` and `key`.
fn encrypt_aead<AEAD: Aead + AeadCore + KeyInit>(
key: &CoseSymmetricKey<'_, <RustCryptoContext<RNG> as CryptoBackend>::Error>,
plaintext: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<<Self as CryptoBackend>::Error>> {
let aes_key = Key::<AEAD>::from_slice(key.k);
let cipher = AEAD::new(aes_key);
let nonce = Nonce::<AEAD>::from_slice(iv);
let payload = Payload {
msg: plaintext,
aad,
};
cipher
.encrypt(nonce, payload)
.map_err(CoseCipherError::from)
}

/// Perform an AEAD decryption operation on `ciphertext` and the additional authenticated
/// data `aad` using the given `iv` and `key`.
fn decrypt_aead<AEAD: Aead + AeadCore + KeyInit>(
key: &CoseSymmetricKey<'_, <RustCryptoContext<RNG> as CryptoBackend>::Error>,
ciphertext: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<<Self as CryptoBackend>::Error>> {
let aes_key = Key::<AEAD>::from_slice(key.k);
let cipher = AEAD::new(aes_key);
let nonce = Nonce::<AEAD>::from_slice(iv);
let payload = Payload {
msg: ciphertext,
aad,
};
cipher
.decrypt(nonce, payload)
.map_err(CoseCipherError::from)
}

/// Perform an AES-GCM encryption operation on `plaintext` and the additional authenticated
/// data `aad` using the given `iv` and `key` with the given `algorithm` variant of AES-GCM.
pub(super) fn encrypt_aes_gcm(
algorithm: iana::Algorithm,
key: &CoseSymmetricKey<'_, <Self as CryptoBackend>::Error>,
plaintext: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<<Self as CryptoBackend>::Error>> {
match algorithm {
iana::Algorithm::A128GCM => Self::encrypt_aead::<Aes128Gcm>(key, plaintext, aad, iv),
iana::Algorithm::A192GCM => {
Self::encrypt_aead::<AesGcm<Aes192, U12>>(key, plaintext, aad, iv)
}
iana::Algorithm::A256GCM => Self::encrypt_aead::<Aes256Gcm>(key, plaintext, aad, iv),
a => Err(CoseCipherError::UnsupportedAlgorithm(Algorithm::Assigned(
a,
))),
}
}

/// Perform an AES-GCM decryption operation on `ciphertext` and the additional authenticated
/// data `aad` using the given `iv` and `key` with the given `algorithm` variant of AES-GCM.
pub(super) fn decrypt_aes_gcm(
algorithm: iana::Algorithm,
key: &CoseSymmetricKey<'_, <Self as CryptoBackend>::Error>,
ciphertext_with_tag: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<<Self as CryptoBackend>::Error>> {
match algorithm {
iana::Algorithm::A128GCM => {
Self::decrypt_aead::<Aes128Gcm>(key, ciphertext_with_tag, aad, iv)
}
iana::Algorithm::A192GCM => {
Self::decrypt_aead::<AesGcm<Aes192, U12>>(key, ciphertext_with_tag, aad, iv)
}
iana::Algorithm::A256GCM => {
Self::decrypt_aead::<Aes256Gcm>(key, ciphertext_with_tag, aad, iv)
}
a => Err(CoseCipherError::UnsupportedAlgorithm(Algorithm::Assigned(
a,
))),
}
}
}
45 changes: 45 additions & 0 deletions src/token/cose/crypto_impl/rustcrypto/encrypt/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2024 The NAMIB Project Developers.
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*
* SPDX-License-Identifier: MIT OR Apache-2.0
*/
use coset::iana;
use rand::{CryptoRng, RngCore};

use crate::error::CoseCipherError;
use crate::token::cose::crypto_impl::rustcrypto::RustCryptoContext;
use crate::token::cose::{CoseSymmetricKey, EncryptCryptoBackend};

#[cfg(feature = "rustcrypto-aes-gcm")]
mod aes_gcm;

impl<RNG: RngCore + CryptoRng> EncryptCryptoBackend for RustCryptoContext<RNG> {
#[cfg(feature = "rustcrypto-aes-gcm")]
fn encrypt_aes_gcm(
&mut self,
algorithm: iana::Algorithm,
key: CoseSymmetricKey<'_, Self::Error>,
plaintext: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
Self::encrypt_aes_gcm(algorithm, &key, plaintext, aad, iv)
}

#[cfg(feature = "rustcrypto-aes-gcm")]
fn decrypt_aes_gcm(
&mut self,
algorithm: iana::Algorithm,
key: CoseSymmetricKey<'_, Self::Error>,
ciphertext_with_tag: &[u8],
aad: &[u8],
iv: &[u8],
) -> Result<Vec<u8>, CoseCipherError<Self::Error>> {
Self::decrypt_aes_gcm(algorithm, &key, ciphertext_with_tag, aad, iv)
}
}
Loading

0 comments on commit 0f6a7c2

Please sign in to comment.