1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
use crate::{types::Algorithm, Error, Result};
use serde::{Deserialize, Serialize};
use base64ct::Encoding;
/// Cryptographic keys for JWT operations
#[derive(Debug, Clone)]
pub enum Key {
/// HMAC shared secret key
Hs(Vec<u8>),
/// RSA public key in PEM format
RsaPublicPem(Vec<u8>),
/// RSA private key in PEM format
RsaPrivatePem(Vec<u8>),
/// ECDSA public key in PEM format
EcPublicPem(Vec<u8>),
/// ECDSA private key in PEM format
EcPrivatePem(Vec<u8>),
/// EdDSA public key in PEM format
EdPublicPem(Vec<u8>),
/// EdDSA private key in PEM format
EdPrivatePem(Vec<u8>),
}
impl Key {
/// Create an HMAC key from a shared secret
pub fn hs(secret: impl AsRef<[u8]>) -> Self { Key::Hs(secret.as_ref().to_vec()) }
/// Create an RSA public key from PEM data
pub fn rsa_public_pem(pem: impl AsRef<[u8]>) -> Self { Key::RsaPublicPem(pem.as_ref().to_vec()) }
/// Create an RSA private key from PEM data
pub fn rsa_private_pem(pem: impl AsRef<[u8]>) -> Self { Key::RsaPrivatePem(pem.as_ref().to_vec()) }
/// Create an ECDSA public key from PEM data
pub fn ec_public_pem(pem: impl AsRef<[u8]>) -> Self { Key::EcPublicPem(pem.as_ref().to_vec()) }
/// Create an ECDSA private key from PEM data
pub fn ec_private_pem(pem: impl AsRef<[u8]>) -> Self { Key::EcPrivatePem(pem.as_ref().to_vec()) }
/// Create an EdDSA public key from PEM data
pub fn ed_public_pem(pem: impl AsRef<[u8]>) -> Self { Key::EdPublicPem(pem.as_ref().to_vec()) }
/// Create an EdDSA private key from PEM data
pub fn ed_private_pem(pem: impl AsRef<[u8]>) -> Self { Key::EdPrivatePem(pem.as_ref().to_vec()) }
}
/// JSON Web Key (JWK) representation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Jwk {
/// Key type (e.g., "RSA", "EC", "OKP", "oct")
pub kty: String,
/// Key ID
#[serde(default)]
pub kid: Option<String>,
/// Algorithm
#[serde(default)]
pub alg: Option<String>,
/// Key use
#[serde(default, rename = "use")]
pub use_: Option<String>,
/// RSA modulus
#[serde(default)] pub n: Option<String>,
/// RSA exponent
#[serde(default)] pub e: Option<String>,
/// Private exponent (RSA, EC, OKP)
#[serde(default)] pub d: Option<String>,
/// RSA first prime factor
#[serde(default)] pub p: Option<String>,
/// RSA second prime factor
#[serde(default)] pub q: Option<String>,
/// RSA first factor CRT exponent
#[serde(default)] pub dp: Option<String>,
/// RSA second factor CRT exponent
#[serde(default)] pub dq: Option<String>,
/// RSA first CRT coefficient
#[serde(default)] pub qi: Option<String>,
/// Curve name (EC, OKP)
#[serde(default)] pub crv: Option<String>,
/// X coordinate (EC, OKP)
#[serde(default)] pub x: Option<String>,
/// Y coordinate (EC)
#[serde(default)] pub y: Option<String>,
/// Octet key value
#[serde(default)] pub k: Option<String>,
}
/// JSON Web Key Set (JWKS) containing multiple JWKs
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Jwks {
/// List of JSON Web Keys
pub keys: Vec<Jwk>
}
impl Jwks {
/// Parse a JWKS from a JSON string
///
/// # Arguments
///
/// * `s` - JSON string containing the JWKS
///
/// # Returns
///
/// Returns a `Result` containing the parsed JWKS or an error
pub fn from_str(s: &str) -> Result<Self> {
serde_json::from_str(s).map_err(|e| Error::Json(e.to_string()))
}
/// Select a key from the JWKS by kid and algorithm
///
/// # Arguments
///
/// * `kid` - Key ID to search for
/// * `alg` - Algorithm to use for key conversion
///
/// # Returns
///
/// Returns a `Result` containing the selected key or an error
///
/// # Errors
///
/// - `Error::KidNotFound` if no key with the given kid is found
/// - `Error::Key` if key conversion fails
pub fn select_for(&self, kid: &str, alg: crate::types::Algorithm) -> Result<Key> {
let jwk = self.keys.iter().find(|k| k.kid.as_deref() == Some(kid)).ok_or(Error::KidNotFound)?;
jwk.to_key_for(alg)
}
}
impl Jwk {
/// Convert this JWK to a Key for the given algorithm
///
/// # Arguments
///
/// * `alg` - The algorithm to use for key conversion
///
/// # Returns
///
/// Returns a `Result` containing the converted key or an error
///
/// # Errors
///
/// - `Error::Key` if the JWK is invalid or conversion fails
///
/// # Note
///
/// Currently only supports octet keys (HMAC). RSA, EC, and EdDSA JWK to PEM
/// conversion is not implemented and will return an error.
pub fn to_key_for(&self, alg: Algorithm) -> Result<Key> {
match self.kty.as_str() {
"oct" => {
let k = self.k.as_ref().ok_or_else(|| Error::Key("oct missing k".into()))?;
let bytes = base64ct::Base64UrlUnpadded::decode_vec(k).map_err(|e| Error::Key(e.to_string()))?;
Ok(Key::Hs(bytes))
}
"RSA" => match alg {
Algorithm::RS256 | Algorithm::RS384 | Algorithm::RS512 => {
Err(Error::Key("RSA JWK to PEM conversion not implemented".into()))
}
_ => Err(Error::Key("RSA JWK used with non-RS alg".into())),
}
"EC" => match (self.crv.as_deref(), alg) {
(Some("P-256"), Algorithm::ES256) |
(Some("P-384"), Algorithm::ES384) |
(Some("P-521"), Algorithm::ES512) => {
Err(Error::Key("EC JWK to PEM conversion not implemented".into()))
}
_ => Err(Error::Key("EC JWK and alg mismatch or unsupported curve".into())),
}
"OKP" => match (self.crv.as_deref(), alg) {
(Some("Ed25519"), Algorithm::EdDSA) => {
Err(Error::Key("EdDSA JWK to PEM conversion not implemented".into()))
}
_ => Err(Error::Key("OKP JWK not Ed25519".into())),
}
_ => Err(Error::Key("unsupported kty".into())),
}
}
}
/// Key source selection strategy
#[derive(Debug, Clone, Copy)]
pub enum KeySource {
/// Automatically select the appropriate key source
Auto
}