]>
Commit | Line | Data |
---|---|---|
aa230682 WB |
1 | use std::convert::{TryFrom, TryInto}; |
2 | ||
3 | use openssl::hash::{Hasher, MessageDigest}; | |
4 | use openssl::pkey::{HasPublic, Id, PKeyRef}; | |
5 | use serde::Serialize; | |
6 | ||
7 | use crate::b64u; | |
8 | use crate::Error; | |
9 | ||
10 | /// An RSA public key. | |
11 | #[derive(Clone, Debug, Serialize)] | |
12 | #[serde(deny_unknown_fields)] | |
13 | pub struct RsaPublicKey { | |
14 | #[serde(with = "b64u::bytes")] | |
15 | e: Vec<u8>, | |
16 | #[serde(with = "b64u::bytes")] | |
17 | n: Vec<u8>, | |
18 | } | |
19 | ||
20 | /// An EC public key. | |
21 | #[derive(Clone, Debug, Serialize)] | |
22 | #[serde(deny_unknown_fields)] | |
23 | pub struct EcPublicKey { | |
24 | crv: &'static str, | |
25 | #[serde(with = "b64u::bytes")] | |
26 | x: Vec<u8>, | |
27 | #[serde(with = "b64u::bytes")] | |
28 | y: Vec<u8>, | |
29 | } | |
30 | ||
31 | /// A public key. | |
32 | /// | |
33 | /// Internally tagged, so this already contains the 'kty' member. | |
34 | #[derive(Clone, Debug, Serialize)] | |
35 | #[serde(tag = "kty")] | |
36 | pub enum PublicKey { | |
37 | #[serde(rename = "RSA")] | |
38 | Rsa(RsaPublicKey), | |
39 | #[serde(rename = "EC")] | |
40 | Ec(EcPublicKey), | |
41 | } | |
42 | ||
43 | impl PublicKey { | |
44 | /// The thumbprint is the b64u encoded sha256sum of the *canonical* json representation. | |
45 | pub fn thumbprint(&self) -> Result<String, Error> { | |
46 | let mut hasher = Hasher::new(MessageDigest::sha256())?; | |
47 | crate::json::to_hash_canonical(&serde_json::to_value(self)?, &mut hasher)?; | |
48 | Ok(b64u::encode(hasher.finish()?.as_ref())) | |
49 | } | |
50 | } | |
51 | ||
52 | #[derive(Clone, Debug, Serialize)] | |
53 | pub struct Jwk { | |
54 | #[serde(rename = "use", skip_serializing_if = "Option::is_none")] | |
55 | pub usage: Option<String>, | |
56 | ||
57 | /// The key data is internally tagged, we can just flatten it. | |
58 | #[serde(flatten)] | |
59 | pub key: PublicKey, | |
60 | } | |
61 | ||
62 | impl<P: HasPublic> TryFrom<&PKeyRef<P>> for Jwk { | |
63 | type Error = Error; | |
64 | ||
65 | fn try_from(key: &PKeyRef<P>) -> Result<Self, Self::Error> { | |
66 | Ok(Self { | |
67 | key: key.try_into()?, | |
68 | usage: None, | |
69 | }) | |
70 | } | |
71 | } | |
72 | ||
73 | impl<P: HasPublic> TryFrom<&PKeyRef<P>> for PublicKey { | |
74 | type Error = Error; | |
75 | ||
76 | fn try_from(key: &PKeyRef<P>) -> Result<Self, Self::Error> { | |
77 | match key.id() { | |
78 | Id::RSA => Ok(PublicKey::Rsa(RsaPublicKey::try_from(&key.rsa()?)?)), | |
79 | Id::EC => Ok(PublicKey::Ec(EcPublicKey::try_from(&key.ec_key()?)?)), | |
80 | _ => Err(Error::UnsupportedKeyType), | |
81 | } | |
82 | } | |
83 | } | |
84 | ||
85 | impl<P: HasPublic> TryFrom<&openssl::rsa::Rsa<P>> for RsaPublicKey { | |
86 | type Error = Error; | |
87 | ||
88 | fn try_from(key: &openssl::rsa::Rsa<P>) -> Result<Self, Self::Error> { | |
89 | Ok(RsaPublicKey { | |
90 | e: key.e().to_vec(), | |
91 | n: key.n().to_vec(), | |
92 | }) | |
93 | } | |
94 | } | |
95 | ||
96 | impl<P: HasPublic> TryFrom<&openssl::ec::EcKey<P>> for EcPublicKey { | |
97 | type Error = Error; | |
98 | ||
99 | fn try_from(key: &openssl::ec::EcKey<P>) -> Result<Self, Self::Error> { | |
100 | let group = key.group(); | |
101 | ||
102 | if group.curve_name() != Some(openssl::nid::Nid::X9_62_PRIME256V1) { | |
103 | return Err(Error::UnsupportedGroup); | |
104 | } | |
105 | ||
106 | let mut ctx = openssl::bn::BigNumContext::new()?; | |
107 | let mut x = openssl::bn::BigNum::new()?; | |
108 | let mut y = openssl::bn::BigNum::new()?; | |
e499b084 WB |
109 | key.public_key() |
110 | .affine_coordinates(group, &mut x, &mut y, &mut ctx)?; | |
aa230682 WB |
111 | |
112 | Ok(EcPublicKey { | |
113 | crv: "P-256", | |
114 | x: x.to_vec(), | |
115 | y: y.to_vec(), | |
116 | }) | |
117 | } | |
118 | } | |
e499b084 WB |
119 | |
120 | #[test] | |
121 | fn test_key_conversion() -> Result<(), Error> { | |
122 | let key = openssl::ec::EcKey::generate( | |
123 | openssl::ec::EcGroup::from_curve_name(openssl::nid::Nid::X9_62_PRIME256V1)?.as_ref(), | |
124 | )?; | |
125 | ||
126 | let _ = EcPublicKey::try_from(&key).expect("failed to jsonify ec key"); | |
127 | ||
128 | Ok(()) | |
129 | } |