1use crate::aws_lc::{
5 ECDSA_SIG_new, ECDSA_SIG_set0, ECDSA_SIG_to_bytes, NID_X9_62_prime256v1, NID_secp256k1,
6 NID_secp384r1, NID_secp521r1, BIGNUM, ECDSA_SIG, EVP_PKEY,
7};
8
9use crate::digest::Digest;
10use crate::ec::compressed_public_key_size_bytes;
11use crate::ec::encoding::parse_ec_public_key;
12use crate::ec::encoding::sec1::marshal_sec1_public_point;
13use crate::encoding::{
14 AsBigEndian, AsDer, EcPublicKeyCompressedBin, EcPublicKeyUncompressedBin, PublicKeyX509Der,
15};
16use crate::error::Unspecified;
17use crate::evp_pkey::No_EVP_PKEY_CTX_consumer;
18use crate::ptr::{DetachableLcPtr, LcPtr};
19use crate::signature::{ParsedPublicKey, ParsedVerificationAlgorithm, VerificationAlgorithm};
20use crate::{digest, sealed};
21use core::fmt;
22use core::fmt::{Debug, Formatter};
23use std::mem::MaybeUninit;
24use std::ops::Deref;
25use std::ptr::null_mut;
26#[cfg(feature = "ring-sig-verify")]
27use untrusted::Input;
28
29#[derive(Debug, Eq, PartialEq)]
31pub struct EcdsaVerificationAlgorithm {
32 pub(crate) id: &'static AlgorithmID,
33 pub(crate) digest: &'static digest::Algorithm,
34 pub(crate) sig_format: EcdsaSignatureFormat,
35}
36
37#[derive(Debug, Eq, PartialEq)]
39pub struct EcdsaSigningAlgorithm(pub(crate) &'static EcdsaVerificationAlgorithm);
40
41impl Deref for EcdsaSigningAlgorithm {
42 type Target = EcdsaVerificationAlgorithm;
43 #[inline]
44 fn deref(&self) -> &Self::Target {
45 self.0
46 }
47}
48
49impl sealed::Sealed for EcdsaVerificationAlgorithm {}
50impl sealed::Sealed for EcdsaSigningAlgorithm {}
51
52#[derive(Debug, Eq, PartialEq)]
53pub(crate) enum EcdsaSignatureFormat {
54 ASN1,
55 Fixed,
56}
57
58#[derive(Debug, Eq, PartialEq)]
59#[allow(non_camel_case_types)]
60pub(crate) enum AlgorithmID {
61 ECDSA_P256,
62 ECDSA_P384,
63 ECDSA_P521,
64 ECDSA_P256K1,
65}
66
67impl AlgorithmID {
68 #[inline]
69 pub(crate) fn nid(&'static self) -> i32 {
70 match self {
71 AlgorithmID::ECDSA_P256 => NID_X9_62_prime256v1,
72 AlgorithmID::ECDSA_P384 => NID_secp384r1,
73 AlgorithmID::ECDSA_P521 => NID_secp521r1,
74 AlgorithmID::ECDSA_P256K1 => NID_secp256k1,
75 }
76 }
77 pub(crate) fn private_key_size(&self) -> usize {
78 match self {
79 AlgorithmID::ECDSA_P256 | AlgorithmID::ECDSA_P256K1 => 32,
80 AlgorithmID::ECDSA_P384 => 48,
81 AlgorithmID::ECDSA_P521 => 66,
82 }
83 }
84 #[inline]
86 #[allow(dead_code)]
87 const fn compressed_pub_key_len(&self) -> usize {
88 match self {
89 AlgorithmID::ECDSA_P256 | AlgorithmID::ECDSA_P256K1 => {
90 compressed_public_key_size_bytes(256)
91 }
92 AlgorithmID::ECDSA_P384 => compressed_public_key_size_bytes(384),
93 AlgorithmID::ECDSA_P521 => compressed_public_key_size_bytes(521),
94 }
95 }
96}
97
98#[derive(Clone)]
100pub struct PublicKey {
101 #[allow(dead_code)]
102 algorithm: &'static EcdsaSigningAlgorithm,
103 evp_pkey: LcPtr<EVP_PKEY>,
104 octets: Box<[u8]>,
105}
106
107pub(crate) fn public_key_from_evp_pkey(
108 evp_pkey: &LcPtr<EVP_PKEY>,
109 algorithm: &'static EcdsaSigningAlgorithm,
110) -> Result<PublicKey, Unspecified> {
111 let pub_key_bytes = marshal_sec1_public_point(evp_pkey, false)?;
112
113 Ok(PublicKey {
114 evp_pkey: evp_pkey.clone(),
115 algorithm,
116 octets: pub_key_bytes.into_boxed_slice(),
117 })
118}
119
120impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
121 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, Unspecified> {
125 let der = self.evp_pkey.as_const().marshal_rfc5280_public_key()?;
126 Ok(PublicKeyX509Der::new(der))
127 }
128}
129
130impl AsBigEndian<EcPublicKeyCompressedBin<'static>> for PublicKey {
131 fn as_be_bytes(&self) -> Result<EcPublicKeyCompressedBin<'static>, crate::error::Unspecified> {
135 let pub_point = marshal_sec1_public_point(&self.evp_pkey, true)?;
136 Ok(EcPublicKeyCompressedBin::new(pub_point))
137 }
138}
139
140impl AsBigEndian<EcPublicKeyUncompressedBin<'static>> for PublicKey {
141 fn as_be_bytes(
145 &self,
146 ) -> Result<EcPublicKeyUncompressedBin<'static>, crate::error::Unspecified> {
147 let mut uncompressed_bytes = vec![0u8; self.octets.len()];
148 uncompressed_bytes.copy_from_slice(&self.octets);
149 Ok(EcPublicKeyUncompressedBin::new(uncompressed_bytes))
150 }
151}
152
153impl Debug for PublicKey {
154 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
155 f.write_str(&format!(
156 "EcdsaPublicKey(\"{}\")",
157 crate::hex::encode(self.octets.as_ref())
158 ))
159 }
160}
161
162impl AsRef<[u8]> for PublicKey {
163 #[inline]
164 fn as_ref(&self) -> &[u8] {
168 self.octets.as_ref()
169 }
170}
171
172unsafe impl Send for PublicKey {}
173unsafe impl Sync for PublicKey {}
174
175impl VerificationAlgorithm for EcdsaVerificationAlgorithm {
176 #[inline]
177 #[cfg(feature = "ring-sig-verify")]
178 fn verify(
179 &self,
180 public_key: Input<'_>,
181 msg: Input<'_>,
182 signature: Input<'_>,
183 ) -> Result<(), Unspecified> {
184 self.verify_sig(
185 public_key.as_slice_less_safe(),
186 msg.as_slice_less_safe(),
187 signature.as_slice_less_safe(),
188 )
189 }
190
191 fn verify_sig(
192 &self,
193 public_key: &[u8],
194 msg: &[u8],
195 signature: &[u8],
196 ) -> Result<(), Unspecified> {
197 let public_key = parse_ec_public_key(public_key, self.id.nid())?;
198 self.verify_ecdsa(msg, signature, &public_key)
199 }
200
201 fn verify_digest_sig(
202 &self,
203 public_key: &[u8],
204 digest: &digest::Digest,
205 signature: &[u8],
206 ) -> Result<(), Unspecified> {
207 let public_key = parse_ec_public_key(public_key, self.id.nid())?;
208
209 self.verify_digest_ecdsa(digest, signature, &public_key)
210 }
211}
212
213impl EcdsaVerificationAlgorithm {
214 fn verify_ecdsa(
215 &self,
216 msg: &[u8],
217 signature: &[u8],
218 public_key: &LcPtr<EVP_PKEY>,
219 ) -> Result<(), Unspecified> {
220 match self.sig_format {
221 EcdsaSignatureFormat::ASN1 => {
222 verify_asn1_signature(self.digest, public_key, msg, signature)
223 }
224 EcdsaSignatureFormat::Fixed => {
225 let (out_bytes, out_bytes_len) = convert_fixed_signature(self.id, signature)?;
226 verify_asn1_signature(self.digest, public_key, msg, unsafe {
227 out_bytes.as_slice(out_bytes_len)
228 })
229 }
230 }
231 }
232
233 fn verify_digest_ecdsa(
234 &self,
235 digest: &Digest,
236 signature: &[u8],
237 public_key: &LcPtr<EVP_PKEY>,
238 ) -> Result<(), Unspecified> {
239 if self.digest != digest.algorithm() {
240 return Err(Unspecified);
241 }
242 match self.sig_format {
243 EcdsaSignatureFormat::ASN1 => {
244 verify_asn1_digest_signature(digest, public_key, signature)
245 }
246 EcdsaSignatureFormat::Fixed => {
247 let (out_bytes, out_bytes_len) = convert_fixed_signature(self.id, signature)?;
248 verify_asn1_digest_signature(digest, public_key, unsafe {
249 out_bytes.as_slice(out_bytes_len)
250 })
251 }
252 }
253 }
254}
255
256impl ParsedVerificationAlgorithm for EcdsaVerificationAlgorithm {
257 fn parsed_verify_sig(
258 &self,
259 public_key: &ParsedPublicKey,
260 msg: &[u8],
261 signature: &[u8],
262 ) -> Result<(), Unspecified> {
263 self.verify_ecdsa(msg, signature, public_key.key())
264 }
265
266 fn parsed_verify_digest_sig(
267 &self,
268 public_key: &ParsedPublicKey,
269 digest: &Digest,
270 signature: &[u8],
271 ) -> Result<(), Unspecified> {
272 self.verify_digest_ecdsa(digest, signature, public_key.key())
273 }
274}
275
276fn convert_fixed_signature(
277 alg: &'static AlgorithmID,
278 signature: &[u8],
279) -> Result<(LcPtr<u8>, usize), Unspecified> {
280 let mut out_bytes = null_mut::<u8>();
281 let mut out_bytes_len = MaybeUninit::<usize>::uninit();
282 let sig = unsafe { ecdsa_sig_from_fixed(alg, signature)? };
283 if 1 != unsafe {
284 ECDSA_SIG_to_bytes(&mut out_bytes, out_bytes_len.as_mut_ptr(), *sig.as_const())
285 } {
286 return Err(Unspecified);
287 }
288 Ok((LcPtr::new(out_bytes)?, unsafe {
289 out_bytes_len.assume_init()
290 }))
291}
292
293fn verify_asn1_signature(
294 digest_alg: &'static digest::Algorithm,
295 public_key: &LcPtr<EVP_PKEY>,
296 msg: &[u8],
297 signature: &[u8],
298) -> Result<(), Unspecified> {
299 public_key.verify(msg, Some(digest_alg), No_EVP_PKEY_CTX_consumer, signature)
300}
301
302fn verify_asn1_digest_signature(
303 digest: &Digest,
304 public_key: &LcPtr<EVP_PKEY>,
305 signature: &[u8],
306) -> Result<(), Unspecified> {
307 public_key.verify_digest_sig(digest, No_EVP_PKEY_CTX_consumer, signature)
308}
309
310#[inline]
311unsafe fn ecdsa_sig_from_fixed(
312 alg_id: &'static AlgorithmID,
313 signature: &[u8],
314) -> Result<LcPtr<ECDSA_SIG>, ()> {
315 let num_size_bytes = alg_id.private_key_size();
316 if signature.len() != 2 * num_size_bytes {
317 return Err(());
318 }
319 let mut r_bn = DetachableLcPtr::<BIGNUM>::try_from(&signature[..num_size_bytes])?;
320 let mut s_bn = DetachableLcPtr::<BIGNUM>::try_from(&signature[num_size_bytes..])?;
321
322 let mut ecdsa_sig = LcPtr::new(ECDSA_SIG_new())?;
323
324 if 1 != ECDSA_SIG_set0(*ecdsa_sig.as_mut(), *r_bn.as_mut(), *s_bn.as_mut()) {
325 return Err(());
326 }
327 r_bn.detach();
328 s_bn.detach();
329
330 Ok(ecdsa_sig)
331}