1#![deny(missing_docs)]
4
5use openssl::{
6 error::ErrorStack,
7 hash::MessageDigest,
8 pkey::{PKey, Private, Public},
9 sha::Sha256,
10 sign::{Signer, Verifier},
11};
12use std::fmt::Debug;
13
14#[derive(Clone)]
16pub struct OpenSslDigest {
17 digest: Sha256,
18}
19
20pub struct OpenSslSigner {
22 private_key: PKey<Private>,
23}
24
25pub struct OpenSslVerifier {
27 public_key: PKey<Public>,
28}
29
30#[derive(Clone, serde::Deserialize, serde::Serialize)]
34pub struct OpenSsl {
35 key_id: String,
36 #[serde(with = "openssl_private_key")]
37 private_key: PKey<Private>,
38}
39
40impl OpenSsl {
41 pub fn new(key_id: String, private_key: PKey<Private>) -> Self {
43 Self {
44 key_id,
45 private_key,
46 }
47 }
48}
49
50impl apub_core::digest::Digest for OpenSslDigest {
51 const NAME: &'static str = "SHA-256";
52
53 fn digest(&mut self, input: &[u8]) -> String {
54 self.digest.update(input);
55 let bytes = self.digest.clone().finish();
56
57 openssl::base64::encode_block(&bytes)
58 }
59
60 fn update(&mut self, input: &[u8]) {
61 self.digest.update(input);
62 }
63
64 fn verify(&mut self, encoded: &str) -> bool {
65 let bytes = self.digest.clone().finish();
66
67 openssl::base64::encode_block(&bytes) == encoded
68 }
69}
70
71impl apub_core::digest::DigestBuilder for OpenSslDigest {
72 fn build() -> Self {
73 OpenSslDigest {
74 digest: Sha256::new(),
75 }
76 }
77}
78
79impl apub_core::signature::Sign for OpenSslSigner {
80 type Error = ErrorStack;
81
82 fn sign(&self, signing_string: &str) -> Result<String, Self::Error> {
83 let mut signer = Signer::new(MessageDigest::sha256(), &self.private_key)?;
84 signer.update(signing_string.as_bytes())?;
85
86 Ok(openssl::base64::encode_block(&signer.sign_to_vec()?))
87 }
88}
89
90impl apub_core::signature::Verify for OpenSslVerifier {
91 type Error = ErrorStack;
92
93 fn verify(&self, signing_string: &str, signature: &str) -> Result<bool, Self::Error> {
94 let mut verifier = Verifier::new(MessageDigest::sha256(), &self.public_key)?;
95 verifier.update(signing_string.as_bytes())?;
96 verifier.verify(&openssl::base64::decode_block(signature)?)
97 }
98}
99
100impl apub_core::signature::VerifyBuilder for OpenSslVerifier {
101 fn build(public_key_pem: &str) -> Result<Self, Self::Error>
102 where
103 Self: Sized,
104 {
105 Ok(OpenSslVerifier {
106 public_key: PKey::public_key_from_pem(public_key_pem.as_bytes())?,
107 })
108 }
109}
110
111impl apub_core::digest::DigestFactory for OpenSsl {
112 type Digest = OpenSslDigest;
113}
114
115impl apub_core::signature::PrivateKey for OpenSsl {
116 type Signer = OpenSslSigner;
117
118 fn key_id(&self) -> String {
119 self.key_id.clone()
120 }
121
122 fn signer(&self) -> Self::Signer {
123 OpenSslSigner {
124 private_key: self.private_key.clone(),
125 }
126 }
127}
128
129impl apub_core::signature::PrivateKeyBuilder for OpenSsl {
130 type Error = ErrorStack;
131
132 fn build(key_id: String, private_key_pem: &str) -> Result<Self, Self::Error>
133 where
134 Self: Sized,
135 {
136 Ok(Self {
137 key_id,
138 private_key: PKey::private_key_from_pem(private_key_pem.as_bytes())?,
139 })
140 }
141
142 fn private_key_pem(&self) -> Result<String, Self::Error> {
143 self.private_key
144 .private_key_to_pem_pkcs8()
145 .map(|v| String::from_utf8_lossy(&v).to_string())
146 }
147}
148
149impl Debug for OpenSslDigest {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 f.debug_struct("OpenSslDigest")
152 .field("digest", &"Sha256")
153 .finish()
154 }
155}
156
157impl Debug for OpenSslSigner {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 f.debug_struct("OpenSslSigner")
160 .field("private_key", &"hidden")
161 .finish()
162 }
163}
164
165impl Debug for OpenSsl {
166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167 f.debug_struct("OpenSsl")
168 .field("key_id", &self.key_id)
169 .field("private_key", &"hidden")
170 .finish()
171 }
172}
173
174mod openssl_private_key {
175 use openssl::pkey::{PKey, Private};
176 use serde::{
177 de::{Deserialize, Deserializer},
178 ser::{Serialize, Serializer},
179 };
180
181 pub(super) fn serialize<S: Serializer>(
182 private_key: &PKey<Private>,
183 serializer: S,
184 ) -> Result<S::Ok, S::Error> {
185 use serde::ser::Error;
186
187 let der = private_key.private_key_to_der().map_err(S::Error::custom)?;
188 let der_string = openssl::base64::encode_block(&der);
189
190 String::serialize(&der_string, serializer)
191 }
192
193 pub(super) fn deserialize<'de, D: Deserializer<'de>>(
194 deserializer: D,
195 ) -> Result<PKey<Private>, D::Error> {
196 use serde::de::Error;
197
198 let der_string = String::deserialize(deserializer)?;
199 let der = openssl::base64::decode_block(&der_string).map_err(D::Error::custom)?;
200
201 PKey::<Private>::private_key_from_der(&der).map_err(D::Error::custom)
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::OpenSsl;
208 use apub_core::signature::{PrivateKey, Sign};
209 use openssl::{pkey::PKey, rsa::Rsa};
210
211 #[test]
212 fn round_trip() {
213 let private_key = PKey::from_rsa(Rsa::generate(1024).unwrap()).unwrap();
214 let crypto = OpenSsl::new("key-id".into(), private_key);
215 let signer = crypto.signer();
216
217 let first_sign = signer.sign("hello").unwrap();
218
219 let s = serde_json::to_string(&crypto).unwrap();
220 let crypto2: OpenSsl = serde_json::from_str(&s).unwrap();
221 let signer2 = crypto2.signer();
222
223 let second_sign = signer2.sign("hello").unwrap();
224
225 let s2 = serde_json::to_string(&crypto2).unwrap();
226
227 assert_eq!(s, s2);
228 assert_eq!(first_sign, second_sign);
229 }
230}