1use const_oid::ObjectIdentifier;
4use der::{
5 Decode,
6 asn1::{SequenceOf, UintRef},
7};
8use digest::{
9 Digest,
10 array::{Array, ArraySize},
11};
12use ecdsa::{
13 EcdsaCurve, EncodedPoint, Signature, SignatureSize, SigningKey as EcSigningKey,
14 VerifyingKey as EcVerifyingKey,
15};
16use elliptic_curve::{
17 AffinePoint, CurveArithmetic, FieldBytes, FieldBytesSize,
18 point::AffineCoordinates,
19 sec1::{FromEncodedPoint, ToEncodedPoint},
20};
21use pkcs8::{AssociatedOid, DecodePrivateKey};
22use sec1::{EcPrivateKey, point::ModulusSize};
23use sha2::{Sha256, Sha384, Sha512};
24use signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner};
25
26pub use const_oid::db::rfc5912::{SECP_256_R_1, SECP_384_R_1, SECP_521_R_1};
27pub use p256::ecdsa::{SigningKey as P256SigningKey, VerifyingKey as P256VerifyingKey};
28pub use p384::ecdsa::{SigningKey as P384SigningKey, VerifyingKey as P384VerifyingKey};
29pub use p521::ecdsa::{SigningKey as P521SigningKey, VerifyingKey as P521VerifyingKey};
30
31pub trait VerifyingKey {
33 fn verifies_sha256(&self, signature: &[u8], message: &[u8]) -> bool;
35 fn verifies_sha384(&self, signature: &[u8], message: &[u8]) -> bool;
37 fn verifies_sha512(&self, signature: &[u8], message: &[u8]) -> bool;
39
40 fn x(&self) -> Vec<u8>;
42
43 fn y(&self) -> Vec<u8>;
45
46 fn curve_oid(&self) -> ObjectIdentifier;
48
49 fn from_coordinates(x: &[u8], y: &[u8]) -> Option<Self>
51 where
52 Self: Sized;
53
54 fn from_encoded_coordinates(coordinates: &[u8]) -> Option<Self>
56 where
57 Self: Sized;
58
59 fn from_spki_der(der: &[u8]) -> Option<Self>
61 where
62 Self: Sized;
63}
64
65pub trait SigningKey {
67 fn sign_sha256(&self, message: &[u8]) -> Vec<u8>;
69 fn sign_sha384(&self, message: &[u8]) -> Vec<u8>;
71 fn sign_sha512(&self, message: &[u8]) -> Vec<u8>;
73
74 fn verifying_key(&self) -> Box<dyn VerifyingKey>;
76
77 fn from_pkcs8_der(der: &[u8]) -> Option<Self>
79 where
80 Self: Sized;
81
82 fn from_sec1_der(der: &[u8]) -> Option<Self>
84 where
85 Self: Sized;
86}
87
88impl<C> VerifyingKey for EcVerifyingKey<C>
89where
90 C: EcdsaCurve + CurveArithmetic + AssociatedOid,
91 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
92 FieldBytesSize<C>: ModulusSize,
93 SignatureSize<C>: ArraySize,
94 EcSigningKey<C>: RandomizedPrehashSigner<Signature<C>> + DecodePrivateKey,
95 Self: pkcs8::DecodePublicKey,
96{
97 fn verifies_sha256(&self, signature: &[u8], message: &[u8]) -> bool {
99 let Some(signature) = get_signature(signature) else {
100 return false;
101 };
102
103 let hash = Sha256::digest(message);
104 self.verify_prehash(&hash, &signature).is_ok()
105 }
106
107 fn verifies_sha384(&self, signature: &[u8], message: &[u8]) -> bool {
109 let Some(signature) = get_signature(signature) else {
110 return false;
111 };
112 let hash = Sha384::digest(message);
113 self.verify_prehash(&hash, &signature).is_ok()
114 }
115
116 fn verifies_sha512(&self, signature: &[u8], message: &[u8]) -> bool {
118 let Some(signature) = get_signature(signature) else {
119 return false;
120 };
121 let hash = Sha512::digest(message);
122 self.verify_prehash(&hash, &signature).is_ok()
123 }
124
125 fn x(&self) -> Vec<u8> {
126 self.as_affine().x().to_vec()
127 }
128
129 fn y(&self) -> Vec<u8> {
130 self.as_affine().y().to_vec()
131 }
132
133 fn from_coordinates(x: &[u8], y: &[u8]) -> Option<Self>
134 where
135 Self: Sized,
136 {
137 let x = Array::try_from(x).ok()?;
138 let y = Array::try_from(y).ok()?;
139 let point = EncodedPoint::<C>::from_affine_coordinates(&x, &y, false);
140 let point = AffinePoint::<C>::from_encoded_point(&point).into_option()?;
141 Self::from_affine(point).ok()
142 }
143
144 fn from_encoded_coordinates(coordinates: &[u8]) -> Option<Self>
145 where
146 Self: Sized,
147 {
148 let point = EncodedPoint::<C>::from_bytes(coordinates).ok()?;
149 let point = AffinePoint::<C>::from_encoded_point(&point).into_option()?;
150 Self::from_affine(point).ok()
151 }
152
153 fn from_spki_der(der: &[u8]) -> Option<Self>
154 where
155 Self: Sized,
156 {
157 <Self as pkcs8::DecodePublicKey>::from_public_key_der(der).ok()
158 }
159
160 fn curve_oid(&self) -> ObjectIdentifier {
161 <C as AssociatedOid>::OID
162 }
163}
164
165impl<C> SigningKey for EcSigningKey<C>
166where
167 C: EcdsaCurve + CurveArithmetic + AssociatedOid,
168 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
169 FieldBytesSize<C>: ModulusSize,
170 SignatureSize<C>: ArraySize,
171 Self: RandomizedPrehashSigner<Signature<C>> + DecodePrivateKey,
172 EcVerifyingKey<C>: pkcs8::DecodePublicKey,
173{
174 fn sign_sha256(&self, message: &[u8]) -> Vec<u8> {
180 let hash = Sha256::digest(message);
181 self.sign_prehash_with_rng(&mut rand::rng(), &hash)
182 .expect("the digest algorithm should produce a hash that is valid for this curve")
183 .to_vec()
184 }
185
186 fn sign_sha384(&self, message: &[u8]) -> Vec<u8> {
192 let hash = Sha384::digest(message);
193 self.sign_prehash_with_rng(&mut rand::rng(), &hash)
194 .expect("the digest algorithm should produce a hash that is valid for this curve")
195 .to_vec()
196 }
197
198 fn sign_sha512(&self, message: &[u8]) -> Vec<u8> {
204 let hash = Sha512::digest(message);
205 self.sign_prehash_with_rng(&mut rand::rng(), &hash)
206 .expect("the digest algorithm should produce a hash that is valid for this curve")
207 .to_vec()
208 }
209
210 fn from_pkcs8_der(der: &[u8]) -> Option<Self>
211 where
212 Self: Sized,
213 {
214 <Self as DecodePrivateKey>::from_pkcs8_der(der).ok()
215 }
216
217 fn from_sec1_der(der: &[u8]) -> Option<Self>
218 where
219 Self: Sized,
220 {
221 let key = EcPrivateKey::from_der(der).ok()?;
222 Self::from_slice(key.private_key).ok()
223 }
224
225 fn verifying_key(&self) -> Box<dyn VerifyingKey> {
226 Box::new(*self.verifying_key())
227 }
228}
229
230fn get_signature<C>(signature: &[u8]) -> Option<Signature<C>>
232where
233 C: EcdsaCurve + CurveArithmetic,
234 SignatureSize<C>: ArraySize,
235{
236 if let Ok(signature) = Signature::from_slice(signature) {
237 Some(signature)
238 } else if let Ok(sequence) = SequenceOf::<UintRef, 2>::from_der(signature) {
239 let r = sequence.get(0)?;
248 let s = sequence.get(1)?;
249
250 let mut r_array = Array::<u8, FieldBytesSize<C>>::default();
252 if r.as_bytes().len() > r_array.len() {
253 return None;
254 }
255 let offset = r_array.len().saturating_sub(r.as_bytes().len());
256 #[allow(clippy::indexing_slicing, reason = "offest is always in bounds")]
257 r_array[offset..].copy_from_slice(r.as_bytes());
258
259 let mut s_array = Array::<u8, FieldBytesSize<C>>::default();
260 if s.as_bytes().len() > s_array.len() {
261 return None;
262 }
263 let offset = r_array.len().saturating_sub(s.as_bytes().len());
264 #[allow(clippy::indexing_slicing, reason = "offest is always in bounds")]
265 s_array[offset..].copy_from_slice(s.as_bytes());
266
267 let r = FieldBytes::<C>::try_from(r_array.as_slice()).ok()?;
268 let s = FieldBytes::<C>::try_from(s_array.as_slice()).ok()?;
269
270 Signature::<C>::from_scalars(r, s).ok()
271 } else {
272 None
273 }
274}