Skip to main content

uselesskey_ring/
lib.rs

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