Skip to main content

uselesskey_aws_lc_rs/
lib.rs

1#![forbid(unsafe_code)]
2
3//! Integration between uselesskey test fixtures and `aws-lc-rs`.
4//!
5//! This crate provides extension traits that convert uselesskey fixtures into
6//! `aws-lc-rs` native signing key types.
7//!
8//! # Features
9//!
10//! - `native` - Enable `aws-lc-rs` dependency (requires NASM on Windows). Disable for wasm-safe builds.
11//! - `rsa` - RSA keypairs -> `aws_lc_rs::rsa::KeyPair`
12//! - `ecdsa` - ECDSA keypairs -> `aws_lc_rs::signature::EcdsaKeyPair`
13//! - `ed25519` - Ed25519 keypairs -> `aws_lc_rs::signature::Ed25519KeyPair`
14//! - `all` - All key types above
15//!
16//! When the `native` feature is disabled, this crate compiles as a no-op
17//! with no traits or implementations available.
18//!
19//! # Example: RSA sign and verify
20//!
21#![cfg_attr(
22    all(feature = "native", any(not(windows), has_nasm), feature = "rsa"),
23    doc = "```"
24)]
25#![cfg_attr(
26    not(all(feature = "native", any(not(windows), has_nasm), feature = "rsa")),
27    doc = "```ignore"
28)]
29//! use uselesskey_core::Factory;
30//! use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
31//! use uselesskey_aws_lc_rs::AwsLcRsRsaKeyPairExt;
32//! use aws_lc_rs::signature;
33//!
34//! let fx = Factory::random();
35//! let keypair = fx.rsa("test", RsaSpec::rs256());
36//! let ring_kp = keypair.rsa_key_pair_aws_lc_rs();
37//!
38//! let rng = aws_lc_rs::rand::SystemRandom::new();
39//! let msg = b"hello world";
40//! let mut sig = vec![0u8; ring_kp.public_modulus_len()];
41//! ring_kp.sign(&signature::RSA_PKCS1_SHA256, &rng, msg, &mut sig).unwrap();
42//! ```
43
44// =========================================================================
45// RSA
46// =========================================================================
47
48/// Extension trait to convert uselesskey RSA fixtures into `aws_lc_rs::rsa::KeyPair`.
49#[cfg(all(feature = "native", any(not(windows), has_nasm), feature = "rsa"))]
50pub trait AwsLcRsRsaKeyPairExt {
51    /// Convert the RSA private key to an `aws_lc_rs::rsa::KeyPair`.
52    fn rsa_key_pair_aws_lc_rs(&self) -> aws_lc_rs::rsa::KeyPair;
53}
54
55#[cfg(all(feature = "native", any(not(windows), has_nasm), feature = "rsa"))]
56impl AwsLcRsRsaKeyPairExt for uselesskey_rsa::RsaKeyPair {
57    fn rsa_key_pair_aws_lc_rs(&self) -> aws_lc_rs::rsa::KeyPair {
58        aws_lc_rs::rsa::KeyPair::from_pkcs8(self.private_key_pkcs8_der())
59            .expect("valid RSA PKCS#8 DER")
60    }
61}
62
63// =========================================================================
64// ECDSA
65// =========================================================================
66
67#[cfg(all(feature = "native", any(not(windows), has_nasm), feature = "ecdsa"))]
68use aws_lc_rs::signature::{
69    ECDSA_P256_SHA256_ASN1_SIGNING, ECDSA_P384_SHA384_ASN1_SIGNING,
70    EcdsaKeyPair as AwsLcRsEcdsaKeyPair, EcdsaSigningAlgorithm,
71};
72
73/// Extension trait to convert uselesskey ECDSA fixtures into `aws_lc_rs::signature::EcdsaKeyPair`.
74#[cfg(all(feature = "native", any(not(windows), has_nasm), feature = "ecdsa"))]
75pub trait AwsLcRsEcdsaKeyPairExt {
76    /// Convert the ECDSA private key to an `aws_lc_rs::signature::EcdsaKeyPair`.
77    ///
78    /// The correct signing algorithm is chosen based on the curve (P-256 or P-384).
79    fn ecdsa_key_pair_aws_lc_rs(&self) -> AwsLcRsEcdsaKeyPair;
80}
81
82#[cfg(all(feature = "native", any(not(windows), has_nasm), feature = "ecdsa"))]
83impl AwsLcRsEcdsaKeyPairExt for uselesskey_ecdsa::EcdsaKeyPair {
84    fn ecdsa_key_pair_aws_lc_rs(&self) -> AwsLcRsEcdsaKeyPair {
85        let alg: &'static EcdsaSigningAlgorithm = match self.spec() {
86            uselesskey_ecdsa::EcdsaSpec::Es256 => &ECDSA_P256_SHA256_ASN1_SIGNING,
87            uselesskey_ecdsa::EcdsaSpec::Es384 => &ECDSA_P384_SHA384_ASN1_SIGNING,
88        };
89        AwsLcRsEcdsaKeyPair::from_pkcs8(alg, self.private_key_pkcs8_der())
90            .expect("valid ECDSA PKCS#8 DER")
91    }
92}
93
94// =========================================================================
95// Ed25519
96// =========================================================================
97
98/// Extension trait to convert uselesskey Ed25519 fixtures into `aws_lc_rs::signature::Ed25519KeyPair`.
99#[cfg(all(feature = "native", any(not(windows), has_nasm), feature = "ed25519"))]
100pub trait AwsLcRsEd25519KeyPairExt {
101    /// Convert the Ed25519 private key to an `aws_lc_rs::signature::Ed25519KeyPair`.
102    fn ed25519_key_pair_aws_lc_rs(&self) -> aws_lc_rs::signature::Ed25519KeyPair;
103}
104
105#[cfg(all(feature = "native", any(not(windows), has_nasm), feature = "ed25519"))]
106impl AwsLcRsEd25519KeyPairExt for uselesskey_ed25519::Ed25519KeyPair {
107    fn ed25519_key_pair_aws_lc_rs(&self) -> aws_lc_rs::signature::Ed25519KeyPair {
108        aws_lc_rs::signature::Ed25519KeyPair::from_pkcs8(self.private_key_pkcs8_der())
109            .expect("valid Ed25519 PKCS#8 DER")
110    }
111}
112
113// =========================================================================
114// Tests
115// =========================================================================
116
117#[cfg(test)]
118mod tests {
119    use std::sync::OnceLock;
120    use uselesskey_core::{Factory, Seed};
121
122    #[allow(dead_code)]
123    static FX: OnceLock<Factory> = OnceLock::new();
124
125    #[allow(dead_code)]
126    fn fx() -> Factory {
127        FX.get_or_init(|| {
128            let seed = Seed::from_env_value("uselesskey-aws-lc-rs-inline-test-seed-v1")
129                .expect("test seed should always parse");
130            Factory::deterministic(seed)
131        })
132        .clone()
133    }
134
135    #[cfg(all(feature = "native", any(not(windows), has_nasm), feature = "rsa"))]
136    mod rsa_tests {
137        use crate::AwsLcRsRsaKeyPairExt;
138        use aws_lc_rs::signature::{self, KeyPair};
139        use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
140
141        #[test]
142        fn test_rsa_sign_verify() {
143            let fx = super::fx();
144            let rsa = fx.rsa("test", RsaSpec::rs256());
145            let kp = rsa.rsa_key_pair_aws_lc_rs();
146
147            let msg = b"test message";
148            let rng = aws_lc_rs::rand::SystemRandom::new();
149            let mut sig = vec![0u8; kp.public_modulus_len()];
150            kp.sign(&signature::RSA_PKCS1_SHA256, &rng, msg, &mut sig)
151                .expect("sign");
152
153            let public_key = kp.public_key();
154            let public_key = signature::UnparsedPublicKey::new(
155                &signature::RSA_PKCS1_2048_8192_SHA256,
156                public_key.as_ref(),
157            );
158            public_key.verify(msg, &sig).expect("verify");
159        }
160    }
161
162    #[cfg(all(feature = "native", any(not(windows), has_nasm), feature = "ecdsa"))]
163    mod ecdsa_tests {
164        use crate::AwsLcRsEcdsaKeyPairExt;
165        use aws_lc_rs::signature::{self, KeyPair};
166        use uselesskey_core::Factory;
167        use uselesskey_ecdsa::{EcdsaFactoryExt, EcdsaSpec};
168
169        #[test]
170        fn test_ecdsa_p256_sign_verify() {
171            let fx = Factory::random();
172            let ecdsa = fx.ecdsa("test", EcdsaSpec::es256());
173            let kp = ecdsa.ecdsa_key_pair_aws_lc_rs();
174
175            let msg = b"test message";
176            let rng = aws_lc_rs::rand::SystemRandom::new();
177            let sig = kp.sign(&rng, msg).expect("sign");
178
179            let public_key_bytes = kp.public_key().as_ref();
180            let public_key = signature::UnparsedPublicKey::new(
181                &signature::ECDSA_P256_SHA256_ASN1,
182                public_key_bytes,
183            );
184            public_key.verify(msg, sig.as_ref()).expect("verify");
185        }
186
187        #[test]
188        fn test_ecdsa_p384_sign_verify() {
189            let fx = Factory::random();
190            let ecdsa = fx.ecdsa("test", EcdsaSpec::es384());
191            let kp = ecdsa.ecdsa_key_pair_aws_lc_rs();
192
193            let msg = b"test message";
194            let rng = aws_lc_rs::rand::SystemRandom::new();
195            let sig = kp.sign(&rng, msg).expect("sign");
196
197            let public_key_bytes = kp.public_key().as_ref();
198            let public_key = signature::UnparsedPublicKey::new(
199                &signature::ECDSA_P384_SHA384_ASN1,
200                public_key_bytes,
201            );
202            public_key.verify(msg, sig.as_ref()).expect("verify");
203        }
204    }
205
206    #[cfg(all(feature = "native", any(not(windows), has_nasm), feature = "ed25519"))]
207    mod ed25519_tests {
208        use crate::AwsLcRsEd25519KeyPairExt;
209        use aws_lc_rs::signature::{self, KeyPair};
210        use uselesskey_core::Factory;
211        use uselesskey_ed25519::{Ed25519FactoryExt, Ed25519Spec};
212
213        #[test]
214        fn test_ed25519_sign_verify() {
215            let fx = Factory::random();
216            let ed = fx.ed25519("test", Ed25519Spec::new());
217            let kp = ed.ed25519_key_pair_aws_lc_rs();
218
219            let msg = b"test message";
220            let sig = kp.sign(msg);
221
222            let public_key_bytes = kp.public_key().as_ref();
223            let public_key =
224                signature::UnparsedPublicKey::new(&signature::ED25519, public_key_bytes);
225            public_key.verify(msg, sig.as_ref()).expect("verify");
226        }
227    }
228}